/* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ART_COMPILER_UTILS_ARENA_ALLOCATOR_H_ #define ART_COMPILER_UTILS_ARENA_ALLOCATOR_H_ #include <stdint.h> #include <stddef.h> #include "base/macros.h" #include "base/mutex.h" #include "mem_map.h" #include "utils.h" #include "utils/debug_stack.h" namespace art { class Arena; class ArenaPool; class ArenaAllocator; class ArenaStack; class ScopedArenaAllocator; class MemStats; template <typename T> class ArenaAllocatorAdapter; static constexpr bool kArenaAllocatorCountAllocations = false; // Type of allocation for memory tuning. enum ArenaAllocKind { kArenaAllocMisc, kArenaAllocBB, kArenaAllocLIR, kArenaAllocLIRResourceMask, kArenaAllocMIR, kArenaAllocDFInfo, kArenaAllocGrowableArray, kArenaAllocGrowableBitMap, kArenaAllocDalvikToSSAMap, kArenaAllocDebugInfo, kArenaAllocSuccessor, kArenaAllocRegAlloc, kArenaAllocData, kArenaAllocPredecessors, kArenaAllocSTL, kNumArenaAllocKinds }; template <bool kCount> class ArenaAllocatorStatsImpl; template <> class ArenaAllocatorStatsImpl<false> { public: ArenaAllocatorStatsImpl() = default; ArenaAllocatorStatsImpl(const ArenaAllocatorStatsImpl& other) = default; ArenaAllocatorStatsImpl& operator = (const ArenaAllocatorStatsImpl& other) = delete; void Copy(const ArenaAllocatorStatsImpl& other) { UNUSED(other); } void RecordAlloc(size_t bytes, ArenaAllocKind kind) { UNUSED(bytes); UNUSED(kind); } size_t NumAllocations() const { return 0u; } size_t BytesAllocated() const { return 0u; } void Dump(std::ostream& os, const Arena* first, ssize_t lost_bytes_adjustment) const { UNUSED(os); UNUSED(first); UNUSED(lost_bytes_adjustment); } }; template <bool kCount> class ArenaAllocatorStatsImpl { public: ArenaAllocatorStatsImpl(); ArenaAllocatorStatsImpl(const ArenaAllocatorStatsImpl& other) = default; ArenaAllocatorStatsImpl& operator = (const ArenaAllocatorStatsImpl& other) = delete; void Copy(const ArenaAllocatorStatsImpl& other); void RecordAlloc(size_t bytes, ArenaAllocKind kind); size_t NumAllocations() const; size_t BytesAllocated() const; void Dump(std::ostream& os, const Arena* first, ssize_t lost_bytes_adjustment) const; private: size_t num_allocations_; // TODO: Use std::array<size_t, kNumArenaAllocKinds> from C++11 when we upgrade the STL. size_t alloc_stats_[kNumArenaAllocKinds]; // Bytes used by various allocation kinds. static const char* const kAllocNames[]; }; typedef ArenaAllocatorStatsImpl<kArenaAllocatorCountAllocations> ArenaAllocatorStats; class Arena { public: static constexpr size_t kDefaultSize = 128 * KB; explicit Arena(size_t size = kDefaultSize); ~Arena(); void Reset(); uint8_t* Begin() { return memory_; } uint8_t* End() { return memory_ + size_; } size_t Size() const { return size_; } size_t RemainingSpace() const { return Size() - bytes_allocated_; } size_t GetBytesAllocated() const { return bytes_allocated_; } private: size_t bytes_allocated_; uint8_t* memory_; size_t size_; MemMap* map_; Arena* next_; friend class ArenaPool; friend class ArenaAllocator; friend class ArenaStack; friend class ScopedArenaAllocator; template <bool kCount> friend class ArenaAllocatorStatsImpl; DISALLOW_COPY_AND_ASSIGN(Arena); }; class ArenaPool { public: ArenaPool(); ~ArenaPool(); Arena* AllocArena(size_t size) LOCKS_EXCLUDED(lock_); void FreeArenaChain(Arena* first) LOCKS_EXCLUDED(lock_); size_t GetBytesAllocated() const LOCKS_EXCLUDED(lock_); private: mutable Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; Arena* free_arenas_ GUARDED_BY(lock_); DISALLOW_COPY_AND_ASSIGN(ArenaPool); }; class ArenaAllocator : private DebugStackRefCounter, private ArenaAllocatorStats { public: explicit ArenaAllocator(ArenaPool* pool); ~ArenaAllocator(); // Get adapter for use in STL containers. See arena_containers.h . ArenaAllocatorAdapter<void> Adapter(ArenaAllocKind kind = kArenaAllocSTL); // Returns zeroed memory. void* Alloc(size_t bytes, ArenaAllocKind kind) ALWAYS_INLINE { if (UNLIKELY(running_on_valgrind_)) { return AllocValgrind(bytes, kind); } bytes = RoundUp(bytes, 8); if (UNLIKELY(ptr_ + bytes > end_)) { // Obtain a new block. ObtainNewArenaForAllocation(bytes); if (UNLIKELY(ptr_ == nullptr)) { return nullptr; } } ArenaAllocatorStats::RecordAlloc(bytes, kind); uint8_t* ret = ptr_; ptr_ += bytes; return ret; } template <typename T> T* AllocArray(size_t length) { return static_cast<T*>(Alloc(length * sizeof(T), kArenaAllocMisc)); } void* AllocValgrind(size_t bytes, ArenaAllocKind kind); void ObtainNewArenaForAllocation(size_t allocation_size); size_t BytesAllocated() const; MemStats GetMemStats() const; private: void UpdateBytesAllocated(); ArenaPool* pool_; uint8_t* begin_; uint8_t* end_; uint8_t* ptr_; Arena* arena_head_; bool running_on_valgrind_; template <typename U> friend class ArenaAllocatorAdapter; DISALLOW_COPY_AND_ASSIGN(ArenaAllocator); }; // ArenaAllocator class MemStats { public: MemStats(const char* name, const ArenaAllocatorStats* stats, const Arena* first_arena, ssize_t lost_bytes_adjustment = 0); void Dump(std::ostream& os) const; private: const char* const name_; const ArenaAllocatorStats* const stats_; const Arena* const first_arena_; const ssize_t lost_bytes_adjustment_; }; // MemStats } // namespace art #endif // ART_COMPILER_UTILS_ARENA_ALLOCATOR_H_