Several changes to VM and Compiler. Still WIP

and non functional.
This commit is contained in:
Calvin Rose 2017-02-12 10:27:18 -05:00
parent 9ffbdcb3e9
commit b9a9a9303c
7 changed files with 584 additions and 688 deletions

View File

@ -6,7 +6,7 @@ TARGET=interp
PREFIX=/usr/local PREFIX=/usr/local
# C sources # C sources
HEADERS=vm.h ds.h compile.h parse.h value.h disasm.h HEADERS=vm.h ds.h compile.h parse.h value.h disasm.h datatypes.h
SOURCES=main.c parse.c value.c vm.c ds.c compile.c disasm.c SOURCES=main.c parse.c value.c vm.c ds.c compile.c disasm.c
OBJECTS=$(patsubst %.c,%.o,$(SOURCES)) OBJECTS=$(patsubst %.c,%.o,$(SOURCES))

756
compile.c

File diff suppressed because it is too large Load Diff

View File

@ -60,23 +60,6 @@ union ValueData {
uint8_t u8[8]; uint8_t u8[8];
} data; } data;
/* Use an Array to represent the stack. A Stack frame is
* represented by a grouping of FRAME_SIZE values. */
#define FRAME_SIZE 4
#define ThreadStack(t) ((t)->data + (t)->count)
#define FrameMeta(t) (ThreadStack(t)[-1])
#define FrameReturn(t) ((ThreadStack(t) - 1)->data.u16[0])
#define FrameSize(t) ((ThreadStack(t) - 1)->data.u16[1])
#define FramePrevSize(t) ((ThreadStack(t) - 1)->data.u16[2])
#define FrameCallee(t) (ThreadStack(t)[-2])
#define FrameEnvValue(t) (ThreadStack(t)[-3])
#define FrameEnv(t) ((ThreadStack(t) - 3)->data.funcenv)
#define FramePCValue(t) (ThreadStack(t)[-4])
#define FramePC(t) ((ThreadStack(t)[-1]).data.pointer)
struct Array { struct Array {
uint32_t count; uint32_t count;
uint32_t capacity; uint32_t capacity;

View File

@ -41,11 +41,11 @@ static uint32_t dasmPrintVarArgOp(FILE * out, const uint16_t * current,
const char * name, uint32_t extra) { const char * name, uint32_t extra) {
uint32_t i, argCount; uint32_t i, argCount;
dasmPrintArg(out, name); dasmPrintArg(out, name);
argCount = current[1];
for (i = 0; i < extra; ++i) { for (i = 0; i < extra; ++i) {
dasmPrintSlot(out, current[i + 2]); dasmPrintSlot(out, current[i + 1]);
} }
fprintf(out, "| "); /* Argument separator */ argCount = current[extra + 1];
fprintf(out, ": "); /* Argument separator */
for (i = 0; i < argCount; ++i) { for (i = 0; i < argCount; ++i) {
dasmPrintSlot(out, current[i + extra + 2]); dasmPrintSlot(out, current[i + extra + 2]);
} }
@ -67,6 +67,8 @@ void dasm(FILE * out, uint16_t *byteCode, uint32_t len) {
uint16_t *current = byteCode; uint16_t *current = byteCode;
uint16_t *end = byteCode + len; uint16_t *end = byteCode + len;
fprintf(out, "----- ASM BYTECODE AT %p -----\n", byteCode);
while (current < end) { while (current < end) {
switch (*current) { switch (*current) {
case VM_OP_ADD: case VM_OP_ADD:
@ -197,4 +199,5 @@ void dasm(FILE * out, uint16_t *byteCode, uint32_t len) {
} }
fprintf(out, "\n"); fprintf(out, "\n");
} }
fprintf(out, "----- END ASM BYTECODE -----\n");
} }

2
ds.c
View File

@ -83,7 +83,7 @@ void ArrayEnsure(VM * vm, Array * array, uint32_t capacity) {
Value * newData; Value * newData;
if (capacity <= array->capacity) return; if (capacity <= array->capacity) return;
newData = VMAlloc(vm, capacity * sizeof(Value)); newData = VMAlloc(vm, capacity * sizeof(Value));
memcpy(newData, array->data, array->count * sizeof(Value)); memcpy(newData, array->data, array->capacity * sizeof(Value));
array->data = newData; array->data = newData;
array->capacity = capacity; array->capacity = capacity;
} }

View File

@ -192,10 +192,10 @@ int ValueEqual(Value x, Value y) {
result = 1; result = 1;
break; break;
case TYPE_BOOLEAN: case TYPE_BOOLEAN:
result = x.data.boolean == y.data.boolean; result = (x.data.boolean == y.data.boolean);
break; break;
case TYPE_NUMBER: case TYPE_NUMBER:
result = x.data.number == y.data.number; result = (x.data.number == y.data.number);
break; break;
/* Assume that when strings are created, equal strings /* Assume that when strings are created, equal strings
* are set to the same string */ * are set to the same string */
@ -227,7 +227,7 @@ int ValueEqual(Value x, Value y) {
case TYPE_FUNCENV: case TYPE_FUNCENV:
case TYPE_THREAD: case TYPE_THREAD:
/* compare pointers */ /* compare pointers */
result = x.data.array == y.data.array; result = (x.data.array == y.data.array);
break; break;
} }
} }

