Heap profiler: annotate fixed arrays by their purpose.
This helps understanding what is a particular array for by just looking at its name. R=vitalyr@chromium.org Review URL: http://codereview.chromium.org/7248058 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8494 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
a482bd7ee3
commit
d0559ee206
@ -1635,7 +1635,8 @@ HeapObject *const V8HeapExplorer::kGcRootsObject =
|
|||||||
V8HeapExplorer::V8HeapExplorer(
|
V8HeapExplorer::V8HeapExplorer(
|
||||||
HeapSnapshot* snapshot,
|
HeapSnapshot* snapshot,
|
||||||
SnapshottingProgressReportingInterface* progress)
|
SnapshottingProgressReportingInterface* progress)
|
||||||
: snapshot_(snapshot),
|
: heap_(Isolate::Current()->heap()),
|
||||||
|
snapshot_(snapshot),
|
||||||
collection_(snapshot_->collection()),
|
collection_(snapshot_->collection()),
|
||||||
progress_(progress),
|
progress_(progress),
|
||||||
filler_(NULL) {
|
filler_(NULL) {
|
||||||
@ -1725,10 +1726,14 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object,
|
|||||||
: "",
|
: "",
|
||||||
children_count,
|
children_count,
|
||||||
retainers_count);
|
retainers_count);
|
||||||
} else if (object->IsFixedArray() || object->IsByteArray()) {
|
} else if (object->IsFixedArray() ||
|
||||||
|
object->IsFixedDoubleArray() ||
|
||||||
|
object->IsByteArray() ||
|
||||||
|
object->IsExternalArray()) {
|
||||||
|
const char* tag = objects_tags_.GetTag(object);
|
||||||
return AddEntry(object,
|
return AddEntry(object,
|
||||||
HeapEntry::kArray,
|
HeapEntry::kArray,
|
||||||
"",
|
tag != NULL ? tag : "",
|
||||||
children_count,
|
children_count,
|
||||||
retainers_count);
|
retainers_count);
|
||||||
} else if (object->IsHeapNumber()) {
|
} else if (object->IsHeapNumber()) {
|
||||||
@ -1836,15 +1841,13 @@ 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.
|
||||||
|
|
||||||
|
bool extract_indexed_refs = true;
|
||||||
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)
|
||||||
// uses for the global object.
|
// uses for the global object.
|
||||||
JSGlobalProxy* proxy = JSGlobalProxy::cast(obj);
|
JSGlobalProxy* proxy = JSGlobalProxy::cast(obj);
|
||||||
SetRootShortcutReference(proxy->map()->prototype());
|
SetRootShortcutReference(proxy->map()->prototype());
|
||||||
SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset);
|
|
||||||
IndexedReferencesExtractor refs_extractor(this, obj, entry);
|
|
||||||
obj->Iterate(&refs_extractor);
|
|
||||||
} else if (obj->IsJSObject()) {
|
} else if (obj->IsJSObject()) {
|
||||||
JSObject* js_obj = JSObject::cast(obj);
|
JSObject* js_obj = JSObject::cast(obj);
|
||||||
ExtractClosureReferences(js_obj, entry);
|
ExtractClosureReferences(js_obj, entry);
|
||||||
@ -1852,7 +1855,7 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
|
|||||||
ExtractElementReferences(js_obj, entry);
|
ExtractElementReferences(js_obj, entry);
|
||||||
ExtractInternalReferences(js_obj, entry);
|
ExtractInternalReferences(js_obj, entry);
|
||||||
SetPropertyReference(
|
SetPropertyReference(
|
||||||
obj, entry, HEAP->Proto_symbol(), js_obj->GetPrototype());
|
obj, entry, heap_->Proto_symbol(), js_obj->GetPrototype());
|
||||||
if (obj->IsJSFunction()) {
|
if (obj->IsJSFunction()) {
|
||||||
JSFunction* js_fun = JSFunction::cast(js_obj);
|
JSFunction* js_fun = JSFunction::cast(js_obj);
|
||||||
Object* proto_or_map = js_fun->prototype_or_initial_map();
|
Object* proto_or_map = js_fun->prototype_or_initial_map();
|
||||||
@ -1860,39 +1863,49 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
|
|||||||
if (!proto_or_map->IsMap()) {
|
if (!proto_or_map->IsMap()) {
|
||||||
SetPropertyReference(
|
SetPropertyReference(
|
||||||
obj, entry,
|
obj, entry,
|
||||||
HEAP->prototype_symbol(), proto_or_map,
|
heap_->prototype_symbol(), proto_or_map,
|
||||||
JSFunction::kPrototypeOrInitialMapOffset);
|
JSFunction::kPrototypeOrInitialMapOffset);
|
||||||
} else {
|
} else {
|
||||||
SetPropertyReference(
|
SetPropertyReference(
|
||||||
obj, entry,
|
obj, entry,
|
||||||
HEAP->prototype_symbol(), js_fun->prototype());
|
heap_->prototype_symbol(), js_fun->prototype());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SetInternalReference(js_fun, entry,
|
SetInternalReference(js_fun, entry,
|
||||||
"shared", js_fun->shared(),
|
"shared", js_fun->shared(),
|
||||||
JSFunction::kSharedFunctionInfoOffset);
|
JSFunction::kSharedFunctionInfoOffset);
|
||||||
|
TagObject(js_fun->unchecked_context(), "(context)");
|
||||||
SetInternalReference(js_fun, entry,
|
SetInternalReference(js_fun, entry,
|
||||||
"context", js_fun->unchecked_context(),
|
"context", js_fun->unchecked_context(),
|
||||||
JSFunction::kContextOffset);
|
JSFunction::kContextOffset);
|
||||||
|
TagObject(js_fun->literals(), "(function literals)");
|
||||||
SetInternalReference(js_fun, entry,
|
SetInternalReference(js_fun, entry,
|
||||||
"literals", js_fun->literals(),
|
"literals", js_fun->literals(),
|
||||||
JSFunction::kLiteralsOffset);
|
JSFunction::kLiteralsOffset);
|
||||||
}
|
}
|
||||||
|
TagObject(js_obj->properties(), "(object properties)");
|
||||||
SetInternalReference(obj, entry,
|
SetInternalReference(obj, entry,
|
||||||
"properties", js_obj->properties(),
|
"properties", js_obj->properties(),
|
||||||
JSObject::kPropertiesOffset);
|
JSObject::kPropertiesOffset);
|
||||||
|
TagObject(js_obj->elements(), "(object elements)");
|
||||||
SetInternalReference(obj, entry,
|
SetInternalReference(obj, entry,
|
||||||
"elements", js_obj->elements(),
|
"elements", js_obj->elements(),
|
||||||
JSObject::kElementsOffset);
|
JSObject::kElementsOffset);
|
||||||
SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset);
|
|
||||||
IndexedReferencesExtractor refs_extractor(this, obj, entry);
|
|
||||||
obj->Iterate(&refs_extractor);
|
|
||||||
} else if (obj->IsString()) {
|
} else if (obj->IsString()) {
|
||||||
if (obj->IsConsString()) {
|
if (obj->IsConsString()) {
|
||||||
ConsString* cs = ConsString::cast(obj);
|
ConsString* cs = ConsString::cast(obj);
|
||||||
SetInternalReference(obj, entry, 1, cs->first());
|
SetInternalReference(obj, entry, 1, cs->first());
|
||||||
SetInternalReference(obj, entry, 2, cs->second());
|
SetInternalReference(obj, entry, 2, cs->second());
|
||||||
}
|
}
|
||||||
|
extract_indexed_refs = false;
|
||||||
|
} else if (obj->IsGlobalContext()) {
|
||||||
|
Context* context = Context::cast(obj);
|
||||||
|
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->map_cache(), "(context map cache)");
|
||||||
|
TagObject(context->data(), "(context data)");
|
||||||
} else if (obj->IsMap()) {
|
} else if (obj->IsMap()) {
|
||||||
Map* map = Map::cast(obj);
|
Map* map = Map::cast(obj);
|
||||||
SetInternalReference(obj, entry,
|
SetInternalReference(obj, entry,
|
||||||
@ -1901,6 +1914,7 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
|
|||||||
"constructor", map->constructor(),
|
"constructor", map->constructor(),
|
||||||
Map::kConstructorOffset);
|
Map::kConstructorOffset);
|
||||||
if (!map->instance_descriptors()->IsEmpty()) {
|
if (!map->instance_descriptors()->IsEmpty()) {
|
||||||
|
TagObject(map->instance_descriptors(), "(map descriptors)");
|
||||||
SetInternalReference(obj, entry,
|
SetInternalReference(obj, entry,
|
||||||
"descriptors", map->instance_descriptors(),
|
"descriptors", map->instance_descriptors(),
|
||||||
Map::kInstanceDescriptorsOrBitField3Offset);
|
Map::kInstanceDescriptorsOrBitField3Offset);
|
||||||
@ -1908,9 +1922,6 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
|
|||||||
SetInternalReference(obj, entry,
|
SetInternalReference(obj, entry,
|
||||||
"code_cache", map->code_cache(),
|
"code_cache", map->code_cache(),
|
||||||
Map::kCodeCacheOffset);
|
Map::kCodeCacheOffset);
|
||||||
SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset);
|
|
||||||
IndexedReferencesExtractor refs_extractor(this, obj, entry);
|
|
||||||
obj->Iterate(&refs_extractor);
|
|
||||||
} else if (obj->IsSharedFunctionInfo()) {
|
} else if (obj->IsSharedFunctionInfo()) {
|
||||||
SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
|
SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
|
||||||
SetInternalReference(obj, entry,
|
SetInternalReference(obj, entry,
|
||||||
@ -1919,16 +1930,61 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
|
|||||||
SetInternalReference(obj, entry,
|
SetInternalReference(obj, entry,
|
||||||
"code", shared->unchecked_code(),
|
"code", shared->unchecked_code(),
|
||||||
SharedFunctionInfo::kCodeOffset);
|
SharedFunctionInfo::kCodeOffset);
|
||||||
|
TagObject(shared->scope_info(), "(function scope info)");
|
||||||
|
SetInternalReference(obj, entry,
|
||||||
|
"scope_info", shared->scope_info(),
|
||||||
|
SharedFunctionInfo::kScopeInfoOffset);
|
||||||
SetInternalReference(obj, entry,
|
SetInternalReference(obj, entry,
|
||||||
"instance_class_name", shared->instance_class_name(),
|
"instance_class_name", shared->instance_class_name(),
|
||||||
SharedFunctionInfo::kInstanceClassNameOffset);
|
SharedFunctionInfo::kInstanceClassNameOffset);
|
||||||
SetInternalReference(obj, entry,
|
SetInternalReference(obj, entry,
|
||||||
"script", shared->script(),
|
"script", shared->script(),
|
||||||
SharedFunctionInfo::kScriptOffset);
|
SharedFunctionInfo::kScriptOffset);
|
||||||
SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset);
|
} else if (obj->IsScript()) {
|
||||||
IndexedReferencesExtractor refs_extractor(this, obj, entry);
|
Script* script = Script::cast(obj);
|
||||||
obj->Iterate(&refs_extractor);
|
SetInternalReference(obj, entry,
|
||||||
} else {
|
"source", script->source(),
|
||||||
|
Script::kSourceOffset);
|
||||||
|
SetInternalReference(obj, entry,
|
||||||
|
"name", script->name(),
|
||||||
|
Script::kNameOffset);
|
||||||
|
SetInternalReference(obj, entry,
|
||||||
|
"data", script->data(),
|
||||||
|
Script::kDataOffset);
|
||||||
|
SetInternalReference(obj, entry,
|
||||||
|
"context_data", script->context_data(),
|
||||||
|
Script::kContextOffset);
|
||||||
|
TagObject(script->line_ends(), "(script line ends)");
|
||||||
|
SetInternalReference(obj, entry,
|
||||||
|
"line_ends", script->line_ends(),
|
||||||
|
Script::kLineEndsOffset);
|
||||||
|
} else if (obj->IsDescriptorArray()) {
|
||||||
|
DescriptorArray* desc_array = DescriptorArray::cast(obj);
|
||||||
|
if (desc_array->length() > DescriptorArray::kContentArrayIndex) {
|
||||||
|
Object* content_array =
|
||||||
|
desc_array->get(DescriptorArray::kContentArrayIndex);
|
||||||
|
TagObject(content_array, "(map descriptor content)");
|
||||||
|
SetInternalReference(obj, entry,
|
||||||
|
"content", content_array,
|
||||||
|
FixedArray::OffsetOfElementAt(
|
||||||
|
DescriptorArray::kContentArrayIndex));
|
||||||
|
}
|
||||||
|
} else if (obj->IsCodeCache()) {
|
||||||
|
CodeCache* code_cache = CodeCache::cast(obj);
|
||||||
|
TagObject(code_cache->default_cache(), "(default code cache)");
|
||||||
|
SetInternalReference(obj, entry,
|
||||||
|
"default_cache", code_cache->default_cache(),
|
||||||
|
CodeCache::kDefaultCacheOffset);
|
||||||
|
TagObject(code_cache->normal_type_cache(), "(code type cache)");
|
||||||
|
SetInternalReference(obj, entry,
|
||||||
|
"type_cache", code_cache->normal_type_cache(),
|
||||||
|
CodeCache::kNormalTypeCacheOffset);
|
||||||
|
} else if (obj->IsCode()) {
|
||||||
|
Code* code = Code::cast(obj);
|
||||||
|
TagObject(code->unchecked_relocation_info(), "(code relocation info)");
|
||||||
|
TagObject(code->unchecked_deoptimization_data(), "(code deopt data)");
|
||||||
|
}
|
||||||
|
if (extract_indexed_refs) {
|
||||||
SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset);
|
SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset);
|
||||||
IndexedReferencesExtractor refs_extractor(this, obj, entry);
|
IndexedReferencesExtractor refs_extractor(this, obj, entry);
|
||||||
obj->Iterate(&refs_extractor);
|
obj->Iterate(&refs_extractor);
|
||||||
@ -2086,7 +2142,7 @@ bool V8HeapExplorer::IterateAndExtractReferences(
|
|||||||
}
|
}
|
||||||
SetRootGcRootsReference();
|
SetRootGcRootsReference();
|
||||||
RootsReferencesExtractor extractor(this);
|
RootsReferencesExtractor extractor(this);
|
||||||
HEAP->IterateRoots(&extractor, VISIT_ALL);
|
heap_->IterateRoots(&extractor, VISIT_ALL);
|
||||||
filler_ = NULL;
|
filler_ = NULL;
|
||||||
return progress_->ProgressReport(false);
|
return progress_->ProgressReport(false);
|
||||||
}
|
}
|
||||||
@ -2241,6 +2297,18 @@ void V8HeapExplorer::SetGcRootsReference(Object* child_obj) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void V8HeapExplorer::TagObject(Object* obj, const char* tag) {
|
||||||
|
if (obj->IsHeapObject() &&
|
||||||
|
!obj->IsOddball() &&
|
||||||
|
obj != heap_->raw_unchecked_empty_byte_array() &&
|
||||||
|
obj != heap_->raw_unchecked_empty_fixed_array() &&
|
||||||
|
obj != heap_->raw_unchecked_empty_fixed_double_array() &&
|
||||||
|
obj != heap_->raw_unchecked_empty_descriptor_array()) {
|
||||||
|
objects_tags_.SetTag(obj, tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class GlobalObjectsEnumerator : public ObjectVisitor {
|
class GlobalObjectsEnumerator : public ObjectVisitor {
|
||||||
public:
|
public:
|
||||||
virtual void VisitPointers(Object** start, Object** end) {
|
virtual void VisitPointers(Object** start, Object** end) {
|
||||||
|
@ -973,9 +973,11 @@ class V8HeapExplorer : public HeapEntriesAllocator {
|
|||||||
void SetRootShortcutReference(Object* child);
|
void SetRootShortcutReference(Object* child);
|
||||||
void SetRootGcRootsReference();
|
void SetRootGcRootsReference();
|
||||||
void SetGcRootsReference(Object* child);
|
void SetGcRootsReference(Object* child);
|
||||||
|
void TagObject(Object* obj, const char* tag);
|
||||||
|
|
||||||
HeapEntry* GetEntry(Object* obj);
|
HeapEntry* GetEntry(Object* obj);
|
||||||
|
|
||||||
|
Heap* heap_;
|
||||||
HeapSnapshot* snapshot_;
|
HeapSnapshot* snapshot_;
|
||||||
HeapSnapshotsCollection* collection_;
|
HeapSnapshotsCollection* collection_;
|
||||||
SnapshottingProgressReportingInterface* progress_;
|
SnapshottingProgressReportingInterface* progress_;
|
||||||
|
Loading…
Reference in New Issue
Block a user