Commit 7817ee1e authored by weinig@apple.com's avatar weinig@apple.com

[JS] Implement Promise.all()

https://bugs.webkit.org/show_bug.cgi?id=126510

Reviewed by Gavin Barraclough.

Source/JavaScriptCore: 

Add Promise.all() implementation and factor out performing resolves and rejects
on deferreds to share a bit of code. Also moves the abruptRejection helper to
JSPromiseDeferred so it can be used in JSPromiseFunctions.

* runtime/CommonIdentifiers.h:
* runtime/JSPromiseConstructor.cpp:
(JSC::JSPromiseConstructorFuncCast):
(JSC::JSPromiseConstructorFuncResolve):
(JSC::JSPromiseConstructorFuncReject):
(JSC::JSPromiseConstructorFuncAll):
* runtime/JSPromiseDeferred.cpp:
(JSC::updateDeferredFromPotentialThenable):
(JSC::performDeferredResolve):
(JSC::performDeferredReject):
(JSC::abruptRejection):
* runtime/JSPromiseDeferred.h:
* runtime/JSPromiseFunctions.cpp:
(JSC::promiseAllCountdownFunction):
(JSC::createPromiseAllCountdownFunction):
* runtime/JSPromiseFunctions.h:
* runtime/JSPromiseReaction.cpp:
(JSC::ExecutePromiseReactionMicrotask::run):

LayoutTests: 

Enabled and fix the existing Promise.all() test case.
- Promise.all() and Promise.all({}) should reject by my reading of the spec.
Also removes the Promise.all() shim used by the crypto tests.

