Unify frame and data stacks
This commit is contained in:
1 parent
c8ab67be27
commit
25bf1a0169
3 files changed
+69
-58
No files matched your search
@@ -21,7 +21,7 @@
|
||||
|
||||
struct jq_state {
|
||||
struct forkable_stack data_stk;
|
||||
struct forkable_stack frame_stk;
|
||||
stack_idx curr_frame;
|
||||
struct forkable_stack fork_stk;
|
||||
jv path;
|
||||
int subexp_nest;
|
||||
@@ -55,8 +55,8 @@ jv stack_pop(jq_state *jq) {
|
||||
struct forkpoint {
|
||||
FORKABLE_STACK_HEADER;
|
||||
struct forkable_stack_state saved_data_stack;
|
||||
struct forkable_stack_state saved_call_stack;
|
||||
int path_len, subexp_nest;
|
||||
stack_idx saved_curr_frame;
|
||||
uint16_t* return_address;
|
||||
};
|
||||
|
||||
@@ -64,17 +64,16 @@ struct forkpoint {
|
||||
void stack_save(jq_state *jq, uint16_t* retaddr){
|
||||
struct forkpoint* fork = forkable_stack_push(&jq->fork_stk, sizeof(struct forkpoint));
|
||||
forkable_stack_save(&jq->data_stk, &fork->saved_data_stack);
|
||||
forkable_stack_save(&jq->frame_stk, &fork->saved_call_stack);
|
||||
fork->path_len =
|
||||
jv_get_kind(jq->path) == JV_KIND_ARRAY ? jv_array_length(jv_copy(jq->path)) : 0;
|
||||
fork->subexp_nest = jq->subexp_nest;
|
||||
fork->saved_curr_frame = jq->curr_frame;
|
||||
fork->return_address = retaddr;
|
||||
}
|
||||
|
||||
void stack_switch(jq_state *jq) {
|
||||
struct forkpoint* fork = forkable_stack_peek(&jq->fork_stk);
|
||||
forkable_stack_switch(&jq->data_stk, &fork->saved_data_stack);
|
||||
forkable_stack_switch(&jq->frame_stk, &fork->saved_call_stack);
|
||||
}
|
||||
|
||||
void path_append(jq_state* jq, jv component) {
|
||||
@@ -91,11 +90,11 @@ void path_append(jq_state* jq, jv component) {
|
||||
uint16_t* stack_restore(jq_state *jq){
|
||||
while (!forkable_stack_empty(&jq->data_stk) &&
|
||||
forkable_stack_pop_will_free(&jq->data_stk)) {
|
||||
jv_free(stack_pop(jq));
|
||||
}
|
||||
while (!forkable_stack_empty(&jq->frame_stk) &&
|
||||
forkable_stack_pop_will_free(&jq->frame_stk)) {
|
||||
frame_pop(&jq->frame_stk);
|
||||
if (forkable_stack_peek(&jq->data_stk) != forkable_stack_from_idx(&jq->data_stk, jq->curr_frame)) {
|
||||
jv_free(stack_pop(jq));
|
||||
} else {
|
||||
jq->curr_frame = frame_pop(&jq->data_stk, jq->curr_frame);
|
||||
}
|
||||
}
|
||||
|
||||
if (forkable_stack_empty(&jq->fork_stk)) {
|
||||
@@ -105,7 +104,7 @@ uint16_t* stack_restore(jq_state *jq){
|
||||
struct forkpoint* fork = forkable_stack_peek(&jq->fork_stk);
|
||||
uint16_t* retaddr = fork->return_address;
|
||||
forkable_stack_restore(&jq->data_stk, &fork->saved_data_stack);
|
||||
forkable_stack_restore(&jq->frame_stk, &fork->saved_call_stack);
|
||||
jq->curr_frame = fork->saved_curr_frame;
|
||||
int path_len = fork->path_len;
|
||||
if (jv_get_kind(jq->path) == JV_KIND_ARRAY) {
|
||||
assert(path_len >= 0);
|
||||
@@ -156,28 +155,30 @@ jv jq_next(jq_state *jq) {
|
||||
uint16_t opcode = *pc;
|
||||
|
||||
if (jq->debug_trace_enabled) {
|
||||
dump_operation(frame_current_bytecode(&jq->frame_stk), pc);
|
||||
dump_operation(frame_current_bytecode(&jq->data_stk, jq->curr_frame), pc);
|
||||
printf("\t");
|
||||
const struct opcode_description* opdesc = opcode_describe(opcode);
|
||||
data_stk_elem* param = 0;
|
||||
int stack_in = opdesc->stack_in;
|
||||
if (stack_in == -1) stack_in = pc[1];
|
||||
for (int i=0; i<stack_in; i++) {
|
||||
if (i == 0) {
|
||||
param = forkable_stack_peek(&jq->data_stk);
|
||||
} else {
|
||||
printf(" | ");
|
||||
param = forkable_stack_peek_next(&jq->data_stk, param);
|
||||
if (!backtracking) {
|
||||
int stack_in = opdesc->stack_in;
|
||||
if (stack_in == -1) stack_in = pc[1];
|
||||
for (int i=0; i<stack_in; i++) {
|
||||
if (i == 0) {
|
||||
param = forkable_stack_peek(&jq->data_stk);
|
||||
} else {
|
||||
printf(" | ");
|
||||
param = forkable_stack_peek_next(&jq->data_stk, param);
|
||||
}
|
||||
if (!param) break;
|
||||
jv_dump(jv_copy(param->val), 0);
|
||||
//printf("<%d>", jv_get_refcnt(param->val));
|
||||
//printf(" -- ");
|
||||
//jv_dump(jv_copy(jq->path), 0);
|
||||
}
|
||||
if (!param) break;
|
||||
jv_dump(jv_copy(param->val), 0);
|
||||
//printf("<%d>", jv_get_refcnt(param->val));
|
||||
//printf(" -- ");
|
||||
//jv_dump(jv_copy(jq->path), 0);
|
||||
} else {
|
||||
printf("\t<backtracking>");
|
||||
}
|
||||
|
||||
if (backtracking) printf("\t<backtracking>");
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
if (backtracking) {
|
||||
@@ -190,7 +191,7 @@ jv jq_next(jq_state *jq) {
|
||||
default: assert(0 && "invalid instruction");
|
||||
|
||||
case LOADK: {
|
||||
jv v = jv_array_get(jv_copy(frame_current_bytecode(&jq->frame_stk)->constants), *pc++);
|
||||
jv v = jv_array_get(jv_copy(frame_current_bytecode(&jq->data_stk, jq->curr_frame)->constants), *pc++);
|
||||
assert(jv_is_valid(v));
|
||||
jv_free(stack_pop(jq));
|
||||
stack_push(jq, v);
|
||||
@@ -240,7 +241,7 @@ jv jq_next(jq_state *jq) {
|
||||
jv v = stack_pop(jq);
|
||||
uint16_t level = *pc++;
|
||||
uint16_t vidx = *pc++;
|
||||
frame_ptr fp = frame_get_level(&jq->frame_stk, frame_current(&jq->frame_stk), level);
|
||||
frame_ptr fp = frame_get_level(&jq->data_stk, frame_current(&jq->data_stk, jq->curr_frame), level);
|
||||
jv* var = frame_local_var(fp, vidx);
|
||||
assert(jv_get_kind(*var) == JV_KIND_ARRAY);
|
||||
*var = jv_array_append(*var, v);
|
||||
@@ -272,7 +273,7 @@ jv jq_next(jq_state *jq) {
|
||||
case RANGE: {
|
||||
uint16_t level = *pc++;
|
||||
uint16_t v = *pc++;
|
||||
frame_ptr fp = frame_get_level(&jq->frame_stk, frame_current(&jq->frame_stk), level);
|
||||
frame_ptr fp = frame_get_level(&jq->data_stk, frame_current(&jq->data_stk, jq->curr_frame), level);
|
||||
jv* var = frame_local_var(fp, v);
|
||||
jv max = stack_pop(jq);
|
||||
if (jv_get_kind(*var) != JV_KIND_NUMBER ||
|
||||
@@ -299,7 +300,7 @@ jv jq_next(jq_state *jq) {
|
||||
case LOADV: {
|
||||
uint16_t level = *pc++;
|
||||
uint16_t v = *pc++;
|
||||
frame_ptr fp = frame_get_level(&jq->frame_stk, frame_current(&jq->frame_stk), level);
|
||||
frame_ptr fp = frame_get_level(&jq->data_stk, frame_current(&jq->data_stk, jq->curr_frame), level);
|
||||
jv* var = frame_local_var(fp, v);
|
||||
if (jq->debug_trace_enabled) {
|
||||
printf("V%d = ", v);
|
||||
@@ -315,7 +316,7 @@ jv jq_next(jq_state *jq) {
|
||||
case LOADVN: {
|
||||
uint16_t level = *pc++;
|
||||
uint16_t v = *pc++;
|
||||
frame_ptr fp = frame_get_level(&jq->frame_stk, frame_current(&jq->frame_stk), level);
|
||||
frame_ptr fp = frame_get_level(&jq->data_stk, frame_current(&jq->data_stk, jq->curr_frame), level);
|
||||
jv* var = frame_local_var(fp, v);
|
||||
if (jq->debug_trace_enabled) {
|
||||
printf("V%d = ", v);
|
||||
@@ -331,7 +332,7 @@ jv jq_next(jq_state *jq) {
|
||||
case STOREV: {
|
||||
uint16_t level = *pc++;
|
||||
uint16_t v = *pc++;
|
||||
frame_ptr fp = frame_get_level(&jq->frame_stk, frame_current(&jq->frame_stk), level);
|
||||
frame_ptr fp = frame_get_level(&jq->data_stk, frame_current(&jq->data_stk, jq->curr_frame), level);
|
||||
jv* var = frame_local_var(fp, v);
|
||||
jv val = stack_pop(jq);
|
||||
if (jq->debug_trace_enabled) {
|
||||
@@ -499,7 +500,7 @@ jv jq_next(jq_state *jq) {
|
||||
for (int i = 1; i < nargs; i++) {
|
||||
cfunc_input[i] = stack_pop(jq);
|
||||
}
|
||||
struct cfunction* func = &frame_current_bytecode(&jq->frame_stk)->globals->cfunctions[*pc++];
|
||||
struct cfunction* func = &frame_current_bytecode(&jq->data_stk, jq->curr_frame)->globals->cfunctions[*pc++];
|
||||
top = cfunction_invoke(func, cfunc_input);
|
||||
if (jv_is_valid(top)) {
|
||||
stack_push(jq, top);
|
||||
@@ -511,37 +512,42 @@ jv jq_next(jq_state *jq) {
|
||||
}
|
||||
|
||||
case CALL_JQ: {
|
||||
jv input = stack_pop(jq);
|
||||
uint16_t nclosures = *pc++;
|
||||
uint16_t* retaddr = pc + 2 + nclosures*2;
|
||||
frame_ptr new_frame = frame_push(&jq->frame_stk,
|
||||
make_closure(&jq->frame_stk, frame_current(&jq->frame_stk), pc),
|
||||
frame_ptr new_frame = frame_push(&jq->data_stk, jq->curr_frame,
|
||||
make_closure(&jq->data_stk, frame_current(&jq->data_stk, jq->curr_frame), pc),
|
||||
retaddr);
|
||||
pc += 2;
|
||||
frame_ptr old_frame = forkable_stack_peek_next(&jq->frame_stk, new_frame);
|
||||
frame_ptr old_frame = frame_current(&jq->data_stk, jq->curr_frame);
|
||||
jq->curr_frame = forkable_stack_to_idx(&jq->data_stk, forkable_stack_peek(&jq->data_stk));
|
||||
|
||||
assert(nclosures == frame_self(new_frame)->bc->nclosures);
|
||||
for (int i=0; i<nclosures; i++) {
|
||||
*frame_closure_arg(new_frame, i) = make_closure(&jq->frame_stk, old_frame, pc);
|
||||
*frame_closure_arg(new_frame, i) = make_closure(&jq->data_stk, old_frame, pc);
|
||||
pc += 2;
|
||||
}
|
||||
|
||||
pc = frame_current_bytecode(&jq->frame_stk)->code;
|
||||
pc = frame_current_bytecode(&jq->data_stk, jq->curr_frame)->code;
|
||||
stack_push(jq, input);
|
||||
break;
|
||||
}
|
||||
|
||||
case RET: {
|
||||
uint16_t* retaddr = *frame_current_retaddr(&jq->frame_stk);
|
||||
jv value = stack_pop(jq);
|
||||
uint16_t* retaddr = *frame_current_retaddr(&jq->data_stk, jq->curr_frame);
|
||||
if (retaddr) {
|
||||
// function return
|
||||
pc = retaddr;
|
||||
frame_pop(&jq->frame_stk);
|
||||
jq->curr_frame = frame_pop(&jq->data_stk, jq->curr_frame);
|
||||
} else {
|
||||
// top-level return, yielding value
|
||||
jv value = stack_pop(jq);
|
||||
stack_save(jq, pc - 1);
|
||||
stack_push(jq, jv_null());
|
||||
stack_switch(jq);
|
||||
return value;
|
||||
}
|
||||
stack_push(jq, value);
|
||||
break;
|
||||
}
|
||||
case ON_BACKTRACK(RET): {
|
||||
@@ -559,12 +565,12 @@ void jq_init(struct bytecode* bc, jv input, jq_state **jq, int flags) {
|
||||
memset(new_jq, 0, sizeof(*new_jq));
|
||||
new_jq->path = jv_null();
|
||||
forkable_stack_init(&new_jq->data_stk, sizeof(data_stk_elem) * 100);
|
||||
forkable_stack_init(&new_jq->frame_stk, 1024);
|
||||
forkable_stack_init(&new_jq->fork_stk, 1024);
|
||||
|
||||
stack_push(new_jq, input);
|
||||
struct closure top = {bc, -1};
|
||||
frame_push(&new_jq->frame_stk, top, 0);
|
||||
frame_push(&new_jq->data_stk, 0, top, 0);
|
||||
new_jq->curr_frame = forkable_stack_to_idx(&new_jq->data_stk, forkable_stack_peek(&new_jq->data_stk));
|
||||
stack_push(new_jq, input);
|
||||
stack_save(new_jq, bc->code);
|
||||
stack_switch(new_jq);
|
||||
if (flags & JQ_DEBUG_TRACE) {
|
||||
@@ -586,10 +592,8 @@ void jq_teardown(jq_state **jq) {
|
||||
|
||||
assert(forkable_stack_empty(&old_jq->fork_stk));
|
||||
assert(forkable_stack_empty(&old_jq->data_stk));
|
||||
assert(forkable_stack_empty(&old_jq->frame_stk));
|
||||
forkable_stack_free(&old_jq->fork_stk);
|
||||
forkable_stack_free(&old_jq->data_stk);
|
||||
forkable_stack_free(&old_jq->frame_stk);
|
||||
|
||||
jv_free(old_jq->path);
|
||||
jv_mem_free(old_jq);
|
||||
|
||||
+1
-1
@@ -155,7 +155,7 @@ static void forkable_stack_restore(struct forkable_stack* s, struct forkable_sta
|
||||
forkable_stack_check(s);
|
||||
}
|
||||
|
||||
typedef int stack_idx;
|
||||
typedef int stack_idx; // never zero when valid
|
||||
|
||||
static stack_idx forkable_stack_to_idx(struct forkable_stack* s, void* ptr) {
|
||||
char* item = ptr;
|
||||
|
||||
+18
-11
@@ -10,6 +10,7 @@ struct closure {
|
||||
struct continuation {
|
||||
struct bytecode* bc;
|
||||
stack_idx env;
|
||||
stack_idx next;
|
||||
uint16_t* retaddr;
|
||||
};
|
||||
|
||||
@@ -49,10 +50,12 @@ static jv* frame_local_var(frame_ptr fr, int var) {
|
||||
}
|
||||
|
||||
|
||||
static frame_ptr frame_current(struct forkable_stack* stk) {
|
||||
frame_ptr fp = forkable_stack_peek(stk);
|
||||
if (forkable_stack_peek_next(stk, fp)) {
|
||||
struct bytecode* bc = frame_self(forkable_stack_peek_next(stk, fp))->bc;
|
||||
static frame_ptr frame_current(struct forkable_stack* stk, stack_idx idx) {
|
||||
frame_ptr fp = forkable_stack_from_idx(stk, idx);
|
||||
|
||||
if (frame_self(fp)->next) {
|
||||
frame_ptr fpnext = forkable_stack_from_idx(stk, frame_self(fp)->next);
|
||||
struct bytecode* bc = frame_self(fpnext)->bc;
|
||||
assert(frame_self(fp)->retaddr >= bc->code && frame_self(fp)->retaddr < bc->code + bc->codelen);
|
||||
} else {
|
||||
assert(frame_self(fp)->retaddr == 0);
|
||||
@@ -60,11 +63,11 @@ static frame_ptr frame_current(struct forkable_stack* stk) {
|
||||
return fp;
|
||||
}
|
||||
|
||||
static struct bytecode* frame_current_bytecode(struct forkable_stack* stk) {
|
||||
return frame_self(frame_current(stk))->bc;
|
||||
static struct bytecode* frame_current_bytecode(struct forkable_stack* stk, stack_idx curr) {
|
||||
return frame_self(frame_current(stk, curr))->bc;
|
||||
}
|
||||
static uint16_t** frame_current_retaddr(struct forkable_stack* stk) {
|
||||
return &frame_self(frame_current(stk))->retaddr;
|
||||
static uint16_t** frame_current_retaddr(struct forkable_stack* stk, stack_idx curr) {
|
||||
return &frame_self(frame_current(stk, curr))->retaddr;
|
||||
}
|
||||
|
||||
static frame_ptr frame_get_parent(struct forkable_stack* stk, frame_ptr fr) {
|
||||
@@ -78,11 +81,12 @@ static frame_ptr frame_get_level(struct forkable_stack* stk, frame_ptr fr, int l
|
||||
return fr;
|
||||
}
|
||||
|
||||
static frame_ptr frame_push(struct forkable_stack* stk, struct closure cl, uint16_t* retaddr) {
|
||||
static frame_ptr frame_push(struct forkable_stack* stk, stack_idx curr, struct closure cl, uint16_t* retaddr) {
|
||||
frame_ptr fp = forkable_stack_push(stk, frame_size(cl.bc));
|
||||
struct continuation* cc = frame_self(fp);
|
||||
cc->bc = cl.bc;
|
||||
cc->env = cl.env;
|
||||
cc->next = curr;
|
||||
cc->retaddr = retaddr;
|
||||
for (int i=0; i<cl.bc->nlocals; i++) {
|
||||
*frame_local_var(fp, i) = jv_invalid();
|
||||
@@ -90,8 +94,10 @@ static frame_ptr frame_push(struct forkable_stack* stk, struct closure cl, uint1
|
||||
return fp;
|
||||
}
|
||||
|
||||
static void frame_pop(struct forkable_stack* stk) {
|
||||
frame_ptr fp = frame_current(stk);
|
||||
static stack_idx frame_pop(struct forkable_stack* stk, stack_idx curr) {
|
||||
frame_ptr fp = frame_current(stk, curr);
|
||||
stack_idx next = frame_self(fp)->next;
|
||||
assert(fp == forkable_stack_peek(stk));
|
||||
if (forkable_stack_pop_will_free(stk)) {
|
||||
int nlocals = frame_self(fp)->bc->nlocals;
|
||||
for (int i=0; i<nlocals; i++) {
|
||||
@@ -99,6 +105,7 @@ static void frame_pop(struct forkable_stack* stk) {
|
||||
}
|
||||
}
|
||||
forkable_stack_pop(stk);
|
||||
return next;
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in new issue
Block a user