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 26 matching lines...) Expand all Loading... | |
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; | |
Mads Ager (chromium)
2014/06/06 09:59:17
Can we just move IntWrapper to right after ThreadM
Erik Corry
2014/06/10 11:21:18
Done.
| |
48 | |
47 class ThreadMarker { | 49 class ThreadMarker { |
48 public: | 50 public: |
49 ThreadMarker() : m_creatingThread(reinterpret_cast<ThreadState*>(0)), m_num( 0) { } | 51 ThreadMarker() : m_creatingThread(reinterpret_cast<ThreadState*>(0)), m_num( 0) { } |
50 ThreadMarker(unsigned i) : m_creatingThread(ThreadState::current()), m_num(i ) { } | 52 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) { } | 53 ThreadMarker(WTF::HashTableDeletedValueType deleted) : m_creatingThread(rein terpret_cast<ThreadState*>(-1)), m_num(0) { } |
52 ~ThreadMarker() | 54 ~ThreadMarker() |
53 { | 55 { |
54 EXPECT_TRUE((m_creatingThread == ThreadState::current()) | 56 EXPECT_TRUE((m_creatingThread == ThreadState::current()) |
55 || (m_creatingThread == reinterpret_cast<ThreadState*>(0)) | 57 || (m_creatingThread == reinterpret_cast<ThreadState*>(0)) |
56 || (m_creatingThread == reinterpret_cast<ThreadState*>(-1))); | 58 || (m_creatingThread == reinterpret_cast<ThreadState*>(-1))); |
(...skipping 11 matching lines...) Expand all Loading... | |
68 } | 70 } |
69 | 71 |
70 static bool equal(const ThreadMarker& a, const ThreadMarker& b) | 72 static bool equal(const ThreadMarker& a, const ThreadMarker& b) |
71 { | 73 { |
72 return a == b; | 74 return a == b; |
73 } | 75 } |
74 | 76 |
75 static const bool safeToCompareToEmptyOrDeleted = false; | 77 static const bool safeToCompareToEmptyOrDeleted = false; |
76 }; | 78 }; |
77 | 79 |
80 typedef std::pair<Member<IntWrapper>, WeakMember<IntWrapper> > StrongWeakPair; | |
81 | |
82 struct PairWithWeakHandling : public StrongWeakPair { | |
Mads Ager (chromium)
2014/06/06 09:59:17
This is clever since it shuts up the gc plugin. ;-
Erik Corry
2014/06/10 11:21:18
OK
| |
83 ALLOW_ONLY_INLINE_ALLOCATION(); | |
84 | |
85 public: | |
86 // Regular constructor. | |
87 PairWithWeakHandling(IntWrapper* one, IntWrapper* two) | |
88 : StrongWeakPair(one, two) | |
89 { | |
90 ASSERT(one); // We use null first field to indicate empty slots in the h ash table. | |
91 } | |
92 | |
93 // The HashTable (via the HashTrait) calls this constructor with a | |
94 // placement new to mark slots in the hash table as being deleted. We will | |
95 // never call trace or the destructor on these slots. We mark ourselves dele ted | |
96 // with a pointer to -1 in the first field. | |
97 PairWithWeakHandling(WTF::HashTableDeletedValueType) | |
98 : StrongWeakPair(reinterpret_cast<IntWrapper*>(-1), nullptr) | |
99 { | |
100 } | |
101 | |
102 // Used by the HashTable (via the HashTrait) to skip deleted slots in the | |
103 // table. Recognizes objects that were 'constructed' using the above | |
104 // constructor. | |
105 bool isHashTableDeletedValue() const { return first == reinterpret_cast<IntW rapper*>(-1); } | |
106 | |
107 // Since we don't allocate independent objects of this type, we don't need | |
108 // a regular trace method. Instead, we use a traceInCollection method. | |
109 void traceInCollection(Visitor* visitor, ShouldWeakPointersBeMarkedStrongly strongify) | |
110 { | |
111 visitor->trace(first); | |
112 visitor->traceInCollection(second, strongify); | |
113 } | |
114 // The traceInCollection may not trace the weak members, so it is vital | |
115 // that shouldRemoveFromCollection checks them so the entry can be removed | |
116 // from the collection (otherwise it would contain a dangling pointer). | |
117 bool shouldRemoveFromCollection(Visitor* visitor) | |
118 { | |
119 return !visitor->isAlive(second); | |
120 } | |
121 }; | |
122 | |
78 } | 123 } |
79 | 124 |
80 namespace WTF { | 125 namespace WTF { |
81 | 126 |
82 template<typename T> struct DefaultHash; | 127 template<typename T> struct DefaultHash; |
83 template<> struct DefaultHash<WebCore::ThreadMarker> { | 128 template<> struct DefaultHash<WebCore::ThreadMarker> { |
84 typedef WebCore::ThreadMarkerHash Hash; | 129 typedef WebCore::ThreadMarkerHash Hash; |
85 }; | 130 }; |
86 | 131 |
87 // ThreadMarkerHash is the default hash for ThreadMarker | 132 // ThreadMarkerHash is the default hash for ThreadMarker |
88 template<> struct HashTraits<WebCore::ThreadMarker> : GenericHashTraits<WebCore: :ThreadMarker> { | 133 template<> struct HashTraits<WebCore::ThreadMarker> : GenericHashTraits<WebCore: :ThreadMarker> { |
89 static const bool emptyValueIsZero = true; | 134 static const bool emptyValueIsZero = true; |
90 static void constructDeletedValue(WebCore::ThreadMarker& slot) { new (NotNul l, &slot) WebCore::ThreadMarker(HashTableDeletedValue); } | 135 static void constructDeletedValue(WebCore::ThreadMarker& slot) { new (NotNul l, &slot) WebCore::ThreadMarker(HashTableDeletedValue); } |
91 static bool isDeletedValue(const WebCore::ThreadMarker& slot) { return slot. isHashTableDeletedValue(); } | 136 static bool isDeletedValue(const WebCore::ThreadMarker& slot) { return slot. isHashTableDeletedValue(); } |
92 }; | 137 }; |
93 | 138 |
139 // The hash algorithm for our custom pair class is just the standard double | |
140 // hash for pairs. Note that this means you can't mutate either of the parts of | |
141 // the pair while they are in the hash table, as that would change their hash | |
142 // code and thus their preferred placement in the table. | |
143 template<> struct DefaultHash<WebCore::PairWithWeakHandling> { | |
144 typedef PairHash<WebCore::Member<WebCore::IntWrapper>, WebCore::WeakMember<W ebCore::IntWrapper> > Hash; | |
145 }; | |
146 | |
147 // Custom traits for the pair. These are weakness handling traits, which means | |
148 // PairWithWeakHandling must implement the traceInCollection and | |
149 // shouldRemoveFromCollection methods. In addition, these traits are concerned | |
150 // with the two magic values for the object, that represent empty and deleted | |
151 // slots in the hash table. The SimpleClassHashTraits allow empty slots in the | |
152 // table to be initialzed with memset to zero, and we use -1 in the first part | |
153 // of the pair to represent deleted slots. | |
154 template<> struct HashTraits<WebCore::PairWithWeakHandling> : WebCore::WeakHandl ingHashTraits<WebCore::PairWithWeakHandling> { | |
155 static const bool needsDestruction = false; | |
156 static const bool hasIsEmptyValueFunction = true; | |
157 static bool isEmptyValue(const WebCore::PairWithWeakHandling& value) { retur n !value.first; } | |
158 static void constructDeletedValue(WebCore::PairWithWeakHandling& slot) { new (NotNull, &slot) WebCore::PairWithWeakHandling(HashTableDeletedValue); } | |
159 static bool isDeletedValue(const WebCore::PairWithWeakHandling& value) { ret urn value.isHashTableDeletedValue(); } | |
160 }; | |
161 | |
94 } | 162 } |
95 | 163 |
96 namespace WebCore { | 164 namespace WebCore { |
97 | 165 |
98 class TestGCScope { | 166 class TestGCScope { |
99 public: | 167 public: |
100 explicit TestGCScope(ThreadState::StackState state) | 168 explicit TestGCScope(ThreadState::StackState state) |
101 : m_state(ThreadState::current()) | 169 : m_state(ThreadState::current()) |
102 , m_safePointScope(state) | 170 , m_safePointScope(state) |
103 , m_parkedAllThreads(false) | 171 , m_parkedAllThreads(false) |
(...skipping 3205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3309 } | 3377 } |
3310 // This forces a GC without stack scanning which results in the objects | 3378 // This forces a GC without stack scanning which results in the objects |
3311 // being collected. This will also rebuild the above mentioned freelists, | 3379 // 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. | 3380 // however we don't rely on that below since we don't have any allocations. |
3313 clearOutOldGarbage(&initialHeapStats); | 3381 clearOutOldGarbage(&initialHeapStats); |
3314 { | 3382 { |
3315 TestGCScope scope(ThreadState::HeapPointersOnStack); | 3383 TestGCScope scope(ThreadState::HeapPointersOnStack); |
3316 EXPECT_TRUE(scope.allThreadsParked()); | 3384 EXPECT_TRUE(scope.allThreadsParked()); |
3317 Heap::makeConsistentForGC(); | 3385 Heap::makeConsistentForGC(); |
3318 for (size_t i = 0; i < objectAddresses.size(); i++) { | 3386 for (size_t i = 0; i < objectAddresses.size(); i++) { |
3319 EXPECT_FALSE(Heap::checkAndMarkPointer(&visitor, objectAddresses[i]) ); | 3387 // We would like to assert that checkAndMarkPointer returned false |
3320 EXPECT_FALSE(Heap::checkAndMarkPointer(&visitor, endAddresses[i])); | 3388 // here because the pointers no longer point into a valid object |
3389 // (it's been freed by the GCs. But checkAndMarkPointer will return | |
3390 // true for any pointer that points into a heap page, regardless of | |
3391 // whether it points at a valid object (this ensures the | |
3392 // correctness of the page-based on-heap address caches), so we | |
3393 // can't make that assert. | |
3394 Heap::checkAndMarkPointer(&visitor, objectAddresses[i]); | |
3395 Heap::checkAndMarkPointer(&visitor, endAddresses[i]); | |
3321 } | 3396 } |
3322 EXPECT_EQ(0ul, visitor.count()); | 3397 EXPECT_EQ(0ul, visitor.count()); |
3323 EXPECT_FALSE(Heap::checkAndMarkPointer(&visitor, largeObjectAddress)); | 3398 Heap::checkAndMarkPointer(&visitor, largeObjectAddress); |
3324 EXPECT_FALSE(Heap::checkAndMarkPointer(&visitor, largeObjectEndAddress)) ; | 3399 Heap::checkAndMarkPointer(&visitor, largeObjectEndAddress); |
3325 EXPECT_EQ(0ul, visitor.count()); | 3400 EXPECT_EQ(0ul, visitor.count()); |
3326 } | 3401 } |
3327 // This round of GC is important to make sure that the object start | 3402 // 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. | 3403 // bitmap are cleared out and that the free lists are rebuild. |
3329 clearOutOldGarbage(&initialHeapStats); | 3404 clearOutOldGarbage(&initialHeapStats); |
3330 } | 3405 } |
3331 | 3406 |
3332 TEST(HeapTest, VisitOffHeapCollections) | 3407 TEST(HeapTest, VisitOffHeapCollections) |
3333 { | 3408 { |
3334 HeapStats initialHeapStats; | 3409 HeapStats initialHeapStats; |
(...skipping 636 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3971 | 4046 |
3972 // class SimpleObject : public GarbageCollected<SimpleObject> {}; | 4047 // class SimpleObject : public GarbageCollected<SimpleObject> {}; |
3973 EXPECT_FALSE(NeedsAdjustAndMark<SimpleObject>::value); | 4048 EXPECT_FALSE(NeedsAdjustAndMark<SimpleObject>::value); |
3974 EXPECT_FALSE(NeedsAdjustAndMark<const SimpleObject>::value); | 4049 EXPECT_FALSE(NeedsAdjustAndMark<const SimpleObject>::value); |
3975 | 4050 |
3976 // class UseMixin : public SimpleObject, public Mixin {}; | 4051 // class UseMixin : public SimpleObject, public Mixin {}; |
3977 EXPECT_FALSE(NeedsAdjustAndMark<UseMixin>::value); | 4052 EXPECT_FALSE(NeedsAdjustAndMark<UseMixin>::value); |
3978 EXPECT_FALSE(NeedsAdjustAndMark<const UseMixin>::value); | 4053 EXPECT_FALSE(NeedsAdjustAndMark<const UseMixin>::value); |
3979 } | 4054 } |
3980 | 4055 |
4056 template<typename Set> | |
4057 void setWithCustomWeaknessHandling() | |
4058 { | |
4059 Set set; | |
4060 Set* set2 = new Set(); | |
4061 Persistent<Set> set3(new Set()); | |
4062 Persistent<IntWrapper> livingInt(IntWrapper::create(42)); | |
4063 set.add(PairWithWeakHandling(IntWrapper::create(0), IntWrapper::create(1))); | |
4064 set2->add(PairWithWeakHandling(IntWrapper::create(2), IntWrapper::create(3)) ); | |
4065 set3->add(PairWithWeakHandling(IntWrapper::create(4), IntWrapper::create(5)) ); | |
4066 Heap::collectGarbage(ThreadState::HeapPointersOnStack); | |
4067 typedef typename Set::iterator Iterator; | |
4068 // The first set is on-stack, so its backing store must be referenced from | |
4069 // the stack. That makes the weak references strong. | |
4070 Iterator i = set.begin(); | |
4071 EXPECT_EQ(0, i->first->value()); | |
4072 EXPECT_EQ(1, i->second->value()); | |
4073 // The second set is pointed to from the stack, so it's referenced, but the | |
4074 // weak processing may have taken place. | |
4075 if (set2->size()) { | |
4076 Iterator i2 = set2->begin(); | |
4077 EXPECT_EQ(2, i2->first->value()); | |
4078 EXPECT_EQ(3, i2->second->value()); | |
4079 } | |
4080 // The third set is pointed to from a persistent, so it's referenced, but | |
4081 // the weak processing may have taken place. | |
4082 if (set3->size()) { | |
4083 Iterator i3 = set3->begin(); | |
4084 EXPECT_EQ(4, i3->first->value()); | |
4085 EXPECT_EQ(5, i3->second->value()); | |
4086 } | |
4087 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); | |
4088 // No looking at the set and set2 now, they are busted by our lying about th e heap pointers on the stack! | |
Mads Ager (chromium)
2014/06/06 09:59:17
How about scoping them so we can't touch them?
Erik Corry
2014/06/10 11:21:18
Done.
| |
4089 if (set3->size()) { | |
Mads Ager (chromium)
2014/06/06 09:59:17
Since we ignore all heap pointers on the stack thi
Erik Corry
2014/06/10 11:21:18
Done.
| |
4090 Iterator i3 = set3->begin(); | |
4091 EXPECT_EQ(4, i3->first->value()); | |
4092 EXPECT_EQ(5, i3->second->value()); | |
4093 } | |
4094 set3->clear(); | |
Mads Ager (chromium)
2014/06/06 09:59:17
And then this is not needed.
Erik Corry
2014/06/10 11:21:18
Done.
| |
4095 set3->add(PairWithWeakHandling(IntWrapper::create(103), livingInt)); | |
4096 set3->add(PairWithWeakHandling(livingInt, IntWrapper::create(103))); // This one gets zapped at GC time because nothing holds the 103 alive. | |
4097 set3->add(PairWithWeakHandling(IntWrapper::create(103), IntWrapper::create(1 03))); // This one gets zapped too. | |
4098 set3->add(PairWithWeakHandling(livingInt, livingInt)); | |
4099 set3->add(PairWithWeakHandling(livingInt, livingInt)); // This one is identi cal to the previous and doesn't add anything. | |
4100 EXPECT_EQ(4u, set3->size()); | |
4101 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); | |
4102 EXPECT_EQ(2u, set3->size()); | |
4103 Iterator i3 = set3->begin(); | |
4104 EXPECT_TRUE(i3->first->value() == 103 || i3->first == livingInt); | |
4105 EXPECT_EQ(livingInt, i3->second); | |
4106 ++i3; | |
4107 EXPECT_TRUE(i3->first->value() == 103 || i3->first == livingInt); | |
4108 EXPECT_EQ(livingInt, i3->second); | |
4109 } | |
4110 | |
4111 TEST(HeapTest, SetWithCustomWeaknessHandling) | |
4112 { | |
4113 setWithCustomWeaknessHandling<HeapHashSet<PairWithWeakHandling> >(); | |
4114 setWithCustomWeaknessHandling<HeapLinkedHashSet<PairWithWeakHandling> >(); | |
4115 } | |
4116 | |
4117 TEST(HeapTest, MapWithCustomWeaknessHandling) | |
4118 { | |
4119 typedef HeapHashMap<PairWithWeakHandling, RefPtr<OffHeapInt> > Map; | |
4120 HeapStats initialHeapSize; | |
4121 clearOutOldGarbage(&initialHeapSize); | |
4122 OffHeapInt::s_destructorCalls = 0; | |
4123 | |
4124 Map map; | |
4125 Map* map2 = new Map(); | |
4126 Persistent<Map> map3(new Map()); | |
4127 Persistent<IntWrapper> livingInt(IntWrapper::create(42)); | |
4128 map.add(PairWithWeakHandling(IntWrapper::create(0), IntWrapper::create(1)), OffHeapInt::create(1001)); | |
4129 map2->add(PairWithWeakHandling(IntWrapper::create(2), IntWrapper::create(3)) , OffHeapInt::create(1002)); | |
4130 map3->add(PairWithWeakHandling(IntWrapper::create(4), IntWrapper::create(5)) , OffHeapInt::create(1003)); | |
4131 EXPECT_EQ(0, OffHeapInt::s_destructorCalls); | |
4132 | |
4133 Heap::collectGarbage(ThreadState::HeapPointersOnStack); | |
4134 typedef typename Map::iterator Iterator; | |
4135 // The first map is on-stack, so its backing store must be referenced from | |
4136 // the stack. That makes the weak references strong. | |
4137 Iterator i = map.begin(); | |
4138 EXPECT_EQ(0, i->key.first->value()); | |
4139 EXPECT_EQ(1, i->key.second->value()); | |
4140 EXPECT_EQ(1001, i->value->value()); | |
4141 // The second map is pointed to from the stack, so it's referenced, but the | |
4142 // weak processing may have taken place. | |
4143 if (map2->size()) { | |
4144 Iterator i2 = map2->begin(); | |
4145 EXPECT_EQ(2, i2->key.first->value()); | |
4146 EXPECT_EQ(3, i2->key.second->value()); | |
4147 EXPECT_EQ(1002, i2->value->value()); | |
4148 } | |
4149 // The third map is pointed to from a persistent, so it's referenced, but | |
4150 // the weak processing may have taken place. | |
4151 if (map3->size()) { | |
4152 Iterator i3 = map3->begin(); | |
4153 EXPECT_EQ(4, i3->key.first->value()); | |
4154 EXPECT_EQ(5, i3->key.second->value()); | |
4155 EXPECT_EQ(1003, i3->value->value()); | |
4156 } | |
4157 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); | |
4158 // No looking at the map and map2 now, they are busted by our lying about th e heap pointers on the stack! | |
4159 if (map3->size()) { | |
Mads Ager (chromium)
2014/06/06 09:59:16
Same here. This should be reduced to the EXPECT_EQ
Erik Corry
2014/06/10 11:21:18
Done.
| |
4160 Iterator i3 = map3->begin(); | |
4161 EXPECT_EQ(4, i3->key.first->value()); | |
4162 EXPECT_EQ(5, i3->key.second->value()); | |
4163 EXPECT_EQ(1003, i3->value->value()); | |
4164 EXPECT_EQ(2, OffHeapInt::s_destructorCalls); | |
4165 } else { | |
4166 EXPECT_EQ(3, OffHeapInt::s_destructorCalls); | |
4167 } | |
4168 map3->clear(); | |
4169 | |
4170 EXPECT_EQ(3, OffHeapInt::s_destructorCalls); | |
4171 OffHeapInt::s_destructorCalls = 0; | |
4172 | |
4173 map3->add(PairWithWeakHandling(IntWrapper::create(103), livingInt), OffHeapI nt::create(2000)); | |
4174 map3->add(PairWithWeakHandling(livingInt, IntWrapper::create(103)), OffHeapI nt::create(2001)); // This one gets zapped at GC time because nothing holds the 103 alive. | |
4175 map3->add(PairWithWeakHandling(IntWrapper::create(103), IntWrapper::create(1 03)), OffHeapInt::create(2002)); // This one gets zapped too. | |
4176 RefPtr<OffHeapInt> dupeInt(OffHeapInt::create(2003)); | |
4177 map3->add(PairWithWeakHandling(livingInt, livingInt), dupeInt); | |
4178 map3->add(PairWithWeakHandling(livingInt, livingInt), dupeInt); // This one is identical to the previous and doesn't add anything. | |
4179 dupeInt.clear(); | |
4180 | |
4181 EXPECT_EQ(0, OffHeapInt::s_destructorCalls); | |
4182 EXPECT_EQ(4u, map3->size()); | |
4183 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); | |
4184 EXPECT_EQ(2, OffHeapInt::s_destructorCalls); | |
4185 EXPECT_EQ(2u, map3->size()); | |
4186 Iterator i3 = map3->begin(); | |
4187 EXPECT_TRUE(i3->key.first->value() == 103 || i3->key.first == livingInt); | |
4188 EXPECT_EQ(livingInt, i3->key.second); | |
4189 ++i3; | |
4190 EXPECT_TRUE(i3->key.first->value() == 103 || i3->key.first == livingInt); | |
4191 EXPECT_EQ(livingInt, i3->key.second); | |
4192 } | |
4193 | |
4194 TEST(HeapTest, MapWithCustomWeaknessHandling2) | |
4195 { | |
4196 typedef HeapHashMap<RefPtr<OffHeapInt>, PairWithWeakHandling> Map; | |
4197 HeapStats initialHeapSize; | |
4198 clearOutOldGarbage(&initialHeapSize); | |
4199 OffHeapInt::s_destructorCalls = 0; | |
4200 | |
4201 Map map; | |
4202 Map* map2 = new Map(); | |
4203 Persistent<Map> map3(new Map()); | |
4204 Persistent<IntWrapper> livingInt(IntWrapper::create(42)); | |
4205 map.add(OffHeapInt::create(1001), PairWithWeakHandling(IntWrapper::create(0) , IntWrapper::create(1))); | |
4206 map2->add(OffHeapInt::create(1002), PairWithWeakHandling(IntWrapper::create( 2), IntWrapper::create(3))); | |
4207 map3->add(OffHeapInt::create(1003), PairWithWeakHandling(IntWrapper::create( 4), IntWrapper::create(5))); | |
4208 EXPECT_EQ(0, OffHeapInt::s_destructorCalls); | |
4209 | |
4210 Heap::collectGarbage(ThreadState::HeapPointersOnStack); | |
4211 typedef typename Map::iterator Iterator; | |
4212 // The first map is on-stack, so its backing store must be referenced from | |
4213 // the stack. That makes the weak references strong. | |
4214 Iterator i = map.begin(); | |
4215 EXPECT_EQ(0, i->value.first->value()); | |
4216 EXPECT_EQ(1, i->value.second->value()); | |
4217 EXPECT_EQ(1001, i->key->value()); | |
4218 // The second map is pointed to from the stack, so it's referenced, but the | |
4219 // weak processing may have taken place. | |
4220 if (map2->size()) { | |
4221 Iterator i2 = map2->begin(); | |
4222 EXPECT_EQ(2, i2->value.first->value()); | |
4223 EXPECT_EQ(3, i2->value.second->value()); | |
4224 EXPECT_EQ(1002, i2->key->value()); | |
4225 } | |
4226 // The third map is pointed to from a persistent, so it's referenced, but | |
4227 // the weak processing may have taken place. | |
4228 if (map3->size()) { | |
4229 Iterator i3 = map3->begin(); | |
4230 EXPECT_EQ(4, i3->value.first->value()); | |
4231 EXPECT_EQ(5, i3->value.second->value()); | |
4232 EXPECT_EQ(1003, i3->key->value()); | |
4233 } | |
4234 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); | |
4235 // No looking at the map and map2 now, they are busted by our lying about th e heap pointers on the stack! | |
4236 if (map3->size()) { | |
Mads Ager (chromium)
2014/06/06 09:59:17
This one too.
Erik Corry
2014/06/10 11:21:18
Done.
| |
4237 Iterator i3 = map3->begin(); | |
4238 EXPECT_EQ(4, i3->value.first->value()); | |
4239 EXPECT_EQ(5, i3->value.second->value()); | |
4240 EXPECT_EQ(1003, i3->key->value()); | |
4241 EXPECT_EQ(2, OffHeapInt::s_destructorCalls); | |
4242 } else { | |
4243 EXPECT_EQ(3, OffHeapInt::s_destructorCalls); | |
4244 } | |
4245 map3->clear(); | |
4246 | |
4247 EXPECT_EQ(3, OffHeapInt::s_destructorCalls); | |
4248 OffHeapInt::s_destructorCalls = 0; | |
4249 | |
4250 map3->add(OffHeapInt::create(2000), PairWithWeakHandling(IntWrapper::create( 103), livingInt)); | |
4251 map3->add(OffHeapInt::create(2001), PairWithWeakHandling(livingInt, IntWrapp er::create(103))); // This one gets zapped at GC time because nothing holds the 103 alive. | |
4252 map3->add(OffHeapInt::create(2002), PairWithWeakHandling(IntWrapper::create( 103), IntWrapper::create(103))); // This one gets zapped too. | |
4253 RefPtr<OffHeapInt> dupeInt(OffHeapInt::create(2003)); | |
4254 map3->add(dupeInt, PairWithWeakHandling(livingInt, livingInt)); | |
4255 map3->add(dupeInt, PairWithWeakHandling(livingInt, livingInt)); // This one is identical to the previous and doesn't add anything. | |
4256 dupeInt.clear(); | |
4257 | |
4258 EXPECT_EQ(0, OffHeapInt::s_destructorCalls); | |
4259 EXPECT_EQ(4u, map3->size()); | |
4260 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); | |
4261 EXPECT_EQ(2, OffHeapInt::s_destructorCalls); | |
4262 EXPECT_EQ(2u, map3->size()); | |
4263 Iterator i3 = map3->begin(); | |
4264 EXPECT_TRUE(i3->value.first->value() == 103 || i3->value.first == livingInt) ; | |
4265 EXPECT_EQ(livingInt, i3->value.second); | |
4266 ++i3; | |
4267 EXPECT_TRUE(i3->value.first->value() == 103 || i3->value.first == livingInt) ; | |
4268 EXPECT_EQ(livingInt, i3->value.second); | |
4269 } | |
4270 | |
3981 } // WebCore namespace | 4271 } // WebCore namespace |
OLD | NEW |