| 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 |
| 27 | 30 static void PrintJSONArray(size_t* array, const int len) { |
| 28 void ObjectStats::TraceObjectStat(const char* name, int count, int size, | 31 PrintF("[ "); |
| 29 double time) { | 32 for (int i = 0; i < len; i++) { |
| 30 int ms_count = heap()->ms_count(); | 33 PrintF("%zu", array[i]); |
| 31 PrintIsolate(isolate(), | 34 if (i != (len - 1)) PrintF(", "); |
| 32 "heap:%p, time:%f, gc:%d, type:%s, count:%d, size:%d\n", | 35 } |
| 33 static_cast<void*>(heap()), time, ms_count, name, count, size); | 36 PrintF(" ]"); |
| 34 } | 37 } |
| 35 | 38 |
| 39 void ObjectStats::PrintJSON(const char* key) { |
| 40 double time = isolate()->time_millis_since_init(); |
| 41 int gc_count = heap()->gc_count(); |
| 36 | 42 |
| 37 void ObjectStats::TraceObjectStats() { | 43 #define PRINT_KEY_AND_ID() \ |
| 38 base::LockGuard<base::Mutex> lock_guard(object_stats_mutex.Pointer()); | 44 PrintF("\"isolate\": \"%p\", \"id\": %d, \"key\": \"%s\", ", \ |
| 39 int index; | 45 reinterpret_cast<void*>(isolate()), gc_count, key); |
| 40 int count; | 46 |
| 41 int size; | 47 // gc_descriptor |
| 42 int total_size = 0; | 48 PrintF("{ "); |
| 43 double time = isolate()->time_millis_since_init(); | 49 PRINT_KEY_AND_ID(); |
| 44 #define TRACE_OBJECT_COUNT(name) \ | 50 PrintF("\"type\": \"gc_descriptor\", \"time\": %f }\n", time); |
| 45 count = static_cast<int>(object_counts_[name]); \ | 51 // bucket_sizes |
| 46 size = static_cast<int>(object_sizes_[name]) / KB; \ | 52 PrintF("{ "); |
| 47 total_size += size; \ | 53 PRINT_KEY_AND_ID(); |
| 48 TraceObjectStat(#name, count, size, time); | 54 PrintF("\"type\": \"bucket_sizes\", \"sizes\": [ "); |
| 49 INSTANCE_TYPE_LIST(TRACE_OBJECT_COUNT) | 55 for (int i = 0; i < kNumberOfBuckets; i++) { |
| 50 #undef TRACE_OBJECT_COUNT | 56 PrintF("%d", 1 << (kFirstBucketShift + i)); |
| 51 #define TRACE_OBJECT_COUNT(name) \ | 57 if (i != (kNumberOfBuckets - 1)) PrintF(", "); |
| 52 index = FIRST_CODE_KIND_SUB_TYPE + Code::name; \ | 58 } |
| 53 count = static_cast<int>(object_counts_[index]); \ | 59 PrintF(" ] }\n"); |
| 54 size = static_cast<int>(object_sizes_[index]) / KB; \ | 60 // instance_type_data |
| 55 TraceObjectStat("*CODE_" #name, count, size, time); | 61 #define PRINT_INSTANCE_TYPE_DATA(name, index) \ |
| 56 CODE_KIND_LIST(TRACE_OBJECT_COUNT) | 62 PrintF("{ "); \ |
| 57 #undef TRACE_OBJECT_COUNT | 63 PRINT_KEY_AND_ID(); \ |
| 58 #define TRACE_OBJECT_COUNT(name) \ | 64 PrintF("\"type\": \"instance_type_data\", "); \ |
| 59 index = FIRST_FIXED_ARRAY_SUB_TYPE + name; \ | 65 PrintF("\"instance_type\": %d, ", index); \ |
| 60 count = static_cast<int>(object_counts_[index]); \ | 66 PrintF("\"instance_type_name\": \"%s\", ", name); \ |
| 61 size = static_cast<int>(object_sizes_[index]) / KB; \ | 67 PrintF("\"overall\": %zu, ", object_sizes_[index]); \ |
| 62 TraceObjectStat("*FIXED_ARRAY_" #name, count, size, time); | 68 PrintF("\"count\": %zu, ", object_counts_[index]); \ |
| 63 FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(TRACE_OBJECT_COUNT) | 69 PrintF("\"over_allocated\": %zu, ", over_allocated_[index]); \ |
| 64 #undef TRACE_OBJECT_COUNT | 70 PrintF("\"histogram\": "); \ |
| 65 #define TRACE_OBJECT_COUNT(name) \ | 71 PrintJSONArray(size_histogram_[index], kNumberOfBuckets); \ |
| 66 index = \ | 72 PrintF(","); \ |
| 67 FIRST_CODE_AGE_SUB_TYPE + Code::k##name##CodeAge - Code::kFirstCodeAge; \ | 73 PrintF("\"over_allocated_histogram\": "); \ |
| 68 count = static_cast<int>(object_counts_[index]); \ | 74 PrintJSONArray(over_allocated_histogram_[index], kNumberOfBuckets); \ |
| 69 size = static_cast<int>(object_sizes_[index]) / KB; \ | 75 PrintF(" }\n"); |
| 70 TraceObjectStat("*CODE_AGE_" #name, count, size, time); | 76 |
| 71 CODE_AGE_LIST_COMPLETE(TRACE_OBJECT_COUNT) | 77 #define INSTANCE_TYPE_WRAPPER(name) PRINT_INSTANCE_TYPE_DATA(#name, name) |
| 72 #undef TRACE_OBJECT_COUNT | 78 #define CODE_KIND_WRAPPER(name) \ |
| 79 PRINT_INSTANCE_TYPE_DATA("*CODE_" #name, \ |
| 80 FIRST_CODE_KIND_SUB_TYPE + Code::name) |
| 81 #define FIXED_ARRAY_SUB_INSTANCE_TYPE_WRAPPER(name) \ |
| 82 PRINT_INSTANCE_TYPE_DATA("*FIXED_ARRAY_" #name, \ |
| 83 FIRST_FIXED_ARRAY_SUB_TYPE + name) |
| 84 #define CODE_AGE_WRAPPER(name) \ |
| 85 PRINT_INSTANCE_TYPE_DATA( \ |
| 86 "*CODE_AGE_" #name, \ |
| 87 FIRST_CODE_AGE_SUB_TYPE + Code::k##name##CodeAge - Code::kFirstCodeAge) |
| 88 |
| 89 INSTANCE_TYPE_LIST(INSTANCE_TYPE_WRAPPER) |
| 90 CODE_KIND_LIST(CODE_KIND_WRAPPER) |
| 91 FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(FIXED_ARRAY_SUB_INSTANCE_TYPE_WRAPPER) |
| 92 CODE_AGE_LIST_COMPLETE(CODE_AGE_WRAPPER) |
| 93 |
| 94 #undef INSTANCE_TYPE_WRAPPER |
| 95 #undef CODE_KIND_WRAPPER |
| 96 #undef FIXED_ARRAY_SUB_INSTANCE_TYPE_WRAPPER |
| 97 #undef CODE_AGE_WRAPPER |
| 98 #undef PRINT_INSTANCE_TYPE_DATA |
| 73 } | 99 } |
| 74 | 100 |
| 75 | |
| 76 void ObjectStats::CheckpointObjectStats() { | 101 void ObjectStats::CheckpointObjectStats() { |
| 77 base::LockGuard<base::Mutex> lock_guard(object_stats_mutex.Pointer()); | 102 base::LockGuard<base::Mutex> lock_guard(object_stats_mutex.Pointer()); |
| 78 Counters* counters = isolate()->counters(); | 103 Counters* counters = isolate()->counters(); |
| 79 #define ADJUST_LAST_TIME_OBJECT_COUNT(name) \ | 104 #define ADJUST_LAST_TIME_OBJECT_COUNT(name) \ |
| 80 counters->count_of_##name()->Increment( \ | 105 counters->count_of_##name()->Increment( \ |
| 81 static_cast<int>(object_counts_[name])); \ | 106 static_cast<int>(object_counts_[name])); \ |
| 82 counters->count_of_##name()->Decrement( \ | 107 counters->count_of_##name()->Decrement( \ |
| 83 static_cast<int>(object_counts_last_time_[name])); \ | 108 static_cast<int>(object_counts_last_time_[name])); \ |
| 84 counters->size_of_##name()->Increment( \ | 109 counters->size_of_##name()->Increment( \ |
| 85 static_cast<int>(object_sizes_[name])); \ | 110 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 | 152 #undef ADJUST_LAST_TIME_OBJECT_COUNT |
| 128 | 153 |
| 129 MemCopy(object_counts_last_time_, object_counts_, sizeof(object_counts_)); | 154 MemCopy(object_counts_last_time_, object_counts_, sizeof(object_counts_)); |
| 130 MemCopy(object_sizes_last_time_, object_sizes_, sizeof(object_sizes_)); | 155 MemCopy(object_sizes_last_time_, object_sizes_, sizeof(object_sizes_)); |
| 131 ClearObjectStats(); | 156 ClearObjectStats(); |
| 132 } | 157 } |
| 133 | 158 |
| 134 | 159 |
| 135 Isolate* ObjectStats::isolate() { return heap()->isolate(); } | 160 Isolate* ObjectStats::isolate() { return heap()->isolate(); } |
| 136 | 161 |
| 137 void ObjectStatsCollector::CountFixedArray( | 162 void ObjectStatsCollector::CollectStatistics(ObjectStats* stats, |
| 138 FixedArrayBase* fixed_array, FixedArraySubInstanceType fast_type, | 163 HeapObject* obj) { |
| 139 FixedArraySubInstanceType dictionary_type) { | 164 Map* map = obj->map(); |
| 140 Heap* heap = fixed_array->map()->GetHeap(); | 165 Heap* heap = obj->GetHeap(); |
| 141 if (fixed_array->map() != heap->fixed_cow_array_map() && | 166 |
| 142 fixed_array->map() != heap->fixed_double_array_map() && | 167 // Record for the InstanceType. |
| 143 fixed_array != heap->empty_fixed_array()) { | 168 int object_size = obj->Size(); |
| 144 if (fixed_array->IsDictionary()) { | 169 stats->RecordObjectStats(map->instance_type(), object_size); |
| 145 heap->object_stats_->RecordFixedArraySubTypeStats(dictionary_type, | 170 |
| 146 fixed_array->Size()); | 171 // Record specific sub types where possible. |
| 172 if (obj->IsMap()) { |
| 173 RecordMapDetails(stats, heap, obj); |
| 174 } |
| 175 if (obj->IsCode()) { |
| 176 RecordCodeDetails(stats, heap, obj); |
| 177 } |
| 178 if (obj->IsSharedFunctionInfo()) { |
| 179 RecordSharedFunctionInfoDetails(stats, heap, obj); |
| 180 } |
| 181 if (obj->IsFixedArray()) { |
| 182 RecordFixedArrayDetails(stats, heap, obj); |
| 183 } |
| 184 if (obj->IsJSObject()) { |
| 185 RecordJSObjectDetails(stats, heap, JSObject::cast(obj)); |
| 186 } |
| 187 if (obj->IsJSWeakCollection()) { |
| 188 RecordJSWeakCollectionDetails(stats, heap, JSWeakCollection::cast(obj)); |
| 189 } |
| 190 } |
| 191 |
| 192 static bool CanRecordFixedArray(Heap* heap, FixedArrayBase* array) { |
| 193 return array->map() != heap->fixed_cow_array_map() && |
| 194 array->map() != heap->fixed_double_array_map() && |
| 195 array != heap->empty_fixed_array(); |
| 196 } |
| 197 |
| 198 void ObjectStatsCollector::RecordJSObjectDetails(ObjectStats* stats, Heap* heap, |
| 199 JSObject* object) { |
| 200 DCHECK(object->IsJSObject()); |
| 201 |
| 202 size_t overhead = 0; |
| 203 FixedArrayBase* elements = object->elements(); |
| 204 if (CanRecordFixedArray(heap, elements)) { |
| 205 if (elements->IsDictionary()) { |
| 206 SeededNumberDictionary* dict = object->element_dictionary(); |
| 207 int used = dict->NumberOfElements() * SeededNumberDictionary::kEntrySize; |
| 208 CHECK_GE(elements->Size(), used); |
| 209 overhead = elements->Size() - used; |
| 210 stats->RecordFixedArraySubTypeStats(DICTIONARY_ELEMENTS_SUB_TYPE, |
| 211 elements->Size(), overhead); |
| 147 } else { | 212 } else { |
| 148 heap->object_stats_->RecordFixedArraySubTypeStats(fast_type, | 213 if (IsFastHoleyElementsKind(object->GetElementsKind())) { |
| 149 fixed_array->Size()); | 214 int used = object->GetFastElementsUsage() * kPointerSize; |
| 150 } | 215 if (object->GetElementsKind() == FAST_HOLEY_DOUBLE_ELEMENTS) used *= 2; |
| 151 } | 216 CHECK_GE(elements->Size(), used); |
| 152 } | 217 overhead = elements->Size() - used; |
| 153 | 218 } |
| 154 void ObjectStatsCollector::CollectStatistics(StaticVisitorBase::VisitorId id, | 219 stats->RecordFixedArraySubTypeStats(FAST_ELEMENTS_SUB_TYPE, |
| 155 Map* map, HeapObject* obj) { | 220 elements->Size(), overhead); |
| 156 // Record any type specific statistics here. | 221 } |
| 157 switch (id) { | 222 } |
| 158 case StaticVisitorBase::kVisitMap: | 223 |
| 159 RecordMapStats(map, obj); | 224 overhead = 0; |
| 160 break; | 225 FixedArrayBase* properties = object->properties(); |
| 161 case StaticVisitorBase::kVisitCode: | 226 if (CanRecordFixedArray(heap, properties)) { |
| 162 RecordCodeStats(map, obj); | 227 if (properties->IsDictionary()) { |
| 163 break; | 228 NameDictionary* dict = object->property_dictionary(); |
| 164 case StaticVisitorBase::kVisitSharedFunctionInfo: | 229 int used = dict->NumberOfElements() * NameDictionary::kEntrySize; |
| 165 RecordSharedFunctionInfoStats(map, obj); | 230 CHECK_GE(properties->Size(), used); |
| 166 break; | 231 overhead = properties->Size() - used; |
| 167 case StaticVisitorBase::kVisitFixedArray: | 232 stats->RecordFixedArraySubTypeStats(DICTIONARY_PROPERTIES_SUB_TYPE, |
| 168 RecordFixedArrayStats(map, obj); | 233 properties->Size(), overhead); |
| 169 break; | 234 } else { |
| 170 default: | 235 stats->RecordFixedArraySubTypeStats(FAST_PROPERTIES_SUB_TYPE, |
| 171 break; | 236 properties->Size(), overhead); |
| 172 } | 237 } |
| 173 | 238 } |
| 174 Heap* heap = map->GetHeap(); | 239 } |
| 175 int object_size = obj->Size(); | 240 |
| 176 heap->object_stats_->RecordObjectStats(map->instance_type(), object_size); | 241 void ObjectStatsCollector::RecordJSWeakCollectionDetails( |
| 177 } | 242 ObjectStats* stats, Heap* heap, JSWeakCollection* obj) { |
| 178 | 243 if (obj->table()->IsHashTable()) { |
| 179 void ObjectStatsCollector::CollectFixedArrayStatistics(HeapObject* obj) { | 244 ObjectHashTable* table = ObjectHashTable::cast(obj->table()); |
| 180 if (obj->IsJSObject()) { | 245 int used = table->NumberOfElements() * ObjectHashTable::kEntrySize; |
| 181 JSObject* object = JSObject::cast(obj); | 246 size_t overhead = table->Size() - used; |
| 182 CountFixedArray(object->elements(), DICTIONARY_ELEMENTS_SUB_TYPE, | 247 stats->RecordFixedArraySubTypeStats(WEAK_COLLECTION_SUB_TYPE, table->Size(), |
| 183 FAST_ELEMENTS_SUB_TYPE); | 248 overhead); |
| 184 CountFixedArray(object->properties(), DICTIONARY_PROPERTIES_SUB_TYPE, | 249 } |
| 185 FAST_PROPERTIES_SUB_TYPE); | 250 } |
| 186 } | 251 |
| 187 } | 252 void ObjectStatsCollector::RecordMapDetails(ObjectStats* stats, Heap* heap, |
| 188 | 253 HeapObject* obj) { |
| 189 void ObjectStatsCollector::RecordMapStats(Map* map, HeapObject* obj) { | |
| 190 Heap* heap = map->GetHeap(); | |
| 191 Map* map_obj = Map::cast(obj); | 254 Map* map_obj = Map::cast(obj); |
| 192 DCHECK(map->instance_type() == MAP_TYPE); | 255 DCHECK(obj->map()->instance_type() == MAP_TYPE); |
| 193 DescriptorArray* array = map_obj->instance_descriptors(); | 256 DescriptorArray* array = map_obj->instance_descriptors(); |
| 194 if (map_obj->owns_descriptors() && array != heap->empty_descriptor_array()) { | 257 if (map_obj->owns_descriptors() && array != heap->empty_descriptor_array()) { |
| 195 int fixed_array_size = array->Size(); | 258 int fixed_array_size = array->Size(); |
| 196 heap->object_stats_->RecordFixedArraySubTypeStats(DESCRIPTOR_ARRAY_SUB_TYPE, | 259 stats->RecordFixedArraySubTypeStats(DESCRIPTOR_ARRAY_SUB_TYPE, |
| 197 fixed_array_size); | 260 fixed_array_size, 0); |
| 198 } | 261 if (array->HasEnumCache()) { |
| 262 stats->RecordFixedArraySubTypeStats(ENUM_CACHE_SUB_TYPE, |
| 263 array->GetEnumCache()->Size(), 0); |
| 264 } |
| 265 if (array->HasEnumIndicesCache()) { |
| 266 stats->RecordFixedArraySubTypeStats( |
| 267 ENUM_INDICES_CACHE_SUB_TYPE, array->GetEnumIndicesCache()->Size(), 0); |
| 268 } |
| 269 } |
| 270 |
| 199 if (map_obj->has_code_cache()) { | 271 if (map_obj->has_code_cache()) { |
| 200 FixedArray* cache = map_obj->code_cache(); | 272 FixedArray* cache = map_obj->code_cache(); |
| 201 heap->object_stats_->RecordFixedArraySubTypeStats(MAP_CODE_CACHE_SUB_TYPE, | 273 stats->RecordFixedArraySubTypeStats(MAP_CODE_CACHE_SUB_TYPE, cache->Size(), |
| 202 cache->Size()); | 274 0); |
| 203 } | 275 } |
| 204 } | 276 } |
| 205 | 277 |
| 206 void ObjectStatsCollector::RecordCodeStats(Map* map, HeapObject* obj) { | 278 void ObjectStatsCollector::RecordCodeDetails(ObjectStats* stats, Heap* heap, |
| 207 Heap* heap = map->GetHeap(); | 279 HeapObject* obj) { |
| 208 int object_size = obj->Size(); | 280 int object_size = obj->Size(); |
| 209 DCHECK(map->instance_type() == CODE_TYPE); | 281 DCHECK(obj->map()->instance_type() == CODE_TYPE); |
| 210 Code* code_obj = Code::cast(obj); | 282 Code* code_obj = Code::cast(obj); |
| 211 heap->object_stats_->RecordCodeSubTypeStats(code_obj->kind(), | 283 stats->RecordCodeSubTypeStats(code_obj->kind(), code_obj->GetAge(), |
| 212 code_obj->GetAge(), object_size); | 284 object_size); |
| 213 } | 285 Code* code = Code::cast(obj); |
| 214 | 286 if (code->deoptimization_data() != heap->empty_fixed_array()) { |
| 215 void ObjectStatsCollector::RecordSharedFunctionInfoStats(Map* map, | 287 stats->RecordFixedArraySubTypeStats(DEOPTIMIZATION_DATA_SUB_TYPE, |
| 216 HeapObject* obj) { | 288 code->deoptimization_data()->Size(), 0); |
| 217 Heap* heap = map->GetHeap(); | 289 } |
| 290 FixedArrayBase* reloc_info = |
| 291 reinterpret_cast<FixedArrayBase*>(code->unchecked_relocation_info()); |
| 292 if (reloc_info != heap->empty_fixed_array()) { |
| 293 stats->RecordFixedArraySubTypeStats(RELOC_INFO_SUB_TYPE, |
| 294 code->relocation_info()->Size(), 0); |
| 295 } |
| 296 FixedArrayBase* source_pos_table = |
| 297 reinterpret_cast<FixedArrayBase*>(code->source_position_table()); |
| 298 if (source_pos_table != heap->empty_fixed_array()) { |
| 299 stats->RecordFixedArraySubTypeStats(SOURCE_POS_SUB_TYPE, |
| 300 source_pos_table->Size(), 0); |
| 301 } |
| 302 } |
| 303 |
| 304 void ObjectStatsCollector::RecordSharedFunctionInfoDetails(ObjectStats* stats, |
| 305 Heap* heap, |
| 306 HeapObject* obj) { |
| 218 SharedFunctionInfo* sfi = SharedFunctionInfo::cast(obj); | 307 SharedFunctionInfo* sfi = SharedFunctionInfo::cast(obj); |
| 219 if (sfi->scope_info() != heap->empty_fixed_array()) { | 308 if (sfi->scope_info() != heap->empty_fixed_array()) { |
| 220 heap->object_stats_->RecordFixedArraySubTypeStats( | 309 stats->RecordFixedArraySubTypeStats(SCOPE_INFO_SUB_TYPE, |
| 221 SCOPE_INFO_SUB_TYPE, FixedArray::cast(sfi->scope_info())->Size()); | 310 sfi->scope_info()->Size(), 0); |
| 222 } | 311 } |
| 223 } | 312 if (sfi->feedback_metadata() != heap->empty_fixed_array()) { |
| 224 | 313 stats->RecordFixedArraySubTypeStats(TYPE_FEEDBACK_METADATA_SUB_TYPE, |
| 225 void ObjectStatsCollector::RecordFixedArrayStats(Map* map, HeapObject* obj) { | 314 sfi->feedback_metadata()->Size(), 0); |
| 226 Heap* heap = map->GetHeap(); | 315 } |
| 316 if (!sfi->OptimizedCodeMapIsCleared()) { |
| 317 FixedArray* optimized_code_map = sfi->optimized_code_map(); |
| 318 // Optimized code map should be small, so skip accounting. |
| 319 int len = optimized_code_map->length(); |
| 320 for (int i = SharedFunctionInfo::kEntriesStart; i < len; |
| 321 i += SharedFunctionInfo::kEntryLength) { |
| 322 Object* slot = |
| 323 optimized_code_map->get(i + SharedFunctionInfo::kLiteralsOffset); |
| 324 LiteralsArray* literals = nullptr; |
| 325 if (slot->IsWeakCell()) { |
| 326 WeakCell* cell = WeakCell::cast(slot); |
| 327 if (!cell->cleared()) { |
| 328 literals = LiteralsArray::cast(cell->value()); |
| 329 } |
| 330 } else { |
| 331 literals = LiteralsArray::cast(slot); |
| 332 } |
| 333 if (literals != nullptr) { |
| 334 stats->RecordFixedArraySubTypeStats(LITERALS_ARRAY_SUB_TYPE, |
| 335 literals->Size(), 0); |
| 336 TypeFeedbackVector* tfv = literals->feedback_vector(); |
| 337 |
| 338 stats->RecordFixedArraySubTypeStats(TYPE_FEEDBACK_VECTOR_SUB_TYPE, |
| 339 tfv->Size(), 0); |
| 340 } |
| 341 } |
| 342 } |
| 343 } |
| 344 |
| 345 void ObjectStatsCollector::RecordFixedArrayDetails(ObjectStats* stats, |
| 346 Heap* heap, |
| 347 HeapObject* obj) { |
| 227 FixedArray* fixed_array = FixedArray::cast(obj); | 348 FixedArray* fixed_array = FixedArray::cast(obj); |
| 228 if (fixed_array == heap->string_table()) { | 349 if (fixed_array == heap->string_table()) { |
| 229 heap->object_stats_->RecordFixedArraySubTypeStats(STRING_TABLE_SUB_TYPE, | 350 stats->RecordFixedArraySubTypeStats(STRING_TABLE_SUB_TYPE, |
| 230 fixed_array->Size()); | 351 fixed_array->Size(), 0); |
| 231 } | 352 } |
| 232 } | 353 if (fixed_array == heap->weak_object_to_code_table()) { |
| 233 | 354 WeakHashTable* table = reinterpret_cast<WeakHashTable*>(fixed_array); |
| 234 void MarkCompactObjectStatsVisitor::Initialize( | 355 int used = table->NumberOfElements() * WeakHashTable::kEntrySize; |
| 235 VisitorDispatchTable<Callback>* original) { | 356 CHECK_GE(fixed_array->Size(), used); |
| 236 // Copy the original visitor table to make call-through possible. After we | 357 size_t overhead = fixed_array->Size() - used; |
| 237 // preserved a copy locally, we patch the original table to call us. | 358 stats->RecordFixedArraySubTypeStats(OBJECT_TO_CODE_SUB_TYPE, |
| 238 table_.CopyFrom(original); | 359 fixed_array->Size(), overhead); |
| 239 #define COUNT_FUNCTION(id) original->Register(kVisit##id, Visit<kVisit##id>); | 360 } |
| 240 VISITOR_ID_LIST(COUNT_FUNCTION) | 361 if (obj->IsContext()) { |
| 241 #undef COUNT_FUNCTION | 362 stats->RecordFixedArraySubTypeStats(CONTEXT_SUB_TYPE, fixed_array->Size(), |
| 242 } | 363 0); |
| 243 | 364 } |
| 244 template <MarkCompactObjectStatsVisitor::VisitorId id> | 365 if (fixed_array->map() == heap->fixed_cow_array_map()) { |
| 245 void MarkCompactObjectStatsVisitor::Visit(Map* map, HeapObject* obj) { | 366 stats->RecordFixedArraySubTypeStats(COPY_ON_WRITE_SUB_TYPE, |
| 246 ObjectStatsCollector::CollectStatistics(id, map, obj); | 367 fixed_array->Size(), 0); |
| 247 table_.GetVisitorById(id)(map, obj); | 368 } |
| 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 } | 369 } |
| 267 | 370 |
| 268 } // namespace internal | 371 } // namespace internal |
| 269 } // namespace v8 | 372 } // namespace v8 |
| OLD | NEW |