1 /* 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 17 #ifndef ART_DEX2OAT_UTILS_SWAP_SPACE_H_ 18 #define ART_DEX2OAT_UTILS_SWAP_SPACE_H_ 19 20 #include <stddef.h> 21 #include <stdint.h> 22 #include <cstdlib> 23 #include <list> 24 #include <set> 25 #include <vector> 26 27 #include <android-base/logging.h> 28 29 #include "base/logging.h" 30 #include "base/macros.h" 31 #include "base/mutex.h" 32 33 namespace art { 34 35 // An arena pool that creates arenas backed by an mmaped file. 36 class SwapSpace { 37 public: 38 SwapSpace(int fd, size_t initial_size); 39 ~SwapSpace(); 40 void* Alloc(size_t size) REQUIRES(!lock_); 41 void Free(void* ptr, size_t size) REQUIRES(!lock_); 42 GetSize()43 size_t GetSize() { 44 return size_; 45 } 46 47 private: 48 // Chunk of space. 49 struct SpaceChunk { 50 // We need mutable members as we keep these objects in a std::set<> (providing only const 51 // access) but we modify these members while carefully preserving the std::set<> ordering. 52 mutable uint8_t* ptr; 53 mutable size_t size; 54 StartSpaceChunk55 uintptr_t Start() const { 56 return reinterpret_cast<uintptr_t>(ptr); 57 } EndSpaceChunk58 uintptr_t End() const { 59 return reinterpret_cast<uintptr_t>(ptr) + size; 60 } 61 }; 62 63 class SortChunkByPtr { 64 public: operator()65 bool operator()(const SpaceChunk& a, const SpaceChunk& b) const { 66 return reinterpret_cast<uintptr_t>(a.ptr) < reinterpret_cast<uintptr_t>(b.ptr); 67 } 68 }; 69 70 using FreeByStartSet = std::set<SpaceChunk, SortChunkByPtr>; 71 72 // Map size to an iterator to free_by_start_'s entry. 73 struct FreeBySizeEntry { FreeBySizeEntryFreeBySizeEntry74 FreeBySizeEntry(size_t sz, FreeByStartSet::const_iterator entry) 75 : size(sz), free_by_start_entry(entry) { } 76 77 // We need mutable members as we keep these objects in a std::set<> (providing only const 78 // access) but we modify these members while carefully preserving the std::set<> ordering. 79 mutable size_t size; 80 mutable FreeByStartSet::const_iterator free_by_start_entry; 81 }; 82 struct FreeBySizeComparator { operatorFreeBySizeComparator83 bool operator()(const FreeBySizeEntry& lhs, const FreeBySizeEntry& rhs) const { 84 if (lhs.size != rhs.size) { 85 return lhs.size < rhs.size; 86 } else { 87 return lhs.free_by_start_entry->Start() < rhs.free_by_start_entry->Start(); 88 } 89 } 90 }; 91 using FreeBySizeSet = std::set<FreeBySizeEntry, FreeBySizeComparator>; 92 93 SpaceChunk NewFileChunk(size_t min_size) REQUIRES(lock_); 94 95 void RemoveChunk(FreeBySizeSet::const_iterator free_by_size_pos) REQUIRES(lock_); 96 void InsertChunk(const SpaceChunk& chunk) REQUIRES(lock_); 97 98 int fd_; 99 size_t size_; 100 101 // NOTE: Boost.Bimap would be useful for the two following members. 102 103 // Map start of a free chunk to its size. 104 FreeByStartSet free_by_start_ GUARDED_BY(lock_); 105 // Free chunks ordered by size. 106 FreeBySizeSet free_by_size_ GUARDED_BY(lock_); 107 108 mutable Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; 109 DISALLOW_COPY_AND_ASSIGN(SwapSpace); 110 }; 111 112 template <typename T> class SwapAllocator; 113 114 template <> 115 class SwapAllocator<void> { 116 public: 117 using value_type = void; 118 using pointer = void*; 119 using const_pointer = const void*; 120 121 template <typename U> 122 struct rebind { 123 using other = SwapAllocator<U>; 124 }; 125 SwapAllocator(SwapSpace * swap_space)126 explicit SwapAllocator(SwapSpace* swap_space) : swap_space_(swap_space) {} 127 128 template <typename U> SwapAllocator(const SwapAllocator<U> & other)129 SwapAllocator(const SwapAllocator<U>& other) 130 : swap_space_(other.swap_space_) {} 131 132 SwapAllocator(const SwapAllocator& other) = default; 133 SwapAllocator& operator=(const SwapAllocator& other) = default; 134 ~SwapAllocator() = default; 135 136 private: 137 SwapSpace* swap_space_; 138 139 template <typename U> 140 friend class SwapAllocator; 141 142 template <typename U> 143 friend bool operator==(const SwapAllocator<U>& lhs, const SwapAllocator<U>& rhs); 144 }; 145 146 template <typename T> 147 class SwapAllocator { 148 public: 149 using value_type = T; 150 using pointer = T*; 151 using reference = T&; 152 using const_pointer = const T*; 153 using const_reference = const T&; 154 using size_type = size_t; 155 using difference_type = ptrdiff_t; 156 157 template <typename U> 158 struct rebind { 159 using other = SwapAllocator<U>; 160 }; 161 SwapAllocator(SwapSpace * swap_space)162 explicit SwapAllocator(SwapSpace* swap_space) : swap_space_(swap_space) {} 163 164 template <typename U> SwapAllocator(const SwapAllocator<U> & other)165 SwapAllocator(const SwapAllocator<U>& other) 166 : swap_space_(other.swap_space_) {} 167 168 SwapAllocator(const SwapAllocator& other) = default; 169 SwapAllocator& operator=(const SwapAllocator& other) = default; 170 ~SwapAllocator() = default; 171 max_size()172 size_type max_size() const { 173 return static_cast<size_type>(-1) / sizeof(T); 174 } 175 address(reference x)176 pointer address(reference x) const { return &x; } address(const_reference x)177 const_pointer address(const_reference x) const { return &x; } 178 179 pointer allocate(size_type n, SwapAllocator<void>::pointer hint ATTRIBUTE_UNUSED = nullptr) { 180 DCHECK_LE(n, max_size()); 181 if (swap_space_ == nullptr) { 182 T* result = reinterpret_cast<T*>(malloc(n * sizeof(T))); 183 CHECK_IMPLIES(result == nullptr, n == 0u); // Abort if malloc() fails. 184 return result; 185 } else { 186 return reinterpret_cast<T*>(swap_space_->Alloc(n * sizeof(T))); 187 } 188 } deallocate(pointer p,size_type n)189 void deallocate(pointer p, size_type n) { 190 if (swap_space_ == nullptr) { 191 free(p); 192 } else { 193 swap_space_->Free(p, n * sizeof(T)); 194 } 195 } 196 construct(pointer p,const_reference val)197 void construct(pointer p, const_reference val) { 198 new (static_cast<void*>(p)) value_type(val); 199 } 200 template <class U, class... Args> construct(U * p,Args &&...args)201 void construct(U* p, Args&&... args) { 202 ::new (static_cast<void*>(p)) U(std::forward<Args>(args)...); 203 } destroy(pointer p)204 void destroy(pointer p) { 205 p->~value_type(); 206 } 207 208 inline bool operator==(SwapAllocator const& other) { 209 return swap_space_ == other.swap_space_; 210 } 211 inline bool operator!=(SwapAllocator const& other) { 212 return !operator==(other); 213 } 214 215 private: 216 SwapSpace* swap_space_; 217 218 template <typename U> 219 friend class SwapAllocator; 220 221 template <typename U> 222 friend bool operator==(const SwapAllocator<U>& lhs, const SwapAllocator<U>& rhs); 223 }; 224 225 template <typename T> 226 inline bool operator==(const SwapAllocator<T>& lhs, const SwapAllocator<T>& rhs) { 227 return lhs.swap_space_ == rhs.swap_space_; 228 } 229 230 template <typename T> 231 inline bool operator!=(const SwapAllocator<T>& lhs, const SwapAllocator<T>& rhs) { 232 return !(lhs == rhs); 233 } 234 235 template <typename T> 236 using SwapVector = std::vector<T, SwapAllocator<T>>; 237 template <typename T, typename Comparator> 238 using SwapSet = std::set<T, Comparator, SwapAllocator<T>>; 239 240 } // namespace art 241 242 #endif // ART_DEX2OAT_UTILS_SWAP_SPACE_H_ 243