Skip to content

Commit

Permalink
Implement all the instructions
Browse files Browse the repository at this point in the history
  • Loading branch information
Josep M. Bach committed Dec 21, 2012
1 parent 15e9f25 commit 49f9eee
Show file tree
Hide file tree
Showing 12 changed files with 547 additions and 17 deletions.
9 changes: 9 additions & 0 deletions src/forkix/darray.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -113,3 +113,12 @@ void *DArray_pop(DArray *array)
error: error:
return NULL; return NULL;
} }

void DArray_set(DArray *array, int i, void *el)
{
check(i < array->max, "darray attempt to set past max");
array->contents[i] = el;
error:
return;
}

8 changes: 1 addition & 7 deletions src/forkix/darray.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -31,13 +31,7 @@ void DArray_clear_destroy(DArray *array);


#define DEFAULT_EXPAND_RATE 300 #define DEFAULT_EXPAND_RATE 300


static inline void DArray_set(DArray *array, int i, void *el) void DArray_set(DArray *array, int i, void *el);
{
check(i < array->max, "darray attempt to set past max");
array->contents[i] = el;
error:
return;
}


static inline void *DArray_get(DArray *array, int i) static inline void *DArray_get(DArray *array, int i)
{ {
Expand Down
15 changes: 13 additions & 2 deletions src/forkix/opcode.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -5,11 +5,22 @@ typedef enum {
NOOP = 0, NOOP = 0,


PUSHSELF = 0x10, // 16 PUSHSELF = 0x10, // 16
PUSHINT, // 17 PUSH, // 17
PUSHTRUE, // 18
PUSHFALSE, // 19
PUSHNIL, // 20


PUSHLOCAL = 0x20, // 32 PUSHLOCAL = 0x20, // 32
SETLOCAL, // 33


ADD, // 33 ADD, // 34

JMP = 0x30, // 48
JIF, // 49
JIT, // 50

GETSLOT = 0x40, // 64
SETSLOT, // 65


POP, POP,


Expand Down
23 changes: 23 additions & 0 deletions src/forkix/runtime.c
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,23 @@
#include <forkix/runtime.h>

VALUE TrueObject = NULL;
VALUE FalseObject = NULL;
VALUE NilObject = NULL;

void Runtime_init() {
// Init extern constants
TrueObject = Value_new(TrueType);
FalseObject = Value_new(FalseType);
NilObject = Value_new(NilType);
}

void Runtime_destroy() {
Value_destroy(TrueObject);
TrueObject = NULL;

Value_destroy(FalseObject);
FalseObject = NULL;

Value_destroy(NilObject);
NilObject = NULL;
}
13 changes: 13 additions & 0 deletions src/forkix/runtime.h
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef _fx_runtime_h_
#define _fx_runtime_h

#include <forkix/value.h>

extern VALUE TrueObject;
extern VALUE FalseObject;
extern VALUE NilObject;

void Runtime_init();
void Runtime_destroy();

#endif
21 changes: 20 additions & 1 deletion src/forkix/value.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -25,6 +25,26 @@ Value_print(VALUE o)
printf("#<Integer %p @value=%i>\n", o, VAL2INT(o)); printf("#<Integer %p @value=%i>\n", o, VAL2INT(o));
break; break;
} }
case StringType: {
printf("#<String %p @value=%s>\n", o, VAL2STR(o));
break;
}
case TrueType: {
printf("#<True %p>\n", o);
break;
}
case FalseType: {
printf("#<False %p>\n", o);
break;
}
case NilType: {
printf("#<Nil %p>\n", o);
break;
}
case MainType: {
printf("#<Main %p>\n", o);
break;
}
default: { default: {
printf("#<Object %p>\n", o); printf("#<Object %p>\n", o);
break; break;
Expand All @@ -47,4 +67,3 @@ String_new(char* value)
val->data.as_str = value; val->data.as_str = value;
return val; return val;
} }

8 changes: 7 additions & 1 deletion src/forkix/value.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -29,7 +29,13 @@ VALUE Integer_new(int);
VALUE String_new(char*); VALUE String_new(char*);
#define VAL2STR(o) (o->data.as_str) #define VAL2STR(o) (o->data.as_str)


#define VALSET(S, K, V) Hashmap_set((S)->table, bfromcstr((K)), (V)); #define VALSET(S, K, V) \
{ \
bstring _slotname = bfromcstr((K)); \
Hashmap_delete((S)->table, _slotname); \
Hashmap_set((S)->table, _slotname, (V)); \
}

#define VALGET(S, K) (VALUE)Hashmap_get((S)->table, bfromcstr((K))) #define VALGET(S, K) (VALUE)Hashmap_get((S)->table, bfromcstr((K)))


#endif #endif
Expand Down
105 changes: 101 additions & 4 deletions src/forkix/vm.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -5,10 +5,16 @@
#include <forkix/vm.h> #include <forkix/vm.h>
#include <forkix/opcode.h> #include <forkix/opcode.h>
#include <forkix/state.h> #include <forkix/state.h>
#include <forkix/runtime.h>
#include <forkix/bootstrap.h> #include <forkix/bootstrap.h>
#include <forkix/bstrlib.h> #include <forkix/bstrlib.h>
#include <forkix/function.h> #include <forkix/function.h>


// Extern global objects declared in runtime.h
VALUE TrueObject;
VALUE FalseObject;
VALUE NilObject;

static inline void dump(Stack* stack) static inline void dump(Stack* stack)
{ {
#ifndef NDEBUG #ifndef NDEBUG
Expand All @@ -27,22 +33,26 @@ static inline void dump(Stack* stack)
#define STATE_FN(A) (Function*)Hashmap_get(state->functions, bfromcstr((A))) #define STATE_FN(A) (Function*)Hashmap_get(state->functions, bfromcstr((A)))
#define LITERAL(A) (VALUE)DArray_at(current_frame->fn->literals, (A)) #define LITERAL(A) (VALUE)DArray_at(current_frame->fn->literals, (A))
#define LOCAL(A) (VALUE)DArray_at(current_frame->locals, (A)) #define LOCAL(A) (VALUE)DArray_at(current_frame->locals, (A))
#define LOCALSET(A, B) DArray_set(current_frame->locals, (A), (B))


void VM_start(BytecodeFile *file) void VM_start(BytecodeFile *file)
{ {
STATE state = State_new(file->functions); STATE state = State_new(file->functions);


VALUE main = Value_new(MainType); // toplevel object VALUE main = Value_new(MainType); // toplevel object


Runtime_init();
State_bootstrap(state); State_bootstrap(state);


Stack *frames = Stack_create(); Stack *frames = Stack_create();
CallFrame *top_frame = CallFrame_new(main, STATE_FN("main"), NULL); CallFrame *top_frame = CallFrame_new(main, STATE_FN("main"), NULL);
Stack_push(frames, top_frame); Stack_push(frames, top_frame);
VM_run(state, frames); VM_run(state, frames);

Runtime_destroy();
} }


void VM_run(STATE state, Stack *frames) VALUE VM_run(STATE state, Stack *frames)
{ {
Stack *stack = Stack_create(); Stack *stack = Stack_create();


Expand All @@ -51,13 +61,91 @@ void VM_run(STATE state, Stack *frames)


while(1) { while(1) {
switch(*ip) { switch(*ip) {
case PUSHINT: { case NOOP:
break;
case PUSH: {
ip++; ip++;
debug("PUSHINT %i", *ip); debug("PUSH %i", *ip);
VALUE value = LITERAL(*ip); VALUE value = LITERAL(*ip);
Stack_push(stack, value); Stack_push(stack, value);
break; break;
} }
case PUSHTRUE: {
debug("PUSHTRUE");
Stack_push(stack, TrueObject);
break;
}
case PUSHFALSE: {
debug("PUSHFALSE");
Stack_push(stack, FalseObject);
break;
}
case PUSHNIL: {
debug("PUSHNIL");
Stack_push(stack, NilObject);
break;
}
case JMP: {
ip++;
int jump = *ip;
debug("JMP %i", jump);
for(int i=1; i < jump; i++) {
ip++;
}
break;
}
case JIF: {
ip++;
int jump = *ip;
debug("JIF %i", jump);

VALUE value = Stack_peek(stack);
if (value == FalseObject || value == NilObject) {
for(int i=1; i < jump; i++) {
ip++;
}
}

break;
}
case JIT: {
ip++;
int jump = *ip;
debug("JIT %i", jump);

VALUE value = Stack_peek(stack);
if (value != FalseObject && value != NilObject) {
for(int i=1; i < jump; i++) {
ip++;
}
}

break;
}
case GETSLOT: {
ip++;
debug("GETSLOT %i", *ip);
VALUE receiver = Stack_pop(stack);
VALUE slot = LITERAL(*ip);

check(slot->type == StringType, "Slot name must be a String.");

Stack_push(stack, VALGET(receiver, VAL2STR(slot)));
break;
}
case SETSLOT: {
ip++;
debug("SETSLOT %i", *ip);
VALUE value = Stack_pop(stack);
VALUE receiver = Stack_pop(stack);
VALUE slot = LITERAL(*ip);

check(slot->type == StringType, "Slot name must be a String.");

VALSET(receiver, VAL2STR(slot), value);
Stack_push(stack, value); // push the rhs back to the stack
break;
}
case ADD: { case ADD: {
debug("ADD"); debug("ADD");
VALUE op1 = Stack_pop(stack); VALUE op1 = Stack_pop(stack);
Expand Down Expand Up @@ -105,6 +193,12 @@ void VM_run(STATE state, Stack *frames)
debug("PUSHLOCAL %i", *ip); debug("PUSHLOCAL %i", *ip);
break; break;
} }
case SETLOCAL: {
ip++;
debug("SETLOCAL %i", *ip);
LOCALSET(*ip, Stack_peek(stack));
break;
}
case POP: { case POP: {
debug("POP"); debug("POP");
Stack_pop(stack); Stack_pop(stack);
Expand All @@ -115,7 +209,7 @@ void VM_run(STATE state, Stack *frames)
CallFrame *old_frame = Stack_pop(frames); CallFrame *old_frame = Stack_pop(frames);


ip = old_frame->ret; ip = old_frame->ret;
if (ip == NULL) return; // if there's nowhere to return, exit if (ip == NULL) return Stack_pop(stack); // if there's nowhere to return, exit


current_frame = (CallFrame*)(Stack_peek(frames)); current_frame = (CallFrame*)(Stack_peek(frames));
break; break;
Expand All @@ -128,4 +222,7 @@ void VM_run(STATE state, Stack *frames)
} }
ip++; ip++;
} }
error:
debug("Aborted.");
return NULL;
} }
3 changes: 2 additions & 1 deletion src/forkix/vm.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@


#include <forkix/stack.h> #include <forkix/stack.h>
#include <forkix/state.h> #include <forkix/state.h>
#include <forkix/value.h>
#include <forkix/input_reader.h> #include <forkix/input_reader.h>


void VM_run(STATE state, Stack *frames); VALUE VM_run(STATE state, Stack *frames);
void VM_start(BytecodeFile *file); void VM_start(BytecodeFile *file);


#endif #endif
2 changes: 1 addition & 1 deletion tests/input_reader_tests.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ char *test_load()
Function *main = Hashmap_get(file->functions, bfromcstr("main")); Function *main = Hashmap_get(file->functions, bfromcstr("main"));
Function *add = Hashmap_get(file->functions, bfromcstr("add")); Function *add = Hashmap_get(file->functions, bfromcstr("add"));


mu_assert(*main->code == PUSHINT, "error parsing main"); mu_assert(*main->code == PUSH, "error parsing main");
VALUE first_lit = DArray_first(main->literals); VALUE first_lit = DArray_first(main->literals);
mu_assert(strcmp(VAL2STR(first_lit), "add") == 0, "error parsing literal in main"); mu_assert(strcmp(VAL2STR(first_lit), "add") == 0, "error parsing literal in main");
mu_assert(*add->code == PUSHSELF, "error parsing add"); mu_assert(*add->code == PUSHSELF, "error parsing add");
Expand Down
36 changes: 36 additions & 0 deletions tests/runtime_tests.c
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,36 @@
#include "minunit.h"
#include <forkix/runtime.h>
#include <assert.h>

char *test_init()
{
Runtime_init();

mu_assert(TrueObject->type == TrueType, "TrueObject didn't initialize");
mu_assert(FalseObject->type == FalseType, "FalseObject didn't initialize");
mu_assert(NilObject->type == NilType, "NilObject didn't initialize");

return NULL;
}

char *test_destroy()
{
Runtime_destroy();

mu_assert(TrueObject == NULL, "TrueObject wasn't destroyed with the runtime");
mu_assert(FalseObject == NULL, "FalseObject wasn't destroyed with the runtime");
mu_assert(NilObject == NULL, "NilObject wasn't destroyed with the runtime");

return NULL;
}

char *all_tests() {
mu_suite_start();

mu_run_test(test_init);
mu_run_test(test_destroy);

return NULL;
}

RUN_TESTS(all_tests);
Loading

0 comments on commit 49f9eee

Please sign in to comment.