diff options
Diffstat (limited to 'src/compiler/builtins.zc')
| -rw-r--r-- | src/compiler/builtins.zc | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/src/compiler/builtins.zc b/src/compiler/builtins.zc index 5efe379..8c00636 100644 --- a/src/compiler/builtins.zc +++ b/src/compiler/builtins.zc @@ -838,6 +838,99 @@ int array_member(int c, int n) { if (n == intern("pop")) return array_pop(t); return array_resize(t); } +// ---- drops and heap() (docs/design/destructors.md) ---- + +// a pointer to a struct whose body declares drop: its values drop through the type +int tdroppable(word t) { + word e; + if (!t || !isptr(t)) return 0; + e = t[4]; + return e[0] == TY_STRUCT && e[3] >= 0 && methof(e, intern("drop")) >= 0; +} +// local i holds a value with a drop: one set on it, or one its type declares +int ldroppable(int i) { return (local_dropset && local_dropset[i]) || tdroppable(ltype[i]); } +// entering o3 from normal code: the collector waits until the outermost region is left +int o3_enter_code() { callname(intern("rt.o3_enter")); op(O_DROP); return 0; } +// a fresh value with a drop that nothing holds: it is held in a hidden slot and +// dropped when the full statement ends +int drop_temporary() { + emit_borrow_hold(); + if (hint_begin(tpack(), HINT_SMALL)) { rt.put_s("value with drop is never bound; it drops at the end of this statement"); dg_close(); } + return 0; +} +// the value is on the stack. compile the drop (the next expression, usually fn() { ... } +// with this bound to the value), attach it with rt.set_drop, and leave the value there +// with the class and facts it had. owner is the local that owns the value, or -1. +int drop_attach(word vty, int owner) { + word t = xty, af = xaf, ev = effect_value; int bor = xbor, st = xstr, c; + if (o3on) serr("a drop can't be set inside an o3 region"); + if (owner >= 0 && fchk && local_dropset) { + if (local_dropset[owner]) cerrn(owner, "drop is already set"); + local_dropset[owner] = 1; + } + lit(0); op(O_PICK); + closure_this = vty; c = expr(); rval(); closure_this = 0; + if (c >= C_VAR) touch(c - C_VAR); + callname(intern("rt.set_drop")); op(O_DROP); + xty = t; xaf = af; effect_value = ev; xbor = bor; xstr = st; + lv = 0; lvk = LV_NONE; xzero = 0; xconst = 0; xfloat = 0; + return 0; +} +// drop(v, fn() { ... }): v, with the drop attached +int drop_call() { + int c, prior = 0, i = 0 - 1; + next(); expect(s_lp); + if (tk == T_ID) { peek(); if (pk_tk == T_OP && (pk_tv == s_comma)) { i = findloc(tv); if (i >= 0) prior = ltag[i] & LREAD; } } + c = expr(); rval(); + i = 0 - 1; + if (c >= C_VAR) i = lroot(c - C_VAR); + if (i >= 0 && prior && fchk) cerrn(i, "drop set after the value was used"); + tcneed(isptr(xty) || xty == tword, "drop needs a heap value", xty); + expect(s_comma); + drop_attach(xty, i); + expect(s_rp); + if (c == C_FRESH) drop_tail = here; + return c; +} +// v.drop(fn() { ... }) gives v back; v.drop = fn() { ... }; is a statement +int drop_member(int c, word borrowed) { + int prior = 0, i = 0 - 1, assign = is_op(s_eq); + if (lv && lvk == LV_LOCAL) prior = ltag[lvi] & LREAD; + rval(); + xaf = borrowed; + if (c >= C_VAR) { i = lroot(c - C_VAR); touch(c - C_VAR); } + if (i >= 0 && prior && fchk) cerrn(i, "drop set after the value was used"); + next(); + if (assign && c == C_FRESH && fchk && infn) { drop_temporary(); c = C_PLAIN; } + drop_attach(xty, i); + if (!assign) expect(s_rp); + if (c == C_FRESH) drop_tail = here; + if (assign) { xty = tint; xaf = 0; xbor = 0 - 1; return C_PLAIN; } + return c; +} +// heap(v): v copied into a fresh owned block sized to it +int heap_box() { + int c, place = tpack(), ms; word t; + next(); expect(s_lp); + c = expr(); rval(); plainuse(c); + expect(s_rp); + t = xty; + stamp_site(); + if (isagg(t)) { + lit(tsz(t)); lit(t); callname(intern("rt.heap_copy")); + newsz = tsz(t); xty = tptr(t); + if (t[0] == TY_STRUCT) { ms = methof(t, intern("drop")); if (ms >= 0) { fnref(ms); callname(intern("rt.set_tdrop")); } } + } else if (isptr(t) && t[4][0] == TY_CHAR) { + callname(intern("rt.heap_s")); newsz = -1; xty = t; + } else { + if (xfloat) xfloat = 0; + lit(t); callname(intern("rt.heap_w")); newsz = 1; xty = tptr(t); + } + newleaf = 0; + xaf = af_new(newsz, 2, place); + lv = 0; lvk = LV_NONE; xzero = 0; xconst = 0; xstr = 0; xbor = 0 - 1; effect_value = 0; + return C_FRESH; +} // compile sizeof(T) or sizeof(e): the size of a type or expression in words. int kw_sizeof() { int t; |
