summaryrefslogtreecommitdiff
path: root/src/3rdparty/v8/src/profile-generator.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/v8/src/profile-generator.cc')
-rw-r--r--src/3rdparty/v8/src/profile-generator.cc507
1 files changed, 168 insertions, 339 deletions
diff --git a/src/3rdparty/v8/src/profile-generator.cc b/src/3rdparty/v8/src/profile-generator.cc
index da2a969..9839edf 100644
--- a/src/3rdparty/v8/src/profile-generator.cc
+++ b/src/3rdparty/v8/src/profile-generator.cc
@@ -169,6 +169,15 @@ const char* StringsStorage::GetName(int index) {
}
+size_t StringsStorage::GetUsedMemorySize() const {
+ size_t size = sizeof(*this);
+ size += sizeof(HashMap::Entry) * names_.capacity();
+ for (HashMap::Entry* p = names_.Start(); p != NULL; p = names_.Next(p)) {
+ size += strlen(reinterpret_cast<const char*>(p->value)) + 1;
+ }
+ return size;
+}
+
const char* const CodeEntry::kEmptyNamePrefix = "";
@@ -964,16 +973,10 @@ HeapEntry::HeapEntry(HeapSnapshot* snapshot,
const char* name,
SnapshotObjectId id,
int self_size)
- : painted_(false),
- user_reachable_(false),
- dominator_(kNoEntry),
- type_(type),
- retainers_count_(0),
- retainers_index_(-1),
+ : type_(type),
children_count_(0),
children_index_(-1),
self_size_(self_size),
- retained_size_(0),
id_(id),
snapshot_(snapshot),
name_(name) { }
@@ -985,7 +988,6 @@ void HeapEntry::SetNamedReference(HeapGraphEdge::Type type,
HeapGraphEdge edge(type, name, this->index(), entry->index());
snapshot_->edges().Add(edge);
++children_count_;
- ++entry->retainers_count_;
}
@@ -995,7 +997,6 @@ void HeapEntry::SetIndexedReference(HeapGraphEdge::Type type,
HeapGraphEdge edge(type, index, this->index(), entry->index());
snapshot_->edges().Add(edge);
++children_count_;
- ++entry->retainers_count_;
}
@@ -1007,9 +1008,8 @@ Handle<HeapObject> HeapEntry::GetHeapObject() {
void HeapEntry::Print(
const char* prefix, const char* edge_name, int max_depth, int indent) {
STATIC_CHECK(sizeof(unsigned) == sizeof(id()));
- OS::Print("%6d %7d @%6u %*c %s%s: ",
- self_size(), retained_size(), id(),
- indent, ' ', prefix, edge_name);
+ OS::Print("%6d @%6u %*c %s%s: ",
+ self_size(), id(), indent, ' ', prefix, edge_name);
if (type() != kString) {
OS::Print("%s %.40s\n", TypeAsString(), name_);
} else {
@@ -1091,13 +1091,17 @@ template <size_t ptr_size> struct SnapshotSizeConstants;
template <> struct SnapshotSizeConstants<4> {
static const int kExpectedHeapGraphEdgeSize = 12;
- static const int kExpectedHeapEntrySize = 40;
+ static const int kExpectedHeapEntrySize = 24;
+ static const int kExpectedHeapSnapshotsCollectionSize = 96;
+ static const int kExpectedHeapSnapshotSize = 136;
static const size_t kMaxSerializableSnapshotRawSize = 256 * MB;
};
template <> struct SnapshotSizeConstants<8> {
static const int kExpectedHeapGraphEdgeSize = 24;
- static const int kExpectedHeapEntrySize = 48;
+ static const int kExpectedHeapEntrySize = 32;
+ static const int kExpectedHeapSnapshotsCollectionSize = 144;
+ static const int kExpectedHeapSnapshotSize = 168;
static const uint64_t kMaxSerializableSnapshotRawSize =
static_cast<uint64_t>(6000) * MB;
};
@@ -1139,16 +1143,6 @@ void HeapSnapshot::RememberLastJSObjectId() {
}
-static void HeapEntryClearPaint(HeapEntry* entry_ptr) {
- entry_ptr->clear_paint();
-}
-
-
-void HeapSnapshot::ClearPaint() {
- entries_.Iterate(HeapEntryClearPaint);
-}
-
-
HeapEntry* HeapSnapshot::AddRootEntry() {
ASSERT(root_index_ == HeapEntry::kNoEntry);
ASSERT(entries_.is_empty()); // Root entry must be the first one.
@@ -1196,32 +1190,19 @@ HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type,
}
-void HeapSnapshot::FillChildrenAndRetainers() {
+void HeapSnapshot::FillChildren() {
ASSERT(children().is_empty());
children().Allocate(edges().length());
- ASSERT(retainers().is_empty());
- retainers().Allocate(edges().length());
int children_index = 0;
- int retainers_index = 0;
for (int i = 0; i < entries().length(); ++i) {
HeapEntry* entry = &entries()[i];
children_index = entry->set_children_index(children_index);
- retainers_index = entry->set_retainers_index(retainers_index);
}
ASSERT(edges().length() == children_index);
- ASSERT(edges().length() == retainers_index);
for (int i = 0; i < edges().length(); ++i) {
HeapGraphEdge* edge = &edges()[i];
edge->ReplaceToIndexWithEntry(this);
edge->from()->add_child(edge);
- edge->to()->add_retainer(edge);
- }
-}
-
-
-void HeapSnapshot::SetDominatorsToSelf() {
- for (int i = 0; i < entries_.length(); ++i) {
- entries_[i].set_dominator(&entries_[i]);
}
}
@@ -1275,16 +1256,18 @@ void HeapSnapshot::Print(int max_depth) {
template<typename T, class P>
static size_t GetMemoryUsedByList(const List<T, P>& list) {
- return list.capacity() * sizeof(T);
+ return list.length() * sizeof(T) + sizeof(list);
}
size_t HeapSnapshot::RawSnapshotSize() const {
+ STATIC_CHECK(SnapshotSizeConstants<kPointerSize>::kExpectedHeapSnapshotSize ==
+ sizeof(HeapSnapshot)); // NOLINT
return
+ sizeof(*this) +
GetMemoryUsedByList(entries_) +
GetMemoryUsedByList(edges_) +
GetMemoryUsedByList(children_) +
- GetMemoryUsedByList(retainers_) +
GetMemoryUsedByList(sorted_entries_);
}
@@ -1390,7 +1373,7 @@ void HeapObjectsMap::UpdateHeapObjectsMap() {
}
-void HeapObjectsMap::PushHeapObjectsStats(OutputStream* stream) {
+SnapshotObjectId HeapObjectsMap::PushHeapObjectsStats(OutputStream* stream) {
UpdateHeapObjectsMap();
time_intervals_.Add(TimeInterval(next_id_));
int prefered_chunk_size = stream->GetChunkSize();
@@ -1420,7 +1403,7 @@ void HeapObjectsMap::PushHeapObjectsStats(OutputStream* stream) {
if (stats_buffer.length() >= prefered_chunk_size) {
OutputStream::WriteResult result = stream->WriteHeapStatsChunk(
&stats_buffer.first(), stats_buffer.length());
- if (result == OutputStream::kAbort) return;
+ if (result == OutputStream::kAbort) return last_assigned_id();
stats_buffer.Clear();
}
}
@@ -1429,9 +1412,10 @@ void HeapObjectsMap::PushHeapObjectsStats(OutputStream* stream) {
if (!stats_buffer.is_empty()) {
OutputStream::WriteResult result = stream->WriteHeapStatsChunk(
&stats_buffer.first(), stats_buffer.length());
- if (result == OutputStream::kAbort) return;
+ if (result == OutputStream::kAbort) return last_assigned_id();
}
stream->EndOfStream();
+ return last_assigned_id();
}
@@ -1478,6 +1462,15 @@ SnapshotObjectId HeapObjectsMap::GenerateId(v8::RetainedObjectInfo* info) {
}
+size_t HeapObjectsMap::GetUsedMemorySize() const {
+ return
+ sizeof(*this) +
+ sizeof(HashMap::Entry) * entries_map_.capacity() +
+ GetMemoryUsedByList(entries_) +
+ GetMemoryUsedByList(time_intervals_);
+}
+
+
HeapSnapshotsCollection::HeapSnapshotsCollection()
: is_tracking_objects_(false),
snapshots_uids_(HeapSnapshotsMatch),
@@ -1557,6 +1550,22 @@ Handle<HeapObject> HeapSnapshotsCollection::FindHeapObjectById(
}
+size_t HeapSnapshotsCollection::GetUsedMemorySize() const {
+ STATIC_CHECK(SnapshotSizeConstants<kPointerSize>::
+ kExpectedHeapSnapshotsCollectionSize ==
+ sizeof(HeapSnapshotsCollection)); // NOLINT
+ size_t size = sizeof(*this);
+ size += names_.GetUsedMemorySize();
+ size += ids_.GetUsedMemorySize();
+ size += sizeof(HashMap::Entry) * snapshots_uids_.capacity();
+ size += GetMemoryUsedByList(snapshots_);
+ for (int i = 0; i < snapshots_.length(); ++i) {
+ size += snapshots_[i]->RawSnapshotSize();
+ }
+ return size;
+}
+
+
HeapEntriesMap::HeapEntriesMap()
: entries_(HeapThingsMatch) {
}
@@ -1702,8 +1711,8 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object) {
name->IsString()
? collection_->names()->GetName(String::cast(name))
: "");
- } else if (object->IsGlobalContext()) {
- return AddEntry(object, HeapEntry::kHidden, "system / GlobalContext");
+ } else if (object->IsNativeContext()) {
+ return AddEntry(object, HeapEntry::kHidden, "system / NativeContext");
} else if (object->IsContext()) {
return AddEntry(object, HeapEntry::kHidden, "system / Context");
} else if (object->IsFixedArray() ||
@@ -1937,8 +1946,8 @@ void V8HeapExplorer::ExtractJSObjectReferences(
"builtins", global_obj->builtins(),
GlobalObject::kBuiltinsOffset);
SetInternalReference(global_obj, entry,
- "global_context", global_obj->global_context(),
- GlobalObject::kGlobalContextOffset);
+ "native_context", global_obj->native_context(),
+ GlobalObject::kNativeContextOffset);
SetInternalReference(global_obj, entry,
"global_receiver", global_obj->global_receiver(),
GlobalObject::kGlobalReceiverOffset);
@@ -1973,17 +1982,17 @@ void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) {
EXTRACT_CONTEXT_FIELD(CLOSURE_INDEX, JSFunction, closure);
EXTRACT_CONTEXT_FIELD(PREVIOUS_INDEX, Context, previous);
EXTRACT_CONTEXT_FIELD(EXTENSION_INDEX, Object, extension);
- EXTRACT_CONTEXT_FIELD(GLOBAL_INDEX, GlobalObject, global);
- if (context->IsGlobalContext()) {
+ EXTRACT_CONTEXT_FIELD(GLOBAL_OBJECT_INDEX, GlobalObject, global);
+ if (context->IsNativeContext()) {
TagObject(context->jsfunction_result_caches(),
"(context func. result caches)");
TagObject(context->normalized_map_cache(), "(context norm. map cache)");
TagObject(context->runtime_context(), "(runtime context)");
TagObject(context->data(), "(context data)");
- GLOBAL_CONTEXT_FIELDS(EXTRACT_CONTEXT_FIELD);
+ NATIVE_CONTEXT_FIELDS(EXTRACT_CONTEXT_FIELD);
#undef EXTRACT_CONTEXT_FIELD
for (int i = Context::FIRST_WEAK_SLOT;
- i < Context::GLOBAL_CONTEXT_SLOTS;
+ i < Context::NATIVE_CONTEXT_SLOTS;
++i) {
SetWeakReference(context, entry, i, context->get(i),
FixedArray::OffsetOfElementAt(i));
@@ -1998,22 +2007,34 @@ void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) {
SetInternalReference(map, entry,
"constructor", map->constructor(),
Map::kConstructorOffset);
- if (!map->instance_descriptors()->IsEmpty()) {
- TagObject(map->instance_descriptors(), "(map descriptors)");
+ if (map->HasTransitionArray()) {
+ TransitionArray* transitions = map->transitions();
+
+ Object* back_pointer = transitions->back_pointer_storage();
+ TagObject(transitions->back_pointer_storage(), "(back pointer)");
+ SetInternalReference(transitions, entry,
+ "backpointer", back_pointer,
+ TransitionArray::kBackPointerStorageOffset);
+ IndexedReferencesExtractor transitions_refs(this, transitions, entry);
+ transitions->Iterate(&transitions_refs);
+
+ TagObject(transitions, "(transition array)");
SetInternalReference(map, entry,
- "descriptors", map->instance_descriptors(),
- Map::kInstanceDescriptorsOrBitField3Offset);
- }
- if (map->unchecked_prototype_transitions()->IsFixedArray()) {
- TagObject(map->prototype_transitions(), "(prototype transitions)");
- SetInternalReference(map, entry,
- "prototype_transitions", map->prototype_transitions(),
- Map::kPrototypeTransitionsOrBackPointerOffset);
+ "transitions", transitions,
+ Map::kTransitionsOrBackPointerOffset);
} else {
+ Object* back_pointer = map->GetBackPointer();
+ TagObject(back_pointer, "(back pointer)");
SetInternalReference(map, entry,
- "back_pointer", map->GetBackPointer(),
- Map::kPrototypeTransitionsOrBackPointerOffset);
+ "backpointer", back_pointer,
+ Map::kTransitionsOrBackPointerOffset);
}
+ DescriptorArray* descriptors = map->instance_descriptors();
+ TagObject(descriptors, "(map descriptors)");
+ SetInternalReference(map, entry,
+ "descriptors", descriptors,
+ Map::kDescriptorsOffset);
+
SetInternalReference(map, entry,
"code_cache", map->code_cache(),
Map::kCodeCacheOffset);
@@ -2169,20 +2190,37 @@ void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj, int entry) {
void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) {
if (js_obj->HasFastProperties()) {
DescriptorArray* descs = js_obj->map()->instance_descriptors();
+ int real_size = js_obj->map()->NumberOfOwnDescriptors();
for (int i = 0; i < descs->number_of_descriptors(); i++) {
+ if (descs->GetDetails(i).descriptor_index() > real_size) continue;
switch (descs->GetType(i)) {
case FIELD: {
int index = descs->GetFieldIndex(i);
+
+ String* k = descs->GetKey(i);
if (index < js_obj->map()->inobject_properties()) {
- SetPropertyReference(
- js_obj, entry,
- descs->GetKey(i), js_obj->InObjectPropertyAt(index),
- NULL,
- js_obj->GetInObjectPropertyOffset(index));
+ Object* value = js_obj->InObjectPropertyAt(index);
+ if (k != heap_->hidden_symbol()) {
+ SetPropertyReference(
+ js_obj, entry,
+ k, value,
+ NULL,
+ js_obj->GetInObjectPropertyOffset(index));
+ } else {
+ TagObject(value, "(hidden properties)");
+ SetInternalReference(
+ js_obj, entry,
+ "hidden_properties", value,
+ js_obj->GetInObjectPropertyOffset(index));
+ }
} else {
- SetPropertyReference(
- js_obj, entry,
- descs->GetKey(i), js_obj->FastPropertyAt(index));
+ Object* value = js_obj->FastPropertyAt(index);
+ if (k != heap_->hidden_symbol()) {
+ SetPropertyReference(js_obj, entry, k, value);
+ } else {
+ TagObject(value, "(hidden properties)");
+ SetInternalReference(js_obj, entry, "hidden_properties", value);
+ }
}
break;
}
@@ -2209,10 +2247,10 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) {
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;
+ case TRANSITION:
+ case NONEXISTENT:
+ UNREACHABLE();
break;
}
}
@@ -2227,7 +2265,7 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) {
Object* value = target->IsJSGlobalPropertyCell()
? JSGlobalPropertyCell::cast(target)->value()
: target;
- if (String::cast(k)->length() > 0) {
+ if (k != heap_->hidden_symbol()) {
SetPropertyReference(js_obj, entry, String::cast(k), value);
} else {
TagObject(value, "(hidden properties)");
@@ -2240,7 +2278,7 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) {
void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, int entry) {
- if (js_obj->HasFastElements()) {
+ if (js_obj->HasFastObjectElements()) {
FixedArray* elements = FixedArray::cast(js_obj->elements());
int length = js_obj->IsJSArray() ?
Smi::cast(JSArray::cast(js_obj)->length())->value() :
@@ -2286,11 +2324,12 @@ String* V8HeapExplorer::GetConstructorName(JSObject* object) {
Object* constructor_prop = NULL;
LookupResult result(heap->isolate());
object->LocalLookupRealNamedProperty(heap->constructor_symbol(), &result);
- if (result.IsProperty()) {
- constructor_prop = result.GetLazyValue();
- }
+ if (!result.IsFound()) return object->constructor_name();
+
+ constructor_prop = result.GetLazyValue();
if (constructor_prop->IsJSFunction()) {
- Object* maybe_name = JSFunction::cast(constructor_prop)->shared()->name();
+ Object* maybe_name =
+ JSFunction::cast(constructor_prop)->shared()->name();
if (maybe_name->IsString()) {
String* name = String::cast(maybe_name);
if (name->length() > 0) return name;
@@ -2404,19 +2443,17 @@ bool V8HeapExplorer::IterateAndExtractReferences(
bool V8HeapExplorer::IsEssentialObject(Object* object) {
- // We have to use raw_unchecked_* versions because checked versions
- // would fail during iteration over object properties.
return object->IsHeapObject()
&& !object->IsOddball()
- && object != heap_->raw_unchecked_empty_byte_array()
- && object != heap_->raw_unchecked_empty_fixed_array()
- && object != heap_->raw_unchecked_empty_descriptor_array()
- && object != heap_->raw_unchecked_fixed_array_map()
- && object != heap_->raw_unchecked_global_property_cell_map()
- && object != heap_->raw_unchecked_shared_function_info_map()
- && object != heap_->raw_unchecked_free_space_map()
- && object != heap_->raw_unchecked_one_pointer_filler_map()
- && object != heap_->raw_unchecked_two_pointer_filler_map();
+ && object != heap_->empty_byte_array()
+ && object != heap_->empty_fixed_array()
+ && object != heap_->empty_descriptor_array()
+ && object != heap_->fixed_array_map()
+ && object != heap_->global_property_cell_map()
+ && object != heap_->shared_function_info_map()
+ && object != heap_->free_space_map()
+ && object != heap_->one_pointer_filler_map()
+ && object != heap_->two_pointer_filler_map();
}
@@ -2552,20 +2589,6 @@ void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj,
}
-void V8HeapExplorer::SetPropertyShortcutReference(HeapObject* parent_obj,
- int parent_entry,
- String* reference_name,
- Object* child_obj) {
- HeapEntry* child_entry = GetEntry(child_obj);
- if (child_entry != NULL) {
- filler_->SetNamedReference(HeapGraphEdge::kShortcut,
- parent_entry,
- collection_->names()->GetName(reference_name),
- child_entry);
- }
-}
-
-
void V8HeapExplorer::SetRootGcRootsReference() {
filler_->SetIndexedAutoIndexReference(
HeapGraphEdge::kElement,
@@ -2646,7 +2669,7 @@ class GlobalObjectsEnumerator : public ObjectVisitor {
public:
virtual void VisitPointers(Object** start, Object** end) {
for (Object** p = start; p < end; p++) {
- if ((*p)->IsGlobalContext()) {
+ if ((*p)->IsNativeContext()) {
Context* context = Context::cast(*p);
JSObject* proxy = context->global_proxy();
if (proxy->IsJSGlobalProxy()) {
@@ -2684,6 +2707,10 @@ void V8HeapExplorer::TagGlobalObjects() {
Object* obj_document;
if (global_obj->GetProperty(*document_string)->ToObject(&obj_document) &&
obj_document->IsJSObject()) {
+ // FixMe: Workaround: SharedWorker's current Isolate has NULL context.
+ // As result GetProperty(*url_string) will crash.
+ if (!Isolate::Current()->context() && obj_document->IsJSGlobalProxy())
+ continue;
JSObject* document = JSObject::cast(obj_document);
Object* obj_url;
if (document->GetProperty(*url_string)->ToObject(&obj_url) &&
@@ -3066,37 +3093,34 @@ bool HeapSnapshotGenerator::GenerateSnapshot() {
Heap::kMakeHeapIterableMask,
"HeapSnapshotGenerator::GenerateSnapshot");
-#ifdef DEBUG
+#ifdef VERIFY_HEAP
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());
+ CHECK(!debug_heap->old_data_space()->was_swept_conservatively());
+ CHECK(!debug_heap->old_pointer_space()->was_swept_conservatively());
+ CHECK(!debug_heap->code_space()->was_swept_conservatively());
+ CHECK(!debug_heap->cell_space()->was_swept_conservatively());
+ CHECK(!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
+#ifdef VERIFY_HEAP
debug_heap->Verify();
#endif
SetProgressTotal(1); // 1 pass.
-#ifdef DEBUG
+#ifdef VERIFY_HEAP
debug_heap->Verify();
#endif
if (!FillReferences()) return false;
- snapshot_->FillChildrenAndRetainers();
+ snapshot_->FillChildren();
snapshot_->RememberLastJSObjectId();
- if (!SetEntriesDominators()) return false;
- if (!CalculateRetainedSizes()) return false;
-
progress_counter_ = progress_total_;
if (!ProgressReport(true)) return false;
return true;
@@ -3138,187 +3162,6 @@ bool HeapSnapshotGenerator::FillReferences() {
}
-bool HeapSnapshotGenerator::IsUserGlobalReference(const HeapGraphEdge* edge) {
- ASSERT(edge->from() == snapshot_->root());
- return edge->type() == HeapGraphEdge::kShortcut;
-}
-
-
-void HeapSnapshotGenerator::MarkUserReachableObjects() {
- List<HeapEntry*> worklist;
-
- Vector<HeapGraphEdge*> children = snapshot_->root()->children();
- for (int i = 0; i < children.length(); ++i) {
- if (IsUserGlobalReference(children[i])) {
- worklist.Add(children[i]->to());
- }
- }
-
- while (!worklist.is_empty()) {
- HeapEntry* entry = worklist.RemoveLast();
- if (entry->user_reachable()) continue;
- entry->set_user_reachable();
- Vector<HeapGraphEdge*> children = entry->children();
- for (int i = 0; i < children.length(); ++i) {
- HeapEntry* child = children[i]->to();
- if (!child->user_reachable()) {
- worklist.Add(child);
- }
- }
- }
-}
-
-
-static bool IsRetainingEdge(HeapGraphEdge* edge) {
- if (edge->type() == HeapGraphEdge::kShortcut) return false;
- // The edge is not retaining if it goes from system domain
- // (i.e. an object not reachable from window) to the user domain
- // (i.e. a reachable object).
- return edge->from()->user_reachable()
- || !edge->to()->user_reachable();
-}
-
-
-void HeapSnapshotGenerator::FillPostorderIndexes(
- Vector<HeapEntry*>* entries) {
- snapshot_->ClearPaint();
- int current_entry = 0;
- List<HeapEntry*> nodes_to_visit;
- HeapEntry* root = snapshot_->root();
- nodes_to_visit.Add(root);
- snapshot_->root()->paint();
- while (!nodes_to_visit.is_empty()) {
- HeapEntry* entry = nodes_to_visit.last();
- Vector<HeapGraphEdge*> children = entry->children();
- bool has_new_edges = false;
- for (int i = 0; i < children.length(); ++i) {
- if (entry != root && !IsRetainingEdge(children[i])) continue;
- HeapEntry* child = children[i]->to();
- if (!child->painted()) {
- nodes_to_visit.Add(child);
- child->paint();
- has_new_edges = true;
- }
- }
- if (!has_new_edges) {
- entry->set_postorder_index(current_entry);
- (*entries)[current_entry++] = entry;
- nodes_to_visit.RemoveLast();
- }
- }
- ASSERT_EQ(current_entry, entries->length());
-}
-
-
-static int Intersect(int i1, int i2, const Vector<int>& dominators) {
- int finger1 = i1, finger2 = i2;
- while (finger1 != finger2) {
- while (finger1 < finger2) finger1 = dominators[finger1];
- while (finger2 < finger1) finger2 = dominators[finger2];
- }
- return finger1;
-}
-
-
-// The algorithm is based on the article:
-// K. Cooper, T. Harvey and K. Kennedy "A Simple, Fast Dominance Algorithm"
-// Softw. Pract. Exper. 4 (2001), pp. 1-10.
-bool HeapSnapshotGenerator::BuildDominatorTree(
- const Vector<HeapEntry*>& entries,
- Vector<int>* dominators) {
- if (entries.length() == 0) return true;
- HeapEntry* root = snapshot_->root();
- const int entries_length = entries.length(), root_index = entries_length - 1;
- for (int i = 0; i < root_index; ++i) (*dominators)[i] = HeapEntry::kNoEntry;
- (*dominators)[root_index] = root_index;
-
- // The affected array is used to mark entries which dominators
- // have to be racalculated because of changes in their retainers.
- ScopedVector<bool> affected(entries_length);
- for (int i = 0; i < affected.length(); ++i) affected[i] = false;
- // Mark the root direct children as affected.
- Vector<HeapGraphEdge*> children = entries[root_index]->children();
- for (int i = 0; i < children.length(); ++i) {
- affected[children[i]->to()->postorder_index()] = true;
- }
-
- bool changed = true;
- while (changed) {
- changed = false;
- if (!ProgressReport(false)) return false;
- for (int i = root_index - 1; i >= 0; --i) {
- if (!affected[i]) continue;
- affected[i] = false;
- // If dominator of the entry has already been set to root,
- // then it can't propagate any further.
- if ((*dominators)[i] == root_index) continue;
- int new_idom_index = HeapEntry::kNoEntry;
- Vector<HeapGraphEdge*> rets = entries[i]->retainers();
- for (int j = 0; j < rets.length(); ++j) {
- if (rets[j]->from() != root && !IsRetainingEdge(rets[j])) continue;
- int ret_index = rets[j]->from()->postorder_index();
- if (dominators->at(ret_index) != HeapEntry::kNoEntry) {
- new_idom_index = new_idom_index == HeapEntry::kNoEntry
- ? ret_index
- : Intersect(ret_index, new_idom_index, *dominators);
- // If idom has already reached the root, it doesn't make sense
- // to check other retainers.
- if (new_idom_index == root_index) break;
- }
- }
- if (new_idom_index != HeapEntry::kNoEntry
- && dominators->at(i) != new_idom_index) {
- (*dominators)[i] = new_idom_index;
- changed = true;
- Vector<HeapGraphEdge*> children = entries[i]->children();
- for (int j = 0; j < children.length(); ++j) {
- affected[children[j]->to()->postorder_index()] = true;
- }
- }
- }
- }
- return true;
-}
-
-
-bool HeapSnapshotGenerator::SetEntriesDominators() {
- MarkUserReachableObjects();
- // This array is used for maintaining postorder of nodes.
- ScopedVector<HeapEntry*> ordered_entries(snapshot_->entries().length());
- FillPostorderIndexes(&ordered_entries);
- ScopedVector<int> dominators(ordered_entries.length());
- if (!BuildDominatorTree(ordered_entries, &dominators)) return false;
- for (int i = 0; i < ordered_entries.length(); ++i) {
- ASSERT(dominators[i] != HeapEntry::kNoEntry);
- ordered_entries[i]->set_dominator(ordered_entries[dominators[i]]);
- }
- return true;
-}
-
-
-bool HeapSnapshotGenerator::CalculateRetainedSizes() {
- // As for the dominators tree we only know parent nodes, not
- // children, to sum up total sizes we "bubble" node's self size
- // adding it to all of its parents.
- List<HeapEntry>& entries = snapshot_->entries();
- for (int i = 0; i < entries.length(); ++i) {
- HeapEntry* entry = &entries[i];
- entry->set_retained_size(entry->self_size());
- }
- for (int i = 0; i < entries.length(); ++i) {
- int entry_size = entries[i].self_size();
- HeapEntry* current = &entries[i];
- for (HeapEntry* dominator = current->dominator();
- dominator != current;
- current = dominator, dominator = current->dominator()) {
- ASSERT(current->dominator() != NULL);
- dominator->add_retained_size(entry_size);
- }
- }
- return true;
-}
-
-
template<int bytes> struct MaxDecimalDigitsIn;
template<> struct MaxDecimalDigitsIn<4> {
static const int kSigned = 11;
@@ -3417,8 +3260,8 @@ class OutputStreamWriter {
// type, name|index, to_node.
const int HeapSnapshotJSONSerializer::kEdgeFieldsCount = 3;
-// type, name, id, self_size, retained_size, dominator, children_index.
-const int HeapSnapshotJSONSerializer::kNodeFieldsCount = 7;
+// type, name, id, self_size, children_index.
+const int HeapSnapshotJSONSerializer::kNodeFieldsCount = 5;
void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) {
ASSERT(writer_ == NULL);
@@ -3458,14 +3301,12 @@ HeapSnapshot* HeapSnapshotJSONSerializer::CreateFakeSnapshot() {
(snapshot_->RawSnapshotSize() + MB - 1) / MB);
HeapEntry* message = result->AddEntry(HeapEntry::kString, text, 0, 4);
result->root()->SetIndexedReference(HeapGraphEdge::kElement, 1, message);
- result->FillChildrenAndRetainers();
- result->SetDominatorsToSelf();
+ result->FillChildren();
return result;
}
void HeapSnapshotJSONSerializer::SerializeImpl() {
- List<HeapEntry>& nodes = snapshot_->entries();
ASSERT(0 == snapshot_->root()->index());
writer_->AddCharacter('{');
writer_->AddString("\"snapshot\":{");
@@ -3473,11 +3314,11 @@ void HeapSnapshotJSONSerializer::SerializeImpl() {
if (writer_->aborted()) return;
writer_->AddString("},\n");
writer_->AddString("\"nodes\":[");
- SerializeNodes(nodes);
+ SerializeNodes();
if (writer_->aborted()) return;
writer_->AddString("],\n");
writer_->AddString("\"edges\":[");
- SerializeEdges(nodes);
+ SerializeEdges();
if (writer_->aborted()) return;
writer_->AddString("],\n");
writer_->AddString("\"strings\":[");
@@ -3519,9 +3360,9 @@ static int utoa(unsigned value, const Vector<char>& buffer, int buffer_pos) {
void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge,
bool first_edge) {
- // The buffer needs space for 3 ints, 3 commas and \0
+ // The buffer needs space for 3 unsigned ints, 3 commas, \n and \0
static const int kBufferSize =
- MaxDecimalDigitsIn<sizeof(int)>::kSigned * 3 + 3 + 1; // NOLINT
+ MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned * 3 + 3 + 2; // NOLINT
EmbeddedVector<char, kBufferSize> buffer;
int edge_name_or_index = edge->type() == HeapGraphEdge::kElement
|| edge->type() == HeapGraphEdge::kHidden
@@ -3536,32 +3377,28 @@ void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge,
buffer_pos = utoa(edge_name_or_index, buffer, buffer_pos);
buffer[buffer_pos++] = ',';
buffer_pos = utoa(entry_index(edge->to()), buffer, buffer_pos);
+ buffer[buffer_pos++] = '\n';
buffer[buffer_pos++] = '\0';
writer_->AddString(buffer.start());
}
-void HeapSnapshotJSONSerializer::SerializeEdges(const List<HeapEntry>& nodes) {
- bool first_edge = true;
- for (int i = 0; i < nodes.length(); ++i) {
- HeapEntry* entry = &nodes[i];
- Vector<HeapGraphEdge*> children = entry->children();
- for (int j = 0; j < children.length(); ++j) {
- SerializeEdge(children[j], first_edge);
- first_edge = false;
- if (writer_->aborted()) return;
- }
+void HeapSnapshotJSONSerializer::SerializeEdges() {
+ List<HeapGraphEdge*>& edges = snapshot_->children();
+ for (int i = 0; i < edges.length(); ++i) {
+ ASSERT(i == 0 ||
+ edges[i - 1]->from()->index() <= edges[i]->from()->index());
+ SerializeEdge(edges[i], i == 0);
+ if (writer_->aborted()) return;
}
}
-void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry,
- int edges_index) {
- // The buffer needs space for 6 ints, 1 uint32_t, 7 commas, \n and \0
+void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry) {
+ // The buffer needs space for 5 unsigned ints, 5 commas, \n and \0
static const int kBufferSize =
- 6 * MaxDecimalDigitsIn<sizeof(int)>::kSigned // NOLINT
- + MaxDecimalDigitsIn<sizeof(uint32_t)>::kUnsigned // NOLINT
- + 7 + 1 + 1;
+ 5 * MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned // NOLINT
+ + 5 + 1 + 1;
EmbeddedVector<char, kBufferSize> buffer;
int buffer_pos = 0;
if (entry_index(entry) != 0) {
@@ -3575,23 +3412,17 @@ void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry,
buffer[buffer_pos++] = ',';
buffer_pos = utoa(entry->self_size(), buffer, buffer_pos);
buffer[buffer_pos++] = ',';
- buffer_pos = utoa(entry->retained_size(), buffer, buffer_pos);
- buffer[buffer_pos++] = ',';
- buffer_pos = utoa(entry_index(entry->dominator()), buffer, buffer_pos);
- buffer[buffer_pos++] = ',';
- buffer_pos = utoa(edges_index, buffer, buffer_pos);
+ buffer_pos = utoa(entry->children_count(), buffer, buffer_pos);
buffer[buffer_pos++] = '\n';
buffer[buffer_pos++] = '\0';
writer_->AddString(buffer.start());
}
-void HeapSnapshotJSONSerializer::SerializeNodes(const List<HeapEntry>& nodes) {
- int edges_index = 0;
- for (int i = 0; i < nodes.length(); ++i) {
- HeapEntry* entry = &nodes[i];
- SerializeNode(entry, edges_index);
- edges_index += entry->children().length() * kEdgeFieldsCount;
+void HeapSnapshotJSONSerializer::SerializeNodes() {
+ List<HeapEntry>& entries = snapshot_->entries();
+ for (int i = 0; i < entries.length(); ++i) {
+ SerializeNode(&entries[i]);
if (writer_->aborted()) return;
}
}
@@ -3615,9 +3446,7 @@ void HeapSnapshotJSONSerializer::SerializeSnapshot() {
JSON_S("name") ","
JSON_S("id") ","
JSON_S("self_size") ","
- JSON_S("retained_size") ","
- JSON_S("dominator") ","
- JSON_S("edges_index")) ","
+ JSON_S("edge_count")) ","
JSON_S("node_types") ":" JSON_A(
JSON_A(
JSON_S("hidden") ","