Skip to content

Commit 657b2f0

Browse files
committed
ZJIT: Parse definedivar into HIR
1 parent cd7c5a3 commit 657b2f0

File tree

1 file changed

+48
-1
lines changed

1 file changed

+48
-1
lines changed

zjit/src/hir.rs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,9 @@ pub enum Insn {
397397
GetIvar { self_val: InsnId, id: ID, state: InsnId },
398398
/// Set `self_val`'s instance variable `id` to `val`
399399
SetIvar { self_val: InsnId, id: ID, val: InsnId, state: InsnId },
400+
/// Check whether an instance variable exists on `self_val`
401+
DefinedIvar { self_val: InsnId, id: ID, pushval: VALUE, state: InsnId },
402+
400403

401404
/// Own a FrameState so that instructions can look up their dominating FrameState when
402405
/// generating deopt side-exits and frame reconstruction metadata. Does not directly generate
@@ -603,6 +606,7 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
603606
Ok(())
604607
},
605608
Insn::Snapshot { state } => write!(f, "Snapshot {}", state),
609+
Insn::DefinedIvar { self_val, id, .. } => write!(f, "DefinedIvar {self_val}, :{}", id.contents_lossy().into_owned()),
606610
Insn::GetIvar { self_val, id, .. } => write!(f, "GetIvar {self_val}, :{}", id.contents_lossy().into_owned()),
607611
Insn::SetIvar { self_val, id, val, .. } => write!(f, "SetIvar {self_val}, :{}, {val}", id.contents_lossy().into_owned()),
608612
Insn::ToArray { val, .. } => write!(f, "ToArray {val}"),
@@ -951,6 +955,7 @@ impl Function {
951955
&HashDup { val , state } => HashDup { val: find!(val), state },
952956
&CCall { cfun, ref args, name, return_type, elidable } => CCall { cfun: cfun, args: args.iter().map(|arg| find!(*arg)).collect(), name: name, return_type: return_type, elidable },
953957
&Defined { op_type, obj, pushval, v } => Defined { op_type, obj, pushval, v: find!(v) },
958+
&DefinedIvar { self_val, pushval, id, state } => DefinedIvar { self_val: find!(self_val), pushval, id, state },
954959
NewArray { elements, state } => NewArray { elements: find_vec!(*elements), state: find!(*state) },
955960
&NewHash { ref elements, state } => {
956961
let mut found_elements = vec![];
@@ -1039,6 +1044,7 @@ impl Function {
10391044
Insn::SendWithoutBlockDirect { .. } => types::BasicObject,
10401045
Insn::Send { .. } => types::BasicObject,
10411046
Insn::Defined { .. } => types::BasicObject,
1047+
Insn::DefinedIvar { .. } => types::BasicObject,
10421048
Insn::GetConstantPath { .. } => types::BasicObject,
10431049
Insn::ArrayMax { .. } => types::BasicObject,
10441050
Insn::GetIvar { .. } => types::BasicObject,
@@ -1599,7 +1605,7 @@ impl Function {
15991605
worklist.push_back(state);
16001606
}
16011607
Insn::CCall { args, .. } => worklist.extend(args),
1602-
Insn::GetIvar { self_val, state, .. } => {
1608+
Insn::GetIvar { self_val, state, .. } | Insn::DefinedIvar { self_val, state, .. } => {
16031609
worklist.push_back(self_val);
16041610
worklist.push_back(state);
16051611
}
@@ -2165,6 +2171,14 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
21652171
let v = state.stack_pop()?;
21662172
state.stack_push(fun.push_insn(block, Insn::Defined { op_type, obj, pushval, v }));
21672173
}
2174+
YARVINSN_definedivar => {
2175+
// (ID id, IVC ic, VALUE pushval)
2176+
let id = ID(get_arg(pc, 0).as_u64());
2177+
let pushval = get_arg(pc, 2);
2178+
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
2179+
let self_val = fun.push_insn(block, Insn::PutSelf);
2180+
state.stack_push(fun.push_insn(block, Insn::DefinedIvar { self_val, id, pushval, state: exit_id }));
2181+
}
21682182
YARVINSN_opt_getconstant_path => {
21692183
let ic = get_arg(pc, 0).as_ptr();
21702184
state.stack_push(fun.push_insn(block, Insn::GetConstantPath { ic }));
@@ -2991,6 +3005,39 @@ mod tests {
29913005
"#]]);
29923006
}
29933007

3008+
#[test]
3009+
fn defined_ivar() {
3010+
eval("
3011+
def test = defined?(@foo)
3012+
");
3013+
assert_method_hir_with_opcode("test", YARVINSN_definedivar, expect![[r#"
3014+
fn test:
3015+
bb0():
3016+
v2:BasicObject = PutSelf
3017+
v3:BasicObject = DefinedIvar v2, :@foo
3018+
Return v3
3019+
"#]]);
3020+
}
3021+
3022+
#[test]
3023+
fn defined() {
3024+
eval("
3025+
def test = return defined?(SeaChange), defined?(favourite), defined?($ruby)
3026+
");
3027+
assert_method_hir_with_opcode("test", YARVINSN_defined, expect![[r#"
3028+
fn test:
3029+
bb0():
3030+
v1:NilClassExact = Const Value(nil)
3031+
v2:BasicObject = Defined constant, v1
3032+
v3:BasicObject = PutSelf
3033+
v4:BasicObject = Defined func, v3
3034+
v5:NilClassExact = Const Value(nil)
3035+
v6:BasicObject = Defined global-variable, v5
3036+
v8:ArrayExact = NewArray v2, v4, v6
3037+
Return v8
3038+
"#]]);
3039+
}
3040+
29943041
#[test]
29953042
fn test_return_const() {
29963043
eval("

0 commit comments

Comments
 (0)