1
0
forked from GitHub/gf-core

now we statically allocate closures for all top-level functions and all nullary constructors. closures are dynamically allocated only for CAFs. this reduces memory use and time to allocate dynamic closures

This commit is contained in:
kr.angelov
2014-10-08 12:57:29 +00:00
parent 67781996b6
commit 9c2f71b07a
6 changed files with 90 additions and 59 deletions

View File

@@ -17,7 +17,9 @@ generateByteCode gr arity eqs =
b = if arity == 0 || null eqs
then instrs
else CHECK_ARGS arity:instrs
in reverse bs
in case bs of
[[FAIL]] -> [] -- in the runtime this is a more efficient variant of [[FAIL]]
_ -> reverse bs
where
is = push_is (arity-1) arity []
@@ -100,8 +102,10 @@ compileFun gr arity st vs (Q (m,id)) h0 bs args =
is1 = setArgs st args
diff = c_arity-n_args
in if diff <= 0
then let h1 = h0 + 2 + n_args
in (h1,bs,PUT_CONSTR (i2i id):is1++[EVAL (HEAP h0) (if arity == 0 then (UpdateCall st st) else (TailCall arity st st))])
then if n_args == 0
then (h0,bs,[EVAL (GLOBAL (i2i id)) (if arity == 0 then (UpdateCall st st) else (TailCall arity st st))])
else let h1 = h0 + 2 + n_args
in (h1,bs,PUT_CONSTR (i2i id):is1++[EVAL (HEAP h0) (if arity == 0 then (UpdateCall st st) else (TailCall arity st st))])
else let h1 = h0 + 1 + n_args
is2 = [SET (FREE_VAR i) | i <- [0..n_args-1]] ++ [SET (ARG_VAR (i+1)) | i <- [0..diff-1]]
b = CHECK_ARGS diff : ALLOC (c_arity+2) : PUT_CONSTR (i2i id) : is2 ++ [EVAL (HEAP h0) (TailCall diff (diff+1) (diff+1))]
@@ -135,11 +139,11 @@ compileArg gr st vs (Q(m,id)) h0 bs =
_ -> let Ok ty = lookupFunType gr m id
(ctxt,_,_) = typeForm ty
c_arity = length ctxt
h1 = h0 + 2
in if c_arity == 0
then (h1,bs,HEAP h0,[PUT_CONSTR (i2i id)])
then (h0,bs,GLOBAL (i2i id),[])
else let is2 = [SET (ARG_VAR (i+1)) | i <- [0..c_arity-1]]
b = CHECK_ARGS c_arity : ALLOC (c_arity+2) : PUT_CONSTR (i2i id) : is2 ++ [EVAL (HEAP h0) (TailCall c_arity (c_arity+1) (c_arity+1))]
h1 = h0 + 2
in (h1,b:bs,HEAP h0,[PUT_CLOSURE (length bs),SET_PAD])
compileArg gr st vs (QC qid) h0 bs =
compileArg gr st vs (Q qid) h0 bs

View File

