diff --git a/src/profile-generator.cc b/src/profile-generator.cc index c9db94f7b1..fd3268d4f6 100644 --- a/src/profile-generator.cc +++ b/src/profile-generator.cc @@ -1690,7 +1690,7 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, : "", children_count, retainers_count); - } else if (object->IsFixedArray()) { + } else if (object->IsFixedArray() || object->IsByteArray()) { return AddEntry(object, HeapEntry::kArray, "", @@ -1705,7 +1705,7 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, } return AddEntry(object, HeapEntry::kHidden, - "system", + GetSystemEntryName(object), children_count, retainers_count); } @@ -1731,6 +1731,21 @@ void V8HeapExplorer::AddRootEntries(SnapshotFillerInterface* filler) { } +const char* V8HeapExplorer::GetSystemEntryName(HeapObject* object) { + switch (object->map()->instance_type()) { + case MAP_TYPE: return "system / Map"; + case JS_GLOBAL_PROPERTY_CELL_TYPE: return "system / JSGlobalPropertyCell"; + case PROXY_TYPE: return "system / Proxy"; + case ODDBALL_TYPE: return "system / Oddball"; +#define MAKE_STRUCT_CASE(NAME, Name, name) \ + case NAME##_TYPE: return "system / "#Name; + STRUCT_LIST(MAKE_STRUCT_CASE) +#undef MAKE_STRUCT_CASE + default: return "system"; + } +} + + int V8HeapExplorer::EstimateObjectsCount() { HeapIterator iterator(HeapIterator::kFilterUnreachable); int objects_count = 0; @@ -1745,12 +1760,10 @@ class IndexedReferencesExtractor : public ObjectVisitor { public: IndexedReferencesExtractor(V8HeapExplorer* generator, HeapObject* parent_obj, - HeapEntry* parent_entry, - bool process_field_marks = false) + HeapEntry* parent_entry) : generator_(generator), parent_obj_(parent_obj), parent_(parent_entry), - process_field_marks_(process_field_marks), next_index_(1) { } void VisitPointers(Object** start, Object** end) { @@ -1768,7 +1781,7 @@ class IndexedReferencesExtractor : public ObjectVisitor { } private: bool CheckVisitedAndUnmark(Object** field) { - if (process_field_marks_ && (*field)->IsFailure()) { + if ((*field)->IsFailure()) { intptr_t untagged = reinterpret_cast(*field) & ~kFailureTagMask; *field = reinterpret_cast(untagged | kHeapObjectTag); ASSERT((*field)->IsHeapObject()); @@ -1779,7 +1792,6 @@ class IndexedReferencesExtractor : public ObjectVisitor { V8HeapExplorer* generator_; HeapObject* parent_obj_; HeapEntry* parent_; - bool process_field_marks_; int next_index_; }; @@ -1794,6 +1806,7 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) { // 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()) { @@ -1806,10 +1819,6 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) { obj, entry, HEAP->Proto_symbol(), js_obj->GetPrototype()); if (obj->IsJSFunction()) { JSFunction* js_fun = JSFunction::cast(js_obj); - SetInternalReference( - js_fun, entry, - "code", js_fun->shared(), - JSFunction::kSharedFunctionInfoOffset); Object* proto_or_map = js_fun->prototype_or_initial_map(); if (!proto_or_map->IsTheHole()) { if (!proto_or_map->IsMap()) { @@ -1823,8 +1832,24 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) { HEAP->prototype_symbol(), js_fun->prototype()); } } + SetInternalReference(js_fun, entry, + "shared", js_fun->shared(), + JSFunction::kSharedFunctionInfoOffset); + SetInternalReference(js_fun, entry, + "context", js_fun->unchecked_context(), + JSFunction::kContextOffset); + SetInternalReference(js_fun, entry, + "literals", js_fun->literals(), + JSFunction::kLiteralsOffset); } - IndexedReferencesExtractor refs_extractor(this, obj, entry, true); + SetInternalReference(obj, entry, + "properties", js_obj->properties(), + JSObject::kPropertiesOffset); + 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()) { @@ -1832,7 +1857,41 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) { SetInternalReference(obj, entry, 1, cs->first()); SetInternalReference(obj, entry, 2, cs->second()); } + } else if (obj->IsMap()) { + Map* map = Map::cast(obj); + SetInternalReference(obj, entry, + "prototype", map->prototype(), Map::kPrototypeOffset); + SetInternalReference(obj, entry, + "constructor", map->constructor(), + Map::kConstructorOffset); + SetInternalReference(obj, entry, + "descriptors", map->instance_descriptors(), + Map::kInstanceDescriptorsOffset); + 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, + "name", shared->name(), + SharedFunctionInfo::kNameOffset); + SetInternalReference(obj, entry, + "code", shared->unchecked_code(), + SharedFunctionInfo::kCodeOffset); + 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 { + SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset); IndexedReferencesExtractor refs_extractor(this, obj, entry); obj->Iterate(&refs_extractor); } @@ -2307,7 +2366,7 @@ void NativeObjectsExplorer::SetWrapperNativeReferences( ASSERT(info_entry != NULL); filler_->SetNamedReference(HeapGraphEdge::kInternal, wrapper, wrapper_entry, - "Native", + "native", info, info_entry); filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement, info, info_entry, diff --git a/src/profile-generator.h b/src/profile-generator.h index 377c083c49..bbc9efc7e4 100644 --- a/src/profile-generator.h +++ b/src/profile-generator.h @@ -930,6 +930,7 @@ class V8HeapExplorer : public HeapEntriesAllocator { const char* name, int children_count, int retainers_count); + const char* GetSystemEntryName(HeapObject* object); void ExtractReferences(HeapObject* obj); void ExtractClosureReferences(JSObject* js_obj, HeapEntry* entry); void ExtractPropertyReferences(JSObject* js_obj, HeapEntry* entry); diff --git a/test/cctest/test-heap-profiler.cc b/test/cctest/test-heap-profiler.cc index 141b42f7b8..bd08d4cec6 100644 --- a/test/cctest/test-heap-profiler.cc +++ b/test/cctest/test-heap-profiler.cc @@ -574,10 +574,10 @@ TEST(HeapSnapshotCodeObjects) { // Find references to code. const v8::HeapGraphNode* compiled_code = - GetProperty(compiled, v8::HeapGraphEdge::kInternal, "code"); + GetProperty(compiled, v8::HeapGraphEdge::kInternal, "shared"); CHECK_NE(NULL, compiled_code); const v8::HeapGraphNode* lazy_code = - GetProperty(lazy, v8::HeapGraphEdge::kInternal, "code"); + GetProperty(lazy, v8::HeapGraphEdge::kInternal, "shared"); CHECK_NE(NULL, lazy_code); // Verify that non-compiled code doesn't contain references to "x" @@ -1257,9 +1257,9 @@ TEST(HeapSnapshotRetainedObjectInfo) { ccc, v8::HeapGraphNode::kString, "CCC"); CHECK_NE(NULL, n_CCC); - CHECK_EQ(aaa, GetProperty(n_AAA, v8::HeapGraphEdge::kInternal, "Native")); - CHECK_EQ(aaa, GetProperty(n_BBB, v8::HeapGraphEdge::kInternal, "Native")); - CHECK_EQ(ccc, GetProperty(n_CCC, v8::HeapGraphEdge::kInternal, "Native")); + CHECK_EQ(aaa, GetProperty(n_AAA, v8::HeapGraphEdge::kInternal, "native")); + CHECK_EQ(aaa, GetProperty(n_BBB, v8::HeapGraphEdge::kInternal, "native")); + CHECK_EQ(ccc, GetProperty(n_CCC, v8::HeapGraphEdge::kInternal, "native")); }