| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 939 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 950 index_ = index; | 950 index_ = index; |
| 951 to_ = to; | 951 to_ = to; |
| 952 } | 952 } |
| 953 | 953 |
| 954 | 954 |
| 955 void HeapGraphEdge::Init(int child_index, int index, HeapEntry* to) { | 955 void HeapGraphEdge::Init(int child_index, int index, HeapEntry* to) { |
| 956 Init(child_index, kElement, index, to); | 956 Init(child_index, kElement, index, to); |
| 957 } | 957 } |
| 958 | 958 |
| 959 | 959 |
| 960 HeapEntry* HeapGraphEdge::From() { | |
| 961 return reinterpret_cast<HeapEntry*>(this - child_index_) - 1; | |
| 962 } | |
| 963 | |
| 964 | |
| 965 void HeapEntry::Init(HeapSnapshot* snapshot, | 960 void HeapEntry::Init(HeapSnapshot* snapshot, |
| 966 Type type, | 961 Type type, |
| 967 const char* name, | 962 const char* name, |
| 968 SnapshotObjectId id, | 963 SnapshotObjectId id, |
| 969 int self_size, | 964 int self_size, |
| 970 int children_count, | 965 int children_count, |
| 971 int retainers_count) { | 966 int retainers_count) { |
| 972 snapshot_ = snapshot; | 967 snapshot_ = snapshot; |
| 973 type_ = type; | 968 type_ = type; |
| 974 painted_ = false; | 969 painted_ = false; |
| 970 reachable_from_window_ = false; |
| 975 name_ = name; | 971 name_ = name; |
| 976 self_size_ = self_size; | 972 self_size_ = self_size; |
| 977 retained_size_ = 0; | 973 retained_size_ = 0; |
| 978 entry_index_ = -1; | 974 entry_index_ = -1; |
| 979 children_count_ = children_count; | 975 children_count_ = children_count; |
| 980 retainers_count_ = retainers_count; | 976 retainers_count_ = retainers_count; |
| 981 dominator_ = NULL; | 977 dominator_ = NULL; |
| 982 id_ = id; | 978 id_ = id; |
| 983 } | 979 } |
| 984 | 980 |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1127 const char* title, | 1123 const char* title, |
| 1128 unsigned uid) | 1124 unsigned uid) |
| 1129 : collection_(collection), | 1125 : collection_(collection), |
| 1130 type_(type), | 1126 type_(type), |
| 1131 title_(title), | 1127 title_(title), |
| 1132 uid_(uid), | 1128 uid_(uid), |
| 1133 root_entry_(NULL), | 1129 root_entry_(NULL), |
| 1134 gc_roots_entry_(NULL), | 1130 gc_roots_entry_(NULL), |
| 1135 natives_root_entry_(NULL), | 1131 natives_root_entry_(NULL), |
| 1136 raw_entries_(NULL), | 1132 raw_entries_(NULL), |
| 1133 number_of_edges_(0), |
| 1137 max_snapshot_js_object_id_(0) { | 1134 max_snapshot_js_object_id_(0) { |
| 1138 STATIC_CHECK( | 1135 STATIC_CHECK( |
| 1139 sizeof(HeapGraphEdge) == | 1136 sizeof(HeapGraphEdge) == |
| 1140 SnapshotSizeConstants<kPointerSize>::kExpectedHeapGraphEdgeSize); | 1137 SnapshotSizeConstants<kPointerSize>::kExpectedHeapGraphEdgeSize); |
| 1141 STATIC_CHECK( | 1138 STATIC_CHECK( |
| 1142 sizeof(HeapEntry) == | 1139 sizeof(HeapEntry) == |
| 1143 SnapshotSizeConstants<kPointerSize>::kExpectedHeapEntrySize); | 1140 SnapshotSizeConstants<kPointerSize>::kExpectedHeapEntrySize); |
| 1144 for (int i = 0; i < VisitorSynchronization::kNumberOfSyncTags; ++i) { | 1141 for (int i = 0; i < VisitorSynchronization::kNumberOfSyncTags; ++i) { |
| 1145 gc_subroot_entries_[i] = NULL; | 1142 gc_subroot_entries_[i] = NULL; |
| 1146 } | 1143 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1160 | 1157 |
| 1161 void HeapSnapshot::RememberLastJSObjectId() { | 1158 void HeapSnapshot::RememberLastJSObjectId() { |
| 1162 max_snapshot_js_object_id_ = collection_->last_assigned_id(); | 1159 max_snapshot_js_object_id_ = collection_->last_assigned_id(); |
| 1163 } | 1160 } |
| 1164 | 1161 |
| 1165 | 1162 |
| 1166 void HeapSnapshot::AllocateEntries(int entries_count, | 1163 void HeapSnapshot::AllocateEntries(int entries_count, |
| 1167 int children_count, | 1164 int children_count, |
| 1168 int retainers_count) { | 1165 int retainers_count) { |
| 1169 ASSERT(raw_entries_ == NULL); | 1166 ASSERT(raw_entries_ == NULL); |
| 1167 number_of_edges_ = children_count; |
| 1170 raw_entries_size_ = | 1168 raw_entries_size_ = |
| 1171 HeapEntry::EntriesSize(entries_count, children_count, retainers_count); | 1169 HeapEntry::EntriesSize(entries_count, children_count, retainers_count); |
| 1172 raw_entries_ = NewArray<char>(raw_entries_size_); | 1170 raw_entries_ = NewArray<char>(raw_entries_size_); |
| 1173 } | 1171 } |
| 1174 | 1172 |
| 1175 | 1173 |
| 1176 static void HeapEntryClearPaint(HeapEntry** entry_ptr) { | 1174 static void HeapEntryClearPaint(HeapEntry** entry_ptr) { |
| 1177 (*entry_ptr)->clear_paint(); | 1175 (*entry_ptr)->clear_paint(); |
| 1178 } | 1176 } |
| 1179 | 1177 |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1305 const SnapshotObjectId HeapObjectsMap::kInternalRootObjectId = 1; | 1303 const SnapshotObjectId HeapObjectsMap::kInternalRootObjectId = 1; |
| 1306 const SnapshotObjectId HeapObjectsMap::kGcRootsObjectId = | 1304 const SnapshotObjectId HeapObjectsMap::kGcRootsObjectId = |
| 1307 HeapObjectsMap::kInternalRootObjectId + HeapObjectsMap::kObjectIdStep; | 1305 HeapObjectsMap::kInternalRootObjectId + HeapObjectsMap::kObjectIdStep; |
| 1308 const SnapshotObjectId HeapObjectsMap::kGcRootsFirstSubrootId = | 1306 const SnapshotObjectId HeapObjectsMap::kGcRootsFirstSubrootId = |
| 1309 HeapObjectsMap::kGcRootsObjectId + HeapObjectsMap::kObjectIdStep; | 1307 HeapObjectsMap::kGcRootsObjectId + HeapObjectsMap::kObjectIdStep; |
| 1310 const SnapshotObjectId HeapObjectsMap::kFirstAvailableObjectId = | 1308 const SnapshotObjectId HeapObjectsMap::kFirstAvailableObjectId = |
| 1311 HeapObjectsMap::kGcRootsFirstSubrootId + | 1309 HeapObjectsMap::kGcRootsFirstSubrootId + |
| 1312 VisitorSynchronization::kNumberOfSyncTags * HeapObjectsMap::kObjectIdStep; | 1310 VisitorSynchronization::kNumberOfSyncTags * HeapObjectsMap::kObjectIdStep; |
| 1313 | 1311 |
| 1314 HeapObjectsMap::HeapObjectsMap() | 1312 HeapObjectsMap::HeapObjectsMap() |
| 1315 : initial_fill_mode_(true), | 1313 : next_id_(kFirstAvailableObjectId), |
| 1316 next_id_(kFirstAvailableObjectId), | 1314 entries_map_(AddressesMatch) { |
| 1317 entries_map_(AddressesMatch), | |
| 1318 entries_(new List<EntryInfo>()) { | |
| 1319 // This dummy element solves a problem with entries_map_. | 1315 // This dummy element solves a problem with entries_map_. |
| 1320 // When we do lookup in HashMap we see no difference between two cases: | 1316 // When we do lookup in HashMap we see no difference between two cases: |
| 1321 // it has an entry with NULL as the value or it has created | 1317 // it has an entry with NULL as the value or it has created |
| 1322 // a new entry on the fly with NULL as the default value. | 1318 // a new entry on the fly with NULL as the default value. |
| 1323 // With such dummy element we have a guaranty that all entries_map_ entries | 1319 // With such dummy element we have a guaranty that all entries_map_ entries |
| 1324 // will have the value field grater than 0. | 1320 // will have the value field grater than 0. |
| 1325 // This fact is using in MoveObject method. | 1321 // This fact is using in MoveObject method. |
| 1326 entries_->Add(EntryInfo(0, NULL)); | 1322 entries_.Add(EntryInfo(0, NULL, 0)); |
| 1327 } | |
| 1328 | |
| 1329 | |
| 1330 HeapObjectsMap::~HeapObjectsMap() { | |
| 1331 delete entries_; | |
| 1332 } | 1323 } |
| 1333 | 1324 |
| 1334 | 1325 |
| 1335 void HeapObjectsMap::SnapshotGenerationFinished() { | 1326 void HeapObjectsMap::SnapshotGenerationFinished() { |
| 1336 initial_fill_mode_ = false; | |
| 1337 RemoveDeadEntries(); | 1327 RemoveDeadEntries(); |
| 1338 } | 1328 } |
| 1339 | 1329 |
| 1340 | 1330 |
| 1341 SnapshotObjectId HeapObjectsMap::FindObject(Address addr) { | |
| 1342 if (!initial_fill_mode_) { | |
| 1343 SnapshotObjectId existing = FindEntry(addr); | |
| 1344 if (existing != 0) return existing; | |
| 1345 } | |
| 1346 SnapshotObjectId id = next_id_; | |
| 1347 next_id_ += kObjectIdStep; | |
| 1348 AddEntry(addr, id); | |
| 1349 // Here and in other places the length of entries_ list has to be | |
| 1350 // the same or greater than the length of entries_map_. But entries_ list | |
| 1351 // has a dummy element at index 0. | |
| 1352 ASSERT(static_cast<uint32_t>(entries_->length()) > entries_map_.occupancy()); | |
| 1353 return id; | |
| 1354 } | |
| 1355 | |
| 1356 | |
| 1357 void HeapObjectsMap::MoveObject(Address from, Address to) { | 1331 void HeapObjectsMap::MoveObject(Address from, Address to) { |
| 1358 ASSERT(to != NULL); | 1332 ASSERT(to != NULL); |
| 1359 ASSERT(from != NULL); | 1333 ASSERT(from != NULL); |
| 1360 if (from == to) return; | 1334 if (from == to) return; |
| 1361 void* from_value = entries_map_.Remove(from, AddressHash(from)); | 1335 void* from_value = entries_map_.Remove(from, AddressHash(from)); |
| 1362 if (from_value == NULL) return; | 1336 if (from_value == NULL) return; |
| 1363 int from_entry_info_index = | 1337 int from_entry_info_index = |
| 1364 static_cast<int>(reinterpret_cast<intptr_t>(from_value)); | 1338 static_cast<int>(reinterpret_cast<intptr_t>(from_value)); |
| 1365 entries_->at(from_entry_info_index).addr = to; | 1339 entries_.at(from_entry_info_index).addr = to; |
| 1366 HashMap::Entry* to_entry = entries_map_.Lookup(to, AddressHash(to), true); | 1340 HashMap::Entry* to_entry = entries_map_.Lookup(to, AddressHash(to), true); |
| 1367 if (to_entry->value != NULL) { | 1341 if (to_entry->value != NULL) { |
| 1368 int to_entry_info_index = | 1342 int to_entry_info_index = |
| 1369 static_cast<int>(reinterpret_cast<intptr_t>(to_entry->value)); | 1343 static_cast<int>(reinterpret_cast<intptr_t>(to_entry->value)); |
| 1370 // Without this operation we will have two EntryInfo's with the same | 1344 // Without this operation we will have two EntryInfo's with the same |
| 1371 // value in addr field. It is bad because later at RemoveDeadEntries | 1345 // value in addr field. It is bad because later at RemoveDeadEntries |
| 1372 // one of this entry will be removed with the corresponding entries_map_ | 1346 // one of this entry will be removed with the corresponding entries_map_ |
| 1373 // entry. | 1347 // entry. |
| 1374 entries_->at(to_entry_info_index).addr = NULL; | 1348 entries_.at(to_entry_info_index).addr = NULL; |
| 1375 } | 1349 } |
| 1376 to_entry->value = reinterpret_cast<void*>(from_entry_info_index); | 1350 to_entry->value = reinterpret_cast<void*>(from_entry_info_index); |
| 1377 } | 1351 } |
| 1378 | 1352 |
| 1379 | 1353 |
| 1380 void HeapObjectsMap::AddEntry(Address addr, SnapshotObjectId id) { | 1354 SnapshotObjectId HeapObjectsMap::FindEntry(Address addr) { |
| 1381 HashMap::Entry* entry = entries_map_.Lookup(addr, AddressHash(addr), true); | 1355 HashMap::Entry* entry = entries_map_.Lookup(addr, AddressHash(addr), false); |
| 1382 ASSERT(entry->value == NULL); | 1356 if (entry == NULL) return 0; |
| 1383 ASSERT(entries_->length() > 0 && | 1357 int entry_index = static_cast<int>(reinterpret_cast<intptr_t>(entry->value)); |
| 1384 entries_->at(0).id == 0 && | 1358 EntryInfo& entry_info = entries_.at(entry_index); |
| 1385 entries_->at(0).addr == NULL); | 1359 ASSERT(static_cast<uint32_t>(entries_.length()) > entries_map_.occupancy()); |
| 1386 ASSERT(entries_->at(entries_->length() - 1).id < id); | 1360 return entry_info.id; |
| 1387 entry->value = reinterpret_cast<void*>(entries_->length()); | |
| 1388 entries_->Add(EntryInfo(id, addr)); | |
| 1389 ASSERT(static_cast<uint32_t>(entries_->length()) > entries_map_.occupancy()); | |
| 1390 } | 1361 } |
| 1391 | 1362 |
| 1392 | 1363 |
| 1393 SnapshotObjectId HeapObjectsMap::FindEntry(Address addr) { | 1364 SnapshotObjectId HeapObjectsMap::FindOrAddEntry(Address addr, |
| 1394 HashMap::Entry* entry = entries_map_.Lookup(addr, AddressHash(addr), false); | 1365 unsigned int size) { |
| 1395 if (entry != NULL) { | 1366 ASSERT(static_cast<uint32_t>(entries_.length()) > entries_map_.occupancy()); |
| 1396 int entry_index = | |
| 1397 static_cast<int>(reinterpret_cast<intptr_t>(entry->value)); | |
| 1398 EntryInfo& entry_info = entries_->at(entry_index); | |
| 1399 entry_info.accessed = true; | |
| 1400 ASSERT(static_cast<uint32_t>(entries_->length()) > | |
| 1401 entries_map_.occupancy()); | |
| 1402 return entry_info.id; | |
| 1403 } else { | |
| 1404 return 0; | |
| 1405 } | |
| 1406 } | |
| 1407 | |
| 1408 | |
| 1409 SnapshotObjectId HeapObjectsMap::FindOrAddEntry(Address addr) { | |
| 1410 ASSERT(static_cast<uint32_t>(entries_->length()) > entries_map_.occupancy()); | |
| 1411 HashMap::Entry* entry = entries_map_.Lookup(addr, AddressHash(addr), true); | 1367 HashMap::Entry* entry = entries_map_.Lookup(addr, AddressHash(addr), true); |
| 1412 if (entry->value != NULL) { | 1368 if (entry->value != NULL) { |
| 1413 int entry_index = | 1369 int entry_index = |
| 1414 static_cast<int>(reinterpret_cast<intptr_t>(entry->value)); | 1370 static_cast<int>(reinterpret_cast<intptr_t>(entry->value)); |
| 1415 EntryInfo& entry_info = entries_->at(entry_index); | 1371 EntryInfo& entry_info = entries_.at(entry_index); |
| 1416 entry_info.accessed = true; | 1372 entry_info.accessed = true; |
| 1373 entry_info.size = size; |
| 1417 return entry_info.id; | 1374 return entry_info.id; |
| 1418 } | 1375 } |
| 1419 entry->value = reinterpret_cast<void*>(entries_->length()); | 1376 entry->value = reinterpret_cast<void*>(entries_.length()); |
| 1420 SnapshotObjectId id = next_id_; | 1377 SnapshotObjectId id = next_id_; |
| 1421 next_id_ += kObjectIdStep; | 1378 next_id_ += kObjectIdStep; |
| 1422 entries_->Add(EntryInfo(id, addr)); | 1379 entries_.Add(EntryInfo(id, addr, size)); |
| 1423 ASSERT(static_cast<uint32_t>(entries_->length()) > entries_map_.occupancy()); | 1380 ASSERT(static_cast<uint32_t>(entries_.length()) > entries_map_.occupancy()); |
| 1424 return id; | 1381 return id; |
| 1425 } | 1382 } |
| 1426 | 1383 |
| 1427 | 1384 |
| 1428 void HeapObjectsMap::StopHeapObjectsTracking() { | 1385 void HeapObjectsMap::StopHeapObjectsTracking() { |
| 1429 time_intervals_.Clear(); | 1386 time_intervals_.Clear(); |
| 1430 } | 1387 } |
| 1431 | 1388 |
| 1432 void HeapObjectsMap::UpdateHeapObjectsMap() { | 1389 void HeapObjectsMap::UpdateHeapObjectsMap() { |
| 1433 HEAP->CollectAllGarbage(Heap::kMakeHeapIterableMask, | 1390 HEAP->CollectAllGarbage(Heap::kMakeHeapIterableMask, |
| 1434 "HeapSnapshotsCollection::UpdateHeapObjectsMap"); | 1391 "HeapSnapshotsCollection::UpdateHeapObjectsMap"); |
| 1435 HeapIterator iterator(HeapIterator::kFilterUnreachable); | 1392 HeapIterator iterator; |
| 1436 for (HeapObject* obj = iterator.next(); | 1393 for (HeapObject* obj = iterator.next(); |
| 1437 obj != NULL; | 1394 obj != NULL; |
| 1438 obj = iterator.next()) { | 1395 obj = iterator.next()) { |
| 1439 FindOrAddEntry(obj->address()); | 1396 FindOrAddEntry(obj->address(), obj->Size()); |
| 1440 } | 1397 } |
| 1441 initial_fill_mode_ = false; | |
| 1442 RemoveDeadEntries(); | 1398 RemoveDeadEntries(); |
| 1443 } | 1399 } |
| 1444 | 1400 |
| 1445 | 1401 |
| 1446 void HeapObjectsMap::PushHeapObjectsStats(OutputStream* stream) { | 1402 void HeapObjectsMap::PushHeapObjectsStats(OutputStream* stream) { |
| 1447 UpdateHeapObjectsMap(); | 1403 UpdateHeapObjectsMap(); |
| 1448 time_intervals_.Add(TimeInterval(next_id_)); | 1404 time_intervals_.Add(TimeInterval(next_id_)); |
| 1449 int prefered_chunk_size = stream->GetChunkSize(); | 1405 int prefered_chunk_size = stream->GetChunkSize(); |
| 1450 List<uint32_t> stats_buffer; | 1406 List<uint32_t> stats_buffer; |
| 1451 ASSERT(!entries_->is_empty()); | 1407 ASSERT(!entries_.is_empty()); |
| 1452 EntryInfo* entry_info = &entries_->first(); | 1408 EntryInfo* entry_info = &entries_.first(); |
| 1453 EntryInfo* end_entry_info = &entries_->last() + 1; | 1409 EntryInfo* end_entry_info = &entries_.last() + 1; |
| 1454 for (int time_interval_index = 0; | 1410 for (int time_interval_index = 0; |
| 1455 time_interval_index < time_intervals_.length(); | 1411 time_interval_index < time_intervals_.length(); |
| 1456 ++time_interval_index) { | 1412 ++time_interval_index) { |
| 1457 TimeInterval& time_interval = time_intervals_[time_interval_index]; | 1413 TimeInterval& time_interval = time_intervals_[time_interval_index]; |
| 1458 SnapshotObjectId time_interval_id = time_interval.id; | 1414 SnapshotObjectId time_interval_id = time_interval.id; |
| 1459 uint32_t entries_count = 0; | 1415 uint32_t entries_size = 0; |
| 1416 EntryInfo* start_entry_info = entry_info; |
| 1460 while (entry_info < end_entry_info && entry_info->id < time_interval_id) { | 1417 while (entry_info < end_entry_info && entry_info->id < time_interval_id) { |
| 1461 ++entries_count; | 1418 entries_size += entry_info->size; |
| 1462 ++entry_info; | 1419 ++entry_info; |
| 1463 } | 1420 } |
| 1464 if (time_interval.count != entries_count) { | 1421 uint32_t entries_count = |
| 1422 static_cast<uint32_t>(entry_info - start_entry_info); |
| 1423 if (time_interval.count != entries_count || |
| 1424 time_interval.size != entries_size) { |
| 1465 stats_buffer.Add(time_interval_index); | 1425 stats_buffer.Add(time_interval_index); |
| 1466 stats_buffer.Add(time_interval.count = entries_count); | 1426 stats_buffer.Add(time_interval.count = entries_count); |
| 1427 stats_buffer.Add(time_interval.size = entries_size); |
| 1467 if (stats_buffer.length() >= prefered_chunk_size) { | 1428 if (stats_buffer.length() >= prefered_chunk_size) { |
| 1468 OutputStream::WriteResult result = stream->WriteUint32Chunk( | 1429 OutputStream::WriteResult result = stream->WriteUint32Chunk( |
| 1469 &stats_buffer.first(), stats_buffer.length()); | 1430 &stats_buffer.first(), stats_buffer.length()); |
| 1470 if (result == OutputStream::kAbort) return; | 1431 if (result == OutputStream::kAbort) return; |
| 1471 stats_buffer.Clear(); | 1432 stats_buffer.Clear(); |
| 1472 } | 1433 } |
| 1473 } | 1434 } |
| 1474 } | 1435 } |
| 1475 ASSERT(entry_info == end_entry_info); | 1436 ASSERT(entry_info == end_entry_info); |
| 1476 if (!stats_buffer.is_empty()) { | 1437 if (!stats_buffer.is_empty()) { |
| 1477 OutputStream::WriteResult result = | 1438 OutputStream::WriteResult result = |
| 1478 stream->WriteUint32Chunk(&stats_buffer.first(), stats_buffer.length()); | 1439 stream->WriteUint32Chunk(&stats_buffer.first(), stats_buffer.length()); |
| 1479 if (result == OutputStream::kAbort) return; | 1440 if (result == OutputStream::kAbort) return; |
| 1480 } | 1441 } |
| 1481 stream->EndOfStream(); | 1442 stream->EndOfStream(); |
| 1482 } | 1443 } |
| 1483 | 1444 |
| 1484 | 1445 |
| 1485 void HeapObjectsMap::RemoveDeadEntries() { | 1446 void HeapObjectsMap::RemoveDeadEntries() { |
| 1486 ASSERT(entries_->length() > 0 && | 1447 ASSERT(entries_.length() > 0 && |
| 1487 entries_->at(0).id == 0 && | 1448 entries_.at(0).id == 0 && |
| 1488 entries_->at(0).addr == NULL); | 1449 entries_.at(0).addr == NULL); |
| 1489 int first_free_entry = 1; | 1450 int first_free_entry = 1; |
| 1490 for (int i = 1; i < entries_->length(); ++i) { | 1451 for (int i = 1; i < entries_.length(); ++i) { |
| 1491 EntryInfo& entry_info = entries_->at(i); | 1452 EntryInfo& entry_info = entries_.at(i); |
| 1492 if (entry_info.accessed) { | 1453 if (entry_info.accessed) { |
| 1493 if (first_free_entry != i) { | 1454 if (first_free_entry != i) { |
| 1494 entries_->at(first_free_entry) = entry_info; | 1455 entries_.at(first_free_entry) = entry_info; |
| 1495 } | 1456 } |
| 1496 entries_->at(first_free_entry).accessed = false; | 1457 entries_.at(first_free_entry).accessed = false; |
| 1497 HashMap::Entry* entry = entries_map_.Lookup( | 1458 HashMap::Entry* entry = entries_map_.Lookup( |
| 1498 entry_info.addr, AddressHash(entry_info.addr), false); | 1459 entry_info.addr, AddressHash(entry_info.addr), false); |
| 1499 ASSERT(entry); | 1460 ASSERT(entry); |
| 1500 entry->value = reinterpret_cast<void*>(first_free_entry); | 1461 entry->value = reinterpret_cast<void*>(first_free_entry); |
| 1501 ++first_free_entry; | 1462 ++first_free_entry; |
| 1502 } else { | 1463 } else { |
| 1503 if (entry_info.addr) { | 1464 if (entry_info.addr) { |
| 1504 entries_map_.Remove(entry_info.addr, AddressHash(entry_info.addr)); | 1465 entries_map_.Remove(entry_info.addr, AddressHash(entry_info.addr)); |
| 1505 } | 1466 } |
| 1506 } | 1467 } |
| 1507 } | 1468 } |
| 1508 entries_->Rewind(first_free_entry); | 1469 entries_.Rewind(first_free_entry); |
| 1509 ASSERT(static_cast<uint32_t>(entries_->length()) - 1 == | 1470 ASSERT(static_cast<uint32_t>(entries_.length()) - 1 == |
| 1510 entries_map_.occupancy()); | 1471 entries_map_.occupancy()); |
| 1511 } | 1472 } |
| 1512 | 1473 |
| 1513 | 1474 |
| 1514 SnapshotObjectId HeapObjectsMap::GenerateId(v8::RetainedObjectInfo* info) { | 1475 SnapshotObjectId HeapObjectsMap::GenerateId(v8::RetainedObjectInfo* info) { |
| 1515 SnapshotObjectId id = static_cast<SnapshotObjectId>(info->GetHash()); | 1476 SnapshotObjectId id = static_cast<SnapshotObjectId>(info->GetHash()); |
| 1516 const char* label = info->GetLabel(); | 1477 const char* label = info->GetLabel(); |
| 1517 id ^= HashSequentialString(label, | 1478 id ^= HashSequentialString(label, |
| 1518 static_cast<int>(strlen(label)), | 1479 static_cast<int>(strlen(label)), |
| 1519 HEAP->HashSeed()); | 1480 HEAP->HashSeed()); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1587 // First perform a full GC in order to avoid dead objects. | 1548 // First perform a full GC in order to avoid dead objects. |
| 1588 HEAP->CollectAllGarbage(Heap::kMakeHeapIterableMask, | 1549 HEAP->CollectAllGarbage(Heap::kMakeHeapIterableMask, |
| 1589 "HeapSnapshotsCollection::FindHeapObjectById"); | 1550 "HeapSnapshotsCollection::FindHeapObjectById"); |
| 1590 AssertNoAllocation no_allocation; | 1551 AssertNoAllocation no_allocation; |
| 1591 HeapObject* object = NULL; | 1552 HeapObject* object = NULL; |
| 1592 HeapIterator iterator(HeapIterator::kFilterUnreachable); | 1553 HeapIterator iterator(HeapIterator::kFilterUnreachable); |
| 1593 // Make sure that object with the given id is still reachable. | 1554 // Make sure that object with the given id is still reachable. |
| 1594 for (HeapObject* obj = iterator.next(); | 1555 for (HeapObject* obj = iterator.next(); |
| 1595 obj != NULL; | 1556 obj != NULL; |
| 1596 obj = iterator.next()) { | 1557 obj = iterator.next()) { |
| 1597 if (ids_.FindObject(obj->address()) == id) { | 1558 if (ids_.FindEntry(obj->address()) == id) { |
| 1598 ASSERT(object == NULL); | 1559 ASSERT(object == NULL); |
| 1599 object = obj; | 1560 object = obj; |
| 1600 // Can't break -- kFilterUnreachable requires full heap traversal. | 1561 // Can't break -- kFilterUnreachable requires full heap traversal. |
| 1601 } | 1562 } |
| 1602 } | 1563 } |
| 1603 return object != NULL ? Handle<HeapObject>(object) : Handle<HeapObject>(); | 1564 return object != NULL ? Handle<HeapObject>(object) : Handle<HeapObject>(); |
| 1604 } | 1565 } |
| 1605 | 1566 |
| 1606 | 1567 |
| 1607 HeapEntry* const HeapEntriesMap::kHeapEntryPlaceholder = | 1568 HeapEntry* const HeapEntriesMap::kHeapEntryPlaceholder = |
| (...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1888 children_count, | 1849 children_count, |
| 1889 retainers_count); | 1850 retainers_count); |
| 1890 } | 1851 } |
| 1891 | 1852 |
| 1892 | 1853 |
| 1893 HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, | 1854 HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, |
| 1894 HeapEntry::Type type, | 1855 HeapEntry::Type type, |
| 1895 const char* name, | 1856 const char* name, |
| 1896 int children_count, | 1857 int children_count, |
| 1897 int retainers_count) { | 1858 int retainers_count) { |
| 1859 int object_size = object->Size(); |
| 1860 SnapshotObjectId object_id = |
| 1861 collection_->GetObjectId(object->address(), object_size); |
| 1898 return snapshot_->AddEntry(type, | 1862 return snapshot_->AddEntry(type, |
| 1899 name, | 1863 name, |
| 1900 collection_->GetObjectId(object->address()), | 1864 object_id, |
| 1901 object->Size(), | 1865 object_size, |
| 1902 children_count, | 1866 children_count, |
| 1903 retainers_count); | 1867 retainers_count); |
| 1904 } | 1868 } |
| 1905 | 1869 |
| 1906 | 1870 |
| 1907 class GcSubrootsEnumerator : public ObjectVisitor { | 1871 class GcSubrootsEnumerator : public ObjectVisitor { |
| 1908 public: | 1872 public: |
| 1909 GcSubrootsEnumerator( | 1873 GcSubrootsEnumerator( |
| 1910 SnapshotFillerInterface* filler, V8HeapExplorer* explorer) | 1874 SnapshotFillerInterface* filler, V8HeapExplorer* explorer) |
| 1911 : filler_(filler), | 1875 : filler_(filler), |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2009 void V8HeapExplorer::ExtractReferences(HeapObject* obj) { | 1973 void V8HeapExplorer::ExtractReferences(HeapObject* obj) { |
| 2010 HeapEntry* entry = GetEntry(obj); | 1974 HeapEntry* entry = GetEntry(obj); |
| 2011 if (entry == NULL) return; // No interest in this object. | 1975 if (entry == NULL) return; // No interest in this object. |
| 2012 | 1976 |
| 2013 bool extract_indexed_refs = true; | 1977 bool extract_indexed_refs = true; |
| 2014 if (obj->IsJSGlobalProxy()) { | 1978 if (obj->IsJSGlobalProxy()) { |
| 2015 // We need to reference JS global objects from snapshot's root. | 1979 // We need to reference JS global objects from snapshot's root. |
| 2016 // We use JSGlobalProxy because this is what embedder (e.g. browser) | 1980 // We use JSGlobalProxy because this is what embedder (e.g. browser) |
| 2017 // uses for the global object. | 1981 // uses for the global object. |
| 2018 JSGlobalProxy* proxy = JSGlobalProxy::cast(obj); | 1982 JSGlobalProxy* proxy = JSGlobalProxy::cast(obj); |
| 2019 SetRootShortcutReference(proxy->map()->prototype()); | 1983 SetWindowReference(proxy->map()->prototype()); |
| 2020 } else if (obj->IsJSObject()) { | 1984 } else if (obj->IsJSObject()) { |
| 2021 JSObject* js_obj = JSObject::cast(obj); | 1985 JSObject* js_obj = JSObject::cast(obj); |
| 2022 ExtractClosureReferences(js_obj, entry); | 1986 ExtractClosureReferences(js_obj, entry); |
| 2023 ExtractPropertyReferences(js_obj, entry); | 1987 ExtractPropertyReferences(js_obj, entry); |
| 2024 ExtractElementReferences(js_obj, entry); | 1988 ExtractElementReferences(js_obj, entry); |
| 2025 ExtractInternalReferences(js_obj, entry); | 1989 ExtractInternalReferences(js_obj, entry); |
| 2026 SetPropertyReference( | 1990 SetPropertyReference( |
| 2027 obj, entry, heap_->Proto_symbol(), js_obj->GetPrototype()); | 1991 obj, entry, heap_->Proto_symbol(), js_obj->GetPrototype()); |
| 2028 if (obj->IsJSFunction()) { | 1992 if (obj->IsJSFunction()) { |
| 2029 JSFunction* js_fun = JSFunction::cast(js_obj); | 1993 JSFunction* js_fun = JSFunction::cast(js_obj); |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2180 obj->Iterate(&refs_extractor); | 2144 obj->Iterate(&refs_extractor); |
| 2181 } | 2145 } |
| 2182 } | 2146 } |
| 2183 | 2147 |
| 2184 | 2148 |
| 2185 void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj, | 2149 void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj, |
| 2186 HeapEntry* entry) { | 2150 HeapEntry* entry) { |
| 2187 if (!js_obj->IsJSFunction()) return; | 2151 if (!js_obj->IsJSFunction()) return; |
| 2188 | 2152 |
| 2189 JSFunction* func = JSFunction::cast(js_obj); | 2153 JSFunction* func = JSFunction::cast(js_obj); |
| 2190 Context* context = func->context(); | 2154 Context* context = func->context()->declaration_context(); |
| 2191 ScopeInfo* scope_info = context->closure()->shared()->scope_info(); | 2155 ScopeInfo* scope_info = context->closure()->shared()->scope_info(); |
| 2192 | 2156 |
| 2193 if (func->shared()->bound()) { | 2157 if (func->shared()->bound()) { |
| 2194 FixedArray* bindings = func->function_bindings(); | 2158 FixedArray* bindings = func->function_bindings(); |
| 2195 SetNativeBindReference(js_obj, entry, "bound_this", | 2159 SetNativeBindReference(js_obj, entry, "bound_this", |
| 2196 bindings->get(JSFunction::kBoundThisIndex)); | 2160 bindings->get(JSFunction::kBoundThisIndex)); |
| 2197 SetNativeBindReference(js_obj, entry, "bound_function", | 2161 SetNativeBindReference(js_obj, entry, "bound_function", |
| 2198 bindings->get(JSFunction::kBoundFunctionIndex)); | 2162 bindings->get(JSFunction::kBoundFunctionIndex)); |
| 2199 for (int i = JSFunction::kBoundArgumentsStartIndex; | 2163 for (int i = JSFunction::kBoundArgumentsStartIndex; |
| 2200 i < bindings->length(); i++) { | 2164 i < bindings->length(); i++) { |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2277 break; | 2241 break; |
| 2278 } | 2242 } |
| 2279 } | 2243 } |
| 2280 } else { | 2244 } else { |
| 2281 StringDictionary* dictionary = js_obj->property_dictionary(); | 2245 StringDictionary* dictionary = js_obj->property_dictionary(); |
| 2282 int length = dictionary->Capacity(); | 2246 int length = dictionary->Capacity(); |
| 2283 for (int i = 0; i < length; ++i) { | 2247 for (int i = 0; i < length; ++i) { |
| 2284 Object* k = dictionary->KeyAt(i); | 2248 Object* k = dictionary->KeyAt(i); |
| 2285 if (dictionary->IsKey(k)) { | 2249 if (dictionary->IsKey(k)) { |
| 2286 Object* target = dictionary->ValueAt(i); | 2250 Object* target = dictionary->ValueAt(i); |
| 2287 SetPropertyReference( | |
| 2288 js_obj, entry, String::cast(k), target); | |
| 2289 // We assume that global objects can only have slow properties. | 2251 // We assume that global objects can only have slow properties. |
| 2290 if (target->IsJSGlobalPropertyCell()) { | 2252 Object* value = target->IsJSGlobalPropertyCell() |
| 2291 SetPropertyShortcutReference(js_obj, | 2253 ? JSGlobalPropertyCell::cast(target)->value() |
| 2292 entry, | 2254 : target; |
| 2293 String::cast(k), | 2255 if (String::cast(k)->length() > 0) { |
| 2294 JSGlobalPropertyCell::cast( | 2256 SetPropertyReference(js_obj, entry, String::cast(k), value); |
| 2295 target)->value()); | 2257 } else { |
| 2258 TagObject(value, "(hidden properties)"); |
| 2259 SetInternalReference(js_obj, entry, "hidden_properties", value); |
| 2296 } | 2260 } |
| 2297 } | 2261 } |
| 2298 } | 2262 } |
| 2299 } | 2263 } |
| 2300 } | 2264 } |
| 2301 | 2265 |
| 2302 | 2266 |
| 2303 void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, | 2267 void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, |
| 2304 HeapEntry* entry) { | 2268 HeapEntry* entry) { |
| 2305 if (js_obj->HasFastElements()) { | 2269 if (js_obj->HasFastElements()) { |
| (...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2654 | 2618 |
| 2655 | 2619 |
| 2656 void V8HeapExplorer::SetRootGcRootsReference() { | 2620 void V8HeapExplorer::SetRootGcRootsReference() { |
| 2657 filler_->SetIndexedAutoIndexReference( | 2621 filler_->SetIndexedAutoIndexReference( |
| 2658 HeapGraphEdge::kElement, | 2622 HeapGraphEdge::kElement, |
| 2659 kInternalRootObject, snapshot_->root(), | 2623 kInternalRootObject, snapshot_->root(), |
| 2660 kGcRootsObject, snapshot_->gc_roots()); | 2624 kGcRootsObject, snapshot_->gc_roots()); |
| 2661 } | 2625 } |
| 2662 | 2626 |
| 2663 | 2627 |
| 2664 void V8HeapExplorer::SetRootShortcutReference(Object* child_obj) { | 2628 void V8HeapExplorer::SetWindowReference(Object* child_obj) { |
| 2665 HeapEntry* child_entry = GetEntry(child_obj); | 2629 HeapEntry* child_entry = GetEntry(child_obj); |
| 2666 ASSERT(child_entry != NULL); | 2630 ASSERT(child_entry != NULL); |
| 2667 filler_->SetNamedAutoIndexReference( | 2631 filler_->SetNamedAutoIndexReference( |
| 2668 HeapGraphEdge::kShortcut, | 2632 HeapGraphEdge::kShortcut, |
| 2669 kInternalRootObject, snapshot_->root(), | 2633 kInternalRootObject, snapshot_->root(), |
| 2670 child_obj, child_entry); | 2634 child_obj, child_entry); |
| 2671 } | 2635 } |
| 2672 | 2636 |
| 2673 | 2637 |
| 2674 void V8HeapExplorer::SetGcRootsReference(VisitorSynchronization::SyncTag tag) { | 2638 void V8HeapExplorer::SetGcRootsReference(VisitorSynchronization::SyncTag tag) { |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2736 isolate->factory()->NewStringFromAscii(CStrVector("document")); | 2700 isolate->factory()->NewStringFromAscii(CStrVector("document")); |
| 2737 Handle<String> url_string = | 2701 Handle<String> url_string = |
| 2738 isolate->factory()->NewStringFromAscii(CStrVector("URL")); | 2702 isolate->factory()->NewStringFromAscii(CStrVector("URL")); |
| 2739 const char** urls = NewArray<const char*>(enumerator.count()); | 2703 const char** urls = NewArray<const char*>(enumerator.count()); |
| 2740 for (int i = 0, l = enumerator.count(); i < l; ++i) { | 2704 for (int i = 0, l = enumerator.count(); i < l; ++i) { |
| 2741 urls[i] = NULL; | 2705 urls[i] = NULL; |
| 2742 HandleScope scope; | 2706 HandleScope scope; |
| 2743 Handle<JSGlobalObject> global_obj = enumerator.at(i); | 2707 Handle<JSGlobalObject> global_obj = enumerator.at(i); |
| 2744 Object* obj_document; | 2708 Object* obj_document; |
| 2745 if (global_obj->GetProperty(*document_string)->ToObject(&obj_document) && | 2709 if (global_obj->GetProperty(*document_string)->ToObject(&obj_document) && |
| 2746 obj_document->IsJSObject()) { | 2710 obj_document->IsJSObject()) { |
| 2747 JSObject* document = JSObject::cast(obj_document); | 2711 JSObject* document = JSObject::cast(obj_document); |
| 2748 Object* obj_url; | 2712 Object* obj_url; |
| 2749 if (document->GetProperty(*url_string)->ToObject(&obj_url) && | 2713 if (document->GetProperty(*url_string)->ToObject(&obj_url) && |
| 2750 obj_url->IsString()) { | 2714 obj_url->IsString()) { |
| 2751 urls[i] = collection_->names()->GetName(String::cast(obj_url)); | 2715 urls[i] = collection_->names()->GetName(String::cast(obj_url)); |
| 2752 } | 2716 } |
| 2753 } | 2717 } |
| 2754 } | 2718 } |
| 2755 | 2719 |
| 2756 AssertNoAllocation no_allocation; | 2720 AssertNoAllocation no_allocation; |
| (...skipping 533 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3290 // in turn may relocate objects in property maps thus changing the heap | 3254 // in turn may relocate objects in property maps thus changing the heap |
| 3291 // layout and affecting retainer counts. This is not acceptable because | 3255 // layout and affecting retainer counts. This is not acceptable because |
| 3292 // number of retainers must not change between count and fill passes. | 3256 // number of retainers must not change between count and fill passes. |
| 3293 // To avoid this there's a separate postpass that set object names. | 3257 // To avoid this there's a separate postpass that set object names. |
| 3294 return v8_heap_explorer_.IterateAndExtractReferences(&filler) | 3258 return v8_heap_explorer_.IterateAndExtractReferences(&filler) |
| 3295 && dom_explorer_.IterateAndExtractReferences(&filler) | 3259 && dom_explorer_.IterateAndExtractReferences(&filler) |
| 3296 && v8_heap_explorer_.IterateAndSetObjectNames(&filler); | 3260 && v8_heap_explorer_.IterateAndSetObjectNames(&filler); |
| 3297 } | 3261 } |
| 3298 | 3262 |
| 3299 | 3263 |
| 3300 void HeapSnapshotGenerator::FillReversePostorderIndexes( | 3264 bool HeapSnapshotGenerator::IsWindowReference(const HeapGraphEdge& edge) { |
| 3265 ASSERT(edge.from() == snapshot_->root()); |
| 3266 return edge.type() == HeapGraphEdge::kShortcut; |
| 3267 } |
| 3268 |
| 3269 |
| 3270 void HeapSnapshotGenerator::MarkWindowReachableObjects() { |
| 3271 List<HeapEntry*> worklist; |
| 3272 |
| 3273 Vector<HeapGraphEdge> children = snapshot_->root()->children(); |
| 3274 for (int i = 0; i < children.length(); ++i) { |
| 3275 if (IsWindowReference(children[i])) { |
| 3276 worklist.Add(children[i].to()); |
| 3277 } |
| 3278 } |
| 3279 |
| 3280 while (!worklist.is_empty()) { |
| 3281 HeapEntry* entry = worklist.RemoveLast(); |
| 3282 if (entry->reachable_from_window()) continue; |
| 3283 entry->set_reachable_from_window(); |
| 3284 Vector<HeapGraphEdge> children = entry->children(); |
| 3285 for (int i = 0; i < children.length(); ++i) { |
| 3286 HeapEntry* child = children[i].to(); |
| 3287 if (!child->reachable_from_window()) { |
| 3288 worklist.Add(child); |
| 3289 } |
| 3290 } |
| 3291 } |
| 3292 } |
| 3293 |
| 3294 |
| 3295 static bool IsRetainingEdge(HeapGraphEdge* edge) { |
| 3296 if (edge->type() == HeapGraphEdge::kShortcut) return false; |
| 3297 // The edge is not retaining if it goes from system domain |
| 3298 // (i.e. an object not reachable from window) to the user domain |
| 3299 // (i.e. a reachable object). |
| 3300 return edge->from()->reachable_from_window() |
| 3301 || !edge->to()->reachable_from_window(); |
| 3302 } |
| 3303 |
| 3304 |
| 3305 void HeapSnapshotGenerator::FillPostorderIndexes( |
| 3301 Vector<HeapEntry*>* entries) { | 3306 Vector<HeapEntry*>* entries) { |
| 3302 snapshot_->ClearPaint(); | 3307 snapshot_->ClearPaint(); |
| 3303 int current_entry = 0; | 3308 int current_entry = 0; |
| 3304 List<HeapEntry*> nodes_to_visit; | 3309 List<HeapEntry*> nodes_to_visit; |
| 3305 nodes_to_visit.Add(snapshot_->root()); | 3310 HeapEntry* root = snapshot_->root(); |
| 3311 nodes_to_visit.Add(root); |
| 3306 snapshot_->root()->paint(); | 3312 snapshot_->root()->paint(); |
| 3307 while (!nodes_to_visit.is_empty()) { | 3313 while (!nodes_to_visit.is_empty()) { |
| 3308 HeapEntry* entry = nodes_to_visit.last(); | 3314 HeapEntry* entry = nodes_to_visit.last(); |
| 3309 Vector<HeapGraphEdge> children = entry->children(); | 3315 Vector<HeapGraphEdge> children = entry->children(); |
| 3310 bool has_new_edges = false; | 3316 bool has_new_edges = false; |
| 3311 for (int i = 0; i < children.length(); ++i) { | 3317 for (int i = 0; i < children.length(); ++i) { |
| 3312 if (children[i].type() == HeapGraphEdge::kShortcut) continue; | 3318 if (entry != root && !IsRetainingEdge(&children[i])) continue; |
| 3313 HeapEntry* child = children[i].to(); | 3319 HeapEntry* child = children[i].to(); |
| 3314 if (!child->painted()) { | 3320 if (!child->painted()) { |
| 3315 nodes_to_visit.Add(child); | 3321 nodes_to_visit.Add(child); |
| 3316 child->paint(); | 3322 child->paint(); |
| 3317 has_new_edges = true; | 3323 has_new_edges = true; |
| 3318 } | 3324 } |
| 3319 } | 3325 } |
| 3320 if (!has_new_edges) { | 3326 if (!has_new_edges) { |
| 3321 entry->set_ordered_index(current_entry); | 3327 entry->set_ordered_index(current_entry); |
| 3322 (*entries)[current_entry++] = entry; | 3328 (*entries)[current_entry++] = entry; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 3337 } | 3343 } |
| 3338 | 3344 |
| 3339 | 3345 |
| 3340 // The algorithm is based on the article: | 3346 // The algorithm is based on the article: |
| 3341 // K. Cooper, T. Harvey and K. Kennedy "A Simple, Fast Dominance Algorithm" | 3347 // K. Cooper, T. Harvey and K. Kennedy "A Simple, Fast Dominance Algorithm" |
| 3342 // Softw. Pract. Exper. 4 (2001), pp. 1-10. | 3348 // Softw. Pract. Exper. 4 (2001), pp. 1-10. |
| 3343 bool HeapSnapshotGenerator::BuildDominatorTree( | 3349 bool HeapSnapshotGenerator::BuildDominatorTree( |
| 3344 const Vector<HeapEntry*>& entries, | 3350 const Vector<HeapEntry*>& entries, |
| 3345 Vector<int>* dominators) { | 3351 Vector<int>* dominators) { |
| 3346 if (entries.length() == 0) return true; | 3352 if (entries.length() == 0) return true; |
| 3353 HeapEntry* root = snapshot_->root(); |
| 3347 const int entries_length = entries.length(), root_index = entries_length - 1; | 3354 const int entries_length = entries.length(), root_index = entries_length - 1; |
| 3348 static const int kNoDominator = -1; | 3355 static const int kNoDominator = -1; |
| 3349 for (int i = 0; i < root_index; ++i) (*dominators)[i] = kNoDominator; | 3356 for (int i = 0; i < root_index; ++i) (*dominators)[i] = kNoDominator; |
| 3350 (*dominators)[root_index] = root_index; | 3357 (*dominators)[root_index] = root_index; |
| 3351 | 3358 |
| 3352 // The affected array is used to mark entries which dominators | 3359 // The affected array is used to mark entries which dominators |
| 3353 // have to be racalculated because of changes in their retainers. | 3360 // have to be racalculated because of changes in their retainers. |
| 3354 ScopedVector<bool> affected(entries_length); | 3361 ScopedVector<bool> affected(entries_length); |
| 3355 for (int i = 0; i < affected.length(); ++i) affected[i] = false; | 3362 for (int i = 0; i < affected.length(); ++i) affected[i] = false; |
| 3356 // Mark the root direct children as affected. | 3363 // Mark the root direct children as affected. |
| 3357 Vector<HeapGraphEdge> children = entries[root_index]->children(); | 3364 Vector<HeapGraphEdge> children = entries[root_index]->children(); |
| 3358 for (int i = 0; i < children.length(); ++i) { | 3365 for (int i = 0; i < children.length(); ++i) { |
| 3359 affected[children[i].to()->ordered_index()] = true; | 3366 affected[children[i].to()->ordered_index()] = true; |
| 3360 } | 3367 } |
| 3361 | 3368 |
| 3362 bool changed = true; | 3369 bool changed = true; |
| 3363 while (changed) { | 3370 while (changed) { |
| 3364 changed = false; | 3371 changed = false; |
| 3365 if (!ProgressReport(true)) return false; | 3372 if (!ProgressReport(true)) return false; |
| 3366 for (int i = root_index - 1; i >= 0; --i) { | 3373 for (int i = root_index - 1; i >= 0; --i) { |
| 3367 if (!affected[i]) continue; | 3374 if (!affected[i]) continue; |
| 3368 affected[i] = false; | 3375 affected[i] = false; |
| 3369 // If dominator of the entry has already been set to root, | 3376 // If dominator of the entry has already been set to root, |
| 3370 // then it can't propagate any further. | 3377 // then it can't propagate any further. |
| 3371 if ((*dominators)[i] == root_index) continue; | 3378 if ((*dominators)[i] == root_index) continue; |
| 3372 int new_idom_index = kNoDominator; | 3379 int new_idom_index = kNoDominator; |
| 3373 Vector<HeapGraphEdge*> rets = entries[i]->retainers(); | 3380 Vector<HeapGraphEdge*> rets = entries[i]->retainers(); |
| 3374 for (int j = 0; j < rets.length(); ++j) { | 3381 for (int j = 0; j < rets.length(); ++j) { |
| 3375 if (rets[j]->type() == HeapGraphEdge::kShortcut) continue; | 3382 if (rets[j]->from() != root && !IsRetainingEdge(rets[j])) continue; |
| 3376 int ret_index = rets[j]->From()->ordered_index(); | 3383 int ret_index = rets[j]->from()->ordered_index(); |
| 3377 if (dominators->at(ret_index) != kNoDominator) { | 3384 if (dominators->at(ret_index) != kNoDominator) { |
| 3378 new_idom_index = new_idom_index == kNoDominator | 3385 new_idom_index = new_idom_index == kNoDominator |
| 3379 ? ret_index | 3386 ? ret_index |
| 3380 : Intersect(ret_index, new_idom_index, *dominators); | 3387 : Intersect(ret_index, new_idom_index, *dominators); |
| 3381 // If idom has already reached the root, it doesn't make sense | 3388 // If idom has already reached the root, it doesn't make sense |
| 3382 // to check other retainers. | 3389 // to check other retainers. |
| 3383 if (new_idom_index == root_index) break; | 3390 if (new_idom_index == root_index) break; |
| 3384 } | 3391 } |
| 3385 } | 3392 } |
| 3386 if (new_idom_index != kNoDominator | 3393 if (new_idom_index != kNoDominator |
| 3387 && dominators->at(i) != new_idom_index) { | 3394 && dominators->at(i) != new_idom_index) { |
| 3388 (*dominators)[i] = new_idom_index; | 3395 (*dominators)[i] = new_idom_index; |
| 3389 changed = true; | 3396 changed = true; |
| 3390 Vector<HeapGraphEdge> children = entries[i]->children(); | 3397 Vector<HeapGraphEdge> children = entries[i]->children(); |
| 3391 for (int j = 0; j < children.length(); ++j) { | 3398 for (int j = 0; j < children.length(); ++j) { |
| 3392 affected[children[j].to()->ordered_index()] = true; | 3399 affected[children[j].to()->ordered_index()] = true; |
| 3393 } | 3400 } |
| 3394 } | 3401 } |
| 3395 } | 3402 } |
| 3396 } | 3403 } |
| 3397 return true; | 3404 return true; |
| 3398 } | 3405 } |
| 3399 | 3406 |
| 3400 | 3407 |
| 3401 bool HeapSnapshotGenerator::SetEntriesDominators() { | 3408 bool HeapSnapshotGenerator::SetEntriesDominators() { |
| 3402 // This array is used for maintaining reverse postorder of nodes. | 3409 MarkWindowReachableObjects(); |
| 3410 // This array is used for maintaining postorder of nodes. |
| 3403 ScopedVector<HeapEntry*> ordered_entries(snapshot_->entries()->length()); | 3411 ScopedVector<HeapEntry*> ordered_entries(snapshot_->entries()->length()); |
| 3404 FillReversePostorderIndexes(&ordered_entries); | 3412 FillPostorderIndexes(&ordered_entries); |
| 3405 ScopedVector<int> dominators(ordered_entries.length()); | 3413 ScopedVector<int> dominators(ordered_entries.length()); |
| 3406 if (!BuildDominatorTree(ordered_entries, &dominators)) return false; | 3414 if (!BuildDominatorTree(ordered_entries, &dominators)) return false; |
| 3407 for (int i = 0; i < ordered_entries.length(); ++i) { | 3415 for (int i = 0; i < ordered_entries.length(); ++i) { |
| 3408 ASSERT(dominators[i] >= 0); | 3416 ASSERT(dominators[i] >= 0); |
| 3409 ordered_entries[i]->set_dominator(ordered_entries[dominators[i]]); | 3417 ordered_entries[i]->set_dominator(ordered_entries[dominators[i]]); |
| 3410 } | 3418 } |
| 3411 return true; | 3419 return true; |
| 3412 } | 3420 } |
| 3413 | 3421 |
| 3414 | 3422 |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3569 SnapshotSizeConstants<kPointerSize>::kMaxSerializableSnapshotRawSize / MB, | 3577 SnapshotSizeConstants<kPointerSize>::kMaxSerializableSnapshotRawSize / MB, |
| 3570 (snapshot_->raw_entries_size() + MB - 1) / MB); | 3578 (snapshot_->raw_entries_size() + MB - 1) / MB); |
| 3571 HeapEntry* message = result->AddEntry( | 3579 HeapEntry* message = result->AddEntry( |
| 3572 HeapEntry::kString, text, 0, 4, 0, 0); | 3580 HeapEntry::kString, text, 0, 4, 0, 0); |
| 3573 root->SetUnidirElementReference(0, 1, message); | 3581 root->SetUnidirElementReference(0, 1, message); |
| 3574 result->SetDominatorsToSelf(); | 3582 result->SetDominatorsToSelf(); |
| 3575 return result; | 3583 return result; |
| 3576 } | 3584 } |
| 3577 | 3585 |
| 3578 | 3586 |
| 3587 void HeapSnapshotJSONSerializer::CalculateNodeIndexes( |
| 3588 const List<HeapEntry*>& nodes) { |
| 3589 // type,name,id,self_size,retained_size,dominator,children_index. |
| 3590 const int node_fields_count = 7; |
| 3591 // Root must be the first. |
| 3592 ASSERT(nodes.first() == snapshot_->root()); |
| 3593 // Rewrite node indexes, so they refer to actual array positions. Do this |
| 3594 // only once. |
| 3595 if (nodes[0]->entry_index() == -1) { |
| 3596 int index = 0; |
| 3597 for (int i = 0; i < nodes.length(); ++i, index += node_fields_count) { |
| 3598 nodes[i]->set_entry_index(index); |
| 3599 } |
| 3600 } |
| 3601 } |
| 3602 |
| 3603 |
| 3579 void HeapSnapshotJSONSerializer::SerializeImpl() { | 3604 void HeapSnapshotJSONSerializer::SerializeImpl() { |
| 3605 List<HeapEntry*>& nodes = *(snapshot_->entries()); |
| 3606 CalculateNodeIndexes(nodes); |
| 3580 writer_->AddCharacter('{'); | 3607 writer_->AddCharacter('{'); |
| 3581 writer_->AddString("\"snapshot\":{"); | 3608 writer_->AddString("\"snapshot\":{"); |
| 3582 SerializeSnapshot(); | 3609 SerializeSnapshot(); |
| 3583 if (writer_->aborted()) return; | 3610 if (writer_->aborted()) return; |
| 3584 writer_->AddString("},\n"); | 3611 writer_->AddString("},\n"); |
| 3585 writer_->AddString("\"nodes\":["); | 3612 writer_->AddString("\"nodes\":["); |
| 3586 SerializeNodes(); | 3613 SerializeNodes(nodes); |
| 3614 if (writer_->aborted()) return; |
| 3615 writer_->AddString("],\n"); |
| 3616 writer_->AddString("\"edges\":["); |
| 3617 SerializeEdges(nodes); |
| 3587 if (writer_->aborted()) return; | 3618 if (writer_->aborted()) return; |
| 3588 writer_->AddString("],\n"); | 3619 writer_->AddString("],\n"); |
| 3589 writer_->AddString("\"strings\":["); | 3620 writer_->AddString("\"strings\":["); |
| 3590 SerializeStrings(); | 3621 SerializeStrings(); |
| 3591 if (writer_->aborted()) return; | 3622 if (writer_->aborted()) return; |
| 3592 writer_->AddCharacter(']'); | 3623 writer_->AddCharacter(']'); |
| 3593 writer_->AddCharacter('}'); | 3624 writer_->AddCharacter('}'); |
| 3594 writer_->Finalize(); | 3625 writer_->Finalize(); |
| 3595 } | 3626 } |
| 3596 | 3627 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 3623 int result = buffer_pos; | 3654 int result = buffer_pos; |
| 3624 do { | 3655 do { |
| 3625 int last_digit = value % 10; | 3656 int last_digit = value % 10; |
| 3626 buffer[--buffer_pos] = '0' + last_digit; | 3657 buffer[--buffer_pos] = '0' + last_digit; |
| 3627 value /= 10; | 3658 value /= 10; |
| 3628 } while (value); | 3659 } while (value); |
| 3629 return result; | 3660 return result; |
| 3630 } | 3661 } |
| 3631 | 3662 |
| 3632 | 3663 |
| 3633 void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge) { | 3664 void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge, |
| 3665 bool first_edge) { |
| 3634 // The buffer needs space for 3 ints, 3 commas and \0 | 3666 // The buffer needs space for 3 ints, 3 commas and \0 |
| 3635 static const int kBufferSize = | 3667 static const int kBufferSize = |
| 3636 MaxDecimalDigitsIn<sizeof(int)>::kSigned * 3 + 3 + 1; // NOLINT | 3668 MaxDecimalDigitsIn<sizeof(int)>::kSigned * 3 + 3 + 1; // NOLINT |
| 3637 EmbeddedVector<char, kBufferSize> buffer; | 3669 EmbeddedVector<char, kBufferSize> buffer; |
| 3638 int edge_name_or_index = edge->type() == HeapGraphEdge::kElement | 3670 int edge_name_or_index = edge->type() == HeapGraphEdge::kElement |
| 3639 || edge->type() == HeapGraphEdge::kHidden | 3671 || edge->type() == HeapGraphEdge::kHidden |
| 3640 || edge->type() == HeapGraphEdge::kWeak | 3672 || edge->type() == HeapGraphEdge::kWeak |
| 3641 ? edge->index() : GetStringId(edge->name()); | 3673 ? edge->index() : GetStringId(edge->name()); |
| 3642 int buffer_pos = 0; | 3674 int buffer_pos = 0; |
| 3643 buffer[buffer_pos++] = ','; | 3675 if (!first_edge) { |
| 3676 buffer[buffer_pos++] = ','; |
| 3677 } |
| 3644 buffer_pos = itoa(edge->type(), buffer, buffer_pos); | 3678 buffer_pos = itoa(edge->type(), buffer, buffer_pos); |
| 3645 buffer[buffer_pos++] = ','; | 3679 buffer[buffer_pos++] = ','; |
| 3646 buffer_pos = itoa(edge_name_or_index, buffer, buffer_pos); | 3680 buffer_pos = itoa(edge_name_or_index, buffer, buffer_pos); |
| 3647 buffer[buffer_pos++] = ','; | 3681 buffer[buffer_pos++] = ','; |
| 3648 buffer_pos = itoa(edge->to()->entry_index(), buffer, buffer_pos); | 3682 buffer_pos = itoa(edge->to()->entry_index(), buffer, buffer_pos); |
| 3649 buffer[buffer_pos++] = '\0'; | 3683 buffer[buffer_pos++] = '\0'; |
| 3650 writer_->AddString(buffer.start()); | 3684 writer_->AddString(buffer.start()); |
| 3651 } | 3685 } |
| 3652 | 3686 |
| 3653 | 3687 |
| 3654 void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry) { | 3688 void HeapSnapshotJSONSerializer::SerializeEdges(const List<HeapEntry*>& nodes) { |
| 3689 bool first_edge = true; |
| 3690 for (int i = 0; i < nodes.length(); ++i) { |
| 3691 HeapEntry* entry = nodes[i]; |
| 3692 Vector<HeapGraphEdge> children = entry->children(); |
| 3693 for (int j = 0; j < children.length(); ++j) { |
| 3694 SerializeEdge(&children[j], first_edge); |
| 3695 first_edge = false; |
| 3696 if (writer_->aborted()) return; |
| 3697 } |
| 3698 } |
| 3699 } |
| 3700 |
| 3701 |
| 3702 void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry, |
| 3703 int edges_index) { |
| 3655 // The buffer needs space for 6 ints, 1 uint32_t, 7 commas, \n and \0 | 3704 // The buffer needs space for 6 ints, 1 uint32_t, 7 commas, \n and \0 |
| 3656 static const int kBufferSize = | 3705 static const int kBufferSize = |
| 3657 6 * MaxDecimalDigitsIn<sizeof(int)>::kSigned // NOLINT | 3706 6 * MaxDecimalDigitsIn<sizeof(int)>::kSigned // NOLINT |
| 3658 + MaxDecimalDigitsIn<sizeof(uint32_t)>::kUnsigned // NOLINT | 3707 + MaxDecimalDigitsIn<sizeof(uint32_t)>::kUnsigned // NOLINT |
| 3659 + 7 + 1 + 1; | 3708 + 7 + 1 + 1; |
| 3660 EmbeddedVector<char, kBufferSize> buffer; | 3709 EmbeddedVector<char, kBufferSize> buffer; |
| 3661 Vector<HeapGraphEdge> children = entry->children(); | |
| 3662 int buffer_pos = 0; | 3710 int buffer_pos = 0; |
| 3663 buffer[buffer_pos++] = '\n'; | 3711 buffer[buffer_pos++] = '\n'; |
| 3664 buffer[buffer_pos++] = ','; | 3712 if (entry->entry_index() != 0) { |
| 3713 buffer[buffer_pos++] = ','; |
| 3714 } |
| 3665 buffer_pos = itoa(entry->type(), buffer, buffer_pos); | 3715 buffer_pos = itoa(entry->type(), buffer, buffer_pos); |
| 3666 buffer[buffer_pos++] = ','; | 3716 buffer[buffer_pos++] = ','; |
| 3667 buffer_pos = itoa(GetStringId(entry->name()), buffer, buffer_pos); | 3717 buffer_pos = itoa(GetStringId(entry->name()), buffer, buffer_pos); |
| 3668 buffer[buffer_pos++] = ','; | 3718 buffer[buffer_pos++] = ','; |
| 3669 buffer_pos = itoa(entry->id(), buffer, buffer_pos); | 3719 buffer_pos = itoa(entry->id(), buffer, buffer_pos); |
| 3670 buffer[buffer_pos++] = ','; | 3720 buffer[buffer_pos++] = ','; |
| 3671 buffer_pos = itoa(entry->self_size(), buffer, buffer_pos); | 3721 buffer_pos = itoa(entry->self_size(), buffer, buffer_pos); |
| 3672 buffer[buffer_pos++] = ','; | 3722 buffer[buffer_pos++] = ','; |
| 3673 buffer_pos = itoa(entry->retained_size(), buffer, buffer_pos); | 3723 buffer_pos = itoa(entry->retained_size(), buffer, buffer_pos); |
| 3674 buffer[buffer_pos++] = ','; | 3724 buffer[buffer_pos++] = ','; |
| 3675 buffer_pos = itoa(entry->dominator()->entry_index(), buffer, buffer_pos); | 3725 buffer_pos = itoa(entry->dominator()->entry_index(), buffer, buffer_pos); |
| 3676 buffer[buffer_pos++] = ','; | 3726 buffer[buffer_pos++] = ','; |
| 3677 buffer_pos = itoa(children.length(), buffer, buffer_pos); | 3727 buffer_pos = itoa(edges_index, buffer, buffer_pos); |
| 3678 buffer[buffer_pos++] = '\0'; | 3728 buffer[buffer_pos++] = '\0'; |
| 3679 writer_->AddString(buffer.start()); | 3729 writer_->AddString(buffer.start()); |
| 3680 for (int i = 0; i < children.length(); ++i) { | 3730 } |
| 3681 SerializeEdge(&children[i]); | 3731 |
| 3732 |
| 3733 void HeapSnapshotJSONSerializer::SerializeNodes(const List<HeapEntry*>& nodes) { |
| 3734 const int edge_fields_count = 3; // type,name|index,to_node. |
| 3735 int edges_index = 0; |
| 3736 for (int i = 0; i < nodes.length(); ++i) { |
| 3737 HeapEntry* entry = nodes[i]; |
| 3738 SerializeNode(entry, edges_index); |
| 3739 edges_index += entry->children().length() * edge_fields_count; |
| 3682 if (writer_->aborted()) return; | 3740 if (writer_->aborted()) return; |
| 3683 } | 3741 } |
| 3684 } | 3742 } |
| 3685 | |
| 3686 | |
| 3687 void HeapSnapshotJSONSerializer::SerializeNodes() { | |
| 3688 // The first (zero) item of nodes array is an object describing node | |
| 3689 // serialization layout. We use a set of macros to improve | |
| 3690 // readability. | |
| 3691 #define JSON_A(s) "["s"]" | |
| 3692 #define JSON_O(s) "{"s"}" | |
| 3693 #define JSON_S(s) "\""s"\"" | |
| 3694 writer_->AddString(JSON_O( | |
| 3695 JSON_S("fields") ":" JSON_A( | |
| 3696 JSON_S("type") | |
| 3697 "," JSON_S("name") | |
| 3698 "," JSON_S("id") | |
| 3699 "," JSON_S("self_size") | |
| 3700 "," JSON_S("retained_size") | |
| 3701 "," JSON_S("dominator") | |
| 3702 "," JSON_S("children_count") | |
| 3703 "," JSON_S("children")) | |
| 3704 "," JSON_S("types") ":" JSON_A( | |
| 3705 JSON_A( | |
| 3706 JSON_S("hidden") | |
| 3707 "," JSON_S("array") | |
| 3708 "," JSON_S("string") | |
| 3709 "," JSON_S("object") | |
| 3710 "," JSON_S("code") | |
| 3711 "," JSON_S("closure") | |
| 3712 "," JSON_S("regexp") | |
| 3713 "," JSON_S("number") | |
| 3714 "," JSON_S("native") | |
| 3715 "," JSON_S("synthetic")) | |
| 3716 "," JSON_S("string") | |
| 3717 "," JSON_S("number") | |
| 3718 "," JSON_S("number") | |
| 3719 "," JSON_S("number") | |
| 3720 "," JSON_S("number") | |
| 3721 "," JSON_S("number") | |
| 3722 "," JSON_O( | |
| 3723 JSON_S("fields") ":" JSON_A( | |
| 3724 JSON_S("type") | |
| 3725 "," JSON_S("name_or_index") | |
| 3726 "," JSON_S("to_node")) | |
| 3727 "," JSON_S("types") ":" JSON_A( | |
| 3728 JSON_A( | |
| 3729 JSON_S("context") | |
| 3730 "," JSON_S("element") | |
| 3731 "," JSON_S("property") | |
| 3732 "," JSON_S("internal") | |
| 3733 "," JSON_S("hidden") | |
| 3734 "," JSON_S("shortcut") | |
| 3735 "," JSON_S("weak")) | |
| 3736 "," JSON_S("string_or_number") | |
| 3737 "," JSON_S("node")))))); | |
| 3738 #undef JSON_S | |
| 3739 #undef JSON_O | |
| 3740 #undef JSON_A | |
| 3741 | |
| 3742 const int node_fields_count = 7; | |
| 3743 // type,name,id,self_size,retained_size,dominator,children_count. | |
| 3744 const int edge_fields_count = 3; // type,name|index,to_node. | |
| 3745 | |
| 3746 List<HeapEntry*>& nodes = *(snapshot_->entries()); | |
| 3747 // Root must be the first. | |
| 3748 ASSERT(nodes.first() == snapshot_->root()); | |
| 3749 // Rewrite node indexes, so they refer to actual array positions. Do this | |
| 3750 // only once. | |
| 3751 if (nodes[0]->entry_index() == -1) { | |
| 3752 // Nodes start from array index 1. | |
| 3753 int index = 1; | |
| 3754 for (int i = 0; i < nodes.length(); ++i) { | |
| 3755 HeapEntry* node = nodes[i]; | |
| 3756 node->set_entry_index(index); | |
| 3757 index += node_fields_count + | |
| 3758 node->children().length() * edge_fields_count; | |
| 3759 } | |
| 3760 } | |
| 3761 | |
| 3762 for (int i = 0; i < nodes.length(); ++i) { | |
| 3763 SerializeNode(nodes[i]); | |
| 3764 if (writer_->aborted()) return; | |
| 3765 } | |
| 3766 } | |
| 3767 | 3743 |
| 3768 | 3744 |
| 3769 void HeapSnapshotJSONSerializer::SerializeSnapshot() { | 3745 void HeapSnapshotJSONSerializer::SerializeSnapshot() { |
| 3770 writer_->AddString("\"title\":\""); | 3746 writer_->AddString("\"title\":\""); |
| 3771 writer_->AddString(snapshot_->title()); | 3747 writer_->AddString(snapshot_->title()); |
| 3772 writer_->AddString("\""); | 3748 writer_->AddString("\""); |
| 3773 writer_->AddString(",\"uid\":"); | 3749 writer_->AddString(",\"uid\":"); |
| 3774 writer_->AddNumber(snapshot_->uid()); | 3750 writer_->AddNumber(snapshot_->uid()); |
| 3751 writer_->AddString(",\"meta\":"); |
| 3752 // The object describing node serialization layout. |
| 3753 // We use a set of macros to improve readability. |
| 3754 #define JSON_A(s) "["s"]" |
| 3755 #define JSON_O(s) "{"s"}" |
| 3756 #define JSON_S(s) "\""s"\"" |
| 3757 writer_->AddString(JSON_O( |
| 3758 JSON_S("node_fields") ":" JSON_A( |
| 3759 JSON_S("type") "," |
| 3760 JSON_S("name") "," |
| 3761 JSON_S("id") "," |
| 3762 JSON_S("self_size") "," |
| 3763 JSON_S("retained_size") "," |
| 3764 JSON_S("dominator") "," |
| 3765 JSON_S("edges_index")) "," |
| 3766 JSON_S("node_types") ":" JSON_A( |
| 3767 JSON_A( |
| 3768 JSON_S("hidden") "," |
| 3769 JSON_S("array") "," |
| 3770 JSON_S("string") "," |
| 3771 JSON_S("object") "," |
| 3772 JSON_S("code") "," |
| 3773 JSON_S("closure") "," |
| 3774 JSON_S("regexp") "," |
| 3775 JSON_S("number") "," |
| 3776 JSON_S("native") "," |
| 3777 JSON_S("synthetic")) "," |
| 3778 JSON_S("string") "," |
| 3779 JSON_S("number") "," |
| 3780 JSON_S("number") "," |
| 3781 JSON_S("number") "," |
| 3782 JSON_S("number") "," |
| 3783 JSON_S("number")) "," |
| 3784 JSON_S("edge_fields") ":" JSON_A( |
| 3785 JSON_S("type") "," |
| 3786 JSON_S("name_or_index") "," |
| 3787 JSON_S("to_node")) "," |
| 3788 JSON_S("edge_types") ":" JSON_A( |
| 3789 JSON_A( |
| 3790 JSON_S("context") "," |
| 3791 JSON_S("element") "," |
| 3792 JSON_S("property") "," |
| 3793 JSON_S("internal") "," |
| 3794 JSON_S("hidden") "," |
| 3795 JSON_S("shortcut") "," |
| 3796 JSON_S("weak")) "," |
| 3797 JSON_S("string_or_number") "," |
| 3798 JSON_S("node")))); |
| 3799 #undef JSON_S |
| 3800 #undef JSON_O |
| 3801 #undef JSON_A |
| 3802 writer_->AddString(",\"node_count\":"); |
| 3803 writer_->AddNumber(snapshot_->entries()->length()); |
| 3804 writer_->AddString(",\"edge_count\":"); |
| 3805 writer_->AddNumber(snapshot_->number_of_edges()); |
| 3775 } | 3806 } |
| 3776 | 3807 |
| 3777 | 3808 |
| 3778 static void WriteUChar(OutputStreamWriter* w, unibrow::uchar u) { | 3809 static void WriteUChar(OutputStreamWriter* w, unibrow::uchar u) { |
| 3779 static const char hex_chars[] = "0123456789ABCDEF"; | 3810 static const char hex_chars[] = "0123456789ABCDEF"; |
| 3780 w->AddString("\\u"); | 3811 w->AddString("\\u"); |
| 3781 w->AddCharacter(hex_chars[(u >> 12) & 0xf]); | 3812 w->AddCharacter(hex_chars[(u >> 12) & 0xf]); |
| 3782 w->AddCharacter(hex_chars[(u >> 8) & 0xf]); | 3813 w->AddCharacter(hex_chars[(u >> 8) & 0xf]); |
| 3783 w->AddCharacter(hex_chars[(u >> 4) & 0xf]); | 3814 w->AddCharacter(hex_chars[(u >> 4) & 0xf]); |
| 3784 w->AddCharacter(hex_chars[u & 0xf]); | 3815 w->AddCharacter(hex_chars[u & 0xf]); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3862 | 3893 |
| 3863 | 3894 |
| 3864 void HeapSnapshotJSONSerializer::SortHashMap( | 3895 void HeapSnapshotJSONSerializer::SortHashMap( |
| 3865 HashMap* map, List<HashMap::Entry*>* sorted_entries) { | 3896 HashMap* map, List<HashMap::Entry*>* sorted_entries) { |
| 3866 for (HashMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) | 3897 for (HashMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) |
| 3867 sorted_entries->Add(p); | 3898 sorted_entries->Add(p); |
| 3868 sorted_entries->Sort(SortUsingEntryValue); | 3899 sorted_entries->Sort(SortUsingEntryValue); |
| 3869 } | 3900 } |
| 3870 | 3901 |
| 3871 } } // namespace v8::internal | 3902 } } // namespace v8::internal |
| OLD | NEW |