aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler/lex.zc6
-rw-r--r--src/compiler/stmt.zc12
-rw-r--r--src/runtime/rt.zc14
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.