summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bootstraptest/test_yjit.rb9
-rw-r--r--yjit/src/codegen.rs31
-rw-r--r--yjit/src/stats.rs1
3 files changed, 41 insertions, 0 deletions
diff --git a/bootstraptest/test_yjit.rb b/bootstraptest/test_yjit.rb
index b8e8e11eec..3df8b1058a 100644
--- a/bootstraptest/test_yjit.rb
+++ b/bootstraptest/test_yjit.rb
@@ -212,6 +212,15 @@ assert_equal 'Sub', %q{
call(Sub.new('o')).class
}
+# String#dup with FL_EXIVAR
+assert_equal '["str", "ivar"]', %q{
+ def str_dup(str) = str.dup
+ str = "str"
+ str.instance_variable_set(:@ivar, "ivar")
+ str = str_dup(str)
+ [str, str.instance_variable_get(:@ivar)]
+}
+
# test splat filling required and feeding rest
assert_equal '[0, 1, 2, [3, 4]]', %q{
public def lead_rest(a, b, *rest)
diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs
index 7d0a7a66d5..1c3b1fe0f8 100644
--- a/yjit/src/codegen.rs
+++ b/yjit/src/codegen.rs
@@ -6017,6 +6017,36 @@ fn jit_rb_str_to_s(
false
}
+fn jit_rb_str_dup(
+ _jit: &mut JITState,
+ asm: &mut Assembler,
+ _ci: *const rb_callinfo,
+ _cme: *const rb_callable_method_entry_t,
+ _block: Option<BlockHandler>,
+ _argc: i32,
+ known_recv_class: Option<VALUE>,
+) -> bool {
+ // We specialize only the BARE_STRING_P case. Otherwise it's not leaf.
+ if unsafe { known_recv_class != Some(rb_cString) } {
+ return false;
+ }
+ asm_comment!(asm, "String#dup");
+
+ // Check !FL_ANY_RAW(str, FL_EXIVAR), which is part of BARE_STRING_P.
+ let recv_opnd = asm.stack_pop(1);
+ let recv_opnd = asm.load(recv_opnd);
+ let flags_opnd = Opnd::mem(64, recv_opnd, RUBY_OFFSET_RBASIC_FLAGS);
+ asm.test(flags_opnd, Opnd::Imm(RUBY_FL_EXIVAR as i64));
+ asm.jnz(Target::side_exit(Counter::send_str_dup_exivar));
+
+ // Call rb_str_dup
+ let stack_ret = asm.stack_push(Type::CString);
+ let ret_opnd = asm.ccall(rb_str_dup as *const u8, vec![recv_opnd]);
+ asm.mov(stack_ret, ret_opnd);
+
+ true
+}
+
// Codegen for rb_str_empty_p()
fn jit_rb_str_empty_p(
_jit: &mut JITState,
@@ -10566,6 +10596,7 @@ pub fn yjit_reg_method_codegen_fns() {
reg_method_codegen(rb_cFloat, "*", jit_rb_float_mul);
reg_method_codegen(rb_cFloat, "/", jit_rb_float_div);
+ reg_method_codegen(rb_cString, "dup", jit_rb_str_dup);
reg_method_codegen(rb_cString, "empty?", jit_rb_str_empty_p);
reg_method_codegen(rb_cString, "to_s", jit_rb_str_to_s);
reg_method_codegen(rb_cString, "to_str", jit_rb_str_to_s);
diff --git a/yjit/src/stats.rs b/yjit/src/stats.rs
index 325d64487c..874a9e9b70 100644
--- a/yjit/src/stats.rs
+++ b/yjit/src/stats.rs
@@ -422,6 +422,7 @@ make_counters! {
send_optimized_block_arg,
send_pred_not_fixnum,
send_pred_underflow,
+ send_str_dup_exivar,
invokesuper_defined_class_mismatch,
invokesuper_forwarding,