480
vm.c
View File

@ -5,15 +5,33 @@
#include "value.h" #include "value.h"
#include "ds.h" #include "ds.h"
#define VMArg(i) (vm->base + (i))
#define VMOpArg(i) (VMArg(vm->pc[(i)]))
static const char OOM[] = "Out of memory"; static const char OOM[] = "Out of memory";
static const char NO_UPVALUE[] = "No upvalue"; static const char NO_UPVALUE[] = "No upvalue";
static const char EXPECTED_FUNCTION[] = "Expected function"; 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_ROP[] = "Expected right operand to be number";
static const char VMS_EXPECTED_NUMBER_LOP[] = "Expected left 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. */
static size_t FRAME_SIZE() {
return ((sizeof(StackFrame) + sizeof(Value) - 1) / sizeof(Value));
}
/* Get the stack frame pointer for a thread */
static StackFrame * ThreadFrame(Array * thread) {
return (StackFrame *)(thread->data + thread->count - FRAME_SIZE());
}
/* The metadata header associated with an allocated block of memory */ /* The metadata header associated with an allocated block of memory */
#define GCHeader(mem) ((GCMemoryHeader *)(mem) - 1) #define GCHeader(mem) ((GCMemoryHeader *)(mem) - 1)
@ -81,15 +99,22 @@ static void VMMark(VM * vm, Value * x) {
case TYPE_THREAD: case TYPE_THREAD:
if (GCHeader(x->data.array)->color != vm->black) { if (GCHeader(x->data.array)->color != vm->black) {
uint32_t i, count; uint32_t i;
count = x->data.array->count; Array * thread = x->data.array;
GCHeader(x->data.array)->color = vm->black; StackFrame * frame = (StackFrame *)thread->data;
GCHeader(x->data.array->data)->color = vm->black; StackFrame * end = (StackFrame *)(thread->data + thread->count - FRAME_SIZE());
if (count) { GCHeader(thread)->color = vm->black;
count += FrameSize(x->data.array); GCHeader(thread->data)->color = vm->black;
for (i = 0; i < count; ++i) while (frame <= end) {
VMMark(vm, x->data.array->data + 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);
}
frame = (StackFrame *)(stack + frame->size);
}
} }
break; break;
@ -192,7 +217,7 @@ void * VMAlloc(VM * vm, uint32_t size) {
/* Allocate some zeroed memory that is tracked for garbage collection */ /* Allocate some zeroed memory that is tracked for garbage collection */
void * VMZalloc(VM * vm, uint32_t size) { void * VMZalloc(VM * vm, uint32_t size) {
uint32_t totalSize = size + sizeof(GCMemoryHeader); uint32_t totalSize = size + sizeof(GCMemoryHeader);
return VMAllocPrepare(vm, calloc(1, totalSize), totalSize); return VMAllocPrepare(vm, calloc(1, totalSize), totalSize);
} }
@ -219,53 +244,55 @@ void VMMaybeCollect(VM * vm) {
static void VMThreadPush(VM * vm, Array * thread, Value callee, uint32_t size) { static void VMThreadPush(VM * vm, Array * thread, Value callee, uint32_t size) {
uint16_t oldSize; uint16_t oldSize;
uint32_t nextCount, i; uint32_t nextCount, i;
StackFrame * frame;
if (thread->count) { if (thread->count) {
oldSize = FrameSize(thread); frame = ThreadFrame(thread);
nextCount = thread->count + oldSize + FRAME_SIZE; oldSize = frame->size;
} else { } else {
oldSize = 0; oldSize = 0;
nextCount = FRAME_SIZE;
} }
nextCount = thread->count + oldSize + FRAME_SIZE();
ArrayEnsure(vm, thread, nextCount + size); ArrayEnsure(vm, thread, nextCount + size);
thread->count = nextCount;
/* Ensure values start out as nil so as to not confuse /* Ensure values start out as nil so as to not confuse
* the garabage collector */ * the garabage collector */
for (i = nextCount; i < nextCount + size; ++i) { for (i = nextCount; i < nextCount + size; ++i)
thread->data[i].type = TYPE_NIL; thread->data[i].type = TYPE_NIL;
} frame = ThreadFrame(thread);
thread->count = nextCount; /* Set up the new stack frame */
FramePrevSize(thread) = oldSize; frame->prevSize = oldSize;
FrameSize(thread) = size; frame->size = size;
FrameEnvValue(thread).type = TYPE_NIL; frame->env = NULL;
FrameEnv(thread) = NULL; frame->callee = callee;
FrameCallee(thread) = callee; vm->base = thread->data + thread->count;
FrameMeta(thread).type = TYPE_NUMBER;
FramePCValue(thread).type = TYPE_NUMBER;
vm->base = ThreadStack(thread);
} }
/* Copy the current function stack to the current closure /* Copy the current function stack to the current closure
environment */ environment */
static void VMThreadSplitStack(VM * vm, Array * thread) { static void VMThreadSplitStack(VM * vm, Array * thread) {
FuncEnv * env = FrameEnv(thread); StackFrame * frame = ThreadFrame(thread);
FuncEnv * env = frame->env;
/* Check for closures */ /* Check for closures */
if (env) { if (env) {
uint32_t size = FrameSize(thread); uint32_t size = frame->size;
env->thread = NULL; env->thread = NULL;
env->stackOffset = size; env->stackOffset = size;
env->values = VMAlloc(vm, sizeof(Value) * size); env->values = VMAlloc(vm, sizeof(Value) * size);
memcpy(env->values, ThreadStack(thread), size * sizeof(Value)); memcpy(env->values, thread->data + thread->count, size * sizeof(Value));
} }
} }
/* Pop the top-most stack frame from stack */ /* Pop the top-most stack frame from stack */
static void VMThreadPop(VM * vm, Array * thread) { static void VMThreadPop(VM * vm, Array * thread) {
StackFrame * frame = ThreadFrame(thread);
uint32_t delta = FRAME_SIZE() + frame->prevSize;
if (thread->count) { if (thread->count) {
VMThreadSplitStack(vm, thread); VMThreadSplitStack(vm, thread);
thread->count -= FRAME_SIZE + FramePrevSize(thread);
} else { } else {
VMError(vm, "Nothing to pop from stack."); VMError(vm, "Nothing to pop from stack.");
} }
vm->base = ThreadStack(thread); thread->count -= delta;
vm->base -= delta;
} }
/* Get an upvalue */ /* Get an upvalue */
@ -287,22 +314,41 @@ static Value * GetUpValue(VM * vm, Func * fn, uint16_t level, uint16_t index) {
} }
/* Get a constant */ /* Get a constant */
static Value * LoadConstant(VM * vm, Func * fn, uint16_t index) { static Value LoadConstant(VM * vm, Func * fn, uint16_t index) {
if (index > fn->def->literalsLen) { if (index > fn->def->literalsLen) {
VMError(vm, NO_UPVALUE); VMError(vm, NO_UPVALUE);
} }
return fn->def->literals + index; return fn->def->literals[index];
} }
/* Truthiness definition in VM */ /* Boolean truth definition */
static int truthy(Value * v) { static int truthy(Value v) {
return v->type != TYPE_NIL && !(v->type == TYPE_BOOLEAN && !v->data.boolean); return v.type != TYPE_NIL && !(v.type == TYPE_BOOLEAN && !v.data.boolean);
} }
/* Pushes a function on the call stack. */ /* Return from the vm */
static void VMPushCallee(VM * vm, uint32_t ret, uint32_t arity, Value callee) { static void VMReturn(VM * vm, Value ret) {
Array * thread = vm->thread; Array * thread = vm->thread;
FrameReturn(thread) = ret; StackFrame * frame = ThreadFrame(thread);
VMThreadPop(vm, thread);
if (thread->count == 0) {
VMExit(vm, ret);
}
vm->pc = frame->pc;
vm->base[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];
if (callee.type == TYPE_FUNCTION) { if (callee.type == TYPE_FUNCTION) {
Func * fn = callee.data.func; Func * fn = callee.data.func;
VMThreadPush(vm, thread, callee, fn->def->locals); VMThreadPush(vm, thread, callee, fn->def->locals);
@ -310,76 +356,36 @@ static void VMPushCallee(VM * vm, uint32_t ret, uint32_t arity, Value callee) {
VMThreadPush(vm, thread, callee, arity); VMThreadPush(vm, thread, callee, arity);
} else { } else {
VMError(vm, EXPECTED_FUNCTION); VMError(vm, EXPECTED_FUNCTION);
return;
} }
/* Reset the base and frame after changing the stack */ oldBase = thread->data + oldCount;
vm->base = ThreadStack(thread);
}
/* Return from the vm */
static void VMReturn(VM * vm, Value ret) {
VMThreadPop(vm, vm->thread);
if (vm->thread->count == 0) {
VMExit(vm, ret);
}
vm->base = ThreadStack(vm->thread);
vm->pc = FramePC(vm->thread);
vm->base[FrameReturn(vm->thread)] = ret;
}
/* Implementation of the opcode for function calls */
static void VMCallOp(VM * vm) {
uint32_t ret = vm->pc[1];
uint32_t arity = vm->pc[2];
Value callee = *VMOpArg(3);
uint32_t i;
Value * argWriter;
FramePC(vm->thread) = vm->pc + 4 + arity;
VMPushCallee(vm, ret, arity, callee);
argWriter = vm->base;
if (callee.type == TYPE_CFUNCTION) { if (callee.type == TYPE_CFUNCTION) {
for (i = 0; i < arity; ++i) for (i = 0; i < arity; ++i)
*(argWriter++) = *VMOpArg(4 + i); vm->base[i] = oldBase[vm->pc[4 + i]];
++vm->lock; ++vm->lock;
VMReturn(vm, callee.data.cfunction(vm)); VMReturn(vm, callee.data.cfunction(vm));
--vm->lock; --vm->lock;
VMMaybeCollect(vm);
} else if (callee.type == TYPE_FUNCTION) {
Func * f = callee.data.func;
uint32_t extraNils = f->def->locals;
if (arity > f->def->arity) {
arity = f->def->arity;
} else if (arity < f->def->arity) {
extraNils += f->def->arity - arity;
}
for (i = 0; i < arity; ++i)
*(argWriter++) = *VMOpArg(4 + i);
for (i = 0; i < extraNils; ++i)
(argWriter++)->type = TYPE_NIL;
vm->pc = f->def->byteCode;
} else { } else {
VMError(vm, EXPECTED_FUNCTION); Func * f = callee.data.func;
uint32_t locals = f->def->locals;
for (i = 0; i < arity; ++i)
vm->base[i] = oldBase[vm->pc[4 + i]];
for (; i < locals; ++i)
vm->base[i].type = TYPE_NIL;
vm->pc = f->def->byteCode;
} }
VMMaybeCollect(vm);
} }
/* Implementation of the opcode for tail calls */ /* Implementation of the opcode for tail calls */
static void VMTailCallOp(VM * vm) { static void VMTailCallOp(VM * vm) {
uint32_t arity = vm->pc[1];
Value callee = *VMOpArg(2);
Value * extra, * argWriter;
Array * thread = vm->thread; Array * thread = vm->thread;
uint16_t newFrameSize; StackFrame * frame = ThreadFrame(thread);
Value callee = vm->base[vm->pc[1]];
uint32_t arity = vm->pc[2];
uint16_t newFrameSize, currentFrameSize;
uint32_t i; uint32_t i;
/* Check for closures */ /* Check for closures */
if (FrameEnvValue(thread).type == TYPE_FUNCENV) { VMThreadSplitStack(vm, thread);
FuncEnv * env = FrameEnv(thread);
uint16_t frameSize = FrameSize(thread);
Value * envValues = VMAlloc(vm, FrameSize(thread) * sizeof(Value));
env->values = envValues;
memcpy(envValues, vm->base, frameSize * sizeof(Value));
env->stackOffset = frameSize;
env->thread = NULL;
}
if (callee.type == TYPE_CFUNCTION) { if (callee.type == TYPE_CFUNCTION) {
newFrameSize = arity; newFrameSize = arity;
} else if (callee.type == TYPE_FUNCTION) { } else if (callee.type == TYPE_FUNCTION) {
@ -388,63 +394,65 @@ static void VMTailCallOp(VM * vm) {
} else { } else {
VMError(vm, EXPECTED_FUNCTION); VMError(vm, EXPECTED_FUNCTION);
} }
/* Ensure that stack is zeroed in this spot */ /* Ensure stack has enough space for copies of arguments */
ArrayEnsure(vm, thread, thread->count + newFrameSize + arity); currentFrameSize = frame->size;
vm->base = ThreadStack(thread); ArrayEnsure(vm, thread, thread->count + currentFrameSize + arity);
extra = argWriter = vm->base + FrameSize(thread) + FRAME_SIZE; frame = ThreadFrame(thread);
vm->base = thread->data + thread->count;
/* Copy the arguments into the extra space */
for (i = 0; i < arity; ++i) { for (i = 0; i < arity; ++i) {
*argWriter++ = *VMOpArg(3 + i); vm->base[currentFrameSize + i] = vm->base[vm->pc[3 + i]];
} }
/* Copy the end of the stack to the parameter position */ /* Copy the end of the stack to the parameter position */
memcpy(vm->base, extra, arity * sizeof(Value)); memcpy(vm->base, vm->base + currentFrameSize, arity * sizeof(Value));
/* nil the new stack for gc */ /* nil the non argument part of the stack for gc */
argWriter = vm->base + arity;
for (i = arity; i < newFrameSize; ++i) { for (i = arity; i < newFrameSize; ++i) {
(argWriter++)->type = TYPE_NIL; vm->base[i].type = TYPE_NIL;
} }
FrameSize(thread) = newFrameSize; /* Update the stack frame */
FrameCallee(thread) = callee; frame->size = newFrameSize;
frame->callee = callee;
frame->env = NULL;
if (callee.type == TYPE_CFUNCTION) { if (callee.type == TYPE_CFUNCTION) {
++vm->lock; ++vm->lock;
VMReturn(vm, callee.data.cfunction(vm)); VMReturn(vm, callee.data.cfunction(vm));
--vm->lock; --vm->lock;
VMMaybeCollect(vm);
} else { } else {
Func * f = callee.data.func; Func * f = callee.data.func;
vm->pc = f->def->byteCode; vm->pc = f->def->byteCode;
} }
VMMaybeCollect(vm);
} }
/* Instantiate a closure */ /* Instantiate a closure */
static void VMMakeClosure(VM * vm, uint16_t ret, uint16_t literal) { static Value VMMakeClosure(VM * vm, uint16_t literal) {
Value * vRet = VMArg(ret); Array * thread = vm->thread;
if (FrameCallee(vm->thread).type != TYPE_FUNCTION) { StackFrame * frame = ThreadFrame(thread);
if (frame->callee.type != TYPE_FUNCTION) {
VMError(vm, EXPECTED_FUNCTION); VMError(vm, EXPECTED_FUNCTION);
} else { } else {
Value constant, ret;
Func * fn, * current; Func * fn, * current;
Value * constant; FuncEnv * env = frame->env;
Array * thread = vm->thread;
FuncEnv * env = FrameEnv(vm->thread);
if (!env) { if (!env) {
env = VMAlloc(vm, sizeof(FuncEnv)); env = VMAlloc(vm, sizeof(FuncEnv));
env->thread = thread; env->thread = thread;
env->stackOffset = thread->count; env->stackOffset = thread->count;
env->values = NULL; env->values = NULL;
FrameEnvValue(vm->thread).data.funcenv = env; frame->env = env;
FrameEnvValue(vm->thread).type = TYPE_FUNCENV;
} }
current = FrameCallee(vm->thread).data.func; current = frame->callee.data.func;
constant = LoadConstant(vm, current, literal); constant = LoadConstant(vm, current, literal);
if (constant->type != TYPE_FUNCDEF) { if (constant.type != TYPE_FUNCDEF) {
VMError(vm, EXPECTED_FUNCTION); VMError(vm, EXPECTED_FUNCTION);
} }
fn = VMAlloc(vm, sizeof(Func)); fn = VMAlloc(vm, sizeof(Func));
fn->def = constant->data.funcdef; fn->def = constant.data.funcdef;
fn->parent = current; fn->parent = current;
fn->env = env; fn->env = env;
vRet->type = TYPE_FUNCTION; ret.type = TYPE_FUNCTION;
vRet->data.func = fn; ret.data.func = fn;
VMMaybeCollect(vm); return ret;
} }
} }
@ -470,114 +478,90 @@ int VMStart(VM * vm) {
uint16_t opcode = *vm->pc; uint16_t opcode = *vm->pc;
switch (opcode) { switch (opcode) {
Value *vRet, *v1, *v2; Value temp, v1, v2;
case VM_OP_ADD: /* Addition */ #define DO_BINARY_MATH(op) \
vRet = VMOpArg(1); v1 = vm->base[vm->pc[2]]; \
v1 = VMOpArg(2); v2 = vm->base[vm->pc[3]]; \
v2 = VMOpArg(3); VMAssert(vm, v1.type == TYPE_NUMBER, VMS_EXPECTED_NUMBER_LOP); \
VMAssert(vm, v1->type == TYPE_NUMBER, VMS_EXPECTED_NUMBER_LOP); VMAssert(vm, v2.type == TYPE_NUMBER, VMS_EXPECTED_NUMBER_ROP); \
VMAssert(vm, v2->type == TYPE_NUMBER, VMS_EXPECTED_NUMBER_ROP); temp.type = TYPE_NUMBER; \
vRet->type = TYPE_NUMBER; temp.data.number = v1.data.number op v2.data.number; \
vRet->data.number = v1->data.number + v2->data.number; vm->base[vm->pc[1]] = temp; \
vm->pc += 4; vm->pc += 4; \
break; break;
case VM_OP_ADD: /* Addition */
DO_BINARY_MATH(+)
case VM_OP_SUB: /* Subtraction */ case VM_OP_SUB: /* Subtraction */
vRet = VMOpArg(1); DO_BINARY_MATH(-)
v1 = VMOpArg(2);
v2 = VMOpArg(3);
VMAssert(vm, v1->type == TYPE_NUMBER, VMS_EXPECTED_NUMBER_LOP);
VMAssert(vm, v2->type == TYPE_NUMBER, VMS_EXPECTED_NUMBER_ROP);
vRet->type = TYPE_NUMBER;
vRet->data.number = v1->data.number - v2->data.number;
vm->pc += 4;
break;
case VM_OP_MUL: /* Multiplication */ case VM_OP_MUL: /* Multiplication */
vRet = VMOpArg(1); DO_BINARY_MATH(*)
v1 = VMOpArg(2);
v2 = VMOpArg(3);
VMAssert(vm, v1->type == TYPE_NUMBER, VMS_EXPECTED_NUMBER_LOP);
VMAssert(vm, v2->type == TYPE_NUMBER, VMS_EXPECTED_NUMBER_ROP);
vRet->type = TYPE_NUMBER;
vRet->data.number = v1->data.number * v2->data.number;
vm->pc += 4;
break;
case VM_OP_DIV: /* Division */ case VM_OP_DIV: /* Division */
vRet = VMOpArg(1); DO_BINARY_MATH(/)
v1 = VMOpArg(2);
v2 = VMOpArg(3);
VMAssert(vm, v1->type == TYPE_NUMBER, VMS_EXPECTED_NUMBER_LOP);
VMAssert(vm, v2->type == TYPE_NUMBER, VMS_EXPECTED_NUMBER_ROP);
vRet->type = TYPE_NUMBER;
vRet->data.number = v1->data.number / v2->data.number;
vm->pc += 4;
break;
case VM_OP_NOT: /* Boolean unary (Boolean not) */ #undef DO_BINARY_MATH
vRet = VMOpArg(1);
v1 = VMOpArg(2); 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; vm->pc += 3;
vRet->type = TYPE_BOOLEAN;
vRet->data.boolean = !truthy(v1);
break; break;
case VM_OP_LD0: /* Load 0 */ case VM_OP_LD0: /* Load 0 */
vRet = VMOpArg(1); temp.type = TYPE_NUMBER;
vRet->type = TYPE_NUMBER; temp.data.number = 0;
vRet->data.number = 0; vm->base[vm->pc[1]] = temp;
vm->pc += 2; vm->pc += 2;
break; break;
case VM_OP_LD1: /* Load 1 */ case VM_OP_LD1: /* Load 1 */
vRet = VMOpArg(1); temp.type = TYPE_NUMBER;
vRet->type = TYPE_NUMBER; temp.data.number = 1;
vRet->data.number = 1; vm->base[vm->pc[1]] = temp;
vm->pc += 2; vm->pc += 2;
break; break;
case VM_OP_FLS: /* Load False */ case VM_OP_FLS: /* Load False */
vRet = VMOpArg(1); temp.type = TYPE_BOOLEAN;
vRet->type = TYPE_BOOLEAN; temp.data.boolean = 0;
vRet->data.boolean = 0; vm->base[vm->pc[1]] = temp;
vm->pc += 2; vm->pc += 2;
break; break;
case VM_OP_TRU: /* Load True */ case VM_OP_TRU: /* Load True */
vRet = VMOpArg(1); temp.type = TYPE_BOOLEAN;
vRet->type = TYPE_BOOLEAN; temp.data.boolean = 1;
vRet->data.boolean = 1; vm->base[vm->pc[1]] = temp;
vm->pc += 2; vm->pc += 2;
break; break;
case VM_OP_NIL: /* Load Nil */ case VM_OP_NIL: /* Load Nil */
vRet = VMOpArg(1); temp.type = TYPE_NIL;
vRet->type = TYPE_NIL; vm->base[vm->pc[1]] = temp;
vm->pc += 2; vm->pc += 2;
break; break;
case VM_OP_I16: /* Load Small Integer */ case VM_OP_I16: /* Load Small Integer */
vRet = VMOpArg(1); temp.type = TYPE_NUMBER;
vRet->type = TYPE_NUMBER; temp.data.number = ((int16_t *)(vm->pc))[2];
vRet->data.number = ((int16_t *)(vm->pc))[2]; vm->base[vm->pc[1]] = temp;
vm->pc += 3; vm->pc += 3;
break; break;
case VM_OP_UPV: /* Load Up Value */ case VM_OP_UPV: /* Load Up Value */
{ temp = ThreadFrame(vm->thread)->callee;
Value callee; VMAssert(vm, temp.type == TYPE_FUNCTION, EXPECTED_FUNCTION);
callee = FrameCallee(vm->thread); vm->base[vm->pc[1]] = *GetUpValue(vm, temp.data.func, vm->pc[2], vm->pc[3]);
VMAssert(vm, callee.type == TYPE_FUNCTION, EXPECTED_FUNCTION); vm->pc += 4;
vRet = VMOpArg(1);
*vRet = *GetUpValue(vm, callee.data.func, vm->pc[2], vm->pc[3]);
vm->pc += 4;
}
break; break;
case VM_OP_JIF: /* Jump If */ case VM_OP_JIF: /* Jump If */
if (truthy(VMOpArg(1))) { if (truthy(vm->base[vm->pc[1]])) {
vm->pc += 4; vm->pc += 4;
} else { } else {
vm->pc += *((int32_t *)(vm->pc + 2)); vm->pc += *((int32_t *)(vm->pc + 2));
@ -593,104 +577,98 @@ int VMStart(VM * vm) {
break; break;
case VM_OP_RET: /* Return */ case VM_OP_RET: /* Return */
VMReturn(vm, *VMOpArg(1)); VMReturn(vm, vm->base[vm->pc[1]]);
break; break;
case VM_OP_SUV: /* Set Up Value */ case VM_OP_SUV: /* Set Up Value */
VMAssert(vm, FrameCallee(vm->thread).type == TYPE_FUNCTION, EXPECTED_FUNCTION); temp = ThreadFrame(vm->thread)->callee;
vRet = VMOpArg(1); VMAssert(vm, temp.type == TYPE_FUNCTION, EXPECTED_FUNCTION);
*GetUpValue(vm, FrameCallee(vm->thread).data.func, vm->pc[2], vm->pc[3]) = *vRet; *GetUpValue(vm, temp.data.func, vm->pc[2], vm->pc[3]) = vm->base[vm->pc[1]];
vm->pc += 4; vm->pc += 4;
break; break;
case VM_OP_CST: /* Load constant value */ case VM_OP_CST: /* Load constant value */
VMAssert(vm, FrameCallee(vm->thread).type == TYPE_FUNCTION, EXPECTED_FUNCTION); temp = ThreadFrame(vm->thread)->callee;
vRet = VMOpArg(1); VMAssert(vm, temp.type == TYPE_FUNCTION, EXPECTED_FUNCTION);
*vRet = *LoadConstant(vm, FrameCallee(vm->thread).data.func, vm->pc[2]); vm->base[vm->pc[1]] = LoadConstant(vm, temp.data.func, vm->pc[2]);
vm->pc += 3; vm->pc += 3;
break; break;
case VM_OP_I32: /* Load 32 bit integer */ case VM_OP_I32: /* Load 32 bit integer */
vRet = VMOpArg(1); temp.type = TYPE_NUMBER;
vRet->type = TYPE_NUMBER; temp.data.number = *((int32_t *)(vm->pc + 2));
vRet->data.number = *((int32_t *)(vm->pc + 2)); vm->base[vm->pc[1]] = temp;
vm->pc += 4; vm->pc += 4;
break; break;
case VM_OP_F64: /* Load 64 bit float */ case VM_OP_F64: /* Load 64 bit float */
vRet = VMOpArg(1); temp.type = TYPE_NUMBER;
vRet->type = TYPE_NUMBER; temp.data.number = (Number) *((double *)(vm->pc + 2));
vRet->data.number = (Number) *((double *)(vm->pc + 2)); vm->base[vm->pc[1]] = temp;
vm->pc += 6; vm->pc += 6;
break; break;
case VM_OP_MOV: /* Move Values */ case VM_OP_MOV: /* Move Values */
vRet = VMOpArg(1); vm->base[vm->pc[1]] = vm->base[vm->pc[2]];
v1 = vm->base + *((uint32_t *)(vm->pc + 2)); vm->pc += 3;
*vRet = *v1;
vm->pc += 4;
break; break;
case VM_OP_CLN: /* Create closure from constant FuncDef */ case VM_OP_CLN: /* Create closure from constant FuncDef */
VMMakeClosure(vm, vm->pc[1], vm->pc[2]); vm->base[vm->pc[1]] = VMMakeClosure(vm, vm->pc[2]);
vm->pc += 3; vm->pc += 3;
break; break;
case VM_OP_EQL: /* Equality */ case VM_OP_EQL: /* Equality */
vRet = VMOpArg(1); temp.type = TYPE_BOOLEAN;
vRet->type = TYPE_BOOLEAN; temp.data.boolean = ValueEqual(vm->base[vm->pc[2]], vm->base[vm->pc[3]]);
vRet->data.boolean = ValueEqual(*VMOpArg(2), *VMOpArg(3)); vm->base[vm->pc[1]] = temp;
vm->pc += 4; vm->pc += 4;
break; break;
case VM_OP_LTN: /* Less Than */ case VM_OP_LTN: /* Less Than */
vRet = VMOpArg(1); temp.type = TYPE_BOOLEAN;
v1 = VMOpArg(2); temp.data.boolean = (ValueCompare(vm->base[vm->pc[2]], vm->base[vm->pc[3]]) == -1);
v2 = VMOpArg(3); vm->base[vm->pc[1]] = temp;
vRet->type = TYPE_BOOLEAN;
vRet->data.boolean = (ValueCompare(*VMOpArg(2), *VMOpArg(3)) == -1);
vm->pc += 4; vm->pc += 4;
break; break;
case VM_OP_LTE: /* Less Than or Equal to */ case VM_OP_LTE: /* Less Than or Equal to */
vRet = VMOpArg(1); temp.type = TYPE_BOOLEAN;
v1 = VMOpArg(2); temp.data.boolean = (ValueEqual(vm->base[vm->pc[2]], vm->base[vm->pc[3]]) != 1);
v2 = VMOpArg(3); vm->base[vm->pc[1]] = temp;
vRet->type = TYPE_BOOLEAN;
vRet->data.boolean = (ValueCompare(*VMOpArg(2), *VMOpArg(3)) != 1);
vm->pc += 4; vm->pc += 4;
break; break;
case VM_OP_ARR: /* Array literal */ case VM_OP_ARR: /* Array literal */
vRet = VMOpArg(1);
{ {
uint32_t i; uint32_t i;
uint32_t arrayLen = vm->pc[2]; uint32_t arrayLen = vm->pc[2];
Array * array = ArrayNew(vm, arrayLen); Array * array = ArrayNew(vm, arrayLen);
array->count = arrayLen; array->count = arrayLen;
for (i = 0; i < arrayLen; ++i) for (i = 0; i < arrayLen; ++i)
array->data[i] = *VMOpArg(3 + i); array->data[i] = vm->base[vm->pc[3 + i]];
vRet->type = TYPE_ARRAY; temp.type = TYPE_ARRAY;
vRet->data.array = array; temp.data.array = array;
vm->base[vm->pc[1]] = temp;
vm->pc += 3 + arrayLen; vm->pc += 3 + arrayLen;
VMMaybeCollect(vm); VMMaybeCollect(vm);
} }
break; break;
case VM_OP_DIC: /* Dictionary literal */ case VM_OP_DIC: /* Dictionary literal */
vRet = VMOpArg(1);
{ {
uint32_t i = 3; uint32_t i = 3;
uint32_t kvs = vm->pc[2]; uint32_t kvs = vm->pc[2];
Dictionary * dict = DictNew(vm, kvs); Dictionary * dict = DictNew(vm, kvs);
kvs = kvs + 3; kvs = kvs + 3;
while (i < kvs) { while (i < kvs) {
v1 = VMOpArg(i++); v1 = vm->base[vm->pc[i++]];
v2 = VMOpArg(i++); v2 = vm->base[vm->pc[i++]];
DictPut(vm, dict, *v1, *v2); DictPut(vm, dict, v1, v2);
} }
vRet->type = TYPE_DICTIONARY; temp.type = TYPE_DICTIONARY;
vRet->data.dict = dict; temp.data.dict = dict;
vm->base[vm->pc[1]] = temp;
vm->pc += kvs; vm->pc += kvs;
VMMaybeCollect(vm); VMMaybeCollect(vm);
} }
@ -702,44 +680,39 @@ int VMStart(VM * vm) {
/* Macro for generating some math operators */ /* Macro for generating some math operators */
#define DO_MULTI_MATH(op, start) { \ #define DO_MULTI_MATH(op, start) { \
uint16_t count = vm->pc[2]; \
uint16_t i; \ uint16_t i; \
uint16_t count = vm->pc[1]; \
Number accum = start; \ Number accum = start; \
vRet = VMOpArg(2); \
for (i = 0; i < count; ++i) { \ for (i = 0; i < count; ++i) { \
Value * x = VMOpArg(3 + i); \ v1 = vm->base[vm->pc[3 + i]]; \
VMAssert(vm, x->type == TYPE_NUMBER, "Expected number"); \ VMAssert(vm, v1.type == TYPE_NUMBER, "Expected number"); \
accum = accum op x->data.number; \ accum = accum op v1.data.number; \
} \ } \
vRet->type = TYPE_NUMBER; vRet->data.number = accum; \ temp.type = TYPE_NUMBER; \
temp.data.number = accum; \
vm->base[vm->pc[1]] = temp; \
vm->pc += 3 + count; \ vm->pc += 3 + count; \
break; \
} }
/* Vectorized math */ /* Vectorized math */
case VM_OP_ADM: case VM_OP_ADM:
DO_MULTI_MATH(+, 0) DO_MULTI_MATH(+, 0)
break;
case VM_OP_SBM: case VM_OP_SBM:
DO_MULTI_MATH(-, 0) DO_MULTI_MATH(-, 0)
break;
case VM_OP_MUM: case VM_OP_MUM:
DO_MULTI_MATH(*, 1) DO_MULTI_MATH(*, 1)
break;
case VM_OP_DVM: case VM_OP_DVM:
DO_MULTI_MATH(/, 1) DO_MULTI_MATH(/, 1)
break;
#undef DO_MULTI_MATH #undef DO_MULTI_MATH
case VM_OP_RTN: /* Return nil */ case VM_OP_RTN: /* Return nil */
{ temp.type = TYPE_NIL;
Value temp; VMReturn(vm, temp);
temp.type = TYPE_NIL;
VMReturn(vm, temp);
}
break; break;
default: default:
@ -751,26 +724,23 @@ int VMStart(VM * vm) {
/* Get an argument from the stack */ /* Get an argument from the stack */
Value VMGetArg(VM * vm, uint16_t index) { Value VMGetArg(VM * vm, uint16_t index) {
uint16_t frameSize = FrameSize(vm->thread); uint16_t frameSize = ThreadFrame(vm->thread)->size;
VMAssert(vm, frameSize > index, "Cannot get arg out of stack bounds"); VMAssert(vm, frameSize > index, "Cannot get arg out of stack bounds");
return *VMArg(index); return vm->base[index];
} }
/* Put a value on the stack */ /* Put a value on the stack */
void VMSetArg(VM * vm, uint16_t index, Value x) { void VMSetArg(VM * vm, uint16_t index, Value x) {
uint16_t frameSize = FrameSize(vm->thread); uint16_t frameSize = ThreadFrame(vm->thread)->size;
VMAssert(vm, frameSize > index, "Cannot set arg out of stack bounds"); VMAssert(vm, frameSize > index, "Cannot set arg out of stack bounds");
*VMArg(index) = x; vm->base[index] = x;
} }
/* Get the size of the VMStack */ /* Get the size of the VMStack */
uint16_t VMCountArgs(VM * vm) { uint16_t VMCountArgs(VM * vm) {
return FrameSize(vm->thread); return ThreadFrame(vm->thread)->size;
} }
#undef VMOpArg
#undef VMArg
/* Initialize the VM */ /* Initialize the VM */
void VMInit(VM * vm) { void VMInit(VM * vm) {
vm->tempRoot.type = TYPE_NIL; vm->tempRoot.type = TYPE_NIL;
@ -793,7 +763,7 @@ void VMLoad(VM * vm, Func * func) {
Value callee; Value callee;
callee.type = TYPE_FUNCTION; callee.type = TYPE_FUNCTION;
callee.data.func = func; callee.data.func = func;
vm->thread = ArrayNew(vm, 20); vm->thread = ArrayNew(vm, 100);
VMThreadPush(vm, vm->thread, callee, func->def->locals); VMThreadPush(vm, vm->thread, callee, func->def->locals);
vm->pc = func->def->byteCode; vm->pc = func->def->byteCode;
} }