blob: 539e6544ef0212db4a59ce849f89ed5f5a498c04 [file] [log] [blame]
John Reck1ed72372015-04-23 15:45:54 -07001/*
2 * Copyright 2012, The Android Open Source Project
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef ANDROID_LINEARALLOCATOR_H
27#define ANDROID_LINEARALLOCATOR_H
28
29#include <stddef.h>
John Reckb5bc4542015-04-23 15:51:55 -070030#include <type_traits>
John Reck1ed72372015-04-23 15:45:54 -070031
Chris Craikb36af872015-10-16 14:23:12 -070032#include <vector>
33
John Reck1ed72372015-04-23 15:45:54 -070034namespace android {
35namespace uirenderer {
36
37/**
38 * A memory manager that internally allocates multi-kbyte buffers for placing objects in. It avoids
39 * the overhead of malloc when many objects are allocated. It is most useful when creating many
40 * small objects with a similar lifetime, and doesn't add significant overhead for large
41 * allocations.
42 */
43class LinearAllocator {
44public:
45 LinearAllocator();
46 ~LinearAllocator();
47
48 /**
49 * Reserves and returns a region of memory of at least size 'size', aligning as needed.
50 * Typically this is used in an object's overridden new() method or as a replacement for malloc.
51 *
52 * The lifetime of the returned buffers is tied to that of the LinearAllocator. If calling
53 * delete() on an object stored in a buffer is needed, it should be overridden to use
54 * rewindIfLastAlloc()
John Reck7df9ff22016-02-10 16:08:08 -080055 *
56 * Note that unlike create, for alloc the type is purely for compile-time error
57 * checking and does not affect size.
John Reck1ed72372015-04-23 15:45:54 -070058 */
John Reck1bcacfd2017-11-03 10:12:19 -070059 template <class T>
John Reck7df9ff22016-02-10 16:08:08 -080060 void* alloc(size_t size) {
61 static_assert(std::is_trivially_destructible<T>::value,
John Reck1bcacfd2017-11-03 10:12:19 -070062 "Error, type is non-trivial! did you mean to use create()?");
John Reck7df9ff22016-02-10 16:08:08 -080063 return allocImpl(size);
64 }
John Reck1ed72372015-04-23 15:45:54 -070065
66 /**
Chris Craike4db79d2015-12-22 16:32:23 -080067 * Allocates an instance of the template type with the given construction parameters
John Reckb5bc4542015-04-23 15:51:55 -070068 * and adds it to the automatic destruction list.
69 */
John Reck1bcacfd2017-11-03 10:12:19 -070070 template <class T, typename... Params>
John Reck7df9ff22016-02-10 16:08:08 -080071 T* create(Params&&... params) {
72 T* ret = new (allocImpl(sizeof(T))) T(std::forward<Params>(params)...);
73 if (!std::is_trivially_destructible<T>::value) {
74 auto dtor = [](void* ret) { ((T*)ret)->~T(); };
75 addToDestructionList(dtor, ret);
76 }
John Reckb5bc4542015-04-23 15:51:55 -070077 return ret;
78 }
79
John Reck1bcacfd2017-11-03 10:12:19 -070080 template <class T, typename... Params>
John Reck7df9ff22016-02-10 16:08:08 -080081 T* create_trivial(Params&&... params) {
82 static_assert(std::is_trivially_destructible<T>::value,
John Reck1bcacfd2017-11-03 10:12:19 -070083 "Error, called create_trivial on a non-trivial type");
John Reck7df9ff22016-02-10 16:08:08 -080084 return new (allocImpl(sizeof(T))) T(std::forward<Params>(params)...);
John Reckb5bc4542015-04-23 15:51:55 -070085 }
86
John Reck1bcacfd2017-11-03 10:12:19 -070087 template <class T>
Chris Craik7a896002016-02-19 15:51:02 -080088 T* create_trivial_array(int count) {
89 static_assert(std::is_trivially_destructible<T>::value,
John Reck1bcacfd2017-11-03 10:12:19 -070090 "Error, called create_trivial_array on a non-trivial type");
Chris Craik7a896002016-02-19 15:51:02 -080091 return reinterpret_cast<T*>(allocImpl(sizeof(T) * count));
92 }
93
John Reckb5bc4542015-04-23 15:51:55 -070094 /**
John Reck1ed72372015-04-23 15:45:54 -070095 * Attempt to deallocate the given buffer, with the LinearAllocator attempting to rewind its
John Reckb5bc4542015-04-23 15:51:55 -070096 * state if possible.
John Reck1ed72372015-04-23 15:45:54 -070097 */
98 void rewindIfLastAlloc(void* ptr, size_t allocSize);
99
100 /**
John Reckb5bc4542015-04-23 15:51:55 -0700101 * Same as rewindIfLastAlloc(void*, size_t)
102 */
John Reck1bcacfd2017-11-03 10:12:19 -0700103 template <class T>
John Reckb5bc4542015-04-23 15:51:55 -0700104 void rewindIfLastAlloc(T* ptr) {
105 rewindIfLastAlloc((void*)ptr, sizeof(T));
106 }
107
108 /**
John Reck1ed72372015-04-23 15:45:54 -0700109 * Dump memory usage statistics to the log (allocated and wasted space)
110 */
111 void dumpMemoryStats(const char* prefix = "");
112
113 /**
114 * The number of bytes used for buffers allocated in the LinearAllocator (does not count space
115 * wasted)
116 */
117 size_t usedSize() const { return mTotalAllocated - mWastedSpace; }
John Reck183e1382019-10-09 13:41:18 -0700118 size_t allocatedSize() const { return mTotalAllocated; }
John Reck1ed72372015-04-23 15:45:54 -0700119
120private:
121 LinearAllocator(const LinearAllocator& other);
122
123 class Page;
John Reckb5bc4542015-04-23 15:51:55 -0700124 typedef void (*Destructor)(void* addr);
125 struct DestructorNode {
126 Destructor dtor;
127 void* addr;
128 DestructorNode* next = nullptr;
129 };
John Reck1ed72372015-04-23 15:45:54 -0700130
John Reck7df9ff22016-02-10 16:08:08 -0800131 void* allocImpl(size_t size);
132
John Reckb5bc4542015-04-23 15:51:55 -0700133 void addToDestructionList(Destructor, void* addr);
134 void runDestructorFor(void* addr);
John Reck1ed72372015-04-23 15:45:54 -0700135 Page* newPage(size_t pageSize);
136 bool fitsInCurrentPage(size_t size);
137 void ensureNext(size_t size);
John Reck1bcacfd2017-11-03 10:12:19 -0700138 void* start(Page* p);
John Reck1ed72372015-04-23 15:45:54 -0700139 void* end(Page* p);
140
141 size_t mPageSize;
142 size_t mMaxAllocSize;
143 void* mNext;
144 Page* mCurrentPage;
145 Page* mPages;
John Reckb5bc4542015-04-23 15:51:55 -0700146 DestructorNode* mDtorList = nullptr;
John Reck1ed72372015-04-23 15:45:54 -0700147
148 // Memory usage tracking
149 size_t mTotalAllocated;
150 size_t mWastedSpace;
151 size_t mPageCount;
152 size_t mDedicatedPageCount;
153};
154
Chris Craik81a1d2a2015-10-15 17:13:00 -0700155template <class T>
156class LinearStdAllocator {
157public:
John Reck1bcacfd2017-11-03 10:12:19 -0700158 typedef T value_type; // needed to implement std::allocator
159 typedef T* pointer; // needed to implement std::allocator
Chris Craik81a1d2a2015-10-15 17:13:00 -0700160
John Reck1bcacfd2017-11-03 10:12:19 -0700161 explicit LinearStdAllocator(LinearAllocator& allocator) : linearAllocator(allocator) {}
162 LinearStdAllocator(const LinearStdAllocator& other) : linearAllocator(other.linearAllocator) {}
Chris Craik81a1d2a2015-10-15 17:13:00 -0700163 ~LinearStdAllocator() {}
164
165 // rebind marks that allocators can be rebound to different types
166 template <class U>
167 struct rebind {
168 typedef LinearStdAllocator<U> other;
169 };
170 // enable allocators to be constructed from other templated types
171 template <class U>
Chih-Hung Hsiehf21b0b62018-12-20 13:48:02 -0800172 LinearStdAllocator(const LinearStdAllocator<U>& other) // NOLINT(google-explicit-constructor)
Chris Craik81a1d2a2015-10-15 17:13:00 -0700173 : linearAllocator(other.linearAllocator) {}
174
175 T* allocate(size_t num, const void* = 0) {
John Reck7df9ff22016-02-10 16:08:08 -0800176 return (T*)(linearAllocator.alloc<void*>(num * sizeof(T)));
Chris Craik81a1d2a2015-10-15 17:13:00 -0700177 }
178
179 void deallocate(pointer p, size_t num) {
180 // attempt to rewind, but no guarantees
181 linearAllocator.rewindIfLastAlloc(p, num * sizeof(T));
182 }
183
184 // public so template copy constructor can access
185 LinearAllocator& linearAllocator;
186};
187
188// return that all specializations of LinearStdAllocator are interchangeable
189template <class T1, class T2>
John Reck1bcacfd2017-11-03 10:12:19 -0700190bool operator==(const LinearStdAllocator<T1>&, const LinearStdAllocator<T2>&) {
191 return true;
192}
Chris Craik81a1d2a2015-10-15 17:13:00 -0700193template <class T1, class T2>
John Reck1bcacfd2017-11-03 10:12:19 -0700194bool operator!=(const LinearStdAllocator<T1>&, const LinearStdAllocator<T2>&) {
195 return false;
196}
Chris Craik81a1d2a2015-10-15 17:13:00 -0700197
Chris Craikb36af872015-10-16 14:23:12 -0700198template <class T>
199class LsaVector : public std::vector<T, LinearStdAllocator<T>> {
200public:
Chih-Hung Hsieha619ec72016-08-29 14:52:43 -0700201 explicit LsaVector(const LinearStdAllocator<T>& allocator)
Chris Craikb36af872015-10-16 14:23:12 -0700202 : std::vector<T, LinearStdAllocator<T>>(allocator) {}
203};
204
Chris Blume7b8a8082018-11-30 15:51:58 -0800205} // namespace uirenderer
206} // namespace android
John Reck1ed72372015-04-23 15:45:54 -0700207
John Reck1bcacfd2017-11-03 10:12:19 -0700208#endif // ANDROID_LINEARALLOCATOR_H