Remove snapshots-related code that is implemented in DevTools heap profiler.

Diffs and retaining paths are implemented on JS side. There is no need
to maintain native implementation.

R=vitalyr@chromium.org
BUG=none
TEST=none

Review URL: http://codereview.chromium.org/6770009

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7412 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
mikhail.naganov@gmail.com 2011-03-29 12:52:07 +00:00
parent 770df67e16
commit 2d95ed4b25
6 changed files with 1 additions and 560 deletions

View File

@ -240,22 +240,6 @@ class V8EXPORT HeapGraphEdge {
};
class V8EXPORT HeapGraphPath {
public:
/** Returns the number of edges in the path. */
int GetEdgesCount() const;
/** Returns an edge from the path. */
const HeapGraphEdge* GetEdge(int index) const;
/** Returns origin node. */
const HeapGraphNode* GetFromNode() const;
/** Returns destination node. */
const HeapGraphNode* GetToNode() const;
};
/**
* HeapGraphNode represents a node in a heap graph.
*/
@ -325,12 +309,6 @@ class V8EXPORT HeapGraphNode {
/** Returns a retainer by index. */
const HeapGraphEdge* GetRetainer(int index) const;
/** Returns the number of simple retaining paths from the root to the node. */
int GetRetainingPathsCount() const;
/** Returns a retaining path by index. */
const HeapGraphPath* GetRetainingPath(int index) const;
/**
* Returns a dominator node. This is the node that participates in every
* path from the snapshot root to the current node.
@ -339,16 +317,6 @@ class V8EXPORT HeapGraphNode {
};
class V8EXPORT HeapSnapshotsDiff {
public:
/** Returns the root node for added nodes. */
const HeapGraphNode* GetAdditionsRoot() const;
/** Returns the root node for deleted nodes. */
const HeapGraphNode* GetDeletionsRoot() const;
};
/**
* HeapSnapshots record the state of the JS heap at some moment.
*/
@ -378,12 +346,6 @@ class V8EXPORT HeapSnapshot {
/** Returns a node by its id. */
const HeapGraphNode* GetNodeById(uint64_t id) const;
/**
* Returns a diff between this snapshot and another one. Only snapshots
* of the same type can be compared.
*/
const HeapSnapshotsDiff* CompareWith(const HeapSnapshot* snapshot) const;
/**
* Deletes the snapshot and removes it from HeapProfiler's list.
* All pointers to nodes, edges and paths previously returned become

View File

@ -5288,34 +5288,6 @@ const HeapGraphNode* HeapGraphEdge::GetToNode() const {
}
static i::HeapGraphPath* ToInternal(const HeapGraphPath* path) {
return const_cast<i::HeapGraphPath*>(
reinterpret_cast<const i::HeapGraphPath*>(path));
}
int HeapGraphPath::GetEdgesCount() const {
return ToInternal(this)->path()->length();
}
const HeapGraphEdge* HeapGraphPath::GetEdge(int index) const {
return reinterpret_cast<const HeapGraphEdge*>(
ToInternal(this)->path()->at(index));
}
const HeapGraphNode* HeapGraphPath::GetFromNode() const {
return GetEdgesCount() > 0 ? GetEdge(0)->GetFromNode() : NULL;
}
const HeapGraphNode* HeapGraphPath::GetToNode() const {
const int count = GetEdgesCount();
return count > 0 ? GetEdge(count - 1)->GetToNode() : NULL;
}
static i::HeapEntry* ToInternal(const HeapGraphNode* entry) {
return const_cast<i::HeapEntry*>(
reinterpret_cast<const i::HeapEntry*>(entry));
@ -5397,21 +5369,6 @@ const HeapGraphEdge* HeapGraphNode::GetRetainer(int index) const {
}
int HeapGraphNode::GetRetainingPathsCount() const {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::HeapSnapshot::GetRetainingPathsCount");
return ToInternal(this)->GetRetainingPaths()->length();
}
const HeapGraphPath* HeapGraphNode::GetRetainingPath(int index) const {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::HeapSnapshot::GetRetainingPath");
return reinterpret_cast<const HeapGraphPath*>(
ToInternal(this)->GetRetainingPaths()->at(index));
}
const HeapGraphNode* HeapGraphNode::GetDominatorNode() const {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::HeapSnapshot::GetDominatorNode");
@ -5419,26 +5376,6 @@ const HeapGraphNode* HeapGraphNode::GetDominatorNode() const {
}
const HeapGraphNode* HeapSnapshotsDiff::GetAdditionsRoot() const {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::HeapSnapshotsDiff::GetAdditionsRoot");
i::HeapSnapshotsDiff* diff =
const_cast<i::HeapSnapshotsDiff*>(
reinterpret_cast<const i::HeapSnapshotsDiff*>(this));
return reinterpret_cast<const HeapGraphNode*>(diff->additions_root());
}
const HeapGraphNode* HeapSnapshotsDiff::GetDeletionsRoot() const {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::HeapSnapshotsDiff::GetDeletionsRoot");
i::HeapSnapshotsDiff* diff =
const_cast<i::HeapSnapshotsDiff*>(
reinterpret_cast<const i::HeapSnapshotsDiff*>(this));
return reinterpret_cast<const HeapGraphNode*>(diff->deletions_root());
}
static i::HeapSnapshot* ToInternal(const HeapSnapshot* snapshot) {
return const_cast<i::HeapSnapshot*>(
reinterpret_cast<const i::HeapSnapshot*>(snapshot));
@ -5494,15 +5431,6 @@ const HeapGraphNode* HeapSnapshot::GetNodeById(uint64_t id) const {
}
const HeapSnapshotsDiff* HeapSnapshot::CompareWith(
const HeapSnapshot* snapshot) const {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::HeapSnapshot::CompareWith");
return reinterpret_cast<const HeapSnapshotsDiff*>(
ToInternal(this)->CompareWith(ToInternal(snapshot)));
}
void HeapSnapshot::Serialize(OutputStream* stream,
HeapSnapshot::SerializationFormat format) const {
i::Isolate* isolate = i::Isolate::Current();

View File

@ -984,11 +984,6 @@ int HeapEntry::RetainedSize(bool exact) {
}
List<HeapGraphPath*>* HeapEntry::GetRetainingPaths() {
return snapshot_->GetRetainingPaths(this);
}
template<class Visitor>
void HeapEntry::ApplyAndPaintAllReachable(Visitor* visitor) {
List<HeapEntry*> list(10);
@ -1147,107 +1142,6 @@ void HeapEntry::CalculateExactRetainedSize() {
}
class CachedHeapGraphPath {
public:
CachedHeapGraphPath()
: nodes_(NodesMatch) { }
CachedHeapGraphPath(const CachedHeapGraphPath& src)
: nodes_(NodesMatch, &HashMap::DefaultAllocator, src.nodes_.capacity()),
path_(src.path_.length() + 1) {
for (HashMap::Entry* p = src.nodes_.Start();
p != NULL;
p = src.nodes_.Next(p)) {
nodes_.Lookup(p->key, p->hash, true);
}
path_.AddAll(src.path_);
}
void Add(HeapGraphEdge* edge) {
nodes_.Lookup(edge->to(), Hash(edge->to()), true);
path_.Add(edge);
}
bool ContainsNode(HeapEntry* node) {
return nodes_.Lookup(node, Hash(node), false) != NULL;
}
const List<HeapGraphEdge*>* path() const { return &path_; }
private:
static uint32_t Hash(HeapEntry* entry) {
return static_cast<uint32_t>(reinterpret_cast<intptr_t>(entry));
}
static bool NodesMatch(void* key1, void* key2) { return key1 == key2; }
HashMap nodes_;
List<HeapGraphEdge*> path_;
};
List<HeapGraphPath*>* HeapEntry::CalculateRetainingPaths() {
List<HeapGraphPath*>* retaining_paths = new List<HeapGraphPath*>(4);
CachedHeapGraphPath path;
FindRetainingPaths(&path, retaining_paths);
return retaining_paths;
}
void HeapEntry::FindRetainingPaths(CachedHeapGraphPath* prev_path,
List<HeapGraphPath*>* retaining_paths) {
Vector<HeapGraphEdge*> rets = retainers();
for (int i = 0; i < rets.length(); ++i) {
HeapGraphEdge* ret_edge = rets[i];
if (prev_path->ContainsNode(ret_edge->From())) continue;
if (ret_edge->From() != snapshot()->root()) {
CachedHeapGraphPath path(*prev_path);
path.Add(ret_edge);
ret_edge->From()->FindRetainingPaths(&path, retaining_paths);
} else {
HeapGraphPath* ret_path = new HeapGraphPath(*prev_path->path());
ret_path->Set(0, ret_edge);
retaining_paths->Add(ret_path);
}
}
}
HeapGraphPath::HeapGraphPath(const List<HeapGraphEdge*>& path)
: path_(path.length() + 1) {
Add(NULL);
for (int i = path.length() - 1; i >= 0; --i) {
Add(path[i]);
}
}
void HeapGraphPath::Print() {
path_[0]->From()->Print(1, 0);
for (int i = 0; i < path_.length(); ++i) {
OS::Print(" -> ");
HeapGraphEdge* edge = path_[i];
switch (edge->type()) {
case HeapGraphEdge::kContextVariable:
OS::Print("[#%s] ", edge->name());
break;
case HeapGraphEdge::kElement:
case HeapGraphEdge::kHidden:
OS::Print("[%d] ", edge->index());
break;
case HeapGraphEdge::kInternal:
OS::Print("[$%s] ", edge->name());
break;
case HeapGraphEdge::kProperty:
OS::Print("[%s] ", edge->name());
break;
case HeapGraphEdge::kShortcut:
OS::Print("[^%s] ", edge->name());
break;
default:
OS::Print("!!! unknown edge type: %d ", edge->type());
}
edge->to()->Print(1, 0);
}
OS::Print("\n");
}
// It is very important to keep objects that form a heap snapshot
// as small as possible.
namespace { // Avoid littering the global namespace.
@ -1278,8 +1172,7 @@ HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection,
gc_roots_entry_(NULL),
natives_root_entry_(NULL),
raw_entries_(NULL),
entries_sorted_(false),
retaining_paths_(HeapEntry::Match) {
entries_sorted_(false) {
STATIC_ASSERT(
sizeof(HeapGraphEdge) ==
SnapshotSizeConstants<sizeof(void*)>::kExpectedHeapGraphEdgeSize); // NOLINT
@ -1288,21 +1181,8 @@ HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection,
SnapshotSizeConstants<sizeof(void*)>::kExpectedHeapEntrySize); // NOLINT
}
static void DeleteHeapGraphPath(HeapGraphPath** path_ptr) {
delete *path_ptr;
}
HeapSnapshot::~HeapSnapshot() {
DeleteArray(raw_entries_);
for (HashMap::Entry* p = retaining_paths_.Start();
p != NULL;
p = retaining_paths_.Next(p)) {
List<HeapGraphPath*>* list =
reinterpret_cast<List<HeapGraphPath*>*>(p->value);
list->Iterate(DeleteHeapGraphPath);
delete list;
}
}
@ -1404,14 +1284,7 @@ HeapEntry* HeapSnapshot::GetNextEntryToInit() {
}
HeapSnapshotsDiff* HeapSnapshot::CompareWith(HeapSnapshot* snapshot) {
return collection_->CompareSnapshots(this, snapshot);
}
HeapEntry* HeapSnapshot::GetEntryById(uint64_t id) {
// GetSortedEntriesList is used in diff algorithm and sorts
// entries by their id.
List<HeapEntry*>* entries_by_id = GetSortedEntriesList();
// Perform a binary search by id.
@ -1432,16 +1305,6 @@ HeapEntry* HeapSnapshot::GetEntryById(uint64_t id) {
}
List<HeapGraphPath*>* HeapSnapshot::GetRetainingPaths(HeapEntry* entry) {
HashMap::Entry* p =
retaining_paths_.Lookup(entry, HeapEntry::Hash(entry), true);
if (p->value == NULL) {
p->value = entry->CalculateRetainingPaths();
}
return reinterpret_cast<List<HeapGraphPath*>*>(p->value);
}
template<class T>
static int SortByIds(const T* entry1_ptr,
const T* entry2_ptr) {
@ -1631,13 +1494,6 @@ void HeapSnapshotsCollection::RemoveSnapshot(HeapSnapshot* snapshot) {
}
HeapSnapshotsDiff* HeapSnapshotsCollection::CompareSnapshots(
HeapSnapshot* snapshot1,
HeapSnapshot* snapshot2) {
return comparator_.Compare(snapshot1, snapshot2);
}
HeapEntry *const HeapEntriesMap::kHeapEntryPlaceholder =
reinterpret_cast<HeapEntry*>(1);
@ -2804,83 +2660,6 @@ bool HeapSnapshotGenerator::ApproximateRetainedSizes() {
}
void HeapSnapshotsDiff::CreateRoots(int additions_count, int deletions_count) {
raw_additions_root_ =
NewArray<char>(HeapEntry::EntriesSize(1, additions_count, 0));
additions_root()->Init(
snapshot2_, HeapEntry::kHidden, "", 0, 0, additions_count, 0);
raw_deletions_root_ =
NewArray<char>(HeapEntry::EntriesSize(1, deletions_count, 0));
deletions_root()->Init(
snapshot1_, HeapEntry::kHidden, "", 0, 0, deletions_count, 0);
}
static void DeleteHeapSnapshotsDiff(HeapSnapshotsDiff** diff_ptr) {
delete *diff_ptr;
}
HeapSnapshotsComparator::~HeapSnapshotsComparator() {
diffs_.Iterate(DeleteHeapSnapshotsDiff);
}
HeapSnapshotsDiff* HeapSnapshotsComparator::Compare(HeapSnapshot* snapshot1,
HeapSnapshot* snapshot2) {
snapshot1->ClearPaint();
snapshot1->root()->PaintAllReachable();
snapshot2->ClearPaint();
snapshot2->root()->PaintAllReachable();
List<HeapEntry*>* entries1 = snapshot1->GetSortedEntriesList();
List<HeapEntry*>* entries2 = snapshot2->GetSortedEntriesList();
int i = 0, j = 0;
List<HeapEntry*> added_entries, deleted_entries;
while (i < entries1->length() && j < entries2->length()) {
uint64_t id1 = entries1->at(i)->id();
uint64_t id2 = entries2->at(j)->id();
if (id1 == id2) {
HeapEntry* entry1 = entries1->at(i++);
HeapEntry* entry2 = entries2->at(j++);
if (entry1->painted_reachable() != entry2->painted_reachable()) {
if (entry1->painted_reachable())
deleted_entries.Add(entry1);
else
added_entries.Add(entry2);
}
} else if (id1 < id2) {
HeapEntry* entry = entries1->at(i++);
deleted_entries.Add(entry);
} else {
HeapEntry* entry = entries2->at(j++);
added_entries.Add(entry);
}
}
while (i < entries1->length()) {
HeapEntry* entry = entries1->at(i++);
deleted_entries.Add(entry);
}
while (j < entries2->length()) {
HeapEntry* entry = entries2->at(j++);
added_entries.Add(entry);
}
HeapSnapshotsDiff* diff = new HeapSnapshotsDiff(snapshot1, snapshot2);
diffs_.Add(diff);
diff->CreateRoots(added_entries.length(), deleted_entries.length());
for (int i = 0; i < deleted_entries.length(); ++i) {
HeapEntry* entry = deleted_entries[i];
diff->AddDeletedEntry(i, i + 1, entry);
}
for (int i = 0; i < added_entries.length(); ++i) {
HeapEntry* entry = added_entries[i];
diff->AddAddedEntry(i, i + 1, entry);
}
return diff;
}
class OutputStreamWriter {
public:
explicit OutputStreamWriter(v8::OutputStream* stream)

View File

@ -490,8 +490,6 @@ class HeapGraphEdge BASE_EMBEDDED {
};
class CachedHeapGraphPath;
class HeapGraphPath;
class HeapSnapshot;
// HeapEntry instances represent an entity from the heap (or a special
@ -551,7 +549,6 @@ class HeapEntry BASE_EMBEDDED {
return Vector<HeapGraphEdge>(children_arr(), children_count_); }
Vector<HeapGraphEdge*> retainers() {
return Vector<HeapGraphEdge*>(retainers_arr(), retainers_count_); }
List<HeapGraphPath*>* GetRetainingPaths();
HeapEntry* dominator() { return dominator_; }
void set_dominator(HeapEntry* entry) { dominator_ = entry; }
@ -585,18 +582,12 @@ class HeapEntry BASE_EMBEDDED {
int EntrySize() { return EntriesSize(1, children_count_, retainers_count_); }
int RetainedSize(bool exact);
List<HeapGraphPath*>* CalculateRetainingPaths();
void Print(int max_depth, int indent);
static int EntriesSize(int entries_count,
int children_count,
int retainers_count);
static uint32_t Hash(HeapEntry* entry) {
return ComputeIntegerHash(
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(entry)));
}
static bool Match(void* entry1, void* entry2) { return entry1 == entry2; }
private:
HeapGraphEdge* children_arr() {
@ -606,8 +597,6 @@ class HeapEntry BASE_EMBEDDED {
return reinterpret_cast<HeapGraphEdge**>(children_arr() + children_count_);
}
void CalculateExactRetainedSize();
void FindRetainingPaths(CachedHeapGraphPath* prev_path,
List<HeapGraphPath*>* retaining_paths);
const char* TypeAsString();
unsigned painted_: 2;
@ -638,27 +627,7 @@ class HeapEntry BASE_EMBEDDED {
};
class HeapGraphPath {
public:
HeapGraphPath()
: path_(8) { }
explicit HeapGraphPath(const List<HeapGraphEdge*>& path);
void Add(HeapGraphEdge* edge) { path_.Add(edge); }
void Set(int index, HeapGraphEdge* edge) { path_[index] = edge; }
const List<HeapGraphEdge*>* path() { return &path_; }
void Print();
private:
List<HeapGraphEdge*> path_;
DISALLOW_COPY_AND_ASSIGN(HeapGraphPath);
};
class HeapSnapshotsCollection;
class HeapSnapshotsDiff;
// HeapSnapshot represents a single heap snapshot. It is stored in
// HeapSnapshotsCollection, which is also a factory for
@ -700,9 +669,7 @@ class HeapSnapshot {
HeapEntry* AddGcRootsEntry(int children_count, int retainers_count);
HeapEntry* AddNativesRootEntry(int children_count, int retainers_count);
void ClearPaint();
HeapSnapshotsDiff* CompareWith(HeapSnapshot* snapshot);
HeapEntry* GetEntryById(uint64_t id);
List<HeapGraphPath*>* GetRetainingPaths(HeapEntry* entry);
List<HeapEntry*>* GetSortedEntriesList();
template<class Visitor>
void IterateEntries(Visitor* visitor) { entries_.Iterate(visitor); }
@ -724,7 +691,6 @@ class HeapSnapshot {
char* raw_entries_;
List<HeapEntry*> entries_;
bool entries_sorted_;
HashMap retaining_paths_;
#ifdef DEBUG
int raw_entries_size_;
#endif
@ -781,58 +747,6 @@ class HeapObjectsMap {
};
class HeapSnapshotsDiff {
public:
HeapSnapshotsDiff(HeapSnapshot* snapshot1, HeapSnapshot* snapshot2)
: snapshot1_(snapshot1),
snapshot2_(snapshot2),
raw_additions_root_(NULL),
raw_deletions_root_(NULL) { }
~HeapSnapshotsDiff() {
DeleteArray(raw_deletions_root_);
DeleteArray(raw_additions_root_);
}
void AddAddedEntry(int child_index, int index, HeapEntry* entry) {
additions_root()->SetUnidirElementReference(child_index, index, entry);
}
void AddDeletedEntry(int child_index, int index, HeapEntry* entry) {
deletions_root()->SetUnidirElementReference(child_index, index, entry);
}
void CreateRoots(int additions_count, int deletions_count);
HeapEntry* additions_root() {
return reinterpret_cast<HeapEntry*>(raw_additions_root_);
}
HeapEntry* deletions_root() {
return reinterpret_cast<HeapEntry*>(raw_deletions_root_);
}
private:
HeapSnapshot* snapshot1_;
HeapSnapshot* snapshot2_;
char* raw_additions_root_;
char* raw_deletions_root_;
DISALLOW_COPY_AND_ASSIGN(HeapSnapshotsDiff);
};
class HeapSnapshotsComparator {
public:
HeapSnapshotsComparator() { }
~HeapSnapshotsComparator();
HeapSnapshotsDiff* Compare(HeapSnapshot* snapshot1, HeapSnapshot* snapshot2);
private:
List<HeapSnapshotsDiff*> diffs_;
DISALLOW_COPY_AND_ASSIGN(HeapSnapshotsComparator);
};
class HeapSnapshotsCollection {
public:
HeapSnapshotsCollection();
@ -853,9 +767,6 @@ class HeapSnapshotsCollection {
uint64_t GetObjectId(Address addr) { return ids_.FindObject(addr); }
void ObjectMoveEvent(Address from, Address to) { ids_.MoveObject(from, to); }
HeapSnapshotsDiff* CompareSnapshots(HeapSnapshot* snapshot1,
HeapSnapshot* snapshot2);
private:
INLINE(static bool HeapSnapshotsMatch(void* key1, void* key2)) {
return key1 == key2;
@ -869,7 +780,6 @@ class HeapSnapshotsCollection {
TokenEnumerator* token_enumerator_;
// Mapping from HeapObject addresses to objects' uids.
HeapObjectsMap ids_;
HeapSnapshotsComparator comparator_;
DISALLOW_COPY_AND_ASSIGN(HeapSnapshotsCollection);
};

View File

@ -36,11 +36,6 @@ test-debug/DebuggerAgent: PASS, (PASS || FAIL) if $system == linux
# BUG(382): Weird test. Can't guarantee that it never times out.
test-api/ApplyInterruption: PASS || TIMEOUT
# BUG(484): This test which we thought was originally corrected in r5236
# is re-appearing. Disabled until bug in test is fixed. This only fails
# when snapshot is on, so I am marking it PASS || FAIL
test-heap-profiler/HeapSnapshotsDiff: PASS || FAIL
# These tests always fail. They are here to test test.py. If
# they don't fail then test.py has failed.
test-serialize/TestThatAlwaysFails: FAIL

View File

@ -433,19 +433,6 @@ static const v8::HeapGraphNode* GetProperty(const v8::HeapGraphNode* node,
}
static bool IsNodeRetainedAs(const v8::HeapGraphNode* node,
v8::HeapGraphEdge::Type type,
const char* name) {
for (int i = 0, count = node->GetRetainersCount(); i < count; ++i) {
const v8::HeapGraphEdge* prop = node->GetRetainer(i);
v8::String::AsciiValue prop_name(prop->GetName());
if (prop->GetType() == type && strcmp(name, *prop_name) == 0)
return true;
}
return false;
}
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);
@ -496,56 +483,6 @@ TEST(HeapSnapshot) {
CHECK(det.has_A2);
CHECK(det.has_B2);
CHECK(det.has_C2);
/*
// Currently disabled. Too many retaining paths emerge, need to
// reduce the amount.
// Verify 'a2' object retainers. They are:
// - (global object).a2
// - c2.x1, c2.x2, c2[1]
// - b2_1 and b2_2 closures: via 'x' variable
CHECK_EQ(6, a2_node->GetRetainingPathsCount());
bool has_global_obj_a2_ref = false;
bool has_c2_x1_ref = false, has_c2_x2_ref = false, has_c2_1_ref = false;
bool has_b2_1_x_ref = false, has_b2_2_x_ref = false;
for (int i = 0; i < a2_node->GetRetainingPathsCount(); ++i) {
const v8::HeapGraphPath* path = a2_node->GetRetainingPath(i);
const int edges_count = path->GetEdgesCount();
CHECK_GT(edges_count, 0);
const v8::HeapGraphEdge* last_edge = path->GetEdge(edges_count - 1);
v8::String::AsciiValue last_edge_name(last_edge->GetName());
if (strcmp("a2", *last_edge_name) == 0
&& last_edge->GetType() == v8::HeapGraphEdge::kProperty) {
has_global_obj_a2_ref = true;
continue;
}
CHECK_GT(edges_count, 1);
const v8::HeapGraphEdge* prev_edge = path->GetEdge(edges_count - 2);
v8::String::AsciiValue prev_edge_name(prev_edge->GetName());
if (strcmp("x1", *last_edge_name) == 0
&& last_edge->GetType() == v8::HeapGraphEdge::kProperty
&& strcmp("c2", *prev_edge_name) == 0) has_c2_x1_ref = true;
if (strcmp("x2", *last_edge_name) == 0
&& last_edge->GetType() == v8::HeapGraphEdge::kProperty
&& strcmp("c2", *prev_edge_name) == 0) has_c2_x2_ref = true;
if (strcmp("1", *last_edge_name) == 0
&& last_edge->GetType() == v8::HeapGraphEdge::kElement
&& strcmp("c2", *prev_edge_name) == 0) has_c2_1_ref = true;
if (strcmp("x", *last_edge_name) == 0
&& last_edge->GetType() == v8::HeapGraphEdge::kContextVariable
&& strcmp("b2_1", *prev_edge_name) == 0) has_b2_1_x_ref = true;
if (strcmp("x", *last_edge_name) == 0
&& last_edge->GetType() == v8::HeapGraphEdge::kContextVariable
&& strcmp("b2_2", *prev_edge_name) == 0) has_b2_2_x_ref = true;
}
CHECK(has_global_obj_a2_ref);
CHECK(has_c2_x1_ref);
CHECK(has_c2_x2_ref);
CHECK(has_c2_1_ref);
CHECK(has_b2_1_x_ref);
CHECK(has_b2_2_x_ref);
*/
}
@ -774,76 +711,6 @@ TEST(HeapEntryIdsAndGC) {
}
TEST(HeapSnapshotsDiff) {
v8::HandleScope scope;
LocalContext env;
CompileRun(
"function A() {}\n"
"function B(x) { this.x = x; }\n"
"function A2(a) { for (var i = 0; i < a; ++i) this[i] = i; }\n"
"var a = new A();\n"
"var b = new B(a);");
const v8::HeapSnapshot* snapshot1 =
v8::HeapProfiler::TakeSnapshot(v8::String::New("s1"));
CompileRun(
"delete a;\n"
"b.x = null;\n"
"var a = new A2(20);\n"
"var b2 = new B(a);");
const v8::HeapSnapshot* snapshot2 =
v8::HeapProfiler::TakeSnapshot(v8::String::New("s2"));
const v8::HeapSnapshotsDiff* diff = snapshot1->CompareWith(snapshot2);
// Verify additions: ensure that addition of A and B was detected.
const v8::HeapGraphNode* additions_root = diff->GetAdditionsRoot();
bool found_A = false, found_B = false;
uint64_t s1_A_id = 0;
for (int i = 0, count = additions_root->GetChildrenCount(); i < count; ++i) {
const v8::HeapGraphEdge* prop = additions_root->GetChild(i);
const v8::HeapGraphNode* node = prop->GetToNode();
if (node->GetType() == v8::HeapGraphNode::kObject) {
v8::String::AsciiValue node_name(node->GetName());
if (strcmp(*node_name, "A2") == 0) {
CHECK(IsNodeRetainedAs(node, v8::HeapGraphEdge::kShortcut, "a"));
CHECK(!found_A);
found_A = true;
s1_A_id = node->GetId();
} else if (strcmp(*node_name, "B") == 0) {
CHECK(IsNodeRetainedAs(node, v8::HeapGraphEdge::kShortcut, "b2"));
CHECK(!found_B);
found_B = true;
}
}
}
CHECK(found_A);
CHECK(found_B);
// Verify deletions: ensure that deletion of A was detected.
const v8::HeapGraphNode* deletions_root = diff->GetDeletionsRoot();
bool found_A_del = false;
uint64_t s2_A_id = 0;
for (int i = 0, count = deletions_root->GetChildrenCount(); i < count; ++i) {
const v8::HeapGraphEdge* prop = deletions_root->GetChild(i);
const v8::HeapGraphNode* node = prop->GetToNode();
if (node->GetType() == v8::HeapGraphNode::kObject) {
v8::String::AsciiValue node_name(node->GetName());
if (strcmp(*node_name, "A") == 0) {
CHECK(IsNodeRetainedAs(node, v8::HeapGraphEdge::kShortcut, "a"));
CHECK(!found_A_del);
found_A_del = true;
s2_A_id = node->GetId();
}
}
}
CHECK(found_A_del);
CHECK_NE_UINT64_T(0, s1_A_id);
CHECK(s1_A_id != s2_A_id);
}
TEST(HeapSnapshotRootPreservedAfterSorting) {
v8::HandleScope scope;
LocalContext env;