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

Side by Side Diff: third_party/WebKit/Source/platform/graphics/ContiguousContainer.h

Issue 2119033003: Fix alignment issue of ContiguousContainer (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 4 years, 5 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
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #ifndef ContiguousContainer_h 5 #ifndef ContiguousContainer_h
6 #define ContiguousContainer_h 6 #define ContiguousContainer_h
7 7
8 #include "platform/PlatformExport.h" 8 #include "platform/PlatformExport.h"
9 #include "wtf/Alignment.h" 9 #include "wtf/Alignment.h"
10 #include "wtf/Allocator.h" 10 #include "wtf/Allocator.h"
11 #include "wtf/Compiler.h" 11 #include "wtf/Compiler.h"
12 #include "wtf/Noncopyable.h" 12 #include "wtf/Noncopyable.h"
13 #include "wtf/TypeTraits.h" 13 #include "wtf/TypeTraits.h"
14 #include "wtf/Vector.h" 14 #include "wtf/Vector.h"
15 #include <cstddef> 15 #include <cstddef>
16 #include <iterator> 16 #include <iterator>
17 #include <memory> 17 #include <memory>
18 #include <utility> 18 #include <utility>
19 19
20 namespace blink { 20 namespace blink {
21 21
22 namespace internal {
23 template <size_t input> struct Log2 { };
24 template<> struct Log2<1> {
25 static const unsigned value = 0;
26 };
27 template<> struct Log2<2> {
28 static const unsigned value = 1;
29 };
30 template<> struct Log2<4> {
31 static const unsigned value = 2;
32 };
33 template<> struct Log2<8> {
34 static const unsigned value = 3;
35 };
36 template<> struct Log2<16> {
37 static const unsigned value = 4;
38 };
39 }
40
41 template<typename T>
42 unsigned log2Alignment() { return internal::Log2<WTF_ALIGN_OF(T)>::value; }
43
22 // ContiguousContainer is a container which stores a list of heterogeneous 44 // ContiguousContainer is a container which stores a list of heterogeneous
23 // objects (in particular, of varying sizes), packed next to one another in 45 // objects (in particular, of varying sizes), packed next to one another in
24 // memory. Objects are never relocated, so it is safe to store pointers to them 46 // memory. Objects are never relocated, so it is safe to store pointers to them
25 // for the lifetime of the container (unless the object is removed). 47 // for the lifetime of the container (unless the object is removed).
26 // 48 //
27 // Memory is allocated in a series of buffers (with exponential growth). When an 49 // Memory is allocated in a series of buffers (with exponential growth). When an
28 // object is allocated, it is given only the space it requires (possibly with 50 // object is allocated, it is given only the space it requires (possibly with
29 // enough padding to preserve alignment), rather than the maximum possible size. 51 // enough padding to preserve alignment), rather than the maximum possible size.
30 // This allows small and large objects to coexist without wasting much space. 52 // This allows small and large objects to coexist without wasting much space.
31 // 53 //
(...skipping 16 matching lines...) Expand all
48 ContiguousContainerBase& operator=(ContiguousContainerBase&&); 70 ContiguousContainerBase& operator=(ContiguousContainerBase&&);
49 71
50 size_t size() const { return m_elements.size(); } 72 size_t size() const { return m_elements.size(); }
51 bool isEmpty() const { return !size(); } 73 bool isEmpty() const { return !size(); }
52 size_t capacityInBytes() const; 74 size_t capacityInBytes() const;
53 size_t usedCapacityInBytes() const; 75 size_t usedCapacityInBytes() const;
54 size_t memoryUsageInBytes() const; 76 size_t memoryUsageInBytes() const;
55 77
56 // These do not invoke constructors or destructors. 78 // These do not invoke constructors or destructors.
57 void reserveInitialCapacity(size_t, const char* typeName); 79 void reserveInitialCapacity(size_t, const char* typeName);
58 void* allocate(size_t objectSize, const char* typeName); 80 void* allocate(size_t objectSize, unsigned log2Alignment, const char* typeNa me);
59 void removeLast(); 81 void removeLast();
60 void clear(); 82 void clear();
61 void swap(ContiguousContainerBase&); 83 void swap(ContiguousContainerBase&);
62 84
63 Vector<void*> m_elements; 85 Vector<void*> m_elements;
64 86
65 private: 87 private:
66 class Buffer; 88 class Buffer;
67 89
68 Buffer* allocateNewBufferForNextAllocation(size_t, const char* typeName); 90 Buffer* allocateNewBufferForNextAllocation(size_t, const char* typeName);
69 91
70 Vector<std::unique_ptr<Buffer>> m_buffers; 92 Vector<std::unique_ptr<Buffer>> m_buffers;
71 unsigned m_endIndex; 93 unsigned m_endIndex;
72 size_t m_maxObjectSize; 94 size_t m_maxObjectSize;
73 }; 95 };
74 96
75 // For most cases, no alignment stricter than pointer alignment is required. If 97 template <class BaseElementType>
76 // one of the derived classes has stronger alignment requirements (and the
77 // static_assert fires), set alignment to the LCM of the derived class
78 // alignments. For small structs without pointers, it may be possible to reduce
79 // alignment for tighter packing.
80
81 template <class BaseElementType, unsigned alignment = sizeof(void*)>
82 class ContiguousContainer : public ContiguousContainerBase { 98 class ContiguousContainer : public ContiguousContainerBase {
83 private: 99 private:
84 // Declares itself as a forward iterator, but also supports a few more 100 // Declares itself as a forward iterator, but also supports a few more
85 // things. The whole random access iterator interface is a bit much. 101 // things. The whole random access iterator interface is a bit much.
86 template <typename BaseIterator, typename ValueType> 102 template <typename BaseIterator, typename ValueType>
87 class IteratorWrapper : public std::iterator<std::forward_iterator_tag, Valu eType> { 103 class IteratorWrapper : public std::iterator<std::forward_iterator_tag, Valu eType> {
88 DISALLOW_NEW(); 104 DISALLOW_NEW();
89 public: 105 public:
90 IteratorWrapper() {} 106 IteratorWrapper() {}
91 bool operator==(const IteratorWrapper& other) const { return m_it == oth er.m_it; } 107 bool operator==(const IteratorWrapper& other) const { return m_it == oth er.m_it; }
92 bool operator!=(const IteratorWrapper& other) const { return m_it != oth er.m_it; } 108 bool operator!=(const IteratorWrapper& other) const { return m_it != oth er.m_it; }
93 ValueType& operator*() const { return *static_cast<ValueType*>(*m_it); } 109 ValueType& operator*() const { return *static_cast<ValueType*>(*m_it); }
94 ValueType* operator->() const { return &operator*(); } 110 ValueType* operator->() const { return &operator*(); }
95 IteratorWrapper operator+(std::ptrdiff_t n) const { return IteratorWrapp er(m_it + n); } 111 IteratorWrapper operator+(std::ptrdiff_t n) const { return IteratorWrapp er(m_it + n); }
96 IteratorWrapper operator++(int) { IteratorWrapper tmp = *this; ++m_it; r eturn tmp; } 112 IteratorWrapper operator++(int) { IteratorWrapper tmp = *this; ++m_it; r eturn tmp; }
97 std::ptrdiff_t operator-(const IteratorWrapper& other) const { return m_ it - other.m_it; } 113 std::ptrdiff_t operator-(const IteratorWrapper& other) const { return m_ it - other.m_it; }
98 IteratorWrapper& operator++() { ++m_it; return *this; } 114 IteratorWrapper& operator++() { ++m_it; return *this; }
99 private: 115 private:
100 explicit IteratorWrapper(const BaseIterator& it) : m_it(it) {} 116 explicit IteratorWrapper(const BaseIterator& it) : m_it(it) {}
101 BaseIterator m_it; 117 BaseIterator m_it;
102 friend class ContiguousContainer; 118 friend class ContiguousContainer;
103 }; 119 };
104 120
105 public: 121 public:
106 using iterator = IteratorWrapper<Vector<void*>::iterator, BaseElementType>; 122 using iterator = IteratorWrapper<Vector<void*>::iterator, BaseElementType>;
107 using const_iterator = IteratorWrapper<Vector<void*>::const_iterator, const BaseElementType>; 123 using const_iterator = IteratorWrapper<Vector<void*>::const_iterator, const BaseElementType>;
108 using reverse_iterator = IteratorWrapper<Vector<void*>::reverse_iterator, Ba seElementType>; 124 using reverse_iterator = IteratorWrapper<Vector<void*>::reverse_iterator, Ba seElementType>;
109 using const_reverse_iterator = IteratorWrapper<Vector<void*>::const_reverse_ iterator, const BaseElementType>; 125 using const_reverse_iterator = IteratorWrapper<Vector<void*>::const_reverse_ iterator, const BaseElementType>;
110 126
111 explicit ContiguousContainer(size_t maxObjectSize) : ContiguousContainerBase (align(maxObjectSize)) {} 127 explicit ContiguousContainer(size_t maxObjectSize) : ContiguousContainerBase (maxObjectSize) {}
112 128
113 ContiguousContainer(size_t maxObjectSize, size_t initialSizeBytes) 129 ContiguousContainer(size_t maxObjectSize, size_t initialSizeBytes)
114 : ContiguousContainer(maxObjectSize) 130 : ContiguousContainer(maxObjectSize)
115 { 131 {
116 reserveInitialCapacity(std::max(maxObjectSize, initialSizeBytes), WTF_HE AP_PROFILER_TYPE_NAME(BaseElementType)); 132 reserveInitialCapacity(std::max(maxObjectSize, initialSizeBytes), WTF_HE AP_PROFILER_TYPE_NAME(BaseElementType));
117 } 133 }
118 134
119 ContiguousContainer(ContiguousContainer&& source) 135 ContiguousContainer(ContiguousContainer&& source)
120 : ContiguousContainerBase(std::move(source)) {} 136 : ContiguousContainerBase(std::move(source)) {}
121 137
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
157 BaseElementType& last() { return *rbegin(); } 173 BaseElementType& last() { return *rbegin(); }
158 const BaseElementType& last() const { return *rbegin(); } 174 const BaseElementType& last() const { return *rbegin(); }
159 BaseElementType& operator[](size_t index) { return *(begin() + index); } 175 BaseElementType& operator[](size_t index) { return *(begin() + index); }
160 const BaseElementType& operator[](size_t index) const { return *(begin() + i ndex); } 176 const BaseElementType& operator[](size_t index) const { return *(begin() + i ndex); }
161 177
162 template <class DerivedElementType, typename... Args> 178 template <class DerivedElementType, typename... Args>
163 DerivedElementType& allocateAndConstruct(Args&&... args) 179 DerivedElementType& allocateAndConstruct(Args&&... args)
164 { 180 {
165 static_assert(WTF::IsSubclass<DerivedElementType, BaseElementType>::valu e, 181 static_assert(WTF::IsSubclass<DerivedElementType, BaseElementType>::valu e,
166 "Must use subclass of BaseElementType."); 182 "Must use subclass of BaseElementType.");
167 static_assert(alignment % WTF_ALIGN_OF(DerivedElementType) == 0, 183 return *new (allocate(sizeof(DerivedElementType), log2Alignment<DerivedE lementType>()))
168 "Derived type requires stronger alignment."); 184 DerivedElementType(std::forward<Args>(args)...);
169 size_t allocSize = align(sizeof(DerivedElementType));
170 return *new (allocate(allocSize)) DerivedElementType(std::forward<Args>( args)...);
171 } 185 }
172 186
173 void removeLast() 187 void removeLast()
174 { 188 {
175 ASSERT(!isEmpty()); 189 ASSERT(!isEmpty());
176 last().~BaseElementType(); 190 last().~BaseElementType();
177 ContiguousContainerBase::removeLast(); 191 ContiguousContainerBase::removeLast();
178 } 192 }
179 193
180 void clear() 194 void clear()
181 { 195 {
182 for (auto& element : *this) { 196 for (auto& element : *this) {
183 (void)element; // MSVC incorrectly reports this variable as unused. 197 (void)element; // MSVC incorrectly reports this variable as unused.
184 element.~BaseElementType(); 198 element.~BaseElementType();
185 } 199 }
186 ContiguousContainerBase::clear(); 200 ContiguousContainerBase::clear();
187 } 201 }
188 202
189 void swap(ContiguousContainer& other) { ContiguousContainerBase::swap(other) ; } 203 void swap(ContiguousContainer& other) { ContiguousContainerBase::swap(other) ; }
190 204
191 // Appends a new element using memcpy, then default-constructs a base 205 // Appends a new element using memcpy, then default-constructs a base
192 // element in its place. Use with care. 206 // element in its place. Use with care.
193 BaseElementType& appendByMoving(BaseElementType& item, size_t size) 207 BaseElementType& appendByMoving(BaseElementType& item, size_t size, unsigned log2Alignment)
194 { 208 {
195 ASSERT(size >= sizeof(BaseElementType)); 209 ASSERT(size >= sizeof(BaseElementType));
196 void* newItem = allocate(size); 210 void* newItem = allocate(size, log2Alignment);
197 memcpy(newItem, static_cast<void*>(&item), size); 211 memcpy(newItem, static_cast<void*>(&item), size);
198 new (&item) BaseElementType; 212 new (&item) BaseElementType;
199 return *static_cast<BaseElementType*>(newItem); 213 return *static_cast<BaseElementType*>(newItem);
200 } 214 }
201 215
202 private: 216 private:
203 void* allocate(size_t objectSize) 217 FRIEND_TEST_ALL_PREFIXES(ContiguousContainerTest, Alignment);
218
219 void* allocate(size_t objectSize, size_t log2Alignment)
204 { 220 {
205 return ContiguousContainerBase::allocate(objectSize, WTF_HEAP_PROFILER_T YPE_NAME(BaseElementType)); 221 return ContiguousContainerBase::allocate(objectSize, log2Alignment, WTF_ HEAP_PROFILER_TYPE_NAME(BaseElementType));
206 }
207
208 static size_t align(size_t size)
209 {
210 size_t alignedSize = alignment * ((size + alignment - 1) / alignment);
211 ASSERT(alignedSize % alignment == 0);
212 ASSERT(alignedSize >= size);
213 ASSERT(alignedSize < size + alignment);
214 return alignedSize;
215 } 222 }
216 }; 223 };
217 224
218 } // namespace blink 225 } // namespace blink
219 226
220 #endif // ContiguousContainer_h 227 #endif // ContiguousContainer_h
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698