summaryrefslogtreecommitdiffstats
path: root/runtime/base
diff options
context:
space:
mode:
authorMathieu Chartier <mathieuc@google.com>2015-02-18 14:33:14 -0800
committerMathieu Chartier <mathieuc@google.com>2015-02-19 09:59:50 -0800
commitb666f4805c8ae707ea6fd7f6c7f375e0b000dba8 (patch)
treea61439a9bcb555dc575286f3e0bb5e50ce185982 /runtime/base
parent39109a06015c91188232e59fa9e60e0915d24cd7 (diff)
downloadart-b666f4805c8ae707ea6fd7f6c7f375e0b000dba8.tar.gz
art-b666f4805c8ae707ea6fd7f6c7f375e0b000dba8.tar.bz2
art-b666f4805c8ae707ea6fd7f6c7f375e0b000dba8.zip
Move arenas into runtime
Moved arena pool into the runtime. Motivation: Allow GC to use arena allocators, recycle arena pool for linear alloc. Bug: 19264997 Change-Id: I8ddbb6d55ee923a980b28fb656c758c5d7697c2f
Diffstat (limited to 'runtime/base')
-rw-r--r--runtime/base/arena_allocator.cc296
-rw-r--r--runtime/base/arena_allocator.h240
-rw-r--r--runtime/base/arena_containers.h206
-rw-r--r--runtime/base/arena_object.h67
-rw-r--r--runtime/base/debug_stack.h138
-rw-r--r--runtime/base/scoped_arena_allocator.cc146
-rw-r--r--runtime/base/scoped_arena_allocator.h150
-rw-r--r--runtime/base/scoped_arena_containers.h193
8 files changed, 1436 insertions, 0 deletions
diff --git a/runtime/base/arena_allocator.cc b/runtime/base/arena_allocator.cc
new file mode 100644
index 0000000000..b3f812e5e0
--- /dev/null
+++ b/runtime/base/arena_allocator.cc
@@ -0,0 +1,296 @@
+/*
+ * 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.
+ */
+
+#include <algorithm>
+#include <iomanip>
+#include <numeric>
+
+#include "arena_allocator.h"
+#include "logging.h"
+#include "mutex.h"
+#include "thread-inl.h"
+#include <memcheck/memcheck.h>
+
+namespace art {
+
+// Memmap is a bit slower than malloc according to my measurements.
+static constexpr bool kUseMemMap = false;
+static constexpr bool kUseMemSet = true && kUseMemMap;
+static constexpr size_t kValgrindRedZoneBytes = 8;
+constexpr size_t Arena::kDefaultSize;
+
+template <bool kCount>
+const char* const ArenaAllocatorStatsImpl<kCount>::kAllocNames[] = {
+ "Misc ",
+ "BasicBlock ",
+ "BBList "
+ "BBPreds ",
+ "DfsPreOrd ",
+ "DfsPostOrd ",
+ "DomPostOrd ",
+ "TopoOrd ",
+ "Lowering ",
+ "LIR ",
+ "LIR masks ",
+ "SwitchTbl ",
+ "FillArray ",
+ "SlowPaths ",
+ "MIR ",
+ "DataFlow ",
+ "GrowList ",
+ "GrowBitMap ",
+ "SSA2Dalvik ",
+ "Dalvik2SSA ",
+ "DebugInfo ",
+ "Successor ",
+ "RegAlloc ",
+ "Data ",
+ "Preds ",
+ "STL ",
+};
+
+template <bool kCount>
+ArenaAllocatorStatsImpl<kCount>::ArenaAllocatorStatsImpl()
+ : num_allocations_(0u) {
+ std::fill_n(alloc_stats_, arraysize(alloc_stats_), 0u);
+}
+
+template <bool kCount>
+void ArenaAllocatorStatsImpl<kCount>::Copy(const ArenaAllocatorStatsImpl& other) {
+ num_allocations_ = other.num_allocations_;
+ std::copy(other.alloc_stats_, other.alloc_stats_ + arraysize(alloc_stats_), alloc_stats_);
+}
+
+template <bool kCount>
+void ArenaAllocatorStatsImpl<kCount>::RecordAlloc(size_t bytes, ArenaAllocKind kind) {
+ alloc_stats_[kind] += bytes;
+ ++num_allocations_;
+}
+
+template <bool kCount>
+size_t ArenaAllocatorStatsImpl<kCount>::NumAllocations() const {
+ return num_allocations_;
+}
+
+template <bool kCount>
+size_t ArenaAllocatorStatsImpl<kCount>::BytesAllocated() const {
+ const size_t init = 0u; // Initial value of the correct type.
+ return std::accumulate(alloc_stats_, alloc_stats_ + arraysize(alloc_stats_), init);
+}
+
+template <bool kCount>
+void ArenaAllocatorStatsImpl<kCount>::Dump(std::ostream& os, const Arena* first,
+ ssize_t lost_bytes_adjustment) const {
+ size_t malloc_bytes = 0u;
+ size_t lost_bytes = 0u;
+ size_t num_arenas = 0u;
+ for (const Arena* arena = first; arena != nullptr; arena = arena->next_) {
+ malloc_bytes += arena->Size();
+ lost_bytes += arena->RemainingSpace();
+ ++num_arenas;
+ }
+ // The lost_bytes_adjustment is used to make up for the fact that the current arena
+ // may not have the bytes_allocated_ updated correctly.
+ lost_bytes += lost_bytes_adjustment;
+ const size_t bytes_allocated = BytesAllocated();
+ os << " MEM: used: " << bytes_allocated << ", allocated: " << malloc_bytes
+ << ", lost: " << lost_bytes << "\n";
+ size_t num_allocations = NumAllocations();
+ if (num_allocations != 0) {
+ os << "Number of arenas allocated: " << num_arenas << ", Number of allocations: "
+ << num_allocations << ", avg size: " << bytes_allocated / num_allocations << "\n";
+ }
+ os << "===== Allocation by kind\n";
+ static_assert(arraysize(kAllocNames) == kNumArenaAllocKinds, "arraysize of kAllocNames");
+ for (int i = 0; i < kNumArenaAllocKinds; i++) {
+ os << kAllocNames[i] << std::setw(10) << alloc_stats_[i] << "\n";
+ }
+}
+
+// Explicitly instantiate the used implementation.
+template class ArenaAllocatorStatsImpl<kArenaAllocatorCountAllocations>;
+
+Arena::Arena(size_t size)
+ : bytes_allocated_(0),
+ map_(nullptr),
+ next_(nullptr) {
+ if (kUseMemMap) {
+ std::string error_msg;
+ map_ = MemMap::MapAnonymous("dalvik-arena", NULL, size, PROT_READ | PROT_WRITE, false,
+ &error_msg);
+ CHECK(map_ != nullptr) << error_msg;
+ memory_ = map_->Begin();
+ size_ = map_->Size();
+ } else {
+ memory_ = reinterpret_cast<uint8_t*>(calloc(1, size));
+ size_ = size;
+ }
+}
+
+Arena::~Arena() {
+ if (kUseMemMap) {
+ delete map_;
+ } else {
+ free(reinterpret_cast<void*>(memory_));
+ }
+}
+
+void Arena::Reset() {
+ if (bytes_allocated_) {
+ if (kUseMemSet || !kUseMemMap) {
+ memset(Begin(), 0, bytes_allocated_);
+ } else {
+ map_->MadviseDontNeedAndZero();
+ }
+ bytes_allocated_ = 0;
+ }
+}
+
+ArenaPool::ArenaPool()
+ : lock_("Arena pool lock"),
+ free_arenas_(nullptr) {
+}
+
+ArenaPool::~ArenaPool() {
+ while (free_arenas_ != nullptr) {
+ auto* arena = free_arenas_;
+ free_arenas_ = free_arenas_->next_;
+ delete arena;
+ }
+}
+
+Arena* ArenaPool::AllocArena(size_t size) {
+ Thread* self = Thread::Current();
+ Arena* ret = nullptr;
+ {
+ MutexLock lock(self, lock_);
+ if (free_arenas_ != nullptr && LIKELY(free_arenas_->Size() >= size)) {
+ ret = free_arenas_;
+ free_arenas_ = free_arenas_->next_;
+ }
+ }
+ if (ret == nullptr) {
+ ret = new Arena(size);
+ }
+ ret->Reset();
+ return ret;
+}
+
+size_t ArenaPool::GetBytesAllocated() const {
+ size_t total = 0;
+ MutexLock lock(Thread::Current(), lock_);
+ for (Arena* arena = free_arenas_; arena != nullptr; arena = arena->next_) {
+ total += arena->GetBytesAllocated();
+ }
+ return total;
+}
+
+void ArenaPool::FreeArenaChain(Arena* first) {
+ if (UNLIKELY(RUNNING_ON_VALGRIND > 0)) {
+ for (Arena* arena = first; arena != nullptr; arena = arena->next_) {
+ VALGRIND_MAKE_MEM_UNDEFINED(arena->memory_, arena->bytes_allocated_);
+ }
+ }
+ if (first != nullptr) {
+ Arena* last = first;
+ while (last->next_ != nullptr) {
+ last = last->next_;
+ }
+ Thread* self = Thread::Current();
+ MutexLock lock(self, lock_);
+ last->next_ = free_arenas_;
+ free_arenas_ = first;
+ }
+}
+
+size_t ArenaAllocator::BytesAllocated() const {
+ return ArenaAllocatorStats::BytesAllocated();
+}
+
+ArenaAllocator::ArenaAllocator(ArenaPool* pool)
+ : pool_(pool),
+ begin_(nullptr),
+ end_(nullptr),
+ ptr_(nullptr),
+ arena_head_(nullptr),
+ running_on_valgrind_(RUNNING_ON_VALGRIND > 0) {
+}
+
+void ArenaAllocator::UpdateBytesAllocated() {
+ if (arena_head_ != nullptr) {
+ // Update how many bytes we have allocated into the arena so that the arena pool knows how
+ // much memory to zero out.
+ arena_head_->bytes_allocated_ = ptr_ - begin_;
+ }
+}
+
+void* ArenaAllocator::AllocValgrind(size_t bytes, ArenaAllocKind kind) {
+ size_t rounded_bytes = RoundUp(bytes + kValgrindRedZoneBytes, 8);
+ if (UNLIKELY(ptr_ + rounded_bytes > end_)) {
+ // Obtain a new block.
+ ObtainNewArenaForAllocation(rounded_bytes);
+ if (UNLIKELY(ptr_ == nullptr)) {
+ return nullptr;
+ }
+ }
+ ArenaAllocatorStats::RecordAlloc(rounded_bytes, kind);
+ uint8_t* ret = ptr_;
+ ptr_ += rounded_bytes;
+ // Check that the memory is already zeroed out.
+ for (uint8_t* ptr = ret; ptr < ptr_; ++ptr) {
+ CHECK_EQ(*ptr, 0U);
+ }
+ VALGRIND_MAKE_MEM_NOACCESS(ret + bytes, rounded_bytes - bytes);
+ return ret;
+}
+
+ArenaAllocator::~ArenaAllocator() {
+ // Reclaim all the arenas by giving them back to the thread pool.
+ UpdateBytesAllocated();
+ pool_->FreeArenaChain(arena_head_);
+}
+
+void ArenaAllocator::ObtainNewArenaForAllocation(size_t allocation_size) {
+ UpdateBytesAllocated();
+ Arena* new_arena = pool_->AllocArena(std::max(Arena::kDefaultSize, allocation_size));
+ new_arena->next_ = arena_head_;
+ arena_head_ = new_arena;
+ // Update our internal data structures.
+ ptr_ = begin_ = new_arena->Begin();
+ end_ = new_arena->End();
+}
+
+MemStats::MemStats(const char* name, const ArenaAllocatorStats* stats, const Arena* first_arena,
+ ssize_t lost_bytes_adjustment)
+ : name_(name),
+ stats_(stats),
+ first_arena_(first_arena),
+ lost_bytes_adjustment_(lost_bytes_adjustment) {
+}
+
+void MemStats::Dump(std::ostream& os) const {
+ os << name_ << " stats:\n";
+ stats_->Dump(os, first_arena_, lost_bytes_adjustment_);
+}
+
+// Dump memory usage stats.
+MemStats ArenaAllocator::GetMemStats() const {
+ ssize_t lost_bytes_adjustment =
+ (arena_head_ == nullptr) ? 0 : (end_ - ptr_) - arena_head_->RemainingSpace();
+ return MemStats("ArenaAllocator", this, arena_head_, lost_bytes_adjustment);
+}
+
+} // namespace art
diff --git a/runtime/base/arena_allocator.h b/runtime/base/arena_allocator.h
new file mode 100644
index 0000000000..92373919d4
--- /dev/null
+++ b/runtime/base/arena_allocator.h
@@ -0,0 +1,240 @@
+/*
+ * 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_RUNTIME_BASE_ARENA_ALLOCATOR_H_
+#define ART_RUNTIME_BASE_ARENA_ALLOCATOR_H_
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include "debug_stack.h"
+#include "macros.h"
+#include "mem_map.h"
+#include "mutex.h"
+#include "utils.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,
+ kArenaAllocBBList,
+ kArenaAllocBBPredecessors,
+ kArenaAllocDfsPreOrder,
+ kArenaAllocDfsPostOrder,
+ kArenaAllocDomPostOrder,
+ kArenaAllocTopologicalSortOrder,
+ kArenaAllocLoweringInfo,
+ kArenaAllocLIR,
+ kArenaAllocLIRResourceMask,
+ kArenaAllocSwitchTable,
+ kArenaAllocFillArrayData,
+ kArenaAllocSlowPaths,
+ kArenaAllocMIR,
+ kArenaAllocDFInfo,
+ kArenaAllocGrowableArray,
+ kArenaAllocGrowableBitMap,
+ kArenaAllocSSAToDalvikMap,
+ 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, 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 = kArenaAllocMisc) ALWAYS_INLINE {
+ if (UNLIKELY(running_on_valgrind_)) {
+ return AllocValgrind(bytes, kind);
+ }
+ bytes = RoundUp(bytes, kAlignment);
+ 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, ArenaAllocKind kind = kArenaAllocMisc) {
+ return static_cast<T*>(Alloc(length * sizeof(T), kind));
+ }
+
+ void* AllocValgrind(size_t bytes, ArenaAllocKind kind);
+ void ObtainNewArenaForAllocation(size_t allocation_size);
+ size_t BytesAllocated() const;
+ MemStats GetMemStats() const;
+
+ private:
+ static constexpr size_t kAlignment = 8;
+
+ 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_RUNTIME_BASE_ARENA_ALLOCATOR_H_
diff --git a/runtime/base/arena_containers.h b/runtime/base/arena_containers.h
new file mode 100644
index 0000000000..162eb16d49
--- /dev/null
+++ b/runtime/base/arena_containers.h
@@ -0,0 +1,206 @@
+/*
+ * 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_ARENA_CONTAINERS_H_
+#define ART_RUNTIME_BASE_ARENA_CONTAINERS_H_
+
+#include <deque>
+#include <queue>
+#include <set>
+#include <vector>
+
+#include "arena_allocator.h"
+#include "safe_map.h"
+
+namespace art {
+
+// Adapter for use of ArenaAllocator in STL containers.
+// Use ArenaAllocator::Adapter() to create an adapter to pass to container constructors.
+// For example,
+// struct Foo {
+// explicit Foo(ArenaAllocator* allocator)
+// : foo_vector(allocator->Adapter(kArenaAllocMisc)),
+// foo_map(std::less<int>(), allocator->Adapter()) {
+// }
+// ArenaVector<int> foo_vector;
+// ArenaSafeMap<int, int> foo_map;
+// };
+template <typename T>
+class ArenaAllocatorAdapter;
+
+template <typename T>
+using ArenaDeque = std::deque<T, ArenaAllocatorAdapter<T>>;
+
+template <typename T>
+using ArenaQueue = std::queue<T, ArenaDeque<T>>;
+
+template <typename T>
+using ArenaVector = std::vector<T, ArenaAllocatorAdapter<T>>;
+
+template <typename T, typename Comparator = std::less<T>>
+using ArenaSet = std::set<T, Comparator, ArenaAllocatorAdapter<T>>;
+
+template <typename K, typename V, typename Comparator = std::less<K>>
+using ArenaSafeMap =
+ SafeMap<K, V, Comparator, ArenaAllocatorAdapter<std::pair<const K, V>>>;
+
+// Implementation details below.
+
+template <bool kCount>
+class ArenaAllocatorAdapterKindImpl;
+
+template <>
+class ArenaAllocatorAdapterKindImpl<false> {
+ public:
+ // Not tracking allocations, ignore the supplied kind and arbitrarily provide kArenaAllocSTL.
+ explicit ArenaAllocatorAdapterKindImpl(ArenaAllocKind kind) { UNUSED(kind); }
+ ArenaAllocatorAdapterKindImpl& operator=(const ArenaAllocatorAdapterKindImpl& other) = default;
+ ArenaAllocKind Kind() { return kArenaAllocSTL; }
+};
+
+template <bool kCount>
+class ArenaAllocatorAdapterKindImpl {
+ public:
+ explicit ArenaAllocatorAdapterKindImpl(ArenaAllocKind kind) : kind_(kind) { }
+ ArenaAllocatorAdapterKindImpl& operator=(const ArenaAllocatorAdapterKindImpl& other) = default;
+ ArenaAllocKind Kind() { return kind_; }
+
+ private:
+ ArenaAllocKind kind_;
+};
+
+typedef ArenaAllocatorAdapterKindImpl<kArenaAllocatorCountAllocations> ArenaAllocatorAdapterKind;
+
+template <>
+class ArenaAllocatorAdapter<void>
+ : private DebugStackReference, private ArenaAllocatorAdapterKind {
+ public:
+ typedef void value_type;
+ typedef void* pointer;
+ typedef const void* const_pointer;
+
+ template <typename U>
+ struct rebind {
+ typedef ArenaAllocatorAdapter<U> other;
+ };
+
+ explicit ArenaAllocatorAdapter(ArenaAllocator* arena_allocator,
+ ArenaAllocKind kind = kArenaAllocSTL)
+ : DebugStackReference(arena_allocator),
+ ArenaAllocatorAdapterKind(kind),
+ arena_allocator_(arena_allocator) {
+ }
+ template <typename U>
+ ArenaAllocatorAdapter(const ArenaAllocatorAdapter<U>& other)
+ : DebugStackReference(other),
+ ArenaAllocatorAdapterKind(other),
+ arena_allocator_(other.arena_allocator_) {
+ }
+ ArenaAllocatorAdapter(const ArenaAllocatorAdapter& other) = default;
+ ArenaAllocatorAdapter& operator=(const ArenaAllocatorAdapter& other) = default;
+ ~ArenaAllocatorAdapter() = default;
+
+ private:
+ ArenaAllocator* arena_allocator_;
+
+ template <typename U>
+ friend class ArenaAllocatorAdapter;
+};
+
+template <typename T>
+class ArenaAllocatorAdapter : private DebugStackReference, private ArenaAllocatorAdapterKind {
+ public:
+ typedef T value_type;
+ typedef T* pointer;
+ typedef T& reference;
+ typedef const T* const_pointer;
+ typedef const T& const_reference;
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+
+ template <typename U>
+ struct rebind {
+ typedef ArenaAllocatorAdapter<U> other;
+ };
+
+ explicit ArenaAllocatorAdapter(ArenaAllocator* arena_allocator, ArenaAllocKind kind)
+ : DebugStackReference(arena_allocator),
+ ArenaAllocatorAdapterKind(kind),
+ arena_allocator_(arena_allocator) {
+ }
+ template <typename U>
+ ArenaAllocatorAdapter(const ArenaAllocatorAdapter<U>& other)
+ : DebugStackReference(other),
+ ArenaAllocatorAdapterKind(other),
+ arena_allocator_(other.arena_allocator_) {
+ }
+ ArenaAllocatorAdapter(const ArenaAllocatorAdapter& other) = default;
+ ArenaAllocatorAdapter& operator=(const ArenaAllocatorAdapter& other) = default;
+ ~ArenaAllocatorAdapter() = default;
+
+ size_type max_size() const {
+ return static_cast<size_type>(-1) / sizeof(T);
+ }
+
+ pointer address(reference x) const { return &x; }
+ const_pointer address(const_reference x) const { return &x; }
+
+ pointer allocate(size_type n, ArenaAllocatorAdapter<void>::pointer hint = nullptr) {
+ UNUSED(hint);
+ DCHECK_LE(n, max_size());
+ return arena_allocator_->AllocArray<T>(n, ArenaAllocatorAdapterKind::Kind());
+ }
+ void deallocate(pointer p, size_type n) {
+ UNUSED(p, n);
+ }
+
+ void construct(pointer p, const_reference val) {
+ new (static_cast<void*>(p)) value_type(val);
+ }
+ void destroy(pointer p) {
+ p->~value_type();
+ }
+
+ private:
+ ArenaAllocator* arena_allocator_;
+
+ template <typename U>
+ friend class ArenaAllocatorAdapter;
+
+ template <typename U>
+ friend bool operator==(const ArenaAllocatorAdapter<U>& lhs,
+ const ArenaAllocatorAdapter<U>& rhs);
+};
+
+template <typename T>
+inline bool operator==(const ArenaAllocatorAdapter<T>& lhs,
+ const ArenaAllocatorAdapter<T>& rhs) {
+ return lhs.arena_allocator_ == rhs.arena_allocator_;
+}
+
+template <typename T>
+inline bool operator!=(const ArenaAllocatorAdapter<T>& lhs,
+ const ArenaAllocatorAdapter<T>& rhs) {
+ return !(lhs == rhs);
+}
+
+inline ArenaAllocatorAdapter<void> ArenaAllocator::Adapter(ArenaAllocKind kind) {
+ return ArenaAllocatorAdapter<void>(this, kind);
+}
+
+} // namespace art
+
+#endif // ART_RUNTIME_BASE_ARENA_CONTAINERS_H_
diff --git a/runtime/base/arena_object.h b/runtime/base/arena_object.h
new file mode 100644
index 0000000000..ab97d0cb66
--- /dev/null
+++ b/runtime/base/arena_object.h
@@ -0,0 +1,67 @@
+/*
+ * 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_ARENA_OBJECT_H_
+#define ART_RUNTIME_BASE_ARENA_OBJECT_H_
+
+#include "base/arena_allocator.h"
+#include "base/logging.h"
+#include "scoped_arena_allocator.h"
+
+namespace art {
+
+// Parent for arena allocated objects giving appropriate new and delete operators.
+template<enum ArenaAllocKind kAllocKind>
+class ArenaObject {
+ public:
+ // Allocate a new ArenaObject of 'size' bytes in the Arena.
+ void* operator new(size_t size, ArenaAllocator* allocator) {
+ return allocator->Alloc(size, kAllocKind);
+ }
+
+ static void* operator new(size_t size, ScopedArenaAllocator* arena) {
+ return arena->Alloc(size, kAllocKind);
+ }
+
+ void operator delete(void*, size_t) {
+ LOG(FATAL) << "UNREACHABLE";
+ UNREACHABLE();
+ }
+};
+
+
+// Parent for arena allocated objects that get deleted, gives appropriate new and delete operators.
+// Currently this is used by the quick compiler for debug reference counting arena allocations.
+template<enum ArenaAllocKind kAllocKind>
+class DeletableArenaObject {
+ public:
+ // Allocate a new ArenaObject of 'size' bytes in the Arena.
+ void* operator new(size_t size, ArenaAllocator* allocator) {
+ return allocator->Alloc(size, kAllocKind);
+ }
+
+ static void* operator new(size_t size, ScopedArenaAllocator* arena) {
+ return arena->Alloc(size, kAllocKind);
+ }
+
+ void operator delete(void*, size_t) {
+ // Nop.
+ }
+};
+
+} // namespace art
+
+#endif // ART_RUNTIME_BASE_ARENA_OBJECT_H_
diff --git a/runtime/base/debug_stack.h b/runtime/base/debug_stack.h
new file mode 100644
index 0000000000..03f457534e
--- /dev/null
+++ b/runtime/base/debug_stack.h
@@ -0,0 +1,138 @@
+/*
+ * 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_DEBUG_STACK_H_
+#define ART_RUNTIME_BASE_DEBUG_STACK_H_
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "globals.h"
+
+namespace art {
+
+// Helper classes for reference counting to enforce construction/destruction order and
+// usage of the top element of a stack in debug mode with no overhead in release mode.
+
+// Reference counter. No references allowed in destructor or in explicitly called CheckNoRefs().
+template <bool kIsDebug>
+class DebugStackRefCounterImpl;
+// Reference. Allows an explicit check that it's the top reference.
+template <bool kIsDebug>
+class DebugStackReferenceImpl;
+// Indirect top reference. Checks that the reference is the top reference when used.
+template <bool kIsDebug>
+class DebugStackIndirectTopRefImpl;
+
+typedef DebugStackRefCounterImpl<kIsDebugBuild> DebugStackRefCounter;
+typedef DebugStackReferenceImpl<kIsDebugBuild> DebugStackReference;
+typedef DebugStackIndirectTopRefImpl<kIsDebugBuild> DebugStackIndirectTopRef;
+
+// Non-debug mode specializations. This should be optimized away.
+
+template <>
+class DebugStackRefCounterImpl<false> {
+ public:
+ size_t IncrementRefCount() { return 0u; }
+ void DecrementRefCount() { }
+ size_t GetRefCount() const { return 0u; }
+ void CheckNoRefs() const { }
+};
+
+template <>
+class DebugStackReferenceImpl<false> {
+ public:
+ explicit DebugStackReferenceImpl(DebugStackRefCounterImpl<false>* counter) { UNUSED(counter); }
+ DebugStackReferenceImpl(const DebugStackReferenceImpl& other) = default;
+ DebugStackReferenceImpl& operator=(const DebugStackReferenceImpl& other) = default;
+ void CheckTop() { }
+};
+
+template <>
+class DebugStackIndirectTopRefImpl<false> {
+ public:
+ explicit DebugStackIndirectTopRefImpl(DebugStackReferenceImpl<false>* ref) { UNUSED(ref); }
+ DebugStackIndirectTopRefImpl(const DebugStackIndirectTopRefImpl& other) = default;
+ DebugStackIndirectTopRefImpl& operator=(const DebugStackIndirectTopRefImpl& other) = default;
+ void CheckTop() { }
+};
+
+// Debug mode versions.
+
+template <bool kIsDebug>
+class DebugStackRefCounterImpl {
+ public:
+ DebugStackRefCounterImpl() : ref_count_(0u) { }
+ ~DebugStackRefCounterImpl() { CheckNoRefs(); }
+ size_t IncrementRefCount() { return ++ref_count_; }
+ void DecrementRefCount() { --ref_count_; }
+ size_t GetRefCount() const { return ref_count_; }
+ void CheckNoRefs() const { CHECK_EQ(ref_count_, 0u); }
+
+ private:
+ size_t ref_count_;
+};
+
+template <bool kIsDebug>
+class DebugStackReferenceImpl {
+ public:
+ explicit DebugStackReferenceImpl(DebugStackRefCounterImpl<kIsDebug>* counter)
+ : counter_(counter), ref_count_(counter->IncrementRefCount()) {
+ }
+ DebugStackReferenceImpl(const DebugStackReferenceImpl& other)
+ : counter_(other.counter_), ref_count_(counter_->IncrementRefCount()) {
+ }
+ DebugStackReferenceImpl& operator=(const DebugStackReferenceImpl& other) {
+ CHECK(counter_ == other.counter_);
+ return *this;
+ }
+ ~DebugStackReferenceImpl() { counter_->DecrementRefCount(); }
+ void CheckTop() { CHECK_EQ(counter_->GetRefCount(), ref_count_); }
+
+ private:
+ DebugStackRefCounterImpl<true>* counter_;
+ size_t ref_count_;
+};
+
+template <bool kIsDebug>
+class DebugStackIndirectTopRefImpl {
+ public:
+ explicit DebugStackIndirectTopRefImpl(DebugStackReferenceImpl<kIsDebug>* ref)
+ : ref_(ref) {
+ CheckTop();
+ }
+ DebugStackIndirectTopRefImpl(const DebugStackIndirectTopRefImpl& other)
+ : ref_(other.ref_) {
+ CheckTop();
+ }
+ DebugStackIndirectTopRefImpl& operator=(const DebugStackIndirectTopRefImpl& other) {
+ CHECK(ref_ == other.ref_);
+ CheckTop();
+ return *this;
+ }
+ ~DebugStackIndirectTopRefImpl() {
+ CheckTop();
+ }
+ void CheckTop() {
+ ref_->CheckTop();
+ }
+
+ private:
+ DebugStackReferenceImpl<kIsDebug>* ref_;
+};
+
+} // namespace art
+
+#endif // ART_RUNTIME_BASE_DEBUG_STACK_H_
diff --git a/runtime/base/scoped_arena_allocator.cc b/runtime/base/scoped_arena_allocator.cc
new file mode 100644
index 0000000000..4a7be384b1
--- /dev/null
+++ b/runtime/base/scoped_arena_allocator.cc
@@ -0,0 +1,146 @@
+/*
+ * 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.
+ */
+
+#include "scoped_arena_allocator.h"
+
+#include "arena_allocator.h"
+#include <memcheck/memcheck.h>
+
+namespace art {
+
+static constexpr size_t kValgrindRedZoneBytes = 8;
+
+ArenaStack::ArenaStack(ArenaPool* arena_pool)
+ : DebugStackRefCounter(),
+ stats_and_pool_(arena_pool),
+ bottom_arena_(nullptr),
+ top_arena_(nullptr),
+ top_ptr_(nullptr),
+ top_end_(nullptr),
+ running_on_valgrind_(RUNNING_ON_VALGRIND > 0) {
+}
+
+ArenaStack::~ArenaStack() {
+ DebugStackRefCounter::CheckNoRefs();
+ stats_and_pool_.pool->FreeArenaChain(bottom_arena_);
+}
+
+void ArenaStack::Reset() {
+ DebugStackRefCounter::CheckNoRefs();
+ stats_and_pool_.pool->FreeArenaChain(bottom_arena_);
+ bottom_arena_ = nullptr;
+ top_arena_ = nullptr;
+ top_ptr_ = nullptr;
+ top_end_ = nullptr;
+}
+
+MemStats ArenaStack::GetPeakStats() const {
+ DebugStackRefCounter::CheckNoRefs();
+ return MemStats("ArenaStack peak", static_cast<const TaggedStats<Peak>*>(&stats_and_pool_),
+ bottom_arena_);
+}
+
+uint8_t* ArenaStack::AllocateFromNextArena(size_t rounded_bytes) {
+ UpdateBytesAllocated();
+ size_t allocation_size = std::max(Arena::kDefaultSize, rounded_bytes);
+ if (UNLIKELY(top_arena_ == nullptr)) {
+ top_arena_ = bottom_arena_ = stats_and_pool_.pool->AllocArena(allocation_size);
+ top_arena_->next_ = nullptr;
+ } else if (top_arena_->next_ != nullptr && top_arena_->next_->Size() >= allocation_size) {
+ top_arena_ = top_arena_->next_;
+ } else {
+ Arena* tail = top_arena_->next_;
+ top_arena_->next_ = stats_and_pool_.pool->AllocArena(allocation_size);
+ top_arena_ = top_arena_->next_;
+ top_arena_->next_ = tail;
+ }
+ top_end_ = top_arena_->End();
+ // top_ptr_ shall be updated by ScopedArenaAllocator.
+ return top_arena_->Begin();
+}
+
+void ArenaStack::UpdatePeakStatsAndRestore(const ArenaAllocatorStats& restore_stats) {
+ if (PeakStats()->BytesAllocated() < CurrentStats()->BytesAllocated()) {
+ PeakStats()->Copy(*CurrentStats());
+ }
+ CurrentStats()->Copy(restore_stats);
+}
+
+void ArenaStack::UpdateBytesAllocated() {
+ if (top_arena_ != nullptr) {
+ // Update how many bytes we have allocated into the arena so that the arena pool knows how
+ // much memory to zero out. Though ScopedArenaAllocator doesn't guarantee the memory is
+ // zero-initialized, the Arena may be reused by ArenaAllocator which does guarantee this.
+ size_t allocated = static_cast<size_t>(top_ptr_ - top_arena_->Begin());
+ if (top_arena_->bytes_allocated_ < allocated) {
+ top_arena_->bytes_allocated_ = allocated;
+ }
+ }
+}
+
+void* ArenaStack::AllocValgrind(size_t bytes, ArenaAllocKind kind) {
+ size_t rounded_bytes = RoundUp(bytes + kValgrindRedZoneBytes, 8);
+ uint8_t* ptr = top_ptr_;
+ if (UNLIKELY(static_cast<size_t>(top_end_ - ptr) < rounded_bytes)) {
+ ptr = AllocateFromNextArena(rounded_bytes);
+ CHECK(ptr != nullptr) << "Failed to allocate memory";
+ }
+ CurrentStats()->RecordAlloc(bytes, kind);
+ top_ptr_ = ptr + rounded_bytes;
+ VALGRIND_MAKE_MEM_UNDEFINED(ptr, bytes);
+ VALGRIND_MAKE_MEM_NOACCESS(ptr + bytes, rounded_bytes - bytes);
+ return ptr;
+}
+
+ScopedArenaAllocator::ScopedArenaAllocator(ArenaStack* arena_stack)
+ : DebugStackReference(arena_stack),
+ DebugStackRefCounter(),
+ ArenaAllocatorStats(*arena_stack->CurrentStats()),
+ arena_stack_(arena_stack),
+ mark_arena_(arena_stack->top_arena_),
+ mark_ptr_(arena_stack->top_ptr_),
+ mark_end_(arena_stack->top_end_) {
+}
+
+ScopedArenaAllocator::~ScopedArenaAllocator() {
+ DoReset();
+}
+
+void ScopedArenaAllocator::Reset() {
+ DoReset();
+ // If this allocator was Create()d, we need to move the arena_stack_->top_ptr_ past *this.
+ if (mark_ptr_ == reinterpret_cast<uint8_t*>(this)) {
+ arena_stack_->top_ptr_ = mark_ptr_ + RoundUp(sizeof(ScopedArenaAllocator), 8);
+ }
+}
+
+void ScopedArenaAllocator::DoReset() {
+ DebugStackReference::CheckTop();
+ DebugStackRefCounter::CheckNoRefs();
+ arena_stack_->UpdatePeakStatsAndRestore(*this);
+ arena_stack_->UpdateBytesAllocated();
+ if (LIKELY(mark_arena_ != nullptr)) {
+ arena_stack_->top_arena_ = mark_arena_;
+ arena_stack_->top_ptr_ = mark_ptr_;
+ arena_stack_->top_end_ = mark_end_;
+ } else if (arena_stack_->bottom_arena_ != nullptr) {
+ mark_arena_ = arena_stack_->top_arena_ = arena_stack_->bottom_arena_;
+ mark_ptr_ = arena_stack_->top_ptr_ = mark_arena_->Begin();
+ mark_end_ = arena_stack_->top_end_ = mark_arena_->End();
+ }
+}
+
+} // namespace art
diff --git a/runtime/base/scoped_arena_allocator.h b/runtime/base/scoped_arena_allocator.h
new file mode 100644
index 0000000000..bbedeac3b0
--- /dev/null
+++ b/runtime/base/scoped_arena_allocator.h
@@ -0,0 +1,150 @@
+/*
+ * 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_
diff --git a/runtime/base/scoped_arena_containers.h b/runtime/base/scoped_arena_containers.h
new file mode 100644
index 0000000000..664a909e5f
--- /dev/null
+++ b/runtime/base/scoped_arena_containers.h
@@ -0,0 +1,193 @@
+/*
+ * 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_CONTAINERS_H_
+#define ART_RUNTIME_BASE_SCOPED_ARENA_CONTAINERS_H_
+
+#include <deque>
+#include <queue>
+#include <set>
+#include <vector>
+
+#include "arena_containers.h" // For ArenaAllocatorAdapterKind.
+#include "scoped_arena_allocator.h"
+#include "safe_map.h"
+
+namespace art {
+
+// Adapter for use of ScopedArenaAllocator in STL containers.
+// Use ScopedArenaAllocator::Adapter() to create an adapter to pass to container constructors.
+// For example,
+// void foo(ScopedArenaAllocator* allocator) {
+// ScopedArenaVector<int> foo_vector(allocator->Adapter(kArenaAllocMisc));
+// ScopedArenaSafeMap<int, int> foo_map(std::less<int>(), allocator->Adapter());
+// // Use foo_vector and foo_map...
+// }
+template <typename T>
+class ScopedArenaAllocatorAdapter;
+
+template <typename T>
+using ScopedArenaDeque = std::deque<T, ScopedArenaAllocatorAdapter<T>>;
+
+template <typename T>
+using ScopedArenaQueue = std::queue<T, ScopedArenaDeque<T>>;
+
+template <typename T>
+using ScopedArenaVector = std::vector<T, ScopedArenaAllocatorAdapter<T>>;
+
+template <typename T, typename Comparator = std::less<T>>
+using ScopedArenaSet = std::set<T, Comparator, ScopedArenaAllocatorAdapter<T>>;
+
+template <typename K, typename V, typename Comparator = std::less<K>>
+using ScopedArenaSafeMap =
+ SafeMap<K, V, Comparator, ScopedArenaAllocatorAdapter<std::pair<const K, V>>>;
+
+// Implementation details below.
+
+template <>
+class ScopedArenaAllocatorAdapter<void>
+ : private DebugStackReference, private DebugStackIndirectTopRef,
+ private ArenaAllocatorAdapterKind {
+ public:
+ typedef void value_type;
+ typedef void* pointer;
+ typedef const void* const_pointer;
+
+ template <typename U>
+ struct rebind {
+ typedef ScopedArenaAllocatorAdapter<U> other;
+ };
+
+ explicit ScopedArenaAllocatorAdapter(ScopedArenaAllocator* arena_allocator,
+ ArenaAllocKind kind = kArenaAllocSTL)
+ : DebugStackReference(arena_allocator),
+ DebugStackIndirectTopRef(arena_allocator),
+ ArenaAllocatorAdapterKind(kind),
+ arena_stack_(arena_allocator->arena_stack_) {
+ }
+ template <typename U>
+ ScopedArenaAllocatorAdapter(const ScopedArenaAllocatorAdapter<U>& other)
+ : DebugStackReference(other),
+ DebugStackIndirectTopRef(other),
+ ArenaAllocatorAdapterKind(other),
+ arena_stack_(other.arena_stack_) {
+ }
+ ScopedArenaAllocatorAdapter(const ScopedArenaAllocatorAdapter& other) = default;
+ ScopedArenaAllocatorAdapter& operator=(const ScopedArenaAllocatorAdapter& other) = default;
+ ~ScopedArenaAllocatorAdapter() = default;
+
+ private:
+ ArenaStack* arena_stack_;
+
+ template <typename U>
+ friend class ScopedArenaAllocatorAdapter;
+};
+
+template <typename T>
+class ScopedArenaAllocatorAdapter
+ : private DebugStackReference, private DebugStackIndirectTopRef,
+ private ArenaAllocatorAdapterKind {
+ public:
+ typedef T value_type;
+ typedef T* pointer;
+ typedef T& reference;
+ typedef const T* const_pointer;
+ typedef const T& const_reference;
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+
+ template <typename U>
+ struct rebind {
+ typedef ScopedArenaAllocatorAdapter<U> other;
+ };
+
+ explicit ScopedArenaAllocatorAdapter(ScopedArenaAllocator* arena_allocator,
+ ArenaAllocKind kind = kArenaAllocSTL)
+ : DebugStackReference(arena_allocator),
+ DebugStackIndirectTopRef(arena_allocator),
+ ArenaAllocatorAdapterKind(kind),
+ arena_stack_(arena_allocator->arena_stack_) {
+ }
+ template <typename U>
+ ScopedArenaAllocatorAdapter(const ScopedArenaAllocatorAdapter<U>& other)
+ : DebugStackReference(other),
+ DebugStackIndirectTopRef(other),
+ ArenaAllocatorAdapterKind(other),
+ arena_stack_(other.arena_stack_) {
+ }
+ ScopedArenaAllocatorAdapter(const ScopedArenaAllocatorAdapter& other) = default;
+ ScopedArenaAllocatorAdapter& operator=(const ScopedArenaAllocatorAdapter& other) = default;
+ ~ScopedArenaAllocatorAdapter() = default;
+
+ size_type max_size() const {
+ return static_cast<size_type>(-1) / sizeof(T);
+ }
+
+ pointer address(reference x) const { return &x; }
+ const_pointer address(const_reference x) const { return &x; }
+
+ pointer allocate(size_type n, ScopedArenaAllocatorAdapter<void>::pointer hint = nullptr) {
+ UNUSED(hint);
+ DCHECK_LE(n, max_size());
+ DebugStackIndirectTopRef::CheckTop();
+ return reinterpret_cast<T*>(arena_stack_->Alloc(n * sizeof(T),
+ ArenaAllocatorAdapterKind::Kind()));
+ }
+ void deallocate(pointer p, size_type n) {
+ UNUSED(p);
+ UNUSED(n);
+ DebugStackIndirectTopRef::CheckTop();
+ }
+
+ void construct(pointer p, const_reference val) {
+ // Don't CheckTop(), allow reusing existing capacity of a vector/deque below the top.
+ new (static_cast<void*>(p)) value_type(val);
+ }
+ void destroy(pointer p) {
+ // Don't CheckTop(), allow reusing existing capacity of a vector/deque below the top.
+ p->~value_type();
+ }
+
+ private:
+ ArenaStack* arena_stack_;
+
+ template <typename U>
+ friend class ScopedArenaAllocatorAdapter;
+
+ template <typename U>
+ friend bool operator==(const ScopedArenaAllocatorAdapter<U>& lhs,
+ const ScopedArenaAllocatorAdapter<U>& rhs);
+};
+
+template <typename T>
+inline bool operator==(const ScopedArenaAllocatorAdapter<T>& lhs,
+ const ScopedArenaAllocatorAdapter<T>& rhs) {
+ return lhs.arena_stack_ == rhs.arena_stack_;
+}
+
+template <typename T>
+inline bool operator!=(const ScopedArenaAllocatorAdapter<T>& lhs,
+ const ScopedArenaAllocatorAdapter<T>& rhs) {
+ return !(lhs == rhs);
+}
+
+inline ScopedArenaAllocatorAdapter<void> ScopedArenaAllocator::Adapter(ArenaAllocKind kind) {
+ return ScopedArenaAllocatorAdapter<void>(this, kind);
+}
+
+} // namespace art
+
+#endif // ART_RUNTIME_BASE_SCOPED_ARENA_CONTAINERS_H_