221 lines
6.7 KiB
C++
221 lines
6.7 KiB
C++
// [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<int>(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<Object*>( 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<typename T>
|
|
ASMJIT_INLINE T* allocT(size_t size = sizeof(T)) noexcept {
|
|
return static_cast<T*>(alloc(size));
|
|
}
|
|
|
|
//! Like `allocZeroed()`, but the return pointer is casted to `T*`.
|
|
template<typename T>
|
|
ASMJIT_INLINE T* allocZeroedT(size_t size = sizeof(T)) noexcept {
|
|
return static_cast<T*>(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
|