Exemplo n.º 1
0
/*
 * This function returns the offset of instruction i's branch target.
 * This is normally the offset corresponding to the branch being
 * taken.  However, if i does not break a trace and it's followed in
 * the trace by the instruction in the taken branch, then this
 * function returns the offset of the i's fall-through instruction.
 * In that case, the invertCond output argument is set to true;
 * otherwise it's set to false.
 */
static Offset getBranchTarget(const NormalizedInstruction& i,
                              bool& invertCond) {
  assert(instrJumpOffset((Op*)(i.pc())) != nullptr);
  Offset targetOffset = i.offset() + i.imm[1].u_BA;
  invertCond = false;

  if (!i.endsRegion && i.nextOffset == targetOffset) {
    invertCond = true;
    Offset fallthruOffset = i.offset() + instrLen((Op*)i.pc());
    targetOffset = fallthruOffset;
  }

  return targetOffset;
}
Exemplo n.º 2
0
void IRTranslator::translateInstr(const NormalizedInstruction& ni) {
  auto& ht = m_hhbcTrans;
  ht.setBcOff(ni.source.offset(),
              ni.endsRegion && !m_hhbcTrans.isInlining());
  FTRACE(1, "\n{:-^60}\n", folly::format("Translating {}: {} with stack:\n{}",
                                         ni.offset(), ni.toString(),
                                         ht.showStack()));
  // When profiling, we disable type predictions to avoid side exits
  assert(IMPLIES(mcg->tx().mode() == TransKind::Profile, !ni.outputPredicted));

  ht.emitRB(RBTypeBytecodeStart, ni.source, 2);
  ht.emitIncStat(Stats::Instr_TC, 1, false);

  auto pc = reinterpret_cast<const Op*>(ni.pc());
  for (auto i = 0, num = instrNumPops(pc); i < num; ++i) {
    auto const type = flavorToType(instrInputFlavor(pc, i));
    if (type != Type::Gen) m_hhbcTrans.assertTypeStack(i, type);
  }

  if (RuntimeOption::EvalHHIRGenerateAsserts >= 2) {
    ht.emitDbgAssertRetAddr();
  }

  if (isAlwaysNop(ni.op())) {
    // Do nothing
  } else if (instrMustInterp(ni) || ni.interp) {
    interpretInstr(ni);
  } else {
    translateInstrWork(ni);
  }
}
Exemplo n.º 3
0
void
IRTranslator::translateBranchOp(const NormalizedInstruction& i) {
  auto const op = i.op();
  assert(op == OpJmpZ || op == OpJmpNZ);

  Offset takenOffset    = i.offset() + i.imm[0].u_BA;
  Offset fallthruOffset = i.offset() + instrLen((Op*)(i.pc()));

  auto jmpFlags = instrJmpFlags(i);

  if (i.nextOffset == takenOffset) {
    always_assert(RuntimeOption::EvalJitPGORegionSelector == "hottrace");
    // invert the branch
    if (op == OpJmpZ) {
      HHIR_EMIT(JmpNZ, fallthruOffset, jmpFlags);
    } else {
      HHIR_EMIT(JmpZ,  fallthruOffset, jmpFlags);
    }
    return;
  }

  if (op == OpJmpZ) {
    HHIR_EMIT(JmpZ,  takenOffset, jmpFlags);
  } else {
    HHIR_EMIT(JmpNZ, takenOffset, jmpFlags);
  }
}
Exemplo n.º 4
0
void
IRTranslator::translateBranchOp(const NormalizedInstruction& i) {
  auto const op = i.op();
  assert(op == OpJmpZ || op == OpJmpNZ);

  Offset takenOffset    = i.offset() + i.imm[0].u_BA;
  Offset fallthruOffset = i.offset() + instrLen((Op*)(i.pc()));
  assert(i.breaksTracelet ||
         i.nextOffset == takenOffset ||
         i.nextOffset == fallthruOffset);
  assert(!i.includeBothPaths || !i.breaksTracelet);

  if (i.breaksTracelet || i.nextOffset == fallthruOffset) {
    if (op == OpJmpZ) {
      HHIR_EMIT(JmpZ,  takenOffset, fallthruOffset, i.includeBothPaths);
    } else {
      HHIR_EMIT(JmpNZ, takenOffset, fallthruOffset, i.includeBothPaths);
    }
    return;
  }
  assert(i.nextOffset == takenOffset);
  // invert the branch
  if (op == OpJmpZ) {
    HHIR_EMIT(JmpNZ, fallthruOffset, takenOffset, i.includeBothPaths);
  } else {
    HHIR_EMIT(JmpZ,  fallthruOffset, takenOffset, i.includeBothPaths);
  }
}
Exemplo n.º 5
0
void IRTranslator::translateInstr(const NormalizedInstruction& ni) {
  auto& ht = m_hhbcTrans;
  ht.setBcOff(ni.source.offset(),
              ni.breaksTracelet && !m_hhbcTrans.isInlining());
  FTRACE(1, "\n{:-^60}\n", folly::format("Translating {}: {} with stack:\n{}",
                                         ni.offset(), ni.toString(),
                                         ht.showStack()));
  // When profiling, we disable type predictions to avoid side exits
  assert(IMPLIES(JIT::tx->mode() == TransKind::Profile, !ni.outputPredicted));

  if (ni.guardedThis) {
    // Task #2067635: This should really generate an AssertThis
    ht.setThisAvailable();
  }

  ht.emitRB(RBTypeBytecodeStart, ni.source, 2);

  auto pc = reinterpret_cast<const Op*>(ni.pc());
  for (auto i = 0, num = instrNumPops(pc); i < num; ++i) {
    auto const type = flavorToType(instrInputFlavor(pc, i));
    if (type != Type::Gen) m_hhbcTrans.assertTypeStack(i, type);
  }

  if (RuntimeOption::EvalHHIRGenerateAsserts >= 2) {
    ht.emitDbgAssertRetAddr();
  }

  if (instrMustInterp(ni) || ni.interp) {
    interpretInstr(ni);
  } else {
    translateInstrWork(ni);
  }

  passPredictedAndInferredTypes(ni);
}
Exemplo n.º 6
0
void translateInstr(
  IRGS& irgs,
  const NormalizedInstruction& ni,
  bool checkOuterTypeOnly,
  bool firstInst
) {
  irgen::prepareForNextHHBC(
    irgs,
    &ni,
    ni.source,
    ni.endsRegion && !irgen::isInlining(irgs)
  );

  const Func* builtinFunc = nullptr;
  if (ni.op() == OpFCallBuiltin) {
    auto str = ni.m_unit->lookupLitstrId(ni.imm[2].u_SA);
    builtinFunc = Unit::lookupFunc(str);
  }
  auto pc = ni.pc();
  for (auto i = 0, num = instrNumPops(pc); i < num; ++i) {
    auto const type =
      !builtinFunc ? flavorToType(instrInputFlavor(pc, i)) :
      builtinFunc->byRef(num - i - 1) ? TGen : TCell;
    // TODO(#5706706): want to use assertTypeLocation, but Location::Stack
    // is a little unsure of itself.
    irgen::assertTypeStack(irgs, BCSPOffset{i}, type);
  }

  FTRACE(1, "\nTranslating {}: {} with state:\n{}\n",
         ni.offset(), ni, show(irgs));

  irgen::ringbufferEntry(irgs, Trace::RBTypeBytecodeStart, ni.source, 2);
  irgen::emitIncStat(irgs, Stats::Instr_TC, 1);
  if (Stats::enableInstrCount()) {
    irgen::emitIncStat(irgs, Stats::opToTranslStat(ni.op()), 1);
  }
  if (Trace::moduleEnabledRelease(Trace::llvm_count, 1) ||
      RuntimeOption::EvalJitLLVMCounters) {
    irgen::gen(irgs, CountBytecode);
  }

  if (isAlwaysNop(ni.op())) return;
  if (ni.interp || RuntimeOption::EvalJitAlwaysInterpOne) {
    irgen::interpOne(irgs, ni);
    return;
  }

  translateDispatch(irgs, ni);

  FTRACE(3, "\nTranslated {}: {} with state:\n{}\n",
         ni.offset(), ni, show(irgs));
}