LCOV - code coverage report
Current view: top level - src/heap - object-stats.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 0 275 0.0 %
Date: 2017-04-26 Functions: 0 37 0.0 %

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

Generated by: LCOV version 1.10