void EventHook::onFunctionReturn(ActRec* ar, TypedValue retval) { // The locals are already gone. Null out everything. ar->setThisOrClassAllowNull(nullptr); ar->setLocalsDecRefd(); ar->setVarEnv(nullptr); try { ssize_t flags = CheckSurprise(); onFunctionExit(ar, &retval, nullptr, flags); // Async profiler if ((flags & AsyncEventHookFlag) && ar->func()->isAsyncFunction() && ar->resumed()) { auto session = AsioSession::Get(); // Return @ resumed execution => AsyncFunctionWaitHandle succeeded. if (session->hasOnResumableSuccessCallback()) { auto afwh = frame_afwh(ar); session->onResumableSuccess(afwh, cellAsCVarRef(retval)); } } } catch (...) { /* * We're responsible for freeing the return value if we exit with an * exception. See irgen-ret. */ tvRefcountedDecRef(retval); throw; } }
void EventHook::onFunctionReturn(ActRec* ar, const TypedValue& retval) { // Null out $this for the exiting function, it has been decref'd so it's // garbage. ar->setThisOrClassAllowNull(nullptr); // The locals are already gone. Mark them as decref'd so that if this hook // fails and unwinder kicks in, it won't try to decref them again. ar->setLocalsDecRefd(); // TODO(#5758054): does this need setVarEnv(nullptr) ? ssize_t flags = CheckSurprise(); onFunctionExit(ar, &retval, nullptr, flags); // Async profiler if ((flags & RequestInjectionData::AsyncEventHookFlag) && ar->func()->isAsyncFunction() && ar->resumed()) { auto session = AsioSession::Get(); // Return @ resumed execution => AsyncFunctionWaitHandle succeeded. if (session->hasOnResumableSuccessCallback()) { auto afwh = frame_afwh(ar); session->onResumableSuccess(afwh, cellAsCVarRef(retval)); } } }
void AsioSession::updateEventHookState() { if (hasOnResumableCreateCallback() || hasOnResumableAwaitCallback() || hasOnResumableSuccessCallback()) { EventHook::EnableAsync(); } else { EventHook::DisableAsync(); } }