Distinguish weak references in heap snapshots, group GC roots.

Several changes to better organize snapshot data:

1. Provide information about weak references.
2. Group (GC roots) children.
3. Prettify debug snapshot printing.

BUG=v8:1832
TEST=cctest/test-heap-profiler/*Weak*

Review URL: http://codereview.chromium.org/8716009

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10158 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 1bfa6220
...@@ -219,8 +219,9 @@ class V8EXPORT HeapGraphEdge { ...@@ -219,8 +219,9 @@ class V8EXPORT HeapGraphEdge {
// (e.g. parts of a ConsString). // (e.g. parts of a ConsString).
kHidden = 4, // A link that is needed for proper sizes kHidden = 4, // A link that is needed for proper sizes
// calculation, but may be hidden from user. // calculation, but may be hidden from user.
kShortcut = 5 // A link that must not be followed during kShortcut = 5, // A link that must not be followed during
// sizes calculation. // sizes calculation.
kWeak = 6 // A weak reference (ignored by the GC).
}; };
/** Returns edge type (see HeapGraphEdge::Type). */ /** Returns edge type (see HeapGraphEdge::Type). */
......
...@@ -299,7 +299,7 @@ class Genesis BASE_EMBEDDED { ...@@ -299,7 +299,7 @@ class Genesis BASE_EMBEDDED {
void Bootstrapper::Iterate(ObjectVisitor* v) { void Bootstrapper::Iterate(ObjectVisitor* v) {
extensions_cache_.Iterate(v); extensions_cache_.Iterate(v);
v->Synchronize("Extensions"); v->Synchronize(VisitorSynchronization::kExtensions);
} }
......
...@@ -5151,29 +5151,29 @@ void Heap::IterateRoots(ObjectVisitor* v, VisitMode mode) { ...@@ -5151,29 +5151,29 @@ void Heap::IterateRoots(ObjectVisitor* v, VisitMode mode) {
void Heap::IterateWeakRoots(ObjectVisitor* v, VisitMode mode) { void Heap::IterateWeakRoots(ObjectVisitor* v, VisitMode mode) {
v->VisitPointer(reinterpret_cast<Object**>(&roots_[kSymbolTableRootIndex])); v->VisitPointer(reinterpret_cast<Object**>(&roots_[kSymbolTableRootIndex]));
v->Synchronize("symbol_table"); v->Synchronize(VisitorSynchronization::kSymbolTable);
if (mode != VISIT_ALL_IN_SCAVENGE && if (mode != VISIT_ALL_IN_SCAVENGE &&
mode != VISIT_ALL_IN_SWEEP_NEWSPACE) { mode != VISIT_ALL_IN_SWEEP_NEWSPACE) {
// Scavenge collections have special processing for this. // Scavenge collections have special processing for this.
external_string_table_.Iterate(v); external_string_table_.Iterate(v);
} }
v->Synchronize("external_string_table"); v->Synchronize(VisitorSynchronization::kExternalStringsTable);
} }
void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) { void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) {
v->VisitPointers(&roots_[0], &roots_[kStrongRootListLength]); v->VisitPointers(&roots_[0], &roots_[kStrongRootListLength]);
v->Synchronize("strong_root_list"); v->Synchronize(VisitorSynchronization::kStrongRootList);
v->VisitPointer(BitCast<Object**>(&hidden_symbol_)); v->VisitPointer(BitCast<Object**>(&hidden_symbol_));
v->Synchronize("symbol"); v->Synchronize(VisitorSynchronization::kSymbol);
isolate_->bootstrapper()->Iterate(v); isolate_->bootstrapper()->Iterate(v);
v->Synchronize("bootstrapper"); v->Synchronize(VisitorSynchronization::kBootstrapper);
isolate_->Iterate(v); isolate_->Iterate(v);
v->Synchronize("top"); v->Synchronize(VisitorSynchronization::kTop);
Relocatable::Iterate(v); Relocatable::Iterate(v);
v->Synchronize("relocatable"); v->Synchronize(VisitorSynchronization::kRelocatable);
#ifdef ENABLE_DEBUGGER_SUPPORT #ifdef ENABLE_DEBUGGER_SUPPORT
isolate_->debug()->Iterate(v); isolate_->debug()->Iterate(v);
...@@ -5181,13 +5181,13 @@ void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) { ...@@ -5181,13 +5181,13 @@ void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) {
isolate_->deoptimizer_data()->Iterate(v); isolate_->deoptimizer_data()->Iterate(v);
} }
#endif #endif
v->Synchronize("debug"); v->Synchronize(VisitorSynchronization::kDebug);
isolate_->compilation_cache()->Iterate(v); isolate_->compilation_cache()->Iterate(v);
v->Synchronize("compilationcache"); v->Synchronize(VisitorSynchronization::kCompilationCache);
// Iterate over local handles in handle scopes. // Iterate over local handles in handle scopes.
isolate_->handle_scope_implementer()->Iterate(v); isolate_->handle_scope_implementer()->Iterate(v);
v->Synchronize("handlescope"); v->Synchronize(VisitorSynchronization::kHandleScope);
// Iterate over the builtin code objects and code stubs in the // Iterate over the builtin code objects and code stubs in the
// heap. Note that it is not necessary to iterate over code objects // heap. Note that it is not necessary to iterate over code objects
...@@ -5195,7 +5195,7 @@ void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) { ...@@ -5195,7 +5195,7 @@ void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) {
if (mode != VISIT_ALL_IN_SCAVENGE) { if (mode != VISIT_ALL_IN_SCAVENGE) {
isolate_->builtins()->IterateBuiltins(v); isolate_->builtins()->IterateBuiltins(v);
} }
v->Synchronize("builtins"); v->Synchronize(VisitorSynchronization::kBuiltins);
// Iterate over global handles. // Iterate over global handles.
switch (mode) { switch (mode) {
...@@ -5210,11 +5210,11 @@ void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) { ...@@ -5210,11 +5210,11 @@ void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) {
isolate_->global_handles()->IterateAllRoots(v); isolate_->global_handles()->IterateAllRoots(v);
break; break;
} }
v->Synchronize("globalhandles"); v->Synchronize(VisitorSynchronization::kGlobalHandles);
// Iterate over pointers being held by inactive threads. // Iterate over pointers being held by inactive threads.
isolate_->thread_manager()->Iterate(v); isolate_->thread_manager()->Iterate(v);
v->Synchronize("threadmanager"); v->Synchronize(VisitorSynchronization::kThreadManager);
// Iterate over the pointers the Serialization/Deserialization code is // Iterate over the pointers the Serialization/Deserialization code is
// holding. // holding.
......
...@@ -7639,6 +7639,22 @@ void SharedFunctionInfo::CompleteInobjectSlackTracking() { ...@@ -7639,6 +7639,22 @@ void SharedFunctionInfo::CompleteInobjectSlackTracking() {
} }
#define DECLARE_TAG(ignore1, name, ignore2) name,
const char* const VisitorSynchronization::kTags[
VisitorSynchronization::kNumberOfSyncTags] = {
VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
};
#undef DECLARE_TAG
#define DECLARE_TAG(ignore1, ignore2, name) name,
const char* const VisitorSynchronization::kTagNames[
VisitorSynchronization::kNumberOfSyncTags] = {
VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
};
#undef DECLARE_TAG
void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) { void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode())); ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address()); Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
......
...@@ -7862,6 +7862,34 @@ class BreakPointInfo: public Struct { ...@@ -7862,6 +7862,34 @@ class BreakPointInfo: public Struct {
#undef DECL_BOOLEAN_ACCESSORS #undef DECL_BOOLEAN_ACCESSORS
#undef DECL_ACCESSORS #undef DECL_ACCESSORS
#define VISITOR_SYNCHRONIZATION_TAGS_LIST(V) \
V(kSymbolTable, "symbol_table", "(Symbols)") \
V(kExternalStringsTable, "external_strings_table", "(External strings)") \
V(kStrongRootList, "strong_root_list", "(Strong roots)") \
V(kSymbol, "symbol", "(Symbol)") \
V(kBootstrapper, "bootstrapper", "(Bootstrapper)") \
V(kTop, "top", "(Isolate)") \
V(kRelocatable, "relocatable", "(Relocatable)") \
V(kDebug, "debug", "(Debugger)") \
V(kCompilationCache, "compilationcache", "(Compilation cache)") \
V(kHandleScope, "handlescope", "(Handle scope)") \
V(kBuiltins, "builtins", "(Builtins)") \
V(kGlobalHandles, "globalhandles", "(Global handles)") \
V(kThreadManager, "threadmanager", "(Thread manager)") \
V(kExtensions, "Extensions", "(Extensions)")
class VisitorSynchronization : public AllStatic {
public:
#define DECLARE_ENUM(enum_item, ignore1, ignore2) enum_item,
enum SyncTag {
VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_ENUM)
kNumberOfSyncTags
};
#undef DECLARE_ENUM
static const char* const kTags[kNumberOfSyncTags];
static const char* const kTagNames[kNumberOfSyncTags];
};
// Abstract base class for visiting, and optionally modifying, the // Abstract base class for visiting, and optionally modifying, the
// pointers contained in Objects. Used in GC and serialization/deserialization. // pointers contained in Objects. Used in GC and serialization/deserialization.
...@@ -7917,13 +7945,10 @@ class ObjectVisitor BASE_EMBEDDED { ...@@ -7917,13 +7945,10 @@ class ObjectVisitor BASE_EMBEDDED {
// Visits a handle that has an embedder-assigned class ID. // Visits a handle that has an embedder-assigned class ID.
virtual void VisitEmbedderReference(Object** p, uint16_t class_id) {} virtual void VisitEmbedderReference(Object** p, uint16_t class_id) {}
#ifdef DEBUG
// Intended for serialization/deserialization checking: insert, or // Intended for serialization/deserialization checking: insert, or
// check for the presence of, a tag at this position in the stream. // check for the presence of, a tag at this position in the stream.
virtual void Synchronize(const char* tag) {} // Also used for marking up GC roots in heap snapshots.
#else virtual void Synchronize(VisitorSynchronization::SyncTag tag) {}
inline void Synchronize(const char* tag) {}
#endif
}; };
......
...@@ -95,6 +95,25 @@ CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) { ...@@ -95,6 +95,25 @@ CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) {
} }
uint64_t HeapObjectsMap::GetNthGcSubrootId(int delta) {
return kGcRootsObjectId + delta * kObjectIdStep;
}
HeapObject* V8HeapExplorer::GetNthGcSubrootObject(int delta) {
return reinterpret_cast<HeapObject*>(
reinterpret_cast<char*>(kFirstGcSubrootObject) +
delta * HeapObjectsMap::kObjectIdStep);
}
int V8HeapExplorer::GetGcSubrootOrder(HeapObject* subroot) {
return (reinterpret_cast<char*>(subroot) -
reinterpret_cast<char*>(kFirstGcSubrootObject)) /
HeapObjectsMap::kObjectIdStep;
}
uint64_t HeapEntry::id() { uint64_t HeapEntry::id() {
union { union {
Id stored_id; Id stored_id;
......
This diff is collapsed.
...@@ -455,7 +455,8 @@ class HeapGraphEdge BASE_EMBEDDED { ...@@ -455,7 +455,8 @@ class HeapGraphEdge BASE_EMBEDDED {
kProperty = v8::HeapGraphEdge::kProperty, kProperty = v8::HeapGraphEdge::kProperty,
kInternal = v8::HeapGraphEdge::kInternal, kInternal = v8::HeapGraphEdge::kInternal,
kHidden = v8::HeapGraphEdge::kHidden, kHidden = v8::HeapGraphEdge::kHidden,
kShortcut = v8::HeapGraphEdge::kShortcut kShortcut = v8::HeapGraphEdge::kShortcut,
kWeak = v8::HeapGraphEdge::kWeak
}; };
HeapGraphEdge() { } HeapGraphEdge() { }
...@@ -465,7 +466,7 @@ class HeapGraphEdge BASE_EMBEDDED { ...@@ -465,7 +466,7 @@ class HeapGraphEdge BASE_EMBEDDED {
Type type() { return static_cast<Type>(type_); } Type type() { return static_cast<Type>(type_); }
int index() { int index() {
ASSERT(type_ == kElement || type_ == kHidden); ASSERT(type_ == kElement || type_ == kHidden || type_ == kWeak);
return index_; return index_;
} }
const char* name() { const char* name() {
...@@ -588,7 +589,8 @@ class HeapEntry BASE_EMBEDDED { ...@@ -588,7 +589,8 @@ class HeapEntry BASE_EMBEDDED {
int EntrySize() { return EntriesSize(1, children_count_, retainers_count_); } int EntrySize() { return EntriesSize(1, children_count_, retainers_count_); }
int RetainedSize(bool exact); int RetainedSize(bool exact);
void Print(int max_depth, int indent); void Print(
const char* prefix, const char* edge_name, int max_depth, int indent);
Handle<HeapObject> GetHeapObject(); Handle<HeapObject> GetHeapObject();
...@@ -661,6 +663,7 @@ class HeapSnapshot { ...@@ -661,6 +663,7 @@ class HeapSnapshot {
HeapEntry* root() { return root_entry_; } HeapEntry* root() { return root_entry_; }
HeapEntry* gc_roots() { return gc_roots_entry_; } HeapEntry* gc_roots() { return gc_roots_entry_; }
HeapEntry* natives_root() { return natives_root_entry_; } HeapEntry* natives_root() { return natives_root_entry_; }
HeapEntry* gc_subroot(int index) { return gc_subroot_entries_[index]; }
List<HeapEntry*>* entries() { return &entries_; } List<HeapEntry*>* entries() { return &entries_; }
int raw_entries_size() { return raw_entries_size_; } int raw_entries_size() { return raw_entries_size_; }
...@@ -674,6 +677,9 @@ class HeapSnapshot { ...@@ -674,6 +677,9 @@ class HeapSnapshot {
int retainers_count); int retainers_count);
HeapEntry* AddRootEntry(int children_count); HeapEntry* AddRootEntry(int children_count);
HeapEntry* AddGcRootsEntry(int children_count, int retainers_count); HeapEntry* AddGcRootsEntry(int children_count, int retainers_count);
HeapEntry* AddGcSubrootEntry(int tag,
int children_count,
int retainers_count);
HeapEntry* AddNativesRootEntry(int children_count, int retainers_count); HeapEntry* AddNativesRootEntry(int children_count, int retainers_count);
void ClearPaint(); void ClearPaint();
HeapEntry* GetEntryById(uint64_t id); HeapEntry* GetEntryById(uint64_t id);
...@@ -695,6 +701,7 @@ class HeapSnapshot { ...@@ -695,6 +701,7 @@ class HeapSnapshot {
HeapEntry* root_entry_; HeapEntry* root_entry_;
HeapEntry* gc_roots_entry_; HeapEntry* gc_roots_entry_;
HeapEntry* natives_root_entry_; HeapEntry* natives_root_entry_;
HeapEntry* gc_subroot_entries_[VisitorSynchronization::kNumberOfSyncTags];
char* raw_entries_; char* raw_entries_;
List<HeapEntry*> entries_; List<HeapEntry*> entries_;
bool entries_sorted_; bool entries_sorted_;
...@@ -716,10 +723,13 @@ class HeapObjectsMap { ...@@ -716,10 +723,13 @@ class HeapObjectsMap {
void MoveObject(Address from, Address to); void MoveObject(Address from, Address to);
static uint64_t GenerateId(v8::RetainedObjectInfo* info); static uint64_t GenerateId(v8::RetainedObjectInfo* info);
static inline uint64_t GetNthGcSubrootId(int delta);
static const int kObjectIdStep = 2;
static const uint64_t kInternalRootObjectId; static const uint64_t kInternalRootObjectId;
static const uint64_t kGcRootsObjectId; static const uint64_t kGcRootsObjectId;
static const uint64_t kNativesRootObjectId; static const uint64_t kNativesRootObjectId;
static const uint64_t kGcRootsFirstSubrootId;
static const uint64_t kFirstAvailableObjectId; static const uint64_t kFirstAvailableObjectId;
private: private:
...@@ -969,6 +979,11 @@ class V8HeapExplorer : public HeapEntriesAllocator { ...@@ -969,6 +979,11 @@ class V8HeapExplorer : public HeapEntriesAllocator {
HeapEntry* parent, HeapEntry* parent,
int index, int index,
Object* child); Object* child);
void SetWeakReference(HeapObject* parent_obj,
HeapEntry* parent_entry,
int index,
Object* child_obj,
int field_offset);
void SetPropertyReference(HeapObject* parent_obj, void SetPropertyReference(HeapObject* parent_obj,
HeapEntry* parent, HeapEntry* parent,
String* reference_name, String* reference_name,
...@@ -981,11 +996,16 @@ class V8HeapExplorer : public HeapEntriesAllocator { ...@@ -981,11 +996,16 @@ class V8HeapExplorer : public HeapEntriesAllocator {
Object* child); Object* child);
void SetRootShortcutReference(Object* child); void SetRootShortcutReference(Object* child);
void SetRootGcRootsReference(); void SetRootGcRootsReference();
void SetGcRootsReference(Object* child); void SetGcRootsReference(VisitorSynchronization::SyncTag tag);
void SetGcSubrootReference(
VisitorSynchronization::SyncTag tag, bool is_weak, Object* child);
void TagObject(Object* obj, const char* tag); void TagObject(Object* obj, const char* tag);
HeapEntry* GetEntry(Object* obj); HeapEntry* GetEntry(Object* obj);
static inline HeapObject* GetNthGcSubrootObject(int delta);
static inline int GetGcSubrootOrder(HeapObject* subroot);
Heap* heap_; Heap* heap_;
HeapSnapshot* snapshot_; HeapSnapshot* snapshot_;
HeapSnapshotsCollection* collection_; HeapSnapshotsCollection* collection_;
...@@ -994,8 +1014,11 @@ class V8HeapExplorer : public HeapEntriesAllocator { ...@@ -994,8 +1014,11 @@ class V8HeapExplorer : public HeapEntriesAllocator {
HeapObjectsSet objects_tags_; HeapObjectsSet objects_tags_;
static HeapObject* const kGcRootsObject; static HeapObject* const kGcRootsObject;
static HeapObject* const kFirstGcSubrootObject;
static HeapObject* const kLastGcSubrootObject;
friend class IndexedReferencesExtractor; friend class IndexedReferencesExtractor;
friend class GcSubrootsEnumerator;
friend class RootsReferencesExtractor; friend class RootsReferencesExtractor;
DISALLOW_COPY_AND_ASSIGN(V8HeapExplorer); DISALLOW_COPY_AND_ASSIGN(V8HeapExplorer);
......
...@@ -1065,3 +1065,82 @@ TEST(FastCaseGetter) { ...@@ -1065,3 +1065,82 @@ TEST(FastCaseGetter) {
GetProperty(obj1, v8::HeapGraphEdge::kProperty, "set-propWithSetter"); GetProperty(obj1, v8::HeapGraphEdge::kProperty, "set-propWithSetter");
CHECK_NE(NULL, setterFunction); CHECK_NE(NULL, setterFunction);
} }
bool HasWeakEdge(const v8::HeapGraphNode* node) {
for (int i = 0; i < node->GetChildrenCount(); ++i) {
const v8::HeapGraphEdge* handle_edge = node->GetChild(i);
if (handle_edge->GetType() == v8::HeapGraphEdge::kWeak) return true;
}
return false;
}
bool HasWeakGlobalHandle() {
const v8::HeapSnapshot* snapshot =
v8::HeapProfiler::TakeSnapshot(v8_str("weaks"));
const v8::HeapGraphNode* gc_roots = GetNode(
snapshot->GetRoot(), v8::HeapGraphNode::kObject, "(GC roots)");
CHECK_NE(NULL, gc_roots);
const v8::HeapGraphNode* global_handles = GetNode(
gc_roots, v8::HeapGraphNode::kObject, "(Global handles)");
CHECK_NE(NULL, global_handles);
return HasWeakEdge(global_handles);
}
static void PersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
handle.Dispose();
}
TEST(WeakGlobalHandle) {
v8::HandleScope scope;
LocalContext env;
CHECK(!HasWeakGlobalHandle());
v8::Persistent<v8::Object> handle =
v8::Persistent<v8::Object>::New(v8::Object::New());
handle.MakeWeak(NULL, PersistentHandleCallback);
CHECK(HasWeakGlobalHandle());
}
TEST(WeakGlobalContextRefs) {
v8::HandleScope scope;
LocalContext env;
const v8::HeapSnapshot* snapshot =
v8::HeapProfiler::TakeSnapshot(v8_str("weaks"));
const v8::HeapGraphNode* gc_roots = GetNode(
snapshot->GetRoot(), v8::HeapGraphNode::kObject, "(GC roots)");
CHECK_NE(NULL, gc_roots);
const v8::HeapGraphNode* global_handles = GetNode(
gc_roots, v8::HeapGraphNode::kObject, "(Global handles)");
CHECK_NE(NULL, global_handles);
const v8::HeapGraphNode* global_context = GetNode(
global_handles, v8::HeapGraphNode::kHidden, "system / GlobalContext");
CHECK_NE(NULL, global_context);
CHECK(HasWeakEdge(global_context));
}
TEST(SfiAndJsFunctionWeakRefs) {
v8::HandleScope scope;
LocalContext env;
CompileRun(
"fun = (function (x) { return function () { return x + 1; } })(1);");
const v8::HeapSnapshot* snapshot =
v8::HeapProfiler::TakeSnapshot(v8_str("fun"));
const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
CHECK_NE(NULL, global);
const v8::HeapGraphNode* fun =
GetProperty(global, v8::HeapGraphEdge::kShortcut, "fun");
CHECK(HasWeakEdge(fun));
const v8::HeapGraphNode* shared =
GetProperty(fun, v8::HeapGraphEdge::kInternal, "shared");
CHECK(HasWeakEdge(shared));
}
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