/* * Copyright (C) 2014 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_RUNTIME_BASE_SCOPED_ARENA_ALLOCATOR_H_ #define ART_RUNTIME_BASE_SCOPED_ARENA_ALLOCATOR_H_ #include "arena_allocator.h" #include "debug_stack.h" #include "globals.h" #include "logging.h" #include "macros.h" namespace art { class ArenaStack; class ScopedArenaAllocator; template <typename T> class ScopedArenaAllocatorAdapter; // Holds a list of Arenas for use by ScopedArenaAllocator stack. class ArenaStack : private DebugStackRefCounter { public: explicit ArenaStack(ArenaPool* arena_pool); ~ArenaStack(); void Reset(); size_t PeakBytesAllocated() { return PeakStats()->BytesAllocated(); } MemStats GetPeakStats() const; private: struct Peak; struct Current; template <typename Tag> struct TaggedStats : ArenaAllocatorStats { }; struct StatsAndPool : TaggedStats<Peak>, TaggedStats<Current> { explicit StatsAndPool(ArenaPool* arena_pool) : pool(arena_pool) { } ArenaPool* const pool; }; ArenaAllocatorStats* PeakStats() { return static_cast<TaggedStats<Peak>*>(&stats_and_pool_); } ArenaAllocatorStats* CurrentStats() { return static_cast<TaggedStats<Current>*>(&stats_and_pool_); } // Private - access via ScopedArenaAllocator or ScopedArenaAllocatorAdapter. void* Alloc(size_t bytes, ArenaAllocKind kind) ALWAYS_INLINE { if (UNLIKELY(running_on_valgrind_)) { return AllocValgrind(bytes, kind); } size_t rounded_bytes = RoundUp(bytes, 8); uint8_t* ptr = top_ptr_; if (UNLIKELY(static_cast<size_t>(top_end_ - ptr) < rounded_bytes)) { ptr = AllocateFromNextArena(rounded_bytes); } CurrentStats()->RecordAlloc(bytes, kind); top_ptr_ = ptr + rounded_bytes; return ptr; } uint8_t* AllocateFromNextArena(size_t rounded_bytes); void UpdatePeakStatsAndRestore(const ArenaAllocatorStats& restore_stats); void UpdateBytesAllocated(); void* AllocValgrind(size_t bytes, ArenaAllocKind kind); StatsAndPool stats_and_pool_; Arena* bottom_arena_; Arena* top_arena_; uint8_t* top_ptr_; uint8_t* top_end_; const bool running_on_valgrind_; friend class ScopedArenaAllocator; template <typename T> friend class ScopedArenaAllocatorAdapter; DISALLOW_COPY_AND_ASSIGN(ArenaStack); }; class ScopedArenaAllocator : private DebugStackReference, private DebugStackRefCounter, private ArenaAllocatorStats { public: // Create a ScopedArenaAllocator directly on the ArenaStack when the scope of // the allocator is not exactly a C++ block scope. For example, an optimization // pass can create the scoped allocator in Start() and destroy it in End(). static ScopedArenaAllocator* Create(ArenaStack* arena_stack) { void* addr = arena_stack->Alloc(sizeof(ScopedArenaAllocator), kArenaAllocMisc); ScopedArenaAllocator* allocator = new(addr) ScopedArenaAllocator(arena_stack); allocator->mark_ptr_ = reinterpret_cast<uint8_t*>(addr); return allocator; } explicit ScopedArenaAllocator(ArenaStack* arena_stack); ~ScopedArenaAllocator(); void Reset(); void* Alloc(size_t bytes, ArenaAllocKind kind = kArenaAllocMisc) ALWAYS_INLINE { DebugStackReference::CheckTop(); return arena_stack_->Alloc(bytes, kind); } template <typename T> T* AllocArray(size_t length, ArenaAllocKind kind = kArenaAllocMisc) { return static_cast<T*>(Alloc(length * sizeof(T), kind)); } // Get adapter for use in STL containers. See scoped_arena_containers.h . ScopedArenaAllocatorAdapter<void> Adapter(ArenaAllocKind kind = kArenaAllocSTL); // Allow a delete-expression to destroy but not deallocate allocators created by Create(). static void operator delete(void* ptr) { UNUSED(ptr); } private: ArenaStack* const arena_stack_; Arena* mark_arena_; uint8_t* mark_ptr_; uint8_t* mark_end_; void DoReset(); template <typename T> friend class ScopedArenaAllocatorAdapter; DISALLOW_COPY_AND_ASSIGN(ScopedArenaAllocator); }; } // namespace art #endif // ART_RUNTIME_BASE_SCOPED_ARENA_ALLOCATOR_H_