From 42ecaf301a864b2c0874e8b698e749b1716a0c9d Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Mon, 13 Feb 2017 00:11:30 -0500 Subject: [PATCH] Remove ValuePrint. Improve ValueToString for reference types. --- main.c | 26 ++-- value.c | 86 ++--------- value.h | 2 - vm.c | 455 ++++++++++++++++++++++++++++---------------------------- 4 files changed, 256 insertions(+), 313 deletions(-) diff --git a/main.c b/main.c index f1c3d9ac..0ffd52d5 100644 --- a/main.c +++ b/main.c @@ -7,16 +7,21 @@ #include "value.h" #include "disasm.h" +void StringPut(uint8_t * string) { + uint32_t i; + uint32_t len = VStringSize(string); + for (i = 0; i < len; ++i) + fputc(string[i], stdout); +} + /* Test c function */ Value print(VM * vm) { - uint32_t i, j, count; + uint32_t j, count; Value nil; count = VMCountArgs(vm); for (j = 0; j < count; ++j) { uint8_t * string = ValueToString(vm, VMGetArg(vm, j)); - uint32_t len = VStringSize(string); - for (i = 0; i < len; ++i) - fputc(string[i], stdout); + StringPut(string); fputc('\n', stdout); } nil.type = TYPE_NIL; @@ -25,7 +30,7 @@ Value print(VM * vm) { /* A simple repl for debugging */ void debugRepl() { - char buffer[128] = {0}; + char buffer[1024] = {0}; const char * reader = buffer; Value func; VM vm; @@ -46,7 +51,7 @@ void debugRepl() { while (p.status == PARSER_PENDING) { /* Get some input if we are done */ if (*reader == '\0') { - printf("> "); + printf(">> "); if (!fgets(buffer, sizeof(buffer), stdin)) { return; } @@ -86,9 +91,9 @@ void debugRepl() { } /* Print asm */ - printf("\n"); - dasmFunc(stdout, func.data.func); - printf("\n"); + //printf("\n"); + //dasmFunc(stdout, func.data.func); + //printf("\n"); /* Execute function */ VMLoad(&vm, func); @@ -98,7 +103,8 @@ void debugRepl() { buffer[0] = 0; continue; } else { - ValuePrint(vm.ret, 0); + uint8_t * string = ValueToString(&vm, vm.ret); + StringPut(string); printf("\n"); } } diff --git a/value.c b/value.c index 3483dd0a..72a4b519 100644 --- a/value.c +++ b/value.c @@ -5,79 +5,6 @@ #include "ds.h" #include "vm.h" -/* Print the bytecode for a FuncDef */ -static void FuncDefBytecodePrint(FuncDef * def) { - uint32_t count, i; - count = def->byteCodeLen; - printf("(bytecode)["); - if (count) { - for (i = 0; i < count - 1; ++i) { - printf("%04x ", def->byteCode[i]); - } - printf("%04x", def->byteCode[i]); - } - printf("]"); -} - -/* Print a value recursively. Used for debugging */ -void ValuePrint(Value x, uint32_t indent) { - uint32_t i; - for (i = 0; i < indent; ++i) - fputc(' ', stdout); - switch (x.type) { - case TYPE_NIL: - printf(""); - break; - case TYPE_BOOLEAN: - printf(x.data.boolean ? "" : ""); - break; - case TYPE_NUMBER: - printf("%f", x.data.number); - break; - case TYPE_FORM: - case TYPE_ARRAY: - if (x.type == TYPE_ARRAY) printf(" [\n"); else printf(" (\n"); - for (i = 0; i < x.data.array->count; ++i) { - ValuePrint(x.data.array->data[i], indent + 4); - printf("\n"); - } - for (i = 0; i < indent; ++i) fputc(' ', stdout); - if (x.type == TYPE_ARRAY) printf(" ]\n"); else printf(" )\n"); - break; - case TYPE_STRING: - printf("\"%.*s\"", VStringSize(x.data.string), (char *) x.data.string); - break; - case TYPE_SYMBOL: - printf("%.*s", VStringSize(x.data.string), (char *) x.data.string); - break; - case TYPE_CFUNCTION: - printf(""); - break; - case TYPE_FUNCTION: - printf("def); - printf(">"); - break; - case TYPE_DICTIONARY: - printf(""); - break; - case TYPE_BYTEBUFFER: - printf(""); - break; - case TYPE_FUNCDEF: - printf(""); - break; - case TYPE_FUNCENV: - printf(""); - break; - case TYPE_THREAD: - printf(""); - break; - } -} - static uint8_t * LoadCString(VM * vm, const char * string, uint32_t len) { uint8_t * data = VMAlloc(vm, len + 2 * sizeof(uint32_t)); data += 2 * sizeof(uint32_t); @@ -104,12 +31,12 @@ static uint8_t * NumberToString(VM * vm, Number x) { return data; } -static const char * HEX_CHARACTERS = "0123456789ABCDEF"; +static const char * HEX_CHARACTERS = "0123456789abcdef"; #define HEX(i) (((uint8_t *) HEX_CHARACTERS)[(i)]) /* Returns a string description for a pointer */ static uint8_t * StringDescription(VM * vm, const char * title, uint32_t titlelen, void * pointer) { - uint32_t len = 3 + titlelen + sizeof(pointer) * 2; + uint32_t len = 5 + titlelen + sizeof(void *) * 2; uint32_t i; uint8_t * data = VMAlloc(vm, len + 2 * sizeof(uint32_t)); uint8_t * c; @@ -125,12 +52,17 @@ static uint8_t * StringDescription(VM * vm, const char * title, uint32_t titlele *c++ = ((uint8_t *)title) [i]; } *c++ = ' '; - for (i = 0; i < sizeof(void *); ++i) { - uint8_t byte = buf.bytes[i]; + *c++ = '0'; + *c++ = 'x'; + for (i = sizeof(void *); i > 0; --i) { + uint8_t byte = buf.bytes[i - 1]; + if (!byte) continue; *c++ = HEX(byte >> 4); *c++ = HEX(byte & 0xF); } *c++ = '>'; + VStringHash(data) = 0; + VStringSize(data) = len; return data; } diff --git a/value.h b/value.h index 817984e4..8b13b3b7 100644 --- a/value.h +++ b/value.h @@ -3,8 +3,6 @@ #include "datatypes.h" -void ValuePrint(Value x, uint32_t indent); - int ValueCompare(Value x, Value y); int ValueEqual(Value x, Value y); diff --git a/vm.c b/vm.c index 7ddb4eae..b89e9ca6 100644 --- a/vm.c +++ b/vm.c @@ -467,259 +467,262 @@ int VMStart(VM * vm) { } for (;;) { + Value temp, v1, v2; uint16_t opcode = *vm->pc; switch (opcode) { - Value temp, v1, v2; - #define DO_BINARY_MATH(op) \ - v1 = vm->base[vm->pc[2]]; \ - v2 = vm->base[vm->pc[3]]; \ - VMAssert(vm, v1.type == TYPE_NUMBER, VMS_EXPECTED_NUMBER_LOP); \ - VMAssert(vm, v2.type == TYPE_NUMBER, VMS_EXPECTED_NUMBER_ROP); \ - temp.type = TYPE_NUMBER; \ - temp.data.number = v1.data.number op v2.data.number; \ - vm->base[vm->pc[1]] = temp; \ - vm->pc += 4; \ - break; + #define DO_BINARY_MATH(op) \ + v1 = vm->base[vm->pc[2]]; \ + v2 = vm->base[vm->pc[3]]; \ + VMAssert(vm, v1.type == TYPE_NUMBER, VMS_EXPECTED_NUMBER_LOP); \ + VMAssert(vm, v2.type == TYPE_NUMBER, VMS_EXPECTED_NUMBER_ROP); \ + temp.type = TYPE_NUMBER; \ + temp.data.number = v1.data.number op v2.data.number; \ + vm->base[vm->pc[1]] = temp; \ + vm->pc += 4; \ + break; - case VM_OP_ADD: /* Addition */ - DO_BINARY_MATH(+) + case VM_OP_ADD: /* Addition */ + DO_BINARY_MATH(+) - case VM_OP_SUB: /* Subtraction */ - DO_BINARY_MATH(-) + case VM_OP_SUB: /* Subtraction */ + DO_BINARY_MATH(-) - case VM_OP_MUL: /* Multiplication */ - DO_BINARY_MATH(*) + case VM_OP_MUL: /* Multiplication */ + DO_BINARY_MATH(*) - case VM_OP_DIV: /* Division */ - DO_BINARY_MATH(/) + case VM_OP_DIV: /* Division */ + DO_BINARY_MATH(/) - #undef DO_BINARY_MATH + #undef DO_BINARY_MATH - case VM_OP_NOT: /* Boolean unary (Boolean not) */ - temp.type = TYPE_BOOLEAN; - temp.data.boolean = !truthy(vm->base[vm->pc[2]]); - vm->base[vm->pc[1]] = temp; - vm->pc += 3; - break; + case VM_OP_NOT: /* Boolean unary (Boolean not) */ + temp.type = TYPE_BOOLEAN; + temp.data.boolean = !truthy(vm->base[vm->pc[2]]); + vm->base[vm->pc[1]] = temp; + vm->pc += 3; + break; - case VM_OP_LD0: /* Load 0 */ - temp.type = TYPE_NUMBER; - temp.data.number = 0; - vm->base[vm->pc[1]] = temp; - vm->pc += 2; - break; + case VM_OP_LD0: /* Load 0 */ + temp.type = TYPE_NUMBER; + temp.data.number = 0; + vm->base[vm->pc[1]] = temp; + vm->pc += 2; + break; - case VM_OP_LD1: /* Load 1 */ - temp.type = TYPE_NUMBER; - temp.data.number = 1; - vm->base[vm->pc[1]] = temp; - vm->pc += 2; - break; + case VM_OP_LD1: /* Load 1 */ + temp.type = TYPE_NUMBER; + temp.data.number = 1; + vm->base[vm->pc[1]] = temp; + vm->pc += 2; + break; - case VM_OP_FLS: /* Load False */ - temp.type = TYPE_BOOLEAN; - temp.data.boolean = 0; - vm->base[vm->pc[1]] = temp; - vm->pc += 2; - break; + case VM_OP_FLS: /* Load False */ + temp.type = TYPE_BOOLEAN; + temp.data.boolean = 0; + vm->base[vm->pc[1]] = temp; + vm->pc += 2; + break; - case VM_OP_TRU: /* Load True */ - temp.type = TYPE_BOOLEAN; - temp.data.boolean = 1; - vm->base[vm->pc[1]] = temp; - vm->pc += 2; - break; + case VM_OP_TRU: /* Load True */ + temp.type = TYPE_BOOLEAN; + temp.data.boolean = 1; + vm->base[vm->pc[1]] = temp; + vm->pc += 2; + break; - case VM_OP_NIL: /* Load Nil */ - temp.type = TYPE_NIL; - vm->base[vm->pc[1]] = temp; - vm->pc += 2; - break; + case VM_OP_NIL: /* Load Nil */ + temp.type = TYPE_NIL; + vm->base[vm->pc[1]] = temp; + vm->pc += 2; + break; - case VM_OP_I16: /* Load Small Integer */ - temp.type = TYPE_NUMBER; - temp.data.number = ((int16_t *)(vm->pc))[2]; - vm->base[vm->pc[1]] = temp; - vm->pc += 3; - break; + case VM_OP_I16: /* Load Small Integer */ + temp.type = TYPE_NUMBER; + temp.data.number = ((int16_t *)(vm->pc))[2]; + vm->base[vm->pc[1]] = temp; + vm->pc += 3; + break; - case VM_OP_UPV: /* Load Up Value */ - temp = vm->frame->callee; - VMAssert(vm, temp.type == TYPE_FUNCTION, EXPECTED_FUNCTION); - vm->base[vm->pc[1]] = *GetUpValue(vm, temp.data.func, vm->pc[2], vm->pc[3]); + case VM_OP_UPV: /* Load Up Value */ + temp = vm->frame->callee; + VMAssert(vm, temp.type == TYPE_FUNCTION, EXPECTED_FUNCTION); + vm->base[vm->pc[1]] = *GetUpValue(vm, temp.data.func, vm->pc[2], vm->pc[3]); + vm->pc += 4; + break; + + case VM_OP_JIF: /* Jump If */ + if (truthy(vm->base[vm->pc[1]])) { vm->pc += 4; - break; - - case VM_OP_JIF: /* Jump If */ - if (truthy(vm->base[vm->pc[1]])) { - vm->pc += 4; - } else { - vm->pc += *((int32_t *)(vm->pc + 2)); - } - break; - - case VM_OP_JMP: /* Jump */ - vm->pc += *((int32_t *)(vm->pc + 1)); - break; - - case VM_OP_CAL: /* Call */ - VMCallOp(vm); - break; - - case VM_OP_RET: /* Return */ - VMReturn(vm, vm->base[vm->pc[1]]); - break; - - case VM_OP_SUV: /* Set Up Value */ - temp = vm->frame->callee; - VMAssert(vm, temp.type == TYPE_FUNCTION, EXPECTED_FUNCTION); - *GetUpValue(vm, temp.data.func, vm->pc[2], vm->pc[3]) = vm->base[vm->pc[1]]; - vm->pc += 4; - break; - - case VM_OP_CST: /* Load constant value */ - temp = vm->frame->callee; - VMAssert(vm, temp.type == TYPE_FUNCTION, EXPECTED_FUNCTION); - vm->base[vm->pc[1]] = LoadConstant(vm, temp.data.func, vm->pc[2]); - vm->pc += 3; - break; - - case VM_OP_I32: /* Load 32 bit integer */ - temp.type = TYPE_NUMBER; - temp.data.number = *((int32_t *)(vm->pc + 2)); - vm->base[vm->pc[1]] = temp; - vm->pc += 4; - break; - - case VM_OP_F64: /* Load 64 bit float */ - temp.type = TYPE_NUMBER; - temp.data.number = (Number) *((double *)(vm->pc + 2)); - vm->base[vm->pc[1]] = temp; - vm->pc += 6; - break; - - case VM_OP_MOV: /* Move Values */ - vm->base[vm->pc[1]] = vm->base[vm->pc[2]]; - vm->pc += 3; - break; - - case VM_OP_CLN: /* Create closure from constant FuncDef */ - vm->base[vm->pc[1]] = VMMakeClosure(vm, vm->pc[2]); - vm->pc += 3; - break; - - case VM_OP_EQL: /* Equality */ - temp.type = TYPE_BOOLEAN; - temp.data.boolean = ValueEqual(vm->base[vm->pc[2]], vm->base[vm->pc[3]]); - vm->base[vm->pc[1]] = temp; - vm->pc += 4; - break; - - case VM_OP_LTN: /* Less Than */ - temp.type = TYPE_BOOLEAN; - temp.data.boolean = (ValueCompare(vm->base[vm->pc[2]], vm->base[vm->pc[3]]) == -1); - vm->base[vm->pc[1]] = temp; - vm->pc += 4; - break; - - case VM_OP_LTE: /* Less Than or Equal to */ - temp.type = TYPE_BOOLEAN; - temp.data.boolean = (ValueEqual(vm->base[vm->pc[2]], vm->base[vm->pc[3]]) != 1); - vm->base[vm->pc[1]] = temp; - vm->pc += 4; - break; - - case VM_OP_ARR: /* Array literal */ - { - uint32_t i; - uint32_t arrayLen = vm->pc[2]; - Array * array = ArrayNew(vm, arrayLen); - array->count = arrayLen; - for (i = 0; i < arrayLen; ++i) - array->data[i] = vm->base[vm->pc[3 + i]]; - temp.type = TYPE_ARRAY; - temp.data.array = array; - vm->base[vm->pc[1]] = temp; - vm->pc += 3 + arrayLen; - } - break; - - case VM_OP_DIC: /* Dictionary literal */ - { - uint32_t i = 3; - uint32_t kvs = vm->pc[2]; - Dictionary * dict = DictNew(vm, kvs + 2); - kvs = kvs + 3; - while (i < kvs) { - v1 = vm->base[vm->pc[i++]]; - v2 = vm->base[vm->pc[i++]]; - DictPut(vm, dict, v1, v2); - } - temp.type = TYPE_DICTIONARY; - temp.data.dict = dict; - vm->base[vm->pc[1]] = temp; - vm->pc += kvs; - } - break; - - case VM_OP_TCL: /* Tail call */ - VMTailCallOp(vm); - break; - - /* Macro for generating some math operators */ - #define DO_MULTI_MATH(op, start) { \ - uint16_t count = vm->pc[2]; \ - uint16_t i; \ - Number accum = start; \ - for (i = 0; i < count; ++i) { \ - v1 = vm->base[vm->pc[3 + i]]; \ - VMAssert(vm, v1.type == TYPE_NUMBER, "Expected number"); \ - accum = accum op v1.data.number; \ - } \ - temp.type = TYPE_NUMBER; \ - temp.data.number = accum; \ - vm->base[vm->pc[1]] = temp; \ - vm->pc += 3 + count; \ - break; \ + } else { + vm->pc += *((int32_t *)(vm->pc + 2)); } + break; - /* Vectorized math */ - case VM_OP_ADM: - DO_MULTI_MATH(+, 0) + case VM_OP_JMP: /* Jump */ + vm->pc += *((int32_t *)(vm->pc + 1)); + break; - case VM_OP_SBM: - DO_MULTI_MATH(-, 0) + case VM_OP_CAL: /* Call */ + VMCallOp(vm); + break; - case VM_OP_MUM: - DO_MULTI_MATH(*, 1) + case VM_OP_RET: /* Return */ + VMReturn(vm, vm->base[vm->pc[1]]); + break; - case VM_OP_DVM: - DO_MULTI_MATH(/, 1) + case VM_OP_SUV: /* Set Up Value */ + temp = vm->frame->callee; + VMAssert(vm, temp.type == TYPE_FUNCTION, EXPECTED_FUNCTION); + *GetUpValue(vm, temp.data.func, vm->pc[2], vm->pc[3]) = vm->base[vm->pc[1]]; + vm->pc += 4; + break; - #undef DO_MULTI_MATH + case VM_OP_CST: /* Load constant value */ + temp = vm->frame->callee; + VMAssert(vm, temp.type == TYPE_FUNCTION, EXPECTED_FUNCTION); + vm->base[vm->pc[1]] = LoadConstant(vm, temp.data.func, vm->pc[2]); + vm->pc += 3; + break; - case VM_OP_RTN: /* Return nil */ - temp.type = TYPE_NIL; - VMReturn(vm, temp); - break; + case VM_OP_I32: /* Load 32 bit integer */ + temp.type = TYPE_NUMBER; + temp.data.number = *((int32_t *)(vm->pc + 2)); + vm->base[vm->pc[1]] = temp; + vm->pc += 4; + break; - case VM_OP_GET: - temp = ValueGet(vm, vm->base[vm->pc[2]], vm->base[vm->pc[3]]); - vm->base[vm->pc[1]] = temp; - vm->pc += 4; - break; + case VM_OP_F64: /* Load 64 bit float */ + temp.type = TYPE_NUMBER; + temp.data.number = (Number) *((double *)(vm->pc + 2)); + vm->base[vm->pc[1]] = temp; + vm->pc += 6; + break; - case VM_OP_SET: - ValueSet(vm, vm->base[vm->pc[1]], vm->base[vm->pc[2]], vm->base[vm->pc[3]]); - vm->pc += 4; - break; + case VM_OP_MOV: /* Move Values */ + vm->base[vm->pc[1]] = vm->base[vm->pc[2]]; + vm->pc += 3; + break; - default: - VMError(vm, "Unknown opcode"); - break; + case VM_OP_CLN: /* Create closure from constant FuncDef */ + vm->base[vm->pc[1]] = VMMakeClosure(vm, vm->pc[2]); + vm->pc += 3; + break; + + case VM_OP_EQL: /* Equality */ + temp.type = TYPE_BOOLEAN; + temp.data.boolean = ValueEqual(vm->base[vm->pc[2]], vm->base[vm->pc[3]]); + vm->base[vm->pc[1]] = temp; + vm->pc += 4; + break; + + case VM_OP_LTN: /* Less Than */ + temp.type = TYPE_BOOLEAN; + temp.data.boolean = (ValueCompare(vm->base[vm->pc[2]], vm->base[vm->pc[3]]) == -1); + vm->base[vm->pc[1]] = temp; + vm->pc += 4; + break; + + case VM_OP_LTE: /* Less Than or Equal to */ + temp.type = TYPE_BOOLEAN; + temp.data.boolean = (ValueEqual(vm->base[vm->pc[2]], vm->base[vm->pc[3]]) != 1); + vm->base[vm->pc[1]] = temp; + vm->pc += 4; + break; + + case VM_OP_ARR: /* Array literal */ + { + uint32_t i; + uint32_t arrayLen = vm->pc[2]; + Array * array = ArrayNew(vm, arrayLen); + array->count = arrayLen; + for (i = 0; i < arrayLen; ++i) + array->data[i] = vm->base[vm->pc[3 + i]]; + temp.type = TYPE_ARRAY; + temp.data.array = array; + vm->base[vm->pc[1]] = temp; + vm->pc += 3 + arrayLen; + } + break; + + case VM_OP_DIC: /* Dictionary literal */ + { + uint32_t i = 3; + uint32_t kvs = vm->pc[2]; + Dictionary * dict = DictNew(vm, kvs + 2); + kvs = kvs + 3; + while (i < kvs) { + v1 = vm->base[vm->pc[i++]]; + v2 = vm->base[vm->pc[i++]]; + DictPut(vm, dict, v1, v2); + } + temp.type = TYPE_DICTIONARY; + temp.data.dict = dict; + vm->base[vm->pc[1]] = temp; + vm->pc += kvs; + } + break; + + case VM_OP_TCL: /* Tail call */ + VMTailCallOp(vm); + break; + + /* Macro for generating some math operators */ + #define DO_MULTI_MATH(op, start) { \ + uint16_t count = vm->pc[2]; \ + uint16_t i; \ + Number accum = start; \ + for (i = 0; i < count; ++i) { \ + v1 = vm->base[vm->pc[3 + i]]; \ + VMAssert(vm, v1.type == TYPE_NUMBER, "Expected number"); \ + accum = accum op v1.data.number; \ + } \ + temp.type = TYPE_NUMBER; \ + temp.data.number = accum; \ + vm->base[vm->pc[1]] = temp; \ + vm->pc += 3 + count; \ + break; \ } + + /* Vectorized math */ + case VM_OP_ADM: + DO_MULTI_MATH(+, 0) + + case VM_OP_SBM: + DO_MULTI_MATH(-, 0) + + case VM_OP_MUM: + DO_MULTI_MATH(*, 1) + + case VM_OP_DVM: + DO_MULTI_MATH(/, 1) + + #undef DO_MULTI_MATH + + case VM_OP_RTN: /* Return nil */ + temp.type = TYPE_NIL; + VMReturn(vm, temp); + break; + + case VM_OP_GET: + temp = ValueGet(vm, vm->base[vm->pc[2]], vm->base[vm->pc[3]]); + vm->base[vm->pc[1]] = temp; + vm->pc += 4; + break; + + case VM_OP_SET: + ValueSet(vm, vm->base[vm->pc[1]], vm->base[vm->pc[2]], vm->base[vm->pc[3]]); + vm->pc += 4; + break; + + default: + VMError(vm, "Unknown opcode"); + break; + } + + /* Move collection only to places that allocate memory */ + /* This, however, is good for testing */ VMMaybeCollect(vm); } } @@ -753,6 +756,10 @@ void VMInit(VM * vm) { /* Garbage collection */ vm->blocks = NULL; vm->nextCollection = 0; + /* Setting memoryInterval to zero currently forces + * a collection pretty much every cycle, which is + * obviously horrible for performance. It helps ensure + * there are no memory bugs during dev */ vm->memoryInterval = 0; vm->black = 0; vm->lock = 0;