Add much commentary about CALL_JQ and call frames
This commit is contained in:
1 parent
3e1baf5916
commit
1204e328df
1 file changed
+55
-18
@@ -36,22 +36,23 @@ struct jq_state {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct closure {
|
struct closure {
|
||||||
struct bytecode* bc;
|
struct bytecode* bc; // jq bytecode
|
||||||
stack_ptr env;
|
stack_ptr env; // jq stack address of closed frame
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// locals for any function called: either a closure or a local variable
|
||||||
union frame_entry {
|
union frame_entry {
|
||||||
struct closure closure;
|
struct closure closure;
|
||||||
jv localvar;
|
jv localvar;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// jq function call frame
|
||||||
struct frame {
|
struct frame {
|
||||||
struct bytecode* bc;
|
struct bytecode* bc; // jq bytecode for callee
|
||||||
stack_ptr env;
|
stack_ptr env; // jq stack address of frame to return to
|
||||||
stack_ptr retdata;
|
stack_ptr retdata; // jq stack address to unwind to on RET
|
||||||
uint16_t* retaddr;
|
uint16_t* retaddr; // jq bytecode return address
|
||||||
/* bc->nclosures closures followed by bc->nlocals local variables */
|
union frame_entry entries[0]; // nclosures + nlocals
|
||||||
union frame_entry entries[0];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int frame_size(struct bytecode* bc) {
|
static int frame_size(struct bytecode* bc) {
|
||||||
@@ -652,23 +653,59 @@ jv jq_next(jq_state *jq) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case CALL_JQ: {
|
case CALL_JQ: {
|
||||||
|
/*
|
||||||
|
* Bytecode layout here:
|
||||||
|
*
|
||||||
|
* CALL_JQ
|
||||||
|
* <nclosures> (i.e., number of call arguments)
|
||||||
|
* <callee closure> (what we're calling)
|
||||||
|
* <nclosures' worth of closures> (frame reference + code pointer)
|
||||||
|
*
|
||||||
|
* <next instruction (to return to)>
|
||||||
|
*
|
||||||
|
* Each closure consists of two uint16_t values: a "level"
|
||||||
|
* identifying the frame to be closed over, and an index.
|
||||||
|
*
|
||||||
|
* The level is a relative number of call frames reachable from
|
||||||
|
* the currently one; 0 -> current frame, 1 -> previous frame, and
|
||||||
|
* so on.
|
||||||
|
*
|
||||||
|
* The index is either an index of the closed frame's subfunctions
|
||||||
|
* or of the closed frame's parameter closures. If the latter,
|
||||||
|
* that closure will be passed, else the closed frame's pointer
|
||||||
|
* and the subfunction's code will form the closure to be passed.
|
||||||
|
*
|
||||||
|
* See make_closure() for more information.
|
||||||
|
*/
|
||||||
jv input = stack_pop(jq);
|
jv input = stack_pop(jq);
|
||||||
uint16_t nclosures = *pc++;
|
uint16_t nclosures = *pc++;
|
||||||
uint16_t* retaddr;
|
uint16_t* retaddr = pc + 2 + nclosures*2;
|
||||||
|
stack_ptr retdata = jq->stk_top;
|
||||||
struct frame* new_frame;
|
struct frame* new_frame;
|
||||||
struct closure cl = make_closure(jq, pc);
|
struct closure cl = make_closure(jq, pc);
|
||||||
if (nclosures == 0 && *(pc + 2) == RET && *pc == 1) {
|
if (nclosures == 0 && *(pc + 2) == RET && *pc >= 1) {
|
||||||
// TCO
|
/*
|
||||||
|
* TCO: Tail call with no references left to the current frame.
|
||||||
|
*
|
||||||
|
* The *pc >= 1 portion of the conditional checks that the
|
||||||
|
* callee does not close over this frame. The nclosures == 0
|
||||||
|
* potion checks that there are no arguments (which could close
|
||||||
|
* over this frame).
|
||||||
|
*
|
||||||
|
* TODO: nclosures > 0 can still allow TCO if none of those
|
||||||
|
* closures refers to the current frame.
|
||||||
|
*
|
||||||
|
* TODO: chase JUMP chains to see if they end in RET.
|
||||||
|
*
|
||||||
|
* These additions will make us want to memoize here or in an
|
||||||
|
* optimizer pass preceding interpretation.
|
||||||
|
*/
|
||||||
retaddr = frame_current(jq)->retaddr;
|
retaddr = frame_current(jq)->retaddr;
|
||||||
stack_ptr retdata = frame_current(jq)->retdata;
|
retdata = frame_current(jq)->retdata;
|
||||||
frame_pop(jq);
|
frame_pop(jq);
|
||||||
new_frame = frame_push(jq, cl, pc + 2, 0);
|
|
||||||
new_frame->retdata = retdata;
|
|
||||||
} else {
|
|
||||||
retaddr = pc + 2 + nclosures*2;
|
|
||||||
new_frame = frame_push(jq, cl, pc + 2, nclosures);
|
|
||||||
new_frame->retdata = jq->stk_top;
|
|
||||||
}
|
}
|
||||||
|
new_frame = frame_push(jq, cl, pc + 2, nclosures);
|
||||||
|
new_frame->retdata = retdata;
|
||||||
new_frame->retaddr = retaddr;
|
new_frame->retaddr = retaddr;
|
||||||
pc = new_frame->bc->code;
|
pc = new_frame->bc->code;
|
||||||
stack_push(jq, input);
|
stack_push(jq, input);
|
||||||
|
|||||||
Reference in new issue
Block a user