Merge from Chromium at DEPS revision 261286

This commit was generated by merge_to_master.py.

Change-Id: I756d37445fd7f470b1689ad81318e715d4244987
diff --git a/Source/heap/HeapTest.cpp b/Source/heap/HeapTest.cpp
index 005556e..f1bbe10 100644
--- a/Source/heap/HeapTest.cpp
+++ b/Source/heap/HeapTest.cpp
@@ -175,6 +175,13 @@
     static SimpleObject* create() { return new SimpleObject(); }
     void trace(Visitor*) { }
     char getPayload(int i) { return payload[i]; }
+    // This virtual method is unused but it is here to make sure
+    // that this object has a vtable. This object is used
+    // as the super class for objects that also have garbage
+    // collected mixins and having a virtual here makes sure
+    // that adjustment is needed both for marking and for isAlive
+    // checks.
+    virtual void virtualMethod() { }
 protected:
     SimpleObject() { }
     char payload[64];
@@ -708,6 +715,11 @@
         ++s_destructorCalls;
     }
 
+    // These are here with their default implementations so you can break in
+    // them in the debugger.
+    void ref() { RefCountedGarbageCollected<RefCountedAndGarbageCollected>::ref(); }
+    void deref() { RefCountedGarbageCollected<RefCountedAndGarbageCollected>::deref(); }
+
     void trace(Visitor*) { }
 
     static int s_destructorCalls;
@@ -1132,10 +1144,9 @@
 public:
     virtual void trace(Visitor* visitor) { }
 
-    char getPayload(int i) { return m_padding[i]; }
+    virtual char getPayload(int i) { return m_padding[i]; }
 
 protected:
-    // This is to force ptr diff for SimpleObject, Mixin, and UseMixin.
     int m_padding[8];
 };
 
@@ -2220,7 +2231,8 @@
 
 TEST(HeapTest, HeapWeakCollectionSimple)
 {
-
+    HeapStats initialHeapStats;
+    clearOutOldGarbage(&initialHeapStats);
     IntWrapper::s_destructorCalls = 0;
 
     PersistentHeapVector<Member<IntWrapper> > keepNumbersAlive;
@@ -2265,6 +2277,133 @@
     EXPECT_EQ(2u, weakSet->size());
 }
 
+class ThingWithDestructor {
+public:
+    ThingWithDestructor()
+        : m_x(emptyValue)
+    {
+        s_liveThingsWithDestructor++;
+    }
+
+    ThingWithDestructor(int x)
+        : m_x(x)
+    {
+        s_liveThingsWithDestructor++;
+    }
+
+    ThingWithDestructor(const ThingWithDestructor&other)
+    {
+        *this = other;
+        s_liveThingsWithDestructor++;
+    }
+
+    ~ThingWithDestructor()
+    {
+        s_liveThingsWithDestructor--;
+    }
+
+    int value() { return m_x; }
+
+    static int s_liveThingsWithDestructor;
+
+    unsigned hash() { return IntHash<int>::hash(m_x); }
+
+private:
+    static const int emptyValue = 0;
+    int m_x;
+};
+
+int ThingWithDestructor::s_liveThingsWithDestructor;
+
+struct ThingWithDestructorTraits : public HashTraits<ThingWithDestructor> {
+    static const bool needsDestruction = true;
+};
+
+static void heapMapDestructorHelper(bool clearMaps)
+{
+    HeapStats initialHeapStats;
+    clearOutOldGarbage(&initialHeapStats);
+    ThingWithDestructor::s_liveThingsWithDestructor = 0;
+
+    typedef HeapHashMap<WeakMember<IntWrapper>, RefPtr<RefCountedAndGarbageCollected> > RefMap;
+
+    typedef HeapHashMap<
+        WeakMember<IntWrapper>,
+        ThingWithDestructor,
+        DefaultHash<WeakMember<IntWrapper> >::Hash,
+        HashTraits<WeakMember<IntWrapper> >,
+        ThingWithDestructorTraits> Map;
+
+    Persistent<Map> map(new Map());
+    Persistent<RefMap> refMap(new RefMap());
+
+    Persistent<IntWrapper> luck(IntWrapper::create(103));
+
+    int baseLine, refBaseLine;
+
+    {
+        Map stackMap;
+        RefMap stackRefMap;
+
+        Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
+        Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
+
+        stackMap.add(IntWrapper::create(42), ThingWithDestructor(1729));
+        stackMap.add(luck, ThingWithDestructor(8128));
+        stackRefMap.add(IntWrapper::create(42), RefCountedAndGarbageCollected::create());
+        stackRefMap.add(luck, RefCountedAndGarbageCollected::create());
+
+        baseLine = ThingWithDestructor::s_liveThingsWithDestructor;
+        refBaseLine = RefCountedAndGarbageCollected::s_destructorCalls;
+
+        // Although the heap maps are on-stack, we can't expect prompt
+        // finalization of the elements, so when they go out of scope here we
+        // will not necessarily have called the relevant destructors.
+    }
+
+    // The RefCountedAndGarbageCollected things need an extra GC to discover
+    // that they are no longer ref counted.
+    Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
+    Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
+    EXPECT_EQ(baseLine - 2, ThingWithDestructor::s_liveThingsWithDestructor);
+    EXPECT_EQ(refBaseLine + 2, RefCountedAndGarbageCollected::s_destructorCalls);
+
+    // Now use maps kept alive with persistents. Here we don't expect any
+    // destructors to be called before there have been GCs.
+
+    map->add(IntWrapper::create(42), ThingWithDestructor(1729));
+    map->add(luck, ThingWithDestructor(8128));
+    refMap->add(IntWrapper::create(42), RefCountedAndGarbageCollected::create());
+    refMap->add(luck, RefCountedAndGarbageCollected::create());
+
+    baseLine  =  ThingWithDestructor::s_liveThingsWithDestructor;
+    refBaseLine = RefCountedAndGarbageCollected::s_destructorCalls;
+
+    luck.clear();
+    if (clearMaps) {
+        map->clear(); // Clear map.
+        refMap->clear(); // Clear map.
+    } else {
+        map.clear(); // Clear Persistent handle, not map.
+        refMap.clear(); // Clear Persistent handle, not map.
+        Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
+        Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
+    }
+
+    EXPECT_EQ(baseLine - 2, ThingWithDestructor::s_liveThingsWithDestructor);
+
+    // Need a GC to make sure that the RefCountedAndGarbageCollected thing
+    // noticies it's been decremented to zero.
+    Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
+    EXPECT_EQ(refBaseLine + 2, RefCountedAndGarbageCollected::s_destructorCalls);
+}
+
+TEST(HeapTest, HeapMapDestructor)
+{
+    heapMapDestructorHelper(true);
+    heapMapDestructorHelper(false);
+}
+
 typedef HeapHashSet<PairWeakStrong> WeakStrongSet;
 typedef HeapHashSet<PairWeakUnwrapped> WeakUnwrappedSet;
 typedef HeapHashSet<PairStrongWeak> StrongWeakSet;
