Heap profiler: add a missing link between a function closure and shared function info.
Review URL: http://codereview.chromium.org/2846012 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4891 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
7808d45af5
commit
93387f272e
@ -196,7 +196,9 @@ class V8EXPORT HeapGraphEdge {
|
|||||||
enum Type {
|
enum Type {
|
||||||
CONTEXT_VARIABLE = 0, // A variable from a function context.
|
CONTEXT_VARIABLE = 0, // A variable from a function context.
|
||||||
ELEMENT = 1, // An element of an array.
|
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). */
|
/** Returns edge type (see HeapGraphEdge::Type). */
|
||||||
|
@ -4460,6 +4460,7 @@ Handle<Value> HeapGraphEdge::GetName() const {
|
|||||||
reinterpret_cast<const i::HeapGraphEdge*>(this);
|
reinterpret_cast<const i::HeapGraphEdge*>(this);
|
||||||
switch (edge->type()) {
|
switch (edge->type()) {
|
||||||
case i::HeapGraphEdge::CONTEXT_VARIABLE:
|
case i::HeapGraphEdge::CONTEXT_VARIABLE:
|
||||||
|
case i::HeapGraphEdge::INTERNAL:
|
||||||
case i::HeapGraphEdge::PROPERTY:
|
case i::HeapGraphEdge::PROPERTY:
|
||||||
return Handle<String>(ToApi<String>(i::Factory::LookupAsciiSymbol(
|
return Handle<String>(ToApi<String>(i::Factory::LookupAsciiSymbol(
|
||||||
edge->name())));
|
edge->name())));
|
||||||
|
@ -155,9 +155,9 @@ static inline void CheckNonEqualsHelper(const char* file,
|
|||||||
static inline void CheckEqualsHelper(const char* file,
|
static inline void CheckEqualsHelper(const char* file,
|
||||||
int line,
|
int line,
|
||||||
const char* expected_source,
|
const char* expected_source,
|
||||||
void* expected,
|
const void* expected,
|
||||||
const char* value_source,
|
const char* value_source,
|
||||||
void* value) {
|
const void* value) {
|
||||||
if (expected != value) {
|
if (expected != value) {
|
||||||
V8_Fatal(file, line,
|
V8_Fatal(file, line,
|
||||||
"CHECK_EQ(%s, %s) failed\n# Expected: %p\n# Found: %p",
|
"CHECK_EQ(%s, %s) failed\n# Expected: %p\n# Found: %p",
|
||||||
@ -170,9 +170,9 @@ static inline void CheckEqualsHelper(const char* file,
|
|||||||
static inline void CheckNonEqualsHelper(const char* file,
|
static inline void CheckNonEqualsHelper(const char* file,
|
||||||
int line,
|
int line,
|
||||||
const char* expected_source,
|
const char* expected_source,
|
||||||
void* expected,
|
const void* expected,
|
||||||
const char* value_source,
|
const char* value_source,
|
||||||
void* value) {
|
const void* value) {
|
||||||
if (expected == value) {
|
if (expected == value) {
|
||||||
V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n# Value: %p",
|
V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n# Value: %p",
|
||||||
expected_source, value_source, value);
|
expected_source, value_source, value);
|
||||||
|
@ -818,7 +818,7 @@ HeapGraphEdge::HeapGraphEdge(Type type,
|
|||||||
HeapEntry* from,
|
HeapEntry* from,
|
||||||
HeapEntry* to)
|
HeapEntry* to)
|
||||||
: type_(type), name_(name), from_(from), to_(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 @@ HeapEntry::~HeapEntry() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void HeapEntry::SetClosureReference(const char* name, HeapEntry* entry) {
|
void HeapEntry::AddEdge(HeapGraphEdge* edge) {
|
||||||
HeapGraphEdge* edge =
|
|
||||||
new HeapGraphEdge(HeapGraphEdge::CONTEXT_VARIABLE, name, this, entry);
|
|
||||||
children_.Add(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) {
|
void HeapEntry::SetElementReference(int index, HeapEntry* entry) {
|
||||||
HeapGraphEdge* edge = new HeapGraphEdge(index, this, entry);
|
AddEdge(new HeapGraphEdge(index, this, entry));
|
||||||
children_.Add(edge);
|
}
|
||||||
entry->retainers_.Add(edge);
|
|
||||||
|
|
||||||
|
void HeapEntry::SetInternalReference(const char* name, HeapEntry* entry) {
|
||||||
|
AddEdge(new HeapGraphEdge(HeapGraphEdge::INTERNAL, name, this, entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void HeapEntry::SetPropertyReference(const char* name, HeapEntry* entry) {
|
void HeapEntry::SetPropertyReference(const char* name, HeapEntry* entry) {
|
||||||
HeapGraphEdge* edge =
|
AddEdge(new HeapGraphEdge(HeapGraphEdge::PROPERTY, name, this, entry));
|
||||||
new HeapGraphEdge(HeapGraphEdge::PROPERTY, name, this, entry);
|
|
||||||
children_.Add(edge);
|
|
||||||
entry->retainers_.Add(edge);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1074,7 +1078,7 @@ void HeapEntry::CutEdges() {
|
|||||||
|
|
||||||
|
|
||||||
void HeapEntry::Print(int max_depth, int indent) {
|
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) {
|
if (type_ != STRING) {
|
||||||
OS::Print("%s %.40s\n", TypeAsString(), name_);
|
OS::Print("%s %.40s\n", TypeAsString(), name_);
|
||||||
} else {
|
} else {
|
||||||
@ -1100,6 +1104,9 @@ void HeapEntry::Print(int max_depth, int indent) {
|
|||||||
case HeapGraphEdge::ELEMENT:
|
case HeapGraphEdge::ELEMENT:
|
||||||
OS::Print(" %*c %d: ", indent, ' ', edge->index());
|
OS::Print(" %*c %d: ", indent, ' ', edge->index());
|
||||||
break;
|
break;
|
||||||
|
case HeapGraphEdge::INTERNAL:
|
||||||
|
OS::Print(" %*c $%s: ", indent, ' ', edge->name());
|
||||||
|
break;
|
||||||
case HeapGraphEdge::PROPERTY:
|
case HeapGraphEdge::PROPERTY:
|
||||||
OS::Print(" %*c %s: ", indent, ' ', edge->name());
|
OS::Print(" %*c %s: ", indent, ' ', edge->name());
|
||||||
break;
|
break;
|
||||||
@ -1145,6 +1152,9 @@ void HeapGraphPath::Print() {
|
|||||||
case HeapGraphEdge::ELEMENT:
|
case HeapGraphEdge::ELEMENT:
|
||||||
OS::Print("[%d] ", edge->index());
|
OS::Print("[%d] ", edge->index());
|
||||||
break;
|
break;
|
||||||
|
case HeapGraphEdge::INTERNAL:
|
||||||
|
OS::Print("[$%s] ", edge->name());
|
||||||
|
break;
|
||||||
case HeapGraphEdge::PROPERTY:
|
case HeapGraphEdge::PROPERTY:
|
||||||
OS::Print("[%s] ", edge->name());
|
OS::Print("[%s] ", edge->name());
|
||||||
break;
|
break;
|
||||||
@ -1318,6 +1328,16 @@ void HeapSnapshot::SetElementReference(HeapEntry* parent,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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,
|
void HeapSnapshot::SetPropertyReference(HeapEntry* parent,
|
||||||
String* reference_name,
|
String* reference_name,
|
||||||
Object* child) {
|
Object* child) {
|
||||||
@ -1546,6 +1566,7 @@ void HeapSnapshotGenerator::ExtractClosureReferences(JSObject* js_obj,
|
|||||||
snapshot_->SetClosureReference(entry, local_name, context->get(idx));
|
snapshot_->SetClosureReference(entry, local_name, context->get(idx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
snapshot_->SetInternalReference(entry, "code", func->shared());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,7 +431,8 @@ class HeapGraphEdge {
|
|||||||
enum Type {
|
enum Type {
|
||||||
CONTEXT_VARIABLE = v8::HeapGraphEdge::CONTEXT_VARIABLE,
|
CONTEXT_VARIABLE = v8::HeapGraphEdge::CONTEXT_VARIABLE,
|
||||||
ELEMENT = v8::HeapGraphEdge::ELEMENT,
|
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);
|
HeapGraphEdge(Type type, const char* name, HeapEntry* from, HeapEntry* to);
|
||||||
@ -443,7 +444,7 @@ class HeapGraphEdge {
|
|||||||
return index_;
|
return index_;
|
||||||
}
|
}
|
||||||
const char* name() const {
|
const char* name() const {
|
||||||
ASSERT(type_ == CONTEXT_VARIABLE || type_ == PROPERTY);
|
ASSERT(type_ == CONTEXT_VARIABLE || type_ == PROPERTY || type_ == INTERNAL);
|
||||||
return name_;
|
return name_;
|
||||||
}
|
}
|
||||||
HeapEntry* from() const { return from_; }
|
HeapEntry* from() const { return from_; }
|
||||||
@ -533,6 +534,7 @@ class HeapEntry {
|
|||||||
void PaintReachableFromOthers() { painted_ = kPaintReachableFromOthers; }
|
void PaintReachableFromOthers() { painted_ = kPaintReachableFromOthers; }
|
||||||
void SetClosureReference(const char* name, HeapEntry* entry);
|
void SetClosureReference(const char* name, HeapEntry* entry);
|
||||||
void SetElementReference(int index, HeapEntry* entry);
|
void SetElementReference(int index, HeapEntry* entry);
|
||||||
|
void SetInternalReference(const char* name, HeapEntry* entry);
|
||||||
void SetPropertyReference(const char* name, HeapEntry* entry);
|
void SetPropertyReference(const char* name, HeapEntry* entry);
|
||||||
void SetAutoIndexReference(HeapEntry* entry);
|
void SetAutoIndexReference(HeapEntry* entry);
|
||||||
|
|
||||||
@ -542,6 +544,7 @@ class HeapEntry {
|
|||||||
void Print(int max_depth, int indent);
|
void Print(int max_depth, int indent);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void AddEdge(HeapGraphEdge* edge);
|
||||||
int CalculateTotalSize();
|
int CalculateTotalSize();
|
||||||
int CalculateNonSharedTotalSize();
|
int CalculateNonSharedTotalSize();
|
||||||
void FindRetainingPaths(HeapEntry* node, CachedHeapGraphPath* prev_path);
|
void FindRetainingPaths(HeapEntry* node, CachedHeapGraphPath* prev_path);
|
||||||
@ -641,6 +644,8 @@ class HeapSnapshot {
|
|||||||
void SetClosureReference(
|
void SetClosureReference(
|
||||||
HeapEntry* parent, String* reference_name, Object* child);
|
HeapEntry* parent, String* reference_name, Object* child);
|
||||||
void SetElementReference(HeapEntry* parent, int index, Object* child);
|
void SetElementReference(HeapEntry* parent, int index, Object* child);
|
||||||
|
void SetInternalReference(
|
||||||
|
HeapEntry* parent, const char* reference_name, Object* child);
|
||||||
void SetPropertyReference(
|
void SetPropertyReference(
|
||||||
HeapEntry* parent, String* reference_name, Object* child);
|
HeapEntry* parent, String* reference_name, Object* child);
|
||||||
|
|
||||||
|
@ -428,6 +428,53 @@ class NamedEntriesDetector {
|
|||||||
|
|
||||||
} // namespace
|
} // 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) {
|
TEST(HeapSnapshot) {
|
||||||
v8::HandleScope scope;
|
v8::HandleScope scope;
|
||||||
|
|
||||||
@ -458,53 +505,20 @@ TEST(HeapSnapshot) {
|
|||||||
"var c2 = new C2(a2);");
|
"var c2 = new C2(a2);");
|
||||||
const v8::HeapSnapshot* snapshot_env2 =
|
const v8::HeapSnapshot* snapshot_env2 =
|
||||||
v8::HeapProfiler::TakeSnapshot(v8::String::New("env2"));
|
v8::HeapProfiler::TakeSnapshot(v8::String::New("env2"));
|
||||||
const v8::HeapGraphNode* global_env2;
|
const v8::HeapGraphNode* global_env2 = GetGlobalObject(snapshot_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();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify, that JS global object of env2 doesn't have '..1'
|
// Verify, that JS global object of env2 doesn't have '..1'
|
||||||
// properties, but has '..2' properties.
|
// properties, but has '..2' properties.
|
||||||
bool has_a1 = false, has_b1_1 = false, has_b1_2 = false, has_c1 = false;
|
CHECK_EQ(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "a1"));
|
||||||
bool has_a2 = false, has_b2_1 = false, has_b2_2 = false, has_c2 = false;
|
CHECK_EQ(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "b1_1"));
|
||||||
// This will be needed further.
|
CHECK_EQ(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "b1_2"));
|
||||||
const v8::HeapGraphNode* a2_node = NULL;
|
CHECK_EQ(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "c1"));
|
||||||
for (int i = 0, count = global_env2->GetChildrenCount(); i < count; ++i) {
|
const v8::HeapGraphNode* a2_node =
|
||||||
const v8::HeapGraphEdge* prop = global_env2->GetChild(i);
|
GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "a2");
|
||||||
v8::String::AsciiValue prop_name(prop->GetName());
|
CHECK_NE(NULL, a2_node);
|
||||||
if (strcmp("a1", *prop_name) == 0) has_a1 = true;
|
CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "b2_1"));
|
||||||
if (strcmp("b1_1", *prop_name) == 0) has_b1_1 = true;
|
CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "b2_2"));
|
||||||
if (strcmp("b1_2", *prop_name) == 0) has_b1_2 = true;
|
CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "c2"));
|
||||||
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);
|
|
||||||
|
|
||||||
// Verify that anything related to '[ABC]1' is not reachable.
|
// Verify that anything related to '[ABC]1' is not reachable.
|
||||||
NamedEntriesDetector det;
|
NamedEntriesDetector det;
|
||||||
@ -565,4 +579,62 @@ TEST(HeapSnapshot) {
|
|||||||
CHECK(has_b2_2_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
|
#endif // ENABLE_LOGGING_AND_PROFILING
|
||||||
|
Loading…
Reference in New Issue
Block a user