xref: /aosp_15_r20/art/dex2oat/utils/swap_space.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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