From 439650f26a376543f7fca19b5d8e2e8fdfa56194 Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Sun, 12 Feb 2017 21:54:18 -0500 Subject: [PATCH] Add get and set instructions. GC is still buggy and currently crashes everything all the time. :( --- Makefile | 2 +- compile.c | 81 +++++++++++++++++++---- datatypes.h | 16 ++++- disasm.c | 8 ++- ds.h | 2 +- main.c | 8 ++- parse.c | 2 +- value.c | 142 +++++++++++++++++++++++++++++++++------- value.h | 2 +- vm.c | 184 +++++++++++++++++++++++++--------------------------- vm.h | 4 +- 11 files changed, 304 insertions(+), 147 deletions(-) diff --git a/Makefile b/Makefile index 4b5ab5bf..e9c5e9dd 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ # TIL -CFLAGS=-std=c99 -Wall -Wextra -g +CFLAGS=-std=c99 -Wall -Wextra -Wpedantic -g TARGET=interp PREFIX=/usr/local diff --git a/compile.c b/compile.c index 1bc9b9da..e6c1ddc4 100644 --- a/compile.c +++ b/compile.c @@ -87,11 +87,11 @@ static FormOptions FormOptionsDefault() { /* Create some helpers that allows us to push more than just raw bytes * to the byte buffer. This helps us create the byte code for the compiled * functions. */ -BufferDefine(UInt32, uint32_t); -BufferDefine(Int32, int32_t); -BufferDefine(Number, Number); -BufferDefine(UInt16, uint16_t); -BufferDefine(Int16, int16_t); +BufferDefine(UInt32, uint32_t) +BufferDefine(Int32, int32_t) +BufferDefine(Number, Number) +BufferDefine(UInt16, uint16_t) +BufferDefine(Int16, int16_t) /* If there is an error during compilation, * jump back to start */ @@ -553,7 +553,7 @@ static Slot CompileArray(Compiler * c, FormOptions opts, Array * array) { * called with n arguments, the number of arguments is written * after the op code, followed by those arguments. * - * This makes a few assumptions about the opertors. One, no side + * This makes a few assumptions about the operators. One, no side * effects. With this assumptions, if the result of the operator * is unused, it's calculation can be ignored (the evaluation of * its argument is still carried out, but their results can @@ -576,7 +576,7 @@ static Slot CompileOperator(Compiler * c, FormOptions opts, Array * form, if (form->count < 2) { if (op0 < 0) { if (opn < 0) CError(c, "This operator does not take 0 arguments."); - /* Use multiple form */ + /* Use multiple form of op */ BufferPushUInt16(c->vm, buffer, opn); BufferPushUInt16(c->vm, buffer, ret.index); BufferPushUInt16(c->vm, buffer, 0); @@ -587,7 +587,7 @@ static Slot CompileOperator(Compiler * c, FormOptions opts, Array * form, } else if (form->count == 2) { if (op1 < 0) { if (opn < 0) CError(c, "This operator does not take 1 argument."); - /* Use multiple form */ + /* Use multiple form of op */ BufferPushUInt16(c->vm, buffer, opn); BufferPushUInt16(c->vm, buffer, ret.index); BufferPushUInt16(c->vm, buffer, 1); @@ -642,6 +642,39 @@ static Slot CompileGreaterThanOrEqual(Compiler * c, FormOptions opts, Array * fo static Slot CompileNot(Compiler * c, FormOptions opts, Array * form) { return CompileOperator(c, opts, form, VM_OP_FLS, VM_OP_NOT, -1, -1, 0); } +static Slot CompileGet(Compiler * c, FormOptions opts, Array * form) { + return CompileOperator(c, opts, form, -1, -1, VM_OP_GET, -1, 0); +} + +/* Associative set */ +static Slot CompileSet(Compiler * c, FormOptions opts, Array * form) { + Buffer * buffer = c->buffer; + FormOptions subOpts = FormOptionsDefault(); + Slot ds, key, val; + if (form->count != 4) CError(c, "Set expects 4 arguments"); + if (opts.resultUnused) { + ds = CompilerRealizeSlot(c, CompileValue(c, subOpts, form->data[1])); + } else { + subOpts = opts; + subOpts.isTail = 0; + ds = CompilerRealizeSlot(c, CompileValue(c, subOpts, form->data[1])); + subOpts = FormOptionsDefault(); + } + key = CompilerRealizeSlot(c, CompileValue(c, subOpts, form->data[2])); + val = CompilerRealizeSlot(c, CompileValue(c, subOpts, form->data[3])); + BufferPushUInt16(c->vm, buffer, VM_OP_SET); + BufferPushUInt16(c->vm, buffer, ds.index); + BufferPushUInt16(c->vm, buffer, key.index); + BufferPushUInt16(c->vm, buffer, val.index); + CompilerDropSlot(c, c->tail, key); + CompilerDropSlot(c, c->tail, val); + if (opts.resultUnused) { + CompilerDropSlot(c, c->tail, ds); + return NilSlot(); + } else { + return ds; + } +} /* Compile an assignment operation */ static Slot CompileAssign(Compiler * c, FormOptions opts, Value left, Value right) { @@ -939,7 +972,7 @@ static Slot CompileQuote(Compiler * c, FormOptions opts, Array * form) { } /* Assignment special */ -static Slot CompileSet(Compiler * c, FormOptions opts, Array * form) { +static Slot CompileVar(Compiler * c, FormOptions opts, Array * form) { if (form->count != 3) CError(c, "Assignment expects 2 arguments"); return CompileAssign(c, opts, form->data[1], form->data[2]); @@ -968,7 +1001,6 @@ static SpecialFormHelper GetSpecial(Array * form) { case '>': return CompileGreaterThan; case '<': return CompileLessThan; case '=': return CompileEquals; - case '\'': return CompileQuote; default: break; } @@ -991,6 +1023,14 @@ static SpecialFormHelper GetSpecial(Array * form) { } } break; + case 'g': + { + if (VStringSize(name) == 3 && + name[1] == 'e' && + name[2] == 't') { + return CompileGet; + } + } case 'd': { if (VStringSize(name) == 2 && @@ -1053,6 +1093,15 @@ static SpecialFormHelper GetSpecial(Array * form) { return CompileWhile; } } + break; + case ':': + { + if (VStringSize(name) == 2 && + name[1] == '=') { + return CompileVar; + } + } + break; default: break; } @@ -1152,7 +1201,7 @@ void CompilerAddGlobalCFunc(Compiler * c, const char * name, CFunction f) { Value func; func.type = TYPE_CFUNCTION; func.data.cfunction = f; - return CompilerAddGlobal(c, name, func); + CompilerAddGlobal(c, name, func); } /* Compile interface. Returns a function that evaluates the @@ -1175,8 +1224,12 @@ Func * CompilerCompile(Compiler * c, Value form) { uint32_t envSize = c->env->count; FuncEnv * env = VMAlloc(c->vm, sizeof(FuncEnv)); Func * func = VMAlloc(c->vm, sizeof(Func)); - env->values = VMAlloc(c->vm, sizeof(Value) * envSize); - memcpy(env->values, c->env->data, envSize * sizeof(Value)); + if (envSize) { + env->values = VMAlloc(c->vm, sizeof(Value) * envSize); + memcpy(env->values, c->env->data, envSize * sizeof(Value)); + } else { + env->values = NULL; + } env->stackOffset = envSize; env->thread = NULL; func->parent = NULL; @@ -1201,7 +1254,7 @@ int CompileMacroExpand(VM * vm, Value x, Dictionary * macros, Value * out) { VMLoad(vm, macroFn); if (VMStart(vm)) { /* We encountered an error during parsing */ - return 1;; + return 1; } else { x = vm->ret; } diff --git a/datatypes.h b/datatypes.h index ca8c0cf6..b8d19613 100644 --- a/datatypes.h +++ b/datatypes.h @@ -43,6 +43,7 @@ typedef struct Parser Parser; typedef struct ParseState ParseState; typedef struct Scope Scope; typedef struct Compiler Compiler; +typedef struct StackFrame StackFrame; union ValueData { Boolean boolean; @@ -116,6 +117,15 @@ struct DictBucket { DictBucket * next; }; +struct StackFrame { + Value callee; + uint16_t size; + uint16_t prevSize; + uint16_t ret; + FuncEnv * env; + uint16_t * pc; +}; + struct VM { /* Garbage collection */ void * blocks; @@ -127,7 +137,7 @@ struct VM { uint16_t * pc; Array * thread; Value * base; - Value root; /* Global state - prevents GC cleanup */ + StackFrame * frame; /* Return state */ const char * error; jmp_buf jump; @@ -206,7 +216,7 @@ enum OpCode { VM_OP_DVM, /* 0x001f */ VM_OP_RTN, /* 0x0020 */ VM_OP_SET, /* 0x0021 */ - VM_OP_GET, /* 0x0022 */ + VM_OP_GET /* 0x0022 */ }; -#endif /* end of include guard: DATATYPES_H_PJJ035NT */ +#endif diff --git a/disasm.c b/disasm.c index 8fd3e776..67ad0d5f 100644 --- a/disasm.c +++ b/disasm.c @@ -67,7 +67,7 @@ void dasm(FILE * out, uint16_t *byteCode, uint32_t len) { uint16_t *current = byteCode; uint16_t *end = byteCode + len; - fprintf(out, "----- ASM BYTECODE AT %p -----\n", byteCode); + fprintf(out, "----- ASM BYTECODE START -----\n"); while (current < end) { switch (*current) { @@ -196,6 +196,12 @@ void dasm(FILE * out, uint16_t *byteCode, uint32_t len) { case VM_OP_RTN: current += dasmPrintFixedOp(out, current, "returnNil", 0); break; + case VM_OP_GET: + current += dasmPrintFixedOp(out, current, "get", 3); + break; + case VM_OP_SET: + current += dasmPrintFixedOp(out, current, "set", 3); + break; } fprintf(out, "\n"); } diff --git a/ds.h b/ds.h index 4c5a2e04..06257c5e 100644 --- a/ds.h +++ b/ds.h @@ -29,7 +29,7 @@ uint8_t * BufferToString(VM * vm, Buffer * buffer); #define BufferDefine(name, type) \ static void BufferPush##name (VM * vm, Buffer * buffer, type x) { \ union { type t; uint8_t bytes[sizeof(type)]; } u; \ - u.t = x; return BufferAppendData(vm, buffer, u.bytes, sizeof(type)); \ + u.t = x; BufferAppendData(vm, buffer, u.bytes, sizeof(type)); \ } /****/ diff --git a/main.c b/main.c index c2f29722..6e227506 100644 --- a/main.c +++ b/main.c @@ -37,7 +37,7 @@ void debugRepl() { for (;;) { /* Run garbage collection */ - VMMaybeCollect(&vm); +/* VMMaybeCollect(&vm);*/ /* Reset state */ ParserInit(&p, &vm); @@ -85,6 +85,11 @@ void debugRepl() { continue; } + /* Print asm */ + printf("\n"); + dasmFunc(stdout, func.data.func); + printf("\n"); + /* Execute function */ VMLoad(&vm, func); if (VMStart(&vm)) { @@ -103,4 +108,5 @@ void debugRepl() { int main() { printf("Super cool interpreter v0.0\n"); debugRepl(); + return 0; } diff --git a/parse.c b/parse.c index c34f1f12..074eb9ba 100644 --- a/parse.c +++ b/parse.c @@ -130,7 +130,7 @@ static int isWhitespace(uint8_t c) { static int isSymbolChar(uint8_t c) { if (c >= 'a' && c <= 'z') return 1; if (c >= 'A' && c <= 'Z') return 1; - if (c >= '0' && c <= '9') return 1; + if (c >= '0' && c <= ':') return 1; if (c >= '<' && c <= '@') return 1; if (c >= '*' && c <= '/') return 1; if (c >= '#' && c <= '&') return 1; diff --git a/value.c b/value.c index b9e02eac..3483dd0a 100644 --- a/value.c +++ b/value.c @@ -148,26 +148,26 @@ uint8_t * ValueToString(VM * vm, Value x) { case TYPE_NUMBER: return NumberToString(vm, x.data.number); case TYPE_ARRAY: - return StringDescription(vm, "array", 5, x.data.array); + return StringDescription(vm, "array", 5, x.data.pointer); case TYPE_FORM: - return StringDescription(vm, "form", 4, x.data.array); + return StringDescription(vm, "form", 4, x.data.pointer); case TYPE_STRING: case TYPE_SYMBOL: return x.data.string; case TYPE_BYTEBUFFER: - return StringDescription(vm, "buffer", 6, x.data.buffer); + return StringDescription(vm, "buffer", 6, x.data.pointer); case TYPE_CFUNCTION: - return StringDescription(vm, "cfunction", 9, x.data.cfunction); + return StringDescription(vm, "cfunction", 9, x.data.pointer); case TYPE_FUNCTION: - return StringDescription(vm, "function", 8, x.data.func); + return StringDescription(vm, "function", 8, x.data.pointer); case TYPE_DICTIONARY: - return StringDescription(vm, "dictionary", 10, x.data.dict); + return StringDescription(vm, "dictionary", 10, x.data.pointer); case TYPE_FUNCDEF: - return StringDescription(vm, "funcdef", 7, x.data.funcdef); + return StringDescription(vm, "funcdef", 7, x.data.pointer); case TYPE_FUNCENV: - return StringDescription(vm, "funcenv", 7, x.data.funcenv); + return StringDescription(vm, "funcenv", 7, x.data.pointer); case TYPE_THREAD: - return StringDescription(vm, "thread", 6, x.data.array); + return StringDescription(vm, "thread", 6, x.data.pointer); } return NULL; } @@ -352,23 +352,115 @@ int ValueCompare(Value x, Value y) { return 1; } -/* Get a value out af an associated data structure. Can throw VM error. */ -Value ValueGet(VM * vm, Value ds, Value key) { - switch (ds.type) { - case TYPE_ARRAY: - case TYPE_FORM: - case TYPE_BYTEBUFFER: - case TYPE_SYMBOL: - case TYPE_STRING: - case TYPE_DICTIONARY: - case TYPE_FUNCENV: - default: - VMError(vm, "Cannot get."); - break; +/* Allow negative indexing to get from end of array like structure */ +/* This probably isn't very fast - look at Lua conversion function. + * I would like to keep this standard C for as long as possible, though. */ +static int32_t ToIndex(Number raw, int64_t len) { + int32_t toInt = raw; + if ((Number) toInt == raw) { + /* We were able to convert */ + if (toInt < 0) { + /* Index from end */ + if (toInt < -len) return -1; + return len + toInt; + } else { + /* Normal indexing */ + if (toInt >= len) return -1; + return toInt; + } + } else { + return -1; } } -/* Set a value in an associative data structure. Can throw VM error. */ -int ValueSet(VM * vm, Value ds, Value key, Value value) { - +/* Convert a number into a byte. */ +static uint8_t NumberToByte(Number raw) { + if (raw > 255) return 255; + if (raw < 0) return 0; + return (uint8_t) raw; +} + +/* Get a value out af an associated data structure. Can throw VM error. */ +Value ValueGet(VM * vm, Value ds, Value key) { + int32_t index; + Value ret; + switch (ds.type) { + case TYPE_ARRAY: + case TYPE_FORM: + VMAssertType(vm, key, TYPE_NUMBER); + index = ToIndex(key.data.number, ds.data.array->count); + if (index == -1) VMError(vm, "Invalid array access"); + return ds.data.array->data[index]; + case TYPE_BYTEBUFFER: + VMAssertType(vm, key, TYPE_NUMBER); + index = ToIndex(key.data.number, ds.data.buffer->count); + if (index == -1) VMError(vm, "Invalid buffer access"); + ret.type = TYPE_NUMBER; + ret.data.number = ds.data.buffer->data[index]; + break; + case TYPE_SYMBOL: + case TYPE_STRING: + VMAssertType(vm, key, TYPE_NUMBER); + index = ToIndex(key.data.number, VStringSize(ds.data.string)); + if (index == -1) VMError(vm, "Invalid string access"); + ret.type = TYPE_NUMBER; + ret.data.number = ds.data.string[index]; + break; + case TYPE_DICTIONARY: + return DictGet(ds.data.dict, key); + case TYPE_FUNCENV: + VMAssertType(vm, key, TYPE_NUMBER); + if (ds.data.funcenv->thread) { + Array * thread = ds.data.funcenv->thread; + index = ToIndex(key.data.number, vm->frame->size); + if (index == -1) VMError(vm, "Invalid funcenv access"); + return thread->data[thread->count + index]; + } else { + index = ToIndex(key.data.number, ds.data.funcenv->stackOffset); + if (index == -1) VMError(vm, "Invalid funcenv access"); + return ds.data.funcenv->values[index]; + } + default: + VMError(vm, "Cannot get."); + } + return ret; +} + +/* Set a value in an associative data structure. Can throw VM error. */ +void ValueSet(VM * vm, Value ds, Value key, Value value) { + int32_t index; + switch (ds.type) { + case TYPE_ARRAY: + case TYPE_FORM: + VMAssertType(vm, key, TYPE_NUMBER); + index = ToIndex(key.data.number, ds.data.array->count); + if (index == -1) VMError(vm, "Invalid array access"); + ds.data.array->data[index] = value; + break; + case TYPE_BYTEBUFFER: + VMAssertType(vm, key, TYPE_NUMBER); + VMAssertType(vm, value, TYPE_NUMBER); + index = ToIndex(key.data.number, ds.data.buffer->count); + if (index == -1) VMError(vm, "Invalid buffer access"); + ds.data.buffer->data[index] = NumberToByte(value.data.number); + break; + case TYPE_DICTIONARY: + DictPut(vm, ds.data.dict, key, value); + break; + case TYPE_FUNCENV: + VMAssertType(vm, key, TYPE_NUMBER); + if (ds.data.funcenv->thread) { + Array * thread = ds.data.funcenv->thread; + index = ToIndex(key.data.number, vm->frame->size); + if (index == -1) VMError(vm, "Invalid funcenv access"); + thread->data[thread->count + index] = value; + } else { + index = ToIndex(key.data.number, ds.data.funcenv->stackOffset); + if (index == -1) VMError(vm, "Invalid funcenv access"); + ds.data.funcenv->values[index] = value; + } + break; + default: + VMError(vm, "Cannot set."); + } } diff --git a/value.h b/value.h index 22f0bf27..817984e4 100644 --- a/value.h +++ b/value.h @@ -11,7 +11,7 @@ int ValueEqual(Value x, Value y); Value ValueGet(VM * vm, Value ds, Value key); -int ValueSet(VM * vm, Value ds, Value key, Value value); +void ValueSet(VM * vm, Value ds, Value key, Value value); Value ValueLoadCString(VM * vm, const char * string); diff --git a/vm.c b/vm.c index d5e66a0b..bd9949b6 100644 --- a/vm.c +++ b/vm.c @@ -11,17 +11,6 @@ static const char EXPECTED_FUNCTION[] = "Expected function"; static const char VMS_EXPECTED_NUMBER_ROP[] = "Expected right operand to be number"; static const char VMS_EXPECTED_NUMBER_LOP[] = "Expected left operand to be number"; -/* The stack frame data */ -typedef struct StackFrame StackFrame; -struct StackFrame { - Value callee; - uint16_t size; - uint16_t prevSize; - uint16_t ret; - FuncEnv * env; - uint16_t * pc; -}; - /* The size of a StackFrame in units of Values. */ #define FRAME_SIZE ((sizeof(StackFrame) + sizeof(Value) - 1) / sizeof(Value)) @@ -37,7 +26,7 @@ static StackFrame * ThreadFrame(Array * thread) { typedef struct GCMemoryHeader GCMemoryHeader; struct GCMemoryHeader { GCMemoryHeader * next; - uint32_t color; + uint32_t color : 1; }; /* Forward declaration */ @@ -52,17 +41,43 @@ static void VMMarkFuncEnv(VM * vm, FuncEnv * env) { temp.type = TYPE_THREAD; temp.data.array = env->thread; VMMark(vm, &temp); - } else { + } else if (env->values) { uint32_t count = env->stackOffset; uint32_t i; GCHeader(env->values)->color = vm->black; - for (i = 0; i < count; ++i) { + for (i = 0; i < count; ++i) VMMark(vm, env->values + i); - } } } } +/* GC helper to mark a FuncDef */ +static void VMMarkFuncDef(VM * vm, FuncDef * def) { + if (GCHeader(def)->color != vm->black) { + GCHeader(def)->color = vm->black; + GCHeader(def->byteCode)->color = vm->black; + uint32_t count, i; + if (def->literals) { + count = def->literalsLen; + GCHeader(def->literals)->color = vm->black; + for (i = 0; i < count; ++i) + VMMark(vm, def->literals + i); + } + } +} + +/* Helper to mark a stack frame. Returns the next frame. */ +static StackFrame * VMMarkStackFrame(VM * vm, StackFrame * frame) { + uint32_t i; + Value * stack = (Value *)frame + FRAME_SIZE; + VMMark(vm, &frame->callee); + if (frame->env) + VMMarkFuncEnv(vm, frame->env); + for (i = 0; i < frame->size; ++i) + VMMark(vm, stack + i); + return (StackFrame *)(stack + frame->size); +} + /* Mark allocated memory associated with a value. This is * the main function for doing garbage collection. */ static void VMMark(VM * vm, Value * x) { @@ -97,22 +112,13 @@ static void VMMark(VM * vm, Value * x) { case TYPE_THREAD: if (GCHeader(x->data.array)->color != vm->black) { - uint32_t i; Array * thread = x->data.array; StackFrame * frame = (StackFrame *)thread->data; - StackFrame * end = (StackFrame *)(thread->data + thread->count - FRAME_SIZE); + StackFrame * end = ThreadFrame(thread); GCHeader(thread)->color = vm->black; GCHeader(thread->data)->color = vm->black; - while (frame <= end) { - Value * stack = (Value *)frame + FRAME_SIZE; - VMMark(vm, &frame->callee); - if (frame->env) - VMMarkFuncEnv(vm, frame->env); - for (i = 0; i < frame->size; ++i) { - VMMark(vm, stack + i); - } - frame = (StackFrame *)(stack + frame->size); - } + while (frame <= end) + frame = VMMarkStackFrame(vm, frame); } break; @@ -121,16 +127,12 @@ static void VMMark(VM * vm, Value * x) { Func * f = x->data.func; GCHeader(f)->color = vm->black; VMMarkFuncEnv(vm, f->env); - { + VMMarkFuncDef(vm, f->def); + if (f->parent) { Value temp; - temp.type = TYPE_FUNCDEF; - temp.data.funcdef = x->data.funcdef; + temp.type = TYPE_FUNCTION; + temp.data.func = f->parent; VMMark(vm, &temp); - if (f->parent) { - temp.type = TYPE_FUNCTION; - temp.data.func = f->parent; - VMMark(vm, &temp); - } } } break; @@ -151,16 +153,7 @@ static void VMMark(VM * vm, Value * x) { break; case TYPE_FUNCDEF: - if (GCHeader(x->data.funcdef)->color != vm->black) { - GCHeader(x->data.funcdef->byteCode)->color = vm->black; - uint32_t count, i; - count = x->data.funcdef->literalsLen; - if (x->data.funcdef->literals) { - GCHeader(x->data.funcdef->literals)->color = vm->black; - for (i = 0; i < count; ++i) - VMMark(vm, x->data.funcdef->literals + i); - } - } + VMMarkFuncDef(vm, x->data.funcdef); break; case TYPE_FUNCENV: @@ -223,14 +216,11 @@ void * VMZalloc(VM * vm, uint32_t size) { void VMCollect(VM * vm) { if (vm->lock > 0) return; /* Thread can be null */ - if (vm->thread) { - Value thread; - thread.type = TYPE_THREAD; - thread.data.array = vm->thread; - VMMark(vm, &thread); - } + Value thread; + thread.type = TYPE_THREAD; + thread.data.array = vm->thread; + VMMark(vm, &thread); VMMark(vm, &vm->ret); - VMMark(vm, &vm->root); VMSweep(vm); vm->nextCollection = 0; } @@ -259,22 +249,23 @@ static void VMThreadPush(VM * vm, Array * thread, Value callee, uint32_t size) { * the garabage collector */ for (i = nextCount; i < nextCount + size; ++i) thread->data[i].type = TYPE_NIL; - frame = ThreadFrame(thread); + vm->base = thread->data + thread->count; + vm->frame = frame = (StackFrame *)(vm->base - FRAME_SIZE); /* Set up the new stack frame */ frame->prevSize = oldSize; frame->size = size; frame->env = NULL; frame->callee = callee; - vm->base = thread->data + thread->count; } /* Copy the current function stack to the current closure environment */ -static void VMThreadSplitStack(VM * vm, Array * thread) { - StackFrame * frame = ThreadFrame(thread); +static void VMThreadSplitStack(VM * vm) { + StackFrame * frame = vm->frame; FuncEnv * env = frame->env; /* Check for closures */ if (env) { + Array * thread = vm->thread; uint32_t size = frame->size; env->thread = NULL; env->stackOffset = size; @@ -284,16 +275,18 @@ static void VMThreadSplitStack(VM * vm, Array * thread) { } /* Pop the top-most stack frame from stack */ -static void VMThreadPop(VM * vm, Array * thread) { - StackFrame * frame = ThreadFrame(thread); +static void VMThreadPop(VM * vm) { + Array * thread = vm->thread; + StackFrame * frame = vm->frame; uint32_t delta = FRAME_SIZE + frame->prevSize; if (thread->count) { - VMThreadSplitStack(vm, thread); + VMThreadSplitStack(vm); } else { VMError(vm, "Nothing to pop from stack."); } thread->count -= delta; vm->base -= delta; + vm->frame = (StackFrame *)(vm->base - FRAME_SIZE); } /* Get an upvalue */ @@ -329,28 +322,24 @@ static int truthy(Value v) { /* Return from the vm */ static void VMReturn(VM * vm, Value ret) { - Array * thread = vm->thread; - StackFrame * frame = ThreadFrame(thread); - VMThreadPop(vm, thread); - if (thread->count == 0) { + VMThreadPop(vm); + if (vm->thread->count == 0) { VMExit(vm, ret); } - frame = ThreadFrame(thread); - vm->pc = frame->pc; - vm->base[frame->ret] = ret; + vm->pc = vm->frame->pc; + vm->base[vm->frame->ret] = ret; } /* Implementation of the opcode for function calls */ static void VMCallOp(VM * vm) { Array * thread = vm->thread; - StackFrame * frame = ThreadFrame(thread); Value callee = vm->base[vm->pc[1]]; uint32_t arity = vm->pc[3]; uint32_t oldCount = thread->count; uint32_t i; Value * oldBase; - frame->pc = vm->pc + 4 + arity; - frame->ret = vm->pc[2]; + vm->frame->pc = vm->pc + 4 + arity; + vm->frame->ret = vm->pc[2]; if (callee.type == TYPE_FUNCTION) { Func * fn = callee.data.func; VMThreadPush(vm, thread, callee, fn->def->locals); @@ -375,19 +364,17 @@ static void VMCallOp(VM * vm) { vm->base[i].type = TYPE_NIL; vm->pc = f->def->byteCode; } - VMMaybeCollect(vm); } /* Implementation of the opcode for tail calls */ static void VMTailCallOp(VM * vm) { Array * thread = vm->thread; - StackFrame * frame = ThreadFrame(thread); Value callee = vm->base[vm->pc[1]]; uint32_t arity = vm->pc[2]; uint16_t newFrameSize, currentFrameSize; uint32_t i; /* Check for closures */ - VMThreadSplitStack(vm, thread); + VMThreadSplitStack(vm); if (callee.type == TYPE_CFUNCTION) { newFrameSize = arity; } else if (callee.type == TYPE_FUNCTION) { @@ -397,9 +384,8 @@ static void VMTailCallOp(VM * vm) { VMError(vm, EXPECTED_FUNCTION); } /* Ensure stack has enough space for copies of arguments */ - currentFrameSize = frame->size; + currentFrameSize = vm->frame->size; ArrayEnsure(vm, thread, thread->count + currentFrameSize + arity); - frame = ThreadFrame(thread); vm->base = thread->data + thread->count; /* Copy the arguments into the extra space */ for (i = 0; i < arity; ++i) { @@ -412,9 +398,9 @@ static void VMTailCallOp(VM * vm) { vm->base[i].type = TYPE_NIL; } /* Update the stack frame */ - frame->size = newFrameSize; - frame->callee = callee; - frame->env = NULL; + vm->frame->size = newFrameSize; + vm->frame->callee = callee; + vm->frame->env = NULL; if (callee.type == TYPE_CFUNCTION) { ++vm->lock; VMReturn(vm, callee.data.cfunction(vm)); @@ -423,27 +409,25 @@ static void VMTailCallOp(VM * vm) { Func * f = callee.data.func; vm->pc = f->def->byteCode; } - VMMaybeCollect(vm); } /* Instantiate a closure */ static Value VMMakeClosure(VM * vm, uint16_t literal) { Array * thread = vm->thread; - StackFrame * frame = ThreadFrame(thread); - if (frame->callee.type != TYPE_FUNCTION) { + if (vm->frame->callee.type != TYPE_FUNCTION) { VMError(vm, EXPECTED_FUNCTION); } else { Value constant, ret; Func * fn, * current; - FuncEnv * env = frame->env; + FuncEnv * env = vm->frame->env; if (!env) { env = VMAlloc(vm, sizeof(FuncEnv)); env->thread = thread; env->stackOffset = thread->count; env->values = NULL; - frame->env = env; + vm->frame->env = env; } - current = frame->callee.data.func; + current = vm->frame->callee.data.func; constant = LoadConstant(vm, current, literal); if (constant.type != TYPE_FUNCDEF) { VMError(vm, EXPECTED_FUNCTION); @@ -500,10 +484,10 @@ int VMStart(VM * vm) { DO_BINARY_MATH(-) case VM_OP_MUL: /* Multiplication */ - DO_BINARY_MATH(*) + DO_BINARY_MATH(*) case VM_OP_DIV: /* Division */ - DO_BINARY_MATH(/) + DO_BINARY_MATH(/) #undef DO_BINARY_MATH @@ -556,7 +540,7 @@ int VMStart(VM * vm) { break; case VM_OP_UPV: /* Load Up Value */ - temp = ThreadFrame(vm->thread)->callee; + 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; @@ -583,14 +567,14 @@ int VMStart(VM * vm) { break; case VM_OP_SUV: /* Set Up Value */ - temp = ThreadFrame(vm->thread)->callee; + 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 = ThreadFrame(vm->thread)->callee; + 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; @@ -653,7 +637,6 @@ int VMStart(VM * vm) { temp.data.array = array; vm->base[vm->pc[1]] = temp; vm->pc += 3 + arrayLen; - VMMaybeCollect(vm); } break; @@ -661,7 +644,7 @@ int VMStart(VM * vm) { { uint32_t i = 3; uint32_t kvs = vm->pc[2]; - Dictionary * dict = DictNew(vm, kvs); + Dictionary * dict = DictNew(vm, kvs + 2); kvs = kvs + 3; while (i < kvs) { v1 = vm->base[vm->pc[i++]]; @@ -672,7 +655,6 @@ int VMStart(VM * vm) { temp.data.dict = dict; vm->base[vm->pc[1]] = temp; vm->pc += kvs; - VMMaybeCollect(vm); } break; @@ -718,40 +700,48 @@ int VMStart(VM * vm) { 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; } + VMMaybeCollect(vm); } } /* Get an argument from the stack */ Value VMGetArg(VM * vm, uint16_t index) { - uint16_t frameSize = ThreadFrame(vm->thread)->size; + uint16_t frameSize = vm->frame->size; VMAssert(vm, frameSize > index, "Cannot get arg out of stack bounds"); return vm->base[index]; } /* Put a value on the stack */ void VMSetArg(VM * vm, uint16_t index, Value x) { - uint16_t frameSize = ThreadFrame(vm->thread)->size; + uint16_t frameSize = vm->frame->size; VMAssert(vm, frameSize > index, "Cannot set arg out of stack bounds"); vm->base[index] = x; } /* Get the size of the VMStack */ uint16_t VMCountArgs(VM * vm) { - return ThreadFrame(vm->thread)->size; + return vm->frame->size; } /* Initialize the VM */ void VMInit(VM * vm) { vm->ret.type = TYPE_NIL; - vm->root.type = TYPE_NIL; vm->base = NULL; + vm->frame = NULL; vm->pc = NULL; vm->error = NULL; /* Garbage collection */ @@ -760,8 +750,8 @@ void VMInit(VM * vm) { vm->memoryInterval = 0; vm->black = 0; vm->lock = 0; - /* Set to empty thread */ - vm->thread = NULL; + /* Add thread */ + vm->thread = ArrayNew(vm, 20); } /* Load a function into the VM. The function will be called with diff --git a/vm.h b/vm.h index 26a12ec1..4afab3d5 100644 --- a/vm.h +++ b/vm.h @@ -17,8 +17,8 @@ { if (!(cond)) { VMError((vm), (e)); } } while (0) /* Type assertion */ -#define VMAssertType(vm, f, type) \ - VMAssert(vm, (f).type == (type), "Expected type " type) +#define VMAssertType(vm, f, t) \ + VMAssert((vm), (f).type == (t), "Expected type,") /* Initialize the VM */ void VMInit(VM * vm);