OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |