EDIT: Ive written an improved heap manager which is available from here:
https://stash.reaper.fm/v/25527/Heman...%20Manager.zip
Here is my older memory manager code. Managed memory starts from block 4. Largest memory block allowed is 1 Gig. I'm now using the Heman code available above.
TIP: Ignore the heap functions, and just use the standard malloc(), calloc(), realloc() & free() functions.
Code:
@init
// Helper function to ensure a valid memory size value.
function size_t(x) global()
(
max(floor(x), 0);
);
// Sets the starting offset for heap memory. Also resets heap link list.
function heap.min(min) global()
(
// Heap min is hardcoded to block 4.
this.min = this.max = max(size_t(min), 4 << 16);
this.min[] = 0;
);
function heap.max(max) global()
(
this.max = max(this.min, size_t(max));
);
heap.min(0);
// Returns the max heap used. Includes memory that was freed.
function heap.size() global()
(
this.max - this.min;
);
// Checks the heap block is valid. Not 100% perfect, but the best we can achieve.
function heap.check(block) global()
(
block >= this.min && (block[] <= -1 || block[] >= 1);
);
// Returns true if heap block is free.
function heap.isfree(block) global()
(
this.heap.check(block) && block[] < 0;
);
// Merges free blocks into one free block.
function heap.merge(block) global() local(ptr, size)
(
this.heap.isfree(block) ? (
size = 0; ptr = block;
while (this.heap.isfree(ptr)) ( size += ptr[]; ptr += abs(ptr[]); );
block[] = size;
);
);
/*
Checks if block is avaliable to store a given size. Also handles merging
of freed blocks after given block.
*/
function heap.avail(block, size) global()
(
!this.heap.check(block) ? block[] = -0x80000000; // 1 gig should be more than enough.
this.heap.merge(block);
size <= -block[];
);
// Allocates a block of memory. Does not clear the new memory.
function malloc(size) global(heap*) local(block)
(
size = size_t(size) + 1;
size >= 1 && size < 0x80000000 ? (
block = heap.min;
while (!heap.avail(block, size)) ( block += abs(block[]); );
size != -block[] ? block[size] = block[] + size;
block[] = size;
heap.max(max(heap.max, block + size));
block + 1;
) : 0;
);
// Same as malloc, but clears the memory to zero. (This is a non-standard helper)
function calloc(size) global()
(
size = size_t(size);
memset(malloc(size), 0, size);
);
// Same as malloc, but clears the memory to zero.
function calloc(count, size) global()
(
calloc(size_t(count) * size_t(size));
);
// Returns TRUE if memory location is valid.
function mcheck(memory) global(heap*)
(
heap.check(memory - 1);
);
// Returns the size of given memory location.
function _msize(memory) global()
(
mcheck(memory) && memory[-1] > 0 ? memory[-1] - 1 : 0;
);
// Same as _msize(). Mac name alias.
function malloc_size(memory) global()
(
_msize(memory);
);
// Frees a memory block.
function free(memory) global()
(
mcheck(memory) ? memory[-1] = -abs(memory[-1]);
0;
);
// Realloc a memory block, with option to clear new memory.
function realloc(memory, size, clear) global() local(newmem)
(
size = size_t(size);
size == _msize(memory) ? (
memory;
) : (
newmem = clear ? calloc(size) : malloc(size);
memcpy(newmem, memory, min(size, _msize(memory)));
free(memory);
newmem;
);
);
// Traditional realloc. New memory is not cleared.
function realloc(m, n) global()
(
realloc(m, n, 0);
);
Just a little info about JS memory. JS memory is allocated in pages of (1 << 16) items. ie: 65536 doubles, which is 512kb of memory. The above memory manager starts on page 4, which gives 2 meg for normal memory usage.
Sing out if you find a bug. I have done a lot of testing, but, more testing is always good.