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

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
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_.fast_forward_to_return_ = false;
393 thread_local_.ignore_step_into_function_ = Smi::kZero;
392 thread_local_.target_frame_count_ = -1; 394 thread_local_.target_frame_count_ = -1;
393 thread_local_.return_value_ = Smi::kZero; 395 thread_local_.return_value_ = Smi::kZero;
394 thread_local_.async_task_count_ = 0; 396 thread_local_.async_task_count_ = 0;
395 clear_suspended_generator(); 397 clear_suspended_generator();
396 thread_local_.restart_fp_ = nullptr; 398 thread_local_.restart_fp_ = nullptr;
397 base::NoBarrier_Store(&thread_local_.current_debug_scope_, 399 base::NoBarrier_Store(&thread_local_.current_debug_scope_,
398 static_cast<base::AtomicWord>(0)); 400 static_cast<base::AtomicWord>(0));
399 UpdateHookOnFunctionCall(); 401 UpdateHookOnFunctionCall();
400 } 402 }
401 403
402 404
403 char* Debug::ArchiveDebug(char* storage) { 405 char* Debug::ArchiveDebug(char* storage) {
404 // Simply reset state. Don't archive anything. 406 // Simply reset state. Don't archive anything.
405 ThreadInit(); 407 ThreadInit();
406 return storage + ArchiveSpacePerThread(); 408 return storage + ArchiveSpacePerThread();
407 } 409 }
408 410
409 411
410 char* Debug::RestoreDebug(char* storage) { 412 char* Debug::RestoreDebug(char* storage) {
411 // Simply reset state. Don't restore anything. 413 // Simply reset state. Don't restore anything.
412 ThreadInit(); 414 ThreadInit();
413 return storage + ArchiveSpacePerThread(); 415 return storage + ArchiveSpacePerThread();
414 } 416 }
415 417
416 int Debug::ArchiveSpacePerThread() { return 0; } 418 int Debug::ArchiveSpacePerThread() { return 0; }
417 419
418 void Debug::Iterate(ObjectVisitor* v) { 420 void Debug::Iterate(ObjectVisitor* v) {
419 v->VisitPointer(&thread_local_.return_value_); 421 v->VisitPointer(&thread_local_.return_value_);
420 v->VisitPointer(&thread_local_.suspended_generator_); 422 v->VisitPointer(&thread_local_.suspended_generator_);
423 v->VisitPointer(&thread_local_.ignore_step_into_function_);
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 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
522 OnDebugBreak(jsarr); 525 OnDebugBreak(jsarr);
523 return; 526 return;
524 } 527 }
525 528
526 // No break point. Check for stepping. 529 // No break point. Check for stepping.
527 StepAction step_action = last_step_action(); 530 StepAction step_action = last_step_action();
528 int current_frame_count = CurrentFrameCount(); 531 int current_frame_count = CurrentFrameCount();
529 int target_frame_count = thread_local_.target_frame_count_; 532 int target_frame_count = thread_local_.target_frame_count_;
530 int last_frame_count = thread_local_.last_frame_count_; 533 int last_frame_count = thread_local_.last_frame_count_;
531 534
535 // StepOut at not return position was requested and return break locations
536 // were flooded with one shots.
537 if (thread_local_.fast_forward_to_return_) {
538 DCHECK(location.IsReturn());
539 // We have to ignore recursive calls to function.
540 if (current_frame_count > target_frame_count) return;
541 ClearStepping();
542 PrepareStep(StepOut);
543 return;
544 }
545
532 bool step_break = false; 546 bool step_break = false;
533 switch (step_action) { 547 switch (step_action) {
534 case StepNone: 548 case StepNone:
535 return; 549 return;
536 case StepOut: 550 case StepOut:
537 // Step out should not break in a deeper frame than target frame. 551 // Step out should not break in a deeper frame than target frame.
538 if (current_frame_count > target_frame_count) return; 552 if (current_frame_count > target_frame_count) return;
539 step_break = true; 553 step_break = true;
540 break; 554 break;
541 case StepNext: 555 case StepNext:
(...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after
807 for (DebugInfoListNode* node = debug_info_list_; node != NULL; 821 for (DebugInfoListNode* node = debug_info_list_; node != NULL;
808 node = node->next()) { 822 node = node->next()) {
809 ClearBreakPoints(node->debug_info()); 823 ClearBreakPoints(node->debug_info());
810 } 824 }
811 // Remove all debug info. 825 // Remove all debug info.
812 while (debug_info_list_ != NULL) { 826 while (debug_info_list_ != NULL) {
813 RemoveDebugInfoAndClearFromShared(debug_info_list_->debug_info()); 827 RemoveDebugInfoAndClearFromShared(debug_info_list_->debug_info());
814 } 828 }
815 } 829 }
816 830
817 void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared) { 831 void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared,
832 bool returns_only) {
818 if (IsBlackboxed(shared)) return; 833 if (IsBlackboxed(shared)) return;
819 // Make sure the function is compiled and has set up the debug info. 834 // Make sure the function is compiled and has set up the debug info.
820 if (!EnsureDebugInfo(shared)) return; 835 if (!EnsureDebugInfo(shared)) return;
821 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); 836 Handle<DebugInfo> debug_info(shared->GetDebugInfo());
822 // Flood the function with break points. 837 // Flood the function with break points.
823 if (debug_info->HasDebugCode()) { 838 if (debug_info->HasDebugCode()) {
824 for (CodeBreakIterator it(debug_info); !it.Done(); it.Next()) { 839 for (CodeBreakIterator it(debug_info); !it.Done(); it.Next()) {
840 if (returns_only && !it.GetBreakLocation().IsReturn()) continue;
825 it.SetDebugBreak(); 841 it.SetDebugBreak();
826 } 842 }
827 } 843 }
828 if (debug_info->HasDebugBytecodeArray()) { 844 if (debug_info->HasDebugBytecodeArray()) {
829 for (BytecodeArrayBreakIterator it(debug_info); !it.Done(); it.Next()) { 845 for (BytecodeArrayBreakIterator it(debug_info); !it.Done(); it.Next()) {
846 if (returns_only && !it.GetBreakLocation().IsReturn()) continue;
830 it.SetDebugBreak(); 847 it.SetDebugBreak();
831 } 848 }
832 } 849 }
833 } 850 }
834 851
835 void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) { 852 void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) {
836 if (type == BreakUncaughtException) { 853 if (type == BreakUncaughtException) {
837 break_on_uncaught_exception_ = enable; 854 break_on_uncaught_exception_ = enable;
838 } else { 855 } else {
839 break_on_exception_ = enable; 856 break_on_exception_ = enable;
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
873 if (break_points_hit_count == 0) return {}; 890 if (break_points_hit_count == 0) return {};
874 break_points_hit->Shrink(break_points_hit_count); 891 break_points_hit->Shrink(break_points_hit_count);
875 return break_points_hit; 892 return break_points_hit;
876 } 893 }
877 894
878 void Debug::PrepareStepIn(Handle<JSFunction> function) { 895 void Debug::PrepareStepIn(Handle<JSFunction> function) {
879 CHECK(last_step_action() >= StepIn); 896 CHECK(last_step_action() >= StepIn);
880 if (ignore_events()) return; 897 if (ignore_events()) return;
881 if (in_debug_scope()) return; 898 if (in_debug_scope()) return;
882 if (break_disabled()) return; 899 if (break_disabled()) return;
900 Handle<SharedFunctionInfo> shared(function->shared());
901 if (IsBlackboxed(shared)) return;
902 if (*function == thread_local_.ignore_step_into_function_) return;
903 thread_local_.ignore_step_into_function_ = Smi::kZero;
883 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared(), isolate_)); 904 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared(), isolate_));
884 } 905 }
885 906
886 void Debug::PrepareStepInSuspendedGenerator() { 907 void Debug::PrepareStepInSuspendedGenerator() {
887 CHECK(has_suspended_generator()); 908 CHECK(has_suspended_generator());
888 if (ignore_events()) return; 909 if (ignore_events()) return;
889 if (in_debug_scope()) return; 910 if (in_debug_scope()) return;
890 if (break_disabled()) return; 911 if (break_disabled()) return;
891 thread_local_.last_step_action_ = StepIn; 912 thread_local_.last_step_action_ = StepIn;
892 UpdateHookOnFunctionCall(); 913 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 999 // 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 1000 // hitting a break point. In other situations (e.g. unhandled exception) the
980 // debug frame is not present. 1001 // debug frame is not present.
981 StackFrame::Id frame_id = break_frame_id(); 1002 StackFrame::Id frame_id = break_frame_id();
982 // If there is no JavaScript stack don't do anything. 1003 // If there is no JavaScript stack don't do anything.
983 if (frame_id == StackFrame::NO_ID) return; 1004 if (frame_id == StackFrame::NO_ID) return;
984 1005
985 feature_tracker()->Track(DebugFeatureTracker::kStepping); 1006 feature_tracker()->Track(DebugFeatureTracker::kStepping);
986 1007
987 thread_local_.last_step_action_ = step_action; 1008 thread_local_.last_step_action_ = step_action;
988 UpdateHookOnFunctionCall();
989 1009
990 StackTraceFrameIterator frames_it(isolate_, frame_id); 1010 StackTraceFrameIterator frames_it(isolate_, frame_id);
991 StandardFrame* frame = frames_it.frame(); 1011 StandardFrame* frame = frames_it.frame();
992 1012
993 // Handle stepping in wasm functions via the wasm interpreter. 1013 // Handle stepping in wasm functions via the wasm interpreter.
994 if (frame->is_wasm()) { 1014 if (frame->is_wasm()) {
995 // If the top frame is compiled, we cannot step. 1015 // If the top frame is compiled, we cannot step.
996 if (frame->is_wasm_compiled()) return; 1016 if (frame->is_wasm_compiled()) return;
997 WasmInterpreterEntryFrame* wasm_frame = 1017 WasmInterpreterEntryFrame* wasm_frame =
998 WasmInterpreterEntryFrame::cast(frame); 1018 WasmInterpreterEntryFrame::cast(frame);
999 wasm_frame->wasm_instance()->debug_info()->PrepareStep(step_action); 1019 wasm_frame->wasm_instance()->debug_info()->PrepareStep(step_action);
1000 return; 1020 return;
1001 } 1021 }
1002 1022
1003 JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame); 1023 JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame);
1004 DCHECK(js_frame->function()->IsJSFunction()); 1024 DCHECK(js_frame->function()->IsJSFunction());
1005 1025
1006 // Get the debug info (create it if it does not exist). 1026 // Get the debug info (create it if it does not exist).
1007 auto summary = FrameSummary::GetTop(frame).AsJavaScript(); 1027 auto summary = FrameSummary::GetTop(frame).AsJavaScript();
1008 Handle<JSFunction> function(summary.function()); 1028 Handle<JSFunction> function(summary.function());
1009 Handle<SharedFunctionInfo> shared(function->shared()); 1029 Handle<SharedFunctionInfo> shared(function->shared());
1010 if (!EnsureDebugInfo(shared)) return; 1030 if (!EnsureDebugInfo(shared)) return;
1011 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); 1031 Handle<DebugInfo> debug_info(shared->GetDebugInfo());
1012 1032
1013 BreakLocation location = BreakLocation::FromFrame(debug_info, js_frame); 1033 BreakLocation location = BreakLocation::FromFrame(debug_info, js_frame);
1014 1034
1015 // Any step at a return is a step-out. 1035 // Any step at a return is a step-out and we need to schedule DebugOnFunction
1016 if (location.IsReturn()) step_action = StepOut; 1036 // call callback.
1037 if (location.IsReturn()) {
1038 // On StepOut we'll ignore our further calls to current function in
1039 // PrepareStepIn callback.
1040 if (last_step_action() == StepOut) {
1041 thread_local_.ignore_step_into_function_ = *function;
1042 }
1043 step_action = StepOut;
1044 thread_local_.last_step_action_ = StepIn;
1045 }
1046 UpdateHookOnFunctionCall();
1047
1017 // A step-next at a tail call is a step-out. 1048 // A step-next at a tail call is a step-out.
1018 if (location.IsTailCall() && step_action == StepNext) step_action = StepOut; 1049 if (location.IsTailCall() && step_action == StepNext) step_action = StepOut;
1019 // A step-next in blackboxed function is a step-out. 1050 // A step-next in blackboxed function is a step-out.
1020 if (step_action == StepNext && IsBlackboxed(shared)) step_action = StepOut; 1051 if (step_action == StepNext && IsBlackboxed(shared)) step_action = StepOut;
1021 1052
1022 thread_local_.last_statement_position_ = 1053 thread_local_.last_statement_position_ =
1023 summary.abstract_code()->SourceStatementPosition(summary.code_offset()); 1054 summary.abstract_code()->SourceStatementPosition(summary.code_offset());
1024 int current_frame_count = CurrentFrameCount(); 1055 int current_frame_count = CurrentFrameCount();
1025 thread_local_.last_frame_count_ = current_frame_count; 1056 thread_local_.last_frame_count_ = current_frame_count;
1026 // No longer perform the current async step. 1057 // No longer perform the current async step.
1027 clear_suspended_generator(); 1058 clear_suspended_generator();
1028 1059
1029 switch (step_action) { 1060 switch (step_action) {
1030 case StepNone: 1061 case StepNone:
1031 UNREACHABLE(); 1062 UNREACHABLE();
1032 break; 1063 break;
1033 case StepOut: { 1064 case StepOut: {
1034 // Clear last position info. For stepping out it does not matter. 1065 // Clear last position info. For stepping out it does not matter.
1035 thread_local_.last_statement_position_ = kNoSourcePosition; 1066 thread_local_.last_statement_position_ = kNoSourcePosition;
1036 thread_local_.last_frame_count_ = -1; 1067 thread_local_.last_frame_count_ = -1;
1068 if (!location.IsReturn() && !IsBlackboxed(shared)) {
1069 // At not return position we flood return positions with one shots and
1070 // will repeat StepOut automatically at next break.
1071 thread_local_.target_frame_count_ = current_frame_count;
1072 thread_local_.fast_forward_to_return_ = true;
1073 FloodWithOneShot(shared, true);
1074 return;
1075 }
1037 // Skip the current frame, find the first frame we want to step out to 1076 // Skip the current frame, find the first frame we want to step out to
1038 // and deoptimize every frame along the way. 1077 // and deoptimize every frame along the way.
1039 bool in_current_frame = true; 1078 bool in_current_frame = true;
1040 for (; !frames_it.done(); frames_it.Advance()) { 1079 for (; !frames_it.done(); frames_it.Advance()) {
1041 // TODO(clemensh): Implement stepping out from JS to WASM. 1080 // TODO(clemensh): Implement stepping out from JS to WASM.
1042 if (frames_it.frame()->is_wasm()) continue; 1081 if (frames_it.frame()->is_wasm()) continue;
1043 JavaScriptFrame* frame = JavaScriptFrame::cast(frames_it.frame()); 1082 JavaScriptFrame* frame = JavaScriptFrame::cast(frames_it.frame());
1044 if (last_step_action() == StepIn) { 1083 if (last_step_action() == StepIn) {
1045 // Deoptimize frame to ensure calls are checked for step-in. 1084 // Deoptimize frame to ensure calls are checked for step-in.
1046 Deoptimizer::DeoptimizeFunction(frame->function()); 1085 Deoptimizer::DeoptimizeFunction(frame->function());
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
1117 } 1156 }
1118 return locations; 1157 return locations;
1119 } 1158 }
1120 1159
1121 void Debug::ClearStepping() { 1160 void Debug::ClearStepping() {
1122 // Clear the various stepping setup. 1161 // Clear the various stepping setup.
1123 ClearOneShot(); 1162 ClearOneShot();
1124 1163
1125 thread_local_.last_step_action_ = StepNone; 1164 thread_local_.last_step_action_ = StepNone;
1126 thread_local_.last_statement_position_ = kNoSourcePosition; 1165 thread_local_.last_statement_position_ = kNoSourcePosition;
1166 thread_local_.ignore_step_into_function_ = Smi::kZero;
1167 thread_local_.fast_forward_to_return_ = false;
1127 thread_local_.last_frame_count_ = -1; 1168 thread_local_.last_frame_count_ = -1;
1128 thread_local_.target_frame_count_ = -1; 1169 thread_local_.target_frame_count_ = -1;
1129 UpdateHookOnFunctionCall(); 1170 UpdateHookOnFunctionCall();
1130 } 1171 }
1131 1172
1132 1173
1133 // Clears all the one-shot break points that are currently set. Normally this 1174 // 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 1175 // function is called each time a break point is hit as one shot break points
1135 // are used to support stepping. 1176 // are used to support stepping.
1136 void Debug::ClearOneShot() { 1177 void Debug::ClearOneShot() {
(...skipping 1319 matching lines...) Expand 10 before | Expand all | Expand 10 after
2456 isolate_->Throw(*isolate_->factory()->NewEvalError( 2497 isolate_->Throw(*isolate_->factory()->NewEvalError(
2457 MessageTemplate::kNoSideEffectDebugEvaluate)); 2498 MessageTemplate::kNoSideEffectDebugEvaluate));
2458 } 2499 }
2459 isolate_->set_needs_side_effect_check(old_needs_side_effect_check_); 2500 isolate_->set_needs_side_effect_check(old_needs_side_effect_check_);
2460 isolate_->debug()->UpdateHookOnFunctionCall(); 2501 isolate_->debug()->UpdateHookOnFunctionCall();
2461 isolate_->debug()->side_effect_check_failed_ = false; 2502 isolate_->debug()->side_effect_check_failed_ = false;
2462 } 2503 }
2463 2504
2464 } // namespace internal 2505 } // namespace internal
2465 } // namespace v8 2506 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698