diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-04-10 09:28:39 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-04-10 09:28:39 +0000 |
commit | 32761a6cee1d0dee366b885b7b9c777e67885688 (patch) | |
tree | d6bec92bebfb216f4126356e55518842c2f476a1 /Source/JavaScriptCore/runtime/JSPromiseConstructor.cpp | |
parent | a4e969f4965059196ca948db781e52f7cfebf19e (diff) | |
download | WebKitGtk-tarball-32761a6cee1d0dee366b885b7b9c777e67885688.tar.gz |
webkitgtk-2.4.11webkitgtk-2.4.11
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSPromiseConstructor.cpp')
-rw-r--r-- | Source/JavaScriptCore/runtime/JSPromiseConstructor.cpp | 501 |
1 files changed, 459 insertions, 42 deletions
diff --git a/Source/JavaScriptCore/runtime/JSPromiseConstructor.cpp b/Source/JavaScriptCore/runtime/JSPromiseConstructor.cpp index 354c7de8b..402619633 100644 --- a/Source/JavaScriptCore/runtime/JSPromiseConstructor.cpp +++ b/Source/JavaScriptCore/runtime/JSPromiseConstructor.cpp @@ -26,16 +26,14 @@ #include "config.h" #include "JSPromiseConstructor.h" -#include "BuiltinNames.h" +#if ENABLE(PROMISES) + #include "Error.h" -#include "Exception.h" -#include "GetterSetter.h" -#include "IteratorOperations.h" -#include "JSCBuiltins.h" #include "JSCJSValueInlines.h" #include "JSCellInlines.h" -#include "JSFunction.h" #include "JSPromise.h" +#include "JSPromiseDeferred.h" +#include "JSPromiseFunctions.h" #include "JSPromisePrototype.h" #include "Lookup.h" #include "NumberObject.h" @@ -45,28 +43,33 @@ namespace JSC { STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSPromiseConstructor); +static EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncCast(ExecState*); +static EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncResolve(ExecState*); +static EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncReject(ExecState*); +static EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncRace(ExecState*); +static EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncAll(ExecState*); } #include "JSPromiseConstructor.lut.h" namespace JSC { -const ClassInfo JSPromiseConstructor::s_info = { "Function", &Base::s_info, &promiseConstructorTable, CREATE_METHOD_TABLE(JSPromiseConstructor) }; +const ClassInfo JSPromiseConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::promiseConstructorTable, CREATE_METHOD_TABLE(JSPromiseConstructor) }; /* Source for JSPromiseConstructor.lut.h @begin promiseConstructorTable - resolve JSBuiltin DontEnum|Function 1 - reject JSBuiltin DontEnum|Function 1 - race JSBuiltin DontEnum|Function 1 - all JSBuiltin DontEnum|Function 1 + cast JSPromiseConstructorFuncCast DontEnum|Function 1 + resolve JSPromiseConstructorFuncResolve DontEnum|Function 1 + reject JSPromiseConstructorFuncReject DontEnum|Function 1 + race JSPromiseConstructorFuncRace DontEnum|Function 1 + all JSPromiseConstructorFuncAll DontEnum|Function 1 @end */ -JSPromiseConstructor* JSPromiseConstructor::create(VM& vm, Structure* structure, JSPromisePrototype* promisePrototype, GetterSetter* speciesSymbol) +JSPromiseConstructor* JSPromiseConstructor::create(VM& vm, Structure* structure, JSPromisePrototype* promisePrototype) { JSPromiseConstructor* constructor = new (NotNull, allocateCell<JSPromiseConstructor>(vm.heap)) JSPromiseConstructor(vm, structure); - constructor->finishCreation(vm, promisePrototype, speciesSymbol); - constructor->addOwnInternalSlots(vm, structure->globalObject()); + constructor->finishCreation(vm, promisePrototype); return constructor; } @@ -76,43 +79,72 @@ Structure* JSPromiseConstructor::createStructure(VM& vm, JSGlobalObject* globalO } JSPromiseConstructor::JSPromiseConstructor(VM& vm, Structure* structure) - : Base(vm, structure) + : InternalFunction(vm, structure) { } -void JSPromiseConstructor::finishCreation(VM& vm, JSPromisePrototype* promisePrototype, GetterSetter* speciesSymbol) +void JSPromiseConstructor::finishCreation(VM& vm, JSPromisePrototype* promisePrototype) { - Base::finishCreation(vm, ASCIILiteral("Promise")); + Base::finishCreation(vm, "Promise"); putDirectWithoutTransition(vm, vm.propertyNames->prototype, promisePrototype, DontEnum | DontDelete | ReadOnly); putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), ReadOnly | DontEnum | DontDelete); - putDirectNonIndexAccessor(vm, vm.propertyNames->speciesSymbol, speciesSymbol, Accessor | ReadOnly | DontEnum); -} - -void JSPromiseConstructor::addOwnInternalSlots(VM& vm, JSGlobalObject* globalObject) -{ - JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().resolvePrivateName(), promiseConstructorResolveCodeGenerator, DontEnum | DontDelete | ReadOnly); - JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().rejectPrivateName(), promiseConstructorRejectCodeGenerator, DontEnum | DontDelete | ReadOnly); } static EncodedJSValue JSC_HOST_CALL constructPromise(ExecState* exec) { - JSGlobalObject* globalObject = exec->callee()->globalObject(); + // NOTE: We ignore steps 1-4 as they only matter if you support subclassing, which we do not yet. + // 1. Let promise be the this value. + // 2. If Type(promise) is not Object, then throw a TypeError exception. + // 3. If promise does not have a [[PromiseStatus]] internal slot, then throw a TypeError exception. + // 4. If promise's [[PromiseStatus]] internal slot is not undefined, then throw a TypeError exception. + + JSValue resolver = exec->argument(0); + + // 5. IsCallable(resolver) is false, then throw a TypeError exception + CallData callData; + CallType callType = getCallData(resolver, callData); + if (callType == CallTypeNone) + return JSValue::encode(throwTypeError(exec, ASCIILiteral("Promise constructor takes a function argument"))); + VM& vm = exec->vm(); + JSGlobalObject* globalObject = exec->callee()->globalObject(); - JSValue newTarget = exec->newTarget(); - if (newTarget.isUndefined()) - return throwVMTypeError(exec); + JSPromise* promise = JSPromise::create(vm, globalObject, jsCast<JSPromiseConstructor*>(exec->callee())); - Structure* promiseStructure = InternalFunction::createSubclassStructure(exec, exec->newTarget(), globalObject->promiseStructure()); - JSPromise* promise = JSPromise::create(vm, promiseStructure); - promise->initialize(exec, globalObject, exec->argument(0)); + // NOTE: Steps 6-8 are handled by JSPromise::create(). + // 6. Set promise's [[PromiseStatus]] internal slot to "unresolved". + // 7. Set promise's [[ResolveReactions]] internal slot to a new empty List. + // 8. Set promise's [[RejectReactions]] internal slot to a new empty List. + + // 9. Let 'resolve' be a new built-in function object as defined in Resolve Promise Functions. + JSFunction* resolve = createResolvePromiseFunction(vm, globalObject); - return JSValue::encode(promise); -} + // 10. Set the [[Promise]] internal slot of 'resolve' to 'promise'. + resolve->putDirect(vm, vm.propertyNames->promisePrivateName, promise); + + // 11. Let 'reject' be a new built-in function object as defined in Reject Promise Functions + JSFunction* reject = createRejectPromiseFunction(vm, globalObject); -static EncodedJSValue JSC_HOST_CALL callPromise(ExecState* exec) -{ - return JSValue::encode(throwConstructorCannotBeCalledAsFunctionTypeError(exec, "Promise")); + // 12. Set the [[Promise]] internal slot of 'reject' to 'promise'. + reject->putDirect(vm, vm.propertyNames->promisePrivateName, promise); + + // 13. Let 'result' be the result of calling the [[Call]] internal method of resolver with + // undefined as thisArgument and a List containing resolve and reject as argumentsList. + MarkedArgumentBuffer arguments; + arguments.append(resolve); + arguments.append(reject); + call(exec, resolver, callType, callData, jsUndefined(), arguments); + + // 14. If result is an abrupt completion, call PromiseReject(promise, result.[[value]]). + if (exec->hadException()) { + JSValue exception = exec->exception(); + exec->clearException(); + + promise->reject(vm, exception); + } + + // 15. Return promise. + return JSValue::encode(promise); } ConstructType JSPromiseConstructor::getConstructData(JSCell*, ConstructData& constructData) @@ -123,17 +155,402 @@ ConstructType JSPromiseConstructor::getConstructData(JSCell*, ConstructData& con CallType JSPromiseConstructor::getCallData(JSCell*, CallData& callData) { - // FIXME: This is workaround. Since JSC does not expose @isConstructor to JS builtins, - // we use typeof function === "function" now. And since typeof constructorWithoutCallability - // returns "object", we need to define [[Call]] for now. - // https://bugs.webkit.org/show_bug.cgi?id=144093 - callData.native.function = callPromise; + callData.native.function = constructPromise; return CallTypeHost; } bool JSPromiseConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { - return getStaticFunctionSlot<Base>(exec, promiseConstructorTable, jsCast<JSPromiseConstructor*>(object), propertyName, slot); + return getStaticFunctionSlot<InternalFunction>(exec, ExecState::promiseConstructorTable(exec->vm()), jsCast<JSPromiseConstructor*>(object), propertyName, slot); +} + +EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncCast(ExecState* exec) +{ + // -- Promise.cast(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()); +} + +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. 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 '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); + + // 5. ReturnIfAbrupt(resolveResult). + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + + // 6. Return deferred.[[Promise]]. + return JSValue::encode(deferred->promise()); +} + +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 JSPromiseConstructorFuncRace(ExecState* exec) +{ + // -- Promise.race(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()); + + JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue); + + // 4. Let 'iterator' be the result of calling GetIterator(iterable). + JSValue iteratorFunction = iterable.get(exec, vm.propertyNames->iteratorPrivateName); + 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)); + + // 6. Repeat + do { + // i. Let 'next' be the result of calling IteratorStep(iterator). + JSValue nextFunction = iterator.get(exec, exec->vm().propertyNames->iteratorNextPrivateName); + if (exec->hadException()) + return JSValue::encode(abruptRejection(exec, deferred)); + + CallData nextFunctionCallData; + CallType nextFunctionCallType = getCallData(nextFunction, nextFunctionCallData); + if (nextFunctionCallType == CallTypeNone) { + throwTypeError(exec); + return JSValue::encode(abruptRejection(exec, deferred)); + } + + MarkedArgumentBuffer nextFunctionArguments; + nextFunctionArguments.append(jsUndefined()); + JSValue next = call(exec, nextFunction, nextFunctionCallType, nextFunctionCallData, iterator, nextFunctionArguments); + + // ii. RejectIfAbrupt(next, deferred). + if (exec->hadException()) + return JSValue::encode(abruptRejection(exec, deferred)); + + // iii. If 'next' is false, return deferred.[[Promise]]. + // Note: We implement this as an iterationTerminator + if (next == vm.iterationTerminator.get()) + return JSValue::encode(deferred->promise()); + + // iv. Let 'nextValue' be the result of calling IteratorValue(next). + // v. RejectIfAbrupt(nextValue, deferred). + // Note: 'next' is already the value, so there is nothing to do here. + + // vi. Let 'nextPromise' be the result of calling Invoke(C, "cast", (nextValue)). + JSValue castFunction = C.get(exec, vm.propertyNames->cast); + if (exec->hadException()) + return JSValue::encode(abruptRejection(exec, deferred)); + + CallData castFunctionCallData; + CallType castFunctionCallType = getCallData(castFunction, castFunctionCallData); + if (castFunctionCallType == CallTypeNone) { + throwTypeError(exec); + return JSValue::encode(abruptRejection(exec, deferred)); + } + + MarkedArgumentBuffer castFunctionArguments; + castFunctionArguments.append(next); + JSValue nextPromise = call(exec, castFunction, castFunctionCallType, castFunctionCallData, C, castFunctionArguments); + + // vii. RejectIfAbrupt(nextPromise, deferred). + if (exec->hadException()) + return JSValue::encode(abruptRejection(exec, deferred)); + + // viii. Let 'result' be the result of calling Invoke(nextPromise, "then", (deferred.[[Resolve]], deferred.[[Reject]])). + JSValue thenFunction = nextPromise.get(exec, vm.propertyNames->then); + if (exec->hadException()) + return JSValue::encode(abruptRejection(exec, deferred)); + + CallData thenFunctionCallData; + CallType thenFunctionCallType = getCallData(thenFunction, thenFunctionCallData); + if (thenFunctionCallType == CallTypeNone) { + throwTypeError(exec); + return JSValue::encode(abruptRejection(exec, deferred)); + } + + MarkedArgumentBuffer thenFunctionArguments; + thenFunctionArguments.append(deferred->resolve()); + thenFunctionArguments.append(deferred->reject()); + + call(exec, thenFunction, thenFunctionCallType, thenFunctionCallData, nextPromise, thenFunctionArguments); + + // ix. RejectIfAbrupt(result, deferred). + if (exec->hadException()) + return JSValue::encode(abruptRejection(exec, deferred)); + } while (true); +} + +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. + JSObject* thisObject = asObject(C); + JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue); + + // 4. Let 'iterator' be the result of calling GetIterator(iterable). + JSValue iteratorFunction = iterable.get(exec, vm.propertyNames->iteratorPrivateName); + 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)); + + // 6. Let 'values' be the result of calling ArrayCreate(0). + JSArray* values = constructEmptyArray(exec, nullptr, thisObject->globalObject()); + + // 7. Let 'countdownHolder' be Record { [[Countdown]]: 0 }. + NumberObject* countdownHolder = constructNumber(exec, thisObject->globalObject(), JSValue(0)); + + // 8. Let 'index' be 0. + unsigned index = 0; + + // 9. Repeat. + do { + // i. Let 'next' be the result of calling IteratorStep(iterator). + JSValue nextFunction = iterator.get(exec, exec->vm().propertyNames->iteratorNextPrivateName); + if (exec->hadException()) + return JSValue::encode(abruptRejection(exec, deferred)); + + CallData nextFunctionCallData; + CallType nextFunctionCallType = getCallData(nextFunction, nextFunctionCallData); + if (nextFunctionCallType == CallTypeNone) { + throwTypeError(exec); + return JSValue::encode(abruptRejection(exec, deferred)); + } + + MarkedArgumentBuffer nextFunctionArguments; + nextFunctionArguments.append(jsUndefined()); + JSValue next = call(exec, nextFunction, nextFunctionCallType, nextFunctionCallData, iterator, nextFunctionArguments); + + // ii. RejectIfAbrupt(next, deferred). + if (exec->hadException()) + return JSValue::encode(abruptRejection(exec, deferred)); + + // iii. If 'next' is false, + // Note: We implement this as an iterationTerminator + if (next == vm.iterationTerminator.get()) { + // a. If 'index' is 0, + if (!index) { + // a. Let 'resolveResult' be the result of calling the [[Call]] internal method + // of deferred.[[Resolve]] with undefined as thisArgument and a List containing + // values as argumentsList. + performDeferredResolve(exec, deferred, values); + + // b. ReturnIfAbrupt(resolveResult). + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + } + + // b. Return deferred.[[Promise]]. + return JSValue::encode(deferred->promise()); + } + + // iv. Let 'nextValue' be the result of calling IteratorValue(next). + // v. RejectIfAbrupt(nextValue, deferred). + // Note: 'next' is already the value, so there is nothing to do here. + + // vi. Let 'nextPromise' be the result of calling Invoke(C, "cast", (nextValue)). + JSValue castFunction = C.get(exec, vm.propertyNames->cast); + if (exec->hadException()) + return JSValue::encode(abruptRejection(exec, deferred)); + + CallData castFunctionCallData; + CallType castFunctionCallType = getCallData(castFunction, castFunctionCallData); + if (castFunctionCallType == CallTypeNone) { + throwTypeError(exec); + return JSValue::encode(abruptRejection(exec, deferred)); + } + + MarkedArgumentBuffer castFunctionArguments; + castFunctionArguments.append(next); + JSValue nextPromise = call(exec, castFunction, castFunctionCallType, castFunctionCallData, C, castFunctionArguments); + + // vii. RejectIfAbrupt(nextPromise, deferred). + if (exec->hadException()) + return JSValue::encode(abruptRejection(exec, deferred)); + + // viii. Let 'countdownFunction' be a new built-in function object as defined in Promise.all Countdown Functions. + JSFunction* countdownFunction = createPromiseAllCountdownFunction(vm, thisObject->globalObject()); + + // ix. Set the [[Index]] internal slot of 'countdownFunction' to 'index'. + countdownFunction->putDirect(vm, vm.propertyNames->indexPrivateName, JSValue(index)); + + // x. Set the [[Values]] internal slot of 'countdownFunction' to 'values'. + countdownFunction->putDirect(vm, vm.propertyNames->valuesPrivateName, values); + + // xi. Set the [[Deferred]] internal slot of 'countdownFunction' to 'deferred'. + countdownFunction->putDirect(vm, vm.propertyNames->deferredPrivateName, deferred); + + // xii. Set the [[CountdownHolder]] internal slot of 'countdownFunction' to 'countdownHolder'. + countdownFunction->putDirect(vm, vm.propertyNames->countdownHolderPrivateName, countdownHolder); + + // xiii. Let 'result' be the result of calling Invoke(nextPromise, "then", (countdownFunction, deferred.[[Reject]])). + JSValue thenFunction = nextPromise.get(exec, vm.propertyNames->then); + if (exec->hadException()) + return JSValue::encode(abruptRejection(exec, deferred)); + + CallData thenFunctionCallData; + CallType thenFunctionCallType = getCallData(thenFunction, thenFunctionCallData); + if (thenFunctionCallType == CallTypeNone) { + throwTypeError(exec); + return JSValue::encode(abruptRejection(exec, deferred)); + } + + MarkedArgumentBuffer thenFunctionArguments; + thenFunctionArguments.append(countdownFunction); + thenFunctionArguments.append(deferred->reject()); + + call(exec, thenFunction, thenFunctionCallType, thenFunctionCallData, nextPromise, thenFunctionArguments); + + // xiv. RejectIfAbrupt(result, deferred). + if (exec->hadException()) + return JSValue::encode(abruptRejection(exec, deferred)); + + // xv. Set index to index + 1. + index++; + + // xvi. Set countdownHolder.[[Countdown]] to countdownHolder.[[Countdown]] + 1. + uint32_t newCountdownValue = countdownHolder->internalValue().asUInt32() + 1; + countdownHolder->setInternalValue(vm, JSValue(newCountdownValue)); + } while (true); +} + +JSPromise* constructPromise(ExecState* exec, JSGlobalObject* globalObject, JSFunction* resolver) +{ + JSPromiseConstructor* promiseConstructor = globalObject->promiseConstructor(); + + ConstructData constructData; + ConstructType constructType = getConstructData(promiseConstructor, constructData); + ASSERT(constructType != ConstructTypeNone); + + MarkedArgumentBuffer arguments; + arguments.append(resolver); + + return jsCast<JSPromise*>(construct(exec, promiseConstructor, constructType, constructData, arguments)); } } // namespace JSC + +#endif // ENABLE(PROMISES) |