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