Commit 97cbb319 authored by yurys@chromium.org's avatar yurys@chromium.org

Provide user-friendly access to natively bound function parameters

For a closure created using native Function.prototype.bind() the most important information for the heap profiler user is bound function, receiver and arguments. This change adds shortcuts for those fields.
Review URL: https://chromiumcodereview.appspot.com/9382002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10675 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent eb71dfee
......@@ -1775,9 +1775,11 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object,
} else if (object->IsJSFunction()) {
JSFunction* func = JSFunction::cast(object);
SharedFunctionInfo* shared = func->shared();
const char* name = shared->bound() ? "native_bind" :
collection_->names()->GetName(String::cast(shared->name()));
return AddEntry(object,
HeapEntry::kClosure,
collection_->names()->GetName(String::cast(shared->name())),
name,
children_count,
retainers_count);
} else if (object->IsJSRegExp()) {
......@@ -2011,19 +2013,22 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
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,
"shared", js_fun->shared(),
bound ? "bindings" : "literals",
js_fun->literals_or_bindings(),
JSFunction::kLiteralsOffset);
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);
TagObject(js_fun->literals_or_bindings(),
"(function literals_or_bindings)");
SetInternalReference(js_fun, entry,
"literals_or_bindings",
js_fun->literals_or_bindings(),
JSFunction::kLiteralsOffset);
for (int i = JSFunction::kNonWeakFieldsEndOffset;
i < JSFunction::kSize;
i += kPointerSize) {
......@@ -2126,17 +2131,6 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
SetInternalReference(obj, entry,
"line_ends", script->line_ends(),
Script::kLineEndsOffset);
} else if (obj->IsDescriptorArray()) {
DescriptorArray* desc_array = DescriptorArray::cast(obj);
if (desc_array->length() > DescriptorArray::kContentArrayIndex) {
Object* content_array =
desc_array->get(DescriptorArray::kContentArrayIndex);
TagObject(content_array, "(map descriptor content)");
SetInternalReference(obj, entry,
"content", content_array,
FixedArray::OffsetOfElementAt(
DescriptorArray::kContentArrayIndex));
}
} else if (obj->IsCodeCache()) {
CodeCache* code_cache = CodeCache::cast(obj);
TagObject(code_cache->default_cache(), "(default code cache)");
......@@ -2162,11 +2156,27 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj,
HeapEntry* entry) {
if (js_obj->IsJSFunction()) {
JSFunction* func = JSFunction::cast(js_obj);
Context* context = func->context();
ScopeInfo* scope_info = context->closure()->shared()->scope_info();
if (!js_obj->IsJSFunction()) return;
JSFunction* func = JSFunction::cast(js_obj);
Context* context = func->context();
ScopeInfo* scope_info = context->closure()->shared()->scope_info();
if (func->shared()->bound()) {
FixedArray* bindings = func->function_bindings();
SetNativeBindReference(js_obj, entry, "bound_this",
bindings->get(JSFunction::kBoundThisIndex));
SetNativeBindReference(js_obj, entry, "bound_function",
bindings->get(JSFunction::kBoundFunctionIndex));
for (int i = JSFunction::kBoundArgumentsStartIndex;
i < bindings->length(); i++) {
const char* reference_name = collection_->names()->GetFormatted(
"bound_argument_%d",
i - JSFunction::kBoundArgumentsStartIndex);
SetNativeBindReference(js_obj, entry, reference_name,
bindings->get(i));
}
} else {
// Add context allocated locals.
int context_locals = scope_info->ContextLocalCount();
for (int i = 0; i < context_locals; ++i) {
......@@ -2444,6 +2454,22 @@ void V8HeapExplorer::SetClosureReference(HeapObject* parent_obj,
}
void V8HeapExplorer::SetNativeBindReference(HeapObject* parent_obj,
HeapEntry* parent_entry,
const char* reference_name,
Object* child_obj) {
HeapEntry* child_entry = GetEntry(child_obj);
if (child_entry != NULL) {
filler_->SetNamedReference(HeapGraphEdge::kShortcut,
parent_obj,
parent_entry,
reference_name,
child_obj,
child_entry);
}
}
void V8HeapExplorer::SetElementReference(HeapObject* parent_obj,
HeapEntry* parent_entry,
int index,
......
......@@ -964,6 +964,10 @@ class V8HeapExplorer : public HeapEntriesAllocator {
HeapEntry* parent,
String* reference_name,
Object* child);
void SetNativeBindReference(HeapObject* parent_obj,
HeapEntry* parent,
const char* reference_name,
Object* child);
void SetElementReference(HeapObject* parent_obj,
HeapEntry* parent,
int index,
......
......@@ -147,6 +147,43 @@ TEST(HeapSnapshotObjectSizes) {
}
TEST(BoundFunctionInSnapshot) {
v8::HandleScope scope;
LocalContext env;
CompileRun(
"function myFunction(a, b) { this.a = a; this.b = b; }\n"
"function AAAAA() {}\n"
"boundFunction = myFunction.bind(new AAAAA(), 20, new Number(12)); \n");
const v8::HeapSnapshot* snapshot =
v8::HeapProfiler::TakeSnapshot(v8_str("sizes"));
const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
const v8::HeapGraphNode* f =
GetProperty(global, v8::HeapGraphEdge::kShortcut, "boundFunction");
CHECK(f);
CHECK_EQ(v8::String::New("native_bind"), f->GetName());
const v8::HeapGraphNode* bindings =
GetProperty(f, v8::HeapGraphEdge::kInternal, "bindings");
CHECK_NE(NULL, bindings);
CHECK_EQ(v8::HeapGraphNode::kArray, bindings->GetType());
CHECK_EQ(4, bindings->GetChildrenCount());
const v8::HeapGraphNode* bound_this = GetProperty(
f, v8::HeapGraphEdge::kShortcut, "bound_this");
CHECK(bound_this);
CHECK_EQ(v8::HeapGraphNode::kObject, bound_this->GetType());
const v8::HeapGraphNode* bound_function = GetProperty(
f, v8::HeapGraphEdge::kShortcut, "bound_function");
CHECK(bound_function);
CHECK_EQ(v8::HeapGraphNode::kClosure, bound_function->GetType());
const v8::HeapGraphNode* bound_argument = GetProperty(
f, v8::HeapGraphEdge::kShortcut, "bound_argument_1");
CHECK(bound_argument);
CHECK_EQ(v8::HeapGraphNode::kObject, bound_argument->GetType());
}
TEST(HeapSnapshotEntryChildren) {
v8::HandleScope scope;
LocalContext env;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment