[promise] Async/await edge case spec compliance fix
- Don't read .constructor when returning a Promise from an async function. Instead, call out to the internals of Promise.resolve directly. This is done by adding back in an "optimization" from an earlier form of the async/await code written by Caitlin Potter. - Async functions always return a new Promise with a distinct identity, even if they simply return another Promise. R=caitp@igalia.com BUG=v8:4483 Review-Url: https://codereview.chromium.org/2219623002 Cr-Commit-Position: refs/heads/master@{#38404}
This commit is contained in:
parent
3f936a5b17
commit
7826bfa789
@ -13,17 +13,17 @@
|
||||
|
||||
var AsyncFunctionNext;
|
||||
var AsyncFunctionThrow;
|
||||
var IsPromise;
|
||||
var GlobalPromise;
|
||||
var NewPromiseCapability;
|
||||
var PerformPromiseThen;
|
||||
var PromiseCastResolved;
|
||||
|
||||
utils.Import(function(from) {
|
||||
AsyncFunctionNext = from.AsyncFunctionNext;
|
||||
AsyncFunctionThrow = from.AsyncFunctionThrow;
|
||||
IsPromise = from.IsPromise;
|
||||
GlobalPromise = from.GlobalPromise;
|
||||
NewPromiseCapability = from.NewPromiseCapability;
|
||||
PromiseCastResolved = from.PromiseCastResolved;
|
||||
PerformPromiseThen = from.PerformPromiseThen;
|
||||
});
|
||||
|
||||
@ -34,14 +34,7 @@ function AsyncFunctionAwait(generator, value) {
|
||||
// value => AsyncFunctionNext(value),
|
||||
// error => AsyncFunctionThrow(error)
|
||||
// );
|
||||
var promise;
|
||||
if (IsPromise(value)) {
|
||||
promise = value;
|
||||
} else {
|
||||
var promiseCapability = NewPromiseCapability(GlobalPromise);
|
||||
%_Call(promiseCapability.resolve, UNDEFINED, value);
|
||||
promise = promiseCapability.promise;
|
||||
}
|
||||
var promise = PromiseCastResolved(value);
|
||||
|
||||
var onFulfilled =
|
||||
(sentValue) => %_Call(AsyncFunctionNext, generator, sentValue);
|
||||
|
@ -191,7 +191,6 @@ function PostNatives(utils) {
|
||||
"IntlParseDate",
|
||||
"IntlParseNumber",
|
||||
"IsNaN",
|
||||
"IsPromise",
|
||||
"MakeError",
|
||||
"MakeRangeError",
|
||||
"MakeTypeError",
|
||||
@ -206,8 +205,7 @@ function PostNatives(utils) {
|
||||
"PromiseChain",
|
||||
"PromiseDefer",
|
||||
"PromiseAccept",
|
||||
"PromiseCreateRejected",
|
||||
"PromiseCreateResolved",
|
||||
"PromiseCastResolved",
|
||||
"PromiseThen",
|
||||
"RegExpSubclassExecJS",
|
||||
"RegExpSubclassMatch",
|
||||
|
@ -386,8 +386,20 @@ function PromiseCreateRejected(r) {
|
||||
return %_Call(PromiseReject, GlobalPromise, r);
|
||||
}
|
||||
|
||||
function PromiseCreateResolved(x) {
|
||||
return %_Call(PromiseResolve, GlobalPromise, x);
|
||||
function PromiseCreateResolved(value) {
|
||||
var promise = PromiseInit(new GlobalPromise(promiseRawSymbol));
|
||||
var resolveResult = ResolvePromise(promise, value);
|
||||
return promise;
|
||||
}
|
||||
|
||||
function PromiseCastResolved(value) {
|
||||
if (IsPromise(value)) {
|
||||
return value;
|
||||
} else {
|
||||
var promise = PromiseInit(new GlobalPromise(promiseRawSymbol));
|
||||
var resolveResult = ResolvePromise(promise, value);
|
||||
return promise;
|
||||
}
|
||||
}
|
||||
|
||||
function PerformPromiseThen(promise, onResolve, onReject, resultCapability) {
|
||||
@ -629,14 +641,11 @@ utils.InstallFunctions(extrasUtils, 0, [
|
||||
fn => %FunctionRemovePrototype(fn));
|
||||
|
||||
utils.Export(function(to) {
|
||||
to.IsPromise = IsPromise;
|
||||
|
||||
to.PromiseChain = PromiseChain;
|
||||
to.PromiseDefer = PromiseDefer;
|
||||
to.PromiseAccept = PromiseAccept;
|
||||
|
||||
to.PromiseCreateRejected = PromiseCreateRejected;
|
||||
to.PromiseCreateResolved = PromiseCreateResolved;
|
||||
to.PromiseCastResolved = PromiseCastResolved;
|
||||
to.PromiseThen = PromiseThen;
|
||||
|
||||
to.GlobalPromise = GlobalPromise;
|
||||
|
27
test/mjsunit/harmony/async-await-no-constructor.js
Normal file
27
test/mjsunit/harmony/async-await-no-constructor.js
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright 2016 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --harmony-async-await --allow-natives-syntax
|
||||
|
||||
'use strict';
|
||||
|
||||
var resolved = Promise.resolve();
|
||||
var count = 0;
|
||||
|
||||
Object.defineProperty(Promise.prototype, 'constructor',
|
||||
{ get() { count++; return Promise; } })
|
||||
|
||||
async function foo() {
|
||||
await resolved;
|
||||
return resolved;
|
||||
}
|
||||
|
||||
async function bar() {
|
||||
throw 1;
|
||||
}
|
||||
|
||||
foo();
|
||||
bar();
|
||||
%RunMicrotasks();
|
||||
assertEquals(0, count);
|
9
test/mjsunit/harmony/async-await-resolve-new.js
Normal file
9
test/mjsunit/harmony/async-await-resolve-new.js
Normal file
@ -0,0 +1,9 @@
|
||||
// Copyright 2016 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --harmony-async-await
|
||||
|
||||
var resolved = Promise.resolve();
|
||||
|
||||
assertTrue((async() => resolved)() !== resolved);
|
Loading…
Reference in New Issue
Block a user