Chromium Code Reviews| Index: src/debug/debug.cc |
| diff --git a/src/debug/debug.cc b/src/debug/debug.cc |
| index 45931b1819fbb21cd8773f429cb488d1bba40e33..60fedd7db8bf5ab46d4a8500fd06764cea0b9b09 100644 |
| --- a/src/debug/debug.cc |
| +++ b/src/debug/debug.cc |
| @@ -38,15 +38,12 @@ namespace internal { |
| Debug::Debug(Isolate* isolate) |
| : debug_context_(Handle<Context>()), |
| - event_listener_(Handle<Object>()), |
| - event_listener_data_(Handle<Object>()), |
| is_active_(false), |
| hook_on_function_call_(false), |
| is_suppressed_(false), |
| live_edit_enabled_(true), // TODO(yangguo): set to false by default. |
| break_disabled_(false), |
| break_points_active_(true), |
| - in_debug_event_listener_(false), |
| break_on_exception_(false), |
| break_on_uncaught_exception_(false), |
| side_effect_check_failed_(false), |
| @@ -473,6 +470,7 @@ bool Debug::Load() { |
| void Debug::Unload() { |
| ClearAllBreakPoints(); |
| ClearStepping(); |
| + RemoveDebugDelegate(); |
| // Return debugger is not loaded. |
| if (!is_loaded()) return; |
| @@ -497,6 +495,7 @@ void Debug::Break(JavaScriptFrame* frame) { |
| // Postpone interrupt during breakpoint processing. |
| PostponeInterruptsScope postpone(isolate_); |
| + DisableBreak no_recursive_break(this); |
| // Return if we fail to retrieve debug info. |
| Handle<JSFunction> function(frame->function()); |
| @@ -1667,11 +1666,11 @@ MaybeHandle<Object> Debug::MakeCompileEvent(Handle<Script> script, |
| return CallFunction("MakeCompileEvent", arraysize(argv), argv); |
| } |
| -MaybeHandle<Object> Debug::MakeAsyncTaskEvent(Handle<Smi> type, |
| - Handle<Smi> id) { |
| - DCHECK(id->IsNumber()); |
| +MaybeHandle<Object> Debug::MakeAsyncTaskEvent( |
| + v8::debug::PromiseDebugActionType type, int id) { |
| // Create the async task event object. |
| - Handle<Object> argv[] = {type, id}; |
| + Handle<Object> argv[] = {Handle<Smi>(Smi::FromInt(type), isolate_), |
| + Handle<Smi>(Smi::FromInt(id), isolate_)}; |
| return CallFunction("MakeAsyncTaskEvent", arraysize(argv), argv); |
| } |
| @@ -1773,7 +1772,6 @@ void Debug::OnException(Handle<Object> exception, Handle<Object> promise) { |
| if (!break_on_exception_) return; |
| } |
| - bool empty_js_stack = false; |
| { |
| JavaScriptFrameIterator it(isolate_); |
| // Check whether the top frame is blackboxed or the break location is muted. |
| @@ -1781,38 +1779,25 @@ void Debug::OnException(Handle<Object> exception, Handle<Object> promise) { |
| IsExceptionBlackboxed(uncaught))) { |
| return; |
| } |
| - empty_js_stack = it.done(); |
| + if (it.done()) return; // Do not trigger an event with an empty stack. |
|
jgruber
2017/02/09 10:33:28
Is there corresponding code in inspector that we c
Yang
2017/02/09 11:24:11
As explained offline, this is not new. Alexey alre
|
| } |
| + if (!debug_delegate_) return; |
|
jgruber
2017/02/09 10:33:28
Would it make sense to move this to the very top o
Yang
2017/02/09 11:24:11
Good idea. I did not move up above the side effect
|
| DebugScope debug_scope(this); |
| if (debug_scope.failed()) return; |
| + HandleScope scope(isolate_); |
| + PostponeInterruptsScope postpone(isolate_); |
| + DisableBreak no_recursive_break(this); |
| - if (debug_delegate_ && !empty_js_stack) { |
| - HandleScope scope(isolate_); |
| - |
| - // Create the execution state. |
| - Handle<Object> exec_state; |
| - // Bail out and don't call debugger if exception. |
| - if (!MakeExecutionState().ToHandle(&exec_state)) return; |
| - |
| - debug_delegate_->ExceptionThrown( |
| - GetDebugEventContext(isolate_), |
| - v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)), |
| - v8::Utils::ToLocal(exception), promise->IsJSObject(), uncaught); |
| - } |
| - if (debug_delegate_ && !non_inspector_listener_exists()) return; |
| - |
| - // Create the event data object. |
| - Handle<Object> event_data; |
| + // Create the execution state. |
| + Handle<Object> exec_state; |
| // Bail out and don't call debugger if exception. |
| - if (!MakeExceptionEvent( |
| - exception, uncaught, promise).ToHandle(&event_data)) { |
| - return; |
| - } |
| + if (!MakeExecutionState().ToHandle(&exec_state)) return; |
| - // Process debug event. |
| - ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data)); |
| - // Return to continue execution from where the exception was thrown. |
| + debug_delegate_->ExceptionThrown( |
| + GetDebugEventContext(isolate_), |
| + v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)), |
| + v8::Utils::ToLocal(exception), v8::Utils::ToLocal(promise), uncaught); |
| } |
| void Debug::OnDebugBreak(Handle<Object> break_points_hit) { |
| @@ -1825,32 +1810,20 @@ void Debug::OnDebugBreak(Handle<Object> break_points_hit) { |
| PrintBreakLocation(); |
| #endif // DEBUG |
| - if (debug_delegate_) { |
| - HandleScope scope(isolate_); |
| - |
| - // Create the execution state. |
| - Handle<Object> exec_state; |
| - // Bail out and don't call debugger if exception. |
| - if (!MakeExecutionState().ToHandle(&exec_state)) return; |
| - |
| - bool previous = in_debug_event_listener_; |
| - in_debug_event_listener_ = true; |
| - debug_delegate_->BreakProgramRequested( |
| - GetDebugEventContext(isolate_), |
| - v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)), |
| - v8::Utils::ToLocal(break_points_hit)); |
| - in_debug_event_listener_ = previous; |
| - if (!non_inspector_listener_exists()) return; |
| - } |
| - |
| + if (!debug_delegate_) return; |
| HandleScope scope(isolate_); |
| - // Create the event data object. |
| - Handle<Object> event_data; |
| + PostponeInterruptsScope no_interrupts(isolate_); |
| + DisableBreak no_recursive_break(this); |
| + |
| + // Create the execution state. |
| + Handle<Object> exec_state; |
| // Bail out and don't call debugger if exception. |
| - if (!MakeBreakEvent(break_points_hit).ToHandle(&event_data)) return; |
| + if (!MakeExecutionState().ToHandle(&exec_state)) return; |
| - // Process debug event. |
| - ProcessDebugEvent(v8::Break, Handle<JSObject>::cast(event_data)); |
| + debug_delegate_->BreakProgramRequested( |
| + GetDebugEventContext(isolate_), |
| + v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)), |
| + v8::Utils::ToLocal(break_points_hit)); |
| } |
| @@ -1881,7 +1854,7 @@ void SendAsyncTaskEventCancel(const v8::WeakCallbackInfo<void>& info) { |
| reinterpret_cast<CollectedCallbackData*>(info.GetParameter())); |
| if (!data->debug->is_active()) return; |
| HandleScope scope(data->isolate); |
| - data->debug->OnAsyncTaskEvent(debug::kDebugPromiseCollected, data->id); |
| + data->debug->OnAsyncTaskEvent(debug::kDebugPromiseCollected, data->id, 0); |
| } |
| void ResetPromiseHandle(const v8::WeakCallbackInfo<void>& info) { |
| @@ -1929,21 +1902,21 @@ void Debug::RunPromiseHook(PromiseHookType type, Handle<JSPromise> promise, |
| int id = GetReferenceAsyncTaskId(isolate_, promise); |
| switch (type) { |
| case PromiseHookType::kInit: |
| - debug_delegate_->PromiseEventOccurred( |
| - debug::kDebugPromiseCreated, id, |
| - parent->IsJSPromise() ? GetReferenceAsyncTaskId( |
| - isolate_, Handle<JSPromise>::cast(parent)) |
| - : 0); |
| + OnAsyncTaskEvent(debug::kDebugPromiseCreated, id, |
| + parent->IsJSPromise() |
| + ? GetReferenceAsyncTaskId( |
| + isolate_, Handle<JSPromise>::cast(parent)) |
| + : 0); |
| return; |
| case PromiseHookType::kResolve: |
| // We can't use this hook because it's called before promise object will |
| // get resolved status. |
| return; |
| case PromiseHookType::kBefore: |
| - OnAsyncTaskEvent(debug::kDebugWillHandle, id); |
| + OnAsyncTaskEvent(debug::kDebugWillHandle, id, 0); |
| return; |
| case PromiseHookType::kAfter: |
| - OnAsyncTaskEvent(debug::kDebugDidHandle, id); |
| + OnAsyncTaskEvent(debug::kDebugDidHandle, id, 0); |
| return; |
| } |
| } |
| @@ -1988,7 +1961,10 @@ bool Debug::IsBlackboxed(Handle<SharedFunctionInfo> shared) { |
| if (!shared->computed_debug_is_blackboxed()) { |
| bool is_blackboxed = false; |
| if (shared->script()->IsScript()) { |
| + SuppressDebug while_processing(this); |
| HandleScope handle_scope(isolate_); |
| + PostponeInterruptsScope no_interrupts(isolate_); |
| + DisableBreak no_recursive_break(this); |
| Handle<Script> script(Script::cast(shared->script())); |
| if (script->type() == i::Script::TYPE_NORMAL) { |
| debug::Location start = |
| @@ -2004,70 +1980,17 @@ bool Debug::IsBlackboxed(Handle<SharedFunctionInfo> shared) { |
| return shared->debug_is_blackboxed(); |
| } |
| -void Debug::OnAsyncTaskEvent(debug::PromiseDebugActionType type, int id) { |
| +void Debug::OnAsyncTaskEvent(debug::PromiseDebugActionType type, int id, |
| + int parent_id) { |
| if (in_debug_scope() || ignore_events()) return; |
| - |
| - if (debug_delegate_) { |
| - debug_delegate_->PromiseEventOccurred(type, id, 0); |
| - if (!non_inspector_listener_exists()) return; |
| - } |
| - |
| - HandleScope scope(isolate_); |
| - DebugScope debug_scope(this); |
| + if (!debug_delegate_) return; |
| + SuppressDebug while_processing(this); |
| + DebugScope debug_scope(isolate_->debug()); |
| if (debug_scope.failed()) return; |
| - |
| - // Create the script collected state object. |
| - Handle<Object> event_data; |
| - // Bail out and don't call debugger if exception. |
| - if (!MakeAsyncTaskEvent(handle(Smi::FromInt(type), isolate_), |
| - handle(Smi::FromInt(id), isolate_)) |
| - .ToHandle(&event_data)) |
| - return; |
| - |
| - // Process debug event. |
| - ProcessDebugEvent(v8::AsyncTaskEvent, Handle<JSObject>::cast(event_data)); |
| -} |
| - |
| -void Debug::ProcessDebugEvent(v8::DebugEvent event, |
| - Handle<JSObject> event_data) { |
| - // Notify registered debug event listener. This can be either a C or |
| - // a JavaScript function. |
| - if (event_listener_.is_null()) return; |
| HandleScope scope(isolate_); |
| - |
| - // Create the execution state. |
| - Handle<Object> exec_state; |
| - // Bail out and don't call debugger if exception. |
| - if (!MakeExecutionState().ToHandle(&exec_state)) return; |
| - |
| - // Prevent other interrupts from triggering, for example API callbacks, |
| - // while dispatching event listners. |
| - PostponeInterruptsScope postpone(isolate_); |
| - bool previous = in_debug_event_listener_; |
| - in_debug_event_listener_ = true; |
| - if (event_listener_->IsForeign()) { |
| - // Invoke the C debug event listener. |
| - v8::Debug::EventCallback callback = FUNCTION_CAST<v8::Debug::EventCallback>( |
| - Handle<Foreign>::cast(event_listener_)->foreign_address()); |
| - EventDetailsImpl event_details(event, Handle<JSObject>::cast(exec_state), |
| - Handle<JSObject>::cast(event_data), |
| - event_listener_data_); |
| - callback(event_details); |
| - CHECK(!isolate_->has_scheduled_exception()); |
| - } else { |
| - // Invoke the JavaScript debug event listener. |
| - DCHECK(event_listener_->IsJSFunction()); |
| - Handle<Object> argv[] = { Handle<Object>(Smi::FromInt(event), isolate_), |
| - exec_state, |
| - event_data, |
| - event_listener_data_ }; |
| - Handle<JSReceiver> global = isolate_->global_proxy(); |
| - MaybeHandle<Object> result = |
| - Execution::Call(isolate_, Handle<JSFunction>::cast(event_listener_), |
| - global, arraysize(argv), argv); |
| - CHECK(!result.is_null()); // Listeners must not throw. |
| - } |
| - in_debug_event_listener_ = previous; |
| + PostponeInterruptsScope no_interrupts(isolate_); |
| + DisableBreak no_recursive_break(this); |
| + debug_delegate_->PromiseEventOccurred(type, id, parent_id); |
| } |
| void Debug::ProcessCompileEvent(v8::DebugEvent event, Handle<Script> script) { |
| @@ -2076,24 +1999,15 @@ void Debug::ProcessCompileEvent(v8::DebugEvent event, Handle<Script> script) { |
| script->type() != i::Script::TYPE_WASM) { |
| return; |
| } |
| + if (!debug_delegate_) return; |
| SuppressDebug while_processing(this); |
| DebugScope debug_scope(this); |
| if (debug_scope.failed()) return; |
| - |
| - if (debug_delegate_) { |
| - debug_delegate_->ScriptCompiled(ToApiHandle<debug::Script>(script), |
| - event != v8::AfterCompile); |
| - if (!non_inspector_listener_exists()) return; |
| - } |
| - |
| HandleScope scope(isolate_); |
| - // Create the compile state object. |
| - Handle<Object> event_data; |
| - // Bail out and don't call debugger if exception. |
| - if (!MakeCompileEvent(script, event).ToHandle(&event_data)) return; |
| - |
| - // Process debug event. |
| - ProcessDebugEvent(event, Handle<JSObject>::cast(event_data)); |
| + PostponeInterruptsScope postpone(isolate_); |
| + DisableBreak no_recursive_break(this); |
| + debug_delegate_->ScriptCompiled(ToApiHandle<debug::Script>(script), |
| + event != v8::AfterCompile); |
| } |
| @@ -2105,27 +2019,6 @@ Handle<Context> Debug::GetDebugContext() { |
| return handle(*debug_context(), isolate_); |
| } |
| - |
| -void Debug::SetEventListener(Handle<Object> callback, |
| - Handle<Object> data) { |
| - GlobalHandles* global_handles = isolate_->global_handles(); |
| - |
| - // Remove existing entry. |
| - GlobalHandles::Destroy(event_listener_.location()); |
| - event_listener_ = Handle<Object>(); |
| - GlobalHandles::Destroy(event_listener_data_.location()); |
| - event_listener_data_ = Handle<Object>(); |
| - |
| - // Set new entry. |
| - if (!callback->IsNullOrUndefined(isolate_)) { |
| - event_listener_ = global_handles->Create(*callback); |
| - if (data.is_null()) data = isolate_->factory()->undefined_value(); |
| - event_listener_data_ = global_handles->Create(*data); |
| - } |
| - |
| - UpdateState(); |
| -} |
| - |
| int Debug::CurrentFrameCount() { |
| StackTraceFrameIterator it(isolate_); |
| if (break_frame_id() != StackFrame::NO_ID) { |
| @@ -2147,13 +2040,25 @@ int Debug::CurrentFrameCount() { |
| return counter; |
| } |
| -void Debug::SetDebugDelegate(debug::DebugDelegate* delegate) { |
| +void Debug::SetDebugDelegate(debug::DebugDelegate* delegate, |
| + bool pass_ownership) { |
| + RemoveDebugDelegate(); |
| debug_delegate_ = delegate; |
| + owns_debug_delegate_ = pass_ownership; |
| UpdateState(); |
| } |
| +void Debug::RemoveDebugDelegate() { |
| + if (debug_delegate_ == nullptr) return; |
| + if (owns_debug_delegate_) { |
| + owns_debug_delegate_ = false; |
| + delete debug_delegate_; |
| + } |
| + debug_delegate_ = nullptr; |
| +} |
| + |
| void Debug::UpdateState() { |
| - bool is_active = !event_listener_.is_null() || debug_delegate_ != nullptr; |
| + bool is_active = debug_delegate_ != nullptr; |
| if (is_active || in_debug_scope()) { |
| // Note that the debug context could have already been loaded to |
| // bootstrap test cases. |
| @@ -2358,59 +2263,159 @@ bool Debug::PerformSideEffectCheckForCallback(Address function) { |
| return false; |
| } |
| -NoSideEffectScope::~NoSideEffectScope() { |
| - if (isolate_->needs_side_effect_check() && |
| - isolate_->debug()->side_effect_check_failed_) { |
| - DCHECK(isolate_->has_pending_exception()); |
| - DCHECK_EQ(isolate_->heap()->termination_exception(), |
| - isolate_->pending_exception()); |
| - // Convert the termination exception into a regular exception. |
| - isolate_->CancelTerminateExecution(); |
| - isolate_->Throw(*isolate_->factory()->NewEvalError( |
| - MessageTemplate::kNoSideEffectDebugEvaluate)); |
| +void LegacyDebugDelegate::PromiseEventOccurred( |
| + v8::debug::PromiseDebugActionType type, int id, int parent_id) { |
| + Handle<Object> event_data; |
| + if (isolate_->debug()->MakeAsyncTaskEvent(type, id).ToHandle(&event_data)) { |
| + ProcessDebugEvent(v8::AsyncTaskEvent, Handle<JSObject>::cast(event_data)); |
| + } |
| +} |
| + |
| +void LegacyDebugDelegate::ScriptCompiled(v8::Local<v8::debug::Script> script, |
| + bool is_compile_error) { |
| + Handle<Object> event_data; |
| + v8::DebugEvent event = is_compile_error ? v8::CompileError : v8::AfterCompile; |
| + if (isolate_->debug() |
| + ->MakeCompileEvent(v8::Utils::OpenHandle(*script), event) |
| + .ToHandle(&event_data)) { |
| + ProcessDebugEvent(event, Handle<JSObject>::cast(event_data)); |
| + } |
| +} |
| + |
| +void LegacyDebugDelegate::BreakProgramRequested( |
| + v8::Local<v8::Context> paused_context, v8::Local<v8::Object> exec_state, |
| + v8::Local<v8::Value> break_points_hit) { |
| + Handle<Object> event_data; |
| + if (isolate_->debug() |
| + ->MakeBreakEvent(v8::Utils::OpenHandle(*break_points_hit)) |
| + .ToHandle(&event_data)) { |
| + ProcessDebugEvent( |
| + v8::Break, Handle<JSObject>::cast(event_data), |
| + Handle<JSObject>::cast(v8::Utils::OpenHandle(*exec_state))); |
| + } |
| +} |
| + |
| +void LegacyDebugDelegate::ExceptionThrown(v8::Local<v8::Context> paused_context, |
| + v8::Local<v8::Object> exec_state, |
| + v8::Local<v8::Value> exception, |
| + v8::Local<v8::Value> promise, |
| + bool is_uncaught) { |
| + Handle<Object> event_data; |
| + if (isolate_->debug() |
| + ->MakeExceptionEvent(v8::Utils::OpenHandle(*exception), is_uncaught, |
| + v8::Utils::OpenHandle(*promise)) |
| + .ToHandle(&event_data)) { |
| + ProcessDebugEvent( |
| + v8::Exception, Handle<JSObject>::cast(event_data), |
| + Handle<JSObject>::cast(v8::Utils::OpenHandle(*exec_state))); |
| + } |
| +} |
| + |
| +void LegacyDebugDelegate::ProcessDebugEvent(v8::DebugEvent event, |
| + Handle<JSObject> event_data) { |
| + Handle<Object> exec_state; |
| + if (isolate_->debug()->MakeExecutionState().ToHandle(&exec_state)) { |
| + ProcessDebugEvent(event, event_data, Handle<JSObject>::cast(exec_state)); |
| } |
| - isolate_->set_needs_side_effect_check(old_needs_side_effect_check_); |
| - isolate_->debug()->UpdateHookOnFunctionCall(); |
| - isolate_->debug()->side_effect_check_failed_ = false; |
| } |
| -EventDetailsImpl::EventDetailsImpl(DebugEvent event, |
| - Handle<JSObject> exec_state, |
| - Handle<JSObject> event_data, |
| - Handle<Object> callback_data) |
| +JavaScriptDebugDelegate::JavaScriptDebugDelegate(Isolate* isolate, |
| + Handle<JSFunction> listener, |
| + Handle<Object> data) |
| + : LegacyDebugDelegate(isolate) { |
| + GlobalHandles* global_handles = isolate->global_handles(); |
| + listener_ = Handle<JSFunction>::cast(global_handles->Create(*listener)); |
| + data_ = global_handles->Create(*data); |
| +} |
| + |
| +JavaScriptDebugDelegate::~JavaScriptDebugDelegate() { |
| + GlobalHandles::Destroy(Handle<Object>::cast(listener_).location()); |
| + GlobalHandles::Destroy(data_.location()); |
| +} |
| + |
| +void JavaScriptDebugDelegate::ProcessDebugEvent(v8::DebugEvent event, |
| + Handle<JSObject> event_data, |
| + Handle<JSObject> exec_state) { |
| + Handle<Object> argv[] = {Handle<Object>(Smi::FromInt(event), isolate_), |
| + exec_state, event_data, data_}; |
| + Handle<JSReceiver> global = isolate_->global_proxy(); |
| + // Listener must not throw. |
| + Execution::Call(isolate_, Handle<JSFunction>::cast(listener_), global, |
|
jgruber
2017/02/09 10:33:28
Nit: the JSFunction cast is already done in the co
Yang
2017/02/09 11:24:11
Done.
|
| + arraysize(argv), argv) |
| + .ToHandleChecked(); |
| +} |
| + |
| +NativeDebugDelegate::NativeDebugDelegate(Isolate* isolate, |
| + v8::Debug::EventCallback callback, |
| + Handle<Object> data) |
| + : LegacyDebugDelegate(isolate), callback_(callback) { |
| + data_ = isolate->global_handles()->Create(*data); |
| +} |
| + |
| +NativeDebugDelegate::~NativeDebugDelegate() { |
| + GlobalHandles::Destroy(data_.location()); |
| +} |
| + |
| +NativeDebugDelegate::EventDetails::EventDetails(DebugEvent event, |
| + Handle<JSObject> exec_state, |
| + Handle<JSObject> event_data, |
| + Handle<Object> callback_data) |
| : event_(event), |
| exec_state_(exec_state), |
| event_data_(event_data), |
| callback_data_(callback_data) {} |
| -DebugEvent EventDetailsImpl::GetEvent() const { |
| +DebugEvent NativeDebugDelegate::EventDetails::GetEvent() const { |
| return event_; |
| } |
| - |
| -v8::Local<v8::Object> EventDetailsImpl::GetExecutionState() const { |
| +v8::Local<v8::Object> NativeDebugDelegate::EventDetails::GetExecutionState() |
| + const { |
| return v8::Utils::ToLocal(exec_state_); |
| } |
| - |
| -v8::Local<v8::Object> EventDetailsImpl::GetEventData() const { |
| +v8::Local<v8::Object> NativeDebugDelegate::EventDetails::GetEventData() const { |
| return v8::Utils::ToLocal(event_data_); |
| } |
| - |
| -v8::Local<v8::Context> EventDetailsImpl::GetEventContext() const { |
| +v8::Local<v8::Context> NativeDebugDelegate::EventDetails::GetEventContext() |
| + const { |
| return GetDebugEventContext(exec_state_->GetIsolate()); |
| } |
| - |
| -v8::Local<v8::Value> EventDetailsImpl::GetCallbackData() const { |
| +v8::Local<v8::Value> NativeDebugDelegate::EventDetails::GetCallbackData() |
| + const { |
| return v8::Utils::ToLocal(callback_data_); |
| } |
| - |
| -v8::Isolate* EventDetailsImpl::GetIsolate() const { |
| +v8::Isolate* NativeDebugDelegate::EventDetails::GetIsolate() const { |
| return reinterpret_cast<v8::Isolate*>(exec_state_->GetIsolate()); |
| } |
| +void NativeDebugDelegate::ProcessDebugEvent(v8::DebugEvent event, |
| + Handle<JSObject> event_data, |
| + Handle<JSObject> exec_state) { |
| + EventDetails event_details(event, exec_state, event_data, data_); |
| + Isolate* isolate = isolate_; |
| + callback_(event_details); |
| + CHECK(!isolate->has_scheduled_exception()); |
| +} |
| + |
| +NoSideEffectScope::~NoSideEffectScope() { |
| + if (isolate_->needs_side_effect_check() && |
| + isolate_->debug()->side_effect_check_failed_) { |
| + DCHECK(isolate_->has_pending_exception()); |
| + DCHECK_EQ(isolate_->heap()->termination_exception(), |
| + isolate_->pending_exception()); |
| + // Convert the termination exception into a regular exception. |
| + isolate_->CancelTerminateExecution(); |
| + isolate_->Throw(*isolate_->factory()->NewEvalError( |
| + MessageTemplate::kNoSideEffectDebugEvaluate)); |
| + } |
| + isolate_->set_needs_side_effect_check(old_needs_side_effect_check_); |
| + isolate_->debug()->UpdateHookOnFunctionCall(); |
| + isolate_->debug()->side_effect_check_failed_ = false; |
| +} |
| + |
| } // namespace internal |
| } // namespace v8 |