ruby-changes:53785
From: ko1 <ko1@a...>
Date: Tue, 27 Nov 2018 03:16:45 +0900 (JST)
Subject: [ruby-changes:53785] ko1:r66003 (trunk): Support targetting TracePoint [Feature #15289]
ko1 2018-11-27 03:16:39 +0900 (Tue, 27 Nov 2018) New Revision: 66003 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=66003 Log: Support targetting TracePoint [Feature #15289] * vm_trace.c (rb_tracepoint_enable_for_target): support targetting TracePoint. [Feature #15289] Tragetting TracePoint is only enabled on specified method, proc and so on, example: `tp.enable(target: code)`. `code` should be consisted of InstructionSeuqnece (iseq) (RubyVM::InstructionSeuqnece.of(code) should not return nil) If code is a tree of iseq, TracePoint is enabled on all of iseqs in a tree. Enabled tragetting TracePoints can not enabled again with and without target. * vm_core.h (rb_iseq_t): introduce `rb_iseq_t::local_hooks` to store local hooks. `rb_iseq_t::aux::trace_events` is renamed to `global_trace_events` to contrast with `local_hooks`. * vm_core.h (rb_hook_list_t): add `rb_hook_list_t::running` to represent how many Threads/Fibers are used this list. If this field is 0, nobody using this hooks and we can delete it. This is why we can remove code from cont.c. * vm_core.h (rb_vm_t): because of above change, we can eliminate `rb_vm_t::trace_running` field. Also renamed from `rb_vm_t::event_hooks` to `global_hooks`. * vm_core.h, vm.c (ruby_vm_event_enabled_global_flags): renamed from `ruby_vm_event_enabled_flags. * vm_core.h, vm.c (ruby_vm_event_local_num): added to count enabled targetting TracePoints. * vm_core.h, vm_trace.c (rb_exec_event_hooks): accepts hook list. * vm_core.h (rb_vm_global_hooks): added for convinience. * method.h (rb_method_bmethod_t): added to maintain Proc and `rb_hook_list_t` for bmethod (defined by define_method). * prelude.rb (TracePoint#enable): extracet a keyword parameter (because it is easy than writing in C). It calls `TracePoint#__enable` internal method written in C. * vm_insnhelper.c (vm_trace): check also iseq->local_hooks. * vm.c (invoke_bmethod): check def->body.bmethod.hooks. * vm.c (hook_before_rewind): check iseq->local_hooks and def->body.bmethod.hooks before rewind by exception. Modified files: trunk/cont.c trunk/gc.c trunk/iseq.c trunk/iseq.h trunk/method.h trunk/mjit_worker.c trunk/prelude.rb trunk/proc.c trunk/test/ruby/test_settracefunc.rb trunk/thread.c trunk/tool/ruby_vm/views/_mjit_compile_insn.erb trunk/tool/ruby_vm/views/_mjit_compile_send.erb trunk/vm.c trunk/vm_core.h trunk/vm_insnhelper.c trunk/vm_method.c trunk/vm_trace.c Index: prelude.rb =================================================================== --- prelude.rb (revision 66002) +++ prelude.rb (revision 66003) @@ -132,6 +132,12 @@ class IO https://github.com/ruby/ruby/blob/trunk/prelude.rb#L132 end end +class TracePoint + def enable target: nil, &blk + self.__enable target, &blk + end +end + class Binding # :nodoc: def irb Index: method.h =================================================================== --- method.h (revision 66002) +++ method.h (revision 66003) @@ -147,6 +147,11 @@ typedef struct rb_method_refined_struct https://github.com/ruby/ruby/blob/trunk/method.h#L147 const VALUE owner; } rb_method_refined_t; +typedef struct rb_method_bmethod_struct { + const VALUE proc; /* should be marked */ + struct rb_hook_list_struct *hooks; +} rb_method_bmethod_t; + enum method_optimized_type { OPTIMIZED_METHOD_TYPE_SEND, OPTIMIZED_METHOD_TYPE_CALL, @@ -165,9 +170,9 @@ PACKED_STRUCT_UNALIGNED(struct rb_method https://github.com/ruby/ruby/blob/trunk/method.h#L170 rb_method_attr_t attr; rb_method_alias_t alias; rb_method_refined_t refined; + rb_method_bmethod_t bmethod; - const VALUE proc; /* should be marked */ - enum method_optimized_type optimize_type; + enum method_optimized_type optimize_type; } body; ID original_id; Index: vm_core.h =================================================================== --- vm_core.h (revision 66002) +++ vm_core.h (revision 66003) @@ -474,7 +474,7 @@ struct rb_iseq_constant_body { https://github.com/ruby/ruby/blob/trunk/vm_core.h#L474 /* typedef rb_iseq_t is in method.h */ struct rb_iseq_struct { VALUE flags; - VALUE reserved1; + struct rb_hook_list_struct *local_hooks; struct rb_iseq_constant_body *body; union { /* 4, 5 words */ @@ -485,7 +485,7 @@ struct rb_iseq_struct { https://github.com/ruby/ruby/blob/trunk/vm_core.h#L485 int index; } loader; - rb_event_flag_t trace_events; + rb_event_flag_t global_trace_events; } aux; }; @@ -577,7 +577,8 @@ void rb_objspace_free(struct rb_objspace https://github.com/ruby/ruby/blob/trunk/vm_core.h#L577 typedef struct rb_hook_list_struct { struct rb_event_hook_struct *hooks; rb_event_flag_t events; - int need_clean; + unsigned int need_clean; + unsigned int running; } rb_hook_list_t; typedef struct rb_vm_struct { @@ -608,8 +609,6 @@ typedef struct rb_vm_struct { https://github.com/ruby/ruby/blob/trunk/vm_core.h#L609 unsigned int thread_report_on_exception: 1; unsigned int safe_level_: 1; - - int trace_running; int sleeper; /* object management */ @@ -634,7 +633,7 @@ typedef struct rb_vm_struct { https://github.com/ruby/ruby/blob/trunk/vm_core.h#L633 } trap_list; /* hook */ - rb_hook_list_t event_hooks; + rb_hook_list_t global_hooks; /* relation table of ensure - rollback for callcc */ struct st_table *ensure_rollback_table; @@ -1694,7 +1693,8 @@ RUBY_SYMBOL_EXPORT_BEGIN https://github.com/ruby/ruby/blob/trunk/vm_core.h#L1693 RUBY_EXTERN rb_vm_t *ruby_current_vm_ptr; RUBY_EXTERN rb_execution_context_t *ruby_current_execution_context_ptr; RUBY_EXTERN rb_event_flag_t ruby_vm_event_flags; -RUBY_EXTERN rb_event_flag_t ruby_vm_event_enabled_flags; +RUBY_EXTERN rb_event_flag_t ruby_vm_event_enabled_global_flags; +RUBY_EXTERN unsigned int ruby_vm_event_local_num; RUBY_SYMBOL_EXPORT_END @@ -1805,6 +1805,7 @@ rb_vm_check_ints(rb_execution_context_t https://github.com/ruby/ruby/blob/trunk/vm_core.h#L1805 } /* tracer */ + struct rb_trace_arg_struct { rb_event_flag_t event; rb_execution_context_t *ec; @@ -1822,24 +1823,29 @@ struct rb_trace_arg_struct { https://github.com/ruby/ruby/blob/trunk/vm_core.h#L1823 VALUE path; }; -void rb_exec_event_hooks(struct rb_trace_arg_struct *trace_arg, int pop_p); +void rb_hook_list_mark(rb_hook_list_t *hooks); +void rb_hook_list_free(rb_hook_list_t *hooks); +void rb_hook_list_connect_tracepoint(VALUE target, rb_hook_list_t *list, VALUE tpval); +void rb_hook_list_remove_tracepoint(rb_hook_list_t *list, VALUE tpval); -#define EXEC_EVENT_HOOK_ORIG(ec_, flag_, vm_flags_, self_, id_, called_id_, klass_, data_, pop_p_) do { \ +void rb_exec_event_hooks(struct rb_trace_arg_struct *trace_arg, rb_hook_list_t *hooks, int pop_p); + +#define EXEC_EVENT_HOOK_ORIG(ec_, hooks_, flag_, self_, id_, called_id_, klass_, data_, pop_p_) do { \ const rb_event_flag_t flag_arg_ = (flag_); \ - if (UNLIKELY(vm_flags_ & (flag_arg_))) { \ - /* defer evaluating the other arguments */ \ - rb_exec_event_hook_orig(ec_, flag_arg_, self_, id_, called_id_, klass_, data_, pop_p_); \ + rb_hook_list_t *hooks_arg_ = (hooks_); \ + if (UNLIKELY((hooks_arg_)->events & (flag_arg_))) { \ + /* defer evaluating the other arguments */ \ + rb_exec_event_hook_orig(ec_, hooks_arg_, flag_arg_, self_, id_, called_id_, klass_, data_, pop_p_); \ } \ } while (0) static inline void -rb_exec_event_hook_orig(rb_execution_context_t *ec, const rb_event_flag_t flag, - VALUE self, ID id, ID called_id, VALUE klass, VALUE data, int pop_p) +rb_exec_event_hook_orig(rb_execution_context_t *ec, rb_hook_list_t *hooks, rb_event_flag_t flag, + VALUE self, ID id, ID called_id, VALUE klass, VALUE data, int pop_p) { struct rb_trace_arg_struct trace_arg; - VM_ASSERT(rb_ec_vm_ptr(ec)->event_hooks.events == ruby_vm_event_flags); - VM_ASSERT(rb_ec_vm_ptr(ec)->event_hooks.events & flag); + VM_ASSERT((hooks->events & flag) != 0); trace_arg.event = flag; trace_arg.ec = ec; @@ -1851,14 +1857,21 @@ rb_exec_event_hook_orig(rb_execution_con https://github.com/ruby/ruby/blob/trunk/vm_core.h#L1857 trace_arg.data = data; trace_arg.path = Qundef; trace_arg.klass_solved = 0; - rb_exec_event_hooks(&trace_arg, pop_p); + + rb_exec_event_hooks(&trace_arg, hooks, pop_p); +} + +static inline rb_hook_list_t * +rb_vm_global_hooks(const rb_execution_context_t *ec) +{ + return &rb_ec_vm_ptr(ec)->global_hooks; } #define EXEC_EVENT_HOOK(ec_, flag_, self_, id_, called_id_, klass_, data_) \ - EXEC_EVENT_HOOK_ORIG(ec_, flag_, ruby_vm_event_flags, self_, id_, called_id_, klass_, data_, 0) + EXEC_EVENT_HOOK_ORIG(ec_, rb_vm_global_hooks(ec_), flag_, self_, id_, called_id_, klass_, data_, 0) #define EXEC_EVENT_HOOK_AND_POP_FRAME(ec_, flag_, self_, id_, called_id_, klass_, data_) \ - EXEC_EVENT_HOOK_ORIG(ec_, flag_, ruby_vm_event_flags, self_, id_, called_id_, klass_, data_, 1) + EXEC_EVENT_HOOK_ORIG(ec_, rb_vm_global_hooks(ec_), flag_, self_, id_, called_id_, klass_, data_, 1) RUBY_SYMBOL_EXPORT_BEGIN Index: iseq.c =================================================================== --- iseq.c (revision 66002) +++ iseq.c (revision 66003) @@ -111,6 +111,11 @@ rb_iseq_free(const rb_iseq_t *iseq) https://github.com/ruby/ruby/blob/trunk/iseq.c#L111 compile_data_free(ISEQ_COMPILE_DATA(iseq)); ruby_xfree(body); } + + if (iseq->local_hooks) { + rb_hook_list_free(iseq->local_hooks); + } + RUBY_FREE_LEAVE("iseq"); } @@ -247,6 +252,9 @@ rb_iseq_mark(const rb_iseq_t *iseq) https://github.com/ruby/ruby/blob/trunk/iseq.c#L252 } } + if (iseq->local_hooks) { + rb_hook_list_mark(iseq->local_hooks); + } if (FL_TEST(iseq, ISEQ_NOT_LOADED_YET)) { rb_gc_mark(iseq->aux.loader.obj); @@ -511,9 +519,9 @@ rb_iseq_insns_info_decode_positions(cons https://github.com/ruby/ruby/blob/trunk/iseq.c#L519 void rb_iseq_init_trace(rb_iseq_t *iseq) { - iseq->aux.trace_events = 0; - if (ruby_vm_event_enabled_flags & ISEQ_TRACE_EVENTS) { - rb_iseq_trace_set(iseq, ruby_vm_event_enabled_flags & ISEQ_TRACE_EVENTS); + iseq->aux.global_trace_events = 0; + if (ruby_vm_event_enabled_global_flags & ISEQ_TRACE_EVENTS) { + rb_iseq_trace_set(iseq, ruby_vm_event_enabled_global_flags & ISEQ_TRACE_EVENTS); } } @@ -1668,7 +1676,7 @@ rb_iseq_clear_event_flags(const rb_iseq_ https://github.com/ruby/ruby/blob/trunk/iseq.c#L1676 struct iseq_insn_info_entry *entry = (struct iseq_insn_info_entry *)get_insn_info(iseq, pos); if (entry) { entry->events &= ~reset; - if (!(entry->events & iseq->aux.trace_events)) { + if (!(entry->events & iseq->aux.global_trace_events)) { void rb_iseq_trace_flag_cleared(const rb_iseq_t *iseq, size_t pos); rb_iseq_trace_flag_cleared(iseq, pos); } @@ -1939,8 +1947,7 @@ rb_iseq_disasm_insn(VALUE ret, const VAL https://github.com/ruby/ruby/blob/trunk/iseq.c#L1947 events & RUBY_EVENT_B_CALL ? "Bc" : "", events & RUBY_EVENT_B_RETURN ? "Br" : "", events & RUBY_EVENT_COVERAGE_LINE ? "Cli" : "", - events & RUBY_EVENT_COVERAGE_BRANCH ? "Cbr" : "" - ); + events & RUBY_EVENT_COVERAGE_BRANCH ? "Cbr" : ""); } } @@ -2137,47 +2144,6 @@ rb_iseq_disasm(const rb_iseq_t *iseq) https://github.com/ruby/ruby/blob/trunk/iseq.c#L2144 return rb_iseq_disasm_recursive(iseq, rb_str_new(0, 0)); } -static VALUE -rb_iseq_all_children(const rb_iseq_t *iseq) -{ - unsigned int i; - VALUE *code = rb_iseq_original_iseq(iseq); - VALUE all_children = rb_obj_hide(rb_ident_hash_new()); - VALUE child; - const struct rb_iseq_constant_body *const body = iseq->body; - - if (body->catch_table) { - for (i = 0; i < body->catch_table->size; i++) { - const struct iseq_catch_table_entry *entry = &body->catch_table->entries[i]; - child = (VALUE)entry->iseq; - if (child) { - rb_hash_aset(all_children, child, Qtrue); - } - } - } - for (i=0; i<body->iseq_size;) { - VALUE insn = code[i]; - int len = insn_len(insn); - const char *types = insn_op_types(insn); - int j; - - for (j=0; types[j]; j++) { - switch (types[j]) { - case TS_ISEQ: - child = code[i+j+1]; - if (child) { - rb_hash_aset(all_children, child, Qtrue); - } - break; - default: - break; - } - } - i += len; - } - return all_children; -} - /* * call-seq: * iseq.disasm -> str @@ -2203,10 +2169,58 @@ iseqw_disasm(VALUE self) https://github.com/ruby/ruby/blob/trunk/iseq.c#L2169 } static int -iseqw_each_child_i(VALUE key, VALUE value, VALUE dummy) +iseq_iterate_children(const rb_iseq_t *iseq, void (*iter_func)(const rb_iseq_t *child_iseq, void *data), void *data) { - rb_yield(iseqw_new((const rb_iseq_t *)key)); - return ST_CONTINUE; + unsigned int i; + VALUE *code = rb_iseq_original_iseq(iseq); + const struct rb_iseq_constant_body *const body = iseq->body; + const rb_iseq_t *child; + VALUE all_children = rb_obj_hide(rb_ident_hash_new()); + + if (body->catch_table) { + for (i = 0; i < body->catch_table->size; i++) { + const struct iseq_catch_table_entry *entry = &body->catch_table->entries[i]; + child = entry->iseq; + if (child) { + if (rb_hash_aref(all_children, (VALUE)child) == Qnil) { + rb_hash_aset(all_children, (VALUE)child, Qtrue); + (*iter_func)(child, data); + } + } + } + } + + for (i=0; i<body->iseq_size;) { + VALUE insn = code[i]; + int len = insn_len(insn); + const char *types = insn_op_types(insn); + int j; + + for (j=0; types[j]; j++) { + switch (types[j]) { + case TS_ISEQ: + child = (const rb_iseq_t *)code[i+j+1]; + if (child) { + if (rb_hash_aref(all_children, (VALUE)child) == Qnil) { + rb_hash_aset(all_children, (VALUE)child, Qtrue); + (*iter_func)(child, data); + } + } + break; + default: + break; + } + } + i += len; + } + + return RHASH_SIZE(all_children); +} + +static void +yield_each_children(const rb_iseq_t *child_iseq, void *data) +{ + rb_yield(iseqw_new(child_iseq)); } /* @@ -2221,8 +2235,7 @@ static VALUE https://github.com/ruby/ruby/blob/trunk/iseq.c#L2235 iseqw_each_child(VALUE self) { const rb_iseq_t *iseq = iseqw_check(self); - VALUE all_children = rb_iseq_all_children(iseq); - rb_hash_foreach(all_children, iseqw_each_child_i, Qnil); + iseq_iterate_children(iseq, yield_each_children, NULL); return self; } @@ -2966,12 +2979,111 @@ rb_iseq_trace_flag_cleared(const rb_iseq https://github.com/ruby/ruby/blob/trunk/iseq.c#L2979 encoded_iseq_trace_instrument(&iseq_encoded[pos], 0); } +static int +iseq_add_local_tracepoint(const rb_iseq_t *iseq, rb_event_flag_t turnon_events, VALUE tpval) +{ + unsigned int pc; + int n = 0; + const struct rb_iseq_constant_body *const body = iseq->body; + VALUE *iseq_encoded = (VALUE *)body->iseq_encoded; + + VM_ASSERT((iseq->flags & ISEQ_USE_COMPILE_DATA) == 0); + + for (pc=0; pc<body->iseq_size;) { + rb_event_flag_t pc_events = rb_iseq_event_flags(iseq, pc); + if (pc_events & turnon_events) { + n++; + } + pc += encoded_iseq_trace_instrument(&iseq_encoded[pc], pc_events & (turnon_events | iseq->aux.global_trace_events)); + } + + if (n > 0) { + if (iseq->local_hooks == NULL) { + ((rb_iseq_t *)iseq)->local_hooks = RB_ZALLOC(rb_hook_list_t); + } + rb_hook_list_connect_tracepoint((VALUE)iseq, iseq->local_hooks, tpval); + } + + return n; +} + +struct trace_set_local_events_struct { + rb_event_flag_t turnon_events; + VALUE tpval; + int n; +}; + +static void +iseq_add_local_tracepoint_i(const rb_iseq_t *iseq, void *p) +{ + struct trace_set_local_events_struct *data = (struct trace_set_local_events_struct *)p; + data->n += iseq_add_local_tracepoint(iseq, data->turnon_events, data->tpval); + iseq_iterate_children(iseq, iseq_add_local_tracepoint_i, p); +} + +int +rb_iseq_add_local_tracepoint_recursively(const rb_iseq_t *iseq, rb_event_flag_t turnon_events, VALUE tpval) +{ + struct trace_set_local_events_struct data = {turnon_events, tpval, 0}; + iseq_add_local_tracepoint_i(iseq, (void *)&data); + if (0) rb_funcall(Qnil, rb_intern("puts"), 1, rb_iseq_disasm(iseq)); /* for debug */ + return data.n; +} + +static int +iseq_remove_local_tracepoint(const rb_iseq_t *iseq, VALUE tpval) +{ + int n = 0; + + if (iseq->local_hooks) { + unsigned int pc; + const struct rb_iseq_constant_body *const body = iseq->body; + VALUE *iseq_encoded = (VALUE *)body->iseq_encoded; + rb_event_flag_t local_events = 0; + + rb_hook_list_remove_tracepoint(iseq->local_hooks, tpval); + local_events = iseq->local_hooks->events; + + if (local_events == 0) { + if (iseq->local_hooks->running == 0) { + rb_hook_list_free(iseq->local_hooks); + } + ((rb_iseq_t *)iseq)->local_hooks = NULL; + } + + for (pc = 0; pc<body->iseq_size;) { + rb_event_flag_t pc_events = rb_iseq_event_flags(iseq, pc); + pc += encoded_iseq_trace_instrument(&iseq_encoded[pc], pc_events & (local_events | iseq->aux.global_trace_events)); + } + } + return n; +} + +struct trace_clear_local_events_struct { + VALUE tpval; + int n; +}; + +static void +iseq_remove_local_tracepoint_i(const rb_iseq_t *iseq, void *p) +{ + struct trace_clear_local_events_struct *data = (struct trace_clear_local_events_struct *)p; + data->n += iseq_remove_local_tracepoint(iseq, data->tpval); + iseq_iterate_children(iseq, iseq_remove_local_tracepoint_i, p); +} + +int +rb_iseq_remove_local_tracepoint_recursively(const rb_iseq_t *iseq, VALUE tpval) +{ + struct trace_clear_local_events_struct data = {tpval, 0}; + iseq_remove_local_tracepoint_i(iseq, (void *)&data); + return data.n; +} + void rb_iseq_trace_set(const rb_iseq_t *iseq, rb_event_flag_t turnon_events) { - VM_ASSERT((turnon_events & ~ISEQ_TRACE_EVENTS) == 0); - - if (iseq->aux.trace_events == turnon_events) { + if (iseq->aux.global_trace_events == turnon_events) { return; } if (iseq->flags & ISEQ_USE_COMPILE_DATA) { @@ -2979,16 +3091,18 @@ rb_iseq_trace_set(const rb_iseq_t *iseq, https://github.com/ruby/ruby/blob/trunk/iseq.c#L3091 return; } else { - unsigned int i; + unsigned int pc; const struct rb_iseq_constant_body *const body = iseq->body; VALUE *iseq_encoded = (VALUE *)body->iseq_encoded; - ((rb_iseq_t *)iseq)->aux.trace_events = turnon_events; - - for (i=0; i<body->iseq_size;) { - rb_event_flag_t events = rb_iseq_event_flags(iseq, i); - i += encoded_iseq_trace_instrument(&iseq_encoded[i], events & turnon_events); + rb_event_flag_t enabled_events; + rb_event_flag_t local_events = iseq->local_hooks ? iseq->local_hooks->events : 0; + ((rb_iseq_t *)iseq)->aux.global_trace_events = turnon_events; + enabled_events = turnon_events | local_events; + + for (pc=0; pc<body->iseq_size;) { + rb_event_flag_t pc_events = rb_iseq_event_flags(iseq, pc); + pc += encoded_iseq_trace_instrument(&iseq_encoded[pc], pc_events & enabled_events); } - /* clear for debugging: ISEQ_ORIGINAL_ISEQ_CLEAR(iseq); */ } } @@ -3013,7 +3127,7 @@ rb_iseq_trace_set_all(rb_event_flag_t tu https://github.com/ruby/ruby/blob/trunk/iseq.c#L3127 } /* This is exported since Ruby 2.5 but not internally used for now. If you're going to use this, please - update `ruby_vm_event_enabled_flags` and set `mjit_call_p = FALSE` as well to cancel MJIT code. */ + update `ruby_vm_event_enabled_global_flags` and set `mjit_call_p = FALSE` as well to cancel MJIT code. */ void rb_iseq_trace_on_all(void) { Index: iseq.h =================================================================== --- iseq.h (revision 66002) +++ iseq.h (revision 66003) @@ -148,6 +148,8 @@ void rb_ibf_load_iseq_complete(rb_iseq_t https://github.com/ruby/ruby/blob/trunk/iseq.h#L148 const rb_iseq_t *rb_iseq_ibf_load(VALUE str); VALUE rb_iseq_ibf_load_extra_data(VALUE str); void rb_iseq_init_trace(rb_iseq_t *iseq); +int rb_iseq_add_local_tracepoint_recursively(const rb_iseq_t *iseq, rb_event_flag_t turnon_events, VALUE tpval); +int rb_iseq_remove_local_tracepoint_recursively(const rb_iseq_t *iseq, VALUE tpval); #if VM_INSN_INFO_TABLE_IMPL == 2 unsigned int *rb_iseq_insns_info_decode_positions(const struct rb_iseq_constant_body *body); Index: proc.c =================================================================== --- proc.c (revision 66002) +++ proc.c (revision 66003) @@ -2342,7 +2342,7 @@ rb_method_entry_min_max_arity(const rb_m https://github.com/ruby/ruby/blob/trunk/proc.c#L2342 def = def->body.alias.original_me->def; goto again; case VM_METHOD_TYPE_BMETHOD: - return rb_proc_min_max_arity(def->body.proc, max); + return rb_proc_min_max_arity(def->body.bmethod.proc, max); case VM_METHOD_TYPE_ISEQ: return rb_iseq_min_max_arity(rb_iseq_check(def->body.iseq.iseqptr), max); case VM_METHOD_TYPE_UNDEF: @@ -2478,8 +2478,8 @@ rb_obj_method_arity(VALUE obj, ID id) https://github.com/ruby/ruby/blob/trunk/proc.c#L2478 return rb_mod_method_arity(CLASS_OF(obj), id); } -static inline const rb_method_definition_t * -method_def(VALUE method) +const rb_method_definition_t * +rb_method_def(VALUE method) { const struct METHOD *data; @@ -2494,7 +2494,7 @@ method_def_iseq(const rb_method_definiti https://github.com/ruby/ruby/blob/trunk/proc.c#L2494 case VM_METHOD_TYPE_ISEQ: return rb_iseq_check(def->body.iseq.iseqptr); case VM_METHOD_TYPE_BMETHOD: - return rb_proc_get_iseq(def->body.proc, 0); + return rb_proc_get_iseq(def->body.bmethod.proc, 0); case VM_METHOD_TYPE_ALIAS: return meth (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/