OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/heap/object-stats.h" | 5 #include "src/heap/object-stats.h" |
6 | 6 |
7 #include "src/counters.h" | 7 #include "src/counters.h" |
8 #include "src/heap/heap-inl.h" | 8 #include "src/heap/heap-inl.h" |
9 #include "src/isolate.h" | 9 #include "src/isolate.h" |
10 #include "src/utils.h" | 10 #include "src/utils.h" |
11 | 11 |
12 namespace v8 { | 12 namespace v8 { |
13 namespace internal { | 13 namespace internal { |
14 | 14 |
15 static base::LazyMutex object_stats_mutex = LAZY_MUTEX_INITIALIZER; | 15 static base::LazyMutex object_stats_mutex = LAZY_MUTEX_INITIALIZER; |
16 | 16 |
17 | 17 |
18 void ObjectStats::ClearObjectStats(bool clear_last_time_stats) { | 18 void ObjectStats::ClearObjectStats(bool clear_last_time_stats) { |
19 memset(object_counts_, 0, sizeof(object_counts_)); | 19 memset(object_counts_, 0, sizeof(object_counts_)); |
20 memset(object_sizes_, 0, sizeof(object_sizes_)); | 20 memset(object_sizes_, 0, sizeof(object_sizes_)); |
| 21 memset(over_allocated_, 0, sizeof(over_allocated_)); |
| 22 memset(size_histogram_, 0, sizeof(size_histogram_)); |
| 23 memset(over_allocated_histogram_, 0, sizeof(over_allocated_histogram_)); |
21 if (clear_last_time_stats) { | 24 if (clear_last_time_stats) { |
22 memset(object_counts_last_time_, 0, sizeof(object_counts_last_time_)); | 25 memset(object_counts_last_time_, 0, sizeof(object_counts_last_time_)); |
23 memset(object_sizes_last_time_, 0, sizeof(object_sizes_last_time_)); | 26 memset(object_sizes_last_time_, 0, sizeof(object_sizes_last_time_)); |
24 } | 27 } |
25 } | 28 } |
26 | 29 |
| 30 void ObjectStats::PrintJSON(const char* key) { |
| 31 double time = isolate()->time_millis_since_init(); |
| 32 int gc_count = heap()->gc_count(); |
27 | 33 |
28 void ObjectStats::TraceObjectStat(const char* name, int count, int size, | 34 #define PRINT_KEY_AND_ID() \ |
29 double time) { | 35 PrintF("\"isolate\": \"%p\", \"id\": %d, \"key\": \"%s\", ", \ |
30 int ms_count = heap()->ms_count(); | 36 reinterpret_cast<void*>(isolate()), gc_count, key); |
31 PrintIsolate(isolate(), | 37 |
32 "heap:%p, time:%f, gc:%d, type:%s, count:%d, size:%d\n", | 38 // gc_descriptor |
33 static_cast<void*>(heap()), time, ms_count, name, count, size); | 39 PrintF("{ "); |
| 40 PRINT_KEY_AND_ID(); |
| 41 PrintF("\"type\": \"gc_descriptor\", \"time\": %f }\n", time); |
| 42 // bucket_sizes |
| 43 PrintF("{ "); |
| 44 PRINT_KEY_AND_ID(); |
| 45 PrintF("\"type\": \"bucket_sizes\", \"sizes\": [ "); |
| 46 for (int i = 0; i < kNumberOfBuckets; i++) { |
| 47 PrintF("%d", 1 << (kFirstBucketShift + i)); |
| 48 if (i != (kNumberOfBuckets - 1)) PrintF(", "); |
| 49 } |
| 50 PrintF(" ] }\n"); |
| 51 // instance_type_data |
| 52 #define PRINT_INSTANCE_TYPE_DATA(name, index) \ |
| 53 PrintF("{ "); \ |
| 54 PRINT_KEY_AND_ID(); \ |
| 55 PrintF("\"type\": \"instance_type_data\", "); \ |
| 56 PrintF("\"instance_type\": %d, ", index); \ |
| 57 PrintF("\"instance_type_name\": \"%s\", ", name); \ |
| 58 PrintF("\"overall\": %zu, ", object_sizes_[index]); \ |
| 59 PrintF("\"count\": %zu, ", object_counts_[index]); \ |
| 60 PrintF("\"over_allocated\": %zu, ", over_allocated_[index]); \ |
| 61 PrintF("\"histogram\": ["); \ |
| 62 for (int j = 0; j < kNumberOfBuckets; j++) { \ |
| 63 PrintF("%zu", size_histogram_[index][j]); \ |
| 64 if (j != (kNumberOfBuckets - 1)) PrintF(", "); \ |
| 65 } \ |
| 66 PrintF(" ],"); \ |
| 67 PrintF("\"over_allocated_histogram\": ["); \ |
| 68 for (int j = 0; j < kNumberOfBuckets; j++) { \ |
| 69 PrintF("%zu", over_allocated_histogram_[index][j]); \ |
| 70 if (j != (kNumberOfBuckets - 1)) PrintF(", "); \ |
| 71 } \ |
| 72 PrintF(" ]"); \ |
| 73 PrintF(" }\n"); |
| 74 |
| 75 #define INSTANCE_TYPE_WRAPPER(name) PRINT_INSTANCE_TYPE_DATA(#name, name) |
| 76 #define CODE_KIND_WRAPPER(name) \ |
| 77 PRINT_INSTANCE_TYPE_DATA("*CODE_" #name, \ |
| 78 FIRST_CODE_KIND_SUB_TYPE + Code::name) |
| 79 #define FIXED_ARRAY_SUB_INSTANCE_TYPE_WRAPPER(name) \ |
| 80 PRINT_INSTANCE_TYPE_DATA("*FIXED_ARRAY_" #name, \ |
| 81 FIRST_FIXED_ARRAY_SUB_TYPE + name) |
| 82 #define CODE_AGE_WRAPPER(name) \ |
| 83 PRINT_INSTANCE_TYPE_DATA( \ |
| 84 "*CODE_AGE_" #name, \ |
| 85 FIRST_CODE_AGE_SUB_TYPE + Code::k##name##CodeAge - Code::kFirstCodeAge) |
| 86 |
| 87 INSTANCE_TYPE_LIST(INSTANCE_TYPE_WRAPPER) |
| 88 CODE_KIND_LIST(CODE_KIND_WRAPPER) |
| 89 FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(FIXED_ARRAY_SUB_INSTANCE_TYPE_WRAPPER) |
| 90 CODE_AGE_LIST_COMPLETE(CODE_AGE_WRAPPER) |
| 91 |
| 92 #undef INSTANCE_TYPE_WRAPPER |
| 93 #undef CODE_KIND_WRAPPER |
| 94 #undef FIXED_ARRAY_SUB_INSTANCE_TYPE_WRAPPER |
| 95 #undef CODE_AGE_WRAPPER |
| 96 #undef PRINT_INSTANCE_TYPE_DATA |
34 } | 97 } |
35 | 98 |
36 | |
37 void ObjectStats::TraceObjectStats() { | |
38 base::LockGuard<base::Mutex> lock_guard(object_stats_mutex.Pointer()); | |
39 int index; | |
40 int count; | |
41 int size; | |
42 int total_size = 0; | |
43 double time = isolate()->time_millis_since_init(); | |
44 #define TRACE_OBJECT_COUNT(name) \ | |
45 count = static_cast<int>(object_counts_[name]); \ | |
46 size = static_cast<int>(object_sizes_[name]) / KB; \ | |
47 total_size += size; \ | |
48 TraceObjectStat(#name, count, size, time); | |
49 INSTANCE_TYPE_LIST(TRACE_OBJECT_COUNT) | |
50 #undef TRACE_OBJECT_COUNT | |
51 #define TRACE_OBJECT_COUNT(name) \ | |
52 index = FIRST_CODE_KIND_SUB_TYPE + Code::name; \ | |
53 count = static_cast<int>(object_counts_[index]); \ | |
54 size = static_cast<int>(object_sizes_[index]) / KB; \ | |
55 TraceObjectStat("*CODE_" #name, count, size, time); | |
56 CODE_KIND_LIST(TRACE_OBJECT_COUNT) | |
57 #undef TRACE_OBJECT_COUNT | |
58 #define TRACE_OBJECT_COUNT(name) \ | |
59 index = FIRST_FIXED_ARRAY_SUB_TYPE + name; \ | |
60 count = static_cast<int>(object_counts_[index]); \ | |
61 size = static_cast<int>(object_sizes_[index]) / KB; \ | |
62 TraceObjectStat("*FIXED_ARRAY_" #name, count, size, time); | |
63 FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(TRACE_OBJECT_COUNT) | |
64 #undef TRACE_OBJECT_COUNT | |
65 #define TRACE_OBJECT_COUNT(name) \ | |
66 index = \ | |
67 FIRST_CODE_AGE_SUB_TYPE + Code::k##name##CodeAge - Code::kFirstCodeAge; \ | |
68 count = static_cast<int>(object_counts_[index]); \ | |
69 size = static_cast<int>(object_sizes_[index]) / KB; \ | |
70 TraceObjectStat("*CODE_AGE_" #name, count, size, time); | |
71 CODE_AGE_LIST_COMPLETE(TRACE_OBJECT_COUNT) | |
72 #undef TRACE_OBJECT_COUNT | |
73 } | |
74 | |
75 | |
76 void ObjectStats::CheckpointObjectStats() { | 99 void ObjectStats::CheckpointObjectStats() { |
77 base::LockGuard<base::Mutex> lock_guard(object_stats_mutex.Pointer()); | 100 base::LockGuard<base::Mutex> lock_guard(object_stats_mutex.Pointer()); |
78 Counters* counters = isolate()->counters(); | 101 Counters* counters = isolate()->counters(); |
79 #define ADJUST_LAST_TIME_OBJECT_COUNT(name) \ | 102 #define ADJUST_LAST_TIME_OBJECT_COUNT(name) \ |
80 counters->count_of_##name()->Increment( \ | 103 counters->count_of_##name()->Increment( \ |
81 static_cast<int>(object_counts_[name])); \ | 104 static_cast<int>(object_counts_[name])); \ |
82 counters->count_of_##name()->Decrement( \ | 105 counters->count_of_##name()->Decrement( \ |
83 static_cast<int>(object_counts_last_time_[name])); \ | 106 static_cast<int>(object_counts_last_time_[name])); \ |
84 counters->size_of_##name()->Increment( \ | 107 counters->size_of_##name()->Increment( \ |
85 static_cast<int>(object_sizes_[name])); \ | 108 static_cast<int>(object_sizes_[name])); \ |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
127 #undef ADJUST_LAST_TIME_OBJECT_COUNT | 150 #undef ADJUST_LAST_TIME_OBJECT_COUNT |
128 | 151 |
129 MemCopy(object_counts_last_time_, object_counts_, sizeof(object_counts_)); | 152 MemCopy(object_counts_last_time_, object_counts_, sizeof(object_counts_)); |
130 MemCopy(object_sizes_last_time_, object_sizes_, sizeof(object_sizes_)); | 153 MemCopy(object_sizes_last_time_, object_sizes_, sizeof(object_sizes_)); |
131 ClearObjectStats(); | 154 ClearObjectStats(); |
132 } | 155 } |
133 | 156 |
134 | 157 |
135 Isolate* ObjectStats::isolate() { return heap()->isolate(); } | 158 Isolate* ObjectStats::isolate() { return heap()->isolate(); } |
136 | 159 |
137 void ObjectStatsCollector::CountFixedArray( | 160 void ObjectStatsCollector::CollectStatistics(ObjectStats* stats, |
138 FixedArrayBase* fixed_array, FixedArraySubInstanceType fast_type, | 161 HeapObject* obj) { |
139 FixedArraySubInstanceType dictionary_type) { | 162 Map* map = obj->map(); |
140 Heap* heap = fixed_array->map()->GetHeap(); | 163 Heap* heap = obj->GetHeap(); |
141 if (fixed_array->map() != heap->fixed_cow_array_map() && | 164 |
142 fixed_array->map() != heap->fixed_double_array_map() && | 165 // Record for the InstanceType. |
143 fixed_array != heap->empty_fixed_array()) { | 166 int object_size = obj->Size(); |
144 if (fixed_array->IsDictionary()) { | 167 stats->RecordObjectStats(map->instance_type(), object_size); |
145 heap->object_stats_->RecordFixedArraySubTypeStats(dictionary_type, | 168 |
146 fixed_array->Size()); | 169 // Record specific sub types where possible. |
| 170 if (obj->IsMap()) { |
| 171 RecordMapDetails(stats, heap, obj); |
| 172 } |
| 173 if (obj->IsCode()) { |
| 174 RecordCodeDetails(stats, heap, obj); |
| 175 } |
| 176 if (obj->IsSharedFunctionInfo()) { |
| 177 RecordSharedFunctionInfoDetails(stats, heap, obj); |
| 178 } |
| 179 if (obj->IsFixedArray()) { |
| 180 RecordFixedArrayDetails(stats, heap, obj); |
| 181 } |
| 182 if (obj->IsJSObject()) { |
| 183 RecordJSObjectDetails(stats, heap, JSObject::cast(obj)); |
| 184 } |
| 185 if (obj->IsJSWeakCollection()) { |
| 186 RecordJSWeakCollectionDetails(stats, heap, JSWeakCollection::cast(obj)); |
| 187 } |
| 188 } |
| 189 |
| 190 static bool CanRecordFixedArray(Heap* heap, FixedArrayBase* array) { |
| 191 return array->map() != heap->fixed_cow_array_map() && |
| 192 array->map() != heap->fixed_double_array_map() && |
| 193 array != heap->empty_fixed_array(); |
| 194 } |
| 195 |
| 196 void ObjectStatsCollector::RecordJSObjectDetails(ObjectStats* stats, Heap* heap, |
| 197 JSObject* object) { |
| 198 DCHECK(object->IsJSObject()); |
| 199 |
| 200 size_t overhead = 0; |
| 201 FixedArrayBase* elements = object->elements(); |
| 202 if (CanRecordFixedArray(heap, elements)) { |
| 203 if (elements->IsDictionary()) { |
| 204 SeededNumberDictionary* dict = object->element_dictionary(); |
| 205 int used = dict->NumberOfElements() * SeededNumberDictionary::kEntrySize; |
| 206 CHECK_GE(elements->Size(), used); |
| 207 overhead = elements->Size() - used; |
| 208 stats->RecordFixedArraySubTypeStats(DICTIONARY_ELEMENTS_SUB_TYPE, |
| 209 elements->Size(), overhead); |
147 } else { | 210 } else { |
148 heap->object_stats_->RecordFixedArraySubTypeStats(fast_type, | 211 if (IsFastHoleyElementsKind(object->GetElementsKind())) { |
149 fixed_array->Size()); | 212 int used = object->GetFastElementsUsage() * kPointerSize; |
| 213 if (object->GetElementsKind() == FAST_HOLEY_DOUBLE_ELEMENTS) used *= 2; |
| 214 CHECK_GE(elements->Size(), used); |
| 215 overhead = elements->Size() - used; |
| 216 } |
| 217 stats->RecordFixedArraySubTypeStats(FAST_ELEMENTS_SUB_TYPE, |
| 218 elements->Size(), overhead); |
| 219 } |
| 220 } |
| 221 |
| 222 overhead = 0; |
| 223 FixedArrayBase* properties = object->properties(); |
| 224 if (CanRecordFixedArray(heap, properties)) { |
| 225 if (properties->IsDictionary()) { |
| 226 NameDictionary* dict = object->property_dictionary(); |
| 227 int used = dict->NumberOfElements() * NameDictionary::kEntrySize; |
| 228 CHECK_GE(properties->Size(), used); |
| 229 overhead = properties->Size() - used; |
| 230 stats->RecordFixedArraySubTypeStats(DICTIONARY_PROPERTIES_SUB_TYPE, |
| 231 properties->Size(), overhead); |
| 232 } else { |
| 233 stats->RecordFixedArraySubTypeStats(FAST_PROPERTIES_SUB_TYPE, |
| 234 properties->Size(), overhead); |
150 } | 235 } |
151 } | 236 } |
152 } | 237 } |
153 | 238 |
154 void ObjectStatsCollector::CollectStatistics(StaticVisitorBase::VisitorId id, | 239 void ObjectStatsCollector::RecordJSWeakCollectionDetails( |
155 Map* map, HeapObject* obj) { | 240 ObjectStats* stats, Heap* heap, JSWeakCollection* obj) { |
156 // Record any type specific statistics here. | 241 if (obj->table()->IsHashTable()) { |
157 switch (id) { | 242 ObjectHashTable* table = ObjectHashTable::cast(obj->table()); |
158 case StaticVisitorBase::kVisitMap: | 243 int used = table->NumberOfElements() * ObjectHashTable::kEntrySize; |
159 RecordMapStats(map, obj); | 244 size_t overhead = table->Size() - used; |
160 break; | 245 stats->RecordFixedArraySubTypeStats(WEAK_COLLECTION_SUB_TYPE, table->Size(), |
161 case StaticVisitorBase::kVisitCode: | 246 overhead); |
162 RecordCodeStats(map, obj); | |
163 break; | |
164 case StaticVisitorBase::kVisitSharedFunctionInfo: | |
165 RecordSharedFunctionInfoStats(map, obj); | |
166 break; | |
167 case StaticVisitorBase::kVisitFixedArray: | |
168 RecordFixedArrayStats(map, obj); | |
169 break; | |
170 default: | |
171 break; | |
172 } | |
173 | |
174 Heap* heap = map->GetHeap(); | |
175 int object_size = obj->Size(); | |
176 heap->object_stats_->RecordObjectStats(map->instance_type(), object_size); | |
177 } | |
178 | |
179 void ObjectStatsCollector::CollectFixedArrayStatistics(HeapObject* obj) { | |
180 if (obj->IsJSObject()) { | |
181 JSObject* object = JSObject::cast(obj); | |
182 CountFixedArray(object->elements(), DICTIONARY_ELEMENTS_SUB_TYPE, | |
183 FAST_ELEMENTS_SUB_TYPE); | |
184 CountFixedArray(object->properties(), DICTIONARY_PROPERTIES_SUB_TYPE, | |
185 FAST_PROPERTIES_SUB_TYPE); | |
186 } | 247 } |
187 } | 248 } |
188 | 249 |
189 void ObjectStatsCollector::RecordMapStats(Map* map, HeapObject* obj) { | 250 void ObjectStatsCollector::RecordMapDetails(ObjectStats* stats, Heap* heap, |
190 Heap* heap = map->GetHeap(); | 251 HeapObject* obj) { |
191 Map* map_obj = Map::cast(obj); | 252 Map* map_obj = Map::cast(obj); |
192 DCHECK(map->instance_type() == MAP_TYPE); | 253 DCHECK(obj->map()->instance_type() == MAP_TYPE); |
193 DescriptorArray* array = map_obj->instance_descriptors(); | 254 DescriptorArray* array = map_obj->instance_descriptors(); |
194 if (map_obj->owns_descriptors() && array != heap->empty_descriptor_array()) { | 255 if (map_obj->owns_descriptors() && array != heap->empty_descriptor_array()) { |
195 int fixed_array_size = array->Size(); | 256 int fixed_array_size = array->Size(); |
196 heap->object_stats_->RecordFixedArraySubTypeStats(DESCRIPTOR_ARRAY_SUB_TYPE, | 257 stats->RecordFixedArraySubTypeStats(DESCRIPTOR_ARRAY_SUB_TYPE, |
197 fixed_array_size); | 258 fixed_array_size, 0); |
| 259 if (array->HasEnumCache()) { |
| 260 stats->RecordFixedArraySubTypeStats(ENUM_CACHE_SUB_TYPE, |
| 261 array->GetEnumCache()->Size(), 0); |
| 262 } |
| 263 if (array->HasEnumIndicesCache()) { |
| 264 stats->RecordFixedArraySubTypeStats( |
| 265 ENUM_INDICES_CACHE_SUB_TYPE, array->GetEnumIndicesCache()->Size(), 0); |
| 266 } |
198 } | 267 } |
| 268 |
199 if (map_obj->has_code_cache()) { | 269 if (map_obj->has_code_cache()) { |
200 FixedArray* cache = map_obj->code_cache(); | 270 FixedArray* cache = map_obj->code_cache(); |
201 heap->object_stats_->RecordFixedArraySubTypeStats(MAP_CODE_CACHE_SUB_TYPE, | 271 stats->RecordFixedArraySubTypeStats(MAP_CODE_CACHE_SUB_TYPE, cache->Size(), |
202 cache->Size()); | 272 0); |
203 } | 273 } |
204 } | 274 } |
205 | 275 |
206 void ObjectStatsCollector::RecordCodeStats(Map* map, HeapObject* obj) { | 276 void ObjectStatsCollector::RecordCodeDetails(ObjectStats* stats, Heap* heap, |
207 Heap* heap = map->GetHeap(); | 277 HeapObject* obj) { |
208 int object_size = obj->Size(); | 278 int object_size = obj->Size(); |
209 DCHECK(map->instance_type() == CODE_TYPE); | 279 DCHECK(obj->map()->instance_type() == CODE_TYPE); |
210 Code* code_obj = Code::cast(obj); | 280 Code* code_obj = Code::cast(obj); |
211 heap->object_stats_->RecordCodeSubTypeStats(code_obj->kind(), | 281 stats->RecordCodeSubTypeStats(code_obj->kind(), code_obj->GetAge(), |
212 code_obj->GetAge(), object_size); | 282 object_size); |
213 } | 283 Code* code = Code::cast(obj); |
214 | 284 if (code->deoptimization_data() != heap->empty_fixed_array()) { |
215 void ObjectStatsCollector::RecordSharedFunctionInfoStats(Map* map, | 285 stats->RecordFixedArraySubTypeStats(DEOPTIMIZATION_DATA_TYPE, |
216 HeapObject* obj) { | 286 code->deoptimization_data()->Size(), 0); |
217 Heap* heap = map->GetHeap(); | 287 } |
218 SharedFunctionInfo* sfi = SharedFunctionInfo::cast(obj); | 288 FixedArrayBase* reloc_info = |
219 if (sfi->scope_info() != heap->empty_fixed_array()) { | 289 reinterpret_cast<FixedArrayBase*>(code->unchecked_relocation_info()); |
220 heap->object_stats_->RecordFixedArraySubTypeStats( | 290 if (reloc_info != heap->empty_fixed_array()) { |
221 SCOPE_INFO_SUB_TYPE, FixedArray::cast(sfi->scope_info())->Size()); | 291 stats->RecordFixedArraySubTypeStats(RELOC_INFO_SUB_TYPE, |
| 292 code->relocation_info()->Size(), 0); |
| 293 } |
| 294 FixedArrayBase* source_pos_table = |
| 295 reinterpret_cast<FixedArrayBase*>(code->source_position_table()); |
| 296 if (source_pos_table != heap->empty_fixed_array()) { |
| 297 stats->RecordFixedArraySubTypeStats(SOURCE_POS_SUB_TYPE, |
| 298 source_pos_table->Size(), 0); |
222 } | 299 } |
223 } | 300 } |
224 | 301 |
225 void ObjectStatsCollector::RecordFixedArrayStats(Map* map, HeapObject* obj) { | 302 void ObjectStatsCollector::RecordSharedFunctionInfoDetails(ObjectStats* stats, |
226 Heap* heap = map->GetHeap(); | 303 Heap* heap, |
227 FixedArray* fixed_array = FixedArray::cast(obj); | 304 HeapObject* obj) { |
228 if (fixed_array == heap->string_table()) { | 305 SharedFunctionInfo* sfi = SharedFunctionInfo::cast(obj); |
229 heap->object_stats_->RecordFixedArraySubTypeStats(STRING_TABLE_SUB_TYPE, | 306 if (sfi->scope_info() != heap->empty_fixed_array()) { |
230 fixed_array->Size()); | 307 stats->RecordFixedArraySubTypeStats(SCOPE_INFO_SUB_TYPE, |
| 308 sfi->scope_info()->Size(), 0); |
| 309 } |
| 310 if (sfi->feedback_metadata() != heap->empty_fixed_array()) { |
| 311 stats->RecordFixedArraySubTypeStats(TYPE_FEEDBACK_METADATA_TYPE, |
| 312 sfi->feedback_metadata()->Size(), 0); |
231 } | 313 } |
232 } | 314 } |
233 | 315 |
234 void MarkCompactObjectStatsVisitor::Initialize( | 316 void ObjectStatsCollector::RecordFixedArrayDetails(ObjectStats* stats, |
235 VisitorDispatchTable<Callback>* original) { | 317 Heap* heap, |
236 // Copy the original visitor table to make call-through possible. After we | 318 HeapObject* obj) { |
237 // preserved a copy locally, we patch the original table to call us. | 319 FixedArray* fixed_array = FixedArray::cast(obj); |
238 table_.CopyFrom(original); | 320 if (fixed_array == heap->string_table()) { |
239 #define COUNT_FUNCTION(id) original->Register(kVisit##id, Visit<kVisit##id>); | 321 stats->RecordFixedArraySubTypeStats(STRING_TABLE_SUB_TYPE, |
240 VISITOR_ID_LIST(COUNT_FUNCTION) | 322 fixed_array->Size(), 0); |
241 #undef COUNT_FUNCTION | 323 } |
242 } | 324 if (fixed_array->map() == heap->fixed_cow_array_map()) { |
243 | 325 stats->RecordFixedArraySubTypeStats(COPY_ON_WRITE_SUB_TYPE, |
244 template <MarkCompactObjectStatsVisitor::VisitorId id> | 326 fixed_array->Size(), 0); |
245 void MarkCompactObjectStatsVisitor::Visit(Map* map, HeapObject* obj) { | 327 } |
246 ObjectStatsCollector::CollectStatistics(id, map, obj); | |
247 table_.GetVisitorById(id)(map, obj); | |
248 ObjectStatsCollector::CollectFixedArrayStatistics(obj); | |
249 } | |
250 | |
251 void IncrementalMarkingObjectStatsVisitor::Initialize( | |
252 VisitorDispatchTable<Callback>* original) { | |
253 // Copy the original visitor table to make call-through possible. After we | |
254 // preserved a copy locally, we patch the original table to call us. | |
255 table_.CopyFrom(original); | |
256 #define COUNT_FUNCTION(id) original->Register(kVisit##id, Visit<kVisit##id>); | |
257 VISITOR_ID_LIST(COUNT_FUNCTION) | |
258 #undef COUNT_FUNCTION | |
259 } | |
260 | |
261 template <IncrementalMarkingObjectStatsVisitor::VisitorId id> | |
262 void IncrementalMarkingObjectStatsVisitor::Visit(Map* map, HeapObject* obj) { | |
263 ObjectStatsCollector::CollectStatistics(id, map, obj); | |
264 table_.GetVisitorById(id)(map, obj); | |
265 ObjectStatsCollector::CollectFixedArrayStatistics(obj); | |
266 } | 328 } |
267 | 329 |
268 } // namespace internal | 330 } // namespace internal |
269 } // namespace v8 | 331 } // namespace v8 |
OLD | NEW |