aboutsummaryrefslogtreecommitdiff
path: root/src/compiler/analyzer.zc
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/analyzer.zc')
-rw-r--r--src/compiler/analyzer.zc80
1 files changed, 71 insertions, 9 deletions
diff --git a/src/compiler/analyzer.zc b/src/compiler/analyzer.zc
index 42cb7b5..ff6a6c1 100644
--- a/src/compiler/analyzer.zc
+++ b/src/compiler/analyzer.zc
@@ -83,6 +83,51 @@ int effect_specialize(int original, int instance, word requirements, word edges)
while (e && e != edges) { if (e[3] == original) e[3] = instance; e = e[0]; }
return 0;
}
+// borrow returns of functions called before their body. such a call's result
+// may turn out to alias an argument's owner, which is only known once the body
+// has been read. the result's local keeps a shadow record (callee, the mask of
+// parameters that got the owner, the owner, the token after the call, so only a call that is the whole right side counts); a
+// use of the local after its owner ended is remembered, and effect_finish
+// reports it when the callee's return aliases one of those parameters.
+word shadow_new(int callee, int mask, int owner) {
+ word e;
+ if (!fchk || !live || dry || owner < 0 || !mask) return 0;
+ e = talloc(4); e[0] = callee; e[1] = mask; e[2] = owner; e[3] = tpack();
+ return e;
+}
+// the local i is assigned: it takes the shadow of a forward call that is its whole right side.
+int shadow_take(int i) {
+ if (!local_shadow) return 0;
+ local_shadow[i] = 0;
+ // the local read just before is the target of this assignment, not a use
+ if (effect_shadows && effect_shadows[10] == i && effect_shadows[11] == lreadpos[i]) effect_shadows = effect_shadows[0];
+ if (xshadow && xshadow[3] == tpack()) local_shadow[i] = xshadow;
+ xshadow = 0; return 0;
+}
+int shadow_use(int i) {
+ word s = local_shadow[i], e; int o = s[2];
+ if (!fchk || !live || lstate[o] != S_DEAD) return 0;
+ local_shadow[i] = 0;
+ e = talloc(12); e[10] = i; e[11] = tpack(); e[0] = effect_shadows; e[1] = s[0]; e[2] = s[1]; e[3] = tpack(); e[4] = curinc; e[5] = effect_floor;
+ e[6] = lname[i]; e[7] = 0; if (local_end_info) e[7] = local_end_info[o]; e[8] = lname[o]; e[9] = local_ended[o];
+ effect_shadows = e; return 0;
+}
+int shadow_finish(int from) {
+ word e = effect_shadows, next; int flags, k;
+ effect_shadows = 0;
+ while (e) {
+ next = e[0];
+ if (e[5] < from) { e[0] = effect_shadows; effect_shadows = e; e = next; continue; }
+ flags = 0; k = 0;
+ while (k < 24) { if ((e[2] >> k) & 1) flags = flags | effect_get(e[1], k); k++; }
+ if ((flags & (EF_ALIAS | EF_IDENTITY)) && !(flags & EF_UNKNOWN) && !dry) {
+ tunpack(e[3]); curinc = e[4]; panic = 0;
+ errat(); ended_message(e[6], e[7], e[8], e[9]); rt.put_s("; "); rt.put_s(sname[e[1]]); rt.put_s(", defined after this call, returns a borrow of its argument"); errend();
+ }
+ e = next;
+ }
+ return 0;
+}
int effect_finish(int from) {
word e, r, next; int changed = 1, flags, prior, save = tpack(), inc = curinc, i = 0;
if (chkabort) return 0;
@@ -110,6 +155,7 @@ int effect_finish(int from) {
}
e = next;
}
+ shadow_finish(from);
tunpack(save); curinc = inc; return 0;
}
int borrow_begin() { return 0; }
@@ -393,6 +439,7 @@ int newloc(int n) {
if (!local_captured) local_captured = chk_resize(0, 0, loccap); local_captured[i] = 0;
if (!local_ended) local_ended = chk_resize(0, 0, loccap); local_ended[i] = 0;
if (!local_end_info) local_end_info = chk_resize(0, 0, loccap); local_end_info[i] = 0;
+ if (!local_shadow) local_shadow = chk_resize(0, 0, loccap); local_shadow[i] = 0;
lpos[i] = 0;
lreadpos[i] = 0;
lowner[i] = 0;
@@ -949,10 +996,17 @@ int lend_drop(int dep, int from) {
return 0;
}
// retire existing aliases together with their owner. dead aliases do not keep later loop snapshots live.
+// end_why and end_whom say how the next end_owner ends its owner, for the message
+// of a later use: 0 transferred, 1 freed, 2 given to a .d parameter of end_whom,
+// 3 moved into end_whom, 4 stored in a container, 5 returned, 6 stored in a global
+// or untracked memory, 7 freed by reassigning it, 8 pushed into end_whom.
+int end_why; char* end_whom;
int end_owner(int i) {
- int j = lbase; word info = talloc(3);
+ int j = lbase; word info = talloc(6);
lend_check(i);
- info[0] = lname[i]; info[1] = lpos[i]; info[2] = tpack();
+ info[0] = lname[i]; info[1] = lpos[i]; info[2] = tpack(); info[3] = end_why; info[4] = end_whom;
+ info[5] = lreadpos[i]; if (!info[5]) info[5] = info[2]; // the owner's own token where it ended, for the editor
+ end_why = 0; end_whom = 0;
local_ended[i] = info[2]; local_end_info[i] = info; lstate[i] = S_DEAD;
while (j < nloc) {
if (j != i && isalias(j) && lroot(j) == i) { local_ended[j] = info[2]; local_end_info[j] = info; lstate[j] = S_DEAD; }
@@ -1345,6 +1399,8 @@ int recast(int c, int t) {
else lstate[i] = t;
return c;
}
+// where the argument argcheck is looking at goes: 0 unknown, 1 a push, else the callee's symbol + 2
+int arg_site;
// an argument for a parameter tagged t (0 plain, 1 m, 2 d)
int argcheck(int c, int t) {
int i, st;
@@ -1373,7 +1429,12 @@ int argcheck(int c, int t) {
touch(i);
return 0;
}
- if (st == S_D || ((st == S_M || st == S_U) && lown[i])) { end_owner(i); luse(i); xgive = 1; ev_put(i, EV_DOWN, -1); return 0; }
+ if (st == S_D || ((st == S_M || st == S_U) && lown[i])) {
+ if (arg_site >= 2 && arg_site - 2 < ubase && (sname[arg_site - 2] == s_free || sname[arg_site - 2] == s_recycle)) end_why = 1;
+ else if (arg_site == 1) end_why = 8;
+ else if (arg_site >= 2) { end_why = 2; end_whom = sname[arg_site - 2]; }
+ end_owner(i); luse(i); xgive = 1; ev_put(i, EV_DOWN, -1); return 0;
+ }
if (st == S_M) cerrn(i, "is m; write d*x to give it away");
else if (st == S_U) cerrn(i, "is u; write d*x to give it away instead of returning it");
else if (st == S_CHILD) cerrn(i, "belongs to a container and can't be given away alone");
@@ -1437,7 +1498,7 @@ int reassign_free(int i, int rc, int bor) {
if (lleaf[i] && !dry && lookup(s_recycle_leaf) >= 0) { lit(lleaf[i]); lit(szclass(lnsz[i])); callname(s_recycle_leaf); }
else callname(s_recycle);
op(O_DROP);
- end_owner(i);
+ end_why = 7; end_owner(i);
if (local_dropset) local_dropset[i] = 0;
lnsz[i] = 0; lleaf[i] = 0;
xty = t; xaf = af; xstr = st; xfloat = fl; xbor = bor;
@@ -1446,6 +1507,7 @@ int reassign_free(int i, int rc, int bor) {
// a store of class rc into an lvalue of kind k (local or container index i)
int assigncheck(int k, int i, int rc) {
int st, j, r, js, bor, origin = effect_origin(rc);
+ if (k == LV_LOCAL) shadow_take(i); else xshadow = 0;
if (k == LV_LOCAL && local_origin) { local_origin[i] = origin; local_origin_mask[i] = local_origin_mask[i] | effect_mask(rc); }
if (k == LV_ELEM) { effect_note_mask(effect_mask(C_VAR + i), EF_WRITE); }
if (k != LV_LOCAL && isptr(xty)) effect_note_mask(effect_mask(rc), EF_RETAIN);
@@ -1491,7 +1553,7 @@ int assigncheck(int k, int i, int rc) {
lstate[i] = S_M; lused[i] = 0; lown[i] = 1;
lnsz[i] = lnsz[j]; lleaf[i] = lleaf[j];
local_ended[i] = 0; local_end_info[i] = 0;
- end_owner(j); luse(j); ev_put(j, EV_MOVE, i);
+ end_why = 3; end_whom = lname[i]; end_owner(j); luse(j); ev_put(j, EV_MOVE, i);
if (ltag[i] & 15) lstate[i] = ltag[i] & 15;
return C_PLAIN;
}
@@ -1499,7 +1561,7 @@ int assigncheck(int k, int i, int rc) {
lstate[i] = S_M;
lused[i] = 0;
lown[i] = 1;
- end_owner(j);
+ end_why = 3; end_whom = lname[i]; end_owner(j);
luse(j); ev_put(j, EV_UP, i);
if (ltag[i] & 15) lstate[i] = ltag[i] & 15;
return C_PLAIN;
@@ -1523,7 +1585,7 @@ int assigncheck(int k, int i, int rc) {
if (js == S_U) {
cerrn(j, "is u; it has to leave through the block above, not into a borrowed object");
}
- else { end_owner(j); luse(j); ev_put(j, EV_STORE, i); emitown(i); } // storing it gives it away
+ else { end_why = 4; end_whom = lname[i]; end_owner(j); luse(j); ev_put(j, EV_STORE, i); emitown(i); } // storing it gives it away
} else if (js != st) cerrn(j, "its tag doesn't match its container's (both have to be m, u or d)");
else if (lhome[j] < lhome[r]) cerrn(j, "lives in an outer block than the container it's stored into");
else { lstate[j] = S_CHILD; lowner[j] = i; luse(j); ev_put(j, EV_STORE, i); emitown(i); }
@@ -1535,7 +1597,7 @@ int assigncheck(int k, int i, int rc) {
if (j >= 0 && k == LV_GLOBAL && xlend == j && lstate[j] == S_M && lown[j]) { xlend = -1; touch(j); lend_add(i, j); return C_PLAIN; }
xlend = -1;
if (j >= 0) {
- if (lstate[j] == S_D || lstate[j] == S_U || (lstate[j] == S_M && lown[j])) { ev_put(j, EV_GLOBAL, -1); end_owner(j); luse(j); }
+ if (lstate[j] == S_D || lstate[j] == S_U || (lstate[j] == S_M && lown[j])) { ev_put(j, EV_GLOBAL, -1); end_why = 6; end_owner(j); luse(j); }
else cerrn(j, "is not an owner, so it can't be stored in a global or in untracked memory (the collector takes it over)");
}
return C_PLAIN;
@@ -1582,7 +1644,7 @@ int retcheck(int c) {
}
if (fret) {
if (i >= 0) {
- if (lstate[i] == S_U) { end_owner(i); luse(i); ev_put(i, EV_RETURN, -1); }
+ if (lstate[i] == S_U) { end_why = 5; end_owner(i); luse(i); ev_put(i, EV_RETURN, -1); }
else cerrn(i, "has to be u to be returned");
}
return 0;