bool getResult(TLTypePtr output)
 {
     if (isSucceeded()) {
         m_layer->processReply(this, output);
     }
     return isSucceeded() && output->isValid();
 }
Beispiel #2
0
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::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;
  }
}
Object c_GenArrayWaitHandle::ti_create(const char* cls, CArrRef dependencies) {
    Array deps = dependencies->copy();
    for (ssize_t iter_pos = deps->iter_begin();
            iter_pos != ArrayData::invalid_index;
            iter_pos = deps->iter_advance(iter_pos)) {

        TypedValue* current = deps->nvGetValueRef(iter_pos);
        if (UNLIKELY(current->m_type == KindOfRef)) {
            tvUnbox(current);
        }

        if (!c_WaitHandle::fromTypedValue(current) &&
                !IS_NULL_TYPE(current->m_type)) {
            Object e(SystemLib::AllocInvalidArgumentExceptionObject(
                         "Expected dependencies to be an array of WaitHandle instances"));
            throw e;
        }
    }

    Object exception;
    for (ssize_t iter_pos = deps->iter_begin();
            iter_pos != ArrayData::invalid_index;
            iter_pos = deps->iter_advance(iter_pos)) {

        TypedValue* current = deps->nvGetValueRef(iter_pos);
        if (IS_NULL_TYPE(current->m_type)) {
            // {uninit,null} yields null
            tvWriteNull(current);
            continue;
        }

        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()) {
            tvSetIgnoreRef(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);

            c_GenArrayWaitHandle* my_wh = NEWOBJ(c_GenArrayWaitHandle)();
            my_wh->initialize(exception, deps, iter_pos, child_wh);
            return my_wh;
        }
    }

    if (exception.isNull()) {
        TypedValue tv;
        tv.m_type = KindOfArray;
        tv.m_data.parr = deps.get();
        return c_StaticResultWaitHandle::Create(&tv);
    } else {
        return c_StaticExceptionWaitHandle::Create(exception.get());
    }
}
Beispiel #5
0
String c_WaitHandle::t_getname() {
  if (isSucceeded()) {
    return s_result;
  } else if (isFailed()) {
    return s_exception;
  }

  assert(instanceof(c_WaitableWaitHandle::classof()));
  return static_cast<c_WaitableWaitHandle*>(this)->getName();
}
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()));
  }
}
Beispiel #7
0
Variant c_WaitHandle::result() {
  assert(isFinished());

  if (LIKELY(isSucceeded())) {
    // succeeded? return result
    return cellAsCVarRef(getResult());
  } else {
    // failed? throw exception
    throw Object{getException()};
  }
}
Object c_SetResultToRefWaitHandle::ti_create(CObjRef wait_handle, VRefParam ref) {
  TypedValue* var_or_cell = ref->asTypedValue();
  if (wait_handle.isNull()) {
    tvSetNull(*var_or_cell);
    return wait_handle;
  }

  if (!wait_handle.get()->getAttribute(ObjectData::IsWaitHandle)) {
    Object e(SystemLib::AllocInvalidArgumentExceptionObject(
        "Expected wait_handle to be an instance of WaitHandle or null"));
    throw e;
  }

  auto wh = static_cast<c_WaitHandle*>(wait_handle.get());

  // succeeded? set result to ref and give back succeeded wait handle
  if (wh->isSucceeded()) {
    tvSet(wh->getResult(), *var_or_cell);
    return wh;
  }

  // failed? reset ref and give back failed wait handle
  if (wh->isFailed()) {
    tvSetNull(*var_or_cell);
    return wh;
  }

  // it's still running so it must be WaitableWaitHandle
  auto child = static_cast<c_WaitableWaitHandle*>(wh);

  // import child into the current context, detect cross-context cycles
  auto session = AsioSession::Get();
  if (session->isInContext()) {
    child->enterContext(session->getCurrentContextIdx());
  }

  // make sure the reference is properly boxed so that we can store cell pointer
  if (UNLIKELY(var_or_cell->m_type != KindOfRef)) {
    tvBox(var_or_cell);
  }

  p_SetResultToRefWaitHandle my_wh = NEWOBJ(c_SetResultToRefWaitHandle)();
  my_wh->initialize(child, var_or_cell->m_data.pref);

  if (UNLIKELY(session->hasOnSetResultToRefCreateCallback())) {
    session->onSetResultToRefCreate(my_wh.get(), child);
  }

  return my_wh;
}
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());
  }
}
void c_AsyncFunctionWaitHandle::resume() {
  auto const child = m_children[0].getChild();
  assert(getState() == STATE_READY);
  assert(child->isFinished());
  setState(STATE_RUNNING);

  if (LIKELY(child->isSucceeded())) {
    // child succeeded, pass the result to the async function
    g_context->resumeAsyncFunc(resumable(), child, child->getResult());
  } else {
    // child failed, raise the exception inside the async function
    g_context->resumeAsyncFuncThrow(resumable(), child,
                                    child->getException());
  }
}
Beispiel #11
0
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);
}
Beispiel #12
0
Variant c_WaitHandle::t_join() {
  if (!isFinished()) {
    // run the full blown machinery
    assert(instanceof(c_WaitableWaitHandle::classof()));
    static_cast<c_WaitableWaitHandle*>(this)->join();
  }
  assert(isFinished());

  if (LIKELY(isSucceeded())) {
    // succeeded? return result
    return cellAsCVarRef(getResult());
  } else {
    // failed? throw exception
    throw Object{getException()};
  }
}
void c_GenArrayWaitHandle::onUnblocked() {
  for (;
       m_iterPos != ArrayData::invalid_index;
       m_iterPos = m_deps->iter_advance(m_iterPos)) {

    TypedValue* current = m_deps->nvGetValueRef(m_iterPos);
    if (IS_NULL_TYPE(current->m_type)) {
      // {uninit,null} yields null
      tvWriteNull(current);
      continue;
    }

    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()) {
      tvSetIgnoreRef(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()) {
    TypedValue result;
    result.m_type = KindOfArray;
    result.m_data.parr = m_deps.get();
    setResult(&result);
    m_deps = nullptr;
  } else {
    setException(m_exception.get());
    m_exception = nullptr;
    m_deps = nullptr;
  }
}
Beispiel #14
0
Variant c_WaitHandle::t_join() {
  if (!isFinished()) {
    // run the full blown machinery
    assert(dynamic_cast<c_WaitableWaitHandle*>(this));
    static_cast<c_WaitableWaitHandle*>(this)->join();
  }

  assert(isFinished());

  if (LIKELY(isSucceeded())) {
    // succeeded? return result
    return tvAsCVarRef(getResult());
  } else {
    // failed? throw exception
    Object e(getException());
    throw e;
  }
}
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 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();
}
void c_AsyncFunctionWaitHandle::resume() {
  // may happen if scheduled in multiple contexts
  if (getState() != STATE_SCHEDULED) {
    decRefObj(this);
    return;
  }

  auto const child = m_children[0].getChild();
  assert(getState() == STATE_SCHEDULED);
  assert(child->isFinished());
  setState(STATE_RUNNING);

  if (LIKELY(child->isSucceeded())) {
    // child succeeded, pass the result to the async function
    g_context->resumeAsyncFunc(resumable(), child, child->getResult());
  } else {
    // child failed, raise the exception inside the async function
    g_context->resumeAsyncFuncThrow(resumable(), child,
                                    child->getException());
  }
}
Beispiel #18
0
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;
  }
}
Beispiel #19
0
bool c_WaitHandle::t_issucceeded() {
  return isSucceeded();
}
void c_AsyncFunctionWaitHandle::run() {
  // may happen if scheduled in multiple contexts
  if (getState() != STATE_SCHEDULED) {
    return;
  }

  try {
    setState(STATE_RUNNING);

    // resume async function
    if (LIKELY(m_child->isSucceeded())) {
      // child succeeded, pass the result to the async function
      g_context->resumeAsyncFunc(resumable(), m_child, m_child->getResult());
    } else if (m_child->isFailed()) {
      // child failed, raise the exception inside the async function
      g_context->resumeAsyncFuncThrow(resumable(), m_child,
                                      m_child->getException());
    } else {
      throw FatalErrorException(
          "Invariant violation: child neither succeeded nor failed");
    }

  retry:
    // async function reached RetC, which already set m_resultOrException
    if (isSucceeded()) {
      m_child = nullptr;
      markAsSucceeded();
      return;
    }

    // async function reached AsyncSuspend, which already set m_child
    assert(!m_child->isFinished());
    assert(m_child->instanceof(c_WaitableWaitHandle::classof()));

    // import child into the current context, detect cross-context cycles
    try {
      child()->enterContext(getContextIdx());
    } catch (Object& e) {
      g_context->resumeAsyncFuncThrow(resumable(), m_child, e.get());
      goto retry;
    }

    // detect cycles
    if (UNLIKELY(isDescendantOf(child()))) {
      Object e(createCycleException(child()));
      g_context->resumeAsyncFuncThrow(resumable(), m_child, e.get());
      goto retry;
    }

    // on await callback
    AsioSession* session = AsioSession::Get();
    if (UNLIKELY(session->hasOnAsyncFunctionAwaitCallback())) {
      session->onAsyncFunctionAwait(this, m_child);
    }

    // set up dependency
    setState(STATE_BLOCKED);
    blockOn(child());
  } catch (const Object& exception) {
    // process exception thrown by the async function
    m_child = nullptr;
    markAsFailed(exception);
  } catch (...) {
    // process C++ exception
    m_child = nullptr;
    markAsFailed(AsioSession::Get()->getAbruptInterruptException());
    throw;
  }
}
Beispiel #21
0
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()));
  }
}