Skip to content

Commit c65d367

Browse files
committed
ZJIT: Inline Kernel#class
We generally know the receiver's class from profile info.
1 parent b43e66d commit c65d367

File tree

5 files changed

+56
-16
lines changed

5 files changed

+56
-16
lines changed

zjit/bindgen/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ fn main() {
107107
.allowlist_function("rb_obj_is_kind_of")
108108
.allowlist_function("rb_obj_frozen_p")
109109
.allowlist_function("rb_class_inherited_p")
110+
.allowlist_function("rb_class_real")
110111
.allowlist_type("ruby_encoding_consts")
111112
.allowlist_function("rb_hash_new")
112113
.allowlist_function("rb_hash_new_with_size")

zjit/src/cruby_bindings.inc.rs

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

zjit/src/cruby_methods.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,11 +186,18 @@ pub fn init() -> Annotations {
186186
($module:ident, $method_name:literal, $return_type:expr) => {
187187
annotate_builtin!($module, $method_name, $return_type, no_gc, leaf, elidable)
188188
};
189-
($module:ident, $method_name:literal, $return_type:expr, $($properties:ident),+) => {
189+
($module:ident, $method_name:literal, $return_type:expr $(, $properties:ident)*) => {
190190
let mut props = FnProperties::default();
191191
props.return_type = $return_type;
192192
$(props.$properties = true;)+
193193
annotate_builtin_method(builtin_funcs, unsafe { $module }, $method_name, props);
194+
};
195+
($module:ident, $method_name:literal, $inline:ident, $return_type:expr $(, $properties:ident)*) => {
196+
let mut props = FnProperties::default();
197+
props.return_type = $return_type;
198+
props.inline = $inline;
199+
$(props.$properties = true;)+
200+
annotate_builtin_method(builtin_funcs, unsafe { $module }, $method_name, props);
194201
}
195202
}
196203

@@ -256,7 +263,7 @@ pub fn init() -> Annotations {
256263
annotate_builtin!(rb_mKernel, "Integer", types::Integer);
257264
// TODO(max): Annotate rb_mKernel#class as returning types::Class. Right now there is a subtle
258265
// type system bug that causes an issue if we make it return types::Class.
259-
annotate_builtin!(rb_mKernel, "class", types::HeapObject, leaf);
266+
annotate_builtin!(rb_mKernel, "class", inline_kernel_class, types::HeapObject, leaf);
260267
annotate_builtin!(rb_mKernel, "frozen?", types::BoolExact);
261268
annotate_builtin!(rb_cSymbol, "name", types::StringExact);
262269
annotate_builtin!(rb_cSymbol, "to_s", types::StringExact);
@@ -785,3 +792,10 @@ fn inline_kernel_respond_to_p(
785792
}
786793
Some(fun.push_insn(block, hir::Insn::Const { val: hir::Const::Value(result) }))
787794
}
795+
796+
fn inline_kernel_class(fun: &mut hir::Function, block: hir::BlockId, _recv: hir::InsnId, args: &[hir::InsnId], _state: hir::InsnId) -> Option<hir::InsnId> {
797+
let &[recv] = args else { return None; };
798+
let recv_class = fun.type_of(recv).runtime_exact_ruby_class()?;
799+
let real_class = unsafe { rb_class_real(recv_class) };
800+
Some(fun.push_insn(block, hir::Insn::Const { val: hir::Const::Value(real_class) }))
801+
}

zjit/src/hir.rs

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -862,6 +862,7 @@ pub enum Insn {
862862
// Invoke a builtin function
863863
InvokeBuiltin {
864864
bf: rb_builtin_function,
865+
recv: InsnId,
865866
args: Vec<InsnId>,
866867
state: InsnId,
867868
leaf: bool,
@@ -1922,7 +1923,7 @@ impl Function {
19221923
state,
19231924
reason,
19241925
},
1925-
&InvokeBuiltin { bf, ref args, state, leaf, return_type } => InvokeBuiltin { bf, args: find_vec!(args), state, leaf, return_type },
1926+
&InvokeBuiltin { bf, recv, ref args, state, leaf, return_type } => InvokeBuiltin { bf, recv: find!(recv), args: find_vec!(args), state, leaf, return_type },
19261927
&ArrayDup { val, state } => ArrayDup { val: find!(val), state },
19271928
&HashDup { val, state } => HashDup { val: find!(val), state },
19281929
&HashAref { hash, key, state } => HashAref { hash: find!(hash), key: find!(key), state },
@@ -2807,6 +2808,7 @@ impl Function {
28072808
self.push_insn(block, Insn::IncrCounter(Counter::inline_iseq_optimized_send_count));
28082809
let replacement = self.push_insn(block, Insn::InvokeBuiltin {
28092810
bf,
2811+
recv,
28102812
args: vec![recv],
28112813
state,
28122814
leaf: true,
@@ -3385,6 +3387,25 @@ impl Function {
33853387
continue;
33863388
}
33873389
}
3390+
Insn::InvokeBuiltin { bf, recv, args, state, .. } => {
3391+
let props = ZJITState::get_method_annotations().get_builtin_properties(&bf).unwrap_or_default();
3392+
// Try inlining the cfunc into HIR
3393+
let tmp_block = self.new_block(u32::MAX);
3394+
if let Some(replacement) = (props.inline)(self, tmp_block, recv, &args, state) {
3395+
// Copy contents of tmp_block to block
3396+
assert_ne!(block, tmp_block);
3397+
let insns = std::mem::take(&mut self.blocks[tmp_block.0].insns);
3398+
self.blocks[block.0].insns.extend(insns);
3399+
self.push_insn(block, Insn::IncrCounter(Counter::inline_cfunc_optimized_send_count));
3400+
self.make_equal_to(insn_id, replacement);
3401+
if self.type_of(replacement).bit_equal(types::Any) {
3402+
// Not set yet; infer type
3403+
self.insn_types[replacement.0] = self.infer_type(replacement);
3404+
}
3405+
self.remove_block(tmp_block);
3406+
continue;
3407+
}
3408+
}
33883409
_ => {}
33893410
}
33903411
self.push_insn_id(block, insn_id);
@@ -3703,13 +3724,13 @@ impl Function {
37033724
| &Insn::CCallVariadic { recv, ref args, state, .. }
37043725
| &Insn::CCallWithFrame { recv, ref args, state, .. }
37053726
| &Insn::SendWithoutBlockDirect { recv, ref args, state, .. }
3727+
| &Insn::InvokeBuiltin { recv, ref args, state, .. }
37063728
| &Insn::InvokeSuper { recv, ref args, state, .. } => {
37073729
worklist.push_back(recv);
37083730
worklist.extend(args);
37093731
worklist.push_back(state);
37103732
}
3711-
&Insn::InvokeBuiltin { ref args, state, .. }
3712-
| &Insn::InvokeBlock { ref args, state, .. } => {
3733+
&Insn::InvokeBlock { ref args, state, .. } => {
37133734
worklist.extend(args);
37143735
worklist.push_back(state)
37153736
}
@@ -4320,6 +4341,7 @@ impl Function {
43204341
| Insn::InvokeSuper { recv, ref args, .. }
43214342
| Insn::CCallWithFrame { recv, ref args, .. }
43224343
| Insn::CCallVariadic { recv, ref args, .. }
4344+
| Insn::InvokeBuiltin { recv, ref args, .. }
43234345
| Insn::ArrayInclude { target: recv, elements: ref args, .. } => {
43244346
self.assert_subtype(insn_id, recv, types::BasicObject)?;
43254347
for &arg in args {
@@ -4328,8 +4350,7 @@ impl Function {
43284350
Ok(())
43294351
}
43304352
// Instructions with a Vec of Ruby objects
4331-
Insn::InvokeBuiltin { ref args, .. }
4332-
| Insn::InvokeBlock { ref args, .. }
4353+
Insn::InvokeBlock { ref args, .. }
43334354
| Insn::NewArray { elements: ref args, .. }
43344355
| Insn::ArrayHash { elements: ref args, .. }
43354356
| Insn::ArrayMax { elements: ref args, .. } => {
@@ -5782,6 +5803,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
57825803

57835804
let insn_id = fun.push_insn(block, Insn::InvokeBuiltin {
57845805
bf,
5806+
recv: self_param,
57855807
args,
57865808
state: exit_id,
57875809
leaf,
@@ -5810,6 +5832,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
58105832

58115833
let insn_id = fun.push_insn(block, Insn::InvokeBuiltin {
58125834
bf,
5835+
recv: self_param,
58135836
args,
58145837
state: exit_id,
58155838
leaf,

zjit/src/hir/opt_tests.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2611,9 +2611,10 @@ mod hir_opt_tests {
26112611
PatchPoint MethodRedefined(Module@0x1010, class@0x1018, cme:0x1020)
26122612
PatchPoint NoSingletonClass(Module@0x1010)
26132613
IncrCounter inline_iseq_optimized_send_count
2614-
v25:HeapObject = InvokeBuiltin leaf _bi20, v20
2614+
v26:Class[Module@0x1010] = Const Value(VALUE(0x1010))
2615+
IncrCounter inline_cfunc_optimized_send_count
26152616
CheckInterrupts
2616-
Return v25
2617+
Return v26
26172618
");
26182619
}
26192620

@@ -8937,15 +8938,15 @@ mod hir_opt_tests {
89378938
PatchPoint NoSingletonClass(C@0x1000)
89388939
v40:HeapObject[class_exact:C] = GuardType v6, HeapObject[class_exact:C]
89398940
IncrCounter inline_iseq_optimized_send_count
8940-
v43:HeapObject = InvokeBuiltin leaf _bi20, v40
8941+
v44:Class[C@0x1000] = Const Value(VALUE(0x1000))
8942+
IncrCounter inline_cfunc_optimized_send_count
89418943
v13:StaticSymbol[:_lex_actions] = Const Value(VALUE(0x1038))
89428944
v15:TrueClass = Const Value(true)
89438945
PatchPoint MethodRedefined(Class@0x1040, respond_to?@0x1048, cme:0x1050)
89448946
PatchPoint NoSingletonClass(Class@0x1040)
8945-
v47:ModuleSubclass[class_exact*:Class@VALUE(0x1040)] = GuardType v43, ModuleSubclass[class_exact*:Class@VALUE(0x1040)]
89468947
PatchPoint MethodRedefined(Class@0x1040, _lex_actions@0x1078, cme:0x1080)
89478948
PatchPoint NoSingletonClass(Class@0x1040)
8948-
v51:TrueClass = Const Value(true)
8949+
v52:TrueClass = Const Value(true)
89498950
IncrCounter inline_cfunc_optimized_send_count
89508951
CheckInterrupts
89518952
v24:StaticSymbol[:CORRECT] = Const Value(VALUE(0x10a8))
@@ -8976,14 +8977,14 @@ mod hir_opt_tests {
89768977
PatchPoint NoSingletonClass(C@0x1000)
89778978
v23:HeapObject[class_exact:C] = GuardType v9, HeapObject[class_exact:C]
89788979
IncrCounter inline_iseq_optimized_send_count
8979-
v26:HeapObject = InvokeBuiltin leaf _bi20, v23
8980+
v27:Class[C@0x1000] = Const Value(VALUE(0x1000))
8981+
IncrCounter inline_cfunc_optimized_send_count
89808982
PatchPoint MethodRedefined(Class@0x1038, name@0x1040, cme:0x1048)
89818983
PatchPoint NoSingletonClass(Class@0x1038)
8982-
v30:ModuleSubclass[class_exact*:Class@VALUE(0x1038)] = GuardType v26, ModuleSubclass[class_exact*:Class@VALUE(0x1038)]
89838984
IncrCounter inline_cfunc_optimized_send_count
8984-
v32:StringExact|NilClass = CCall v30, :Module#name@0x1070
8985+
v33:StringExact|NilClass = CCall v27, :Module#name@0x1070
89858986
CheckInterrupts
8986-
Return v32
8987+
Return v33
89878988
");
89888989
}
89898990

0 commit comments

Comments
 (0)