From dd0d340ebafbafe92f43bbb77a96ea8531ac1307 Mon Sep 17 00:00:00 2001 From: Stephen Dolan Date: Tue, 21 Aug 2012 12:35:36 +0100 Subject: [PATCH] frame layout refactor --- c/bytecode.h | 9 +++- c/compile.c | 3 +- c/execute.c | 110 ++++++++++++++++++--------------------------- c/forkable_stack.h | 11 +++-- c/frame_layout.h | 81 +++++++++++++++++++++++++++++++++ c/opcode.c | 1 + c/opcode.h | 3 +- c/opcode_list.h | 2 + 8 files changed, 147 insertions(+), 73 deletions(-) create mode 100644 c/frame_layout.h diff --git a/c/bytecode.h b/c/bytecode.h index ddf1105a..a7141e4b 100644 --- a/c/bytecode.h +++ b/c/bytecode.h @@ -23,11 +23,18 @@ struct symbol_table { struct bytecode { uint16_t* code; int codelen; - int framesize; + + int nlocals; + int nclosures; + json_t* constants; struct symbol_table* globals; + + struct bytecode* subfunctions; + int nsubfunctions; }; void dump_disassembly(struct bytecode* code); void dump_operation(struct bytecode* bc, uint16_t* op); + #endif diff --git a/c/compile.c b/c/compile.c index cc344575..b102eeeb 100644 --- a/c/compile.c +++ b/c/compile.c @@ -274,7 +274,8 @@ struct bytecode* block_compile(struct symbol_table* syms, block b) { } free(stack_height); bc->constants = constant_pool; - bc->framesize = maxvar + 2; // FIXME: frames of size zero? + bc->nlocals = maxvar + 2; // FIXME: frames of size zero? + bc->nclosures = 0; bc->globals = syms; return bc; } diff --git a/c/execute.c b/c/execute.c index 44aaab3a..a97d80f2 100644 --- a/c/execute.c +++ b/c/execute.c @@ -10,6 +10,7 @@ #include "compile.h" #include "forkable_stack.h" +#include "frame_layout.h" typedef struct { @@ -52,34 +53,19 @@ typedef struct { stackval sv; } data_stk_elem; -data_stk_elem* stk_push_frame(int n) { - return forkable_stack_push(&data_stk, sizeof(data_stk_elem) * n); -} - -void stk_pop_frame(int n) { - forkable_stack_pop(&data_stk, sizeof(data_stk_elem) * n); -} - void stk_push(stackval val) { - data_stk_elem* s = stk_push_frame(1); + data_stk_elem* s = forkable_stack_push(&data_stk, sizeof(data_stk_elem)); s->sv = val; } stackval stk_pop() { - data_stk_elem* s = forkable_stack_peek(&data_stk, sizeof(data_stk_elem)); + data_stk_elem* s = forkable_stack_peek(&data_stk); stackval sv = s->sv; - forkable_stack_pop(&data_stk, sizeof(data_stk_elem)); + forkable_stack_pop(&data_stk); return sv; } - -typedef struct { - FORKABLE_STACK_HEADER; - struct bytecode* bc; - data_stk_elem* fp; - uint16_t* pc; -} call_stk_elem; -struct forkable_stack call_stk; +struct forkable_stack frame_stk; struct forkpoint { @@ -93,20 +79,20 @@ struct forkable_stack fork_stk; void stack_save(){ struct forkpoint* fork = forkable_stack_push(&fork_stk, sizeof(struct forkpoint)); forkable_stack_save(&data_stk, &fork->saved_data_stack); - forkable_stack_save(&call_stk, &fork->saved_call_stack); + forkable_stack_save(&frame_stk, &fork->saved_call_stack); } void stack_switch() { - struct forkpoint* fork = forkable_stack_peek(&fork_stk, sizeof(struct forkpoint)); + struct forkpoint* fork = forkable_stack_peek(&fork_stk); forkable_stack_switch(&data_stk, &fork->saved_data_stack); - forkable_stack_switch(&call_stk, &fork->saved_call_stack); + forkable_stack_switch(&frame_stk, &fork->saved_call_stack); } void stack_restore(){ - struct forkpoint* fork = forkable_stack_peek(&fork_stk, sizeof(struct forkpoint)); + struct forkpoint* fork = forkable_stack_peek(&fork_stk); forkable_stack_restore(&data_stk, &fork->saved_data_stack); - forkable_stack_restore(&call_stk, &fork->saved_call_stack); - forkable_stack_pop(&fork_stk, sizeof(struct forkpoint)); + forkable_stack_restore(&frame_stk, &fork->saved_call_stack); + forkable_stack_pop(&fork_stk); } #define stack_push stk_push @@ -115,29 +101,31 @@ void stack_restore(){ #define ON_BACKTRACK(op) ((op)+NUM_OPCODES) json_t* jq_next() { - assert(!forkable_stack_empty(&call_stk)); - call_stk_elem* ctx = forkable_stack_peek(&call_stk, sizeof(call_stk_elem)); - struct bytecode* bc = ctx->bc; - uint16_t* pc = ctx->pc; - data_stk_elem* fp = ctx->fp; - json_t* cpool = bc->constants; - json_t* cfunc_input[MAX_CFUNCTION_ARGS] = {0}; json_t* cfunc_output[MAX_CFUNCTION_ARGS] = {0}; + + + assert(!forkable_stack_empty(&frame_stk)); + uint16_t* pc = *frame_current_pc(&frame_stk); + int backtracking = 0; while (1) { - - dump_operation(bc, pc); + *frame_current_pc(&frame_stk) = pc; + dump_operation(frame_current_bytecode(&frame_stk), pc); uint16_t opcode = *pc++; printf("\t"); const struct opcode_description* opdesc = opcode_describe(opcode); - data_stk_elem* param = forkable_stack_peek(&data_stk, sizeof(data_stk_elem)); + data_stk_elem* param; for (int i=0; istack_in; i++) { + if (i == 0) { + param = forkable_stack_peek(&data_stk); + } else { + param = forkable_stack_peek_next(&data_stk, param); + } json_dumpf(param->sv.value, stdout, JSON_ENCODE_ANY); if (i < opdesc->stack_in-1) printf(" | "); - param = forkable_stack_peek_next(&data_stk, param, sizeof(data_stk_elem)); } if (backtracking) { @@ -152,7 +140,7 @@ json_t* jq_next() { default: assert(0 && "invalid instruction"); case LOADK: { - json_t* v = json_array_get(cpool, *pc++); + json_t* v = json_array_get(frame_current_bytecode(&frame_stk)->constants, *pc++); assert(v); stack_push(stackval_replace(stack_pop(), v)); break; @@ -205,17 +193,19 @@ json_t* jq_next() { case LOADV: { uint16_t v = *pc++; - stack_push(stackval_replace(stack_pop(), fp[v].sv.value)); + json_t** var = frame_local_var(frame_current(&frame_stk), v); + stack_push(stackval_replace(stack_pop(), *var)); break; } case STOREV: { uint16_t v = *pc++; + json_t** var = frame_local_var(frame_current(&frame_stk), v); stackval val = stack_pop(); printf("V%d = ", v); json_dumpf(val.value, stdout, JSON_ENCODE_ANY); printf("\n"); - fp[v].sv.value = val.value; + *var = val.value; break; } @@ -277,10 +267,7 @@ json_t* jq_next() { stack_save(); stack_push(array); stack_push(stackval_root(json_integer(idx+1))); - call_stk_elem* ctx = forkable_stack_push(&call_stk, sizeof(call_stk_elem)); - ctx->bc = bc; - ctx->fp = fp; - ctx->pc = pc - 1; + frame_push_backtrack(&frame_stk, frame_current_bytecode(&frame_stk), pc - 1); stack_switch(); stackval sv = {json_array_get(array.value, idx), @@ -296,22 +283,15 @@ json_t* jq_next() { return 0; } stack_restore(); - call_stk_elem* ctx = forkable_stack_peek(&call_stk, sizeof(call_stk_elem)); - bc = ctx->bc; - pc = ctx->pc; - fp = ctx->fp; - cpool = bc->constants; - forkable_stack_pop(&call_stk, sizeof(call_stk_elem)); + pc = *frame_current_pc(&frame_stk); + frame_pop(&frame_stk); backtracking = 1; break; } case FORK: { stack_save(); - call_stk_elem* ctx = forkable_stack_push(&call_stk, sizeof(call_stk_elem)); - ctx->bc = bc; - ctx->fp = fp; - ctx->pc = pc - 1; + frame_push_backtrack(&frame_stk, frame_current_bytecode(&frame_stk), pc - 1); stack_switch(); pc++; // skip offset this time break; @@ -324,17 +304,14 @@ json_t* jq_next() { case YIELD: { json_t* value = stack_pop().value; - call_stk_elem* ctx = forkable_stack_push(&call_stk, sizeof(call_stk_elem)); - ctx->bc = bc; - ctx->fp = fp; - ctx->pc = pc; + *frame_current_pc(&frame_stk) = pc; return value; } case CALL_BUILTIN_1_1: { stackval top = stack_pop(); cfunc_input[0] = top.value; - struct cfunction* func = &bc->globals->cfunctions[*pc++]; + struct cfunction* func = &frame_current_bytecode(&frame_stk)->globals->cfunctions[*pc++]; printf(" call %s\n", func->name); func->fptr(cfunc_input, cfunc_output); stack_push(stackval_replace(top, cfunc_output[0])); @@ -348,13 +325,19 @@ json_t* jq_next() { cfunc_input[0] = top.value; cfunc_input[1] = a; cfunc_input[2] = b; - struct cfunction* func = &bc->globals->cfunctions[*pc++]; + struct cfunction* func = &frame_current_bytecode(&frame_stk)->globals->cfunctions[*pc++]; printf(" call %s\n", func->name); func->fptr(cfunc_input, cfunc_output); stack_push(stackval_replace(top, cfunc_output[0])); break; } + + /* + case CALL_1_1: { + uint16_t nargs = *pc++; + } + */ } } @@ -363,16 +346,11 @@ json_t* jq_next() { void jq_init(struct bytecode* bc, json_t* input) { forkable_stack_init(&data_stk, sizeof(stackval) * 100); // FIXME: lower this number, see if it breaks - forkable_stack_init(&call_stk, 1024); // FIXME: lower this number, see if it breaks + forkable_stack_init(&frame_stk, 1024); // FIXME: lower this number, see if it breaks forkable_stack_init(&fork_stk, 1024); // FIXME: lower this number, see if it breaks - data_stk_elem* frame = stk_push_frame(bc->framesize); - stack_push(stackval_root(input)); - call_stk_elem* ctx = forkable_stack_push(&call_stk, sizeof(call_stk_elem)); - ctx->pc = bc->code; - ctx->bc = bc; - ctx->fp = frame; + frame_push(&frame_stk, bc); } void run_program(struct bytecode* bc) { diff --git a/c/forkable_stack.h b/c/forkable_stack.h index 5b8ec8ad..88a280f2 100644 --- a/c/forkable_stack.h +++ b/c/forkable_stack.h @@ -1,3 +1,5 @@ +#ifndef FORKABLE_STACK_H +#define FORKABLE_STACK_H #include #include #include @@ -65,21 +67,21 @@ static void* forkable_stack_push(struct forkable_stack* s, size_t size) { return ret; } -static void* forkable_stack_peek(struct forkable_stack* s, size_t size) { +static void* forkable_stack_peek(struct forkable_stack* s) { assert(!forkable_stack_empty(s)); forkable_stack_check(s); return (void*)(s->stk + s->pos); } -static void* forkable_stack_peek_next(struct forkable_stack* s, void* top, size_t size) { +static void* forkable_stack_peek_next(struct forkable_stack* s, void* top) { forkable_stack_check(s); struct forkable_stack_header* elem = top; return (void*)(s->stk + elem->next); } -static void forkable_stack_pop(struct forkable_stack* s, size_t size) { +static void forkable_stack_pop(struct forkable_stack* s) { forkable_stack_check(s); - struct forkable_stack_header* elem = forkable_stack_peek(s, size); + struct forkable_stack_header* elem = forkable_stack_peek(s); s->pos = elem->next; } @@ -114,3 +116,4 @@ static void forkable_stack_restore(struct forkable_stack* s, struct forkable_sta s->savedlimit = state->prevlimit; forkable_stack_check(s); } +#endif diff --git a/c/frame_layout.h b/c/frame_layout.h new file mode 100644 index 00000000..55919f8a --- /dev/null +++ b/c/frame_layout.h @@ -0,0 +1,81 @@ +#ifndef FRAME_LAYOUT_H +#include "forkable_stack.h" +#include "bytecode.h" +#include + +struct closure { + struct bytecode* bc; + uint16_t* pc; +}; + +typedef union frame_elem { + FORKABLE_STACK_HEADER; + struct closure closure; + json_t* jsonval; +} *frame_ptr; + +/* + * Frame layout + * fr[0] - FORKABLE_STACK_HEADER (next pointer) + * fr[1] - self (used to store return addresses, etc) + * fr[2...nclosures+2] - closure params + * fr[nclosures+2..nclosures+nlocals+2] - local variables + */ + +static int frame_size(struct bytecode* bc) { + return sizeof(union frame_elem) * (bc->nclosures + bc->nlocals + 2); +} + +static struct closure* frame_self(frame_ptr fr) { + return &fr[1].closure; +} + +static struct closure* frame_closure_arg(frame_ptr fr, int closure) { + assert(closure >= 0); + assert(closure < frame_self(fr)->bc->nclosures); + return &fr[2+closure].closure; +} + +static json_t** frame_local_var(frame_ptr fr, int var) { + assert(var >= 0); + assert(var < frame_self(fr)->bc->nlocals); + return &fr[2 + frame_self(fr)->bc->nclosures + var].jsonval; +} + + +static frame_ptr frame_current(struct forkable_stack* stk) { + frame_ptr fp = forkable_stack_peek(stk); + struct bytecode* bc = frame_self(fp)->bc; + assert(frame_self(fp)->pc >= bc->code && frame_self(fp)->pc < bc->code + bc->codelen); + return fp; +} + +static struct bytecode* frame_current_bytecode(struct forkable_stack* stk) { + return frame_self(frame_current(stk))->bc; +} +static uint16_t** frame_current_pc(struct forkable_stack* stk) { + return &frame_self(frame_current(stk))->pc; +} + + + + +static void frame_push(struct forkable_stack* stk, struct bytecode* bc) { + frame_ptr fp = forkable_stack_push(stk, frame_size(bc)); + frame_self(fp)->bc = bc; + frame_self(fp)->pc = bc->code; +} + +static void frame_push_backtrack(struct forkable_stack* stk, + struct bytecode* bc, uint16_t* pc) { + frame_ptr fp = forkable_stack_push(stk, sizeof(union frame_elem) * 2); + frame_self(fp)->bc = bc; + frame_self(fp)->pc = pc; +} + + +static void frame_pop(struct forkable_stack* stk) { + forkable_stack_pop(stk); +} + +#endif diff --git a/c/opcode.c b/c/opcode.c index b14e0db6..92bbcd29 100644 --- a/c/opcode.c +++ b/c/opcode.c @@ -5,6 +5,7 @@ #define VARIABLE (OP_HAS_IMMEDIATE | OP_HAS_VARIABLE) #define BRANCH (OP_HAS_IMMEDIATE | OP_HAS_BRANCH) #define CFUNC (OP_HAS_IMMEDIATE | OP_HAS_SYMBOL | OP_HAS_CFUNC) +#define UFUNC (OP_HAS_IMMEDIATE | OP_HAS_UFUNC) #define OP(name, imm, in, out) \ {name, #name, imm, in, out}, diff --git a/c/opcode.h b/c/opcode.h index 797e6a96..36d41920 100644 --- a/c/opcode.h +++ b/c/opcode.h @@ -19,7 +19,8 @@ enum { OP_HAS_VARIABLE = 4, OP_HAS_BRANCH = 8, OP_HAS_SYMBOL = 16, - OP_HAS_CFUNC = 32 + OP_HAS_CFUNC = 32, + OP_HAS_UFUNC = 64, }; struct opcode_description { opcode op; diff --git a/c/opcode_list.h b/c/opcode_list.h index 2fe3f8a8..d3bfb983 100644 --- a/c/opcode_list.h +++ b/c/opcode_list.h @@ -16,3 +16,5 @@ OP(INSERT, NONE, 4, 2) OP(CALL_BUILTIN_1_1, CFUNC, 1, 1) OP(CALL_BUILTIN_3_1, CFUNC, 3, 1) + +OP(CALL_1_1, UFUNC, 1, 1)