static ActRec* getPrevActRec(const ActRec* fp, Offset* prevPc) { if (fp && fp->func() && fp->resumed() && fp->func()->isAsyncFunction()) { c_WaitableWaitHandle* currentWaitHandle = frame_afwh(fp); if (currentWaitHandle->isFinished()) { /* * It's possible in very rare cases (it will return a truncated stack): * 1) async function which WaitHandle is not referenced by anything * else finishes * 2) its return value is an object with destructor * 3) this destructor gets called as part of destruction of the * WaitHandleobject, which happens right before FP is adjusted */ return nullptr; } auto const contextIdx = currentWaitHandle->getContextIdx(); while (currentWaitHandle != nullptr) { auto p = currentWaitHandle->getParentChain().firstInContext(contextIdx); if (p == nullptr) break; if (p->getKind() == c_WaitHandle::Kind::AsyncFunction) { auto wh = p->asAsyncFunction(); *prevPc = wh->resumable()->resumeOffset(); return wh->actRec(); } currentWaitHandle = p; } *prevPc = 0; return AsioSession::Get()->getContext(contextIdx)->getSavedFP(); } return g_context->getPrevVMState(fp, prevPc); }
String c_WaitableWaitHandle::getName() { switch (getKind()) { case Kind::Static: not_reached(); case Kind::AsyncFunction: return asAsyncFunction()->getName(); case Kind::AsyncGenerator: return asAsyncGenerator()->getName(); case Kind::AwaitAll: return asAwaitAll()->getName(); case Kind::Condition: return asCondition()->getName(); case Kind::Reschedule: return asReschedule()->getName(); case Kind::Sleep: return asSleep()->getName(); case Kind::ExternalThreadEvent: return asExternalThreadEvent()->getName(); } not_reached(); }
c_WaitableWaitHandle* c_WaitableWaitHandle::getChild() { assertx(!isFinished()); switch (getKind()) { case Kind::Static: not_reached(); case Kind::AsyncFunction: return asAsyncFunction()->getChild(); case Kind::AsyncGenerator: return asAsyncGenerator()->getChild(); case Kind::AwaitAll: return asAwaitAll()->getChild(); case Kind::Condition: return asCondition()->getChild(); case Kind::Reschedule: return nullptr; case Kind::Sleep: return nullptr; case Kind::ExternalThreadEvent: return nullptr; } not_reached(); }
c_WaitableWaitHandle* c_WaitableWaitHandle::getChild() { assert(!isFinished()); switch (getKind()) { case Kind::Static: not_reached(); case Kind::AsyncFunction: return asAsyncFunction()->getChild(); case Kind::AsyncGenerator: return asAsyncGenerator()->getChild(); case Kind::GenArray: return asGenArray()->getChild(); case Kind::GenMap: return asGenMap()->getChild(); case Kind::GenVector: return asGenVector()->getChild(); case Kind::Reschedule: return nullptr; case Kind::Sleep: return nullptr; case Kind::ExternalThreadEvent: return nullptr; return nullptr; } not_reached(); }
static ActRec* getPrevActRec( const ActRec* fp, Offset* prevPc, folly::small_vector<c_WaitableWaitHandle*, 64>& visitedWHs) { if (fp && fp->func() && fp->resumed() && fp->func()->isAsyncFunction()) { c_WaitableWaitHandle* currentWaitHandle = frame_afwh(fp); if (currentWaitHandle->isFinished()) { /* * It's possible in very rare cases (it will return a truncated stack): * 1) async function which WaitHandle is not referenced by anything * else finishes * 2) its return value is an object with destructor * 3) this destructor gets called as part of destruction of the * WaitHandleobject, which happens right before FP is adjusted */ return nullptr; } auto const contextIdx = currentWaitHandle->getContextIdx(); while (currentWaitHandle != nullptr) { auto p = currentWaitHandle->getParentChain().firstInContext(contextIdx); if (p == nullptr || UNLIKELY(std::find(visitedWHs.begin(), visitedWHs.end(), p) != visitedWHs.end())) { // If the parent exists in our backtrace, it means we have detected a // cycle. Fall back to savedFP in that case. break; } visitedWHs.push_back(p); if (p->getKind() == c_WaitHandle::Kind::AsyncFunction) { auto wh = p->asAsyncFunction(); *prevPc = wh->resumable()->resumeOffset(); return wh->actRec(); } currentWaitHandle = p; } *prevPc = 0; return AsioSession::Get()->getContext(contextIdx)->getSavedFP(); } return g_context->getPrevVMState(fp, prevPc); }
void c_WaitableWaitHandle::enterContextImpl(context_idx_t ctx_idx) { switch (getKind()) { case Kind::Static: not_reached(); case Kind::AsyncFunction: return asAsyncFunction()->enterContextImpl(ctx_idx); case Kind::AsyncGenerator: return asAsyncGenerator()->enterContextImpl(ctx_idx); case Kind::GenArray: return asGenArray()->enterContextImpl(ctx_idx); case Kind::GenMap: return asGenMap()->enterContextImpl(ctx_idx); case Kind::GenVector: return asGenVector()->enterContextImpl(ctx_idx); case Kind::Reschedule: return asReschedule()->enterContextImpl(ctx_idx); case Kind::Sleep: return asSleep()->enterContextImpl(ctx_idx); case Kind::ExternalThreadEvent: return asExternalThreadEvent()->enterContextImpl(ctx_idx); } not_reached(); }