From 20e6446bd21ce00c0d9d073479af3b88e2a765bc Mon Sep 17 00:00:00 2001 From: "alexeif@chromium.org" Date: Tue, 24 Apr 2012 12:38:58 +0000 Subject: [PATCH] Refactoring of heap profiler: split ExtractReferences into several functions. Review URL: https://chromiumcodereview.appspot.com/10198011 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@11424 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/profile-generator.cc | 434 ++++++++++++++++++++++++++--------------------- src/profile-generator.h | 10 ++ 2 files changed, 247 insertions(+), 197 deletions(-) diff --git a/src/profile-generator.cc b/src/profile-generator.cc index 4f4b76b..5d03fe6 100644 --- a/src/profile-generator.cc +++ b/src/profile-generator.cc @@ -1978,212 +1978,24 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) { 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); - Object* object = proxy->map()->prototype(); - bool is_debug_object = false; -#ifdef ENABLE_DEBUGGER_SUPPORT - is_debug_object = object->IsGlobalObject() && - Isolate::Current()->debug()->IsDebugGlobal(GlobalObject::cast(object)); -#endif - if (!is_debug_object) { - SetUserGlobalReference(object); - } + ExtractJSGlobalProxy(JSGlobalProxy::cast(obj)); } else if (obj->IsJSObject()) { - JSObject* js_obj = JSObject::cast(obj); - ExtractClosureReferences(js_obj, entry); - ExtractPropertyReferences(js_obj, entry); - ExtractElementReferences(js_obj, entry); - ExtractInternalReferences(js_obj, entry); - SetPropertyReference( - 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(); - if (!proto_or_map->IsTheHole()) { - if (!proto_or_map->IsMap()) { - SetPropertyReference( - obj, entry, - heap_->prototype_symbol(), proto_or_map, - NULL, - JSFunction::kPrototypeOrInitialMapOffset); - } else { - SetPropertyReference( - obj, entry, - heap_->prototype_symbol(), js_fun->prototype()); - } - } - SharedFunctionInfo* shared_info = js_fun->shared(); - // JSFunction has either bindings or literals and never both. - bool bound = shared_info->bound(); - TagObject(js_fun->literals_or_bindings(), - bound ? "(function bindings)" : "(function literals)"); - SetInternalReference(js_fun, entry, - bound ? "bindings" : "literals", - js_fun->literals_or_bindings(), - JSFunction::kLiteralsOffset); - TagObject(shared_info, "(shared function info)"); - SetInternalReference(js_fun, entry, - "shared", shared_info, - JSFunction::kSharedFunctionInfoOffset); - TagObject(js_fun->unchecked_context(), "(context)"); - SetInternalReference(js_fun, entry, - "context", js_fun->unchecked_context(), - JSFunction::kContextOffset); - for (int i = JSFunction::kNonWeakFieldsEndOffset; - i < JSFunction::kSize; - i += kPointerSize) { - SetWeakReference(js_fun, entry, i, *HeapObject::RawField(js_fun, i), i); - } - } else if (obj->IsGlobalObject()) { - GlobalObject* global_obj = GlobalObject::cast(obj); - SetInternalReference(global_obj, entry, - "builtins", global_obj->builtins(), - GlobalObject::kBuiltinsOffset); - SetInternalReference(global_obj, entry, - "global_context", global_obj->global_context(), - GlobalObject::kGlobalContextOffset); - SetInternalReference(global_obj, entry, - "global_receiver", global_obj->global_receiver(), - GlobalObject::kGlobalReceiverOffset); - } - 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); + ExtractJSObject(entry, JSObject::cast(obj)); } else if (obj->IsString()) { - if (obj->IsConsString()) { - ConsString* cs = ConsString::cast(obj); - SetInternalReference(obj, entry, 1, cs->first()); - SetInternalReference(obj, entry, 2, cs->second()); - } - if (obj->IsSlicedString()) { - SlicedString* ss = SlicedString::cast(obj); - SetInternalReference(obj, entry, "parent", ss->parent()); - } + ExtractString(entry, String::cast(obj)); extract_indexed_refs = false; } else if (obj->IsContext()) { - Context* context = Context::cast(obj); -#define EXTRACT_CONTEXT_FIELD(index, type, name) \ - SetInternalReference(context, entry, #name, context->get(Context::index), \ - FixedArray::OffsetOfElementAt(Context::index)); - EXTRACT_CONTEXT_FIELD(CLOSURE_INDEX, JSFunction, closure); - EXTRACT_CONTEXT_FIELD(PREVIOUS_INDEX, Context, previous); - EXTRACT_CONTEXT_FIELD(EXTENSION_INDEX, Object, extension); - EXTRACT_CONTEXT_FIELD(GLOBAL_INDEX, GlobalObject, global); - if (obj->IsGlobalContext()) { - 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->data(), "(context data)"); - GLOBAL_CONTEXT_FIELDS(EXTRACT_CONTEXT_FIELD); -#undef EXTRACT_CONTEXT_FIELD - for (int i = Context::FIRST_WEAK_SLOT; - i < Context::GLOBAL_CONTEXT_SLOTS; - ++i) { - SetWeakReference(obj, entry, - i, context->get(i), - FixedArray::OffsetOfElementAt(i)); - } - } + ExtractContext(entry, Context::cast(obj)); } 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); - if (!map->instance_descriptors()->IsEmpty()) { - TagObject(map->instance_descriptors(), "(map descriptors)"); - SetInternalReference(obj, entry, - "descriptors", map->instance_descriptors(), - Map::kInstanceDescriptorsOrBitField3Offset); - } - TagObject(map->prototype_transitions(), "(prototype transitions)"); - SetInternalReference(obj, entry, - "prototype_transitions", map->prototype_transitions(), - Map::kPrototypeTransitionsOffset); - SetInternalReference(obj, entry, - "code_cache", map->code_cache(), - Map::kCodeCacheOffset); + ExtractMap(entry, Map::cast(obj)); } else if (obj->IsSharedFunctionInfo()) { - SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj); - SetInternalReference(obj, entry, - "name", shared->name(), - SharedFunctionInfo::kNameOffset); - TagObject(shared->code(), "(code)"); - SetInternalReference(obj, entry, - "code", shared->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); - TagObject(shared->construct_stub(), "(code)"); - SetInternalReference(obj, entry, - "construct_stub", shared->construct_stub(), - SharedFunctionInfo::kConstructStubOffset); - SetInternalReference(obj, entry, - "function_data", shared->function_data(), - SharedFunctionInfo::kFunctionDataOffset); - SetInternalReference(obj, entry, - "debug_info", shared->debug_info(), - SharedFunctionInfo::kDebugInfoOffset); - SetInternalReference(obj, entry, - "inferred_name", shared->inferred_name(), - SharedFunctionInfo::kInferredNameOffset); - SetInternalReference(obj, entry, - "this_property_assignments", - shared->this_property_assignments(), - SharedFunctionInfo::kThisPropertyAssignmentsOffset); - SetWeakReference(obj, entry, - 1, shared->initial_map(), - SharedFunctionInfo::kInitialMapOffset); + ExtractSharedFunctionInfo(entry, SharedFunctionInfo::cast(obj)); } 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); + ExtractScript(entry, Script::cast(obj)); } 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); + ExtractCodeCache(entry, CodeCache::cast(obj)); } 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)"); + ExtractCode(entry, Code::cast(obj)); } if (extract_indexed_refs) { SetInternalReference(obj, entry, "map", obj->map(), HeapObject::kMapOffset); @@ -2193,6 +2005,234 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) { } +void V8HeapExplorer::ExtractJSGlobalProxy(JSGlobalProxy* proxy) { + // 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. + Object* object = proxy->map()->prototype(); + bool is_debug_object = false; +#ifdef ENABLE_DEBUGGER_SUPPORT + is_debug_object = object->IsGlobalObject() && + Isolate::Current()->debug()->IsDebugGlobal(GlobalObject::cast(object)); +#endif + if (!is_debug_object) { + SetUserGlobalReference(object); + } +} + + +void V8HeapExplorer::ExtractJSObject(HeapEntry* entry, JSObject* js_obj) { + HeapObject* obj = js_obj; + ExtractClosureReferences(js_obj, entry); + ExtractPropertyReferences(js_obj, entry); + ExtractElementReferences(js_obj, entry); + ExtractInternalReferences(js_obj, entry); + SetPropertyReference( + 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(); + if (!proto_or_map->IsTheHole()) { + if (!proto_or_map->IsMap()) { + SetPropertyReference( + obj, entry, + heap_->prototype_symbol(), proto_or_map, + NULL, + JSFunction::kPrototypeOrInitialMapOffset); + } else { + SetPropertyReference( + obj, entry, + heap_->prototype_symbol(), js_fun->prototype()); + } + } + SharedFunctionInfo* shared_info = js_fun->shared(); + // JSFunction has either bindings or literals and never both. + bool bound = shared_info->bound(); + TagObject(js_fun->literals_or_bindings(), + bound ? "(function bindings)" : "(function literals)"); + SetInternalReference(js_fun, entry, + bound ? "bindings" : "literals", + js_fun->literals_or_bindings(), + JSFunction::kLiteralsOffset); + TagObject(shared_info, "(shared function info)"); + SetInternalReference(js_fun, entry, + "shared", shared_info, + JSFunction::kSharedFunctionInfoOffset); + TagObject(js_fun->unchecked_context(), "(context)"); + SetInternalReference(js_fun, entry, + "context", js_fun->unchecked_context(), + JSFunction::kContextOffset); + for (int i = JSFunction::kNonWeakFieldsEndOffset; + i < JSFunction::kSize; + i += kPointerSize) { + SetWeakReference(js_fun, entry, i, *HeapObject::RawField(js_fun, i), i); + } + } else if (obj->IsGlobalObject()) { + GlobalObject* global_obj = GlobalObject::cast(obj); + SetInternalReference(global_obj, entry, + "builtins", global_obj->builtins(), + GlobalObject::kBuiltinsOffset); + SetInternalReference(global_obj, entry, + "global_context", global_obj->global_context(), + GlobalObject::kGlobalContextOffset); + SetInternalReference(global_obj, entry, + "global_receiver", global_obj->global_receiver(), + GlobalObject::kGlobalReceiverOffset); + } + 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); +} + + +void V8HeapExplorer::ExtractString(HeapEntry* entry, String* string) { + if (string->IsConsString()) { + ConsString* cs = ConsString::cast(string); + SetInternalReference(cs, entry, 1, cs->first()); + SetInternalReference(cs, entry, 2, cs->second()); + } + if (string->IsSlicedString()) { + SlicedString* ss = SlicedString::cast(string); + SetInternalReference(ss, entry, "parent", ss->parent()); + } +} + + +void V8HeapExplorer::ExtractContext(HeapEntry* entry, Context* context) { +#define EXTRACT_CONTEXT_FIELD(index, type, name) \ + SetInternalReference(context, entry, #name, context->get(Context::index), \ + FixedArray::OffsetOfElementAt(Context::index)); + EXTRACT_CONTEXT_FIELD(CLOSURE_INDEX, JSFunction, closure); + EXTRACT_CONTEXT_FIELD(PREVIOUS_INDEX, Context, previous); + EXTRACT_CONTEXT_FIELD(EXTENSION_INDEX, Object, extension); + EXTRACT_CONTEXT_FIELD(GLOBAL_INDEX, GlobalObject, global); + if (context->IsGlobalContext()) { + 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->data(), "(context data)"); + GLOBAL_CONTEXT_FIELDS(EXTRACT_CONTEXT_FIELD); +#undef EXTRACT_CONTEXT_FIELD + for (int i = Context::FIRST_WEAK_SLOT; + i < Context::GLOBAL_CONTEXT_SLOTS; + ++i) { + SetWeakReference(context, entry, i, context->get(i), + FixedArray::OffsetOfElementAt(i)); + } + } +} + + +void V8HeapExplorer::ExtractMap(HeapEntry* entry, Map* map) { + SetInternalReference(map, entry, + "prototype", map->prototype(), Map::kPrototypeOffset); + SetInternalReference(map, entry, + "constructor", map->constructor(), + Map::kConstructorOffset); + if (!map->instance_descriptors()->IsEmpty()) { + TagObject(map->instance_descriptors(), "(map descriptors)"); + SetInternalReference(map, entry, + "descriptors", map->instance_descriptors(), + Map::kInstanceDescriptorsOrBitField3Offset); + } + TagObject(map->prototype_transitions(), "(prototype transitions)"); + SetInternalReference(map, entry, + "prototype_transitions", map->prototype_transitions(), + Map::kPrototypeTransitionsOffset); + SetInternalReference(map, entry, + "code_cache", map->code_cache(), + Map::kCodeCacheOffset); +} + + +void V8HeapExplorer::ExtractSharedFunctionInfo( + HeapEntry* entry, SharedFunctionInfo* shared) { + HeapObject* obj = shared; + SetInternalReference(obj, entry, + "name", shared->name(), + SharedFunctionInfo::kNameOffset); + TagObject(shared->code(), "(code)"); + SetInternalReference(obj, entry, + "code", shared->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); + TagObject(shared->construct_stub(), "(code)"); + SetInternalReference(obj, entry, + "construct_stub", shared->construct_stub(), + SharedFunctionInfo::kConstructStubOffset); + SetInternalReference(obj, entry, + "function_data", shared->function_data(), + SharedFunctionInfo::kFunctionDataOffset); + SetInternalReference(obj, entry, + "debug_info", shared->debug_info(), + SharedFunctionInfo::kDebugInfoOffset); + SetInternalReference(obj, entry, + "inferred_name", shared->inferred_name(), + SharedFunctionInfo::kInferredNameOffset); + SetInternalReference(obj, entry, + "this_property_assignments", + shared->this_property_assignments(), + SharedFunctionInfo::kThisPropertyAssignmentsOffset); + SetWeakReference(obj, entry, + 1, shared->initial_map(), + SharedFunctionInfo::kInitialMapOffset); +} + + +void V8HeapExplorer::ExtractScript(HeapEntry* entry, Script* script) { + HeapObject* obj = script; + 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); +} + + +void V8HeapExplorer::ExtractCodeCache(HeapEntry* entry, CodeCache* code_cache) { + TagObject(code_cache->default_cache(), "(default code cache)"); + SetInternalReference(code_cache, entry, + "default_cache", code_cache->default_cache(), + CodeCache::kDefaultCacheOffset); + TagObject(code_cache->normal_type_cache(), "(code type cache)"); + SetInternalReference(code_cache, entry, + "type_cache", code_cache->normal_type_cache(), + CodeCache::kNormalTypeCacheOffset); +} + + +void V8HeapExplorer::ExtractCode(HeapEntry* entry, Code* code) { + TagObject(code->unchecked_relocation_info(), "(code relocation info)"); + TagObject(code->unchecked_deoptimization_data(), "(code deopt data)"); +} + + void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj, HeapEntry* entry) { if (!js_obj->IsJSFunction()) return; diff --git a/src/profile-generator.h b/src/profile-generator.h index 3b748e2..1468777 100644 --- a/src/profile-generator.h +++ b/src/profile-generator.h @@ -975,7 +975,17 @@ class V8HeapExplorer : public HeapEntriesAllocator { int children_count, int retainers_count); const char* GetSystemEntryName(HeapObject* object); + void ExtractReferences(HeapObject* obj); + void ExtractJSGlobalProxy(JSGlobalProxy* proxy); + void ExtractJSObject(HeapEntry* entry, JSObject* js_obj); + void ExtractString(HeapEntry* entry, String* obj); + void ExtractContext(HeapEntry* entry, Context* context); + void ExtractMap(HeapEntry* entry, Map* map); + void ExtractSharedFunctionInfo(HeapEntry* entry, SharedFunctionInfo* shared); + void ExtractScript(HeapEntry* entry, Script* script); + void ExtractCodeCache(HeapEntry* entry, CodeCache* code_cache); + void ExtractCode(HeapEntry* entry, Code* code); void ExtractClosureReferences(JSObject* js_obj, HeapEntry* entry); void ExtractPropertyReferences(JSObject* js_obj, HeapEntry* entry); void ExtractElementReferences(JSObject* js_obj, HeapEntry* entry); -- 2.7.4