aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-03-06 12:24:58 +0000
committerko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-03-06 12:24:58 +0000
commitd84f9b16946bca06ce0557ebe99152d7d445c9ec (patch)
tree8141a5d835d1e5638231aced09a08c74ff8fadae
parente0f5a6ab4850e2745d5cb6fb081eb81dc024d2d4 (diff)
downloadruby-d84f9b16946bca06ce0557ebe99152d7d445c9ec.tar.gz
* 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
-rw-r--r--ChangeLog46
-rw-r--r--class.c7
-rw-r--r--gc.c5
-rw-r--r--insns.def27
-rw-r--r--iseq.c25
-rw-r--r--method.h8
-rw-r--r--node.c1
-rw-r--r--proc.c20
-rw-r--r--struct.c4
-rw-r--r--test/ruby/test_class.rb120
-rw-r--r--vm.c76
-rw-r--r--vm_args.c2
-rw-r--r--vm_core.h13
-rw-r--r--vm_eval.c7
-rw-r--r--vm_insnhelper.c102
-rw-r--r--vm_method.c46
16 files changed, 378 insertions, 131 deletions
diff --git a/ChangeLog b/ChangeLog
index 737e6222d0..cfcf7a7a00 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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>
* test/webrick/test_filehandler.rb: on vboxsf (on VirtualBox
diff --git a/class.c b/class.c
index 12bac24487..42c27b5f32 100644
--- a/class.c
+++ b/class.c
@@ -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) {
rb_iseq_t *iseq;
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);
- rb_vm_rewrite_cref_stack(me->def->body.iseq->cref_stack, me->klass, klass, &new_cref);
- RB_OBJ_WRITE(iseq->self, &iseq->cref_stack, new_cref);
- rb_add_method(klass, mid, VM_METHOD_TYPE_ISEQ, iseq, me->flag);
+ rb_vm_rewrite_cref_stack(me->def->body.iseq_body.cref, me->klass, klass, &new_cref);
+ rb_add_method_iseq(klass, mid, iseq, new_cref, me->flag);
RB_GC_GUARD(newiseqval);
}
else {
diff --git a/gc.c b/gc.c
index d69276ee3e..10b74b0cae 100644
--- a/gc.c
+++ b/gc.c
@@ -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;
gc_mark(objspace, me->klass);
+
again:
if (!def) return;
+
switch (def->type) {
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;
case VM_METHOD_TYPE_BMETHOD:
gc_mark(objspace, def->body.proc);
diff --git a/insns.def b/insns.def
index 778999d7db..761d1fc5eb 100644
--- a/insns.def
+++ b/insns.def
@@ -159,7 +159,7 @@ getclassvariable
()
(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);
}
@@ -174,7 +174,7 @@ setclassvariable
(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);
}
@@ -196,7 +196,7 @@ getconstant
(VALUE klass)
(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;
break;
case VM_SPECIAL_OBJECT_CBASE:
- val = vm_get_cbase(GET_ISEQ(), GET_EP());
+ val = vm_get_cbase(GET_EP());
break;
case VM_SPECIAL_OBJECT_CONST_BASE:
- val = vm_get_const_base(GET_ISEQ(), GET_EP());
+ val = vm_get_const_base(GET_EP());
break;
default:
rb_bug("putspecialobject insn: unknown value_type");
@@ -730,7 +730,7 @@ defined
}
break;
case DEFINED_IVAR2:
- klass = vm_get_cbase(GET_ISEQ(), GET_EP());
+ klass = vm_get_cbase(GET_EP());
break;
case DEFINED_GVAR:
if (rb_gvar_defined(rb_global_entry(SYM2ID(obj)))) {
@@ -738,7 +738,7 @@ defined
}
break;
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());
if (rb_cvar_defined(klass, SYM2ID(obj))) {
expr_type = DEFINED_CVAR;
@@ -747,7 +747,7 @@ defined
}
case DEFINED_CONST:
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;
}
break;
@@ -1013,13 +1013,14 @@ defineclass
rb_bug("unknown defineclass type: %d", (int)type);
}
- COPY_CREF(class_iseq->cref_stack, vm_cref_push(th, klass, NOEX_PUBLIC, NULL));
-
/* enter scope */
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->local_size, 0, class_iseq->stack_max);
+
RESTORE_REGS();
NEXT_INSN();
}
@@ -1241,7 +1242,8 @@ getinlinecache
()
(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;
JUMP(dst);
}
@@ -1267,6 +1269,7 @@ setinlinecache
}
ic->ic_value.value = val;
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;
}
diff --git a/iseq.c b/iseq.c
index de65dcbf33..1eac9309f3 100644
--- a/iseq.c
+++ b/iseq.c
@@ -121,7 +121,6 @@ iseq_mark(void *ptr)
RUBY_MARK_UNLESS_NULL(iseq->location.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->coverage);
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;
}
-#define ISEQ_SET_CREF(iseq, cref) RB_OBJ_WRITE((iseq)->self, &(iseq)->cref_stack, (cref))
-
static void
set_relation(rb_iseq_t *iseq, const VALUE parent)
{
const VALUE type = iseq->type;
- rb_thread_t *th = GET_THREAD();
rb_iseq_t *piseq;
/* set class nest stack */
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;
}
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;
}
else if (RTEST(parent)) {
GetISeqPtr(parent, piseq);
- ISEQ_SET_CREF(iseq, piseq->cref_stack);
iseq->local_iseq = piseq->local_iseq;
}
@@ -1973,13 +1955,8 @@ rb_iseq_clone(VALUE iseqval, VALUE newcbase)
if (iseq0->local_iseq == iseq0) {
iseq1->local_iseq = iseq1;
}
+
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);
}
diff --git a/method.h b/method.h
index 65070532aa..9df9430946 100644
--- a/method.h
+++ b/method.h
@@ -12,6 +12,7 @@
#define METHOD_H
#include "internal.h"
+#include "node.h"
#ifndef END_OF_ENUMERATION
# if defined(__GNUC__) &&! defined(__STRICT_ANSI__)
@@ -79,8 +80,12 @@ typedef struct rb_method_definition_struct {
rb_method_type_t type; /* method type */
int alias_count;
ID original_id;
+
union {
- rb_iseq_t * const iseq; /* should be mark */
+ struct {
+ rb_iseq_t *const iseq; /* should be mark */
+ NODE *cref;
+ } iseq_body;
rb_method_cfunc_t cfunc;
rb_method_attr_t attr;
const VALUE proc; /* should be mark */
@@ -113,6 +118,7 @@ struct unlinked_method_entry_list_entry {
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, 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_method_entry(VALUE klass, ID id, VALUE *define_class_ptr);
rb_method_entry_t *rb_method_entry_at(VALUE obj, ID id);
diff --git a/node.c b/node.c
index 32518d3154..8e2dcdf8b7 100644
--- a/node.c
+++ b/node.c
@@ -947,6 +947,7 @@ rb_gc_mark_node(NODE *obj)
{
switch (nd_type(obj)) {
case NODE_IF: /* 1,2,3 */
+ rb_gc_mark(obj->nd_refinements); /* use as SVAR */
case NODE_FOR:
case NODE_ITER:
case NODE_WHEN:
diff --git a/proc.c b/proc.c
index 224df0120f..6da2f547c5 100644
--- a/proc.c
+++ b/proc.c
@@ -1208,7 +1208,6 @@ mnew_internal(rb_method_entry_t *me, VALUE defined_class, VALUE klass,
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++;
@@ -2025,7 +2024,7 @@ rb_method_entry_min_max_arity(const rb_method_entry_t *me, int *max)
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;
+ rb_iseq_t *iseq = def->body.iseq_body.iseq;
return rb_iseq_min_max_arity(iseq, max);
}
case VM_METHOD_TYPE_UNDEF:
@@ -2162,12 +2161,24 @@ method_get_iseq(rb_method_definition_t *def)
case VM_METHOD_TYPE_BMETHOD:
return get_proc_iseq(def->body.proc, 0);
case VM_METHOD_TYPE_ISEQ:
- return def->body.iseq;
+ return def->body.iseq_body.iseq;
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_method_get_iseq(VALUE method)
{
@@ -2376,6 +2387,7 @@ method_proc(VALUE method)
env->block.self = meth->recv;
env->block.klass = meth->defined_class;
env->block.iseq = method_get_iseq(meth->me->def);
+ env->block.ep[-1] = (VALUE)method_get_cref(meth->me->def);
return procval;
}
diff --git a/struct.c b/struct.c
index c123318b81..cd427ffef5 100644
--- a/struct.c
+++ b/struct.c
@@ -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);
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);
}
@@ -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);
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);
}
diff --git a/test/ruby/test_class.rb b/test/ruby/test_class.rb
index e17f56f913..36aeaf2bdf 100644
--- a/test/ruby/test_class.rb
+++ b/test/ruby/test_class.rb
@@ -399,4 +399,124 @@ class TestClass < Test::Unit::TestCase
def c.f; 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
diff --git a/vm.c b/vm.c
index b84ba788c2..cc9acbcb7d 100644
--- a/vm.c
+++ b/vm.c
@@ -79,6 +79,39 @@ rb_vm_control_frame_block_ptr(const rb_control_frame_t *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
static void vm_collect_usage_operand(int insn, int n, VALUE op);
static void vm_collect_usage_insn(int insn);
@@ -200,7 +233,7 @@ vm_stat(int argc, VALUE *argv, VALUE self)
/* control stack frame */
static void
-vm_set_top_stack(rb_thread_t * th, VALUE iseqval)
+vm_set_top_stack(rb_thread_t *th, VALUE iseqval)
{
rb_iseq_t *iseq;
GetISeqPtr(iseqval, iseq);
@@ -211,7 +244,9 @@ vm_set_top_stack(rb_thread_t * th, VALUE iseqval)
/* for return */
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);
}
@@ -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,
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);
-
- if (cref) {
- th->cfp->ep[-1] = (VALUE)cref;
- }
}
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,
self, defined_class,
VM_ENVVAL_PREV_EP_PTR(block->ep),
+ cref,
iseq->iseq_encoded + opt_pc,
cfp->sp + arg_size, iseq->local_size - arg_size,
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,
self, defined_class,
VM_ENVVAL_PREV_EP_PTR(block->ep),
+ cref,
iseq->iseq_encoded + opt_pc,
cfp->sp + arg_size, iseq->local_size - arg_size,
0, iseq->stack_max);
}
- if (cref) {
- th->cfp->ep[-1] = (VALUE)cref;
- }
-
ret = vm_exec(th);
if (me) {
@@ -1017,7 +1048,8 @@ rb_vm_cref(void)
if (cfp == 0) {
return NULL;
}
- return rb_vm_get_cref(cfp->iseq, cfp->ep);
+
+ return rb_vm_get_cref(cfp->ep);
}
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 NODE *cref;
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;
return cref;
}
@@ -1053,7 +1085,7 @@ rb_vm_cbase(void)
if (cfp == 0) {
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 */
@@ -1594,6 +1626,7 @@ vm_exec(rb_thread_t *th)
vm_push_frame(th, catch_iseq, VM_FRAME_MAGIC_RESCUE,
cfp->self, cfp->klass,
VM_ENVVAL_PREV_EP_PTR(cfp->ep),
+ NULL,
catch_iseq->iseq_encoded,
cfp->sp + 1 /* push value */,
catch_iseq->local_size - 1,
@@ -1745,7 +1778,8 @@ rb_vm_call_cfunc(VALUE recv, VALUE (*func)(VALUE), VALUE arg,
VALUE val;
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);
@@ -2183,7 +2217,9 @@ th_init(rb_thread_t *th, VALUE self)
th->cfp = (void *)(th->stack + th->stack_size);
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->errinfo = Qnil;
@@ -2250,15 +2286,13 @@ vm_define_method(rb_thread_t *th, VALUE obj, ID id, VALUE iseqval,
}
/* dup */
- COPY_CREF(miseq->cref_stack, cref);
- miseq->cref_stack->nd_visi = NOEX_PUBLIC;
RB_OBJ_WRITE(miseq->self, &miseq->klass, klass);
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) {
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->klass = Qnil;
+ th->cfp->ep[-1] = (VALUE)vm_cref_new(rb_cObject, NOEX_PRIVATE, NULL);
+
/*
* The Binding of the top level scope
*/
diff --git a/vm_args.c b/vm_args.c
index cf7256b2d7..e4ade6bb2f 100644
--- a/vm_args.c
+++ b/vm_args.c
@@ -675,7 +675,7 @@ raise_argument_error(rb_thread_t *th, const rb_iseq_t *iseq, const VALUE exc)
VALUE at;
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 */);
at = rb_vm_backtrace_object();
vm_pop_frame(th);
diff --git a/vm_core.h b/vm_core.h
index 1f17dfd56a..5b364129bb 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -117,6 +117,7 @@ typedef struct rb_compile_option_struct rb_compile_option_t;
struct iseq_inline_cache_entry {
rb_serial_t ic_serial;
+ NODE *ic_cref;
union {
size_t index;
VALUE value;
@@ -322,17 +323,6 @@ struct rb_iseq_struct {
VALUE self;
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;
/* misc */
@@ -416,7 +406,6 @@ typedef struct rb_vm_struct {
/* object management */
VALUE mark_object_ary;
-
const VALUE special_exceptions[ruby_special_error_count];
/* load */
diff --git a/vm_eval.c b/vm_eval.c
index 4039b6c9f2..add2aaf50a 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -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;
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);
@@ -1306,13 +1307,13 @@ eval_string_with_cref(VALUE self, VALUE src, VALUE scope, NODE *const cref_arg,
if (!cref && base_block->iseq) {
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);
crefval = (VALUE) cref;
COPY_CREF(cref, orig_cref);
}
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);
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 815cf4e30b..e4afbdb0fb 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -46,6 +46,7 @@ vm_push_frame(rb_thread_t *th,
VALUE self,
VALUE klass,
VALUE specval,
+ const NODE *cref,
const VALUE *pc,
VALUE *sp,
int local_size,
@@ -68,7 +69,8 @@ vm_push_frame(rb_thread_t *th,
}
/* set special val */
- *sp = specval;
+ sp[-1] = (VALUE)cref;
+ sp[ 0] = specval;
/* 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;
if (NIL_P((VALUE)svar)) return Qnil;
+ if (nd_type(svar) == NODE_CREF) return Qnil;
switch (key) {
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)) {
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) {
@@ -245,28 +254,42 @@ vm_getspecial(rb_thread_t *th, VALUE *lep, rb_num_t key, rb_num_t type)
}
static NODE *
-vm_get_cref0(const rb_iseq_t *iseq, const VALUE *ep)
+ep_cref(const VALUE *ep)
{
- while (1) {
- if (VM_EP_LEP_P(ep)) {
- if (!RUBY_VM_NORMAL_ISEQ_P(iseq)) return NULL;
- return iseq->cref_stack;
- }
- else if (ep[-1] != Qnil) {
+ const VALUE svar = ep[-1];
+
+ if (!svar) {
+ return NULL;
+ }
+ 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];
}
ep = VM_EP_PREV_EP(ep);
}
+ return ep_cref(ep);
}
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) {
rb_bug("rb_vm_get_cref: unreachable");
}
+
return cref;
}
@@ -274,6 +297,7 @@ void
rb_vm_rewrite_cref_stack(NODE *node, VALUE old_klass, VALUE new_klass, NODE **new_cref_ptr)
{
NODE *new_node;
+
while (node) {
if (node->nd_clss == old_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 *
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 *cref = NEW_CREF(klass);
- cref->nd_refinements = Qnil;
- cref->nd_visi = noex;
+ NODE *prev_cref = NULL;
+ NODE *cref = NULL;
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) {
- RB_OBJ_WRITE(cref, &cref->nd_next, vm_get_cref0(cfp->iseq, cfp->ep));
+ else {
+ 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? */
if (cref->nd_next && cref->nd_next != (void *) 1 &&
!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
-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;
while (cref) {
@@ -331,9 +359,9 @@ vm_get_cbase(const rb_iseq_t *iseq, const VALUE *ep)
}
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;
while (cref) {
@@ -373,14 +401,13 @@ vm_get_iclass(rb_control_frame_t *cfp, VALUE klass)
}
static inline VALUE
-vm_get_ev_const(rb_thread_t *th, const rb_iseq_t *iseq,
- VALUE orig_klass, ID id, int is_defined)
+vm_get_ev_const(rb_thread_t *th, VALUE orig_klass, ID id, int is_defined)
{
VALUE val;
if (orig_klass == Qnil) {
/* 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;
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
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);
}
@@ -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;
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;
/* 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_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);
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;
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 *sp_orig, *sp;
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,
- 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);
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);
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);
@@ -1465,7 +1494,8 @@ vm_call_cfunc_push_frame(rb_thread_t *th)
th->passed_ci = 0;
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) {
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:
break;
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 refinement, defined_class;
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;
}
- 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->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,
self, defined_class,
- VM_ENVVAL_PREV_EP_PTR(block->ep), 0,
- th->cfp->sp, 1, th->passed_bmethod_me, 0);
+ VM_ENVVAL_PREV_EP_PTR(block->ep), NULL /* cref */,
+ 0, th->cfp->sp, 1, th->passed_bmethod_me, 0);
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,
block->self,
block->klass,
- VM_ENVVAL_PREV_EP_PTR(block->ep),
+ VM_ENVVAL_PREV_EP_PTR(block->ep), NULL /* cref */,
iseq->iseq_encoded + opt_pc,
rsp + arg_size,
iseq->local_size - arg_size, 0, iseq->stack_max);
diff --git a/vm_method.c b/vm_method.c
index 7dd2f4bff7..d5fe52404a 100644
--- a/vm_method.c
+++ b/vm_method.c
@@ -245,8 +245,7 @@ rb_add_refined_method_entry(VALUE refined_class, ID mid)
rb_clear_method_cache_by_class(refined_class);
}
else {
- rb_add_method(refined_class, mid, VM_METHOD_TYPE_REFINED, 0,
- NOEX_PUBLIC);
+ rb_add_method(refined_class, mid, VM_METHOD_TYPE_REFINED, 0, 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));
switch (old_def->type) {
case VM_METHOD_TYPE_ISEQ:
- iseq = old_def->body.iseq;
+ iseq = old_def->body.iseq_body.iseq;
break;
case VM_METHOD_TYPE_BMETHOD:
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) {
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;
case VM_METHOD_TYPE_IVAR:
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_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_control_frame_t *cfp;
int line;
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);
+
if (me->def && me->def->type == VM_METHOD_TYPE_REFINED) {
me->def->body.orig_me->def = def;
}
else {
me->def = def;
}
+
+ if (0 && cref) vm_cref_dump("rb_add_method0", cref);
+
def->type = type;
def->original_id = mid;
def->alias_count = 0;
+
switch (type) {
case VM_METHOD_TYPE_ISEQ: {
rb_iseq_t *iseq = (rb_iseq_t *)opts;
- *(rb_iseq_t **)&def->body.iseq = iseq;
- RB_OBJ_WRITTEN(klass, Qundef, iseq->self);
+ NODE *private_cref;
+
+ *(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;
}
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;
}
+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 *
method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *me,
rb_method_flag_t noex, VALUE defined_class)
{
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,
- defined_class);
+ rb_method_entry_t *newme = rb_method_entry_make(klass, mid, type, me->def, noex, defined_class);
method_added(klass, mid);
return newme;
}
@@ -1195,7 +1219,7 @@ rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_defini
}
switch (d1->type) {
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:
return
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);
switch (def->type) {
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:
hash = rb_hash_uint(hash, (st_index_t)def->body.cfunc.func);
return rb_hash_uint(hash, def->body.cfunc.argc);