Index: src/profile-generator.cc |
diff --git a/src/profile-generator.cc b/src/profile-generator.cc |
index b2c9de8524cabbc9d0b73303191b35798c057b9a..4b3dd7b0f380e6bfab4879f72c9fe60d0551a10a 100644 |
--- a/src/profile-generator.cc |
+++ b/src/profile-generator.cc |
@@ -1635,7 +1635,8 @@ HeapObject *const V8HeapExplorer::kGcRootsObject = |
V8HeapExplorer::V8HeapExplorer( |
HeapSnapshot* snapshot, |
SnapshottingProgressReportingInterface* progress) |
- : snapshot_(snapshot), |
+ : heap_(Isolate::Current()->heap()), |
+ snapshot_(snapshot), |
collection_(snapshot_->collection()), |
progress_(progress), |
filler_(NULL) { |
@@ -1725,10 +1726,14 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, |
: "", |
children_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, |
HeapEntry::kArray, |
- "", |
+ tag != NULL ? tag : "", |
children_count, |
retainers_count); |
} else if (object->IsHeapNumber()) { |
@@ -1836,15 +1841,13 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) { |
HeapEntry* entry = GetEntry(obj); |
if (entry == NULL) return; // No interest in this object. |
+ bool extract_indexed_refs = true; |
if (obj->IsJSGlobalProxy()) { |
// We need to reference JS global objects from snapshot's root. |
// We use JSGlobalProxy because this is what embedder (e.g. browser) |
// uses for the global object. |
JSGlobalProxy* proxy = JSGlobalProxy::cast(obj); |
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()) { |
JSObject* js_obj = JSObject::cast(obj); |
ExtractClosureReferences(js_obj, entry); |
@@ -1852,7 +1855,7 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) { |
ExtractElementReferences(js_obj, entry); |
ExtractInternalReferences(js_obj, entry); |
SetPropertyReference( |
- obj, entry, HEAP->Proto_symbol(), js_obj->GetPrototype()); |
+ obj, entry, heap_->Proto_symbol(), js_obj->GetPrototype()); |
if (obj->IsJSFunction()) { |
JSFunction* js_fun = JSFunction::cast(js_obj); |
Object* proto_or_map = js_fun->prototype_or_initial_map(); |
@@ -1860,39 +1863,48 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) { |
if (!proto_or_map->IsMap()) { |
SetPropertyReference( |
obj, entry, |
- HEAP->prototype_symbol(), proto_or_map, |
+ heap_->prototype_symbol(), proto_or_map, |
JSFunction::kPrototypeOrInitialMapOffset); |
} else { |
SetPropertyReference( |
obj, entry, |
- HEAP->prototype_symbol(), js_fun->prototype()); |
+ heap_->prototype_symbol(), js_fun->prototype()); |
} |
} |
SetInternalReference(js_fun, entry, |
"shared", js_fun->shared(), |
JSFunction::kSharedFunctionInfoOffset); |
+ TagObject(js_fun->unchecked_context(), "(context)"); |
SetInternalReference(js_fun, entry, |
"context", js_fun->unchecked_context(), |
JSFunction::kContextOffset); |
+ TagObject(js_fun->literals(), "(function literals)"); |
SetInternalReference(js_fun, entry, |
"literals", js_fun->literals(), |
JSFunction::kLiteralsOffset); |
} |
+ TagObject(js_obj->properties(), "(object properties)"); |
SetInternalReference(obj, entry, |
"properties", js_obj->properties(), |
JSObject::kPropertiesOffset); |
+ TagObject(js_obj->elements(), "(object elements)"); |
SetInternalReference(obj, entry, |
"elements", js_obj->elements(), |
JSObject::kElementsOffset); |
- SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset); |
- IndexedReferencesExtractor refs_extractor(this, obj, entry); |
- obj->Iterate(&refs_extractor); |
} else if (obj->IsString()) { |
if (obj->IsConsString()) { |
ConsString* cs = ConsString::cast(obj); |
SetInternalReference(obj, entry, 1, cs->first()); |
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 caches)"); |
Vitaly Repeshko
2011/06/30 13:45:27
nit: Maybe we should avoid abbreviations? The name
mnaganov (inactive)
2011/06/30 14:15:22
Done.
|
+ 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()) { |
Map* map = Map::cast(obj); |
SetInternalReference(obj, entry, |
@@ -1901,6 +1913,7 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) { |
"constructor", map->constructor(), |
Map::kConstructorOffset); |
if (!map->instance_descriptors()->IsEmpty()) { |
+ objects_tags_.SetTag(map->instance_descriptors(), "(map descriptors)"); |
Vitaly Repeshko
2011/06/30 13:45:27
Use TagObject here?
mnaganov (inactive)
2011/06/30 14:15:22
Done.
|
SetInternalReference(obj, entry, |
"descriptors", map->instance_descriptors(), |
Map::kInstanceDescriptorsOrBitField3Offset); |
@@ -1908,9 +1921,6 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) { |
SetInternalReference(obj, entry, |
"code_cache", map->code_cache(), |
Map::kCodeCacheOffset); |
- SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset); |
- IndexedReferencesExtractor refs_extractor(this, obj, entry); |
- obj->Iterate(&refs_extractor); |
} else if (obj->IsSharedFunctionInfo()) { |
SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj); |
SetInternalReference(obj, entry, |
@@ -1919,16 +1929,61 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) { |
SetInternalReference(obj, entry, |
"code", shared->unchecked_code(), |
SharedFunctionInfo::kCodeOffset); |
+ TagObject(shared->scope_info(), "(function scope info)"); |
+ SetInternalReference(obj, entry, |
+ "scope_info", shared->scope_info(), |
+ SharedFunctionInfo::kScopeInfoOffset); |
SetInternalReference(obj, entry, |
"instance_class_name", shared->instance_class_name(), |
SharedFunctionInfo::kInstanceClassNameOffset); |
SetInternalReference(obj, entry, |
"script", shared->script(), |
SharedFunctionInfo::kScriptOffset); |
- SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset); |
- IndexedReferencesExtractor refs_extractor(this, obj, entry); |
- obj->Iterate(&refs_extractor); |
- } else { |
+ } else if (obj->IsScript()) { |
+ Script* script = Script::cast(obj); |
+ SetInternalReference(obj, entry, |
+ "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); |
IndexedReferencesExtractor refs_extractor(this, obj, entry); |
obj->Iterate(&refs_extractor); |
@@ -2086,7 +2141,7 @@ bool V8HeapExplorer::IterateAndExtractReferences( |
} |
SetRootGcRootsReference(); |
RootsReferencesExtractor extractor(this); |
- HEAP->IterateRoots(&extractor, VISIT_ALL); |
+ heap_->IterateRoots(&extractor, VISIT_ALL); |
filler_ = NULL; |
return progress_->ProgressReport(false); |
} |
@@ -2241,6 +2296,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 { |
public: |
virtual void VisitPointers(Object** start, Object** end) { |