Beispiel #1
0
void EventHook::onFunctionExit(const ActRec* ar, const TypedValue* retval,
                               const Fault* fault, ssize_t flags) {
  // Xenon
  if (flags & XenonSignalFlag) {
    Xenon::getInstance().log(Xenon::ExitSample);
  }

  // Run IntervalTimer callbacks only if it's safe to do so, i.e., not when
  // there's a pending exception or we're unwinding from a C++ exception.
  if (flags & IntervalTimerFlag
      && ThreadInfo::s_threadInfo->m_pendingException == nullptr
      && (!fault || fault->m_faultType == Fault::Type::UserException)) {
    IntervalTimer::RunCallbacks(IntervalTimer::ExitSample);
  }

  // Inlined calls normally skip the function enter and exit events. If we
  // side exit in an inlined callee, we short-circuit here in order to skip
  // exit events that could unbalance the call stack.
  if (RuntimeOption::EvalJit &&
      ((jit::TCA) ar->m_savedRip == jit::mcg->tx().uniqueStubs.retInlHelper)) {
    return;
  }

  // User profiler
  if (flags & EventHookFlag) {
    auto profiler = ThreadInfo::s_threadInfo->m_profiler;
    if (profiler != nullptr &&
        !(profiler->shouldSkipBuiltins() && ar->func()->isBuiltin())) {
      // NB: we don't have a function type flag to match what we got in
      // onFunctionEnter. That's okay, though... we tolerate this in
      // TraceProfiler.
      end_profiler_frame(profiler,
                         retval,
                         GetFunctionNameForProfiler(ar->func(), NormalFunc));
    }

    if (shouldRunUserProfiler(ar->func())) {
      if (ThreadInfo::s_threadInfo->m_pendingException != nullptr) {
        // Avoid running PHP code when exception from destructor is pending.
        // TODO(#2329497) will not happen once CheckSurprise is used
      } else if (!fault) {
        runUserProfilerOnFunctionExit(ar, retval, nullptr);
      } else if (fault->m_faultType == Fault::Type::UserException) {
        runUserProfilerOnFunctionExit(ar, retval, fault->m_userException);
      } else {
        // Avoid running PHP code when unwinding C++ exception.
      }
    }
  }

  // Debugger hook
  if (flags & DebuggerHookFlag) {
    DEBUGGER_ATTACHED_ONLY(phpDebuggerFuncExitHook(ar));
  }
}
Beispiel #2
0
void EventHook::onFunctionExit(const ActRec* ar, const TypedValue* retval,
                               const Fault* fault, ssize_t flags) {
  // Xenon
  if (flags & RequestInjectionData::XenonSignalFlag) {
    Xenon::getInstance().log(Xenon::ExitSample);
  }

  // Inlined calls normally skip the function enter and exit events. If we
  // side exit in an inlined callee, we short-circuit here in order to skip
  // exit events that could unbalance the call stack.
  if ((JIT::TCA) ar->m_savedRip == JIT::mcg->tx().uniqueStubs.retInlHelper) {
    return;
  }

  // User profiler
  if (flags & RequestInjectionData::EventHookFlag) {
    Profiler* profiler = ThreadInfo::s_threadInfo->m_profiler;
    if (profiler != nullptr) {
      // NB: we don't have a function type flag to match what we got in
      // onFunctionEnter. That's okay, though... we tolerate this in
      // TraceProfiler.
      end_profiler_frame(profiler,
                         retval,
                         GetFunctionNameForProfiler(ar->func(), NormalFunc));
    }

    if (shouldRunUserProfiler(ar->func())) {
      if (ThreadInfo::s_threadInfo->m_pendingException != nullptr) {
        // Avoid running PHP code when exception from destructor is pending.
        // TODO(#2329497) will not happen once CheckSurprise is used
      } else if (!fault) {
        runUserProfilerOnFunctionExit(ar, retval, nullptr);
      } else if (fault->m_faultType == Fault::Type::UserException) {
        runUserProfilerOnFunctionExit(ar, retval, fault->m_userException);
      } else {
        // Avoid running PHP code when unwinding C++ exception.
      }
    }
  }

  // Debugger hook
  if (flags & RequestInjectionData::DebuggerHookFlag) {
    DEBUGGER_ATTACHED_ONLY(phpDebuggerFuncExitHook(ar));
  }
}