Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(70)

Side by Side Diff: src/debug/debug.cc

Issue 2622863003: [debugger] infrastructure for side-effect-free debug-evaluate. (Closed)
Patch Set: Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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"
(...skipping 24 matching lines...) Expand all
35 namespace internal { 35 namespace internal {
36 36
37 Debug::Debug(Isolate* isolate) 37 Debug::Debug(Isolate* isolate)
38 : debug_context_(Handle<Context>()), 38 : debug_context_(Handle<Context>()),
39 event_listener_(Handle<Object>()), 39 event_listener_(Handle<Object>()),
40 event_listener_data_(Handle<Object>()), 40 event_listener_data_(Handle<Object>()),
41 message_handler_(NULL), 41 message_handler_(NULL),
42 command_received_(0), 42 command_received_(0),
43 command_queue_(isolate->logger(), kQueueInitialSize), 43 command_queue_(isolate->logger(), kQueueInitialSize),
44 is_active_(false), 44 is_active_(false),
45 hook_on_function_call_(false),
45 is_suppressed_(false), 46 is_suppressed_(false),
46 live_edit_enabled_(true), // TODO(yangguo): set to false by default. 47 live_edit_enabled_(true), // TODO(yangguo): set to false by default.
47 break_disabled_(false), 48 break_disabled_(false),
48 break_points_active_(true), 49 break_points_active_(true),
49 in_debug_event_listener_(false), 50 in_debug_event_listener_(false),
50 break_on_exception_(false), 51 break_on_exception_(false),
51 break_on_uncaught_exception_(false), 52 break_on_uncaught_exception_(false),
53 needs_readonly_check_(false),
54 readonly_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
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
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
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
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
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 hook_on_function_call_ =
2093 thread_local_.last_step_action_ >= StepIn || needs_readonly_check_;
2094 }
2095
2081 // Calls the registered debug message handler. This callback is part of the 2096 // Calls the registered debug message handler. This callback is part of the
2082 // public API. 2097 // public API.
2083 void Debug::InvokeMessageHandler(MessageImpl message) { 2098 void Debug::InvokeMessageHandler(MessageImpl message) {
2084 if (message_handler_ != NULL) message_handler_(message); 2099 if (message_handler_ != NULL) message_handler_(message);
2085 } 2100 }
2086 2101
2087 // Puts a command coming from the public API on the queue. Creates 2102 // 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 2103 // 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 2104 // point, the command data was managed by the API client. Called
2090 // by the API client thread. 2105 // by the API client thread.
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after
2268 reinterpret_cast<base::AtomicWord>(prev_)); 2283 reinterpret_cast<base::AtomicWord>(prev_));
2269 2284
2270 // Restore to the previous break state. 2285 // Restore to the previous break state.
2271 debug_->thread_local_.break_frame_id_ = break_frame_id_; 2286 debug_->thread_local_.break_frame_id_ = break_frame_id_;
2272 debug_->thread_local_.break_id_ = break_id_; 2287 debug_->thread_local_.break_id_ = break_id_;
2273 debug_->thread_local_.return_value_ = return_value_; 2288 debug_->thread_local_.return_value_ = return_value_;
2274 2289
2275 debug_->UpdateState(); 2290 debug_->UpdateState();
2276 } 2291 }
2277 2292
2293 bool Debug::PerformReadOnlyCheck(Handle<JSFunction> function) {
2294 DCHECK(needs_readonly_check_);
2295 if (!Compiler::Compile(function, Compiler::KEEP_EXCEPTION)) return false;
2296 Deoptimizer::DeoptimizeFunction(*function);
2297 if (!function->shared()->IsReadOnly()) {
2298 if (FLAG_trace_readonly_debug_evaluate) {
2299 PrintF("[ro] Function %s failed read-only check.\n",
2300 function->shared()->DebugName()->ToCString().get());
2301 }
2302 readonly_check_failed_ = true;
2303 // Throw an uncatchable termination exception.
2304 isolate_->TerminateExecution();
2305 return false;
2306 }
2307 return true;
2308 }
2309
2310 ReadOnlyEvaluate::~ReadOnlyEvaluate() {
2311 debug_->needs_readonly_check_ = old_state_;
2312 debug_->UpdateHookOnFunctionCall();
2313 Isolate* isolate = debug_->isolate_;
2314 if (debug_->readonly_check_failed_ && isolate->has_pending_exception() &&
jgruber 2017/01/10 12:46:37 Doesn't readonly_check_failed_ imply the remaining
Yang 2017/01/10 14:14:06 Done.
2315 isolate->pending_exception() ==
2316 isolate->heap()->termination_exception()) {
2317 // Convert the termination exception into a regular exception.
2318 isolate->CancelTerminateExecution();
2319 isolate->Throw(*isolate->factory()->NewEvalError(
2320 MessageTemplate::kReadOnlyDebugEvaluate));
2321 }
2322 debug_->readonly_check_failed_ = false;
2323 }
2324
2278 MessageImpl MessageImpl::NewEvent(DebugEvent event, bool running, 2325 MessageImpl MessageImpl::NewEvent(DebugEvent event, bool running,
2279 Handle<JSObject> exec_state, 2326 Handle<JSObject> exec_state,
2280 Handle<JSObject> event_data) { 2327 Handle<JSObject> event_data) {
2281 MessageImpl message(true, event, running, exec_state, event_data, 2328 MessageImpl message(true, event, running, exec_state, event_data,
2282 Handle<String>(), NULL); 2329 Handle<String>(), NULL);
2283 return message; 2330 return message;
2284 } 2331 }
2285 2332
2286 MessageImpl MessageImpl::NewResponse(DebugEvent event, bool running, 2333 MessageImpl MessageImpl::NewResponse(DebugEvent event, bool running,
2287 Handle<JSObject> exec_state, 2334 Handle<JSObject> exec_state,
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after
2496 logger_->DebugEvent("Put", message.text()); 2543 logger_->DebugEvent("Put", message.text());
2497 } 2544 }
2498 2545
2499 void LockingCommandMessageQueue::Clear() { 2546 void LockingCommandMessageQueue::Clear() {
2500 base::LockGuard<base::Mutex> lock_guard(&mutex_); 2547 base::LockGuard<base::Mutex> lock_guard(&mutex_);
2501 queue_.Clear(); 2548 queue_.Clear();
2502 } 2549 }
2503 2550
2504 } // namespace internal 2551 } // namespace internal
2505 } // namespace v8 2552 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698