@@ -2844,22 +2983,31 @@
     Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
     EXPECT_EQ(1u, map->get(key).size());
     EXPECT_EQ(0, IntWrapper::s_destructorCalls);
+
+    keepAlive = nullptr;
+    Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
+    EXPECT_EQ(1, IntWrapper::s_destructorCalls);
 }
 
-TEST(heap, GarbageCollectedMixin)
+TEST(HeapTest, GarbageCollectedMixin)
 {
     HeapStats initialHeapStats;
     clearOutOldGarbage(&initialHeapStats);
 
     Persistent<UseMixin> usemixin = UseMixin::create();
-    ASSERT_EQ(0, UseMixin::s_traceCount);
+    EXPECT_EQ(0, UseMixin::s_traceCount);
     Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
-    ASSERT_EQ(1, UseMixin::s_traceCount);
+    EXPECT_EQ(1, UseMixin::s_traceCount);
 
     Persistent<Mixin> mixin = usemixin;
     usemixin = nullptr;
     Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
-    ASSERT_EQ(2, UseMixin::s_traceCount);
+    EXPECT_EQ(2, UseMixin::s_traceCount);
+
+    PersistentHeapHashSet<WeakMember<Mixin> > weakMap;
+    weakMap.add(UseMixin::create());
+    Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
+    EXPECT_EQ(0u, weakMap.size());
 }
 
 TEST(HeapTest, CollectionNesting2)
@@ -3062,4 +3210,27 @@
     EXPECT_EQ(512, OneKiloByteObject::s_destructorCalls);
 }
 
+class SimpleClassWithDestructor {
+public:
+    SimpleClassWithDestructor() { }
+    ~SimpleClassWithDestructor()
+    {
+        ASSERT(!s_wasDestructed);
+        s_wasDestructed = true;
+    }
+    static bool s_wasDestructed;
+};
+
+bool SimpleClassWithDestructor::s_wasDestructed;
+
+TEST(HeapTest, DestructorsCalledOnMapClear)
+{
+    HeapHashMap<SimpleClassWithDestructor*, OwnPtr<SimpleClassWithDestructor> > map;
+    SimpleClassWithDestructor* hasDestructor = new SimpleClassWithDestructor();
+    map.add(hasDestructor, adoptPtr(hasDestructor));
+    SimpleClassWithDestructor::s_wasDestructed = false;
+    map.clear();
+    ASSERT(SimpleClassWithDestructor::s_wasDestructed);
+}
+
 } // WebCore namespace