diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/compiler/lex.zc | 6 | ||||
| -rw-r--r-- | src/compiler/stmt.zc | 12 | ||||
| -rw-r--r-- | src/runtime/rt.zc | 14 |
3 files changed, 24 insertions, 8 deletions
diff --git a/src/compiler/lex.zc b/src/compiler/lex.zc index 712eff8..95415a6 100644 --- a/src/compiler/lex.zc +++ b/src/compiler/lex.zc @@ -533,8 +533,9 @@ int lex1() { while (isidc(ch)) { n = token_char(n, ch); nextch(); } tbuf[n] = 0; if (n == 1 && tbuf[0] == 'b' && ch == 34) { - n = 0; nextch(); + n = 0; dg = line; nextch(); while (ch >= 0 && ch != 34) { v = escch(); n = token_char(n, v); } + if (ch < 0) { tline = dg; serr("unterminated string literal"); } // spec 1.4.4 nextch(); tbuf[n] = 0; tk = T_BSTR; tv = intern(tbuf); return 0; @@ -556,8 +557,9 @@ int lex1() { return 0; } if (ch == 34) { - nextch(); + dg = line; nextch(); while (ch >= 0 && ch != 34) { v = escch(); n = token_char(n, v); } + if (ch < 0) { tline = dg; serr("unterminated string literal"); } // spec 1.4.4 nextch(); tbuf[n] = 0; tk = T_STR; tv = intern(tbuf); return 0; diff --git a/src/compiler/stmt.zc b/src/compiler/stmt.zc index e98cb27..79e5fb8 100644 --- a/src/compiler/stmt.zc +++ b/src/compiler/stmt.zc @@ -566,11 +566,19 @@ int casebody(int s0, int live0) { live = 0; return 0; } +// a case label seen twice in one switch is an error (spec 4.7.2): the second +// arm could never run. the first 256 labels of a switch are checked. +int case_seen(word seen, int n, int v) { + int i = 0; + while (i < n) { if (seen[i] == v) { serr("duplicate case label"); return n; } i++; } + if (n < 256) { seen[n] = v; n++; } + return n; +} // compile a switch statement. int kw_switch() { int sl = tline; int save = nloc, tmp, c, s0, live0, defent = -1, skip, nxt, bj, v, a = -1, st, tg = 0, cov = 0, gi, nb = 0, j, arm, bi; - word[8] pbn; word[8] pbl; + word[8] pbn; word[8] pbl; word[256] seen; int nseen = 0; stmtonly(); next(); expect(s_lp); c = expr(); st = xty; rval(); plainuse(c); expect(s_rp); @@ -609,6 +617,7 @@ int kw_switch() { expect(s_rp); if (nb && nb != pm_nf[gi]) serr("a case binds every field of its member"); // member() with no names matches by tag (spec 4.7.3) v = pm_tag[gi]; + nseen = case_seen(seen, nseen, v); if (v < 63) cov = cov | (1 << v); laddr(lslot[tmp]); op(O_LD); op(O_LD); lit(v); op(O_SUB); bj = fixnew(hole(), bj); op(O_JZ); @@ -633,6 +642,7 @@ int kw_switch() { } else { while (1) { v = cexpr(); + nseen = case_seen(seen, nseen, v); if (tg && v >= 0 && v < 63) cov = cov | (1 << v); laddr(lslot[tmp]); op(O_LD); if (tg) op(O_LD); diff --git a/src/runtime/rt.zc b/src/runtime/rt.zc index 149138b..4f96320 100644 --- a/src/runtime/rt.zc +++ b/src/runtime/rt.zc @@ -428,7 +428,7 @@ const int F_SHARE = 8; // table (dtab), its drop has run (it never runs again), and the collector found it // unreachable and runs its drop once the sweep is over. const int F_HASDROP = 16, F_DROPPED = 32, F_FINAL = 64, F_CYCLE = 128; // F_CYCLE: during gc_drops only, a candidate its own contents reach -int o3_depth, gc_pending; +int o3_depth, gc_pending, gc_cyc; // gc_cyc: the last sweep found a cycle with drops to run // flags live in these bits; the size class is above them. const int F_LOW = 65535; int hbump; word[32] freel; int gc_runs, gc_freed, gc_auto = 1; @@ -1456,7 +1456,7 @@ int o3_leave() { // an unreachable value with a drop that hasn't run is kept for one more cycle and // flagged F_FINAL, unless another such value reaches it (its parent drops first and // it waits for a later collection) and it doesn't reach itself (a cycle drops one -// value per collection). nothing runs user code here. +// value per sweep, and gc() repeats the sweep until the cycle is done). nothing runs user code here. int gc_drops() { int i, again = 1; word k; while (again) { @@ -1486,9 +1486,9 @@ int gc_drops() { k = dtab[i * 3]; if (k > 1 && (k[-4] & F_FINAL)) { // reached from another candidate: later. one in a cycle has nothing outside it - // to drop first, so it drops now (it is marked, so kept), and the rest of the - // cycle in later collections, one each, never twice - if ((k[-4] & 7) == 1) mark(k); else if (!(k[-4] & F_CYCLE)) k[-4] = k[-4] & ~F_FINAL; + // to drop first, so it drops now (it is marked, so kept); gc() then sweeps again + // for the rest of the cycle, one each, never twice + if ((k[-4] & 7) == 1) mark(k); else if (!(k[-4] & F_CYCLE)) k[-4] = k[-4] & ~F_FINAL; else gc_cyc = 1; k[-4] = k[-4] & ~F_CYCLE; } i++; @@ -1549,8 +1549,12 @@ unchecked int gc_sweep() { unchecked int gc() { int n; if (o3_depth) { gc_pending = 1; return 0; } + gc_cyc = 0; n = gc_sweep(); if (dcount) gc_finalize(); + // an unreachable cycle with drops finishes in this collection: each sweep drops one + // member (nothing outside the cycle has to go first), and every value drops once + while (gc_cyc) { gc_cyc = 0; n = n + gc_sweep(); if (dcount) gc_finalize(); } return n; } // the number of live heap objects, for tests and leak checks. |
