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

ruby-changes:36783

From: nobu <ko1@a...>
Date: Tue, 16 Dec 2014 15:18:40 +0900 (JST)
Subject: [ruby-changes:36783] nobu:r48864 (trunk): iseq.c: struct accessors

nobu	2014-12-16 15:18:25 +0900 (Tue, 16 Dec 2014)

  New Revision: 48864

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

  Log:
    iseq.c: struct accessors
    
    * iseq.c (rb_method_for_self_aref, rb_method_for_self_aset): call
      accessor functions directly, not to be affected by [] and []=
      methods.  [ruby-core:66846] [Bug #10601]
    * struct.c (define_aref_method, define_aset_method): ditto.
    * vm_insnhelper.c (rb_vm_opt_struct_aref, rb_vm_opt_struct_aset):
      direct accessors of Struct.

  Modified files:
    trunk/ChangeLog
    trunk/iseq.c
    trunk/struct.c
    trunk/test/ruby/test_struct.rb
    trunk/vm_insnhelper.c
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 48863)
+++ ChangeLog	(revision 48864)
@@ -1,3 +1,14 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Tue Dec 16 15:18:23 2014  Nobuyoshi Nakada  <nobu@r...>
+
+	* iseq.c (rb_method_for_self_aref, rb_method_for_self_aset): call
+	  accessor functions directly, not to be affected by [] and []=
+	  methods.  [ruby-core:66846] [Bug #10601]
+
+	* struct.c (define_aref_method, define_aset_method): ditto.
+
+	* vm_insnhelper.c (rb_vm_opt_struct_aref, rb_vm_opt_struct_aset):
+	  direct accessors of Struct.
+
 Tue Dec 16 12:01:29 2014  Koichi Sasada  <ko1@a...>
 
 	* test/ruby/test_process.rb (test_deadlock_by_signal_at_forking):
Index: iseq.c
===================================================================
--- iseq.c	(revision 48863)
+++ iseq.c	(revision 48864)
@@ -569,14 +569,14 @@ caller_location(VALUE *path) https://github.com/ruby/ruby/blob/trunk/iseq.c#L569
 }
 
 VALUE
