blob: 80144d2c09b21c86f85ccd73cc20eba5663f2cf0 [file] [log] [blame]
Vladimir Marko69f08ba2014-04-11 12:28:11 +01001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
David Sehr1ce2b3b2018-04-05 11:02:03 -070017#ifndef ART_LIBARTBASE_BASE_SCOPED_ARENA_CONTAINERS_H_
18#define ART_LIBARTBASE_BASE_SCOPED_ARENA_CONTAINERS_H_
Vladimir Marko69f08ba2014-04-11 12:28:11 +010019
Vladimir Marko622bdbe2014-06-19 14:59:05 +010020#include <deque>
21#include <queue>
Vladimir Marko69f08ba2014-04-11 12:28:11 +010022#include <set>
Andreas Gampe784e7902015-10-23 17:31:36 -070023#include <type_traits>
Mathieu Chartiere401d142015-04-22 13:56:20 -070024#include <unordered_map>
Vladimir Marko1f497642015-10-05 20:34:42 +010025#include <utility>
Vladimir Marko69f08ba2014-04-11 12:28:11 +010026
Mathieu Chartierb666f482015-02-18 14:33:14 -080027#include "arena_containers.h" // For ArenaAllocatorAdapterKind.
David Sehr1979c642018-04-26 14:41:18 -070028#include "dchecked_vector.h"
29#include "safe_map.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070030#include "scoped_arena_allocator.h"
Vladimir Marko69f08ba2014-04-11 12:28:11 +010031
32namespace art {
33
Vladimir Marko8081d2b2014-07-31 15:33:43 +010034// Adapter for use of ScopedArenaAllocator in STL containers.
35// Use ScopedArenaAllocator::Adapter() to create an adapter to pass to container constructors.
36// For example,
37// void foo(ScopedArenaAllocator* allocator) {
38// ScopedArenaVector<int> foo_vector(allocator->Adapter(kArenaAllocMisc));
39// ScopedArenaSafeMap<int, int> foo_map(std::less<int>(), allocator->Adapter());
40// // Use foo_vector and foo_map...
41// }
42template <typename T>
43class ScopedArenaAllocatorAdapter;
44
Vladimir Marko69f08ba2014-04-11 12:28:11 +010045template <typename T>
Vladimir Marko622bdbe2014-06-19 14:59:05 +010046using ScopedArenaDeque = std::deque<T, ScopedArenaAllocatorAdapter<T>>;
47
48template <typename T>
49using ScopedArenaQueue = std::queue<T, ScopedArenaDeque<T>>;
50
51template <typename T>
Vladimir Markoec7802a2015-10-01 20:57:57 +010052using ScopedArenaVector = dchecked_vector<T, ScopedArenaAllocatorAdapter<T>>;
Vladimir Marko69f08ba2014-04-11 12:28:11 +010053
Ian Rogers700a4022014-05-19 16:49:03 -070054template <typename T, typename Comparator = std::less<T>>
Vladimir Markoe764d2e2017-10-05 14:35:55 +010055using ScopedArenaPriorityQueue = std::priority_queue<T, ScopedArenaVector<T>, Comparator>;
56
57template <typename T>
58using ScopedArenaStdStack = std::stack<T, ScopedArenaDeque<T>>;
59
60template <typename T, typename Comparator = std::less<T>>
Ian Rogers700a4022014-05-19 16:49:03 -070061using ScopedArenaSet = std::set<T, Comparator, ScopedArenaAllocatorAdapter<T>>;
Vladimir Marko69f08ba2014-04-11 12:28:11 +010062
Ian Rogers700a4022014-05-19 16:49:03 -070063template <typename K, typename V, typename Comparator = std::less<K>>
Vladimir Marko69f08ba2014-04-11 12:28:11 +010064using ScopedArenaSafeMap =
Ian Rogers700a4022014-05-19 16:49:03 -070065 SafeMap<K, V, Comparator, ScopedArenaAllocatorAdapter<std::pair<const K, V>>>;
Vladimir Marko69f08ba2014-04-11 12:28:11 +010066
Vladimir Markoca6fff82017-10-03 14:49:14 +010067template <typename T,
68 typename EmptyFn = DefaultEmptyFn<T>,
Vladimir Marko54159c62018-06-20 14:30:08 +010069 typename HashFn = DefaultHashFn<T>,
70 typename Pred = DefaultPred<T>>
Vladimir Markoca6fff82017-10-03 14:49:14 +010071using ScopedArenaHashSet = HashSet<T, EmptyFn, HashFn, Pred, ScopedArenaAllocatorAdapter<T>>;
72
73template <typename Key,
74 typename Value,
75 typename EmptyFn = DefaultEmptyFn<std::pair<Key, Value>>,
Vladimir Marko54159c62018-06-20 14:30:08 +010076 typename HashFn = DefaultHashFn<Key>,
77 typename Pred = DefaultPred<Key>>
Vladimir Markoca6fff82017-10-03 14:49:14 +010078using ScopedArenaHashMap = HashMap<Key,
79 Value,
80 EmptyFn,
81 HashFn,
82 Pred,
83 ScopedArenaAllocatorAdapter<std::pair<Key, Value>>>;
84
Mathieu Chartiere401d142015-04-22 13:56:20 -070085template <typename K, typename V, class Hash = std::hash<K>, class KeyEqual = std::equal_to<K>>
86using ScopedArenaUnorderedMap =
87 std::unordered_map<K, V, Hash, KeyEqual, ScopedArenaAllocatorAdapter<std::pair<const K, V>>>;
88
David Srbecky159c9dd2018-05-24 14:56:51 +010089template <typename K, typename V, class Hash = std::hash<K>, class KeyEqual = std::equal_to<K>>
90using ScopedArenaUnorderedMultimap =
91 std::unordered_multimap<K,
92 V,
93 Hash,
94 KeyEqual,
95 ScopedArenaAllocatorAdapter<std::pair<const K, V>>>;
96
Vladimir Marko8081d2b2014-07-31 15:33:43 +010097// Implementation details below.
98
99template <>
100class ScopedArenaAllocatorAdapter<void>
101 : private DebugStackReference, private DebugStackIndirectTopRef,
102 private ArenaAllocatorAdapterKind {
103 public:
104 typedef void value_type;
105 typedef void* pointer;
106 typedef const void* const_pointer;
107
108 template <typename U>
109 struct rebind {
110 typedef ScopedArenaAllocatorAdapter<U> other;
111 };
112
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100113 explicit ScopedArenaAllocatorAdapter(ScopedArenaAllocator* allocator,
Vladimir Marko8081d2b2014-07-31 15:33:43 +0100114 ArenaAllocKind kind = kArenaAllocSTL)
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100115 : DebugStackReference(allocator),
116 DebugStackIndirectTopRef(allocator),
Vladimir Marko8081d2b2014-07-31 15:33:43 +0100117 ArenaAllocatorAdapterKind(kind),
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100118 arena_stack_(allocator->arena_stack_) {
Vladimir Marko8081d2b2014-07-31 15:33:43 +0100119 }
120 template <typename U>
Igor Murashkin5573c372017-11-16 13:34:30 -0800121 ScopedArenaAllocatorAdapter(const ScopedArenaAllocatorAdapter<U>& other)
Vladimir Marko8081d2b2014-07-31 15:33:43 +0100122 : DebugStackReference(other),
123 DebugStackIndirectTopRef(other),
124 ArenaAllocatorAdapterKind(other),
125 arena_stack_(other.arena_stack_) {
126 }
Andreas Gampec801f0d2015-02-24 20:55:16 -0800127 ScopedArenaAllocatorAdapter(const ScopedArenaAllocatorAdapter&) = default;
128 ScopedArenaAllocatorAdapter& operator=(const ScopedArenaAllocatorAdapter&) = default;
Vladimir Marko8081d2b2014-07-31 15:33:43 +0100129 ~ScopedArenaAllocatorAdapter() = default;
130
131 private:
132 ArenaStack* arena_stack_;
133
134 template <typename U>
135 friend class ScopedArenaAllocatorAdapter;
136};
137
138template <typename T>
139class ScopedArenaAllocatorAdapter
140 : private DebugStackReference, private DebugStackIndirectTopRef,
141 private ArenaAllocatorAdapterKind {
142 public:
143 typedef T value_type;
144 typedef T* pointer;
145 typedef T& reference;
146 typedef const T* const_pointer;
147 typedef const T& const_reference;
148 typedef size_t size_type;
149 typedef ptrdiff_t difference_type;
150
151 template <typename U>
152 struct rebind {
153 typedef ScopedArenaAllocatorAdapter<U> other;
154 };
155
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100156 explicit ScopedArenaAllocatorAdapter(ScopedArenaAllocator* allocator,
Vladimir Marko8081d2b2014-07-31 15:33:43 +0100157 ArenaAllocKind kind = kArenaAllocSTL)
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100158 : DebugStackReference(allocator),
159 DebugStackIndirectTopRef(allocator),
Vladimir Marko8081d2b2014-07-31 15:33:43 +0100160 ArenaAllocatorAdapterKind(kind),
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100161 arena_stack_(allocator->arena_stack_) {
Vladimir Marko8081d2b2014-07-31 15:33:43 +0100162 }
163 template <typename U>
Igor Murashkin5573c372017-11-16 13:34:30 -0800164 ScopedArenaAllocatorAdapter(const ScopedArenaAllocatorAdapter<U>& other)
Vladimir Marko8081d2b2014-07-31 15:33:43 +0100165 : DebugStackReference(other),
166 DebugStackIndirectTopRef(other),
167 ArenaAllocatorAdapterKind(other),
168 arena_stack_(other.arena_stack_) {
169 }
Andreas Gampec801f0d2015-02-24 20:55:16 -0800170 ScopedArenaAllocatorAdapter(const ScopedArenaAllocatorAdapter&) = default;
171 ScopedArenaAllocatorAdapter& operator=(const ScopedArenaAllocatorAdapter&) = default;
Vladimir Marko8081d2b2014-07-31 15:33:43 +0100172 ~ScopedArenaAllocatorAdapter() = default;
173
174 size_type max_size() const {
175 return static_cast<size_type>(-1) / sizeof(T);
176 }
177
178 pointer address(reference x) const { return &x; }
179 const_pointer address(const_reference x) const { return &x; }
180
Roland Levillain4b8f1ec2015-08-26 18:34:03 +0100181 pointer allocate(size_type n,
182 ScopedArenaAllocatorAdapter<void>::pointer hint ATTRIBUTE_UNUSED = nullptr) {
Vladimir Marko8081d2b2014-07-31 15:33:43 +0100183 DCHECK_LE(n, max_size());
184 DebugStackIndirectTopRef::CheckTop();
185 return reinterpret_cast<T*>(arena_stack_->Alloc(n * sizeof(T),
186 ArenaAllocatorAdapterKind::Kind()));
187 }
188 void deallocate(pointer p, size_type n) {
189 DebugStackIndirectTopRef::CheckTop();
Vladimir Marko2a408a32015-09-18 14:11:00 +0100190 arena_stack_->MakeInaccessible(p, sizeof(T) * n);
Vladimir Marko8081d2b2014-07-31 15:33:43 +0100191 }
192
Vladimir Marko1f497642015-10-05 20:34:42 +0100193 template <typename U, typename... Args>
194 void construct(U* p, Args&&... args) {
Vladimir Marko8081d2b2014-07-31 15:33:43 +0100195 // Don't CheckTop(), allow reusing existing capacity of a vector/deque below the top.
Vladimir Marko1f497642015-10-05 20:34:42 +0100196 ::new (static_cast<void*>(p)) U(std::forward<Args>(args)...);
Vladimir Marko8081d2b2014-07-31 15:33:43 +0100197 }
Vladimir Marko1f497642015-10-05 20:34:42 +0100198 template <typename U>
199 void destroy(U* p) {
Vladimir Marko8081d2b2014-07-31 15:33:43 +0100200 // Don't CheckTop(), allow reusing existing capacity of a vector/deque below the top.
Vladimir Marko1f497642015-10-05 20:34:42 +0100201 p->~U();
Vladimir Marko8081d2b2014-07-31 15:33:43 +0100202 }
203
204 private:
205 ArenaStack* arena_stack_;
206
207 template <typename U>
208 friend class ScopedArenaAllocatorAdapter;
209
210 template <typename U>
211 friend bool operator==(const ScopedArenaAllocatorAdapter<U>& lhs,
212 const ScopedArenaAllocatorAdapter<U>& rhs);
213};
214
215template <typename T>
216inline bool operator==(const ScopedArenaAllocatorAdapter<T>& lhs,
217 const ScopedArenaAllocatorAdapter<T>& rhs) {
218 return lhs.arena_stack_ == rhs.arena_stack_;
219}
220
221template <typename T>
222inline bool operator!=(const ScopedArenaAllocatorAdapter<T>& lhs,
223 const ScopedArenaAllocatorAdapter<T>& rhs) {
224 return !(lhs == rhs);
225}
226
227inline ScopedArenaAllocatorAdapter<void> ScopedArenaAllocator::Adapter(ArenaAllocKind kind) {
228 return ScopedArenaAllocatorAdapter<void>(this, kind);
229}
230
Mathieu Chartier7b05e172015-10-15 17:47:48 -0700231// Special deleter that only calls the destructor. Also checks for double free errors.
232template <typename T>
233class ArenaDelete {
234 static constexpr uint8_t kMagicFill = 0xCE;
Mathieu Chartier88177602016-02-17 11:04:20 -0800235
Mathieu Chartier361e04a2016-02-16 14:06:35 -0800236 protected:
237 // Used for variable sized objects such as RegisterLine.
238 ALWAYS_INLINE void ProtectMemory(T* ptr, size_t size) const {
Roland Levillain05e34f42018-05-24 13:19:05 +0000239 if (kRunningOnMemoryTool) {
Mathieu Chartier88177602016-02-17 11:04:20 -0800240 // Writing to the memory will fail ift we already destroyed the pointer with
Mathieu Chartier7b05e172015-10-15 17:47:48 -0700241 // DestroyOnlyDelete since we make it no access.
Mathieu Chartier361e04a2016-02-16 14:06:35 -0800242 memset(ptr, kMagicFill, size);
243 MEMORY_TOOL_MAKE_NOACCESS(ptr, size);
Mathieu Chartier7b05e172015-10-15 17:47:48 -0700244 } else if (kIsDebugBuild) {
245 CHECK(ArenaStack::ArenaTagForAllocation(reinterpret_cast<void*>(ptr)) == ArenaFreeTag::kUsed)
246 << "Freeing invalid object " << ptr;
247 ArenaStack::ArenaTagForAllocation(reinterpret_cast<void*>(ptr)) = ArenaFreeTag::kFree;
248 // Write a magic value to try and catch use after free error.
Mathieu Chartier361e04a2016-02-16 14:06:35 -0800249 memset(ptr, kMagicFill, size);
Mathieu Chartier7b05e172015-10-15 17:47:48 -0700250 }
251 }
Mathieu Chartier361e04a2016-02-16 14:06:35 -0800252
253 public:
254 void operator()(T* ptr) const {
Mathieu Chartier88177602016-02-17 11:04:20 -0800255 if (ptr != nullptr) {
256 ptr->~T();
257 ProtectMemory(ptr, sizeof(T));
258 }
Mathieu Chartier361e04a2016-02-16 14:06:35 -0800259 }
Mathieu Chartier7b05e172015-10-15 17:47:48 -0700260};
261
Andreas Gampe784e7902015-10-23 17:31:36 -0700262// In general we lack support for arrays. We would need to call the destructor on each element,
263// which requires access to the array size. Support for that is future work.
264//
265// However, we can support trivially destructible component types, as then a destructor doesn't
266// need to be called.
Mathieu Chartier7b05e172015-10-15 17:47:48 -0700267template <typename T>
268class ArenaDelete<T[]> {
269 public:
Andreas Gampe784e7902015-10-23 17:31:36 -0700270 void operator()(T* ptr ATTRIBUTE_UNUSED) const {
271 static_assert(std::is_trivially_destructible<T>::value,
272 "ArenaUniquePtr does not support non-trivially-destructible arrays.");
273 // TODO: Implement debug checks, and MEMORY_TOOL support.
274 }
Mathieu Chartier7b05e172015-10-15 17:47:48 -0700275};
276
277// Arena unique ptr that only calls the destructor of the element.
278template <typename T>
279using ArenaUniquePtr = std::unique_ptr<T, ArenaDelete<T>>;
280
Vladimir Marko69f08ba2014-04-11 12:28:11 +0100281} // namespace art
282
David Sehr1ce2b3b2018-04-05 11:02:03 -0700283#endif // ART_LIBARTBASE_BASE_SCOPED_ARENA_CONTAINERS_H_