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:
parent
45118bfdfb
commit
923fbafc15
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user