This source file includes following definitions.
- makefuncdatasym
- gvardefx
- gvardef
- gvarkill
- removevardef
- gcsymdup
- compile
- cmpstackvar
- allocauto
- movelarge
- movelargefn
- cgen_checknil
#include <u.h>
#include <libc.h>
#include "md5.h"
#include "gg.h"
#include "opt.h"
#include "../../pkg/runtime/funcdata.h"
static void allocauto(Prog* p);
static Sym*
makefuncdatasym(char *namefmt, int64 funcdatakind)
{
Node nod;
Node *pnod;
Sym *sym;
static int32 nsym;
snprint(namebuf, sizeof(namebuf), namefmt, nsym++);
sym = lookup(namebuf);
pnod = newname(sym);
pnod->class = PEXTERN;
nodconst(&nod, types[TINT32], funcdatakind);
gins(AFUNCDATA, &nod, pnod);
return sym;
}
static void
gvardefx(Node *n, int as)
{
if(n == N)
fatal("gvardef nil");
if(n->op != ONAME) {
yyerror("gvardef %#O; %N", n->op, n);
return;
}
switch(n->class) {
case PAUTO:
case PPARAM:
case PPARAMOUT:
gins(as, N, n);
}
}
void
gvardef(Node *n)
{
gvardefx(n, AVARDEF);
}
void
gvarkill(Node *n)
{
gvardefx(n, AVARKILL);
}
static void
removevardef(Prog *firstp)
{
Prog *p;
for(p = firstp; p != P; p = p->link) {
while(p->link != P && (p->link->as == AVARDEF || p->link->as == AVARKILL))
p->link = p->link->link;
if(p->to.type == D_BRANCH)
while(p->to.u.branch != P && (p->to.u.branch->as == AVARDEF || p->to.u.branch->as == AVARKILL))
p->to.u.branch = p->to.u.branch->link;
}
}
static void
gcsymdup(Sym *s)
{
LSym *ls;
uint64 lo, hi;
ls = linksym(s);
if(ls->nr > 0)
fatal("cannot rosymdup %s with relocations", ls->name);
MD5 d;
md5reset(&d);
md5write(&d, ls->p, ls->np);
lo = md5sum(&d, &hi);
ls->name = smprint("gclocals·%016llux%016llux", lo, hi);
ls->dupok = 1;
}
void
compile(Node *fn)
{
Plist *pl;
Node nod1, *n;
Prog *ptxt, *p;
int32 lno;
Type *t;
Iter save;
vlong oldstksize;
NodeList *l;
Sym *gcargs;
Sym *gclocals;
if(newproc == N) {
newproc = sysfunc("newproc");
deferproc = sysfunc("deferproc");
deferreturn = sysfunc("deferreturn");
panicindex = sysfunc("panicindex");
panicslice = sysfunc("panicslice");
throwreturn = sysfunc("throwreturn");
}
lno = setlineno(fn);
if(fn->nbody == nil) {
if(pure_go || strncmp(fn->nname->sym->name, "init·", 6) == 0)
yyerror("missing function body", fn);
goto ret;
}
saveerrors();
clearlabels();
curfn = fn;
dowidth(curfn->type);
if(curfn->type->outnamed) {
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(flag_race)
racewalk(curfn);
if(nerrors != 0)
goto ret;
continpc = P;
breakpc = P;
pl = newplist();
pl->name = linksym(curfn->nname->sym);
setlineno(curfn);
nodconst(&nod1, types[TINT32], 0);
ptxt = gins(ATEXT, isblank(curfn->nname) ? N : curfn->nname, &nod1);
if(fn->dupok)
ptxt->TEXTFLAG |= DUPOK;
if(fn->wrapper)
ptxt->TEXTFLAG |= WRAPPER;
if(fn->needctxt)
ptxt->TEXTFLAG |= NEEDCTXT;
if(myimportpath != nil && strcmp(myimportpath, "reflect") == 0) {
if(strcmp(curfn->nname->sym->name, "callReflect") == 0 || strcmp(curfn->nname->sym->name, "callMethod") == 0)
ptxt->TEXTFLAG |= WRAPPER;
}
afunclit(&ptxt->from, curfn->nname);
ginit();
gcargs = makefuncdatasym("gcargs·%d", FUNCDATA_ArgsPointerMaps);
gclocals = makefuncdatasym("gclocals·%d", FUNCDATA_LocalsPointerMaps);
for(t=curfn->paramfld; t; t=t->down)
gtrack(tracksym(t->type));
for(l=fn->dcl; l; l=l->next) {
n = l->n;
if(n->op != ONAME)
continue;
switch(n->class) {
case PAUTO:
case PPARAM:
case PPARAMOUT:
nodconst(&nod1, types[TUINTPTR], l->n->type->width);
p = gins(ATYPE, l->n, &nod1);
p->from.gotype = linksym(ngotype(l->n));
break;
}
}
genlist(curfn->enter);
genlist(curfn->nbody);
gclean();
checklabels();
if(nerrors != 0)
goto ret;
if(curfn->endlineno)
lineno = curfn->endlineno;
if(curfn->type->outtuple != 0)
ginscall(throwreturn, 0);
ginit();
cgen_ret(nil);
if(hasdefer) {
if(maxarg < widthptr)
maxarg = widthptr;
}
gclean();
if(nerrors != 0)
goto ret;
pc->as = ARET;
pc->lineno = lineno;
fixjmp(ptxt);
if(!debug['N'] || debug['R'] || debug['P']) {
regopt(ptxt);
nilopt(ptxt);
}
expandchecks(ptxt);
oldstksize = stksize;
allocauto(ptxt);
if(0)
print("allocauto: %lld to %lld\n", oldstksize, (vlong)stksize);
USED(oldstksize);
setlineno(curfn);
if((int64)stksize+maxarg > (1ULL<<31)) {
yyerror("stack frame too large (>2GB)");
goto ret;
}
liveness(curfn, ptxt, gcargs, gclocals);
gcsymdup(gcargs);
gcsymdup(gclocals);
defframe(ptxt);
if(0)
frame(0);
removevardef(ptxt);
ret:
lineno = lno;
}
static int
cmpstackvar(Node *a, Node *b)
{
int ap, bp;
if (a->class != b->class)
return (a->class == PAUTO) ? +1 : -1;
if (a->class != PAUTO) {
if (a->xoffset < b->xoffset)
return -1;
if (a->xoffset > b->xoffset)
return +1;
return 0;
}
if ((a->used == 0) != (b->used == 0))
return b->used - a->used;
ap = haspointers(a->type);
bp = haspointers(b->type);
if(ap != bp)
return bp - ap;
ap = a->needzero;
bp = b->needzero;
if(ap != bp)
return bp - ap;
if(a->type->width < b->type->width)
return +1;
if(a->type->width > b->type->width)
return -1;
return strcmp(a->sym->name, b->sym->name);
}
static void
allocauto(Prog* ptxt)
{
NodeList *ll;
Node* n;
vlong w;
stksize = 0;
stkptrsize = 0;
if(curfn->dcl == nil)
return;
for(ll=curfn->dcl; ll != nil; ll=ll->next)
if (ll->n->class == PAUTO)
ll->n->used = 0;
markautoused(ptxt);
listsort(&curfn->dcl, cmpstackvar);
ll = curfn->dcl;
n = ll->n;
if (n->class == PAUTO && n->op == ONAME && !n->used) {
curfn->dcl = nil;
fixautoused(ptxt);
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;
}
}
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(haspointers(n->type))
stkptrsize = stksize;
if(thechar == '5')
stksize = rnd(stksize, widthptr);
if(stksize >= (1ULL<<31)) {
setlineno(curfn);
yyerror("stack frame too large (>2GB)");
}
n->stkdelta = -stksize - n->xoffset;
}
stksize = rnd(stksize, widthreg);
stkptrsize = rnd(stkptrsize, widthreg);
fixautoused(ptxt);
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;
}
}
static void movelargefn(Node*);
void
movelarge(NodeList *l)
{
for(; l; l=l->next)
if(l->n->op == ODCLFUNC)
movelargefn(l->n);
}
static void
movelargefn(Node *fn)
{
NodeList *l;
Node *n;
for(l=fn->dcl; l != nil; l=l->next) {
n = l->n;
if(n->class == PAUTO && n->type != T && n->type->width > MaxStackVarSize)
addrescapes(n);
}
}
void
cgen_checknil(Node *n)
{
Node reg;
if(disable_checknil)
return;
if(n->type == T || (!isptr[n->type->etype] && !isint[n->type->etype] && n->type->etype != TUNSAFEPTR)) {
dump("checknil", n);
fatal("bad checknil");
}
if((thechar == '5' && n->op != OREGISTER) || !n->addable || n->op == OLITERAL) {
regalloc(®, types[tptr], n);
cgen(n, ®);
gins(ACHECKNIL, ®, N);
regfree(®);
return;
}
gins(ACHECKNIL, n, N);
}