From baec95c85aa7e1ae80180eaf392277e6ecf1a1f3 Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Mon, 29 Sep 2025 08:55:19 -0700 Subject: [PATCH 1/3] ZJIT: Incorporate parameter loads into HIR (#14659) --- zjit/src/codegen.rs | 122 +---- zjit/src/cruby.rs | 16 +- zjit/src/hir.rs | 1096 +++++++++++++++++++++++++++++++------------ 3 files changed, 826 insertions(+), 408 deletions(-) diff --git a/zjit/src/codegen.rs b/zjit/src/codegen.rs index 8230d39522504f..2845aaf719963c 100644 --- a/zjit/src/codegen.rs +++ b/zjit/src/codegen.rs @@ -16,7 +16,7 @@ use crate::stats::{exit_counter_for_compile_error, incr_counter, incr_counter_by use crate::stats::{counter_ptr, with_time_stat, Counter, send_fallback_counter, Counter::{compile_time_ns, exit_compile_error}}; use crate::{asm::CodeBlock, cruby::*, options::debug, virtualmem::CodePtr}; use crate::backend::lir::{self, asm_comment, asm_ccall, Assembler, Opnd, Target, CFP, C_ARG_OPNDS, C_RET_OPND, EC, NATIVE_STACK_PTR, NATIVE_BASE_PTR, SCRATCH_OPND, SP}; -use crate::hir::{iseq_to_hir, Block, BlockId, BranchEdge, Invariant, MethodType, RangeType, SideExitReason::{self, *}, SpecialBackrefSymbol, SpecialObjectType, SELF_PARAM_IDX}; +use crate::hir::{iseq_to_hir, BlockId, BranchEdge, Invariant, MethodType, RangeType, SideExitReason::{self, *}, SpecialBackrefSymbol, SpecialObjectType}; use crate::hir::{Const, FrameState, Function, Insn, InsnId}; use crate::hir_type::{types, Type}; use crate::options::get_option; @@ -126,7 +126,7 @@ fn gen_iseq_entry_point(cb: &mut CodeBlock, iseq: IseqPtr, jit_exception: bool) })?; // Compile an entry point to the JIT code - gen_entry(cb, iseq, &function, start_ptr).inspect_err(|err| { + gen_entry(cb, iseq, start_ptr).inspect_err(|err| { debug!("{err:?}: gen_entry failed: {}", iseq_get_location(iseq, 0)); }) } @@ -164,11 +164,10 @@ fn register_with_perf(iseq_name: String, start_ptr: usize, code_size: usize) { } /// Compile a JIT entry -fn gen_entry(cb: &mut CodeBlock, iseq: IseqPtr, function: &Function, function_ptr: CodePtr) -> Result { +fn gen_entry(cb: &mut CodeBlock, iseq: IseqPtr, function_ptr: CodePtr) -> Result { // Set up registers for CFP, EC, SP, and basic block arguments let mut asm = Assembler::new(); gen_entry_prologue(&mut asm, iseq); - gen_entry_params(&mut asm, iseq, function.entry_block()); // Jump to the first block using a call instruction asm.ccall(function_ptr.raw_ptr(cb), vec![]); @@ -409,8 +408,8 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio Insn::GetIvar { self_val, id, state: _ } => gen_getivar(asm, opnd!(self_val), *id), Insn::SetGlobal { id, val, state } => no_output!(gen_setglobal(jit, asm, *id, opnd!(val), &function.frame_state(*state))), Insn::GetGlobal { id, state } => gen_getglobal(jit, asm, *id, &function.frame_state(*state)), - &Insn::GetLocal { ep_offset, level } => gen_getlocal_with_ep(asm, ep_offset, level), - &Insn::SetLocal { val, ep_offset, level } => no_output!(gen_setlocal_with_ep(asm, opnd!(val), function.type_of(val), ep_offset, level)), + &Insn::GetLocal { ep_offset, level, use_sp, .. } => gen_getlocal(asm, ep_offset, level, use_sp), + &Insn::SetLocal { val, ep_offset, level } => no_output!(gen_setlocal(asm, opnd!(val), function.type_of(val), ep_offset, level)), Insn::GetConstantPath { ic, state } => gen_get_constant_path(jit, asm, *ic, &function.frame_state(*state)), Insn::SetIvar { self_val, id, val, state: _ } => no_output!(gen_setivar(asm, opnd!(self_val), *id, opnd!(val))), Insn::SideExit { state, reason } => no_output!(gen_side_exit(jit, asm, reason, &function.frame_state(*state))), @@ -430,6 +429,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio &Insn::ArrayExtend { left, right, state } => { no_output!(gen_array_extend(jit, asm, opnd!(left), opnd!(right), &function.frame_state(state))) }, &Insn::GuardShape { val, shape, state } => gen_guard_shape(jit, asm, opnd!(val), shape, &function.frame_state(state)), Insn::LoadPC => gen_load_pc(asm), + Insn::LoadSelf => gen_load_self(), &Insn::LoadIvarEmbedded { self_val, id, index } => gen_load_ivar_embedded(asm, opnd!(self_val), id, index), &Insn::LoadIvarExtended { self_val, id, index } => gen_load_ivar_extended(asm, opnd!(self_val), id, index), &Insn::ArrayMax { state, .. } @@ -537,19 +537,28 @@ fn gen_defined(jit: &JITState, asm: &mut Assembler, op_type: usize, obj: VALUE, /// Get a local variable from a higher scope or the heap. `local_ep_offset` is in number of VALUEs. /// We generate this instruction with level=0 only when the local variable is on the heap, so we /// can't optimize the level=0 case using the SP register. -fn gen_getlocal_with_ep(asm: &mut Assembler, local_ep_offset: u32, level: u32) -> lir::Opnd { +fn gen_getlocal(asm: &mut Assembler, local_ep_offset: u32, level: u32, use_sp: bool) -> lir::Opnd { + let local_ep_offset = i32::try_from(local_ep_offset).unwrap_or_else(|_| panic!("Could not convert local_ep_offset {local_ep_offset} to i32")); if level > 0 { gen_incr_counter(asm, Counter::vm_read_from_parent_iseq_local_count); } - let ep = gen_get_ep(asm, level); - let offset = -(SIZEOF_VALUE_I32 * i32::try_from(local_ep_offset).unwrap_or_else(|_| panic!("Could not convert local_ep_offset {local_ep_offset} to i32"))); - asm.load(Opnd::mem(64, ep, offset)) + let local = if use_sp { + assert_eq!(level, 0, "use_sp optimization should be used only for level=0 locals"); + let offset = -(SIZEOF_VALUE_I32 * (local_ep_offset + 1)); + Opnd::mem(64, SP, offset) + } else { + let ep = gen_get_ep(asm, level); + let offset = -(SIZEOF_VALUE_I32 * local_ep_offset); + Opnd::mem(64, ep, offset) + }; + asm.load(local) } /// Set a local variable from a higher scope or the heap. `local_ep_offset` is in number of VALUEs. /// We generate this instruction with level=0 only when the local variable is on the heap, so we /// can't optimize the level=0 case using the SP register. -fn gen_setlocal_with_ep(asm: &mut Assembler, val: Opnd, val_type: Type, local_ep_offset: u32, level: u32) { +fn gen_setlocal(asm: &mut Assembler, val: Opnd, val_type: Type, local_ep_offset: u32, level: u32) { + let local_ep_offset = c_int::try_from(local_ep_offset).unwrap_or_else(|_| panic!("Could not convert local_ep_offset {local_ep_offset} to i32")); if level > 0 { gen_incr_counter(asm, Counter::vm_write_to_parent_iseq_local_count); } @@ -558,12 +567,12 @@ fn gen_setlocal_with_ep(asm: &mut Assembler, val: Opnd, val_type: Type, local_ep // When we've proved that we're writing an immediate, // we can skip the write barrier. if val_type.is_immediate() { - let offset = -(SIZEOF_VALUE_I32 * i32::try_from(local_ep_offset).unwrap_or_else(|_| panic!("Could not convert local_ep_offset {local_ep_offset} to i32"))); + let offset = -(SIZEOF_VALUE_I32 * local_ep_offset); asm.mov(Opnd::mem(64, ep, offset), val); } else { // We're potentially writing a reference to an IMEMO/env object, // so take care of the write barrier with a function. - let local_index = c_int::try_from(local_ep_offset).ok().and_then(|idx| idx.checked_mul(-1)).unwrap_or_else(|| panic!("Could not turn {local_ep_offset} into a negative c_int")); + let local_index = local_ep_offset * -1; asm_ccall!(asm, rb_vm_env_write, ep, local_index.into(), val); } } @@ -834,6 +843,10 @@ fn gen_load_pc(asm: &mut Assembler) -> Opnd { asm.load(Opnd::mem(64, CFP, RUBY_OFFSET_CFP_PC)) } +fn gen_load_self() -> Opnd { + Opnd::mem(64, CFP, RUBY_OFFSET_CFP_SELF) +} + fn gen_load_ivar_embedded(asm: &mut Assembler, self_val: Opnd, id: ID, index: u16) -> Opnd { // See ROBJECT_FIELDS() from include/ruby/internal/core/robject.h @@ -871,53 +884,6 @@ fn gen_entry_prologue(asm: &mut Assembler, iseq: IseqPtr) { asm.mov(SP, Opnd::mem(64, CFP, RUBY_OFFSET_CFP_SP)); } -/// Assign method arguments to basic block arguments at JIT entry -fn gen_entry_params(asm: &mut Assembler, iseq: IseqPtr, entry_block: &Block) { - let num_params = entry_block.params().len() - 1; // -1 to exclude self - if num_params > 0 { - asm_comment!(asm, "set method params: {num_params}"); - - // Fill basic block parameters. - // Doing it in reverse is load-bearing. High index params have memory slots that might - // require using a register to fill. Filling them first avoids clobbering. - for idx in (0..num_params).rev() { - let param = param_opnd(idx + 1); // +1 for self - let local = gen_entry_param(asm, iseq, idx); - - // Funky offset adjustment to write into the native stack frame of the - // HIR function we'll be calling into. This only makes sense in context - // of the schedule of instructions in gen_entry() for the JIT entry point. - // - // The entry point needs to load VALUEs into native stack slots _before_ the - // frame containing the slots exists. So, we anticipate the stack frame size - // of the Function and subtract offsets based on that. - // - // native SP at entry point ─────►┌────────────┐ Native SP grows downwards - // │ │ ↓ on all arches we support. - // SP-0x8 ├────────────┤ - // │ │ - // where native SP SP-0x10├────────────┤ - // would be while │ │ - // the HIR function ────────────► └────────────┘ - // is running - match param { - Opnd::Mem(lir::Mem { base: _, disp, num_bits }) => { - let param_slot = Opnd::mem(num_bits, NATIVE_STACK_PTR, disp - Assembler::frame_size()); - asm.mov(param_slot, local); - } - // Prepare for parallel move for locals in registers - reg @ Opnd::Reg(_) => { - asm.load_into(reg, local); - } - _ => unreachable!("on entry, params are either in memory or in reg. Got {param:?}") - } - - // Assign local variables to the basic block arguments - } - } - asm.load_into(param_opnd(SELF_PARAM_IDX), Opnd::mem(VALUE_BITS, CFP, RUBY_OFFSET_CFP_SELF)); -} - /// Set branch params to basic block arguments fn gen_branch_params(jit: &mut JITState, asm: &mut Assembler, branch: &BranchEdge) { if branch.args.is_empty() { @@ -941,28 +907,6 @@ fn gen_branch_params(jit: &mut JITState, asm: &mut Assembler, branch: &BranchEdg asm.parallel_mov(moves); } -/// Get a method parameter on JIT entry. As of entry, whether EP is escaped or not solely -/// depends on the ISEQ type. -fn gen_entry_param(asm: &mut Assembler, iseq: IseqPtr, local_idx: usize) -> lir::Opnd { - let ep_offset = local_idx_to_ep_offset(iseq, local_idx); - - // If the ISEQ does not escape EP, we can optimize the local variable access using the SP register. - if !iseq_entry_escapes_ep(iseq) { - // Create a reference to the local variable using the SP register. We assume EP == BP. - // TODO: Implement the invalidation in rb_zjit_invalidate_no_ep_escape() - let offs = -(SIZEOF_VALUE_I32 * (ep_offset + 1)); - Opnd::mem(64, SP, offs) - } else { - // Get the EP of the current CFP - let ep_opnd = Opnd::mem(64, CFP, RUBY_OFFSET_CFP_EP); - let ep_reg = asm.load(ep_opnd); - - // Create a reference to the local variable using cfp->ep - let offs = -(SIZEOF_VALUE_I32 * ep_offset); - Opnd::mem(64, ep_reg, offs) - } -} - /// Compile a constant fn gen_const_value(val: VALUE) -> lir::Opnd { // Just propagate the constant value and generate nothing @@ -1817,20 +1761,6 @@ fn build_side_exit(jit: &JITState, state: &FrameState, reason: SideExitReason, l } } -/// Return true if a given ISEQ is known to escape EP to the heap on entry. -/// -/// As of vm_push_frame(), EP is always equal to BP. However, after pushing -/// a frame, some ISEQ setups call vm_bind_update_env(), which redirects EP. -fn iseq_entry_escapes_ep(iseq: IseqPtr) -> bool { - match unsafe { get_iseq_body_type(iseq) } { - //
frame is always associated to TOPLEVEL_BINDING. - ISEQ_TYPE_MAIN | - // Kernel#eval uses a heap EP when a Binding argument is not nil. - ISEQ_TYPE_EVAL => true, - _ => false, - } -} - /// Returne the maximum number of arguments for a block in a given function fn max_num_params(function: &Function) -> usize { let reverse_post_order = function.rpo(); diff --git a/zjit/src/cruby.rs b/zjit/src/cruby.rs index 9575c3d1993393..baba0992ccaef9 100644 --- a/zjit/src/cruby.rs +++ b/zjit/src/cruby.rs @@ -294,7 +294,10 @@ pub fn iseq_opcode_at_idx(iseq: IseqPtr, insn_idx: u32) -> u32 { unsafe { rb_iseq_opcode_at_pc(iseq, pc) as u32 } } -/// Return true if the ISEQ always uses a frame with escaped EP. +/// Return true if a given ISEQ is known to escape EP to the heap on entry. +/// +/// As of vm_push_frame(), EP is always equal to BP. However, after pushing +/// a frame, some ISEQ setups call vm_bind_update_env(), which redirects EP. pub fn iseq_escapes_ep(iseq: IseqPtr) -> bool { match unsafe { get_iseq_body_type(iseq) } { // The EP of the
frame points to TOPLEVEL_BINDING @@ -305,6 +308,17 @@ pub fn iseq_escapes_ep(iseq: IseqPtr) -> bool { } } +/// Index of the local variable that has a rest parameter if any +pub fn iseq_rest_param_idx(iseq: IseqPtr) -> Option { + if !iseq.is_null() && unsafe { get_iseq_flags_has_rest(iseq) } { + let opt_num = unsafe { get_iseq_body_param_opt_num(iseq) }; + let lead_num = unsafe { get_iseq_body_param_lead_num(iseq) }; + Some(opt_num + lead_num) + } else { + None + } +} + /// Iterate over all existing ISEQs pub fn for_each_iseq(mut callback: F) { unsafe extern "C" fn callback_wrapper(iseq: IseqPtr, data: *mut c_void) { diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index 598bcb00c4e082..6805854802a30a 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -589,13 +589,17 @@ pub enum Insn { /// Load cfp->pc LoadPC, + /// Load cfp->self + LoadSelf, /// Read an instance variable at the given index, embedded in the object LoadIvarEmbedded { self_val: InsnId, id: ID, index: u16 }, /// Read an instance variable at the given index, from the extended table LoadIvarExtended { self_val: InsnId, id: ID, index: u16 }, - /// Get a local variable from a higher scope or the heap - GetLocal { level: u32, ep_offset: u32 }, + /// Get a local variable from a higher scope or the heap. + /// If `use_sp` is true, it uses the SP register to optimize the read. + /// `rest_param` is used by infer_types to infer the ArrayExact type. + GetLocal { level: u32, ep_offset: u32, use_sp: bool, rest_param: bool }, /// Set a local variable in a higher scope or the heap SetLocal { level: u32, ep_offset: u32, val: InsnId }, GetSpecialSymbol { symbol_type: SpecialBackrefSymbol, state: InsnId }, @@ -769,6 +773,8 @@ impl Insn { Insn::FixnumOr { .. } => false, Insn::GetLocal { .. } => false, Insn::IsNil { .. } => false, + Insn::LoadPC => false, + Insn::LoadSelf => false, Insn::LoadIvarEmbedded { .. } => false, Insn::LoadIvarExtended { .. } => false, Insn::CCall { elidable, .. } => !elidable, @@ -992,12 +998,14 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> { Insn::DefinedIvar { self_val, id, .. } => write!(f, "DefinedIvar {self_val}, :{}", id.contents_lossy()), Insn::GetIvar { self_val, id, .. } => write!(f, "GetIvar {self_val}, :{}", id.contents_lossy()), Insn::LoadPC => write!(f, "LoadPC"), + Insn::LoadSelf => write!(f, "LoadSelf"), &Insn::LoadIvarEmbedded { self_val, id, index } => write!(f, "LoadIvarEmbedded {self_val}, :{}@{:p}", id.contents_lossy(), self.ptr_map.map_index(index as u64)), &Insn::LoadIvarExtended { self_val, id, index } => write!(f, "LoadIvarExtended {self_val}, :{}@{:p}", id.contents_lossy(), self.ptr_map.map_index(index as u64)), Insn::SetIvar { self_val, id, val, .. } => write!(f, "SetIvar {self_val}, :{}, {val}", id.contents_lossy()), Insn::GetGlobal { id, .. } => write!(f, "GetGlobal :{}", id.contents_lossy()), Insn::SetGlobal { id, val, .. } => write!(f, "SetGlobal :{}, {val}", id.contents_lossy()), - Insn::GetLocal { level, ep_offset } => write!(f, "GetLocal l{level}, EP@{ep_offset}"), + &Insn::GetLocal { level, ep_offset, use_sp: true, rest_param } => write!(f, "GetLocal l{level}, SP@{}{}", ep_offset + 1, if rest_param { ", *" } else { "" }), + &Insn::GetLocal { level, ep_offset, use_sp: false, rest_param } => write!(f, "GetLocal l{level}, EP@{ep_offset}{}", if rest_param { ", *" } else { "" }), Insn::SetLocal { val, level, ep_offset } => write!(f, "SetLocal l{level}, EP@{ep_offset}, {val}"), Insn::GetSpecialSymbol { symbol_type, .. } => write!(f, "GetSpecialSymbol {symbol_type:?}"), Insn::GetSpecialNumber { nth, .. } => write!(f, "GetSpecialNumber {nth}"), @@ -1376,6 +1384,7 @@ impl Function { | SideExit {..} | EntryPoint {..} | LoadPC + | LoadSelf | IncrCounter(_)) => result.clone(), &Snapshot { state: FrameState { iseq, insn_idx, pc, ref stack, ref locals } } => Snapshot { @@ -1593,6 +1602,7 @@ impl Function { Insn::GetGlobal { .. } => types::BasicObject, Insn::GetIvar { .. } => types::BasicObject, Insn::LoadPC => types::CPtr, + Insn::LoadSelf => types::BasicObject, Insn::LoadIvarEmbedded { .. } => types::BasicObject, Insn::LoadIvarExtended { .. } => types::BasicObject, Insn::GetSpecialSymbol { .. } => types::BasicObject, @@ -1601,6 +1611,7 @@ impl Function { Insn::ToArray { .. } => types::ArrayExact, Insn::ObjToString { .. } => types::BasicObject, Insn::AnyToString { .. } => types::String, + Insn::GetLocal { rest_param: true, .. } => types::ArrayExact, Insn::GetLocal { .. } => types::BasicObject, // The type of Snapshot doesn't really matter; it's never materialized. It's used only // as a reference for FrameState, which we use to generate side-exit code. @@ -1608,17 +1619,11 @@ impl Function { } } - /// Set self.param_types. They are copied to the param types of entry blocks. + /// Set self.param_types. They are copied to the param types of jit_entry_blocks. fn set_param_types(&mut self) { let iseq = self.iseq; let param_size = unsafe { get_iseq_body_param_size(iseq) }.as_usize(); - let rest_param_idx = if !iseq.is_null() && unsafe { get_iseq_flags_has_rest(iseq) } { - let opt_num = unsafe { get_iseq_body_param_opt_num(iseq) }; - let lead_num = unsafe { get_iseq_body_param_lead_num(iseq) }; - Some(opt_num + lead_num) - } else { - None - }; + let rest_param_idx = iseq_rest_param_idx(iseq); self.param_types.push(types::BasicObject); // self for local_idx in 0..param_size { @@ -1631,10 +1636,10 @@ impl Function { } } - /// Copy self.param_types to the param types of entry blocks. + /// Copy self.param_types to the param types of jit_entry_blocks. fn copy_param_types(&mut self) { - for entry_block in self.entry_blocks() { - let entry_params = self.blocks[entry_block.0].params.iter(); + for jit_entry_block in self.jit_entry_blocks.iter() { + let entry_params = self.blocks[jit_entry_block.0].params.iter(); let param_types = self.param_types.iter(); assert_eq!( entry_params.len(), @@ -2414,7 +2419,8 @@ impl Function { &Insn::Const { .. } | &Insn::Param { .. } | &Insn::EntryPoint { .. } - | &Insn::LoadPC { .. } + | &Insn::LoadPC + | &Insn::LoadSelf | &Insn::GetLocal { .. } | &Insn::PutSpecialObject { .. } | &Insn::IncrCounter(_) => @@ -3653,7 +3659,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result { let ep_offset = get_arg(pc, 0).as_u32(); if ep_escaped || has_blockiseq { // TODO: figure out how to drop has_blockiseq here // Read the local using EP - let val = fun.push_insn(block, Insn::GetLocal { ep_offset, level: 0 }); + let val = fun.push_insn(block, Insn::GetLocal { ep_offset, level: 0, use_sp: false, rest_param: false }); state.setlocal(ep_offset, val); // remember the result to spill on side-exits state.stack_push(val); } else { @@ -3687,7 +3693,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result { } YARVINSN_getlocal_WC_1 => { let ep_offset = get_arg(pc, 0).as_u32(); - state.stack_push(fun.push_insn(block, Insn::GetLocal { ep_offset, level: 1 })); + state.stack_push(fun.push_insn(block, Insn::GetLocal { ep_offset, level: 1, use_sp: false, rest_param: false })); } YARVINSN_setlocal_WC_1 => { let ep_offset = get_arg(pc, 0).as_u32(); @@ -3696,7 +3702,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result { YARVINSN_getlocal => { let ep_offset = get_arg(pc, 0).as_u32(); let level = get_arg(pc, 1).as_u32(); - state.stack_push(fun.push_insn(block, Insn::GetLocal { ep_offset, level })); + state.stack_push(fun.push_insn(block, Insn::GetLocal { ep_offset, level, use_sp: false, rest_param: false })); } YARVINSN_setlocal => { let ep_offset = get_arg(pc, 0).as_u32(); @@ -3896,7 +3902,8 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result { // or not used after this. Max thinks we could eventually DCE them. for local_idx in 0..state.locals.len() { let ep_offset = local_idx_to_ep_offset(iseq, local_idx) as u32; - let val = fun.push_insn(block, Insn::GetLocal { ep_offset, level: 0 }); + // TODO: We could use `use_sp: true` with PatchPoint + let val = fun.push_insn(block, Insn::GetLocal { ep_offset, level: 0, use_sp: false, rest_param: false }); state.setlocal(ep_offset, val); } } @@ -3925,7 +3932,8 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result { // Reload locals that may have been modified by the blockiseq. for local_idx in 0..state.locals.len() { let ep_offset = local_idx_to_ep_offset(iseq, local_idx) as u32; - let val = fun.push_insn(block, Insn::GetLocal { ep_offset, level: 0 }); + // TODO: We could use `use_sp: true` with PatchPoint + let val = fun.push_insn(block, Insn::GetLocal { ep_offset, level: 0, use_sp: false, rest_param: false }); state.setlocal(ep_offset, val); } } @@ -3955,7 +3963,8 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result { // or not used after this. Max thinks we could eventually DCE them. for local_idx in 0..state.locals.len() { let ep_offset = local_idx_to_ep_offset(iseq, local_idx) as u32; - let val = fun.push_insn(block, Insn::GetLocal { ep_offset, level: 0 }); + // TODO: We could use `use_sp: true` with PatchPoint + let val = fun.push_insn(block, Insn::GetLocal { ep_offset, level: 0, use_sp: false, rest_param: false }); state.setlocal(ep_offset, val); } } @@ -4199,30 +4208,51 @@ fn compile_entry_block(fun: &mut Function, jit_entry_insns: &Vec) { } } +/// Compile initial locals for an entry_block for the interpreter +fn compile_entry_state(fun: &mut Function, entry_block: BlockId) -> (InsnId, FrameState) { + let iseq = fun.iseq; + let param_size = unsafe { get_iseq_body_param_size(iseq) }.as_usize(); + let rest_param_idx = iseq_rest_param_idx(iseq); + + let self_param = fun.push_insn(entry_block, Insn::LoadSelf); + let mut entry_state = FrameState::new(iseq); + for local_idx in 0..num_locals(iseq) { + if local_idx < param_size { + let ep_offset = local_idx_to_ep_offset(iseq, local_idx) as u32; + let use_sp = !iseq_escapes_ep(iseq); // If the ISEQ does not escape EP, we can assume EP + 1 == SP + let rest_param = Some(local_idx as i32) == rest_param_idx; + entry_state.locals.push(fun.push_insn(entry_block, Insn::GetLocal { level: 0, ep_offset, use_sp, rest_param })); + } else { + entry_state.locals.push(fun.push_insn(entry_block, Insn::Const { val: Const::Value(Qnil) })); + } + } + (self_param, entry_state) +} + /// Compile a jit_entry_block fn compile_jit_entry_block(fun: &mut Function, jit_entry_idx: usize, target_block: BlockId) { let jit_entry_block = fun.jit_entry_blocks[jit_entry_idx]; fun.push_insn(jit_entry_block, Insn::EntryPoint { jit_entry_idx: Some(jit_entry_idx) }); // Prepare entry_state with basic block params - let (self_param, entry_state) = compile_entry_state(fun, jit_entry_block); + let (self_param, entry_state) = compile_jit_entry_state(fun, jit_entry_block); // Jump to target_block fun.push_insn(jit_entry_block, Insn::Jump(BranchEdge { target: target_block, args: entry_state.as_args(self_param) })); } -/// Compile params and initial locals for an entry block -fn compile_entry_state(fun: &mut Function, entry_block: BlockId) -> (InsnId, FrameState) { +/// Compile params and initial locals for a jit_entry_block +fn compile_jit_entry_state(fun: &mut Function, jit_entry_block: BlockId) -> (InsnId, FrameState) { let iseq = fun.iseq; let param_size = unsafe { get_iseq_body_param_size(iseq) }.as_usize(); - let self_param = fun.push_insn(entry_block, Insn::Param { idx: SELF_PARAM_IDX }); + let self_param = fun.push_insn(jit_entry_block, Insn::Param { idx: SELF_PARAM_IDX }); let mut entry_state = FrameState::new(iseq); for local_idx in 0..num_locals(iseq) { if local_idx < param_size { - entry_state.locals.push(fun.push_insn(entry_block, Insn::Param { idx: local_idx + 1 })); // +1 for self + entry_state.locals.push(fun.push_insn(jit_entry_block, Insn::Param { idx: local_idx + 1 })); // +1 for self } else { - entry_state.locals.push(fun.push_insn(entry_block, Insn::Const { val: Const::Value(Qnil) })); + entry_state.locals.push(fun.push_insn(jit_entry_block, Insn::Const { val: Const::Value(Qnil) })); } } (self_param, entry_state) @@ -4541,18 +4571,6 @@ mod infer_tests { }); } - #[test] - fn test_unknown() { - crate::cruby::with_rubyvm(|| { - let mut function = Function::new(std::ptr::null()); - let param = function.push_insn(function.entry_block, Insn::Param { idx: SELF_PARAM_IDX }); - function.param_types.push(types::BasicObject); // self - let val = function.push_insn(function.entry_block, Insn::Test { val: param }); - function.infer_types(); - assert_bit_equal(function.type_of(val), types::CBool); - }); - } - #[test] fn newarray() { let mut function = Function::new(std::ptr::null()); @@ -4627,8 +4645,11 @@ mod snapshot_tests { eval("def test(a, b) = [a, b]"); assert_snapshot!(hir_string("test"), @r" fn test@:1: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -4729,8 +4750,10 @@ mod tests { eval("def test(x=1) = 123"); assert_snapshot!(hir_string("test"), @r" fn test@:1: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 v3:CPtr = LoadPC v4:CPtr[CPtr(0x1000)] = Const CPtr(0x1008) v5:CBool = IsBitEqual v3, v4 @@ -4758,8 +4781,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_putobject); assert_snapshot!(hir_string("test"), @r" fn test@:1: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -4777,8 +4801,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_newarray); assert_snapshot!(hir_string("test"), @r" fn test@:1: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -4796,8 +4821,10 @@ mod tests { assert_contains_opcode("test", YARVINSN_newarray); assert_snapshot!(hir_string("test"), @r" fn test@:1: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -4815,8 +4842,11 @@ mod tests { assert_contains_opcode("test", YARVINSN_newarray); assert_snapshot!(hir_string("test"), @r" fn test@:1: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -4834,8 +4864,10 @@ mod tests { assert_contains_opcode("test", YARVINSN_newrange); assert_snapshot!(hir_string("test"), @r" fn test@:1: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -4854,8 +4886,11 @@ mod tests { assert_contains_opcode("test", YARVINSN_newrange); assert_snapshot!(hir_string("test"), @r" fn test@:1: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -4873,8 +4908,10 @@ mod tests { assert_contains_opcode("test", YARVINSN_newrange); assert_snapshot!(hir_string("test"), @r" fn test@:1: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -4893,8 +4930,11 @@ mod tests { assert_contains_opcode("test", YARVINSN_newrange); assert_snapshot!(hir_string("test"), @r" fn test@:1: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -4912,8 +4952,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_duparray); assert_snapshot!(hir_string("test"), @r" fn test@:1: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -4932,8 +4973,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_duphash); assert_snapshot!(hir_string("test"), @r" fn test@:1: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -4952,8 +4994,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_newhash); assert_snapshot!(hir_string("test"), @r" fn test@:1: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -4971,8 +5014,11 @@ mod tests { assert_contains_opcode("test", YARVINSN_newhash); assert_snapshot!(hir_string("test"), @r" fn test@:1: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -4992,8 +5038,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_putchilledstring); assert_snapshot!(hir_string("test"), @r" fn test@:1: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -5012,8 +5059,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_putobject); assert_snapshot!(hir_string("test"), @r" fn test@:1: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -5031,8 +5079,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_putobject); assert_snapshot!(hir_string("test"), @r" fn test@:1: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -5050,8 +5099,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_putobject); assert_snapshot!(hir_string("test"), @r" fn test@:1: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -5069,8 +5119,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_putobject); assert_snapshot!(hir_string("test"), @r" fn test@:1: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -5088,8 +5139,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_plus); assert_snapshot!(hir_string("test"), @r" fn test@:1: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -5111,8 +5163,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_hash_freeze); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -5136,8 +5189,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_hash_freeze); assert_snapshot!(hir_string("test"), @r" fn test@:5: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -5155,8 +5209,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_ary_freeze); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -5180,8 +5235,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_ary_freeze); assert_snapshot!(hir_string("test"), @r" fn test@:5: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -5199,8 +5255,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_str_freeze); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -5224,8 +5281,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_str_freeze); assert_snapshot!(hir_string("test"), @r" fn test@:5: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -5243,8 +5301,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_str_uminus); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -5268,8 +5327,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_str_uminus); assert_snapshot!(hir_string("test"), @r" fn test@:5: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -5290,8 +5350,9 @@ mod tests { assert_contains_opcodes("test", &[YARVINSN_getlocal_WC_0, YARVINSN_setlocal_WC_0]); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf v2:NilClass = Const Value(nil) Jump bb2(v1, v2) bb1(v5:BasicObject): @@ -5329,8 +5390,9 @@ mod tests { YARVINSN_getlocal, YARVINSN_setlocal]); assert_snapshot!(hir_string("test"), @r" fn block (3 levels) in @:10: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -5360,8 +5422,10 @@ mod tests { assert_contains_opcode("test", YARVINSN_setlocal_WC_0); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 v3:NilClass = Const Value(nil) v4:CPtr = LoadPC v5:CPtr[CPtr(0x1000)] = Const CPtr(0x1008) @@ -5411,8 +5475,10 @@ mod tests { "); assert_snapshot!(hir_string_proc("test"), @r" fn block in test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -5431,8 +5497,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_definedivar); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -5458,8 +5525,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_definedivar); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -5487,8 +5555,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_defined); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -5519,8 +5588,10 @@ mod tests { assert_contains_opcode("test", YARVINSN_leave); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -5553,8 +5624,10 @@ mod tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 v3:NilClass = Const Value(nil) Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject): @@ -5589,8 +5662,11 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_plus); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -5611,8 +5687,11 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_minus); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -5633,8 +5712,11 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_mult); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -5655,8 +5737,11 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_div); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -5677,8 +5762,11 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_mod); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -5699,8 +5787,11 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_eq); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -5721,8 +5812,11 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_neq); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -5743,8 +5837,11 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_lt); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -5765,8 +5862,11 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_le); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -5787,8 +5887,11 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_gt); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -5816,8 +5919,9 @@ mod tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf v2:NilClass = Const Value(nil) v3:NilClass = Const Value(nil) Jump bb2(v1, v2, v3) @@ -5861,8 +5965,11 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_ge); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -5888,8 +5995,9 @@ mod tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf v2:NilClass = Const Value(nil) Jump bb2(v1, v2) bb1(v5:BasicObject): @@ -5924,8 +6032,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_send_without_block); assert_snapshot!(hir_string("test"), @r" fn test@:6: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -5952,8 +6061,10 @@ mod tests { assert_contains_opcode("test", YARVINSN_send); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -5977,8 +6088,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_intern); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -6002,8 +6114,9 @@ mod tests { // The 2 string literals have the same address because they're deduped. assert_snapshot!(hir_string("test"), @r" fn test@:1: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -6030,8 +6143,10 @@ mod tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -6049,8 +6164,10 @@ mod tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -6069,8 +6186,10 @@ mod tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -6088,8 +6207,10 @@ mod tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -6110,8 +6231,9 @@ mod tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -6130,8 +6252,9 @@ mod tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -6150,8 +6273,9 @@ mod tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -6171,8 +6295,10 @@ mod tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -6187,8 +6313,10 @@ mod tests { eval("def forwardable(...) = nil"); assert_snapshot!(hir_string("forwardable"), @r" fn forwardable@:1: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -6209,8 +6337,10 @@ mod tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -6237,8 +6367,10 @@ mod tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:ArrayExact): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:ArrayExact = GetLocal l0, SP@4, * Jump bb2(v1, v2) bb1(v5:BasicObject, v6:ArrayExact): EntryPoint JIT(0) @@ -6258,8 +6390,10 @@ mod tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -6278,8 +6412,13 @@ mod tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject, v3:ArrayExact, v4:BasicObject, v5:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@8 + v3:ArrayExact = GetLocal l0, SP@7, * + v4:BasicObject = GetLocal l0, SP@6 + v5:BasicObject = GetLocal l0, SP@5 v6:NilClass = Const Value(nil) Jump bb2(v1, v2, v3, v4, v5, v6) bb1(v9:BasicObject, v10:BasicObject, v11:ArrayExact, v12:BasicObject, v13:BasicObject): @@ -6304,8 +6443,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_new); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -6337,8 +6477,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_newarray_send); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -6359,8 +6500,11 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_newarray_send); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -6386,8 +6530,11 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_newarray_send); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@7 + v3:BasicObject = GetLocal l0, SP@6 v4:NilClass = Const Value(nil) v5:NilClass = Const Value(nil) Jump bb2(v1, v2, v3, v4, v5) @@ -6415,8 +6562,11 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_newarray_send); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@7 + v3:BasicObject = GetLocal l0, SP@6 v4:NilClass = Const Value(nil) v5:NilClass = Const Value(nil) Jump bb2(v1, v2, v3, v4, v5) @@ -6444,8 +6594,11 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_newarray_send); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@7 + v3:BasicObject = GetLocal l0, SP@6 v4:NilClass = Const Value(nil) v5:NilClass = Const Value(nil) Jump bb2(v1, v2, v3, v4, v5) @@ -6477,8 +6630,11 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_newarray_send); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@7 + v3:BasicObject = GetLocal l0, SP@6 v4:NilClass = Const Value(nil) v5:NilClass = Const Value(nil) Jump bb2(v1, v2, v3, v4, v5) @@ -6501,8 +6657,11 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_length); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -6523,8 +6682,11 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_size); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -6546,8 +6708,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_getinstancevariable); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -6569,8 +6732,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_setinstancevariable); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -6593,8 +6757,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_setglobal); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -6616,8 +6781,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_getglobal); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -6637,8 +6803,10 @@ mod tests { assert_contains_opcode("test", YARVINSN_splatarray); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -6658,8 +6826,10 @@ mod tests { assert_contains_opcode("test", YARVINSN_concattoarray); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -6682,8 +6852,10 @@ mod tests { assert_contains_opcode("test", YARVINSN_pushtoarray); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -6705,8 +6877,10 @@ mod tests { assert_contains_opcode("test", YARVINSN_pushtoarray); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -6732,8 +6906,11 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_aset); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -6755,8 +6932,11 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_aref); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -6776,8 +6956,10 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_empty_p); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -6797,8 +6979,10 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_succ); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -6818,8 +7002,11 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_and); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -6839,8 +7026,11 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_or); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -6860,8 +7050,10 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_not); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -6881,8 +7073,11 @@ mod tests { assert_contains_opcode("test", YARVINSN_opt_regexpmatch2); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -6906,8 +7101,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_putspecialobject); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -6940,8 +7136,9 @@ mod tests { assert_contains_opcode("reverse_even", YARVINSN_opt_reverse); assert_snapshot!(hir_strings!("reverse_odd", "reverse_even"), @r" fn reverse_odd@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf v2:NilClass = Const Value(nil) v3:NilClass = Const Value(nil) v4:NilClass = Const Value(nil) @@ -6965,8 +7162,9 @@ mod tests { Return v33 fn reverse_even@:8: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf v2:NilClass = Const Value(nil) v3:NilClass = Const Value(nil) v4:NilClass = Const Value(nil) @@ -7003,8 +7201,10 @@ mod tests { assert_contains_opcode("test", YARVINSN_branchnil); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -7026,8 +7226,12 @@ mod tests { assert_contains_opcode("Float", YARVINSN_opt_invokebuiltin_delegate_leave); assert_snapshot!(hir_string("Float"), @r" fn Float@: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject, v4:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@6 + v3:BasicObject = GetLocal l0, SP@5 + v4:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3, v4) bb1(v7:BasicObject, v8:BasicObject, v9:BasicObject, v10:BasicObject): EntryPoint JIT(0) @@ -7046,8 +7250,9 @@ mod tests { assert_contains_opcode("class", YARVINSN_opt_invokebuiltin_delegate_leave); assert_snapshot!(hir_string("class"), @r" fn class@: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -7069,8 +7274,13 @@ mod tests { let function = iseq_to_hir(iseq).unwrap(); assert_snapshot!(hir_string_function(&function), @r" fn open@: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject, v4:BasicObject, v5:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@8 + v3:BasicObject = GetLocal l0, SP@7 + v4:BasicObject = GetLocal l0, SP@6 + v5:BasicObject = GetLocal l0, SP@5 v6:NilClass = Const Value(nil) Jump bb2(v1, v2, v3, v4, v5, v6) bb1(v9:BasicObject, v10:BasicObject, v11:BasicObject, v12:BasicObject, v13:BasicObject): @@ -7104,8 +7314,9 @@ mod tests { let function = iseq_to_hir(iseq).unwrap(); assert_snapshot!(hir_string_function(&function), @r" fn enable@: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -7126,8 +7337,13 @@ mod tests { let function = iseq_to_hir(iseq).unwrap(); assert_snapshot!(hir_string_function(&function), @r" fn start@: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject, v4:BasicObject, v5:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@7 + v3:BasicObject = GetLocal l0, SP@6 + v4:BasicObject = GetLocal l0, SP@5 + v5:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3, v4, v5) bb1(v8:BasicObject, v9:BasicObject, v10:BasicObject, v11:BasicObject, v12:BasicObject): EntryPoint JIT(0) @@ -7148,8 +7364,10 @@ mod tests { assert_contains_opcode("test", YARVINSN_dupn); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -7180,8 +7398,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_objtostring); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -7205,8 +7424,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_concatstrings); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -7235,8 +7455,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_concatstrings); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -7260,8 +7481,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_toregexp); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -7290,8 +7512,9 @@ mod tests { assert_contains_opcode("test", YARVINSN_toregexp); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -7319,8 +7542,9 @@ mod tests { assert_contains_opcode("throw_break", YARVINSN_throw); assert_snapshot!(hir_strings!("throw_return", "throw_break"), @r" fn block in @:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -7330,8 +7554,9 @@ mod tests { Throw TAG_RETURN, v12 fn block in @:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -7351,8 +7576,9 @@ mod tests { "#); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -7373,8 +7599,11 @@ mod tests { "#); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -7414,8 +7643,11 @@ mod graphviz_tests { node [shape=plaintext]; mode=hier; overlap=false; splines=true; bb0 [label=< - + + + +
bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject) 
bb0() 
EntryPoint interpreter 
v1:BasicObject = LoadSelf 
v2:BasicObject = GetLocal l0, SP@5 
v3:BasicObject = GetLocal l0, SP@4 
Jump bb2(v1, v2, v3) 
>]; bb0:v4 -> bb2:params:n; @@ -7460,8 +7692,10 @@ mod graphviz_tests { node [shape=plaintext]; mode=hier; overlap=false; splines=true; bb0 [label=< - + + +
bb0(v1:BasicObject, v2:BasicObject) 
bb0() 
EntryPoint interpreter 
v1:BasicObject = LoadSelf 
v2:BasicObject = GetLocal l0, SP@4 
Jump bb2(v1, v2) 
>]; bb0:v3 -> bb2:params:n; @@ -7527,8 +7761,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf v2:NilClass = Const Value(nil) Jump bb2(v1, v2) bb1(v5:BasicObject): @@ -7558,8 +7793,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf v2:NilClass = Const Value(nil) Jump bb2(v1, v2) bb1(v5:BasicObject): @@ -7584,8 +7820,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -7612,8 +7849,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -7640,8 +7878,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -7665,8 +7904,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -7691,8 +7931,10 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -7726,8 +7968,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -7757,8 +8000,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -7793,8 +8037,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -7824,8 +8069,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -7860,8 +8106,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -7891,8 +8138,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -7922,8 +8170,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -7954,8 +8203,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -7983,8 +8233,10 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -8010,8 +8262,10 @@ mod opt_tests { "); assert_snapshot!(hir_strings!("rest", "kw", "kw_rest", "block", "post"), @r" fn rest@:2: - bb0(v1:BasicObject, v2:ArrayExact): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:ArrayExact = GetLocal l0, SP@4, * Jump bb2(v1, v2) bb1(v5:BasicObject, v6:ArrayExact): EntryPoint JIT(0) @@ -8021,8 +8275,11 @@ mod opt_tests { Return v9 fn kw@:3: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -8032,8 +8289,10 @@ mod opt_tests { Return v11 fn kw_rest@:4: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -8043,8 +8302,10 @@ mod opt_tests { Return v9 fn block@:6: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -8055,8 +8316,11 @@ mod opt_tests { Return v13 fn post@:5: - bb0(v1:BasicObject, v2:ArrayExact, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:ArrayExact = GetLocal l0, SP@5, * + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:ArrayExact, v8:BasicObject): EntryPoint JIT(0) @@ -8079,8 +8343,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:5: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -8107,8 +8372,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:5: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -8133,8 +8399,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:6: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -8158,8 +8425,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -8186,8 +8454,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:5: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -8218,8 +8487,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:7: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -8246,8 +8516,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -8276,8 +8547,11 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:7: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -8297,8 +8571,11 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -8321,8 +8598,10 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -8345,8 +8624,10 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -8369,8 +8650,11 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -8393,8 +8677,10 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -8417,8 +8703,10 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -8444,8 +8732,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf v2:NilClass = Const Value(nil) Jump bb2(v1, v2) bb1(v5:BasicObject): @@ -8473,8 +8762,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf v2:NilClass = Const Value(nil) Jump bb2(v1, v2) bb1(v5:BasicObject): @@ -8500,8 +8790,10 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -8525,8 +8817,10 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -8550,8 +8844,10 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -8575,8 +8871,10 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -8601,8 +8899,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf v2:NilClass = Const Value(nil) Jump bb2(v1, v2) bb1(v5:BasicObject): @@ -8628,8 +8927,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf v2:NilClass = Const Value(nil) Jump bb2(v1, v2) bb1(v5:BasicObject): @@ -8655,8 +8955,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf v2:NilClass = Const Value(nil) Jump bb2(v1, v2) bb1(v5:BasicObject): @@ -8687,8 +8988,10 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 v3:NilClass = Const Value(nil) Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject): @@ -8713,8 +9016,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf v2:NilClass = Const Value(nil) Jump bb2(v1, v2) bb1(v5:BasicObject): @@ -8740,8 +9044,11 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@6 + v3:BasicObject = GetLocal l0, SP@5 v4:NilClass = Const Value(nil) Jump bb2(v1, v2, v3, v4) bb1(v7:BasicObject, v8:BasicObject, v9:BasicObject): @@ -8770,8 +9077,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf v2:NilClass = Const Value(nil) Jump bb2(v1, v2) bb1(v5:BasicObject): @@ -8797,8 +9105,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf v2:NilClass = Const Value(nil) Jump bb2(v1, v2) bb1(v5:BasicObject): @@ -8825,8 +9134,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf v2:NilClass = Const Value(nil) Jump bb2(v1, v2) bb1(v5:BasicObject): @@ -8851,8 +9161,9 @@ mod opt_tests { "#); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf v2:NilClass = Const Value(nil) Jump bb2(v1, v2) bb1(v5:BasicObject): @@ -8879,8 +9190,11 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -8906,8 +9220,11 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -8933,8 +9250,11 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -8960,8 +9280,11 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -8988,8 +9311,11 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -9016,8 +9342,11 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -9043,8 +9372,11 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -9070,8 +9402,11 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -9097,8 +9432,11 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -9124,8 +9462,11 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -9151,8 +9492,11 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -9178,8 +9522,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -9201,8 +9546,10 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -9223,8 +9570,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -9248,8 +9596,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf v2:NilClass = Const Value(nil) Jump bb2(v1, v2) bb1(v5:BasicObject): @@ -9279,8 +9628,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:4: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf v2:NilClass = Const Value(nil) Jump bb2(v1, v2) bb1(v5:BasicObject): @@ -9310,8 +9660,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf v2:NilClass = Const Value(nil) Jump bb2(v1, v2) bb1(v5:BasicObject): @@ -9337,8 +9688,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -9360,8 +9712,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -9393,8 +9746,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -9422,8 +9776,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:4: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -9447,8 +9802,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf v2:NilClass = Const Value(nil) Jump bb2(v1, v2) bb1(v5:BasicObject): @@ -9475,8 +9831,9 @@ mod opt_tests { // Not specialized assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -9497,8 +9854,10 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -9522,8 +9881,10 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 v3:NilClass = Const Value(nil) Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject): @@ -9550,8 +9911,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -9584,8 +9946,10 @@ mod opt_tests { assert_snapshot!(hir_string("test"), @r" fn test@:8: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -9609,8 +9973,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -9633,8 +9998,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -9660,8 +10026,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:4: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf v2:NilClass = Const Value(nil) Jump bb2(v1, v2) bb1(v5:BasicObject): @@ -9689,8 +10056,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -9713,8 +10081,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -9735,8 +10104,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -9756,8 +10126,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -9779,8 +10150,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -9801,8 +10173,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -9822,8 +10195,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -9851,8 +10225,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:8: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -9875,8 +10250,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -9909,8 +10285,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:7: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -9939,8 +10316,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -9968,8 +10346,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -9997,8 +10376,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10026,8 +10406,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10054,8 +10435,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10084,8 +10466,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10111,8 +10494,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10141,8 +10525,11 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -10163,8 +10550,11 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -10185,8 +10575,10 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -10207,8 +10599,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10228,8 +10621,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10250,8 +10644,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10274,8 +10669,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:5: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10292,8 +10688,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10314,8 +10711,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10336,8 +10734,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10358,8 +10757,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10379,8 +10779,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10401,8 +10802,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10423,8 +10825,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10445,8 +10848,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10466,8 +10870,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10488,8 +10893,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10511,8 +10917,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10534,8 +10941,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10555,8 +10963,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10577,8 +10986,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10600,8 +11010,9 @@ mod opt_tests { "##); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10623,8 +11034,9 @@ mod opt_tests { "##); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10651,8 +11063,10 @@ mod opt_tests { assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -10680,8 +11094,10 @@ mod opt_tests { assert_snapshot!(hir_string("test"), @r" fn test@:5: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -10706,8 +11122,10 @@ mod opt_tests { assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -10734,8 +11152,9 @@ mod opt_tests { assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf v2:NilClass = Const Value(nil) Jump bb2(v1, v2) bb1(v5:BasicObject): @@ -10761,8 +11180,9 @@ mod opt_tests { assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf v2:NilClass = Const Value(nil) Jump bb2(v1, v2) bb1(v5:BasicObject): @@ -10786,8 +11206,9 @@ mod opt_tests { "##); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10810,8 +11231,9 @@ mod opt_tests { "##); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10834,8 +11256,9 @@ mod opt_tests { "##); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10858,8 +11281,9 @@ mod opt_tests { "##); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10885,8 +11309,9 @@ mod opt_tests { "##); assert_snapshot!(hir_string("test"), @r" fn test@:5: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10911,8 +11336,9 @@ mod opt_tests { "##); assert_snapshot!(hir_string("test"), @r" fn test@:5: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10939,8 +11365,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:4: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10961,8 +11388,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -10981,8 +11409,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -11006,8 +11435,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -11028,8 +11458,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -11053,8 +11484,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -11077,8 +11509,10 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -11101,8 +11535,10 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -11125,8 +11561,10 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -11149,8 +11587,10 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -11173,8 +11613,10 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -11197,8 +11639,10 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -11221,8 +11665,10 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -11245,8 +11691,10 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -11269,8 +11717,10 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -11293,8 +11743,10 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -11318,8 +11770,11 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -11342,8 +11797,11 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -11367,8 +11825,11 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:2: - bb0(v1:BasicObject, v2:BasicObject, v3:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@5 + v3:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2, v3) bb1(v6:BasicObject, v7:BasicObject, v8:BasicObject): EntryPoint JIT(0) @@ -11394,8 +11855,9 @@ mod opt_tests { assert_snapshot!(hir_string("test"), @r" fn test@:3: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -11426,8 +11888,10 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:10: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -11459,8 +11923,10 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:10: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -11503,8 +11969,10 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:20: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -11530,8 +11998,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:7: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -11562,8 +12031,9 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:7: - bb0(v1:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf Jump bb2(v1) bb1(v4:BasicObject): EntryPoint JIT(0) @@ -11593,8 +12063,10 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:6: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) @@ -11622,8 +12094,10 @@ mod opt_tests { "); assert_snapshot!(hir_string("test"), @r" fn test@:6: - bb0(v1:BasicObject, v2:BasicObject): + bb0(): EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 Jump bb2(v1, v2) bb1(v5:BasicObject, v6:BasicObject): EntryPoint JIT(0) From 7a1873857eff3125c8124416f2fb3e0b13f3f238 Mon Sep 17 00:00:00 2001 From: Alan Wu Date: Fri, 26 Sep 2025 15:48:41 -0400 Subject: [PATCH 2/3] ZJIT: Remove RefCell from IseqCall No point taking the panic risks with RefCell when most fields in it are already in a Cell. Put `iseq` in a Cell and we no longer need the wrapping. Saves memory, too. --- zjit/src/codegen.rs | 48 ++++++++++++++++++++++----------------------- zjit/src/gc.rs | 10 ++++------ 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/zjit/src/codegen.rs b/zjit/src/codegen.rs index 2845aaf719963c..0ea675016134ee 100644 --- a/zjit/src/codegen.rs +++ b/zjit/src/codegen.rs @@ -37,7 +37,7 @@ struct JITState { jit_entries: Vec>>, /// ISEQ calls that need to be compiled later - iseq_calls: Vec>>, + iseq_calls: Vec, /// The number of bytes allocated for basic block arguments spilled onto the C stack c_stack_slots: usize, @@ -132,17 +132,17 @@ fn gen_iseq_entry_point(cb: &mut CodeBlock, iseq: IseqPtr, jit_exception: bool) } /// Stub a branch for a JIT-to-JIT call -fn gen_iseq_call(cb: &mut CodeBlock, caller_iseq: IseqPtr, iseq_call: &Rc>) -> Result<(), CompileError> { +fn gen_iseq_call(cb: &mut CodeBlock, caller_iseq: IseqPtr, iseq_call: &IseqCallRef) -> Result<(), CompileError> { // Compile a function stub let stub_ptr = gen_function_stub(cb, iseq_call.clone()).inspect_err(|err| { debug!("{err:?}: gen_function_stub failed: {} -> {}", - iseq_get_location(caller_iseq, 0), iseq_get_location(iseq_call.borrow().iseq, 0)); + iseq_get_location(caller_iseq, 0), iseq_get_location(iseq_call.iseq.get(), 0)); })?; // Update the JIT-to-JIT call to call the stub let stub_addr = stub_ptr.raw_ptr(cb); - let iseq = iseq_call.borrow().iseq; - iseq_call.borrow_mut().regenerate(cb, |asm| { + let iseq = iseq_call.iseq.get(); + iseq_call.regenerate(cb, |asm| { asm_comment!(asm, "call function stub: {}", iseq_get_location(iseq, 0)); asm.ccall(stub_addr, vec![]); }); @@ -235,7 +235,7 @@ fn gen_iseq_body(cb: &mut CodeBlock, iseq: IseqPtr, function: Option<&Function>, } // Prepare for GC - payload.iseq_calls.extend(iseq_calls.clone()); + payload.iseq_calls.extend(iseq_calls); append_gc_offsets(iseq, &gc_offsets); Ok(iseq_code_ptrs) } @@ -1797,8 +1797,8 @@ c_callable! { with_vm_lock(src_loc!(), || { // gen_push_frame() doesn't set PC, so we need to set them before exit. // function_stub_hit_body() may allocate and call gc_validate_pc(), so we always set PC. - let iseq_call = unsafe { Rc::from_raw(iseq_call_ptr as *const RefCell) }; - let iseq = iseq_call.borrow().iseq; + let iseq_call = unsafe { Rc::from_raw(iseq_call_ptr as *const IseqCall) }; + let iseq = iseq_call.iseq.get(); let pc = unsafe { rb_iseq_pc_at_idx(iseq, 0) }; // TODO: handle opt_pc once supported unsafe { rb_set_cfp_pc(cfp, pc) }; @@ -1834,7 +1834,7 @@ c_callable! { }; if let Some(compile_error) = compile_error { // We'll use this Rc again, so increment the ref count decremented by from_raw. - unsafe { Rc::increment_strong_count(iseq_call_ptr as *const RefCell); } + unsafe { Rc::increment_strong_count(iseq_call_ptr as *const IseqCall); } prepare_for_exit(iseq, cfp, sp, compile_error); return ZJITState::get_exit_trampoline_with_counter().raw_ptr(cb); @@ -1853,10 +1853,10 @@ c_callable! { } /// Compile an ISEQ for a function stub -fn function_stub_hit_body(cb: &mut CodeBlock, iseq_call: &Rc>) -> Result { +fn function_stub_hit_body(cb: &mut CodeBlock, iseq_call: &IseqCallRef) -> Result { // Compile the stubbed ISEQ - let IseqCodePtrs { jit_entry_ptrs, .. } = gen_iseq(cb, iseq_call.borrow().iseq, None).inspect_err(|err| { - debug!("{err:?}: gen_iseq failed: {}", iseq_get_location(iseq_call.borrow().iseq, 0)); + let IseqCodePtrs { jit_entry_ptrs, .. } = gen_iseq(cb, iseq_call.iseq.get(), None).inspect_err(|err| { + debug!("{err:?}: gen_iseq failed: {}", iseq_get_location(iseq_call.iseq.get(), 0)); })?; // We currently don't support JIT-to-JIT calls for ISEQs with optional arguments. @@ -1866,8 +1866,8 @@ fn function_stub_hit_body(cb: &mut CodeBlock, iseq_call: &Rc>) // Update the stub to call the code pointer let code_addr = jit_entry_ptr.raw_ptr(cb); - let iseq = iseq_call.borrow().iseq; - iseq_call.borrow_mut().regenerate(cb, |asm| { + let iseq = iseq_call.iseq.get(); + iseq_call.regenerate(cb, |asm| { asm_comment!(asm, "call compiled function: {}", iseq_get_location(iseq, 0)); asm.ccall(code_addr, vec![]); }); @@ -1876,9 +1876,9 @@ fn function_stub_hit_body(cb: &mut CodeBlock, iseq_call: &Rc>) } /// Compile a stub for an ISEQ called by SendWithoutBlockDirect -fn gen_function_stub(cb: &mut CodeBlock, iseq_call: Rc>) -> Result { +fn gen_function_stub(cb: &mut CodeBlock, iseq_call: IseqCallRef) -> Result { let mut asm = Assembler::new(); - asm_comment!(asm, "Stub: {}", iseq_get_location(iseq_call.borrow().iseq, 0)); + asm_comment!(asm, "Stub: {}", iseq_get_location(iseq_call.iseq.get(), 0)); // Call function_stub_hit using the shared trampoline. See `gen_function_stub_hit_trampoline`. // Use load_into instead of mov, which is split on arm64, to avoid clobbering ALLOC_REGS. @@ -2043,7 +2043,7 @@ fn aligned_stack_bytes(num_slots: usize) -> usize { impl Assembler { /// Make a C call while marking the start and end positions for IseqCall - fn ccall_with_iseq_call(&mut self, fptr: *const u8, opnds: Vec, iseq_call: &Rc>) -> Opnd { + fn ccall_with_iseq_call(&mut self, fptr: *const u8, opnds: Vec, iseq_call: &IseqCallRef) -> Opnd { // We need to create our own branch rc objects so that we can move the closure below let start_iseq_call = iseq_call.clone(); let end_iseq_call = iseq_call.clone(); @@ -2052,10 +2052,10 @@ impl Assembler { fptr, opnds, move |code_ptr, _| { - start_iseq_call.borrow_mut().start_addr.set(Some(code_ptr)); + start_iseq_call.start_addr.set(Some(code_ptr)); }, move |code_ptr, _| { - end_iseq_call.borrow_mut().end_addr.set(Some(code_ptr)); + end_iseq_call.end_addr.set(Some(code_ptr)); }, ) } @@ -2084,7 +2084,7 @@ impl JITEntry { #[derive(Debug)] pub struct IseqCall { /// Callee ISEQ that start_addr jumps to - pub iseq: IseqPtr, + pub iseq: Cell, /// Position where the call instruction starts start_addr: Cell>, @@ -2093,17 +2093,17 @@ pub struct IseqCall { end_addr: Cell>, } -type IseqCallRef = Rc>; +pub type IseqCallRef = Rc; impl IseqCall { /// Allocate a new IseqCall - fn new(iseq: IseqPtr) -> Rc> { + fn new(iseq: IseqPtr) -> IseqCallRef { let iseq_call = IseqCall { - iseq, + iseq: Cell::new(iseq), start_addr: Cell::new(None), end_addr: Cell::new(None), }; - Rc::new(RefCell::new(iseq_call)) + Rc::new(iseq_call) } /// Regenerate a IseqCall with a given callback diff --git a/zjit/src/gc.rs b/zjit/src/gc.rs index eed202ac77a378..cc08b8fc9ebb07 100644 --- a/zjit/src/gc.rs +++ b/zjit/src/gc.rs @@ -1,9 +1,7 @@ //! This module is responsible for marking/moving objects on GC. -use std::cell::RefCell; -use std::rc::Rc; use std::{ffi::c_void, ops::Range}; -use crate::codegen::IseqCall; +use crate::codegen::IseqCallRef; use crate::stats::CompileError; use crate::{cruby::*, profile::IseqProfile, state::ZJITState, stats::with_time_stat, virtualmem::CodePtr}; use crate::stats::Counter::gc_time_ns; @@ -21,7 +19,7 @@ pub struct IseqPayload { pub gc_offsets: Vec, /// JIT-to-JIT calls in the ISEQ. The IseqPayload's ISEQ is the caller of it. - pub iseq_calls: Vec>>, + pub iseq_calls: Vec, } impl IseqPayload { @@ -191,10 +189,10 @@ fn iseq_update_references(payload: &mut IseqPayload) { // Move ISEQ references in IseqCall for iseq_call in payload.iseq_calls.iter_mut() { - let old_iseq = iseq_call.borrow().iseq; + let old_iseq = iseq_call.iseq.get(); let new_iseq = unsafe { rb_gc_location(VALUE(old_iseq as usize)) }.0 as IseqPtr; if old_iseq != new_iseq { - iseq_call.borrow_mut().iseq = new_iseq; + iseq_call.iseq.set(new_iseq); } } From 1083c2c063e388003eeded1c2364f749bcd91b1a Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Mon, 29 Sep 2025 18:48:44 +0100 Subject: [PATCH 3/3] ZJIT: Add stats for cfuncs that are not optimized (#14638) * ZJIT: Add stats for cfuncs that are not optimized * ZJIT: Add IncrCounterPtr HIR instead From `lobsters` ``` Top-20 Unoptimized C functions (73.0% of total 15,276,688): Kernel#is_a?: 2,052,363 (13.4%) Class#current: 1,892,623 (12.4%) String#to_s: 975,973 ( 6.4%) Hash#key?: 677,623 ( 4.4%) String#empty?: 636,468 ( 4.2%) TrueClass#===: 457,232 ( 3.0%) Hash#[]=: 455,908 ( 3.0%) FalseClass#===: 448,798 ( 2.9%) ActiveSupport::OrderedOptions#_get: 377,468 ( 2.5%) Kernel#kind_of?: 339,551 ( 2.2%) Kernel#dup: 329,371 ( 2.2%) String#==: 324,286 ( 2.1%) String#include?: 297,528 ( 1.9%) Hash#[]: 294,561 ( 1.9%) Array#include?: 287,145 ( 1.9%) Kernel#block_given?: 283,633 ( 1.9%) BasicObject#!=: 278,874 ( 1.8%) Hash#delete: 250,951 ( 1.6%) Set#include?: 246,447 ( 1.6%) NilClass#===: 242,776 ( 1.6%) ``` From `liquid-render` ``` Top-20 Unoptimized C functions (99.8% of total 5,195,549): Hash#key?: 2,459,048 (47.3%) String#to_s: 1,119,758 (21.6%) Set#include?: 799,469 (15.4%) Kernel#is_a?: 214,223 ( 4.1%) Integer#<<: 171,073 ( 3.3%) Integer#/: 127,622 ( 2.5%) CGI::EscapeExt#escapeHTML: 56,971 ( 1.1%) Regexp#===: 50,008 ( 1.0%) String#empty?: 43,990 ( 0.8%) String#===: 36,838 ( 0.7%) String#==: 21,309 ( 0.4%) Time#strftime: 21,251 ( 0.4%) String#strip: 15,271 ( 0.3%) String#scan: 13,753 ( 0.3%) String#+@: 12,603 ( 0.2%) Array#include?: 8,059 ( 0.2%) String#+: 5,295 ( 0.1%) String#dup: 4,606 ( 0.1%) String#-@: 3,213 ( 0.1%) Class#generate: 3,011 ( 0.1%) ``` --- zjit.rb | 1 + zjit/src/codegen.rs | 16 +++++++++---- zjit/src/hir.rs | 56 +++++++++++++++++++++++++++++++-------------- zjit/src/state.rs | 10 ++++++++ zjit/src/stats.rs | 7 ++++++ 5 files changed, 68 insertions(+), 22 deletions(-) diff --git a/zjit.rb b/zjit.rb index eb47a704708cae..b85b5629a72654 100644 --- a/zjit.rb +++ b/zjit.rb @@ -43,6 +43,7 @@ def stats_string print_counters_with_prefix(prefix: 'dynamic_send_type_', prompt: 'dynamic send types', buf:, stats:, limit: 20) print_counters_with_prefix(prefix: 'unspecialized_def_type_', prompt: 'send fallback unspecialized def_types', buf:, stats:, limit: 20) print_counters_with_prefix(prefix: 'send_fallback_', prompt: 'dynamic send types', buf:, stats:, limit: 20) + print_counters_with_prefix(prefix: 'not_optimized_cfuncs_', prompt: 'unoptimized sends to C functions', buf:, stats:, limit: 20) # Show exit counters, ordered by the typical amount of exits for the prefix at the time print_counters_with_prefix(prefix: 'unhandled_yarv_insn_', prompt: 'unhandled YARV insns', buf:, stats:, limit: 20) diff --git a/zjit/src/codegen.rs b/zjit/src/codegen.rs index 0ea675016134ee..e8f1d968298860 100644 --- a/zjit/src/codegen.rs +++ b/zjit/src/codegen.rs @@ -419,6 +419,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio Insn::GetSpecialSymbol { symbol_type, state: _ } => gen_getspecial_symbol(asm, *symbol_type), Insn::GetSpecialNumber { nth, state } => gen_getspecial_number(asm, *nth, &function.frame_state(*state)), &Insn::IncrCounter(counter) => no_output!(gen_incr_counter(asm, counter)), + Insn::IncrCounterPtr { counter_ptr } => no_output!(gen_incr_counter_ptr(asm, *counter_ptr)), Insn::ObjToString { val, cd, state, .. } => gen_objtostring(jit, asm, opnd!(val), *cd, &function.frame_state(*state)), &Insn::CheckInterrupts { state } => no_output!(gen_check_interrupts(jit, asm, &function.frame_state(state))), &Insn::HashDup { val, state } => { gen_hash_dup(asm, opnd!(val), &function.frame_state(state)) }, @@ -1528,15 +1529,20 @@ fn gen_guard_bit_equals(jit: &mut JITState, asm: &mut Assembler, val: lir::Opnd, val } +/// Generate code that records unoptimized C functions if --zjit-stats is enabled +fn gen_incr_counter_ptr(asm: &mut Assembler, counter_ptr: *mut u64) { + if get_option!(stats) { + let ptr_reg = asm.load(Opnd::const_ptr(counter_ptr as *const u8)); + let counter_opnd = Opnd::mem(64, ptr_reg, 0); + asm.incr_counter(counter_opnd, Opnd::UImm(1)); + } +} + /// Generate code that increments a counter if --zjit-stats fn gen_incr_counter(asm: &mut Assembler, counter: Counter) { if get_option!(stats) { let ptr = counter_ptr(counter); - let ptr_reg = asm.load(Opnd::const_ptr(ptr as *const u8)); - let counter_opnd = Opnd::mem(64, ptr_reg, 0); - - // Increment and store the updated value - asm.incr_counter(counter_opnd, Opnd::UImm(1)); + gen_incr_counter_ptr(asm, ptr); } } diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index 6805854802a30a..d81231e2820b88 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -711,6 +711,9 @@ pub enum Insn { /// Increment a counter in ZJIT stats IncrCounter(Counter), + /// Increment a counter in ZJIT stats for the given counter pointer + IncrCounterPtr { counter_ptr: *mut u64 }, + /// Equivalent of RUBY_VM_CHECK_INTS. Automatically inserted by the compiler before jumps and /// return instructions. CheckInterrupts { state: InsnId }, @@ -724,7 +727,7 @@ impl Insn { | Insn::IfTrue { .. } | Insn::IfFalse { .. } | Insn::EntryPoint { .. } | Insn::Return { .. } | Insn::PatchPoint { .. } | Insn::SetIvar { .. } | Insn::ArrayExtend { .. } | Insn::ArrayPush { .. } | Insn::SideExit { .. } | Insn::SetGlobal { .. } - | Insn::SetLocal { .. } | Insn::Throw { .. } | Insn::IncrCounter(_) + | Insn::SetLocal { .. } | Insn::Throw { .. } | Insn::IncrCounter(_) | Insn::IncrCounterPtr { .. } | Insn::CheckInterrupts { .. } | Insn::GuardBlockParamProxy { .. } => false, _ => true, } @@ -978,6 +981,7 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> { } Ok(()) }, + Insn::IncrCounterPtr { .. } => write!(f, "IncrCounterPtr"), Insn::Snapshot { state } => write!(f, "Snapshot {}", state.print(self.ptr_map)), Insn::Defined { op_type, v, .. } => { // op_type (enum defined_type) printing logic from iseq.c. @@ -1385,6 +1389,7 @@ impl Function { | EntryPoint {..} | LoadPC | LoadSelf + | IncrCounterPtr {..} | IncrCounter(_)) => result.clone(), &Snapshot { state: FrameState { iseq, insn_idx, pc, ref stack, ref locals } } => Snapshot { @@ -1534,7 +1539,7 @@ impl Function { | Insn::IfTrue { .. } | Insn::IfFalse { .. } | Insn::Return { .. } | Insn::Throw { .. } | Insn::PatchPoint { .. } | Insn::SetIvar { .. } | Insn::ArrayExtend { .. } | Insn::ArrayPush { .. } | Insn::SideExit { .. } | Insn::SetLocal { .. } | Insn::IncrCounter(_) - | Insn::CheckInterrupts { .. } | Insn::GuardBlockParamProxy { .. } => + | Insn::CheckInterrupts { .. } | Insn::GuardBlockParamProxy { .. } | Insn::IncrCounterPtr { .. } => panic!("Cannot infer type of instruction with no output: {}", self.insns[insn.0]), Insn::Const { val: Const::Value(val) } => Type::from_value(*val), Insn::Const { val: Const::CBool(val) } => Type::from_cbool(*val), @@ -2154,9 +2159,9 @@ impl Function { self_type: Type, send: Insn, send_insn_id: InsnId, - ) -> Result<(), ()> { + ) -> Result<(), Option<*const rb_callable_method_entry_struct>> { let Insn::SendWithoutBlock { mut recv, cd, mut args, state, .. } = send else { - return Err(()); + return Err(None); }; let call_info = unsafe { (*cd).ci }; @@ -2168,20 +2173,20 @@ impl Function { (class, None) } else { let iseq_insn_idx = fun.frame_state(state).insn_idx; - let Some(recv_type) = fun.profiled_type_of_at(recv, iseq_insn_idx) else { return Err(()) }; + let Some(recv_type) = fun.profiled_type_of_at(recv, iseq_insn_idx) else { return Err(None) }; (recv_type.class(), Some(recv_type)) }; // Do method lookup - let method = unsafe { rb_callable_method_entry(recv_class, method_id) }; + let method: *const rb_callable_method_entry_struct = unsafe { rb_callable_method_entry(recv_class, method_id) }; if method.is_null() { - return Err(()); + return Err(None); } // Filter for C methods let def_type = unsafe { get_cme_def_type(method) }; if def_type != VM_METHOD_TYPE_CFUNC { - return Err(()); + return Err(None); } // Find the `argc` (arity) of the C method, which describes the parameters it expects @@ -2193,7 +2198,7 @@ impl Function { // // Bail on argc mismatch if argc != cfunc_argc as u32 { - return Err(()); + return Err(Some(method)); } // Filter for a leaf and GC free function @@ -2201,7 +2206,7 @@ impl Function { let Some(FnProperties { leaf: true, no_gc: true, return_type, elidable }) = ZJITState::get_method_annotations().get_cfunc_properties(method) else { - return Err(()); + return Err(Some(method)); }; let ci_flags = unsafe { vm_ci_flag(call_info) }; @@ -2218,13 +2223,13 @@ impl Function { cfunc_args.append(&mut args); let ccall = fun.push_insn(block, Insn::CCall { cfun, args: cfunc_args, name: method_id, return_type, elidable }); fun.make_equal_to(send_insn_id, ccall); - return Ok(()); + return Ok(()) } } // Variadic method -1 => { if unsafe { rb_zjit_method_tracing_currently_enabled() } { - return Err(()); + return Err(None); } // The method gets a pointer to the first argument // func(int argc, VALUE *argv, VALUE recv) @@ -2256,8 +2261,9 @@ impl Function { }); fun.make_equal_to(send_insn_id, ccall); - return Ok(()); + return Ok(()) } + // Fall through for complex cases (splat, kwargs, etc.) } -2 => { @@ -2267,7 +2273,7 @@ impl Function { _ => unreachable!("unknown cfunc kind: argc={argc}") } - Err(()) + Err(Some(method)) } for block in self.rpo() { @@ -2276,8 +2282,23 @@ impl Function { for insn_id in old_insns { if let send @ Insn::SendWithoutBlock { recv, .. } = self.find(insn_id) { let recv_type = self.type_of(recv); - if reduce_to_ccall(self, block, recv_type, send, insn_id).is_ok() { - continue; + match reduce_to_ccall(self, block, recv_type, send, insn_id) { + Ok(()) => continue, + Err(Some(cme)) => { + if get_option!(stats) { + let owner = unsafe { (*cme).owner }; + let called_id = unsafe { (*cme).called_id }; + let class_name = get_class_name(owner); + let method_name = called_id.contents_lossy(); + let qualified_method_name = format!("{}#{}", class_name, method_name); + let unoptimized_cfunc_counter_pointers = ZJITState::get_unoptimized_cfunc_counter_pointers(); + let counter_ptr = unoptimized_cfunc_counter_pointers.entry(qualified_method_name.clone()).or_insert_with(|| Box::new(0)); + let counter_ptr = &mut **counter_ptr as *mut u64; + + self.push_insn(block, Insn::IncrCounterPtr { counter_ptr }); + } + } + _ => {} } } self.push_insn_id(block, insn_id); @@ -2423,7 +2444,8 @@ impl Function { | &Insn::LoadSelf | &Insn::GetLocal { .. } | &Insn::PutSpecialObject { .. } - | &Insn::IncrCounter(_) => + | &Insn::IncrCounter(_) + | &Insn::IncrCounterPtr { .. } => {} &Insn::PatchPoint { state, .. } | &Insn::CheckInterrupts { state } diff --git a/zjit/src/state.rs b/zjit/src/state.rs index c0f81e1e856dec..fa5d3bc83f506c 100644 --- a/zjit/src/state.rs +++ b/zjit/src/state.rs @@ -8,6 +8,7 @@ use crate::asm::CodeBlock; use crate::options::get_option; use crate::stats::{Counters, ExitCounters}; use crate::virtualmem::CodePtr; +use std::collections::HashMap; #[allow(non_upper_case_globals)] #[unsafe(no_mangle)] @@ -46,6 +47,9 @@ pub struct ZJITState { /// Trampoline to call function_stub_hit function_stub_hit_trampoline: CodePtr, + + /// Counter pointers for unoptimized C functions + unoptimized_cfunc_counter_pointers: HashMap>, } /// Private singleton instance of the codegen globals @@ -80,6 +84,7 @@ impl ZJITState { exit_trampoline, function_stub_hit_trampoline, exit_trampoline_with_counter: exit_trampoline, + unoptimized_cfunc_counter_pointers: HashMap::new(), }; unsafe { ZJIT_STATE = Some(zjit_state); } @@ -138,6 +143,11 @@ impl ZJITState { &mut ZJITState::get_instance().exit_counters } + /// Get a mutable reference to unoptimized cfunc counter pointers + pub fn get_unoptimized_cfunc_counter_pointers() -> &'static mut HashMap> { + &mut ZJITState::get_instance().unoptimized_cfunc_counter_pointers + } + /// Was --zjit-save-compiled-iseqs specified? pub fn should_log_compiled_iseqs() -> bool { get_option!(log_compiled_iseqs).is_some() diff --git a/zjit/src/stats.rs b/zjit/src/stats.rs index 6d4525084ef849..42dc44538ada0a 100644 --- a/zjit/src/stats.rs +++ b/zjit/src/stats.rs @@ -384,6 +384,13 @@ pub extern "C" fn rb_zjit_stats(_ec: EcPtr, _self: VALUE, target_key: VALUE) -> set_stat_f64!(hash, "ratio_in_zjit", 100.0 * zjit_insn_count as f64 / total_insn_count as f64); } + // Set unoptimized cfunc counters + let unoptimized_cfuncs = ZJITState::get_unoptimized_cfunc_counter_pointers(); + for (signature, counter) in unoptimized_cfuncs.iter() { + let key_string = format!("not_optimized_cfuncs_{}", signature); + set_stat_usize!(hash, &key_string, **counter); + } + hash }