xref: /aosp_15_r20/art/libartbase/base/arena_allocator.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2013 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_LIBARTBASE_BASE_ARENA_ALLOCATOR_H_
18*795d594fSAndroid Build Coastguard Worker #define ART_LIBARTBASE_BASE_ARENA_ALLOCATOR_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 
23*795d594fSAndroid Build Coastguard Worker #include "bit_utils.h"
24*795d594fSAndroid Build Coastguard Worker #include "debug_stack.h"
25*795d594fSAndroid Build Coastguard Worker #include "dchecked_vector.h"
26*795d594fSAndroid Build Coastguard Worker #include "macros.h"
27*795d594fSAndroid Build Coastguard Worker #include "memory_tool.h"
28*795d594fSAndroid Build Coastguard Worker 
29*795d594fSAndroid Build Coastguard Worker namespace art {
30*795d594fSAndroid Build Coastguard Worker 
31*795d594fSAndroid Build Coastguard Worker class Arena;
32*795d594fSAndroid Build Coastguard Worker class ArenaPool;
33*795d594fSAndroid Build Coastguard Worker class ArenaAllocator;
34*795d594fSAndroid Build Coastguard Worker class ArenaStack;
35*795d594fSAndroid Build Coastguard Worker class ScopedArenaAllocator;
36*795d594fSAndroid Build Coastguard Worker class MemStats;
37*795d594fSAndroid Build Coastguard Worker 
38*795d594fSAndroid Build Coastguard Worker template <typename T>
39*795d594fSAndroid Build Coastguard Worker class ArenaAllocatorAdapter;
40*795d594fSAndroid Build Coastguard Worker 
41*795d594fSAndroid Build Coastguard Worker static constexpr bool kArenaAllocatorCountAllocations = false;
42*795d594fSAndroid Build Coastguard Worker 
43*795d594fSAndroid Build Coastguard Worker // Type of allocation for memory tuning.
44*795d594fSAndroid Build Coastguard Worker enum ArenaAllocKind {
45*795d594fSAndroid Build Coastguard Worker   kArenaAllocMisc,
46*795d594fSAndroid Build Coastguard Worker   kArenaAllocSwitchTable,
47*795d594fSAndroid Build Coastguard Worker   kArenaAllocSlowPaths,
48*795d594fSAndroid Build Coastguard Worker   kArenaAllocGrowableBitMap,
49*795d594fSAndroid Build Coastguard Worker   kArenaAllocSTL,
50*795d594fSAndroid Build Coastguard Worker   kArenaAllocGraphBuilder,
51*795d594fSAndroid Build Coastguard Worker   kArenaAllocGraph,
52*795d594fSAndroid Build Coastguard Worker   kArenaAllocBasicBlock,
53*795d594fSAndroid Build Coastguard Worker   kArenaAllocBlockList,
54*795d594fSAndroid Build Coastguard Worker   kArenaAllocReversePostOrder,
55*795d594fSAndroid Build Coastguard Worker   kArenaAllocLinearOrder,
56*795d594fSAndroid Build Coastguard Worker   kArenaAllocReachabilityGraph,
57*795d594fSAndroid Build Coastguard Worker   kArenaAllocConstantsMap,
58*795d594fSAndroid Build Coastguard Worker   kArenaAllocPredecessors,
59*795d594fSAndroid Build Coastguard Worker   kArenaAllocSuccessors,
60*795d594fSAndroid Build Coastguard Worker   kArenaAllocDominated,
61*795d594fSAndroid Build Coastguard Worker   kArenaAllocInstruction,
62*795d594fSAndroid Build Coastguard Worker   kArenaAllocConstructorFenceInputs,
63*795d594fSAndroid Build Coastguard Worker   kArenaAllocInvokeInputs,
64*795d594fSAndroid Build Coastguard Worker   kArenaAllocPhiInputs,
65*795d594fSAndroid Build Coastguard Worker   kArenaAllocTypeCheckInputs,
66*795d594fSAndroid Build Coastguard Worker   kArenaAllocLoopInfo,
67*795d594fSAndroid Build Coastguard Worker   kArenaAllocLoopInfoBackEdges,
68*795d594fSAndroid Build Coastguard Worker   kArenaAllocTryCatchInfo,
69*795d594fSAndroid Build Coastguard Worker   kArenaAllocUseListNode,
70*795d594fSAndroid Build Coastguard Worker   kArenaAllocEnvironment,
71*795d594fSAndroid Build Coastguard Worker   kArenaAllocEnvironmentLocations,
72*795d594fSAndroid Build Coastguard Worker   kArenaAllocLocationSummary,
73*795d594fSAndroid Build Coastguard Worker   kArenaAllocSsaBuilder,
74*795d594fSAndroid Build Coastguard Worker   kArenaAllocMoveOperands,
75*795d594fSAndroid Build Coastguard Worker   kArenaAllocCodeBuffer,
76*795d594fSAndroid Build Coastguard Worker   kArenaAllocStackMaps,
77*795d594fSAndroid Build Coastguard Worker   kArenaAllocOptimization,
78*795d594fSAndroid Build Coastguard Worker   kArenaAllocGvn,
79*795d594fSAndroid Build Coastguard Worker   kArenaAllocInductionVarAnalysis,
80*795d594fSAndroid Build Coastguard Worker   kArenaAllocBoundsCheckElimination,
81*795d594fSAndroid Build Coastguard Worker   kArenaAllocDCE,
82*795d594fSAndroid Build Coastguard Worker   kArenaAllocLSA,
83*795d594fSAndroid Build Coastguard Worker   kArenaAllocLSE,
84*795d594fSAndroid Build Coastguard Worker   kArenaAllocCFRE,
85*795d594fSAndroid Build Coastguard Worker   kArenaAllocLICM,
86*795d594fSAndroid Build Coastguard Worker   kArenaAllocWBE,
87*795d594fSAndroid Build Coastguard Worker   kArenaAllocLoopOptimization,
88*795d594fSAndroid Build Coastguard Worker   kArenaAllocSsaLiveness,
89*795d594fSAndroid Build Coastguard Worker   kArenaAllocSsaPhiElimination,
90*795d594fSAndroid Build Coastguard Worker   kArenaAllocReferenceTypePropagation,
91*795d594fSAndroid Build Coastguard Worker   kArenaAllocSelectGenerator,
92*795d594fSAndroid Build Coastguard Worker   kArenaAllocSideEffectsAnalysis,
93*795d594fSAndroid Build Coastguard Worker   kArenaAllocRegisterAllocator,
94*795d594fSAndroid Build Coastguard Worker   kArenaAllocRegisterAllocatorValidate,
95*795d594fSAndroid Build Coastguard Worker   kArenaAllocStackMapStream,
96*795d594fSAndroid Build Coastguard Worker   kArenaAllocBitTableBuilder,
97*795d594fSAndroid Build Coastguard Worker   kArenaAllocVectorNode,
98*795d594fSAndroid Build Coastguard Worker   kArenaAllocCodeGenerator,
99*795d594fSAndroid Build Coastguard Worker   kArenaAllocAssembler,
100*795d594fSAndroid Build Coastguard Worker   kArenaAllocParallelMoveResolver,
101*795d594fSAndroid Build Coastguard Worker   kArenaAllocGraphChecker,
102*795d594fSAndroid Build Coastguard Worker   kArenaAllocVerifier,
103*795d594fSAndroid Build Coastguard Worker   kArenaAllocCallingConvention,
104*795d594fSAndroid Build Coastguard Worker   kArenaAllocCHA,
105*795d594fSAndroid Build Coastguard Worker   kArenaAllocScheduler,
106*795d594fSAndroid Build Coastguard Worker   kArenaAllocProfile,
107*795d594fSAndroid Build Coastguard Worker   kArenaAllocSuperblockCloner,
108*795d594fSAndroid Build Coastguard Worker   kArenaAllocTransaction,
109*795d594fSAndroid Build Coastguard Worker   kNumArenaAllocKinds
110*795d594fSAndroid Build Coastguard Worker };
111*795d594fSAndroid Build Coastguard Worker 
112*795d594fSAndroid Build Coastguard Worker template <bool kCount>
113*795d594fSAndroid Build Coastguard Worker class ArenaAllocatorStatsImpl;
114*795d594fSAndroid Build Coastguard Worker 
115*795d594fSAndroid Build Coastguard Worker template <>
116*795d594fSAndroid Build Coastguard Worker class ArenaAllocatorStatsImpl<false> {
117*795d594fSAndroid Build Coastguard Worker  public:
118*795d594fSAndroid Build Coastguard Worker   ArenaAllocatorStatsImpl() = default;
119*795d594fSAndroid Build Coastguard Worker   ArenaAllocatorStatsImpl(const ArenaAllocatorStatsImpl& other) = default;
120*795d594fSAndroid Build Coastguard Worker   ArenaAllocatorStatsImpl& operator = (const ArenaAllocatorStatsImpl& other) = delete;
121*795d594fSAndroid Build Coastguard Worker 
Copy(const ArenaAllocatorStatsImpl & other)122*795d594fSAndroid Build Coastguard Worker   void Copy([[maybe_unused]] const ArenaAllocatorStatsImpl& other) {}
RecordAlloc(size_t bytes,ArenaAllocKind kind)123*795d594fSAndroid Build Coastguard Worker   void RecordAlloc([[maybe_unused]] size_t bytes, [[maybe_unused]] ArenaAllocKind kind) {}
NumAllocations()124*795d594fSAndroid Build Coastguard Worker   size_t NumAllocations() const { return 0u; }
BytesAllocated()125*795d594fSAndroid Build Coastguard Worker   size_t BytesAllocated() const { return 0u; }
Dump(std::ostream & os,const Arena * first,ssize_t lost_bytes_adjustment)126*795d594fSAndroid Build Coastguard Worker   void Dump([[maybe_unused]] std::ostream& os,
127*795d594fSAndroid Build Coastguard Worker             [[maybe_unused]] const Arena* first,
128*795d594fSAndroid Build Coastguard Worker             [[maybe_unused]] ssize_t lost_bytes_adjustment) const {}
129*795d594fSAndroid Build Coastguard Worker };
130*795d594fSAndroid Build Coastguard Worker 
131*795d594fSAndroid Build Coastguard Worker template <bool kCount>
132*795d594fSAndroid Build Coastguard Worker class ArenaAllocatorStatsImpl {
133*795d594fSAndroid Build Coastguard Worker  public:
134*795d594fSAndroid Build Coastguard Worker   ArenaAllocatorStatsImpl();
135*795d594fSAndroid Build Coastguard Worker   ArenaAllocatorStatsImpl(const ArenaAllocatorStatsImpl& other) = default;
136*795d594fSAndroid Build Coastguard Worker   ArenaAllocatorStatsImpl& operator = (const ArenaAllocatorStatsImpl& other) = delete;
137*795d594fSAndroid Build Coastguard Worker 
138*795d594fSAndroid Build Coastguard Worker   void Copy(const ArenaAllocatorStatsImpl& other);
139*795d594fSAndroid Build Coastguard Worker   void RecordAlloc(size_t bytes, ArenaAllocKind kind);
140*795d594fSAndroid Build Coastguard Worker   size_t NumAllocations() const;
141*795d594fSAndroid Build Coastguard Worker   size_t BytesAllocated() const;
142*795d594fSAndroid Build Coastguard Worker   void Dump(std::ostream& os, const Arena* first, ssize_t lost_bytes_adjustment) const;
143*795d594fSAndroid Build Coastguard Worker 
144*795d594fSAndroid Build Coastguard Worker  private:
145*795d594fSAndroid Build Coastguard Worker   size_t num_allocations_;
146*795d594fSAndroid Build Coastguard Worker   dchecked_vector<size_t> alloc_stats_;  // Bytes used by various allocation kinds.
147*795d594fSAndroid Build Coastguard Worker 
148*795d594fSAndroid Build Coastguard Worker   static const char* const kAllocNames[];
149*795d594fSAndroid Build Coastguard Worker };
150*795d594fSAndroid Build Coastguard Worker 
151*795d594fSAndroid Build Coastguard Worker using ArenaAllocatorStats = ArenaAllocatorStatsImpl<kArenaAllocatorCountAllocations>;
152*795d594fSAndroid Build Coastguard Worker 
153*795d594fSAndroid Build Coastguard Worker class ArenaAllocatorMemoryTool {
154*795d594fSAndroid Build Coastguard Worker  public:
IsRunningOnMemoryTool()155*795d594fSAndroid Build Coastguard Worker   static constexpr bool IsRunningOnMemoryTool() { return kMemoryToolIsAvailable; }
156*795d594fSAndroid Build Coastguard Worker 
MakeDefined(void * ptr,size_t size)157*795d594fSAndroid Build Coastguard Worker   void MakeDefined(void* ptr, size_t size) {
158*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(IsRunningOnMemoryTool())) {
159*795d594fSAndroid Build Coastguard Worker       DoMakeDefined(ptr, size);
160*795d594fSAndroid Build Coastguard Worker     }
161*795d594fSAndroid Build Coastguard Worker   }
MakeUndefined(void * ptr,size_t size)162*795d594fSAndroid Build Coastguard Worker   void MakeUndefined(void* ptr, size_t size) {
163*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(IsRunningOnMemoryTool())) {
164*795d594fSAndroid Build Coastguard Worker       DoMakeUndefined(ptr, size);
165*795d594fSAndroid Build Coastguard Worker     }
166*795d594fSAndroid Build Coastguard Worker   }
MakeInaccessible(void * ptr,size_t size)167*795d594fSAndroid Build Coastguard Worker   void MakeInaccessible(void* ptr, size_t size) {
168*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(IsRunningOnMemoryTool())) {
169*795d594fSAndroid Build Coastguard Worker       DoMakeInaccessible(ptr, size);
170*795d594fSAndroid Build Coastguard Worker     }
171*795d594fSAndroid Build Coastguard Worker   }
172*795d594fSAndroid Build Coastguard Worker 
173*795d594fSAndroid Build Coastguard Worker  private:
174*795d594fSAndroid Build Coastguard Worker   void DoMakeDefined(void* ptr, size_t size);
175*795d594fSAndroid Build Coastguard Worker   void DoMakeUndefined(void* ptr, size_t size);
176*795d594fSAndroid Build Coastguard Worker   void DoMakeInaccessible(void* ptr, size_t size);
177*795d594fSAndroid Build Coastguard Worker };
178*795d594fSAndroid Build Coastguard Worker 
179*795d594fSAndroid Build Coastguard Worker class Arena {
180*795d594fSAndroid Build Coastguard Worker  public:
Arena()181*795d594fSAndroid Build Coastguard Worker   Arena() : bytes_allocated_(0), memory_(nullptr), size_(0), next_(nullptr) {}
182*795d594fSAndroid Build Coastguard Worker 
~Arena()183*795d594fSAndroid Build Coastguard Worker   virtual ~Arena() { }
184*795d594fSAndroid Build Coastguard Worker   // Reset is for pre-use and uses memset for performance.
185*795d594fSAndroid Build Coastguard Worker   void Reset();
186*795d594fSAndroid Build Coastguard Worker   // Release is used inbetween uses and uses madvise for memory usage.
Release()187*795d594fSAndroid Build Coastguard Worker   virtual void Release() { }
Begin()188*795d594fSAndroid Build Coastguard Worker   uint8_t* Begin() const {
189*795d594fSAndroid Build Coastguard Worker     return memory_;
190*795d594fSAndroid Build Coastguard Worker   }
191*795d594fSAndroid Build Coastguard Worker 
End()192*795d594fSAndroid Build Coastguard Worker   uint8_t* End() const { return memory_ + size_; }
193*795d594fSAndroid Build Coastguard Worker 
Size()194*795d594fSAndroid Build Coastguard Worker   size_t Size() const {
195*795d594fSAndroid Build Coastguard Worker     return size_;
196*795d594fSAndroid Build Coastguard Worker   }
197*795d594fSAndroid Build Coastguard Worker 
RemainingSpace()198*795d594fSAndroid Build Coastguard Worker   size_t RemainingSpace() const {
199*795d594fSAndroid Build Coastguard Worker     return Size() - bytes_allocated_;
200*795d594fSAndroid Build Coastguard Worker   }
201*795d594fSAndroid Build Coastguard Worker 
GetBytesAllocated()202*795d594fSAndroid Build Coastguard Worker   size_t GetBytesAllocated() const {
203*795d594fSAndroid Build Coastguard Worker     return bytes_allocated_;
204*795d594fSAndroid Build Coastguard Worker   }
205*795d594fSAndroid Build Coastguard Worker 
206*795d594fSAndroid Build Coastguard Worker   // Return true if ptr is contained in the arena.
Contains(const void * ptr)207*795d594fSAndroid Build Coastguard Worker   bool Contains(const void* ptr) const { return memory_ <= ptr && ptr < memory_ + size_; }
208*795d594fSAndroid Build Coastguard Worker 
Next()209*795d594fSAndroid Build Coastguard Worker   Arena* Next() const { return next_; }
210*795d594fSAndroid Build Coastguard Worker 
211*795d594fSAndroid Build Coastguard Worker  protected:
212*795d594fSAndroid Build Coastguard Worker   size_t bytes_allocated_;
213*795d594fSAndroid Build Coastguard Worker   uint8_t* memory_;
214*795d594fSAndroid Build Coastguard Worker   size_t size_;
215*795d594fSAndroid Build Coastguard Worker   Arena* next_;
216*795d594fSAndroid Build Coastguard Worker   friend class MallocArenaPool;
217*795d594fSAndroid Build Coastguard Worker   friend class MemMapArenaPool;
218*795d594fSAndroid Build Coastguard Worker   friend class ArenaAllocator;
219*795d594fSAndroid Build Coastguard Worker   friend class ArenaStack;
220*795d594fSAndroid Build Coastguard Worker   friend class ScopedArenaAllocator;
221*795d594fSAndroid Build Coastguard Worker   template <bool kCount> friend class ArenaAllocatorStatsImpl;
222*795d594fSAndroid Build Coastguard Worker 
223*795d594fSAndroid Build Coastguard Worker   friend class ArenaAllocatorTest;
224*795d594fSAndroid Build Coastguard Worker 
225*795d594fSAndroid Build Coastguard Worker  private:
226*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(Arena);
227*795d594fSAndroid Build Coastguard Worker };
228*795d594fSAndroid Build Coastguard Worker 
229*795d594fSAndroid Build Coastguard Worker class ArenaPool {
230*795d594fSAndroid Build Coastguard Worker  public:
231*795d594fSAndroid Build Coastguard Worker   virtual ~ArenaPool() = default;
232*795d594fSAndroid Build Coastguard Worker 
233*795d594fSAndroid Build Coastguard Worker   virtual Arena* AllocArena(size_t size) = 0;
234*795d594fSAndroid Build Coastguard Worker   virtual void FreeArenaChain(Arena* first) = 0;
235*795d594fSAndroid Build Coastguard Worker   virtual size_t GetBytesAllocated() const = 0;
236*795d594fSAndroid Build Coastguard Worker   virtual void ReclaimMemory() = 0;
237*795d594fSAndroid Build Coastguard Worker   virtual void LockReclaimMemory() = 0;
238*795d594fSAndroid Build Coastguard Worker   // Trim the maps in arenas by madvising, used by JIT to reduce memory usage.
239*795d594fSAndroid Build Coastguard Worker   virtual void TrimMaps() = 0;
240*795d594fSAndroid Build Coastguard Worker 
241*795d594fSAndroid Build Coastguard Worker  protected:
242*795d594fSAndroid Build Coastguard Worker   ArenaPool() = default;
243*795d594fSAndroid Build Coastguard Worker 
244*795d594fSAndroid Build Coastguard Worker  private:
245*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(ArenaPool);
246*795d594fSAndroid Build Coastguard Worker };
247*795d594fSAndroid Build Coastguard Worker 
248*795d594fSAndroid Build Coastguard Worker // Fast single-threaded allocator for zero-initialized memory chunks.
249*795d594fSAndroid Build Coastguard Worker //
250*795d594fSAndroid Build Coastguard Worker // Memory is allocated from ArenaPool in large chunks and then rationed through
251*795d594fSAndroid Build Coastguard Worker // the ArenaAllocator. It's returned to the ArenaPool only when the ArenaAllocator
252*795d594fSAndroid Build Coastguard Worker // is destroyed.
253*795d594fSAndroid Build Coastguard Worker class ArenaAllocator
254*795d594fSAndroid Build Coastguard Worker     : private DebugStackRefCounter, private ArenaAllocatorStats, private ArenaAllocatorMemoryTool {
255*795d594fSAndroid Build Coastguard Worker  public:
256*795d594fSAndroid Build Coastguard Worker   explicit ArenaAllocator(ArenaPool* pool);
257*795d594fSAndroid Build Coastguard Worker   ~ArenaAllocator();
258*795d594fSAndroid Build Coastguard Worker 
259*795d594fSAndroid Build Coastguard Worker   using ArenaAllocatorMemoryTool::IsRunningOnMemoryTool;
260*795d594fSAndroid Build Coastguard Worker   using ArenaAllocatorMemoryTool::MakeDefined;
261*795d594fSAndroid Build Coastguard Worker   using ArenaAllocatorMemoryTool::MakeUndefined;
262*795d594fSAndroid Build Coastguard Worker   using ArenaAllocatorMemoryTool::MakeInaccessible;
263*795d594fSAndroid Build Coastguard Worker 
264*795d594fSAndroid Build Coastguard Worker   // Get adapter for use in STL containers. See arena_containers.h .
265*795d594fSAndroid Build Coastguard Worker   ArenaAllocatorAdapter<void> Adapter(ArenaAllocKind kind = kArenaAllocSTL);
266*795d594fSAndroid Build Coastguard Worker 
267*795d594fSAndroid Build Coastguard Worker   // Returns zeroed memory.
268*795d594fSAndroid Build Coastguard Worker   void* Alloc(size_t bytes, ArenaAllocKind kind = kArenaAllocMisc) ALWAYS_INLINE {
269*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(IsRunningOnMemoryTool())) {
270*795d594fSAndroid Build Coastguard Worker       return AllocWithMemoryTool(bytes, kind);
271*795d594fSAndroid Build Coastguard Worker     }
272*795d594fSAndroid Build Coastguard Worker     bytes = RoundUp(bytes, kAlignment);
273*795d594fSAndroid Build Coastguard Worker     ArenaAllocatorStats::RecordAlloc(bytes, kind);
274*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(bytes > static_cast<size_t>(end_ - ptr_))) {
275*795d594fSAndroid Build Coastguard Worker       return AllocFromNewArena(bytes);
276*795d594fSAndroid Build Coastguard Worker     }
277*795d594fSAndroid Build Coastguard Worker     uint8_t* ret = ptr_;
278*795d594fSAndroid Build Coastguard Worker     DCHECK_ALIGNED(ret, kAlignment);
279*795d594fSAndroid Build Coastguard Worker     ptr_ += bytes;
280*795d594fSAndroid Build Coastguard Worker     return ret;
281*795d594fSAndroid Build Coastguard Worker   }
282*795d594fSAndroid Build Coastguard Worker 
283*795d594fSAndroid Build Coastguard Worker   // Returns zeroed memory.
284*795d594fSAndroid Build Coastguard Worker   void* AllocAlign16(size_t bytes, ArenaAllocKind kind = kArenaAllocMisc) ALWAYS_INLINE {
285*795d594fSAndroid Build Coastguard Worker     // It is an error to request 16-byte aligned allocation of unaligned size.
286*795d594fSAndroid Build Coastguard Worker     DCHECK_ALIGNED(bytes, 16);
287*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(IsRunningOnMemoryTool())) {
288*795d594fSAndroid Build Coastguard Worker       return AllocWithMemoryToolAlign16(bytes, kind);
289*795d594fSAndroid Build Coastguard Worker     }
290*795d594fSAndroid Build Coastguard Worker     uintptr_t padding =
291*795d594fSAndroid Build Coastguard Worker         RoundUp(reinterpret_cast<uintptr_t>(ptr_), 16) - reinterpret_cast<uintptr_t>(ptr_);
292*795d594fSAndroid Build Coastguard Worker     ArenaAllocatorStats::RecordAlloc(bytes, kind);
293*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(padding + bytes > static_cast<size_t>(end_ - ptr_))) {
294*795d594fSAndroid Build Coastguard Worker       static_assert(kArenaAlignment >= 16, "Expecting sufficient alignment for new Arena.");
295*795d594fSAndroid Build Coastguard Worker       return AllocFromNewArena(bytes);
296*795d594fSAndroid Build Coastguard Worker     }
297*795d594fSAndroid Build Coastguard Worker     ptr_ += padding;
298*795d594fSAndroid Build Coastguard Worker     uint8_t* ret = ptr_;
299*795d594fSAndroid Build Coastguard Worker     DCHECK_ALIGNED(ret, 16);
300*795d594fSAndroid Build Coastguard Worker     ptr_ += bytes;
301*795d594fSAndroid Build Coastguard Worker     return ret;
302*795d594fSAndroid Build Coastguard Worker   }
303*795d594fSAndroid Build Coastguard Worker 
304*795d594fSAndroid Build Coastguard Worker   // Realloc never frees the input pointer, it is the caller's job to do this if necessary.
305*795d594fSAndroid Build Coastguard Worker   void* Realloc(void* ptr,
306*795d594fSAndroid Build Coastguard Worker                 size_t ptr_size,
307*795d594fSAndroid Build Coastguard Worker                 size_t new_size,
308*795d594fSAndroid Build Coastguard Worker                 ArenaAllocKind kind = kArenaAllocMisc) ALWAYS_INLINE {
309*795d594fSAndroid Build Coastguard Worker     DCHECK_GE(new_size, ptr_size);
310*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(ptr == nullptr, ptr_size == 0u);
311*795d594fSAndroid Build Coastguard Worker     // We always allocate aligned.
312*795d594fSAndroid Build Coastguard Worker     const size_t aligned_ptr_size = RoundUp(ptr_size, kAlignment);
313*795d594fSAndroid Build Coastguard Worker     auto* end = reinterpret_cast<uint8_t*>(ptr) + aligned_ptr_size;
314*795d594fSAndroid Build Coastguard Worker     // If we haven't allocated anything else, we can safely extend.
315*795d594fSAndroid Build Coastguard Worker     if (end == ptr_) {
316*795d594fSAndroid Build Coastguard Worker       // Red zone prevents end == ptr_ (unless input = allocator state = null).
317*795d594fSAndroid Build Coastguard Worker       DCHECK(!IsRunningOnMemoryTool() || ptr_ == nullptr);
318*795d594fSAndroid Build Coastguard Worker       const size_t aligned_new_size = RoundUp(new_size, kAlignment);
319*795d594fSAndroid Build Coastguard Worker       const size_t size_delta = aligned_new_size - aligned_ptr_size;
320*795d594fSAndroid Build Coastguard Worker       // Check remain space.
321*795d594fSAndroid Build Coastguard Worker       const size_t remain = end_ - ptr_;
322*795d594fSAndroid Build Coastguard Worker       if (remain >= size_delta) {
323*795d594fSAndroid Build Coastguard Worker         ptr_ += size_delta;
324*795d594fSAndroid Build Coastguard Worker         ArenaAllocatorStats::RecordAlloc(size_delta, kind);
325*795d594fSAndroid Build Coastguard Worker         DCHECK_ALIGNED(ptr_, kAlignment);
326*795d594fSAndroid Build Coastguard Worker         return ptr;
327*795d594fSAndroid Build Coastguard Worker       }
328*795d594fSAndroid Build Coastguard Worker     }
329*795d594fSAndroid Build Coastguard Worker     auto* new_ptr = Alloc(new_size, kind);  // Note: Alloc will take care of aligning new_size.
330*795d594fSAndroid Build Coastguard Worker     memcpy(new_ptr, ptr, ptr_size);
331*795d594fSAndroid Build Coastguard Worker     // TODO: Call free on ptr if linear alloc supports free.
332*795d594fSAndroid Build Coastguard Worker     return new_ptr;
333*795d594fSAndroid Build Coastguard Worker   }
334*795d594fSAndroid Build Coastguard Worker 
335*795d594fSAndroid Build Coastguard Worker   template <typename T>
336*795d594fSAndroid Build Coastguard Worker   T* Alloc(ArenaAllocKind kind = kArenaAllocMisc) {
337*795d594fSAndroid Build Coastguard Worker     return AllocArray<T>(1, kind);
338*795d594fSAndroid Build Coastguard Worker   }
339*795d594fSAndroid Build Coastguard Worker 
340*795d594fSAndroid Build Coastguard Worker   template <typename T>
341*795d594fSAndroid Build Coastguard Worker   T* AllocArray(size_t length, ArenaAllocKind kind = kArenaAllocMisc) {
342*795d594fSAndroid Build Coastguard Worker     return static_cast<T*>(Alloc(length * sizeof(T), kind));
343*795d594fSAndroid Build Coastguard Worker   }
344*795d594fSAndroid Build Coastguard Worker 
345*795d594fSAndroid Build Coastguard Worker   size_t BytesAllocated() const;
346*795d594fSAndroid Build Coastguard Worker 
347*795d594fSAndroid Build Coastguard Worker   MemStats GetMemStats() const;
348*795d594fSAndroid Build Coastguard Worker 
349*795d594fSAndroid Build Coastguard Worker   // The BytesUsed method sums up bytes allocated from arenas in arena_head_ and nodes.
350*795d594fSAndroid Build Coastguard Worker   // TODO: Change BytesAllocated to this behavior?
351*795d594fSAndroid Build Coastguard Worker   size_t BytesUsed() const;
352*795d594fSAndroid Build Coastguard Worker 
GetArenaPool()353*795d594fSAndroid Build Coastguard Worker   ArenaPool* GetArenaPool() const {
354*795d594fSAndroid Build Coastguard Worker     return pool_;
355*795d594fSAndroid Build Coastguard Worker   }
356*795d594fSAndroid Build Coastguard Worker 
GetHeadArena()357*795d594fSAndroid Build Coastguard Worker   Arena* GetHeadArena() const {
358*795d594fSAndroid Build Coastguard Worker     return arena_head_;
359*795d594fSAndroid Build Coastguard Worker   }
360*795d594fSAndroid Build Coastguard Worker 
CurrentPtr()361*795d594fSAndroid Build Coastguard Worker   uint8_t* CurrentPtr() const {
362*795d594fSAndroid Build Coastguard Worker     return ptr_;
363*795d594fSAndroid Build Coastguard Worker   }
364*795d594fSAndroid Build Coastguard Worker 
CurrentArenaUnusedBytes()365*795d594fSAndroid Build Coastguard Worker   size_t CurrentArenaUnusedBytes() const {
366*795d594fSAndroid Build Coastguard Worker     DCHECK_LE(ptr_, end_);
367*795d594fSAndroid Build Coastguard Worker     return end_ - ptr_;
368*795d594fSAndroid Build Coastguard Worker   }
369*795d594fSAndroid Build Coastguard Worker   // Resets the current arena in use, which will force us to get a new arena
370*795d594fSAndroid Build Coastguard Worker   // on next allocation.
371*795d594fSAndroid Build Coastguard Worker   void ResetCurrentArena();
372*795d594fSAndroid Build Coastguard Worker 
373*795d594fSAndroid Build Coastguard Worker   bool Contains(const void* ptr) const;
374*795d594fSAndroid Build Coastguard Worker 
375*795d594fSAndroid Build Coastguard Worker   // The alignment guaranteed for individual allocations.
376*795d594fSAndroid Build Coastguard Worker   static constexpr size_t kAlignment = 8u;
377*795d594fSAndroid Build Coastguard Worker 
378*795d594fSAndroid Build Coastguard Worker   // The alignment required for the whole Arena rather than individual allocations.
379*795d594fSAndroid Build Coastguard Worker   static constexpr size_t kArenaAlignment = 16u;
380*795d594fSAndroid Build Coastguard Worker 
381*795d594fSAndroid Build Coastguard Worker   // Extra bytes required by the memory tool.
382*795d594fSAndroid Build Coastguard Worker   static constexpr size_t kMemoryToolRedZoneBytes = 8u;
383*795d594fSAndroid Build Coastguard Worker 
384*795d594fSAndroid Build Coastguard Worker  private:
385*795d594fSAndroid Build Coastguard Worker   void* AllocWithMemoryTool(size_t bytes, ArenaAllocKind kind);
386*795d594fSAndroid Build Coastguard Worker   void* AllocWithMemoryToolAlign16(size_t bytes, ArenaAllocKind kind);
387*795d594fSAndroid Build Coastguard Worker   uint8_t* AllocFromNewArena(size_t bytes);
388*795d594fSAndroid Build Coastguard Worker   uint8_t* AllocFromNewArenaWithMemoryTool(size_t bytes);
389*795d594fSAndroid Build Coastguard Worker 
390*795d594fSAndroid Build Coastguard Worker   void UpdateBytesAllocated();
391*795d594fSAndroid Build Coastguard Worker 
392*795d594fSAndroid Build Coastguard Worker   ArenaPool* pool_;
393*795d594fSAndroid Build Coastguard Worker   uint8_t* begin_;
394*795d594fSAndroid Build Coastguard Worker   uint8_t* end_;
395*795d594fSAndroid Build Coastguard Worker   uint8_t* ptr_;
396*795d594fSAndroid Build Coastguard Worker   Arena* arena_head_;
397*795d594fSAndroid Build Coastguard Worker 
398*795d594fSAndroid Build Coastguard Worker   template <typename U>
399*795d594fSAndroid Build Coastguard Worker   friend class ArenaAllocatorAdapter;
400*795d594fSAndroid Build Coastguard Worker 
401*795d594fSAndroid Build Coastguard Worker   friend class ArenaAllocatorTest;
402*795d594fSAndroid Build Coastguard Worker 
403*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(ArenaAllocator);
404*795d594fSAndroid Build Coastguard Worker };  // ArenaAllocator
405*795d594fSAndroid Build Coastguard Worker 
406*795d594fSAndroid Build Coastguard Worker class MemStats {
407*795d594fSAndroid Build Coastguard Worker  public:
408*795d594fSAndroid Build Coastguard Worker   MemStats(const char* name,
409*795d594fSAndroid Build Coastguard Worker            const ArenaAllocatorStats* stats,
410*795d594fSAndroid Build Coastguard Worker            const Arena* first_arena,
411*795d594fSAndroid Build Coastguard Worker            ssize_t lost_bytes_adjustment = 0);
412*795d594fSAndroid Build Coastguard Worker   void Dump(std::ostream& os) const;
413*795d594fSAndroid Build Coastguard Worker 
414*795d594fSAndroid Build Coastguard Worker  private:
415*795d594fSAndroid Build Coastguard Worker   const char* const name_;
416*795d594fSAndroid Build Coastguard Worker   const ArenaAllocatorStats* const stats_;
417*795d594fSAndroid Build Coastguard Worker   const Arena* const first_arena_;
418*795d594fSAndroid Build Coastguard Worker   const ssize_t lost_bytes_adjustment_;
419*795d594fSAndroid Build Coastguard Worker };  // MemStats
420*795d594fSAndroid Build Coastguard Worker 
421*795d594fSAndroid Build Coastguard Worker }  // namespace art
422*795d594fSAndroid Build Coastguard Worker 
423*795d594fSAndroid Build Coastguard Worker #endif  // ART_LIBARTBASE_BASE_ARENA_ALLOCATOR_H_
424