8000 ZJIT: Replace GetConstantPath with Const if the IC is not empty (#13183) · ruby/ruby@6052b12 · GitHub
[go: up one dir, main page]

Skip to content

Commit 6052b12

Browse files
authored
ZJIT: Replace GetConstantPath with Const if the IC is not empty (#13183)
* Add rb_zjit_constcache_shareable * Add rb_zjit_multi_ractor_p * Replace GetConstantPath with Const if the IC is not empty
1 parent 1e41668 commit 6052b12

File tree

4 files changed

+126
-2
lines changed

4 files changed

+126
-2
lines changed

zjit.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,13 +525,25 @@ rb_BASIC_OP_UNREDEFINED_P(enum ruby_basic_operators bop, uint32_t klass)
525525
return BASIC_OP_UNREDEFINED_P(bop, klass);
526526
}
527527

528+
bool
529+
rb_zjit_multi_ractor_p(void)
530+
{
531+
return rb_multi_ractor_p();
532+
}
533+
528534
// For debug builds
529535
void
530536
rb_assert_iseq_handle(VALUE handle)
531537
{
532538
RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(handle, imemo_iseq));
533539
}
534540

541+
bool
542+
rb_zjit_constcache_shareable(const struct iseq_inline_constant_cache_entry *ice)
543+
{
544+
return (ice->flags & IMEMO_CONST_CACHE_SHAREABLE) != 0;
545+
}
546+
535547
void
536548
rb_assert_cme_handle(VALUE handle)
537549
{

zjit/bindgen/src/main.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,8 @@ fn main() {
409409
.allowlist_function("rb_get_cfp_ep")
410410
.allowlist_function("rb_get_cfp_ep_level")
411411
.allowlist_function("rb_get_cme_def_type")
412+
.allowlist_function("rb_zjit_multi_ractor_p")
413+
.allowlist_function("rb_zjit_constcache_shareable")
412414
.allowlist_function("rb_get_cme_def_body_attr_id")
413415
.allowlist_function("rb_get_symbol_id")
414416
.allowlist_function("rb_get_cme_def_body_optimized_type")

zjit/src/cruby_bindings.inc.rs

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

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)
0