heap_dump 0.0.28 → 0.0.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +80 -28
 - data/Rakefile +4 -1
 - data/ext/heap_dump/heap_dump.c +319 -162
 - data/ext/heap_dump/specific/ruby-1.9.2/gc_internal.h +8 -16
 - data/ext/heap_dump/specific/ruby-1.9.2/internal_typed_data.h +34 -2
 - data/ext/heap_dump/specific/ruby-1.9.3/gc_internal.h +7 -0
 - data/ext/heap_dump/specific/ruby-1.9.3/internal_typed_data.h +33 -3
 - data/lib/heap_dump/version.rb +1 -1
 - data/lib/heap_dump.rb +14 -0
 - metadata +3 -3
 
    
        data/README.md
    CHANGED
    
    | 
         @@ -24,6 +24,7 @@ Or install it yourself as: 
     | 
|
| 
       24 
24 
     | 
    
         | 
| 
       25 
25 
     | 
    
         
             
            ## Usage
         
     | 
| 
       26 
26 
     | 
    
         | 
| 
      
 27 
     | 
    
         
            +
            ### Dumping heap references
         
     | 
| 
       27 
28 
     | 
    
         
             
            In your code call:
         
     | 
| 
       28 
29 
     | 
    
         | 
| 
       29 
30 
     | 
    
         
             
            ```ruby
         
     | 
| 
         @@ -34,6 +35,77 @@ HeapDump.dump 
     | 
|
| 
       34 
35 
     | 
    
         
             
            this will run GC and then create a dump.json with live heap contents.
         
     | 
| 
       35 
36 
     | 
    
         
             
            Json contains one object per line, thus can be easily grepped.
         
     | 
| 
       36 
37 
     | 
    
         | 
| 
      
 38 
     | 
    
         
            +
            #### Output example/format
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
            Format is not stable yet, but looks like this:
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            ```json
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            [{"id":"_ROOTS_","stack_and_registers":[70313628419480,70313628419480,70313628419480,"trace",70313627751860],"classes":[70313627319820,70313628530860]}
         
     | 
| 
      
 45 
     | 
    
         
            +
            ,{"id":70365602702620,"bt":"T_ARRAY","val":[">=",70365602705060]}
         
     | 
| 
      
 46 
     | 
    
         
            +
            ,{"id":70365602847060,"bt":"T_ARRAY","val":[]}
         
     | 
| 
      
 47 
     | 
    
         
            +
            ,{"id":70365602702660,"bt":"T_DATA","type_name":"iseq","size":564,"name":"activate_spec","filename":"/Users/vasfed/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/site_ruby/1.9.1/rubygems.rb","line":485,"type":"method","refs_array_id":70365602847060,"coverage":null,"klass":70365602821240,"cref_stack":70365602848300,"defined_method_id":12672}
         
     | 
| 
      
 48 
     | 
    
         
            +
            ,{"id":70365602702680,"bt":"T_STRING","val":"activate_spec"}
         
     | 
| 
      
 49 
     | 
    
         
            +
            ,{"id":70365602821260,"bt":"T_HASH","val":{"EXEEXT":"","RUBY_SO_NAME":"ruby.1.9.1","arch":"x86_64-darwin11.2.0","bindir":70365603049640,"libdir":70365603050600,"ruby_install_name":"ruby","ruby_version":"1.9.1","rubylibprefix":70365603112080,"sitedir":70365603112440,"sitelibdir":70365603048920,"datadir":70365603049880,"vendordir":70365603112500,"vendorlibdir":70365603048800}}
         
     | 
| 
      
 50 
     | 
    
         
            +
            ,{"id":70365602712560,"bt":"T_CLASS","name":"URI::HTTPS","methods":{},"ivs":{"__classpath__":"URI::HTTPS","DEFAULT_PORT":443},"super":70365602771440}
         
     | 
| 
      
 51 
     | 
    
         
            +
            ,{"id":70365602771400,"bt":"T_CLASS","name":"Class","methods":{"build":70365602782860},"ivs":{"__attached__":70365602771440},"super":70365611597900}
         
     | 
| 
      
 52 
     | 
    
         
            +
            ,{"id":70365602717060,"bt":"T_DATA","type_name":"proc","size":72,"is_lambda":0,"blockprocval":null,"envval":70365602712440,"iseq":{"id":70365600821896,"name":"block in <class:FileList>","filename":"/Users/vasfed/.rvm/gems/ruby-1.9.2-p290/gems/rake-0.9.2.2/lib/rake/file_list.rb","line":743,"type":"block","refs_array_id":70365611724600,"coverage":null,"klass":null,"cref_stack":70365611799480,"defined_method_id":0}}
         
     | 
| 
      
 53 
     | 
    
         
            +
            ,{"id":70365603045160,"bt":"T_DATA","type_name":"VM/env","size":128,"refs":[]}
         
     | 
| 
      
 54 
     | 
    
         
            +
            ,{"id":70365613258980,"bt":"T_ICLASS","name":"Object","methods":{"==":"(CFUNC)",">":"(CFUNC)",">=":"(CFUNC)","<":"(CFUNC)","<=":"(CFUNC)","between?":"(CFUNC)"},"ivs":{"__classid__":"Comparable"},"super":70365613259120}
         
     | 
| 
      
 55 
     | 
    
         
            +
            ,{"id":70151795145340,"bt":"T_DATA","type_name":"proc","size":72,"is_lambda":0,"blockprocval":null,"envval":70151795224840,"iseq":{"id":70151828020360,"name":"block in subscribe","filename":"/Users/vasfed/acceptor.rb","line":91,"type":"block","refs_array_id":70151796420080,"coverage":null,"klass":null,"cref_stack":70151796421080,"defined_method_id":0}}
         
     | 
| 
      
 56 
     | 
    
         
            +
            ,{"id":70151795224840,"bt":"T_DATA","type_name":"VM/env","size":120,"refs":[70151806738200,70151796176180,"string1",null,0,70151795224840,null]}
         
     | 
| 
      
 57 
     | 
    
         
            +
            ]
         
     | 
| 
      
 58 
     | 
    
         
            +
            ```
         
     | 
| 
      
 59 
     | 
    
         
            +
            etc.
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
            bt field is ruby builtin type name.
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
            Where available - val/refs/ivs/etc. field present with hash/array of references.
         
     | 
| 
      
 64 
     | 
    
         
            +
            Long numbers usually are object ids.
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
            ### Counting objects in heap
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
            Also heap_dump now includes an object counter, like `ObjectSpace.count_objects`, but capable of counting objects from your namespace
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
            HeapDump.count_objects :YourNameSpace # => json string
         
     | 
| 
      
 73 
     | 
    
         
            +
            ```
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
            which results in something like:
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
            ```json
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
            {
         
     | 
| 
      
 80 
     | 
    
         
            +
                "total_slots": 56419,
         
     | 
| 
      
 81 
     | 
    
         
            +
                "free_slots": 12384,
         
     | 
| 
      
 82 
     | 
    
         
            +
                "basic_types": {
         
     | 
| 
      
 83 
     | 
    
         
            +
                    "T_OBJECT": 1945,
         
     | 
| 
      
 84 
     | 
    
         
            +
                    "T_CLASS": 931,
         
     | 
| 
      
 85 
     | 
    
         
            +
                    "T_MODULE": 68,
         
     | 
| 
      
 86 
     | 
    
         
            +
                    "T_FLOAT": 24,
         
     | 
| 
      
 87 
     | 
    
         
            +
                    "T_STRING": 26557,
         
     | 
| 
      
 88 
     | 
    
         
            +
                    "T_REGEXP": 346,
         
     | 
| 
      
 89 
     | 
    
         
            +
                    "T_ARRAY": 6556,
         
     | 
| 
      
 90 
     | 
    
         
            +
                    "T_HASH": 159,
         
     | 
| 
      
 91 
     | 
    
         
            +
                    "T_STRUCT": 45,
         
     | 
| 
      
 92 
     | 
    
         
            +
                    "T_BIGNUM": 2,
         
     | 
| 
      
 93 
     | 
    
         
            +
                    "T_FILE": 6,
         
     | 
| 
      
 94 
     | 
    
         
            +
                    "T_DATA": 3516,
         
     | 
| 
      
 95 
     | 
    
         
            +
                    "T_MATCH": 15,
         
     | 
| 
      
 96 
     | 
    
         
            +
                    "T_COMPLEX": 1,
         
     | 
| 
      
 97 
     | 
    
         
            +
                    "T_RATIONAL": 10,
         
     | 
| 
      
 98 
     | 
    
         
            +
                    "T_NODE": 3754,
         
     | 
| 
      
 99 
     | 
    
         
            +
                    "T_ICLASS": 100
         
     | 
| 
      
 100 
     | 
    
         
            +
                },
         
     | 
| 
      
 101 
     | 
    
         
            +
                "user_types": {
         
     | 
| 
      
 102 
     | 
    
         
            +
                    "YourNameSpace::B": 2,
         
     | 
| 
      
 103 
     | 
    
         
            +
                    "YourNameSpace::A": 3
         
     | 
| 
      
 104 
     | 
    
         
            +
                }
         
     | 
| 
      
 105 
     | 
    
         
            +
            }
         
     | 
| 
      
 106 
     | 
    
         
            +
            ```
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
       37 
109 
     | 
    
         
             
            ### Injecting into live process via GDB
         
     | 
| 
       38 
110 
     | 
    
         | 
| 
       39 
111 
     | 
    
         
             
            For long-running applications common and recommended usecase is to have some kind of custom action or signal handler in app itself that invokes dump.
         
     | 
| 
         @@ -71,34 +143,6 @@ cat dump.json | sed 's/^[,\[]//;s/\]$//;s/^{"id"/{"_id"/' | mongoimport -d datab 
     | 
|
| 
       71 
143 
     | 
    
         
             
            Note that even small dumps usually contain a few hundred thousands objects, so do not forget to add some indexes.
         
     | 
| 
       72 
144 
     | 
    
         | 
| 
       73 
145 
     | 
    
         | 
| 
       74 
     | 
    
         
            -
            ### Output example/format
         
     | 
| 
       75 
     | 
    
         
            -
             
     | 
| 
       76 
     | 
    
         
            -
            Format is not stable yet, but looks like this:
         
     | 
| 
       77 
     | 
    
         
            -
             
     | 
| 
       78 
     | 
    
         
            -
            ```json
         
     | 
| 
       79 
     | 
    
         
            -
             
     | 
| 
       80 
     | 
    
         
            -
            [{"id":"_ROOTS_","stack_and_registers":[70313628419480,70313628419480,70313628419480,"trace",70313627751860],"classes":[70313627319820,70313628530860]}
         
     | 
| 
       81 
     | 
    
         
            -
            ,{"id":70365602702620,"bt":"T_ARRAY","val":[">=",70365602705060]}
         
     | 
| 
       82 
     | 
    
         
            -
            ,{"id":70365602847060,"bt":"T_ARRAY","val":[]}
         
     | 
| 
       83 
     | 
    
         
            -
            ,{"id":70365602702660,"bt":"T_DATA","type_name":"iseq","size":564,"name":"activate_spec","filename":"/Users/vasfed/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/site_ruby/1.9.1/rubygems.rb","line":485,"type":"method","refs_array_id":70365602847060,"coverage":null,"klass":70365602821240,"cref_stack":70365602848300,"defined_method_id":12672}
         
     | 
| 
       84 
     | 
    
         
            -
            ,{"id":70365602702680,"bt":"T_STRING","val":"activate_spec"}
         
     | 
| 
       85 
     | 
    
         
            -
            ,{"id":70365602821260,"bt":"T_HASH","val":{"EXEEXT":"","RUBY_SO_NAME":"ruby.1.9.1","arch":"x86_64-darwin11.2.0","bindir":70365603049640,"libdir":70365603050600,"ruby_install_name":"ruby","ruby_version":"1.9.1","rubylibprefix":70365603112080,"sitedir":70365603112440,"sitelibdir":70365603048920,"datadir":70365603049880,"vendordir":70365603112500,"vendorlibdir":70365603048800}}
         
     | 
| 
       86 
     | 
    
         
            -
            ,{"id":70365602712560,"bt":"T_CLASS","name":"URI::HTTPS","methods":{},"ivs":{"__classpath__":"URI::HTTPS","DEFAULT_PORT":443},"super":70365602771440}
         
     | 
| 
       87 
     | 
    
         
            -
            ,{"id":70365602771400,"bt":"T_CLASS","name":"Class","methods":{"build":70365602782860},"ivs":{"__attached__":70365602771440},"super":70365611597900}
         
     | 
| 
       88 
     | 
    
         
            -
            ,{"id":70365602717060,"bt":"T_DATA","type_name":"proc","size":72,"is_lambda":0,"blockprocval":null,"envval":70365602712440,"iseq":{"id":70365600821896,"name":"block in <class:FileList>","filename":"/Users/vasfed/.rvm/gems/ruby-1.9.2-p290/gems/rake-0.9.2.2/lib/rake/file_list.rb","line":743,"type":"block","refs_array_id":70365611724600,"coverage":null,"klass":null,"cref_stack":70365611799480,"defined_method_id":0}}
         
     | 
| 
       89 
     | 
    
         
            -
            ,{"id":70365603045160,"bt":"T_DATA","type_name":"VM/env","size":128,"refs":[]}
         
     | 
| 
       90 
     | 
    
         
            -
            ,{"id":70365613258980,"bt":"T_ICLASS","name":"Object","methods":{"==":"(CFUNC)",">":"(CFUNC)",">=":"(CFUNC)","<":"(CFUNC)","<=":"(CFUNC)","between?":"(CFUNC)"},"ivs":{"__classid__":"Comparable"},"super":70365613259120}
         
     | 
| 
       91 
     | 
    
         
            -
            ,{"id":70151795145340,"bt":"T_DATA","type_name":"proc","size":72,"is_lambda":0,"blockprocval":null,"envval":70151795224840,"iseq":{"id":70151828020360,"name":"block in subscribe","filename":"/Users/vasfed/acceptor.rb","line":91,"type":"block","refs_array_id":70151796420080,"coverage":null,"klass":null,"cref_stack":70151796421080,"defined_method_id":0}}
         
     | 
| 
       92 
     | 
    
         
            -
            ,{"id":70151795224840,"bt":"T_DATA","type_name":"VM/env","size":120,"refs":[70151806738200,70151796176180,"string1",null,0,70151795224840,null]}
         
     | 
| 
       93 
     | 
    
         
            -
            ]
         
     | 
| 
       94 
     | 
    
         
            -
            ```
         
     | 
