• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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