Esempio n. 1
0
RegionDescPtr selectCalleeRegion(const SrcKey& sk,
                                 const Func* callee,
                                 const irgen::IRGS& irgs,
                                 InliningDecider& inl,
                                 int32_t maxBCInstrs) {
  auto const op = sk.pc();
  auto const numArgs = getImm(op, 0).u_IVA;

  auto const& fpi = irgs.irb->fs().fpiStack();
  assertx(!fpi.empty());
  auto const ctx = fpi.back().ctxType;

  std::vector<Type> argTypes;
  for (int i = numArgs - 1; i >= 0; --i) {
    // DataTypeGeneric is used because we're just passing the locals into the
    // callee.  It's up to the callee to constrain further if needed.
    auto type = irgen::publicTopType(irgs, BCSPRelOffset{i});

    // If we don't have sufficient type information to inline the region return
    // early
    if (!(type <= TCell) && !(type <= TBoxedCell) && !(type <= TCls)) {
      return nullptr;
    }
    argTypes.push_back(type);
  }

  const auto mode = RuntimeOption::EvalInlineRegionMode;
  if (mode == "tracelet" || mode == "both") {
    auto region = selectCalleeTracelet(
      callee,
      numArgs,
      ctx,
      argTypes,
      maxBCInstrs
    );
    auto const maxCost = RuntimeOption::EvalHHIRInliningMaxVasmCost;
    if (region && inl.shouldInline(sk, callee, *region, maxCost)) return region;
    if (mode == "tracelet") return nullptr;
  }

  if (profData()) {
    auto region = selectCalleeCFG(callee, numArgs, ctx, argTypes, maxBCInstrs);
    auto const maxCost = RuntimeOption::EvalHHIRInliningMaxVasmCost;
    if (region && inl.shouldInline(sk, callee, *region, maxCost)) return region;
  }

  return nullptr;
}
Esempio n. 2
0
void addDbgGuardImpl(SrcKey sk, SrcRec* sr) {
  TCA realCode = sr->getTopTranslation();
  if (!realCode) return;  // No translations, nothing to do.

  auto& cb = mcg->code.main();

  auto const dbgGuard = vwrap(cb, [&] (Vout& v) {
    if (!sk.resumed()) {
      auto const off = sr->nonResumedSPOff();
      v << lea{rvmfp()[-cellsToBytes(off.offset)], rvmsp()};
    }

    auto const tinfo = v.makeReg();
    auto const attached = v.makeReg();
    auto const sf = v.makeReg();

    auto const done = v.makeBlock();

    constexpr size_t dbgOff =
      offsetof(ThreadInfo, m_reqInjectionData) +
      RequestInjectionData::debuggerReadOnlyOffset();

    v << ldimmq{reinterpret_cast<uintptr_t>(sk.pc()), rarg(0)};

    emitTLSLoad(v, tls_datum(ThreadInfo::s_threadInfo), tinfo);
    v << loadb{tinfo[dbgOff], attached};
    v << testbi{static_cast<int8_t>(0xffu), attached, sf};

    v << jcci{CC_NZ, sf, done, mcg->ustubs().interpHelper};

    v = done;
    v << fallthru{};
  }, CodeKind::Helper);

  // Emit a jump to the actual code.
  auto const dbgBranchGuardSrc = emitSmashableJmp(cb, realCode);

  // Add the guard to the SrcRec.
  sr->addDebuggerGuard(dbgGuard, dbgBranchGuardSrc);
}
Esempio n. 3
0
/*
 * Check that we don't have any missing or extra arguments.
 */
bool checkNumArgs(SrcKey callSK, const Func* callee, Annotations& annotations) {
  assertx(callSK.op() == Op::FCall);
  assertx(callee);

  auto refuse = [&] (const char* why) {
    return traceRefusal(callSK, callee, why, annotations);
  };

  auto pc = callSK.pc();
  auto const fca = getImm(pc, 0).u_FCA;
  auto const numParams = callee->numParams();

  if (fca.numArgs > numParams) {
    return refuse("callee called with too many arguments");
  }

  if (fca.hasUnpack) {
    return refuse("callee called with variadic arguments");
  }

  if (fca.numRets != 1) {
    return refuse("callee with multiple returns");
  }

  // It's okay if we passed fewer arguments than there are parameters as long
  // as the gap can be filled in by DV funclets.
  for (auto i = fca.numArgs; i < numParams; ++i) {
    auto const& param = callee->params()[i];
    if (!param.hasDefaultValue() &&
        (i < numParams - 1 || !callee->hasVariadicCaptureParam())) {
      return refuse("callee called with too few arguments");
    }
  }

  return true;
}