{
IntWrapper* wrapper;
+ typedef Persistent<IntWrapper, GlobalPersistents> GlobalIntWrapperPersistent;
+ OwnPtr<GlobalIntWrapperPersistent> globalPersistent = adoptPtr(new GlobalIntWrapperPersistent(IntWrapper::create(0x0ed0cabb)));
+
for (int i = 0; i < numberOfAllocations; i++) {
wrapper = IntWrapper::create(0x0bbac0de);
- if (!(i % 10))
+ if (!(i % 10)) {
+ globalPersistent = adoptPtr(new GlobalIntWrapperPersistent(IntWrapper::create(0x0ed0cabb)));
ThreadState::current()->safePoint(ThreadState::HeapPointersOnStack);
+ }
yield();
}
}
EXPECT_EQ(wrapper->value(), 0x0bbac0de);
+ EXPECT_EQ((*globalPersistent)->value(), 0x0ed0cabb);
}
yield();
}
+ ThreadState::current()->cleanup();
ThreadState::detach();
atomicDecrement(&m_threadsToFinish);
}
class RefCountedAndGarbageCollected2 : public HeapTestOtherSuperClass, public RefCountedGarbageCollected<RefCountedAndGarbageCollected2> {
DECLARE_GC_INFO
public:
- static PassRefPtr<RefCountedAndGarbageCollected2> create()
+ static RefCountedAndGarbageCollected2* create()
{
- return adoptRef(new RefCountedAndGarbageCollected2());
+ return adoptRefCountedGarbageCollected(new RefCountedAndGarbageCollected2());
}
~RefCountedAndGarbageCollected2()
class PointsBack : public RefCountedWillBeGarbageCollectedFinalized<PointsBack> {
DECLARE_GC_INFO;
public:
- static PassRefPtrWillBePtr<PointsBack> create()
+ static PassRefPtrWillBeRawPtr<PointsBack> create()
{
return adoptRefWillBeNoop(new PointsBack());
}
static int s_aliveCount;
private:
- PointsBack() : m_backPointer(nullptr)
+ PointsBack() : m_backPointer(0)
{
++s_aliveCount;
}
- PtrWillBeWeakMember<SuperClass> m_backPointer;
+ RawPtrWillBeWeakMember<SuperClass> m_backPointer;
};
int PointsBack::s_aliveCount = 0;
class SuperClass : public RefCountedWillBeGarbageCollectedFinalized<SuperClass> {
DECLARE_GC_INFO;
public:
- static PassRefPtrWillBePtr<SuperClass> create(PassRefPtrWillBePtr<PointsBack> pointsBack)
+ static PassRefPtrWillBeRawPtr<SuperClass> create(PassRefPtrWillBeRawPtr<PointsBack> pointsBack)
{
return adoptRefWillBeNoop(new SuperClass(pointsBack));
}
--s_aliveCount;
}
- void doStuff(PassRefPtrWillBePtr<SuperClass> targetPass, PointsBack* pointsBack, int superClassCount)
+ void doStuff(PassRefPtrWillBeRawPtr<SuperClass> targetPass, PointsBack* pointsBack, int superClassCount)
{
- RefPtrWillBePtr<SuperClass> target = targetPass;
+ RefPtrWillBeRawPtr<SuperClass> target = targetPass;
Heap::collectGarbage(ThreadState::HeapPointersOnStack);
EXPECT_EQ(pointsBack, target->pointsBack());
EXPECT_EQ(superClassCount, SuperClass::s_aliveCount);
static int s_aliveCount;
protected:
- explicit SuperClass(PassRefPtrWillBePtr<PointsBack> pointsBack)
+ explicit SuperClass(PassRefPtrWillBeRawPtr<PointsBack> pointsBack)
: m_pointsBack(pointsBack)
{
m_pointsBack->setBackPointer(this);
class SubClass : public SuperClass {
public:
- static PassRefPtrWillBePtr<SubClass> create(PassRefPtrWillBePtr<PointsBack> pointsBack)
+ static PassRefPtrWillBeRawPtr<SubClass> create(PassRefPtrWillBeRawPtr<PointsBack> pointsBack)
{
return adoptRefWillBeNoop(new SubClass(pointsBack));
}
static int s_aliveCount;
private:
- explicit SubClass(PassRefPtrWillBePtr<PointsBack> pointsBack)
+ explicit SubClass(PassRefPtrWillBeRawPtr<PointsBack> pointsBack)
: SuperClass(pointsBack)
, m_data(adoptPtrWillBeNoop(new SubData()))
{
int SubClass::s_aliveCount = 0;
+class TransitionRefCounted : public RefCountedWillBeRefCountedGarbageCollected<TransitionRefCounted> {
+ DECLARE_GC_INFO
+public:
+ static PassRefPtrWillBeRawPtr<TransitionRefCounted> create()
+ {
+ return adoptRefCountedWillBeRefCountedGarbageCollected(new TransitionRefCounted());
+ }
+
+ ~TransitionRefCounted()
+ {
+ --s_aliveCount;
+ }
+
+ void trace(Visitor* visitor) { }
+
+ static int s_aliveCount;
+
+private:
+ TransitionRefCounted()
+ {
+ ++s_aliveCount;
+ }
+};
+
+int TransitionRefCounted::s_aliveCount = 0;
+
TEST(HeapTest, Transition)
{
+ {
+ RefPtr<TransitionRefCounted> refCounted = TransitionRefCounted::create();
+ EXPECT_EQ(1, TransitionRefCounted::s_aliveCount);
+ Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
+ EXPECT_EQ(1, TransitionRefCounted::s_aliveCount);
+ }
+ Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
+ EXPECT_EQ(0, TransitionRefCounted::s_aliveCount);
+
RefPtrWillBePersistent<PointsBack> pointsBack1 = PointsBack::create();
RefPtrWillBePersistent<PointsBack> pointsBack2 = PointsBack::create();
RefPtrWillBePersistent<SuperClass> superClass = SuperClass::create(pointsBack1);
EXPECT_EQ(1, SubData::s_aliveCount);
Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
+ EXPECT_EQ(0, TransitionRefCounted::s_aliveCount);
EXPECT_EQ(2, PointsBack::s_aliveCount);
EXPECT_EQ(2, SuperClass::s_aliveCount);
EXPECT_EQ(1, SubClass::s_aliveCount);
if (testPagesAllocated)
EXPECT_EQ(0ul, heapStats.totalAllocatedSpace() & (blinkPageSize - 1));
- for (size_t i = 0; i < persistentCount; i++)
- persistents[i]->release();
+ for (size_t i = 0; i < persistentCount; i++) {
+ delete persistents[i];
+ persistents[i] = 0;
+ }
uint8_t* address = Heap::reallocate<uint8_t>(0, 100);
for (int i = 0; i < 100; i++)
EXPECT_EQ(2u, Bar::s_live);
EXPECT_TRUE(reinterpret_cast<Address>(foo) != reinterpret_cast<Address>(bar.get()));
Heap::collectGarbage(ThreadState::HeapPointersOnStack);
+ EXPECT_TRUE(foo != bar); // To make sure foo is kept alive.
EXPECT_EQ(2u, Bar::s_live);
}
Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
}
EXPECT_EQ(depth + 2, Bar::s_live);
Heap::collectGarbage(ThreadState::HeapPointersOnStack);
+ EXPECT_TRUE(foo != bar); // To make sure foo and bar are kept alive.
EXPECT_EQ(depth + 2, Bar::s_live);
}
Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
IntWrapper* one(IntWrapper::create(1));
IntWrapper* anotherOne(IntWrapper::create(1));
map->add(one, one);
+
HeapStats afterOneAdd;
getHeapStats(&afterOneAdd);
EXPECT_TRUE(afterOneAdd.totalObjectSpace() > afterGC.totalObjectSpace());
map->add(anotherOne, one);
+ // the addition above can cause an allocation of a new
+ // backing store. We therefore garbage collect before
+ // taking the heap stats in order to get rid of the old
+ // backing store.
+ Heap::collectGarbage(ThreadState::HeapPointersOnStack);
+ HeapStats afterAddAndGC;
+ getHeapStats(&afterAddAndGC);
+ EXPECT_TRUE(afterAddAndGC.totalObjectSpace() >= afterOneAdd.totalObjectSpace());
+
EXPECT_EQ(map->size(), 2u); // Two different wrappings of '1' are distinct.
Heap::collectGarbage(ThreadState::HeapPointersOnStack);
HeapStats afterGC2;
getHeapStats(&afterGC2);
- EXPECT_EQ(afterGC2.totalObjectSpace(), afterOneAdd.totalObjectSpace());
+ EXPECT_EQ(afterGC2.totalObjectSpace(), afterAddAndGC.totalObjectSpace());
IntWrapper* dozen = 0;
Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
}
+class Container : public GarbageCollected<Container> {
+ DECLARE_GC_INFO
+public:
+ static Container* create() { return new Container(); }
+ HeapHashMap<Member<IntWrapper>, Member<IntWrapper> > map;
+ HeapHashSet<Member<IntWrapper> > set;
+ HeapHashSet<Member<IntWrapper> > set2;
+ HeapVector<Member<IntWrapper>, 2> vector;
+ void trace(Visitor* visitor)
+ {
+ visitor->trace(map);
+ visitor->trace(set);
+ visitor->trace(set2);
+ visitor->trace(vector);
+ }
+};
+
+struct ShouldBeTraced {
+ explicit ShouldBeTraced(IntWrapper* wrapper) : m_wrapper(wrapper) { }
+ void trace(Visitor* visitor) { visitor->trace(m_wrapper); }
+ Member<IntWrapper> m_wrapper;
+};
+
+class OffHeapContainer : public GarbageCollectedFinalized<OffHeapContainer> {
+ DECLARE_GC_INFO
+public:
+ static OffHeapContainer* create() { return new OffHeapContainer(); }
+
+ 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));
+ }
+
+ void trace(Visitor* visitor)
+ {
+ visitor->trace(m_deque1);
+ visitor->trace(m_vector1);
+ visitor->trace(m_deque2);
+ visitor->trace(m_vector2);
+ visitor->trace(m_hashSet);
+ visitor->trace(m_hashMap);
+ visitor->trace(m_listHashSet);
+ }
+
+ Deque<ShouldBeTraced> m_deque1;
+ Vector<ShouldBeTraced> m_vector1;
+ Deque<Member<IntWrapper> > m_deque2;
+ Vector<Member<IntWrapper> > m_vector2;
+ HashSet<Member<IntWrapper> > m_hashSet;
+ HashMap<void*, Member<IntWrapper> > m_hashMap;
+ ListHashSet<Member<IntWrapper> > m_listHashSet;
+};
+
+TEST(HeapTest, HeapVectorWithInlineCapacity)
+{
+ IntWrapper* one = IntWrapper::create(1);
+ IntWrapper* two = IntWrapper::create(2);
+ IntWrapper* three = IntWrapper::create(3);
+ IntWrapper* four = IntWrapper::create(4);
+ IntWrapper* five = IntWrapper::create(5);
+ IntWrapper* six = IntWrapper::create(6);
+ {
+ HeapVector<Member<IntWrapper>, 2> vector;
+ vector.append(one);
+ vector.append(two);
+ Heap::collectGarbage(ThreadState::HeapPointersOnStack);
+ EXPECT_TRUE(vector.contains(one));
+ EXPECT_TRUE(vector.contains(two));
+
+ vector.append(three);
+ vector.append(four);
+ Heap::collectGarbage(ThreadState::HeapPointersOnStack);
+ EXPECT_TRUE(vector.contains(one));
+ EXPECT_TRUE(vector.contains(two));
+ EXPECT_TRUE(vector.contains(three));
+ EXPECT_TRUE(vector.contains(four));
+
+ vector.shrink(1);
+ Heap::collectGarbage(ThreadState::HeapPointersOnStack);
+ EXPECT_TRUE(vector.contains(one));
+ EXPECT_FALSE(vector.contains(two));
+ EXPECT_FALSE(vector.contains(three));
+ EXPECT_FALSE(vector.contains(four));
+ }
+ {
+ HeapVector<Member<IntWrapper>, 2> vector1;
+ HeapVector<Member<IntWrapper>, 2> vector2;
+
+ vector1.append(one);
+ vector2.append(two);
+ vector1.swap(vector2);
+ Heap::collectGarbage(ThreadState::HeapPointersOnStack);
+ EXPECT_TRUE(vector1.contains(two));
+ EXPECT_TRUE(vector2.contains(one));
+ }
+ {
+ HeapVector<Member<IntWrapper>, 2> vector1;
+ HeapVector<Member<IntWrapper>, 2> vector2;
+
+ vector1.append(one);
+ vector1.append(two);
+ vector2.append(three);
+ vector2.append(four);
+ vector2.append(five);
+ vector2.append(six);
+ vector1.swap(vector2);
+ Heap::collectGarbage(ThreadState::HeapPointersOnStack);
+ EXPECT_TRUE(vector1.contains(three));
+ EXPECT_TRUE(vector1.contains(four));
+ EXPECT_TRUE(vector1.contains(five));
+ EXPECT_TRUE(vector1.contains(six));
+ EXPECT_TRUE(vector2.contains(one));
+ EXPECT_TRUE(vector2.contains(two));
+ }
+}
+
+TEST(HeapTest, HeapCollectionTypes)
+{
+ HeapStats initialHeapSize;
+ IntWrapper::s_destructorCalls = 0;
+
+ typedef HeapHashMap<Member<IntWrapper>, Member<IntWrapper> > MemberMember;
+ typedef HeapHashMap<Member<IntWrapper>, int> MemberPrimitive;
+ typedef HeapHashMap<int, Member<IntWrapper> > PrimitiveMember;
+
+ typedef HeapHashSet<Member<IntWrapper> > MemberSet;
+ typedef HeapHashSet<WeakMember<IntWrapper> > WeakMemberSet;
+
+ typedef HeapVector<Member<IntWrapper>, 2> MemberVector;
+
+ Persistent<MemberMember> memberMember = new MemberMember();
+ Persistent<MemberMember> memberMember2 = new MemberMember();
+ Persistent<MemberMember> memberMember3 = new MemberMember();
+ Persistent<MemberPrimitive> memberPrimitive = new MemberPrimitive();
+ Persistent<PrimitiveMember> primitiveMember = new PrimitiveMember();
+ Persistent<MemberSet> set = new MemberSet();
+ Persistent<MemberSet> set2 = new MemberSet();
+ Persistent<MemberVector> vector = new MemberVector();
+ Persistent<MemberVector> vector2 = new MemberVector();
+ Persistent<Container> container = Container::create();
+
+ clearOutOldGarbage(&initialHeapSize);
+ {
+ Persistent<IntWrapper> one(IntWrapper::create(1));
+ Persistent<IntWrapper> two(IntWrapper::create(2));
+ Persistent<IntWrapper> oneB(IntWrapper::create(1));
+ Persistent<IntWrapper> twoB(IntWrapper::create(2));
+ Persistent<IntWrapper> oneC(IntWrapper::create(1));
+ Persistent<IntWrapper> twoC(IntWrapper::create(2));
+ {
+ IntWrapper* three(IntWrapper::create(3));
+ IntWrapper* four(IntWrapper::create(4));
+ IntWrapper* threeB(IntWrapper::create(3));
+ IntWrapper* fourB(IntWrapper::create(4));
+
+ // Member Collections.
+ memberMember2->add(one, two);
+ memberMember2->add(two, three);
+ memberMember2->add(three, four);
+ memberMember2->add(four, one);
+ primitiveMember->add(1, two);
+ primitiveMember->add(2, three);
+ primitiveMember->add(3, four);
+ primitiveMember->add(4, one);
+ memberPrimitive->add(one, 2);
+ memberPrimitive->add(two, 3);
+ memberPrimitive->add(three, 4);
+ memberPrimitive->add(four, 1);
+ set2->add(one);
+ set2->add(two);
+ set2->add(three);
+ set2->add(four);
+ set->add(oneB);
+ vector->append(oneB);
+ vector2->append(threeB);
+ vector2->append(fourB);
+
+ // Collect garbage. This should change nothing since we are keeping
+ // alive the IntWrapper objects with on-stack pointers.
+ Heap::collectGarbage(ThreadState::HeapPointersOnStack);
+ EXPECT_EQ(0u, memberMember->size());
+ EXPECT_EQ(4u, memberMember2->size());
+ EXPECT_EQ(4u, primitiveMember->size());
+ EXPECT_EQ(4u, memberPrimitive->size());
+ EXPECT_EQ(1u, set->size());
+ EXPECT_EQ(4u, set2->size());
+ EXPECT_EQ(1u, vector->size());
+ EXPECT_EQ(2u, vector2->size());
+
+ MemberVector& cvec = container->vector;
+ cvec.swap(*vector.get());
+ vector2->swap(cvec);
+ vector->swap(cvec);
+
+ // Swap set and set2 in a roundabout way.
+ MemberSet& cset1 = container->set;
+ MemberSet& cset2 = container->set2;
+ set->swap(cset1);
+ set2->swap(cset2);
+ set->swap(cset2);
+ cset1.swap(cset2);
+ cset2.swap(set2);
+
+ // Triple swap.
+ container->map.swap(memberMember2);
+ MemberMember& containedMap = container->map;
+ memberMember3->swap(containedMap);
+ memberMember3->swap(memberMember);
+
+ EXPECT_TRUE(memberMember->get(one) == two);
+ EXPECT_TRUE(memberMember->get(two) == three);
+ EXPECT_TRUE(memberMember->get(three) == four);
+ EXPECT_TRUE(memberMember->get(four) == one);
+ EXPECT_TRUE(primitiveMember->get(1) == two);
+ EXPECT_TRUE(primitiveMember->get(2) == three);
+ EXPECT_TRUE(primitiveMember->get(3) == four);
+ EXPECT_TRUE(primitiveMember->get(4) == one);
+ EXPECT_EQ(1, memberPrimitive->get(four));
+ EXPECT_EQ(2, memberPrimitive->get(one));
+ EXPECT_EQ(3, memberPrimitive->get(two));
+ EXPECT_EQ(4, memberPrimitive->get(three));
+ EXPECT_TRUE(set->contains(one));
+ EXPECT_TRUE(set->contains(two));
+ EXPECT_TRUE(set->contains(three));
+ EXPECT_TRUE(set->contains(four));
+ EXPECT_TRUE(set2->contains(oneB));
+ EXPECT_TRUE(vector->contains(threeB));
+ EXPECT_TRUE(vector->contains(fourB));
+ EXPECT_TRUE(vector2->contains(oneB));
+ EXPECT_FALSE(vector2->contains(threeB));
+ }
+
+ Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
+
+ EXPECT_EQ(4u, memberMember->size());
+ EXPECT_EQ(0u, memberMember2->size());
+ EXPECT_EQ(4u, primitiveMember->size());
+ EXPECT_EQ(4u, memberPrimitive->size());
+ EXPECT_EQ(4u, set->size());
+ EXPECT_EQ(1u, set2->size());
+ EXPECT_EQ(2u, vector->size());
+ EXPECT_EQ(1u, vector2->size());
+
+ EXPECT_TRUE(memberMember->get(one) == two);
+ EXPECT_TRUE(primitiveMember->get(1) == two);
+ EXPECT_TRUE(primitiveMember->get(4) == one);
+ EXPECT_EQ(2, memberPrimitive->get(one));
+ EXPECT_EQ(3, memberPrimitive->get(two));
+ EXPECT_TRUE(set->contains(one));
+ EXPECT_TRUE(set->contains(two));
+ EXPECT_FALSE(set->contains(oneB));
+ EXPECT_TRUE(set2->contains(oneB));
+ EXPECT_EQ(3, vector->at(0)->value());
+ EXPECT_EQ(4, vector->at(1)->value());
+ }
+
+ Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
+ Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
+
+ EXPECT_EQ(4u, memberMember->size());
+ EXPECT_EQ(4u, primitiveMember->size());
+ EXPECT_EQ(4u, memberPrimitive->size());
+ EXPECT_EQ(4u, set->size());
+ EXPECT_EQ(1u, set2->size());
+ EXPECT_EQ(2u, vector->size());
+ EXPECT_EQ(1u, vector2->size());
+ EXPECT_EQ(2u, vector->size());
+ EXPECT_EQ(1u, vector2->size());
+}
+
+template<typename T>
+void MapIteratorCheck(T& it, const T& end, int expected)
+{
+ int found = 0;
+ while (it != end) {
+ found++;
+ int key = it->key->value();
+ int value = it->value->value();
+ EXPECT_TRUE(key >= 0 && key < 1100);
+ EXPECT_TRUE(value >= 0 && value < 1100);
+ ++it;
+ }
+ EXPECT_EQ(expected, found);
+}
+
+template<typename T>
+void SetIteratorCheck(T& it, const T& end, int expected)
+{
+ int found = 0;
+ while (it != end) {
+ found++;
+ int value = (*it)->value();
+ EXPECT_TRUE(value >= 0 && value < 1100);
+ ++it;
+ }
+ EXPECT_EQ(expected, found);
+}
+
+TEST(HeapTest, CollectionPersistent)
+{
+ HeapStats empty;
+ clearOutOldGarbage(&empty);
+ IntWrapper::s_destructorCalls = 0;
+
+ CollectionPersistent<Vector<Member<IntWrapper> > > vector;
+ CollectionPersistent<HashSet<Member<IntWrapper> > > set;
+ CollectionPersistent<HashMap<Member<IntWrapper>, Member<IntWrapper> > > map;
+ CollectionPersistent<ListHashSet<Member<IntWrapper> > > listSet;
+
+ vector->append(IntWrapper::create(42));
+ set->add(IntWrapper::create(103));
+ map->add(IntWrapper::create(137), IntWrapper::create(139));
+ listSet->add(IntWrapper::create(167));
+ listSet->add(IntWrapper::create(671));
+ listSet->add(IntWrapper::create(176));
+
+ EXPECT_EQ(0, IntWrapper::s_destructorCalls);
+
+ Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
+
+ EXPECT_EQ(0, IntWrapper::s_destructorCalls);
+
+ typedef HashSet<Member<IntWrapper> >::iterator SetIterator;
+ typedef HashMap<Member<IntWrapper>, Member<IntWrapper> >::iterator MapIterator;
+ typedef ListHashSet<Member<IntWrapper> >::iterator ListSetIterator;
+
+ SetIterator setIterator = set->begin();
+ MapIterator mapIterator = map->begin();
+ ListSetIterator listSetIterator = listSet->begin();
+
+ EXPECT_EQ(42, vector[0]->value());
+ EXPECT_EQ(103, (*setIterator)->value());
+ EXPECT_EQ(137, mapIterator->key->value());
+ EXPECT_EQ(139, mapIterator->value->value());
+ EXPECT_EQ(167, (*listSetIterator)->value());
+}
+
+TEST(HeapTest, HeapWeakCollectionSimple)
+{
+
+ IntWrapper::s_destructorCalls = 0;
+
+ CollectionPersistent<Vector<Member<IntWrapper> > > keepNumbersAlive;
+
+ typedef HeapHashMap<WeakMember<IntWrapper>, Member<IntWrapper> > WeakStrong;
+ typedef HeapHashMap<Member<IntWrapper>, WeakMember<IntWrapper> > StrongWeak;
+ typedef HeapHashMap<WeakMember<IntWrapper>, WeakMember<IntWrapper> > WeakWeak;
+ typedef HeapHashSet<WeakMember<IntWrapper> > WeakSet;
+
+ Persistent<WeakStrong> weakStrong = new WeakStrong();
+ Persistent<StrongWeak> strongWeak = new StrongWeak();
+ Persistent<WeakWeak> weakWeak = new WeakWeak();
+ Persistent<WeakSet> weakSet = new WeakSet();
+
+ Persistent<IntWrapper> two = IntWrapper::create(2);
+
+ keepNumbersAlive->append(IntWrapper::create(103));
+ keepNumbersAlive->append(IntWrapper::create(10));
+
+ {
+ weakStrong->add(IntWrapper::create(1), two);
+ strongWeak->add(two, IntWrapper::create(1));
+ weakWeak->add(two, IntWrapper::create(42));
+ weakWeak->add(IntWrapper::create(42), two);
+ weakSet->add(IntWrapper::create(0));
+ weakSet->add(two);
+ weakSet->add(keepNumbersAlive[0]);
+ weakSet->add(keepNumbersAlive[1]);
+ EXPECT_EQ(1u, weakStrong->size());
+ EXPECT_EQ(1u, strongWeak->size());
+ EXPECT_EQ(2u, weakWeak->size());
+ EXPECT_EQ(4u, weakSet->size());
+ }
+
+ keepNumbersAlive[0] = 0;
+
+ Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
+
+ EXPECT_EQ(0u, weakStrong->size());
+ EXPECT_EQ(0u, strongWeak->size());
+ EXPECT_EQ(0u, weakWeak->size());
+ EXPECT_EQ(2u, weakSet->size());
+}
+
+TEST(HeapTest, HeapWeakCollectionTypes)
+{
+ HeapStats initialHeapSize;
+ IntWrapper::s_destructorCalls = 0;
+
+ typedef HeapHashMap<WeakMember<IntWrapper>, Member<IntWrapper> > WeakStrong;
+ typedef HeapHashMap<Member<IntWrapper>, WeakMember<IntWrapper> > StrongWeak;
+ typedef HeapHashMap<WeakMember<IntWrapper>, WeakMember<IntWrapper> > WeakWeak;
+ typedef HeapHashSet<WeakMember<IntWrapper> > WeakSet;
+
+ clearOutOldGarbage(&initialHeapSize);
+
+ const int weakStrongIndex = 0;
+ const int strongWeakIndex = 1;
+ const int weakWeakIndex = 2;
+ const int numberOfMapIndices = 3;
+ const int weakSetIndex = 3;
+ const int numberOfCollections = 4;
+
+ for (int testRun = 0; testRun < 4; testRun++) {
+ for (int collectionNumber = 0; collectionNumber < numberOfCollections; collectionNumber++) {
+ bool testThatIteratorsMakeStrong = (testRun == weakSetIndex);
+ bool deleteAfterwards = (testRun == 1);
+ bool addAfterwards = (testRun == weakWeakIndex);
+
+ // The test doesn't work for strongWeak with deleting because we lost
+ // the key from the keepNumbersAlive array, so we can't do the lookup.
+ if (deleteAfterwards && collectionNumber == strongWeakIndex)
+ continue;
+
+ unsigned added = addAfterwards ? 100 : 0;
+
+ Persistent<WeakStrong> weakStrong = new WeakStrong();
+ Persistent<StrongWeak> strongWeak = new StrongWeak();
+ Persistent<WeakWeak> weakWeak = new WeakWeak();
+
+ Persistent<WeakSet> weakSet = new WeakSet();
+
+ CollectionPersistent<Vector<Member<IntWrapper> > > keepNumbersAlive;
+ for (int i = 0; i < 128; i += 2) {
+ IntWrapper* wrapped = IntWrapper::create(i);
+ IntWrapper* wrapped2 = IntWrapper::create(i + 1);
+ keepNumbersAlive->append(wrapped);
+ keepNumbersAlive->append(wrapped2);
+ weakStrong->add(wrapped, wrapped2);
+ strongWeak->add(wrapped2, wrapped);
+ weakWeak->add(wrapped, wrapped2);
+ weakSet->add(wrapped);
+ }
+
+ EXPECT_EQ(64u, weakStrong->size());
+ EXPECT_EQ(64u, strongWeak->size());
+ EXPECT_EQ(64u, weakWeak->size());
+ EXPECT_EQ(64u, weakSet->size());
+
+ // Collect garbage. This should change nothing since we are keeping
+ // alive the IntWrapper objects.
+ Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
+
+ EXPECT_EQ(64u, weakStrong->size());
+ EXPECT_EQ(64u, strongWeak->size());
+ EXPECT_EQ(64u, weakWeak->size());
+ EXPECT_EQ(64u, weakSet->size());
+
+ for (int i = 0; i < 128; i += 2) {
+ IntWrapper* wrapped = keepNumbersAlive[i];
+ IntWrapper* wrapped2 = keepNumbersAlive[i + 1];
+ EXPECT_EQ(wrapped2, weakStrong->get(wrapped));
+ EXPECT_EQ(wrapped, strongWeak->get(wrapped2));
+ EXPECT_EQ(wrapped2, weakWeak->get(wrapped));
+ EXPECT_TRUE(weakSet->contains(wrapped));
+ }
+
+ for (int i = 0; i < 128; i += 3)
+ keepNumbersAlive[i] = 0;
+
+ if (collectionNumber != weakStrongIndex)
+ weakStrong->clear();
+ if (collectionNumber != strongWeakIndex)
+ strongWeak->clear();
+ if (collectionNumber != weakWeakIndex)
+ weakWeak->clear();
+ if (collectionNumber != weakSetIndex)
+ weakSet->clear();
+
+ if (testThatIteratorsMakeStrong) {
+ WeakStrong::iterator it1 = weakStrong->begin();
+ StrongWeak::iterator it2 = strongWeak->begin();
+ WeakWeak::iterator it3 = weakWeak->begin();
+ WeakSet::iterator it4 = weakSet->begin();
+ // Collect garbage. This should change nothing since the
+ // iterators make the collections strong.
+ Heap::collectGarbage(ThreadState::HeapPointersOnStack);
+ if (collectionNumber == weakStrongIndex) {
+ EXPECT_EQ(64u, weakStrong->size());
+ MapIteratorCheck(it1, weakStrong->end(), 64);
+ } else if (collectionNumber == strongWeakIndex) {
+ EXPECT_EQ(64u, strongWeak->size());
+ MapIteratorCheck(it2, strongWeak->end(), 64);
+ } else if (collectionNumber == weakWeakIndex) {
+ EXPECT_EQ(64u, weakWeak->size());
+ MapIteratorCheck(it3, weakWeak->end(), 64);
+ } else if (collectionNumber == weakSetIndex) {
+ EXPECT_EQ(64u, weakSet->size());
+ SetIteratorCheck(it4, weakSet->end(), 64);
+ }
+ } else {
+ // Collect garbage. This causes weak processing to remove
+ // things from the collections.
+ Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
+ unsigned count = 0;
+ for (int i = 0; i < 128; i += 2) {
+ bool firstAlive = keepNumbersAlive[i];
+ bool secondAlive = keepNumbersAlive[i + 1];
+ if (firstAlive && (collectionNumber == weakStrongIndex || collectionNumber == strongWeakIndex))
+ secondAlive = true;
+ if (firstAlive && secondAlive && collectionNumber < numberOfMapIndices) {
+ if (collectionNumber == weakStrongIndex) {
+ if (deleteAfterwards)
+ EXPECT_EQ(i + 1, weakStrong->take(keepNumbersAlive[i])->value());
+ } else if (collectionNumber == strongWeakIndex) {
+ if (deleteAfterwards)
+ EXPECT_EQ(i, strongWeak->take(keepNumbersAlive[i + 1])->value());
+ } else if (collectionNumber == weakWeakIndex) {
+ if (deleteAfterwards)
+ EXPECT_EQ(i + 1, weakWeak->take(keepNumbersAlive[i])->value());
+ }
+ if (!deleteAfterwards)
+ count++;
+ } else if (collectionNumber == weakSetIndex && firstAlive) {
+ ASSERT_TRUE(weakSet->contains(keepNumbersAlive[i]));
+ if (deleteAfterwards)
+ weakSet->remove(keepNumbersAlive[i]);
+ else
+ count++;
+ }
+ }
+ if (addAfterwards) {
+ for (int i = 1000; i < 1100; i++) {
+ IntWrapper* wrapped = IntWrapper::create(i);
+ keepNumbersAlive->append(wrapped);
+ weakStrong->add(wrapped, wrapped);
+ strongWeak->add(wrapped, wrapped);
+ weakWeak->add(wrapped, wrapped);
+ weakSet->add(wrapped);
+ }
+ }
+ if (collectionNumber == weakStrongIndex)
+ EXPECT_EQ(count + added, weakStrong->size());
+ else if (collectionNumber == strongWeakIndex)
+ EXPECT_EQ(count + added, strongWeak->size());
+ else if (collectionNumber == weakWeakIndex)
+ EXPECT_EQ(count + added, weakWeak->size());
+ else if (collectionNumber == weakSetIndex)
+ EXPECT_EQ(count + added, weakSet->size());
+ WeakStrong::iterator it1 = weakStrong->begin();
+ StrongWeak::iterator it2 = strongWeak->begin();
+ WeakWeak::iterator it3 = weakWeak->begin();
+ WeakSet::iterator it4 = weakSet->begin();
+ MapIteratorCheck(it1, weakStrong->end(), (collectionNumber == weakStrongIndex ? count : 0) + added);
+ MapIteratorCheck(it2, strongWeak->end(), (collectionNumber == strongWeakIndex ? count : 0) + added);
+ MapIteratorCheck(it3, weakWeak->end(), (collectionNumber == weakWeakIndex ? count : 0) + added);
+ SetIteratorCheck(it4, weakSet->end(), (collectionNumber == weakSetIndex ? count : 0) + added);
+ }
+ for (unsigned i = 0; i < 128 + added; i++)
+ keepNumbersAlive[i] = 0;
+ Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
+ EXPECT_EQ(added, weakStrong->size());
+ EXPECT_EQ(added, strongWeak->size());
+ EXPECT_EQ(added, weakWeak->size());
+ EXPECT_EQ(added, weakSet->size());
+ }
+ }
+}
+
TEST(HeapTest, RefCountedGarbageCollected)
{
RefCountedAndGarbageCollected::s_destructorCalls = 0;
RefCountedAndGarbageCollected2::s_destructorCalls = 0;
{
RefCountedAndGarbageCollected* pointer1 = 0;
- RefCountedAndGarbageCollected* pointer2 = 0;
+ RefCountedAndGarbageCollected2* pointer2 = 0;
{
RefPtr<RefCountedAndGarbageCollected> object1 = RefCountedAndGarbageCollected::create();
- RefPtr<RefCountedAndGarbageCollected> object2 = RefCountedAndGarbageCollected::create();
+ RefPtr<RefCountedAndGarbageCollected2> object2 = RefCountedAndGarbageCollected2::create();
pointer1 = object1.get();
pointer2 = object2.get();
void* objects[2] = { object1.get(), object2.get() };
Heap::collectGarbage(ThreadState::HeapPointersOnStack);
EXPECT_EQ(0, RefCountedAndGarbageCollected::s_destructorCalls);
+ EXPECT_EQ(0, RefCountedAndGarbageCollected2::s_destructorCalls);
}
Heap::collectGarbage(ThreadState::HeapPointersOnStack);
EXPECT_EQ(0, RefCountedAndGarbageCollected::s_destructorCalls);
+ EXPECT_EQ(0, RefCountedAndGarbageCollected2::s_destructorCalls);
// At this point, the reference counts of object1 and object2 are 0.
// Only pointer1 and pointer2 keep references to object1 and object2.
{
RefPtr<RefCountedAndGarbageCollected> object1(pointer1);
- RefPtr<RefCountedAndGarbageCollected> object2(pointer2);
+ RefPtr<RefCountedAndGarbageCollected2> object2(pointer2);
void* objects[2] = { object1.get(), object2.get() };
RefCountedGarbageCollectedVisitor visitor(2, objects);
ThreadState::current()->visitPersistents(&visitor);
Heap::collectGarbage(ThreadState::HeapPointersOnStack);
EXPECT_EQ(0, RefCountedAndGarbageCollected::s_destructorCalls);
+ EXPECT_EQ(0, RefCountedAndGarbageCollected2::s_destructorCalls);
}
Heap::collectGarbage(ThreadState::HeapPointersOnStack);
EXPECT_EQ(0, RefCountedAndGarbageCollected::s_destructorCalls);
+ EXPECT_EQ(0, RefCountedAndGarbageCollected2::s_destructorCalls);
}
Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
- EXPECT_EQ(2, RefCountedAndGarbageCollected::s_destructorCalls);
+ EXPECT_EQ(1, RefCountedAndGarbageCollected::s_destructorCalls);
+ EXPECT_EQ(1, RefCountedAndGarbageCollected2::s_destructorCalls);
}
TEST(HeapTest, WeakMembers)
clearOutOldGarbage(&initialHeapStats);
}
+TEST(HeapTest, VisitOffHeapCollections)
+{
+ HeapStats initialHeapStats;
+ clearOutOldGarbage(&initialHeapStats);
+ IntWrapper::s_destructorCalls = 0;
+ Persistent<OffHeapContainer> container = OffHeapContainer::create();
+ Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
+ EXPECT_EQ(0, IntWrapper::s_destructorCalls);
+ container = 0;
+ Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
+ EXPECT_EQ(7, IntWrapper::s_destructorCalls);
+}
+
+TEST(HeapTest, PersistentHeapCollectionTypes)
+{
+ HeapStats initialHeapSize;
+ IntWrapper::s_destructorCalls = 0;
+
+ typedef HeapVector<Member<IntWrapper> > Vec;
+ typedef PersistentHeapVector<Member<IntWrapper> > PVec;
+ typedef PersistentHeapHashSet<Member<IntWrapper> > PSet;
+ typedef PersistentHeapHashMap<Member<IntWrapper>, Member<IntWrapper> > PMap;
+
+ clearOutOldGarbage(&initialHeapSize);
+ {
+ PVec pVec;
+ PSet pSet;
+ PMap pMap;
+
+ IntWrapper* one(IntWrapper::create(1));
+ IntWrapper* two(IntWrapper::create(2));
+ IntWrapper* three(IntWrapper::create(3));
+ IntWrapper* four(IntWrapper::create(4));
+ IntWrapper* five(IntWrapper::create(5));
+ IntWrapper* six(IntWrapper::create(6));
+
+ pVec.append(one);
+ pVec.append(two);
+
+ Vec* vec = new Vec();
+ vec->swap(pVec);
+
+ pVec.append(two);
+ pVec.append(three);
+
+ pSet.add(four);
+ pMap.add(five, six);
+
+ // Collect |vec| and |one|.
+ vec = 0;
+ Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
+ EXPECT_EQ(1, IntWrapper::s_destructorCalls);
+
+ EXPECT_EQ(2u, pVec.size());
+ EXPECT_TRUE(pVec.at(0) == two);
+ EXPECT_TRUE(pVec.at(1) == three);
+
+ EXPECT_EQ(1u, pSet.size());
+ EXPECT_TRUE(pSet.contains(four));
+
+ EXPECT_EQ(1u, pMap.size());
+ EXPECT_TRUE(pMap.get(five) == six);
+ }
+
+ // Collect previous roots.
+ Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
+ EXPECT_EQ(6, IntWrapper::s_destructorCalls);
+}
+
DEFINE_GC_INFO(Bar);
DEFINE_GC_INFO(Baz);
DEFINE_GC_INFO(ClassWithMember);
DEFINE_GC_INFO(ConstructorAllocation);
+DEFINE_GC_INFO(Container);
DEFINE_GC_INFO(HeapAllocatedArray);
DEFINE_GC_INFO(HeapTestSuperClass);
DEFINE_GC_INFO(IntWrapper);
DEFINE_GC_INFO(LargeObject);
+DEFINE_GC_INFO(OffHeapContainer);
DEFINE_GC_INFO(PointsBack);
DEFINE_GC_INFO(RefCountedAndGarbageCollected);
DEFINE_GC_INFO(RefCountedAndGarbageCollected2);
DEFINE_GC_INFO(SubData);
DEFINE_GC_INFO(TestTypedHeapClass);
DEFINE_GC_INFO(TraceCounter);
+DEFINE_GC_INFO(TransitionRefCounted);
} // namespace