Add get and set instructions. GC is still buggy and currently

crashes everything all the time. :(
This commit is contained in:
Calvin Rose 2017-02-12 21:54:18 -05:00
parent f2d6b979f0
commit 439650f26a
11 changed files with 304 additions and 147 deletions

View File

@ -1,6 +1,6 @@
# TIL
CFLAGS=-std=c99 -Wall -Wextra -g
CFLAGS=-std=c99 -Wall -Wextra -Wpedantic -g
TARGET=interp
PREFIX=/usr/local

View File

@ -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;
}

View File

@ -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

View File

@ -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");
}

2
ds.h
View File

@ -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)); \
}
/****/

8
main.c
View File

@ -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;
}

View File

@ -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;

142
value.c
View File

@ -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.");
}
}

View File

@ -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);

184
vm.c
View File

@ -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

4
vm.h
View File

@ -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);