183cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko/*
283cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko * Copyright (C) 2014 The Android Open Source Project
383cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko *
483cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko * Licensed under the Apache License, Version 2.0 (the "License");
583cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko * you may not use this file except in compliance with the License.
683cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko * You may obtain a copy of the License at
783cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko *
883cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko *      http://www.apache.org/licenses/LICENSE-2.0
983cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko *
1083cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko * Unless required by applicable law or agreed to in writing, software
1183cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko * distributed under the License is distributed on an "AS IS" BASIS,
1283cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1383cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko * See the License for the specific language governing permissions and
1483cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko * limitations under the License.
1583cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko */
1683cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko
1783cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko#ifndef ART_COMPILER_UTILS_SCOPED_ARENA_ALLOCATOR_H_
1883cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko#define ART_COMPILER_UTILS_SCOPED_ARENA_ALLOCATOR_H_
1983cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko
2083cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko#include "base/logging.h"
2183cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko#include "base/macros.h"
2283cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko#include "utils/arena_allocator.h"
2383cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko#include "utils/debug_stack.h"
2483cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko#include "globals.h"
2583cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko
2683cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Markonamespace art {
2783cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko
2883cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Markoclass ArenaStack;
2983cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Markoclass ScopedArenaAllocator;
3083cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko
3183cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Markotemplate <typename T>
3283cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Markoclass ScopedArenaAllocatorAdapter;
3383cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko
3483cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko// Holds a list of Arenas for use by ScopedArenaAllocator stack.
3583cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Markoclass ArenaStack : private DebugStackRefCounter {
3683cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko public:
3783cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  explicit ArenaStack(ArenaPool* arena_pool);
3883cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  ~ArenaStack();
3983cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko
4053b6afc93d91f9a48660682082dafcd81a652d6cVladimir Marko  void Reset();
4153b6afc93d91f9a48660682082dafcd81a652d6cVladimir Marko
4283cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  size_t PeakBytesAllocated() {
4383cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko    return PeakStats()->BytesAllocated();
4483cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  }
4583cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko
4683cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  MemStats GetPeakStats() const;
4783cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko
4883cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko private:
4983cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  struct Peak;
5083cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  struct Current;
5183cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  template <typename Tag> struct TaggedStats : ArenaAllocatorStats { };
5283cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  struct StatsAndPool : TaggedStats<Peak>, TaggedStats<Current> {
5383cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko    explicit StatsAndPool(ArenaPool* arena_pool) : pool(arena_pool) { }
5483cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko    ArenaPool* const pool;
5583cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  };
5683cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko
5783cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  ArenaAllocatorStats* PeakStats() {
5883cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko    return static_cast<TaggedStats<Peak>*>(&stats_and_pool_);
5983cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  }
6083cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko
6183cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  ArenaAllocatorStats* CurrentStats() {
6283cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko    return static_cast<TaggedStats<Current>*>(&stats_and_pool_);
6383cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  }
6483cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko
6583cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  // Private - access via ScopedArenaAllocator or ScopedArenaAllocatorAdapter.
6683cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  void* Alloc(size_t bytes, ArenaAllocKind kind) ALWAYS_INLINE {
6783cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko    if (UNLIKELY(running_on_valgrind_)) {
6883cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko      return AllocValgrind(bytes, kind);
6983cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko    }
7022a0ef8fbe78577ad4127e5becf20b3afa797478Vladimir Marko    size_t rounded_bytes = RoundUp(bytes, 8);
7183cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko    uint8_t* ptr = top_ptr_;
7283cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko    if (UNLIKELY(static_cast<size_t>(top_end_ - ptr) < rounded_bytes)) {
7383cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko      ptr = AllocateFromNextArena(rounded_bytes);
7483cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko    }
7583cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko    CurrentStats()->RecordAlloc(bytes, kind);
7683cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko    top_ptr_ = ptr + rounded_bytes;
7783cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko    return ptr;
7883cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  }
7983cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko
8083cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  uint8_t* AllocateFromNextArena(size_t rounded_bytes);
8183cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  void UpdatePeakStatsAndRestore(const ArenaAllocatorStats& restore_stats);
8283cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  void UpdateBytesAllocated();
8383cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  void* AllocValgrind(size_t bytes, ArenaAllocKind kind);
8483cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko
8583cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  StatsAndPool stats_and_pool_;
8683cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  Arena* bottom_arena_;
8783cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  Arena* top_arena_;
8883cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  uint8_t* top_ptr_;
8983cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  uint8_t* top_end_;
9083cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko
9183cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  const bool running_on_valgrind_;
9283cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko
9383cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  friend class ScopedArenaAllocator;
9483cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  template <typename T>
9583cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  friend class ScopedArenaAllocatorAdapter;
9683cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko
9783cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  DISALLOW_COPY_AND_ASSIGN(ArenaStack);
9883cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko};
9983cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko
10083cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Markoclass ScopedArenaAllocator
10183cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko    : private DebugStackReference, private DebugStackRefCounter, private ArenaAllocatorStats {
10283cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko public:
10383cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  // Create a ScopedArenaAllocator directly on the ArenaStack when the scope of
10483cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  // the allocator is not exactly a C++ block scope. For example, an optimization
10583cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  // pass can create the scoped allocator in Start() and destroy it in End().
10683cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  static ScopedArenaAllocator* Create(ArenaStack* arena_stack) {
10783cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko    void* addr = arena_stack->Alloc(sizeof(ScopedArenaAllocator), kArenaAllocMisc);
10883cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko    ScopedArenaAllocator* allocator = new(addr) ScopedArenaAllocator(arena_stack);
10983cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko    allocator->mark_ptr_ = reinterpret_cast<uint8_t*>(addr);
11083cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko    return allocator;
11183cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  }
11283cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko
11383cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  explicit ScopedArenaAllocator(ArenaStack* arena_stack);
11483cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  ~ScopedArenaAllocator();
11583cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko
11683cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  void Reset();
11783cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko
11883cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  void* Alloc(size_t bytes, ArenaAllocKind kind) ALWAYS_INLINE {
11983cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko    DebugStackReference::CheckTop();
12083cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko    return arena_stack_->Alloc(bytes, kind);
12183cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  }
12283cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko
1238081d2b8d7a743729557051d0294e040e61c747aVladimir Marko  // Get adapter for use in STL containers. See scoped_arena_containers.h .
1248081d2b8d7a743729557051d0294e040e61c747aVladimir Marko  ScopedArenaAllocatorAdapter<void> Adapter(ArenaAllocKind kind = kArenaAllocSTL);
12583cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko
12683cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  // Allow a delete-expression to destroy but not deallocate allocators created by Create().
12783cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  static void operator delete(void* ptr) { UNUSED(ptr); }
12883cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko
12983cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko private:
13083cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  ArenaStack* const arena_stack_;
13183cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  Arena* mark_arena_;
13283cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  uint8_t* mark_ptr_;
13383cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  uint8_t* mark_end_;
13483cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko
13583cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  template <typename T>
13683cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  friend class ScopedArenaAllocatorAdapter;
13783cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko
13883cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko  DISALLOW_COPY_AND_ASSIGN(ScopedArenaAllocator);
13983cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko};
14083cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko
14183cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko}  // namespace art
14283cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko
14383cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko#endif  // ART_COMPILER_UTILS_SCOPED_ARENA_ALLOCATOR_H_
144