TCA fcallHelper(ActRec* ar) {
  assert_native_stack_aligned();

  assertx(!ar->resumed());
  if (LIKELY(!RuntimeOption::EvalFailJitPrologs)) {
    auto const tca = mcg->getFuncPrologue(
      const_cast<Func*>(ar->m_func),
      ar->numArgs(),
      ar
    );
    if (tca) return tca;
  }

  // Check for stack overflow in the same place func prologues make their
  // StackCheck::Early check (see irgen-func-prologue.cpp).  This handler also
  // cleans and syncs vmRegs for us.
  if (checkCalleeStackOverflow(ar)) handleStackOverflow(ar);

  try {
    VMRegAnchor _(ar);
    if (doFCall(ar, vmpc())) {
      return mcg->tx().uniqueStubs.resumeHelperRet;
    }
    // We've been asked to skip the function body (fb_intercept).  The vmregs
    // have already been fixed; indicate this with a nullptr return.
    return nullptr;
  } catch (...) {
    // The VMRegAnchor above took care of us, but we need to tell the unwinder
    // (since ~VMRegAnchor() will have reset tl_regState).
    tl_regState = VMRegState::CLEAN;
    throw;
  }
}
示例#2
0
TCA fcallHelper(ActRec* ar, void* sp) {
  try {
    assert(!ar->resumed());
    TCA tca = mcg->getFuncPrologue((Func*)ar->m_func, ar->numArgs(), ar);
    if (tca) {
      return tca;
    }
    if (!ar->m_func->isClonedClosure()) {
      /*
       * If the func is a cloned closure, then the original
       * closure has already run the prologue, and the prologues
       * array is just being used as entry points for the
       * dv funclets. Dont run the prologue again.
       */
      VMRegAnchor _(ar);
      if (doFCall(ar, vmpc())) {
        return mcg->tx().uniqueStubs.resumeHelperRet;
      }
      // We've been asked to skip the function body
      // (fb_intercept). frame, stack and pc have
      // already been fixed - flag that with a negative
      // return address.
      return (TCA)-ar->m_savedRip;
    }
    setupAfterPrologue(ar, sp);
    assert(ar == vmRegsUnsafe().fp);
    return mcg->tx().uniqueStubs.resumeHelper;
  } catch (...) {
    /*
      The return address is set to __fcallHelperThunk,
      which has no unwind information. Its "logically"
      part of the tc, but the c++ unwinder wont know
      that. So point our return address at the called
      function's return address (which will be in the
      tc).
      Note that the registers really are clean - we
      cleaned them in the try above - so we just
      have to tell the unwinder that.
    */
    DECLARE_FRAME_POINTER(framePtr);
    tl_regState = VMRegState::CLEAN;
    framePtr->m_savedRip = ar->m_savedRip;
    throw;
  }
}