Skip to content

Commit 86ffe18

Browse files
committed
ZJIT: Add codegen (and FrameState) for GetConstPath
Issue a call to rb_vm_opt_getconstant_path() like the interpreter, but since that allocates the IC, we need to save the PC before calling. Add FrameState to GetConstPath to get access to the PC.
1 parent 9647dca commit 86ffe18

3 files changed

Lines changed: 86 additions & 44 deletions

File tree

test/ruby/test_zjit.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,27 @@ def test() = @foo = 1
650650
}
651651
end
652652

653+
def test_uncached_getconstant_path
654+
assert_compiles RUBY_COPYRIGHT.dump, %q{
655+
def test = RUBY_COPYRIGHT
656+
test
657+
}, call_threshold: 1, insns: [:opt_getconstant_path]
658+
end
659+
660+
def test_getconstant_path_autoload
661+
# A constant-referencing expression can run arbitrary code through Kernel#autoload.
662+
Dir.mktmpdir('autoload') do |tmpdir|
663+
autoload_path = File.join(tmpdir, 'test_getconstant_path_autoload.rb')
664+
File.write(autoload_path, 'X = RUBY_COPYRIGHT')
665+
666+
assert_compiles RUBY_COPYRIGHT.dump, %Q{
667+
Object.autoload(:X, #{File.realpath(autoload_path).inspect})
668+
def test = X
669+
test
670+
}, call_threshold: 1, insns: [:opt_getconstant_path]
671+
end
672+
end
673+
653674
def test_send_backtrace
654675
backtrace = [
655676
"-e:2:in 'Object#jit_frame1'",

zjit/src/codegen.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
278278
Insn::GetIvar { self_val, id, state: _ } => gen_getivar(asm, opnd!(self_val), *id),
279279
Insn::SetGlobal { id, val, state: _ } => gen_setglobal(asm, *id, opnd!(val)),
280280
Insn::GetGlobal { id, state: _ } => gen_getglobal(asm, *id),
281+
Insn::GetConstantPath { ic, state } => gen_get_constant_path(asm, *ic, &function.frame_state(*state)),
281282
Insn::SetIvar { self_val, id, val, state: _ } => return gen_setivar(asm, opnd!(self_val), *id, opnd!(val)),
282283
Insn::SideExit { state } => return gen_side_exit(jit, asm, &function.frame_state(*state)),
283284
Insn::PutSpecialObject { value_type } => gen_putspecialobject(asm, *value_type),
@@ -295,6 +296,21 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
295296
Some(())
296297
}
297298

299+
fn gen_get_constant_path(asm: &mut Assembler, ic: *const iseq_inline_constant_cache, state: &FrameState) -> Opnd {
300+
unsafe extern "C" {
301+
fn rb_vm_opt_getconstant_path(ec: EcPtr, cfp: CfpPtr, ic: *const iseq_inline_constant_cache) -> VALUE;
302+
}
303+
304+
// Save PC since the call can allocate an IC
305+
gen_save_pc(asm, state);
306+
307+
let val = asm.ccall(
308+
rb_vm_opt_getconstant_path as *const u8,
309+
vec![EC, CFP, Opnd::const_ptr(ic as *const u8)],
310+
);
311+
val
312+
}
313+
298314
/// Lowering for [`Insn::CCall`]. This is a low-level raw call that doesn't know
299315
/// anything about the callee, so handling for e.g. GC safety is dealt with elsewhere.
300316
fn gen_ccall(jit: &mut JITState, asm: &mut Assembler, cfun: *const u8, args: &[InsnId]) -> Option<lir::Opnd> {

zjit/src/hir.rs

Lines changed: 49 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ pub enum Insn {
427427
/// Return C `true` if `val` is `Qnil`, else `false`.
428428
IsNil { val: InsnId },
429429
Defined { op_type: usize, obj: VALUE, pushval: VALUE, v: InsnId },
430-
GetConstantPath { ic: *const iseq_inline_constant_cache },
430+
GetConstantPath { ic: *const iseq_inline_constant_cache, state: InsnId },
431431

432432
/// Get a global variable named `id`
433433
GetGlobal { id: ID, state: InsnId },
@@ -647,7 +647,7 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
647647
Insn::GuardType { val, guard_type, .. } => { write!(f, "GuardType {val}, {}", guard_type.print(self.ptr_map)) },
648648
Insn::GuardBitEquals { val, expected, .. } => { write!(f, "GuardBitEquals {val}, {}", expected.print(self.ptr_map)) },
649649
Insn::PatchPoint(invariant) => { write!(f, "PatchPoint {}", invariant.print(self.ptr_map)) },
650-
Insn::GetConstantPath { ic } => { write!(f, "GetConstantPath {:p}", self.ptr_map.map_ptr(ic)) },
650+
Insn::GetConstantPath { ic, .. } => { write!(f, "GetConstantPath {:p}", self.ptr_map.map_ptr(ic)) },
651651
Insn::CCall { cfun, args, name, return_type: _, elidable: _ } => {
652652
write!(f, "CCall {}@{:p}", name.contents_lossy(), self.ptr_map.map_ptr(cfun))?;
653653
for arg in args {
@@ -1315,7 +1315,7 @@ impl Function {
13151315
let send_direct = self.push_insn(block, Insn::SendWithoutBlockDirect { self_val, call_info, cd, cme, iseq, args, state });
13161316
self.make_equal_to(insn_id, send_direct);
13171317
}
1318-
Insn::GetConstantPath { ic } => {
1318+
Insn::GetConstantPath { ic, .. } => {
13191319
let idlist: *const ID = unsafe { (*ic).segments };
13201320
let ice = unsafe { (*ic).entry };
13211321
if ice.is_null() {
@@ -1602,10 +1602,14 @@ impl Function {
16021602
if necessary[insn_id.0] { continue; }
16031603
necessary[insn_id.0] = true;
16041604
match self.find(insn_id) {
1605-
Insn::Const { .. } | Insn::Param { .. }
1606-
| Insn::PatchPoint(..) | Insn::GetConstantPath { .. }
1605+
Insn::Const { .. }
1606+
| Insn::Param { .. }
1607+
| Insn::PatchPoint(..)
16071608
| Insn::PutSpecialObject { .. } =>
16081609
{}
1610+
Insn::GetConstantPath { ic: _, state } => {
1611+
worklist.push_back(state);
1612+
}
16091613
Insn::ArrayMax { elements, state }
16101614
| Insn::NewArray { elements, state } => {
16111615
worklist.extend(elements);
@@ -2269,7 +2273,8 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
22692273
}
22702274
YARVINSN_opt_getconstant_path => {
22712275
let ic = get_arg(pc, 0).as_ptr();
2272-
state.stack_push(fun.push_insn(block, Insn::GetConstantPath { ic }));
2276+
let snapshot = fun.push_insn(block, Insn::Snapshot { state: exit_state });
2277+
state.stack_push(fun.push_insn(block, Insn::GetConstantPath { ic, state: snapshot }));
22732278
}
22742279
YARVINSN_branchunless => {
22752280
let offset = get_arg(pc, 0).as_i64();
@@ -3621,14 +3626,14 @@ mod tests {
36213626
assert_method_hir_with_opcode("test", YARVINSN_opt_new, expect![[r#"
36223627
fn test:
36233628
bb0(v0:BasicObject):
3624-
v2:BasicObject = GetConstantPath 0x1000
3625-
v3:NilClassExact = Const Value(nil)
3626-
Jump bb1(v0, v3, v2)
3627-
bb1(v5:BasicObject, v6:NilClassExact, v7:BasicObject):
3628-
v10:BasicObject = SendWithoutBlock v7, :new
3629-
Jump bb2(v5, v10, v6)
3630-
bb2(v12:BasicObject, v13:BasicObject, v14:NilClassExact):
3631-
Return v13
3629+
v3:BasicObject = GetConstantPath 0x1000
3630+
v4:NilClassExact = Const Value(nil)
3631+
Jump bb1(v0, v4, v3)
3632+
bb1(v6:BasicObject, v7:NilClassExact, v8:BasicObject):
3633+
v11:BasicObject = SendWithoutBlock v8, :new
3634+
Jump bb2(v6, v11, v7)
3635+
bb2(v13:BasicObject, v14:BasicObject, v15:NilClassExact):
3636+
Return v14
36323637
"#]]);
36333638
}
36343639

@@ -5031,9 +5036,9 @@ mod opt_tests {
50315036
assert_optimized_method_hir("test", expect![[r#"
50325037
fn test:
50335038
bb0(v0:BasicObject):
5034-
v2:BasicObject = GetConstantPath 0x1000
5035-
v3:Fixnum[5] = Const Value(5)
5036-
Return v3
5039+
v3:BasicObject = GetConstantPath 0x1000
5040+
v4:Fixnum[5] = Const Value(5)
5041+
Return v4
50375042
"#]]);
50385043
}
50395044

@@ -5102,8 +5107,8 @@ mod opt_tests {
51025107
PatchPoint SingleRactorMode
51035108
PatchPoint StableConstantNames(0x1000, M)
51045109
PatchPoint MethodRedefined(Module@0x1008, name@0x1010)
5105-
v6:Fixnum[1] = Const Value(1)
5106-
Return v6
5110+
v7:Fixnum[1] = Const Value(1)
5111+
Return v7
51075112
"#]]);
51085113
}
51095114

@@ -5220,8 +5225,8 @@ mod opt_tests {
52205225
assert_optimized_method_hir("test", expect![[r#"
52215226
fn test:
52225227
bb0(v0:BasicObject):
5223-
v2:BasicObject = GetConstantPath 0x1000
5224-
Return v2
5228+
v3:BasicObject = GetConstantPath 0x1000
5229+
Return v3
52255230
"#]]);
52265231
}
52275232

@@ -5235,8 +5240,8 @@ mod opt_tests {
52355240
assert_optimized_method_hir("test", expect![[r#"
52365241
fn test:
52375242
bb0(v0:BasicObject):
5238-
v2:BasicObject = GetConstantPath 0x1000
5239-
Return v2
5243+
v3:BasicObject = GetConstantPath 0x1000
5244+
Return v3
52405245
"#]]);
52415246
}
52425247

@@ -5251,8 +5256,8 @@ mod opt_tests {
52515256
bb0(v0:BasicObject):
52525257
PatchPoint SingleRactorMode
52535258
PatchPoint StableConstantNames(0x1000, Kernel)
5254-
v6:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
5255-
Return v6
5259+
v7:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
5260+
Return v7
52565261
"#]]);
52575262
}
52585263

@@ -5273,8 +5278,8 @@ mod opt_tests {
52735278
bb0(v0:BasicObject):
52745279
PatchPoint SingleRactorMode
52755280
PatchPoint StableConstantNames(0x1000, Foo::Bar::C)
5276-
v6:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
5277-
Return v6
5281+
v7:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
5282+
Return v7
52785283
"#]]);
52795284
}
52805285

@@ -5290,14 +5295,14 @@ mod opt_tests {
52905295
bb0(v0:BasicObject):
52915296
PatchPoint SingleRactorMode
52925297
PatchPoint StableConstantNames(0x1000, C)
5293-
v19:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
5294-
v3:NilClassExact = Const Value(nil)
5295-
Jump bb1(v0, v3, v19)
5296-
bb1(v5:BasicObject, v6:NilClassExact, v7:BasicObject[VALUE(0x1008)]):
5297-
v10:BasicObject = SendWithoutBlock v7, :new
5298-
Jump bb2(v5, v10, v6)
5299-
bb2(v12:BasicObject, v13:BasicObject, v14:NilClassExact):
5300-
Return v13
5298+
v20:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
5299+
v4:NilClassExact = Const Value(nil)
5300+
Jump bb1(v0, v4, v20)
5301+
bb1(v6:BasicObject, v7:NilClassExact, v8:BasicObject[VALUE(0x1008)]):
5302+
v11:BasicObject = SendWithoutBlock v8, :new
5303+
Jump bb2(v6, v11, v7)
5304+
bb2(v13:BasicObject, v14:BasicObject, v15:NilClassExact):
5305+
Return v14
53015306
"#]]);
53025307
}
53035308

@@ -5317,15 +5322,15 @@ mod opt_tests {
53175322
bb0(v0:BasicObject):
53185323
PatchPoint SingleRactorMode
53195324
PatchPoint StableConstantNames(0x1000, C)
5320-
v21:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
5321-
v3:NilClassExact = Const Value(nil)
5322-
v4:Fixnum[1] = Const Value(1)
5323-
Jump bb1(v0, v3, v21, v4)
5324-
bb1(v6:BasicObject, v7:NilClassExact, v8:BasicObject[VALUE(0x1008)], v9:Fixnum[1]):
5325-
v12:BasicObject = SendWithoutBlock v8, :new, v9
5326-
Jump bb2(v6, v12, v7)
5327-
bb2(v14:BasicObject, v15:BasicObject, v16:NilClassExact):
5328-
Return v15
5325+
v22:BasicObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
5326+
v4:NilClassExact = Const Value(nil)
5327+
v5:Fixnum[1] = Const Value(1)
5328+
Jump bb1(v0, v4, v22, v5)
5329+
bb1(v7:BasicObject, v8:NilClassExact, v9:BasicObject[VALUE(0x1008)], v10:Fixnum[1]):
5330+
v13:BasicObject = SendWithoutBlock v9, :new, v10
5331+
Jump bb2(v7, v13, v8)
5332+
bb2(v15:BasicObject, v16:BasicObject, v17:NilClassExact):
5333+
Return v16
53295334
"#]]);
53305335
}
53315336

0 commit comments

Comments
 (0)