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/