From 6ddc2cb80c45e21bb0dc4c5c9790cdb6c4164359 Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Tue, 25 Nov 2014 03:15:11 +1100 Subject: [PATCH 01/19] [dev.cc] runtime: convert dragonfly/386 port to Go LGTM=rsc R=rsc, bradfitz CC=golang-codereviews https://golang.org/cl/178210043 --- src/runtime/defs_dragonfly_386.go | 80 ++++++++++++++++------------- src/runtime/signal_dragonfly_386.go | 34 ++++++++++++ src/runtime/signal_dragonfly_386.h | 23 --------- 3 files changed, 78 insertions(+), 59 deletions(-) create mode 100644 src/runtime/signal_dragonfly_386.go delete mode 100644 src/runtime/signal_dragonfly_386.h diff --git a/src/runtime/defs_dragonfly_386.go b/src/runtime/defs_dragonfly_386.go index 1768dbac41..e9c6353152 100644 --- a/src/runtime/defs_dragonfly_386.go +++ b/src/runtime/defs_dragonfly_386.go @@ -92,16 +92,16 @@ type rtprio struct { } type lwpparams struct { - _type unsafe.Pointer - arg *byte - stack *byte - tid1 *int32 - tid2 *int32 + start_func uintptr + arg unsafe.Pointer + stack uintptr + tid1 unsafe.Pointer // *int32 + tid2 unsafe.Pointer // *int32 } type sigaltstackt struct { - ss_sp *int8 - ss_size uint32 + ss_sp uintptr + ss_size uintptr ss_flags int32 } @@ -110,8 +110,8 @@ type sigset struct { } type stackt struct { - ss_sp *int8 - ss_size uint32 + ss_sp uintptr + ss_size uintptr ss_flags int32 } @@ -122,39 +122,39 @@ type siginfo struct { si_pid int32 si_uid uint32 si_status int32 - si_addr *byte + si_addr uintptr si_value [4]byte si_band int32 __spare__ [7]int32 } type mcontext struct { - mc_onstack int32 - mc_gs int32 - mc_fs int32 - mc_es int32 - mc_ds int32 - mc_edi int32 - mc_esi int32 - mc_ebp int32 - mc_isp int32 - mc_ebx int32 - mc_edx int32 - mc_ecx int32 - mc_eax int32 - mc_xflags int32 - mc_trapno int32 - mc_err int32 - mc_eip int32 - mc_cs int32 - mc_eflags int32 - mc_esp int32 - mc_ss int32 - mc_len int32 - mc_fpformat int32 - mc_ownedfp int32 - mc_fpregs [128]int32 - __spare__ [16]int32 + mc_onstack uint32 + mc_gs uint32 + mc_fs uint32 + mc_es uint32 + mc_ds uint32 + mc_edi uint32 + mc_esi uint32 + mc_ebp uint32 + mc_isp uint32 + mc_ebx uint32 + mc_edx uint32 + mc_ecx uint32 + mc_eax uint32 + mc_xflags uint32 + mc_trapno uint32 + mc_err uint32 + mc_eip uint32 + mc_cs uint32 + mc_eflags uint32 + mc_esp uint32 + mc_ss uint32 + mc_len uint32 + mc_fpformat uint32 + mc_ownedfp uint32 + mc_fpregs [128]uint32 + __spare__ [16]uint32 } type ucontext struct { @@ -170,11 +170,19 @@ type timespec struct { tv_nsec int32 } +func (ts *timespec) set_sec(x int64) { + ts.tv_sec = int32(x) +} + type timeval struct { tv_sec int32 tv_usec int32 } +func (tv *timeval) set_usec(x int32) { + tv.tv_usec = x +} + type itimerval struct { it_interval timeval it_value timeval diff --git a/src/runtime/signal_dragonfly_386.go b/src/runtime/signal_dragonfly_386.go new file mode 100644 index 0000000000..a0fec1309c --- /dev/null +++ b/src/runtime/signal_dragonfly_386.go @@ -0,0 +1,34 @@ +// 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. + +package runtime + +import "unsafe" + +type sigctxt struct { + info *siginfo + ctxt unsafe.Pointer +} + +func (c *sigctxt) regs() *mcontext { return &(*ucontext)(c.ctxt).uc_mcontext } +func (c *sigctxt) eax() uint32 { return c.regs().mc_eax } +func (c *sigctxt) ebx() uint32 { return c.regs().mc_ebx } +func (c *sigctxt) ecx() uint32 { return c.regs().mc_ecx } +func (c *sigctxt) edx() uint32 { return c.regs().mc_edx } +func (c *sigctxt) edi() uint32 { return c.regs().mc_edi } +func (c *sigctxt) esi() uint32 { return c.regs().mc_esi } +func (c *sigctxt) ebp() uint32 { return c.regs().mc_ebp } +func (c *sigctxt) esp() uint32 { return c.regs().mc_esp } +func (c *sigctxt) eip() uint32 { return c.regs().mc_eip } +func (c *sigctxt) eflags() uint32 { return c.regs().mc_eflags } +func (c *sigctxt) cs() uint32 { return uint32(c.regs().mc_cs) } +func (c *sigctxt) fs() uint32 { return uint32(c.regs().mc_fs) } +func (c *sigctxt) gs() uint32 { return uint32(c.regs().mc_gs) } +func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) } +func (c *sigctxt) sigaddr() uint32 { return uint32(c.info.si_addr) } + +func (c *sigctxt) set_eip(x uint32) { c.regs().mc_eip = x } +func (c *sigctxt) set_esp(x uint32) { c.regs().mc_esp = x } +func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) } +func (c *sigctxt) set_sigaddr(x uint32) { c.info.si_addr = uintptr(x) } diff --git a/src/runtime/signal_dragonfly_386.h b/src/runtime/signal_dragonfly_386.h deleted file mode 100644 index a24f1ee96c..0000000000 --- a/src/runtime/signal_dragonfly_386.h +++ /dev/null @@ -1,23 +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. - -#define SIG_REGS(ctxt) (((Ucontext*)(ctxt))->uc_mcontext) - -#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).mc_eax) -#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).mc_ebx) -#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).mc_ecx) -#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).mc_edx) -#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).mc_edi) -#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).mc_esi) -#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).mc_ebp) -#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).mc_esp) -#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).mc_eip) -#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).mc_eflags) - -#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).mc_cs) -#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).mc_fs) -#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).mc_gs) - -#define SIG_CODE0(info, ctxt) ((info)->si_code) -#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr) From e78777ebfef59356c72a3788483a78610f9ad0a2 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Mon, 24 Nov 2014 11:40:36 -0500 Subject: [PATCH 02/19] [dev.cc] 9g: fill progtable for CC, V, and VCC instruction variants This adds some utilities for converting between the CC, V, and VCC variants of operations and uses these to derive the ProgInfo entries for these variants (which are identical to the ProgInfo for the base operations). The 9g peephole optimizer will also use these conversion utilities. LGTM=minux, rsc R=rsc, dave, minux CC=golang-codereviews https://golang.org/cl/180110044 --- src/cmd/9g/opt.h | 10 +++ src/cmd/9g/prog.c | 162 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+) diff --git a/src/cmd/9g/opt.h b/src/cmd/9g/opt.h index 7f15b5a69f..6a07b268f2 100644 --- a/src/cmd/9g/opt.h +++ b/src/cmd/9g/opt.h @@ -225,6 +225,16 @@ enum void proginfo(ProgInfo*, Prog*); +// Many Power ISA arithmetic and logical instructions come in four +// standard variants. These bits let us map between variants. +enum { + V_CC = 1<<0, // xCC (affect CR field 0 flags) + V_V = 1<<1, // xV (affect SO and OV flags) +}; + +int as2variant(int); +int variant2as(int, int); + // To allow use of AJMP, ACALL, ARET in ../gc/popt.c. enum { diff --git a/src/cmd/9g/prog.c b/src/cmd/9g/prog.c index 51c132d183..7c0f0c7959 100644 --- a/src/cmd/9g/prog.c +++ b/src/cmd/9g/prog.c @@ -101,9 +101,36 @@ static ProgInfo progtable[ALAST] = { [ADUFFCOPY]= {Call}, }; +static void +initproginfo(void) +{ + static int initialized; + int addvariant[] = {V_CC, V_V, V_CC|V_V}; + int as, as2, i, variant; + + if(initialized) + return; + initialized = 1; + + // Perform one-time expansion of instructions in progtable to + // their CC, V, and VCC variants + for(as=0; asas]; if(info->flags == 0) { *info = progtable[AADD]; @@ -143,3 +170,138 @@ proginfo(ProgInfo *info, Prog *p) info->regset |= RtoB(3) | RtoB(4); } } + +// Instruction variants table. Initially this contains entries only +// for the "base" form of each instruction. On the first call to +// as2variant or variant2as, we'll add the variants to the table. +static int varianttable[ALAST][4] = { + [AADD]= {AADD, AADDCC, AADDV, AADDVCC}, + [AADDC]= {AADDC, AADDCCC, AADDCV, AADDCVCC}, + [AADDE]= {AADDE, AADDECC, AADDEV, AADDEVCC}, + [AADDME]= {AADDME, AADDMECC, AADDMEV, AADDMEVCC}, + [AADDZE]= {AADDZE, AADDZECC, AADDZEV, AADDZEVCC}, + [AAND]= {AAND, AANDCC, 0, 0}, + [AANDN]= {AANDN, AANDNCC, 0, 0}, + [ACNTLZD]= {ACNTLZD, ACNTLZDCC, 0, 0}, + [ACNTLZW]= {ACNTLZW, ACNTLZWCC, 0, 0}, + [ADIVD]= {ADIVD, ADIVDCC, ADIVDV, ADIVDVCC}, + [ADIVDU]= {ADIVDU, ADIVDUCC, ADIVDUV, ADIVDUVCC}, + [ADIVW]= {ADIVW, ADIVWCC, ADIVWV, ADIVWVCC}, + [ADIVWU]= {ADIVWU, ADIVWUCC, ADIVWUV, ADIVWUVCC}, + [AEQV]= {AEQV, AEQVCC, 0, 0}, + [AEXTSB]= {AEXTSB, AEXTSBCC, 0, 0}, + [AEXTSH]= {AEXTSH, AEXTSHCC, 0, 0}, + [AEXTSW]= {AEXTSW, AEXTSWCC, 0, 0}, + [AFABS]= {AFABS, AFABSCC, 0, 0}, + [AFADD]= {AFADD, AFADDCC, 0, 0}, + [AFADDS]= {AFADDS, AFADDSCC, 0, 0}, + [AFCFID]= {AFCFID, AFCFIDCC, 0, 0}, + [AFCTID]= {AFCTID, AFCTIDCC, 0, 0}, + [AFCTIDZ]= {AFCTIDZ, AFCTIDZCC, 0, 0}, + [AFCTIW]= {AFCTIW, AFCTIWCC, 0, 0}, + [AFCTIWZ]= {AFCTIWZ, AFCTIWZCC, 0, 0}, + [AFDIV]= {AFDIV, AFDIVCC, 0, 0}, + [AFDIVS]= {AFDIVS, AFDIVSCC, 0, 0}, + [AFMADD]= {AFMADD, AFMADDCC, 0, 0}, + [AFMADDS]= {AFMADDS, AFMADDSCC, 0, 0}, + [AFMOVD]= {AFMOVD, AFMOVDCC, 0, 0}, + [AFMSUB]= {AFMSUB, AFMSUBCC, 0, 0}, + [AFMSUBS]= {AFMSUBS, AFMSUBSCC, 0, 0}, + [AFMUL]= {AFMUL, AFMULCC, 0, 0}, + [AFMULS]= {AFMULS, AFMULSCC, 0, 0}, + [AFNABS]= {AFNABS, AFNABSCC, 0, 0}, + [AFNEG]= {AFNEG, AFNEGCC, 0, 0}, + [AFNMADD]= {AFNMADD, AFNMADDCC, 0, 0}, + [AFNMADDS]= {AFNMADDS, AFNMADDSCC, 0, 0}, + [AFNMSUB]= {AFNMSUB, AFNMSUBCC, 0, 0}, + [AFNMSUBS]= {AFNMSUBS, AFNMSUBSCC, 0, 0}, + [AFRES]= {AFRES, AFRESCC, 0, 0}, + [AFRSP]= {AFRSP, AFRSPCC, 0, 0}, + [AFRSQRTE]= {AFRSQRTE, AFRSQRTECC, 0, 0}, + [AFSEL]= {AFSEL, AFSELCC, 0, 0}, + [AFSQRT]= {AFSQRT, AFSQRTCC, 0, 0}, + [AFSQRTS]= {AFSQRTS, AFSQRTSCC, 0, 0}, + [AFSUB]= {AFSUB, AFSUBCC, 0, 0}, + [AFSUBS]= {AFSUBS, AFSUBSCC, 0, 0}, + [AMTFSB0]= {AMTFSB0, AMTFSB0CC, 0, 0}, + [AMTFSB1]= {AMTFSB1, AMTFSB1CC, 0, 0}, + [AMULHD]= {AMULHD, AMULHDCC, 0, 0}, + [AMULHDU]= {AMULHDU, AMULHDUCC, 0, 0}, + [AMULHW]= {AMULHW, AMULHWCC, 0, 0}, + [AMULHWU]= {AMULHWU, AMULHWUCC, 0, 0}, + [AMULLD]= {AMULLD, AMULLDCC, AMULLDV, AMULLDVCC}, + [AMULLW]= {AMULLW, AMULLWCC, AMULLWV, AMULLWVCC}, + [ANAND]= {ANAND, ANANDCC, 0, 0}, + [ANEG]= {ANEG, ANEGCC, ANEGV, ANEGVCC}, + [ANOR]= {ANOR, ANORCC, 0, 0}, + [AOR]= {AOR, AORCC, 0, 0}, + [AORN]= {AORN, AORNCC, 0, 0}, + [AREM]= {AREM, AREMCC, AREMV, AREMVCC}, + [AREMD]= {AREMD, AREMDCC, AREMDV, AREMDVCC}, + [AREMDU]= {AREMDU, AREMDUCC, AREMDUV, AREMDUVCC}, + [AREMU]= {AREMU, AREMUCC, AREMUV, AREMUVCC}, + [ARLDC]= {ARLDC, ARLDCCC, 0, 0}, + [ARLDCL]= {ARLDCL, ARLDCLCC, 0, 0}, + [ARLDCR]= {ARLDCR, ARLDCRCC, 0, 0}, + [ARLDMI]= {ARLDMI, ARLDMICC, 0, 0}, + [ARLWMI]= {ARLWMI, ARLWMICC, 0, 0}, + [ARLWNM]= {ARLWNM, ARLWNMCC, 0, 0}, + [ASLD]= {ASLD, ASLDCC, 0, 0}, + [ASLW]= {ASLW, ASLWCC, 0, 0}, + [ASRAD]= {ASRAD, ASRADCC, 0, 0}, + [ASRAW]= {ASRAW, ASRAWCC, 0, 0}, + [ASRD]= {ASRD, ASRDCC, 0, 0}, + [ASRW]= {ASRW, ASRWCC, 0, 0}, + [ASUB]= {ASUB, ASUBCC, ASUBV, ASUBVCC}, + [ASUBC]= {ASUBC, ASUBCCC, ASUBCV, ASUBCVCC}, + [ASUBE]= {ASUBE, ASUBECC, ASUBEV, ASUBEVCC}, + [ASUBME]= {ASUBME, ASUBMECC, ASUBMEV, ASUBMEVCC}, + [ASUBZE]= {ASUBZE, ASUBZECC, ASUBZEV, ASUBZEVCC}, + [AXOR]= {AXOR, AXORCC, 0, 0}, +}; + +static void +initvariants(void) +{ + static int initialized; + int i, j; + + if(initialized) + return; + initialized = 1; + + for(i=0; i Date: Mon, 24 Nov 2014 11:42:15 -0500 Subject: [PATCH 03/19] [dev.cc] 9g: peephole optimizer This was based on the 9c peephole optimizer, modified to work with code generated by gc and use the proginfo infrastructure in gc. LGTM=rsc R=rsc, bradfitz, minux CC=golang-codereviews https://golang.org/cl/179190043 --- src/cmd/9g/peep.c | 896 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 892 insertions(+), 4 deletions(-) diff --git a/src/cmd/9g/peep.c b/src/cmd/9g/peep.c index ec314d6338..1f430220e5 100644 --- a/src/cmd/9g/peep.c +++ b/src/cmd/9g/peep.c @@ -33,12 +33,295 @@ #include "gg.h" #include "opt.h" +static int regzer(Addr *a); +static int subprop(Flow*); +static int copyprop(Flow*); +static int copy1(Addr*, Addr*, Flow*, int); +static int copyas(Addr*, Addr*); +static int copyau(Addr*, Addr*); +static int copysub(Addr*, Addr*, Addr*, int); +static int copysub1(Prog*, Addr*, Addr*, int); +static int copyau1(Prog *p, Addr *v); + +static uint32 gactive; + void -peep(Prog *p) +peep(Prog *firstp) { - USED(p); - // TODO(minux) - return; + Graph *g; + Flow *r, *r1; + Prog *p, *p1; + int t; + + g = flowstart(firstp, sizeof(Flow)); + if(g == nil) + return; + gactive = 0; + +loop1: + if(debug['P'] && debug['v']) + dumpit("loop1", g->start, 0); + + t = 0; + for(r=g->start; r!=nil; r=r->link) { + p = r->prog; + // TODO(austin) Handle smaller moves. arm and amd64 + // distinguish between moves that moves that *must* + // sign/zero extend and moves that don't care so they + // can eliminate moves that don't care without + // breaking moves that do care. This might let us + // simplify or remove the next peep loop, too. + if(p->as == AMOVD || p->as == AFMOVD) + if(regtyp(&p->to)) { + // Try to eliminate reg->reg moves + if(regtyp(&p->from)) + if(p->from.type == p->to.type) { + if(copyprop(r)) { + excise(r); + t++; + } else + if(subprop(r) && copyprop(r)) { + excise(r); + t++; + } + } + // Convert uses to $0 to uses of R0 and + // propagate R0 + if(regzer(&p->from)) + if(p->to.type == D_REG) { + p->from.type = D_REG; + p->from.reg = REGZERO; + if(copyprop(r)) { + excise(r); + t++; + } else + if(subprop(r) && copyprop(r)) { + excise(r); + t++; + } + } + } + } + if(t) + goto loop1; + + /* + * look for MOVB x,R; MOVB R,R (for small MOVs not handled above) + */ + for(r=g->start; r!=nil; r=r->link) { + p = r->prog; + switch(p->as) { + default: + continue; + case AMOVH: + case AMOVHZ: + case AMOVB: + case AMOVBZ: + case AMOVW: + case AMOVWZ: + if(p->to.type != D_REG) + continue; + break; + } + r1 = r->link; + if(r1 == nil) + continue; + p1 = r1->prog; + if(p1->as != p->as) + continue; + if(p1->from.type != D_REG || p1->from.reg != p->to.reg) + continue; + if(p1->to.type != D_REG || p1->to.reg != p->to.reg) + continue; + excise(r1); + } + + if(debug['D'] > 1) + goto ret; /* allow following code improvement to be suppressed */ + + /* + * look for OP x,y,R; CMP R, $0 -> OPCC x,y,R + * when OP can set condition codes correctly + */ + for(r=g->start; r!=nil; r=r->link) { + p = r->prog; + switch(p->as) { + case ACMP: + case ACMPW: /* always safe? */ + if(!regzer(&p->to)) + continue; + r1 = r->s1; + if(r1 == nil) + continue; + switch(r1->prog->as) { + default: + continue; + case ABCL: + case ABC: + /* the conditions can be complex and these are currently little used */ + continue; + case ABEQ: + case ABGE: + case ABGT: + case ABLE: + case ABLT: + case ABNE: + case ABVC: + case ABVS: + break; + } + r1 = r; + do + r1 = uniqp(r1); + while (r1 != nil && r1->prog->as == ANOP); + if(r1 == nil) + continue; + p1 = r1->prog; + if(p1->to.type != D_REG || p1->to.reg != p->from.reg) + continue; + switch(p1->as) { + case ASUB: + case AADD: + case AXOR: + case AOR: + /* irregular instructions */ + if(p1->from.type == D_CONST) + continue; + break; + } + switch(p1->as) { + default: + continue; + case AMOVW: + case AMOVD: + if(p1->from.type != D_REG) + continue; + continue; + case AANDCC: + case AANDNCC: + case AORCC: + case AORNCC: + case AXORCC: + case ASUBCC: + case ASUBECC: + case ASUBMECC: + case ASUBZECC: + case AADDCC: + case AADDCCC: + case AADDECC: + case AADDMECC: + case AADDZECC: + case ARLWMICC: + case ARLWNMCC: + /* don't deal with floating point instructions for now */ +/* + case AFABS: + case AFADD: + case AFADDS: + case AFCTIW: + case AFCTIWZ: + case AFDIV: + case AFDIVS: + case AFMADD: + case AFMADDS: + case AFMOVD: + case AFMSUB: + case AFMSUBS: + case AFMUL: + case AFMULS: + case AFNABS: + case AFNEG: + case AFNMADD: + case AFNMADDS: + case AFNMSUB: + case AFNMSUBS: + case AFRSP: + case AFSUB: + case AFSUBS: + case ACNTLZW: + case AMTFSB0: + case AMTFSB1: +*/ + case AADD: + case AADDV: + case AADDC: + case AADDCV: + case AADDME: + case AADDMEV: + case AADDE: + case AADDEV: + case AADDZE: + case AADDZEV: + case AAND: + case AANDN: + case ADIVW: + case ADIVWV: + case ADIVWU: + case ADIVWUV: + case ADIVD: + case ADIVDV: + case ADIVDU: + case ADIVDUV: + case AEQV: + case AEXTSB: + case AEXTSH: + case AEXTSW: + case AMULHW: + case AMULHWU: + case AMULLW: + case AMULLWV: + case AMULHD: + case AMULHDU: + case AMULLD: + case AMULLDV: + case ANAND: + case ANEG: + case ANEGV: + case ANOR: + case AOR: + case AORN: + case AREM: + case AREMV: + case AREMU: + case AREMUV: + case AREMD: + case AREMDV: + case AREMDU: + case AREMDUV: + case ARLWMI: + case ARLWNM: + case ASLW: + case ASRAW: + case ASRW: + case ASLD: + case ASRAD: + case ASRD: + case ASUB: + case ASUBV: + case ASUBC: + case ASUBCV: + case ASUBME: + case ASUBMEV: + case ASUBE: + case ASUBEV: + case ASUBZE: + case ASUBZEV: + case AXOR: + t = variant2as(p1->as, as2variant(p1->as) | V_CC); + break; + } + if(debug['D']) + print("cmp %P; %P -> ", p1, p); + p1->as = t; + if(debug['D']) + print("%P\n", p1); + excise(r); + continue; + } + } + +ret: + flowend(g); } void @@ -56,6 +339,22 @@ excise(Flow *r) ostats.ndelmov++; } +/* + * regzer returns 1 if a's value is 0 (a is R0 or $0) + */ +static int +regzer(Addr *a) +{ + if(a->type == D_CONST) + if(a->sym == nil && a->reg == NREG) + if(a->offset == 0) + return 1; + if(a->type == D_REG) + if(a->reg == REGZERO) + return 1; + return 0; +} + int regtyp(Adr *a) { @@ -63,11 +362,600 @@ regtyp(Adr *a) default: return 0; case D_REG: + if(a->reg == REGZERO) + return 0; case D_FREG: return 1; } } +/* + * the idea is to substitute + * one register for another + * from one MOV to another + * MOV a, R1 + * ADD b, R1 / no use of R2 + * MOV R1, R2 + * would be converted to + * MOV a, R2 + * ADD b, R2 + * MOV R2, R1 + * hopefully, then the former or latter MOV + * will be eliminated by copy propagation. + * + * r0 (the argument, not the register) is the MOV at the end of the + * above sequences. This returns 1 if it modified any instructions. + */ +static int +subprop(Flow *r0) +{ + Prog *p; + Addr *v1, *v2; + Flow *r; + int t; + ProgInfo info; + + p = r0->prog; + v1 = &p->from; + if(!regtyp(v1)) + return 0; + v2 = &p->to; + if(!regtyp(v2)) + return 0; + for(r=uniqp(r0); r!=nil; r=uniqp(r)) { + if(uniqs(r) == nil) + break; + p = r->prog; + if(p->as == AVARDEF || p->as == AVARKILL) + continue; + proginfo(&info, p); + if(info.flags & Call) + return 0; + + if((info.flags & (RightRead|RightWrite)) == RightWrite) { + if(p->to.type == v1->type) + if(p->to.reg == v1->reg) + goto gotit; + } + + if(copyau(&p->from, v2) || + copyau1(p, v2) || + copyau(&p->to, v2)) + break; + if(copysub(&p->from, v1, v2, 0) || + copysub1(p, v1, v2, 0) || + copysub(&p->to, v1, v2, 0)) + break; + } + return 0; + +gotit: + copysub(&p->to, v1, v2, 1); + if(debug['P']) { + print("gotit: %D->%D\n%P", v1, v2, r->prog); + if(p->from.type == v2->type) + print(" excise"); + print("\n"); + } + for(r=uniqs(r); r!=r0; r=uniqs(r)) { + p = r->prog; + copysub(&p->from, v1, v2, 1); + copysub1(p, v1, v2, 1); + copysub(&p->to, v1, v2, 1); + if(debug['P']) + print("%P\n", r->prog); + } + t = v1->reg; + v1->reg = v2->reg; + v2->reg = t; + if(debug['P']) + print("%P last\n", r->prog); + return 1; +} + +/* + * The idea is to remove redundant copies. + * v1->v2 F=0 + * (use v2 s/v2/v1/)* + * set v1 F=1 + * use v2 return fail (v1->v2 move must remain) + * ----------------- + * v1->v2 F=0 + * (use v2 s/v2/v1/)* + * set v1 F=1 + * set v2 return success (caller can remove v1->v2 move) + */ +static int +copyprop(Flow *r0) +{ + Prog *p; + Addr *v1, *v2; + + p = r0->prog; + v1 = &p->from; + v2 = &p->to; + if(copyas(v1, v2)) { + if(debug['P']) + print("eliminating self-move\n", r0->prog); + return 1; + } + gactive++; + if(debug['P']) + print("trying to eliminate %D->%D move from:\n%P\n", v1, v2, r0->prog); + return copy1(v1, v2, r0->s1, 0); +} + +// copy1 replaces uses of v2 with v1 starting at r and returns 1 if +// all uses were rewritten. +static int +copy1(Addr *v1, Addr *v2, Flow *r, int f) +{ + int t; + Prog *p; + + if(r->active == gactive) { + if(debug['P']) + print("act set; return 1\n"); + return 1; + } + r->active = gactive; + if(debug['P']) + print("copy1 replace %D with %D f=%d\n", v2, v1, f); + for(; r != nil; r = r->s1) { + p = r->prog; + if(debug['P']) + print("%P", p); + if(!f && uniqp(r) == nil) { + // Multiple predecessors; conservatively + // assume v1 was set on other path + f = 1; + if(debug['P']) + print("; merge; f=%d", f); + } + t = copyu(p, v2, nil); + switch(t) { + case 2: /* rar, can't split */ + if(debug['P']) + print("; %D rar; return 0\n", v2); + return 0; + + case 3: /* set */ + if(debug['P']) + print("; %D set; return 1\n", v2); + return 1; + + case 1: /* used, substitute */ + case 4: /* use and set */ + if(f) { + if(!debug['P']) + return 0; + if(t == 4) + print("; %D used+set and f=%d; return 0\n", v2, f); + else + print("; %D used and f=%d; return 0\n", v2, f); + return 0; + } + if(copyu(p, v2, v1)) { + if(debug['P']) + print("; sub fail; return 0\n"); + return 0; + } + if(debug['P']) + print("; sub %D->%D\n => %P", v2, v1, p); + if(t == 4) { + if(debug['P']) + print("; %D used+set; return 1\n", v2); + return 1; + } + break; + } + if(!f) { + t = copyu(p, v1, nil); + if(!f && (t == 2 || t == 3 || t == 4)) { + f = 1; + if(debug['P']) + print("; %D set and !f; f=%d", v1, f); + } + } + if(debug['P']) + print("\n"); + if(r->s2) + if(!copy1(v1, v2, r->s2, f)) + return 0; + } + return 1; +} + +// If s==nil, copyu returns the set/use of v in p; otherwise, it +// modifies p to replace reads of v with reads of s and returns 0 for +// success or non-zero for failure. +// +// If s==nil, copy returns one of the following values: +// 1 if v only used +// 2 if v is set and used in one address (read-alter-rewrite; +// can't substitute) +// 3 if v is only set +// 4 if v is set in one address and used in another (so addresses +// can be rewritten independently) +// 0 otherwise (not touched) +int +copyu(Prog *p, Addr *v, Addr *s) +{ + if(p->from3.type != D_NONE) + // 9g never generates a from3 + print("copyu: from3 (%D) not implemented\n", p->from3); + + switch(p->as) { + + default: + print("copyu: can't find %A\n", p->as); + return 2; + + case ANOP: /* read p->from, write p->to */ + case AMOVH: + case AMOVHZ: + case AMOVB: + case AMOVBZ: + case AMOVW: + case AMOVWZ: + case AMOVD: + + case ANEG: + case ANEGCC: + case AADDME: + case AADDMECC: + case AADDZE: + case AADDZECC: + case ASUBME: + case ASUBMECC: + case ASUBZE: + case ASUBZECC: + + case AFCTIW: + case AFCTIWZ: + case AFCTID: + case AFCTIDZ: + case AFCFID: + case AFCFIDCC: + case AFMOVS: + case AFMOVD: + case AFRSP: + case AFNEG: + case AFNEGCC: + if(s != nil) { + if(copysub(&p->from, v, s, 1)) + return 1; + // Update only indirect uses of v in p->to + if(!copyas(&p->to, v)) + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; + } + if(copyas(&p->to, v)) { + // Fix up implicit from + if(p->from.type == D_NONE) + p->from = p->to; + if(copyau(&p->from, v)) + return 4; + return 3; + } + if(copyau(&p->from, v)) + return 1; + if(copyau(&p->to, v)) + // p->to only indirectly uses v + return 1; + return 0; + + case AMOVBU: /* rar p->from, write p->to or read p->from, rar p->to */ + case AMOVBZU: + case AMOVHU: + case AMOVHZU: + case AMOVWZU: + case AMOVDU: + if(p->from.type == D_OREG) { + if(copyas(&p->from, v)) + // No s!=nil check; need to fail + // anyway in that case + return 2; + if(s != nil) { + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; + } + if(copyas(&p->to, v)) + return 3; + } else if (p->to.type == D_OREG) { + if(copyas(&p->to, v)) + return 2; + if(s != nil) { + if(copysub(&p->from, v, s, 1)) + return 1; + return 0; + } + if(copyau(&p->from, v)) + return 1; + } else { + print("copyu: bad %P\n", p); + } + return 0; + + case ARLWMI: /* read p->from, read p->reg, rar p->to */ + case ARLWMICC: + if(copyas(&p->to, v)) + return 2; + /* fall through */ + + case AADD: /* read p->from, read p->reg, write p->to */ + case AADDC: + case AADDE: + case ASUB: + case ASLW: + case ASRW: + case ASRAW: + case ASLD: + case ASRD: + case ASRAD: + case AOR: + case AORCC: + case AORN: + case AORNCC: + case AAND: + case AANDCC: + case AANDN: + case AANDNCC: + case ANAND: + case ANANDCC: + case ANOR: + case ANORCC: + case AXOR: + case AMULHW: + case AMULHWU: + case AMULLW: + case AMULLD: + case ADIVW: + case ADIVD: + case ADIVWU: + case ADIVDU: + case AREM: + case AREMU: + case AREMD: + case AREMDU: + case ARLWNM: + case ARLWNMCC: + + case AFADDS: + case AFADD: + case AFSUBS: + case AFSUB: + case AFMULS: + case AFMUL: + case AFDIVS: + case AFDIV: + if(s != nil) { + if(copysub(&p->from, v, s, 1)) + return 1; + if(copysub1(p, v, s, 1)) + return 1; + // Update only indirect uses of v in p->to + if(!copyas(&p->to, v)) + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; + } + if(copyas(&p->to, v)) { + if(p->reg == NREG) + // Fix up implicit reg (e.g., ADD + // R3,R4 -> ADD R3,R4,R4) so we can + // update reg and to separately. + p->reg = p->to.reg; + if(copyau(&p->from, v)) + return 4; + if(copyau1(p, v)) + return 4; + return 3; + } + if(copyau(&p->from, v)) + return 1; + if(copyau1(p, v)) + return 1; + if(copyau(&p->to, v)) + return 1; + return 0; + + case ABEQ: + case ABGT: + case ABGE: + case ABLT: + case ABLE: + case ABNE: + case ABVC: + case ABVS: + return 0; + + case ACHECKNIL: /* read p->from */ + case ACMP: /* read p->from, read p->to */ + case ACMPU: + case ACMPW: + case ACMPWU: + case AFCMPO: + case AFCMPU: + if(s != nil) { + if(copysub(&p->from, v, s, 1)) + return 1; + return copysub(&p->to, v, s, 1); + } + if(copyau(&p->from, v)) + return 1; + if(copyau(&p->to, v)) + return 1; + return 0; + + case ABR: /* read p->to */ + // 9g never generates a branch to a GPR (this isn't + // even a normal instruction; liblink turns it in to a + // mov and a branch). + if(s != nil) { + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; + } + if(copyau(&p->to, v)) + return 1; + return 0; + + case ARETURN: /* funny */ + if(s != nil) + return 0; + // All registers die at this point, so claim + // everything is set (and not used). + return 3; + + case ABL: /* funny */ + if(v->type == D_REG) { + if(v->reg <= REGEXT && v->reg > exregoffset) + return 2; + if(v->reg == REGARG) + return 2; + } + if(v->type == D_FREG) { + if(v->reg <= FREGEXT && v->reg > exfregoffset) + return 2; + } + if(p->from.type == D_REG && v->type == D_REG && p->from.reg == v->reg) + return 2; + + if(s != nil) { + if(copysub(&p->to, v, s, 1)) + return 1; + return 0; + } + if(copyau(&p->to, v)) + return 4; + return 3; + + case ADUFFZERO: + // R0 is zero, used by DUFFZERO, cannot be substituted. + // R3 is ptr to memory, used and set, cannot be substituted. + if(v->type == D_REG) { + if(v->reg == 0) + return 1; + if(v->reg == 3) + return 2; + } + return 0; + + case ADUFFCOPY: + // R3, R4 are ptr to src, dst, used and set, cannot be substituted. + // R5 is scratch, set by DUFFCOPY, cannot be substituted. + if(v->type == D_REG) { + if(v->reg == 3 || v->reg == 4) + return 2; + if(v->reg == 5) + return 3; + } + return 0; + + case ATEXT: /* funny */ + if(v->type == D_REG) + if(v->reg == REGARG) + return 3; + return 0; + + case APCDATA: + case AFUNCDATA: + case AVARDEF: + case AVARKILL: + return 0; + } +} + +int +a2type(Prog *p) +{ + ProgInfo info; + proginfo(&info, p); + if(info.flags & (SizeB|SizeW|SizeL|SizeQ)) + return D_REG; + if(info.flags & (SizeF|SizeD)) + return D_FREG; + return D_NONE; +} + +// copyas returns 1 if a and v address the same register. +// +// If a is the from operand, this means this operation reads the +// register in v. If a is the to operand, this means this operation +// writes the register in v. +static int +copyas(Addr *a, Addr *v) +{ + if(regtyp(v)) + if(a->type == v->type) + if(a->reg == v->reg) + return 1; + return 0; +} + +// copyau returns 1 if a either directly or indirectly addresses the +// same register as v. +// +// If a is the from operand, this means this operation reads the +// register in v. If a is the to operand, this means the operation +// either reads or writes the register in v (if !copyas(a, v), then +// the operation reads the register in v). +static int +copyau(Addr *a, Addr *v) +{ + if(copyas(a, v)) + return 1; + if(v->type == D_REG) + if(a->type == D_OREG || (a->type == D_CONST && a->reg != NREG)) + if(v->reg == a->reg) + return 1; + return 0; +} + +// copyau1 returns 1 if p->reg references the same register as v and v +// is a direct reference. +static int +copyau1(Prog *p, Addr *v) +{ + if(regtyp(v)) + if(p->from.type == v->type || p->to.type == v->type) + if(p->reg == v->reg) { + // Whether p->reg is a GPR or an FPR is + // implied by the instruction (both are + // numbered from 0). But the type should + // match v->type. Sanity check this. + if(a2type(p) != v->type) + print("botch a2type %P\n", p); + return 1; + } + return 0; +} + +// copysub replaces v with s in a if f!=0 or indicates it if could if f==0. +// Returns 1 on failure to substitute (it always succeeds on power64). +static int +copysub(Addr *a, Addr *v, Addr *s, int f) +{ + if(f) + if(copyau(a, v)) + a->reg = s->reg; + return 0; +} + +// copysub1 replaces v with s in p1->reg if f!=0 or indicates if it could if f==0. +// Returns 1 on failure to substitute (it always succeeds on power64). +static int +copysub1(Prog *p1, Addr *v, Addr *s, int f) +{ + if(f) + if(copyau1(p1, v)) + p1->reg = s->reg; + return 0; +} + int sameaddr(Addr *a, Addr *v) { From 355f25305b058f9975ce61401d7226e376e2db77 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 24 Nov 2014 20:18:44 -0500 Subject: [PATCH 04/19] go/build: build $GOOS_test.go always We decided to build $GOOS.go always but forgot to test $GOOS_test.go. Fixes #9159. LGTM=r R=r CC=golang-codereviews https://golang.org/cl/176290043 --- src/go/build/build.go | 8 +++++--- src/go/build/build_test.go | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/go/build/build.go b/src/go/build/build.go index 7a51cf3c06..311ecb01f4 100644 --- a/src/go/build/build.go +++ b/src/go/build/build.go @@ -1310,11 +1310,13 @@ func (ctxt *Context) goodOSArchFile(name string, allTags map[string]bool) bool { // auto-tagging to apply only to files with a non-empty prefix, so // "foo_linux.go" is tagged but "linux.go" is not. This allows new operating // sytems, such as android, to arrive without breaking existing code with - // innocuous source code in "android.go". The easiest fix: files without - // underscores are always included. - if !strings.ContainsRune(name, '_') { + // innocuous source code in "android.go". The easiest fix: cut everything + // in the name before the initial _. + i := strings.Index(name, "_") + if i < 0 { return true } + name = name[i:] // ignore everything before first _ l := strings.Split(name, "_") if n := len(l); n > 0 && l[n-1] == "test" { diff --git a/src/go/build/build_test.go b/src/go/build/build_test.go index 43d09cbd14..a40def0fa0 100644 --- a/src/go/build/build_test.go +++ b/src/go/build/build_test.go @@ -189,6 +189,7 @@ var matchFileTests = []struct { {ctxtAndroid, "foo_plan9.go", "", false}, {ctxtAndroid, "android.go", "", true}, {ctxtAndroid, "plan9.go", "", true}, + {ctxtAndroid, "plan9_test.go", "", true}, {ctxtAndroid, "arm.s", "", true}, {ctxtAndroid, "amd64.s", "", true}, } From c1374b5c7806c97d627017a3bfb5d41470f89b0e Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Tue, 25 Nov 2014 15:41:33 +1100 Subject: [PATCH 05/19] doc: tidy up "Projects" page; add Go 1.4 LGTM=r R=r CC=golang-codereviews https://golang.org/cl/182750043 --- doc/contrib.html | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/doc/contrib.html b/doc/contrib.html index a615fc67a3..8a674d647c 100644 --- a/doc/contrib.html +++ b/doc/contrib.html @@ -30,21 +30,16 @@ We encourage all Go users to subscribe to

