Skip to content

Commit 85524c3

Browse files
committed
ZJIT: Implement defined? codegen for non-yield calls
1 parent 24d0b45 commit 85524c3

3 files changed

Lines changed: 43 additions & 12 deletions

File tree

test/ruby/test_zjit.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,6 +1043,26 @@ def +(_) = 100
10431043
}
10441044
end
10451045

1046+
def test_defined_with_defined_values
1047+
assert_compiles '["constant", "method", "global-variable"]', %q{
1048+
class Foo; end
1049+
def bar; end
1050+
$ruby = 1
1051+
1052+
def test = return defined?(Foo), defined?(bar), defined?($ruby)
1053+
1054+
test
1055+
}, insns: [:defined]
1056+
end
1057+
1058+
def test_defined_with_undefined_values
1059+
assert_compiles '[nil, nil, nil]', %q{
1060+
def test = return defined?(Foo), defined?(bar), defined?($ruby)
1061+
1062+
test
1063+
}, insns: [:defined]
1064+
end
1065+
10461066
def test_defined_yield
10471067
assert_compiles "nil", "defined?(yield)"
10481068
assert_compiles '[nil, nil, "yield"]', %q{

zjit/src/codegen.rs

Lines changed: 13 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,17 @@ 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+
// TODO: Inline the cases for each op_type
463+
// Call vm_defined(ec, reg_cfp, op_type, obj, v)
464+
let def_result = asm_ccall!(asm, rb_vm_defined, EC, CFP, op_type.into(), obj.into(), tested_value);
465+
466+
asm.test(def_result, def_result);
467+
Some(asm.csel_nz(pushval.into(), Qnil.into()))
468+
}
459469
}
460470
}
461471

zjit/src/hir.rs

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

478478
/// Get a global variable named `id`
@@ -1173,7 +1173,7 @@ impl Function {
11731173
&ArrayDup { val, state } => ArrayDup { val: find!(val), state },
11741174
&HashDup { val, state } => HashDup { val: find!(val), state },
11751175
&CCall { cfun, ref args, name, return_type, elidable } => CCall { cfun, args: find_vec!(args), name, return_type, elidable },
1176-
&Defined { op_type, obj, pushval, v } => Defined { op_type, obj, pushval, v: find!(v) },
1176+
&Defined { op_type, obj, pushval, v, state } => Defined { op_type, obj, pushval, v: find!(v), state: find!(state) },
11771177
&DefinedIvar { self_val, pushval, id, state } => DefinedIvar { self_val: find!(self_val), pushval, id, state },
11781178
&NewArray { ref elements, state } => NewArray { elements: find_vec!(elements), state: find!(state) },
11791179
&NewHash { ref elements, state } => {
@@ -2786,7 +2786,8 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
27862786
let obj = get_arg(pc, 1);
27872787
let pushval = get_arg(pc, 2);
27882788
let v = state.stack_pop()?;
2789-
state.stack_push(fun.push_insn(block, Insn::Defined { op_type, obj, pushval, v }));
2789+
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
2790+
state.stack_push(fun.push_insn(block, Insn::Defined { op_type, obj, pushval, v, state: exit_id }));
27902791
}
27912792
YARVINSN_definedivar => {
27922793
// (ID id, IVC ic, VALUE pushval)
@@ -4059,12 +4060,12 @@ mod tests {
40594060
fn test@<compiled>:2:
40604061
bb0(v0:BasicObject):
40614062
v2:NilClass = Const Value(nil)
4062-
v3:BasicObject = Defined constant, v2
4063-
v4:BasicObject = Defined func, v0
4064-
v5:NilClass = Const Value(nil)
4065-
v6:BasicObject = Defined global-variable, v5
4066-
v8:ArrayExact = NewArray v3, v4, v6
4067-
Return v8
4063+
v4:BasicObject = Defined constant, v2
4064+
v6:BasicObject = Defined func, v0
4065+
v7:NilClass = Const Value(nil)
4066+
v9:BasicObject = Defined global-variable, v7
4067+
v11:ArrayExact = NewArray v4, v6, v9
4068+
Return v11
40684069
"#]]);
40694070
}
40704071

0 commit comments

Comments
 (0)