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 690 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
701 static PassRefPtr<RefCountedAndGarbageCollected> create() | 701 static PassRefPtr<RefCountedAndGarbageCollected> create() |
702 { | 702 { |
703 return adoptRef(new RefCountedAndGarbageCollected()); | 703 return adoptRef(new RefCountedAndGarbageCollected()); |
704 } | 704 } |
705 | 705 |
706 ~RefCountedAndGarbageCollected() | 706 ~RefCountedAndGarbageCollected() |
707 { | 707 { |
708 ++s_destructorCalls; | 708 ++s_destructorCalls; |
709 } | 709 } |
710 | 710 |
| 711 // These are here with their default implementations so you can break in |
| 712 // them in the debugger. |
| 713 void ref() { RefCountedGarbageCollected<RefCountedAndGarbageCollected>::ref(
); } |
| 714 void deref() { RefCountedGarbageCollected<RefCountedAndGarbageCollected>::de
ref(); } |
| 715 |
711 void trace(Visitor*) { } | 716 void trace(Visitor*) { } |
712 | 717 |
713 static int s_destructorCalls; | 718 static int s_destructorCalls; |
714 | 719 |
715 private: | 720 private: |
716 RefCountedAndGarbageCollected() | 721 RefCountedAndGarbageCollected() |
717 { | 722 { |
718 } | 723 } |
719 }; | 724 }; |
720 | 725 |
(...skipping 1492 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2213 found++; | 2218 found++; |
2214 int value = (*it)->value(); | 2219 int value = (*it)->value(); |
2215 EXPECT_TRUE(value >= 0 && value < 1100); | 2220 EXPECT_TRUE(value >= 0 && value < 1100); |
2216 ++it; | 2221 ++it; |
2217 } | 2222 } |
2218 EXPECT_EQ(expected, found); | 2223 EXPECT_EQ(expected, found); |
2219 } | 2224 } |
2220 | 2225 |
2221 TEST(HeapTest, HeapWeakCollectionSimple) | 2226 TEST(HeapTest, HeapWeakCollectionSimple) |
2222 { | 2227 { |
2223 | 2228 HeapStats initialHeapStats; |
| 2229 clearOutOldGarbage(&initialHeapStats); |
2224 IntWrapper::s_destructorCalls = 0; | 2230 IntWrapper::s_destructorCalls = 0; |
2225 | 2231 |
2226 PersistentHeapVector<Member<IntWrapper> > keepNumbersAlive; | 2232 PersistentHeapVector<Member<IntWrapper> > keepNumbersAlive; |
2227 | 2233 |
2228 typedef HeapHashMap<WeakMember<IntWrapper>, Member<IntWrapper> > WeakStrong; | 2234 typedef HeapHashMap<WeakMember<IntWrapper>, Member<IntWrapper> > WeakStrong; |
2229 typedef HeapHashMap<Member<IntWrapper>, WeakMember<IntWrapper> > StrongWeak; | 2235 typedef HeapHashMap<Member<IntWrapper>, WeakMember<IntWrapper> > StrongWeak; |
2230 typedef HeapHashMap<WeakMember<IntWrapper>, WeakMember<IntWrapper> > WeakWea
k; | 2236 typedef HeapHashMap<WeakMember<IntWrapper>, WeakMember<IntWrapper> > WeakWea
k; |
2231 typedef HeapHashSet<WeakMember<IntWrapper> > WeakSet; | 2237 typedef HeapHashSet<WeakMember<IntWrapper> > WeakSet; |
2232 | 2238 |
2233 Persistent<WeakStrong> weakStrong = new WeakStrong(); | 2239 Persistent<WeakStrong> weakStrong = new WeakStrong(); |
(...skipping 24 matching lines...) Expand all Loading... |
2258 keepNumbersAlive[0] = nullptr; | 2264 keepNumbersAlive[0] = nullptr; |
2259 | 2265 |
2260 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); | 2266 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); |
2261 | 2267 |
2262 EXPECT_EQ(0u, weakStrong->size()); | 2268 EXPECT_EQ(0u, weakStrong->size()); |
2263 EXPECT_EQ(0u, strongWeak->size()); | 2269 EXPECT_EQ(0u, strongWeak->size()); |
2264 EXPECT_EQ(0u, weakWeak->size()); | 2270 EXPECT_EQ(0u, weakWeak->size()); |
2265 EXPECT_EQ(2u, weakSet->size()); | 2271 EXPECT_EQ(2u, weakSet->size()); |
2266 } | 2272 } |
2267 | 2273 |
| 2274 class ThingWithDestructor { |
| 2275 public: |
| 2276 ThingWithDestructor() |
| 2277 : m_x(emptyValue) |
| 2278 { |
| 2279 s_liveThingsWithDestructor++; |
| 2280 } |
| 2281 |
| 2282 ThingWithDestructor(int x) |
| 2283 : m_x(x) |
| 2284 { |
| 2285 s_liveThingsWithDestructor++; |
| 2286 } |
| 2287 |
| 2288 ThingWithDestructor(const ThingWithDestructor&other) |
| 2289 { |
| 2290 *this = other; |
| 2291 s_liveThingsWithDestructor++; |
| 2292 } |
| 2293 |
| 2294 ~ThingWithDestructor() |
| 2295 { |
| 2296 s_liveThingsWithDestructor--; |
| 2297 } |
| 2298 |
| 2299 int value() { return m_x; } |
| 2300 |
| 2301 static int s_liveThingsWithDestructor; |
| 2302 |
| 2303 unsigned hash() { return IntHash<int>::hash(m_x); } |
| 2304 |
| 2305 private: |
| 2306 static const int emptyValue = 0; |
| 2307 int m_x; |
| 2308 }; |
| 2309 |
| 2310 int ThingWithDestructor::s_liveThingsWithDestructor; |
| 2311 |
| 2312 struct ThingWithDestructorTraits : public HashTraits<ThingWithDestructor> { |
| 2313 static const bool needsDestruction = true; |
| 2314 }; |
| 2315 |
| 2316 static void heapMapDestructorHelper(bool clearMaps) |
| 2317 { |
| 2318 HeapStats initialHeapStats; |
| 2319 clearOutOldGarbage(&initialHeapStats); |
| 2320 ThingWithDestructor::s_liveThingsWithDestructor = 0; |
| 2321 |
| 2322 typedef HeapHashMap<WeakMember<IntWrapper>, RefPtr<RefCountedAndGarbageColle
cted> > RefMap; |
| 2323 |
| 2324 typedef HeapHashMap< |
| 2325 WeakMember<IntWrapper>, |
| 2326 ThingWithDestructor, |
| 2327 DefaultHash<WeakMember<IntWrapper> >::Hash, |
| 2328 HashTraits<WeakMember<IntWrapper> >, |
| 2329 ThingWithDestructorTraits> Map; |
| 2330 |
| 2331 Persistent<Map> map(new Map()); |
| 2332 Persistent<RefMap> refMap(new RefMap()); |
| 2333 |
| 2334 Persistent<IntWrapper> luck(IntWrapper::create(103)); |
| 2335 |
| 2336 int baseLine, refBaseLine; |
| 2337 |
| 2338 { |
| 2339 Map stackMap; |
| 2340 RefMap stackRefMap; |
| 2341 |
| 2342 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); |
| 2343 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); |
| 2344 |
| 2345 stackMap.add(IntWrapper::create(42), ThingWithDestructor(1729)); |
| 2346 stackMap.add(luck, ThingWithDestructor(8128)); |
| 2347 stackRefMap.add(IntWrapper::create(42), RefCountedAndGarbageCollected::c
reate()); |
| 2348 stackRefMap.add(luck, RefCountedAndGarbageCollected::create()); |
| 2349 |
| 2350 baseLine = ThingWithDestructor::s_liveThingsWithDestructor; |
| 2351 refBaseLine = RefCountedAndGarbageCollected::s_destructorCalls; |
| 2352 |
| 2353 // Although the heap maps are on-stack, we can't expect prompt |
| 2354 // finalization of the elements, so when they go out of scope here we |
| 2355 // will not necessarily have called the relevant destructors. |
| 2356 } |
| 2357 |
| 2358 // The RefCountedAndGarbageCollected things need an extra GC to discover |
| 2359 // that they are no longer ref counted. |
| 2360 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); |
| 2361 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); |
| 2362 EXPECT_EQ(baseLine - 2, ThingWithDestructor::s_liveThingsWithDestructor); |
| 2363 EXPECT_EQ(refBaseLine + 2, RefCountedAndGarbageCollected::s_destructorCalls)
; |
| 2364 |
| 2365 // Now use maps kept alive with persistents. Here we don't expect any |
| 2366 // destructors to be called before there have been GCs. |
| 2367 |
| 2368 map->add(IntWrapper::create(42), ThingWithDestructor(1729)); |
| 2369 map->add(luck, ThingWithDestructor(8128)); |
| 2370 refMap->add(IntWrapper::create(42), RefCountedAndGarbageCollected::create())
; |
| 2371 refMap->add(luck, RefCountedAndGarbageCollected::create()); |
| 2372 |
| 2373 baseLine = ThingWithDestructor::s_liveThingsWithDestructor; |
| 2374 refBaseLine = RefCountedAndGarbageCollected::s_destructorCalls; |
| 2375 |
| 2376 luck.clear(); |
| 2377 if (clearMaps) { |
| 2378 map->clear(); // Clear map. |
| 2379 refMap->clear(); // Clear map. |
| 2380 } else { |
| 2381 map.clear(); // Clear Persistent handle, not map. |
| 2382 refMap.clear(); // Clear Persistent handle, not map. |
| 2383 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); |
| 2384 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); |
| 2385 } |
| 2386 |
| 2387 EXPECT_EQ(baseLine - 2, ThingWithDestructor::s_liveThingsWithDestructor); |
| 2388 |
| 2389 // Need a GC to make sure that the RefCountedAndGarbageCollected thing |
| 2390 // noticies it's been decremented to zero. |
| 2391 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); |
| 2392 EXPECT_EQ(refBaseLine + 2, RefCountedAndGarbageCollected::s_destructorCalls)
; |
| 2393 } |
| 2394 |
| 2395 TEST(HeapTest, HeapMapDestructor) |
| 2396 { |
| 2397 heapMapDestructorHelper(true); |
| 2398 heapMapDestructorHelper(false); |
| 2399 } |
| 2400 |
2268 typedef HeapHashSet<PairWeakStrong> WeakStrongSet; | 2401 typedef HeapHashSet<PairWeakStrong> WeakStrongSet; |
2269 typedef HeapHashSet<PairWeakUnwrapped> WeakUnwrappedSet; | 2402 typedef HeapHashSet<PairWeakUnwrapped> WeakUnwrappedSet; |
2270 typedef HeapHashSet<PairStrongWeak> StrongWeakSet; | 2403 typedef HeapHashSet<PairStrongWeak> StrongWeakSet; |
2271 typedef HeapHashSet<PairUnwrappedWeak> UnwrappedWeakSet; | 2404 typedef HeapHashSet<PairUnwrappedWeak> UnwrappedWeakSet; |
2272 | 2405 |
2273 void checkPairSets( | 2406 void checkPairSets( |
2274 Persistent<WeakStrongSet>& weakStrong, | 2407 Persistent<WeakStrongSet>& weakStrong, |
2275 Persistent<StrongWeakSet>& strongWeak, | 2408 Persistent<StrongWeakSet>& strongWeak, |
2276 Persistent<WeakUnwrappedSet>& weakUnwrapped, | 2409 Persistent<WeakUnwrappedSet>& weakUnwrapped, |
2277 Persistent<UnwrappedWeakSet>& unwrappedWeak, | 2410 Persistent<UnwrappedWeakSet>& unwrappedWeak, |
(...skipping 559 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2837 HeapHashMap<void*, IntVector>::iterator it = map->find(key); | 2970 HeapHashMap<void*, IntVector>::iterator it = map->find(key); |
2838 EXPECT_EQ(0u, map->get(key).size()); | 2971 EXPECT_EQ(0u, map->get(key).size()); |
2839 | 2972 |
2840 it->value.append(IntWrapper::create(42)); | 2973 it->value.append(IntWrapper::create(42)); |
2841 EXPECT_EQ(1u, map->get(key).size()); | 2974 EXPECT_EQ(1u, map->get(key).size()); |
2842 | 2975 |
2843 Persistent<HeapHashMap<void*, IntVector> > keepAlive(map); | 2976 Persistent<HeapHashMap<void*, IntVector> > keepAlive(map); |
2844 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); | 2977 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); |
2845 EXPECT_EQ(1u, map->get(key).size()); | 2978 EXPECT_EQ(1u, map->get(key).size()); |
2846 EXPECT_EQ(0, IntWrapper::s_destructorCalls); | 2979 EXPECT_EQ(0, IntWrapper::s_destructorCalls); |
| 2980 |
| 2981 keepAlive = nullptr; |
| 2982 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); |
| 2983 EXPECT_EQ(1, IntWrapper::s_destructorCalls); |
2847 } | 2984 } |
2848 | 2985 |
2849 TEST(heap, GarbageCollectedMixin) | 2986 TEST(heap, GarbageCollectedMixin) |
2850 { | 2987 { |
2851 HeapStats initialHeapStats; | 2988 HeapStats initialHeapStats; |
2852 clearOutOldGarbage(&initialHeapStats); | 2989 clearOutOldGarbage(&initialHeapStats); |
2853 | 2990 |
2854 Persistent<UseMixin> usemixin = UseMixin::create(); | 2991 Persistent<UseMixin> usemixin = UseMixin::create(); |
2855 ASSERT_EQ(0, UseMixin::s_traceCount); | 2992 ASSERT_EQ(0, UseMixin::s_traceCount); |
2856 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); | 2993 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); |
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3055 // Check that the wrapper allocated during finalization is not | 3192 // Check that the wrapper allocated during finalization is not |
3056 // swept away and zapped later in the same sweeping phase. | 3193 // swept away and zapped later in the same sweeping phase. |
3057 EXPECT_EQ(42, wrapper->value()); | 3194 EXPECT_EQ(42, wrapper->value()); |
3058 | 3195 |
3059 wrapper.clear(); | 3196 wrapper.clear(); |
3060 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); | 3197 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); |
3061 EXPECT_EQ(10, IntWrapper::s_destructorCalls); | 3198 EXPECT_EQ(10, IntWrapper::s_destructorCalls); |
3062 EXPECT_EQ(512, OneKiloByteObject::s_destructorCalls); | 3199 EXPECT_EQ(512, OneKiloByteObject::s_destructorCalls); |
3063 } | 3200 } |
3064 | 3201 |
| 3202 class SimpleClassWithDestructor { |
| 3203 public: |
| 3204 SimpleClassWithDestructor() { } |
| 3205 ~SimpleClassWithDestructor() |
| 3206 { |
| 3207 ASSERT(!s_wasDestructed); |
| 3208 s_wasDestructed = true; |
| 3209 } |
| 3210 static bool s_wasDestructed; |
| 3211 }; |
| 3212 |
| 3213 bool SimpleClassWithDestructor::s_wasDestructed; |
| 3214 |
| 3215 TEST(HeapTest, DestructorsCalledOnMapClear) |
| 3216 { |
| 3217 HeapHashMap<SimpleClassWithDestructor*, OwnPtr<SimpleClassWithDestructor> >
map; |
| 3218 SimpleClassWithDestructor* hasDestructor = new SimpleClassWithDestructor(); |
| 3219 map.add(hasDestructor, adoptPtr(hasDestructor)); |
| 3220 SimpleClassWithDestructor::s_wasDestructed = false; |
| 3221 map.clear(); |
| 3222 ASSERT(SimpleClassWithDestructor::s_wasDestructed); |
| 3223 } |
| 3224 |
3065 } // WebCore namespace | 3225 } // WebCore namespace |
OLD | NEW |