mirror of
https://github.com/golang/go
synced 2024-11-20 10:34:42 -07:00
e431398e09
remove zerostack compiler experiment; will do at link time instead ««« original CL description cmd/gc: add GOEXPERIMENT=zerostack to clear stack on function entry This is expensive but it might be useful in cases where people are suffering from false positives during garbage collection and are willing to trade the CPU time for getting rid of the false positives. On the other hand it only eliminates false positives caused by other function calls, not false positives caused by dead temporaries stored in the current function call. The 5g/6g/8g changes were pulled out of the history, from the last time we needed to do this (to work around a goto bug). The code in go.h, lex.c, pgen.c is new but tiny. R=ken2 CC=golang-dev https://golang.org/cl/6938073 »»» R=ken2 CC=golang-dev https://golang.org/cl/7002051
231 lines
4.3 KiB
C
231 lines
4.3 KiB
C
// Copyright 2011 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
#include <u.h>
|
|
#include <libc.h>
|
|
#include "gg.h"
|
|
#include "opt.h"
|
|
|
|
static void allocauto(Prog* p);
|
|
|
|
void
|
|
compile(Node *fn)
|
|
{
|
|
Plist *pl;
|
|
Node nod1, *n;
|
|
Prog *ptxt;
|
|
int32 lno;
|
|
Type *t;
|
|
Iter save;
|
|
vlong oldstksize;
|
|
|
|
if(newproc == N) {
|
|
newproc = sysfunc("newproc");
|
|
deferproc = sysfunc("deferproc");
|
|
deferreturn = sysfunc("deferreturn");
|
|
panicindex = sysfunc("panicindex");
|
|
panicslice = sysfunc("panicslice");
|
|
throwreturn = sysfunc("throwreturn");
|
|
}
|
|
|
|
if(fn->nbody == nil)
|
|
return;
|
|
|
|
saveerrors();
|
|
|
|
// set up domain for labels
|
|
clearlabels();
|
|
|
|
lno = setlineno(fn);
|
|
|
|
curfn = fn;
|
|
dowidth(curfn->type);
|
|
|
|
if(curfn->type->outnamed) {
|
|
// add clearing of the output parameters
|
|
t = structfirst(&save, getoutarg(curfn->type));
|
|
while(t != T) {
|
|
if(t->nname != N) {
|
|
n = nod(OAS, t->nname, N);
|
|
typecheck(&n, Etop);
|
|
curfn->nbody = concat(list1(n), curfn->nbody);
|
|
}
|
|
t = structnext(&save);
|
|
}
|
|
}
|
|
|
|
order(curfn);
|
|
if(nerrors != 0)
|
|
goto ret;
|
|
|
|
hasdefer = 0;
|
|
walk(curfn);
|
|
if(nerrors != 0)
|
|
goto ret;
|
|
if(debug['b'])
|
|
racewalk(curfn);
|
|
if(nerrors != 0)
|
|
goto ret;
|
|
|
|
continpc = P;
|
|
breakpc = P;
|
|
|
|
pl = newplist();
|
|
pl->name = curfn->nname;
|
|
|
|
setlineno(curfn);
|
|
|
|
nodconst(&nod1, types[TINT32], 0);
|
|
ptxt = gins(ATEXT, isblank(curfn->nname) ? N : curfn->nname, &nod1);
|
|
if(fn->dupok)
|
|
ptxt->TEXTFLAG = DUPOK;
|
|
afunclit(&ptxt->from);
|
|
|
|
ginit();
|
|
|
|
for(t=curfn->paramfld; t; t=t->down)
|
|
gtrack(tracksym(t->type));
|
|
|
|
genlist(curfn->enter);
|
|
|
|
retpc = nil;
|
|
if(hasdefer || curfn->exit) {
|
|
Prog *p1;
|
|
|
|
p1 = gjmp(nil);
|
|
retpc = gjmp(nil);
|
|
patch(p1, pc);
|
|
}
|
|
|
|
genlist(curfn->nbody);
|
|
gclean();
|
|
checklabels();
|
|
if(nerrors != 0)
|
|
goto ret;
|
|
if(curfn->endlineno)
|
|
lineno = curfn->endlineno;
|
|
|
|
if(curfn->type->outtuple != 0)
|
|
ginscall(throwreturn, 0);
|
|
|
|
if(retpc)
|
|
patch(retpc, pc);
|
|
ginit();
|
|
if(hasdefer)
|
|
ginscall(deferreturn, 0);
|
|
if(curfn->exit)
|
|
genlist(curfn->exit);
|
|
gclean();
|
|
if(nerrors != 0)
|
|
goto ret;
|
|
|
|
pc->as = ARET; // overwrite AEND
|
|
pc->lineno = lineno;
|
|
|
|
if(!debug['N'] || debug['R'] || debug['P']) {
|
|
regopt(ptxt);
|
|
}
|
|
|
|
oldstksize = stksize;
|
|
allocauto(ptxt);
|
|
if(0)
|
|
print("allocauto: %lld to %lld\n", oldstksize, (vlong)stksize);
|
|
|
|
setlineno(curfn);
|
|
if((int64)stksize+maxarg > (1ULL<<31))
|
|
yyerror("stack frame too large (>2GB)");
|
|
|
|
defframe(ptxt);
|
|
|
|
if(0)
|
|
frame(0);
|
|
|
|
ret:
|
|
lineno = lno;
|
|
}
|
|
|
|
|
|
// Sort the list of stack variables. autos after anything else,
|
|
// within autos, unused after used, and within used on reverse alignment.
|
|
// non-autos sort on offset.
|
|
static int
|
|
cmpstackvar(Node *a, Node *b)
|
|
{
|
|
if (a->class != b->class)
|
|
return (a->class == PAUTO) ? 1 : -1;
|
|
if (a->class != PAUTO)
|
|
return a->xoffset - b->xoffset;
|
|
if ((a->used == 0) != (b->used == 0))
|
|
return b->used - a->used;
|
|
return b->type->align - a->type->align;
|
|
|
|
}
|
|
|
|
// TODO(lvd) find out where the PAUTO/OLITERAL nodes come from.
|
|
static void
|
|
allocauto(Prog* ptxt)
|
|
{
|
|
NodeList *ll;
|
|
Node* n;
|
|
vlong w;
|
|
|
|
if(curfn->dcl == nil)
|
|
return;
|
|
|
|
// Mark the PAUTO's unused.
|
|
for(ll=curfn->dcl; ll != nil; ll=ll->next)
|
|
if (ll->n->class == PAUTO)
|
|
ll->n->used = 0;
|
|
|
|
markautoused(ptxt);
|
|
|
|
listsort(&curfn->dcl, cmpstackvar);
|
|
|
|
// Unused autos are at the end, chop 'em off.
|
|
ll = curfn->dcl;
|
|
n = ll->n;
|
|
if (n->class == PAUTO && n->op == ONAME && !n->used) {
|
|
curfn->dcl = nil;
|
|
stksize = 0;
|
|
return;
|
|
}
|
|
|
|
for(ll = curfn->dcl; ll->next != nil; ll=ll->next) {
|
|
n = ll->next->n;
|
|
if (n->class == PAUTO && n->op == ONAME && !n->used) {
|
|
ll->next = nil;
|
|
curfn->dcl->end = ll;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Reassign stack offsets of the locals that are still there.
|
|
stksize = 0;
|
|
for(ll = curfn->dcl; ll != nil; ll=ll->next) {
|
|
n = ll->n;
|
|
if (n->class != PAUTO || n->op != ONAME)
|
|
continue;
|
|
|
|
dowidth(n->type);
|
|
w = n->type->width;
|
|
if(w >= MAXWIDTH || w < 0)
|
|
fatal("bad width");
|
|
stksize += w;
|
|
stksize = rnd(stksize, n->type->align);
|
|
if(thechar == '5')
|
|
stksize = rnd(stksize, widthptr);
|
|
n->stkdelta = -stksize - n->xoffset;
|
|
}
|
|
|
|
fixautoused(ptxt);
|
|
|
|
// The debug information needs accurate offsets on the symbols.
|
|
for(ll = curfn->dcl ;ll != nil; ll=ll->next) {
|
|
if (ll->n->class != PAUTO || ll->n->op != ONAME)
|
|
continue;
|
|
ll->n->xoffset += ll->n->stkdelta;
|
|
ll->n->stkdelta = 0;
|
|
}
|
|
}
|