From 326d4f436d351826ce5f66d0ccd53ad55782f610 Mon Sep 17 00:00:00 2001 From: Caitlin Potter Date: Thu, 9 Mar 2017 11:09:59 -0500 Subject: [PATCH] [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 Reviewed-by: Jakob Gruber Commit-Queue: Caitlin Potter Cr-Commit-Position: refs/heads/master@{#43742} --- src/builtins/builtins.cc | 6 + src/builtins/builtins.h | 5 + ...nc-for-await-of-promise-stack-expected.txt | 57 ++++++ .../async-for-await-of-promise-stack.js | 164 ++++++++++++++++++ 4 files changed, 232 insertions(+) create mode 100644 test/inspector/debugger/async-for-await-of-promise-stack-expected.txt create mode 100644 test/inspector/debugger/async-for-await-of-promise-stack.js diff --git a/src/builtins/builtins.cc b/src/builtins/builtins.cc index 518075a632..dc04b7df71 100644 --- a/src/builtins/builtins.cc +++ b/src/builtins/builtins.cc @@ -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. diff --git a/src/builtins/builtins.h b/src/builtins/builtins.h index 781016ba68..ae94669160 100644 --- a/src/builtins/builtins.h +++ b/src/builtins/builtins.h @@ -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) diff --git a/test/inspector/debugger/async-for-await-of-promise-stack-expected.txt b/test/inspector/debugger/async-for-await-of-promise-stack-expected.txt new file mode 100644 index 0000000000..fb1403917a --- /dev/null +++ b/test/inspector/debugger/async-for-await-of-promise-stack-expected.txt @@ -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) \ No newline at end of file diff --git a/test/inspector/debugger/async-for-await-of-promise-stack.js b/test/inspector/debugger/async-for-await-of-promise-stack.js new file mode 100644 index 0000000000..4e6c0bf15e --- /dev/null +++ b/test/inspector/debugger/async-for-await-of-promise-stack.js @@ -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); +}