diff options
Diffstat (limited to 'src/compiler/analyzer.zc')
| -rw-r--r-- | src/compiler/analyzer.zc | 80 |
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; |
