From 9c2f71b07a5de7d6d4d13dc3c72d9b9ddc2f37dc Mon Sep 17 00:00:00 2001 From: "kr.angelov" Date: Wed, 8 Oct 2014 12:57:29 +0000 Subject: [PATCH] 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 --- src/compiler/GF/Compile/GenerateBC.hs | 14 +++-- src/runtime/c/pgf/data.h | 10 +++- src/runtime/c/pgf/evaluator.c | 25 ++++---- src/runtime/c/pgf/evaluator.h | 9 ++- src/runtime/c/pgf/jit.c | 84 +++++++++++++++------------ src/runtime/c/pgf/reader.c | 7 ++- 6 files changed, 90 insertions(+), 59 deletions(-) diff --git a/src/compiler/GF/Compile/GenerateBC.hs b/src/compiler/GF/Compile/GenerateBC.hs index 8e96a54e1..b749a40e1 100644 --- a/src/compiler/GF/Compile/GenerateBC.hs +++ b/src/compiler/GF/Compile/GenerateBC.hs @@ -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 diff --git a/src/runtime/c/pgf/data.h b/src/runtime/c/pgf/data.h index 4f1f66a3b..ac319c59f 100644 --- a/src/runtime/c/pgf/data.h +++ b/src/runtime/c/pgf/data.h @@ -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); diff --git a/src/runtime/c/pgf/evaluator.c b/src/runtime/c/pgf/evaluator.c index eebaefd98..812b9f130 100644 --- a/src/runtime/c/pgf/evaluator.c +++ b/src/runtime/c/pgf/evaluator.c @@ -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 = diff --git a/src/runtime/c/pgf/evaluator.h b/src/runtime/c/pgf/evaluator.h index ac314f602..09b0afb2a 100644 --- a/src/runtime/c/pgf/evaluator.h +++ b/src/runtime/c/pgf/evaluator.h @@ -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* diff --git a/src/runtime/c/pgf/jit.c b/src/runtime/c/pgf/jit.c index 6968c0957..570cf3e8e 100644 --- a/src/runtime/c/pgf/jit.c +++ b/src/runtime/c/pgf/jit.c @@ -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); } } } diff --git a/src/runtime/c/pgf/reader.c b/src/runtime/c/pgf/reader.c index c65b8b057..2e8c154be 100644 --- a/src/runtime/c/pgf/reader.c +++ b/src/runtime/c/pgf/reader.c @@ -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);