ruby-changes:38647
From: ko1 <ko1@a...>
Date: Tue, 2 Jun 2015 13:20:42 +0900 (JST)
Subject: [ruby-changes:38647] ko1:r50728 (trunk): * method.h: make rb_method_entry_t a VALUE.
ko1 2015-06-02 13:20:30 +0900 (Tue, 02 Jun 2015) New Revision: 50728 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=50728 Log: * method.h: make rb_method_entry_t a VALUE. Motivation and new data structure are described in [Bug #11203]. This patch also solve the following issues. * [Bug #11200] Memory leak of method entries * [Bug #11046] __callee__ returns incorrect method name in orphan proc * test/ruby/test_method.rb: add a test for [Bug #11046]. * vm_core.h: remvoe rb_control_frame_t::me. me is located at value stack. * vm_core.h, gc.c, vm_method.c: remove unlinked_method... codes because method entries are simple VALUEs. * method.h: Now, all method entries has own independent method definititons. Strictly speaking, this change is not essential, but for future changes. * rb_method_entry_t::flag is move to rb_method_definition_t::flag. * rb_method_definition_t::alias_count is now rb_method_definition_t::alias_count_ptr, a pointer to the counter. * vm_core.h, vm_insnhelper.c (rb_vm_frame_method_entry) added to search the current method entry from value stack. * vm_insnhelper.c (VM_CHECK_MODE): introduced to enable/disable assertions. Modified files: trunk/ChangeLog trunk/class.c trunk/cont.c trunk/eval.c trunk/gc.c trunk/insns.def trunk/internal.h trunk/method.h trunk/proc.c trunk/struct.c trunk/test/ruby/test_method.rb trunk/thread.c trunk/vm.c trunk/vm_args.c trunk/vm_backtrace.c trunk/vm_core.h trunk/vm_dump.c trunk/vm_eval.c trunk/vm_insnhelper.c trunk/vm_method.c Index: method.h =================================================================== --- method.h (revision 50727) +++ method.h (revision 50728) @@ -44,6 +44,14 @@ typedef enum { https://github.com/ruby/ruby/blob/trunk/method.h#L44 /* method data type */ +typedef struct rb_method_entry_struct { + VALUE flags; + VALUE reserved; + struct rb_method_definition_struct * const def; + ID called_id; + const VALUE klass; /* should be marked */ +} rb_method_entry_t; + typedef enum { VM_METHOD_TYPE_ISEQ, VM_METHOD_TYPE_CFUNC, @@ -61,6 +69,14 @@ typedef enum { https://github.com/ruby/ruby/blob/trunk/method.h#L69 END_OF_ENUMERATION(VM_METHOD_TYPE) } rb_method_type_t; +typedef struct rb_iseq_struct rb_iseq_t; + +typedef struct rb_method_iseq_struct { + rb_iseq_t * const iseqptr; /* should be separated from iseqval */ + rb_cref_t * const cref; /* shoudl be marked */ + const VALUE iseqval; /* should be marked */ +} rb_method_iseq_t; + typedef struct rb_method_cfunc_struct { VALUE (*func)(ANYARGS); VALUE (*invoker)(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv); @@ -69,25 +85,21 @@ typedef struct rb_method_cfunc_struct { https://github.com/ruby/ruby/blob/trunk/method.h#L85 typedef struct rb_method_attr_struct { ID id; - const VALUE location; + const VALUE location; /* sould be marked */ } rb_method_attr_t; typedef struct rb_method_alias_struct { const struct rb_method_entry_struct *original_me; /* original_me->klass is original owner */ } rb_method_alias_t; -typedef struct rb_iseq_struct rb_iseq_t; - typedef struct rb_method_definition_struct { + rb_method_flag_t flag; rb_method_type_t type; /* method type */ - int alias_count; + int *alias_count_ptr; ID original_id; union { - struct { - rb_iseq_t *const iseq; /* should be marked */ - rb_cref_t *cref; - } iseq_body; + rb_method_iseq_t iseq; rb_method_cfunc_t cfunc; rb_method_attr_t attr; rb_method_alias_t alias; @@ -102,26 +114,13 @@ typedef struct rb_method_definition_stru https://github.com/ruby/ruby/blob/trunk/method.h#L114 } body; } rb_method_definition_t; -typedef struct rb_method_entry_struct { - rb_method_flag_t flag; - char mark; - rb_method_definition_t *def; - ID called_id; - VALUE klass; /* should be marked */ -} rb_method_entry_t; - -struct unlinked_method_entry_list_entry { - struct unlinked_method_entry_list_entry *next; - rb_method_entry_t *me; -}; - #define UNDEFINED_METHOD_ENTRY_P(me) (!(me) || !(me)->def || (me)->def->type == VM_METHOD_TYPE_UNDEF) #define UNDEFINED_REFINED_METHOD_P(def) \ ((def)->type == VM_METHOD_TYPE_REFINED && \ UNDEFINED_METHOD_ENTRY_P((def)->body.orig_me)) void rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_method_flag_t noex); -void rb_add_method_iseq(VALUE klass, ID mid, rb_iseq_t *iseq, rb_cref_t *cref, rb_method_flag_t noex); +void rb_add_method_iseq(VALUE klass, ID mid, VALUE iseq, rb_cref_t *cref, rb_method_flag_t noex); rb_method_entry_t *rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *option, rb_method_flag_t noex); rb_method_entry_t *rb_method_entry(VALUE klass, ID id, VALUE *define_class_ptr); rb_method_entry_t *rb_method_entry_at(VALUE obj, ID id); @@ -145,8 +144,11 @@ VALUE rb_method_entry_location(const rb_ https://github.com/ruby/ruby/blob/trunk/method.h#L144 VALUE rb_mod_method_location(VALUE mod, ID id); VALUE rb_obj_method_location(VALUE obj, ID id); -void rb_mark_method_entry(const rb_method_entry_t *me); void rb_free_method_entry(const rb_method_entry_t *me); void rb_sweep_method_entry(void *vm); +rb_method_entry_t *rb_method_entry_create(ID called_id, VALUE klass, rb_method_definition_t *def); +rb_method_entry_t *rb_method_entry_clone(const rb_method_entry_t *me); +void rb_method_entry_copy(rb_method_entry_t *dst, rb_method_entry_t *src); + #endif /* METHOD_H */ Index: insns.def =================================================================== --- insns.def (revision 50727) +++ insns.def (revision 50728) @@ -760,8 +760,9 @@ defined https://github.com/ruby/ruby/blob/trunk/insns.def#L760 const rb_method_entry_t *me = rb_method_entry(klass, SYM2ID(obj), 0); if (me) { - if (!(me->flag & NOEX_PRIVATE)) { - if (!((me->flag & NOEX_PROTECTED) && + const rb_method_definition_t *def = me->def; + if (!(def->flag & NOEX_PRIVATE)) { + if (!((def->flag & NOEX_PROTECTED) && !rb_obj_is_kind_of(GET_SELF(), rb_class_real(klass)))) { expr_type = DEFINED_METHOD; @@ -1015,9 +1016,9 @@ defineclass https://github.com/ruby/ruby/blob/trunk/insns.def#L1016 vm_push_frame(th, class_iseq, VM_FRAME_MAGIC_CLASS, klass, 0, VM_ENVVAL_BLOCK_PTR(GET_BLOCK_PTR()), - vm_cref_push(th, klass, NOEX_PUBLIC, NULL), + (VALUE)vm_cref_push(th, klass, NOEX_PUBLIC, NULL), class_iseq->iseq_encoded, GET_SP(), - class_iseq->local_size, 0, class_iseq->stack_max); + class_iseq->local_size, class_iseq->stack_max); RESTORE_REGS(); NEXT_INSN(); Index: ChangeLog =================================================================== --- ChangeLog (revision 50727) +++ ChangeLog (revision 50728) @@ -1,3 +1,36 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Tue Jun 2 12:43:46 2015 Koichi Sasada <ko1@a...> + + * method.h: make rb_method_entry_t a VALUE. + Motivation and new data structure are described in [Bug #11203]. + + This patch also solve the following issues. + + * [Bug #11200] Memory leak of method entries + * [Bug #11046] __callee__ returns incorrect method name in orphan + proc + + * test/ruby/test_method.rb: add a test for [Bug #11046]. + + * vm_core.h: remvoe rb_control_frame_t::me. me is located at value + stack. + + * vm_core.h, gc.c, vm_method.c: remove unlinked_method... codes + because method entries are simple VALUEs. + + * method.h: Now, all method entries has own independent method + definititons. Strictly speaking, this change is not essential, + but for future changes. + + * rb_method_entry_t::flag is move to rb_method_definition_t::flag. + * rb_method_definition_t::alias_count is now + rb_method_definition_t::alias_count_ptr, a pointer to the counter. + + * vm_core.h, vm_insnhelper.c (rb_vm_frame_method_entry) added to + search the current method entry from value stack. + + * vm_insnhelper.c (VM_CHECK_MODE): introduced to enable/disable + assertions. + Tue Jun 2 10:46:36 2015 Eric Wong <e@8...> * test/socket/test_nonblock.rb: new test for sendmsg_nonblock Index: vm_core.h =================================================================== --- vm_core.h (revision 50727) +++ vm_core.h (revision 50728) @@ -440,8 +440,6 @@ typedef struct rb_vm_struct { https://github.com/ruby/ruby/blob/trunk/vm_core.h#L440 VALUE verbose, debug, orig_progname, progname; VALUE coverages; - struct unlinked_method_entry_list_entry *unlinked_method_entry_list; - VALUE defined_module_hash; #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE @@ -513,10 +511,9 @@ typedef struct rb_control_frame_struct { https://github.com/ruby/ruby/blob/trunk/vm_core.h#L511 VALUE *ep; /* cfp[6] / block[2] */ rb_iseq_t *block_iseq; /* cfp[7] / block[3] */ VALUE proc; /* cfp[8] / block[4] */ - const rb_method_entry_t *me;/* cfp[9] */ #if VM_DEBUG_BP_CHECK - VALUE *bp_check; /* cfp[10] */ + VALUE *bp_check; /* cfp[9] */ #endif } rb_control_frame_t; @@ -954,7 +951,6 @@ void rb_vm_gvl_destroy(rb_vm_t *vm); https://github.com/ruby/ruby/blob/trunk/vm_core.h#L951 VALUE rb_vm_call(rb_thread_t *th, VALUE recv, VALUE id, int argc, const VALUE *argv, const rb_method_entry_t *me, VALUE defined_class); -void rb_gc_mark_unlinked_live_method_entries(void *pvm); void rb_thread_start_timer_thread(void); void rb_thread_stop_timer_thread(int); @@ -1001,6 +997,8 @@ int rb_autoloading_value(VALUE mod, ID i https://github.com/ruby/ruby/blob/trunk/vm_core.h#L997 void rb_vm_rewrite_cref_stack(rb_cref_t *node, VALUE old_klass, VALUE new_klass, rb_cref_t **new_cref_ptr); +const rb_method_entry_t *rb_vm_frame_method_entry(const rb_control_frame_t *cfp); + #define sysstack_error GET_VM()->special_exceptions[ruby_error_sysstack] #define RUBY_CONST_ASSERT(expr) (1/!!(expr)) /* expr must be a compile-time constant */ Index: vm_eval.c =================================================================== --- vm_eval.c (revision 50727) +++ vm_eval.c (revision 50728) @@ -120,8 +120,8 @@ vm_call0_cfunc_with_frame(rb_thread_t* t https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L120 rb_control_frame_t *reg_cfp = th->cfp; vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, recv, defined_class, - VM_ENVVAL_BLOCK_PTR(blockptr), NULL /* cref */, - 0, reg_cfp->sp, 1, me, 0); + VM_ENVVAL_BLOCK_PTR(blockptr), (VALUE)me, + 0, reg_cfp->sp, 1, 0); if (len >= 0) rb_check_arity(argc, len, len); @@ -200,8 +200,7 @@ vm_call0_body(rb_thread_t* th, rb_call_i https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L200 case VM_METHOD_TYPE_REFINED: { const rb_method_type_t type = ci->me->def->type; - if (type == VM_METHOD_TYPE_REFINED && - ci->me->def->body.orig_me) { + if (type == VM_METHOD_TYPE_REFINED && ci->me->def->body.orig_me) { ci->me = ci->me->def->body.orig_me; goto again; } @@ -283,7 +282,7 @@ vm_call_super(rb_thread_t *th, int argc, https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L282 klass = RCLASS_ORIGIN(cfp->klass); klass = RCLASS_SUPER(klass); - id = cfp->me->def->original_id; + id = rb_vm_frame_method_entry(cfp)->def->original_id; me = rb_method_entry(klass, id, &klass); if (!me) { return method_missing(recv, id, argc, argv, NOEX_SUPER); @@ -392,7 +391,7 @@ check_funcall_respond_to(rb_thread_t *th https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L391 VALUE defined_class; const rb_method_entry_t *me = rb_method_entry(klass, idRespond_to, &defined_class); - if (me && !(me->flag & NOEX_BASIC)) { + if (me && !(me->def->flag & NOEX_BASIC)) { const rb_block_t *passed_block = th->passed_block; VALUE args[2], result; int arity = rb_method_entry_arity(me); @@ -575,7 +574,7 @@ rb_method_call_status(rb_thread_t *th, c https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L574 } klass = me->klass; oid = me->def->original_id; - noex = me->flag; + noex = me->def->flag; if (oid != idMethodMissing) { /* receiver specified form for private method */ Index: proc.c =================================================================== --- proc.c (revision 50727) +++ proc.c (revision 50728) @@ -21,8 +21,7 @@ struct METHOD { https://github.com/ruby/ruby/blob/trunk/proc.c#L21 VALUE rclass; VALUE defined_class; ID id; - rb_method_entry_t *me; - struct unlinked_method_entry_list_entry *ume; + rb_method_entry_t * const me; }; VALUE rb_cUnboundMethod; @@ -1100,18 +1099,12 @@ bm_mark(void *ptr) https://github.com/ruby/ruby/blob/trunk/proc.c#L1099 rb_gc_mark(data->defined_class); rb_gc_mark(data->rclass); rb_gc_mark(data->recv); - if (data->me) rb_mark_method_entry(data->me); + rb_gc_mark((VALUE)data->me); } static void bm_free(void *ptr) { - struct METHOD *data = ptr; - struct unlinked_method_entry_list_entry *ume = data->ume; - data->me->mark = 0; - ume->me = data->me; - ume->next = GET_VM()->unlinked_method_entry_list; - GET_VM()->unlinked_method_entry_list = ume; xfree(ptr); } @@ -1167,22 +1160,13 @@ mnew_missing(VALUE rclass, VALUE klass, https://github.com/ruby/ruby/blob/trunk/proc.c#L1160 data->defined_class = klass; data->id = rid; - me = ALLOC(rb_method_entry_t); - data->me = me; - me->flag = 0; - me->mark = 0; - me->called_id = id; - me->klass = klass; - me->def = 0; - - def = ALLOC(rb_method_definition_t); - me->def = def; + def = ZALLOC(rb_method_definition_t); + def->flag = 0; def->type = VM_METHOD_TYPE_MISSING; def->original_id = id; - def->alias_count = 0; - data->ume = ALLOC(struct unlinked_method_entry_list_entry); - data->me->def->alias_count++; + me = rb_method_entry_create(id, klass, def); + RB_OBJ_WRITE(method, &data->me, me); OBJ_INFECT(method, klass); @@ -1210,13 +1194,13 @@ mnew_internal(const rb_method_entry_t *m https://github.com/ruby/ruby/blob/trunk/proc.c#L1194 } def = me->def; if (flag == NOEX_UNDEF) { - flag = me->flag; + flag = def->flag; if (scope && (flag & NOEX_MASK) != NOEX_PUBLIC) { if (!error) return Qnil; rb_print_inaccessible(klass, id, flag & NOEX_MASK); } } - if (def && def->type == VM_METHOD_TYPE_ZSUPER) { + if (def->type == VM_METHOD_TYPE_ZSUPER) { klass = RCLASS_SUPER(defined_class); id = def->original_id; me = rb_method_entry_without_refinements(klass, id, &defined_class); @@ -1236,13 +1220,8 @@ mnew_internal(const rb_method_entry_t *m https://github.com/ruby/ruby/blob/trunk/proc.c#L1220 data->rclass = rclass; data->defined_class = defined_class; data->id = rid; - data->me = ALLOC(rb_method_entry_t); - *data->me = *me; - data->ume = ALLOC(struct unlinked_method_entry_list_entry); - data->me->def->alias_count++; - + RB_OBJ_WRITE(method, &data->me, rb_method_entry_clone(me)); OBJ_INFECT(method, klass); - return method; } @@ -1364,12 +1343,9 @@ method_unbind(VALUE obj) https://github.com/ruby/ruby/blob/trunk/proc.c#L1343 &method_data_type, data); data->recv = Qundef; data->id = orig->id; - data->me = ALLOC(rb_method_entry_t); - *data->me = *orig->me; - if (orig->me->def) orig->me->def->alias_count++; + RB_OBJ_WRITE(method, &data->me, rb_method_entry_clone(orig->me)); data->rclass = orig->rclass; data->defined_class = orig->defined_class; - data->ume = ALLOC(struct unlinked_method_entry_list_entry); OBJ_INFECT(method, obj); return method; @@ -1832,12 +1808,11 @@ method_clone(VALUE self) https://github.com/ruby/ruby/blob/trunk/proc.c#L1808 TypedData_Get_Struct(self, struct METHOD, &method_data_type, orig); clone = TypedData_Make_Struct(CLASS_OF(self), struct METHOD, &method_data_type, data); CLONESETUP(clone, self); - *data = *orig; - data->me = ALLOC(rb_method_entry_t); - *data->me = *orig->me; - if (data->me->def) data->me->def->alias_count++; - data->ume = ALLOC(struct unlinked_method_entry_list_entry); - + data->recv = orig->recv; + data->rclass = orig->rclass; + data->defined_class = orig->defined_class; + data->id = orig->id; + RB_OBJ_WRITE(clone, &data->me, rb_method_entry_clone(orig->me)); return clone; } @@ -2020,10 +1995,11 @@ umethod_bind(VALUE method, VALUE recv) https://github.com/ruby/ruby/blob/trunk/proc.c#L1995 } method = TypedData_Make_Struct(rb_cMethod, struct METHOD, &method_data_type, bound); - *bound = *data; - bound->me = ALLOC(rb_method_entry_t); - *bound->me = *data->me; - if (bound->me->def) bound->me->def->alias_count++; + bound->recv = data->recv; + bound->rclass = data->rclass; + bound->defined_class = data->defined_class; + bound->id = data->id; + RB_OBJ_WRITE(method, &bound->me, rb_method_entry_clone(data->me)); rclass = CLASS_OF(recv); if (BUILTIN_TYPE(bound->defined_class) == T_MODULE) { VALUE ic = rb_class_search_ancestor(rclass, bound->defined_class); @@ -2036,7 +2012,6 @@ umethod_bind(VALUE method, VALUE recv) https://github.com/ruby/ruby/blob/trunk/proc.c#L2012 } bound->recv = recv; bound->rclass = rclass; - data->ume = ALLOC(struct unlinked_method_entry_list_entry); return method; } @@ -2071,7 +2046,8 @@ rb_method_entry_min_max_arity(const rb_m https://github.com/ruby/ruby/blob/trunk/proc.c#L2046 case VM_METHOD_TYPE_BMETHOD: return rb_proc_min_max_arity(def->body.proc, max); case VM_METHOD_TYPE_ISEQ: { - rb_iseq_t *iseq = def->body.iseq_body.iseq; + rb_iseq_t *iseq; + GetISeqPtr(def->body.iseq.iseqval, iseq); return rb_iseq_min_max_arity(iseq, max); } case VM_METHOD_TYPE_UNDEF: @@ -2207,7 +2183,11 @@ method_def_iseq(const rb_method_definiti https://github.com/ruby/ruby/blob/trunk/proc.c#L2183 { switch (def->type) { case VM_METHOD_TYPE_ISEQ: - return def->body.iseq_body.iseq; + { + rb_iseq_t *iseq; + GetISeqPtr(def->body.iseq.iseqval, iseq); + return iseq; + } case VM_METHOD_TYPE_BMETHOD: return get_proc_iseq(def->body.proc, 0); case VM_METHOD_TYPE_ALIAS: @@ -2240,7 +2220,7 @@ method_cref(VALUE method) https://github.com/ruby/ruby/blob/trunk/proc.c#L2220 again: switch (def->type) { case VM_METHOD_TYPE_ISEQ: - return def->body.iseq_body.cref; + return def->body.iseq.cref; case VM_METHOD_TYPE_ALIAS: def = def->body.alias.original_me->def; goto again; @@ -2675,6 +2655,7 @@ proc_curry(int argc, const VALUE *argv, https://github.com/ruby/ruby/blob/trunk/proc.c#L2655 else { sarity = FIX2INT(arity); if (rb_proc_lambda_p(self)) { + bp(); rb_check_arity(sarity, min_arity, max_arity); } } Index: thread.c =================================================================== --- thread.c (revision 50727) +++ thread.c (revision 50728) @@ -580,7 +580,7 @@ thread_start_func_2(rb_thread_t *th, VAL https://github.com/ruby/ruby/blob/trunk/thread.c#L580 GetProcPtr(th->first_proc, proc); th->errinfo = Qnil; th->root_lep = rb_vm_ep_local_ep(proc->block.ep); - th->root_svar = Qnil; + th->root_svar = Qfalse; EXEC_EVENT_HOOK(th, RUBY_EVENT_THREAD_BEGIN, th->self, 0, 0, Qundef); th->value = rb_vm_invoke_proc(th, proc, (int)RARRAY_LEN(args), RARRAY_CONST_PTR(args), 0); EXEC_EVENT_HOOK(th, RUBY_EVENT_THREAD_END, th->self, 0, 0, Qundef); Index: vm_backtrace.c =================================================================== --- vm_backtrace.c (revision 50727) +++ vm_backtrace.c (revision 50728) @@ -465,7 +465,8 @@ backtrace_each(rb_thread_t *th, https://github.com/ruby/ruby/blob/trunk/vm_backtrace.c#L465 } } else if (RUBYVM_CFUNC_FRAME_P(cfp)) { - ID mid = cfp->me->def ? cfp->me->def->original_id : cfp->me->called_id; + const rb_method_entry_t *me = rb_vm_frame_method_entry(cfp); + ID mid = me->def->original_id; iter_cfunc(arg, cfp, mid); } Index: vm_method.c =================================================================== --- vm_method.c (revision 50727) +++ vm_method.c (revision 50728) @@ -2,6 +2,8 @@ https://github.com/ruby/ruby/blob/trunk/vm_method.c#L2 * This file is included by vm.c */ +#define METHOD_DEBUG 0 + #if OPT_GLOBAL_METHOD_CACHE #ifndef GLOBAL_METHOD_CACHE_SIZE #define GLOBAL_METHOD_CACHE_SIZE 0x800 @@ -110,7 +112,7 @@ rb_f_notimplement(int argc, const VALUE https://github.com/ruby/ruby/blob/trunk/vm_method.c#L112 static void rb_define_notimplement_method_id(VALUE mod, ID id, rb_method_flag_t noex) { - rb_add_method(mod, id, VM_METHOD_TYPE_NOTIMPLEMENTED, 0, noex); + rb_add_method(mod, id, VM_METHOD_TYPE_NOTIMPLEMENTED, (void *)1, noex); } void @@ -129,80 +131,33 @@ rb_add_method_cfunc(VALUE klass, ID mid, https://github.com/ruby/ruby/blob/trunk/vm_method.c#L131 } static void -rb_unlink_method_entry(rb_method_entry_t *me) -{ - struct unlinked_method_entry_list_entry *ume = ALLOC(struct unlinked_method_entry_list_entry); - ume->me = me; - ume->next = GET_VM()->unlinked_method_entry_list; - GET_VM()->unlinked_method_entry_list = ume; -} - -void -rb_gc_mark_unlinked_live_method_entries(void *pvm) +rb_method_definition_release(rb_method_definition_t *def) { - rb_vm_t *vm = pvm; - struct unlinked_method_entry_li (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/