/*
 * This is used to generate an entry point for the entry
 * to a function, after the prologue has run.
 */
TCA funcBodyHelper(ActRec* fp, void* sp) {
  setupAfterPrologue(fp, sp);
  tl_regState = VMRegState::CLEAN;
  Func* func = const_cast<Func*>(fp->m_func);

  TCA tca = mcg->getCallArrayPrologue(func);

  if (!tca) {
    tca = tx->uniqueStubs.resumeHelper;
  }
  tl_regState = VMRegState::DIRTY;
  return tca;
}
/*
 * This is used to generate an entry point for the entry to a function, after
 * the prologue has run.
 */
TCA funcBodyHelper(ActRec* fp, void* sp) {
  assert_native_stack_aligned();
  setupAfterPrologue(fp, sp);
  tl_regState = VMRegState::CLEAN;
  Func* func = const_cast<Func*>(fp->m_func);

  TCA tca = mcg->getCallArrayPrologue(func);

  if (!tca) {
    tca = mcg->tx().uniqueStubs.resumeHelper;
  }
  tl_regState = VMRegState::DIRTY;
  return tca;
}
/*
 * This is used to generate an entry point for the entry to a function, after
 * the prologue has run.
 */
TCA funcBodyHelper(ActRec* fp) {
  assert_native_stack_aligned();
  void* const sp = reinterpret_cast<Cell*>(fp) - fp->func()->numSlotsInFrame();
  setupAfterPrologue(fp, sp);
  tl_regState = VMRegState::CLEAN;

  auto const func = const_cast<Func*>(fp->m_func);
  auto tca = mcg->getFuncBody(func);
  if (!tca) {
    tca = mcg->tx().uniqueStubs.resumeHelper;
  }

  tl_regState = VMRegState::DIRTY;
  return tca;
}
TCA fcallHelper(ActRec* ar, void* sp) {
  try {
    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);
      uint64_t rip = ar->m_savedRip;
      if (g_context->doFCall(ar, g_context->m_pc)) {
        ar->m_savedRip = rip;
        return 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)-rip;
    }
    setupAfterPrologue(ar, sp);
    assert(ar == g_context->m_fp);
    return 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;
  }
}