Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / heap / HeapTest.cpp
index 1d31ad6..597c050 100644 (file)
@@ -284,10 +284,15 @@ private:
             {
                 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();
                 }
 
@@ -298,9 +303,11 @@ private:
                 }
 
                 EXPECT_EQ(wrapper->value(), 0x0bbac0de);
+                EXPECT_EQ((*globalPersistent)->value(), 0x0ed0cabb);
             }
             yield();
         }
+        ThreadState::current()->cleanup();
         ThreadState::detach();
         atomicDecrement(&m_threadsToFinish);
     }
@@ -605,9 +612,9 @@ int RefCountedAndGarbageCollected::s_destructorCalls = 0;
 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()
@@ -765,7 +772,7 @@ class SuperClass;
 class PointsBack : public RefCountedWillBeGarbageCollectedFinalized<PointsBack> {
     DECLARE_GC_INFO;
 public:
-    static PassRefPtrWillBePtr<PointsBack> create()
+    static PassRefPtrWillBeRawPtr<PointsBack> create()
     {
         return adoptRefWillBeNoop(new PointsBack());
     }
@@ -791,12 +798,12 @@ public:
 
     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;
@@ -804,7 +811,7 @@ 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));
     }
@@ -817,9 +824,9 @@ public:
         --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);
@@ -836,7 +843,7 @@ public:
 
     static int s_aliveCount;
 protected:
-    explicit SuperClass(PassRefPtrWillBePtr<PointsBack> pointsBack)
+    explicit SuperClass(PassRefPtrWillBeRawPtr<PointsBack> pointsBack)
         : m_pointsBack(pointsBack)
     {
         m_pointsBack->setBackPointer(this);
@@ -863,7 +870,7 @@ int SubData::s_aliveCount = 0;
 
 class SubClass : public SuperClass {
 public:
-    static PassRefPtrWillBePtr<SubClass> create(PassRefPtrWillBePtr<PointsBack> pointsBack)
+    static PassRefPtrWillBeRawPtr<SubClass> create(PassRefPtrWillBeRawPtr<PointsBack> pointsBack)
     {
         return adoptRefWillBeNoop(new SubClass(pointsBack));
     }
@@ -883,7 +890,7 @@ public:
 
     static int s_aliveCount;
 private:
-    explicit SubClass(PassRefPtrWillBePtr<PointsBack> pointsBack)
+    explicit SubClass(PassRefPtrWillBeRawPtr<PointsBack> pointsBack)
         : SuperClass(pointsBack)
         , m_data(adoptPtrWillBeNoop(new SubData()))
     {
@@ -896,8 +903,43 @@ private:
 
 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);
@@ -908,6 +950,7 @@ TEST(HeapTest, Transition)
     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);
@@ -1073,8 +1116,10 @@ TEST(HeapTest, BasicFunctionality)
     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++)
@@ -1218,6 +1263,7 @@ TEST(HeapTest, MarkTest)
             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);
@@ -1244,6 +1290,7 @@ TEST(HeapTest, DeepTest)
         }
         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);
@@ -1298,6 +1345,7 @@ TEST(HeapTest, HashMapOfMembers)
         IntWrapper* one(IntWrapper::create(1));
         IntWrapper* anotherOne(IntWrapper::create(1));
         map->add(one, one);
+
         HeapStats afterOneAdd;
         getHeapStats(&afterOneAdd);
         EXPECT_TRUE(afterOneAdd.totalObjectSpace() > afterGC.totalObjectSpace());
@@ -1309,6 +1357,15 @@ TEST(HeapTest, HashMapOfMembers)
 
         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);
@@ -1321,7 +1378,7 @@ TEST(HeapTest, HashMapOfMembers)
 
         HeapStats afterGC2;
         getHeapStats(&afterGC2);
-        EXPECT_EQ(afterGC2.totalObjectSpace(), afterOneAdd.totalObjectSpace());
+        EXPECT_EQ(afterGC2.totalObjectSpace(), afterAddAndGC.totalObjectSpace());
 
         IntWrapper* dozen = 0;
 
@@ -1415,6 +1472,571 @@ TEST(HeapTest, LargeObjects)
     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;
@@ -1452,10 +2074,10 @@ TEST(HeapTest, RefCountedGarbageCollectedWithStackPointers)
     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() };
@@ -1465,9 +2087,11 @@ TEST(HeapTest, RefCountedGarbageCollectedWithStackPointers)
 
             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.
@@ -1478,7 +2102,7 @@ TEST(HeapTest, RefCountedGarbageCollectedWithStackPointers)
 
         {
             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);
@@ -1486,14 +2110,17 @@ TEST(HeapTest, RefCountedGarbageCollectedWithStackPointers)
 
             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)
@@ -1606,14 +2233,85 @@ TEST(HeapTest, CheckAndMarkPointer)
     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);
@@ -1623,5 +2321,6 @@ DEFINE_GC_INFO(SuperClass);
 DEFINE_GC_INFO(SubData);
 DEFINE_GC_INFO(TestTypedHeapClass);
 DEFINE_GC_INFO(TraceCounter);
+DEFINE_GC_INFO(TransitionRefCounted);
 
 } // namespace