Index: Source/heap/HeapTest.cpp |
diff --git a/Source/heap/HeapTest.cpp b/Source/heap/HeapTest.cpp |
index f1bbe104fdfd41094719fef93bc9a15c7321083e..fc56a36b83aeb6ca79f52e01d38efc46c1dc6f78 100644 |
--- a/Source/heap/HeapTest.cpp |
+++ b/Source/heap/HeapTest.cpp |
@@ -38,6 +38,7 @@ |
#include "heap/Visitor.h" |
#include "wtf/HashTraits.h" |
+#include "wtf/LinkedHashSet.h" |
#include <gtest/gtest.h> |
@@ -300,9 +301,39 @@ private: |
int m_x; |
}; |
+class OffHeapInt : public RefCounted<OffHeapInt> { |
+public: |
+ static RefPtr<OffHeapInt> create(int x) |
+ { |
+ return adoptRef(new OffHeapInt(x)); |
+ } |
+ |
+ virtual ~OffHeapInt() |
+ { |
+ ++s_destructorCalls; |
+ } |
+ |
+ static int s_destructorCalls; |
+ static void trace(Visitor*) { } |
Mads Ager (chromium)
2014/04/03 09:24:35
This is off heap, why do you need a trace method (
Erik Corry
2014/04/10 10:47:37
Done.
|
+ |
+ int value() const { return m_x; } |
+ |
+ bool operator==(const OffHeapInt& other) const { return other.value() == value(); } |
+ |
+ unsigned hash() { return IntHash<int>::hash(m_x); } |
+ |
+protected: |
+ OffHeapInt(int x) : m_x(x) { } |
+ |
+private: |
+ OffHeapInt(); |
+ int m_x; |
+}; |
+ |
USED_FROM_MULTIPLE_THREADS(IntWrapper); |
int IntWrapper::s_destructorCalls = 0; |
+int OffHeapInt::s_destructorCalls = 0; |
class ThreadedTesterBase { |
protected: |
@@ -1882,15 +1913,65 @@ class OffHeapContainer : public GarbageCollectedFinalized<OffHeapContainer> { |
public: |
static OffHeapContainer* create() { return new OffHeapContainer(); } |
+ static const int iterations = 300; |
+ static const int deadWrappers = 2400; |
+ |
OffHeapContainer() |
{ |
- m_deque1.append(ShouldBeTraced(IntWrapper::create(1))); |
- m_vector1.append(ShouldBeTraced(IntWrapper::create(2))); |
- m_deque2.append(IntWrapper::create(3)); |
- m_vector2.append(IntWrapper::create(4)); |
- m_hashSet.add(IntWrapper::create(5)); |
- m_hashMap.add(this, IntWrapper::create(6)); |
- m_listHashSet.add(IntWrapper::create(7)); |
+ for (int i = 0; i < iterations; i++) { |
+ m_deque1.append(ShouldBeTraced(IntWrapper::create(i))); |
+ m_vector1.append(ShouldBeTraced(IntWrapper::create(i))); |
+ m_deque2.append(IntWrapper::create(i)); |
+ m_vector2.append(IntWrapper::create(i)); |
+ m_hashSet.add(IntWrapper::create(i)); |
+ m_hashMap.add(i + 103, IntWrapper::create(i)); |
+ m_listHashSet.add(IntWrapper::create(i)); |
+ m_linkedHashSet.add(IntWrapper::create(i)); |
+ } |
+ |
+ Deque<ShouldBeTraced>::iterator d1Iterator(m_deque1.begin()); |
+ Vector<ShouldBeTraced>::iterator v1Iterator(m_vector1.begin()); |
+ Deque<Member<IntWrapper> >::iterator d2Iterator(m_deque2.begin()); |
+ Vector<Member<IntWrapper> >::iterator v2Iterator(m_vector2.begin()); |
+ HashSet<Member<IntWrapper> >::iterator setIterator(m_hashSet.begin()); |
+ HashMap<int, Member<IntWrapper> >::iterator mapIterator(m_hashMap.begin()); |
+ ListHashSet<Member<IntWrapper> >::iterator listSetIterator(m_listHashSet.begin()); |
+ LinkedHashSet<Member<IntWrapper> >::iterator linkedSetIterator(m_linkedHashSet.begin()); |
+ |
+ for (int i = 0; i < iterations; i++) { |
+ EXPECT_EQ(i, m_vector1[i].m_wrapper->value()); |
+ EXPECT_EQ(i, m_vector2[i]->value()); |
+ EXPECT_EQ(i, d1Iterator->m_wrapper->value()); |
+ EXPECT_EQ(i, v1Iterator->m_wrapper->value()); |
+ EXPECT_EQ(i, d2Iterator->get()->value()); |
+ EXPECT_EQ(i, v2Iterator->get()->value()); |
+ EXPECT_EQ(i, linkedSetIterator->get()->value()); |
+ int value = setIterator->get()->value(); |
+ EXPECT_LE(0, value); |
+ EXPECT_GT(iterations, value); |
+ value = listSetIterator->get()->value(); |
+ EXPECT_LE(0, value); |
+ EXPECT_GT(iterations, value); |
+ value = mapIterator->value.get()->value(); |
+ EXPECT_LE(0, value); |
+ EXPECT_GT(iterations, value); |
+ ++d1Iterator; |
+ ++v1Iterator; |
+ ++d2Iterator; |
+ ++v2Iterator; |
+ ++setIterator; |
+ ++mapIterator; |
+ ++listSetIterator; |
+ ++linkedSetIterator; |
+ } |
+ EXPECT_EQ(d1Iterator, m_deque1.end()); |
+ EXPECT_EQ(v1Iterator, m_vector1.end()); |
+ EXPECT_EQ(d2Iterator, m_deque2.end()); |
+ EXPECT_EQ(v2Iterator, m_vector2.end()); |
+ EXPECT_EQ(setIterator, m_hashSet.end()); |
+ EXPECT_EQ(mapIterator, m_hashMap.end()); |
+ EXPECT_EQ(listSetIterator, m_listHashSet.end()); |
+ EXPECT_EQ(linkedSetIterator, m_linkedHashSet.end()); |
} |
void trace(Visitor* visitor) |
@@ -1902,6 +1983,7 @@ public: |
visitor->trace(m_hashSet); |
visitor->trace(m_hashMap); |
visitor->trace(m_listHashSet); |
+ visitor->trace(m_linkedHashSet); |
} |
Deque<ShouldBeTraced> m_deque1; |
@@ -1909,11 +1991,11 @@ public: |
Deque<Member<IntWrapper> > m_deque2; |
Vector<Member<IntWrapper> > m_vector2; |
HashSet<Member<IntWrapper> > m_hashSet; |
- HashMap<void*, Member<IntWrapper> > m_hashMap; |
+ HashMap<int, Member<IntWrapper> > m_hashMap; |
ListHashSet<Member<IntWrapper> > m_listHashSet; |
+ LinkedHashSet<Member<IntWrapper> > m_linkedHashSet; |
}; |
- |
// These class definitions test compile-time asserts with transition |
// types. They are therefore unused in test code and just need to |
// compile. This is intentional; do not delete the A and B classes below. |
@@ -2277,6 +2359,126 @@ TEST(HeapTest, HeapWeakCollectionSimple) |
EXPECT_EQ(2u, weakSet->size()); |
} |
+template<typename Set> |
+void linkedSetHelper(bool strong) |
+{ |
+ HeapStats initialHeapStats; |
+ clearOutOldGarbage(&initialHeapStats); |
+ IntWrapper::s_destructorCalls = 0; |
+ |
+ typedef const Set& ConstSet; |
Mads Ager (chromium)
2014/04/03 09:24:35
Remove the typedef for a type you are using only o
Erik Corry
2014/04/10 10:47:37
Done.
|
+ |
+ PersistentHeapVector<Member<IntWrapper> > keepNumbersAlive; |
+ |
+ Persistent<Set> set = new Set(); |
+ Persistent<Set> setX = new Set(); |
Mads Ager (chromium)
2014/04/03 09:24:35
What does the X mean? If it is just a random other
Erik Corry
2014/04/10 10:47:37
Done.
|
+ |
+ ConstSet cSet = *set.get(); |
Mads Ager (chromium)
2014/04/03 09:24:35
cSet -> constSetReference
Erik Corry
2014/04/10 10:47:37
constSet
|
+ |
+ keepNumbersAlive.append(IntWrapper::create(2)); |
+ keepNumbersAlive.append(IntWrapper::create(103)); |
+ keepNumbersAlive.append(IntWrapper::create(10)); |
+ |
+ set->add(IntWrapper::create(0)); |
+ set->add(keepNumbersAlive[0]); |
+ set->add(keepNumbersAlive[1]); |
+ set->add(keepNumbersAlive[2]); |
+ |
+ setX->clear(); |
+ setX->add(IntWrapper::create(42)); |
+ setX->clear(); |
+ |
+ EXPECT_EQ(4u, set->size()); |
+ typename Set::iterator it(set->begin()); |
+ typename Set::reverse_iterator reverse(set->rbegin()); |
+ typename Set::const_iterator cit(cSet.begin()); |
+ typename Set::const_reverse_iterator creverse(cSet.rbegin()); |
+ |
+ EXPECT_EQ(0, (*it)->value()); |
+ EXPECT_EQ(0, (*cit)->value()); |
+ ++it; |
+ ++cit; |
+ EXPECT_EQ(2, (*it)->value()); |
+ EXPECT_EQ(2, (*cit)->value()); |
+ --it; |
+ --cit; |
+ EXPECT_EQ(0, (*it)->value()); |
+ EXPECT_EQ(0, (*cit)->value()); |
+ ++it; |
+ ++cit; |
+ ++it; |
+ ++cit; |
+ EXPECT_EQ(103, (*it)->value()); |
+ EXPECT_EQ(103, (*cit)->value()); |
+ ++it; |
+ ++cit; |
+ EXPECT_EQ(10, (*it)->value()); |
+ EXPECT_EQ(10, (*cit)->value()); |
+ ++it; |
+ ++cit; |
+ |
+ EXPECT_EQ(10, (*reverse)->value()); |
+ EXPECT_EQ(10, (*creverse)->value()); |
+ ++reverse; |
+ ++creverse; |
+ EXPECT_EQ(103, (*reverse)->value()); |
+ EXPECT_EQ(103, (*creverse)->value()); |
+ --reverse; |
+ --creverse; |
+ EXPECT_EQ(10, (*reverse)->value()); |
+ EXPECT_EQ(10, (*creverse)->value()); |
+ ++reverse; |
+ ++creverse; |
+ ++reverse; |
+ ++creverse; |
+ EXPECT_EQ(2, (*reverse)->value()); |
+ EXPECT_EQ(2, (*creverse)->value()); |
+ ++reverse; |
+ ++creverse; |
+ EXPECT_EQ(0, (*reverse)->value()); |
+ EXPECT_EQ(0, (*creverse)->value()); |
+ ++reverse; |
+ ++creverse; |
+ |
+ EXPECT_EQ(set->end(), it); |
+ EXPECT_EQ(cSet.end(), cit); |
+ EXPECT_EQ(set->rend(), reverse); |
+ EXPECT_EQ(cSet.rend(), creverse); |
+ |
+ typename Set::iterator iX(setX->begin()); |
+ EXPECT_EQ(setX->end(), iX); |
+ |
+ if (strong) |
+ set->remove(keepNumbersAlive[0]); |
+ |
+ keepNumbersAlive[0] = nullptr; |
+ |
+ Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); |
+ |
+ EXPECT_EQ(2u + (strong ? 1u : 0u), set->size()); |
+ |
+ EXPECT_EQ(2 + (strong ? 0 : 1), IntWrapper::s_destructorCalls); |
+ |
+ typename Set::iterator i2(set->begin()); |
+ if (strong) { |
+ EXPECT_EQ(0, (*i2)->value()); |
+ ++i2; |
+ EXPECT_NE(set->end(), i2); |
+ } |
+ EXPECT_EQ(103, (*i2)->value()); |
+ ++i2; |
+ EXPECT_NE(set->end(), i2); |
+ EXPECT_EQ(10, (*i2)->value()); |
+ ++i2; |
+ EXPECT_EQ(set->end(), i2); |
+} |
+ |
+TEST(HeapTest, HeapWeakLinkedHashSet) |
+{ |
+ linkedSetHelper<HeapLinkedHashSet<Member<IntWrapper> > >(true); |
+ linkedSetHelper<HeapLinkedHashSet<WeakMember<IntWrapper> > >(false); |
+} |
+ |
class ThingWithDestructor { |
public: |
ThingWithDestructor() |
@@ -2903,7 +3105,7 @@ TEST(HeapTest, VisitOffHeapCollections) |
EXPECT_EQ(0, IntWrapper::s_destructorCalls); |
container = nullptr; |
Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); |
- EXPECT_EQ(7, IntWrapper::s_destructorCalls); |
+ EXPECT_EQ(OffHeapContainer::deadWrappers, IntWrapper::s_destructorCalls); |
} |
TEST(HeapTest, PersistentHeapCollectionTypes) |