Index: src/debug.cc |
diff --git a/src/debug.cc b/src/debug.cc |
index 9f9bcd9a35c64a34ee8f5ef6b188a8298ef81f46..c6b936c33ba27abaf3c7a53fe89d2f6c827bc1bf 100644 |
--- a/src/debug.cc |
+++ b/src/debug.cc |
@@ -855,8 +855,8 @@ void Debug::Unload() { |
ClearAllBreakPoints(); |
ClearStepping(); |
- // Match unmatched PromiseHandlePrologue calls. |
- while (thread_local_.promise_on_stack_) PromiseHandleEpilogue(); |
+ // Match unmatched PopPromise calls. |
+ while (thread_local_.promise_on_stack_) PopPromise(); |
// Return debugger is not loaded. |
if (!is_loaded()) return; |
@@ -1272,30 +1272,29 @@ bool Debug::IsBreakOnException(ExceptionBreakType type) { |
} |
-PromiseOnStack::PromiseOnStack(Isolate* isolate, |
- PromiseOnStack* prev, |
- Handle<JSFunction> getter) |
+PromiseOnStack::PromiseOnStack(Isolate* isolate, PromiseOnStack* prev, |
+ Handle<JSObject> promise) |
: isolate_(isolate), prev_(prev) { |
handler_ = StackHandler::FromAddress( |
Isolate::handler(isolate->thread_local_top())); |
- getter_ = Handle<JSFunction>::cast( |
- isolate->global_handles()->Create(*getter)); |
+ promise_ = |
+ Handle<JSObject>::cast(isolate->global_handles()->Create(*promise)); |
} |
PromiseOnStack::~PromiseOnStack() { |
- isolate_->global_handles()->Destroy(Handle<Object>::cast(getter_).location()); |
+ isolate_->global_handles()->Destroy( |
+ Handle<Object>::cast(promise_).location()); |
} |
-void Debug::PromiseHandlePrologue(Handle<JSFunction> promise_getter) { |
+void Debug::PushPromise(Handle<JSObject> promise) { |
PromiseOnStack* prev = thread_local_.promise_on_stack_; |
- thread_local_.promise_on_stack_ = |
- new PromiseOnStack(isolate_, prev, promise_getter); |
+ thread_local_.promise_on_stack_ = new PromiseOnStack(isolate_, prev, promise); |
} |
-void Debug::PromiseHandleEpilogue() { |
+void Debug::PopPromise() { |
if (thread_local_.promise_on_stack_ == NULL) return; |
PromiseOnStack* prev = thread_local_.promise_on_stack_->prev(); |
delete thread_local_.promise_on_stack_; |
@@ -1303,35 +1302,40 @@ void Debug::PromiseHandleEpilogue() { |
} |
-Handle<Object> Debug::GetPromiseForUncaughtException() { |
+Handle<Object> Debug::GetPromiseOnStackOnThrow() { |
Handle<Object> undefined = isolate_->factory()->undefined_value(); |
if (thread_local_.promise_on_stack_ == NULL) return undefined; |
- Handle<JSFunction> promise_getter = thread_local_.promise_on_stack_->getter(); |
- StackHandler* promise_catch = thread_local_.promise_on_stack_->handler(); |
+ StackHandler* promise_try = thread_local_.promise_on_stack_->handler(); |
// Find the top-most try-catch handler. |
StackHandler* handler = StackHandler::FromAddress( |
Isolate::handler(isolate_->thread_local_top())); |
- while (handler != NULL && !handler->is_catch()) { |
+ do { |
+ if (handler == promise_try) { |
+ // Mark the pushed try-catch handler to prevent a later duplicate event |
+ // triggered with the following reject. |
+ return thread_local_.promise_on_stack_->promise(); |
+ } |
handler = handler->next(); |
- } |
-#ifdef DEBUG |
- // Make sure that our promise catch handler is in the list of handlers, |
- // even if it's not the top-most try-catch handler. |
- StackHandler* temp = handler; |
- while (temp != promise_catch && !temp->is_catch()) { |
- temp = temp->next(); |
- CHECK(temp != NULL); |
- } |
-#endif // DEBUG |
- |
- if (handler == promise_catch) { |
- return Execution::Call( |
- isolate_, promise_getter, undefined, 0, NULL).ToHandleChecked(); |
- } |
+ // There must be a try-catch handler if a promise is on stack. |
+ DCHECK_NE(NULL, handler); |
+ // Throwing inside a Promise can be intercepted by an inner try-catch, so |
+ // we stop at the first try-catch handler. |
+ } while (!handler->is_catch()); |
return undefined; |
} |
+bool Debug::PromiseHasRejectHandler(Handle<JSObject> promise) { |
+ Handle<JSFunction> fun = Handle<JSFunction>::cast( |
+ JSObject::GetDataProperty(isolate_->js_builtins_object(), |
+ isolate_->factory()->NewStringFromStaticAscii( |
+ "PromiseHasRejectHandler"))); |
+ Handle<Object> result = |
+ Execution::Call(isolate_, fun, promise, 0, NULL).ToHandleChecked(); |
+ return result->IsTrue(); |
+} |
+ |
+ |
void Debug::PrepareStep(StepAction step_action, |
int step_count, |
StackFrame::Id frame_id) { |
@@ -2562,13 +2566,25 @@ MaybeHandle<Object> Debug::MakeAsyncTaskEvent(Handle<JSObject> task_event) { |
} |
-void Debug::OnException(Handle<Object> exception, bool uncaught) { |
+void Debug::OnThrow(Handle<Object> exception, bool uncaught) { |
if (in_debug_scope() || ignore_events()) return; |
+ HandleScope scope(isolate_); |
+ OnException(exception, uncaught, GetPromiseOnStackOnThrow()); |
+} |
+ |
+void Debug::OnPromiseReject(Handle<JSObject> promise, Handle<Object> value) { |
+ if (in_debug_scope() || ignore_events()) return; |
HandleScope scope(isolate_); |
- Handle<Object> promise = GetPromiseForUncaughtException(); |
- uncaught |= !promise->IsUndefined(); |
+ OnException(value, false, promise); |
+} |
+ |
+void Debug::OnException(Handle<Object> exception, bool uncaught, |
+ Handle<Object> promise) { |
+ if (promise->IsJSObject()) { |
+ uncaught |= !PromiseHasRejectHandler(Handle<JSObject>::cast(promise)); |
+ } |
// Bail out if exception breaks are not active |
if (uncaught) { |
// Uncaught exceptions are reported by either flags. |