mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	* 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
					
				
					 7 changed files with 167 additions and 8 deletions
				
			
		
							
								
								
									
										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>
 | 
			
		||||
 | 
			
		||||
	* .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
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										20
									
								
								vm.c
									
										
									
									
									
								
							
							
						
						
									
										20
									
								
								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)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -487,6 +487,58 @@ vm_env_cref_by_cref(const VALUE *ep)
 | 
			
		|||
    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 *
 | 
			
		||||
rb_vm_get_cref(const VALUE *ep)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue