| Index: src/profile-generator.cc
|
| diff --git a/src/profile-generator.cc b/src/profile-generator.cc
|
| index 4f4b76b637a900c63a2766c0620dda87c002ac9e..5d03fe6461f722c6139ba3c1bbda04de4219d928 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;
|
|
|