|
4 | 4 | #![allow(non_upper_case_globals)] |
5 | 5 |
|
6 | 6 | use crate::{ |
7 | | - cruby::*, |
8 | | - options::{get_option, DumpHIR}, |
9 | | - profile::{get_or_create_iseq_payload, IseqPayload}, |
10 | | - state::ZJITState, |
11 | | - cast::IntoUsize, |
| 7 | + cast::IntoUsize, cruby::*, options::{get_option, DumpHIR}, profile::{get_or_create_iseq_payload, IseqPayload}, state::ZJITState |
12 | 8 | }; |
13 | 9 | use std::{ |
14 | 10 | cell::RefCell, |
@@ -2195,7 +2191,32 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> { |
2195 | 2191 | n -= 1; |
2196 | 2192 | } |
2197 | 2193 | } |
| 2194 | + YARVINSN_opt_aref_with => { |
| 2195 | + // NB: opt_aref_with has an instruction argument for the call at get_arg(0) |
| 2196 | + let cd: *const rb_call_data = get_arg(pc, 1).as_ptr(); |
| 2197 | + let call_info = unsafe { rb_get_call_data_ci(cd) }; |
| 2198 | + if unknown_call_type(unsafe { rb_vm_ci_flag(call_info) }) { |
| 2199 | + // Unknown call type; side-exit into the interpreter |
| 2200 | + let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state }); |
| 2201 | + fun.push_insn(block, Insn::SideExit { state: exit_id }); |
| 2202 | + break; // End the block |
| 2203 | + } |
| 2204 | + let argc = unsafe { vm_ci_argc((*cd).ci) }; |
| 2205 | + |
| 2206 | + let method_name = unsafe { |
| 2207 | + let mid = rb_vm_ci_mid(call_info); |
| 2208 | + mid.contents_lossy().into_owned() |
| 2209 | + }; |
| 2210 | + |
| 2211 | + assert_eq!(1, argc, "opt_aref_with should only be emitted for argc=1"); |
| 2212 | + let aref_arg = fun.push_insn(block, Insn::Const { val: Const::Value(get_arg(pc, 0)) }); |
| 2213 | + let args = vec![aref_arg]; |
2198 | 2214 |
|
| 2215 | + let recv = state.stack_pop()?; |
| 2216 | + let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state }); |
| 2217 | + let send = fun.push_insn(block, Insn::SendWithoutBlock { self_val: recv, call_info: CallInfo { method_name }, cd, args, state: exit_id }); |
| 2218 | + state.stack_push(send); |
| 2219 | + } |
2199 | 2220 | YARVINSN_opt_neq => { |
2200 | 2221 | // NB: opt_neq has two cd; get_arg(0) is for eq and get_arg(1) is for neq |
2201 | 2222 | let cd: *const rb_call_data = get_arg(pc, 1).as_ptr(); |
@@ -3597,6 +3618,20 @@ mod tests { |
3597 | 3618 | "#]]); |
3598 | 3619 | } |
3599 | 3620 |
|
| 3621 | + #[test] |
| 3622 | + fn test_aref_with() { |
| 3623 | + eval(" |
| 3624 | + def test(a) = a['string lit triggers aref_with'] |
| 3625 | + "); |
| 3626 | + assert_method_hir("test", expect![[r#" |
| 3627 | + fn test: |
| 3628 | + bb0(v0:BasicObject): |
| 3629 | + v2:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000)) |
| 3630 | + v4:BasicObject = SendWithoutBlock v0, :[], v2 |
| 3631 | + Return v4 |
| 3632 | + "#]]); |
| 3633 | + } |
| 3634 | + |
3600 | 3635 | #[test] |
3601 | 3636 | fn test_branchnil() { |
3602 | 3637 | eval(" |
|
0 commit comments