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 18 matching lines...) Expand all Loading... |
29 */ | 29 */ |
30 | 30 |
31 #include "config.h" | 31 #include "config.h" |
32 | 32 |
33 #include "platform/heap/Handle.h" | 33 #include "platform/heap/Handle.h" |
34 #include "platform/heap/Heap.h" | 34 #include "platform/heap/Heap.h" |
35 #include "platform/heap/HeapLinkedStack.h" | 35 #include "platform/heap/HeapLinkedStack.h" |
36 #include "platform/heap/HeapTerminatedArrayBuilder.h" | 36 #include "platform/heap/HeapTerminatedArrayBuilder.h" |
37 #include "platform/heap/ThreadState.h" | 37 #include "platform/heap/ThreadState.h" |
38 #include "platform/heap/Visitor.h" | 38 #include "platform/heap/Visitor.h" |
| 39 #include "public/platform/Platform.h" |
39 #include "wtf/HashTraits.h" | 40 #include "wtf/HashTraits.h" |
40 #include "wtf/LinkedHashSet.h" | 41 #include "wtf/LinkedHashSet.h" |
41 | 42 |
42 #include <gtest/gtest.h> | 43 #include <gtest/gtest.h> |
43 | 44 |
44 namespace WebCore { | 45 namespace WebCore { |
45 | 46 |
46 class ThreadMarker { | 47 class ThreadMarker { |
47 public: | 48 public: |
48 ThreadMarker() : m_creatingThread(reinterpret_cast<ThreadState*>(0)), m_num(
0) { } | 49 ThreadMarker() : m_creatingThread(reinterpret_cast<ThreadState*>(0)), m_num(
0) { } |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
92 | 93 |
93 } | 94 } |
94 | 95 |
95 namespace WebCore { | 96 namespace WebCore { |
96 | 97 |
97 class TestGCScope { | 98 class TestGCScope { |
98 public: | 99 public: |
99 explicit TestGCScope(ThreadState::StackState state) | 100 explicit TestGCScope(ThreadState::StackState state) |
100 : m_state(ThreadState::current()) | 101 : m_state(ThreadState::current()) |
101 , m_safePointScope(state) | 102 , m_safePointScope(state) |
| 103 , m_parkedAllThreads(false) |
102 { | 104 { |
103 m_state->checkThread(); | 105 m_state->checkThread(); |
104 ASSERT(!m_state->isInGC()); | 106 ASSERT(!m_state->isInGC()); |
105 ThreadState::stopThreads(); | 107 if (LIKELY(ThreadState::stopThreads())) { |
106 m_state->enterGC(); | 108 m_state->enterGC(); |
| 109 m_parkedAllThreads = true; |
| 110 } |
107 } | 111 } |
108 | 112 |
| 113 bool allThreadsParked() { return m_parkedAllThreads; } |
| 114 |
109 ~TestGCScope() | 115 ~TestGCScope() |
110 { | 116 { |
111 m_state->leaveGC(); | 117 // Only cleanup if we parked all threads in which case the GC happened |
112 ASSERT(!m_state->isInGC()); | 118 // and we need to resume the other threads. |
113 ThreadState::resumeThreads(); | 119 if (LIKELY(m_parkedAllThreads)) { |
| 120 m_state->leaveGC(); |
| 121 ASSERT(!m_state->isInGC()); |
| 122 ThreadState::resumeThreads(); |
| 123 } |
114 } | 124 } |
115 | 125 |
116 private: | 126 private: |
117 ThreadState* m_state; | 127 ThreadState* m_state; |
118 ThreadState::SafePointScope m_safePointScope; | 128 ThreadState::SafePointScope m_safePointScope; |
| 129 bool m_parkedAllThreads; // False if we fail to park all threads |
119 }; | 130 }; |
120 | 131 |
121 static void getHeapStats(HeapStats* stats) | 132 static void getHeapStats(HeapStats* stats) |
122 { | 133 { |
123 TestGCScope scope(ThreadState::NoHeapPointersOnStack); | 134 TestGCScope scope(ThreadState::NoHeapPointersOnStack); |
| 135 EXPECT_TRUE(scope.allThreadsParked()); |
124 Heap::getStats(stats); | 136 Heap::getStats(stats); |
125 } | 137 } |
126 | 138 |
127 #define DEFINE_VISITOR_METHODS(Type) \ | 139 #define DEFINE_VISITOR_METHODS(Type) \ |
128 virtual void mark(const Type* object, TraceCallback callback) OVERRIDE \ | 140 virtual void mark(const Type* object, TraceCallback callback) OVERRIDE \ |
129 { \ | 141 { \ |
130 if (object) \ | 142 if (object) \ |
131 m_count++; \ | 143 m_count++; \ |
132 } \ | 144 } \ |
133 virtual bool isMarked(const Type*) OVERRIDE { return false; } | 145 virtual bool isMarked(const Type*) OVERRIDE { return false; } |
(...skipping 3029 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3163 | 3175 |
3164 // This is a low-level test where we call checkAndMarkPointer. This method | 3176 // This is a low-level test where we call checkAndMarkPointer. This method |
3165 // causes the object start bitmap to be computed which requires the heap | 3177 // causes the object start bitmap to be computed which requires the heap |
3166 // to be in a consistent state (e.g. the free allocation area must be put | 3178 // to be in a consistent state (e.g. the free allocation area must be put |
3167 // into a free list header). However when we call makeConsistentForGC it | 3179 // into a free list header). However when we call makeConsistentForGC it |
3168 // also clears out the freelists so we have to rebuild those before trying | 3180 // also clears out the freelists so we have to rebuild those before trying |
3169 // to allocate anything again. We do this by forcing a GC after doing the | 3181 // to allocate anything again. We do this by forcing a GC after doing the |
3170 // checkAndMarkPointer tests. | 3182 // checkAndMarkPointer tests. |
3171 { | 3183 { |
3172 TestGCScope scope(ThreadState::HeapPointersOnStack); | 3184 TestGCScope scope(ThreadState::HeapPointersOnStack); |
| 3185 EXPECT_TRUE(scope.allThreadsParked()); // Fail the test if we could not
park all threads. |
3173 Heap::makeConsistentForGC(); | 3186 Heap::makeConsistentForGC(); |
3174 for (size_t i = 0; i < objectAddresses.size(); i++) { | 3187 for (size_t i = 0; i < objectAddresses.size(); i++) { |
3175 EXPECT_TRUE(Heap::checkAndMarkPointer(&visitor, objectAddresses[i]))
; | 3188 EXPECT_TRUE(Heap::checkAndMarkPointer(&visitor, objectAddresses[i]))
; |
3176 EXPECT_TRUE(Heap::checkAndMarkPointer(&visitor, endAddresses[i])); | 3189 EXPECT_TRUE(Heap::checkAndMarkPointer(&visitor, endAddresses[i])); |
3177 } | 3190 } |
3178 EXPECT_EQ(objectAddresses.size() * 2, visitor.count()); | 3191 EXPECT_EQ(objectAddresses.size() * 2, visitor.count()); |
3179 visitor.reset(); | 3192 visitor.reset(); |
3180 EXPECT_TRUE(Heap::checkAndMarkPointer(&visitor, largeObjectAddress)); | 3193 EXPECT_TRUE(Heap::checkAndMarkPointer(&visitor, largeObjectAddress)); |
3181 EXPECT_TRUE(Heap::checkAndMarkPointer(&visitor, largeObjectEndAddress)); | 3194 EXPECT_TRUE(Heap::checkAndMarkPointer(&visitor, largeObjectEndAddress)); |
3182 EXPECT_EQ(2ul, visitor.count()); | 3195 EXPECT_EQ(2ul, visitor.count()); |
3183 visitor.reset(); | 3196 visitor.reset(); |
3184 } | 3197 } |
3185 // This forces a GC without stack scanning which results in the objects | 3198 // This forces a GC without stack scanning which results in the objects |
3186 // being collected. This will also rebuild the above mentioned freelists, | 3199 // being collected. This will also rebuild the above mentioned freelists, |
3187 // however we don't rely on that below since we don't have any allocations. | 3200 // however we don't rely on that below since we don't have any allocations. |
3188 clearOutOldGarbage(&initialHeapStats); | 3201 clearOutOldGarbage(&initialHeapStats); |
3189 { | 3202 { |
3190 TestGCScope scope(ThreadState::HeapPointersOnStack); | 3203 TestGCScope scope(ThreadState::HeapPointersOnStack); |
| 3204 EXPECT_TRUE(scope.allThreadsParked()); |
3191 Heap::makeConsistentForGC(); | 3205 Heap::makeConsistentForGC(); |
3192 for (size_t i = 0; i < objectAddresses.size(); i++) { | 3206 for (size_t i = 0; i < objectAddresses.size(); i++) { |
3193 EXPECT_FALSE(Heap::checkAndMarkPointer(&visitor, objectAddresses[i])
); | 3207 EXPECT_FALSE(Heap::checkAndMarkPointer(&visitor, objectAddresses[i])
); |
3194 EXPECT_FALSE(Heap::checkAndMarkPointer(&visitor, endAddresses[i])); | 3208 EXPECT_FALSE(Heap::checkAndMarkPointer(&visitor, endAddresses[i])); |
3195 } | 3209 } |
3196 EXPECT_EQ(0ul, visitor.count()); | 3210 EXPECT_EQ(0ul, visitor.count()); |
3197 EXPECT_FALSE(Heap::checkAndMarkPointer(&visitor, largeObjectAddress)); | 3211 EXPECT_FALSE(Heap::checkAndMarkPointer(&visitor, largeObjectAddress)); |
3198 EXPECT_FALSE(Heap::checkAndMarkPointer(&visitor, largeObjectEndAddress))
; | 3212 EXPECT_FALSE(Heap::checkAndMarkPointer(&visitor, largeObjectEndAddress))
; |
3199 EXPECT_EQ(0ul, visitor.count()); | 3213 EXPECT_EQ(0ul, visitor.count()); |
3200 } | 3214 } |
(...skipping 415 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3616 TEST(HeapTest, DestructorsCalledOnMapClear) | 3630 TEST(HeapTest, DestructorsCalledOnMapClear) |
3617 { | 3631 { |
3618 HeapHashMap<SimpleClassWithDestructor*, OwnPtr<SimpleClassWithDestructor> >
map; | 3632 HeapHashMap<SimpleClassWithDestructor*, OwnPtr<SimpleClassWithDestructor> >
map; |
3619 SimpleClassWithDestructor* hasDestructor = new SimpleClassWithDestructor(); | 3633 SimpleClassWithDestructor* hasDestructor = new SimpleClassWithDestructor(); |
3620 map.add(hasDestructor, adoptPtr(hasDestructor)); | 3634 map.add(hasDestructor, adoptPtr(hasDestructor)); |
3621 SimpleClassWithDestructor::s_wasDestructed = false; | 3635 SimpleClassWithDestructor::s_wasDestructed = false; |
3622 map.clear(); | 3636 map.clear(); |
3623 ASSERT(SimpleClassWithDestructor::s_wasDestructed); | 3637 ASSERT(SimpleClassWithDestructor::s_wasDestructed); |
3624 } | 3638 } |
3625 | 3639 |
| 3640 |
| 3641 class GCParkingThreadTester { |
| 3642 public: |
| 3643 static void test() |
| 3644 { |
| 3645 createThread(&sleeperMainFunc, 0, "SleepingThread"); |
| 3646 |
| 3647 // Wait for the sleeper to run. |
| 3648 while (!s_sleeperRunning) { |
| 3649 yield(); |
| 3650 } |
| 3651 |
| 3652 { |
| 3653 // Expect the first attempt to park the sleeping thread to fail |
| 3654 TestGCScope scope(ThreadState::NoHeapPointersOnStack); |
| 3655 EXPECT_FALSE(scope.allThreadsParked()); |
| 3656 } |
| 3657 |
| 3658 s_sleeperDone = true; |
| 3659 |
| 3660 // Wait for the sleeper to finish. |
| 3661 while (s_sleeperRunning) { |
| 3662 yield(); |
| 3663 } |
| 3664 { |
| 3665 // Since the sleeper thread has detached this is the only thread. |
| 3666 TestGCScope scope(ThreadState::NoHeapPointersOnStack); |
| 3667 EXPECT_TRUE(scope.allThreadsParked()); |
| 3668 } |
| 3669 } |
| 3670 |
| 3671 private: |
| 3672 static void sleeperMainFunc(void* data) |
| 3673 { |
| 3674 ThreadState::attach(); |
| 3675 s_sleeperRunning = true; |
| 3676 |
| 3677 // Simulate a long running op that is not entering a safepoint. |
| 3678 while (!s_sleeperDone) { |
| 3679 yield(); |
| 3680 } |
| 3681 |
| 3682 ThreadState::detach(); |
| 3683 s_sleeperRunning = false; |
| 3684 } |
| 3685 |
| 3686 static volatile bool s_sleeperRunning; |
| 3687 static volatile bool s_sleeperDone; |
| 3688 }; |
| 3689 |
| 3690 volatile bool GCParkingThreadTester::s_sleeperRunning = false; |
| 3691 volatile bool GCParkingThreadTester::s_sleeperDone = false; |
| 3692 |
| 3693 TEST(HeapTest, GCParkingTimeout) |
| 3694 { |
| 3695 GCParkingThreadTester::test(); |
| 3696 } |
| 3697 |
3626 } // WebCore namespace | 3698 } // WebCore namespace |
OLD | NEW |