зеркало из https://github.com/github/ruby.git
* 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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51166 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
202643de00
Коммит
02d5868962
27
ChangeLog
27
ChangeLog
|
@ -1,3 +1,30 @@
|
|||
Tue Jul 7 03:33:20 2015 Koichi Sasada <ko1@atdot.net>
|
||||
|
||||
* 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@atdot.net>
|
||||
|
||||
* cont.c (fiber_init): initialize control frame correctly.
|
||||
|
|
|
@ -853,7 +853,6 @@ VALUE rb_iseq_absolute_path(VALUE iseqval);
|
|||
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 */
|
||||
|
|
18
iseq.c
18
iseq.c
|
@ -127,8 +127,6 @@ iseq_mark(void *ptr)
|
|||
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,
|
|||
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);
|
||||
|
@ -938,14 +935,6 @@ rb_iseq_first_lineno(VALUE self)
|
|||
return iseq->location.first_lineno;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -1961,13 +1950,6 @@ rb_iseq_clone(VALUE iseqval, VALUE newcbase)
|
|||
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;
|
||||
|
|
1
proc.c
1
proc.c
|
@ -1725,7 +1725,6 @@ rb_mod_define_method(int argc, VALUE *argv, VALUE mod)
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -25,12 +25,12 @@ class TestProfileFrames < Test::Unit::TestCase
|
|||
}.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::TestCase
|
|||
"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,
|
||||
|
|
|
@ -405,11 +405,7 @@ class TestMethod < Test::Unit::TestCase
|
|||
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
|
||||
|
|
6
vm.c
6
vm.c
|
@ -2278,11 +2278,6 @@ vm_define_method(rb_thread_t *th, VALUE obj, ID id, VALUE iseqval,
|
|||
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 obj, ID id, VALUE iseqval,
|
|||
}
|
||||
|
||||
/* dup */
|
||||
RB_OBJ_WRITE(miseq->self, &miseq->klass, klass);
|
||||
miseq->defined_method_id = id;
|
||||
rb_add_method_iseq(klass, id, iseqval, cref, visi);
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
**********************************************************************/
|
||||
|
||||
#define VM_CHECK_MODE 2
|
||||
|
||||
#include "internal.h"
|
||||
#include "ruby/debug.h"
|
||||
|
||||
|
@ -1248,15 +1250,24 @@ rb_profile_frames(int start, int limit, VALUE *buff, int *lines)
|
|||
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, VALUE *buff, int *lines)
|
|||
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)
|
|||
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(VALUE frame)
|
|||
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);
|
||||
|
|
|
@ -348,7 +348,6 @@ struct rb_iseq_struct {
|
|||
|
||||
VALUE self;
|
||||
const VALUE orig; /* non-NULL if its data have origin */
|
||||
const VALUE klass;
|
||||
|
||||
/* misc */
|
||||
ID defined_method_id; /* for define_method */
|
||||
|
|
|
@ -2173,58 +2173,19 @@ vm_super_outside(void)
|
|||
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
|
||||
|
|
Загрузка…
Ссылка в новой задаче