Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(91)

Unified Diff: Source/platform/heap/HeapTest.cpp

Issue 1086413003: Oilpan: HeapVectorBacking should call destructors for its elements (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: rebased past r194046 (upto r194085.) Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/platform/heap/Heap.h ('k') | Source/wtf/Deque.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/platform/heap/HeapTest.cpp
diff --git a/Source/platform/heap/HeapTest.cpp b/Source/platform/heap/HeapTest.cpp
index f15079494805380de6832ec0e87d57e2800f39a6..242d4453c63930d4cbeec3a53a8b93913f55df36 100644
--- a/Source/platform/heap/HeapTest.cpp
+++ b/Source/platform/heap/HeapTest.cpp
@@ -3887,6 +3887,104 @@ TEST(HeapTest, EmbeddedInDeque)
EXPECT_EQ(8, SimpleFinalizedObject::s_destructorCalls);
}
+class InlinedVectorObject {
+ ALLOW_ONLY_INLINE_ALLOCATION();
+public:
+ InlinedVectorObject()
+ {
+ }
+ ~InlinedVectorObject()
+ {
+ s_destructorCalls++;
+ }
+ DEFINE_INLINE_TRACE()
+ {
+ }
+
+ static int s_destructorCalls;
+};
+
+int InlinedVectorObject::s_destructorCalls = 0;
+
+} // namespace blink
+
+WTF_ALLOW_MOVE_AND_INIT_WITH_MEM_FUNCTIONS(blink::InlinedVectorObject);
+
+namespace blink {
+
+class InlinedVectorObjectWrapper final : public GarbageCollectedFinalized<InlinedVectorObjectWrapper> {
+public:
+ InlinedVectorObjectWrapper()
+ {
+ InlinedVectorObject i1, i2;
+ m_vector1.append(i1);
+ m_vector1.append(i2);
+ m_vector2.append(i1);
+ m_vector2.append(i2); // This allocates an out-of-line buffer.
+ m_vector3.append(i1);
+ m_vector3.append(i2);
+ }
+
+ DEFINE_INLINE_TRACE()
+ {
+ visitor->trace(m_vector1);
+ visitor->trace(m_vector2);
+ visitor->trace(m_vector3);
+ }
+
+private:
+ HeapVector<InlinedVectorObject> m_vector1;
+ HeapVector<InlinedVectorObject, 1> m_vector2;
+ HeapVector<InlinedVectorObject, 2> m_vector3;
+};
+
+TEST(HeapTest, VectorDestructors)
+{
+ clearOutOldGarbage();
+ InlinedVectorObject::s_destructorCalls = 0;
+ {
+ HeapVector<InlinedVectorObject> vector;
+ InlinedVectorObject i1, i2;
+ vector.append(i1);
+ vector.append(i2);
+ }
+ Heap::collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::GCWithSweep, Heap::ForcedGC);
+ // This is not EXPECT_EQ but EXPECT_LE because a HeapVectorBacking calls
+ // destructors for all elements in (not the size but) the capacity of
+ // the vector. Thus the number of destructors called becomes larger
+ // than the actual number of objects in the vector.
+ EXPECT_LE(4, InlinedVectorObject::s_destructorCalls);
+
+ InlinedVectorObject::s_destructorCalls = 0;
+ {
+ HeapVector<InlinedVectorObject, 1> vector;
+ InlinedVectorObject i1, i2;
+ vector.append(i1);
+ vector.append(i2); // This allocates an out-of-line buffer.
+ }
+ Heap::collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::GCWithSweep, Heap::ForcedGC);
+ EXPECT_LE(4, InlinedVectorObject::s_destructorCalls);
+
+ InlinedVectorObject::s_destructorCalls = 0;
+ {
+ HeapVector<InlinedVectorObject, 2> vector;
+ InlinedVectorObject i1, i2;
+ vector.append(i1);
+ vector.append(i2);
+ }
+ Heap::collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::GCWithSweep, Heap::ForcedGC);
+ EXPECT_LE(4, InlinedVectorObject::s_destructorCalls);
+
+ InlinedVectorObject::s_destructorCalls = 0;
+ {
+ new InlinedVectorObjectWrapper();
+ Heap::collectGarbage(ThreadState::HeapPointersOnStack, ThreadState::GCWithSweep, Heap::ForcedGC);
+ EXPECT_EQ(2, InlinedVectorObject::s_destructorCalls);
+ }
+ Heap::collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::GCWithSweep, Heap::ForcedGC);
+ EXPECT_LE(8, InlinedVectorObject::s_destructorCalls);
+}
+
template<typename Set>
void rawPtrInHashHelper()
{
@@ -5555,6 +5653,140 @@ TEST(HeapTest, DequeExpand)
}
}
+class SimpleRefValue : public RefCounted<SimpleRefValue> {
+public:
+ static PassRefPtr<SimpleRefValue> create(int i)
+ {
+ return adoptRef(new SimpleRefValue(i));
+ }
+
+ int value() const { return m_value; }
+private:
+ explicit SimpleRefValue(int value)
+ : m_value(value)
+ {
+ }
+
+ int m_value;
+};
+
+class PartObjectWithRef {
+ ALLOW_ONLY_INLINE_ALLOCATION();
+public:
+ PartObjectWithRef(int i)
+ : m_value(SimpleRefValue::create(i))
+ {
+ }
+
+ int value() const { return m_value->value(); }
+
+private:
+ RefPtr<SimpleRefValue> m_value;
+};
+
+} // namespace blink
+
+WTF_ALLOW_INIT_WITH_MEM_FUNCTIONS(blink::PartObjectWithRef);
+
+namespace blink {
+
+TEST(HeapTest, DequePartObjectsExpand)
+{
+ // Test expansion of HeapDeque<PartObject>
+
+ using PartDeque = HeapDeque<PartObjectWithRef>;
+
+ Persistent<PartDeque> deque = new PartDeque();
+ // Auxillary Deque used to prevent 'inline' buffer expansion.
+ Persistent<PartDeque> dequeUnused = new PartDeque();
+
+ // Append a sequence, bringing about repeated expansions of the
+ // deque's buffer.
+ int i = 0;
+ for (; i < 60; ++i) {
+ deque->append(PartObjectWithRef(i));
+ dequeUnused->append(PartObjectWithRef(i));
+ }
+
+ EXPECT_EQ(60u, deque->size());
+ i = 0;
+ for (const PartObjectWithRef& part : *deque) {
+ EXPECT_EQ(i, part.value());
+ i++;
+ }
+
+ // Remove most of the queued objects and have the buffer's start index
+ // 'point' somewhere into the buffer, just behind the end index.
+ for (i = 0; i < 50; ++i)
+ deque->takeFirst();
+
+ EXPECT_EQ(10u, deque->size());
+ i = 0;
+ for (const PartObjectWithRef& part : *deque) {
+ EXPECT_EQ(50 + i, part.value());
+ i++;
+ }
+
+ // Append even more, eventually causing an expansion of the underlying
+ // buffer once the end index wraps around and reaches the start index.
+ for (i = 0; i < 70; ++i)
+ deque->append(PartObjectWithRef(60 + i));
+
+ // Verify that the final buffer expansion copied the start and end segments
+ // of the old buffer to both ends of the expanded buffer, along with
+ // re-adjusting both start&end indices in terms of that expanded buffer.
+ EXPECT_EQ(80u, deque->size());
+ i = 0;
+ for (const PartObjectWithRef& part : *deque) {
+ EXPECT_EQ(i + 50, part.value());
+ i++;
+ }
+
+ for (i = 0; i < 70; ++i)
+ deque->append(PartObjectWithRef(130 + i));
+
+ EXPECT_EQ(150u, deque->size());
+ i = 0;
+ for (const PartObjectWithRef& part : *deque) {
+ EXPECT_EQ(i + 50, part.value());
+ i++;
+ }
+}
+
+TEST(HeapTest, HeapVectorPartObjects)
+{
+ HeapVector<PartObjectWithRef> vector1;
+ HeapVector<PartObjectWithRef> vector2;
+
+ for (int i = 0; i < 10; ++i) {
+ vector1.append(PartObjectWithRef(i));
+ vector2.append(PartObjectWithRef(i));
+ }
+
+ vector1.reserveCapacity(150);
+ EXPECT_EQ(150u, vector1.capacity());
+ EXPECT_EQ(10u, vector1.size());
+
+ vector2.reserveCapacity(100);
+ EXPECT_EQ(100u, vector2.capacity());
+ EXPECT_EQ(10u, vector2.size());
+
+ for (int i = 0; i < 4; ++i) {
+ vector1.append(PartObjectWithRef(10 + i));
+ vector2.append(PartObjectWithRef(10 + i));
+ vector2.append(PartObjectWithRef(10 + i));
+ }
+
+ // Shrinking heap vector backing stores always succeeds,
+ // so these two will not currently exercise the code path
+ // where shrinking causes copying into a new, small buffer.
+ vector2.shrinkToReasonableCapacity();
+ EXPECT_EQ(18u, vector2.size());
+
+ vector1.shrinkToReasonableCapacity();
+ EXPECT_EQ(14u, vector1.size());
+}
+
namespace {
enum GrowthDirection {
« no previous file with comments | « Source/platform/heap/Heap.h ('k') | Source/wtf/Deque.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698