| Index: Source/platform/heap/HeapTest.cpp
|
| diff --git a/Source/platform/heap/HeapTest.cpp b/Source/platform/heap/HeapTest.cpp
|
| index 6c7f071a9fb7bab7a3fbc34f9f1ed2b223d3277d..c2485b4c76f8b8f6392ce1a6e91efa528b5b0130 100644
|
| --- a/Source/platform/heap/HeapTest.cpp
|
| +++ b/Source/platform/heap/HeapTest.cpp
|
| @@ -549,6 +549,109 @@ private:
|
| }
|
| };
|
|
|
| +class ThreadPersistentHeapTester : public ThreadedTesterBase {
|
| +public:
|
| + static void test()
|
| + {
|
| + ThreadedTesterBase::test(new ThreadPersistentHeapTester);
|
| + }
|
| +
|
| +protected:
|
| + class Local final : public GarbageCollected<Local> {
|
| + public:
|
| + Local() { }
|
| +
|
| + void trace(Visitor* visitor) { }
|
| + };
|
| +
|
| + class BookEnd;
|
| +
|
| + class PersistentStore {
|
| + public:
|
| + static PersistentStore* create(int count, int* gcCount, BookEnd* bookend)
|
| + {
|
| + return new PersistentStore(count, gcCount, bookend);
|
| + }
|
| +
|
| + void advance()
|
| + {
|
| + (*m_gcCount)++;
|
| + m_store.removeLast();
|
| + // Remove reference to BookEnd when there are no Persistent<Local>s left.
|
| + // The BookEnd object will then be swept out at the next GC, and pre-finalized,
|
| + // causing this PersistentStore instance to be destructed, along with
|
| + // the Persistent<BookEnd>. It being the very last Persistent<>, causing the
|
| + // GC loop in ThreadState::detach() to terminate.
|
| + if (!m_store.size())
|
| + m_bookend = nullptr;
|
| + }
|
| +
|
| + private:
|
| + PersistentStore(int count, int* gcCount, BookEnd* bookend)
|
| + {
|
| + m_gcCount = gcCount;
|
| + m_bookend = bookend;
|
| + for (int i = 0; i < count; ++i)
|
| + m_store.append(Persistent<ThreadPersistentHeapTester::Local>(new ThreadPersistentHeapTester::Local()));
|
| + }
|
| +
|
| + Vector<Persistent<Local>> m_store;
|
| + Persistent<BookEnd> m_bookend;
|
| + int* m_gcCount;
|
| + };
|
| +
|
| + class BookEnd final : public GarbageCollected<BookEnd> {
|
| + USING_PRE_FINALIZER(BookEnd, dispose);
|
| + public:
|
| + BookEnd()
|
| + : m_store(nullptr)
|
| + {
|
| + ThreadState::current()->registerPreFinalizer(*this);
|
| + }
|
| +
|
| + void initialize(PersistentStore* store)
|
| + {
|
| + m_store = store;
|
| + }
|
| +
|
| + void dispose()
|
| + {
|
| + delete m_store;
|
| + }
|
| +
|
| + void trace(Visitor* visitor)
|
| + {
|
| + ASSERT(m_store);
|
| + m_store->advance();
|
| + }
|
| +
|
| + private:
|
| + PersistentStore* m_store;
|
| + };
|
| +
|
| + virtual void runThread() override
|
| + {
|
| + ThreadState::attach();
|
| +
|
| + const int iterations = 5;
|
| + int gcCount = 0;
|
| + BookEnd* bookend = new BookEnd();
|
| + PersistentStore* store = PersistentStore::create(iterations, &gcCount, bookend);
|
| + bookend->initialize(store);
|
| +
|
| + bookend = nullptr;
|
| + store = nullptr;
|
| +
|
| + // Upon thread detach, GCs will run until all persistents have been
|
| + // released. We verify that the draining of persistents proceeds
|
| + // as expected by dropping one Persistent<> per GC until there
|
| + // are none left.
|
| + ThreadState::detach();
|
| + EXPECT_EQ(iterations, gcCount);
|
| + atomicDecrement(&m_threadsToFinish);
|
| + }
|
| +};
|
| +
|
| // The accounting for memory includes the memory used by rounding up object
|
| // sizes. This is done in a different way on 32 bit and 64 bit, so we have to
|
| // have some slack in the tests.
|
| @@ -1518,6 +1621,11 @@ TEST(HeapTest, ThreadedWeakness)
|
| ThreadedWeaknessTester::test();
|
| }
|
|
|
| +TEST(HeapTest, ThreadPersistent)
|
| +{
|
| + ThreadPersistentHeapTester::test();
|
| +}
|
| +
|
| TEST(HeapTest, BasicFunctionality)
|
| {
|
| clearOutOldGarbage();
|
|
|