Feature #13715 ยป 0001-avoid-garbage-from-Symbol-to_s-in-interpolation.patch
| benchmark/bm_vm2_dstr_digit.rb | ||
|---|---|---|
| i = 0 | ||
| x = 0 | ||
| y = 9 | ||
| while i<6_000_000 # benchmark loop 2 | ||
|   i += 1 | ||
|   str = "foo#{x}bar#{y}baz" | ||
| end | ||
| benchmark/bm_vm2_dstr_int.rb | ||
|---|---|---|
| i = 0 | ||
| while i<6_000_000 # benchmark loop 2 | ||
|   i += 1 | ||
|   str = "foo#{i}bar#{i}baz" | ||
| end | ||
| benchmark/bm_vm2_dstr_nil.rb | ||
|---|---|---|
| i = 0 | ||
| x = y = nil | ||
| while i<6_000_000 # benchmark loop 2 | ||
|   i += 1 | ||
|   str = "foo#{x}bar#{y}baz" | ||
| end | ||
| benchmark/bm_vm2_dstr_sym.rb | ||
|---|---|---|
| i = 0 | ||
| x = y = :z | ||
| while i<6_000_000 # benchmark loop 2 | ||
|   i += 1 | ||
|   str = "foo#{x}bar#{y}baz" | ||
| end | ||
| compile.c | ||
|---|---|---|
| 	    ADD_INSN(ret, line, pop); | ||
| 	} | ||
| 	else { | ||
| 	    ADD_INSN(ret, line, tostring); | ||
| 	    ADD_INSN2(ret, line, tostring, | ||
| 		      new_callinfo(iseq, idTo_s, 0, 0, NULL, FALSE), | ||
| 		      NULL/* CALL_CACHE */); | ||
| 	} | ||
| 	break; | ||
|       } | ||
| insns.def | ||
|---|---|---|
|  */ | ||
| DEFINE_INSN | ||
| tostring | ||
| () | ||
| (CALL_INFO ci, CALL_CACHE cc) | ||
| (VALUE val) | ||
| (VALUE val) | ||
| { | ||
|     val = rb_obj_as_string(val); | ||
|     val = vm_tostring(th, val, ci, cc); | ||
| } | ||
| /** | ||
| test/ruby/test_optimization.rb | ||
|---|---|---|
|       def t; if false; case 42; when s {}; end; end; end | ||
|     end; | ||
|   end | ||
|   def test_tostring | ||
|     before = GC.stat(:total_allocated_objects) | ||
|     3.times { "x #{:total_allocated_objects}" } | ||
|     assert_equal before + 3, GC.stat(:total_allocated_objects) | ||
|     s = :total_allocated_objects | ||
|     assert_equal 'total_allocated_objects!', "#{s}" << '!', 'result mutable' | ||
|     assert_redefine_method('Symbol', 'to_s', <<-'end') | ||
|       assert_match %r{\A#<Symbol:0x[0-9a-f]+>\z}, "#{:foo}" | ||
|     end | ||
|   end | ||
| end | ||
| vm_eval.c | ||
|---|---|---|
|     return vm_call0_cfunc_with_frame(th, calling, ci, cc, argv); | ||
| } | ||
| VALUE | ||
| rb_vm_call0_body(rb_thread_t *th, struct rb_calling_info *calling, | ||
| 		const struct rb_call_info *ci, struct rb_call_cache *cc, | ||
| 		const VALUE *argv) | ||
| { | ||
|     return vm_call0_body(th, calling, ci, cc, argv); | ||
| } | ||
| /* `ci' should point temporal value (on stack value) */ | ||
| static VALUE | ||
| vm_call0_body(rb_thread_t* th, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc, const VALUE *argv) | ||
| vm_insnhelper.c | ||
|---|---|---|
|     } | ||
| } | ||
| /* vm_eval.c */ | ||
| VALUE rb_vm_call0_body(rb_thread_t *, struct rb_calling_info *, | ||
| 			const struct rb_call_info *, struct rb_call_cache *, | ||
| 			const VALUE *argv); | ||
| static VALUE | ||
| vm_tostring(rb_thread_t *th, VALUE recv, CALL_INFO ci, CALL_CACHE cc) | ||
| { | ||
|     struct rb_calling_info calling; | ||
|     VALUE val; | ||
|     if (RB_TYPE_P(recv, T_STRING)) { | ||
| 	return recv; | ||
|     } | ||
|     if (RB_TYPE_P(recv, T_SYMBOL)) { | ||
| 	vm_search_method(ci, cc, recv); | ||
| 	if (check_cfunc(cc->me, rb_sym_to_s)) { | ||
| 	    return rb_sym2str(recv); | ||
| 	} | ||
|     /* TODO: digits (0-9), maybe true/false/nil... */ | ||
|     } | ||
|     else { | ||
| 	vm_search_method(ci, cc, recv); | ||
|     } | ||
|     calling.block_handler = VM_BLOCK_HANDLER_NONE; | ||
|     calling.argc = 0; | ||
|     calling.recv = recv; | ||
|     val = rb_vm_call0_body(th, &calling, ci, cc, 0); | ||
|     return RB_TYPE_P(val, T_STRING) ? val : rb_any_to_s(recv); | ||
| } | ||
| static void | ||
| vm_freezestring(VALUE str, VALUE debug) | ||
| { | ||
| -  | ||