diff options
Diffstat (limited to 'src/cmd')
-rw-r--r-- | src/cmd/6g/ggen.c | 40 | ||||
-rw-r--r-- | src/cmd/8g/ggen.c | 28 | ||||
-rw-r--r-- | src/cmd/gc/builtin.c | 1 | ||||
-rw-r--r-- | src/cmd/gc/gen.c | 12 | ||||
-rw-r--r-- | src/cmd/gc/go.h | 2 | ||||
-rw-r--r-- | src/cmd/gc/mparith2.c | 4 | ||||
-rw-r--r-- | src/cmd/gc/runtime.go | 1 | ||||
-rw-r--r-- | src/cmd/gc/sinit.c | 12 | ||||
-rw-r--r-- | src/cmd/gc/typecheck.c | 57 | ||||
-rw-r--r-- | src/cmd/gc/walk.c | 278 | ||||
-rw-r--r-- | src/cmd/go/build.go | 1 | ||||
-rw-r--r-- | src/cmd/go/generate.go | 4 | ||||
-rw-r--r-- | src/cmd/go/get.go | 25 | ||||
-rwxr-xr-x | src/cmd/go/test.bash | 10 | ||||
-rw-r--r-- | src/cmd/go/vcs.go | 50 | ||||
-rw-r--r-- | src/cmd/ld/data.c | 4 | ||||
-rw-r--r-- | src/cmd/ld/ldelf.c | 2 | ||||
-rw-r--r-- | src/cmd/objdump/main.go | 2 | ||||
-rw-r--r-- | src/cmd/objdump/objdump_test.go | 19 |
19 files changed, 381 insertions, 171 deletions
diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c index 987473cca..363620769 100644 --- a/src/cmd/6g/ggen.c +++ b/src/cmd/6g/ggen.c @@ -1102,26 +1102,54 @@ clearfat(Node *nl) c = w % 8; // bytes q = w / 8; // quads + if(q < 4) { + // Write sequence of MOV 0, off(base) instead of using STOSQ. + // The hope is that although the code will be slightly longer, + // the MOVs will have no dependencies and pipeline better + // than the unrolled STOSQ loop. + // NOTE: Must use agen, not igen, so that optimizer sees address + // being taken. We are not writing on field boundaries. + agenr(nl, &n1, N); + n1.op = OINDREG; + nodconst(&z, types[TUINT64], 0); + while(q-- > 0) { + n1.type = z.type; + gins(AMOVQ, &z, &n1); + n1.xoffset += 8; + } + if(c >= 4) { + nodconst(&z, types[TUINT32], 0); + n1.type = z.type; + gins(AMOVL, &z, &n1); + n1.xoffset += 4; + c -= 4; + } + nodconst(&z, types[TUINT8], 0); + while(c-- > 0) { + n1.type = z.type; + gins(AMOVB, &z, &n1); + n1.xoffset++; + } + regfree(&n1); + return; + } + savex(D_DI, &n1, &oldn1, N, types[tptr]); agen(nl, &n1); savex(D_AX, &ax, &oldax, N, types[tptr]); gconreg(AMOVL, 0, D_AX); - if(q > 128 || (q >= 4 && nacl)) { + if(q > 128 || nacl) { gconreg(movptr, q, D_CX); gins(AREP, N, N); // repeat gins(ASTOSQ, N, N); // STOQ AL,*(DI)+ - } else if(q >= 4) { + } else { p = gins(ADUFFZERO, N, N); p->to.type = D_ADDR; p->to.sym = linksym(pkglookup("duffzero", runtimepkg)); // 2 and 128 = magic constants: see ../../runtime/asm_amd64.s p->to.offset = 2*(128-q); - } else - while(q > 0) { - gins(ASTOSQ, N, N); // STOQ AL,*(DI)+ - q--; } z = ax; diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c index 7c986cc64..6333a60bb 100644 --- a/src/cmd/8g/ggen.c +++ b/src/cmd/8g/ggen.c @@ -157,7 +157,7 @@ void clearfat(Node *nl) { uint32 w, c, q; - Node n1; + Node n1, z; Prog *p; /* clear a fat object */ @@ -172,6 +172,32 @@ clearfat(Node *nl) c = w % 4; // bytes q = w / 4; // quads + if(q < 4) { + // Write sequence of MOV 0, off(base) instead of using STOSL. + // The hope is that although the code will be slightly longer, + // the MOVs will have no dependencies and pipeline better + // than the unrolled STOSL loop. + // NOTE: Must use agen, not igen, so that optimizer sees address + // being taken. We are not writing on field boundaries. + regalloc(&n1, types[tptr], N); + agen(nl, &n1); + n1.op = OINDREG; + nodconst(&z, types[TUINT64], 0); + while(q-- > 0) { + n1.type = z.type; + gins(AMOVL, &z, &n1); + n1.xoffset += 4; + } + nodconst(&z, types[TUINT8], 0); + while(c-- > 0) { + n1.type = z.type; + gins(AMOVB, &z, &n1); + n1.xoffset++; + } + regfree(&n1); + return; + } + nodreg(&n1, types[tptr], D_DI); agen(nl, &n1); gconreg(AMOVL, 0, D_AX); diff --git a/src/cmd/gc/builtin.c b/src/cmd/gc/builtin.c index 5fbb4f0cf..fbca4ee5f 100644 --- a/src/cmd/gc/builtin.c +++ b/src/cmd/gc/builtin.c @@ -24,7 +24,6 @@ char *runtimeimport = "func @\"\".printslice (? any)\n" "func @\"\".printnl ()\n" "func @\"\".printsp ()\n" - "func @\"\".goprintf ()\n" "func @\"\".concatstring2 (? string, ? string) (? string)\n" "func @\"\".concatstring3 (? string, ? string, ? string) (? string)\n" "func @\"\".concatstring4 (? string, ? string, ? string, ? string) (? string)\n" diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c index eb9eacca8..c7c9fcdaf 100644 --- a/src/cmd/gc/gen.c +++ b/src/cmd/gc/gen.c @@ -731,14 +731,10 @@ cgen_as(Node *nl, Node *nr) return; } - if(nr == N || isnil(nr)) { - // externals and heaps should already be clear - if(nr == N) { - if(nl->class == PEXTERN) - return; - if(nl->class & PHEAP) - return; - } + if(nr == N || iszero(nr)) { + // heaps should already be clear + if(nr == N && (nl->class & PHEAP)) + return; tl = nl->type; if(tl == T) diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index 8178f7272..965a0550d 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -283,6 +283,7 @@ struct Node uchar addrtaken; // address taken, even if not moved to heap uchar dupok; // duplicate definitions ok (for func) uchar wrapper; // is method wrapper (for func) + uchar reslice; // this is a reslice x = x[0:y] or x = append(x, ...) schar likely; // likeliness of if statement uchar hasbreak; // has break statement uchar needzero; // if it contains pointers, needs to be zeroed on function entry @@ -1374,6 +1375,7 @@ int isnilinter(Type *t); int isptrto(Type *t, int et); int isslice(Type *t); int istype(Type *t, int et); +int iszero(Node *n); void linehist(char *file, int32 off, int relative); NodeList* list(NodeList *l, Node *n); NodeList* list1(Node *n); diff --git a/src/cmd/gc/mparith2.c b/src/cmd/gc/mparith2.c index 5cf98c62c..fd9f591ce 100644 --- a/src/cmd/gc/mparith2.c +++ b/src/cmd/gc/mparith2.c @@ -656,7 +656,7 @@ mpdivmodfixfix(Mpint *q, Mpint *r, Mpint *n, Mpint *d) } static int -iszero(Mpint *a) +mpiszero(Mpint *a) { long *a1; int i; @@ -687,7 +687,7 @@ mpdivfract(Mpint *a, Mpint *b) for(j=0; j<Mpscale; j++) { x <<= 1; if(mpcmp(&d, &n) <= 0) { - if(!iszero(&d)) + if(!mpiszero(&d)) x |= 1; mpsubfixfix(&n, &d); } diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go index 86afe67f1..0fb15c265 100644 --- a/src/cmd/gc/runtime.go +++ b/src/cmd/gc/runtime.go @@ -36,7 +36,6 @@ func printeface(any) func printslice(any) func printnl() func printsp() -func goprintf() func concatstring2(string, string) string func concatstring3(string, string, string) string diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c index f050026d9..8ad7ae7ab 100644 --- a/src/cmd/gc/sinit.c +++ b/src/cmd/gc/sinit.c @@ -17,7 +17,6 @@ enum InitPending = 2, }; -static int iszero(Node*); static void initplan(Node*); static NodeList *initlist; static void init2(Node*, NodeList**); @@ -1068,7 +1067,7 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init) if(t->etype != TSTRUCT) fatal("anylit: not struct"); - if(simplename(var)) { + if(simplename(var) && count(n->list) > 4) { if(ctxt == 0) { // lay out static data @@ -1091,7 +1090,7 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init) } // initialize of not completely specified - if(count(n->list) < structcount(t)) { + if(simplename(var) || count(n->list) < structcount(t)) { a = nod(OAS, var, N); typecheck(&a, Etop); walkexpr(&a, init); @@ -1108,7 +1107,7 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init) break; } - if(simplename(var)) { + if(simplename(var) && count(n->list) > 4) { if(ctxt == 0) { // lay out static data @@ -1131,7 +1130,7 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init) } // initialize of not completely specified - if(count(n->list) < t->bound) { + if(simplename(var) || count(n->list) < t->bound) { a = nod(OAS, var, N); typecheck(&a, Etop); walkexpr(&a, init); @@ -1356,7 +1355,6 @@ no: return 0; } -static int iszero(Node*); static int isvaluelit(Node*); static InitEntry* entry(InitPlan*); static void addvalue(InitPlan*, vlong, Node*, Node*); @@ -1440,7 +1438,7 @@ addvalue(InitPlan *p, vlong xoffset, Node *key, Node *n) e->expr = n; } -static int +int iszero(Node *n) { NodeList *l; diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index ff49fe6f9..714c66268 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -2127,13 +2127,16 @@ lookdot(Node *n, Type *t, int dostrcmp) n->left = nod(OADDR, n->left, N); n->left->implicit = 1; typecheck(&n->left, Etype|Erv); - } else if(tt->etype == tptr && eqtype(tt->type, rcvr)) { + } else if(tt->etype == tptr && rcvr->etype != tptr && eqtype(tt->type, rcvr)) { n->left = nod(OIND, n->left, N); n->left->implicit = 1; typecheck(&n->left, Etype|Erv); - } else if(tt->etype == tptr && tt->type->etype == tptr && eqtype(derefall(tt), rcvr)) { + } else if(tt->etype == tptr && tt->type->etype == tptr && eqtype(derefall(tt), derefall(rcvr))) { yyerror("calling method %N with receiver %lN requires explicit dereference", n->right, n->left); while(tt->etype == tptr) { + // Stop one level early for method with pointer receiver. + if(rcvr->etype == tptr && tt->type->etype != tptr) + break; n->left = nod(OIND, n->left, N); n->left->implicit = 1; typecheck(&n->left, Etype|Erv); @@ -2814,6 +2817,33 @@ checkassignlist(NodeList *l) checkassign(l->n); } +// Check whether l and r are the same side effect-free expression, +// so that it is safe to reuse one instead of computing both. +static int +samesafeexpr(Node *l, Node *r) +{ + if(l->op != r->op || !eqtype(l->type, r->type)) + return 0; + + switch(l->op) { + case ONAME: + case OCLOSUREVAR: + return l == r; + + case ODOT: + case ODOTPTR: + return l->right != nil && r->right != nil && l->right->sym == r->right->sym && samesafeexpr(l->left, r->left); + + case OIND: + return samesafeexpr(l->left, r->left); + + case OINDEX: + return samesafeexpr(l->left, r->left) && samesafeexpr(l->right, r->right); + } + + return 0; +} + /* * type check assignment. * if this assignment is the definition of a var on the left side, @@ -2851,6 +2881,29 @@ typecheckas(Node *n) n->typecheck = 1; if(n->left->typecheck == 0) typecheck(&n->left, Erv | Easgn); + + // Recognize slices being updated in place, for better code generation later. + // Don't rewrite if using race detector, to avoid needing to teach race detector + // about this optimization. + if(n->left && n->left->op != OINDEXMAP && n->right && !flag_race) { + switch(n->right->op) { + case OSLICE: + case OSLICE3: + case OSLICESTR: + // For x = x[0:y], x can be updated in place, without touching pointer. + if(samesafeexpr(n->left, n->right->left) && (n->right->right->left == N || iszero(n->right->right->left))) + n->right->reslice = 1; + break; + + case OAPPEND: + // For x = append(x, ...), x can be updated in place when there is capacity, + // without touching the pointer; otherwise the emitted code to growslice + // can take care of updating the pointer, and only in that case. + if(n->right->list != nil && samesafeexpr(n->left, n->right->list->n)) + n->right->reslice = 1; + break; + } + } } static void diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index 241d7d74a..ff9b36208 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -7,7 +7,7 @@ #include "go.h" #include "../ld/textflag.h" -static Node* walkprint(Node*, NodeList**, int); +static Node* walkprint(Node*, NodeList**); static Node* writebarrierfn(char*, Type*, Type*); static Node* applywritebarrier(Node*, NodeList**); static Node* mapfn(char*, Type*); @@ -32,6 +32,7 @@ static void walkmul(Node**, NodeList**); static void walkdiv(Node**, NodeList**); static int bounded(Node*, int64); static Mpint mpzero; +static void walkprintfunc(Node**, NodeList**); void walk(Node *fn) @@ -226,8 +227,7 @@ walkstmt(Node **np) switch(n->left->op) { case OPRINT: case OPRINTN: - walkexprlist(n->left->list, &n->ninit); - n->left = walkprint(n->left, &n->ninit, 1); + walkprintfunc(&n->left, &n->ninit); break; case OCOPY: n->left = copyany(n->left, &n->ninit, 1); @@ -260,8 +260,7 @@ walkstmt(Node **np) switch(n->left->op) { case OPRINT: case OPRINTN: - walkexprlist(n->left->list, &n->ninit); - n->left = walkprint(n->left, &n->ninit, 1); + walkprintfunc(&n->left, &n->ninit); break; case OCOPY: n->left = copyany(n->left, &n->ninit, 1); @@ -543,7 +542,7 @@ walkexpr(Node **np, NodeList **init) case OPRINT: case OPRINTN: walkexprlist(n->list, init); - n = walkprint(n, init, 0); + n = walkprint(n, init); goto ret; case OPANIC: @@ -614,7 +613,7 @@ walkexpr(Node **np, NodeList **init) if(oaslit(n, init)) goto ret; - if(n->right == N) + if(n->right == N || iszero(n->right) && !flag_race) goto ret; switch(n->right->op) { @@ -1390,7 +1389,6 @@ walkexpr(Node **np, NodeList **init) case OMAPLIT: case OSTRUCTLIT: case OPTRLIT: - // XXX TODO do we need to clear var? var = temp(n->type); anylit(0, n, var, init); n = var; @@ -1494,7 +1492,7 @@ fncall(Node *l, Type *rt) if(l->ullman >= UINF || l->op == OINDEXMAP) return 1; - r.op = 0; + memset(&r, 0, sizeof r); if(needwritebarrier(l, &r)) return 1; if(eqtype(l->type, rt)) @@ -1758,7 +1756,7 @@ ret: // generate code for print static Node* -walkprint(Node *nn, NodeList **init, int defer) +walkprint(Node *nn, NodeList **init) { Node *r; Node *n; @@ -1766,31 +1764,17 @@ walkprint(Node *nn, NodeList **init, int defer) Node *on; Type *t; int notfirst, et, op; - NodeList *calls, *intypes, *args; - Fmt fmt; + NodeList *calls; on = nil; op = nn->op; all = nn->list; calls = nil; notfirst = 0; - intypes = nil; - args = nil; - - memset(&fmt, 0, sizeof fmt); - if(defer) { - // defer print turns into defer printf with format string - fmtstrinit(&fmt); - intypes = list(intypes, nod(ODCLFIELD, N, typenod(types[TSTRING]))); - args = list1(nod(OXXX, N, N)); - } for(l=all; l; l=l->next) { if(notfirst) { - if(defer) - fmtprint(&fmt, " "); - else - calls = list(calls, mkcall("printsp", T, init)); + calls = list(calls, mkcall("printsp", T, init)); } notfirst = op == OPRINTN; @@ -1818,122 +1802,63 @@ walkprint(Node *nn, NodeList **init, int defer) t = n->type; et = n->type->etype; if(isinter(n->type)) { - if(defer) { - if(isnilinter(n->type)) - fmtprint(&fmt, "%%e"); - else - fmtprint(&fmt, "%%i"); - } else { - if(isnilinter(n->type)) - on = syslook("printeface", 1); - else - on = syslook("printiface", 1); - argtype(on, n->type); // any-1 - } + if(isnilinter(n->type)) + on = syslook("printeface", 1); + else + on = syslook("printiface", 1); + argtype(on, n->type); // any-1 } else if(isptr[et] || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR) { - if(defer) { - fmtprint(&fmt, "%%p"); - } else { - on = syslook("printpointer", 1); - argtype(on, n->type); // any-1 - } + on = syslook("printpointer", 1); + argtype(on, n->type); // any-1 } else if(isslice(n->type)) { - if(defer) { - fmtprint(&fmt, "%%a"); - } else { - on = syslook("printslice", 1); - argtype(on, n->type); // any-1 - } + on = syslook("printslice", 1); + argtype(on, n->type); // any-1 } else if(isint[et]) { - if(defer) { - if(et == TUINT64) - fmtprint(&fmt, "%%U"); - else { - fmtprint(&fmt, "%%D"); - t = types[TINT64]; - } - } else { - if(et == TUINT64) { - if((t->sym->pkg == runtimepkg || compiling_runtime) && strcmp(t->sym->name, "hex") == 0) - on = syslook("printhex", 0); - else - on = syslook("printuint", 0); - } else - on = syslook("printint", 0); - } - } else if(isfloat[et]) { - if(defer) { - fmtprint(&fmt, "%%f"); - t = types[TFLOAT64]; + if(et == TUINT64) { + if((t->sym->pkg == runtimepkg || compiling_runtime) && strcmp(t->sym->name, "hex") == 0) + on = syslook("printhex", 0); + else + on = syslook("printuint", 0); } else - on = syslook("printfloat", 0); + on = syslook("printint", 0); + } else if(isfloat[et]) { + on = syslook("printfloat", 0); } else if(iscomplex[et]) { - if(defer) { - fmtprint(&fmt, "%%C"); - t = types[TCOMPLEX128]; - } else - on = syslook("printcomplex", 0); + on = syslook("printcomplex", 0); } else if(et == TBOOL) { - if(defer) - fmtprint(&fmt, "%%t"); - else - on = syslook("printbool", 0); + on = syslook("printbool", 0); } else if(et == TSTRING) { - if(defer) - fmtprint(&fmt, "%%S"); - else - on = syslook("printstring", 0); + on = syslook("printstring", 0); } else { badtype(OPRINT, n->type, T); continue; } - if(!defer) { - t = *getinarg(on->type); - if(t != nil) - t = t->type; - if(t != nil) - t = t->type; - } + t = *getinarg(on->type); + if(t != nil) + t = t->type; + if(t != nil) + t = t->type; if(!eqtype(t, n->type)) { n = nod(OCONV, n, N); n->type = t; } - if(defer) { - intypes = list(intypes, nod(ODCLFIELD, N, typenod(t))); - args = list(args, n); - } else { - r = nod(OCALL, on, N); - r->list = list1(n); - calls = list(calls, r); - } + r = nod(OCALL, on, N); + r->list = list1(n); + calls = list(calls, r); } - if(defer) { - if(op == OPRINTN) - fmtprint(&fmt, "\n"); - on = syslook("goprintf", 1); - on->type = functype(nil, intypes, nil); - args->n = nod(OLITERAL, N, N); - args->n->val.ctype = CTSTR; - args->n->val.u.sval = strlit(fmtstrflush(&fmt)); - r = nod(OCALL, on, N); - r->list = args; - typecheck(&r, Etop); - walkexpr(&r, init); - } else { - if(op == OPRINTN) - calls = list(calls, mkcall("printnl", T, nil)); - typechecklist(calls, Etop); - walkexprlist(calls, init); + if(op == OPRINTN) + calls = list(calls, mkcall("printnl", T, nil)); + typechecklist(calls, Etop); + walkexprlist(calls, init); - r = nod(OEMPTY, N, N); - typecheck(&r, Etop); - walkexpr(&r, init); - r->ninit = calls; - } + r = nod(OEMPTY, N, N); + typecheck(&r, Etop); + walkexpr(&r, init); + r->ninit = calls; return r; } @@ -2009,8 +1934,8 @@ needwritebarrier(Node *l, Node *r) if(isstack(l)) return 0; - // No write barrier for zeroing. - if(r == N) + // No write barrier for implicit or explicit zeroing. + if(r == N || iszero(r)) return 0; // No write barrier for initialization to constant. @@ -2031,6 +1956,28 @@ needwritebarrier(Node *l, Node *r) if(r->op == OADDR && isglobal(r->left)) return 0; + // No write barrier for reslice: x = x[0:y] or x = append(x, ...). + // Both are compiled to modify x directly. + // In the case of append, a write barrier may still be needed + // if the underlying array grows, but the append code can + // generate the write barrier directly in that case. + // (It does not yet, but the cost of the write barrier will be + // small compared to the cost of the allocation.) + if(r->reslice) { + switch(r->op) { + case OSLICE: + case OSLICE3: + case OSLICESTR: + case OAPPEND: + break; + default: + dump("bad reslice-l", l); + dump("bad reslice-r", r); + break; + } + return 0; + } + // Otherwise, be conservative and use write barrier. return 1; } @@ -3208,7 +3155,7 @@ countfield(Type *t) static void walkcompare(Node **np, NodeList **init) { - Node *n, *l, *r, *call, *a, *li, *ri, *expr; + Node *n, *l, *r, *call, *a, *li, *ri, *expr, *cmpl, *cmpr; int andor, i; Type *t, *t1; @@ -3228,18 +3175,25 @@ walkcompare(Node **np, NodeList **init) break; } - if(!islvalue(n->left) || !islvalue(n->right)) { - fatal("arguments of comparison must be lvalues"); + cmpl = n->left; + while(cmpl != N && cmpl->op == OCONVNOP) + cmpl = cmpl->left; + cmpr = n->right; + while(cmpr != N && cmpr->op == OCONVNOP) + cmpr = cmpr->left; + + if(!islvalue(cmpl) || !islvalue(cmpr)) { + fatal("arguments of comparison must be lvalues - %N %N", cmpl, cmpr); } l = temp(ptrto(t)); - a = nod(OAS, l, nod(OADDR, n->left, N)); + a = nod(OAS, l, nod(OADDR, cmpl, N)); a->right->etype = 1; // addr does not escape typecheck(&a, Etop); *init = list(*init, a); r = temp(ptrto(t)); - a = nod(OAS, r, nod(OADDR, n->right, N)); + a = nod(OAS, r, nod(OADDR, cmpr, N)); a->right->etype = 1; // addr does not escape typecheck(&a, Etop); *init = list(*init, a); @@ -3913,3 +3867,71 @@ candiscard(Node *n) return 1; } + +// rewrite +// print(x, y, z) +// into +// func(a1, a2, a3) { +// print(a1, a2, a3) +// }(x, y, z) +// and same for println. +static void +walkprintfunc(Node **np, NodeList **init) +{ + Node *n; + Node *a, *fn, *t, *oldfn; + NodeList *l, *printargs; + int num; + char buf[100]; + static int prgen; + + n = *np; + + if(n->ninit != nil) { + walkstmtlist(n->ninit); + *init = concat(*init, n->ninit); + n->ninit = nil; + } + + t = nod(OTFUNC, N, N); + num = 0; + printargs = nil; + for(l=n->list; l != nil; l=l->next) { + snprint(buf, sizeof buf, "a%d", num++); + a = nod(ODCLFIELD, newname(lookup(buf)), typenod(l->n->type)); + t->list = list(t->list, a); + printargs = list(printargs, a->left); + } + + fn = nod(ODCLFUNC, N, N); + snprint(buf, sizeof buf, "print·%d", ++prgen); + fn->nname = newname(lookup(buf)); + fn->nname->defn = fn; + fn->nname->ntype = t; + declare(fn->nname, PFUNC); + + oldfn = curfn; + curfn = nil; + funchdr(fn); + + a = nod(n->op, N, N); + a->list = printargs; + typecheck(&a, Etop); + walkstmt(&a); + + fn->nbody = list1(a); + + funcbody(fn); + + typecheck(&fn, Etop); + typechecklist(fn->nbody, Etop); + xtop = list(xtop, fn); + curfn = oldfn; + + a = nod(OCALL, N, N); + a->left = fn->nname; + a->list = n->list; + typecheck(&a, Etop); + walkexpr(&a, init); + *np = a; +} diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go index 49b84709e..79a27116a 100644 --- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -1945,6 +1945,7 @@ func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions [] } ldflags = append(ldflags, afiles...) ldflags = append(ldflags, cgoldflags...) + ldflags = append(ldflags, envList("CGO_LDFLAGS", "")...) ldflags = append(ldflags, p.CgoLDFLAGS...) if usesCgo && goos == "linux" { ldflags = append(ldflags, "-Wl,-E") diff --git a/src/cmd/go/generate.go b/src/cmd/go/generate.go index 167758207..4227abbe7 100644 --- a/src/cmd/go/generate.go +++ b/src/cmd/go/generate.go @@ -169,6 +169,7 @@ func (g *Generator) run() (ok bool) { if e != stop { panic(e) } + setExitStatus(1) } }() g.dir, g.file = filepath.Split(g.path) @@ -267,7 +268,8 @@ Words: var stop = fmt.Errorf("error in generation") // errorf logs an error message prefixed with the file and line number. -// It then exits the program because generation stops at the first error. +// It then exits the program (with exit status 1) because generation stops +// at the first error. func (g *Generator) errorf(format string, args ...interface{}) { fmt.Fprintf(os.Stderr, "%s:%d: %s\n", shortPath(g.path), g.lineNum, fmt.Sprintf(format, args...)) diff --git a/src/cmd/go/get.go b/src/cmd/go/get.go index 264033941..86e169761 100644 --- a/src/cmd/go/get.go +++ b/src/cmd/go/get.go @@ -16,7 +16,7 @@ import ( ) var cmdGet = &Command{ - UsageLine: "get [-d] [-fix] [-t] [-u] [build flags] [packages]", + UsageLine: "get [-d] [-f] [-fix] [-t] [-u] [build flags] [packages]", Short: "download and install packages and dependencies", Long: ` Get downloads and installs the packages named by the import paths, @@ -25,6 +25,11 @@ along with their dependencies. The -d flag instructs get to stop after downloading the packages; that is, it instructs get not to install the packages. +The -f flag, valid only when -u is set, forces get -u not to verify that +each package has been checked out from the source control repository +implied by its import path. This can be useful if the source is a local fork +of the original. + The -fix flag instructs get to run the fix tool on the downloaded packages before resolving dependencies or building the code. @@ -53,6 +58,7 @@ See also: go build, go install, go clean. } var getD = cmdGet.Flag.Bool("d", false, "") +var getF = cmdGet.Flag.Bool("f", false, "") var getT = cmdGet.Flag.Bool("t", false, "") var getU = cmdGet.Flag.Bool("u", false, "") var getFix = cmdGet.Flag.Bool("fix", false, "") @@ -63,6 +69,10 @@ func init() { } func runGet(cmd *Command, args []string) { + if *getF && !*getU { + fatalf("go get: cannot use -f flag without -u") + } + // Phase 1. Download/update. var stk importStack for _, arg := range downloadPaths(args) { @@ -268,12 +278,19 @@ func downloadPackage(p *Package) error { repo = "<local>" // should be unused; make distinctive // Double-check where it came from. - if *getU && vcs.remoteRepo != nil { + if *getU && vcs.remoteRepo != nil && !*getF { dir := filepath.Join(p.build.SrcRoot, rootPath) if remote, err := vcs.remoteRepo(vcs, dir); err == nil { if rr, err := repoRootForImportPath(p.ImportPath); err == nil { - if remote != rr.repo { - return fmt.Errorf("%s is from %s, should be from %s", dir, remote, rr.repo) + repo := rr.repo + if rr.vcs.resolveRepo != nil { + resolved, err := rr.vcs.resolveRepo(rr.vcs, dir, repo) + if err == nil { + repo = resolved + } + } + if remote != repo { + return fmt.Errorf("%s is from %s, should be from %s", dir, remote, repo) } } } diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash index 652ef3b5b..2b5230b1a 100755 --- a/src/cmd/go/test.bash +++ b/src/cmd/go/test.bash @@ -219,6 +219,16 @@ q' | ed $d/src/$config >/dev/null 2>&1 cat $d/err ok=false fi + + if GOPATH=$d ./testgo get -d -f -u $url 2>$d/err; then + echo "go get -d -u $url succeeded with wrong remote repo" + cat $d/err + ok=false + elif ! egrep -i 'validating server certificate|not found' $d/err >/dev/null; then + echo "go get -d -f -u $url failed for wrong reason" + cat $d/err + ok=false + fi fi rm -rf $d } diff --git a/src/cmd/go/vcs.go b/src/cmd/go/vcs.go index 0834a7d19..1cac61338 100644 --- a/src/cmd/go/vcs.go +++ b/src/cmd/go/vcs.go @@ -34,7 +34,8 @@ type vcsCmd struct { scheme []string pingCmd string - remoteRepo func(v *vcsCmd, rootDir string) (remoteRepo string, err error) + remoteRepo func(v *vcsCmd, rootDir string) (remoteRepo string, err error) + resolveRepo func(v *vcsCmd, rootDir, remoteRepo string) (realRepo string, err error) } // A tagCmd describes a command to list available tags @@ -164,8 +165,51 @@ var vcsBzr = &vcsCmd{ tagSyncCmd: "update -r {tag}", tagSyncDefault: "update -r revno:-1", - scheme: []string{"https", "http", "bzr", "bzr+ssh"}, - pingCmd: "info {scheme}://{repo}", + scheme: []string{"https", "http", "bzr", "bzr+ssh"}, + pingCmd: "info {scheme}://{repo}", + remoteRepo: bzrRemoteRepo, + resolveRepo: bzrResolveRepo, +} + +func bzrRemoteRepo(vcsBzr *vcsCmd, rootDir string) (remoteRepo string, err error) { + outb, err := vcsBzr.runOutput(rootDir, "config parent_location") + if err != nil { + return "", err + } + return strings.TrimSpace(string(outb)), nil +} + +func bzrResolveRepo(vcsBzr *vcsCmd, rootDir, remoteRepo string) (realRepo string, err error) { + outb, err := vcsBzr.runOutput(rootDir, "info "+remoteRepo) + if err != nil { + return "", err + } + out := string(outb) + + // Expect: + // ... + // (branch root|repository branch): <URL> + // ... + + found := false + for _, prefix := range []string{"\n branch root: ", "\n repository branch: "} { + i := strings.Index(out, prefix) + if i >= 0 { + out = out[i+len(prefix):] + found = true + break + } + } + if !found { + return "", fmt.Errorf("unable to parse output of bzr info") + } + + i := strings.Index(out, "\n") + if i < 0 { + return "", fmt.Errorf("unable to parse output of bzr info") + } + out = out[:i] + return strings.TrimSpace(string(out)), nil } // vcsSvn describes how to use Subversion. diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c index 9983a9281..61847546a 100644 --- a/src/cmd/ld/data.c +++ b/src/cmd/ld/data.c @@ -633,9 +633,7 @@ addstrdata(char *name, char *value) s->dupok = 1; reachable = s->reachable; addaddr(ctxt, s, sp); - adduint32(ctxt, s, strlen(value)); - if(PtrSize == 8) - adduint32(ctxt, s, 0); // round struct to pointer width + adduintxx(ctxt, s, strlen(value), PtrSize); // addstring, addaddr, etc., mark the symbols as reachable. // In this case that is not necessarily true, so stick to what diff --git a/src/cmd/ld/ldelf.c b/src/cmd/ld/ldelf.c index 35f8b4985..b5d081949 100644 --- a/src/cmd/ld/ldelf.c +++ b/src/cmd/ld/ldelf.c @@ -819,7 +819,7 @@ readsym(ElfObj *obj, int i, ElfSym *sym, int needSym) } break; case ElfSymBindLocal: - if(!(thechar == '5' && (strcmp(sym->name, "$a") == 0 || strcmp(sym->name, "$d") == 0))) // binutils for arm generate these mapping symbols, ignore these + if(!(thechar == '5' && (strncmp(sym->name, "$a", 2) == 0 || strncmp(sym->name, "$d", 2) == 0))) // binutils for arm generate these mapping symbols, ignore these if(needSym) { // local names and hidden visiblity global names are unique // and should only reference by its index, not name, so we diff --git a/src/cmd/objdump/main.go b/src/cmd/objdump/main.go index aafc50111..0f66f20a4 100644 --- a/src/cmd/objdump/main.go +++ b/src/cmd/objdump/main.go @@ -159,7 +159,7 @@ func dump(tab *gosym.Table, lookup lookupFunc, disasm disasmFunc, goarch string, printed := false for _, sym := range syms { - if sym.Code != 'T' || sym.Size == 0 || sym.Name == "_text" || sym.Name == "text" || sym.Addr < textStart || symRE != nil && !symRE.MatchString(sym.Name) { + if (sym.Code != 'T' && sym.Code != 't') || sym.Size == 0 || sym.Name == "_text" || sym.Name == "text" || sym.Addr < textStart || symRE != nil && !symRE.MatchString(sym.Name) { continue } if sym.Addr >= textStart+uint64(len(textData)) || sym.Addr+uint64(sym.Size) > textStart+uint64(len(textData)) { diff --git a/src/cmd/objdump/objdump_test.go b/src/cmd/objdump/objdump_test.go index 541085626..0a2d2565a 100644 --- a/src/cmd/objdump/objdump_test.go +++ b/src/cmd/objdump/objdump_test.go @@ -157,12 +157,15 @@ var armNeed = []string{ // binary for the current system (only) and test that objdump // can handle that one. -func TestDisasm(t *testing.T) { +func testDisasm(t *testing.T, flags ...string) { tmp, exe := buildObjdump(t) defer os.RemoveAll(tmp) hello := filepath.Join(tmp, "hello.exe") - out, err := exec.Command("go", "build", "-o", hello, "testdata/fmthello.go").CombinedOutput() + args := []string{"build", "-o", hello} + args = append(args, flags...) + args = append(args, "testdata/fmthello.go") + out, err := exec.Command("go", args...).CombinedOutput() if err != nil { t.Fatalf("go build fmthello.go: %v\n%s", err, out) } @@ -194,3 +197,15 @@ func TestDisasm(t *testing.T) { t.Logf("full disassembly:\n%s", text) } } + +func TestDisasm(t *testing.T) { + testDisasm(t) +} + +func TestDisasmExtld(t *testing.T) { + switch runtime.GOOS { + case "plan9", "windows": + t.Skipf("skipping on %s", runtime.GOOS) + } + testDisasm(t, "-ldflags=-linkmode=external") +} |