Title: [161365] trunk
Revision
161365
Author
[email protected]
Date
2014-01-06 13:00:03 -0800 (Mon, 06 Jan 2014)

Log Message

[JS] Implement Promise.all()
https://bugs.webkit.org/show_bug.cgi?id=126510

Reviewed by Gavin Barraclough.

Source/_javascript_Core: 

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:

Modified Paths

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);
     }
 }
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to