| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/debug/debug.h" | 5 #include "src/debug/debug.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 | 8 |
| 9 #include "src/api.h" | 9 #include "src/api.h" |
| 10 #include "src/arguments.h" | 10 #include "src/arguments.h" |
| 11 #include "src/bootstrapper.h" | 11 #include "src/bootstrapper.h" |
| 12 #include "src/code-stubs.h" | 12 #include "src/code-stubs.h" |
| 13 #include "src/codegen.h" | 13 #include "src/codegen.h" |
| 14 #include "src/compilation-cache.h" | 14 #include "src/compilation-cache.h" |
| 15 #include "src/compiler-dispatcher/optimizing-compile-dispatcher.h" | 15 #include "src/compiler-dispatcher/optimizing-compile-dispatcher.h" |
| 16 #include "src/compiler.h" | 16 #include "src/compiler.h" |
| 17 #include "src/debug/debug-evaluate.h" |
| 17 #include "src/debug/liveedit.h" | 18 #include "src/debug/liveedit.h" |
| 18 #include "src/deoptimizer.h" | 19 #include "src/deoptimizer.h" |
| 19 #include "src/execution.h" | 20 #include "src/execution.h" |
| 20 #include "src/frames-inl.h" | 21 #include "src/frames-inl.h" |
| 21 #include "src/full-codegen/full-codegen.h" | 22 #include "src/full-codegen/full-codegen.h" |
| 22 #include "src/global-handles.h" | 23 #include "src/global-handles.h" |
| 23 #include "src/globals.h" | 24 #include "src/globals.h" |
| 24 #include "src/interpreter/interpreter.h" | 25 #include "src/interpreter/interpreter.h" |
| 25 #include "src/isolate-inl.h" | 26 #include "src/isolate-inl.h" |
| 26 #include "src/list.h" | 27 #include "src/list.h" |
| 27 #include "src/log.h" | 28 #include "src/log.h" |
| 28 #include "src/messages.h" | 29 #include "src/messages.h" |
| 29 #include "src/snapshot/natives.h" | 30 #include "src/snapshot/natives.h" |
| 30 #include "src/wasm/wasm-module.h" | 31 #include "src/wasm/wasm-module.h" |
| 31 | 32 |
| 32 #include "include/v8-debug.h" | 33 #include "include/v8-debug.h" |
| 33 | 34 |
| 34 namespace v8 { | 35 namespace v8 { |
| 35 namespace internal { | 36 namespace internal { |
| 36 | 37 |
| 37 Debug::Debug(Isolate* isolate) | 38 Debug::Debug(Isolate* isolate) |
| 38 : debug_context_(Handle<Context>()), | 39 : debug_context_(Handle<Context>()), |
| 39 event_listener_(Handle<Object>()), | 40 event_listener_(Handle<Object>()), |
| 40 event_listener_data_(Handle<Object>()), | 41 event_listener_data_(Handle<Object>()), |
| 41 message_handler_(NULL), | 42 message_handler_(NULL), |
| 42 command_received_(0), | 43 command_received_(0), |
| 43 command_queue_(isolate->logger(), kQueueInitialSize), | 44 command_queue_(isolate->logger(), kQueueInitialSize), |
| 44 is_active_(false), | 45 is_active_(false), |
| 46 hook_on_function_call_(false), |
| 45 is_suppressed_(false), | 47 is_suppressed_(false), |
| 46 live_edit_enabled_(true), // TODO(yangguo): set to false by default. | 48 live_edit_enabled_(true), // TODO(yangguo): set to false by default. |
| 47 break_disabled_(false), | 49 break_disabled_(false), |
| 48 break_points_active_(true), | 50 break_points_active_(true), |
| 49 in_debug_event_listener_(false), | 51 in_debug_event_listener_(false), |
| 50 break_on_exception_(false), | 52 break_on_exception_(false), |
| 51 break_on_uncaught_exception_(false), | 53 break_on_uncaught_exception_(false), |
| 54 side_effect_check_failed_(false), |
| 52 debug_info_list_(NULL), | 55 debug_info_list_(NULL), |
| 53 feature_tracker_(isolate), | 56 feature_tracker_(isolate), |
| 54 isolate_(isolate) { | 57 isolate_(isolate) { |
| 55 ThreadInit(); | 58 ThreadInit(); |
| 56 } | 59 } |
| 57 | 60 |
| 58 BreakLocation BreakLocation::FromFrame(Handle<DebugInfo> debug_info, | 61 BreakLocation BreakLocation::FromFrame(Handle<DebugInfo> debug_info, |
| 59 JavaScriptFrame* frame) { | 62 JavaScriptFrame* frame) { |
| 60 FrameSummary summary = FrameSummary::GetFirst(frame); | 63 FrameSummary summary = FrameSummary::GetFirst(frame); |
| 61 int offset = summary.code_offset(); | 64 int offset = summary.code_offset(); |
| (...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 399 thread_local_.last_step_action_ = StepNone; | 402 thread_local_.last_step_action_ = StepNone; |
| 400 thread_local_.last_statement_position_ = kNoSourcePosition; | 403 thread_local_.last_statement_position_ = kNoSourcePosition; |
| 401 thread_local_.last_fp_ = 0; | 404 thread_local_.last_fp_ = 0; |
| 402 thread_local_.target_fp_ = 0; | 405 thread_local_.target_fp_ = 0; |
| 403 thread_local_.return_value_ = Handle<Object>(); | 406 thread_local_.return_value_ = Handle<Object>(); |
| 404 thread_local_.async_task_count_ = 0; | 407 thread_local_.async_task_count_ = 0; |
| 405 clear_suspended_generator(); | 408 clear_suspended_generator(); |
| 406 // TODO(isolates): frames_are_dropped_? | 409 // TODO(isolates): frames_are_dropped_? |
| 407 base::NoBarrier_Store(&thread_local_.current_debug_scope_, | 410 base::NoBarrier_Store(&thread_local_.current_debug_scope_, |
| 408 static_cast<base::AtomicWord>(0)); | 411 static_cast<base::AtomicWord>(0)); |
| 412 UpdateHookOnFunctionCall(); |
| 409 } | 413 } |
| 410 | 414 |
| 411 | 415 |
| 412 char* Debug::ArchiveDebug(char* storage) { | 416 char* Debug::ArchiveDebug(char* storage) { |
| 413 // Simply reset state. Don't archive anything. | 417 // Simply reset state. Don't archive anything. |
| 414 ThreadInit(); | 418 ThreadInit(); |
| 415 return storage + ArchiveSpacePerThread(); | 419 return storage + ArchiveSpacePerThread(); |
| 416 } | 420 } |
| 417 | 421 |
| 418 | 422 |
| (...skipping 479 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 898 if (type == BreakUncaughtException) { | 902 if (type == BreakUncaughtException) { |
| 899 return break_on_uncaught_exception_; | 903 return break_on_uncaught_exception_; |
| 900 } else { | 904 } else { |
| 901 return break_on_exception_; | 905 return break_on_exception_; |
| 902 } | 906 } |
| 903 } | 907 } |
| 904 | 908 |
| 905 | 909 |
| 906 void Debug::PrepareStepIn(Handle<JSFunction> function) { | 910 void Debug::PrepareStepIn(Handle<JSFunction> function) { |
| 907 CHECK(last_step_action() >= StepIn); | 911 CHECK(last_step_action() >= StepIn); |
| 908 if (!is_active()) return; | 912 if (ignore_events()) return; |
| 909 if (in_debug_scope()) return; | 913 if (in_debug_scope()) return; |
| 914 if (break_disabled()) return; |
| 910 FloodWithOneShot(function); | 915 FloodWithOneShot(function); |
| 911 } | 916 } |
| 912 | 917 |
| 913 void Debug::PrepareStepInSuspendedGenerator() { | 918 void Debug::PrepareStepInSuspendedGenerator() { |
| 914 CHECK(has_suspended_generator()); | 919 CHECK(has_suspended_generator()); |
| 915 if (!is_active()) return; | 920 if (ignore_events()) return; |
| 916 if (in_debug_scope()) return; | 921 if (in_debug_scope()) return; |
| 922 if (break_disabled()) return; |
| 917 thread_local_.last_step_action_ = StepIn; | 923 thread_local_.last_step_action_ = StepIn; |
| 924 UpdateHookOnFunctionCall(); |
| 918 Handle<JSFunction> function( | 925 Handle<JSFunction> function( |
| 919 JSGeneratorObject::cast(thread_local_.suspended_generator_)->function()); | 926 JSGeneratorObject::cast(thread_local_.suspended_generator_)->function()); |
| 920 FloodWithOneShot(function); | 927 FloodWithOneShot(function); |
| 921 clear_suspended_generator(); | 928 clear_suspended_generator(); |
| 922 } | 929 } |
| 923 | 930 |
| 924 void Debug::PrepareStepOnThrow() { | 931 void Debug::PrepareStepOnThrow() { |
| 925 if (!is_active()) return; | |
| 926 if (last_step_action() == StepNone) return; | 932 if (last_step_action() == StepNone) return; |
| 933 if (ignore_events()) return; |
| 927 if (in_debug_scope()) return; | 934 if (in_debug_scope()) return; |
| 935 if (break_disabled()) return; |
| 928 | 936 |
| 929 ClearOneShot(); | 937 ClearOneShot(); |
| 930 | 938 |
| 931 // Iterate through the JavaScript stack looking for handlers. | 939 // Iterate through the JavaScript stack looking for handlers. |
| 932 JavaScriptFrameIterator it(isolate_); | 940 JavaScriptFrameIterator it(isolate_); |
| 933 while (!it.done()) { | 941 while (!it.done()) { |
| 934 JavaScriptFrame* frame = it.frame(); | 942 JavaScriptFrame* frame = it.frame(); |
| 935 if (frame->LookupExceptionHandlerInTable(nullptr, nullptr) > 0) break; | 943 if (frame->LookupExceptionHandlerInTable(nullptr, nullptr) > 0) break; |
| 936 it.Advance(); | 944 it.Advance(); |
| 937 } | 945 } |
| (...skipping 30 matching lines...) Expand all Loading... |
| 968 StackFrame::Id frame_id = break_frame_id(); | 976 StackFrame::Id frame_id = break_frame_id(); |
| 969 // If there is no JavaScript stack don't do anything. | 977 // If there is no JavaScript stack don't do anything. |
| 970 if (frame_id == StackFrame::NO_ID) return; | 978 if (frame_id == StackFrame::NO_ID) return; |
| 971 | 979 |
| 972 JavaScriptFrameIterator frames_it(isolate_, frame_id); | 980 JavaScriptFrameIterator frames_it(isolate_, frame_id); |
| 973 JavaScriptFrame* frame = frames_it.frame(); | 981 JavaScriptFrame* frame = frames_it.frame(); |
| 974 | 982 |
| 975 feature_tracker()->Track(DebugFeatureTracker::kStepping); | 983 feature_tracker()->Track(DebugFeatureTracker::kStepping); |
| 976 | 984 |
| 977 thread_local_.last_step_action_ = step_action; | 985 thread_local_.last_step_action_ = step_action; |
| 986 UpdateHookOnFunctionCall(); |
| 978 | 987 |
| 979 // If the function on the top frame is unresolved perform step out. This will | 988 // If the function on the top frame is unresolved perform step out. This will |
| 980 // be the case when calling unknown function and having the debugger stopped | 989 // be the case when calling unknown function and having the debugger stopped |
| 981 // in an unhandled exception. | 990 // in an unhandled exception. |
| 982 if (!frame->function()->IsJSFunction()) { | 991 if (!frame->function()->IsJSFunction()) { |
| 983 // Step out: Find the calling JavaScript frame and flood it with | 992 // Step out: Find the calling JavaScript frame and flood it with |
| 984 // breakpoints. | 993 // breakpoints. |
| 985 frames_it.Advance(); | 994 frames_it.Advance(); |
| 986 // Fill the function to return to with one-shot break points. | 995 // Fill the function to return to with one-shot break points. |
| 987 JSFunction* function = frames_it.frame()->function(); | 996 JSFunction* function = frames_it.frame()->function(); |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1098 } | 1107 } |
| 1099 | 1108 |
| 1100 void Debug::ClearStepping() { | 1109 void Debug::ClearStepping() { |
| 1101 // Clear the various stepping setup. | 1110 // Clear the various stepping setup. |
| 1102 ClearOneShot(); | 1111 ClearOneShot(); |
| 1103 | 1112 |
| 1104 thread_local_.last_step_action_ = StepNone; | 1113 thread_local_.last_step_action_ = StepNone; |
| 1105 thread_local_.last_statement_position_ = kNoSourcePosition; | 1114 thread_local_.last_statement_position_ = kNoSourcePosition; |
| 1106 thread_local_.last_fp_ = 0; | 1115 thread_local_.last_fp_ = 0; |
| 1107 thread_local_.target_fp_ = 0; | 1116 thread_local_.target_fp_ = 0; |
| 1117 UpdateHookOnFunctionCall(); |
| 1108 } | 1118 } |
| 1109 | 1119 |
| 1110 | 1120 |
| 1111 // Clears all the one-shot break points that are currently set. Normally this | 1121 // Clears all the one-shot break points that are currently set. Normally this |
| 1112 // function is called each time a break point is hit as one shot break points | 1122 // function is called each time a break point is hit as one shot break points |
| 1113 // are used to support stepping. | 1123 // are used to support stepping. |
| 1114 void Debug::ClearOneShot() { | 1124 void Debug::ClearOneShot() { |
| 1115 // The current implementation just runs through all the breakpoints. When the | 1125 // The current implementation just runs through all the breakpoints. When the |
| 1116 // last break point for a function is removed that function is automatically | 1126 // last break point for a function is removed that function is automatically |
| 1117 // removed from the list. | 1127 // removed from the list. |
| (...skipping 1010 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2128 // bootstrap test cases. | 2138 // bootstrap test cases. |
| 2129 isolate_->compilation_cache()->Disable(); | 2139 isolate_->compilation_cache()->Disable(); |
| 2130 is_active = Load(); | 2140 is_active = Load(); |
| 2131 } else if (is_loaded()) { | 2141 } else if (is_loaded()) { |
| 2132 isolate_->compilation_cache()->Enable(); | 2142 isolate_->compilation_cache()->Enable(); |
| 2133 Unload(); | 2143 Unload(); |
| 2134 } | 2144 } |
| 2135 is_active_ = is_active; | 2145 is_active_ = is_active; |
| 2136 } | 2146 } |
| 2137 | 2147 |
| 2148 void Debug::UpdateHookOnFunctionCall() { |
| 2149 STATIC_ASSERT(StepFrame > StepIn); |
| 2150 STATIC_ASSERT(LastStepAction == StepFrame); |
| 2151 hook_on_function_call_ = thread_local_.last_step_action_ >= StepIn || |
| 2152 isolate_->needs_side_effect_check(); |
| 2153 } |
| 2154 |
| 2138 // Calls the registered debug message handler. This callback is part of the | 2155 // Calls the registered debug message handler. This callback is part of the |
| 2139 // public API. | 2156 // public API. |
| 2140 void Debug::InvokeMessageHandler(MessageImpl message) { | 2157 void Debug::InvokeMessageHandler(MessageImpl message) { |
| 2141 if (message_handler_ != NULL) message_handler_(message); | 2158 if (message_handler_ != NULL) message_handler_(message); |
| 2142 } | 2159 } |
| 2143 | 2160 |
| 2144 // Puts a command coming from the public API on the queue. Creates | 2161 // Puts a command coming from the public API on the queue. Creates |
| 2145 // a copy of the command string managed by the debugger. Up to this | 2162 // a copy of the command string managed by the debugger. Up to this |
| 2146 // point, the command data was managed by the API client. Called | 2163 // point, the command data was managed by the API client. Called |
| 2147 // by the API client thread. | 2164 // by the API client thread. |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2325 reinterpret_cast<base::AtomicWord>(prev_)); | 2342 reinterpret_cast<base::AtomicWord>(prev_)); |
| 2326 | 2343 |
| 2327 // Restore to the previous break state. | 2344 // Restore to the previous break state. |
| 2328 debug_->thread_local_.break_frame_id_ = break_frame_id_; | 2345 debug_->thread_local_.break_frame_id_ = break_frame_id_; |
| 2329 debug_->thread_local_.break_id_ = break_id_; | 2346 debug_->thread_local_.break_id_ = break_id_; |
| 2330 debug_->thread_local_.return_value_ = return_value_; | 2347 debug_->thread_local_.return_value_ = return_value_; |
| 2331 | 2348 |
| 2332 debug_->UpdateState(); | 2349 debug_->UpdateState(); |
| 2333 } | 2350 } |
| 2334 | 2351 |
| 2352 bool Debug::PerformSideEffectCheck(Handle<JSFunction> function) { |
| 2353 DCHECK(isolate_->needs_side_effect_check()); |
| 2354 DisallowJavascriptExecution no_js(isolate_); |
| 2355 if (!Compiler::Compile(function, Compiler::KEEP_EXCEPTION)) return false; |
| 2356 Deoptimizer::DeoptimizeFunction(*function); |
| 2357 if (!function->shared()->HasNoSideEffect()) { |
| 2358 if (FLAG_trace_side_effect_free_debug_evaluate) { |
| 2359 PrintF("[debug-evaluate] Function %s failed side effect check.\n", |
| 2360 function->shared()->DebugName()->ToCString().get()); |
| 2361 } |
| 2362 side_effect_check_failed_ = true; |
| 2363 // Throw an uncatchable termination exception. |
| 2364 isolate_->TerminateExecution(); |
| 2365 return false; |
| 2366 } |
| 2367 return true; |
| 2368 } |
| 2369 |
| 2370 bool Debug::PerformSideEffectCheckForCallback(Address function) { |
| 2371 DCHECK(isolate_->needs_side_effect_check()); |
| 2372 if (DebugEvaluate::CallbackHasNoSideEffect(function)) return true; |
| 2373 side_effect_check_failed_ = true; |
| 2374 // Throw an uncatchable termination exception. |
| 2375 isolate_->TerminateExecution(); |
| 2376 isolate_->OptionalRescheduleException(false); |
| 2377 return false; |
| 2378 } |
| 2379 |
| 2380 NoSideEffectScope::~NoSideEffectScope() { |
| 2381 if (isolate_->needs_side_effect_check() && |
| 2382 isolate_->debug()->side_effect_check_failed_) { |
| 2383 DCHECK(isolate_->has_pending_exception()); |
| 2384 DCHECK_EQ(isolate_->heap()->termination_exception(), |
| 2385 isolate_->pending_exception()); |
| 2386 // Convert the termination exception into a regular exception. |
| 2387 isolate_->CancelTerminateExecution(); |
| 2388 isolate_->Throw(*isolate_->factory()->NewEvalError( |
| 2389 MessageTemplate::kNoSideEffectDebugEvaluate)); |
| 2390 } |
| 2391 isolate_->set_needs_side_effect_check(old_needs_side_effect_check_); |
| 2392 isolate_->debug()->UpdateHookOnFunctionCall(); |
| 2393 isolate_->debug()->side_effect_check_failed_ = false; |
| 2394 } |
| 2395 |
| 2335 MessageImpl MessageImpl::NewEvent(DebugEvent event, bool running, | 2396 MessageImpl MessageImpl::NewEvent(DebugEvent event, bool running, |
| 2336 Handle<JSObject> exec_state, | 2397 Handle<JSObject> exec_state, |
| 2337 Handle<JSObject> event_data) { | 2398 Handle<JSObject> event_data) { |
| 2338 MessageImpl message(true, event, running, exec_state, event_data, | 2399 MessageImpl message(true, event, running, exec_state, event_data, |
| 2339 Handle<String>(), NULL); | 2400 Handle<String>(), NULL); |
| 2340 return message; | 2401 return message; |
| 2341 } | 2402 } |
| 2342 | 2403 |
| 2343 MessageImpl MessageImpl::NewResponse(DebugEvent event, bool running, | 2404 MessageImpl MessageImpl::NewResponse(DebugEvent event, bool running, |
| 2344 Handle<JSObject> exec_state, | 2405 Handle<JSObject> exec_state, |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2553 logger_->DebugEvent("Put", message.text()); | 2614 logger_->DebugEvent("Put", message.text()); |
| 2554 } | 2615 } |
| 2555 | 2616 |
| 2556 void LockingCommandMessageQueue::Clear() { | 2617 void LockingCommandMessageQueue::Clear() { |
| 2557 base::LockGuard<base::Mutex> lock_guard(&mutex_); | 2618 base::LockGuard<base::Mutex> lock_guard(&mutex_); |
| 2558 queue_.Clear(); | 2619 queue_.Clear(); |
| 2559 } | 2620 } |
| 2560 | 2621 |
| 2561 } // namespace internal | 2622 } // namespace internal |
| 2562 } // namespace v8 | 2623 } // namespace v8 |
| OLD | NEW |