ruby-changes:72818
From: Noah <ko1@a...>
Date: Fri, 5 Aug 2022 01:19:31 +0900 (JST)
Subject: [ruby-changes:72818] 1e7a2415a4 (master): YJIT: Allow str-concat arg to be any string subtype, not just rb_cString (#6205)
https://git.ruby-lang.org/ruby.git/commit/?id=1e7a2415a4 From 1e7a2415a4c69aa64c9c2a561197bf9cfc5a91f8 Mon Sep 17 00:00:00 2001 From: Noah Gibbs <noah.gibbs@s...> Date: Thu, 4 Aug 2022 17:19:14 +0100 Subject: YJIT: Allow str-concat arg to be any string subtype, not just rb_cString (#6205) Allow str-concat arg to be any string subtype, not just rb_cString --- yjit/src/codegen.rs | 69 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 49 insertions(+), 20 deletions(-) diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index 818e3fbb41..119477f505 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -1338,6 +1338,31 @@ fn guard_object_is_array( https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L1338 jne_ptr(cb, side_exit); } +fn guard_object_is_string( + cb: &mut CodeBlock, + object_reg: X86Opnd, + flags_reg: X86Opnd, + side_exit: CodePtr, +) { + add_comment(cb, "guard object is string"); + + // Pull out the type mask + mov( + cb, + flags_reg, + mem_opnd( + 8 * SIZEOF_VALUE as u8, + object_reg, + RUBY_OFFSET_RBASIC_FLAGS, + ), + ); + and(cb, flags_reg, uimm_opnd(RUBY_T_MASK as u64)); + + // Compare the result with T_STRING + cmp(cb, flags_reg, uimm_opnd(RUBY_T_STRING as u64)); + jne_ptr(cb, side_exit); +} + // push enough nils onto the stack to fill out an array fn gen_expandarray( jit: &mut JITState, @@ -3730,7 +3755,7 @@ fn jit_rb_str_to_s( https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L3755 false } -// Codegen for rb_str_concat() +// Codegen for rb_str_concat() -- *not* String#concat // Frequently strings are concatenated using "out_str << next_str". // This is common in Erb and similar templating languages. fn jit_rb_str_concat( @@ -3744,14 +3769,12 @@ fn jit_rb_str_concat( https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L3769 _argc: i32, _known_recv_class: *const VALUE, ) -> bool { + // The << operator can accept integer codepoints for characters + // as the argument. We only specially optimise string arguments. + // If the peeked-at compile time argument is something other than + // a string, assume it won't be a string later either. let comptime_arg = jit_peek_at_stack(jit, ctx, 0); - let comptime_arg_type = ctx.get_opnd_type(StackOpnd(0)); - - // String#<< can take an integer codepoint as an argument, but we don't optimise that. - // Also, a non-string argument would have to call .to_str on itself before being treated - // as a string, and that would require saving pc/sp, which we don't do here. - // TODO: figure out how we should optimise a string-subtype argument here - if comptime_arg_type != Type::CString && comptime_arg.class_of() != unsafe { rb_cString } { + if ! unsafe { RB_TYPE_P(comptime_arg, RUBY_T_STRING) } { return false; } @@ -3759,19 +3782,25 @@ fn jit_rb_str_concat( https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L3782 let side_exit = get_side_exit(jit, ocb, ctx); // Guard that the argument is of class String at runtime. + let insn_opnd = StackOpnd(0); let arg_opnd = ctx.stack_opnd(0); mov(cb, REG0, arg_opnd); - jit_guard_known_klass( - jit, - ctx, - cb, - ocb, - unsafe { rb_cString }, - StackOpnd(0), - comptime_arg, - SEND_MAX_DEPTH, - side_exit, - ); + let arg_type = ctx.get_opnd_type(insn_opnd); + + if arg_type != Type::CString && arg_type != Type::TString { + if !arg_type.is_heap() { + add_comment(cb, "guard arg not immediate"); + test(cb, REG0, imm_opnd(RUBY_IMMEDIATE_MASK as i64)); + jnz_ptr(cb, side_exit); + cmp(cb, REG0, imm_opnd(Qnil.into())); + jbe_ptr(cb, side_exit); + + ctx.upgrade_opnd_type(insn_opnd, Type::UnknownHeap); + } + guard_object_is_string(cb, REG0, REG1, side_exit); + // We know this has type T_STRING, but not necessarily that it's a ::String + ctx.upgrade_opnd_type(insn_opnd, Type::TString); + } let concat_arg = ctx.stack_pop(1); let recv = ctx.stack_pop(1); @@ -3794,7 +3823,7 @@ fn jit_rb_str_concat( https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L3823 test(cb, REG0, uimm_opnd(RUBY_ENCODING_MASK as u64)); let enc_mismatch = cb.new_label("enc_mismatch".to_string()); - jne_label(cb, enc_mismatch); + jnz_label(cb, enc_mismatch); // If encodings match, call the simple append function and jump to return call_ptr(cb, REG0, rb_yjit_str_simple_append as *const u8); -- cgit v1.2.1 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/