Chromium Code Reviews| Index: src/debug.cc |
| diff --git a/src/debug.cc b/src/debug.cc |
| index 9f9bcd9a35c64a34ee8f5ef6b188a8298ef81f46..118861f3b124d6b3d868cb672a56f4f4f8310e79 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,26 @@ 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()) { |
| + bool hasreject = PromiseHasRejectHandler(Handle<JSObject>::cast(promise)); |
|
aandrey
2014/08/05 11:59:39
hasreject -> has_reject
Yang
2014/08/05 12:56:04
Removed this interim result entirely.
|
| + uncaught |= !hasreject; |
| + } |
| // Bail out if exception breaks are not active |
| if (uncaught) { |
| // Uncaught exceptions are reported by either flags. |