diff options
Diffstat (limited to 'src/cmd/gc/gen.c')
-rw-r--r-- | src/cmd/gc/gen.c | 95 |
1 files changed, 64 insertions, 31 deletions
diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c index ada16eacc..cf630f348 100644 --- a/src/cmd/gc/gen.c +++ b/src/cmd/gc/gen.c @@ -301,6 +301,9 @@ gen(Node *n) break; case OLABEL: + if(isblanksym(n->left->sym)) + break; + lab = newlab(n); // if there are pending gotos, resolve them all to the current pc. @@ -495,6 +498,11 @@ gen(Node *n) case OCHECKNIL: cgen_checknil(n->left); + break; + + case OVARKILL: + gvarkill(n->left); + break; } ret: @@ -562,8 +570,7 @@ cgen_proc(Node *n, int proc) /* * generate declaration. - * nothing to do for on-stack automatics, - * but might have to allocate heap copy + * have to allocate heap copy * for escaped variables. */ static void @@ -739,6 +746,8 @@ cgen_as(Node *nl, Node *nr) if(tl == T) return; if(isfat(tl)) { + if(nl->op == ONAME) + gvardef(nl); clearfat(nl); return; } @@ -767,10 +776,18 @@ cgen_eface(Node *n, Node *res) * so it's important that it is done first */ Node dst; + Node *tmp; + + tmp = temp(types[tptr]); + cgen(n->right, tmp); + + gvardef(res); + dst = *res; dst.type = types[tptr]; dst.xoffset += widthptr; - cgen(n->right, &dst); + cgen(tmp, &dst); + dst.xoffset -= widthptr; cgen(n->left, &dst); } @@ -787,7 +804,7 @@ cgen_eface(Node *n, Node *res) void cgen_slice(Node *n, Node *res) { - Node src, dst, *cap, *len, *offs, *add; + Node src, dst, *cap, *len, *offs, *add, *base; cap = n->list->n; len = n->list->next->n; @@ -795,24 +812,15 @@ cgen_slice(Node *n, Node *res) if(n->list->next->next) offs = n->list->next->next->n; - // dst.len = hi [ - lo ] - dst = *res; - dst.xoffset += Array_nel; - dst.type = types[simtype[TUINT]]; - cgen(len, &dst); - - if(n->op != OSLICESTR) { - // dst.cap = cap [ - lo ] - dst = *res; - dst.xoffset += Array_cap; - dst.type = types[simtype[TUINT]]; - cgen(cap, &dst); - } - - // dst.array = src.array [ + lo *width ] - dst = *res; - dst.xoffset += Array_array; - dst.type = types[TUINTPTR]; + // evaluate base pointer first, because it is the only + // possibly complex expression. once that is evaluated + // and stored, updating the len and cap can be done + // without making any calls, so without doing anything that + // might cause preemption or garbage collection. + // this makes the whole slice update atomic as far as the + // garbage collector can see. + + base = temp(types[TUINTPTR]); if(isnil(n->left)) { tempname(&src, n->left->type); @@ -821,24 +829,49 @@ cgen_slice(Node *n, Node *res) src = *n->left; if(n->op == OSLICE || n->op == OSLICE3 || n->op == OSLICESTR) src.xoffset += Array_array; - src.type = types[TUINTPTR]; if(n->op == OSLICEARR || n->op == OSLICE3ARR) { if(!isptr[n->left->type->etype]) fatal("slicearr is supposed to work on pointer: %+N\n", n); - cgen(&src, &dst); - cgen_checknil(&dst); + cgen(&src, base); + cgen_checknil(base); if(offs != N) { - add = nod(OADD, &dst, offs); + add = nod(OADD, base, offs); typecheck(&add, Erv); - cgen(add, &dst); + cgen(add, base); } } else if(offs == N) { - cgen(&src, &dst); + src.type = types[tptr]; + cgen(&src, base); } else { - add = nod(OADD, &src, offs); + src.type = types[tptr]; + add = nod(OADDPTR, &src, offs); typecheck(&add, Erv); - cgen(add, &dst); + cgen(add, base); + } + + // committed to the update + gvardef(res); + + // dst.array = src.array [ + lo *width ] + dst = *res; + dst.xoffset += Array_array; + dst.type = types[tptr]; + + cgen(base, &dst); + + // dst.len = hi [ - lo ] + dst = *res; + dst.xoffset += Array_nel; + dst.type = types[simtype[TUINT]]; + cgen(len, &dst); + + if(n->op != OSLICESTR) { + // dst.cap = cap [ - lo ] + dst = *res; + dst.xoffset += Array_cap; + dst.type = types[simtype[TUINT]]; + cgen(cap, &dst); } } @@ -935,5 +968,5 @@ temp(Type *t) n = nod(OXXX, N, N); tempname(n, t); n->sym->def->used = 1; - return n; + return n->orig; } |