Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(799)

Side by Side Diff: src/profile-generator.cc

Issue 2722005: The new JS Heap Profiler: the main part. (Closed)
Patch Set: Comments addressed Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/profile-generator.h ('k') | src/profile-generator-inl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2010 the V8 project authors. All rights reserved. 1 // Copyright 2010 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 11 matching lines...) Expand all
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 27
28 #ifdef ENABLE_LOGGING_AND_PROFILING 28 #ifdef ENABLE_LOGGING_AND_PROFILING
29 29
30 #include "v8.h" 30 #include "v8.h"
31 #include "global-handles.h" 31 #include "global-handles.h"
32 #include "scopeinfo.h"
33 #include "top.h"
34 #include "zone-inl.h"
32 35
33 #include "profile-generator-inl.h" 36 #include "profile-generator-inl.h"
34 37
35 #include "../include/v8-profiler.h"
36
37 namespace v8 { 38 namespace v8 {
38 namespace internal { 39 namespace internal {
39 40
40 41
41 TokenEnumerator::TokenEnumerator() 42 TokenEnumerator::TokenEnumerator()
42 : token_locations_(4), 43 : token_locations_(4),
43 token_removed_(4) { 44 token_removed_(4) {
44 } 45 }
45 46
46 47
(...skipping 757 matching lines...) Expand 10 before | Expand all | Expand 10 after
804 } 805 }
805 // If no frames were symbolized, put the VM state entry in. 806 // If no frames were symbolized, put the VM state entry in.
806 if (no_symbolized_entries) { 807 if (no_symbolized_entries) {
807 *entry++ = EntryForVMState(sample.state); 808 *entry++ = EntryForVMState(sample.state);
808 } 809 }
809 } 810 }
810 811
811 profiles_->AddPathToCurrentProfiles(entries); 812 profiles_->AddPathToCurrentProfiles(entries);
812 } 813 }
813 814
815
816 HeapGraphEdge::HeapGraphEdge(Type type,
817 const char* name,
818 HeapEntry* from,
819 HeapEntry* to)
820 : type_(type), name_(name), from_(from), to_(to) {
821 ASSERT(type_ == CONTEXT_VARIABLE || type_ == PROPERTY);
822 }
823
824
825 HeapGraphEdge::HeapGraphEdge(int index,
826 HeapEntry* from,
827 HeapEntry* to)
828 : type_(ELEMENT), index_(index), from_(from), to_(to) {
829 }
830
831
832 static void DeleteHeapGraphEdge(HeapGraphEdge** edge_ptr) {
833 delete *edge_ptr;
834 }
835
836
837 static void DeleteHeapGraphPath(HeapGraphPath** path_ptr) {
838 delete *path_ptr;
839 }
840
841
842 HeapEntry::~HeapEntry() {
843 children_.Iterate(DeleteHeapGraphEdge);
844 retaining_paths_.Iterate(DeleteHeapGraphPath);
845 }
846
847
848 void HeapEntry::SetClosureReference(const char* name, HeapEntry* entry) {
849 HeapGraphEdge* edge =
850 new HeapGraphEdge(HeapGraphEdge::CONTEXT_VARIABLE, name, this, entry);
851 children_.Add(edge);
852 entry->retainers_.Add(edge);
853 }
854
855
856 void HeapEntry::SetElementReference(int index, HeapEntry* entry) {
857 HeapGraphEdge* edge = new HeapGraphEdge(index, this, entry);
858 children_.Add(edge);
859 entry->retainers_.Add(edge);
860 }
861
862
863 void HeapEntry::SetPropertyReference(const char* name, HeapEntry* entry) {
864 HeapGraphEdge* edge =
865 new HeapGraphEdge(HeapGraphEdge::PROPERTY, name, this, entry);
866 children_.Add(edge);
867 entry->retainers_.Add(edge);
868 }
869
870
871 void HeapEntry::SetAutoIndexReference(HeapEntry* entry) {
872 SetElementReference(next_auto_index_++, entry);
873 }
874
875
876 int HeapEntry::TotalSize() {
877 return total_size_ != kUnknownSize ? total_size_ : CalculateTotalSize();
878 }
879
880
881 int HeapEntry::NonSharedTotalSize() {
882 return non_shared_total_size_ != kUnknownSize ?
883 non_shared_total_size_ : CalculateNonSharedTotalSize();
884 }
885
886
887 int HeapEntry::CalculateTotalSize() {
888 snapshot_->ClearPaint();
889 List<HeapEntry*> list(10);
890 list.Add(this);
891 total_size_ = self_size_;
892 this->PaintReachable();
893 while (!list.is_empty()) {
894 HeapEntry* entry = list.RemoveLast();
895 const int children_count = entry->children_.length();
896 for (int i = 0; i < children_count; ++i) {
897 HeapEntry* child = entry->children_[i]->to();
898 if (!child->painted_reachable()) {
899 list.Add(child);
900 child->PaintReachable();
901 total_size_ += child->self_size_;
902 }
903 }
904 }
905 return total_size_;
906 }
907
908
909 namespace {
910
911 class NonSharedSizeCalculator {
912 public:
913 NonSharedSizeCalculator()
914 : non_shared_total_size_(0) {
915 }
916
917 int non_shared_total_size() const { return non_shared_total_size_; }
918
919 void Apply(HeapEntry* entry) {
920 if (entry->painted_reachable()) {
921 non_shared_total_size_ += entry->self_size();
922 }
923 }
924
925 private:
926 int non_shared_total_size_;
927 };
928
929 } // namespace
930
931 int HeapEntry::CalculateNonSharedTotalSize() {
932 // To calculate non-shared total size, first we paint all reachable
933 // nodes in one color, then we paint all nodes reachable from other
934 // nodes with a different color. Then we consider only nodes painted
935 // with the first color for caclulating the total size.
936 snapshot_->ClearPaint();
937 List<HeapEntry*> list(10);
938 list.Add(this);
939 this->PaintReachable();
940 while (!list.is_empty()) {
941 HeapEntry* entry = list.RemoveLast();
942 const int children_count = entry->children_.length();
943 for (int i = 0; i < children_count; ++i) {
944 HeapEntry* child = entry->children_[i]->to();
945 if (!child->painted_reachable()) {
946 list.Add(child);
947 child->PaintReachable();
948 }
949 }
950 }
951
952 List<HeapEntry*> list2(10);
953 if (this != snapshot_->root()) {
954 list2.Add(snapshot_->root());
955 snapshot_->root()->PaintReachableFromOthers();
956 }
957 while (!list2.is_empty()) {
958 HeapEntry* entry = list2.RemoveLast();
959 const int children_count = entry->children_.length();
960 for (int i = 0; i < children_count; ++i) {
961 HeapEntry* child = entry->children_[i]->to();
962 if (child != this && child->not_painted_reachable_from_others()) {
963 list2.Add(child);
964 child->PaintReachableFromOthers();
965 }
966 }
967 }
968
969 NonSharedSizeCalculator calculator;
970 snapshot_->IterateEntries(&calculator);
971 return calculator.non_shared_total_size();
972 }
973
974
975 class CachedHeapGraphPath {
976 public:
977 CachedHeapGraphPath()
978 : nodes_(NodesMatch) { }
979 CachedHeapGraphPath(const CachedHeapGraphPath& src)
980 : nodes_(NodesMatch, &HashMap::DefaultAllocator, src.nodes_.capacity()),
981 path_(src.path_.length() + 1) {
982 for (HashMap::Entry* p = src.nodes_.Start();
983 p != NULL;
984 p = src.nodes_.Next(p)) {
985 nodes_.Lookup(p->key, p->hash, true);
986 }
987 path_.AddAll(src.path_);
988 }
989 void Add(HeapGraphEdge* edge) {
990 nodes_.Lookup(edge->to(), Hash(edge->to()), true);
991 path_.Add(edge);
992 }
993 bool ContainsNode(HeapEntry* node) {
994 return nodes_.Lookup(node, Hash(node), false) != NULL;
995 }
996 const List<HeapGraphEdge*>* path() const { return &path_; }
997
998 private:
999 static uint32_t Hash(HeapEntry* entry) {
1000 return static_cast<uint32_t>(reinterpret_cast<intptr_t>(entry));
1001 }
1002 static bool NodesMatch(void* key1, void* key2) { return key1 == key2; }
1003
1004 HashMap nodes_;
1005 List<HeapGraphEdge*> path_;
1006 };
1007
1008
1009 const List<HeapGraphPath*>* HeapEntry::GetRetainingPaths() {
1010 if (retaining_paths_.length() == 0 && retainers_.length() != 0) {
1011 CachedHeapGraphPath path;
1012 FindRetainingPaths(this, &path);
1013 }
1014 return &retaining_paths_;
1015 }
1016
1017
1018 void HeapEntry::FindRetainingPaths(HeapEntry* node,
1019 CachedHeapGraphPath* prev_path) {
1020 for (int i = 0; i < node->retainers_.length(); ++i) {
1021 HeapGraphEdge* ret_edge = node->retainers_[i];
1022 if (prev_path->ContainsNode(ret_edge->from())) continue;
1023 if (ret_edge->from() != snapshot_->root()) {
1024 CachedHeapGraphPath path(*prev_path);
1025 path.Add(ret_edge);
1026 FindRetainingPaths(ret_edge->from(), &path);
1027 } else {
1028 HeapGraphPath* ret_path = new HeapGraphPath(*prev_path->path());
1029 ret_path->Set(0, ret_edge);
1030 retaining_paths_.Add(ret_path);
1031 }
1032 }
1033 }
1034
1035
1036 static void RemoveEdge(List<HeapGraphEdge*>* list, HeapGraphEdge* edge) {
1037 for (int i = 0; i < list->length(); ) {
1038 if (list->at(i) == edge) {
1039 list->Remove(i);
1040 return;
1041 } else {
1042 ++i;
1043 }
1044 }
1045 UNREACHABLE();
1046 }
1047
1048
1049 void HeapEntry::RemoveChild(HeapGraphEdge* edge) {
1050 RemoveEdge(&children_, edge);
1051 delete edge;
1052 }
1053
1054
1055 void HeapEntry::RemoveRetainer(HeapGraphEdge* edge) {
1056 RemoveEdge(&retainers_, edge);
1057 }
1058
1059
1060 void HeapEntry::CutEdges() {
1061 for (int i = 0; i < children_.length(); ++i) {
1062 HeapGraphEdge* edge = children_[i];
1063 edge->to()->RemoveRetainer(edge);
1064 }
1065 children_.Iterate(DeleteHeapGraphEdge);
1066 children_.Clear();
1067
1068 for (int i = 0; i < retainers_.length(); ++i) {
1069 HeapGraphEdge* edge = retainers_[i];
1070 edge->from()->RemoveChild(edge);
1071 }
1072 retainers_.Clear();
1073 }
1074
1075
1076 void HeapEntry::Print(int max_depth, int indent) {
1077 OS::Print("%6d %6d %6d", self_size_, TotalSize(), NonSharedTotalSize());
1078 if (type_ != STRING) {
1079 OS::Print("%s %.40s\n", TypeAsString(), name_);
1080 } else {
1081 OS::Print("\"");
1082 const char* c = name_;
1083 while (*c && (c - name_) <= 40) {
1084 if (*c != '\n')
1085 OS::Print("%c", *c);
1086 else
1087 OS::Print("\\n");
1088 ++c;
1089 }
1090 OS::Print("\"\n");
1091 }
1092 if (--max_depth == 0) return;
1093 const int children_count = children_.length();
1094 for (int i = 0; i < children_count; ++i) {
1095 HeapGraphEdge* edge = children_[i];
1096 switch (edge->type()) {
1097 case HeapGraphEdge::CONTEXT_VARIABLE:
1098 OS::Print(" %*c #%s: ", indent, ' ', edge->name());
1099 break;
1100 case HeapGraphEdge::ELEMENT:
1101 OS::Print(" %*c %d: ", indent, ' ', edge->index());
1102 break;
1103 case HeapGraphEdge::PROPERTY:
1104 OS::Print(" %*c %s: ", indent, ' ', edge->name());
1105 break;
1106 default:
1107 OS::Print("!!! unknown edge type: %d ", edge->type());
1108 }
1109 edge->to()->Print(max_depth, indent + 2);
1110 }
1111 }
1112
1113
1114 const char* HeapEntry::TypeAsString() {
1115 switch (type_) {
1116 case INTERNAL: return "/internal/";
1117 case JS_OBJECT: return "/object/";
1118 case CLOSURE: return "/closure/";
1119 case STRING: return "/string/";
1120 case CODE: return "/code/";
1121 case ARRAY: return "/array/";
1122 default: return "???";
1123 }
1124 }
1125
1126
1127 HeapGraphPath::HeapGraphPath(const List<HeapGraphEdge*>& path)
1128 : path_(path.length() + 1) {
1129 Add(NULL);
1130 for (int i = path.length() - 1; i >= 0; --i) {
1131 Add(path[i]);
1132 }
1133 }
1134
1135
1136 void HeapGraphPath::Print() {
1137 path_[0]->from()->Print(1, 0);
1138 for (int i = 0; i < path_.length(); ++i) {
1139 OS::Print(" -> ");
1140 HeapGraphEdge* edge = path_[i];
1141 switch (edge->type()) {
1142 case HeapGraphEdge::CONTEXT_VARIABLE:
1143 OS::Print("[#%s] ", edge->name());
1144 break;
1145 case HeapGraphEdge::ELEMENT:
1146 OS::Print("[%d] ", edge->index());
1147 break;
1148 case HeapGraphEdge::PROPERTY:
1149 OS::Print("[%s] ", edge->name());
1150 break;
1151 default:
1152 OS::Print("!!! unknown edge type: %d ", edge->type());
1153 }
1154 edge->to()->Print(1, 0);
1155 }
1156 OS::Print("\n");
1157 }
1158
1159
1160 class IndexedReferencesExtractor : public ObjectVisitor {
1161 public:
1162 IndexedReferencesExtractor(HeapSnapshot* snapshot, HeapEntry* parent)
1163 : snapshot_(snapshot),
1164 parent_(parent) {
1165 }
1166
1167 void VisitPointer(Object** o) {
1168 if (!(*o)->IsHeapObject()) return;
1169 HeapEntry* entry = snapshot_->GetEntry(HeapObject::cast(*o));
1170 if (entry != NULL) {
1171 parent_->SetAutoIndexReference(entry);
1172 }
1173 }
1174
1175 void VisitPointers(Object** start, Object** end) {
1176 for (Object** p = start; p < end; p++) VisitPointer(p);
1177 }
1178
1179 private:
1180 HeapSnapshot* snapshot_;
1181 HeapEntry* parent_;
1182 };
1183
1184
1185 HeapEntriesMap::HeapEntriesMap()
1186 : entries_(HeapObjectsMatch) {
1187 }
1188
1189
1190 HeapEntriesMap::~HeapEntriesMap() {
1191 for (HashMap::Entry* p = entries_.Start();
1192 p != NULL;
1193 p = entries_.Next(p)) {
1194 if (!IsAlias(p->value)) delete reinterpret_cast<HeapEntry*>(p->value);
1195 }
1196 }
1197
1198
1199 void HeapEntriesMap::Alias(HeapObject* object, HeapEntry* entry) {
1200 HashMap::Entry* cache_entry = entries_.Lookup(object, Hash(object), true);
1201 if (cache_entry->value == NULL)
1202 cache_entry->value = reinterpret_cast<void*>(
1203 reinterpret_cast<intptr_t>(entry) | kAliasTag);
1204 }
1205
1206
1207 void HeapEntriesMap::Apply(void (HeapEntry::*Func)(void)) {
1208 for (HashMap::Entry* p = entries_.Start();
1209 p != NULL;
1210 p = entries_.Next(p)) {
1211 if (!IsAlias(p->value)) (reinterpret_cast<HeapEntry*>(p->value)->*Func)();
1212 }
1213 }
1214
1215
1216 HeapEntry* HeapEntriesMap::Map(HeapObject* object) {
1217 HashMap::Entry* cache_entry = entries_.Lookup(object, Hash(object), false);
1218 return cache_entry != NULL ?
1219 reinterpret_cast<HeapEntry*>(
1220 reinterpret_cast<intptr_t>(cache_entry->value) & (~kAliasTag)) : NULL;
1221 }
1222
1223
1224 void HeapEntriesMap::Pair(HeapObject* object, HeapEntry* entry) {
1225 HashMap::Entry* cache_entry = entries_.Lookup(object, Hash(object), true);
1226 ASSERT(cache_entry->value == NULL);
1227 cache_entry->value = entry;
1228 }
1229
1230
1231 HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection,
1232 const char* title,
1233 unsigned uid)
1234 : collection_(collection),
1235 title_(title),
1236 uid_(uid),
1237 root_(this) {
1238 }
1239
1240
1241 void HeapSnapshot::ClearPaint() {
1242 root_.ClearPaint();
1243 entries_.Apply(&HeapEntry::ClearPaint);
1244 }
1245
1246
1247 HeapEntry* HeapSnapshot::GetEntry(Object* obj) {
1248 if (!obj->IsHeapObject()) return NULL;
1249 HeapObject* object = HeapObject::cast(obj);
1250
1251 {
1252 HeapEntry* existing = FindEntry(object);
1253 if (existing != NULL) return existing;
1254 }
1255
1256 // Add new entry.
1257 if (object->IsJSFunction()) {
1258 JSFunction* func = JSFunction::cast(object);
1259 SharedFunctionInfo* shared = func->shared();
1260 String* name = String::cast(shared->name())->length() > 0 ?
1261 String::cast(shared->name()) : shared->inferred_name();
1262 return AddEntry(object, HeapEntry::CLOSURE, collection_->GetName(name));
1263 } else if (object->IsJSObject()) {
1264 return AddEntry(object,
1265 HeapEntry::JS_OBJECT,
1266 collection_->GetName(
1267 JSObject::cast(object)->constructor_name()));
1268 } else if (object->IsJSGlobalPropertyCell()) {
1269 HeapEntry* value = GetEntry(JSGlobalPropertyCell::cast(object)->value());
1270 // If GPC references an object that we have interest in, add the object.
1271 // We don't store HeapEntries for GPCs. Instead, we make our hash map
1272 // to point to object's HeapEntry by GPCs address.
1273 if (value != NULL) AddEntryAlias(object, value);
1274 return value;
1275 } else if (object->IsString()) {
1276 return AddEntry(object,
1277 HeapEntry::STRING,
1278 collection_->GetName(String::cast(object)));
1279 } else if (object->IsCode()
1280 || object->IsSharedFunctionInfo()
1281 || object->IsScript()) {
1282 return AddEntry(object, HeapEntry::CODE);
1283 } else if (object->IsFixedArray()) {
1284 return AddEntry(object, HeapEntry::ARRAY);
1285 }
1286 // No interest in this object.
1287 return NULL;
1288 }
1289
1290
1291 void HeapSnapshot::SetClosureReference(HeapEntry* parent,
1292 String* reference_name,
1293 Object* child) {
1294 HeapEntry* child_entry = GetEntry(child);
1295 if (child_entry != NULL) {
1296 parent->SetClosureReference(
1297 collection_->GetName(reference_name), child_entry);
1298 }
1299 }
1300
1301
1302 void HeapSnapshot::SetElementReference(HeapEntry* parent,
1303 int index,
1304 Object* child) {
1305 HeapEntry* child_entry = GetEntry(child);
1306 if (child_entry != NULL) {
1307 parent->SetElementReference(index, child_entry);
1308 }
1309 }
1310
1311
1312 void HeapSnapshot::SetPropertyReference(HeapEntry* parent,
1313 String* reference_name,
1314 Object* child) {
1315 HeapEntry* child_entry = GetEntry(child);
1316 if (child_entry != NULL) {
1317 parent->SetPropertyReference(
1318 collection_->GetName(reference_name), child_entry);
1319 }
1320 }
1321
1322
1323 HeapEntry* HeapSnapshot::AddEntry(HeapObject* object,
1324 HeapEntry::Type type,
1325 const char* name) {
1326 HeapEntry* entry = new HeapEntry(this,
1327 type,
1328 name,
1329 GetObjectSize(object),
1330 GetObjectSecurityToken(object));
1331 entries_.Pair(object, entry);
1332
1333 // Detect, if this is a JS global object of the current context, and
1334 // add it to snapshot's roots. There can be several JS global objects
1335 // in a context.
1336 if (object->IsJSGlobalProxy()) {
1337 int global_security_token = GetGlobalSecurityToken();
1338 int object_security_token =
1339 collection_->token_enumerator()->GetTokenId(
1340 Context::cast(
1341 JSGlobalProxy::cast(object)->context())->security_token());
1342 if (object_security_token == TokenEnumerator::kNoSecurityToken
1343 || object_security_token == global_security_token) {
1344 HeapEntry* global_object_entry =
1345 GetEntry(HeapObject::cast(object->map()->prototype()));
1346 ASSERT(global_object_entry != NULL);
1347 root_.SetAutoIndexReference(global_object_entry);
1348 }
1349 }
1350
1351 return entry;
1352 }
1353
1354
1355 namespace {
1356
1357 class EdgesCutter {
1358 public:
1359 explicit EdgesCutter(int global_security_token)
1360 : global_security_token_(global_security_token) {
1361 }
1362
1363 void Apply(HeapEntry* entry) {
1364 if (entry->security_token_id() != TokenEnumerator::kNoSecurityToken
1365 && entry->security_token_id() != global_security_token_) {
1366 entry->CutEdges();
1367 }
1368 }
1369
1370 private:
1371 const int global_security_token_;
1372 };
1373
1374 } // namespace
1375
1376 void HeapSnapshot::CutObjectsFromForeignSecurityContexts() {
1377 EdgesCutter cutter(GetGlobalSecurityToken());
1378 entries_.Apply(&cutter);
1379 }
1380
1381
1382 int HeapSnapshot::GetGlobalSecurityToken() {
1383 return collection_->token_enumerator()->GetTokenId(
1384 Top::context()->global()->global_context()->security_token());
1385 }
1386
1387
1388 int HeapSnapshot::GetObjectSize(HeapObject* obj) {
1389 return obj->IsJSObject() ?
1390 CalculateNetworkSize(JSObject::cast(obj)) : obj->Size();
1391 }
1392
1393
1394 int HeapSnapshot::GetObjectSecurityToken(HeapObject* obj) {
1395 if (obj->IsGlobalContext()) {
1396 return collection_->token_enumerator()->GetTokenId(
1397 Context::cast(obj)->security_token());
1398 } else {
1399 return TokenEnumerator::kNoSecurityToken;
1400 }
1401 }
1402
1403
1404 int HeapSnapshot::CalculateNetworkSize(JSObject* obj) {
1405 int size = obj->Size();
1406 // If 'properties' and 'elements' are non-empty (thus, non-shared),
1407 // take their size into account.
1408 if (FixedArray::cast(obj->properties())->length() != 0) {
1409 size += obj->properties()->Size();
1410 }
1411 if (FixedArray::cast(obj->elements())->length() != 0) {
1412 size += obj->elements()->Size();
1413 }
1414 // For functions, also account non-empty context and literals sizes.
1415 if (obj->IsJSFunction()) {
1416 JSFunction* f = JSFunction::cast(obj);
1417 if (f->unchecked_context()->IsContext()) {
1418 size += f->context()->Size();
1419 }
1420 if (f->literals()->length() != 0) {
1421 size += f->literals()->Size();
1422 }
1423 }
1424 return size;
1425 }
1426
1427
1428 void HeapSnapshot::Print(int max_depth) {
1429 root_.Print(max_depth, 0);
1430 }
1431
1432
1433 HeapSnapshotsCollection::HeapSnapshotsCollection()
1434 : snapshots_uids_(HeapSnapshotsMatch),
1435 token_enumerator_(new TokenEnumerator()) {
1436 }
1437
1438
1439 static void DeleteHeapSnapshot(HeapSnapshot** snapshot_ptr) {
1440 delete *snapshot_ptr;
1441 }
1442
1443
1444 HeapSnapshotsCollection::~HeapSnapshotsCollection() {
1445 delete token_enumerator_;
1446 snapshots_.Iterate(DeleteHeapSnapshot);
1447 }
1448
1449
1450 HeapSnapshot* HeapSnapshotsCollection::NewSnapshot(const char* name,
1451 unsigned uid) {
1452 HeapSnapshot* snapshot = new HeapSnapshot(this, name, uid);
1453 snapshots_.Add(snapshot);
1454 HashMap::Entry* entry =
1455 snapshots_uids_.Lookup(reinterpret_cast<void*>(snapshot->uid()),
1456 static_cast<uint32_t>(snapshot->uid()),
1457 true);
1458 ASSERT(entry->value == NULL);
1459 entry->value = snapshot;
1460 return snapshot;
1461 }
1462
1463
1464 HeapSnapshot* HeapSnapshotsCollection::GetSnapshot(unsigned uid) {
1465 HashMap::Entry* entry = snapshots_uids_.Lookup(reinterpret_cast<void*>(uid),
1466 static_cast<uint32_t>(uid),
1467 false);
1468 return entry != NULL ? reinterpret_cast<HeapSnapshot*>(entry->value) : NULL;
1469 }
1470
1471
1472 HeapSnapshotGenerator::HeapSnapshotGenerator(HeapSnapshot* snapshot)
1473 : snapshot_(snapshot) {
1474 }
1475
1476
1477 void HeapSnapshotGenerator::GenerateSnapshot() {
1478 AssertNoAllocation no_alloc;
1479
1480 // Iterate heap contents.
1481 HeapIterator iterator;
1482 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1483 ExtractReferences(obj);
1484 }
1485
1486 snapshot_->CutObjectsFromForeignSecurityContexts();
1487 }
1488
1489
1490 void HeapSnapshotGenerator::ExtractReferences(HeapObject* obj) {
1491 HeapEntry* entry = snapshot_->GetEntry(obj);
1492 if (entry == NULL) return;
1493 if (entry->visited()) return;
1494
1495 if (obj->IsJSObject()) {
1496 JSObject* js_obj = JSObject::cast(obj);
1497 ExtractClosureReferences(js_obj, entry);
1498 ExtractPropertyReferences(js_obj, entry);
1499 ExtractElementReferences(js_obj, entry);
1500 snapshot_->SetPropertyReference(
1501 entry, Heap::prototype_symbol(), js_obj->map()->prototype());
1502 } else if (obj->IsJSGlobalPropertyCell()) {
1503 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(obj);
1504 snapshot_->SetElementReference(entry, 0, cell->value());
1505 } else if (obj->IsString()) {
1506 if (obj->IsConsString()) {
1507 ConsString* cs = ConsString::cast(obj);
1508 snapshot_->SetElementReference(entry, 0, cs->first());
1509 snapshot_->SetElementReference(entry, 1, cs->second());
1510 }
1511 } else if (obj->IsCode() || obj->IsSharedFunctionInfo() || obj->IsScript()) {
1512 IndexedReferencesExtractor refs_extractor(snapshot_, entry);
1513 obj->Iterate(&refs_extractor);
1514 } else if (obj->IsFixedArray()) {
1515 IndexedReferencesExtractor refs_extractor(snapshot_, entry);
1516 obj->Iterate(&refs_extractor);
1517 }
1518 entry->MarkAsVisited();
1519 }
1520
1521
1522 void HeapSnapshotGenerator::ExtractClosureReferences(JSObject* js_obj,
1523 HeapEntry* entry) {
1524 if (js_obj->IsJSFunction()) {
1525 HandleScope hs;
1526 JSFunction* func = JSFunction::cast(js_obj);
1527 Context* context = func->context();
1528 ZoneScope zscope(DELETE_ON_EXIT);
1529 ScopeInfo<ZoneListAllocationPolicy> scope_info(
1530 context->closure()->shared()->code());
1531 int locals_number = scope_info.NumberOfLocals();
1532 for (int i = 0; i < locals_number; ++i) {
1533 String* local_name = *scope_info.LocalName(i);
1534 int idx = ScopeInfo<>::ContextSlotIndex(
1535 context->closure()->shared()->code(), local_name, NULL);
1536 if (idx >= 0 && idx < context->length()) {
1537 snapshot_->SetClosureReference(entry, local_name, context->get(idx));
1538 }
1539 }
1540 }
1541 }
1542
1543
1544 void HeapSnapshotGenerator::ExtractPropertyReferences(JSObject* js_obj,
1545 HeapEntry* entry) {
1546 if (js_obj->HasFastProperties()) {
1547 DescriptorArray* descs = js_obj->map()->instance_descriptors();
1548 for (int i = 0; i < descs->number_of_descriptors(); i++) {
1549 switch (descs->GetType(i)) {
1550 case FIELD: {
1551 int index = descs->GetFieldIndex(i);
1552 snapshot_->SetPropertyReference(
1553 entry, descs->GetKey(i), js_obj->FastPropertyAt(index));
1554 break;
1555 }
1556 case CONSTANT_FUNCTION:
1557 snapshot_->SetPropertyReference(
1558 entry, descs->GetKey(i), descs->GetConstantFunction(i));
1559 break;
1560 default: ;
1561 }
1562 }
1563 } else {
1564 StringDictionary* dictionary = js_obj->property_dictionary();
1565 int length = dictionary->Capacity();
1566 for (int i = 0; i < length; ++i) {
1567 Object* k = dictionary->KeyAt(i);
1568 if (dictionary->IsKey(k)) {
1569 snapshot_->SetPropertyReference(
1570 entry, String::cast(k), dictionary->ValueAt(i));
1571 }
1572 }
1573 }
1574 }
1575
1576
1577 void HeapSnapshotGenerator::ExtractElementReferences(JSObject* js_obj,
1578 HeapEntry* entry) {
1579 if (js_obj->HasFastElements()) {
1580 FixedArray* elements = FixedArray::cast(js_obj->elements());
1581 int length = js_obj->IsJSArray() ?
1582 Smi::cast(JSArray::cast(js_obj)->length())->value() :
1583 elements->length();
1584 for (int i = 0; i < length; ++i) {
1585 if (!elements->get(i)->IsTheHole()) {
1586 snapshot_->SetElementReference(entry, i, elements->get(i));
1587 }
1588 }
1589 } else if (js_obj->HasDictionaryElements()) {
1590 NumberDictionary* dictionary = js_obj->element_dictionary();
1591 int length = dictionary->Capacity();
1592 for (int i = 0; i < length; ++i) {
1593 Object* k = dictionary->KeyAt(i);
1594 if (dictionary->IsKey(k)) {
1595 ASSERT(k->IsNumber());
1596 uint32_t index = static_cast<uint32_t>(k->Number());
1597 snapshot_->SetElementReference(entry, index, dictionary->ValueAt(i));
1598 }
1599 }
1600 }
1601 }
1602
814 } } // namespace v8::internal 1603 } } // namespace v8::internal
815 1604
816 #endif // ENABLE_LOGGING_AND_PROFILING 1605 #endif // ENABLE_LOGGING_AND_PROFILING
OLDNEW
« no previous file with comments | « src/profile-generator.h ('k') | src/profile-generator-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698