Chromium Code Reviews| Index: src/profile-generator.cc |
| diff --git a/src/profile-generator.cc b/src/profile-generator.cc |
| index 4f4b76b637a900c63a2766c0620dda87c002ac9e..e46a555464cfbe4e748563922b52a1bfaba22c3f 100644 |
| --- a/src/profile-generator.cc |
| +++ b/src/profile-generator.cc |
| @@ -1972,218 +1972,258 @@ class IndexedReferencesExtractor : public ObjectVisitor { |
| }; |
| +void V8HeapExplorer::ExtractJSGlobalProxy(JSGlobalProxy* proxy) { |
|
mnaganov (inactive)
2012/04/24 12:25:45
I think you should put these functions after Extra
alexeif
2012/04/24 12:33:28
Done.
|
| + // 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::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); |
| - 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); |