Heap profiler: correctly determine equivalence of objects having self-refs.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2972 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent f1a89f33
......@@ -333,6 +333,8 @@ void JSObjectsCluster::Print(StringStream* accumulator) const {
accumulator->Add("(roots)");
} else if (constructor_ == FromSpecialCase(GLOBAL_PROPERTY)) {
accumulator->Add("(global property)");
} else if (constructor_ == FromSpecialCase(SELF)) {
accumulator->Add("(self)");
} else {
SmartPointer<char> s_name(
constructor_->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL));
......@@ -393,9 +395,11 @@ inline int ClustersCoarser::ClusterBackRefs::Compare(
ClustersCoarser::ClustersCoarser()
: zscope_(DELETE_ON_EXIT),
sim_list_(ClustersCoarser::kInitialSimilarityListCapacity),
current_pair_(NULL) {
: zscope_(DELETE_ON_EXIT),
sim_list_(ClustersCoarser::kInitialSimilarityListCapacity),
current_pair_(NULL),
current_set_(NULL),
self_(NULL) {
}
......@@ -406,10 +410,12 @@ void ClustersCoarser::Call(const JSObjectsCluster& cluster,
ASSERT(current_pair_ == NULL);
current_pair_ = &pair;
current_set_ = new JSObjectsRetainerTree();
self_ = &cluster;
tree->ForEach(this);
sim_list_.Add(pair);
current_pair_ = NULL;
current_set_ = NULL;
self_ = NULL;
}
......@@ -417,8 +423,13 @@ void ClustersCoarser::Call(const JSObjectsCluster& cluster,
const NumberAndSizeInfo& number_and_size) {
ASSERT(current_pair_ != NULL);
ASSERT(current_set_ != NULL);
JSObjectsCluster eq = GetCoarseEquivalent(cluster);
ASSERT(self_ != NULL);
JSObjectsRetainerTree::Locator loc;
if (JSObjectsCluster::Compare(*self_, cluster) == 0) {
current_pair_->refs.Add(JSObjectsCluster(JSObjectsCluster::SELF));
return;
}
JSObjectsCluster eq = GetCoarseEquivalent(cluster);
if (!eq.is_null()) {
if (current_set_->Find(eq, &loc)) return;
current_pair_->refs.Add(eq);
......@@ -443,11 +454,7 @@ void ClustersCoarser::Process(JSObjectsRetainerTree* tree) {
int ClustersCoarser::DoProcess(JSObjectsRetainerTree* tree) {
tree->ForEach(this);
// To sort similarity list properly, references list of a cluster is
// required to be sorted, thus 'O1 <- A, B' and 'O2 <- B, A' would
// be considered equivalent. But we don't sort them explicitly
// because we know that they come from a splay tree traversal, so
// they are already sorted.
sim_list_.Iterate(ClusterBackRefs::SortRefsIterator);
sim_list_.Sort(ClusterBackRefsCmp);
return FillEqualityTree();
}
......
......@@ -53,7 +53,8 @@ class JSObjectsCluster BASE_EMBEDDED {
// These special cases are used in retainer profile.
enum SpecialCase {
ROOTS = 1,
GLOBAL_PROPERTY = 2
GLOBAL_PROPERTY = 2,
SELF = 3 // This case is used in ClustersCoarser only.
};
JSObjectsCluster() : constructor_(NULL), instance_(NULL) {}
......@@ -77,6 +78,9 @@ class JSObjectsCluster BASE_EMBEDDED {
(a.instance_ == b.instance_ ? 0 : (a.instance_ < b.instance_ ? -1 : 1))
: cons_cmp;
}
static int Compare(const JSObjectsCluster* a, const JSObjectsCluster* b) {
return Compare(*a, *b);
}
bool is_null() const { return constructor_ == NULL; }
bool can_be_coarsed() const { return instance_ != NULL; }
......@@ -93,6 +97,7 @@ class JSObjectsCluster BASE_EMBEDDED {
switch (special) {
case ROOTS: return Heap::result_symbol();
case GLOBAL_PROPERTY: return Heap::code_symbol();
case SELF: return Heap::catch_var_symbol();
default:
UNREACHABLE();
return NULL;
......@@ -183,6 +188,8 @@ class ClustersCoarser BASE_EMBEDDED {
ClusterBackRefs& operator=(const ClusterBackRefs& src);
static int Compare(const ClusterBackRefs& a, const ClusterBackRefs& b);
void SortRefs() { refs.Sort(JSObjectsCluster::Compare); }
static void SortRefsIterator(ClusterBackRefs* ref) { ref->SortRefs(); }
JSObjectsCluster cluster;
ZoneList<JSObjectsCluster> refs;
......@@ -219,6 +226,7 @@ class ClustersCoarser BASE_EMBEDDED {
EqualityTree eq_tree_;
ClusterBackRefs* current_pair_;
JSObjectsRetainerTree* current_set_;
const JSObjectsCluster* self_;
};
......
......@@ -74,13 +74,12 @@ TEST(ConstructorProfile) {
}
static JSObjectsCluster AddHeapObjectToTree(
JSObjectsRetainerTree* tree,
i::String* constructor,
int instance,
JSObjectsCluster* ref1 = NULL,
JSObjectsCluster* ref2 = NULL,
JSObjectsCluster* ref3 = NULL) {
static JSObjectsCluster AddHeapObjectToTree(JSObjectsRetainerTree* tree,
i::String* constructor,
int instance,
JSObjectsCluster* ref1 = NULL,
JSObjectsCluster* ref2 = NULL,
JSObjectsCluster* ref3 = NULL) {
JSObjectsCluster o(constructor, reinterpret_cast<i::Object*>(instance));
JSObjectsClusterTree* o_tree = new JSObjectsClusterTree();
JSObjectsClusterTree::Locator o_loc;
......@@ -94,6 +93,16 @@ static JSObjectsCluster AddHeapObjectToTree(
}
static void AddSelfReferenceToTree(JSObjectsRetainerTree* tree,
JSObjectsCluster* self_ref) {
JSObjectsRetainerTree::Locator loc;
CHECK(tree->Find(*self_ref, &loc));
JSObjectsClusterTree::Locator o_loc;
CHECK_NE(NULL, loc.value());
loc.value()->Insert(*self_ref, &o_loc);
}
static inline void CheckEqualsHelper(const char* file, int line,
const char* expected_source,
const JSObjectsCluster& expected,
......@@ -121,7 +130,7 @@ static inline void CheckNonEqualsHelper(const char* file, int line,
if (JSObjectsCluster::Compare(expected, value) == 0) {
i::HeapStringAllocator allocator;
i::StringStream stream(&allocator);
stream.Add("# Expected: ");
stream.Add("# !Expected: ");
expected.DebugPrint(&stream);
stream.Add("\n# Found: ");
value.DebugPrint(&stream);
......@@ -243,9 +252,11 @@ TEST(ClustersCoarserPathsTraversal) {
coarser.Process(&tree);
CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o));
CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(o11));
CHECK_EQ(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(o12));
CHECK_EQ(coarser.GetCoarseEquivalent(o21), coarser.GetCoarseEquivalent(o22));
CHECK_NE(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(o21));
CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(p));
CHECK_EQ(coarser.GetCoarseEquivalent(p), coarser.GetCoarseEquivalent(q));
CHECK_EQ(coarser.GetCoarseEquivalent(q), coarser.GetCoarseEquivalent(r));
CHECK_NE(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(p));
......@@ -253,6 +264,54 @@ TEST(ClustersCoarserPathsTraversal) {
}
TEST(ClustersCoarserSelf) {
v8::HandleScope scope;
v8::Handle<v8::Context> env = v8::Context::New();
env->Enter();
i::ZoneScope zn_scope(i::DELETE_ON_EXIT);
JSObjectsRetainerTree tree;
// On the following graph:
//
// p (self-referencing)
// <- o1 <-
// q (self-referencing) o
// <- o2 <-
// r (self-referencing)
//
// we expect that coarser will deduce equivalences: p ~ q ~ r, o1 ~ o2;
JSObjectsCluster o =
AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100);
JSObjectsCluster o1 =
AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x110, &o);
JSObjectsCluster o2 =
AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x120, &o);
JSObjectsCluster p =
AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x300, &o1);
AddSelfReferenceToTree(&tree, &p);
JSObjectsCluster q =
AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x310, &o1, &o2);
AddSelfReferenceToTree(&tree, &q);
JSObjectsCluster r =
AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x320, &o2);
AddSelfReferenceToTree(&tree, &r);
ClustersCoarser coarser;
coarser.Process(&tree);
CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o));
CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(o1));
CHECK_EQ(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o2));
CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(p));
CHECK_EQ(coarser.GetCoarseEquivalent(p), coarser.GetCoarseEquivalent(q));
CHECK_EQ(coarser.GetCoarseEquivalent(q), coarser.GetCoarseEquivalent(r));
CHECK_NE(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(p));
}
namespace {
class RetainerProfilePrinter : public RetainerHeapProfile::Printer {
......
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