Trigger debug event on not yet caught exception in promises.
R=aandrey@chromium.org, rossberg@chromium.org, yurys@chromium.org BUG=v8:3093 LOG=Y Review URL: https://codereview.chromium.org/249503002 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20956 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
7f217b9d49
commit
28f5cf398e
@ -43,7 +43,8 @@ enum DebugEvent {
|
||||
BeforeCompile = 4,
|
||||
AfterCompile = 5,
|
||||
ScriptCollected = 6,
|
||||
BreakForCommand = 7
|
||||
UncaughtExceptionInPromise = 7,
|
||||
BreakForCommand = 8
|
||||
};
|
||||
|
||||
|
||||
|
@ -42,7 +42,8 @@ Debug.DebugEvent = { Break: 1,
|
||||
NewFunction: 3,
|
||||
BeforeCompile: 4,
|
||||
AfterCompile: 5,
|
||||
ScriptCollected: 6 };
|
||||
ScriptCollected: 6,
|
||||
PendingExceptionInPromise: 7 };
|
||||
|
||||
// Types of exceptions that can be broken upon.
|
||||
Debug.ExceptionBreak = { Caught : 0,
|
||||
@ -1093,15 +1094,16 @@ BreakEvent.prototype.toJSONProtocol = function() {
|
||||
};
|
||||
|
||||
|
||||
function MakeExceptionEvent(exec_state, exception, uncaught) {
|
||||
return new ExceptionEvent(exec_state, exception, uncaught);
|
||||
function MakeExceptionEvent(exec_state, exception, uncaught, promise) {
|
||||
return new ExceptionEvent(exec_state, exception, uncaught, promise);
|
||||
}
|
||||
|
||||
|
||||
function ExceptionEvent(exec_state, exception, uncaught) {
|
||||
function ExceptionEvent(exec_state, exception, uncaught, promise) {
|
||||
this.exec_state_ = exec_state;
|
||||
this.exception_ = exception;
|
||||
this.uncaught_ = uncaught;
|
||||
this.promise_ = promise;
|
||||
}
|
||||
|
||||
|
||||
@ -1125,6 +1127,11 @@ ExceptionEvent.prototype.uncaught = function() {
|
||||
};
|
||||
|
||||
|
||||
ExceptionEvent.prototype.promise = function() {
|
||||
return this.promise_;
|
||||
};
|
||||
|
||||
|
||||
ExceptionEvent.prototype.func = function() {
|
||||
return this.exec_state_.frame(0).func();
|
||||
};
|
||||
|
22
src/debug.cc
22
src/debug.cc
@ -2628,13 +2628,15 @@ MaybeHandle<Object> Debugger::MakeBreakEvent(Handle<Object> break_points_hit) {
|
||||
|
||||
|
||||
MaybeHandle<Object> Debugger::MakeExceptionEvent(Handle<Object> exception,
|
||||
bool uncaught) {
|
||||
bool uncaught,
|
||||
Handle<Object> promise) {
|
||||
Handle<Object> exec_state;
|
||||
if (!MakeExecutionState().ToHandle(&exec_state)) return MaybeHandle<Object>();
|
||||
// Create the new exception event object.
|
||||
Handle<Object> argv[] = { exec_state,
|
||||
exception,
|
||||
isolate_->factory()->ToBoolean(uncaught) };
|
||||
isolate_->factory()->ToBoolean(uncaught),
|
||||
promise };
|
||||
return MakeJSObject(CStrVector("MakeExceptionEvent"), ARRAY_SIZE(argv), argv);
|
||||
}
|
||||
|
||||
@ -2664,7 +2666,9 @@ MaybeHandle<Object> Debugger::MakeScriptCollectedEvent(int id) {
|
||||
}
|
||||
|
||||
|
||||
void Debugger::OnException(Handle<Object> exception, bool uncaught) {
|
||||
void Debugger::OnException(Handle<Object> exception,
|
||||
bool uncaught,
|
||||
Handle<Object> promise) {
|
||||
HandleScope scope(isolate_);
|
||||
Debug* debug = isolate_->debug();
|
||||
|
||||
@ -2688,13 +2692,21 @@ void Debugger::OnException(Handle<Object> exception, bool uncaught) {
|
||||
|
||||
// Clear all current stepping setup.
|
||||
debug->ClearStepping();
|
||||
|
||||
// Determine event;
|
||||
DebugEvent event = promise->IsUndefined()
|
||||
? v8::Exception : v8::UncaughtExceptionInPromise;
|
||||
|
||||
// Create the event data object.
|
||||
Handle<Object> event_data;
|
||||
// Bail out and don't call debugger if exception.
|
||||
if (!MakeExceptionEvent(exception, uncaught).ToHandle(&event_data)) return;
|
||||
if (!MakeExceptionEvent(
|
||||
exception, uncaught, promise).ToHandle(&event_data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Process debug event.
|
||||
ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data), false);
|
||||
ProcessDebugEvent(event, Handle<JSObject>::cast(event_data), false);
|
||||
// Return to continue execution from where the exception was thrown.
|
||||
}
|
||||
|
||||
|
@ -793,13 +793,17 @@ class Debugger {
|
||||
MUST_USE_RESULT MaybeHandle<Object> MakeBreakEvent(
|
||||
Handle<Object> break_points_hit);
|
||||
MUST_USE_RESULT MaybeHandle<Object> MakeExceptionEvent(
|
||||
Handle<Object> exception, bool uncaught);
|
||||
Handle<Object> exception,
|
||||
bool uncaught,
|
||||
Handle<Object> promise);
|
||||
MUST_USE_RESULT MaybeHandle<Object> MakeCompileEvent(
|
||||
Handle<Script> script, bool before);
|
||||
MUST_USE_RESULT MaybeHandle<Object> MakeScriptCollectedEvent(int id);
|
||||
|
||||
void OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue);
|
||||
void OnException(Handle<Object> exception, bool uncaught);
|
||||
void OnException(Handle<Object> exception,
|
||||
bool uncaught,
|
||||
Handle<Object> promise = Handle<Object>::null());
|
||||
void OnBeforeCompile(Handle<Script> script);
|
||||
|
||||
enum AfterCompileFlags {
|
||||
|
@ -316,7 +316,7 @@ void Execution::RunMicrotasks(Isolate* isolate) {
|
||||
isolate->run_microtasks(),
|
||||
isolate->factory()->undefined_value(),
|
||||
0,
|
||||
NULL).Assert();
|
||||
NULL).Check();
|
||||
}
|
||||
|
||||
|
||||
@ -327,7 +327,7 @@ void Execution::EnqueueMicrotask(Isolate* isolate, Handle<Object> microtask) {
|
||||
isolate->enqueue_external_microtask(),
|
||||
isolate->factory()->undefined_value(),
|
||||
1,
|
||||
args).Assert();
|
||||
args).Check();
|
||||
}
|
||||
|
||||
|
||||
|
@ -1055,7 +1055,8 @@ void Isolate::DoThrow(Object* exception, MessageLocation* location) {
|
||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||
// Notify debugger of exception.
|
||||
if (catchable_by_javascript) {
|
||||
debugger_->OnException(exception_handle, report_exception);
|
||||
debugger_->OnException(
|
||||
exception_handle, report_exception, factory()->undefined_value());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -191,9 +191,22 @@ function PromiseHandle(value, handler, deferred) {
|
||||
%_CallFunction(result, deferred.resolve, deferred.reject, PromiseChain);
|
||||
else
|
||||
deferred.resolve(result);
|
||||
} catch(e) {
|
||||
// TODO(rossberg): perhaps log uncaught exceptions below.
|
||||
try { deferred.reject(e) } catch(e) {}
|
||||
} catch (exception) {
|
||||
var uncaught = false;
|
||||
var reject_queue = GET_PRIVATE(deferred.promise, promiseOnReject);
|
||||
if (reject_queue && reject_queue.length == 0) {
|
||||
// The deferred promise may get a reject handler attached later.
|
||||
// For now, we consider the exception to be (for the moment) uncaught.
|
||||
uncaught = true;
|
||||
}
|
||||
try {
|
||||
deferred.reject(exception);
|
||||
} catch (e) {
|
||||
// The reject handler can only throw for a custom deferred promise.
|
||||
// We consider the original exception to be uncaught.
|
||||
uncaught = true;
|
||||
}
|
||||
if (uncaught) %DebugPendingExceptionInPromise(exception, deferred.promise);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5625,7 +5625,6 @@ RUNTIME_FUNCTION(Runtime_StoreArrayLiteralElement) {
|
||||
// Check whether debugger and is about to step into the callback that is passed
|
||||
// to a built-in function such as Array.forEach.
|
||||
RUNTIME_FUNCTION(Runtime_DebugCallbackSupportsStepping) {
|
||||
SealHandleScope shs(isolate);
|
||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||
ASSERT(args.length() == 1);
|
||||
if (!isolate->IsDebuggerActive() || !isolate->debug()->StepInActive()) {
|
||||
@ -5644,7 +5643,6 @@ RUNTIME_FUNCTION(Runtime_DebugCallbackSupportsStepping) {
|
||||
// Set one shot breakpoints for the callback function that is passed to a
|
||||
// built-in function such as Array.forEach to enable stepping into the callback.
|
||||
RUNTIME_FUNCTION(Runtime_DebugPrepareStepInIfStepping) {
|
||||
SealHandleScope shs(isolate);
|
||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||
ASSERT(args.length() == 1);
|
||||
Debug* debug = isolate->debug();
|
||||
@ -5661,6 +5659,19 @@ RUNTIME_FUNCTION(Runtime_DebugPrepareStepInIfStepping) {
|
||||
}
|
||||
|
||||
|
||||
// Notify the debugger if an expcetion in a promise is not caught (yet).
|
||||
RUNTIME_FUNCTION(Runtime_DebugPendingExceptionInPromise) {
|
||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||
ASSERT(args.length() == 2);
|
||||
HandleScope scope(isolate);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, exception, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 1);
|
||||
isolate->debugger()->OnException(exception, true, promise);
|
||||
#endif // ENABLE_DEBUGGER_SUPPORT
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
|
||||
// Set a local property, even if it is READ_ONLY. If the property does not
|
||||
// exist, it will be added with attributes NONE.
|
||||
RUNTIME_FUNCTION(Runtime_IgnoreAttributesAndSetProperty) {
|
||||
|
@ -99,6 +99,7 @@ namespace internal {
|
||||
F(StoreArrayLiteralElement, 5, 1) \
|
||||
F(DebugCallbackSupportsStepping, 1, 1) \
|
||||
F(DebugPrepareStepInIfStepping, 1, 1) \
|
||||
F(DebugPendingExceptionInPromise, 2, 1) \
|
||||
F(FlattenString, 1, 1) \
|
||||
F(LoadMutableDouble, 2, 1) \
|
||||
F(TryMigrateInstance, 1, 1) \
|
||||
|
56
test/mjsunit/es6/debug-promises-caught-all.js
Normal file
56
test/mjsunit/es6/debug-promises-caught-all.js
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright 2014 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-promises --expose-debug-as debug
|
||||
|
||||
// Test debug events when we listen to all exceptions and
|
||||
// there is a catch handler for the exception thrown in a Promise.
|
||||
// Expectation:
|
||||
// - only the normal Exception debug event is triggered.
|
||||
|
||||
Debug = debug.Debug;
|
||||
|
||||
var log = [];
|
||||
var step = 0;
|
||||
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
log.push("resolve");
|
||||
resolve();
|
||||
});
|
||||
|
||||
var q = p.chain(
|
||||
function() {
|
||||
log.push("throw");
|
||||
throw new Error("caught");
|
||||
});
|
||||
|
||||
q.catch(
|
||||
function(e) {
|
||||
assertEquals("caught", e.message);
|
||||
});
|
||||
|
||||
function listener(event, exec_state, event_data, data) {
|
||||
try {
|
||||
// Ignore exceptions during startup in stress runs.
|
||||
if (step >= 1) return;
|
||||
assertEquals(["resolve", "end main", "throw"], log);
|
||||
assertTrue(event != Debug.DebugEvent.PendingExceptionInPromise);
|
||||
if (event == Debug.DebugEvent.Exception) {
|
||||
assertEquals("caught", event_data.exception().message);
|
||||
assertEquals(undefined, event_data.promise());
|
||||
step++;
|
||||
}
|
||||
} catch (e) {
|
||||
// Signal a failure with exit code 1. This is necessary since the
|
||||
// debugger swallows exceptions and we expect the chained function
|
||||
// and this listener to be executed after the main script is finished.
|
||||
print("Unexpected exception: " + e + "\n" + e.stack);
|
||||
quit(1);
|
||||
}
|
||||
}
|
||||
|
||||
Debug.setBreakOnException();
|
||||
Debug.setListener(listener);
|
||||
|
||||
log.push("end main");
|
42
test/mjsunit/es6/debug-promises-caught-uncaught.js
Normal file
42
test/mjsunit/es6/debug-promises-caught-uncaught.js
Normal file
@ -0,0 +1,42 @@
|
||||
// Copyright 2014 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-promises --expose-debug-as debug
|
||||
|
||||
// Test debug events when we only listen to uncaught exceptions and
|
||||
// there is a catch handler for the exception thrown in a Promise.
|
||||
// Expectation:
|
||||
// - no debug event is triggered.
|
||||
|
||||
Debug = debug.Debug;
|
||||
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
resolve();
|
||||
});
|
||||
|
||||
var q = p.chain(
|
||||
function() {
|
||||
throw new Error("caught");
|
||||
});
|
||||
|
||||
q.catch(
|
||||
function(e) {
|
||||
assertEquals("caught", e.message);
|
||||
});
|
||||
|
||||
function listener(event, exec_state, event_data, data) {
|
||||
try {
|
||||
assertTrue(event != Debug.DebugEvent.Exception);
|
||||
assertTrue(event != Debug.DebugEvent.PendingExceptionInPromise);
|
||||
} catch (e) {
|
||||
// Signal a failure with exit code 1. This is necessary since the
|
||||
// debugger swallows exceptions and we expect the chained function
|
||||
// and this listener to be executed after the main script is finished.
|
||||
print("Unexpected exception: " + e + "\n" + e.stack);
|
||||
quit(1);
|
||||
}
|
||||
}
|
||||
|
||||
Debug.setBreakOnUncaughtException();
|
||||
Debug.setListener(listener);
|
61
test/mjsunit/es6/debug-promises-throw-in-reject.js
Normal file
61
test/mjsunit/es6/debug-promises-throw-in-reject.js
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright 2014 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-promises --expose-debug-as debug
|
||||
|
||||
// Test debug events when an exception is thrown inside a Promise, which is
|
||||
// caught by a custom promise, which throws a new exception in its reject
|
||||
// handler. We expect a PendingExceptionInPromise event to be triggered.
|
||||
|
||||
Debug = debug.Debug;
|
||||
|
||||
var log = [];
|
||||
var step = 0;
|
||||
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
log.push("resolve");
|
||||
resolve();
|
||||
});
|
||||
|
||||
function MyPromise(resolver) {
|
||||
var reject = function() {
|
||||
log.push("throw reject");
|
||||
throw new Error("reject");
|
||||
};
|
||||
var resolve = function() { };
|
||||
log.push("construct");
|
||||
resolver(resolve, reject);
|
||||
};
|
||||
|
||||
MyPromise.prototype = p;
|
||||
p.constructor = MyPromise;
|
||||
|
||||
var q = p.chain(
|
||||
function() {
|
||||
log.push("throw caught");
|
||||
throw new Error("caught");
|
||||
});
|
||||
|
||||
function listener(event, exec_state, event_data, data) {
|
||||
try {
|
||||
if (event == Debug.DebugEvent.PendingExceptionInPromise) {
|
||||
assertEquals(["resolve", "construct", "end main",
|
||||
"throw caught", "throw reject"], log);
|
||||
assertEquals("caught", event_data.exception().message);
|
||||
} else if (event == Debug.DebugEvent.Exception) {
|
||||
assertUnreachable();
|
||||
}
|
||||
} catch (e) {
|
||||
// Signal a failure with exit code 1. This is necessary since the
|
||||
// debugger swallows exceptions and we expect the chained function
|
||||
// and this listener to be executed after the main script is finished.
|
||||
print("Unexpected exception: " + e + "\n" + e.stack);
|
||||
quit(1);
|
||||
}
|
||||
}
|
||||
|
||||
Debug.setBreakOnUncaughtException();
|
||||
Debug.setListener(listener);
|
||||
|
||||
log.push("end main");
|
62
test/mjsunit/es6/debug-promises-uncaught-all.js
Normal file
62
test/mjsunit/es6/debug-promises-uncaught-all.js
Normal file
@ -0,0 +1,62 @@
|
||||
// Copyright 2014 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-promises --expose-debug-as debug
|
||||
|
||||
// Test debug events when we listen to all exceptions and
|
||||
// there is a catch handler for the exception thrown in a Promise.
|
||||
// Expectation:
|
||||
// - the normal Exception debug event is triggered.
|
||||
// - the PendingExceptionInPromise debug event is triggered afterwards,
|
||||
// with the same exception object.
|
||||
|
||||
Debug = debug.Debug;
|
||||
|
||||
var log = [];
|
||||
var step = 0;
|
||||
var exception = undefined;
|
||||
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
log.push("resolve");
|
||||
resolve();
|
||||
});
|
||||
|
||||
var q = p.chain(
|
||||
function() {
|
||||
log.push("throw");
|
||||
throw new Error("uncaught");
|
||||
});
|
||||
|
||||
function listener(event, exec_state, event_data, data) {
|
||||
try {
|
||||
// Ignore exceptions during startup in stress runs.
|
||||
if (step > 1) return;
|
||||
assertEquals(["resolve", "end main", "throw"], log);
|
||||
if (event == Debug.DebugEvent.Exception) {
|
||||
assertEquals(0, step);
|
||||
exception = event_data.exception();
|
||||
assertEquals(undefined, event_data.promise());
|
||||
} else if (event == Debug.DebugEvent.PendingExceptionInPromise) {
|
||||
assertEquals(1, step);
|
||||
assertEquals(exception, event_data.exception());
|
||||
assertEquals("uncaught", exception.message);
|
||||
assertTrue(event_data.promise() instanceof Promise);
|
||||
assertTrue(event_data.uncaught());
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
step++;
|
||||
} catch (e) {
|
||||
// Signal a failure with exit code 1. This is necessary since the
|
||||
// debugger swallows exceptions and we expect the chained function
|
||||
// and this listener to be executed after the main script is finished.
|
||||
print("Unexpected exception: " + e + "\n" + e.stack);
|
||||
quit(1);
|
||||
}
|
||||
}
|
||||
|
||||
Debug.setBreakOnException();
|
||||
Debug.setListener(listener);
|
||||
|
||||
log.push("end main");
|
54
test/mjsunit/es6/debug-promises-uncaught-uncaught.js
Normal file
54
test/mjsunit/es6/debug-promises-uncaught-uncaught.js
Normal file
@ -0,0 +1,54 @@
|
||||
// Copyright 2014 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-promises --expose-debug-as debug
|
||||
|
||||
// Test debug events when we only listen to uncaught exceptions and
|
||||
// there is a catch handler for the exception thrown in a Promise.
|
||||
// Expectation:
|
||||
// - only the PendingExceptionInPromise debug event is triggered.
|
||||
|
||||
Debug = debug.Debug;
|
||||
|
||||
var log = [];
|
||||
var step = 0;
|
||||
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
log.push("resolve");
|
||||
resolve();
|
||||
});
|
||||
|
||||
var q = p.chain(
|
||||
function() {
|
||||
log.push("throw");
|
||||
throw new Error("uncaught");
|
||||
});
|
||||
|
||||
function listener(event, exec_state, event_data, data) {
|
||||
try {
|
||||
// Ignore exceptions during startup in stress runs.
|
||||
if (step >= 1) return;
|
||||
assertEquals(["resolve", "end main", "throw"], log);
|
||||
if (event == Debug.DebugEvent.Exception) {
|
||||
assertUnreachable();
|
||||
} else if (event == Debug.DebugEvent.PendingExceptionInPromise) {
|
||||
assertEquals(0, step);
|
||||
assertEquals("uncaught", event_data.exception().message);
|
||||
assertTrue(event_data.promise() instanceof Promise);
|
||||
assertTrue(event_data.uncaught());
|
||||
step++;
|
||||
}
|
||||
} catch (e) {
|
||||
// Signal a failure with exit code 1. This is necessary since the
|
||||
// debugger swallows exceptions and we expect the chained function
|
||||
// and this listener to be executed after the main script is finished.
|
||||
print("Unexpected exception: " + e + "\n" + e.stack);
|
||||
quit(1);
|
||||
}
|
||||
}
|
||||
|
||||
Debug.setBreakOnUncaughtException();
|
||||
Debug.setListener(listener);
|
||||
|
||||
log.push("end main");
|
57
test/mjsunit/es6/debug-promises-undefined-reject.js
Normal file
57
test/mjsunit/es6/debug-promises-undefined-reject.js
Normal file
@ -0,0 +1,57 @@
|
||||
// Copyright 2014 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-promises --expose-debug-as debug
|
||||
|
||||
// Test debug events when an exception is thrown inside a Promise, which is
|
||||
// caught by a custom promise, which has no reject handler.
|
||||
// We expect a PendingExceptionInPromise event to be triggered.
|
||||
|
||||
Debug = debug.Debug;
|
||||
|
||||
var log = [];
|
||||
var step = 0;
|
||||
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
log.push("resolve");
|
||||
resolve();
|
||||
});
|
||||
|
||||
function MyPromise(resolver) {
|
||||
var reject = undefined;
|
||||
var resolve = function() { };
|
||||
log.push("construct");
|
||||
resolver(resolve, reject);
|
||||
};
|
||||
|
||||
MyPromise.prototype = p;
|
||||
p.constructor = MyPromise;
|
||||
|
||||
var q = p.chain(
|
||||
function() {
|
||||
log.push("throw caught");
|
||||
throw new Error("caught");
|
||||
});
|
||||
|
||||
function listener(event, exec_state, event_data, data) {
|
||||
try {
|
||||
if (event == Debug.DebugEvent.PendingExceptionInPromise) {
|
||||
assertEquals(["resolve", "construct", "end main", "throw caught"], log);
|
||||
assertEquals("caught", event_data.exception().message);
|
||||
} else if (event == Debug.DebugEvent.Exception) {
|
||||
assertUnreachable();
|
||||
}
|
||||
} catch (e) {
|
||||
// Signal a failure with exit code 1. This is necessary since the
|
||||
// debugger swallows exceptions and we expect the chained function
|
||||
// and this listener to be executed after the main script is finished.
|
||||
print("Unexpected exception: " + e + "\n" + e.stack);
|
||||
quit(1);
|
||||
}
|
||||
}
|
||||
|
||||
Debug.setBreakOnUncaughtException();
|
||||
Debug.setListener(listener);
|
||||
|
||||
log.push("end main");
|
Loading…
Reference in New Issue
Block a user