mirror of
https://github.com/DarkPlacesEngine/gmqcc.git
synced 2024-12-18 00:11:06 +00:00
Merge branch 'master' into test-suite
Conflicts: Makefile
This commit is contained in:
commit
990dcb106a
3 changed files with 9 additions and 362 deletions
6
Makefile
6
Makefile
|
@ -56,4 +56,8 @@ all: gmqcc qcvm test
|
|||
clean:
|
||||
rm -f *.o gmqcc qcvm test *.dat
|
||||
|
||||
|
||||
$(OBJ) $(OBJ_C) $(OBJ_X): gmqcc.h
|
||||
main.o: lexer.h
|
||||
parser.o: ast.h lexer.h
|
||||
ast.o: ast.h ir.h
|
||||
ir.o: ir.h
|
||||
|
|
5
lexer.c
5
lexer.c
|
@ -13,7 +13,10 @@ void lexerror(lex_file *lex, const char *fmt, ...)
|
|||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
con_vprintmsg(LVL_ERROR, lex->name, lex->sline, "parse error", fmt, ap);
|
||||
if (lex)
|
||||
con_vprintmsg(LVL_ERROR, lex->name, lex->sline, "parse error", fmt, ap);
|
||||
else
|
||||
con_vprintmsg(LVL_ERROR, "", 0, "parse error", fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
|
|
360
mem.c
360
mem.c
|
@ -1,360 +0,0 @@
|
|||
#include "gmqcc.h"
|
||||
#include <assert.h>
|
||||
/*
|
||||
* GMQCC does a lot of allocations on shortly lived objects all of which
|
||||
* call down to malloc/free internally. The overhead involved with these
|
||||
* allocations makes GMQCC slow. To combat this, a special allocator was
|
||||
* in need. This is an implementation of a user-space buddy allocator
|
||||
* that sits ontop of malloc/free. I'd like to thank Lee Salzman for
|
||||
* guiding me in the right direction for designing this.
|
||||
*/
|
||||
#define GMQCC_MEM_USED 0xEDCA10A1EDCA10A1
|
||||
#define GMQCC_MEM_FREE 0xEEF8EEF8EEF8EEF8
|
||||
#define GMQCC_MEM_BSL -1
|
||||
#define GMQCC_MEM_BSR 1
|
||||
#define GMQCC_MEM_DEBUG 1
|
||||
|
||||
/* debug info for dumping heap contents nicely */
|
||||
#define GMQCC_MEM_DEBUG_BPL 32 /* bytes per line */
|
||||
#define GMQCC_MEM_DEBUG_BIG 8 /* bytes in group */
|
||||
#define GMQCC_MEM_DEBUG_BSG 4 /* bytes split group */
|
||||
|
||||
#ifdef GMQCC_MEM_DEBUG
|
||||
# include <stdio.h>
|
||||
# define GMQCC_MEM_TRACE(TAG, ...) \
|
||||
do { \
|
||||
printf("[mem:%s]: %s ", TAG, __func__); \
|
||||
printf(__VA_ARGS__); \
|
||||
printf("\n"); \
|
||||
} while (0)
|
||||
#else
|
||||
# define GMQCC_MEM_TRACE(TAG, ...)
|
||||
#endif
|
||||
|
||||
typedef unsigned long int mem_addr;
|
||||
|
||||
static void *mem_heap = NULL;
|
||||
static size_t mem_look = 0; /* lookup table offset */
|
||||
static size_t mem_size = 0; /* heap size */
|
||||
|
||||
/* read or write to heap */
|
||||
#define GMQCC_MEM_WRITEHEAP(OFFSET, TYPE, VALUE) \
|
||||
do { \
|
||||
TYPE *T = (TYPE*)((unsigned char*)mem_heap + (OFFSET)); \
|
||||
*T = VALUE; \
|
||||
} while (0)
|
||||
#define GMQCC_MEM_READHEAP(OFFSET, TYPE) ((TYPE)*((TYPE *)(((unsigned char*)mem_heap + (OFFSET)))))
|
||||
|
||||
/* read of write first block to heap */
|
||||
#define GMQCC_MEM_WRITEFBA(SIZE, ADDR) GMQCC_MEM_WRITEHEAP(mem_look + (SIZE) * sizeof(mem_addr), mem_addr, (ADDR))
|
||||
#define GMQCC_MEM_READFBA(SIZE) GMQCC_MEM_READHEAP (mem_look + (SIZE) * sizeof(mem_addr), mem_addr)
|
||||
|
||||
/* read and write block sizes from heap */
|
||||
#define GMQCC_MEM_WRITEBS(ADDR, SIZE) GMQCC_MEM_WRITEHEAP(ADDR, mem_addr, (SIZE))
|
||||
#define GMQCC_MEM_READBS(ADDR) GMQCC_MEM_READHEAP (ADDR, mem_addr);
|
||||
|
||||
/*
|
||||
* Getting address of previous/following siblings, as well as
|
||||
* setting address of previous/following siblings.
|
||||
*/
|
||||
#define GMQCC_MEM_GETADDROFPS(ADDR) GMQCC_MEM_READHEAP ((ADDR) + 2 * sizeof(mem_addr), mem_addr)
|
||||
#define GMQCC_MEM_GETADDROFFS(ADDR) GMQCC_MEM_READHEAP ((ADDR) + 3 * sizeof(mem_addr), mem_addr)
|
||||
#define GMQCC_MEM_SETADDROFPS(ADDR,V) GMQCC_MEM_WRITEHEAP((ADDR) + 2 * sizeof(mem_addr), mem_addr, V)
|
||||
#define GMQCC_MEM_SETADDROFFS(ADDR,V) GMQCC_MEM_WRITEHEAP((ADDR) + 3 * sizeof(mem_addr), mem_addr, V)
|
||||
|
||||
/* Marking blocks as used or free */
|
||||
#define GMQCC_MEM_MARKUSED(ADDR) GMQCC_MEM_WRITEHEAP((ADDR) + 1 * sizeof(mem_addr), mem_addr, GMQCC_MEM_USED)
|
||||
#define GMQCC_MEM_MARKFREE(ADDR) GMQCC_MEM_WRITEHEAP((ADDR) + 1 * sizeof(mem_addr), mem_addr, GMQCC_MEM_FREE)
|
||||
|
||||
/* Has block? */
|
||||
#define GMQCC_MEM_HASBLOCK(SIZE) (GMQCC_MEM_READFBA(SIZE) != 0)
|
||||
|
||||
/* Block free? */
|
||||
#define GMQCC_MEM_BLOCKFREE(ADDR) ((GMQCC_MEM_READHEAP((ADDR) + 1 * sizeof(mem_addr), mem_addr)) == GMQCC_MEM_FREE)
|
||||
|
||||
/*
|
||||
* Must be first since it's used internally, but also should be exposed
|
||||
* to the outside, statics exist after this.
|
||||
*/
|
||||
void mem_dump() {
|
||||
size_t addr = 0;
|
||||
unsigned char *ptr = (unsigned char*)mem_heap;
|
||||
|
||||
while (addr < mem_size) {
|
||||
size_t offset = 0;
|
||||
printf("% 8X: ", addr);
|
||||
while (offset < GMQCC_MEM_DEBUG_BPL) {
|
||||
if (addr + offset >= mem_size)
|
||||
break;
|
||||
|
||||
ptr ++;
|
||||
offset ++;
|
||||
|
||||
printf (
|
||||
!(offset%GMQCC_MEM_DEBUG_BSG) &&
|
||||
(offset%GMQCC_MEM_DEBUG_BIG) ? "%02X " :
|
||||
!(offset%GMQCC_MEM_DEBUG_BIG) ? "%02X " : "%02X ",
|
||||
*ptr
|
||||
);
|
||||
}
|
||||
printf("\n");
|
||||
addr += GMQCC_MEM_DEBUG_BPL;
|
||||
}
|
||||
}
|
||||
|
||||
static void mem_init_table(size_t size) {
|
||||
size_t i;
|
||||
GMQCC_MEM_TRACE("flow", "(%lu)", size);
|
||||
|
||||
mem_look = 8 * ((mem_addr)1 << (size - 1)) + sizeof(mem_addr);
|
||||
|
||||
GMQCC_MEM_WRITEHEAP(0, mem_addr, mem_look);
|
||||
GMQCC_MEM_WRITEHEAP(mem_look, mem_addr, size);
|
||||
|
||||
/* write pointers to first free bock of said size */
|
||||
for (i = 1; i < size; i++)
|
||||
GMQCC_MEM_WRITEHEAP(mem_look + sizeof(mem_addr) * i, mem_addr, 0);
|
||||
|
||||
GMQCC_MEM_WRITEHEAP(mem_look + sizeof(mem_addr) * size, mem_addr, sizeof(mem_addr));
|
||||
GMQCC_MEM_WRITEHEAP(sizeof(mem_addr), mem_addr, size);
|
||||
GMQCC_MEM_MARKFREE (sizeof(mem_addr) * 2);
|
||||
GMQCC_MEM_WRITEHEAP(sizeof(mem_addr) * 3, mem_addr, 0);
|
||||
GMQCC_MEM_WRITEHEAP(sizeof(mem_addr) * 4, mem_addr, 0);
|
||||
}
|
||||
|
||||
/* get needed block size */
|
||||
static size_t mem_getnbs(const size_t need) {
|
||||
size_t b = 8;
|
||||
size_t s = 1;
|
||||
|
||||
while (need > b) {
|
||||
b *= 2;
|
||||
s ++;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static void mem_removeblock(mem_addr a, size_t size) {
|
||||
mem_addr p = GMQCC_MEM_GETADDROFPS(a);
|
||||
mem_addr n = GMQCC_MEM_GETADDROFFS(a);
|
||||
|
||||
GMQCC_MEM_TRACE("flow", "(%lu, %lu)", a, size);
|
||||
|
||||
GMQCC_MEM_SETADDROFPS(a, ~((mem_addr)0));
|
||||
GMQCC_MEM_SETADDROFFS(a, ~((mem_addr)0));
|
||||
|
||||
/* handle singles in list */
|
||||
if ((p == 0) && (n == 0)) {
|
||||
GMQCC_MEM_WRITEFBA(size, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* first in list has different sibling semantics */
|
||||
if (p == 0) {
|
||||
GMQCC_MEM_WRITEFBA (size, n);
|
||||
GMQCC_MEM_SETADDROFPS(n, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* last item also has special meaning :) */
|
||||
if (n == 0) {
|
||||
GMQCC_MEM_SETADDROFFS(p, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* middle of list */
|
||||
GMQCC_MEM_SETADDROFPS(n, p);
|
||||
GMQCC_MEM_SETADDROFFS(p, n);
|
||||
}
|
||||
|
||||
static int mem_createblock(const size_t size) {
|
||||
mem_addr parent;
|
||||
int test;
|
||||
|
||||
GMQCC_MEM_TRACE("flow", "(%lu)", size);
|
||||
if (GMQCC_MEM_HASBLOCK(size))
|
||||
return 0;
|
||||
|
||||
if (size > GMQCC_MEM_READHEAP(mem_look, mem_addr))
|
||||
abort();
|
||||
|
||||
/* recrusive ... */
|
||||
test = mem_createblock(size + 1);
|
||||
if (test != 0)
|
||||
return test;
|
||||
|
||||
/* safe splits assured */
|
||||
parent = GMQCC_MEM_READFBA(size + 1);
|
||||
mem_removeblock(parent, size + 1);
|
||||
|
||||
/* split it */
|
||||
GMQCC_MEM_WRITEFBA(size, parent);
|
||||
{
|
||||
/* find center and split */
|
||||
mem_addr block = parent + 8 * ((mem_addr)1 << (size - 1));
|
||||
mem_addr left = parent;
|
||||
mem_addr right = block;
|
||||
|
||||
GMQCC_MEM_TRACE(
|
||||
"dump",
|
||||
"left: %lu right: %lu parent: %lu",
|
||||
left, right, parent
|
||||
);
|
||||
|
||||
/* left half */
|
||||
GMQCC_MEM_WRITEHEAP (left, mem_addr, size);
|
||||
GMQCC_MEM_MARKFREE (left);
|
||||
GMQCC_MEM_SETADDROFPS(left, 0);
|
||||
GMQCC_MEM_SETADDROFFS(left, right);
|
||||
/* right half */
|
||||
GMQCC_MEM_WRITEHEAP (right, mem_addr, size);
|
||||
GMQCC_MEM_MARKFREE (right);
|
||||
GMQCC_MEM_SETADDROFPS(right, left);
|
||||
GMQCC_MEM_SETADDROFFS(right, 0);
|
||||
}
|
||||
mem_dump();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static mem_addr mem_allocblock(const size_t size) {
|
||||
GMQCC_MEM_TRACE("flow", "(%lu)", size);
|
||||
int test = mem_createblock(size);
|
||||
mem_addr first;
|
||||
mem_addr next;
|
||||
|
||||
if (test != 0)
|
||||
return 0;
|
||||
|
||||
/* first free one */
|
||||
first = GMQCC_MEM_READFBA (size);
|
||||
next = GMQCC_MEM_GETADDROFFS(first);
|
||||
|
||||
mem_removeblock(first, size);
|
||||
|
||||
GMQCC_MEM_WRITEFBA(next, size);
|
||||
GMQCC_MEM_MARKUSED(first);
|
||||
|
||||
return first;
|
||||
}
|
||||
|
||||
static int mem_getside(mem_addr addr, const size_t size) {
|
||||
size_t start = addr - sizeof(mem_addr);
|
||||
size_t test = 0;
|
||||
start /= 8;
|
||||
test = ((mem_addr)1 << (size));
|
||||
|
||||
return ((start % test) == 0) ? GMQCC_MEM_BSL : GMQCC_MEM_BSR;
|
||||
}
|
||||
|
||||
static mem_addr mem_getaddr(mem_addr start, const size_t size) {
|
||||
size_t length = ((mem_addr)1 << (size - 1));
|
||||
length *= 8;
|
||||
|
||||
switch (mem_getside(start, size)) {
|
||||
case GMQCC_MEM_BSL: return start + length;
|
||||
case GMQCC_MEM_BSR: return start - length;
|
||||
}
|
||||
/* if reached blow up */
|
||||
return (abort(), 1);
|
||||
}
|
||||
|
||||
static void mem_addblock(mem_addr a, size_t s) {
|
||||
mem_addr first = GMQCC_MEM_READFBA(s);
|
||||
if (first == 0) {
|
||||
/* only block */
|
||||
GMQCC_MEM_WRITEFBA (s, a);
|
||||
GMQCC_MEM_SETADDROFPS(a, 0);
|
||||
GMQCC_MEM_SETADDROFFS(a, 0);
|
||||
} else {
|
||||
/* add to front */
|
||||
GMQCC_MEM_WRITEFBA (s, a);
|
||||
GMQCC_MEM_SETADDROFPS(a, 0);
|
||||
GMQCC_MEM_SETADDROFFS(a, first);
|
||||
GMQCC_MEM_SETADDROFPS(first, a);
|
||||
}
|
||||
}
|
||||
|
||||
void mem_init(size_t size) {
|
||||
size_t alloc = size;
|
||||
size_t count = 1;
|
||||
size_t block = 1;
|
||||
|
||||
/* blow up if too small */
|
||||
assert (sizeof(void*) == sizeof(mem_addr));
|
||||
|
||||
if (!(mem_heap = malloc(size)))
|
||||
abort();
|
||||
|
||||
memset(mem_heap, 170, size);
|
||||
mem_size = size;
|
||||
alloc -= 2 * sizeof(mem_addr);
|
||||
|
||||
while (alloc + sizeof(mem_addr) > 8 * block) {
|
||||
alloc -= sizeof(mem_addr);
|
||||
block *= 2;
|
||||
count ++;
|
||||
}
|
||||
|
||||
/* over shot ? */
|
||||
block /= 2;
|
||||
count --;
|
||||
|
||||
mem_init_table(count);
|
||||
}
|
||||
|
||||
/* doesn't get any simpler :-) */
|
||||
void mem_destroy() {
|
||||
free(mem_heap);
|
||||
mem_heap = NULL;
|
||||
}
|
||||
|
||||
void *mem_alloc(size_t amount) {
|
||||
GMQCC_MEM_TRACE("flow", "(%lu)", amount);
|
||||
size_t need = amount + 4 * sizeof(mem_addr);
|
||||
size_t size = mem_getnbs (need);
|
||||
mem_addr block = mem_allocblock(size);
|
||||
|
||||
GMQCC_MEM_TRACE("dump", "will allocate %lu size block", size);
|
||||
/* standard behaviour */
|
||||
if (block == 0)
|
||||
return NULL;
|
||||
GMQCC_MEM_TRACE("dump", "returning offset %lu", block);
|
||||
return mem_heap + block + 4 * sizeof(mem_addr);
|
||||
}
|
||||
|
||||
void mem_free(void *ptr) {
|
||||
mem_addr start = (mem_addr)(ptr - mem_heap) - 4 * sizeof(mem_addr);
|
||||
size_t size = GMQCC_MEM_READHEAP(start, mem_addr);
|
||||
mem_addr addr = mem_getaddr(start, size);
|
||||
int side = mem_getside(start, size);
|
||||
|
||||
|
||||
GMQCC_MEM_TRACE (
|
||||
"dump",
|
||||
"deallocating %s buddy (neighbour at %lu)",
|
||||
(side == GMQCC_MEM_BSL) ? "left" : "right",
|
||||
addr
|
||||
);
|
||||
GMQCC_MEM_MARKFREE(start);
|
||||
|
||||
/* while free block merge */
|
||||
while (GMQCC_MEM_BLOCKFREE(addr)) {
|
||||
GMQCC_MEM_TRACE("dump", "merging ...");
|
||||
mem_removeblock(addr, size);
|
||||
|
||||
/* find new start */
|
||||
start = addr < start ? addr : start;
|
||||
size ++;
|
||||
|
||||
if (size == GMQCC_MEM_READHEAP(mem_look, mem_addr))
|
||||
break; /* blow up */
|
||||
|
||||
addr = mem_getaddr(start, size);
|
||||
GMQCC_MEM_TRACE("dump", "new block start is %lu, buddy at %lu", start, addr);
|
||||
}
|
||||
|
||||
/* add it */
|
||||
GMQCC_MEM_WRITEBS(start, size);
|
||||
mem_addblock (start, size);
|
||||
}
|
Loading…
Reference in a new issue