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::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, 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(); }