diff --git a/vm_insnhelper.c b/vm_insnhelper.c index f4aeb7fc34..ca4cca4707 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -6939,6 +6939,12 @@ vm_opt_aset_with(VALUE recv, VALUE key, VALUE val) } } +VALUE +rb_vm_opt_aset_with(VALUE recv, VALUE key, VALUE value) +{ + return vm_opt_aset_with(recv, key, value); +} + static VALUE vm_opt_length(VALUE recv, int bop) { diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index b608f98462..7cc4aff473 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -3891,6 +3891,40 @@ fn gen_opt_aref( } } +fn gen_opt_aset_with( + jit: &mut JITState, + asm: &mut Assembler, +) -> Option { + // We might allocate or raise + jit_prepare_non_leaf_call(jit, asm); + + let key_opnd = Opnd::Value(jit.get_arg(0)); + let recv_opnd = asm.stack_opnd(1); + let value_opnd = asm.stack_opnd(0); + + extern "C" { + fn rb_vm_opt_aset_with(recv: VALUE, key: VALUE, value: VALUE) -> VALUE; + } + + let val_opnd = asm.ccall( + rb_vm_opt_aset_with as *const u8, + vec![ + recv_opnd, + key_opnd, + value_opnd, + ], + ); + asm.stack_pop(2); // Keep it on stack during GC + + asm.cmp(val_opnd, Qundef.into()); + asm.je(Target::side_exit(Counter::opt_aset_with_qundef)); + + let top = asm.stack_push(Type::Unknown); + asm.mov(top, val_opnd); + + return Some(KeepCompiling); +} + fn gen_opt_aset( jit: &mut JITState, asm: &mut Assembler, @@ -10753,6 +10787,7 @@ fn get_gen_fn(opcode: VALUE) -> Option { YARVINSN_opt_aref => Some(gen_opt_aref), YARVINSN_opt_aset => Some(gen_opt_aset), YARVINSN_opt_aref_with => Some(gen_opt_aref_with), + YARVINSN_opt_aset_with => Some(gen_opt_aset_with), YARVINSN_opt_mult => Some(gen_opt_mult), YARVINSN_opt_div => Some(gen_opt_div), YARVINSN_opt_ltlt => Some(gen_opt_ltlt), diff --git a/yjit/src/stats.rs b/yjit/src/stats.rs index 8cbf3ab317..ba84b7a549 100644 --- a/yjit/src/stats.rs +++ b/yjit/src/stats.rs @@ -520,6 +520,7 @@ make_counters! { opt_aset_not_hash, opt_aref_with_qundef, + opt_aset_with_qundef, opt_case_dispatch_megamorphic,