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

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

Issue 319593004: Oilpan:Allow custom handling of classes that contain weak pointers that are embedded in collections. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Remove 'typename' that Win compiler does not like Created 6 years, 6 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
« no previous file with comments | « Source/platform/heap/Heap.h ('k') | Source/platform/heap/Visitor.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 26 matching lines...) Expand all
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 "public/platform/Platform.h"
40 #include "wtf/HashTraits.h" 40 #include "wtf/HashTraits.h"
41 #include "wtf/LinkedHashSet.h" 41 #include "wtf/LinkedHashSet.h"
42 42
43 #include <gtest/gtest.h> 43 #include <gtest/gtest.h>
44 44
45 namespace WebCore { 45 namespace WebCore {
46 46
47 class IntWrapper : public GarbageCollectedFinalized<IntWrapper> {
48 public:
49 static IntWrapper* create(int x)
50 {
51 return new IntWrapper(x);
52 }
53
54 virtual ~IntWrapper()
55 {
56 ++s_destructorCalls;
57 }
58
59 static int s_destructorCalls;
60 static void trace(Visitor*) { }
61
62 int value() const { return m_x; }
63
64 bool operator==(const IntWrapper& other) const { return other.value() == val ue(); }
65
66 unsigned hash() { return IntHash<int>::hash(m_x); }
67
68 protected:
69 IntWrapper(int x) : m_x(x) { }
70
71 private:
72 IntWrapper();
73 int m_x;
74 };
75
76 USED_FROM_MULTIPLE_THREADS(IntWrapper);
77
47 class ThreadMarker { 78 class ThreadMarker {
48 public: 79 public:
49 ThreadMarker() : m_creatingThread(reinterpret_cast<ThreadState*>(0)), m_num( 0) { } 80 ThreadMarker() : m_creatingThread(reinterpret_cast<ThreadState*>(0)), m_num( 0) { }
50 ThreadMarker(unsigned i) : m_creatingThread(ThreadState::current()), m_num(i ) { } 81 ThreadMarker(unsigned i) : m_creatingThread(ThreadState::current()), m_num(i ) { }
51 ThreadMarker(WTF::HashTableDeletedValueType deleted) : m_creatingThread(rein terpret_cast<ThreadState*>(-1)), m_num(0) { } 82 ThreadMarker(WTF::HashTableDeletedValueType deleted) : m_creatingThread(rein terpret_cast<ThreadState*>(-1)), m_num(0) { }
52 ~ThreadMarker() 83 ~ThreadMarker()
53 { 84 {
54 EXPECT_TRUE((m_creatingThread == ThreadState::current()) 85 EXPECT_TRUE((m_creatingThread == ThreadState::current())
55 || (m_creatingThread == reinterpret_cast<ThreadState*>(0)) 86 || (m_creatingThread == reinterpret_cast<ThreadState*>(0))
56 || (m_creatingThread == reinterpret_cast<ThreadState*>(-1))); 87 || (m_creatingThread == reinterpret_cast<ThreadState*>(-1)));
(...skipping 11 matching lines...) Expand all
68 } 99 }
69 100
70 static bool equal(const ThreadMarker& a, const ThreadMarker& b) 101 static bool equal(const ThreadMarker& a, const ThreadMarker& b)
71 { 102 {
72 return a == b; 103 return a == b;
73 } 104 }
74 105
75 static const bool safeToCompareToEmptyOrDeleted = false; 106 static const bool safeToCompareToEmptyOrDeleted = false;
76 }; 107 };
77 108
109 typedef std::pair<Member<IntWrapper>, WeakMember<IntWrapper> > StrongWeakPair;
110
111 struct PairWithWeakHandling : public StrongWeakPair {
112 ALLOW_ONLY_INLINE_ALLOCATION();
113
114 public:
115 // Regular constructor.
116 PairWithWeakHandling(IntWrapper* one, IntWrapper* two)
117 : StrongWeakPair(one, two)
118 {
119 ASSERT(one); // We use null first field to indicate empty slots in the h ash table.
120 }
121
122 // The HashTable (via the HashTrait) calls this constructor with a
123 // placement new to mark slots in the hash table as being deleted. We will
124 // never call trace or the destructor on these slots. We mark ourselves dele ted
125 // with a pointer to -1 in the first field.
126 PairWithWeakHandling(WTF::HashTableDeletedValueType)
127 : StrongWeakPair(reinterpret_cast<IntWrapper*>(-1), nullptr)
128 {
129 }
130
131 // Used by the HashTable (via the HashTrait) to skip deleted slots in the
132 // table. Recognizes objects that were 'constructed' using the above
133 // constructor.
134 bool isHashTableDeletedValue() const { return first == reinterpret_cast<IntW rapper*>(-1); }
135
136 // Since we don't allocate independent objects of this type, we don't need
137 // a regular trace method. Instead, we use a traceInCollection method.
138 void traceInCollection(Visitor* visitor, ShouldWeakPointersBeMarkedStrongly strongify)
139 {
140 visitor->trace(first);
141 visitor->traceInCollection(second, strongify);
142 }
143 // The traceInCollection may not trace the weak members, so it is vital
144 // that shouldRemoveFromCollection checks them so the entry can be removed
145 // from the collection (otherwise it would contain a dangling pointer).
146 bool shouldRemoveFromCollection(Visitor* visitor)
147 {
148 return !visitor->isAlive(second);
149 }
150 };
151
78 } 152 }
79 153
80 namespace WTF { 154 namespace WTF {
81 155
82 template<typename T> struct DefaultHash; 156 template<typename T> struct DefaultHash;
83 template<> struct DefaultHash<WebCore::ThreadMarker> { 157 template<> struct DefaultHash<WebCore::ThreadMarker> {
84 typedef WebCore::ThreadMarkerHash Hash; 158 typedef WebCore::ThreadMarkerHash Hash;
85 }; 159 };
86 160
87 // ThreadMarkerHash is the default hash for ThreadMarker 161 // ThreadMarkerHash is the default hash for ThreadMarker
88 template<> struct HashTraits<WebCore::ThreadMarker> : GenericHashTraits<WebCore: :ThreadMarker> { 162 template<> struct HashTraits<WebCore::ThreadMarker> : GenericHashTraits<WebCore: :ThreadMarker> {
89 static const bool emptyValueIsZero = true; 163 static const bool emptyValueIsZero = true;
90 static void constructDeletedValue(WebCore::ThreadMarker& slot) { new (NotNul l, &slot) WebCore::ThreadMarker(HashTableDeletedValue); } 164 static void constructDeletedValue(WebCore::ThreadMarker& slot) { new (NotNul l, &slot) WebCore::ThreadMarker(HashTableDeletedValue); }
91 static bool isDeletedValue(const WebCore::ThreadMarker& slot) { return slot. isHashTableDeletedValue(); } 165 static bool isDeletedValue(const WebCore::ThreadMarker& slot) { return slot. isHashTableDeletedValue(); }
92 }; 166 };
93 167
168 // The hash algorithm for our custom pair class is just the standard double
169 // hash for pairs. Note that this means you can't mutate either of the parts of
170 // the pair while they are in the hash table, as that would change their hash
171 // code and thus their preferred placement in the table.
172 template<> struct DefaultHash<WebCore::PairWithWeakHandling> {
173 typedef PairHash<WebCore::Member<WebCore::IntWrapper>, WebCore::WeakMember<W ebCore::IntWrapper> > Hash;
174 };
175
176 // Custom traits for the pair. These are weakness handling traits, which means
177 // PairWithWeakHandling must implement the traceInCollection and
178 // shouldRemoveFromCollection methods. In addition, these traits are concerned
179 // with the two magic values for the object, that represent empty and deleted
180 // slots in the hash table. The SimpleClassHashTraits allow empty slots in the
181 // table to be initialzed with memset to zero, and we use -1 in the first part
182 // of the pair to represent deleted slots.
183 template<> struct HashTraits<WebCore::PairWithWeakHandling> : WebCore::WeakHandl ingHashTraits<WebCore::PairWithWeakHandling> {
184 static const bool needsDestruction = false;
185 static const bool hasIsEmptyValueFunction = true;
186 static bool isEmptyValue(const WebCore::PairWithWeakHandling& value) { retur n !value.first; }
187 static void constructDeletedValue(WebCore::PairWithWeakHandling& slot) { new (NotNull, &slot) WebCore::PairWithWeakHandling(HashTableDeletedValue); }
188 static bool isDeletedValue(const WebCore::PairWithWeakHandling& value) { ret urn value.isHashTableDeletedValue(); }
189 };
190
94 } 191 }
95 192
96 namespace WebCore { 193 namespace WebCore {
97 194
98 class TestGCScope { 195 class TestGCScope {
99 public: 196 public:
100 explicit TestGCScope(ThreadState::StackState state) 197 explicit TestGCScope(ThreadState::StackState state)
101 : m_state(ThreadState::current()) 198 : m_state(ThreadState::current())
102 , m_safePointScope(state) 199 , m_safePointScope(state)
103 , m_parkedAllThreads(false) 200 , m_parkedAllThreads(false)
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
286 while (true) { 383 while (true) {
287 getHeapStats(heapStats); 384 getHeapStats(heapStats);
288 size_t used = heapStats->totalObjectSpace(); 385 size_t used = heapStats->totalObjectSpace();
289 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 386 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
290 getHeapStats(heapStats); 387 getHeapStats(heapStats);
291 if (heapStats->totalObjectSpace() >= used) 388 if (heapStats->totalObjectSpace() >= used)
292 break; 389 break;
293 } 390 }
294 } 391 }
295 392
296 class IntWrapper : public GarbageCollectedFinalized<IntWrapper> {
297 public:
298 static IntWrapper* create(int x)
299 {
300 return new IntWrapper(x);
301 }
302
303 virtual ~IntWrapper()
304 {
305 ++s_destructorCalls;
306 }
307
308 static int s_destructorCalls;
309 static void trace(Visitor*) { }
310
311 int value() const { return m_x; }
312
313 bool operator==(const IntWrapper& other) const { return other.value() == val ue(); }
314
315 unsigned hash() { return IntHash<int>::hash(m_x); }
316
317 protected:
318 IntWrapper(int x) : m_x(x) { }
319
320 private:
321 IntWrapper();
322 int m_x;
323 };
324
325 class OffHeapInt : public RefCounted<OffHeapInt> { 393 class OffHeapInt : public RefCounted<OffHeapInt> {
326 public: 394 public:
327 static RefPtr<OffHeapInt> create(int x) 395 static RefPtr<OffHeapInt> create(int x)
328 { 396 {
329 return adoptRef(new OffHeapInt(x)); 397 return adoptRef(new OffHeapInt(x));
330 } 398 }
331 399
332 virtual ~OffHeapInt() 400 virtual ~OffHeapInt()
333 { 401 {
334 ++s_destructorCalls; 402 ++s_destructorCalls;
335 } 403 }
336 404
337 static int s_destructorCalls; 405 static int s_destructorCalls;
338 406
339 int value() const { return m_x; } 407 int value() const { return m_x; }
340 408
341 bool operator==(const OffHeapInt& other) const { return other.value() == val ue(); } 409 bool operator==(const OffHeapInt& other) const { return other.value() == val ue(); }
342 410
343 unsigned hash() { return IntHash<int>::hash(m_x); } 411 unsigned hash() { return IntHash<int>::hash(m_x); }
344 412
345 protected: 413 protected:
346 OffHeapInt(int x) : m_x(x) { } 414 OffHeapInt(int x) : m_x(x) { }
347 415
348 private: 416 private:
349 OffHeapInt(); 417 OffHeapInt();
350 int m_x; 418 int m_x;
351 }; 419 };
352 420
353 USED_FROM_MULTIPLE_THREADS(IntWrapper);
354
355 int IntWrapper::s_destructorCalls = 0; 421 int IntWrapper::s_destructorCalls = 0;
356 int OffHeapInt::s_destructorCalls = 0; 422 int OffHeapInt::s_destructorCalls = 0;
357 423
358 class ThreadedTesterBase { 424 class ThreadedTesterBase {
359 protected: 425 protected:
360 static void test(ThreadedTesterBase* tester) 426 static void test(ThreadedTesterBase* tester)
361 { 427 {
362 for (int i = 0; i < numberOfThreads; i++) 428 for (int i = 0; i < numberOfThreads; i++)
363 createThread(&threadFunc, tester, "testing thread"); 429 createThread(&threadFunc, tester, "testing thread");
364 while (tester->m_threadsToFinish) { 430 while (tester->m_threadsToFinish) {
(...skipping 2944 matching lines...) Expand 10 before | Expand all | Expand 10 after
3309 } 3375 }
3310 // This forces a GC without stack scanning which results in the objects 3376 // This forces a GC without stack scanning which results in the objects
3311 // being collected. This will also rebuild the above mentioned freelists, 3377 // being collected. This will also rebuild the above mentioned freelists,
3312 // however we don't rely on that below since we don't have any allocations. 3378 // however we don't rely on that below since we don't have any allocations.
3313 clearOutOldGarbage(&initialHeapStats); 3379 clearOutOldGarbage(&initialHeapStats);
3314 { 3380 {
3315 TestGCScope scope(ThreadState::HeapPointersOnStack); 3381 TestGCScope scope(ThreadState::HeapPointersOnStack);
3316 EXPECT_TRUE(scope.allThreadsParked()); 3382 EXPECT_TRUE(scope.allThreadsParked());
3317 Heap::makeConsistentForGC(); 3383 Heap::makeConsistentForGC();
3318 for (size_t i = 0; i < objectAddresses.size(); i++) { 3384 for (size_t i = 0; i < objectAddresses.size(); i++) {
3319 EXPECT_FALSE(Heap::checkAndMarkPointer(&visitor, objectAddresses[i]) ); 3385 // We would like to assert that checkAndMarkPointer returned false
3320 EXPECT_FALSE(Heap::checkAndMarkPointer(&visitor, endAddresses[i])); 3386 // here because the pointers no longer point into a valid object
3387 // (it's been freed by the GCs. But checkAndMarkPointer will return
3388 // true for any pointer that points into a heap page, regardless of
3389 // whether it points at a valid object (this ensures the
3390 // correctness of the page-based on-heap address caches), so we
3391 // can't make that assert.
3392 Heap::checkAndMarkPointer(&visitor, objectAddresses[i]);
3393 Heap::checkAndMarkPointer(&visitor, endAddresses[i]);
3321 } 3394 }
3322 EXPECT_EQ(0ul, visitor.count()); 3395 EXPECT_EQ(0ul, visitor.count());
3323 EXPECT_FALSE(Heap::checkAndMarkPointer(&visitor, largeObjectAddress)); 3396 Heap::checkAndMarkPointer(&visitor, largeObjectAddress);
3324 EXPECT_FALSE(Heap::checkAndMarkPointer(&visitor, largeObjectEndAddress)) ; 3397 Heap::checkAndMarkPointer(&visitor, largeObjectEndAddress);
3325 EXPECT_EQ(0ul, visitor.count()); 3398 EXPECT_EQ(0ul, visitor.count());
3326 } 3399 }
3327 // This round of GC is important to make sure that the object start 3400 // This round of GC is important to make sure that the object start
3328 // bitmap are cleared out and that the free lists are rebuild. 3401 // bitmap are cleared out and that the free lists are rebuild.
3329 clearOutOldGarbage(&initialHeapStats); 3402 clearOutOldGarbage(&initialHeapStats);
3330 } 3403 }
3331 3404
3332 TEST(HeapTest, VisitOffHeapCollections) 3405 TEST(HeapTest, VisitOffHeapCollections)
3333 { 3406 {
3334 HeapStats initialHeapStats; 3407 HeapStats initialHeapStats;
(...skipping 636 matching lines...) Expand 10 before | Expand all | Expand 10 after
3971 4044
3972 // class SimpleObject : public GarbageCollected<SimpleObject> {}; 4045 // class SimpleObject : public GarbageCollected<SimpleObject> {};
3973 EXPECT_FALSE(NeedsAdjustAndMark<SimpleObject>::value); 4046 EXPECT_FALSE(NeedsAdjustAndMark<SimpleObject>::value);
3974 EXPECT_FALSE(NeedsAdjustAndMark<const SimpleObject>::value); 4047 EXPECT_FALSE(NeedsAdjustAndMark<const SimpleObject>::value);
3975 4048
3976 // class UseMixin : public SimpleObject, public Mixin {}; 4049 // class UseMixin : public SimpleObject, public Mixin {};
3977 EXPECT_FALSE(NeedsAdjustAndMark<UseMixin>::value); 4050 EXPECT_FALSE(NeedsAdjustAndMark<UseMixin>::value);
3978 EXPECT_FALSE(NeedsAdjustAndMark<const UseMixin>::value); 4051 EXPECT_FALSE(NeedsAdjustAndMark<const UseMixin>::value);
3979 } 4052 }
3980 4053
4054 template<typename Set>
4055 void setWithCustomWeaknessHandling()
4056 {
4057 typedef typename Set::iterator Iterator;
4058 Persistent<IntWrapper> livingInt(IntWrapper::create(42));
4059 Persistent<Set> set1(new Set());
4060 {
4061 Set set2;
4062 Set* set3 = new Set();
4063 set2.add(PairWithWeakHandling(IntWrapper::create(0), IntWrapper::create( 1)));
4064 set3->add(PairWithWeakHandling(IntWrapper::create(2), IntWrapper::create (3)));
4065 set1->add(PairWithWeakHandling(IntWrapper::create(4), IntWrapper::create (5)));
4066 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
4067 // The first set is pointed to from a persistent, so it's referenced, bu t
4068 // the weak processing may have taken place.
4069 if (set1->size()) {
4070 Iterator i1 = set1->begin();
4071 EXPECT_EQ(4, i1->first->value());
4072 EXPECT_EQ(5, i1->second->value());
4073 }
4074 // The second set is on-stack, so its backing store must be referenced f rom
4075 // the stack. That makes the weak references strong.
4076 Iterator i2 = set2.begin();
4077 EXPECT_EQ(0, i2->first->value());
4078 EXPECT_EQ(1, i2->second->value());
4079 // The third set is pointed to from the stack, so it's referenced, but t he
4080 // weak processing may have taken place.
4081 if (set3->size()) {
4082 Iterator i3 = set3->begin();
4083 EXPECT_EQ(2, i3->first->value());
4084 EXPECT_EQ(3, i3->second->value());
4085 }
4086 }
4087 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4088 EXPECT_EQ(0u, set1->size());
4089 set1->add(PairWithWeakHandling(IntWrapper::create(103), livingInt));
4090 set1->add(PairWithWeakHandling(livingInt, IntWrapper::create(103))); // This one gets zapped at GC time because nothing holds the 103 alive.
4091 set1->add(PairWithWeakHandling(IntWrapper::create(103), IntWrapper::create(1 03))); // This one gets zapped too.
4092 set1->add(PairWithWeakHandling(livingInt, livingInt));
4093 set1->add(PairWithWeakHandling(livingInt, livingInt)); // This one is identi cal to the previous and doesn't add anything.
4094 EXPECT_EQ(4u, set1->size());
4095 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4096 EXPECT_EQ(2u, set1->size());
4097 Iterator i1 = set1->begin();
4098 EXPECT_TRUE(i1->first->value() == 103 || i1->first == livingInt);
4099 EXPECT_EQ(livingInt, i1->second);
4100 ++i1;
4101 EXPECT_TRUE(i1->first->value() == 103 || i1->first == livingInt);
4102 EXPECT_EQ(livingInt, i1->second);
4103 }
4104
4105 TEST(HeapTest, SetWithCustomWeaknessHandling)
4106 {
4107 setWithCustomWeaknessHandling<HeapHashSet<PairWithWeakHandling> >();
4108 setWithCustomWeaknessHandling<HeapLinkedHashSet<PairWithWeakHandling> >();
4109 }
4110
4111 TEST(HeapTest, MapWithCustomWeaknessHandling)
4112 {
4113 typedef HeapHashMap<PairWithWeakHandling, RefPtr<OffHeapInt> > Map;
4114 typedef Map::iterator Iterator;
4115 HeapStats initialHeapSize;
4116 clearOutOldGarbage(&initialHeapSize);
4117 OffHeapInt::s_destructorCalls = 0;
4118
4119 Persistent<Map> map1(new Map());
4120 Persistent<IntWrapper> livingInt(IntWrapper::create(42));
4121 {
4122 Map map2;
4123 Map* map3 = new Map();
4124 map2.add(PairWithWeakHandling(IntWrapper::create(0), IntWrapper::create( 1)), OffHeapInt::create(1001));
4125 map3->add(PairWithWeakHandling(IntWrapper::create(2), IntWrapper::create (3)), OffHeapInt::create(1002));
4126 map1->add(PairWithWeakHandling(IntWrapper::create(4), IntWrapper::create (5)), OffHeapInt::create(1003));
4127 EXPECT_EQ(0, OffHeapInt::s_destructorCalls);
4128
4129 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
4130 // The first map2 is pointed to from a persistent, so it's referenced, b ut
4131 // the weak processing may have taken place.
4132 if (map1->size()) {
4133 Iterator i1 = map1->begin();
4134 EXPECT_EQ(4, i1->key.first->value());
4135 EXPECT_EQ(5, i1->key.second->value());
4136 EXPECT_EQ(1003, i1->value->value());
4137 }
4138 // The second map2 is on-stack, so its backing store must be referenced from
4139 // the stack. That makes the weak references strong.
4140 Iterator i2 = map2.begin();
4141 EXPECT_EQ(0, i2->key.first->value());
4142 EXPECT_EQ(1, i2->key.second->value());
4143 EXPECT_EQ(1001, i2->value->value());
4144 // The third map2 is pointed to from the stack, so it's referenced, but the
4145 // weak processing may have taken place.
4146 if (map3->size()) {
4147 Iterator i3 = map3->begin();
4148 EXPECT_EQ(2, i3->key.first->value());
4149 EXPECT_EQ(3, i3->key.second->value());
4150 EXPECT_EQ(1002, i3->value->value());
4151 }
4152 }
4153 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4154
4155 EXPECT_EQ(0u, map1->size());
4156 EXPECT_EQ(3, OffHeapInt::s_destructorCalls);
4157
4158 OffHeapInt::s_destructorCalls = 0;
4159
4160 map1->add(PairWithWeakHandling(IntWrapper::create(103), livingInt), OffHeapI nt::create(2000));
4161 map1->add(PairWithWeakHandling(livingInt, IntWrapper::create(103)), OffHeapI nt::create(2001)); // This one gets zapped at GC time because nothing holds the 103 alive.
4162 map1->add(PairWithWeakHandling(IntWrapper::create(103), IntWrapper::create(1 03)), OffHeapInt::create(2002)); // This one gets zapped too.
4163 RefPtr<OffHeapInt> dupeInt(OffHeapInt::create(2003));
4164 map1->add(PairWithWeakHandling(livingInt, livingInt), dupeInt);
4165 map1->add(PairWithWeakHandling(livingInt, livingInt), dupeInt); // This one is identical to the previous and doesn't add anything.
4166 dupeInt.clear();
4167
4168 EXPECT_EQ(0, OffHeapInt::s_destructorCalls);
4169 EXPECT_EQ(4u, map1->size());
4170 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4171 EXPECT_EQ(2, OffHeapInt::s_destructorCalls);
4172 EXPECT_EQ(2u, map1->size());
4173 Iterator i1 = map1->begin();
4174 EXPECT_TRUE(i1->key.first->value() == 103 || i1->key.first == livingInt);
4175 EXPECT_EQ(livingInt, i1->key.second);
4176 ++i1;
4177 EXPECT_TRUE(i1->key.first->value() == 103 || i1->key.first == livingInt);
4178 EXPECT_EQ(livingInt, i1->key.second);
4179 }
4180
4181 TEST(HeapTest, MapWithCustomWeaknessHandling2)
4182 {
4183 typedef HeapHashMap<RefPtr<OffHeapInt>, PairWithWeakHandling> Map;
4184 typedef Map::iterator Iterator;
4185 HeapStats initialHeapSize;
4186 clearOutOldGarbage(&initialHeapSize);
4187 OffHeapInt::s_destructorCalls = 0;
4188
4189 Persistent<Map> map1(new Map());
4190 Persistent<IntWrapper> livingInt(IntWrapper::create(42));
4191
4192 {
4193 Map map2;
4194 Map* map3 = new Map();
4195 map2.add(OffHeapInt::create(1001), PairWithWeakHandling(IntWrapper::crea te(0), IntWrapper::create(1)));
4196 map3->add(OffHeapInt::create(1002), PairWithWeakHandling(IntWrapper::cre ate(2), IntWrapper::create(3)));
4197 map1->add(OffHeapInt::create(1003), PairWithWeakHandling(IntWrapper::cre ate(4), IntWrapper::create(5)));
4198 EXPECT_EQ(0, OffHeapInt::s_destructorCalls);
4199
4200 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
4201 // The first map2 is pointed to from a persistent, so it's referenced, b ut
4202 // the weak processing may have taken place.
4203 if (map1->size()) {
4204 Iterator i1 = map1->begin();
4205 EXPECT_EQ(4, i1->value.first->value());
4206 EXPECT_EQ(5, i1->value.second->value());
4207 EXPECT_EQ(1003, i1->key->value());
4208 }
4209 // The second map2 is on-stack, so its backing store must be referenced from
4210 // the stack. That makes the weak references strong.
4211 Iterator i2 = map2.begin();
4212 EXPECT_EQ(0, i2->value.first->value());
4213 EXPECT_EQ(1, i2->value.second->value());
4214 EXPECT_EQ(1001, i2->key->value());
4215 // The third map2 is pointed to from the stack, so it's referenced, but the
4216 // weak processing may have taken place.
4217 if (map3->size()) {
4218 Iterator i3 = map3->begin();
4219 EXPECT_EQ(2, i3->value.first->value());
4220 EXPECT_EQ(3, i3->value.second->value());
4221 EXPECT_EQ(1002, i3->key->value());
4222 }
4223 }
4224 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4225
4226 EXPECT_EQ(0u, map1->size());
4227 EXPECT_EQ(3, OffHeapInt::s_destructorCalls);
4228
4229 OffHeapInt::s_destructorCalls = 0;
4230
4231 map1->add(OffHeapInt::create(2000), PairWithWeakHandling(IntWrapper::create( 103), livingInt));
4232 map1->add(OffHeapInt::create(2001), PairWithWeakHandling(livingInt, IntWrapp er::create(103))); // This one gets zapped at GC time because nothing holds the 103 alive.
4233 map1->add(OffHeapInt::create(2002), PairWithWeakHandling(IntWrapper::create( 103), IntWrapper::create(103))); // This one gets zapped too.
4234 RefPtr<OffHeapInt> dupeInt(OffHeapInt::create(2003));
4235 map1->add(dupeInt, PairWithWeakHandling(livingInt, livingInt));
4236 map1->add(dupeInt, PairWithWeakHandling(livingInt, livingInt)); // This one is identical to the previous and doesn't add anything.
4237 dupeInt.clear();
4238
4239 EXPECT_EQ(0, OffHeapInt::s_destructorCalls);
4240 EXPECT_EQ(4u, map1->size());
4241 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4242 EXPECT_EQ(2, OffHeapInt::s_destructorCalls);
4243 EXPECT_EQ(2u, map1->size());
4244 Iterator i1 = map1->begin();
4245 EXPECT_TRUE(i1->value.first->value() == 103 || i1->value.first == livingInt) ;
4246 EXPECT_EQ(livingInt, i1->value.second);
4247 ++i1;
4248 EXPECT_TRUE(i1->value.first->value() == 103 || i1->value.first == livingInt) ;
4249 EXPECT_EQ(livingInt, i1->value.second);
4250 }
4251
3981 TEST(HeapTest, Bind) 4252 TEST(HeapTest, Bind)
3982 { 4253 {
3983 Closure closure = bind(&Bar::trace, Bar::create(), static_cast<Visitor*>(0)) ; 4254 Closure closure = bind(&Bar::trace, Bar::create(), static_cast<Visitor*>(0)) ;
3984 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4255 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3985 // The closure should have a persistent handle to the Bar. 4256 // The closure should have a persistent handle to the Bar.
3986 EXPECT_EQ(1u, Bar::s_live); 4257 EXPECT_EQ(1u, Bar::s_live);
3987 4258
3988 Closure closure2 = bind(&Bar::trace, RawPtr<Bar>(Bar::create()), static_cast <Visitor*>(0)); 4259 Closure closure2 = bind(&Bar::trace, RawPtr<Bar>(Bar::create()), static_cast <Visitor*>(0));
3989 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4260 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3990 // The closure should have a persistent handle to the Bar. 4261 // The closure should have a persistent handle to the Bar.
3991 EXPECT_EQ(2u, Bar::s_live); 4262 EXPECT_EQ(2u, Bar::s_live);
3992 4263
3993 UseMixin::s_traceCount = 0; 4264 UseMixin::s_traceCount = 0;
3994 Mixin* mixin = UseMixin::create(); 4265 Mixin* mixin = UseMixin::create();
3995 Closure mixinClosure = bind(&Mixin::trace, mixin, static_cast<Visitor*>(0)); 4266 Closure mixinClosure = bind(&Mixin::trace, mixin, static_cast<Visitor*>(0));
3996 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4267 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3997 // The closure should have a persistent handle to the mixin. 4268 // The closure should have a persistent handle to the mixin.
3998 EXPECT_EQ(1, UseMixin::s_traceCount); 4269 EXPECT_EQ(1, UseMixin::s_traceCount);
3999 } 4270 }
4000 4271
4001 } // WebCore namespace 4272 } // WebCore namespace
OLDNEW
« no previous file with comments | « Source/platform/heap/Heap.h ('k') | Source/platform/heap/Visitor.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698