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 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
398 thread_local_.break_frame_id_ = StackFrame::NO_ID; | 401 thread_local_.break_frame_id_ = StackFrame::NO_ID; |
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 clear_suspended_generator(); | 407 clear_suspended_generator(); |
405 // TODO(isolates): frames_are_dropped_? | 408 // TODO(isolates): frames_are_dropped_? |
406 base::NoBarrier_Store(&thread_local_.current_debug_scope_, | 409 base::NoBarrier_Store(&thread_local_.current_debug_scope_, |
407 static_cast<base::AtomicWord>(0)); | 410 static_cast<base::AtomicWord>(0)); |
411 UpdateHookOnFunctionCall(); | |
408 } | 412 } |
409 | 413 |
410 | 414 |
411 char* Debug::ArchiveDebug(char* storage) { | 415 char* Debug::ArchiveDebug(char* storage) { |
412 // Simply reset state. Don't archive anything. | 416 // Simply reset state. Don't archive anything. |
413 ThreadInit(); | 417 ThreadInit(); |
414 return storage + ArchiveSpacePerThread(); | 418 return storage + ArchiveSpacePerThread(); |
415 } | 419 } |
416 | 420 |
417 | 421 |
(...skipping 479 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
897 if (type == BreakUncaughtException) { | 901 if (type == BreakUncaughtException) { |
898 return break_on_uncaught_exception_; | 902 return break_on_uncaught_exception_; |
899 } else { | 903 } else { |
900 return break_on_exception_; | 904 return break_on_exception_; |
901 } | 905 } |
902 } | 906 } |
903 | 907 |
904 | 908 |
905 void Debug::PrepareStepIn(Handle<JSFunction> function) { | 909 void Debug::PrepareStepIn(Handle<JSFunction> function) { |
906 CHECK(last_step_action() >= StepIn); | 910 CHECK(last_step_action() >= StepIn); |
907 if (!is_active()) return; | 911 if (ignore_events()) return; |
908 if (in_debug_scope()) return; | 912 if (in_debug_scope()) return; |
913 if (break_disabled()) return; | |
909 FloodWithOneShot(function); | 914 FloodWithOneShot(function); |
910 } | 915 } |
911 | 916 |
912 void Debug::PrepareStepInSuspendedGenerator() { | 917 void Debug::PrepareStepInSuspendedGenerator() { |
913 CHECK(has_suspended_generator()); | 918 CHECK(has_suspended_generator()); |
914 if (!is_active()) return; | 919 if (ignore_events()) return; |
915 if (in_debug_scope()) return; | 920 if (in_debug_scope()) return; |
921 if (break_disabled()) return; | |
916 thread_local_.last_step_action_ = StepIn; | 922 thread_local_.last_step_action_ = StepIn; |
923 UpdateHookOnFunctionCall(); | |
917 Handle<JSFunction> function( | 924 Handle<JSFunction> function( |
918 JSGeneratorObject::cast(thread_local_.suspended_generator_)->function()); | 925 JSGeneratorObject::cast(thread_local_.suspended_generator_)->function()); |
919 FloodWithOneShot(function); | 926 FloodWithOneShot(function); |
920 clear_suspended_generator(); | 927 clear_suspended_generator(); |
921 } | 928 } |
922 | 929 |
923 void Debug::PrepareStepOnThrow() { | 930 void Debug::PrepareStepOnThrow() { |
924 if (!is_active()) return; | |
925 if (last_step_action() == StepNone) return; | 931 if (last_step_action() == StepNone) return; |
932 if (ignore_events()) return; | |
926 if (in_debug_scope()) return; | 933 if (in_debug_scope()) return; |
934 if (break_disabled()) return; | |
927 | 935 |
928 ClearOneShot(); | 936 ClearOneShot(); |
929 | 937 |
930 // Iterate through the JavaScript stack looking for handlers. | 938 // Iterate through the JavaScript stack looking for handlers. |
931 JavaScriptFrameIterator it(isolate_); | 939 JavaScriptFrameIterator it(isolate_); |
932 while (!it.done()) { | 940 while (!it.done()) { |
933 JavaScriptFrame* frame = it.frame(); | 941 JavaScriptFrame* frame = it.frame(); |
934 if (frame->LookupExceptionHandlerInTable(nullptr, nullptr) > 0) break; | 942 if (frame->LookupExceptionHandlerInTable(nullptr, nullptr) > 0) break; |
935 it.Advance(); | 943 it.Advance(); |
936 } | 944 } |
(...skipping 30 matching lines...) Expand all Loading... | |
967 StackFrame::Id frame_id = break_frame_id(); | 975 StackFrame::Id frame_id = break_frame_id(); |
968 // If there is no JavaScript stack don't do anything. | 976 // If there is no JavaScript stack don't do anything. |
969 if (frame_id == StackFrame::NO_ID) return; | 977 if (frame_id == StackFrame::NO_ID) return; |
970 | 978 |
971 JavaScriptFrameIterator frames_it(isolate_, frame_id); | 979 JavaScriptFrameIterator frames_it(isolate_, frame_id); |
972 JavaScriptFrame* frame = frames_it.frame(); | 980 JavaScriptFrame* frame = frames_it.frame(); |
973 | 981 |
974 feature_tracker()->Track(DebugFeatureTracker::kStepping); | 982 feature_tracker()->Track(DebugFeatureTracker::kStepping); |
975 | 983 |
976 thread_local_.last_step_action_ = step_action; | 984 thread_local_.last_step_action_ = step_action; |
985 UpdateHookOnFunctionCall(); | |
977 | 986 |
978 // If the function on the top frame is unresolved perform step out. This will | 987 // If the function on the top frame is unresolved perform step out. This will |
979 // be the case when calling unknown function and having the debugger stopped | 988 // be the case when calling unknown function and having the debugger stopped |
980 // in an unhandled exception. | 989 // in an unhandled exception. |
981 if (!frame->function()->IsJSFunction()) { | 990 if (!frame->function()->IsJSFunction()) { |
982 // Step out: Find the calling JavaScript frame and flood it with | 991 // Step out: Find the calling JavaScript frame and flood it with |
983 // breakpoints. | 992 // breakpoints. |
984 frames_it.Advance(); | 993 frames_it.Advance(); |
985 // Fill the function to return to with one-shot break points. | 994 // Fill the function to return to with one-shot break points. |
986 JSFunction* function = frames_it.frame()->function(); | 995 JSFunction* function = frames_it.frame()->function(); |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1097 } | 1106 } |
1098 | 1107 |
1099 void Debug::ClearStepping() { | 1108 void Debug::ClearStepping() { |
1100 // Clear the various stepping setup. | 1109 // Clear the various stepping setup. |
1101 ClearOneShot(); | 1110 ClearOneShot(); |
1102 | 1111 |
1103 thread_local_.last_step_action_ = StepNone; | 1112 thread_local_.last_step_action_ = StepNone; |
1104 thread_local_.last_statement_position_ = kNoSourcePosition; | 1113 thread_local_.last_statement_position_ = kNoSourcePosition; |
1105 thread_local_.last_fp_ = 0; | 1114 thread_local_.last_fp_ = 0; |
1106 thread_local_.target_fp_ = 0; | 1115 thread_local_.target_fp_ = 0; |
1116 UpdateHookOnFunctionCall(); | |
1107 } | 1117 } |
1108 | 1118 |
1109 | 1119 |
1110 // Clears all the one-shot break points that are currently set. Normally this | 1120 // Clears all the one-shot break points that are currently set. Normally this |
1111 // function is called each time a break point is hit as one shot break points | 1121 // function is called each time a break point is hit as one shot break points |
1112 // are used to support stepping. | 1122 // are used to support stepping. |
1113 void Debug::ClearOneShot() { | 1123 void Debug::ClearOneShot() { |
1114 // The current implementation just runs through all the breakpoints. When the | 1124 // The current implementation just runs through all the breakpoints. When the |
1115 // last break point for a function is removed that function is automatically | 1125 // last break point for a function is removed that function is automatically |
1116 // removed from the list. | 1126 // removed from the list. |
(...skipping 954 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2071 // bootstrap test cases. | 2081 // bootstrap test cases. |
2072 isolate_->compilation_cache()->Disable(); | 2082 isolate_->compilation_cache()->Disable(); |
2073 is_active = Load(); | 2083 is_active = Load(); |
2074 } else if (is_loaded()) { | 2084 } else if (is_loaded()) { |
2075 isolate_->compilation_cache()->Enable(); | 2085 isolate_->compilation_cache()->Enable(); |
2076 Unload(); | 2086 Unload(); |
2077 } | 2087 } |
2078 is_active_ = is_active; | 2088 is_active_ = is_active; |
2079 } | 2089 } |
2080 | 2090 |
2091 void Debug::UpdateHookOnFunctionCall() { | |
2092 STATIC_ASSERT(StepFrame > StepIn); | |
2093 STATIC_ASSERT(LastStepAction == StepFrame); | |
2094 hook_on_function_call_ = thread_local_.last_step_action_ >= StepIn || | |
2095 isolate_->needs_side_effect_check(); | |
2096 } | |
2097 | |
2081 // Calls the registered debug message handler. This callback is part of the | 2098 // Calls the registered debug message handler. This callback is part of the |
2082 // public API. | 2099 // public API. |
2083 void Debug::InvokeMessageHandler(MessageImpl message) { | 2100 void Debug::InvokeMessageHandler(MessageImpl message) { |
2084 if (message_handler_ != NULL) message_handler_(message); | 2101 if (message_handler_ != NULL) message_handler_(message); |
2085 } | 2102 } |
2086 | 2103 |
2087 // Puts a command coming from the public API on the queue. Creates | 2104 // Puts a command coming from the public API on the queue. Creates |
2088 // a copy of the command string managed by the debugger. Up to this | 2105 // a copy of the command string managed by the debugger. Up to this |
2089 // point, the command data was managed by the API client. Called | 2106 // point, the command data was managed by the API client. Called |
2090 // by the API client thread. | 2107 // by the API client thread. |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2268 reinterpret_cast<base::AtomicWord>(prev_)); | 2285 reinterpret_cast<base::AtomicWord>(prev_)); |
2269 | 2286 |
2270 // Restore to the previous break state. | 2287 // Restore to the previous break state. |
2271 debug_->thread_local_.break_frame_id_ = break_frame_id_; | 2288 debug_->thread_local_.break_frame_id_ = break_frame_id_; |
2272 debug_->thread_local_.break_id_ = break_id_; | 2289 debug_->thread_local_.break_id_ = break_id_; |
2273 debug_->thread_local_.return_value_ = return_value_; | 2290 debug_->thread_local_.return_value_ = return_value_; |
2274 | 2291 |
2275 debug_->UpdateState(); | 2292 debug_->UpdateState(); |
2276 } | 2293 } |
2277 | 2294 |
2295 bool Debug::PerformSideEffectCheck(Handle<JSFunction> function) { | |
jgruber
2017/01/11 16:12:39
Double-checking: I suppose this can never be enter
Yang
2017/01/12 06:04:51
Yup. Now guarding that too.
| |
2296 DCHECK(isolate_->needs_side_effect_check()); | |
2297 if (!Compiler::Compile(function, Compiler::KEEP_EXCEPTION)) return false; | |
2298 Deoptimizer::DeoptimizeFunction(*function); | |
2299 if (!function->shared()->HasNoSideEffect()) { | |
2300 if (FLAG_trace_side_effect_free_debug_evaluate) { | |
2301 PrintF("[debug-evaluate] Function %s failed side effect check.\n", | |
2302 function->shared()->DebugName()->ToCString().get()); | |
2303 } | |
2304 side_effect_check_failed_ = true; | |
2305 // Throw an uncatchable termination exception. | |
2306 isolate_->TerminateExecution(); | |
2307 return false; | |
2308 } | |
2309 return true; | |
2310 } | |
2311 | |
2312 bool Debug::PerformSideEffectCheckForCallback(Address function) { | |
2313 DCHECK(isolate_->needs_side_effect_check()); | |
2314 if (DebugEvaluate::CallbackHasNoSideEffect(function)) return true; | |
2315 side_effect_check_failed_ = true; | |
2316 // Throw an uncatchable termination exception. | |
2317 isolate_->TerminateExecution(); | |
2318 isolate_->OptionalRescheduleException(false); | |
2319 return false; | |
2320 } | |
2321 | |
2322 NoSideEffectScope::~NoSideEffectScope() { | |
2323 if (isolate_->needs_side_effect_check() && | |
2324 isolate_->debug()->side_effect_check_failed_) { | |
2325 DCHECK(isolate_->has_pending_exception()); | |
2326 DCHECK_EQ(isolate_->heap()->termination_exception(), | |
2327 isolate_->pending_exception()); | |
2328 // Convert the termination exception into a regular exception. | |
2329 isolate_->CancelTerminateExecution(); | |
2330 isolate_->Throw(*isolate_->factory()->NewEvalError( | |
2331 MessageTemplate::kNoSideEffectDebugEvaluate)); | |
2332 } | |
2333 isolate_->set_needs_side_effect_check(old_needs_side_effect_check_); | |
2334 isolate_->debug()->UpdateHookOnFunctionCall(); | |
2335 isolate_->debug()->side_effect_check_failed_ = false; | |
2336 } | |
2337 | |
2278 MessageImpl MessageImpl::NewEvent(DebugEvent event, bool running, | 2338 MessageImpl MessageImpl::NewEvent(DebugEvent event, bool running, |
2279 Handle<JSObject> exec_state, | 2339 Handle<JSObject> exec_state, |
2280 Handle<JSObject> event_data) { | 2340 Handle<JSObject> event_data) { |
2281 MessageImpl message(true, event, running, exec_state, event_data, | 2341 MessageImpl message(true, event, running, exec_state, event_data, |
2282 Handle<String>(), NULL); | 2342 Handle<String>(), NULL); |
2283 return message; | 2343 return message; |
2284 } | 2344 } |
2285 | 2345 |
2286 MessageImpl MessageImpl::NewResponse(DebugEvent event, bool running, | 2346 MessageImpl MessageImpl::NewResponse(DebugEvent event, bool running, |
2287 Handle<JSObject> exec_state, | 2347 Handle<JSObject> exec_state, |
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2496 logger_->DebugEvent("Put", message.text()); | 2556 logger_->DebugEvent("Put", message.text()); |
2497 } | 2557 } |
2498 | 2558 |
2499 void LockingCommandMessageQueue::Clear() { | 2559 void LockingCommandMessageQueue::Clear() { |
2500 base::LockGuard<base::Mutex> lock_guard(&mutex_); | 2560 base::LockGuard<base::Mutex> lock_guard(&mutex_); |
2501 queue_.Clear(); | 2561 queue_.Clear(); |
2502 } | 2562 } |
2503 | 2563 |
2504 } // namespace internal | 2564 } // namespace internal |
2505 } // namespace v8 | 2565 } // namespace v8 |
OLD | NEW |