コード例 #1
0
ファイル: frame-state.cpp プロジェクト: abhiskaushik/hhvm
void FrameState::clear() {
  clearCse();
  clearLocals(*this);
  m_frameSpansCall = false;
  m_spValue = m_fpValue = nullptr;
  m_spOffset = 0;
  m_thisAvailable = false;
  m_marker = BCMarker();
  m_snapshots.clear();
  assert(m_inlineSavedStates.empty());
}
コード例 #2
0
ファイル: frame-state.cpp プロジェクト: abhiskaushik/hhvm
/*
 * Merge current state into state.  Frame pointers and stack depth must match.
 * If the stack pointer tmps are different, clear the tracked value (we can
 * make a new one, given fp and spOffset).
 *
 * thisIsAvailable remains true if it's true in both states.
 * local variable values are preserved if the match in both states.
 * types are combined using Type::unionOf.
 */
void FrameState::merge(Snapshot& state) {
  // cannot merge fp or spOffset state, so assert they match
  assert(state.fpValue == m_fpValue);
  assert(state.spOffset == m_spOffset);
  assert(state.curFunc == m_curFunc);
  if (state.spValue != m_spValue) {
    // we have two different sp definitions but we know they're equal
    // because spOffset matched.
    state.spValue = nullptr;
  }
  // this is available iff it's available in both states
  state.thisAvailable &= m_thisAvailable;

  assert(m_locals.size() == state.locals.size());
  for (unsigned i = 0; i < m_locals.size(); ++i) {
    auto& local = state.locals[i];

    // preserve local values if they're the same in both states,
    // This would be the place to insert phi nodes (jmps+deflabels) if we want
    // to avoid clearing state, which triggers a downstream reload.
    if (local.value != m_locals[i].value) local.value = nullptr;
    if (local.typeSource != m_locals[i].typeSource) local.typeSource = nullptr;

    local.type = Type::unionOf(local.type, m_locals[i].type);
  }

  // TODO(t3729135): If we are merging states from different bytecode
  // paths, we must conservatively clear the CSE table.  Since the
  // markers may or may not have been updated, we always clear.  What
  // we need is a global CSE algorithm.
  if (RuntimeOption::EvalHHIRBytecodeControlFlow) {
    clearCse();
  }

  // For now, we shouldn't be merging states with different inline states.
  assert(m_inlineSavedStates == state.inlineSavedStates);
}
コード例 #3
0
ファイル: frame-state.cpp プロジェクト: abhiskaushik/hhvm
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());
  }
}
コード例 #4
0
ファイル: frame-state.cpp プロジェクト: Hillgod/hiphop-php
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));
      }
    }
  }
}