Chromium Code Reviews| Index: src/profile-generator.cc |
| diff --git a/src/profile-generator.cc b/src/profile-generator.cc |
| index b2c9de8524cabbc9d0b73303191b35798c057b9a..96475b1ff2cbc80672e547ffd4b5cf607f2beba7 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,51 @@ 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); |
| + if (js_fun->unchecked_context()->IsContext()) { |
|
Vitaly Repeshko
2011/06/30 12:41:44
How about instead of having TagFoo functions just
mnaganov (inactive)
2011/06/30 13:37:05
Done.
|
| + objects_tags_.SetTag(js_fun->unchecked_context(), "(context)"); |
| + } |
| SetInternalReference(js_fun, entry, |
| "context", js_fun->unchecked_context(), |
| JSFunction::kContextOffset); |
| + TagFixedArray(js_fun->literals(), "(function literals)"); |
| SetInternalReference(js_fun, entry, |
| "literals", js_fun->literals(), |
| JSFunction::kLiteralsOffset); |
| } |
| + TagFixedArray(js_obj->properties(), "(object properties)"); |
| SetInternalReference(obj, entry, |
| "properties", js_obj->properties(), |
| JSObject::kPropertiesOffset); |
| + TagFixedArray(js_obj->elements(), "(object elements)") || |
| + TagFixedDoubleArray(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); |
| + TagFixedArray(context->jsfunction_result_caches(), "(context func caches)"); |
| + TagFixedArray(context->normalized_map_cache(), "(context norm. map cache)"); |
| + TagFixedArray(context->runtime_context(), "(runtime context)"); |
| + TagFixedArray(context->map_cache(), "(context map cache)"); |
|
Vitaly Repeshko
2011/06/30 12:41:44
This made me realize our map cache is just leaking
|
| + TagFixedArray(context->data(), "(context data)"); |
| } else if (obj->IsMap()) { |
| Map* map = Map::cast(obj); |
| SetInternalReference(obj, entry, |
| @@ -1901,6 +1916,7 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) { |
| "constructor", map->constructor(), |
| Map::kConstructorOffset); |
| if (!map->instance_descriptors()->IsEmpty()) { |
| + objects_tags_.SetTag(map->instance_descriptors(), "(map descriptors)"); |
| SetInternalReference(obj, entry, |
| "descriptors", map->instance_descriptors(), |
| Map::kInstanceDescriptorsOrBitField3Offset); |
| @@ -1908,9 +1924,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 +1932,63 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) { |
| SetInternalReference(obj, entry, |
| "code", shared->unchecked_code(), |
| SharedFunctionInfo::kCodeOffset); |
| + TagFixedArray(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); |
| + TagFixedArray(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); |
| + TagFixedArray(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); |
| + TagFixedArray(code_cache->default_cache(), "(default code cache)"); |
| + SetInternalReference(obj, entry, |
| + "default_cache", code_cache->default_cache(), |
| + CodeCache::kDefaultCacheOffset); |
| + if (code_cache->normal_type_cache()->IsCodeCacheHashTable()) { |
| + objects_tags_.SetTag(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); |
| + TagByteArray(code->unchecked_relocation_info(), "(code relocation info)"); |
| + TagFixedArray(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 +2146,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 +2301,36 @@ void V8HeapExplorer::SetGcRootsReference(Object* child_obj) { |
| } |
| +bool V8HeapExplorer::TagByteArray(Object* maybe_array, const char* tag) { |
| + if (maybe_array->IsByteArray() && |
| + maybe_array != heap_->empty_byte_array()) { |
| + objects_tags_.SetTag(maybe_array, tag); |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| + |
| +bool V8HeapExplorer::TagFixedArray(Object* maybe_array, const char* tag) { |
| + if (maybe_array->IsFixedArray() && |
| + maybe_array != heap_->empty_fixed_array()) { |
| + objects_tags_.SetTag(maybe_array, tag); |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| + |
| +bool V8HeapExplorer::TagFixedDoubleArray(Object* maybe_array, const char* tag) { |
| + if (maybe_array->IsFixedDoubleArray() && |
| + maybe_array != heap_->empty_fixed_double_array()) { |
| + objects_tags_.SetTag(maybe_array, tag); |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| + |
| class GlobalObjectsEnumerator : public ObjectVisitor { |
| public: |
| virtual void VisitPointers(Object** start, Object** end) { |