Commit 4ff98cb1 authored by Michael Lippautz's avatar Michael Lippautz Committed by Commit Bot

[object-stats] Refactor to allow additional passes over objects

Move heap iteration to object stats to untangle the dependency from
MC.

Bug: v8:7266
Change-Id: I6f0f4f5f3bb0a911591a211ffd71580343765cdd
Reviewed-on: https://chromium-review.googlesource.com/860358Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50502}
parent 4e116c4b
...@@ -1689,54 +1689,12 @@ void MarkCompactCollector::ProcessTopOptimizedFrame(ObjectVisitor* visitor) { ...@@ -1689,54 +1689,12 @@ void MarkCompactCollector::ProcessTopOptimizedFrame(ObjectVisitor* visitor) {
} }
} }
class ObjectStatsVisitor : public HeapObjectVisitor {
public:
ObjectStatsVisitor(Heap* heap, ObjectStats* live_stats,
ObjectStats* dead_stats)
: live_collector_(heap, live_stats),
dead_collector_(heap, dead_stats),
marking_state_(
heap->mark_compact_collector()->non_atomic_marking_state()) {
DCHECK_NOT_NULL(live_stats);
DCHECK_NOT_NULL(dead_stats);
// Global objects are roots and thus recorded as live.
live_collector_.CollectGlobalStatistics();
}
bool Visit(HeapObject* obj, int size) override {
if (marking_state_->IsBlack(obj)) {
live_collector_.CollectStatistics(obj);
} else {
DCHECK(!marking_state_->IsGrey(obj));
dead_collector_.CollectStatistics(obj);
}
return true;
}
private:
ObjectStatsCollector live_collector_;
ObjectStatsCollector dead_collector_;
MarkCompactCollector::NonAtomicMarkingState* marking_state_;
};
void MarkCompactCollector::VisitAllObjects(HeapObjectVisitor* visitor) {
SpaceIterator space_it(heap());
HeapObject* obj = nullptr;
while (space_it.has_next()) {
std::unique_ptr<ObjectIterator> it(space_it.next()->GetObjectIterator());
ObjectIterator* obj_it = it.get();
while ((obj = obj_it->Next()) != nullptr) {
visitor->Visit(obj, obj->Size());
}
}
}
void MarkCompactCollector::RecordObjectStats() { void MarkCompactCollector::RecordObjectStats() {
if (V8_UNLIKELY(FLAG_gc_stats)) { if (V8_UNLIKELY(FLAG_gc_stats)) {
heap()->CreateObjectStats(); heap()->CreateObjectStats();
ObjectStatsVisitor visitor(heap(), heap()->live_object_stats_, ObjectStatsCollector collector(heap(), heap()->live_object_stats_,
heap()->dead_object_stats_); heap()->dead_object_stats_);
VisitAllObjects(&visitor); collector.Collect();
if (V8_UNLIKELY(FLAG_gc_stats & if (V8_UNLIKELY(FLAG_gc_stats &
v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING)) { v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING)) {
std::stringstream live, dead; std::stringstream live, dead;
......
...@@ -723,8 +723,6 @@ class MarkCompactCollector final : public MarkCompactCollectorBase { ...@@ -723,8 +723,6 @@ class MarkCompactCollector final : public MarkCompactCollectorBase {
int* target_fragmentation_percent, int* target_fragmentation_percent,
size_t* max_evacuated_bytes); size_t* max_evacuated_bytes);
void VisitAllObjects(HeapObjectVisitor* visitor);
void RecordObjectStats(); void RecordObjectStats();
// Finishes GC, performs heap verification if enabled. // Finishes GC, performs heap verification if enabled.
......
...@@ -267,13 +267,49 @@ bool ObjectStats::RecordFixedArraySubTypeStats(FixedArrayBase* array, ...@@ -267,13 +267,49 @@ bool ObjectStats::RecordFixedArraySubTypeStats(FixedArrayBase* array,
Isolate* ObjectStats::isolate() { return heap()->isolate(); } Isolate* ObjectStats::isolate() { return heap()->isolate(); }
ObjectStatsCollector::ObjectStatsCollector(Heap* heap, ObjectStats* stats) class ObjectStatsCollectorImpl {
public:
ObjectStatsCollectorImpl(Heap* heap, ObjectStats* stats);
void CollectGlobalStatistics();
void CollectStatistics(HeapObject* obj);
private:
class CompilationCacheTableVisitor;
void RecordBytecodeArrayDetails(BytecodeArray* obj);
void RecordCodeDetails(Code* code);
void RecordFixedArrayDetails(FixedArray* array);
void RecordJSCollectionDetails(JSObject* obj);
void RecordJSObjectDetails(JSObject* object);
void RecordJSWeakCollectionDetails(JSWeakCollection* obj);
void RecordMapDetails(Map* map);
void RecordScriptDetails(Script* obj);
void RecordTemplateInfoDetails(TemplateInfo* obj);
void RecordSharedFunctionInfoDetails(SharedFunctionInfo* sfi);
bool RecordFixedArrayHelper(HeapObject* parent, FixedArray* array,
int subtype, size_t overhead);
void RecursivelyRecordFixedArrayHelper(HeapObject* parent, FixedArray* array,
int subtype);
template <class HashTable>
void RecordHashTableHelper(HeapObject* parent, HashTable* array, int subtype);
bool SameLiveness(HeapObject* obj1, HeapObject* obj2);
Heap* heap_;
ObjectStats* stats_;
MarkCompactCollector::NonAtomicMarkingState* marking_state_;
friend class ObjectStatsCollectorImpl::CompilationCacheTableVisitor;
};
ObjectStatsCollectorImpl::ObjectStatsCollectorImpl(Heap* heap,
ObjectStats* stats)
: heap_(heap), : heap_(heap),
stats_(stats), stats_(stats),
marking_state_( marking_state_(
heap->mark_compact_collector()->non_atomic_marking_state()) {} heap->mark_compact_collector()->non_atomic_marking_state()) {}
void ObjectStatsCollector::CollectStatistics(HeapObject* obj) { void ObjectStatsCollectorImpl::CollectStatistics(HeapObject* obj) {
Map* map = obj->map(); Map* map = obj->map();
// Record for the InstanceType. // Record for the InstanceType.
...@@ -303,9 +339,10 @@ void ObjectStatsCollector::CollectStatistics(HeapObject* obj) { ...@@ -303,9 +339,10 @@ void ObjectStatsCollector::CollectStatistics(HeapObject* obj) {
if (obj->IsScript()) RecordScriptDetails(Script::cast(obj)); if (obj->IsScript()) RecordScriptDetails(Script::cast(obj));
} }
class ObjectStatsCollector::CompilationCacheTableVisitor : public RootVisitor { class ObjectStatsCollectorImpl::CompilationCacheTableVisitor
: public RootVisitor {
public: public:
explicit CompilationCacheTableVisitor(ObjectStatsCollector* parent) explicit CompilationCacheTableVisitor(ObjectStatsCollectorImpl* parent)
: parent_(parent) {} : parent_(parent) {}
void VisitRootPointers(Root root, Object** start, Object** end) override { void VisitRootPointers(Root root, Object** start, Object** end) override {
...@@ -319,10 +356,10 @@ class ObjectStatsCollector::CompilationCacheTableVisitor : public RootVisitor { ...@@ -319,10 +356,10 @@ class ObjectStatsCollector::CompilationCacheTableVisitor : public RootVisitor {
} }
private: private:
ObjectStatsCollector* parent_; ObjectStatsCollectorImpl* parent_;
}; };
void ObjectStatsCollector::CollectGlobalStatistics() { void ObjectStatsCollectorImpl::CollectGlobalStatistics() {
// Global FixedArrays. // Global FixedArrays.
RecordFixedArrayHelper(nullptr, heap_->weak_new_space_object_to_code_list(), RecordFixedArrayHelper(nullptr, heap_->weak_new_space_object_to_code_list(),
WEAK_NEW_SPACE_OBJECT_TO_CODE_SUB_TYPE, 0); WEAK_NEW_SPACE_OBJECT_TO_CODE_SUB_TYPE, 0);
...@@ -371,12 +408,13 @@ static bool IsCowArray(Heap* heap, FixedArrayBase* array) { ...@@ -371,12 +408,13 @@ static bool IsCowArray(Heap* heap, FixedArrayBase* array) {
return array->map() == heap->fixed_cow_array_map(); return array->map() == heap->fixed_cow_array_map();
} }
bool ObjectStatsCollector::SameLiveness(HeapObject* obj1, HeapObject* obj2) { bool ObjectStatsCollectorImpl::SameLiveness(HeapObject* obj1,
HeapObject* obj2) {
return obj1 == nullptr || obj2 == nullptr || return obj1 == nullptr || obj2 == nullptr ||
marking_state_->Color(obj1) == marking_state_->Color(obj2); marking_state_->Color(obj1) == marking_state_->Color(obj2);
} }
bool ObjectStatsCollector::RecordFixedArrayHelper(HeapObject* parent, bool ObjectStatsCollectorImpl::RecordFixedArrayHelper(HeapObject* parent,
FixedArray* array, FixedArray* array,
int subtype, int subtype,
size_t overhead) { size_t overhead) {
...@@ -388,9 +426,8 @@ bool ObjectStatsCollector::RecordFixedArrayHelper(HeapObject* parent, ...@@ -388,9 +426,8 @@ bool ObjectStatsCollector::RecordFixedArrayHelper(HeapObject* parent,
return false; return false;
} }
void ObjectStatsCollector::RecursivelyRecordFixedArrayHelper(HeapObject* parent, void ObjectStatsCollectorImpl::RecursivelyRecordFixedArrayHelper(
FixedArray* array, HeapObject* parent, FixedArray* array, int subtype) {
int subtype) {
if (RecordFixedArrayHelper(parent, array, subtype, 0)) { if (RecordFixedArrayHelper(parent, array, subtype, 0)) {
for (int i = 0; i < array->length(); i++) { for (int i = 0; i < array->length(); i++) {
if (array->get(i)->IsFixedArray()) { if (array->get(i)->IsFixedArray()) {
...@@ -402,7 +439,7 @@ void ObjectStatsCollector::RecursivelyRecordFixedArrayHelper(HeapObject* parent, ...@@ -402,7 +439,7 @@ void ObjectStatsCollector::RecursivelyRecordFixedArrayHelper(HeapObject* parent,
} }
template <class HashTable> template <class HashTable>
void ObjectStatsCollector::RecordHashTableHelper(HeapObject* parent, void ObjectStatsCollectorImpl::RecordHashTableHelper(HeapObject* parent,
HashTable* array, HashTable* array,
int subtype) { int subtype) {
int used = array->NumberOfElements() * HashTable::kEntrySize * kPointerSize; int used = array->NumberOfElements() * HashTable::kEntrySize * kPointerSize;
...@@ -413,7 +450,7 @@ void ObjectStatsCollector::RecordHashTableHelper(HeapObject* parent, ...@@ -413,7 +450,7 @@ void ObjectStatsCollector::RecordHashTableHelper(HeapObject* parent,
RecordFixedArrayHelper(parent, array, subtype, overhead); RecordFixedArrayHelper(parent, array, subtype, overhead);
} }
void ObjectStatsCollector::RecordJSObjectDetails(JSObject* object) { void ObjectStatsCollectorImpl::RecordJSObjectDetails(JSObject* object) {
size_t overhead = 0; size_t overhead = 0;
FixedArrayBase* elements = object->elements(); FixedArrayBase* elements = object->elements();
if (CanRecordFixedArray(heap_, elements) && !IsCowArray(heap_, elements)) { if (CanRecordFixedArray(heap_, elements) && !IsCowArray(heap_, elements)) {
...@@ -448,7 +485,7 @@ void ObjectStatsCollector::RecordJSObjectDetails(JSObject* object) { ...@@ -448,7 +485,7 @@ void ObjectStatsCollector::RecordJSObjectDetails(JSObject* object) {
} }
} }
void ObjectStatsCollector::RecordJSWeakCollectionDetails( void ObjectStatsCollectorImpl::RecordJSWeakCollectionDetails(
JSWeakCollection* obj) { JSWeakCollection* obj) {
if (obj->table()->IsHashTable()) { if (obj->table()->IsHashTable()) {
ObjectHashTable* table = ObjectHashTable::cast(obj->table()); ObjectHashTable* table = ObjectHashTable::cast(obj->table());
...@@ -458,7 +495,7 @@ void ObjectStatsCollector::RecordJSWeakCollectionDetails( ...@@ -458,7 +495,7 @@ void ObjectStatsCollector::RecordJSWeakCollectionDetails(
} }
} }
void ObjectStatsCollector::RecordJSCollectionDetails(JSObject* obj) { void ObjectStatsCollectorImpl::RecordJSCollectionDetails(JSObject* obj) {
// The JS versions use a different HashTable implementation that cannot use // The JS versions use a different HashTable implementation that cannot use
// the regular helper. Since overall impact is usually small just record // the regular helper. Since overall impact is usually small just record
// without overhead. // without overhead.
...@@ -472,12 +509,12 @@ void ObjectStatsCollector::RecordJSCollectionDetails(JSObject* obj) { ...@@ -472,12 +509,12 @@ void ObjectStatsCollector::RecordJSCollectionDetails(JSObject* obj) {
} }
} }
void ObjectStatsCollector::RecordScriptDetails(Script* obj) { void ObjectStatsCollectorImpl::RecordScriptDetails(Script* obj) {
FixedArray* infos = FixedArray::cast(obj->shared_function_infos()); FixedArray* infos = FixedArray::cast(obj->shared_function_infos());
RecordFixedArrayHelper(obj, infos, SHARED_FUNCTION_INFOS_SUB_TYPE, 0); RecordFixedArrayHelper(obj, infos, SHARED_FUNCTION_INFOS_SUB_TYPE, 0);
} }
void ObjectStatsCollector::RecordMapDetails(Map* map_obj) { void ObjectStatsCollectorImpl::RecordMapDetails(Map* map_obj) {
DescriptorArray* array = map_obj->instance_descriptors(); DescriptorArray* array = map_obj->instance_descriptors();
if (map_obj->owns_descriptors() && array != heap_->empty_descriptor_array() && if (map_obj->owns_descriptors() && array != heap_->empty_descriptor_array() &&
SameLiveness(map_obj, array)) { SameLiveness(map_obj, array)) {
...@@ -508,7 +545,7 @@ void ObjectStatsCollector::RecordMapDetails(Map* map_obj) { ...@@ -508,7 +545,7 @@ void ObjectStatsCollector::RecordMapDetails(Map* map_obj) {
} }
} }
void ObjectStatsCollector::RecordTemplateInfoDetails(TemplateInfo* obj) { void ObjectStatsCollectorImpl::RecordTemplateInfoDetails(TemplateInfo* obj) {
if (obj->property_accessors()->IsFixedArray()) { if (obj->property_accessors()->IsFixedArray()) {
RecordFixedArrayHelper(obj, FixedArray::cast(obj->property_accessors()), RecordFixedArrayHelper(obj, FixedArray::cast(obj->property_accessors()),
TEMPLATE_INFO_SUB_TYPE, 0); TEMPLATE_INFO_SUB_TYPE, 0);
...@@ -519,14 +556,14 @@ void ObjectStatsCollector::RecordTemplateInfoDetails(TemplateInfo* obj) { ...@@ -519,14 +556,14 @@ void ObjectStatsCollector::RecordTemplateInfoDetails(TemplateInfo* obj) {
} }
} }
void ObjectStatsCollector::RecordBytecodeArrayDetails(BytecodeArray* obj) { void ObjectStatsCollectorImpl::RecordBytecodeArrayDetails(BytecodeArray* obj) {
RecordFixedArrayHelper(obj, obj->constant_pool(), RecordFixedArrayHelper(obj, obj->constant_pool(),
BYTECODE_ARRAY_CONSTANT_POOL_SUB_TYPE, 0); BYTECODE_ARRAY_CONSTANT_POOL_SUB_TYPE, 0);
RecordFixedArrayHelper(obj, obj->handler_table(), RecordFixedArrayHelper(obj, obj->handler_table(),
BYTECODE_ARRAY_HANDLER_TABLE_SUB_TYPE, 0); BYTECODE_ARRAY_HANDLER_TABLE_SUB_TYPE, 0);
} }
void ObjectStatsCollector::RecordCodeDetails(Code* code) { void ObjectStatsCollectorImpl::RecordCodeDetails(Code* code) {
stats_->RecordCodeSubTypeStats(code->kind(), code->Size()); stats_->RecordCodeSubTypeStats(code->kind(), code->Size());
RecordFixedArrayHelper(code, code->deoptimization_data(), RecordFixedArrayHelper(code, code->deoptimization_data(),
DEOPTIMIZATION_DATA_SUB_TYPE, 0); DEOPTIMIZATION_DATA_SUB_TYPE, 0);
...@@ -554,7 +591,7 @@ void ObjectStatsCollector::RecordCodeDetails(Code* code) { ...@@ -554,7 +591,7 @@ void ObjectStatsCollector::RecordCodeDetails(Code* code) {
} }
} }
void ObjectStatsCollector::RecordSharedFunctionInfoDetails( void ObjectStatsCollectorImpl::RecordSharedFunctionInfoDetails(
SharedFunctionInfo* sfi) { SharedFunctionInfo* sfi) {
FixedArray* scope_info = sfi->scope_info(); FixedArray* scope_info = sfi->scope_info();
RecordFixedArrayHelper(sfi, scope_info, SCOPE_INFO_SUB_TYPE, 0); RecordFixedArrayHelper(sfi, scope_info, SCOPE_INFO_SUB_TYPE, 0);
...@@ -565,7 +602,7 @@ void ObjectStatsCollector::RecordSharedFunctionInfoDetails( ...@@ -565,7 +602,7 @@ void ObjectStatsCollector::RecordSharedFunctionInfoDetails(
} }
} }
void ObjectStatsCollector::RecordFixedArrayDetails(FixedArray* array) { void ObjectStatsCollectorImpl::RecordFixedArrayDetails(FixedArray* array) {
if (array->IsContext()) { if (array->IsContext()) {
RecordFixedArrayHelper(nullptr, array, CONTEXT_SUB_TYPE, 0); RecordFixedArrayHelper(nullptr, array, CONTEXT_SUB_TYPE, 0);
} }
...@@ -585,5 +622,58 @@ void ObjectStatsCollector::RecordFixedArrayDetails(FixedArray* array) { ...@@ -585,5 +622,58 @@ void ObjectStatsCollector::RecordFixedArrayDetails(FixedArray* array) {
} }
} }
class ObjectStatsVisitor {
public:
ObjectStatsVisitor(Heap* heap, ObjectStatsCollectorImpl* live_collector,
ObjectStatsCollectorImpl* dead_collector)
: live_collector_(live_collector),
dead_collector_(dead_collector),
marking_state_(
heap->mark_compact_collector()->non_atomic_marking_state()) {}
bool Visit(HeapObject* obj, int size) {
if (marking_state_->IsBlack(obj)) {
live_collector_->CollectStatistics(obj);
} else {
DCHECK(!marking_state_->IsGrey(obj));
dead_collector_->CollectStatistics(obj);
}
return true;
}
private:
ObjectStatsCollectorImpl* live_collector_;
ObjectStatsCollectorImpl* dead_collector_;
MarkCompactCollector::NonAtomicMarkingState* marking_state_;
};
namespace {
void IterateHeap(Heap* heap, ObjectStatsVisitor* visitor) {
SpaceIterator space_it(heap);
HeapObject* obj = nullptr;
while (space_it.has_next()) {
std::unique_ptr<ObjectIterator> it(space_it.next()->GetObjectIterator());
ObjectIterator* obj_it = it.get();
while ((obj = obj_it->Next()) != nullptr) {
visitor->Visit(obj, obj->Size());
}
}
}
} // namespace
void ObjectStatsCollector::Collect() {
ObjectStatsCollectorImpl live_collector(heap_, live_);
ObjectStatsCollectorImpl dead_collector(heap_, dead_);
// 1. Collect system type otherwise indistinguishable from other types.
// TODO(mlippautz): Implement.
// 2. Collect globals; only applies to live objects.
live_collector.CollectGlobalStatistics();
// 3. Collect rest.
ObjectStatsVisitor visitor(heap_, &live_collector, &dead_collector);
IterateHeap(heap_, &visitor);
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -88,37 +88,21 @@ class ObjectStats { ...@@ -88,37 +88,21 @@ class ObjectStats {
class ObjectStatsCollector { class ObjectStatsCollector {
public: public:
ObjectStatsCollector(Heap* heap, ObjectStats* stats); ObjectStatsCollector(Heap* heap, ObjectStats* live, ObjectStats* dead)
: heap_(heap), live_(live), dead_(dead) {
DCHECK_NOT_NULL(heap_);
DCHECK_NOT_NULL(live_);
DCHECK_NOT_NULL(dead_);
}
void CollectGlobalStatistics(); // Collects type information of live and dead objects. Requires mark bits to
void CollectStatistics(HeapObject* obj); // be present.
void Collect();
private: private:
class CompilationCacheTableVisitor; Heap* const heap_;
ObjectStats* const live_;
void RecordBytecodeArrayDetails(BytecodeArray* obj); ObjectStats* const dead_;
void RecordCodeDetails(Code* code);
void RecordFixedArrayDetails(FixedArray* array);
void RecordJSCollectionDetails(JSObject* obj);
void RecordJSObjectDetails(JSObject* object);
void RecordJSWeakCollectionDetails(JSWeakCollection* obj);
void RecordMapDetails(Map* map);
void RecordScriptDetails(Script* obj);
void RecordTemplateInfoDetails(TemplateInfo* obj);
void RecordSharedFunctionInfoDetails(SharedFunctionInfo* sfi);
bool RecordFixedArrayHelper(HeapObject* parent, FixedArray* array,
int subtype, size_t overhead);
void RecursivelyRecordFixedArrayHelper(HeapObject* parent, FixedArray* array,
int subtype);
template <class HashTable>
void RecordHashTableHelper(HeapObject* parent, HashTable* array, int subtype);
bool SameLiveness(HeapObject* obj1, HeapObject* obj2);
Heap* heap_;
ObjectStats* stats_;
MarkCompactCollector::NonAtomicMarkingState* marking_state_;
friend class ObjectStatsCollector::CompilationCacheTableVisitor;
}; };
} // namespace internal } // namespace internal
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment