| 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" |
| (...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |