void FrameState::update(const IRInstruction* inst) { FTRACE(3, "FrameState::update processing {}\n", *inst); if (auto* taken = inst->taken()) { // When we're building the IR, we append a conditional jump after // generating its target block: see emitJmpCondHelper, where we // call makeExit() before gen(JmpZero). It doesn't make sense to // update the target block state at this point, so don't. The // state doesn't have this problem during optimization passes, // because we'll always process the jump before the target block. if (!m_building || taken->empty()) save(taken); } auto const opc = inst->op(); getLocalEffects(inst, *this); switch (opc) { case DefInlineFP: trackDefInlineFP(inst); break; case InlineReturn: trackInlineReturn(inst); break; case Call: m_spValue = inst->dst(); m_frameSpansCall = true; // A call pops the ActRec and pushes a return value. m_spOffset -= kNumActRecCells; m_spOffset += 1; assert(m_spOffset >= 0); clearCse(); break; case CallArray: m_spValue = inst->dst(); m_frameSpansCall = true; // A CallArray pops the ActRec an array arg and pushes a return value. m_spOffset -= kNumActRecCells; assert(m_spOffset >= 0); clearCse(); break; case ContEnter: clearCse(); break; case DefFP: case FreeActRec: m_fpValue = inst->dst(); break; case ReDefResumableSP: m_spValue = inst->dst(); break; case ReDefSP: m_spValue = inst->dst(); m_spOffset = inst->extra<ReDefSP>()->spOffset; break; case DefInlineSP: case DefSP: m_spValue = inst->dst(); m_spOffset = inst->extra<StackOffset>()->offset; break; case AssertStk: case CastStk: case CoerceStk: case CheckStk: case GuardStk: case ExceptionBarrier: m_spValue = inst->dst(); break; case SpillStack: { m_spValue = inst->dst(); // Push the spilled values but adjust for the popped values int64_t stackAdjustment = inst->src(1)->intVal(); m_spOffset -= stackAdjustment; m_spOffset += spillValueCells(inst); break; } case SpillFrame: case CufIterSpillFrame: m_spValue = inst->dst(); m_spOffset += kNumActRecCells; break; case InterpOne: case InterpOneCF: { m_spValue = inst->dst(); auto const& extra = *inst->extra<InterpOneData>(); int64_t stackAdjustment = extra.cellsPopped - extra.cellsPushed; // push the return value if any and adjust for the popped values m_spOffset -= stackAdjustment; break; } case AssertLoc: case GuardLoc: case CheckLoc: m_fpValue = inst->dst(); break; case LdThis: m_thisAvailable = true; break; default: break; } if (inst->modifiesStack()) { m_spValue = inst->modifiedStkPtr(); } // update the CSE table if (m_enableCse && inst->canCSE()) { cseInsert(inst); } // if the instruction kills any of its sources, remove them from the // CSE table if (inst->killsSources()) { for (int i = 0; i < inst->numSrcs(); ++i) { if (inst->killsSource(i)) { cseKill(inst->src(i)); } } } // Save state for each block at the end. if (inst->isTerminal()) { save(inst->block()); } }
void TraceBuilder::updateTrackedState(IRInstruction* inst) { // We don't track state for any trace other than the main trace. if (m_savedTraces.size() > 0) return; Opcode opc = inst->op(); // Update tracked state of local values/types, stack/frame pointer, CSE, etc. // kill tracked memory values if (inst->mayModifyRefs()) { m_refCountedMemValue = nullptr; } switch (opc) { case DefInlineFP: trackDefInlineFP(inst); break; case InlineReturn: trackInlineReturn(inst); break; case InlineFPAnchor: m_needsFPAnchor = true; break; case Call: m_spValue = inst->dst(); m_frameSpansCall = true; // A call pops the ActRec and pushes a return value. m_spOffset -= kNumActRecCells; m_spOffset += 1; assert(m_spOffset >= 0); killCse(); killLocalsForCall(); break; case CallArray: m_spValue = inst->dst(); m_frameSpansCall = true; // A CallArray pops the ActRec an array arg and pushes a return value. m_spOffset -= kNumActRecCells; assert(m_spOffset >= 0); killCse(); killLocalsForCall(); break; case ContEnter: killCse(); killLocalsForCall(); break; case DefFP: case FreeActRec: m_fpValue = inst->dst(); break; case ReDefGeneratorSP: m_spValue = inst->dst(); break; case ReDefSP: m_spValue = inst->dst(); m_spOffset = inst->extra<ReDefSP>()->offset; break; case DefInlineSP: case DefSP: m_spValue = inst->dst(); m_spOffset = inst->extra<StackOffset>()->offset; break; case AssertStk: case AssertStkVal: case CastStk: case CoerceStk: case CheckStk: case GuardStk: case ExceptionBarrier: m_spValue = inst->dst(); break; case SpillStack: { m_spValue = inst->dst(); // Push the spilled values but adjust for the popped values int64_t stackAdjustment = inst->src(1)->getValInt(); m_spOffset -= stackAdjustment; m_spOffset += spillValueCells(inst); break; } case SpillFrame: case CufIterSpillFrame: m_spValue = inst->dst(); m_spOffset += kNumActRecCells; break; case InterpOne: case InterpOneCF: { m_spValue = inst->dst(); auto const& extra = *inst->extra<InterpOneData>(); int64_t stackAdjustment = extra.cellsPopped - extra.cellsPushed; // push the return value if any and adjust for the popped values m_spOffset -= stackAdjustment; break; } case StElem: case StProp: case StPropNT: // fall through to StMem; stored value is the same arg number (2) case StMem: case StMemNT: m_refCountedMemValue = inst->src(2); break; case LdMem: case LdProp: case LdElem: case LdRef: case ArrayGet: case VectorGet: case PairGet: case MapGet: case StableMapGet: m_refCountedMemValue = inst->dst(); break; case StRefNT: case StRef: { m_refCountedMemValue = inst->src(2); SSATmp* newRef = inst->dst(); SSATmp* prevRef = inst->src(0); // update other tracked locals that also contain prevRef updateLocalRefValues(prevRef, newRef); break; } case StLocNT: case StLoc: setLocalValue(inst->extra<LocalId>()->locId, inst->src(1)); break; case LdLoc: setLocalValue(inst->extra<LdLoc>()->locId, inst->dst()); break; case OverrideLoc: // If changing the inner type of a boxed local, also drop the // information about inner types for any other boxed locals. if (inst->typeParam().isBoxed()) dropLocalRefsInnerTypes(); setLocalType(inst->extra<LocalId>()->locId, inst->typeParam()); break; case AssertLoc: case GuardLoc: case CheckLoc: m_fpValue = inst->dst(); refineLocalType(inst->extra<LocalId>()->locId, inst->typeParam()); break; case OverrideLocVal: setLocalValue(inst->extra<LocalId>()->locId, inst->src(1)); break; case SmashLocals: clearLocals(); break; case IterInitK: case WIterInitK: // kill the locals to which this instruction stores iter's key and value killLocalValue(inst->src(3)->getValInt()); killLocalValue(inst->src(4)->getValInt()); break; case IterInit: case WIterInit: // kill the local to which this instruction stores iter's value killLocalValue(inst->src(3)->getValInt()); break; case IterNextK: case WIterNextK: // kill the locals to which this instruction stores iter's key and value killLocalValue(inst->src(2)->getValInt()); killLocalValue(inst->src(3)->getValInt()); break; case IterNext: case WIterNext: // kill the local to which this instruction stores iter's value killLocalValue(inst->src(2)->getValInt()); break; case LdThis: m_thisIsAvailable = true; break; default: break; } if (MInstrEffects::supported(inst)) { MInstrEffects::get(inst, [&](uint32_t id, SSATmp* val) { // storeLocalValue setLocalValue(id, val); }, [&](uint32_t id, Type t) { // setLocalType setLocalType(id, t); }); } if (inst->modifiesStack()) { m_spValue = inst->modifiedStkPtr(); } // update the CSE table if (m_enableCse && inst->canCSE()) { cseInsert(inst); } // if the instruction kills any of its sources, remove them from the // CSE table if (inst->killsSources()) { for (int i = 0; i < inst->numSrcs(); ++i) { if (inst->killsSource(i)) { cseKill(inst->src(i)); } } } // save a copy of the current state for each successor. if (Block* target = inst->taken()) saveState(target); }
void FrameState::update(const IRInstruction* inst) { if (auto* taken = inst->taken()) { save(taken); } auto const opc = inst->op(); getLocalEffects(inst, *this); switch (opc) { case DefInlineFP: trackDefInlineFP(inst); break; case InlineReturn: trackInlineReturn(inst); break; case Call: m_spValue = inst->dst(); m_frameSpansCall = true; // A call pops the ActRec and pushes a return value. m_spOffset -= kNumActRecCells; m_spOffset += 1; assert(m_spOffset >= 0); clearCse(); break; case CallArray: m_spValue = inst->dst(); m_frameSpansCall = true; // A CallArray pops the ActRec an array arg and pushes a return value. m_spOffset -= kNumActRecCells; assert(m_spOffset >= 0); clearCse(); break; case ContEnter: clearCse(); break; case DefFP: case FreeActRec: m_fpValue = inst->dst(); break; case ReDefGeneratorSP: m_spValue = inst->dst(); break; case ReDefSP: m_spValue = inst->dst(); m_spOffset = inst->extra<ReDefSP>()->spOffset; break; case DefInlineSP: case DefSP: m_spValue = inst->dst(); m_spOffset = inst->extra<StackOffset>()->offset; break; case AssertStk: case AssertStkVal: case CastStk: case CoerceStk: case CheckStk: case GuardStk: case ExceptionBarrier: m_spValue = inst->dst(); break; case SpillStack: { m_spValue = inst->dst(); // Push the spilled values but adjust for the popped values int64_t stackAdjustment = inst->src(1)->getValInt(); m_spOffset -= stackAdjustment; m_spOffset += spillValueCells(inst); break; } case SpillFrame: case CufIterSpillFrame: m_spValue = inst->dst(); m_spOffset += kNumActRecCells; break; case InterpOne: case InterpOneCF: { m_spValue = inst->dst(); auto const& extra = *inst->extra<InterpOneData>(); int64_t stackAdjustment = extra.cellsPopped - extra.cellsPushed; // push the return value if any and adjust for the popped values m_spOffset -= stackAdjustment; break; } case AssertLoc: case GuardLoc: case CheckLoc: m_fpValue = inst->dst(); break; case LdThis: m_thisAvailable = true; break; default: break; } if (inst->modifiesStack()) { m_spValue = inst->modifiedStkPtr(); } // update the CSE table if (m_enableCse && inst->canCSE()) { cseInsert(inst); } // if the instruction kills any of its sources, remove them from the // CSE table if (inst->killsSources()) { for (int i = 0; i < inst->numSrcs(); ++i) { if (inst->killsSource(i)) { cseKill(inst->src(i)); } } } }