ruby-changes:39085
From: ko1 <ko1@a...>
Date: Tue, 7 Jul 2015 03:45:16 +0900 (JST)
Subject: [ruby-changes:39085] ko1:r51166 (trunk): * vm_core.h: remove rb_iseq_t::klass to reduce dynamic data.
ko1 2015-07-07 03:44:54 +0900 (Tue, 07 Jul 2015) New Revision: 51166 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=51166 Log: * vm_core.h: remove rb_iseq_t::klass to reduce dynamic data. * internal.h, iseq.c (rb_iseq_klass): remove it because rb_iseq_t::klass is removed. * vm_insnhelper.c (vm_super_outside): do not see cfp->iseq, but check callable method entry on a frame. This fix simplify the logic to search super class. * test/ruby/test_method.rb: support super() from Proc. Now, [Bug #4881] and [Bug #3136] was solved. * proc.c (rb_mod_define_method): catch up this change. * vm.c (vm_define_method): ditto. * vm_backtrace.c (rb_profile_frames): now, each `frame' objects are rb_callable_method_entry_t data or iseq VALUEs. This fix introduce minor compatibility issue that rb_profile_frame_label() always returns rb_profile_frame_base_label(). * test/-ext-/debug/test_profile_frames.rb: catch up this change. Modified files: trunk/ChangeLog trunk/internal.h trunk/iseq.c trunk/proc.c trunk/test/-ext-/debug/test_profile_frames.rb trunk/test/ruby/test_method.rb trunk/vm.c trunk/vm_backtrace.c trunk/vm_core.h trunk/vm_insnhelper.c Index: ChangeLog =================================================================== --- ChangeLog (revision 51165) +++ ChangeLog (revision 51166) @@ -1,3 +1,30 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Tue Jul 7 03:33:20 2015 Koichi Sasada <ko1@a...> + + * vm_core.h: remove rb_iseq_t::klass to reduce dynamic data. + + * internal.h, iseq.c (rb_iseq_klass): remove it because + rb_iseq_t::klass is removed. + + * vm_insnhelper.c (vm_super_outside): do not see cfp->iseq, but + check callable method entry on a frame. + This fix simplify the logic to search super class. + + * test/ruby/test_method.rb: support super() from Proc. + Now, [Bug #4881] and [Bug #3136] was solved. + + * proc.c (rb_mod_define_method): catch up this change. + + * vm.c (vm_define_method): ditto. + + * vm_backtrace.c (rb_profile_frames): now, each `frame' objects + are rb_callable_method_entry_t data or iseq VALUEs. + + This fix introduce minor compatibility issue that + rb_profile_frame_label() always returns + rb_profile_frame_base_label(). + + * test/-ext-/debug/test_profile_frames.rb: catch up this change. + Tue Jul 7 01:52:14 2015 Koichi Sasada <ko1@a...> * cont.c (fiber_init): initialize control frame correctly. Index: vm_core.h =================================================================== --- vm_core.h (revision 51165) +++ vm_core.h (revision 51166) @@ -348,7 +348,6 @@ struct rb_iseq_struct { https://github.com/ruby/ruby/blob/trunk/vm_core.h#L348 VALUE self; const VALUE orig; /* non-NULL if its data have origin */ - const VALUE klass; /* misc */ ID defined_method_id; /* for define_method */ Index: iseq.c =================================================================== --- iseq.c (revision 51165) +++ iseq.c (revision 51166) @@ -127,8 +127,6 @@ iseq_mark(void *ptr) https://github.com/ruby/ruby/blob/trunk/iseq.c#L127 RUBY_MARK_UNLESS_NULL(iseq->orig); } - RUBY_MARK_UNLESS_NULL(iseq->klass); - if (iseq->compile_data != 0) { struct iseq_compile_data *const compile_data = iseq->compile_data; RUBY_MARK_UNLESS_NULL(compile_data->mark_ary); @@ -261,7 +259,6 @@ prepare_iseq_build(rb_iseq_t *iseq, https://github.com/ruby/ruby/blob/trunk/iseq.c#L259 const rb_compile_option_t *option) { iseq->type = type; - RB_OBJ_WRITE(iseq->self, &iseq->klass, 0); set_relation(iseq, parent); name = rb_fstring(name); @@ -939,14 +936,6 @@ rb_iseq_first_lineno(VALUE self) https://github.com/ruby/ruby/blob/trunk/iseq.c#L936 } VALUE -rb_iseq_klass(VALUE self) -{ - rb_iseq_t *iseq; - GetISeqPtr(self, iseq); - return iseq->local_iseq->klass; -} - -VALUE rb_iseq_method_name(VALUE self) { rb_iseq_t *iseq, *local_iseq; @@ -1961,13 +1950,6 @@ rb_iseq_clone(VALUE iseqval, VALUE newcb https://github.com/ruby/ruby/blob/trunk/iseq.c#L1950 iseq1->local_iseq = iseq1; } - if (newcbase) { - RB_OBJ_WRITE(iseq1->self, &iseq1->klass, newcbase); - } - else { - RB_OBJ_WRITTEN(iseq1->self, Qundef, iseq1->klass); - } - RB_GC_GUARD(iseqval); /* seems necessary iff RGenGC is disabled */ return newiseq; Index: proc.c =================================================================== --- proc.c (revision 51165) +++ proc.c (revision 51166) @@ -1725,7 +1725,6 @@ rb_mod_define_method(int argc, VALUE *ar https://github.com/ruby/ruby/blob/trunk/proc.c#L1725 GetProcPtr(body, proc); if (!RUBY_VM_IFUNC_P(proc->block.iseq)) { proc->block.iseq->defined_method_id = id; - RB_OBJ_WRITE(proc->block.iseq->self, &proc->block.iseq->klass, mod); proc->is_lambda = TRUE; proc->is_from_method = TRUE; } Index: vm_backtrace.c =================================================================== --- vm_backtrace.c (revision 51165) +++ vm_backtrace.c (revision 51166) @@ -9,6 +9,8 @@ https://github.com/ruby/ruby/blob/trunk/vm_backtrace.c#L9 **********************************************************************/ +#define VM_CHECK_MODE 2 + #include "internal.h" #include "ruby/debug.h" @@ -1248,15 +1250,24 @@ rb_profile_frames(int start, int limit, https://github.com/ruby/ruby/blob/trunk/vm_backtrace.c#L1250 rb_control_frame_t *cfp = th->cfp, *end_cfp = RUBY_VM_END_CONTROL_FRAME(th); for (i=0; i<limit && cfp != end_cfp;) { - if (cfp->iseq && cfp->pc) { /* should be NORMAL_ISEQ */ + const rb_callable_method_entry_t *cme = rb_vm_frame_method_entry(cfp); + + if ((cme && cme->def->type == VM_METHOD_TYPE_ISEQ) || (cfp->iseq && cfp->pc)) { if (start > 0) { start--; continue; } /* record frame info */ - buff[i] = cfp->iseq->self; - if (lines) lines[i] = calc_lineno(cfp->iseq, cfp->pc); + if (cme) { + buff[i] = (VALUE)cme; + } + else { + buff[i] = cfp->iseq->self; + } + + if (cfp->iseq && lines) lines[i] = calc_lineno(cfp->iseq, cfp->pc); + i++; } cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); @@ -1265,42 +1276,83 @@ rb_profile_frames(int start, int limit, https://github.com/ruby/ruby/blob/trunk/vm_backtrace.c#L1276 return i; } -#define frame2iseq(frame) frame +static VALUE +frame2iseq(VALUE frame) +{ + if (frame == Qnil) return Qnil; + + if (RB_TYPE_P(frame, T_DATA)) { + VM_ASSERT(strcmp(rb_objspace_data_type_name(frame), "iseq") == 0); + return frame; + } + + if (RB_TYPE_P(frame, T_IMEMO)) { + const rb_callable_method_entry_t *cme = (rb_callable_method_entry_t *)frame; + VM_ASSERT(imemo_type(frame) == imemo_ment); + switch (cme->def->type) { + case VM_METHOD_TYPE_ISEQ: + return cme->def->body.iseq.iseqptr->self; + default: + return Qnil; + } + } + rb_bug("frame2iseq: unreachable"); +} VALUE rb_profile_frame_path(VALUE frame) { - return rb_iseq_path(frame2iseq(frame)); + VALUE iseqv = frame2iseq(frame); + return NIL_P(iseqv) ? Qnil : rb_iseq_path(iseqv); } VALUE rb_profile_frame_absolute_path(VALUE frame) { - return rb_iseq_absolute_path(frame2iseq(frame)); + VALUE iseqv = frame2iseq(frame); + return NIL_P(iseqv) ? Qnil : rb_iseq_absolute_path(iseqv); } VALUE rb_profile_frame_label(VALUE frame) { - return rb_iseq_label(frame2iseq(frame)); + VALUE iseqv = frame2iseq(frame); + return NIL_P(iseqv) ? Qnil : rb_iseq_label(iseqv); } VALUE rb_profile_frame_base_label(VALUE frame) { - return rb_iseq_base_label(frame2iseq(frame)); + VALUE iseqv = frame2iseq(frame); + return NIL_P(iseqv) ? Qnil : rb_iseq_base_label(iseqv); } VALUE rb_profile_frame_first_lineno(VALUE frame) { - return rb_iseq_first_lineno(frame2iseq(frame)); + VALUE iseqv = frame2iseq(frame); + return NIL_P(iseqv) ? Qnil : rb_iseq_first_lineno(iseqv); +} + +static VALUE +frame2klass(VALUE frame) +{ + if (frame == Qnil) return Qnil; + + if (RB_TYPE_P(frame, T_IMEMO)) { + const rb_callable_method_entry_t *cme = (rb_callable_method_entry_t *)frame; + VM_ASSERT(imemo_type(frame) == imemo_ment); + return cme->defined_class; + } + else { + return Qnil; + } } VALUE rb_profile_frame_classpath(VALUE frame) { - VALUE klass = rb_iseq_klass(frame2iseq(frame)); + VALUE klass = frame2klass(frame); if (klass && !NIL_P(klass)) { if (RB_TYPE_P(klass, T_ICLASS)) { @@ -1321,7 +1373,8 @@ rb_profile_frame_classpath(VALUE frame) https://github.com/ruby/ruby/blob/trunk/vm_backtrace.c#L1373 VALUE rb_profile_frame_singleton_method_p(VALUE frame) { - VALUE klass = rb_iseq_klass(frame2iseq(frame)); + VALUE klass = frame2klass(frame); + if (klass && !NIL_P(klass) && FL_TEST(klass, FL_SINGLETON)) { return Qtrue; } @@ -1333,13 +1386,15 @@ rb_profile_frame_singleton_method_p(VALU https://github.com/ruby/ruby/blob/trunk/vm_backtrace.c#L1386 VALUE rb_profile_frame_method_name(VALUE frame) { - return rb_iseq_method_name(frame2iseq(frame)); + VALUE iseqv = frame2iseq(frame); + return NIL_P(iseqv) ? Qnil : rb_iseq_method_name(iseqv); } VALUE rb_profile_frame_qualified_method_name(VALUE frame) { - VALUE method_name = rb_iseq_method_name(frame2iseq(frame)); + VALUE method_name = rb_profile_frame_method_name(frame); + if (method_name != Qnil) { VALUE classpath = rb_profile_frame_classpath(frame); VALUE singleton_p = rb_profile_frame_singleton_method_p(frame); Index: internal.h =================================================================== --- internal.h (revision 51165) +++ internal.h (revision 51166) @@ -853,7 +853,6 @@ VALUE rb_iseq_absolute_path(VALUE iseqva https://github.com/ruby/ruby/blob/trunk/internal.h#L853 VALUE rb_iseq_label(VALUE iseqval); VALUE rb_iseq_base_label(VALUE iseqval); VALUE rb_iseq_first_lineno(VALUE iseqval); -VALUE rb_iseq_klass(VALUE iseqval); /* completely temporary function */ VALUE rb_iseq_method_name(VALUE self); /* load.c */ Index: vm.c =================================================================== --- vm.c (revision 51165) +++ vm.c (revision 51166) @@ -2278,11 +2278,6 @@ vm_define_method(rb_thread_t *th, VALUE https://github.com/ruby/ruby/blob/trunk/vm.c#L2278 rb_iseq_t *miseq; GetISeqPtr(iseqval, miseq); - if (miseq->klass) { - iseqval = rb_iseq_clone(iseqval, 0); - GetISeqPtr(iseqval, miseq); - } - if (NIL_P(klass)) { rb_raise(rb_eTypeError, "no class/module to add method"); } @@ -2293,7 +2288,6 @@ vm_define_method(rb_thread_t *th, VALUE https://github.com/ruby/ruby/blob/trunk/vm.c#L2288 } /* dup */ - RB_OBJ_WRITE(miseq->self, &miseq->klass, klass); miseq->defined_method_id = id; rb_add_method_iseq(klass, id, iseqval, cref, visi); Index: vm_insnhelper.c =================================================================== --- vm_insnhelper.c (revision 51165) +++ vm_insnhelper.c (revision 51166) @@ -2173,58 +2173,19 @@ vm_super_outside(void) https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L2173 static int vm_search_superclass(rb_control_frame_t *reg_cfp, rb_iseq_t *iseq, VALUE sigval, rb_call_info_t *ci) { - const rb_callable_method_entry_t *me; + const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(reg_cfp); - while (iseq && !iseq->klass) { - iseq = iseq->parent_iseq; - } - - if (iseq == 0) { + if (me == NULL) { return -1; } - - ci->mid = iseq->defined_method_id; - - if (iseq != iseq->local_iseq) { - /* defined by Module#define_method() */ - rb_control_frame_t *lcfp = GET_CFP(); - - if (!sigval) { - /* zsuper */ - return -2; - } - - while (lcfp->iseq != iseq) { - rb_thread_t *th = GET_THREAD(); - VALUE *tep = VM_EP_PREV_EP(lcfp->ep); - while (1) { - lcfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(lcfp); - if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, lcfp)) { - return -1; - } - if (lcfp->ep == tep) { - break; - } - } - } - - me = rb_vm_frame_method_entry(lcfp); - - /* temporary measure for [Bug #2420] [Bug #3136] */ - if (!me) { - fprintf(stderr, "kore?\n"); - return -1; - } - - ci->mid = me->def->original_id; - ci->klass = vm_search_normal_superclass(me->defined_class); + else if (me->def->type == VM_METHOD_TYPE_BMETHOD && !sigval) { + return -2; } else { - me = rb_vm_frame_method_entry(reg_cfp); + ci->mid = me->def->original_id; ci->klass = vm_search_normal_superclass(me->defined_class); + return 0; } - - return 0; } static void Index: test/ruby/test_method.rb =================================================================== --- test/ruby/test_method.rb (revision 51165) +++ test/ruby/test_method.rb (revision 51166) @@ -405,11 +405,7 @@ class TestMethod < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_method.rb#L405 end } c2 = Class.new(c1) { define_method(:m) { Proc.new { super() } } } - # c2.new.m.call should return :m1, but currently it raise NoMethodError. - # see [Bug #4881] and [Bug #3136] - assert_raise(NoMethodError) { - c2.new.m.call - } + assert_equal(:m1, c2.new.m.call, 'see [Bug #4881] and [Bug #3136]') end def test_clone Index: test/-ext-/debug/test_profile_frames.rb =================================================================== --- test/-ext-/debug/test_profile_frames.rb (revision 51165) +++ test/-ext-/debug/test_profile_frames.rb (revision 51166) @@ -25,12 +25,12 @@ class TestProfileFrames < Test::Unit::Te https://github.com/ruby/ruby/blob/trunk/test/-ext-/debug/test_profile_frames.rb#L25 }.resume labels = [ - "block (2 levels) in test_profile_frames", + "test_profile_frames", "zab", "baz", "bar", "foo", - "block in test_profile_frames", + "test_profile_frames", ] base_labels = [ "test_profile_frames", @@ -41,12 +41,12 @@ class TestProfileFrames < Test::Unit::Te https://github.com/ruby/ruby/blob/trunk/test/-ext-/debug/test_profile_frames.rb#L41 "test_profile_frames", ] full_labels = [ - "block (2 levels) in TestProfileFrames#test_profile_frames", + "TestProfileFrames#test_profile_frames", "#{obj.inspect}.zab", "SampleClassForTestProfileFrames::Sample2#baz", "SampleClassForTestProfileFrames.bar", "SampleClassForTestProfileFrames#foo", - "block in TestProfileFrames#test_profile_frames", + "TestProfileFrames#test_profile_frames", ] classes = [ TestProfileFrames, -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/