| 
       95 
     | 
    
         
            -
            etc.
         
     | 
| 
       96 
     | 
    
         
            -
             
     | 
| 
       97 
     | 
    
         
            -
            bt field is ruby builtin type name.
         
     | 
| 
       98 
     | 
    
         
            -
             
     | 
| 
       99 
     | 
    
         
            -
            Where available - val/refs/ivs/etc. field present with hash/array of references.
         
     | 
| 
       100 
     | 
    
         
            -
            Long numbers usually are object ids.
         
     | 
| 
       101 
     | 
    
         
            -
             
     | 
| 
       102 
146 
     | 
    
         
             
            ## What may leak
         
     | 
| 
       103 
147 
     | 
    
         | 
| 
       104 
148 
     | 
    
         
             
            ### Brief Ruby GC decription
         
     | 
| 
         @@ -126,6 +170,14 @@ Obvious references: from variables, instance variables (including class), arrays 
     | 
|
| 
       126 
170 
     | 
    
         
             
            Less obvious: method closures. These are stored in T_DATAs with 'VM/env' type.
         
     | 
| 
       127 
171 
     | 
    
         
             
            Latest version of heap_dump allows to trace such references: search for a env, by it's id you can find it's owner iseq, which usually has file and line number where block/lambda/proc was created.
         
     | 
| 
       128 
172 
     | 
    
         | 
| 
      
 173 
     | 
    
         
            +
            ## Hints on finding leaks
         
     | 
| 
      
 174 
     | 
    
         
            +
             
     | 
| 
      
 175 
     | 
    
         
            +
            Usually it's a good practice first to detect leaking type by running several `HeapDump.count_objects` while making some load on your app and comparing results. Note objects that may be reasons for others to linger in memory according to your architecture (for example - something like "session"/"incoming connection"/"delayed job" etc.).
         
     | 
| 
      
 176 
     | 
    
         
            +
             
     | 
| 
      
 177 
     | 
    
         
            +
            Then make a full dump and inspect references to those objects.
         
     | 
| 
      
 178 
     | 
    
         
            +
             
     | 
| 
      
 179 
     | 
    
         
            +
            Note that heapdump operates only on process it has been called on, so if you have multiple workers (Unicorn/Rainbows/Passenger spawned processes etc.) - you may run into a situation when request for dump is not routed to process you're interested in.
         
     | 
| 
      
 180 
     | 
    
         
            +
             
     | 
| 
       129 
181 
     | 
    
         
             
            ## Contributing
         
     | 
| 
       130 
182 
     | 
    
         | 
| 
       131 
183 
     | 
    
         
             
            1. Fork it
         
     | 
    
        data/Rakefile
    CHANGED
    
    | 
         @@ -37,8 +37,11 @@ task :test => :compile do 
     | 
|
| 
       37 
37 
     | 
    
         
             
                  Fiber.yield e
         
     | 
| 
       38 
38 
     | 
    
         
             
                  fiber_var = :some_fiber_var3
         
     | 
| 
       39 
39 
     | 
    
         
             
                }.resume
         
     | 
| 
       40 
     | 
    
         
            -
               
     | 
| 
      
 40 
     | 
    
         
            +
              $some_global = "value_global"
         
     | 
| 
      
 41 
     | 
    
         
            +
              puts "Dumping...(rake)"
         
     | 
| 
      
 42 
     | 
    
         
            +
              HeapDump.verbose = true
         
     | 
| 
       41 
43 
     | 
    
         
             
              HeapDump.dump
         
     | 
| 
      
 44 
     | 
    
         
            +
              puts "Done"
         
     | 
| 
       42 
45 
     | 
    
         
             
            end
         
     | 
| 
       43 
46 
     | 
    
         | 
| 
       44 
47 
     | 
    
         
             
            task :default => :test
         
     | 
    
        data/ext/heap_dump/heap_dump.c
    CHANGED
    
    | 
         @@ -47,6 +47,7 @@ 
     | 
|
| 
       47 
47 
     | 
    
         | 
| 
       48 
48 
     | 
    
         
             
            // simple test - rake compile && bundle exec ruby -e 'require "heap_dump"; HeapDump.dump'
         
     | 
| 
       49 
49 
     | 
    
         | 
| 
      
 50 
     | 
    
         
            +
            #include <dlfcn.h>
         
     | 
| 
       50 
51 
     | 
    
         | 
| 
       51 
52 
     | 
    
         
             
            #ifdef HAVE_GC_INTERNAL_H
         
     | 
| 
       52 
53 
     | 
    
         
             
            #include "gc_internal.h"
         
     | 
| 
         @@ -64,12 +65,16 @@ static VALUE rb_mHeapDumpModule; 
     | 
|
| 
       64 
65 
     | 
    
         
             
            static ID classid;
         
     | 
| 
       65 
66 
     | 
    
         | 
| 
       66 
67 
     | 
    
         
             
            //shortcuts to yajl
         
     | 
| 
       67 
     | 
    
         
            -
            #define  
     | 
| 
      
 68 
     | 
    
         
            +
            #define YAJL ctx->yajl
         
     | 
| 
      
 69 
     | 
    
         
            +
            #define yg_string(str,len) yajl_gen_string(YAJL, str, len)
         
     | 
| 
       68 
70 
     | 
    
         
             
            #define yg_cstring(str) yg_string(str, (unsigned int)strlen(str))
         
     | 
| 
       69 
71 
     | 
    
         
             
            #define yg_rstring(str) yg_string(RSTRING_PTR(str), (unsigned int)RSTRING_LEN(str))
         
     | 
| 
       70 
     | 
    
         
            -
            #define yg_int(i) yajl_gen_integer( 
     | 
| 
       71 
     | 
    
         
            -
            #define yg_double(d) (yajl_gen_double( 
     | 
| 
       72 
     | 
    
         
            -
            #define yg_null() yajl_gen_null( 
     | 
| 
      
 72 
     | 
    
         
            +
            #define yg_int(i) yajl_gen_integer(YAJL, i)
         
     | 
| 
      
 73 
     | 
    
         
            +
            #define yg_double(d) (yajl_gen_double(YAJL, d)==yajl_gen_invalid_number? yg_cstring("inf|NaN") : true)
         
     | 
| 
      
 74 
     | 
    
         
            +
            #define yg_null() yajl_gen_null(YAJL)
         
     | 
| 
      
 75 
     | 
    
         
            +
            #define yg_bool(b) yajl_gen_bool(YAJL, b);
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
            #define yg_funcaddr(addr) yg_funcaddr_real(ctx, addr)
         
     | 
| 
       73 
78 
     | 
    
         | 
| 
       74 
79 
     | 
    
         
             
            //#define yg_id(obj) yg_int(NUM2LONG(rb_obj_id(obj)))
         
     | 
| 
       75 
80 
     | 
    
         
             
            #define yg_id(obj) yg_id1(obj,ctx)
         
     | 
| 
         @@ -82,10 +87,10 @@ static ID classid; 
     | 
|
| 
       82 
87 
     | 
    
         
             
            #define ygh_cstring(key,str) {yg_cstring(key); yg_cstring(str);}
         
     | 
| 
       83 
88 
     | 
    
         
             
            #define ygh_rstring(key,str) {yg_cstring(key); yg_rstring(str);}
         
     | 
| 
       84 
89 
     | 
    
         | 
| 
       85 
     | 
    
         
            -
            #define yg_map() yajl_gen_map_open( 
     | 
| 
       86 
     | 
    
         
            -
            #define yg_map_end() yajl_gen_map_close( 
     | 
| 
       87 
     | 
    
         
            -
            #define yg_array() yajl_gen_array_open( 
     | 
| 
       88 
     | 
    
         
            -
            #define yg_array_end() yajl_gen_array_close( 
     | 
| 
      
 90 
     | 
    
         
            +
            #define yg_map() yajl_gen_map_open(YAJL);
         
     | 
| 
      
 91 
     | 
    
         
            +
            #define yg_map_end() yajl_gen_map_close(YAJL);
         
     | 
| 
      
 92 
     | 
    
         
            +
            #define yg_array() yajl_gen_array_open(YAJL);
         
     | 
| 
      
 93 
     | 
    
         
            +
            #define yg_array_end() yajl_gen_array_close(YAJL);
         
     | 
| 
       89 
94 
     | 
    
         | 
| 
       90 
95 
     | 
    
         | 
| 
       91 
96 
     | 
    
         
             
            // context for objectspace_walker callback
         
     | 