* crypto/subtle/resources/common.js:
* js/dom/Promise-static-all-expected.txt:
* js/dom/Promise-static-all.html:


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@161365 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent ba83364c
2014-01-05 Sam Weinig <sam@webkit.org>
[JS] Implement Promise.all()
https://bugs.webkit.org/show_bug.cgi?id=126510
Reviewed by Gavin Barraclough.
Enabled and fix the existing Promise.all() test case.
- Promise.all() and Promise.all({}) should reject by my reading of the spec.
Also removes the Promise.all() shim used by the crypto tests.
* crypto/subtle/resources/common.js:
* js/dom/Promise-static-all-expected.txt:
* js/dom/Promise-static-all.html:
2014-01-06 Zan Dobersek <zdobersek@igalia.com>
Unreviewed GTK gardening.
......@@ -101,24 +101,5 @@ var Base64URL = {
}
};
if (!Promise.all) {
// A very simple temporary implementation only for WebCrypto tests.
Promise.all = function(promises) {
var results = [];
var resultCount = 0;
var resolver;
var rejector;
function next(result) {
results[resultCount++] = result;
if (resultCount < promises.length)
promises[resultCount].then(next);
else
resolver(results);
}
promises[0].then(next, function() { rejector(null) });
return new Promise(function(resolve, reject) { resolver = resolve; rejector = reject; });
}
}
if (!crypto.subtle)
crypto.subtle = crypto.webkitSubtle;
......@@ -2,6 +2,28 @@ Test Promise.all
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS result is undefined
PASS Promise.all() is rejected.
PASS Promise.all([p1, p2, p3]) is fulfilled.
PASS result.length is 3
PASS result[0] is "p1"
PASS result[1] is "p2"
PASS result[2] is "p3"
PASS Promise.all([p1, p6, p5]) is rejected.
PASS result is "p6"
PASS Promise.all([p9]) is fulfilled.
PASS result.length is 1
PASS result[0] is "p2"
PASS Promise.all([p9,,,]) is fulfilled.
PASS result.length is 3
PASS result[0] is "p2"
PASS result[1] is undefined
PASS result[2] is undefined
PASS Promise.all([p9,42]) is fulfilled.
PASS result.length is 2
PASS result[0] is "p2"
PASS result[1] is 42
PASS Promise.all({}) is rejected.
PASS successfullyParsed is true
TEST COMPLETE
......
......@@ -9,7 +9,6 @@
<script>
description('Test Promise.all');
/*
window.jsTestIsAsync = true;
result = undefined;
......@@ -30,11 +29,9 @@ Promise.all([p1, p2, p5]).then(function(result) {
});
Promise.all().then(function(result) {
testPassed('Promise.all() is fulfilled.');
window.result = result;
shouldBe('result.length', '0');
testFailed('Promise.all() is fulfilled.');
}, function() {
testFailed('Promise.all() is rejected.');
testPassed('Promise.all() is rejected.');
}).then(function() {
return Promise.all([p1, p2, p3]).then(function(result) {
testPassed('Promise.all([p1, p2, p3]) is fulfilled.');
......@@ -90,16 +87,13 @@ Promise.all().then(function(result) {
}).then(function() {
// Not iterable object case.
return Promise.all({}).then(function(result) {
testPassed('Promise.all({}) is fulfilled.');
window.result = result;
shouldBe('result.length', '0');
testFailed('Promise.all({}) is fulfilled.');
}, function(result) {
testFailed('Promise.all({}) is rejected.');
testPassed('Promise.all({}) is rejected.');
});
}).then(finishJSTest, finishJSTest);
shouldBe('result', 'undefined');
*/
</script>
<script src="../../resources/js-test-post.js"></script>
......
2014-01-05 Sam Weinig <sam@webkit.org>
[JS] Implement Promise.all()
https://bugs.webkit.org/show_bug.cgi?id=126510
Reviewed by Gavin Barraclough.
Add Promise.all() implementation and factor out performing resolves and rejects
on deferreds to share a bit of code. Also moves the abruptRejection helper to
JSPromiseDeferred so it can be used in JSPromiseFunctions.
* runtime/CommonIdentifiers.h:
* runtime/JSPromiseConstructor.cpp:
(JSC::JSPromiseConstructorFuncCast):
(JSC::JSPromiseConstructorFuncResolve):
(JSC::JSPromiseConstructorFuncReject):
(JSC::JSPromiseConstructorFuncAll):
* runtime/JSPromiseDeferred.cpp:
(JSC::updateDeferredFromPotentialThenable):
(JSC::performDeferredResolve):
(JSC::performDeferredReject):
(JSC::abruptRejection):
* runtime/JSPromiseDeferred.h:
* runtime/JSPromiseFunctions.cpp:
(JSC::promiseAllCountdownFunction):
(JSC::createPromiseAllCountdownFunction):
* runtime/JSPromiseFunctions.h:
* runtime/JSPromiseReaction.cpp:
(JSC::ExecutePromiseReactionMicrotask::run):
2014-01-06 Filip Pizlo <fpizlo@apple.com>
Get rid of ENABLE(VALUE_PROFILER). It's on all the time now.
......
......@@ -212,7 +212,11 @@
macro(reject) \
macro(promise) \
macro(fulfillmentHandler) \
macro(rejectionHandler)
macro(rejectionHandler) \
macro(index) \
macro(values) \
macro(deferred) \
macro(countdownHolder)
namespace JSC {
......
......@@ -36,6 +36,7 @@
#include "JSPromiseFunctions.h"
#include "JSPromisePrototype.h"
#include "Lookup.h"
#include "NumberObject.h"
#include "StructureInlines.h"
namespace JSC {
......@@ -46,6 +47,7 @@ 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"
......@@ -60,6 +62,7 @@ const ClassInfo JSPromiseConstructor::s_info = { "Function", &InternalFunction::
resolve JSPromiseConstructorFuncResolve DontEnum|Function 1
reject JSPromiseConstructorFuncReject DontEnum|Function 1
race JSPromiseConstructorFuncRace DontEnum|Function 1
all JSPromiseConstructorFuncAll DontEnum|Function 1
@end
*/
......@@ -191,17 +194,7 @@ EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncCast(ExecState* exec)
// 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.
JSValue deferredResolve = deferred->resolve();
CallData resolveCallData;
CallType resolveCallType = getCallData(deferredResolve, resolveCallData);
ASSERT(resolveCallType != CallTypeNone);
MarkedArgumentBuffer arguments;
arguments.append(x);
call(exec, deferredResolve, resolveCallType, resolveCallData, jsUndefined(), arguments);
performDeferredResolve(exec, deferred, x);
// 6. ReturnIfAbrupt(resolveResult).
if (exec->hadException())
......@@ -231,17 +224,7 @@ EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncResolve(ExecState* exec)
// 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.
JSValue deferredResolve = deferred->resolve();
CallData resolveCallData;
CallType resolveCallType = getCallData(deferredResolve, resolveCallData);
ASSERT(resolveCallType != CallTypeNone);
MarkedArgumentBuffer arguments;
arguments.append(x);
call(exec, deferredResolve, resolveCallType, resolveCallData, jsUndefined(), arguments);
performDeferredResolve(exec, deferred, x);
// 5. ReturnIfAbrupt(resolveResult).
if (exec->hadException())
......@@ -271,17 +254,7 @@ EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncReject(ExecState* exec)
// 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.
JSValue deferredReject = deferred->reject();
CallData rejectCallData;
CallType rejectCallType = getCallData(deferredReject, rejectCallData);
ASSERT(rejectCallType != CallTypeNone);
MarkedArgumentBuffer arguments;
arguments.append(r);
call(exec, deferredReject, rejectCallType, rejectCallData, jsUndefined(), arguments);
performDeferredReject(exec, deferred, r);
// 5. ReturnIfAbrupt(resolveResult).
if (exec->hadException())
......@@ -291,37 +264,122 @@ EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncReject(ExecState* exec)
return JSValue::encode(deferred->promise());
}
static JSValue abruptRejection(ExecState* exec, JSPromiseDeferred* deferred)
EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncRace(ExecState* exec)
{
ASSERT(exec->hadException());
JSValue argument = exec->exception();
exec->clearException();
// -- Promise.race(iterable) --
JSValue iterable = exec->argument(0);
VM& vm = exec->vm();
// 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.
JSValue deferredReject = deferred->reject();
// 1. Let 'C' be the this value.
JSValue C = exec->thisValue();
CallData rejectCallData;
CallType rejectCallType = getCallData(deferredReject, rejectCallData);
ASSERT(rejectCallType != CallTypeNone);
// 2. Let 'deferred' be the result of calling GetDeferred(C).
JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C);
MarkedArgumentBuffer arguments;
arguments.append(argument);
// 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));
}
call(exec, deferredReject, rejectCallType, rejectCallData, jsUndefined(), arguments);
ArgList iteratorFunctionArguments;
JSValue iterator = call(exec, iteratorFunction, iteratorFunctionCallType, iteratorFunctionCallData, iterable, iteratorFunctionArguments);
// ii. ReturnIfAbrupt(rejectResult).
// 5. RejectIfAbrupt(iterator, deferred).
if (exec->hadException())
return jsUndefined();
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);
// iii. Return deferred.[[Promise]].
return deferred->promise();
// ix. RejectIfAbrupt(result, deferred).
if (exec->hadException())
return JSValue::encode(abruptRejection(exec, deferred));
} while (true);
}
EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncRace(ExecState* exec)
EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncAll(ExecState* exec)
{
// -- Promise.race(iterable) --
// -- Promise.all(iterable) --
JSValue iterable = exec->argument(0);
VM& vm = exec->vm();
......@@ -335,6 +393,9 @@ EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncRace(ExecState* exec)
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).
......@@ -356,7 +417,16 @@ EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncRace(ExecState* exec)
if (exec->hadException())
return JSValue::encode(abruptRejection(exec, deferred));
// 6. Repeat
// 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);
......@@ -377,11 +447,25 @@ EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncRace(ExecState* exec)
// ii. RejectIfAbrupt(next, deferred).
if (exec->hadException())
return JSValue::encode(abruptRejection(exec, deferred));
// iii. If 'next' is false, return deferred.[[Promise]].
// iii. If 'next' is false,
// Note: We implement this as an iterationTerminator
if (next == vm.iterationTerminator.get())
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).
......@@ -407,7 +491,22 @@ EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncRace(ExecState* exec)
if (exec->hadException())
return JSValue::encode(abruptRejection(exec, deferred));
// viii. Let 'result' be the result of calling Invoke(nextPromise, "then", (deferred.[[Resolve]], deferred.[[Reject]])).
// 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));
......@@ -420,14 +519,21 @@ EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncRace(ExecState* exec)
}
MarkedArgumentBuffer thenFunctionArguments;
thenFunctionArguments.append(deferred->resolve());
thenFunctionArguments.append(countdownFunction);
thenFunctionArguments.append(deferred->reject());
call(exec, thenFunction, thenFunctionCallType, thenFunctionCallData, nextPromise, thenFunctionArguments);
// ix. RejectIfAbrupt(result, deferred).
// 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);
}
......
......@@ -152,16 +152,7 @@ ThenableStatus updateDeferredFromPotentialThenable(ExecState* exec, JSValue x, J
JSValue exception = exec->exception();
exec->clearException();
JSValue deferredReject = deferred->reject();
CallData rejectCallData;
CallType rejectCallType = getCallData(deferredReject, rejectCallData);
ASSERT(rejectCallType != CallTypeNone);
MarkedArgumentBuffer rejectArguments;
rejectArguments.append(exception);
call(exec, deferredReject, rejectCallType, rejectCallData, jsUndefined(), rejectArguments);
performDeferredReject(exec, deferred, exception);
// ii. ReturnIfAbrupt(rejectResult).
// NOTE: Nothing to do.
......@@ -196,16 +187,7 @@ ThenableStatus updateDeferredFromPotentialThenable(ExecState* exec, JSValue x, J
JSValue exception = exec->exception();
exec->clearException();
JSValue deferredReject = deferred->reject();
CallData rejectCallData;
CallType rejectCallType = getCallData(deferredReject, rejectCallData);
ASSERT(rejectCallType != CallTypeNone);
MarkedArgumentBuffer rejectArguments;
rejectArguments.append(exception);
call(exec, deferredReject, rejectCallType, rejectCallData, jsUndefined(), rejectArguments);
performDeferredReject(exec, deferred, exception);
// ii. ReturnIfAbrupt(rejectResult).
// NOTE: Nothing to do.
......@@ -214,4 +196,51 @@ ThenableStatus updateDeferredFromPotentialThenable(ExecState* exec, JSValue x, J
return WasAThenable;
}
void performDeferredResolve(ExecState* exec, JSPromiseDeferred* deferred, JSValue argument)
{
JSValue deferredResolve = deferred->resolve();
CallData resolveCallData;
CallType resolveCallType = getCallData(deferredResolve, resolveCallData);
ASSERT(resolveCallType != CallTypeNone);
MarkedArgumentBuffer arguments;
arguments.append(argument);
call(exec, deferredResolve, resolveCallType, resolveCallData, jsUndefined(), arguments);
}
void performDeferredReject(ExecState* exec, JSPromiseDeferred* deferred, JSValue argument)
{
JSValue deferredReject = deferred->reject();
CallData rejectCallData;
CallType rejectCallType = getCallData(deferredReject, rejectCallData);
ASSERT(rejectCallType != CallTypeNone);
MarkedArgumentBuffer arguments;
arguments.append(argument);
call(exec, deferredReject, rejectCallType, rejectCallData, jsUndefined(), arguments);
}
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();
}
} // namespace JSC
......@@ -70,6 +70,11 @@ enum ThenableStatus {
JSValue createJSPromiseDeferredFromConstructor(ExecState*, JSValue constructor);
ThenableStatus updateDeferredFromPotentialThenable(ExecState*, JSValue, JSPromiseDeferred*);
void performDeferredResolve(ExecState*, JSPromiseDeferred*, JSValue argument);
void performDeferredReject(ExecState*, JSPromiseDeferred*, JSValue argument);
JSValue abruptRejection(ExecState*, JSPromiseDeferred*);
} // namespace JSC
#endif // JSPromiseDeferred_h
......@@ -34,6 +34,7 @@
#include "JSPromise.h"
#include "JSPromiseConstructor.h"
#include "JSPromiseDeferred.h"
#include "NumberObject.h"
namespace JSC {
......@@ -71,6 +72,55 @@ JSFunction* createIdentifyFunction(VM& vm, JSGlobalObject* globalObject)
return JSFunction::create(vm, globalObject, 1, ASCIILiteral("IdentityFunction"), identifyFunction);
}
// Promise.All Countdown Functions
static EncodedJSValue JSC_HOST_CALL promiseAllCountdownFunction(ExecState* exec)
{
JSValue x = exec->argument(0);
VM& vm = exec->vm();
JSObject* F = exec->callee();
// 1. Let 'index' be the value of F's [[Index]] internal slot.
uint32_t index = F->get(exec, vm.propertyNames->indexPrivateName).asUInt32();
// 2. Let 'values' be the value of F's [[Values]] internal slot..
JSArray* values = jsCast<JSArray*>(F->get(exec, vm.propertyNames->valuesPrivateName));
// 3. Let 'deferred' be the value of F's [[Deferred]] internal slot.
JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(F->get(exec, vm.propertyNames->deferredPrivateName));
// 4. Let 'countdownHolder' be the value of F's [[CountdownHolder]] internal slot.
NumberObject* countdownHolder = jsCast<NumberObject*>(F->get(exec, vm.propertyNames->countdownHolderPrivateName));
// 5. Let 'result' be the result of calling the [[DefineOwnProperty]] internal method
// of 'values' with arguments 'index' and Property Descriptor { [[Value]]: x,
// [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true }.
values->putDirectIndex(exec, index, x);
// 6. RejectIfAbrupt(result, deferred).
if (exec->hadException())
abruptRejection(exec, deferred);
// 7. Set countdownHolder.[[Countdown]] to countdownHolder.[[Countdown]] - 1.
uint32_t newCountdownValue = countdownHolder->internalValue().asUInt32() - 1;
countdownHolder->setInternalValue(vm, JSValue(newCountdownValue));
// 8. If countdownHolder.[[Countdown]] is 0,
if (!newCountdownValue) {
// i. Return 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);
}
// 9. Return.
return JSValue::encode(jsUndefined());
}
JSFunction* createPromiseAllCountdownFunction(VM& vm, JSGlobalObject* globalObject)
{
return JSFunction::create(vm, globalObject, 1, ASCIILiteral("PromiseAllCountdownFunction"), promiseAllCountdownFunction);
}
// Promise Resolution Handler Functions
static EncodedJSValue JSC_HOST_CALL promiseResolutionHandlerFunction(ExecState* exec)
......
......@@ -34,6 +34,7 @@ namespace JSC {
JSFunction* createDeferredConstructionFunction(VM&, JSGlobalObject*);
JSFunction* createIdentifyFunction(VM&, JSGlobalObject*);
JSFunction* createPromiseAllCountdownFunction(VM&, JSGlobalObject*);
JSFunction* createPromiseResolutionHandlerFunction(VM&, JSGlobalObject*);
JSFunction* createRejectPromiseFunction(VM&, JSGlobalObject*);
JSFunction* createResolvePromiseFunction(VM&, JSGlobalObject*);
......
......@@ -89,17 +89,7 @@ void ExecutePromiseReactionMicrotask::run(ExecState* exec)