mirror of
https://github.com/asmjit/asmjit.git
synced 2025-12-18 13:04:36 +03:00
Reworked Zone memory allocator a bit.
This commit is contained in:
@@ -29,7 +29,7 @@ CodeGen::CodeGen(Runtime* runtime) :
|
|||||||
_features(static_cast<uint8_t>(IntUtil::mask(kCodeGenOptimizedAlign))),
|
_features(static_cast<uint8_t>(IntUtil::mask(kCodeGenOptimizedAlign))),
|
||||||
_error(kErrorOk),
|
_error(kErrorOk),
|
||||||
_options(0),
|
_options(0),
|
||||||
_baseZone(16384 - sizeof(Zone::Chunk) - kMemAllocOverhead) {}
|
_baseZone(16384 - kZoneOverhead) {}
|
||||||
|
|
||||||
CodeGen::~CodeGen() {
|
CodeGen::~CodeGen() {
|
||||||
if (_errorHandler != NULL)
|
if (_errorHandler != NULL)
|
||||||
|
|||||||
@@ -44,9 +44,9 @@ BaseCompiler::BaseCompiler(Runtime* runtime) :
|
|||||||
_lastNode(NULL),
|
_lastNode(NULL),
|
||||||
_cursor(NULL),
|
_cursor(NULL),
|
||||||
_func(NULL),
|
_func(NULL),
|
||||||
_varZone(4096 - kMemAllocOverhead),
|
_varZone(4096 - kZoneOverhead),
|
||||||
_stringZone(4096 - kMemAllocOverhead),
|
_stringZone(4096 - kZoneOverhead),
|
||||||
_localConstZone(4096 - kMemAllocOverhead),
|
_localConstZone(4096 - kZoneOverhead),
|
||||||
_localConstPool(&_localConstZone),
|
_localConstPool(&_localConstZone),
|
||||||
_globalConstPool(&_baseZone) {}
|
_globalConstPool(&_baseZone) {}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace asmjit {
|
|||||||
|
|
||||||
BaseContext::BaseContext(BaseCompiler* compiler) :
|
BaseContext::BaseContext(BaseCompiler* compiler) :
|
||||||
_compiler(compiler),
|
_compiler(compiler),
|
||||||
_baseZone(8192 - sizeof(Zone::Chunk) - kMemAllocOverhead) {
|
_baseZone(8192 - kZoneOverhead) {
|
||||||
|
|
||||||
BaseContext::reset();
|
BaseContext::reset();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,32 +29,39 @@
|
|||||||
// efficient. There are several goals I decided to write implementation myself.
|
// efficient. There are several goals I decided to write implementation myself.
|
||||||
//
|
//
|
||||||
// Goals:
|
// Goals:
|
||||||
// - We need usually to allocate blocks of 64 bytes long and more.
|
|
||||||
// - Alignment of allocated blocks is large - 32 bytes or 64 bytes.
|
|
||||||
// - Keep memory manager information outside allocated virtual memory pages
|
|
||||||
// (these pages allows execution of code).
|
|
||||||
// - Keep implementation small.
|
|
||||||
//
|
//
|
||||||
// I think that implementation is not small and probably not too much readable,
|
// - Granularity of allocated blocks is different than granularity for a typical
|
||||||
// so there is small know how.
|
// C malloc. It is at least 64-bytes so Assembler/Compiler can guarantee the
|
||||||
|
// alignment required. Alignment requirements can grow in the future, but at
|
||||||
|
// the moment 64 bytes is safe (we may jump to 128 bytes if necessary or make
|
||||||
|
// it configurable).
|
||||||
//
|
//
|
||||||
// - Implementation is based on bit arrays and binary trees. Bit arrays
|
// - Keep memory manager information outside of the allocated virtual memory
|
||||||
// contains information about allocated and unused blocks of memory. Each
|
// pages, because these pages allow executing of machine code and there should
|
||||||
// block size describes MemNode::density member. Count of blocks are
|
// not be data required to keep track of these blocks. Another reason is that
|
||||||
// stored in MemNode::blocks member. For example if density is 64 and
|
// some environments (i.e. iOS) allow to generate and run JIT code, but this
|
||||||
// count of blocks is 20, memory node contains 64*20 bytes of memory and
|
// code has to be set to [Executable, but not Writable].
|
||||||
// smallest possible allocation (and also alignment) is 64 bytes. So density
|
//
|
||||||
// describes also memory alignment. Binary trees are used to enable fast
|
// - Keep implementation simple and easy to follow.
|
||||||
// lookup into all addresses allocated by memory manager instance. This is
|
//
|
||||||
// used mainly in VMemPrivate::release().
|
// Implementation is based on bit arrays and binary trees. Bit arrays contain
|
||||||
|
// information related to allocated and unused blocks of memory. The size of
|
||||||
|
// a block is described by `MemNode::density`. Count of blocks is stored in
|
||||||
|
// `MemNode::blocks`. For example if density is 64 and count of blocks is 20,
|
||||||
|
// memory node contains 64*20 bytes of memory and smallest possible allocation
|
||||||
|
// (and also alignment) is 64 bytes. So density is also related to memory
|
||||||
|
// alignment. Binary trees (RB) are used to enable fast lookup into all addresses
|
||||||
|
// allocated by memory manager instance. This is used mainly by `VMemPrivate::release()`.
|
||||||
|
//
|
||||||
|
// Bit array looks like this (empty = unused, X = used) - Size of block 64:
|
||||||
//
|
//
|
||||||
// Bit array looks like this (empty = unused, X = used) - Size of block 64
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// | |X|X| | | | | |X|X|X|X|X|X| | | | | | | | | | | | |X| | | | |X|X|X| | |
|
// | |X|X| | | | | |X|X|X|X|X|X| | | | | | | | | | | | |X| | | | |X|X|X| | |
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// Bits array shows that there are 12 allocated blocks of 64 bytes, so total
|
// (Maximum continuous block)
|
||||||
// allocated size is 768 bytes. Maximum count of continuous blocks is 12
|
//
|
||||||
// (see largest gap).
|
// These bits show that there are 12 allocated blocks (X) of 64 bytes, so total
|
||||||
|
// size allocated is 768 bytes. Maximum count of continuous memory is 12 * 64.
|
||||||
|
|
||||||
namespace asmjit {
|
namespace asmjit {
|
||||||
|
|
||||||
|
|||||||
@@ -19,18 +19,18 @@
|
|||||||
|
|
||||||
namespace asmjit {
|
namespace asmjit {
|
||||||
|
|
||||||
//! Zero width chunk used when Zone doesn't have any memory allocated.
|
//! Zero size block used by `Zone` that doesn't have any memory allocated.
|
||||||
static const Zone::Chunk Zone_zeroChunk = {
|
static const Zone::Block Zone_zeroBlock = {
|
||||||
NULL, 0, 0, { 0 }
|
NULL, NULL, NULL, NULL, { 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// [asmjit::Zone - Construction / Destruction]
|
// [asmjit::Zone - Construction / Destruction]
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
Zone::Zone(size_t chunkSize) {
|
Zone::Zone(size_t blockSize) {
|
||||||
_chunks = const_cast<Zone::Chunk*>(&Zone_zeroChunk);
|
_blocks = const_cast<Zone::Block*>(&Zone_zeroBlock);
|
||||||
_chunkSize = chunkSize;
|
_blockSize = blockSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
Zone::~Zone() {
|
Zone::~Zone() {
|
||||||
@@ -42,35 +42,33 @@ Zone::~Zone() {
|
|||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
void Zone::clear() {
|
void Zone::clear() {
|
||||||
Chunk* cur = _chunks;
|
Block* cur = _blocks;
|
||||||
|
|
||||||
if (cur == &Zone_zeroChunk)
|
// Can't be altered.
|
||||||
|
if (cur == &Zone_zeroBlock)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
while (cur->prev != NULL)
|
||||||
cur = cur->prev;
|
cur = cur->prev;
|
||||||
while (cur != NULL) {
|
|
||||||
Chunk* prev = cur->prev;
|
|
||||||
::free(cur);
|
|
||||||
cur = prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
_chunks->pos = 0;
|
cur->pos = cur->data;
|
||||||
_chunks->prev = NULL;
|
_blocks = cur;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Zone::reset() {
|
void Zone::reset() {
|
||||||
Chunk* cur = _chunks;
|
Block* cur = _blocks;
|
||||||
|
|
||||||
if (cur == &Zone_zeroChunk)
|
// Can't be altered.
|
||||||
|
if (cur == &Zone_zeroBlock)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
while (cur != NULL) {
|
do {
|
||||||
Chunk* prev = cur->prev;
|
Block* prev = cur->prev;
|
||||||
::free(cur);
|
::free(cur);
|
||||||
cur = prev;
|
cur = prev;
|
||||||
}
|
} while (cur != NULL);
|
||||||
|
|
||||||
_chunks = const_cast<Zone::Chunk*>(&Zone_zeroChunk);
|
_blocks = const_cast<Zone::Block*>(&Zone_zeroBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -78,38 +76,58 @@ void Zone::reset() {
|
|||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
void* Zone::_alloc(size_t size) {
|
void* Zone::_alloc(size_t size) {
|
||||||
Chunk* cur = _chunks;
|
Block* curBlock = _blocks;
|
||||||
ASMJIT_ASSERT(cur == &Zone_zeroChunk || cur->getRemainingSize() < size);
|
size_t blockSize = IntUtil::iMax<size_t>(_blockSize, size);
|
||||||
|
|
||||||
size_t chunkSize = _chunkSize;
|
// The `_alloc()` method can only be called if there is not enough space
|
||||||
if (chunkSize < size)
|
// in the current block, see `alloc()` implementation for more details.
|
||||||
chunkSize = size;
|
ASMJIT_ASSERT(curBlock == &Zone_zeroBlock || curBlock->getRemainingSize() < size);
|
||||||
|
|
||||||
cur = static_cast<Chunk*>(::malloc(sizeof(Chunk) - sizeof(void*) + chunkSize));
|
// If the `Zone` has been cleared the current block doesn't have to be the
|
||||||
if (cur == NULL)
|
// last one. Check if there is a block that can be used instead of allocating
|
||||||
return NULL;
|
// a new one. If there is a `next` block it's completely unused, we don't have
|
||||||
|
// to check for remaining bytes.
|
||||||
cur->prev = NULL;
|
Block* next = curBlock->next;
|
||||||
cur->pos = 0;
|
if (next != NULL && next->getBlockSize() >= size) {
|
||||||
cur->size = chunkSize;
|
next->pos = next->data + size;
|
||||||
|
_blocks = next;
|
||||||
if (_chunks != &Zone_zeroChunk)
|
return static_cast<void*>(next->data);
|
||||||
cur->prev = _chunks;
|
|
||||||
_chunks = cur;
|
|
||||||
|
|
||||||
uint8_t* p = cur->data + cur->pos;
|
|
||||||
cur->pos += size;
|
|
||||||
|
|
||||||
ASMJIT_ASSERT(cur->pos <= cur->size);
|
|
||||||
return (void*)p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void* Zone::_allocZeroed(size_t size) {
|
// Prevent arithmetic overflow.
|
||||||
void* p = _alloc(size);
|
if (blockSize > ~static_cast<size_t>(0) - sizeof(Block))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
Block* newBlock = static_cast<Block*>(::malloc(sizeof(Block) - sizeof(void*) + blockSize));
|
||||||
|
if (newBlock == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
newBlock->pos = newBlock->data + size;
|
||||||
|
newBlock->end = newBlock->data + blockSize;
|
||||||
|
newBlock->prev = NULL;
|
||||||
|
newBlock->next = NULL;
|
||||||
|
|
||||||
|
if (curBlock != &Zone_zeroBlock) {
|
||||||
|
newBlock->prev = curBlock;
|
||||||
|
curBlock->next = newBlock;
|
||||||
|
|
||||||
|
// Does only happen if there is a next block, but the requested memory
|
||||||
|
// can't fit into it. In this case a new buffer is allocated and inserted
|
||||||
|
// between the current block and the next one.
|
||||||
|
if (next != NULL) {
|
||||||
|
newBlock->next = next;
|
||||||
|
next->prev = newBlock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_blocks = newBlock;
|
||||||
|
return static_cast<void*>(newBlock->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* Zone::allocZeroed(size_t size) {
|
||||||
|
void* p = alloc(size);
|
||||||
if (p != NULL)
|
if (p != NULL)
|
||||||
::memset(p, 0, size);
|
::memset(p, 0, size);
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,7 +150,7 @@ char* Zone::sdup(const char* str) {
|
|||||||
if (str == NULL)
|
if (str == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
size_t len = strlen(str);
|
size_t len = ::strlen(str);
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@@ -153,17 +171,16 @@ char* Zone::sformat(const char* fmt, ...) {
|
|||||||
if (fmt == NULL)
|
if (fmt == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
char buf[256];
|
char buf[512];
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
len = vsnprintf(buf, 256, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
len = IntUtil::iMin<size_t>(len, 255);
|
len = vsnprintf(buf, ASMJIT_ARRAY_SIZE(buf) - 1, fmt, ap);
|
||||||
buf[len++] = 0;
|
buf[len++] = 0;
|
||||||
|
|
||||||
|
va_end(ap);
|
||||||
return static_cast<char*>(dup(buf, len));
|
return static_cast<char*>(dup(buf, len));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,28 +23,53 @@ namespace asmjit {
|
|||||||
// [asmjit::Zone]
|
// [asmjit::Zone]
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
//! Fast incremental memory allocator.
|
//! Zone memory allocator.
|
||||||
//!
|
//!
|
||||||
//! Memory allocator designed to allocate small objects that will be invalidated
|
//! Zone is an incremental memory allocator that allocates memory by simply
|
||||||
//! (freed) all at once.
|
//! 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 `clear()` or `reset()`.
|
||||||
struct Zone {
|
struct Zone {
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
// [Chunk]
|
// [Block]
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
//! \internal
|
//! \internal
|
||||||
//!
|
//!
|
||||||
//! One allocated chunk of memory.
|
//! A single block of memory.
|
||||||
struct Chunk {
|
struct Block {
|
||||||
//! Get count of remaining (unused) bytes in chunk.
|
// ------------------------------------------------------------------------
|
||||||
ASMJIT_INLINE size_t getRemainingSize() const { return size - pos; }
|
// [Accessors]
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
//! Link to previous chunk.
|
//! Get the size of the block.
|
||||||
Chunk* prev;
|
ASMJIT_INLINE size_t getBlockSize() const {
|
||||||
//! Position in this chunk.
|
return (size_t)(end - data);
|
||||||
size_t pos;
|
}
|
||||||
//! Size of this chunk (in bytes).
|
|
||||||
size_t size;
|
//! Get count of remaining bytes in the block.
|
||||||
|
ASMJIT_INLINE size_t getRemainingSize() const {
|
||||||
|
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.
|
//! Data.
|
||||||
uint8_t data[sizeof(void*)];
|
uint8_t data[sizeof(void*)];
|
||||||
@@ -56,38 +81,45 @@ struct Zone {
|
|||||||
|
|
||||||
//! Create a new instance of `Zone` allocator.
|
//! Create a new instance of `Zone` allocator.
|
||||||
//!
|
//!
|
||||||
//! The `chunkSize` parameter describes the size of the chunk. If `alloc()`
|
//! The `blockSize` parameter describes the default size of the block. If the
|
||||||
//! requires more memory than `chunkSize` then a bigger chunk will be
|
//! `size` parameter passed to `alloc()` is greater than the default size
|
||||||
//! allocated, however `chunkSize` will not be changed.
|
//! `Zone` will allocate and use a larger block, but it will not change the
|
||||||
ASMJIT_API Zone(size_t chunkSize);
|
//! default `blockSize`.
|
||||||
|
|
||||||
//! Destroy `Zone` instance.
|
|
||||||
//!
|
//!
|
||||||
//! Destructor released all chunks allocated by `Zone`. The `reset()` member
|
//! It's not required, but it's good practice to set `blockSize` to a
|
||||||
//! function does the same without actually destroying `Zone` object itself.
|
//! 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);
|
||||||
|
|
||||||
|
//! Destroy the `Zone` instance.
|
||||||
|
//!
|
||||||
|
//! This will destroy the `Zone` instance and release all blocks of memory
|
||||||
|
//! allocated by it. It performs implicit `reset()`.
|
||||||
ASMJIT_API ~Zone();
|
ASMJIT_API ~Zone();
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
// [Clear / Reset]
|
// [Clear / Reset]
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
//! Reset the `Zone` releasing all chunks allocated.
|
//! Clear the `Zone`, but keep all blocks allocated so they can be reused.
|
||||||
//!
|
//!
|
||||||
//! Calling `clear()` will release all chunks allocated by `Zone` except the
|
//! This is the preferred way of invalidating objects allocated by `Zone`.
|
||||||
//! first one that will be reused if needed.
|
|
||||||
ASMJIT_API void clear();
|
ASMJIT_API void clear();
|
||||||
|
|
||||||
//! Reset the `Zone` releasing all chunks allocated.
|
//! Reset the `Zone` releasing all blocks allocated.
|
||||||
//!
|
//!
|
||||||
//! Calling `reset()` will release all chunks allocated by `Zone`.
|
//! Calling `reset()` does complete cleanup, it releases all blocks allocated
|
||||||
|
//! by `Zone`.
|
||||||
ASMJIT_API void reset();
|
ASMJIT_API void reset();
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
// [Accessors]
|
// [Accessors]
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
//! Get chunk size.
|
//! Get the default block size.
|
||||||
ASMJIT_INLINE size_t getChunkSize() const { return _chunkSize; }
|
ASMJIT_INLINE size_t getBlockSize() const {
|
||||||
|
return _blockSize;
|
||||||
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
// [Alloc]
|
// [Alloc]
|
||||||
@@ -95,75 +127,70 @@ struct Zone {
|
|||||||
|
|
||||||
//! Allocate `size` bytes of memory.
|
//! Allocate `size` bytes of memory.
|
||||||
//!
|
//!
|
||||||
//! Pointer allocated by this way will be valid until `Zone` object is
|
//! Pointer returned is valid until the `Zone` instance is destroyed or reset
|
||||||
//! destroyed. To create class by this way use placement `new` and `delete`
|
//! by calling `clear()` or `reset()`. If you plan to make an instance of C++
|
||||||
//! operators:
|
//! from the given pointer use placement `new` and `delete` operators:
|
||||||
//!
|
//!
|
||||||
//! ~~~
|
//! ~~~
|
||||||
//! // Example of simple class allocation.
|
//! using namespace asmjit;
|
||||||
//! using namespace asmjit
|
|
||||||
//!
|
//!
|
||||||
//! // Your class.
|
//! class SomeObject { ... };
|
||||||
//! class Object {
|
|
||||||
//! // members...
|
|
||||||
//! };
|
|
||||||
//!
|
//!
|
||||||
//! // Your function
|
//! // Create Zone with default block size of 65536 bytes.
|
||||||
//! void f() {
|
|
||||||
//! // Create zone object with chunk size of 65536 bytes.
|
|
||||||
//! Zone zone(65536);
|
//! Zone zone(65536);
|
||||||
//!
|
//!
|
||||||
//! // Create your objects using zone object allocating, for example:
|
//! // Create your objects using zone object allocating, for example:
|
||||||
//! Object* obj = new(zone.alloc(sizeof(YourClass))) Object();
|
//! Object* obj = static_cast<Object*>( zone.alloc(sizeof(SomeClass)) );
|
||||||
|
//
|
||||||
|
//! if (obj == NULL) {
|
||||||
|
//! // Handle out of memory error.
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! // To instantiate class placement `new` and `delete` operators can be used.
|
||||||
|
//! new(obj) Object();
|
||||||
//!
|
//!
|
||||||
//! // ... lifetime of your objects ...
|
//! // ... lifetime of your objects ...
|
||||||
//!
|
//!
|
||||||
//! // Destroy your objects:
|
//! // To destroy the instance (if required).
|
||||||
//! obj->~Object();
|
//! obj->~Object();
|
||||||
//!
|
//!
|
||||||
//! // Zone destructor will free all memory allocated through it, you can
|
//! // Reset of destroy `Zone`.
|
||||||
//! // call `zone.reset()` if you wan't to reuse current `Zone`.
|
//! zone.reset();
|
||||||
//! }
|
|
||||||
//! ~~~
|
//! ~~~
|
||||||
ASMJIT_INLINE void* alloc(size_t size) {
|
ASMJIT_INLINE void* alloc(size_t size) {
|
||||||
Chunk* cur = _chunks;
|
Block* cur = _blocks;
|
||||||
|
|
||||||
if (cur->getRemainingSize() < size)
|
uint8_t* ptr = cur->pos;
|
||||||
|
size_t remainingBytes = (size_t)(cur->end - ptr);
|
||||||
|
|
||||||
|
if (remainingBytes < size)
|
||||||
return _alloc(size);
|
return _alloc(size);
|
||||||
|
|
||||||
uint8_t* p = cur->data + cur->pos;
|
|
||||||
cur->pos += size;
|
cur->pos += size;
|
||||||
ASMJIT_ASSERT(cur->pos <= cur->size);
|
ASMJIT_ASSERT(cur->pos <= cur->end);
|
||||||
|
|
||||||
return (void*)p;
|
return (void*)ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Like `alloc()`, but the return is casted to `T*`.
|
//! Allocate `size` bytes of zeroed memory.
|
||||||
|
//!
|
||||||
|
//! See \ref alloc() for more details.
|
||||||
|
ASMJIT_API void* allocZeroed(size_t size);
|
||||||
|
|
||||||
|
//! Like `alloc()`, but the return pointer is casted to `T*`.
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ASMJIT_INLINE T* allocT(size_t size = sizeof(T)) {
|
ASMJIT_INLINE T* allocT(size_t size = sizeof(T)) {
|
||||||
return static_cast<T*>(alloc(size));
|
return static_cast<T*>(alloc(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \internal
|
//! Like `allocZeroed()`, but the return pointer is casted to `T*`.
|
||||||
ASMJIT_API void* _alloc(size_t size);
|
template<typename T>
|
||||||
|
ASMJIT_INLINE T* allocZeroedT(size_t size = sizeof(T)) {
|
||||||
//! Allocate `size` bytes of zeroed memory.
|
return static_cast<T*>(allocZeroed(size));
|
||||||
ASMJIT_INLINE void* allocZeroed(size_t size) {
|
|
||||||
Chunk* cur = _chunks;
|
|
||||||
|
|
||||||
if (cur->getRemainingSize() < size)
|
|
||||||
return _allocZeroed(size);
|
|
||||||
|
|
||||||
uint8_t* p = cur->data + cur->pos;
|
|
||||||
cur->pos += size;
|
|
||||||
ASMJIT_ASSERT(cur->pos <= cur->size);
|
|
||||||
|
|
||||||
::memset(p, 0, size);
|
|
||||||
return (void*)p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \internal
|
//! \internal
|
||||||
ASMJIT_API void* _allocZeroed(size_t size);
|
ASMJIT_API void* _alloc(size_t size);
|
||||||
|
|
||||||
//! Helper to duplicate data.
|
//! Helper to duplicate data.
|
||||||
ASMJIT_API void* dup(const void* data, size_t size);
|
ASMJIT_API void* dup(const void* data, size_t size);
|
||||||
@@ -178,10 +205,15 @@ struct Zone {
|
|||||||
// [Members]
|
// [Members]
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
//! Last allocated chunk of memory.
|
//! The current block.
|
||||||
Chunk* _chunks;
|
Block* _blocks;
|
||||||
//! Default chunk size.
|
//! Default block size.
|
||||||
size_t _chunkSize;
|
size_t _blockSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
//! Zone allocator overhead.
|
||||||
|
kZoneOverhead = static_cast<int>(sizeof(Zone::Block) - sizeof(void*)) + kMemAllocOverhead
|
||||||
};
|
};
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|||||||
Reference in New Issue
Block a user