heap_dump 0.0.29 → 0.0.30

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -4,7 +4,7 @@ Low-level ruby heap memory dump - including data and code references, useful for
4
4
  Has no performance overhead while not active, so can be used in production environment.
5
5
 
6
6
  Originally written across ruby 1.9.2-p290 data structures.
7
- Does work on other 1.9.2s and 1.9.3, but not well-tested yet(output is not proven to be as full etc.).
7
+ Does work on other 1.9.2s, 1.9.3 and 2.0.0-preview1, but not well-tested yet(output is not proven to be as full etc.).
8
8
 
9
9
  Currently is under development and output format may differ.
10
10
 
@@ -1,6 +1,20 @@
1
1
  #!/usr/bin/env ruby
2
2
  #encoding: utf-8
3
3
 
4
+ # autodetect ruby headers
5
+ unless ARGV.any? {|arg| arg.include?('--with-ruby-include') }
6
+ require 'rbconfig'
7
+ bindir = RbConfig::CONFIG['bindir']
8
+ if bindir =~ %r{(^.*/\.rbenv/versions)/([^/]+)/bin$}
9
+ ruby_include = "#{$1}/#{$2}/include/ruby-1.9.1/ruby-#{$2}"
10
+ ARGV << "--with-ruby-include=#{ruby_include}"
11
+ elsif bindir =~ %r{(^.*/\.rvm/rubies)/([^/]+)/bin$}
12
+ ruby_include = "#{$1}/#{$2}/include/ruby-1.9.1/#{$2}"
13
+ ruby_include = "#{ENV['rvm_path']}/src/#{$2}" unless File.exist?(ruby_include)
14
+ ARGV << "--with-ruby-include=#{ruby_include}"
15
+ end
16
+ end
17
+
4
18
  require 'mkmf'
5
19
  require 'debugger/ruby_core_source'
6
20
 
@@ -50,13 +64,32 @@ hdrs = proc {
50
64
  %w{
51
65
  constant.h
52
66
  internal.h
67
+ gc.h
53
68
  }.each{|h| have_header(h)}
54
69
 
70
+ have_struct_member("rb_iseq_t", "filename", "vm_core.h")
71
+ have_struct_member("rb_binding_t", "filename", "vm_core.h")
72
+ have_struct_member("rb_control_frame_t", "bp", "vm_core.h")
73
+ have_struct_member("rb_thread_t", "thrown_errinfo", "vm_core.h")
74
+ have_struct_member("rb_event_hook_t", "data", "vm_core.h")
75
+
76
+
77
+
78
+ have_struct_member("rb_iseq_t", "location", "vm_core.h")
79
+ #have_struct_member("rb_iseq_location_t", "filename", "vm_core.h")
80
+ have_struct_member("rb_block_t", "klass", "vm_core.h")
81
+ have_struct_member("rb_block_t", "lfp", "vm_core.h")
82
+
55
83
  res
56
84
  }
57
85
 
58
86
  dir_config("ruby") # allow user to pass in non-standard core include directory
59
87
 
60
88
  if !Debugger::RubyCoreSource::create_makefile_with_core(hdrs, "heap_dump")
89
+ STDERR.print("Makefile creation failed\n")
90
+ STDERR.print("*************************************************************\n\n")
91
+ STDERR.print(" NOTE: If your headers were not found, try passing\n")
92
+ STDERR.print(" --with-ruby-include=PATH_TO_HEADERS \n\n")
93
+ STDERR.print("*************************************************************\n\n")
61
94
  exit(1)
62
95
  end
@@ -16,6 +16,10 @@
16
16
  // #include "atomic.h"
17
17
  #include "iseq.h"
18
18
 
19
+ #ifdef HAVE_GC_H
20
+ #include "gc.h"
21
+ #endif
22
+
19
23
  #ifdef HAVE_INTERNAL_H
20
24
  #include "internal.h"
21
25
  #else
@@ -66,9 +70,9 @@ static ID classid;
66
70
 
67
71
  //shortcuts to yajl
68
72
  #define YAJL ctx->yajl
69
- #define yg_string(str,len) yajl_gen_string(YAJL, str, len)
70
- #define yg_cstring(str) yg_string(str, (unsigned int)strlen(str))
71
- #define yg_rstring(str) yg_string(RSTRING_PTR(str), (unsigned int)RSTRING_LEN(str))
73
+ #define yg_string(str,len) yajl_gen_string(YAJL, (const unsigned char *)(str), (unsigned int)(len))
74
+ #define yg_cstring(str) yg_string(str, strlen(str))
75
+ #define yg_rstring(str) yg_string(RSTRING_PTR(str), RSTRING_LEN(str))
72
76
  #define yg_int(i) yajl_gen_integer(YAJL, i)
73
77
  #define yg_double(d) (yajl_gen_double(YAJL, d)==yajl_gen_invalid_number? yg_cstring("inf|NaN") : true)
74
78
  #define yg_null() yajl_gen_null(YAJL)
@@ -135,11 +139,6 @@ static inline const char* rb_type_str(int type){
135
139
  }
136
140
  }
137
141
 
138
- static inline const char* rb_builtin_type(VALUE obj){
139
- //NOTE: only for heap objects, on embedded use (TYPE(...))
140
- return rb_type_str(BUILTIN_TYPE(obj));
141
- }
142
-
143
142
  #define true 1
144
143
  #define false 0
145
144
 
@@ -565,9 +564,20 @@ static const char* iseq_type(VALUE type){
565
564
  }
566
565
 
