diff options
author | Jeremy Evans <code@jeremyevans.net> | 2021-11-18 15:10:20 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-18 15:10:20 -0800 |
commit | b08dacfea39ad8da3f1fd7fdd0e4538cc892ec44 (patch) | |
tree | 0e3ab7e2f068ce840aaa4e3cbb46e2561a7c153e /numeric.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 <e@80x24.org> Co-authored-by: Alan Wu <XrXr@users.noreply.github.com> Co-authored-by: Yusuke Endoh <mame@ruby-lang.org> Co-authored-by: Koichi Sasada <ko1@atdot.net>
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/5002 Merged-By: jeremyevans <code@jeremyevans.net>
Diffstat (limited to 'numeric.c')
-rw-r--r-- | numeric.c | 33 |
1 files changed, 30 insertions, 3 deletions
@@ -35,6 +35,7 @@ #include "internal/numeric.h" #include "internal/object.h" #include "internal/rational.h" +#include "internal/string.h" #include "internal/util.h" #include "internal/variable.h" #include "ruby/encoding.h" @@ -3631,6 +3632,18 @@ rb_fix2str(VALUE x, int base) return rb_usascii_str_new(b, e - b); } +static VALUE rb_fix_to_s_static[10]; + +MJIT_FUNC_EXPORTED VALUE +rb_fix_to_s(VALUE x) +{ + long i = FIX2LONG(x); + if (i >= 0 && i < 10) { + return rb_fix_to_s_static[i]; + } + return rb_fix2str(x, 10); +} + /* * call-seq: * to_s(base = 10) -> string @@ -3652,8 +3665,8 @@ rb_fix2str(VALUE x, int base) * */ -static VALUE -int_to_s(int argc, VALUE *argv, VALUE x) +MJIT_FUNC_EXPORTED VALUE +rb_int_to_s(int argc, VALUE *argv, VALUE x) { int base; @@ -5949,7 +5962,7 @@ Init_Numeric(void) rb_define_singleton_method(rb_cInteger, "sqrt", rb_int_s_isqrt, 1); rb_define_singleton_method(rb_cInteger, "try_convert", int_s_try_convert, 1); - rb_define_method(rb_cInteger, "to_s", int_to_s, -1); + rb_define_method(rb_cInteger, "to_s", rb_int_to_s, -1); rb_define_alias(rb_cInteger, "inspect", "to_s"); rb_define_method(rb_cInteger, "allbits?", int_allbits_p, 1); rb_define_method(rb_cInteger, "anybits?", int_anybits_p, 1); @@ -5999,6 +6012,20 @@ Init_Numeric(void) rb_define_method(rb_cInteger, "digits", rb_int_digits, -1); + rb_fix_to_s_static[0] = rb_fstring_literal("0"); + rb_fix_to_s_static[1] = rb_fstring_literal("1"); + rb_fix_to_s_static[2] = rb_fstring_literal("2"); + rb_fix_to_s_static[3] = rb_fstring_literal("3"); + rb_fix_to_s_static[4] = rb_fstring_literal("4"); + rb_fix_to_s_static[5] = rb_fstring_literal("5"); + rb_fix_to_s_static[6] = rb_fstring_literal("6"); + rb_fix_to_s_static[7] = rb_fstring_literal("7"); + rb_fix_to_s_static[8] = rb_fstring_literal("8"); + rb_fix_to_s_static[9] = rb_fstring_literal("9"); + for(int i = 0; i < 10; i++) { + rb_gc_register_mark_object(rb_fix_to_s_static[i]); + } + /* An obsolete class, use Integer */ rb_define_const(rb_cObject, "Fixnum", rb_cInteger); rb_deprecate_constant(rb_cObject, "Fixnum"); |