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

ruby-changes:27549

From: nobu <ko1@a...>
Date: Tue, 5 Mar 2013 21:36:54 +0900 (JST)
Subject: [ruby-changes:27549] nobu:r39601 (trunk): class.c: check redefinition

nobu	2013-03-05 21:36:45 +0900 (Tue, 05 Mar 2013)

  New Revision: 39601

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

  Log:
    class.c: check redefinition
    
    * class.c (rb_prepend_module): check redefinition of built-in opimized
      methods.  [ruby-dev:47124] [Bug #7983]
    * vm.c (rb_vm_check_redefinition_by_prepend): ditto.

  Modified files:
    trunk/ChangeLog
    trunk/class.c
    trunk/test/ruby/test_module.rb
    trunk/vm.c

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 39600)
+++ ChangeLog	(revision 39601)
@@ -1,3 +1,10 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Tue Mar  5 21:36:43 2013  Nobuyoshi Nakada  <nobu@r...>
+
+	* class.c (rb_prepend_module): check redefinition of built-in opimized
+	  methods.  [ruby-dev:47124] [Bug #7983]
+
+	* vm.c (rb_vm_check_redefinition_by_prepend): ditto.
+
 Tue Mar  5 20:29:25 2013  Nobuyoshi Nakada  <nobu@r...>
 
 	* proc.c (mnew): revert r39224.  [ruby-core:53038] [Bug #7988]
Index: class.c
===================================================================
--- class.c	(revision 39600)
+++ class.c	(revision 39601)
@@ -790,6 +790,7 @@ move_refined_method(st_data_t key, st_da https://github.com/ruby/ruby/blob/trunk/class.c#L790
 void
 rb_prepend_module(VALUE klass, VALUE module)
 {
+    void rb_vm_check_redefinition_by_prepend(VALUE klass);
     VALUE origin;
     int changed = 0;
 
@@ -816,7 +817,10 @@ rb_prepend_module(VALUE klass, VALUE mod https://github.com/ruby/ruby/blob/trunk/class.c#L817
     changed = include_modules_at(klass, klass, module);
     if (changed < 0)
 	rb_raise(rb_eArgError, "cyclic prepend detected");
-    if (changed) rb_clear_cache();
+    if (changed) {
+	rb_clear_cache();
+	rb_vm_check_redefinition_by_prepend(klass);
+    }
 }
 
 /*
Index: vm.c
===================================================================
--- vm.c	(revision 39600)
+++ vm.c	(revision 39601)
@@ -972,28 +972,54 @@ rb_iter_break_value(VALUE val) https://github.com/ruby/ruby/blob/trunk/vm.c#L972
 
 static st_table *vm_opt_method_table = 0;
 
+static int
+vm_redefinition_check_flag(VALUE klass)
+{
+    if (klass == rb_cFixnum) return FIXNUM_REDEFINED_OP_FLAG;
+    if (klass == rb_cFloat)  return FLOAT_REDEFINED_OP_FLAG;
+    if (klass == rb_cString) return STRING_REDEFINED_OP_FLAG;
+    if (klass == rb_cArray)  return ARRAY_REDEFINED_OP_FLAG;
+    if (klass == rb_cHash)   return HASH_REDEFINED_OP_FLAG;
+    if (klass == rb_cBignum) return BIGNUM_REDEFINED_OP_FLAG;
+    if (klass == rb_cSymbol) return SYMBOL_REDEFINED_OP_FLAG;
+    if (klass == rb_cTime)   return TIME_REDEFINED_OP_FLAG;
+    return 0;
+}
+
 static void
 rb_vm_check_redefinition_opt_method(const rb_method_entry_t *me, VALUE klass)
 {
     st_data_t bop;
     if (!me->def || me->def->type == VM_METHOD_TYPE_CFUNC) {
 	if (st_lookup(vm_opt_method_table, (st_data_t)me, &bop)) {
-	    int flag = 0;
-
-	    if      (klass == rb_cFixnum) flag = FIXNUM_REDEFINED_OP_FLAG;
-	    else if (klass == rb_cFloat)  flag = FLOAT_REDEFINED_OP_FLAG;
-	    else if (klass == rb_cString) flag = STRING_REDEFINED_OP_FLAG;
-	    else if (klass == rb_cArray)  flag = ARRAY_REDEFINED_OP_FLAG;
-	    else if (klass == rb_cHash)   flag = HASH_REDEFINED_OP_FLAG;
-	    else if (klass == rb_cBignum) flag = BIGNUM_REDEFINED_OP_FLAG;
-	    else if (klass == rb_cSymbol) flag = SYMBOL_REDEFINED_OP_FLAG;
-	    else if (klass == rb_cTime)   flag = TIME_REDEFINED_OP_FLAG;
+	    int flag = vm_redefinition_check_flag(klass);
 
 	    ruby_vm_redefined_flag[bop] |= flag;
 	}
     }
 }
 
+static int
+check_redefined_method(st_data_t key, st_data_t value, st_data_t data)
+{
+    ID mid = (ID)key;
+    rb_method_entry_t *me = (rb_method_entry_t *)value;
+    VALUE klass = (VALUE)data;
+    rb_method_entry_t *newme = rb_method_entry(klass, mid, NULL);
+
+    if (newme != me)
+	rb_vm_check_redefinition_opt_method(me, me->klass);
+    return ST_CONTINUE;
+}
+
+void
+rb_vm_check_redefinition_by_prepend(VALUE klass)
+{
+    if (!vm_redefinition_check_flag(klass)) return;
+    st_foreach(RCLASS_M_TBL(RCLASS_ORIGIN(klass)), check_redefined_method,
+	       (st_data_t)klass);
+}
+
 static void
 add_opt_method(VALUE klass, ID mid, VALUE bop)
 {
Index: test/ruby/test_module.rb
===================================================================
--- test/ruby/test_module.rb	(revision 39600)
+++ test/ruby/test_module.rb	(revision 39601)
@@ -1475,6 +1475,20 @@ class TestModule < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_module.rb#L1475
     end
   end
 
+  def test_prepend_optmethod
+    bug7983 = '[ruby-dev:47124] [Bug #7983]'
+    assert_separately [], %{
+      module M
+        def /(other)
+          to_f / other
+        end
+      end
+      Fixnum.send(:prepend, M)
+      assert_equal(0.5, 1 / 2, "#{bug7983}")
+    }
+    assert_equal(0, 1 / 2)
+  end
+
   def test_class_variables
     m = Module.new
     m.class_variable_set(:@@foo, 1)

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

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