567
566
  static void dump_iseq(const rb_iseq_t* iseq, walk_ctx_t *ctx){
567
+ int i;
568
+ #ifdef HAVE_RB_ISEQ_T_FILENAME
568
569
  if(iseq->name) ygh_rstring("name", iseq->name);
569
570
  if(iseq->filename) ygh_rstring("filename", iseq->filename);
570
571
  ygh_int("line", FIX2LONG(iseq->line_no));
572
+ #else
573
+ #ifdef HAVE_RB_ISEQ_T_LOCATION
574
+ if(iseq->location.label) ygh_rstring("name", iseq->location.label);
575
+ if(iseq->location.path) ygh_rstring("filename", iseq->location.path);
576
+ //base_label usually(always?)==label
577
+ // if(iseq->location.base_label) ygh_rstring("base_label", iseq->location.base_label);
578
+ ygh_int("line", FIX2LONG(iseq->location.first_lineno));
579
+ #endif
580
+ #endif
571
581
 
572
582
  //if(iseq->type != 25116) //also 28 in mark_ary
573
583
  ygh_cstring("type", iseq_type(iseq->type));
@@ -581,12 +591,11 @@ static void dump_iseq(const rb_iseq_t* iseq, walk_ctx_t *ctx){
581
591
  ygh_id("klass", iseq->klass);
582
592
  ygh_id("cref_stack", (VALUE)iseq->cref_stack); //NODE*
583
593
 
584
- ID id = iseq->defined_method_id;
585
594
  yg_cstring("defined_method_id");
586
- if(id && id != ID_ALLOCATOR){
587
- yg_cstring(rb_id2name(id)); // symbol=ID2SYM(id);
595
+ if(iseq->defined_method_id && iseq->defined_method_id != ID_ALLOCATOR){
596
+ yg_cstring(rb_id2name(iseq->defined_method_id));
588
597
  } else {
589
- yg_int(id);
598
+ yg_int(iseq->defined_method_id);
590
599
  }
591
600
 
592
601
  if (iseq->compile_data != 0) {
@@ -599,9 +608,8 @@ static void dump_iseq(const rb_iseq_t* iseq, walk_ctx_t *ctx){
599
608
  if(iseq->local_table_size > 0){
600
609
  yg_cstring("local_table");
601
610
  yg_array();
602
- int i;
603
611
  for(i = 0; i < iseq->local_table_size; i++){
604
- char* name = rb_id2name(iseq->local_table[i]);
612
+ const char* name = rb_id2name(iseq->local_table[i]);
605
613
  if(name){
606
614
  yg_cstring(name);
607
615
  } else {
@@ -632,11 +640,17 @@ static void dump_block(const rb_block_t* block, walk_ctx_t *ctx){
632
640
 
633
641
  ygh_id("self", block->self);
634
642
 
643
+ #ifdef HAVE_RB_BLOCK_T_LFP
635
644
  //FIXME: these are pointers to some memory, may be dumped more clever
636
645
  ygh_id("lfp", (VALUE)block->lfp);
637
646
  ygh_id("dfp", (VALUE)block->dfp);
638
647
  //lfp = local frame pointer? local_num elems?
639
648
  // dfp = ?
649
+ #endif
650
+ #ifdef HAVE_RB_BLOCK_T_KLASS
651
+ ygh_id("class", (VALUE)block->klass);
652
+ //TODO: VALUE*ep = ?
653
+ #endif
640
654
  }
641
655
 
642
656
 
@@ -672,7 +686,7 @@ static void dump_locations(VALUE* p, long int n, walk_ctx_t *ctx){
672
686
  static void dump_thread(const rb_thread_t* th, walk_ctx_t *ctx);
673
687
 
674
688
 
675
- vm_dump_each_thread_func(st_data_t key, VALUE obj, walk_ctx_t *ctx){
689
+ static int vm_dump_each_thread_func(st_data_t key, VALUE obj, walk_ctx_t *ctx){
676
690
  //here stored 'self' from thread
677
691
  // yg_map();
678
692
  ygh_id("id", obj);
@@ -758,16 +772,20 @@ static void dump_data_if_known(VALUE obj, walk_ctx_t *ctx){
758
772
  rb_binding_t *bind = RTYPEDDATA_DATA(obj);
759
773
  if(!bind) return;
760
774
  ygh_id("env", bind->env);
775
+ #ifdef HAVE_RB_BINDING_T_FILENAME
761
776
  ygh_id("filename", bind->filename);
777
+ ygh_int("line", bind->line_no);
778
+ #else
779
+ ygh_id("filename", bind->path);
780
+ ygh_int("line", bind->first_lineno);
781
+ #endif
762
782
  return;
763
783
  }
764
784
 
765
785
  if(!strcmp("VM/env", typename)){
766
786
  const rb_env_t* env = RTYPEDDATA_DATA(obj);
767
- int i = 0;
768
787
  yg_cstring("env");
769
788
  yajl_gen_array_open(ctx->yajl);
770
- //for(; i < env->env_size; i++) yg_id(env->env[i]);
771
789
  dump_locations(env->env, env->env_size, ctx);
772
790
  yajl_gen_array_close(ctx->yajl);
773
791
 
@@ -891,7 +909,7 @@ static void dump_data_if_known(VALUE obj, walk_ctx_t *ctx){
891
909
  // rb_gc_mark(tobj->vtm.subsecx);
892
910
  // rb_gc_mark(tobj->vtm.utc_offset);
893
911
  VALUE flt = rb_funcall(obj, rb_intern("to_f"), 0);
894
- if(BUILTIN_TYPE(flt) == T_FLOAT){ ygh_double("val", RFLOAT_VALUE(flt)); }
912
+ if(TYPE(flt) == T_FLOAT){ ygh_double("val", NUM2DBL(flt)); }
895
913
  return;
896
914
  }
897
915
 
@@ -920,11 +938,13 @@ static VALUE rb_class_real_checked(VALUE cl)
920
938
  }
921
939
 
922
940
  static inline void walk_live_object(VALUE obj, walk_ctx_t *ctx){
941
+ //note: BUILTIN_TYPE is only for heap, for embedded use TYPE
942
+ const int bt_type = BUILTIN_TYPE(obj);
923
943
  ctx->live_objects++;
924
944
  yajl_gen_map_open(ctx->yajl);
925
945
 
926
946
  ygh_int("id", NUM2LONG(rb_obj_id(obj)));
927
- ygh_cstring("bt", rb_builtin_type(obj));
947
+ ygh_cstring("bt", rb_type_str(bt_type));
928
948
 
929
949
  //TODO:
930
950
  #ifdef GC_DEBUG
@@ -938,8 +958,6 @@ static inline void walk_live_object(VALUE obj, walk_ctx_t *ctx){
938
958
  // if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj))
939
959
  // return generic_ivar_get(obj, id, warn);
940
960
 
941
- const int bt_type = BUILTIN_TYPE(obj);
942
-
943
961
  // for generic types ivars are held separately in a table
944
962
  if(bt_type != T_OBJECT && bt_type != T_CLASS && bt_type != T_MODULE && bt_type != T_ICLASS){
945
963
  st_table* generic_tbl = rb_generic_ivar_table(obj);
@@ -1151,10 +1169,11 @@ static inline void walk_live_object(VALUE obj, walk_ctx_t *ctx){
1151
1169
  * vend: a pointer to next to the valid heap_slot area.
1152
1170
  * stride: a distance to next VALUE.
1153
1171
  */
1154
- static int objspace_walker(void *vstart, void *vend, int stride, walk_ctx_t *ctx) {
1172
+ static int objspace_walker(void *vstart, void *vend, size_t stride, void* data) {
1173
+ VALUE v = (VALUE)vstart;
1174
+ walk_ctx_t *ctx = data;
1155
1175
  ctx->walker_called++;
1156
1176
 
1157
- VALUE v = (VALUE)vstart;
1158
1177
  for (; v != (VALUE)vend; v += stride) {
1159
1178
  if (RBASIC(v)->flags) { // is live object
1160
1179
  walk_live_object(v, ctx);
@@ -1165,18 +1184,8 @@ static int objspace_walker(void *vstart, void *vend, int stride, walk_ctx_t *ctx
1165
1184
  }
1166
1185
 
1167
1186
 
1168
- //TODO: move to separate header.
1169
- /*
1170
- Bits of code taken directly from ruby gc
1171
- Copyright (C) 1993-2007 Yukihiro Matsumoto
1172
- Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
1173
- Copyright (C) 2000 Information-technology Promotion Agency, Japan
1174
- */
1175
- // #if defined(__x86_64__) && defined(__GNUC__) && !defined(__native_client__)
1176
- // #define SET_MACHINE_STACK_END(p) __asm__("movq\t%%rsp, %0" : "=r" (*(p)))
1177
- // #elif defined(__i386) && defined(__GNUC__) && !defined(__native_client__)
1178
- // #define SET_MACHINE_STACK_END(p) __asm__("movl\t%%esp, %0" : "=r" (*(p)))
1179
- // #else
1187
+ //TODO: move to separate header?
1188
+ #ifndef SET_MACHINE_STACK_END
1180
1189
  NOINLINE(static void rb_gc_set_stack_end(VALUE **stack_end_p));
1181
1190
  #define SET_MACHINE_STACK_END(p) rb_gc_set_stack_end(p)
1182
1191
  #define USE_CONSERVATIVE_STACK_END
@@ -1187,6 +1196,7 @@ rb_gc_set_stack_end(VALUE **stack_end_p)
1187
1196
  VALUE stack_end;
1188
1197
  *stack_end_p = &stack_end;
1189
1198
  }
1199
+ #endif
1190
1200
 
1191
1201
  #ifdef __ia64
1192
1202
  #define SET_STACK_END (SET_MACHINE_STACK_END(&th->machine_stack_end), th->machine_register_stack_end = rb_ia64_bsp())
@@ -1234,7 +1244,6 @@ ruby_get_stack_grow_direction(volatile VALUE *addr)
1234
1244
 
1235
1245
  #define numberof(array) (int)(sizeof(array) / sizeof((array)[0]))
1236
1246
 
1237
-
1238
1247
  /////////////
1239
1248
 
1240
1249
 
@@ -1251,8 +1260,10 @@ static int
1251
1260
  dump_backtrace(void* data, VALUE file, int line, VALUE method, int argc, VALUE* argv)
1252
1261
  {
1253
1262
  walk_ctx_t *ctx = data;
1254
- yg_map();
1255
1263
  const char *filename = NIL_P(file) ? "<ruby>" : RSTRING_PTR(file);
1264
+ int i;
1265
+
1266
+ yg_map();
1256
1267
 
1257
1268
  ygh_cstring("file", filename);
1258
1269
  ygh_int("line", line);
@@ -1268,7 +1279,6 @@ dump_backtrace(void* data, VALUE file, int line, VALUE method, int argc, VALUE*
1268
1279
  if(argc > 0){
1269
1280
  yg_cstring("argv");
1270
1281
  yg_array();
1271
- int i;
1272
1282
  for(i = 0; i < argc; i++)
1273
1283
  yg_id(argv[i]);
1274
1284
  yg_array_end();
@@ -1281,11 +1291,12 @@ typedef int (rb_backtrace_iter_ext_func)(void *arg, VALUE file, int line, VALUE
1281
1291
 
1282
1292
  // copied from ruby_ext_backtrace
1283
1293
  static int
1284
- vm_backtrace_each_ext(rb_thread_t *th, int lev, void (*init)(void *), rb_backtrace_iter_ext_func *iter, void *arg)
1294
+ vm_backtrace_each_ext(const rb_thread_t *th, int lev, void (*init)(void *), rb_backtrace_iter_ext_func *iter, void *arg)
1285
1295
  {
1286
1296
  const rb_control_frame_t *limit_cfp = th->cfp;
1287
1297
  const rb_control_frame_t *cfp = (void *)(th->stack + th->stack_size);
1288
1298
  VALUE file = Qnil;
1299
+ VALUE* argv;
1289
1300
  int line_no = 0;
1290
1301
 
1291
1302
  cfp -= 2;
@@ -1301,18 +1312,32 @@ vm_backtrace_each_ext(rb_thread_t *th, int lev, void (*init)(void *), rb_backtra
1301
1312
  if (th->vm->progname) file = th->vm->progname;
1302
1313
 
1303
1314
  while (cfp > limit_cfp) {
1315
+ #ifdef HAVE_RB_CONTROL_FRAME_T_BP
1316
+ VALUE* bp = cfp->bp;
1317
+ #else
1318
+ VALUE* bp = cfp->sp; //??
1319
+ #endif
1304
1320
  if (cfp->iseq != 0) {
1305
1321
  if (cfp->pc != 0) {
1306
1322
  rb_iseq_t *iseq = cfp->iseq;
1307
1323
 
1308
1324
  line_no = rb_vm_get_sourceline(cfp);
1325
+ #ifdef HAVE_RB_ISEQ_T_FILENAME
1309
1326
  file = iseq->filename;
1310
-
1327
+ #else
1328
+ file = iseq->location.path;
1329
+ #endif
1311
1330
  //arguments pushed this way: *reg_cfp->sp++ = recv; for (i = 0; i < argc; i++) *reg_cfp->sp++ = argv[i];
1312
1331
  //local vars = cfp->iseq->local_size - cfp->iseq->arg_size;
1313
1332
  //in memory: receiver params locals (bp(incremented))
1314
- VALUE* argv = &cfp->bp[- cfp->iseq->local_size - 1];
1315
- if ((*iter)(arg, file, line_no, iseq->name, cfp->iseq->arg_size, argv)) break;
1333
+ argv = &bp[- cfp->iseq->local_size - 1];
1334
+ if ((*iter)(arg, file, line_no,
1335
+ #ifdef HAVE_RB_ISEQ_T_LOCATION
1336
+ iseq->location.label
1337
+ #else
1338
+ iseq->name
1339
+ #endif
1340
+ , cfp->iseq->arg_size, argv)) break;
1316
1341
  }
1317
1342
  } else
1318
1343
  if (RUBYVM_CFUNC_FRAME_P(cfp)) {
@@ -1321,11 +1346,11 @@ vm_backtrace_each_ext(rb_thread_t *th, int lev, void (*init)(void *), rb_backtra
1321
1346
  if (NIL_P(file)) file = ruby_engine_name;
1322
1347
 
1323
1348
  if (id != ID_ALLOCATOR){
1324
- VALUE* argv = NULL;
1349
+ argv = NULL;
1325
1350
  // when argc==-1/-2(variable length params without/with splat) - the cfp has no info on params count :(
1326
1351
  //TODO: infere from somewhere ex. find self in stack? (not guaranted btw, for example: obj.method(obj, 123, obj) - will find last param instead of self)
1327
1352
  if(cfp->me->def->body.cfunc.argc >= 0){ //only fixed args
1328
- argv = &cfp->bp[- cfp->me->def->body.cfunc.argc - 2]; // args+self, bp was incremented thus minus 2
1353
+ argv = &bp[- cfp->me->def->body.cfunc.argc - 2]; // args+self, bp was incremented thus minus 2
1329
1354
  }
1330
1355
  //file+line no from previous iseq frame
1331
1356
  if((*iter)(arg, file, line_no, rb_id2str(id), cfp->me->def->body.cfunc.argc, argv)) break;
@@ -1337,6 +1362,15 @@ vm_backtrace_each_ext(rb_thread_t *th, int lev, void (*init)(void *), rb_backtra
1337
1362
  }
1338
1363
 
1339
1364
  static void dump_thread(const rb_thread_t* th, walk_ctx_t *ctx){
1365
+ rb_iseq_t *iseq;
1366
+ int line_no;
1367
+ ID id;
1368
+ #ifdef HAVE_RB_EVENT_HOOK_T_DATA
1369
+ rb_event_hook_t *hook = th->event_hooks;
1370
+ #else
1371
+ struct rb_event_hook_struct *hook = th->event_hooks.hooks;
1372
+ #endif
1373
+
1340
1374
  if(th->stack){
1341
1375
  VALUE *p = th->stack;
1342
1376
  VALUE *sp = th->cfp->sp;
@@ -1357,13 +1391,18 @@ static void dump_thread(const rb_thread_t* th, walk_ctx_t *ctx){
1357
1391
  //TODO: this is kind of backtrace, but other direction plus some other info, merge it in backtrace.
1358
1392
  while (cfp != limit_cfp) {
1359
1393
  yajl_gen_map_open(ctx->yajl);
1360
- rb_iseq_t *iseq = cfp->iseq;
1394
+ iseq = cfp->iseq;
1361
1395
  ygh_id("proc", cfp->proc);
1362
1396
  ygh_id("self", cfp->self);
1363
1397
  if (iseq) {
1364
1398
  ygh_id("iseq", RUBY_VM_NORMAL_ISEQ_P(iseq) ? iseq->self : (VALUE)iseq);
1365
- int line_no = rb_vm_get_sourceline(cfp);
1399
+ line_no = rb_vm_get_sourceline(cfp);
1400
+ //TODO: dry?
1401
+ #ifdef HAVE_RB_ISEQ_T_FILENAME
1366
1402
  ygh_rstring("file", iseq->filename);
1403
+ #else
1404
+ ygh_rstring("file", iseq->location.path);
1405
+ #endif
1367
1406
  ygh_int("line_no",line_no);
1368
1407
  }
1369
1408
  if (cfp->me){
@@ -1376,7 +1415,7 @@ static void dump_thread(const rb_thread_t* th, walk_ctx_t *ctx){
1376
1415
  // char mark;
1377
1416
  //rb_method_definition_t *def;
1378
1417
  ygh_id("klass", me->klass);
1379
- ID id = me->called_id;
1418
+ id = me->called_id;
1380
1419
 
1381
1420
  if(me->def){
1382
1421
  id = me->def->original_id;
@@ -1405,8 +1444,12 @@ static void dump_thread(const rb_thread_t* th, walk_ctx_t *ctx){
1405
1444
  ygh_id("thgroup", th->thgroup);
1406
1445
  ygh_id("value", th->value);
1407
1446
  ygh_id("errinfo", th->errinfo);
1447
+
1448
+ #ifdef HAVE_RB_THREAD_T_THROWN_ERRINFO
1408
1449
  ygh_id("thrown_errinfo", th->thrown_errinfo);
1409
1450
  ygh_id("local_svar", th->local_svar);
1451
+ #endif
1452
+
1410
1453
  ygh_id("top_self", th->top_self);
1411
1454
  ygh_id("top_wrapper", th->top_wrapper);
1412
1455
  ygh_id("fiber", th->fiber);
@@ -1438,8 +1481,6 @@ static void dump_thread(const rb_thread_t* th, walk_ctx_t *ctx){
1438
1481
  }
1439
1482
  yajl_gen_map_close(ctx->yajl);
1440
1483
 
1441
- // mark_event_hooks(th->event_hooks);
1442
- rb_event_hook_t *hook = th->event_hooks;
1443
1484
  yg_cstring("event_hooks");
1444
1485
  yajl_gen_array_open(ctx->yajl);
1445
1486
  while(hook){
@@ -1451,6 +1492,9 @@ static void dump_thread(const rb_thread_t* th, walk_ctx_t *ctx){
1451
1492
 
1452
1493
 
1453
1494
  static void dump_machine_context(walk_ctx_t *ctx){
1495
+ VALUE* x;
1496
+ unsigned long n;
1497
+
1454
1498
  //TODO: other threads?
1455
1499
  rb_thread_t* th = GET_THREAD()->vm->main_thread; //GET_THREAD();
1456
1500
  union {
@@ -1470,8 +1514,8 @@ static void dump_machine_context(walk_ctx_t *ctx){
1470
1514
  yg_cstring("registers");
1471
1515
  yajl_gen_array_open(ctx->yajl);
1472
1516
  //mark_locations_array(objspace, save_regs_gc_mark.v, numberof(save_regs_gc_mark.v));
1473
- VALUE* x = save_regs_gc_mark.v;
1474
- unsigned long n = numberof(save_regs_gc_mark.v);
1517
+ x = save_regs_gc_mark.v;
1518
+ n = numberof(save_regs_gc_mark.v);
1475
1519
  while (n--) {
1476
1520
  VALUE v = *(x++);
1477
1521
  if(is_in_heap((void*)v, NULL))
@@ -1501,22 +1545,21 @@ static void dump_machine_context(walk_ctx_t *ctx){
1501
1545
  // 1.9.2, rb_class_tbl fails to be linked in 1.9.3 :(
1502
1546
 
1503
1547
  static int dump_class_tbl_entry(ID key, rb_const_entry_t* ce/*st_data_t val*/, walk_ctx_t *ctx){
1548
+ const char* id;
1504
1549
  if (!rb_is_const_id(key)) return ST_CONTINUE; //?
1505
- VALUE value = ce->value;
1506
1550
 
1507
- char* id = rb_id2name(key);
1508
- if(id)
1551
+ if((id = rb_id2name(key)))
1509
1552
  yg_cstring(id);
1510
1553
  else
1511
1554
  yg_cstring("(unknown)");
1512
- yg_id(value);
1555
+ yg_id(ce->value);
1513
1556
  return ST_CONTINUE;
1514
1557
  }
1515
1558
  #endif
1516
1559
 
1517
1560
  #ifdef HAVE_RB_GLOBAL_TBL
1518
1561
  static int dump_global_tbl_entry(ID key, struct rb_global_entry* ge/*st_data_t val*/, walk_ctx_t *ctx){
1519
- char* id = rb_id2name(key);
1562
+ const char* id = rb_id2name(key);
1520
1563
  if(id)
1521
1564
  yg_cstring(id);
1522
1565
  else
@@ -1530,8 +1573,8 @@ static int dump_global_tbl_entry(ID key, struct rb_global_entry* ge/*st_data_t v
1530
1573
  yg_cstring(info.dli_sname);
1531
1574
 
1532
1575
  if(!strcmp("rb_gvar_val_getter", info.dli_sname)){
1533
- yg_cstring("data");
1534
- yg_id(ge->var->data);
1576
+ yg_cstring("data");
1577
+ yg_id((VALUE)ge->var->data);
1535
1578
  }
1536
1579
  }
1537
1580
 
@@ -1547,11 +1590,13 @@ static int dump_global_tbl_entry(ID key, struct rb_global_entry* ge/*st_data_t v
1547
1590
  #include <stdarg.h>
1548
1591
  static bool g_verbose = false;
1549
1592
  static int log_printf(const char* format, ...){
1593
+ int res = 0;
1550
1594
  va_list list;
1551
1595
  va_start(list, format);
1552
1596
  if(g_verbose)
1553
- vprintf(format, list);
1597
+ res = vprintf(format, list);
1554
1598
  va_end(list);
1599
+ return res;
1555
1600
  }
1556
1601
 
1557
1602
  #define log log_printf
@@ -1569,6 +1614,14 @@ static VALUE heapdump_verbose_setter(VALUE self, VALUE verbose){
1569
1614
  //public symbol, can be used from GDB
1570
1615
  void heapdump_dump(const char* filename){
1571
1616
  struct walk_ctx ctx_o, *ctx = &ctx_o;
1617
+ struct gc_list *list;
1618
+ #ifdef HAVE_RB_CLASS_TBL
1619
+ st_table *rb_class_tbl;
1620
+ #endif
1621
+ #ifdef HAVE_RB_GLOBAL_TBL
1622
+ st_table *rb_global_tbl;
1623
+ #endif
1624
+
1572
1625
  memset(ctx, 0, sizeof(*ctx));
1573
1626
 
1574
1627
  if(!filename){
@@ -1589,7 +1642,6 @@ void heapdump_dump(const char* filename){
1589
1642
  flush_yajl(ctx);
1590
1643
  // fprintf(ctx->file, "\n");
1591
1644
 
1592
- struct gc_list *list;
1593
1645
  /* mark protected global variables */
1594
1646
  log("global_list\n");
1595
1647
  yg_cstring("globals");
@@ -1602,7 +1654,7 @@ void heapdump_dump(const char* filename){
1602
1654
 
1603
1655
  //TODO: rb_global_tbl
1604
1656
  #ifdef HAVE_RB_GLOBAL_TBL
1605
- st_table *rb_global_tbl = rb_get_global_tbl();
1657
+ rb_global_tbl = rb_get_global_tbl();
1606
1658
  if (rb_global_tbl && rb_global_tbl->num_entries > 0){
1607
1659
  log("globals\n");
1608
1660
  yg_cstring("global_tbl");
@@ -1614,7 +1666,7 @@ void heapdump_dump(const char* filename){
1614
1666
  #endif
1615
1667
 
1616
1668
  #ifdef HAVE_RB_CLASS_TBL
1617
- st_table *rb_class_tbl = rb_get_class_tbl();
1669
+ rb_class_tbl = rb_get_class_tbl();
1618
1670
  if (rb_class_tbl && rb_class_tbl->num_entries > 0){
1619
1671
  log("classes\n");
1620
1672
  yg_cstring("classes");
@@ -1666,13 +1718,25 @@ iterate_user_type_counts(VALUE key, VALUE value, yajl_gen yajl){
1666
1718
 
1667
1719
  static VALUE
1668
1720
  rb_heapdump_count_objects(VALUE self, VALUE string_prefixes, VALUE do_gc){
1669
- rb_check_array_type(string_prefixes);
1670
1721
  yajl_gen_config cfg;
1722
+ yajl_gen yajl;
1723
+ VALUE cls, class_name, prefix;
1724
+ size_t counts[T_MASK+1];
1725
+ size_t freed = 0;
1726
+ size_t total = 0;
1727
+ size_t i;
1728
+ long int n;
1729
+ const unsigned char* buf;
1730
+ unsigned int len;
1731
+ VALUE hash = rb_hash_new();
1732
+ rb_objspace_t *objspace = GET_THREAD()->vm->objspace;
1733
+
1734
+ rb_check_array_type(string_prefixes);
1671
1735
  memset(&cfg, 0, sizeof(cfg));
1672
1736
  cfg.beautify = true;
1673
1737
  cfg.htmlSafe = true;
1674
1738
  cfg.indentString = " ";
1675
- yajl_gen yajl = yajl_gen_alloc(&cfg,NULL);
1739
+ yajl = yajl_gen_alloc(&cfg,NULL);
1676
1740
  yg_map();
1677
1741
  if(do_gc){
1678
1742
  yg_cstring("gc_ran");
@@ -1680,13 +1744,6 @@ rb_heapdump_count_objects(VALUE self, VALUE string_prefixes, VALUE do_gc){
1680
1744
  rb_gc_start();
1681
1745
  }
1682
1746
 
1683
- rb_objspace_t *objspace = GET_THREAD()->vm->objspace;
1684
- size_t counts[T_MASK+1];
1685
- size_t freed = 0;
1686
- size_t total = 0;
1687
- size_t i;
1688
- VALUE hash = rb_hash_new();
1689
-
1690
1747
  for (i = 0; i <= T_MASK; i++) counts[i] = 0;
1691
1748
 
1692
1749
  FOR_EACH_HEAP_SLOT(p)
@@ -1696,12 +1753,11 @@ rb_heapdump_count_objects(VALUE self, VALUE string_prefixes, VALUE do_gc){
1696
1753
  counts[type]++;
1697
1754
  if(type == T_OBJECT){
1698
1755
  //take class etc.
1699
- VALUE cls = rb_class_real_checked(CLASS_OF(p));
1756
+ cls = rb_class_real_checked(CLASS_OF(p));
1700
1757
  if(!cls) continue;
1701
- VALUE class_name = rb_class_path(cls);
1702
- long int n = RARRAY_LEN(string_prefixes)-1;
1703
- for(; n >= 0; n--){
1704
- VALUE prefix = rb_check_string_type(RARRAY_PTR(string_prefixes)[n]);
1758
+ class_name = rb_class_path(cls);
1759
+ for(n = RARRAY_LEN(string_prefixes)-1; n >= 0; n--){
1760
+ prefix = rb_check_string_type(RARRAY_PTR(string_prefixes)[n]);
1705
1761
  if(NIL_P(prefix)) continue;
1706
1762
  rb_enc_check(class_name, prefix);
1707
1763
  if (RSTRING_LEN(class_name) < RSTRING_LEN(prefix)) continue;
@@ -1744,11 +1800,9 @@ rb_heapdump_count_objects(VALUE self, VALUE string_prefixes, VALUE do_gc){
1744
1800
  yg_map_end(); //all document
1745
1801
 
1746
1802
  //flush yajl:
1747
- const unsigned char* buf;
1748
- unsigned int len;
1749
1803
  if(yajl_gen_get_buf(yajl, &buf, &len) == yajl_gen_status_ok){
1750
1804
  //fwrite(buf, len, 1, ctx->file);
1751
- VALUE res = rb_str_new(buf, len);
1805
+ VALUE res = rb_str_new((char*)buf, len);
1752
1806
  yajl_gen_clear(yajl);
1753
1807
  yajl_gen_free(yajl);
1754
1808
  return res;
@@ -0,0 +1,67 @@
1
+ #define CAPTURE_JUST_VALID_VM_STACK 1
2
+
3
+ enum context_type {
4
+ CONTINUATION_CONTEXT = 0,
5
+ FIBER_CONTEXT = 1,
6
+ ROOT_FIBER_CONTEXT = 2
7
+ };
8
+
9
+ typedef struct rb_context_struct {
10
+ enum context_type type;
11
+ VALUE self;
12
+ int argc;
13
+ VALUE value;
14
+ VALUE *vm_stack;
15
+ #ifdef CAPTURE_JUST_VALID_VM_STACK
16
+ size_t vm_stack_slen; /* length of stack (head of th->stack) */
17
+ size_t vm_stack_clen; /* length of control frames (tail of th->stack) */
18
+ #endif
19
+ VALUE *machine_stack;
20
+ VALUE *machine_stack_src;
21
+ #ifdef __ia64
22
+ VALUE *machine_register_stack;
23
+ VALUE *machine_register_stack_src;
24
+ int machine_register_stack_size;
25
+ #endif
26
+ rb_thread_t saved_thread;
27
+ rb_jmpbuf_t jmpbuf;
28
+ size_t machine_stack_size;
29
+ } rb_context_t;
30
+
31
+ enum fiber_status {
32
+ CREATED,
33
+ RUNNING,
34
+ TERMINATED
35
+ };
36
+
37
+ #if FIBER_USE_NATIVE && !defined(_WIN32)
38
+ #define MAX_MAHINE_STACK_CACHE 10
39
+ static int machine_stack_cache_index = 0;
40
+ typedef struct machine_stack_cache_struct {
41
+ void *ptr;
42
+ size_t size;
43
+ } machine_stack_cache_t;
44
+ static machine_stack_cache_t machine_stack_cache[MAX_MAHINE_STACK_CACHE];
45
+ static machine_stack_cache_t terminated_machine_stack;
46
+ #endif
47
+
48
+ typedef struct rb_fiber_struct {
49
+ rb_context_t cont;
50
+ VALUE prev;
51
+ enum fiber_status status;
52
+ struct rb_fiber_struct *prev_fiber;
53
+ struct rb_fiber_struct *next_fiber;
54
+ /* If a fiber invokes "transfer",
55
+ * then this fiber can't "resume" any more after that.
56
+ * You shouldn't mix "transfer" and "resume".
57
+ */
58
+ int transfered;
59
+
60
+ #if FIBER_USE_NATIVE
61
+ #ifdef _WIN32
62
+ void *fib_handle;
63
+ #else
64
+ ucontext_t context;
65
+ #endif
66
+ #endif
67
+ } rb_fiber_t;
@@ -0,0 +1,251 @@
1
+ #include "ruby/re.h"
2
+
3
+ #ifndef GC_PROFILE_MORE_DETAIL
4
+ #define GC_PROFILE_MORE_DETAIL 0
5
+ #endif
6
+
7
+ typedef struct gc_profile_record {
8
+ double gc_time;
9
+ double gc_invoke_time;
10
+
11
+ size_t heap_total_objects;
12
+ size_t heap_use_size;
13
+ size_t heap_total_size;
14
+
15
+ int is_marked;
16
+
17
+ #if GC_PROFILE_MORE_DETAIL
18
+ double gc_mark_time;
19
+ double gc_sweep_time;
20
+
21
+ size_t heap_use_slots;
22
+ size_t heap_live_objects;
23
+ size_t heap_free_objects;
24
+
25
+ int have_finalize;
26
+
27
+ size_t allocate_increase;
28
+ size_t allocate_limit;
29
+ #endif
30
+ } gc_profile_record;
31
+
32
+
33
+ #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CYGWIN__)
34
+ #pragma pack(push, 1) /* magic for reducing sizeof(RVALUE): 24 -> 20 */
35
+ #endif
36
+
37
+ typedef struct RVALUE {
38
+ union {
39
+ struct {
40
+ VALUE flags; /* always 0 for freed obj */
41
+ struct RVALUE *next;
42
+ } free;
43
+ struct RBasic basic;
44
+ struct RObject object;
45
+ struct RClass klass;
46
+ struct RFloat flonum;
47
+ struct RString string;
48
+ struct RArray array;
49
+ struct RRegexp regexp;
50
+ struct RHash hash;
51
+ struct RData data;
52
+ struct RTypedData typeddata;
53
+ struct RStruct rstruct;
54
+ struct RBignum bignum;
55
+ struct RFile file;
56
+ struct RNode node;
57
+ struct RMatch match;
58
+ struct RRational rational;
59
+ struct RComplex complex;
60
+ } as;
61
+ #ifdef GC_DEBUG
62
+ const char *file;
63
+ int line;
64
+ #endif
65
+ } RVALUE;
66
+
67
+ #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CYGWIN__)
68
+ #pragma pack(pop)
69
+ #endif
70
+
71
+ struct heaps_slot {
72
+ void *membase;
73
+ RVALUE *slot;
74
+ size_t limit;
75
+ uintptr_t *bits;
76
+ RVALUE *freelist;
77
+ struct heaps_slot *next;
78
+ struct heaps_slot *prev;
79
+ struct heaps_slot *free_next;
80
+ };
81
+
82
+ struct heaps_header {
83
+ struct heaps_slot *base;
84
+ uintptr_t *bits;
85
+ };
86
+
87
+ struct sorted_heaps_slot {
88
+ RVALUE *start;
89
+ RVALUE *end;
90
+ struct heaps_slot *slot;
91
+ };
92
+
93
+ struct heaps_free_bitmap {
94
+ struct heaps_free_bitmap *next;
95
+ };
96
+
97
+ struct gc_list {
98
+ VALUE *varptr;
99
+ struct gc_list *next;
100
+ };
101
+
102
+ #define STACK_CHUNK_SIZE 500
103
+
104
+ typedef struct stack_chunk {
105
+ VALUE data[STACK_CHUNK_SIZE];
106
+ struct stack_chunk *next;
107
+ } stack_chunk_t;
108
+
109
+ typedef struct mark_stack {
110
+ stack_chunk_t *chunk;
111
+ stack_chunk_t *cache;
112
+ size_t index;
113
+ size_t limit;
114
+ size_t cache_size;
115
+ size_t unused_cache_size;
116
+ } mark_stack_t;
117
+
118
+ #ifndef CALC_EXACT_MALLOC_SIZE
119
+ #define CALC_EXACT_MALLOC_SIZE 0
120
+ #endif
121
+
122
+ typedef struct rb_objspace {
123
+ struct {
124
+ size_t limit;
125
+ size_t increase;
126
+ #if CALC_EXACT_MALLOC_SIZE
127
+ size_t allocated_size;
128
+ size_t allocations;
129
+ #endif
130
+ } malloc_params;
131
+ struct {
132
+ size_t increment;
133
+ struct heaps_slot *ptr;
134
+ struct heaps_slot *sweep_slots;
135
+ struct heaps_slot *free_slots;
136
+ struct sorted_heaps_slot *sorted;
137
+ size_t length;
138
+ size_t used;
139
+ struct heaps_free_bitmap *free_bitmap;
140
+ RVALUE *range[2];
141
+ RVALUE *freed;
142
+ size_t live_num;
143
+ size_t free_num;
144
+ size_t free_min;
145
+ size_t final_num;
146
+ size_t do_heap_free;
147
+ } heap;
148
+ struct {
149
+ int dont_gc;
150
+ int dont_lazy_sweep;
151
+ int during_gc;
152
+ rb_atomic_t finalizing;
153
+ } flags;
154
+ struct {
155
+ st_table *table;
156
+ RVALUE *deferred;
157
+ } final;
158
+ mark_stack_t mark_stack;
159
+ struct {
160
+ int run;
161
+ gc_profile_record *record;
162
+ size_t count;
163
+ size_t size;
164
+ double invoke_time;
165
+ } profile;
166
+ struct gc_list *global_list;
167
+ size_t count;
168
+ int gc_stress;
169
+
170
+ struct mark_func_data_struct {
171
+ void *data;
172
+ void (*mark_func)(VALUE v, void *data);
173
+ } *mark_func_data;
174
+ } rb_objspace_t;
175
+
176
+ #define malloc_limit objspace->malloc_params.limit
177
+ #define malloc_increase objspace->malloc_params.increase
178
+ #define heaps objspace->heap.ptr
179
+ #define heaps_length objspace->heap.length
180
+ #define heaps_used objspace->heap.used
181
+ #define lomem objspace->heap.range[0]
182
+ #define himem objspace->heap.range[1]
183
+ #define heaps_inc objspace->heap.increment
184
+ #define heaps_freed objspace->heap.freed
185
+ #define dont_gc objspace->flags.dont_gc
186
+ #define during_gc objspace->flags.during_gc
187
+ #define finalizing objspace->flags.finalizing
188
+ #define finalizer_table objspace->final.table
189
+ #define deferred_final_list objspace->final.deferred
190
+ #define global_List objspace->global_list
191
+ #define ruby_gc_stress objspace->gc_stress
192
+ #define initial_malloc_limit initial_params.initial_malloc_limit
193
+ #define initial_heap_min_slots initial_params.initial_heap_min_slots
194
+ #define initial_free_min initial_params.initial_free_min
195
+
196
+ #define is_lazy_sweeping(objspace) ((objspace)->heap.sweep_slots != 0)
197
+
198
+ #define nonspecial_obj_id(obj) (VALUE)((SIGNED_VALUE)(obj)|FIXNUM_FLAG)
199
+
200
+ #define RANY(o) ((RVALUE*)(o))
201
+ #define has_free_object (objspace->heap.free_slots && objspace->heap.free_slots->freelist)
202
+
203
+ #define HEAP_HEADER(p) ((struct heaps_header *)(p))
204
+ #define GET_HEAP_HEADER(x) (HEAP_HEADER((uintptr_t)(x) & ~(HEAP_ALIGN_MASK)))
205
+ #define GET_HEAP_SLOT(x) (GET_HEAP_HEADER(x)->base)
206
+ #define GET_HEAP_BITMAP(x) (GET_HEAP_HEADER(x)->bits)
207
+ #define NUM_IN_SLOT(p) (((uintptr_t)(p) & HEAP_ALIGN_MASK)/sizeof(RVALUE))
208
+ #define BITMAP_INDEX(p) (NUM_IN_SLOT(p) / (sizeof(uintptr_t) * CHAR_BIT))
209
+ #define BITMAP_OFFSET(p) (NUM_IN_SLOT(p) & ((sizeof(uintptr_t) * CHAR_BIT)-1))
210
+ #define MARKED_IN_BITMAP(bits, p) (bits[BITMAP_INDEX(p)] & ((uintptr_t)1 << BITMAP_OFFSET(p)))
211
+
212
+ //
213
+ #define RANY(o) ((RVALUE*)(o))
214
+ //
215
+
216
+ static inline int
217
+ is_pointer_to_heap(rb_objspace_t *objspace, void *ptr)
218
+ {
219
+ register RVALUE *p = RANY(ptr);
220
+ register struct sorted_heaps_slot *heap;
221
+ register size_t hi, lo, mid;
222
+
223
+ if (p < lomem || p > himem) return FALSE;
224
+ if ((VALUE)p % sizeof(RVALUE) != 0) return FALSE;
225
+
226
+ /* check if p looks like a pointer using bsearch*/
227
+ lo = 0;
228
+ hi = heaps_used;
229
+ while (lo < hi) {
230
+ mid = (lo + hi) / 2;
231
+ heap = &objspace->heap.sorted[mid];
232
+ if (heap->start <= p) {
233
+ if (p < heap->end)
234
+ return TRUE;
235
+ lo = mid + 1;
236
+ }
237
+ else {
238
+ hi = mid;
239
+ }
240
+ }
241
+ return FALSE;
242
+ }
243
+
244
+ //from count_objects:
245
+ #define FOR_EACH_HEAP_SLOT(p) for (i = 0; i < heaps_used; i++) {\
246
+ RVALUE *p = objspace->heap.sorted[i].start, *pend = objspace->heap.sorted[i].end;\
247
+ if(!p) continue;\
248
+ for (; p < pend; p++) {
249
+ #define FOR_EACH_HEAP_SLOT_END(total) } total += objspace->heap.sorted[i].slot->limit; }
250
+
251
+ #define NODE_OPTBLOCK 1000000 //FIXME
@@ -0,0 +1,109 @@
1
+ //FIXME: autogen this from ruby (this copied from 1.9.3p194)
2
+
3
+ // thread.c:
4
+ struct thgroup {
5
+ int enclosed;
6
+ VALUE group;
7
+ };
8
+
9
+ // enumerator.c:
10
+ struct enumerator {
11
+ VALUE obj;
12
+ ID meth;
13
+ VALUE args;
14
+ VALUE fib;
15
+ VALUE dst;
16
+ VALUE lookahead;
17
+ VALUE feedvalue;
18
+ VALUE stop_exc;
19
+ };
20
+
21
+ //
22
+ struct generator {
23
+ VALUE proc;
24
+ };
25
+
26
+ struct yielder {
27
+ VALUE proc;
28
+ };
29
+
30
+
31
+ // proc.c:
32
+ struct METHOD {
33
+ VALUE recv;
34
+ VALUE rclass;
35
+ VALUE defined_class; //FIXME: dump this
36
+ ID id;
37
+ rb_method_entry_t *me;
38
+ struct unlinked_method_entry_list_entry *ume;
39
+ };
40
+
41
+ //
42
+ #define METHOD_DEFINITIONP(m) (m->me ? m->me->def : NULL)
43
+
44
+ //class.c:
45
+ #define HAVE_RB_CLASS_TBL 1
46
+ //For som reason this fails to link directly on 1.9.3 :(
47
+
48
+ //HACK:
49
+ #include <dlfcn.h>
50
+
51
+ inline st_table * rb_get_class_tbl(){
52
+ Dl_info info;
53
+ void* image;
54
+ if(!dladdr(rb_intern, &info) || !info.dli_fname){
55
+ return NULL;
56
+ }
57
+ image = dlopen(info.dli_fname, RTLD_NOLOAD | RTLD_GLOBAL);
58
+ // printf("Image is %p, addr is %p (%p rel)\n", image, rb_intern, ((void*)rb_intern - image));
59
+ if(image)
60
+ {
61
+ void* tbl = dlsym(image, "_rb_class_tbl");
62
+ dlclose(image);
63
+ if(tbl)
64
+ return tbl;
65
+ }
66
+
67
+ //TODO: parse sym table and calculate address?
68
+
69
+ return NULL;
70
+ }
71
+
72
+ #define ruby_current_thread ((rb_thread_t *)RTYPEDDATA_DATA(rb_thread_current()))
73
+ #define GET_THREAD() ruby_current_thread
74
+
75
+ //FIXME: get global const for it: rb_define_global_const("RUBY_ENGINE", ruby_engine_name = MKSTR(engine));
76
+ #define ruby_engine_name Qnil
77
+
78
+ #define ID_ALLOCATOR 0
79
+
80
+ //vm_trace.c
81
+ typedef enum {
82
+ RUBY_HOOK_FLAG_SAFE = 0x01,
83
+ RUBY_HOOK_FLAG_DELETED = 0x02,
84
+ RUBY_HOOK_FLAG_RAW_ARG = 0x04
85
+ } rb_hook_flag_t;
86
+ typedef struct rb_event_hook_struct {
87
+ rb_hook_flag_t hook_flags;
88
+ rb_event_flag_t events;
89
+ rb_event_hook_func_t func;
90
+ VALUE data;
91
+ struct rb_event_hook_struct *next;
92
+ } rb_event_hook_t;
93
+
94
+ //vm_backtrace.c
95
+ inline static int
96
+ calc_lineno(const rb_iseq_t *iseq, const VALUE *pc)
97
+ {
98
+ return rb_iseq_line_no(iseq, pc - iseq->iseq_encoded);
99
+ }
100
+
101
+ int rb_vm_get_sourceline(const rb_control_frame_t * cfp){
102
+ int lineno = 0;
103
+ const rb_iseq_t *iseq = cfp->iseq;
104
+
105
+ if (RUBY_VM_NORMAL_ISEQ_P(iseq)) {
106
+ lineno = calc_lineno(cfp->iseq, cfp->pc);
107
+ }
108
+ return lineno;
109
+ }
@@ -1,3 +1,3 @@
1
1
  module HeapDump
2
- VERSION = "0.0.29"
2
+ VERSION = "0.0.30"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: heap_dump
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.29
4
+ version: 0.0.30
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-19 00:00:00.000000000 Z
12
+ date: 2012-11-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: debugger-ruby_core_source
@@ -82,6 +82,9 @@ files:
82
82
  - ext/heap_dump/specific/ruby-1.9.3/fiber.h
83
83
  - ext/heap_dump/specific/ruby-1.9.3/gc_internal.h
84
84
  - ext/heap_dump/specific/ruby-1.9.3/internal_typed_data.h
85
+ - ext/heap_dump/specific/ruby-2.0.0/fiber.h
86
+ - ext/heap_dump/specific/ruby-2.0.0/gc_internal.h
87
+ - ext/heap_dump/specific/ruby-2.0.0/internal_typed_data.h
85
88
  - heap_dump.gemspec
86
89
  - lib/heap_dump.rb
87
90
  - lib/heap_dump/version.rb
@@ -103,9 +106,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
103
106
  - - ! '>='
104
107
  - !ruby/object:Gem::Version
105
108
  version: '0'
106
- segments:
107
- - 0
108
- hash: -3423213544880593547
109
109
  requirements: []
110
110
  rubyforge_project:
111
111
  rubygems_version: 1.8.24
@@ -114,3 +114,4 @@ specification_version: 3
114
114
  summary: Allows to dump heap to track reference leaks, including leaks in proc contexts
115
115
  and fibers
116
116
  test_files: []
117
+ has_rdoc: