1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* fix namespace issue on singleton class expressions. [Bug #10943]

* vm_core.h, method.h: remove rb_iseq_t::cref_stack. CREF is stored
  to rb_method_definition_t::body.iseq_body.cref.
* vm_insnhelper.c: modify SVAR usage.
  When calling ISEQ type method, push CREF information onto method
  frame, SVAR located place. Before this fix, SVAR is simply nil.
  After this patch, CREF (or NULL == Qfalse for not iseq methods)
  is stored at the method invocation.
  When SVAR is requierd, then put NODE_IF onto SVAR location,
  and NDOE_IF::nd_reserved points CREF itself.
* vm.c (vm_cref_new, vm_cref_dump, vm_cref_new_toplevel): added.
* vm_insnhelper.c (vm_push_frame): accept CREF.
* method.h, vm_method.c (rb_add_method_iseq): added. This function
  accepts iseq and CREF.
* class.c (clone_method): use rb_add_method_iseq().
* gc.c (mark_method_entry): mark method_entry::body.iseq_body.cref.
* iseq.c: remove CREF related codes.
* insns.def (getinlinecache/setinlinecache): CREF should be cache key
  because a different CREF has a different namespace.
* node.c (rb_gc_mark_node): mark NODE_IF::nd_reserved for SVAR.
* proc.c: catch up changes.
* struct.c: ditto.
* insns.def: ditto.
* vm_args.c (raise_argument_error): ditto.
* vm_eval.c: ditto.
* test/ruby/test_class.rb: add a test.



git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@49874 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
ko1 2015-03-06 12:24:58 +00:00
parent e0f5a6ab48
commit d84f9b1694
16 changed files with 378 additions and 131 deletions

View file

@ -1,3 +1,49 @@
Fri Mar 6 20:18:38 2015 Koichi Sasada <ko1@atdot.net>
* fix namespace issue on singleton class expressions. [Bug #10943]
* vm_core.h, method.h: remove rb_iseq_t::cref_stack. CREF is stored
to rb_method_definition_t::body.iseq_body.cref.
* vm_insnhelper.c: modify SVAR usage.
When calling ISEQ type method, push CREF information onto method
frame, SVAR located place. Before this fix, SVAR is simply nil.
After this patch, CREF (or NULL == Qfalse for not iseq methods)
is stored at the method invocation.
When SVAR is requierd, then put NODE_IF onto SVAR location,
and NDOE_IF::nd_reserved points CREF itself.
* vm.c (vm_cref_new, vm_cref_dump, vm_cref_new_toplevel): added.
* vm_insnhelper.c (vm_push_frame): accept CREF.
* method.h, vm_method.c (rb_add_method_iseq): added. This function
accepts iseq and CREF.
* class.c (clone_method): use rb_add_method_iseq().
* gc.c (mark_method_entry): mark method_entry::body.iseq_body.cref.
* iseq.c: remove CREF related codes.
* insns.def (getinlinecache/setinlinecache): CREF should be cache key
because a different CREF has a different namespace.
* node.c (rb_gc_mark_node): mark NODE_IF::nd_reserved for SVAR.
* proc.c: catch up changes.
* struct.c: ditto.
* insns.def: ditto.
* vm_args.c (raise_argument_error): ditto.
* vm_eval.c: ditto.
* test/ruby/test_class.rb: add a test.
Fri Mar 6 18:19:13 2015 Koichi Sasada <ko1@atdot.net> Fri Mar 6 18:19:13 2015 Koichi Sasada <ko1@atdot.net>
* test/webrick/test_filehandler.rb: on vboxsf (on VirtualBox * test/webrick/test_filehandler.rb: on vboxsf (on VirtualBox

View file

@ -247,11 +247,10 @@ clone_method(VALUE klass, ID mid, const rb_method_entry_t *me)
if (me->def && me->def->type == VM_METHOD_TYPE_ISEQ) { if (me->def && me->def->type == VM_METHOD_TYPE_ISEQ) {
rb_iseq_t *iseq; rb_iseq_t *iseq;
NODE *new_cref; NODE *new_cref;
newiseqval = rb_iseq_clone(me->def->body.iseq->self, klass); newiseqval = rb_iseq_clone(me->def->body.iseq_body.iseq->self, klass);
GetISeqPtr(newiseqval, iseq); GetISeqPtr(newiseqval, iseq);
rb_vm_rewrite_cref_stack(me->def->body.iseq->cref_stack, me->klass, klass, &new_cref); rb_vm_rewrite_cref_stack(me->def->body.iseq_body.cref, me->klass, klass, &new_cref);
RB_OBJ_WRITE(iseq->self, &iseq->cref_stack, new_cref); rb_add_method_iseq(klass, mid, iseq, new_cref, me->flag);
rb_add_method(klass, mid, VM_METHOD_TYPE_ISEQ, iseq, me->flag);
RB_GC_GUARD(newiseqval); RB_GC_GUARD(newiseqval);
} }
else { else {

5
gc.c
View file

@ -3786,11 +3786,14 @@ mark_method_entry(rb_objspace_t *objspace, const rb_method_entry_t *me)
const rb_method_definition_t *def = me->def; const rb_method_definition_t *def = me->def;
gc_mark(objspace, me->klass); gc_mark(objspace, me->klass);
again: again:
if (!def) return; if (!def) return;
switch (def->type) { switch (def->type) {
case VM_METHOD_TYPE_ISEQ: case VM_METHOD_TYPE_ISEQ:
gc_mark(objspace, def->body.iseq->self); gc_mark(objspace, def->body.iseq_body.iseq->self);
gc_mark(objspace, (VALUE)def->body.iseq_body.cref);
break; break;
case VM_METHOD_TYPE_BMETHOD: case VM_METHOD_TYPE_BMETHOD:
gc_mark(objspace, def->body.proc); gc_mark(objspace, def->body.proc);

View file

@ -159,7 +159,7 @@ getclassvariable
() ()
(VALUE val) (VALUE val)
{ {
NODE *cref = rb_vm_get_cref(GET_ISEQ(), GET_EP()); NODE *cref = rb_vm_get_cref(GET_EP());
val = rb_cvar_get(vm_get_cvar_base(cref, GET_CFP()), id); val = rb_cvar_get(vm_get_cvar_base(cref, GET_CFP()), id);
} }
@ -174,7 +174,7 @@ setclassvariable
(VALUE val) (VALUE val)
() ()
{ {
NODE *cref = rb_vm_get_cref(GET_ISEQ(), GET_EP()); NODE *cref = rb_vm_get_cref(GET_EP());
rb_cvar_set(vm_get_cvar_base(cref, GET_CFP()), id, val); rb_cvar_set(vm_get_cvar_base(cref, GET_CFP()), id, val);
} }
@ -196,7 +196,7 @@ getconstant
(VALUE klass) (VALUE klass)
(VALUE val) (VALUE val)
{ {
val = vm_get_ev_const(th, GET_ISEQ(), klass, id, 0); val = vm_get_ev_const(th, klass, id, 0);
} }
/** /**
@ -318,10 +318,10 @@ putspecialobject
val = rb_mRubyVMFrozenCore; val = rb_mRubyVMFrozenCore;
break; break;
case VM_SPECIAL_OBJECT_CBASE: case VM_SPECIAL_OBJECT_CBASE:
val = vm_get_cbase(GET_ISEQ(), GET_EP()); val = vm_get_cbase(GET_EP());
break; break;
case VM_SPECIAL_OBJECT_CONST_BASE: case VM_SPECIAL_OBJECT_CONST_BASE:
val = vm_get_const_base(GET_ISEQ(), GET_EP()); val = vm_get_const_base(GET_EP());
break; break;
default: default:
rb_bug("putspecialobject insn: unknown value_type"); rb_bug("putspecialobject insn: unknown value_type");
@ -730,7 +730,7 @@ defined
} }
break; break;
case DEFINED_IVAR2: case DEFINED_IVAR2:
klass = vm_get_cbase(GET_ISEQ(), GET_EP()); klass = vm_get_cbase(GET_EP());
break; break;
case DEFINED_GVAR: case DEFINED_GVAR:
if (rb_gvar_defined(rb_global_entry(SYM2ID(obj)))) { if (rb_gvar_defined(rb_global_entry(SYM2ID(obj)))) {
@ -738,7 +738,7 @@ defined
} }
break; break;
case DEFINED_CVAR: { case DEFINED_CVAR: {
NODE *cref = rb_vm_get_cref(GET_ISEQ(), GET_EP()); NODE *cref = rb_vm_get_cref(GET_EP());
klass = vm_get_cvar_base(cref, GET_CFP()); klass = vm_get_cvar_base(cref, GET_CFP());
if (rb_cvar_defined(klass, SYM2ID(obj))) { if (rb_cvar_defined(klass, SYM2ID(obj))) {
expr_type = DEFINED_CVAR; expr_type = DEFINED_CVAR;
@ -747,7 +747,7 @@ defined
} }
case DEFINED_CONST: case DEFINED_CONST:
klass = v; klass = v;
if (vm_get_ev_const(th, GET_ISEQ(), klass, SYM2ID(obj), 1)) { if (vm_get_ev_const(th, klass, SYM2ID(obj), 1)) {
expr_type = DEFINED_CONST; expr_type = DEFINED_CONST;
} }
break; break;
@ -1013,13 +1013,14 @@ defineclass
rb_bug("unknown defineclass type: %d", (int)type); rb_bug("unknown defineclass type: %d", (int)type);
} }
COPY_CREF(class_iseq->cref_stack, vm_cref_push(th, klass, NOEX_PUBLIC, NULL));
/* enter scope */ /* enter scope */
vm_push_frame(th, class_iseq, VM_FRAME_MAGIC_CLASS, vm_push_frame(th, class_iseq, VM_FRAME_MAGIC_CLASS,
klass, 0, VM_ENVVAL_BLOCK_PTR(GET_BLOCK_PTR()), klass, 0,
VM_ENVVAL_BLOCK_PTR(GET_BLOCK_PTR()),
vm_cref_push(th, klass, NOEX_PUBLIC, NULL),
class_iseq->iseq_encoded, GET_SP(), class_iseq->iseq_encoded, GET_SP(),
class_iseq->local_size, 0, class_iseq->stack_max); class_iseq->local_size, 0, class_iseq->stack_max);
RESTORE_REGS(); RESTORE_REGS();
NEXT_INSN(); NEXT_INSN();
} }
@ -1241,7 +1242,8 @@ getinlinecache
() ()
(VALUE val) (VALUE val)
{ {
if (ic->ic_serial == GET_GLOBAL_CONSTANT_STATE()) { if (ic->ic_serial == GET_GLOBAL_CONSTANT_STATE() &&
ic->ic_cref == rb_vm_get_cref(GET_EP())) {
val = ic->ic_value.value; val = ic->ic_value.value;
JUMP(dst); JUMP(dst);
} }
@ -1267,6 +1269,7 @@ setinlinecache
} }
ic->ic_value.value = val; ic->ic_value.value = val;
ic->ic_serial = GET_GLOBAL_CONSTANT_STATE() - ruby_vm_const_missing_count; ic->ic_serial = GET_GLOBAL_CONSTANT_STATE() - ruby_vm_const_missing_count;
ic->ic_cref = rb_vm_get_cref(GET_EP());
ruby_vm_const_missing_count = 0; ruby_vm_const_missing_count = 0;
} }

25
iseq.c
View file

@ -121,7 +121,6 @@ iseq_mark(void *ptr)
RUBY_MARK_UNLESS_NULL(iseq->location.path); RUBY_MARK_UNLESS_NULL(iseq->location.path);
RUBY_MARK_UNLESS_NULL(iseq->location.absolute_path); RUBY_MARK_UNLESS_NULL(iseq->location.absolute_path);
RUBY_MARK_UNLESS_NULL((VALUE)iseq->cref_stack);
RUBY_MARK_UNLESS_NULL(iseq->klass); RUBY_MARK_UNLESS_NULL(iseq->klass);
RUBY_MARK_UNLESS_NULL(iseq->coverage); RUBY_MARK_UNLESS_NULL(iseq->coverage);
RUBY_MARK_UNLESS_NULL(iseq->orig); RUBY_MARK_UNLESS_NULL(iseq->orig);
@ -213,38 +212,21 @@ iseq_location_setup(rb_iseq_t *iseq, VALUE path, VALUE absolute_path, VALUE name
return loc; return loc;
} }
#define ISEQ_SET_CREF(iseq, cref) RB_OBJ_WRITE((iseq)->self, &(iseq)->cref_stack, (cref))
static void static void
set_relation(rb_iseq_t *iseq, const VALUE parent) set_relation(rb_iseq_t *iseq, const VALUE parent)
{ {
const VALUE type = iseq->type; const VALUE type = iseq->type;
rb_thread_t *th = GET_THREAD();
rb_iseq_t *piseq; rb_iseq_t *piseq;
/* set class nest stack */ /* set class nest stack */
if (type == ISEQ_TYPE_TOP) { if (type == ISEQ_TYPE_TOP) {
/* toplevel is private */
RB_OBJ_WRITE(iseq->self, &iseq->cref_stack, NEW_CREF(rb_cObject));
iseq->cref_stack->nd_refinements = Qnil;
iseq->cref_stack->nd_visi = NOEX_PRIVATE;
if (th->top_wrapper) {
NODE *cref = NEW_CREF(th->top_wrapper);
cref->nd_refinements = Qnil;
cref->nd_visi = NOEX_PRIVATE;
RB_OBJ_WRITE(cref, &cref->nd_next, iseq->cref_stack);
ISEQ_SET_CREF(iseq, cref);
}
iseq->local_iseq = iseq; iseq->local_iseq = iseq;
} }
else if (type == ISEQ_TYPE_METHOD || type == ISEQ_TYPE_CLASS) { else if (type == ISEQ_TYPE_METHOD || type == ISEQ_TYPE_CLASS) {
ISEQ_SET_CREF(iseq, NEW_CREF(0)); /* place holder */
iseq->cref_stack->nd_refinements = Qnil;
iseq->local_iseq = iseq; iseq->local_iseq = iseq;
} }
else if (RTEST(parent)) { else if (RTEST(parent)) {
GetISeqPtr(parent, piseq); GetISeqPtr(parent, piseq);
ISEQ_SET_CREF(iseq, piseq->cref_stack);
iseq->local_iseq = piseq->local_iseq; iseq->local_iseq = piseq->local_iseq;
} }
@ -1973,13 +1955,8 @@ rb_iseq_clone(VALUE iseqval, VALUE newcbase)
if (iseq0->local_iseq == iseq0) { if (iseq0->local_iseq == iseq0) {
iseq1->local_iseq = iseq1; iseq1->local_iseq = iseq1;
} }
if (newcbase) { if (newcbase) {
ISEQ_SET_CREF(iseq1, NEW_CREF(newcbase));
RB_OBJ_WRITE(iseq1->cref_stack, &iseq1->cref_stack->nd_refinements, iseq0->cref_stack->nd_refinements);
iseq1->cref_stack->nd_visi = iseq0->cref_stack->nd_visi;
if (iseq0->cref_stack->nd_next) {
RB_OBJ_WRITE(iseq1->cref_stack, &iseq1->cref_stack->nd_next, iseq0->cref_stack->nd_next);
}
RB_OBJ_WRITE(iseq1->self, &iseq1->klass, newcbase); RB_OBJ_WRITE(iseq1->self, &iseq1->klass, newcbase);
} }

View file

@ -12,6 +12,7 @@
#define METHOD_H #define METHOD_H
#include "internal.h" #include "internal.h"
#include "node.h"
#ifndef END_OF_ENUMERATION #ifndef END_OF_ENUMERATION
# if defined(__GNUC__) &&! defined(__STRICT_ANSI__) # if defined(__GNUC__) &&! defined(__STRICT_ANSI__)
@ -79,8 +80,12 @@ typedef struct rb_method_definition_struct {
rb_method_type_t type; /* method type */ rb_method_type_t type; /* method type */
int alias_count; int alias_count;
ID original_id; ID original_id;
union { union {
struct {
rb_iseq_t *const iseq; /* should be mark */ rb_iseq_t *const iseq; /* should be mark */
NODE *cref;
} iseq_body;
rb_method_cfunc_t cfunc; rb_method_cfunc_t cfunc;
rb_method_attr_t attr; rb_method_attr_t attr;
const VALUE proc; /* should be mark */ const VALUE proc; /* should be mark */
@ -113,6 +118,7 @@ struct unlinked_method_entry_list_entry {
UNDEFINED_METHOD_ENTRY_P((def)->body.orig_me)) 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_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, NODE *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_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(VALUE klass, ID id, VALUE *define_class_ptr);
rb_method_entry_t *rb_method_entry_at(VALUE obj, ID id); rb_method_entry_t *rb_method_entry_at(VALUE obj, ID id);

1
node.c
View file

@ -947,6 +947,7 @@ rb_gc_mark_node(NODE *obj)
{ {
switch (nd_type(obj)) { switch (nd_type(obj)) {
case NODE_IF: /* 1,2,3 */ case NODE_IF: /* 1,2,3 */
rb_gc_mark(obj->nd_refinements); /* use as SVAR */
case NODE_FOR: case NODE_FOR:
case NODE_ITER: case NODE_ITER:
case NODE_WHEN: case NODE_WHEN:

20
proc.c
View file

@ -1208,7 +1208,6 @@ mnew_internal(rb_method_entry_t *me, VALUE defined_class, VALUE klass,
def->type = VM_METHOD_TYPE_MISSING; def->type = VM_METHOD_TYPE_MISSING;
def->original_id = id; def->original_id = id;
def->alias_count = 0; def->alias_count = 0;
} }
data->ume = ALLOC(struct unlinked_method_entry_list_entry); data->ume = ALLOC(struct unlinked_method_entry_list_entry);
data->me->def->alias_count++; data->me->def->alias_count++;
@ -2025,7 +2024,7 @@ rb_method_entry_min_max_arity(const rb_method_entry_t *me, int *max)
case VM_METHOD_TYPE_BMETHOD: case VM_METHOD_TYPE_BMETHOD:
return rb_proc_min_max_arity(def->body.proc, max); return rb_proc_min_max_arity(def->body.proc, max);
case VM_METHOD_TYPE_ISEQ: { case VM_METHOD_TYPE_ISEQ: {
rb_iseq_t *iseq = def->body.iseq; rb_iseq_t *iseq = def->body.iseq_body.iseq;
return rb_iseq_min_max_arity(iseq, max); return rb_iseq_min_max_arity(iseq, max);
} }
case VM_METHOD_TYPE_UNDEF: case VM_METHOD_TYPE_UNDEF:
@ -2162,12 +2161,24 @@ method_get_iseq(rb_method_definition_t *def)
case VM_METHOD_TYPE_BMETHOD: case VM_METHOD_TYPE_BMETHOD:
return get_proc_iseq(def->body.proc, 0); return get_proc_iseq(def->body.proc, 0);
case VM_METHOD_TYPE_ISEQ: case VM_METHOD_TYPE_ISEQ:
return def->body.iseq; return def->body.iseq_body.iseq;
default: default:
return 0; return NULL;
} }
} }
static NODE *
method_get_cref(rb_method_definition_t *def)
{
switch (def->type) {
case VM_METHOD_TYPE_ISEQ:
return def->body.iseq_body.cref;
default:
return NULL;
}
}
rb_iseq_t * rb_iseq_t *
rb_method_get_iseq(VALUE method) rb_method_get_iseq(VALUE method)
{ {
@ -2376,6 +2387,7 @@ method_proc(VALUE method)
env->block.self = meth->recv; env->block.self = meth->recv;
env->block.klass = meth->defined_class; env->block.klass = meth->defined_class;
env->block.iseq = method_get_iseq(meth->me->def); env->block.iseq = method_get_iseq(meth->me->def);
env->block.ep[-1] = (VALUE)method_get_cref(meth->me->def);
return procval; return procval;
} }

View file

@ -179,7 +179,7 @@ define_aref_method(VALUE nstr, VALUE name, VALUE off)
VALUE iseqval = rb_method_for_self_aref(name, off, rb_vm_opt_struct_aref); VALUE iseqval = rb_method_for_self_aref(name, off, rb_vm_opt_struct_aref);
rb_iseq_t *iseq = DATA_PTR(iseqval); rb_iseq_t *iseq = DATA_PTR(iseqval);
rb_add_method(nstr, SYM2ID(name), VM_METHOD_TYPE_ISEQ, iseq, NOEX_PUBLIC); rb_add_method_iseq(nstr, SYM2ID(name), iseq, NULL, NOEX_PUBLIC);
RB_GC_GUARD(iseqval); RB_GC_GUARD(iseqval);
} }
@ -190,7 +190,7 @@ define_aset_method(VALUE nstr, VALUE name, VALUE off)
VALUE iseqval = rb_method_for_self_aset(name, off, rb_vm_opt_struct_aset); VALUE iseqval = rb_method_for_self_aset(name, off, rb_vm_opt_struct_aset);
rb_iseq_t *iseq = DATA_PTR(iseqval); rb_iseq_t *iseq = DATA_PTR(iseqval);
rb_add_method(nstr, SYM2ID(name), VM_METHOD_TYPE_ISEQ, iseq, NOEX_PUBLIC); rb_add_method_iseq(nstr, SYM2ID(name), iseq, NULL, NOEX_PUBLIC);
RB_GC_GUARD(iseqval); RB_GC_GUARD(iseqval);
} }

View file

@ -399,4 +399,124 @@ class TestClass < Test::Unit::TestCase
def c.f; end def c.f; end
} }
end end
def test_singleton_class_should_has_own_namespace
# CONST in singleton class
objs = []
$i = 0
2.times{
objs << obj = Object.new
class << obj
CONST = ($i += 1)
def foo
CONST
end
end
}
assert_equal(1, objs[0].foo, '[Bug #10943]')
assert_equal(2, objs[1].foo, '[Bug #10943]')
# CONST in block in singleton class
objs = []
$i = 0
2.times{
objs << obj = Object.new
class << obj
1.times{
CONST = ($i += 1)
}
def foo
[nil].map{
CONST
}
end
end
}
assert_equal([1], objs[0].foo, '[Bug #10943]')
assert_equal([2], objs[1].foo, '[Bug #10943]')
# class def in singleton class
objs = []
$xs = []
$i = 0
2.times{
objs << obj = Object.new
class << obj
CONST = ($i += 1)
class X
$xs << self
CONST = ($i += 1)
def foo
CONST
end
end
def x
X
end
end
}
assert_not_equal($xs[0], $xs[1], '[Bug #10943]')
assert_not_equal(objs[0].x, objs[1].x, '[Bug #10943]')
assert_equal(2, $xs[0]::CONST, '[Bug #10943]')
assert_equal(2, $xs[0].new.foo, '[Bug #10943]')
assert_equal(4, $xs[1]::CONST, '[Bug #10943]')
assert_equal(4, $xs[1].new.foo, '[Bug #10943]')
# class def in block in singleton class
objs = []
$xs = []
$i = 0
2.times{
objs << obj = Object.new
class << obj
1.times{
CONST = ($i += 1)
}
1.times{
class X
$xs << self
CONST = ($i += 1)
def foo
CONST
end
end
def x
X
end
}
end
}
assert_not_equal($xs[0], $xs[1], '[Bug #10943]')
assert_not_equal(objs[0].x, objs[1].x, '[Bug #10943]')
assert_equal(2, $xs[0]::CONST, '[Bug #10943]')
assert_equal(2, $xs[0].new.foo, '[Bug #10943]')
assert_equal(4, $xs[1]::CONST, '[Bug #10943]')
assert_equal(4, $xs[1].new.foo, '[Bug #10943]')
# method def in singleton class
ms = []
ps = $test_singleton_class_shared_cref_ps = []
2.times{
ms << Module.new do
class << self
$test_singleton_class_shared_cref_ps << Proc.new{
def xyzzy
self
end
}
end
end
}
ps.each{|p| p.call} # define xyzzy methods for each singleton classes
ms.each{|m|
assert_equal(m, m.xyzzy, "Bug #10871")
}
end
end end

74
vm.c
View file

@ -79,6 +79,39 @@ rb_vm_control_frame_block_ptr(const rb_control_frame_t *cfp)
return VM_CF_BLOCK_PTR(cfp); return VM_CF_BLOCK_PTR(cfp);
} }
static NODE *
vm_cref_new(VALUE klass, long visi, NODE *prev_cref)
{
NODE *cref = NEW_CREF(klass);
cref->nd_refinements = Qnil;
cref->nd_visi = visi;
cref->nd_next = prev_cref;
return cref;
}
static NODE *
vm_cref_new_toplevel(rb_thread_t *th)
{
NODE *cref = vm_cref_new(rb_cObject, NOEX_PRIVATE /* toplevel visibility is private */, NULL);
if (th->top_wrapper) {
cref = vm_cref_new(th->top_wrapper, NOEX_PRIVATE, cref);
}
return cref;
}
static void
vm_cref_dump(const char *mesg, const NODE *cref)
{
fprintf(stderr, "vm_cref_dump: %s (%p)\n", mesg, cref);
while (cref) {
fprintf(stderr, "= cref| klass: %s\n", RSTRING_PTR(rb_class_path(cref->nd_clss)));
cref = cref->nd_next;
}
}
#if VM_COLLECT_USAGE_DETAILS #if VM_COLLECT_USAGE_DETAILS
static void vm_collect_usage_operand(int insn, int n, VALUE op); static void vm_collect_usage_operand(int insn, int n, VALUE op);
static void vm_collect_usage_insn(int insn); static void vm_collect_usage_insn(int insn);
@ -211,7 +244,9 @@ vm_set_top_stack(rb_thread_t * th, VALUE iseqval)
/* for return */ /* for return */
vm_push_frame(th, iseq, VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH, vm_push_frame(th, iseq, VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH,
th->top_self, rb_cObject, VM_ENVVAL_BLOCK_PTR(0), th->top_self, rb_cObject,
VM_ENVVAL_BLOCK_PTR(0),
vm_cref_new_toplevel(th),
iseq->iseq_encoded, th->cfp->sp, iseq->local_size, 0, iseq->stack_max); iseq->iseq_encoded, th->cfp->sp, iseq->local_size, 0, iseq->stack_max);
} }
@ -223,12 +258,10 @@ vm_set_eval_stack(rb_thread_t * th, VALUE iseqval, const NODE *cref, rb_block_t
vm_push_frame(th, iseq, VM_FRAME_MAGIC_EVAL | VM_FRAME_FLAG_FINISH, vm_push_frame(th, iseq, VM_FRAME_MAGIC_EVAL | VM_FRAME_FLAG_FINISH,
base_block->self, base_block->klass, base_block->self, base_block->klass,
VM_ENVVAL_PREV_EP_PTR(base_block->ep), iseq->iseq_encoded, VM_ENVVAL_PREV_EP_PTR(base_block->ep),
cref,
iseq->iseq_encoded,
th->cfp->sp, iseq->local_size, 0, iseq->stack_max); th->cfp->sp, iseq->local_size, 0, iseq->stack_max);
if (cref) {
th->cfp->ep[-1] = (VALUE)cref;
}
} }
static void static void
@ -790,6 +823,7 @@ invoke_block_from_c(rb_thread_t *th, const rb_block_t *block,
vm_push_frame(th, iseq, type | VM_FRAME_FLAG_FINISH | VM_FRAME_FLAG_BMETHOD, vm_push_frame(th, iseq, type | VM_FRAME_FLAG_FINISH | VM_FRAME_FLAG_BMETHOD,
self, defined_class, self, defined_class,
VM_ENVVAL_PREV_EP_PTR(block->ep), VM_ENVVAL_PREV_EP_PTR(block->ep),
cref,
iseq->iseq_encoded + opt_pc, iseq->iseq_encoded + opt_pc,
cfp->sp + arg_size, iseq->local_size - arg_size, cfp->sp + arg_size, iseq->local_size - arg_size,
me, iseq->stack_max); me, iseq->stack_max);
@ -801,15 +835,12 @@ invoke_block_from_c(rb_thread_t *th, const rb_block_t *block,
vm_push_frame(th, iseq, type | VM_FRAME_FLAG_FINISH, vm_push_frame(th, iseq, type | VM_FRAME_FLAG_FINISH,
self, defined_class, self, defined_class,
VM_ENVVAL_PREV_EP_PTR(block->ep), VM_ENVVAL_PREV_EP_PTR(block->ep),
cref,
iseq->iseq_encoded + opt_pc, iseq->iseq_encoded + opt_pc,
cfp->sp + arg_size, iseq->local_size - arg_size, cfp->sp + arg_size, iseq->local_size - arg_size,
0, iseq->stack_max); 0, iseq->stack_max);
} }
if (cref) {
th->cfp->ep[-1] = (VALUE)cref;
}
ret = vm_exec(th); ret = vm_exec(th);
if (me) { if (me) {
@ -1017,7 +1048,8 @@ rb_vm_cref(void)
if (cfp == 0) { if (cfp == 0) {
return NULL; return NULL;
} }
return rb_vm_get_cref(cfp->iseq, cfp->ep);
return rb_vm_get_cref(cfp->ep);
} }
const NODE * const NODE *
@ -1027,7 +1059,7 @@ rb_vm_cref_in_context(VALUE self, VALUE cbase)
const rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp); const rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp);
const NODE *cref; const NODE *cref;
if (cfp->self != self) return NULL; if (cfp->self != self) return NULL;
cref = rb_vm_get_cref(cfp->iseq, cfp->ep); cref = rb_vm_get_cref(cfp->ep);
if (cref->nd_clss != cbase) return NULL; if (cref->nd_clss != cbase) return NULL;
return cref; return cref;
} }
@ -1053,7 +1085,7 @@ rb_vm_cbase(void)
if (cfp == 0) { if (cfp == 0) {
rb_raise(rb_eRuntimeError, "Can't call on top of Fiber or Thread"); rb_raise(rb_eRuntimeError, "Can't call on top of Fiber or Thread");
} }
return vm_get_cbase(cfp->iseq, cfp->ep); return vm_get_cbase(cfp->ep);
} }
/* jump */ /* jump */
@ -1594,6 +1626,7 @@ vm_exec(rb_thread_t *th)
vm_push_frame(th, catch_iseq, VM_FRAME_MAGIC_RESCUE, vm_push_frame(th, catch_iseq, VM_FRAME_MAGIC_RESCUE,
cfp->self, cfp->klass, cfp->self, cfp->klass,
VM_ENVVAL_PREV_EP_PTR(cfp->ep), VM_ENVVAL_PREV_EP_PTR(cfp->ep),
NULL,
catch_iseq->iseq_encoded, catch_iseq->iseq_encoded,
cfp->sp + 1 /* push value */, cfp->sp + 1 /* push value */,
catch_iseq->local_size - 1, catch_iseq->local_size - 1,
@ -1745,7 +1778,8 @@ rb_vm_call_cfunc(VALUE recv, VALUE (*func)(VALUE), VALUE arg,
VALUE val; VALUE val;
vm_push_frame(th, DATA_PTR(iseqval), VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH, vm_push_frame(th, DATA_PTR(iseqval), VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH,
recv, CLASS_OF(recv), VM_ENVVAL_BLOCK_PTR(blockptr), 0, reg_cfp->sp, 1, 0, 0); recv, CLASS_OF(recv), VM_ENVVAL_BLOCK_PTR(blockptr), vm_cref_new_toplevel(th),
0, reg_cfp->sp, 1, 0, 0);
val = (*func)(arg); val = (*func)(arg);
@ -2183,7 +2217,9 @@ th_init(rb_thread_t *th, VALUE self)
th->cfp = (void *)(th->stack + th->stack_size); th->cfp = (void *)(th->stack + th->stack_size);
vm_push_frame(th, 0 /* dummy iseq */, VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH, vm_push_frame(th, 0 /* dummy iseq */, VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH,
Qnil /* dummy self */, Qnil /* dummy klass */, VM_ENVVAL_BLOCK_PTR(0), 0 /* dummy pc */, th->stack, 1, 0, 0); Qnil /* dummy self */, Qnil /* dummy klass */, VM_ENVVAL_BLOCK_PTR(0),
NULL /* dummy cref */,
0 /* dummy pc */, th->stack, 1, 0, 0);
th->status = THREAD_RUNNABLE; th->status = THREAD_RUNNABLE;
th->errinfo = Qnil; th->errinfo = Qnil;
@ -2250,15 +2286,13 @@ vm_define_method(rb_thread_t *th, VALUE obj, ID id, VALUE iseqval,
} }
/* dup */ /* dup */
COPY_CREF(miseq->cref_stack, cref);
miseq->cref_stack->nd_visi = NOEX_PUBLIC;
RB_OBJ_WRITE(miseq->self, &miseq->klass, klass); RB_OBJ_WRITE(miseq->self, &miseq->klass, klass);
miseq->defined_method_id = id; miseq->defined_method_id = id;
rb_add_method(klass, id, VM_METHOD_TYPE_ISEQ, miseq, noex); rb_add_method_iseq(klass, id, miseq, cref, noex);
if (!is_singleton && noex == NOEX_MODFUNC) { if (!is_singleton && noex == NOEX_MODFUNC) {
klass = rb_singleton_class(klass); klass = rb_singleton_class(klass);
rb_add_method(klass, id, VM_METHOD_TYPE_ISEQ, miseq, NOEX_PUBLIC); rb_add_method_iseq(klass, id, miseq, cref, NOEX_PUBLIC);
} }
} }
@ -2745,6 +2779,8 @@ Init_VM(void)
th->cfp->self = th->top_self; th->cfp->self = th->top_self;
th->cfp->klass = Qnil; th->cfp->klass = Qnil;
th->cfp->ep[-1] = (VALUE)vm_cref_new(rb_cObject, NOEX_PRIVATE, NULL);
/* /*
* The Binding of the top level scope * The Binding of the top level scope
*/ */

