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

Side by Side Diff: Source/platform/heap/HeapTest.cpp

Issue 393823003: Revert "Revert "[oilpan]: Make thread shutdown more robust."" (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 6 years, 5 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 unified diff | Download patch
« no previous file with comments | « Source/platform/heap/Heap.cpp ('k') | Source/platform/heap/ThreadState.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved. 2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 1679 matching lines...) Expand 10 before | Expand all | Expand 10 after
1690 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 1690 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1691 EXPECT_EQ(2, HeapTestSubClass::s_destructorCalls); 1691 EXPECT_EQ(2, HeapTestSubClass::s_destructorCalls);
1692 EXPECT_EQ(3, HeapTestSuperClass::s_destructorCalls); 1692 EXPECT_EQ(3, HeapTestSuperClass::s_destructorCalls);
1693 } 1693 }
1694 1694
1695 TEST(HeapTest, TypedHeapSanity) 1695 TEST(HeapTest, TypedHeapSanity)
1696 { 1696 {
1697 // We use TraceCounter for allocating an object on the general heap. 1697 // We use TraceCounter for allocating an object on the general heap.
1698 Persistent<TraceCounter> generalHeapObject = TraceCounter::create(); 1698 Persistent<TraceCounter> generalHeapObject = TraceCounter::create();
1699 Persistent<TestTypedHeapClass> typedHeapObject = TestTypedHeapClass::create( ); 1699 Persistent<TestTypedHeapClass> typedHeapObject = TestTypedHeapClass::create( );
1700 EXPECT_NE(pageHeaderAddress(reinterpret_cast<Address>(generalHeapObject.get( ))), 1700 EXPECT_NE(pageHeaderFromObject(generalHeapObject.get()),
1701 pageHeaderAddress(reinterpret_cast<Address>(typedHeapObject.get()))); 1701 pageHeaderFromObject(typedHeapObject.get()));
1702 } 1702 }
1703 1703
1704 TEST(HeapTest, NoAllocation) 1704 TEST(HeapTest, NoAllocation)
1705 { 1705 {
1706 EXPECT_TRUE(ThreadState::current()->isAllocationAllowed()); 1706 EXPECT_TRUE(ThreadState::current()->isAllocationAllowed());
1707 { 1707 {
1708 // Disallow allocation 1708 // Disallow allocation
1709 NoAllocationScope<AnyThread> noAllocationScope; 1709 NoAllocationScope<AnyThread> noAllocationScope;
1710 EXPECT_FALSE(ThreadState::current()->isAllocationAllowed()); 1710 EXPECT_FALSE(ThreadState::current()->isAllocationAllowed());
1711 } 1711 }
(...skipping 1710 matching lines...) Expand 10 before | Expand all | Expand 10 after
3422 { 3422 {
3423 HeapStats initialHeapSize; 3423 HeapStats initialHeapSize;
3424 IntWrapper::s_destructorCalls = 0; 3424 IntWrapper::s_destructorCalls = 0;
3425 3425
3426 typedef HeapVector<Member<IntWrapper> > Vec; 3426 typedef HeapVector<Member<IntWrapper> > Vec;
3427 typedef PersistentHeapVector<Member<IntWrapper> > PVec; 3427 typedef PersistentHeapVector<Member<IntWrapper> > PVec;
3428 typedef PersistentHeapHashSet<Member<IntWrapper> > PSet; 3428 typedef PersistentHeapHashSet<Member<IntWrapper> > PSet;
3429 typedef PersistentHeapListHashSet<Member<IntWrapper> > PListSet; 3429 typedef PersistentHeapListHashSet<Member<IntWrapper> > PListSet;
3430 typedef PersistentHeapLinkedHashSet<Member<IntWrapper> > PLinkedSet; 3430 typedef PersistentHeapLinkedHashSet<Member<IntWrapper> > PLinkedSet;
3431 typedef PersistentHeapHashMap<Member<IntWrapper>, Member<IntWrapper> > PMap; 3431 typedef PersistentHeapHashMap<Member<IntWrapper>, Member<IntWrapper> > PMap;
3432 typedef PersistentHeapHashMap<WeakMember<IntWrapper>, Member<IntWrapper> > W eakPMap;
3432 typedef PersistentHeapDeque<Member<IntWrapper> > PDeque; 3433 typedef PersistentHeapDeque<Member<IntWrapper> > PDeque;
3433 3434
3434 clearOutOldGarbage(&initialHeapSize); 3435 clearOutOldGarbage(&initialHeapSize);
3435 { 3436 {
3436 PVec pVec; 3437 PVec pVec;
3437 PDeque pDeque; 3438 PDeque pDeque;
3438 PSet pSet; 3439 PSet pSet;
3439 PListSet pListSet; 3440 PListSet pListSet;
3440 PLinkedSet pLinkedSet; 3441 PLinkedSet pLinkedSet;
3441 PMap pMap; 3442 PMap pMap;
3443 WeakPMap wpMap;
3442 3444
3443 IntWrapper* one(IntWrapper::create(1)); 3445 IntWrapper* one(IntWrapper::create(1));
3444 IntWrapper* two(IntWrapper::create(2)); 3446 IntWrapper* two(IntWrapper::create(2));
3445 IntWrapper* three(IntWrapper::create(3)); 3447 IntWrapper* three(IntWrapper::create(3));
3446 IntWrapper* four(IntWrapper::create(4)); 3448 IntWrapper* four(IntWrapper::create(4));
3447 IntWrapper* five(IntWrapper::create(5)); 3449 IntWrapper* five(IntWrapper::create(5));
3448 IntWrapper* six(IntWrapper::create(6)); 3450 IntWrapper* six(IntWrapper::create(6));
3449 IntWrapper* seven(IntWrapper::create(7)); 3451 IntWrapper* seven(IntWrapper::create(7));
3450 IntWrapper* eight(IntWrapper::create(8)); 3452 IntWrapper* eight(IntWrapper::create(8));
3451 IntWrapper* nine(IntWrapper::create(9)); 3453 IntWrapper* nine(IntWrapper::create(9));
3454 Persistent<IntWrapper> ten(IntWrapper::create(10));
3455 IntWrapper* eleven(IntWrapper::create(11));
3452 3456
3453 pVec.append(one); 3457 pVec.append(one);
3454 pVec.append(two); 3458 pVec.append(two);
3455 3459
3456 pDeque.append(seven); 3460 pDeque.append(seven);
3457 pDeque.append(two); 3461 pDeque.append(two);
3458 3462
3459 Vec* vec = new Vec(); 3463 Vec* vec = new Vec();
3460 vec->swap(pVec); 3464 vec->swap(pVec);
3461 3465
3462 pVec.append(two); 3466 pVec.append(two);
3463 pVec.append(three); 3467 pVec.append(three);
3464 3468
3465 pSet.add(four); 3469 pSet.add(four);
3466 pListSet.add(eight); 3470 pListSet.add(eight);
3467 pLinkedSet.add(nine); 3471 pLinkedSet.add(nine);
3468 pMap.add(five, six); 3472 pMap.add(five, six);
3473 wpMap.add(ten, eleven);
3469 3474
3470 // Collect |vec| and |one|. 3475 // Collect |vec| and |one|.
3471 vec = 0; 3476 vec = 0;
3472 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3477 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3473 EXPECT_EQ(1, IntWrapper::s_destructorCalls); 3478 EXPECT_EQ(1, IntWrapper::s_destructorCalls);
3474 3479
3475 EXPECT_EQ(2u, pVec.size()); 3480 EXPECT_EQ(2u, pVec.size());
3476 EXPECT_EQ(two, pVec.at(0)); 3481 EXPECT_EQ(two, pVec.at(0));
3477 EXPECT_EQ(three, pVec.at(1)); 3482 EXPECT_EQ(three, pVec.at(1));
3478 3483
3479 EXPECT_EQ(2u, pDeque.size()); 3484 EXPECT_EQ(2u, pDeque.size());
3480 EXPECT_EQ(seven, pDeque.first()); 3485 EXPECT_EQ(seven, pDeque.first());
3481 EXPECT_EQ(seven, pDeque.takeFirst()); 3486 EXPECT_EQ(seven, pDeque.takeFirst());
3482 EXPECT_EQ(two, pDeque.first()); 3487 EXPECT_EQ(two, pDeque.first());
3483 3488
3484 EXPECT_EQ(1u, pDeque.size()); 3489 EXPECT_EQ(1u, pDeque.size());
3485 3490
3486 EXPECT_EQ(1u, pSet.size()); 3491 EXPECT_EQ(1u, pSet.size());
3487 EXPECT_TRUE(pSet.contains(four)); 3492 EXPECT_TRUE(pSet.contains(four));
3488 3493
3489 EXPECT_EQ(1u, pListSet.size()); 3494 EXPECT_EQ(1u, pListSet.size());
3490 EXPECT_TRUE(pListSet.contains(eight)); 3495 EXPECT_TRUE(pListSet.contains(eight));
3491 3496
3492 EXPECT_EQ(1u, pLinkedSet.size()); 3497 EXPECT_EQ(1u, pLinkedSet.size());
3493 EXPECT_TRUE(pLinkedSet.contains(nine)); 3498 EXPECT_TRUE(pLinkedSet.contains(nine));
3494 3499
3495 EXPECT_EQ(1u, pMap.size()); 3500 EXPECT_EQ(1u, pMap.size());
3496 EXPECT_EQ(six, pMap.get(five)); 3501 EXPECT_EQ(six, pMap.get(five));
3502
3503 EXPECT_EQ(1u, wpMap.size());
3504 EXPECT_EQ(eleven, wpMap.get(ten));
3505 ten.clear();
3506 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3507 EXPECT_EQ(0u, wpMap.size());
3497 } 3508 }
3498 3509
3499 // Collect previous roots. 3510 // Collect previous roots.
3500 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3511 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3501 EXPECT_EQ(9, IntWrapper::s_destructorCalls); 3512 EXPECT_EQ(11, IntWrapper::s_destructorCalls);
3502 } 3513 }
3503 3514
3504 TEST(HeapTest, CollectionNesting) 3515 TEST(HeapTest, CollectionNesting)
3505 { 3516 {
3506 HeapStats initialStats; 3517 HeapStats initialStats;
3507 clearOutOldGarbage(&initialStats); 3518 clearOutOldGarbage(&initialStats);
3508 int* key = &IntWrapper::s_destructorCalls; 3519 int* key = &IntWrapper::s_destructorCalls;
3509 IntWrapper::s_destructorCalls = 0; 3520 IntWrapper::s_destructorCalls = 0;
3510 typedef HeapVector<Member<IntWrapper> > IntVector; 3521 typedef HeapVector<Member<IntWrapper> > IntVector;
3511 typedef HeapDeque<Member<IntWrapper> > IntDeque; 3522 typedef HeapDeque<Member<IntWrapper> > IntDeque;
(...skipping 1064 matching lines...) Expand 10 before | Expand all | Expand 10 after
4576 EXPECT_EQ(lifeObject, map->get(lifeObject)->link()); 4587 EXPECT_EQ(lifeObject, map->get(lifeObject)->link());
4577 deadObject.clear(); // Now it can live up to its name. 4588 deadObject.clear(); // Now it can live up to its name.
4578 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4589 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4579 EXPECT_EQ(1u, map->size()); 4590 EXPECT_EQ(1u, map->size());
4580 EXPECT_EQ(lifeObject, map->get(lifeObject)->link()); 4591 EXPECT_EQ(lifeObject, map->get(lifeObject)->link());
4581 lifeObject.clear(); // Despite its name. 4592 lifeObject.clear(); // Despite its name.
4582 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4593 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4583 EXPECT_EQ(0u, map->size()); 4594 EXPECT_EQ(0u, map->size());
4584 } 4595 }
4585 4596
4597 static Mutex& mainThreadMutex()
4598 {
4599 AtomicallyInitializedStatic(Mutex&, mainMutex = *new Mutex);
4600 return mainMutex;
4601 }
4602
4603 static ThreadCondition& mainThreadCondition()
4604 {
4605 AtomicallyInitializedStatic(ThreadCondition&, mainCondition = *new ThreadCon dition);
4606 return mainCondition;
4607 }
4608
4609 static void parkMainThread()
4610 {
4611 mainThreadCondition().wait(mainThreadMutex());
4612 }
4613
4614 static void wakeMainThread()
4615 {
4616 MutexLocker locker(mainThreadMutex());
4617 mainThreadCondition().signal();
4618 }
4619
4620 static Mutex& workerThreadMutex()
4621 {
4622 AtomicallyInitializedStatic(Mutex&, workerMutex = *new Mutex);
4623 return workerMutex;
4624 }
4625
4626 static ThreadCondition& workerThreadCondition()
4627 {
4628 AtomicallyInitializedStatic(ThreadCondition&, workerCondition = *new ThreadC ondition);
4629 return workerCondition;
4630 }
4631
4632 static void parkWorkerThread()
4633 {
4634 workerThreadCondition().wait(workerThreadMutex());
4635 }
4636
4637 static void wakeWorkerThread()
4638 {
4639 MutexLocker locker(workerThreadMutex());
4640 workerThreadCondition().signal();
4641 }
4642
4643 class CrossThreadObject : public GarbageCollectedFinalized<CrossThreadObject> {
4644 public:
4645 static CrossThreadObject* create(IntWrapper* workerObjectPointer)
4646 {
4647 return new CrossThreadObject(workerObjectPointer);
4648 }
4649
4650 virtual ~CrossThreadObject()
4651 {
4652 ++s_destructorCalls;
4653 }
4654
4655 static int s_destructorCalls;
4656 void trace(Visitor* visitor) { visitor->trace(m_workerObject); }
4657
4658 private:
4659 CrossThreadObject(IntWrapper* workerObjectPointer) : m_workerObject(workerOb jectPointer) { }
4660
4661 private:
4662 Member<IntWrapper> m_workerObject;
4663 };
4664
4665 int CrossThreadObject::s_destructorCalls = 0;
4666
4667 class CrossThreadPointerTester {
4668 public:
4669 static void test()
4670 {
4671 CrossThreadObject::s_destructorCalls = 0;
4672 IntWrapper::s_destructorCalls = 0;
4673
4674 MutexLocker locker(mainThreadMutex());
4675 createThread(&workerThreadMain, 0, "Worker Thread");
4676
4677 parkMainThread();
4678
4679 uintptr_t stackPtrValue = 0;
4680 {
4681 // Create an object with a pointer to the other heap's IntWrapper.
4682 Persistent<CrossThreadObject> cto = CrossThreadObject::create(const_ cast<IntWrapper*>(s_workerObjectPointer));
4683 s_workerObjectPointer = 0;
4684
4685 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4686
4687 // Nothing should have been collected/destructed.
4688 EXPECT_EQ(0, CrossThreadObject::s_destructorCalls);
4689 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
4690
4691 // Put cto into a stack value. This is used to check that a conserva tive
4692 // GC succeeds even though we are tracing the other thread heap afte r
4693 // shutting it down.
4694 stackPtrValue = reinterpret_cast<uintptr_t>(cto.get());
4695 }
4696 RELEASE_ASSERT(stackPtrValue);
4697
4698 // At this point it is "programatically" okay to shut down the worker th read
4699 // since the cto object should be dead. However out stackPtrValue will c ause a
4700 // trace of the object when doing a conservative GC.
4701 // The worker thread's thread local GC's should just add the worker thre ad's
4702 // pages to the heap after finalizing IntWrapper.
4703 wakeWorkerThread();
4704
4705 // Wait for the worker to shutdown.
4706 parkMainThread();
4707
4708 // After the worker thread has detached it should have finalized the
4709 // IntWrapper object on its heaps. Since there has been no global GC
4710 // the cto object should not have been finalized.
4711 EXPECT_EQ(0, CrossThreadObject::s_destructorCalls);
4712 EXPECT_EQ(1, IntWrapper::s_destructorCalls);
4713
4714 // Now do a conservative GC. The stackPtrValue should keep cto alive
4715 // and will also cause the orphaned page of the other thread to be
4716 // traced. At this point cto should still not be finalized.
4717 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
4718 EXPECT_EQ(0, CrossThreadObject::s_destructorCalls);
4719 EXPECT_EQ(1, IntWrapper::s_destructorCalls);
4720
4721 // Do a GC with no pointers on the stack to see the cto being collected.
4722 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4723 EXPECT_EQ(1, CrossThreadObject::s_destructorCalls);
4724 EXPECT_EQ(1, IntWrapper::s_destructorCalls);
4725 }
4726
4727 private:
4728 static void workerThreadMain(void* data)
4729 {
4730 MutexLocker locker(workerThreadMutex());
4731 ThreadState::attach();
4732
4733 {
4734 // Create a worker object that is only kept alive by a cross thread
4735 // pointer (from CrossThreadObject).
4736 IntWrapper* workerObject = IntWrapper::create(42);
4737 s_workerObjectPointer = workerObject;
4738 }
4739
4740 // Wake up the main thread which is waiting for the worker to do its
4741 // allocation and passing the pointer.
4742 wakeMainThread();
4743
4744 // Wait for main thread to signal the worker to shutdown.
4745 {
4746 ThreadState::SafePointScope scope(ThreadState::NoHeapPointersOnStack );
4747 parkWorkerThread();
4748 }
4749
4750 ThreadState::detach();
4751
4752 // Tell the main thread the worker has done its shutdown.
4753 wakeMainThread();
4754 }
4755
4756 static volatile IntWrapper* s_workerObjectPointer;
4757 };
4758
4759 volatile IntWrapper* CrossThreadPointerTester::s_workerObjectPointer = 0;
4760
4761 TEST(HeapTest, CrossThreadPointerToOrphanedPage)
4762 {
4763 CrossThreadPointerTester::test();
4764 }
4765
4766 class DeadBitTester {
4767 public:
4768 static void test()
4769 {
4770 IntWrapper::s_destructorCalls = 0;
4771
4772 MutexLocker locker(mainThreadMutex());
4773 createThread(&workerThreadMain, 0, "Worker Thread");
4774
4775 // Wait for the worker thread to have done its initialization,
4776 // IE. the worker allocates an object and then throw aways any
4777 // pointers to it.
4778 parkMainThread();
4779
4780 // Now do a GC. This will not find the worker threads object since it
4781 // is not referred from any of the threads. Even a conservative
4782 // GC will not find it.
4783 // Also at this point the worker is waiting for the main thread
4784 // to be parked and will not do any sweep of its heap.
4785 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4786
4787 // Since the worker thread is not sweeping the worker object should
4788 // not have been finalized.
4789 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
4790
4791 // Put the worker thread's object address on the stack and do a
4792 // conservative GC. This should find the worker object, but since
4793 // it was dead in the previous GC it should not be traced in this
4794 // GC.
4795 uintptr_t stackPtrValue = s_workerObjectPointer;
4796 s_workerObjectPointer = 0;
4797 ASSERT_UNUSED(stackPtrValue, stackPtrValue);
4798 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
4799
4800 // Since the worker thread is not sweeping the worker object should
4801 // not have been finalized.
4802 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
4803
4804 // Wake up the worker thread so it can continue with its sweeping.
4805 // This should finalized the worker object which we test below.
4806 // The worker thread will go back to sleep once sweeping to ensure
4807 // we don't have thread local GCs until after validating the destructor
4808 // was called.
4809 wakeWorkerThread();
4810
4811 // Wait for the worker thread to sweep its heaps before checking.
4812 parkMainThread();
4813 EXPECT_EQ(1, IntWrapper::s_destructorCalls);
4814
4815 // Wake up the worker to allow it thread to continue with thread
4816 // shutdown.
4817 wakeWorkerThread();
4818 }
4819
4820 private:
4821
4822 static void workerThreadMain(void* data)
4823 {
4824 MutexLocker locker(workerThreadMutex());
4825
4826 ThreadState::attach();
4827
4828 {
4829 // Create a worker object that is not kept alive except the
4830 // main thread will keep it as an integer value on its stack.
4831 IntWrapper* workerObject = IntWrapper::create(42);
4832 s_workerObjectPointer = reinterpret_cast<uintptr_t>(workerObject);
4833 }
4834
4835 // Signal the main thread that the worker is done with its allocation.
4836 wakeMainThread();
4837
4838 {
4839 // Wait for the main thread to do two GCs without sweeping this thre ad
4840 // heap. The worker waits within a safepoint, but there is no sweepi ng
4841 // until leaving the safepoint scope.
4842 ThreadState::SafePointScope scope(ThreadState::NoHeapPointersOnStack );
4843 parkWorkerThread();
4844 }
4845
4846 // Wake up the main thread when done sweeping.
4847 wakeMainThread();
4848
4849 // Wait with detach until the main thread says so. This is not strictly
4850 // necessary, but it means the worker thread will not do its thread loca l
4851 // GCs just yet, making it easier to reason about that no new GC has occ urred
4852 // and the above sweep was the one finalizing the worker object.
4853 parkWorkerThread();
4854
4855 ThreadState::detach();
4856 }
4857
4858 static volatile uintptr_t s_workerObjectPointer;
4859 };
4860
4861 volatile uintptr_t DeadBitTester::s_workerObjectPointer = 0;
4862
4863 TEST(HeapTest, ObjectDeadBit)
4864 {
4865 DeadBitTester::test();
4866 }
4586 4867
4587 } // WebCore namespace 4868 } // WebCore namespace
OLDNEW
« no previous file with comments | « Source/platform/heap/Heap.cpp ('k') | Source/platform/heap/ThreadState.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698