summaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
authorAustin Clements <austin@google.com>2014-10-22 11:21:16 -0400
committerAustin Clements <austin@google.com>2014-10-22 11:21:16 -0400
commit2c586384223e980fd3303625ea6b02ed5d9fb9c0 (patch)
tree54aa72cd9d5eb1566f682d3b0770141a11b54fc2 /src/cmd
parentebe8a09fb603d9510cb982a6c11a3e1638f7f8fb (diff)
parent45fcda1dc8d9b4d4a9b642faf8e78941873f508d (diff)
downloadgo-2c586384223e980fd3303625ea6b02ed5d9fb9c0.tar.gz
[dev.power64] build: merge default into dev.power64
LGTM=rsc R=rsc CC=golang-codereviews https://codereview.appspot.com/160200044
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/5c/cgen.c34
-rw-r--r--src/cmd/5c/gc.h4
-rw-r--r--src/cmd/5c/sgen.c2
-rw-r--r--src/cmd/5c/swt.c9
-rw-r--r--src/cmd/5c/txt.c40
-rw-r--r--src/cmd/5g/cgen.c74
-rw-r--r--src/cmd/5g/gsubr.c1
-rw-r--r--src/cmd/5g/reg.c1
-rw-r--r--src/cmd/5l/asm.c4
-rw-r--r--src/cmd/6a/lex.c34
-rw-r--r--src/cmd/6c/cgen.c34
-rw-r--r--src/cmd/6c/gc.h4
-rw-r--r--src/cmd/6c/sgen.c7
-rw-r--r--src/cmd/6c/swt.c9
-rw-r--r--src/cmd/6c/txt.c40
-rw-r--r--src/cmd/6g/cgen.c8
-rw-r--r--src/cmd/6g/gg.h1
-rw-r--r--src/cmd/6g/ggen.c2
-rw-r--r--src/cmd/6g/gsubr.c7
-rw-r--r--src/cmd/6g/peep.c5
-rw-r--r--src/cmd/6g/reg.c3
-rw-r--r--src/cmd/6l/asm.c25
-rw-r--r--src/cmd/8a/lex.c34
-rw-r--r--src/cmd/8c/cgen.c34
-rw-r--r--src/cmd/8c/gc.h4
-rw-r--r--src/cmd/8c/sgen.c2
-rw-r--r--src/cmd/8c/swt.c9
-rw-r--r--src/cmd/8c/txt.c40
-rw-r--r--src/cmd/8g/cgen.c81
-rw-r--r--src/cmd/8g/ggen.c2
-rw-r--r--src/cmd/8g/gsubr.c1
-rw-r--r--src/cmd/8g/peep.c5
-rw-r--r--src/cmd/8g/reg.c1
-rw-r--r--src/cmd/8l/asm.c8
-rw-r--r--src/cmd/9c/cgen.c30
-rw-r--r--src/cmd/9c/gc.h5
-rw-r--r--src/cmd/9c/sgen.c2
-rw-r--r--src/cmd/9c/swt.c9
-rw-r--r--src/cmd/9c/txt.c40
-rw-r--r--src/cmd/9g/cgen.c1
-rw-r--r--src/cmd/9g/gg.h1
-rw-r--r--src/cmd/9g/gsubr.c7
-rw-r--r--src/cmd/9l/asm.c4
-rw-r--r--src/cmd/addr2line/main.go159
-rw-r--r--src/cmd/api/goapi.go46
-rw-r--r--src/cmd/api/run.go4
-rw-r--r--src/cmd/cc/cc.h2
-rw-r--r--src/cmd/cc/cc.y1
-rw-r--r--src/cmd/cc/dcl.c16
-rw-r--r--src/cmd/cc/godefs.c81
-rw-r--r--src/cmd/cc/pgen.c45
-rw-r--r--src/cmd/cgo/gcc.go94
-rw-r--r--src/cmd/cgo/out.go202
-rw-r--r--src/cmd/dist/a.h4
-rw-r--r--src/cmd/dist/buf.c2
-rw-r--r--src/cmd/dist/build.c47
-rw-r--r--src/cmd/dist/buildruntime.c58
-rw-r--r--src/cmd/dist/goc2c.c833
-rw-r--r--src/cmd/dist/plan9.c6
-rw-r--r--src/cmd/dist/unix.c16
-rw-r--r--src/cmd/dist/windows.c4
-rw-r--r--src/cmd/fix/doc.go2
-rw-r--r--src/cmd/gc/builtin.c18
-rw-r--r--src/cmd/gc/bv.c5
-rw-r--r--src/cmd/gc/const.c8
-rw-r--r--src/cmd/gc/fmt.c2
-rw-r--r--src/cmd/gc/gen.c55
-rw-r--r--src/cmd/gc/go.h3
-rw-r--r--src/cmd/gc/mparith1.c2
-rw-r--r--src/cmd/gc/mparith3.c4
-rw-r--r--src/cmd/gc/order.c26
-rw-r--r--src/cmd/gc/plive.c7
-rw-r--r--src/cmd/gc/popt.c2
-rw-r--r--src/cmd/gc/racewalk.c6
-rw-r--r--src/cmd/gc/reflect.c40
-rw-r--r--src/cmd/gc/runtime.go19
-rw-r--r--src/cmd/gc/select.c6
-rw-r--r--src/cmd/gc/subr.c113
-rw-r--r--src/cmd/gc/typecheck.c15
-rw-r--r--src/cmd/gc/walk.c105
-rw-r--r--src/cmd/go/build.go24
-rw-r--r--src/cmd/go/doc.go97
-rw-r--r--src/cmd/go/generate.go355
-rw-r--r--src/cmd/go/generate_test.go48
-rw-r--r--src/cmd/go/get.go4
-rw-r--r--src/cmd/go/main.go1
-rw-r--r--src/cmd/go/pkg.go91
-rwxr-xr-xsrc/cmd/go/test.bash90
-rw-r--r--src/cmd/go/testdata/generate/test1.go13
-rw-r--r--src/cmd/go/testdata/generate/test2.go10
-rw-r--r--src/cmd/go/testdata/generate/test3.go9
-rw-r--r--src/cmd/go/testdata/importcom/bad.go3
-rw-r--r--src/cmd/go/testdata/importcom/conflict.go3
-rw-r--r--src/cmd/go/testdata/importcom/src/bad/bad.go1
-rw-r--r--src/cmd/go/testdata/importcom/src/conflict/a.go1
-rw-r--r--src/cmd/go/testdata/importcom/src/conflict/b.go1
-rw-r--r--src/cmd/go/testdata/importcom/src/works/x/x.go1
-rw-r--r--src/cmd/go/testdata/importcom/src/works/x/x1.go1
-rw-r--r--src/cmd/go/testdata/importcom/src/wrongplace/x.go1
-rw-r--r--src/cmd/go/testdata/importcom/works.go3
-rw-r--r--src/cmd/go/testdata/importcom/wrongplace.go3
-rw-r--r--src/cmd/go/testdata/testinternal/p.go3
-rw-r--r--src/cmd/go/testdata/testinternal2/p.go3
-rw-r--r--src/cmd/go/testdata/testinternal2/x/y/z/internal/w/w.go1
-rw-r--r--src/cmd/go/vcs_test.go5
-rw-r--r--src/cmd/gofmt/gofmt.go11
-rw-r--r--src/cmd/gofmt/gofmt_test.go123
-rw-r--r--src/cmd/gofmt/testdata/composites.golden2
-rw-r--r--src/cmd/gofmt/testdata/composites.input2
-rw-r--r--src/cmd/gofmt/testdata/crlf.golden1
-rw-r--r--src/cmd/gofmt/testdata/crlf.input1
-rw-r--r--src/cmd/gofmt/testdata/emptydecl.golden4
-rw-r--r--src/cmd/gofmt/testdata/emptydecl.input4
-rw-r--r--src/cmd/gofmt/testdata/ranges.golden2
-rw-r--r--src/cmd/gofmt/testdata/ranges.input2
-rw-r--r--src/cmd/gofmt/testdata/rewrite1.golden2
-rw-r--r--src/cmd/gofmt/testdata/rewrite1.input2
-rw-r--r--src/cmd/gofmt/testdata/rewrite2.golden2
-rw-r--r--src/cmd/gofmt/testdata/rewrite2.input2
-rw-r--r--src/cmd/gofmt/testdata/rewrite3.golden2
-rw-r--r--src/cmd/gofmt/testdata/rewrite3.input2
-rw-r--r--src/cmd/gofmt/testdata/rewrite4.golden2
-rw-r--r--src/cmd/gofmt/testdata/rewrite4.input2
-rw-r--r--src/cmd/gofmt/testdata/rewrite5.golden2
-rw-r--r--src/cmd/gofmt/testdata/rewrite5.input2
-rw-r--r--src/cmd/gofmt/testdata/rewrite6.golden2
-rw-r--r--src/cmd/gofmt/testdata/rewrite6.input2
-rw-r--r--src/cmd/gofmt/testdata/rewrite7.golden2
-rw-r--r--src/cmd/gofmt/testdata/rewrite7.input2
-rw-r--r--src/cmd/gofmt/testdata/rewrite8.golden2
-rw-r--r--src/cmd/gofmt/testdata/rewrite8.input2
-rw-r--r--src/cmd/gofmt/testdata/slices1.golden2
-rw-r--r--src/cmd/gofmt/testdata/slices1.input2
-rw-r--r--src/cmd/gofmt/testdata/slices2.golden2
-rw-r--r--src/cmd/gofmt/testdata/slices2.input2
-rw-r--r--src/cmd/gofmt/testdata/stdin1.golden2
-rw-r--r--src/cmd/gofmt/testdata/stdin1.golden.gofmt3
-rw-r--r--src/cmd/gofmt/testdata/stdin1.input2
-rw-r--r--src/cmd/gofmt/testdata/stdin1.input.gofmt3
-rw-r--r--src/cmd/gofmt/testdata/stdin2.golden2
-rw-r--r--src/cmd/gofmt/testdata/stdin2.golden.gofmt10
-rw-r--r--src/cmd/gofmt/testdata/stdin2.input2
-rw-r--r--src/cmd/gofmt/testdata/stdin2.input.gofmt11
-rw-r--r--src/cmd/gofmt/testdata/stdin3.golden1
-rw-r--r--src/cmd/gofmt/testdata/stdin3.golden.gofmt7
-rw-r--r--src/cmd/gofmt/testdata/stdin3.input1
-rw-r--r--src/cmd/gofmt/testdata/stdin3.input.gofmt7
-rw-r--r--src/cmd/gofmt/testdata/stdin4.golden2
-rw-r--r--src/cmd/gofmt/testdata/stdin4.golden.gofmt3
-rw-r--r--src/cmd/gofmt/testdata/stdin4.input2
-rw-r--r--src/cmd/gofmt/testdata/stdin4.input.gofmt3
-rw-r--r--src/cmd/gofmt/testdata/stdin5.golden3
-rw-r--r--src/cmd/gofmt/testdata/stdin5.input3
-rw-r--r--src/cmd/internal/objfile/elf.go (renamed from src/cmd/nm/elf.go)44
-rw-r--r--src/cmd/internal/objfile/goobj.go (renamed from src/cmd/nm/goobj.go)35
-rw-r--r--src/cmd/internal/objfile/macho.go (renamed from src/cmd/nm/macho.go)49
-rw-r--r--src/cmd/internal/objfile/objfile.go72
-rw-r--r--src/cmd/internal/objfile/pe.go170
-rw-r--r--src/cmd/internal/objfile/plan9obj.go124
-rw-r--r--src/cmd/ld/data.c122
-rw-r--r--src/cmd/ld/lib.c57
-rw-r--r--src/cmd/ld/lib.h5
-rw-r--r--src/cmd/ld/pcln.c4
-rw-r--r--src/cmd/ld/pobj.c2
-rw-r--r--src/cmd/ld/symtab.c46
-rw-r--r--src/cmd/link/auto.go40
-rw-r--r--src/cmd/link/layout.go6
-rw-r--r--src/cmd/link/pclntab.go4
-rw-r--r--src/cmd/link/pclntab_test.go8
-rw-r--r--src/cmd/link/runtime.go4
-rw-r--r--src/cmd/link/testdata/Makefile2
-rw-r--r--src/cmd/link/testdata/autosection.6bin890 -> 942 bytes
-rw-r--r--src/cmd/link/testdata/autosection.s24
-rw-r--r--src/cmd/link/testdata/autoweak.6bin427 -> 387 bytes
-rw-r--r--src/cmd/link/testdata/dead.6bin1066 -> 854 bytes
-rw-r--r--src/cmd/link/testdata/dead.s3
-rw-r--r--src/cmd/link/testdata/genpcln.go2
-rw-r--r--src/cmd/link/testdata/hello.6bin273 -> 233 bytes
-rw-r--r--src/cmd/link/testdata/layout.6bin431 -> 391 bytes
-rw-r--r--src/cmd/link/testdata/layout.s2
-rw-r--r--src/cmd/link/testdata/link.hello.darwin.amd6411
-rw-r--r--src/cmd/link/testdata/pclntab.6bin4611 -> 3809 bytes
-rw-r--r--src/cmd/link/testdata/pclntab.s2
-rw-r--r--src/cmd/nm/nm.go57
-rw-r--r--src/cmd/nm/nm_test.go4
-rw-r--r--src/cmd/nm/pe.go98
-rw-r--r--src/cmd/nm/plan9obj.go48
-rw-r--r--src/cmd/objdump/main.go38
-rw-r--r--src/cmd/yacc/Makefile12
-rw-r--r--src/cmd/yacc/doc.go5
-rw-r--r--src/cmd/yacc/testdata/expr/README20
-rw-r--r--src/cmd/yacc/testdata/expr/expr.y (renamed from src/cmd/yacc/expr.y)5
-rw-r--r--src/cmd/yacc/testdata/expr/main.go15
193 files changed, 2765 insertions, 2132 deletions
diff --git a/src/cmd/5c/cgen.c b/src/cmd/5c/cgen.c
index 08ed36055..5ea8eea07 100644
--- a/src/cmd/5c/cgen.c
+++ b/src/cmd/5c/cgen.c
@@ -46,7 +46,7 @@ _cgen(Node *n, Node *nn, int inrel)
}
if(n == Z || n->type == T)
return;
- if(typesuv[n->type->etype]) {
+ if(typesuv[n->type->etype] && (n->op != OFUNC || nn != Z)) {
sugen(n, nn, n->type->width);
return;
}
@@ -75,7 +75,7 @@ _cgen(Node *n, Node *nn, int inrel)
if(r != Z && r->complex >= FNX)
switch(o) {
default:
- regret(&nod, r);
+ regret(&nod, r, 0, 0);
cgen(r, &nod);
regsalloc(&nod1, r);
@@ -107,7 +107,7 @@ _cgen(Node *n, Node *nn, int inrel)
if(l->addable >= INDEXED && l->complex < FNX) {
if(nn != Z || r->addable < INDEXED) {
if(r->complex >= FNX && nn == Z)
- regret(&nod, r);
+ regret(&nod, r, 0, 0);
else
regalloc(&nod, r, nn);
cgen(r, &nod);
@@ -348,7 +348,7 @@ _cgen(Node *n, Node *nn, int inrel)
if(l->op != OIND)
diag(n, "bad function call");
- regret(&nod, l->left);
+ regret(&nod, l->left, 0, 0);
cgen(l->left, &nod);
regsalloc(&nod1, l->left);
gopcode(OAS, &nod, Z, &nod1);
@@ -377,11 +377,11 @@ _cgen(Node *n, Node *nn, int inrel)
if(REGARG >= 0)
if(o != reg[REGARG])
reg[REGARG]--;
- if(nn != Z) {
- regret(&nod, n);
- gopcode(OAS, &nod, Z, nn);
+ regret(&nod, n, l->type, 1);
+ if(nn != Z)
+ gmove(&nod, nn);
+ if(nod.op == OREGISTER)
regfree(&nod);
- }
break;
case OIND:
@@ -823,7 +823,7 @@ boolgen(Node *n, int true, Node *nn)
if(true)
o = comrel[relindex(o)];
if(l->complex >= FNX && r->complex >= FNX) {
- regret(&nod, r);
+ regret(&nod, r, 0, 0);
cgenrel(r, &nod);
regsalloc(&nod1, r);
gopcode(OAS, &nod, Z, &nod1);
@@ -957,7 +957,7 @@ sugen(Node *n, Node *nn, int32 w)
if(nn != Z && side(nn)) {
nod1 = *n;
nod1.type = typ(TIND, n->type);
- regret(&nod2, &nod1);
+ regret(&nod2, &nod1, 0, 0);
lcgen(nn, &nod2);
regsalloc(&nod0, &nod1);
gopcode(OAS, &nod2, Z, &nod0);
@@ -1036,6 +1036,20 @@ sugen(Node *n, Node *nn, int32 w)
break;
case OFUNC:
+ if(!hasdotdotdot(n->left->type)) {
+ cgen(n, Z);
+ if(nn != Z) {
+ curarg -= n->type->width;
+ regret(&nod1, n, n->left->type, 1);
+ if(nn->complex >= FNX) {
+ regsalloc(&nod2, n);
+ cgen(&nod1, &nod2);
+ nod1 = nod2;
+ }
+ cgen(&nod1, nn);
+ }
+ break;
+ }
if(nn == Z) {
sugen(n, nodrat, w);
break;
diff --git a/src/cmd/5c/gc.h b/src/cmd/5c/gc.h
index 166900c3a..7417b7dbe 100644
--- a/src/cmd/5c/gc.h
+++ b/src/cmd/5c/gc.h
@@ -210,7 +210,7 @@ void usedset(Node*, int);
void xcom(Node*);
int bcomplex(Node*, Node*);
Prog* gtext(Sym*, int32);
-vlong argsize(void);
+vlong argsize(int);
/*
* cgen.c
@@ -236,7 +236,7 @@ Node* nodconst(int32);
Node* nod32const(vlong);
Node* nodfconst(double);
void nodreg(Node*, Node*, int);
-void regret(Node*, Node*);
+void regret(Node*, Node*, Type*, int);
int tmpreg(void);
void regalloc(Node*, Node*, Node*);
void regfree(Node*);
diff --git a/src/cmd/5c/sgen.c b/src/cmd/5c/sgen.c
index efcc0437b..a36612caa 100644
--- a/src/cmd/5c/sgen.c
+++ b/src/cmd/5c/sgen.c
@@ -36,7 +36,7 @@ gtext(Sym *s, int32 stkoff)
{
int32 a;
- a = argsize();
+ a = argsize(1);
if((textflag & NOSPLIT) != 0 && stkoff >= 128)
yyerror("stack frame too large for NOSPLIT function");
diff --git a/src/cmd/5c/swt.c b/src/cmd/5c/swt.c
index d24a5df9b..f39963b8f 100644
--- a/src/cmd/5c/swt.c
+++ b/src/cmd/5c/swt.c
@@ -374,10 +374,11 @@ align(int32 i, Type *t, int op, int32 *maxalign)
{
int32 o;
Type *v;
- int w;
+ int w, packw;
o = i;
w = 1;
+ packw = 0;
switch(op) {
default:
diag(Z, "unknown align opcode %d", op);
@@ -388,7 +389,7 @@ align(int32 i, Type *t, int op, int32 *maxalign)
if(w < 1)
w = 1;
if(packflg)
- w = packflg;
+ packw = packflg;
break;
case Ael1: /* initial align of struct element */
@@ -404,7 +405,7 @@ align(int32 i, Type *t, int op, int32 *maxalign)
if(w < 1 || w > SZ_LONG)
fatal(Z, "align");
if(packflg)
- w = packflg;
+ packw = packflg;
break;
case Ael2: /* width of a struct element */
@@ -440,6 +441,8 @@ align(int32 i, Type *t, int op, int32 *maxalign)
w = SZ_LONG; /* because of a pun in cc/dcl.c:contig() */
break;
}
+ if(packw != 0 && xround(o, w) != xround(o, packw))
+ diag(Z, "#pragma pack changes offset of %T", t);
o = xround(o, w);
if(maxalign != nil && *maxalign < w)
*maxalign = w;
diff --git a/src/cmd/5c/txt.c b/src/cmd/5c/txt.c
index a753510ca..af40220cc 100644
--- a/src/cmd/5c/txt.c
+++ b/src/cmd/5c/txt.c
@@ -274,15 +274,43 @@ nodreg(Node *n, Node *nn, int reg)
}
void
-regret(Node *n, Node *nn)
+regret(Node *n, Node *nn, Type *t, int mode)
{
int r;
- r = REGRET;
- if(typefd[nn->type->etype])
- r = FREGRET+NREG;
- nodreg(n, nn, r);
- reg[r]++;
+ if(mode == 0 || hasdotdotdot(t) || nn->type->width == 0) {
+ r = REGRET;
+ if(typefd[nn->type->etype])
+ r = FREGRET+NREG;
+ nodreg(n, nn, r);
+ reg[r]++;
+ return;
+ }
+
+ if(mode == 1) {
+ // fetch returned value after call.
+ // already called gargs, so curarg is set.
+ curarg = (curarg+3) & ~3;
+ regaalloc(n, nn);
+ return;
+ }
+
+ if(mode == 2) {
+ // store value to be returned.
+ // must compute arg offset.
+ if(t->etype != TFUNC)
+ fatal(Z, "bad regret func %T", t);
+ *n = *nn;
+ n->op = ONAME;
+ n->class = CPARAM;
+ n->sym = slookup(".ret");
+ n->complex = nodret->complex;
+ n->xoffset = argsize(0);
+ n->addable = 20;
+ return;
+ }
+
+ fatal(Z, "bad regret");
}
int
diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c
index a42e67baf..5fae7a564 100644
--- a/src/cmd/5g/cgen.c
+++ b/src/cmd/5g/cgen.c
@@ -254,7 +254,6 @@ cgen(Node *n, Node *res)
case OOR:
case OXOR:
case OADD:
- case OADDPTR:
case OMUL:
a = optoas(n->op, nl->type);
goto sbop;
@@ -1635,7 +1634,10 @@ int
componentgen(Node *nr, Node *nl)
{
Node nodl, nodr, tmp;
+ Type *t;
int freel, freer;
+ vlong fldcount;
+ vlong loffset, roffset;
freel = 0;
freer = 0;
@@ -1645,8 +1647,33 @@ componentgen(Node *nr, Node *nl)
goto no;
case TARRAY:
- if(!isslice(nl->type))
+ t = nl->type;
+
+ // Slices are ok.
+ if(isslice(t))
+ break;
+ // Small arrays are ok.
+ if(t->bound > 0 && t->bound <= 3 && !isfat(t->type))
+ break;
+
+ goto no;
+
+ case TSTRUCT:
+ // Small structs with non-fat types are ok.
+ // Zero-sized structs are treated separately elsewhere.
+ fldcount = 0;
+ for(t=nl->type->type; t; t=t->down) {
+ if(isfat(t->type))
+ goto no;
+ if(t->etype != TFIELD)
+ fatal("componentgen: not a TFIELD: %lT", t);
+ fldcount++;
+ }
+ if(fldcount == 0 || fldcount > 4)
goto no;
+
+ break;
+
case TSTRING:
case TINTER:
break;
@@ -1674,6 +1701,7 @@ componentgen(Node *nr, Node *nl)
freer = 1;
}
+
// nl and nr are 'cadable' which basically means they are names (variables) now.
// If they are the same variable, don't generate any code, because the
// VARDEF we generate will mark the old value as dead incorrectly.
@@ -1683,8 +1711,25 @@ componentgen(Node *nr, Node *nl)
switch(nl->type->etype) {
case TARRAY:
+ // componentgen for arrays.
if(nl->op == ONAME)
gvardef(nl);
+ t = nl->type;
+ if(!isslice(t)) {
+ nodl.type = t->type;
+ nodr.type = nodl.type;
+ for(fldcount=0; fldcount < t->bound; fldcount++) {
+ if(nr == N)
+ clearslim(&nodl);
+ else
+ gmove(&nodr, &nodl);
+ nodl.xoffset += t->type->width;
+ nodr.xoffset += t->type->width;
+ }
+ goto yes;
+ }
+
+ // componentgen for slices.
nodl.xoffset += Array_array;
nodl.type = ptrto(nl->type->type);
@@ -1759,6 +1804,31 @@ componentgen(Node *nr, Node *nl)
gmove(&nodr, &nodl);
goto yes;
+
+ case TSTRUCT:
+ if(nl->op == ONAME)
+ gvardef(nl);
+ loffset = nodl.xoffset;
+ roffset = nodr.xoffset;
+ // funarg structs may not begin at offset zero.
+ if(nl->type->etype == TSTRUCT && nl->type->funarg && nl->type->type)
+ loffset -= nl->type->type->width;
+ if(nr != N && nr->type->etype == TSTRUCT && nr->type->funarg && nr->type->type)
+ roffset -= nr->type->type->width;
+
+ for(t=nl->type->type; t; t=t->down) {
+ nodl.xoffset = loffset + t->width;
+ nodl.type = t->type;
+
+ if(nr == N)
+ clearslim(&nodl);
+ else {
+ nodr.xoffset = roffset + t->width;
+ nodr.type = nodl.type;
+ gmove(&nodr, &nodl);
+ }
+ }
+ goto yes;
}
no:
diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c
index 1241a23ea..5a70fcdda 100644
--- a/src/cmd/5g/gsubr.c
+++ b/src/cmd/5g/gsubr.c
@@ -1599,7 +1599,6 @@ optoas(int op, Type *t)
case CASE(OADD, TINT32):
case CASE(OADD, TUINT32):
case CASE(OADD, TPTR32):
- case CASE(OADDPTR, TPTR32):
a = AADD;
break;
diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c
index d259a232e..8e49a2d9c 100644
--- a/src/cmd/5g/reg.c
+++ b/src/cmd/5g/reg.c
@@ -1315,6 +1315,7 @@ void
addreg(Adr *a, int rn)
{
a->sym = nil;
+ a->node = nil;
a->name = D_NONE;
a->type = D_REG;
a->reg = rn;
diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c
index 02b4c78f1..9c1c04e2d 100644
--- a/src/cmd/5l/asm.c
+++ b/src/cmd/5l/asm.c
@@ -599,10 +599,10 @@ asmb(void)
if(iself)
goto ElfSym;
case Hplan9:
- symo = HEADR+segtext.len+segdata.filelen;
+ symo = segdata.fileoff+segdata.filelen;
break;
ElfSym:
- symo = rnd(HEADR+segtext.filelen, INITRND)+rnd(HEADR+segrodata.filelen, INITRND)+segdata.filelen;
+ symo = segdata.fileoff+segdata.filelen;
symo = rnd(symo, INITRND);
break;
}
diff --git a/src/cmd/6a/lex.c b/src/cmd/6a/lex.c
index 167e6b6c1..b50e1622e 100644
--- a/src/cmd/6a/lex.c
+++ b/src/cmd/6a/lex.c
@@ -435,49 +435,49 @@ struct
"IRETQ", LTYPE0, AIRETQ,
"IRETW", LTYPE0, AIRETW,
- "JOS", LTYPER, AJOS,
+ "JOS", LTYPER, AJOS, /* overflow set (OF = 1) */
"JO", LTYPER, AJOS, /* alternate */
- "JOC", LTYPER, AJOC,
+ "JOC", LTYPER, AJOC, /* overflow clear (OF = 0) */
"JNO", LTYPER, AJOC, /* alternate */
- "JCS", LTYPER, AJCS,
+ "JCS", LTYPER, AJCS, /* carry set (CF = 1) */
"JB", LTYPER, AJCS, /* alternate */
"JC", LTYPER, AJCS, /* alternate */
"JNAE", LTYPER, AJCS, /* alternate */
"JLO", LTYPER, AJCS, /* alternate */
- "JCC", LTYPER, AJCC,
+ "JCC", LTYPER, AJCC, /* carry clear (CF = 0) */
"JAE", LTYPER, AJCC, /* alternate */
"JNB", LTYPER, AJCC, /* alternate */
"JNC", LTYPER, AJCC, /* alternate */
"JHS", LTYPER, AJCC, /* alternate */
- "JEQ", LTYPER, AJEQ,
+ "JEQ", LTYPER, AJEQ, /* equal (ZF = 1) */
"JE", LTYPER, AJEQ, /* alternate */
"JZ", LTYPER, AJEQ, /* alternate */
- "JNE", LTYPER, AJNE,
+ "JNE", LTYPER, AJNE, /* not equal (ZF = 0) */
"JNZ", LTYPER, AJNE, /* alternate */
- "JLS", LTYPER, AJLS,
+ "JLS", LTYPER, AJLS, /* lower or same (unsigned) (CF = 1 || ZF = 1) */
"JBE", LTYPER, AJLS, /* alternate */
"JNA", LTYPER, AJLS, /* alternate */
- "JHI", LTYPER, AJHI,
+ "JHI", LTYPER, AJHI, /* higher (unsigned) (CF = 0 && ZF = 0) */
"JA", LTYPER, AJHI, /* alternate */
"JNBE", LTYPER, AJHI, /* alternate */
- "JMI", LTYPER, AJMI,
+ "JMI", LTYPER, AJMI, /* negative (minus) (SF = 1) */
"JS", LTYPER, AJMI, /* alternate */
- "JPL", LTYPER, AJPL,
+ "JPL", LTYPER, AJPL, /* non-negative (plus) (SF = 0) */
"JNS", LTYPER, AJPL, /* alternate */
- "JPS", LTYPER, AJPS,
+ "JPS", LTYPER, AJPS, /* parity set (PF = 1) */
"JP", LTYPER, AJPS, /* alternate */
"JPE", LTYPER, AJPS, /* alternate */
- "JPC", LTYPER, AJPC,
+ "JPC", LTYPER, AJPC, /* parity clear (PF = 0) */
"JNP", LTYPER, AJPC, /* alternate */
"JPO", LTYPER, AJPC, /* alternate */
- "JLT", LTYPER, AJLT,
+ "JLT", LTYPER, AJLT, /* less than (signed) (SF != OF) */
"JL", LTYPER, AJLT, /* alternate */
"JNGE", LTYPER, AJLT, /* alternate */
- "JGE", LTYPER, AJGE,
+ "JGE", LTYPER, AJGE, /* greater than or equal (signed) (SF = OF) */
"JNL", LTYPER, AJGE, /* alternate */
- "JLE", LTYPER, AJLE,
+ "JLE", LTYPER, AJLE, /* less than or equal (signed) (ZF = 1 || SF != OF) */
"JNG", LTYPER, AJLE, /* alternate */
- "JGT", LTYPER, AJGT,
+ "JGT", LTYPER, AJGT, /* greater than (signed) (ZF = 0 && SF = OF) */
"JG", LTYPER, AJGT, /* alternate */
"JNLE", LTYPER, AJGT, /* alternate */
"JCXZL", LTYPER, AJCXZL,
@@ -612,7 +612,7 @@ struct
"SCASL", LTYPE0, ASCASL,
"SCASQ", LTYPE0, ASCASQ,
"SCASW", LTYPE0, ASCASW,
- "SETCC", LTYPE1, ASETCC,
+ "SETCC", LTYPE1, ASETCC, /* see JCC etc above for condition codes */
"SETCS", LTYPE1, ASETCS,
"SETEQ", LTYPE1, ASETEQ,
"SETGE", LTYPE1, ASETGE,
diff --git a/src/cmd/6c/cgen.c b/src/cmd/6c/cgen.c
index bdef76ff0..b66c6add3 100644
--- a/src/cmd/6c/cgen.c
+++ b/src/cmd/6c/cgen.c
@@ -51,7 +51,7 @@ cgen(Node *n, Node *nn)
}
if(n == Z || n->type == T)
return;
- if(typesu[n->type->etype]) {
+ if(typesu[n->type->etype] && (n->op != OFUNC || nn != Z)) {
sugen(n, nn, n->type->width);
return;
}
@@ -88,7 +88,7 @@ cgen(Node *n, Node *nn)
if(cond(o) && typesu[l->type->etype])
break;
- regret(&nod, r);
+ regret(&nod, r, 0, 0);
cgen(r, &nod);
regsalloc(&nod1, r);
@@ -135,7 +135,7 @@ cgen(Node *n, Node *nn)
if(!hardleft) {
if(nn != Z || r->addable < INDEXED || hardconst(r)) {
if(r->complex >= FNX && nn == Z)
- regret(&nod, r);
+ regret(&nod, r, 0, 0);
else
regalloc(&nod, r, nn);
cgen(r, &nod);
@@ -929,7 +929,7 @@ cgen(Node *n, Node *nn)
if(l->op != OIND)
diag(n, "bad function call");
- regret(&nod, l->left);
+ regret(&nod, l->left, 0, 0);
cgen(l->left, &nod);
regsalloc(&nod1, l->left);
gmove(&nod, &nod1);
@@ -956,11 +956,13 @@ cgen(Node *n, Node *nn)
gpcdata(PCDATA_ArgSize, -1);
if(REGARG >= 0 && reg[REGARG])
reg[REGARG]--;
- if(nn != Z) {
- regret(&nod, n);
+ regret(&nod, n, l->type, 1); // update maxarg if nothing else
+ gpcdata(PCDATA_ArgSize, curarg);
+ gpcdata(PCDATA_ArgSize, -1);
+ if(nn != Z)
gmove(&nod, nn);
+ if(nod.op == OREGISTER)
regfree(&nod);
- }
break;
case OIND:
@@ -1382,7 +1384,7 @@ boolgen(Node *n, int true, Node *nn)
if(true)
o = comrel[relindex(o)];
if(l->complex >= FNX && r->complex >= FNX) {
- regret(&nod, r);
+ regret(&nod, r, 0, 0);
cgen(r, &nod);
regsalloc(&nod1, r);
gmove(&nod, &nod1);
@@ -1535,7 +1537,7 @@ sugen(Node *n, Node *nn, int32 w)
if(nn != Z && side(nn)) {
nod1 = *n;
nod1.type = typ(TIND, n->type);
- regret(&nod2, &nod1);
+ regret(&nod2, &nod1, 0, 0);
lcgen(nn, &nod2);
regsalloc(&nod0, &nod1);
cgen(&nod2, &nod0);
@@ -1617,6 +1619,20 @@ sugen(Node *n, Node *nn, int32 w)
break;
case OFUNC:
+ if(!hasdotdotdot(n->left->type)) {
+ cgen(n, Z);
+ if(nn != Z) {
+ curarg -= n->type->width;
+ regret(&nod1, n, n->left->type, 1);
+ if(nn->complex >= FNX) {
+ regsalloc(&nod2, n);
+ cgen(&nod1, &nod2);
+ nod1 = nod2;
+ }
+ cgen(&nod1, nn);
+ }
+ break;
+ }
if(nn == Z) {
sugen(n, nodrat, w);
break;
diff --git a/src/cmd/6c/gc.h b/src/cmd/6c/gc.h
index bc4e36ccd..aa9d95d21 100644
--- a/src/cmd/6c/gc.h
+++ b/src/cmd/6c/gc.h
@@ -210,7 +210,7 @@ void xcom(Node*);
void indx(Node*);
int bcomplex(Node*, Node*);
Prog* gtext(Sym*, int32);
-vlong argsize(void);
+vlong argsize(int);
/*
* cgen.c
@@ -239,7 +239,7 @@ Node* nodfconst(double);
Node* nodgconst(vlong, Type*);
int nodreg(Node*, Node*, int);
int isreg(Node*, int);
-void regret(Node*, Node*);
+void regret(Node*, Node*, Type*, int);
void regalloc(Node*, Node*, Node*);
void regfree(Node*);
void regialloc(Node*, Node*, Node*);
diff --git a/src/cmd/6c/sgen.c b/src/cmd/6c/sgen.c
index ba1c1f652..d99510185 100644
--- a/src/cmd/6c/sgen.c
+++ b/src/cmd/6c/sgen.c
@@ -36,7 +36,7 @@ gtext(Sym *s, int32 stkoff)
{
vlong v;
- v = ((uvlong)argsize() << 32) | (stkoff & 0xffffffff);
+ v = ((uvlong)argsize(1) << 32) | (stkoff & 0xffffffff);
if((textflag & NOSPLIT) && stkoff >= 128)
yyerror("stack frame too large for NOSPLIT function");
@@ -124,10 +124,7 @@ xcom(Node *n)
break;
case ONAME:
- if(flag_largemodel)
- n->addable = 9;
- else
- n->addable = 10;
+ n->addable = 9;
if(n->class == CPARAM || n->class == CAUTO)
n->addable = 11;
break;
diff --git a/src/cmd/6c/swt.c b/src/cmd/6c/swt.c
index d7713648d..6e918eb10 100644
--- a/src/cmd/6c/swt.c
+++ b/src/cmd/6c/swt.c
@@ -250,10 +250,11 @@ align(int32 i, Type *t, int op, int32 *maxalign)
{
int32 o;
Type *v;
- int w;
+ int w, packw;
o = i;
w = 1;
+ packw = 0;
switch(op) {
default:
diag(Z, "unknown align opcode %d", op);
@@ -264,7 +265,7 @@ align(int32 i, Type *t, int op, int32 *maxalign)
if(w < 1)
w = 1;
if(packflg)
- w = packflg;
+ packw = packflg;
break;
case Ael1: /* initial align of struct element */
@@ -277,7 +278,7 @@ align(int32 i, Type *t, int op, int32 *maxalign)
if(w < 1 || w > SZ_VLONG)
fatal(Z, "align");
if(packflg)
- w = packflg;
+ packw = packflg;
break;
case Ael2: /* width of a struct element */
@@ -331,6 +332,8 @@ align(int32 i, Type *t, int op, int32 *maxalign)
o = align(o, t, Ael2, nil);
break;
}
+ if(packw != 0 && xround(o, w) != xround(o, packw))
+ diag(Z, "#pragma pack changes offset of %T", t);
o = xround(o, w);
if(maxalign && *maxalign < w)
*maxalign = w;
diff --git a/src/cmd/6c/txt.c b/src/cmd/6c/txt.c
index 4d07436c3..3bdbf410e 100644
--- a/src/cmd/6c/txt.c
+++ b/src/cmd/6c/txt.c
@@ -351,15 +351,43 @@ nodreg(Node *n, Node *nn, int r)
}
void
-regret(Node *n, Node *nn)
+regret(Node *n, Node *nn, Type *t, int mode)
{
int r;
+
+ if(mode == 0 || hasdotdotdot(t) || nn->type->width == 0) {
+ r = REGRET;
+ if(typefd[nn->type->etype])
+ r = FREGRET;
+ nodreg(n, nn, r);
+ reg[r]++;
+ return;
+ }
+
+ if(mode == 1) {
+ // fetch returned value after call.
+ // already called gargs, so curarg is set.
+ curarg = (curarg+7) & ~7;
+ regaalloc(n, nn);
+ return;
+ }
- r = REGRET;
- if(typefd[nn->type->etype])
- r = FREGRET;
- nodreg(n, nn, r);
- reg[r]++;
+ if(mode == 2) {
+ // store value to be returned.
+ // must compute arg offset.
+ if(t->etype != TFUNC)
+ fatal(Z, "bad regret func %T", t);
+ *n = *nn;
+ n->op = ONAME;
+ n->class = CPARAM;
+ n->sym = slookup(".ret");
+ n->complex = nodret->complex;
+ n->addable = 20;
+ n->xoffset = argsize(0);
+ return;
+ }
+
+ fatal(Z, "bad regret");
}
void
diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c
index 4dd505b08..592e81542 100644
--- a/src/cmd/6g/cgen.c
+++ b/src/cmd/6g/cgen.c
@@ -247,7 +247,6 @@ cgen(Node *n, Node *res)
case OOR:
case OXOR:
case OADD:
- case OADDPTR:
case OMUL:
a = optoas(n->op, nl->type);
if(a == AIMULB) {
@@ -752,12 +751,7 @@ agenr(Node *n, Node *a, Node *res)
regalloc(&n3, types[tptr], res);
p1 = gins(ALEAQ, N, &n3);
datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
- if(flag_largemodel) {
- gins(AADDQ, &n2, &n3);
- } else {
- p1->from.scale = 1;
- p1->from.index = n2.val.u.reg;
- }
+ gins(AADDQ, &n2, &n3);
goto indexdone;
}
diff --git a/src/cmd/6g/gg.h b/src/cmd/6g/gg.h
index a5da17d61..27f6c01fe 100644
--- a/src/cmd/6g/gg.h
+++ b/src/cmd/6g/gg.h
@@ -51,7 +51,6 @@ void allocparams(void);
void checklabels(void);
void ginscall(Node*, int);
int gen_as_init(Node*);
-void clearslim(Node*);
/*
* cgen.c
diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c
index c385798f2..9665d831b 100644
--- a/src/cmd/6g/ggen.c
+++ b/src/cmd/6g/ggen.c
@@ -943,7 +943,7 @@ cgen_hmul(Node *nl, Node *nr, Node *res)
if(t->width == 1) {
// byte multiply behaves differently.
nodreg(&ax, t, D_AH);
- nodreg(&dx, t, D_DL);
+ nodreg(&dx, t, D_DX);
gmove(&ax, &dx);
}
nodreg(&dx, t, D_DX);
diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c
index f3464b7e1..a451d7d62 100644
--- a/src/cmd/6g/gsubr.c
+++ b/src/cmd/6g/gsubr.c
@@ -598,11 +598,8 @@ ismem(Node *n)
case ONAME:
case OPARAM:
case OCLOSUREVAR:
- return 1;
case OADDR:
- if(flag_largemodel)
- return 1;
- break;
+ return 1;
}
return 0;
}
@@ -1540,14 +1537,12 @@ optoas(int op, Type *t)
case CASE(OADD, TINT32):
case CASE(OADD, TUINT32):
case CASE(OADD, TPTR32):
- case CASE(OADDPTR, TPTR32):
a = AADDL;
break;
case CASE(OADD, TINT64):
case CASE(OADD, TUINT64):
case CASE(OADD, TPTR64):
- case CASE(OADDPTR, TPTR64):
a = AADDQ;
break;
diff --git a/src/cmd/6g/peep.c b/src/cmd/6g/peep.c
index 0f2720443..24617836f 100644
--- a/src/cmd/6g/peep.c
+++ b/src/cmd/6g/peep.c
@@ -838,6 +838,11 @@ copyu(Prog *p, Adr *v, Adr *s)
static int
copyas(Adr *a, Adr *v)
{
+ if(D_AL <= a->type && a->type <= D_R15B)
+ fatal("use of byte register");
+ if(D_AL <= v->type && v->type <= D_R15B)
+ fatal("use of byte register");
+
if(a->type != v->type)
return 0;
if(regtyp(v))
diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c
index 02945fb40..1f757e197 100644
--- a/src/cmd/6g/reg.c
+++ b/src/cmd/6g/reg.c
@@ -844,7 +844,7 @@ prop(Reg *r, Bits ref, Bits cal)
if(v == v1 || ((cal.b[j/32]>>(j&31))&1) == 0) {
for(; v1 != nil; v1 = v1->nextinnode) {
j = v1 - var;
- cal.b[j/32] |= 1<<(j&31);
+ cal.b[j/32] |= 1UL<<(j&31);
}
}
}
@@ -1191,6 +1191,7 @@ void
addreg(Adr *a, int rn)
{
a->sym = nil;
+ a->node = nil;
a->offset = 0;
a->type = rn;
diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c
index e251e32ca..18b5aa311 100644
--- a/src/cmd/6l/asm.c
+++ b/src/cmd/6l/asm.c
@@ -290,7 +290,6 @@ elfreloc1(Reloc *r, vlong sectoff)
break;
case R_CALL:
- case R_PCREL:
if(r->siz == 4) {
if(r->xsym->type == SDYNIMPORT)
VPUT(R_X86_64_GOTPCREL | (uint64)elfsym<<32);
@@ -299,7 +298,14 @@ elfreloc1(Reloc *r, vlong sectoff)
} else
return -1;
break;
-
+
+ case R_PCREL:
+ if(r->siz == 4) {
+ VPUT(R_X86_64_PC32 | (uint64)elfsym<<32);
+ } else
+ return -1;
+ break;
+
case R_TLS:
if(r->siz == 4) {
if(flag_shared)
@@ -323,7 +329,7 @@ machoreloc1(Reloc *r, vlong sectoff)
rs = r->xsym;
- if(rs->type == SHOSTOBJ) {
+ if(rs->type == SHOSTOBJ || r->type == R_PCREL) {
if(rs->dynid < 0) {
diag("reloc %d to non-macho symbol %s type=%d", r->type, rs->name, rs->type);
return -1;
@@ -345,10 +351,13 @@ machoreloc1(Reloc *r, vlong sectoff)
v |= MACHO_X86_64_RELOC_UNSIGNED<<28;
break;
case R_CALL:
- case R_PCREL:
v |= 1<<24; // pc-relative bit
v |= MACHO_X86_64_RELOC_BRANCH<<28;
break;
+ case R_PCREL:
+ // NOTE: Only works with 'external' relocation. Forced above.
+ v |= 1<<24; // pc-relative bit
+ v |= MACHO_X86_64_RELOC_SIGNED<<28;
}
switch(r->siz) {
@@ -689,10 +698,10 @@ asmb(void)
case Hplan9:
case Helf:
debug['s'] = 1;
- symo = HEADR+segtext.len+segdata.filelen;
+ symo = segdata.fileoff+segdata.filelen;
break;
case Hdarwin:
- symo = rnd(HEADR+segtext.len, INITRND)+rnd(segdata.filelen, INITRND)+machlink;
+ symo = segdata.fileoff+rnd(segdata.filelen, INITRND)+machlink;
break;
case Hlinux:
case Hfreebsd:
@@ -701,11 +710,11 @@ asmb(void)
case Hdragonfly:
case Hsolaris:
case Hnacl:
- symo = rnd(HEADR+segtext.len, INITRND)+rnd(segrodata.len, INITRND)+segdata.filelen;
+ symo = segdata.fileoff+segdata.filelen;
symo = rnd(symo, INITRND);
break;
case Hwindows:
- symo = rnd(HEADR+segtext.filelen, PEFILEALIGN)+segdata.filelen;
+ symo = segdata.fileoff+segdata.filelen;
symo = rnd(symo, PEFILEALIGN);
break;
}
diff --git a/src/cmd/8a/lex.c b/src/cmd/8a/lex.c
index 32c099b75..807e48cb5 100644
--- a/src/cmd/8a/lex.c
+++ b/src/cmd/8a/lex.c
@@ -352,49 +352,49 @@ struct
"IRETL", LTYPE0, AIRETL,
"IRETW", LTYPE0, AIRETW,
- "JOS", LTYPER, AJOS,
+ "JOS", LTYPER, AJOS, /* overflow set (OF = 1) */
"JO", LTYPER, AJOS, /* alternate */
- "JOC", LTYPER, AJOC,
+ "JOC", LTYPER, AJOC, /* overflow clear (OF = 0) */
"JNO", LTYPER, AJOC, /* alternate */
- "JCS", LTYPER, AJCS,
+ "JCS", LTYPER, AJCS, /* carry set (CF = 1) */
"JB", LTYPER, AJCS, /* alternate */
"JC", LTYPER, AJCS, /* alternate */
"JNAE", LTYPER, AJCS, /* alternate */
"JLO", LTYPER, AJCS, /* alternate */
- "JCC", LTYPER, AJCC,
+ "JCC", LTYPER, AJCC, /* carry clear (CF = 0) */
"JAE", LTYPER, AJCC, /* alternate */
"JNB", LTYPER, AJCC, /* alternate */
"JNC", LTYPER, AJCC, /* alternate */
"JHS", LTYPER, AJCC, /* alternate */
- "JEQ", LTYPER, AJEQ,
+ "JEQ", LTYPER, AJEQ, /* equal (ZF = 1) */
"JE", LTYPER, AJEQ, /* alternate */
"JZ", LTYPER, AJEQ, /* alternate */
- "JNE", LTYPER, AJNE,
+ "JNE", LTYPER, AJNE, /* not equal (ZF = 0) */
"JNZ", LTYPER, AJNE, /* alternate */
- "JLS", LTYPER, AJLS,
+ "JLS", LTYPER, AJLS, /* lower or same (unsigned) (CF = 1 || ZF = 1) */
"JBE", LTYPER, AJLS, /* alternate */
"JNA", LTYPER, AJLS, /* alternate */
- "JHI", LTYPER, AJHI,
+ "JHI", LTYPER, AJHI, /* higher (unsigned) (CF = 0 && ZF = 0) */
"JA", LTYPER, AJHI, /* alternate */
"JNBE", LTYPER, AJHI, /* alternate */
- "JMI", LTYPER, AJMI,
+ "JMI", LTYPER, AJMI, /* negative (minus) (SF = 1) */
"JS", LTYPER, AJMI, /* alternate */
- "JPL", LTYPER, AJPL,
+ "JPL", LTYPER, AJPL, /* non-negative (plus) (SF = 0) */
"JNS", LTYPER, AJPL, /* alternate */
- "JPS", LTYPER, AJPS,
+ "JPS", LTYPER, AJPS, /* parity set (PF = 1) */
"JP", LTYPER, AJPS, /* alternate */
"JPE", LTYPER, AJPS, /* alternate */
- "JPC", LTYPER, AJPC,
+ "JPC", LTYPER, AJPC, /* parity clear (PF = 0) */
"JNP", LTYPER, AJPC, /* alternate */
"JPO", LTYPER, AJPC, /* alternate */
- "JLT", LTYPER, AJLT,
+ "JLT", LTYPER, AJLT, /* less than (signed) (SF != OF) */
"JL", LTYPER, AJLT, /* alternate */
"JNGE", LTYPER, AJLT, /* alternate */
- "JGE", LTYPER, AJGE,
+ "JGE", LTYPER, AJGE, /* greater than or equal (signed) (SF = OF) */
"JNL", LTYPER, AJGE, /* alternate */
- "JLE", LTYPER, AJLE,
+ "JLE", LTYPER, AJLE, /* less than or equal (signed) (ZF = 1 || SF != OF) */
"JNG", LTYPER, AJLE, /* alternate */
- "JGT", LTYPER, AJGT,
+ "JGT", LTYPER, AJGT, /* greater than (signed) (ZF = 0 && SF = OF) */
"JG", LTYPER, AJGT, /* alternate */
"JNLE", LTYPER, AJGT, /* alternate */
@@ -493,7 +493,7 @@ struct
"SCASB", LTYPE0, ASCASB,
"SCASL", LTYPE0, ASCASL,
"SCASW", LTYPE0, ASCASW,
- "SETCC", LTYPE1, ASETCC,
+ "SETCC", LTYPE1, ASETCC, /* see JCC etc above for condition codes */
"SETCS", LTYPE1, ASETCS,
"SETEQ", LTYPE1, ASETEQ,
"SETGE", LTYPE1, ASETGE,
diff --git a/src/cmd/8c/cgen.c b/src/cmd/8c/cgen.c
index f54102245..8ac8e3600 100644
--- a/src/cmd/8c/cgen.c
+++ b/src/cmd/8c/cgen.c
@@ -49,7 +49,7 @@ cgen(Node *n, Node *nn)
}
if(n == Z || n->type == T)
return;
- if(typesuv[n->type->etype]) {
+ if(typesuv[n->type->etype] && (n->op != OFUNC || nn != Z)) {
sugen(n, nn, n->type->width);
return;
}
@@ -86,7 +86,7 @@ cgen(Node *n, Node *nn)
if(cond(o) && typesuv[l->type->etype])
break;
- regret(&nod, r);
+ regret(&nod, r, 0, 0);
cgen(r, &nod);
regsalloc(&nod1, r);
@@ -147,7 +147,7 @@ cgen(Node *n, Node *nn)
if(!hardleft) {
if(nn != Z || r->addable < INDEXED) {
if(r->complex >= FNX && nn == Z)
- regret(&nod, r);
+ regret(&nod, r, 0, 0);
else
regalloc(&nod, r, nn);
cgen(r, &nod);
@@ -922,7 +922,7 @@ cgen(Node *n, Node *nn)
if(l->op != OIND)
diag(n, "bad function call");
- regret(&nod, l->left);
+ regret(&nod, l->left, 0, 0);
cgen(l->left, &nod);
regsalloc(&nod1, l->left);
gmove(&nod, &nod1);
@@ -949,12 +949,12 @@ cgen(Node *n, Node *nn)
gpcdata(PCDATA_ArgSize, -1);
if(REGARG >= 0 && reg[REGARG])
reg[REGARG]--;
- if(nn != Z) {
- regret(&nod, n);
+ regret(&nod, n, l->type, 1); // update maxarg if nothing else
+ if(nn != Z)
gmove(&nod, nn);
+ if(nod.op == OREGISTER)
regfree(&nod);
- } else
- if(typefd[n->type->etype])
+ if(nn == Z && hasdotdotdot(l->type) && typefd[n->type->etype])
gins(AFMOVDP, &fregnode0, &fregnode0);
break;
@@ -1374,7 +1374,7 @@ boolgen(Node *n, int true, Node *nn)
if(true)
o = comrel[relindex(o)];
if(l->complex >= FNX && r->complex >= FNX) {
- regret(&nod, r);
+ regret(&nod, r, 0, 0);
cgen(r, &nod);
regsalloc(&nod1, r);
gmove(&nod, &nod1);
@@ -1567,7 +1567,7 @@ sugen(Node *n, Node *nn, int32 w)
if(nn != Z && side(nn)) {
nod1 = *n;
nod1.type = typ(TIND, n->type);
- regret(&nod2, &nod1);
+ regret(&nod2, &nod1, 0, 0);
lcgen(nn, &nod2);
regsalloc(&nod0, &nod1);
cgen(&nod2, &nod0);
@@ -1649,6 +1649,20 @@ sugen(Node *n, Node *nn, int32 w)
break;
case OFUNC:
+ if(!hasdotdotdot(n->left->type)) {
+ cgen(n, Z);
+ if(nn != Z) {
+ curarg -= n->type->width;
+ regret(&nod1, n, n->left->type, 1);
+ if(nn->complex >= FNX) {
+ regsalloc(&nod2, n);
+ cgen(&nod1, &nod2);
+ nod1 = nod2;
+ }
+ cgen(&nod1, nn);
+ }
+ break;
+ }
if(nn == Z) {
sugen(n, nodrat, w);
break;
diff --git a/src/cmd/8c/gc.h b/src/cmd/8c/gc.h
index 9c4613f56..aa3888d73 100644
--- a/src/cmd/8c/gc.h
+++ b/src/cmd/8c/gc.h
@@ -210,7 +210,7 @@ void xcom(Node*);
void indx(Node*);
int bcomplex(Node*, Node*);
Prog* gtext(Sym*, int32);
-vlong argsize(void);
+vlong argsize(int);
/*
* cgen.c
@@ -244,7 +244,7 @@ Node* nodconst(int32);
Node* nodfconst(double);
int nodreg(Node*, Node*, int);
int isreg(Node*, int);
-void regret(Node*, Node*);
+void regret(Node*, Node*, Type*, int);
void regalloc(Node*, Node*, Node*);
void regfree(Node*);
void regialloc(Node*, Node*, Node*);
diff --git a/src/cmd/8c/sgen.c b/src/cmd/8c/sgen.c
index 069bbc1fc..d647010ef 100644
--- a/src/cmd/8c/sgen.c
+++ b/src/cmd/8c/sgen.c
@@ -35,7 +35,7 @@ gtext(Sym *s, int32 stkoff)
{
int32 a;
- a = argsize();
+ a = argsize(1);
if((textflag & NOSPLIT) != 0 && stkoff >= 128)
yyerror("stack frame too large for NOSPLIT function");
diff --git a/src/cmd/8c/swt.c b/src/cmd/8c/swt.c
index ae36f84ea..d960519e3 100644
--- a/src/cmd/8c/swt.c
+++ b/src/cmd/8c/swt.c
@@ -255,10 +255,11 @@ align(int32 i, Type *t, int op, int32 *maxalign)
{
int32 o;
Type *v;
- int w;
+ int w, packw;
o = i;
w = 1;
+ packw = 0;
switch(op) {
default:
diag(Z, "unknown align opcode %d", op);
@@ -269,7 +270,7 @@ align(int32 i, Type *t, int op, int32 *maxalign)
if(w < 1)
w = 1;
if(packflg)
- w = packflg;
+ packw = packflg;
break;
case Ael1: /* initial align of struct element */
@@ -285,7 +286,7 @@ align(int32 i, Type *t, int op, int32 *maxalign)
if(w < 1 || w > SZ_LONG)
fatal(Z, "align");
if(packflg)
- w = packflg;
+ packw = packflg;
break;
case Ael2: /* width of a struct element */
@@ -320,6 +321,8 @@ align(int32 i, Type *t, int op, int32 *maxalign)
o = align(o, t, Ael2, nil);
break;
}
+ if(packw != 0 && xround(o, w) != xround(o, packw))
+ diag(Z, "#pragma pack changes offset of %T", t);
o = xround(o, w);
if(maxalign && *maxalign < w)
*maxalign = w;
diff --git a/src/cmd/8c/txt.c b/src/cmd/8c/txt.c
index 25082de05..7f87a0a0d 100644
--- a/src/cmd/8c/txt.c
+++ b/src/cmd/8c/txt.c
@@ -311,15 +311,43 @@ nodreg(Node *n, Node *nn, int r)
}
void
-regret(Node *n, Node *nn)
+regret(Node *n, Node *nn, Type *t, int mode)
{
int r;
- r = REGRET;
- if(typefd[nn->type->etype])
- r = FREGRET;
- nodreg(n, nn, r);
- reg[r]++;
+ if(mode == 0 || hasdotdotdot(t) || nn->type->width == 0) {
+ r = REGRET;
+ if(typefd[nn->type->etype])
+ r = FREGRET;
+ nodreg(n, nn, r);
+ reg[r]++;
+ return;
+ }
+
+ if(mode == 1) {
+ // fetch returned value after call.
+ // already called gargs, so curarg is set.
+ curarg = (curarg+3) & ~3;
+ regaalloc(n, nn);
+ return;
+ }
+
+ if(mode == 2) {
+ // store value to be returned.
+ // must compute arg offset.
+ if(t->etype != TFUNC)
+ fatal(Z, "bad regret func %T", t);
+ *n = *nn;
+ n->op = ONAME;
+ n->class = CPARAM;
+ n->sym = slookup(".retx");
+ n->complex = 0;
+ n->addable = 20;
+ n->xoffset = argsize(0);
+ return;
+ }
+
+ fatal(Z, "bad regret");
}
void
diff --git a/src/cmd/8g/cgen.c b/src/cmd/8g/cgen.c
index 5988a4328..f3093bc26 100644
--- a/src/cmd/8g/cgen.c
+++ b/src/cmd/8g/cgen.c
@@ -242,7 +242,6 @@ cgen(Node *n, Node *res)
case OOR:
case OXOR:
case OADD:
- case OADDPTR:
case OMUL:
a = optoas(n->op, nl->type);
if(a == AIMULB) {
@@ -1367,7 +1366,10 @@ int
componentgen(Node *nr, Node *nl)
{
Node nodl, nodr;
+ Type *t;
int freel, freer;
+ vlong fldcount;
+ vlong loffset, roffset;
freel = 0;
freer = 0;
@@ -1377,8 +1379,33 @@ componentgen(Node *nr, Node *nl)
goto no;
case TARRAY:
- if(!isslice(nl->type))
+ t = nl->type;
+
+ // Slices are ok.
+ if(isslice(t))
+ break;
+ // Small arrays are ok.
+ if(t->bound > 0 && t->bound <= 3 && !isfat(t->type))
+ break;
+
+ goto no;
+
+ case TSTRUCT:
+ // Small structs with non-fat types are ok.
+ // Zero-sized structs are treated separately elsewhere.
+ fldcount = 0;
+ for(t=nl->type->type; t; t=t->down) {
+ if(isfat(t->type))
+ goto no;
+ if(t->etype != TFIELD)
+ fatal("componentgen: not a TFIELD: %lT", t);
+ fldcount++;
+ }
+ if(fldcount == 0 || fldcount > 4)
goto no;
+
+ break;
+
case TSTRING:
case TINTER:
break;
@@ -1399,7 +1426,7 @@ componentgen(Node *nr, Node *nl)
freer = 1;
}
}
-
+
// nl and nr are 'cadable' which basically means they are names (variables) now.
// If they are the same variable, don't generate any code, because the
// VARDEF we generate will mark the old value as dead incorrectly.
@@ -1409,8 +1436,25 @@ componentgen(Node *nr, Node *nl)
switch(nl->type->etype) {
case TARRAY:
+ // componentgen for arrays.
if(nl->op == ONAME)
gvardef(nl);
+ t = nl->type;
+ if(!isslice(t)) {
+ nodl.type = t->type;
+ nodr.type = nodl.type;
+ for(fldcount=0; fldcount < t->bound; fldcount++) {
+ if(nr == N)
+ clearslim(&nodl);
+ else
+ gmove(&nodr, &nodl);
+ nodl.xoffset += t->type->width;
+ nodr.xoffset += t->type->width;
+ }
+ goto yes;
+ }
+
+ // componentgen for slices.
nodl.xoffset += Array_array;
nodl.type = ptrto(nl->type->type);
@@ -1422,7 +1466,7 @@ componentgen(Node *nr, Node *nl)
gmove(&nodr, &nodl);
nodl.xoffset += Array_nel-Array_array;
- nodl.type = types[TUINT32];
+ nodl.type = types[simtype[TUINT]];
if(nr != N) {
nodr.xoffset += Array_nel-Array_array;
@@ -1432,7 +1476,7 @@ componentgen(Node *nr, Node *nl)
gmove(&nodr, &nodl);
nodl.xoffset += Array_cap-Array_nel;
- nodl.type = types[TUINT32];
+ nodl.type = types[simtype[TUINT]];
if(nr != N) {
nodr.xoffset += Array_cap-Array_nel;
@@ -1457,7 +1501,7 @@ componentgen(Node *nr, Node *nl)
gmove(&nodr, &nodl);
nodl.xoffset += Array_nel-Array_array;
- nodl.type = types[TUINT32];
+ nodl.type = types[simtype[TUINT]];
if(nr != N) {
nodr.xoffset += Array_nel-Array_array;
@@ -1492,6 +1536,31 @@ componentgen(Node *nr, Node *nl)
gmove(&nodr, &nodl);
goto yes;
+
+ case TSTRUCT:
+ if(nl->op == ONAME)
+ gvardef(nl);
+ loffset = nodl.xoffset;
+ roffset = nodr.xoffset;
+ // funarg structs may not begin at offset zero.
+ if(nl->type->etype == TSTRUCT && nl->type->funarg && nl->type->type)
+ loffset -= nl->type->type->width;
+ if(nr != N && nr->type->etype == TSTRUCT && nr->type->funarg && nr->type->type)
+ roffset -= nr->type->type->width;
+
+ for(t=nl->type->type; t; t=t->down) {
+ nodl.xoffset = loffset + t->width;
+ nodl.type = t->type;
+
+ if(nr == N)
+ clearslim(&nodl);
+ else {
+ nodr.xoffset = roffset + t->width;
+ nodr.type = nodl.type;
+ gmove(&nodr, &nodl);
+ }
+ }
+ goto yes;
}
no:
diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c
index 2285a04e6..5e3140480 100644
--- a/src/cmd/8g/ggen.c
+++ b/src/cmd/8g/ggen.c
@@ -991,7 +991,7 @@ cgen_hmul(Node *nl, Node *nr, Node *res)
if(t->width == 1) {
// byte multiply behaves differently.
nodreg(&ax, t, D_AH);
- nodreg(&dx, t, D_DL);
+ nodreg(&dx, t, D_DX);
gmove(&ax, &dx);
}
nodreg(&dx, t, D_DX);
diff --git a/src/cmd/8g/gsubr.c b/src/cmd/8g/gsubr.c
index 66d5b8d69..9ee418cb7 100644
--- a/src/cmd/8g/gsubr.c
+++ b/src/cmd/8g/gsubr.c
@@ -430,7 +430,6 @@ optoas(int op, Type *t)
case CASE(OADD, TINT32):
case CASE(OADD, TUINT32):
case CASE(OADD, TPTR32):
- case CASE(OADDPTR, TPTR32):
a = AADDL;
break;
diff --git a/src/cmd/8g/peep.c b/src/cmd/8g/peep.c
index d88987f95..91a91d20d 100644
--- a/src/cmd/8g/peep.c
+++ b/src/cmd/8g/peep.c
@@ -636,6 +636,11 @@ copyu(Prog *p, Adr *v, Adr *s)
static int
copyas(Adr *a, Adr *v)
{
+ if(D_AL <= a->type && a->type <= D_BL)
+ fatal("use of byte register");
+ if(D_AL <= v->type && v->type <= D_BL)
+ fatal("use of byte register");
+
if(a->type != v->type)
return 0;
if(regtyp(v))
diff --git a/src/cmd/8g/reg.c b/src/cmd/8g/reg.c
index a69d124db..302b273a1 100644
--- a/src/cmd/8g/reg.c
+++ b/src/cmd/8g/reg.c
@@ -1168,6 +1168,7 @@ void
addreg(Adr *a, int rn)
{
a->sym = nil;
+ a->node = nil;
a->offset = 0;
a->type = rn;
diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c
index 114a3eb5d..c135dce70 100644
--- a/src/cmd/8l/asm.c
+++ b/src/cmd/8l/asm.c
@@ -619,17 +619,17 @@ asmb(void)
if(iself)
goto Elfsym;
case Hplan9:
- symo = HEADR+segtext.filelen+segdata.filelen;
+ symo = segdata.fileoff+segdata.filelen;
break;
case Hdarwin:
- symo = rnd(HEADR+segtext.filelen, INITRND)+rnd(segdata.filelen, INITRND)+machlink;
+ symo = segdata.fileoff+rnd(segdata.filelen, INITRND)+machlink;
break;
Elfsym:
- symo = rnd(HEADR+segtext.filelen, INITRND)+rnd(HEADR+segrodata.filelen, INITRND)+segdata.filelen;
+ symo = segdata.fileoff+segdata.filelen;
symo = rnd(symo, INITRND);
break;
case Hwindows:
- symo = rnd(HEADR+segtext.filelen, PEFILEALIGN)+segdata.filelen;
+ symo = segdata.fileoff+segdata.filelen;
symo = rnd(symo, PEFILEALIGN);
break;
}
diff --git a/src/cmd/9c/cgen.c b/src/cmd/9c/cgen.c
index 0d7a40294..aeedc60c0 100644
--- a/src/cmd/9c/cgen.c
+++ b/src/cmd/9c/cgen.c
@@ -45,7 +45,7 @@ cgen(Node *n, Node *nn)
}
if(n == Z || n->type == T)
return;
- if(typesu[n->type->etype]) {
+ if(typesu[n->type->etype] && (n->op != OFUNC || nn != Z)) {
sugen(n, nn, n->type->width);
return;
}
@@ -74,7 +74,7 @@ cgen(Node *n, Node *nn)
if(r != Z && r->complex >= FNX)
switch(o) {
default:
- regret(&nod, r);
+ regret(&nod, r, 0, 0);
cgen(r, &nod);
regsalloc(&nod1, r);
@@ -324,7 +324,7 @@ cgen(Node *n, Node *nn)
if(l->op != OIND)
diag(n, "bad function call");
- regret(&nod, l->left);
+ regret(&nod, l->left, 0, 0);
cgen(l->left, &nod);
regsalloc(&nod1, l->left);
gopcode(OAS, &nod, Z, &nod1);
@@ -353,11 +353,13 @@ cgen(Node *n, Node *nn)
if(REGARG>=0)
if(o != reg[REGARG])
reg[REGARG]--;
- if(nn != Z) {
- regret(&nod, n);
+ regret(&nod, n, l->type, 1); // update maxarg if nothing else
+ gpcdata(PCDATA_ArgSize, curarg);
+ gpcdata(PCDATA_ArgSize, -1);
+ if(nn != Z)
gopcode(OAS, &nod, Z, nn);
+ if(nod.op == OREGISTER)
regfree(&nod);
- }
break;
case OIND:
@@ -759,7 +761,7 @@ boolgen(Node *n, int true, Node *nn)
if(true)
o = comrel[relindex(o)];
if(l->complex >= FNX && r->complex >= FNX) {
- regret(&nod, r);
+ regret(&nod, r, 0, 0);
cgen(r, &nod);
regsalloc(&nod1, r);
gopcode(OAS, &nod, Z, &nod1);
@@ -966,6 +968,20 @@ sugen(Node *n, Node *nn, int32 w)
break;
case OFUNC:
+ if(!hasdotdotdot(n->left->type)) {
+ cgen(n, Z);
+ if(nn != Z) {
+ curarg -= n->type->width;
+ regret(&nod1, n, n->left->type, 1);
+ if(nn->complex >= FNX) {
+ regsalloc(&nod2, n);
+ cgen(&nod1, &nod2);
+ nod1 = nod2;
+ }
+ cgen(&nod1, nn);
+ }
+ break;
+ }
if(nn == Z) {
sugen(n, nodrat, w);
break;
diff --git a/src/cmd/9c/gc.h b/src/cmd/9c/gc.h
index 82204902b..fbe5099fe 100644
--- a/src/cmd/9c/gc.h
+++ b/src/cmd/9c/gc.h
@@ -141,7 +141,6 @@ extern int hintabsize;
EXTERN int32 maxargsafe;
EXTERN Multab multab[20];
EXTERN int mnstring;
-EXTERN int retok;
EXTERN Node* nodrat;
EXTERN Node* nodret;
EXTERN Node* nodsafe;
@@ -212,7 +211,7 @@ void noretval(int);
void xcom(Node*);
int bcomplex(Node*, Node*);
Prog* gtext(Sym*, int32);
-vlong argsize(void);
+vlong argsize(int);
/*
* cgen.c
@@ -238,7 +237,7 @@ Node* nod32const(vlong);
Node* nodfconst(double);
Node* nodgconst(vlong v, Type *t);
void nodreg(Node*, Node*, int);
-void regret(Node*, Node*);
+void regret(Node*, Node*, Type*, int);
void regalloc(Node*, Node*, Node*);
void regfree(Node*);
void regialloc(Node*, Node*, Node*);
diff --git a/src/cmd/9c/sgen.c b/src/cmd/9c/sgen.c
index 25f0438e5..b03c17267 100644
--- a/src/cmd/9c/sgen.c
+++ b/src/cmd/9c/sgen.c
@@ -34,7 +34,7 @@ gtext(Sym *s, int32 stkoff)
{
vlong v;
- v = ((uvlong)argsize() << 32) | (stkoff & 0xffffffff);
+ v = ((uvlong)argsize(1) << 32) | (stkoff & 0xffffffff);
if((textflag & NOSPLIT) && stkoff >= 128)
yyerror("stack frame too large for NOSPLIT function");
diff --git a/src/cmd/9c/swt.c b/src/cmd/9c/swt.c
index 83058e7ab..a63db60b2 100644
--- a/src/cmd/9c/swt.c
+++ b/src/cmd/9c/swt.c
@@ -324,10 +324,11 @@ align(int32 i, Type *t, int op, int32 *maxalign)
{
int32 o;
Type *v;
- int w;
+ int w, packw;
o = i;
w = 1;
+ packw = 0;
switch(op) {
default:
diag(Z, "unknown align opcode %d", op);
@@ -338,7 +339,7 @@ align(int32 i, Type *t, int op, int32 *maxalign)
if(w < 1)
w = 1;
if(packflg)
- w = packflg;
+ packw = packflg;
break;
case Ael1: /* initial allign of struct element */
@@ -351,7 +352,7 @@ align(int32 i, Type *t, int op, int32 *maxalign)
if(w < 1 || w > SZ_VLONG)
fatal(Z, "align");
if(packflg)
- w = packflg;
+ packw = packflg;
break;
case Ael2: /* width of a struct element */
@@ -386,6 +387,8 @@ align(int32 i, Type *t, int op, int32 *maxalign)
o = align(o, t, Ael2, nil);
break;
}
+ if(packw != 0 && xround(o, w) != xround(o, packw))
+ diag(Z, "#pragma pack changes offset of %T", t);
o = xround(o, w);
if(maxalign && *maxalign < w)
*maxalign = w;
diff --git a/src/cmd/9c/txt.c b/src/cmd/9c/txt.c
index 84aeb4d8a..e46aba84e 100644
--- a/src/cmd/9c/txt.c
+++ b/src/cmd/9c/txt.c
@@ -319,15 +319,43 @@ nodreg(Node *n, Node *nn, int reg)
}
void
-regret(Node *n, Node *nn)
+regret(Node *n, Node *nn, Type *t, int mode)
{
int r;
+
+ if(mode == 0 || hasdotdotdot(t) || nn->type->width == 0) {
+ r = REGRET;
+ if(typefd[nn->type->etype])
+ r = FREGRET+NREG;
+ nodreg(n, nn, r);
+ reg[r]++;
+ return;
+ }
+
+ if(mode == 1) {
+ // fetch returned value after call.
+ // already called gargs, so curarg is set.
+ curarg = (curarg+7) & ~7;
+ regaalloc(n, nn);
+ return;
+ }
- r = REGRET;
- if(typefd[nn->type->etype])
- r = FREGRET+NREG;
- nodreg(n, nn, r);
- reg[r]++;
+ if(mode == 2) {
+ // store value to be returned.
+ // must compute arg offset.
+ if(t->etype != TFUNC)
+ fatal(Z, "bad regret func %T", t);
+ *n = *nn;
+ n->op = ONAME;
+ n->class = CPARAM;
+ n->sym = slookup(".ret");
+ n->complex = nodret->complex;
+ n->addable = 20;
+ n->xoffset = argsize(0);
+ return;
+ }
+
+ fatal(Z, "bad regret");
}
void
diff --git a/src/cmd/9g/cgen.c b/src/cmd/9g/cgen.c
index 86a56975a..e38936001 100644
--- a/src/cmd/9g/cgen.c
+++ b/src/cmd/9g/cgen.c
@@ -260,7 +260,6 @@ cgen(Node *n, Node *res)
case OOR:
case OXOR:
case OADD:
- case OADDPTR:
case OMUL:
a = optoas(n->op, nl->type);
goto sbop;
diff --git a/src/cmd/9g/gg.h b/src/cmd/9g/gg.h
index 6aa00117f..2eb516b40 100644
--- a/src/cmd/9g/gg.h
+++ b/src/cmd/9g/gg.h
@@ -49,7 +49,6 @@ void allocparams(void);
void checklabels(void);
void ginscall(Node*, int);
int gen_as_init(Node*);
-void clearslim(Node*);
/*
* cgen.c
diff --git a/src/cmd/9g/gsubr.c b/src/cmd/9g/gsubr.c
index dfdff0587..b194cfd9e 100644
--- a/src/cmd/9g/gsubr.c
+++ b/src/cmd/9g/gsubr.c
@@ -614,11 +614,8 @@ ismem(Node *n)
case ONAME:
case OPARAM:
case OCLOSUREVAR:
- return 1;
case OADDR:
- //if(flag_largemodel)
- return 1;
- break;
+ return 1;
}
return 0;
}
@@ -1474,11 +1471,9 @@ optoas(int op, Type *t)
case CASE(OADD, TINT32):
case CASE(OADD, TUINT32):
case CASE(OADD, TPTR32):
- case CASE(OADDPTR, TPTR32):
case CASE(OADD, TINT64):
case CASE(OADD, TUINT64):
case CASE(OADD, TPTR64):
- case CASE(OADDPTR, TPTR64):
a = AADD;
break;
diff --git a/src/cmd/9l/asm.c b/src/cmd/9l/asm.c
index 5aeea1b6b..b8ca777c3 100644
--- a/src/cmd/9l/asm.c
+++ b/src/cmd/9l/asm.c
@@ -245,10 +245,10 @@ asmb(void)
if(iself)
goto ElfSym;
case Hplan9:
- symo = HEADR+segtext.len+segdata.filelen;
+ symo = segdata.fileoff+segdata.filelen;
break;
ElfSym:
- symo = rnd(HEADR+segtext.filelen, INITRND)+rnd(HEADR+segrodata.filelen, INITRND)+segdata.filelen;
+ symo = segdata.fileoff+segdata.filelen;
symo = rnd(symo, INITRND);
break;
}
diff --git a/src/cmd/addr2line/main.go b/src/cmd/addr2line/main.go
index 3802f764f..267f4170a 100644
--- a/src/cmd/addr2line/main.go
+++ b/src/cmd/addr2line/main.go
@@ -19,17 +19,14 @@ package main
import (
"bufio"
- "debug/elf"
- "debug/gosym"
- "debug/macho"
- "debug/pe"
- "debug/plan9obj"
"flag"
"fmt"
"log"
"os"
"strconv"
"strings"
+
+ "cmd/internal/objfile"
)
func printUsage(w *os.File) {
@@ -60,18 +57,12 @@ func main() {
usage()
}
- f, err := os.Open(flag.Arg(0))
+ f, err := objfile.Open(flag.Arg(0))
if err != nil {
log.Fatal(err)
}
- textStart, symtab, pclntab, err := loadTables(f)
- if err != nil {
- log.Fatalf("reading %s: %v", flag.Arg(0), err)
- }
-
- pcln := gosym.NewLineTable(pclntab, textStart)
- tab, err := gosym.NewTable(symtab, pcln)
+ tab, err := f.PCLineTable()
if err != nil {
log.Fatalf("reading %s: %v", flag.Arg(0), err)
}
@@ -102,145 +93,3 @@ func main() {
}
stdout.Flush()
}
-
-func loadTables(f *os.File) (textStart uint64, symtab, pclntab []byte, err error) {
- if obj, err := elf.NewFile(f); err == nil {
- if sect := obj.Section(".text"); sect != nil {
- textStart = sect.Addr
- }
- if sect := obj.Section(".gosymtab"); sect != nil {
- if symtab, err = sect.Data(); err != nil {
- return 0, nil, nil, err
- }
- }
- if sect := obj.Section(".gopclntab"); sect != nil {
- if pclntab, err = sect.Data(); err != nil {
- return 0, nil, nil, err
- }
- }
- return textStart, symtab, pclntab, nil
- }
-
- if obj, err := macho.NewFile(f); err == nil {
- if sect := obj.Section("__text"); sect != nil {
- textStart = sect.Addr
- }
- if sect := obj.Section("__gosymtab"); sect != nil {
- if symtab, err = sect.Data(); err != nil {
- return 0, nil, nil, err
- }
- }
- if sect := obj.Section("__gopclntab"); sect != nil {
- if pclntab, err = sect.Data(); err != nil {
- return 0, nil, nil, err
- }
- }
- return textStart, symtab, pclntab, nil
- }
-
- if obj, err := pe.NewFile(f); err == nil {
- var imageBase uint64
- switch oh := obj.OptionalHeader.(type) {
- case *pe.OptionalHeader32:
- imageBase = uint64(oh.ImageBase)
- case *pe.OptionalHeader64:
- imageBase = oh.ImageBase
- default:
- return 0, nil, nil, fmt.Errorf("pe file format not recognized")
- }
- if sect := obj.Section(".text"); sect != nil {
- textStart = imageBase + uint64(sect.VirtualAddress)
- }
- if pclntab, err = loadPETable(obj, "pclntab", "epclntab"); err != nil {
- return 0, nil, nil, err
- }
- if symtab, err = loadPETable(obj, "symtab", "esymtab"); err != nil {
- return 0, nil, nil, err
- }
- return textStart, symtab, pclntab, nil
- }
-
- if obj, err := plan9obj.NewFile(f); err == nil {
- textStart = obj.LoadAddress + obj.HdrSize
- if pclntab, err = loadPlan9Table(obj, "pclntab", "epclntab"); err != nil {
- return 0, nil, nil, err
- }
- if symtab, err = loadPlan9Table(obj, "symtab", "esymtab"); err != nil {
- return 0, nil, nil, err
- }
- return textStart, symtab, pclntab, nil
- }
-
- return 0, nil, nil, fmt.Errorf("unrecognized binary format")
-}
-
-func findPESymbol(f *pe.File, name string) (*pe.Symbol, error) {
- for _, s := range f.Symbols {
- if s.Name != name {
- continue
- }
- if s.SectionNumber <= 0 {
- return nil, fmt.Errorf("symbol %s: invalid section number %d", name, s.SectionNumber)
- }
- if len(f.Sections) < int(s.SectionNumber) {
- return nil, fmt.Errorf("symbol %s: section number %d is larger than max %d", name, s.SectionNumber, len(f.Sections))
- }
- return s, nil
- }
- return nil, fmt.Errorf("no %s symbol found", name)
-}
-
-func loadPETable(f *pe.File, sname, ename string) ([]byte, error) {
- ssym, err := findPESymbol(f, sname)
- if err != nil {
- return nil, err
- }
- esym, err := findPESymbol(f, ename)
- if err != nil {
- return nil, err
- }
- if ssym.SectionNumber != esym.SectionNumber {
- return nil, fmt.Errorf("%s and %s symbols must be in the same section", sname, ename)
- }
- sect := f.Sections[ssym.SectionNumber-1]
- data, err := sect.Data()
- if err != nil {
- return nil, err
- }
- return data[ssym.Value:esym.Value], nil
-}
-
-func findPlan9Symbol(f *plan9obj.File, name string) (*plan9obj.Sym, error) {
- syms, err := f.Symbols()
- if err != nil {
- return nil, err
- }
- for _, s := range syms {
- if s.Name != name {
- continue
- }
- return &s, nil
- }
- return nil, fmt.Errorf("no %s symbol found", name)
-}
-
-func loadPlan9Table(f *plan9obj.File, sname, ename string) ([]byte, error) {
- ssym, err := findPlan9Symbol(f, sname)
- if err != nil {
- return nil, err
- }
- esym, err := findPlan9Symbol(f, ename)
- if err != nil {
- return nil, err
- }
- sect := f.Section("text")
- if sect == nil {
- return nil, err
- }
- data, err := sect.Data()
- if err != nil {
- return nil, err
- }
- textStart := f.LoadAddress + f.HdrSize
- return data[ssym.Value-textStart : esym.Value-textStart], nil
-}
diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go
index 932b5520f..7e8f85848 100644
--- a/src/cmd/api/goapi.go
+++ b/src/cmd/api/goapi.go
@@ -378,7 +378,51 @@ func (w *Walker) parseFile(dir, file string) (*ast.File, error) {
}
if w.context != nil && file == fmt.Sprintf("zruntime_defs_%s_%s.go", w.context.GOOS, w.context.GOARCH) {
// Just enough to keep the api checker happy.
- src := "package runtime; type maptype struct{}; type _type struct{}; type alg struct{}; type mspan struct{}; type m struct{}; type lock struct{}; type slicetype struct{};"
+ src := "package runtime; type (" +
+ " _defer struct{};" +
+ " _func struct{};" +
+ " _panic struct{};" +
+ " _select struct{}; " +
+ " _type struct{};" +
+ " alg struct{};" +
+ " chantype struct{};" +
+ " context struct{};" + // windows
+ " eface struct{};" +
+ " funcval struct{};" +
+ " g struct{};" +
+ " gobuf struct{};" +
+ " hchan struct{};" +
+ " iface struct{};" +
+ " interfacetype struct{};" +
+ " itab struct{};" +
+ " m struct{};" +
+ " maptype struct{};" +
+ " mcache struct{};" +
+ " mspan struct{};" +
+ " mutex struct{};" +
+ " note struct{};" +
+ " slicetype struct{};" +
+ " stkframe struct{};" +
+ " sudog struct{};" +
+ " waitq struct{};" +
+ " wincallbackcontext struct{};" +
+ " keventt struct{};" +
+ " timespec struct{};" +
+ " epollevent struct{};" +
+ "); " +
+ "const (" +
+ " cb_max = 2000;" +
+ " _CacheLineSize = 64;" +
+ " _Gidle = 1;" +
+ " _Grunnable = 2;" +
+ " _Grunning = 3;" +
+ " _Gsyscall = 4;" +
+ " _Gwaiting = 5;" +
+ " _Gdead = 6;" +
+ " _Genqueue = 7;" +
+ " _Gcopystack = 8;" +
+ " _NSIG = 32;" +
+ ")"
f, err = parser.ParseFile(fset, filename, src, 0)
if err != nil {
log.Fatalf("incorrect generated file: %s", err)
diff --git a/src/cmd/api/run.go b/src/cmd/api/run.go
index 896b2b4a1..c323deb60 100644
--- a/src/cmd/api/run.go
+++ b/src/cmd/api/run.go
@@ -98,11 +98,9 @@ func prepGoPath() string {
if err == nil {
username = u.Username
} else {
- // Only need to handle Unix here, as Windows's os/user uses
- // native syscall and should work fine without cgo.
username = os.Getenv("USER")
if username == "" {
- log.Fatalf("Error getting current user: %v", err)
+ username = "nobody"
}
}
diff --git a/src/cmd/cc/cc.h b/src/cmd/cc/cc.h
index c8aac1253..1dae5acd9 100644
--- a/src/cmd/cc/cc.h
+++ b/src/cmd/cc/cc.h
@@ -794,7 +794,7 @@ void xcom(Node*);
int32 exreg(Type*);
int32 align(int32, Type*, int, int32*);
int32 maxround(int32, int32);
-int hasdotdotdot(void);
+int hasdotdotdot(Type*);
void linkarchinit(void);
extern schar ewidth[];
diff --git a/src/cmd/cc/cc.y b/src/cmd/cc/cc.y
index 11ee444b7..8d7cb1472 100644
--- a/src/cmd/cc/cc.y
+++ b/src/cmd/cc/cc.y
@@ -1043,6 +1043,7 @@ complex:
}
| LSTRUCT sbody
{
+ diag(Z, "struct must have tag");
taggen++;
sprint(symb, "_%d_", taggen);
$$ = dotag(lookup(), TSTRUCT, autobn);
diff --git a/src/cmd/cc/dcl.c b/src/cmd/cc/dcl.c
index a7a942686..292717d68 100644
--- a/src/cmd/cc/dcl.c
+++ b/src/cmd/cc/dcl.c
@@ -697,7 +697,8 @@ argmark(Node *n, int pass)
{
Type *t;
- autoffset = align(0, thisfn->link, Aarg0, nil);
+ if(hasdotdotdot(thisfn->link))
+ autoffset = align(0, thisfn->link, Aarg0, nil);
stkoff = 0;
for(; n->left != Z; n = n->left) {
if(n->op != OFUNC || n->left->op != ONAME)
@@ -1401,6 +1402,10 @@ xdecl(int c, Type *t, Sym *s)
}
tmerge(t, s);
s->type = t;
+ if(c == CTYPEDEF && (typechlv[t->etype] || typefd[t->etype])) {
+ s->type = copytyp(t);
+ s->type->tag = s;
+ }
s->class = c;
s->block = 0;
s->offset = o;
@@ -1481,12 +1486,9 @@ edecl(int c, Type *t, Sym *s)
{
Type *t1;
- if(s == S) {
- if(!typesu[t->etype])
- diag(Z, "unnamed structure element must be struct/union");
- if(c != CXXX)
- diag(Z, "unnamed structure element cannot have class");
- } else
+ if(s == S)
+ diag(Z, "unnamed structure elements not supported");
+ else
if(c != CXXX)
diag(Z, "structure element cannot have class: %s", s->name);
t1 = t;
diff --git a/src/cmd/cc/godefs.c b/src/cmd/cc/godefs.c
index 3755a8fc0..d3ab52fde 100644
--- a/src/cmd/cc/godefs.c
+++ b/src/cmd/cc/godefs.c
@@ -154,7 +154,6 @@ static void
printtypename(Type *t)
{
Sym *s;
- Type *t1;
int w;
char *n;
@@ -188,60 +187,27 @@ printtypename(Type *t)
switch(t->etype) {
case TINT:
- Bprint(&outbuf, "int32");
- break;
case TUINT:
- Bprint(&outbuf, "uint32");
- break;
case TCHAR:
- Bprint(&outbuf, "int8");
- break;
case TUCHAR:
- Bprint(&outbuf, "uint8");
- break;
case TSHORT:
- Bprint(&outbuf, "int16");
- break;
case TUSHORT:
- Bprint(&outbuf, "uint16");
- break;
case TLONG:
- // The 32/64-bit ambiguous types (int,uint,uintptr)
- // are assigned a TLONG/TULONG to distinguish them
- // from always 32-bit types which get a TINT/TUINT.
- // (See int_x/uint_x in pkg/runtime/runtime.h.)
- // For LONG and VLONG types, we generate the
- // unqualified Go type when appropriate.
- // This makes it easier to write Go code that
- // modifies objects with autogenerated-from-C types.
- if(ewidth[TIND] == 4)
- Bprint(&outbuf, "int");
- else
- Bprint(&outbuf, "int32");
- break;
case TULONG:
- if(ewidth[TIND] == 4)
- Bprint(&outbuf, "uint");
- else
- Bprint(&outbuf, "uint32");
- break;
case TVLONG:
- if(ewidth[TIND] == 8)
- Bprint(&outbuf, "int");
- else
- Bprint(&outbuf, "int64");
- break;
case TUVLONG:
- if(ewidth[TIND] == 8)
- Bprint(&outbuf, "uint");
- else
- Bprint(&outbuf, "uint64");
- break;
case TFLOAT:
- Bprint(&outbuf, "float32");
- break;
case TDOUBLE:
- Bprint(&outbuf, "float64");
+ // All names used in the runtime code should be typedefs.
+ if(t->tag != nil) {
+ if(strcmp(t->tag->name, "intgo") == 0)
+ Bprint(&outbuf, "int");
+ else if(strcmp(t->tag->name, "uintgo") == 0)
+ Bprint(&outbuf, "uint");
+ else
+ Bprint(&outbuf, "%s", t->tag->name);
+ } else
+ Bprint(&outbuf, "C.%T", t);
break;
case TUNION:
case TSTRUCT:
@@ -251,27 +217,18 @@ printtypename(Type *t)
n = s->name;
else if(t->tag)
n = t->tag->name;
- if(strcmp(n, "String") == 0){
+ if(strcmp(n, "String") == 0)
Bprint(&outbuf, "string");
- } else if(strcmp(n, "Slice") == 0){
+ else if(strcmp(n, "Slice") == 0)
Bprint(&outbuf, "[]byte");
- } else
+ else if(strcmp(n, "Eface") == 0)
+ Bprint(&outbuf, "interface{}");
+ else
Bprint(&outbuf, "%U", n);
break;
case TFUNC:
- Bprint(&outbuf, "func(");
- for(t1 = t->down; t1 != T; t1 = t1->down) {
- if(t1->etype == TVOID)
- break;
- if(t1 != t->down)
- Bprint(&outbuf, ", ");
- printtypename(t1);
- }
- Bprint(&outbuf, ")");
- if(t->link && t->link->etype != TVOID) {
- Bprint(&outbuf, " ");
- printtypename(t->link);
- }
+ // There's no equivalent to a C function in the Go world.
+ Bprint(&outbuf, "unsafe.Pointer");
break;
case TDOT:
Bprint(&outbuf, "...interface{}");
@@ -360,9 +317,9 @@ godefvar(Sym *s)
switch(t->etype) {
case TENUM:
if(!typefd[t->etype])
- Bprint(&outbuf, "const %U = %lld\n", s->name, s->vconst);
+ Bprint(&outbuf, "const %s = %lld\n", s->name, s->vconst);
else
- Bprint(&outbuf, "const %U = %f\n;", s->name, s->fconst);
+ Bprint(&outbuf, "const %s = %f\n;", s->name, s->fconst);
break;
case TFUNC:
diff --git a/src/cmd/cc/pgen.c b/src/cmd/cc/pgen.c
index c2cf0e101..4b4684a52 100644
--- a/src/cmd/cc/pgen.c
+++ b/src/cmd/cc/pgen.c
@@ -56,24 +56,24 @@ makefuncdatasym(char *namefmt, int64 funcdatakind)
}
int
-hasdotdotdot(void)
+hasdotdotdot(Type *t)
{
- Type *t;
-
- for(t=thisfn->down; t!=T; t=t->down)
+ for(t=t->down; t!=T; t=t->down)
if(t->etype == TDOT)
return 1;
return 0;
}
vlong
-argsize(void)
+argsize(int doret)
{
Type *t;
int32 s;
//print("t=%T\n", thisfn);
- s = align(0, thisfn->link, Aarg0, nil);
+ s = 0;
+ if(hasdotdotdot(thisfn))
+ s = align(s, thisfn->link, Aarg0, nil);
for(t=thisfn->down; t!=T; t=t->down) {
switch(t->etype) {
case TVOID:
@@ -93,6 +93,14 @@ argsize(void)
s = (s+7) & ~7;
else
s = (s+3) & ~3;
+ if(doret && thisfn->link->etype != TVOID) {
+ s = align(s, thisfn->link, Aarg1, nil);
+ s = align(s, thisfn->link, Aarg2, nil);
+ if(thechar == '6')
+ s = (s+7) & ~7;
+ else
+ s = (s+3) & ~3;
+ }
return s;
}
@@ -123,13 +131,14 @@ codgen(Node *n, Node *nn)
nearln = nn->lineno;
p = gtext(n1->sym, stkoff);
+ p->from.sym->cfunc = 1;
sp = p;
/*
* generate funcdata symbol for this function.
* data is filled in at the end of codgen().
*/
- isvarargs = hasdotdotdot();
+ isvarargs = hasdotdotdot(thisfn);
gcargs = nil;
if(!isvarargs)
gcargs = makefuncdatasym("gcargs·%d", FUNCDATA_ArgsPointerMaps);
@@ -212,7 +221,7 @@ supgen(Node *n)
void
gen(Node *n)
{
- Node *l, nod;
+ Node *l, nod, nod1;
Prog *sp, *spc, *spb;
Case *cn;
long sbc, scc;
@@ -273,14 +282,26 @@ loop:
gbranch(ORETURN);
break;
}
+ if(typecmplx[n->type->etype] && !hasdotdotdot(thisfn)) {
+ regret(&nod, n, thisfn, 2);
+ sugen(l, &nod, n->type->width);
+ noretval(3);
+ gbranch(ORETURN);
+ break;
+ }
if(typecmplx[n->type->etype]) {
sugen(l, nodret, n->type->width);
noretval(3);
gbranch(ORETURN);
break;
}
- regret(&nod, n);
+ regret(&nod1, n, thisfn, 2);
+ nod = nod1;
+ if(nod.op != OREGISTER)
+ regalloc(&nod, n, Z);
cgen(l, &nod);
+ if(nod1.op != OREGISTER)
+ gmove(&nod, &nod1);
regfree(&nod);
if(typefd[n->type->etype])
noretval(1);
@@ -729,9 +750,11 @@ dumpgcargs(Type *fn, Sym *sym)
symoffset = 0;
gextern(sym, nodconst(1), symoffset, 4);
symoffset += 4;
- argbytes = (argsize() + ewidth[TIND] - 1);
+ argbytes = (argsize(1) + ewidth[TIND] - 1);
bv = bvalloc((argbytes / ewidth[TIND]) * BitsPerPointer);
- argoffset = align(0, fn->link, Aarg0, nil);
+ argoffset = 0;
+ if(hasdotdotdot(thisfn))
+ argoffset = align(0, fn->link, Aarg0, nil);
if(argoffset > 0) {
// The C calling convention returns structs by copying them to a
// location pointed to by a hidden first argument. This first
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index 841c84833..d77d56c22 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -229,7 +229,8 @@ func (p *Package) guessKinds(f *File) []*Name {
// Determine kinds for names we already know about,
// like #defines or 'struct foo', before bothering with gcc.
var names, needType []*Name
- for _, n := range f.Name {
+ for _, key := range nameKeys(f.Name) {
+ n := f.Name[key]
// If we've already found this name as a #define
// and we can translate it as a constant value, do so.
if n.Define != "" {
@@ -331,6 +332,7 @@ func (p *Package) guessKinds(f *File) []*Name {
const (
notType = 1 << iota
notConst
+ notDeclared
)
for _, line := range strings.Split(stderr, "\n") {
if !strings.Contains(line, ": error:") {
@@ -365,7 +367,7 @@ func (p *Package) guessKinds(f *File) []*Name {
completed = true
case "not-declared":
- error_(token.NoPos, "%s", strings.TrimSpace(line[c2+1:]))
+ sniff[i] |= notDeclared
case "not-type":
sniff[i] |= notType
case "not-const":
@@ -374,12 +376,12 @@ func (p *Package) guessKinds(f *File) []*Name {
}
if !completed {
- fatalf("%s did not produce error at completed:1\non input:\n%s", p.gccBaseCmd()[0], b.Bytes())
+ fatalf("%s did not produce error at completed:1\non input:\n%s\nfull error output:\n%s", p.gccBaseCmd()[0], b.Bytes(), stderr)
}
for i, n := range names {
switch sniff[i] {
- case 0:
+ default:
error_(token.NoPos, "could not determine kind of name for C.%s", fixGo(n.Go))
case notType:
n.Kind = "const"
@@ -390,6 +392,14 @@ func (p *Package) guessKinds(f *File) []*Name {
}
}
if nerrors > 0 {
+ // Check if compiling the preamble by itself causes any errors,
+ // because the messages we've printed out so far aren't helpful
+ // to users debugging preamble mistakes. See issue 8442.
+ preambleErrors := p.gccErrors([]byte(f.Preamble))
+ if len(preambleErrors) > 0 {
+ error_(token.NoPos, "\n%s errors for preamble:\n%s", p.gccBaseCmd()[0], preambleErrors)
+ }
+
fatalf("unresolved names")
}
@@ -649,7 +659,13 @@ func (p *Package) rewriteRef(f *File) {
f.Name[fpName] = name
}
r.Name = name
- expr = ast.NewIdent(name.Mangle)
+ // Rewrite into call to _Cgo_ptr to prevent assignments. The _Cgo_ptr
+ // function is defined in out.go and simply returns its argument. See
+ // issue 7757.
+ expr = &ast.CallExpr{
+ Fun: &ast.Ident{NamePos: (*r.Expr).Pos(), Name: "_Cgo_ptr"},
+ Args: []ast.Expr{ast.NewIdent(name.Mangle)},
+ }
} else if r.Name.Kind == "type" {
// Okay - might be new(T)
expr = r.Name.Type.Go
@@ -1068,12 +1084,6 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
return t
}
- // clang won't generate DW_AT_byte_size for pointer types,
- // so we have to fix it here.
- if dt, ok := base(dtype).(*dwarf.PtrType); ok && dt.ByteSize == -1 {
- dt.ByteSize = c.ptrSize
- }
-
t := new(Type)
t.Size = dtype.Size() // note: wrong for array of pointers, corrected below
t.Align = -1
@@ -1097,12 +1107,20 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
t.Go = c.Opaque(t.Size)
break
}
+ count := dt.Count
+ if count == -1 {
+ // Indicates flexible array member, which Go doesn't support.
+ // Translate to zero-length array instead.
+ count = 0
+ }
sub := c.Type(dt.Type, pos)
t.Align = sub.Align
t.Go = &ast.ArrayType{
- Len: c.intExpr(dt.Count),
+ Len: c.intExpr(count),
Elt: sub.Go,
}
+ // Recalculate t.Size now that we know sub.Size.
+ t.Size = count * sub.Size
t.C.Set("__typeof__(%s[%d])", sub.C, dt.Count)
case *dwarf.BoolType:
@@ -1203,6 +1221,11 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
}
case *dwarf.PtrType:
+ // Clang doesn't emit DW_AT_byte_size for pointer types.
+ if t.Size != c.ptrSize && t.Size != -1 {
+ fatalf("%s: unexpected: %d-byte pointer type - %s", lineno(pos), t.Size, dtype)
+ }
+ t.Size = c.ptrSize
t.Align = c.ptrSize
if _, ok := base(dt.Type).(*dwarf.VoidType); ok {
@@ -1374,34 +1397,24 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
}
}
- if t.Size <= 0 {
- // Clang does not record the size of a pointer in its DWARF entry,
- // so if dtype is an array, the call to dtype.Size at the top of the function
- // computed the size as the array length * 0 = 0.
- // The type switch called Type (this function) recursively on the pointer
- // entry, and the code near the top of the function updated the size to
- // be correct, so calling dtype.Size again will produce the correct value.
- t.Size = dtype.Size()
- if t.Size < 0 {
- // Unsized types are [0]byte, unless they're typedefs of other types
- // or structs with tags.
- // if so, use the name we've already defined.
- t.Size = 0
- switch dt := dtype.(type) {
- case *dwarf.TypedefType:
- // ok
- case *dwarf.StructType:
- if dt.StructName != "" {
- break
- }
- t.Go = c.Opaque(0)
- default:
- t.Go = c.Opaque(0)
- }
- if t.C.Empty() {
- t.C.Set("void")
+ if t.Size < 0 {
+ // Unsized types are [0]byte, unless they're typedefs of other types
+ // or structs with tags.
+ // if so, use the name we've already defined.
+ t.Size = 0
+ switch dt := dtype.(type) {
+ case *dwarf.TypedefType:
+ // ok
+ case *dwarf.StructType:
+ if dt.StructName != "" {
+ break
}
- return t
+ t.Go = c.Opaque(0)
+ default:
+ t.Go = c.Opaque(0)
+ }
+ if t.C.Empty() {
+ t.C.Set("void")
}
}
@@ -1533,6 +1546,9 @@ func (c *typeConv) pad(fld []*ast.Field, size int64) []*ast.Field {
// Struct conversion: return Go and (6g) C syntax for type.
func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.StructType, csyntax string, align int64) {
+ // Minimum alignment for a struct is 1 byte.
+ align = 1
+
var buf bytes.Buffer
buf.WriteString("struct {")
fld := make([]*ast.Field, 0, 2*len(dt.Field)+1) // enough for padding around every field
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index 1ef78b757..6586531ad 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -58,16 +58,14 @@ func (p *Package) writeDefs() {
fmt.Fprintf(fgo2, "// Created by cgo - DO NOT EDIT\n\n")
fmt.Fprintf(fgo2, "package %s\n\n", p.PackageName)
fmt.Fprintf(fgo2, "import \"unsafe\"\n\n")
- if *importSyscall {
- fmt.Fprintf(fgo2, "import \"syscall\"\n\n")
- }
if !*gccgo && *importRuntimeCgo {
fmt.Fprintf(fgo2, "import _ \"runtime/cgo\"\n\n")
}
- fmt.Fprintf(fgo2, "type _ unsafe.Pointer\n\n")
if *importSyscall {
- fmt.Fprintf(fgo2, "func _Cerrno(dst *error, x int32) { *dst = syscall.Errno(x) }\n")
+ fmt.Fprintf(fgo2, "import \"syscall\"\n\n")
+ fmt.Fprintf(fgo2, "var _ syscall.Errno\n")
}
+ fmt.Fprintf(fgo2, "func _Cgo_ptr(ptr unsafe.Pointer) unsafe.Pointer { return ptr }\n\n")
typedefNames := make([]string, 0, len(typedef))
for name := range typedef {
@@ -87,9 +85,10 @@ func (p *Package) writeDefs() {
}
if *gccgo {
- fmt.Fprintf(fc, p.cPrologGccgo())
+ fmt.Fprint(fc, p.cPrologGccgo())
} else {
- fmt.Fprintf(fc, cProlog)
+ fmt.Fprint(fc, cProlog)
+ fmt.Fprint(fgo2, goProlog)
}
gccgoSymbolPrefix := p.gccgoSymbolPrefix()
@@ -296,10 +295,6 @@ func (p *Package) structType(n *Name) (string, int64) {
fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
off += pad
}
- if n.AddError {
- fmt.Fprint(&buf, "\t\tint e[2*sizeof(void *)/sizeof(int)]; /* error */\n")
- off += 2 * p.PtrSize
- }
if off == 0 {
fmt.Fprintf(&buf, "\t\tchar unused;\n") // avoid empty struct
}
@@ -334,19 +329,18 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
}
// Builtins defined in the C prolog.
- inProlog := name == "CString" || name == "GoString" || name == "GoStringN" || name == "GoBytes" || name == "_CMalloc"
+ inProlog := builtinDefs[name] != ""
+ cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle)
+ paramnames := []string(nil)
+ for i, param := range d.Type.Params.List {
+ paramName := fmt.Sprintf("p%d", i)
+ param.Names = []*ast.Ident{ast.NewIdent(paramName)}
+ paramnames = append(paramnames, paramName)
+ }
if *gccgo {
// Gccgo style hooks.
fmt.Fprint(fgo2, "\n")
- cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle)
- paramnames := []string(nil)
- for i, param := range d.Type.Params.List {
- paramName := fmt.Sprintf("p%d", i)
- param.Names = []*ast.Ident{ast.NewIdent(paramName)}
- paramnames = append(paramnames, paramName)
- }
-
conf.Fprint(fgo2, fset, d)
fmt.Fprint(fgo2, " {\n")
if !inProlog {
@@ -383,7 +377,7 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
fmt.Fprint(fgo2, "}\n")
// declare the C function.
- fmt.Fprintf(fgo2, "//extern _cgo%s%s\n", cPrefix, n.Mangle)
+ fmt.Fprintf(fgo2, "//extern %s\n", cname)
d.Name = ast.NewIdent(cname)
if n.AddError {
l := d.Type.Results.List
@@ -394,61 +388,49 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
return
}
- conf.Fprint(fgo2, fset, d)
- fmt.Fprint(fgo2, "\n")
if inProlog {
+ fmt.Fprint(fgo2, builtinDefs[name])
return
}
- var argSize int64
- _, argSize = p.structType(n)
-
// C wrapper calls into gcc, passing a pointer to the argument frame.
- fmt.Fprintf(fc, "#pragma cgo_import_static _cgo%s%s\n", cPrefix, n.Mangle)
- fmt.Fprintf(fc, "void _cgo%s%s(void*);\n", cPrefix, n.Mangle)
- fmt.Fprintf(fc, "\n")
- fmt.Fprintf(fc, "void\n")
- if argSize == 0 {
- argSize++
+ fmt.Fprintf(fc, "#pragma cgo_import_static %s\n", cname)
+ fmt.Fprintf(fc, "void %s(void*);\n", cname)
+ fmt.Fprintf(fc, "void *·%s = %s;\n", cname, cname)
+
+ nret := 0
+ if !void {
+ d.Type.Results.List[0].Names = []*ast.Ident{ast.NewIdent("r1")}
+ nret = 1
}
- // TODO(rsc): The struct here should declare pointers only where
- // there are pointers in the actual argument frame.
- // This is a workaround for golang.org/issue/6397.
- fmt.Fprintf(fc, "·%s(struct{", n.Mangle)
- if n := argSize / p.PtrSize; n > 0 {
- fmt.Fprintf(fc, "void *y[%d];", n)
+ if n.AddError {
+ d.Type.Results.List[nret].Names = []*ast.Ident{ast.NewIdent("r2")}
}
- if n := argSize % p.PtrSize; n > 0 {
- fmt.Fprintf(fc, "uint8 x[%d];", n)
+
+ fmt.Fprint(fgo2, "\n")
+ fmt.Fprintf(fgo2, "var %s unsafe.Pointer\n", cname)
+ conf.Fprint(fgo2, fset, d)
+ fmt.Fprint(fgo2, " {\n")
+
+ // NOTE: Using uintptr to hide from escape analysis.
+ arg := "0"
+ if len(paramnames) > 0 {
+ arg = "uintptr(unsafe.Pointer(&p0))"
+ } else if !void {
+ arg = "uintptr(unsafe.Pointer(&r1))"
}
- fmt.Fprintf(fc, "}p)\n")
- fmt.Fprintf(fc, "{\n")
- fmt.Fprintf(fc, "\truntime·cgocall(_cgo%s%s, &p);\n", cPrefix, n.Mangle)
+
+ prefix := ""
if n.AddError {
- // gcc leaves errno in first word of interface at end of p.
- // check whether it is zero; if so, turn interface into nil.
- // if not, turn interface into errno.
- // Go init function initializes ·_Cerrno with an os.Errno
- // for us to copy.
- fmt.Fprintln(fc, ` {
- int32 e;
- void **v;
- v = (void**)(&p+1) - 2; /* v = final two void* of p */
- e = *(int32*)v;
- v[0] = (void*)0xdeadbeef;
- v[1] = (void*)0xdeadbeef;
- if(e == 0) {
- /* nil interface */
- v[0] = 0;
- v[1] = 0;
- } else {
- ·_Cerrno(v, e); /* fill in v as error for errno e */
- }
- }`)
+ prefix = "errno := "
}
- fmt.Fprintf(fc, "}\n")
- fmt.Fprintf(fc, "\n")
+ fmt.Fprintf(fgo2, "\t%s_cgo_runtime_cgocall_errno(%s, %s)\n", prefix, cname, arg)
+ if n.AddError {
+ fmt.Fprintf(fgo2, "\tif errno != 0 { r2 = syscall.Errno(errno) }\n")
+ }
+ fmt.Fprintf(fgo2, "\treturn\n")
+ fmt.Fprintf(fgo2, "}\n")
}
// writeOutput creates stubs for a specific source file to be compiled by 6g
@@ -521,7 +503,11 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
// Gcc wrapper unpacks the C argument struct
// and calls the actual C function.
- fmt.Fprintf(fgcc, "void\n")
+ if n.AddError {
+ fmt.Fprintf(fgcc, "int\n")
+ } else {
+ fmt.Fprintf(fgcc, "void\n")
+ }
fmt.Fprintf(fgcc, "_cgo%s%s(void *v)\n", cPrefix, n.Mangle)
fmt.Fprintf(fgcc, "{\n")
if n.AddError {
@@ -557,7 +543,7 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
}
fmt.Fprintf(fgcc, ");\n")
if n.AddError {
- fmt.Fprintf(fgcc, "\t*(int*)(a->e) = errno;\n")
+ fmt.Fprintf(fgcc, "\treturn errno;\n")
}
fmt.Fprintf(fgcc, "}\n")
fmt.Fprintf(fgcc, "\n")
@@ -1166,46 +1152,74 @@ const cProlog = `
#include "runtime.h"
#include "cgocall.h"
+static void *cgocall_errno = runtime·cgocall_errno;
+void *·_cgo_runtime_cgocall_errno = &cgocall_errno;
+
+static void *runtime_gostring = runtime·gostring;
+void *·_cgo_runtime_gostring = &runtime_gostring;
+
+static void *runtime_gostringn = runtime·gostringn;
+void *·_cgo_runtime_gostringn = &runtime_gostringn;
+
+static void *runtime_gobytes = runtime·gobytes;
+void *·_cgo_runtime_gobytes = &runtime_gobytes;
+
+static void *runtime_cmalloc = runtime·cmalloc;
+void *·_cgo_runtime_cmalloc = &runtime_cmalloc;
+
void ·_Cerrno(void*, int32);
+`
-void
-·_Cfunc_GoString(int8 *p, String s)
-{
- s = runtime·gostring((byte*)p);
- FLUSH(&s);
+const goProlog = `
+var _cgo_runtime_cgocall_errno func(unsafe.Pointer, uintptr) int32
+var _cgo_runtime_cmalloc func(uintptr) unsafe.Pointer
+`
+
+const goStringDef = `
+var _cgo_runtime_gostring func(*_Ctype_char) string
+func _Cfunc_GoString(p *_Ctype_char) string {
+ return _cgo_runtime_gostring(p)
}
+`
-void
-·_Cfunc_GoStringN(int8 *p, int32 l, String s)
-{
- s = runtime·gostringn((byte*)p, l);
- FLUSH(&s);
+const goStringNDef = `
+var _cgo_runtime_gostringn func(*_Ctype_char, int) string
+func _Cfunc_GoStringN(p *_Ctype_char, l _Ctype_int) string {
+ return _cgo_runtime_gostringn(p, int(l))
}
+`
-void
-·_Cfunc_GoBytes(int8 *p, int32 l, Slice s)
-{
- s = runtime·gobytes((byte*)p, l);
- FLUSH(&s);
+const goBytesDef = `
+var _cgo_runtime_gobytes func(unsafe.Pointer, int) []byte
+func _Cfunc_GoBytes(p unsafe.Pointer, l _Ctype_int) []byte {
+ return _cgo_runtime_gobytes(p, int(l))
}
+`
-void
-·_Cfunc_CString(String s, int8 *p)
-{
- p = runtime·cmalloc(s.len+1);
- runtime·memmove((byte*)p, s.str, s.len);
- p[s.len] = 0;
- FLUSH(&p);
+const cStringDef = `
+func _Cfunc_CString(s string) *_Ctype_char {
+ p := _cgo_runtime_cmalloc(uintptr(len(s)+1))
+ pp := (*[1<<30]byte)(p)
+ copy(pp[:], s)
+ pp[len(s)] = 0
+ return (*_Ctype_char)(p)
}
+`
-void
-·_Cfunc__CMalloc(uintptr n, int8 *p)
-{
- p = runtime·cmalloc(n);
- FLUSH(&p);
+const cMallocDef = `
+func _Cfunc__CMalloc(n _Ctype_size_t) unsafe.Pointer {
+ return _cgo_runtime_cmalloc(uintptr(n))
}
`
+var builtinDefs = map[string]string{
+ "GoString": goStringDef,
+ "GoStringN": goStringNDef,
+ "GoBytes": goBytesDef,
+ "CString": cStringDef,
+ "_CMalloc": cMallocDef,
+}
+
func (p *Package) cPrologGccgo() string {
return strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1)
}
diff --git a/src/cmd/dist/a.h b/src/cmd/dist/a.h
index 6222e5060..288063b94 100644
--- a/src/cmd/dist/a.h
+++ b/src/cmd/dist/a.h
@@ -108,9 +108,6 @@ void mkzexperiment(char*, char*);
// buildgo.c
void mkzdefaultcc(char*, char*);
-// goc2c.c
-void goc2c(char*, char*);
-
// main.c
extern int vflag;
extern int sflag;
@@ -129,6 +126,7 @@ bool isfile(char *p);
char* lastelem(char*);
Time mtime(char*);
void readfile(Buf*, char*);
+void copyfile(char*, char*, int);
void run(Buf *b, char *dir, int mode, char *cmd, ...);
void runv(Buf *b, char *dir, int mode, Vec *argv);
void bgrunv(char *dir, int mode, Vec *argv);
diff --git a/src/cmd/dist/buf.c b/src/cmd/dist/buf.c
index 45fb1954d..2ddc6be75 100644
--- a/src/cmd/dist/buf.c
+++ b/src/cmd/dist/buf.c
@@ -202,7 +202,7 @@ vadd(Vec *v, char *p)
}
// vaddn adds a string consisting of the n bytes at p to the vector.
-void
+static void
vaddn(Vec *v, char *p, int n)
{
char *q;
diff --git a/src/cmd/dist/build.c b/src/cmd/dist/build.c
index 1feeccf41..6fab14a11 100644
--- a/src/cmd/dist/build.c
+++ b/src/cmd/dist/build.c
@@ -35,7 +35,6 @@ bool rebuildall;
bool defaultclang;
static bool shouldbuild(char*, char*);
-static void copy(char*, char*, int);
static void dopack(char*, char*, char**, int);
static char *findgoversion(void);
@@ -628,7 +627,6 @@ char *depsuffix[] = {
".h",
".s",
".go",
- ".goc",
};
// gentab records how to generate some trivial files.
@@ -661,7 +659,7 @@ install(char *dir)
{
char *name, *p, *elem, *prefix, *exe;
bool islib, ispkg, isgo, stale, ispackcmd;
- Buf b, b1, path;
+ Buf b, b1, path, final_path, final_name;
Vec compile, files, link, go, missing, clean, lib, extra;
Time ttarg, t;
int i, j, k, n, doclean, targ;
@@ -676,6 +674,8 @@ install(char *dir)
binit(&b);
binit(&b1);
binit(&path);
+ binit(&final_path);
+ binit(&final_name);
vinit(&compile);
vinit(&files);
vinit(&link);
@@ -688,11 +688,12 @@ install(char *dir)
// path = full path to dir.
bpathf(&path, "%s/src/%s", goroot, dir);
+ bpathf(&final_path, "%s/src/%s", goroot_final, dir);
name = lastelem(dir);
// For misc/prof, copy into the tool directory and we're done.
if(hasprefix(dir, "misc/")) {
- copy(bpathf(&b, "%s/%s", tooldir, name),
+ copyfile(bpathf(&b, "%s/%s", tooldir, name),
bpathf(&b1, "%s/misc/%s", goroot, name), 1);
goto out;
}
@@ -904,17 +905,19 @@ install(char *dir)
// For package runtime, copy some files into the work space.
if(streq(dir, "pkg/runtime")) {
- copy(bpathf(&b, "%s/arch_GOARCH.h", workdir),
+ copyfile(bpathf(&b, "%s/arch_GOARCH.h", workdir),
bpathf(&b1, "%s/arch_%s.h", bstr(&path), goarch), 0);
- copy(bpathf(&b, "%s/defs_GOOS_GOARCH.h", workdir),
+ copyfile(bpathf(&b, "%s/defs_GOOS_GOARCH.h", workdir),
bpathf(&b1, "%s/defs_%s_%s.h", bstr(&path), goos, goarch), 0);
p = bpathf(&b1, "%s/signal_%s_%s.h", bstr(&path), goos, goarch);
if(isfile(p))
- copy(bpathf(&b, "%s/signal_GOOS_GOARCH.h", workdir), p, 0);
- copy(bpathf(&b, "%s/os_GOOS.h", workdir),
+ copyfile(bpathf(&b, "%s/signal_GOOS_GOARCH.h", workdir), p, 0);
+ copyfile(bpathf(&b, "%s/os_GOOS.h", workdir),
bpathf(&b1, "%s/os_%s.h", bstr(&path), goos), 0);
- copy(bpathf(&b, "%s/signals_GOOS.h", workdir),
+ copyfile(bpathf(&b, "%s/signals_GOOS.h", workdir),
bpathf(&b1, "%s/signals_%s.h", bstr(&path), goos), 0);
+ copyfile(bpathf(&b, "%s/pkg/%s_%s/textflag.h", goroot, goos, goarch),
+ bpathf(&b1, "%s/src/cmd/ld/textflag.h", goroot), 0);
}
// Generate any missing files; regenerate existing ones.
@@ -948,26 +951,10 @@ install(char *dir)
// The last batch was required for the generators.
// This one is generated.
if(streq(dir, "pkg/runtime")) {
- copy(bpathf(&b, "%s/zasm_GOOS_GOARCH.h", workdir),
+ copyfile(bpathf(&b, "%s/zasm_GOOS_GOARCH.h", workdir),
bpathf(&b1, "%s/zasm_%s_%s.h", bstr(&path), goos, goarch), 0);
}
- // Generate .c files from .goc files.
- if(streq(dir, "pkg/runtime")) {
- for(i=0; i<files.len; i++) {
- p = files.p[i];
- if(!hassuffix(p, ".goc"))
- continue;
- // b = path/zp but with _goos_goarch.c instead of .goc
- bprintf(&b, "%s%sz%s", bstr(&path), slash, lastelem(p));
- b.len -= 4;
- bwritef(&b, "_%s_%s.c", goos, goarch);
- goc2c(p, bstr(&b));
- vadd(&files, bstr(&b));
- }
- vuniq(&files);
- }
-
if((!streq(goos, gohostos) || !streq(goarch, gohostarch)) && isgo) {
// We've generated the right files; the go command can do the build.
if(vflag > 1)
@@ -1138,9 +1125,9 @@ nobuild:
// In package runtime, we install runtime.h and cgocall.h too,
// for use by cgo compilation.
if(streq(dir, "pkg/runtime")) {
- copy(bpathf(&b, "%s/pkg/%s_%s/cgocall.h", goroot, goos, goarch),
+ copyfile(bpathf(&b, "%s/pkg/%s_%s/cgocall.h", goroot, goos, goarch),
bpathf(&b1, "%s/src/pkg/runtime/cgocall.h", goroot), 0);
- copy(bpathf(&b, "%s/pkg/%s_%s/runtime.h", goroot, goos, goarch),
+ copyfile(bpathf(&b, "%s/pkg/%s_%s/runtime.h", goroot, goos, goarch),
bpathf(&b1, "%s/src/pkg/runtime/runtime.h", goroot), 0);
}
@@ -1277,8 +1264,8 @@ out:
}
// copy copies the file src to dst, via memory (so only good for small files).
-static void
-copy(char *dst, char *src, int exec)
+void
+copyfile(char *dst, char *src, int exec)
{
Buf b;
diff --git a/src/cmd/dist/buildruntime.c b/src/cmd/dist/buildruntime.c
index 9b40a5968..7af38456d 100644
--- a/src/cmd/dist/buildruntime.c
+++ b/src/cmd/dist/buildruntime.c
@@ -112,7 +112,7 @@ mkzgoos(char *dir, char *file)
bwritestr(&out, "// auto generated by go tool dist\n\n");
- if (streq(goos, "linux")) {
+ if(streq(goos, "linux")) {
bwritestr(&out, "// +build !android\n\n");
}
@@ -169,11 +169,12 @@ mkzasm(char *dir, char *file)
{
int i, n;
char *aggr, *p;
- Buf in, b, out, exp;
+ Buf in, b, b1, out, exp;
Vec argv, lines, fields;
binit(&in);
binit(&b);
+ binit(&b1);
binit(&out);
binit(&exp);
vinit(&argv);
@@ -181,6 +182,10 @@ mkzasm(char *dir, char *file)
vinit(&fields);
bwritestr(&out, "// auto generated by go tool dist\n\n");
+ if(streq(goos, "linux")) {
+ bwritestr(&out, "// +build !android\n\n");
+ }
+
for(i=0; i<nelem(zasmhdr); i++) {
if(hasprefix(goarch, zasmhdr[i].goarch) && hasprefix(goos, zasmhdr[i].goos)) {
bwritestr(&out, zasmhdr[i].hdr);
@@ -190,6 +195,9 @@ mkzasm(char *dir, char *file)
fatal("unknown $GOOS/$GOARCH in mkzasm");
ok:
+ copyfile(bpathf(&b, "%s/pkg/%s_%s/textflag.h", goroot, goos, goarch),
+ bpathf(&b1, "%s/src/cmd/ld/textflag.h", goroot), 0);
+
// Run 6c -D GOOS_goos -D GOARCH_goarch -I workdir -a -n -o workdir/proc.acid proc.c
// to get acid [sic] output. Run once without the -a -o workdir/proc.acid in order to
// report compilation failures (the -o redirects all messages, unfortunately).
@@ -201,6 +209,8 @@ ok:
vadd(&argv, bprintf(&b, "GOARCH_%s", goarch));
vadd(&argv, "-I");
vadd(&argv, bprintf(&b, "%s", workdir));
+ vadd(&argv, "-I");
+ vadd(&argv, bprintf(&b, "%s/pkg/%s_%s", goroot, goos, goarch));
vadd(&argv, "-n");
vadd(&argv, "-a");
vadd(&argv, "-o");
@@ -241,6 +251,8 @@ ok:
aggr = "seh";
else if(streq(fields.p[1], "Alg"))
aggr = "alg";
+ else if(streq(fields.p[1], "Panic"))
+ aggr = "panic";
}
if(hasprefix(lines.p[i], "}"))
aggr = nil;
@@ -273,6 +285,7 @@ ok:
bfree(&in);
bfree(&b);
+ bfree(&b1);
bfree(&out);
bfree(&exp);
vfree(&argv);
@@ -294,6 +307,10 @@ mkzsys(char *dir, char *file)
binit(&out);
bwritestr(&out, "// auto generated by go tool dist\n\n");
+ if(streq(goos, "linux")) {
+ bwritestr(&out, "// +build !android\n\n");
+ }
+
if(streq(goos, "windows")) {
bwritef(&out,
"// runtime·callbackasm is called by external code to\n"
@@ -346,13 +363,24 @@ mkzruntimedefs(char *dir, char *file)
vinit(&seen);
bwritestr(&out, "// auto generated by go tool dist\n"
- "\n"
+ "\n");
+
+ if(streq(goos, "linux")) {
+ bwritestr(&out, "// +build !android\n\n");
+ }
+
+ bwritestr(&out,
"package runtime\n"
"import \"unsafe\"\n"
"var _ unsafe.Pointer\n"
"\n"
);
+ // Do not emit definitions for these.
+ vadd(&seen, "true");
+ vadd(&seen, "false");
+ vadd(&seen, "raceenabled");
+ vadd(&seen, "allgs");
// Run 6c -D GOOS_goos -D GOARCH_goarch -I workdir -q -n -o workdir/runtimedefs
// on each of the runtimedefs C files.
@@ -363,6 +391,8 @@ mkzruntimedefs(char *dir, char *file)
vadd(&argv, bprintf(&b, "GOARCH_%s", goarch));
vadd(&argv, "-I");
vadd(&argv, bprintf(&b, "%s", workdir));
+ vadd(&argv, "-I");
+ vadd(&argv, bprintf(&b, "%s/pkg/%s_%s", goroot, goos, goarch));
vadd(&argv, "-q");
vadd(&argv, "-n");
vadd(&argv, "-o");
@@ -382,15 +412,15 @@ mkzruntimedefs(char *dir, char *file)
splitlines(&lines, bstr(&in));
for(i=0; i<lines.len; i++) {
p = lines.p[i];
- // Drop comment, func, and const lines.
- if(hasprefix(p, "//") || hasprefix(p, "const") || hasprefix(p, "func"))
+ // Drop comment and func lines.
+ if(hasprefix(p, "//") || hasprefix(p, "func"))
continue;
// Note beginning of type or var decl, which can be multiline.
// Remove duplicates. The linear check of seen here makes the
// whole processing quadratic in aggregate, but there are only
// about 100 declarations, so this is okay (and simple).
- if(hasprefix(p, "type ") || hasprefix(p, "var ")) {
+ if(hasprefix(p, "type ") || hasprefix(p, "var ") || hasprefix(p, "const ")) {
splitfields(&fields, p);
if(fields.len < 2)
continue;
@@ -401,6 +431,17 @@ mkzruntimedefs(char *dir, char *file)
}
vadd(&seen, fields.p[1]);
}
+
+ // Const lines are printed in original case (usually upper). Add a leading _ as needed.
+ if(hasprefix(p, "const ")) {
+ if('A' <= p[6] && p[6] <= 'Z')
+ bwritestr(&out, "const _");
+ else
+ bwritestr(&out, "const ");
+ bwritestr(&out, p+6);
+ continue;
+ }
+
if(skip) {
if(hasprefix(p, "}"))
skip = 0;
@@ -409,6 +450,11 @@ mkzruntimedefs(char *dir, char *file)
bwritestr(&out, p);
}
+
+ // Some windows specific const.
+ if(streq(goos, "windows")) {
+ bwritestr(&out, bprintf(&b, "const cb_max = %d\n", MAXWINCB));
+ }
writefile(&out, file, 0);
diff --git a/src/cmd/dist/goc2c.c b/src/cmd/dist/goc2c.c
deleted file mode 100644
index 72cbc1be6..000000000
--- a/src/cmd/dist/goc2c.c
+++ /dev/null
@@ -1,833 +0,0 @@
-// Copyright 2009 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 "a.h"
-
-/*
- * Translate a .goc file into a .c file. A .goc file is a combination
- * of a limited form of Go with C.
- */
-
-/*
- package PACKAGENAME
- {# line}
- func NAME([NAME TYPE { , NAME TYPE }]) [(NAME TYPE { , NAME TYPE })] \{
- C code with proper brace nesting
- \}
-*/
-
-/*
- * We generate C code which implements the function such that it can
- * be called from Go and executes the C code.
- */
-
-static char *input;
-static Buf *output;
-#define EOF -1
-
-enum
-{
- use64bitint = 1,
-};
-
-static int
-xgetchar(void)
-{
- int c;
-
- c = *input;
- if(c == 0)
- return EOF;
- input++;
- return c;
-}
-
-static void
-xungetc(void)
-{
- input--;
-}
-
-static void
-xputchar(char c)
-{
- bwrite(output, &c, 1);
-}
-
-static int
-xisspace(int c)
-{
- return c == ' ' || c == '\t' || c == '\r' || c == '\n';
-}
-
-/* Whether we're emitting for gcc */
-static int gcc;
-
-/* File and line number */
-static const char *file;
-static unsigned int lineno;
-
-/* List of names and types. */
-struct params {
- struct params *next;
- char *name;
- char *type;
-};
-
-/* index into type_table */
-enum {
- Bool,
- Float,
- Int,
- Uint,
- Uintptr,
- String,
- Slice,
- Eface,
- Complex128,
- Float32,
- Float64,
-};
-
-static struct {
- char *name;
- int size;
- int rnd; // alignment
-} type_table[] = {
- /*
- * variable sized first, for easy replacement.
- * order matches enum above.
- * default is 32-bit architecture sizes.
- * spelling as in package runtime, so intgo/uintgo not int/uint.
- */
- {"bool", 1},
- {"float", 4},
- {"intgo", 4},
- {"uintgo", 4},
- {"uintptr", 4},
- {"String", 8},
- {"Slice", 12},
- {"Eface", 8},
- {"Complex128", 16},
-
- /* fixed size */
- {"float32", 4},
- {"float64", 8},
- {"byte", 1},
- {"int8", 1},
- {"uint8", 1},
- {"int16", 2},
- {"uint16", 2},
- {"int32", 4},
- {"rune", 4},
- {"uint32", 4},
- {"int64", 8},
- {"uint64", 8},
-
- {nil, 0},
-};
-
-/* Fixed structure alignment (non-gcc only) */
-int structround = 4;
-
-/* Unexpected EOF. */
-static void
-bad_eof(void)
-{
- fatal("%s:%d: unexpected EOF\n", file, lineno);
-}
-
-/* Free a list of parameters. */
-static void
-free_params(struct params *p)
-{
- while (p != nil) {
- struct params *next;
-
- next = p->next;
- xfree(p->name);
- xfree(p->type);
- xfree(p);
- p = next;
- }
-}
-
-/* Read a character, tracking lineno. */
-static int
-getchar_update_lineno(void)
-{
- int c;
-
- c = xgetchar();
- if (c == '\n')
- ++lineno;
- return c;
-}
-
-/* Read a character, giving an error on EOF, tracking lineno. */
-static int
-getchar_no_eof(void)
-{
- int c;
-
- c = getchar_update_lineno();
- if (c == EOF)
- bad_eof();
- return c;
-}
-
-/* Read a character, skipping comments. */
-static int
-getchar_skipping_comments(void)
-{
- int c;
-
- while (1) {
- c = getchar_update_lineno();
- if (c != '/')
- return c;
-
- c = xgetchar();
- if (c == '/') {
- do {
- c = getchar_update_lineno();
- } while (c != EOF && c != '\n');
- return c;
- } else if (c == '*') {
- while (1) {
- c = getchar_update_lineno();
- if (c == EOF)
- return EOF;
- if (c == '*') {
- do {
- c = getchar_update_lineno();
- } while (c == '*');
- if (c == '/')
- break;
- }
- }
- } else {
- xungetc();
- return '/';
- }
- }
-}
-
-/*
- * Read and return a token. Tokens are string or character literals
- * or else delimited by whitespace or by [(),{}].
- * The latter are all returned as single characters.
- */
-static char *
-read_token(void)
-{
- int c, q;
- char *buf;
- unsigned int alc, off;
- char* delims = "(),{}";
-
- while (1) {
- c = getchar_skipping_comments();
- if (c == EOF)
- return nil;
- if (!xisspace(c))
- break;
- }
- alc = 16;
- buf = xmalloc(alc + 1);
- off = 0;
- if(c == '"' || c == '\'') {
- q = c;
- buf[off] = c;
- ++off;
- while (1) {
- if (off+2 >= alc) { // room for c and maybe next char
- alc *= 2;
- buf = xrealloc(buf, alc + 1);
- }
- c = getchar_no_eof();
- buf[off] = c;
- ++off;
- if(c == q)
- break;
- if(c == '\\') {
- buf[off] = getchar_no_eof();
- ++off;
- }
- }
- } else if (xstrrchr(delims, c) != nil) {
- buf[off] = c;
- ++off;
- } else {
- while (1) {
- if (off >= alc) {
- alc *= 2;
- buf = xrealloc(buf, alc + 1);
- }
- buf[off] = c;
- ++off;
- c = getchar_skipping_comments();
- if (c == EOF)
- break;
- if (xisspace(c) || xstrrchr(delims, c) != nil) {
- if (c == '\n')
- lineno--;
- xungetc();
- break;
- }
- }
- }
- buf[off] = '\0';
- return buf;
-}
-
-/* Read a token, giving an error on EOF. */
-static char *
-read_token_no_eof(void)
-{
- char *token = read_token();
- if (token == nil)
- bad_eof();
- return token;
-}
-
-/* Read the package clause, and return the package name. */
-static char *
-read_package(void)
-{
- char *token;
-
- token = read_token_no_eof();
- if (token == nil)
- fatal("%s:%d: no token\n", file, lineno);
- if (!streq(token, "package")) {
- fatal("%s:%d: expected \"package\", got \"%s\"\n",
- file, lineno, token);
- }
- return read_token_no_eof();
-}
-
-/* Read and copy preprocessor lines. */
-static void
-read_preprocessor_lines(void)
-{
- int first;
-
- first = 1;
- while (1) {
- int c;
-
- do {
- c = getchar_skipping_comments();
- } while (xisspace(c));
- if (c != '#') {
- xungetc();
- break;
- }
- if(first) {
- first = 0;
- xputchar('\n');
- }
- xputchar(c);
- do {
- c = getchar_update_lineno();
- xputchar(c);
- } while (c != '\n');
- }
-}
-
-/*
- * Read a type in Go syntax and return a type in C syntax. We only
- * permit basic types and pointers.
- */
-static char *
-read_type(void)
-{
- char *p, *op, *q;
- int pointer_count;
- unsigned int len;
-
- p = read_token_no_eof();
- if (*p != '*' && !streq(p, "int") && !streq(p, "uint"))
- return p;
- op = p;
- pointer_count = 0;
- while (*p == '*') {
- ++pointer_count;
- ++p;
- }
- len = xstrlen(p);
- q = xmalloc(len + 2 + pointer_count + 1);
- xmemmove(q, p, len);
-
- // Turn int/uint into intgo/uintgo.
- if((len == 3 && xmemcmp(q, "int", 3) == 0) || (len == 4 && xmemcmp(q, "uint", 4) == 0)) {
- q[len++] = 'g';
- q[len++] = 'o';
- }
-
- while (pointer_count-- > 0)
- q[len++] = '*';
-
- q[len] = '\0';
- xfree(op);
- return q;
-}
-
-/* Return the size of the given type. */
-static int
-type_size(char *p, int *rnd)
-{
- int i;
-
- if(p[xstrlen(p)-1] == '*') {
- *rnd = type_table[Uintptr].rnd;
- return type_table[Uintptr].size;
- }
-
- if(streq(p, "Iface"))
- p = "Eface";
-
- for(i=0; type_table[i].name; i++)
- if(streq(type_table[i].name, p)) {
- *rnd = type_table[i].rnd;
- return type_table[i].size;
- }
- fatal("%s:%d: unknown type %s\n", file, lineno, p);
- return 0;
-}
-
-/*
- * Read a list of parameters. Each parameter is a name and a type.
- * The list ends with a ')'. We have already read the '('.
- */
-static struct params *
-read_params(int *poffset)
-{
- char *token;
- struct params *ret, **pp, *p;
- int offset, size, rnd;
-
- ret = nil;
- pp = &ret;
- token = read_token_no_eof();
- offset = 0;
- if (!streq(token, ")")) {
- while (1) {
- p = xmalloc(sizeof(struct params));
- p->name = token;
- p->next = nil;
- *pp = p;
- pp = &p->next;
-
- if(streq(token, "...")) {
- p->type = xstrdup("");
- } else {
- p->type = read_type();
- rnd = 0;
- size = type_size(p->type, &rnd);
- if(rnd > structround)
- rnd = structround;
- if(offset%rnd)
- offset += rnd - offset%rnd;
- offset += size;
- }
-
- token = read_token_no_eof();
- if (!streq(token, ","))
- break;
- token = read_token_no_eof();
- }
- }
- if (!streq(token, ")")) {
- fatal("%s:%d: expected '('\n",
- file, lineno);
- }
- if (poffset != nil)
- *poffset = offset;
- return ret;
-}
-
-/*
- * Read a function header. This reads up to and including the initial
- * '{' character. Returns 1 if it read a header, 0 at EOF.
- */
-static int
-read_func_header(char **name, struct params **params, int *paramwid, struct params **rets)
-{
- int lastline;
- char *token;
-
- lastline = -1;
- while (1) {
- read_preprocessor_lines();
- token = read_token();
- if (token == nil)
- return 0;
- if (streq(token, "func")) {
- if(lastline != -1)
- bwritef(output, "\n");
- break;
- }
- if (lastline != lineno) {
- if (lastline == lineno-1)
- bwritef(output, "\n");
- else
- bwritef(output, "\n#line %d \"%s\"\n", lineno, file);
- lastline = lineno;
- }
- bwritef(output, "%s ", token);
- }
-
- *name = read_token_no_eof();
-
- token = read_token();
- if (token == nil || !streq(token, "(")) {
- fatal("%s:%d: expected \"(\"\n",
- file, lineno);
- }
- *params = read_params(paramwid);
-
- token = read_token();
- if (token == nil || !streq(token, "("))
- *rets = nil;
- else {
- *rets = read_params(nil);
- token = read_token();
- }
- if (token == nil || !streq(token, "{")) {
- fatal("%s:%d: expected \"{\"\n",
- file, lineno);
- }
- return 1;
-}
-
-/* Write out parameters. */
-static void
-write_params(struct params *params, int *first)
-{
- struct params *p;
-
- for (p = params; p != nil; p = p->next) {
- if (*first)
- *first = 0;
- else
- bwritef(output, ", ");
- bwritef(output, "%s %s", p->type, p->name);
- }
-}
-
-/* Write a 6g function header. */
-static void
-write_6g_func_header(char *package, char *name, struct params *params,
- int paramwid, struct params *rets)
-{
- int first, n;
- struct params *p;
-
- bwritef(output, "void\n");
- if(!contains(name, "·"))
- bwritef(output, "%s·", package);
- bwritef(output, "%s(", name);
-
- first = 1;
- write_params(params, &first);
-
- /* insert padding to align output struct */
- if(rets != nil && paramwid%structround != 0) {
- n = structround - paramwid%structround;
- if(n & 1)
- bwritef(output, ", uint8");
- if(n & 2)
- bwritef(output, ", uint16");
- if(n & 4)
- bwritef(output, ", uint32");
- }
-
- write_params(rets, &first);
- bwritef(output, ")\n{\n");
-
- for (p = rets; p != nil; p = p->next) {
- if(streq(p->name, "..."))
- continue;
- if(streq(p->type, "Slice"))
- bwritef(output, "\t%s.array = 0;\n\t%s.len = 0;\n\t%s.cap = 0;\n", p->name, p->name, p->name);
- else if(streq(p->type, "String"))
- bwritef(output, "\t%s.str = 0;\n\t%s.len = 0;\n", p->name, p->name);
- else if(streq(p->type, "Eface"))
- bwritef(output, "\t%s.type = 0;\n\t%s.data = 0;\n", p->name, p->name);
- else if(streq(p->type, "Iface"))
- bwritef(output, "\t%s.tab = 0;\n\t%s.data = 0;\n", p->name, p->name);
- else if(streq(p->type, "Complex128"))
- bwritef(output, "\t%s.real = 0;\n\t%s.imag = 0;\n", p->name, p->name);
- else
- bwritef(output, "\t%s = 0;\n", p->name);
- bwritef(output, "\tFLUSH(&%s);\n", p->name);
- }
-}
-
-/* Write a 6g function trailer. */
-static void
-write_6g_func_trailer(struct params *rets)
-{
- struct params *p;
-
- for (p = rets; p != nil; p = p->next)
- if(!streq(p->name, "..."))
- bwritef(output, "\tFLUSH(&%s);\n", p->name);
- bwritef(output, "}\n");
-}
-
-/* Define the gcc function return type if necessary. */
-static void
-define_gcc_return_type(char *package, char *name, struct params *rets)
-{
- struct params *p;
-
- if (rets == nil || rets->next == nil)
- return;
- bwritef(output, "struct %s_%s_ret {\n", package, name);
- for (p = rets; p != nil; p = p->next)
- bwritef(output, " %s %s;\n", p->type, p->name);
- bwritef(output, "};\n");
-}
-
-/* Write out the gcc function return type. */
-static void
-write_gcc_return_type(char *package, char *name, struct params *rets)
-{
- if (rets == nil)
- bwritef(output, "void");
- else if (rets->next == nil)
- bwritef(output, "%s", rets->type);
- else
- bwritef(output, "struct %s_%s_ret", package, name);
-}
-
-/* Write out a gcc function header. */
-static void
-write_gcc_func_header(char *package, char *name, struct params *params,
- struct params *rets)
-{
- int first;
- struct params *p;
-
- define_gcc_return_type(package, name, rets);
- write_gcc_return_type(package, name, rets);
- bwritef(output, " %s_%s(", package, name);
- first = 1;
- write_params(params, &first);
- bwritef(output, ") asm (\"%s.%s\");\n", package, name);
- write_gcc_return_type(package, name, rets);
- bwritef(output, " %s_%s(", package, name);
- first = 1;
- write_params(params, &first);
- bwritef(output, ")\n{\n");
- for (p = rets; p != nil; p = p->next)
- bwritef(output, " %s %s;\n", p->type, p->name);
-}
-
-/* Write out a gcc function trailer. */
-static void
-write_gcc_func_trailer(char *package, char *name, struct params *rets)
-{
- if (rets == nil) {
- // nothing to do
- }
- else if (rets->next == nil)
- bwritef(output, "return %s;\n", rets->name);
- else {
- struct params *p;
-
- bwritef(output, " {\n struct %s_%s_ret __ret;\n", package, name);
- for (p = rets; p != nil; p = p->next)
- bwritef(output, " __ret.%s = %s;\n", p->name, p->name);
- bwritef(output, " return __ret;\n }\n");
- }
- bwritef(output, "}\n");
-}
-
-/* Write out a function header. */
-static void
-write_func_header(char *package, char *name,
- struct params *params, int paramwid,
- struct params *rets)
-{
- if (gcc)
- write_gcc_func_header(package, name, params, rets);
- else
- write_6g_func_header(package, name, params, paramwid, rets);
- bwritef(output, "#line %d \"%s\"\n", lineno, file);
-}
-
-/* Write out a function trailer. */
-static void
-write_func_trailer(char *package, char *name,
- struct params *rets)
-{
- if (gcc)
- write_gcc_func_trailer(package, name, rets);
- else
- write_6g_func_trailer(rets);
-}
-
-/*
- * Read and write the body of the function, ending in an unnested }
- * (which is read but not written).
- */
-static void
-copy_body(void)
-{
- int nesting = 0;
- while (1) {
- int c;
-
- c = getchar_no_eof();
- if (c == '}' && nesting == 0)
- return;
- xputchar(c);
- switch (c) {
- default:
- break;
- case '{':
- ++nesting;
- break;
- case '}':
- --nesting;
- break;
- case '/':
- c = getchar_update_lineno();
- xputchar(c);
- if (c == '/') {
- do {
- c = getchar_no_eof();
- xputchar(c);
- } while (c != '\n');
- } else if (c == '*') {
- while (1) {
- c = getchar_no_eof();
- xputchar(c);
- if (c == '*') {
- do {
- c = getchar_no_eof();
- xputchar(c);
- } while (c == '*');
- if (c == '/')
- break;
- }
- }
- }
- break;
- case '"':
- case '\'':
- {
- int delim = c;
- do {
- c = getchar_no_eof();
- xputchar(c);
- if (c == '\\') {
- c = getchar_no_eof();
- xputchar(c);
- c = '\0';
- }
- } while (c != delim);
- }
- break;
- }
- }
-}
-
-/* Process the entire file. */
-static void
-process_file(void)
-{
- char *package, *name, *p, *n;
- struct params *params, *rets;
- int paramwid;
-
- package = read_package();
- read_preprocessor_lines();
- while (read_func_header(&name, &params, &paramwid, &rets)) {
- // name may have a package override already
- n = xstrstr(name, "·");
- if(n != nil) {
- p = xmalloc(n - name + 1);
- xmemmove(p, name, n - name);
- p[n - name] = 0;
- n += xstrlen("·");
- } else {
- p = package;
- n = name;
- }
- write_func_header(p, n, params, paramwid, rets);
- copy_body();
- write_func_trailer(p, n, rets);
- xfree(name);
- if(p != package) xfree(p);
- free_params(params);
- free_params(rets);
- }
- xfree(package);
-}
-
-void
-goc2c(char *goc, char *c)
-{
- int i;
- Buf in, out;
-
- binit(&in);
- binit(&out);
-
- file = goc;
- readfile(&in, goc);
-
- // TODO: set gcc=1 when using gcc
-
- if(!gcc) {
- if(contains(goarch, "64p32")) {
- type_table[Uintptr].size = 4;
- type_table[Int].size = 4;
- structround = 8;
- } else if(contains(goarch, "64")) {
- type_table[Uintptr].size = 8;
- if(use64bitint) {
- type_table[Int].size = 8;
- } else {
- type_table[Int].size = 4;
- }
- structround = 8;
- } else {
- // NOTE: These are set in the initializer,
- // but they might have been changed by a
- // previous invocation of goc2c, so we have
- // to restore them.
- type_table[Uintptr].size = 4;
- type_table[Int].size = 4;
- structround = 4;
- }
-
- type_table[Uint].size = type_table[Int].size;
- type_table[Slice].size = type_table[Uintptr].size+2*type_table[Int].size;
- type_table[Eface].size = 2*type_table[Uintptr].size;
- type_table[String].size = 2*type_table[Uintptr].size;
-
- for(i=0; i<nelem(type_table); i++)
- type_table[i].rnd = type_table[i].size;
-
- type_table[String].rnd = type_table[Uintptr].rnd;
- type_table[Slice].rnd = type_table[Uintptr].rnd;
- type_table[Eface].rnd = type_table[Uintptr].rnd;
- type_table[Complex128].rnd = type_table[Float64].rnd;
- }
-
- bprintf(&out, "// auto generated by go tool dist\n// goos=%s goarch=%s\n\n", goos, goarch);
- input = bstr(&in);
- output = &out;
-
- lineno = 1;
- process_file();
-
- writefile(&out, c, 0);
-}
diff --git a/src/cmd/dist/plan9.c b/src/cmd/dist/plan9.c
index 8d492ebc6..e4bf25147 100644
--- a/src/cmd/dist/plan9.c
+++ b/src/cmd/dist/plan9.c
@@ -23,7 +23,7 @@ bprintf(Buf *b, char *fmt, ...)
{
va_list arg;
char buf[4096];
-
+
breset(b);
va_start(arg, fmt);
vsnprintf(buf, sizeof buf, fmt, arg);
@@ -572,10 +572,10 @@ bool
hassuffix(char *p, char *suffix)
{
int np, ns;
-
+
np = strlen(p);
ns = strlen(suffix);
- return np >= ns && strcmp(p+np-ns, suffix) == 0;
+ return np >= ns && streq(p+np-ns, suffix);
}
// hasprefix reports whether p begins with prefix.
diff --git a/src/cmd/dist/unix.c b/src/cmd/dist/unix.c
index 668b189ca..893ed5cdd 100644
--- a/src/cmd/dist/unix.c
+++ b/src/cmd/dist/unix.c
@@ -431,7 +431,7 @@ xremoveall(char *p)
}
bfree(&b);
- vfree(&dir);
+ vfree(&dir);
}
// xreaddir replaces dst with a list of the names of the files in dir.
@@ -441,13 +441,13 @@ xreaddir(Vec *dst, char *dir)
{
DIR *d;
struct dirent *dp;
-
+
vreset(dst);
d = opendir(dir);
if(d == nil)
fatal("opendir %s: %s", dir, strerror(errno));
while((dp = readdir(d)) != nil) {
- if(strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
+ if(streq(dp->d_name, ".") || streq(dp->d_name, ".."))
continue;
vadd(dst, dp->d_name);
}
@@ -461,7 +461,7 @@ xworkdir(void)
{
Buf b;
char *p;
-
+
binit(&b);
xgetenv(&b, "TMPDIR");
@@ -546,10 +546,10 @@ bool
hassuffix(char *p, char *suffix)
{
int np, ns;
-
+
np = strlen(p);
ns = strlen(suffix);
- return np >= ns && strcmp(p+np-ns, suffix) == 0;
+ return np >= ns && streq(p+np-ns, suffix);
}
// hasprefix reports whether p begins with prefix.
@@ -716,7 +716,7 @@ main(int argc, char **argv)
fatal("unknown architecture: %s", u.machine);
}
- if(strcmp(gohostarch, "arm") == 0)
+ if(streq(gohostarch, "arm"))
maxnbg = 1;
// The OS X 10.6 linker does not support external linking mode.
@@ -728,7 +728,7 @@ main(int argc, char **argv)
//
// Roughly, OS X 10.N shows up as uname release (N+4),
// so OS X 10.6 is uname version 10 and OS X 10.8 is uname version 12.
- if(strcmp(gohostos, "darwin") == 0) {
+ if(streq(gohostos, "darwin")) {
if(uname(&u) < 0)
fatal("uname: %s", strerror(errno));
osx = atoi(u.release) - 4;
diff --git a/src/cmd/dist/windows.c b/src/cmd/dist/windows.c
index 2839c4bc5..1102adff5 100644
--- a/src/cmd/dist/windows.c
+++ b/src/cmd/dist/windows.c
@@ -770,10 +770,10 @@ bool
hassuffix(char *p, char *suffix)
{
int np, ns;
-
+
np = strlen(p);
ns = strlen(suffix);
- return np >= ns && strcmp(p+np-ns, suffix) == 0;
+ return np >= ns && streq(p+np-ns, suffix);
}
bool
diff --git a/src/cmd/fix/doc.go b/src/cmd/fix/doc.go
index 5de3e08c5..057016957 100644
--- a/src/cmd/fix/doc.go
+++ b/src/cmd/fix/doc.go
@@ -27,7 +27,7 @@ rewrites are idempotent, so that it is safe to apply fix to updated
or partially updated code even without using the -r flag.
Fix prints the full list of fixes it can apply in its help output;
-to see them, run go tool fix -?.
+to see them, run go tool fix -help.
Fix does not make backup copies of the files that it edits.
Instead, use a version control system's ``diff'' functionality to inspect
diff --git a/src/cmd/gc/builtin.c b/src/cmd/gc/builtin.c
index 4808269b7..60b7c2f97 100644
--- a/src/cmd/gc/builtin.c
+++ b/src/cmd/gc/builtin.c
@@ -9,11 +9,12 @@ char *runtimeimport =
"func @\"\".throwreturn ()\n"
"func @\"\".throwinit ()\n"
"func @\"\".panicwrap (? string, ? string, ? string)\n"
- "func @\"\".panic (? interface {})\n"
- "func @\"\".recover (? *int32) (? interface {})\n"
+ "func @\"\".gopanic (? interface {})\n"
+ "func @\"\".gorecover (? *int32) (? interface {})\n"
"func @\"\".printbool (? bool)\n"
"func @\"\".printfloat (? float64)\n"
"func @\"\".printint (? int64)\n"
+ "func @\"\".printhex (? uint64)\n"
"func @\"\".printuint (? uint64)\n"
"func @\"\".printcomplex (? complex128)\n"
"func @\"\".printstring (? string)\n"
@@ -64,7 +65,6 @@ char *runtimeimport =
"func @\"\".efaceeq (@\"\".i1·2 any, @\"\".i2·3 any) (@\"\".ret·1 bool)\n"
"func @\"\".ifacethash (@\"\".i1·2 any) (@\"\".ret·1 uint32)\n"
"func @\"\".efacethash (@\"\".i1·2 any) (@\"\".ret·1 uint32)\n"
- "func @\"\".equal (@\"\".typ·2 *byte, @\"\".x1·3 any, @\"\".x2·4 any) (@\"\".ret·1 bool)\n"
"func @\"\".makemap (@\"\".mapType·2 *byte, @\"\".hint·3 int64) (@\"\".hmap·1 map[any]any)\n"
"func @\"\".mapaccess1 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 *any) (@\"\".val·1 *any)\n"
"func @\"\".mapaccess1_fast32 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n"
@@ -96,12 +96,12 @@ char *runtimeimport =
"func @\"\".makeslice (@\"\".typ·2 *byte, @\"\".nel·3 int64, @\"\".cap·4 int64) (@\"\".ary·1 []any)\n"
"func @\"\".growslice (@\"\".typ·2 *byte, @\"\".old·3 []any, @\"\".n·4 int64) (@\"\".ary·1 []any)\n"
"func @\"\".memmove (@\"\".to·1 *any, @\"\".frm·2 *any, @\"\".length·3 uintptr)\n"
- "func @\"\".memequal (@\"\".eq·1 *bool, @\"\".size·2 uintptr, @\"\".x·3 *any, @\"\".y·4 *any)\n"
- "func @\"\".memequal8 (@\"\".eq·1 *bool, @\"\".size·2 uintptr, @\"\".x·3 *any, @\"\".y·4 *any)\n"
- "func @\"\".memequal16 (@\"\".eq·1 *bool, @\"\".size·2 uintptr, @\"\".x·3 *any, @\"\".y·4 *any)\n"
- "func @\"\".memequal32 (@\"\".eq·1 *bool, @\"\".size·2 uintptr, @\"\".x·3 *any, @\"\".y·4 *any)\n"
- "func @\"\".memequal64 (@\"\".eq·1 *bool, @\"\".size·2 uintptr, @\"\".x·3 *any, @\"\".y·4 *any)\n"
- "func @\"\".memequal128 (@\"\".eq·1 *bool, @\"\".size·2 uintptr, @\"\".x·3 *any, @\"\".y·4 *any)\n"
+ "func @\"\".memequal (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
+ "func @\"\".memequal8 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
+ "func @\"\".memequal16 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
+ "func @\"\".memequal32 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
+ "func @\"\".memequal64 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
+ "func @\"\".memequal128 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
"func @\"\".int64div (? int64, ? int64) (? int64)\n"
"func @\"\".uint64div (? uint64, ? uint64) (? uint64)\n"
"func @\"\".int64mod (? int64, ? int64) (? int64)\n"
diff --git a/src/cmd/gc/bv.c b/src/cmd/gc/bv.c
index 0e8f8d473..cfd1cd281 100644
--- a/src/cmd/gc/bv.c
+++ b/src/cmd/gc/bv.c
@@ -108,6 +108,9 @@ bvnext(Bvec *bv, int32 i)
{
uint32 w;
+ if(i >= bv->n)
+ return -1;
+
// Jump i ahead to next word with bits.
if((bv->b[i>>WORDSHIFT]>>(i&WORDMASK)) == 0) {
i &= ~WORDMASK;
@@ -117,7 +120,7 @@ bvnext(Bvec *bv, int32 i)
}
if(i >= bv->n)
return -1;
-
+
// Find 1 bit.
w = bv->b[i>>WORDSHIFT]>>(i&WORDMASK);
while((w&1) == 0) {
diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c
index c01784a81..e418b9c56 100644
--- a/src/cmd/gc/const.c
+++ b/src/cmd/gc/const.c
@@ -1566,7 +1566,6 @@ isgoconst(Node *n)
case ORSH:
case OSUB:
case OXOR:
- case OCONV:
case OIOTA:
case OCOMPLEX:
case OREAL:
@@ -1574,7 +1573,12 @@ isgoconst(Node *n)
if(isgoconst(n->left) && (n->right == N || isgoconst(n->right)))
return 1;
break;
-
+
+ case OCONV:
+ if(okforconst[n->type->etype] && isgoconst(n->left))
+ return 1;
+ break;
+
case OLEN:
case OCAP:
l = n->left;
diff --git a/src/cmd/gc/fmt.c b/src/cmd/gc/fmt.c
index 951170aef..98556a658 100644
--- a/src/cmd/gc/fmt.c
+++ b/src/cmd/gc/fmt.c
@@ -1153,7 +1153,7 @@ exprfmt(Fmt *f, Node *n, int prec)
case Csend:
return fmtprint(f, "chan<- %N", n->left);
default:
- if(n->left != N && n->left->op == TCHAN && n->left->sym == S && n->left->etype == Crecv)
+ if(n->left != N && n->left->op == OTCHAN && n->left->sym == S && n->left->etype == Crecv)
return fmtprint(f, "chan (%N)", n->left);
else
return fmtprint(f, "chan %N", n->left);
diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c
index 908a5e53d..86acd8825 100644
--- a/src/cmd/gc/gen.c
+++ b/src/cmd/gc/gen.c
@@ -806,7 +806,8 @@ cgen_eface(Node *n, Node *res)
void
cgen_slice(Node *n, Node *res)
{
- Node src, dst, *cap, *len, *offs, *add, *base;
+ Node src, dst, *cap, *len, *offs, *add, *base, *tmpcap, *tmplen, *cmp, con;
+ Prog *p1, *p2;
cap = n->list->n;
len = n->list->next->n;
@@ -823,6 +824,11 @@ cgen_slice(Node *n, Node *res)
// garbage collector can see.
base = temp(types[TUINTPTR]);
+ tmplen = temp(types[TINT]);
+ if(n->op != OSLICESTR)
+ tmpcap = temp(types[TINT]);
+ else
+ tmpcap = tmplen;
if(isnil(n->left)) {
tempname(&src, n->left->type);
@@ -837,43 +843,62 @@ cgen_slice(Node *n, Node *res)
fatal("slicearr is supposed to work on pointer: %+N\n", n);
cgen(&src, base);
cgen_checknil(base);
- if(offs != N) {
- add = nod(OADD, base, offs);
- typecheck(&add, Erv);
- cgen(add, base);
- }
- } else if(offs == N) {
- src.type = types[tptr];
- cgen(&src, base);
} else {
src.type = types[tptr];
- add = nod(OADDPTR, &src, offs);
- typecheck(&add, Erv);
- cgen(add, base);
+ cgen(&src, base);
}
// committed to the update
gvardef(res);
+ // compute len and cap.
+ // len = n-i, cap = m-i, and offs = i*width.
+ // computing offs last lets the multiply overwrite i.
+ cgen(len, tmplen);
+ if(n->op != OSLICESTR)
+ cgen(cap, tmpcap);
+
+ // if new cap != 0 { base += add }
+ // This avoids advancing base past the end of the underlying array/string,
+ // so that it cannot point at the next object in memory.
+ // If cap == 0, the base doesn't matter except insofar as it is 0 or non-zero.
+ // In essence we are replacing x[i:j:k] where i == j == k
+ // or x[i:j] where i == j == cap(x) with x[0:0:0].
+ if(offs != N) {
+ p1 = gjmp(P);
+ p2 = gjmp(P);
+ patch(p1, pc);
+
+ nodconst(&con, tmpcap->type, 0);
+ cmp = nod(OEQ, tmpcap, &con);
+ typecheck(&cmp, Erv);
+ bgen(cmp, 1, -1, p2);
+
+ add = nod(OADD, base, offs);
+ typecheck(&add, Erv);
+ cgen(add, base);
+
+ patch(p2, pc);
+ }
+
// 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);
+ cgen(tmplen, &dst);
if(n->op != OSLICESTR) {
// dst.cap = cap [ - lo ]
dst = *res;
dst.xoffset += Array_cap;
dst.type = types[simtype[TUINT]];
- cgen(cap, &dst);
+ cgen(tmpcap, &dst);
}
}
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index c3da5f636..12c1e9853 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -447,7 +447,6 @@ enum
OSUB, // x - y
OOR, // x | y
OXOR, // x ^ y
- OADDPTR, // ptr + uintptr, inserted by compiler only, used to avoid unsafe type changes during codegen
OADDSTR, // s + "foo"
OADDR, // &x
OANDAND, // b0 && b1
@@ -1169,6 +1168,7 @@ void cgen_callmeth(Node *n, int proc);
void cgen_eface(Node* n, Node* res);
void cgen_slice(Node* n, Node* res);
void clearlabels(void);
+void clearslim(Node*);
void checklabels(void);
int dotoffset(Node *n, int64 *oary, Node **nn);
void gen(Node *n);
@@ -1363,6 +1363,7 @@ int is64(Type *t);
int isbadimport(Strlit *s);
int isblank(Node *n);
int isblanksym(Sym *s);
+int isdirectiface(Type*);
int isfixedarray(Type *t);
int isideal(Type *t);
int isinter(Type *t);
diff --git a/src/cmd/gc/mparith1.c b/src/cmd/gc/mparith1.c
index 1519caec7..d33a81e09 100644
--- a/src/cmd/gc/mparith1.c
+++ b/src/cmd/gc/mparith1.c
@@ -591,7 +591,7 @@ Fconv(Fmt *fp)
d = mpgetflt(fvp);
if(d >= 0 && (fp->flags & FmtSign))
fmtprint(fp, "+");
- return fmtprint(fp, "%g", d, exp, fvp);
+ return fmtprint(fp, "%g", d);
}
// very out of range. compute decimal approximation by hand.
diff --git a/src/cmd/gc/mparith3.c b/src/cmd/gc/mparith3.c
index 95618f1c6..6afd75c02 100644
--- a/src/cmd/gc/mparith3.c
+++ b/src/cmd/gc/mparith3.c
@@ -251,8 +251,8 @@ mpgetfltN(Mpflt *a, int prec, int bias)
s = minexp - e;
if(s > prec+1)
s = prec+1;
- if((v & ((1<<s)-1)) != 0)
- v |= 1<<s;
+ if((v & ((1ULL<<s)-1)) != 0)
+ v |= 1ULL<<s;
v >>= s;
e = minexp;
}
diff --git a/src/cmd/gc/order.c b/src/cmd/gc/order.c
index 30dbc7dac..d11e9828c 100644
--- a/src/cmd/gc/order.c
+++ b/src/cmd/gc/order.c
@@ -593,7 +593,10 @@ orderstmt(Node *n, Order *order)
orderexpr(&n->rlist->n->left, order); // arg to recv
ch = n->rlist->n->left->type;
tmp1 = ordertemp(ch->type, order, haspointers(ch->type));
- tmp2 = ordertemp(types[TBOOL], order, 0);
+ if(!isblank(n->list->next->n))
+ tmp2 = ordertemp(n->list->next->n->type, order, 0);
+ else
+ tmp2 = ordertemp(types[TBOOL], order, 0);
order->out = list(order->out, n);
r = nod(OAS, n->list->n, tmp1);
typecheck(&r, Etop);
@@ -768,6 +771,12 @@ orderstmt(Node *n, Order *order)
// Special: clean case temporaries in each block entry.
// Select must enter one of its blocks, so there is no
// need for a cleaning at the end.
+ // Doubly special: evaluation order for select is stricter
+ // than ordinary expressions. Even something like p.c
+ // has to be hoisted into a temporary, so that it cannot be
+ // reordered after the channel evaluation for a different
+ // case (if p were nil, then the timing of the fault would
+ // give this away).
t = marktemp(order);
for(l=n->list; l; l=l->next) {
if(l->n->op != OXCASE)
@@ -810,6 +819,8 @@ orderstmt(Node *n, Order *order)
// r->left == N means 'case <-c'.
// c is always evaluated; x and ok are only evaluated when assigned.
orderexpr(&r->right->left, order);
+ if(r->right->left->op != ONAME)
+ r->right->left = ordercopyexpr(r->right->left, r->right->left->type, order, 0);
// Introduce temporary for receive and move actual copy into case body.
// avoids problems with target being addressed, as usual.
@@ -1055,6 +1066,19 @@ orderexpr(Node **np, Order *order)
orderexpr(&n->left, order);
n = ordercopyexpr(n, n->type, order, 1);
break;
+
+ case OEQ:
+ case ONE:
+ orderexpr(&n->left, order);
+ orderexpr(&n->right, order);
+ t = n->left->type;
+ if(t->etype == TSTRUCT || isfixedarray(t)) {
+ // for complex comparisons, we need both args to be
+ // addressable so we can pass them to the runtime.
+ orderaddrtemp(&n->left, order);
+ orderaddrtemp(&n->right, order);
+ }
+ break;
}
lineno = lno;
diff --git a/src/cmd/gc/plive.c b/src/cmd/gc/plive.c
index 716cdd108..dc4edad63 100644
--- a/src/cmd/gc/plive.c
+++ b/src/cmd/gc/plive.c
@@ -1113,8 +1113,7 @@ twobitwalktype1(Type *t, vlong *xoffset, Bvec *bv)
// struct { byte *str; intgo len; }
if((*xoffset & (widthptr-1)) != 0)
fatal("twobitwalktype1: invalid alignment, %T", t);
- bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 0);
- bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 3:0 = multiword:string
+ bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr in first slot
*xoffset += t->width;
break;
@@ -1145,9 +1144,7 @@ twobitwalktype1(Type *t, vlong *xoffset, Bvec *bv)
// struct { byte *array; uintgo len; uintgo cap; }
if((*xoffset & (widthptr-1)) != 0)
fatal("twobitwalktype1: invalid TARRAY alignment, %T", t);
- bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 0);
- bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1);
- bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 2); // 3:1 = multiword/slice
+ bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr in first slot
*xoffset += t->width;
} else
for(i = 0; i < t->bound; i++)
diff --git a/src/cmd/gc/popt.c b/src/cmd/gc/popt.c
index 4c75e6c26..6e6db88ef 100644
--- a/src/cmd/gc/popt.c
+++ b/src/cmd/gc/popt.c
@@ -49,7 +49,7 @@ noreturn(Prog *p)
symlist[0] = pkglookup("panicindex", runtimepkg);
symlist[1] = pkglookup("panicslice", runtimepkg);
symlist[2] = pkglookup("throwinit", runtimepkg);
- symlist[3] = pkglookup("panic", runtimepkg);
+ symlist[3] = pkglookup("gopanic", runtimepkg);
symlist[4] = pkglookup("panicwrap", runtimepkg);
symlist[5] = pkglookup("throwreturn", runtimepkg);
symlist[6] = pkglookup("selectgo", runtimepkg);
diff --git a/src/cmd/gc/racewalk.c b/src/cmd/gc/racewalk.c
index 285bd78a2..27581702c 100644
--- a/src/cmd/gc/racewalk.c
+++ b/src/cmd/gc/racewalk.c
@@ -419,8 +419,10 @@ racewalknode(Node **np, NodeList **init, int wr, int skip)
ret:
if(n->op != OBLOCK) // OBLOCK is handled above in a special way.
racewalklist(n->list, init);
- racewalknode(&n->ntest, &n->ntest->ninit, 0, 0);
- racewalknode(&n->nincr, &n->nincr->ninit, 0, 0);
+ if(n->ntest != N)
+ racewalknode(&n->ntest, &n->ntest->ninit, 0, 0);
+ if(n->nincr != N)
+ racewalknode(&n->nincr, &n->nincr->ninit, 0, 0);
racewalklist(n->nbody, nil);
racewalklist(n->nelse, nil);
racewalklist(n->rlist, nil);
diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c
index 8170c15b6..f227054ca 100644
--- a/src/cmd/gc/reflect.c
+++ b/src/cmd/gc/reflect.c
@@ -378,7 +378,7 @@ methods(Type *t)
// type stored in interface word
it = t;
- if(it->width > widthptr)
+ if(!isdirectiface(it))
it = ptrto(t);
// make list of methods for t,
@@ -724,7 +724,7 @@ dcommontype(Sym *s, int ot, Type *t)
if(ot != 0)
fatal("dcommontype %d", ot);
- sizeofAlg = 4*widthptr;
+ sizeofAlg = 2*widthptr;
if(algarray == nil)
algarray = pkglookup("algarray", runtimepkg);
alg = algtype(t);
@@ -785,6 +785,8 @@ dcommontype(Sym *s, int ot, Type *t)
i = KindSlice;
if(!haspointers(t))
i |= KindNoPointers;
+ if(isdirectiface(t))
+ i |= KindDirectIface;
if(gcprog)
i |= KindGCProg;
ot = duint8(s, ot, i); // kind
@@ -1239,8 +1241,7 @@ static Sym*
dalgsym(Type *t)
{
int ot;
- Sym *s, *hash, *hashfunc, *eq;
- char buf[100];
+ Sym *s, *hash, *hashfunc, *eq, *eqfunc;
// dalgsym is only called for a type that needs an algorithm table,
// which implies that the type is comparable (or else it would use ANOEQ).
@@ -1251,29 +1252,18 @@ dalgsym(Type *t)
eq = typesymprefix(".eq", t);
geneq(eq, t);
- // make Go func (a closure) for calling the hash function from Go
+ // make Go funcs (closures) for calling hash and equal from Go
hashfunc = typesymprefix(".hashfunc", t);
dsymptr(hashfunc, 0, hash, 0);
ggloblsym(hashfunc, widthptr, DUPOK|RODATA);
+ eqfunc = typesymprefix(".eqfunc", t);
+ dsymptr(eqfunc, 0, eq, 0);
+ ggloblsym(eqfunc, widthptr, DUPOK|RODATA);
- // ../../pkg/runtime/runtime.h:/Alg
+ // ../../pkg/runtime/alg.go:/typeAlg
ot = 0;
ot = dsymptr(s, ot, hashfunc, 0);
- ot = dsymptr(s, ot, eq, 0);
- ot = dsymptr(s, ot, pkglookup("memprint", runtimepkg), 0);
- switch(t->width) {
- default:
- ot = dsymptr(s, ot, pkglookup("memcopy", runtimepkg), 0);
- break;
- case 1:
- case 2:
- case 4:
- case 8:
- case 16:
- snprint(buf, sizeof buf, "memcopy%d", (int)t->width*8);
- ot = dsymptr(s, ot, pkglookup(buf, runtimepkg), 0);
- break;
- }
+ ot = dsymptr(s, ot, eqfunc, 0);
ggloblsym(s, ot, DUPOK|RODATA);
return s;
@@ -1511,8 +1501,8 @@ gengcprog1(ProgGen *g, Type *t, vlong *xoffset)
*xoffset += t->width;
break;
case TSTRING:
- proggendata(g, BitsMultiWord);
- proggendata(g, BitsString);
+ proggendata(g, BitsPointer);
+ proggendata(g, BitsScalar);
*xoffset += t->width;
break;
case TINTER:
@@ -1525,8 +1515,8 @@ gengcprog1(ProgGen *g, Type *t, vlong *xoffset)
break;
case TARRAY:
if(isslice(t)) {
- proggendata(g, BitsMultiWord);
- proggendata(g, BitsSlice);
+ proggendata(g, BitsPointer);
+ proggendata(g, BitsScalar);
proggendata(g, BitsScalar);
} else {
t1 = t->type;
diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go
index 0257c3c7d..128fd1a31 100644
--- a/src/cmd/gc/runtime.go
+++ b/src/cmd/gc/runtime.go
@@ -20,12 +20,13 @@ func throwreturn()
func throwinit()
func panicwrap(string, string, string)
-func panic(interface{})
-func recover(*int32) interface{}
+func gopanic(interface{})
+func gorecover(*int32) interface{}
func printbool(bool)
func printfloat(float64)
func printint(int64)
+func printhex(uint64)
func printuint(uint64)
func printcomplex(complex128)
func printstring(string)
@@ -84,8 +85,6 @@ func efaceeq(i1 any, i2 any) (ret bool)
func ifacethash(i1 any) (ret uint32)
func efacethash(i1 any) (ret uint32)
-func equal(typ *byte, x1, x2 any) (ret bool)
-
// *byte is really *runtime.Type
func makemap(mapType *byte, hint int64) (hmap map[any]any)
func mapaccess1(mapType *byte, hmap map[any]any, key *any) (val *any)
@@ -124,12 +123,12 @@ func makeslice(typ *byte, nel int64, cap int64) (ary []any)
func growslice(typ *byte, old []any, n int64) (ary []any)
func memmove(to *any, frm *any, length uintptr)
-func memequal(eq *bool, size uintptr, x, y *any)
-func memequal8(eq *bool, size uintptr, x, y *any)
-func memequal16(eq *bool, size uintptr, x, y *any)
-func memequal32(eq *bool, size uintptr, x, y *any)
-func memequal64(eq *bool, size uintptr, x, y *any)
-func memequal128(eq *bool, size uintptr, x, y *any)
+func memequal(x, y *any, size uintptr) bool
+func memequal8(x, y *any, size uintptr) bool
+func memequal16(x, y *any, size uintptr) bool
+func memequal32(x, y *any, size uintptr) bool
+func memequal64(x, y *any, size uintptr) bool
+func memequal128(x, y *any, size uintptr) bool
// only used on 32-bit
func int64div(int64, int64) int64
diff --git a/src/cmd/gc/select.c b/src/cmd/gc/select.c
index 7168e6b80..ed23e4318 100644
--- a/src/cmd/gc/select.c
+++ b/src/cmd/gc/select.c
@@ -337,19 +337,23 @@ selecttype(int32 size)
sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("g")), typenod(ptrto(types[TUINT8]))));
sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("selectdone")), typenod(ptrto(types[TUINT8]))));
sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("link")), typenod(ptrto(types[TUINT8]))));
+ sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("prev")), typenod(ptrto(types[TUINT8]))));
sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("elem")), typenod(ptrto(types[TUINT8]))));
sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("releasetime")), typenod(types[TUINT64])));
+ sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("nrelease")), typenod(types[TINT32])));
+ sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("waitlink")), typenod(ptrto(types[TUINT8]))));
typecheck(&sudog, Etype);
sudog->type->noalg = 1;
sudog->type->local = 1;
scase = nod(OTSTRUCT, N, N);
- scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("sg")), sudog));
+ scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("elem")), typenod(ptrto(types[TUINT8]))));
scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("chan")), typenod(ptrto(types[TUINT8]))));
scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("pc")), typenod(types[TUINTPTR])));
scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("kind")), typenod(types[TUINT16])));
scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("so")), typenod(types[TUINT16])));
scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("receivedp")), typenod(ptrto(types[TUINT8]))));
+ scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("releasetime")), typenod(types[TUINT64])));
typecheck(&scase, Etype);
scase->type->noalg = 1;
scase->type->local = 1;
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index 0195f3d62..d62d55e77 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -656,11 +656,15 @@ maptype(Type *key, Type *val)
{
Type *t;
Type *bad;
- int atype;
+ int atype, mtype;
if(key != nil) {
atype = algtype1(key, &bad);
- switch(bad == T ? key->etype : bad->etype) {
+ if(bad == T)
+ mtype = key->etype;
+ else
+ mtype = bad->etype;
+ switch(mtype) {
default:
if(atype == ANOEQ)
yyerror("invalid map key type %T", key);
@@ -2856,18 +2860,19 @@ genhash(Sym *sym, Type *t)
}
// Return node for
-// if p.field != q.field { *eq = false; return }
+// if p.field != q.field { return false }
static Node*
-eqfield(Node *p, Node *q, Node *field, Node *eq)
+eqfield(Node *p, Node *q, Node *field)
{
- Node *nif, *nx, *ny;
+ Node *nif, *nx, *ny, *r;
nx = nod(OXDOT, p, field);
ny = nod(OXDOT, q, field);
nif = nod(OIF, N, N);
nif->ntest = nod(ONE, nx, ny);
- nif->nbody = list(nif->nbody, nod(OAS, nod(OIND, eq, N), nodbool(0)));
- nif->nbody = list(nif->nbody, nod(ORETURN, N, N));
+ r = nod(ORETURN, N, N);
+ r->list = list(r->list, nodbool(0));
+ nif->nbody = list(nif->nbody, r);
return nif;
}
@@ -2896,11 +2901,11 @@ eqmemfunc(vlong size, Type *type)
}
// Return node for
-// if memequal(size, &p.field, &q.field, eq); !*eq { return }
+// if !memequal(&p.field, &q.field, size) { return false }
static Node*
-eqmem(Node *p, Node *q, Node *field, vlong size, Node *eq)
+eqmem(Node *p, Node *q, Node *field, vlong size)
{
- Node *nif, *nx, *ny, *call;
+ Node *nif, *nx, *ny, *call, *r;
nx = nod(OADDR, nod(OXDOT, p, field), N);
nx->etype = 1; // does not escape
@@ -2910,15 +2915,16 @@ eqmem(Node *p, Node *q, Node *field, vlong size, Node *eq)
typecheck(&ny, Erv);
call = nod(OCALL, eqmemfunc(size, nx->type->type), N);
- call->list = list(call->list, eq);
- call->list = list(call->list, nodintconst(size));
call->list = list(call->list, nx);
call->list = list(call->list, ny);
+ call->list = list(call->list, nodintconst(size));
nif = nod(OIF, N, N);
nif->ninit = list(nif->ninit, call);
- nif->ntest = nod(ONOT, nod(OIND, eq, N), N);
- nif->nbody = list(nif->nbody, nod(ORETURN, N, N));
+ nif->ntest = nod(ONOT, call, N);
+ r = nod(ORETURN, N, N);
+ r->list = list(r->list, nodbool(0));
+ nif->nbody = list(nif->nbody, r);
return nif;
}
@@ -2928,7 +2934,7 @@ eqmem(Node *p, Node *q, Node *field, vlong size, Node *eq)
void
geneq(Sym *sym, Type *t)
{
- Node *n, *fn, *np, *neq, *nq, *tfn, *nif, *ni, *nx, *ny, *nrange;
+ Node *n, *fn, *np, *nq, *tfn, *nif, *ni, *nx, *ny, *nrange, *r;
Type *t1, *first;
int old_safemode;
int64 size;
@@ -2941,24 +2947,23 @@ geneq(Sym *sym, Type *t)
dclcontext = PEXTERN;
markdcl();
- // func sym(eq *bool, s uintptr, p, q *T)
+ // func sym(p, q *T, s uintptr) bool
fn = nod(ODCLFUNC, N, N);
fn->nname = newname(sym);
fn->nname->class = PFUNC;
tfn = nod(OTFUNC, N, N);
fn->nname->ntype = tfn;
- n = nod(ODCLFIELD, newname(lookup("eq")), typenod(ptrto(types[TBOOL])));
- tfn->list = list(tfn->list, n);
- neq = n->left;
- n = nod(ODCLFIELD, newname(lookup("s")), typenod(types[TUINTPTR]));
- tfn->list = list(tfn->list, n);
n = nod(ODCLFIELD, newname(lookup("p")), typenod(ptrto(t)));
tfn->list = list(tfn->list, n);
np = n->left;
n = nod(ODCLFIELD, newname(lookup("q")), typenod(ptrto(t)));
tfn->list = list(tfn->list, n);
nq = n->left;
+ n = nod(ODCLFIELD, newname(lookup("s")), typenod(types[TUINTPTR]));
+ tfn->list = list(tfn->list, n);
+ n = nod(ODCLFIELD, N, typenod(types[TBOOL]));
+ tfn->rlist = list(tfn->rlist, n);
funchdr(fn);
@@ -2984,7 +2989,7 @@ geneq(Sym *sym, Type *t)
colasdefn(nrange->list, nrange);
ni = nrange->list->n;
- // if p[i] != q[i] { *eq = false; return }
+ // if p[i] != q[i] { return false }
nx = nod(OINDEX, np, ni);
nx->bounded = 1;
ny = nod(OINDEX, nq, ni);
@@ -2992,13 +2997,11 @@ geneq(Sym *sym, Type *t)
nif = nod(OIF, N, N);
nif->ntest = nod(ONE, nx, ny);
- nif->nbody = list(nif->nbody, nod(OAS, nod(OIND, neq, N), nodbool(0)));
- nif->nbody = list(nif->nbody, nod(ORETURN, N, N));
+ r = nod(ORETURN, N, N);
+ r->list = list(r->list, nodbool(0));
+ nif->nbody = list(nif->nbody, r);
nrange->nbody = list(nrange->nbody, nif);
fn->nbody = list(fn->nbody, nrange);
-
- // *eq = true;
- fn->nbody = list(fn->nbody, nod(OAS, nod(OIND, neq, N), nodbool(1)));
break;
case TSTRUCT:
@@ -3023,16 +3026,16 @@ geneq(Sym *sym, Type *t)
// cross-package unexported fields.
if(first != T) {
if(first->down == t1) {
- fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq));
+ fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym)));
} else if(first->down->down == t1) {
- fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq));
+ fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym)));
first = first->down;
if(!isblanksym(first->sym))
- fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq));
+ fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym)));
} else {
// More than two fields: use memequal.
size = offend - first->width; // first->width is offset
- fn->nbody = list(fn->nbody, eqmem(np, nq, newname(first->sym), size, neq));
+ fn->nbody = list(fn->nbody, eqmem(np, nq, newname(first->sym), size));
}
first = T;
}
@@ -3042,14 +3045,17 @@ geneq(Sym *sym, Type *t)
continue;
// Check this field, which is not just memory.
- fn->nbody = list(fn->nbody, eqfield(np, nq, newname(t1->sym), neq));
+ fn->nbody = list(fn->nbody, eqfield(np, nq, newname(t1->sym)));
}
- // *eq = true;
- fn->nbody = list(fn->nbody, nod(OAS, nod(OIND, neq, N), nodbool(1)));
break;
}
+ // return true
+ r = nod(ORETURN, N, N);
+ r->list = list(r->list, nodbool(1));
+ fn->nbody = list(fn->nbody, r);
+
if(debug['r'])
dumplist("geneq body", fn->nbody);
@@ -3792,3 +3798,42 @@ checknil(Node *x, NodeList **init)
n->typecheck = 1;
*init = list(*init, n);
}
+
+/*
+ * Can this type be stored directly in an interface word?
+ */
+int
+isdirectiface(Type *t)
+{
+ // Setting IfacePointerOnly = 1 changes the
+ // interface representation so that the data word
+ // in an interface value must always be a pointer.
+ // Setting it to 0 uses the original representation,
+ // where the data word can hold a pointer or any
+ // non-pointer value no bigger than a pointer.
+ enum {
+ IfacePointerOnly = 1,
+ };
+
+ if(IfacePointerOnly) {
+ switch(t->etype) {
+ case TPTR32:
+ case TPTR64:
+ case TCHAN:
+ case TMAP:
+ case TFUNC:
+ case TUNSAFEPTR:
+ return 1;
+ case TARRAY:
+ // Array of 1 direct iface type can be direct.
+ return t->bound == 1 && isdirectiface(t->type);
+ case TSTRUCT:
+ // Struct with 1 field of direct iface type can be direct.
+ return t->type != T && t->type->down == T && isdirectiface(t->type->type);
+ }
+ return 0;
+ }
+
+ dowidth(t);
+ return t->width <= widthptr;
+}
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
index 92e9ad521..746feb4d1 100644
--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -525,19 +525,6 @@ reswitch:
op = n->etype;
goto arith;
- case OADDPTR:
- ok |= Erv;
- l = typecheck(&n->left, Erv);
- r = typecheck(&n->right, Erv);
- if(l->type == T || r->type == T)
- goto error;
- if(l->type->etype != tptr)
- fatal("bad OADDPTR left type %E for %N", l->type->etype, n->left);
- if(r->type->etype != TUINTPTR)
- fatal("bad OADDPTR right type %E for %N", r->type->etype, n->right);
- n->type = types[tptr];
- goto ret;
-
case OADD:
case OAND:
case OANDAND:
@@ -2965,7 +2952,7 @@ typecheckas2(Node *n)
if(l->defn == n)
l->type = r->type;
l = n->list->next->n;
- if(l->type != T)
+ if(l->type != T && l->type->etype != TBOOL)
checkassignto(types[TBOOL], l);
if(l->defn == n && l->ntype == N)
l->type = types[TBOOL];
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index cf25a3eac..365ece267 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -543,11 +543,11 @@ walkexpr(Node **np, NodeList **init)
goto ret;
case OPANIC:
- n = mkcall("panic", T, init, n->left);
+ n = mkcall("gopanic", T, init, n->left);
goto ret;
case ORECOVER:
- n = mkcall("recover", n->type, init, nod(OADDR, nodfp, N));
+ n = mkcall("gorecover", n->type, init, nod(OADDR, nodfp, N));
goto ret;
case OLITERAL:
@@ -673,7 +673,7 @@ walkexpr(Node **np, NodeList **init)
n1 = nod(OADDR, n->list->n, N);
n1->etype = 1; // addr does not escape
fn = chanfn("chanrecv2", 2, r->left->type);
- r = mkcall1(fn, types[TBOOL], init, typename(r->left->type), r->left, n1);
+ r = mkcall1(fn, n->list->next->n->type, init, typename(r->left->type), r->left, n1);
n = nod(OAS, n->list->next->n, r);
typecheck(&n, Etop);
goto ret;
@@ -723,6 +723,12 @@ walkexpr(Node **np, NodeList **init)
var->typecheck = 1;
fn = mapfn(p, t);
r = mkcall1(fn, getoutargx(fn->type), init, typename(t), r->left, key);
+
+ // mapaccess2* returns a typed bool, but due to spec changes,
+ // the boolean result of i.(T) is now untyped so we make it the
+ // same type as the variable on the lhs.
+ if(!isblank(n->list->next->n))
+ r->type->type->down->type = n->list->next->n->type;
n->rlist = list1(r);
n->op = OAS2FUNC;
n->list->n = var;
@@ -770,6 +776,12 @@ walkexpr(Node **np, NodeList **init)
*p = '\0';
fn = syslook(buf, 1);
+
+ // runtime.assert(E|I)2TOK returns a typed bool, but due
+ // to spec changes, the boolean result of i.(T) is now untyped
+ // so we make it the same type as the variable on the lhs.
+ if(!isblank(n->list->next->n))
+ fn->type->type->down->type->type = n->list->next->n->type;
ll = list1(typename(r->type));
ll = list(ll, r->left);
argtype(fn, r->left->type);
@@ -822,9 +834,7 @@ walkexpr(Node **np, NodeList **init)
walkexpr(&n->left, init);
// Optimize convT2E as a two-word copy when T is uintptr-shaped.
- if(!isinter(n->left->type) && isnilinter(n->type) &&
- (n->left->type->width == widthptr) &&
- isint[simsimtype(n->left->type)]) {
+ if(isnilinter(n->type) && isdirectiface(n->left->type) && n->left->type->width == widthptr && isint[simsimtype(n->left->type)]) {
l = nod(OEFACE, typename(n->left->type), n->left);
l->type = n->type;
l->typecheck = n->typecheck;
@@ -872,8 +882,7 @@ walkexpr(Node **np, NodeList **init)
l->addable = 1;
ll = list(ll, l);
- if(n->left->type->width == widthptr &&
- isint[simsimtype(n->left->type)]) {
+ if(isdirectiface(n->left->type) && n->left->type->width == widthptr && isint[simsimtype(n->left->type)]) {
/* For pointer types, we can make a special form of optimization
*
* These statements are put onto the expression init list:
@@ -1828,9 +1837,12 @@ walkprint(Node *nn, NodeList **init, int defer)
t = types[TINT64];
}
} else {
- if(et == TUINT64)
- on = syslook("printuint", 0);
- 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]) {
@@ -2866,14 +2878,14 @@ sliceany(Node* n, NodeList **init)
lb = N;
}
- // dynamic checks convert all bounds to unsigned to save us the bound < 0 comparison
- // generate
- // if hb > bound || lb > hb { panicslice() }
+ // Checking src[lb:hb:cb] or src[lb:hb].
+ // if chk0 || chk1 || chk2 { panicslice() }
chk = N;
- chk0 = N;
- chk1 = N;
- chk2 = N;
+ chk0 = N; // cap(src) < cb
+ chk1 = N; // cb < hb for src[lb:hb:cb]; cap(src) < hb for src[lb:hb]
+ chk2 = N; // hb < lb
+ // All comparisons are unsigned to avoid testing < 0.
bt = types[simtype[TUINT]];
if(cb != N && cb->type->width > 4)
bt = types[TUINT64];
@@ -3013,10 +3025,10 @@ eqfor(Type *t)
n = newname(sym);
n->class = PFUNC;
ntype = nod(OTFUNC, N, N);
- ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(types[TBOOL]))));
- ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
+ ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
+ ntype->rlist = list(ntype->rlist, nod(ODCLFIELD, N, typenod(types[TBOOL])));
typecheck(&ntype, Etype);
n->type = ntype->type;
return n;
@@ -3037,10 +3049,9 @@ countfield(Type *t)
static void
walkcompare(Node **np, NodeList **init)
{
- Node *n, *l, *r, *fn, *call, *a, *li, *ri, *expr;
+ Node *n, *l, *r, *call, *a, *li, *ri, *expr;
int andor, i;
Type *t, *t1;
- static Node *tempbool;
n = *np;
@@ -3058,8 +3069,9 @@ walkcompare(Node **np, NodeList **init)
break;
}
- if(!islvalue(n->left) || !islvalue(n->right))
- goto hard;
+ if(!islvalue(n->left) || !islvalue(n->right)) {
+ fatal("arguments of comparison must be lvalues");
+ }
l = temp(ptrto(t));
a = nod(OAS, l, nod(OADDR, n->left, N));
@@ -3118,57 +3130,16 @@ walkcompare(Node **np, NodeList **init)
goto ret;
}
- // Chose not to inline, but still have addresses.
- // Call equality function directly.
- // The equality function requires a bool pointer for
- // storing its address, because it has to be callable
- // from C, and C can't access an ordinary Go return value.
- // To avoid creating many temporaries, cache one per function.
- if(tempbool == N || tempbool->curfn != curfn)
- tempbool = temp(types[TBOOL]);
-
+ // Chose not to inline. Call equality function directly.
call = nod(OCALL, eqfor(t), N);
- a = nod(OADDR, tempbool, N);
- a->etype = 1; // does not escape
- call->list = list(call->list, a);
- call->list = list(call->list, nodintconst(t->width));
call->list = list(call->list, l);
call->list = list(call->list, r);
- typecheck(&call, Etop);
- walkstmt(&call);
- *init = list(*init, call);
-
- // tempbool cannot be used directly as multiple comparison
- // expressions may exist in the same statement. Create another
- // temporary to hold the value (its address is not taken so it can
- // be optimized away).
- r = temp(types[TBOOL]);
- a = nod(OAS, r, tempbool);
- typecheck(&a, Etop);
- walkstmt(&a);
- *init = list(*init, a);
-
+ call->list = list(call->list, nodintconst(t->width));
+ r = call;
if(n->op != OEQ)
r = nod(ONOT, r, N);
goto ret;
-hard:
- // Cannot take address of one or both of the operands.
- // Instead, pass directly to runtime helper function.
- // Easier on the stack than passing the address
- // of temporary variables, because we are better at reusing
- // the argument space than temporary variable space.
- fn = syslook("equal", 1);
- l = n->left;
- r = n->right;
- argtype(fn, n->left->type);
- argtype(fn, n->left->type);
- r = mkcall1(fn, n->type, init, typename(n->left->type), l, r);
- if(n->op == ONE) {
- r = nod(ONOT, r, N);
- }
- goto ret;
-
ret:
typecheck(&r, Erv);
walkexpr(&r, init);
diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go
index fa9262c0f..fd92ca278 100644
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -885,7 +885,7 @@ func (b *builder) build(a *action) (err error) {
}
if len(gofiles) == 0 {
- return &build.NoGoError{a.p.Dir}
+ return &build.NoGoError{Dir: a.p.Dir}
}
// If we're doing coverage, preprocess the .go files and put them in the work directory
@@ -1613,8 +1613,10 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []
}
func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
+ // Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files.
+ inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
sfile = mkAbs(p.Dir, sfile)
- return b.run(p.Dir, p.ImportPath, nil, tool(archChar+"a"), "-trimpath", b.work, "-I", obj, "-o", ofile, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, sfile)
+ return b.run(p.Dir, p.ImportPath, nil, tool(archChar+"a"), "-trimpath", b.work, "-I", obj, "-I", inc, "-o", ofile, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, sfile)
}
func (gcToolchain) pkgpath(basedir string, p *Package) string {
@@ -2312,7 +2314,23 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles
nonGccObjs = append(nonGccObjs, f)
}
}
- if err := b.gccld(p, ofile, stringList(bareLDFLAGS, "-Wl,-r", "-nostdlib", staticLibs), gccObjs); err != nil {
+ ldflags := stringList(bareLDFLAGS, "-Wl,-r", "-nostdlib", staticLibs)
+
+ // Some systems, such as Ubuntu, always add --build-id to
+ // every link, but we don't want a build ID since we are
+ // producing an object file. On some of those system a plain
+ // -r (not -Wl,-r) will turn off --build-id, but clang 3.0
+ // doesn't support a plain -r. I don't know how to turn off
+ // --build-id when using clang other than passing a trailing
+ // --build-id=none. So that is what we do, but only on
+ // systems likely to support it, which is to say, systems that
+ // normally use gold or the GNU linker.
+ switch goos {
+ case "android", "dragonfly", "linux", "netbsd":
+ ldflags = append(ldflags, "-Wl,--build-id=none")
+ }
+
+ if err := b.gccld(p, ofile, ldflags, gccObjs); err != nil {
return nil, nil, err
}
diff --git a/src/cmd/go/doc.go b/src/cmd/go/doc.go
index 4778048b5..0d4e26389 100644
--- a/src/cmd/go/doc.go
+++ b/src/cmd/go/doc.go
@@ -19,6 +19,7 @@ The commands are:
env print Go environment information
fix run go tool fix on packages
fmt run gofmt on package sources
+ generate generate Go files by processing source
get download and install packages and dependencies
install compile and install packages and dependencies
list list packages
@@ -219,6 +220,98 @@ To run gofmt with specific options, run gofmt itself.
See also: go fix, go vet.
+Generate Go files by processing source
+
+Usage:
+
+ go generate [-run regexp] [file.go... | packages]
+
+Generate runs commands described by directives within existing
+files. Those commands can run any process but the intent is to
+create or update Go source files, for instance by running yacc.
+
+Go generate is never run automatically by go build, go get, go test,
+and so on. It must be run explicitly.
+
+Directives are written as a whole-line comment of the form
+
+ //go:generate command argument...
+
+(note: no space in "//go") where command is the generator to be
+run, corresponding to an executable file that can be run locally.
+It must either be in the shell path (gofmt), a fully qualified path
+(/usr/you/bin/mytool), or a command alias, described below.
+
+The arguments are space-separated tokens or double-quoted strings
+passed to the generator as individual arguments when it is run.
+
+Quoted strings use Go syntax and are evaluated before execution; a
+quoted string appears a single argument to the generator.
+
+Go generate sets several variables when it runs the generator:
+
+ $GOARCH
+ The execution architecture (arm, amd64, etc.)
+ $GOOS
+ The execution operating system (linux, windows, etc.)
+ $GOFILE
+ The base name of the file.
+ $GOPACKAGE
+ The name of the package of the file containing the directive.
+
+Other than variable substition and quoted-string evaluation, no
+special processing such as "globbing" is performed on the command
+line.
+
+As a last step before running the command, any invocations of any
+environment variables with alphanumeric names, such as $GOFILE or
+$HOME, are expanded throughout the command line. The syntax for
+variable expansion is $NAME on all operating systems. Due to the
+order of evaluation, variables are expanded even inside quoted
+strings. If the variable NAME is not set, $NAME expands to the
+empty string.
+
+A directive of the form,
+
+ //go:generate -command xxx args...
+
+specifies, for the remainder of this source file only, that the
+string xxx represents the command identified by the arguments. This
+can be used to create aliases or to handle multiword generators.
+For example,
+
+ //go:generate -command yacc go tool yacc
+
+specifies that the command "yacc" represents the generator
+"go tool yacc".
+
+Generate processes packages in the order given on the command line,
+one at a time. If the command line lists .go files, they are treated
+as a single package. Within a package, generate processes the
+source files in a package in file name order, one at a time. Within
+a source file, generate runs generators in the order they appear
+in the file, one at a time.
+
+If any generator returns an error exit status, "go generate" skips
+all further processing for that package.
+
+The generator is run in the package's source directory.
+
+Go generate accepts one specific flag:
+
+ -run=""
+ if non-empty, specifies a regular expression to
+ select directives whose command matches the expression.
+
+It also accepts the standard build flags -v, -n, and -x.
+The -v flag prints the names of packages and files as they are
+processed.
+The -n flag prints commands that would be executed.
+The -x flag prints commands as they are executed.
+
+For more about specifying packages, see 'go help packages'.
+
+
Download and install packages and dependencies
Usage:
@@ -750,10 +843,10 @@ will result in the following request(s):
If that page contains the meta tag
- <meta name="go-import" content="example.org git https://code.example/r/p/exproj">
+ <meta name="go-import" content="example.org git https://code.org/r/p/exproj">
the go tool will verify that https://example.org/?go-get=1 contains the
-same meta tag and then git clone https://code.example/r/p/exproj into
+same meta tag and then git clone https://code.org/r/p/exproj into
GOPATH/src/example.org.
New downloaded packages are written to the first directory
diff --git a/src/cmd/go/generate.go b/src/cmd/go/generate.go
new file mode 100644
index 000000000..167758207
--- /dev/null
+++ b/src/cmd/go/generate.go
@@ -0,0 +1,355 @@
+// 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.
+
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "log"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+ "strconv"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+)
+
+var cmdGenerate = &Command{
+ Run: runGenerate,
+ UsageLine: "generate [-run regexp] [file.go... | packages]",
+ Short: "generate Go files by processing source",
+ Long: `
+Generate runs commands described by directives within existing
+files. Those commands can run any process but the intent is to
+create or update Go source files, for instance by running yacc.
+
+Go generate is never run automatically by go build, go get, go test,
+and so on. It must be run explicitly.
+
+Directives are written as a whole-line comment of the form
+
+ //go:generate command argument...
+
+(note: no space in "//go") where command is the generator to be
+run, corresponding to an executable file that can be run locally.
+It must either be in the shell path (gofmt), a fully qualified path
+(/usr/you/bin/mytool), or a command alias, described below.
+
+The arguments are space-separated tokens or double-quoted strings
+passed to the generator as individual arguments when it is run.
+
+Quoted strings use Go syntax and are evaluated before execution; a
+quoted string appears a single argument to the generator.
+
+Go generate sets several variables when it runs the generator:
+
+ $GOARCH
+ The execution architecture (arm, amd64, etc.)
+ $GOOS
+ The execution operating system (linux, windows, etc.)
+ $GOFILE
+ The base name of the file.
+ $GOPACKAGE
+ The name of the package of the file containing the directive.
+
+Other than variable substition and quoted-string evaluation, no
+special processing such as "globbing" is performed on the command
+line.
+
+As a last step before running the command, any invocations of any
+environment variables with alphanumeric names, such as $GOFILE or
+$HOME, are expanded throughout the command line. The syntax for
+variable expansion is $NAME on all operating systems. Due to the
+order of evaluation, variables are expanded even inside quoted
+strings. If the variable NAME is not set, $NAME expands to the
+empty string.
+
+A directive of the form,
+
+ //go:generate -command xxx args...
+
+specifies, for the remainder of this source file only, that the
+string xxx represents the command identified by the arguments. This
+can be used to create aliases or to handle multiword generators.
+For example,
+
+ //go:generate -command yacc go tool yacc
+
+specifies that the command "yacc" represents the generator
+"go tool yacc".
+
+Generate processes packages in the order given on the command line,
+one at a time. If the command line lists .go files, they are treated
+as a single package. Within a package, generate processes the
+source files in a package in file name order, one at a time. Within
+a source file, generate runs generators in the order they appear
+in the file, one at a time.
+
+If any generator returns an error exit status, "go generate" skips
+all further processing for that package.
+
+The generator is run in the package's source directory.
+
+Go generate accepts one specific flag:
+
+ -run=""
+ if non-empty, specifies a regular expression to
+ select directives whose command matches the expression.
+
+It also accepts the standard build flags -v, -n, and -x.
+The -v flag prints the names of packages and files as they are
+processed.
+The -n flag prints commands that would be executed.
+The -x flag prints commands as they are executed.
+
+For more about specifying packages, see 'go help packages'.
+ `,
+}
+
+var generateRunFlag string // generate -run flag
+
+func init() {
+ addBuildFlags(cmdGenerate)
+ cmdGenerate.Flag.StringVar(&generateRunFlag, "run", "", "")
+}
+
+func runGenerate(cmd *Command, args []string) {
+ // Even if the arguments are .go files, this loop suffices.
+ for _, pkg := range packages(args) {
+ for _, file := range pkg.gofiles {
+ if !generate(pkg.Name, file) {
+ break
+ }
+ }
+ }
+}
+
+// generate runs the generation directives for a single file.
+func generate(pkg, absFile string) bool {
+ fd, err := os.Open(absFile)
+ if err != nil {
+ log.Fatalf("generate: %s", err)
+ }
+ defer fd.Close()
+ g := &Generator{
+ r: fd,
+ path: absFile,
+ pkg: pkg,
+ commands: make(map[string][]string),
+ }
+ return g.run()
+}
+
+// A Generator represents the state of a single Go source file
+// being scanned for generator commands.
+type Generator struct {
+ r io.Reader
+ path string // full rooted path name.
+ dir string // full rooted directory of file.
+ file string // base name of file.
+ pkg string
+ commands map[string][]string
+ lineNum int
+}
+
+// run runs the generators in the current file.
+func (g *Generator) run() (ok bool) {
+ // Processing below here calls g.errorf on failure, which does panic(stop).
+ // If we encounter an error, we abort the package.
+ defer func() {
+ e := recover()
+ if e != nil {
+ ok = false
+ if e != stop {
+ panic(e)
+ }
+ }
+ }()
+ g.dir, g.file = filepath.Split(g.path)
+ g.dir = filepath.Clean(g.dir) // No final separator please.
+ if buildV {
+ fmt.Fprintf(os.Stderr, "%s\n", shortPath(g.path))
+ }
+
+ s := bufio.NewScanner(g.r)
+ for s.Scan() {
+ g.lineNum++
+ if !bytes.HasPrefix(s.Bytes(), []byte("//go:generate ")) && !bytes.HasPrefix(s.Bytes(), []byte("//go:generate\t")) {
+ continue
+ }
+ words := g.split(s.Text())
+ if len(words) == 0 {
+ g.errorf("no arguments to directive")
+ }
+ if words[0] == "-command" {
+ g.setShorthand(words)
+ continue
+ }
+ // Run the command line.
+ if buildN || buildX {
+ fmt.Fprintf(os.Stderr, "%s\n", strings.Join(words, " "))
+ }
+ if buildN {
+ continue
+ }
+ g.exec(words)
+ }
+ if s.Err() != nil {
+ g.errorf("error reading %s: %s", shortPath(g.path), s.Err())
+ }
+ return true
+}
+
+// split breaks the line into words, evaluating quoted
+// strings and evaluating environment variables.
+// The initial //go:generate element is dropped.
+func (g *Generator) split(line string) []string {
+ // Parse line, obeying quoted strings.
+ var words []string
+ line = line[len("//go:generate "):]
+ // One (possibly quoted) word per iteration.
+Words:
+ for {
+ line = strings.TrimLeft(line, " \t")
+ if len(line) == 0 {
+ break
+ }
+ if line[0] == '"' {
+ for i := 1; i < len(line); i++ {
+ c := line[i] // Only looking for ASCII so this is OK.
+ switch c {
+ case '\\':
+ if i+1 == len(line) {
+ g.errorf("bad backslash")
+ }
+ i++ // Absorb next byte (If it's a multibyte we'll get an error in Unquote).
+ case '"':
+ word, err := strconv.Unquote(line[0 : i+1])
+ if err != nil {
+ g.errorf("bad quoted string")
+ }
+ words = append(words, word)
+ line = line[i+1:]
+ // Check the next character is space or end of line.
+ if len(line) > 0 && line[0] != ' ' && line[0] != '\t' {
+ g.errorf("expect space after quoted argument")
+ }
+ continue Words
+ }
+ }
+ g.errorf("mismatched quoted string")
+ }
+ i := strings.IndexAny(line, " \t")
+ if i < 0 {
+ i = len(line)
+ }
+ words = append(words, line[0:i])
+ line = line[i:]
+ }
+ // Substitute command if required.
+ if len(words) > 0 && g.commands[words[0]] != nil {
+ // Replace 0th word by command substitution.
+ words = append(g.commands[words[0]], words[1:]...)
+ }
+ // Substitute environment variables.
+ for i, word := range words {
+ words[i] = g.expandEnv(word)
+ }
+ return 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.
+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...))
+ panic(stop)
+}
+
+// expandEnv expands any $XXX invocations in word.
+func (g *Generator) expandEnv(word string) string {
+ if !strings.ContainsRune(word, '$') {
+ return word
+ }
+ var buf bytes.Buffer
+ var w int
+ var r rune
+ for i := 0; i < len(word); i += w {
+ r, w = utf8.DecodeRuneInString(word[i:])
+ if r != '$' {
+ buf.WriteRune(r)
+ continue
+ }
+ w += g.identLength(word[i+w:])
+ envVar := word[i+1 : i+w]
+ var sub string
+ switch envVar {
+ case "GOARCH":
+ sub = runtime.GOARCH
+ case "GOOS":
+ sub = runtime.GOOS
+ case "GOFILE":
+ sub = g.file
+ case "GOPACKAGE":
+ sub = g.pkg
+ default:
+ sub = os.Getenv(envVar)
+ }
+ buf.WriteString(sub)
+ }
+ return buf.String()
+}
+
+// identLength returns the length of the identifier beginning the string.
+func (g *Generator) identLength(word string) int {
+ for i, r := range word {
+ if r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r) {
+ continue
+ }
+ return i
+ }
+ return len(word)
+}
+
+// setShorthand installs a new shorthand as defined by a -command directive.
+func (g *Generator) setShorthand(words []string) {
+ // Create command shorthand.
+ if len(words) == 1 {
+ g.errorf("no command specified for -command")
+ }
+ command := words[1]
+ if g.commands[command] != nil {
+ g.errorf("command %q defined multiply defined", command)
+ }
+ g.commands[command] = words[2:len(words):len(words)] // force later append to make copy
+}
+
+// exec runs the command specified by the argument. The first word is
+// the command name itself.
+func (g *Generator) exec(words []string) {
+ cmd := exec.Command(words[0], words[1:]...)
+ // Standard in and out of generator should be the usual.
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ // Run the command in the package directory.
+ cmd.Dir = g.dir
+ env := []string{
+ "GOARCH=" + runtime.GOARCH,
+ "GOOS=" + runtime.GOOS,
+ "GOFILE=" + g.file,
+ "GOPACKAGE=" + g.pkg,
+ }
+ cmd.Env = mergeEnvLists(env, os.Environ())
+ err := cmd.Run()
+ if err != nil {
+ g.errorf("running %q: %s", words[0], err)
+ }
+}
diff --git a/src/cmd/go/generate_test.go b/src/cmd/go/generate_test.go
new file mode 100644
index 000000000..93c0ae66e
--- /dev/null
+++ b/src/cmd/go/generate_test.go
@@ -0,0 +1,48 @@
+// 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.
+
+package main
+
+import (
+ "reflect"
+ "runtime"
+ "testing"
+)
+
+type splitTest struct {
+ in string
+ out []string
+}
+
+var splitTests = []splitTest{
+ {"", nil},
+ {"x", []string{"x"}},
+ {" a b\tc ", []string{"a", "b", "c"}},
+ {` " a " `, []string{" a "}},
+ {"$GOARCH", []string{runtime.GOARCH}},
+ {"$GOOS", []string{runtime.GOOS}},
+ {"$GOFILE", []string{"proc.go"}},
+ {"$GOPACKAGE", []string{"sys"}},
+ {"a $XXNOTDEFINEDXX b", []string{"a", "", "b"}},
+ {"/$XXNOTDEFINED/", []string{"//"}},
+ {"yacc -o $GOARCH/yacc_$GOFILE", []string{"go", "tool", "yacc", "-o", runtime.GOARCH + "/yacc_proc.go"}},
+}
+
+func TestGenerateCommandParse(t *testing.T) {
+ g := &Generator{
+ r: nil, // Unused here.
+ path: "/usr/ken/sys/proc.go",
+ dir: "/usr/ken/sys",
+ file: "proc.go",
+ pkg: "sys",
+ commands: make(map[string][]string),
+ }
+ g.setShorthand([]string{"-command", "yacc", "go", "tool", "yacc"})
+ for _, test := range splitTests {
+ got := g.split("//go:generate " + test.in)
+ if !reflect.DeepEqual(got, test.out) {
+ t.Errorf("split(%q): got %q expected %q", test.in, got, test.out)
+ }
+ }
+}
diff --git a/src/cmd/go/get.go b/src/cmd/go/get.go
index e708fcf77..a34286f54 100644
--- a/src/cmd/go/get.go
+++ b/src/cmd/go/get.go
@@ -151,7 +151,9 @@ func download(arg string, stk *importStack, getTestDeps bool) {
}
// Only process each package once.
- if downloadCache[arg] {
+ // (Unless we're fetching test dependencies for this package,
+ // in which case we want to process it again.)
+ if downloadCache[arg] && !getTestDeps {
return
}
downloadCache[arg] = true
diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go
index 5b1194aaa..eb69606de 100644
--- a/src/cmd/go/main.go
+++ b/src/cmd/go/main.go
@@ -79,6 +79,7 @@ var commands = []*Command{
cmdEnv,
cmdFix,
cmdFmt,
+ cmdGenerate,
cmdGet,
cmdInstall,
cmdList,
diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go
index d45df265b..1af33f037 100644
--- a/src/cmd/go/pkg.go
+++ b/src/cmd/go/pkg.go
@@ -244,6 +244,9 @@ func loadImport(path string, srcDir string, stk *importStack, importPos []token.
importPath = dirToImportPath(filepath.Join(srcDir, path))
}
if p := packageCache[importPath]; p != nil {
+ if perr := disallowInternal(srcDir, p, stk); perr != p {
+ return perr
+ }
return reusePackage(p, stk)
}
@@ -258,11 +261,14 @@ func loadImport(path string, srcDir string, stk *importStack, importPos []token.
//
// TODO: After Go 1, decide when to pass build.AllowBinary here.
// See issue 3268 for mistakes to avoid.
- bp, err := buildContext.Import(path, srcDir, 0)
+ bp, err := buildContext.Import(path, srcDir, build.ImportComment)
bp.ImportPath = importPath
if gobin != "" {
bp.BinDir = gobin
}
+ if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path {
+ err = fmt.Errorf("code in directory %s expects import %q", bp.Dir, bp.ImportComment)
+ }
p.load(stk, bp, err)
if p.Error != nil && len(importPos) > 0 {
pos := importPos[0]
@@ -270,6 +276,10 @@ func loadImport(path string, srcDir string, stk *importStack, importPos []token.
p.Error.Pos = pos.String()
}
+ if perr := disallowInternal(srcDir, p, stk); perr != p {
+ return perr
+ }
+
return p
}
@@ -298,6 +308,75 @@ func reusePackage(p *Package, stk *importStack) *Package {
return p
}
+// disallowInternal checks that srcDir is allowed to import p.
+// If the import is allowed, disallowInternal returns the original package p.
+// If not, it returns a new package containing just an appropriate error.
+func disallowInternal(srcDir string, p *Package, stk *importStack) *Package {
+ // golang.org/s/go14internal:
+ // An import of a path containing the element “internal”
+ // is disallowed if the importing code is outside the tree
+ // rooted at the parent of the “internal” directory.
+ //
+ // ... For Go 1.4, we will implement the rule first for $GOROOT, but not $GOPATH.
+
+ // Only applies to $GOROOT.
+ if !p.Standard {
+ return p
+ }
+
+ // The stack includes p.ImportPath.
+ // If that's the only thing on the stack, we started
+ // with a name given on the command line, not an
+ // import. Anything listed on the command line is fine.
+ if len(*stk) == 1 {
+ return p
+ }
+
+ // Check for "internal" element: four cases depending on begin of string and/or end of string.
+ i, ok := findInternal(p.ImportPath)
+ if !ok {
+ return p
+ }
+
+ // Internal is present.
+ // Map import path back to directory corresponding to parent of internal.
+ if i > 0 {
+ i-- // rewind over slash in ".../internal"
+ }
+ parent := p.Dir[:i+len(p.Dir)-len(p.ImportPath)]
+ if hasPathPrefix(filepath.ToSlash(srcDir), filepath.ToSlash(parent)) {
+ return p
+ }
+
+ // Internal is present, and srcDir is outside parent's tree. Not allowed.
+ perr := *p
+ perr.Error = &PackageError{
+ ImportStack: stk.copy(),
+ Err: "use of internal package not allowed",
+ }
+ perr.Incomplete = true
+ return &perr
+}
+
+// findInternal looks for the final "internal" path element in the given import path.
+// If there isn't one, findInternal returns ok=false.
+// Otherwise, findInternal returns ok=true and the index of the "internal".
+func findInternal(path string) (index int, ok bool) {
+ // Four cases, depending on internal at start/end of string or not.
+ // The order matters: we must return the index of the final element,
+ // because the final one produces the most restrictive requirement
+ // on the importer.
+ switch {
+ case strings.HasSuffix(path, "/internal"):
+ return len(path) - len("internal"), true
+ case strings.Contains(path, "/internal/"):
+ return strings.LastIndex(path, "/internal/") + 1, true
+ case path == "internal", strings.HasPrefix(path, "internal/"):
+ return 0, true
+ }
+ return 0, false
+}
+
type targetDir int
const (
@@ -482,7 +561,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
// Build list of imported packages and full dependency list.
imports := make([]*Package, 0, len(p.Imports))
- deps := make(map[string]bool)
+ deps := make(map[string]*Package)
for i, path := range importPaths {
if path == "C" {
continue
@@ -502,10 +581,10 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
path = p1.ImportPath
importPaths[i] = path
}
- deps[path] = true
+ deps[path] = p1
imports = append(imports, p1)
- for _, dep := range p1.Deps {
- deps[dep] = true
+ for _, dep := range p1.deps {
+ deps[dep.ImportPath] = dep
}
if p1.Incomplete {
p.Incomplete = true
@@ -519,7 +598,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
}
sort.Strings(p.Deps)
for _, dep := range p.Deps {
- p1 := packageCache[dep]
+ p1 := deps[dep]
if p1 == nil {
panic("impossible: missing entry in package cache for " + dep + " imported by " + p.ImportPath)
}
diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash
index c62f62940..24640e272 100755
--- a/src/cmd/go/test.bash
+++ b/src/cmd/go/test.bash
@@ -105,6 +105,58 @@ cp -R testdata/local "testdata/$bad"
testlocal "$bad" 'with bad characters in path'
rm -rf "testdata/$bad"
+TEST 'internal packages in $GOROOT are respected'
+if ./testgo build -v ./testdata/testinternal >testdata/std.out 2>&1; then
+ echo "go build ./testdata/testinternal succeeded incorrectly"
+ ok=false
+elif ! grep 'use of internal package not allowed' testdata/std.out >/dev/null; then
+ echo "wrong error message for testdata/testinternal"
+ cat std.out
+ ok=false
+fi
+
+TEST 'internal packages outside $GOROOT are not respected'
+if ! ./testgo build -v ./testdata/testinternal2; then
+ echo "go build ./testdata/testinternal2 failed"
+ ok=false
+fi
+
+export GOPATH=$(pwd)/testdata/importcom
+TEST 'import comment - match'
+if ! ./testgo build ./testdata/importcom/works.go; then
+ echo 'go build ./testdata/importcom/works.go failed'
+ ok=false
+fi
+TEST 'import comment - mismatch'
+if ./testgo build ./testdata/importcom/wrongplace.go 2>testdata/err; then
+ echo 'go build ./testdata/importcom/wrongplace.go suceeded'
+ ok=false
+elif ! grep 'wrongplace expects import "my/x"' testdata/err >/dev/null; then
+ echo 'go build did not mention incorrect import:'
+ cat testdata/err
+ ok=false
+fi
+TEST 'import comment - syntax error'
+if ./testgo build ./testdata/importcom/bad.go 2>testdata/err; then
+ echo 'go build ./testdata/importcom/bad.go suceeded'
+ ok=false
+elif ! grep 'cannot parse import comment' testdata/err >/dev/null; then
+ echo 'go build did not mention syntax error:'
+ cat testdata/err
+ ok=false
+fi
+TEST 'import comment - conflict'
+if ./testgo build ./testdata/importcom/conflict.go 2>testdata/err; then
+ echo 'go build ./testdata/importcom/conflict.go suceeded'
+ ok=false
+elif ! grep 'found import comments' testdata/err >/dev/null; then
+ echo 'go build did not mention comment conflict:'
+ cat testdata/err
+ ok=false
+fi
+rm -f ./testdata/err
+unset GOPATH
+
TEST error message for syntax error in test go file says FAIL
export GOPATH=$(pwd)/testdata
if ./testgo test syntaxerror 2>testdata/err; then
@@ -527,6 +579,17 @@ TEST go get cover
unset GOPATH
rm -rf $d
+TEST go get -t "code.google.com/p/go-get-issue-8181/{a,b}"
+d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
+export GOPATH=$d
+if ./testgo get -t code.google.com/p/go-get-issue-8181/{a,b}; then
+ ./testgo list ... | grep go.tools/godoc > /dev/null || ok=false
+else
+ ok=false
+fi
+unset GOPATH
+rm -rf $d
+
TEST shadowing logic
export GOPATH=$(pwd)/testdata/shadow/root1:$(pwd)/testdata/shadow/root2
@@ -815,6 +878,33 @@ elif ! grep 'File with non-runnable example was built.' testdata/std.out > /dev/
ok=false
fi
+TEST 'go generate handles simple command'
+if ! ./testgo generate ./testdata/generate/test1.go > testdata/std.out; then
+ echo "go test ./testdata/generate/test1.go failed to run"
+ ok=false
+elif ! grep 'Success' testdata/std.out > /dev/null; then
+ echo "go test ./testdata/generate/test1.go generated wrong output"
+ ok=false
+fi
+
+TEST 'go generate handles command alias'
+if ! ./testgo generate ./testdata/generate/test2.go > testdata/std.out; then
+ echo "go test ./testdata/generate/test2.go failed to run"
+ ok=false
+elif ! grep 'Now is the time for all good men' testdata/std.out > /dev/null; then
+ echo "go test ./testdata/generate/test2.go generated wrong output"
+ ok=false
+fi
+
+TEST 'go generate variable substitution'
+if ! ./testgo generate ./testdata/generate/test3.go > testdata/std.out; then
+ echo "go test ./testdata/generate/test3.go failed to run"
+ ok=false
+elif ! grep "$GOARCH test3.go p xyzp/test3.go/123" testdata/std.out > /dev/null; then
+ echo "go test ./testdata/generate/test3.go generated wrong output"
+ ok=false
+fi
+
# clean up
if $started; then stop; fi
rm -rf testdata/bin testdata/bin1
diff --git a/src/cmd/go/testdata/generate/test1.go b/src/cmd/go/testdata/generate/test1.go
new file mode 100644
index 000000000..1f05734f0
--- /dev/null
+++ b/src/cmd/go/testdata/generate/test1.go
@@ -0,0 +1,13 @@
+// Copyright 2014 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.
+
+// Simple test for go generate.
+
+// We include a build tag that go generate should ignore.
+
+// +build ignore
+
+//go:generate echo Success
+
+package p
diff --git a/src/cmd/go/testdata/generate/test2.go b/src/cmd/go/testdata/generate/test2.go
new file mode 100644
index 000000000..ef1a3d951
--- /dev/null
+++ b/src/cmd/go/testdata/generate/test2.go
@@ -0,0 +1,10 @@
+// Copyright 2014 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.
+
+// Test that go generate handles command aliases.
+
+//go:generate -command run echo Now is the time
+//go:generate run for all good men
+
+package p
diff --git a/src/cmd/go/testdata/generate/test3.go b/src/cmd/go/testdata/generate/test3.go
new file mode 100644
index 000000000..41ffb7ea8
--- /dev/null
+++ b/src/cmd/go/testdata/generate/test3.go
@@ -0,0 +1,9 @@
+// Copyright 2014 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.
+
+// Test go generate variable substitution.
+
+//go:generate echo $GOARCH $GOFILE $GOPACKAGE xyz$GOPACKAGE/$GOFILE/123
+
+package p
diff --git a/src/cmd/go/testdata/importcom/bad.go b/src/cmd/go/testdata/importcom/bad.go
new file mode 100644
index 000000000..e104c2e99
--- /dev/null
+++ b/src/cmd/go/testdata/importcom/bad.go
@@ -0,0 +1,3 @@
+package p
+
+import "bad"
diff --git a/src/cmd/go/testdata/importcom/conflict.go b/src/cmd/go/testdata/importcom/conflict.go
new file mode 100644
index 000000000..995556c51
--- /dev/null
+++ b/src/cmd/go/testdata/importcom/conflict.go
@@ -0,0 +1,3 @@
+package p
+
+import "conflict"
diff --git a/src/cmd/go/testdata/importcom/src/bad/bad.go b/src/cmd/go/testdata/importcom/src/bad/bad.go
new file mode 100644
index 000000000..bc51fd3fd
--- /dev/null
+++ b/src/cmd/go/testdata/importcom/src/bad/bad.go
@@ -0,0 +1 @@
+package bad // import
diff --git a/src/cmd/go/testdata/importcom/src/conflict/a.go b/src/cmd/go/testdata/importcom/src/conflict/a.go
new file mode 100644
index 000000000..2d6770351
--- /dev/null
+++ b/src/cmd/go/testdata/importcom/src/conflict/a.go
@@ -0,0 +1 @@
+package conflict // import "a"
diff --git a/src/cmd/go/testdata/importcom/src/conflict/b.go b/src/cmd/go/testdata/importcom/src/conflict/b.go
new file mode 100644
index 000000000..8fcfb3c8b
--- /dev/null
+++ b/src/cmd/go/testdata/importcom/src/conflict/b.go
@@ -0,0 +1 @@
+package conflict /* import "b" */
diff --git a/src/cmd/go/testdata/importcom/src/works/x/x.go b/src/cmd/go/testdata/importcom/src/works/x/x.go
new file mode 100644
index 000000000..044c6eca8
--- /dev/null
+++ b/src/cmd/go/testdata/importcom/src/works/x/x.go
@@ -0,0 +1 @@
+package x // import "works/x"
diff --git a/src/cmd/go/testdata/importcom/src/works/x/x1.go b/src/cmd/go/testdata/importcom/src/works/x/x1.go
new file mode 100644
index 000000000..2449b29df
--- /dev/null
+++ b/src/cmd/go/testdata/importcom/src/works/x/x1.go
@@ -0,0 +1 @@
+package x // important! not an import comment
diff --git a/src/cmd/go/testdata/importcom/src/wrongplace/x.go b/src/cmd/go/testdata/importcom/src/wrongplace/x.go
new file mode 100644
index 000000000..b89849da7
--- /dev/null
+++ b/src/cmd/go/testdata/importcom/src/wrongplace/x.go
@@ -0,0 +1 @@
+package x // import "my/x"
diff --git a/src/cmd/go/testdata/importcom/works.go b/src/cmd/go/testdata/importcom/works.go
new file mode 100644
index 000000000..31b55d08a
--- /dev/null
+++ b/src/cmd/go/testdata/importcom/works.go
@@ -0,0 +1,3 @@
+package p
+
+import _ "works/x"
diff --git a/src/cmd/go/testdata/importcom/wrongplace.go b/src/cmd/go/testdata/importcom/wrongplace.go
new file mode 100644
index 000000000..e2535e01a
--- /dev/null
+++ b/src/cmd/go/testdata/importcom/wrongplace.go
@@ -0,0 +1,3 @@
+package p
+
+import "wrongplace"
diff --git a/src/cmd/go/testdata/testinternal/p.go b/src/cmd/go/testdata/testinternal/p.go
new file mode 100644
index 000000000..e3558a53b
--- /dev/null
+++ b/src/cmd/go/testdata/testinternal/p.go
@@ -0,0 +1,3 @@
+package p
+
+import _ "net/http/internal"
diff --git a/src/cmd/go/testdata/testinternal2/p.go b/src/cmd/go/testdata/testinternal2/p.go
new file mode 100644
index 000000000..c594f5c5e
--- /dev/null
+++ b/src/cmd/go/testdata/testinternal2/p.go
@@ -0,0 +1,3 @@
+package p
+
+import _ "./x/y/z/internal/w"
diff --git a/src/cmd/go/testdata/testinternal2/x/y/z/internal/w/w.go b/src/cmd/go/testdata/testinternal2/x/y/z/internal/w/w.go
new file mode 100644
index 000000000..a796c0b5f
--- /dev/null
+++ b/src/cmd/go/testdata/testinternal2/x/y/z/internal/w/w.go
@@ -0,0 +1 @@
+package w
diff --git a/src/cmd/go/vcs_test.go b/src/cmd/go/vcs_test.go
index f9bf75fef..14d681ba6 100644
--- a/src/cmd/go/vcs_test.go
+++ b/src/cmd/go/vcs_test.go
@@ -12,6 +12,9 @@ import (
// Test that RepoRootForImportPath creates the correct RepoRoot for a given importPath.
// TODO(cmang): Add tests for SVN and BZR.
func TestRepoRootForImportPath(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping test to avoid external network")
+ }
switch runtime.GOOS {
case "nacl", "android":
t.Skipf("no networking available on %s", runtime.GOOS)
@@ -106,7 +109,7 @@ func TestRepoRootForImportPath(t *testing.T) {
if want == nil {
if err == nil {
- t.Errorf("RepoRootForImport(%q): Error expected but not received")
+ t.Errorf("RepoRootForImport(%q): Error expected but not received", test.path)
}
continue
}
diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go
index 576cae522..f322a2b0a 100644
--- a/src/cmd/gofmt/gofmt.go
+++ b/src/cmd/gofmt/gofmt.go
@@ -122,7 +122,7 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
fmt.Fprintln(out, filename)
}
if *write {
- err = ioutil.WriteFile(filename, res, 0)
+ err = ioutil.WriteFile(filename, res, 0644)
if err != nil {
return err
}
@@ -186,6 +186,11 @@ func gofmtMain() {
initRewrite()
if flag.NArg() == 0 {
+ if *write {
+ fmt.Fprintln(os.Stderr, "error: cannot use -w with standard input")
+ exitCode = 2
+ return
+ }
if err := processFile("<standard input>", os.Stdin, os.Stdout, true); err != nil {
report(err)
}
@@ -277,14 +282,14 @@ func parse(fset *token.FileSet, filename string, src []byte, stdin bool) (*ast.F
// into a function body. This handles expressions too.
// Insert using a ;, not a newline, so that the line numbers
// in fsrc match the ones in src.
- fsrc := append(append([]byte("package p; func _() {"), src...), '}')
+ fsrc := append(append([]byte("package p; func _() {"), src...), '\n', '}')
file, err = parser.ParseFile(fset, filename, fsrc, parserMode)
if err == nil {
adjust := func(orig, src []byte) []byte {
// Remove the wrapping.
// Gofmt has turned the ; into a \n\n.
src = src[len("package p\n\nfunc _() {"):]
- src = src[:len(src)-len("}\n")]
+ src = src[:len(src)-len("\n}\n")]
// Gofmt has also indented the function body one level.
// Remove that indent.
src = bytes.Replace(src, []byte("\n\t"), []byte("\n"), -1)
diff --git a/src/cmd/gofmt/gofmt_test.go b/src/cmd/gofmt/gofmt_test.go
index ca44f3dcf..d1edb7bcc 100644
--- a/src/cmd/gofmt/gofmt_test.go
+++ b/src/cmd/gofmt/gofmt_test.go
@@ -6,18 +6,60 @@ package main
import (
"bytes"
+ "flag"
"io/ioutil"
+ "os"
"path/filepath"
"strings"
"testing"
+ "text/scanner"
)
-func runTest(t *testing.T, in, out, flags string) {
+var update = flag.Bool("update", false, "update .golden files")
+
+// gofmtFlags looks for a comment of the form
+//
+// //gofmt flags
+//
+// within the first maxLines lines of the given file,
+// and returns the flags string, if any. Otherwise it
+// returns the empty string.
+func gofmtFlags(filename string, maxLines int) string {
+ f, err := os.Open(filename)
+ if err != nil {
+ return "" // ignore errors - they will be found later
+ }
+ defer f.Close()
+
+ // initialize scanner
+ var s scanner.Scanner
+ s.Init(f)
+ s.Error = func(*scanner.Scanner, string) {} // ignore errors
+ s.Mode = scanner.GoTokens &^ scanner.SkipComments // want comments
+
+ // look for //gofmt comment
+ for s.Line <= maxLines {
+ switch s.Scan() {
+ case scanner.Comment:
+ const prefix = "//gofmt "
+ if t := s.TokenText(); strings.HasPrefix(t, prefix) {
+ return strings.TrimSpace(t[len(prefix):])
+ }
+ case scanner.EOF:
+ return ""
+ }
+
+ }
+
+ return ""
+}
+
+func runTest(t *testing.T, in, out string) {
// process flags
*simplifyAST = false
*rewriteRule = ""
stdin := false
- for _, flag := range strings.Split(flags, " ") {
+ for _, flag := range strings.Split(gofmtFlags(in, 20), " ") {
elts := strings.SplitN(flag, "=", 2)
name := elts[0]
value := ""
@@ -56,6 +98,17 @@ func runTest(t *testing.T, in, out, flags string) {
}
if got := buf.Bytes(); !bytes.Equal(got, expected) {
+ if *update {
+ if in != out {
+ if err := ioutil.WriteFile(out, got, 0666); err != nil {
+ t.Error(err)
+ }
+ return
+ }
+ // in == out: don't accidentally destroy input
+ t.Errorf("WARNING: -update did not rewrite input file %s", in)
+ }
+
t.Errorf("(gofmt %s) != %s (see %s.gofmt)", in, out, in)
d, err := diff(expected, got)
if err == nil {
@@ -67,53 +120,37 @@ func runTest(t *testing.T, in, out, flags string) {
}
}
-var tests = []struct {
- in, flags string
-}{
- {"gofmt.go", ""},
- {"gofmt_test.go", ""},
- {"testdata/composites.input", "-s"},
- {"testdata/slices1.input", "-s"},
- {"testdata/slices2.input", "-s"},
- {"testdata/ranges.input", "-s"},
- {"testdata/old.input", ""},
- {"testdata/rewrite1.input", "-r=Foo->Bar"},
- {"testdata/rewrite2.input", "-r=int->bool"},
- {"testdata/rewrite3.input", "-r=x->x"},
- {"testdata/rewrite4.input", "-r=(x)->x"},
- {"testdata/rewrite5.input", "-r=x+x->2*x"},
- {"testdata/rewrite6.input", "-r=fun(x)->Fun(x)"},
- {"testdata/rewrite7.input", "-r=fun(x...)->Fun(x)"},
- {"testdata/rewrite8.input", "-r=interface{}->int"},
- {"testdata/stdin*.input", "-stdin"},
- {"testdata/comments.input", ""},
- {"testdata/import.input", ""},
- {"testdata/crlf.input", ""}, // test case for issue 3961; see also TestCRLF
- {"testdata/typeswitch.input", ""}, // test case for issue 4470
- {"testdata/emptydecl.input", "-s"}, // test case for issue 7631
-}
-
+// TestRewrite processes testdata/*.input files and compares them to the
+// corresponding testdata/*.golden files. The gofmt flags used to process
+// a file must be provided via a comment of the form
+//
+// //gofmt flags
+//
+// in the processed file within the first 20 lines, if any.
func TestRewrite(t *testing.T) {
- for _, test := range tests {
- match, err := filepath.Glob(test.in)
- if err != nil {
- t.Error(err)
- continue
+ // determine input files
+ match, err := filepath.Glob("testdata/*.input")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // add larger examples
+ match = append(match, "gofmt.go", "gofmt_test.go")
+
+ for _, in := range match {
+ out := in // for files where input and output are identical
+ if strings.HasSuffix(in, ".input") {
+ out = in[:len(in)-len(".input")] + ".golden"
}
- for _, in := range match {
- out := in
- if strings.HasSuffix(in, ".input") {
- out = in[:len(in)-len(".input")] + ".golden"
- }
- runTest(t, in, out, test.flags)
- if in != out {
- // Check idempotence.
- runTest(t, out, out, test.flags)
- }
+ runTest(t, in, out)
+ if in != out {
+ // Check idempotence.
+ runTest(t, out, out)
}
}
}
+// Test case for issue 3961.
func TestCRLF(t *testing.T) {
const input = "testdata/crlf.input" // must contain CR/LF's
const golden = "testdata/crlf.golden" // must not contain any CR's
diff --git a/src/cmd/gofmt/testdata/composites.golden b/src/cmd/gofmt/testdata/composites.golden
index b2825e732..fc9c98e62 100644
--- a/src/cmd/gofmt/testdata/composites.golden
+++ b/src/cmd/gofmt/testdata/composites.golden
@@ -1,3 +1,5 @@
+//gofmt -s
+
package P
type T struct {
diff --git a/src/cmd/gofmt/testdata/composites.input b/src/cmd/gofmt/testdata/composites.input
index 7210dafc9..fc7598af9 100644
--- a/src/cmd/gofmt/testdata/composites.input
+++ b/src/cmd/gofmt/testdata/composites.input
@@ -1,3 +1,5 @@
+//gofmt -s
+
package P
type T struct {
diff --git a/src/cmd/gofmt/testdata/crlf.golden b/src/cmd/gofmt/testdata/crlf.golden
index 57679f770..193dbacc7 100644
--- a/src/cmd/gofmt/testdata/crlf.golden
+++ b/src/cmd/gofmt/testdata/crlf.golden
@@ -2,6 +2,7 @@
Source containing CR/LF line endings.
The gofmt'ed output must only have LF
line endings.
+ Test case for issue 3961.
*/
package main
diff --git a/src/cmd/gofmt/testdata/crlf.input b/src/cmd/gofmt/testdata/crlf.input
index 61a1aa0b4..ae7e14dbf 100644
--- a/src/cmd/gofmt/testdata/crlf.input
+++ b/src/cmd/gofmt/testdata/crlf.input
@@ -2,6 +2,7 @@
Source containing CR/LF line endings.
The gofmt'ed output must only have LF
line endings.
+ Test case for issue 3961.
*/
package main
diff --git a/src/cmd/gofmt/testdata/emptydecl.golden b/src/cmd/gofmt/testdata/emptydecl.golden
index 9fe62c973..33d6435e0 100644
--- a/src/cmd/gofmt/testdata/emptydecl.golden
+++ b/src/cmd/gofmt/testdata/emptydecl.golden
@@ -1,3 +1,7 @@
+//gofmt -s
+
+// Test case for issue 7631.
+
package main
// Keep this declaration
diff --git a/src/cmd/gofmt/testdata/emptydecl.input b/src/cmd/gofmt/testdata/emptydecl.input
index d1cab00ef..4948a61f0 100644
--- a/src/cmd/gofmt/testdata/emptydecl.input
+++ b/src/cmd/gofmt/testdata/emptydecl.input
@@ -1,3 +1,7 @@
+//gofmt -s
+
+// Test case for issue 7631.
+
package main
// Keep this declaration
diff --git a/src/cmd/gofmt/testdata/ranges.golden b/src/cmd/gofmt/testdata/ranges.golden
index 42168526d..506b3a035 100644
--- a/src/cmd/gofmt/testdata/ranges.golden
+++ b/src/cmd/gofmt/testdata/ranges.golden
@@ -1,3 +1,5 @@
+//gofmt -s
+
// Test cases for range simplification.
package p
diff --git a/src/cmd/gofmt/testdata/ranges.input b/src/cmd/gofmt/testdata/ranges.input
index 4b02d5175..df5f8333c 100644
--- a/src/cmd/gofmt/testdata/ranges.input
+++ b/src/cmd/gofmt/testdata/ranges.input
@@ -1,3 +1,5 @@
+//gofmt -s
+
// Test cases for range simplification.
package p
diff --git a/src/cmd/gofmt/testdata/rewrite1.golden b/src/cmd/gofmt/testdata/rewrite1.golden
index d9beb3705..3ee5373a7 100644
--- a/src/cmd/gofmt/testdata/rewrite1.golden
+++ b/src/cmd/gofmt/testdata/rewrite1.golden
@@ -1,3 +1,5 @@
+//gofmt -r=Foo->Bar
+
// 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.
diff --git a/src/cmd/gofmt/testdata/rewrite1.input b/src/cmd/gofmt/testdata/rewrite1.input
index bdb894320..a84c8f781 100644
--- a/src/cmd/gofmt/testdata/rewrite1.input
+++ b/src/cmd/gofmt/testdata/rewrite1.input
@@ -1,3 +1,5 @@
+//gofmt -r=Foo->Bar
+
// 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.
diff --git a/src/cmd/gofmt/testdata/rewrite2.golden b/src/cmd/gofmt/testdata/rewrite2.golden
index 64c67ffa6..f980e0353 100644
--- a/src/cmd/gofmt/testdata/rewrite2.golden
+++ b/src/cmd/gofmt/testdata/rewrite2.golden
@@ -1,3 +1,5 @@
+//gofmt -r=int->bool
+
// 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.
diff --git a/src/cmd/gofmt/testdata/rewrite2.input b/src/cmd/gofmt/testdata/rewrite2.input
index 21171447a..489be4e07 100644
--- a/src/cmd/gofmt/testdata/rewrite2.input
+++ b/src/cmd/gofmt/testdata/rewrite2.input
@@ -1,3 +1,5 @@
+//gofmt -r=int->bool
+
// 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.
diff --git a/src/cmd/gofmt/testdata/rewrite3.golden b/src/cmd/gofmt/testdata/rewrite3.golden
index 0d16d1601..261a220c6 100644
--- a/src/cmd/gofmt/testdata/rewrite3.golden
+++ b/src/cmd/gofmt/testdata/rewrite3.golden
@@ -1,3 +1,5 @@
+//gofmt -r=x->x
+
// 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.
diff --git a/src/cmd/gofmt/testdata/rewrite3.input b/src/cmd/gofmt/testdata/rewrite3.input
index 0d16d1601..261a220c6 100644
--- a/src/cmd/gofmt/testdata/rewrite3.input
+++ b/src/cmd/gofmt/testdata/rewrite3.input
@@ -1,3 +1,5 @@
+//gofmt -r=x->x
+
// 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.
diff --git a/src/cmd/gofmt/testdata/rewrite4.golden b/src/cmd/gofmt/testdata/rewrite4.golden
index 8dfc81a07..b05547b4b 100644
--- a/src/cmd/gofmt/testdata/rewrite4.golden
+++ b/src/cmd/gofmt/testdata/rewrite4.golden
@@ -1,3 +1,5 @@
+//gofmt -r=(x)->x
+
// Copyright 2012 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.
diff --git a/src/cmd/gofmt/testdata/rewrite4.input b/src/cmd/gofmt/testdata/rewrite4.input
index 164cc0451..081709920 100644
--- a/src/cmd/gofmt/testdata/rewrite4.input
+++ b/src/cmd/gofmt/testdata/rewrite4.input
@@ -1,3 +1,5 @@
+//gofmt -r=(x)->x
+
// Copyright 2012 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.
diff --git a/src/cmd/gofmt/testdata/rewrite5.golden b/src/cmd/gofmt/testdata/rewrite5.golden
index 5a448a63d..9beb34aee 100644
--- a/src/cmd/gofmt/testdata/rewrite5.golden
+++ b/src/cmd/gofmt/testdata/rewrite5.golden
@@ -1,3 +1,5 @@
+//gofmt -r=x+x->2*x
+
// 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.
diff --git a/src/cmd/gofmt/testdata/rewrite5.input b/src/cmd/gofmt/testdata/rewrite5.input
index 0d759e69b..d7a6122d0 100644
--- a/src/cmd/gofmt/testdata/rewrite5.input
+++ b/src/cmd/gofmt/testdata/rewrite5.input
@@ -1,3 +1,5 @@
+//gofmt -r=x+x->2*x
+
// 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.
diff --git a/src/cmd/gofmt/testdata/rewrite6.golden b/src/cmd/gofmt/testdata/rewrite6.golden
index e565dbdd9..48ec9aa0d 100644
--- a/src/cmd/gofmt/testdata/rewrite6.golden
+++ b/src/cmd/gofmt/testdata/rewrite6.golden
@@ -1,3 +1,5 @@
+//gofmt -r=fun(x)->Fun(x)
+
// Copyright 2013 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.
diff --git a/src/cmd/gofmt/testdata/rewrite6.input b/src/cmd/gofmt/testdata/rewrite6.input
index 8c088b3e8..b085a84fe 100644
--- a/src/cmd/gofmt/testdata/rewrite6.input
+++ b/src/cmd/gofmt/testdata/rewrite6.input
@@ -1,3 +1,5 @@
+//gofmt -r=fun(x)->Fun(x)
+
// Copyright 2013 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.
diff --git a/src/cmd/gofmt/testdata/rewrite7.golden b/src/cmd/gofmt/testdata/rewrite7.golden
index 29babad9f..8386a0b2a 100644
--- a/src/cmd/gofmt/testdata/rewrite7.golden
+++ b/src/cmd/gofmt/testdata/rewrite7.golden
@@ -1,3 +1,5 @@
+//gofmt -r=fun(x...)->Fun(x)
+
// Copyright 2013 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.
diff --git a/src/cmd/gofmt/testdata/rewrite7.input b/src/cmd/gofmt/testdata/rewrite7.input
index 073e2a3e6..c1984708e 100644
--- a/src/cmd/gofmt/testdata/rewrite7.input
+++ b/src/cmd/gofmt/testdata/rewrite7.input
@@ -1,3 +1,5 @@
+//gofmt -r=fun(x...)->Fun(x)
+
// Copyright 2013 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.
diff --git a/src/cmd/gofmt/testdata/rewrite8.golden b/src/cmd/gofmt/testdata/rewrite8.golden
index cfc452b03..62f0419df 100644
--- a/src/cmd/gofmt/testdata/rewrite8.golden
+++ b/src/cmd/gofmt/testdata/rewrite8.golden
@@ -1,3 +1,5 @@
+//gofmt -r=interface{}->int
+
// Copyright 2013 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.
diff --git a/src/cmd/gofmt/testdata/rewrite8.input b/src/cmd/gofmt/testdata/rewrite8.input
index 235efa91c..7964c5c75 100644
--- a/src/cmd/gofmt/testdata/rewrite8.input
+++ b/src/cmd/gofmt/testdata/rewrite8.input
@@ -1,3 +1,5 @@
+//gofmt -r=interface{}->int
+
// Copyright 2013 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.
diff --git a/src/cmd/gofmt/testdata/slices1.golden b/src/cmd/gofmt/testdata/slices1.golden
index 6633a5e00..04bc16f21 100644
--- a/src/cmd/gofmt/testdata/slices1.golden
+++ b/src/cmd/gofmt/testdata/slices1.golden
@@ -1,3 +1,5 @@
+//gofmt -s
+
// Test cases for slice expression simplification.
package p
diff --git a/src/cmd/gofmt/testdata/slices1.input b/src/cmd/gofmt/testdata/slices1.input
index 27e9cb8fe..1f25c43cc 100644
--- a/src/cmd/gofmt/testdata/slices1.input
+++ b/src/cmd/gofmt/testdata/slices1.input
@@ -1,3 +1,5 @@
+//gofmt -s
+
// Test cases for slice expression simplification.
package p
diff --git a/src/cmd/gofmt/testdata/slices2.golden b/src/cmd/gofmt/testdata/slices2.golden
index 433788e1e..ab657004e 100644
--- a/src/cmd/gofmt/testdata/slices2.golden
+++ b/src/cmd/gofmt/testdata/slices2.golden
@@ -1,3 +1,5 @@
+//gofmt -s
+
// Test cases for slice expression simplification.
// Because of a dot import, these slices must remain untouched.
package p
diff --git a/src/cmd/gofmt/testdata/slices2.input b/src/cmd/gofmt/testdata/slices2.input
index 433788e1e..ab657004e 100644
--- a/src/cmd/gofmt/testdata/slices2.input
+++ b/src/cmd/gofmt/testdata/slices2.input
@@ -1,3 +1,5 @@
+//gofmt -s
+
// Test cases for slice expression simplification.
// Because of a dot import, these slices must remain untouched.
package p
diff --git a/src/cmd/gofmt/testdata/stdin1.golden b/src/cmd/gofmt/testdata/stdin1.golden
index ff8b0b7ab..9e4dcd20f 100644
--- a/src/cmd/gofmt/testdata/stdin1.golden
+++ b/src/cmd/gofmt/testdata/stdin1.golden
@@ -1,3 +1,5 @@
+ //gofmt -stdin
+
if x {
y
}
diff --git a/src/cmd/gofmt/testdata/stdin1.golden.gofmt b/src/cmd/gofmt/testdata/stdin1.golden.gofmt
deleted file mode 100644
index 1f888877d..000000000
--- a/src/cmd/gofmt/testdata/stdin1.golden.gofmt
+++ /dev/null
@@ -1,3 +0,0 @@
- if x {
- y
-}
diff --git a/src/cmd/gofmt/testdata/stdin1.input b/src/cmd/gofmt/testdata/stdin1.input
index ff8b0b7ab..9e4dcd20f 100644
--- a/src/cmd/gofmt/testdata/stdin1.input
+++ b/src/cmd/gofmt/testdata/stdin1.input
@@ -1,3 +1,5 @@
+ //gofmt -stdin
+
if x {
y
}
diff --git a/src/cmd/gofmt/testdata/stdin1.input.gofmt b/src/cmd/gofmt/testdata/stdin1.input.gofmt
deleted file mode 100644
index 1f888877d..000000000
--- a/src/cmd/gofmt/testdata/stdin1.input.gofmt
+++ /dev/null
@@ -1,3 +0,0 @@
- if x {
- y
-}
diff --git a/src/cmd/gofmt/testdata/stdin2.golden b/src/cmd/gofmt/testdata/stdin2.golden
index 7eb1b54fe..57df35540 100644
--- a/src/cmd/gofmt/testdata/stdin2.golden
+++ b/src/cmd/gofmt/testdata/stdin2.golden
@@ -1,4 +1,4 @@
-
+//gofmt -stdin
var x int
diff --git a/src/cmd/gofmt/testdata/stdin2.golden.gofmt b/src/cmd/gofmt/testdata/stdin2.golden.gofmt
deleted file mode 100644
index 85e800300..000000000
--- a/src/cmd/gofmt/testdata/stdin2.golden.gofmt
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-var x int
-
-func f() {
- y := z
-}
-
-
diff --git a/src/cmd/gofmt/testdata/stdin2.input b/src/cmd/gofmt/testdata/stdin2.input
index 99defd2d1..69d6bdd68 100644
--- a/src/cmd/gofmt/testdata/stdin2.input
+++ b/src/cmd/gofmt/testdata/stdin2.input
@@ -1,4 +1,4 @@
-
+//gofmt -stdin
var x int
diff --git a/src/cmd/gofmt/testdata/stdin2.input.gofmt b/src/cmd/gofmt/testdata/stdin2.input.gofmt
deleted file mode 100644
index 7eb1b54fe..000000000
--- a/src/cmd/gofmt/testdata/stdin2.input.gofmt
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-var x int
-
-func f() {
- y := z
- /* this is a comment */
- // this is a comment too
-}
-
-
diff --git a/src/cmd/gofmt/testdata/stdin3.golden b/src/cmd/gofmt/testdata/stdin3.golden
index 1bf2f5a48..d6da0e417 100644
--- a/src/cmd/gofmt/testdata/stdin3.golden
+++ b/src/cmd/gofmt/testdata/stdin3.golden
@@ -1,3 +1,4 @@
+ //gofmt -stdin
/* note: no newline at end of file */
for i := 0; i < 10; i++ {
diff --git a/src/cmd/gofmt/testdata/stdin3.golden.gofmt b/src/cmd/gofmt/testdata/stdin3.golden.gofmt
deleted file mode 100644
index b4d1d4663..000000000
--- a/src/cmd/gofmt/testdata/stdin3.golden.gofmt
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
- /* note: no newline at end of file */
- for i := 0; i < 10; i++ {
- s += i
- }
- \ No newline at end of file
diff --git a/src/cmd/gofmt/testdata/stdin3.input b/src/cmd/gofmt/testdata/stdin3.input
index d963bd0d2..ab46c1063 100644
--- a/src/cmd/gofmt/testdata/stdin3.input
+++ b/src/cmd/gofmt/testdata/stdin3.input
@@ -1,3 +1,4 @@
+ //gofmt -stdin
/* note: no newline at end of file */
for i := 0; i < 10; i++ { s += i }
diff --git a/src/cmd/gofmt/testdata/stdin3.input.gofmt b/src/cmd/gofmt/testdata/stdin3.input.gofmt
deleted file mode 100644
index b4d1d4663..000000000
--- a/src/cmd/gofmt/testdata/stdin3.input.gofmt
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
- /* note: no newline at end of file */
- for i := 0; i < 10; i++ {
- s += i
- }
- \ No newline at end of file
diff --git a/src/cmd/gofmt/testdata/stdin4.golden b/src/cmd/gofmt/testdata/stdin4.golden
index 5f7343551..0c7acace5 100644
--- a/src/cmd/gofmt/testdata/stdin4.golden
+++ b/src/cmd/gofmt/testdata/stdin4.golden
@@ -1,3 +1,5 @@
+ //gofmt -stdin
+
// comment
i := 0
diff --git a/src/cmd/gofmt/testdata/stdin4.golden.gofmt b/src/cmd/gofmt/testdata/stdin4.golden.gofmt
deleted file mode 100644
index 5f7343551..000000000
--- a/src/cmd/gofmt/testdata/stdin4.golden.gofmt
+++ /dev/null
@@ -1,3 +0,0 @@
- // comment
-
- i := 0
diff --git a/src/cmd/gofmt/testdata/stdin4.input b/src/cmd/gofmt/testdata/stdin4.input
index f02a54fb1..1fc73f31e 100644
--- a/src/cmd/gofmt/testdata/stdin4.input
+++ b/src/cmd/gofmt/testdata/stdin4.input
@@ -1,3 +1,5 @@
+ //gofmt -stdin
+
// comment
i := 0
diff --git a/src/cmd/gofmt/testdata/stdin4.input.gofmt b/src/cmd/gofmt/testdata/stdin4.input.gofmt
deleted file mode 100644
index 5f7343551..000000000
--- a/src/cmd/gofmt/testdata/stdin4.input.gofmt
+++ /dev/null
@@ -1,3 +0,0 @@
- // comment
-
- i := 0
diff --git a/src/cmd/gofmt/testdata/stdin5.golden b/src/cmd/gofmt/testdata/stdin5.golden
new file mode 100644
index 000000000..31ce6b248
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin5.golden
@@ -0,0 +1,3 @@
+//gofmt -stdin
+
+i := 5 // Line comment without newline. \ No newline at end of file
diff --git a/src/cmd/gofmt/testdata/stdin5.input b/src/cmd/gofmt/testdata/stdin5.input
new file mode 100644
index 000000000..0a7c97d18
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin5.input
@@ -0,0 +1,3 @@
+//gofmt -stdin
+
+i :=5// Line comment without newline. \ No newline at end of file
diff --git a/src/cmd/nm/elf.go b/src/cmd/internal/objfile/elf.go
index 5aaa194dd..8495fa753 100644
--- a/src/cmd/nm/elf.go
+++ b/src/cmd/internal/objfile/elf.go
@@ -4,24 +4,29 @@
// Parsing of ELF executables (Linux, FreeBSD, and so on).
-package main
+package objfile
import (
"debug/elf"
"os"
)
-func elfSymbols(f *os.File) []Sym {
- p, err := elf.NewFile(f)
+type elfFile struct {
+ elf *elf.File
+}
+
+func openElf(r *os.File) (rawFile, error) {
+ f, err := elf.NewFile(r)
if err != nil {
- errorf("parsing %s: %v", f.Name(), err)
- return nil
+ return nil, err
}
+ return &elfFile{f}, nil
+}
- elfSyms, err := p.Symbols()
+func (f *elfFile) symbols() ([]Sym, error) {
+ elfSyms, err := f.elf.Symbols()
if err != nil {
- errorf("parsing %s: %v", f.Name(), err)
- return nil
+ return nil, err
}
var syms []Sym
@@ -34,10 +39,10 @@ func elfSymbols(f *os.File) []Sym {
sym.Code = 'B'
default:
i := int(s.Section)
- if i < 0 || i >= len(p.Sections) {
+ if i < 0 || i >= len(f.elf.Sections) {
break
}
- sect := p.Sections[i]
+ sect := f.elf.Sections[i]
switch sect.Flags & (elf.SHF_WRITE | elf.SHF_ALLOC | elf.SHF_EXECINSTR) {
case elf.SHF_ALLOC | elf.SHF_EXECINSTR:
sym.Code = 'T'
@@ -53,5 +58,22 @@ func elfSymbols(f *os.File) []Sym {
syms = append(syms, sym)
}
- return syms
+ return syms, nil
+}
+
+func (f *elfFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) {
+ if sect := f.elf.Section(".text"); sect != nil {
+ textStart = sect.Addr
+ }
+ if sect := f.elf.Section(".gosymtab"); sect != nil {
+ if symtab, err = sect.Data(); err != nil {
+ return 0, nil, nil, err
+ }
+ }
+ if sect := f.elf.Section(".gopclntab"); sect != nil {
+ if pclntab, err = sect.Data(); err != nil {
+ return 0, nil, nil, err
+ }
+ }
+ return textStart, symtab, pclntab, nil
}
diff --git a/src/cmd/nm/goobj.go b/src/cmd/internal/objfile/goobj.go
index b0de51db9..a4f49ebe4 100644
--- a/src/cmd/nm/goobj.go
+++ b/src/cmd/internal/objfile/goobj.go
@@ -4,7 +4,7 @@
// Parsing of Go intermediate object files and archives.
-package main
+package objfile
import (
"debug/goobj"
@@ -12,6 +12,18 @@ import (
"os"
)
+type goobjFile struct {
+ goobj *goobj.Package
+}
+
+func openGoobj(r *os.File) (rawFile, error) {
+ f, err := goobj.Parse(r, `""`)
+ if err != nil {
+ return nil, err
+ }
+ return &goobjFile{f}, nil
+}
+
func goobjName(id goobj.SymID) string {
if id.Version == 0 {
return id.Name
@@ -19,17 +31,11 @@ func goobjName(id goobj.SymID) string {
return fmt.Sprintf("%s<%d>", id.Name, id.Version)
}
-func goobjSymbols(f *os.File) []Sym {
- pkg, err := goobj.Parse(f, `""`)
- if err != nil {
- errorf("parsing %s: %v", f.Name(), err)
- return nil
- }
-
+func (f *goobjFile) symbols() ([]Sym, error) {
seen := make(map[goobj.SymID]bool)
var syms []Sym
- for _, s := range pkg.Syms {
+ for _, s := range f.goobj.Syms {
seen[s.SymID] = true
sym := Sym{Addr: uint64(s.Data.Offset), Name: goobjName(s.SymID), Size: int64(s.Size), Type: s.Type.Name, Code: '?'}
switch s.Kind {
@@ -50,7 +56,7 @@ func goobjSymbols(f *os.File) []Sym {
syms = append(syms, sym)
}
- for _, s := range pkg.Syms {
+ for _, s := range f.goobj.Syms {
for _, r := range s.Reloc {
if !seen[r.Sym] {
seen[r.Sym] = true
@@ -64,5 +70,12 @@ func goobjSymbols(f *os.File) []Sym {
}
}
- return syms
+ return syms, nil
+}
+
+// pcln does not make sense for Go object files, because each
+// symbol has its own individual pcln table, so there is no global
+// space of addresses to map.
+func (f *goobjFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) {
+ return 0, nil, nil, fmt.Errorf("pcln not available in go object file")
}
diff --git a/src/cmd/nm/macho.go b/src/cmd/internal/objfile/macho.go
index c60bde55b..f845792ff 100644
--- a/src/cmd/nm/macho.go
+++ b/src/cmd/internal/objfile/macho.go
@@ -4,36 +4,42 @@
// Parsing of Mach-O executables (OS X).
-package main
+package objfile
import (
"debug/macho"
+ "fmt"
"os"
"sort"
)
-func machoSymbols(f *os.File) []Sym {
- p, err := macho.NewFile(f)
+type machoFile struct {
+ macho *macho.File
+}
+
+func openMacho(r *os.File) (rawFile, error) {
+ f, err := macho.NewFile(r)
if err != nil {
- errorf("parsing %s: %v", f.Name(), err)
- return nil
+ return nil, err
}
+ return &machoFile{f}, nil
+}
- if p.Symtab == nil {
- errorf("%s: no symbol table", f.Name())
- return nil
+func (f *machoFile) symbols() ([]Sym, error) {
+ if f.macho.Symtab == nil {
+ return nil, fmt.Errorf("missing symbol table")
}
// Build sorted list of addresses of all symbols.
// We infer the size of a symbol by looking at where the next symbol begins.
var addrs []uint64
- for _, s := range p.Symtab.Syms {
+ for _, s := range f.macho.Symtab.Syms {
addrs = append(addrs, s.Value)
}
sort.Sort(uint64s(addrs))
var syms []Sym
- for _, s := range p.Symtab.Syms {
+ for _, s := range f.macho.Symtab.Syms {
sym := Sym{Name: s.Name, Addr: s.Value, Code: '?'}
i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value })
if i < len(addrs) {
@@ -41,8 +47,8 @@ func machoSymbols(f *os.File) []Sym {
}
if s.Sect == 0 {
sym.Code = 'U'
- } else if int(s.Sect) <= len(p.Sections) {
- sect := p.Sections[s.Sect-1]
+ } else if int(s.Sect) <= len(f.macho.Sections) {
+ sect := f.macho.Sections[s.Sect-1]
switch sect.Seg {
case "__TEXT":
sym.Code = 'R'
@@ -59,7 +65,24 @@ func machoSymbols(f *os.File) []Sym {
syms = append(syms, sym)
}
- return syms
+ return syms, nil
+}
+
+func (f *machoFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) {
+ if sect := f.macho.Section("__text"); sect != nil {
+ textStart = sect.Addr
+ }
+ if sect := f.macho.Section("__gosymtab"); sect != nil {
+ if symtab, err = sect.Data(); err != nil {
+ return 0, nil, nil, err
+ }
+ }
+ if sect := f.macho.Section("__gopclntab"); sect != nil {
+ if pclntab, err = sect.Data(); err != nil {
+ return 0, nil, nil, err
+ }
+ }
+ return textStart, symtab, pclntab, nil
}
type uint64s []uint64
diff --git a/src/cmd/internal/objfile/objfile.go b/src/cmd/internal/objfile/objfile.go
new file mode 100644
index 000000000..09fa63e60
--- /dev/null
+++ b/src/cmd/internal/objfile/objfile.go
@@ -0,0 +1,72 @@
+// Copyright 2014 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.
+
+// Package objfile implements portable access to OS-specific executable files.
+package objfile
+
+import (
+ "debug/gosym"
+ "fmt"
+ "os"
+)
+
+type rawFile interface {
+ symbols() (syms []Sym, err error)
+ pcln() (textStart uint64, symtab, pclntab []byte, err error)
+}
+
+// A File is an opened executable file.
+type File struct {
+ r *os.File
+ raw rawFile
+}
+
+// A Sym is a symbol defined in an executable file.
+type Sym struct {
+ Name string // symbol name
+ Addr uint64 // virtual address of symbol
+ Size int64 // size in bytes
+ Code rune // nm code (T for text, D for data, and so on)
+ Type string // XXX?
+}
+
+var openers = []func(*os.File) (rawFile, error){
+ openElf,
+ openGoobj,
+ openMacho,
+ openPE,
+ openPlan9,
+}
+
+// Open opens the named file.
+// The caller must call f.Close when the file is no longer needed.
+func Open(name string) (*File, error) {
+ r, err := os.Open(name)
+ if err != nil {
+ return nil, err
+ }
+ for _, try := range openers {
+ if raw, err := try(r); err == nil {
+ return &File{r, raw}, nil
+ }
+ }
+ r.Close()
+ return nil, fmt.Errorf("open %s: unrecognized object file", name)
+}
+
+func (f *File) Close() error {
+ return f.r.Close()
+}
+
+func (f *File) Symbols() ([]Sym, error) {
+ return f.raw.symbols()
+}
+
+func (f *File) PCLineTable() (*gosym.Table, error) {
+ textStart, symtab, pclntab, err := f.raw.pcln()
+ if err != nil {
+ return nil, err
+ }
+ return gosym.NewTable(symtab, gosym.NewLineTable(pclntab, textStart))
+}
diff --git a/src/cmd/internal/objfile/pe.go b/src/cmd/internal/objfile/pe.go
new file mode 100644
index 000000000..868709eaf
--- /dev/null
+++ b/src/cmd/internal/objfile/pe.go
@@ -0,0 +1,170 @@
+// Copyright 2013 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.
+
+// Parsing of PE executables (Microsoft Windows).
+
+package objfile
+
+import (
+ "debug/pe"
+ "fmt"
+ "os"
+ "sort"
+)
+
+type peFile struct {
+ pe *pe.File
+}
+
+func openPE(r *os.File) (rawFile, error) {
+ f, err := pe.NewFile(r)
+ if err != nil {
+ return nil, err
+ }
+ switch f.OptionalHeader.(type) {
+ case *pe.OptionalHeader32, *pe.OptionalHeader64:
+ // ok
+ default:
+ return nil, fmt.Errorf("unrecognized PE format")
+ }
+ return &peFile{f}, nil
+}
+
+func (f *peFile) symbols() ([]Sym, error) {
+ // Build sorted list of addresses of all symbols.
+ // We infer the size of a symbol by looking at where the next symbol begins.
+ var addrs []uint64
+
+ var imageBase uint64
+ switch oh := f.pe.OptionalHeader.(type) {
+ case *pe.OptionalHeader32:
+ imageBase = uint64(oh.ImageBase)
+ case *pe.OptionalHeader64:
+ imageBase = oh.ImageBase
+ }
+
+ var syms []Sym
+ for _, s := range f.pe.Symbols {
+ const (
+ N_UNDEF = 0 // An undefined (extern) symbol
+ N_ABS = -1 // An absolute symbol (e_value is a constant, not an address)
+ N_DEBUG = -2 // A debugging symbol
+ )
+ sym := Sym{Name: s.Name, Addr: uint64(s.Value), Code: '?'}
+ switch s.SectionNumber {
+ case N_UNDEF:
+ sym.Code = 'U'
+ case N_ABS:
+ sym.Code = 'C'
+ case N_DEBUG:
+ sym.Code = '?'
+ default:
+ if s.SectionNumber < 0 || len(f.pe.Sections) < int(s.SectionNumber) {
+ return nil, fmt.Errorf("invalid section number in symbol table")
+ }
+ sect := f.pe.Sections[s.SectionNumber-1]
+ const (
+ text = 0x20
+ data = 0x40
+ bss = 0x80
+ permX = 0x20000000
+ permR = 0x40000000
+ permW = 0x80000000
+ )
+ ch := sect.Characteristics
+ switch {
+ case ch&text != 0:
+ sym.Code = 'T'
+ case ch&data != 0:
+ if ch&permW == 0 {
+ sym.Code = 'R'
+ } else {
+ sym.Code = 'D'
+ }
+ case ch&bss != 0:
+ sym.Code = 'B'
+ }
+ sym.Addr += imageBase + uint64(sect.VirtualAddress)
+ }
+ syms = append(syms, sym)
+ addrs = append(addrs, sym.Addr)
+ }
+
+ sort.Sort(uint64s(addrs))
+ for i := range syms {
+ j := sort.Search(len(addrs), func(x int) bool { return addrs[x] > syms[i].Addr })
+ if j < len(addrs) {
+ syms[i].Size = int64(addrs[j] - syms[i].Addr)
+ }
+ }
+
+ return syms, nil
+}
+
+func (f *peFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) {
+ var imageBase uint64
+ switch oh := f.pe.OptionalHeader.(type) {
+ case *pe.OptionalHeader32:
+ imageBase = uint64(oh.ImageBase)
+ case *pe.OptionalHeader64:
+ imageBase = oh.ImageBase
+ default:
+ return 0, nil, nil, fmt.Errorf("pe file format not recognized")
+ }
+ if sect := f.pe.Section(".text"); sect != nil {
+ textStart = imageBase + uint64(sect.VirtualAddress)
+ }
+ if pclntab, err = loadPETable(f.pe, "runtime.pclntab", "runtime.epclntab"); err != nil {
+ // We didn't find the symbols, so look for the names used in 1.3 and earlier.
+ // TODO: Remove code looking for the old symbols when we no longer care about 1.3.
+ var err2 error
+ if pclntab, err2 = loadPETable(f.pe, "pclntab", "epclntab"); err2 != nil {
+ return 0, nil, nil, err
+ }
+ }
+ if symtab, err = loadPETable(f.pe, "runtime.symtab", "runtime.esymtab"); err != nil {
+ // Same as above.
+ var err2 error
+ if symtab, err2 = loadPETable(f.pe, "symtab", "esymtab"); err2 != nil {
+ return 0, nil, nil, err
+ }
+ }
+ return textStart, symtab, pclntab, nil
+}
+
+func findPESymbol(f *pe.File, name string) (*pe.Symbol, error) {
+ for _, s := range f.Symbols {
+ if s.Name != name {
+ continue
+ }
+ if s.SectionNumber <= 0 {
+ return nil, fmt.Errorf("symbol %s: invalid section number %d", name, s.SectionNumber)
+ }
+ if len(f.Sections) < int(s.SectionNumber) {
+ return nil, fmt.Errorf("symbol %s: section number %d is larger than max %d", name, s.SectionNumber, len(f.Sections))
+ }
+ return s, nil
+ }
+ return nil, fmt.Errorf("no %s symbol found", name)
+}
+
+func loadPETable(f *pe.File, sname, ename string) ([]byte, error) {
+ ssym, err := findPESymbol(f, sname)
+ if err != nil {
+ return nil, err
+ }
+ esym, err := findPESymbol(f, ename)
+ if err != nil {
+ return nil, err
+ }
+ if ssym.SectionNumber != esym.SectionNumber {
+ return nil, fmt.Errorf("%s and %s symbols must be in the same section", sname, ename)
+ }
+ sect := f.Sections[ssym.SectionNumber-1]
+ data, err := sect.Data()
+ if err != nil {
+ return nil, err
+ }
+ return data[ssym.Value:esym.Value], nil
+}
diff --git a/src/cmd/internal/objfile/plan9obj.go b/src/cmd/internal/objfile/plan9obj.go
new file mode 100644
index 000000000..80744f82a
--- /dev/null
+++ b/src/cmd/internal/objfile/plan9obj.go
@@ -0,0 +1,124 @@
+// Copyright 2014 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.
+
+// Parsing of Plan 9 a.out executables.
+
+package objfile
+
+import (
+ "debug/plan9obj"
+ "fmt"
+ "os"
+ "sort"
+)
+
+var validSymType = map[rune]bool{
+ 'T': true,
+ 't': true,
+ 'D': true,
+ 'd': true,
+ 'B': true,
+ 'b': true,
+}
+
+type plan9File struct {
+ plan9 *plan9obj.File
+}
+
+func openPlan9(r *os.File) (rawFile, error) {
+ f, err := plan9obj.NewFile(r)
+ if err != nil {
+ return nil, err
+ }
+ return &plan9File{f}, nil
+}
+
+func (f *plan9File) symbols() ([]Sym, error) {
+ plan9Syms, err := f.plan9.Symbols()
+ if err != nil {
+ return nil, err
+ }
+
+ // Build sorted list of addresses of all symbols.
+ // We infer the size of a symbol by looking at where the next symbol begins.
+ var addrs []uint64
+ for _, s := range plan9Syms {
+ if !validSymType[s.Type] {
+ continue
+ }
+ addrs = append(addrs, s.Value)
+ }
+ sort.Sort(uint64s(addrs))
+
+ var syms []Sym
+
+ for _, s := range plan9Syms {
+ if !validSymType[s.Type] {
+ continue
+ }
+ sym := Sym{Addr: s.Value, Name: s.Name, Code: rune(s.Type)}
+ i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value })
+ if i < len(addrs) {
+ sym.Size = int64(addrs[i] - s.Value)
+ }
+ syms = append(syms, sym)
+ }
+
+ return syms, nil
+}
+
+func (f *plan9File) pcln() (textStart uint64, symtab, pclntab []byte, err error) {
+ textStart = f.plan9.LoadAddress + f.plan9.HdrSize
+ if pclntab, err = loadPlan9Table(f.plan9, "runtime.pclntab", "runtime.epclntab"); err != nil {
+ // We didn't find the symbols, so look for the names used in 1.3 and earlier.
+ // TODO: Remove code looking for the old symbols when we no longer care about 1.3.
+ var err2 error
+ if pclntab, err2 = loadPlan9Table(f.plan9, "pclntab", "epclntab"); err2 != nil {
+ return 0, nil, nil, err
+ }
+ }
+ if symtab, err = loadPlan9Table(f.plan9, "runtime.symtab", "runtime.esymtab"); err != nil {
+ // Same as above.
+ var err2 error
+ if symtab, err2 = loadPlan9Table(f.plan9, "symtab", "esymtab"); err2 != nil {
+ return 0, nil, nil, err
+ }
+ }
+ return textStart, symtab, pclntab, nil
+}
+
+func findPlan9Symbol(f *plan9obj.File, name string) (*plan9obj.Sym, error) {
+ syms, err := f.Symbols()
+ if err != nil {
+ return nil, err
+ }
+ for _, s := range syms {
+ if s.Name != name {
+ continue
+ }
+ return &s, nil
+ }
+ return nil, fmt.Errorf("no %s symbol found", name)
+}
+
+func loadPlan9Table(f *plan9obj.File, sname, ename string) ([]byte, error) {
+ ssym, err := findPlan9Symbol(f, sname)
+ if err != nil {
+ return nil, err
+ }
+ esym, err := findPlan9Symbol(f, ename)
+ if err != nil {
+ return nil, err
+ }
+ sect := f.Section("text")
+ if sect == nil {
+ return nil, err
+ }
+ data, err := sect.Data()
+ if err != nil {
+ return nil, err
+ }
+ textStart := f.LoadAddress + f.HdrSize
+ return data[ssym.Value-textStart : esym.Value-textStart], nil
+}
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c
index 702f559a8..7bf18f081 100644
--- a/src/cmd/ld/data.c
+++ b/src/cmd/ld/data.c
@@ -145,7 +145,7 @@ relocsym(LSym *s)
diag("%s: invalid relocation %d+%d not in [%d,%d)", s->name, off, siz, 0, s->np);
continue;
}
- if(r->sym != S && (r->sym->type & SMASK == 0 || r->sym->type & SMASK == SXREF)) {
+ if(r->sym != S && ((r->sym->type & (SMASK | SHIDDEN)) == 0 || (r->sym->type & SMASK) == SXREF)) {
diag("%s: not defined", r->sym->name);
continue;
}
@@ -281,9 +281,13 @@ relocsym(LSym *s)
if(thechar == '6')
o = 0;
} else if(HEADTYPE == Hdarwin) {
- if(rs->type != SHOSTOBJ)
- o += symaddr(rs) - rs->sect->vaddr;
- o -= r->off; // WTF?
+ if(r->type == R_CALL) {
+ if(rs->type != SHOSTOBJ)
+ o += symaddr(rs) - rs->sect->vaddr;
+ o -= r->off; // relative to section offset, not symbol
+ } else {
+ o += r->siz;
+ }
} else {
diag("unhandled pcrel relocation for %s", headstring);
}
@@ -425,10 +429,10 @@ dynreloc(void)
}
static void
-blk(LSym *start, int32 addr, int32 size)
+blk(LSym *start, int64 addr, int64 size)
{
LSym *sym;
- int32 eaddr;
+ int64 eaddr;
uchar *p, *ep;
for(sym = start; sym != nil; sym = sym->next)
@@ -469,10 +473,10 @@ blk(LSym *start, int32 addr, int32 size)
}
void
-codeblk(int32 addr, int32 size)
+codeblk(int64 addr, int64 size)
{
LSym *sym;
- int32 eaddr, n;
+ int64 eaddr, n;
uchar *q;
if(debug['a'])
@@ -529,10 +533,10 @@ codeblk(int32 addr, int32 size)
}
void
-datblk(int32 addr, int32 size)
+datblk(int64 addr, int64 size)
{
LSym *sym;
- int32 i, eaddr;
+ int64 i, eaddr;
uchar *p, *ep;
char *typ, *rsname;
Reloc *r;
@@ -985,8 +989,8 @@ dodata(void)
sect->align = maxalign(s, SINITARR-1);
datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
- linklookup(ctxt, "noptrdata", 0)->sect = sect;
- linklookup(ctxt, "enoptrdata", 0)->sect = sect;
+ linklookup(ctxt, "runtime.noptrdata", 0)->sect = sect;
+ linklookup(ctxt, "runtime.enoptrdata", 0)->sect = sect;
for(; s != nil && s->type < SINITARR; s = s->next) {
datsize = aligndatsize(datsize, s);
s->sect = sect;
@@ -1016,9 +1020,9 @@ dodata(void)
sect->align = maxalign(s, SBSS-1);
datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
- linklookup(ctxt, "data", 0)->sect = sect;
- linklookup(ctxt, "edata", 0)->sect = sect;
- gcdata = linklookup(ctxt, "gcdata", 0);
+ linklookup(ctxt, "runtime.data", 0)->sect = sect;
+ linklookup(ctxt, "runtime.edata", 0)->sect = sect;
+ gcdata = linklookup(ctxt, "runtime.gcdata", 0);
proggeninit(&gen, gcdata);
for(; s != nil && s->type < SBSS; s = s->next) {
if(s->type == SINITARR) {
@@ -1040,9 +1044,9 @@ dodata(void)
sect->align = maxalign(s, SNOPTRBSS-1);
datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
- linklookup(ctxt, "bss", 0)->sect = sect;
- linklookup(ctxt, "ebss", 0)->sect = sect;
- gcbss = linklookup(ctxt, "gcbss", 0);
+ linklookup(ctxt, "runtime.bss", 0)->sect = sect;
+ linklookup(ctxt, "runtime.ebss", 0)->sect = sect;
+ gcbss = linklookup(ctxt, "runtime.gcbss", 0);
proggeninit(&gen, gcbss);
for(; s != nil && s->type < SNOPTRBSS; s = s->next) {
s->sect = sect;
@@ -1059,8 +1063,8 @@ dodata(void)
sect->align = maxalign(s, SNOPTRBSS);
datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
- linklookup(ctxt, "noptrbss", 0)->sect = sect;
- linklookup(ctxt, "enoptrbss", 0)->sect = sect;
+ linklookup(ctxt, "runtime.noptrbss", 0)->sect = sect;
+ linklookup(ctxt, "runtime.enoptrbss", 0)->sect = sect;
for(; s != nil && s->type == SNOPTRBSS; s = s->next) {
datsize = aligndatsize(datsize, s);
s->sect = sect;
@@ -1068,7 +1072,7 @@ dodata(void)
growdatsize(&datsize, s);
}
sect->len = datsize - sect->vaddr;
- linklookup(ctxt, "end", 0)->sect = sect;
+ linklookup(ctxt, "runtime.end", 0)->sect = sect;
// 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
if(datsize != (uint32)datsize) {
@@ -1139,8 +1143,8 @@ dodata(void)
sect->align = maxalign(s, STYPELINK-1);
datsize = rnd(datsize, sect->align);
sect->vaddr = 0;
- linklookup(ctxt, "rodata", 0)->sect = sect;
- linklookup(ctxt, "erodata", 0)->sect = sect;
+ linklookup(ctxt, "runtime.rodata", 0)->sect = sect;
+ linklookup(ctxt, "runtime.erodata", 0)->sect = sect;
for(; s != nil && s->type < STYPELINK; s = s->next) {
datsize = aligndatsize(datsize, s);
s->sect = sect;
@@ -1155,8 +1159,8 @@ dodata(void)
sect->align = maxalign(s, STYPELINK);
datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
- linklookup(ctxt, "typelink", 0)->sect = sect;
- linklookup(ctxt, "etypelink", 0)->sect = sect;
+ linklookup(ctxt, "runtime.typelink", 0)->sect = sect;
+ linklookup(ctxt, "runtime.etypelink", 0)->sect = sect;
for(; s != nil && s->type == STYPELINK; s = s->next) {
datsize = aligndatsize(datsize, s);
s->sect = sect;
@@ -1171,8 +1175,8 @@ dodata(void)
sect->align = maxalign(s, SPCLNTAB-1);
datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
- linklookup(ctxt, "symtab", 0)->sect = sect;
- linklookup(ctxt, "esymtab", 0)->sect = sect;
+ linklookup(ctxt, "runtime.symtab", 0)->sect = sect;
+ linklookup(ctxt, "runtime.esymtab", 0)->sect = sect;
for(; s != nil && s->type < SPCLNTAB; s = s->next) {
datsize = aligndatsize(datsize, s);
s->sect = sect;
@@ -1187,8 +1191,8 @@ dodata(void)
sect->align = maxalign(s, SELFROSECT-1);
datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
- linklookup(ctxt, "pclntab", 0)->sect = sect;
- linklookup(ctxt, "epclntab", 0)->sect = sect;
+ linklookup(ctxt, "runtime.pclntab", 0)->sect = sect;
+ linklookup(ctxt, "runtime.epclntab", 0)->sect = sect;
for(; s != nil && s->type < SELFROSECT; s = s->next) {
datsize = aligndatsize(datsize, s);
s->sect = sect;
@@ -1241,8 +1245,8 @@ textaddress(void)
// and then letting threads copy down, but probably not worth it.
sect = segtext.sect;
sect->align = funcalign;
- linklookup(ctxt, "text", 0)->sect = sect;
- linklookup(ctxt, "etext", 0)->sect = sect;
+ linklookup(ctxt, "runtime.text", 0)->sect = sect;
+ linklookup(ctxt, "runtime.etext", 0)->sect = sect;
va = INITTEXT;
sect->vaddr = va;
for(sym = ctxt->textp; sym != nil; sym = sym->next) {
@@ -1353,32 +1357,32 @@ address(void)
sub->value += sym->value;
}
- xdefine("text", STEXT, text->vaddr);
- xdefine("etext", STEXT, text->vaddr + text->len);
- xdefine("rodata", SRODATA, rodata->vaddr);
- xdefine("erodata", SRODATA, rodata->vaddr + rodata->len);
- xdefine("typelink", SRODATA, typelink->vaddr);
- xdefine("etypelink", SRODATA, typelink->vaddr + typelink->len);
-
- sym = linklookup(ctxt, "gcdata", 0);
- xdefine("egcdata", SRODATA, symaddr(sym) + sym->size);
- linklookup(ctxt, "egcdata", 0)->sect = sym->sect;
-
- sym = linklookup(ctxt, "gcbss", 0);
- xdefine("egcbss", SRODATA, symaddr(sym) + sym->size);
- linklookup(ctxt, "egcbss", 0)->sect = sym->sect;
-
- xdefine("symtab", SRODATA, symtab->vaddr);
- xdefine("esymtab", SRODATA, symtab->vaddr + symtab->len);
- xdefine("pclntab", SRODATA, pclntab->vaddr);
- xdefine("epclntab", SRODATA, pclntab->vaddr + pclntab->len);
- xdefine("noptrdata", SNOPTRDATA, noptr->vaddr);
- xdefine("enoptrdata", SNOPTRDATA, noptr->vaddr + noptr->len);
- xdefine("bss", SBSS, bss->vaddr);
- xdefine("ebss", SBSS, bss->vaddr + bss->len);
- xdefine("data", SDATA, data->vaddr);
- xdefine("edata", SDATA, data->vaddr + data->len);
- xdefine("noptrbss", SNOPTRBSS, noptrbss->vaddr);
- xdefine("enoptrbss", SNOPTRBSS, noptrbss->vaddr + noptrbss->len);
- xdefine("end", SBSS, segdata.vaddr + segdata.len);
+ xdefine("runtime.text", STEXT, text->vaddr);
+ xdefine("runtime.etext", STEXT, text->vaddr + text->len);
+ xdefine("runtime.rodata", SRODATA, rodata->vaddr);
+ xdefine("runtime.erodata", SRODATA, rodata->vaddr + rodata->len);
+ xdefine("runtime.typelink", SRODATA, typelink->vaddr);
+ xdefine("runtime.etypelink", SRODATA, typelink->vaddr + typelink->len);
+
+ sym = linklookup(ctxt, "runtime.gcdata", 0);
+ xdefine("runtime.egcdata", SRODATA, symaddr(sym) + sym->size);
+ linklookup(ctxt, "runtime.egcdata", 0)->sect = sym->sect;
+
+ sym = linklookup(ctxt, "runtime.gcbss", 0);
+ xdefine("runtime.egcbss", SRODATA, symaddr(sym) + sym->size);
+ linklookup(ctxt, "runtime.egcbss", 0)->sect = sym->sect;
+
+ xdefine("runtime.symtab", SRODATA, symtab->vaddr);
+ xdefine("runtime.esymtab", SRODATA, symtab->vaddr + symtab->len);
+ xdefine("runtime.pclntab", SRODATA, pclntab->vaddr);
+ xdefine("runtime.epclntab", SRODATA, pclntab->vaddr + pclntab->len);
+ xdefine("runtime.noptrdata", SNOPTRDATA, noptr->vaddr);
+ xdefine("runtime.enoptrdata", SNOPTRDATA, noptr->vaddr + noptr->len);
+ xdefine("runtime.bss", SBSS, bss->vaddr);
+ xdefine("runtime.ebss", SBSS, bss->vaddr + bss->len);
+ xdefine("runtime.data", SDATA, data->vaddr);
+ xdefine("runtime.edata", SDATA, data->vaddr + data->len);
+ xdefine("runtime.noptrbss", SNOPTRBSS, noptrbss->vaddr);
+ xdefine("runtime.enoptrbss", SNOPTRBSS, noptrbss->vaddr + noptrbss->len);
+ xdefine("runtime.end", SBSS, segdata.vaddr + segdata.len);
}
diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c
index 5db41f9a7..7b997464d 100644
--- a/src/cmd/ld/lib.c
+++ b/src/cmd/ld/lib.c
@@ -1351,10 +1351,10 @@ genasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*))
// These symbols won't show up in the first loop below because we
// skip STEXT symbols. Normal STEXT symbols are emitted by walking textp.
- s = linklookup(ctxt, "text", 0);
+ s = linklookup(ctxt, "runtime.text", 0);
if(s->type == STEXT)
put(s, s->name, 'T', s->value, s->size, s->version, 0);
- s = linklookup(ctxt, "etext", 0);
+ s = linklookup(ctxt, "runtime.etext", 0);
if(s->type == STEXT)
put(s, s->name, 'T', s->value, s->size, s->version, 0);
@@ -1556,3 +1556,56 @@ diag(char *fmt, ...)
errorexit();
}
}
+
+void
+checkgo(void)
+{
+ LSym *s;
+ Reloc *r;
+ int i;
+ int changed;
+
+ if(!debug['C'])
+ return;
+
+ // TODO(rsc,khr): Eventually we want to get to no Go-called C functions at all,
+ // which would simplify this logic quite a bit.
+
+ // Mark every Go-called C function with cfunc=2, recursively.
+ do {
+ changed = 0;
+ for(s = ctxt->textp; s != nil; s = s->next) {
+ if(s->cfunc == 0 || (s->cfunc == 2 && s->nosplit)) {
+ for(i=0; i<s->nr; i++) {
+ r = &s->r[i];
+ if(r->sym == nil)
+ continue;
+ if((r->type == R_CALL || r->type == R_CALLARM) && r->sym->type == STEXT) {
+ if(r->sym->cfunc == 1) {
+ changed = 1;
+ r->sym->cfunc = 2;
+ }
+ }
+ }
+ }
+ }
+ }while(changed);
+
+ // Complain about Go-called C functions that can split the stack
+ // (that can be preempted for garbage collection or trigger a stack copy).
+ for(s = ctxt->textp; s != nil; s = s->next) {
+ if(s->cfunc == 0 || (s->cfunc == 2 && s->nosplit)) {
+ for(i=0; i<s->nr; i++) {
+ r = &s->r[i];
+ if(r->sym == nil)
+ continue;
+ if((r->type == R_CALL || r->type == R_CALLARM) && r->sym->type == STEXT) {
+ if(s->cfunc == 0 && r->sym->cfunc == 2 && !r->sym->nosplit)
+ print("Go %s calls C %s\n", s->name, r->sym->name);
+ else if(s->cfunc == 2 && s->nosplit && !r->sym->nosplit)
+ print("Go calls C %s calls %s\n", s->name, r->sym->name);
+ }
+ }
+ }
+ }
+}
diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h
index 4094dfa6b..067ffa0bc 100644
--- a/src/cmd/ld/lib.h
+++ b/src/cmd/ld/lib.h
@@ -183,12 +183,13 @@ uint16 be16(uchar *b);
uint32 be32(uchar *b);
uint64 be64(uchar *b);
void callgraph(void);
+void checkgo(void);
void cflush(void);
-void codeblk(int32 addr, int32 size);
+void codeblk(int64 addr, int64 size);
vlong cpos(void);
void cseek(vlong p);
void cwrite(void *buf, int n);
-void datblk(int32 addr, int32 size);
+void datblk(int64 addr, int64 size);
int datcmp(LSym *s1, LSym *s2);
vlong datoff(vlong addr);
void deadcode(void);
diff --git a/src/cmd/ld/pcln.c b/src/cmd/ld/pcln.c
index 4c2ffa78e..3cd9e65da 100644
--- a/src/cmd/ld/pcln.c
+++ b/src/cmd/ld/pcln.c
@@ -90,7 +90,7 @@ renumberfiles(Link *ctxt, LSym **files, int nfiles, Pcdata *d)
}
dv = val - newval;
newval = val;
- v = (uint32)(dv<<1) ^ (uint32)(int32)(dv>>31);
+ v = ((uint32)dv<<1) ^ (uint32)(int32)(dv>>31);
addvarint(&out, v);
// pc delta
@@ -119,7 +119,7 @@ pclntab(void)
static Pcln zpcln;
funcdata_bytes = 0;
- ftab = linklookup(ctxt, "pclntab", 0);
+ ftab = linklookup(ctxt, "runtime.pclntab", 0);
ftab->type = SPCLNTAB;
ftab->reachable = 1;
diff --git a/src/cmd/ld/pobj.c b/src/cmd/ld/pobj.c
index d78dacd36..54c5ef247 100644
--- a/src/cmd/ld/pobj.c
+++ b/src/cmd/ld/pobj.c
@@ -71,6 +71,7 @@ main(int argc, char *argv[])
if(thechar == '6')
flagcount("8", "assume 64-bit addresses", &debug['8']);
flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo);
+ flagcount("C", "check Go calls to C code", &debug['C']);
flagint64("D", "addr: data address", &INITDAT);
flagstr("E", "sym: entry symbol", &INITENTRY);
if(thechar == '5')
@@ -162,6 +163,7 @@ main(int argc, char *argv[])
mark(linklookup(ctxt, "runtime.read_tls_fallback", 0));
}
+ checkgo();
deadcode();
callgraph();
paramspace = "SP"; /* (FP) now (SP) on output */
diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c
index 8149a6716..c3a72c3cf 100644
--- a/src/cmd/ld/symtab.c
+++ b/src/cmd/ld/symtab.c
@@ -347,36 +347,36 @@ symtab(void)
// Define these so that they'll get put into the symbol table.
// data.c:/^address will provide the actual values.
- xdefine("text", STEXT, 0);
- xdefine("etext", STEXT, 0);
- xdefine("typelink", SRODATA, 0);
- xdefine("etypelink", SRODATA, 0);
- xdefine("rodata", SRODATA, 0);
- xdefine("erodata", SRODATA, 0);
- xdefine("noptrdata", SNOPTRDATA, 0);
- xdefine("enoptrdata", SNOPTRDATA, 0);
- xdefine("data", SDATA, 0);
- xdefine("edata", SDATA, 0);
- xdefine("bss", SBSS, 0);
- xdefine("ebss", SBSS, 0);
- xdefine("noptrbss", SNOPTRBSS, 0);
- xdefine("enoptrbss", SNOPTRBSS, 0);
- xdefine("end", SBSS, 0);
- xdefine("epclntab", SRODATA, 0);
- xdefine("esymtab", SRODATA, 0);
+ xdefine("runtime.text", STEXT, 0);
+ xdefine("runtime.etext", STEXT, 0);
+ xdefine("runtime.typelink", SRODATA, 0);
+ xdefine("runtime.etypelink", SRODATA, 0);
+ xdefine("runtime.rodata", SRODATA, 0);
+ xdefine("runtime.erodata", SRODATA, 0);
+ xdefine("runtime.noptrdata", SNOPTRDATA, 0);
+ xdefine("runtime.enoptrdata", SNOPTRDATA, 0);
+ xdefine("runtime.data", SDATA, 0);
+ xdefine("runtime.edata", SDATA, 0);
+ xdefine("runtime.bss", SBSS, 0);
+ xdefine("runtime.ebss", SBSS, 0);
+ xdefine("runtime.noptrbss", SNOPTRBSS, 0);
+ xdefine("runtime.enoptrbss", SNOPTRBSS, 0);
+ xdefine("runtime.end", SBSS, 0);
+ xdefine("runtime.epclntab", SRODATA, 0);
+ xdefine("runtime.esymtab", SRODATA, 0);
// garbage collection symbols
- s = linklookup(ctxt, "gcdata", 0);
+ s = linklookup(ctxt, "runtime.gcdata", 0);
s->type = SRODATA;
s->size = 0;
s->reachable = 1;
- xdefine("egcdata", SRODATA, 0);
+ xdefine("runtime.egcdata", SRODATA, 0);
- s = linklookup(ctxt, "gcbss", 0);
+ s = linklookup(ctxt, "runtime.gcbss", 0);
s->type = SRODATA;
s->size = 0;
s->reachable = 1;
- xdefine("egcbss", SRODATA, 0);
+ xdefine("runtime.egcbss", SRODATA, 0);
// pseudo-symbols to mark locations of type, string, and go string data.
s = linklookup(ctxt, "type.*", 0);
@@ -397,9 +397,9 @@ symtab(void)
s->reachable = 1;
symgofunc = s;
- symtypelink = linklookup(ctxt, "typelink", 0);
+ symtypelink = linklookup(ctxt, "runtime.typelink", 0);
- symt = linklookup(ctxt, "symtab", 0);
+ symt = linklookup(ctxt, "runtime.symtab", 0);
symt->type = SSYMTAB;
symt->size = 0;
symt->reachable = 1;
diff --git a/src/cmd/link/auto.go b/src/cmd/link/auto.go
index 8f0c39f8c..f9228e8ca 100644
--- a/src/cmd/link/auto.go
+++ b/src/cmd/link/auto.go
@@ -18,26 +18,26 @@ import (
// linkerDefined lists the symbols supplied by other parts of the linker
// (runtime.go and layout.go).
var linkerDefined = map[string]bool{
- "bss": true,
- "data": true,
- "ebss": true,
- "edata": true,
- "efunctab": true,
- "end": true,
- "enoptrbss": true,
- "enoptrdata": true,
- "erodata": true,
- "etext": true,
- "etypelink": true,
- "functab": true,
- "gcbss": true,
- "gcdata": true,
- "noptrbss": true,
- "noptrdata": true,
- "pclntab": true,
- "rodata": true,
- "text": true,
- "typelink": true,
+ "runtime.bss": true,
+ "runtime.data": true,
+ "runtime.ebss": true,
+ "runtime.edata": true,
+ "runtime.efunctab": true,
+ "runtime.end": true,
+ "runtime.enoptrbss": true,
+ "runtime.enoptrdata": true,
+ "runtime.erodata": true,
+ "runtime.etext": true,
+ "runtime.etypelink": true,
+ "runtime.functab": true,
+ "runtime.gcbss": true,
+ "runtime.gcdata": true,
+ "runtime.noptrbss": true,
+ "runtime.noptrdata": true,
+ "runtime.pclntab": true,
+ "runtime.rodata": true,
+ "runtime.text": true,
+ "runtime.typelink": true,
}
// isAuto reports whether sym is an automatically-generated data or constant symbol.
diff --git a/src/cmd/link/layout.go b/src/cmd/link/layout.go
index 647702244..149ebced0 100644
--- a/src/cmd/link/layout.go
+++ b/src/cmd/link/layout.go
@@ -172,9 +172,9 @@ func (p *Prog) layout() {
start = sect.VirtAddr
end = sect.VirtAddr + sect.Size
}
- p.defineConst(name, start)
- p.defineConst("e"+name, end)
+ p.defineConst("runtime."+name, start)
+ p.defineConst("runtime.e"+name, end)
progEnd = end
}
- p.defineConst("end", progEnd)
+ p.defineConst("runtime.end", progEnd)
}
diff --git a/src/cmd/link/pclntab.go b/src/cmd/link/pclntab.go
index b0b19ad53..232d586bf 100644
--- a/src/cmd/link/pclntab.go
+++ b/src/cmd/link/pclntab.go
@@ -183,7 +183,7 @@ func (p *Prog) pclntab() {
pclntab := &Sym{
Sym: &goobj.Sym{
- SymID: goobj.SymID{Name: "pclntab"},
+ SymID: goobj.SymID{Name: "runtime.pclntab"},
Kind: goobj.SPCLNTAB,
Size: buf.Size(),
Reloc: buf.Reloc(),
@@ -437,7 +437,7 @@ func (it *PCIter) Next() {
return
}
it.start = false
- sv := int32(uv)>>1 ^ int32(uv)<<31>>31
+ sv := int32(uv>>1) ^ int32(uv<<31)>>31
it.Value += sv
// pc delta
diff --git a/src/cmd/link/pclntab_test.go b/src/cmd/link/pclntab_test.go
index 5696a0978..19953f579 100644
--- a/src/cmd/link/pclntab_test.go
+++ b/src/cmd/link/pclntab_test.go
@@ -141,7 +141,7 @@ func TestPclntab(t *testing.T) {
// It returns a symbol reader for pclntab, the offset of the function information
// within that symbol, and the args and frame values read out of the information.
func findFunc(t *testing.T, p *Prog, name string) (r *SymReader, off, args, frame int, ok bool) {
- tabsym := p.Syms[goobj.SymID{Name: "pclntab"}]
+ tabsym := p.Syms[goobj.SymID{Name: "runtime.pclntab"}]
if tabsym == nil {
t.Errorf("pclntab is missing in binary")
return
@@ -276,6 +276,12 @@ func checkPCData(t *testing.T, r *SymReader, name string, off, pc, pnum, val int
// readPCData reads the PCData table offset off
// to obtain and return the value associated with pc.
func readPCData(t *testing.T, r *SymReader, name, pcdataname string, pcoff uint32, pc int) (int, bool) {
+ // "If pcsp, pcfile, pcln, or any of the pcdata offsets is zero,
+ // that table is considered missing, and all PCs take value -1."
+ if pcoff == 0 {
+ return -1, true
+ }
+
var it PCIter
for it.Init(r.p, r.data[pcoff:]); !it.Done; it.Next() {
if it.PC <= uint32(pc) && uint32(pc) < it.NextPC {
diff --git a/src/cmd/link/runtime.go b/src/cmd/link/runtime.go
index 5d37015eb..b0c1ac98a 100644
--- a/src/cmd/link/runtime.go
+++ b/src/cmd/link/runtime.go
@@ -15,13 +15,13 @@ func (p *Prog) runtime() {
// TODO: Implement garbage collection data.
p.addSym(&Sym{
Sym: &goobj.Sym{
- SymID: goobj.SymID{Name: "gcdata"},
+ SymID: goobj.SymID{Name: "runtime.gcdata"},
Kind: goobj.SRODATA,
},
})
p.addSym(&Sym{
Sym: &goobj.Sym{
- SymID: goobj.SymID{Name: "gcbss"},
+ SymID: goobj.SymID{Name: "runtime.gcbss"},
Kind: goobj.SRODATA,
},
})
diff --git a/src/cmd/link/testdata/Makefile b/src/cmd/link/testdata/Makefile
index 3b1b15f73..e9651a03f 100644
--- a/src/cmd/link/testdata/Makefile
+++ b/src/cmd/link/testdata/Makefile
@@ -9,7 +9,7 @@ ALL=\
all: $(ALL)
%.6: %.s
- go tool 6a $*.s
+ GOARCH=amd64 GOOS=darwin go tool 6a -trimpath=$(shell pwd) $*.s
pclntab.s: genpcln.go
go run genpcln.go >pclntab.s
diff --git a/src/cmd/link/testdata/autosection.6 b/src/cmd/link/testdata/autosection.6
index bc9d446e1..386f422cf 100644
--- a/src/cmd/link/testdata/autosection.6
+++ b/src/cmd/link/testdata/autosection.6
Binary files differ
diff --git a/src/cmd/link/testdata/autosection.s b/src/cmd/link/testdata/autosection.s
index 8a579b702..e0cb21723 100644
--- a/src/cmd/link/testdata/autosection.s
+++ b/src/cmd/link/testdata/autosection.s
@@ -4,7 +4,7 @@
// Test of section-named symbols.
-#include "../../ld/textflag.h"
+#include "textflag.h"
TEXT start(SB),7,$0
MOVQ $autotab(SB),AX
@@ -16,37 +16,37 @@ GLOBL zero(SB), $8
GLOBL zeronoptr(SB), NOPTR, $16
// text
-DATA autotab+0x00(SB)/8, $text(SB)
+DATA autotab+0x00(SB)/8, $runtime·text(SB)
DATA autotab+0x08(SB)/8, $start(SB)
-DATA autotab+0x10(SB)/8, $etext(SB)
+DATA autotab+0x10(SB)/8, $runtime·etext(SB)
DATA autotab+0x18(SB)/8, $start+16(SB)
// data
-DATA autotab+0x20(SB)/8, $data(SB)
+DATA autotab+0x20(SB)/8, $runtime·data(SB)
DATA autotab+0x28(SB)/8, $autotab(SB)
-DATA autotab+0x30(SB)/8, $edata(SB)
+DATA autotab+0x30(SB)/8, $runtime·edata(SB)
DATA autotab+0x38(SB)/8, $nonzero+4(SB)
// bss
-DATA autotab+0x40(SB)/8, $bss(SB)
+DATA autotab+0x40(SB)/8, $runtime·bss(SB)
DATA autotab+0x48(SB)/8, $zero(SB)
-DATA autotab+0x50(SB)/8, $ebss(SB)
+DATA autotab+0x50(SB)/8, $runtime·ebss(SB)
DATA autotab+0x58(SB)/8, $zero+8(SB)
// noptrdata
-DATA autotab+0x60(SB)/8, $noptrdata(SB)
+DATA autotab+0x60(SB)/8, $runtime·noptrdata(SB)
DATA autotab+0x68(SB)/8, $nonzeronoptr(SB)
-DATA autotab+0x70(SB)/8, $enoptrdata(SB)
+DATA autotab+0x70(SB)/8, $runtime·enoptrdata(SB)
DATA autotab+0x78(SB)/8, $nonzeronoptr+8(SB)
// noptrbss
-DATA autotab+0x80(SB)/8, $noptrbss(SB)
+DATA autotab+0x80(SB)/8, $runtime·noptrbss(SB)
DATA autotab+0x88(SB)/8, $zeronoptr(SB)
-DATA autotab+0x90(SB)/8, $enoptrbss(SB)
+DATA autotab+0x90(SB)/8, $runtime·enoptrbss(SB)
DATA autotab+0x98(SB)/8, $zeronoptr+16(SB)
// end
-DATA autotab+0xa0(SB)/8, $end(SB)
+DATA autotab+0xa0(SB)/8, $runtime·end(SB)
DATA autotab+0xa8(SB)/8, $zeronoptr+16(SB)
GLOBL autotab(SB), $0xb0
diff --git a/src/cmd/link/testdata/autoweak.6 b/src/cmd/link/testdata/autoweak.6
index 636a4d844..5d74d4e2b 100644
--- a/src/cmd/link/testdata/autoweak.6
+++ b/src/cmd/link/testdata/autoweak.6
Binary files differ
diff --git a/src/cmd/link/testdata/dead.6 b/src/cmd/link/testdata/dead.6
index bb77aafe8..9540adc1a 100644
--- a/src/cmd/link/testdata/dead.6
+++ b/src/cmd/link/testdata/dead.6
Binary files differ
diff --git a/src/cmd/link/testdata/dead.s b/src/cmd/link/testdata/dead.s
index 832ddaff6..86f31360f 100644
--- a/src/cmd/link/testdata/dead.s
+++ b/src/cmd/link/testdata/dead.s
@@ -17,7 +17,7 @@ TEXT text1(SB),7,$0
RET
TEXT text2(SB),7,$0
- MOVQ $edata(SB),BX
+ MOVQ $runtime·edata(SB),BX
RET
DATA data1<>+0(SB)/8, $data2(SB)
@@ -46,4 +46,3 @@ GLOBL dead_data1(SB), $16
GLOBL dead_data2(SB), $1
GLOBL dead_data3(SB), $1
GLOBL dead_funcdata(SB), $8
-
diff --git a/src/cmd/link/testdata/genpcln.go b/src/cmd/link/testdata/genpcln.go
index 684cc07a2..c10eaeae9 100644
--- a/src/cmd/link/testdata/genpcln.go
+++ b/src/cmd/link/testdata/genpcln.go
@@ -107,6 +107,6 @@ func main() {
for f := 0; f < 3; f++ {
fmt.Printf("\tCALL func%d(SB)\n", f)
}
- fmt.Printf("\tMOVQ $pclntab(SB), AX\n")
+ fmt.Printf("\tMOVQ $runtime·pclntab(SB), AX\n")
fmt.Printf("\n\tRET\n")
}
diff --git a/src/cmd/link/testdata/hello.6 b/src/cmd/link/testdata/hello.6
index b129dc029..67983f1a9 100644
--- a/src/cmd/link/testdata/hello.6
+++ b/src/cmd/link/testdata/hello.6
Binary files differ
diff --git a/src/cmd/link/testdata/layout.6 b/src/cmd/link/testdata/layout.6
index 8cd5bd2cd..db24ef3e5 100644
--- a/src/cmd/link/testdata/layout.6
+++ b/src/cmd/link/testdata/layout.6
Binary files differ
diff --git a/src/cmd/link/testdata/layout.s b/src/cmd/link/testdata/layout.s
index 0d492c5af..c3e55ef49 100644
--- a/src/cmd/link/testdata/layout.s
+++ b/src/cmd/link/testdata/layout.s
@@ -5,7 +5,7 @@
// Test of section assignment in layout.go.
// Each symbol should end up in the section named by the symbol name prefix (up to the underscore).
-#include "../../ld/textflag.h"
+#include "textflag.h"
TEXT text_start(SB),7,$0
MOVQ $rodata_sym(SB), AX
diff --git a/src/cmd/link/testdata/link.hello.darwin.amd64 b/src/cmd/link/testdata/link.hello.darwin.amd64
index b1f0a93b2..0bd475dd8 100644
--- a/src/cmd/link/testdata/link.hello.darwin.amd64
+++ b/src/cmd/link/testdata/link.hello.darwin.amd64
@@ -6,8 +6,8 @@
*
00000060 00 00 00 00 00 00 00 00 19 00 00 00 38 01 00 00 |............8...|
00000070 5f 5f 54 45 58 54 00 00 00 00 00 00 00 00 00 00 |__TEXT..........|
-00000080 00 10 00 00 00 00 00 00 d6 10 00 00 00 00 00 00 |................|
-00000090 00 00 00 00 00 00 00 00 d6 10 00 00 00 00 00 00 |................|
+00000080 00 10 00 00 00 00 00 00 b0 10 00 00 00 00 00 00 |................|
+00000090 00 00 00 00 00 00 00 00 b0 10 00 00 00 00 00 00 |................|
000000a0 07 00 00 00 05 00 00 00 03 00 00 00 00 00 00 00 |................|
000000b0 5f 5f 74 65 78 74 00 00 00 00 00 00 00 00 00 00 |__text..........|
000000c0 5f 5f 54 45 58 54 00 00 00 00 00 00 00 00 00 00 |__TEXT..........|
@@ -21,7 +21,7 @@
*
00000150 5f 5f 66 75 6e 63 74 61 62 00 00 00 00 00 00 00 |__functab.......|
00000160 5f 5f 54 45 58 54 00 00 00 00 00 00 00 00 00 00 |__TEXT..........|
-00000170 20 20 00 00 00 00 00 00 b6 00 00 00 00 00 00 00 | ..............|
+00000170 20 20 00 00 00 00 00 00 90 00 00 00 00 00 00 00 | ..............|
00000180 20 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ...............|
*
000001a0 19 00 00 00 98 00 00 00 5f 5f 44 41 54 41 00 00 |........__DATA..|
@@ -48,10 +48,7 @@
00001070 00 00 00 00 00 00 00 00 5f 72 74 30 5f 67 6f 00 |........_rt0_go.|
00001080 02 20 00 04 20 00 06 05 02 05 02 05 02 05 02 02 |. .. ...........|
00001090 02 02 02 05 02 02 02 01 00 00 00 00 00 00 00 00 |................|
-000010a0 02 00 00 00 88 00 00 00 2f 55 73 65 72 73 2f 72 |......../Users/r|
-000010b0 73 63 2f 67 2f 67 6f 2f 73 72 63 2f 63 6d 64 2f |sc/g/go/src/cmd/|
-000010c0 6c 69 6e 6b 2f 74 65 73 74 64 61 74 61 2f 68 65 |link/testdata/he|
-000010d0 6c 6c 6f 2e 73 00 00 00 00 00 00 00 00 00 00 00 |llo.s...........|
+000010a0 02 00 00 00 88 00 00 00 68 65 6c 6c 6f 2e 73 00 |........hello.s.|
*
00002000 68 65 6c 6c 6f 20 77 6f 72 6c 64 0a |hello world.|
0000200c
diff --git a/src/cmd/link/testdata/pclntab.6 b/src/cmd/link/testdata/pclntab.6
index 918411ca5..9e7f9afdb 100644
--- a/src/cmd/link/testdata/pclntab.6
+++ b/src/cmd/link/testdata/pclntab.6
Binary files differ
diff --git a/src/cmd/link/testdata/pclntab.s b/src/cmd/link/testdata/pclntab.s
index 22c4ee0de..12dac70b0 100644
--- a/src/cmd/link/testdata/pclntab.s
+++ b/src/cmd/link/testdata/pclntab.s
@@ -1746,6 +1746,6 @@ TEXT start(SB),7,$0
CALL func0(SB)
CALL func1(SB)
CALL func2(SB)
- MOVQ $pclntab(SB), AX
+ MOVQ $runtime·pclntab(SB), AX
RET
diff --git a/src/cmd/nm/nm.go b/src/cmd/nm/nm.go
index a4036184e..3089e481b 100644
--- a/src/cmd/nm/nm.go
+++ b/src/cmd/nm/nm.go
@@ -6,13 +6,13 @@ package main
import (
"bufio"
- "bytes"
"flag"
"fmt"
- "io"
"log"
"os"
"sort"
+
+ "cmd/internal/objfile"
)
func usage() {
@@ -85,55 +85,22 @@ func errorf(format string, args ...interface{}) {
exitCode = 1
}
-type Sym struct {
- Addr uint64
- Size int64
- Code rune
- Name string
- Type string
-}
-
-var parsers = []struct {
- prefix []byte
- parse func(*os.File) []Sym
-}{
- {[]byte("!<arch>\n"), goobjSymbols},
- {[]byte("go object "), goobjSymbols},
- {[]byte("\x7FELF"), elfSymbols},
- {[]byte("\xFE\xED\xFA\xCE"), machoSymbols},
- {[]byte("\xFE\xED\xFA\xCF"), machoSymbols},
- {[]byte("\xCE\xFA\xED\xFE"), machoSymbols},
- {[]byte("\xCF\xFA\xED\xFE"), machoSymbols},
- {[]byte("MZ"), peSymbols},
- {[]byte("\x00\x00\x01\xEB"), plan9Symbols}, // 386
- {[]byte("\x00\x00\x04\x07"), plan9Symbols}, // mips
- {[]byte("\x00\x00\x06\x47"), plan9Symbols}, // arm
- {[]byte("\x00\x00\x8A\x97"), plan9Symbols}, // amd64
-}
-
func nm(file string) {
- f, err := os.Open(file)
+ f, err := objfile.Open(file)
if err != nil {
errorf("%v", err)
return
}
defer f.Close()
- buf := make([]byte, 16)
- io.ReadFull(f, buf)
- f.Seek(0, 0)
-
- var syms []Sym
- for _, p := range parsers {
- if bytes.HasPrefix(buf, p.prefix) {
- syms = p.parse(f)
- goto HaveSyms
- }
+ syms, err := f.Symbols()
+ if err != nil {
+ errorf("reading %s: %v", file, err)
+ }
+ if len(syms) == 0 {
+ errorf("reading %s: no symbols", file)
}
- errorf("%v: unknown file format", file)
- return
-HaveSyms:
switch *sortOrder {
case "address":
sort.Sort(byAddr(syms))
@@ -165,19 +132,19 @@ HaveSyms:
w.Flush()
}
-type byAddr []Sym
+type byAddr []objfile.Sym
func (x byAddr) Len() int { return len(x) }
func (x byAddr) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x byAddr) Less(i, j int) bool { return x[i].Addr < x[j].Addr }
-type byName []Sym
+type byName []objfile.Sym
func (x byName) Len() int { return len(x) }
func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x byName) Less(i, j int) bool { return x[i].Name < x[j].Name }
-type bySize []Sym
+type bySize []objfile.Sym
func (x bySize) Len() int { return len(x) }
func (x bySize) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
diff --git a/src/cmd/nm/nm_test.go b/src/cmd/nm/nm_test.go
index 74773877f..f447e8e49 100644
--- a/src/cmd/nm/nm_test.go
+++ b/src/cmd/nm/nm_test.go
@@ -77,7 +77,7 @@ func TestNM(t *testing.T) {
"elf/testdata/gcc-amd64-linux-exec",
"macho/testdata/gcc-386-darwin-exec",
"macho/testdata/gcc-amd64-darwin-exec",
- "pe/testdata/gcc-amd64-mingw-exec",
+ // "pe/testdata/gcc-amd64-mingw-exec", // no symbols!
"pe/testdata/gcc-386-mingw-exec",
"plan9obj/testdata/amd64-plan9-exec",
"plan9obj/testdata/386-plan9-exec",
@@ -87,7 +87,7 @@ func TestNM(t *testing.T) {
cmd := exec.Command(testnmpath, exepath)
out, err := cmd.CombinedOutput()
if err != nil {
- t.Fatalf("go tool nm %v: %v\n%s", exepath, err, string(out))
+ t.Errorf("go tool nm %v: %v\n%s", exepath, err, string(out))
}
}
diff --git a/src/cmd/nm/pe.go b/src/cmd/nm/pe.go
deleted file mode 100644
index 52d05e51d..000000000
--- a/src/cmd/nm/pe.go
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2013 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.
-
-// Parsing of PE executables (Microsoft Windows).
-
-package main
-
-import (
- "debug/pe"
- "os"
- "sort"
-)
-
-func peSymbols(f *os.File) []Sym {
- p, err := pe.NewFile(f)
- if err != nil {
- errorf("parsing %s: %v", f.Name(), err)
- return nil
- }
-
- // Build sorted list of addresses of all symbols.
- // We infer the size of a symbol by looking at where the next symbol begins.
- var addrs []uint64
-
- var imageBase uint64
- switch oh := p.OptionalHeader.(type) {
- case *pe.OptionalHeader32:
- imageBase = uint64(oh.ImageBase)
- case *pe.OptionalHeader64:
- imageBase = oh.ImageBase
- default:
- errorf("parsing %s: file format not recognized", f.Name())
- return nil
- }
-
- var syms []Sym
- for _, s := range p.Symbols {
- const (
- N_UNDEF = 0 // An undefined (extern) symbol
- N_ABS = -1 // An absolute symbol (e_value is a constant, not an address)
- N_DEBUG = -2 // A debugging symbol
- )
- sym := Sym{Name: s.Name, Addr: uint64(s.Value), Code: '?'}
- switch s.SectionNumber {
- case N_UNDEF:
- sym.Code = 'U'
- case N_ABS:
- sym.Code = 'C'
- case N_DEBUG:
- sym.Code = '?'
- default:
- if s.SectionNumber < 0 {
- errorf("parsing %s: invalid section number %d", f.Name(), s.SectionNumber)
- return nil
- }
- if len(p.Sections) < int(s.SectionNumber) {
- errorf("parsing %s: section number %d is large then max %d", f.Name(), s.SectionNumber, len(p.Sections))
- return nil
- }
- sect := p.Sections[s.SectionNumber-1]
- const (
- text = 0x20
- data = 0x40
- bss = 0x80
- permX = 0x20000000
- permR = 0x40000000
- permW = 0x80000000
- )
- ch := sect.Characteristics
- switch {
- case ch&text != 0:
- sym.Code = 'T'
- case ch&data != 0:
- if ch&permW == 0 {
- sym.Code = 'R'
- } else {
- sym.Code = 'D'
- }
- case ch&bss != 0:
- sym.Code = 'B'
- }
- sym.Addr += imageBase + uint64(sect.VirtualAddress)
- }
- syms = append(syms, sym)
- addrs = append(addrs, sym.Addr)
- }
-
- sort.Sort(uint64s(addrs))
- for i := range syms {
- j := sort.Search(len(addrs), func(x int) bool { return addrs[x] > syms[i].Addr })
- if j < len(addrs) {
- syms[i].Size = int64(addrs[j] - syms[i].Addr)
- }
- }
-
- return syms
-}
diff --git a/src/cmd/nm/plan9obj.go b/src/cmd/nm/plan9obj.go
deleted file mode 100644
index 006c66ebf..000000000
--- a/src/cmd/nm/plan9obj.go
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2014 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.
-
-// Parsing of Plan 9 a.out executables.
-
-package main
-
-import (
- "debug/plan9obj"
- "os"
- "sort"
-)
-
-func plan9Symbols(f *os.File) []Sym {
- p, err := plan9obj.NewFile(f)
- if err != nil {
- errorf("parsing %s: %v", f.Name(), err)
- return nil
- }
-
- plan9Syms, err := p.Symbols()
- if err != nil {
- errorf("parsing %s: %v", f.Name(), err)
- return nil
- }
-
- // Build sorted list of addresses of all symbols.
- // We infer the size of a symbol by looking at where the next symbol begins.
- var addrs []uint64
- for _, s := range plan9Syms {
- addrs = append(addrs, s.Value)
- }
- sort.Sort(uint64s(addrs))
-
- var syms []Sym
-
- for _, s := range plan9Syms {
- sym := Sym{Addr: s.Value, Name: s.Name, Code: rune(s.Type)}
- i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value })
- if i < len(addrs) {
- sym.Size = int64(addrs[i] - s.Value)
- }
- syms = append(syms, sym)
- }
-
- return syms
-}
diff --git a/src/cmd/objdump/main.go b/src/cmd/objdump/main.go
index 9922dcc02..1e4163296 100644
--- a/src/cmd/objdump/main.go
+++ b/src/cmd/objdump/main.go
@@ -101,7 +101,7 @@ func main() {
keep := syms[:0]
for _, sym := range syms {
switch sym.Name {
- case "text", "_text", "etext", "_etext":
+ case "runtime.text", "text", "_text", "runtime.etext", "etext", "_etext":
// drop
default:
keep = append(keep, sym)
@@ -118,7 +118,7 @@ func main() {
i := sort.Search(len(syms), func(i int) bool { return syms[i].Addr > addr })
if i > 0 {
s := syms[i-1]
- if s.Addr <= addr && addr < s.Addr+uint64(s.Size) && s.Name != "etext" && s.Name != "_etext" {
+ if s.Addr <= addr && addr < s.Addr+uint64(s.Size) && s.Name != "runtime.etext" && s.Name != "etext" && s.Name != "_etext" {
return s.Name, s.Addr
}
}
@@ -355,11 +355,20 @@ func loadTables(f *os.File) (textStart uint64, textData, symtab, pclntab []byte,
textStart = imageBase + uint64(sect.VirtualAddress)
textData, _ = sect.Data()
}
- if pclntab, err = loadPETable(obj, "pclntab", "epclntab"); err != nil {
- return 0, nil, nil, nil, err
+ if pclntab, err = loadPETable(obj, "runtime.pclntab", "runtime.epclntab"); err != nil {
+ // We didn't find the symbols, so look for the names used in 1.3 and earlier.
+ // TODO: Remove code looking for the old symbols when we no longer care about 1.3.
+ var err2 error
+ if pclntab, err2 = loadPETable(obj, "pclntab", "epclntab"); err2 != nil {
+ return 0, nil, nil, nil, err
+ }
}
- if symtab, err = loadPETable(obj, "symtab", "esymtab"); err != nil {
- return 0, nil, nil, nil, err
+ if symtab, err = loadPETable(obj, "runtime.symtab", "runtime.esymtab"); err != nil {
+ // Same as above.
+ var err2 error
+ if symtab, err2 = loadPETable(obj, "symtab", "esymtab"); err2 != nil {
+ return 0, nil, nil, nil, err
+ }
}
return textStart, textData, symtab, pclntab, nil
}
@@ -369,11 +378,20 @@ func loadTables(f *os.File) (textStart uint64, textData, symtab, pclntab []byte,
if sect := obj.Section("text"); sect != nil {
textData, _ = sect.Data()
}
- if pclntab, err = loadPlan9Table(obj, "pclntab", "epclntab"); err != nil {
- return 0, nil, nil, nil, err
+ if pclntab, err = loadPlan9Table(obj, "runtime.pclntab", "runtime.epclntab"); err != nil {
+ // We didn't find the symbols, so look for the names used in 1.3 and earlier.
+ // TODO: Remove code looking for the old symbols when we no longer care about 1.3.
+ var err2 error
+ if pclntab, err2 = loadPlan9Table(obj, "pclntab", "epclntab"); err2 != nil {
+ return 0, nil, nil, nil, err
+ }
}
- if symtab, err = loadPlan9Table(obj, "symtab", "esymtab"); err != nil {
- return 0, nil, nil, nil, err
+ if symtab, err = loadPlan9Table(obj, "runtime.symtab", "runtime.esymtab"); err != nil {
+ // Same as above.
+ var err2 error
+ if symtab, err2 = loadPlan9Table(obj, "symtab", "esymtab"); err2 != nil {
+ return 0, nil, nil, nil, err
+ }
}
return textStart, textData, symtab, pclntab, nil
}
diff --git a/src/cmd/yacc/Makefile b/src/cmd/yacc/Makefile
deleted file mode 100644
index f8c8169bd..000000000
--- a/src/cmd/yacc/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright 2009 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.
-
-TARG=expr$(shell go env GOEXE)
-
-$(TARG): yacc.go expr.y
- go run yacc.go -p expr expr.y
- go build -o $(TARG) y.go
-
-clean:
- rm -f y.go y.output $(TARG)
diff --git a/src/cmd/yacc/doc.go b/src/cmd/yacc/doc.go
index ceaaf2448..702c9f0d2 100644
--- a/src/cmd/yacc/doc.go
+++ b/src/cmd/yacc/doc.go
@@ -20,8 +20,9 @@ written in C and documented at
Adepts of the original yacc will have no trouble adapting to this
form of the tool.
-The file expr.y in this directory is a yacc grammar for a very simple
-expression parser. It needs the flag "-p expr" (see below).
+The directory $GOROOT/cmd/yacc/testdata/expr is a yacc program
+for a very simple expression parser. See expr.y and main.go in that
+directory for examples of how to write and build yacc programs.
The generated parser is reentrant. Parse expects to be given an
argument that conforms to the following interface:
diff --git a/src/cmd/yacc/testdata/expr/README b/src/cmd/yacc/testdata/expr/README
new file mode 100644
index 000000000..302ef57a7
--- /dev/null
+++ b/src/cmd/yacc/testdata/expr/README
@@ -0,0 +1,20 @@
+This directory contains a simple program demonstrating how to use
+the Go version of yacc.
+
+To build it:
+
+ $ go generate
+ $ go build
+
+or
+
+ $ go generate
+ $ go run expr.go
+
+The file main.go contains the "go generate" command to run yacc to
+create expr.go from expr.y. It also has the package doc comment,
+as godoc will not scan the .y file.
+
+The actual implementation is in expr.y.
+
+The program is not installed in the binary distributions of Go.
diff --git a/src/cmd/yacc/expr.y b/src/cmd/yacc/testdata/expr/expr.y
index 77e9259da..09451949f 100644
--- a/src/cmd/yacc/expr.y
+++ b/src/cmd/yacc/testdata/expr/expr.y
@@ -11,11 +11,6 @@
%{
-// This tag will be copied to the generated file to prevent that file
-// confusing a future build.
-
-// +build ignore
-
package main
import (
diff --git a/src/cmd/yacc/testdata/expr/main.go b/src/cmd/yacc/testdata/expr/main.go
new file mode 100644
index 000000000..8d5b6911f
--- /dev/null
+++ b/src/cmd/yacc/testdata/expr/main.go
@@ -0,0 +1,15 @@
+// Copyright 2014 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.
+
+// This file holds the go generate command to run yacc on the grammar in expr.y.
+// To build expr:
+// % go generate
+// % go build
+
+//go:generate -command yacc go tool yacc
+//go:generate yacc -o expr.go -p "expr" expr.y
+
+// Expr is a simple expression evaluator that serves as a working example of
+// how to use Go's yacc implemenation.
+package main