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