Update func env representation to not store envs in function

objects.
This commit is contained in:
Calvin Rose 2018-02-12 16:43:59 -05:00
parent e124029ae3
commit a614816a04
10 changed files with 93 additions and 96 deletions

View File

@ -187,17 +187,19 @@ static int32_t dst_asm_addenv(DstAssembler *a, Dst envname) {
int32_t envindex;
int32_t res;
if (dst_equals(a->name, envname)) {
return 0;
return -1;
}
/* Check for memoized value */
check = dst_table_get(&a->envs, envname);
if (dst_checktype(check, DST_INTEGER)) return dst_unwrap_integer(check);
if (NULL == a->parent) return -1;
if (dst_checktype(check, DST_INTEGER)) {
return dst_unwrap_integer(check);
}
if (NULL == a->parent) return -2;
res = dst_asm_addenv(a->parent, envname);
if (res < 0)
if (res < -1) {
return res;
}
envindex = def->environments_length;
if (envindex == 0) envindex = 1;
dst_table_put(&a->envs, envname, dst_wrap_integer(envindex));
if (envindex >= a->environments_capacity) {
int32_t newcap = 2 * envindex;
@ -291,7 +293,7 @@ static int32_t doarg_1(
if (argtype == DST_OAT_ENVIRONMENT && ret == -1) {
/* Add a new env */
ret = dst_asm_addenv(a, x);
if (ret < 0) {
if (ret < -1) {
dst_asm_errorv(a, dst_formatc("unknown environment %q", x));
}
}
@ -788,8 +790,7 @@ Dst dst_disasm(DstFuncDef *def) {
DstArray *bcode = dst_array(def->bytecode_length);
DstArray *constants;
DstTable *ret = dst_table(10);
if (def->arity)
dst_table_put(ret, dst_csymbolv("arity"), dst_wrap_integer(def->arity));
dst_table_put(ret, dst_csymbolv("arity"), dst_wrap_integer(def->arity));
dst_table_put(ret, dst_csymbolv("bytecode"), dst_wrap_array(bcode));
if (NULL != def->sourcepath) {
dst_table_put(ret, dst_csymbolv("sourcepath"),
@ -871,7 +872,7 @@ int dst_asm_cfun(DstArgs args) {
if (args.n < 1) return dst_throw(args, "expected assembly source");
res = dst_asm(args.v[0], 0);
if (res.status == DST_ASSEMBLE_OK) {
return dst_return(args, dst_wrap_function(dst_function(res.funcdef, NULL)));
return dst_return(args, dst_wrap_function(dst_thunk(res.funcdef)));
} else {
return dst_throwv(args, dst_wrap_string(res.error));
}

View File

@ -132,7 +132,7 @@ int32_t dstc_lslotn(DstCompiler *c, int32_t max, int32_t nth) {
/* Free a slot */
void dstc_freeslot(DstCompiler *c, DstSlot s) {
if (s.flags & (DST_SLOT_CONSTANT | DST_SLOT_REF | DST_SLOT_NAMED)) return;
if (s.envindex > 0) return;
if (s.envindex >= 0) return;
dstc_sfreei(c, s.index);
}
@ -208,7 +208,7 @@ void dstc_popscope(DstCompiler *c) {
/* Leave a scope but keep a slot allocated. */
void dstc_popscope_keepslot(DstCompiler *c, DstSlot retslot) {
dstc_popscope(c);
if (retslot.envindex == 0 && retslot.index >= 0) {
if (retslot.envindex < 0 && retslot.index >= 0) {
slotalloci(c, retslot.index);
}
}
@ -219,7 +219,7 @@ DstSlot dstc_cslot(Dst x) {
ret.flags = (1 << dst_type(x)) | DST_SLOT_CONSTANT;
ret.index = -1;
ret.constant = x;
ret.envindex = 0;
ret.envindex = -1;
return ret;
}
@ -285,7 +285,7 @@ DstSlot dstc_resolve(
/* Unused references and locals shouldn't add captured envs. */
if (unused || foundlocal) {
ret.envindex = 0;
ret.envindex = -1;
return ret;
}
@ -294,18 +294,17 @@ DstSlot dstc_resolve(
while (scope >= c->scopes && !(scope->flags & DST_SCOPE_FUNCTION)) scope--;
dst_assert(scope >= c->scopes, "invalid scopes");
scope->flags |= DST_SCOPE_ENV;
if (!dst_v_count(scope->envs)) dst_v_push(scope->envs, 0);
scope++;
/* Propogate env up to current scope */
int32_t envindex = 0;
int32_t envindex = -1;
while (scope <= top) {
if (scope->flags & DST_SCOPE_FUNCTION) {
int32_t j, len;
int scopefound = 0;
/* Check if scope already has env. If so, break */
len = dst_v_count(scope->envs);
for (j = 1; j < len; j++) {
for (j = 0; j < len; j++) {
if (scope->envs[j] == envindex) {
scopefound = 1;
envindex = j;
@ -314,7 +313,6 @@ DstSlot dstc_resolve(
}
/* Add the environment if it is not already referenced */
if (!scopefound) {
if (!dst_v_count(scope->envs)) dst_v_push(scope->envs, 0);
len = dst_v_count(scope->envs);
dst_v_push(scope->envs, envindex);
envindex = len;
@ -418,7 +416,7 @@ int32_t dstc_preread(
(ret << 8) |
DOP_GET_INDEX);
}
} else if (s.envindex > 0 || s.index > max) {
} else if (s.envindex >= 0 || s.index > max) {
ret = dstc_lslotn(c, max, nth);
dstc_emit(c, ast,
((uint32_t)(s.index) << 24) |
@ -440,7 +438,7 @@ int32_t dstc_preread(
/* Call this to release a read handle after emitting the instruction. */
void dstc_postread(DstCompiler *c, DstSlot s, int32_t index) {
if (index != s.index || s.envindex > 0 || s.flags & DST_SLOT_CONSTANT) {
if (index != s.index || s.envindex >= 0 || s.flags & DST_SLOT_CONSTANT) {
/* We need to free the temporary slot */
dstc_sfreei(c, index);
}
@ -495,7 +493,7 @@ void dstc_copy(
/* far index */
/* If dest is a near index, do some optimization */
if (dest.envindex == 0 && dest.index >= 0 && dest.index <= 0xFF) {
if (dest.envindex < 0 && dest.index >= 0 && dest.index <= 0xFF) {
if (src.flags & DST_SLOT_CONSTANT) {
dstc_loadconst(c, ast, src.constant, dest.index);
} else if (src.flags & DST_SLOT_REF) {
@ -504,7 +502,7 @@ void dstc_copy(
(dest.index << 16) |
(dest.index << 8) |
DOP_GET_INDEX);
} else if (src.envindex > 0) {
} else if (src.envindex >= 0) {
dstc_emit(c, ast,
(src.index << 24) |
(src.envindex << 16) |
@ -533,7 +531,7 @@ void dstc_copy(
(dstc_const(c, ast, dest.constant) << 16) |
(reflocal << 8) |
DOP_LOAD_CONSTANT);
} else if (dest.envindex > 0) {
} else if (dest.envindex >= 0) {
writeback = 2;
destlocal = srclocal;
} else if (dest.index > 0xFF) {
@ -597,11 +595,11 @@ DstSlot dstc_return(DstCompiler *c, DstAst *ast, DstSlot s) {
DstSlot dstc_gettarget(DstFopts opts) {
DstSlot slot;
if ((opts.flags & DST_FOPTS_HINT) &&
(opts.hint.envindex == 0) &&
(opts.hint.envindex < 0) &&
(opts.hint.index >= 0 && opts.hint.index <= 0xFF)) {
slot = opts.hint;
} else {
slot.envindex = 0;
slot.envindex = -1;
slot.constant = dst_wrap_nil();
slot.flags = 0;
slot.index = dstc_lslotn(opts.compiler, 0xFF, 4);
@ -883,7 +881,7 @@ DstFuncDef *dstc_pop_funcdef(DstCompiler *c) {
/* Copy envs */
def->environments_length = dst_v_count(scope.envs);
if (def->environments_length > 1) def->environments = dst_v_flatten(scope.envs);
def->environments = dst_v_flatten(scope.envs);
def->constants_length = dst_v_count(scope.consts);
def->constants = dst_v_flatten(scope.consts);
@ -926,9 +924,6 @@ DstFuncDef *dstc_pop_funcdef(DstCompiler *c) {
def->flags = 0;
if (scope.flags & DST_SCOPE_ENV) {
def->flags |= DST_FUNCDEF_FLAG_NEEDSENV;
if (def->environments_length == 0) {
def->environments_length = 1;
}
}
/* Pop the scope */
@ -1001,7 +996,7 @@ int dst_compile_cfun(DstArgs args) {
env = dst_unwrap_table(args.v[1]);
res = dst_compile(args.v[0], env, 0);
if (res.status == DST_COMPILE_OK) {
DstFunction *fun = dst_function(res.funcdef, NULL);
DstFunction *fun = dst_thunk(res.funcdef);
return dst_return(args, dst_wrap_function(fun));
} else {
t = dst_table(2);

View File

@ -40,7 +40,7 @@ int dst_dobytes(DstTable *env, const uint8_t *bytes, int32_t len) {
Dst form = dst_parser_produce(&parser);
DstCompileResult cres = dst_compile(form, env, 0);
if (cres.status == DST_COMPILE_OK) {
DstFunction *f = dst_function(cres.funcdef, NULL);
DstFunction *f = dst_thunk(cres.funcdef);
Dst ret;
if (dst_run(dst_wrap_function(f), &ret)) {
printf("internal runtime error: %s\n", (const char *) dst_to_string(ret));

View File

@ -90,7 +90,7 @@ static void destructure(DstCompiler *c, Dst left, DstSlot right,
dstc_postread(c, islot, locali);
}
newright.index = localsub;
newright.envindex = 0;
newright.envindex = -1;
newright.constant = dst_wrap_nil();
newright.flags = DST_SLOTTYPE_ANY;
/* Traverse into the structure */
@ -120,7 +120,7 @@ static void destructure(DstCompiler *c, Dst left, DstSlot right,
DOP_GET);
dstc_postread(c, kslot, localk);
newright.index = localsub;
newright.envindex = 0;
newright.envindex = -1;
newright.constant = dst_wrap_nil();
newright.flags = DST_SLOTTYPE_ANY;
/* Traverse into the structure */
@ -197,7 +197,7 @@ static DstSlot dohead(DstCompiler *c, DstFopts opts, DstAst *ast, Dst *head, int
static DstSlot namelocal(DstCompiler *c, DstAst *ast, Dst head, int32_t flags, DstSlot ret) {
/* Non root scope, bring to local slot */
if (ret.flags & DST_SLOT_NAMED ||
ret.envindex != 0 ||
ret.envindex >= 0 ||
ret.index < 0 ||
ret.index > 0xFF) {
/* Slot is not able to be named */
@ -205,7 +205,7 @@ static DstSlot namelocal(DstCompiler *c, DstAst *ast, Dst head, int32_t flags, D
localslot.index = dstc_lsloti(c);
/* infer type? */
localslot.flags = flags;
localslot.envindex = 0;
localslot.envindex = -1;
localslot.constant = dst_wrap_nil();
dstc_copy(c, ast, localslot, ret);
ret = localslot;
@ -546,7 +546,7 @@ DstSlot dstc_fn(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) {
continue;
}
slot.flags = DST_SLOT_NAMED;
slot.envindex = 0;
slot.envindex = -1;
slot.constant = dst_wrap_nil();
slot.index = dstc_lsloti(c);
dstc_nameslot(c, dst_unwrap_symbol(param), slot);
@ -564,7 +564,7 @@ DstSlot dstc_fn(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) {
/* Check for self ref */
if (selfref) {
DstSlot slot;
slot.envindex = 0;
slot.envindex = -1;
slot.flags = DST_SLOT_NAMED | DST_FUNCTION;
slot.constant = dst_wrap_nil();
slot.index = dstc_lsloti(c);

View File

@ -221,26 +221,11 @@ DstFuncDef *dst_funcdef_alloc() {
return def;
}
/* Create a closure from a funcdef and a parent function */
DstFunction *dst_function(DstFuncDef *def, DstFunction *parent) {
int32_t i;
/* Create a simple closure from a funcdef */
DstFunction *dst_thunk(DstFuncDef *def) {
DstFunction *func = dst_gcalloc(DST_MEMORY_FUNCTION, sizeof(DstFunction));
int32_t elen = def->environments_length;
func->def = def;
if (elen) {
func->envs = malloc(sizeof(DstFuncEnv *) * elen);
if (elen > 1 && !parent) return NULL;
if (NULL == func->envs) {
DST_OUT_OF_MEMORY;
}
func->envs[0] = NULL;
} else {
func->envs = NULL;
}
for (i = 1; i < def->environments_length; ++i) {
int32_t inherit = def->environments[i];
func->envs[i] = parent->envs[inherit];
}
func->envs = NULL;
return func;
}
@ -256,5 +241,5 @@ DstFunction *dst_quick_asm(int32_t arity, int varargs, int32_t slots, const uint
DST_OUT_OF_MEMORY;
}
memcpy(def->bytecode, bytecode, bytecode_size);
return dst_function(def, NULL);
return dst_thunk(def);
}

View File

@ -101,19 +101,6 @@ void dst_fiber_pushn(DstFiber *fiber, const Dst *arr, int32_t n) {
fiber->stacktop = newtop;
}
/* Help set up function */
static void funcframe_env(DstFiber *fiber, DstFunction *func) {
/* Check closure env */
if (func->def->flags & DST_FUNCDEF_FLAG_NEEDSENV) {
/* Delayed capture of current stack frame */
DstFuncEnv *env = dst_gcalloc(DST_MEMORY_FUNCENV, sizeof(DstFuncEnv));
env->offset = fiber->frame;
env->as.fiber = fiber;
env->length = func->def->slotcount;
func->envs[0] = env;
}
}
/* Push a stack frame to a fiber */
void dst_fiber_funcframe(DstFiber *fiber, DstFunction *func) {
DstStackFrame *newframe;
@ -140,6 +127,7 @@ void dst_fiber_funcframe(DstFiber *fiber, DstFunction *func) {
newframe->prevframe = oldframe;
newframe->pc = func->def->bytecode;
newframe->func = func;
newframe->env = NULL;
/* Check varargs */
if (func->def->flags & DST_FUNCDEF_FLAG_VARARG) {
@ -152,17 +140,13 @@ void dst_fiber_funcframe(DstFiber *fiber, DstFunction *func) {
oldtop - tuplehead));
}
}
/* Check env */
funcframe_env(fiber, func) ;
}
/* If a frame has a closure environment, detach it from
* the stack and have it keep its own values */
static void dst_function_detach(DstFunction *func) {
static void dst_env_detach(DstFuncEnv *env) {
/* Check for closure environment */
if (NULL != func->envs && NULL != func->envs[0]) {
DstFuncEnv *env = func->envs[0];
if (env) {
size_t s = sizeof(Dst) * env->length;
Dst *vmem = malloc(s);
if (NULL == vmem) {
@ -190,7 +174,8 @@ void dst_fiber_funcframe_tail(DstFiber *fiber, DstFunction *func) {
/* Detatch old function */
if (NULL != dst_fiber_frame(fiber)->func)
dst_function_detach(dst_fiber_frame(fiber)->func);
dst_env_detach(dst_fiber_frame(fiber)->env);
dst_fiber_frame(fiber)->env = NULL;
/* Check varargs */
if (func->def->flags & DST_FUNCDEF_FLAG_VARARG) {
@ -218,9 +203,6 @@ void dst_fiber_funcframe_tail(DstFiber *fiber, DstFunction *func) {
/* Set stack stuff */
fiber->stacktop = fiber->stackstart = nextstacktop;
/* Varargs and func envs */
funcframe_env(fiber, func);
/* Set frame stuff */
dst_fiber_frame(fiber)->func = func;
dst_fiber_frame(fiber)->pc = func->def->bytecode;
@ -257,7 +239,7 @@ void dst_fiber_popframe(DstFiber *fiber) {
/* Clean up the frame (detach environments) */
if (NULL != frame->func)
dst_function_detach(frame->func);
dst_env_detach(frame->env);
/* Shrink stack */
fiber->stacktop = fiber->stackstart = fiber->frame;

View File

@ -186,6 +186,8 @@ static void dst_mark_fiber(DstFiber *fiber) {
frame = (DstStackFrame *)(fiber->data + i - DST_FRAME_SIZE);
if (NULL != frame->func)
dst_mark_function(frame->func);
if (NULL != frame->env)
dst_mark_funcenv(frame->env);
/* Mark all values in the stack frame */
dst_mark_many(fiber->data + i, j - i);
j = i - DST_FRAME_SIZE;

View File

@ -494,32 +494,63 @@ static void *op_lookup[255] = {
VM_OP(DOP_CLOSURE)
{
DstFuncDef *fd;
DstFunction *fn;
vm_assert((int32_t)oparg(2, 0xFFFF) < func->def->defs_length, "invalid funcdef");
fd = func->def->defs[(int32_t)oparg(2, 0xFFFF)];
stack[oparg(1, 0xFF)] = dst_wrap_function(dst_function(fd, func));
fn = dst_thunk(fd);
{
int32_t elen = fd->environments_length;
if (elen) {
int32_t i;
fn->envs = malloc(sizeof(DstFuncEnv *) * elen);
if (NULL == fn->envs) {
DST_OUT_OF_MEMORY;
}
for (i = 0; i < elen; ++i) {
int32_t inherit = fd->environments[i];
if (inherit == -1) {
DstStackFrame *frame = (DstStackFrame *)stack - 1;
if (!frame->env) {
/* Lazy capture of current stack frame */
DstFuncEnv *env = dst_gcalloc(DST_MEMORY_FUNCENV, sizeof(DstFuncEnv));
env->offset = dst_vm_fiber->frame;
env->as.fiber = dst_vm_fiber;
env->length = func->def->slotcount;
frame->env = env;
}
fn->envs[i] = frame->env;
} else {
fn->envs[i] = func->envs[inherit];
}
}
} else {
fn->envs = NULL;
}
}
stack[oparg(1, 0xFF)] = dst_wrap_function(fn);
pc++;
vm_checkgc_next();
}
VM_OP(DOP_PUSH)
dst_fiber_push(dst_vm_fiber, stack[oparg(1, 0xFFFFFF)]);
pc++;
stack = dst_vm_fiber->data + dst_vm_fiber->frame;
vm_checkgc_next();
dst_fiber_push(dst_vm_fiber, stack[oparg(1, 0xFFFFFF)]);
pc++;
stack = dst_vm_fiber->data + dst_vm_fiber->frame;
vm_checkgc_next();
VM_OP(DOP_PUSH_2)
dst_fiber_push2(dst_vm_fiber,
stack[oparg(1, 0xFF)],
stack[oparg(2, 0xFFFF)]);
dst_fiber_push2(dst_vm_fiber,
stack[oparg(1, 0xFF)],
stack[oparg(2, 0xFFFF)]);
pc++;
stack = dst_vm_fiber->data + dst_vm_fiber->frame;
vm_checkgc_next();
VM_OP(DOP_PUSH_3)
dst_fiber_push3(dst_vm_fiber,
stack[oparg(1, 0xFF)],
stack[oparg(2, 0xFF)],
stack[oparg(3, 0xFF)]);
dst_fiber_push3(dst_vm_fiber,
stack[oparg(1, 0xFF)],
stack[oparg(2, 0xFF)],
stack[oparg(3, 0xFF)]);
pc++;
stack = dst_vm_fiber->data + dst_vm_fiber->frame;
vm_checkgc_next();
@ -743,10 +774,10 @@ static void *op_lookup[255] = {
/* Run the vm with a given function. This function is
* called to start the vm. */
int dst_run(Dst callee, Dst *returnreg) {
if (NULL == dst_vm_fiber) {
dst_vm_fiber = dst_fiber(0);
if (dst_vm_fiber) {
dst_fiber_reset(dst_vm_fiber);
} else {
dst_fiber_reset(dst_vm_fiber);
dst_vm_fiber = dst_fiber(64);
}
if (dst_checktype(callee, DST_CFUNCTION)) {
DstArgs args;
@ -772,7 +803,7 @@ int dst_call(Dst callee, Dst *returnreg, int32_t argn, const Dst *argv) {
int lock;
DstFiber *oldfiber = dst_vm_fiber;
lock = dst_vm_gc_suspend++;
dst_vm_fiber = dst_fiber(0);
dst_vm_fiber = dst_fiber(64);
dst_fiber_pushn(dst_vm_fiber, argv, argn);
if (dst_checktype(callee, DST_CFUNCTION)) {
DstArgs args;

View File

@ -172,7 +172,7 @@ int dst_gcunrootall(Dst root);
/* Functions */
DstFuncDef *dst_funcdef_alloc(void);
DstFunction *dst_function(DstFuncDef *def, DstFunction *parent);
DstFunction *dst_thunk(DstFuncDef *def);
int dst_verify(DstFuncDef *def);
DstFunction *dst_quick_asm(int32_t arity, int varargs, int32_t slots, const uint32_t *bytecode, size_t bytecode_size);

View File

@ -328,6 +328,7 @@ struct DstStackFrame {
DstFunction *func;
uint32_t *pc;
int32_t prevframe;
DstFuncEnv *env;
};
/* Number of Dsts a frame takes up in the stack */