| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/debugger.h" | 5 #include "vm/debugger.h" |
| 6 | 6 |
| 7 #include "include/dart_api.h" | 7 #include "include/dart_api.h" |
| 8 | 8 |
| 9 #include "vm/code_generator.h" | 9 #include "vm/code_generator.h" |
| 10 #include "vm/code_patcher.h" | 10 #include "vm/code_patcher.h" |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 51 const Function& func, | 51 const Function& func, |
| 52 intptr_t token_pos) | 52 intptr_t token_pos) |
| 53 : id_(id), | 53 : id_(id), |
| 54 function_(func.raw()), | 54 function_(func.raw()), |
| 55 token_pos_(token_pos), | 55 token_pos_(token_pos), |
| 56 line_number_(-1), | 56 line_number_(-1), |
| 57 is_enabled_(false), | 57 is_enabled_(false), |
| 58 next_(NULL) { | 58 next_(NULL) { |
| 59 ASSERT(!func.IsNull()); | 59 ASSERT(!func.IsNull()); |
| 60 ASSERT((func.token_pos() <= token_pos_) && | 60 ASSERT((func.token_pos() <= token_pos_) && |
| 61 (token_pos_ < func.end_token_pos())); | 61 (token_pos_ <= func.end_token_pos())); |
| 62 } | 62 } |
| 63 | 63 |
| 64 | 64 |
| 65 void SourceBreakpoint::Enable() { | 65 void SourceBreakpoint::Enable() { |
| 66 is_enabled_ = true; | 66 is_enabled_ = true; |
| 67 Isolate::Current()->debugger()->SyncBreakpoint(this); | 67 Isolate::Current()->debugger()->SyncBreakpoint(this); |
| 68 } | 68 } |
| 69 | 69 |
| 70 | 70 |
| 71 void SourceBreakpoint::Disable() { | 71 void SourceBreakpoint::Disable() { |
| (...skipping 781 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 853 ASSERT(!function.IsNull()); | 853 ASSERT(!function.IsNull()); |
| 854 if (function.HasOptimizedCode()) { | 854 if (function.HasOptimizedCode()) { |
| 855 function.SwitchToUnoptimizedCode(); | 855 function.SwitchToUnoptimizedCode(); |
| 856 } | 856 } |
| 857 } | 857 } |
| 858 } | 858 } |
| 859 } | 859 } |
| 860 } | 860 } |
| 861 | 861 |
| 862 | 862 |
| 863 static bool IsSafePoint(PcDescriptors::Kind kind) { |
| 864 return ((kind == PcDescriptors::kIcCall) || |
| 865 (kind == PcDescriptors::kFuncCall) || |
| 866 (kind == PcDescriptors::kClosureCall) || |
| 867 (kind == PcDescriptors::kReturn)); |
| 868 } |
| 869 |
| 870 |
| 863 void Debugger::InstrumentForStepping(const Function& target_function) { | 871 void Debugger::InstrumentForStepping(const Function& target_function) { |
| 864 if (!target_function.HasCode()) { | 872 if (!target_function.HasCode()) { |
| 865 Compiler::CompileFunction(target_function); | 873 Compiler::CompileFunction(target_function); |
| 866 // If there were any errors, ignore them silently and return without | 874 // If there were any errors, ignore them silently and return without |
| 867 // adding breakpoints to target. | 875 // adding breakpoints to target. |
| 868 if (!target_function.HasCode()) { | 876 if (!target_function.HasCode()) { |
| 869 return; | 877 return; |
| 870 } | 878 } |
| 871 } | 879 } |
| 872 DeoptimizeWorld(); | 880 DeoptimizeWorld(); |
| 873 ASSERT(!target_function.HasOptimizedCode()); | 881 ASSERT(!target_function.HasOptimizedCode()); |
| 874 Code& code = Code::Handle(target_function.unoptimized_code()); | 882 Code& code = Code::Handle(target_function.unoptimized_code()); |
| 875 ASSERT(!code.IsNull()); | 883 ASSERT(!code.IsNull()); |
| 876 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); | 884 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); |
| 877 for (int i = 0; i < desc.Length(); i++) { | 885 for (int i = 0; i < desc.Length(); i++) { |
| 878 CodeBreakpoint* bpt = GetCodeBreakpoint(desc.PC(i)); | 886 CodeBreakpoint* bpt = GetCodeBreakpoint(desc.PC(i)); |
| 879 if (bpt != NULL) { | 887 if (bpt != NULL) { |
| 880 // There is already a breakpoint for this address. Make sure | 888 // There is already a breakpoint for this address. Make sure |
| 881 // it is enabled. | 889 // it is enabled. |
| 882 bpt->Enable(); | 890 bpt->Enable(); |
| 883 continue; | 891 continue; |
| 884 } | 892 } |
| 885 PcDescriptors::Kind kind = desc.DescriptorKind(i); | 893 if (IsSafePoint(desc.DescriptorKind(i))) { |
| 886 if ((kind == PcDescriptors::kIcCall) || | |
| 887 (kind == PcDescriptors::kFuncCall) || | |
| 888 (kind == PcDescriptors::kClosureCall) || | |
| 889 (kind == PcDescriptors::kReturn)) { | |
| 890 bpt = new CodeBreakpoint(target_function, i); | 894 bpt = new CodeBreakpoint(target_function, i); |
| 891 RegisterCodeBreakpoint(bpt); | 895 RegisterCodeBreakpoint(bpt); |
| 892 bpt->Enable(); | 896 bpt->Enable(); |
| 893 } | 897 } |
| 894 } | 898 } |
| 895 } | 899 } |
| 896 | 900 |
| 897 | 901 |
| 898 void Debugger::SignalBpResolved(SourceBreakpoint* bpt) { | 902 void Debugger::SignalBpResolved(SourceBreakpoint* bpt) { |
| 899 if (event_handler_ != NULL) { | 903 if (event_handler_ != NULL) { |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1021 DebuggerEvent event; | 1025 DebuggerEvent event; |
| 1022 event.type = kExceptionThrown; | 1026 event.type = kExceptionThrown; |
| 1023 event.exception = &exc; | 1027 event.exception = &exc; |
| 1024 ASSERT(event_handler_ != NULL); | 1028 ASSERT(event_handler_ != NULL); |
| 1025 (*event_handler_)(&event); | 1029 (*event_handler_)(&event); |
| 1026 stack_trace_ = NULL; | 1030 stack_trace_ = NULL; |
| 1027 obj_cache_ = NULL; // Remote object cache is zone allocated. | 1031 obj_cache_ = NULL; // Remote object cache is zone allocated. |
| 1028 } | 1032 } |
| 1029 | 1033 |
| 1030 | 1034 |
| 1031 CodeBreakpoint* Debugger::MakeCodeBreakpoint(const Function& func, | 1035 // Given a function and a token position range, return the best fit |
| 1032 intptr_t first_token_pos, | 1036 // token position to set a breakpoint. |
| 1033 intptr_t last_token_pos) { | 1037 // If multiple possible breakpoint positions are within the given range, |
| 1038 // the one with the lowest machine code address is picked. |
| 1039 // If no possible breakpoint location exists in the given range, the closest |
| 1040 // token position after the range is returned. |
| 1041 intptr_t Debugger::ResolveBreakpointPos(const Function& func, |
| 1042 intptr_t first_token_pos, |
| 1043 intptr_t last_token_pos) { |
| 1034 ASSERT(func.HasCode()); | 1044 ASSERT(func.HasCode()); |
| 1035 ASSERT(!func.HasOptimizedCode()); | 1045 ASSERT(!func.HasOptimizedCode()); |
| 1036 Code& code = Code::Handle(func.unoptimized_code()); | 1046 Code& code = Code::Handle(func.unoptimized_code()); |
| 1037 ASSERT(!code.IsNull()); | 1047 ASSERT(!code.IsNull()); |
| 1038 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); | 1048 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); |
| 1039 // We attempt to find the PC descriptor that is closest to the | |
| 1040 // beginning of the token range, in terms of native code address. If we | |
| 1041 // don't find a PC descriptor within the given range, we pick the | |
| 1042 // nearest one to the beginning of the range, in terms of token position. | |
| 1043 intptr_t best_fit_index = -1; | 1049 intptr_t best_fit_index = -1; |
| 1044 intptr_t best_fit = INT_MAX; | 1050 intptr_t best_fit = INT_MAX; |
| 1045 uword lowest_pc = kUwordMax; | 1051 uword lowest_pc = kUwordMax; |
| 1046 intptr_t lowest_pc_index = -1; | 1052 intptr_t lowest_pc_index = -1; |
| 1047 for (int i = 0; i < desc.Length(); i++) { | 1053 for (int i = 0; i < desc.Length(); i++) { |
| 1048 intptr_t desc_token_pos = desc.TokenPos(i); | 1054 intptr_t desc_token_pos = desc.TokenPos(i); |
| 1049 ASSERT(desc_token_pos >= 0); | 1055 ASSERT(desc_token_pos >= 0); |
| 1050 if (desc_token_pos < first_token_pos) { | 1056 if (desc_token_pos < first_token_pos) { |
| 1057 // This descriptor is before the given range. |
| 1051 continue; | 1058 continue; |
| 1052 } | 1059 } |
| 1053 PcDescriptors::Kind kind = desc.DescriptorKind(i); | 1060 if (IsSafePoint(desc.DescriptorKind(i))) { |
| 1054 if ((kind == PcDescriptors::kIcCall) || | |
| 1055 (kind == PcDescriptors::kFuncCall) || | |
| 1056 (kind == PcDescriptors::kClosureCall) || | |
| 1057 (kind == PcDescriptors::kReturn)) { | |
| 1058 if ((desc_token_pos - first_token_pos) < best_fit) { | 1061 if ((desc_token_pos - first_token_pos) < best_fit) { |
| 1062 // So far, this descriptor has the closest token position to the |
| 1063 // beginning of the range. |
| 1059 best_fit = desc_token_pos - first_token_pos; | 1064 best_fit = desc_token_pos - first_token_pos; |
| 1060 ASSERT(best_fit >= 0); | 1065 ASSERT(best_fit >= 0); |
| 1061 best_fit_index = i; | 1066 best_fit_index = i; |
| 1062 } | 1067 } |
| 1063 if ((first_token_pos <= desc_token_pos) && | 1068 if ((first_token_pos <= desc_token_pos) && |
| 1064 (desc_token_pos <= last_token_pos) && | 1069 (desc_token_pos <= last_token_pos) && |
| 1065 (desc.PC(i) < lowest_pc)) { | 1070 (desc.PC(i) < lowest_pc)) { |
| 1071 // This descriptor is within the token position range and so |
| 1072 // far has the lowest code address. |
| 1066 lowest_pc = desc.PC(i); | 1073 lowest_pc = desc.PC(i); |
| 1067 lowest_pc_index = i; | 1074 lowest_pc_index = i; |
| 1068 } | 1075 } |
| 1069 } | 1076 } |
| 1070 } | 1077 } |
| 1071 if (lowest_pc_index >= 0) { | 1078 if (lowest_pc_index >= 0) { |
| 1072 // We found the the pc descriptor within the given token range that | 1079 // We found the the pc descriptor within the given token range that |
| 1073 // has the lowest execution address. This is the first possible | 1080 // has the lowest execution address. This is the first possible |
| 1074 // breakpoint on the line. We use this instead of the nearest | 1081 // breakpoint on the line. We use this instead of the nearest |
| 1075 // PC descriptor measured in token index distance. | 1082 // PC descriptor measured in token index distance. |
| 1076 best_fit_index = lowest_pc_index; | 1083 best_fit_index = lowest_pc_index; |
| 1077 } | 1084 } |
| 1078 if (best_fit_index >= 0) { | 1085 if (best_fit_index >= 0) { |
| 1079 CodeBreakpoint* bpt = GetCodeBreakpoint(desc.PC(best_fit_index)); | 1086 return desc.TokenPos(best_fit_index); |
| 1080 // We should only ever have one code breakpoint at the same address. | |
| 1081 if (bpt != NULL) { | |
| 1082 return bpt; | |
| 1083 } | |
| 1084 | |
| 1085 bpt = new CodeBreakpoint(func, best_fit_index); | |
| 1086 if (FLAG_verbose_debug) { | |
| 1087 OS::Print("Setting breakpoint in function '%s' " | |
| 1088 "(%s:%"Pd") (Token %"Pd") (PC %#"Px")\n", | |
| 1089 String::Handle(func.name()).ToCString(), | |
| 1090 String::Handle(bpt->SourceUrl()).ToCString(), | |
| 1091 bpt->LineNumber(), | |
| 1092 bpt->token_pos(), | |
| 1093 bpt->pc()); | |
| 1094 } | |
| 1095 RegisterCodeBreakpoint(bpt); | |
| 1096 return bpt; | |
| 1097 } | 1087 } |
| 1098 return NULL; | 1088 return -1; |
| 1099 } | 1089 } |
| 1100 | 1090 |
| 1101 | 1091 |
| 1092 void Debugger::MakeCodeBreakpointsAt(const Function& func, |
| 1093 intptr_t token_pos, |
| 1094 SourceBreakpoint* bpt) { |
| 1095 ASSERT(!func.HasOptimizedCode()); |
| 1096 Code& code = Code::Handle(func.unoptimized_code()); |
| 1097 ASSERT(!code.IsNull()); |
| 1098 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); |
| 1099 for (int i = 0; i < desc.Length(); i++) { |
| 1100 intptr_t desc_token_pos = desc.TokenPos(i); |
| 1101 if ((desc_token_pos == token_pos) && IsSafePoint(desc.DescriptorKind(i))) { |
| 1102 CodeBreakpoint* code_bpt = GetCodeBreakpoint(desc.PC(i)); |
| 1103 if (code_bpt == NULL) { |
| 1104 // No code breakpoint for this code exists; create one. |
| 1105 code_bpt = new CodeBreakpoint(func, i); |
| 1106 RegisterCodeBreakpoint(code_bpt); |
| 1107 } |
| 1108 code_bpt->set_src_bpt(bpt); |
| 1109 } |
| 1110 } |
| 1111 } |
| 1112 |
| 1113 |
| 1102 SourceBreakpoint* Debugger::SetBreakpoint(const Function& target_function, | 1114 SourceBreakpoint* Debugger::SetBreakpoint(const Function& target_function, |
| 1103 intptr_t first_token_pos, | 1115 intptr_t first_token_pos, |
| 1104 intptr_t last_token_pos) { | 1116 intptr_t last_token_pos) { |
| 1105 if ((last_token_pos < target_function.token_pos()) || | 1117 if ((last_token_pos < target_function.token_pos()) || |
| 1106 (target_function.end_token_pos() < first_token_pos)) { | 1118 (target_function.end_token_pos() < first_token_pos)) { |
| 1107 // The given token position is not within the target function. | 1119 // The given token position is not within the target function. |
| 1108 return NULL; | 1120 return NULL; |
| 1109 } | 1121 } |
| 1110 DeoptimizeWorld(); | 1122 intptr_t breakpoint_pos = -1; |
| 1111 ASSERT(!target_function.HasOptimizedCode()); | 1123 Function& closure = Function::Handle(isolate_); |
| 1112 | 1124 if (target_function.HasImplicitClosureFunction()) { |
| 1113 CodeBreakpoint* cbpt = NULL; | 1125 // There is a closurized version of this function. |
| 1114 SourceBreakpoint* source_bpt = NULL; | 1126 closure = target_function.ImplicitClosureFunction(); |
| 1127 } |
| 1128 // Determine actual breakpoint location if the function or an |
| 1129 // implicit closure of the function has been compiled already. |
| 1115 if (target_function.HasCode()) { | 1130 if (target_function.HasCode()) { |
| 1116 cbpt = MakeCodeBreakpoint(target_function, first_token_pos, last_token_pos); | 1131 DeoptimizeWorld(); |
| 1117 if (cbpt != NULL) { | 1132 ASSERT(!target_function.HasOptimizedCode()); |
| 1118 if (cbpt->src_bpt() != NULL) { | 1133 breakpoint_pos = |
| 1119 // There is already a source breakpoint for the location. | 1134 ResolveBreakpointPos(target_function, first_token_pos, last_token_pos); |
| 1120 ASSERT(cbpt->src_bpt() == | 1135 } else if (!closure.IsNull() && closure.HasCode()) { |
| 1121 GetSourceBreakpoint(target_function, cbpt->token_pos())); | 1136 DeoptimizeWorld(); |
| 1122 return cbpt->src_bpt(); | 1137 ASSERT(!closure.HasOptimizedCode()); |
| 1138 breakpoint_pos = |
| 1139 ResolveBreakpointPos(closure, first_token_pos, last_token_pos); |
| 1140 } else { |
| 1141 // This function has not been compiled yet. Set a pending |
| 1142 // breakpoint to be resolved later. |
| 1143 SourceBreakpoint* source_bpt = |
| 1144 GetSourceBreakpoint(target_function, first_token_pos); |
| 1145 if (source_bpt != NULL) { |
| 1146 // A pending source breakpoint for this uncompiled location |
| 1147 // already exists. |
| 1148 if (FLAG_verbose_debug) { |
| 1149 OS::Print("Pending breakpoint for uncompiled function" |
| 1150 " '%s' at line %"Pd" already exists\n", |
| 1151 target_function.ToFullyQualifiedCString(), |
| 1152 source_bpt->LineNumber()); |
| 1123 } | 1153 } |
| 1124 // No source breakpoint exists yet that is associated with the code | |
| 1125 // breakpoint we found. (This is an internal breakpoint.) Adjust | |
| 1126 // the breakpoint location to the actual position where breakpoint | |
| 1127 // got set. | |
| 1128 first_token_pos = cbpt->token_pos(); | |
| 1129 } | |
| 1130 } else { | |
| 1131 source_bpt = GetSourceBreakpoint(target_function, first_token_pos); | |
| 1132 if (source_bpt != NULL) { | |
| 1133 // A source breakpoint for this uncompiled location already | |
| 1134 // exists. | |
| 1135 return source_bpt; | 1154 return source_bpt; |
| 1136 } | 1155 } |
| 1137 } | 1156 source_bpt = |
| 1138 source_bpt = new SourceBreakpoint(nextId(), target_function, first_token_pos); | 1157 new SourceBreakpoint(nextId(), target_function, first_token_pos); |
| 1139 RegisterSourceBreakpoint(source_bpt); | 1158 RegisterSourceBreakpoint(source_bpt); |
| 1140 if (FLAG_verbose_debug && !target_function.HasCode()) { | |
| 1141 OS::Print("Registering breakpoint for " | |
| 1142 "uncompiled function '%s' at line %"Pd"\n", | |
| 1143 target_function.ToFullyQualifiedCString(), | |
| 1144 source_bpt->LineNumber()); | |
| 1145 } | |
| 1146 | |
| 1147 if (cbpt != NULL) { | |
| 1148 ASSERT(cbpt->src_bpt() == NULL); | |
| 1149 cbpt->set_src_bpt(source_bpt); | |
| 1150 SignalBpResolved(source_bpt); | |
| 1151 } else { | |
| 1152 if (FLAG_verbose_debug) { | 1159 if (FLAG_verbose_debug) { |
| 1153 OS::Print("Failed to set breakpoint at '%s' line %"Pd"\n", | 1160 OS::Print("Registering pending breakpoint for " |
| 1154 String::Handle(source_bpt->SourceUrl()).ToCString(), | 1161 "uncompiled function '%s' at line %"Pd"\n", |
| 1162 target_function.ToFullyQualifiedCString(), |
| 1155 source_bpt->LineNumber()); | 1163 source_bpt->LineNumber()); |
| 1156 } | 1164 } |
| 1165 source_bpt->Enable(); |
| 1166 return source_bpt; |
| 1157 } | 1167 } |
| 1158 | 1168 ASSERT(breakpoint_pos != -1); |
| 1159 if (target_function.HasImplicitClosureFunction()) { | 1169 SourceBreakpoint* source_bpt = |
| 1160 // There is a closurized version of this function. If the closure | 1170 GetSourceBreakpoint(target_function, breakpoint_pos); |
| 1161 // is already compiled, we need to set a code breakpoint in its | 1171 if (source_bpt != NULL) { |
| 1162 // code. | 1172 // A source breakpoint for this location already exists. |
| 1163 const Function& closure = | 1173 return source_bpt; |
| 1164 Function::Handle(target_function.ImplicitClosureFunction()); | 1174 } |
| 1165 if (closure.HasCode()) { | 1175 source_bpt = new SourceBreakpoint(nextId(), target_function, breakpoint_pos); |
| 1166 ASSERT(!closure.HasOptimizedCode()); | 1176 RegisterSourceBreakpoint(source_bpt); |
| 1167 CodeBreakpoint* closure_bpt = | 1177 if (target_function.HasCode()) { |
| 1168 MakeCodeBreakpoint(closure, first_token_pos, last_token_pos); | 1178 MakeCodeBreakpointsAt(target_function, breakpoint_pos, source_bpt); |
| 1169 if ((closure_bpt != NULL) && (closure_bpt->src_bpt() == NULL)) { | 1179 } |
| 1170 closure_bpt->set_src_bpt(source_bpt); | 1180 if (!closure.IsNull() && closure.HasCode()) { |
| 1171 } | 1181 MakeCodeBreakpointsAt(closure, breakpoint_pos, source_bpt); |
| 1172 } | |
| 1173 } | 1182 } |
| 1174 source_bpt->Enable(); | 1183 source_bpt->Enable(); |
| 1175 return source_bpt; | 1184 return source_bpt; |
| 1176 } | 1185 } |
| 1177 | 1186 |
| 1178 | 1187 |
| 1179 // Synchronize the enabled/disabled state of all code breakpoints | 1188 // Synchronize the enabled/disabled state of all code breakpoints |
| 1180 // associated with the source breakpoint bpt. | 1189 // associated with the source breakpoint bpt. |
| 1181 void Debugger::SyncBreakpoint(SourceBreakpoint* bpt) { | 1190 void Debugger::SyncBreakpoint(SourceBreakpoint* bpt) { |
| 1182 CodeBreakpoint* cbpt = code_breakpoints_; | 1191 CodeBreakpoint* cbpt = code_breakpoints_; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1202 const Function& target_function) { | 1211 const Function& target_function) { |
| 1203 ASSERT(!target_function.IsNull()); | 1212 ASSERT(!target_function.IsNull()); |
| 1204 return SetBreakpoint(target_function, | 1213 return SetBreakpoint(target_function, |
| 1205 target_function.token_pos(), | 1214 target_function.token_pos(), |
| 1206 target_function.end_token_pos()); | 1215 target_function.end_token_pos()); |
| 1207 } | 1216 } |
| 1208 | 1217 |
| 1209 | 1218 |
| 1210 SourceBreakpoint* Debugger::SetBreakpointAtLine(const String& script_url, | 1219 SourceBreakpoint* Debugger::SetBreakpointAtLine(const String& script_url, |
| 1211 intptr_t line_number) { | 1220 intptr_t line_number) { |
| 1212 Library& lib = Library::Handle(); | 1221 Library& lib = Library::Handle(isolate_); |
| 1213 Script& script = Script::Handle(); | 1222 Script& script = Script::Handle(isolate_); |
| 1214 const GrowableObjectArray& libs = | 1223 const GrowableObjectArray& libs = |
| 1215 GrowableObjectArray::Handle(isolate_->object_store()->libraries()); | 1224 GrowableObjectArray::Handle(isolate_->object_store()->libraries()); |
| 1216 for (int i = 0; i < libs.Length(); i++) { | 1225 for (int i = 0; i < libs.Length(); i++) { |
| 1217 lib ^= libs.At(i); | 1226 lib ^= libs.At(i); |
| 1218 script = lib.LookupScript(script_url); | 1227 script = lib.LookupScript(script_url); |
| 1219 if (!script.IsNull()) { | 1228 if (!script.IsNull()) { |
| 1220 break; | 1229 break; |
| 1221 } | 1230 } |
| 1222 } | 1231 } |
| 1223 if (script.IsNull()) { | 1232 if (script.IsNull()) { |
| 1224 if (FLAG_verbose_debug) { | 1233 if (FLAG_verbose_debug) { |
| 1225 OS::Print("Failed to find script with url '%s'\n", | 1234 OS::Print("Failed to find script with url '%s'\n", |
| 1226 script_url.ToCString()); | 1235 script_url.ToCString()); |
| 1227 } | 1236 } |
| 1228 return NULL; | 1237 return NULL; |
| 1229 } | 1238 } |
| 1230 intptr_t first_token_idx, last_token_idx; | 1239 intptr_t first_token_idx, last_token_idx; |
| 1231 script.TokenRangeAtLine(line_number, &first_token_idx, &last_token_idx); | 1240 script.TokenRangeAtLine(line_number, &first_token_idx, &last_token_idx); |
| 1232 if (first_token_idx < 0) { | 1241 if (first_token_idx < 0) { |
| 1233 // Script does not contain the given line number. | 1242 // Script does not contain the given line number. |
| 1234 if (FLAG_verbose_debug) { | 1243 if (FLAG_verbose_debug) { |
| 1235 OS::Print("Script '%s' does not contain line number %"Pd"\n", | 1244 OS::Print("Script '%s' does not contain line number %"Pd"\n", |
| 1236 script_url.ToCString(), line_number); | 1245 script_url.ToCString(), line_number); |
| 1237 } | 1246 } |
| 1238 return NULL; | 1247 return NULL; |
| 1239 } | 1248 } |
| 1240 const Function& func = | 1249 |
| 1241 Function::Handle(lib.LookupFunctionInScript(script, first_token_idx)); | 1250 Function& func = Function::Handle(isolate_); |
| 1251 while (first_token_idx <= last_token_idx) { |
| 1252 func = lib.LookupFunctionInScript(script, first_token_idx); |
| 1253 if (!func.IsNull()) { |
| 1254 break; |
| 1255 } |
| 1256 first_token_idx++; |
| 1257 } |
| 1242 if (func.IsNull()) { | 1258 if (func.IsNull()) { |
| 1243 if (FLAG_verbose_debug) { | 1259 if (FLAG_verbose_debug) { |
| 1244 OS::Print("No executable code at line %"Pd" in '%s'\n", | 1260 OS::Print("No executable code at line %"Pd" in '%s'\n", |
| 1245 line_number, script_url.ToCString()); | 1261 line_number, script_url.ToCString()); |
| 1246 } | 1262 } |
| 1247 return NULL; | 1263 return NULL; |
| 1248 } | 1264 } |
| 1249 if (last_token_idx < 0) { | 1265 if (last_token_idx < 0) { |
| 1250 // The token at first_token_index is past the requested source line. | 1266 // The token at first_token_index is past the requested source line. |
| 1251 // Set the breakpoint at the closest position after that line. | 1267 // Set the breakpoint at the closest position after that line. |
| (...skipping 425 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1677 if (FLAG_verbose_debug) { | 1693 if (FLAG_verbose_debug) { |
| 1678 OS::Print("Resetting pending breakpoint to function %s\n", | 1694 OS::Print("Resetting pending breakpoint to function %s\n", |
| 1679 closure.ToFullyQualifiedCString()); | 1695 closure.ToFullyQualifiedCString()); |
| 1680 } | 1696 } |
| 1681 bpt->set_function(closure); | 1697 bpt->set_function(closure); |
| 1682 } else { | 1698 } else { |
| 1683 if (FLAG_verbose_debug) { | 1699 if (FLAG_verbose_debug) { |
| 1684 OS::Print("Enable pending breakpoint for function '%s'\n", | 1700 OS::Print("Enable pending breakpoint for function '%s'\n", |
| 1685 String::Handle(lookup_function.name()).ToCString()); | 1701 String::Handle(lookup_function.name()).ToCString()); |
| 1686 } | 1702 } |
| 1687 // Set breakpoint in newly compiled code of function func. | 1703 intptr_t bp_pos = |
| 1688 CodeBreakpoint* cbpt = | 1704 ResolveBreakpointPos(func, bpt->token_pos(), func.end_token_pos()); |
| 1689 MakeCodeBreakpoint(func, bpt->token_pos(), func.end_token_pos()); | 1705 bpt->set_token_pos(bp_pos); |
| 1690 if (cbpt != NULL) { | 1706 MakeCodeBreakpointsAt(func, bp_pos, bpt); |
| 1691 cbpt->set_src_bpt(bpt); | 1707 SignalBpResolved(bpt); |
| 1692 SignalBpResolved(bpt); | |
| 1693 } | |
| 1694 } | 1708 } |
| 1695 bpt->Enable(); // Enables the code breakpoint as well. | 1709 bpt->Enable(); // Enables the code breakpoint as well. |
| 1696 } | 1710 } |
| 1697 bpt = bpt->next(); | 1711 bpt = bpt->next(); |
| 1698 } | 1712 } |
| 1699 } | 1713 } |
| 1700 | 1714 |
| 1701 | 1715 |
| 1702 CodeBreakpoint* Debugger::GetCodeBreakpoint(uword breakpoint_address) { | 1716 CodeBreakpoint* Debugger::GetCodeBreakpoint(uword breakpoint_address) { |
| 1703 CodeBreakpoint* bpt = code_breakpoints_; | 1717 CodeBreakpoint* bpt = code_breakpoints_; |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1811 } | 1825 } |
| 1812 | 1826 |
| 1813 | 1827 |
| 1814 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 1828 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
| 1815 ASSERT(bpt->next() == NULL); | 1829 ASSERT(bpt->next() == NULL); |
| 1816 bpt->set_next(code_breakpoints_); | 1830 bpt->set_next(code_breakpoints_); |
| 1817 code_breakpoints_ = bpt; | 1831 code_breakpoints_ = bpt; |
| 1818 } | 1832 } |
| 1819 | 1833 |
| 1820 } // namespace dart | 1834 } // namespace dart |
| OLD | NEW |