@@ -69,6 +69,8 @@ typedef struct {
typedef GuSeq PgfEquations;
typedef void *PgfFunction;
typedef struct {
PgfCId name;
PgfType* type;
@@ -76,7 +78,13 @@ typedef struct {
PgfEquations* defns; // maybe null
PgfExprProb ep;
void* predicate;
size_t closure_id;
struct {
PgfFunction code;
union {
size_t caf_offset;
PgfFunction* con;
};
} closure;
} PgfAbsFun;
extern GU_DECLARE_TYPE(PgfAbsFun, abstract);

View File

@@ -82,8 +82,8 @@ repeat:;
gu_map_get(state->pgf->abstract.funs, efun->fun, PgfAbsFun*);
gu_assert(absfun != NULL);
if (absfun->closure_id > 0) {
res = &state->globals[absfun->closure_id-1].header;
if (absfun->closure.code != NULL) {
res = (PgfClosure*) &absfun->closure;
if (n_args > 0) {
PgfValuePAP* val = gu_new_flex(state->pool, PgfValuePAP, args, n_args);
@@ -101,7 +101,7 @@ repeat:;
if (n_args == arity) {
PgfValue* val = gu_new_flex(state->pool, PgfValue, args, arity);
val->header.code = state->eval_gates->evaluate_value;
val->absfun = absfun;
val->con = (PgfClosure*) &absfun->closure;
for (size_t i = 0; i < arity; i++) {
val->args[i] = args[--n_args];
@@ -240,9 +240,10 @@ pgf_value2expr(PgfEvalState* state, int level, PgfClosure* clos, GuPool* pool)
if (clos->code == state->eval_gates->evaluate_value) {
PgfValue* val = (PgfValue*) clos;
PgfAbsFun* absfun = gu_container(val->con, PgfAbsFun, closure);
expr = val->absfun->ep.expr;
n_args = val->absfun->arity;
expr = absfun->ep.expr;
n_args = absfun->arity;
args = val->args;
} else if (clos->code == state->eval_gates->evaluate_value_gen) {
PgfValueGen* val = (PgfValueGen*) clos;
@@ -360,19 +361,21 @@ pgf_value2expr(PgfEvalState* state, int level, PgfClosure* clos, GuPool* pool)
PgfExpr
pgf_compute(PgfPGF* pgf, PgfExpr expr, GuExn* err, GuPool* pool, GuPool* out_pool)
{
size_t n_closures = gu_seq_length(pgf->abstract.eval_gates->defrules);
size_t n_cafs =
(pgf->abstract.eval_gates->cafs == NULL)
? 0 : gu_seq_length(pgf->abstract.eval_gates->cafs);
PgfEvalState* state =
gu_new_flex(pool, PgfEvalState, globals, n_closures);
gu_new_flex(pool, PgfEvalState, cafs, n_cafs);
state->pgf = pgf;
state->eval_gates = pgf->abstract.eval_gates;
state->pool = pool;
state->err = err;
PgfFunction* defrules = gu_seq_data(state->eval_gates->defrules);
for (size_t i = 0; i < n_closures; i++) {
state->globals[i].header.code = defrules[i];
state->globals[i].val = NULL;
PgfFunction* cafs = gu_seq_data(state->eval_gates->cafs);
for (size_t i = 0; i < n_cafs; i++) {
state->cafs[i].header.code = cafs[i];
state->cafs[i].val = NULL;
}
PgfExprThunk* thunk =

View File

@@ -1,8 +1,6 @@
#ifndef PGF_EVALUATOR_H_
#define PGF_EVALUATOR_H_
typedef void *PgfFunction;
typedef struct {
PgfFunction code;
} PgfClosure;
@@ -17,7 +15,7 @@ typedef struct {
PgfEvalGates* eval_gates; // cached from pgf->abstr->eval_gates
GuPool* pool;
GuExn* err;
PgfIndirection globals[]; // derived from gu_seq_data(pgf->abstr->eval_gates->defrules)
PgfIndirection cafs[]; // derived from gu_seq_data(pgf->abstr->eval_gates->cafs)
} PgfEvalState;
typedef struct PgfEnv PgfEnv;
@@ -35,7 +33,7 @@ typedef struct {
typedef struct {
PgfClosure header;
PgfAbsFun* absfun;
PgfClosure* con;
PgfClosure* args[];
} PgfValue;
@@ -75,6 +73,7 @@ struct PgfEvalGates {
PgfFunction evaluate_value_lit;
PgfFunction evaluate_value_pap;
PgfFunction evaluate_value_lambda;
PgfFunction evaluate_caf;
PgfFunction update_closure;
PgfFunction update_pap;
@@ -84,7 +83,7 @@ struct PgfEvalGates {
PgfClosure* (*enter)(PgfEvalState* state, PgfClosure* closure);
GuFinalizer fin;
GuSeq* defrules;
GuSeq* cafs;
};
PgfClosure*

View File

@@ -16,7 +16,7 @@ struct PgfJitState {
char *save_ip_ptr;
GuBuf* call_patches;
GuBuf* segment_patches;
size_t n_closures;
size_t n_cafs;
};
#define _jit (rdr->jit_state->jit)
@@ -81,7 +81,7 @@ pgf_new_jit(PgfReader* rdr)
state->segment_patches = gu_new_buf(PgfSegmentPatch, rdr->tmp_pool);
state->buf = NULL;
state->save_ip_ptr = NULL;
state->n_closures = 0;
state->n_cafs = 0;
return state;
}
@@ -318,11 +318,11 @@ pgf_jit_predicate(PgfReader* rdr, PgfAbstr* abstr,
}
static void
pgf_jit_finalize_defrules(GuFinalizer* self)
pgf_jit_finalize_cafs(GuFinalizer* self)
{
PgfEvalGates* gates = gu_container(self, PgfEvalGates, fin);
if (gates->defrules != NULL)
gu_seq_free(gates->defrules);
if (gates->cafs != NULL)
gu_seq_free(gates->cafs);
}
PgfEvalGates*
@@ -343,7 +343,7 @@ pgf_jit_gates(PgfReader* rdr)
gates->evaluate_value = jit_get_ip().ptr;
jit_movr_p(JIT_VHEAP, JIT_VCLOS);
jit_ldxi_p(JIT_RET, JIT_VHEAP, offsetof(PgfValue, absfun));
jit_ldxi_p(JIT_RET, JIT_VHEAP, offsetof(PgfValue, con));
jit_bare_ret(0);
pgf_jit_make_space(rdr, JIT_CODE_WINDOW*2);
@@ -454,6 +454,14 @@ pgf_jit_gates(PgfReader* rdr)
pgf_jit_make_space(rdr, JIT_CODE_WINDOW);
gates->evaluate_caf = jit_get_ip().ptr;
jit_ldxi_i(JIT_R0, JIT_VCLOS, offsetof(PgfAbsFun, closure.caf_offset) - offsetof(PgfAbsFun, closure));
jit_addr_p(JIT_VCLOS, JIT_VSTATE, JIT_R0);
jit_ldr_p(JIT_R0, JIT_VCLOS);
jit_jmpr(JIT_R0);
pgf_jit_make_space(rdr, JIT_CODE_WINDOW);
gates->enter = (void*) jit_get_ip().ptr;
jit_prolog(2);
int es_arg = jit_arg_p();
@@ -588,7 +596,7 @@ pgf_jit_gates(PgfReader* rdr)
jit_jmpr(JIT_R0);
gates->mk_const = jit_get_ip().ptr;
jit_ldxi_p(JIT_R0, JIT_VHEAP, offsetof(PgfAbsFun,arity));
jit_ldxi_p(JIT_R0, JIT_VCLOS, offsetof(PgfAbsFun,arity)-offsetof(PgfAbsFun,closure));
jit_muli_i(JIT_R0, JIT_R0, sizeof(PgfClosure*));
jit_pushr_i(JIT_R0);
jit_prepare(2);
@@ -599,7 +607,7 @@ pgf_jit_gates(PgfReader* rdr)
jit_finish(gu_malloc);
jit_movi_p(JIT_R1, gates->evaluate_value);
jit_str_p(JIT_RET, JIT_R1);
jit_stxi_p(offsetof(PgfValue,absfun), JIT_RET, JIT_VHEAP);
jit_stxi_p(offsetof(PgfValue,con), JIT_RET, JIT_VCLOS);
jit_movr_p(JIT_VHEAP, JIT_RET);
jit_popr_i(JIT_R1);
jit_popr_p(JIT_VCLOS);
@@ -613,14 +621,14 @@ pgf_jit_gates(PgfReader* rdr)
jit_patch(ref);
jit_jmpr(JIT_VCLOS);
gates->fin.fn = pgf_jit_finalize_defrules;
gates->defrules = NULL;
gates->fin.fn = pgf_jit_finalize_cafs;
gates->cafs = NULL;
gu_pool_finally(rdr->opool, &gates->fin);
return gates;
}
#define PGF_DEFRULES_DELTA 20
#define PGF_CAFS_DELTA 20
void
pgf_jit_function(PgfReader* rdr, PgfAbstr* abstr,
@@ -635,19 +643,13 @@ pgf_jit_function(PgfReader* rdr, PgfAbstr* abstr,
gu_puts(":\n", out, err);
#endif
if (rdr->jit_state->n_closures % PGF_DEFRULES_DELTA == 0) {
abstr->eval_gates->defrules =
gu_realloc_seq(abstr->eval_gates->defrules,
PgfFunction,
rdr->jit_state->n_closures + PGF_DEFRULES_DELTA);
}
absfun->closure_id = ++rdr->jit_state->n_closures;
size_t n_segments = pgf_read_len(rdr);
gu_return_on_exn(rdr->err, );
gu_buf_flush(rdr->jit_state->segment_patches);
absfun->closure.code = abstr->eval_gates->mk_const;
for (size_t segment = 0; segment < n_segments; segment++) {
size_t n_instrs = pgf_read_len(rdr);
gu_return_on_exn(rdr->err, );
@@ -655,10 +657,26 @@ pgf_jit_function(PgfReader* rdr, PgfAbstr* abstr,
pgf_jit_make_space(rdr, (JIT_CODE_WINDOW/4)*n_instrs);
if (segment == 0) {
gu_seq_set(abstr->eval_gates->defrules,
PgfFunction,
absfun->closure_id-1,
jit_get_ip().ptr);
if (absfun->arity == 0) {
// we add a new CAF
if (rdr->jit_state->n_cafs % PGF_CAFS_DELTA == 0) {
abstr->eval_gates->cafs =
gu_realloc_seq(abstr->eval_gates->cafs,
PgfFunction,
rdr->jit_state->n_cafs + PGF_CAFS_DELTA);
}
absfun->closure.code = abstr->eval_gates->evaluate_caf;
size_t caf_id = rdr->jit_state->n_cafs++;
absfun->closure.caf_offset =
offsetof(PgfEvalState,cafs)+
caf_id*sizeof(PgfIndirection);
gu_seq_set(abstr->eval_gates->cafs,
PgfFunction,
caf_id,
jit_get_ip().ptr);
} else {
absfun->closure.code = jit_get_ip().ptr;
}
}
size_t curr_offset = 0;
@@ -928,7 +946,7 @@ pgf_jit_function(PgfReader* rdr, PgfAbstr* abstr,
#endif
PgfCallPatch patch;
patch.cid = id;
patch.ref = jit_addi_p(JIT_R0, JIT_VSTATE, jit_forward());
patch.ref = jit_movi_p(JIT_R0, jit_forward());
gu_buf_push(rdr->jit_state->call_patches, PgfCallPatch, patch);
break;
}
@@ -990,7 +1008,7 @@ pgf_jit_function(PgfReader* rdr, PgfAbstr* abstr,
#endif
PgfCallPatch patch;
patch.cid = id;
patch.ref = jit_addi_p(JIT_R0, JIT_VSTATE, jit_forward());
patch.ref = jit_movi_p(JIT_R0, jit_forward());
gu_buf_push(rdr->jit_state->call_patches, PgfCallPatch, patch);
jit_pushr_p(JIT_R0);
break;
@@ -1036,7 +1054,7 @@ pgf_jit_function(PgfReader* rdr, PgfAbstr* abstr,
#endif
PgfCallPatch patch;
patch.cid = id;
patch.ref = jit_addi_p(JIT_VCLOS, JIT_VSTATE, jit_forward());
patch.ref = jit_movi_p(JIT_VCLOS, jit_forward());
gu_buf_push(rdr->jit_state->call_patches, PgfCallPatch, patch);
break;
}
@@ -1140,7 +1158,6 @@ pgf_jit_function(PgfReader* rdr, PgfAbstr* abstr,
#ifdef PGF_JIT_DEBUG
gu_printf(out, err, "FAIL\n");
#endif
jit_movi_p(JIT_VHEAP, absfun);
jit_jmpi(abstr->eval_gates->mk_const);
break;
default:
@@ -1163,17 +1180,12 @@ pgf_jit_done(PgfReader* rdr, PgfAbstr* abstr)
if (arg != NULL) {
jit_patch_calli(patch->ref,(jit_insn*) arg->predicate);
} else {
PgfAbsFun* con =
PgfAbsFun* fun =
gu_map_get(abstr->funs, patch->cid, PgfAbsFun*);
if (con == NULL)
if (fun == NULL)
gu_impossible();
else if (con->closure_id == 0) {
jit_patch_movi(patch->ref,con);
} else {
size_t offset =
offsetof(PgfEvalState,globals)+
sizeof(PgfIndirection)*(con->closure_id-1);
jit_patch_movi(patch->ref,offset);
else {
jit_patch_movi(patch->ref,&fun->closure);
}
}
}

View File

@@ -442,7 +442,12 @@ pgf_read_absfun(PgfReader* rdr, PgfAbstr* abstr)
switch (tag) {
case 0:
absfun->defns = NULL;
absfun->closure_id = 0;
if (absfun->arity == 0) {
absfun->closure.code = abstr->eval_gates->evaluate_value;
absfun->closure.con = &absfun->closure.code;
} else {
absfun->closure.code = NULL;
}
break;
case 1: {
GuLength length = pgf_read_len(rdr);