summaryrefslogtreecommitdiff
path: root/zjit/src/hir.rs
diff options
context:
space:
mode:
Diffstat (limited to 'zjit/src/hir.rs')
-rw-r--r--zjit/src/hir.rs89
1 files changed, 83 insertions, 6 deletions
diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs
index f988b629d9..45a9024ca9 100644
--- a/zjit/src/hir.rs
+++ b/zjit/src/hir.rs
@@ -392,6 +392,11 @@ pub enum Insn {
Defined { op_type: usize, obj: VALUE, pushval: VALUE, v: InsnId },
GetConstantPath { ic: *const iseq_inline_constant_cache },
+ /// Get a global variable named `id`
+ GetGlobal { id: ID, state: InsnId },
+ /// Set a global variable named `id` to `val`
+ SetGlobal { id: ID, val: InsnId, state: InsnId },
+
//NewObject?
/// Get an instance variable `id` from `self_val`
GetIvar { self_val: InsnId, id: ID, state: InsnId },
@@ -421,7 +426,15 @@ pub enum Insn {
/// Ignoring keyword arguments etc for now
SendWithoutBlock { self_val: InsnId, call_info: CallInfo, cd: *const rb_call_data, args: Vec<InsnId>, state: InsnId },
Send { self_val: InsnId, call_info: CallInfo, cd: *const rb_call_data, blockiseq: IseqPtr, args: Vec<InsnId>, state: InsnId },
- SendWithoutBlockDirect { self_val: InsnId, call_info: CallInfo, cd: *const rb_call_data, iseq: IseqPtr, args: Vec<InsnId>, state: InsnId },
+ SendWithoutBlockDirect {
+ self_val: InsnId,
+ call_info: CallInfo,
+ cd: *const rb_call_data,
+ cme: *const rb_callable_method_entry_t,
+ iseq: IseqPtr,
+ args: Vec<InsnId>,
+ state: InsnId,
+ },
/// Control flow instructions
Return { val: InsnId },
@@ -459,7 +472,7 @@ impl Insn {
Insn::ArraySet { .. } | Insn::Snapshot { .. } | Insn::Jump(_)
| Insn::IfTrue { .. } | Insn::IfFalse { .. } | Insn::Return { .. }
| Insn::PatchPoint { .. } | Insn::SetIvar { .. } | Insn::ArrayExtend { .. }
- | Insn::ArrayPush { .. } | Insn::SideExit { .. } => false,
+ | Insn::ArrayPush { .. } | Insn::SideExit { .. } | Insn::SetGlobal { .. } => false,
_ => true,
}
}
@@ -625,6 +638,8 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
Insn::DefinedIvar { self_val, id, .. } => write!(f, "DefinedIvar {self_val}, :{}", id.contents_lossy().into_owned()),
Insn::GetIvar { self_val, id, .. } => write!(f, "GetIvar {self_val}, :{}", id.contents_lossy().into_owned()),
Insn::SetIvar { self_val, id, val, .. } => write!(f, "SetIvar {self_val}, :{}, {val}", id.contents_lossy().into_owned()),
+ Insn::GetGlobal { id, .. } => write!(f, "GetGlobal :{}", id.contents_lossy().into_owned()),
+ Insn::SetGlobal { id, val, .. } => write!(f, "SetGlobal :{}, {val}", id.contents_lossy().into_owned()),
Insn::ToArray { val, .. } => write!(f, "ToArray {val}"),
Insn::ToNewArray { val, .. } => write!(f, "ToNewArray {val}"),
Insn::ArrayExtend { left, right, .. } => write!(f, "ArrayExtend {left}, {right}"),
@@ -950,10 +965,11 @@ impl Function {
args: args.iter().map(|arg| find!(*arg)).collect(),
state: *state,
},
- SendWithoutBlockDirect { self_val, call_info, cd, iseq, args, state } => SendWithoutBlockDirect {
+ SendWithoutBlockDirect { self_val, call_info, cd, cme, iseq, args, state } => SendWithoutBlockDirect {
self_val: find!(*self_val),
call_info: call_info.clone(),
cd: *cd,
+ cme: *cme,
iseq: *iseq,
args: args.iter().map(|arg| find!(*arg)).collect(),
state: *state,
@@ -982,6 +998,8 @@ impl Function {
}
&NewRange { low, high, flag, state } => NewRange { low: find!(low), high: find!(high), flag, state: find!(state) },
ArrayMax { elements, state } => ArrayMax { elements: find_vec!(*elements), state: find!(*state) },
+ &GetGlobal { id, state } => GetGlobal { id, state },
+ &SetGlobal { id, val, state } => SetGlobal { id, val: find!(val), state },
&GetIvar { self_val, id, state } => GetIvar { self_val: find!(self_val), id, state },
&SetIvar { self_val, id, val, state } => SetIvar { self_val: find!(self_val), id, val, state },
&ToArray { val, state } => ToArray { val: find!(val), state },
@@ -1012,7 +1030,7 @@ impl Function {
assert!(self.insns[insn.0].has_output());
match &self.insns[insn.0] {
Insn::Param { .. } => unimplemented!("params should not be present in block.insns"),
- Insn::ArraySet { .. } | Insn::Snapshot { .. } | Insn::Jump(_)
+ Insn::SetGlobal { .. } | Insn::ArraySet { .. } | Insn::Snapshot { .. } | Insn::Jump(_)
| Insn::IfTrue { .. } | Insn::IfFalse { .. } | Insn::Return { .. }
| Insn::PatchPoint { .. } | Insn::SetIvar { .. } | Insn::ArrayExtend { .. }
| Insn::ArrayPush { .. } | Insn::SideExit { .. } =>
@@ -1063,6 +1081,7 @@ impl Function {
Insn::DefinedIvar { .. } => types::BasicObject,
Insn::GetConstantPath { .. } => types::BasicObject,
Insn::ArrayMax { .. } => types::BasicObject,
+ Insn::GetGlobal { .. } => types::BasicObject,
Insn::GetIvar { .. } => types::BasicObject,
Insn::ToNewArray { .. } => types::ArrayExact,
Insn::ToArray { .. } => types::ArrayExact,
@@ -1251,7 +1270,7 @@ impl Function {
if let Some(expected) = guard_equal_to {
self_val = self.push_insn(block, Insn::GuardBitEquals { val: self_val, expected, state });
}
- let send_direct = self.push_insn(block, Insn::SendWithoutBlockDirect { self_val, call_info, cd, iseq, args, state });
+ 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 } => {
@@ -1568,7 +1587,8 @@ impl Function {
| Insn::Test { val }
| Insn::IsNil { val } =>
worklist.push_back(val),
- Insn::GuardType { val, state, .. }
+ Insn::SetGlobal { val, state, .. }
+ | Insn::GuardType { val, state, .. }
| Insn::GuardBitEquals { val, state, .. }
| Insn::ToArray { val, state }
| Insn::ToNewArray { val, state } => {
@@ -1635,6 +1655,7 @@ impl Function {
worklist.push_back(val);
worklist.push_back(state);
}
+ Insn::GetGlobal { state, .. } |
Insn::SideExit { state } => worklist.push_back(state),
}
}
@@ -2380,6 +2401,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
YARVINSN_opt_and |
YARVINSN_opt_or |
YARVINSN_opt_not |
+ YARVINSN_opt_regexpmatch2 |
YARVINSN_opt_send_without_block => {
let cd: *const rb_call_data = get_arg(pc, 0).as_ptr();
let call_info = unsafe { rb_get_call_data_ci(cd) };
@@ -2434,6 +2456,18 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
let send = fun.push_insn(block, Insn::Send { self_val: recv, call_info: CallInfo { method_name }, cd, blockiseq, args, state: exit_id });
state.stack_push(send);
}
+ YARVINSN_getglobal => {
+ let id = ID(get_arg(pc, 0).as_u64());
+ let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
+ let result = fun.push_insn(block, Insn::GetGlobal { id, state: exit_id });
+ state.stack_push(result);
+ }
+ YARVINSN_setglobal => {
+ let id = ID(get_arg(pc, 0).as_u64());
+ let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
+ let val = state.stack_pop()?;
+ fun.push_insn(block, Insn::SetGlobal { id, val, state: exit_id });
+ }
YARVINSN_getinstancevariable => {
let id = ID(get_arg(pc, 0).as_u64());
// ic is in arg 1
@@ -3711,6 +3745,35 @@ mod tests {
}
#[test]
+ fn test_setglobal() {
+ eval("
+ def test = $foo = 1
+ test
+ ");
+ assert_method_hir_with_opcode("test", YARVINSN_setglobal, expect![[r#"
+ fn test:
+ bb0(v0:BasicObject):
+ v2:Fixnum[1] = Const Value(1)
+ SetGlobal :$foo, v2
+ Return v2
+ "#]]);
+ }
+
+ #[test]
+ fn test_getglobal() {
+ eval("
+ def test = $foo
+ test
+ ");
+ assert_method_hir_with_opcode("test", YARVINSN_getglobal, expect![[r#"
+ fn test:
+ bb0(v0:BasicObject):
+ v3:BasicObject = GetGlobal :$foo
+ Return v3
+ "#]]);
+ }
+
+ #[test]
fn test_splatarray_mut() {
eval("
def test(a) = [*a]
@@ -3879,6 +3942,20 @@ mod tests {
Return v4
"#]]);
}
+
+ #[test]
+ fn opt_regexpmatch2() {
+ eval("
+ def test(regexp, matchee) = regexp =~ matchee
+ ");
+ assert_method_hir_with_opcode("test", YARVINSN_opt_regexpmatch2, expect![[r#"
+ fn test:
+ bb0(v0:BasicObject, v1:BasicObject, v2:BasicObject):
+ v5:BasicObject = SendWithoutBlock v1, :=~, v2
+ Return v5
+ "#]]);
+ }
+
#[test]
fn test_branchnil() {
eval("