mirror of
https://github.com/ruby/ruby.git
synced 2026-01-27 04:24:23 +00:00
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:
parent
b539cd2a33
commit
fb5f10e0d6
Notes:
git
2025-11-10 15:52:25 +00:00
Merged-By: tekknolagi <donotemailthisaddress@bernsteinbear.com>
@ -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) </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v15">PatchPoint NoTracePoint </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v17">PatchPoint NoTracePoint </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v25">PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, 29) </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v26">v26:Fixnum = GuardType v11, Fixnum </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v27">v27:Fixnum = GuardType v12, Fixnum </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v28">v28:Fixnum = FixnumOr v26, v27 </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v18">PatchPoint NoTracePoint </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v24">PatchPoint BOPRedefined(INTEGER_REDEFINED_OP_FLAG, 29) </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v25">v25:Fixnum = GuardType v11, Fixnum </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v26">v26:Fixnum = GuardType v12, Fixnum </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v27">v27:Fixnum = FixnumOr v25, v26 </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v21">PatchPoint NoTracePoint </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v23">CheckInterrupts </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v24">Return v28 </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v22">CheckInterrupts </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v23">Return v27 </TD></TR>
|
||||
</TABLE>>];
|
||||
}
|
||||
"#);
|
||||
@ -6003,17 +5945,17 @@ mod graphviz_tests {
|
||||
<TR><TD ALIGN="left" PORT="v18">PatchPoint NoTracePoint </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v19">v19:Fixnum[3] = Const Value(3) </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v21">PatchPoint NoTracePoint </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v23">CheckInterrupts </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v24">Return v19 </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v22">CheckInterrupts </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v23">Return v19 </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) </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v29">PatchPoint NoTracePoint </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v30">v30:Fixnum[4] = Const Value(4) </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v32">PatchPoint NoTracePoint </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v34">CheckInterrupts </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v35">Return v30 </TD></TR>
|
||||
<TR><TD ALIGN="LEFT" PORT="params" BGCOLOR="gray">bb3(v24:BasicObject, v25:BasicObject) </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v28">PatchPoint NoTracePoint </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v29">v29:Fixnum[4] = Const Value(4) </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v31">PatchPoint NoTracePoint </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v32">CheckInterrupts </TD></TR>
|
||||
<TR><TD ALIGN="left" PORT="v33">Return v29 </TD></TR>
|
||||
</TABLE>>];
|
||||
}
|
||||
"#);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user