EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncReject(ExecState* exec)
{
    // -- Promise.reject(x) --
    JSValue r = exec->argument(0);

    // 1. Let 'C' be the this value.
    JSValue C = exec->thisValue();

    // 2. Let 'deferred' be the result of calling GetDeferred(C).
    JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C);

    // 3. ReturnIfAbrupt(deferred).
    if (exec->hadException())
        return JSValue::encode(jsUndefined());

    JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue);

    // 4. Let 'rejectResult' be the result of calling the [[Call]] internal method
    //    of deferred.[[Reject]] with undefined as thisArgument and a List containing r
    //    as argumentsList.
    performDeferredReject(exec, deferred, r);

    // 5. ReturnIfAbrupt(resolveResult).
    if (exec->hadException())
        return JSValue::encode(jsUndefined());

    // 6. Return deferred.[[Promise]].
    return JSValue::encode(deferred->promise());
}
EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncAll(ExecState* exec)
{
    // -- Promise.all(iterable) --

    JSValue iterable = exec->argument(0);
    VM& vm = exec->vm();

    // 1. Let 'C' be the this value.
    JSValue C = exec->thisValue();

    // 2. Let 'deferred' be the result of calling GetDeferred(C).
    JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C);

    // 3. ReturnIfAbrupt(deferred).
    if (exec->hadException())
        return JSValue::encode(jsUndefined());

    // NOTE: A non-abrupt completion of createJSPromiseDeferredFromConstructor implies that
    // C and deferredValue are objects.
    JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue);

    // 4. Let 'iterator' be the result of calling GetIterator(iterable).
    JSValue iteratorFunction = iterable.get(exec, vm.propertyNames->iteratorSymbol);
    if (exec->hadException())
        return JSValue::encode(abruptRejection(exec, deferred));

    CallData iteratorFunctionCallData;
    CallType iteratorFunctionCallType = getCallData(iteratorFunction, iteratorFunctionCallData);
    if (iteratorFunctionCallType == CallTypeNone) {
        throwTypeError(exec);
        return JSValue::encode(abruptRejection(exec, deferred));
    }

    ArgList iteratorFunctionArguments;
    JSValue iterator = call(exec, iteratorFunction, iteratorFunctionCallType, iteratorFunctionCallData, iterable, iteratorFunctionArguments);

    // 5. RejectIfAbrupt(iterator, deferred).
    if (exec->hadException())
        return JSValue::encode(abruptRejection(exec, deferred));

    JSValue result = performPromiseAll(exec, iterator, C, deferred);
    if (exec->hadException()) {
        iteratorClose(exec, iterator);
        if (exec->hadException())
            return JSValue::encode(abruptRejection(exec, deferred));
    }
    return JSValue::encode(result);
}
EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncResolve(ExecState* exec)
{
    // -- Promise.resolve(x) --
    JSValue x = exec->argument(0);

    // 1. Let 'C' be the this value.
    JSValue C = exec->thisValue();

    // 2. If IsPromise(x) is true,
    JSPromise* promise = jsDynamicCast<JSPromise*>(x);
    if (promise) {
        // i. Let 'constructor' be the value of x's [[PromiseConstructor]] internal slot.
        JSValue constructor = promise->constructor();
        // ii. If SameValue(constructor, C) is true, return x.
        if (sameValue(exec, constructor, C))
            return JSValue::encode(x);
    }

    // 3. Let 'deferred' be the result of calling GetDeferred(C).
    JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C);

    // 4. ReturnIfAbrupt(deferred).
    if (exec->hadException())
        return JSValue::encode(jsUndefined());

    JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue);

    // 5. Let 'resolveResult' be the result of calling the [[Call]] internal method
    //    of deferred.[[Resolve]] with undefined as thisArgument and a List containing x
    //    as argumentsList.
    performDeferredResolve(exec, deferred, x);

    // 6. ReturnIfAbrupt(resolveResult).
    if (exec->hadException())
        return JSValue::encode(jsUndefined());

    // 7. Return deferred.[[Promise]].
    return JSValue::encode(deferred->promise());
}
static EncodedJSValue JSC_HOST_CALL promiseResolutionHandlerFunction(ExecState* exec)
{
    JSValue x = exec->argument(0);
    VM& vm = exec->vm();
    JSObject* F = exec->callee();

    // 1. Let 'promise' be the value of F's [[Promise]] internal slot
    JSPromise* promise = jsCast<JSPromise*>(F->get(exec, vm.propertyNames->promisePrivateName));

    // 2. Let 'fulfillmentHandler' be the value of F's [[FulfillmentHandler]] internal slot.
    JSValue fulfillmentHandler = F->get(exec, vm.propertyNames->fulfillmentHandlerPrivateName);
    
    // 3. Let 'rejectionHandler' be the value of F's [[RejectionHandler]] internal slot.
    JSValue rejectionHandler = F->get(exec, vm.propertyNames->rejectionHandlerPrivateName);
    
    // 4. If SameValue(x, promise) is true,
    if (sameValue(exec, x, promise)) {
        // i. Let 'selfResolutionError' be a newly-created TypeError object.
        JSObject* selfResolutionError = createTypeError(exec, ASCIILiteral("Resolve a promise with itself"));
        // ii. Return the result of calling the [[Call]] internal method of rejectionHandler with
        //     undefined as thisArgument and a List containing selfResolutionError as argumentsList.
        CallData rejectCallData;
        CallType rejectCallType = getCallData(rejectionHandler, rejectCallData);
        ASSERT(rejectCallType != CallTypeNone);

        MarkedArgumentBuffer rejectArguments;
        rejectArguments.append(selfResolutionError);

        return JSValue::encode(call(exec, rejectionHandler, rejectCallType, rejectCallData, jsUndefined(), rejectArguments));
    }

    // 5. Let 'C' be the value of promise's [[PromiseConstructor]] internal slot.
    JSValue C = promise->constructor();

    // 6. Let 'deferred' be the result of calling GetDeferred(C)
    JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C);

    // 7. ReturnIfAbrupt(deferred).
    if (exec->hadException())
        return JSValue::encode(jsUndefined());

    JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue);

    // 8. Let 'updateResult' be the result of calling UpdateDeferredFromPotentialThenable(x, deferred).
    ThenableStatus updateResult = updateDeferredFromPotentialThenable(exec, x, deferred);

    // 9. ReturnIfAbrupt(updateResult).
    if (exec->hadException())
        return JSValue::encode(jsUndefined());

    // 10. If 'updateResult' is not "not a thenable", return the result of calling
    //     Invoke(deferred.[[Promise]], "then", (fulfillmentHandler, rejectionHandler)).
    // NOTE: Invoke does not seem to be defined anywhere, so I am guessing here.
    if (updateResult != NotAThenable) {
        JSObject* deferredPromise = deferred->promise();
    
        JSValue thenValue = deferredPromise->get(exec, exec->vm().propertyNames->then);
        if (exec->hadException())
            return JSValue::encode(jsUndefined());

        CallData thenCallData;
        CallType thenCallType = getCallData(thenValue, thenCallData);
        if (thenCallType == CallTypeNone)
            return JSValue::encode(throwTypeError(exec));

        MarkedArgumentBuffer arguments;
        arguments.append(fulfillmentHandler);
        arguments.append(rejectionHandler);

        return JSValue::encode(call(exec, thenValue, thenCallType, thenCallData, deferredPromise, arguments));
    }
    
    // 11. Return the result of calling the [[Call]] internal method of fulfillmentHandler
    //     with undefined as thisArgument and a List containing x as argumentsList.
    CallData fulfillmentHandlerCallData;
    CallType fulfillmentHandlerCallType = getCallData(fulfillmentHandler, fulfillmentHandlerCallData);
    ASSERT(fulfillmentHandlerCallType != CallTypeNone);
    
    MarkedArgumentBuffer fulfillmentHandlerArguments;
    fulfillmentHandlerArguments.append(x);

    return JSValue::encode(call(exec, fulfillmentHandler, fulfillmentHandlerCallType, fulfillmentHandlerCallData, jsUndefined(), fulfillmentHandlerArguments));
}