Diff
Modified: trunk/LayoutTests/ChangeLog (161364 => 161365)
--- trunk/LayoutTests/ChangeLog 2014-01-06 20:41:32 UTC (rev 161364)
+++ trunk/LayoutTests/ChangeLog 2014-01-06 21:00:03 UTC (rev 161365)
@@ -1,3 +1,18 @@
+2014-01-05 Sam Weinig <[email protected]>
+
+ [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 <[email protected]>
Unreviewed GTK gardening.
Modified: trunk/LayoutTests/crypto/subtle/resources/common.js (161364 => 161365)
--- trunk/LayoutTests/crypto/subtle/resources/common.js 2014-01-06 20:41:32 UTC (rev 161364)
+++ trunk/LayoutTests/crypto/subtle/resources/common.js 2014-01-06 21:00:03 UTC (rev 161365)
@@ -101,24 +101,5 @@
}
};
-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;
Modified: trunk/LayoutTests/js/dom/Promise-static-all-expected.txt (161364 => 161365)
--- trunk/LayoutTests/js/dom/Promise-static-all-expected.txt 2014-01-06 20:41:32 UTC (rev 161364)
+++ trunk/LayoutTests/js/dom/Promise-static-all-expected.txt 2014-01-06 21:00:03 UTC (rev 161365)
@@ -2,6 +2,28 @@
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
Modified: trunk/LayoutTests/js/dom/Promise-static-all.html (161364 => 161365)
--- trunk/LayoutTests/js/dom/Promise-static-all.html 2014-01-06 20:41:32 UTC (rev 161364)
+++ trunk/LayoutTests/js/dom/Promise-static-all.html 2014-01-06 21:00:03 UTC (rev 161365)
@@ -9,7 +9,6 @@
<script>
description('Test Promise.all');
-/*
window.jsTestIsAsync = true;
result = undefined;
@@ -30,11 +29,9 @@
});
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 @@
}).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=""
Modified: trunk/Source/_javascript_Core/ChangeLog (161364 => 161365)
--- trunk/Source/_javascript_Core/ChangeLog 2014-01-06 20:41:32 UTC (rev 161364)
+++ trunk/Source/_javascript_Core/ChangeLog 2014-01-06 21:00:03 UTC (rev 161365)
@@ -1,3 +1,33 @@
+2014-01-05 Sam Weinig <[email protected]>
+
+ [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 <[email protected]>
Get rid of ENABLE(VALUE_PROFILER). It's on all the time now.
Modified: trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h (161364 => 161365)
--- trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h 2014-01-06 20:41:32 UTC (rev 161364)
+++ trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h 2014-01-06 21:00:03 UTC (rev 161365)
@@ -212,7 +212,11 @@
macro(reject) \
macro(promise) \
macro(fulfillmentHandler) \
- macro(rejectionHandler)
+ macro(rejectionHandler) \
+ macro(index) \
+ macro(values) \
+ macro(deferred) \
+ macro(countdownHolder)
namespace JSC {
Modified: trunk/Source/_javascript_Core/runtime/JSPromiseConstructor.cpp (161364 => 161365)
--- trunk/Source/_javascript_Core/runtime/JSPromiseConstructor.cpp 2014-01-06 20:41:32 UTC (rev 161364)
+++ trunk/Source/_javascript_Core/runtime/JSPromiseConstructor.cpp 2014-01-06 21:00:03 UTC (rev 161365)
@@ -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 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 @@
resolve JSPromiseConstructorFuncResolve DontEnum|Function 1
reject JSPromiseConstructorFuncReject DontEnum|Function 1
race JSPromiseConstructorFuncRace DontEnum|Function 1
+ all JSPromiseConstructorFuncAll DontEnum|Function 1
@end
*/
@@ -191,18 +194,8 @@
// 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();
+ performDeferredResolve(exec, deferred, x);
- CallData resolveCallData;
- CallType resolveCallType = getCallData(deferredResolve, resolveCallData);
- ASSERT(resolveCallType != CallTypeNone);
-
- MarkedArgumentBuffer arguments;
- arguments.append(x);
-
- call(exec, deferredResolve, resolveCallType, resolveCallData, jsUndefined(), arguments);
-
// 6. ReturnIfAbrupt(resolveResult).
if (exec->hadException())
return JSValue::encode(jsUndefined());
@@ -231,17 +224,7 @@
// 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,18 +254,8 @@
// 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);
- 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);
-
// 5. ReturnIfAbrupt(resolveResult).
if (exec->hadException())
return JSValue::encode(jsUndefined());
@@ -291,37 +264,122 @@
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());
- call(exec, deferredReject, rejectCallType, rejectCallData, jsUndefined(), arguments);
+ JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue);
- // ii. ReturnIfAbrupt(rejectResult).
+ // 4. Let 'iterator' be the result of calling GetIterator(iterable).
+ JSValue iteratorFunction = iterable.get(exec, vm.propertyNames->iteratorPrivateName);
if (exec->hadException())
- return jsUndefined();
+ return JSValue::encode(abruptRejection(exec, deferred));
- // iii. Return deferred.[[Promise]].
- return deferred->promise();
+ 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 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 @@
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 @@
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 @@
// 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 @@
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 @@
}
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);
}
Modified: trunk/Source/_javascript_Core/runtime/JSPromiseDeferred.cpp (161364 => 161365)
--- trunk/Source/_javascript_Core/runtime/JSPromiseDeferred.cpp 2014-01-06 20:41:32 UTC (rev 161364)
+++ trunk/Source/_javascript_Core/runtime/JSPromiseDeferred.cpp 2014-01-06 21:00:03 UTC (rev 161365)
@@ -152,17 +152,8 @@
JSValue exception = exec->exception();
exec->clearException();
- JSValue deferredReject = deferred->reject();
+ performDeferredReject(exec, deferred, exception);
- CallData rejectCallData;
- CallType rejectCallType = getCallData(deferredReject, rejectCallData);
- ASSERT(rejectCallType != CallTypeNone);
-
- MarkedArgumentBuffer rejectArguments;
- rejectArguments.append(exception);
-
- call(exec, deferredReject, rejectCallType, rejectCallData, jsUndefined(), rejectArguments);
-
// ii. ReturnIfAbrupt(rejectResult).
// NOTE: Nothing to do.
@@ -196,17 +187,8 @@
JSValue exception = exec->exception();
exec->clearException();
- JSValue deferredReject = deferred->reject();
+ performDeferredReject(exec, deferred, exception);
- CallData rejectCallData;
- CallType rejectCallType = getCallData(deferredReject, rejectCallData);
- ASSERT(rejectCallType != CallTypeNone);
-
- MarkedArgumentBuffer rejectArguments;
- rejectArguments.append(exception);
-
- call(exec, deferredReject, rejectCallType, rejectCallData, jsUndefined(), rejectArguments);
-
// ii. ReturnIfAbrupt(rejectResult).
// NOTE: Nothing to do.
}
@@ -214,4 +196,51 @@
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
Modified: trunk/Source/_javascript_Core/runtime/JSPromiseDeferred.h (161364 => 161365)
--- trunk/Source/_javascript_Core/runtime/JSPromiseDeferred.h 2014-01-06 20:41:32 UTC (rev 161364)
+++ trunk/Source/_javascript_Core/runtime/JSPromiseDeferred.h 2014-01-06 21:00:03 UTC (rev 161365)
@@ -70,6 +70,11 @@
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
Modified: trunk/Source/_javascript_Core/runtime/JSPromiseFunctions.cpp (161364 => 161365)
--- trunk/Source/_javascript_Core/runtime/JSPromiseFunctions.cpp 2014-01-06 20:41:32 UTC (rev 161364)
+++ trunk/Source/_javascript_Core/runtime/JSPromiseFunctions.cpp 2014-01-06 21:00:03 UTC (rev 161365)
@@ -34,6 +34,7 @@
#include "JSPromise.h"
#include "JSPromiseConstructor.h"
#include "JSPromiseDeferred.h"
+#include "NumberObject.h"
namespace JSC {
@@ -71,6 +72,55 @@
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)
Modified: trunk/Source/_javascript_Core/runtime/JSPromiseFunctions.h (161364 => 161365)
--- trunk/Source/_javascript_Core/runtime/JSPromiseFunctions.h 2014-01-06 20:41:32 UTC (rev 161364)
+++ trunk/Source/_javascript_Core/runtime/JSPromiseFunctions.h 2014-01-06 21:00:03 UTC (rev 161365)
@@ -34,6 +34,7 @@
JSFunction* createDeferredConstructionFunction(VM&, JSGlobalObject*);
JSFunction* createIdentifyFunction(VM&, JSGlobalObject*);
+JSFunction* createPromiseAllCountdownFunction(VM&, JSGlobalObject*);
JSFunction* createPromiseResolutionHandlerFunction(VM&, JSGlobalObject*);
JSFunction* createRejectPromiseFunction(VM&, JSGlobalObject*);
JSFunction* createResolvePromiseFunction(VM&, JSGlobalObject*);
Modified: trunk/Source/_javascript_Core/runtime/JSPromiseReaction.cpp (161364 => 161365)
--- trunk/Source/_javascript_Core/runtime/JSPromiseReaction.cpp 2014-01-06 20:41:32 UTC (rev 161364)
+++ trunk/Source/_javascript_Core/runtime/JSPromiseReaction.cpp 2014-01-06 21:00:03 UTC (rev 161365)
@@ -89,17 +89,7 @@
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);
- // FIXME: Should we return the result somewhere?
+ performDeferredReject(exec, deferred, exception);
}
// 5. Let 'handlerResult' be handlerResult.[[value]].
@@ -109,19 +99,10 @@
if (sameValue(exec, handlerResult, deferred->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 deferred.[[Reject]] passing
// undefined as thisArgument and a List containing selfResolutionError as argumentsList.
- JSValue deferredReject = deferred->reject();
-
- CallData rejectCallData;
- CallType rejectCallType = getCallData(deferredReject, rejectCallData);
- ASSERT(rejectCallType != CallTypeNone);
-
- MarkedArgumentBuffer rejectArguments;
- rejectArguments.append(selfResolutionError);
-
- call(exec, deferredReject, rejectCallType, rejectCallData, jsUndefined(), rejectArguments);
- // FIXME: Should we return the result somewhere?
+ performDeferredReject(exec, deferred, selfResolutionError);
}
// 7. Let 'updateResult' be the result of calling UpdateDeferredFromPotentialThenable(handlerResult, deferred).
@@ -135,18 +116,7 @@
if (updateResult == NotAThenable) {
// i. Return the result of calling the [[Call]] internal method of deferred.[[Resolve]]
// passing undefined as thisArgument and a List containing handlerResult as argumentsList.
-
- JSValue deferredResolve = deferred->resolve();
-
- CallData resolveCallData;
- CallType resolveCallType = getCallData(deferredResolve, resolveCallData);
- ASSERT(resolveCallType != CallTypeNone);
-
- MarkedArgumentBuffer arguments;
- arguments.append(handlerResult);
-
- call(exec, deferredResolve, resolveCallType, resolveCallData, jsUndefined(), arguments);
- // FIXME: Should we return the result somewhere?
+ performDeferredResolve(exec, deferred, handlerResult);
}
}