Skip to content

Commit acc4145

Browse files
authored
ZJIT: Support inlining send-with-block (ruby#15998)
Autosplat only happens due to `yield` or `.call`, neither of which is permitted in our trivial inliner.
1 parent b51a112 commit acc4145

2 files changed

Lines changed: 122 additions & 3 deletions

File tree

zjit/src/hir.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3643,8 +3643,10 @@ impl Function {
36433643
assert!(self.blocks[block.0].insns.is_empty());
36443644
for insn_id in old_insns {
36453645
match self.find(insn_id) {
3646-
// Reject block ISEQs to avoid autosplat and other block parameter complications.
3647-
Insn::SendDirect { recv, iseq, cd, args, state, blockiseq: None, .. } => {
3646+
// We can inline SendDirect with blockiseq because we are prohibiting `yield`
3647+
// and `.call`, which would trigger autosplat. We only inline constants and
3648+
// variables and builtin calls.
3649+
Insn::SendDirect { recv, iseq, cd, args, state, .. } => {
36483650
let call_info = unsafe { (*cd).ci };
36493651
let ci_flags = unsafe { vm_ci_flag(call_info) };
36503652
// .send call is not currently supported for builtins

zjit/src/hir/opt_tests.rs

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2930,7 +2930,7 @@ mod hir_opt_tests {
29302930
PatchPoint NoSingletonClass(Object@0x1000)
29312931
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
29322932
v31:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v8, HeapObject[class_exact*:Object@VALUE(0x1000)]
2933-
v32:BasicObject = SendDirect v31, 0x1038, :foo (0x1048)
2933+
IncrCounter inline_iseq_optimized_send_count
29342934
v20:BasicObject = GetLocal :a, l0, EP@3
29352935
v24:BasicObject = GetLocal :a, l0, EP@3
29362936
CheckInterrupts
@@ -9545,6 +9545,123 @@ mod hir_opt_tests {
95459545
");
95469546
}
95479547

9548+
#[test]
9549+
fn test_inline_send_with_block_with_no_params() {
9550+
eval(r#"
9551+
def callee = 123
9552+
def test
9553+
callee do
9554+
end
9555+
end
9556+
test
9557+
"#);
9558+
assert_snapshot!(hir_string("test"), @r"
9559+
fn test@<compiled>:4:
9560+
bb0():
9561+
EntryPoint interpreter
9562+
v1:BasicObject = LoadSelf
9563+
Jump bb2(v1)
9564+
bb1(v4:BasicObject):
9565+
EntryPoint JIT(0)
9566+
Jump bb2(v4)
9567+
bb2(v6:BasicObject):
9568+
PatchPoint NoSingletonClass(Object@0x1000)
9569+
PatchPoint MethodRedefined(Object@0x1000, callee@0x1008, cme:0x1010)
9570+
v18:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
9571+
IncrCounter inline_iseq_optimized_send_count
9572+
v21:Fixnum[123] = Const Value(123)
9573+
CheckInterrupts
9574+
Return v21
9575+
");
9576+
}
9577+
9578+
#[test]
9579+
fn test_inline_send_with_block_with_one_param() {
9580+
eval(r#"
9581+
def callee = 123
9582+
def test
9583+
callee do |_|
9584+
end
9585+
end
9586+
test
9587+
"#);
9588+
assert_snapshot!(hir_string("test"), @r"
9589+
fn test@<compiled>:4:
9590+
bb0():
9591+
EntryPoint interpreter
9592+
v1:BasicObject = LoadSelf
9593+
Jump bb2(v1)
9594+
bb1(v4:BasicObject):
9595+
EntryPoint JIT(0)
9596+
Jump bb2(v4)
9597+
bb2(v6:BasicObject):
9598+
PatchPoint NoSingletonClass(Object@0x1000)
9599+
PatchPoint MethodRedefined(Object@0x1000, callee@0x1008, cme:0x1010)
9600+
v18:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
9601+
IncrCounter inline_iseq_optimized_send_count
9602+
v21:Fixnum[123] = Const Value(123)
9603+
CheckInterrupts
9604+
Return v21
9605+
");
9606+
}
9607+
9608+
#[test]
9609+
fn test_inline_send_with_block_with_multiple_params() {
9610+
eval(r#"
9611+
def callee = 123
9612+
def test
9613+
callee do |_a, _b|
9614+
end
9615+
end
9616+
test
9617+
"#);
9618+
assert_snapshot!(hir_string("test"), @r"
9619+
fn test@<compiled>:4:
9620+
bb0():
9621+
EntryPoint interpreter
9622+
v1:BasicObject = LoadSelf
9623+
Jump bb2(v1)
9624+
bb1(v4:BasicObject):
9625+
EntryPoint JIT(0)
9626+
Jump bb2(v4)
9627+
bb2(v6:BasicObject):
9628+
PatchPoint NoSingletonClass(Object@0x1000)
9629+
PatchPoint MethodRedefined(Object@0x1000, callee@0x1008, cme:0x1010)
9630+
v18:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
9631+
IncrCounter inline_iseq_optimized_send_count
9632+
v21:Fixnum[123] = Const Value(123)
9633+
CheckInterrupts
9634+
Return v21
9635+
");
9636+
}
9637+
9638+
#[test]
9639+
fn test_no_inline_send_with_symbol_block() {
9640+
eval(r#"
9641+
def callee = 123
9642+
public def the_block = 456
9643+
def test
9644+
callee(&:the_block)
9645+
end
9646+
puts test
9647+
"#);
9648+
assert_snapshot!(hir_string("test"), @r"
9649+
fn test@<compiled>:5:
9650+
bb0():
9651+
EntryPoint interpreter
9652+
v1:BasicObject = LoadSelf
9653+
Jump bb2(v1)
9654+
bb1(v4:BasicObject):
9655+
EntryPoint JIT(0)
9656+
Jump bb2(v4)
9657+
bb2(v6:BasicObject):
9658+
v11:StaticSymbol[:the_block] = Const Value(VALUE(0x1000))
9659+
v13:BasicObject = Send v6, 0x1008, :callee, v11 # SendFallbackReason: Uncategorized(send)
9660+
CheckInterrupts
9661+
Return v13
9662+
");
9663+
}
9664+
95489665
#[test]
95499666
fn test_optimize_stringexact_eq_stringexact() {
95509667
eval(r#"

0 commit comments

Comments
 (0)