Object c_AwaitAllWaitHandle::FromMap(const BaseMap* dependencies) { auto const start = dependencies->firstElm(); auto const stop = dependencies->elmLimit(); int32_t cnt = 0; for (auto iter = start; iter != stop; iter = BaseMap::nextElm(iter, stop)) { auto const current = tvAssertCell(&iter->data); auto const child = c_WaitHandle::fromCell(current); if (UNLIKELY(!child)) failMap(); cnt += !child->isFinished(); } if (!cnt) return returnEmpty(); SmartPtr<c_AwaitAllWaitHandle> result(Alloc(cnt)); auto next = &result->m_children[cnt]; for (auto iter = start; iter != stop; iter = BaseMap::nextElm(iter, stop)) { auto const current = tvAssertCell(&iter->data); auto const child = c_WaitHandle::fromCell(current); if (child->isFinished()) continue; child->incRefCount(); *(--next) = static_cast<c_WaitableWaitHandle*>(child); } assert(next == &result->m_children[0]); result->initialize(); return Object(std::move(result)); }
Object c_AwaitAllWaitHandle::FromVector(const BaseVector* dependencies) { auto const start = dependencies->data(); auto const stop = start + dependencies->size(); int32_t cnt = 0; for (auto iter = start; iter < stop; ++iter) { auto const current = tvAssertCell(iter); auto const child = c_WaitHandle::fromCell(current); if (UNLIKELY(!child)) failVector(); cnt += !child->isFinished(); } if (!cnt) return returnEmpty(); SmartPtr<c_AwaitAllWaitHandle> result(Alloc(cnt)); auto next = &result->m_children[cnt]; for (auto iter = start; iter < stop; ++iter) { auto const current = tvAssertCell(iter); auto const child = c_WaitHandle::fromCell(current); if (child->isFinished()) continue; child->incRefCount(); *(--next) = static_cast<c_WaitableWaitHandle*>(child); } assert(next == &result->m_children[0]); result->initialize(); return Object(std::move(result)); }
Object c_GenMapWaitHandle::ti_create(const Variant& dependencies) { if (UNLIKELY(!dependencies.isObject() || dependencies.getObjectData()->getCollectionType() != Collection::MapType)) { Object e(SystemLib::AllocInvalidArgumentExceptionObject( "Expected dependencies to be an instance of Map")); throw e; } assert(dependencies.getObjectData()->instanceof(c_Map::classof())); auto deps = p_Map::attach(c_Map::Clone(dependencies.getObjectData())); for (ssize_t iter_pos = deps->iter_begin(); deps->iter_valid(iter_pos); iter_pos = deps->iter_next(iter_pos)) { auto* current = tvAssertCell(deps->iter_value(iter_pos)); if (UNLIKELY(!c_WaitHandle::fromCell(current))) { Object e(SystemLib::AllocInvalidArgumentExceptionObject( "Expected dependencies to be a map of WaitHandle instances")); throw e; } } Object exception; for (ssize_t iter_pos = deps->iter_begin(); deps->iter_valid(iter_pos); iter_pos = deps->iter_next(iter_pos)) { auto* current = tvAssertCell(deps->iter_value(iter_pos)); assert(current->m_type == KindOfObject); assert(current->m_data.pobj->instanceof(c_WaitHandle::classof())); auto child = static_cast<c_WaitHandle*>(current->m_data.pobj); if (child->isSucceeded()) { auto k = deps->iter_key(iter_pos); deps->set(k.asCell(), &child->getResult()); } else if (child->isFailed()) { putException(exception, child->getException()); } else { assert(child->instanceof(c_WaitableWaitHandle::classof())); auto child_wh = static_cast<c_WaitableWaitHandle*>(child); p_GenMapWaitHandle my_wh = NEWOBJ(c_GenMapWaitHandle)(); my_wh->initialize(exception, deps.get(), iter_pos, child_wh); AsioSession* session = AsioSession::Get(); if (UNLIKELY(session->hasOnGenMapCreateCallback())) { session->onGenMapCreate(my_wh.get(), dependencies); } return my_wh; } } if (exception.isNull()) { return Object::attach(c_StaticWaitHandle::CreateSucceeded( make_tv<KindOfObject>(deps.detach()))); } else { return Object::attach(c_StaticWaitHandle::CreateFailed(exception.detach())); } }
void c_GenVectorWaitHandle::enterContext(context_idx_t ctx_idx) { assert(AsioSession::Get()->getContext(ctx_idx)); // stop before corrupting unioned data if (isFinished()) { return; } // already in the more specific context? if (LIKELY(getContextIdx() >= ctx_idx)) { return; } assert(getState() == STATE_BLOCKED); // recursively import current child { assert(m_iterPos < m_deps->size()); Cell* current = tvAssertCell(m_deps->at(m_iterPos)); assert(current->m_type == KindOfObject); assert(dynamic_cast<c_WaitableWaitHandle*>(current->m_data.pobj)); auto child_wh = static_cast<c_WaitableWaitHandle*>(current->m_data.pobj); child_wh->enterContext(ctx_idx); } // import ourselves setContextIdx(ctx_idx); // try to import other children try { for (int64_t iter_pos = m_iterPos + 1; iter_pos < m_deps->size(); ++iter_pos) { Cell* current = tvAssertCell(m_deps->at(iter_pos)); assert(current->m_type == KindOfObject); assert(dynamic_cast<c_WaitHandle*>(current->m_data.pobj)); auto child = static_cast<c_WaitHandle*>(current->m_data.pobj); if (child->isFinished()) { continue; } assert(dynamic_cast<c_WaitableWaitHandle*>(child)); auto child_wh = static_cast<c_WaitableWaitHandle*>(child); child_wh->enterContext(ctx_idx); } } catch (const Object& cycle_exception) { // exception will be eventually processed by onUnblocked() } }
void c_AsyncFunctionWaitHandle::Create(c_Continuation* continuation) { assert(continuation); assert(continuation->m_label > 0); assert(continuation->m_waitHandle.isNull()); AsioSession* session = AsioSession::Get(); uint16_t depth = session->getCurrentWaitHandleDepth(); if (UNLIKELY(depth >= MAX_DEPTH)) { Object e(SystemLib::AllocInvalidOperationExceptionObject( "Asio stack overflow")); throw e; } Cell* value = tvAssertCell(continuation->m_value.asTypedValue()); assert(dynamic_cast<c_WaitableWaitHandle*>(c_WaitHandle::fromCell(value))); auto child = static_cast<c_WaitableWaitHandle*>(value->m_data.pobj); assert(!child->isFinished()); // import child into the current context, detect cross-context cycles if (session->isInContext()) { child->enterContext(session->getCurrentContextIdx()); } continuation->m_waitHandle = NEWOBJ(c_AsyncFunctionWaitHandle)(); continuation->m_waitHandle->initialize(continuation, child, depth + 1); // needs to be called after continuation->m_waitHandle is set if (UNLIKELY(session->hasOnAsyncFunctionCreateCallback())) { session->onAsyncFunctionCreate(continuation->m_waitHandle.get()); } }
void c_GenVectorWaitHandle::onUnblocked() { for (; m_iterPos < m_deps->size(); ++m_iterPos) { Cell* current = tvAssertCell(m_deps->at(m_iterPos)); assert(current->m_type == KindOfObject); assert(dynamic_cast<c_WaitHandle*>(current->m_data.pobj)); auto child = static_cast<c_WaitHandle*>(current->m_data.pobj); if (child->isSucceeded()) { cellSet(child->getResult(), *current); } else if (child->isFailed()) { putException(m_exception, child->getException()); } else { assert(dynamic_cast<c_WaitableWaitHandle*>(child)); auto child_wh = static_cast<c_WaitableWaitHandle*>(child); try { blockOn(child_wh); return; } catch (const Object& cycle_exception) { putException(m_exception, cycle_exception.get()); } } } if (m_exception.isNull()) { setResult(make_tv<KindOfObject>(m_deps.get())); m_deps = nullptr; } else { setException(m_exception.get()); m_exception = nullptr; m_deps = nullptr; } }
Variant HHVM_FUNCTION(serialize_memoize_param, const Variant& param) { // Memoize throws in the emitter if any function parameters are references, so // we can just assert that the param is cell here const auto& cell_param = *tvAssertCell(param.asTypedValue()); auto type = param.getType(); if (type == KindOfInt64) { return param; } else if (type == KindOfUninit || type == KindOfNull) { return s_empty; } else if (type == KindOfBoolean) { return param.asBooleanVal() ? s_true : s_false; } else if (type == KindOfString) { auto str = param.asCStrRef(); if (str.empty()) { return s_emptyStr; } else if (str.charAt(0) > '9') { // If it doesn't start with a number, then we know it can never collide // with an int or any of our constants, so it's fine as is return param; } } else if (isContainer(cell_param) && getContainerSize(cell_param) == 0) { return s_emptyArr; } return fb_compact_serialize(param, FBCompactSerializeBehavior::MemoizeParam); }
Object c_AwaitAllWaitHandle::FromVector(const BaseVector* dependencies) { auto const start = dependencies->data(); auto const stop = start + dependencies->size(); return createAAWH<const TypedValue*>(start, stop, [](const TypedValue* tv, UNUSED const TypedValue* limit) { return tv + 1; }, [](const TypedValue* tv) { return tvAssertCell(tv); }); }
Object c_AwaitAllWaitHandle::FromMap(const BaseMap* dependencies) { auto const start = dependencies->firstElm(); auto const stop = dependencies->elmLimit(); return createAAWH<const BaseMap::Elm*>(start, stop, [](const BaseMap::Elm* cur, const BaseMap::Elm* limit) { return BaseMap::nextElm(cur, limit); }, [](const BaseMap::Elm* elm) { return tvAssertCell(&elm->data); }); }
Object c_GenVectorWaitHandle::ti_create(const Variant& dependencies) { if (UNLIKELY(!dependencies.isObject() || dependencies.getObjectData()->getCollectionType() != Collection::VectorType)) { Object e(SystemLib::AllocInvalidArgumentExceptionObject( "Expected dependencies to be an instance of Vector")); throw e; } assert(dependencies.getObjectData()->instanceof(c_Vector::classof())); auto deps = SmartObject<c_Vector>::attach( c_Vector::Clone(dependencies.getObjectData())); for (int64_t iter_pos = 0; iter_pos < deps->size(); ++iter_pos) { Cell* current = deps->at(iter_pos); if (UNLIKELY(!c_WaitHandle::fromCell(current))) { Object e(SystemLib::AllocInvalidArgumentExceptionObject( "Expected dependencies to be a vector of WaitHandle instances")); throw e; } } Object exception; for (int64_t iter_pos = 0; iter_pos < deps->size(); ++iter_pos) { auto current = tvAssertCell(deps->at(iter_pos)); assert(current->m_type == KindOfObject); assert(current->m_data.pobj->instanceof(c_WaitHandle::classof())); auto child = static_cast<c_WaitHandle*>(current->m_data.pobj); if (child->isSucceeded()) { auto result = child->getResult(); deps->set(iter_pos, &result); } else if (child->isFailed()) { putException(exception, child->getException()); } else { assert(child->instanceof(c_WaitableWaitHandle::classof())); auto child_wh = static_cast<c_WaitableWaitHandle*>(child); SmartObject<c_GenVectorWaitHandle> my_wh(newobj<c_GenVectorWaitHandle>()); my_wh->initialize(exception, deps.get(), iter_pos, child_wh); AsioSession* session = AsioSession::Get(); if (UNLIKELY(session->hasOnGenVectorCreateCallback())) { session->onGenVectorCreate(my_wh.get(), dependencies); } return my_wh; } } if (exception.isNull()) { return Object::attach(c_StaticWaitHandle::CreateSucceeded( make_tv<KindOfObject>(deps.detach()))); } else { return Object::attach(c_StaticWaitHandle::CreateFailed(exception.detach())); } }
void throwable_init_file_and_line_from_builtin(ObjectData* throwable) { assertx(vmfp_is_builtin()); assertx(is_throwable(throwable)); assertx(throwable_has_expected_props()); assertx(throwable->propVec()[s_fileIdx].m_type == KindOfNull); assertx(throwable->propVec()[s_lineIdx].m_type == KindOfNull); assertx(throwable->propVec()[s_traceIdx].m_type == KindOfArray); auto const trace = throwable->propVec()[s_traceIdx].m_data.parr; for (ArrayIter iter(trace); iter; ++iter) { assertx(iter.second().asTypedValue()->m_type == KindOfArray); auto const frame = iter.second().asTypedValue()->m_data.parr; auto const file = frame->nvGet(s_file.get()); auto const line = frame->nvGet(s_line.get()); if (file || line) { if (file) cellDup(*tvAssertCell(file), throwable->propVec()[s_fileIdx]); if (line) cellDup(*tvAssertCell(line), throwable->propVec()[s_lineIdx]); return; } } }
void c_GenVectorWaitHandle::enterContextImpl(context_idx_t ctx_idx) { assert(getState() == STATE_BLOCKED); // recursively import current child { assert(m_iterPos < m_deps->size()); Cell* current = tvAssertCell(m_deps->at(m_iterPos)); assert(current->m_type == KindOfObject); assert(current->m_data.pobj->instanceof(c_WaitableWaitHandle::classof())); auto child_wh = static_cast<c_WaitableWaitHandle*>(current->m_data.pobj); child_wh->enterContext(ctx_idx); } // import ourselves setContextIdx(ctx_idx); // try to import other children try { for (int64_t iter_pos = m_iterPos + 1; iter_pos < m_deps->size(); ++iter_pos) { Cell* current = tvAssertCell(m_deps->at(iter_pos)); assert(current->m_type == KindOfObject); assert(current->m_data.pobj->instanceof(c_WaitHandle::classof())); auto child = static_cast<c_WaitHandle*>(current->m_data.pobj); if (child->isFinished()) { continue; } assert(child->instanceof(c_WaitableWaitHandle::classof())); auto child_wh = static_cast<c_WaitableWaitHandle*>(child); child_wh->enterContext(ctx_idx); } } catch (const Object& cycle_exception) { // exception will be eventually processed by onUnblocked() } }
Object c_GenVectorWaitHandle::ti_create(CVarRef dependencies) { if (UNLIKELY(!dependencies.instanceof(c_Vector::s_cls))) { Object e(SystemLib::AllocInvalidArgumentExceptionObject( "Expected dependencies to be an instance of Vector")); throw e; } assert(dynamic_cast<c_Vector*>(dependencies.getObjectData())); p_Vector deps = static_cast<c_Vector*>(dependencies.getObjectData())->clone(); for (int64_t iter_pos = 0; iter_pos < deps->size(); ++iter_pos) { Cell* current = deps->at(iter_pos); if (UNLIKELY(!c_WaitHandle::fromCell(current))) { Object e(SystemLib::AllocInvalidArgumentExceptionObject( "Expected dependencies to be a vector of WaitHandle instances")); throw e; } } Object exception; for (int64_t iter_pos = 0; iter_pos < deps->size(); ++iter_pos) { Cell* current = tvAssertCell(deps->at(iter_pos)); assert(current->m_type == KindOfObject); assert(dynamic_cast<c_WaitHandle*>(current->m_data.pobj)); auto child = static_cast<c_WaitHandle*>(current->m_data.pobj); if (child->isSucceeded()) { cellSet(child->getResult(), *current); } else if (child->isFailed()) { putException(exception, child->getException()); } else { assert(dynamic_cast<c_WaitableWaitHandle*>(child)); auto child_wh = static_cast<c_WaitableWaitHandle*>(child); p_GenVectorWaitHandle my_wh = NEWOBJ(c_GenVectorWaitHandle)(); my_wh->initialize(exception, deps.get(), iter_pos, child_wh); AsioSession* session = AsioSession::Get(); if (UNLIKELY(session->hasOnGenVectorCreateCallback())) { session->onGenVectorCreate(my_wh.get(), dependencies); } return my_wh; } } if (exception.isNull()) { return c_StaticResultWaitHandle::Create(make_tv<KindOfObject>(deps.get())); } else { return c_StaticExceptionWaitHandle::Create(exception.get()); } }
Object c_AwaitAllWaitHandle::FromVector(const BaseVector* dependencies) { auto const start = dependencies->data(); auto const stop = start + dependencies->size(); auto ctx_idx = std::numeric_limits<context_idx_t>::max(); int32_t cnt = 0; for (auto iter = start; iter < stop; ++iter) { prepareChild(tvAssertCell(iter), ctx_idx, cnt); } if (!cnt) return returnEmpty(); auto result = Alloc(cnt); auto next = &result->m_children[cnt]; for (auto iter = start; iter < stop; ++iter) { addChild(tvAssertCell(iter), next); } assert(next == &result->m_children[0]); result->initialize(ctx_idx); return Object{std::move(result)}; }
Object c_AwaitAllWaitHandle::FromMap(const BaseMap* dependencies) { auto const start = dependencies->firstElm(); auto const stop = dependencies->elmLimit(); auto ctx_idx = std::numeric_limits<context_idx_t>::max(); int32_t cnt = 0; for (auto iter = start; iter != stop; iter = BaseMap::nextElm(iter, stop)) { prepareChild(tvAssertCell(&iter->data), ctx_idx, cnt); } if (!cnt) return returnEmpty(); auto result = Alloc(cnt); auto next = &result->m_children[cnt]; for (auto iter = start; iter != stop; iter = BaseMap::nextElm(iter, stop)) { addChild(tvAssertCell(&iter->data), next); } assert(next == &result->m_children[0]); result->initialize(ctx_idx); return Object{std::move(result)}; }
void c_GenMapWaitHandle::onUnblocked() { assert(getState() == STATE_BLOCKED); for (; m_deps->iter_valid(m_iterPos); m_iterPos = m_deps->iter_next(m_iterPos)) { auto* current = tvAssertCell(m_deps->iter_value(m_iterPos)); assert(current->m_type == KindOfObject); assert(current->m_data.pobj->instanceof(c_WaitHandle::classof())); auto child = static_cast<c_WaitHandle*>(current->m_data.pobj); if (child->isSucceeded()) { auto k = m_deps->iter_key(m_iterPos); m_deps->set(k.asCell(), &child->getResult()); } else if (child->isFailed()) { putException(m_exception, child->getException()); } else { assert(child->instanceof(c_WaitHandle::classof())); auto child_wh = static_cast<c_WaitableWaitHandle*>(child); try { if (isInContext()) { child_wh->enterContext(getContextIdx()); } detectCycle(child_wh); blockOn(child_wh); return; } catch (const Object& cycle_exception) { putException(m_exception, cycle_exception.get()); } } } auto const parentChain = getFirstParent(); if (m_exception.isNull()) { setState(STATE_SUCCEEDED); tvWriteObject(m_deps.get(), &m_resultOrException); } else { setState(STATE_FAILED); tvWriteObject(m_exception.get(), &m_resultOrException); m_exception = nullptr; } m_deps = nullptr; UnblockChain(parentChain); decRefObj(this); }
void c_GenVectorWaitHandle::onUnblocked() { assert(getState() == STATE_BLOCKED); for (; m_iterPos < m_deps->size(); ++m_iterPos) { Cell* current = tvAssertCell(m_deps->at(m_iterPos)); assert(current->m_type == KindOfObject); assert(current->m_data.pobj->instanceof(c_WaitHandle::classof())); auto child = static_cast<c_WaitHandle*>(current->m_data.pobj); if (child->isSucceeded()) { auto result = child->getResult(); m_deps->set(m_iterPos, &result); } else if (child->isFailed()) { putException(m_exception, child->getException()); } else { assert(child->instanceof(c_WaitableWaitHandle::classof())); auto child_wh = static_cast<c_WaitableWaitHandle*>(child); try { detectCycle(child_wh); child_wh->getParentChain() .addParent(m_blockable, AsioBlockable::Kind::GenVectorWaitHandle); return; } catch (const Object& cycle_exception) { putException(m_exception, cycle_exception.get()); } } } auto parentChain = getParentChain(); if (m_exception.isNull()) { setState(STATE_SUCCEEDED); tvWriteObject(m_deps.get(), &m_resultOrException); } else { setState(STATE_FAILED); tvWriteObject(m_exception.get(), &m_resultOrException); m_exception = nullptr; } m_deps = nullptr; parentChain.unblock(); decRefObj(this); }
void HHVM_FUNCTION(set_frame_metadata, const Variant& metadata) { VMRegAnchor _; auto fp = vmfp(); if (fp && fp->skipFrame()) fp = g_context->getPrevVMState(fp); if (UNLIKELY(!fp)) return; if (LIKELY(!(fp->func()->attrs() & AttrMayUseVV)) || LIKELY(!fp->hasVarEnv())) { auto const local = fp->func()->lookupVarId(s_86metadata.get()); if (LIKELY(local != kInvalidId)) { cellSet(*metadata.asCell(), *tvAssertCell(frame_local(fp, local))); } else { SystemLib::throwInvalidArgumentExceptionObject( "Unsupported dynamic call of set_frame_metadata()"); } } else { fp->getVarEnv()->set(s_86metadata.get(), metadata.asTypedValue()); } }
void c_GenVectorWaitHandle::onUnblocked() { assert(getState() == STATE_BLOCKED); for (; m_iterPos < m_deps->size(); ++m_iterPos) { Cell* current = tvAssertCell(m_deps->at(m_iterPos)); assert(current->m_type == KindOfObject); assert(current->m_data.pobj->instanceof(c_WaitHandle::classof())); auto child = static_cast<c_WaitHandle*>(current->m_data.pobj); if (child->isSucceeded()) { cellSet(child->getResult(), *current); } else if (child->isFailed()) { putException(m_exception, child->getException()); } else { assert(child->instanceof(c_WaitableWaitHandle::classof())); auto child_wh = static_cast<c_WaitableWaitHandle*>(child); try { if (isInContext()) { child_wh->enterContext(getContextIdx()); } detectCycle(child_wh); blockOn(child_wh); return; } catch (const Object& cycle_exception) { putException(m_exception, cycle_exception.get()); } } } if (m_exception.isNull()) { setState(STATE_SUCCEEDED); tvWriteObject(m_deps.get(), &m_resultOrException); } else { setState(STATE_FAILED); tvWriteObject(m_exception.get(), &m_resultOrException); m_exception = nullptr; } m_deps = nullptr; done(); }
c_StaticWaitHandle* AsyncGenerator::yield(Offset resumeOffset, const Cell* key, const Cell value) { assert(isRunning()); resumable()->setResumeAddr(nullptr, resumeOffset); setState(State::Started); auto keyValueTuple = make_packed_array( key ? Variant(tvAsCVarRef(key), Variant::CellCopy()) : init_null_variant, Variant(tvAsCVarRef(&value), Variant::CellCopy())); auto keyValueTupleTV = make_tv<KindOfArray>(keyValueTuple.detach()); if (m_waitHandle) { // Resumed execution. req::ptr<c_AsyncGeneratorWaitHandle> wh(std::move(m_waitHandle)); wh->ret(*tvAssertCell(&keyValueTupleTV)); return nullptr; } // Eager execution. return c_StaticWaitHandle::CreateSucceeded(keyValueTupleTV); }
void c_GenMapWaitHandle::onUnblocked() { for (; m_deps->iter_valid(m_iterPos); m_iterPos = m_deps->iter_next(m_iterPos)) { Cell* current = tvAssertCell(m_deps->iter_value(m_iterPos)); assert(current->m_type == KindOfObject); assert(current->m_data.pobj->instanceof(c_WaitHandle::classof())); auto child = static_cast<c_WaitHandle*>(current->m_data.pobj); if (child->isSucceeded()) { cellSet(child->getResult(), *current); } else if (child->isFailed()) { putException(m_exception, child->getException()); } else { assert(child->instanceof(c_WaitHandle::classof())); auto child_wh = static_cast<c_WaitableWaitHandle*>(child); try { if (isInContext()) { child_wh->enterContext(getContextIdx()); } detectCycle(child_wh); blockOn(child_wh); return; } catch (const Object& cycle_exception) { putException(m_exception, cycle_exception.get()); } } } if (m_exception.isNull()) { setResult(make_tv<KindOfObject>(m_deps.get())); m_deps = nullptr; } else { setException(m_exception.get()); m_exception = nullptr; m_deps = nullptr; } }
Object c_AwaitAllWaitHandle::Create(Iter iter) { auto ctx_idx = std::numeric_limits<context_idx_t>::max(); uint32_t cnt = 0; auto toCell = convert ? [](TypedValue tv) { return tvToCell(tv); } : [](TypedValue tv) { return tvAssertCell(tv); }; iter([&](TypedValue v) { prepareChild(toCell(v), ctx_idx, cnt); }); if (!cnt) { return Object{returnEmpty()}; } auto result = Alloc(cnt); auto next = &result->m_children[cnt]; uint32_t idx = cnt - 1; iter([&](TypedValue v) { addChild(toCell(v), next, idx); }); assert(next == &result->m_children[0]); result->initialize(ctx_idx); return Object{std::move(result)}; }
void c_AsyncFunctionWaitHandle::run() { // may happen if scheduled in multiple contexts if (getState() != STATE_SCHEDULED) { return; } try { setState(STATE_RUNNING); // iterate continuation if (LIKELY(m_child->isSucceeded())) { // child succeeded, pass the result to the continuation m_continuation->call_send(m_child->getResult()); } else if (m_child->isFailed()) { // child failed, raise the exception inside continuation m_continuation->call_raise(m_child->getException()); } else { throw FatalErrorException( "Invariant violation: child neither succeeded nor failed"); } // continuation finished, retrieve result from its m_value if (m_continuation->done()) { markAsSucceeded(*m_continuation->m_value.asCell()); return; } retry: // save child Cell* value = tvAssertCell(m_continuation->m_value.asTypedValue()); assert(dynamic_cast<c_WaitableWaitHandle*>(c_WaitHandle::fromCell(value))); m_child = static_cast<c_WaitableWaitHandle*>(value->m_data.pobj); assert(!m_child->isFinished()); // import child into the current context, detect cross-context cycles try { m_child->enterContext(getContextIdx()); } catch (Object& e) { m_continuation->call_raise(e.get()); goto retry; } // detect cycles if (UNLIKELY(isDescendantOf(m_child.get()))) { Object e(createCycleException(m_child.get())); m_continuation->call_raise(e.get()); goto retry; } // on await callback AsioSession* session = AsioSession::Get(); if (UNLIKELY(session->hasOnAsyncFunctionAwaitCallback())) { session->onAsyncFunctionAwait(this, m_child.get()); } // set up dependency blockOn(m_child.get()); } catch (const Object& exception) { // process exception thrown by the async function markAsFailed(exception); } catch (...) { // process C++ exception markAsFailed(AsioSession::Get()->getAbruptInterruptException()); throw; } }
Object c_GenMapWaitHandle::ti_create(const Variant& dependencies) { ObjectData* obj; if (UNLIKELY(!dependencies.isObject() || !(obj = dependencies.getObjectData())->isCollection() || obj->collectionType() != CollectionType::Map)) { SystemLib::throwInvalidArgumentExceptionObject( "Expected dependencies to be an instance of Map"); } assertx(obj->collectionType() == CollectionType::Map); auto deps = req::ptr<c_Map>::attach(c_Map::Clone(obj)); auto ctx_idx = std::numeric_limits<context_idx_t>::max(); for (ssize_t iter_pos = deps->iter_begin(); deps->iter_valid(iter_pos); iter_pos = deps->iter_next(iter_pos)) { auto* current = tvAssertCell(deps->iter_value(iter_pos)); auto const child = c_WaitHandle::fromCell(current); if (UNLIKELY(!child)) { SystemLib::throwInvalidArgumentExceptionObject( "Expected dependencies to be a map of WaitHandle instances"); } if (!child->isFinished()) { ctx_idx = std::min( ctx_idx, static_cast<c_WaitableWaitHandle*>(child)->getContextIdx() ); } } Object exception; for (ssize_t iter_pos = deps->iter_begin(); deps->iter_valid(iter_pos); iter_pos = deps->iter_next(iter_pos)) { auto* current = tvAssertCell(deps->iter_value(iter_pos)); assert(current->m_type == KindOfObject); assert(current->m_data.pobj->instanceof(c_WaitHandle::classof())); auto child = static_cast<c_WaitHandle*>(current->m_data.pobj); if (child->isSucceeded()) { auto k = deps->iter_key(iter_pos); auto result = child->getResult(); deps->set(k.asCell(), &result); } else if (child->isFailed()) { putException(exception, child->getException()); } else { assert(child->instanceof(c_WaitableWaitHandle::classof())); auto child_wh = static_cast<c_WaitableWaitHandle*>(child); auto my_wh = req::make<c_GenMapWaitHandle>(); my_wh->initialize(exception, deps.get(), iter_pos, ctx_idx, child_wh); AsioSession* session = AsioSession::Get(); if (UNLIKELY(session->hasOnGenMapCreate())) { session->onGenMapCreate(my_wh.get(), dependencies); } return Object(std::move(my_wh)); } } if (exception.isNull()) { return Object::attach(c_StaticWaitHandle::CreateSucceeded( make_tv<KindOfObject>(deps.detach()))); } else { return Object::attach(c_StaticWaitHandle::CreateFailed(exception.detach())); } }