// 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 #include "src/zone/zone.h" namespace v8 { namespace internal { template class ZoneAllocator { public: using pointer = T*; using const_pointer = const T*; using reference = T&; using const_reference = const T&; using value_type = T; using size_type = size_t; using difference_type = ptrdiff_t; template struct rebind { using other = ZoneAllocator; }; #ifdef V8_OS_WIN // The exported class ParallelMove derives from ZoneVector, which derives // from std::vector. On Windows, the semantics of dllexport mean that // a class's superclasses that are not explicitly exported themselves get // implicitly exported together with the subclass, and exporting a class // exports all its functions -- including the std::vector() constructors // that don't take an explicit allocator argument, which in turn reference // the vector allocator's default constructor. So this constructor needs // to exist for linking purposes, even if it's never called. // Other fixes would be to disallow subclasses of ZoneVector (etc) to be // exported, or using composition instead of inheritance for either // ZoneVector and friends or for ParallelMove. ZoneAllocator() : ZoneAllocator(nullptr) { UNREACHABLE(); } #endif explicit ZoneAllocator(Zone* zone) : zone_(zone) {} template ZoneAllocator(const ZoneAllocator& other) V8_NOEXCEPT : ZoneAllocator(other.zone_) {} template friend class ZoneAllocator; T* allocate(size_t n) { return zone_->NewArray(n); } void deallocate(T* p, size_t) {} // noop for zones size_t max_size() const { return std::numeric_limits::max() / sizeof(T); } template void construct(U* p, Args&&... args) { void* v_p = const_cast(static_cast(p)); new (v_p) U(std::forward(args)...); } template 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 class RecyclingZoneAllocator : public ZoneAllocator { public: template struct rebind { using other = RecyclingZoneAllocator; }; explicit RecyclingZoneAllocator(Zone* zone) : ZoneAllocator(zone), free_list_(nullptr) {} template RecyclingZoneAllocator(const RecyclingZoneAllocator& other) V8_NOEXCEPT : ZoneAllocator(other), free_list_(nullptr) {} template friend class RecyclingZoneAllocator; T* allocate(size_t n) { // 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(free_list_); free_list_ = free_list_->next; return return_val; } return ZoneAllocator::allocate(n); } 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(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_; }; using ZoneBoolAllocator = ZoneAllocator; using ZoneIntAllocator = ZoneAllocator; } // namespace internal } // namespace v8 #endif // V8_ZONE_ZONE_ALLOCATOR_H_