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

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: 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
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;
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
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 {
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
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
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 TEST(HeapTest, TypesWithCustomWeaknessHandling)
4057 {
4058 HeapHashSet<PairWithWeakHandling> set;
4059 HeapHashSet<PairWithWeakHandling>* set2 = new HeapHashSet<PairWithWeakHandli ng>();
4060 Persistent<HeapHashSet<PairWithWeakHandling> > set3(new HeapHashSet<PairWith WeakHandling>());
4061 Persistent<IntWrapper> livingInt(IntWrapper::create(42));
4062 set.add(PairWithWeakHandling(IntWrapper::create(0), IntWrapper::create(1)));
4063 set2->add(PairWithWeakHandling(IntWrapper::create(2), IntWrapper::create(3)) );
4064 set3->add(PairWithWeakHandling(IntWrapper::create(4), IntWrapper::create(5)) );
4065 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
4066 typedef HeapHashSet<PairWithWeakHandling>::iterator Iterator;
4067 // The first set is on-stack, so its backing store must be referenced from
4068 // the stack. That makes the weak references strong.
4069 Iterator i = set.begin();
4070 EXPECT_EQ(0, i->first->value());
4071 EXPECT_EQ(1, i->second->value());
4072 // The second set is pointed to from the stack, so it's referenced, but the
4073 // weak processing may have taken place.
4074 if (set2->size()) {
4075 Iterator i2 = set2->begin();
4076 EXPECT_EQ(2, i2->first->value());
4077 EXPECT_EQ(3, i2->second->value());
4078 }
4079 // The second set is pointed to from a persistent, so it's referenced, but
4080 // the weak processing may have taken place.
4081 if (set3->size()) {
4082 Iterator i3 = set3->begin();
4083 EXPECT_EQ(4, i3->first->value());
4084 EXPECT_EQ(5, i3->second->value());
4085 }
4086 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4087 // No looking at the set and set2 now, they are busted by our lying about th e heap pointers on the stack!
4088 if (set3->size()) {
4089 Iterator i3 = set3->begin();
4090 EXPECT_EQ(4, i3->first->value());
4091 EXPECT_EQ(5, i3->second->value());
4092 }
4093 set3->clear();
4094 set3->add(PairWithWeakHandling(IntWrapper::create(103), livingInt));
4095 set3->add(PairWithWeakHandling(livingInt, IntWrapper::create(103))); // This one gets zapped at GC time because nothing holds the 103 alive.
4096 set3->add(PairWithWeakHandling(IntWrapper::create(103), IntWrapper::create(1 03))); // This one gets zapped too.
4097 set3->add(PairWithWeakHandling(livingInt, livingInt));
4098 set3->add(PairWithWeakHandling(livingInt, livingInt)); // This one is identi cal to the previous and doesn't add anything.
4099 EXPECT_EQ(4u, set3->size());
4100 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4101 EXPECT_EQ(2u, set3->size());
4102 Iterator i3 = set3->begin();
4103 EXPECT_TRUE(i3->first->value() == 103 || i3->first == livingInt);
4104 EXPECT_EQ(livingInt, i3->second);
4105 ++i3;
4106 EXPECT_TRUE(i3->first->value() == 103 || i3->first == livingInt);
4107 EXPECT_EQ(livingInt, i3->second);
4108 }
4109
3981 } // WebCore namespace 4110 } // WebCore namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698