Revision: 4891
Author: [email protected]
Date: Thu Jun 17 05:56:55 2010
Log: Heap profiler: add a missing link between a function closure and
shared function info.
Review URL: http://codereview.chromium.org/2846012
http://code.google.com/p/v8/source/detail?r=4891
Modified:
/branches/bleeding_edge/include/v8-profiler.h
/branches/bleeding_edge/src/api.cc
/branches/bleeding_edge/src/checks.h
/branches/bleeding_edge/src/profile-generator.cc
/branches/bleeding_edge/src/profile-generator.h
/branches/bleeding_edge/test/cctest/test-heap-profiler.cc
=======================================
--- /branches/bleeding_edge/include/v8-profiler.h Tue Jun 15 04:44:07 2010
+++ /branches/bleeding_edge/include/v8-profiler.h Thu Jun 17 05:56:55 2010
@@ -196,7 +196,9 @@
enum Type {
CONTEXT_VARIABLE = 0, // A variable from a function context.
ELEMENT = 1, // An element of an array.
- PROPERTY = 2 // A named object property.
+ PROPERTY = 2, // A named object property.
+ INTERNAL = 3 // A link that can't be accessed from JS,
+ // thus, its name isn't a real property name.
};
/** Returns edge type (see HeapGraphEdge::Type). */
=======================================
--- /branches/bleeding_edge/src/api.cc Tue Jun 15 10:01:02 2010
+++ /branches/bleeding_edge/src/api.cc Thu Jun 17 05:56:55 2010
@@ -4460,6 +4460,7 @@
reinterpret_cast<const i::HeapGraphEdge*>(this);
switch (edge->type()) {
case i::HeapGraphEdge::CONTEXT_VARIABLE:
+ case i::HeapGraphEdge::INTERNAL:
case i::HeapGraphEdge::PROPERTY:
return Handle<String>(ToApi<String>(i::Factory::LookupAsciiSymbol(
edge->name())));
=======================================
--- /branches/bleeding_edge/src/checks.h Tue Jun 8 05:04:49 2010
+++ /branches/bleeding_edge/src/checks.h Thu Jun 17 05:56:55 2010
@@ -155,9 +155,9 @@
static inline void CheckEqualsHelper(const char* file,
int line,
const char* expected_source,
- void* expected,
+ const void* expected,
const char* value_source,
- void* value) {
+ const void* value) {
if (expected != value) {
V8_Fatal(file, line,
"CHECK_EQ(%s, %s) failed\n# Expected: %p\n# Found: %p",
@@ -170,9 +170,9 @@
static inline void CheckNonEqualsHelper(const char* file,
int line,
const char* expected_source,
- void* expected,
+ const void* expected,
const char* value_source,
- void* value) {
+ const void* value) {
if (expected == value) {
V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n# Value: %p",
expected_source, value_source, value);
=======================================
--- /branches/bleeding_edge/src/profile-generator.cc Tue Jun 15 04:44:07
2010
+++ /branches/bleeding_edge/src/profile-generator.cc Thu Jun 17 05:56:55
2010
@@ -818,7 +818,7 @@
HeapEntry* from,
HeapEntry* to)
: type_(type), name_(name), from_(from), to_(to) {
- ASSERT(type_ == CONTEXT_VARIABLE || type_ == PROPERTY);
+ ASSERT(type_ == CONTEXT_VARIABLE || type_ == PROPERTY || type_ ==
INTERNAL);
}
@@ -845,26 +845,30 @@
}
-void HeapEntry::SetClosureReference(const char* name, HeapEntry* entry) {
- HeapGraphEdge* edge =
- new HeapGraphEdge(HeapGraphEdge::CONTEXT_VARIABLE, name, this,
entry);
+void HeapEntry::AddEdge(HeapGraphEdge* edge) {
children_.Add(edge);
- entry->retainers_.Add(edge);
+ edge->to()->retainers_.Add(edge);
+}
+
+
+void HeapEntry::SetClosureReference(const char* name, HeapEntry* entry) {
+ AddEdge(
+ new HeapGraphEdge(HeapGraphEdge::CONTEXT_VARIABLE, name, this,
entry));
}
void HeapEntry::SetElementReference(int index, HeapEntry* entry) {
- HeapGraphEdge* edge = new HeapGraphEdge(index, this, entry);
- children_.Add(edge);
- entry->retainers_.Add(edge);
+ AddEdge(new HeapGraphEdge(index, this, entry));
+}
+
+
+void HeapEntry::SetInternalReference(const char* name, HeapEntry* entry) {
+ AddEdge(new HeapGraphEdge(HeapGraphEdge::INTERNAL, name, this, entry));
}
void HeapEntry::SetPropertyReference(const char* name, HeapEntry* entry) {
- HeapGraphEdge* edge =
- new HeapGraphEdge(HeapGraphEdge::PROPERTY, name, this, entry);
- children_.Add(edge);
- entry->retainers_.Add(edge);
+ AddEdge(new HeapGraphEdge(HeapGraphEdge::PROPERTY, name, this, entry));
}
@@ -1074,7 +1078,7 @@
void HeapEntry::Print(int max_depth, int indent) {
- OS::Print("%6d %6d %6d", self_size_, TotalSize(), NonSharedTotalSize());
+ OS::Print("%6d %6d %6d ", self_size_, TotalSize(), NonSharedTotalSize());
if (type_ != STRING) {
OS::Print("%s %.40s\n", TypeAsString(), name_);
} else {
@@ -1100,6 +1104,9 @@
case HeapGraphEdge::ELEMENT:
OS::Print(" %*c %d: ", indent, ' ', edge->index());
break;
+ case HeapGraphEdge::INTERNAL:
+ OS::Print(" %*c $%s: ", indent, ' ', edge->name());
+ break;
case HeapGraphEdge::PROPERTY:
OS::Print(" %*c %s: ", indent, ' ', edge->name());
break;
@@ -1145,6 +1152,9 @@
case HeapGraphEdge::ELEMENT:
OS::Print("[%d] ", edge->index());
break;
+ case HeapGraphEdge::INTERNAL:
+ OS::Print("[$%s] ", edge->name());
+ break;
case HeapGraphEdge::PROPERTY:
OS::Print("[%s] ", edge->name());
break;
@@ -1316,6 +1326,16 @@
parent->SetElementReference(index, child_entry);
}
}
+
+
+void HeapSnapshot::SetInternalReference(HeapEntry* parent,
+ const char* reference_name,
+ Object* child) {
+ HeapEntry* child_entry = GetEntry(child);
+ if (child_entry != NULL) {
+ parent->SetInternalReference(reference_name, child_entry);
+ }
+}
void HeapSnapshot::SetPropertyReference(HeapEntry* parent,
@@ -1546,6 +1566,7 @@
snapshot_->SetClosureReference(entry, local_name,
context->get(idx));
}
}
+ snapshot_->SetInternalReference(entry, "code", func->shared());
}
}
=======================================
--- /branches/bleeding_edge/src/profile-generator.h Tue Jun 15 04:44:07 2010
+++ /branches/bleeding_edge/src/profile-generator.h Thu Jun 17 05:56:55 2010
@@ -431,7 +431,8 @@
enum Type {
CONTEXT_VARIABLE = v8::HeapGraphEdge::CONTEXT_VARIABLE,
ELEMENT = v8::HeapGraphEdge::ELEMENT,
- PROPERTY = v8::HeapGraphEdge::PROPERTY
+ PROPERTY = v8::HeapGraphEdge::PROPERTY,
+ INTERNAL = v8::HeapGraphEdge::INTERNAL
};
HeapGraphEdge(Type type, const char* name, HeapEntry* from, HeapEntry*
to);
@@ -443,7 +444,7 @@
return index_;
}
const char* name() const {
- ASSERT(type_ == CONTEXT_VARIABLE || type_ == PROPERTY);
+ ASSERT(type_ == CONTEXT_VARIABLE || type_ == PROPERTY || type_ ==
INTERNAL);
return name_;
}
HeapEntry* from() const { return from_; }
@@ -533,6 +534,7 @@
void PaintReachableFromOthers() { painted_ = kPaintReachableFromOthers; }
void SetClosureReference(const char* name, HeapEntry* entry);
void SetElementReference(int index, HeapEntry* entry);
+ void SetInternalReference(const char* name, HeapEntry* entry);
void SetPropertyReference(const char* name, HeapEntry* entry);
void SetAutoIndexReference(HeapEntry* entry);
@@ -542,6 +544,7 @@
void Print(int max_depth, int indent);
private:
+ void AddEdge(HeapGraphEdge* edge);
int CalculateTotalSize();
int CalculateNonSharedTotalSize();
void FindRetainingPaths(HeapEntry* node, CachedHeapGraphPath* prev_path);
@@ -641,6 +644,8 @@
void SetClosureReference(
HeapEntry* parent, String* reference_name, Object* child);
void SetElementReference(HeapEntry* parent, int index, Object* child);
+ void SetInternalReference(
+ HeapEntry* parent, const char* reference_name, Object* child);
void SetPropertyReference(
HeapEntry* parent, String* reference_name, Object* child);
=======================================
--- /branches/bleeding_edge/test/cctest/test-heap-profiler.cc Tue Jun 15
05:28:25 2010
+++ /branches/bleeding_edge/test/cctest/test-heap-profiler.cc Thu Jun 17
05:56:55 2010
@@ -428,6 +428,53 @@
} // namespace
+
+static const v8::HeapGraphNode* GetGlobalObject(
+ const v8::HeapSnapshot* snapshot) {
+ if (i::Snapshot::IsEnabled()) {
+ // In case if snapshots are enabled, there will present a
+ // vanilla deserealized global object, without properties
+ // added by the test code.
+ CHECK_EQ(2, snapshot->GetHead()->GetChildrenCount());
+ // Choose the global object of a bigger size.
+ const v8::HeapGraphNode* node0 =
+ snapshot->GetHead()->GetChild(0)->GetToNode();
+ const v8::HeapGraphNode* node1 =
+ snapshot->GetHead()->GetChild(1)->GetToNode();
+ return node0->GetTotalSize() > node1->GetTotalSize() ? node0 : node1;
+ } else {
+ CHECK_EQ(1, snapshot->GetHead()->GetChildrenCount());
+ return snapshot->GetHead()->GetChild(0)->GetToNode();
+ }
+}
+
+
+static const v8::HeapGraphNode* GetProperty(const v8::HeapGraphNode* node,
+ v8::HeapGraphEdge::Type type,
+ const char* name) {
+ for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
+ const v8::HeapGraphEdge* prop = node->GetChild(i);
+ v8::String::AsciiValue prop_name(prop->GetName());
+ if (prop->GetType() == type && strcmp(name, *prop_name) == 0)
+ return prop->GetToNode();
+ }
+ return NULL;
+}
+
+
+static bool HasString(const v8::HeapGraphNode* node, const char* contents)
{
+ for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
+ const v8::HeapGraphEdge* prop = node->GetChild(i);
+ const v8::HeapGraphNode* node = prop->GetToNode();
+ if (node->GetType() == v8::HeapGraphNode::STRING) {
+ v8::String::AsciiValue node_name(node->GetName());
+ if (strcmp(contents, *node_name) == 0) return true;
+ }
+ }
+ return false;
+}
+
+
TEST(HeapSnapshot) {
v8::HandleScope scope;
@@ -458,53 +505,20 @@
"var c2 = new C2(a2);");
const v8::HeapSnapshot* snapshot_env2 =
v8::HeapProfiler::TakeSnapshot(v8::String::New("env2"));
- const v8::HeapGraphNode* global_env2;
- if (i::Snapshot::IsEnabled()) {
- // In case if snapshots are enabled, there will present a
- // vanilla deserealized global object, without properties
- // added by the test code.
- CHECK_EQ(2, snapshot_env2->GetHead()->GetChildrenCount());
- // Choose the global object of a bigger size.
- const v8::HeapGraphNode* node0 =
- snapshot_env2->GetHead()->GetChild(0)->GetToNode();
- const v8::HeapGraphNode* node1 =
- snapshot_env2->GetHead()->GetChild(1)->GetToNode();
- global_env2 = node0->GetTotalSize() > node1->GetTotalSize() ?
- node0 : node1;
- } else {
- CHECK_EQ(1, snapshot_env2->GetHead()->GetChildrenCount());
- global_env2 = snapshot_env2->GetHead()->GetChild(0)->GetToNode();
- }
+ const v8::HeapGraphNode* global_env2 = GetGlobalObject(snapshot_env2);
// Verify, that JS global object of env2 doesn't have '..1'
// properties, but has '..2' properties.
- bool has_a1 = false, has_b1_1 = false, has_b1_2 = false, has_c1 = false;
- bool has_a2 = false, has_b2_1 = false, has_b2_2 = false, has_c2 = false;
- // This will be needed further.
- const v8::HeapGraphNode* a2_node = NULL;
- for (int i = 0, count = global_env2->GetChildrenCount(); i < count; ++i)
{
- const v8::HeapGraphEdge* prop = global_env2->GetChild(i);
- v8::String::AsciiValue prop_name(prop->GetName());
- if (strcmp("a1", *prop_name) == 0) has_a1 = true;
- if (strcmp("b1_1", *prop_name) == 0) has_b1_1 = true;
- if (strcmp("b1_2", *prop_name) == 0) has_b1_2 = true;
- if (strcmp("c1", *prop_name) == 0) has_c1 = true;
- if (strcmp("a2", *prop_name) == 0) {
- has_a2 = true;
- a2_node = prop->GetToNode();
- }
- if (strcmp("b2_1", *prop_name) == 0) has_b2_1 = true;
- if (strcmp("b2_2", *prop_name) == 0) has_b2_2 = true;
- if (strcmp("c2", *prop_name) == 0) has_c2 = true;
- }
- CHECK(!has_a1);
- CHECK(!has_b1_1);
- CHECK(!has_b1_2);
- CHECK(!has_c1);
- CHECK(has_a2);
- CHECK(has_b2_1);
- CHECK(has_b2_2);
- CHECK(has_c2);
+ CHECK_EQ(NULL, GetProperty(global_env2,
v8::HeapGraphEdge::PROPERTY, "a1"));
+ CHECK_EQ(NULL, GetProperty(global_env2,
v8::HeapGraphEdge::PROPERTY, "b1_1"));
+ CHECK_EQ(NULL, GetProperty(global_env2,
v8::HeapGraphEdge::PROPERTY, "b1_2"));
+ CHECK_EQ(NULL, GetProperty(global_env2,
v8::HeapGraphEdge::PROPERTY, "c1"));
+ const v8::HeapGraphNode* a2_node =
+ GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "a2");
+ CHECK_NE(NULL, a2_node);
+ CHECK_NE(NULL, GetProperty(global_env2,
v8::HeapGraphEdge::PROPERTY, "b2_1"));
+ CHECK_NE(NULL, GetProperty(global_env2,
v8::HeapGraphEdge::PROPERTY, "b2_2"));
+ CHECK_NE(NULL, GetProperty(global_env2,
v8::HeapGraphEdge::PROPERTY, "c2"));
// Verify that anything related to '[ABC]1' is not reachable.
NamedEntriesDetector det;
@@ -564,5 +578,63 @@
CHECK(has_b2_1_x_ref);
CHECK(has_b2_2_x_ref);
}
+
+
+TEST(HeapSnapshotCodeObjects) {
+ v8::HandleScope scope;
+ v8::Handle<v8::Context> env = v8::Context::New();
+ env->Enter();
+
+ CompileAndRunScript(
+ "function lazy(x) { return x - 1; }\n"
+ "function compiled(x) { return x + 1; }\n"
+ "compiled(1)");
+ const v8::HeapSnapshot* snapshot =
+ v8::HeapProfiler::TakeSnapshot(v8::String::New("code"));
+
+ const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
+ const v8::HeapGraphNode* compiled =
+ GetProperty(global, v8::HeapGraphEdge::PROPERTY, "compiled");
+ CHECK_NE(NULL, compiled);
+ CHECK_EQ(v8::HeapGraphNode::CLOSURE, compiled->GetType());
+ const v8::HeapGraphNode* lazy =
+ GetProperty(global, v8::HeapGraphEdge::PROPERTY, "lazy");
+ CHECK_NE(NULL, lazy);
+ CHECK_EQ(v8::HeapGraphNode::CLOSURE, lazy->GetType());
+
+ // Find references to code.
+ const v8::HeapGraphNode* compiled_code =
+ GetProperty(compiled, v8::HeapGraphEdge::INTERNAL, "code");
+ CHECK_NE(NULL, compiled_code);
+ const v8::HeapGraphNode* lazy_code =
+ GetProperty(lazy, v8::HeapGraphEdge::INTERNAL, "code");
+ CHECK_NE(NULL, lazy_code);
+
+ // Verify that non-compiled code doesn't contain references to "x"
+ // literal, while compiled code does.
+ bool compiled_references_x = false, lazy_references_x = false;
+ for (int i = 0, count = compiled_code->GetChildrenCount(); i < count;
++i) {
+ const v8::HeapGraphEdge* prop = compiled_code->GetChild(i);
+ const v8::HeapGraphNode* node = prop->GetToNode();
+ if (node->GetType() == v8::HeapGraphNode::CODE) {
+ if (HasString(node, "x")) {
+ compiled_references_x = true;
+ break;
+ }
+ }
+ }
+ for (int i = 0, count = lazy_code->GetChildrenCount(); i < count; ++i) {
+ const v8::HeapGraphEdge* prop = lazy_code->GetChild(i);
+ const v8::HeapGraphNode* node = prop->GetToNode();
+ if (node->GetType() == v8::HeapGraphNode::CODE) {
+ if (HasString(node, "x")) {
+ lazy_references_x = true;
+ break;
+ }
+ }
+ }
+ CHECK(compiled_references_x);
+ CHECK(!lazy_references_x);
+}
#endif // ENABLE_LOGGING_AND_PROFILING
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev