diff options
Diffstat (limited to '3rdparty/asmjit/src/asmjit/core/zone.h')
-rw-r--r-- | 3rdparty/asmjit/src/asmjit/core/zone.h | 244 |
1 files changed, 103 insertions, 141 deletions
diff --git a/3rdparty/asmjit/src/asmjit/core/zone.h b/3rdparty/asmjit/src/asmjit/core/zone.h index 52e9f125461..b61a3d1292c 100644 --- a/3rdparty/asmjit/src/asmjit/core/zone.h +++ b/3rdparty/asmjit/src/asmjit/core/zone.h @@ -1,25 +1,7 @@ -// AsmJit - Machine code generation for C++ +// This file is part of AsmJit project <https://asmjit.com> // -// * Official AsmJit Home Page: https://asmjit.com -// * Official Github Repository: https://github.com/asmjit/asmjit -// -// Copyright (c) 2008-2020 The AsmJit Authors -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. +// See asmjit.h or LICENSE.md for license and copyright information +// SPDX-License-Identifier: Zlib #ifndef ASMJIT_CORE_ZONE_H_INCLUDED #define ASMJIT_CORE_ZONE_H_INCLUDED @@ -31,20 +13,14 @@ ASMJIT_BEGIN_NAMESPACE //! \addtogroup asmjit_zone //! \{ -// ============================================================================ -// [asmjit::Zone] -// ============================================================================ - //! Zone memory. //! -//! Zone is an incremental memory allocator that allocates memory by simply -//! incrementing a pointer. It allocates blocks of memory by using C's `malloc()`, -//! but divides these blocks into smaller segments requested by calling +//! Zone is an incremental memory allocator that allocates memory by simply incrementing a pointer. It allocates +//! blocks of memory by using C's `malloc()`, but divides these blocks into smaller segments requested by calling //! `Zone::alloc()` and friends. //! -//! Zone has no function to release the allocated memory. It has to be released -//! all at once by calling `reset()`. If you need a more friendly allocator that -//! also supports `release()`, consider using `Zone` with `ZoneAllocator`. +//! Zone has no function to release the allocated memory. It has to be released all at once by calling `reset()`. +//! If you need a more friendly allocator that also supports `release()`, consider using `Zone` with `ZoneAllocator`. class Zone { public: ASMJIT_NONCOPYABLE(Zone) @@ -103,28 +79,31 @@ public: //! Creates a new Zone. //! - //! The `blockSize` parameter describes the default size of the block. If the - //! `size` parameter passed to `alloc()` is greater than the default size - //! `Zone` will allocate and use a larger block, but it will not change the + //! The `blockSize` parameter describes the default size of the block. If the `size` parameter passed to `alloc()` + //! is greater than the default size `Zone` will allocate and use a larger block, but it will not change the //! default `blockSize`. //! - //! It's not required, but it's good practice to set `blockSize` to a - //! reasonable value that depends on the usage of `Zone`. Greater block sizes - //! are generally safer and perform better than unreasonably low block sizes. - ASMJIT_INLINE explicit Zone(size_t blockSize, size_t blockAlignment = 1) noexcept { + //! It's not required, but it's good practice to set `blockSize` to a reasonable value that depends on the usage + //! of `Zone`. Greater block sizes are generally safer and perform better than unreasonably low block sizes. + ASMJIT_INLINE_NODEBUG explicit Zone(size_t blockSize, size_t blockAlignment = 1) noexcept { _init(blockSize, blockAlignment, nullptr); } - ASMJIT_INLINE Zone(size_t blockSize, size_t blockAlignment, const Support::Temporary& temporary) noexcept { + //! Creates a new Zone with a first block pointing to a `temporary` memory. + ASMJIT_INLINE_NODEBUG Zone(size_t blockSize, size_t blockAlignment, const Support::Temporary& temporary) noexcept { _init(blockSize, blockAlignment, &temporary); } + //! \overload + ASMJIT_INLINE_NODEBUG Zone(size_t blockSize, size_t blockAlignment, const Support::Temporary* temporary) noexcept { + _init(blockSize, blockAlignment, temporary); + } + //! Moves an existing `Zone`. //! - //! \note You cannot move an existing `ZoneTmp` as it uses embedded storage. - //! Attempting to move `ZoneTmp` would result in assertion failure in debug - //! mode and undefined behavior in release mode. - ASMJIT_INLINE Zone(Zone&& other) noexcept + //! \note You cannot move an existing `ZoneTmp` as it uses embedded storage. Attempting to move `ZoneTmp` would + //! result in assertion failure in debug mode and undefined behavior in release mode. + inline Zone(Zone&& other) noexcept : _ptr(other._ptr), _end(other._end), _block(other._block), @@ -137,16 +116,16 @@ public: //! Destroys the `Zone` instance. //! - //! This will destroy the `Zone` instance and release all blocks of memory - //! allocated by it. It performs implicit `reset(Globals::kResetHard)`. - ASMJIT_INLINE ~Zone() noexcept { reset(Globals::kResetHard); } + //! This will destroy the `Zone` instance and release all blocks of memory allocated by it. It performs implicit + //! `reset(ResetPolicy::kHard)`. + ASMJIT_INLINE_NODEBUG ~Zone() noexcept { reset(ResetPolicy::kHard); } ASMJIT_API void _init(size_t blockSize, size_t blockAlignment, const Support::Temporary* temporary) noexcept; //! Resets the `Zone` invalidating all blocks allocated. //! //! See `Globals::ResetPolicy` for more details. - ASMJIT_API void reset(uint32_t resetPolicy = Globals::kResetSoft) noexcept; + ASMJIT_API void reset(ResetPolicy resetPolicy = ResetPolicy::kSoft) noexcept; //! \} @@ -154,29 +133,28 @@ public: //! \{ //! Tests whether this `Zone` is actually a `ZoneTmp` that uses temporary memory. - ASMJIT_INLINE bool isTemporary() const noexcept { return _isTemporary != 0; } + ASMJIT_INLINE_NODEBUG bool isTemporary() const noexcept { return _isTemporary != 0; } //! Returns the default block size. - ASMJIT_INLINE size_t blockSize() const noexcept { return _blockSize; } + ASMJIT_INLINE_NODEBUG size_t blockSize() const noexcept { return _blockSize; } //! Returns the default block alignment. - ASMJIT_INLINE size_t blockAlignment() const noexcept { return size_t(1) << _blockAlignmentShift; } + ASMJIT_INLINE_NODEBUG size_t blockAlignment() const noexcept { return size_t(1) << _blockAlignmentShift; } //! Returns remaining size of the current block. - ASMJIT_INLINE size_t remainingSize() const noexcept { return (size_t)(_end - _ptr); } + ASMJIT_INLINE_NODEBUG size_t remainingSize() const noexcept { return (size_t)(_end - _ptr); } //! Returns the current zone cursor (dangerous). //! - //! This is a function that can be used to get exclusive access to the current - //! block's memory buffer. + //! This is a function that can be used to get exclusive access to the current block's memory buffer. template<typename T = uint8_t> - ASMJIT_INLINE T* ptr() noexcept { return reinterpret_cast<T*>(_ptr); } + ASMJIT_INLINE_NODEBUG T* ptr() noexcept { return reinterpret_cast<T*>(_ptr); } //! Returns the end of the current zone block, only useful if you use `ptr()`. template<typename T = uint8_t> - ASMJIT_INLINE T* end() noexcept { return reinterpret_cast<T*>(_end); } + ASMJIT_INLINE_NODEBUG T* end() noexcept { return reinterpret_cast<T*>(_end); } //! Sets the current zone pointer to `ptr` (must be within the current block). template<typename T> - ASMJIT_INLINE void setPtr(T* ptr) noexcept { + inline void setPtr(T* ptr) noexcept { uint8_t* p = reinterpret_cast<uint8_t*>(ptr); ASMJIT_ASSERT(p >= _ptr && p <= _end); _ptr = p; @@ -184,7 +162,7 @@ public: //! Sets the end zone pointer to `end` (must be within the current block). template<typename T> - ASMJIT_INLINE void setEnd(T* end) noexcept { + inline void setEnd(T* end) noexcept { uint8_t* p = reinterpret_cast<uint8_t*>(end); ASMJIT_ASSERT(p >= _ptr && p <= _end); _end = p; @@ -195,7 +173,7 @@ public: //! \name Utilities //! \{ - ASMJIT_INLINE void swap(Zone& other) noexcept { + inline void swap(Zone& other) noexcept { // This could lead to a disaster. ASMJIT_ASSERT(!this->isTemporary()); ASMJIT_ASSERT(!other.isTemporary()); @@ -207,30 +185,29 @@ public: } //! Aligns the current pointer to `alignment`. - ASMJIT_INLINE void align(size_t alignment) noexcept { + ASMJIT_INLINE_NODEBUG void align(size_t alignment) noexcept { _ptr = Support::min(Support::alignUp(_ptr, alignment), _end); } //! Ensures the remaining size is at least equal or greater than `size`. //! - //! \note This function doesn't respect any alignment. If you need to ensure - //! there is enough room for an aligned allocation you need to call `align()` - //! before calling `ensure()`. - ASMJIT_INLINE Error ensure(size_t size) noexcept { + //! \note This function doesn't respect any alignment. If you need to ensure there is enough room for an aligned + //! allocation you need to call `align()` before calling `ensure()`. + ASMJIT_INLINE_NODEBUG Error ensure(size_t size) noexcept { if (size <= remainingSize()) return kErrorOk; else return _alloc(0, 1) ? kErrorOk : DebugUtils::errored(kErrorOutOfMemory); } - ASMJIT_INLINE void _assignBlock(Block* block) noexcept { + inline void _assignBlock(Block* block) noexcept { size_t alignment = blockAlignment(); _ptr = Support::alignUp(block->data(), alignment); _end = Support::alignDown(block->data() + block->size, alignment); _block = block; } - ASMJIT_INLINE void _assignZeroBlock() noexcept { + inline void _assignZeroBlock() noexcept { Block* block = const_cast<Block*>(&_zeroBlock); _ptr = block->data(); _end = block->data(); @@ -244,9 +221,8 @@ public: //! Allocates the requested memory specified by `size`. //! - //! Pointer returned is valid until the `Zone` instance is destroyed or reset - //! by calling `reset()`. If you plan to make an instance of C++ from the - //! given pointer use placement `new` and `delete` operators: + //! Pointer returned is valid until the `Zone` instance is destroyed or reset by calling `reset()`. If you plan to + //! make an instance of C++ from the given pointer use placement `new` and `delete` operators: //! //! ``` //! using namespace asmjit; @@ -274,7 +250,7 @@ public: //! // Reset or destroy `Zone`. //! zone.reset(); //! ``` - ASMJIT_INLINE void* alloc(size_t size) noexcept { + inline void* alloc(size_t size) noexcept { if (ASMJIT_UNLIKELY(size > remainingSize())) return _alloc(size, 1); @@ -284,7 +260,7 @@ public: } //! Allocates the requested memory specified by `size` and `alignment`. - ASMJIT_INLINE void* alloc(size_t size, size_t alignment) noexcept { + inline void* alloc(size_t size, size_t alignment) noexcept { ASMJIT_ASSERT(Support::isPowerOf2(alignment)); uint8_t* ptr = Support::alignUp(_ptr, alignment); @@ -298,7 +274,7 @@ public: //! Allocates the requested memory specified by `size` without doing any checks. //! //! Can only be called if `remainingSize()` returns size at least equal to `size`. - ASMJIT_INLINE void* allocNoCheck(size_t size) noexcept { + inline void* allocNoCheck(size_t size) noexcept { ASMJIT_ASSERT(remainingSize() >= size); uint8_t* ptr = _ptr; @@ -309,7 +285,7 @@ public: //! Allocates the requested memory specified by `size` and `alignment` without doing any checks. //! //! Performs the same operation as `Zone::allocNoCheck(size)` with `alignment` applied. - ASMJIT_INLINE void* allocNoCheck(size_t size, size_t alignment) noexcept { + inline void* allocNoCheck(size_t size, size_t alignment) noexcept { ASMJIT_ASSERT(Support::isPowerOf2(alignment)); uint8_t* ptr = Support::alignUp(_ptr, alignment); @@ -324,38 +300,38 @@ public: //! Like `alloc()`, but the return pointer is casted to `T*`. template<typename T> - ASMJIT_INLINE T* allocT(size_t size = sizeof(T), size_t alignment = alignof(T)) noexcept { + inline T* allocT(size_t size = sizeof(T), size_t alignment = alignof(T)) noexcept { return static_cast<T*>(alloc(size, alignment)); } //! Like `allocNoCheck()`, but the return pointer is casted to `T*`. template<typename T> - ASMJIT_INLINE T* allocNoCheckT(size_t size = sizeof(T), size_t alignment = alignof(T)) noexcept { + inline T* allocNoCheckT(size_t size = sizeof(T), size_t alignment = alignof(T)) noexcept { return static_cast<T*>(allocNoCheck(size, alignment)); } //! Like `allocZeroed()`, but the return pointer is casted to `T*`. template<typename T> - ASMJIT_INLINE T* allocZeroedT(size_t size = sizeof(T), size_t alignment = alignof(T)) noexcept { + inline T* allocZeroedT(size_t size = sizeof(T), size_t alignment = alignof(T)) noexcept { return static_cast<T*>(allocZeroed(size, alignment)); } //! Like `new(std::nothrow) T(...)`, but allocated by `Zone`. template<typename T> - ASMJIT_INLINE T* newT() noexcept { + inline T* newT() noexcept { void* p = alloc(sizeof(T), alignof(T)); if (ASMJIT_UNLIKELY(!p)) return nullptr; - return new(p) T(); + return new(Support::PlacementNew{p}) T(); } //! Like `new(std::nothrow) T(...)`, but allocated by `Zone`. template<typename T, typename... Args> - ASMJIT_INLINE T* newT(Args&&... args) noexcept { + inline T* newT(Args&&... args) noexcept { void* p = alloc(sizeof(T), alignof(T)); if (ASMJIT_UNLIKELY(!p)) return nullptr; - return new(p) T(std::forward<Args>(args)...); + return new(Support::PlacementNew{p}) T(std::forward<Args>(args)...); } //! \cond INTERNAL @@ -368,7 +344,7 @@ public: ASMJIT_API void* dup(const void* data, size_t size, bool nullTerminate = false) noexcept; //! Helper to duplicate data. - ASMJIT_INLINE void* dupAligned(const void* data, size_t size, size_t alignment, bool nullTerminate = false) noexcept { + inline void* dupAligned(const void* data, size_t size, size_t alignment, bool nullTerminate = false) noexcept { align(alignment); return dup(data, size, nullTerminate); } @@ -379,19 +355,14 @@ public: //! \} }; -// ============================================================================ -// [b2d::ZoneTmp] -// ============================================================================ - //! \ref Zone with `N` bytes of a static storage, used for the initial block. //! -//! Temporary zones are used in cases where it's known that some memory will be -//! required, but in many cases it won't exceed N bytes, so the whole operation -//! can be performed without a dynamic memory allocation. +//! Temporary zones are used in cases where it's known that some memory will be required, but in many cases it won't +//! exceed N bytes, so the whole operation can be performed without a dynamic memory allocation. template<size_t N> class ZoneTmp : public Zone { public: - ASMJIT_NONCOPYABLE(ZoneTmp<N>) + ASMJIT_NONCOPYABLE(ZoneTmp) //! Temporary storage, embedded after \ref Zone. struct Storage { @@ -399,35 +370,29 @@ public: } _storage; //! Creates a temporary zone. Dynamic block size is specified by `blockSize`. - ASMJIT_INLINE explicit ZoneTmp(size_t blockSize, size_t blockAlignment = 1) noexcept + inline explicit ZoneTmp(size_t blockSize, size_t blockAlignment = 1) noexcept : Zone(blockSize, blockAlignment, Support::Temporary(_storage.data, N)) {} }; -// ============================================================================ -// [asmjit::ZoneAllocator] -// ============================================================================ - -//! Zone-based memory allocator that uses an existing `Zone` and provides a -//! `release()` functionality on top of it. It uses `Zone` only for chunks -//! that can be pooled, and uses libc `malloc()` for chunks that are large. +//! Zone-based memory allocator that uses an existing `Zone` and provides a `release()` functionality on top of it. +//! It uses `Zone` only for chunks that can be pooled, and uses libc `malloc()` for chunks that are large. //! -//! The advantage of ZoneAllocator is that it can allocate small chunks of memory -//! really fast, and these chunks, when released, will be reused by consecutive -//! calls to `alloc()`. Also, since ZoneAllocator uses `Zone`, you can turn any -//! `Zone` into a `ZoneAllocator`, and use it in your `Pass` when necessary. +//! The advantage of ZoneAllocator is that it can allocate small chunks of memory really fast, and these chunks, +//! when released, will be reused by consecutive calls to `alloc()`. Also, since ZoneAllocator uses `Zone`, you can +//! turn any `Zone` into a `ZoneAllocator`, and use it in your `Pass` when necessary. //! -//! ZoneAllocator is used by AsmJit containers to make containers having only -//! few elements fast (and lightweight) and to allow them to grow and use -//! dynamic blocks when require more storage. +//! ZoneAllocator is used by AsmJit containers to make containers having only few elements fast (and lightweight) +//! and to allow them to grow and use dynamic blocks when require more storage. class ZoneAllocator { public: ASMJIT_NONCOPYABLE(ZoneAllocator) //! \cond INTERNAL - enum { - // In short, we pool chunks of these sizes: - // [32, 64, 96, 128, 192, 256, 320, 384, 448, 512] + // In short, we pool chunks of these sizes: + // [32, 64, 96, 128, 192, 256, 320, 384, 448, 512] + + enum : uint32_t { //! How many bytes per a low granularity pool (has to be at least 16). kLoGranularity = 32, //! Number of slots of a low granularity pool. @@ -452,9 +417,8 @@ public: Slot* next; }; - //! A block of memory that has been allocated dynamically and is not part of - //! block-list used by the allocator. This is used to keep track of all these - //! blocks so they can be freed by `reset()` if not freed explicitly. + //! A block of memory that has been allocated dynamically and is not part of block-list used by the allocator. + //! This is used to keep track of all these blocks so they can be freed by `reset()` if not freed explicitly. struct DynamicBlock { DynamicBlock* prev; DynamicBlock* next; @@ -462,12 +426,17 @@ public: //! \endcond + //! \name Members + //! \{ + //! Zone used to allocate memory that fits into slots. - Zone* _zone; + Zone* _zone {}; //! Indexed slots containing released memory. - Slot* _slots[kLoCount + kHiCount]; + Slot* _slots[kLoCount + kHiCount] {}; //! Dynamic blocks for larger allocations (no slots). - DynamicBlock* _dynamicBlocks; + DynamicBlock* _dynamicBlocks {}; + + //! \} //! \name Construction & Destruction //! \{ @@ -475,30 +444,26 @@ public: //! Creates a new `ZoneAllocator`. //! //! \note To use it, you must first `init()` it. - inline ZoneAllocator() noexcept { - memset(this, 0, sizeof(*this)); - } + ASMJIT_INLINE_NODEBUG ZoneAllocator() noexcept {} //! Creates a new `ZoneAllocator` initialized to use `zone`. - inline explicit ZoneAllocator(Zone* zone) noexcept { - memset(this, 0, sizeof(*this)); - _zone = zone; - } + ASMJIT_INLINE_NODEBUG explicit ZoneAllocator(Zone* zone) noexcept + : _zone(zone) {} //! Destroys the `ZoneAllocator`. - inline ~ZoneAllocator() noexcept { reset(); } + ASMJIT_INLINE_NODEBUG ~ZoneAllocator() noexcept { reset(); } //! Tests whether the `ZoneAllocator` is initialized (i.e. has `Zone`). - inline bool isInitialized() const noexcept { return _zone != nullptr; } + ASMJIT_INLINE_NODEBUG bool isInitialized() const noexcept { return _zone != nullptr; } //! Convenience function to initialize the `ZoneAllocator` with `zone`. //! //! It's the same as calling `reset(zone)`. - inline void init(Zone* zone) noexcept { reset(zone); } + ASMJIT_INLINE_NODEBUG void init(Zone* zone) noexcept { reset(zone); } - //! Resets this `ZoneAllocator` and also forget about the current `Zone` which - //! is attached (if any). Reset optionally attaches a new `zone` passed, or - //! keeps the `ZoneAllocator` in an uninitialized state, if `zone` is null. + //! Resets this `ZoneAllocator` and also forget about the current `Zone` which is attached (if any). Reset + //! optionally attaches a new `zone` passed, or keeps the `ZoneAllocator` in an uninitialized state, if + //! `zone` is null. ASMJIT_API void reset(Zone* zone = nullptr) noexcept; //! \} @@ -506,9 +471,8 @@ public: //! \name Accessors //! \{ - //! Returns the assigned `Zone` of this allocator or null if this `ZoneAllocator` - //! is not initialized. - inline Zone* zone() const noexcept { return _zone; } + //! Returns the assigned `Zone` of this allocator or null if this `ZoneAllocator` is not initialized. + ASMJIT_INLINE_NODEBUG Zone* zone() const noexcept { return _zone; } //! \} @@ -516,10 +480,10 @@ public: //! \name Internals //! \{ - //! Returns the slot index to be used for `size`. Returns `true` if a valid slot - //! has been written to `slot` and `allocatedSize` has been filled with slot - //! exact size (`allocatedSize` can be equal or slightly greater than `size`). - static ASMJIT_INLINE bool _getSlotIndex(size_t size, uint32_t& slot) noexcept { + //! Returns the slot index to be used for `size`. Returns `true` if a valid slot has been written to `slot` and + //! `allocatedSize` has been filled with slot exact size (`allocatedSize` can be equal or slightly greater than + //! `size`). + static inline bool _getSlotIndex(size_t size, uint32_t& slot) noexcept { ASMJIT_ASSERT(size > 0); if (size > kHiMaxSize) return false; @@ -533,7 +497,7 @@ public: } //! \overload - static ASMJIT_INLINE bool _getSlotIndex(size_t size, uint32_t& slot, size_t& allocatedSize) noexcept { + static inline bool _getSlotIndex(size_t size, uint32_t& slot, size_t& allocatedSize) noexcept { ASMJIT_ASSERT(size > 0); if (size > kHiMaxSize) return false; @@ -571,9 +535,8 @@ public: return _alloc(size, allocatedSize); } - //! Like `alloc(size)`, but provides a second argument `allocatedSize` that - //! provides a way to know how big the block returned actually is. This is - //! useful for containers to prevent growing too early. + //! Like `alloc(size)`, but provides a second argument `allocatedSize` that provides a way to know how big + //! the block returned actually is. This is useful for containers to prevent growing too early. inline void* alloc(size_t size, size_t& allocatedSize) noexcept { ASMJIT_ASSERT(isInitialized()); return _alloc(size, allocatedSize); @@ -610,7 +573,7 @@ public: void* p = allocT<T>(); if (ASMJIT_UNLIKELY(!p)) return nullptr; - return new(p) T(); + return new(Support::PlacementNew{p}) T(); } //! Like `new(std::nothrow) T(...)`, but allocated by `Zone`. template<typename T, typename... Args> @@ -618,12 +581,11 @@ public: void* p = allocT<T>(); if (ASMJIT_UNLIKELY(!p)) return nullptr; - return new(p) T(std::forward<Args>(args)...); + return new(Support::PlacementNew{p}) T(std::forward<Args>(args)...); } - //! Releases the memory previously allocated by `alloc()`. The `size` argument - //! has to be the same as used to call `alloc()` or `allocatedSize` returned - //! by `alloc()`. + //! Releases the memory previously allocated by `alloc()`. The `size` argument has to be the same as used to call + //! `alloc()` or `allocatedSize` returned by `alloc()`. inline void release(void* p, size_t size) noexcept { ASMJIT_ASSERT(isInitialized()); ASMJIT_ASSERT(p != nullptr); |