diff options
author | Jeremy Evans <[email protected]> | 2021-11-18 15:10:20 -0800 |
---|---|---|
committer | GitHub <[email protected]> | 2021-11-18 15:10:20 -0800 |
commit | b08dacfea39ad8da3f1fd7fdd0e4538cc892ec44 (patch) | |
tree | 0e3ab7e2f068ce840aaa4e3cbb46e2561a7c153e /compile.c | |
parent | 4adb012926f8bd6011168327d8832cf19976de40 (diff) |
Optimize dynamic string interpolation for symbol/true/false/nil/0-9
This provides a significant speedup for symbol, true, false,
nil, and 0-9, class/module, and a small speedup in most other cases.
Speedups (using included benchmarks):
:symbol :: 60%
0-9 :: 50%
Class/Module :: 50%
nil/true/false :: 20%
integer :: 10%
[] :: 10%
"" :: 3%
One reason this approach is faster is it reduces the number of
VM instructions for each interpolated value.
Initial idea, approach, and benchmarks from Eric Wong. I applied
the same approach against the master branch, updating it to handle
the significant internal changes since this was first proposed 4
years ago (such as CALL_INFO/CALL_CACHE -> CALL_DATA). I also
expanded it to optimize true/false/nil/0-9/class/module, and added
handling of missing methods, refined methods, and RUBY_DEBUG.
This renames the tostring insn to anytostring, and adds an
objtostring insn that implements the optimization. This requires
making a few functions non-static, and adding some non-static
functions.
This disables 4 YJIT tests. Those tests should be reenabled after
YJIT optimizes the new objtostring insn.
Implements [Feature #13715]
Co-authored-by: Eric Wong <[email protected]>
Co-authored-by: Alan Wu <[email protected]>
Co-authored-by: Yusuke Endoh <[email protected]>
Co-authored-by: Koichi Sasada <[email protected]>
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/5002
Merged-By: jeremyevans <[email protected]>
Diffstat (limited to 'compile.c')
-rw-r--r-- | compile.c | 21 |
1 files changed, 9 insertions, 12 deletions
@@ -3271,13 +3271,13 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal } } - if (IS_INSN_ID(iobj, tostring)) { + if (IS_INSN_ID(iobj, anytostring)) { LINK_ELEMENT *next = iobj->link.next; /* - * tostring + * anytostring * concatstrings 1 * => - * tostring + * anytostring */ if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) && OPERAND_AT(next, 0) == INT2FIX(1)) { @@ -7642,17 +7642,14 @@ compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i CHECK(COMPILE_(ret, "nd_body", node, popped)); if (!popped && !all_string_result_p(node)) { - const int line = nd_line(node); const NODE *line_node = node; const unsigned int flag = VM_CALL_FCALL; - LABEL *isstr = NEW_LABEL(line); - ADD_INSN(ret, line_node, dup); - ADD_INSN1(ret, line_node, checktype, INT2FIX(T_STRING)); - ADD_INSNL(ret, line_node, branchif, isstr); - ADD_INSN(ret, line_node, dup); - ADD_SEND_R(ret, line_node, idTo_s, INT2FIX(0), NULL, INT2FIX(flag), NULL); - ADD_INSN(ret, line_node, tostring); - ADD_LABEL(ret, isstr); + + // Note, this dup could be removed if we are willing to change anytostring. It pops + // two VALUEs off the stack when it could work by replacing the top most VALUE. + ADD_INSN(ret, line_node, dup); + ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE)); + ADD_INSN(ret, line_node, anytostring); } return COMPILE_OK; } |