diff options
Diffstat (limited to 'src/cmd/gc')
-rw-r--r-- | src/cmd/gc/Makefile | 2 | ||||
-rw-r--r-- | src/cmd/gc/align.c | 12 | ||||
-rw-r--r-- | src/cmd/gc/closure.c | 44 | ||||
-rw-r--r-- | src/cmd/gc/const.c | 4 | ||||
-rw-r--r-- | src/cmd/gc/dcl.c | 28 | ||||
-rw-r--r-- | src/cmd/gc/gen.c | 4 | ||||
-rw-r--r-- | src/cmd/gc/go.h | 14 | ||||
-rw-r--r-- | src/cmd/gc/go.y | 1 | ||||
-rw-r--r-- | src/cmd/gc/init.c | 5 | ||||
-rw-r--r-- | src/cmd/gc/lex.c | 16 | ||||
-rw-r--r-- | src/cmd/gc/obj.c | 1 | ||||
-rw-r--r-- | src/cmd/gc/pgen.c | 119 | ||||
-rw-r--r-- | src/cmd/gc/sinit.c | 4 | ||||
-rw-r--r-- | src/cmd/gc/subr.c | 3 | ||||
-rw-r--r-- | src/cmd/gc/typecheck.c | 59 | ||||
-rw-r--r-- | src/cmd/gc/walk.c | 18 |
16 files changed, 289 insertions, 45 deletions
diff --git a/src/cmd/gc/Makefile b/src/cmd/gc/Makefile index dbfd86474..286618ec1 100644 --- a/src/cmd/gc/Makefile +++ b/src/cmd/gc/Makefile @@ -49,7 +49,7 @@ include ../../Make.clib install: $(LIB) y1.tab.c: y.tab.c # make yystate global, yytname mutable - cat y.tab.c | sed '/ int yystate;/d; s/int yychar;/int yychar, yystate;/; s/static const char \*const yytname/const char *yytname/' >y1.tab.c + cat y.tab.c | sed '/ int yystate;/d; s/int yychar;/int yychar, yystate;/; s/static const char \*const yytname/const char *yytname/; s/char const \*yymsgp/char *yymsgp/' >y1.tab.c yerr.h: bisonerrors go.errors y.tab.h # y.tab.h rule generates y.output too awk -f bisonerrors y.output go.errors >yerr.h diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c index a8454bf13..7fcac4833 100644 --- a/src/cmd/gc/align.c +++ b/src/cmd/gc/align.c @@ -234,9 +234,11 @@ dowidth(Type *t) if(t->bound > cap) yyerror("type %lT larger than address space", t); w = t->bound * t->type->width; - if(w == 0) - w = 1; t->align = t->type->align; + if(w == 0) { + w = 1; + t->align = 1; + } } else if(t->bound == -1) { w = sizeof_Array; @@ -253,10 +255,10 @@ dowidth(Type *t) if(t->funarg) fatal("dowidth fn struct %T", t); w = widstruct(t, 0, 1); - if(w == 0) + if(w == 0) { w = 1; - //if(t->align < widthptr) - // warn("align %d: %T\n", t->align, t); + t->align = 1; + } break; case TFUNC: diff --git a/src/cmd/gc/closure.c b/src/cmd/gc/closure.c index eb7014366..906dadbc9 100644 --- a/src/cmd/gc/closure.c +++ b/src/cmd/gc/closure.c @@ -75,7 +75,7 @@ closurebody(NodeList *body) } void -typecheckclosure(Node *func) +typecheckclosure(Node *func, int top) { Node *oldfn; NodeList *l; @@ -106,6 +106,10 @@ typecheckclosure(Node *func) v->op = 0; continue; } + // For a closure that is called in place, but not + // inside a go statement, avoid moving variables to the heap. + if ((top & (Ecall|Eproc)) == Ecall) + v->heapaddr->etype = 1; typecheck(&v->heapaddr, Erv); func->enter = list(func->enter, v->heapaddr); v->heapaddr = N; @@ -199,3 +203,41 @@ walkclosure(Node *func, NodeList **init) walkexpr(&call, init); return call; } + +// Special case for closures that get called in place. +// Optimize runtime.closure(X, __func__xxxx_, .... ) away +// to __func__xxxx_(Y ....). +// On entry, expect n->op == OCALL, n->left->op == OCLOSURE. +void +walkcallclosure(Node *n, NodeList **init) +{ + Node *z; + NodeList *ll, *cargs; + + walkexpr(&n->left, init); + cargs = n->left // FUNC runtime.closure + ->list // arguments + ->next // skip first + ->next; // skip second + + n->left = n->left // FUNC runtime.closure + ->list // arguments + ->next // skip first + ->n // AS (to indreg) + ->right; // argument == the generated function + + // New arg list for n. First the closure-args, stolen from + // runtime.closure's 3rd and following, + ll = nil; + for (; cargs; cargs = cargs->next) + ll = list(ll, cargs->n->right); // cargs->n is the OAS(INDREG, arg) + + // then an extra zero, to fill the dummy return pointer slot, + z = nod(OXXX, N, N); + nodconst(z, types[TUINTPTR], 0); + z->typecheck = 1; + ll = list(ll, z); + + // and finally the original parameter list. + n->list = concat(ll, n->list); +} diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c index a36ec68c0..8fe9072b2 100644 --- a/src/cmd/gc/const.c +++ b/src/cmd/gc/const.c @@ -103,6 +103,8 @@ convlit1(Node **np, Type *t, int explicit) case ORSH: convlit1(&n->left, t, explicit && isideal(n->left->type)); t = n->left->type; + if(t != T && t->etype == TIDEAL && n->val.ctype != CTINT) + n->val = toint(n->val); if(t != T && !isint[t->etype]) { yyerror("invalid operation: %#N (shift of type %T)", n, t); t = T; @@ -514,6 +516,8 @@ evconst(Node *n) n->right = nr; if(nr->type && (issigned[nr->type->etype] || !isint[nr->type->etype])) goto illegal; + nl->val = toint(nl->val); + nr->val = toint(nr->val); break; } diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c index 99af18d9f..78c676346 100644 --- a/src/cmd/gc/dcl.c +++ b/src/cmd/gc/dcl.c @@ -188,6 +188,7 @@ declare(Node *n, int ctxt) else if(n->op == ONAME) gen = ++vargen; pushdcl(s); + n->curfn = curfn; } if(ctxt == PAUTO) n->xoffset = BADWIDTH; @@ -524,6 +525,30 @@ colas(NodeList *left, NodeList *right) } /* + * declare the arguments in an + * interface field declaration. + */ +void +ifacedcl(Node *n) +{ + if(n->op != ODCLFIELD || n->right == N) + fatal("ifacedcl"); + + dclcontext = PAUTO; + markdcl(); + funcdepth++; + n->outer = curfn; + curfn = n; + funcargs(n->right); + + // funcbody is normally called after the parser has + // seen the body of a function but since an interface + // field declaration does not have a body, we must + // call it now to pop the current declaration context. + funcbody(n); +} + +/* * declare the function proper * and declare the arguments. * called in extern-declaration context @@ -1226,9 +1251,6 @@ funccompile(Node *n, int isclosure) if(curfn) fatal("funccompile %S inside %S", n->nname->sym, curfn->nname->sym); - curfn = n; - typechecklist(n->nbody, Etop); - curfn = nil; stksize = 0; dclcontext = PAUTO; diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c index 8ad6c437d..0b6f5bbd8 100644 --- a/src/cmd/gc/gen.c +++ b/src/cmd/gc/gen.c @@ -59,6 +59,8 @@ allocparams(void) fatal("bad width"); stksize += w; stksize = rnd(stksize, n->type->align); + if(thechar == '5') + stksize = rnd(stksize, widthptr); n->xoffset = -stksize; } lineno = lno; @@ -698,6 +700,8 @@ tempname(Node *n, Type *t) w = t->width; stksize += w; stksize = rnd(stksize, t->align); + if(thechar == '5') + stksize = rnd(stksize, widthptr); n->xoffset = -stksize; n->pun = anyregalloc(); } diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index 359881e11..f5c0443f8 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -254,6 +254,7 @@ struct Node Node* ntype; Node* defn; Node* pack; // real package for import . names + Node* curfn; // function for local variables // ONAME func param with PHEAP Node* heapaddr; // temp holding heap address of param @@ -517,15 +518,16 @@ enum enum { - Etop = 1<<1, // evaluated at statement level - Erv = 1<<2, // evaluated in value context + Etop = 1<<1, // evaluated at statement level + Erv = 1<<2, // evaluated in value context Etype = 1<<3, - Ecall = 1<<4, // call-only expressions are ok + Ecall = 1<<4, // call-only expressions are ok Efnstruct = 1<<5, // multivalue function returns are ok Eiota = 1<<6, // iota is ok Easgn = 1<<7, // assigning to expression Eindir = 1<<8, // indirecting through expression Eaddr = 1<<9, // taking address of expression + Eproc = 1<<10, // inside a go statement }; #define BITS 5 @@ -815,8 +817,9 @@ int bset(Bits a, uint n); */ Node* closurebody(NodeList *body); void closurehdr(Node *ntype); -void typecheckclosure(Node *func); +void typecheckclosure(Node *func, int top); Node* walkclosure(Node *func, NodeList **init); +void walkcallclosure(Node *n, NodeList **init); /* * const.c @@ -870,6 +873,7 @@ void funcbody(Node *n); void funccompile(Node *n, int isclosure); void funchdr(Node *n); Type* functype(Node *this, NodeList *in, NodeList *out); +void ifacedcl(Node *n); int isifacemethod(Type *f); void markdcl(void); Node* methodname(Node *n, Type *t); @@ -1209,6 +1213,7 @@ EXTERN Prog* continpc; EXTERN Prog* breakpc; EXTERN Prog* pc; EXTERN Prog* firstpc; +EXTERN Prog* retpc; EXTERN Node* nodfp; @@ -1222,6 +1227,7 @@ void cgen_callinter(Node *n, Node *res, int proc); void cgen_ret(Node *n); void clearfat(Node *n); void compile(Node*); +void defframe(Prog*); int dgostringptr(Sym*, int off, char *str); int dgostrlitptr(Sym*, int off, Strlit*); int dstringptr(Sym *s, int off, char *str); diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y index 7adfd002a..fdaab4fa4 100644 --- a/src/cmd/gc/go.y +++ b/src/cmd/gc/go.y @@ -1380,6 +1380,7 @@ interfacedcl: new_name indcl { $$ = nod(ODCLFIELD, $1, $2); + ifacedcl($$); } | packname { diff --git a/src/cmd/gc/init.c b/src/cmd/gc/init.c index af4eb0336..8818db08c 100644 --- a/src/cmd/gc/init.c +++ b/src/cmd/gc/init.c @@ -182,11 +182,14 @@ fninit(NodeList *n) // (11) a = nod(ORETURN, N, N); r = list(r, a); - exportsym(fn->nname); fn->nbody = r; funcbody(fn); + + curfn = fn; typecheck(&fn, Etop); + typechecklist(r, Etop); + curfn = nil; funccompile(fn, 0); } diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c index 04dd0d5b9..5e2f73fc5 100644 --- a/src/cmd/gc/lex.c +++ b/src/cmd/gc/lex.c @@ -235,13 +235,14 @@ main(int argc, char *argv[]) if(debug['f']) frame(1); - // Process top-level declarations in three phases. + // Process top-level declarations in four phases. // Phase 1: const, type, and names and types of funcs. // This will gather all the information about types // and methods but doesn't depend on any of it. // Phase 2: Variable assignments. // To check interface assignments, depends on phase 1. - // Phase 3: Function bodies. + // Phase 3: Type check function bodies. + // Phase 4: Compile function bodies. defercheckwidth(); for(l=xtop; l; l=l->next) if(l->n->op != ODCL && l->n->op != OAS) @@ -251,17 +252,28 @@ main(int argc, char *argv[]) typecheck(&l->n, Etop); resumetypecopy(); resumecheckwidth(); + + for(l=xtop; l; l=l->next) + if(l->n->op == ODCLFUNC) { + curfn = l->n; + typechecklist(l->n->nbody, Etop); + } + curfn = nil; + for(l=xtop; l; l=l->next) if(l->n->op == ODCLFUNC) funccompile(l->n, 0); + if(nerrors == 0) fninit(xtop); + while(closures) { l = closures; closures = nil; for(; l; l=l->next) funccompile(l->n, 1); } + dclchecks(); if(nerrors) diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c index 9f4b7b318..f34fc76c8 100644 --- a/src/cmd/gc/obj.c +++ b/src/cmd/gc/obj.c @@ -284,6 +284,7 @@ stringsym(char *s, int len) off = dsname(sym, off, s+n, m); } off = duint8(sym, off, 0); // terminating NUL for runtime + off = (off+widthptr-1)&~(widthptr-1); // round to pointer alignment ggloblsym(sym, off, 1); text(); diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c new file mode 100644 index 000000000..9bd845dde --- /dev/null +++ b/src/cmd/gc/pgen.c @@ -0,0 +1,119 @@ +// 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. + +#undef EXTERN +#define EXTERN +#include "gg.h" +#include "opt.h" + +void +compile(Node *fn) +{ + Plist *pl; + Node nod1, *n; + Prog *ptxt; + int32 lno; + Type *t; + Iter save; + + 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; + + // 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); + } + } + + hasdefer = 0; + walk(curfn); + if(nerrors != 0 || isblank(curfn->nname)) + goto ret; + + allocparams(); + + continpc = P; + breakpc = P; + + pl = newplist(); + pl->name = curfn->nname; + + setlineno(curfn); + + nodconst(&nod1, types[TINT32], 0); + ptxt = gins(ATEXT, curfn->nname, &nod1); + afunclit(&ptxt->from); + + ginit(); + 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); + } + + defframe(ptxt); + + if(debug['f']) + frame(0); + +ret: + lineno = lno; +} diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c index be96a1477..eb7ef31ec 100644 --- a/src/cmd/gc/sinit.c +++ b/src/cmd/gc/sinit.c @@ -173,10 +173,10 @@ initfix(NodeList *l) /* * from here down is the walk analysis - * of composit literals. + * of composite literals. * most of the work is to generate * data statements for the constant - * part of the composit literal. + * part of the composite literal. */ static void structlit(int ctxt, int pass, Node *n, Node *var, NodeList **init); diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index 326a5ba74..4c0819cd8 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -3170,7 +3170,10 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface) dumplist("genwrapper body", fn->nbody); funcbody(fn); + curfn = fn; typecheck(&fn, Etop); + typechecklist(fn->nbody, Etop); + curfn = nil; funccompile(fn, 0); } diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index 9aaf3e6ef..44d08352d 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -29,8 +29,8 @@ static void typecheckfunc(Node*); static void checklvalue(Node*, char*); static void checkassign(Node*); static void checkassignlist(NodeList*); -static void stringtoarraylit(Node**); -static Node* resolve(Node*); +static void stringtoarraylit(Node**); +static Node* resolve(Node*); static Type* getforwtype(Node*); /* @@ -780,7 +780,7 @@ reswitch: n = r; goto reswitch; } - typecheck(&n->left, Erv | Etype | Ecall); + typecheck(&n->left, Erv | Etype | Ecall |(top&Eproc)); l = n->left; if(l->op == ONAME && l->etype != 0) { if(n->isddd && l->etype != OAPPEND) @@ -794,7 +794,7 @@ reswitch: defaultlit(&n->left, T); l = n->left; if(l->op == OTYPE) { - if(n->isddd) + if(n->isddd || l->type->bound == -100) yyerror("invalid use of ... in type conversion", l); // pick off before type-checking arguments ok |= Erv; @@ -822,7 +822,13 @@ reswitch: case ODOTMETH: n->op = OCALLMETH; - typecheckaste(OCALL, n->left, 0, getthisx(t), list1(l->left), "method receiver"); + // typecheckaste was used here but there wasn't enough + // information further down the call chain to know if we + // were testing a method receiver for unexported fields. + // It isn't necessary, so just do a sanity check. + tp = getthisx(t)->type->type; + if(l->left == N || !eqtype(l->left->type, tp)) + fatal("method receiver"); break; default: @@ -1021,9 +1027,9 @@ reswitch: // copy([]byte, string) if(isslice(n->left->type) && n->right->type->etype == TSTRING) { - if (n->left->type->type ==types[TUINT8]) - goto ret; - yyerror("arguments to copy have different element types: %lT and string", n->left->type); + if (n->left->type->type == types[TUINT8]) + goto ret; + yyerror("arguments to copy have different element types: %lT and string", n->left->type); goto error; } @@ -1211,7 +1217,7 @@ reswitch: case OCLOSURE: ok |= Erv; - typecheckclosure(n); + typecheckclosure(n, top); if(n->type == T) goto error; goto ret; @@ -1240,11 +1246,15 @@ reswitch: goto ret; case ODEFER: - case OPROC: ok |= Etop; typecheck(&n->left, Etop); goto ret; + case OPROC: + ok |= Etop; + typecheck(&n->left, Etop|Eproc); + goto ret; + case OFOR: ok |= Etop; typechecklist(n->ninit, Etop); @@ -2159,7 +2169,9 @@ addrescapes(Node *n) if(n->noescape) break; switch(n->class) { - case PAUTO: + case PPARAMREF: + addrescapes(n->defn); + break; case PPARAM: case PPARAMOUT: // if func param, need separate temporary @@ -2167,16 +2179,17 @@ addrescapes(Node *n) // the function type has already been checked // (we're in the function body) // so the param already has a valid xoffset. - if(n->class == PPARAM || n->class == PPARAMOUT) { - // expression to refer to stack copy - n->stackparam = nod(OPARAM, n, N); - n->stackparam->type = n->type; - n->stackparam->addable = 1; - if(n->xoffset == BADWIDTH) - fatal("addrescapes before param assignment"); - n->stackparam->xoffset = n->xoffset; - n->xoffset = 0; - } + + // expression to refer to stack copy + n->stackparam = nod(OPARAM, n, N); + n->stackparam->type = n->type; + n->stackparam->addable = 1; + if(n->xoffset == BADWIDTH) + fatal("addrescapes before param assignment"); + n->stackparam->xoffset = n->xoffset; + n->xoffset = 0; + // fallthrough + case PAUTO: n->class |= PHEAP; n->addable = 0; @@ -2189,7 +2202,9 @@ addrescapes(Node *n) snprint(buf, sizeof buf, "&%S", n->sym); n->heapaddr->sym = lookup(buf); n->heapaddr->class = PHEAP-1; // defer tempname to allocparams - curfn->dcl = list(curfn->dcl, n->heapaddr); + n->heapaddr->ullman = 1; + n->curfn->dcl = list(n->curfn->dcl, n->heapaddr); + break; } break; diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index b3b400556..ccc65ff21 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -66,6 +66,7 @@ walk(Node *fn) int lno; curfn = fn; + if(debug['W']) { snprint(s, sizeof(s), "\nbefore %S", curfn->nname->sym); dumplist(s, curfn->nbody); @@ -73,7 +74,7 @@ walk(Node *fn) if(curfn->type->outtuple) if(walkret(curfn->nbody)) yyerror("function ends without a return statement"); - typechecklist(curfn->nbody, Etop); + lno = lineno; for(l=fn->dcl; l; l=l->next) { n = l->n; @@ -468,8 +469,10 @@ walkstmt(Node **np) case OPANIC: case OEMPTY: case ORECOVER: - if(n->typecheck == 0) + if(n->typecheck == 0) { + dump("missing typecheck:", n); fatal("missing typecheck"); + } init = n->ninit; n->ninit = nil; walkexpr(&n, &init); @@ -770,8 +773,15 @@ walkexpr(Node **np, NodeList **init) t = n->left->type; if(n->list && n->list->n->op == OAS) goto ret; - walkexpr(&n->left, init); + + if(n->left->op == OCLOSURE) { + walkcallclosure(n, init); + t = n->left->type; + } else + walkexpr(&n->left, init); + walkexprlist(n->list, init); + ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init); n->list = reorder1(ll); if(isselect(n)) { @@ -1525,7 +1535,7 @@ ascompatee(int op, NodeList *nl, NodeList *nr, NodeList **init) static int fncall(Node *l, Type *rt) { - if(l->ullman >= UINF) + if(l->ullman >= UINF || l->op == OINDEXMAP) return 1; if(eqtype(l->type, rt)) return 0; |