8000 ZJIT: Add codegen (and FrameState) for GetConstPath by XrXr · Pull Request #13628 · ruby/ruby · GitHub
[go: up one dir, main page]

Skip to content

ZJIT: Add codegen (and FrameState) for GetConstPath #13628

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions test/ruby/test_zjit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,27 @@ def test() = @foo = 1
}
end

def test_uncached_getconstant_path
assert_compiles RUBY_COPYRIGHT.dump, %q{
def test = RUBY_COPYRIGHT
test
}, call_threshold: 1, insns: [:opt_getconstant_path]
end

def test_getconstant_path_autoload
# A constant-referencing expression can run arbitrary code through Kernel#autoload.
Dir.mktmpdir('autoload') do |tmpdir|
autoload_path = File.join(tmpdir, 'test_getconstant_path_autoload.rb')
File.write(autoload_path, 'X = RUBY_COPYRIGHT')

assert_compiles RUBY_COPYRIGHT.dump, %Q{
Object.autoload(:X, #{File.realpath(autoload_path).inspect})
def test = X
test
}, call_threshold: 1, insns: [:opt_getconstant_path]
end
end

def test_send_backtrace
backtrace = [
"-e:2:in 'Object#jit_frame1'",
Expand Down
16 changes: 16 additions & 0 deletions zjit/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
Insn::GetIvar { self_val, id, state: _ } => gen_getivar(asm, opnd!(self_val), *id),
Insn::SetGlobal { id, val, state: _ } => gen_setglobal(asm, *id, opnd!(val)),
Insn::GetGlobal { id, state: _ } => gen_getglobal(asm, *id),
Insn::GetConstantPath { ic, state } => gen_get_constant_path(asm, *ic, &function.frame_state(*state)),
Insn::SetIvar { self_val, id, val, state: _ } => return gen_setivar(asm, opnd!(self_val), *id, opnd!(val)),
Insn::SideExit { state } => return gen_side_exit(jit, asm, &function.frame_state(*state)),
Insn::PutSpecialObject { value_type } => gen_putspecialobject(asm, *value_type),
Expand All @@ -295,6 +296,21 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
Some(())
}

fn gen_get_constant_path(asm: &mut Assembler, ic: *const iseq_inline_constant_cache, state: &FrameState) -> Opnd {
unsafe extern "C" {
fn rb_vm_opt_getconstant_path(ec: EcPtr, cfp: CfpPtr, ic: *const iseq_inline_constant_cache) -> VALUE;
}

// Save PC since the call can allocate an IC
gen_save_pc(asm, state);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


let val = asm.ccall(
rb_vm_opt_getconstant_path as *const u8,
vec![EC, CFP, Opnd::const_ptr(ic as *const u8)],
);
val
}

/// Lowering for [`Insn::CCall`]. This is a low-level raw call that doesn't know
/// anything about the callee, so handling for e.g. GC safety is dealt with elsewhere.
fn gen_ccall(jit: &mut JITState, asm: &mut Assembler, cfun: *const u8, args: &[InsnId]) -> Option<lir::Opnd> {
Expand Down
93 changes: 49 additions & 44 deletions zjit/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ pub enum Insn {
/// Return C `true` if `val` is `Qnil`, else `false`.
IsNil { val: InsnId },
Defined { op_type: usize, obj: VALUE, pushval: VALUE, v: InsnId },
GetConstantPath { ic: *const iseq_inline_constant_cache },
GetConstantPath { ic: *const iseq_inline_constant_cache, state: InsnId },

/// Get a global variable named `id`
GetGlobal { id: ID, state: InsnId },
Expand Down Expand Up @@ -647,7 +647,7 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
Insn::GuardType { val, guard_type, .. } => { write!(f, "GuardType {val}, {}", guard_type.print(self.ptr_map)) },
Insn::GuardBitEquals { val, expected, .. } => { write!(f, "GuardBitEquals {val}, {}", expected.print(self.ptr_map)) },
Insn::PatchPoint(invariant) => { write!(f, "PatchPoint {}", invariant.print(self.ptr_map)) },
Insn::GetConstantPath { ic } => { write!(f, "GetConstantPath {:p}", self.ptr_map.map_ptr(ic)) },
Insn::GetConstantPath { ic, .. } => { write!(f, "GetConstantPath {:p}", self.ptr_map.map_ptr(ic)) },
Insn::CCall { cfun, args, name, return_type: _, elidable: _ } => {
write!(f, "CCall {}@{:p}", name.contents_lossy(), self.ptr_map.map_ptr(cfun))?;
for arg in args {
Expand Down Expand Up @@ -1315,7 +1315,7 @@ impl Function {
let send_direct = self.push_insn(block, Insn::SendWithoutBlockDirect { self_val, call_info, cd, cme, iseq, args, state });
self.make_equal_to(insn_id, send_direct);
}
Insn::GetConstantPath { ic } => {
Insn::GetConstantPath { ic, .. } => {
let idlist: *const ID = unsafe { (*ic).segments };
let ice = unsafe { (*ic).entry };
if ice.is_null() {
Expand Down Expand Up @@ -1602,10 +1602,14 @@ impl Function {
if necessary[insn_id.0] { continue; }
necessary[insn_id.0] = true;
match self.find(insn_id) {
Insn::Const { .. } | Insn::Param { .. }
| Insn::PatchPoint(..) | Insn::GetConstantPath { .. }
Insn::Const { .. }
| Insn::Param { .. }
| Insn::PatchPoint(..)
| Insn::PutSpecialObject { .. } =>
{}
Insn::GetConstantPath { ic: _, state } => {
worklist.push_back(state);
}
Insn::ArrayMax { elements, state }
| Insn::NewArray { elements, state } => {
worklist.extend(elements);
Expand Down Expand Up @@ -2269,7 +2273,8 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
}
YARVINSN_opt_getconstant_path => {
let ic = get_arg(pc, 0).as_ptr();
state.stack_push(fun.push_insn(block, Insn::GetConstantPath { ic }));
let snapshot = fun.push_insn(block, Insn::Snapshot { state: exit_state });
state.stack_push(fun.push_insn(block, Insn::GetConstantPath { ic, state: snapshot }));
}
YARVINSN_branchunless => {
let offset = get_arg(pc, 0).as_i64();
Expand Down Expand Up @@ -3621,14 +3626,14 @@ mod tests {
assert_method_hir_with_opcode("test", YARVINSN_opt_new, expect![[r#"
fn test:
bb0(v0:BasicObject):
v2:BasicObject = GetConstantPath 0x1000
v3:NilClassExact = Const Value(nil)
Jump bb1(v0, v3, v2)
bb1(v5:BasicObject, v6:NilClassExact, v7:BasicObject):
v10:BasicObject = SendWithoutBlock v7, :new
Jump bb2(v5, v10, v6)
bb2(v12:BasicObject, v13:BasicObject, v14:NilClassExact):
Return v13
v3:BasicObject = GetConstantPath 0x1000
v4:NilClassExact = Const Value(nil)
Jump bb1(v0, v4, v3)
bb1(v6:BasicObject, v7:NilClassExact, v8:BasicObject):
v11:BasicObject = SendWithoutBlock v8, :new
Jump bb2(v6, v11, v7)
bb2(v13:BasicObject, v14:BasicObject, v15:NilClassExact):
Return v14
"#]]);
}

Expand Down Expand Up @@ -5031,9 +5036,9 @@ mod opt_tests {
assert_optimized_method_hir("test", expect![[r#"
fn test:
bb0(v0:BasicObject):
v2:BasicObject = GetConstantPath 0x1000
v3:Fixnum[5] = Const Value(5)
Return v3
v3:BasicObject = GetConstantPath 0x1000
v4:Fixnum[5] = Const Value(5)
Return v4
"#]]);
}

Expand Down Expand Up @@ -5102,8 +5107,8 @@ mod opt_tests {
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, M)
PatchPoint MethodRedefined(Module@0x1008, name@0x1010)
v6:Fixnum[1] = Const Value(1)
Return v6
v7:Fixnum[1] = Const Value(1)
Return v7
"#]]);
}

Expand Down Expand Up @@ -5220,8 +5225,8 @@ mod opt_tests {
assert_optimized_method_hir("test", expect![[r#"
fn test:
bb0(v0:BasicObject):
v2:BasicObject = GetConstantPath 0x1000
Return v2
v3:BasicObject = GetConstantPath 0x1000
Return v3
"#]]);
}

Expand All @@ -5235,8 +5240,8 @@ mod opt_tests {
assert_optimized_method_hir("test", expect![[r#"
fn test:
bb0(v0:BasicObject):
v2:BasicObject = GetConstantPath 0x1000
Return v2
v3:BasicObject = GetConstantPath 0x1000
Return v3
"#]]);
}

Expand All @@ -5251,8 +5256,8 @@ mod opt_tests {
bb0(v0:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, Kernel)
v6:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
Return v6
v7:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
Return v7
"#]]);
}

Expand All @@ -5273,8 +5278,8 @@ mod opt_tests {
bb0(v0:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, Foo::Bar::C)
v6:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
Return v6
v7:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
Return v7
"#]]);
}

Expand All @@ -5290,14 +5295,14 @@ mod opt_tests {
bb0(v0:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, C)
v19:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
v3:NilClassExact = Const Value(nil)
Jump bb1(v0, v3, v19)
bb1(v5:BasicObject, v6:NilClassExact, v7:BasicObject[VALUE(0x1008)]):
v10:BasicObject = SendWithoutBlock v7, :new
Jump bb2(v5, v10, v6)
bb2(v12:BasicObject, v13:BasicObject, v14:NilClassExact):
Return v13
v20:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
v4:NilClassExact = Const Value(nil)
Jump bb1(v0, v4, v20)
bb1(v6:BasicObject, v7:NilClassExact, v8:BasicObject[VALUE(0x1008)]):
v11:BasicObject = SendWithoutBlock v8, :new
Jump bb2(v6, v11, v7)
bb2(v13:BasicObject, v14:BasicObject, v15:NilClassExact):
Return v14
"#]]);
}

Expand All @@ -5317,15 +5322,15 @@ mod opt_tests {
bb0(v0:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, C)
v21:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
v3:NilClassExact = Const Value(nil)
v4:Fixnum[1] = Const Value(1)
Jump bb1(v0, v3, v21, v4)
bb1(v6:BasicObject, v7:NilClassExact, v8:BasicObject[VALUE(0x1008)], v9:Fixnum[1]):
v12:BasicObject = SendWithoutBlock v8, :new, v9
Jump bb2(v6, v12, v7)
bb2(v14:BasicObject, v15:BasicObject, v16:NilClassExact):
Return v15
v22:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
v4:NilClassExact = Const Value(nil)
v5:Fixnum[1] = Const Value(1)
Jump bb1(v0, v4, v22, v5)
bb1(v7:BasicObject, v8:NilClassExact, v9:BasicObject[VALUE(0x1008)], v10:Fixnum[1]):
v13:BasicObject = SendWithoutBlock v9, :new, v10
Jump bb2(v7, v13, v8)
bb2(v15:BasicObject, v16:BasicObject, v17:NilClassExact):
Return v16
"#]]);
}

Expand Down
Loading
0