diff options
Diffstat (limited to 'src/compiler/base.zc')
| -rw-r--r-- | src/compiler/base.zc | 54 |
1 files changed, 45 insertions, 9 deletions
diff --git a/src/compiler/base.zc b/src/compiler/base.zc index dc786b5..7e4b5bc 100644 --- a/src/compiler/base.zc +++ b/src/compiler/base.zc @@ -254,7 +254,7 @@ int fn_return_type; // a consistent return type inferred from the function body // effects come from the real compiler's uses, stores, returns and call edges; unknown bodies stay conservative. const int EF_READ = 1, EF_WRITE = 2, EF_RETAIN = 4, EF_CONSUME = 8, EF_UNKNOWN = 16, EF_ALIAS = 32, EF_IDENTITY = 64; word effect_symbols, effect_edges, effect_requirements, effect_current; int effect_floor, effect_argument_base; -word local_origin, local_origin_mask, local_cell, local_captured, local_ended, local_end_info; word effect_value, argorigin_mask; int capture_enabled; word[1] capture_dummy; +word local_origin, local_origin_mask, local_cell, local_captured, local_ended, local_end_info, local_shadow, xshadow, effect_shadows; int argowner_mask; word effect_value, argorigin_mask; int capture_enabled; word[1] capture_dummy; // drops (docs/design/destructors.md): the code position just past a drop form (a fresh // value with a drop still on the stack there), the type `this` gets in the next closure, // a local whose drop is set, a mailbox send whose arguments are checked, and o3 block depth. @@ -415,6 +415,11 @@ int s_new_k, s_recycle_leaf; // server streams diagnostics and drops a check whose source has been replaced word chk_hook; int cmode, chkabort, chkfuel; word dgbuf, dggrow; int dgcap, dgpos, dgn, dgopen, dgprev, dgmode; +// related places of check-mode records, for the editor: DGREL_W words each, [the record's +// offset in dgbuf, the packed place where the owner ended, the packed place of the owner's +// declaration, how it ended (end_why), the owner's name]. reset by chk_begin. +const int DGREL_W = 5; +word dgrel; int dgreln, dgrelcap; // expand a diagnostic in progress, keeping its output offset within the buffer. int dg_expand() { dgbuf = chk_resize(dgbuf, dgpos + 5 + rt.outn, dgcap * 2); @@ -433,8 +438,22 @@ int dg_expand() { int probe_off = -1, probe_has, probe_n, probe_cap, probe_static; char** probe_name; word probe_kind, probe_state, probe_type, probe_decl, probe_mem; char* curinc; int incdepth, dgdrop; int incplace; // how many includes deep the compile is; a record to throw away; the place of the outermost include +// an open record's range becomes the packed place p (the use itself, not the token after it). +int dg_place(int p) { + if (!cmode || !dgopen || incdepth > 0 || !p || (p & 0xFFFFFF) != tline) return 0; + dgbuf[dgpos + 1] = p & 0xFFFFFF; dgbuf[dgpos + 2] = ((p >> 40) & 0x1FFFFF) - 1; dgbuf[dgpos + 3] = (p >> 24) & 0xFFFF; + return 0; +} +int dg_related(int end_place, int decl_place, int why, char* owner) { + if (!cmode || !dgopen || dgdrop || incdepth > 0) return 0; + if (dgreln == dgrelcap) { int cap = dgrelcap * 2; if (!cap) cap = 16; dgrel = chk_resize(dgrel, dgreln * DGREL_W, cap * DGREL_W); dgrelcap = cap; } + word e = dgrel + dgreln * DGREL_W; + e[0] = dgpos; e[1] = end_place; e[2] = decl_place; e[3] = why; e[4] = owner; dgreln++; + return 0; +} int dg_close() { if (!dgopen) return 0; + if (dgdrop && dgreln && dgrel[(dgreln - 1) * DGREL_W] == dgpos) dgreln--; // its record is thrown away if (!dgdrop) { dgbuf[dgpos + 4] = rt.outn; dgpos = dgpos + 5 + rt.outn; dgn++; } dgdrop = 0; dgopen = 0; rt.outmode = dgmode; rt.outgrow = dggrow; @@ -470,7 +489,7 @@ word[256] dgseen_initial; word dgseen = dgseen_initial; int dgseen_cap = 256, dg // start and stop a check run. chk_begin points the diagnostics at a buffer // the caller owns; chk_end flushes any open record and restores output. int chk_begin(int buf, int cap) { - cmode = 1; chkabort = 0; chkfuel = 0; dgbuf = buf; dgcap = cap; dgpos = 0; dgn = 0; dgopen = 0; + cmode = 1; chkabort = 0; chkfuel = 0; dgbuf = buf; dgcap = cap; dgpos = 0; dgn = 0; dgopen = 0; dgreln = 0; nerr = 0; panic = 0; dgmode = rt.outmode; rt.fill_w(dgseen, 0, dgseen_cap); dgseen_n = 0; return 0; } @@ -758,6 +777,7 @@ int reserve_locals(int need) { if (local_captured) local_captured = chk_resize(local_captured, nloc, cap); if (local_ended) local_ended = chk_resize(local_ended, nloc, cap); if (local_end_info) local_end_info = chk_resize(local_end_info, nloc, cap); + if (local_shadow) local_shadow = chk_resize(local_shadow, nloc, cap); lafact = chk_resize(lafact, nloc, cap); laaddr = chk_resize(laaddr, nloc, cap); lprev = chk_resize(lprev, nloc, cap); if (lvkind) { lvkind = chk_resize(lvkind, nloc, cap); lvvalue = chk_resize(lvvalue, nloc, cap); lvescaped = chk_resize(lvescaped, nloc, cap); } o3cache = chk_resize(o3cache, nloc, cap); @@ -958,6 +978,27 @@ int cerr(char* msg) { if (fchk && live) serr(msg); return 0; } +// how an owner ended, from end_owner's record: the use, the owner, what ended it and where. +// "r: used after it was given away; r borrows t, and t was freed on line 5 (t declared on line 4)" +int ended_message(char* use, word info, char* root, int cause) { + char* owner = root; int why = 0; char* whom = 0; + if (info) { owner = info[0]; why = info[3]; whom = info[4]; dg_related(info[5], info[1], why, owner); } + rt.put_s(use); rt.put_s(": used after it was given away; "); + if (!rt.eq_w(use, owner)) { rt.put_s(use); rt.put_s(" borrows "); rt.put_s(owner); rt.put_s(", and "); } + rt.put_s(owner); + if (why == 1) rt.put_s(" was freed"); + else if (why == 2) { rt.put_s(" was given to "); rt.put_s(whom); rt.put_s("'s .d parameter"); } + else if (why == 3) { rt.put_s(" was moved into "); rt.put_s(whom); } + else if (why == 4) { rt.put_s(" was stored into "); rt.put_s(whom); } + else if (why == 5) rt.put_s(" was returned"); + else if (why == 6) rt.put_s(" was stored in a global or untracked memory"); + else if (why == 7) rt.put_s(" was freed by reassigning it"); + else if (why == 8) rt.put_s(" was pushed into an array"); + else rt.put_s(" was transferred"); + rt.put_s(" on line "); rt.put_n(cause & 0xFFFFFF); + if (info && info[1]) { rt.put_s(" ("); if (!rt.eq_w(use, owner)) { rt.put_s(owner); rt.put_c(' '); } rt.put_s("declared on line "); rt.put_n(info[1] & 0xFFFFFF); rt.put_c(')'); } + return 0; +} // report an analyzer error about local i, named in the message. int cerrn(int i, char* msg) { int root = i, cause = 0; word info = 0; @@ -967,13 +1008,8 @@ int cerrn(int i, char* msg) { if (!info && local_end_info) info = local_end_info[root]; if (info) cause = info[2]; else if (local_ended) cause = local_ended[root]; } - if (cause && !panic && !dry) { - errat(); rt.put_s(lname[i]); rt.put_s(": "); rt.put_s(msg); - rt.put_s("; owner "); if (info) rt.put_s(info[0]); else rt.put_s(lname[root]); - rt.put_s(" was transferred on line "); rt.put_n(cause & 0xFFFFFF); - if (info && info[1]) { rt.put_s(" (declared on line "); rt.put_n(info[1] & 0xFFFFFF); rt.put_c(')'); } - errend(); - } else serrn(lname[i], msg); + if (cause && !panic && !dry) { errat(); dg_place(lreadpos[i]); ended_message(lname[i], info, lname[root], cause); errend(); } + else serrn(lname[i], msg); } return 0; } |
