Skip to content

Commit de351ba

Browse files
committed
Replace GetConstantPath with Const if the IC is not empty
1 parent 7c90e6d commit de351ba

File tree

1 file changed

+110
-2
lines changed

1 file changed

+110
-2
lines changed

zjit/src/hir.rs

Lines changed: 110 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,13 @@ pub enum Invariant {
113113
/// The method ID of the method we want to assume unchanged
114114
method: ID,
115115
},
116+
/// A list of constant expression path segments that must have not been written to for the
117+
/// following code to be valid.
118+
StableConstantNames {
119+
idlist: *const ID,
120+
},
121+
/// There is one ractor running. If a non-root ractor gets spawned, this is invalidated.
122+
SingleRactorMode,
116123
}
117124

118125
impl Invariant {
@@ -161,6 +168,22 @@ impl<'a> std::fmt::Display for InvariantPrinter<'a> {
161168
self.ptr_map.map_id(method.0)
162169
)
163170
}
171+
Invariant::StableConstantNames { idlist } => {
172+
write!(f, "StableConstantNames({:p}, ", self.ptr_map.map_ptr(idlist))?;
173+
let mut idx = 0;
174+
let mut sep = "";
175+
loop {
176+
let id = unsafe { *idlist.wrapping_add(idx) };
177+
if id.0 == 0 {
178+
break;
179+
}
180+
write!(f, "{sep}{}", id.contents_lossy())?;
181+
sep = "::";
182+
idx += 1;
183+
}
184+
write!(f, ")")
185+
}
186+
Invariant::SingleRactorMode => write!(f, "SingleRactorMode"),
164187
}
165188
}
166189
}
@@ -292,7 +315,7 @@ pub enum Insn {
292315
// with IfTrue/IfFalse in the backend to generate jcc.
293316
Test { val: InsnId },
294317
Defined { op_type: usize, obj: VALUE, pushval: VALUE, v: InsnId },
295-
GetConstantPath { ic: *const u8 },
318+
GetConstantPath { ic: *const iseq_inline_constant_cache },
296319

297320
//NewObject?
298321
//SetIvar {},
@@ -1013,6 +1036,25 @@ impl Function {
10131036
let send_direct = self.push_insn(block, Insn::SendWithoutBlockDirect { self_val, call_info, cd, iseq, args, state });
10141037
self.make_equal_to(insn_id, send_direct);
10151038
}
1039+
Insn::GetConstantPath { ic } => {
1040+
let idlist: *const ID = unsafe { (*ic).segments };
1041+
let ice = unsafe { (*ic).entry };
1042+
if ice.is_null() {
1043+
self.push_insn_id(block, insn_id); continue;
1044+
}
1045+
let cref_sensitive = !unsafe { (*ice).ic_cref }.is_null();
1046+
let multi_ractor_mode = unsafe { rb_zjit_multi_ractor_p() };
1047+
if cref_sensitive || multi_ractor_mode {
1048+
self.push_insn_id(block, insn_id); continue;
1049+
}
1050+
// Assume single-ractor mode.
1051+
self.push_insn(block, Insn::PatchPoint(Invariant::SingleRactorMode));
1052+
// Invalidate output code on any constant writes associated with constants
1053+
// referenced after the PatchPoint.
1054+
self.push_insn(block, Insn::PatchPoint(Invariant::StableConstantNames { idlist }));
1055+
let replacement = self.push_insn(block, Insn::Const { val: Const::Value(unsafe { (*ice).value }) });
1056+
self.make_equal_to(insn_id, replacement);
1057+
}
10161058
_ => { self.push_insn_id(block, insn_id); }
10171059
}
10181060
}
@@ -1714,7 +1756,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
17141756
state.stack_push(fun.push_insn(block, Insn::Defined { op_type, obj, pushval, v }));
17151757
}
17161758
YARVINSN_opt_getconstant_path => {
1717-
let ic = get_arg(pc, 0).as_ptr::<u8>();
1759+
let ic = get_arg(pc, 0).as_ptr();
17181760
state.stack_push(fun.push_insn(block, Insn::GetConstantPath { ic }));
17191761
}
17201762
YARVINSN_branchunless => {
@@ -3565,4 +3607,70 @@ mod opt_tests {
35653607
Return v7
35663608
"#]]);
35673609
}
3610+
3611+
#[test]
3612+
fn dont_replace_get_constant_path_with_empty_ic() {
3613+
eval("
3614+
def test = Kernel
3615+
");
3616+
assert_optimized_method_hir("test", expect![[r#"
3617+
fn test:
3618+
bb0():
3619+
v1:BasicObject = GetConstantPath 0x1000
3620+
Return v1
3621+
"#]]);
3622+
}
3623+
3624+
#[test]
3625+
fn dont_replace_get_constant_path_with_invalidated_ic() {
3626+
eval("
3627+
def test = Kernel
3628+
test
3629+
Kernel = 5
3630+
");
3631+
assert_optimized_method_hir("test", expect![[r#"
3632+
fn test:
3633+
bb0():
3634+
v1:BasicObject = GetConstantPath 0x1000
3635+
Return v1
3636+
"#]]);
3637+
}
3638+
3639+
#[test]
3640+
fn replace_get_constant_path_with_const() {
3641+
eval("
3642+
def test = Kernel
3643+
test
3644+
");
3645+
assert_optimized_method_hir("test", expect![[r#"
3646+
fn test:
3647+
bb0():
3648+
PatchPoint SingleRactorMode
3649+
PatchPoint StableConstantNames(0x1000, Kernel)
3650+
v5:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
3651+
Return v5
3652+
"#]]);
3653+
}
3654+
3655+
#[test]
3656+
fn replace_nested_get_constant_path_with_const() {
3657+
eval("
3658+
module Foo
3659+
module Bar
3660+
class C
3661+
end
3662+
end
3663+
end
3664+
def test = Foo::Bar::C
3665+
test
3666+
");
3667+
assert_optimized_method_hir("test", expect![[r#"
3668+
fn test:
3669+
bb0():
3670+
PatchPoint SingleRactorMode
3671+
PatchPoint StableConstantNames(0x1000, Foo::Bar::C)
3672+
v5:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
3673+
Return v5
3674+
"#]]);
3675+
}
35683676
}

0 commit comments

Comments
 (0)