[前][次][番号順一覧][スレッド一覧]

ruby-changes:40598

From: ko1 <ko1@a...>
Date: Fri, 20 Nov 2015 09:20:02 +0900 (JST)
Subject: [ruby-changes:40598] ko1:r52677 (trunk): * vm.c (rb_vm_cref_replace_with_duplicated_cref): added.

ko1	2015-11-20 09:17:25 +0900 (Fri, 20 Nov 2015)

  New Revision: 52677

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=52677

  Log:
    * 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.

  Modified files:
    trunk/ChangeLog
    trunk/eval.c
    trunk/eval_intern.h
    trunk/test/ruby/test_refinement.rb
    trunk/vm.c
    trunk/vm_eval.c
    trunk/vm_insnhelper.c
Index: eval_intern.h
===================================================================
--- eval_intern.h	(revision 52676)
+++ eval_intern.h	(revision 52677)
@@ -274,6 +274,7 @@ NORETURN(void rb_raise_method_missing(rb https://github.com/ruby/ruby/blob/trunk/eval_intern.h#L274
 
 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);
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 52676)
+++ ChangeLog	(revision 52677)
@@ -1,3 +1,24 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Fri Nov 20 09:05:21 2015  Koichi Sasada  <ko1@a...>
+
+	* 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@8...>
 
 	* .gitattributes: new file for git users
Index: vm_eval.c
===================================================================
--- vm_eval.c	(revision 52676)
+++ vm_eval.c	(revision 52677)
@@ -1271,7 +1271,6 @@ eval_string_with_cref(VALUE self, VALUE https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L1271
     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 https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L1336
 
 	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);
Index: eval.c
===================================================================
--- eval.c	(revision 52676)
+++ eval.c	(revision 52677)
@@ -1284,7 +1284,6 @@ rb_mod_refine(VALUE module, VALUE klass) https://github.com/ruby/ruby/blob/trunk/eval.c#L1284
 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) https://github.com/ruby/ruby/blob/trunk/eval.c#L1293
     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) https://github.com/ruby/ruby/blob/trunk/eval.c#L1426
     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;
 }
 
Index: vm.c
===================================================================
--- vm.c	(revision 52676)
+++ vm.c	(revision 52677)
@@ -136,10 +136,17 @@ vm_cref_dup(const rb_cref_t *cref) https://github.com/ruby/ruby/blob/trunk/vm.c#L136
 {
     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) https://github.com/ruby/ruby/blob/trunk/vm.c#L1199
     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)
 {
Index: vm_insnhelper.c
===================================================================
--- vm_insnhelper.c	(revision 52676)
+++ vm_insnhelper.c	(revision 52677)
@@ -488,6 +488,58 @@ vm_env_cref_by_cref(const VALUE *ep) https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L488
 }
 
 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);
Index: test/ruby/test_refinement.rb
===================================================================
--- test/ruby/test_refinement.rb	(revision 52676)
+++ test/ruby/test_refinement.rb	(revision 52677)
@@ -1523,6 +1523,77 @@ class TestRefinement < Test::Unit::TestC https://github.com/ruby/ruby/blob/trunk/test/ruby/test_refinement.rb#L1523
     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)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]