Show references from weak containers as weak in heap snapshots.

BUG=356590
LOG=Y
R=ulan@chromium.org, yurys@chromium.org

Review URL: https://codereview.chromium.org/213673006

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20429 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
alph@chromium.org 2014-04-02 11:19:53 +00:00
parent 45118bfdfb
commit 923fbafc15
3 changed files with 146 additions and 25 deletions

View File

@ -1101,10 +1101,8 @@ class IndexedReferencesExtractor : public ObjectVisitor {
};
void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
HeapEntry* heap_entry = GetEntry(obj);
if (heap_entry == NULL) return; // No interest in this object.
int entry = heap_entry->index();
bool V8HeapExplorer::ExtractReferencesPass1(int entry, HeapObject* obj) {
if (obj->IsFixedArray()) return false; // FixedArrays are processed on pass 2
if (obj->IsJSGlobalProxy()) {
ExtractJSGlobalProxyReferences(entry, JSGlobalProxy::cast(obj));
@ -1114,8 +1112,6 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
ExtractJSObjectReferences(entry, JSObject::cast(obj));
} else if (obj->IsString()) {
ExtractStringReferences(entry, String::cast(obj));
} else if (obj->IsContext()) {
ExtractContextReferences(entry, Context::cast(obj));
} else if (obj->IsMap()) {
ExtractMapReferences(entry, Map::cast(obj));
} else if (obj->IsSharedFunctionInfo()) {
@ -1137,12 +1133,19 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
} else if (obj->IsAllocationSite()) {
ExtractAllocationSiteReferences(entry, AllocationSite::cast(obj));
}
SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset);
return true;
}
// Extract unvisited fields as hidden references and restore tags
// of visited fields.
IndexedReferencesExtractor refs_extractor(this, obj, entry);
obj->Iterate(&refs_extractor);
bool V8HeapExplorer::ExtractReferencesPass2(int entry, HeapObject* obj) {
if (!obj->IsFixedArray()) return false;
if (obj->IsContext()) {
ExtractContextReferences(entry, Context::cast(obj));
} else {
ExtractFixedArrayReferences(entry, FixedArray::cast(obj));
}
return true;
}
@ -1320,6 +1323,7 @@ void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) {
SetInternalReference(transitions, transitions_entry,
"back_pointer", back_pointer);
TagObject(transitions, "(transition array)");
MarkAsWeakContainer(transitions);
SetInternalReference(map, entry,
"transitions", transitions,
Map::kTransitionsOrBackPointerOffset);
@ -1336,6 +1340,7 @@ void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) {
"descriptors", descriptors,
Map::kDescriptorsOffset);
MarkAsWeakContainer(map->code_cache());
SetInternalReference(map, entry,
"code_cache", map->code_cache(),
Map::kCodeCacheOffset);
@ -1345,6 +1350,7 @@ void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) {
"constructor", map->constructor(),
Map::kConstructorOffset);
TagObject(map->dependent_code(), "(dependent code)");
MarkAsWeakContainer(map->dependent_code());
SetInternalReference(map, entry,
"dependent_code", map->dependent_code(),
Map::kDependentCodeOffset);
@ -1506,6 +1512,7 @@ void V8HeapExplorer::ExtractPropertyCellReferences(int entry,
ExtractCellReferences(entry, cell);
SetInternalReference(cell, entry, "type", cell->type(),
PropertyCell::kTypeOffset);
MarkAsWeakContainer(cell->dependent_code());
SetInternalReference(cell, entry, "dependent_code", cell->dependent_code(),
PropertyCell::kDependentCodeOffset);
}
@ -1517,6 +1524,7 @@ void V8HeapExplorer::ExtractAllocationSiteReferences(int entry,
AllocationSite::kTransitionInfoOffset);
SetInternalReference(site, entry, "nested_site", site->nested_site(),
AllocationSite::kNestedSiteOffset);
MarkAsWeakContainer(site->dependent_code());
SetInternalReference(site, entry, "dependent_code", site->dependent_code(),
AllocationSite::kDependentCodeOffset);
// Do not visit weak_next as it is not visited by the StaticVisitor,
@ -1562,6 +1570,20 @@ void V8HeapExplorer::ExtractJSArrayBufferReferences(
}
void V8HeapExplorer::ExtractFixedArrayReferences(int entry, FixedArray* array) {
bool is_weak = weak_containers_.Contains(array);
for (int i = 0, l = array->length(); i < l; ++i) {
if (is_weak) {
SetWeakReference(array, entry,
i, array->get(i), array->OffsetOfElementAt(i));
} else {
SetInternalReference(array, entry,
i, array->get(i), array->OffsetOfElementAt(i));
}
}
}
void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj, int entry) {
if (!js_obj->IsJSFunction()) return;
@ -1833,18 +1855,13 @@ bool V8HeapExplorer::IterateAndExtractReferences(
heap_->IterateRoots(&extractor, VISIT_ALL);
extractor.FillReferences(this);
// Now iterate the whole heap.
bool interrupted = false;
HeapIterator iterator(heap_, HeapIterator::kFilterUnreachable);
// Heap iteration with filtering must be finished in any case.
for (HeapObject* obj = iterator.next();
obj != NULL;
obj = iterator.next(), progress_->ProgressStep()) {
if (!interrupted) {
ExtractReferences(obj);
if (!progress_->ProgressReport(false)) interrupted = true;
}
}
// We have to do two passes as sometimes FixedArrays are used
// to weakly hold their items, and it's impossible to distinguish
// between these cases without processing the array owner first.
bool interrupted =
IterateAndExtractSinglePass<&V8HeapExplorer::ExtractReferencesPass1>() ||
IterateAndExtractSinglePass<&V8HeapExplorer::ExtractReferencesPass2>();
if (interrupted) {
filler_ = NULL;
return false;
@ -1855,6 +1872,34 @@ bool V8HeapExplorer::IterateAndExtractReferences(
}
template<V8HeapExplorer::ExtractReferencesMethod extractor>
bool V8HeapExplorer::IterateAndExtractSinglePass() {
// Now iterate the whole heap.
bool interrupted = false;
HeapIterator iterator(heap_, HeapIterator::kFilterUnreachable);
// Heap iteration with filtering must be finished in any case.
for (HeapObject* obj = iterator.next();
obj != NULL;
obj = iterator.next(), progress_->ProgressStep()) {
if (interrupted) continue;
HeapEntry* heap_entry = GetEntry(obj);
int entry = heap_entry->index();
if ((this->*extractor)(entry, obj)) {
SetInternalReference(obj, entry,
"map", obj->map(), HeapObject::kMapOffset);
// Extract unvisited fields as hidden references and restore tags
// of visited fields.
IndexedReferencesExtractor refs_extractor(this, obj, entry);
obj->Iterate(&refs_extractor);
}
if (!progress_->ProgressReport(false)) interrupted = true;
}
return interrupted;
}
bool V8HeapExplorer::IsEssentialObject(Object* object) {
return object->IsHeapObject()
&& !object->IsOddball()
@ -1987,6 +2032,24 @@ void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj,
}
void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj,
int parent_entry,
int index,
Object* child_obj,
int field_offset) {
ASSERT(parent_entry == GetEntry(parent_obj)->index());
HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry == NULL) return;
if (IsEssentialObject(child_obj)) {
filler_->SetNamedReference(HeapGraphEdge::kWeak,
parent_entry,
names_->GetFormatted("%d", index),
child_entry);
}
IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
}
void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj,
int parent_entry,
Name* reference_name,
@ -2114,6 +2177,13 @@ void V8HeapExplorer::TagObject(Object* obj, const char* tag) {
}
void V8HeapExplorer::MarkAsWeakContainer(Object* object) {
if (IsEssentialObject(object) && object->IsFixedArray()) {
weak_containers_.Insert(object);
}
}
class GlobalObjectsEnumerator : public ObjectVisitor {
public:
virtual void VisitPointers(Object** start, Object** end) {
@ -2504,7 +2574,7 @@ bool HeapSnapshotGenerator::GenerateSnapshot() {
debug_heap->Verify();
#endif
SetProgressTotal(1); // 1 pass.
SetProgressTotal(2); // 2 passes.
#ifdef VERIFY_HEAP
debug_heap->Verify();

View File

@ -376,6 +376,9 @@ class V8HeapExplorer : public HeapEntriesAllocator {
static HeapObject* const kInternalRootObject;
private:
typedef bool (V8HeapExplorer::*ExtractReferencesMethod)(int entry,
HeapObject* object);
HeapEntry* AddEntry(HeapObject* object);
HeapEntry* AddEntry(HeapObject* object,
HeapEntry::Type type,
@ -383,7 +386,11 @@ class V8HeapExplorer : public HeapEntriesAllocator {
const char* GetSystemEntryName(HeapObject* object);
void ExtractReferences(HeapObject* obj);
template<V8HeapExplorer::ExtractReferencesMethod extractor>
bool IterateAndExtractSinglePass();
bool ExtractReferencesPass1(int entry, HeapObject* obj);
bool ExtractReferencesPass2(int entry, HeapObject* obj);
void ExtractJSGlobalProxyReferences(int entry, JSGlobalProxy* proxy);
void ExtractJSObjectReferences(int entry, JSObject* js_obj);
void ExtractStringReferences(int entry, String* obj);
@ -400,12 +407,14 @@ class V8HeapExplorer : public HeapEntriesAllocator {
void ExtractPropertyCellReferences(int entry, PropertyCell* cell);
void ExtractAllocationSiteReferences(int entry, AllocationSite* site);
void ExtractJSArrayBufferReferences(int entry, JSArrayBuffer* buffer);
void ExtractFixedArrayReferences(int entry, FixedArray* array);
void ExtractClosureReferences(JSObject* js_obj, int entry);
void ExtractPropertyReferences(JSObject* js_obj, int entry);
bool ExtractAccessorPairProperty(JSObject* js_obj, int entry,
Object* key, Object* callback_obj);
void ExtractElementReferences(JSObject* js_obj, int entry);
void ExtractInternalReferences(JSObject* js_obj, int entry);
bool IsEssentialObject(Object* object);
void SetContextReference(HeapObject* parent_obj,
int parent,
@ -439,6 +448,11 @@ class V8HeapExplorer : public HeapEntriesAllocator {
const char* reference_name,
Object* child_obj,
int field_offset);
void SetWeakReference(HeapObject* parent_obj,
int parent,
int index,
Object* child_obj,
int field_offset);
void SetPropertyReference(HeapObject* parent_obj,
int parent,
Name* reference_name,
@ -452,6 +466,7 @@ class V8HeapExplorer : public HeapEntriesAllocator {
VisitorSynchronization::SyncTag tag, bool is_weak, Object* child);
const char* GetStrongGcSubrootName(Object* object);
void TagObject(Object* obj, const char* tag);
void MarkAsWeakContainer(Object* object);
HeapEntry* GetEntry(Object* obj);
@ -467,6 +482,7 @@ class V8HeapExplorer : public HeapEntriesAllocator {
HeapObjectsSet objects_tags_;
HeapObjectsSet strong_gc_subroot_names_;
HeapObjectsSet user_roots_;
HeapObjectsSet weak_containers_;
v8::HeapProfiler::ObjectNameResolver* global_object_name_resolver_;
static HeapObject* const kGcRootsObject;

View File

@ -2508,6 +2508,41 @@ TEST(BoxObject) {
}
TEST(WeakContainers) {
i::FLAG_allow_natives_syntax = true;
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
if (!CcTest::i_isolate()->use_crankshaft()) return;
v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
CompileRun(
"function foo(a) { return a.x; }\n"
"obj = {x : 123};\n"
"foo(obj);\n"
"foo(obj);\n"
"%OptimizeFunctionOnNextCall(foo);\n"
"foo(obj);\n");
const v8::HeapSnapshot* snapshot =
heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
CHECK(ValidateSnapshot(snapshot));
const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
const v8::HeapGraphNode* obj =
GetProperty(global, v8::HeapGraphEdge::kProperty, "obj");
CHECK_NE(NULL, obj);
const v8::HeapGraphNode* map =
GetProperty(obj, v8::HeapGraphEdge::kInternal, "map");
CHECK_NE(NULL, map);
const v8::HeapGraphNode* dependent_code =
GetProperty(map, v8::HeapGraphEdge::kInternal, "dependent_code");
if (!dependent_code) return;
int count = dependent_code->GetChildrenCount();
CHECK_NE(0, count);
for (int i = 0; i < count; ++i) {
const v8::HeapGraphEdge* prop = dependent_code->GetChild(i);
CHECK_EQ(v8::HeapGraphEdge::kWeak, prop->GetType());
}
}
static inline i::Address ToAddress(int n) {
return reinterpret_cast<i::Address>(n);
}