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:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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*
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user