[builtins] add exception predictions for AsyncFromSyncIterator methods

Add a mechanic to set these Builtin exception predictions per-Isolate
rather than per-Context in the Bootstrapper.

Also add Debugger tests which would fail without these prediction
modes set.

Does not yet test for AsyncFromSyncIteratorPrototypeReturn, as this
requires AsyncGenerators and `yield*` to be hit.

BUG=chromium:691875
R=yangguo@chromium.org, jgruber@chromium.org, gsathya@chromium.org

Change-Id: Ic2d2aba3870cce2f7321080f4278875edf253c76
Reviewed-on: https://chromium-review.googlesource.com/451967
Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Commit-Queue: Caitlin Potter <caitp@igalia.com>
Cr-Commit-Position: refs/heads/master@{#43742}
This commit is contained in:
Caitlin Potter 2017-03-09 11:09:59 -05:00 committed by Commit Bot
parent b2efe57cdf
commit 326d4f436d
4 changed files with 232 additions and 0 deletions

View File

@ -167,6 +167,12 @@ void Builtins::SetUp(Isolate* isolate, bool create_heap_objects) {
for (int i = 0; i < builtin_count; i++) {
Code::cast(builtins_[i])->set_builtin_index(i);
}
#define EXCEPTION_PREDICTION(Name, type) \
Code::cast(builtins_[k##Name])->set_##type(true);
BUILTIN_EXCEPTION_PREDICTION_LIST(EXCEPTION_PREDICTION)
#undef EXCEPTION_PREDICTION
}
// Mark as initialized.

View File

@ -854,6 +854,11 @@ class Isolate;
/* proposal-async-iteration/#sec-async-iterator-value-unwrap-functions */ \
TFJ(AsyncIteratorValueUnwrap, 1)
#define BUILTIN_EXCEPTION_PREDICTION_LIST(V) \
V(AsyncFromSyncIteratorPrototypeNext, is_promise_rejection) \
V(AsyncFromSyncIteratorPrototypeReturn, is_promise_rejection) \
V(AsyncFromSyncIteratorPrototypeThrow, is_promise_rejection)
#define IGNORE_BUILTIN(...)
#define BUILTIN_LIST_ALL(V) BUILTIN_LIST(V, V, V, V, V, V, V)

View File

@ -0,0 +1,57 @@
Checks that async chains for for-await-of are correct.
Running test: testBasic
Debugger (test.js:10:2)
Basic (test.js:48:4)
-- async function (test.js:46:20)--
Basic (test.js:46:20)
(anonymous) (testBasic.js:0:0)
Running test: testUncaughtReject
Debugger (test.js:10:2)
-- async function (test.js:52:29)--
UncaughtReject (test.js:52:29)
(anonymous) (testUncaughtReject.js:0:0)
Running test: testUncaughtThrow
Debugger (test.js:10:2)
-- async function (test.js:61:28)--
UncaughtThrow (test.js:61:28)
(anonymous) (testUncaughtThrow.js:0:0)
Running test: testCaughtReject
Debugger (test.js:10:2)
CaughtReject (test.js:76:4)
-- async function (test.js:70:27)--
CaughtReject (test.js:70:27)
(anonymous) (testCaughtReject.js:0:0)
Running test: testCaughtThrow
Debugger (test.js:10:2)
CaughtThrow (test.js:86:4)
-- async function (test.js:80:26)--
CaughtThrow (test.js:80:26)
(anonymous) (testCaughtThrow.js:0:0)
Running test: testUncaughtRejectOnBreak
Running test: testUncaughtThrowOnBreak
Debugger (test.js:10:2)
-- async function (test.js:99:35)--
UncaughtThrowOnBreak (test.js:99:35)
(anonymous) (testUncaughtThrowOnBreak.js:0:0)
Running test: testCaughtRejectOnBreak
Running test: testCaughtThrowOnBreak
Debugger (test.js:10:2)
CaughtThrowOnBreak (test.js:124:4)
-- async function (test.js:118:33)--
CaughtThrowOnBreak (test.js:118:33)
(anonymous) (testCaughtThrowOnBreak.js:0:0)

View File

@ -0,0 +1,164 @@
// 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-iteration
InspectorTest.log('Checks that async chains for for-await-of are correct.');
InspectorTest.addScript(`
function Debugger(value) {
debugger;
}
function Reject(reason) {
var reject;
var promise = new Promise(function(resolvefn, rejectfn) {
reject = rejectfn;
});
setTimeout(reject.bind(undefined, reason), 0);
return promise;
}
function Throw(reason) {
return {
get then() { throw reason; }
};
}
function ThrowOnReturn(items) {
var it = items[Symbol.iterator]();
return {
[Symbol.iterator]() { return this; },
next(v) { return it.next(v); },
return(v) { throw new Error("boop"); }
};
}
function RejectOnReturn(items) {
var it = items[Symbol.iterator]();
return {
[Symbol.iterator]() { return this; },
next(v) { return it.next(v); },
return(v) { return Reject(new Error("boop")); }
};
}
async function Basic() {
for await (let x of ["a"]) {
Debugger();
}
}
async function UncaughtReject() {
async function loop() {
for await (let x of [Reject(new Error("boop"))]) {
Debugger();
}
}
return loop().catch(Debugger);
}
async function UncaughtThrow() {
async function loop() {
for await (let x of [Throw(new Error("boop"))]) {
Debugger();
}
}
return loop().catch(Debugger);
}
async function CaughtReject() {
try {
for await (let x of [Reject(new Error("boop"))]) {
Debugger(x);
}
} catch (e) {
Debugger(e);
}
}
async function CaughtThrow() {
try {
for await (let x of [Throw(new Error("boop"))]) {
Debugger(x);
}
} catch (e) {
Debugger(e);
}
}
async function UncaughtRejectOnBreak() {
async function loop() {
for await (let x of RejectOnReturn(["0", "1"])) {
break;
}
}
return loop().catch(Debugger);
}
async function UncaughtThrowOnBreak() {
async function loop() {
for await (let x of ThrowOnReturn(["0", "1"])) {
break;
}
}
return loop().catch(Debugger);
}
async function CaughtRejectOnBreak() {
try {
for await (let x of RejectOnReturn(["0", "1"])) {
break;
}
} catch (e) {
Debugger(e);
}
}
async function CaughtThrowOnBreak() {
try {
for await (let x of ThrowOnReturn(["0", "1"])) {
break;
}
} catch (e) {
Debugger(e);
}
}
//# sourceURL=test.js`, 7, 129);
InspectorTest.setupScriptMap();
Protocol.Debugger.onPaused(message => {
InspectorTest.logCallFrames(message.params.callFrames);
InspectorTest.logAsyncStackTrace(message.params.asyncStackTrace);
InspectorTest.log('');
Protocol.Debugger.resume();
});
Protocol.Debugger.enable();
Protocol.Debugger.setAsyncCallStackDepth({ maxDepth: 128 });
var testList = [
'Basic',
'UncaughtReject',
'UncaughtThrow',
'CaughtReject',
'CaughtThrow',
'UncaughtRejectOnBreak',
'UncaughtThrowOnBreak',
'CaughtRejectOnBreak',
'CaughtThrowOnBreak',
]
InspectorTest.runTestSuite(testList.map(name => {
return eval(`
(function test${capitalize(name)}(next) {
Protocol.Runtime.evaluate({ expression: \`${name}()
//# sourceURL=test${capitalize(name)}.js\`, awaitPromise: true})
.then(next);
})
`);
}));
function capitalize(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}