v8/test/mjsunit/harmony/async-debug-caught-exception.js
littledan 013e49f73c Change which ExceptionEvents are triggered by Promises
To make async/await catch prediction work well, this patch regularizes
the exception events sent to DevTools from various places in the Promise
lifecycle. The core is that there should be an exception event when the
rejection first starts, rather than when it is propagated.

- Several cases within Promise code which propagate errors are
  modified to not trigger a new ExceptionEvent in that case, such
  as .then on a rejected Promise and returning a rejected Promise
  from .then, as well as Promise.race and Promise.all.
- Make Promise.reject() create an ExceptionEvent, subject to catch
  prediction based on the Promise stack. This is important
  so that, e.g., if "await Promise.reject()" will trigger a new
  throw (rather than a silent rethrow of something that never
  triggered an event in the first place).

BUG=v8:5167

Review-Url: https://codereview.chromium.org/2244003003
Cr-Commit-Position: refs/heads/master@{#38847}
2016-08-24 00:20:50 +00:00

124 lines
2.8 KiB
JavaScript

// 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: --allow-natives-syntax --harmony-async-await --expose-debug-as debug
Debug = debug.Debug
var exception = null;
var log;
function listener(event, exec_state, event_data, data) {
if (event != Debug.DebugEvent.Exception) return;
try {
var line = exec_state.frame(0).sourceLineText();
var match = /Exception (\w)/.exec(line);
assertNotNull(match);
log.push(match[1]);
} catch (e) {
exception = e;
}
}
async function thrower() {
throw "a"; // Exception a
}
async function caught_throw() {
try {
await thrower();
} catch (e) {
assertEquals("a", e);
}
}
// Caught throw, events on any exception.
log = [];
Debug.setListener(listener);
Debug.setBreakOnException();
caught_throw();
%RunMicrotasks();
Debug.setListener(null);
Debug.clearBreakOnException();
assertEquals(["a"], log);
assertNull(exception);
// Caught throw, events on uncaught exception.
log = [];
Debug.setListener(listener);
Debug.setBreakOnUncaughtException();
caught_throw();
%RunMicrotasks();
Debug.setListener(null);
Debug.clearBreakOnUncaughtException();
assertEquals([], log);
assertNull(exception);
var reject = Promise.reject("b");
async function caught_reject() {
try {
await reject;
} catch (e) {
assertEquals("b", e);
}
}
// Caught reject, events on any exception.
log = [];
Debug.setListener(listener);
Debug.setBreakOnException();
caught_reject();
%RunMicrotasks();
Debug.setListener(null);
Debug.clearBreakOnException();
assertEquals([], log);
assertNull(exception);
// Caught reject, events on uncaught exception.
log = [];
Debug.setListener(listener);
Debug.setBreakOnUncaughtException();
caught_reject();
%RunMicrotasks();
Debug.setListener(null);
Debug.clearBreakOnUncaughtException();
assertEquals([], log);
assertNull(exception);
log = [];
Debug.setListener(listener);
Debug.setBreakOnException();
// "rethrown" uncaught exceptions in return don't cause another event
async function propagate_inner() { return thrower(); }
async function propagate_outer() { return propagate_inner(); }
propagate_outer();
%RunMicrotasks();
assertEquals(["a"], log);
assertNull(exception);
// Also don't propagate if an await interceded
log = [];
async function propagate_await() { await 1; return thrower(); }
async function propagate_await_outer() { return propagate_await(); }
propagate_await_outer();
%RunMicrotasks();
assertEquals(["a"], log);
assertNull(exception);
Debug.clearBreakOnException();
Debug.setBreakOnUncaughtException();
log = [];
Promise.resolve().then(() => Promise.reject()).catch(() => log.push("d")); // Exception c
%RunMicrotasks();
assertEquals(["d"], log);
assertNull(exception);
Debug.clearBreakOnUncaughtException();
Debug.setListener(null);