Exemple #1
0
bool breaksRegion(SrcKey sk) {
  switch (sk.op()) {
    case Op::SSwitch:
    case Op::CreateCont:
    case Op::Yield:
    case Op::YieldK:
    case Op::RetC:
    case Op::RetV:
    case Op::Exit:
    case Op::Fatal:
    case Op::Throw:
    case Op::Unwind:
    case Op::Eval:
    case Op::NativeImpl:
      return true;

    case Op::Await:
      // We break regions at resumed Await instructions, to avoid
      // duplicating the translation of the resumed SrcKey after the
      // Await.
      return sk.resumed();

    default:
      return false;
  }
}
Exemple #2
0
bool InliningDecider::canInlineAt(SrcKey callSK, const Func* callee) const {
  if (m_disabled ||
      !callee ||
      !RuntimeOption::EvalHHIREnableGenTimeInlining ||
      RuntimeOption::EvalJitEnableRenameFunction ||
      callee->attrs() & AttrInterceptable) {
    return false;
  }

  // We can only inline at normal FCalls.
  if (callSK.op() != Op::FCall &&
      callSK.op() != Op::FCallD) {
    return false;
  }

  // Don't inline from resumed functions.  The inlining mechanism doesn't have
  // support for these---it has no way to redefine stack pointers relative to
  // the frame pointer, because in a resumed function the frame pointer points
  // into the heap instead of into the eval stack.
  if (callSK.resumed()) return false;

  // TODO(#4238160): Inlining into pseudomain callsites is still buggy.
  if (callSK.func()->isPseudoMain()) return false;

  if (!isCalleeInlinable(callSK, callee) || !checkNumArgs(callSK, callee)) {
    return false;
  }

  return true;
}
Exemple #3
0
bool InliningDecider::canInlineAt(SrcKey callSK, const Func* callee) const {
  if (!callee ||
      !RuntimeOption::EvalHHIREnableGenTimeInlining ||
      RuntimeOption::EvalJitEnableRenameFunction ||
      callee->attrs() & AttrInterceptable) {
    return false;
  }

  if (callee->cls()) {
    if (!classHasPersistentRDS(callee->cls())) {
      // if the callee's class is not persistent, its still ok
      // to use it if we're jitting into a method of a subclass
      auto ctx = callSK.func()->cls();
      if (!ctx || !ctx->classof(callee->cls())) {
        return false;
      }
    }
  } else {
    auto const handle = callee->funcHandle();
    if (handle == rds::kInvalidHandle || !rds::isPersistentHandle(handle)) {
      // if the callee isn't persistent, its still ok to
      // use it if its defined at the top level in the same
      // unit as the caller
      if (callee->unit() != callSK.unit() || !callee->top()) {
        return false;
      }
    }
  }

  // If inlining was disabled... don't inline.
  if (m_disabled) return false;

  // TODO(#3331014): We have this hack until more ARM codegen is working.
  if (arch() == Arch::ARM) return false;

  // We can only inline at normal FCalls.
  if (callSK.op() != Op::FCall &&
      callSK.op() != Op::FCallD) {
    return false;
  }

  // Don't inline from resumed functions.  The inlining mechanism doesn't have
  // support for these---it has no way to redefine stack pointers relative to
  // the frame pointer, because in a resumed function the frame pointer points
  // into the heap instead of into the eval stack.
  if (callSK.resumed()) return false;

  // TODO(#4238160): Inlining into pseudomain callsites is still buggy.
  if (callSK.func()->isPseudoMain()) return false;

  if (!isCalleeInlinable(callSK, callee) || !checkNumArgs(callSK, callee)) {
    return false;
  }

  return true;
}
Exemple #4
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;
}
Exemple #5
0
bool InliningDecider::canInlineAt(SrcKey callSK, const Func* callee,
                                  const RegionDesc& region) const {
  if (!RuntimeOption::RepoAuthoritative ||
      !RuntimeOption::EvalHHIREnableGenTimeInlining) {
    return false;
  }

  // If inlining was disabled... don't inline.
  if (m_disabled) return false;

  // TODO(#3331014): We have this hack until more ARM codegen is working.
  if (arch() == Arch::ARM) return false;

  // We can only inline at normal FCalls.
  if (callSK.op() != Op::FCall &&
      callSK.op() != Op::FCallD) {
    return false;
  }

  // Don't inline from resumed functions.  The inlining mechanism doesn't have
  // support for these---it has no way to redefine stack pointers relative to
  // the frame pointer, because in a resumed function the frame pointer points
  // into the heap instead of into the eval stack.
  if (callSK.resumed()) return false;

  // TODO(#4238160): Inlining into pseudomain callsites is still buggy.
  if (callSK.func()->isPseudoMain()) return false;

  if (!isCalleeInlinable(callSK, callee) ||
      !checkNumArgs(callSK, callee) ||
      !checkFPIRegion(callSK, callee, region)) {
    return false;
  }

  return true;
}