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 |