Line data Source code
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
3 : // found in the LICENSE file.
4 :
5 : #include "src/heap/object-stats.h"
6 :
7 : #include "src/assembler-inl.h"
8 : #include "src/compilation-cache.h"
9 : #include "src/counters.h"
10 : #include "src/heap/heap-inl.h"
11 : #include "src/isolate.h"
12 : #include "src/objects/compilation-cache-inl.h"
13 : #include "src/utils.h"
14 :
15 : namespace v8 {
16 : namespace internal {
17 :
18 : static base::LazyMutex object_stats_mutex = LAZY_MUTEX_INITIALIZER;
19 :
20 :
21 0 : void ObjectStats::ClearObjectStats(bool clear_last_time_stats) {
22 0 : memset(object_counts_, 0, sizeof(object_counts_));
23 0 : memset(object_sizes_, 0, sizeof(object_sizes_));
24 0 : memset(over_allocated_, 0, sizeof(over_allocated_));
25 0 : memset(size_histogram_, 0, sizeof(size_histogram_));
26 0 : memset(over_allocated_histogram_, 0, sizeof(over_allocated_histogram_));
27 0 : if (clear_last_time_stats) {
28 0 : memset(object_counts_last_time_, 0, sizeof(object_counts_last_time_));
29 0 : memset(object_sizes_last_time_, 0, sizeof(object_sizes_last_time_));
30 : }
31 : visited_fixed_array_sub_types_.clear();
32 0 : }
33 :
34 : // Tell the compiler to never inline this: occasionally, the optimizer will
35 : // decide to inline this and unroll the loop, making the compiled code more than
36 : // 100KB larger.
37 0 : V8_NOINLINE static void PrintJSONArray(size_t* array, const int len) {
38 0 : PrintF("[ ");
39 0 : for (int i = 0; i < len; i++) {
40 0 : PrintF("%zu", array[i]);
41 0 : if (i != (len - 1)) PrintF(", ");
42 : }
43 0 : PrintF(" ]");
44 0 : }
45 :
46 0 : V8_NOINLINE static void DumpJSONArray(std::stringstream& stream, size_t* array,
47 : const int len) {
48 0 : stream << "[";
49 0 : for (int i = 0; i < len; i++) {
50 0 : stream << array[i];
51 0 : if (i != (len - 1)) stream << ",";
52 : }
53 0 : stream << "]";
54 0 : }
55 :
56 0 : void ObjectStats::PrintKeyAndId(const char* key, int gc_count) {
57 : PrintF("\"isolate\": \"%p\", \"id\": %d, \"key\": \"%s\", ",
58 0 : reinterpret_cast<void*>(isolate()), gc_count, key);
59 0 : }
60 :
61 0 : void ObjectStats::PrintInstanceTypeJSON(const char* key, int gc_count,
62 : const char* name, int index) {
63 0 : PrintF("{ ");
64 : PrintKeyAndId(key, gc_count);
65 0 : PrintF("\"type\": \"instance_type_data\", ");
66 0 : PrintF("\"instance_type\": %d, ", index);
67 0 : PrintF("\"instance_type_name\": \"%s\", ", name);
68 0 : PrintF("\"overall\": %zu, ", object_sizes_[index]);
69 0 : PrintF("\"count\": %zu, ", object_counts_[index]);
70 0 : PrintF("\"over_allocated\": %zu, ", over_allocated_[index]);
71 0 : PrintF("\"histogram\": ");
72 0 : PrintJSONArray(size_histogram_[index], kNumberOfBuckets);
73 0 : PrintF(",");
74 0 : PrintF("\"over_allocated_histogram\": ");
75 0 : PrintJSONArray(over_allocated_histogram_[index], kNumberOfBuckets);
76 0 : PrintF(" }\n");
77 0 : }
78 :
79 0 : void ObjectStats::PrintJSON(const char* key) {
80 : double time = isolate()->time_millis_since_init();
81 0 : int gc_count = heap()->gc_count();
82 :
83 : // gc_descriptor
84 0 : PrintF("{ ");
85 : PrintKeyAndId(key, gc_count);
86 0 : PrintF("\"type\": \"gc_descriptor\", \"time\": %f }\n", time);
87 : // bucket_sizes
88 0 : PrintF("{ ");
89 : PrintKeyAndId(key, gc_count);
90 0 : PrintF("\"type\": \"bucket_sizes\", \"sizes\": [ ");
91 0 : for (int i = 0; i < kNumberOfBuckets; i++) {
92 0 : PrintF("%d", 1 << (kFirstBucketShift + i));
93 0 : if (i != (kNumberOfBuckets - 1)) PrintF(", ");
94 : }
95 0 : PrintF(" ] }\n");
96 :
97 : #define INSTANCE_TYPE_WRAPPER(name) \
98 : PrintInstanceTypeJSON(key, gc_count, #name, name);
99 : #define CODE_KIND_WRAPPER(name) \
100 : PrintInstanceTypeJSON(key, gc_count, "*CODE_" #name, \
101 : FIRST_CODE_KIND_SUB_TYPE + Code::name);
102 : #define FIXED_ARRAY_SUB_INSTANCE_TYPE_WRAPPER(name) \
103 : PrintInstanceTypeJSON(key, gc_count, "*FIXED_ARRAY_" #name, \
104 : FIRST_FIXED_ARRAY_SUB_TYPE + name);
105 :
106 0 : INSTANCE_TYPE_LIST(INSTANCE_TYPE_WRAPPER)
107 0 : CODE_KIND_LIST(CODE_KIND_WRAPPER)
108 0 : FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(FIXED_ARRAY_SUB_INSTANCE_TYPE_WRAPPER)
109 :
110 : #undef INSTANCE_TYPE_WRAPPER
111 : #undef CODE_KIND_WRAPPER
112 : #undef FIXED_ARRAY_SUB_INSTANCE_TYPE_WRAPPER
113 : #undef PRINT_INSTANCE_TYPE_DATA
114 : #undef PRINT_KEY_AND_ID
115 0 : }
116 :
117 0 : void ObjectStats::DumpInstanceTypeData(std::stringstream& stream,
118 : const char* name, int index) {
119 0 : stream << "\"" << name << "\":{";
120 0 : stream << "\"type\":" << static_cast<int>(index) << ",";
121 0 : stream << "\"overall\":" << object_sizes_[index] << ",";
122 0 : stream << "\"count\":" << object_counts_[index] << ",";
123 0 : stream << "\"over_allocated\":" << over_allocated_[index] << ",";
124 0 : stream << "\"histogram\":";
125 0 : DumpJSONArray(stream, size_histogram_[index], kNumberOfBuckets);
126 0 : stream << ",\"over_allocated_histogram\":";
127 0 : DumpJSONArray(stream, over_allocated_histogram_[index], kNumberOfBuckets);
128 0 : stream << "},";
129 0 : }
130 :
131 0 : void ObjectStats::Dump(std::stringstream& stream) {
132 : double time = isolate()->time_millis_since_init();
133 0 : int gc_count = heap()->gc_count();
134 :
135 0 : stream << "{";
136 0 : stream << "\"isolate\":\"" << reinterpret_cast<void*>(isolate()) << "\",";
137 0 : stream << "\"id\":" << gc_count << ",";
138 0 : stream << "\"time\":" << time << ",";
139 0 : stream << "\"bucket_sizes\":[";
140 0 : for (int i = 0; i < kNumberOfBuckets; i++) {
141 0 : stream << (1 << (kFirstBucketShift + i));
142 0 : if (i != (kNumberOfBuckets - 1)) stream << ",";
143 : }
144 0 : stream << "],";
145 0 : stream << "\"type_data\":{";
146 :
147 : #define INSTANCE_TYPE_WRAPPER(name) DumpInstanceTypeData(stream, #name, name);
148 : #define CODE_KIND_WRAPPER(name) \
149 : DumpInstanceTypeData(stream, "*CODE_" #name, \
150 : FIRST_CODE_KIND_SUB_TYPE + Code::name);
151 :
152 : #define FIXED_ARRAY_SUB_INSTANCE_TYPE_WRAPPER(name) \
153 : DumpInstanceTypeData(stream, "*FIXED_ARRAY_" #name, \
154 : FIRST_FIXED_ARRAY_SUB_TYPE + name);
155 :
156 0 : INSTANCE_TYPE_LIST(INSTANCE_TYPE_WRAPPER);
157 0 : CODE_KIND_LIST(CODE_KIND_WRAPPER);
158 0 : FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(FIXED_ARRAY_SUB_INSTANCE_TYPE_WRAPPER);
159 0 : stream << "\"END\":{}}}";
160 :
161 : #undef INSTANCE_TYPE_WRAPPER
162 : #undef CODE_KIND_WRAPPER
163 : #undef FIXED_ARRAY_SUB_INSTANCE_TYPE_WRAPPER
164 : #undef PRINT_INSTANCE_TYPE_DATA
165 0 : }
166 :
167 0 : void ObjectStats::CheckpointObjectStats() {
168 : base::LockGuard<base::Mutex> lock_guard(object_stats_mutex.Pointer());
169 : Counters* counters = isolate()->counters();
170 : #define ADJUST_LAST_TIME_OBJECT_COUNT(name) \
171 : counters->count_of_##name()->Increment( \
172 : static_cast<int>(object_counts_[name])); \
173 : counters->count_of_##name()->Decrement( \
174 : static_cast<int>(object_counts_last_time_[name])); \
175 : counters->size_of_##name()->Increment( \
176 : static_cast<int>(object_sizes_[name])); \
177 : counters->size_of_##name()->Decrement( \
178 : static_cast<int>(object_sizes_last_time_[name]));
179 0 : INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
180 : #undef ADJUST_LAST_TIME_OBJECT_COUNT
181 : int index;
182 : #define ADJUST_LAST_TIME_OBJECT_COUNT(name) \
183 : index = FIRST_CODE_KIND_SUB_TYPE + Code::name; \
184 : counters->count_of_CODE_TYPE_##name()->Increment( \
185 : static_cast<int>(object_counts_[index])); \
186 : counters->count_of_CODE_TYPE_##name()->Decrement( \
187 : static_cast<int>(object_counts_last_time_[index])); \
188 : counters->size_of_CODE_TYPE_##name()->Increment( \
189 : static_cast<int>(object_sizes_[index])); \
190 : counters->size_of_CODE_TYPE_##name()->Decrement( \
191 : static_cast<int>(object_sizes_last_time_[index]));
192 0 : CODE_KIND_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
193 : #undef ADJUST_LAST_TIME_OBJECT_COUNT
194 : #define ADJUST_LAST_TIME_OBJECT_COUNT(name) \
195 : index = FIRST_FIXED_ARRAY_SUB_TYPE + name; \
196 : counters->count_of_FIXED_ARRAY_##name()->Increment( \
197 : static_cast<int>(object_counts_[index])); \
198 : counters->count_of_FIXED_ARRAY_##name()->Decrement( \
199 : static_cast<int>(object_counts_last_time_[index])); \
200 : counters->size_of_FIXED_ARRAY_##name()->Increment( \
201 : static_cast<int>(object_sizes_[index])); \
202 : counters->size_of_FIXED_ARRAY_##name()->Decrement( \
203 : static_cast<int>(object_sizes_last_time_[index]));
204 0 : FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
205 : #undef ADJUST_LAST_TIME_OBJECT_COUNT
206 :
207 0 : MemCopy(object_counts_last_time_, object_counts_, sizeof(object_counts_));
208 0 : MemCopy(object_sizes_last_time_, object_sizes_, sizeof(object_sizes_));
209 0 : ClearObjectStats();
210 0 : }
211 :
212 :
213 0 : Isolate* ObjectStats::isolate() { return heap()->isolate(); }
214 :
215 0 : ObjectStatsCollector::ObjectStatsCollector(Heap* heap, ObjectStats* stats)
216 : : heap_(heap),
217 : stats_(stats),
218 : marking_state_(
219 0 : heap->mark_compact_collector()->non_atomic_marking_state()) {}
220 :
221 0 : void ObjectStatsCollector::CollectStatistics(HeapObject* obj) {
222 : Map* map = obj->map();
223 :
224 : // Record for the InstanceType.
225 0 : int object_size = obj->Size();
226 0 : stats_->RecordObjectStats(map->instance_type(), object_size);
227 :
228 : // Record specific sub types where possible.
229 0 : if (obj->IsMap()) RecordMapDetails(Map::cast(obj));
230 0 : if (obj->IsObjectTemplateInfo() || obj->IsFunctionTemplateInfo()) {
231 0 : RecordTemplateInfoDetails(TemplateInfo::cast(obj));
232 : }
233 0 : if (obj->IsBytecodeArray()) {
234 0 : RecordBytecodeArrayDetails(BytecodeArray::cast(obj));
235 : }
236 0 : if (obj->IsCode()) RecordCodeDetails(Code::cast(obj));
237 0 : if (obj->IsSharedFunctionInfo()) {
238 0 : RecordSharedFunctionInfoDetails(SharedFunctionInfo::cast(obj));
239 : }
240 0 : if (obj->IsFixedArray()) RecordFixedArrayDetails(FixedArray::cast(obj));
241 0 : if (obj->IsJSObject()) RecordJSObjectDetails(JSObject::cast(obj));
242 0 : if (obj->IsJSWeakCollection()) {
243 0 : RecordJSWeakCollectionDetails(JSWeakCollection::cast(obj));
244 : }
245 0 : if (obj->IsJSCollection()) {
246 0 : RecordJSCollectionDetails(JSObject::cast(obj));
247 : }
248 0 : if (obj->IsScript()) RecordScriptDetails(Script::cast(obj));
249 0 : }
250 :
251 0 : class ObjectStatsCollector::CompilationCacheTableVisitor : public RootVisitor {
252 : public:
253 : explicit CompilationCacheTableVisitor(ObjectStatsCollector* parent)
254 0 : : parent_(parent) {}
255 :
256 0 : void VisitRootPointers(Root root, Object** start, Object** end) override {
257 0 : for (Object** current = start; current < end; current++) {
258 0 : HeapObject* obj = HeapObject::cast(*current);
259 0 : if (obj->IsUndefined(parent_->heap_->isolate())) continue;
260 0 : CHECK(obj->IsCompilationCacheTable());
261 : parent_->RecordHashTableHelper(nullptr, CompilationCacheTable::cast(obj),
262 0 : COMPILATION_CACHE_TABLE_SUB_TYPE);
263 : }
264 0 : }
265 :
266 : private:
267 : ObjectStatsCollector* parent_;
268 : };
269 :
270 0 : void ObjectStatsCollector::CollectGlobalStatistics() {
271 : // Global FixedArrays.
272 0 : RecordFixedArrayHelper(nullptr, heap_->weak_new_space_object_to_code_list(),
273 0 : WEAK_NEW_SPACE_OBJECT_TO_CODE_SUB_TYPE, 0);
274 : RecordFixedArrayHelper(nullptr, heap_->serialized_templates(),
275 0 : SERIALIZED_TEMPLATES_SUB_TYPE, 0);
276 : RecordFixedArrayHelper(nullptr, heap_->number_string_cache(),
277 0 : NUMBER_STRING_CACHE_SUB_TYPE, 0);
278 : RecordFixedArrayHelper(nullptr, heap_->single_character_string_cache(),
279 0 : SINGLE_CHARACTER_STRING_CACHE_SUB_TYPE, 0);
280 : RecordFixedArrayHelper(nullptr, heap_->string_split_cache(),
281 0 : STRING_SPLIT_CACHE_SUB_TYPE, 0);
282 : RecordFixedArrayHelper(nullptr, heap_->regexp_multiple_cache(),
283 0 : REGEXP_MULTIPLE_CACHE_SUB_TYPE, 0);
284 0 : RecordFixedArrayHelper(nullptr, heap_->retained_maps(),
285 0 : RETAINED_MAPS_SUB_TYPE, 0);
286 :
287 : // Global weak FixedArrays.
288 : RecordFixedArrayHelper(
289 0 : nullptr, WeakFixedArray::cast(heap_->noscript_shared_function_infos()),
290 0 : NOSCRIPT_SHARED_FUNCTION_INFOS_SUB_TYPE, 0);
291 0 : RecordFixedArrayHelper(nullptr, WeakFixedArray::cast(heap_->script_list()),
292 0 : SCRIPT_LIST_SUB_TYPE, 0);
293 :
294 : // Global hash tables.
295 0 : RecordHashTableHelper(nullptr, heap_->string_table(), STRING_TABLE_SUB_TYPE);
296 : RecordHashTableHelper(nullptr, heap_->weak_object_to_code_table(),
297 0 : OBJECT_TO_CODE_SUB_TYPE);
298 : RecordHashTableHelper(nullptr, heap_->code_stubs(),
299 0 : CODE_STUBS_TABLE_SUB_TYPE);
300 : RecordHashTableHelper(nullptr, heap_->empty_property_dictionary(),
301 0 : EMPTY_PROPERTIES_DICTIONARY_SUB_TYPE);
302 0 : CompilationCache* compilation_cache = heap_->isolate()->compilation_cache();
303 : CompilationCacheTableVisitor v(this);
304 0 : compilation_cache->Iterate(&v);
305 0 : }
306 :
307 0 : static bool CanRecordFixedArray(Heap* heap, FixedArrayBase* array) {
308 0 : return (array->map()->instance_type() == FIXED_ARRAY_TYPE ||
309 0 : array->map()->instance_type() == HASH_TABLE_TYPE) &&
310 0 : array->map() != heap->fixed_double_array_map() &&
311 0 : array != heap->empty_fixed_array() &&
312 0 : array != heap->empty_byte_array() &&
313 0 : array != heap->empty_sloppy_arguments_elements() &&
314 0 : array != heap->empty_slow_element_dictionary() &&
315 0 : array != heap->empty_descriptor_array() &&
316 0 : array != heap->empty_property_dictionary();
317 : }
318 :
319 0 : static bool IsCowArray(Heap* heap, FixedArrayBase* array) {
320 : return array->map() == heap->fixed_cow_array_map();
321 : }
322 :
323 0 : bool ObjectStatsCollector::SameLiveness(HeapObject* obj1, HeapObject* obj2) {
324 0 : return obj1 == nullptr || obj2 == nullptr ||
325 0 : marking_state_->Color(obj1) == marking_state_->Color(obj2);
326 : }
327 :
328 0 : bool ObjectStatsCollector::RecordFixedArrayHelper(HeapObject* parent,
329 : FixedArray* array,
330 : int subtype,
331 : size_t overhead) {
332 0 : if (SameLiveness(parent, array) && CanRecordFixedArray(heap_, array) &&
333 0 : !IsCowArray(heap_, array)) {
334 0 : return stats_->RecordFixedArraySubTypeStats(array, subtype, array->Size(),
335 0 : overhead);
336 : }
337 : return false;
338 : }
339 :
340 0 : void ObjectStatsCollector::RecursivelyRecordFixedArrayHelper(HeapObject* parent,
341 : FixedArray* array,
342 : int subtype) {
343 0 : if (RecordFixedArrayHelper(parent, array, subtype, 0)) {
344 0 : for (int i = 0; i < array->length(); i++) {
345 0 : if (array->get(i)->IsFixedArray()) {
346 : RecursivelyRecordFixedArrayHelper(
347 0 : parent, FixedArray::cast(array->get(i)), subtype);
348 : }
349 : }
350 : }
351 0 : }
352 :
353 : template <class HashTable>
354 0 : void ObjectStatsCollector::RecordHashTableHelper(HeapObject* parent,
355 : HashTable* array,
356 : int subtype) {
357 0 : int used = array->NumberOfElements() * HashTable::kEntrySize * kPointerSize;
358 0 : CHECK_GE(array->Size(), used);
359 0 : size_t overhead = array->Size() - used -
360 : HashTable::kElementsStartIndex * kPointerSize -
361 0 : FixedArray::kHeaderSize;
362 0 : RecordFixedArrayHelper(parent, array, subtype, overhead);
363 0 : }
364 :
365 0 : void ObjectStatsCollector::RecordJSObjectDetails(JSObject* object) {
366 : size_t overhead = 0;
367 : FixedArrayBase* elements = object->elements();
368 0 : if (CanRecordFixedArray(heap_, elements) && !IsCowArray(heap_, elements)) {
369 0 : if (elements->IsDictionary() && SameLiveness(object, elements)) {
370 : SeededNumberDictionary* dict = SeededNumberDictionary::cast(elements);
371 0 : RecordHashTableHelper(object, dict, DICTIONARY_ELEMENTS_SUB_TYPE);
372 : } else {
373 0 : if (IsHoleyElementsKind(object->GetElementsKind())) {
374 0 : int used = object->GetFastElementsUsage() * kPointerSize;
375 0 : if (object->GetElementsKind() == HOLEY_DOUBLE_ELEMENTS) used *= 2;
376 0 : CHECK_GE(elements->Size(), used);
377 0 : overhead = elements->Size() - used - FixedArray::kHeaderSize;
378 : }
379 : stats_->RecordFixedArraySubTypeStats(elements, PACKED_ELEMENTS_SUB_TYPE,
380 0 : elements->Size(), overhead);
381 : }
382 : }
383 :
384 0 : if (object->IsJSGlobalObject()) {
385 : GlobalDictionary* properties =
386 : JSGlobalObject::cast(object)->global_dictionary();
387 0 : if (CanRecordFixedArray(heap_, properties) &&
388 0 : SameLiveness(object, properties)) {
389 0 : RecordHashTableHelper(object, properties, DICTIONARY_PROPERTIES_SUB_TYPE);
390 : }
391 0 : } else if (!object->HasFastProperties()) {
392 : NameDictionary* properties = object->property_dictionary();
393 0 : if (CanRecordFixedArray(heap_, properties) &&
394 0 : SameLiveness(object, properties)) {
395 0 : RecordHashTableHelper(object, properties, DICTIONARY_PROPERTIES_SUB_TYPE);
396 : }
397 : }
398 0 : }
399 :
400 0 : void ObjectStatsCollector::RecordJSWeakCollectionDetails(
401 : JSWeakCollection* obj) {
402 0 : if (obj->table()->IsHashTable()) {
403 : ObjectHashTable* table = ObjectHashTable::cast(obj->table());
404 0 : int used = table->NumberOfElements() * ObjectHashTable::kEntrySize;
405 0 : size_t overhead = table->Size() - used;
406 0 : RecordFixedArrayHelper(obj, table, JS_WEAK_COLLECTION_SUB_TYPE, overhead);
407 : }
408 0 : }
409 :
410 0 : void ObjectStatsCollector::RecordJSCollectionDetails(JSObject* obj) {
411 : // The JS versions use a different HashTable implementation that cannot use
412 : // the regular helper. Since overall impact is usually small just record
413 : // without overhead.
414 0 : if (obj->IsJSMap()) {
415 : RecordFixedArrayHelper(nullptr, FixedArray::cast(JSMap::cast(obj)->table()),
416 0 : JS_COLLECTION_SUB_TYPE, 0);
417 : }
418 0 : if (obj->IsJSSet()) {
419 : RecordFixedArrayHelper(nullptr, FixedArray::cast(JSSet::cast(obj)->table()),
420 0 : JS_COLLECTION_SUB_TYPE, 0);
421 : }
422 0 : }
423 :
424 0 : void ObjectStatsCollector::RecordScriptDetails(Script* obj) {
425 : FixedArray* infos = FixedArray::cast(obj->shared_function_infos());
426 0 : RecordFixedArrayHelper(obj, infos, SHARED_FUNCTION_INFOS_SUB_TYPE, 0);
427 0 : }
428 :
429 0 : void ObjectStatsCollector::RecordMapDetails(Map* map_obj) {
430 : DescriptorArray* array = map_obj->instance_descriptors();
431 0 : if (map_obj->owns_descriptors() && array != heap_->empty_descriptor_array() &&
432 0 : SameLiveness(map_obj, array)) {
433 0 : RecordFixedArrayHelper(map_obj, array, DESCRIPTOR_ARRAY_SUB_TYPE, 0);
434 : EnumCache* enum_cache = array->GetEnumCache();
435 0 : RecordFixedArrayHelper(array, enum_cache->keys(), ENUM_CACHE_SUB_TYPE, 0);
436 : RecordFixedArrayHelper(array, enum_cache->indices(),
437 0 : ENUM_INDICES_CACHE_SUB_TYPE, 0);
438 : }
439 :
440 0 : for (DependentCode* cur_dependent_code = map_obj->dependent_code();
441 0 : cur_dependent_code != heap_->empty_fixed_array();
442 : cur_dependent_code = DependentCode::cast(
443 : cur_dependent_code->get(DependentCode::kNextLinkIndex))) {
444 : RecordFixedArrayHelper(map_obj, cur_dependent_code, DEPENDENT_CODE_SUB_TYPE,
445 0 : 0);
446 : }
447 :
448 0 : if (map_obj->is_prototype_map()) {
449 0 : if (map_obj->prototype_info()->IsPrototypeInfo()) {
450 : PrototypeInfo* info = PrototypeInfo::cast(map_obj->prototype_info());
451 : Object* users = info->prototype_users();
452 0 : if (users->IsWeakFixedArray()) {
453 : RecordFixedArrayHelper(map_obj, WeakFixedArray::cast(users),
454 0 : PROTOTYPE_USERS_SUB_TYPE, 0);
455 : }
456 : }
457 : }
458 0 : }
459 :
460 0 : void ObjectStatsCollector::RecordTemplateInfoDetails(TemplateInfo* obj) {
461 0 : if (obj->property_accessors()->IsFixedArray()) {
462 : RecordFixedArrayHelper(obj, FixedArray::cast(obj->property_accessors()),
463 0 : TEMPLATE_INFO_SUB_TYPE, 0);
464 : }
465 0 : if (obj->property_list()->IsFixedArray()) {
466 : RecordFixedArrayHelper(obj, FixedArray::cast(obj->property_list()),
467 0 : TEMPLATE_INFO_SUB_TYPE, 0);
468 : }
469 0 : }
470 :
471 0 : void ObjectStatsCollector::RecordBytecodeArrayDetails(BytecodeArray* obj) {
472 : RecordFixedArrayHelper(obj, obj->constant_pool(),
473 0 : BYTECODE_ARRAY_CONSTANT_POOL_SUB_TYPE, 0);
474 : RecordFixedArrayHelper(obj, obj->handler_table(),
475 0 : BYTECODE_ARRAY_HANDLER_TABLE_SUB_TYPE, 0);
476 0 : }
477 :
478 0 : void ObjectStatsCollector::RecordCodeDetails(Code* code) {
479 0 : stats_->RecordCodeSubTypeStats(code->kind(), code->Size());
480 : RecordFixedArrayHelper(code, code->deoptimization_data(),
481 0 : DEOPTIMIZATION_DATA_SUB_TYPE, 0);
482 0 : if (code->kind() == Code::Kind::OPTIMIZED_FUNCTION) {
483 : DeoptimizationData* input_data =
484 : DeoptimizationData::cast(code->deoptimization_data());
485 0 : if (input_data->length() > 0) {
486 : RecordFixedArrayHelper(code->deoptimization_data(),
487 : input_data->LiteralArray(),
488 0 : OPTIMIZED_CODE_LITERALS_SUB_TYPE, 0);
489 : }
490 : }
491 : RecordFixedArrayHelper(code, code->handler_table(), HANDLER_TABLE_SUB_TYPE,
492 0 : 0);
493 : int const mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
494 0 : for (RelocIterator it(code, mode_mask); !it.done(); it.next()) {
495 0 : RelocInfo::Mode mode = it.rinfo()->rmode();
496 0 : if (mode == RelocInfo::EMBEDDED_OBJECT) {
497 0 : Object* target = it.rinfo()->target_object();
498 0 : if (target->IsFixedArray()) {
499 : RecursivelyRecordFixedArrayHelper(code, FixedArray::cast(target),
500 0 : EMBEDDED_OBJECT_SUB_TYPE);
501 : }
502 : }
503 : }
504 0 : }
505 :
506 0 : void ObjectStatsCollector::RecordSharedFunctionInfoDetails(
507 : SharedFunctionInfo* sfi) {
508 : FixedArray* scope_info = sfi->scope_info();
509 0 : RecordFixedArrayHelper(sfi, scope_info, SCOPE_INFO_SUB_TYPE, 0);
510 : FeedbackMetadata* feedback_metadata = sfi->feedback_metadata();
511 0 : if (!feedback_metadata->is_empty()) {
512 : RecordFixedArrayHelper(sfi, feedback_metadata, FEEDBACK_METADATA_SUB_TYPE,
513 0 : 0);
514 : }
515 0 : }
516 :
517 0 : void ObjectStatsCollector::RecordFixedArrayDetails(FixedArray* array) {
518 0 : if (array->IsContext()) {
519 0 : RecordFixedArrayHelper(nullptr, array, CONTEXT_SUB_TYPE, 0);
520 : }
521 0 : if (IsCowArray(heap_, array) && CanRecordFixedArray(heap_, array)) {
522 : stats_->RecordFixedArraySubTypeStats(array, COPY_ON_WRITE_SUB_TYPE,
523 0 : array->Size(), 0);
524 : }
525 0 : if (array->IsNativeContext()) {
526 : Context* native_ctx = Context::cast(array);
527 : RecordHashTableHelper(array,
528 : native_ctx->slow_template_instantiations_cache(),
529 0 : SLOW_TEMPLATE_INSTANTIATIONS_CACHE_SUB_TYPE);
530 : FixedArray* fast_cache = native_ctx->fast_template_instantiations_cache();
531 : stats_->RecordFixedArraySubTypeStats(
532 : fast_cache, FAST_TEMPLATE_INSTANTIATIONS_CACHE_SUB_TYPE,
533 0 : fast_cache->Size(), 0);
534 : }
535 0 : }
536 :
537 : } // namespace internal
538 : } // namespace v8
|