summaryrefslogtreecommitdiff
path: root/vm_insnhelper.c
diff options
context:
space:
mode:
authorJeremy Evans <code@jeremyevans.net>2021-11-18 15:10:20 -0800
committerGitHub <noreply@github.com>2021-11-18 15:10:20 -0800
commitb08dacfea39ad8da3f1fd7fdd0e4538cc892ec44 (patch)
tree0e3ab7e2f068ce840aaa4e3cbb46e2561a7c153e /vm_insnhelper.c
parent4adb012926f8bd6011168327d8832cf19976de40 (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 'vm_insnhelper.c')
-rw-r--r--vm_insnhelper.c64
1 files changed, 64 insertions, 0 deletions
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 75809f7d86..9643bdd861 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -4729,6 +4729,70 @@ vm_sendish(
#endif
}
+/* object.c */
+VALUE rb_nil_to_s(VALUE);
+VALUE rb_true_to_s(VALUE);
+VALUE rb_false_to_s(VALUE);
+/* numeric.c */
+VALUE rb_int_to_s(int argc, VALUE *argv, VALUE x);
+VALUE rb_fix_to_s(VALUE);
+/* variable.c */
+VALUE rb_mod_to_s(VALUE);
+VALUE rb_mod_name(VALUE);
+
+static VALUE
+vm_objtostring(const rb_iseq_t *iseq, VALUE recv, CALL_DATA cd)
+{
+ const struct rb_callcache *cc = vm_search_method((VALUE)iseq, cd, recv);
+
+ switch (TYPE(recv)) {
+ case T_STRING:
+ return recv;
+ case T_SYMBOL:
+ if (check_cfunc(vm_cc_cme(cc), rb_sym_to_s)) {
+ // rb_sym_to_s() allocates a mutable string, but since we are only
+ // going to use this string for interpolation, it's fine to use the
+ // frozen string.
+ return rb_sym2str(recv);
+ }
+ break;
+ case T_MODULE:
+ case T_CLASS:
+ if (check_cfunc(vm_cc_cme(cc), rb_mod_to_s)) {
+ // rb_mod_to_s() allocates a mutable string, but since we are only
+ // going to use this string for interpolation, it's fine to use the
+ // frozen string.
+ VALUE val = rb_mod_name(recv);
+ if (val == Qnil) {
+ val = rb_mod_to_s(recv);
+ }
+ return val;
+ }
+ break;
+ case T_NIL:
+ if (check_cfunc(vm_cc_cme(cc), rb_nil_to_s)) {
+ return rb_nil_to_s(recv);
+ }
+ break;
+ case T_TRUE:
+ if (check_cfunc(vm_cc_cme(cc), rb_true_to_s)) {
+ return rb_true_to_s(recv);
+ }
+ break;
+ case T_FALSE:
+ if (check_cfunc(vm_cc_cme(cc), rb_false_to_s)) {
+ return rb_false_to_s(recv);
+ }
+ break;
+ case T_FIXNUM:
+ if (check_cfunc(vm_cc_cme(cc), rb_int_to_s)) {
+ return rb_fix_to_s(recv);
+ }
+ break;
+ }
+ return Qundef;
+}
+
static VALUE
vm_opt_str_freeze(VALUE str, int bop, ID id)
{