summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Kokubun <takashikkbn@gmail.com>2024-01-25 16:22:27 -0800
committerGitHub <noreply@github.com>2024-01-26 00:22:27 +0000
commit7567e4e1e1e8029b19cda81b612f2d1a0c27cb9f (patch)
tree71d1c6b29b144010033dadefdff176e36ff0396f
parent30b4070ffac3a66904a6fd74f4cb4860dd20ac37 (diff)
YJIT: Fix exits on splatkw instruction (#9711)
-rw-r--r--bootstraptest/test_yjit.rb12
-rw-r--r--yjit/bindgen/src/main.rs1
-rw-r--r--yjit/src/codegen.rs28
-rw-r--r--yjit/src/cruby_bindings.inc.rs1
4 files changed, 42 insertions, 0 deletions
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<CodegenStatus> {
+ // 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<InsnGenFn> {
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,