case kHeapNumber: return "/number/";
case kNative: return "/native/";
case kSynthetic: return "/synthetic/";
+ case kContext: return "/context/";
default: return "???";
}
}
} else if (object->IsNativeContext()) {
return AddEntry(object, HeapEntry::kHidden, "system / NativeContext");
} else if (object->IsContext()) {
- return AddEntry(object, HeapEntry::kHidden, "system / Context");
+ return AddEntry(object, HeapEntry::kContext, "system / Context");
} else if (object->IsFixedArray() ||
object->IsFixedDoubleArray() ||
object->IsByteArray() ||
void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) {
+ if (context == context->declaration_context()) {
+ ScopeInfo* scope_info = context->closure()->shared()->scope_info();
+ // Add context allocated locals.
+ int context_locals = scope_info->ContextLocalCount();
+ for (int i = 0; i < context_locals; ++i) {
+ String* local_name = scope_info->ContextLocalName(i);
+ int idx = Context::MIN_CONTEXT_SLOTS + i;
+ SetContextReference(context, entry, local_name, context->get(idx),
+ Context::OffsetOfElementAt(idx));
+ }
+ if (scope_info->HasFunctionName()) {
+ String* name = scope_info->FunctionName();
+ VariableMode mode;
+ int idx = scope_info->FunctionContextSlotIndex(name, &mode);
+ if (idx >= 0) {
+ SetContextReference(context, entry, name, context->get(idx),
+ Context::OffsetOfElementAt(idx));
+ }
+ }
+ }
+
#define EXTRACT_CONTEXT_FIELD(index, type, name) \
SetInternalReference(context, entry, #name, context->get(Context::index), \
FixedArray::OffsetOfElementAt(Context::index));
SetNativeBindReference(js_obj, entry, reference_name,
bindings->get(i));
}
- } else {
- Context* context = func->context()->declaration_context();
- ScopeInfo* scope_info = context->closure()->shared()->scope_info();
- // Add context allocated locals.
- int context_locals = scope_info->ContextLocalCount();
- for (int i = 0; i < context_locals; ++i) {
- String* local_name = scope_info->ContextLocalName(i);
- int idx = Context::MIN_CONTEXT_SLOTS + i;
- SetClosureReference(js_obj, entry, local_name, context->get(idx));
- }
-
- // Add function variable.
- if (scope_info->HasFunctionName()) {
- String* name = scope_info->FunctionName();
- VariableMode mode;
- int idx = scope_info->FunctionContextSlotIndex(name, &mode);
- if (idx >= 0) {
- SetClosureReference(js_obj, entry, name, context->get(idx));
- }
- }
}
}
}
-void V8HeapExplorer::SetClosureReference(HeapObject* parent_obj,
+void V8HeapExplorer::SetContextReference(HeapObject* parent_obj,
int parent_entry,
String* reference_name,
- Object* child_obj) {
+ Object* child_obj,
+ int field_offset) {
HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry != NULL) {
filler_->SetNamedReference(HeapGraphEdge::kContextVariable,
parent_entry,
collection_->names()->GetName(reference_name),
child_entry);
+ IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset);
}
}
JSON_S("regexp") ","
JSON_S("number") ","
JSON_S("native") ","
- JSON_S("synthetic")) ","
+ JSON_S("synthetic") ","
+ JSON_S("context")) ","
JSON_S("string") ","
JSON_S("number") ","
JSON_S("number") ","
kRegExp = v8::HeapGraphNode::kRegExp,
kHeapNumber = v8::HeapGraphNode::kHeapNumber,
kNative = v8::HeapGraphNode::kNative,
- kSynthetic = v8::HeapGraphNode::kSynthetic
+ kSynthetic = v8::HeapGraphNode::kSynthetic,
+ kContext = v8::HeapGraphNode::kContext
};
static const int kNoEntry;
void ExtractElementReferences(JSObject* js_obj, int entry);
void ExtractInternalReferences(JSObject* js_obj, int entry);
bool IsEssentialObject(Object* object);
- void SetClosureReference(HeapObject* parent_obj,
+ void SetContextReference(HeapObject* parent_obj,
int parent,
String* reference_name,
- Object* child);
+ Object* child,
+ int field_offset);
void SetNativeBindReference(HeapObject* parent_obj,
int parent,
const char* reference_name,
map, v8::HeapGraphEdge::kInternal, "transitions");
CHECK_EQ(NULL, own_transitions);
}
+
+
+TEST(ManyLocalsInSharedContext) {
+ v8::HandleScope scope;
+ LocalContext env;
+ int num_objects = 5000;
+ CompileRun(
+ "var n = 5000;"
+ "var result = [];"
+ "result.push('(function outer() {');"
+ "for (var i = 0; i < n; i++) {"
+ " var f = 'function f_' + i + '() { ';"
+ " if (i > 0)"
+ " f += 'f_' + (i - 1) + '();';"
+ " f += ' }';"
+ " result.push(f);"
+ "}"
+ "result.push('return f_' + (n - 1) + ';');"
+ "result.push('})()');"
+ "var ok = eval(result.join('\\n'));");
+ const v8::HeapSnapshot* snapshot =
+ v8::HeapProfiler::TakeSnapshot(v8_str("snapshot"));
+ const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
+ CHECK_NE(NULL, global);
+ const v8::HeapGraphNode* ok_object =
+ GetProperty(global, v8::HeapGraphEdge::kProperty, "ok");
+ CHECK_NE(NULL, ok_object);
+ const v8::HeapGraphNode* context_object =
+ GetProperty(ok_object, v8::HeapGraphEdge::kInternal, "context");
+ CHECK_NE(NULL, context_object);
+ // Check the objects are not duplicated in the context.
+ CHECK_EQ(v8::internal::Context::MIN_CONTEXT_SLOTS + num_objects - 1,
+ context_object->GetChildrenCount());
+ // Check all the objects have got their names.
+ // ... well check just every 8th because otherwise it's too slow in debug.
+ for (int i = 0; i < num_objects - 1; i += 8) {
+ char var_name[100];
+ snprintf(var_name, sizeof(var_name), "f_%d", i);
+ const v8::HeapGraphNode* f_object = GetProperty(
+ context_object, v8::HeapGraphEdge::kContextVariable, var_name);
+ CHECK_NE(NULL, f_object);
+ }
+}