Dramatically speed up detailed heap snapshot generation.

I've replaced calls to HashMap::Clear with instance re-creation.
This has sped up taking a heap snapshot of GMail from 33s -> 3s!

R=vitalyr@chromium.org
BUG=none
TEST=none

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7259 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 4722f692
...@@ -1313,6 +1313,12 @@ int JSObject::GetInternalFieldCount() { ...@@ -1313,6 +1313,12 @@ int JSObject::GetInternalFieldCount() {
} }
int JSObject::GetInternalFieldOffset(int index) {
ASSERT(index < GetInternalFieldCount() && index >= 0);
return GetHeaderSize() + (kPointerSize * index);
}
Object* JSObject::GetInternalField(int index) { Object* JSObject::GetInternalField(int index) {
ASSERT(index < GetInternalFieldCount() && index >= 0); ASSERT(index < GetInternalFieldCount() && index >= 0);
// Internal objects do follow immediately after the header, whereas in-object // Internal objects do follow immediately after the header, whereas in-object
...@@ -1364,6 +1370,14 @@ Object* JSObject::FastPropertyAtPut(int index, Object* value) { ...@@ -1364,6 +1370,14 @@ Object* JSObject::FastPropertyAtPut(int index, Object* value) {
} }
int JSObject::GetInObjectPropertyOffset(int index) {
// Adjust for the number of properties stored in the object.
index -= map()->inobject_properties();
ASSERT(index < 0);
return map()->instance_size() + (index * kPointerSize);
}
Object* JSObject::InObjectPropertyAt(int index) { Object* JSObject::InObjectPropertyAt(int index) {
// Adjust for the number of properties stored in the object. // Adjust for the number of properties stored in the object.
index -= map()->inobject_properties(); index -= map()->inobject_properties();
......
...@@ -1587,6 +1587,7 @@ class JSObject: public HeapObject { ...@@ -1587,6 +1587,7 @@ class JSObject: public HeapObject {
inline int GetHeaderSize(); inline int GetHeaderSize();
inline int GetInternalFieldCount(); inline int GetInternalFieldCount();
inline int GetInternalFieldOffset(int index);
inline Object* GetInternalField(int index); inline Object* GetInternalField(int index);
inline void SetInternalField(int index, Object* value); inline void SetInternalField(int index, Object* value);
...@@ -1704,6 +1705,7 @@ class JSObject: public HeapObject { ...@@ -1704,6 +1705,7 @@ class JSObject: public HeapObject {
inline Object* FastPropertyAtPut(int index, Object* value); inline Object* FastPropertyAtPut(int index, Object* value);
// Access to in object properties. // Access to in object properties.
inline int GetInObjectPropertyOffset(int index);
inline Object* InObjectPropertyAt(int index); inline Object* InObjectPropertyAt(int index);
inline Object* InObjectPropertyAtPut(int index, inline Object* InObjectPropertyAtPut(int index,
Object* value, Object* value,
......
...@@ -1826,25 +1826,40 @@ class IndexedReferencesExtractor : public ObjectVisitor { ...@@ -1826,25 +1826,40 @@ class IndexedReferencesExtractor : public ObjectVisitor {
IndexedReferencesExtractor(V8HeapExplorer* generator, IndexedReferencesExtractor(V8HeapExplorer* generator,
HeapObject* parent_obj, HeapObject* parent_obj,
HeapEntry* parent_entry, HeapEntry* parent_entry,
HeapObjectsSet* known_references = NULL) bool process_field_marks = false)
: generator_(generator), : generator_(generator),
parent_obj_(parent_obj), parent_obj_(parent_obj),
parent_(parent_entry), parent_(parent_entry),
known_references_(known_references), process_field_marks_(process_field_marks),
next_index_(1) { next_index_(1) {
} }
void VisitPointers(Object** start, Object** end) { void VisitPointers(Object** start, Object** end) {
for (Object** p = start; p < end; p++) { for (Object** p = start; p < end; p++) {
if (!known_references_ || !known_references_->Contains(*p)) { if (CheckVisitedAndUnmark(p)) continue;
generator_->SetHiddenReference(parent_obj_, parent_, next_index_++, *p); generator_->SetHiddenReference(parent_obj_, parent_, next_index_++, *p);
}
} }
} }
static void MarkVisitedField(HeapObject* obj, int offset) {
if (offset < 0) return;
Address field = obj->address() + offset;
ASSERT(!Memory::Object_at(field)->IsFailure());
ASSERT(Memory::Object_at(field)->IsHeapObject());
*field |= kFailureTag;
}
private: private:
bool CheckVisitedAndUnmark(Object** field) {
if (process_field_marks_ && (*field)->IsFailure()) {
intptr_t untagged = reinterpret_cast<intptr_t>(*field) & ~kFailureTagMask;
*field = reinterpret_cast<Object*>(untagged | kHeapObjectTag);
ASSERT((*field)->IsHeapObject());
return true;
}
return false;
}
V8HeapExplorer* generator_; V8HeapExplorer* generator_;
HeapObject* parent_obj_; HeapObject* parent_obj_;
HeapEntry* parent_; HeapEntry* parent_;
HeapObjectsSet* known_references_; bool process_field_marks_;
int next_index_; int next_index_;
}; };
...@@ -1853,7 +1868,6 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) { ...@@ -1853,7 +1868,6 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
HeapEntry* entry = GetEntry(obj); HeapEntry* entry = GetEntry(obj);
if (entry == NULL) return; // No interest in this object. if (entry == NULL) return; // No interest in this object.
known_references_.Clear();
if (obj->IsJSGlobalProxy()) { if (obj->IsJSGlobalProxy()) {
// We need to reference JS global objects from snapshot's root. // We need to reference JS global objects from snapshot's root.
// We use JSGlobalProxy because this is what embedder (e.g. browser) // We use JSGlobalProxy because this is what embedder (e.g. browser)
...@@ -1868,17 +1882,29 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) { ...@@ -1868,17 +1882,29 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
ExtractPropertyReferences(js_obj, entry); ExtractPropertyReferences(js_obj, entry);
ExtractElementReferences(js_obj, entry); ExtractElementReferences(js_obj, entry);
ExtractInternalReferences(js_obj, entry); ExtractInternalReferences(js_obj, entry);
SetPropertyReference( SetPropertyReference(obj, entry,
obj, entry, Heap::Proto_symbol(), js_obj->GetPrototype()); Heap::Proto_symbol(), js_obj->GetPrototype());
if (obj->IsJSFunction()) { if (obj->IsJSFunction()) {
JSFunction* js_fun = JSFunction::cast(obj); JSFunction* js_fun = JSFunction::cast(js_obj);
if (js_fun->has_prototype()) { SetInternalReference(
SetPropertyReference( js_fun, entry,
obj, entry, Heap::prototype_symbol(), js_fun->prototype()); "code", js_fun->shared(),
JSFunction::kSharedFunctionInfoOffset);
Object* proto_or_map = js_fun->prototype_or_initial_map();
if (!proto_or_map->IsTheHole()) {
if (!proto_or_map->IsMap()) {
SetPropertyReference(
obj, entry,
Heap::prototype_symbol(), proto_or_map,
JSFunction::kPrototypeOrInitialMapOffset);
} else {
SetPropertyReference(
obj, entry,
Heap::prototype_symbol(), js_fun->prototype());
}
} }
} }
IndexedReferencesExtractor refs_extractor( IndexedReferencesExtractor refs_extractor(this, obj, entry, true);
this, obj, entry, &known_references_);
obj->Iterate(&refs_extractor); obj->Iterate(&refs_extractor);
} else if (obj->IsString()) { } else if (obj->IsString()) {
if (obj->IsConsString()) { if (obj->IsConsString()) {
...@@ -1911,7 +1937,6 @@ void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj, ...@@ -1911,7 +1937,6 @@ void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj,
SetClosureReference(js_obj, entry, local_name, context->get(idx)); SetClosureReference(js_obj, entry, local_name, context->get(idx));
} }
} }
SetInternalReference(js_obj, entry, "code", func->shared());
} }
} }
...@@ -1924,13 +1949,22 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, ...@@ -1924,13 +1949,22 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj,
switch (descs->GetType(i)) { switch (descs->GetType(i)) {
case FIELD: { case FIELD: {
int index = descs->GetFieldIndex(i); int index = descs->GetFieldIndex(i);
SetPropertyReference( if (index < js_obj->map()->inobject_properties()) {
js_obj, entry, descs->GetKey(i), js_obj->FastPropertyAt(index)); SetPropertyReference(
js_obj, entry,
descs->GetKey(i), js_obj->InObjectPropertyAt(index),
js_obj->GetInObjectPropertyOffset(index));
} else {
SetPropertyReference(
js_obj, entry,
descs->GetKey(i), js_obj->FastPropertyAt(index));
}
break; break;
} }
case CONSTANT_FUNCTION: case CONSTANT_FUNCTION:
SetPropertyReference( SetPropertyReference(
js_obj, entry, descs->GetKey(i), descs->GetConstantFunction(i)); js_obj, entry,
descs->GetKey(i), descs->GetConstantFunction(i));
break; break;
default: ; default: ;
} }
...@@ -1990,7 +2024,8 @@ void V8HeapExplorer::ExtractInternalReferences(JSObject* js_obj, ...@@ -1990,7 +2024,8 @@ void V8HeapExplorer::ExtractInternalReferences(JSObject* js_obj,
int length = js_obj->GetInternalFieldCount(); int length = js_obj->GetInternalFieldCount();
for (int i = 0; i < length; ++i) { for (int i = 0; i < length; ++i) {
Object* o = js_obj->GetInternalField(i); Object* o = js_obj->GetInternalField(i);
SetInternalReference(js_obj, entry, i, o); SetInternalReference(
js_obj, entry, i, o, js_obj->GetInternalFieldOffset(i));
} }
} }
...@@ -2052,7 +2087,6 @@ void V8HeapExplorer::SetClosureReference(HeapObject* parent_obj, ...@@ -2052,7 +2087,6 @@ void V8HeapExplorer::SetClosureReference(HeapObject* parent_obj,
collection_->names()->GetName(reference_name), collection_->names()->GetName(reference_name),
child_obj, child_obj,
child_entry); child_entry);
known_references_.Insert(child_obj);
} }
} }
...@@ -2069,7 +2103,6 @@ void V8HeapExplorer::SetElementReference(HeapObject* parent_obj, ...@@ -2069,7 +2103,6 @@ void V8HeapExplorer::SetElementReference(HeapObject* parent_obj,
index, index,
child_obj, child_obj,
child_entry); child_entry);
known_references_.Insert(child_obj);
} }
} }
...@@ -2077,7 +2110,8 @@ void V8HeapExplorer::SetElementReference(HeapObject* parent_obj, ...@@ -2077,7 +2110,8 @@ void V8HeapExplorer::SetElementReference(HeapObject* parent_obj,
void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj, void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
HeapEntry* parent_entry, HeapEntry* parent_entry,
const char* reference_name, const char* reference_name,
Object* child_obj) { Object* child_obj,
int field_offset) {
HeapEntry* child_entry = GetEntry(child_obj); HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry != NULL) { if (child_entry != NULL) {
filler_->SetNamedReference(HeapGraphEdge::kInternal, filler_->SetNamedReference(HeapGraphEdge::kInternal,
...@@ -2086,7 +2120,7 @@ void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj, ...@@ -2086,7 +2120,7 @@ void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
reference_name, reference_name,
child_obj, child_obj,
child_entry); child_entry);
known_references_.Insert(child_obj); IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
} }
} }
...@@ -2094,7 +2128,8 @@ void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj, ...@@ -2094,7 +2128,8 @@ void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj, void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
HeapEntry* parent_entry, HeapEntry* parent_entry,
int index, int index,
Object* child_obj) { Object* child_obj,
int field_offset) {
HeapEntry* child_entry = GetEntry(child_obj); HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry != NULL) { if (child_entry != NULL) {
filler_->SetNamedReference(HeapGraphEdge::kInternal, filler_->SetNamedReference(HeapGraphEdge::kInternal,
...@@ -2103,7 +2138,7 @@ void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj, ...@@ -2103,7 +2138,7 @@ void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj,
collection_->names()->GetName(index), collection_->names()->GetName(index),
child_obj, child_obj,
child_entry); child_entry);
known_references_.Insert(child_obj); IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
} }
} }
...@@ -2127,7 +2162,8 @@ void V8HeapExplorer::SetHiddenReference(HeapObject* parent_obj, ...@@ -2127,7 +2162,8 @@ void V8HeapExplorer::SetHiddenReference(HeapObject* parent_obj,
void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj, void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj,
HeapEntry* parent_entry, HeapEntry* parent_entry,
String* reference_name, String* reference_name,
Object* child_obj) { Object* child_obj,
int field_offset) {
HeapEntry* child_entry = GetEntry(child_obj); HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry != NULL) { if (child_entry != NULL) {
HeapGraphEdge::Type type = reference_name->length() > 0 ? HeapGraphEdge::Type type = reference_name->length() > 0 ?
...@@ -2138,16 +2174,15 @@ void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj, ...@@ -2138,16 +2174,15 @@ void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj,
collection_->names()->GetName(reference_name), collection_->names()->GetName(reference_name),
child_obj, child_obj,
child_entry); child_entry);
known_references_.Insert(child_obj); IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
} }
} }
void V8HeapExplorer::SetPropertyShortcutReference( void V8HeapExplorer::SetPropertyShortcutReference(HeapObject* parent_obj,
HeapObject* parent_obj, HeapEntry* parent_entry,
HeapEntry* parent_entry, String* reference_name,
String* reference_name, Object* child_obj) {
Object* child_obj) {
HeapEntry* child_entry = GetEntry(child_obj); HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry != NULL) { if (child_entry != NULL) {
filler_->SetNamedReference(HeapGraphEdge::kShortcut, filler_->SetNamedReference(HeapGraphEdge::kShortcut,
......
...@@ -1030,11 +1030,13 @@ class V8HeapExplorer : public HeapEntriesAllocator { ...@@ -1030,11 +1030,13 @@ class V8HeapExplorer : public HeapEntriesAllocator {
void SetInternalReference(HeapObject* parent_obj, void SetInternalReference(HeapObject* parent_obj,
HeapEntry* parent, HeapEntry* parent,
const char* reference_name, const char* reference_name,
Object* child); Object* child,
int field_offset = -1);
void SetInternalReference(HeapObject* parent_obj, void SetInternalReference(HeapObject* parent_obj,
HeapEntry* parent, HeapEntry* parent,
int index, int index,
Object* child); Object* child,
int field_offset = -1);
void SetHiddenReference(HeapObject* parent_obj, void SetHiddenReference(HeapObject* parent_obj,
HeapEntry* parent, HeapEntry* parent,
int index, int index,
...@@ -1042,7 +1044,8 @@ class V8HeapExplorer : public HeapEntriesAllocator { ...@@ -1042,7 +1044,8 @@ class V8HeapExplorer : public HeapEntriesAllocator {
void SetPropertyReference(HeapObject* parent_obj, void SetPropertyReference(HeapObject* parent_obj,
HeapEntry* parent, HeapEntry* parent,
String* reference_name, String* reference_name,
Object* child); Object* child,
int field_offset = -1);
void SetPropertyShortcutReference(HeapObject* parent_obj, void SetPropertyShortcutReference(HeapObject* parent_obj,
HeapEntry* parent, HeapEntry* parent,
String* reference_name, String* reference_name,
...@@ -1056,9 +1059,6 @@ class V8HeapExplorer : public HeapEntriesAllocator { ...@@ -1056,9 +1059,6 @@ class V8HeapExplorer : public HeapEntriesAllocator {
HeapSnapshot* snapshot_; HeapSnapshot* snapshot_;
HeapSnapshotsCollection* collection_; HeapSnapshotsCollection* collection_;
SnapshottingProgressReportingInterface* progress_; SnapshottingProgressReportingInterface* progress_;
// Used during references extraction to mark heap objects that
// are references via non-hidden properties.
HeapObjectsSet known_references_;
SnapshotFillerInterface* filler_; SnapshotFillerInterface* filler_;
static HeapObject* const kGcRootsObject; static HeapObject* const kGcRootsObject;
......
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