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