| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 "platform/address_sanitizer.h" | 5 #include "platform/address_sanitizer.h" |
| 6 #include "platform/memory_sanitizer.h" | 6 #include "platform/memory_sanitizer.h" |
| 7 #include "platform/utils.h" | 7 #include "platform/utils.h" |
| 8 | 8 |
| 9 #include "vm/allocation.h" | 9 #include "vm/allocation.h" |
| 10 #include "vm/atomic.h" | 10 #include "vm/atomic.h" |
| (...skipping 1031 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1042 sample, | 1042 sample, |
| 1043 &native_stack_walker, | 1043 &native_stack_walker, |
| 1044 &dart_exit_stack_walker, | 1044 &dart_exit_stack_walker, |
| 1045 &dart_stack_walker, | 1045 &dart_stack_walker, |
| 1046 pc, | 1046 pc, |
| 1047 fp, | 1047 fp, |
| 1048 sp); | 1048 sp); |
| 1049 } | 1049 } |
| 1050 | 1050 |
| 1051 | 1051 |
| 1052 |
| 1053 CodeDescriptor::CodeDescriptor(const Code& code) : code_(code) { |
| 1054 ASSERT(!code_.IsNull()); |
| 1055 } |
| 1056 |
| 1057 |
| 1058 uword CodeDescriptor::Entry() const { |
| 1059 return code_.EntryPoint(); |
| 1060 } |
| 1061 |
| 1062 |
| 1063 uword CodeDescriptor::Size() const { |
| 1064 return code_.Size(); |
| 1065 } |
| 1066 |
| 1067 |
| 1068 int64_t CodeDescriptor::CompileTimestamp() const { |
| 1069 return code_.compile_timestamp(); |
| 1070 } |
| 1071 |
| 1072 |
| 1073 CodeLookupTable::CodeLookupTable(Thread* thread) { |
| 1074 Build(thread); |
| 1075 } |
| 1076 |
| 1077 |
| 1078 class CodeLookupTableBuilder : public ObjectVisitor { |
| 1079 public: |
| 1080 CodeLookupTableBuilder(Isolate* isolate, CodeLookupTable* table) |
| 1081 : ObjectVisitor(isolate), |
| 1082 table_(table) { |
| 1083 ASSERT(table_ != NULL); |
| 1084 } |
| 1085 |
| 1086 ~CodeLookupTableBuilder() { |
| 1087 } |
| 1088 |
| 1089 void VisitObject(RawObject* raw_obj) { |
| 1090 uword tags = raw_obj->ptr()->tags_; |
| 1091 if (RawObject::ClassIdTag::decode(tags) == kCodeCid) { |
| 1092 RawCode* raw_code = reinterpret_cast<RawCode*>(raw_obj); |
| 1093 const Code& code = Code::Handle(raw_code); |
| 1094 ASSERT(!code.IsNull()); |
| 1095 const Instructions& instructions = |
| 1096 Instructions::Handle(code.instructions()); |
| 1097 ASSERT(!instructions.IsNull()); |
| 1098 table_->Add(code); |
| 1099 } |
| 1100 } |
| 1101 |
| 1102 private: |
| 1103 CodeLookupTable* table_; |
| 1104 }; |
| 1105 |
| 1106 |
| 1107 void CodeLookupTable::Build(Thread* thread) { |
| 1108 ASSERT(thread != NULL); |
| 1109 Isolate* isolate = thread->isolate(); |
| 1110 ASSERT(isolate != NULL); |
| 1111 Isolate* vm_isolate = Dart::vm_isolate(); |
| 1112 ASSERT(vm_isolate != NULL); |
| 1113 |
| 1114 // Clear. |
| 1115 code_objects_.Clear(); |
| 1116 |
| 1117 // Add all found Code objects. |
| 1118 CodeLookupTableBuilder cltb(isolate, this); |
| 1119 vm_isolate->heap()->IterateOldObjects(&cltb); |
| 1120 isolate->heap()->IterateOldObjects(&cltb); |
| 1121 |
| 1122 // Sort by entry. |
| 1123 code_objects_.Sort(CodeDescriptor::Compare); |
| 1124 |
| 1125 #if defined(DEBUG) |
| 1126 if (length() <= 1) { |
| 1127 return; |
| 1128 } |
| 1129 ASSERT(FindCode(0) == NULL); |
| 1130 ASSERT(FindCode(~0) == NULL); |
| 1131 // Sanity check that we don't have duplicate entries and that the entries |
| 1132 // are sorted. |
| 1133 for (intptr_t i = 0; i < length() - 1; i++) { |
| 1134 const CodeDescriptor* a = At(i); |
| 1135 const CodeDescriptor* b = At(i + 1); |
| 1136 ASSERT(a->Entry() < b->Entry()); |
| 1137 ASSERT(FindCode(a->Entry()) == a); |
| 1138 ASSERT(FindCode(b->Entry()) == b); |
| 1139 ASSERT(FindCode(a->Entry() + a->Size() - 1) == a); |
| 1140 ASSERT(FindCode(b->Entry() + b->Size() - 1) == b); |
| 1141 } |
| 1142 #endif |
| 1143 } |
| 1144 |
| 1145 |
| 1146 void CodeLookupTable::Add(const Code& code) { |
| 1147 ASSERT(!code.IsNull()); |
| 1148 CodeDescriptor* cd = new CodeDescriptor(code); |
| 1149 code_objects_.Add(cd); |
| 1150 } |
| 1151 |
| 1152 |
| 1153 const CodeDescriptor* CodeLookupTable::FindCode(uword pc) const { |
| 1154 intptr_t first = 0; |
| 1155 intptr_t count = length(); |
| 1156 while (count > 0) { |
| 1157 intptr_t current = first; |
| 1158 intptr_t step = count / 2; |
| 1159 current += step; |
| 1160 const CodeDescriptor* cd = At(current); |
| 1161 if (pc >= cd->Entry()) { |
| 1162 first = ++current; |
| 1163 count -= step + 1; |
| 1164 } else { |
| 1165 count = step; |
| 1166 } |
| 1167 } |
| 1168 // First points to the first code object whose entry is greater than PC. |
| 1169 // That means the code object we need to check is first - 1. |
| 1170 if (first == 0) { |
| 1171 return NULL; |
| 1172 } |
| 1173 first--; |
| 1174 ASSERT(first >= 0); |
| 1175 ASSERT(first < length()); |
| 1176 const CodeDescriptor* cd = At(first); |
| 1177 if (cd->Contains(pc)) { |
| 1178 return cd; |
| 1179 } |
| 1180 return NULL; |
| 1181 } |
| 1182 |
| 1183 |
| 1052 ProcessedSampleBuffer* SampleBuffer::BuildProcessedSampleBuffer( | 1184 ProcessedSampleBuffer* SampleBuffer::BuildProcessedSampleBuffer( |
| 1053 SampleFilter* filter) { | 1185 SampleFilter* filter) { |
| 1054 ASSERT(filter != NULL); | 1186 ASSERT(filter != NULL); |
| 1055 Thread* thread = Thread::Current(); | 1187 Thread* thread = Thread::Current(); |
| 1056 Zone* zone = thread->zone(); | 1188 Zone* zone = thread->zone(); |
| 1057 | 1189 |
| 1058 ProcessedSampleBuffer* buffer = new(zone) ProcessedSampleBuffer(); | 1190 ProcessedSampleBuffer* buffer = new(zone) ProcessedSampleBuffer(); |
| 1059 | 1191 |
| 1060 const intptr_t length = capacity(); | 1192 const intptr_t length = capacity(); |
| 1061 for (intptr_t i = 0; i < length; i++) { | 1193 for (intptr_t i = 0; i < length; i++) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1077 continue; | 1209 continue; |
| 1078 } | 1210 } |
| 1079 if (sample->At(0) == 0) { | 1211 if (sample->At(0) == 0) { |
| 1080 // No frames. | 1212 // No frames. |
| 1081 continue; | 1213 continue; |
| 1082 } | 1214 } |
| 1083 if (!filter->FilterSample(sample)) { | 1215 if (!filter->FilterSample(sample)) { |
| 1084 // Did not pass filter. | 1216 // Did not pass filter. |
| 1085 continue; | 1217 continue; |
| 1086 } | 1218 } |
| 1087 buffer->Add(BuildProcessedSample(sample)); | 1219 buffer->Add(BuildProcessedSample(sample, buffer->code_lookup_table())); |
| 1088 } | 1220 } |
| 1089 return buffer; | 1221 return buffer; |
| 1090 } | 1222 } |
| 1091 | 1223 |
| 1092 | 1224 |
| 1093 ProcessedSample* SampleBuffer::BuildProcessedSample(Sample* sample) { | 1225 ProcessedSample* SampleBuffer::BuildProcessedSample( |
| 1226 Sample* sample, |
| 1227 const CodeLookupTable& clt) { |
| 1094 Thread* thread = Thread::Current(); | 1228 Thread* thread = Thread::Current(); |
| 1095 Zone* zone = thread->zone(); | 1229 Zone* zone = thread->zone(); |
| 1096 | 1230 |
| 1097 ProcessedSample* processed_sample = new(zone) ProcessedSample(); | 1231 ProcessedSample* processed_sample = new(zone) ProcessedSample(); |
| 1098 | 1232 |
| 1099 // Copy state bits from sample. | 1233 // Copy state bits from sample. |
| 1100 processed_sample->set_timestamp(sample->timestamp()); | 1234 processed_sample->set_timestamp(sample->timestamp()); |
| 1101 processed_sample->set_vm_tag(sample->vm_tag()); | 1235 processed_sample->set_vm_tag(sample->vm_tag()); |
| 1102 processed_sample->set_user_tag(sample->user_tag()); | 1236 processed_sample->set_user_tag(sample->user_tag()); |
| 1103 if (sample->is_allocation_sample()) { | 1237 if (sample->is_allocation_sample()) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1114 break; | 1248 break; |
| 1115 } | 1249 } |
| 1116 processed_sample->Add(current->At(i)); | 1250 processed_sample->Add(current->At(i)); |
| 1117 } | 1251 } |
| 1118 | 1252 |
| 1119 truncated = truncated || current->truncated_trace(); | 1253 truncated = truncated || current->truncated_trace(); |
| 1120 current = Next(current); | 1254 current = Next(current); |
| 1121 } | 1255 } |
| 1122 | 1256 |
| 1123 if (!sample->exit_frame_sample()) { | 1257 if (!sample->exit_frame_sample()) { |
| 1124 Isolate* vm_isolate = Dart::vm_isolate(); | 1258 processed_sample->FixupCaller(clt, |
| 1125 processed_sample->FixupCaller(thread, | |
| 1126 vm_isolate, | |
| 1127 sample->pc_marker(), | 1259 sample->pc_marker(), |
| 1128 sample->GetStackBuffer()); | 1260 sample->GetStackBuffer()); |
| 1129 } | 1261 } |
| 1130 | 1262 |
| 1131 processed_sample->set_truncated(truncated); | 1263 processed_sample->set_truncated(truncated); |
| 1132 return processed_sample; | 1264 return processed_sample; |
| 1133 } | 1265 } |
| 1134 | 1266 |
| 1135 | 1267 |
| 1136 Sample* SampleBuffer::Next(Sample* sample) { | 1268 Sample* SampleBuffer::Next(Sample* sample) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1156 ProcessedSample::ProcessedSample() | 1288 ProcessedSample::ProcessedSample() |
| 1157 : pcs_(kSampleSize), | 1289 : pcs_(kSampleSize), |
| 1158 timestamp_(0), | 1290 timestamp_(0), |
| 1159 vm_tag_(0), | 1291 vm_tag_(0), |
| 1160 user_tag_(0), | 1292 user_tag_(0), |
| 1161 allocation_cid_(-1), | 1293 allocation_cid_(-1), |
| 1162 truncated_(false) { | 1294 truncated_(false) { |
| 1163 } | 1295 } |
| 1164 | 1296 |
| 1165 | 1297 |
| 1166 void ProcessedSample::FixupCaller(Thread* thread, | 1298 void ProcessedSample::FixupCaller(const CodeLookupTable& clt, |
| 1167 Isolate* vm_isolate, | |
| 1168 uword pc_marker, | 1299 uword pc_marker, |
| 1169 uword* stack_buffer) { | 1300 uword* stack_buffer) { |
| 1170 REUSABLE_CODE_HANDLESCOPE(thread); | 1301 const CodeDescriptor* cd = clt.FindCode(At(0)); |
| 1171 // Lookup code object for leaf frame. | 1302 if (cd == NULL) { |
| 1172 Code& code = reused_code_handle.Handle(); | 1303 // No Dart code. |
| 1173 code = FindCodeForPC(thread->isolate(), vm_isolate, At(0)); | |
| 1174 if (code.IsNull()) { | |
| 1175 return; | 1304 return; |
| 1176 } | 1305 } |
| 1177 if (code.compile_timestamp() > timestamp()) { | 1306 if (cd->CompileTimestamp() > timestamp()) { |
| 1178 // Code compiled after sample. Ignore. | 1307 // Code compiled after sample. Ignore. |
| 1179 return; | 1308 return; |
| 1180 } | 1309 } |
| 1181 CheckForMissingDartFrame( | 1310 CheckForMissingDartFrame(clt, cd, pc_marker, stack_buffer); |
| 1182 thread->isolate(), vm_isolate, code, pc_marker, stack_buffer); | |
| 1183 } | 1311 } |
| 1184 | 1312 |
| 1185 | 1313 |
| 1186 void ProcessedSample::CheckForMissingDartFrame(Isolate* isolate, | 1314 void ProcessedSample::CheckForMissingDartFrame(const CodeLookupTable& clt, |
| 1187 Isolate* vm_isolate, | 1315 const CodeDescriptor* cd, |
| 1188 const Code& code, | |
| 1189 uword pc_marker, | 1316 uword pc_marker, |
| 1190 uword* stack_buffer) { | 1317 uword* stack_buffer) { |
| 1318 ASSERT(cd != NULL); |
| 1319 const Code& code = Code::Handle(cd->code()); |
| 1320 ASSERT(!code.IsNull()); |
| 1191 // Some stubs (and intrinsics) do not push a frame onto the stack leaving | 1321 // Some stubs (and intrinsics) do not push a frame onto the stack leaving |
| 1192 // the frame pointer in the caller. | 1322 // the frame pointer in the caller. |
| 1193 // | 1323 // |
| 1194 // PC -> STUB | 1324 // PC -> STUB |
| 1195 // FP -> DART3 <-+ | 1325 // FP -> DART3 <-+ |
| 1196 // DART2 <-| <- TOP FRAME RETURN ADDRESS. | 1326 // DART2 <-| <- TOP FRAME RETURN ADDRESS. |
| 1197 // DART1 <-| | 1327 // DART1 <-| |
| 1198 // ..... | 1328 // ..... |
| 1199 // | 1329 // |
| 1200 // In this case, traversing the linked stack frames will not collect a PC | 1330 // In this case, traversing the linked stack frames will not collect a PC |
| 1201 // inside DART3. The stack will incorrectly be: STUB, DART2, DART1. | 1331 // inside DART3. The stack will incorrectly be: STUB, DART2, DART1. |
| 1202 // In Dart code, after pushing the FP onto the stack, an IP in the current | 1332 // In Dart code, after pushing the FP onto the stack, an IP in the current |
| 1203 // function is pushed onto the stack as well. This stack slot is called | 1333 // function is pushed onto the stack as well. This stack slot is called |
| 1204 // the PC marker. We can use the PC marker to insert DART3 into the stack | 1334 // the PC marker. We can use the PC marker to insert DART3 into the stack |
| 1205 // so that it will correctly be: STUB, DART3, DART2, DART1. Note the | 1335 // so that it will correctly be: STUB, DART3, DART2, DART1. Note the |
| 1206 // inserted PC may not accurately reflect the true return address into DART3. | 1336 // inserted PC may not accurately reflect the true return address into DART3. |
| 1207 ASSERT(!code.IsNull()); | |
| 1208 | 1337 |
| 1209 // The pc marker is our current best guess of a return address. | 1338 // The pc marker is our current best guess of a return address. |
| 1210 uword return_address = pc_marker; | 1339 uword return_address = pc_marker; |
| 1211 | 1340 |
| 1212 // Attempt to find a better return address. | 1341 // Attempt to find a better return address. |
| 1213 ReturnAddressLocator ral(At(0), stack_buffer, code); | 1342 ReturnAddressLocator ral(At(0), stack_buffer, code); |
| 1214 | 1343 |
| 1215 if (!ral.LocateReturnAddress(&return_address)) { | 1344 if (!ral.LocateReturnAddress(&return_address)) { |
| 1216 ASSERT(return_address == pc_marker); | 1345 ASSERT(return_address == pc_marker); |
| 1217 if (code.GetPrologueOffset() == 0) { | 1346 if (code.GetPrologueOffset() == 0) { |
| 1218 // Code has the prologue at offset 0. The frame is already setup and | 1347 // Code has the prologue at offset 0. The frame is already setup and |
| 1219 // can be trusted. | 1348 // can be trusted. |
| 1220 return; | 1349 return; |
| 1221 } | 1350 } |
| 1222 // Could not find a better return address than the pc_marker. | 1351 // Could not find a better return address than the pc_marker. |
| 1223 if (code.ContainsInstructionAt(return_address)) { | 1352 if (code.ContainsInstructionAt(return_address)) { |
| 1224 // PC marker is in the same code as pc, no missing frame. | 1353 // PC marker is in the same code as pc, no missing frame. |
| 1225 return; | 1354 return; |
| 1226 } | 1355 } |
| 1227 } | 1356 } |
| 1228 | 1357 |
| 1229 if (!ContainedInDartCodeHeaps(isolate, vm_isolate, return_address)) { | 1358 if (clt.FindCode(return_address) == NULL) { |
| 1230 // return address is not from the Dart heap. Do not insert. | 1359 // Return address is not from a Dart code object. Do not insert. |
| 1231 return; | 1360 return; |
| 1232 } | 1361 } |
| 1233 | 1362 |
| 1234 if (return_address != 0) { | 1363 if (return_address != 0) { |
| 1235 InsertAt(1, return_address); | 1364 InsertAt(1, return_address); |
| 1236 } | 1365 } |
| 1237 } | 1366 } |
| 1238 | 1367 |
| 1239 | 1368 |
| 1240 RawCode* ProcessedSample::FindCodeForPC(Isolate* isolate, | 1369 ProcessedSampleBuffer::ProcessedSampleBuffer() |
| 1241 Isolate* vm_isolate, | 1370 : code_lookup_table_(new CodeLookupTable(Thread::Current())) { |
| 1242 uword pc) { | 1371 ASSERT(code_lookup_table_ != NULL); |
| 1243 // Check current isolate for pc. | |
| 1244 if (isolate->heap()->CodeContains(pc)) { | |
| 1245 return Code::LookupCode(pc); | |
| 1246 } | |
| 1247 | |
| 1248 // Check VM isolate for pc. | |
| 1249 if (vm_isolate->heap()->CodeContains(pc)) { | |
| 1250 return Code::LookupCodeInVmIsolate(pc); | |
| 1251 } | |
| 1252 | |
| 1253 return Code::null(); | |
| 1254 } | |
| 1255 | |
| 1256 | |
| 1257 bool ProcessedSample::ContainedInDartCodeHeaps(Isolate* isolate, | |
| 1258 Isolate* vm_isolate, | |
| 1259 uword pc) { | |
| 1260 return vm_isolate->heap()->CodeContains(pc) | |
| 1261 || isolate->heap()->CodeContains(pc); | |
| 1262 } | |
| 1263 | |
| 1264 | |
| 1265 ProcessedSampleBuffer::ProcessedSampleBuffer() { | |
| 1266 } | 1372 } |
| 1267 | 1373 |
| 1268 } // namespace dart | 1374 } // namespace dart |
| OLD | NEW |