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

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

Issue 216723002: Make sure all destructors are called in HeapHashMap and HeapHashSet (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 6 years, 9 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 690 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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() : m_x(emptyValue) { }
2277 ThingWithDestructor(int x) : m_x(x) { ASSERT(x != emptyValue); }
2278
2279 ~ThingWithDestructor()
2280 {
2281 if (m_x != emptyValue)
wibling-chromium 2014/03/28 10:35:23 Does the constructor get called more than once?
Erik Corry 2014/03/30 20:11:36 Thanks for pointing this out. There was a bug in
2282 s_destructorCalls++;
2283 m_x = emptyValue;
2284 }
2285
2286 int value() { return m_x; }
2287
2288 static int s_destructorCalls;
2289
2290 unsigned hash() { return IntHash<int>::hash(m_x); }
2291
2292 private:
2293 static const int emptyValue = 0;
2294 int m_x;
2295 };
2296
2297 int ThingWithDestructor::s_destructorCalls;
2298
2299 struct ThingWithDestructorTraits : public HashTraits<ThingWithDestructor> {
2300 static const bool needsDestruction = true;
2301 };
2302
2303 static void heapMapDestructorHelper(bool clearMaps)
2304 {
2305 HeapStats initialHeapStats;
2306 clearOutOldGarbage(&initialHeapStats);
2307 ThingWithDestructor::s_destructorCalls = 0;
2308
2309 typedef HeapHashMap<WeakMember<IntWrapper>, RefPtr<RefCountedAndGarbageColle cted> > RefMap;
2310
2311 typedef HeapHashMap<
2312 WeakMember<IntWrapper>,
2313 ThingWithDestructor,
2314 DefaultHash<WeakMember<IntWrapper> >::Hash,
2315 HashTraits<WeakMember<IntWrapper> >,
2316 ThingWithDestructorTraits> Map;
2317
2318 Persistent<Map> map(new Map());
2319 Persistent<RefMap> refMap(new RefMap());
2320
2321 Persistent<IntWrapper> luck(IntWrapper::create(103));
2322
2323 int baseLine, refBaseLine;
2324
2325 {
2326 Map stackMap;
2327 RefMap stackRefMap;
2328
2329 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2330 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2331
2332 stackMap.add(IntWrapper::create(42), ThingWithDestructor(1729));
2333 stackMap.add(luck, ThingWithDestructor(8128));
2334 stackRefMap.add(IntWrapper::create(42), RefCountedAndGarbageCollected::c reate());
2335 stackRefMap.add(luck, RefCountedAndGarbageCollected::create());
2336
2337 baseLine = ThingWithDestructor::s_destructorCalls;
2338 refBaseLine = RefCountedAndGarbageCollected::s_destructorCalls;
2339
2340 // Although the heap maps are on-stack, we can't expect prompt
2341 // finalization of the elements, so when they go out of scope here we
2342 // will not necessarily have called the relevant destructors.
2343 }
2344
2345 // The RefCountedAndGarbageCollected things need an extra GC to discover
2346 // that they are no longer ref counted.
2347 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2348 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2349 EXPECT_EQ(baseLine + 2, ThingWithDestructor::s_destructorCalls);
2350 EXPECT_EQ(refBaseLine + 2, RefCountedAndGarbageCollected::s_destructorCalls) ;
2351
2352 // Now use maps kept alive with persistents. Here we don't expect any
2353 // destructors to be called before there have been GCs.
2354
2355 map->add(IntWrapper::create(42), ThingWithDestructor(1729));
2356 map->add(luck, ThingWithDestructor(8128));
2357 refMap->add(IntWrapper::create(42), RefCountedAndGarbageCollected::create()) ;
2358 refMap->add(luck, RefCountedAndGarbageCollected::create());
2359
2360 baseLine = ThingWithDestructor::s_destructorCalls;
2361 refBaseLine = RefCountedAndGarbageCollected::s_destructorCalls;
2362
2363 luck.clear();
2364 if (clearMaps) {
2365 map->clear(); // Clear map.
2366 refMap->clear(); // Clear map.
2367 } else {
2368 map.clear(); // Clear Persistent handle, not map.
2369 refMap.clear(); // Clear Persistent handle, not map.
2370 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2371 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2372 }
2373
2374 EXPECT_EQ(baseLine + 2, ThingWithDestructor::s_destructorCalls);
2375
2376 // Need a GC to make sure that the RefCountedAndGarbageCollected thing
2377 // noticies it's been decremented to zero.
2378 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2379 EXPECT_EQ(refBaseLine + 2, RefCountedAndGarbageCollected::s_destructorCalls) ;
2380 }
2381
2382 TEST(HeapTest, HeapMapDestructor)
2383 {
2384 heapMapDestructorHelper(true);
2385 heapMapDestructorHelper(false);
2386 }
2387
2268 typedef HeapHashSet<PairWeakStrong> WeakStrongSet; 2388 typedef HeapHashSet<PairWeakStrong> WeakStrongSet;
2269 typedef HeapHashSet<PairWeakUnwrapped> WeakUnwrappedSet; 2389 typedef HeapHashSet<PairWeakUnwrapped> WeakUnwrappedSet;
2270 typedef HeapHashSet<PairStrongWeak> StrongWeakSet; 2390 typedef HeapHashSet<PairStrongWeak> StrongWeakSet;
2271 typedef HeapHashSet<PairUnwrappedWeak> UnwrappedWeakSet; 2391 typedef HeapHashSet<PairUnwrappedWeak> UnwrappedWeakSet;
2272 2392
2273 void checkPairSets( 2393 void checkPairSets(
2274 Persistent<WeakStrongSet>& weakStrong, 2394 Persistent<WeakStrongSet>& weakStrong,
2275 Persistent<StrongWeakSet>& strongWeak, 2395 Persistent<StrongWeakSet>& strongWeak,
2276 Persistent<WeakUnwrappedSet>& weakUnwrapped, 2396 Persistent<WeakUnwrappedSet>& weakUnwrapped,
2277 Persistent<UnwrappedWeakSet>& unwrappedWeak, 2397 Persistent<UnwrappedWeakSet>& unwrappedWeak,
(...skipping 559 matching lines...) Expand 10 before | Expand all | Expand 10 after
2837 HeapHashMap<void*, IntVector>::iterator it = map->find(key); 2957 HeapHashMap<void*, IntVector>::iterator it = map->find(key);
2838 EXPECT_EQ(0u, map->get(key).size()); 2958 EXPECT_EQ(0u, map->get(key).size());
2839 2959
2840 it->value.append(IntWrapper::create(42)); 2960 it->value.append(IntWrapper::create(42));
2841 EXPECT_EQ(1u, map->get(key).size()); 2961 EXPECT_EQ(1u, map->get(key).size());
2842 2962
2843 Persistent<HeapHashMap<void*, IntVector> > keepAlive(map); 2963 Persistent<HeapHashMap<void*, IntVector> > keepAlive(map);
2844 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 2964 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2845 EXPECT_EQ(1u, map->get(key).size()); 2965 EXPECT_EQ(1u, map->get(key).size());
2846 EXPECT_EQ(0, IntWrapper::s_destructorCalls); 2966 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
2967
2968 keepAlive = nullptr;
2969 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
2970 EXPECT_EQ(1, IntWrapper::s_destructorCalls);
2847 } 2971 }
2848 2972
2849 TEST(heap, GarbageCollectedMixin) 2973 TEST(heap, GarbageCollectedMixin)
2850 { 2974 {
2851 HeapStats initialHeapStats; 2975 HeapStats initialHeapStats;
2852 clearOutOldGarbage(&initialHeapStats); 2976 clearOutOldGarbage(&initialHeapStats);
2853 2977
2854 Persistent<UseMixin> usemixin = UseMixin::create(); 2978 Persistent<UseMixin> usemixin = UseMixin::create();
2855 ASSERT_EQ(0, UseMixin::s_traceCount); 2979 ASSERT_EQ(0, UseMixin::s_traceCount);
2856 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 2980 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after
3055 // Check that the wrapper allocated during finalization is not 3179 // Check that the wrapper allocated during finalization is not
3056 // swept away and zapped later in the same sweeping phase. 3180 // swept away and zapped later in the same sweeping phase.
3057 EXPECT_EQ(42, wrapper->value()); 3181 EXPECT_EQ(42, wrapper->value());
3058 3182
3059 wrapper.clear(); 3183 wrapper.clear();
3060 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3184 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3061 EXPECT_EQ(10, IntWrapper::s_destructorCalls); 3185 EXPECT_EQ(10, IntWrapper::s_destructorCalls);
3062 EXPECT_EQ(512, OneKiloByteObject::s_destructorCalls); 3186 EXPECT_EQ(512, OneKiloByteObject::s_destructorCalls);
3063 } 3187 }
3064 3188
3189 class Fluff {
Mads Ager (chromium) 2014/03/28 11:12:39 Ehm, move meaningful names, please?
Erik Corry 2014/03/30 20:11:36 Done.
3190 public:
3191 Fluff() { }
3192 ~Fluff()
3193 {
3194 ASSERT(!s_wasDestructed);
3195 s_wasDestructed = true;
3196 }
3197 static bool s_wasDestructed;
3198 };
3199
3200 bool Fluff::s_wasDestructed;
3201
3202 TEST(HeapTest, Flaf)
Mads Ager (chromium) 2014/03/28 11:12:39 DestructorsCalledOnMapClear?
Erik Corry 2014/03/30 20:11:36 Done.
3203 {
3204 HeapHashMap<Fluff*, OwnPtr<Fluff> > map;
3205 Fluff* fluff = new Fluff();
3206 map.add(fluff, adoptPtr(fluff));
3207 Fluff::s_wasDestructed = false;
3208 map.clear();
3209 ASSERT(Fluff::s_wasDestructed);
3210 }
3211
3065 } // WebCore namespace 3212 } // WebCore namespace
OLDNEW
« no previous file with comments | « Source/heap/Heap.h ('k') | Source/heap/Visitor.h » ('j') | Source/wtf/HashTable.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698