ZJIT: Snapshot once per YARV insn (#15082)

This is roughly net-neutral for the number of instructions created but
at least cenetralizes where the Snapshot is made.

Previously, we might have multiple Snapshot per YARV instruction
depending on if it had event flags, if the body of the instruction also
needed a Snapshot, etc.
This commit is contained in:
Max Bernstein 2025-11-10 07:51:56 -08:00 committed by GitHub
parent b539cd2a33
commit fb5f10e0d6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
Notes: git 2025-11-10 15:52:25 +00:00
Merged-By: tekknolagi <donotemailthisaddress@bernsteinbear.com>
3 changed files with 1065 additions and 1123 deletions

View File

@ -4585,8 +4585,8 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
unsafe extern "C" {
fn rb_iseq_event_flags(iseq: IseqPtr, pos: usize) -> rb_event_flag_t;
}
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state.clone() });
if unsafe { rb_iseq_event_flags(iseq, insn_idx as usize) } != 0 {
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state.clone() });
fun.push_insn(block, Insn::PatchPoint { invariant: Invariant::NoTracePoint, state: exit_id });
}
@ -4612,26 +4612,22 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
}
YARVINSN_putstring => {
let val = fun.push_insn(block, Insn::Const { val: Const::Value(get_arg(pc, 0)) });
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
let insn_id = fun.push_insn(block, Insn::StringCopy { val, chilled: false, state: exit_id });
state.stack_push(insn_id);
}
YARVINSN_putchilledstring => {
let val = fun.push_insn(block, Insn::Const { val: Const::Value(get_arg(pc, 0)) });
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
let insn_id = fun.push_insn(block, Insn::StringCopy { val, chilled: true, state: exit_id });
state.stack_push(insn_id);
}
YARVINSN_putself => { state.stack_push(self_param); }
YARVINSN_intern => {
let val = state.stack_pop()?;
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
let insn_id = fun.push_insn(block, Insn::StringIntern { val, state: exit_id });
state.stack_push(insn_id);
}
YARVINSN_concatstrings => {
let count = get_arg(pc, 0).as_u32();
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
let strings = state.stack_pop_n(count as usize)?;
let insn_id = fun.push_insn(block, Insn::StringConcat { strings, state: exit_id });
state.stack_push(insn_id);
@ -4640,14 +4636,12 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
// First arg contains the options (multiline, extended, ignorecase) used to create the regexp
let opt = get_arg(pc, 0).as_usize();
let count = get_arg(pc, 1).as_usize();
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
let values = state.stack_pop_n(count)?;
let insn_id = fun.push_insn(block, Insn::ToRegexp { opt, values, state: exit_id });
state.stack_push(insn_id);
}
YARVINSN_newarray => {
let count = get_arg(pc, 0).as_usize();
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
let elements = state.stack_pop_n(count)?;
state.stack_push(fun.push_insn(block, Insn::NewArray { elements, state: exit_id }));
}
@ -4655,7 +4649,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
let count = get_arg(pc, 0).as_usize();
let method = get_arg(pc, 1).as_u32();
let elements = state.stack_pop_n(count)?;
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
let (bop, insn) = match method {
VM_OPT_NEWARRAY_SEND_MAX => (BOP_MAX, Insn::ArrayMax { elements, state: exit_id }),
VM_OPT_NEWARRAY_SEND_INCLUDE_P => {
@ -4679,7 +4672,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
}
YARVINSN_duparray => {
let val = fun.push_insn(block, Insn::Const { val: Const::Value(get_arg(pc, 0)) });
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
let insn_id = fun.push_insn(block, Insn::ArrayDup { val, state: exit_id });
state.stack_push(insn_id);
}
@ -4691,7 +4683,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
break;
}
let target = state.stack_pop()?;
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
let bop = match method_id {
x if x == ID!(include_p).0 => BOP_INCLUDE_P,
_ => {
@ -4710,7 +4701,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
YARVINSN_newhash => {
let count = get_arg(pc, 0).as_usize();
assert!(count % 2 == 0, "newhash count should be even");
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
let mut elements = vec![];
for _ in 0..(count/2) {
let value = state.stack_pop()?;
@ -4723,7 +4713,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
}
YARVINSN_duphash => {
let val = fun.push_insn(block, Insn::Const { val: Const::Value(get_arg(pc, 0)) });
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
let insn_id = fun.push_insn(block, Insn::HashDup { val, state: exit_id });
state.stack_push(insn_id);
}
@ -4731,7 +4720,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
let flag = get_arg(pc, 0);
let result_must_be_mutable = flag.test();
let val = state.stack_pop()?;
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
let obj = if result_must_be_mutable {
fun.push_insn(block, Insn::ToNewArray { val, state: exit_id })
} else {
@ -4742,7 +4730,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
YARVINSN_concattoarray => {
let right = state.stack_pop()?;
let left = state.stack_pop()?;
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
let right_array = fun.push_insn(block, Insn::ToArray { val: right, state: exit_id });
fun.push_insn(block, Insn::ArrayExtend { left, right: right_array, state: exit_id });
state.stack_push(left);
@ -4751,7 +4738,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
let count = get_arg(pc, 0).as_usize();
let vals = state.stack_pop_n(count)?;
let array = state.stack_pop()?;
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
for val in vals.into_iter() {
fun.push_insn(block, Insn::ArrayPush { array, val, state: exit_id });
}
@ -4769,14 +4755,12 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
let obj = get_arg(pc, 1);
let pushval = get_arg(pc, 2);
let v = state.stack_pop()?;
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
state.stack_push(fun.push_insn(block, Insn::Defined { op_type, obj, pushval, v, state: exit_id }));
}
YARVINSN_definedivar => {
// (ID id, IVC ic, VALUE pushval)
let id = ID(get_arg(pc, 0).as_u64());
let pushval = get_arg(pc, 2);
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
state.stack_push(fun.push_insn(block, Insn::DefinedIvar { self_val: self_param, id, pushval, state: exit_id }));
}
YARVINSN_checkkeyword => {
@ -4801,7 +4785,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
state.stack_push(fun.push_insn(block, Insn::GetConstantPath { ic, state: snapshot }));
}
YARVINSN_branchunless => {
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
fun.push_insn(block, Insn::CheckInterrupts { state: exit_id });
let offset = get_arg(pc, 0).as_i64();
let val = state.stack_pop()?;
@ -4815,7 +4798,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
queue.push_back((state.clone(), target, target_idx, local_inval));
}
YARVINSN_branchif => {
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
fun.push_insn(block, Insn::CheckInterrupts { state: exit_id });
let offset = get_arg(pc, 0).as_i64();
let val = state.stack_pop()?;
@ -4829,7 +4811,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
queue.push_back((state.clone(), target, target_idx, local_inval));
}
YARVINSN_branchnil => {
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
fun.push_insn(block, Insn::CheckInterrupts { state: exit_id });
let offset = get_arg(pc, 0).as_i64();
let val = state.stack_pop()?;
@ -4856,7 +4837,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
// 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 val = state.stack_topn(argc)?;
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
let test_id = fun.push_insn(block, Insn::IsMethodCfunc { val, cd, cfunc: rb_class_new_instance_pass_kw as *const u8, state: exit_id });
// Jump to the fallback block if it's not the expected function.
@ -4876,7 +4856,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
}
YARVINSN_jump => {
let offset = get_arg(pc, 0).as_i64();
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
fun.push_insn(block, Insn::CheckInterrupts { state: exit_id });
let target_idx = insn_idx_at_offset(insn_idx, offset);
let target = insn_idx_to_block[&target_idx];
@ -4942,7 +4921,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
}
YARVINSN_getblockparamproxy => {
let level = get_arg(pc, 1).as_u32();
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
fun.push_insn(block, Insn::GuardBlockParamProxy { level, state: exit_id });
// TODO(Shopify/ruby#753): GC root, so we should be able to avoid unnecessary GC tracing
state.stack_push(fun.push_insn(block, Insn::Const { val: Const::Value(unsafe { rb_block_param_proxy }) }));
@ -4987,7 +4965,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
let flags = unsafe { rb_vm_ci_flag(call_info) };
if let Err(call_type) = unhandled_call_type(flags) {
// Can't handle the call type; side-exit into the interpreter
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnhandledCallType(call_type) });
break; // End the block
}
@ -4995,14 +4972,12 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
let args = state.stack_pop_n(argc as usize)?;
let recv = state.stack_pop()?;
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
let send = fun.push_insn(block, Insn::SendWithoutBlock { recv, cd, args, state: exit_id, reason: NotOptimizedInstruction(opcode) });
state.stack_push(send);
}
YARVINSN_opt_hash_freeze => {
let klass = HASH_REDEFINED_OP_FLAG;
let bop = BOP_FREEZE;
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
if unsafe { rb_BASIC_OP_UNREDEFINED_P(bop, klass) } {
fun.push_insn(block, Insn::PatchPoint { invariant: Invariant::BOPRedefined { klass, bop }, state: exit_id });
let recv = fun.push_insn(block, Insn::Const { val: Const::Value(get_arg(pc, 0)) });
@ -5015,7 +4990,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
YARVINSN_opt_ary_freeze => {
let klass = ARRAY_REDEFINED_OP_FLAG;
let bop = BOP_FREEZE;
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
if unsafe { rb_BASIC_OP_UNREDEFINED_P(bop, klass) } {
fun.push_insn(block, Insn::PatchPoint { invariant: Invariant::BOPRedefined { klass, bop }, state: exit_id });
let recv = fun.push_insn(block, Insn::Const { val: Const::Value(get_arg(pc, 0)) });
@ -5028,7 +5002,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
YARVINSN_opt_str_freeze => {
let klass = STRING_REDEFINED_OP_FLAG;
let bop = BOP_FREEZE;
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
if unsafe { rb_BASIC_OP_UNREDEFINED_P(bop, klass) } {
fun.push_insn(block, Insn::PatchPoint { invariant: Invariant::BOPRedefined { klass, bop }, state: exit_id });
let recv = fun.push_insn(block, Insn::Const { val: Const::Value(get_arg(pc, 0)) });
@ -5041,7 +5014,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
YARVINSN_opt_str_uminus => {
let klass = STRING_REDEFINED_OP_FLAG;
let bop = BOP_UMINUS;
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
if unsafe { rb_BASIC_OP_UNREDEFINED_P(bop, klass) } {
fun.push_insn(block, Insn::PatchPoint { invariant: Invariant::BOPRedefined { klass, bop }, state: exit_id });
let recv = fun.push_insn(block, Insn::Const { val: Const::Value(get_arg(pc, 0)) });
@ -5052,13 +5024,11 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
}
}
YARVINSN_leave => {
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
fun.push_insn(block, Insn::CheckInterrupts { state: exit_id });
fun.push_insn(block, Insn::Return { val: state.stack_pop()? });
break; // Don't enqueue the next block as a successor
}
YARVINSN_throw => {
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
fun.push_insn(block, Insn::Throw { throw_state: get_arg(pc, 0).as_u32(), val: state.stack_pop()?, state: exit_id });
break; // Don't enqueue the next block as a successor
}
@ -5095,7 +5065,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
let flags = unsafe { rb_vm_ci_flag(call_info) };
if let Err(call_type) = unhandled_call_type(flags) {
// Can't handle tailcall; side-exit into the interpreter
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnhandledCallType(call_type) });
break; // End the block
}
@ -5103,7 +5072,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
let args = state.stack_pop_n(argc as usize)?;
let recv = state.stack_pop()?;
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
let send = fun.push_insn(block, Insn::SendWithoutBlock { recv, cd, args, state: exit_id, reason: NotOptimizedInstruction(opcode) });
state.stack_push(send);
}
@ -5114,7 +5082,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
let flags = unsafe { rb_vm_ci_flag(call_info) };
if let Err(call_type) = unhandled_call_type(flags) {
// Can't handle tailcall; side-exit into the interpreter
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnhandledCallType(call_type) });
break; // End the block
}
@ -5123,7 +5090,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
let args = state.stack_pop_n(argc as usize + usize::from(block_arg))?;
let recv = state.stack_pop()?;
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
let send = fun.push_insn(block, Insn::Send { recv, cd, blockiseq, args, state: exit_id, reason: NotOptimizedInstruction(opcode) });
state.stack_push(send);
@ -5147,7 +5113,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
let forwarding = (flags & VM_CALL_FORWARDING) != 0;
if let Err(call_type) = unhandled_call_type(flags) {
// Can't handle the call type; side-exit into the interpreter
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnhandledCallType(call_type) });
break; // End the block
}
@ -5155,7 +5120,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
let args = state.stack_pop_n(argc as usize + usize::from(forwarding))?;
let recv = state.stack_pop()?;
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
let send_forward = fun.push_insn(block, Insn::SendForward { recv, cd, blockiseq, args, state: exit_id, reason: NotOptimizedInstruction(opcode) });
state.stack_push(send_forward);
@ -5175,7 +5139,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
let flags = unsafe { rb_vm_ci_flag(call_info) };
if let Err(call_type) = unhandled_call_type(flags) {
// Can't handle tailcall; side-exit into the interpreter
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnhandledCallType(call_type) });
break; // End the block
}
@ -5184,7 +5147,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
let args = state.stack_pop_n(argc as usize + usize::from(block_arg))?;
let recv = state.stack_pop()?;
let blockiseq: IseqPtr = get_arg(pc, 1).as_ptr();
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
let result = fun.push_insn(block, Insn::InvokeSuper { recv, cd, blockiseq, args, state: exit_id, reason: NotOptimizedInstruction(opcode) });
state.stack_push(result);
@ -5206,33 +5168,28 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
let flags = unsafe { rb_vm_ci_flag(call_info) };
if let Err(call_type) = unhandled_call_type(flags) {
// Can't handle tailcall; side-exit into the interpreter
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnhandledCallType(call_type) });
break; // End the block
}
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 exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
let result = fun.push_insn(block, Insn::InvokeBlock { cd, args, state: exit_id, reason: NotOptimizedInstruction(opcode) });
state.stack_push(result);
}
YARVINSN_getglobal => {
let id = ID(get_arg(pc, 0).as_u64());
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
let result = fun.push_insn(block, Insn::GetGlobal { id, state: exit_id });
state.stack_push(result);
}
YARVINSN_setglobal => {
let id = ID(get_arg(pc, 0).as_u64());
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
let val = state.stack_pop()?;
fun.push_insn(block, Insn::SetGlobal { id, val, state: exit_id });
}
YARVINSN_getinstancevariable => {
let id = ID(get_arg(pc, 0).as_u64());
// ic is in arg 1
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
// Assume single-Ractor mode to omit gen_prepare_non_leaf_call on gen_getivar
// TODO: We only really need this if self_val is a class/module
fun.push_insn(block, Insn::PatchPoint { invariant: Invariant::SingleRactorMode, state: exit_id });
@ -5242,7 +5199,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
YARVINSN_setinstancevariable => {
let id = ID(get_arg(pc, 0).as_u64());
let ic = get_arg(pc, 1).as_ptr();
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
// Assume single-Ractor mode to omit gen_prepare_non_leaf_call on gen_setivar
// TODO: We only really need this if self_val is a class/module
fun.push_insn(block, Insn::PatchPoint { invariant: Invariant::SingleRactorMode, state: exit_id });
@ -5252,14 +5208,12 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
YARVINSN_getclassvariable => {
let id = ID(get_arg(pc, 0).as_u64());
let ic = get_arg(pc, 1).as_ptr();
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
let result = fun.push_insn(block, Insn::GetClassVar { id, ic, state: exit_id });
state.stack_push(result);
}
YARVINSN_setclassvariable => {
let id = ID(get_arg(pc, 0).as_u64());
let ic = get_arg(pc, 1).as_ptr();
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
let val = state.stack_pop()?;
fun.push_insn(block, Insn::SetClassVar { id, val, ic, state: exit_id });
}
@ -5277,7 +5231,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
let flag = RangeType::from(get_arg(pc, 0).as_u32());
let high = state.stack_pop()?;
let low = state.stack_pop()?;
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
let insn_id = fun.push_insn(block, Insn::NewRange { low, high, flag, state: exit_id });
state.stack_push(insn_id);
}
@ -5291,8 +5244,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
args.push(self_param);
args.reverse();
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
// Check if this builtin is annotated
let return_type = ZJITState::get_method_annotations()
.get_builtin_properties(&bf)
@ -5321,8 +5272,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
args.push(local);
}
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
// Check if this builtin is annotated
let return_type = ZJITState::get_method_annotations()
.get_builtin_properties(&bf)
@ -5346,7 +5295,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
assert_eq!(0, argc, "objtostring should not have args");
let recv = state.stack_pop()?;
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
let objtostring = fun.push_insn(block, Insn::ObjToString { val: recv, cd, state: exit_id });
state.stack_push(objtostring)
}
@ -5354,7 +5302,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
let str = state.stack_pop()?;
let val = state.stack_pop()?;
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
let anytostring = fun.push_insn(block, Insn::AnyToString { val, str, state: exit_id });
state.stack_push(anytostring);
}
@ -5362,8 +5309,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
let key = get_arg(pc, 0).as_u64();
let svar = get_arg(pc, 1).as_u64();
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
if svar == 0 {
// TODO: Handle non-backref
fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnknownSpecialVariable(key) });
@ -5389,12 +5334,10 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
// (reverse?)
//
// Unhandled opcode; side-exit into the interpreter
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnhandledYARVInsn(opcode) });
break; // End the block
}
let val = state.stack_pop()?;
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
let array = fun.push_insn(block, Insn::GuardType { val, guard_type: types::ArrayExact, state: exit_id, });
let length = fun.push_insn(block, Insn::ArrayLength { array });
fun.push_insn(block, Insn::GuardBitEquals { val: length, expected: Const::CInt64(num as i64), state: exit_id });
@ -5408,7 +5351,6 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
}
_ => {
// Unhandled opcode; side-exit into the interpreter
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state });
fun.push_insn(block, Insn::SideExit { state: exit_id, reason: SideExitReason::UnhandledYARVInsn(opcode) });
break; // End the block
}
@ -5949,14 +5891,14 @@ mod graphviz_tests {
bb2 [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD ALIGN="LEFT" PORT="params" BGCOLOR="gray">bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject)&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v15">PatchPoint NoTracePoint&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v17">PatchPoint NoTracePoint&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v25">PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, 29)&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v26">v26:Fixnum = GuardType v11, Fixnum&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v27">v27:Fixnum = GuardType v12, Fixnum&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v28">v28:Fixnum = FixnumOr v26, v27&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v18">PatchPoint NoTracePoint&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v24">PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, 29)&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v25">v25:Fixnum = GuardType v11, Fixnum&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v26">v26:Fixnum = GuardType v12, Fixnum&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v27">v27:Fixnum = FixnumOr v25, v26&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v21">PatchPoint NoTracePoint&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v23">CheckInterrupts&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v24">Return v28&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v22">CheckInterrupts&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v23">Return v27&nbsp;</TD></TR>
</TABLE>>];
}
"#);
@ -6003,17 +5945,17 @@ mod graphviz_tests {
<TR><TD ALIGN="left" PORT="v18">PatchPoint NoTracePoint&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v19">v19:Fixnum[3] = Const Value(3)&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v21">PatchPoint NoTracePoint&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v23">CheckInterrupts&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v24">Return v19&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v22">CheckInterrupts&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v23">Return v19&nbsp;</TD></TR>
</TABLE>>];
bb2:v16 -> bb3:params:n;
bb3 [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
<TR><TD ALIGN="LEFT" PORT="params" BGCOLOR="gray">bb3(v25:BasicObject, v26:BasicObject)&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v29">PatchPoint NoTracePoint&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v30">v30:Fixnum[4] = Const Value(4)&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v32">PatchPoint NoTracePoint&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v34">CheckInterrupts&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v35">Return v30&nbsp;</TD></TR>
<TR><TD ALIGN="LEFT" PORT="params" BGCOLOR="gray">bb3(v24:BasicObject, v25:BasicObject)&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v28">PatchPoint NoTracePoint&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v29">v29:Fixnum[4] = Const Value(4)&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v31">PatchPoint NoTracePoint&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v32">CheckInterrupts&nbsp;</TD></TR>
<TR><TD ALIGN="left" PORT="v33">Return v29&nbsp;</TD></TR>
</TABLE>>];
}
"#);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff