Skip to content

Commit 3fb96ee

Browse files
committed
ZJIT: Inline method calls to ISEQs that just do leaf Primitive calls
1 parent 8d45e1f commit 3fb96ee

File tree

1 file changed

+84
-11
lines changed

1 file changed

+84
-11
lines changed

zjit/src/hir.rs

Lines changed: 84 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1379,6 +1379,7 @@ enum IseqReturn {
13791379
Value(VALUE),
13801380
LocalVariable(u32),
13811381
Receiver,
1382+
InvokeLeafBuiltin(rb_builtin_function),
13821383
}
13831384

13841385
unsafe extern "C" {
@@ -1390,10 +1391,6 @@ fn iseq_get_return_value(iseq: IseqPtr, captured_opnd: Option<InsnId>, ci_flags:
13901391
// Expect only two instructions and one possible operand
13911392
// NOTE: If an ISEQ has an optional keyword parameter with a default value that requires
13921393
// computation, the ISEQ will always have more than two instructions and won't be inlined.
1393-
let iseq_size = unsafe { get_iseq_encoded_size(iseq) };
1394-
if !(2..=3).contains(&iseq_size) {
1395-
return None;
1396-
}
13971394

13981395
// Get the first two instructions
13991396
let first_insn = iseq_opcode_at_idx(iseq, 0);
@@ -1436,6 +1433,16 @@ fn iseq_get_return_value(iseq: IseqPtr, captured_opnd: Option<InsnId>, ci_flags:
14361433
YARVINSN_putobject_INT2FIX_1_ => Some(IseqReturn::Value(VALUE::fixnum_from_usize(1))),
14371434
// We don't support invokeblock for now. Such ISEQs are likely not used by blocks anyway.
14381435
YARVINSN_putself if captured_opnd.is_none() => Some(IseqReturn::Receiver),
1436+
YARVINSN_opt_invokebuiltin_delegate_leave => {
1437+
let pc = unsafe { rb_iseq_pc_at_idx(iseq, 0) };
1438+
let bf: rb_builtin_function = unsafe { *get_arg(pc, 0).as_ptr() };
1439+
let argc = bf.argc as usize;
1440+
if argc != 0 { return None; }
1441+
let builtin_attrs = unsafe { rb_jit_iseq_builtin_attrs(iseq) };
1442+
let leaf = builtin_attrs & BUILTIN_ATTR_LEAF != 0;
1443+
if !leaf { return None; }
1444+
Some(IseqReturn::InvokeLeafBuiltin(bf))
1445+
}
14391446
_ => None,
14401447
}
14411448
}
@@ -2437,7 +2444,7 @@ impl Function {
24372444
for insn_id in old_insns {
24382445
match self.find(insn_id) {
24392446
// Reject block ISEQs to avoid autosplat and other block parameter complications.
2440-
Insn::SendWithoutBlockDirect { recv, iseq, cd, args, .. } => {
2447+
Insn::SendWithoutBlockDirect { recv, iseq, cd, args, state, .. } => {
24412448
let call_info = unsafe { (*cd).ci };
24422449
let ci_flags = unsafe { vm_ci_flag(call_info) };
24432450
// .send call is not currently supported for builtins
@@ -2461,6 +2468,17 @@ impl Function {
24612468
self.push_insn(block, Insn::IncrCounter(Counter::inline_iseq_optimized_send_count));
24622469
self.make_equal_to(insn_id, recv);
24632470
}
2471+
IseqReturn::InvokeLeafBuiltin(bf) => {
2472+
self.push_insn(block, Insn::IncrCounter(Counter::inline_iseq_optimized_send_count));
2473+
let replacement = self.push_insn(block, Insn::InvokeBuiltin {
2474+
bf,
2475+
args: vec![recv],
2476+
state,
2477+
leaf: true,
2478+
return_type: None,
2479+
});
2480+
self.make_equal_to(insn_id, replacement);
2481+
}
24642482
}
24652483
}
24662484
_ => { self.push_insn_id(block, insn_id); }
@@ -10955,9 +10973,10 @@ mod opt_tests {
1095510973
bb2(v8:BasicObject, v9:BasicObject):
1095610974
v13:Fixnum[1] = Const Value(1)
1095710975
PatchPoint MethodRedefined(Integer@0x1000, zero?@0x1008, cme:0x1010)
10958-
v22:BasicObject = SendWithoutBlockDirect v13, :zero? (0x1038)
10976+
IncrCounter inline_iseq_optimized_send_count
10977+
v24:BasicObject = InvokeBuiltin leaf _bi285, v13
1095910978
CheckInterrupts
10960-
Return v22
10979+
Return v24
1096110980
");
1096210981
}
1096310982

@@ -10986,9 +11005,10 @@ mod opt_tests {
1098611005
v18:ArrayExact = ArrayDup v16
1098711006
PatchPoint MethodRedefined(Array@0x1008, first@0x1010, cme:0x1018)
1098811007
PatchPoint NoSingletonClass(Array@0x1008)
10989-
v30:BasicObject = SendWithoutBlockDirect v18, :first (0x1040)
11008+
IncrCounter inline_iseq_optimized_send_count
11009+
v32:BasicObject = InvokeBuiltin leaf _bi132, v18
1099011010
CheckInterrupts
10991-
Return v30
11011+
Return v32
1099211012
");
1099311013
}
1099411014

@@ -11015,9 +11035,10 @@ mod opt_tests {
1101511035
v21:ModuleExact[VALUE(0x1008)] = Const Value(VALUE(0x1008))
1101611036
PatchPoint MethodRedefined(Module@0x1010, class@0x1018, cme:0x1020)
1101711037
PatchPoint NoSingletonClass(Module@0x1010)
11018-
v24:BasicObject = SendWithoutBlockDirect v21, :class (0x1048)
11038+
IncrCounter inline_iseq_optimized_send_count
11039+
v26:BasicObject = InvokeBuiltin leaf _bi20, v21
1101911040
CheckInterrupts
11020-
Return v24
11041+
Return v26
1102111042
");
1102211043
}
1102311044

@@ -15345,6 +15366,58 @@ mod opt_tests {
1534515366
");
1534615367
}
1534715368

15369+
#[test]
15370+
fn test_inline_symbol_name() {
15371+
eval("
15372+
def test(x) = x.to_s
15373+
test(:foo)
15374+
");
15375+
assert_snapshot!(hir_string("test"), @r"
15376+
fn test@<compiled>:2:
15377+
bb0():
15378+
EntryPoint interpreter
15379+
v1:BasicObject = LoadSelf
15380+
v2:BasicObject = GetLocal l0, SP@4
15381+
Jump bb2(v1, v2)
15382+
bb1(v5:BasicObject, v6:BasicObject):
15383+
EntryPoint JIT(0)
15384+
Jump bb2(v5, v6)
15385+
bb2(v8:BasicObject, v9:BasicObject):
15386+
PatchPoint MethodRedefined(Symbol@0x1000, to_s@0x1008, cme:0x1010)
15387+
v21:StaticSymbol = GuardType v9, StaticSymbol
15388+
IncrCounter inline_iseq_optimized_send_count
15389+
v24:BasicObject = InvokeBuiltin leaf _bi12, v21
15390+
CheckInterrupts
15391+
Return v24
15392+
");
15393+
}
15394+
15395+
#[test]
15396+
fn test_inline_symbol_to_s() {
15397+
eval("
15398+
def test(x) = x.to_s
15399+
test(:foo)
15400+
");
15401+
assert_snapshot!(hir_string("test"), @r"
15402+
fn test@<compiled>:2:
15403+
bb0():
15404+
EntryPoint interpreter
15405+
v1:BasicObject = LoadSelf
15406+
v2:BasicObject = GetLocal l0, SP@4
15407+
Jump bb2(v1, v2)
15408+
bb1(v5:BasicObject, v6:BasicObject):
15409+
EntryPoint JIT(0)
15410+
Jump bb2(v5, v6)
15411+
bb2(v8:BasicObject, v9:BasicObject):
15412+
PatchPoint MethodRedefined(Symbol@0x1000, to_s@0x1008, cme:0x1010)
15413+
v21:StaticSymbol = GuardType v9, StaticSymbol
15414+
IncrCounter inline_iseq_optimized_send_count
15415+
v24:BasicObject = InvokeBuiltin leaf _bi12, v21
15416+
CheckInterrupts
15417+
Return v24
15418+
");
15419+
}
15420+
1534815421
#[test]
1534915422
fn test_optimize_stringexact_eq_stringexact() {
1535015423
eval(r#"

0 commit comments

Comments
 (0)