aboutsummaryrefslogtreecommitdiff
path: root/src/compiler/decl.zc
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/decl.zc')
-rw-r--r--src/compiler/decl.zc56
1 files changed, 55 insertions, 1 deletions
diff --git a/src/compiler/decl.zc b/src/compiler/decl.zc
index 52d08c7..fed7b8d 100644
--- a/src/compiler/decl.zc
+++ b/src/compiler/decl.zc
@@ -230,11 +230,61 @@ int prologue() {
setlit(k, here); setlit(done, here); op(O_DROP); setlit(busy, here);
return 0;
}
+// a function of a hold block takes the block's lock on entry (op 57 of the syscall gate)
+// and gives it back at its one exit (op 58), with the return value left on the stack. the
+// host keeps the shared values: entering the block from outside copies them into the
+// block's variables, leaving copies them back, so inside, every read and write is a plain
+// global access on every backend. the lock is reentrant and held for the whole call.
+int hold_gate(int code) {
+ if (!fhold || nclo) return 0;
+ lit(fhold); lit(rt.SYSGATE + 1); op(O_ST);
+ lit(hold_desc); lit(rt.SYSGATE + 2); op(O_ST);
+ lit(code); lit(rt.SYSGATE); op(O_ST);
+ return 0;
+}
+// hold { shared let c; fn a() { ... } ... }: a monitor. the shared variables can be used
+// only by the functions written in the block; each call holds the block's lock.
+int kw_hold() {
+ int rank, d, before, s, i, w; word t;
+ if (hold_cur) serr("hold blocks don't nest");
+ next(); expect(s_lb);
+ rank = hold_count + 1; hold_count = rank;
+ reserve_code(1); d = here; emit(0);
+ hold_cur = rank; hold_desc = d; hold_nshared = 0;
+ while (!is_op(s_rb)) {
+ if (tk == T_EOF) { die("missing } at the end of a hold block"); break; }
+ if (panic) { topsync(); continue; }
+ if (tk == T_ID && rt.eq_w(tv, "shared")) {
+ next(); before = nsym;
+ if (is_id(s_var)) gdecl(0);
+ else if (tstart()) { rettype(); gdecl2(dty, dtag, name()); }
+ else { die("expected let or a type after shared"); continue; }
+ s = before;
+ while (s < nsym) {
+ if (skind[s] == K_GVAR || skind[s] == K_GARR) {
+ t = stype[s]; w = 1;
+ if (skind[s] == K_GARR) { w = tsz(t); if (t[0] == TY_ARR) t = t[1]; }
+ if (t && (isptr(t) || isagg(t) || t == tbstr || t[0] == TY_DYN || t[0] == TY_FN)) serrn(sname[s], "is shared, so it holds numbers: no pointers, strings or structs (each actor has its own heap)");
+ sflag[s] = sflag[s] | F_SHARED | rank * F_SHARED_RANK;
+ if (hold_nshared >= 64) serr("too many shared variables in one hold block (64)");
+ else { hold_tab[hold_nshared * 2] = sval[s]; hold_tab[hold_nshared * 2 + 1] = w; hold_nshared++; }
+ }
+ s++;
+ }
+ } else topitem0();
+ }
+ next();
+ reserve_code(1 + hold_nshared * 2); *(d + hdelta) = here; emit(hold_nshared);
+ i = 0; while (i < hold_nshared * 2) { emit(hold_tab[i]); i++; }
+ hold_cur = 0; hold_desc = 0;
+ return 0;
+}
// emit the function epilogue, patching every return to it.
int epilogue() {
int k, node, done, helper = !nclo && (sname[finsym] == s_frame_grow || sname[finsym] == s_frame_leave);
lit(0);
fixall(epichain, here);
+ hold_gate(58);
lit(rt.ZFP); op(O_LD); lit(fslots); op(O_ADD); lit(rt.ZFP); op(O_ST);
if (!helper) {
lit(sval[lookup(s_frame_node)]); op(O_LD); node = hole(); op(O_JZ);
@@ -404,7 +454,9 @@ int fndef(int chk, int rty, int ret, int n) {
if (typed && explicit_rty) fty = rty;
no3pend = 0;
if (o3f) { o3on = 1; o3reset(); sflag[s] = sflag[s] | F_O3; }
- prologue(); borrow_prologue();
+ fhold = hold_cur;
+ if (fhold && o3f) serrn(n, "is in a hold block and can't be o3");
+ prologue(); borrow_prologue(); hold_gate(57);
i = 0;
while (i < np) {
t = newloc(pn[i]); lrskind[t] = RS_PARAM; lrsoff[t] = pnoffs[i]; lpos[t] = pnplaces[i]; fslots++; lsmark(1, pn[i]);
@@ -431,6 +483,7 @@ int fndef(int chk, int rty, int ret, int n) {
}
hi = here;
epilogue();
+ fhold = 0;
lend = here;
if (o3f) {
o3on = 0;
@@ -720,6 +773,7 @@ int topitem1() {
if (!is_op(s_lp)) { die("expected a function"); return 0; }
return fndone(fndef(chk, dty, dtag == S_U, n), imm);
}
+ if (tk == T_ID && rt.eq_w(tv, "hold")) { peek(); if (pk_tk == T_OP && pk_tv == s_lb) return kw_hold(); }
if (is_id(s_var)) return gdecl(0);
if (is_id(s_struct)) { kw_struct(); return 0; }
if (is_id(s_type)) return kw_type();