summaryrefslogtreecommitdiff
path: root/compiler_and_linker/FrontEnd/Optimizer/IroMalloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'compiler_and_linker/FrontEnd/Optimizer/IroMalloc.c')
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroMalloc.c564
1 files changed, 564 insertions, 0 deletions
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroMalloc.c b/compiler_and_linker/FrontEnd/Optimizer/IroMalloc.c
new file mode 100644
index 0000000..1f15cad
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroMalloc.c
@@ -0,0 +1,564 @@
+#include "IroMalloc.h"
+#include "compiler/CompilerTools.h"
+
+#define FLAGMASK 0xF
+
+typedef struct Block {
+ struct Block *prev;
+ struct Block *next;
+ void *x8;
+ void *xC;
+ size_t remain;
+ size_t x14;
+} Block;
+
+typedef struct SubBlockBase {
+ size_t x0;
+ Block *block;
+} SubBlockBase;
+
+typedef struct SubBlock {
+ size_t x0;
+ Block *block;
+ struct SubBlock *x8;
+ struct SubBlock *xC;
+} SubBlock;
+
+typedef struct SubBlockTail {
+ size_t x0copy;
+} SubBlockTail;
+
+typedef struct BlockTail {
+ size_t x14copy;
+ SubBlock *unk;
+} BlockTail;
+
+typedef struct FixStart {
+ struct FixBlock *a;
+ struct FixSubBlock *b;
+ long count;
+} FixStart;
+
+typedef struct FixBlock {
+ struct FixBlock *prev;
+ struct FixBlock *next;
+ size_t entrysize;
+} FixBlock;
+
+typedef struct FixSubBlockBase {
+ FixBlock *fixblock;
+} FixSubBlockBase;
+
+typedef struct FixSubBlock {
+ FixBlock *fixblock;
+ struct FixSubBlock *next;
+} FixSubBlock;
+
+static const size_t fix_pool_sizes[] = {0xC, 0x1C, 0x2C, 0x4C};
+static Block *start_;
+static FixStart fix_start[4];
+static int initialized;
+
+// forward decls
+static void Block_link(Block *block, SubBlock *subblock);
+static void Block_unlink(Block *block, SubBlock *subblock);
+static void SubBlock_construct(SubBlock *subblock, size_t size, Block *block, int flag1, int flag2);
+static SubBlock *SubBlock_split(SubBlock *subblock, size_t pos);
+static SubBlock *SubBlock_merge_prev(SubBlock *subblock, SubBlock **sbptr);
+static void SubBlock_merge_next(SubBlock *subblock, SubBlock **sbptr);
+
+#define BLOCK_TAIL(block) ((BlockTail *) ((long) (block) + ((block)->x14 & ~FLAGMASK) - sizeof(BlockTail)))
+
+#define BUF_LOCATOR(buf) (*((size_t *) ((long) (buf) - sizeof(size_t))))
+#define SBB_BLOCK(sbb) ((Block *) ((long) ((sbb)->block) & ~1))
+
+#define BUF_IS_VAR(buf) (BUF_LOCATOR(buf) & 1)
+#define VARBUF_SBB(buf) ((SubBlockBase *) ((long) (buf) - sizeof(SubBlockBase)))
+#define VARBUF_SB(buf) ((SubBlock *) ((long) (buf) - sizeof(SubBlockBase)))
+#define VARBUF_BLOCKSIZE(buf) (VARBUF_SBB(buf)->x0 & ~FLAGMASK)
+#define VARBUF_SIZE(buf) (((VARBUF_SBB(buf)->x0 & ~FLAGMASK) - sizeof(SubBlockBase)))
+#define VARBUF_BLOCK(buf) SBB_BLOCK(VARBUF_SBB(buf))
+#define FIXBUF_SIZE(buf) (((FixBlock *) BUF_LOCATOR(buf))->entrysize)
+
+#define BUF_SIZE(buf) BUF_IS_VAR(buf) ? VARBUF_SIZE(buf) : FIXBUF_SIZE(buf)
+
+static void Block_construct(Block *block, size_t size) {
+ SubBlock *subblock;
+
+ block->x14 = size | 3;
+ ((BlockTail *) ((long) block + size - sizeof(BlockTail)))->x14copy = block->x14;
+
+ subblock = (SubBlock *) (block + 1);
+ SubBlock_construct(subblock, size - sizeof(Block) - sizeof(BlockTail), block, 0, 0);
+
+ block->remain = size - sizeof(Block) - sizeof(BlockTail);
+ BLOCK_TAIL(block)->unk = NULL;
+
+ Block_link(block, subblock);
+}
+
+static SubBlock *Block_subBlock(Block *block, size_t size) {
+ SubBlock *subblock;
+ size_t check;
+ size_t best;
+
+ if (!BLOCK_TAIL(block)->unk)
+ return NULL;
+
+ subblock = BLOCK_TAIL(block)->unk;
+ best = subblock->x0 & ~FLAGMASK;
+ check = subblock->x0 & ~FLAGMASK;
+ while (check < size) {
+ subblock = subblock->xC;
+ check = subblock->x0 & ~FLAGMASK;
+ if (best < check)
+ best = check;
+ if (subblock == BLOCK_TAIL(block)->unk) {
+ block->remain = best;
+ return NULL;
+ }
+ }
+
+ if ((check - size) >= 0x60)
+ SubBlock_split(subblock, size);
+
+ BLOCK_TAIL(block)->unk = subblock->xC;
+ Block_unlink(block, subblock);
+ return subblock;
+}
+
+static void Block_link(Block *block, SubBlock *subblock) {
+ size_t size;
+ SubBlock **sbptr;
+
+ size = subblock->x0 & ~FLAGMASK;
+ subblock->x0 &= ~2;
+ ((SubBlock *) ((long) subblock + size))->x0 &= ~4;
+ ((SubBlockTail *) ((long) subblock + size - sizeof(SubBlockTail)))->x0copy = size;
+
+ sbptr = &BLOCK_TAIL(block)->unk;
+ if (*sbptr) {
+ subblock->x8 = (*sbptr)->x8;
+ subblock->x8->xC = subblock;
+ subblock->xC = *sbptr;
+ (*sbptr)->x8 = subblock;
+ *sbptr = subblock;
+ *sbptr = SubBlock_merge_prev(*sbptr, sbptr);
+ SubBlock_merge_next(*sbptr, sbptr);
+ } else {
+ *sbptr = subblock;
+ subblock->x8 = subblock;
+ subblock->xC = subblock;
+ }
+
+ if (block->remain < ((*sbptr)->x0 & ~FLAGMASK))
+ block->remain = (*sbptr)->x0 & ~FLAGMASK;
+}
+
+static void Block_unlink(Block *block, SubBlock *subblock) {
+ size_t size;
+ SubBlock **sbptr;
+
+ size = subblock->x0 & ~FLAGMASK;
+ subblock->x0 |= 2;
+ ((SubBlock *) ((long) subblock + size))->x0 |= 4;
+
+ sbptr = &BLOCK_TAIL(block)->unk;
+ if (*sbptr == subblock)
+ *sbptr = subblock->xC;
+
+ if (*sbptr == subblock) {
+ *sbptr = NULL;
+ block->remain = 0;
+ } else {
+ subblock->xC->x8 = subblock->x8;
+ subblock->x8->xC = subblock->xC;
+ }
+}
+
+static void SubBlock_construct(SubBlock *subblock, size_t size, Block *block, int flag1, int flag2) {
+ subblock->block = (Block *) ((long) block | 1);
+ subblock->x0 = size;
+ if (flag1)
+ subblock->x0 |= 4;
+ if (flag2) {
+ subblock->x0 |= 2;
+ ((SubBlock *) (((long) subblock) + size))->x0 |= 4;
+ } else {
+ ((SubBlockTail *) (((long) subblock) + size - sizeof(SubBlockTail)))->x0copy = size;
+ }
+}
+
+static SubBlock *SubBlock_split(SubBlock *subblock, size_t pos) {
+ size_t oldsize;
+ int flag;
+ SubBlock *splitright;
+ Block *block;
+
+ oldsize = subblock->x0 & ~FLAGMASK;
+ flag = !(subblock->x0 & 2);
+ splitright = (SubBlock *) ((long) subblock + pos);
+ block = (Block *) ((long) subblock->block & ~1);
+ SubBlock_construct(subblock, pos, block, subblock->x0 & 4, !flag);
+ SubBlock_construct(splitright, oldsize - pos, block, !flag, !flag);
+ if (flag) {
+ splitright->xC = subblock->xC;
+ splitright->xC->x8 = splitright;
+ splitright->x8 = subblock;
+ subblock->xC = splitright;
+ }
+
+ return splitright;
+}
+
+static SubBlock *SubBlock_merge_prev(SubBlock *subblock, SubBlock **sbptr) {
+ size_t prevsize;
+ SubBlock *prevblock;
+
+ if (!(subblock->x0 & 4)) {
+ prevsize = ((SubBlockTail *) ((long) subblock - sizeof(SubBlockTail)))->x0copy;
+ if (prevsize & 2)
+ return subblock;
+
+ prevblock = (SubBlock *) ((long) subblock - prevsize);
+ prevblock->x0 = prevblock->x0 & FLAGMASK;
+ prevblock->x0 |= (prevsize + (subblock->x0 & ~FLAGMASK)) & ~FLAGMASK;
+ if (!(prevblock->x0 & 2))
+ ((SubBlockTail *) ((long) prevblock + prevsize + (subblock->x0 & ~FLAGMASK) - sizeof(SubBlockTail)))->x0copy = prevsize + (subblock->x0 & ~FLAGMASK);
+
+ if (*sbptr == subblock)
+ *sbptr = (*sbptr)->xC;
+
+ subblock->xC->x8 = subblock->x8;
+ subblock->xC->x8->xC = subblock->xC;
+ return prevblock;
+ }
+
+ return subblock;
+}
+
+static void SubBlock_merge_next(SubBlock *subblock, SubBlock **sbptr) {
+ SubBlock *nextblock;
+ size_t nextsize;
+
+ nextblock = (SubBlock *) ((long) subblock + (subblock->x0 & ~FLAGMASK));
+ if (!(nextblock->x0 & 2)) {
+ nextsize = (subblock->x0 & ~FLAGMASK) + (nextblock->x0 & ~FLAGMASK);
+ subblock->x0 = subblock->x0 & FLAGMASK;
+ subblock->x0 |= nextsize & ~FLAGMASK;
+
+ if (!(subblock->x0 & 2))
+ ((SubBlockTail *) ((long) subblock + nextsize - sizeof(SubBlockTail)))->x0copy = nextsize;
+
+ if (!(subblock->x0 & 2))
+ ((SubBlock *) ((long) subblock + nextsize))->x0 &= ~4;
+ else
+ ((SubBlock *) ((long) subblock + nextsize))->x0 |= 4;
+
+ if (*sbptr == nextblock)
+ *sbptr = (*sbptr)->xC;
+ if (*sbptr == nextblock)
+ *sbptr = NULL;
+
+ nextblock->xC->x8 = nextblock->x8;
+ nextblock->x8->xC = nextblock->xC;
+ }
+}
+
+static void link_block(Block *block) {
+ if (start_) {
+ block->prev = start_->prev;
+ block->prev->next = block;
+ block->next = start_;
+
+ start_->prev = block;
+ start_ = block;
+ } else {
+ start_ = block;
+ block->prev = block;
+ block->next = block;
+ }
+}
+
+static Block *unlink_block(Block *block) {
+ Block *newblock;
+
+ newblock = block->next;
+ if (newblock == block)
+ newblock = NULL;
+
+ if (start_ == block)
+ start_ = newblock;
+
+ if (newblock) {
+ newblock->prev = block->prev;
+ newblock->prev->next = newblock;
+ }
+
+ block->prev = block->next = NULL;
+ return newblock;
+}
+
+static Block *link_new_block(size_t size) {
+ Block *block;
+
+ size = (size + 0x1000 + sizeof(Block) + sizeof(BlockTail) - 1) & ~0xFFF;
+ if (size < 0x10000)
+ size = 0x10000;
+
+ if (!(block = galloc(size)))
+ return NULL;
+
+ Block_construct(block, size);
+ link_block(block);
+ return block;
+}
+
+static void *allocate_from_var_pools(size_t size) {
+ Block *block;
+ SubBlock *subblock;
+
+ size = (size + sizeof(Block) - 1) & ~0xF;
+ if (size < 0x60)
+ size = 0x60;
+
+ block = start_ ? start_ : link_new_block(size);
+ if (!block)
+ return NULL;
+
+ do {
+ if (size <= block->remain) {
+ if ((subblock = Block_subBlock(block, size))) {
+ start_ = block;
+ goto allocated;
+ }
+ }
+ } while ((block = block->next) != start_);
+
+ block = link_new_block(size);
+ if (!block)
+ return NULL;
+ subblock = Block_subBlock(block, size);
+allocated:
+ return (SubBlockBase *) subblock + 1;
+}
+
+static void deallocate_from_var_pools(void *buf) {
+ Block *block;
+ SubBlock *subblock;
+ int flag;
+
+ subblock = (SubBlock *) ((long) buf - sizeof(SubBlockBase));
+ block = (Block *) ((long) subblock->block & ~1);
+ Block_link(block, subblock);
+
+ flag = 0;
+ subblock = (SubBlock *) (block + 1);
+ if (!(subblock->x0 & 2)) {
+ if ((subblock->x0 & ~FLAGMASK) == ((block->x14 & ~FLAGMASK) - sizeof(Block) - sizeof(BlockTail)))
+ flag = 1;
+ }
+
+ if (flag)
+ unlink_block(block);
+}
+
+static void FixBlock_construct(FixBlock *fixblock, FixBlock *prev, FixBlock *next, int poolIndex, void *buffer, size_t buffersize) {
+ size_t entrysize;
+ size_t entrycount;
+ size_t i;
+ FixSubBlock *fsb;
+ FixSubBlock *fsbnext;
+
+ fixblock->prev = prev;
+ fixblock->next = next;
+ fixblock->entrysize = fix_pool_sizes[poolIndex];
+
+ entrysize = fix_pool_sizes[poolIndex] + sizeof(void *);
+ entrycount = (buffersize / entrysize);
+ fsb = buffer;
+ for (i = 0; i < (entrycount - 1); i++) {
+ fsbnext = (FixSubBlock *) ((long) fsb + entrysize);
+ fsb->fixblock = fixblock;
+ fsb->next = fsbnext;
+ fsb = fsbnext;
+ }
+
+ fsb->fixblock = fixblock;
+ fsb->next = fix_start[poolIndex].b;
+ fix_start[poolIndex].b = buffer;
+}
+
+static void *allocate_from_fixed_pools(size_t size) {
+ int poolIndex;
+ FixSubBlock *fsb;
+
+ poolIndex = 0;
+ while (size > fix_pool_sizes[poolIndex])
+ poolIndex++;
+
+ if (!fix_start[poolIndex].b) {
+ void *buf;
+ size_t bufsize;
+
+ buf = allocate_from_var_pools(4000);
+ if (!buf)
+ return NULL;
+
+ bufsize = !BUF_IS_VAR(buf) ? FIXBUF_SIZE(buf) : VARBUF_SIZE(buf);
+ FixBlock_construct(
+ buf, NULL, fix_start[poolIndex].a, poolIndex,
+ ((FixBlock *) buf) + 1,
+ bufsize - sizeof(FixBlock)
+ );
+ fix_start[poolIndex].a = buf;
+ }
+
+ fsb = fix_start[poolIndex].b;
+ fix_start[poolIndex].b = fsb->next;
+ fix_start[poolIndex].count++;
+ return ((FixSubBlockBase *) fsb) + 1;
+}
+
+static void deallocate_from_fixed_pools(void *buf, size_t size) {
+ int poolIndex;
+ FixBlock *fixblock;
+ FixBlock *nextfb;
+ FixSubBlock *fsb;
+
+ poolIndex = 0;
+ while (size > fix_pool_sizes[poolIndex])
+ poolIndex++;
+
+ fsb = (FixSubBlock *) ((long) buf - sizeof(FixSubBlockBase));
+ fsb->next = fix_start[poolIndex].b;
+ fix_start[poolIndex].b = fsb;
+ if (--fix_start[poolIndex].count == 0) {
+ fixblock = fix_start[poolIndex].a;
+ while (fixblock) {
+ nextfb = fixblock->next;
+ deallocate_from_var_pools(fixblock);
+ fixblock = nextfb;
+ }
+ fix_start[poolIndex].a = NULL;
+ fix_start[poolIndex].b = NULL;
+ }
+}
+
+size_t IRO_msize(void *buf) {
+ return BUF_SIZE(buf);
+}
+
+void *IRO_malloc(size_t size) {
+ if (!size)
+ return NULL;
+
+ if (size <= 0x4C)
+ return allocate_from_fixed_pools(size);
+ else
+ return allocate_from_var_pools(size);
+}
+
+void IRO_free(void *buf) {
+ if (buf) {
+ size_t size = !BUF_IS_VAR(buf) ? FIXBUF_SIZE(buf) : VARBUF_SIZE(buf);
+
+ if (size <= 0x4C)
+ deallocate_from_fixed_pools(buf, size);
+ else
+ deallocate_from_var_pools(buf);
+ }
+}
+
+void *IRO_realloc(void *buf, size_t newsize) {
+ size_t oldsize;
+ size_t newblocksize;
+ void *newbuf;
+
+ if (!buf)
+ return IRO_malloc(newsize);
+
+ if (!newsize) {
+ IRO_free(buf);
+ return NULL;
+ }
+
+ oldsize = !BUF_IS_VAR(buf) ? FIXBUF_SIZE(buf) : VARBUF_SIZE(buf);
+ if (newsize > oldsize) {
+ if (BUF_IS_VAR(buf)) {
+ newblocksize = (newsize + sizeof(Block) - 1) & ~FLAGMASK;
+ if (newblocksize < 0x60)
+ newblocksize = 0x60;
+ SubBlock_merge_next(VARBUF_SB(buf), &BLOCK_TAIL(VARBUF_BLOCK(buf))->unk);
+ if (VARBUF_BLOCKSIZE(buf) >= newblocksize) {
+ if ((VARBUF_BLOCKSIZE(buf) - newblocksize) >= 0x60) {
+ Block_link(VARBUF_BLOCK(buf), SubBlock_split(VARBUF_SB(buf), newblocksize));
+ }
+ return buf;
+ }
+ }
+
+ newbuf = IRO_malloc(newsize);
+ if (!newbuf)
+ return NULL;
+
+ memcpy(newbuf, buf, oldsize);
+ IRO_free(buf);
+ return newbuf;
+ }
+
+ if (BUF_IS_VAR(buf)) {
+ newsize = (newsize + sizeof(Block) - 1) & ~FLAGMASK;
+ if (newsize < 0x60)
+ newsize = 0x60;
+ if ((VARBUF_BLOCKSIZE(buf) - newsize) >= 0x60) {
+ Block_link(VARBUF_BLOCK(buf), SubBlock_split(VARBUF_SB(buf), newsize));
+ }
+ }
+
+ return buf;
+}
+
+void *IRO_calloc(size_t a, size_t b) {
+ void *buf;
+ size_t len = b * a;
+ buf = IRO_malloc(len);
+ if (buf)
+ memset(buf, 0, len);
+ return buf;
+}
+
+void IRO_pool_free_all(void) {
+ int i;
+ Block *block;
+ if ((block = start_)) {
+ do {
+ block = block->next;
+ } while (block != start_);
+ start_ = NULL;
+
+ for (i = 0; i < 4; i++) {
+ fix_start[i].a = NULL;
+ fix_start[i].b = NULL;
+ fix_start[i].count = 0;
+ }
+ }
+}
+
+void IRO_InitializeAllocator(void) {
+ if (!initialized) {
+ int i;
+ for (i = 0; i < 4; i++) {
+ fix_start[i].a = NULL;
+ fix_start[i].b = NULL;
+ fix_start[i].count = 0;
+ }
+ start_ = NULL;
+ initialized = 1;
+ }
+}
+
+void IRO_TerminateAllocator(void) {
+ initialized = 0;
+}
+