| // Copyright 2014 the V8 project authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef V8_ZONE_ZONE_ALLOCATOR_H_ | |
| #define V8_ZONE_ZONE_ALLOCATOR_H_ | |
| #include <limits> | |
| #include "src/zone/zone.h" | |
| namespace v8 { | |
| namespace internal { | |
| template <typename T> | |
| class ZoneAllocator { | |
| public: | |
| typedef T* pointer; | |
| typedef const T* const_pointer; | |
| typedef T& reference; | |
| typedef const T& const_reference; | |
| typedef T value_type; | |
| typedef size_t size_type; | |
| typedef ptrdiff_t difference_type; | |
| template <class O> | |
| struct rebind { | |
| typedef ZoneAllocator<O> other; | |
| }; | |
| #ifdef V8_CC_MSVC | |
| // MSVS unfortunately requires the default constructor to be defined. | |
| ZoneAllocator() : ZoneAllocator(nullptr) { UNREACHABLE(); } | |
| #endif | |
| explicit ZoneAllocator(Zone* zone) throw() : zone_(zone) {} | |
| explicit ZoneAllocator(const ZoneAllocator& other) throw() | |
| : ZoneAllocator<T>(other.zone_) {} | |
| template <typename U> | |
| ZoneAllocator(const ZoneAllocator<U>& other) throw() | |
| : ZoneAllocator<T>(other.zone_) {} | |
| template <typename U> | |
| friend class ZoneAllocator; | |
| T* address(T& x) const { return &x; } | |
| const T* address(const T& x) const { return &x; } | |
| T* allocate(size_t n, const void* hint = 0) { | |
| return static_cast<T*>(zone_->NewArray<T>(static_cast<int>(n))); | |
| } | |
| void deallocate(T* p, size_t) { /* noop for Zones */ | |
| } | |
| size_t max_size() const throw() { | |
| return std::numeric_limits<int>::max() / sizeof(T); | |
| } | |
| template <typename U, typename... Args> | |
| void construct(U* p, Args&&... args) { | |
| void* v_p = const_cast<void*>(static_cast<const void*>(p)); | |
| new (v_p) U(std::forward<Args>(args)...); | |
| } | |
| template <typename U> | |
| void destroy(U* p) { | |
| p->~U(); | |
| } | |
| bool operator==(ZoneAllocator const& other) const { | |
| return zone_ == other.zone_; | |
| } | |
| bool operator!=(ZoneAllocator const& other) const { | |
| return zone_ != other.zone_; | |
| } | |
| Zone* zone() { return zone_; } | |
| private: | |
| Zone* zone_; | |
| }; | |
| // A recycling zone allocator maintains a free list of deallocated chunks | |
| // to reuse on subsiquent allocations. The free list management is purposely | |
| // very simple and works best for data-structures which regularly allocate and | |
| // free blocks of similar sized memory (such as std::deque). | |
| template <typename T> | |
| class RecyclingZoneAllocator : public ZoneAllocator<T> { | |
| public: | |
| template <class O> | |
| struct rebind { | |
| typedef RecyclingZoneAllocator<O> other; | |
| }; | |
| #ifdef V8_CC_MSVC | |
| // MSVS unfortunately requires the default constructor to be defined. | |
| RecyclingZoneAllocator() | |
| : ZoneAllocator(nullptr, nullptr), free_list_(nullptr) { | |
| UNREACHABLE(); | |
| } | |
| #endif | |
| explicit RecyclingZoneAllocator(Zone* zone) throw() | |
| : ZoneAllocator<T>(zone), free_list_(nullptr) {} | |
| explicit RecyclingZoneAllocator(const RecyclingZoneAllocator& other) throw() | |
| : ZoneAllocator<T>(other), free_list_(nullptr) {} | |
| template <typename U> | |
| RecyclingZoneAllocator(const RecyclingZoneAllocator<U>& other) throw() | |
| : ZoneAllocator<T>(other), free_list_(nullptr) {} | |
| template <typename U> | |
| friend class RecyclingZoneAllocator; | |
| T* allocate(size_t n, const void* hint = 0) { | |
| // Only check top block in free list, since this will be equal to or larger | |
| // than the other blocks in the free list. | |
| if (free_list_ && free_list_->size >= n) { | |
| T* return_val = reinterpret_cast<T*>(free_list_); | |
| free_list_ = free_list_->next; | |
| return return_val; | |
| } else { | |
| return ZoneAllocator<T>::allocate(n, hint); | |
| } | |
| } | |
| void deallocate(T* p, size_t n) { | |
| if ((sizeof(T) * n < sizeof(FreeBlock))) return; | |
| // Only add block to free_list if it is equal or larger than previous block | |
| // so that allocation stays O(1) only having to look at the top block. | |
| if (!free_list_ || free_list_->size <= n) { | |
| // Store the free-list within the block being deallocated. | |
| DCHECK((sizeof(T) * n >= sizeof(FreeBlock))); | |
| FreeBlock* new_free_block = reinterpret_cast<FreeBlock*>(p); | |
| new_free_block->size = n; | |
| new_free_block->next = free_list_; | |
| free_list_ = new_free_block; | |
| } | |
| } | |
| private: | |
| struct FreeBlock { | |
| FreeBlock* next; | |
| size_t size; | |
| }; | |
| FreeBlock* free_list_; | |
| }; | |
| typedef ZoneAllocator<bool> ZoneBoolAllocator; | |
| typedef ZoneAllocator<int> ZoneIntAllocator; | |
| } // namespace internal | |
| } // namespace v8 | |
| #endif // V8_ZONE_ZONE_ALLOCATOR_H_ |