X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=exec.c;h=e2bcc5245b75adcc4f0249c3fc6f83f391c4e1b6;hb=61605636d16e5caa626e6485ed1610543f1be331;hp=63d0e17773a8d5a0e1fd8a8822c372cb95414829;hpb=f8b3081c44fa51860bb56f7d13b3b730717e9e3b;p=xonotic%2Fgmqcc.git diff --git a/exec.c b/exec.c index 63d0e17..e2bcc52 100644 --- a/exec.c +++ b/exec.c @@ -1,4 +1,5 @@ #include +#include #include #include @@ -9,18 +10,21 @@ MEM_VEC_FUNCTIONS(qc_program, prog_section_def, defs) MEM_VEC_FUNCTIONS(qc_program, prog_section_def, fields) MEM_VEC_FUNCTIONS(qc_program, prog_section_function, functions) MEM_VEC_FUNCTIONS(qc_program, char, strings) -_MEM_VEC_FUN_APPEND(qc_program, char, strings) -_MEM_VEC_FUN_RESIZE(qc_program, char, strings) +MEM_VEC_FUN_APPEND(qc_program, char, strings) +MEM_VEC_FUN_RESIZE(qc_program, char, strings) MEM_VEC_FUNCTIONS(qc_program, qcint, globals) MEM_VEC_FUNCTIONS(qc_program, qcint, entitydata) +MEM_VEC_FUNCTIONS(qc_program, bool, entitypool) MEM_VEC_FUNCTIONS(qc_program, qcint, localstack) -_MEM_VEC_FUN_APPEND(qc_program, qcint, localstack) -_MEM_VEC_FUN_RESIZE(qc_program, qcint, localstack) +MEM_VEC_FUN_APPEND(qc_program, qcint, localstack) +MEM_VEC_FUN_RESIZE(qc_program, qcint, localstack) MEM_VEC_FUNCTIONS(qc_program, qc_exec_stack, stack) MEM_VEC_FUNCTIONS(qc_program, size_t, profile) -_MEM_VEC_FUN_RESIZE(qc_program, size_t, profile) +MEM_VEC_FUN_RESIZE(qc_program, size_t, profile) + +MEM_VEC_FUNCTIONS(qc_program, prog_builtin, builtins) static void loaderror(const char *fmt, ...) { @@ -32,10 +36,23 @@ static void loaderror(const char *fmt, ...) printf(": %s\n", strerror(err)); } +static void qcvmerror(qc_program *prog, const char *fmt, ...) +{ + va_list ap; + + prog->vmerror++; + + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + putchar('\n'); +} + qc_program* prog_load(const char *filename) { qc_program *prog; prog_header header; + size_t i; FILE *file; file = fopen(filename, "rb"); @@ -106,6 +123,19 @@ qc_program* prog_load(const char *filename) if (!qc_program_strings_resize(prog, prog->strings_count + 16*1024)) goto error; + /* spawn the world entity */ + if (!qc_program_entitypool_add(prog, true)) { + loaderror("failed to allocate world entity\n"); + goto error; + } + for (i = 0; i < prog->entityfields; ++i) { + if (!qc_program_entitydata_add(prog, 0)) { + loaderror("failed to allocate world data\n"); + goto error; + } + } + prog->entities = 1; + return prog; error: @@ -117,6 +147,7 @@ error: if (prog->strings) mem_d(prog->strings); if (prog->globals) mem_d(prog->globals); if (prog->entitydata) mem_d(prog->entitydata); + if (prog->entitypool) mem_d(prog->entitypool); mem_d(prog); return NULL; } @@ -131,9 +162,15 @@ void prog_delete(qc_program *prog) MEM_VECTOR_CLEAR(prog, strings); MEM_VECTOR_CLEAR(prog, globals); MEM_VECTOR_CLEAR(prog, entitydata); + MEM_VECTOR_CLEAR(prog, entitypool); MEM_VECTOR_CLEAR(prog, localstack); MEM_VECTOR_CLEAR(prog, stack); MEM_VECTOR_CLEAR(prog, profile); + + if (prog->builtins_alloc) { + MEM_VECTOR_CLEAR(prog, builtins); + } + /* otherwise the builtins were statically allocated */ mem_d(prog); } @@ -170,7 +207,58 @@ prog_section_def* prog_getdef(qc_program *prog, qcint off) qcany* prog_getedict(qc_program *prog, qcint e) { - return (qcany*)(prog->entitydata + (prog->entityfields + e)); + if (e >= prog->entitypool_count) { + prog->vmerror++; + printf("Accessing out of bounds edict %i\n", (int)e); + e = 0; + } + return (qcany*)(prog->entitydata + (prog->entityfields * e)); +} + +qcint prog_spawn_entity(qc_program *prog) +{ + size_t i; + qcint e; + for (e = 0; e < (qcint)prog->entitypool_count; ++e) { + if (!prog->entitypool[e]) { + char *data = (char*)(prog->entitydata + (prog->entityfields * e)); + memset(data, 0, prog->entityfields * sizeof(qcint)); + return e; + } + } + if (!qc_program_entitypool_add(prog, true)) { + prog->vmerror++; + printf("Failed to allocate entity\n"); + return 0; + } + prog->entities++; + for (i = 0; i < prog->entityfields; ++i) { + if (!qc_program_entitydata_add(prog, 0)) { + printf("Failed to allocate entity\n"); + return 0; + } + } + return e; +} + +void prog_free_entity(qc_program *prog, qcint e) +{ + if (!e) { + prog->vmerror++; + printf("Trying to free world entity\n"); + return; + } + if (e >= prog->entitypool_count) { + prog->vmerror++; + printf("Trying to free out of bounds entity\n"); + return; + } + if (!prog->entitypool[e]) { + prog->vmerror++; + printf("Double free on entity\n"); + return; + } + prog->entitypool[e] = false; } qcint prog_tempstring(qc_program *prog, const char *_str) @@ -204,6 +292,32 @@ qcint prog_tempstring(qc_program *prog, const char *_str) return at; } +static int print_escaped_string(const char *str) +{ + int len = 2; + putchar('"'); + while (*str) { + switch (*str) { + case '\a': len += 2; putchar('\\'); putchar('a'); break; + case '\b': len += 2; putchar('\\'); putchar('b'); break; + case '\r': len += 2; putchar('\\'); putchar('r'); break; + case '\n': len += 2; putchar('\\'); putchar('n'); break; + case '\t': len += 2; putchar('\\'); putchar('t'); break; + case '\f': len += 2; putchar('\\'); putchar('f'); break; + case '\v': len += 2; putchar('\\'); putchar('v'); break; + case '\\': len += 2; putchar('\\'); putchar('\\'); break; + case '"': len += 2; putchar('\\'); putchar('"'); break; + default: + ++len; + putchar(*str); + break; + } + ++str; + } + putchar('"'); + return len; +} + static void trace_print_global(qc_program *prog, unsigned int glob, int vtype) { static char spaces[16+1] = " "; @@ -222,7 +336,7 @@ static void trace_print_global(qc_program *prog, unsigned int glob, int vtype) vtype = def->type; } else - len = printf("[#%u] ", glob); + len = printf("[@%u] ", glob); switch (vtype) { case TYPE_VOID: @@ -238,7 +352,8 @@ static void trace_print_global(qc_program *prog, unsigned int glob, int vtype) value->vector[2]); break; case TYPE_STRING: - len += printf("\"%s\",", prog_getstring(prog, value->string)); + len += print_escaped_string(prog_getstring(prog, value->string)); + /* len += printf("\"%s\",", prog_getstring(prog, value->string)); */ break; case TYPE_FLOAT: default: @@ -258,7 +373,7 @@ static void prog_print_statement(qc_program *prog, prog_section_statement *st) printf("\n", st->opcode); return; } - printf("%-12s", asm_instr[st->opcode].m); + printf(" <> %-12s", asm_instr[st->opcode].m); if (st->opcode >= INSTR_IF && st->opcode <= INSTR_IFNOT) { @@ -405,6 +520,8 @@ bool prog_exec(qc_program *prog, prog_section_function *func, size_t flags, long long jumpcount = 0; prog_section_statement *st; + prog->vmerror = 0; + st = prog->code + prog_enterfunction(prog, func); --st; switch (flags) @@ -443,6 +560,8 @@ bool prog_exec(qc_program *prog, prog_section_function *func, size_t flags, long cleanup: prog->localstack_count = 0; prog->stack_count = 0; + if (prog->vmerror) + return false; return true; } @@ -451,6 +570,72 @@ cleanup: */ #if defined(QCVM_EXECUTOR) +bool opts_debug = false; +bool opts_memchk = false; + +#define CheckArgs(num) do { \ + if (prog->argc != (num)) { \ + prog->vmerror++; \ + printf("ERROR: invalid number of arguments for %s: %i, expected %i\n", \ + __FUNCTION__, prog->argc, (num)); \ + return -1; \ + } \ +} while (0) + +#define GetGlobal(idx) ((qcany*)(prog->globals + (idx))) +#define GetArg(num) GetGlobal(OFS_PARM0 + 3*(num)) +#define Return(any) *(GetGlobal(OFS_RETURN)) = (any) + +static int qc_print(qc_program *prog) +{ + size_t i; + for (i = 0; i < prog->argc; ++i) { + qcany *str = (qcany*)(prog->globals + OFS_PARM0 + 3*i); + printf("%s", prog_getstring(prog, str->string)); + } + return 0; +} + +static int qc_ftos(qc_program *prog) +{ + char buffer[512]; + qcany *num; + qcany str; + CheckArgs(1); + num = GetArg(0); + snprintf(buffer, sizeof(buffer), "%g", num->_float); + str.string = prog_tempstring(prog, buffer); + Return(str); + return 0; +} + +static int qc_spawn(qc_program *prog) +{ + qcany ent; + CheckArgs(0); + ent.edict = prog_spawn_entity(prog); + Return(ent); + return (ent.edict ? 0 : -1); +} + +static int qc_kill(qc_program *prog) +{ + qcany *ent; + CheckArgs(1); + ent = GetArg(0); + prog_free_entity(prog, ent->edict); + return 0; +} + +static prog_builtin qc_builtins[] = { + NULL, + &qc_print, + &qc_ftos, + &qc_spawn, + &qc_kill +}; +static size_t qc_builtins_count = sizeof(qc_builtins) / sizeof(qc_builtins[0]); + int main(int argc, char **argv) { size_t i; @@ -468,12 +653,17 @@ int main(int argc, char **argv) exit(1); } + prog->builtins = qc_builtins; + prog->builtins_count = qc_builtins_count; + prog->builtins_alloc = 0; + for (i = 1; i < prog->functions_count; ++i) { const char *name = prog_getstring(prog, prog->functions[i].name); printf("Found function: %s\n", name); if (!strcmp(name, "main")) fnmain = (qcint)i; } + printf("Entity field space: %i\n", (int)prog->entityfields); if (fnmain > 0) { prog_exec(prog, &prog->functions[fnmain], VMXF_TRACE, VM_JUMPS_DEFAULT);