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

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

Issue 2758483002: [debugger] tuned StepNext and StepOut at return position (Closed)
Patch Set: more tests 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
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
(...skipping 144 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 if (*function == thread_local_.ignore_step_into_function_) return;
891 thread_local_.last_step_action_ = StepIn;
Yang 2017/03/20 14:29:40 We should clear thread_local_.ignore_step_into_fun
kozy 2017/03/20 15:52:54 Done.
883 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared(), isolate_)); 892 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared(), isolate_));
884 } 893 }
885 894
886 void Debug::PrepareStepInSuspendedGenerator() { 895 void Debug::PrepareStepInSuspendedGenerator() {
887 CHECK(has_suspended_generator()); 896 CHECK(has_suspended_generator());
888 if (ignore_events()) return; 897 if (ignore_events()) return;
889 if (in_debug_scope()) return; 898 if (in_debug_scope()) return;
890 if (break_disabled()) return; 899 if (break_disabled()) return;
891 thread_local_.last_step_action_ = StepIn; 900 thread_local_.last_step_action_ = StepIn;
892 UpdateHookOnFunctionCall(); 901 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 987 // 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 988 // hitting a break point. In other situations (e.g. unhandled exception) the
980 // debug frame is not present. 989 // debug frame is not present.
981 StackFrame::Id frame_id = break_frame_id(); 990 StackFrame::Id frame_id = break_frame_id();
982 // If there is no JavaScript stack don't do anything. 991 // If there is no JavaScript stack don't do anything.
983 if (frame_id == StackFrame::NO_ID) return; 992 if (frame_id == StackFrame::NO_ID) return;
984 993
985 feature_tracker()->Track(DebugFeatureTracker::kStepping); 994 feature_tracker()->Track(DebugFeatureTracker::kStepping);
986 995
987 thread_local_.last_step_action_ = step_action; 996 thread_local_.last_step_action_ = step_action;
988 UpdateHookOnFunctionCall();
989 997
990 StackTraceFrameIterator frames_it(isolate_, frame_id); 998 StackTraceFrameIterator frames_it(isolate_, frame_id);
991 StandardFrame* frame = frames_it.frame(); 999 StandardFrame* frame = frames_it.frame();
992 1000
993 // Handle stepping in wasm functions via the wasm interpreter. 1001 // Handle stepping in wasm functions via the wasm interpreter.
994 if (frame->is_wasm()) { 1002 if (frame->is_wasm()) {
995 // If the top frame is compiled, we cannot step. 1003 // If the top frame is compiled, we cannot step.
996 if (frame->is_wasm_compiled()) return; 1004 if (frame->is_wasm_compiled()) return;
997 WasmInterpreterEntryFrame* wasm_frame = 1005 WasmInterpreterEntryFrame* wasm_frame =
998 WasmInterpreterEntryFrame::cast(frame); 1006 WasmInterpreterEntryFrame::cast(frame);
999 wasm_frame->wasm_instance()->debug_info()->PrepareStep(step_action); 1007 wasm_frame->wasm_instance()->debug_info()->PrepareStep(step_action);
1000 return; 1008 return;
1001 } 1009 }
1002 1010
1003 JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame); 1011 JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame);
1004 DCHECK(js_frame->function()->IsJSFunction()); 1012 DCHECK(js_frame->function()->IsJSFunction());
1005 1013
1006 // Get the debug info (create it if it does not exist). 1014 // Get the debug info (create it if it does not exist).
1007 auto summary = FrameSummary::GetTop(frame).AsJavaScript(); 1015 auto summary = FrameSummary::GetTop(frame).AsJavaScript();
1008 Handle<JSFunction> function(summary.function()); 1016 Handle<JSFunction> function(summary.function());
1009 Handle<SharedFunctionInfo> shared(function->shared()); 1017 Handle<SharedFunctionInfo> shared(function->shared());
1010 if (!EnsureDebugInfo(shared)) return; 1018 if (!EnsureDebugInfo(shared)) return;
1011 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); 1019 Handle<DebugInfo> debug_info(shared->GetDebugInfo());
1012 1020
1013 BreakLocation location = BreakLocation::FromFrame(debug_info, js_frame); 1021 BreakLocation location = BreakLocation::FromFrame(debug_info, js_frame);
1014 1022
1023 thread_local_.step_into_function_call_requested_ = step_action == StepIn;
1024 if (location.IsReturn()) {
1025 thread_local_.step_into_function_call_requested_ = true;
1026 if (last_step_action() == StepOut) {
1027 thread_local_.ignore_step_into_function_ = *function;
1028 }
1029 step_action = StepOut;
1030 }
1031 UpdateHookOnFunctionCall();
1032
1015 // Any step at a return is a step-out. 1033 // Any step at a return is a step-out.
1016 if (location.IsReturn()) step_action = StepOut; 1034 if (location.IsReturn()) step_action = StepOut;
1017 // A step-next at a tail call is a step-out. 1035 // A step-next at a tail call is a step-out.
1018 if (location.IsTailCall() && step_action == StepNext) step_action = StepOut; 1036 if (location.IsTailCall() && step_action == StepNext) step_action = StepOut;
1019 // A step-next in blackboxed function is a step-out. 1037 // A step-next in blackboxed function is a step-out.
1020 if (step_action == StepNext && IsBlackboxed(shared)) step_action = StepOut; 1038 if (step_action == StepNext && IsBlackboxed(shared)) step_action = StepOut;
1021 1039
1022 thread_local_.last_statement_position_ = 1040 thread_local_.last_statement_position_ =
1023 summary.abstract_code()->SourceStatementPosition(summary.code_offset()); 1041 summary.abstract_code()->SourceStatementPosition(summary.code_offset());
1024 int current_frame_count = CurrentFrameCount(); 1042 int current_frame_count = CurrentFrameCount();
1025 thread_local_.last_frame_count_ = current_frame_count; 1043 thread_local_.last_frame_count_ = current_frame_count;
1026 // No longer perform the current async step. 1044 // No longer perform the current async step.
1027 clear_suspended_generator(); 1045 clear_suspended_generator();
1028 1046
1029 switch (step_action) { 1047 switch (step_action) {
1030 case StepNone: 1048 case StepNone:
1031 UNREACHABLE(); 1049 UNREACHABLE();
1032 break; 1050 break;
1033 case StepOut: { 1051 case StepOut: {
1034 // Clear last position info. For stepping out it does not matter. 1052 // Clear last position info. For stepping out it does not matter.
1035 thread_local_.last_statement_position_ = kNoSourcePosition; 1053 thread_local_.last_statement_position_ = kNoSourcePosition;
1036 thread_local_.last_frame_count_ = -1; 1054 thread_local_.last_frame_count_ = -1;
1055 if (!location.IsReturn() && !IsBlackboxed(shared)) {
1056 thread_local_.target_frame_count_ = current_frame_count;
1057 thread_local_.ignore_next_stepping_break_ = true;
1058 FloodWithOneShot(shared, true);
1059 return;
1060 }
1037 // Skip the current frame, find the first frame we want to step out to 1061 // Skip the current frame, find the first frame we want to step out to
1038 // and deoptimize every frame along the way. 1062 // and deoptimize every frame along the way.
1039 bool in_current_frame = true; 1063 bool in_current_frame = true;
1040 for (; !frames_it.done(); frames_it.Advance()) { 1064 for (; !frames_it.done(); frames_it.Advance()) {
1041 // TODO(clemensh): Implement stepping out from JS to WASM. 1065 // TODO(clemensh): Implement stepping out from JS to WASM.
1042 if (frames_it.frame()->is_wasm()) continue; 1066 if (frames_it.frame()->is_wasm()) continue;
1043 JavaScriptFrame* frame = JavaScriptFrame::cast(frames_it.frame()); 1067 JavaScriptFrame* frame = JavaScriptFrame::cast(frames_it.frame());
1044 if (last_step_action() == StepIn) { 1068 if (last_step_action() == StepIn) {
1045 // Deoptimize frame to ensure calls are checked for step-in. 1069 // Deoptimize frame to ensure calls are checked for step-in.
1046 Deoptimizer::DeoptimizeFunction(frame->function()); 1070 Deoptimizer::DeoptimizeFunction(frame->function());
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
1117 } 1141 }
1118 return locations; 1142 return locations;
1119 } 1143 }
1120 1144
1121 void Debug::ClearStepping() { 1145 void Debug::ClearStepping() {
1122 // Clear the various stepping setup. 1146 // Clear the various stepping setup.
1123 ClearOneShot(); 1147 ClearOneShot();
1124 1148
1125 thread_local_.last_step_action_ = StepNone; 1149 thread_local_.last_step_action_ = StepNone;
1126 thread_local_.last_statement_position_ = kNoSourcePosition; 1150 thread_local_.last_statement_position_ = kNoSourcePosition;
1151 thread_local_.ignore_step_into_function_ = Smi::kZero;
1152 thread_local_.step_into_function_call_requested_ = false;
1153 thread_local_.ignore_next_stepping_break_ = false;
1127 thread_local_.last_frame_count_ = -1; 1154 thread_local_.last_frame_count_ = -1;
1128 thread_local_.target_frame_count_ = -1; 1155 thread_local_.target_frame_count_ = -1;
1129 UpdateHookOnFunctionCall(); 1156 UpdateHookOnFunctionCall();
1130 } 1157 }
1131 1158
1132 1159
1133 // Clears all the one-shot break points that are currently set. Normally this 1160 // 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 1161 // function is called each time a break point is hit as one shot break points
1135 // are used to support stepping. 1162 // are used to support stepping.
1136 void Debug::ClearOneShot() { 1163 void Debug::ClearOneShot() {
(...skipping 964 matching lines...) Expand 10 before | Expand all | Expand 10 after
2101 } else if (is_loaded()) { 2128 } else if (is_loaded()) {
2102 isolate_->compilation_cache()->Enable(); 2129 isolate_->compilation_cache()->Enable();
2103 Unload(); 2130 Unload();
2104 } 2131 }
2105 is_active_ = is_active; 2132 is_active_ = is_active;
2106 isolate_->DebugStateUpdated(); 2133 isolate_->DebugStateUpdated();
2107 } 2134 }
2108 2135
2109 void Debug::UpdateHookOnFunctionCall() { 2136 void Debug::UpdateHookOnFunctionCall() {
2110 STATIC_ASSERT(LastStepAction == StepIn); 2137 STATIC_ASSERT(LastStepAction == StepIn);
2111 hook_on_function_call_ = thread_local_.last_step_action_ == StepIn || 2138 hook_on_function_call_ = thread_local_.step_into_function_call_requested_ ||
2112 isolate_->needs_side_effect_check(); 2139 isolate_->needs_side_effect_check();
2113 } 2140 }
2114 2141
2115 MaybeHandle<Object> Debug::Call(Handle<Object> fun, Handle<Object> data) { 2142 MaybeHandle<Object> Debug::Call(Handle<Object> fun, Handle<Object> data) {
2116 DebugScope debug_scope(this); 2143 DebugScope debug_scope(this);
2117 if (debug_scope.failed()) return isolate_->factory()->undefined_value(); 2144 if (debug_scope.failed()) return isolate_->factory()->undefined_value();
2118 2145
2119 // Create the execution state. 2146 // Create the execution state.
2120 Handle<Object> exec_state; 2147 Handle<Object> exec_state;
2121 if (!MakeExecutionState().ToHandle(&exec_state)) { 2148 if (!MakeExecutionState().ToHandle(&exec_state)) {
(...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after
2456 isolate_->Throw(*isolate_->factory()->NewEvalError( 2483 isolate_->Throw(*isolate_->factory()->NewEvalError(
2457 MessageTemplate::kNoSideEffectDebugEvaluate)); 2484 MessageTemplate::kNoSideEffectDebugEvaluate));
2458 } 2485 }
2459 isolate_->set_needs_side_effect_check(old_needs_side_effect_check_); 2486 isolate_->set_needs_side_effect_check(old_needs_side_effect_check_);
2460 isolate_->debug()->UpdateHookOnFunctionCall(); 2487 isolate_->debug()->UpdateHookOnFunctionCall();
2461 isolate_->debug()->side_effect_check_failed_ = false; 2488 isolate_->debug()->side_effect_check_failed_ = false;
2462 } 2489 }
2463 2490
2464 } // namespace internal 2491 } // namespace internal
2465 } // namespace v8 2492 } // namespace v8
OLDNEW
« no previous file with comments | « src/debug/debug.h ('k') | src/runtime/runtime-debug.cc » ('j') | test/cctest/test-debug.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698