Skip to content

Commit 83e7457

Browse files
committed
ZJIT: Implement defined? codegen for non-yield calls
1 parent 8091f3b commit 83e7457

3 files changed

Lines changed: 42 additions & 12 deletions

File tree

test/ruby/test_zjit.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -983,6 +983,26 @@ def +(_) = 100
983983
}
984984
end
985985

986+
def test_defined_with_defined_values
987+
assert_compiles '["constant", "method", "global-variable"]', %q{
988+
class Foo; end
989+
def bar; end
990+
$ruby = 1
991+
992+
def test = return defined?(Foo), defined?(bar), defined?($ruby)
993+
994+
test
995+
}, insns: [:defined]
996+
end
997+
998+
def test_defined_with_undefined_values
999+
assert_compiles '[nil, nil, nil]', %q{
1000+
def test = return defined?(Foo), defined?(bar), defined?($ruby)
1001+
1002+
test
1003+
}, insns: [:defined]
1004+
end
1005+
9861006
def test_defined_yield
9871007
assert_compiles "nil", "defined?(yield)"
9881008
assert_compiles '[nil, nil, "yield"]', %q{

zjit/src/codegen.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
369369
Insn::SideExit { state, reason } => return gen_side_exit(jit, asm, reason, &function.frame_state(*state)),
370370
Insn::PutSpecialObject { value_type } => gen_putspecialobject(asm, *value_type),
371371
Insn::AnyToString { val, str, state } => gen_anytostring(asm, opnd!(val), opnd!(str), &function.frame_state(*state))?,
372-
Insn::Defined { op_type, obj, pushval, v } => gen_defined(jit, asm, *op_type, *obj, *pushval, opnd!(v))?,
372+
Insn::Defined { op_type, obj, pushval, v, state } => gen_defined(jit, asm, *op_type, *obj, *pushval, opnd!(v), &function.frame_state(*state))?,
373373
&Insn::IncrCounter(counter) => return Some(gen_incr_counter(asm, counter)),
374374
Insn::ArrayExtend { .. }
375375
| Insn::ArrayMax { .. }
@@ -438,7 +438,7 @@ fn gen_get_ep(asm: &mut Assembler, level: u32) -> Opnd {
438438
ep_opnd
439439
}
440440

441-
fn gen_defined(jit: &JITState, asm: &mut Assembler, op_type: usize, _obj: VALUE, pushval: VALUE, _tested_value: Opnd) -> Option<Opnd> {
441+
fn gen_defined(jit: &JITState, asm: &mut Assembler, op_type: usize, obj: VALUE, pushval: VALUE, tested_value: Opnd, state: &FrameState) -> Option<Opnd> {
442442
match op_type as defined_type {
443443
DEFINED_YIELD => {
444444
// `yield` goes to the block handler stowed in the "local" iseq which is
@@ -455,7 +455,16 @@ fn gen_defined(jit: &JITState, asm: &mut Assembler, op_type: usize, _obj: VALUE,
455455
Some(Qnil.into())
456456
}
457457
}
458-
_ => None
458+
_ => {
459+
// Save the PC and SP because the callee may allocate or call #respond_to?
460+
gen_prepare_non_leaf_call(jit, asm, state)?;
461+
462+
// Call vm_defined(ec, reg_cfp, op_type, obj, v)
463+
let def_result = asm.ccall(rb_vm_defined as *const u8, vec![EC, CFP, op_type.into(), obj.into(), tested_value]);
464+
465+
asm.test(def_result, Opnd::UImm(255));
466+
Some(asm.csel_nz(pushval.into(), Qnil.into()))
467+
}
459468
}
460469
}
461470

zjit/src/hir.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,7 @@ pub enum Insn {
471471
Test { val: InsnId },
472472
/// Return C `true` if `val` is `Qnil`, else `false`.
473473
IsNil { val: InsnId },
474-
Defined { op_type: usize, obj: VALUE, pushval: VALUE, v: InsnId },
474+
Defined { op_type: usize, obj: VALUE, pushval: VALUE, v: InsnId, state: InsnId },
475475
GetConstantPath { ic: *const iseq_inline_constant_cache, state: InsnId },
476476

477477
/// Get a global variable named `id`
@@ -1172,7 +1172,7 @@ impl Function {
11721172
&ArrayDup { val, state } => ArrayDup { val: find!(val), state },
11731173
&HashDup { val, state } => HashDup { val: find!(val), state },
11741174
&CCall { cfun, ref args, name, return_type, elidable } => CCall { cfun, args: find_vec!(args), name, return_type, elidable },
1175-
&Defined { op_type, obj, pushval, v } => Defined { op_type, obj, pushval, v: find!(v) },
1175+
&Defined { op_type, obj, pushval, v, state } => Defined { op_type, obj, pushval, v: find!(v), state: find!(state) },
11761176
&DefinedIvar { self_val, pushval, id, state } => DefinedIvar { self_val: find!(self_val), pushval, id, state },
11771177
&NewArray { ref elements, state } => NewArray { elements: find_vec!(elements), state: find!(state) },
11781178
&NewHash { ref elements, state } => {
@@ -2770,7 +2770,8 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
27702770
let obj = get_arg(pc, 1);
27712771
let pushval = get_arg(pc, 2);
27722772
let v = state.stack_pop()?;
2773-
state.stack_push(fun.push_insn(block, Insn::Defined { op_type, obj, pushval, v }));
2773+
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
2774+
state.stack_push(fun.push_insn(block, Insn::Defined { op_type, obj, pushval, v, state: exit_id }));
27742775
}
27752776
YARVINSN_definedivar => {
27762777
// (ID id, IVC ic, VALUE pushval)
@@ -4043,12 +4044,12 @@ mod tests {
40434044
fn test@<compiled>:2:
40444045
bb0(v0:BasicObject):
40454046
v2:NilClass = Const Value(nil)
4046-
v3:BasicObject = Defined constant, v2
4047-
v4:BasicObject = Defined func, v0
4048-
v5:NilClass = Const Value(nil)
4049-
v6:BasicObject = Defined global-variable, v5
4050-
v8:ArrayExact = NewArray v3, v4, v6
4051-
Return v8
4047+
v4:BasicObject = Defined constant, v2
4048+
v6:BasicObject = Defined func, v0
4049+
v7:NilClass = Const Value(nil)
4050+
v9:BasicObject = Defined global-variable, v7
4051+
v11:ArrayExact = NewArray v4, v6, v9
4052+
Return v11
40524053
"#]]);
40534054
}
40544055

0 commit comments

Comments
 (0)