1 /*
2  * Copyright 2022 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_RUNTIME_BASE_GC_VISITED_ARENA_POOL_H_
18 #define ART_RUNTIME_BASE_GC_VISITED_ARENA_POOL_H_
19 
20 #include <set>
21 
22 #include "base/allocator.h"
23 #include "base/arena_allocator.h"
24 #include "base/casts.h"
25 #include "base/hash_set.h"
26 #include "base/locks.h"
27 #include "base/mem_map.h"
28 #include "read_barrier_config.h"
29 #include "runtime.h"
30 
31 namespace art HIDDEN {
32 
33 // GcVisitedArenaPool can be used for tracking allocations so that they can
34 // be visited during GC to update the GC-roots inside them.
35 
36 // An Arena which tracks its allocations.
37 class TrackedArena final : public Arena {
38  public:
39   // Used for searching in maps. Only arena's starting address is relevant.
TrackedArena(uint8_t * addr)40   explicit TrackedArena(uint8_t* addr) : pre_zygote_fork_(false) { memory_ = addr; }
41   TrackedArena(uint8_t* start, size_t size, bool pre_zygote_fork, bool single_obj_arena);
42 
43   template <typename PageVisitor>
VisitRoots(PageVisitor & visitor)44   void VisitRoots(PageVisitor& visitor) const REQUIRES_SHARED(Locks::mutator_lock_) {
45     uint8_t* page_begin = Begin();
46     if (first_obj_array_.get() != nullptr) {
47       DCHECK_ALIGNED_PARAM(Size(), gPageSize);
48       DCHECK_ALIGNED_PARAM(Begin(), gPageSize);
49       for (int i = 0, nr_pages = DivideByPageSize(Size());
50            i < nr_pages;
51            i++, page_begin += gPageSize) {
52         uint8_t* first = first_obj_array_[i];
53         if (first != nullptr) {
54           visitor(page_begin, first, gPageSize);
55         } else {
56           break;
57         }
58       }
59     } else {
60       size_t page_size = Size();
61       while (page_size > gPageSize) {
62         visitor(page_begin, nullptr, gPageSize);
63         page_begin += gPageSize;
64         page_size -= gPageSize;
65       }
66       visitor(page_begin, nullptr, page_size);
67     }
68   }
69 
70   // Return the page addr of the first page with first_obj set to nullptr.
GetLastUsedByte()71   uint8_t* GetLastUsedByte() const REQUIRES_SHARED(Locks::mutator_lock_) {
72     // Jump past bytes-allocated for arenas which are not currently being used
73     // by arena-allocator. This helps in reducing loop iterations below.
74     uint8_t* last_byte = AlignUp(Begin() + GetBytesAllocated(), gPageSize);
75     if (first_obj_array_.get() != nullptr) {
76       DCHECK_ALIGNED_PARAM(Begin(), gPageSize);
77       DCHECK_ALIGNED_PARAM(End(), gPageSize);
78       DCHECK_LE(last_byte, End());
79     } else {
80       DCHECK_EQ(last_byte, End());
81     }
82     for (size_t i = DivideByPageSize(last_byte - Begin());
83          last_byte < End() && first_obj_array_[i] != nullptr;
84          last_byte += gPageSize, i++) {
85       // No body.
86     }
87     return last_byte;
88   }
89 
GetFirstObject(uint8_t * addr)90   uint8_t* GetFirstObject(uint8_t* addr) const REQUIRES_SHARED(Locks::mutator_lock_) {
91     DCHECK_LE(Begin(), addr);
92     DCHECK_GT(End(), addr);
93     if (first_obj_array_.get() != nullptr) {
94       return first_obj_array_[DivideByPageSize(addr - Begin())];
95     } else {
96       // The pages of this arena contain array of GC-roots. So we don't need
97       // first-object of any given page of the arena.
98       // Returning null helps distinguish which visitor is to be called.
99       return nullptr;
100     }
101   }
102 
103   // Set 'obj_begin' in first_obj_array_ in every element for which it's the
104   // first object.
105   EXPORT void SetFirstObject(uint8_t* obj_begin, uint8_t* obj_end);
106   // Setup the arena for deferred deletion.
SetupForDeferredDeletion(TrackedArena * next_arena)107   void SetupForDeferredDeletion(TrackedArena* next_arena) {
108     DCHECK(next_arena == nullptr || next_arena->waiting_for_deletion_);
109     DCHECK(!waiting_for_deletion_);
110     waiting_for_deletion_ = true;
111     next_ = next_arena;
112   }
IsWaitingForDeletion()113   bool IsWaitingForDeletion() const { return waiting_for_deletion_; }
114 
115   // Madvise the pages in the given range. 'begin' is expected to be page
116   // aligned.
117   // TODO: Remove this once we remove the shmem (minor-fault) code in
118   // userfaultfd GC and directly use ZeroAndReleaseMemory().
119   static void ReleasePages(uint8_t* begin, size_t size, bool pre_zygote_fork);
120   void Release() override;
IsPreZygoteForkArena()121   bool IsPreZygoteForkArena() const { return pre_zygote_fork_; }
IsSingleObjectArena()122   bool IsSingleObjectArena() const { return first_obj_array_.get() == nullptr; }
123 
124  private:
125   // first_obj_array_[i] is the object that overlaps with the ith page's
126   // beginning, i.e. first_obj_array_[i] <= ith page_begin.
127   std::unique_ptr<uint8_t*[]> first_obj_array_;
128   const bool pre_zygote_fork_;
129   bool waiting_for_deletion_;
130 };
131 
132 // An arena-pool wherein allocations can be tracked so that the GC can visit all
133 // the GC roots. All the arenas are allocated in one sufficiently large memory
134 // range to avoid multiple calls to mremapped/mprotected syscalls.
135 class GcVisitedArenaPool final : public ArenaPool {
136  public:
137 #if defined(__LP64__)
138   // Use a size in multiples of 1GB as that can utilize the optimized mremap
139   // page-table move.
140   static constexpr size_t kLinearAllocPoolSize = 1 * GB;
141   static constexpr size_t kLow4GBLinearAllocPoolSize = 32 * MB;
142 #else
143   static constexpr size_t kLinearAllocPoolSize = 32 * MB;
144 #endif
145 
146   explicit GcVisitedArenaPool(bool low_4gb = false,
147                               bool is_zygote = false,
148                               const char* name = "LinearAlloc");
149   virtual ~GcVisitedArenaPool();
150 
151   Arena* AllocArena(size_t size, bool need_first_obj_arr) REQUIRES(lock_);
152   // Use by arena allocator.
AllocArena(size_t size)153   Arena* AllocArena(size_t size) override REQUIRES(!lock_) {
154     WriterMutexLock wmu(Thread::Current(), lock_);
155     return AllocArena(size, /*need_first_obj_arr=*/false);
156   }
157   void FreeArenaChain(Arena* first) override REQUIRES(!lock_);
158   size_t GetBytesAllocated() const override REQUIRES(!lock_);
ReclaimMemory()159   void ReclaimMemory() override {}
LockReclaimMemory()160   void LockReclaimMemory() override {}
TrimMaps()161   void TrimMaps() override {}
162 
163   EXPORT uint8_t* AllocSingleObjArena(size_t size) REQUIRES(!lock_);
164   EXPORT void FreeSingleObjArena(uint8_t* addr) REQUIRES(!lock_);
165 
Contains(void * ptr)166   bool Contains(void* ptr) REQUIRES(!lock_) {
167     ReaderMutexLock rmu(Thread::Current(), lock_);
168     for (auto& map : maps_) {
169       if (map.HasAddress(ptr)) {
170         return true;
171       }
172     }
173     return false;
174   }
175 
176   template <typename PageVisitor>
VisitRoots(PageVisitor & visitor)177   void VisitRoots(PageVisitor& visitor) REQUIRES_SHARED(Locks::mutator_lock_, lock_) {
178     for (auto& arena : allocated_arenas_) {
179       arena->VisitRoots(visitor);
180     }
181   }
182 
183   template <typename Callback>
ForEachAllocatedArena(Callback cb)184   void ForEachAllocatedArena(Callback cb) REQUIRES_SHARED(Locks::mutator_lock_, lock_) {
185     // We should not have any unused arenas when calling this function.
186     CHECK(unused_arenas_ == nullptr);
187     for (auto& arena : allocated_arenas_) {
188       cb(*arena);
189     }
190   }
191 
192   // Called in Heap::PreZygoteFork(). All allocations after this are done in
193   // arena-pool which is visited by userfaultfd.
SetupPostZygoteMode()194   void SetupPostZygoteMode() REQUIRES(!lock_) {
195     WriterMutexLock wmu(Thread::Current(), lock_);
196     DCHECK(pre_zygote_fork_);
197     pre_zygote_fork_ = false;
198   }
199 
200   // For userfaultfd GC to be able to acquire the lock to avoid concurrent
201   // release of arenas when it is visiting them.
GetLock()202   ReaderWriterMutex& GetLock() const RETURN_CAPABILITY(lock_) { return lock_; }
203 
204   // Called in the compaction pause to indicate that all arenas that will be
205   // freed until compaction is done shouldn't delete the TrackedArena object to
206   // avoid ABA problem. Called with lock_ acquired.
DeferArenaFreeing()207   void DeferArenaFreeing() REQUIRES(lock_) {
208     CHECK(unused_arenas_ == nullptr);
209     defer_arena_freeing_ = true;
210   }
211 
212   // Clear defer_arena_freeing_ and delete all unused arenas.
213   void DeleteUnusedArenas() REQUIRES(!lock_);
214 
215  private:
216   void FreeRangeLocked(uint8_t* range_begin, size_t range_size) REQUIRES(lock_);
217   // Add a map (to be visited by userfaultfd) to the pool of at least min_size
218   // and return its address.
219   uint8_t* AddMap(size_t min_size) REQUIRES(lock_);
220   // Add a private anonymous map prior to zygote fork to the pool and return its
221   // address.
222   uint8_t* AddPreZygoteForkMap(size_t size) REQUIRES(lock_);
223 
224   class Chunk {
225    public:
Chunk(uint8_t * addr,size_t size)226     Chunk(uint8_t* addr, size_t size) : addr_(addr), size_(size) {}
227     uint8_t* addr_;
228     size_t size_;
229   };
230 
231   class LessByChunkAddr {
232    public:
operator()233     bool operator()(const Chunk* a, const Chunk* b) const {
234       return std::less<uint8_t*>{}(a->addr_, b->addr_);
235     }
236   };
237 
238   class LessByChunkSize {
239    public:
240     // Since two chunks could have the same size, use addr when that happens.
operator()241     bool operator()(const Chunk* a, const Chunk* b) const {
242       return a->size_ < b->size_ ||
243              (a->size_ == b->size_ && std::less<uint8_t*>{}(a->addr_, b->addr_));
244     }
245   };
246 
247   class TrackedArenaEquals {
248    public:
operator()249     bool operator()(const TrackedArena* a, const TrackedArena* b) const {
250       return std::equal_to<uint8_t*>{}(a->Begin(), b->Begin());
251     }
252   };
253 
254   class TrackedArenaHash {
255    public:
operator()256     size_t operator()(const TrackedArena* arena) const {
257       return std::hash<size_t>{}(DivideByPageSize(reinterpret_cast<uintptr_t>(arena->Begin())));
258     }
259   };
260   using AllocatedArenaSet =
261       HashSet<TrackedArena*, DefaultEmptyFn<TrackedArena*>, TrackedArenaHash, TrackedArenaEquals>;
262 
263   mutable ReaderWriterMutex lock_;
264   std::vector<MemMap> maps_ GUARDED_BY(lock_);
265   std::set<Chunk*, LessByChunkSize> best_fit_allocs_ GUARDED_BY(lock_);
266   std::set<Chunk*, LessByChunkAddr> free_chunks_ GUARDED_BY(lock_);
267   // Set of allocated arenas. It's required to be able to find the arena
268   // corresponding to a given address.
269   AllocatedArenaSet allocated_arenas_ GUARDED_BY(lock_);
270   // Number of bytes allocated so far.
271   size_t bytes_allocated_ GUARDED_BY(lock_);
272   // To hold arenas that are freed while GC is happening. These are kept until
273   // the end of GC to avoid ABA problem.
274   TrackedArena* unused_arenas_ GUARDED_BY(lock_);
275   const char* name_;
276   // Flag to indicate that some arenas have been freed. This flag is used as an
277   // optimization by GC to know if it needs to find if the arena being visited
278   // has been freed or not. The flag is cleared in the compaction pause and read
279   // when linear-alloc space is concurrently visited updated to update GC roots.
280   bool defer_arena_freeing_ GUARDED_BY(lock_);
281   const bool low_4gb_;
282   // Set to true in zygote process so that all linear-alloc allocations are in
283   // private-anonymous mappings and not on userfaultfd visited pages. At
284   // first zygote fork, it's set to false, after which all allocations are done
285   // in userfaultfd visited space.
286   bool pre_zygote_fork_ GUARDED_BY(lock_);
287 
288   DISALLOW_COPY_AND_ASSIGN(GcVisitedArenaPool);
289 };
290 
291 // Allocator for class-table and intern-table hash-sets. It enables updating the
292 // roots concurrently page-by-page.
293 template <class T, AllocatorTag kTag>
294 class GcRootArenaAllocator {
295   TrackingAllocator<T, kTag> tracking_alloc_;
296 
297  public:
298   using value_type = T;
299 
300   // Used internally by STL data structures. This copy constructor needs to be implicit. Don't wrap
301   // the line because that would break cpplint's detection of the implicit constructor.
302   template <class U>
GcRootArenaAllocator(const GcRootArenaAllocator<U,kTag> & alloc)303   GcRootArenaAllocator([[maybe_unused]] const GcRootArenaAllocator<U, kTag>& alloc) noexcept {}  // NOLINT [runtime/explicit]
304   // Used internally by STL data structures.
GcRootArenaAllocator()305   GcRootArenaAllocator() noexcept {}
306 
307   // Enables an allocator for objects of one type to allocate storage for objects of another type.
308   // Used internally by STL data structures.
309   template <class U>
310   struct rebind {
311     using other = GcRootArenaAllocator<U, kTag>;
312   };
313 
allocate(size_t n)314   T* allocate(size_t n) {
315     if (!gUseUserfaultfd) {
316       return tracking_alloc_.allocate(n);
317     }
318     size_t size = n * sizeof(T);
319     GcVisitedArenaPool* pool =
320         down_cast<GcVisitedArenaPool*>(Runtime::Current()->GetLinearAllocArenaPool());
321     return reinterpret_cast<T*>(pool->AllocSingleObjArena(size));
322   }
323 
deallocate(T * p,size_t n)324   void deallocate(T* p, size_t n) {
325     if (!gUseUserfaultfd) {
326       tracking_alloc_.deallocate(p, n);
327       return;
328     }
329     GcVisitedArenaPool* pool =
330         down_cast<GcVisitedArenaPool*>(Runtime::Current()->GetLinearAllocArenaPool());
331     pool->FreeSingleObjArena(reinterpret_cast<uint8_t*>(p));
332   }
333 };
334 
335 }  // namespace art
336 
337 #endif  // ART_RUNTIME_BASE_GC_VISITED_ARENA_POOL_H_
338