diff --git a/bootstraptest/test_yjit.rb b/bootstraptest/test_yjit.rb index a981ba150b..a13a8d6295 100644 --- a/bootstraptest/test_yjit.rb +++ b/bootstraptest/test_yjit.rb @@ -2521,6 +2521,18 @@ assert_equal '[1, 2, 3, 4, 5]', %q{ splatarray } +# splatkw +assert_equal '[1, 2]', %q{ + def foo(a:) = [a, yield] + + def entry(&block) + a = { a: 1 } + foo(**a, &block) + end + + entry { 2 } +} + assert_equal '[1, 1, 2, 1, 2, 3]', %q{ def expandarray arr = [1, 2, 3] diff --git a/yjit/bindgen/src/main.rs b/yjit/bindgen/src/main.rs index df9bb4d727..2c264287bc 100644 --- a/yjit/bindgen/src/main.rs +++ b/yjit/bindgen/src/main.rs @@ -119,6 +119,7 @@ fn main() { .allowlist_function("rb_hash_new_with_size") .allowlist_function("rb_hash_resurrect") .allowlist_function("rb_hash_stlike_foreach") + .allowlist_function("rb_to_hash_type") // From include/ruby/st.h .allowlist_type("st_retval") diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index 2bec0cf6d4..a8c77b8d01 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -1435,6 +1435,33 @@ fn gen_splatarray( Some(KeepCompiling) } +// call to_hash on hash to keyword splat before converting block +// e.g. foo(**object, &block) +fn gen_splatkw( + jit: &mut JITState, + asm: &mut Assembler, + _ocb: &mut OutlinedCb, +) -> Option { + // Save the PC and SP because the callee may allocate + jit_prepare_routine_call(jit, asm); + + // Get the operands from the stack + let block_opnd = asm.stack_opnd(0); + let block_type = asm.ctx.get_opnd_type(block_opnd.into()); + let hash_opnd = asm.stack_opnd(1); + + let hash = asm.ccall(rb_to_hash_type as *const u8, vec![hash_opnd]); + asm.stack_pop(2); // Keep it on stack during ccall for GC + + let stack_ret = asm.stack_push(Type::Hash); + asm.mov(stack_ret, hash); + asm.stack_push(block_type); + // Leave block_opnd spilled by ccall as is + asm.ctx.dealloc_temp_reg(asm.ctx.get_stack_size() - 1); + + Some(KeepCompiling) +} + // concat two arrays fn gen_concatarray( jit: &mut JITState, @@ -8951,6 +8978,7 @@ fn get_gen_fn(opcode: VALUE) -> Option { YARVINSN_opt_str_uminus => Some(gen_opt_str_uminus), YARVINSN_opt_newarray_send => Some(gen_opt_newarray_send), YARVINSN_splatarray => Some(gen_splatarray), + YARVINSN_splatkw => Some(gen_splatkw), YARVINSN_concatarray => Some(gen_concatarray), YARVINSN_concattoarray => Some(gen_concattoarray), YARVINSN_pushtoarray => Some(gen_pushtoarray), diff --git a/yjit/src/cruby_bindings.inc.rs b/yjit/src/cruby_bindings.inc.rs index 2f965059d8..db71c1b0db 100644 --- a/yjit/src/cruby_bindings.inc.rs +++ b/yjit/src/cruby_bindings.inc.rs @@ -1015,6 +1015,7 @@ extern "C" { pub fn rb_obj_as_string_result(str_: VALUE, obj: VALUE) -> VALUE; pub fn rb_str_concat_literals(num: usize, strary: *const VALUE) -> VALUE; pub fn rb_ec_str_resurrect(ec: *mut rb_execution_context_struct, str_: VALUE) -> VALUE; + pub fn rb_to_hash_type(obj: VALUE) -> VALUE; pub fn rb_hash_stlike_foreach( hash: VALUE, func: st_foreach_callback_func,