summaryrefslogtreecommitdiff
path: root/zjit/src
diff options
context:
space:
mode:
Diffstat (limited to 'zjit/src')
-rw-r--r--zjit/src/backend/lir.rs65
-rw-r--r--zjit/src/codegen.rs60
-rw-r--r--zjit/src/cruby.rs13
-rw-r--r--zjit/src/cruby_bindings.inc.rs9
-rw-r--r--zjit/src/cruby_methods.rs8
-rw-r--r--zjit/src/hir.rs88
-rw-r--r--zjit/src/hir/opt_tests.rs537
-rw-r--r--zjit/src/hir/tests.rs12
-rw-r--r--zjit/src/hir_type/gen_hir_type.rb6
-rw-r--r--zjit/src/hir_type/hir_type.inc.rs77
-rw-r--r--zjit/src/hir_type/mod.rs29
-rw-r--r--zjit/src/profile.rs15
12 files changed, 531 insertions, 388 deletions
diff --git a/zjit/src/backend/lir.rs b/zjit/src/backend/lir.rs
index 467cd5b4de..a8d03ad69a 100644
--- a/zjit/src/backend/lir.rs
+++ b/zjit/src/backend/lir.rs
@@ -1812,8 +1812,9 @@ impl Assembler
Opnd::Reg(ALLOC_REGS[idx])
} else {
// With FrameSetup, the address that NATIVE_BASE_PTR points to stores an old value in the register.
- // To avoid clobbering it, we need to start from the next slot, hence `+ 1` for the index.
- Opnd::mem(64, NATIVE_BASE_PTR, (idx - ALLOC_REGS.len() + 1) as i32 * -SIZEOF_VALUE_I32)
+ // To avoid clobbering it, we need to start from the next slot, and we also reserve one space for
+ // JITFrame, hence `+ 2` for the index.
+ Opnd::mem(64, NATIVE_BASE_PTR, (idx - ALLOC_REGS.len() + 2) as i32 * -SIZEOF_VALUE_I32)
}
}
@@ -2661,24 +2662,8 @@ impl Assembler
asm.cret(Opnd::UImm(Qundef.as_u64()));
}
- /// Compile the main side-exit code. This function takes only SideExit so
- /// that it can be safely deduplicated by using SideExit as a dedup key.
- fn compile_exit(asm: &mut Assembler, exit: &SideExit) {
- compile_exit_save_state(asm, exit);
- // If this side exit should trigger recompilation, call the recompile
- // function after saving VM state. The ccall must happen after
- // compile_exit_save_state because it clobbers caller-saved registers
- // that may hold stack/local operands we need to save.
+ fn compile_exit_recompile(asm: &mut Assembler, exit: &SideExit) {
if let Some(recompile) = &exit.recompile {
- if cfg!(feature = "runtime_checks") {
- // Clear jit_return to fully materialize the frame. This must happen
- // before any C call in the exit path (e.g. exit_recompile)
- // because that C call can trigger GC, which walks the stack and would
- // hit the CFP_JIT_RETURN assertion if jit_return still holds the
- // runtime_checks poison value (JIT_RETURN_POISON).
- asm_comment!(asm, "clear cfp->jit_return");
- asm.store(Opnd::mem(64, CFP, RUBY_OFFSET_CFP_JIT_RETURN), 0.into());
- }
use crate::codegen::exit_recompile;
asm_comment!(asm, "profile and maybe recompile");
@@ -2692,6 +2677,34 @@ impl Assembler
})
);
}
+ }
+
+ /// Compile the main side-exit code. The side exit will optionally record a traced exit
+ /// stack, optionally trigger recompilation, and then return to the interpreter. Shared
+ /// exits pass no trace reason so they can still be deduplicated by SideExit.
+ /// IOW, we should never pass a trace reason if we expect the exit to be
+ /// deduplicated.
+ fn compile_exit(asm: &mut Assembler, exit: &SideExit, trace_reason: Option<SideExitReason>) {
+ // Save VM state before the ccall so that
+ // rb_profile_frames sees valid cfp->pc and the
+ // ccall doesn't clobber caller-saved registers
+ // holding stack/local operands.
+ compile_exit_save_state(asm, exit);
+ if trace_reason.is_some() || exit.recompile.is_some() {
+ // Clear cfp->jit_return to prepare for a C call. Normally, cfp->jit_return
+ // is cleared by the caller jit_exec() or JIT_EXEC(), but if we're about to
+ // make a C call, we need to clear any stale JITFrame.
+ asm_comment!(asm, "clear cfp->jit_return");
+ asm.store(Opnd::mem(64, CFP, RUBY_OFFSET_CFP_JIT_RETURN), 0.into());
+ }
+ if let Some(reason) = trace_reason {
+ // Leak a CString with the reason so it's available at runtime
+ let reason_cstr = std::ffi::CString::new(reason.to_string())
+ .unwrap_or_else(|_| std::ffi::CString::new("unknown").unwrap());
+ let reason_ptr = reason_cstr.into_raw() as *const u8;
+ asm_ccall!(asm, rb_zjit_record_exit_stack, Opnd::const_ptr(reason_ptr));
+ }
+ compile_exit_recompile(asm, exit);
compile_exit_return(asm);
}
@@ -2768,17 +2781,7 @@ impl Assembler
}
if should_record_exit {
- // Save VM state before the ccall so that
- // rb_profile_frames sees valid cfp->pc and the
- // ccall doesn't clobber caller-saved registers
- // holding stack/local operands.
- compile_exit_save_state(self, &exit);
- // Leak a CString with the reason so it's available at runtime
- let reason_cstr = std::ffi::CString::new(reason.to_string())
- .unwrap_or_else(|_| std::ffi::CString::new("unknown").unwrap());
- let reason_ptr = reason_cstr.into_raw() as *const u8;
- asm_ccall!(self, rb_zjit_record_exit_stack, Opnd::const_ptr(reason_ptr));
- compile_exit_return(self);
+ compile_exit(self, &exit, Some(reason));
} else {
// If the side exit has already been compiled, jump to it.
// Otherwise, let it fall through and compile the exit next.
@@ -2798,7 +2801,7 @@ impl Assembler
let new_exit = self.new_label("side_exit");
self.write_label(new_exit.clone());
asm_comment!(self, "Exit: {pc}");
- compile_exit(self, &exit);
+ compile_exit(self, &exit, None);
compiled_exits.insert(exit, new_exit.unwrap_label());
new_exit
};
diff --git a/zjit/src/codegen.rs b/zjit/src/codegen.rs
index f4d62fc7bc..4eee769315 100644
--- a/zjit/src/codegen.rs
+++ b/zjit/src/codegen.rs
@@ -19,7 +19,7 @@ use crate::state::ZJITState;
use crate::stats::{CompileError, exit_counter_for_compile_error, exit_counter_for_unhandled_hir_insn, incr_counter, incr_counter_by, send_fallback_counter, send_fallback_counter_for_method_type, send_fallback_counter_for_super_method_type, send_fallback_counter_ptr_for_opcode, send_without_block_fallback_counter_for_method_type, send_without_block_fallback_counter_for_optimized_method_type};
use crate::stats::{counter_ptr, with_time_stat, trace_compile_phase, Counter, Counter::{compile_time_ns, exit_compile_error}};
use crate::{asm::CodeBlock, cruby::*, options::debug, virtualmem::CodePtr};
-use crate::backend::lir::{self, Assembler, C_ARG_OPNDS, C_RET_OPND, CFP, EC, NATIVE_STACK_PTR, Opnd, SP, SideExit, SideExitRecompile, Target, asm_ccall, asm_comment};
+use crate::backend::lir::{self, Assembler, C_ARG_OPNDS, C_RET_OPND, CFP, EC, NATIVE_BASE_PTR, NATIVE_STACK_PTR, Opnd, SP, SideExit, SideExitRecompile, Target, asm_ccall, asm_comment};
use crate::hir::{iseq_to_hir, BlockId, Invariant, RangeType, SideExitReason::{self, *}, SpecialBackrefSymbol, SpecialObjectType};
use crate::hir::{BlockHandler, Const, FieldName, FrameState, Function, Insn, InsnId, Recompile, SendFallbackReason};
use crate::hir_type::{types, Type};
@@ -376,7 +376,7 @@ fn gen_function(cb: &mut CodeBlock, iseq: IseqPtr, version: IseqVersionRef, func
let (mut jit, asm) = trace_compile_phase("codegen", || {
let num_spilled_params = max_num_params(function).saturating_sub(ALLOC_REGS.len());
let mut jit = JITState::new(version, function.num_insns(), function.num_blocks());
- let mut asm = Assembler::new_with_stack_slots(num_spilled_params);
+ let mut asm = Assembler::new_with_stack_slots(num_spilled_params + 1); // +1 for JITFrame
// Mapping from HIR block IDs to LIR block IDs.
// This is is a one-to-one mapping from HIR to LIR blocks used for finding
@@ -679,7 +679,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
&Insn::GuardBitEquals { val, expected, reason, state, recompile } => gen_guard_bit_equals(jit, asm, opnd!(val), expected, reason, recompile, &function.frame_state(state)),
&Insn::GuardAnyBitSet { val, mask, reason, state, .. } => gen_guard_any_bit_set(jit, asm, opnd!(val), mask, reason, &function.frame_state(state)),
&Insn::GuardNoBitsSet { val, mask, reason, state, .. } => gen_guard_no_bits_set(jit, asm, opnd!(val), mask, reason, &function.frame_state(state)),
- &Insn::GuardLess { left, right, state } => gen_guard_less(jit, asm, opnd!(left), opnd!(right), &function.frame_state(state)),
+ &Insn::GuardLess { left, right, reason, state } => gen_guard_less(jit, asm, opnd!(left), opnd!(right), reason, &function.frame_state(state)),
&Insn::GuardGreaterEq { left, right, state, .. } => gen_guard_greater_eq(jit, asm, opnd!(left), opnd!(right), &function.frame_state(state)),
Insn::PatchPoint { invariant, state } => no_output!(gen_patch_point(jit, asm, invariant, &function.frame_state(*state))),
Insn::CCall { cfunc, recv, args, name, owner: _, return_type: _, elidable: _ } => gen_ccall(asm, *cfunc, *name, opnd!(recv), opnds!(args)),
@@ -885,9 +885,9 @@ fn gen_getblockparam(jit: &mut JITState, asm: &mut Assembler, ep_offset: u32, le
asm.load(Opnd::mem(VALUE_BITS, ep, offset))
}
-fn gen_guard_less(jit: &mut JITState, asm: &mut Assembler, left: Opnd, right: Opnd, state: &FrameState) -> Opnd {
+fn gen_guard_less(jit: &mut JITState, asm: &mut Assembler, left: Opnd, right: Opnd, reason: SideExitReason, state: &FrameState) -> Opnd {
asm.cmp(left, right);
- asm.jge(jit, side_exit(jit, state, SideExitReason::GuardLess));
+ asm.jge(jit, side_exit(jit, state, reason));
left
}
@@ -2111,19 +2111,17 @@ fn gen_new_hash(
elements: Vec<Opnd>,
state: &FrameState,
) -> lir::Opnd {
- gen_prepare_non_leaf_call(jit, asm, state);
-
- let cap: c_long = elements.len().try_into().expect("Unable to fit length of elements into c_long");
- let new_hash = asm_ccall!(asm, rb_hash_new_with_size, lir::Opnd::Imm(cap));
+ if elements.is_empty() {
+ gen_prepare_leaf_call_with_gc(asm, state);
+ asm_ccall!(asm, rb_hash_new,)
+ } else {
+ gen_prepare_non_leaf_call(jit, asm, state);
- if !elements.is_empty() {
let argv = gen_push_opnds(asm, &elements);
- asm_ccall!(asm, rb_hash_bulk_insert, elements.len().into(), argv, new_hash);
-
+ let hash = asm_ccall!(asm, rb_hash_new_with_bulk_insert, elements.len().into(), argv);
gen_pop_opnds(asm, &elements);
+ hash
}
-
- new_hash
}
/// Compile a new range instruction
@@ -2186,6 +2184,17 @@ fn gen_entry_point(jit: &mut JITState, asm: &mut Assembler, jit_entry_idx: Optio
});
}
asm.frame_setup(&[]);
+
+ // Publish the JITFrame slot's location via cfp->jit_return. The slot at
+ // [NATIVE_BASE_PTR - 8] is left uninitialized here; the JIT design relies on
+ // gen_save_pc_for_gc() to populate it before any C call, and on cross-ractor
+ // barriers ensuring that no other ractor scans this CFP before such a call.
+ asm.mov(Opnd::mem(64, CFP, RUBY_OFFSET_CFP_JIT_RETURN), NATIVE_BASE_PTR);
+
+ // Poison the JITFrame slot. It should be read only after gen_save_pc_for_gc().
+ if let Some(jit_return_poison) = JIT_RETURN_POISON {
+ asm.mov(Opnd::mem(64, NATIVE_BASE_PTR, -SIZEOF_VALUE_I32), jit_return_poison.into());
+ }
}
/// Compile code that exits from JIT code with a return value
@@ -2710,11 +2719,16 @@ fn gen_save_pc_for_gc(asm: &mut Assembler, state: &FrameState) {
gen_incr_counter(asm, Counter::vm_write_jit_frame_count);
asm_comment!(asm, "save JITFrame to CFP");
- if let Some(pc) = PC_POISON {
- asm.mov(Opnd::mem(64, CFP, RUBY_OFFSET_CFP_PC), Opnd::const_ptr(pc));
- }
let jit_frame = JITFrame::new_iseq(next_pc, state.iseq, !iseq_may_write_block_code(state.iseq));
- asm.mov(Opnd::mem(64, CFP, RUBY_OFFSET_CFP_JIT_RETURN), Opnd::const_ptr(jit_frame));
+ asm.mov(Opnd::mem(64, NATIVE_BASE_PTR, -SIZEOF_VALUE_I32), Opnd::const_ptr(jit_frame));
+
+ // CFP_PC for a live JIT frame routes through the JITFrame on the native
+ // stack (cfp->jit_return points to NATIVE_BASE_PTR), so we don't need to
+ // touch cfp->pc here. Poisoning cfp->pc with PC_POISON would actively
+ // break the case where rb_zjit_materialize_frames() previously copied
+ // jit_frame->pc into cfp->pc and cleared cfp->jit_return: the JIT keeps
+ // running, lands on this routine again, and the poison would replace
+ // the valid materialized pc behind the GC's back.
}
/// Save the current PC on the CFP as a preparation for calling a C function
@@ -2843,9 +2857,7 @@ fn gen_push_frame(asm: &mut Assembler, argc: usize, state: &FrameState, frame: C
if frame.iseq.is_some() {
// PC, SP, and ISEQ are written lazily by the callee on side-exits, non-leaf calls, or GC.
- if let Some(jit_return_poison) = JIT_RETURN_POISON {
- asm.mov(cfp_opnd(RUBY_OFFSET_CFP_JIT_RETURN), jit_return_poison.into());
- }
+ // cfp->jit_return will be written by gen_entry_point() on the callee after this frame push.
if frame.write_block_code {
asm_comment!(asm, "write block_code for iseq that may use it");
asm.mov(cfp_opnd(RUBY_OFFSET_CFP_BLOCK_CODE), 0.into());
@@ -3387,11 +3399,7 @@ fn gen_toregexp(jit: &mut JITState, asm: &mut Assembler, opt: usize, values: Vec
gen_prepare_non_leaf_call(jit, asm, state);
let first_opnd_ptr = gen_push_opnds(asm, &values);
-
- let tmp_ary = asm_ccall!(asm, rb_ary_tmp_new_from_values, Opnd::Imm(0), values.len().into(), first_opnd_ptr);
- let result = asm_ccall!(asm, rb_reg_new_ary, tmp_ary, opt.into());
- asm_ccall!(asm, rb_ary_clear, tmp_ary);
-
+ let result = asm_ccall!(asm, rb_reg_new_from_values, values.len().into(), first_opnd_ptr, opt.into());
gen_pop_opnds(asm, &values);
result
diff --git a/zjit/src/cruby.rs b/zjit/src/cruby.rs
index 6a5dd234bb..14db7c57d7 100644
--- a/zjit/src/cruby.rs
+++ b/zjit/src/cruby.rs
@@ -1471,6 +1471,19 @@ pub fn get_class_name(class: VALUE) -> String {
name
}
+// Return the module name for a given module or class. For anonymous modules, returns None since
+// rb_mod_name returns Qnil.
+pub fn get_module_name(module: VALUE) -> Option<String> {
+ // type checks for rb_mod_name()
+ assert!(unsafe { RB_TYPE_P(module, RUBY_T_MODULE) || RB_TYPE_P(module, RUBY_T_CLASS) }, "Expected class or module");
+ let name = unsafe { rb_mod_name(module) };
+ if name == Qnil {
+ None
+ } else {
+ Some(ruby_str_to_rust_string(name))
+ }
+}
+
#[cfg(test)]
mod class_name_tests {
diff --git a/zjit/src/cruby_bindings.inc.rs b/zjit/src/cruby_bindings.inc.rs
index 860e1726db..5a7c3de606 100644
--- a/zjit/src/cruby_bindings.inc.rs
+++ b/zjit/src/cruby_bindings.inc.rs
@@ -462,6 +462,7 @@ pub struct vm_ifunc {
pub data: *const ::std::os::raw::c_void,
pub argc: vm_ifunc_argc,
}
+pub type rb_atomic_t = ::std::os::raw::c_uint;
pub const METHOD_VISI_UNDEF: rb_method_visibility_t = 0;
pub const METHOD_VISI_PUBLIC: rb_method_visibility_t = 1;
pub const METHOD_VISI_PRIVATE: rb_method_visibility_t = 2;
@@ -1535,7 +1536,7 @@ pub type vm_call_flag_bits = u32;
#[repr(C)]
pub struct rb_callinfo_kwarg {
pub keyword_len: ::std::os::raw::c_int,
- pub references: ::std::os::raw::c_int,
+ pub references: rb_atomic_t,
pub keywords: __IncompleteArrayField<VALUE>,
}
#[repr(C)]
@@ -2059,6 +2060,11 @@ unsafe extern "C" {
pub fn rb_class_allocate_instance(klass: VALUE) -> VALUE;
pub fn rb_obj_equal(obj1: VALUE, obj2: VALUE) -> VALUE;
pub fn rb_reg_new_ary(ary: VALUE, options: ::std::os::raw::c_int) -> VALUE;
+ pub fn rb_reg_new_from_values(
+ cnt: ::std::os::raw::c_long,
+ elements: *const VALUE,
+ opt: ::std::os::raw::c_int,
+ ) -> VALUE;
pub fn rb_ary_tmp_new_from_values(
arg1: VALUE,
arg2: ::std::os::raw::c_long,
@@ -2131,6 +2137,7 @@ unsafe extern "C" {
arg: st_data_t,
) -> ::std::os::raw::c_int;
pub fn rb_hash_new_with_size(size: st_index_t) -> VALUE;
+ pub fn rb_hash_new_with_bulk_insert(argc: ::std::os::raw::c_long, argv: *const VALUE) -> VALUE;
pub fn rb_hash_resurrect(hash: VALUE) -> VALUE;
pub fn rb_hash_stlike_lookup(
hash: VALUE,
diff --git a/zjit/src/cruby_methods.rs b/zjit/src/cruby_methods.rs
index db09930721..05b0055032 100644
--- a/zjit/src/cruby_methods.rs
+++ b/zjit/src/cruby_methods.rs
@@ -367,7 +367,7 @@ fn inline_array_aref(fun: &mut hir::Function, block: hir::BlockId, recv: hir::In
let index = fun.coerce_to(block, index, types::Fixnum, state);
let index = fun.push_insn(block, hir::Insn::UnboxFixnum { val: index });
let length = fun.push_insn(block, hir::Insn::ArrayLength { array: recv });
- let index = fun.push_insn(block, hir::Insn::GuardLess { left: index, right: length, state });
+ let index = fun.push_insn(block, hir::Insn::GuardLess { left: index, right: length, reason: SideExitReason::GuardLess, state });
let index = fun.push_insn(block, hir::Insn::AdjustBounds { index, length });
let zero = fun.push_insn(block, hir::Insn::Const { val: hir::Const::CInt64(0) });
use crate::hir::SideExitReason;
@@ -392,7 +392,7 @@ fn inline_array_aset(fun: &mut hir::Function, block: hir::BlockId, recv: hir::In
// Bounds check: unbox Fixnum index and guard 0 <= idx < length.
let index = fun.push_insn(block, hir::Insn::UnboxFixnum { val: index });
let length = fun.push_insn(block, hir::Insn::ArrayLength { array: recv });
- let index = fun.push_insn(block, hir::Insn::GuardLess { left: index, right: length, state });
+ let index = fun.push_insn(block, hir::Insn::GuardLess { left: index, right: length, reason: SideExitReason::GuardLess, state });
let index = fun.push_insn(block, hir::Insn::AdjustBounds { index, length });
let zero = fun.push_insn(block, hir::Insn::Const { val: hir::Const::CInt64(0) });
use crate::hir::SideExitReason;
@@ -492,7 +492,7 @@ fn inline_string_getbyte(fun: &mut hir::Function, block: hir::BlockId, recv: hir
// the data dependency is gone (say, the StringGetbyte is elided), they can also be elided.
//
// This is unlike most other guards.
- let unboxed_index = fun.push_insn(block, hir::Insn::GuardLess { left: unboxed_index, right: len, state });
+ let unboxed_index = fun.push_insn(block, hir::Insn::GuardLess { left: unboxed_index, right: len, reason: SideExitReason::GuardLess, state });
let unboxed_index = fun.push_insn(block, hir::Insn::AdjustBounds { index: unboxed_index, length: len });
let zero = fun.push_insn(block, hir::Insn::Const { val: hir::Const::CInt64(0) });
use crate::hir::SideExitReason;
@@ -516,7 +516,7 @@ fn inline_string_setbyte(fun: &mut hir::Function, block: hir::BlockId, recv: hir
offset: RUBY_OFFSET_RSTRING_LEN as i32,
return_type: types::CInt64,
});
- let unboxed_index = fun.push_insn(block, hir::Insn::GuardLess { left: unboxed_index, right: len, state });
+ let unboxed_index = fun.push_insn(block, hir::Insn::GuardLess { left: unboxed_index, right: len, reason: SideExitReason::GuardLess, state });
let unboxed_index = fun.push_insn(block, hir::Insn::AdjustBounds { index: unboxed_index, length: len });
let zero = fun.push_insn(block, hir::Insn::Const { val: hir::Const::CInt64(0) });
use crate::hir::SideExitReason;
diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs
index e5976a4045..93dbbec690 100644
--- a/zjit/src/hir.rs
+++ b/zjit/src/hir.rs
@@ -1157,7 +1157,7 @@ pub enum Insn {
/// Side-exit if left is not greater than or equal to right (both operands are C long).
GuardGreaterEq { left: InsnId, right: InsnId, reason: SideExitReason, state: InsnId },
/// Side-exit if left is not less than right (both operands are C long).
- GuardLess { left: InsnId, right: InsnId, state: InsnId },
+ GuardLess { left: InsnId, right: InsnId, reason: SideExitReason, state: InsnId },
/// Generate no code (or padding if necessary) and insert a patch point
/// that can be rewritten to a side exit when the Invariant is broken.
@@ -1311,7 +1311,7 @@ macro_rules! for_each_operand_impl {
$visit_one!(state);
}
Insn::GuardGreaterEq { left, right, state, .. }
- | Insn::GuardLess { left, right, state } => {
+ | Insn::GuardLess { left, right, state, .. } => {
$visit_one!(left);
$visit_one!(right);
$visit_one!(state);
@@ -2099,7 +2099,13 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
Insn::GuardType { val, guard_type, .. } => { write!(f, "GuardType {val}, {}", guard_type.print(self.ptr_map)) },
Insn::RefineType { val, new_type, .. } => { write!(f, "RefineType {val}, {}", new_type.print(self.ptr_map)) },
Insn::HasType { val, expected, .. } => { write!(f, "HasType {val}, {}", expected.print(self.ptr_map)) },
- Insn::GuardBitEquals { val, expected, .. } => { write!(f, "GuardBitEquals {val}, {}", expected.print(self.ptr_map)) },
+ Insn::GuardBitEquals { val, expected, recompile, .. } => {
+ write!(f, "GuardBitEquals {val}, {}", expected.print(self.ptr_map))?;
+ if recompile.is_some() {
+ write!(f, " recompile")?;
+ }
+ return Ok(())
+ },
Insn::GuardAnyBitSet { val, mask, mask_name: Some(name), .. } => { write!(f, "GuardAnyBitSet {val}, {name}={}", mask.print(self.ptr_map)) },
Insn::GuardAnyBitSet { val, mask, .. } => { write!(f, "GuardAnyBitSet {val}, {}", mask.print(self.ptr_map)) },
Insn::GuardNoBitsSet { val, mask, mask_name: Some(name), .. } => { write!(f, "GuardNoBitsSet {val}, {name}={}", mask.print(self.ptr_map)) },
@@ -3323,10 +3329,18 @@ impl Function {
/// - `StaticallyKnown` if the receiver's exact class is known at compile-time
/// - Result of [`Self::resolve_receiver_type_from_profile`] if we need to check profile data
fn resolve_receiver_type(&self, recv: InsnId, recv_type: Type, insn_idx: YarvInsnIdx) -> ReceiverTypeResolution {
- if let Some(class) = recv_type.runtime_exact_ruby_class() {
- return ReceiverTypeResolution::StaticallyKnown { class };
+ match self.resolve_receiver_type_from_profile(recv, insn_idx) {
+ ReceiverTypeResolution::NoProfile => {
+ // Use known type information as a fallback because it doesn't have shape
+ // information (and we can generally eliminate duplicate guards).
+ if let Some(class) = recv_type.runtime_exact_ruby_class() {
+ ReceiverTypeResolution::StaticallyKnown { class }
+ } else {
+ ReceiverTypeResolution::NoProfile
+ }
+ }
+ resolution => resolution,
}
- self.resolve_receiver_type_from_profile(recv, insn_idx)
}
fn polymorphic_summary(&self, profiles: &ProfileOracle, recv: InsnId, insn_idx: YarvInsnIdx) -> Option<TypeDistributionSummary> {
@@ -5088,6 +5102,15 @@ impl Function {
_ => insn_id,
}
}
+ Insn::ArrayLength { array } => {
+ match self.type_of(array).ruby_object() {
+ Some(array_obj) if array_obj.is_frozen() => {
+ let length = unsafe { rb_jit_array_len(array_obj) };
+ self.new_insn(Insn::Const { val: Const::CInt64(length) })
+ }
+ _ => insn_id,
+ }
+ }
Insn::UnboxFixnum { val } => {
let recv_type = self.type_of(val);
match recv_type.fixnum_value() {
@@ -5107,6 +5130,18 @@ impl Function {
_ => insn_id,
}
},
+ Insn::GuardLess { left, right, state, reason } => {
+ let left_num = self.type_of(left).cint64_value();
+ let right_num = self.type_of(right).cint64_value();
+ match (left_num, right_num) {
+ (Some(l), Some(r)) if l < r => {
+ self.make_equal_to(insn_id, left);
+ continue
+ },
+ (Some(_), Some(_)) => self.new_insn(Insn::SideExit { state, reason, recompile: None }),
+ _ => insn_id,
+ }
+ },
Insn::GuardBitEquals { val, expected, .. } => {
let recv_type = self.type_of(val);
if recv_type.has_value(expected) {
@@ -6572,16 +6607,14 @@ impl ProfileOracle {
}
/// Map the interpreter-recorded types of the stack onto the HIR operands on our compile-time virtual stack.
- /// `stack_offset` is the number of extra stack entries above the profiled operands (e.g. 1 for
- /// sends with ARGS_BLOCKARG, where the block arg sits on top of the regular args).
- fn profile_stack(&mut self, state: &FrameState, stack_offset: usize) {
+ fn profile_stack(&mut self, state: &FrameState) {
let iseq_insn_idx = state.insn_idx;
let Some(operand_types) = self.payload.profile.get_operand_types(iseq_insn_idx) else { return };
let entry = self.types.entry(iseq_insn_idx).or_default();
// operand_types is always going to be <= stack size (otherwise it would have an underflow
// at run-time) so use that to drive iteration.
for (idx, insn_type_distribution) in operand_types.iter().rev().enumerate() {
- let insn = state.stack_topn(idx + stack_offset).expect("Unexpected stack underflow in profiling");
+ let insn = state.stack_topn(idx).expect("Unexpected stack underflow in profiling");
entry.push((insn, TypeDistributionSummary::new(insn_type_distribution)))
}
}
@@ -6784,17 +6817,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
}
}
else {
- // For sends with ARGS_BLOCKARG, the block arg sits on the stack above
- // the profiled operands (receiver + regular args). Skip it so that the
- // profile types map onto the correct HIR operands.
- let stack_offset = if opcode == YARVINSN_send || opcode == YARVINSN_opt_send_without_block {
- let cd: *const rb_call_data = get_arg(pc, 0).as_ptr();
- let flags = unsafe { vm_ci_flag(rb_get_call_data_ci(cd)) };
- usize::from(flags & VM_CALL_ARGS_BLOCKARG != 0)
- } else {
- 0
- };
- profiles.profile_stack(&exit_state, stack_offset);
+ profiles.profile_stack(&exit_state);
}
// Flag a future getlocal/setlocal to add a patch point if this instruction is not leaf.
@@ -7220,7 +7243,10 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
// Check if #new resolves to rb_class_new_instance_pass_kw.
// TODO: Guard on a profiled class and add a patch point for #new redefinition
- let argc = unsafe { vm_ci_argc((*cd).ci) } as usize;
+ let argc = crate::profile::num_arguments_on_stack(cd);
+ let ci = unsafe { get_call_data_ci(cd) };
+ let flags = unsafe { rb_vm_ci_flag(ci) };
+ assert_eq!(flags & VM_CALL_ARGS_BLOCKARG, 0);
let val = state.stack_topn(argc)?;
let test_id = fun.push_insn(block, Insn::IsMethodCfunc { val, cd, cfunc: rb_class_new_instance_pass_kw as *const u8, state: exit_id });
@@ -7646,7 +7672,8 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnhandledCallType(call_type), recompile: None });
break; // End the block
}
- let argc = unsafe { vm_ci_argc((*cd).ci) };
+ let argc = crate::profile::num_arguments_on_stack(cd);
+ assert_eq!(flags & VM_CALL_ARGS_BLOCKARG, 0);
// Side-exit send fallbacks while tracing to avoid FLAG_FINISH breaking throw TAG_RETURN semantics
if unsafe { rb_zjit_iseq_tracing_currently_enabled() } {
@@ -7751,7 +7778,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnhandledCallType(call_type), recompile: None });
break; // End the block
}
- let argc = unsafe { vm_ci_argc((*cd).ci) };
+ let argc = crate::profile::num_arguments_on_stack(cd);
let mid = unsafe { rb_vm_ci_mid(call_info) };
// Check for calls to directives
@@ -7885,10 +7912,9 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::SendWhileTracing, recompile: None });
break;
}
- let argc = unsafe { vm_ci_argc((*cd).ci) };
let block_arg = (flags & VM_CALL_ARGS_BLOCKARG) != 0;
- let args = state.stack_pop_n(argc as usize + usize::from(block_arg))?;
+ let args = state.stack_pop_n(crate::profile::num_arguments_on_stack(cd))?;
let recv = state.stack_pop()?;
let block_handler = if !blockiseq.is_null() {
Some(BlockHandler::BlockIseq(blockiseq))
@@ -7985,9 +8011,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::SendWhileTracing, recompile: None });
break;
}
- let argc = unsafe { vm_ci_argc((*cd).ci) };
- let block_arg = (flags & VM_CALL_ARGS_BLOCKARG) != 0;
- let args = state.stack_pop_n(argc as usize + usize::from(block_arg))?;
+ let args = state.stack_pop_n(crate::profile::num_arguments_on_stack(cd))?;
let recv = state.stack_pop()?;
let blockiseq: IseqPtr = get_arg(pc, 1).as_ptr();
let result = fun.push_insn(block, Insn::InvokeSuper { recv, cd, blockiseq, args, state: exit_id, reason: Uncategorized(opcode) });
@@ -8079,9 +8103,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::SendWhileTracing, recompile: None });
break;
}
- let argc = unsafe { vm_ci_argc((*cd).ci) };
- let block_arg = (flags & VM_CALL_ARGS_BLOCKARG) != 0;
- let args = state.stack_pop_n(argc as usize + usize::from(block_arg))?;
+ let args = state.stack_pop_n(crate::profile::num_arguments_on_stack(cd))?;
// Check if this is a monomorphic IFUNC block handler we can specialize
let block_handler_types = profiles.payload.profile.get_operand_types(exit_state.insn_idx);
@@ -8327,7 +8349,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
}
YARVINSN_objtostring => {
let cd: *const rb_call_data = get_arg(pc, 0).as_ptr();
- let argc = unsafe { vm_ci_argc((*cd).ci) };
+ let argc = crate::profile::num_arguments_on_stack(cd);
assert_eq!(0, argc, "objtostring should not have args");
let recv = state.stack_pop()?;
diff --git a/zjit/src/hir/opt_tests.rs b/zjit/src/hir/opt_tests.rs
index 3435347d33..4a83b40e38 100644
--- a/zjit/src/hir/opt_tests.rs
+++ b/zjit/src/hir/opt_tests.rs
@@ -222,13 +222,13 @@ mod hir_opt_tests {
bb3(v9:BasicObject, v10:BasicObject):
v14:Fixnum[0] = Const Value(0)
PatchPoint MethodRedefined(Integer@0x1008, *@0x1010, cme:0x1018)
- v35:Fixnum = GuardType v10, Fixnum
- v44:Fixnum[0] = Const Value(0)
- v45:Fixnum[0] = Const Value(0)
- PatchPoint MethodRedefined(Integer@0x1008, +@0x1040, cme:0x1048)
+ v36:Fixnum = GuardType v10, Fixnum
v46:Fixnum[0] = Const Value(0)
+ v47:Fixnum[0] = Const Value(0)
+ PatchPoint MethodRedefined(Integer@0x1008, +@0x1040, cme:0x1048)
+ v48:Fixnum[0] = Const Value(0)
CheckInterrupts
- Return v46
+ Return v48
");
}
@@ -608,9 +608,9 @@ mod hir_opt_tests {
v10:Fixnum[4] = Const Value(4)
v12:Fixnum[-7] = Const Value(-7)
PatchPoint MethodRedefined(Integer@0x1000, &@0x1008, cme:0x1010)
- v24:Fixnum[0] = Const Value(0)
+ v25:Fixnum[0] = Const Value(0)
CheckInterrupts
- Return v24
+ Return v25
");
}
@@ -637,9 +637,9 @@ mod hir_opt_tests {
v10:Fixnum[-4] = Const Value(-4)
v12:Fixnum[7] = Const Value(7)
PatchPoint MethodRedefined(Integer@0x1000, &@0x1008, cme:0x1010)
- v24:Fixnum[4] = Const Value(4)
+ v25:Fixnum[4] = Const Value(4)
CheckInterrupts
- Return v24
+ Return v25
");
}
@@ -666,9 +666,9 @@ mod hir_opt_tests {
v10:Fixnum[4] = Const Value(4)
v12:Fixnum[1] = Const Value(1)
PatchPoint MethodRedefined(Integer@0x1000, |@0x1008, cme:0x1010)
- v24:Fixnum[5] = Const Value(5)
+ v25:Fixnum[5] = Const Value(5)
CheckInterrupts
- Return v24
+ Return v25
");
}
@@ -695,9 +695,9 @@ mod hir_opt_tests {
v10:Fixnum[-4] = Const Value(-4)
v12:Fixnum[1] = Const Value(1)
PatchPoint MethodRedefined(Integer@0x1000, |@0x1008, cme:0x1010)
- v24:Fixnum[-3] = Const Value(-3)
+ v25:Fixnum[-3] = Const Value(-3)
CheckInterrupts
- Return v24
+ Return v25
");
}
@@ -724,9 +724,9 @@ mod hir_opt_tests {
v10:Fixnum[4] = Const Value(4)
v12:Fixnum[-1] = Const Value(-1)
PatchPoint MethodRedefined(Integer@0x1000, |@0x1008, cme:0x1010)
- v24:Fixnum[-1] = Const Value(-1)
+ v25:Fixnum[-1] = Const Value(-1)
CheckInterrupts
- Return v24
+ Return v25
");
}
@@ -1076,9 +1076,8 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Array@0x1008)
PatchPoint MethodRedefined(Array@0x1008, []@0x1010, cme:0x1018)
v32:CInt64[-10] = Const CInt64(-10)
- v26:CInt64 = ArrayLength v11
- v27:CInt64[-10] = GuardLess v32, v26
- v28:CInt64 = AdjustBounds v27, v26
+ v33:CInt64[3] = Const CInt64(3)
+ v28:CInt64 = AdjustBounds v32, v33
v29:CInt64[0] = Const CInt64(0)
v30:CInt64 = GuardGreaterEq v28, v29
v31:BasicObject = ArrayAref v11, v30
@@ -1905,10 +1904,10 @@ mod hir_opt_tests {
bb3(v9:BasicObject, v10:BasicObject):
v14:Fixnum[1] = Const Value(1)
PatchPoint MethodRedefined(Integer@0x1008, +@0x1010, cme:0x1018)
- v26:Fixnum = GuardType v10, Fixnum
- v27:Fixnum = FixnumAdd v14, v26
+ v27:Fixnum = GuardType v10, Fixnum
+ v28:Fixnum = FixnumAdd v14, v27
CheckInterrupts
- Return v27
+ Return v28
");
}
@@ -2105,10 +2104,10 @@ mod hir_opt_tests {
bb3(v9:BasicObject, v10:BasicObject):
v14:Fixnum[1] = Const Value(1)
PatchPoint MethodRedefined(Integer@0x1008, <@0x1010, cme:0x1018)
- v26:Fixnum = GuardType v10, Fixnum
- v27:BoolExact = FixnumLt v14, v26
+ v27:Fixnum = GuardType v10, Fixnum
+ v28:BoolExact = FixnumLt v14, v27
CheckInterrupts
- Return v27
+ Return v28
");
}
@@ -3207,10 +3206,10 @@ mod hir_opt_tests {
bb3(v8:BasicObject, v9:NilClass):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, M)
- v29:ModuleExact[VALUE(0x1008)] = Const Value(VALUE(0x1008))
+ v29:ModuleExact[M@0x1008] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(Module@0x1010)
PatchPoint MethodRedefined(Module@0x1010, name@0x1018, cme:0x1020)
- v33:StringExact|NilClass = CCall v29, :Module#name@0x1048
+ v34:StringExact|NilClass = CCall v29, :Module#name@0x1048
PatchPoint NoEPEscape(test)
v21:Fixnum[1] = Const Value(1)
CheckInterrupts
@@ -3266,7 +3265,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, C)
- v18:Class[C@0x1008] = Const Value(VALUE(0x1008))
+ v18:ClassSubclass[C@0x1008] = Const Value(VALUE(0x1008))
CheckInterrupts
Return v18
");
@@ -3291,13 +3290,13 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, String)
- v26:Class[String@0x1008] = Const Value(VALUE(0x1008))
+ v26:ClassSubclass[String@0x1008] = Const Value(VALUE(0x1008))
PatchPoint StableConstantNames(0x1010, Class)
- v29:Class[Class@0x1018] = Const Value(VALUE(0x1018))
+ v29:ClassSubclass[Class@0x1018] = Const Value(VALUE(0x1018))
PatchPoint StableConstantNames(0x1020, Module)
- v32:Class[Module@0x1028] = Const Value(VALUE(0x1028))
+ v32:ClassSubclass[Module@0x1028] = Const Value(VALUE(0x1028))
PatchPoint StableConstantNames(0x1030, BasicObject)
- v35:Class[BasicObject@0x1038] = Const Value(VALUE(0x1038))
+ v35:ClassSubclass[BasicObject@0x1038] = Const Value(VALUE(0x1038))
v18:ArrayExact = NewArray v26, v29, v32, v35
CheckInterrupts
Return v18
@@ -3323,9 +3322,9 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, Enumerable)
- v22:ModuleExact[VALUE(0x1008)] = Const Value(VALUE(0x1008))
+ v22:ModuleExact[Enumerable@0x1008] = Const Value(VALUE(0x1008))
PatchPoint StableConstantNames(0x1010, Kernel)
- v25:ModuleExact[VALUE(0x1018)] = Const Value(VALUE(0x1018))
+ v25:ModuleSubclass[Kernel@0x1018] = Const Value(VALUE(0x1018))
v14:ArrayExact = NewArray v22, v25
CheckInterrupts
Return v14
@@ -3353,7 +3352,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, MY_MODULE)
- v18:ModuleSubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
+ v18:ModuleSubclass[MY_MODULE@0x1008] = Const Value(VALUE(0x1008))
CheckInterrupts
Return v18
");
@@ -3575,12 +3574,12 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, M)
- v20:ModuleExact[VALUE(0x1008)] = Const Value(VALUE(0x1008))
+ v20:ModuleExact[M@0x1008] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(Module@0x1010)
PatchPoint MethodRedefined(Module@0x1010, class@0x1018, cme:0x1020)
- v25:Class[Module@0x1010] = Const Value(VALUE(0x1010))
+ v26:ClassSubclass[Module@0x1010] = Const Value(VALUE(0x1010))
CheckInterrupts
- Return v25
+ Return v26
");
}
@@ -4392,7 +4391,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, Kernel)
- v18:ModuleExact[VALUE(0x1008)] = Const Value(VALUE(0x1008))
+ v18:ModuleSubclass[Kernel@0x1008] = Const Value(VALUE(0x1008))
CheckInterrupts
Return v18
");
@@ -4423,7 +4422,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, Foo::Bar::C)
- v18:Class[Foo::Bar::C@0x1008] = Const Value(VALUE(0x1008))
+ v18:ClassSubclass[Foo::Bar::C@0x1008] = Const Value(VALUE(0x1008))
CheckInterrupts
Return v18
");
@@ -4449,13 +4448,13 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, C)
- v43:Class[C@0x1008] = Const Value(VALUE(0x1008))
+ v43:ClassSubclass[C@0x1008] = Const Value(VALUE(0x1008))
v12:NilClass = Const Value(nil)
PatchPoint MethodRedefined(C@0x1008, new@0x1009, cme:0x1010)
v46:ObjectSubclass[class_exact:C] = ObjectAllocClass C:VALUE(0x1008)
PatchPoint NoSingletonClass(C@0x1008)
PatchPoint MethodRedefined(C@0x1008, initialize@0x1038, cme:0x1040)
- v50:NilClass = Const Value(nil)
+ v51:NilClass = Const Value(nil)
CheckInterrupts
Return v46
");
@@ -4485,14 +4484,14 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, C)
- v46:Class[C@0x1008] = Const Value(VALUE(0x1008))
+ v46:ClassSubclass[C@0x1008] = Const Value(VALUE(0x1008))
v12:NilClass = Const Value(nil)
v15:Fixnum[1] = Const Value(1)
PatchPoint MethodRedefined(C@0x1008, new@0x1009, cme:0x1010)
v49:ObjectSubclass[class_exact:C] = ObjectAllocClass C:VALUE(0x1008)
PatchPoint NoSingletonClass(C@0x1008)
PatchPoint MethodRedefined(C@0x1008, initialize@0x1038, cme:0x1040)
- v52:BasicObject = SendDirect v49, 0x1068, :initialize (0x1078), v15
+ v53:BasicObject = SendDirect v49, 0x1068, :initialize (0x1078), v15
CheckInterrupts
Return v49
");
@@ -4517,13 +4516,13 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, Object)
- v43:Class[Object@0x1008] = Const Value(VALUE(0x1008))
+ v43:ClassSubclass[Object@0x1008] = Const Value(VALUE(0x1008))
v12:NilClass = Const Value(nil)
PatchPoint MethodRedefined(Object@0x1008, new@0x1009, cme:0x1010)
v46:ObjectExact = ObjectAllocClass Object:VALUE(0x1008)
PatchPoint NoSingletonClass(Object@0x1008)
PatchPoint MethodRedefined(Object@0x1008, initialize@0x1038, cme:0x1040)
- v50:NilClass = Const Value(nil)
+ v51:NilClass = Const Value(nil)
CheckInterrupts
Return v46
");
@@ -4548,13 +4547,13 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, BasicObject)
- v43:Class[BasicObject@0x1008] = Const Value(VALUE(0x1008))
+ v43:ClassSubclass[BasicObject@0x1008] = Const Value(VALUE(0x1008))
v12:NilClass = Const Value(nil)
PatchPoint MethodRedefined(BasicObject@0x1008, new@0x1009, cme:0x1010)
v46:BasicObjectExact = ObjectAllocClass BasicObject:VALUE(0x1008)
PatchPoint NoSingletonClass(BasicObject@0x1008)
PatchPoint MethodRedefined(BasicObject@0x1008, initialize@0x1038, cme:0x1040)
- v50:NilClass = Const Value(nil)
+ v51:NilClass = Const Value(nil)
CheckInterrupts
Return v46
");
@@ -4579,14 +4578,14 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, Hash)
- v43:Class[Hash@0x1008] = Const Value(VALUE(0x1008))
+ v43:ClassSubclass[Hash@0x1008] = Const Value(VALUE(0x1008))
v12:NilClass = Const Value(nil)
PatchPoint MethodRedefined(Hash@0x1008, new@0x1009, cme:0x1010)
v46:HashExact = ObjectAllocClass Hash:VALUE(0x1008)
v47:Fixnum[0] = Const Value(0)
PatchPoint NoSingletonClass(Hash@0x1008)
PatchPoint MethodRedefined(Hash@0x1008, initialize@0x1038, cme:0x1040)
- v51:BasicObject = SendDirect v46, 0x1068, :initialize (0x1078), v47
+ v52:BasicObject = SendDirect v46, 0x1068, :initialize (0x1078), v47
CheckInterrupts
Return v46
");
@@ -4612,14 +4611,14 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, Array)
- v46:Class[Array@0x1008] = Const Value(VALUE(0x1008))
+ v46:ClassSubclass[Array@0x1008] = Const Value(VALUE(0x1008))
v12:NilClass = Const Value(nil)
v15:Fixnum[1] = Const Value(1)
PatchPoint MethodRedefined(Array@0x1008, new@0x1009, cme:0x1010)
PatchPoint MethodRedefined(Class@0x1038, new@0x1009, cme:0x1010)
- v52:BasicObject = CCallVariadic v46, :Array.new@0x1040, v15
+ v53:BasicObject = CCallVariadic v46, :Array.new@0x1040, v15
CheckInterrupts
- Return v52
+ Return v53
");
}
@@ -4642,7 +4641,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, Set)
- v43:Class[Set@0x1008] = Const Value(VALUE(0x1008))
+ v43:ClassSubclass[Set@0x1008] = Const Value(VALUE(0x1008))
v12:NilClass = Const Value(nil)
PatchPoint MethodRedefined(Set@0x1008, new@0x1009, cme:0x1010)
v17:HeapBasicObject = ObjectAlloc v43
@@ -4674,13 +4673,13 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, String)
- v43:Class[String@0x1008] = Const Value(VALUE(0x1008))
+ v43:ClassSubclass[String@0x1008] = Const Value(VALUE(0x1008))
v12:NilClass = Const Value(nil)
PatchPoint MethodRedefined(String@0x1008, new@0x1009, cme:0x1010)
PatchPoint MethodRedefined(Class@0x1038, new@0x1009, cme:0x1010)
- v53:BasicObject = CCallVariadic v43, :String.new@0x1040
+ v54:BasicObject = CCallVariadic v43, :String.new@0x1040
CheckInterrupts
- Return v53
+ Return v54
");
}
@@ -4703,7 +4702,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, Regexp)
- v47:Class[Regexp@0x1008] = Const Value(VALUE(0x1008))
+ v47:ClassSubclass[Regexp@0x1008] = Const Value(VALUE(0x1008))
v12:NilClass = Const Value(nil)
v15:StringExact[VALUE(0x1010)] = Const Value(VALUE(0x1010))
v16:StringExact = StringCopy v15
@@ -4711,7 +4710,7 @@ mod hir_opt_tests {
v50:RegexpExact = ObjectAllocClass Regexp:VALUE(0x1008)
PatchPoint NoSingletonClass(Regexp@0x1008)
PatchPoint MethodRedefined(Regexp@0x1008, initialize@0x1048, cme:0x1050)
- v54:BasicObject = CCallVariadic v50, :Regexp#initialize@0x1078, v16
+ v55:BasicObject = CCallVariadic v50, :Regexp#initialize@0x1078, v16
CheckInterrupts
Return v50
");
@@ -4737,11 +4736,11 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, C)
- v20:Class[C@0x1008] = Const Value(VALUE(0x1008))
+ v20:ClassSubclass[C@0x1008] = Const Value(VALUE(0x1008))
PatchPoint MethodRedefined(Class@0x1010, allocate@0x1018, cme:0x1020)
- v23:ObjectSubclass[class_exact:C] = ObjectAllocClass C:VALUE(0x1008)
+ v24:ObjectSubclass[class_exact:C] = ObjectAllocClass C:VALUE(0x1008)
CheckInterrupts
- Return v23
+ Return v24
");
}
@@ -4767,7 +4766,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, C)
- v22:Class[C@0x1008] = Const Value(VALUE(0x1008))
+ v22:ClassSubclass[C@0x1008] = Const Value(VALUE(0x1008))
v12:Fixnum[1] = Const Value(1)
v14:BasicObject = Send v22, :allocate, v12 # SendFallbackReason: SendWithoutBlock: unsupported method type Cfunc
CheckInterrupts
@@ -4797,11 +4796,11 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, SC)
- v20:Class[Class@0x1008] = Const Value(VALUE(0x1008))
+ v20:ClassSubclass[Class@0x1008] = Const Value(VALUE(0x1008))
PatchPoint MethodRedefined(Class@0x1010, allocate@0x1018, cme:0x1020)
- v23:BasicObject = CCallWithFrame v20, :Class.allocate@0x1048
+ v24:BasicObject = CCallWithFrame v20, :Class.allocate@0x1048
CheckInterrupts
- Return v23
+ Return v24
");
}
@@ -5270,7 +5269,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
v16:HeapBasicObject = GuardType v6, HeapBasicObject
v17:CShape = LoadField v16, :shape_id@0x1000
- v18:CShape[0x1001] = GuardBitEquals v17, CShape(0x1001)
+ v18:CShape[0x1001] = GuardBitEquals v17, CShape(0x1001) recompile
v19:StringExact[VALUE(0x1008)] = Const Value(VALUE(0x1008))
CheckInterrupts
Return v19
@@ -5296,7 +5295,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
v16:HeapBasicObject = GuardType v6, HeapBasicObject
v17:CShape = LoadField v16, :shape_id@0x1000
- v18:CShape[0x1001] = GuardBitEquals v17, CShape(0x1001)
+ v18:CShape[0x1001] = GuardBitEquals v17, CShape(0x1001) recompile
v19:NilClass = Const Value(nil)
CheckInterrupts
Return v19
@@ -5614,7 +5613,7 @@ mod hir_opt_tests {
PatchPoint SingleRactorMode
v21:HeapBasicObject = GuardType v6, HeapBasicObject
v22:CShape = LoadField v21, :shape_id@0x1000
- v23:CShape[0x1001] = GuardBitEquals v22, CShape(0x1001)
+ v23:CShape[0x1001] = GuardBitEquals v22, CShape(0x1001) recompile
StoreField v21, :@foo@0x1002, v10
WriteBarrier v21, v10
CheckInterrupts
@@ -5643,7 +5642,7 @@ mod hir_opt_tests {
PatchPoint SingleRactorMode
v21:HeapBasicObject = GuardType v6, HeapBasicObject
v22:CShape = LoadField v21, :shape_id@0x1000
- v23:CShape[0x1001] = GuardBitEquals v22, CShape(0x1001)
+ v23:CShape[0x1001] = GuardBitEquals v22, CShape(0x1001) recompile
StoreField v21, :@foo@0x1002, v10
WriteBarrier v21, v10
v26:CShape[0x1003] = Const CShape(0x1003)
@@ -5688,7 +5687,7 @@ mod hir_opt_tests {
PatchPoint SingleRactorMode
v28:HeapBasicObject = GuardType v6, HeapBasicObject
v29:CShape = LoadField v28, :shape_id@0x1000
- v30:CShape[0x1001] = GuardBitEquals v29, CShape(0x1001)
+ v30:CShape[0x1001] = GuardBitEquals v29, CShape(0x1001) recompile
StoreField v28, :@foo@0x1002, v10
WriteBarrier v28, v10
v33:CShape[0x1003] = Const CShape(0x1003)
@@ -6368,8 +6367,8 @@ mod hir_opt_tests {
v28:ArrayExact = GuardType v10, ArrayExact
PatchPoint NoSingletonClass(Array@0x1010)
PatchPoint MethodRedefined(Array@0x1010, to_s@0x1018, cme:0x1020)
- v33:BasicObject = CCallWithFrame v28, :Array#to_s@0x1048
- v20:String = AnyToString v28, str: v33
+ v34:BasicObject = CCallWithFrame v28, :Array#to_s@0x1048
+ v20:String = AnyToString v28, str: v34
v22:StringExact = StringConcat v14, v20
CheckInterrupts
Return v22
@@ -6459,12 +6458,12 @@ mod hir_opt_tests {
v12:Fixnum[0] = Const Value(0)
PatchPoint NoSingletonClass(Array@0x1010)
PatchPoint MethodRedefined(Array@0x1010, []@0x1018, cme:0x1020)
- v34:CInt64[0] = Const CInt64(0)
- v28:CInt64 = ArrayLength v23
- v29:CInt64[0] = GuardLess v34, v28
- v33:BasicObject = ArrayAref v23, v29
+ v35:CInt64[0] = Const CInt64(0)
+ v29:CInt64 = ArrayLength v23
+ v30:CInt64[0] = GuardLess v35, v29
+ v34:BasicObject = ArrayAref v23, v30
CheckInterrupts
- Return v33
+ Return v34
");
// TODO(max): Check the result of `S[0] = 5; test` using `inspect` to make sure that we
// actually do the load at run-time.
@@ -6491,12 +6490,9 @@ mod hir_opt_tests {
v13:Fixnum[1] = Const Value(1)
PatchPoint NoSingletonClass(Array@0x1008)
PatchPoint MethodRedefined(Array@0x1008, []@0x1010, cme:0x1018)
- v32:CInt64[1] = Const CInt64(1)
- v26:CInt64 = ArrayLength v11
- v27:CInt64[1] = GuardLess v32, v26
- v33:Fixnum[5] = Const Value(5)
+ v34:Fixnum[5] = Const Value(5)
CheckInterrupts
- Return v33
+ Return v34
");
}
@@ -6522,9 +6518,8 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Array@0x1008)
PatchPoint MethodRedefined(Array@0x1008, []@0x1010, cme:0x1018)
v32:CInt64[-3] = Const CInt64(-3)
- v26:CInt64 = ArrayLength v11
- v27:CInt64[-3] = GuardLess v32, v26
- v28:CInt64 = AdjustBounds v27, v26
+ v33:CInt64[3] = Const CInt64(3)
+ v28:CInt64 = AdjustBounds v32, v33
v29:CInt64[0] = Const CInt64(0)
v30:CInt64 = GuardGreaterEq v28, v29
v31:BasicObject = ArrayAref v11, v30
@@ -6555,9 +6550,8 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Array@0x1008)
PatchPoint MethodRedefined(Array@0x1008, []@0x1010, cme:0x1018)
v32:CInt64[-10] = Const CInt64(-10)
- v26:CInt64 = ArrayLength v11
- v27:CInt64[-10] = GuardLess v32, v26
- v28:CInt64 = AdjustBounds v27, v26
+ v33:CInt64[3] = Const CInt64(3)
+ v28:CInt64 = AdjustBounds v32, v33
v29:CInt64[0] = Const CInt64(0)
v30:CInt64 = GuardGreaterEq v28, v29
v31:BasicObject = ArrayAref v11, v30
@@ -6587,12 +6581,7 @@ mod hir_opt_tests {
v13:Fixnum[10] = Const Value(10)
PatchPoint NoSingletonClass(Array@0x1008)
PatchPoint MethodRedefined(Array@0x1008, []@0x1010, cme:0x1018)
- v32:CInt64[10] = Const CInt64(10)
- v26:CInt64 = ArrayLength v11
- v27:CInt64[10] = GuardLess v32, v26
- v33:NilClass = Const Value(nil)
- CheckInterrupts
- Return v33
+ SideExit GuardLess
");
}
@@ -6840,7 +6829,7 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, Foo)
- v22:Class[Foo@0x1008] = Const Value(VALUE(0x1008))
+ v22:ClassSubclass[Foo@0x1008] = Const Value(VALUE(0x1008))
v12:Fixnum[100] = Const Value(100)
PatchPoint MethodRedefined(Class@0x1010, identity@0x1018, cme:0x1020)
CheckInterrupts
@@ -7509,7 +7498,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(C@0x1008, foo@0x1010, cme:0x1018)
v23:ObjectSubclass[class_exact:C] = GuardType v10, ObjectSubclass[class_exact:C]
v26:CShape = LoadField v23, :shape_id@0x1040
- v27:CShape[0x1041] = GuardBitEquals v26, CShape(0x1041)
+ v27:CShape[0x1041] = GuardBitEquals v26, CShape(0x1041) recompile
v28:BasicObject = LoadField v23, :@foo@0x1042
CheckInterrupts
Return v28
@@ -7777,7 +7766,7 @@ mod hir_opt_tests {
PatchPoint SingleRactorMode
v17:Module = GuardType v6, Module
v18:CShape = LoadField v17, :shape_id@0x1000
- v19:CShape[0x1001] = GuardBitEquals v18, CShape(0x1001)
+ v19:CShape[0x1001] = GuardBitEquals v18, CShape(0x1001) recompile
PatchPoint RootBoxOnly
v21:RubyValue = LoadField v17, :fields_obj@0x1002
v22:BasicObject = LoadField v21, :@foo@0x1003
@@ -7849,7 +7838,7 @@ mod hir_opt_tests {
PatchPoint SingleRactorMode
v17:Class = GuardType v6, Class
v18:CShape = LoadField v17, :shape_id@0x1000
- v19:CShape[0x1001] = GuardBitEquals v18, CShape(0x1001)
+ v19:CShape[0x1001] = GuardBitEquals v18, CShape(0x1001) recompile
PatchPoint RootBoxOnly
v21:RubyValue = LoadField v17, :fields_obj@0x1002
v22:BasicObject = LoadField v21, :@foo@0x1003
@@ -7914,7 +7903,7 @@ mod hir_opt_tests {
PatchPoint SingleRactorMode
v17:HeapBasicObject = GuardType v6, HeapBasicObject
v18:CShape = LoadField v17, :shape_id@0x1000
- v19:CShape[0x1001] = GuardBitEquals v18, CShape(0x1001)
+ v19:CShape[0x1001] = GuardBitEquals v18, CShape(0x1001) recompile
v20:CAttrIndex[0] = Const CAttrIndex(0)
v21:BasicObject = CCall v17, :rb_ivar_get_at_no_ractor_check@0x1008, v20
CheckInterrupts
@@ -7949,7 +7938,7 @@ mod hir_opt_tests {
PatchPoint SingleRactorMode
v17:TypedTData = GuardType v6, TypedTData
v18:CShape = LoadField v17, :shape_id@0x1000
- v19:CShape[0x1001] = GuardBitEquals v18, CShape(0x1001)
+ v19:CShape[0x1001] = GuardBitEquals v18, CShape(0x1001) recompile
v20:RubyValue = LoadField v17, :fields_obj@0x1002
v21:BasicObject = LoadField v20, :@a@0x1002
CheckInterrupts
@@ -8186,7 +8175,7 @@ mod hir_opt_tests {
Jump bb4(v29)
bb8():
v44:CShape = LoadField v11, :shape_id@0x1005
- v45:CShape[0x1006] = GuardBitEquals v44, CShape(0x1006)
+ v45:CShape[0x1006] = GuardBitEquals v44, CShape(0x1006) recompile
v46:CPtr = LoadField v11, :as_heap@0x1002
v47:BasicObject = LoadField v46, :@foo@0x1000
Jump bb4(v47)
@@ -8454,9 +8443,9 @@ mod hir_opt_tests {
v11:ArrayExact = ArrayDup v10
PatchPoint NoSingletonClass(Array@0x1008)
PatchPoint MethodRedefined(Array@0x1008, map@0x1010, cme:0x1018)
- v21:BasicObject = SendDirect v11, 0x1040, :map (0x1050)
+ v22:BasicObject = SendDirect v11, 0x1040, :map (0x1050)
CheckInterrupts
- Return v21
+ Return v22
");
}
@@ -8495,7 +8484,7 @@ mod hir_opt_tests {
v41:ArrayExact[VALUE(0x1018)] = Const Value(VALUE(0x1018))
PatchPoint NoSingletonClass(Array@0x1020)
PatchPoint MethodRedefined(Array@0x1020, zip@0x1028, cme:0x1030)
- v45:BasicObject = CCallVariadic v38, :Array#zip@0x1058, v41
+ v46:BasicObject = CCallVariadic v38, :Array#zip@0x1058, v41
PatchPoint NoEPEscape(test)
v24:CPtr = LoadSP
v25:BasicObject = LoadField v24, :result@0x1060
@@ -8744,11 +8733,11 @@ mod hir_opt_tests {
v20:ObjectSubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(C@0x1010)
PatchPoint MethodRedefined(C@0x1010, foo@0x1018, cme:0x1020)
- v25:CShape = LoadField v20, :shape_id@0x1048
- v26:CShape[0x1049] = GuardBitEquals v25, CShape(0x1049)
- v27:NilClass = Const Value(nil)
+ v26:CShape = LoadField v20, :shape_id@0x1048
+ v27:CShape[0x1049] = GuardBitEquals v26, CShape(0x1049) recompile
+ v28:NilClass = Const Value(nil)
CheckInterrupts
- Return v27
+ Return v28
");
}
@@ -8780,11 +8769,11 @@ mod hir_opt_tests {
v20:ObjectSubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(C@0x1010)
PatchPoint MethodRedefined(C@0x1010, foo@0x1018, cme:0x1020)
- v25:CShape = LoadField v20, :shape_id@0x1048
- v26:CShape[0x1049] = GuardBitEquals v25, CShape(0x1049)
- v27:NilClass = Const Value(nil)
+ v26:CShape = LoadField v20, :shape_id@0x1048
+ v27:CShape[0x1049] = GuardBitEquals v26, CShape(0x1049) recompile
+ v28:NilClass = Const Value(nil)
CheckInterrupts
- Return v27
+ Return v28
");
}
@@ -8817,7 +8806,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(C@0x1008, foo@0x1010, cme:0x1018)
v23:ObjectSubclass[class_exact:C] = GuardType v10, ObjectSubclass[class_exact:C]
v26:CShape = LoadField v23, :shape_id@0x1040
- v27:CShape[0x1041] = GuardBitEquals v26, CShape(0x1041)
+ v27:CShape[0x1041] = GuardBitEquals v26, CShape(0x1041) recompile
v28:NilClass = Const Value(nil)
CheckInterrupts
Return v28
@@ -8853,7 +8842,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(C@0x1008, foo@0x1010, cme:0x1018)
v23:ObjectSubclass[class_exact:C] = GuardType v10, ObjectSubclass[class_exact:C]
v26:CShape = LoadField v23, :shape_id@0x1040
- v27:CShape[0x1041] = GuardBitEquals v26, CShape(0x1041)
+ v27:CShape[0x1041] = GuardBitEquals v26, CShape(0x1041) recompile
v28:NilClass = Const Value(nil)
CheckInterrupts
Return v28
@@ -9347,8 +9336,8 @@ mod hir_opt_tests {
v14:StringExact[VALUE(0x1008)] = Const Value(VALUE(0x1008))
v28:Fixnum = GuardType v10, Fixnum
PatchPoint MethodRedefined(Integer@0x1010, to_s@0x1018, cme:0x1020)
- v32:StringExact = CCallVariadic v28, :Integer#to_s@0x1048
- v22:StringExact = StringConcat v14, v32
+ v33:StringExact = CCallVariadic v28, :Integer#to_s@0x1048
+ v22:StringExact = StringConcat v14, v33
CheckInterrupts
Return v22
");
@@ -9593,9 +9582,9 @@ mod hir_opt_tests {
v12:StaticSymbol[:a] = Const Value(VALUE(0x1010))
PatchPoint NoSingletonClass(Hash@0x1018)
PatchPoint MethodRedefined(Hash@0x1018, []@0x1020, cme:0x1028)
- v27:BasicObject = HashAref v23, v12
+ v28:BasicObject = HashAref v23, v12
CheckInterrupts
- Return v27
+ Return v28
");
}
@@ -9722,13 +9711,13 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, Thread)
- v20:Class[Thread@0x1008] = Const Value(VALUE(0x1008))
+ v20:ClassSubclass[Thread@0x1008] = Const Value(VALUE(0x1008))
PatchPoint MethodRedefined(Class@0x1010, current@0x1018, cme:0x1020)
- v23:CPtr = LoadEC
- v24:CPtr = LoadField v23, :thread_ptr@0x1048
- v25:BasicObject = LoadField v24, :self@0x1049
+ v24:CPtr = LoadEC
+ v25:CPtr = LoadField v24, :thread_ptr@0x1048
+ v26:BasicObject = LoadField v25, :self@0x1049
CheckInterrupts
- Return v25
+ Return v26
");
}
@@ -12413,9 +12402,9 @@ mod hir_opt_tests {
v14:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
PatchPoint NoSingletonClass(String@0x1008)
PatchPoint MethodRedefined(String@0x1008, ==@0x1010, cme:0x1018)
- v31:TrueClass = Const Value(true)
+ v32:TrueClass = Const Value(true)
CheckInterrupts
- Return v31
+ Return v32
");
}
@@ -12445,9 +12434,9 @@ mod hir_opt_tests {
v14:StringExact[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(String@0x1010)
PatchPoint MethodRedefined(String@0x1010, ==@0x1018, cme:0x1020)
- v27:FalseClass = Const Value(false)
+ v28:FalseClass = Const Value(false)
CheckInterrupts
- Return v27
+ Return v28
");
}
@@ -12478,9 +12467,9 @@ mod hir_opt_tests {
v14:StringExact = StringCopy v13
PatchPoint NoSingletonClass(String@0x1008)
PatchPoint MethodRedefined(String@0x1008, ==@0x1010, cme:0x1018)
- v26:BoolExact = StringEqual v11, v14
+ v27:BoolExact = StringEqual v11, v14
CheckInterrupts
- Return v26
+ Return v27
");
}
@@ -12511,9 +12500,9 @@ mod hir_opt_tests {
v14:StringExact = StringCopy v13
PatchPoint NoSingletonClass(String@0x1010)
PatchPoint MethodRedefined(String@0x1010, ==@0x1018, cme:0x1020)
- v26:BoolExact = StringEqual v11, v14
+ v27:BoolExact = StringEqual v11, v14
CheckInterrupts
- Return v26
+ Return v27
");
}
@@ -12543,9 +12532,9 @@ mod hir_opt_tests {
v12:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
PatchPoint NoSingletonClass(String@0x1008)
PatchPoint MethodRedefined(String@0x1008, ==@0x1010, cme:0x1018)
- v25:TrueClass = Const Value(true)
+ v26:TrueClass = Const Value(true)
CheckInterrupts
- Return v25
+ Return v26
");
}
@@ -12575,9 +12564,9 @@ mod hir_opt_tests {
v12:StringExact[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(String@0x1010)
PatchPoint MethodRedefined(String@0x1010, ==@0x1018, cme:0x1020)
- v25:FalseClass = Const Value(false)
+ v26:FalseClass = Const Value(false)
CheckInterrupts
- Return v25
+ Return v26
");
}
@@ -12617,13 +12606,13 @@ mod hir_opt_tests {
v28:StringExact = StringCopy v27
PatchPoint NoSingletonClass(String@0x1008)
PatchPoint MethodRedefined(String@0x1008, <<@0x1010, cme:0x1018)
- v49:StringExact = StringAppend v17, v28
+ v50:StringExact = StringAppend v17, v28
PatchPoint NoEPEscape(test)
PatchPoint NoSingletonClass(String@0x1008)
PatchPoint MethodRedefined(String@0x1008, ==@0x1040, cme:0x1048)
- v53:BoolExact = StringEqual v17, v22
+ v55:BoolExact = StringEqual v17, v22
CheckInterrupts
- Return v53
+ Return v55
");
}
@@ -12685,10 +12674,10 @@ mod hir_opt_tests {
v15:StringExact = StringCopy v14
PatchPoint NoSingletonClass(String@0x1010)
PatchPoint MethodRedefined(String@0x1010, ==@0x1018, cme:0x1020)
- v28:String = GuardType v10, String
- v29:BoolExact = StringEqual v15, v28
+ v29:String = GuardType v10, String
+ v30:BoolExact = StringEqual v15, v29
CheckInterrupts
- Return v29
+ Return v30
");
}
@@ -12979,12 +12968,12 @@ mod hir_opt_tests {
bb3(v9:BasicObject, v10:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1008, String)
- v27:Class[String@0x1010] = Const Value(VALUE(0x1010))
+ v27:ClassSubclass[String@0x1010] = Const Value(VALUE(0x1010))
PatchPoint NoEPEscape(test)
PatchPoint MethodRedefined(Class@0x1018, ===@0x1020, cme:0x1028)
- v30:BoolExact = IsA v10, v27
+ v31:BoolExact = IsA v10, v27
CheckInterrupts
- Return v30
+ Return v31
");
}
@@ -13010,12 +12999,12 @@ mod hir_opt_tests {
bb3(v9:BasicObject, v10:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1008, Kernel)
- v27:ModuleExact[VALUE(0x1010)] = Const Value(VALUE(0x1010))
+ v27:ModuleSubclass[Kernel@0x1010] = Const Value(VALUE(0x1010))
PatchPoint NoEPEscape(test)
PatchPoint MethodRedefined(Module@0x1018, ===@0x1020, cme:0x1028)
- v30:BoolExact = CCall v27, :Module#===@0x1050, v10
+ v31:BoolExact = CCall v27, :Module#===@0x1050, v10
CheckInterrupts
- Return v30
+ Return v31
");
}
@@ -13041,7 +13030,7 @@ mod hir_opt_tests {
bb3(v9:BasicObject, v10:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1008, String)
- v25:Class[String@0x1010] = Const Value(VALUE(0x1010))
+ v25:ClassSubclass[String@0x1010] = Const Value(VALUE(0x1010))
PatchPoint NoSingletonClass(String@0x1010)
PatchPoint MethodRedefined(String@0x1010, is_a?@0x1011, cme:0x1018)
v29:StringExact = GuardType v10, StringExact
@@ -13073,7 +13062,7 @@ mod hir_opt_tests {
bb3(v9:BasicObject, v10:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1008, Kernel)
- v25:ModuleExact[VALUE(0x1010)] = Const Value(VALUE(0x1010))
+ v25:ModuleSubclass[Kernel@0x1010] = Const Value(VALUE(0x1010))
PatchPoint NoSingletonClass(String@0x1018)
PatchPoint MethodRedefined(String@0x1018, is_a?@0x1020, cme:0x1028)
v29:StringExact = GuardType v10, StringExact
@@ -13108,7 +13097,7 @@ mod hir_opt_tests {
bb3(v9:BasicObject, v10:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1008, Integer)
- v29:Class[Integer@0x1010] = Const Value(VALUE(0x1010))
+ v29:ClassSubclass[Integer@0x1010] = Const Value(VALUE(0x1010))
PatchPoint NoSingletonClass(String@0x1018)
PatchPoint MethodRedefined(String@0x1018, is_a?@0x1020, cme:0x1028)
v33:StringExact = GuardType v10, StringExact
@@ -13143,7 +13132,7 @@ mod hir_opt_tests {
bb3(v9:BasicObject, v10:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1008, Integer)
- v31:Class[Integer@0x1010] = Const Value(VALUE(0x1010))
+ v31:ClassSubclass[Integer@0x1010] = Const Value(VALUE(0x1010))
PatchPoint NoEPEscape(test)
PatchPoint MethodRedefined(Class@0x1018, ===@0x1020, cme:0x1028)
v23:Fixnum[5] = Const Value(5)
@@ -13174,7 +13163,7 @@ mod hir_opt_tests {
bb3(v9:BasicObject, v10:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1008, String)
- v25:Class[String@0x1010] = Const Value(VALUE(0x1010))
+ v25:ClassSubclass[String@0x1010] = Const Value(VALUE(0x1010))
PatchPoint NoSingletonClass(String@0x1010)
PatchPoint MethodRedefined(String@0x1010, kind_of?@0x1011, cme:0x1018)
v29:StringExact = GuardType v10, StringExact
@@ -13206,7 +13195,7 @@ mod hir_opt_tests {
bb3(v9:BasicObject, v10:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1008, Kernel)
- v25:ModuleExact[VALUE(0x1010)] = Const Value(VALUE(0x1010))
+ v25:ModuleSubclass[Kernel@0x1010] = Const Value(VALUE(0x1010))
PatchPoint NoSingletonClass(String@0x1018)
PatchPoint MethodRedefined(String@0x1018, kind_of?@0x1020, cme:0x1028)
v29:StringExact = GuardType v10, StringExact
@@ -13241,7 +13230,7 @@ mod hir_opt_tests {
bb3(v9:BasicObject, v10:BasicObject):
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1008, Integer)
- v29:Class[Integer@0x1010] = Const Value(VALUE(0x1010))
+ v29:ClassSubclass[Integer@0x1010] = Const Value(VALUE(0x1010))
PatchPoint NoSingletonClass(String@0x1018)
PatchPoint MethodRedefined(String@0x1018, kind_of?@0x1020, cme:0x1028)
v33:StringExact = GuardType v10, StringExact
@@ -13271,11 +13260,11 @@ mod hir_opt_tests {
v10:Fixnum[5] = Const Value(5)
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, Integer)
- v22:Class[Integer@0x1008] = Const Value(VALUE(0x1008))
+ v22:ClassSubclass[Integer@0x1008] = Const Value(VALUE(0x1008))
PatchPoint MethodRedefined(Integer@0x1008, is_a?@0x1009, cme:0x1010)
- v26:TrueClass = Const Value(true)
+ v27:TrueClass = Const Value(true)
CheckInterrupts
- Return v26
+ Return v27
");
}
@@ -13299,11 +13288,11 @@ mod hir_opt_tests {
v10:Fixnum[5] = Const Value(5)
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, String)
- v22:Class[String@0x1008] = Const Value(VALUE(0x1008))
+ v22:ClassSubclass[String@0x1008] = Const Value(VALUE(0x1008))
PatchPoint MethodRedefined(Integer@0x1010, is_a?@0x1018, cme:0x1020)
- v26:FalseClass = Const Value(false)
+ v27:FalseClass = Const Value(false)
CheckInterrupts
- Return v26
+ Return v27
");
}
@@ -13330,12 +13319,12 @@ mod hir_opt_tests {
PatchPoint StableConstantNames(0x1000, O)
v22:ArraySubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint StableConstantNames(0x1010, Array)
- v25:Class[Array@0x1018] = Const Value(VALUE(0x1018))
+ v25:ClassSubclass[Array@0x1018] = Const Value(VALUE(0x1018))
PatchPoint NoSingletonClass(C@0x1020)
PatchPoint MethodRedefined(C@0x1020, is_a?@0x1028, cme:0x1030)
- v30:TrueClass = Const Value(true)
+ v31:TrueClass = Const Value(true)
CheckInterrupts
- Return v30
+ Return v31
");
}
@@ -13362,12 +13351,12 @@ mod hir_opt_tests {
PatchPoint StableConstantNames(0x1000, O)
v22:ObjectSubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint StableConstantNames(0x1010, C)
- v25:Class[C@0x1018] = Const Value(VALUE(0x1018))
+ v25:ClassSubclass[C@0x1018] = Const Value(VALUE(0x1018))
PatchPoint NoSingletonClass(C@0x1018)
PatchPoint MethodRedefined(C@0x1018, is_a?@0x1019, cme:0x1020)
- v30:TrueClass = Const Value(true)
+ v31:TrueClass = Const Value(true)
CheckInterrupts
- Return v30
+ Return v31
");
}
@@ -13393,11 +13382,11 @@ mod hir_opt_tests {
PatchPoint StableConstantNames(0x1000, O)
v22:StaticSymbol[:my_static_symbol] = Const Value(VALUE(0x1008))
PatchPoint StableConstantNames(0x1010, Symbol)
- v25:Class[Symbol@0x1018] = Const Value(VALUE(0x1018))
+ v25:ClassSubclass[Symbol@0x1018] = Const Value(VALUE(0x1018))
PatchPoint MethodRedefined(Symbol@0x1018, is_a?@0x1019, cme:0x1020)
- v29:TrueClass = Const Value(true)
+ v30:TrueClass = Const Value(true)
CheckInterrupts
- Return v29
+ Return v30
");
}
@@ -13516,12 +13505,12 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(C@0x1000)
PatchPoint MethodRedefined(C@0x1000, class@0x1008, cme:0x1010)
v43:ObjectSubclass[class_exact:C] = GuardType v6, ObjectSubclass[class_exact:C]
- v46:Class[C@0x1000] = Const Value(VALUE(0x1000))
+ v46:ClassSubclass[C@0x1000] = Const Value(VALUE(0x1000))
v13:StaticSymbol[:_lex_actions] = Const Value(VALUE(0x1038))
v15:TrueClass = Const Value(true)
PatchPoint MethodRedefined(Class@0x1040, respond_to?@0x1048, cme:0x1050)
PatchPoint MethodRedefined(Class@0x1040, _lex_actions@0x1078, cme:0x1080)
- v51:TrueClass = Const Value(true)
+ v52:TrueClass = Const Value(true)
CheckInterrupts
v26:StaticSymbol[:CORRECT] = Const Value(VALUE(0x10a8))
Return v26
@@ -13552,11 +13541,11 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(C@0x1008)
PatchPoint MethodRedefined(C@0x1008, class@0x1010, cme:0x1018)
v25:ObjectSubclass[class_exact:C] = GuardType v10, ObjectSubclass[class_exact:C]
- v28:Class[C@0x1008] = Const Value(VALUE(0x1008))
+ v28:ClassSubclass[C@0x1008] = Const Value(VALUE(0x1008))
PatchPoint MethodRedefined(Class@0x1040, name@0x1048, cme:0x1050)
- v31:StringExact|NilClass = CCall v28, :Module#name@0x1078
+ v32:StringExact|NilClass = CCall v28, :Module#name@0x1078
CheckInterrupts
- Return v31
+ Return v32
");
}
@@ -13584,7 +13573,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(C@0x1008)
PatchPoint MethodRedefined(C@0x1008, class@0x1010, cme:0x1018)
v23:ObjectSubclass[class_exact:C] = GuardType v10, ObjectSubclass[class_exact:C]
- v26:Class[C@0x1008] = Const Value(VALUE(0x1008))
+ v26:ClassSubclass[C@0x1008] = Const Value(VALUE(0x1008))
CheckInterrupts
Return v26
");
@@ -13609,9 +13598,9 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
v10:Fixnum[5] = Const Value(5)
PatchPoint MethodRedefined(Integer@0x1000, class@0x1008, cme:0x1010)
- v21:Class[Integer@0x1000] = Const Value(VALUE(0x1000))
+ v22:ClassSubclass[Integer@0x1000] = Const Value(VALUE(0x1000))
CheckInterrupts
- Return v21
+ Return v22
");
}
@@ -13634,13 +13623,43 @@ mod hir_opt_tests {
bb3(v6:BasicObject):
PatchPoint MethodRedefined(Object@0x1000, class@0x1008, cme:0x1010)
v18:ObjectSubclass[class_exact*:Object@VALUE(0x1000)] = GuardType v6, ObjectSubclass[class_exact*:Object@VALUE(0x1000)]
- v21:Class[Object@0x1038] = Const Value(VALUE(0x1038))
+ v21:ClassSubclass[Object@0x1038] = Const Value(VALUE(0x1038))
CheckInterrupts
Return v21
");
}
#[test]
+ fn test_print_nil_module_name() {
+ eval(r#"
+ X = [Module.new].freeze
+ def test = X[0]
+ test
+ "#);
+ assert_snapshot!(hir_string("test"), @"
+ fn test@<compiled>:3:
+ bb1():
+ EntryPoint interpreter
+ v1:BasicObject = LoadSelf
+ Jump bb3(v1)
+ bb2():
+ EntryPoint JIT(0)
+ v4:BasicObject = LoadArg :self@0
+ Jump bb3(v4)
+ bb3(v6:BasicObject):
+ PatchPoint SingleRactorMode
+ PatchPoint StableConstantNames(0x1000, X)
+ v23:ArrayExact[VALUE(0x1008)] = Const Value(VALUE(0x1008))
+ v12:Fixnum[0] = Const Value(0)
+ PatchPoint NoSingletonClass(Array@0x1010)
+ PatchPoint MethodRedefined(Array@0x1010, []@0x1018, cme:0x1020)
+ v37:ModuleExact[VALUE(0x1048)] = Const Value(VALUE(0x1048))
+ CheckInterrupts
+ Return v37
+ ");
+ }
+
+ #[test]
fn no_load_from_ep_right_after_entrypoint() {
let formatted = eval("
def read_nil_local(a, _b, _c)
@@ -13683,16 +13702,16 @@ mod hir_opt_tests {
SetLocal :formatted, l0, EP@3, v16
PatchPoint SingleRactorMode
SetIvar v15, :@formatted, v16
- v47:Class[VMFrozenCore] = Const Value(VALUE(0x1008))
+ v47:ClassSubclass[VMFrozenCore] = Const Value(VALUE(0x1008))
PatchPoint MethodRedefined(Class@0x1010, lambda@0x1018, cme:0x1020)
- v62:BasicObject = CCallWithFrame v47, :RubyVM::FrozenCore.lambda@0x1048, block=0x1050
+ v63:BasicObject = CCallWithFrame v47, :RubyVM::FrozenCore.lambda@0x1048, block=0x1050
v50:CPtr = GetEP 0
v51:BasicObject = LoadField v50, :a@0x1001
v52:BasicObject = LoadField v50, :_b@0x1002
v53:BasicObject = LoadField v50, :_c@0x1058
v54:BasicObject = LoadField v50, :formatted@0x1059
CheckInterrupts
- Return v62
+ Return v63
");
}
@@ -13729,9 +13748,9 @@ mod hir_opt_tests {
v20:ObjectSubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(TestFrozen@0x1010)
PatchPoint MethodRedefined(TestFrozen@0x1010, a@0x1018, cme:0x1020)
- v29:Fixnum[1] = Const Value(1)
+ v30:Fixnum[1] = Const Value(1)
CheckInterrupts
- Return v29
+ Return v30
");
}
@@ -13770,9 +13789,9 @@ mod hir_opt_tests {
v20:ObjectSubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(TestMultiIvars@0x1010)
PatchPoint MethodRedefined(TestMultiIvars@0x1010, b@0x1018, cme:0x1020)
- v29:Fixnum[20] = Const Value(20)
+ v30:Fixnum[20] = Const Value(20)
CheckInterrupts
- Return v29
+ Return v30
");
}
@@ -13809,9 +13828,9 @@ mod hir_opt_tests {
v20:ObjectSubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(TestFrozenStr@0x1010)
PatchPoint MethodRedefined(TestFrozenStr@0x1010, name@0x1018, cme:0x1020)
- v29:StringExact[VALUE(0x1048)] = Const Value(VALUE(0x1048))
+ v30:StringExact[VALUE(0x1048)] = Const Value(VALUE(0x1048))
CheckInterrupts
- Return v29
+ Return v30
");
}
@@ -13848,9 +13867,9 @@ mod hir_opt_tests {
v20:ObjectSubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(TestFrozenNil@0x1010)
PatchPoint MethodRedefined(TestFrozenNil@0x1010, value@0x1018, cme:0x1020)
- v29:NilClass = Const Value(nil)
+ v30:NilClass = Const Value(nil)
CheckInterrupts
- Return v29
+ Return v30
");
}
@@ -13887,11 +13906,11 @@ mod hir_opt_tests {
v20:ObjectSubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(TestUnfrozen@0x1010)
PatchPoint MethodRedefined(TestUnfrozen@0x1010, a@0x1018, cme:0x1020)
- v25:CShape = LoadField v20, :shape_id@0x1048
- v26:CShape[0x1049] = GuardBitEquals v25, CShape(0x1049)
- v27:BasicObject = LoadField v20, :@a@0x104a
+ v26:CShape = LoadField v20, :shape_id@0x1048
+ v27:CShape[0x1049] = GuardBitEquals v26, CShape(0x1049) recompile
+ v28:BasicObject = LoadField v20, :@a@0x104a
CheckInterrupts
- Return v27
+ Return v28
");
}
@@ -13928,9 +13947,9 @@ mod hir_opt_tests {
v20:ObjectSubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(TestAttrReader@0x1010)
PatchPoint MethodRedefined(TestAttrReader@0x1010, value@0x1018, cme:0x1020)
- v29:Fixnum[42] = Const Value(42)
+ v30:Fixnum[42] = Const Value(42)
CheckInterrupts
- Return v29
+ Return v30
");
}
@@ -13967,9 +13986,9 @@ mod hir_opt_tests {
v20:ObjectSubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(TestFrozenSym@0x1010)
PatchPoint MethodRedefined(TestFrozenSym@0x1010, sym@0x1018, cme:0x1020)
- v29:StaticSymbol[:hello] = Const Value(VALUE(0x1048))
+ v30:StaticSymbol[:hello] = Const Value(VALUE(0x1048))
CheckInterrupts
- Return v29
+ Return v30
");
}
@@ -14006,9 +14025,9 @@ mod hir_opt_tests {
v20:ObjectSubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(TestFrozenBool@0x1010)
PatchPoint MethodRedefined(TestFrozenBool@0x1010, flag@0x1018, cme:0x1020)
- v29:TrueClass = Const Value(true)
+ v30:TrueClass = Const Value(true)
CheckInterrupts
- Return v29
+ Return v30
");
}
@@ -14046,7 +14065,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(TestDynamic@0x1008, val@0x1010, cme:0x1018)
v23:ObjectSubclass[class_exact:TestDynamic] = GuardType v10, ObjectSubclass[class_exact:TestDynamic]
v26:CShape = LoadField v23, :shape_id@0x1040
- v27:CShape[0x1041] = GuardBitEquals v26, CShape(0x1041)
+ v27:CShape[0x1041] = GuardBitEquals v26, CShape(0x1041) recompile
v28:BasicObject = LoadField v23, :@val@0x1042
CheckInterrupts
Return v28
@@ -14087,15 +14106,15 @@ mod hir_opt_tests {
v27:ObjectSubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(TestNestedAccess@0x1010)
PatchPoint MethodRedefined(TestNestedAccess@0x1010, x@0x1018, cme:0x1020)
- v51:Fixnum[100] = Const Value(100)
+ v53:Fixnum[100] = Const Value(100)
PatchPoint StableConstantNames(0x1048, NESTED_FROZEN)
- v33:ObjectSubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
+ v34:ObjectSubclass[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint MethodRedefined(TestNestedAccess@0x1010, y@0x1050, cme:0x1058)
- v53:Fixnum[200] = Const Value(200)
+ v55:Fixnum[200] = Const Value(200)
PatchPoint MethodRedefined(Integer@0x1080, +@0x1088, cme:0x1090)
- v54:Fixnum[300] = Const Value(300)
+ v56:Fixnum[300] = Const Value(300)
CheckInterrupts
- Return v54
+ Return v56
");
}
@@ -14122,10 +14141,10 @@ mod hir_opt_tests {
v20:StringExact[VALUE(0x1008)] = Const Value(VALUE(0x1008))
PatchPoint NoSingletonClass(String@0x1010)
PatchPoint MethodRedefined(String@0x1010, bytesize@0x1018, cme:0x1020)
- v24:CInt64 = LoadField v20, :len@0x1048
- v25:Fixnum = BoxFixnum v24
+ v25:CInt64 = LoadField v20, :len@0x1048
+ v26:Fixnum = BoxFixnum v25
CheckInterrupts
- Return v25
+ Return v26
");
}
@@ -15530,7 +15549,7 @@ mod hir_opt_tests {
PatchPoint SingleRactorMode
v35:HeapBasicObject = GuardType v8, HeapBasicObject
v36:CShape = LoadField v35, :shape_id@0x1000
- v37:CShape[0x1001] = GuardBitEquals v36, CShape(0x1001)
+ v37:CShape[0x1001] = GuardBitEquals v36, CShape(0x1001) recompile
StoreField v35, :@a@0x1002, v13
WriteBarrier v35, v13
v40:CShape[0x1003] = Const CShape(0x1003)
@@ -15578,7 +15597,7 @@ mod hir_opt_tests {
PatchPoint SingleRactorMode
v49:HeapBasicObject = GuardType v10, HeapBasicObject
v50:CShape = LoadField v49, :shape_id@0x1000
- v51:CShape[0x1001] = GuardBitEquals v50, CShape(0x1001)
+ v51:CShape[0x1001] = GuardBitEquals v50, CShape(0x1001) recompile
StoreField v49, :@a@0x1002, v16
WriteBarrier v49, v16
v54:CShape[0x1003] = Const CShape(0x1003)
@@ -15587,7 +15606,7 @@ mod hir_opt_tests {
v26:Fixnum[5] = Const Value(5)
PatchPoint NoEPEscape(initialize)
PatchPoint MethodRedefined(Integer@0x1008, +@0x1010, cme:0x1018)
- v64:Fixnum[6] = Const Value(6)
+ v65:Fixnum[6] = Const Value(6)
PatchPoint SingleRactorMode
WriteBarrier v23, v16
CheckInterrupts
@@ -15626,7 +15645,7 @@ mod hir_opt_tests {
PatchPoint SingleRactorMode
v43:HeapBasicObject = GuardType v8, HeapBasicObject
v44:CShape = LoadField v43, :shape_id@0x1000
- v45:CShape[0x1001] = GuardBitEquals v44, CShape(0x1001)
+ v45:CShape[0x1001] = GuardBitEquals v44, CShape(0x1001) recompile
StoreField v43, :@a@0x1002, v13
WriteBarrier v43, v13
v48:CShape[0x1003] = Const CShape(0x1003)
@@ -15895,9 +15914,9 @@ mod hir_opt_tests {
v21:Fixnum[2] = Const Value(2)
v40:Fixnum = FixnumSub v35, v21
PatchPoint MethodRedefined(Integer@0x1008, +@0x1040, cme:0x1048)
- v43:Fixnum = FixnumAdd v36, v40
+ v44:Fixnum = FixnumAdd v36, v40
CheckInterrupts
- Return v43
+ Return v44
");
}
@@ -16030,7 +16049,7 @@ mod hir_opt_tests {
Jump bb8(v63)
bb12():
v97:CShape = LoadField v46, :shape_id@0x103c
- v98:CShape[0x103d] = GuardBitEquals v97, CShape(0x103d)
+ v98:CShape[0x103d] = GuardBitEquals v97, CShape(0x103d) recompile
v99:BasicObject = LoadField v46, :@levar@0x103a
Jump bb8(v99)
bb8(v48:BasicObject):
@@ -16041,7 +16060,7 @@ mod hir_opt_tests {
PatchPoint NoEPEscape(set_value_loop)
PatchPoint SingleRactorMode
v101:CShape = LoadField v46, :shape_id@0x103c
- v102:CShape[0x103e] = GuardBitEquals v101, CShape(0x103e)
+ v102:CShape[0x103e] = GuardBitEquals v101, CShape(0x103e) recompile
StoreField v46, :@levar@0x103a, v41
WriteBarrier v46, v41
v105:CShape[0x103d] = Const CShape(0x103d)
@@ -16509,20 +16528,80 @@ mod hir_opt_tests {
v138:ObjectSubclass[class_exact:C] = GuardType v12, ObjectSubclass[class_exact:C]
v139:BasicObject = LoadField v138, :var@0x1040
PatchPoint MethodRedefined(Integer@0x1048, +@0x1050, cme:0x1058)
- v178:Fixnum = GuardType v139, Fixnum
- v179:Fixnum = FixnumAdd v17, v178
+ v179:Fixnum = GuardType v139, Fixnum
+ v180:Fixnum = FixnumAdd v17, v179
PatchPoint NoEPEscape(test)
- v183:Fixnum = FixnumAdd v179, v178
- v187:Fixnum = FixnumAdd v183, v178
- v191:Fixnum = FixnumAdd v187, v178
- v195:Fixnum = FixnumAdd v191, v178
- v199:Fixnum = FixnumAdd v195, v178
- v203:Fixnum = FixnumAdd v199, v178
- v207:Fixnum = FixnumAdd v203, v178
- v211:Fixnum = FixnumAdd v207, v178
- v215:Fixnum = FixnumAdd v211, v178
- CheckInterrupts
- Return v215
+ v185:Fixnum = FixnumAdd v180, v179
+ v190:Fixnum = FixnumAdd v185, v179
+ v195:Fixnum = FixnumAdd v190, v179
+ v200:Fixnum = FixnumAdd v195, v179
+ v205:Fixnum = FixnumAdd v200, v179
+ v210:Fixnum = FixnumAdd v205, v179
+ v215:Fixnum = FixnumAdd v210, v179
+ v220:Fixnum = FixnumAdd v215, v179
+ v225:Fixnum = FixnumAdd v220, v179
+ CheckInterrupts
+ Return v225
+ ");
+ }
+
+ #[test]
+ fn test_dont_fold_array_length() {
+ eval(r#"
+ A = [1, 2, 3, 4]
+ def test = A.length
+ test
+ "#);
+ assert_snapshot!(hir_string("test"), @"
+ fn test@<compiled>:3:
+ bb1():
+ EntryPoint interpreter
+ v1:BasicObject = LoadSelf
+ Jump bb3(v1)
+ bb2():
+ EntryPoint JIT(0)
+ v4:BasicObject = LoadArg :self@0
+ Jump bb3(v4)
+ bb3(v6:BasicObject):
+ PatchPoint SingleRactorMode
+ PatchPoint StableConstantNames(0x1000, A)
+ v21:ArrayExact[VALUE(0x1008)] = Const Value(VALUE(0x1008))
+ PatchPoint NoSingletonClass(Array@0x1010)
+ PatchPoint MethodRedefined(Array@0x1010, length@0x1018, cme:0x1020)
+ v26:CInt64 = ArrayLength v21
+ v27:Fixnum = BoxFixnum v26
+ CheckInterrupts
+ Return v27
+ ");
+ }
+
+ #[test]
+ fn test_fold_frozen_array_length() {
+ eval(r#"
+ A = [1, 2, 3, 4].freeze
+ def test = A.length
+ test
+ "#);
+ assert_snapshot!(hir_string("test"), @"
+ fn test@<compiled>:3:
+ bb1():
+ EntryPoint interpreter
+ v1:BasicObject = LoadSelf
+ Jump bb3(v1)
+ bb2():
+ EntryPoint JIT(0)
+ v4:BasicObject = LoadArg :self@0
+ Jump bb3(v4)
+ bb3(v6:BasicObject):
+ PatchPoint SingleRactorMode
+ PatchPoint StableConstantNames(0x1000, A)
+ v21:ArrayExact[VALUE(0x1008)] = Const Value(VALUE(0x1008))
+ PatchPoint NoSingletonClass(Array@0x1010)
+ PatchPoint MethodRedefined(Array@0x1010, length@0x1018, cme:0x1020)
+ v28:CInt64[4] = Const CInt64(4)
+ v27:Fixnum = BoxFixnum v28
+ CheckInterrupts
+ Return v27
");
}
}
diff --git a/zjit/src/hir/tests.rs b/zjit/src/hir/tests.rs
index 566cf7aeb7..7a1cd85c5f 100644
--- a/zjit/src/hir/tests.rs
+++ b/zjit/src/hir/tests.rs
@@ -50,10 +50,10 @@ mod snapshot_tests {
v12:Fixnum[2] = Const Value(2)
v13:Any = Snapshot FrameState { pc: 0x1008, stack: [v10, v12], locals: [] }
PatchPoint MethodRedefined(Integer@0x1010, +@0x1018, cme:0x1020)
- v33:Fixnum[6] = Const Value(6)
- v21:Any = Snapshot FrameState { pc: 0x1048, stack: [v33], locals: [] }
+ v35:Fixnum[6] = Const Value(6)
+ v21:Any = Snapshot FrameState { pc: 0x1048, stack: [v35], locals: [] }
CheckInterrupts
- Return v33
+ Return v35
");
}
@@ -2384,11 +2384,11 @@ pub(crate) mod hir_build_tests {
v7:BasicObject = LoadArg :a@1
Jump bb3(v6, v7)
bb3(v9:BasicObject, v10:BasicObject):
- v15:Class[VMFrozenCore] = Const Value(VALUE(0x1008))
+ v15:ClassSubclass[VMFrozenCore] = Const Value(VALUE(0x1008))
v17:HashExact = NewHash
PatchPoint NoEPEscape(test)
v22:BasicObject = Send v15, :core#hash_merge_kwd, v17, v10 # SendFallbackReason: Uncategorized(opt_send_without_block)
- v24:Class[VMFrozenCore] = Const Value(VALUE(0x1008))
+ v24:ClassSubclass[VMFrozenCore] = Const Value(VALUE(0x1008))
v27:StaticSymbol[:b] = Const Value(VALUE(0x1010))
v29:Fixnum[1] = Const Value(1)
v31:BasicObject = Send v24, :core#hash_merge_ptr, v22, v27, v29 # SendFallbackReason: Uncategorized(opt_send_without_block)
@@ -4360,7 +4360,7 @@ pub(crate) mod hir_build_tests {
v4:BasicObject = LoadArg :self@0
Jump bb3(v4)
bb3(v6:BasicObject):
- v10:Class[VMFrozenCore] = Const Value(VALUE(0x1000))
+ v10:ClassSubclass[VMFrozenCore] = Const Value(VALUE(0x1000))
v12:BasicObject = PutSpecialObject CBase
v14:StaticSymbol[:aliased] = Const Value(VALUE(0x1008))
v16:StaticSymbol[:__callee__] = Const Value(VALUE(0x1010))
diff --git a/zjit/src/hir_type/gen_hir_type.rb b/zjit/src/hir_type/gen_hir_type.rb
index e9d925ba0f..41f96a7a82 100644
--- a/zjit/src/hir_type/gen_hir_type.rb
+++ b/zjit/src/hir_type/gen_hir_type.rb
@@ -75,8 +75,8 @@ $inexact_c_names = {
# Define a new type that can be subclassed (most of them).
# If c_name is given, mark the rb_cXYZ object as equivalent to this exact type.
-def base_type name, c_name: nil
- type = $object.subtype name
+def base_type name, base: $object, c_name: nil
+ type = base.subtype name
exact = type.subtype(name+"Exact")
subclass = type.subtype(name+"Subclass")
if c_name
@@ -111,7 +111,7 @@ base_type "Regexp", c_name: "rb_cRegexp"
module_class, _ = base_type "Module", c_name: "rb_cModule"
# Class cannot be subclassed by doing `class Sub < Class`,
# but every metaclass is a subclass of `Class`. It's not final.
-module_class.subtype "Class"
+base_type "Class", base: module_class, c_name: "rb_cClass"
numeric, _ = base_type "Numeric", c_name: "rb_cNumeric"
diff --git a/zjit/src/hir_type/hir_type.inc.rs b/zjit/src/hir_type/hir_type.inc.rs
index 8b95914ddf..f4c3bf3489 100644
--- a/zjit/src/hir_type/hir_type.inc.rs
+++ b/zjit/src/hir_type/hir_type.inc.rs
@@ -9,7 +9,7 @@ mod bits {
pub const BasicObjectSubclass: u64 = 1u64 << 3;
pub const Bignum: u64 = 1u64 << 4;
pub const BoolExact: u64 = FalseClass | TrueClass;
- pub const BuiltinExact: u64 = ArrayExact | BasicObjectExact | FalseClass | Float | HashExact | Integer | ModuleExact | NilClass | NumericExact | ObjectExact | RangeExact | RegexpExact | SetExact | StringExact | Symbol | TrueClass;
+ pub const BuiltinExact: u64 = ArrayExact | BasicObjectExact | ClassExact | FalseClass | Float | HashExact | Integer | ModuleExact | NilClass | NumericExact | ObjectExact | RangeExact | RegexpExact | SetExact | StringExact | Symbol | TrueClass;
pub const CAttrIndex: u64 = 1u64 << 5;
pub const CBool: u64 = 1u64 << 6;
pub const CDouble: u64 = 1u64 << 7;
@@ -29,54 +29,56 @@ mod bits {
pub const CUnsigned: u64 = CAttrIndex | CShape | CUInt16 | CUInt32 | CUInt64 | CUInt8;
pub const CValue: u64 = CBool | CDouble | CInt | CNull | CPtr;
pub const CallableMethodEntry: u64 = 1u64 << 19;
- pub const Class: u64 = 1u64 << 20;
- pub const DynamicSymbol: u64 = 1u64 << 21;
+ pub const Class: u64 = ClassExact | ClassSubclass;
+ pub const ClassExact: u64 = 1u64 << 20;
+ pub const ClassSubclass: u64 = 1u64 << 21;
+ pub const DynamicSymbol: u64 = 1u64 << 22;
pub const Empty: u64 = 0u64;
- pub const FalseClass: u64 = 1u64 << 22;
+ pub const FalseClass: u64 = 1u64 << 23;
pub const Falsy: u64 = FalseClass | NilClass;
- pub const Fixnum: u64 = 1u64 << 23;
+ pub const Fixnum: u64 = 1u64 << 24;
pub const Float: u64 = Flonum | HeapFloat;
- pub const Flonum: u64 = 1u64 << 24;
+ pub const Flonum: u64 = 1u64 << 25;
pub const Hash: u64 = HashExact | HashSubclass;
- pub const HashExact: u64 = 1u64 << 25;
- pub const HashSubclass: u64 = 1u64 << 26;
+ pub const HashExact: u64 = 1u64 << 26;
+ pub const HashSubclass: u64 = 1u64 << 27;
pub const HeapBasicObject: u64 = BasicObject & !Immediate;
- pub const HeapFloat: u64 = 1u64 << 27;
+ pub const HeapFloat: u64 = 1u64 << 28;
pub const HeapObject: u64 = Object & !Immediate;
pub const Immediate: u64 = FalseClass | Fixnum | Flonum | NilClass | StaticSymbol | TrueClass | Undef;
pub const Integer: u64 = Bignum | Fixnum;
pub const Module: u64 = Class | ModuleExact | ModuleSubclass;
- pub const ModuleExact: u64 = 1u64 << 28;
- pub const ModuleSubclass: u64 = 1u64 << 29;
- pub const NilClass: u64 = 1u64 << 30;
+ pub const ModuleExact: u64 = 1u64 << 29;
+ pub const ModuleSubclass: u64 = 1u64 << 30;
+ pub const NilClass: u64 = 1u64 << 31;
pub const NotNil: u64 = BasicObject & !NilClass;
pub const Numeric: u64 = Float | Integer | NumericExact | NumericSubclass;
- pub const NumericExact: u64 = 1u64 << 31;
- pub const NumericSubclass: u64 = 1u64 << 32;
+ pub const NumericExact: u64 = 1u64 << 32;
+ pub const NumericSubclass: u64 = 1u64 << 33;
pub const Object: u64 = Array | FalseClass | Hash | Module | NilClass | Numeric | ObjectExact | ObjectSubclass | Range | Regexp | Set | String | Symbol | TrueClass;
- pub const ObjectExact: u64 = 1u64 << 33;
- pub const ObjectSubclass: u64 = 1u64 << 34;
+ pub const ObjectExact: u64 = 1u64 << 34;
+ pub const ObjectSubclass: u64 = 1u64 << 35;
pub const Range: u64 = RangeExact | RangeSubclass;
- pub const RangeExact: u64 = 1u64 << 35;
- pub const RangeSubclass: u64 = 1u64 << 36;
+ pub const RangeExact: u64 = 1u64 << 36;
+ pub const RangeSubclass: u64 = 1u64 << 37;
pub const Regexp: u64 = RegexpExact | RegexpSubclass;
- pub const RegexpExact: u64 = 1u64 << 37;
- pub const RegexpSubclass: u64 = 1u64 << 38;
+ pub const RegexpExact: u64 = 1u64 << 38;
+ pub const RegexpSubclass: u64 = 1u64 << 39;
pub const RubyValue: u64 = BasicObject | CallableMethodEntry | Undef;
pub const Set: u64 = SetExact | SetSubclass;
- pub const SetExact: u64 = 1u64 << 39;
- pub const SetSubclass: u64 = 1u64 << 40;
- pub const StaticSymbol: u64 = 1u64 << 41;
+ pub const SetExact: u64 = 1u64 << 40;
+ pub const SetSubclass: u64 = 1u64 << 41;
+ pub const StaticSymbol: u64 = 1u64 << 42;
pub const String: u64 = StringExact | StringSubclass;
- pub const StringExact: u64 = 1u64 << 42;
- pub const StringSubclass: u64 = 1u64 << 43;
- pub const Subclass: u64 = ArraySubclass | BasicObjectSubclass | HashSubclass | ModuleSubclass | NumericSubclass | ObjectSubclass | RangeSubclass | RegexpSubclass | SetSubclass | StringSubclass;
+ pub const StringExact: u64 = 1u64 << 43;
+ pub const StringSubclass: u64 = 1u64 << 44;
+ pub const Subclass: u64 = ArraySubclass | BasicObjectSubclass | ClassSubclass | HashSubclass | ModuleSubclass | NumericSubclass | ObjectSubclass | RangeSubclass | RegexpSubclass | SetSubclass | StringSubclass;
pub const Symbol: u64 = DynamicSymbol | StaticSymbol;
- pub const TrueClass: u64 = 1u64 << 44;
+ pub const TrueClass: u64 = 1u64 << 45;
pub const Truthy: u64 = BasicObject & !Falsy;
- pub const TypedTData: u64 = 1u64 << 45;
- pub const Undef: u64 = 1u64 << 46;
- pub const AllBitPatterns: [(&str, u64); 76] = [
+ pub const TypedTData: u64 = 1u64 << 46;
+ pub const Undef: u64 = 1u64 << 47;
+ pub const AllBitPatterns: [(&str, u64); 78] = [
("Any", Any),
("RubyValue", RubyValue),
("Immediate", Immediate),
@@ -127,6 +129,8 @@ mod bits {
("FalseClass", FalseClass),
("DynamicSymbol", DynamicSymbol),
("Class", Class),
+ ("ClassSubclass", ClassSubclass),
+ ("ClassExact", ClassExact),
("CallableMethodEntry", CallableMethodEntry),
("CValue", CValue),
("CInt", CInt),
@@ -154,7 +158,7 @@ mod bits {
("ArrayExact", ArrayExact),
("Empty", Empty),
];
- pub const NumTypeBits: u64 = 47;
+ pub const NumTypeBits: u64 = 48;
}
pub mod types {
use super::*;
@@ -188,6 +192,8 @@ pub mod types {
pub const CValue: Type = Type::from_bits(bits::CValue);
pub const CallableMethodEntry: Type = Type::from_bits(bits::CallableMethodEntry);
pub const Class: Type = Type::from_bits(bits::Class);
+ pub const ClassExact: Type = Type::from_bits(bits::ClassExact);
+ pub const ClassSubclass: Type = Type::from_bits(bits::ClassSubclass);
pub const DynamicSymbol: Type = Type::from_bits(bits::DynamicSymbol);
pub const Empty: Type = Type::from_bits(bits::Empty);
pub const FalseClass: Type = Type::from_bits(bits::FalseClass);
@@ -234,7 +240,7 @@ pub mod types {
pub const Truthy: Type = Type::from_bits(bits::Truthy);
pub const TypedTData: Type = Type::from_bits(bits::TypedTData);
pub const Undef: Type = Type::from_bits(bits::Undef);
- pub const ExactBitsAndClass: [(u64, *const VALUE); 16] = [
+ pub const ExactBitsAndClass: [(u64, *const VALUE); 17] = [
(bits::ObjectExact, &raw const crate::cruby::rb_cObject),
(bits::BasicObjectExact, &raw const crate::cruby::rb_cBasicObject),
(bits::StringExact, &raw const crate::cruby::rb_cString),
@@ -244,6 +250,7 @@ pub mod types {
(bits::SetExact, &raw const crate::cruby::rb_cSet),
(bits::RegexpExact, &raw const crate::cruby::rb_cRegexp),
(bits::ModuleExact, &raw const crate::cruby::rb_cModule),
+ (bits::ClassExact, &raw const crate::cruby::rb_cClass),
(bits::NumericExact, &raw const crate::cruby::rb_cNumeric),
(bits::Integer, &raw const crate::cruby::rb_cInteger),
(bits::Float, &raw const crate::cruby::rb_cFloat),
@@ -252,8 +259,9 @@ pub mod types {
(bits::TrueClass, &raw const crate::cruby::rb_cTrueClass),
(bits::FalseClass, &raw const crate::cruby::rb_cFalseClass),
];
- pub const SubclassBitsAndClass: [(u64, *const VALUE); 16] = [
+ pub const SubclassBitsAndClass: [(u64, *const VALUE); 17] = [
(bits::ArraySubclass, &raw const crate::cruby::rb_cArray),
+ (bits::ClassSubclass, &raw const crate::cruby::rb_cClass),
(bits::FalseClass, &raw const crate::cruby::rb_cFalseClass),
(bits::Integer, &raw const crate::cruby::rb_cInteger),
(bits::HashSubclass, &raw const crate::cruby::rb_cHash),
@@ -270,8 +278,9 @@ pub mod types {
(bits::ObjectSubclass, &raw const crate::cruby::rb_cObject),
(bits::BasicObjectSubclass, &raw const crate::cruby::rb_cBasicObject),
];
- pub const InexactBitsAndClass: [(u64, *const VALUE); 16] = [
+ pub const InexactBitsAndClass: [(u64, *const VALUE); 17] = [
(bits::Array, &raw const crate::cruby::rb_cArray),
+ (bits::Class, &raw const crate::cruby::rb_cClass),
(bits::FalseClass, &raw const crate::cruby::rb_cFalseClass),
(bits::Integer, &raw const crate::cruby::rb_cInteger),
(bits::Hash, &raw const crate::cruby::rb_cHash),
diff --git a/zjit/src/hir_type/mod.rs b/zjit/src/hir_type/mod.rs
index 206b74e7d3..cdfc15a935 100644
--- a/zjit/src/hir_type/mod.rs
+++ b/zjit/src/hir_type/mod.rs
@@ -2,13 +2,13 @@
#![allow(non_upper_case_globals)]
use crate::cruby;
-use crate::cruby::{rb_block_param_proxy, Qfalse, Qnil, Qtrue, RUBY_T_ARRAY, RUBY_T_CLASS, RUBY_T_HASH, RUBY_T_MODULE, RUBY_T_STRING, VALUE};
-use crate::cruby::{rb_cInteger, rb_cFloat, rb_cArray, rb_cHash, rb_cString, rb_cSymbol, rb_cRange, rb_cModule, rb_zjit_singleton_class_p};
+use crate::cruby::{rb_block_param_proxy, Qfalse, Qnil, Qtrue, RUBY_T_ARRAY, RUBY_T_HASH, RUBY_T_STRING, VALUE};
+use crate::cruby::{rb_cInteger, rb_cFloat, rb_cArray, rb_cHash, rb_cString, rb_cSymbol, rb_cRange, rb_zjit_singleton_class_p};
use crate::cruby::ClassRelationship;
use crate::cruby::get_class_name;
+use crate::cruby::get_module_name;
use crate::cruby::ruby_sym_to_rust_string;
use crate::cruby::rb_mRubyVMFrozenCore;
-use crate::cruby::rb_obj_class;
use crate::hir::{Const, PtrPrintMap};
use crate::profile::ProfiledType;
@@ -80,6 +80,14 @@ fn write_spec(f: &mut std::fmt::Formatter, printer: &TypePrinter) -> std::fmt::R
Specialization::Object(val) if ty.is_subtype(types::Symbol) => write!(f, "[:{}]", ruby_sym_to_rust_string(val)),
Specialization::Object(val) if ty.is_subtype(types::Class) =>
write!(f, "[{}@{:p}]", get_class_name(val), printer.ptr_map.map_ptr(val.0 as *const std::ffi::c_void)),
+ Specialization::Object(val) if ty.is_subtype(types::Module) => {
+ if let Some(name) = get_module_name(val) {
+ write!(f, "[{}@{:p}]", name, printer.ptr_map.map_ptr(val.0 as *const std::ffi::c_void))
+ } else {
+ // Same as generic Specialization::Object
+ write!(f, "[{}]", val.print(printer.ptr_map))
+ }
+ }
Specialization::Object(val) => write!(f, "[{}]", val.print(printer.ptr_map)),
// TODO(max): Ensure singleton classes never have Type specialization
Specialization::Type(val) if unsafe { rb_zjit_singleton_class_p(val) } =>
@@ -169,18 +177,6 @@ fn is_range_exact(val: VALUE) -> bool {
val.class_of() == unsafe { rb_cRange }
}
-fn is_module_exact(val: VALUE) -> bool {
- if val.builtin_type() != RUBY_T_MODULE {
- return false;
- }
-
- // For Class and Module instances, `class_of` will return the singleton class of the object.
- // Using `rb_obj_class` will give us the actual class of the module so we can check if the
- // object is an instance of Module, or an instance of Module subclass.
- let klass = unsafe { rb_obj_class(val) };
- klass == unsafe { rb_cModule }
-}
-
impl Type {
/// Create a `Type` from the given integer.
pub const fn fixnum(val: i64) -> Type {
@@ -212,9 +208,6 @@ impl Type {
if is_array_exact(val) { bits::ArrayExact }
else if is_hash_exact(val) { bits::HashExact }
else if is_string_exact(val) { bits::StringExact }
- // Singleton classes
- else if is_module_exact(val) { bits::ModuleExact }
- else if val.builtin_type() == RUBY_T_CLASS { bits::Class }
// Classes that have an immediate/heap split
else if val.class_of() == unsafe { rb_cInteger } { bits::Bignum }
else if val.class_of() == unsafe { rb_cFloat } { bits::HeapFloat }
diff --git a/zjit/src/profile.rs b/zjit/src/profile.rs
index d8bcd50d96..08803c4570 100644
--- a/zjit/src/profile.rs
+++ b/zjit/src/profile.rs
@@ -95,9 +95,9 @@ fn profile_insn(bare_opcode: ruby_vminsn_type, ec: EcPtr) {
YARVINSN_invokesuper => profile_invokesuper(profiler, profile),
YARVINSN_opt_send_without_block | YARVINSN_send => {
let cd: *const rb_call_data = profiler.insn_opnd(0).as_ptr();
- let argc = unsafe { vm_ci_argc((*cd).ci) };
+ let argc = num_arguments_on_stack(cd);
// Profile all the arguments and self (+1).
- profile_operands(profiler, profile, (argc + 1) as usize);
+ profile_operands(profiler, profile, argc + 1);
}
YARVINSN_splatkw => profile_operands(profiler, profile, 2),
_ => {}
@@ -111,6 +111,15 @@ fn profile_insn(bare_opcode: ruby_vminsn_type, ec: EcPtr) {
}
}
+/// Return the argc as stated in the calldata plus:
+/// * 1 if there is an explicit blockarg, since that will be passed on the stack
+pub fn num_arguments_on_stack(cd: *const rb_call_data) -> usize {
+ let ci = unsafe { rb_get_call_data_ci(cd) };
+ let flags = unsafe { rb_vm_ci_flag(ci) };
+ let has_blockarg = (flags & VM_CALL_ARGS_BLOCKARG) != 0;
+ (unsafe { vm_ci_argc(ci) }) as usize + has_blockarg as usize
+}
+
const DISTRIBUTION_SIZE: usize = 4;
pub type TypeDistribution = Distribution<ProfiledType, DISTRIBUTION_SIZE>;
@@ -184,7 +193,7 @@ fn profile_invokesuper(profiler: &mut Profiler, profile: &mut IseqProfile) {
unsafe { rb_gc_writebarrier(profiler.iseq.into(), cme_value) };
let cd: *const rb_call_data = profiler.insn_opnd(0).as_ptr();
- let argc = unsafe { vm_ci_argc((*cd).ci) };
+ let argc = num_arguments_on_stack(cd);
// Profile all the arguments and self (+1).
profile_operands(profiler, profile, (argc + 1) as usize);