1
0
mirror of https://github.com/janet-lang/janet synced 2024-11-24 09:17:17 +00:00

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 # TIL
CFLAGS=-std=c99 -Wall -Wextra -g CFLAGS=-std=c99 -Wall -Wextra -Wpedantic -g
TARGET=interp TARGET=interp
PREFIX=/usr/local 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 /* 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 * to the byte buffer. This helps us create the byte code for the compiled
* functions. */ * functions. */
BufferDefine(UInt32, uint32_t); BufferDefine(UInt32, uint32_t)
BufferDefine(Int32, int32_t); BufferDefine(Int32, int32_t)
BufferDefine(Number, Number); BufferDefine(Number, Number)
BufferDefine(UInt16, uint16_t); BufferDefine(UInt16, uint16_t)
BufferDefine(Int16, int16_t); BufferDefine(Int16, int16_t)
/* If there is an error during compilation, /* If there is an error during compilation,
* jump back to start */ * 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 * called with n arguments, the number of arguments is written
* after the op code, followed by those arguments. * 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 * effects. With this assumptions, if the result of the operator
* is unused, it's calculation can be ignored (the evaluation of * is unused, it's calculation can be ignored (the evaluation of
* its argument is still carried out, but their results can * 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 (form->count < 2) {
if (op0 < 0) { if (op0 < 0) {
if (opn < 0) CError(c, "This operator does not take 0 arguments."); 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, opn);
BufferPushUInt16(c->vm, buffer, ret.index); BufferPushUInt16(c->vm, buffer, ret.index);
BufferPushUInt16(c->vm, buffer, 0); BufferPushUInt16(c->vm, buffer, 0);
@ -587,7 +587,7 @@ static Slot CompileOperator(Compiler * c, FormOptions opts, Array * form,
} else if (form->count == 2) { } else if (form->count == 2) {
if (op1 < 0) { if (op1 < 0) {
if (opn < 0) CError(c, "This operator does not take 1 argument."); 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, opn);
BufferPushUInt16(c->vm, buffer, ret.index); BufferPushUInt16(c->vm, buffer, ret.index);
BufferPushUInt16(c->vm, buffer, 1); 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) { static Slot CompileNot(Compiler * c, FormOptions opts, Array * form) {
return CompileOperator(c, opts, form, VM_OP_FLS, VM_OP_NOT, -1, -1, 0); 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 */ /* Compile an assignment operation */
static Slot CompileAssign(Compiler * c, FormOptions opts, Value left, Value right) { 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 */ /* Assignment special */
static Slot CompileSet(Compiler * c, FormOptions opts, Array * form) { static Slot CompileVar(Compiler * c, FormOptions opts, Array * form) {
if (form->count != 3) if (form->count != 3)
CError(c, "Assignment expects 2 arguments"); CError(c, "Assignment expects 2 arguments");
return CompileAssign(c, opts, form->data[1], form->data[2]); return CompileAssign(c, opts, form->data[1], form->data[2]);
@ -968,7 +1001,6 @@ static SpecialFormHelper GetSpecial(Array * form) {
case '>': return CompileGreaterThan; case '>': return CompileGreaterThan;
case '<': return CompileLessThan; case '<': return CompileLessThan;
case '=': return CompileEquals; case '=': return CompileEquals;
case '\'': return CompileQuote;
default: default:
break; break;
} }
@ -991,6 +1023,14 @@ static SpecialFormHelper GetSpecial(Array * form) {
} }
} }
break; break;
case 'g':
{
if (VStringSize(name) == 3 &&
name[1] == 'e' &&
name[2] == 't') {
return CompileGet;
}
}
case 'd': case 'd':
{ {
if (VStringSize(name) == 2 && if (VStringSize(name) == 2 &&
@ -1053,6 +1093,15 @@ static SpecialFormHelper GetSpecial(Array * form) {
return CompileWhile; return CompileWhile;
} }
} }
break;
case ':':
{
if (VStringSize(name) == 2 &&
name[1] == '=') {
return CompileVar;
}
}
break;
default: default:
break; break;
} }
@ -1152,7 +1201,7 @@ void CompilerAddGlobalCFunc(Compiler * c, const char * name, CFunction f) {
Value func; Value func;
func.type = TYPE_CFUNCTION; func.type = TYPE_CFUNCTION;
func.data.cfunction = f; func.data.cfunction = f;
return CompilerAddGlobal(c, name, func); CompilerAddGlobal(c, name, func);
} }
/* Compile interface. Returns a function that evaluates the /* Compile interface. Returns a function that evaluates the
@ -1175,8 +1224,12 @@ Func * CompilerCompile(Compiler * c, Value form) {
uint32_t envSize = c->env->count; uint32_t envSize = c->env->count;
FuncEnv * env = VMAlloc(c->vm, sizeof(FuncEnv)); FuncEnv * env = VMAlloc(c->vm, sizeof(FuncEnv));
Func * func = VMAlloc(c->vm, sizeof(Func)); Func * func = VMAlloc(c->vm, sizeof(Func));
env->values = VMAlloc(c->vm, sizeof(Value) * envSize); if (envSize) {
memcpy(env->values, c->env->data, envSize * sizeof(Value)); 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->stackOffset = envSize;
env->thread = NULL; env->thread = NULL;
func->parent = NULL; func->parent = NULL;
@ -1201,7 +1254,7 @@ int CompileMacroExpand(VM * vm, Value x, Dictionary * macros, Value * out) {
VMLoad(vm, macroFn); VMLoad(vm, macroFn);
if (VMStart(vm)) { if (VMStart(vm)) {
/* We encountered an error during parsing */ /* We encountered an error during parsing */
return 1;; return 1;
} else { } else {
x = vm->ret; x = vm->ret;
} }

View File

@ -43,6 +43,7 @@ typedef struct Parser Parser;
typedef struct ParseState ParseState; typedef struct ParseState ParseState;
typedef struct Scope Scope; typedef struct Scope Scope;
typedef struct Compiler Compiler; typedef struct Compiler Compiler;
typedef struct StackFrame StackFrame;
union ValueData { union ValueData {
Boolean boolean; Boolean boolean;
@ -116,6 +117,15 @@ struct DictBucket {
DictBucket * next; DictBucket * next;
}; };
struct StackFrame {
Value callee;
uint16_t size;
uint16_t prevSize;
uint16_t ret;
FuncEnv * env;
uint16_t * pc;
};
struct VM { struct VM {
/* Garbage collection */ /* Garbage collection */
void * blocks; void * blocks;
@ -127,7 +137,7 @@ struct VM {
uint16_t * pc; uint16_t * pc;
Array * thread; Array * thread;
Value * base; Value * base;
Value root; /* Global state - prevents GC cleanup */ StackFrame * frame;
/* Return state */ /* Return state */
const char * error; const char * error;
jmp_buf jump; jmp_buf jump;
@ -206,7 +216,7 @@ enum OpCode {
VM_OP_DVM, /* 0x001f */ VM_OP_DVM, /* 0x001f */
VM_OP_RTN, /* 0x0020 */ VM_OP_RTN, /* 0x0020 */
VM_OP_SET, /* 0x0021 */ 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 *current = byteCode;
uint16_t *end = byteCode + len; uint16_t *end = byteCode + len;
fprintf(out, "----- ASM BYTECODE AT %p -----\n", byteCode); fprintf(out, "----- ASM BYTECODE START -----\n");
while (current < end) { while (current < end) {
switch (*current) { switch (*current) {
@ -196,6 +196,12 @@ void dasm(FILE * out, uint16_t *byteCode, uint32_t len) {
case VM_OP_RTN: case VM_OP_RTN:
current += dasmPrintFixedOp(out, current, "returnNil", 0); current += dasmPrintFixedOp(out, current, "returnNil", 0);
break; 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"); fprintf(out, "\n");
} }

2
ds.h
View File

@ -29,7 +29,7 @@ uint8_t * BufferToString(VM * vm, Buffer * buffer);
#define BufferDefine(name, type) \ #define BufferDefine(name, type) \
static void BufferPush##name (VM * vm, Buffer * buffer, type x) { \ static void BufferPush##name (VM * vm, Buffer * buffer, type x) { \
union { type t; uint8_t bytes[sizeof(type)]; } u; \ 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 (;;) { for (;;) {
/* Run garbage collection */ /* Run garbage collection */
VMMaybeCollect(&vm); /* VMMaybeCollect(&vm);*/
/* Reset state */ /* Reset state */
ParserInit(&p, &vm); ParserInit(&p, &vm);
@ -85,6 +85,11 @@ void debugRepl() {
continue; continue;
} }
/* Print asm */
printf("\n");
dasmFunc(stdout, func.data.func);
printf("\n");
/* Execute function */ /* Execute function */
VMLoad(&vm, func); VMLoad(&vm, func);
if (VMStart(&vm)) { if (VMStart(&vm)) {
@ -103,4 +108,5 @@ void debugRepl() {
int main() { int main() {
printf("Super cool interpreter v0.0\n"); printf("Super cool interpreter v0.0\n");
debugRepl(); debugRepl();
return 0;
} }

View File

@ -130,7 +130,7 @@ static int isWhitespace(uint8_t c) {
static int isSymbolChar(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 >= '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; 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: case TYPE_NUMBER:
return NumberToString(vm, x.data.number); return NumberToString(vm, x.data.number);
case TYPE_ARRAY: case TYPE_ARRAY:
return StringDescription(vm, "array", 5, x.data.array); return StringDescription(vm, "array", 5, x.data.pointer);
case TYPE_FORM: case TYPE_FORM:
return StringDescription(vm, "form", 4, x.data.array); return StringDescription(vm, "form", 4, x.data.pointer);
case TYPE_STRING: case TYPE_STRING:
case TYPE_SYMBOL: case TYPE_SYMBOL:
return x.data.string; return x.data.string;
case TYPE_BYTEBUFFER: case TYPE_BYTEBUFFER:
return StringDescription(vm, "buffer", 6, x.data.buffer); return StringDescription(vm, "buffer", 6, x.data.pointer);
case TYPE_CFUNCTION: case TYPE_CFUNCTION:
return StringDescription(vm, "cfunction", 9, x.data.cfunction); return StringDescription(vm, "cfunction", 9, x.data.pointer);
case TYPE_FUNCTION: case TYPE_FUNCTION:
return StringDescription(vm, "function", 8, x.data.func); return StringDescription(vm, "function", 8, x.data.pointer);
case TYPE_DICTIONARY: case TYPE_DICTIONARY:
return StringDescription(vm, "dictionary", 10, x.data.dict); return StringDescription(vm, "dictionary", 10, x.data.pointer);
case TYPE_FUNCDEF: case TYPE_FUNCDEF:
return StringDescription(vm, "funcdef", 7, x.data.funcdef); return StringDescription(vm, "funcdef", 7, x.data.pointer);
case TYPE_FUNCENV: case TYPE_FUNCENV:
return StringDescription(vm, "funcenv", 7, x.data.funcenv); return StringDescription(vm, "funcenv", 7, x.data.pointer);
case TYPE_THREAD: case TYPE_THREAD:
return StringDescription(vm, "thread", 6, x.data.array); return StringDescription(vm, "thread", 6, x.data.pointer);
} }
return NULL; return NULL;
} }
@ -352,23 +352,115 @@ int ValueCompare(Value x, Value y) {
return 1; return 1;
} }
/* Get a value out af an associated data structure. Can throw VM error. */ /* Allow negative indexing to get from end of array like structure */
Value ValueGet(VM * vm, Value ds, Value key) { /* This probably isn't very fast - look at Lua conversion function.
switch (ds.type) { * I would like to keep this standard C for as long as possible, though. */
case TYPE_ARRAY: static int32_t ToIndex(Number raw, int64_t len) {
case TYPE_FORM: int32_t toInt = raw;
case TYPE_BYTEBUFFER: if ((Number) toInt == raw) {
case TYPE_SYMBOL: /* We were able to convert */
case TYPE_STRING: if (toInt < 0) {
case TYPE_DICTIONARY: /* Index from end */
case TYPE_FUNCENV: if (toInt < -len) return -1;
default: return len + toInt;
VMError(vm, "Cannot get."); } else {
break; /* Normal indexing */
if (toInt >= len) return -1;
return toInt;
}
} else {
return -1;
} }
} }
/* Set a value in an associative data structure. Can throw VM error. */ /* Convert a number into a byte. */
int ValueSet(VM * vm, Value ds, Value key, Value value) { 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); 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); 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_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. */ /* The size of a StackFrame in units of Values. */
#define FRAME_SIZE ((sizeof(StackFrame) + sizeof(Value) - 1) / sizeof(Value)) #define FRAME_SIZE ((sizeof(StackFrame) + sizeof(Value) - 1) / sizeof(Value))
@ -37,7 +26,7 @@ static StackFrame * ThreadFrame(Array * thread) {
typedef struct GCMemoryHeader GCMemoryHeader; typedef struct GCMemoryHeader GCMemoryHeader;
struct GCMemoryHeader { struct GCMemoryHeader {
GCMemoryHeader * next; GCMemoryHeader * next;
uint32_t color; uint32_t color : 1;
}; };
/* Forward declaration */ /* Forward declaration */
@ -52,17 +41,43 @@ static void VMMarkFuncEnv(VM * vm, FuncEnv * env) {
temp.type = TYPE_THREAD; temp.type = TYPE_THREAD;
temp.data.array = env->thread; temp.data.array = env->thread;
VMMark(vm, &temp); VMMark(vm, &temp);
} else { } else if (env->values) {
uint32_t count = env->stackOffset; uint32_t count = env->stackOffset;
uint32_t i; uint32_t i;
GCHeader(env->values)->color = vm->black; GCHeader(env->values)->color = vm->black;
for (i = 0; i < count; ++i) { for (i = 0; i < count; ++i)
VMMark(vm, env->values + 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 /* Mark allocated memory associated with a value. This is
* the main function for doing garbage collection. */ * the main function for doing garbage collection. */
static void VMMark(VM * vm, Value * x) { static void VMMark(VM * vm, Value * x) {
@ -97,22 +112,13 @@ 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;
Array * thread = x->data.array; Array * thread = x->data.array;
StackFrame * frame = (StackFrame *)thread->data; 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)->color = vm->black;
GCHeader(thread->data)->color = vm->black; GCHeader(thread->data)->color = vm->black;
while (frame <= end) { while (frame <= end)
Value * stack = (Value *)frame + FRAME_SIZE; frame = VMMarkStackFrame(vm, frame);
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;
@ -121,16 +127,12 @@ static void VMMark(VM * vm, Value * x) {
Func * f = x->data.func; Func * f = x->data.func;
GCHeader(f)->color = vm->black; GCHeader(f)->color = vm->black;
VMMarkFuncEnv(vm, f->env); VMMarkFuncEnv(vm, f->env);
{ VMMarkFuncDef(vm, f->def);
if (f->parent) {
Value temp; Value temp;
temp.type = TYPE_FUNCDEF; temp.type = TYPE_FUNCTION;
temp.data.funcdef = x->data.funcdef; temp.data.func = f->parent;
VMMark(vm, &temp); VMMark(vm, &temp);
if (f->parent) {
temp.type = TYPE_FUNCTION;
temp.data.func = f->parent;
VMMark(vm, &temp);
}
} }
} }
break; break;
@ -151,16 +153,7 @@ static void VMMark(VM * vm, Value * x) {
break; break;
case TYPE_FUNCDEF: case TYPE_FUNCDEF:
if (GCHeader(x->data.funcdef)->color != vm->black) { VMMarkFuncDef(vm, x->data.funcdef);
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);
}
}
break; break;
case TYPE_FUNCENV: case TYPE_FUNCENV:
@ -223,14 +216,11 @@ void * VMZalloc(VM * vm, uint32_t size) {
void VMCollect(VM * vm) { void VMCollect(VM * vm) {
if (vm->lock > 0) return; if (vm->lock > 0) return;
/* Thread can be null */ /* Thread can be null */
if (vm->thread) { Value thread;
Value thread; thread.type = TYPE_THREAD;
thread.type = TYPE_THREAD; thread.data.array = vm->thread;
thread.data.array = vm->thread; VMMark(vm, &thread);
VMMark(vm, &thread);
}
VMMark(vm, &vm->ret); VMMark(vm, &vm->ret);
VMMark(vm, &vm->root);
VMSweep(vm); VMSweep(vm);
vm->nextCollection = 0; vm->nextCollection = 0;
} }
@ -259,22 +249,23 @@ static void VMThreadPush(VM * vm, Array * thread, Value callee, uint32_t size) {
* 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); vm->base = thread->data + thread->count;
vm->frame = frame = (StackFrame *)(vm->base - FRAME_SIZE);
/* Set up the new stack frame */ /* Set up the new stack frame */
frame->prevSize = oldSize; frame->prevSize = oldSize;
frame->size = size; frame->size = size;
frame->env = NULL; frame->env = NULL;
frame->callee = callee; frame->callee = callee;
vm->base = thread->data + thread->count;
} }
/* 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) {
StackFrame * frame = ThreadFrame(thread); StackFrame * frame = vm->frame;
FuncEnv * env = frame->env; FuncEnv * env = frame->env;
/* Check for closures */ /* Check for closures */
if (env) { if (env) {
Array * thread = vm->thread;
uint32_t size = frame->size; uint32_t size = frame->size;
env->thread = NULL; env->thread = NULL;
env->stackOffset = size; env->stackOffset = size;
@ -284,16 +275,18 @@ static void VMThreadSplitStack(VM * vm, Array * thread) {
} }
/* 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) {
StackFrame * frame = ThreadFrame(thread); Array * thread = vm->thread;
StackFrame * frame = vm->frame;
uint32_t delta = FRAME_SIZE + frame->prevSize; uint32_t delta = FRAME_SIZE + frame->prevSize;
if (thread->count) { if (thread->count) {
VMThreadSplitStack(vm, thread); VMThreadSplitStack(vm);
} else { } else {
VMError(vm, "Nothing to pop from stack."); VMError(vm, "Nothing to pop from stack.");
} }
thread->count -= delta; thread->count -= delta;
vm->base -= delta; vm->base -= delta;
vm->frame = (StackFrame *)(vm->base - FRAME_SIZE);
} }
/* Get an upvalue */ /* Get an upvalue */
@ -329,28 +322,24 @@ static int truthy(Value v) {
/* Return from the vm */ /* Return from the vm */
static void VMReturn(VM * vm, Value ret) { static void VMReturn(VM * vm, Value ret) {
Array * thread = vm->thread; VMThreadPop(vm);
StackFrame * frame = ThreadFrame(thread); if (vm->thread->count == 0) {
VMThreadPop(vm, thread);
if (thread->count == 0) {
VMExit(vm, ret); VMExit(vm, ret);
} }
frame = ThreadFrame(thread); vm->pc = vm->frame->pc;
vm->pc = frame->pc; vm->base[vm->frame->ret] = ret;
vm->base[frame->ret] = ret;
} }
/* Implementation of the opcode for function calls */ /* Implementation of the opcode for function calls */
static void VMCallOp(VM * vm) { static void VMCallOp(VM * vm) {
Array * thread = vm->thread; Array * thread = vm->thread;
StackFrame * frame = ThreadFrame(thread);
Value callee = vm->base[vm->pc[1]]; Value callee = vm->base[vm->pc[1]];
uint32_t arity = vm->pc[3]; uint32_t arity = vm->pc[3];
uint32_t oldCount = thread->count; uint32_t oldCount = thread->count;
uint32_t i; uint32_t i;
Value * oldBase; Value * oldBase;
frame->pc = vm->pc + 4 + arity; vm->frame->pc = vm->pc + 4 + arity;
frame->ret = vm->pc[2]; vm->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);
@ -375,19 +364,17 @@ static void VMCallOp(VM * vm) {
vm->base[i].type = TYPE_NIL; vm->base[i].type = TYPE_NIL;
vm->pc = f->def->byteCode; 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) {
Array * thread = vm->thread; Array * thread = vm->thread;
StackFrame * frame = ThreadFrame(thread);
Value callee = vm->base[vm->pc[1]]; Value callee = vm->base[vm->pc[1]];
uint32_t arity = vm->pc[2]; uint32_t arity = vm->pc[2];
uint16_t newFrameSize, currentFrameSize; uint16_t newFrameSize, currentFrameSize;
uint32_t i; uint32_t i;
/* Check for closures */ /* Check for closures */
VMThreadSplitStack(vm, thread); VMThreadSplitStack(vm);
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) {
@ -397,9 +384,8 @@ static void VMTailCallOp(VM * vm) {
VMError(vm, EXPECTED_FUNCTION); VMError(vm, EXPECTED_FUNCTION);
} }
/* Ensure stack has enough space for copies of arguments */ /* Ensure stack has enough space for copies of arguments */
currentFrameSize = frame->size; currentFrameSize = vm->frame->size;
ArrayEnsure(vm, thread, thread->count + currentFrameSize + arity); ArrayEnsure(vm, thread, thread->count + currentFrameSize + arity);
frame = ThreadFrame(thread);
vm->base = thread->data + thread->count; vm->base = thread->data + thread->count;
/* Copy the arguments into the extra space */ /* Copy the arguments into the extra space */
for (i = 0; i < arity; ++i) { for (i = 0; i < arity; ++i) {
@ -412,9 +398,9 @@ static void VMTailCallOp(VM * vm) {
vm->base[i].type = TYPE_NIL; vm->base[i].type = TYPE_NIL;
} }
/* Update the stack frame */ /* Update the stack frame */
frame->size = newFrameSize; vm->frame->size = newFrameSize;
frame->callee = callee; vm->frame->callee = callee;
frame->env = NULL; vm->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));
@ -423,27 +409,25 @@ static void VMTailCallOp(VM * vm) {
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 Value VMMakeClosure(VM * vm, uint16_t literal) { static Value VMMakeClosure(VM * vm, uint16_t literal) {
Array * thread = vm->thread; Array * thread = vm->thread;
StackFrame * frame = ThreadFrame(thread); if (vm->frame->callee.type != TYPE_FUNCTION) {
if (frame->callee.type != TYPE_FUNCTION) {
VMError(vm, EXPECTED_FUNCTION); VMError(vm, EXPECTED_FUNCTION);
} else { } else {
Value constant, ret; Value constant, ret;
Func * fn, * current; Func * fn, * current;
FuncEnv * env = frame->env; FuncEnv * env = vm->frame->env;
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;
frame->env = env; vm->frame->env = env;
} }
current = frame->callee.data.func; current = vm->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);
@ -500,10 +484,10 @@ int VMStart(VM * vm) {
DO_BINARY_MATH(-) DO_BINARY_MATH(-)
case VM_OP_MUL: /* Multiplication */ case VM_OP_MUL: /* Multiplication */
DO_BINARY_MATH(*) DO_BINARY_MATH(*)
case VM_OP_DIV: /* Division */ case VM_OP_DIV: /* Division */
DO_BINARY_MATH(/) DO_BINARY_MATH(/)
#undef DO_BINARY_MATH #undef DO_BINARY_MATH
@ -556,7 +540,7 @@ int VMStart(VM * vm) {
break; break;
case VM_OP_UPV: /* Load Up Value */ case VM_OP_UPV: /* Load Up Value */
temp = ThreadFrame(vm->thread)->callee; temp = vm->frame->callee;
VMAssert(vm, temp.type == TYPE_FUNCTION, EXPECTED_FUNCTION); 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->base[vm->pc[1]] = *GetUpValue(vm, temp.data.func, vm->pc[2], vm->pc[3]);
vm->pc += 4; vm->pc += 4;
@ -583,14 +567,14 @@ int VMStart(VM * vm) {
break; break;
case VM_OP_SUV: /* Set Up Value */ case VM_OP_SUV: /* Set Up Value */
temp = ThreadFrame(vm->thread)->callee; temp = vm->frame->callee;
VMAssert(vm, temp.type == TYPE_FUNCTION, EXPECTED_FUNCTION); VMAssert(vm, temp.type == TYPE_FUNCTION, EXPECTED_FUNCTION);
*GetUpValue(vm, temp.data.func, vm->pc[2], vm->pc[3]) = vm->base[vm->pc[1]]; *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 */
temp = ThreadFrame(vm->thread)->callee; temp = vm->frame->callee;
VMAssert(vm, temp.type == TYPE_FUNCTION, EXPECTED_FUNCTION); VMAssert(vm, temp.type == TYPE_FUNCTION, EXPECTED_FUNCTION);
vm->base[vm->pc[1]] = LoadConstant(vm, temp.data.func, vm->pc[2]); vm->base[vm->pc[1]] = LoadConstant(vm, temp.data.func, vm->pc[2]);
vm->pc += 3; vm->pc += 3;
@ -653,7 +637,6 @@ int VMStart(VM * vm) {
temp.data.array = array; temp.data.array = array;
vm->base[vm->pc[1]] = temp; vm->base[vm->pc[1]] = temp;
vm->pc += 3 + arrayLen; vm->pc += 3 + arrayLen;
VMMaybeCollect(vm);
} }
break; break;
@ -661,7 +644,7 @@ int VMStart(VM * vm) {
{ {
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 + 2);
kvs = kvs + 3; kvs = kvs + 3;
while (i < kvs) { while (i < kvs) {
v1 = vm->base[vm->pc[i++]]; v1 = vm->base[vm->pc[i++]];
@ -672,7 +655,6 @@ int VMStart(VM * vm) {
temp.data.dict = dict; temp.data.dict = dict;
vm->base[vm->pc[1]] = temp; vm->base[vm->pc[1]] = temp;
vm->pc += kvs; vm->pc += kvs;
VMMaybeCollect(vm);
} }
break; break;
@ -718,40 +700,48 @@ int VMStart(VM * vm) {
break; break;
case VM_OP_GET: 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; break;
default: default:
VMError(vm, "Unknown opcode"); VMError(vm, "Unknown opcode");
break; break;
} }
VMMaybeCollect(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 = ThreadFrame(vm->thread)->size; uint16_t frameSize = vm->frame->size;
VMAssert(vm, frameSize > index, "Cannot get arg out of stack bounds"); VMAssert(vm, frameSize > index, "Cannot get arg out of stack bounds");
return vm->base[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 = ThreadFrame(vm->thread)->size; uint16_t frameSize = vm->frame->size;
VMAssert(vm, frameSize > index, "Cannot set arg out of stack bounds"); VMAssert(vm, frameSize > index, "Cannot set arg out of stack bounds");
vm->base[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 ThreadFrame(vm->thread)->size; return vm->frame->size;
} }
/* Initialize the VM */ /* Initialize the VM */
void VMInit(VM * vm) { void VMInit(VM * vm) {
vm->ret.type = TYPE_NIL; vm->ret.type = TYPE_NIL;
vm->root.type = TYPE_NIL;
vm->base = NULL; vm->base = NULL;
vm->frame = NULL;
vm->pc = NULL; vm->pc = NULL;
vm->error = NULL; vm->error = NULL;
/* Garbage collection */ /* Garbage collection */
@ -760,8 +750,8 @@ void VMInit(VM * vm) {
vm->memoryInterval = 0; vm->memoryInterval = 0;
vm->black = 0; vm->black = 0;
vm->lock = 0; vm->lock = 0;
/* Set to empty thread */ /* Add thread */
vm->thread = NULL; vm->thread = ArrayNew(vm, 20);
} }
/* Load a function into the VM. The function will be called with /* 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) { if (!(cond)) { VMError((vm), (e)); } } while (0)
/* Type assertion */ /* Type assertion */
#define VMAssertType(vm, f, type) \ #define VMAssertType(vm, f, t) \
VMAssert(vm, (f).type == (type), "Expected type " type) VMAssert((vm), (f).type == (t), "Expected type,")
/* Initialize the VM */ /* Initialize the VM */
void VMInit(VM * vm); void VMInit(VM * vm);