| 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/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #include "src/api.h" | 7 #include "src/api.h" |
| 8 #include "src/arguments.h" | 8 #include "src/arguments.h" |
| 9 #include "src/bootstrapper.h" | 9 #include "src/bootstrapper.h" |
| 10 #include "src/code-stubs.h" | 10 #include "src/code-stubs.h" |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 Debug::Debug(Isolate* isolate) | 29 Debug::Debug(Isolate* isolate) |
| 30 : debug_context_(Handle<Context>()), | 30 : debug_context_(Handle<Context>()), |
| 31 event_listener_(Handle<Object>()), | 31 event_listener_(Handle<Object>()), |
| 32 event_listener_data_(Handle<Object>()), | 32 event_listener_data_(Handle<Object>()), |
| 33 message_handler_(NULL), | 33 message_handler_(NULL), |
| 34 command_received_(0), | 34 command_received_(0), |
| 35 command_queue_(isolate->logger(), kQueueInitialSize), | 35 command_queue_(isolate->logger(), kQueueInitialSize), |
| 36 is_active_(false), | 36 is_active_(false), |
| 37 is_suppressed_(false), | 37 is_suppressed_(false), |
| 38 live_edit_enabled_(true), // TODO(yangguo): set to false by default. | 38 live_edit_enabled_(true), // TODO(yangguo): set to false by default. |
| 39 has_break_points_(false), | |
| 40 break_disabled_(false), | 39 break_disabled_(false), |
| 41 in_debug_event_listener_(false), | 40 in_debug_event_listener_(false), |
| 42 break_on_exception_(false), | 41 break_on_exception_(false), |
| 43 break_on_uncaught_exception_(false), | 42 break_on_uncaught_exception_(false), |
| 44 script_cache_(NULL), | 43 script_cache_(NULL), |
| 45 debug_info_list_(NULL), | 44 debug_info_list_(NULL), |
| 46 isolate_(isolate) { | 45 isolate_(isolate) { |
| 47 ThreadInit(); | 46 ThreadInit(); |
| 48 } | 47 } |
| 49 | 48 |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 139 break; | 138 break; |
| 140 } | 139 } |
| 141 break_index_++; | 140 break_index_++; |
| 142 } | 141 } |
| 143 | 142 |
| 144 | 143 |
| 145 // Find the break point at the supplied address, or the closest one before | 144 // Find the break point at the supplied address, or the closest one before |
| 146 // the address. | 145 // the address. |
| 147 BreakLocation BreakLocation::FromAddress(Handle<DebugInfo> debug_info, | 146 BreakLocation BreakLocation::FromAddress(Handle<DebugInfo> debug_info, |
| 148 BreakLocatorType type, Address pc) { | 147 BreakLocatorType type, Address pc) { |
| 149 DCHECK(debug_info->code()->has_debug_break_slots()); | |
| 150 Iterator it(debug_info, type); | 148 Iterator it(debug_info, type); |
| 151 it.SkipTo(BreakIndexFromAddress(debug_info, type, pc)); | 149 it.SkipTo(BreakIndexFromAddress(debug_info, type, pc)); |
| 152 return it.GetBreakLocation(); | 150 return it.GetBreakLocation(); |
| 153 } | 151 } |
| 154 | 152 |
| 155 | 153 |
| 156 // Find the break point at the supplied address, or the closest one before | 154 // Find the break point at the supplied address, or the closest one before |
| 157 // the address. | 155 // the address. |
| 158 void BreakLocation::FromAddressSameStatement(Handle<DebugInfo> debug_info, | 156 void BreakLocation::FromAddressSameStatement(Handle<DebugInfo> debug_info, |
| 159 BreakLocatorType type, Address pc, | 157 BreakLocatorType type, Address pc, |
| 160 List<BreakLocation>* result_out) { | 158 List<BreakLocation>* result_out) { |
| 161 DCHECK(debug_info->code()->has_debug_break_slots()); | |
| 162 int break_index = BreakIndexFromAddress(debug_info, type, pc); | 159 int break_index = BreakIndexFromAddress(debug_info, type, pc); |
| 163 Iterator it(debug_info, type); | 160 Iterator it(debug_info, type); |
| 164 it.SkipTo(break_index); | 161 it.SkipTo(break_index); |
| 165 int statement_position = it.statement_position(); | 162 int statement_position = it.statement_position(); |
| 166 while (!it.Done() && it.statement_position() == statement_position) { | 163 while (!it.Done() && it.statement_position() == statement_position) { |
| 167 result_out->Add(it.GetBreakLocation()); | 164 result_out->Add(it.GetBreakLocation()); |
| 168 it.Next(); | 165 it.Next(); |
| 169 } | 166 } |
| 170 } | 167 } |
| 171 | 168 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 184 if (distance == 0) break; | 181 if (distance == 0) break; |
| 185 } | 182 } |
| 186 } | 183 } |
| 187 return closest_break; | 184 return closest_break; |
| 188 } | 185 } |
| 189 | 186 |
| 190 | 187 |
| 191 BreakLocation BreakLocation::FromPosition(Handle<DebugInfo> debug_info, | 188 BreakLocation BreakLocation::FromPosition(Handle<DebugInfo> debug_info, |
| 192 BreakLocatorType type, int position, | 189 BreakLocatorType type, int position, |
| 193 BreakPositionAlignment alignment) { | 190 BreakPositionAlignment alignment) { |
| 194 DCHECK(debug_info->code()->has_debug_break_slots()); | |
| 195 // Run through all break points to locate the one closest to the source | 191 // Run through all break points to locate the one closest to the source |
| 196 // position. | 192 // position. |
| 197 int closest_break = 0; | 193 int closest_break = 0; |
| 198 int distance = kMaxInt; | 194 int distance = kMaxInt; |
| 199 | 195 |
| 200 for (Iterator it(debug_info, type); !it.Done(); it.Next()) { | 196 for (Iterator it(debug_info, type); !it.Done(); it.Next()) { |
| 201 int next_position; | 197 int next_position; |
| 202 if (alignment == STATEMENT_ALIGNED) { | 198 if (alignment == STATEMENT_ALIGNED) { |
| 203 next_position = it.statement_position(); | 199 next_position = it.statement_position(); |
| 204 } else { | 200 } else { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 215 | 211 |
| 216 Iterator it(debug_info, type); | 212 Iterator it(debug_info, type); |
| 217 it.SkipTo(closest_break); | 213 it.SkipTo(closest_break); |
| 218 return it.GetBreakLocation(); | 214 return it.GetBreakLocation(); |
| 219 } | 215 } |
| 220 | 216 |
| 221 | 217 |
| 222 void BreakLocation::SetBreakPoint(Handle<Object> break_point_object) { | 218 void BreakLocation::SetBreakPoint(Handle<Object> break_point_object) { |
| 223 // If there is not already a real break point here patch code with debug | 219 // If there is not already a real break point here patch code with debug |
| 224 // break. | 220 // break. |
| 225 DCHECK(code()->has_debug_break_slots()); | |
| 226 if (!HasBreakPoint()) SetDebugBreak(); | 221 if (!HasBreakPoint()) SetDebugBreak(); |
| 227 DCHECK(IsDebugBreak() || IsDebuggerStatement()); | 222 DCHECK(IsDebugBreak() || IsDebuggerStatement()); |
| 228 // Set the break point information. | 223 // Set the break point information. |
| 229 DebugInfo::SetBreakPoint(debug_info_, pc_offset_, position_, | 224 DebugInfo::SetBreakPoint(debug_info_, pc_offset_, position_, |
| 230 statement_position_, break_point_object); | 225 statement_position_, break_point_object); |
| 231 } | 226 } |
| 232 | 227 |
| 233 | 228 |
| 234 void BreakLocation::ClearBreakPoint(Handle<Object> break_point_object) { | 229 void BreakLocation::ClearBreakPoint(Handle<Object> break_point_object) { |
| 235 // Clear the break point information. | 230 // Clear the break point information. |
| (...skipping 364 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 600 // Enter the debugger. | 595 // Enter the debugger. |
| 601 DebugScope debug_scope(this); | 596 DebugScope debug_scope(this); |
| 602 if (debug_scope.failed()) return; | 597 if (debug_scope.failed()) return; |
| 603 | 598 |
| 604 // Postpone interrupt during breakpoint processing. | 599 // Postpone interrupt during breakpoint processing. |
| 605 PostponeInterruptsScope postpone(isolate_); | 600 PostponeInterruptsScope postpone(isolate_); |
| 606 | 601 |
| 607 // Get the debug info (create it if it does not exist). | 602 // Get the debug info (create it if it does not exist). |
| 608 Handle<SharedFunctionInfo> shared = | 603 Handle<SharedFunctionInfo> shared = |
| 609 Handle<SharedFunctionInfo>(frame->function()->shared()); | 604 Handle<SharedFunctionInfo>(frame->function()->shared()); |
| 610 Handle<DebugInfo> debug_info = GetDebugInfo(shared); | 605 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
| 611 | 606 |
| 612 // Find the break point where execution has stopped. | 607 // Find the break point where execution has stopped. |
| 613 // PC points to the instruction after the current one, possibly a break | 608 // PC points to the instruction after the current one, possibly a break |
| 614 // location as well. So the "- 1" to exclude it from the search. | 609 // location as well. So the "- 1" to exclude it from the search. |
| 615 Address call_pc = frame->pc() - 1; | 610 Address call_pc = frame->pc() - 1; |
| 616 BreakLocation break_location = | 611 BreakLocation break_location = |
| 617 BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc); | 612 BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc); |
| 618 | 613 |
| 619 // Check whether step next reached a new statement. | 614 // Check whether step next reached a new statement. |
| 620 if (!StepNextContinue(&break_location, frame)) { | 615 if (!StepNextContinue(&break_location, frame)) { |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 773 arraysize(argv), | 768 arraysize(argv), |
| 774 argv).ToHandle(&result)) { | 769 argv).ToHandle(&result)) { |
| 775 return false; | 770 return false; |
| 776 } | 771 } |
| 777 | 772 |
| 778 // Return whether the break point is triggered. | 773 // Return whether the break point is triggered. |
| 779 return result->IsTrue(); | 774 return result->IsTrue(); |
| 780 } | 775 } |
| 781 | 776 |
| 782 | 777 |
| 783 // Check whether the function has debug information. | |
| 784 bool Debug::HasDebugInfo(Handle<SharedFunctionInfo> shared) { | |
| 785 return !shared->debug_info()->IsUndefined(); | |
| 786 } | |
| 787 | |
| 788 | |
| 789 // Return the debug info for this function. EnsureDebugInfo must be called | |
| 790 // prior to ensure the debug info has been generated for shared. | |
| 791 Handle<DebugInfo> Debug::GetDebugInfo(Handle<SharedFunctionInfo> shared) { | |
| 792 DCHECK(HasDebugInfo(shared)); | |
| 793 return Handle<DebugInfo>(DebugInfo::cast(shared->debug_info())); | |
| 794 } | |
| 795 | |
| 796 | |
| 797 bool Debug::SetBreakPoint(Handle<JSFunction> function, | 778 bool Debug::SetBreakPoint(Handle<JSFunction> function, |
| 798 Handle<Object> break_point_object, | 779 Handle<Object> break_point_object, |
| 799 int* source_position) { | 780 int* source_position) { |
| 800 HandleScope scope(isolate_); | 781 HandleScope scope(isolate_); |
| 801 | 782 |
| 802 PrepareForBreakPoints(); | |
| 803 | |
| 804 // Make sure the function is compiled and has set up the debug info. | 783 // Make sure the function is compiled and has set up the debug info. |
| 805 Handle<SharedFunctionInfo> shared(function->shared()); | 784 Handle<SharedFunctionInfo> shared(function->shared()); |
| 806 if (!EnsureDebugInfo(shared, function)) { | 785 if (!EnsureDebugInfo(shared, function)) { |
| 807 // Return if retrieving debug info failed. | 786 // Return if retrieving debug info failed. |
| 808 return true; | 787 return true; |
| 809 } | 788 } |
| 810 | 789 |
| 811 Handle<DebugInfo> debug_info = GetDebugInfo(shared); | 790 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
| 812 // Source positions starts with zero. | 791 // Source positions starts with zero. |
| 813 DCHECK(*source_position >= 0); | 792 DCHECK(*source_position >= 0); |
| 814 | 793 |
| 815 // Find the break point and change it. | 794 // Find the break point and change it. |
| 816 BreakLocation location = BreakLocation::FromPosition( | 795 BreakLocation location = BreakLocation::FromPosition( |
| 817 debug_info, ALL_BREAK_LOCATIONS, *source_position, STATEMENT_ALIGNED); | 796 debug_info, ALL_BREAK_LOCATIONS, *source_position, STATEMENT_ALIGNED); |
| 818 *source_position = location.statement_position(); | 797 *source_position = location.statement_position(); |
| 819 location.SetBreakPoint(break_point_object); | 798 location.SetBreakPoint(break_point_object); |
| 820 | 799 |
| 821 // At least one active break point now. | 800 // At least one active break point now. |
| 822 return debug_info->GetBreakPointCount() > 0; | 801 return debug_info->GetBreakPointCount() > 0; |
| 823 } | 802 } |
| 824 | 803 |
| 825 | 804 |
| 826 bool Debug::SetBreakPointForScript(Handle<Script> script, | 805 bool Debug::SetBreakPointForScript(Handle<Script> script, |
| 827 Handle<Object> break_point_object, | 806 Handle<Object> break_point_object, |
| 828 int* source_position, | 807 int* source_position, |
| 829 BreakPositionAlignment alignment) { | 808 BreakPositionAlignment alignment) { |
| 830 HandleScope scope(isolate_); | 809 HandleScope scope(isolate_); |
| 831 | 810 |
| 832 PrepareForBreakPoints(); | |
| 833 | |
| 834 // Obtain shared function info for the function. | 811 // Obtain shared function info for the function. |
| 835 Handle<Object> result = | 812 Handle<Object> result = |
| 836 FindSharedFunctionInfoInScript(script, *source_position); | 813 FindSharedFunctionInfoInScript(script, *source_position); |
| 837 if (result->IsUndefined()) return false; | 814 if (result->IsUndefined()) return false; |
| 838 | 815 |
| 839 // Make sure the function has set up the debug info. | 816 // Make sure the function has set up the debug info. |
| 840 Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>::cast(result); | 817 Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>::cast(result); |
| 841 if (!EnsureDebugInfo(shared, Handle<JSFunction>::null())) { | 818 if (!EnsureDebugInfo(shared, Handle<JSFunction>::null())) { |
| 842 // Return if retrieving debug info failed. | 819 // Return if retrieving debug info failed. |
| 843 return false; | 820 return false; |
| 844 } | 821 } |
| 845 | 822 |
| 846 // Find position within function. The script position might be before the | 823 // Find position within function. The script position might be before the |
| 847 // source position of the first function. | 824 // source position of the first function. |
| 848 int position; | 825 int position; |
| 849 if (shared->start_position() > *source_position) { | 826 if (shared->start_position() > *source_position) { |
| 850 position = 0; | 827 position = 0; |
| 851 } else { | 828 } else { |
| 852 position = *source_position - shared->start_position(); | 829 position = *source_position - shared->start_position(); |
| 853 } | 830 } |
| 854 | 831 |
| 855 Handle<DebugInfo> debug_info = GetDebugInfo(shared); | 832 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
| 856 // Source positions starts with zero. | 833 // Source positions starts with zero. |
| 857 DCHECK(position >= 0); | 834 DCHECK(position >= 0); |
| 858 | 835 |
| 859 // Find the break point and change it. | 836 // Find the break point and change it. |
| 860 BreakLocation location = BreakLocation::FromPosition( | 837 BreakLocation location = BreakLocation::FromPosition( |
| 861 debug_info, ALL_BREAK_LOCATIONS, position, alignment); | 838 debug_info, ALL_BREAK_LOCATIONS, position, alignment); |
| 862 location.SetBreakPoint(break_point_object); | 839 location.SetBreakPoint(break_point_object); |
| 863 | 840 |
| 864 position = (alignment == STATEMENT_ALIGNED) ? location.statement_position() | 841 position = (alignment == STATEMENT_ALIGNED) ? location.statement_position() |
| 865 : location.position(); | 842 : location.position(); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 919 } | 896 } |
| 920 // Remove all debug info. | 897 // Remove all debug info. |
| 921 while (debug_info_list_ != NULL) { | 898 while (debug_info_list_ != NULL) { |
| 922 RemoveDebugInfoAndClearFromShared(debug_info_list_->debug_info()); | 899 RemoveDebugInfoAndClearFromShared(debug_info_list_->debug_info()); |
| 923 } | 900 } |
| 924 } | 901 } |
| 925 | 902 |
| 926 | 903 |
| 927 void Debug::FloodWithOneShot(Handle<JSFunction> function, | 904 void Debug::FloodWithOneShot(Handle<JSFunction> function, |
| 928 BreakLocatorType type) { | 905 BreakLocatorType type) { |
| 929 PrepareForBreakPoints(); | |
| 930 | |
| 931 // Make sure the function is compiled and has set up the debug info. | 906 // Make sure the function is compiled and has set up the debug info. |
| 932 Handle<SharedFunctionInfo> shared(function->shared()); | 907 Handle<SharedFunctionInfo> shared(function->shared()); |
| 933 if (!EnsureDebugInfo(shared, function)) { | 908 if (!EnsureDebugInfo(shared, function)) { |
| 934 // Return if we failed to retrieve the debug info. | 909 // Return if we failed to retrieve the debug info. |
| 935 return; | 910 return; |
| 936 } | 911 } |
| 937 | 912 |
| 938 // Flood the function with break points. | 913 // Flood the function with break points. |
| 939 for (BreakLocation::Iterator it(GetDebugInfo(shared), type); !it.Done(); | 914 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
| 940 it.Next()) { | 915 for (BreakLocation::Iterator it(debug_info, type); !it.Done(); it.Next()) { |
| 941 it.GetBreakLocation().SetOneShot(); | 916 it.GetBreakLocation().SetOneShot(); |
| 942 } | 917 } |
| 943 } | 918 } |
| 944 | 919 |
| 945 | 920 |
| 946 void Debug::FloodBoundFunctionWithOneShot(Handle<JSFunction> function) { | 921 void Debug::FloodBoundFunctionWithOneShot(Handle<JSFunction> function) { |
| 947 Handle<FixedArray> new_bindings(function->function_bindings()); | 922 Handle<FixedArray> new_bindings(function->function_bindings()); |
| 948 Handle<Object> bindee(new_bindings->get(JSFunction::kBoundFunctionIndex), | 923 Handle<Object> bindee(new_bindings->get(JSFunction::kBoundFunctionIndex), |
| 949 isolate_); | 924 isolate_); |
| 950 | 925 |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1026 | 1001 |
| 1027 bool Debug::IsBreakOnException(ExceptionBreakType type) { | 1002 bool Debug::IsBreakOnException(ExceptionBreakType type) { |
| 1028 if (type == BreakUncaughtException) { | 1003 if (type == BreakUncaughtException) { |
| 1029 return break_on_uncaught_exception_; | 1004 return break_on_uncaught_exception_; |
| 1030 } else { | 1005 } else { |
| 1031 return break_on_exception_; | 1006 return break_on_exception_; |
| 1032 } | 1007 } |
| 1033 } | 1008 } |
| 1034 | 1009 |
| 1035 | 1010 |
| 1011 FrameSummary GetFirstFrameSummary(JavaScriptFrame* frame) { |
| 1012 List<FrameSummary> frames(FLAG_max_inlining_levels + 1); |
| 1013 frame->Summarize(&frames); |
| 1014 return frames.first(); |
| 1015 } |
| 1016 |
| 1017 |
| 1036 void Debug::PrepareStep(StepAction step_action, | 1018 void Debug::PrepareStep(StepAction step_action, |
| 1037 int step_count, | 1019 int step_count, |
| 1038 StackFrame::Id frame_id) { | 1020 StackFrame::Id frame_id) { |
| 1039 HandleScope scope(isolate_); | 1021 HandleScope scope(isolate_); |
| 1040 | 1022 |
| 1041 PrepareForBreakPoints(); | |
| 1042 | |
| 1043 DCHECK(in_debug_scope()); | 1023 DCHECK(in_debug_scope()); |
| 1044 | 1024 |
| 1045 // Remember this step action and count. | 1025 // Remember this step action and count. |
| 1046 thread_local_.last_step_action_ = step_action; | 1026 thread_local_.last_step_action_ = step_action; |
| 1047 if (step_action == StepOut) { | 1027 if (step_action == StepOut) { |
| 1048 // For step out target frame will be found on the stack so there is no need | 1028 // For step out target frame will be found on the stack so there is no need |
| 1049 // to set step counter for it. It's expected to always be 0 for StepOut. | 1029 // to set step counter for it. It's expected to always be 0 for StepOut. |
| 1050 thread_local_.step_count_ = 0; | 1030 thread_local_.step_count_ = 0; |
| 1051 } else { | 1031 } else { |
| 1052 thread_local_.step_count_ = step_count; | 1032 thread_local_.step_count_ = step_count; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1077 if (!frame->function()->IsJSFunction()) { | 1057 if (!frame->function()->IsJSFunction()) { |
| 1078 // Step out: Find the calling JavaScript frame and flood it with | 1058 // Step out: Find the calling JavaScript frame and flood it with |
| 1079 // breakpoints. | 1059 // breakpoints. |
| 1080 frames_it.Advance(); | 1060 frames_it.Advance(); |
| 1081 // Fill the function to return to with one-shot break points. | 1061 // Fill the function to return to with one-shot break points. |
| 1082 JSFunction* function = frames_it.frame()->function(); | 1062 JSFunction* function = frames_it.frame()->function(); |
| 1083 FloodWithOneShot(Handle<JSFunction>(function)); | 1063 FloodWithOneShot(Handle<JSFunction>(function)); |
| 1084 return; | 1064 return; |
| 1085 } | 1065 } |
| 1086 | 1066 |
| 1087 List<FrameSummary> frames(FLAG_max_inlining_levels + 1); | |
| 1088 frames_it.frame()->Summarize(&frames); | |
| 1089 FrameSummary summary = frames.first(); | |
| 1090 | |
| 1091 // Get the debug info (create it if it does not exist). | 1067 // Get the debug info (create it if it does not exist). |
| 1068 FrameSummary summary = GetFirstFrameSummary(frame); |
| 1092 Handle<JSFunction> function(summary.function()); | 1069 Handle<JSFunction> function(summary.function()); |
| 1093 Handle<SharedFunctionInfo> shared(function->shared()); | 1070 Handle<SharedFunctionInfo> shared(function->shared()); |
| 1094 if (!EnsureDebugInfo(shared, function)) { | 1071 if (!EnsureDebugInfo(shared, function)) { |
| 1095 // Return if ensuring debug info failed. | 1072 // Return if ensuring debug info failed. |
| 1096 return; | 1073 return; |
| 1097 } | 1074 } |
| 1098 Handle<DebugInfo> debug_info = GetDebugInfo(shared); | |
| 1099 | 1075 |
| 1100 // Compute whether or not the target is a call target. | 1076 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
| 1101 bool is_at_restarted_function = false; | 1077 // Refresh frame summary if the code has been recompiled for debugging. |
| 1102 Handle<Code> call_function_stub; | 1078 if (shared->code() != *summary.code()) summary = GetFirstFrameSummary(frame); |
| 1103 | 1079 |
| 1104 // PC points to the instruction after the current one, possibly a break | 1080 // PC points to the instruction after the current one, possibly a break |
| 1105 // location as well. So the "- 1" to exclude it from the search. | 1081 // location as well. So the "- 1" to exclude it from the search. |
| 1106 Address call_pc = summary.pc() - 1; | 1082 Address call_pc = summary.pc() - 1; |
| 1107 BreakLocation location = | 1083 BreakLocation location = |
| 1108 BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc); | 1084 BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc); |
| 1109 | 1085 |
| 1110 if (thread_local_.restarter_frame_function_pointer_ != NULL) { | |
| 1111 is_at_restarted_function = true; | |
| 1112 } | |
| 1113 | |
| 1114 // If this is the last break code target step out is the only possibility. | 1086 // If this is the last break code target step out is the only possibility. |
| 1115 if (location.IsReturn() || step_action == StepOut) { | 1087 if (location.IsReturn() || step_action == StepOut) { |
| 1116 if (step_action == StepOut) { | 1088 if (step_action == StepOut) { |
| 1117 // Skip step_count frames starting with the current one. | 1089 // Skip step_count frames starting with the current one. |
| 1118 while (step_count-- > 0 && !frames_it.done()) { | 1090 while (step_count-- > 0 && !frames_it.done()) { |
| 1119 frames_it.Advance(); | 1091 frames_it.Advance(); |
| 1120 } | 1092 } |
| 1121 } else { | 1093 } else { |
| 1122 DCHECK(location.IsReturn()); | 1094 DCHECK(location.IsReturn()); |
| 1123 frames_it.Advance(); | 1095 frames_it.Advance(); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1135 FloodWithOneShot(Handle<JSFunction>(function)); | 1107 FloodWithOneShot(Handle<JSFunction>(function)); |
| 1136 // Set target frame pointer. | 1108 // Set target frame pointer. |
| 1137 ActivateStepOut(frames_it.frame()); | 1109 ActivateStepOut(frames_it.frame()); |
| 1138 } | 1110 } |
| 1139 return; | 1111 return; |
| 1140 } | 1112 } |
| 1141 | 1113 |
| 1142 if (step_action != StepNext && step_action != StepMin) { | 1114 if (step_action != StepNext && step_action != StepMin) { |
| 1143 // If there's restarter frame on top of the stack, just get the pointer | 1115 // If there's restarter frame on top of the stack, just get the pointer |
| 1144 // to function which is going to be restarted. | 1116 // to function which is going to be restarted. |
| 1145 if (is_at_restarted_function) { | 1117 if (thread_local_.restarter_frame_function_pointer_ != NULL) { |
| 1146 Handle<JSFunction> restarted_function( | 1118 Handle<JSFunction> restarted_function( |
| 1147 JSFunction::cast(*thread_local_.restarter_frame_function_pointer_)); | 1119 JSFunction::cast(*thread_local_.restarter_frame_function_pointer_)); |
| 1148 FloodWithOneShot(restarted_function); | 1120 FloodWithOneShot(restarted_function); |
| 1149 } else if (location.IsCall()) { | 1121 } else if (location.IsCall()) { |
| 1150 // Find target function on the expression stack. | 1122 // Find target function on the expression stack. |
| 1151 // Expression stack looks like this (top to bottom): | 1123 // Expression stack looks like this (top to bottom): |
| 1152 // argN | 1124 // argN |
| 1153 // ... | 1125 // ... |
| 1154 // arg0 | 1126 // arg0 |
| 1155 // Receiver | 1127 // Receiver |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1246 return code->is_debug_stub(); | 1218 return code->is_debug_stub(); |
| 1247 } | 1219 } |
| 1248 | 1220 |
| 1249 | 1221 |
| 1250 // Simple function for returning the source positions for active break points. | 1222 // Simple function for returning the source positions for active break points. |
| 1251 Handle<Object> Debug::GetSourceBreakLocations( | 1223 Handle<Object> Debug::GetSourceBreakLocations( |
| 1252 Handle<SharedFunctionInfo> shared, | 1224 Handle<SharedFunctionInfo> shared, |
| 1253 BreakPositionAlignment position_alignment) { | 1225 BreakPositionAlignment position_alignment) { |
| 1254 Isolate* isolate = shared->GetIsolate(); | 1226 Isolate* isolate = shared->GetIsolate(); |
| 1255 Heap* heap = isolate->heap(); | 1227 Heap* heap = isolate->heap(); |
| 1256 if (!HasDebugInfo(shared)) { | 1228 if (!shared->HasDebugInfo()) { |
| 1257 return Handle<Object>(heap->undefined_value(), isolate); | 1229 return Handle<Object>(heap->undefined_value(), isolate); |
| 1258 } | 1230 } |
| 1259 Handle<DebugInfo> debug_info = GetDebugInfo(shared); | 1231 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
| 1260 if (debug_info->GetBreakPointCount() == 0) { | 1232 if (debug_info->GetBreakPointCount() == 0) { |
| 1261 return Handle<Object>(heap->undefined_value(), isolate); | 1233 return Handle<Object>(heap->undefined_value(), isolate); |
| 1262 } | 1234 } |
| 1263 Handle<FixedArray> locations = | 1235 Handle<FixedArray> locations = |
| 1264 isolate->factory()->NewFixedArray(debug_info->GetBreakPointCount()); | 1236 isolate->factory()->NewFixedArray(debug_info->GetBreakPointCount()); |
| 1265 int count = 0; | 1237 int count = 0; |
| 1266 for (int i = 0; i < debug_info->break_points()->length(); ++i) { | 1238 for (int i = 0; i < debug_info->break_points()->length(); ++i) { |
| 1267 if (!debug_info->break_points()->get(i)->IsUndefined()) { | 1239 if (!debug_info->break_points()->get(i)->IsUndefined()) { |
| 1268 BreakPointInfo* break_point_info = | 1240 BreakPointInfo* break_point_info = |
| 1269 BreakPointInfo::cast(debug_info->break_points()->get(i)); | 1241 BreakPointInfo::cast(debug_info->break_points()->get(i)); |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1362 } | 1334 } |
| 1363 | 1335 |
| 1364 | 1336 |
| 1365 void Debug::ClearStepNext() { | 1337 void Debug::ClearStepNext() { |
| 1366 thread_local_.last_step_action_ = StepNone; | 1338 thread_local_.last_step_action_ = StepNone; |
| 1367 thread_local_.last_statement_position_ = RelocInfo::kNoPosition; | 1339 thread_local_.last_statement_position_ = RelocInfo::kNoPosition; |
| 1368 thread_local_.last_fp_ = 0; | 1340 thread_local_.last_fp_ = 0; |
| 1369 } | 1341 } |
| 1370 | 1342 |
| 1371 | 1343 |
| 1372 static void CollectActiveFunctionsFromThread( | |
| 1373 Isolate* isolate, | |
| 1374 ThreadLocalTop* top, | |
| 1375 List<Handle<JSFunction> >* active_functions, | |
| 1376 Object* active_code_marker) { | |
| 1377 // Find all non-optimized code functions with activation frames | |
| 1378 // on the stack. This includes functions which have optimized | |
| 1379 // activations (including inlined functions) on the stack as the | |
| 1380 // non-optimized code is needed for the lazy deoptimization. | |
| 1381 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) { | |
| 1382 JavaScriptFrame* frame = it.frame(); | |
| 1383 if (frame->is_optimized()) { | |
| 1384 List<JSFunction*> functions(FLAG_max_inlining_levels + 1); | |
| 1385 frame->GetFunctions(&functions); | |
| 1386 for (int i = 0; i < functions.length(); i++) { | |
| 1387 JSFunction* function = functions[i]; | |
| 1388 active_functions->Add(Handle<JSFunction>(function)); | |
| 1389 function->shared()->code()->set_gc_metadata(active_code_marker); | |
| 1390 } | |
| 1391 } else if (frame->function()->IsJSFunction()) { | |
| 1392 JSFunction* function = frame->function(); | |
| 1393 DCHECK(frame->LookupCode()->kind() == Code::FUNCTION); | |
| 1394 active_functions->Add(Handle<JSFunction>(function)); | |
| 1395 function->shared()->code()->set_gc_metadata(active_code_marker); | |
| 1396 } | |
| 1397 } | |
| 1398 } | |
| 1399 | |
| 1400 | |
| 1401 // Count the number of calls before the current frame PC to find the | 1344 // Count the number of calls before the current frame PC to find the |
| 1402 // corresponding PC in the newly recompiled code. | 1345 // corresponding PC in the newly recompiled code. |
| 1403 static Address ComputeNewPcForRedirect(Code* new_code, Code* old_code, | 1346 static Address ComputeNewPcForRedirect(Code* new_code, Code* old_code, |
| 1404 Address old_pc) { | 1347 Address old_pc) { |
| 1405 DCHECK_EQ(old_code->kind(), Code::FUNCTION); | 1348 DCHECK_EQ(old_code->kind(), Code::FUNCTION); |
| 1406 DCHECK_EQ(new_code->kind(), Code::FUNCTION); | 1349 DCHECK_EQ(new_code->kind(), Code::FUNCTION); |
| 1407 DCHECK(!old_code->has_debug_break_slots()); | |
| 1408 DCHECK(new_code->has_debug_break_slots()); | 1350 DCHECK(new_code->has_debug_break_slots()); |
| 1409 int mask = RelocInfo::kCodeTargetMask; | 1351 int mask = RelocInfo::kCodeTargetMask; |
| 1410 int index = 0; | 1352 int index = 0; |
| 1411 intptr_t delta = 0; | 1353 intptr_t delta = 0; |
| 1412 for (RelocIterator it(old_code, mask); !it.done(); it.next()) { | 1354 for (RelocIterator it(old_code, mask); !it.done(); it.next()) { |
| 1413 RelocInfo* rinfo = it.rinfo(); | 1355 RelocInfo* rinfo = it.rinfo(); |
| 1414 Address current_pc = rinfo->pc(); | 1356 Address current_pc = rinfo->pc(); |
| 1415 // The frame PC is behind the call instruction by the call instruction size. | 1357 // The frame PC is behind the call instruction by the call instruction size. |
| 1416 if (current_pc > old_pc) break; | 1358 if (current_pc > old_pc) break; |
| 1417 index++; | 1359 index++; |
| 1418 delta = old_pc - current_pc; | 1360 delta = old_pc - current_pc; |
| 1419 } | 1361 } |
| 1420 | 1362 |
| 1421 RelocIterator it(new_code, mask); | 1363 RelocIterator it(new_code, mask); |
| 1422 for (int i = 1; i < index; i++) it.next(); | 1364 for (int i = 1; i < index; i++) it.next(); |
| 1423 return it.rinfo()->pc() + delta; | 1365 return it.rinfo()->pc() + delta; |
| 1424 } | 1366 } |
| 1425 | 1367 |
| 1426 | 1368 |
| 1427 // Count the number of continuations at which the current pc offset is at. | 1369 // Count the number of continuations at which the current pc offset is at. |
| 1428 static int ComputeContinuationIndexFromPcOffset(Code* code, int pc_offset) { | 1370 static int ComputeContinuationIndexFromPcOffset(Code* code, int pc_offset) { |
| 1429 DCHECK_EQ(code->kind(), Code::FUNCTION); | 1371 DCHECK_EQ(code->kind(), Code::FUNCTION); |
| 1430 DCHECK(!code->has_debug_break_slots()); | |
| 1431 Address pc = code->instruction_start() + pc_offset; | 1372 Address pc = code->instruction_start() + pc_offset; |
| 1432 int mask = RelocInfo::ModeMask(RelocInfo::GENERATOR_CONTINUATION); | 1373 int mask = RelocInfo::ModeMask(RelocInfo::GENERATOR_CONTINUATION); |
| 1433 int index = 0; | 1374 int index = 0; |
| 1434 for (RelocIterator it(code, mask); !it.done(); it.next()) { | 1375 for (RelocIterator it(code, mask); !it.done(); it.next()) { |
| 1435 index++; | 1376 index++; |
| 1436 RelocInfo* rinfo = it.rinfo(); | 1377 RelocInfo* rinfo = it.rinfo(); |
| 1437 Address current_pc = rinfo->pc(); | 1378 Address current_pc = rinfo->pc(); |
| 1438 if (current_pc == pc) break; | 1379 if (current_pc == pc) break; |
| 1439 DCHECK(current_pc < pc); | 1380 DCHECK(current_pc < pc); |
| 1440 } | 1381 } |
| 1441 return index; | 1382 return index; |
| 1442 } | 1383 } |
| 1443 | 1384 |
| 1444 | 1385 |
| 1445 // Find the pc offset for the given continuation index. | 1386 // Find the pc offset for the given continuation index. |
| 1446 static int ComputePcOffsetFromContinuationIndex(Code* code, int index) { | 1387 static int ComputePcOffsetFromContinuationIndex(Code* code, int index) { |
| 1447 DCHECK_EQ(code->kind(), Code::FUNCTION); | 1388 DCHECK_EQ(code->kind(), Code::FUNCTION); |
| 1448 DCHECK(code->has_debug_break_slots()); | 1389 DCHECK(code->has_debug_break_slots()); |
| 1449 int mask = RelocInfo::ModeMask(RelocInfo::GENERATOR_CONTINUATION); | 1390 int mask = RelocInfo::ModeMask(RelocInfo::GENERATOR_CONTINUATION); |
| 1450 RelocIterator it(code, mask); | 1391 RelocIterator it(code, mask); |
| 1451 for (int i = 1; i < index; i++) it.next(); | 1392 for (int i = 1; i < index; i++) it.next(); |
| 1452 return static_cast<int>(it.rinfo()->pc() - code->instruction_start()); | 1393 return static_cast<int>(it.rinfo()->pc() - code->instruction_start()); |
| 1453 } | 1394 } |
| 1454 | 1395 |
| 1455 | 1396 |
| 1456 static void RedirectActivationsToRecompiledCodeOnThread( | 1397 class RedirectActiveFunctions : public ThreadVisitor { |
| 1457 Isolate* isolate, | 1398 public: |
| 1458 ThreadLocalTop* top) { | 1399 explicit RedirectActiveFunctions(SharedFunctionInfo* shared) |
| 1459 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) { | 1400 : shared_(shared) { |
| 1460 JavaScriptFrame* frame = it.frame(); | 1401 DCHECK(shared->HasDebugCode()); |
| 1402 } |
| 1461 | 1403 |
| 1462 if (frame->is_optimized() || !frame->function()->IsJSFunction()) continue; | 1404 void VisitThread(Isolate* isolate, ThreadLocalTop* top) { |
| 1405 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) { |
| 1406 JavaScriptFrame* frame = it.frame(); |
| 1407 JSFunction* function = frame->function(); |
| 1408 if (frame->is_optimized()) continue; |
| 1409 if (!function->Inlines(shared_)) continue; |
| 1463 | 1410 |
| 1464 JSFunction* function = frame->function(); | 1411 Code* frame_code = frame->LookupCode(); |
| 1412 DCHECK(frame_code->kind() == Code::FUNCTION); |
| 1413 if (frame_code->has_debug_break_slots()) continue; |
| 1465 | 1414 |
| 1466 DCHECK(frame->LookupCode()->kind() == Code::FUNCTION); | 1415 Code* new_code = function->shared()->code(); |
| 1416 Address old_pc = frame->pc(); |
| 1417 Address new_pc = ComputeNewPcForRedirect(new_code, frame_code, old_pc); |
| 1467 | 1418 |
| 1468 Handle<Code> frame_code(frame->LookupCode()); | 1419 if (FLAG_trace_deopt) { |
| 1469 if (frame_code->has_debug_break_slots()) continue; | 1420 PrintF("Replacing pc for debugging: %08" V8PRIxPTR " => %08" V8PRIxPTR |
| 1421 "\n", |
| 1422 reinterpret_cast<intptr_t>(old_pc), |
| 1423 reinterpret_cast<intptr_t>(new_pc)); |
| 1424 } |
| 1470 | 1425 |
| 1471 Handle<Code> new_code(function->shared()->code()); | 1426 if (FLAG_enable_embedded_constant_pool) { |
| 1472 if (new_code->kind() != Code::FUNCTION || | 1427 // Update constant pool pointer for new code. |
| 1473 !new_code->has_debug_break_slots()) { | 1428 frame->set_constant_pool(new_code->constant_pool()); |
| 1474 continue; | 1429 } |
| 1430 |
| 1431 // Patch the return address to return into the code with |
| 1432 // debug break slots. |
| 1433 frame->set_pc(new_pc); |
| 1475 } | 1434 } |
| 1435 } |
| 1476 | 1436 |
| 1477 Address new_pc = | 1437 private: |
| 1478 ComputeNewPcForRedirect(*new_code, *frame_code, frame->pc()); | 1438 SharedFunctionInfo* shared_; |
| 1439 DisallowHeapAllocation no_gc_; |
| 1440 }; |
| 1479 | 1441 |
| 1480 if (FLAG_trace_deopt) { | 1442 |
| 1481 PrintF("Replacing code %08" V8PRIxPTR " - %08" V8PRIxPTR " (%d) " | 1443 bool Debug::PrepareFunctionForBreakPoints(Handle<SharedFunctionInfo> shared) { |
| 1482 "with %08" V8PRIxPTR " - %08" V8PRIxPTR " (%d) " | 1444 DCHECK(shared->is_compiled()); |
| 1483 "for debugging, " | 1445 |
| 1484 "changing pc from %08" V8PRIxPTR " to %08" V8PRIxPTR "\n", | 1446 if (isolate_->concurrent_recompilation_enabled()) { |
| 1485 reinterpret_cast<intptr_t>( | 1447 isolate_->optimizing_compile_dispatcher()->Flush(); |
| 1486 frame_code->instruction_start()), | 1448 } |
| 1487 reinterpret_cast<intptr_t>( | 1449 |
| 1488 frame_code->instruction_start()) + | 1450 List<Handle<JSFunction> > functions; |
| 1489 frame_code->instruction_size(), | 1451 List<Handle<JSGeneratorObject> > suspended_generators; |
| 1490 frame_code->instruction_size(), | 1452 |
| 1491 reinterpret_cast<intptr_t>(new_code->instruction_start()), | 1453 if (!shared->optimized_code_map()->IsSmi()) { |
| 1492 reinterpret_cast<intptr_t>(new_code->instruction_start()) + | 1454 shared->ClearOptimizedCodeMap(); |
| 1493 new_code->instruction_size(), | 1455 } |
| 1494 new_code->instruction_size(), | 1456 |
| 1495 reinterpret_cast<intptr_t>(frame->pc()), | 1457 // Make sure we abort incremental marking. |
| 1496 reinterpret_cast<intptr_t>(new_pc)); | 1458 isolate_->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask, |
| 1459 "prepare for break points"); |
| 1460 |
| 1461 { |
| 1462 HeapIterator iterator(isolate_->heap()); |
| 1463 HeapObject* obj; |
| 1464 bool include_generators = shared->is_generator(); |
| 1465 |
| 1466 while ((obj = iterator.next())) { |
| 1467 if (obj->IsJSFunction()) { |
| 1468 JSFunction* function = JSFunction::cast(obj); |
| 1469 if (!function->Inlines(*shared)) continue; |
| 1470 if (function->code()->kind() == Code::OPTIMIZED_FUNCTION) { |
| 1471 Deoptimizer::DeoptimizeFunction(function); |
| 1472 } |
| 1473 functions.Add(handle(function)); |
| 1474 } else if (include_generators && obj->IsJSGeneratorObject()) { |
| 1475 JSGeneratorObject* generator_obj = JSGeneratorObject::cast(obj); |
| 1476 if (!generator_obj->is_suspended()) continue; |
| 1477 JSFunction* function = generator_obj->function(); |
| 1478 if (!function->Inlines(*shared)) continue; |
| 1479 int pc_offset = generator_obj->continuation(); |
| 1480 int index = |
| 1481 ComputeContinuationIndexFromPcOffset(function->code(), pc_offset); |
| 1482 generator_obj->set_continuation(index); |
| 1483 suspended_generators.Add(handle(generator_obj)); |
| 1484 } |
| 1497 } | 1485 } |
| 1486 } |
| 1498 | 1487 |
| 1499 if (FLAG_enable_embedded_constant_pool) { | 1488 if (!shared->HasDebugCode()) { |
| 1500 // Update constant pool pointer for new code. | 1489 DCHECK(functions.length() > 0); |
| 1501 frame->set_constant_pool(new_code->constant_pool()); | 1490 if (Compiler::GetDebugCode(functions.first()).is_null()) { |
| 1491 return false; |
| 1502 } | 1492 } |
| 1493 } |
| 1503 | 1494 |
| 1504 // Patch the return address to return into the code with | 1495 for (Handle<JSFunction> const function : functions) { |
| 1505 // debug break slots. | 1496 function->ReplaceCode(shared->code()); |
| 1506 frame->set_pc(new_pc); | |
| 1507 } | 1497 } |
| 1498 |
| 1499 for (Handle<JSGeneratorObject> const generator_obj : suspended_generators) { |
| 1500 int index = generator_obj->continuation(); |
| 1501 int pc_offset = ComputePcOffsetFromContinuationIndex(shared->code(), index); |
| 1502 generator_obj->set_continuation(pc_offset); |
| 1503 } |
| 1504 |
| 1505 // Update PCs on the stack to point to recompiled code. |
| 1506 RedirectActiveFunctions redirect_visitor(*shared); |
| 1507 redirect_visitor.VisitThread(isolate_, isolate_->thread_local_top()); |
| 1508 isolate_->thread_manager()->IterateArchivedThreads(&redirect_visitor); |
| 1509 |
| 1510 return true; |
| 1508 } | 1511 } |
| 1509 | 1512 |
| 1510 | 1513 |
| 1511 class ActiveFunctionsCollector : public ThreadVisitor { | |
| 1512 public: | |
| 1513 explicit ActiveFunctionsCollector(List<Handle<JSFunction> >* active_functions, | |
| 1514 Object* active_code_marker) | |
| 1515 : active_functions_(active_functions), | |
| 1516 active_code_marker_(active_code_marker) { } | |
| 1517 | |
| 1518 void VisitThread(Isolate* isolate, ThreadLocalTop* top) { | |
| 1519 CollectActiveFunctionsFromThread(isolate, | |
| 1520 top, | |
| 1521 active_functions_, | |
| 1522 active_code_marker_); | |
| 1523 } | |
| 1524 | |
| 1525 private: | |
| 1526 List<Handle<JSFunction> >* active_functions_; | |
| 1527 Object* active_code_marker_; | |
| 1528 }; | |
| 1529 | |
| 1530 | |
| 1531 class ActiveFunctionsRedirector : public ThreadVisitor { | |
| 1532 public: | |
| 1533 void VisitThread(Isolate* isolate, ThreadLocalTop* top) { | |
| 1534 RedirectActivationsToRecompiledCodeOnThread(isolate, top); | |
| 1535 } | |
| 1536 }; | |
| 1537 | |
| 1538 | |
| 1539 static void EnsureFunctionHasDebugBreakSlots(Handle<JSFunction> function) { | |
| 1540 if (function->code()->kind() == Code::FUNCTION && | |
| 1541 function->code()->has_debug_break_slots()) { | |
| 1542 // Nothing to do. Function code already had debug break slots. | |
| 1543 return; | |
| 1544 } | |
| 1545 // Make sure that the shared full code is compiled with debug | |
| 1546 // break slots. | |
| 1547 if (!function->shared()->code()->has_debug_break_slots()) { | |
| 1548 MaybeHandle<Code> code = Compiler::GetDebugCode(function); | |
| 1549 // Recompilation can fail. In that case leave the code as it was. | |
| 1550 if (!code.is_null()) function->ReplaceCode(*code.ToHandleChecked()); | |
| 1551 } else { | |
| 1552 // Simply use shared code if it has debug break slots. | |
| 1553 function->ReplaceCode(function->shared()->code()); | |
| 1554 } | |
| 1555 } | |
| 1556 | |
| 1557 | |
| 1558 static void RecompileAndRelocateSuspendedGenerators( | |
| 1559 const List<Handle<JSGeneratorObject> > &generators) { | |
| 1560 for (int i = 0; i < generators.length(); i++) { | |
| 1561 Handle<JSFunction> fun(generators[i]->function()); | |
| 1562 | |
| 1563 EnsureFunctionHasDebugBreakSlots(fun); | |
| 1564 | |
| 1565 int index = generators[i]->continuation(); | |
| 1566 int pc_offset = ComputePcOffsetFromContinuationIndex(fun->code(), index); | |
| 1567 generators[i]->set_continuation(pc_offset); | |
| 1568 } | |
| 1569 } | |
| 1570 | |
| 1571 | |
| 1572 static bool SkipSharedFunctionInfo(SharedFunctionInfo* shared, | |
| 1573 Object* active_code_marker) { | |
| 1574 if (!shared->allows_lazy_compilation()) return true; | |
| 1575 Object* script = shared->script(); | |
| 1576 if (!script->IsScript()) return true; | |
| 1577 if (Script::cast(script)->type()->value() == Script::TYPE_NATIVE) return true; | |
| 1578 Code* shared_code = shared->code(); | |
| 1579 return shared_code->gc_metadata() == active_code_marker; | |
| 1580 } | |
| 1581 | |
| 1582 | |
| 1583 static inline bool HasDebugBreakSlots(Code* code) { | |
| 1584 return code->kind() == Code::FUNCTION && code->has_debug_break_slots(); | |
| 1585 } | |
| 1586 | |
| 1587 | |
| 1588 void Debug::PrepareForBreakPoints() { | |
| 1589 // If preparing for the first break point make sure to deoptimize all | |
| 1590 // functions as debugging does not work with optimized code. | |
| 1591 if (!has_break_points_) { | |
| 1592 if (isolate_->concurrent_recompilation_enabled()) { | |
| 1593 isolate_->optimizing_compile_dispatcher()->Flush(); | |
| 1594 } | |
| 1595 | |
| 1596 Deoptimizer::DeoptimizeAll(isolate_); | |
| 1597 | |
| 1598 Handle<Code> lazy_compile = isolate_->builtins()->CompileLazy(); | |
| 1599 | |
| 1600 // There will be at least one break point when we are done. | |
| 1601 has_break_points_ = true; | |
| 1602 | |
| 1603 // Keep the list of activated functions in a handlified list as it | |
| 1604 // is used both in GC and non-GC code. | |
| 1605 List<Handle<JSFunction> > active_functions(100); | |
| 1606 | |
| 1607 // A list of all suspended generators. | |
| 1608 List<Handle<JSGeneratorObject> > suspended_generators; | |
| 1609 | |
| 1610 // A list of all generator functions. We need to recompile all functions, | |
| 1611 // but we don't know until after visiting the whole heap which generator | |
| 1612 // functions have suspended activations and which do not. As in the case of | |
| 1613 // functions with activations on the stack, we need to be careful with | |
| 1614 // generator functions with suspended activations because although they | |
| 1615 // should be recompiled, recompilation can fail, and we need to avoid | |
| 1616 // leaving the heap in an inconsistent state. | |
| 1617 // | |
| 1618 // We could perhaps avoid this list and instead re-use the GC metadata | |
| 1619 // links. | |
| 1620 List<Handle<JSFunction> > generator_functions; | |
| 1621 | |
| 1622 { | |
| 1623 // We are going to iterate heap to find all functions without | |
| 1624 // debug break slots. | |
| 1625 Heap* heap = isolate_->heap(); | |
| 1626 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, | |
| 1627 "preparing for breakpoints"); | |
| 1628 HeapIterator iterator(heap); | |
| 1629 | |
| 1630 // Ensure no GC in this scope as we are going to use gc_metadata | |
| 1631 // field in the Code object to mark active functions. | |
| 1632 DisallowHeapAllocation no_allocation; | |
| 1633 | |
| 1634 Object* active_code_marker = heap->the_hole_value(); | |
| 1635 | |
| 1636 CollectActiveFunctionsFromThread(isolate_, | |
| 1637 isolate_->thread_local_top(), | |
| 1638 &active_functions, | |
| 1639 active_code_marker); | |
| 1640 ActiveFunctionsCollector active_functions_collector(&active_functions, | |
| 1641 active_code_marker); | |
| 1642 isolate_->thread_manager()->IterateArchivedThreads( | |
| 1643 &active_functions_collector); | |
| 1644 | |
| 1645 // Scan the heap for all non-optimized functions which have no | |
| 1646 // debug break slots and are not active or inlined into an active | |
| 1647 // function and mark them for lazy compilation. | |
| 1648 HeapObject* obj = NULL; | |
| 1649 while (((obj = iterator.next()) != NULL)) { | |
| 1650 if (obj->IsJSFunction()) { | |
| 1651 JSFunction* function = JSFunction::cast(obj); | |
| 1652 SharedFunctionInfo* shared = function->shared(); | |
| 1653 if (SkipSharedFunctionInfo(shared, active_code_marker)) continue; | |
| 1654 if (shared->is_generator()) { | |
| 1655 generator_functions.Add(Handle<JSFunction>(function, isolate_)); | |
| 1656 continue; | |
| 1657 } | |
| 1658 if (HasDebugBreakSlots(function->code())) continue; | |
| 1659 Code* fallback = HasDebugBreakSlots(shared->code()) ? shared->code() | |
| 1660 : *lazy_compile; | |
| 1661 Code::Kind kind = function->code()->kind(); | |
| 1662 if (kind == Code::FUNCTION || | |
| 1663 (kind == Code::BUILTIN && // Abort in-flight compilation. | |
| 1664 (function->IsInOptimizationQueue() || | |
| 1665 function->IsMarkedForOptimization() || | |
| 1666 function->IsMarkedForConcurrentOptimization()))) { | |
| 1667 function->ReplaceCode(fallback); | |
| 1668 } | |
| 1669 if (kind == Code::OPTIMIZED_FUNCTION) { | |
| 1670 // Optimized code can only get here if DeoptimizeAll did not | |
| 1671 // deoptimize turbo fan code. | |
| 1672 DCHECK(!FLAG_turbo_asm_deoptimization); | |
| 1673 DCHECK(function->shared()->asm_function()); | |
| 1674 DCHECK(function->code()->is_turbofanned()); | |
| 1675 function->ReplaceCode(fallback); | |
| 1676 } | |
| 1677 } else if (obj->IsJSGeneratorObject()) { | |
| 1678 JSGeneratorObject* gen = JSGeneratorObject::cast(obj); | |
| 1679 if (!gen->is_suspended()) continue; | |
| 1680 | |
| 1681 JSFunction* fun = gen->function(); | |
| 1682 DCHECK_EQ(fun->code()->kind(), Code::FUNCTION); | |
| 1683 if (fun->code()->has_debug_break_slots()) continue; | |
| 1684 | |
| 1685 int pc_offset = gen->continuation(); | |
| 1686 DCHECK_LT(0, pc_offset); | |
| 1687 | |
| 1688 int index = | |
| 1689 ComputeContinuationIndexFromPcOffset(fun->code(), pc_offset); | |
| 1690 | |
| 1691 // This will be fixed after we recompile the functions. | |
| 1692 gen->set_continuation(index); | |
| 1693 | |
| 1694 suspended_generators.Add(Handle<JSGeneratorObject>(gen, isolate_)); | |
| 1695 } else if (obj->IsSharedFunctionInfo()) { | |
| 1696 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj); | |
| 1697 if (SkipSharedFunctionInfo(shared, active_code_marker)) continue; | |
| 1698 if (shared->is_generator()) continue; | |
| 1699 if (HasDebugBreakSlots(shared->code())) continue; | |
| 1700 shared->ReplaceCode(*lazy_compile); | |
| 1701 } | |
| 1702 } | |
| 1703 | |
| 1704 // Clear gc_metadata field. | |
| 1705 for (int i = 0; i < active_functions.length(); i++) { | |
| 1706 Handle<JSFunction> function = active_functions[i]; | |
| 1707 function->shared()->code()->set_gc_metadata(Smi::FromInt(0)); | |
| 1708 } | |
| 1709 } | |
| 1710 | |
| 1711 // Recompile generator functions that have suspended activations, and | |
| 1712 // relocate those activations. | |
| 1713 RecompileAndRelocateSuspendedGenerators(suspended_generators); | |
| 1714 | |
| 1715 // Mark generator functions that didn't have suspended activations for lazy | |
| 1716 // recompilation. Note that this set does not include any active functions. | |
| 1717 for (int i = 0; i < generator_functions.length(); i++) { | |
| 1718 Handle<JSFunction> &function = generator_functions[i]; | |
| 1719 if (function->code()->kind() != Code::FUNCTION) continue; | |
| 1720 if (function->code()->has_debug_break_slots()) continue; | |
| 1721 function->ReplaceCode(*lazy_compile); | |
| 1722 function->shared()->ReplaceCode(*lazy_compile); | |
| 1723 } | |
| 1724 | |
| 1725 // Now recompile all functions with activation frames and and | |
| 1726 // patch the return address to run in the new compiled code. It could be | |
| 1727 // that some active functions were recompiled already by the suspended | |
| 1728 // generator recompilation pass above; a generator with suspended | |
| 1729 // activations could also have active activations. That's fine. | |
| 1730 for (int i = 0; i < active_functions.length(); i++) { | |
| 1731 Handle<JSFunction> function = active_functions[i]; | |
| 1732 Handle<SharedFunctionInfo> shared(function->shared()); | |
| 1733 if (!shared->allows_lazy_compilation()) { | |
| 1734 // Ignore functions that cannot be recompiled. Fortunately, those are | |
| 1735 // only ones that are not subject to debugging in the first place. | |
| 1736 DCHECK(!function->IsSubjectToDebugging()); | |
| 1737 continue; | |
| 1738 } | |
| 1739 if (shared->code()->kind() == Code::BUILTIN) continue; | |
| 1740 | |
| 1741 EnsureFunctionHasDebugBreakSlots(function); | |
| 1742 } | |
| 1743 | |
| 1744 RedirectActivationsToRecompiledCodeOnThread(isolate_, | |
| 1745 isolate_->thread_local_top()); | |
| 1746 | |
| 1747 ActiveFunctionsRedirector active_functions_redirector; | |
| 1748 isolate_->thread_manager()->IterateArchivedThreads( | |
| 1749 &active_functions_redirector); | |
| 1750 } | |
| 1751 } | |
| 1752 | |
| 1753 | |
| 1754 class SharedFunctionInfoFinder { | 1514 class SharedFunctionInfoFinder { |
| 1755 public: | 1515 public: |
| 1756 explicit SharedFunctionInfoFinder(int target_position) | 1516 explicit SharedFunctionInfoFinder(int target_position) |
| 1757 : current_candidate_(NULL), | 1517 : current_candidate_(NULL), |
| 1758 current_candidate_closure_(NULL), | 1518 current_candidate_closure_(NULL), |
| 1759 current_start_position_(RelocInfo::kNoPosition), | 1519 current_start_position_(RelocInfo::kNoPosition), |
| 1760 target_position_(target_position) {} | 1520 target_position_(target_position) {} |
| 1761 | 1521 |
| 1762 void NewCandidate(SharedFunctionInfo* shared, JSFunction* closure = NULL) { | 1522 void NewCandidate(SharedFunctionInfo* shared, JSFunction* closure = NULL) { |
| 1763 int start_position = shared->function_token_position(); | 1523 int start_position = shared->function_token_position(); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1792 | 1552 |
| 1793 private: | 1553 private: |
| 1794 SharedFunctionInfo* current_candidate_; | 1554 SharedFunctionInfo* current_candidate_; |
| 1795 JSFunction* current_candidate_closure_; | 1555 JSFunction* current_candidate_closure_; |
| 1796 int current_start_position_; | 1556 int current_start_position_; |
| 1797 int target_position_; | 1557 int target_position_; |
| 1798 DisallowHeapAllocation no_gc_; | 1558 DisallowHeapAllocation no_gc_; |
| 1799 }; | 1559 }; |
| 1800 | 1560 |
| 1801 | 1561 |
| 1802 template <typename C> | 1562 // We need to find a SFI for a literal that may not yet have been compiled yet, |
| 1803 bool Debug::CompileToRevealInnerFunctions(C* compilable) { | 1563 // and there may not be a JSFunction referencing it. Find the SFI closest to |
| 1804 HandleScope scope(isolate_); | 1564 // the given position, compile it to reveal possible inner SFIs and repeat. |
| 1805 // Force compiling inner functions that require context. | 1565 // While we are at this, also ensure code with debug break slots so that we do |
| 1806 // TODO(yangguo): remove this hack. | 1566 // not have to compile a SFI without JSFunction, which is paifu for those that |
| 1807 bool has_break_points = has_break_points_; | 1567 // cannot be compiled without context (need to find outer compilable SFI etc.) |
| 1808 has_break_points_ = true; | |
| 1809 Handle<C> compilable_handle(compilable); | |
| 1810 bool result = !Compiler::GetUnoptimizedCode(compilable_handle).is_null(); | |
| 1811 has_break_points_ = has_break_points; | |
| 1812 return result; | |
| 1813 } | |
| 1814 | |
| 1815 | |
| 1816 Handle<Object> Debug::FindSharedFunctionInfoInScript(Handle<Script> script, | 1568 Handle<Object> Debug::FindSharedFunctionInfoInScript(Handle<Script> script, |
| 1817 int position) { | 1569 int position) { |
| 1818 while (true) { | 1570 while (true) { |
| 1819 // Go through all shared function infos associated with this script to | 1571 // Go through all shared function infos associated with this script to |
| 1820 // find the inner most function containing this position. | 1572 // find the inner most function containing this position. |
| 1821 if (!script->shared_function_infos()->IsWeakFixedArray()) break; | 1573 if (!script->shared_function_infos()->IsWeakFixedArray()) break; |
| 1822 WeakFixedArray* array = | 1574 WeakFixedArray* array = |
| 1823 WeakFixedArray::cast(script->shared_function_infos()); | 1575 WeakFixedArray::cast(script->shared_function_infos()); |
| 1824 | 1576 |
| 1825 SharedFunctionInfo* shared; | 1577 SharedFunctionInfo* shared; |
| 1826 { | 1578 { |
| 1827 SharedFunctionInfoFinder finder(position); | 1579 SharedFunctionInfoFinder finder(position); |
| 1828 for (int i = 0; i < array->Length(); i++) { | 1580 for (int i = 0; i < array->Length(); i++) { |
| 1829 Object* item = array->Get(i); | 1581 Object* item = array->Get(i); |
| 1830 if (!item->IsSharedFunctionInfo()) continue; | 1582 if (!item->IsSharedFunctionInfo()) continue; |
| 1831 finder.NewCandidate(SharedFunctionInfo::cast(item)); | 1583 finder.NewCandidate(SharedFunctionInfo::cast(item)); |
| 1832 } | 1584 } |
| 1833 shared = finder.Result(); | 1585 shared = finder.Result(); |
| 1834 if (shared == NULL) break; | 1586 if (shared == NULL) break; |
| 1835 // We found it if it's already compiled. | 1587 // We found it if it's already compiled and has debug code. |
| 1836 if (shared->is_compiled()) return handle(shared); | 1588 if (shared->HasDebugCode()) return handle(shared); |
| 1837 } | 1589 } |
| 1838 // If not, compile to reveal inner functions, if possible. | 1590 // If not, compile to reveal inner functions, if possible. |
| 1839 if (shared->allows_lazy_compilation_without_context()) { | 1591 if (shared->allows_lazy_compilation_without_context()) { |
| 1840 if (!CompileToRevealInnerFunctions(shared)) break; | 1592 HandleScope scope(isolate_); |
| 1593 if (Compiler::GetDebugCode(handle(shared)).is_null()) break; |
| 1841 continue; | 1594 continue; |
| 1842 } | 1595 } |
| 1843 | 1596 |
| 1844 // If not possible, comb the heap for the best suitable compile target. | 1597 // If not possible, comb the heap for the best suitable compile target. |
| 1845 JSFunction* closure; | 1598 JSFunction* closure; |
| 1846 { | 1599 { |
| 1847 HeapIterator it(isolate_->heap(), HeapIterator::kNoFiltering); | 1600 HeapIterator it(isolate_->heap()); |
| 1848 SharedFunctionInfoFinder finder(position); | 1601 SharedFunctionInfoFinder finder(position); |
| 1849 while (HeapObject* object = it.next()) { | 1602 while (HeapObject* object = it.next()) { |
| 1850 JSFunction* candidate_closure = NULL; | 1603 JSFunction* candidate_closure = NULL; |
| 1851 SharedFunctionInfo* candidate = NULL; | 1604 SharedFunctionInfo* candidate = NULL; |
| 1852 if (object->IsJSFunction()) { | 1605 if (object->IsJSFunction()) { |
| 1853 candidate_closure = JSFunction::cast(object); | 1606 candidate_closure = JSFunction::cast(object); |
| 1854 candidate = candidate_closure->shared(); | 1607 candidate = candidate_closure->shared(); |
| 1855 } else if (object->IsSharedFunctionInfo()) { | 1608 } else if (object->IsSharedFunctionInfo()) { |
| 1856 candidate = SharedFunctionInfo::cast(object); | 1609 candidate = SharedFunctionInfo::cast(object); |
| 1857 if (!candidate->allows_lazy_compilation_without_context()) continue; | 1610 if (!candidate->allows_lazy_compilation_without_context()) continue; |
| 1858 } else { | 1611 } else { |
| 1859 continue; | 1612 continue; |
| 1860 } | 1613 } |
| 1861 if (candidate->script() == *script) { | 1614 if (candidate->script() == *script) { |
| 1862 finder.NewCandidate(candidate, candidate_closure); | 1615 finder.NewCandidate(candidate, candidate_closure); |
| 1863 } | 1616 } |
| 1864 } | 1617 } |
| 1865 closure = finder.ResultClosure(); | 1618 closure = finder.ResultClosure(); |
| 1866 shared = finder.Result(); | 1619 shared = finder.Result(); |
| 1867 } | 1620 } |
| 1868 if (closure == NULL ? !CompileToRevealInnerFunctions(shared) | 1621 HandleScope scope(isolate_); |
| 1869 : !CompileToRevealInnerFunctions(closure)) { | 1622 if (closure == NULL) { |
| 1870 break; | 1623 if (Compiler::GetDebugCode(handle(shared)).is_null()) break; |
| 1624 } else { |
| 1625 if (Compiler::GetDebugCode(handle(closure)).is_null()) break; |
| 1871 } | 1626 } |
| 1872 } | 1627 } |
| 1873 return isolate_->factory()->undefined_value(); | 1628 return isolate_->factory()->undefined_value(); |
| 1874 } | 1629 } |
| 1875 | 1630 |
| 1876 | 1631 |
| 1877 // Ensures the debug information is present for shared. | 1632 // Ensures the debug information is present for shared. |
| 1878 bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared, | 1633 bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared, |
| 1879 Handle<JSFunction> function) { | 1634 Handle<JSFunction> function) { |
| 1880 if (!shared->IsSubjectToDebugging()) return false; | 1635 if (!shared->IsSubjectToDebugging()) return false; |
| 1881 | 1636 |
| 1882 // Return if we already have the debug info for shared. | 1637 // Return if we already have the debug info for shared. |
| 1883 if (HasDebugInfo(shared)) { | 1638 if (shared->HasDebugInfo()) return true; |
| 1884 DCHECK(shared->is_compiled()); | |
| 1885 DCHECK(shared->code()->has_debug_break_slots()); | |
| 1886 return true; | |
| 1887 } | |
| 1888 | |
| 1889 // There will be at least one break point when we are done. | |
| 1890 has_break_points_ = true; | |
| 1891 | 1639 |
| 1892 if (function.is_null()) { | 1640 if (function.is_null()) { |
| 1893 DCHECK(shared->is_compiled()); | 1641 DCHECK(shared->HasDebugCode()); |
| 1894 DCHECK(shared->code()->has_debug_break_slots()); | |
| 1895 } else if (!Compiler::EnsureCompiled(function, CLEAR_EXCEPTION)) { | 1642 } else if (!Compiler::EnsureCompiled(function, CLEAR_EXCEPTION)) { |
| 1896 return false; | 1643 return false; |
| 1897 } | 1644 } |
| 1898 | 1645 |
| 1646 if (!PrepareFunctionForBreakPoints(shared)) return false; |
| 1647 |
| 1899 // Make sure IC state is clean. This is so that we correctly flood | 1648 // Make sure IC state is clean. This is so that we correctly flood |
| 1900 // accessor pairs when stepping in. | 1649 // accessor pairs when stepping in. |
| 1901 shared->code()->ClearInlineCaches(); | 1650 shared->code()->ClearInlineCaches(); |
| 1902 shared->feedback_vector()->ClearICSlots(*shared); | 1651 shared->feedback_vector()->ClearICSlots(*shared); |
| 1903 | 1652 |
| 1904 // Create the debug info object. | 1653 // Create the debug info object. |
| 1905 DCHECK(shared->is_compiled()); | 1654 DCHECK(shared->HasDebugCode()); |
| 1906 DCHECK(shared->code()->has_debug_break_slots()); | |
| 1907 Handle<DebugInfo> debug_info = isolate_->factory()->NewDebugInfo(shared); | 1655 Handle<DebugInfo> debug_info = isolate_->factory()->NewDebugInfo(shared); |
| 1908 | 1656 |
| 1909 // Add debug info to the list. | 1657 // Add debug info to the list. |
| 1910 DebugInfoListNode* node = new DebugInfoListNode(*debug_info); | 1658 DebugInfoListNode* node = new DebugInfoListNode(*debug_info); |
| 1911 node->set_next(debug_info_list_); | 1659 node->set_next(debug_info_list_); |
| 1912 debug_info_list_ = node; | 1660 debug_info_list_ = node; |
| 1913 | 1661 |
| 1914 return true; | 1662 return true; |
| 1915 } | 1663 } |
| 1916 | 1664 |
| 1917 | 1665 |
| 1918 void Debug::RemoveDebugInfo(DebugInfoListNode* prev, DebugInfoListNode* node) { | 1666 void Debug::RemoveDebugInfo(DebugInfoListNode* prev, DebugInfoListNode* node) { |
| 1919 // Unlink from list. If prev is NULL we are looking at the first element. | 1667 // Unlink from list. If prev is NULL we are looking at the first element. |
| 1920 if (prev == NULL) { | 1668 if (prev == NULL) { |
| 1921 debug_info_list_ = node->next(); | 1669 debug_info_list_ = node->next(); |
| 1922 } else { | 1670 } else { |
| 1923 prev->set_next(node->next()); | 1671 prev->set_next(node->next()); |
| 1924 } | 1672 } |
| 1925 delete node; | 1673 delete node; |
| 1926 | |
| 1927 // If there are no more debug info objects there are not more break | |
| 1928 // points. | |
| 1929 has_break_points_ = debug_info_list_ != NULL; | |
| 1930 } | 1674 } |
| 1931 | 1675 |
| 1932 | 1676 |
| 1933 void Debug::RemoveDebugInfo(DebugInfo** debug_info) { | 1677 void Debug::RemoveDebugInfo(DebugInfo** debug_info) { |
| 1934 DCHECK(debug_info_list_ != NULL); | 1678 DCHECK(debug_info_list_ != NULL); |
| 1935 // Run through the debug info objects to find this one and remove it. | 1679 // Run through the debug info objects to find this one and remove it. |
| 1936 DebugInfoListNode* prev = NULL; | 1680 DebugInfoListNode* prev = NULL; |
| 1937 DebugInfoListNode* current = debug_info_list_; | 1681 DebugInfoListNode* current = debug_info_list_; |
| 1938 while (current != NULL) { | 1682 while (current != NULL) { |
| 1939 if (current->debug_info().location() == debug_info) { | 1683 if (current->debug_info().location() == debug_info) { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1982 if (LiveEdit::SetAfterBreakTarget(this)) return; // LiveEdit did the job. | 1726 if (LiveEdit::SetAfterBreakTarget(this)) return; // LiveEdit did the job. |
| 1983 | 1727 |
| 1984 // Continue just after the slot. | 1728 // Continue just after the slot. |
| 1985 after_break_target_ = frame->pc(); | 1729 after_break_target_ = frame->pc(); |
| 1986 } | 1730 } |
| 1987 | 1731 |
| 1988 | 1732 |
| 1989 bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) { | 1733 bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) { |
| 1990 HandleScope scope(isolate_); | 1734 HandleScope scope(isolate_); |
| 1991 | 1735 |
| 1992 // If there are no break points this cannot be break at return, as | |
| 1993 // the debugger statement and stack guard debug break cannot be at | |
| 1994 // return. | |
| 1995 if (!has_break_points_) return false; | |
| 1996 | |
| 1997 PrepareForBreakPoints(); | |
| 1998 | |
| 1999 // Get the executing function in which the debug break occurred. | 1736 // Get the executing function in which the debug break occurred. |
| 2000 Handle<JSFunction> function(JSFunction::cast(frame->function())); | 1737 Handle<JSFunction> function(JSFunction::cast(frame->function())); |
| 2001 Handle<SharedFunctionInfo> shared(function->shared()); | 1738 Handle<SharedFunctionInfo> shared(function->shared()); |
| 2002 if (!EnsureDebugInfo(shared, function)) { | 1739 |
| 2003 // Return if we failed to retrieve the debug info. | 1740 // With no debug info there are no break points, so we can't be at a return. |
| 2004 return false; | 1741 if (!shared->HasDebugInfo()) return false; |
| 2005 } | 1742 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
| 2006 Handle<DebugInfo> debug_info = GetDebugInfo(shared); | |
| 2007 Handle<Code> code(debug_info->code()); | 1743 Handle<Code> code(debug_info->code()); |
| 2008 #ifdef DEBUG | 1744 #ifdef DEBUG |
| 2009 // Get the code which is actually executing. | 1745 // Get the code which is actually executing. |
| 2010 Handle<Code> frame_code(frame->LookupCode()); | 1746 Handle<Code> frame_code(frame->LookupCode()); |
| 2011 DCHECK(frame_code.is_identical_to(code)); | 1747 DCHECK(frame_code.is_identical_to(code)); |
| 2012 #endif | 1748 #endif |
| 2013 | 1749 |
| 2014 // Find the reloc info matching the start of the debug break slot. | 1750 // Find the reloc info matching the start of the debug break slot. |
| 2015 Address slot_pc = frame->pc() - Assembler::kDebugBreakSlotLength; | 1751 Address slot_pc = frame->pc() - Assembler::kDebugBreakSlotLength; |
| 2016 int mask = RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_RETURN); | 1752 int mask = RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_RETURN); |
| 2017 for (RelocIterator it(debug_info->code(), mask); !it.done(); it.next()) { | 1753 for (RelocIterator it(*code, mask); !it.done(); it.next()) { |
| 2018 if (it.rinfo()->pc() == slot_pc) return true; | 1754 if (it.rinfo()->pc() == slot_pc) return true; |
| 2019 } | 1755 } |
| 2020 return false; | 1756 return false; |
| 2021 } | 1757 } |
| 2022 | 1758 |
| 2023 | 1759 |
| 2024 void Debug::FramesHaveBeenDropped(StackFrame::Id new_break_frame_id, | 1760 void Debug::FramesHaveBeenDropped(StackFrame::Id new_break_frame_id, |
| 2025 LiveEdit::FrameDropMode mode, | 1761 LiveEdit::FrameDropMode mode, |
| 2026 Object** restarter_frame_function_pointer) { | 1762 Object** restarter_frame_function_pointer) { |
| 2027 if (mode != LiveEdit::CURRENTLY_SET_MODE) { | 1763 if (mode != LiveEdit::CURRENTLY_SET_MODE) { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2061 // Perform GC to get unreferenced scripts evicted from the cache before | 1797 // Perform GC to get unreferenced scripts evicted from the cache before |
| 2062 // returning the content. | 1798 // returning the content. |
| 2063 isolate_->heap()->CollectAllGarbage(Heap::kNoGCFlags, | 1799 isolate_->heap()->CollectAllGarbage(Heap::kNoGCFlags, |
| 2064 "Debug::GetLoadedScripts"); | 1800 "Debug::GetLoadedScripts"); |
| 2065 | 1801 |
| 2066 // Get the scripts from the cache. | 1802 // Get the scripts from the cache. |
| 2067 return script_cache_->GetScripts(); | 1803 return script_cache_->GetScripts(); |
| 2068 } | 1804 } |
| 2069 | 1805 |
| 2070 | 1806 |
| 1807 void Debug::GetStepinPositions(JavaScriptFrame* frame, StackFrame::Id frame_id, |
| 1808 List<int>* results_out) { |
| 1809 FrameSummary summary = GetFirstFrameSummary(frame); |
| 1810 |
| 1811 Handle<JSFunction> fun = Handle<JSFunction>(summary.function()); |
| 1812 Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>(fun->shared()); |
| 1813 |
| 1814 if (!EnsureDebugInfo(shared, fun)) return; |
| 1815 |
| 1816 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
| 1817 // Refresh frame summary if the code has been recompiled for debugging. |
| 1818 if (shared->code() != *summary.code()) summary = GetFirstFrameSummary(frame); |
| 1819 |
| 1820 // Find range of break points starting from the break point where execution |
| 1821 // has stopped. |
| 1822 Address call_pc = summary.pc() - 1; |
| 1823 List<BreakLocation> locations; |
| 1824 BreakLocation::FromAddressSameStatement(debug_info, ALL_BREAK_LOCATIONS, |
| 1825 call_pc, &locations); |
| 1826 |
| 1827 for (BreakLocation location : locations) { |
| 1828 if (location.pc() <= summary.pc()) { |
| 1829 // The break point is near our pc. Could be a step-in possibility, |
| 1830 // that is currently taken by active debugger call. |
| 1831 if (break_frame_id() == StackFrame::NO_ID) { |
| 1832 continue; // We are not stepping. |
| 1833 } else { |
| 1834 JavaScriptFrameIterator frame_it(isolate_, break_frame_id()); |
| 1835 // If our frame is a top frame and we are stepping, we can do step-in |
| 1836 // at this place. |
| 1837 if (frame_it.frame()->id() != frame_id) continue; |
| 1838 } |
| 1839 } |
| 1840 if (location.IsStepInLocation()) results_out->Add(location.position()); |
| 1841 } |
| 1842 } |
| 1843 |
| 1844 |
| 2071 void Debug::RecordEvalCaller(Handle<Script> script) { | 1845 void Debug::RecordEvalCaller(Handle<Script> script) { |
| 2072 script->set_compilation_type(Script::COMPILATION_TYPE_EVAL); | 1846 script->set_compilation_type(Script::COMPILATION_TYPE_EVAL); |
| 2073 // For eval scripts add information on the function from which eval was | 1847 // For eval scripts add information on the function from which eval was |
| 2074 // called. | 1848 // called. |
| 2075 StackTraceFrameIterator it(script->GetIsolate()); | 1849 StackTraceFrameIterator it(script->GetIsolate()); |
| 2076 if (!it.done()) { | 1850 if (!it.done()) { |
| 2077 script->set_eval_from_shared(it.frame()->function()->shared()); | 1851 script->set_eval_from_shared(it.frame()->function()->shared()); |
| 2078 Code* code = it.frame()->LookupCode(); | 1852 Code* code = it.frame()->LookupCode(); |
| 2079 int offset = static_cast<int>( | 1853 int offset = static_cast<int>( |
| 2080 it.frame()->pc() - code->instruction_start()); | 1854 it.frame()->pc() - code->instruction_start()); |
| (...skipping 979 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3060 } | 2834 } |
| 3061 | 2835 |
| 3062 | 2836 |
| 3063 void LockingCommandMessageQueue::Clear() { | 2837 void LockingCommandMessageQueue::Clear() { |
| 3064 base::LockGuard<base::Mutex> lock_guard(&mutex_); | 2838 base::LockGuard<base::Mutex> lock_guard(&mutex_); |
| 3065 queue_.Clear(); | 2839 queue_.Clear(); |
| 3066 } | 2840 } |
| 3067 | 2841 |
| 3068 } // namespace internal | 2842 } // namespace internal |
| 3069 } // namespace v8 | 2843 } // namespace v8 |
| OLD | NEW |