[JSC] always wrap AwaitExpression operand in a new Promise
authorcaitp@igalia.com <caitp@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 Nov 2016 03:42:55 +0000 (03:42 +0000)
committercaitp@igalia.com <caitp@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 Nov 2016 03:42:55 +0000 (03:42 +0000)
https://bugs.webkit.org/show_bug.cgi?id=165181

Reviewed by Yusuke Suzuki.

JSTests:

* stress/async-await-basic.js:
(async.awaitedPromisesAreWrapped):

Source/JavaScriptCore:

Ensure operand of AwaitExpression is wrapped in a new Promise by
explicitly creating a new Promise Capability and invoking its
resolve callback. This avoids the specified short-circuit for
Promise.resolve().

* builtins/AsyncFunctionPrototype.js:
(globalPrivate.asyncFunctionResume):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@209113 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JSTests/ChangeLog
JSTests/stress/async-await-basic.js
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/builtins/AsyncFunctionPrototype.js

index 6e5fbe6..a757ba9 100644 (file)
@@ -1,3 +1,13 @@
+2016-11-29  Caitlin Potter  <caitp@igalia.com>
+
+        [JSC] always wrap AwaitExpression operand in a new Promise
+        https://bugs.webkit.org/show_bug.cgi?id=165181
+
+        Reviewed by Yusuke Suzuki.
+
+        * stress/async-await-basic.js:
+        (async.awaitedPromisesAreWrapped):
+
 2016-11-29  Keith Miller  <keith_miller@apple.com>
 
         Add simple way to implement Wasm ops that require more than one B3 opcode
 2016-11-29  Keith Miller  <keith_miller@apple.com>
 
         Add simple way to implement Wasm ops that require more than one B3 opcode
index 085f990..08dad34 100644 (file)
@@ -294,3 +294,16 @@ shouldThrowSyntaxError("class C { async ['foo'] : true };", "Unexpected token ':
 shouldThrowSyntaxError("class C { async ['foo'] = true };", "Unexpected token '='. Expected an opening '(' before a async method's parameter list.");
 shouldThrowSyntaxError("class C { async ['foo'] , bar };", "Unexpected token ','. Expected an opening '(' before a async method's parameter list.");
 shouldThrowSyntaxError("class C { async ['foo'] }", "Unexpected token '}'. Expected an opening '(' before a async method's parameter list.");
 shouldThrowSyntaxError("class C { async ['foo'] = true };", "Unexpected token '='. Expected an opening '(' before a async method's parameter list.");
 shouldThrowSyntaxError("class C { async ['foo'] , bar };", "Unexpected token ','. Expected an opening '(' before a async method's parameter list.");
 shouldThrowSyntaxError("class C { async ['foo'] }", "Unexpected token '}'. Expected an opening '(' before a async method's parameter list.");
+
+// Ensure awaited builtin Promise objects are themselves wrapped in a new Promise,
+// per https://tc39.github.io/ecma262/#sec-async-functions-abstract-operations-async-function-await
+log = [];
+async function awaitedPromisesAreWrapped() {
+    log.push("before");
+    await Promise.resolve();
+    log.push("after");
+}
+awaitedPromisesAreWrapped();
+Promise.resolve().then(() => log.push("Promise.resolve()"));
+drainMicrotasks();
+shouldBe("before|Promise.resolve()|after", log.join("|"));
\ No newline at end of file
index 670e1ca..4446b5c 100644 (file)
@@ -1,3 +1,18 @@
+2016-11-29  Caitlin Potter  <caitp@igalia.com>
+
+        [JSC] always wrap AwaitExpression operand in a new Promise
+        https://bugs.webkit.org/show_bug.cgi?id=165181
+
+        Reviewed by Yusuke Suzuki.
+
+        Ensure operand of AwaitExpression is wrapped in a new Promise by
+        explicitly creating a new Promise Capability and invoking its
+        resolve callback. This avoids the specified short-circuit for
+        Promise.resolve().
+
+        * builtins/AsyncFunctionPrototype.js:
+        (globalPrivate.asyncFunctionResume):
+
 2016-11-29  Saam Barati  <sbarati@apple.com>
 
         We should support CreateThis in the FTL
 2016-11-29  Saam Barati  <sbarati@apple.com>
 
         We should support CreateThis in the FTL
index 8d40367..88cfb01 100644 (file)
@@ -47,7 +47,10 @@ function asyncFunctionResume(generator, promiseCapability, sentValue, resumeMode
         return promiseCapability.@promise;
     }
 
         return promiseCapability.@promise;
     }
 
-    @Promise.@resolve(value).@then(
+    let wrappedValue = @newPromiseCapability(@Promise);
+    wrappedValue.@resolve.@call(@undefined, value);
+
+    wrappedValue.@promise.@then(
         function(value) { @asyncFunctionResume(generator, promiseCapability, value, @GeneratorResumeModeNormal); },
         function(error) { @asyncFunctionResume(generator, promiseCapability, error, @GeneratorResumeModeThrow); });
 
         function(value) { @asyncFunctionResume(generator, promiseCapability, value, @GeneratorResumeModeNormal); },
         function(error) { @asyncFunctionResume(generator, promiseCapability, error, @GeneratorResumeModeThrow); });