summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Wu <[email protected]>2025-05-28 17:40:54 -0400
committerAlan Wu <[email protected]>2025-06-04 06:23:30 -0400
commit6f0f84e5dd1fc603a646d744d64eedcfef43f7c1 (patch)
tree1e363c20f66fff3aff84019034fe403a7b3b1ebf
parent8070d5d97d0b1ff4f2457326d7af325560ac9ec7 (diff)
ZJIT: Parse opt_aref_with into HIR
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/13468
-rw-r--r--zjit/src/hir.rs45
1 files changed, 40 insertions, 5 deletions
diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs
index eb4198aaca..68d6ac1b8f 100644
--- a/zjit/src/hir.rs
+++ b/zjit/src/hir.rs
@@ -4,11 +4,7 @@
#![allow(non_upper_case_globals)]
use crate::{
- cruby::*,
- options::{get_option, DumpHIR},
- profile::{get_or_create_iseq_payload, IseqPayload},
- state::ZJITState,
- cast::IntoUsize,
+ cast::IntoUsize, cruby::*, options::{get_option, DumpHIR}, profile::{get_or_create_iseq_payload, IseqPayload}, state::ZJITState
};
use std::{
cell::RefCell,
@@ -2195,7 +2191,32 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
n -= 1;
}
}
+ YARVINSN_opt_aref_with => {
+ // NB: opt_aref_with has an instruction argument for the call at get_arg(0)
+ let cd: *const rb_call_data = get_arg(pc, 1).as_ptr();
+ let call_info = unsafe { rb_get_call_data_ci(cd) };
+ if unknown_call_type(unsafe { rb_vm_ci_flag(call_info) }) {
+ // Unknown call type; side-exit into the interpreter
+ let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
+ fun.push_insn(block, Insn::SideExit { state: exit_id });
+ break; // End the block
+ }
+ let argc = unsafe { vm_ci_argc((*cd).ci) };
+
+ let method_name = unsafe {
+ let mid = rb_vm_ci_mid(call_info);
+ mid.contents_lossy().into_owned()
+ };
+
+ assert_eq!(1, argc, "opt_aref_with should only be emitted for argc=1");
+ let aref_arg = fun.push_insn(block, Insn::Const { val: Const::Value(get_arg(pc, 0)) });
+ let args = vec![aref_arg];
+ let recv = state.stack_pop()?;
+ let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
+ let send = fun.push_insn(block, Insn::SendWithoutBlock { self_val: recv, call_info: CallInfo { method_name }, cd, args, state: exit_id });
+ state.stack_push(send);
+ }
YARVINSN_opt_neq => {
// NB: opt_neq has two cd; get_arg(0) is for eq and get_arg(1) is for neq
let cd: *const rb_call_data = get_arg(pc, 1).as_ptr();
@@ -3598,6 +3619,20 @@ mod tests {
}
#[test]
+ fn test_aref_with() {
+ eval("
+ def test(a) = a['string lit triggers aref_with']
+ ");
+ assert_method_hir("test", expect![[r#"
+ fn test:
+ bb0(v0:BasicObject):
+ v2:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
+ v4:BasicObject = SendWithoutBlock v0, :[], v2
+ Return v4
+ "#]]);
+ }
+
+ #[test]
fn test_branchnil() {
eval("
def test(x) = x&.itself