Object c_AwaitAllWaitHandle::createAAWH(T start, T stop, F1 iterNext, F2 getCell) { auto ctx_idx = std::numeric_limits<context_idx_t>::max(); uint32_t cnt = 0; for (auto iter = start; iter != stop; iter = iterNext(iter, stop)) { prepareChild(getCell(iter), ctx_idx, cnt); } if (!cnt) { return Object{returnEmpty()}; } auto result = Alloc(cnt); auto next = &result->m_children[cnt]; uint32_t idx = cnt - 1; for (auto iter = start; iter != stop; iter = iterNext(iter, stop)) { addChild(getCell(iter), next, idx); } assert(next == &result->m_children[0]); result->initialize(ctx_idx); return Object{std::move(result)}; }
Object c_AwaitAllWaitHandle::FromMixedArray(const MixedArray* dependencies) { auto const start = dependencies->data(); auto const stop = start + dependencies->iterLimit(); auto ctx_idx = std::numeric_limits<context_idx_t>::max(); int32_t cnt = 0; for (auto iter = start; iter < stop; ++iter) { if (MixedArray::isTombstone(iter->data.m_type)) continue; prepareChild(tvToCell(&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) { if (MixedArray::isTombstone(iter->data.m_type)) continue; addChild(tvToCell(&iter->data), next); } assert(next == &result->m_children[0]); result->initialize(ctx_idx); return Object{std::move(result)}; }
Object c_AwaitAllWaitHandle::ti_fromarray(const Array& dependencies) { auto ad = dependencies.get(); assert(ad); if (!ad->size()) return returnEmpty(); retry: switch (ad->kind()) { case ArrayData::kPackedKind: return FromPackedArray(ad); case ArrayData::kMixedKind: case ArrayData::kStructKind: return FromMixedArray(MixedArray::asMixed(ad)); case ArrayData::kProxyKind: ad = ProxyArray::innerArr(ad); goto retry; case ArrayData::kApcKind: case ArrayData::kGlobalsKind: // APC can't store WaitHandles, GlobalsArray is used only for // $GLOBALS, which contain non-WaitHandles. failArray(); case ArrayData::kEmptyKind: // Handled by dependencies->size() check. not_reached(); case ArrayData::kNumKinds: not_reached(); } not_reached(); }
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_AwaitAllWaitHandle::FromPackedArray(const ArrayData* dependencies) { auto const start = reinterpret_cast<const TypedValue*>(dependencies + 1); auto const stop = start + dependencies->getSize(); int32_t cnt = 0; for (auto iter = start; iter < stop; ++iter) { auto const current = tvToCell(iter); auto const child = c_WaitHandle::fromCell(current); if (UNLIKELY(!child)) failArray(); 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 = tvToCell(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_AwaitAllWaitHandle::FromMixedArray(const MixedArray* dependencies) { auto const start = dependencies->data(); auto const stop = start + dependencies->iterLimit(); int32_t cnt = 0; for (auto iter = start; iter < stop; ++iter) { if (MixedArray::isTombstone(iter->data.m_type)) continue; auto const current = tvToCell(&iter->data); auto const child = c_WaitHandle::fromCell(current); if (UNLIKELY(!child)) failArray(); 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) { if (MixedArray::isTombstone(iter->data.m_type)) continue; auto const current = tvToCell(&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 HHVM_STATIC_METHOD(AwaitAllWaitHandle, fromDict, const Array& dependencies) { auto ad = dependencies.get(); assertx(ad); assertx(ad->isDict()); if (!ad->size()) return Object{returnEmpty()}; return c_AwaitAllWaitHandle::FromMixedArray(MixedArray::asMixed(ad)); }
Object HHVM_STATIC_METHOD(AwaitAllWaitHandle, fromVec, const Array& dependencies) { auto ad = dependencies.get(); assertx(ad); assertx(ad->isVecArray()); if (!ad->size()) return Object{returnEmpty()}; return c_AwaitAllWaitHandle::FromPackedArray(ad); }
Object HHVM_STATIC_METHOD(AwaitAllWaitHandle, fromDict, const Array& dependencies) { auto ad = dependencies.get(); assertx(ad); assertx(ad->isDict()); if (!ad->size()) return Object{returnEmpty()}; return c_AwaitAllWaitHandle::Create<false>([=](auto fn) { MixedArray::IterateV(MixedArray::asMixed(ad), fn); }); }
Object HHVM_STATIC_METHOD(AwaitAllWaitHandle, fromArray, const Array& dependencies) { auto ad = dependencies.get(); assertx(ad); assertx(ad->isPHPArray()); if (!ad->size()) return Object{returnEmpty()}; retry: switch (ad->kind()) { case ArrayData::kPackedKind: return c_AwaitAllWaitHandle::Create<true>([=](auto fn) { PackedArray::IterateV(ad, fn); }); case ArrayData::kMixedKind: return c_AwaitAllWaitHandle::Create<true>([=](auto fn) { MixedArray::IterateV(MixedArray::asMixed(ad), fn); }); case ArrayData::kProxyKind: ad = ProxyArray::innerArr(ad); goto retry; case ArrayData::kApcKind: case ArrayData::kGlobalsKind: // APC can't store WaitHandles, GlobalsArray is used only for // $GLOBALS, which contain non-WaitHandles. failArray(); case ArrayData::kEmptyKind: // Handled by dependencies->size() check. not_reached(); case ArrayData::kVecKind: case ArrayData::kDictKind: case ArrayData::kKeysetKind: // Shouldn't get Hack arrays not_reached(); case ArrayData::kNumKinds: not_reached(); } not_reached(); }
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)}; }
Object c_AwaitAllWaitHandle::FromPackedArray(const ArrayData* dependencies) { auto const start = reinterpret_cast<const TypedValue*>(dependencies + 1); auto const stop = start + dependencies->getSize(); auto ctx_idx = std::numeric_limits<context_idx_t>::max(); int32_t cnt = 0; for (auto iter = start; iter < stop; ++iter) { prepareChild(tvToCell(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(tvToCell(iter), next); } assert(next == &result->m_children[0]); result->initialize(ctx_idx); return Object{std::move(result)}; }
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)}; }