C++程序  |  186行  |  5.3 KB

//===- subzero/src/IceMemory.h - Memory management declarations -*- C++ -*-===//
//
//                        The Subzero Code Generator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief Declares some useful data structures and routines dealing with
/// memory management in Subzero (mostly, allocator types.)
///
//===----------------------------------------------------------------------===//

#ifndef SUBZERO_SRC_ICEMEMORY_H
#define SUBZERO_SRC_ICEMEMORY_H

#include "IceTLS.h"

#include "llvm/Support/Allocator.h"

#include <cstddef>
#include <mutex>

namespace Ice {

class Cfg;
class GlobalContext;
class Liveness;

using ArenaAllocator =
    llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, /*SlabSize=*/1024 * 1024>;

class LockedArenaAllocator {
  LockedArenaAllocator() = delete;
  LockedArenaAllocator(const LockedArenaAllocator &) = delete;
  LockedArenaAllocator &operator=(const LockedArenaAllocator &) = delete;

public:
  LockedArenaAllocator(ArenaAllocator *Alloc, std::mutex *Mutex)
      : Alloc(Alloc), AutoLock(*Mutex) {}
  LockedArenaAllocator(LockedArenaAllocator &&) = default;
  LockedArenaAllocator &operator=(LockedArenaAllocator &&) = default;
  ~LockedArenaAllocator() = default;

  ArenaAllocator *operator->() { return Alloc; }

private:
  ArenaAllocator *Alloc;
  std::unique_lock<std::mutex> AutoLock;
};

template <typename T, typename Traits> struct sz_allocator {
  /// std::allocator interface implementation.
  /// @{
  using value_type = T;
  using pointer = T *;
  using const_pointer = const T *;
  using reference = T &;
  using const_reference = const T &;
  using size_type = std::size_t;
  using difference_type = std::ptrdiff_t;

  sz_allocator() : Current() {}
  template <class U>
  sz_allocator(const sz_allocator<U, Traits> &)
      : Current() {}

  pointer address(reference x) const {
    return reinterpret_cast<pointer>(&reinterpret_cast<char &>(x));
  }
  const_pointer address(const_reference x) const {
    return reinterpret_cast<const_pointer>(&reinterpret_cast<const char &>(x));
  }

  pointer allocate(size_type num) {
    assert(current() != nullptr);
    return current()->template Allocate<T>(num);
  }

  template <typename... A> void construct(pointer P, A &&... Args) {
    new (static_cast<void *>(P)) T(std::forward<A>(Args)...);
  }

  void deallocate(pointer, size_type) {}

  template <class U> struct rebind { typedef sz_allocator<U, Traits> other; };

  void destroy(pointer P) { P->~T(); }
  /// @}

  /// Manages the current underlying allocator.
  /// @{
  typename Traits::allocator_type current() {
    if (!Traits::cache_allocator) {
      // TODO(jpp): allocators should always be cacheable... maybe. Investigate.
      return Traits::current();
    }
    if (Current == nullptr) {
      Current = Traits::current();
    }
    assert(Current == Traits::current());
    return Current;
  }
  static void init() { Traits::init(); }
  /// @}
  typename Traits::allocator_type Current;
};

template <class Traits> struct sz_allocator_scope {
  explicit sz_allocator_scope(typename Traits::manager_type *Manager) {
    Traits::set_current(Manager);
  }

  ~sz_allocator_scope() { Traits::set_current(nullptr); }
};

template <typename T, typename U, typename Traits>
inline bool operator==(const sz_allocator<T, Traits> &,
                       const sz_allocator<U, Traits> &) {
  return true;
}

template <typename T, typename U, typename Traits>
inline bool operator!=(const sz_allocator<T, Traits> &,
                       const sz_allocator<U, Traits> &) {
  return false;
}

class CfgAllocatorTraits {
  CfgAllocatorTraits() = delete;
  CfgAllocatorTraits(const CfgAllocatorTraits &) = delete;
  CfgAllocatorTraits &operator=(const CfgAllocatorTraits &) = delete;
  ~CfgAllocatorTraits() = delete;

public:
  using allocator_type = ArenaAllocator *;
  using manager_type = Cfg;
  static constexpr bool cache_allocator = false;

  static void init() { ICE_TLS_INIT_FIELD(CfgAllocator); };

  static allocator_type current();
  static void set_current(const manager_type *Manager);
  static void set_current(ArenaAllocator *Allocator);
  static void set_current(std::nullptr_t);

private:
  ICE_TLS_DECLARE_FIELD(ArenaAllocator *, CfgAllocator);
};

template <typename T>
using CfgLocalAllocator = sz_allocator<T, CfgAllocatorTraits>;

using CfgLocalAllocatorScope = sz_allocator_scope<CfgAllocatorTraits>;

class LivenessAllocatorTraits {
  LivenessAllocatorTraits() = delete;
  LivenessAllocatorTraits(const LivenessAllocatorTraits &) = delete;
  LivenessAllocatorTraits &operator=(const LivenessAllocatorTraits &) = delete;
  ~LivenessAllocatorTraits() = delete;

public:
  using allocator_type = ArenaAllocator *;
  using manager_type = Liveness;
  static constexpr bool cache_allocator = true;

  static void init() { ICE_TLS_INIT_FIELD(LivenessAllocator); };

  static allocator_type current();
  static void set_current(const manager_type *Manager);

private:
  ICE_TLS_DECLARE_FIELD(ArenaAllocator *, LivenessAllocator);
};

template <typename T>
using LivenessAllocator = sz_allocator<T, LivenessAllocatorTraits>;

using LivenessAllocatorScope = sz_allocator_scope<LivenessAllocatorTraits>;

} // end of namespace Ice

#endif // SUBZERO_SRC_ICEMEMORY_H