aboutsummaryrefslogtreecommitdiff
path: root/src/compiler/builtins.zc
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/builtins.zc')
-rw-r--r--src/compiler/builtins.zc93
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;