Index: Source/platform/heap/HeapTest.cpp |
diff --git a/Source/platform/heap/HeapTest.cpp b/Source/platform/heap/HeapTest.cpp |
index accbbd36e779ced2264453c44e33dcaf93551e9e..3b7caf75b1caf44d46f1ba508734a5aa5b1b7cb6 100644 |
--- a/Source/platform/heap/HeapTest.cpp |
+++ b/Source/platform/heap/HeapTest.cpp |
@@ -5050,24 +5050,35 @@ class ClassWithGarbageCollectingMixinConstructor |
, public MixinWithGarbageCollectionInConstructor { |
USING_GARBAGE_COLLECTED_MIXIN(ClassWithGarbageCollectingMixinConstructor); |
public: |
- ClassWithGarbageCollectingMixinConstructor() : m_wrapper(IntWrapper::create(32)) |
+ static int s_traceCalled; |
+ |
+ ClassWithGarbageCollectingMixinConstructor() |
+ : m_traceCounter(TraceCounter::create()) |
+ , m_wrapper(IntWrapper::create(32)) |
{ |
} |
DEFINE_INLINE_VIRTUAL_TRACE() |
{ |
+ s_traceCalled++; |
+ visitor->trace(m_traceCounter); |
visitor->trace(m_wrapper); |
} |
void verify() |
{ |
EXPECT_EQ(32, m_wrapper->value()); |
+ EXPECT_EQ(0, m_traceCounter->traceCount()); |
+ EXPECT_EQ(0, s_traceCalled); |
} |
private: |
+ Member<TraceCounter> m_traceCounter; |
Member<IntWrapper> m_wrapper; |
}; |
+int ClassWithGarbageCollectingMixinConstructor::s_traceCalled = 0; |
+ |
// Regression test for out of bounds call through vtable. |
// Passes if it doesn't crash. |
TEST(HeapTest, GarbageCollectionDuringMixinConstruction) |
@@ -5568,4 +5579,106 @@ TEST(HeapTest, StackGrowthDirection) |
EXPECT_EQ(GrowsTowardsLower, stackGrowthDirection()); |
} |
+class TestMixinAllocationA : public GarbageCollected<TestMixinAllocationA>, public GarbageCollectedMixin { |
+ USING_GARBAGE_COLLECTED_MIXIN(TestMixinAllocationA); |
+public: |
+ TestMixinAllocationA() |
+ { |
+ // Completely wrong in general, but test only |
+ // runs this constructor while constructing another mixin. |
+ ASSERT(ThreadState::current()->isGCForbidden()); |
+ } |
+ |
+ DEFINE_INLINE_VIRTUAL_TRACE() { } |
+}; |
+ |
+class TestMixinAllocationB : public TestMixinAllocationA { |
+ USING_GARBAGE_COLLECTED_MIXIN_NESTED(TestMixinAllocationB, TestMixinAllocationA); |
+public: |
+ TestMixinAllocationB() |
+ { |
+ // Completely wrong in general, but test only |
+ // runs this constructor while constructing another mixin. |
+ ASSERT(ThreadState::current()->isGCForbidden()); |
+ } |
+ |
+ DEFINE_INLINE_TRACE() { TestMixinAllocationA::trace(visitor); } |
+}; |
+ |
+class TestMixinAllocationC final : public TestMixinAllocationB { |
+ USING_GARBAGE_COLLECTED_MIXIN_NESTED(TestMixinAllocationC, TestMixinAllocationB); |
+public: |
+ TestMixinAllocationC() |
+ { |
+ ASSERT(!ThreadState::current()->isGCForbidden()); |
+ } |
+ |
+ DEFINE_INLINE_TRACE() { TestMixinAllocationB::trace(visitor); } |
+}; |
+ |
+TEST(HeapTest, NestedMixinConstruction) |
+{ |
+ TestMixinAllocationC* object = new TestMixinAllocationC(); |
+ EXPECT_TRUE(object); |
+} |
+ |
+class ObjectWithLargeAmountsOfAllocationInConstructor { |
+public: |
+ ObjectWithLargeAmountsOfAllocationInConstructor(size_t numberOfLargeObjectsToAllocate, ClassWithMember* member) |
+ { |
+ // Should a constructor allocate plenty in its constructor, |
+ // and it is a base of GC mixin, GCs will remain locked out |
+ // regardless, as we cannot safely trace the leftmost GC |
+ // mixin base. |
+ ASSERT(ThreadState::current()->isGCForbidden()); |
+ for (size_t i = 0; i < numberOfLargeObjectsToAllocate; i++) { |
+ LargeHeapObject* largeObject = LargeHeapObject::create(); |
+ EXPECT_TRUE(largeObject); |
+ EXPECT_EQ(0, member->traceCount()); |
+ } |
+ } |
+}; |
+ |
+class TestMixinAllocatingObject final : public TestMixinAllocationB, public ObjectWithLargeAmountsOfAllocationInConstructor { |
+ USING_GARBAGE_COLLECTED_MIXIN_NESTED(TestMixinAllocatingObject, TestMixinAllocationB); |
+public: |
+ static TestMixinAllocatingObject* create(ClassWithMember* member) |
+ { |
+ return new TestMixinAllocatingObject(member); |
+ } |
+ |
+ DEFINE_INLINE_TRACE() |
+ { |
+ visitor->trace(m_traceCounter); |
+ TestMixinAllocationB::trace(visitor); |
+ } |
+ |
+ int traceCount() const { return m_traceCounter->traceCount(); } |
+ |
+private: |
+ TestMixinAllocatingObject(ClassWithMember* member) |
+ : ObjectWithLargeAmountsOfAllocationInConstructor(600, member) |
+ , m_traceCounter(TraceCounter::create()) |
+ { |
+ ASSERT(!ThreadState::current()->isGCForbidden()); |
+ // The large object allocation should trigger a GC.. |
+ LargeHeapObject* largeObject = LargeHeapObject::create(); |
+ EXPECT_TRUE(largeObject); |
+ EXPECT_GT(member->traceCount(), 0); |
+ EXPECT_GT(traceCount(), 0); |
+ } |
+ |
+ Member<TraceCounter> m_traceCounter; |
+}; |
+ |
+TEST(HeapTest, MixinConstructionNoGC) |
+{ |
+ Persistent<ClassWithMember> object = ClassWithMember::create(); |
+ EXPECT_EQ(0, object->traceCount()); |
+ TestMixinAllocatingObject* mixin = TestMixinAllocatingObject::create(object.get()); |
+ EXPECT_TRUE(mixin); |
+ EXPECT_GT(object->traceCount(), 0); |
+ EXPECT_GT(mixin->traceCount(), 0); |
+} |
+ |
} // namespace blink |