void ScriptPromisePropertyBase::resolveOrReject(State targetState)
{
    ASSERT(executionContext());
    ASSERT(m_state == Pending);
    ASSERT(targetState == Resolved || targetState == Rejected);

    m_state = targetState;

    v8::HandleScope handleScope(m_isolate);
    size_t i = 0;
    while (i < m_wrappers.size()) {
        const OwnPtr<ScopedPersistent<v8::Object> >& persistent = m_wrappers[i];
        if (persistent->isEmpty()) {
            // wrapper has died.
            // Since v8 GC can run during the iteration and clear the reference,
            // we can't move this check out of the loop.
            m_wrappers.remove(i);
            continue;
        }
        v8::Local<v8::Object> wrapper = persistent->newLocal(m_isolate);
        ScriptState::Scope scope(ScriptState::from(wrapper->CreationContext()));

        v8::Local<v8::Promise::Resolver> resolver = V8HiddenValue::getHiddenValue(m_isolate, wrapper, resolverName()).As<v8::Promise::Resolver>();

        V8HiddenValue::deleteHiddenValue(m_isolate, wrapper, resolverName());
        resolveOrRejectInternal(resolver);
        ++i;
    }
}
void ScriptPromisePropertyBase::clearWrappers()
{
    v8::HandleScope handleScope(m_isolate);
    for (WeakPersistentSet::iterator i = m_wrappers.begin(); i != m_wrappers.end(); ++i) {
        v8::Local<v8::Object> wrapper = (*i)->newLocal(m_isolate);
        if (!wrapper.IsEmpty()) {
            wrapper->DeleteHiddenValue(resolverName());
            wrapper->DeleteHiddenValue(promiseName());
        }
    }
    m_wrappers.clear();
}
void ScriptPromisePropertyBase::clearWrappers()
{
    checkThis();
    checkWrappers();
    v8::HandleScope handleScope(m_isolate);
    for (WeakPersistentSet::iterator i = m_wrappers.begin(); i != m_wrappers.end(); ++i) {
        v8::Local<v8::Object> wrapper = (*i)->newLocal(m_isolate);
        if (!wrapper.IsEmpty()) {
            ScriptState* scriptState = ScriptState::from(wrapper->CreationContext());
            V8HiddenValue::deleteHiddenValue(scriptState, wrapper, resolverName());
            V8HiddenValue::deleteHiddenValue(scriptState, wrapper, promiseName());
        }
    }
    m_wrappers.clear();
}
ScriptPromise ScriptPromisePropertyBase::promise(DOMWrapperWorld& world)
{
    if (!getExecutionContext())
        return ScriptPromise();

    v8::HandleScope handleScope(m_isolate);
    v8::Local<v8::Context> context = toV8Context(getExecutionContext(), world);
    if (context.IsEmpty())
        return ScriptPromise();
    ScriptState* scriptState = ScriptState::from(context);
    ScriptState::Scope scope(scriptState);

    v8::Local<v8::Object> wrapper = ensureHolderWrapper(scriptState);
    ASSERT(wrapper->CreationContext() == context);

    v8::Local<v8::Value> cachedPromise = V8HiddenValue::getHiddenValue(scriptState, wrapper, promiseName());
    if (!cachedPromise.IsEmpty() && cachedPromise->IsPromise())
        return ScriptPromise(scriptState, cachedPromise);

    // Create and cache the Promise
    v8::Local<v8::Promise::Resolver> resolver;
    if (!v8::Promise::Resolver::New(context).ToLocal(&resolver))
        return ScriptPromise();
    v8::Local<v8::Promise> promise = resolver->GetPromise();
    V8HiddenValue::setHiddenValue(scriptState, wrapper, promiseName(), promise);

    switch (m_state) {
    case Pending:
        // Cache the resolver too
        V8HiddenValue::setHiddenValue(scriptState, wrapper, resolverName(), resolver);
        break;
    case Resolved:
    case Rejected:
        resolveOrRejectInternal(resolver);
        break;
    }

    return ScriptPromise(scriptState, promise);
}