void HeapGraphEdge::Init(int child_index, Type type, int index, HeapEntry* to) {
- ASSERT(type == kElement || type == kHidden || type == kWeak);
+ ASSERT(type == kElement || type == kHidden);
child_index_ = child_index;
type_ = type;
index_ = index;
}
-void HeapEntry::Print(
- const char* prefix, const char* edge_name, int max_depth, int indent) {
- OS::Print("%6d %7d @%6llu %*c %s%s: ",
- self_size(), RetainedSize(false), id(),
- indent, ' ', prefix, edge_name);
+void HeapEntry::Print(int max_depth, int indent) {
+ OS::Print("%6d %6d [%llu] ", self_size(), RetainedSize(false), id());
if (type() != kString) {
OS::Print("%s %.40s\n", TypeAsString(), name_);
} else {
Vector<HeapGraphEdge> ch = children();
for (int i = 0; i < ch.length(); ++i) {
HeapGraphEdge& edge = ch[i];
- const char* edge_prefix = "";
- ScopedVector<char> index(64);
- const char* edge_name = index.start();
switch (edge.type()) {
case HeapGraphEdge::kContextVariable:
- edge_prefix = "#";
- edge_name = edge.name();
+ OS::Print(" %*c #%s: ", indent, ' ', edge.name());
break;
case HeapGraphEdge::kElement:
- OS::SNPrintF(index, "%d", edge.index());
+ OS::Print(" %*c %d: ", indent, ' ', edge.index());
break;
case HeapGraphEdge::kInternal:
- edge_prefix = "$";
- edge_name = edge.name();
+ OS::Print(" %*c $%s: ", indent, ' ', edge.name());
break;
case HeapGraphEdge::kProperty:
- edge_name = edge.name();
+ OS::Print(" %*c %s: ", indent, ' ', edge.name());
break;
case HeapGraphEdge::kHidden:
- edge_prefix = "$";
- OS::SNPrintF(index, "%d", edge.index());
+ OS::Print(" %*c $%d: ", indent, ' ', edge.index());
break;
case HeapGraphEdge::kShortcut:
- edge_prefix = "^";
- edge_name = edge.name();
- break;
- case HeapGraphEdge::kWeak:
- edge_prefix = "w";
- OS::SNPrintF(index, "%d", edge.index());
+ OS::Print(" %*c ^%s: ", indent, ' ', edge.name());
break;
default:
- OS::SNPrintF(index, "!!! unknown edge type: %d ", edge.type());
+ OS::Print("!!! unknown edge type: %d ", edge.type());
}
- edge.to()->Print(edge_prefix, edge_name, max_depth, indent + 2);
+ edge.to()->Print(max_depth, indent + 2);
}
}
STATIC_ASSERT(
sizeof(HeapEntry) ==
SnapshotSizeConstants<sizeof(void*)>::kExpectedHeapEntrySize); // NOLINT
- for (int i = 0; i < VisitorSynchronization::kNumberOfSyncTags; ++i) {
- gc_subroot_entries_[i] = NULL;
- }
}
HeapSnapshot::~HeapSnapshot() {
}
-HeapEntry* HeapSnapshot::AddGcSubrootEntry(int tag,
- int children_count,
- int retainers_count) {
- ASSERT(gc_subroot_entries_[tag] == NULL);
- ASSERT(0 <= tag && tag < VisitorSynchronization::kNumberOfSyncTags);
- return (gc_subroot_entries_[tag] = AddEntry(
- HeapEntry::kObject,
- VisitorSynchronization::kTagNames[tag],
- HeapObjectsMap::GetNthGcSubrootId(tag),
- 0,
- children_count,
- retainers_count));
-}
-
-
HeapEntry* HeapSnapshot::AddNativesRootEntry(int children_count,
int retainers_count) {
ASSERT(natives_root_entry_ == NULL);
void HeapSnapshot::Print(int max_depth) {
- root()->Print("", "", max_depth, 0);
+ root()->Print(max_depth, 0);
}
// We split IDs on evens for embedder objects (see
// HeapObjectsMap::GenerateId) and odds for native objects.
const uint64_t HeapObjectsMap::kInternalRootObjectId = 1;
-const uint64_t HeapObjectsMap::kGcRootsObjectId =
- HeapObjectsMap::kInternalRootObjectId + HeapObjectsMap::kObjectIdStep;
-const uint64_t HeapObjectsMap::kNativesRootObjectId =
- HeapObjectsMap::kGcRootsObjectId + HeapObjectsMap::kObjectIdStep;
-const uint64_t HeapObjectsMap::kGcRootsFirstSubrootId =
- HeapObjectsMap::kNativesRootObjectId + HeapObjectsMap::kObjectIdStep;
-const uint64_t HeapObjectsMap::kFirstAvailableObjectId =
- HeapObjectsMap::kGcRootsFirstSubrootId +
- VisitorSynchronization::kNumberOfSyncTags * HeapObjectsMap::kObjectIdStep;
+const uint64_t HeapObjectsMap::kGcRootsObjectId = 3;
+const uint64_t HeapObjectsMap::kNativesRootObjectId = 5;
+// Increase kFirstAvailableObjectId if new 'special' objects appear.
+const uint64_t HeapObjectsMap::kFirstAvailableObjectId = 7;
HeapObjectsMap::HeapObjectsMap()
: initial_fill_mode_(true),
if (existing != 0) return existing;
}
uint64_t id = next_id_;
- next_id_ += kObjectIdStep;
+ next_id_ += 2;
AddEntry(addr, id);
return id;
}
HeapObject *const V8HeapExplorer::kGcRootsObject =
reinterpret_cast<HeapObject*>(
static_cast<intptr_t>(HeapObjectsMap::kGcRootsObjectId));
-HeapObject *const V8HeapExplorer::kFirstGcSubrootObject =
- reinterpret_cast<HeapObject*>(
- static_cast<intptr_t>(HeapObjectsMap::kGcRootsFirstSubrootId));
-HeapObject *const V8HeapExplorer::kLastGcSubrootObject =
- reinterpret_cast<HeapObject*>(
- static_cast<intptr_t>(HeapObjectsMap::kFirstAvailableObjectId));
V8HeapExplorer::V8HeapExplorer(
return snapshot_->AddRootEntry(children_count);
} else if (object == kGcRootsObject) {
return snapshot_->AddGcRootsEntry(children_count, retainers_count);
- } else if (object >= kFirstGcSubrootObject && object < kLastGcSubrootObject) {
- return snapshot_->AddGcSubrootEntry(
- GetGcSubrootOrder(object),
- children_count,
- retainers_count);
} else if (object->IsJSGlobalObject()) {
const char* tag = objects_tags_.GetTag(object);
const char* name = collection_->names()->GetName(
: "",
children_count,
retainers_count);
- } else if (object->IsGlobalContext()) {
- return AddEntry(object,
- HeapEntry::kHidden,
- "system / GlobalContext",
- children_count,
- retainers_count);
- } else if (object->IsContext()) {
- return AddEntry(object,
- HeapEntry::kHidden,
- "system / Context",
- children_count,
- retainers_count);
} else if (object->IsFixedArray() ||
object->IsFixedDoubleArray() ||
object->IsByteArray() ||
}
-class GcSubrootsEnumerator : public ObjectVisitor {
- public:
- GcSubrootsEnumerator(
- SnapshotFillerInterface* filler, V8HeapExplorer* explorer)
- : filler_(filler),
- explorer_(explorer),
- previous_object_count_(0),
- object_count_(0) {
- }
- void VisitPointers(Object** start, Object** end) {
- object_count_ += end - start;
- }
- void Synchronize(VisitorSynchronization::SyncTag tag) {
- // Skip empty subroots.
- if (previous_object_count_ != object_count_) {
- previous_object_count_ = object_count_;
- filler_->AddEntry(V8HeapExplorer::GetNthGcSubrootObject(tag), explorer_);
- }
- }
- private:
- SnapshotFillerInterface* filler_;
- V8HeapExplorer* explorer_;
- intptr_t previous_object_count_;
- intptr_t object_count_;
-};
-
-
void V8HeapExplorer::AddRootEntries(SnapshotFillerInterface* filler) {
filler->AddEntry(kInternalRootObject, this);
filler->AddEntry(kGcRootsObject, this);
- GcSubrootsEnumerator enumerator(filler, this);
- heap_->IterateRoots(&enumerator, VISIT_ALL);
}
"literals_or_bindings",
js_fun->literals_or_bindings(),
JSFunction::kLiteralsOffset);
- for (int i = JSFunction::kNonWeakFieldsEndOffset;
- i < JSFunction::kSize;
- i += kPointerSize) {
- SetWeakReference(js_fun, entry, i, *HeapObject::RawField(js_fun, i), i);
- }
}
TagObject(js_obj->properties(), "(object properties)");
SetInternalReference(obj, entry,
"(context func. result caches)");
TagObject(context->normalized_map_cache(), "(context norm. map cache)");
TagObject(context->runtime_context(), "(runtime context)");
+ TagObject(context->map_cache(), "(context map cache)");
TagObject(context->data(), "(context data)");
- for (int i = Context::FIRST_WEAK_SLOT;
- i < Context::GLOBAL_CONTEXT_SLOTS;
- ++i) {
- SetWeakReference(obj, entry,
- i, context->get(i),
- FixedArray::OffsetOfElementAt(i));
- }
} else if (obj->IsMap()) {
Map* map = Map::cast(obj);
SetInternalReference(obj, entry,
SetInternalReference(obj, entry,
"script", shared->script(),
SharedFunctionInfo::kScriptOffset);
- SetWeakReference(obj, entry,
- 1, shared->initial_map(),
- SharedFunctionInfo::kInitialMapOffset);
} else if (obj->IsScript()) {
Script* script = Script::cast(obj);
SetInternalReference(obj, entry,
class RootsReferencesExtractor : public ObjectVisitor {
- private:
- struct IndexTag {
- IndexTag(int index, VisitorSynchronization::SyncTag tag)
- : index(index), tag(tag) { }
- int index;
- VisitorSynchronization::SyncTag tag;
- };
-
public:
- RootsReferencesExtractor()
- : collecting_all_references_(false),
- previous_reference_count_(0) {
+ explicit RootsReferencesExtractor(V8HeapExplorer* explorer)
+ : explorer_(explorer) {
}
-
void VisitPointers(Object** start, Object** end) {
- if (collecting_all_references_) {
- for (Object** p = start; p < end; p++) all_references_.Add(*p);
- } else {
- for (Object** p = start; p < end; p++) strong_references_.Add(*p);
- }
- }
-
- void SetCollectingAllReferences() { collecting_all_references_ = true; }
-
- void FillReferences(V8HeapExplorer* explorer) {
- ASSERT(strong_references_.length() <= all_references_.length());
- for (int i = 0; i < reference_tags_.length(); ++i) {
- explorer->SetGcRootsReference(reference_tags_[i].tag);
- }
- int strong_index = 0, all_index = 0, tags_index = 0;
- while (all_index < all_references_.length()) {
- if (strong_index < strong_references_.length() &&
- strong_references_[strong_index] == all_references_[all_index]) {
- explorer->SetGcSubrootReference(reference_tags_[tags_index].tag,
- false,
- all_references_[all_index++]);
- ++strong_index;
- } else {
- explorer->SetGcSubrootReference(reference_tags_[tags_index].tag,
- true,
- all_references_[all_index++]);
- }
- if (reference_tags_[tags_index].index == all_index) ++tags_index;
- }
- }
-
- void Synchronize(VisitorSynchronization::SyncTag tag) {
- if (collecting_all_references_ &&
- previous_reference_count_ != all_references_.length()) {
- previous_reference_count_ = all_references_.length();
- reference_tags_.Add(IndexTag(previous_reference_count_, tag));
- }
+ for (Object** p = start; p < end; p++) explorer_->SetGcRootsReference(*p);
}
-
private:
- bool collecting_all_references_;
- List<Object*> strong_references_;
- List<Object*> all_references_;
- int previous_reference_count_;
- List<IndexTag> reference_tags_;
+ V8HeapExplorer* explorer_;
};
return false;
}
SetRootGcRootsReference();
- RootsReferencesExtractor extractor;
- heap_->IterateRoots(&extractor, VISIT_ONLY_STRONG);
- extractor.SetCollectingAllReferences();
+ RootsReferencesExtractor extractor(this);
heap_->IterateRoots(&extractor, VISIT_ALL);
- extractor.FillReferences(this);
filler_ = NULL;
return progress_->ProgressReport(false);
}
}
-void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj,
- HeapEntry* parent_entry,
- int index,
- Object* child_obj,
- int field_offset) {
- HeapEntry* child_entry = GetEntry(child_obj);
- if (child_entry != NULL) {
- filler_->SetIndexedReference(HeapGraphEdge::kWeak,
- parent_obj,
- parent_entry,
- index,
- child_obj,
- child_entry);
- IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
- }
-}
-
-
void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj,
HeapEntry* parent_entry,
String* reference_name,
}
-void V8HeapExplorer::SetGcRootsReference(VisitorSynchronization::SyncTag tag) {
- filler_->SetIndexedAutoIndexReference(
- HeapGraphEdge::kElement,
- kGcRootsObject, snapshot_->gc_roots(),
- GetNthGcSubrootObject(tag), snapshot_->gc_subroot(tag));
-}
-
-
-void V8HeapExplorer::SetGcSubrootReference(
- VisitorSynchronization::SyncTag tag, bool is_weak, Object* child_obj) {
+void V8HeapExplorer::SetGcRootsReference(Object* child_obj) {
HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry != NULL) {
filler_->SetIndexedAutoIndexReference(
- is_weak ? HeapGraphEdge::kWeak : HeapGraphEdge::kElement,
- GetNthGcSubrootObject(tag), snapshot_->gc_subroot(tag),
+ HeapGraphEdge::kElement,
+ kGcRootsObject, snapshot_->gc_roots(),
child_obj, child_entry);
}
}
writer_->AddNumber(edge->type());
writer_->AddCharacter(',');
if (edge->type() == HeapGraphEdge::kElement
- || edge->type() == HeapGraphEdge::kHidden
- || edge->type() == HeapGraphEdge::kWeak) {
+ || edge->type() == HeapGraphEdge::kHidden) {
writer_->AddNumber(edge->index());
} else {
writer_->AddNumber(GetStringId(edge->name()));
"," JSON_S("property")
"," JSON_S("internal")
"," JSON_S("hidden")
- "," JSON_S("shortcut")
- "," JSON_S("weak"))
+ "," JSON_S("shortcut"))
"," JSON_S("string_or_number")
"," JSON_S("node"))))));
#undef JSON_S
kProperty = v8::HeapGraphEdge::kProperty,
kInternal = v8::HeapGraphEdge::kInternal,
kHidden = v8::HeapGraphEdge::kHidden,
- kShortcut = v8::HeapGraphEdge::kShortcut,
- kWeak = v8::HeapGraphEdge::kWeak
+ kShortcut = v8::HeapGraphEdge::kShortcut
};
HeapGraphEdge() { }
Type type() { return static_cast<Type>(type_); }
int index() {
- ASSERT(type_ == kElement || type_ == kHidden || type_ == kWeak);
+ ASSERT(type_ == kElement || type_ == kHidden);
return index_;
}
const char* name() {
int EntrySize() { return EntriesSize(1, children_count_, retainers_count_); }
int RetainedSize(bool exact);
- void Print(
- const char* prefix, const char* edge_name, int max_depth, int indent);
+ void Print(int max_depth, int indent);
Handle<HeapObject> GetHeapObject();
HeapEntry* root() { return root_entry_; }
HeapEntry* gc_roots() { return gc_roots_entry_; }
HeapEntry* natives_root() { return natives_root_entry_; }
- HeapEntry* gc_subroot(int index) { return gc_subroot_entries_[index]; }
List<HeapEntry*>* entries() { return &entries_; }
int raw_entries_size() { return raw_entries_size_; }
int retainers_count);
HeapEntry* AddRootEntry(int children_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);
void ClearPaint();
HeapEntry* GetEntryById(uint64_t id);
HeapEntry* root_entry_;
HeapEntry* gc_roots_entry_;
HeapEntry* natives_root_entry_;
- HeapEntry* gc_subroot_entries_[VisitorSynchronization::kNumberOfSyncTags];
char* raw_entries_;
List<HeapEntry*> entries_;
bool entries_sorted_;
void MoveObject(Address from, Address to);
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 kGcRootsObjectId;
static const uint64_t kNativesRootObjectId;
- static const uint64_t kGcRootsFirstSubrootId;
static const uint64_t kFirstAvailableObjectId;
private:
HeapEntry* parent,
int index,
Object* child);
- void SetWeakReference(HeapObject* parent_obj,
- HeapEntry* parent_entry,
- int index,
- Object* child_obj,
- int field_offset);
void SetPropertyReference(HeapObject* parent_obj,
HeapEntry* parent,
String* reference_name,
Object* child);
void SetRootShortcutReference(Object* child);
void SetRootGcRootsReference();
- void SetGcRootsReference(VisitorSynchronization::SyncTag tag);
- void SetGcSubrootReference(
- VisitorSynchronization::SyncTag tag, bool is_weak, Object* child);
+ void SetGcRootsReference(Object* child);
void TagObject(Object* obj, const char* tag);
HeapEntry* GetEntry(Object* obj);
- static inline HeapObject* GetNthGcSubrootObject(int delta);
- static inline int GetGcSubrootOrder(HeapObject* subroot);
-
Heap* heap_;
HeapSnapshot* snapshot_;
HeapSnapshotsCollection* collection_;
HeapObjectsSet objects_tags_;
static HeapObject* const kGcRootsObject;
- static HeapObject* const kFirstGcSubrootObject;
- static HeapObject* const kLastGcSubrootObject;
friend class IndexedReferencesExtractor;
- friend class GcSubrootsEnumerator;
friend class RootsReferencesExtractor;
DISALLOW_COPY_AND_ASSIGN(V8HeapExplorer);
GetProperty(obj1, v8::HeapGraphEdge::kProperty, "set-propWithSetter");
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));
-}