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

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

Issue 2758483002: [debugger] tuned StepNext and StepOut at return position (Closed)
Patch Set: addressed comments Created 3 years, 9 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
« no previous file with comments | « src/debug/debug.h ('k') | src/runtime/runtime-debug.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 371 matching lines...) Expand 10 before | Expand all | Expand 10 after
382 382
383 383
384 // Threading support. 384 // Threading support.
385 void Debug::ThreadInit() { 385 void Debug::ThreadInit() {
386 thread_local_.break_count_ = 0; 386 thread_local_.break_count_ = 0;
387 thread_local_.break_id_ = 0; 387 thread_local_.break_id_ = 0;
388 thread_local_.break_frame_id_ = StackFrame::NO_ID; 388 thread_local_.break_frame_id_ = StackFrame::NO_ID;
389 thread_local_.last_step_action_ = StepNone; 389 thread_local_.last_step_action_ = StepNone;
390 thread_local_.last_statement_position_ = kNoSourcePosition; 390 thread_local_.last_statement_position_ = kNoSourcePosition;
391 thread_local_.last_frame_count_ = -1; 391 thread_local_.last_frame_count_ = -1;
392 thread_local_.ignore_next_stepping_break_ = false;
393 thread_local_.ignore_step_into_function_ = Smi::kZero;
394 thread_local_.step_into_function_call_requested_ = false;
392 thread_local_.target_frame_count_ = -1; 395 thread_local_.target_frame_count_ = -1;
393 thread_local_.return_value_ = Smi::kZero; 396 thread_local_.return_value_ = Smi::kZero;
394 thread_local_.async_task_count_ = 0; 397 thread_local_.async_task_count_ = 0;
395 clear_suspended_generator(); 398 clear_suspended_generator();
396 thread_local_.restart_fp_ = nullptr; 399 thread_local_.restart_fp_ = nullptr;
397 base::NoBarrier_Store(&thread_local_.current_debug_scope_, 400 base::NoBarrier_Store(&thread_local_.current_debug_scope_,
398 static_cast<base::AtomicWord>(0)); 401 static_cast<base::AtomicWord>(0));
399 UpdateHookOnFunctionCall(); 402 UpdateHookOnFunctionCall();
400 } 403 }
401 404
402 405
403 char* Debug::ArchiveDebug(char* storage) { 406 char* Debug::ArchiveDebug(char* storage) {
404 // Simply reset state. Don't archive anything. 407 // Simply reset state. Don't archive anything.
405 ThreadInit(); 408 ThreadInit();
406 return storage + ArchiveSpacePerThread(); 409 return storage + ArchiveSpacePerThread();
407 } 410 }
408 411
409 412
410 char* Debug::RestoreDebug(char* storage) { 413 char* Debug::RestoreDebug(char* storage) {
411 // Simply reset state. Don't restore anything. 414 // Simply reset state. Don't restore anything.
412 ThreadInit(); 415 ThreadInit();
413 return storage + ArchiveSpacePerThread(); 416 return storage + ArchiveSpacePerThread();
414 } 417 }
415 418
416 int Debug::ArchiveSpacePerThread() { return 0; } 419 int Debug::ArchiveSpacePerThread() { return 0; }
417 420
418 void Debug::Iterate(ObjectVisitor* v) { 421 void Debug::Iterate(ObjectVisitor* v) {
419 v->VisitPointer(&thread_local_.return_value_); 422 v->VisitPointer(&thread_local_.return_value_);
420 v->VisitPointer(&thread_local_.suspended_generator_); 423 v->VisitPointer(&thread_local_.suspended_generator_);
Yang 2017/03/21 13:13:52 You need to iterate ignore_step_into_function_, or
kozy 2017/03/21 16:03:11 Thanks! done.
421 } 424 }
422 425
423 DebugInfoListNode::DebugInfoListNode(DebugInfo* debug_info): next_(NULL) { 426 DebugInfoListNode::DebugInfoListNode(DebugInfo* debug_info): next_(NULL) {
424 // Globalize the request debug info object and make it weak. 427 // Globalize the request debug info object and make it weak.
425 GlobalHandles* global_handles = debug_info->GetIsolate()->global_handles(); 428 GlobalHandles* global_handles = debug_info->GetIsolate()->global_handles();
426 debug_info_ = 429 debug_info_ =
427 Handle<DebugInfo>::cast(global_handles->Create(debug_info)).location(); 430 Handle<DebugInfo>::cast(global_handles->Create(debug_info)).location();
428 } 431 }
429 432
430 433
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
546 // Fall through. 549 // Fall through.
547 case StepIn: { 550 case StepIn: {
548 FrameSummary summary = FrameSummary::GetTop(frame); 551 FrameSummary summary = FrameSummary::GetTop(frame);
549 step_break = step_break || location.IsReturn() || 552 step_break = step_break || location.IsReturn() ||
550 current_frame_count != last_frame_count || 553 current_frame_count != last_frame_count ||
551 thread_local_.last_statement_position_ != 554 thread_local_.last_statement_position_ !=
552 summary.SourceStatementPosition(); 555 summary.SourceStatementPosition();
553 break; 556 break;
554 } 557 }
555 } 558 }
559 step_break = step_break && !thread_local_.ignore_next_stepping_break_;
556 560
557 // Clear all current stepping setup. 561 // Clear all current stepping setup.
558 ClearStepping(); 562 ClearStepping();
559 563
560 if (step_break) { 564 if (step_break) {
561 // Notify the debug event listeners. 565 // Notify the debug event listeners.
562 OnDebugBreak(isolate_->factory()->undefined_value()); 566 OnDebugBreak(isolate_->factory()->undefined_value());
563 } else { 567 } else {
564 // Re-prepare to continue. 568 // Re-prepare to continue.
565 PrepareStep(step_action); 569 PrepareStep(step_action);
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after
807 for (DebugInfoListNode* node = debug_info_list_; node != NULL; 811 for (DebugInfoListNode* node = debug_info_list_; node != NULL;
808 node = node->next()) { 812 node = node->next()) {
809 ClearBreakPoints(node->debug_info()); 813 ClearBreakPoints(node->debug_info());
810 } 814 }
811 // Remove all debug info. 815 // Remove all debug info.
812 while (debug_info_list_ != NULL) { 816 while (debug_info_list_ != NULL) {
813 RemoveDebugInfoAndClearFromShared(debug_info_list_->debug_info()); 817 RemoveDebugInfoAndClearFromShared(debug_info_list_->debug_info());
814 } 818 }
815 } 819 }
816 820
817 void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared) { 821 void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared,
822 bool returns_only) {
818 if (IsBlackboxed(shared)) return; 823 if (IsBlackboxed(shared)) return;
819 // Make sure the function is compiled and has set up the debug info. 824 // Make sure the function is compiled and has set up the debug info.
820 if (!EnsureDebugInfo(shared)) return; 825 if (!EnsureDebugInfo(shared)) return;
821 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); 826 Handle<DebugInfo> debug_info(shared->GetDebugInfo());
822 // Flood the function with break points. 827 // Flood the function with break points.
823 if (debug_info->HasDebugCode()) { 828 if (debug_info->HasDebugCode()) {
824 for (CodeBreakIterator it(debug_info); !it.Done(); it.Next()) { 829 for (CodeBreakIterator it(debug_info); !it.Done(); it.Next()) {
830 if (returns_only && !it.GetBreakLocation().IsReturn()) continue;
825 it.SetDebugBreak(); 831 it.SetDebugBreak();
826 } 832 }
827 } 833 }
828 if (debug_info->HasDebugBytecodeArray()) { 834 if (debug_info->HasDebugBytecodeArray()) {
829 for (BytecodeArrayBreakIterator it(debug_info); !it.Done(); it.Next()) { 835 for (BytecodeArrayBreakIterator it(debug_info); !it.Done(); it.Next()) {
836 if (returns_only && !it.GetBreakLocation().IsReturn()) continue;
830 it.SetDebugBreak(); 837 it.SetDebugBreak();
831 } 838 }
832 } 839 }
833 } 840 }
834 841
835 void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) { 842 void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) {
836 if (type == BreakUncaughtException) { 843 if (type == BreakUncaughtException) {
837 break_on_uncaught_exception_ = enable; 844 break_on_uncaught_exception_ = enable;
838 } else { 845 } else {
839 break_on_exception_ = enable; 846 break_on_exception_ = enable;
(...skipping 29 matching lines...) Expand all
869 if (CheckBreakPoint(break_point_object)) { 876 if (CheckBreakPoint(break_point_object)) {
870 break_points_hit->set(break_points_hit_count++, *break_point_object); 877 break_points_hit->set(break_points_hit_count++, *break_point_object);
871 } 878 }
872 } 879 }
873 if (break_points_hit_count == 0) return {}; 880 if (break_points_hit_count == 0) return {};
874 break_points_hit->Shrink(break_points_hit_count); 881 break_points_hit->Shrink(break_points_hit_count);
875 return break_points_hit; 882 return break_points_hit;
876 } 883 }
877 884
878 void Debug::PrepareStepIn(Handle<JSFunction> function) { 885 void Debug::PrepareStepIn(Handle<JSFunction> function) {
879 CHECK(last_step_action() >= StepIn); 886 CHECK(step_into_function_call_requested());
880 if (ignore_events()) return; 887 if (ignore_events()) return;
881 if (in_debug_scope()) return; 888 if (in_debug_scope()) return;
882 if (break_disabled()) return; 889 if (break_disabled()) return;
890 Handle<SharedFunctionInfo> shared(function->shared());
891 if (IsBlackboxed(shared)) return;
892 if (*function == thread_local_.ignore_step_into_function_) return;
893 thread_local_.ignore_step_into_function_ = Smi::kZero;
894 thread_local_.last_step_action_ = StepIn;
883 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared(), isolate_)); 895 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared(), isolate_));
884 } 896 }
885 897
886 void Debug::PrepareStepInSuspendedGenerator() { 898 void Debug::PrepareStepInSuspendedGenerator() {
887 CHECK(has_suspended_generator()); 899 CHECK(has_suspended_generator());
888 if (ignore_events()) return; 900 if (ignore_events()) return;
889 if (in_debug_scope()) return; 901 if (in_debug_scope()) return;
890 if (break_disabled()) return; 902 if (break_disabled()) return;
891 thread_local_.last_step_action_ = StepIn; 903 thread_local_.last_step_action_ = StepIn;
892 UpdateHookOnFunctionCall(); 904 UpdateHookOnFunctionCall();
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
978 // any. The debug frame will only be present if execution was stopped due to 990 // any. The debug frame will only be present if execution was stopped due to
979 // hitting a break point. In other situations (e.g. unhandled exception) the 991 // hitting a break point. In other situations (e.g. unhandled exception) the
980 // debug frame is not present. 992 // debug frame is not present.
981 StackFrame::Id frame_id = break_frame_id(); 993 StackFrame::Id frame_id = break_frame_id();
982 // If there is no JavaScript stack don't do anything. 994 // If there is no JavaScript stack don't do anything.
983 if (frame_id == StackFrame::NO_ID) return; 995 if (frame_id == StackFrame::NO_ID) return;
984 996
985 feature_tracker()->Track(DebugFeatureTracker::kStepping); 997 feature_tracker()->Track(DebugFeatureTracker::kStepping);
986 998
987 thread_local_.last_step_action_ = step_action; 999 thread_local_.last_step_action_ = step_action;
988 UpdateHookOnFunctionCall();
989 1000
990 StackTraceFrameIterator frames_it(isolate_, frame_id); 1001 StackTraceFrameIterator frames_it(isolate_, frame_id);
991 StandardFrame* frame = frames_it.frame(); 1002 StandardFrame* frame = frames_it.frame();
992 1003
993 // Handle stepping in wasm functions via the wasm interpreter. 1004 // Handle stepping in wasm functions via the wasm interpreter.
994 if (frame->is_wasm()) { 1005 if (frame->is_wasm()) {
995 // If the top frame is compiled, we cannot step. 1006 // If the top frame is compiled, we cannot step.
996 if (frame->is_wasm_compiled()) return; 1007 if (frame->is_wasm_compiled()) return;
997 WasmInterpreterEntryFrame* wasm_frame = 1008 WasmInterpreterEntryFrame* wasm_frame =
998 WasmInterpreterEntryFrame::cast(frame); 1009 WasmInterpreterEntryFrame::cast(frame);
999 wasm_frame->wasm_instance()->debug_info()->PrepareStep(step_action); 1010 wasm_frame->wasm_instance()->debug_info()->PrepareStep(step_action);
1000 return; 1011 return;
1001 } 1012 }
1002 1013
1003 JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame); 1014 JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame);
1004 DCHECK(js_frame->function()->IsJSFunction()); 1015 DCHECK(js_frame->function()->IsJSFunction());
1005 1016
1006 // Get the debug info (create it if it does not exist). 1017 // Get the debug info (create it if it does not exist).
1007 auto summary = FrameSummary::GetTop(frame).AsJavaScript(); 1018 auto summary = FrameSummary::GetTop(frame).AsJavaScript();
1008 Handle<JSFunction> function(summary.function()); 1019 Handle<JSFunction> function(summary.function());
1009 Handle<SharedFunctionInfo> shared(function->shared()); 1020 Handle<SharedFunctionInfo> shared(function->shared());
1010 if (!EnsureDebugInfo(shared)) return; 1021 if (!EnsureDebugInfo(shared)) return;
1011 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); 1022 Handle<DebugInfo> debug_info(shared->GetDebugInfo());
1012 1023
1013 BreakLocation location = BreakLocation::FromFrame(debug_info, js_frame); 1024 BreakLocation location = BreakLocation::FromFrame(debug_info, js_frame);
1014 1025
1026 thread_local_.step_into_function_call_requested_ = step_action == StepIn;
1027 if (location.IsReturn()) {
Yang 2017/03/21 13:13:52 Please add comments! How about this slight change
kozy 2017/03/21 16:03:11 Done! My goals with current solutions were: doesn'
1028 thread_local_.step_into_function_call_requested_ = true;
1029 if (last_step_action() == StepOut) {
1030 thread_local_.ignore_step_into_function_ = *function;
1031 }
1032 step_action = StepOut;
1033 }
1034 UpdateHookOnFunctionCall();
1035
1015 // Any step at a return is a step-out. 1036 // Any step at a return is a step-out.
1016 if (location.IsReturn()) step_action = StepOut; 1037 if (location.IsReturn()) step_action = StepOut;
Yang 2017/03/21 13:13:52 We already have this here.
kozy 2017/03/21 16:03:11 removed.
1017 // A step-next at a tail call is a step-out. 1038 // A step-next at a tail call is a step-out.
1018 if (location.IsTailCall() && step_action == StepNext) step_action = StepOut; 1039 if (location.IsTailCall() && step_action == StepNext) step_action = StepOut;
1019 // A step-next in blackboxed function is a step-out. 1040 // A step-next in blackboxed function is a step-out.
1020 if (step_action == StepNext && IsBlackboxed(shared)) step_action = StepOut; 1041 if (step_action == StepNext && IsBlackboxed(shared)) step_action = StepOut;
1021 1042
1022 thread_local_.last_statement_position_ = 1043 thread_local_.last_statement_position_ =
1023 summary.abstract_code()->SourceStatementPosition(summary.code_offset()); 1044 summary.abstract_code()->SourceStatementPosition(summary.code_offset());
1024 int current_frame_count = CurrentFrameCount(); 1045 int current_frame_count = CurrentFrameCount();
1025 thread_local_.last_frame_count_ = current_frame_count; 1046 thread_local_.last_frame_count_ = current_frame_count;
1026 // No longer perform the current async step. 1047 // No longer perform the current async step.
1027 clear_suspended_generator(); 1048 clear_suspended_generator();
1028 1049
1029 switch (step_action) { 1050 switch (step_action) {
1030 case StepNone: 1051 case StepNone:
1031 UNREACHABLE(); 1052 UNREACHABLE();
1032 break; 1053 break;
1033 case StepOut: { 1054 case StepOut: {
1034 // Clear last position info. For stepping out it does not matter. 1055 // Clear last position info. For stepping out it does not matter.
1035 thread_local_.last_statement_position_ = kNoSourcePosition; 1056 thread_local_.last_statement_position_ = kNoSourcePosition;
1036 thread_local_.last_frame_count_ = -1; 1057 thread_local_.last_frame_count_ = -1;
1058 if (!location.IsReturn() && !IsBlackboxed(shared)) {
Yang 2017/03/21 13:13:52 How can IsBlackboxed return true?
kozy 2017/03/21 16:03:11 we can break in blackboxed frame in case when we h
1059 thread_local_.target_frame_count_ = current_frame_count;
1060 thread_local_.ignore_next_stepping_break_ = true;
1061 FloodWithOneShot(shared, true);
1062 return;
1063 }
1037 // Skip the current frame, find the first frame we want to step out to 1064 // Skip the current frame, find the first frame we want to step out to
1038 // and deoptimize every frame along the way. 1065 // and deoptimize every frame along the way.
1039 bool in_current_frame = true; 1066 bool in_current_frame = true;
1040 for (; !frames_it.done(); frames_it.Advance()) { 1067 for (; !frames_it.done(); frames_it.Advance()) {
1041 // TODO(clemensh): Implement stepping out from JS to WASM. 1068 // TODO(clemensh): Implement stepping out from JS to WASM.
1042 if (frames_it.frame()->is_wasm()) continue; 1069 if (frames_it.frame()->is_wasm()) continue;
1043 JavaScriptFrame* frame = JavaScriptFrame::cast(frames_it.frame()); 1070 JavaScriptFrame* frame = JavaScriptFrame::cast(frames_it.frame());
1044 if (last_step_action() == StepIn) { 1071 if (last_step_action() == StepIn) {
1045 // Deoptimize frame to ensure calls are checked for step-in. 1072 // Deoptimize frame to ensure calls are checked for step-in.
1046 Deoptimizer::DeoptimizeFunction(frame->function()); 1073 Deoptimizer::DeoptimizeFunction(frame->function());
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
1117 } 1144 }
1118 return locations; 1145 return locations;
1119 } 1146 }
1120 1147
1121 void Debug::ClearStepping() { 1148 void Debug::ClearStepping() {
1122 // Clear the various stepping setup. 1149 // Clear the various stepping setup.
1123 ClearOneShot(); 1150 ClearOneShot();
1124 1151
1125 thread_local_.last_step_action_ = StepNone; 1152 thread_local_.last_step_action_ = StepNone;
1126 thread_local_.last_statement_position_ = kNoSourcePosition; 1153 thread_local_.last_statement_position_ = kNoSourcePosition;
1154 thread_local_.ignore_step_into_function_ = Smi::kZero;
1155 thread_local_.step_into_function_call_requested_ = false;
1156 thread_local_.ignore_next_stepping_break_ = false;
1127 thread_local_.last_frame_count_ = -1; 1157 thread_local_.last_frame_count_ = -1;
1128 thread_local_.target_frame_count_ = -1; 1158 thread_local_.target_frame_count_ = -1;
1129 UpdateHookOnFunctionCall(); 1159 UpdateHookOnFunctionCall();
1130 } 1160 }
1131 1161
1132 1162
1133 // Clears all the one-shot break points that are currently set. Normally this 1163 // Clears all the one-shot break points that are currently set. Normally this
1134 // function is called each time a break point is hit as one shot break points 1164 // function is called each time a break point is hit as one shot break points
1135 // are used to support stepping. 1165 // are used to support stepping.
1136 void Debug::ClearOneShot() { 1166 void Debug::ClearOneShot() {
(...skipping 964 matching lines...) Expand 10 before | Expand all | Expand 10 after
2101 } else if (is_loaded()) { 2131 } else if (is_loaded()) {
2102 isolate_->compilation_cache()->Enable(); 2132 isolate_->compilation_cache()->Enable();
2103 Unload(); 2133 Unload();
2104 } 2134 }
2105 is_active_ = is_active; 2135 is_active_ = is_active;
2106 isolate_->DebugStateUpdated(); 2136 isolate_->DebugStateUpdated();
2107 } 2137 }
2108 2138
2109 void Debug::UpdateHookOnFunctionCall() { 2139 void Debug::UpdateHookOnFunctionCall() {
2110 STATIC_ASSERT(LastStepAction == StepIn); 2140 STATIC_ASSERT(LastStepAction == StepIn);
2111 hook_on_function_call_ = thread_local_.last_step_action_ == StepIn || 2141 hook_on_function_call_ = thread_local_.step_into_function_call_requested_ ||
2112 isolate_->needs_side_effect_check(); 2142 isolate_->needs_side_effect_check();
2113 } 2143 }
2114 2144
2115 MaybeHandle<Object> Debug::Call(Handle<Object> fun, Handle<Object> data) { 2145 MaybeHandle<Object> Debug::Call(Handle<Object> fun, Handle<Object> data) {
2116 DebugScope debug_scope(this); 2146 DebugScope debug_scope(this);
2117 if (debug_scope.failed()) return isolate_->factory()->undefined_value(); 2147 if (debug_scope.failed()) return isolate_->factory()->undefined_value();
2118 2148
2119 // Create the execution state. 2149 // Create the execution state.
2120 Handle<Object> exec_state; 2150 Handle<Object> exec_state;
2121 if (!MakeExecutionState().ToHandle(&exec_state)) { 2151 if (!MakeExecutionState().ToHandle(&exec_state)) {
(...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after
2456 isolate_->Throw(*isolate_->factory()->NewEvalError( 2486 isolate_->Throw(*isolate_->factory()->NewEvalError(
2457 MessageTemplate::kNoSideEffectDebugEvaluate)); 2487 MessageTemplate::kNoSideEffectDebugEvaluate));
2458 } 2488 }
2459 isolate_->set_needs_side_effect_check(old_needs_side_effect_check_); 2489 isolate_->set_needs_side_effect_check(old_needs_side_effect_check_);
2460 isolate_->debug()->UpdateHookOnFunctionCall(); 2490 isolate_->debug()->UpdateHookOnFunctionCall();
2461 isolate_->debug()->side_effect_check_failed_ = false; 2491 isolate_->debug()->side_effect_check_failed_ = false;
2462 } 2492 }
2463 2493
2464 } // namespace internal 2494 } // namespace internal
2465 } // namespace v8 2495 } // namespace v8
OLDNEW
« no previous file with comments | « src/debug/debug.h ('k') | src/runtime/runtime-debug.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698