summaryrefslogtreecommitdiff
path: root/deps/v8/src/profile-generator.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/profile-generator.cc')
-rw-r--r--deps/v8/src/profile-generator.cc632
1 files changed, 501 insertions, 131 deletions
diff --git a/deps/v8/src/profile-generator.cc b/deps/v8/src/profile-generator.cc
index e319efb043..c6e6131a71 100644
--- a/deps/v8/src/profile-generator.cc
+++ b/deps/v8/src/profile-generator.cc
@@ -152,9 +152,12 @@ const char* StringsStorage::GetVFormatted(const char* format, va_list args) {
const char* StringsStorage::GetName(String* name) {
if (name->IsString()) {
- return AddOrDisposeString(
- name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL).Detach(),
- name->Hash());
+ int length = Min(kMaxNameSize, name->length());
+ SmartArrayPointer<char> data =
+ name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL, 0, length);
+ uint32_t hash =
+ HashSequentialString(*data, length, name->GetHeap()->HashSeed());
+ return AddOrDisposeString(data.Detach(), hash);
}
return "";
}
@@ -493,8 +496,6 @@ void CpuProfile::Print() {
CodeEntry* const CodeMap::kSharedFunctionCodeEntry = NULL;
const CodeMap::CodeTreeConfig::Key CodeMap::CodeTreeConfig::kNoKey = NULL;
-const CodeMap::CodeTreeConfig::Value CodeMap::CodeTreeConfig::kNoValue =
- CodeMap::CodeEntryInfo(NULL, 0);
void CodeMap::AddCode(Address addr, CodeEntry* entry, unsigned size) {
@@ -903,7 +904,7 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
entry++;
}
- for (const Address *stack_pos = sample.stack,
+ for (const Address* stack_pos = sample.stack,
*stack_end = stack_pos + sample.frames_count;
stack_pos != stack_end;
++stack_pos) {
@@ -943,7 +944,7 @@ void HeapGraphEdge::Init(
void HeapGraphEdge::Init(int child_index, Type type, int index, HeapEntry* to) {
- ASSERT(type == kElement || type == kHidden);
+ ASSERT(type == kElement || type == kHidden || type == kWeak);
child_index_ = child_index;
type_ = type;
index_ = index;
@@ -1058,8 +1059,11 @@ void HeapEntry::PaintAllReachable() {
}
-void HeapEntry::Print(int max_depth, int indent) {
- OS::Print("%6d %6d [%llu] ", self_size(), RetainedSize(false), id());
+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);
if (type() != kString) {
OS::Print("%s %.40s\n", TypeAsString(), name_);
} else {
@@ -1078,29 +1082,40 @@ void HeapEntry::Print(int max_depth, int indent) {
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:
- OS::Print(" %*c #%s: ", indent, ' ', edge.name());
+ edge_prefix = "#";
+ edge_name = edge.name();
break;
case HeapGraphEdge::kElement:
- OS::Print(" %*c %d: ", indent, ' ', edge.index());
+ OS::SNPrintF(index, "%d", edge.index());
break;
case HeapGraphEdge::kInternal:
- OS::Print(" %*c $%s: ", indent, ' ', edge.name());
+ edge_prefix = "$";
+ edge_name = edge.name();
break;
case HeapGraphEdge::kProperty:
- OS::Print(" %*c %s: ", indent, ' ', edge.name());
+ edge_name = edge.name();
break;
case HeapGraphEdge::kHidden:
- OS::Print(" %*c $%d: ", indent, ' ', edge.index());
+ edge_prefix = "$";
+ OS::SNPrintF(index, "%d", edge.index());
break;
case HeapGraphEdge::kShortcut:
- OS::Print(" %*c ^%s: ", indent, ' ', edge.name());
+ edge_prefix = "^";
+ edge_name = edge.name();
+ break;
+ case HeapGraphEdge::kWeak:
+ edge_prefix = "w";
+ OS::SNPrintF(index, "%d", edge.index());
break;
default:
- OS::Print("!!! unknown edge type: %d ", edge.type());
+ OS::SNPrintF(index, "!!! unknown edge type: %d ", edge.type());
}
- edge.to()->Print(max_depth, indent + 2);
+ edge.to()->Print(edge_prefix, edge_name, max_depth, indent + 2);
}
}
@@ -1116,6 +1131,7 @@ const char* HeapEntry::TypeAsString() {
case kRegExp: return "/regexp/";
case kHeapNumber: return "/number/";
case kNative: return "/native/";
+ case kSynthetic: return "/synthetic/";
default: return "???";
}
}
@@ -1219,7 +1235,10 @@ HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection,
SnapshotSizeConstants<kPointerSize>::kExpectedHeapGraphEdgeSize);
STATIC_ASSERT(
sizeof(HeapEntry) ==
- SnapshotSizeConstants<sizeof(void*)>::kExpectedHeapEntrySize); // NOLINT
+ SnapshotSizeConstants<kPointerSize>::kExpectedHeapEntrySize);
+ for (int i = 0; i < VisitorSynchronization::kNumberOfSyncTags; ++i) {
+ gc_subroot_entries_[i] = NULL;
+ }
}
HeapSnapshot::~HeapSnapshot() {
@@ -1275,13 +1294,15 @@ HeapEntry* HeapSnapshot::AddGcRootsEntry(int children_count,
}
-HeapEntry* HeapSnapshot::AddNativesRootEntry(int children_count,
- int retainers_count) {
- ASSERT(natives_root_entry_ == NULL);
- return (natives_root_entry_ = AddEntry(
+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,
- "(Native objects)",
- HeapObjectsMap::kNativesRootObjectId,
+ VisitorSynchronization::kTagNames[tag],
+ HeapObjectsMap::GetNthGcSubrootId(tag),
0,
children_count,
retainers_count));
@@ -1360,17 +1381,20 @@ List<HeapEntry*>* HeapSnapshot::GetSortedEntriesList() {
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 = 3;
-const uint64_t HeapObjectsMap::kNativesRootObjectId = 5;
-// Increase kFirstAvailableObjectId if new 'special' objects appear.
-const uint64_t HeapObjectsMap::kFirstAvailableObjectId = 7;
+const uint64_t HeapObjectsMap::kGcRootsObjectId =
+ HeapObjectsMap::kInternalRootObjectId + HeapObjectsMap::kObjectIdStep;
+const uint64_t HeapObjectsMap::kGcRootsFirstSubrootId =
+ HeapObjectsMap::kGcRootsObjectId + HeapObjectsMap::kObjectIdStep;
+const uint64_t HeapObjectsMap::kFirstAvailableObjectId =
+ HeapObjectsMap::kGcRootsFirstSubrootId +
+ VisitorSynchronization::kNumberOfSyncTags * HeapObjectsMap::kObjectIdStep;
HeapObjectsMap::HeapObjectsMap()
: initial_fill_mode_(true),
@@ -1396,7 +1420,7 @@ uint64_t HeapObjectsMap::FindObject(Address addr) {
if (existing != 0) return existing;
}
uint64_t id = next_id_;
- next_id_ += 2;
+ next_id_ += kObjectIdStep;
AddEntry(addr, id);
return id;
}
@@ -1408,10 +1432,12 @@ void HeapObjectsMap::MoveObject(Address from, Address to) {
if (entry != NULL) {
void* value = entry->value;
entries_map_.Remove(from, AddressHash(from));
- entry = entries_map_.Lookup(to, AddressHash(to), true);
- // We can have an entry at the new location, it is OK, as GC can overwrite
- // dead objects with alive objects being moved.
- entry->value = value;
+ if (to != NULL) {
+ entry = entries_map_.Lookup(to, AddressHash(to), true);
+ // We can have an entry at the new location, it is OK, as GC can overwrite
+ // dead objects with alive objects being moved.
+ entry->value = value;
+ }
}
}
@@ -1536,6 +1562,9 @@ void HeapSnapshotsCollection::RemoveSnapshot(HeapSnapshot* snapshot) {
Handle<HeapObject> HeapSnapshotsCollection::FindHeapObjectById(uint64_t id) {
+ // First perform a full GC in order to avoid dead objects.
+ HEAP->CollectAllGarbage(Heap::kMakeHeapIterableMask,
+ "HeapSnapshotsCollection::FindHeapObjectById");
AssertNoAllocation no_allocation;
HeapObject* object = NULL;
HeapIterator iterator(HeapIterator::kFilterUnreachable);
@@ -1553,7 +1582,7 @@ Handle<HeapObject> HeapSnapshotsCollection::FindHeapObjectById(uint64_t id) {
}
-HeapEntry *const HeapEntriesMap::kHeapEntryPlaceholder =
+HeapEntry* const HeapEntriesMap::kHeapEntryPlaceholder =
reinterpret_cast<HeapEntry*>(1);
HeapEntriesMap::HeapEntriesMap()
@@ -1682,12 +1711,18 @@ void HeapObjectsSet::SetTag(Object* obj, const char* tag) {
}
-HeapObject *const V8HeapExplorer::kInternalRootObject =
+HeapObject* const V8HeapExplorer::kInternalRootObject =
reinterpret_cast<HeapObject*>(
static_cast<intptr_t>(HeapObjectsMap::kInternalRootObjectId));
-HeapObject *const V8HeapExplorer::kGcRootsObject =
+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(
@@ -1720,6 +1755,11 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object,
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(
@@ -1783,6 +1823,18 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object,
: "",
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() ||
@@ -1822,9 +1874,38 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object,
}
+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);
}
@@ -1843,12 +1924,13 @@ const char* V8HeapExplorer::GetSystemEntryName(HeapObject* object) {
}
-int V8HeapExplorer::EstimateObjectsCount() {
- HeapIterator iterator(HeapIterator::kFilterUnreachable);
+int V8HeapExplorer::EstimateObjectsCount(HeapIterator* iterator) {
int objects_count = 0;
- for (HeapObject* obj = iterator.next();
+ for (HeapObject* obj = iterator->next();
obj != NULL;
- obj = iterator.next(), ++objects_count) {}
+ obj = iterator->next()) {
+ objects_count++;
+ }
return objects_count;
}
@@ -1921,6 +2003,7 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
SetPropertyReference(
obj, entry,
heap_->prototype_symbol(), proto_or_map,
+ NULL,
JSFunction::kPrototypeOrInitialMapOffset);
} else {
SetPropertyReference(
@@ -1935,10 +2018,17 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
SetInternalReference(js_fun, entry,
"context", js_fun->unchecked_context(),
JSFunction::kContextOffset);
- TagObject(js_fun->literals(), "(function literals)");
+ TagObject(js_fun->literals_or_bindings(),
+ "(function literals_or_bindings)");
SetInternalReference(js_fun, entry,
- "literals", js_fun->literals(),
+ "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,
@@ -1954,6 +2044,10 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
SetInternalReference(obj, entry, 1, cs->first());
SetInternalReference(obj, entry, 2, cs->second());
}
+ if (obj->IsSlicedString()) {
+ SlicedString* ss = SlicedString::cast(obj);
+ SetInternalReference(obj, entry, "parent", ss->parent());
+ }
extract_indexed_refs = false;
} else if (obj->IsGlobalContext()) {
Context* context = Context::cast(obj);
@@ -1961,8 +2055,14 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
"(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,
@@ -1976,6 +2076,14 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
"descriptors", map->instance_descriptors(),
Map::kInstanceDescriptorsOrBitField3Offset);
}
+ if (map->prototype_transitions() != heap_->empty_fixed_array()) {
+ TagObject(map->prototype_transitions(), "(prototype transitions)");
+ SetInternalReference(obj,
+ entry,
+ "prototype_transitions",
+ map->prototype_transitions(),
+ Map::kPrototypeTransitionsOffset);
+ }
SetInternalReference(obj, entry,
"code_cache", map->code_cache(),
Map::kCodeCacheOffset);
@@ -1997,6 +2105,9 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
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,
@@ -2052,20 +2163,27 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj,
HeapEntry* entry) {
if (js_obj->IsJSFunction()) {
- HandleScope hs;
JSFunction* func = JSFunction::cast(js_obj);
Context* context = func->context();
- ZoneScope zscope(Isolate::Current(), DELETE_ON_EXIT);
- SerializedScopeInfo* serialized_scope_info =
- context->closure()->shared()->scope_info();
- ScopeInfo<ZoneListAllocationPolicy> zone_scope_info(serialized_scope_info);
- int locals_number = zone_scope_info.NumberOfLocals();
- for (int i = 0; i < locals_number; ++i) {
- String* local_name = *zone_scope_info.LocalName(i);
- int idx = serialized_scope_info->ContextSlotIndex(local_name, NULL);
- if (idx >= 0 && idx < context->length()) {
- SetClosureReference(js_obj, entry, local_name, context->get(idx));
- }
+ ScopeInfo* scope_info = context->closure()->shared()->scope_info();
+
+ // Add context allocated locals.
+ int context_locals = scope_info->ContextLocalCount();
+ for (int i = 0; i < context_locals; ++i) {
+ String* local_name = scope_info->ContextLocalName(i);
+ int idx = Context::MIN_CONTEXT_SLOTS + i;
+ SetClosureReference(js_obj, entry, local_name, context->get(idx));
+ }
+
+ // Add function variable.
+ if (scope_info->HasFunctionName()) {
+ String* name = scope_info->FunctionName();
+ int idx = Context::MIN_CONTEXT_SLOTS + context_locals;
+#ifdef DEBUG
+ VariableMode mode;
+ ASSERT(idx == scope_info->FunctionContextSlotIndex(name, &mode));
+#endif
+ SetClosureReference(js_obj, entry, name, context->get(idx));
}
}
}
@@ -2083,6 +2201,7 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj,
SetPropertyReference(
js_obj, entry,
descs->GetKey(i), js_obj->InObjectPropertyAt(index),
+ NULL,
js_obj->GetInObjectPropertyOffset(index));
} else {
SetPropertyReference(
@@ -2096,7 +2215,29 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj,
js_obj, entry,
descs->GetKey(i), descs->GetConstantFunction(i));
break;
- default: ;
+ case CALLBACKS: {
+ Object* callback_obj = descs->GetValue(i);
+ if (callback_obj->IsAccessorPair()) {
+ AccessorPair* accessors = AccessorPair::cast(callback_obj);
+ if (Object* getter = accessors->getter()) {
+ SetPropertyReference(js_obj, entry, descs->GetKey(i),
+ getter, "get-%s");
+ }
+ if (Object* setter = accessors->setter()) {
+ SetPropertyReference(js_obj, entry, descs->GetKey(i),
+ setter, "set-%s");
+ }
+ }
+ break;
+ }
+ case NORMAL: // only in slow mode
+ case HANDLER: // only in lookup results, not in descriptors
+ case INTERCEPTOR: // only in lookup results, not in descriptors
+ case MAP_TRANSITION: // we do not care about transitions here...
+ case ELEMENTS_TRANSITION:
+ case CONSTANT_TRANSITION:
+ case NULL_DESCRIPTOR: // ... and not about "holes"
+ break;
}
}
} else {
@@ -2161,15 +2302,16 @@ void V8HeapExplorer::ExtractInternalReferences(JSObject* js_obj,
String* V8HeapExplorer::GetConstructorName(JSObject* object) {
- if (object->IsJSFunction()) return HEAP->closure_symbol();
+ Heap* heap = object->GetHeap();
+ if (object->IsJSFunction()) return heap->closure_symbol();
String* constructor_name = object->constructor_name();
- if (constructor_name == HEAP->Object_symbol()) {
+ if (constructor_name == heap->Object_symbol()) {
// Look up an immediate "constructor" property, if it is a function,
// return its name. This is for instances of binding objects, which
// have prototype constructor type "Object".
Object* constructor_prop = NULL;
- LookupResult result;
- object->LocalLookupRealNamedProperty(HEAP->constructor_symbol(), &result);
+ LookupResult result(heap->isolate());
+ object->LocalLookupRealNamedProperty(heap->constructor_symbol(), &result);
if (result.IsProperty()) {
constructor_prop = result.GetLazyValue();
}
@@ -2192,23 +2334,76 @@ HeapEntry* V8HeapExplorer::GetEntry(Object* obj) {
class RootsReferencesExtractor : public ObjectVisitor {
+ private:
+ struct IndexTag {
+ IndexTag(int index, VisitorSynchronization::SyncTag tag)
+ : index(index), tag(tag) { }
+ int index;
+ VisitorSynchronization::SyncTag tag;
+ };
+
public:
- explicit RootsReferencesExtractor(V8HeapExplorer* explorer)
- : explorer_(explorer) {
+ RootsReferencesExtractor()
+ : collecting_all_references_(false),
+ previous_reference_count_(0) {
}
+
void VisitPointers(Object** start, Object** end) {
- for (Object** p = start; p < end; p++) explorer_->SetGcRootsReference(*p);
+ 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));
+ }
+ }
+
private:
- V8HeapExplorer* explorer_;
+ bool collecting_all_references_;
+ List<Object*> strong_references_;
+ List<Object*> all_references_;
+ int previous_reference_count_;
+ List<IndexTag> reference_tags_;
};
bool V8HeapExplorer::IterateAndExtractReferences(
SnapshotFillerInterface* filler) {
- filler_ = filler;
HeapIterator iterator(HeapIterator::kFilterUnreachable);
+
+ filler_ = filler;
bool interrupted = false;
+
// Heap iteration with filtering must be finished in any case.
for (HeapObject* obj = iterator.next();
obj != NULL;
@@ -2223,8 +2418,11 @@ bool V8HeapExplorer::IterateAndExtractReferences(
return false;
}
SetRootGcRootsReference();
- RootsReferencesExtractor extractor(this);
+ RootsReferencesExtractor extractor;
+ heap_->IterateRoots(&extractor, VISIT_ONLY_STRONG);
+ extractor.SetCollectingAllReferences();
heap_->IterateRoots(&extractor, VISIT_ALL);
+ extractor.FillReferences(this);
filler_ = NULL;
return progress_->ProgressReport(false);
}
@@ -2314,19 +2512,45 @@ void V8HeapExplorer::SetHiddenReference(HeapObject* parent_obj,
}
+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,
Object* child_obj,
+ const char* name_format_string,
int field_offset) {
HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry != NULL) {
HeapGraphEdge::Type type = reference_name->length() > 0 ?
HeapGraphEdge::kProperty : HeapGraphEdge::kInternal;
+ const char* name = name_format_string != NULL ?
+ collection_->names()->GetFormatted(
+ name_format_string,
+ *reference_name->ToCString(DISALLOW_NULLS,
+ ROBUST_STRING_TRAVERSAL)) :
+ collection_->names()->GetName(reference_name);
+
filler_->SetNamedReference(type,
parent_obj,
parent_entry,
- collection_->names()->GetName(reference_name),
+ name,
child_obj,
child_entry);
IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
@@ -2368,12 +2592,21 @@ void V8HeapExplorer::SetRootShortcutReference(Object* child_obj) {
}
-void V8HeapExplorer::SetGcRootsReference(Object* child_obj) {
+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) {
HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry != NULL) {
filler_->SetIndexedAutoIndexReference(
- HeapGraphEdge::kElement,
- kGcRootsObject, snapshot_->gc_roots(),
+ is_weak ? HeapGraphEdge::kWeak : HeapGraphEdge::kElement,
+ GetNthGcSubrootObject(tag), snapshot_->gc_subroot(tag),
child_obj, child_entry);
}
}
@@ -2417,6 +2650,7 @@ class GlobalObjectsEnumerator : public ObjectVisitor {
// Modifies heap. Must not be run during heap traversal.
void V8HeapExplorer::TagGlobalObjects() {
+ HandleScope scope;
Isolate* isolate = Isolate::Current();
GlobalObjectsEnumerator enumerator;
isolate->global_handles()->IterateAllRoots(&enumerator);
@@ -2427,6 +2661,7 @@ void V8HeapExplorer::TagGlobalObjects() {
const char** urls = NewArray<const char*>(enumerator.count());
for (int i = 0, l = enumerator.count(); i < l; ++i) {
urls[i] = NULL;
+ HandleScope scope;
Handle<JSGlobalObject> global_obj = enumerator.at(i);
Object* obj_document;
if (global_obj->GetProperty(*document_string)->ToObject(&obj_document) &&
@@ -2464,9 +2699,43 @@ class GlobalHandlesExtractor : public ObjectVisitor {
NativeObjectsExplorer* explorer_;
};
-HeapThing const NativeObjectsExplorer::kNativesRootObject =
- reinterpret_cast<HeapThing>(
- static_cast<intptr_t>(HeapObjectsMap::kNativesRootObjectId));
+
+class BasicHeapEntriesAllocator : public HeapEntriesAllocator {
+ public:
+ BasicHeapEntriesAllocator(
+ HeapSnapshot* snapshot,
+ HeapEntry::Type entries_type)
+ : snapshot_(snapshot),
+ collection_(snapshot_->collection()),
+ entries_type_(entries_type) {
+ }
+ virtual HeapEntry* AllocateEntry(
+ HeapThing ptr, int children_count, int retainers_count);
+ private:
+ HeapSnapshot* snapshot_;
+ HeapSnapshotsCollection* collection_;
+ HeapEntry::Type entries_type_;
+};
+
+
+HeapEntry* BasicHeapEntriesAllocator::AllocateEntry(
+ HeapThing ptr, int children_count, int retainers_count) {
+ v8::RetainedObjectInfo* info = reinterpret_cast<v8::RetainedObjectInfo*>(ptr);
+ intptr_t elements = info->GetElementCount();
+ intptr_t size = info->GetSizeInBytes();
+ return snapshot_->AddEntry(
+ entries_type_,
+ elements != -1 ?
+ collection_->names()->GetFormatted(
+ "%s / %" V8_PTR_PREFIX "d entries",
+ info->GetLabel(),
+ info->GetElementCount()) :
+ collection_->names()->GetCopy(info->GetLabel()),
+ HeapObjectsMap::GenerateId(info),
+ size != -1 ? static_cast<int>(size) : 0,
+ children_count,
+ retainers_count);
+}
NativeObjectsExplorer::NativeObjectsExplorer(
@@ -2476,7 +2745,12 @@ NativeObjectsExplorer::NativeObjectsExplorer(
progress_(progress),
embedder_queried_(false),
objects_by_info_(RetainedInfosMatch),
+ native_groups_(StringsMatch),
filler_(NULL) {
+ synthetic_entries_allocator_ =
+ new BasicHeapEntriesAllocator(snapshot, HeapEntry::kSynthetic);
+ native_entries_allocator_ =
+ new BasicHeapEntriesAllocator(snapshot, HeapEntry::kNative);
}
@@ -2491,37 +2765,15 @@ NativeObjectsExplorer::~NativeObjectsExplorer() {
reinterpret_cast<List<HeapObject*>* >(p->value);
delete objects;
}
-}
-
-
-HeapEntry* NativeObjectsExplorer::AllocateEntry(
- HeapThing ptr, int children_count, int retainers_count) {
- if (ptr == kNativesRootObject) {
- return snapshot_->AddNativesRootEntry(children_count, retainers_count);
- } else {
+ for (HashMap::Entry* p = native_groups_.Start();
+ p != NULL;
+ p = native_groups_.Next(p)) {
v8::RetainedObjectInfo* info =
- reinterpret_cast<v8::RetainedObjectInfo*>(ptr);
- intptr_t elements = info->GetElementCount();
- intptr_t size = info->GetSizeInBytes();
- return snapshot_->AddEntry(
- HeapEntry::kNative,
- elements != -1 ?
- collection_->names()->GetFormatted(
- "%s / %" V8_PTR_PREFIX "d entries",
- info->GetLabel(),
- info->GetElementCount()) :
- collection_->names()->GetCopy(info->GetLabel()),
- HeapObjectsMap::GenerateId(info),
- size != -1 ? static_cast<int>(size) : 0,
- children_count,
- retainers_count);
+ reinterpret_cast<v8::RetainedObjectInfo*>(p->value);
+ info->Dispose();
}
-}
-
-
-void NativeObjectsExplorer::AddRootEntries(SnapshotFillerInterface* filler) {
- if (EstimateObjectsCount() <= 0) return;
- filler->AddEntry(kNativesRootObject, this);
+ delete synthetic_entries_allocator_;
+ delete native_entries_allocator_;
}
@@ -2556,6 +2808,29 @@ void NativeObjectsExplorer::FillRetainedObjects() {
embedder_queried_ = true;
}
+void NativeObjectsExplorer::FillImplicitReferences() {
+ Isolate* isolate = Isolate::Current();
+ List<ImplicitRefGroup*>* groups =
+ isolate->global_handles()->implicit_ref_groups();
+ for (int i = 0; i < groups->length(); ++i) {
+ ImplicitRefGroup* group = groups->at(i);
+ HeapObject* parent = *group->parent_;
+ HeapEntry* parent_entry =
+ filler_->FindOrAddEntry(parent, native_entries_allocator_);
+ ASSERT(parent_entry != NULL);
+ Object*** children = group->children_;
+ for (size_t j = 0; j < group->length_; ++j) {
+ Object* child = *children[j];
+ HeapEntry* child_entry =
+ filler_->FindOrAddEntry(child, native_entries_allocator_);
+ filler_->SetNamedReference(
+ HeapGraphEdge::kInternal,
+ parent, parent_entry,
+ "native",
+ child, child_entry);
+ }
+ }
+}
List<HeapObject*>* NativeObjectsExplorer::GetListMaybeDisposeInfo(
v8::RetainedObjectInfo* info) {
@@ -2572,34 +2847,82 @@ List<HeapObject*>* NativeObjectsExplorer::GetListMaybeDisposeInfo(
bool NativeObjectsExplorer::IterateAndExtractReferences(
SnapshotFillerInterface* filler) {
- if (EstimateObjectsCount() <= 0) return true;
filler_ = filler;
FillRetainedObjects();
- for (HashMap::Entry* p = objects_by_info_.Start();
- p != NULL;
- p = objects_by_info_.Next(p)) {
- v8::RetainedObjectInfo* info =
- reinterpret_cast<v8::RetainedObjectInfo*>(p->key);
- SetNativeRootReference(info);
- List<HeapObject*>* objects =
- reinterpret_cast<List<HeapObject*>* >(p->value);
- for (int i = 0; i < objects->length(); ++i) {
- SetWrapperNativeReferences(objects->at(i), info);
+ FillImplicitReferences();
+ if (EstimateObjectsCount() > 0) {
+ for (HashMap::Entry* p = objects_by_info_.Start();
+ p != NULL;
+ p = objects_by_info_.Next(p)) {
+ v8::RetainedObjectInfo* info =
+ reinterpret_cast<v8::RetainedObjectInfo*>(p->key);
+ SetNativeRootReference(info);
+ List<HeapObject*>* objects =
+ reinterpret_cast<List<HeapObject*>* >(p->value);
+ for (int i = 0; i < objects->length(); ++i) {
+ SetWrapperNativeReferences(objects->at(i), info);
+ }
}
+ SetRootNativeRootsReference();
}
- SetRootNativesRootReference();
filler_ = NULL;
return true;
}
+class NativeGroupRetainedObjectInfo : public v8::RetainedObjectInfo {
+ public:
+ explicit NativeGroupRetainedObjectInfo(const char* label)
+ : disposed_(false),
+ hash_(reinterpret_cast<intptr_t>(label)),
+ label_(label) {
+ }
+
+ virtual ~NativeGroupRetainedObjectInfo() {}
+ virtual void Dispose() {
+ CHECK(!disposed_);
+ disposed_ = true;
+ delete this;
+ }
+ virtual bool IsEquivalent(RetainedObjectInfo* other) {
+ return hash_ == other->GetHash() && !strcmp(label_, other->GetLabel());
+ }
+ virtual intptr_t GetHash() { return hash_; }
+ virtual const char* GetLabel() { return label_; }
+
+ private:
+ bool disposed_;
+ intptr_t hash_;
+ const char* label_;
+};
+
+
+NativeGroupRetainedObjectInfo* NativeObjectsExplorer::FindOrAddGroupInfo(
+ const char* label) {
+ const char* label_copy = collection_->names()->GetCopy(label);
+ uint32_t hash = HashSequentialString(label_copy,
+ static_cast<int>(strlen(label_copy)),
+ HEAP->HashSeed());
+ HashMap::Entry* entry = native_groups_.Lookup(const_cast<char*>(label_copy),
+ hash, true);
+ if (entry->value == NULL)
+ entry->value = new NativeGroupRetainedObjectInfo(label);
+ return static_cast<NativeGroupRetainedObjectInfo*>(entry->value);
+}
+
+
void NativeObjectsExplorer::SetNativeRootReference(
v8::RetainedObjectInfo* info) {
- HeapEntry* child_entry = filler_->FindOrAddEntry(info, this);
+ HeapEntry* child_entry =
+ filler_->FindOrAddEntry(info, native_entries_allocator_);
ASSERT(child_entry != NULL);
- filler_->SetIndexedAutoIndexReference(
- HeapGraphEdge::kElement,
- kNativesRootObject, snapshot_->natives_root(),
+ NativeGroupRetainedObjectInfo* group_info =
+ FindOrAddGroupInfo(info->GetGroupLabel());
+ HeapEntry* group_entry =
+ filler_->FindOrAddEntry(group_info, synthetic_entries_allocator_);
+ filler_->SetNamedAutoIndexReference(
+ HeapGraphEdge::kInternal,
+ group_info, group_entry,
info, child_entry);
}
@@ -2608,7 +2931,8 @@ void NativeObjectsExplorer::SetWrapperNativeReferences(
HeapObject* wrapper, v8::RetainedObjectInfo* info) {
HeapEntry* wrapper_entry = filler_->FindEntry(wrapper);
ASSERT(wrapper_entry != NULL);
- HeapEntry* info_entry = filler_->FindOrAddEntry(info, this);
+ HeapEntry* info_entry =
+ filler_->FindOrAddEntry(info, native_entries_allocator_);
ASSERT(info_entry != NULL);
filler_->SetNamedReference(HeapGraphEdge::kInternal,
wrapper, wrapper_entry,
@@ -2620,11 +2944,20 @@ void NativeObjectsExplorer::SetWrapperNativeReferences(
}
-void NativeObjectsExplorer::SetRootNativesRootReference() {
- filler_->SetIndexedAutoIndexReference(
- HeapGraphEdge::kElement,
- V8HeapExplorer::kInternalRootObject, snapshot_->root(),
- kNativesRootObject, snapshot_->natives_root());
+void NativeObjectsExplorer::SetRootNativeRootsReference() {
+ for (HashMap::Entry* entry = native_groups_.Start();
+ entry;
+ entry = native_groups_.Next(entry)) {
+ NativeGroupRetainedObjectInfo* group_info =
+ static_cast<NativeGroupRetainedObjectInfo*>(entry->value);
+ HeapEntry* group_entry =
+ filler_->FindOrAddEntry(group_info, native_entries_allocator_);
+ ASSERT(group_entry != NULL);
+ filler_->SetIndexedAutoIndexReference(
+ HeapGraphEdge::kElement,
+ V8HeapExplorer::kInternalRootObject, snapshot_->root(),
+ group_info, group_entry);
+ }
}
@@ -2774,13 +3107,47 @@ class SnapshotFiller : public SnapshotFillerInterface {
bool HeapSnapshotGenerator::GenerateSnapshot() {
v8_heap_explorer_.TagGlobalObjects();
+ // TODO(1562) Profiler assumes that any object that is in the heap after
+ // full GC is reachable from the root when computing dominators.
+ // This is not true for weakly reachable objects.
+ // As a temporary solution we call GC twice.
+ Isolate::Current()->heap()->CollectAllGarbage(
+ Heap::kMakeHeapIterableMask,
+ "HeapSnapshotGenerator::GenerateSnapshot");
+ Isolate::Current()->heap()->CollectAllGarbage(
+ Heap::kMakeHeapIterableMask,
+ "HeapSnapshotGenerator::GenerateSnapshot");
+
+#ifdef DEBUG
+ Heap* debug_heap = Isolate::Current()->heap();
+ ASSERT(!debug_heap->old_data_space()->was_swept_conservatively());
+ ASSERT(!debug_heap->old_pointer_space()->was_swept_conservatively());
+ ASSERT(!debug_heap->code_space()->was_swept_conservatively());
+ ASSERT(!debug_heap->cell_space()->was_swept_conservatively());
+ ASSERT(!debug_heap->map_space()->was_swept_conservatively());
+#endif
+
+ // The following code uses heap iterators, so we want the heap to be
+ // stable. It should follow TagGlobalObjects as that can allocate.
AssertNoAllocation no_alloc;
+#ifdef DEBUG
+ debug_heap->Verify();
+#endif
+
SetProgressTotal(4); // 2 passes + dominators + sizes.
+#ifdef DEBUG
+ debug_heap->Verify();
+#endif
+
// Pass 1. Iterate heap contents to count entries and references.
if (!CountEntriesAndReferences()) return false;
+#ifdef DEBUG
+ debug_heap->Verify();
+#endif
+
// Allocate and fill entries in the snapshot, allocate references.
snapshot_->AllocateEntries(entries_.entries_count(),
entries_.total_children_count(),
@@ -2818,8 +3185,9 @@ bool HeapSnapshotGenerator::ProgressReport(bool force) {
void HeapSnapshotGenerator::SetProgressTotal(int iterations_count) {
if (control_ == NULL) return;
+ HeapIterator iterator(HeapIterator::kFilterUnreachable);
progress_total_ = (
- v8_heap_explorer_.EstimateObjectsCount() +
+ v8_heap_explorer_.EstimateObjectsCount(&iterator) +
dom_explorer_.EstimateObjectsCount()) * iterations_count;
progress_counter_ = 0;
}
@@ -2828,7 +3196,6 @@ void HeapSnapshotGenerator::SetProgressTotal(int iterations_count) {
bool HeapSnapshotGenerator::CountEntriesAndReferences() {
SnapshotCounter counter(&entries_);
v8_heap_explorer_.AddRootEntries(&counter);
- dom_explorer_.AddRootEntries(&counter);
return
v8_heap_explorer_.IterateAndExtractReferences(&counter) &&
dom_explorer_.IterateAndExtractReferences(&counter);
@@ -2869,7 +3236,7 @@ void HeapSnapshotGenerator::FillReversePostorderIndexes(
nodes_to_visit.RemoveLast();
}
}
- entries->Truncate(current_entry);
+ ASSERT_EQ(current_entry, entries->length());
}
@@ -3149,7 +3516,8 @@ void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge) {
writer_->AddNumber(edge->type());
writer_->AddCharacter(',');
if (edge->type() == HeapGraphEdge::kElement
- || edge->type() == HeapGraphEdge::kHidden) {
+ || edge->type() == HeapGraphEdge::kHidden
+ || edge->type() == HeapGraphEdge::kWeak) {
writer_->AddNumber(edge->index());
} else {
writer_->AddNumber(GetStringId(edge->name()));
@@ -3210,7 +3578,8 @@ void HeapSnapshotJSONSerializer::SerializeNodes() {
"," JSON_S("closure")
"," JSON_S("regexp")
"," JSON_S("number")
- "," JSON_S("native"))
+ "," JSON_S("native")
+ "," JSON_S("synthetic"))
"," JSON_S("string")
"," JSON_S("number")
"," JSON_S("number")
@@ -3229,7 +3598,8 @@ void HeapSnapshotJSONSerializer::SerializeNodes() {
"," JSON_S("property")
"," JSON_S("internal")
"," JSON_S("hidden")
- "," JSON_S("shortcut"))
+ "," JSON_S("shortcut")
+ "," JSON_S("weak"))
"," JSON_S("string_or_number")
"," JSON_S("node"))))));
#undef JSON_S