-rb_method_for_self_aref(VALUE name, VALUE arg)
+rb_method_for_self_aref(VALUE name, VALUE arg, rb_insn_func_t func)
 {
+    rb_control_frame_t *FUNC_FASTCALL(rb_vm_struct_aref_c)(rb_thread_t *, rb_control_frame_t *);
     VALUE iseqval = iseq_alloc(rb_cISeq);
     rb_iseq_t *iseq;
     VALUE path, lineno = caller_location(&path);
     VALUE parent = 0;
     VALUE misc, locals, params, exception, body, send_arg;
-    int flag = VM_CALL_FCALL | VM_CALL_ARGS_SIMPLE;
 
     GetISeqPtr(iseqval, iseq);
     iseq->self = iseqval;
@@ -593,18 +593,15 @@ rb_method_for_self_aref(VALUE name, VALU https://github.com/ruby/ruby/blob/trunk/iseq.c#L593
 #define ADD(a) rb_ary_push(body, rb_obj_hide(a))
     /* def name; self[arg]; end */
     ADD(lineno);
-    ADD(rb_ary_new3(1, S(putself)));
     ADD(rb_ary_new3(2, S(putobject), arg));
 
-    /* {:mid=>:[], :flag=>264, :blockptr=>nil, :orig_argc=>1} */
-    send_arg = rb_hash_new();
-    rb_hash_aset(send_arg, S(mid), ID2SYM(idAREF));
-    rb_hash_aset(send_arg, S(flag), INT2FIX(flag));
-    rb_hash_aset(send_arg, S(blockptr), Qnil);
-    rb_hash_aset(send_arg, S(orig_argc), INT2FIX(1));
-
-    /* we do not want opt_aref for struct */
-    ADD(rb_ary_new3(2, S(opt_send_without_block), send_arg));
+#if SIZEOF_VALUE <= SIZEOF_LONG
+    send_arg = LONG2NUM((SIGNED_VALUE)func);
+#else
+    send_arg = LL2NUM((SIGNED_VALUE)func);
+#endif
+    send_arg = rb_ary_new3(2, S(opt_call_c_function), send_arg);
+    ADD(send_arg);
     ADD(rb_ary_new3(1, S(leave)));
 #undef S
 #undef ADD
@@ -613,19 +610,19 @@ rb_method_for_self_aref(VALUE name, VALU https://github.com/ruby/ruby/blob/trunk/iseq.c#L610
     cleanup_iseq_build(iseq);
 
     rb_ary_clear(body);
+    rb_ary_clear(send_arg);
 
     return iseqval;
 }
 
 VALUE
-rb_method_for_self_aset(VALUE name, VALUE arg)
+rb_method_for_self_aset(VALUE name, VALUE arg, rb_insn_func_t func)
 {
     VALUE iseqval = iseq_alloc(rb_cISeq);
     rb_iseq_t *iseq;
     VALUE path, lineno = caller_location(&path);
     VALUE parent = 0;
     VALUE misc, locals, params, exception, body, send_arg;
-    int flag = VM_CALL_FCALL | VM_CALL_ARGS_SIMPLE;
 
     GetISeqPtr(iseqval, iseq);
     iseq->self = iseqval;
@@ -641,26 +638,21 @@ rb_method_for_self_aset(VALUE name, VALU https://github.com/ruby/ruby/blob/trunk/iseq.c#L638
     locals = rb_obj_hide(rb_ary_new3(1, S(val)));
     params = rb_hash_new();
     exception = rb_ary_tmp_new(0); /* empty */
-    body = rb_ary_tmp_new(9);
+    body = rb_ary_tmp_new(6);
 
     rb_hash_aset(params, S(lead_num), INT2FIX(1));
 
     ADD(lineno);
-    ADD(rb_ary_new3(1, S(putnil)));
-    ADD(rb_ary_new3(1, S(putself)));
-    ADD(rb_ary_new3(2, S(putobject), arg));
     ADD(rb_ary_new3(3, S(getlocal), INT2FIX(2), INT2FIX(0)));
-    ADD(rb_ary_new3(2, S(setn), INT2FIX(3)));
-
-    /* {:mid=>:[]=, :flag=>264, :blockptr=>nil, :orig_argc=>2} */
-    send_arg = rb_hash_new();
-    rb_hash_aset(send_arg, S(mid), ID2SYM(idASET));
-    rb_hash_aset(send_arg, S(flag), INT2FIX(flag));
-    rb_hash_aset(send_arg, S(blockptr), Qnil);
-    rb_hash_aset(send_arg, S(orig_argc), INT2FIX(2));
+    ADD(rb_ary_new3(2, S(putobject), arg));
 
-    /* we do not want opt_aset for struct */
-    ADD(rb_ary_new3(2, S(opt_send_without_block), send_arg));
+#if SIZEOF_VALUE <= SIZEOF_LONG
+    send_arg = LONG2NUM((SIGNED_VALUE)func);
+#else
+    send_arg = LL2NUM((SIGNED_VALUE)func);
+#endif
+    send_arg = rb_ary_new3(2, S(opt_call_c_function), send_arg);
+    ADD(send_arg);
 
     ADD(rb_ary_new3(1, S(pop)));
     ADD(rb_ary_new3(1, S(leave)));
@@ -671,6 +663,7 @@ rb_method_for_self_aset(VALUE name, VALU https://github.com/ruby/ruby/blob/trunk/iseq.c#L663
     cleanup_iseq_build(iseq);
 
     rb_ary_clear(body);
+    rb_ary_clear(send_arg);
 
     return iseqval;
 }
Index: struct.c
===================================================================
--- struct.c	(revision 48863)
+++ struct.c	(revision 48864)
@@ -13,8 +13,8 @@ https://github.com/ruby/ruby/blob/trunk/struct.c#L13
 #include "vm_core.h"
 #include "method.h"
 
-VALUE rb_method_for_self_aref(VALUE name, VALUE arg);
-VALUE rb_method_for_self_aset(VALUE name, VALUE arg);
+VALUE rb_method_for_self_aref(VALUE name, VALUE arg, rb_insn_func_t func);
+VALUE rb_method_for_self_aset(VALUE name, VALUE arg, rb_insn_func_t func);
 
 VALUE rb_cStruct;
 static ID id_members;
@@ -175,7 +175,8 @@ new_struct(VALUE name, VALUE super) https://github.com/ruby/ruby/blob/trunk/struct.c#L175
 static void
 define_aref_method(VALUE nstr, VALUE name, VALUE off)
 {
-    VALUE iseqval = rb_method_for_self_aref(name, off);
+    rb_control_frame_t *FUNC_FASTCALL(rb_vm_opt_struct_aref)(rb_thread_t *, rb_control_frame_t *);
+    VALUE iseqval = rb_method_for_self_aref(name, off, rb_vm_opt_struct_aref);
     rb_iseq_t *iseq = DATA_PTR(iseqval);
 
     rb_add_method(nstr, SYM2ID(name), VM_METHOD_TYPE_ISEQ, iseq, NOEX_PUBLIC);
@@ -185,7 +186,8 @@ define_aref_method(VALUE nstr, VALUE nam https://github.com/ruby/ruby/blob/trunk/struct.c#L186
 static void
 define_aset_method(VALUE nstr, VALUE name, VALUE off)
 {
-    VALUE iseqval = rb_method_for_self_aset(name, off);
+    rb_control_frame_t *FUNC_FASTCALL(rb_vm_opt_struct_aset)(rb_thread_t *, rb_control_frame_t *);
+    VALUE iseqval = rb_method_for_self_aset(name, off, rb_vm_opt_struct_aset);
     rb_iseq_t *iseq = DATA_PTR(iseqval);
 
     rb_add_method(nstr, SYM2ID(name), VM_METHOD_TYPE_ISEQ, iseq, NOEX_PUBLIC);
Index: vm_insnhelper.c
===================================================================
--- vm_insnhelper.c	(revision 48863)
+++ vm_insnhelper.c	(revision 48864)
@@ -2107,3 +2107,16 @@ vm_once_clear(VALUE data) https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L2107
     return Qnil;
 }
 
+rb_control_frame_t *
+FUNC_FASTCALL(rb_vm_opt_struct_aref)(rb_thread_t *th, rb_control_frame_t *reg_cfp)
+{
+    TOPN(0) = rb_struct_aref(GET_SELF(), TOPN(0));
+    return reg_cfp;
+}
+
+rb_control_frame_t *
+FUNC_FASTCALL(rb_vm_opt_struct_aset)(rb_thread_t *th, rb_control_frame_t *reg_cfp)
+{
+    rb_struct_aset(GET_SELF(), TOPN(0), TOPN(1));
+    return reg_cfp;
+}
Index: test/ruby/test_struct.rb
===================================================================
--- test/ruby/test_struct.rb	(revision 48863)
+++ test/ruby/test_struct.rb	(revision 48864)
@@ -195,6 +195,39 @@ module TestStruct https://github.com/ruby/ruby/blob/trunk/test/ruby/test_struct.rb#L195
     assert_equal(:foo, o[25])
   end
 
+  def test_overridden_aset
+    bug10601 = '[ruby-core:66846] [Bug #10601]: should not be affected by []= method'
+
+    struct = Class.new(Struct.new(*(:a..:z), :result)) do
+      def []=(*args)
+        raise args.inspect
+      end
+    end
+
+    obj = struct.new
+    assert_nothing_raised(RuntimeError, bug10601) do
+      obj.result = 42
+    end
+    assert_equal(42, obj.result, bug10601)
+  end
+
+  def test_overridden_aref
+    bug10601 = '[ruby-core:66846] [Bug #10601]: should not be affected by [] method'
+
+    struct = Class.new(Struct.new(*(:a..:z), :result)) do
+      def [](*args)
+        raise args.inspect
+      end
+    end
+
+    obj = struct.new
+    obj.result = 42
+    result = assert_nothing_raised(RuntimeError, bug10601) do
+      break obj.result
+    end
+    assert_equal(42, result, bug10601)
+  end
+
   def test_equal
     klass1 = @Struct.new(:a)
     klass2 = @Struct.new(:a, :b)

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

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