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