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();
}
Beispiel #4
0
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));
}
Beispiel #5
0
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));
}
Beispiel #6
0
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));
}
Beispiel #7
0
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)};
}