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
parent a482bd7e
...@@ -1635,7 +1635,8 @@ HeapObject *const V8HeapExplorer::kGcRootsObject = ...@@ -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, ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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( ...@@ -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) { ...@@ -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 { ...@@ -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_;
......
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