1 /*
2  * Copyright (C) 2013 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_COMPILER_UTILS_ARENA_ALLOCATOR_H_
18 #define ART_COMPILER_UTILS_ARENA_ALLOCATOR_H_
19 
20 #include <stdint.h>
21 #include <stddef.h>
22 
23 #include "base/macros.h"
24 #include "base/mutex.h"
25 #include "mem_map.h"
26 #include "utils.h"
27 #include "utils/debug_stack.h"
28 
29 namespace art {
30 
31 class Arena;
32 class ArenaPool;
33 class ArenaAllocator;
34 class ArenaStack;
35 class ScopedArenaAllocator;
36 class MemStats;
37 
38 template <typename T>
39 class ArenaAllocatorAdapter;
40 
41 static constexpr bool kArenaAllocatorCountAllocations = false;
42 
43 // Type of allocation for memory tuning.
44 enum ArenaAllocKind {
45   kArenaAllocMisc,
46   kArenaAllocBB,
47   kArenaAllocLIR,
48   kArenaAllocLIRResourceMask,
49   kArenaAllocMIR,
50   kArenaAllocDFInfo,
51   kArenaAllocGrowableArray,
52   kArenaAllocGrowableBitMap,
53   kArenaAllocDalvikToSSAMap,
54   kArenaAllocDebugInfo,
55   kArenaAllocSuccessor,
56   kArenaAllocRegAlloc,
57   kArenaAllocData,
58   kArenaAllocPredecessors,
59   kArenaAllocSTL,
60   kNumArenaAllocKinds
61 };
62 
63 template <bool kCount>
64 class ArenaAllocatorStatsImpl;
65 
66 template <>
67 class ArenaAllocatorStatsImpl<false> {
68  public:
69   ArenaAllocatorStatsImpl() = default;
70   ArenaAllocatorStatsImpl(const ArenaAllocatorStatsImpl& other) = default;
71   ArenaAllocatorStatsImpl& operator = (const ArenaAllocatorStatsImpl& other) = delete;
72 
Copy(const ArenaAllocatorStatsImpl & other)73   void Copy(const ArenaAllocatorStatsImpl& other) { UNUSED(other); }
RecordAlloc(size_t bytes,ArenaAllocKind kind)74   void RecordAlloc(size_t bytes, ArenaAllocKind kind) { UNUSED(bytes); UNUSED(kind); }
NumAllocations()75   size_t NumAllocations() const { return 0u; }
BytesAllocated()76   size_t BytesAllocated() const { return 0u; }
Dump(std::ostream & os,const Arena * first,ssize_t lost_bytes_adjustment)77   void Dump(std::ostream& os, const Arena* first, ssize_t lost_bytes_adjustment) const {
78     UNUSED(os); UNUSED(first); UNUSED(lost_bytes_adjustment);
79   }
80 };
81 
82 template <bool kCount>
83 class ArenaAllocatorStatsImpl {
84  public:
85   ArenaAllocatorStatsImpl();
86   ArenaAllocatorStatsImpl(const ArenaAllocatorStatsImpl& other) = default;
87   ArenaAllocatorStatsImpl& operator = (const ArenaAllocatorStatsImpl& other) = delete;
88 
89   void Copy(const ArenaAllocatorStatsImpl& other);
90   void RecordAlloc(size_t bytes, ArenaAllocKind kind);
91   size_t NumAllocations() const;
92   size_t BytesAllocated() const;
93   void Dump(std::ostream& os, const Arena* first, ssize_t lost_bytes_adjustment) const;
94 
95  private:
96   size_t num_allocations_;
97   // TODO: Use std::array<size_t, kNumArenaAllocKinds> from C++11 when we upgrade the STL.
98   size_t alloc_stats_[kNumArenaAllocKinds];  // Bytes used by various allocation kinds.
99 
100   static const char* const kAllocNames[];
101 };
102 
103 typedef ArenaAllocatorStatsImpl<kArenaAllocatorCountAllocations> ArenaAllocatorStats;
104 
105 class Arena {
106  public:
107   static constexpr size_t kDefaultSize = 128 * KB;
108   explicit Arena(size_t size = kDefaultSize);
109   ~Arena();
110   void Reset();
Begin()111   uint8_t* Begin() {
112     return memory_;
113   }
114 
End()115   uint8_t* End() {
116     return memory_ + size_;
117   }
118 
Size()119   size_t Size() const {
120     return size_;
121   }
122 
RemainingSpace()123   size_t RemainingSpace() const {
124     return Size() - bytes_allocated_;
125   }
126 
GetBytesAllocated()127   size_t GetBytesAllocated() const {
128     return bytes_allocated_;
129   }
130 
131  private:
132   size_t bytes_allocated_;
133   uint8_t* memory_;
134   size_t size_;
135   MemMap* map_;
136   Arena* next_;
137   friend class ArenaPool;
138   friend class ArenaAllocator;
139   friend class ArenaStack;
140   friend class ScopedArenaAllocator;
141   template <bool kCount> friend class ArenaAllocatorStatsImpl;
142   DISALLOW_COPY_AND_ASSIGN(Arena);
143 };
144 
145 class ArenaPool {
146  public:
147   ArenaPool();
148   ~ArenaPool();
149   Arena* AllocArena(size_t size) LOCKS_EXCLUDED(lock_);
150   void FreeArenaChain(Arena* first) LOCKS_EXCLUDED(lock_);
151   size_t GetBytesAllocated() const LOCKS_EXCLUDED(lock_);
152 
153  private:
154   mutable Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
155   Arena* free_arenas_ GUARDED_BY(lock_);
156   DISALLOW_COPY_AND_ASSIGN(ArenaPool);
157 };
158 
159 class ArenaAllocator : private DebugStackRefCounter, private ArenaAllocatorStats {
160  public:
161   explicit ArenaAllocator(ArenaPool* pool);
162   ~ArenaAllocator();
163 
164   // Get adapter for use in STL containers. See arena_containers.h .
165   ArenaAllocatorAdapter<void> Adapter(ArenaAllocKind kind = kArenaAllocSTL);
166 
167   // Returns zeroed memory.
Alloc(size_t bytes,ArenaAllocKind kind)168   void* Alloc(size_t bytes, ArenaAllocKind kind) ALWAYS_INLINE {
169     if (UNLIKELY(running_on_valgrind_)) {
170       return AllocValgrind(bytes, kind);
171     }
172     bytes = RoundUp(bytes, 8);
173     if (UNLIKELY(ptr_ + bytes > end_)) {
174       // Obtain a new block.
175       ObtainNewArenaForAllocation(bytes);
176       if (UNLIKELY(ptr_ == nullptr)) {
177         return nullptr;
178       }
179     }
180     ArenaAllocatorStats::RecordAlloc(bytes, kind);
181     uint8_t* ret = ptr_;
182     ptr_ += bytes;
183     return ret;
184   }
185 
AllocArray(size_t length)186   template <typename T> T* AllocArray(size_t length) {
187     return static_cast<T*>(Alloc(length * sizeof(T), kArenaAllocMisc));
188   }
189 
190   void* AllocValgrind(size_t bytes, ArenaAllocKind kind);
191   void ObtainNewArenaForAllocation(size_t allocation_size);
192   size_t BytesAllocated() const;
193   MemStats GetMemStats() const;
194 
195  private:
196   void UpdateBytesAllocated();
197 
198   ArenaPool* pool_;
199   uint8_t* begin_;
200   uint8_t* end_;
201   uint8_t* ptr_;
202   Arena* arena_head_;
203   bool running_on_valgrind_;
204 
205   template <typename U>
206   friend class ArenaAllocatorAdapter;
207 
208   DISALLOW_COPY_AND_ASSIGN(ArenaAllocator);
209 };  // ArenaAllocator
210 
211 class MemStats {
212  public:
213   MemStats(const char* name, const ArenaAllocatorStats* stats, const Arena* first_arena,
214            ssize_t lost_bytes_adjustment = 0);
215   void Dump(std::ostream& os) const;
216 
217  private:
218   const char* const name_;
219   const ArenaAllocatorStats* const stats_;
220   const Arena* const first_arena_;
221   const ssize_t lost_bytes_adjustment_;
222 };  // MemStats
223 
224 }  // namespace art
225 
226 #endif  // ART_COMPILER_UTILS_ARENA_ALLOCATOR_H_
227