Version history

Release History

-

A summary of the changes between Go releases.

-

Go 1 Release Notes

-

-A guide for updating your code to work with Go 1. -

+

A summary of the changes between Go releases. Notes for the major releases:

-

Go 1.1 Release Notes

-

-A list of significant changes in Go 1.1, with instructions for updating -your code where necessary. -Each point release includes a similar document appropriate for that -release: Go 1.2, Go 1.3, -and so on. -

+

Go 1 and the Future of Go Programs

From c8af6de2e8f315a6e8282004e8e90d9c567531ea Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Tue, 25 Nov 2014 08:42:00 +0100 Subject: [PATCH 06/19] [dev.cc] cmd/5g,cmd/6g,cmd/9g: fix warnings on Plan 9 warning: src/cmd/5g/reg.c:461 format mismatch d VLONG, arg 5 warning: src/cmd/6g/reg.c:396 format mismatch d VLONG, arg 5 warning: src/cmd/9g/reg.c:440 format mismatch d VLONG, arg 5 LGTM=minux R=rsc, minux CC=golang-codereviews https://golang.org/cl/179300043 --- src/cmd/5g/reg.c | 2 +- src/cmd/6g/reg.c | 2 +- src/cmd/9g/reg.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c index 611310f124..30fb816013 100644 --- a/src/cmd/5g/reg.c +++ b/src/cmd/5g/reg.c @@ -458,7 +458,7 @@ brk: print("\nregisterizing\n"); for(i=0; icost, rgp->varno, rgp->enter->f.prog->pc); + print("region %d: cost %d varno %d enter %lld\n", i, rgp->cost, rgp->varno, rgp->enter->f.prog->pc); bit = blsh(rgp->varno); vreg = paint2(rgp->enter, rgp->varno, 0); vreg = allreg(vreg, rgp); diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c index 75f9573b2e..f3dc59b146 100644 --- a/src/cmd/6g/reg.c +++ b/src/cmd/6g/reg.c @@ -393,7 +393,7 @@ brk: print("\nregisterizing\n"); for(i=0; icost, rgp->varno, rgp->enter->f.prog->pc); + print("region %d: cost %d varno %d enter %lld\n", i, rgp->cost, rgp->varno, rgp->enter->f.prog->pc); bit = blsh(rgp->varno); vreg = paint2(rgp->enter, rgp->varno, 0); vreg = allreg(vreg, rgp); diff --git a/src/cmd/9g/reg.c b/src/cmd/9g/reg.c index 2e546a95bb..2d8dbc4f1a 100644 --- a/src/cmd/9g/reg.c +++ b/src/cmd/9g/reg.c @@ -437,7 +437,7 @@ brk: print("\nregisterizing\n"); for(i=0; icost, rgp->varno, rgp->enter->f.prog->pc); + print("region %d: cost %d varno %d enter %lld\n", i, rgp->cost, rgp->varno, rgp->enter->f.prog->pc); bit = blsh(rgp->varno); usedreg = paint2(rgp->enter, rgp->varno, 0); vreg = allreg(usedreg, rgp); From 6f755f2f8f4665d44745b4065cd54a90eba0bde9 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Tue, 25 Nov 2014 16:00:25 -0500 Subject: [PATCH 07/19] [dev.cc] 9l: make R_CALLPOWER like ELF's R_PPC64_REL24 These accomplished the same thing, but R_CALLPOWER expected the whole instruction to be in the addend (and completely overwrote what was in the text section), while R_PPC64_REL24 overwrites only bits 6 through 24 of whatever was in the text section. Make R_CALLPOWER work like R_PPC64_REL24 to ease the implementation of dynamic linking. LGTM=rsc R=rsc CC=golang-codereviews, minux https://golang.org/cl/177430043 --- src/cmd/9l/asm.c | 22 +++++++++++++--------- src/liblink/asm9.c | 2 +- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/cmd/9l/asm.c b/src/cmd/9l/asm.c index b8ca777c35..65a36285d8 100644 --- a/src/cmd/9l/asm.c +++ b/src/cmd/9l/asm.c @@ -65,14 +65,6 @@ needlib(char *name) int nelfsym = 1; -// b is the addresses, a is the I-form branch instruction template, peform -// addition so that the instruction jumps to address (offset) b. -static int32 -braddoff(int32 a, int32 b) -{ - return (((uint32)a) & 0xfc000003U) | (0x03fffffcU & (uint32)((a & 0x3fffffcU) + b)); -} - void adddynrela(LSym *rel, LSym *s, Reloc *r) { @@ -160,7 +152,19 @@ archreloc(Reloc *r, LSym *s, vlong *val) *val = ((vlong)o2 << 32) | o1; return 0; case R_CALLPOWER: - *val = braddoff((uint32)r->add, (int32)(symaddr(r->sym) - (s->value + r->off))); + // Bits 6 through 29 = (S + A - P) >> 2 + if(ctxt->arch->endian == BigEndian) + o1 = be32(s->p + r->off); + else + o1 = le32(s->p + r->off); + + t = symaddr(r->sym) + r->add - (s->value + r->off); + if(t & 3) + ctxt->diag("relocation for %s is not aligned: %lld", s->name, t); + if(t << 6 >> 6 != t) + ctxt->diag("relocation for %s is too big: %lld", s->name, t); + + *val = (o1 & 0xfc000003U) | (t & ~0xfc000003U); return 0; } return -1; diff --git a/src/liblink/asm9.c b/src/liblink/asm9.c index 3c125b3b0f..5a379270d1 100644 --- a/src/liblink/asm9.c +++ b/src/liblink/asm9.c @@ -1589,7 +1589,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, int32 *out) ctxt->diag("odd branch target address\n%P", p); v &= ~03; } - rel->add = o1 | (v & 0x03FFFFFC); + rel->add = v; rel->type = R_CALLPOWER; } break; From 7c1e33033ddc2370c468b0f3087d5a584dfd2c7e Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Mon, 1 Dec 2014 07:52:09 -0800 Subject: [PATCH 08/19] reflect: Fix reflect.funcLayout. The GC bitmap has two bits per pointer, not one. Fixes #9179 LGTM=iant, rsc R=golang-codereviews, iant, rsc CC=golang-codereviews https://golang.org/cl/182160043 --- src/reflect/all_test.go | 101 +++++++++++++++++++++++++++++++++++++ src/reflect/export_test.go | 19 +++++++ src/reflect/type.go | 4 +- 3 files changed, 122 insertions(+), 2 deletions(-) diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index 268a9e319f..7a01c95d86 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -4055,3 +4055,104 @@ func TestLargeGCProg(t *testing.T) { fv := ValueOf(func([256]*byte) {}) fv.Call([]Value{ValueOf([256]*byte{})}) } + +// Issue 9179. +func TestCallGC(t *testing.T) { + f := func(a, b, c, d, e string) { + } + g := func(in []Value) []Value { + runtime.GC() + return nil + } + typ := ValueOf(f).Type() + f2 := MakeFunc(typ, g).Interface().(func(string, string, string, string, string)) + f2("four", "five5", "six666", "seven77", "eight888") +} + +type funcLayoutTest struct { + rcvr, t Type + argsize, retOffset uintptr + stack []byte +} + +var funcLayoutTests []funcLayoutTest + +func init() { + var argAlign = PtrSize + if runtime.GOARCH == "amd64p32" { + argAlign = 2 * PtrSize + } + roundup := func(x uintptr, a uintptr) uintptr { + return (x + a - 1) / a * a + } + + funcLayoutTests = append(funcLayoutTests, + funcLayoutTest{ + nil, + ValueOf(func(a, b string) string { return "" }).Type(), + 4 * PtrSize, + 4 * PtrSize, + []byte{BitsPointer, BitsScalar, BitsPointer}, + }) + + var r []byte + if PtrSize == 4 { + r = []byte{BitsScalar, BitsScalar, BitsScalar, BitsPointer} + } else { + r = []byte{BitsScalar, BitsScalar, BitsPointer} + } + funcLayoutTests = append(funcLayoutTests, + funcLayoutTest{ + nil, + ValueOf(func(a, b, c uint32, p *byte, d uint16) {}).Type(), + roundup(3*4, PtrSize) + PtrSize + 2, + roundup(roundup(3*4, PtrSize)+PtrSize+2, argAlign), + r, + }) + + funcLayoutTests = append(funcLayoutTests, + funcLayoutTest{ + nil, + ValueOf(func(a map[int]int, b uintptr, c interface{}) {}).Type(), + 4 * PtrSize, + 4 * PtrSize, + []byte{BitsPointer, BitsScalar, BitsPointer, BitsPointer}, + }) + + type S struct { + a, b uintptr + c, d *byte + } + funcLayoutTests = append(funcLayoutTests, + funcLayoutTest{ + nil, + ValueOf(func(a S) {}).Type(), + 4 * PtrSize, + 4 * PtrSize, + []byte{BitsScalar, BitsScalar, BitsPointer, BitsPointer}, + }) + + funcLayoutTests = append(funcLayoutTests, + funcLayoutTest{ + ValueOf((*byte)(nil)).Type(), + ValueOf(func(a uintptr, b *int) {}).Type(), + 3 * PtrSize, + roundup(3*PtrSize, argAlign), + []byte{BitsPointer, BitsScalar, BitsPointer}, + }) +} + +func TestFuncLayout(t *testing.T) { + for _, lt := range funcLayoutTests { + _, argsize, retOffset, stack := FuncLayout(lt.t, lt.rcvr) + if argsize != lt.argsize { + t.Errorf("funcLayout(%v, %v).argsize=%d, want %d", lt.t, lt.rcvr, argsize, lt.argsize) + } + if retOffset != lt.retOffset { + t.Errorf("funcLayout(%v, %v).retOffset=%d, want %d", lt.t, lt.rcvr, retOffset, lt.retOffset) + } + if !bytes.Equal(stack, lt.stack) { + t.Errorf("funcLayout(%v, %v).stack=%v, want %v", lt.t, lt.rcvr, stack, lt.stack) + } + } +} diff --git a/src/reflect/export_test.go b/src/reflect/export_test.go index 0778ad37f5..caaf51a50f 100644 --- a/src/reflect/export_test.go +++ b/src/reflect/export_test.go @@ -17,3 +17,22 @@ func IsRO(v Value) bool { var ArrayOf = arrayOf var CallGC = &callGC + +const PtrSize = ptrSize +const BitsPointer = bitsPointer +const BitsScalar = bitsScalar + +func FuncLayout(t Type, rcvr Type) (frametype Type, argSize, retOffset uintptr, stack []byte) { + var ft *rtype + var s *bitVector + if rcvr != nil { + ft, argSize, retOffset, s = funcLayout(t.(*rtype), rcvr.(*rtype)) + } else { + ft, argSize, retOffset, s = funcLayout(t.(*rtype), nil) + } + frametype = ft + for i := uint32(0); i < s.n; i += 2 { + stack = append(stack, s.data[i/8]>>(i%8)&3) + } + return +} diff --git a/src/reflect/type.go b/src/reflect/type.go index 572e611fa9..c0ddfcad0a 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -1894,14 +1894,14 @@ func addTypeBits(bv *bitVector, offset *uintptr, t *rtype) { switch Kind(t.kind & kindMask) { case Chan, Func, Map, Ptr, Slice, String, UnsafePointer: // 1 pointer at start of representation - for bv.n < uint32(*offset/uintptr(ptrSize)) { + for bv.n < 2*uint32(*offset/uintptr(ptrSize)) { bv.append2(bitsScalar) } bv.append2(bitsPointer) case Interface: // 2 pointers - for bv.n < uint32(*offset/uintptr(ptrSize)) { + for bv.n < 2*uint32(*offset/uintptr(ptrSize)) { bv.append2(bitsScalar) } bv.append2(bitsPointer) From 2b62e1eaece7c98444a588e2f2a3dbed8dddc273 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 1 Dec 2014 16:32:06 -0500 Subject: [PATCH 09/19] runtime: fix hang in GC due to shrinkstack vs netpoll race MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During garbage collection, after scanning a stack, we think about shrinking it to reclaim some memory. The shrinking code (called while the world is stopped) checked that the status was Gwaiting or Grunnable and then changed the state to Gcopystack, to essentially lock the stack so that no other GC thread is scanning it. The same locking happens for stack growth (and is more necessary there). oldstatus = runtime·readgstatus(gp); oldstatus &= ~Gscan; if(oldstatus == Gwaiting || oldstatus == Grunnable) runtime·casgstatus(gp, oldstatus, Gcopystack); // oldstatus is Gwaiting or Grunnable else runtime·throw("copystack: bad status, not Gwaiting or Grunnable"); Unfortunately, "stop the world" doesn't stop everything. It stops all normal goroutine execution, but the network polling thread is still blocked in epoll and may wake up. If it does, and it chooses a goroutine to mark runnable, and that goroutine is the one whose stack is shrinking, then it can happen that between readgstatus and casgstatus, the status changes from Gwaiting to Grunnable. casgstatus assumes that if the status is not what is expected, it is a transient change (like from Gwaiting to Gscanwaiting and back, or like from Gwaiting to Gcopystack and back), and it loops until the status has been restored to the expected value. In this case, the status has changed semi-permanently from Gwaiting to Grunnable - it won't change again until the GC is done and the world can continue, but the GC is waiting for the status to change back. This wedges the program. To fix, call a special variant of casgstatus that accepts either Gwaiting or Grunnable as valid statuses. Without the fix bug with the extra check+throw in casgstatus, the program below dies in a few seconds (2-10) with GOMAXPROCS=8 on a 2012 Retina MacBook Pro. With the fix, it runs for minutes and minutes. package main import ( "io" "log" "net" "runtime" ) func main() { const N = 100 for i := 0; i < N; i++ { l, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { log.Fatal(err) } ch := make(chan net.Conn, 1) go func() { var err error c1, err := net.Dial("tcp", l.Addr().String()) if err != nil { log.Fatal(err) } ch <- c1 }() c2, err := l.Accept() if err != nil { log.Fatal(err) } c1 := <-ch l.Close() go netguy(c1, c2) go netguy(c2, c1) c1.Write(make([]byte, 100)) } for { runtime.GC() } } func netguy(r, w net.Conn) { buf := make([]byte, 100) for { bigstack(1000) _, err := io.ReadFull(r, buf) if err != nil { log.Fatal(err) } w.Write(buf) } } var g int func bigstack(n int) { var buf [100]byte if n > 0 { bigstack(n - 1) } g = int(buf[0]) + int(buf[99]) } Fixes #9186. LGTM=rlh R=austin, rlh CC=dvyukov, golang-codereviews, iant, khr, r https://golang.org/cl/179680043 --- src/runtime/proc.c | 32 ++++++++++++++++++++++++++++++++ src/runtime/runtime.h | 2 ++ src/runtime/stack.c | 7 +------ 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/runtime/proc.c b/src/runtime/proc.c index 91e3fe16d6..8462c4b1d6 100644 --- a/src/runtime/proc.c +++ b/src/runtime/proc.c @@ -402,6 +402,7 @@ runtime·castogscanstatus(G *gp, uint32 oldval, uint32 newval) static void badcasgstatus(void); static void helpcasgstatus(void); +static void badgstatusrunnable(void); // If asked to move to or from a Gscanstatus this will throw. Use the castogscanstatus // and casfromgscanstatus instead. @@ -423,6 +424,10 @@ runtime·casgstatus(G *gp, uint32 oldval, uint32 newval) // loop if gp->atomicstatus is in a scan state giving // GC time to finish and change the state to oldval. while(!runtime·cas(&gp->atomicstatus, oldval, newval)) { + if(oldval == Gwaiting && gp->atomicstatus == Grunnable) { + fn = badgstatusrunnable; + runtime·onM(&fn); + } // Help GC if needed. if(gp->preemptscan && !gp->gcworkdone && (oldval == Grunning || oldval == Gsyscall)) { gp->preemptscan = false; @@ -433,6 +438,33 @@ runtime·casgstatus(G *gp, uint32 oldval, uint32 newval) } } +static void +badgstatusrunnable(void) +{ + runtime·throw("casgstatus: waiting for Gwaiting but is Grunnable"); +} + +// casgstatus(gp, oldstatus, Gcopystack), assuming oldstatus is Gwaiting or Grunnable. +// Returns old status. Cannot call casgstatus directly, because we are racing with an +// async wakeup that might come in from netpoll. If we see Gwaiting from the readgstatus, +// it might have become Grunnable by the time we get to the cas. If we called casgstatus, +// it would loop waiting for the status to go back to Gwaiting, which it never will. +#pragma textflag NOSPLIT +uint32 +runtime·casgcopystack(G *gp) +{ + uint32 oldstatus; + + for(;;) { + oldstatus = runtime·readgstatus(gp) & ~Gscan; + if(oldstatus != Gwaiting && oldstatus != Grunnable) + runtime·throw("copystack: bad status, not Gwaiting or Grunnable"); + if(runtime·cas(&gp->atomicstatus, oldstatus, Gcopystack)) + break; + } + return oldstatus; +} + static void badcasgstatus(void) { diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 977c4547df..177a1287ec 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -666,6 +666,8 @@ enum { uint32 runtime·readgstatus(G*); void runtime·casgstatus(G*, uint32, uint32); +void runtime·casgstatus(G*, uint32, uint32); +uint32 runtime·casgcopystack(G*); void runtime·quiesce(G*); bool runtime·stopg(G*); void runtime·restartg(G*); diff --git a/src/runtime/stack.c b/src/runtime/stack.c index 072bc242bc..cb9557243b 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -637,12 +637,7 @@ copystack(G *gp, uintptr newsize) } runtime·memmove((byte*)new.hi - used, (byte*)old.hi - used, used); - oldstatus = runtime·readgstatus(gp); - oldstatus &= ~Gscan; - if(oldstatus == Gwaiting || oldstatus == Grunnable) - runtime·casgstatus(gp, oldstatus, Gcopystack); // oldstatus is Gwaiting or Grunnable - else - runtime·throw("copystack: bad status, not Gwaiting or Grunnable"); + oldstatus = runtime·casgcopystack(gp); // cas from Gwaiting or Grunnable to Gcopystack, return old status // Swap out old stack for new one gp->stack = new; From ce5d7cffe8c69e2097ae878b8b7cfb6b2265bf69 Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Tue, 2 Dec 2014 14:39:23 +1100 Subject: [PATCH 10/19] tag go1.4rc2 LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/178600043 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 9867bc339f..eb9e82e408 100644 --- a/.hgtags +++ b/.hgtags @@ -137,3 +137,4 @@ f44017549ff9c3cc5eef74ebe7276cd0dfc066b6 go1.3.3 f44017549ff9c3cc5eef74ebe7276cd0dfc066b6 release 1fdfd7dfaedb1b7702141617e621ab7328a236a1 go1.4beta1 bffdd0cae380ce1ccf3e98ed6b6cd53fece7ba72 go1.4rc1 +6c4e66ae713704840fcea78c8055b44ba86ae5ea go1.4rc2 From 14948481f60accb7d7062f2f1d4f4cc50fb4e140 Mon Sep 17 00:00:00 2001 From: Dominik Honnef Date: Wed, 3 Dec 2014 10:28:54 +1100 Subject: [PATCH 11/19] cmd/go: regenerate doc.go Move change from CL 170770043 to correct file and regenerate docs for changes from CL 164120043. LGTM=adg R=golang-codereviews, adg, bradfitz CC=golang-codereviews https://golang.org/cl/183000043 --- src/cmd/go/doc.go | 7 ++++++- src/cmd/go/generate.go | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/cmd/go/doc.go b/src/cmd/go/doc.go index 43a3159440..879fc7f8ba 100644 --- a/src/cmd/go/doc.go +++ b/src/cmd/go/doc.go @@ -317,7 +317,7 @@ Download and install packages and dependencies Usage: - go get [-d] [-fix] [-t] [-u] [build flags] [packages] + go get [-d] [-f] [-fix] [-t] [-u] [build flags] [packages] Get downloads and installs the packages named by the import paths, along with their dependencies. @@ -325,6 +325,11 @@ along with their dependencies. The -d flag instructs get to stop after downloading the packages; that is, it instructs get not to install the packages. +The -f flag, valid only when -u is set, forces get -u not to verify that +each package has been checked out from the source control repository +implied by its import path. This can be useful if the source is a local fork +of the original. + The -fix flag instructs get to run the fix tool on the downloaded packages before resolving dependencies or building the code. diff --git a/src/cmd/go/generate.go b/src/cmd/go/generate.go index a83cce8f7a..2772452dd5 100644 --- a/src/cmd/go/generate.go +++ b/src/cmd/go/generate.go @@ -45,7 +45,7 @@ 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. +quoted string appears as a single argument to the generator. Go generate sets several variables when it runs the generator: From 9f04a62a39133439e20ea32a658cc35c21d33729 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 3 Dec 2014 14:14:00 -0500 Subject: [PATCH 12/19] cmd/pprof: fix symbol resolution for remote profiles Fixes #9199. LGTM=iant R=golang-codereviews, iant CC=austin, golang-codereviews, minux https://golang.org/cl/183080043 --- src/cmd/pprof/internal/symbolizer/symbolizer.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/cmd/pprof/internal/symbolizer/symbolizer.go b/src/cmd/pprof/internal/symbolizer/symbolizer.go index cabddaa76e..86de5640d2 100644 --- a/src/cmd/pprof/internal/symbolizer/symbolizer.go +++ b/src/cmd/pprof/internal/symbolizer/symbolizer.go @@ -32,6 +32,10 @@ func Symbolize(mode string, prof *profile.Profile, obj plugin.ObjTool, ui plugin } } + if len(prof.Mapping) == 0 { + return fmt.Errorf("no known mappings") + } + mt, err := newMapping(prof, obj, ui, force) if err != nil { return err From 583b29cb18e5dd93d71b79622e23d44833ab1715 Mon Sep 17 00:00:00 2001 From: David Symonds Date: Thu, 4 Dec 2014 09:29:29 +1100 Subject: [PATCH 13/19] spec: add comment marker for consistency. LGTM=r R=gri, r CC=golang-codereviews https://golang.org/cl/185830043 --- doc/go_spec.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/go_spec.html b/doc/go_spec.html index ca0deb56a3..3b67f307f6 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -5579,7 +5579,7 @@ s3 := append(s2, s0...) // append a slice s3 == []int{0, s4 := append(s3[3:6], s3[2:]...) // append overlapping slice s4 == []int{3, 5, 7, 2, 3, 5, 7, 0, 0} var t []interface{} -t = append(t, 42, 3.1415, "foo") t == []interface{}{42, 3.1415, "foo"} +t = append(t, 42, 3.1415, "foo") // t == []interface{}{42, 3.1415, "foo"} var b []byte b = append(b, "bar"...) // append string contents b == []byte{'b', 'a', 'r' } From b2950a2931bd89323569c1389f780f2cd744e12c Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Wed, 3 Dec 2014 20:07:48 -0800 Subject: [PATCH 14/19] lib/time: update to ICANN time zone database 2014j Fixes #9189. LGTM=dsymonds R=golang-codereviews, dsymonds CC=golang-codereviews https://golang.org/cl/178660043 --- lib/time/update.bash | 4 ++-- lib/time/zoneinfo.zip | Bin 358933 -> 360713 bytes 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/time/update.bash b/lib/time/update.bash index 8e1662afde..caa8450fa6 100755 --- a/lib/time/update.bash +++ b/lib/time/update.bash @@ -7,8 +7,8 @@ # downloaded from the ICANN/IANA distribution. # Versions to use. -CODE=2014d -DATA=2014d +CODE=2014j +DATA=2014j set -e rm -rf work diff --git a/lib/time/zoneinfo.zip b/lib/time/zoneinfo.zip index e0d3afe07434ff1349ee23a2506992c9960f4de6..425d7c98fa1f4bfcc9d642ff2e3d3b5a2c1a5970 100644 GIT binary patch delta 78888 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�(?L(y5RHnf?d)k%iM?Objlamd`-)3@z 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 delta 78660 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%0DNo>x}WtF*|-iggyKBZFIAS*V1a&l$< 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 R3(^*(si$yL1pZ!8{sU1pRBZqN From c9d0c812142be1c8f224012f24d111ba46ccdc10 Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Thu, 4 Dec 2014 11:24:23 -0500 Subject: [PATCH 15/19] cmd/pprof/internal/commands: add command to open browser on windows While we're at there, also add a message to prompt the user to install Graphviz if "dot" command is not found. Fixes #9178. LGTM=adg, alex.brainman, cookieo9, rsc R=rsc, adg, bradfitz, alex.brainman, cookieo9, smyrman CC=golang-codereviews https://golang.org/cl/180380043 --- src/cmd/pprof/internal/commands/commands.go | 26 +++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/cmd/pprof/internal/commands/commands.go b/src/cmd/pprof/internal/commands/commands.go index 6d35820184..51397a3c60 100644 --- a/src/cmd/pprof/internal/commands/commands.go +++ b/src/cmd/pprof/internal/commands/commands.go @@ -11,6 +11,7 @@ import ( "io" "os" "os/exec" + "runtime" "strings" "cmd/pprof/internal/plugin" @@ -71,15 +72,27 @@ func PProf(c Completer, interactive **bool, svgpan **string) Commands { "eog": {c, report.Dot, invokeVisualizer(interactive, invokeDot("svg"), "svg", []string{"eog"}), false, "Visualize graph through eog"}, "evince": {c, report.Dot, invokeVisualizer(interactive, invokeDot("pdf"), "pdf", []string{"evince"}), false, "Visualize graph through evince"}, "gv": {c, report.Dot, invokeVisualizer(interactive, invokeDot("ps"), "ps", []string{"gv --noantialias"}), false, "Visualize graph through gv"}, - "web": {c, report.Dot, invokeVisualizer(interactive, saveSVGToFile(svgpan), "svg", browsers), false, "Visualize graph through web browser"}, + "web": {c, report.Dot, invokeVisualizer(interactive, saveSVGToFile(svgpan), "svg", browsers()), false, "Visualize graph through web browser"}, // Visualize HTML directly generated by report. - "weblist": {c, report.WebList, invokeVisualizer(interactive, awayFromTTY("html"), "html", browsers), true, "Output annotated source in HTML for functions matching regexp or address"}, + "weblist": {c, report.WebList, invokeVisualizer(interactive, awayFromTTY("html"), "html", browsers()), true, "Output annotated source in HTML for functions matching regexp or address"}, } } -// List of web browsers to attempt for web visualization -var browsers = []string{"chrome", "google-chrome", "firefox", "/usr/bin/open"} +// browsers returns a list of commands to attempt for web visualization +// on the current platform +func browsers() []string { + cmds := []string{"chrome", "google-chrome", "firefox"} + switch runtime.GOOS { + case "darwin": + cmds = append(cmds, "/usr/bin/open") + case "windows": + cmds = append(cmds, "cmd /c start") + default: + cmds = append(cmds, "xdg-open") + } + return cmds +} // NewCompleter creates an autocompletion function for a set of commands. func NewCompleter(cs Commands) Completer { @@ -142,6 +155,10 @@ func awayFromTTY(format string) PostProcessor { func invokeDot(format string) PostProcessor { divert := awayFromTTY(format) return func(input *bytes.Buffer, output io.Writer, ui plugin.UI) error { + if _, err := exec.LookPath("dot"); err != nil { + ui.PrintErr("Cannot find dot, have you installed Graphviz?") + return err + } cmd := exec.Command("dot", "-T"+format) var buf bytes.Buffer cmd.Stdin, cmd.Stdout, cmd.Stderr = input, &buf, os.Stderr @@ -174,6 +191,7 @@ func invokeVisualizer(interactive **bool, format PostProcessor, suffix string, v if err = format(input, tempFile, ui); err != nil { return err } + tempFile.Close() // on windows, if the file is Open, start cannot access it. // Try visualizers until one is successful for _, v := range visualizers { // Separate command and arguments for exec.Command. From dd26fc3822e474112e388f51d59a7257361fb72f Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Fri, 5 Dec 2014 09:15:38 +0900 Subject: [PATCH 16/19] cmd/go: avoid use of bufio.Scanner in generate Scanner can't handle stupid long lines and there are reports of stupid long lines in production. Note the issue isn't long "//go:generate" lines, but any long line in any Go source file. To be fair, if you're going to have a stupid long line it's not a bad bet you'll want to run it through go generate, because it's some embeddable asset that has been machine generated. (One could ask why that generation process didn't add a newline or two, but we should cope anyway.) Rewrite the file scanner in "go generate" so it can handle arbitrarily long lines, and only stores in memory those lines that start "//go:generate". Also: Adjust the documentation to make clear that it does not parse the file. Fixes #9143. Fixes #9196. LGTM=rsc, dominik.honnef R=rsc, cespare, minux, dominik.honnef CC=golang-codereviews https://golang.org/cl/182970043 --- src/cmd/go/doc.go | 21 ++++++++----- src/cmd/go/generate.go | 71 +++++++++++++++++++++++++++++++++--------- 2 files changed, 70 insertions(+), 22 deletions(-) diff --git a/src/cmd/go/doc.go b/src/cmd/go/doc.go index 879fc7f8ba..65640fb483 100644 --- a/src/cmd/go/doc.go +++ b/src/cmd/go/doc.go @@ -234,17 +234,24 @@ 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 scans the file for directives, which are lines 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. +(note: no leading spaces and 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. +Note that go generate does not parse the file, so lines that look +like directives in comments or multiline strings will be treated +as directives. + +The arguments to the directive 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 as a single argument to the generator. diff --git a/src/cmd/go/generate.go b/src/cmd/go/generate.go index 2772452dd5..88f7efa0f3 100644 --- a/src/cmd/go/generate.go +++ b/src/cmd/go/generate.go @@ -32,17 +32,24 @@ 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 scans the file for directives, which are lines 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. +(note: no leading spaces and 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. +Note that go generate does not parse the file, so lines that look +like directives in comments or multiline strings will be treated +as directives. + +The arguments to the directive 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 as a single argument to the generator. @@ -178,13 +185,43 @@ func (g *Generator) run() (ok bool) { 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")) { + // Scan for lines that start "//go:generate". + // Can't use bufio.Scanner because it can't handle long lines, + // which are likely to appear when using generate. + input := bufio.NewReader(g.r) + var err error + // One line per loop. + for { + g.lineNum++ // 1-indexed. + var buf []byte + buf, err = input.ReadSlice('\n') + if err == bufio.ErrBufferFull { + // Line too long - consume and ignore. + if isGoGenerate(buf) { + g.errorf("directive too long") + } + for err == bufio.ErrBufferFull { + _, err = input.ReadSlice('\n') + } + if err != nil { + break + } continue } - words := g.split(s.Text()) + + if err != nil { + // Check for marker at EOF without final \n. + if err == io.EOF && isGoGenerate(buf) { + err = io.ErrUnexpectedEOF + } + break + } + + if !isGoGenerate(buf) { + continue + } + + words := g.split(string(buf)) if len(words) == 0 { g.errorf("no arguments to directive") } @@ -201,19 +238,23 @@ func (g *Generator) run() (ok bool) { } g.exec(words) } - if s.Err() != nil { - g.errorf("error reading %s: %s", shortPath(g.path), s.Err()) + if err != nil && err != io.EOF { + g.errorf("error reading %s: %s", shortPath(g.path), err) } return true } +func isGoGenerate(buf []byte) bool { + return bytes.HasPrefix(buf, []byte("//go:generate ")) || bytes.HasPrefix(buf, []byte("//go:generate\t")) +} + // 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 "):] + line = line[len("//go:generate ") : len(line)-1] // Drop preamble and final newline. // One (possibly quoted) word per iteration. Words: for { From 41c6b84342b27353ed40aa3942ef8647631a322b Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Fri, 5 Dec 2014 09:37:56 +0900 Subject: [PATCH 17/19] cmd/go: fix build The new semantics of split require the newline be present. The test was stale. LGTM=adg R=golang-codereviews, adg CC=golang-codereviews https://golang.org/cl/182480043 --- src/cmd/go/generate.go | 2 +- src/cmd/go/generate_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/go/generate.go b/src/cmd/go/generate.go index 88f7efa0f3..baf4d2b55c 100644 --- a/src/cmd/go/generate.go +++ b/src/cmd/go/generate.go @@ -250,7 +250,7 @@ func isGoGenerate(buf []byte) bool { // split breaks the line into words, evaluating quoted // strings and evaluating environment variables. -// The initial //go:generate element is dropped. +// The initial //go:generate element is present in line. func (g *Generator) split(line string) []string { // Parse line, obeying quoted strings. var words []string diff --git a/src/cmd/go/generate_test.go b/src/cmd/go/generate_test.go index 93c0ae66e9..660ebabbe8 100644 --- a/src/cmd/go/generate_test.go +++ b/src/cmd/go/generate_test.go @@ -40,7 +40,7 @@ func TestGenerateCommandParse(t *testing.T) { } g.setShorthand([]string{"-command", "yacc", "go", "tool", "yacc"}) for _, test := range splitTests { - got := g.split("//go:generate " + test.in) + got := g.split("//go:generate " + test.in + "\n") if !reflect.DeepEqual(got, test.out) { t.Errorf("split(%q): got %q expected %q", test.in, got, test.out) } From 274976f45c9b2c3f9140768b457e9140ea65bfb4 Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Fri, 5 Dec 2014 02:22:20 -0500 Subject: [PATCH 18/19] [dev.cc] cmd/ld: finalize linkmode before determining whether to import runtime/cgo Frankly, I don't understand how the current code could possibly work except when every android program is using cgo. Discovered this while working on the iOS port. LGTM=crawshaw, rsc R=rsc, crawshaw CC=golang-codereviews https://golang.org/cl/177470043 --- src/cmd/ld/lib.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c index 64608d226e..925274bfd3 100644 --- a/src/cmd/ld/lib.c +++ b/src/cmd/ld/lib.c @@ -202,7 +202,18 @@ loadlib(void) iscgo |= strcmp(ctxt->library[i].pkg, "runtime/cgo") == 0; objfile(ctxt->library[i].file, ctxt->library[i].pkg); } - + + if(linkmode == LinkAuto) { + if(iscgo && externalobj) + linkmode = LinkExternal; + else + linkmode = LinkInternal; + + // Force external linking for android. + if(strcmp(goos, "android") == 0) + linkmode = LinkExternal; + } + if(linkmode == LinkExternal && !iscgo) { // This indicates a user requested -linkmode=external. // The startup code uses an import of runtime/cgo to decide @@ -229,17 +240,6 @@ loadlib(void) } } - if(linkmode == LinkAuto) { - if(iscgo && externalobj) - linkmode = LinkExternal; - else - linkmode = LinkInternal; - - // Force external linking for android. - if(strcmp(goos, "android") == 0) - linkmode = LinkExternal; - } - if(linkmode == LinkInternal) { // Drop all the cgo_import_static declarations. // Turns out we won't be needing them. From e04c8b063fd7d7aaded8e1ff549dbb520038c61e Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 5 Dec 2014 09:24:01 -0500 Subject: [PATCH 19/19] [dev.cc] liblink: don't patch jumps to jumps to symbols When liblink sees something like JMP x ... x: JMP y it rewrites the first jump to jump directly to y. This is fine if y is a resolved label. However, it *also* does this if y is a function symbol, but fails to carry over the relocation that would later patch in that symbol's value. As a result, the original jump becomes either a self-jump (if relative) or a jump to PC 0 (if absolute). Fix this by disabling this optimization if the jump being patched in is a jump to a symbol. LGTM=minux R=rsc, minux CC=golang-codereviews https://golang.org/cl/185890044 --- src/liblink/pass.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/liblink/pass.c b/src/liblink/pass.c index bc8eb43679..8721a6a796 100644 --- a/src/liblink/pass.c +++ b/src/liblink/pass.c @@ -41,7 +41,7 @@ brchain(Link *ctxt, Prog *p) int i; for(i=0; i<20; i++) { - if(p == nil || p->as != ctxt->arch->AJMP) + if(p == nil || p->as != ctxt->arch->AJMP || p->pcond == nil) return p; p = p->pcond; } @@ -56,7 +56,7 @@ brloop(Link *ctxt, Prog *p) c = 0; for(q = p; q != nil; q = q->pcond) { - if(q->as != ctxt->arch->AJMP) + if(q->as != ctxt->arch->AJMP || q->pcond == nil) break; c++; if(c >= 5000)