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

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

Issue 371623002: [oilpan]: Make thread shutdown more robust. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
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 | Annotate | Revision Log
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 class CrossThreadObject : public GarbageCollectedFinalized<CrossThreadObject> {
4598 public:
4599 static CrossThreadObject* create(IntWrapper* workerObjectPointer)
4600 {
4601 return new CrossThreadObject(workerObjectPointer);
4602 }
4603
4604 virtual ~CrossThreadObject()
4605 {
4606 ++s_destructorCalls;
4607 }
4608
4609 static int s_destructorCalls;
4610 void trace(Visitor* visitor) { visitor->trace(m_workerObject); }
4611
4612 private:
4613 CrossThreadObject(IntWrapper* workerObjectPointer) : m_workerObject(workerOb jectPointer) { }
4614
4615 private:
4616 Member<IntWrapper> m_workerObject;
4617 };
4618
4619 int CrossThreadObject::s_destructorCalls = 0;
4620
4621 class CrossThreadPointerTester {
4622 public:
4623 static void test()
4624 {
4625 CrossThreadObject::s_destructorCalls = 0;
4626 IntWrapper::s_destructorCalls = 0;
4627 createThread(&workerThreadMain, 0, "Worker Thread");
4628
4629 // Wait for the worker to run.
4630 while (!s_workerRunning) {
4631 yield();
4632 }
4633
4634 uintptr_t stackPtrValue = 0;
4635 {
4636 // Create an object with a pointer to the other heap's IntWrapper.
4637 Persistent<CrossThreadObject> cto = CrossThreadObject::create(const_ cast<IntWrapper*>(s_workerObjectPointer));
4638 s_workerObjectPointer = 0;
4639
4640 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4641
4642 // Nothing should have been collected/destructed.
4643 EXPECT_EQ(0, CrossThreadObject::s_destructorCalls);
4644 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
4645
4646 // Put cto into a stack value. This is used to check that a conserva tive
4647 // GC succeeds even though we are tracing the other thread heap afte r
4648 // shutting it down.
4649 stackPtrValue = reinterpret_cast<uintptr_t>(cto.get());
4650 }
4651
4652 // At this point it is "programatically" okay to shut down the worker th read
4653 // since the cto object should be dead. However out stackPtrValue will c ause a
4654 // trace of the object when doing a conservative GC.
4655 // The worker thread's thread local GC's should just add the worker thre ad's
4656 // pages to the heap after finalizing IntWrapper.
4657 s_workerFinish = true;
4658
4659 // Wait for the worker to finish.
4660 while (s_workerRunning) {
4661 // No need to enter a safepoint since the GC's done by the worker at detach
4662 // are thread local and doesn't require other threads to enter a saf epoint.
4663 yield();
4664 }
4665 // After the worker thread has detached it should have finalized the
4666 // IntWrapper object on its heaps. Since there has been no global GC
4667 // the cto object should not have been finalized.
4668 EXPECT_EQ(0, CrossThreadObject::s_destructorCalls);
4669 EXPECT_EQ(1, IntWrapper::s_destructorCalls);
4670
4671 // Now do a conservative GC. The stackPtrValue should keep cto alive
4672 // and will also cause the orphaned page of the other thread to be
4673 // traced. At this point cto should still not be finalized.
4674 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
4675 EXPECT_EQ(0, CrossThreadObject::s_destructorCalls);
4676 EXPECT_EQ(1, IntWrapper::s_destructorCalls);
4677
4678 // Set stackPtrValue to zero and see the cto object being collected in t he
4679 // conservative GC.
4680 stackPtrValue = 0;
4681 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
4682 EXPECT_EQ(1, CrossThreadObject::s_destructorCalls);
4683 EXPECT_EQ(1, IntWrapper::s_destructorCalls);
4684 }
4685
4686 private:
4687 static void workerThreadMain(void* data)
4688 {
4689 ThreadState::attach();
4690
4691 {
4692 // Create a worker object that is only kept alive by a cross thread
4693 // pointer (from CrossThreadObject).
4694 IntWrapper* workerObject = IntWrapper::create(42);
4695 s_workerObjectPointer = workerObject;
4696 s_workerRunning = true;
4697 }
4698
4699 // Wait for main thread to signal the worker to finish.
4700 while (!s_workerFinish) {
4701 ThreadState::current()->safePoint(ThreadState::NoHeapPointersOnStack );
4702 yield();
4703 }
4704
4705 ThreadState::detach();
4706 s_workerRunning = false;
4707 }
4708
4709 static volatile IntWrapper* s_workerObjectPointer;
4710 static volatile bool s_workerRunning;
4711 static volatile bool s_workerFinish;
4712 };
4713
4714 volatile bool CrossThreadPointerTester::s_workerRunning = false;
4715 volatile bool CrossThreadPointerTester::s_workerFinish = false;
4716 volatile IntWrapper* CrossThreadPointerTester::s_workerObjectPointer = 0;
4717
4718 TEST(HeapTest, CrossThreadPointerToOrphanedPage)
4719 {
4720 CrossThreadPointerTester::test();
4721 }
4722
4723 class DeadBitTester {
4724 public:
4725 static void test()
4726 {
4727 IntWrapper::s_destructorCalls = 0;
4728 createThread(&workerThreadMain, 0, "Worker Thread");
4729
4730 // Wait for the worker to run.
4731 while (!s_workerRunning) {
4732 yield();
4733 }
4734
4735 // Do a GC. This will not find the worker threads object since it
4736 // is not referred from any of the threads. Even a conservative
4737 // GC will not find it.
4738 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4739
4740 // Since the worker thread is not sweeping the worker object should
4741 // not have been finalized.
4742 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
4743
4744 // Put the worker thread's object address on the stack and do a
4745 // conservative GC. This should find the worker object, but since
4746 // it was dead in the previous GC it should not be traced in this
4747 // GC.
4748 uintptr_t stackPtrValue = s_workerObjectPointer;
4749 s_workerObjectPointer = 0;
4750 ASSERT_UNUSED(stackPtrValue, stackPtrValue);
4751 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
4752
4753 // Since the worker thread is not sweeping the worker object should
4754 // not have been finalized.
4755 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
4756
4757 // Tell the worker thread to finish its busy loop, but not detach.
4758 // This means there is no further GC, however the worker thread gets
4759 // to sweep so the worker object should now be finalized since the
4760 // above conservative GC should not have traced the object that was
4761 // found dead in the first GC.
4762 s_workerContinue = true;
4763
4764 // Wait for the worker to sweep.
4765 while (!s_workerDidSweep) {
4766 // No need to enter a safepoint since the worker thread is just swee ping
4767 // its own heap.
4768 yield();
4769 }
4770 EXPECT_EQ(1, IntWrapper::s_destructorCalls);
4771
4772 // Tell the worker to shut down.
4773 s_workerFinish = true;
4774 }
4775
4776 private:
4777 static void workerThreadMain(void* data)
4778 {
4779 ThreadState::attach();
4780
4781 {
4782 // Create a worker object that is not kept alive except the
4783 // main thread will keep it as an integer value on its stack.
4784 IntWrapper* workerObject = IntWrapper::create(42);
4785 s_workerObjectPointer = reinterpret_cast<uintptr_t>(workerObject);
4786 s_workerRunning = true;
4787 }
4788
4789 // Enter a safepoint, but don't exit until the main thread tells us it
4790 // has done it works. This means this thread will not sweep its heap
4791 // since the sweep is done when the safepoint scope is destructed.
4792 {
4793 ThreadState::SafePointScope scope(ThreadState::NoHeapPointersOnStack );
4794 while (!s_workerContinue) {
4795 yield();
4796 }
4797 }
4798
4799 // At this point the worker have swept its heaps. Tell the main thread i ts
4800 // done.
4801 s_workerDidSweep = true;
4802
4803 // Wait with detach until the main thread says so. This is not strictly
4804 // necessary, but it means the worker thread will not do its thread loca l
4805 // GCs just yet, making it easier to reason about that no new GC has occ urred
4806 // and the above sweep was the one finalizing the worker object.
4807 while (!s_workerFinish) {
4808 yield();
4809 }
4810
4811 ThreadState::detach();
4812 s_workerRunning = false;
4813 }
4814
4815 static volatile bool s_workerRunning;
Mads Ager (chromium) 2014/07/11 10:59:34 I guess we should either use atomic ops here or ha
wibling-chromium 2014/07/11 13:06:54 Done.
4816 static volatile bool s_workerContinue;
4817 static volatile bool s_workerDidSweep;
4818 static volatile bool s_workerFinish;
4819 static volatile uintptr_t s_workerObjectPointer;
4820 };
4821
4822 volatile bool DeadBitTester::s_workerRunning = false;
4823 volatile bool DeadBitTester::s_workerContinue = false;
4824 volatile bool DeadBitTester::s_workerDidSweep = false;
4825 volatile bool DeadBitTester::s_workerFinish = false;
4826 volatile uintptr_t DeadBitTester::s_workerObjectPointer = 0;
4827
4828 TEST(HeapTest, ObjectDeadBit)
4829 {
4830 DeadBitTester::test();
4831 }
4586 4832
4587 } // WebCore namespace 4833 } // WebCore namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698