ThenableStatus updateDeferredFromPotentialThenable(ExecState* exec, JSValue x, JSPromiseDeferred* deferred)
{
    // 1. If Type(x) is not Object, return "not a thenable".
    if (!x.isObject())
        return NotAThenable;

    // 2. Let 'then' be the result of calling Get(x, "then").
    JSValue thenValue = x.get(exec, exec->vm().propertyNames->then);

    // 3. If then is an abrupt completion,
    if (exec->hadException()) {
        // i. Let 'rejectResult' be the result of calling the [[Call]] internal method of
        //    deferred.[[Reject]] with undefined as thisArgument and a List containing
        //    then.[[value]] as argumentsList.
        JSValue exception = exec->exception();
        exec->clearException();

        performDeferredReject(exec, deferred, exception);

        // ii. ReturnIfAbrupt(rejectResult).
        // NOTE: Nothing to do.

        // iii. Return.
        return WasAThenable;
    }

    // 4. Let 'then' be then.[[value]].
    // Note: Nothing to do.

    // 5. If IsCallable(then) is false, return "not a thenable".
    CallData thenCallData;
    CallType thenCallType = getCallData(thenValue, thenCallData);
    if (thenCallType == CallTypeNone)
        return NotAThenable;

    // 6. Let 'thenCallResult' be the result of calling the [[Call]] internal method of
    //    'then' passing x as thisArgument and a List containing deferred.[[Resolve]] and
    //    deferred.[[Reject]] as argumentsList.
    MarkedArgumentBuffer thenArguments;
    thenArguments.append(deferred->resolve());
    thenArguments.append(deferred->reject());

    call(exec, thenValue, thenCallType, thenCallData, x, thenArguments);

    // 7. If 'thenCallResult' is an abrupt completion,
    if (exec->hadException()) {
        // i. Let 'rejectResult' be the result of calling the [[Call]] internal method of
        //    deferred.[[Reject]] with undefined as thisArgument and a List containing
        //    thenCallResult.[[value]] as argumentsList.
        JSValue exception = exec->exception();
        exec->clearException();

        performDeferredReject(exec, deferred, exception);

        // ii. ReturnIfAbrupt(rejectResult).
        // NOTE: Nothing to do.
    }

    return WasAThenable;
}
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());
}
JSValue abruptRejection(ExecState* exec, JSPromiseDeferred* deferred)
{
    ASSERT(exec->hadException());
    JSValue argument = exec->exception();
    exec->clearException();

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

    // ii. ReturnIfAbrupt(rejectResult).
    if (exec->hadException())
        return jsUndefined();

    // iii. Return deferred.[[Promise]].
    return deferred->promise();
}