Index: src/heap/object-stats.cc |
diff --git a/src/heap/object-stats.cc b/src/heap/object-stats.cc |
index 3c82c7f7852bf307ed6a1b4bd86577a2fc2fd8bc..93a74e655bce78a5a9bb7c6eb93a544e50cfbafe 100644 |
--- a/src/heap/object-stats.cc |
+++ b/src/heap/object-stats.cc |
@@ -7,6 +7,7 @@ |
#include "src/counters.h" |
#include "src/heap/heap-inl.h" |
#include "src/isolate.h" |
+#include "src/macro-assembler.h" |
#include "src/utils.h" |
namespace v8 { |
@@ -25,6 +26,7 @@ void ObjectStats::ClearObjectStats(bool clear_last_time_stats) { |
memset(object_counts_last_time_, 0, sizeof(object_counts_last_time_)); |
memset(object_sizes_last_time_, 0, sizeof(object_sizes_last_time_)); |
} |
+ visited_fixed_array_sub_types_.clear(); |
} |
static void PrintJSONArray(size_t* array, const int len) { |
@@ -187,12 +189,35 @@ void ObjectStatsCollector::CollectStatistics(ObjectStats* stats, |
if (obj->IsJSWeakCollection()) { |
RecordJSWeakCollectionDetails(stats, heap, JSWeakCollection::cast(obj)); |
} |
+ if (obj->IsScript()) { |
+ RecordScriptDetails(stats, heap, Script::cast(obj)); |
+ } |
} |
static bool CanRecordFixedArray(Heap* heap, FixedArrayBase* array) { |
- return array->map() != heap->fixed_cow_array_map() && |
+ return array->map()->instance_type() == FIXED_ARRAY_TYPE && |
+ array->map() != heap->fixed_cow_array_map() && |
array->map() != heap->fixed_double_array_map() && |
- array != heap->empty_fixed_array(); |
+ array != heap->empty_fixed_array() && |
+ array != heap->empty_byte_array() && |
+ array != heap->empty_literals_array() && |
+ array != heap->empty_sloppy_arguments_elements() && |
+ array != heap->empty_slow_element_dictionary() && |
+ array != heap->empty_descriptor_array() && |
+ array != heap->empty_properties_dictionary(); |
+} |
+ |
+static bool SameLiveness(HeapObject* obj1, HeapObject* obj2) { |
+ return ObjectMarking::Color(obj1) == ObjectMarking::Color(obj2); |
+} |
+ |
+void ObjectStatsCollector::RecordFixedArrayHelper( |
+ ObjectStats* stats, Heap* heap, HeapObject* parent, FixedArray* array, |
+ int subtype, size_t overhead) { |
+ if (SameLiveness(parent, array) && CanRecordFixedArray(heap, array)) { |
+ stats->RecordFixedArraySubTypeStats(array, subtype, array->Size(), |
+ overhead); |
+ } |
} |
void ObjectStatsCollector::RecordJSObjectDetails(ObjectStats* stats, Heap* heap, |
@@ -202,13 +227,13 @@ void ObjectStatsCollector::RecordJSObjectDetails(ObjectStats* stats, Heap* heap, |
size_t overhead = 0; |
FixedArrayBase* elements = object->elements(); |
if (CanRecordFixedArray(heap, elements)) { |
- if (elements->IsDictionary()) { |
- SeededNumberDictionary* dict = object->element_dictionary(); |
+ if (elements->IsDictionary() && SameLiveness(object, elements)) { |
+ SeededNumberDictionary* dict = SeededNumberDictionary::cast(elements); |
int used = dict->NumberOfElements() * SeededNumberDictionary::kEntrySize; |
CHECK_GE(elements->Size(), used); |
overhead = elements->Size() - used; |
- stats->RecordFixedArraySubTypeStats(DICTIONARY_ELEMENTS_SUB_TYPE, |
- elements->Size(), overhead); |
+ stats->RecordFixedArraySubTypeStats( |
+ elements, DICTIONARY_ELEMENTS_SUB_TYPE, elements->Size(), overhead); |
} else { |
if (IsFastHoleyElementsKind(object->GetElementsKind())) { |
int used = object->GetFastElementsUsage() * kPointerSize; |
@@ -216,23 +241,25 @@ void ObjectStatsCollector::RecordJSObjectDetails(ObjectStats* stats, Heap* heap, |
CHECK_GE(elements->Size(), used); |
overhead = elements->Size() - used; |
} |
- stats->RecordFixedArraySubTypeStats(FAST_ELEMENTS_SUB_TYPE, |
+ stats->RecordFixedArraySubTypeStats(elements, FAST_ELEMENTS_SUB_TYPE, |
elements->Size(), overhead); |
} |
} |
overhead = 0; |
FixedArrayBase* properties = object->properties(); |
- if (CanRecordFixedArray(heap, properties)) { |
+ if (CanRecordFixedArray(heap, properties) && |
+ SameLiveness(object, properties)) { |
if (properties->IsDictionary()) { |
- NameDictionary* dict = object->property_dictionary(); |
+ NameDictionary* dict = NameDictionary::cast(properties); |
int used = dict->NumberOfElements() * NameDictionary::kEntrySize; |
CHECK_GE(properties->Size(), used); |
overhead = properties->Size() - used; |
- stats->RecordFixedArraySubTypeStats(DICTIONARY_PROPERTIES_SUB_TYPE, |
+ stats->RecordFixedArraySubTypeStats(properties, |
+ DICTIONARY_PROPERTIES_SUB_TYPE, |
properties->Size(), overhead); |
} else { |
- stats->RecordFixedArraySubTypeStats(FAST_PROPERTIES_SUB_TYPE, |
+ stats->RecordFixedArraySubTypeStats(properties, FAST_PROPERTIES_SUB_TYPE, |
properties->Size(), overhead); |
} |
} |
@@ -244,34 +271,41 @@ void ObjectStatsCollector::RecordJSWeakCollectionDetails( |
ObjectHashTable* table = ObjectHashTable::cast(obj->table()); |
int used = table->NumberOfElements() * ObjectHashTable::kEntrySize; |
size_t overhead = table->Size() - used; |
- stats->RecordFixedArraySubTypeStats(WEAK_COLLECTION_SUB_TYPE, table->Size(), |
- overhead); |
+ RecordFixedArrayHelper(stats, heap, obj, table, WEAK_COLLECTION_SUB_TYPE, |
+ overhead); |
} |
} |
+void ObjectStatsCollector::RecordScriptDetails(ObjectStats* stats, Heap* heap, |
+ Script* obj) { |
+ Object* infos = WeakFixedArray::cast(obj->shared_function_infos()); |
+ if (infos->IsWeakFixedArray()) |
+ RecordFixedArrayHelper(stats, heap, obj, WeakFixedArray::cast(infos), |
+ SHARED_FUNCTION_INFOS_SUB_TYPE, 0); |
+} |
+ |
void ObjectStatsCollector::RecordMapDetails(ObjectStats* stats, Heap* heap, |
HeapObject* obj) { |
Map* map_obj = Map::cast(obj); |
DCHECK(obj->map()->instance_type() == MAP_TYPE); |
DescriptorArray* array = map_obj->instance_descriptors(); |
- if (map_obj->owns_descriptors() && array != heap->empty_descriptor_array()) { |
- int fixed_array_size = array->Size(); |
- stats->RecordFixedArraySubTypeStats(DESCRIPTOR_ARRAY_SUB_TYPE, |
- fixed_array_size, 0); |
+ if (map_obj->owns_descriptors() && array != heap->empty_descriptor_array() && |
+ SameLiveness(map_obj, array)) { |
+ RecordFixedArrayHelper(stats, heap, map_obj, array, |
+ DESCRIPTOR_ARRAY_SUB_TYPE, 0); |
if (array->HasEnumCache()) { |
- stats->RecordFixedArraySubTypeStats(ENUM_CACHE_SUB_TYPE, |
- array->GetEnumCache()->Size(), 0); |
+ RecordFixedArrayHelper(stats, heap, array, array->GetEnumCache(), |
+ ENUM_CACHE_SUB_TYPE, 0); |
} |
if (array->HasEnumIndicesCache()) { |
- stats->RecordFixedArraySubTypeStats( |
- ENUM_INDICES_CACHE_SUB_TYPE, array->GetEnumIndicesCache()->Size(), 0); |
+ RecordFixedArrayHelper(stats, heap, array, array->GetEnumIndicesCache(), |
+ ENUM_INDICES_CACHE_SUB_TYPE, 0); |
} |
} |
if (map_obj->has_code_cache()) { |
- FixedArray* cache = map_obj->code_cache(); |
- stats->RecordFixedArraySubTypeStats(MAP_CODE_CACHE_SUB_TYPE, cache->Size(), |
- 0); |
+ RecordFixedArrayHelper(stats, heap, map_obj, map_obj->code_cache(), |
+ MAP_CODE_CACHE_SUB_TYPE, 0); |
} |
} |
@@ -283,21 +317,17 @@ void ObjectStatsCollector::RecordCodeDetails(ObjectStats* stats, Heap* heap, |
stats->RecordCodeSubTypeStats(code_obj->kind(), code_obj->GetAge(), |
object_size); |
Code* code = Code::cast(obj); |
- if (code->deoptimization_data() != heap->empty_fixed_array()) { |
- stats->RecordFixedArraySubTypeStats(DEOPTIMIZATION_DATA_SUB_TYPE, |
- code->deoptimization_data()->Size(), 0); |
- } |
- FixedArrayBase* reloc_info = |
- reinterpret_cast<FixedArrayBase*>(code->unchecked_relocation_info()); |
- if (reloc_info != heap->empty_fixed_array()) { |
- stats->RecordFixedArraySubTypeStats(RELOC_INFO_SUB_TYPE, |
- code->relocation_info()->Size(), 0); |
- } |
- FixedArrayBase* source_pos_table = |
- reinterpret_cast<FixedArrayBase*>(code->source_position_table()); |
- if (source_pos_table != heap->empty_fixed_array()) { |
- stats->RecordFixedArraySubTypeStats(SOURCE_POS_SUB_TYPE, |
- source_pos_table->Size(), 0); |
+ RecordFixedArrayHelper(stats, heap, code, code->deoptimization_data(), |
+ DEOPTIMIZATION_DATA_SUB_TYPE, 0); |
+ for (RelocIterator it(code); !it.done(); it.next()) { |
+ RelocInfo::Mode mode = it.rinfo()->rmode(); |
+ if (mode == RelocInfo::EMBEDDED_OBJECT) { |
+ Object* target = it.rinfo()->target_object(); |
+ if (target->IsFixedArray()) { |
+ RecordFixedArrayHelper(stats, heap, code, FixedArray::cast(target), |
+ EMBEDDED_OBJECT_SUB_TYPE, 0); |
+ } |
+ } |
} |
} |
@@ -305,14 +335,12 @@ void ObjectStatsCollector::RecordSharedFunctionInfoDetails(ObjectStats* stats, |
Heap* heap, |
HeapObject* obj) { |
SharedFunctionInfo* sfi = SharedFunctionInfo::cast(obj); |
- if (sfi->scope_info() != heap->empty_fixed_array()) { |
- stats->RecordFixedArraySubTypeStats(SCOPE_INFO_SUB_TYPE, |
- sfi->scope_info()->Size(), 0); |
- } |
- if (sfi->feedback_metadata() != heap->empty_fixed_array()) { |
- stats->RecordFixedArraySubTypeStats(TYPE_FEEDBACK_METADATA_SUB_TYPE, |
- sfi->feedback_metadata()->Size(), 0); |
- } |
+ FixedArray* scope_info = sfi->scope_info(); |
+ RecordFixedArrayHelper(stats, heap, sfi, scope_info, SCOPE_INFO_SUB_TYPE, 0); |
+ FixedArray* feedback_metadata = sfi->feedback_metadata(); |
+ RecordFixedArrayHelper(stats, heap, sfi, feedback_metadata, |
+ TYPE_FEEDBACK_METADATA_SUB_TYPE, 0); |
+ |
if (!sfi->OptimizedCodeMapIsCleared()) { |
FixedArray* optimized_code_map = sfi->optimized_code_map(); |
// Optimized code map should be small, so skip accounting. |
@@ -331,12 +359,10 @@ void ObjectStatsCollector::RecordSharedFunctionInfoDetails(ObjectStats* stats, |
literals = LiteralsArray::cast(slot); |
} |
if (literals != nullptr) { |
- stats->RecordFixedArraySubTypeStats(LITERALS_ARRAY_SUB_TYPE, |
- literals->Size(), 0); |
- TypeFeedbackVector* tfv = literals->feedback_vector(); |
- |
- stats->RecordFixedArraySubTypeStats(TYPE_FEEDBACK_VECTOR_SUB_TYPE, |
- tfv->Size(), 0); |
+ RecordFixedArrayHelper(stats, heap, sfi, literals, |
+ LITERALS_ARRAY_SUB_TYPE, 0); |
+ RecordFixedArrayHelper(stats, heap, sfi, literals->feedback_vector(), |
+ TYPE_FEEDBACK_VECTOR_SUB_TYPE, 0); |
} |
} |
} |
@@ -345,26 +371,61 @@ void ObjectStatsCollector::RecordSharedFunctionInfoDetails(ObjectStats* stats, |
void ObjectStatsCollector::RecordFixedArrayDetails(ObjectStats* stats, |
Heap* heap, |
HeapObject* obj) { |
- FixedArray* fixed_array = FixedArray::cast(obj); |
- if (fixed_array == heap->string_table()) { |
- stats->RecordFixedArraySubTypeStats(STRING_TABLE_SUB_TYPE, |
- fixed_array->Size(), 0); |
+ FixedArray* array = FixedArray::cast(obj); |
+ |
+ // Special fixed arrays. |
+ int subtype = -1; |
+ if (array == heap->weak_new_space_object_to_code_list()) |
+ subtype = WEAK_NEW_SPACE_OBJECT_TO_CODE_SUB_TYPE; |
+ if (array == heap->serialized_templates()) |
+ subtype = SERIALIZED_TEMPLATES_SUB_TYPE; |
+ if (array == heap->string_table()) subtype = STRING_TABLE_SUB_TYPE; |
+ if (array == heap->number_string_cache()) |
+ subtype = NUMBER_STRING_CACHE_SUB_TYPE; |
+ if (array == heap->single_character_string_cache()) |
+ subtype = SINGLE_CHARACTER_STRING_CACHE_SUB_TYPE; |
+ if (array == heap->string_split_cache()) |
+ subtype = STRING_SPLIT_CACHE_SUB_TYPE; |
+ if (array == heap->regexp_multiple_cache()) |
+ subtype = REGEXP_MULTIPLE_CACHE_SUB_TYPE; |
+ if (array->IsContext()) subtype = CONTEXT_SUB_TYPE; |
+ if (array->map() == heap->fixed_cow_array_map()) |
+ subtype = COPY_ON_WRITE_SUB_TYPE; |
+ if (subtype != -1) { |
+ stats->RecordFixedArraySubTypeStats(array, subtype, array->Size(), 0); |
} |
- if (fixed_array == heap->weak_object_to_code_table()) { |
- WeakHashTable* table = reinterpret_cast<WeakHashTable*>(fixed_array); |
+ |
+ // Special hash maps. |
+ if (array == heap->weak_object_to_code_table()) { |
+ WeakHashTable* table = reinterpret_cast<WeakHashTable*>(array); |
int used = table->NumberOfElements() * WeakHashTable::kEntrySize; |
- CHECK_GE(fixed_array->Size(), used); |
- size_t overhead = fixed_array->Size() - used; |
- stats->RecordFixedArraySubTypeStats(OBJECT_TO_CODE_SUB_TYPE, |
- fixed_array->Size(), overhead); |
+ CHECK_GE(array->Size(), used); |
+ size_t overhead = array->Size() - used; |
+ stats->RecordFixedArraySubTypeStats(table, OBJECT_TO_CODE_SUB_TYPE, |
+ table->Size(), overhead); |
+ } |
+ if (array->IsNativeContext()) { |
+ Context* native_ctx = Context::cast(array); |
+ UnseededNumberDictionary* dict = |
+ native_ctx->template_instantiations_cache(); |
+ int used = dict->NumberOfElements() * UnseededNumberDictionary::kEntrySize; |
+ size_t overhead = dict->Size() - used; |
+ RecordFixedArrayHelper(stats, heap, array, dict, |
+ TEMPLATE_INSTANTIATIONS_CACHE_SUB_TYPE, overhead); |
} |
- if (obj->IsContext()) { |
- stats->RecordFixedArraySubTypeStats(CONTEXT_SUB_TYPE, fixed_array->Size(), |
- 0); |
+ if (array == heap->code_stubs()) { |
+ UnseededNumberDictionary* dict = UnseededNumberDictionary::cast(array); |
+ int used = dict->NumberOfElements() * UnseededNumberDictionary::kEntrySize; |
+ size_t overhead = dict->Size() - used; |
+ stats->RecordFixedArraySubTypeStats(dict, CODE_STUBS_TABLE_SUB_TYPE, |
+ dict->Size(), overhead); |
} |
- if (fixed_array->map() == heap->fixed_cow_array_map()) { |
- stats->RecordFixedArraySubTypeStats(COPY_ON_WRITE_SUB_TYPE, |
- fixed_array->Size(), 0); |
+ if (array == heap->intrinsic_function_names()) { |
+ NameDictionary* dict = NameDictionary::cast(array); |
+ int used = dict->NumberOfElements() * NameDictionary::kEntrySize; |
+ size_t overhead = dict->Size() - used; |
+ stats->RecordFixedArraySubTypeStats(dict, INTRINSIC_FUNCTION_NAMES_SUB_TYPE, |
+ dict->Size(), overhead); |
} |
} |