| 
         @@ -138,6 +143,15 @@ static inline const char* rb_builtin_type(VALUE obj){ 
     | 
|
| 
       138 
143 
     | 
    
         
             
            #define true 1
         
     | 
| 
       139 
144 
     | 
    
         
             
            #define false 0
         
     | 
| 
       140 
145 
     | 
    
         | 
| 
      
 146 
     | 
    
         
            +
            static void yg_funcaddr_real(walk_ctx_t* ctx, void* addr){
         
     | 
| 
      
 147 
     | 
    
         
            +
              Dl_info info;
         
     | 
| 
      
 148 
     | 
    
         
            +
              if(dladdr(addr, &info) && info.dli_sname){
         
     | 
| 
      
 149 
     | 
    
         
            +
                yg_cstring(info.dli_sname);
         
     | 
| 
      
 150 
     | 
    
         
            +
              } else {
         
     | 
| 
      
 151 
     | 
    
         
            +
                yg_cstring("(unknown)");
         
     | 
| 
      
 152 
     | 
    
         
            +
              }
         
     | 
| 
      
 153 
     | 
    
         
            +
            }
         
     | 
| 
      
 154 
     | 
    
         
            +
             
     | 
| 
       141 
155 
     | 
    
         
             
            //FIXME: handle non-ids?
         
     | 
| 
       142 
156 
     | 
    
         
             
            static void yg_id1(VALUE obj, walk_ctx_t* ctx){
         
     | 
| 
       143 
157 
     | 
    
         
             
              if(!obj) {
         
     | 
| 
         @@ -145,23 +159,17 @@ static void yg_id1(VALUE obj, walk_ctx_t* ctx){ 
     | 
|
| 
       145 
159 
     | 
    
         
             
                return;
         
     | 
| 
       146 
160 
     | 
    
         
             
              }
         
     | 
| 
       147 
161 
     | 
    
         
             
              if (IMMEDIATE_P(obj)) {
         
     | 
| 
       148 
     | 
    
         
            -
                 
     | 
| 
       149 
     | 
    
         
            -
                if (FIXNUM_P(obj)) { /*ignore immediate fixnum*/
         
     | 
| 
       150 
     | 
    
         
            -
                  //fixme: output some readable info
         
     | 
| 
       151 
     | 
    
         
            -
                  //yajl_gen_null(ctx->yajl);
         
     | 
| 
      
 162 
     | 
    
         
            +
                if (FIXNUM_P(obj)) {
         
     | 
| 
       152 
163 
     | 
    
         
             
                  yg_int(FIX2LONG(obj));
         
     | 
| 
       153 
164 
     | 
    
         
             
                  return;
         
     | 
| 
       154 
165 
     | 
    
         
             
                }
         
     | 
| 
       155 
166 
     | 
    
         
             
                if (obj == Qtrue){ yajl_gen_bool(ctx->yajl, true); return; }
         
     | 
| 
       156 
167 
     | 
    
         
             
                if (SYMBOL_P(obj)) {
         
     | 
| 
       157 
     | 
    
         
            -
                  //printf("symbol\n");
         
     | 
| 
       158 
168 
     | 
    
         
             
                  yg_cstring(rb_id2name(SYM2ID(obj)));
         
     | 
| 
       159 
     | 
    
         
            -
                  //printf("symbol %s\n", rb_id2name(SYM2ID(obj)));
         
     | 
| 
       160 
169 
     | 
    
         
             
                  return;
         
     | 
| 
       161 
170 
     | 
    
         
             
                }
         
     | 
| 
       162 
171 
     | 
    
         
             
                if (obj == Qundef) { yg_cstring("(undef)"); return; }
         
     | 
| 
       163 
172 
     | 
    
         | 
| 
       164 
     | 
    
         
            -
                printf("immediate p %p?\n", (void*)obj);
         
     | 
| 
       165 
173 
     | 
    
         
             
                yg_cstring("(unknown)");
         
     | 
| 
       166 
174 
     | 
    
         
             
                return;
         
     | 
| 
       167 
175 
     | 
    
         
             
              } else /*non-immediate*/ {
         
     | 
| 
         @@ -174,26 +182,11 @@ static void yg_id1(VALUE obj, walk_ctx_t* ctx){ 
     | 
|
| 
       174 
182 
     | 
    
         
             
                    yajl_gen_bool(ctx->yajl, false);
         
     | 
| 
       175 
183 
     | 
    
         
             
                    return;
         
     | 
| 
       176 
184 
     | 
    
         
             
                  }
         
     | 
| 
       177 
     | 
    
         
            -
                  //printf("non r-test\n");
         
     | 
| 
       178 
185 
     | 
    
         
             
                }
         
     | 
| 
       179 
186 
     | 
    
         
             
              }
         
     | 
| 
       180 
187 
     | 
    
         | 
| 
       181 
     | 
    
         
            -
              //25116(0x621c aka 0b110001000011100), 28(0x) - wtf?
         
     | 
| 
       182 
     | 
    
         
            -
              //28 = 0x1c
         
     | 
| 
       183 
     | 
    
         
            -
              //1c= TNODE? or other flags combination
         
     | 
| 
       184 
     | 
    
         
            -
             
     | 
| 
       185 
     | 
    
         
            -
              //also 30(x1e) ? - some internal symbols?
         
     | 
| 
       186 
     | 
    
         
            -
             
     | 
| 
       187 
     | 
    
         
            -
              // if((obj & ~(~(VALUE)0 << RUBY_SPECIAL_SHIFT)) == 0x1c){
         
     | 
| 
       188 
     | 
    
         
            -
              //   printf("!!!!! special shift flags is 0x1c: %p\n", obj);
         
     | 
| 
       189 
     | 
    
         
            -
              //   yg_cstring("(unknown or internal 1c)");
         
     | 
| 
       190 
     | 
    
         
            -
              //   return;
         
     | 
| 
       191 
     | 
    
         
            -
              // }
         
     | 
| 
       192 
     | 
    
         
            -
             
     | 
| 
       193 
188 
     | 
    
         
             
              if(BUILTIN_TYPE(obj) == T_STRING && (!(RBASIC(obj)->flags & RSTRING_NOEMBED))){
         
     | 
| 
       194 
     | 
    
         
            -
                // 
     | 
| 
       195 
     | 
    
         
            -
                //yajl_gen_null(ctx->yajl);
         
     | 
| 
       196 
     | 
    
         
            -
             
     | 
| 
      
 189 
     | 
    
         
            +
                //embedded string
         
     | 
| 
       197 
190 
     | 
    
         
             
                if(rb_enc_get_index(obj) == rb_usascii_encindex())
         
     | 
| 
       198 
191 
     | 
    
         
             
                  yg_rstring(obj);
         
     | 
| 
       199 
192 
     | 
    
         
             
                else{
         
     | 
| 
         @@ -319,14 +312,14 @@ static void dump_node_refs(NODE* obj, walk_ctx_t* ctx){ 
     | 
|
| 
       319 
312 
     | 
    
         
             
                  return; //goto again;
         
     | 
| 
       320 
313 
     | 
    
         | 
| 
       321 
314 
     | 
    
         
             
                case NODE_SCOPE:  /* 2,3 */ //ANN("format: [nd_tbl]: local table, [nd_args]: arguments, [nd_body]: body");
         
     | 
| 
       322 
     | 
    
         
            -
                  // 
     | 
| 
      
 315 
     | 
    
         
            +
                  //actually this is not present in live ruby 1.9+
         
     | 
| 
       323 
316 
     | 
    
         
             
                  if(obj->nd_tbl){
         
     | 
| 
       324 
317 
     | 
    
         
             
                    ID *tbl = RNODE(obj)->nd_tbl;
         
     | 
| 
       325 
318 
     | 
    
         
             
                    unsigned long i = 0, size = tbl[0];
         
     | 
| 
       326 
319 
     | 
    
         
             
                    tbl++;
         
     | 
| 
       327 
320 
     | 
    
         
             
                    for (; i < size; i++) {
         
     | 
| 
       328 
321 
     | 
    
         
             
                      //TODO: dump local var names?
         
     | 
| 
       329 
     | 
    
         
            -
                      // 
     | 
| 
      
 322 
     | 
    
         
            +
                      // rb_id2name(tbl[i])...
         
     | 
| 
       330 
323 
     | 
    
         
             
                      //yg_id(tbl[i]); //FIXME: these are ids, not values
         
     | 
| 
       331 
324 
     | 
    
         
             
                    }
         
     | 
| 
       332 
325 
     | 
    
         
             
                  }
         
     | 
| 
         @@ -399,7 +392,6 @@ static void dump_node_refs(NODE* obj, walk_ctx_t* ctx){ 
     | 
|
| 
       399 
392 
     | 
    
         | 
| 
       400 
393 
     | 
    
         
             
                case NODE_MEMO:
         
     | 
| 
       401 
394 
     | 
    
         
             
                  yg_id((VALUE)obj->u1.node);
         
     | 
| 
       402 
     | 
    
         
            -
                  //printf("MEMO NODE: %p %p %p\n", obj->u1.node, obj->u2.node, obj->u3.node);
         
     | 
| 
       403 
395 
     | 
    
         
             
                  break;
         
     | 
| 
       404 
396 
     | 
    
         | 
| 
       405 
397 
     | 
    
         
             
                //not implemented:
         
     | 
| 
         @@ -416,14 +408,15 @@ static void dump_node_refs(NODE* obj, walk_ctx_t* ctx){ 
     | 
|
| 
       416 
408 
     | 
    
         | 
| 
       417 
409 
     | 
    
         
             
                //iteration func - blocks,procs,lambdas etc:
         
     | 
| 
       418 
410 
     | 
    
         
             
                case NODE_IFUNC: //NEN_CFNC, NEN_TVAL, NEN_STATE? / u2 seems to be data for func(context?)
         
     | 
| 
       419 
     | 
    
         
            -
                   
     | 
| 
      
 411 
     | 
    
         
            +
                  {
         
     | 
| 
      
 412 
     | 
    
         
            +
                    //find in symbol table, if present:
         
     | 
| 
      
 413 
     | 
    
         
            +
                    yg_funcaddr(obj->nd_cfnc);
         
     | 
| 
      
 414 
     | 
    
         
            +
                  }
         
     | 
| 
       420 
415 
     | 
    
         
             
                  if(is_in_heap(obj->u2.node, 0)){
         
     | 
| 
       421 
     | 
    
         
            -
                    //printf("in heap: %p\n", obj->u2.node);
         
     | 
| 
       422 
416 
     | 
    
         
             
                    //TODO: do we need to dump it inline?
         
     | 
| 
       423 
417 
     | 
    
         
             
                    yg_id((VALUE)obj->u2.node);
         
     | 
| 
       424 
418 
     | 
    
         
             
                  }
         
     | 
| 
       425 
419 
     | 
    
         
             
                  if(is_in_heap( (void*)obj->nd_aid, 0)){
         
     | 
| 
       426 
     | 
    
         
            -
                    //printf("in heap: %p\n", (void*)obj->nd_aid);
         
     | 
| 
       427 
420 
     | 
    
         
             
                    yg_id(obj->nd_aid);
         
     | 
| 
       428 
421 
     | 
    
         
             
                  }
         
     | 
| 
       429 
422 
     | 
    
         
             
                  break;
         
     | 
| 
         @@ -432,11 +425,7 @@ static void dump_node_refs(NODE* obj, walk_ctx_t* ctx){ 
     | 
|
| 
       432 
425 
     | 
    
         
             
                case NODE_BEGIN: break;
         
     | 
| 
       433 
426 
     | 
    
         
             
                default:    /* unlisted NODE */
         
     | 
| 
       434 
427 
     | 
    
         
             
                  //FIXME: check pointers!
         
     | 
| 
       435 
     | 
    
         
            -
             
     | 
| 
       436 
     | 
    
         
            -
                  {
         
     | 
| 
       437 
     | 
    
         
            -
                  printf("UNKNOWN NODE TYPE %d(%s): %p %p %p\n", nd_type(obj), node_type_name(obj), (void*)obj->u1.node, (void*)obj->u2.node, (void*)obj->u3.node);
         
     | 
| 
       438 
     | 
    
         
            -
                  }
         
     | 
| 
       439 
     | 
    
         
            -
             
     | 
| 
      
 428 
     | 
    
         
            +
                  {}
         
     | 
| 
       440 
429 
     | 
    
         
             
                  // if (is_in_heap(obj->as.node.u1.node, objspace)) { gc_mark(objspace, (VALUE)obj->as.node.u1.node, lev); }
         
     | 
| 
       441 
430 
     | 
    
         
             
                  // if (is_in_heap(obj->as.node.u2.node, objspace)) { gc_mark(objspace, (VALUE)obj->as.node.u2.node, lev); }
         
     | 
| 
       442 
431 
     | 
    
         
             
                  // if (is_in_heap(obj->as.node.u3.node, objspace)) { gc_mark(objspace, (VALUE)obj->as.node.u3.node, lev); }
         
     | 
| 
         @@ -459,11 +448,6 @@ static inline void dump_node(NODE* obj, walk_ctx_t *ctx){ 
     | 
|
| 
       459 
448 
     | 
    
         | 
| 
       460 
449 
     | 
    
         
             
            static int
         
     | 
| 
       461 
450 
     | 
    
         
             
            dump_keyvalue(st_data_t key, st_data_t value, walk_ctx_t *ctx){
         
     | 
| 
       462 
     | 
    
         
            -
                if ((VALUE)key == Qundef){
         
     | 
| 
       463 
     | 
    
         
            -
                  printf("undef key!\n");
         
     | 
| 
       464 
     | 
    
         
            -
                  // return ST_CONTINUE;
         
     | 
| 
       465 
     | 
    
         
            -
                }
         
     | 
| 
       466 
     | 
    
         
            -
             
     | 
| 
       467 
451 
     | 
    
         
             
                if(!key || (VALUE)key == Qnil){
         
     | 
| 
       468 
452 
     | 
    
         
             
                  yg_cstring("___null_key___"); //TODO: just ""?
         
     | 
| 
       469 
453 
     | 
    
         
             
                } else {
         
     | 
| 
         @@ -477,7 +461,7 @@ dump_keyvalue(st_data_t key, st_data_t value, walk_ctx_t *ctx){ 
     | 
|
| 
       477 
461 
     | 
    
         
             
                      buf[sizeof(buf)-1] = 0;
         
     | 
| 
       478 
462 
     | 
    
         
             
                      switch(type){
         
     | 
| 
       479 
463 
     | 
    
         
             
                        case T_FIXNUM:
         
     | 
| 
       480 
     | 
    
         
            -
                          snprintf(buf, sizeof(buf)-1, "% 
     | 
| 
      
 464 
     | 
    
         
            +
                          snprintf(buf, sizeof(buf)-1, "%ld", FIX2LONG(key));
         
     | 
| 
       481 
465 
     | 
    
         
             
                          break;
         
     | 
| 
       482 
466 
     | 
    
         
             
                        case T_FLOAT:
         
     | 
| 
       483 
467 
     | 
    
         
             
                          snprintf(buf, sizeof(buf)-1, "%lg", NUM2DBL(key));
         
     | 
| 
         @@ -508,22 +492,17 @@ static void dump_method_definition_as_value(const rb_method_definition_t *def, w 
     | 
|
| 
       508 
492 
     | 
    
         
             
                yajl_gen_null(ctx->yajl);
         
     | 
| 
       509 
493 
     | 
    
         
             
                return;
         
     | 
| 
       510 
494 
     | 
    
         
             
              }
         
     | 
| 
       511 
     | 
    
         
            -
              //printf("mdef %d\n", def->type);
         
     | 
| 
       512 
495 
     | 
    
         | 
| 
       513 
496 
     | 
    
         
             
              switch (def->type) {
         
     | 
| 
       514 
497 
     | 
    
         
             
                case VM_METHOD_TYPE_ISEQ:
         
     | 
| 
       515 
     | 
    
         
            -
                  //printf("method iseq %p\n", def->body.iseq);
         
     | 
| 
       516 
     | 
    
         
            -
                  //printf("self %p\n", def->body.iseq->self);
         
     | 
| 
       517 
498 
     | 
    
         
             
                  yg_id(def->body.iseq->self);
         
     | 
| 
       518 
499 
     | 
    
         
             
                  break;
         
     | 
| 
       519 
500 
     | 
    
         
             
                case VM_METHOD_TYPE_CFUNC: yg_cstring("(CFUNC)"); break;
         
     | 
| 
       520 
501 
     | 
    
         
             
                case VM_METHOD_TYPE_ATTRSET:
         
     | 
| 
       521 
502 
     | 
    
         
             
                case VM_METHOD_TYPE_IVAR:
         
     | 
| 
       522 
     | 
    
         
            -
                  //printf("method ivar\n");
         
     | 
| 
       523 
503 
     | 
    
         
             
                  yg_id(def->body.attr.location);
         
     | 
| 
       524 
504 
     | 
    
         
             
                  break;
         
     | 
| 
       525 
505 
     | 
    
         
             
                case VM_METHOD_TYPE_BMETHOD:
         
     | 
| 
       526 
     | 
    
         
            -
                  //printf("method binary\n");
         
     | 
| 
       527 
506 
     | 
    
         
             
                  yg_id(def->body.proc);
         
     | 
| 
       528 
507 
     | 
    
         
             
                  break;
         
     | 
| 
       529 
508 
     | 
    
         
             
                case VM_METHOD_TYPE_ZSUPER: yg_cstring("(ZSUPER)"); break;
         
     | 
| 
         @@ -546,7 +525,6 @@ static int dump_method_entry_i(ID key, const rb_method_entry_t *me, st_data_t da 
     | 
|
| 
       546 
525 
     | 
    
         
             
              }
         
     | 
| 
       547 
526 
     | 
    
         | 
| 
       548 
527 
     | 
    
         
             
              //gc_mark(objspace, me->klass, lev);?
         
     | 
| 
       549 
     | 
    
         
            -
              //printf("method entry\n");
         
     | 
| 
       550 
528 
     | 
    
         
             
              dump_method_definition_as_value(me->def, ctx);
         
     | 
| 
       551 
529 
     | 
    
         
             
              return ST_CONTINUE;
         
     | 
| 
       552 
530 
     | 
    
         
             
            }
         
     | 
| 
         @@ -556,24 +534,16 @@ static int dump_iv_entry(ID key, VALUE value, walk_ctx_t *ctx){ 
     | 
|
| 
       556 
534 
     | 
    
         
             
              if(key_str)
         
     | 
| 
       557 
535 
     | 
    
         
             
                yg_cstring(key_str);
         
     | 
| 
       558 
536 
     | 
    
         
             
              else{
         
     | 
| 
       559 
     | 
    
         
            -
                //  
     | 
| 
      
 537 
     | 
    
         
            +
                // cannot use yg_null() - keys must be strings
         
     | 
| 
      
 538 
     | 
    
         
            +
                //TODO: just ""?
         
     | 
| 
       560 
539 
     | 
    
         
             
                yg_cstring("___null_key___");
         
     | 
| 
       561 
     | 
    
         
            -
                //yg_null();
         
     | 
| 
       562 
540 
     | 
    
         
             
              }
         
     | 
| 
       563 
541 
     | 
    
         
             
              yg_id(value);
         
     | 
| 
       564 
542 
     | 
    
         
             
              return ST_CONTINUE;
         
     | 
| 
       565 
543 
     | 
    
         
             
            }
         
     | 
| 
       566 
544 
     | 
    
         | 
| 
       567 
545 
     | 
    
         
             
            static int dump_const_entry_i(ID key, const rb_const_entry_t *ce, walk_ctx_t *ctx){
         
     | 
| 
       568 
     | 
    
         
            -
             
     | 
| 
       569 
     | 
    
         
            -
            //was(ID key, VALUE value, walk_ctx_t *ctx){
         
     | 
| 
       570 
     | 
    
         
            -
             
     | 
| 
       571 
     | 
    
         
            -
              printf("const entry\n");
         
     | 
| 
       572 
     | 
    
         
            -
             
     | 
| 
       573 
546 
     | 
    
         
             
              VALUE value = ce->value;
         
     | 
| 
       574 
     | 
    
         
            -
              //file = ce->file
         
     | 
| 
       575 
     | 
    
         
            -
             
     | 
| 
       576 
     | 
    
         
            -
              printf("const key %p\n", (void*)key);
         
     | 
| 
       577 
547 
     | 
    
         
             
              yg_cstring(rb_id2name(key));
         
     | 
| 
       578 
548 
     | 
    
         
             
              yg_id(value);
         
     | 
| 
       579 
549 
     | 
    
         
             
              return ST_CONTINUE;
         
     | 
| 
         @@ -591,14 +561,13 @@ static const char* iseq_type(VALUE type){ 
     | 
|
| 
       591 
561 
     | 
    
         
             
                case ISEQ_TYPE_MAIN:   return "main";
         
     | 
| 
       592 
562 
     | 
    
         
             
                case ISEQ_TYPE_DEFINED_GUARD: return "defined_guard";
         
     | 
| 
       593 
563 
     | 
    
         
             
              }
         
     | 
| 
       594 
     | 
    
         
            -
               
     | 
| 
       595 
     | 
    
         
            -
              return "unknown";
         
     | 
| 
      
 564 
     | 
    
         
            +
              return "unknown_iseq";
         
     | 
| 
       596 
565 
     | 
    
         
             
            }
         
     | 
| 
       597 
566 
     | 
    
         | 
| 
       598 
567 
     | 
    
         
             
            static void dump_iseq(const rb_iseq_t* iseq, walk_ctx_t *ctx){
         
     | 
| 
       599 
568 
     | 
    
         
             
              if(iseq->name) ygh_rstring("name", iseq->name);
         
     | 
| 
       600 
569 
     | 
    
         
             
              if(iseq->filename) ygh_rstring("filename", iseq->filename);
         
     | 
| 
       601 
     | 
    
         
            -
              ygh_int("line",  
     | 
| 
      
 570 
     | 
    
         
            +
              ygh_int("line", FIX2LONG(iseq->line_no));
         
     | 
| 
       602 
571 
     | 
    
         | 
| 
       603 
572 
     | 
    
         
             
              //if(iseq->type != 25116) //also 28 in mark_ary
         
     | 
| 
       604 
573 
     | 
    
         
             
              ygh_cstring("type", iseq_type(iseq->type));
         
     | 
| 
         @@ -626,6 +595,21 @@ static void dump_iseq(const rb_iseq_t* iseq, walk_ctx_t *ctx){ 
     | 
|
| 
       626 
595 
     | 
    
         
             
                ygh_id("cd_err_info", compile_data->err_info);
         
     | 
| 
       627 
596 
     | 
    
         
             
                ygh_id("cd_catch_table_ary", compile_data->catch_table_ary);
         
     | 
| 
       628 
597 
     | 
    
         
             
              }
         
     | 
| 
      
 598 
     | 
    
         
            +
             
     | 
| 
      
 599 
     | 
    
         
            +
              if(iseq->local_table_size > 0){
         
     | 
| 
      
 600 
     | 
    
         
            +
                yg_cstring("local_table");
         
     | 
| 
      
 601 
     | 
    
         
            +
                yg_array();
         
     | 
| 
      
 602 
     | 
    
         
            +
                int i;
         
     | 
| 
      
 603 
     | 
    
         
            +
                for(i = 0; i < iseq->local_table_size; i++){
         
     | 
| 
      
 604 
     | 
    
         
            +
                  char* name = rb_id2name(iseq->local_table[i]);
         
     | 
| 
      
 605 
     | 
    
         
            +
                  if(name){
         
     | 
| 
      
 606 
     | 
    
         
            +
                    yg_cstring(name);
         
     | 
| 
      
 607 
     | 
    
         
            +
                  } else {
         
     | 
| 
      
 608 
     | 
    
         
            +
                    yg_cstring("(unnamed)");
         
     | 
| 
      
 609 
     | 
    
         
            +
                  }
         
     | 
| 
      
 610 
     | 
    
         
            +
                }
         
     | 
| 
      
 611 
     | 
    
         
            +
                yg_array_end();
         
     | 
| 
      
 612 
     | 
    
         
            +
              }
         
     | 
| 
       629 
613 
     | 
    
         
             
            }
         
     | 
| 
       630 
614 
     | 
    
         | 
| 
       631 
615 
     | 
    
         
             
            static void dump_block(const rb_block_t* block, walk_ctx_t *ctx){
         
     | 
| 
         @@ -758,26 +742,20 @@ static void dump_data_if_known(VALUE obj, walk_ctx_t *ctx){ 
     | 
|
| 
       758 
742 
     | 
    
         
             
              }
         
     | 
| 
       759 
743 
     | 
    
         | 
| 
       760 
744 
     | 
    
         
             
              if(!strcmp("method", typename)){
         
     | 
| 
       761 
     | 
    
         
            -
                //printf("method\n");
         
     | 
| 
       762 
745 
     | 
    
         
             
                struct METHOD *data = RTYPEDDATA_DATA(obj);
         
     | 
| 
       763 
     | 
    
         
            -
                //printf("method %p: %p %p\n", data, data->rclass, data->recv);
         
     | 
| 
       764 
746 
     | 
    
         
             
                ygh_id("rclass", data->rclass);
         
     | 
| 
       765 
747 
     | 
    
         
             
                ygh_id("recv", data->recv);
         
     | 
| 
       766 
748 
     | 
    
         
             
                ygh_int("method_id", data->id);
         
     | 
| 
       767 
749 
     | 
    
         | 
| 
       768 
750 
     | 
    
         
             
                yg_cstring("method");
         
     | 
| 
       769 
751 
     | 
    
         
             
                if(METHOD_DEFINITIONP(data)){
         
     | 
| 
       770 
     | 
    
         
            -
                  //printf("methof def %p\n", &data->me);
         
     | 
| 
       771 
752 
     | 
    
         
             
                  dump_method_definition_as_value(METHOD_DEFINITIONP(data), ctx);
         
     | 
| 
       772 
     | 
    
         
            -
                  //printf("meth end\n");
         
     | 
| 
       773 
753 
     | 
    
         
             
                }
         
     | 
| 
       774 
754 
     | 
    
         
             
                return;
         
     | 
| 
       775 
755 
     | 
    
         
             
              }
         
     | 
| 
       776 
756 
     | 
    
         | 
| 
       777 
757 
     | 
    
         
             
              if(!strcmp("binding", typename)){
         
     | 
| 
       778 
     | 
    
         
            -
                //printf("binding\n");
         
     | 
| 
       779 
758 
     | 
    
         
             
                rb_binding_t *bind = RTYPEDDATA_DATA(obj);
         
     | 
| 
       780 
     | 
    
         
            -
                //printf("binding %p\n", bind);
         
     | 
| 
       781 
759 
     | 
    
         
             
                if(!bind) return;
         
     | 
| 
       782 
760 
     | 
    
         
             
                ygh_id("env", bind->env);
         
     | 
| 
       783 
761 
     | 
    
         
             
                ygh_id("filename", bind->filename);
         
     | 
| 
         @@ -929,9 +907,9 @@ static void dump_data_if_known(VALUE obj, walk_ctx_t *ctx){ 
     | 
|
| 
       929 
907 
     | 
    
         | 
| 
       930 
908 
     | 
    
         
             
            static VALUE rb_class_real_checked(VALUE cl)
         
     | 
| 
       931 
909 
     | 
    
         
             
            {
         
     | 
| 
       932 
     | 
    
         
            -
                if (cl == 0)
         
     | 
| 
      
 910 
     | 
    
         
            +
                if (cl == 0 || IMMEDIATE_P(cl))
         
     | 
| 
       933 
911 
     | 
    
         
             
                    return 0;
         
     | 
| 
       934 
     | 
    
         
            -
                while ((RBASIC(cl)->flags & FL_SINGLETON) || BUILTIN_TYPE(cl) == T_ICLASS) {
         
     | 
| 
      
 912 
     | 
    
         
            +
                while (cl && ((RBASIC(cl)->flags & FL_SINGLETON) || BUILTIN_TYPE(cl) == T_ICLASS)) {
         
     | 
| 
       935 
913 
     | 
    
         
             
                  if(RCLASS_EXT(cl) && RCLASS_SUPER(cl)){
         
     | 
| 
       936 
914 
     | 
    
         
             
                    cl = RCLASS_SUPER(cl);
         
     | 
| 
       937 
915 
     | 
    
         
             
                  } else {
         
     | 
| 
         @@ -1084,14 +1062,13 @@ static inline void walk_live_object(VALUE obj, walk_ctx_t *ctx){ 
     | 
|
| 
       1084 
1062 
     | 
    
         
             
                      yajl_gen_map_close(ctx->yajl);
         
     | 
| 
       1085 
1063 
     | 
    
         
             
                    }
         
     | 
| 
       1086 
1064 
     | 
    
         | 
| 
       1087 
     | 
    
         
            -
                    # 
     | 
| 
      
 1065 
     | 
    
         
            +
                    #ifdef HAVE_CONSTANT_H
         
     | 
| 
       1088 
1066 
     | 
    
         
             
                    // this is for 1.9.3 or so - where rb_classext_t has const_tbl
         
     | 
| 
       1089 
1067 
     | 
    
         
             
                    if(RCLASS_CONST_TBL(obj)){
         
     | 
| 
       1090 
1068 
     | 
    
         
             
                      yg_cstring("consts");
         
     | 
| 
       1091 
     | 
    
         
            -
                       
     | 
| 
       1092 
     | 
    
         
            -
                      flush_yajl(ctx); //for debug only
         
     | 
| 
      
 1069 
     | 
    
         
            +
                      yg_map();
         
     | 
| 
       1093 
1070 
     | 
    
         
             
                      st_foreach(RCLASS_CONST_TBL(obj), dump_const_entry_i, (st_data_t)ctx);
         
     | 
| 
       1094 
     | 
    
         
            -
                       
     | 
| 
      
 1071 
     | 
    
         
            +
                      yg_map_end();
         
     | 
| 
       1095 
1072 
     | 
    
         
             
                    }
         
     | 
| 
       1096 
1073 
     | 
    
         
             
                    #endif
         
     | 
| 
       1097 
1074 
     | 
    
         | 
| 
         @@ -1115,7 +1092,7 @@ static inline void walk_live_object(VALUE obj, walk_ctx_t *ctx){ 
     | 
|
| 
       1115 
1092 
     | 
    
         
             
                  break;
         
     | 
| 
       1116 
1093 
     | 
    
         | 
| 
       1117 
1094 
     | 
    
         
             
                case T_FIXNUM:
         
     | 
| 
       1118 
     | 
    
         
            -
                  ygh_int("val",  
     | 
| 
      
 1095 
     | 
    
         
            +
                  ygh_int("val", FIX2LONG(obj));
         
     | 
| 
       1119 
1096 
     | 
    
         
             
                  break;
         
     | 
| 
       1120 
1097 
     | 
    
         
             
                case T_FLOAT:
         
     | 
| 
       1121 
1098 
     | 
    
         
             
                  ygh_double("val", RFLOAT_VALUE(obj));
         
     | 
| 
         @@ -1271,7 +1248,7 @@ static inline int is_in_heap(void *ptr, void* osp){ 
     | 
|
| 
       1271 
1248 
     | 
    
         | 
| 
       1272 
1249 
     | 
    
         | 
| 
       1273 
1250 
     | 
    
         
             
            static int
         
     | 
| 
       1274 
     | 
    
         
            -
            dump_backtrace(void* data, VALUE file, int line, VALUE method)
         
     | 
| 
      
 1251 
     | 
    
         
            +
            dump_backtrace(void* data, VALUE file, int line, VALUE method, int argc, VALUE* argv)
         
     | 
| 
       1275 
1252 
     | 
    
         
             
            {
         
     | 
| 
       1276 
1253 
     | 
    
         
             
                walk_ctx_t *ctx = data;
         
     | 
| 
       1277 
1254 
     | 
    
         
             
                yg_map();
         
     | 
| 
         @@ -1287,54 +1264,76 @@ dump_backtrace(void* data, VALUE file, int line, VALUE method) 
     | 
|
| 
       1287 
1264 
     | 
    
         
             
                  //fprintf(fp, "\tfrom %s:%d:in `%s'\n", filename, line, RSTRING_PTR(method));
         
     | 
| 
       1288 
1265 
     | 
    
         
             
                  ygh_rstring("method", method);
         
     | 
| 
       1289 
1266 
     | 
    
         
             
                }
         
     | 
| 
      
 1267 
     | 
    
         
            +
                ygh_int("argc", argc);
         
     | 
| 
      
 1268 
     | 
    
         
            +
                if(argc > 0){
         
     | 
| 
      
 1269 
     | 
    
         
            +
                  yg_cstring("argv");
         
     | 
| 
      
 1270 
     | 
    
         
            +
                  yg_array();
         
     | 
| 
      
 1271 
     | 
    
         
            +
                  int i;
         
     | 
| 
      
 1272 
     | 
    
         
            +
                  for(i = 0; i < argc; i++)
         
     | 
| 
      
 1273 
     | 
    
         
            +
                    yg_id(argv[i]);
         
     | 
| 
      
 1274 
     | 
    
         
            +
                  yg_array_end();
         
     | 
| 
      
 1275 
     | 
    
         
            +
                }
         
     | 
| 
       1290 
1276 
     | 
    
         
             
                yg_map_end();
         
     | 
| 
       1291 
1277 
     | 
    
         
             
                return FALSE;
         
     | 
| 
       1292 
1278 
     | 
    
         
             
            }
         
     | 
| 
       1293 
1279 
     | 
    
         | 
| 
       1294 
     | 
    
         
            -
             
     | 
| 
       1295 
     | 
    
         
            -
             
     | 
| 
      
 1280 
     | 
    
         
            +
            typedef int (rb_backtrace_iter_ext_func)(void *arg, VALUE file, int line, VALUE method_name, int argc, VALUE* argv);
         
     | 
| 
      
 1281 
     | 
    
         
            +
             
     | 
| 
      
 1282 
     | 
    
         
            +
            // copied from ruby_ext_backtrace
         
     | 
| 
       1296 
1283 
     | 
    
         
             
            static int
         
     | 
| 
       1297 
     | 
    
         
            -
             
     | 
| 
      
 1284 
     | 
    
         
            +
            vm_backtrace_each_ext(rb_thread_t *th, int lev, void (*init)(void *), rb_backtrace_iter_ext_func *iter, void *arg)
         
     | 
| 
       1298 
1285 
     | 
    
         
             
            {
         
     | 
| 
       1299 
     | 
    
         
            -
             
     | 
| 
       1300 
     | 
    
         
            -
             
     | 
| 
       1301 
     | 
    
         
            -
             
     | 
| 
       1302 
     | 
    
         
            -
             
     | 
| 
       1303 
     | 
    
         
            -
             
     | 
| 
       1304 
     | 
    
         
            -
             
     | 
| 
       1305 
     | 
    
         
            -
             
     | 
| 
       1306 
     | 
    
         
            -
               
     | 
| 
       1307 
     | 
    
         
            -
             
     | 
| 
      
 1286 
     | 
    
         
            +
              const rb_control_frame_t *limit_cfp = th->cfp;
         
     | 
| 
      
 1287 
     | 
    
         
            +
              const rb_control_frame_t *cfp = (void *)(th->stack + th->stack_size);
         
     | 
| 
      
 1288 
     | 
    
         
            +
              VALUE file = Qnil;
         
     | 
| 
      
 1289 
     | 
    
         
            +
              int line_no = 0;
         
     | 
| 
      
 1290 
     | 
    
         
            +
             
     | 
| 
      
 1291 
     | 
    
         
            +
              cfp -= 2;
         
     | 
| 
      
 1292 
     | 
    
         
            +
              //skip lev frames:
         
     | 
| 
      
 1293 
     | 
    
         
            +
              while (lev-- >= 0) {
         
     | 
| 
      
 1294 
     | 
    
         
            +
                if (++limit_cfp > cfp)
         
     | 
| 
      
 1295 
     | 
    
         
            +
                    return FALSE;
         
     | 
| 
       1308 
1296 
     | 
    
         
             
              }
         
     | 
| 
       1309 
     | 
    
         
            -
                }
         
     | 
| 
       1310 
     | 
    
         
            -
                if (init) (*init)(arg);
         
     | 
| 
       1311 
     | 
    
         
            -
                limit_cfp = RUBY_VM_NEXT_CONTROL_FRAME(limit_cfp);
         
     | 
| 
       1312 
     | 
    
         
            -
                if (th->vm->progname) file = th->vm->progname;
         
     | 
| 
       1313 
     | 
    
         
            -
                while (cfp > limit_cfp) {
         
     | 
| 
       1314 
     | 
    
         
            -
              if (cfp->iseq != 0) {
         
     | 
| 
       1315 
     | 
    
         
            -
                  if (cfp->pc != 0) {
         
     | 
| 
       1316 
     | 
    
         
            -
                rb_iseq_t *iseq = cfp->iseq;
         
     | 
| 
       1317 
     | 
    
         
            -
             
     | 
| 
       1318 
     | 
    
         
            -
                line_no = rb_vm_get_sourceline(cfp);
         
     | 
| 
       1319 
     | 
    
         
            -
                file = iseq->filename;
         
     | 
| 
       1320 
     | 
    
         
            -
                if ((*iter)(arg, file, line_no, iseq->name)) break;
         
     | 
| 
       1321 
     | 
    
         
            -
                  }
         
     | 
| 
       1322 
     | 
    
         
            -
              }
         
     | 
| 
       1323 
     | 
    
         
            -
              else if (RUBYVM_CFUNC_FRAME_P(cfp)) {
         
     | 
| 
       1324 
     | 
    
         
            -
                  ID id;
         
     | 
| 
       1325 
     | 
    
         
            -
                  
         
     | 
| 
       1326 
1297 
     | 
    
         | 
| 
       1327 
     | 
    
         
            -
             
     | 
| 
       1328 
     | 
    
         
            -
             
     | 
| 
       1329 
     | 
    
         
            -
             
     | 
| 
       1330 
     | 
    
         
            -
             
     | 
| 
       1331 
     | 
    
         
            -
             
     | 
| 
       1332 
     | 
    
         
            -
             
     | 
| 
       1333 
     | 
    
         
            -
                 
     | 
| 
      
 1298 
     | 
    
         
            +
              if (init) (*init)(arg);
         
     | 
| 
      
 1299 
     | 
    
         
            +
             
     | 
| 
      
 1300 
     | 
    
         
            +
              limit_cfp = RUBY_VM_NEXT_CONTROL_FRAME(limit_cfp);
         
     | 
| 
      
 1301 
     | 
    
         
            +
              if (th->vm->progname) file = th->vm->progname;
         
     | 
| 
      
 1302 
     | 
    
         
            +
             
     | 
| 
      
 1303 
     | 
    
         
            +
              while (cfp > limit_cfp) {
         
     | 
| 
      
 1304 
     | 
    
         
            +
                if (cfp->iseq != 0) {
         
     | 
| 
      
 1305 
     | 
    
         
            +
                    if (cfp->pc != 0) {
         
     | 
| 
      
 1306 
     | 
    
         
            +
                      rb_iseq_t *iseq = cfp->iseq;
         
     | 
| 
      
 1307 
     | 
    
         
            +
             
     | 
| 
      
 1308 
     | 
    
         
            +
                      line_no = rb_vm_get_sourceline(cfp);
         
     | 
| 
      
 1309 
     | 
    
         
            +
                      file = iseq->filename;
         
     | 
| 
      
 1310 
     | 
    
         
            +
             
     | 
| 
      
 1311 
     | 
    
         
            +
                      //arguments pushed this way: *reg_cfp->sp++ = recv; for (i = 0; i < argc; i++) *reg_cfp->sp++ = argv[i];
         
     | 
| 
      
 1312 
     | 
    
         
            +
                      //local vars = cfp->iseq->local_size - cfp->iseq->arg_size;
         
     | 
| 
      
 1313 
     | 
    
         
            +
                      //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;
         
     | 
| 
      
 1316 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1317 
     | 
    
         
            +
                } else
         
     | 
| 
      
 1318 
     | 
    
         
            +
                  if (RUBYVM_CFUNC_FRAME_P(cfp)) {
         
     | 
| 
      
 1319 
     | 
    
         
            +
                    ID id = cfp->me->def? cfp->me->def->original_id : cfp->me->called_id;
         
     | 
| 
      
 1320 
     | 
    
         
            +
             
     | 
| 
      
 1321 
     | 
    
         
            +
                    if (NIL_P(file)) file = ruby_engine_name;
         
     | 
| 
      
 1322 
     | 
    
         
            +
             
     | 
| 
      
 1323 
     | 
    
         
            +
                    if (id != ID_ALLOCATOR){
         
     | 
| 
      
 1324 
     | 
    
         
            +
                      VALUE* argv = NULL;
         
     | 
| 
      
 1325 
     | 
    
         
            +
                      // when argc==-1/-2(variable length params without/with splat) - the cfp has no info on params count :(
         
     | 
| 
      
 1326 
     | 
    
         
            +
                      //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 
     | 
    
         
            +
                      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
         
     | 
| 
      
 1329 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1330 
     | 
    
         
            +
                      //file+line no from previous iseq frame
         
     | 
| 
      
 1331 
     | 
    
         
            +
                      if((*iter)(arg, file, line_no, rb_id2str(id), cfp->me->def->body.cfunc.argc, argv)) break;
         
     | 
| 
      
 1332 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1333 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1334 
     | 
    
         
            +
                cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp);
         
     | 
| 
       1334 
1335 
     | 
    
         
             
              }
         
     | 
| 
       1335 
     | 
    
         
            -
               
     | 
| 
       1336 
     | 
    
         
            -
                }
         
     | 
| 
       1337 
     | 
    
         
            -
                return TRUE;
         
     | 
| 
      
 1336 
     | 
    
         
            +
              return TRUE;
         
     | 
| 
       1338 
1337 
     | 
    
         
             
            }
         
     | 
| 
       1339 
1338 
     | 
    
         | 
| 
       1340 
1339 
     | 
    
         
             
            static void dump_thread(const rb_thread_t* th, walk_ctx_t *ctx){
         
     | 
| 
         @@ -1355,6 +1354,7 @@ static void dump_thread(const rb_thread_t* th, walk_ctx_t *ctx){ 
     | 
|
| 
       1355 
1354 
     | 
    
         | 
| 
       1356 
1355 
     | 
    
         
             
                yg_cstring("cfp");
         
     | 
| 
       1357 
1356 
     | 
    
         
             
                yajl_gen_array_open(ctx->yajl);
         
     | 
| 
      
 1357 
     | 
    
         
            +
                //TODO: this is kind of backtrace, but other direction plus some other info, merge it in backtrace.
         
     | 
| 
       1358 
1358 
     | 
    
         
             
                while (cfp != limit_cfp) {
         
     | 
| 
       1359 
1359 
     | 
    
         
             
                  yajl_gen_map_open(ctx->yajl);
         
     | 
| 
       1360 
1360 
     | 
    
         
             
                  rb_iseq_t *iseq = cfp->iseq;
         
     | 
| 
         @@ -1395,7 +1395,7 @@ static void dump_thread(const rb_thread_t* th, walk_ctx_t *ctx){ 
     | 
|
| 
       1395 
1395 
     | 
    
         | 
| 
       1396 
1396 
     | 
    
         
             
              yg_cstring("backtrace");
         
     | 
| 
       1397 
1397 
     | 
    
         
             
              yg_array();
         
     | 
| 
       1398 
     | 
    
         
            -
               
     | 
| 
      
 1398 
     | 
    
         
            +
              vm_backtrace_each_ext(th, -1, NULL, dump_backtrace, ctx);
         
     | 
| 
       1399 
1399 
     | 
    
         
             
              yg_array_end();
         
     | 
| 
       1400 
1400 
     | 
    
         | 
| 
       1401 
1401 
     | 
    
         
             
              //TODO: mark other...
         
     | 
| 
         @@ -1472,7 +1472,6 @@ static void dump_machine_context(walk_ctx_t *ctx){ 
     | 
|
| 
       1472 
1472 
     | 
    
         
             
              //mark_locations_array(objspace, save_regs_gc_mark.v, numberof(save_regs_gc_mark.v));
         
     | 
| 
       1473 
1473 
     | 
    
         
             
              VALUE* x = save_regs_gc_mark.v;
         
     | 
| 
       1474 
1474 
     | 
    
         
             
              unsigned long n = numberof(save_regs_gc_mark.v);
         
     | 
| 
       1475 
     | 
    
         
            -
              //printf("registers\n");
         
     | 
| 
       1476 
1475 
     | 
    
         
             
              while (n--) {
         
     | 
| 
       1477 
1476 
     | 
    
         
             
                VALUE v = *(x++);
         
     | 
| 
       1478 
1477 
     | 
    
         
             
                if(is_in_heap((void*)v, NULL))
         
     | 
| 
         @@ -1480,7 +1479,6 @@ static void dump_machine_context(walk_ctx_t *ctx){ 
     | 
|
| 
       1480 
1479 
     | 
    
         
             
              }
         
     | 
| 
       1481 
1480 
     | 
    
         
             
              yajl_gen_array_close(ctx->yajl);
         
     | 
| 
       1482 
1481 
     | 
    
         | 
| 
       1483 
     | 
    
         
            -
              //printf("stack: %p %p\n", stack_start, stack_end);
         
     | 
| 
       1484 
1482 
     | 
    
         
             
              yg_cstring("stack");
         
     | 
| 
       1485 
1483 
     | 
    
         
             
              yajl_gen_array_open(ctx->yajl);
         
     | 
| 
       1486 
1484 
     | 
    
         
             
              //rb_gc_mark_locations(stack_start, stack_end);
         
     | 
| 
         @@ -1489,10 +1487,8 @@ static void dump_machine_context(walk_ctx_t *ctx){ 
     | 
|
| 
       1489 
1487 
     | 
    
         
             
                x = stack_start;
         
     | 
| 
       1490 
1488 
     | 
    
         
             
                while (n--) {
         
     | 
| 
       1491 
1489 
     | 
    
         
             
                  VALUE v = *(x++);
         
     | 
| 
       1492 
     | 
    
         
            -
                  //printf("val: %p\n", (void*)v);
         
     | 
| 
       1493 
1490 
     | 
    
         
             
                  //FIXME: other objspace (not default one?)
         
     | 
| 
       1494 
1491 
     | 
    
         
             
                  if(is_in_heap((void*)v, NULL)) {
         
     | 
| 
       1495 
     | 
    
         
            -
                    //printf("ON heap\n");
         
     | 
| 
       1496 
1492 
     | 
    
         
             
                    yg_id(v);
         
     | 
| 
       1497 
1493 
     | 
    
         
             
                  }
         
     | 
| 
       1498 
1494 
     | 
    
         
             
                }
         
     | 
| 
         @@ -1501,39 +1497,73 @@ static void dump_machine_context(walk_ctx_t *ctx){ 
     | 
|
| 
       1501 
1497 
     | 
    
         
             
              yajl_gen_array_close(ctx->yajl);
         
     | 
| 
       1502 
1498 
     | 
    
         
             
            }
         
     | 
| 
       1503 
1499 
     | 
    
         | 
| 
       1504 
     | 
    
         
            -
             
     | 
| 
      
 1500 
     | 
    
         
            +
            #ifdef HAVE_RB_CLASS_TBL
         
     | 
| 
      
 1501 
     | 
    
         
            +
            // 1.9.2, rb_class_tbl fails to be linked in 1.9.3 :(
         
     | 
| 
      
 1502 
     | 
    
         
            +
             
     | 
| 
      
 1503 
     | 
    
         
            +
            static int dump_class_tbl_entry(ID key, rb_const_entry_t* ce/*st_data_t val*/, walk_ctx_t *ctx){
         
     | 
| 
       1505 
1504 
     | 
    
         
             
              if (!rb_is_const_id(key)) return ST_CONTINUE; //?
         
     | 
| 
       1506 
     | 
    
         
            -
              //rb_const_entry_t* ce = val;
         
     | 
| 
       1507 
1505 
     | 
    
         
             
              VALUE value = ce->value;
         
     | 
| 
       1508 
1506 
     | 
    
         | 
| 
       1509 
     | 
    
         
            -
               
     | 
| 
       1510 
     | 
    
         
            -
               
     | 
| 
      
 1507 
     | 
    
         
            +
              char* id = rb_id2name(key);
         
     | 
| 
      
 1508 
     | 
    
         
            +
              if(id)
         
     | 
| 
      
 1509 
     | 
    
         
            +
                yg_cstring(id);
         
     | 
| 
      
 1510 
     | 
    
         
            +
              else
         
     | 
| 
      
 1511 
     | 
    
         
            +
                yg_cstring("(unknown)");
         
     | 
| 
      
 1512 
     | 
    
         
            +
              yg_id(value);
         
     | 
| 
      
 1513 
     | 
    
         
            +
              return ST_CONTINUE;
         
     | 
| 
      
 1514 
     | 
    
         
            +
            }
         
     | 
| 
      
 1515 
     | 
    
         
            +
            #endif
         
     | 
| 
       1511 
1516 
     | 
    
         | 
| 
       1512 
     | 
    
         
            -
             
     | 
| 
      
 1517 
     | 
    
         
            +
            #ifdef HAVE_RB_GLOBAL_TBL
         
     | 
| 
      
 1518 
     | 
    
         
            +
            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);
         
     | 
| 
      
 1520 
     | 
    
         
            +
              if(id)
         
     | 
| 
      
 1521 
     | 
    
         
            +
                yg_cstring(id);
         
     | 
| 
      
 1522 
     | 
    
         
            +
              else
         
     | 
| 
      
 1523 
     | 
    
         
            +
                yg_cstring("(unknown)");
         
     | 
| 
       1513 
1524 
     | 
    
         | 
| 
       1514 
     | 
    
         
            -
               
     | 
| 
      
 1525 
     | 
    
         
            +
              yg_map();
         
     | 
| 
       1515 
1526 
     | 
    
         | 
| 
       1516 
     | 
    
         
            -
               
     | 
| 
       1517 
     | 
    
         
            -
             
     | 
| 
       1518 
     | 
    
         
            -
                 
     | 
| 
       1519 
     | 
    
         
            -
             
     | 
| 
      
 1527 
     | 
    
         
            +
              Dl_info info;
         
     | 
| 
      
 1528 
     | 
    
         
            +
              if(dladdr(ge->var->getter, &info) && info.dli_sname){
         
     | 
| 
      
 1529 
     | 
    
         
            +
                yg_cstring("getter");
         
     | 
| 
      
 1530 
     | 
    
         
            +
                yg_cstring(info.dli_sname);
         
     | 
| 
       1520 
1531 
     | 
    
         | 
| 
      
 1532 
     | 
    
         
            +
                if(!strcmp("rb_gvar_val_getter", info.dli_sname)){
         
     | 
| 
      
 1533 
     | 
    
         
            +
                yg_cstring("data");
         
     | 
| 
      
 1534 
     | 
    
         
            +
                yg_id(ge->var->data);
         
     | 
| 
      
 1535 
     | 
    
         
            +
                }
         
     | 
| 
      
 1536 
     | 
    
         
            +
              }
         
     | 
| 
      
 1537 
     | 
    
         
            +
             
     | 
| 
      
 1538 
     | 
    
         
            +
              yg_cstring("setter");
         
     | 
| 
      
 1539 
     | 
    
         
            +
              yg_funcaddr(ge->var->setter);
         
     | 
| 
      
 1540 
     | 
    
         
            +
             
     | 
| 
      
 1541 
     | 
    
         
            +
              yg_map_end();
         
     | 
| 
       1521 
1542 
     | 
    
         
             
              return ST_CONTINUE;
         
     | 
| 
       1522 
1543 
     | 
    
         
             
            }
         
     | 
| 
      
 1544 
     | 
    
         
            +
            #endif
         
     | 
| 
       1523 
1545 
     | 
    
         | 
| 
       1524 
     | 
    
         
            -
            // static void try_dump_generic_ivars(walk_ctx_t* ctx){
         
     | 
| 
       1525 
     | 
    
         
            -
            //   //very nasty hack:
         
     | 
| 
       1526 
     | 
    
         
            -
            //   #if defined(__x86_64__) && defined(__GNUC__) && !defined(__native_client__)
         
     | 
| 
       1527 
     | 
    
         
            -
            //   printf("Trying generic ivars\n");
         
     | 
| 
       1528 
     | 
    
         
            -
            //   //TODO: config to turn this off in case this will not work
         
     | 
| 
       1529 
1546 
     | 
    
         | 
| 
       1530 
     | 
    
         
            -
             
     | 
| 
       1531 
     | 
    
         
            -
             
     | 
| 
       1532 
     | 
    
         
            -
             
     | 
| 
       1533 
     | 
    
         
            -
             
     | 
| 
      
 1547 
     | 
    
         
            +
            #include <stdarg.h>
         
     | 
| 
      
 1548 
     | 
    
         
            +
            static bool g_verbose = false;
         
     | 
| 
      
 1549 
     | 
    
         
            +
            static int log_printf(const char* format, ...){
         
     | 
| 
      
 1550 
     | 
    
         
            +
              va_list list;
         
     | 
| 
      
 1551 
     | 
    
         
            +
              va_start(list, format);
         
     | 
| 
      
 1552 
     | 
    
         
            +
              if(g_verbose)
         
     | 
| 
      
 1553 
     | 
    
         
            +
                vprintf(format, list);
         
     | 
| 
      
 1554 
     | 
    
         
            +
              va_end(list);
         
     | 
| 
      
 1555 
     | 
    
         
            +
            }
         
     | 
| 
      
 1556 
     | 
    
         
            +
             
     | 
| 
      
 1557 
     | 
    
         
            +
            #define log log_printf
         
     | 
| 
      
 1558 
     | 
    
         
            +
             
     | 
| 
      
 1559 
     | 
    
         
            +
            static VALUE heapdump_verbose(VALUE self){
         
     | 
| 
      
 1560 
     | 
    
         
            +
              return g_verbose ? Qtrue : Qfalse;
         
     | 
| 
      
 1561 
     | 
    
         
            +
            }
         
     | 
| 
       1534 
1562 
     | 
    
         | 
| 
       1535 
     | 
    
         
            -
             
     | 
| 
       1536 
     | 
    
         
            -
             
     | 
| 
      
 1563 
     | 
    
         
            +
            static VALUE heapdump_verbose_setter(VALUE self, VALUE verbose){
         
     | 
| 
      
 1564 
     | 
    
         
            +
              g_verbose = RTEST(verbose);
         
     | 
| 
      
 1565 
     | 
    
         
            +
              return heapdump_verbose(self);
         
     | 
| 
      
 1566 
     | 
    
         
            +
            }
         
     | 
| 
       1537 
1567 
     | 
    
         | 
| 
       1538 
1568 
     | 
    
         | 
| 
       1539 
1569 
     | 
    
         
             
            //public symbol, can be used from GDB
         
     | 
| 
         @@ -1544,7 +1574,7 @@ void heapdump_dump(const char* filename){ 
     | 
|
| 
       1544 
1574 
     | 
    
         
             
              if(!filename){
         
     | 
| 
       1545 
1575 
     | 
    
         
             
                filename = "dump.json";
         
     | 
| 
       1546 
1576 
     | 
    
         
             
              }
         
     | 
| 
       1547 
     | 
    
         
            -
               
     | 
| 
      
 1577 
     | 
    
         
            +
              log("Dump should go to %s\n", filename);
         
     | 
| 
       1548 
1578 
     | 
    
         
             
              ctx->file = fopen(filename, "wt");
         
     | 
| 
       1549 
1579 
     | 
    
         
             
              ctx->yajl = yajl_gen_alloc(NULL,NULL);
         
     | 
| 
       1550 
1580 
     | 
    
         
             
              yajl_gen_array_open(ctx->yajl);
         
     | 
| 
         @@ -1553,7 +1583,7 @@ void heapdump_dump(const char* filename){ 
     | 
|
| 
       1553 
1583 
     | 
    
         
             
              yajl_gen_map_open(ctx->yajl);
         
     | 
| 
       1554 
1584 
     | 
    
         
             
              ygh_cstring("id", "_ROOTS_");
         
     | 
| 
       1555 
1585 
     | 
    
         | 
| 
       1556 
     | 
    
         
            -
               
     | 
| 
      
 1586 
     | 
    
         
            +
              log("machine context\n");
         
     | 
| 
       1557 
1587 
     | 
    
         | 
| 
       1558 
1588 
     | 
    
         
             
              dump_machine_context(ctx);
         
     | 
| 
       1559 
1589 
     | 
    
         
             
              flush_yajl(ctx);
         
     | 
| 
         @@ -1561,24 +1591,39 @@ void heapdump_dump(const char* filename){ 
     | 
|
| 
       1561 
1591 
     | 
    
         | 
| 
       1562 
1592 
     | 
    
         
             
              struct gc_list *list;
         
     | 
| 
       1563 
1593 
     | 
    
         
             
              /* mark protected global variables */
         
     | 
| 
       1564 
     | 
    
         
            -
               
     | 
| 
      
 1594 
     | 
    
         
            +
              log("global_list\n");
         
     | 
| 
      
 1595 
     | 
    
         
            +
              yg_cstring("globals");
         
     | 
| 
      
 1596 
     | 
    
         
            +
              yg_array();
         
     | 
| 
       1565 
1597 
     | 
    
         
             
              for (list = GET_THREAD()->vm->global_List; list; list = list->next) {
         
     | 
| 
       1566 
1598 
     | 
    
         
             
                VALUE v = *list->varptr;
         
     | 
| 
       1567 
     | 
    
         
            -
                 
     | 
| 
      
 1599 
     | 
    
         
            +
                yg_id(v);
         
     | 
| 
       1568 
1600 
     | 
    
         
             
              }
         
     | 
| 
      
 1601 
     | 
    
         
            +
              yg_array_end();
         
     | 
| 
       1569 
1602 
     | 
    
         | 
| 
       1570 
     | 
    
         
            -
             
     | 
| 
       1571 
     | 
    
         
            -
             
     | 
| 
       1572 
     | 
    
         
            -
               
     | 
| 
       1573 
     | 
    
         
            -
               
     | 
| 
       1574 
     | 
    
         
            -
             
     | 
| 
       1575 
     | 
    
         
            -
                 
     | 
| 
       1576 
     | 
    
         
            -
             
     | 
| 
       1577 
     | 
    
         
            -
             
     | 
| 
       1578 
     | 
    
         
            -
             
     | 
| 
      
 1603 
     | 
    
         
            +
              //TODO: rb_global_tbl
         
     | 
| 
      
 1604 
     | 
    
         
            +
            #ifdef HAVE_RB_GLOBAL_TBL
         
     | 
| 
      
 1605 
     | 
    
         
            +
              st_table *rb_global_tbl = rb_get_global_tbl();
         
     | 
| 
      
 1606 
     | 
    
         
            +
              if (rb_global_tbl && rb_global_tbl->num_entries > 0){
         
     | 
| 
      
 1607 
     | 
    
         
            +
                log("globals\n");
         
     | 
| 
      
 1608 
     | 
    
         
            +
                yg_cstring("global_tbl");
         
     | 
| 
      
 1609 
     | 
    
         
            +
                yg_map();
         
     | 
| 
      
 1610 
     | 
    
         
            +
                st_foreach(rb_global_tbl, dump_global_tbl_entry, (st_data_t)ctx);
         
     | 
| 
      
 1611 
     | 
    
         
            +
                yg_map_end();
         
     | 
| 
      
 1612 
     | 
    
         
            +
                flush_yajl(ctx);
         
     | 
| 
      
 1613 
     | 
    
         
            +
              }
         
     | 
| 
       1579 
1614 
     | 
    
         
             
            #endif
         
     | 
| 
       1580 
1615 
     | 
    
         | 
| 
       1581 
     | 
    
         
            -
             
     | 
| 
      
 1616 
     | 
    
         
            +
            #ifdef HAVE_RB_CLASS_TBL
         
     | 
| 
      
 1617 
     | 
    
         
            +
              st_table *rb_class_tbl = rb_get_class_tbl();
         
     | 
| 
      
 1618 
     | 
    
         
            +
              if (rb_class_tbl && rb_class_tbl->num_entries > 0){
         
     | 
| 
      
 1619 
     | 
    
         
            +
                log("classes\n");
         
     | 
| 
      
 1620 
     | 
    
         
            +
                yg_cstring("classes");
         
     | 
| 
      
 1621 
     | 
    
         
            +
                yg_map();
         
     | 
| 
      
 1622 
     | 
    
         
            +
                st_foreach(rb_class_tbl, dump_class_tbl_entry, (st_data_t)ctx);
         
     | 
| 
      
 1623 
     | 
    
         
            +
                yg_map_end();
         
     | 
| 
      
 1624 
     | 
    
         
            +
                flush_yajl(ctx);
         
     | 
| 
      
 1625 
     | 
    
         
            +
              }
         
     | 
| 
      
 1626 
     | 
    
         
            +
            #endif
         
     | 
| 
       1582 
1627 
     | 
    
         | 
| 
       1583 
1628 
     | 
    
         
             
              //TODO: other gc entry points - symbols, encodings, etc.
         
     | 
| 
       1584 
1629 
     | 
    
         | 
| 
         @@ -1587,7 +1632,7 @@ void heapdump_dump(const char* filename){ 
     | 
|
| 
       1587 
1632 
     | 
    
         
             
              fprintf(ctx->file, "\n");
         
     | 
| 
       1588 
1633 
     | 
    
         | 
| 
       1589 
1634 
     | 
    
         
             
              //now dump all live objects
         
     | 
| 
       1590 
     | 
    
         
            -
               
     | 
| 
      
 1635 
     | 
    
         
            +
              log("starting objspace walk\n");
         
     | 
| 
       1591 
1636 
     | 
    
         
             
              rb_objspace_each_objects(objspace_walker, ctx);
         
     | 
| 
       1592 
1637 
     | 
    
         | 
| 
       1593 
1638 
     | 
    
         
             
              yajl_gen_array_close(ctx->yajl);
         
     | 
| 
         @@ -1595,7 +1640,7 @@ void heapdump_dump(const char* filename){ 
     | 
|
| 
       1595 
1640 
     | 
    
         
             
              yajl_gen_free(ctx->yajl);
         
     | 
| 
       1596 
1641 
     | 
    
         
             
              fclose(ctx->file);
         
     | 
| 
       1597 
1642 
     | 
    
         | 
| 
       1598 
     | 
    
         
            -
               
     | 
| 
      
 1643 
     | 
    
         
            +
              log("Walker called %d times, seen %d live objects.\n", ctx->walker_called, ctx->live_objects);
         
     | 
| 
       1599 
1644 
     | 
    
         
             
            }
         
     | 
| 
       1600 
1645 
     | 
    
         | 
| 
       1601 
1646 
     | 
    
         
             
            static VALUE
         
     | 
| 
         @@ -1606,6 +1651,113 @@ rb_heapdump_dump(VALUE self, VALUE filename) 
     | 
|
| 
       1606 
1651 
     | 
    
         
             
              return Qnil;
         
     | 
| 
       1607 
1652 
     | 
    
         
             
            }
         
     | 
| 
       1608 
1653 
     | 
    
         | 
| 
      
 1654 
     | 
    
         
            +
             
     | 
| 
      
 1655 
     | 
    
         
            +
             
     | 
| 
      
 1656 
     | 
    
         
            +
            // HeapDump.count_objects:
         
     | 
| 
      
 1657 
     | 
    
         
            +
             
     | 
| 
      
 1658 
     | 
    
         
            +
            #undef YAJL
         
     | 
| 
      
 1659 
     | 
    
         
            +
            #define YAJL yajl
         
     | 
| 
      
 1660 
     | 
    
         
            +
            static int
         
     | 
| 
      
 1661 
     | 
    
         
            +
            iterate_user_type_counts(VALUE key, VALUE value, yajl_gen yajl){
         
     | 
| 
      
 1662 
     | 
    
         
            +
              yg_rstring(key);
         
     | 
| 
      
 1663 
     | 
    
         
            +
              yg_int(FIX2LONG(value));
         
     | 
| 
      
 1664 
     | 
    
         
            +
              return ST_CONTINUE;
         
     | 
| 
      
 1665 
     | 
    
         
            +
            }
         
     | 
| 
      
 1666 
     | 
    
         
            +
             
     | 
| 
      
 1667 
     | 
    
         
            +
            static VALUE
         
     | 
| 
      
 1668 
     | 
    
         
            +
            rb_heapdump_count_objects(VALUE self, VALUE string_prefixes, VALUE do_gc){
         
     | 
| 
      
 1669 
     | 
    
         
            +
              rb_check_array_type(string_prefixes);
         
     | 
| 
      
 1670 
     | 
    
         
            +
              yajl_gen_config cfg;
         
     | 
| 
      
 1671 
     | 
    
         
            +
              memset(&cfg, 0, sizeof(cfg));
         
     | 
| 
      
 1672 
     | 
    
         
            +
              cfg.beautify = true;
         
     | 
| 
      
 1673 
     | 
    
         
            +
              cfg.htmlSafe = true;
         
     | 
| 
      
 1674 
     | 
    
         
            +
              cfg.indentString = "    ";
         
     | 
| 
      
 1675 
     | 
    
         
            +
              yajl_gen yajl = yajl_gen_alloc(&cfg,NULL);
         
     | 
| 
      
 1676 
     | 
    
         
            +
              yg_map();
         
     | 
| 
      
 1677 
     | 
    
         
            +
              if(do_gc){
         
     | 
| 
      
 1678 
     | 
    
         
            +
                yg_cstring("gc_ran");
         
     | 
| 
      
 1679 
     | 
    
         
            +
                yg_bool(true);
         
     | 
| 
      
 1680 
     | 
    
         
            +
                rb_gc_start();
         
     | 
| 
      
 1681 
     | 
    
         
            +
              }
         
     | 
| 
      
 1682 
     | 
    
         
            +
             
     | 
| 
      
 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 
     | 
    
         
            +
              for (i = 0; i <= T_MASK; i++) counts[i] = 0;
         
     | 
| 
      
 1691 
     | 
    
         
            +
             
     | 
| 
      
 1692 
     | 
    
         
            +
              FOR_EACH_HEAP_SLOT(p)
         
     | 
| 
      
 1693 
     | 
    
         
            +
                // danger: allocates memory while walking heap
         
     | 
| 
      
 1694 
     | 
    
         
            +
                if (p->as.basic.flags) {
         
     | 
| 
      
 1695 
     | 
    
         
            +
                  int type = BUILTIN_TYPE(p);
         
     | 
| 
      
 1696 
     | 
    
         
            +
                  counts[type]++;
         
     | 
| 
      
 1697 
     | 
    
         
            +
                  if(type == T_OBJECT){
         
     | 
| 
      
 1698 
     | 
    
         
            +
                    //take class etc.
         
     | 
| 
      
 1699 
     | 
    
         
            +
                    VALUE cls = rb_class_real_checked(CLASS_OF(p));
         
     | 
| 
      
 1700 
     | 
    
         
            +
                    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]);
         
     | 
| 
      
 1705 
     | 
    
         
            +
                      if(NIL_P(prefix)) continue;
         
     | 
| 
      
 1706 
     | 
    
         
            +
                      rb_enc_check(class_name, prefix);
         
     | 
| 
      
 1707 
     | 
    
         
            +
                      if (RSTRING_LEN(class_name) < RSTRING_LEN(prefix)) continue;
         
     | 
| 
      
 1708 
     | 
    
         
            +
                      if (!memcmp(RSTRING_PTR(class_name), RSTRING_PTR(prefix), RSTRING_LEN(prefix)))
         
     | 
| 
      
 1709 
     | 
    
         
            +
                        if(RSTRING_LEN(class_name) == RSTRING_LEN(prefix) ||
         
     | 
| 
      
 1710 
     | 
    
         
            +
                          RSTRING_PTR(class_name)[RSTRING_LEN(prefix)] == ':'){
         
     | 
| 
      
 1711 
     | 
    
         
            +
                          //class match
         
     | 
| 
      
 1712 
     | 
    
         
            +
                          VALUE val = rb_hash_aref(hash, class_name);
         
     | 
| 
      
 1713 
     | 
    
         
            +
                          long num;
         
     | 
| 
      
 1714 
     | 
    
         
            +
                          if(FIXNUM_P(val)){
         
     | 
| 
      
 1715 
     | 
    
         
            +
                            num = FIX2LONG(val) + 1;
         
     | 
| 
      
 1716 
     | 
    
         
            +
                          } else {
         
     | 
| 
      
 1717 
     | 
    
         
            +
                            num = 1;
         
     | 
| 
      
 1718 
     | 
    
         
            +
                          }
         
     | 
| 
      
 1719 
     | 
    
         
            +
                          rb_hash_aset(hash, class_name, LONG2FIX(num));
         
     | 
| 
      
 1720 
     | 
    
         
            +
                        }
         
     | 
| 
      
 1721 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1722 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1723 
     | 
    
         
            +
                } else {
         
     | 
| 
      
 1724 
     | 
    
         
            +
                  freed++;
         
     | 
| 
      
 1725 
     | 
    
         
            +
                }
         
     | 
| 
      
 1726 
     | 
    
         
            +
              FOR_EACH_HEAP_SLOT_END(total)
         
     | 
| 
      
 1727 
     | 
    
         
            +
             
     | 
| 
      
 1728 
     | 
    
         
            +
              ygh_int("total_slots", total);
         
     | 
| 
      
 1729 
     | 
    
         
            +
              ygh_int("free_slots", freed);
         
     | 
| 
      
 1730 
     | 
    
         
            +
              yg_cstring("basic_types");
         
     | 
| 
      
 1731 
     | 
    
         
            +
              yg_map();
         
     | 
| 
      
 1732 
     | 
    
         
            +
              for (i = 0; i <= T_MASK; i++) {
         
     | 
| 
      
 1733 
     | 
    
         
            +
                if(!counts[i]) continue;
         
     | 
| 
      
 1734 
     | 
    
         
            +
                yg_cstring(rb_type_str((int)i));
         
     | 
| 
      
 1735 
     | 
    
         
            +
                yg_int(counts[i]);
         
     | 
| 
      
 1736 
     | 
    
         
            +
              }
         
     | 
| 
      
 1737 
     | 
    
         
            +
              yg_map_end();
         
     | 
| 
      
 1738 
     | 
    
         
            +
             
     | 
| 
      
 1739 
     | 
    
         
            +
              yg_cstring("user_types");
         
     | 
| 
      
 1740 
     | 
    
         
            +
              yg_map();
         
     | 
| 
      
 1741 
     | 
    
         
            +
              rb_hash_foreach(hash, iterate_user_type_counts, (VALUE)yajl);
         
     | 
| 
      
 1742 
     | 
    
         
            +
              yg_map_end();
         
     | 
| 
      
 1743 
     | 
    
         
            +
             
     | 
| 
      
 1744 
     | 
    
         
            +
              yg_map_end(); //all document
         
     | 
| 
      
 1745 
     | 
    
         
            +
             
     | 
| 
      
 1746 
     | 
    
         
            +
              //flush yajl:
         
     | 
| 
      
 1747 
     | 
    
         
            +
              const unsigned char* buf;
         
     | 
| 
      
 1748 
     | 
    
         
            +
              unsigned int len;
         
     | 
| 
      
 1749 
     | 
    
         
            +
              if(yajl_gen_get_buf(yajl, &buf, &len) == yajl_gen_status_ok){
         
     | 
| 
      
 1750 
     | 
    
         
            +
                //fwrite(buf, len, 1, ctx->file);
         
     | 
| 
      
 1751 
     | 
    
         
            +
                VALUE res = rb_str_new(buf, len);
         
     | 
| 
      
 1752 
     | 
    
         
            +
                yajl_gen_clear(yajl);
         
     | 
| 
      
 1753 
     | 
    
         
            +
                yajl_gen_free(yajl);
         
     | 
| 
      
 1754 
     | 
    
         
            +
                return res;
         
     | 
| 
      
 1755 
     | 
    
         
            +
              } else {
         
     | 
| 
      
 1756 
     | 
    
         
            +
                return Qnil;
         
     | 
| 
      
 1757 
     | 
    
         
            +
              }
         
     | 
| 
      
 1758 
     | 
    
         
            +
            #undef YAJL
         
     | 
| 
      
 1759 
     | 
    
         
            +
            }
         
     | 
| 
      
 1760 
     | 
    
         
            +
             
     | 
| 
       1609 
1761 
     | 
    
         
             
            void Init_heap_dump(){
         
     | 
| 
       1610 
1762 
     | 
    
         
             
              //ruby-internal need to be required before linking us, but just in case..
         
     | 
| 
       1611 
1763 
     | 
    
         
             
              ID require, gem;
         
     | 
| 
         @@ -1619,4 +1771,9 @@ void Init_heap_dump(){ 
     | 
|
| 
       1619 
1771 
     | 
    
         | 
| 
       1620 
1772 
     | 
    
         
             
              rb_mHeapDumpModule = rb_define_module("HeapDump");
         
     | 
| 
       1621 
1773 
     | 
    
         
             
              rb_define_singleton_method(rb_mHeapDumpModule, "dump_ext", rb_heapdump_dump, 1);
         
     | 
| 
      
 1774 
     | 
    
         
            +
              rb_define_singleton_method(rb_mHeapDumpModule, "count_objects_ext", rb_heapdump_count_objects, 2);
         
     | 
| 
      
 1775 
     | 
    
         
            +
             
     | 
| 
      
 1776 
     | 
    
         
            +
              rb_define_singleton_method(rb_mHeapDumpModule, "verbose", heapdump_verbose, 0);
         
     | 
| 
      
 1777 
     | 
    
         
            +
              rb_define_singleton_method(rb_mHeapDumpModule, "verbose=", heapdump_verbose_setter, 1);
         
     | 
| 
      
 1778 
     | 
    
         
            +
             
     | 
| 
       1622 
1779 
     | 
    
         
             
            }
         
     | 
| 
         @@ -67,11 +67,7 @@ struct heaps_slot { 
     | 
|
| 
       67 
67 
     | 
    
         
             
                void *membase;
         
     | 
| 
       68 
68 
     | 
    
         
             
                RVALUE *slot;
         
     | 
| 
       69 
69 
     | 
    
         
             
                size_t limit;
         
     | 
| 
       70 
     | 
    
         
            -
                 
     | 
| 
       71 
     | 
    
         
            -
                RVALUE *freelist;
         
     | 
| 
       72 
     | 
    
         
            -
                struct heaps_slot *next;
         
     | 
| 
       73 
     | 
    
         
            -
                struct heaps_slot *prev;
         
     | 
| 
       74 
     | 
    
         
            -
                struct heaps_slot *free_next;
         
     | 
| 
      
 70 
     | 
    
         
            +
                int finalize_flag;
         
     | 
| 
       75 
71 
     | 
    
         
             
            };
         
     | 
| 
       76 
72 
     | 
    
         | 
| 
       77 
73 
     | 
    
         
             
            struct heaps_header {
         
     | 
| 
         @@ -79,16 +75,6 @@ struct heaps_header { 
     | 
|
| 
       79 
75 
     | 
    
         
             
                uintptr_t *bits;
         
     | 
| 
       80 
76 
     | 
    
         
             
            };
         
     | 
| 
       81 
77 
     | 
    
         | 
| 
       82 
     | 
    
         
            -
            struct sorted_heaps_slot {
         
     | 
| 
       83 
     | 
    
         
            -
                RVALUE *start;
         
     | 
| 
       84 
     | 
    
         
            -
                RVALUE *end;
         
     | 
| 
       85 
     | 
    
         
            -
                struct heaps_slot *slot;
         
     | 
| 
       86 
     | 
    
         
            -
            };
         
     | 
| 
       87 
     | 
    
         
            -
             
     | 
| 
       88 
     | 
    
         
            -
            struct heaps_free_bitmap {
         
     | 
| 
       89 
     | 
    
         
            -
                struct heaps_free_bitmap *next;
         
     | 
| 
       90 
     | 
    
         
            -
            };
         
     | 
| 
       91 
     | 
    
         
            -
             
     | 
| 
       92 
78 
     | 
    
         
             
            struct gc_list {
         
     | 
| 
       93 
79 
     | 
    
         
             
                VALUE *varptr;
         
     | 
| 
       94 
80 
     | 
    
         
             
                struct gc_list *next;
         
     | 
| 
         @@ -189,4 +175,10 @@ is_pointer_to_heap(rb_objspace_t *objspace, void *ptr) 
     | 
|
| 
       189 
175 
     | 
    
         
             
                }
         
     | 
| 
       190 
176 
     | 
    
         
             
                  }
         
     | 
| 
       191 
177 
     | 
    
         
             
                return FALSE;
         
     | 
| 
       192 
     | 
    
         
            -
            }
         
     | 
| 
      
 178 
     | 
    
         
            +
            }
         
     | 
| 
      
 179 
     | 
    
         
            +
             
     | 
| 
      
 180 
     | 
    
         
            +
            #define FOR_EACH_HEAP_SLOT(p) for (i = 0; i < heaps_used; i++) {\
         
     | 
| 
      
 181 
     | 
    
         
            +
                  RVALUE *p = heaps[i].slot; RVALUE *pend = p + heaps[i].limit;\
         
     | 
| 
      
 182 
     | 
    
         
            +
                  if(!p || p < heaps[i].membase) continue;\
         
     | 
| 
      
 183 
     | 
    
         
            +
                  for (; p < pend; p++) {
         
     | 
| 
      
 184 
     | 
    
         
            +
            #define FOR_EACH_HEAP_SLOT_END(total) } total += heaps[i].limit; }
         
     | 
| 
         @@ -39,7 +39,39 @@ struct METHOD { 
     | 
|
| 
       39 
39 
     | 
    
         
             
            #define METHOD_DEFINITIONP(m) m->me.def
         
     | 
| 
       40 
40 
     | 
    
         | 
| 
       41 
41 
     | 
    
         
             
            #define HAVE_RB_CLASS_TBL 1
         
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
            inline st_table * rb_get_class_tbl(){
         
     | 
| 
      
 44 
     | 
    
         
            +
              //class.c:
         
     | 
| 
      
 45 
     | 
    
         
            +
              extern st_table *rb_class_tbl;
         
     | 
| 
      
 46 
     | 
    
         
            +
              return rb_class_tbl;
         
     | 
| 
      
 47 
     | 
    
         
            +
            }
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
            #define HAVE_RB_GLOBAL_TBL 1
         
     | 
| 
      
 50 
     | 
    
         
            +
            inline st_table * rb_get_global_tbl(){
         
     | 
| 
      
 51 
     | 
    
         
            +
              //class.c:
         
     | 
| 
      
 52 
     | 
    
         
            +
              extern st_table *rb_global_tbl;
         
     | 
| 
      
 53 
     | 
    
         
            +
              return rb_global_tbl;
         
     | 
| 
      
 54 
     | 
    
         
            +
            }
         
     | 
| 
      
 55 
     | 
    
         
            +
            #define gvar_getter_t rb_gvar_getter_t
         
     | 
| 
      
 56 
     | 
    
         
            +
            #define gvar_setter_t rb_gvar_setter_t
         
     | 
| 
      
 57 
     | 
    
         
            +
            #define gvar_marker_t rb_gvar_marker_t
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
            struct trace_var {
         
     | 
| 
      
 60 
     | 
    
         
            +
                int removed;
         
     | 
| 
      
 61 
     | 
    
         
            +
                void (*func)(VALUE arg, VALUE val);
         
     | 
| 
      
 62 
     | 
    
         
            +
                VALUE data;
         
     | 
| 
      
 63 
     | 
    
         
            +
                struct trace_var *next;
         
     | 
| 
      
 64 
     | 
    
         
            +
            };
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
            //struct global_variable {
         
     | 
| 
      
 67 
     | 
    
         
            +
            struct rb_global_variable {
         
     | 
| 
      
 68 
     | 
    
         
            +
                int   counter;
         
     | 
| 
      
 69 
     | 
    
         
            +
                void *data;
         
     | 
| 
      
 70 
     | 
    
         
            +
                gvar_getter_t *getter;
         
     | 
| 
      
 71 
     | 
    
         
            +
                gvar_setter_t *setter;
         
     | 
| 
      
 72 
     | 
    
         
            +
                gvar_marker_t *marker;
         
     | 
| 
      
 73 
     | 
    
         
            +
                int block_trace;
         
     | 
| 
      
 74 
     | 
    
         
            +
                struct trace_var *trace;
         
     | 
| 
      
 75 
     | 
    
         
            +
            };
         
     | 
| 
       44 
76 
     | 
    
         | 
| 
       45 
77 
     | 
    
         
             
            extern VALUE ruby_engine_name;
         
     | 
| 
         @@ -189,3 +189,10 @@ is_pointer_to_heap(rb_objspace_t *objspace, void *ptr) 
     | 
|
| 
       189 
189 
     | 
    
         
             
                }
         
     | 
| 
       190 
190 
     | 
    
         
             
                return FALSE;
         
     | 
| 
       191 
191 
     | 
    
         
             
            }
         
     | 
| 
      
 192 
     | 
    
         
            +
             
     | 
| 
      
 193 
     | 
    
         
            +
            #define FOR_EACH_HEAP_SLOT(p) for (i = 0; i < heaps_used; i++) {\
         
     | 
| 
      
 194 
     | 
    
         
            +
                  RVALUE *p = objspace->heap.sorted[i].start, *pend = objspace->heap.sorted[i].end;\
         
     | 
| 
      
 195 
     | 
    
         
            +
                  if(!p) continue;\
         
     | 
| 
      
 196 
     | 
    
         
            +
                  for (; p < pend; p++) {
         
     | 
| 
      
 197 
     | 
    
         
            +
            #define FOR_EACH_HEAP_SLOT_END(total) } total += objspace->heap.sorted[i].slot->limit; }
         
     | 
| 
      
 198 
     | 
    
         
            +
             
     | 
| 
         @@ -41,9 +41,39 @@ struct METHOD { 
     | 
|
| 
       41 
41 
     | 
    
         
             
            #define METHOD_DEFINITIONP(m) (m->me ? m->me->def : NULL)
         
     | 
| 
       42 
42 
     | 
    
         | 
| 
       43 
43 
     | 
    
         
             
            //class.c:
         
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
       45 
     | 
    
         
            -
            //For som reason this fails to link on 1.9.3 :(
         
     | 
| 
       46 
     | 
    
         
            -
             
     | 
| 
      
 44 
     | 
    
         
            +
            #define HAVE_RB_CLASS_TBL 1
         
     | 
| 
      
 45 
     | 
    
         
            +
            //For som reason this fails to link directly on 1.9.3 :(
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
            //HACK:
         
     | 
| 
      
 48 
     | 
    
         
            +
            // otool -L `which ruby`
         
     | 
| 
      
 49 
     | 
    
         
            +
            // /Users/vasfed/.rvm/rubies/ruby-1.9.3-p194/bin/ruby:
         
     | 
| 
      
 50 
     | 
    
         
            +
            //   @executable_path/../lib/libruby.1.9.1.dylib (compatibility version 1.9.1, current version 1.9.1)
         
     | 
| 
      
 51 
     | 
    
         
            +
            // nm ~/.rvm/rubies/ruby-1.9.3-p194/lib/libruby.1.9.1.dylib | grep rb_class_tbl
         
     | 
| 
      
 52 
     | 
    
         
            +
            // 000000000024be28 s _rb_class_tbl
         
     | 
| 
      
 53 
     | 
    
         
            +
            // 00000000000b311c T _rb_intern
         
     | 
| 
      
 54 
     | 
    
         
            +
            // 000000000024bd38 S _rb_mKernel
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
            #include <dlfcn.h>
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
            inline st_table * rb_get_class_tbl(){
         
     | 
| 
      
 59 
     | 
    
         
            +
              Dl_info info;
         
     | 
| 
      
 60 
     | 
    
         
            +
              if(!dladdr(rb_intern, &info) || !info.dli_fname){
         
     | 
| 
      
 61 
     | 
    
         
            +
                return NULL;
         
     | 
| 
      
 62 
     | 
    
         
            +
              }
         
     | 
| 
      
 63 
     | 
    
         
            +
              void* image = dlopen(info.dli_fname, RTLD_NOLOAD | RTLD_GLOBAL);
         
     | 
| 
      
 64 
     | 
    
         
            +
              // printf("Image is %p, addr is %p (%p rel)\n", image, rb_intern, ((void*)rb_intern - image));
         
     | 
| 
      
 65 
     | 
    
         
            +
              if(image)
         
     | 
| 
      
 66 
     | 
    
         
            +
              {
         
     | 
| 
      
 67 
     | 
    
         
            +
                void* tbl = dlsym(image, "_rb_class_tbl");
         
     | 
| 
      
 68 
     | 
    
         
            +
                dlclose(image);
         
     | 
| 
      
 69 
     | 
    
         
            +
                if(tbl)
         
     | 
| 
      
 70 
     | 
    
         
            +
                  return tbl;
         
     | 
| 
      
 71 
     | 
    
         
            +
              }
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
              //TODO: parse sym table and calculate address?
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
              return NULL;
         
     | 
| 
      
 76 
     | 
    
         
            +
            }
         
     | 
| 
       47 
77 
     | 
    
         | 
| 
       48 
78 
     | 
    
         
             
            #define ruby_current_thread ((rb_thread_t *)RTYPEDDATA_DATA(rb_thread_current()))
         
     | 
| 
       49 
79 
     | 
    
         | 
    
        data/lib/heap_dump/version.rb
    CHANGED
    
    
    
        data/lib/heap_dump.rb
    CHANGED
    
    | 
         @@ -9,4 +9,18 @@ module HeapDump 
     | 
|
| 
       9 
9 
     | 
    
         
             
                GC.start if gc_before_dump
         
     | 
| 
       10 
10 
     | 
    
         
             
                return dump_ext(filename)
         
     | 
| 
       11 
11 
     | 
    
         
             
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              # provides an object count - like ObjectSpace.count_objects, but also for user classes
         
     | 
| 
      
 14 
     | 
    
         
            +
              def self.count_objects namespaces_array, gc=false
         
     | 
| 
      
 15 
     | 
    
         
            +
                unless namespaces_array.is_a?(Array) && namespaces_array.all?{|v|v.is_a? Symbol}
         
     | 
| 
      
 16 
     | 
    
         
            +
                  if namespaces_array.is_a? Symbol
         
     | 
| 
      
 17 
     | 
    
         
            +
                    namespaces_array = [namespaces_array]
         
     | 
| 
      
 18 
     | 
    
         
            +
                  else
         
     | 
| 
      
 19 
     | 
    
         
            +
                    #TODO: actually, better way is to accept anything convertable, even module itself
         
     | 
| 
      
 20 
     | 
    
         
            +
                    raise ArgumentError.new("namespaces_array must be a symbol or array of symbols")
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
                prefixes_array = namespaces_array.map{|c| c.to_s}
         
     | 
| 
      
 24 
     | 
    
         
            +
                return count_objects_ext(prefixes_array, !!gc)
         
     | 
| 
      
 25 
     | 
    
         
            +
              end
         
     | 
| 
       12 
26 
     | 
    
         
             
            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. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.0.29
         
     | 
| 
       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- 
     | 
| 
      
 12 
     | 
    
         
            +
            date: 2012-11-19 00:00:00.000000000 Z
         
     | 
| 
       13 
13 
     | 
    
         
             
            dependencies:
         
     | 
| 
       14 
14 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       15 
15 
     | 
    
         
             
              name: debugger-ruby_core_source
         
     | 
| 
         @@ -105,7 +105,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement 
     | 
|
| 
       105 
105 
     | 
    
         
             
                  version: '0'
         
     | 
| 
       106 
106 
     | 
    
         
             
                  segments:
         
     | 
| 
       107 
107 
     | 
    
         
             
                  - 0
         
     | 
| 
       108 
     | 
    
         
            -
                  hash: - 
     | 
| 
      
 108 
     | 
    
         
            +
                  hash: -3423213544880593547
         
     | 
| 
       109 
109 
     | 
    
         
             
            requirements: []
         
     | 
| 
       110 
110 
     | 
    
         
             
            rubyforge_project: 
         
     | 
| 
       111 
111 
     | 
    
         
             
            rubygems_version: 1.8.24
         
     |