View file

@ -675,7 +675,7 @@ raise_argument_error(rb_thread_t *th, const rb_iseq_t *iseq, const VALUE exc)
VALUE at; VALUE at;
if (iseq) { if (iseq) {
vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD, Qnil /* self */, Qnil /* klass */, Qnil /* specval*/, vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD, Qnil /* self */, Qnil /* klass */, Qnil /* specval*/, NULL /* cref */,
iseq->iseq_encoded, th->cfp->sp, 0 /* local_size */, 0 /* me */, 0 /* stack_max */); iseq->iseq_encoded, th->cfp->sp, 0 /* local_size */, 0 /* me */, 0 /* stack_max */);
at = rb_vm_backtrace_object(); at = rb_vm_backtrace_object();
vm_pop_frame(th); vm_pop_frame(th);

View file

@ -117,6 +117,7 @@ typedef struct rb_compile_option_struct rb_compile_option_t;
struct iseq_inline_cache_entry { struct iseq_inline_cache_entry {
rb_serial_t ic_serial; rb_serial_t ic_serial;
NODE *ic_cref;
union { union {
size_t index; size_t index;
VALUE value; VALUE value;
@ -322,17 +323,6 @@ struct rb_iseq_struct {
VALUE self; VALUE self;
const VALUE orig; /* non-NULL if its data have origin */ const VALUE orig; /* non-NULL if its data have origin */
/* block inlining */
/*
* NODE *node;
* void *special_block_builder;
* void *cached_special_block_builder;
* VALUE cached_special_block;
*/
/* klass/module nest information stack (cref) */
NODE * const cref_stack;
const VALUE klass; const VALUE klass;
/* misc */ /* misc */
@ -416,7 +406,6 @@ typedef struct rb_vm_struct {
/* object management */ /* object management */
VALUE mark_object_ary; VALUE mark_object_ary;
const VALUE special_exceptions[ruby_special_error_count]; const VALUE special_exceptions[ruby_special_error_count];
/* load */ /* load */

View file

@ -119,7 +119,8 @@ vm_call0_cfunc_with_frame(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv
rb_control_frame_t *reg_cfp = th->cfp; rb_control_frame_t *reg_cfp = th->cfp;
vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, recv, defined_class, vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, recv, defined_class,
VM_ENVVAL_BLOCK_PTR(blockptr), 0, reg_cfp->sp, 1, me, 0); VM_ENVVAL_BLOCK_PTR(blockptr), NULL /* cref */,
0, reg_cfp->sp, 1, me, 0);
if (len >= 0) rb_check_arity(argc, len, len); if (len >= 0) rb_check_arity(argc, len, len);
@ -1306,13 +1307,13 @@ eval_string_with_cref(VALUE self, VALUE src, VALUE scope, NODE *const cref_arg,
if (!cref && base_block->iseq) { if (!cref && base_block->iseq) {
if (NIL_P(scope)) { if (NIL_P(scope)) {
orig_cref = rb_vm_get_cref(base_block->iseq, base_block->ep); orig_cref = rb_vm_get_cref(base_block->ep);
cref = NEW_CREF(Qnil); cref = NEW_CREF(Qnil);
crefval = (VALUE) cref; crefval = (VALUE) cref;
COPY_CREF(cref, orig_cref); COPY_CREF(cref, orig_cref);
} }
else { else {
cref = rb_vm_get_cref(base_block->iseq, base_block->ep); cref = rb_vm_get_cref(base_block->ep);
} }
} }
vm_set_eval_stack(th, iseqval, cref, base_block); vm_set_eval_stack(th, iseqval, cref, base_block);

View file

@ -46,6 +46,7 @@ vm_push_frame(rb_thread_t *th,
VALUE self, VALUE self,
VALUE klass, VALUE klass,
VALUE specval, VALUE specval,
const NODE *cref,
const VALUE *pc, const VALUE *pc,
VALUE *sp, VALUE *sp,
int local_size, int local_size,
@ -68,7 +69,8 @@ vm_push_frame(rb_thread_t *th,
} }
/* set special val */ /* set special val */
*sp = specval; sp[-1] = (VALUE)cref;
sp[ 0] = specval;
/* setup vm control frame stack */ /* setup vm control frame stack */
@ -161,6 +163,7 @@ lep_svar_get(rb_thread_t *th, const VALUE *lep, rb_num_t key)
const NODE * const svar = *svar_place; const NODE * const svar = *svar_place;
if (NIL_P((VALUE)svar)) return Qnil; if (NIL_P((VALUE)svar)) return Qnil;
if (nd_type(svar) == NODE_CREF) return Qnil;
switch (key) { switch (key) {
case VM_SVAR_LASTLINE: case VM_SVAR_LASTLINE:
@ -188,6 +191,12 @@ lep_svar_set(rb_thread_t *th, VALUE *lep, rb_num_t key, VALUE val)
if (NIL_P((VALUE)svar)) { if (NIL_P((VALUE)svar)) {
svar = *svar_place = NEW_IF(Qnil, Qnil, Qnil); svar = *svar_place = NEW_IF(Qnil, Qnil, Qnil);
svar->nd_reserved = Qfalse;
}
else if (nd_type(svar) == NODE_CREF) {
NODE *cref = svar;
svar = *svar_place = NEW_IF(Qnil, Qnil, Qnil);
svar->nd_reserved = (VALUE)cref;
} }
switch (key) { switch (key) {
@ -245,28 +254,42 @@ vm_getspecial(rb_thread_t *th, VALUE *lep, rb_num_t key, rb_num_t type)
} }
static NODE * static NODE *
vm_get_cref0(const rb_iseq_t *iseq, const VALUE *ep) ep_cref(const VALUE *ep)
{ {
while (1) { const VALUE svar = ep[-1];
if (VM_EP_LEP_P(ep)) {
if (!RUBY_VM_NORMAL_ISEQ_P(iseq)) return NULL; if (!svar) {
return iseq->cref_stack; return NULL;
} }
else if (ep[-1] != Qnil) { else if (nd_type(svar) == NODE_CREF) {
return (NODE *)svar;
}
else {
return (NODE *)((NODE *)svar)->nd_reserved;
}
}
static NODE *
vm_get_cref0(const VALUE *ep)
{
while (!VM_EP_LEP_P(ep)) {
if (ep[-1]) {
return (NODE *)ep[-1]; return (NODE *)ep[-1];
} }
ep = VM_EP_PREV_EP(ep); ep = VM_EP_PREV_EP(ep);
} }
return ep_cref(ep);
} }
NODE * NODE *
rb_vm_get_cref(const rb_iseq_t *iseq, const VALUE *ep) rb_vm_get_cref(const VALUE *ep)
{ {
NODE *cref = vm_get_cref0(iseq, ep); NODE *cref = vm_get_cref0(ep);
if (cref == 0) { if (cref == 0) {
rb_bug("rb_vm_get_cref: unreachable"); rb_bug("rb_vm_get_cref: unreachable");
} }
return cref; return cref;
} }
@ -274,6 +297,7 @@ void
rb_vm_rewrite_cref_stack(NODE *node, VALUE old_klass, VALUE new_klass, NODE **new_cref_ptr) rb_vm_rewrite_cref_stack(NODE *node, VALUE old_klass, VALUE new_klass, NODE **new_cref_ptr)
{ {
NODE *new_node; NODE *new_node;
while (node) { while (node) {
if (node->nd_clss == old_klass) { if (node->nd_clss == old_klass) {
new_node = NEW_CREF(new_klass); new_node = NEW_CREF(new_klass);
@ -294,17 +318,21 @@ rb_vm_rewrite_cref_stack(NODE *node, VALUE old_klass, VALUE new_klass, NODE **ne
static NODE * static NODE *
vm_cref_push(rb_thread_t *th, VALUE klass, int noex, rb_block_t *blockptr) vm_cref_push(rb_thread_t *th, VALUE klass, int noex, rb_block_t *blockptr)
{ {
rb_control_frame_t *cfp = vm_get_ruby_level_caller_cfp(th, th->cfp); NODE *prev_cref = NULL;
NODE *cref = NEW_CREF(klass); NODE *cref = NULL;
cref->nd_refinements = Qnil;
cref->nd_visi = noex;
if (blockptr) { if (blockptr) {
RB_OBJ_WRITE(cref, &cref->nd_next, vm_get_cref0(blockptr->iseq, blockptr->ep)); prev_cref = vm_get_cref0(blockptr->ep);
} }
else if (cfp) { else {
RB_OBJ_WRITE(cref, &cref->nd_next, vm_get_cref0(cfp->iseq, cfp->ep)); rb_control_frame_t *cfp = vm_get_ruby_level_caller_cfp(th, th->cfp);
if (cfp) {
prev_cref = vm_get_cref0(cfp->ep);
} }
}
cref = vm_cref_new(klass, noex, prev_cref);
/* TODO: why cref->nd_next is 1? */ /* TODO: why cref->nd_next is 1? */
if (cref->nd_next && cref->nd_next != (void *) 1 && if (cref->nd_next && cref->nd_next != (void *) 1 &&
!NIL_P(cref->nd_next->nd_refinements)) { !NIL_P(cref->nd_next->nd_refinements)) {
@ -315,9 +343,9 @@ vm_cref_push(rb_thread_t *th, VALUE klass, int noex, rb_block_t *blockptr)
} }
static inline VALUE static inline VALUE
vm_get_cbase(const rb_iseq_t *iseq, const VALUE *ep) vm_get_cbase(const VALUE *ep)
{ {
NODE *cref = rb_vm_get_cref(iseq, ep); NODE *cref = rb_vm_get_cref(ep);
VALUE klass = Qundef; VALUE klass = Qundef;
while (cref) { while (cref) {
@ -331,9 +359,9 @@ vm_get_cbase(const rb_iseq_t *iseq, const VALUE *ep)
} }
static inline VALUE static inline VALUE
vm_get_const_base(const rb_iseq_t *iseq, const VALUE *ep) vm_get_const_base(const VALUE *ep)
{ {
NODE *cref = rb_vm_get_cref(iseq, ep); NODE *cref = rb_vm_get_cref(ep);
VALUE klass = Qundef; VALUE klass = Qundef;
while (cref) { while (cref) {
@ -373,14 +401,13 @@ vm_get_iclass(rb_control_frame_t *cfp, VALUE klass)
} }
static inline VALUE static inline VALUE
vm_get_ev_const(rb_thread_t *th, const rb_iseq_t *iseq, vm_get_ev_const(rb_thread_t *th, VALUE orig_klass, ID id, int is_defined)
VALUE orig_klass, ID id, int is_defined)
{ {
VALUE val; VALUE val;
if (orig_klass == Qnil) { if (orig_klass == Qnil) {
/* in current lexical scope */ /* in current lexical scope */
const NODE *root_cref = rb_vm_get_cref(iseq, th->cfp->ep); const NODE *root_cref = rb_vm_get_cref(th->cfp->ep);
const NODE *cref; const NODE *cref;
VALUE klass = orig_klass; VALUE klass = orig_klass;
@ -1128,7 +1155,7 @@ vm_callee_setup_arg(rb_thread_t *th, rb_call_info_t *ci, const rb_iseq_t *iseq,
static VALUE static VALUE
vm_call_iseq_setup(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci) vm_call_iseq_setup(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
{ {
vm_callee_setup_arg(th, ci, ci->me->def->body.iseq, cfp->sp - ci->argc); vm_callee_setup_arg(th, ci, ci->me->def->body.iseq_body.iseq, cfp->sp - ci->argc);
return vm_call_iseq_setup_2(th, cfp, ci); return vm_call_iseq_setup_2(th, cfp, ci);
} }
@ -1148,7 +1175,7 @@ vm_call_iseq_setup_normal(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info
{ {
int i, local_size; int i, local_size;
VALUE *argv = cfp->sp - ci->argc; VALUE *argv = cfp->sp - ci->argc;
rb_iseq_t *iseq = ci->me->def->body.iseq; rb_iseq_t *iseq = ci->me->def->body.iseq_body.iseq;
VALUE *sp = argv + iseq->param.size; VALUE *sp = argv + iseq->param.size;
/* clear local variables (arg_size...local_size) */ /* clear local variables (arg_size...local_size) */
@ -1157,7 +1184,7 @@ vm_call_iseq_setup_normal(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info
} }
vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD, ci->recv, ci->defined_class, vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD, ci->recv, ci->defined_class,
VM_ENVVAL_BLOCK_PTR(ci->blockptr), VM_ENVVAL_BLOCK_PTR(ci->blockptr), ci->me->def->body.iseq_body.cref,
iseq->iseq_encoded + ci->aux.opt_pc, sp, 0, ci->me, iseq->stack_max); iseq->iseq_encoded + ci->aux.opt_pc, sp, 0, ci->me, iseq->stack_max);
cfp->sp = argv - 1 /* recv */; cfp->sp = argv - 1 /* recv */;
@ -1169,7 +1196,7 @@ vm_call_iseq_setup_tailcall(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_in
{ {
int i; int i;
VALUE *argv = cfp->sp - ci->argc; VALUE *argv = cfp->sp - ci->argc;
rb_iseq_t *iseq = ci->me->def->body.iseq; rb_iseq_t *iseq = ci->me->def->body.iseq_body.iseq;
VALUE *src_argv = argv; VALUE *src_argv = argv;
VALUE *sp_orig, *sp; VALUE *sp_orig, *sp;
VALUE finish_flag = VM_FRAME_TYPE_FINISH_P(cfp) ? VM_FRAME_FLAG_FINISH : 0; VALUE finish_flag = VM_FRAME_TYPE_FINISH_P(cfp) ? VM_FRAME_FLAG_FINISH : 0;
@ -1195,7 +1222,8 @@ vm_call_iseq_setup_tailcall(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_in
} }
vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD | finish_flag, vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD | finish_flag,
ci->recv, ci->defined_class, VM_ENVVAL_BLOCK_PTR(ci->blockptr), ci->recv, ci->defined_class,
VM_ENVVAL_BLOCK_PTR(ci->blockptr), ci->me->def->body.iseq_body.cref,
iseq->iseq_encoded + ci->aux.opt_pc, sp, 0, ci->me, iseq->stack_max); iseq->iseq_encoded + ci->aux.opt_pc, sp, 0, ci->me, iseq->stack_max);
cfp->sp = sp_orig; cfp->sp = sp_orig;
@ -1377,7 +1405,8 @@ vm_call_cfunc_with_frame(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_i
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass, Qundef); EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass, Qundef);
vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, recv, defined_class, vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, recv, defined_class,
VM_ENVVAL_BLOCK_PTR(blockptr), 0, th->cfp->sp, 1, me, 0); VM_ENVVAL_BLOCK_PTR(blockptr), NULL /* cref */,
0, th->cfp->sp, 1, me, 0);
if (len >= 0) rb_check_arity(argc, len, len); if (len >= 0) rb_check_arity(argc, len, len);
@ -1465,7 +1494,8 @@ vm_call_cfunc_push_frame(rb_thread_t *th)
th->passed_ci = 0; th->passed_ci = 0;
vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, ci->recv, ci->defined_class, vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, ci->recv, ci->defined_class,
VM_ENVVAL_BLOCK_PTR(ci->blockptr), 0, th->cfp->sp + ci->aux.inc_sp, 1, me); VM_ENVVAL_BLOCK_PTR(ci->blockptr), NULL /* cref */,
0, th->cfp->sp + ci->aux.inc_sp, 1, me);
if (ci->call != vm_call_general) { if (ci->call != vm_call_general) {
ci->call = vm_call_cfunc_with_frame; ci->call = vm_call_cfunc_with_frame;
@ -1754,7 +1784,7 @@ vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info_t *ci)
case VM_METHOD_TYPE_UNDEF: case VM_METHOD_TYPE_UNDEF:
break; break;
case VM_METHOD_TYPE_REFINED:{ case VM_METHOD_TYPE_REFINED:{
NODE *cref = rb_vm_get_cref(cfp->iseq, cfp->ep); NODE *cref = rb_vm_get_cref(cfp->ep);
VALUE refinements = cref ? cref->nd_refinements : Qnil; VALUE refinements = cref ? cref->nd_refinements : Qnil;
VALUE refinement, defined_class; VALUE refinement, defined_class;
rb_method_entry_t *me; rb_method_entry_t *me;
@ -1983,7 +2013,7 @@ vm_search_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_inf
iseq = iseq->parent_iseq; iseq = iseq->parent_iseq;
} }
if (ci->me && ci->me->def->type == VM_METHOD_TYPE_ISEQ && ci->me->def->body.iseq == iseq) { if (ci->me && ci->me->def->type == VM_METHOD_TYPE_ISEQ && ci->me->def->body.iseq_body.iseq == iseq) {
ci->klass = RCLASS_SUPER(ci->defined_class); ci->klass = RCLASS_SUPER(ci->defined_class);
ci->me = rb_method_entry(ci->klass, ci->mid, &ci->defined_class); ci->me = rb_method_entry(ci->klass, ci->mid, &ci->defined_class);
} }
@ -2039,8 +2069,8 @@ vm_yield_with_cfunc(rb_thread_t *th, const rb_block_t *block,
vm_push_frame(th, (rb_iseq_t *)ifunc, VM_FRAME_MAGIC_IFUNC, vm_push_frame(th, (rb_iseq_t *)ifunc, VM_FRAME_MAGIC_IFUNC,
self, defined_class, self, defined_class,
VM_ENVVAL_PREV_EP_PTR(block->ep), 0, VM_ENVVAL_PREV_EP_PTR(block->ep), NULL /* cref */,
th->cfp->sp, 1, th->passed_bmethod_me, 0); 0, th->cfp->sp, 1, th->passed_bmethod_me, 0);
val = (*ifunc->nd_cfnc) (arg, ifunc->nd_tval, argc, argv, blockarg); val = (*ifunc->nd_cfnc) (arg, ifunc->nd_tval, argc, argv, blockarg);
@ -2095,7 +2125,7 @@ vm_invoke_block(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci
is_lambda ? VM_FRAME_MAGIC_LAMBDA : VM_FRAME_MAGIC_BLOCK, is_lambda ? VM_FRAME_MAGIC_LAMBDA : VM_FRAME_MAGIC_BLOCK,
block->self, block->self,
block->klass, block->klass,
VM_ENVVAL_PREV_EP_PTR(block->ep), VM_ENVVAL_PREV_EP_PTR(block->ep), NULL /* cref */,
iseq->iseq_encoded + opt_pc, iseq->iseq_encoded + opt_pc,
rsp + arg_size, rsp + arg_size,
iseq->local_size - arg_size, 0, iseq->stack_max); iseq->local_size - arg_size, 0, iseq->stack_max);

View file

@ -245,8 +245,7 @@ rb_add_refined_method_entry(VALUE refined_class, ID mid)
rb_clear_method_cache_by_class(refined_class); rb_clear_method_cache_by_class(refined_class);
} }
else { else {
rb_add_method(refined_class, mid, VM_METHOD_TYPE_REFINED, 0, rb_add_method(refined_class, mid, VM_METHOD_TYPE_REFINED, 0, NOEX_PUBLIC);
NOEX_PUBLIC);
} }
} }
@ -325,7 +324,7 @@ rb_method_entry_make(VALUE klass, ID mid, rb_method_type_t type,
rb_warning("method redefined; discarding old %"PRIsVALUE, rb_id2str(mid)); rb_warning("method redefined; discarding old %"PRIsVALUE, rb_id2str(mid));
switch (old_def->type) { switch (old_def->type) {
case VM_METHOD_TYPE_ISEQ: case VM_METHOD_TYPE_ISEQ:
iseq = old_def->body.iseq; iseq = old_def->body.iseq_body.iseq;
break; break;
case VM_METHOD_TYPE_BMETHOD: case VM_METHOD_TYPE_BMETHOD:
iseq = rb_proc_get_iseq(old_def->body.proc, 0); iseq = rb_proc_get_iseq(old_def->body.proc, 0);
@ -359,7 +358,8 @@ rb_method_entry_make(VALUE klass, ID mid, rb_method_type_t type,
switch(def->type) { switch(def->type) {
case VM_METHOD_TYPE_ISEQ: case VM_METHOD_TYPE_ISEQ:
RB_OBJ_WRITTEN(klass, Qundef, def->body.iseq->self); RB_OBJ_WRITTEN(klass, Qundef, def->body.iseq_body.iseq->self);
RB_OBJ_WRITTEN(klass, Qundef, def->body.iseq_body.cref);
break; break;
case VM_METHOD_TYPE_IVAR: case VM_METHOD_TYPE_IVAR:
RB_OBJ_WRITTEN(klass, Qundef, def->body.attr.location); RB_OBJ_WRITTEN(klass, Qundef, def->body.attr.location);
@ -447,27 +447,40 @@ setup_method_cfunc_struct(rb_method_cfunc_t *cfunc, VALUE (*func)(), int argc)
} }
rb_method_entry_t * rb_method_entry_t *
rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *opts, rb_method_flag_t noex) rb_add_method0(VALUE klass, ID mid, rb_method_type_t type, void *opts, rb_method_flag_t noex, NODE *cref)
{ {
rb_thread_t *th; rb_thread_t *th;
rb_control_frame_t *cfp; rb_control_frame_t *cfp;
int line; int line;
rb_method_entry_t *me = rb_method_entry_make(klass, mid, type, 0, noex, klass); rb_method_entry_t *me = rb_method_entry_make(klass, mid, type, 0, noex, klass);
rb_method_definition_t *def = ALLOC(rb_method_definition_t); rb_method_definition_t *def = ALLOC(rb_method_definition_t);
if (me->def && me->def->type == VM_METHOD_TYPE_REFINED) { if (me->def && me->def->type == VM_METHOD_TYPE_REFINED) {
me->def->body.orig_me->def = def; me->def->body.orig_me->def = def;
} }
else { else {
me->def = def; me->def = def;
} }
if (0 && cref) vm_cref_dump("rb_add_method0", cref);
def->type = type; def->type = type;
def->original_id = mid; def->original_id = mid;
def->alias_count = 0; def->alias_count = 0;
switch (type) { switch (type) {
case VM_METHOD_TYPE_ISEQ: { case VM_METHOD_TYPE_ISEQ: {
rb_iseq_t *iseq = (rb_iseq_t *)opts; rb_iseq_t *iseq = (rb_iseq_t *)opts;
*(rb_iseq_t **)&def->body.iseq = iseq; NODE *private_cref;
RB_OBJ_WRITTEN(klass, Qundef, iseq->self);
*(rb_iseq_t **)&def->body.iseq_body.iseq = iseq;
RB_OBJ_WRITTEN(klass, Qundef, iseq->self); /* should be set iseq before newobj */
def->body.iseq_body.cref = NULL;
private_cref = vm_cref_new_toplevel(GET_THREAD()); /* TODO: CREF should be shared with other methods */
if (cref) COPY_CREF(private_cref, cref);
private_cref->nd_visi = NOEX_PUBLIC;
RB_OBJ_WRITE(klass, &def->body.iseq_body.cref, private_cref);
break; break;
} }
case VM_METHOD_TYPE_CFUNC: case VM_METHOD_TYPE_CFUNC:
@ -511,13 +524,24 @@ rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *opts, rb_method_
return me; return me;
} }
rb_method_entry_t *
rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *opts, rb_method_flag_t noex)
{
return rb_add_method0(klass, mid, type, opts, noex, NULL);
}
void
rb_add_method_iseq(VALUE klass, ID mid, rb_iseq_t *iseq, NODE *cref, rb_method_flag_t noex)
{
rb_add_method0(klass, mid, VM_METHOD_TYPE_ISEQ, iseq, noex, cref);
}
static rb_method_entry_t * static rb_method_entry_t *
method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *me, method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *me,
rb_method_flag_t noex, VALUE defined_class) rb_method_flag_t noex, VALUE defined_class)
{ {
rb_method_type_t type = me->def ? me->def->type : VM_METHOD_TYPE_UNDEF; rb_method_type_t type = me->def ? me->def->type : VM_METHOD_TYPE_UNDEF;
rb_method_entry_t *newme = rb_method_entry_make(klass, mid, type, me->def, noex, rb_method_entry_t *newme = rb_method_entry_make(klass, mid, type, me->def, noex, defined_class);
defined_class);
method_added(klass, mid); method_added(klass, mid);
return newme; return newme;
} }
@ -1195,7 +1219,7 @@ rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_defini
} }
switch (d1->type) { switch (d1->type) {
case VM_METHOD_TYPE_ISEQ: case VM_METHOD_TYPE_ISEQ:
return d1->body.iseq == d2->body.iseq; return d1->body.iseq_body.iseq == d2->body.iseq_body.iseq;
case VM_METHOD_TYPE_CFUNC: case VM_METHOD_TYPE_CFUNC:
return return
d1->body.cfunc.func == d2->body.cfunc.func && d1->body.cfunc.func == d2->body.cfunc.func &&
@ -1226,7 +1250,7 @@ rb_hash_method_definition(st_index_t hash, const rb_method_definition_t *def)
hash = rb_hash_uint(hash, def->type); hash = rb_hash_uint(hash, def->type);
switch (def->type) { switch (def->type) {
case VM_METHOD_TYPE_ISEQ: case VM_METHOD_TYPE_ISEQ:
return rb_hash_uint(hash, (st_index_t)def->body.iseq); return rb_hash_uint(hash, (st_index_t)def->body.iseq_body.iseq);
case VM_METHOD_TYPE_CFUNC: case VM_METHOD_TYPE_CFUNC:
hash = rb_hash_uint(hash, (st_index_t)def->body.cfunc.func); hash = rb_hash_uint(hash, (st_index_t)def->body.cfunc.func);
return rb_hash_uint(hash, def->body.cfunc.argc); return rb_hash_uint(hash, def->body.cfunc.argc);