* 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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@52677 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
895b44dcf6
commit
c267d24ef0
21
ChangeLog
21
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>
|
Fri Nov 20 06:52:53 2015 Eric Wong <e@80x24.org>
|
||||||
|
|
||||||
* .gitattributes: new file for git users
|
* .gitattributes: new file for git users
|
||||||
|
5
eval.c
5
eval.c
@ -1284,7 +1284,6 @@ rb_mod_refine(VALUE module, VALUE klass)
|
|||||||
static VALUE
|
static VALUE
|
||||||
mod_using(VALUE self, VALUE module)
|
mod_using(VALUE self, VALUE module)
|
||||||
{
|
{
|
||||||
const rb_cref_t *cref = rb_vm_cref();
|
|
||||||
rb_control_frame_t *prev_cfp = previous_frame(GET_THREAD());
|
rb_control_frame_t *prev_cfp = previous_frame(GET_THREAD());
|
||||||
|
|
||||||
if (prev_frame_func()) {
|
if (prev_frame_func()) {
|
||||||
@ -1294,7 +1293,7 @@ mod_using(VALUE self, VALUE module)
|
|||||||
if (prev_cfp && prev_cfp->self != self) {
|
if (prev_cfp && prev_cfp->self != self) {
|
||||||
rb_raise(rb_eRuntimeError, "Module#using is not called on 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;
|
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))) {
|
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_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;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
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(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);
|
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_vm_set_progname(VALUE filename);
|
||||||
void rb_thread_terminate_all(void);
|
void rb_thread_terminate_all(void);
|
||||||
|
@ -1523,6 +1523,77 @@ class TestRefinement < Test::Unit::TestCase
|
|||||||
end;
|
end;
|
||||||
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
|
private
|
||||||
|
|
||||||
def eval_using(mod, s)
|
def eval_using(mod, s)
|
||||||
|
20
vm.c
20
vm.c
@ -136,10 +136,17 @@ vm_cref_dup(const rb_cref_t *cref)
|
|||||||
{
|
{
|
||||||
VALUE klass = CREF_CLASS(cref);
|
VALUE klass = CREF_CLASS(cref);
|
||||||
const rb_scope_visibility_t *visi = CREF_SCOPE_VISI(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);
|
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 *
|
static rb_cref_t *
|
||||||
@ -1192,6 +1199,15 @@ rb_vm_cref(void)
|
|||||||
return rb_vm_get_cref(cfp->ep);
|
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 *
|
const rb_cref_t *
|
||||||
rb_vm_cref_in_context(VALUE self, VALUE cbase)
|
rb_vm_cref_in_context(VALUE self, VALUE cbase)
|
||||||
{
|
{
|
||||||
|
@ -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;
|
rb_block_t block, *base_block;
|
||||||
volatile int parse_in_eval;
|
volatile int parse_in_eval;
|
||||||
volatile int mild_compile_error;
|
volatile int mild_compile_error;
|
||||||
rb_cref_t *orig_cref;
|
|
||||||
volatile VALUE file;
|
volatile VALUE file;
|
||||||
volatile int line;
|
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 (!cref && base_block->iseq) {
|
||||||
if (NIL_P(scope)) {
|
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);
|
cref = vm_cref_dup(orig_cref);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
cref = rb_vm_get_cref(base_block->ep);
|
cref = NULL; /* use stacked CREF */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vm_set_eval_stack(th, iseq, cref, base_block);
|
vm_set_eval_stack(th, iseq, cref, base_block);
|
||||||
|
@ -487,6 +487,58 @@ vm_env_cref_by_cref(const VALUE *ep)
|
|||||||
return is_cref(ep[-1], TRUE);
|
return is_cref(ep[-1], TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 *
|
static rb_cref_t *
|
||||||
rb_vm_get_cref(const VALUE *ep)
|
rb_vm_get_cref(const VALUE *ep)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user