| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 16 matching lines...) Expand all Loading... |
| 27 | 27 |
| 28 #include "v8.h" | 28 #include "v8.h" |
| 29 | 29 |
| 30 #include "heap-snapshot-generator-inl.h" | 30 #include "heap-snapshot-generator-inl.h" |
| 31 | 31 |
| 32 #include "allocation-tracker.h" | 32 #include "allocation-tracker.h" |
| 33 #include "code-stubs.h" | 33 #include "code-stubs.h" |
| 34 #include "heap-profiler.h" | 34 #include "heap-profiler.h" |
| 35 #include "debug.h" | 35 #include "debug.h" |
| 36 #include "types.h" | 36 #include "types.h" |
| 37 #include "v8conversions.h" |
| 37 | 38 |
| 38 namespace v8 { | 39 namespace v8 { |
| 39 namespace internal { | 40 namespace internal { |
| 40 | 41 |
| 41 | 42 |
| 42 HeapGraphEdge::HeapGraphEdge(Type type, const char* name, int from, int to) | 43 HeapGraphEdge::HeapGraphEdge(Type type, const char* name, int from, int to) |
| 43 : type_(type), | 44 : type_(type), |
| 44 from_index_(from), | 45 from_index_(from), |
| 45 to_index_(to), | 46 to_index_(to), |
| 46 name_(name) { | 47 name_(name) { |
| 47 ASSERT(type == kContextVariable | 48 ASSERT(type == kContextVariable |
| 48 || type == kProperty | 49 || type == kProperty |
| 49 || type == kInternal | 50 || type == kInternal |
| 50 || type == kShortcut); | 51 || type == kShortcut |
| 52 || type == kWeak); |
| 51 } | 53 } |
| 52 | 54 |
| 53 | 55 |
| 54 HeapGraphEdge::HeapGraphEdge(Type type, int index, int from, int to) | 56 HeapGraphEdge::HeapGraphEdge(Type type, int index, int from, int to) |
| 55 : type_(type), | 57 : type_(type), |
| 56 from_index_(from), | 58 from_index_(from), |
| 57 to_index_(to), | 59 to_index_(to), |
| 58 index_(index) { | 60 index_(index) { |
| 59 ASSERT(type == kElement || type == kHidden || type == kWeak); | 61 ASSERT(type == kElement || type == kHidden); |
| 60 } | 62 } |
| 61 | 63 |
| 62 | 64 |
| 63 void HeapGraphEdge::ReplaceToIndexWithEntry(HeapSnapshot* snapshot) { | 65 void HeapGraphEdge::ReplaceToIndexWithEntry(HeapSnapshot* snapshot) { |
| 64 to_entry_ = &snapshot->entries()[to_index_]; | 66 to_entry_ = &snapshot->entries()[to_index_]; |
| 65 } | 67 } |
| 66 | 68 |
| 67 | 69 |
| 68 const int HeapEntry::kNoEntry = -1; | 70 const int HeapEntry::kNoEntry = -1; |
| 69 | 71 |
| 70 HeapEntry::HeapEntry(HeapSnapshot* snapshot, | 72 HeapEntry::HeapEntry(HeapSnapshot* snapshot, |
| 71 Type type, | 73 Type type, |
| 72 const char* name, | 74 const char* name, |
| 73 SnapshotObjectId id, | 75 SnapshotObjectId id, |
| 74 int self_size) | 76 size_t self_size) |
| 75 : type_(type), | 77 : type_(type), |
| 76 children_count_(0), | 78 children_count_(0), |
| 77 children_index_(-1), | 79 children_index_(-1), |
| 78 self_size_(self_size), | 80 self_size_(self_size), |
| 79 id_(id), | 81 id_(id), |
| 80 snapshot_(snapshot), | 82 snapshot_(snapshot), |
| 81 name_(name) { } | 83 name_(name) { } |
| 82 | 84 |
| 83 | 85 |
| 84 void HeapEntry::SetNamedReference(HeapGraphEdge::Type type, | 86 void HeapEntry::SetNamedReference(HeapGraphEdge::Type type, |
| (...skipping 10 matching lines...) Expand all Loading... |
| 95 HeapEntry* entry) { | 97 HeapEntry* entry) { |
| 96 HeapGraphEdge edge(type, index, this->index(), entry->index()); | 98 HeapGraphEdge edge(type, index, this->index(), entry->index()); |
| 97 snapshot_->edges().Add(edge); | 99 snapshot_->edges().Add(edge); |
| 98 ++children_count_; | 100 ++children_count_; |
| 99 } | 101 } |
| 100 | 102 |
| 101 | 103 |
| 102 void HeapEntry::Print( | 104 void HeapEntry::Print( |
| 103 const char* prefix, const char* edge_name, int max_depth, int indent) { | 105 const char* prefix, const char* edge_name, int max_depth, int indent) { |
| 104 STATIC_CHECK(sizeof(unsigned) == sizeof(id())); | 106 STATIC_CHECK(sizeof(unsigned) == sizeof(id())); |
| 105 OS::Print("%6d @%6u %*c %s%s: ", | 107 OS::Print("%6" V8PRIuPTR " @%6u %*c %s%s: ", |
| 106 self_size(), id(), indent, ' ', prefix, edge_name); | 108 self_size(), id(), indent, ' ', prefix, edge_name); |
| 107 if (type() != kString) { | 109 if (type() != kString) { |
| 108 OS::Print("%s %.40s\n", TypeAsString(), name_); | 110 OS::Print("%s %.40s\n", TypeAsString(), name_); |
| 109 } else { | 111 } else { |
| 110 OS::Print("\""); | 112 OS::Print("\""); |
| 111 const char* c = name_; | 113 const char* c = name_; |
| 112 while (*c && (c - name_) <= 40) { | 114 while (*c && (c - name_) <= 40) { |
| 113 if (*c != '\n') | 115 if (*c != '\n') |
| 114 OS::Print("%c", *c); | 116 OS::Print("%c", *c); |
| 115 else | 117 else |
| (...skipping 27 matching lines...) Expand all Loading... |
| 143 case HeapGraphEdge::kHidden: | 145 case HeapGraphEdge::kHidden: |
| 144 edge_prefix = "$"; | 146 edge_prefix = "$"; |
| 145 OS::SNPrintF(index, "%d", edge.index()); | 147 OS::SNPrintF(index, "%d", edge.index()); |
| 146 break; | 148 break; |
| 147 case HeapGraphEdge::kShortcut: | 149 case HeapGraphEdge::kShortcut: |
| 148 edge_prefix = "^"; | 150 edge_prefix = "^"; |
| 149 edge_name = edge.name(); | 151 edge_name = edge.name(); |
| 150 break; | 152 break; |
| 151 case HeapGraphEdge::kWeak: | 153 case HeapGraphEdge::kWeak: |
| 152 edge_prefix = "w"; | 154 edge_prefix = "w"; |
| 153 OS::SNPrintF(index, "%d", edge.index()); | 155 edge_name = edge.name(); |
| 154 break; | 156 break; |
| 155 default: | 157 default: |
| 156 OS::SNPrintF(index, "!!! unknown edge type: %d ", edge.type()); | 158 OS::SNPrintF(index, "!!! unknown edge type: %d ", edge.type()); |
| 157 } | 159 } |
| 158 edge.to()->Print(edge_prefix, edge_name, max_depth, indent + 2); | 160 edge.to()->Print(edge_prefix, edge_name, max_depth, indent + 2); |
| 159 } | 161 } |
| 160 } | 162 } |
| 161 | 163 |
| 162 | 164 |
| 163 const char* HeapEntry::TypeAsString() { | 165 const char* HeapEntry::TypeAsString() { |
| (...skipping 21 matching lines...) Expand all Loading... |
| 185 | 187 |
| 186 template <size_t ptr_size> struct SnapshotSizeConstants; | 188 template <size_t ptr_size> struct SnapshotSizeConstants; |
| 187 | 189 |
| 188 template <> struct SnapshotSizeConstants<4> { | 190 template <> struct SnapshotSizeConstants<4> { |
| 189 static const int kExpectedHeapGraphEdgeSize = 12; | 191 static const int kExpectedHeapGraphEdgeSize = 12; |
| 190 static const int kExpectedHeapEntrySize = 24; | 192 static const int kExpectedHeapEntrySize = 24; |
| 191 }; | 193 }; |
| 192 | 194 |
| 193 template <> struct SnapshotSizeConstants<8> { | 195 template <> struct SnapshotSizeConstants<8> { |
| 194 static const int kExpectedHeapGraphEdgeSize = 24; | 196 static const int kExpectedHeapGraphEdgeSize = 24; |
| 195 static const int kExpectedHeapEntrySize = 32; | 197 static const int kExpectedHeapEntrySize = 40; |
| 196 }; | 198 }; |
| 197 | 199 |
| 198 } // namespace | 200 } // namespace |
| 199 | 201 |
| 200 | 202 |
| 201 HeapSnapshot::HeapSnapshot(HeapProfiler* profiler, | 203 HeapSnapshot::HeapSnapshot(HeapProfiler* profiler, |
| 202 const char* title, | 204 const char* title, |
| 203 unsigned uid) | 205 unsigned uid) |
| 204 : profiler_(profiler), | 206 : profiler_(profiler), |
| 205 title_(title), | 207 title_(title), |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 268 HeapObjectsMap::GetNthGcSubrootId(tag), | 270 HeapObjectsMap::GetNthGcSubrootId(tag), |
| 269 0); | 271 0); |
| 270 gc_subroot_indexes_[tag] = entry->index(); | 272 gc_subroot_indexes_[tag] = entry->index(); |
| 271 return entry; | 273 return entry; |
| 272 } | 274 } |
| 273 | 275 |
| 274 | 276 |
| 275 HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type, | 277 HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type, |
| 276 const char* name, | 278 const char* name, |
| 277 SnapshotObjectId id, | 279 SnapshotObjectId id, |
| 278 int size) { | 280 size_t size) { |
| 279 HeapEntry entry(this, type, name, id, size); | 281 HeapEntry entry(this, type, name, id, size); |
| 280 entries_.Add(entry); | 282 entries_.Add(entry); |
| 281 return &entries_.last(); | 283 return &entries_.last(); |
| 282 } | 284 } |
| 283 | 285 |
| 284 | 286 |
| 285 void HeapSnapshot::FillChildren() { | 287 void HeapSnapshot::FillChildren() { |
| 286 ASSERT(children().is_empty()); | 288 ASSERT(children().is_empty()); |
| 287 children().Allocate(edges().length()); | 289 children().Allocate(edges().length()); |
| 288 int children_index = 0; | 290 int children_index = 0; |
| (...skipping 602 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 891 } else if (object->IsHeapNumber()) { | 893 } else if (object->IsHeapNumber()) { |
| 892 return AddEntry(object, HeapEntry::kHeapNumber, "number"); | 894 return AddEntry(object, HeapEntry::kHeapNumber, "number"); |
| 893 } | 895 } |
| 894 return AddEntry(object, HeapEntry::kHidden, GetSystemEntryName(object)); | 896 return AddEntry(object, HeapEntry::kHidden, GetSystemEntryName(object)); |
| 895 } | 897 } |
| 896 | 898 |
| 897 | 899 |
| 898 HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, | 900 HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, |
| 899 HeapEntry::Type type, | 901 HeapEntry::Type type, |
| 900 const char* name) { | 902 const char* name) { |
| 901 int object_size = object->Size(); | 903 return AddEntry(object->address(), type, name, object->Size()); |
| 902 SnapshotObjectId object_id = | |
| 903 heap_object_map_->FindOrAddEntry(object->address(), object_size); | |
| 904 return snapshot_->AddEntry(type, name, object_id, object_size); | |
| 905 } | 904 } |
| 906 | 905 |
| 907 | 906 |
| 907 HeapEntry* V8HeapExplorer::AddEntry(Address address, |
| 908 HeapEntry::Type type, |
| 909 const char* name, |
| 910 size_t size) { |
| 911 SnapshotObjectId object_id = heap_object_map_->FindOrAddEntry( |
| 912 address, static_cast<unsigned int>(size)); |
| 913 return snapshot_->AddEntry(type, name, object_id, size); |
| 914 } |
| 915 |
| 916 |
| 908 class GcSubrootsEnumerator : public ObjectVisitor { | 917 class GcSubrootsEnumerator : public ObjectVisitor { |
| 909 public: | 918 public: |
| 910 GcSubrootsEnumerator( | 919 GcSubrootsEnumerator( |
| 911 SnapshotFillerInterface* filler, V8HeapExplorer* explorer) | 920 SnapshotFillerInterface* filler, V8HeapExplorer* explorer) |
| 912 : filler_(filler), | 921 : filler_(filler), |
| 913 explorer_(explorer), | 922 explorer_(explorer), |
| 914 previous_object_count_(0), | 923 previous_object_count_(0), |
| 915 object_count_(0) { | 924 object_count_(0) { |
| 916 } | 925 } |
| 917 void VisitPointers(Object** start, Object** end) { | 926 void VisitPointers(Object** start, Object** end) { |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 984 parent_(parent), | 993 parent_(parent), |
| 985 next_index_(0) { | 994 next_index_(0) { |
| 986 } | 995 } |
| 987 void VisitCodeEntry(Address entry_address) { | 996 void VisitCodeEntry(Address entry_address) { |
| 988 Code* code = Code::cast(Code::GetObjectFromEntryAddress(entry_address)); | 997 Code* code = Code::cast(Code::GetObjectFromEntryAddress(entry_address)); |
| 989 generator_->SetInternalReference(parent_obj_, parent_, "code", code); | 998 generator_->SetInternalReference(parent_obj_, parent_, "code", code); |
| 990 generator_->TagCodeObject(code); | 999 generator_->TagCodeObject(code); |
| 991 } | 1000 } |
| 992 void VisitPointers(Object** start, Object** end) { | 1001 void VisitPointers(Object** start, Object** end) { |
| 993 for (Object** p = start; p < end; p++) { | 1002 for (Object** p = start; p < end; p++) { |
| 1003 ++next_index_; |
| 994 if (CheckVisitedAndUnmark(p)) continue; | 1004 if (CheckVisitedAndUnmark(p)) continue; |
| 995 generator_->SetHiddenReference(parent_obj_, parent_, next_index_++, *p); | 1005 generator_->SetHiddenReference(parent_obj_, parent_, next_index_, *p); |
| 996 } | 1006 } |
| 997 } | 1007 } |
| 998 static void MarkVisitedField(HeapObject* obj, int offset) { | 1008 static void MarkVisitedField(HeapObject* obj, int offset) { |
| 999 if (offset < 0) return; | 1009 if (offset < 0) return; |
| 1000 Address field = obj->address() + offset; | 1010 Address field = obj->address() + offset; |
| 1001 ASSERT(!Memory::Object_at(field)->IsFailure()); | 1011 ASSERT(!Memory::Object_at(field)->IsFailure()); |
| 1002 ASSERT(Memory::Object_at(field)->IsHeapObject()); | 1012 ASSERT(Memory::Object_at(field)->IsHeapObject()); |
| 1003 *field |= kFailureTag; | 1013 *field |= kFailureTag; |
| 1004 } | 1014 } |
| 1005 | 1015 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1020 }; | 1030 }; |
| 1021 | 1031 |
| 1022 | 1032 |
| 1023 void V8HeapExplorer::ExtractReferences(HeapObject* obj) { | 1033 void V8HeapExplorer::ExtractReferences(HeapObject* obj) { |
| 1024 HeapEntry* heap_entry = GetEntry(obj); | 1034 HeapEntry* heap_entry = GetEntry(obj); |
| 1025 if (heap_entry == NULL) return; // No interest in this object. | 1035 if (heap_entry == NULL) return; // No interest in this object. |
| 1026 int entry = heap_entry->index(); | 1036 int entry = heap_entry->index(); |
| 1027 | 1037 |
| 1028 if (obj->IsJSGlobalProxy()) { | 1038 if (obj->IsJSGlobalProxy()) { |
| 1029 ExtractJSGlobalProxyReferences(entry, JSGlobalProxy::cast(obj)); | 1039 ExtractJSGlobalProxyReferences(entry, JSGlobalProxy::cast(obj)); |
| 1040 } else if (obj->IsJSArrayBuffer()) { |
| 1041 ExtractJSArrayBufferReferences(entry, JSArrayBuffer::cast(obj)); |
| 1030 } else if (obj->IsJSObject()) { | 1042 } else if (obj->IsJSObject()) { |
| 1031 ExtractJSObjectReferences(entry, JSObject::cast(obj)); | 1043 ExtractJSObjectReferences(entry, JSObject::cast(obj)); |
| 1032 } else if (obj->IsString()) { | 1044 } else if (obj->IsString()) { |
| 1033 ExtractStringReferences(entry, String::cast(obj)); | 1045 ExtractStringReferences(entry, String::cast(obj)); |
| 1034 } else if (obj->IsContext()) { | 1046 } else if (obj->IsContext()) { |
| 1035 ExtractContextReferences(entry, Context::cast(obj)); | 1047 ExtractContextReferences(entry, Context::cast(obj)); |
| 1036 } else if (obj->IsMap()) { | 1048 } else if (obj->IsMap()) { |
| 1037 ExtractMapReferences(entry, Map::cast(obj)); | 1049 ExtractMapReferences(entry, Map::cast(obj)); |
| 1038 } else if (obj->IsSharedFunctionInfo()) { | 1050 } else if (obj->IsSharedFunctionInfo()) { |
| 1039 ExtractSharedFunctionInfoReferences(entry, SharedFunctionInfo::cast(obj)); | 1051 ExtractSharedFunctionInfoReferences(entry, SharedFunctionInfo::cast(obj)); |
| 1040 } else if (obj->IsScript()) { | 1052 } else if (obj->IsScript()) { |
| 1041 ExtractScriptReferences(entry, Script::cast(obj)); | 1053 ExtractScriptReferences(entry, Script::cast(obj)); |
| 1042 } else if (obj->IsAccessorPair()) { | 1054 } else if (obj->IsAccessorPair()) { |
| 1043 ExtractAccessorPairReferences(entry, AccessorPair::cast(obj)); | 1055 ExtractAccessorPairReferences(entry, AccessorPair::cast(obj)); |
| 1044 } else if (obj->IsCodeCache()) { | 1056 } else if (obj->IsCodeCache()) { |
| 1045 ExtractCodeCacheReferences(entry, CodeCache::cast(obj)); | 1057 ExtractCodeCacheReferences(entry, CodeCache::cast(obj)); |
| 1046 } else if (obj->IsCode()) { | 1058 } else if (obj->IsCode()) { |
| 1047 ExtractCodeReferences(entry, Code::cast(obj)); | 1059 ExtractCodeReferences(entry, Code::cast(obj)); |
| 1060 } else if (obj->IsBox()) { |
| 1061 ExtractBoxReferences(entry, Box::cast(obj)); |
| 1048 } else if (obj->IsCell()) { | 1062 } else if (obj->IsCell()) { |
| 1049 ExtractCellReferences(entry, Cell::cast(obj)); | 1063 ExtractCellReferences(entry, Cell::cast(obj)); |
| 1050 } else if (obj->IsPropertyCell()) { | 1064 } else if (obj->IsPropertyCell()) { |
| 1051 ExtractPropertyCellReferences(entry, PropertyCell::cast(obj)); | 1065 ExtractPropertyCellReferences(entry, PropertyCell::cast(obj)); |
| 1052 } else if (obj->IsAllocationSite()) { | 1066 } else if (obj->IsAllocationSite()) { |
| 1053 ExtractAllocationSiteReferences(entry, AllocationSite::cast(obj)); | 1067 ExtractAllocationSiteReferences(entry, AllocationSite::cast(obj)); |
| 1054 } | 1068 } |
| 1055 SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset); | 1069 SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset); |
| 1056 | 1070 |
| 1057 // Extract unvisited fields as hidden references and restore tags | 1071 // Extract unvisited fields as hidden references and restore tags |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1107 js_fun->literals_or_bindings(), | 1121 js_fun->literals_or_bindings(), |
| 1108 JSFunction::kLiteralsOffset); | 1122 JSFunction::kLiteralsOffset); |
| 1109 TagObject(shared_info, "(shared function info)"); | 1123 TagObject(shared_info, "(shared function info)"); |
| 1110 SetInternalReference(js_fun, entry, | 1124 SetInternalReference(js_fun, entry, |
| 1111 "shared", shared_info, | 1125 "shared", shared_info, |
| 1112 JSFunction::kSharedFunctionInfoOffset); | 1126 JSFunction::kSharedFunctionInfoOffset); |
| 1113 TagObject(js_fun->context(), "(context)"); | 1127 TagObject(js_fun->context(), "(context)"); |
| 1114 SetInternalReference(js_fun, entry, | 1128 SetInternalReference(js_fun, entry, |
| 1115 "context", js_fun->context(), | 1129 "context", js_fun->context(), |
| 1116 JSFunction::kContextOffset); | 1130 JSFunction::kContextOffset); |
| 1117 for (int i = JSFunction::kNonWeakFieldsEndOffset; | 1131 SetWeakReference(js_fun, entry, |
| 1118 i < JSFunction::kSize; | 1132 "next_function_link", js_fun->next_function_link(), |
| 1119 i += kPointerSize) { | 1133 JSFunction::kNextFunctionLinkOffset); |
| 1120 SetWeakReference(js_fun, entry, i, *HeapObject::RawField(js_fun, i), i); | 1134 STATIC_CHECK(JSFunction::kNextFunctionLinkOffset |
| 1121 } | 1135 == JSFunction::kNonWeakFieldsEndOffset); |
| 1136 STATIC_CHECK(JSFunction::kNextFunctionLinkOffset + kPointerSize |
| 1137 == JSFunction::kSize); |
| 1122 } else if (obj->IsGlobalObject()) { | 1138 } else if (obj->IsGlobalObject()) { |
| 1123 GlobalObject* global_obj = GlobalObject::cast(obj); | 1139 GlobalObject* global_obj = GlobalObject::cast(obj); |
| 1124 SetInternalReference(global_obj, entry, | 1140 SetInternalReference(global_obj, entry, |
| 1125 "builtins", global_obj->builtins(), | 1141 "builtins", global_obj->builtins(), |
| 1126 GlobalObject::kBuiltinsOffset); | 1142 GlobalObject::kBuiltinsOffset); |
| 1127 SetInternalReference(global_obj, entry, | 1143 SetInternalReference(global_obj, entry, |
| 1128 "native_context", global_obj->native_context(), | 1144 "native_context", global_obj->native_context(), |
| 1129 GlobalObject::kNativeContextOffset); | 1145 GlobalObject::kNativeContextOffset); |
| 1130 SetInternalReference(global_obj, entry, | 1146 SetInternalReference(global_obj, entry, |
| 1147 "global_context", global_obj->global_context(), |
| 1148 GlobalObject::kGlobalContextOffset); |
| 1149 SetInternalReference(global_obj, entry, |
| 1131 "global_receiver", global_obj->global_receiver(), | 1150 "global_receiver", global_obj->global_receiver(), |
| 1132 GlobalObject::kGlobalReceiverOffset); | 1151 GlobalObject::kGlobalReceiverOffset); |
| 1152 STATIC_CHECK(GlobalObject::kHeaderSize - JSObject::kHeaderSize == |
| 1153 4 * kPointerSize); |
| 1154 } else if (obj->IsJSArrayBufferView()) { |
| 1155 JSArrayBufferView* view = JSArrayBufferView::cast(obj); |
| 1156 SetInternalReference(view, entry, "buffer", view->buffer(), |
| 1157 JSArrayBufferView::kBufferOffset); |
| 1158 SetWeakReference(view, entry, "weak_next", view->weak_next(), |
| 1159 JSArrayBufferView::kWeakNextOffset); |
| 1133 } | 1160 } |
| 1134 TagObject(js_obj->properties(), "(object properties)"); | 1161 TagObject(js_obj->properties(), "(object properties)"); |
| 1135 SetInternalReference(obj, entry, | 1162 SetInternalReference(obj, entry, |
| 1136 "properties", js_obj->properties(), | 1163 "properties", js_obj->properties(), |
| 1137 JSObject::kPropertiesOffset); | 1164 JSObject::kPropertiesOffset); |
| 1138 TagObject(js_obj->elements(), "(object elements)"); | 1165 TagObject(js_obj->elements(), "(object elements)"); |
| 1139 SetInternalReference(obj, entry, | 1166 SetInternalReference(obj, entry, |
| 1140 "elements", js_obj->elements(), | 1167 "elements", js_obj->elements(), |
| 1141 JSObject::kElementsOffset); | 1168 JSObject::kElementsOffset); |
| 1142 } | 1169 } |
| (...skipping 30 matching lines...) Expand all Loading... |
| 1173 VariableMode mode; | 1200 VariableMode mode; |
| 1174 int idx = scope_info->FunctionContextSlotIndex(name, &mode); | 1201 int idx = scope_info->FunctionContextSlotIndex(name, &mode); |
| 1175 if (idx >= 0) { | 1202 if (idx >= 0) { |
| 1176 SetContextReference(context, entry, name, context->get(idx), | 1203 SetContextReference(context, entry, name, context->get(idx), |
| 1177 Context::OffsetOfElementAt(idx)); | 1204 Context::OffsetOfElementAt(idx)); |
| 1178 } | 1205 } |
| 1179 } | 1206 } |
| 1180 } | 1207 } |
| 1181 | 1208 |
| 1182 #define EXTRACT_CONTEXT_FIELD(index, type, name) \ | 1209 #define EXTRACT_CONTEXT_FIELD(index, type, name) \ |
| 1183 SetInternalReference(context, entry, #name, context->get(Context::index), \ | 1210 if (Context::index < Context::FIRST_WEAK_SLOT) { \ |
| 1184 FixedArray::OffsetOfElementAt(Context::index)); | 1211 SetInternalReference(context, entry, #name, context->get(Context::index), \ |
| 1212 FixedArray::OffsetOfElementAt(Context::index)); \ |
| 1213 } else { \ |
| 1214 SetWeakReference(context, entry, #name, context->get(Context::index), \ |
| 1215 FixedArray::OffsetOfElementAt(Context::index)); \ |
| 1216 } |
| 1185 EXTRACT_CONTEXT_FIELD(CLOSURE_INDEX, JSFunction, closure); | 1217 EXTRACT_CONTEXT_FIELD(CLOSURE_INDEX, JSFunction, closure); |
| 1186 EXTRACT_CONTEXT_FIELD(PREVIOUS_INDEX, Context, previous); | 1218 EXTRACT_CONTEXT_FIELD(PREVIOUS_INDEX, Context, previous); |
| 1187 EXTRACT_CONTEXT_FIELD(EXTENSION_INDEX, Object, extension); | 1219 EXTRACT_CONTEXT_FIELD(EXTENSION_INDEX, Object, extension); |
| 1188 EXTRACT_CONTEXT_FIELD(GLOBAL_OBJECT_INDEX, GlobalObject, global); | 1220 EXTRACT_CONTEXT_FIELD(GLOBAL_OBJECT_INDEX, GlobalObject, global); |
| 1189 if (context->IsNativeContext()) { | 1221 if (context->IsNativeContext()) { |
| 1190 TagObject(context->jsfunction_result_caches(), | 1222 TagObject(context->jsfunction_result_caches(), |
| 1191 "(context func. result caches)"); | 1223 "(context func. result caches)"); |
| 1192 TagObject(context->normalized_map_cache(), "(context norm. map cache)"); | 1224 TagObject(context->normalized_map_cache(), "(context norm. map cache)"); |
| 1193 TagObject(context->runtime_context(), "(runtime context)"); | 1225 TagObject(context->runtime_context(), "(runtime context)"); |
| 1194 TagObject(context->embedder_data(), "(context data)"); | 1226 TagObject(context->embedder_data(), "(context data)"); |
| 1195 NATIVE_CONTEXT_FIELDS(EXTRACT_CONTEXT_FIELD); | 1227 NATIVE_CONTEXT_FIELDS(EXTRACT_CONTEXT_FIELD); |
| 1228 EXTRACT_CONTEXT_FIELD(OPTIMIZED_FUNCTIONS_LIST, unused, |
| 1229 optimized_functions_list); |
| 1230 EXTRACT_CONTEXT_FIELD(OPTIMIZED_CODE_LIST, unused, optimized_code_list); |
| 1231 EXTRACT_CONTEXT_FIELD(DEOPTIMIZED_CODE_LIST, unused, deoptimized_code_list); |
| 1232 EXTRACT_CONTEXT_FIELD(NEXT_CONTEXT_LINK, unused, next_context_link); |
| 1196 #undef EXTRACT_CONTEXT_FIELD | 1233 #undef EXTRACT_CONTEXT_FIELD |
| 1197 for (int i = Context::FIRST_WEAK_SLOT; | 1234 STATIC_CHECK(Context::OPTIMIZED_FUNCTIONS_LIST == Context::FIRST_WEAK_SLOT); |
| 1198 i < Context::NATIVE_CONTEXT_SLOTS; | 1235 STATIC_CHECK(Context::NEXT_CONTEXT_LINK + 1 |
| 1199 ++i) { | 1236 == Context::NATIVE_CONTEXT_SLOTS); |
| 1200 SetWeakReference(context, entry, i, context->get(i), | 1237 STATIC_CHECK(Context::FIRST_WEAK_SLOT + 5 == Context::NATIVE_CONTEXT_SLOTS); |
| 1201 FixedArray::OffsetOfElementAt(i)); | |
| 1202 } | |
| 1203 } | 1238 } |
| 1204 } | 1239 } |
| 1205 | 1240 |
| 1206 | 1241 |
| 1207 void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) { | 1242 void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) { |
| 1208 if (map->HasTransitionArray()) { | 1243 if (map->HasTransitionArray()) { |
| 1209 TransitionArray* transitions = map->transitions(); | 1244 TransitionArray* transitions = map->transitions(); |
| 1210 int transitions_entry = GetEntry(transitions)->index(); | 1245 int transitions_entry = GetEntry(transitions)->index(); |
| 1211 Object* back_pointer = transitions->back_pointer_storage(); | 1246 Object* back_pointer = transitions->back_pointer_storage(); |
| 1212 TagObject(back_pointer, "(back pointer)"); | 1247 TagObject(back_pointer, "(back pointer)"); |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1286 SetInternalReference(obj, entry, | 1321 SetInternalReference(obj, entry, |
| 1287 "debug_info", shared->debug_info(), | 1322 "debug_info", shared->debug_info(), |
| 1288 SharedFunctionInfo::kDebugInfoOffset); | 1323 SharedFunctionInfo::kDebugInfoOffset); |
| 1289 SetInternalReference(obj, entry, | 1324 SetInternalReference(obj, entry, |
| 1290 "inferred_name", shared->inferred_name(), | 1325 "inferred_name", shared->inferred_name(), |
| 1291 SharedFunctionInfo::kInferredNameOffset); | 1326 SharedFunctionInfo::kInferredNameOffset); |
| 1292 SetInternalReference(obj, entry, | 1327 SetInternalReference(obj, entry, |
| 1293 "optimized_code_map", shared->optimized_code_map(), | 1328 "optimized_code_map", shared->optimized_code_map(), |
| 1294 SharedFunctionInfo::kOptimizedCodeMapOffset); | 1329 SharedFunctionInfo::kOptimizedCodeMapOffset); |
| 1295 SetWeakReference(obj, entry, | 1330 SetWeakReference(obj, entry, |
| 1296 1, shared->initial_map(), | 1331 "initial_map", shared->initial_map(), |
| 1297 SharedFunctionInfo::kInitialMapOffset); | 1332 SharedFunctionInfo::kInitialMapOffset); |
| 1298 } | 1333 } |
| 1299 | 1334 |
| 1300 | 1335 |
| 1301 void V8HeapExplorer::ExtractScriptReferences(int entry, Script* script) { | 1336 void V8HeapExplorer::ExtractScriptReferences(int entry, Script* script) { |
| 1302 HeapObject* obj = script; | 1337 HeapObject* obj = script; |
| 1303 SetInternalReference(obj, entry, | 1338 SetInternalReference(obj, entry, |
| 1304 "source", script->source(), | 1339 "source", script->source(), |
| 1305 Script::kSourceOffset); | 1340 Script::kSourceOffset); |
| 1306 SetInternalReference(obj, entry, | 1341 SetInternalReference(obj, entry, |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1334 SetInternalReference(code_cache, entry, | 1369 SetInternalReference(code_cache, entry, |
| 1335 "default_cache", code_cache->default_cache(), | 1370 "default_cache", code_cache->default_cache(), |
| 1336 CodeCache::kDefaultCacheOffset); | 1371 CodeCache::kDefaultCacheOffset); |
| 1337 TagObject(code_cache->normal_type_cache(), "(code type cache)"); | 1372 TagObject(code_cache->normal_type_cache(), "(code type cache)"); |
| 1338 SetInternalReference(code_cache, entry, | 1373 SetInternalReference(code_cache, entry, |
| 1339 "type_cache", code_cache->normal_type_cache(), | 1374 "type_cache", code_cache->normal_type_cache(), |
| 1340 CodeCache::kNormalTypeCacheOffset); | 1375 CodeCache::kNormalTypeCacheOffset); |
| 1341 } | 1376 } |
| 1342 | 1377 |
| 1343 | 1378 |
| 1344 void V8HeapExplorer::TagCodeObject(Code* code, const char* external_name) { | 1379 void V8HeapExplorer::TagBuiltinCodeObject(Code* code, const char* name) { |
| 1345 TagObject(code, names_->GetFormatted("(%s code)", external_name)); | 1380 TagObject(code, names_->GetFormatted("(%s builtin)", name)); |
| 1346 } | 1381 } |
| 1347 | 1382 |
| 1348 | 1383 |
| 1349 void V8HeapExplorer::TagCodeObject(Code* code) { | 1384 void V8HeapExplorer::TagCodeObject(Code* code) { |
| 1350 if (code->kind() == Code::STUB) { | 1385 if (code->kind() == Code::STUB) { |
| 1351 TagObject(code, names_->GetFormatted( | 1386 TagObject(code, names_->GetFormatted( |
| 1352 "(%s code)", CodeStub::MajorName( | 1387 "(%s code)", CodeStub::MajorName( |
| 1353 static_cast<CodeStub::Major>(code->major_key()), true))); | 1388 static_cast<CodeStub::Major>(code->major_key()), true))); |
| 1354 } | 1389 } |
| 1355 } | 1390 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1372 SetInternalReference(code, entry, | 1407 SetInternalReference(code, entry, |
| 1373 "type_feedback_info", code->type_feedback_info(), | 1408 "type_feedback_info", code->type_feedback_info(), |
| 1374 Code::kTypeFeedbackInfoOffset); | 1409 Code::kTypeFeedbackInfoOffset); |
| 1375 } | 1410 } |
| 1376 SetInternalReference(code, entry, | 1411 SetInternalReference(code, entry, |
| 1377 "gc_metadata", code->gc_metadata(), | 1412 "gc_metadata", code->gc_metadata(), |
| 1378 Code::kGCMetadataOffset); | 1413 Code::kGCMetadataOffset); |
| 1379 SetInternalReference(code, entry, | 1414 SetInternalReference(code, entry, |
| 1380 "constant_pool", code->constant_pool(), | 1415 "constant_pool", code->constant_pool(), |
| 1381 Code::kConstantPoolOffset); | 1416 Code::kConstantPoolOffset); |
| 1417 if (code->kind() == Code::OPTIMIZED_FUNCTION) { |
| 1418 SetWeakReference(code, entry, |
| 1419 "next_code_link", code->next_code_link(), |
| 1420 Code::kNextCodeLinkOffset); |
| 1421 } |
| 1382 } | 1422 } |
| 1383 | 1423 |
| 1384 | 1424 |
| 1425 void V8HeapExplorer::ExtractBoxReferences(int entry, Box* box) { |
| 1426 SetInternalReference(box, entry, "value", box->value(), Box::kValueOffset); |
| 1427 } |
| 1428 |
| 1429 |
| 1385 void V8HeapExplorer::ExtractCellReferences(int entry, Cell* cell) { | 1430 void V8HeapExplorer::ExtractCellReferences(int entry, Cell* cell) { |
| 1386 SetInternalReference(cell, entry, "value", cell->value(), Cell::kValueOffset); | 1431 SetInternalReference(cell, entry, "value", cell->value(), Cell::kValueOffset); |
| 1387 } | 1432 } |
| 1388 | 1433 |
| 1389 | 1434 |
| 1390 void V8HeapExplorer::ExtractPropertyCellReferences(int entry, | 1435 void V8HeapExplorer::ExtractPropertyCellReferences(int entry, |
| 1391 PropertyCell* cell) { | 1436 PropertyCell* cell) { |
| 1392 ExtractCellReferences(entry, cell); | 1437 ExtractCellReferences(entry, cell); |
| 1393 SetInternalReference(cell, entry, "type", cell->type(), | 1438 SetInternalReference(cell, entry, "type", cell->type(), |
| 1394 PropertyCell::kTypeOffset); | 1439 PropertyCell::kTypeOffset); |
| 1395 SetInternalReference(cell, entry, "dependent_code", cell->dependent_code(), | 1440 SetInternalReference(cell, entry, "dependent_code", cell->dependent_code(), |
| 1396 PropertyCell::kDependentCodeOffset); | 1441 PropertyCell::kDependentCodeOffset); |
| 1397 } | 1442 } |
| 1398 | 1443 |
| 1399 | 1444 |
| 1400 void V8HeapExplorer::ExtractAllocationSiteReferences(int entry, | 1445 void V8HeapExplorer::ExtractAllocationSiteReferences(int entry, |
| 1401 AllocationSite* site) { | 1446 AllocationSite* site) { |
| 1402 SetInternalReference(site, entry, "transition_info", site->transition_info(), | 1447 SetInternalReference(site, entry, "transition_info", site->transition_info(), |
| 1403 AllocationSite::kTransitionInfoOffset); | 1448 AllocationSite::kTransitionInfoOffset); |
| 1404 SetInternalReference(site, entry, "nested_site", site->nested_site(), | 1449 SetInternalReference(site, entry, "nested_site", site->nested_site(), |
| 1405 AllocationSite::kNestedSiteOffset); | 1450 AllocationSite::kNestedSiteOffset); |
| 1406 SetInternalReference(site, entry, "pretenure_data", | |
| 1407 site->pretenure_data(), | |
| 1408 AllocationSite::kPretenureDataOffset); | |
| 1409 SetInternalReference(site, entry, "pretenure_create_count", | |
| 1410 site->pretenure_create_count(), | |
| 1411 AllocationSite::kPretenureCreateCountOffset); | |
| 1412 SetInternalReference(site, entry, "dependent_code", site->dependent_code(), | 1451 SetInternalReference(site, entry, "dependent_code", site->dependent_code(), |
| 1413 AllocationSite::kDependentCodeOffset); | 1452 AllocationSite::kDependentCodeOffset); |
| 1453 // Do not visit weak_next as it is not visited by the StaticVisitor, |
| 1454 // and we're not very interested in weak_next field here. |
| 1455 STATIC_CHECK(AllocationSite::kWeakNextOffset >= |
| 1456 AllocationSite::BodyDescriptor::kEndOffset); |
| 1414 } | 1457 } |
| 1415 | 1458 |
| 1416 | 1459 |
| 1460 class JSArrayBufferDataEntryAllocator : public HeapEntriesAllocator { |
| 1461 public: |
| 1462 JSArrayBufferDataEntryAllocator(size_t size, V8HeapExplorer* explorer) |
| 1463 : size_(size) |
| 1464 , explorer_(explorer) { |
| 1465 } |
| 1466 virtual HeapEntry* AllocateEntry(HeapThing ptr) { |
| 1467 return explorer_->AddEntry( |
| 1468 static_cast<Address>(ptr), |
| 1469 HeapEntry::kNative, "system / JSArrayBufferData", size_); |
| 1470 } |
| 1471 private: |
| 1472 size_t size_; |
| 1473 V8HeapExplorer* explorer_; |
| 1474 }; |
| 1475 |
| 1476 |
| 1477 void V8HeapExplorer::ExtractJSArrayBufferReferences( |
| 1478 int entry, JSArrayBuffer* buffer) { |
| 1479 SetWeakReference(buffer, entry, "weak_next", buffer->weak_next(), |
| 1480 JSArrayBuffer::kWeakNextOffset); |
| 1481 SetWeakReference(buffer, entry, |
| 1482 "weak_first_view", buffer->weak_first_view(), |
| 1483 JSArrayBuffer::kWeakFirstViewOffset); |
| 1484 // Setup a reference to a native memory backing_store object. |
| 1485 if (!buffer->backing_store()) |
| 1486 return; |
| 1487 size_t data_size = NumberToSize(heap_->isolate(), buffer->byte_length()); |
| 1488 JSArrayBufferDataEntryAllocator allocator(data_size, this); |
| 1489 HeapEntry* data_entry = |
| 1490 filler_->FindOrAddEntry(buffer->backing_store(), &allocator); |
| 1491 filler_->SetNamedReference(HeapGraphEdge::kInternal, |
| 1492 entry, "backing_store", data_entry); |
| 1493 } |
| 1494 |
| 1495 |
| 1417 void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj, int entry) { | 1496 void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj, int entry) { |
| 1418 if (!js_obj->IsJSFunction()) return; | 1497 if (!js_obj->IsJSFunction()) return; |
| 1419 | 1498 |
| 1420 JSFunction* func = JSFunction::cast(js_obj); | 1499 JSFunction* func = JSFunction::cast(js_obj); |
| 1421 if (func->shared()->bound()) { | 1500 if (func->shared()->bound()) { |
| 1422 FixedArray* bindings = func->function_bindings(); | 1501 FixedArray* bindings = func->function_bindings(); |
| 1423 SetNativeBindReference(js_obj, entry, "bound_this", | 1502 SetNativeBindReference(js_obj, entry, "bound_this", |
| 1424 bindings->get(JSFunction::kBoundThisIndex)); | 1503 bindings->get(JSFunction::kBoundThisIndex)); |
| 1425 SetNativeBindReference(js_obj, entry, "bound_function", | 1504 SetNativeBindReference(js_obj, entry, "bound_function", |
| 1426 bindings->get(JSFunction::kBoundFunctionIndex)); | 1505 bindings->get(JSFunction::kBoundFunctionIndex)); |
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1628 void SetCollectingAllReferences() { collecting_all_references_ = true; } | 1707 void SetCollectingAllReferences() { collecting_all_references_ = true; } |
| 1629 | 1708 |
| 1630 void FillReferences(V8HeapExplorer* explorer) { | 1709 void FillReferences(V8HeapExplorer* explorer) { |
| 1631 ASSERT(strong_references_.length() <= all_references_.length()); | 1710 ASSERT(strong_references_.length() <= all_references_.length()); |
| 1632 Builtins* builtins = heap_->isolate()->builtins(); | 1711 Builtins* builtins = heap_->isolate()->builtins(); |
| 1633 for (int i = 0; i < reference_tags_.length(); ++i) { | 1712 for (int i = 0; i < reference_tags_.length(); ++i) { |
| 1634 explorer->SetGcRootsReference(reference_tags_[i].tag); | 1713 explorer->SetGcRootsReference(reference_tags_[i].tag); |
| 1635 } | 1714 } |
| 1636 int strong_index = 0, all_index = 0, tags_index = 0, builtin_index = 0; | 1715 int strong_index = 0, all_index = 0, tags_index = 0, builtin_index = 0; |
| 1637 while (all_index < all_references_.length()) { | 1716 while (all_index < all_references_.length()) { |
| 1638 if (strong_index < strong_references_.length() && | 1717 bool is_strong = strong_index < strong_references_.length() |
| 1639 strong_references_[strong_index] == all_references_[all_index]) { | 1718 && strong_references_[strong_index] == all_references_[all_index]; |
| 1640 explorer->SetGcSubrootReference(reference_tags_[tags_index].tag, | 1719 explorer->SetGcSubrootReference(reference_tags_[tags_index].tag, |
| 1641 false, | 1720 !is_strong, |
| 1642 all_references_[all_index]); | 1721 all_references_[all_index]); |
| 1643 ++strong_index; | |
| 1644 } else { | |
| 1645 explorer->SetGcSubrootReference(reference_tags_[tags_index].tag, | |
| 1646 true, | |
| 1647 all_references_[all_index]); | |
| 1648 } | |
| 1649 if (reference_tags_[tags_index].tag == | 1722 if (reference_tags_[tags_index].tag == |
| 1650 VisitorSynchronization::kBuiltins) { | 1723 VisitorSynchronization::kBuiltins) { |
| 1651 ASSERT(all_references_[all_index]->IsCode()); | 1724 ASSERT(all_references_[all_index]->IsCode()); |
| 1652 explorer->TagCodeObject(Code::cast(all_references_[all_index]), | 1725 explorer->TagBuiltinCodeObject( |
| 1726 Code::cast(all_references_[all_index]), |
| 1653 builtins->name(builtin_index++)); | 1727 builtins->name(builtin_index++)); |
| 1654 } | 1728 } |
| 1655 ++all_index; | 1729 ++all_index; |
| 1730 if (is_strong) ++strong_index; |
| 1656 if (reference_tags_[tags_index].index == all_index) ++tags_index; | 1731 if (reference_tags_[tags_index].index == all_index) ++tags_index; |
| 1657 } | 1732 } |
| 1658 } | 1733 } |
| 1659 | 1734 |
| 1660 void Synchronize(VisitorSynchronization::SyncTag tag) { | 1735 void Synchronize(VisitorSynchronization::SyncTag tag) { |
| 1661 if (collecting_all_references_ && | 1736 if (collecting_all_references_ && |
| 1662 previous_reference_count_ != all_references_.length()) { | 1737 previous_reference_count_ != all_references_.length()) { |
| 1663 previous_reference_count_ = all_references_.length(); | 1738 previous_reference_count_ = all_references_.length(); |
| 1664 reference_tags_.Add(IndexTag(previous_reference_count_, tag)); | 1739 reference_tags_.Add(IndexTag(previous_reference_count_, tag)); |
| 1665 } | 1740 } |
| 1666 } | 1741 } |
| 1667 | 1742 |
| 1668 private: | 1743 private: |
| 1669 bool collecting_all_references_; | 1744 bool collecting_all_references_; |
| 1670 List<Object*> strong_references_; | 1745 List<Object*> strong_references_; |
| 1671 List<Object*> all_references_; | 1746 List<Object*> all_references_; |
| 1672 int previous_reference_count_; | 1747 int previous_reference_count_; |
| 1673 List<IndexTag> reference_tags_; | 1748 List<IndexTag> reference_tags_; |
| 1674 Heap* heap_; | 1749 Heap* heap_; |
| 1675 }; | 1750 }; |
| 1676 | 1751 |
| 1677 | 1752 |
| 1678 bool V8HeapExplorer::IterateAndExtractReferences( | 1753 bool V8HeapExplorer::IterateAndExtractReferences( |
| 1679 SnapshotFillerInterface* filler) { | 1754 SnapshotFillerInterface* filler) { |
| 1755 filler_ = filler; |
| 1756 |
| 1757 // Make sure builtin code objects get their builtin tags |
| 1758 // first. Otherwise a particular JSFunction object could set |
| 1759 // its custom name to a generic builtin. |
| 1760 SetRootGcRootsReference(); |
| 1761 RootsReferencesExtractor extractor(heap_); |
| 1762 heap_->IterateRoots(&extractor, VISIT_ONLY_STRONG); |
| 1763 extractor.SetCollectingAllReferences(); |
| 1764 heap_->IterateRoots(&extractor, VISIT_ALL); |
| 1765 extractor.FillReferences(this); |
| 1766 |
| 1767 // Now iterate the whole heap. |
| 1768 bool interrupted = false; |
| 1680 HeapIterator iterator(heap_, HeapIterator::kFilterUnreachable); | 1769 HeapIterator iterator(heap_, HeapIterator::kFilterUnreachable); |
| 1681 | |
| 1682 filler_ = filler; | |
| 1683 bool interrupted = false; | |
| 1684 | |
| 1685 // Heap iteration with filtering must be finished in any case. | 1770 // Heap iteration with filtering must be finished in any case. |
| 1686 for (HeapObject* obj = iterator.next(); | 1771 for (HeapObject* obj = iterator.next(); |
| 1687 obj != NULL; | 1772 obj != NULL; |
| 1688 obj = iterator.next(), progress_->ProgressStep()) { | 1773 obj = iterator.next(), progress_->ProgressStep()) { |
| 1689 if (!interrupted) { | 1774 if (!interrupted) { |
| 1690 ExtractReferences(obj); | 1775 ExtractReferences(obj); |
| 1691 if (!progress_->ProgressReport(false)) interrupted = true; | 1776 if (!progress_->ProgressReport(false)) interrupted = true; |
| 1692 } | 1777 } |
| 1693 } | 1778 } |
| 1694 if (interrupted) { | 1779 if (interrupted) { |
| 1695 filler_ = NULL; | 1780 filler_ = NULL; |
| 1696 return false; | 1781 return false; |
| 1697 } | 1782 } |
| 1698 | 1783 |
| 1699 SetRootGcRootsReference(); | |
| 1700 RootsReferencesExtractor extractor(heap_); | |
| 1701 heap_->IterateRoots(&extractor, VISIT_ONLY_STRONG); | |
| 1702 extractor.SetCollectingAllReferences(); | |
| 1703 heap_->IterateRoots(&extractor, VISIT_ALL); | |
| 1704 extractor.FillReferences(this); | |
| 1705 filler_ = NULL; | 1784 filler_ = NULL; |
| 1706 return progress_->ProgressReport(true); | 1785 return progress_->ProgressReport(true); |
| 1707 } | 1786 } |
| 1708 | 1787 |
| 1709 | 1788 |
| 1710 bool V8HeapExplorer::IsEssentialObject(Object* object) { | 1789 bool V8HeapExplorer::IsEssentialObject(Object* object) { |
| 1711 return object->IsHeapObject() | 1790 return object->IsHeapObject() |
| 1712 && !object->IsOddball() | 1791 && !object->IsOddball() |
| 1713 && object != heap_->empty_byte_array() | 1792 && object != heap_->empty_byte_array() |
| 1714 && object != heap_->empty_fixed_array() | 1793 && object != heap_->empty_fixed_array() |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1816 filler_->SetIndexedReference(HeapGraphEdge::kHidden, | 1895 filler_->SetIndexedReference(HeapGraphEdge::kHidden, |
| 1817 parent_entry, | 1896 parent_entry, |
| 1818 index, | 1897 index, |
| 1819 child_entry); | 1898 child_entry); |
| 1820 } | 1899 } |
| 1821 } | 1900 } |
| 1822 | 1901 |
| 1823 | 1902 |
| 1824 void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj, | 1903 void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj, |
| 1825 int parent_entry, | 1904 int parent_entry, |
| 1826 int index, | 1905 const char* reference_name, |
| 1827 Object* child_obj, | 1906 Object* child_obj, |
| 1828 int field_offset) { | 1907 int field_offset) { |
| 1829 ASSERT(parent_entry == GetEntry(parent_obj)->index()); | 1908 ASSERT(parent_entry == GetEntry(parent_obj)->index()); |
| 1830 HeapEntry* child_entry = GetEntry(child_obj); | 1909 HeapEntry* child_entry = GetEntry(child_obj); |
| 1831 if (child_entry == NULL) return; | 1910 if (child_entry == NULL) return; |
| 1832 if (IsEssentialObject(child_obj)) { | 1911 if (IsEssentialObject(child_obj)) { |
| 1833 filler_->SetIndexedReference(HeapGraphEdge::kWeak, | 1912 filler_->SetNamedReference(HeapGraphEdge::kWeak, |
| 1834 parent_entry, | 1913 parent_entry, |
| 1835 index, | 1914 reference_name, |
| 1836 child_entry); | 1915 child_entry); |
| 1837 } | 1916 } |
| 1838 IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset); | 1917 IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset); |
| 1839 } | 1918 } |
| 1840 | 1919 |
| 1841 | 1920 |
| 1842 void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj, | 1921 void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj, |
| 1843 int parent_entry, | 1922 int parent_entry, |
| 1844 Name* reference_name, | 1923 Name* reference_name, |
| 1845 Object* child_obj, | 1924 Object* child_obj, |
| 1846 const char* name_format_string, | 1925 const char* name_format_string, |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1898 HeapEntry* child_entry = GetEntry(child_obj); | 1977 HeapEntry* child_entry = GetEntry(child_obj); |
| 1899 if (child_entry != NULL) { | 1978 if (child_entry != NULL) { |
| 1900 const char* name = GetStrongGcSubrootName(child_obj); | 1979 const char* name = GetStrongGcSubrootName(child_obj); |
| 1901 if (name != NULL) { | 1980 if (name != NULL) { |
| 1902 filler_->SetNamedReference( | 1981 filler_->SetNamedReference( |
| 1903 HeapGraphEdge::kInternal, | 1982 HeapGraphEdge::kInternal, |
| 1904 snapshot_->gc_subroot(tag)->index(), | 1983 snapshot_->gc_subroot(tag)->index(), |
| 1905 name, | 1984 name, |
| 1906 child_entry); | 1985 child_entry); |
| 1907 } else { | 1986 } else { |
| 1908 filler_->SetIndexedAutoIndexReference( | 1987 if (is_weak) { |
| 1909 is_weak ? HeapGraphEdge::kWeak : HeapGraphEdge::kElement, | 1988 filler_->SetNamedAutoIndexReference( |
| 1910 snapshot_->gc_subroot(tag)->index(), | 1989 HeapGraphEdge::kWeak, |
| 1911 child_entry); | 1990 snapshot_->gc_subroot(tag)->index(), |
| 1991 child_entry); |
| 1992 } else { |
| 1993 filler_->SetIndexedAutoIndexReference( |
| 1994 HeapGraphEdge::kElement, |
| 1995 snapshot_->gc_subroot(tag)->index(), |
| 1996 child_entry); |
| 1997 } |
| 1912 } | 1998 } |
| 1913 | 1999 |
| 1914 // Add a shortcut to JS global object reference at snapshot root. | 2000 // Add a shortcut to JS global object reference at snapshot root. |
| 1915 if (child_obj->IsNativeContext()) { | 2001 if (child_obj->IsNativeContext()) { |
| 1916 Context* context = Context::cast(child_obj); | 2002 Context* context = Context::cast(child_obj); |
| 1917 GlobalObject* global = context->global_object(); | 2003 GlobalObject* global = context->global_object(); |
| 1918 if (global->IsJSGlobalObject()) { | 2004 if (global->IsJSGlobalObject()) { |
| 1919 bool is_debug_object = false; | 2005 bool is_debug_object = false; |
| 1920 #ifdef ENABLE_DEBUGGER_SUPPORT | 2006 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 1921 is_debug_object = heap_->isolate()->debug()->IsDebugGlobal(global); | 2007 is_debug_object = heap_->isolate()->debug()->IsDebugGlobal(global); |
| (...skipping 687 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2609 int HeapSnapshotJSONSerializer::GetStringId(const char* s) { | 2695 int HeapSnapshotJSONSerializer::GetStringId(const char* s) { |
| 2610 HashMap::Entry* cache_entry = strings_.Lookup( | 2696 HashMap::Entry* cache_entry = strings_.Lookup( |
| 2611 const_cast<char*>(s), StringHash(s), true); | 2697 const_cast<char*>(s), StringHash(s), true); |
| 2612 if (cache_entry->value == NULL) { | 2698 if (cache_entry->value == NULL) { |
| 2613 cache_entry->value = reinterpret_cast<void*>(next_string_id_++); | 2699 cache_entry->value = reinterpret_cast<void*>(next_string_id_++); |
| 2614 } | 2700 } |
| 2615 return static_cast<int>(reinterpret_cast<intptr_t>(cache_entry->value)); | 2701 return static_cast<int>(reinterpret_cast<intptr_t>(cache_entry->value)); |
| 2616 } | 2702 } |
| 2617 | 2703 |
| 2618 | 2704 |
| 2619 static int utoa(unsigned value, const Vector<char>& buffer, int buffer_pos) { | 2705 namespace { |
| 2706 |
| 2707 template<size_t size> struct ToUnsigned; |
| 2708 |
| 2709 template<> struct ToUnsigned<4> { |
| 2710 typedef uint32_t Type; |
| 2711 }; |
| 2712 |
| 2713 template<> struct ToUnsigned<8> { |
| 2714 typedef uint64_t Type; |
| 2715 }; |
| 2716 |
| 2717 } // namespace |
| 2718 |
| 2719 |
| 2720 template<typename T> |
| 2721 static int utoa_impl(T value, const Vector<char>& buffer, int buffer_pos) { |
| 2722 STATIC_CHECK(static_cast<T>(-1) > 0); // Check that T is unsigned |
| 2620 int number_of_digits = 0; | 2723 int number_of_digits = 0; |
| 2621 unsigned t = value; | 2724 T t = value; |
| 2622 do { | 2725 do { |
| 2623 ++number_of_digits; | 2726 ++number_of_digits; |
| 2624 } while (t /= 10); | 2727 } while (t /= 10); |
| 2625 | 2728 |
| 2626 buffer_pos += number_of_digits; | 2729 buffer_pos += number_of_digits; |
| 2627 int result = buffer_pos; | 2730 int result = buffer_pos; |
| 2628 do { | 2731 do { |
| 2629 int last_digit = value % 10; | 2732 int last_digit = static_cast<int>(value % 10); |
| 2630 buffer[--buffer_pos] = '0' + last_digit; | 2733 buffer[--buffer_pos] = '0' + last_digit; |
| 2631 value /= 10; | 2734 value /= 10; |
| 2632 } while (value); | 2735 } while (value); |
| 2633 return result; | 2736 return result; |
| 2634 } | 2737 } |
| 2635 | 2738 |
| 2636 | 2739 |
| 2740 template<typename T> |
| 2741 static int utoa(T value, const Vector<char>& buffer, int buffer_pos) { |
| 2742 typename ToUnsigned<sizeof(value)>::Type unsigned_value = value; |
| 2743 STATIC_CHECK(sizeof(value) == sizeof(unsigned_value)); |
| 2744 return utoa_impl(unsigned_value, buffer, buffer_pos); |
| 2745 } |
| 2746 |
| 2747 |
| 2637 void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge, | 2748 void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge, |
| 2638 bool first_edge) { | 2749 bool first_edge) { |
| 2639 // The buffer needs space for 3 unsigned ints, 3 commas, \n and \0 | 2750 // The buffer needs space for 3 unsigned ints, 3 commas, \n and \0 |
| 2640 static const int kBufferSize = | 2751 static const int kBufferSize = |
| 2641 MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned * 3 + 3 + 2; // NOLINT | 2752 MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned * 3 + 3 + 2; // NOLINT |
| 2642 EmbeddedVector<char, kBufferSize> buffer; | 2753 EmbeddedVector<char, kBufferSize> buffer; |
| 2643 int edge_name_or_index = edge->type() == HeapGraphEdge::kElement | 2754 int edge_name_or_index = edge->type() == HeapGraphEdge::kElement |
| 2644 || edge->type() == HeapGraphEdge::kHidden | 2755 || edge->type() == HeapGraphEdge::kHidden |
| 2645 || edge->type() == HeapGraphEdge::kWeak | |
| 2646 ? edge->index() : GetStringId(edge->name()); | 2756 ? edge->index() : GetStringId(edge->name()); |
| 2647 int buffer_pos = 0; | 2757 int buffer_pos = 0; |
| 2648 if (!first_edge) { | 2758 if (!first_edge) { |
| 2649 buffer[buffer_pos++] = ','; | 2759 buffer[buffer_pos++] = ','; |
| 2650 } | 2760 } |
| 2651 buffer_pos = utoa(edge->type(), buffer, buffer_pos); | 2761 buffer_pos = utoa(edge->type(), buffer, buffer_pos); |
| 2652 buffer[buffer_pos++] = ','; | 2762 buffer[buffer_pos++] = ','; |
| 2653 buffer_pos = utoa(edge_name_or_index, buffer, buffer_pos); | 2763 buffer_pos = utoa(edge_name_or_index, buffer, buffer_pos); |
| 2654 buffer[buffer_pos++] = ','; | 2764 buffer[buffer_pos++] = ','; |
| 2655 buffer_pos = utoa(entry_index(edge->to()), buffer, buffer_pos); | 2765 buffer_pos = utoa(entry_index(edge->to()), buffer, buffer_pos); |
| 2656 buffer[buffer_pos++] = '\n'; | 2766 buffer[buffer_pos++] = '\n'; |
| 2657 buffer[buffer_pos++] = '\0'; | 2767 buffer[buffer_pos++] = '\0'; |
| 2658 writer_->AddString(buffer.start()); | 2768 writer_->AddString(buffer.start()); |
| 2659 } | 2769 } |
| 2660 | 2770 |
| 2661 | 2771 |
| 2662 void HeapSnapshotJSONSerializer::SerializeEdges() { | 2772 void HeapSnapshotJSONSerializer::SerializeEdges() { |
| 2663 List<HeapGraphEdge*>& edges = snapshot_->children(); | 2773 List<HeapGraphEdge*>& edges = snapshot_->children(); |
| 2664 for (int i = 0; i < edges.length(); ++i) { | 2774 for (int i = 0; i < edges.length(); ++i) { |
| 2665 ASSERT(i == 0 || | 2775 ASSERT(i == 0 || |
| 2666 edges[i - 1]->from()->index() <= edges[i]->from()->index()); | 2776 edges[i - 1]->from()->index() <= edges[i]->from()->index()); |
| 2667 SerializeEdge(edges[i], i == 0); | 2777 SerializeEdge(edges[i], i == 0); |
| 2668 if (writer_->aborted()) return; | 2778 if (writer_->aborted()) return; |
| 2669 } | 2779 } |
| 2670 } | 2780 } |
| 2671 | 2781 |
| 2672 | 2782 |
| 2673 void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry) { | 2783 void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry) { |
| 2674 // The buffer needs space for 5 unsigned ints, 5 commas, \n and \0 | 2784 // The buffer needs space for 4 unsigned ints, 1 size_t, 5 commas, \n and \0 |
| 2675 static const int kBufferSize = | 2785 static const int kBufferSize = |
| 2676 5 * MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned // NOLINT | 2786 4 * MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned // NOLINT |
| 2787 + MaxDecimalDigitsIn<sizeof(size_t)>::kUnsigned // NOLINT |
| 2677 + 5 + 1 + 1; | 2788 + 5 + 1 + 1; |
| 2678 EmbeddedVector<char, kBufferSize> buffer; | 2789 EmbeddedVector<char, kBufferSize> buffer; |
| 2679 int buffer_pos = 0; | 2790 int buffer_pos = 0; |
| 2680 if (entry_index(entry) != 0) { | 2791 if (entry_index(entry) != 0) { |
| 2681 buffer[buffer_pos++] = ','; | 2792 buffer[buffer_pos++] = ','; |
| 2682 } | 2793 } |
| 2683 buffer_pos = utoa(entry->type(), buffer, buffer_pos); | 2794 buffer_pos = utoa(entry->type(), buffer, buffer_pos); |
| 2684 buffer[buffer_pos++] = ','; | 2795 buffer[buffer_pos++] = ','; |
| 2685 buffer_pos = utoa(GetStringId(entry->name()), buffer, buffer_pos); | 2796 buffer_pos = utoa(GetStringId(entry->name()), buffer, buffer_pos); |
| 2686 buffer[buffer_pos++] = ','; | 2797 buffer[buffer_pos++] = ','; |
| (...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2954 writer_->AddString("\"<dummy>\""); | 3065 writer_->AddString("\"<dummy>\""); |
| 2955 for (int i = 1; i < sorted_strings.length(); ++i) { | 3066 for (int i = 1; i < sorted_strings.length(); ++i) { |
| 2956 writer_->AddCharacter(','); | 3067 writer_->AddCharacter(','); |
| 2957 SerializeString(sorted_strings[i]); | 3068 SerializeString(sorted_strings[i]); |
| 2958 if (writer_->aborted()) return; | 3069 if (writer_->aborted()) return; |
| 2959 } | 3070 } |
| 2960 } | 3071 } |
| 2961 | 3072 |
| 2962 | 3073 |
| 2963 } } // namespace v8::internal | 3074 } } // namespace v8::internal |
| OLD | NEW |