// [AsmJit] // Complete x86/x64 JIT and Remote Assembler for C++. // // [License] // Zlib - See LICENSE.md file in the package. // [Guard] #ifndef _ASMJIT_BASE_ZONE_H #define _ASMJIT_BASE_ZONE_H // [Dependencies] #include "../base/globals.h" // [Api-Begin] #include "../apibegin.h" namespace asmjit { //! \addtogroup asmjit_base //! \{ // ============================================================================ // [asmjit::Zone] // ============================================================================ //! Zone memory allocator. //! //! Zone is an incremental memory allocator that allocates memory by simply //! incrementing a pointer. It allocates blocks of memory by using standard //! C library `malloc/free`, but divides these blocks into smaller segments //! requirested by calling `Zone::alloc()` and friends. //! //! Zone memory allocators are designed to allocate data of short lifetime. The //! data used by `Assembler` and `Compiler` has a very short lifetime, thus, is //! allocated by `Zone`. The advantage is that `Zone` can free all of the data //! allocated at once by calling `reset()` or by `Zone` destructor. class Zone { public: //! \internal //! //! A single block of memory. struct Block { // ------------------------------------------------------------------------ // [Accessors] // ------------------------------------------------------------------------ //! Get the size of the block. ASMJIT_INLINE size_t getBlockSize() const noexcept { return (size_t)(end - data); } //! Get count of remaining bytes in the block. ASMJIT_INLINE size_t getRemainingSize() const noexcept { return (size_t)(end - pos); } // ------------------------------------------------------------------------ // [Members] // ------------------------------------------------------------------------ //! Current data pointer (pointer to the first available byte). uint8_t* pos; //! End data pointer (pointer to the first invalid byte). uint8_t* end; //! Link to the previous block. Block* prev; //! Link to the next block. Block* next; //! Data. uint8_t data[sizeof(void*)]; }; enum { //! Zone allocator overhead. kZoneOverhead = kMemAllocOverhead + static_cast(sizeof(Block) - sizeof(void*)) }; // -------------------------------------------------------------------------- // [Construction / Destruction] // -------------------------------------------------------------------------- //! Create a new instance of `Zone` allocator. //! //! 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 performs better than unreasonably low values. ASMJIT_API Zone(size_t blockSize) noexcept; //! Destroy the `Zone` instance. //! //! This will destroy the `Zone` instance and release all blocks of memory //! allocated by it. It performs implicit `reset(true)`. ASMJIT_API ~Zone() noexcept; // -------------------------------------------------------------------------- // [Reset] // -------------------------------------------------------------------------- //! Reset the `Zone` invalidating all blocks allocated. //! //! If `releaseMemory` is true all buffers will be released to the system. ASMJIT_API void reset(bool releaseMemory = false) noexcept; // -------------------------------------------------------------------------- // [Accessors] // -------------------------------------------------------------------------- //! Get the default block size. ASMJIT_INLINE size_t getBlockSize() const noexcept { return _blockSize; } // -------------------------------------------------------------------------- // [Alloc] // -------------------------------------------------------------------------- //! Allocate `size` bytes of memory. //! //! 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; //! //! class Object { ... }; //! //! // Create Zone with default block size of approximately 65536 bytes. //! Zone zone(65536 - Zone::kZoneOverhead); //! //! // Create your objects using zone object allocating, for example: //! Object* obj = static_cast( zone.alloc(sizeof(Object)) ); // //! if (obj == nullptr) { //! // Handle out of memory error. //! } //! //! // Placement `new` and `delete` operators can be used to instantiate it. //! new(obj) Object(); //! //! // ... lifetime of your objects ... //! //! // To destroy the instance (if required). //! obj->~Object(); //! //! // Reset or destroy `Zone`. //! zone.reset(); //! ~~~ ASMJIT_INLINE void* alloc(size_t size) noexcept { Block* cur = _block; uint8_t* ptr = cur->pos; size_t remainingBytes = (size_t)(cur->end - ptr); if (remainingBytes < size) return _alloc(size); cur->pos += size; ASMJIT_ASSERT(cur->pos <= cur->end); return (void*)ptr; } //! Allocate `size` bytes of zeroed memory. //! //! See \ref alloc() for more details. ASMJIT_API void* allocZeroed(size_t size) noexcept; //! Like `alloc()`, but the return pointer is casted to `T*`. template ASMJIT_INLINE T* allocT(size_t size = sizeof(T)) noexcept { return static_cast(alloc(size)); } //! Like `allocZeroed()`, but the return pointer is casted to `T*`. template ASMJIT_INLINE T* allocZeroedT(size_t size = sizeof(T)) noexcept { return static_cast(allocZeroed(size)); } //! \internal ASMJIT_API void* _alloc(size_t size) noexcept; //! Helper to duplicate data. ASMJIT_API void* dup(const void* data, size_t size) noexcept; //! Helper to duplicate string. ASMJIT_API char* sdup(const char* str) noexcept; //! Helper to duplicate formatted string, maximum length is 256 bytes. ASMJIT_API char* sformat(const char* str, ...) noexcept; // -------------------------------------------------------------------------- // [Members] // -------------------------------------------------------------------------- //! The current block. Block* _block; //! Default block size. size_t _blockSize; }; //! \} } // asmjit namespace // [Api-End] #include "../apiend.h" // [Guard] #endif // _ASMJIT_BASE_ZONE_H