summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog21
-rw-r--r--eval.c5
-rw-r--r--eval_intern.h1
-rw-r--r--test/ruby/test_refinement.rb71
-rw-r--r--vm.c20
-rw-r--r--vm_eval.c5
-rw-r--r--vm_insnhelper.c52
7 files changed, 167 insertions, 8 deletions
diff --git a/ChangeLog b/ChangeLog
index ce4ce44944..6ceec5c932 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+Fri Nov 20 09:05:21 2015 Koichi Sasada <ko1@atdot.net>
+
+ * vm.c (rb_vm_cref_replace_with_duplicated_cref): added.
+
+ CREFs should not be shared by methods between `using'.
+ [Bug #11247]
+
+ * vm_insnhelper.c (vm_cref_replace_with_duplicated_cref): ditto.
+
+ * vm.c (vm_cref_dup): should copy refinements correctly.
+
+ * eval.c: use rb_vm_cref_replace_with_duplicated_cref().
+
+ * eval_intern.h: add a decl. of
+ rb_vm_cref_replace_with_duplicated_cref().
+
+ * vm_eval.c (eval_string_with_cref): do not need to pass
+ scope's CREF because VM can find out CREF from stack frames.
+
+ * test/ruby/test_refinement.rb: add a test.
+
Fri Nov 20 06:52:53 2015 Eric Wong <e@80x24.org>
* .gitattributes: new file for git users
diff --git a/eval.c b/eval.c
index cd1f78047c..f87be390f6 100644
--- a/eval.c
+++ b/eval.c
@@ -1284,7 +1284,6 @@ rb_mod_refine(VALUE module, VALUE klass)
static VALUE
mod_using(VALUE self, VALUE module)
{
- const rb_cref_t *cref = rb_vm_cref();
rb_control_frame_t *prev_cfp = previous_frame(GET_THREAD());
if (prev_frame_func()) {
@@ -1294,7 +1293,7 @@ mod_using(VALUE self, VALUE module)
if (prev_cfp && prev_cfp->self != self) {
rb_raise(rb_eRuntimeError, "Module#using is not called on self");
}
- rb_using_module(cref, module);
+ rb_using_module(rb_vm_cref_replace_with_duplicated_cref(), module);
return self;
}
@@ -1427,7 +1426,7 @@ top_using(VALUE self, VALUE module)
if (CREF_NEXT(cref) || (prev_cfp && rb_vm_frame_method_entry(prev_cfp))) {
rb_raise(rb_eRuntimeError, "main.using is permitted only at toplevel");
}
- rb_using_module(cref, module);
+ rb_using_module(rb_vm_cref_replace_with_duplicated_cref(), module);
return self;
}
diff --git a/eval_intern.h b/eval_intern.h
index 5dbdf00a3a..9c2b8960dc 100644
--- a/eval_intern.h
+++ b/eval_intern.h
@@ -274,6 +274,7 @@ NORETURN(void rb_raise_method_missing(rb_thread_t *th, int argc, const VALUE *ar
VALUE rb_vm_make_jump_tag_but_local_jump(int state, VALUE val);
rb_cref_t *rb_vm_cref(void);
+rb_cref_t *rb_vm_cref_replace_with_duplicated_cref(void);
VALUE rb_vm_call_cfunc(VALUE recv, VALUE (*func)(VALUE), VALUE arg, const rb_block_t *blockptr, VALUE filename);
void rb_vm_set_progname(VALUE filename);
void rb_thread_terminate_all(void);
diff --git a/test/ruby/test_refinement.rb b/test/ruby/test_refinement.rb
index 43f58b1038..80407c01a2 100644
--- a/test/ruby/test_refinement.rb
+++ b/test/ruby/test_refinement.rb
@@ -1523,6 +1523,77 @@ class TestRefinement < Test::Unit::TestCase
end;
end
+ module MixedUsing1
+ class C
+ def foo
+ :orig_foo
+ end
+ end
+
+ module R1
+ refine C do
+ def foo
+ [:R1, super]
+ end
+ end
+ end
+
+ module_function
+
+ def foo
+ [:foo, C.new.foo]
+ end
+
+ using R1
+
+ def bar
+ [:bar, C.new.foo]
+ end
+ end
+
+ module MixedUsing2
+ class C
+ def foo
+ :orig_foo
+ end
+ end
+
+ module R1
+ refine C do
+ def foo
+ [:R1_foo, super]
+ end
+ end
+ end
+
+ module R2
+ refine C do
+ def bar
+ [:R2_bar, C.new.foo]
+ end
+
+ using R1
+
+ def baz
+ [:R2_baz, C.new.foo]
+ end
+ end
+ end
+
+ using R2
+ module_function
+ def f1; C.new.bar; end
+ def f2; C.new.baz; end
+ end
+
+ def test_mixed_using
+ assert_equal([:foo, :orig_foo], MixedUsing1.foo)
+ assert_equal([:bar, [:R1, :orig_foo]], MixedUsing1.bar)
+
+ assert_equal([:R2_bar, :orig_foo], MixedUsing2.f1)
+ assert_equal([:R2_baz, [:R1_foo, :orig_foo]], MixedUsing2.f2)
+ end
+
private
def eval_using(mod, s)
diff --git a/vm.c b/vm.c
index 929144d6a8..de8be50e72 100644
--- a/vm.c
+++ b/vm.c
@@ -136,10 +136,17 @@ vm_cref_dup(const rb_cref_t *cref)
{
VALUE klass = CREF_CLASS(cref);
const rb_scope_visibility_t *visi = CREF_SCOPE_VISI(cref);
- rb_cref_t *next_cref = CREF_NEXT(cref);
+ rb_cref_t *next_cref = CREF_NEXT(cref), *new_cref;
int pushed_by_eval = CREF_PUSHED_BY_EVAL(cref);
- return vm_cref_new(klass, visi->method_visi, visi->module_func, next_cref, pushed_by_eval);
+ new_cref = vm_cref_new(klass, visi->method_visi, visi->module_func, next_cref, pushed_by_eval);
+
+ if (!NIL_P(CREF_REFINEMENTS(cref))) {
+ CREF_REFINEMENTS_SET(new_cref, rb_hash_dup(CREF_REFINEMENTS(cref)));
+ CREF_OMOD_SHARED_UNSET(new_cref);
+ }
+
+ return new_cref;
}
static rb_cref_t *
@@ -1192,6 +1199,15 @@ rb_vm_cref(void)
return rb_vm_get_cref(cfp->ep);
}
+rb_cref_t *
+rb_vm_cref_replace_with_duplicated_cref(void)
+{
+ rb_thread_t *th = GET_THREAD();
+ rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp);
+ rb_cref_t *cref = vm_cref_replace_with_duplicated_cref(cfp->ep);
+ return cref;
+}
+
const rb_cref_t *
rb_vm_cref_in_context(VALUE self, VALUE cbase)
{
diff --git a/vm_eval.c b/vm_eval.c
index 1bc91f518f..d32cf1ba55 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -1271,7 +1271,6 @@ eval_string_with_cref(VALUE self, VALUE src, VALUE scope, rb_cref_t *const cref_
rb_block_t block, *base_block;
volatile int parse_in_eval;
volatile int mild_compile_error;
- rb_cref_t *orig_cref;
volatile VALUE file;
volatile int line;
@@ -1337,11 +1336,11 @@ eval_string_with_cref(VALUE self, VALUE src, VALUE scope, rb_cref_t *const cref_
if (!cref && base_block->iseq) {
if (NIL_P(scope)) {
- orig_cref = rb_vm_get_cref(base_block->ep);
+ rb_cref_t *orig_cref = rb_vm_get_cref(base_block->ep);
cref = vm_cref_dup(orig_cref);
}
else {
- cref = rb_vm_get_cref(base_block->ep);
+ cref = NULL; /* use stacked CREF */
}
}
vm_set_eval_stack(th, iseq, cref, base_block);
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 3b89b3a695..033edea5fd 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -488,6 +488,58 @@ vm_env_cref_by_cref(const VALUE *ep)
}
static rb_cref_t *
+cref_replace_with_duplicated_cref_each_frame(VALUE *vptr, int can_be_svar, VALUE parent)
+{
+ const VALUE v = *vptr;
+ rb_cref_t *cref, *new_cref;
+
+ if (RB_TYPE_P(v, T_IMEMO)) {
+ switch (imemo_type(v)) {
+ case imemo_cref:
+ cref = (rb_cref_t *)v;
+ new_cref = vm_cref_dup(cref);
+ if (parent) {
+ /* this pointer is in svar */
+ RB_OBJ_WRITE(parent, vptr, new_cref);
+ }
+ else {
+ *vptr = (VALUE)new_cref;
+ }
+ return (rb_cref_t *)new_cref;
+ case imemo_svar:
+ if (can_be_svar) {
+ return cref_replace_with_duplicated_cref_each_frame((VALUE *)&((struct vm_svar *)v)->cref_or_me, FALSE, v);
+ }
+ case imemo_ment:
+ rb_bug("cref_replace_with_duplicated_cref_each_frame: unreachable");
+ default:
+ break;
+ }
+ }
+ return FALSE;
+}
+
+static rb_cref_t *
+vm_cref_replace_with_duplicated_cref(const VALUE *ep)
+{
+ if (vm_env_cref_by_cref(ep)) {
+ rb_cref_t *cref;
+
+ while (!VM_EP_LEP_P(ep)) {
+ if ((cref = cref_replace_with_duplicated_cref_each_frame((VALUE *)&ep[-1], FALSE, Qfalse)) != NULL) {
+ return cref;
+ }
+ ep = VM_EP_PREV_EP(ep);
+ }
+ return cref_replace_with_duplicated_cref_each_frame((VALUE *)&ep[-1], TRUE, Qfalse);
+ }
+ else {
+ rb_bug("vm_cref_dup: unreachable");
+ }
+}
+
+
+static rb_cref_t *
rb_vm_get_cref(const VALUE *ep)
{
rb_cref_t *cref = vm_env_cref(ep);