[dev.link] all: merge master to dev.link
Change-Id: Ia30d70096e740d012e4d9e070bbc4347805527a7
diff --git a/AUTHORS b/AUTHORS
index d79d4ed..69e35a1 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1142,6 +1142,7 @@
Piyush Mishra <piyush@codeitout.com>
Platform.sh
Pontus Leitzler <leitzler@gmail.com>
+Prasanga Siripala <pj@pjebs.com.au>
Prashant Varanasi <prashant@prashantv.com>
Pravendra Singh <hackpravj@gmail.com>
Preetam Jinka <pj@preet.am>
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 07bdb4c..934834f 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -1788,6 +1788,7 @@
Piyush Mishra <piyush@codeitout.com>
Plekhanov Maxim <kishtatix@gmail.com>
Pontus Leitzler <leitzler@gmail.com>
+Prasanga Siripala <pj@pjebs.com.au>
Prasanna Swaminathan <prasanna@mediamath.com>
Prashant Agrawal <prashant.a.vjti@gmail.com>
Prashant Varanasi <prashant@prashantv.com>
diff --git a/misc/wasm/wasm_exec.js b/misc/wasm/wasm_exec.js
index a99aaed..8501ae7 100644
--- a/misc/wasm/wasm_exec.js
+++ b/misc/wasm/wasm_exec.js
@@ -175,37 +175,19 @@
const storeValue = (addr, v) => {
const nanHead = 0x7FF80000;
- if (typeof v === "number") {
+ if (typeof v === "number" && v !== 0) {
if (isNaN(v)) {
this.mem.setUint32(addr + 4, nanHead, true);
this.mem.setUint32(addr, 0, true);
return;
}
- if (v === 0) {
- this.mem.setUint32(addr + 4, nanHead, true);
- this.mem.setUint32(addr, 1, true);
- return;
- }
this.mem.setFloat64(addr, v, true);
return;
}
- switch (v) {
- case undefined:
- this.mem.setFloat64(addr, 0, true);
- return;
- case null:
- this.mem.setUint32(addr + 4, nanHead, true);
- this.mem.setUint32(addr, 2, true);
- return;
- case true:
- this.mem.setUint32(addr + 4, nanHead, true);
- this.mem.setUint32(addr, 3, true);
- return;
- case false:
- this.mem.setUint32(addr + 4, nanHead, true);
- this.mem.setUint32(addr, 4, true);
- return;
+ if (v === undefined) {
+ this.mem.setFloat64(addr, 0, true);
+ return;
}
let id = this._ids.get(v);
@@ -219,8 +201,13 @@
this._ids.set(v, id);
}
this._goRefCounts[id]++;
- let typeFlag = 1;
+ let typeFlag = 0;
switch (typeof v) {
+ case "object":
+ if (v !== null) {
+ typeFlag = 1;
+ }
+ break;
case "string":
typeFlag = 2;
break;
@@ -493,10 +480,17 @@
global,
this,
];
- this._goRefCounts = []; // number of references that Go has to a JS value, indexed by reference id
- this._ids = new Map(); // mapping from JS values to reference ids
- this._idPool = []; // unused ids that have been garbage collected
- this.exited = false; // whether the Go program has exited
+ this._goRefCounts = new Array(this._values.length).fill(Infinity); // number of references that Go has to a JS value, indexed by reference id
+ this._ids = new Map([ // mapping from JS values to reference ids
+ [0, 1],
+ [null, 2],
+ [true, 3],
+ [false, 4],
+ [global, 5],
+ [this, 6],
+ ]);
+ this._idPool = []; // unused ids that have been garbage collected
+ this.exited = false; // whether the Go program has exited
// Pass command line arguments and environment variables to WebAssembly by writing them to the linear memory.
let offset = 4096;
diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s
index c0e2fb7..69267bf 100644
--- a/src/cmd/asm/internal/asm/testdata/arm64.s
+++ b/src/cmd/asm/internal/asm/testdata/arm64.s
@@ -274,6 +274,9 @@
ADDW $0x60060, R2 // ADDW $393312, R2 // 4280011142804111
CMPW $0x60060, R2 // CMPW $393312, R2 // 1b0c8052db00a0725f001b6b
+ // TODO: this could have better encoding
+ ANDW $-1, R10 // 1b0080124a011b0a
+
AND $8, R0, RSP // 1f007d92
ORR $8, R0, RSP // 1f007db2
EOR $8, R0, RSP // 1f007dd2
diff --git a/src/cmd/compile/internal/gc/noder.go b/src/cmd/compile/internal/gc/noder.go
index 31fe46a..802aab2 100644
--- a/src/cmd/compile/internal/gc/noder.go
+++ b/src/cmd/compile/internal/gc/noder.go
@@ -44,7 +44,7 @@
f, err := os.Open(filename)
if err != nil {
- p.error(syntax.Error{Pos: syntax.MakePos(base, 0, 0), Msg: err.Error()})
+ p.error(syntax.Error{Msg: err.Error()})
return
}
defer f.Close()
diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go
index 2bbc5e4..9362c74 100644
--- a/src/cmd/compile/internal/gc/subr.go
+++ b/src/cmd/compile/internal/gc/subr.go
@@ -60,9 +60,15 @@
}
func adderr(pos src.XPos, format string, args ...interface{}) {
+ msg := fmt.Sprintf(format, args...)
+ // Only add the position if know the position.
+ // See issue golang.org/issue/11361.
+ if pos.IsKnown() {
+ msg = fmt.Sprintf("%v: %s", linestr(pos), msg)
+ }
errors = append(errors, Error{
pos: pos,
- msg: fmt.Sprintf("%v: %s\n", linestr(pos), fmt.Sprintf(format, args...)),
+ msg: msg + "\n",
})
}
diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go
index 8132aee..dec4b96 100644
--- a/src/cmd/compile/internal/gc/typecheck.go
+++ b/src/cmd/compile/internal/gc/typecheck.go
@@ -2967,6 +2967,8 @@
if ci := lookdot1(nil, l.Sym, t, t.Fields(), 2); ci != nil { // Case-insensitive lookup.
if visible(ci.Sym) {
yyerror("unknown field '%v' in struct literal of type %v (but does have %v)", l.Sym, t, ci.Sym)
+ } else if nonexported(l.Sym) && l.Sym.Name == ci.Sym.Name { // Ensure exactness before the suggestion.
+ yyerror("cannot refer to unexported field '%v' in struct literal of type %v", l.Sym, t)
} else {
yyerror("unknown field '%v' in struct literal of type %v", l.Sym, t)
}
@@ -3070,6 +3072,11 @@
return sym != nil && (types.IsExported(sym.Name) || sym.Pkg == localpkg)
}
+// nonexported reports whether sym is an unexported field.
+func nonexported(sym *types.Sym) bool {
+ return sym != nil && !types.IsExported(sym.Name)
+}
+
// lvalue etc
func islvalue(n *Node) bool {
switch n.Op {
diff --git a/src/cmd/compile/internal/ssa/cse.go b/src/cmd/compile/internal/ssa/cse.go
index 15dfe6d..6bfd296 100644
--- a/src/cmd/compile/internal/ssa/cse.go
+++ b/src/cmd/compile/internal/ssa/cse.go
@@ -190,43 +190,6 @@
}
}
- // if we rewrite a tuple generator to a new one in a different block,
- // copy its selectors to the new generator's block, so tuple generator
- // and selectors stay together.
- // be careful not to copy same selectors more than once (issue 16741).
- copiedSelects := make(map[ID][]*Value)
- for _, b := range f.Blocks {
- out:
- for _, v := range b.Values {
- // New values are created when selectors are copied to
- // a new block. We can safely ignore those new values,
- // since they have already been copied (issue 17918).
- if int(v.ID) >= len(rewrite) || rewrite[v.ID] != nil {
- continue
- }
- if v.Op != OpSelect0 && v.Op != OpSelect1 {
- continue
- }
- if !v.Args[0].Type.IsTuple() {
- f.Fatalf("arg of tuple selector %s is not a tuple: %s", v.String(), v.Args[0].LongString())
- }
- t := rewrite[v.Args[0].ID]
- if t != nil && t.Block != b {
- // v.Args[0] is tuple generator, CSE'd into a different block as t, v is left behind
- for _, c := range copiedSelects[t.ID] {
- if v.Op == c.Op {
- // an equivalent selector is already copied
- rewrite[v.ID] = c
- continue out
- }
- }
- c := v.copyInto(t.Block)
- rewrite[v.ID] = c
- copiedSelects[t.ID] = append(copiedSelects[t.ID], c)
- }
- }
- }
-
rewrites := int64(0)
// Apply substitutions
@@ -259,6 +222,61 @@
}
}
}
+
+ // Fixup tuple selectors.
+ //
+ // If we have rewritten a tuple generator to a new one in a different
+ // block, copy its selectors to the new generator's block, so tuple
+ // generator and selectors stay together.
+ //
+ // Note: that there must be only one selector of each type per tuple
+ // generator. CSE may have left us with more than one so we de-duplicate
+ // them using a map. See issue 16741.
+ selectors := make(map[struct {
+ id ID
+ op Op
+ }]*Value)
+ for _, b := range f.Blocks {
+ for _, selector := range b.Values {
+ if selector.Op != OpSelect0 && selector.Op != OpSelect1 {
+ continue
+ }
+
+ // Get the tuple generator to use as a key for de-duplication.
+ tuple := selector.Args[0]
+ if !tuple.Type.IsTuple() {
+ f.Fatalf("arg of tuple selector %s is not a tuple: %s", selector.String(), tuple.LongString())
+ }
+
+ // If there is a pre-existing selector in the target block then
+ // use that. Do this even if the selector is already in the
+ // target block to avoid duplicate tuple selectors.
+ key := struct {
+ id ID
+ op Op
+ }{tuple.ID, selector.Op}
+ if t := selectors[key]; t != nil {
+ if selector != t {
+ selector.copyOf(t)
+ }
+ continue
+ }
+
+ // If the selector is in the wrong block copy it into the target
+ // block.
+ if selector.Block != tuple.Block {
+ t := selector.copyInto(tuple.Block)
+ selector.copyOf(t)
+ selectors[key] = t
+ continue
+ }
+
+ // The selector is in the target block. Add it to the map so it
+ // cannot be duplicated.
+ selectors[key] = selector
+ }
+ }
+
if f.pass.stats > 0 {
f.LogStat("CSE REWRITES", rewrites)
}
diff --git a/src/cmd/compile/internal/ssa/gen/PPC64.rules b/src/cmd/compile/internal/ssa/gen/PPC64.rules
index 761ffa2..fd28e10 100644
--- a/src/cmd/compile/internal/ssa/gen/PPC64.rules
+++ b/src/cmd/compile/internal/ssa/gen/PPC64.rules
@@ -153,18 +153,18 @@
(Rsh8x64 x (MOVDconst [c])) && uint64(c) < 8 => (SRAWconst (SignExt8to32 x) [c])
(Rsh8Ux64 x (MOVDconst [c])) && uint64(c) < 8 => (SRWconst (ZeroExt8to32 x) [c])
-(Lsh64x32 x (MOVDconst [c])) && uint32(c) < 64 => (SLDconst x [c])
-(Rsh64x32 x (MOVDconst [c])) && uint32(c) < 64 => (SRADconst x [c])
-(Rsh64Ux32 x (MOVDconst [c])) && uint32(c) < 64 => (SRDconst x [c])
-(Lsh32x32 x (MOVDconst [c])) && uint32(c) < 32 => (SLWconst x [c])
-(Rsh32x32 x (MOVDconst [c])) && uint32(c) < 32 => (SRAWconst x [c])
-(Rsh32Ux32 x (MOVDconst [c])) && uint32(c) < 32 => (SRWconst x [c])
-(Lsh16x32 x (MOVDconst [c])) && uint32(c) < 16 => (SLWconst x [c])
-(Rsh16x32 x (MOVDconst [c])) && uint32(c) < 16 => (SRAWconst (SignExt16to32 x) [c])
-(Rsh16Ux32 x (MOVDconst [c])) && uint32(c) < 16 => (SRWconst (ZeroExt16to32 x) [c])
-(Lsh8x32 x (MOVDconst [c])) && uint32(c) < 8 => (SLWconst x [c])
-(Rsh8x32 x (MOVDconst [c])) && uint32(c) < 8 => (SRAWconst (SignExt8to32 x) [c])
-(Rsh8Ux32 x (MOVDconst [c])) && uint32(c) < 8 => (SRWconst (ZeroExt8to32 x) [c])
+(Lsh64x32 x (MOVDconst [c])) && uint32(c) < 64 => (SLDconst x [c&63])
+(Rsh64x32 x (MOVDconst [c])) && uint32(c) < 64 => (SRADconst x [c&63])
+(Rsh64Ux32 x (MOVDconst [c])) && uint32(c) < 64 => (SRDconst x [c&63])
+(Lsh32x32 x (MOVDconst [c])) && uint32(c) < 32 => (SLWconst x [c&31])
+(Rsh32x32 x (MOVDconst [c])) && uint32(c) < 32 => (SRAWconst x [c&31])
+(Rsh32Ux32 x (MOVDconst [c])) && uint32(c) < 32 => (SRWconst x [c&31])
+(Lsh16x32 x (MOVDconst [c])) && uint32(c) < 16 => (SLWconst x [c&31])
+(Rsh16x32 x (MOVDconst [c])) && uint32(c) < 16 => (SRAWconst (SignExt16to32 x) [c&15])
+(Rsh16Ux32 x (MOVDconst [c])) && uint32(c) < 16 => (SRWconst (ZeroExt16to32 x) [c&15])
+(Lsh8x32 x (MOVDconst [c])) && uint32(c) < 8 => (SLWconst x [c&7])
+(Rsh8x32 x (MOVDconst [c])) && uint32(c) < 8 => (SRAWconst (SignExt8to32 x) [c&7])
+(Rsh8Ux32 x (MOVDconst [c])) && uint32(c) < 8 => (SRWconst (ZeroExt8to32 x) [c&7])
// Lower bounded shifts first. No need to check shift value.
(Lsh64x(64|32|16|8) x y) && shiftIsBounded(v) => (SLD x y)
@@ -285,7 +285,8 @@
(MaskIfNotCarry (FlagCarrySet)) => (MOVDconst [0])
(MaskIfNotCarry (FlagCarryClear)) => (MOVDconst [-1])
-(S(RAD|RAW|RD|RW|LD|LW) x (MOVDconst [c])) => (S(RAD|RAW|RD|RW|LD|LW)const [c] x)
+(S(RAD|RD|LD) x (MOVDconst [c])) => (S(RAD|RD|LD)const [c&63 | (c>>6&1*63)] x)
+(S(RAW|RW|LW) x (MOVDconst [c])) => (S(RAW|RW|LW)const [c&31 | (c>>5&1*31)] x)
(Addr {sym} base) => (MOVDaddr {sym} [0] base)
(LocalAddr {sym} base _) => (MOVDaddr {sym} base)
diff --git a/src/cmd/compile/internal/ssa/gen/PPC64Ops.go b/src/cmd/compile/internal/ssa/gen/PPC64Ops.go
index a665734..f8bc6cb 100644
--- a/src/cmd/compile/internal/ssa/gen/PPC64Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/PPC64Ops.go
@@ -194,12 +194,12 @@
{name: "FMSUB", argLength: 3, reg: fp31, asm: "FMSUB"}, // arg0*arg1 - arg2
{name: "FMSUBS", argLength: 3, reg: fp31, asm: "FMSUBS"}, // arg0*arg1 - arg2
- {name: "SRAD", argLength: 2, reg: gp21, asm: "SRAD"}, // arg0 >>a arg1, 64 bits (all sign if arg1 & 64 != 0)
- {name: "SRAW", argLength: 2, reg: gp21, asm: "SRAW"}, // arg0 >>a arg1, 32 bits (all sign if arg1 & 32 != 0)
- {name: "SRD", argLength: 2, reg: gp21, asm: "SRD"}, // arg0 >> arg1, 64 bits (0 if arg1 & 64 != 0)
- {name: "SRW", argLength: 2, reg: gp21, asm: "SRW"}, // arg0 >> arg1, 32 bits (0 if arg1 & 32 != 0)
- {name: "SLD", argLength: 2, reg: gp21, asm: "SLD"}, // arg0 << arg1, 64 bits (0 if arg1 & 64 != 0)
- {name: "SLW", argLength: 2, reg: gp21, asm: "SLW"}, // arg0 << arg1, 32 bits (0 if arg1 & 32 != 0)
+ {name: "SRAD", argLength: 2, reg: gp21, asm: "SRAD"}, // signed arg0 >> (arg1&127), 64 bit width (note: 127, not 63!)
+ {name: "SRAW", argLength: 2, reg: gp21, asm: "SRAW"}, // signed arg0 >> (arg1&63), 32 bit width
+ {name: "SRD", argLength: 2, reg: gp21, asm: "SRD"}, // unsigned arg0 >> (arg1&127), 64 bit width
+ {name: "SRW", argLength: 2, reg: gp21, asm: "SRW"}, // unsigned arg0 >> (arg1&63), 32 bit width
+ {name: "SLD", argLength: 2, reg: gp21, asm: "SLD"}, // arg0 << (arg1&127), 64 bit width
+ {name: "SLW", argLength: 2, reg: gp21, asm: "SLW"}, // arg0 << (arg1&63), 32 bit width
{name: "ROTL", argLength: 2, reg: gp21, asm: "ROTL"}, // arg0 rotate left by arg1 mod 64
{name: "ROTLW", argLength: 2, reg: gp21, asm: "ROTLW"}, // uint32(arg0) rotate left by arg1 mod 32
@@ -208,12 +208,12 @@
{name: "ADDconstForCarry", argLength: 1, reg: regInfo{inputs: []regMask{gp | sp | sb}, clobbers: tmp}, aux: "Int16", asm: "ADDC", typ: "Flags"}, // _, carry := arg0 + auxint
{name: "MaskIfNotCarry", argLength: 1, reg: crgp, asm: "ADDME", typ: "Int64"}, // carry - 1 (if carry then 0 else -1)
- {name: "SRADconst", argLength: 1, reg: gp11, asm: "SRAD", aux: "Int64"}, // arg0 >>a aux, 64 bits
- {name: "SRAWconst", argLength: 1, reg: gp11, asm: "SRAW", aux: "Int64"}, // arg0 >>a aux, 32 bits
- {name: "SRDconst", argLength: 1, reg: gp11, asm: "SRD", aux: "Int64"}, // arg0 >> aux, 64 bits
- {name: "SRWconst", argLength: 1, reg: gp11, asm: "SRW", aux: "Int64"}, // arg0 >> aux, 32 bits
- {name: "SLDconst", argLength: 1, reg: gp11, asm: "SLD", aux: "Int64"}, // arg0 << aux, 64 bits
- {name: "SLWconst", argLength: 1, reg: gp11, asm: "SLW", aux: "Int64"}, // arg0 << aux, 32 bits
+ {name: "SRADconst", argLength: 1, reg: gp11, asm: "SRAD", aux: "Int64"}, // signed arg0 >> auxInt, 0 <= auxInt < 64, 64 bit width
+ {name: "SRAWconst", argLength: 1, reg: gp11, asm: "SRAW", aux: "Int64"}, // signed arg0 >> auxInt, 0 <= auxInt < 32, 32 bit width
+ {name: "SRDconst", argLength: 1, reg: gp11, asm: "SRD", aux: "Int64"}, // unsigned arg0 >> auxInt, 0 <= auxInt < 64, 64 bit width
+ {name: "SRWconst", argLength: 1, reg: gp11, asm: "SRW", aux: "Int64"}, // unsigned arg0 >> auxInt, 0 <= auxInt < 32, 32 bit width
+ {name: "SLDconst", argLength: 1, reg: gp11, asm: "SLD", aux: "Int64"}, // arg0 << auxInt, 0 <= auxInt < 64, 64 bit width
+ {name: "SLWconst", argLength: 1, reg: gp11, asm: "SLW", aux: "Int64"}, // arg0 << auxInt, 0 <= auxInt < 32, 32 bit width
{name: "ROTLconst", argLength: 1, reg: gp11, asm: "ROTL", aux: "Int64"}, // arg0 rotate left by auxInt bits
{name: "ROTLWconst", argLength: 1, reg: gp11, asm: "ROTLW", aux: "Int64"}, // uint32(arg0) rotate left by auxInt bits
diff --git a/src/cmd/compile/internal/ssa/gen/RISCV64.rules b/src/cmd/compile/internal/ssa/gen/RISCV64.rules
index fbd8736..9437c8e 100644
--- a/src/cmd/compile/internal/ssa/gen/RISCV64.rules
+++ b/src/cmd/compile/internal/ssa/gen/RISCV64.rules
@@ -445,16 +445,6 @@
(Addr {sym} base) => (MOVaddr {sym} [0] base)
(LocalAddr {sym} base _) => (MOVaddr {sym} base)
-// Conditional branches
-//
-// cond is 1 if true.
-//
-// TODO(prattmic): RISCV branch instructions take two operands to compare,
-// so we could generate more efficient code by computing the condition in the
-// branch itself. This should be revisited now that the compiler has support
-// for two control values (https://golang.org/cl/196557).
-(If cond yes no) => (BNEZ cond yes no)
-
// Calls
(StaticCall ...) => (CALLstatic ...)
(ClosureCall ...) => (CALLclosure ...)
@@ -480,11 +470,31 @@
(AtomicExchange32 ...) => (LoweredAtomicExchange32 ...)
(AtomicExchange64 ...) => (LoweredAtomicExchange64 ...)
+// Conditional branches
+(If cond yes no) => (BNEZ cond yes no)
+
// Optimizations
-// Absorb SNEZ into branch.
+// Absorb SEQZ/SNEZ into branch.
+(BEQZ (SEQZ x) yes no) => (BNEZ x yes no)
+(BEQZ (SNEZ x) yes no) => (BEQZ x yes no)
+(BNEZ (SEQZ x) yes no) => (BEQZ x yes no)
(BNEZ (SNEZ x) yes no) => (BNEZ x yes no)
+// Convert BEQZ/BNEZ into more optimal branch conditions.
+(BEQZ (SUB x y) yes no) => (BEQ x y yes no)
+(BNEZ (SUB x y) yes no) => (BNE x y yes no)
+(BEQZ (SLT x y) yes no) => (BGE x y yes no)
+(BNEZ (SLT x y) yes no) => (BLT x y yes no)
+(BEQZ (SLTU x y) yes no) => (BGEU x y yes no)
+(BNEZ (SLTU x y) yes no) => (BLTU x y yes no)
+
+// Convert branch with zero to BEQZ/BNEZ.
+(BEQ (MOVDconst [0]) cond yes no) => (BEQZ cond yes no)
+(BEQ cond (MOVDconst [0]) yes no) => (BEQZ cond yes no)
+(BNE (MOVDconst [0]) cond yes no) => (BNEZ cond yes no)
+(BNE cond (MOVDconst [0]) yes no) => (BNEZ cond yes no)
+
// Store zero
(MOVBstore [off] {sym} ptr (MOVBconst [0]) mem) => (MOVBstorezero [off] {sym} ptr mem)
(MOVHstore [off] {sym} ptr (MOVHconst [0]) mem) => (MOVHstorezero [off] {sym} ptr mem)
diff --git a/src/cmd/compile/internal/ssa/prove.go b/src/cmd/compile/internal/ssa/prove.go
index 12c2580..a8e43d0 100644
--- a/src/cmd/compile/internal/ssa/prove.go
+++ b/src/cmd/compile/internal/ssa/prove.go
@@ -1189,15 +1189,38 @@
}
v.Op = ctzNonZeroOp[v.Op]
}
-
+ case OpRsh8x8, OpRsh8x16, OpRsh8x32, OpRsh8x64,
+ OpRsh16x8, OpRsh16x16, OpRsh16x32, OpRsh16x64,
+ OpRsh32x8, OpRsh32x16, OpRsh32x32, OpRsh32x64,
+ OpRsh64x8, OpRsh64x16, OpRsh64x32, OpRsh64x64:
+ // Check whether, for a >> b, we know that a is non-negative
+ // and b is all of a's bits except the MSB. If so, a is shifted to zero.
+ bits := 8 * v.Type.Size()
+ if v.Args[1].isGenericIntConst() && v.Args[1].AuxInt >= bits-1 && ft.isNonNegative(v.Args[0]) {
+ if b.Func.pass.debug > 0 {
+ b.Func.Warnl(v.Pos, "Proved %v shifts to zero", v.Op)
+ }
+ switch bits {
+ case 64:
+ v.reset(OpConst64)
+ case 32:
+ v.reset(OpConst32)
+ case 16:
+ v.reset(OpConst16)
+ case 8:
+ v.reset(OpConst8)
+ default:
+ panic("unexpected integer size")
+ }
+ v.AuxInt = 0
+ continue // Be sure not to fallthrough - this is no longer OpRsh.
+ }
+ // If the Rsh hasn't been replaced with 0, still check if it is bounded.
+ fallthrough
case OpLsh8x8, OpLsh8x16, OpLsh8x32, OpLsh8x64,
OpLsh16x8, OpLsh16x16, OpLsh16x32, OpLsh16x64,
OpLsh32x8, OpLsh32x16, OpLsh32x32, OpLsh32x64,
OpLsh64x8, OpLsh64x16, OpLsh64x32, OpLsh64x64,
- OpRsh8x8, OpRsh8x16, OpRsh8x32, OpRsh8x64,
- OpRsh16x8, OpRsh16x16, OpRsh16x32, OpRsh16x64,
- OpRsh32x8, OpRsh32x16, OpRsh32x32, OpRsh32x64,
- OpRsh64x8, OpRsh64x16, OpRsh64x32, OpRsh64x64,
OpRsh8Ux8, OpRsh8Ux16, OpRsh8Ux32, OpRsh8Ux64,
OpRsh16Ux8, OpRsh16Ux16, OpRsh16Ux32, OpRsh16Ux64,
OpRsh32Ux8, OpRsh32Ux16, OpRsh32Ux32, OpRsh32Ux64,
diff --git a/src/cmd/compile/internal/ssa/rewritePPC64.go b/src/cmd/compile/internal/ssa/rewritePPC64.go
index 6a2c164..37b75cc 100644
--- a/src/cmd/compile/internal/ssa/rewritePPC64.go
+++ b/src/cmd/compile/internal/ssa/rewritePPC64.go
@@ -2351,7 +2351,7 @@
typ := &b.Func.Config.Types
// match: (Lsh16x32 x (MOVDconst [c]))
// cond: uint32(c) < 16
- // result: (SLWconst x [c])
+ // result: (SLWconst x [c&31])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -2362,7 +2362,7 @@
break
}
v.reset(OpPPC64SLWconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c & 31)
v.AddArg(x)
return true
}
@@ -2552,7 +2552,7 @@
typ := &b.Func.Config.Types
// match: (Lsh32x32 x (MOVDconst [c]))
// cond: uint32(c) < 32
- // result: (SLWconst x [c])
+ // result: (SLWconst x [c&31])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -2563,7 +2563,7 @@
break
}
v.reset(OpPPC64SLWconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c & 31)
v.AddArg(x)
return true
}
@@ -2792,7 +2792,7 @@
typ := &b.Func.Config.Types
// match: (Lsh64x32 x (MOVDconst [c]))
// cond: uint32(c) < 64
- // result: (SLDconst x [c])
+ // result: (SLDconst x [c&63])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -2803,7 +2803,7 @@
break
}
v.reset(OpPPC64SLDconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c & 63)
v.AddArg(x)
return true
}
@@ -3032,7 +3032,7 @@
typ := &b.Func.Config.Types
// match: (Lsh8x32 x (MOVDconst [c]))
// cond: uint32(c) < 8
- // result: (SLWconst x [c])
+ // result: (SLWconst x [c&7])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -3043,7 +3043,7 @@
break
}
v.reset(OpPPC64SLWconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c & 7)
v.AddArg(x)
return true
}
@@ -12046,7 +12046,7 @@
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (SLD x (MOVDconst [c]))
- // result: (SLDconst [c] x)
+ // result: (SLDconst [c&63 | (c>>6&1*63)] x)
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -12054,7 +12054,7 @@
}
c := auxIntToInt64(v_1.AuxInt)
v.reset(OpPPC64SLDconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c&63 | (c >> 6 & 1 * 63))
v.AddArg(x)
return true
}
@@ -12064,7 +12064,7 @@
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (SLW x (MOVDconst [c]))
- // result: (SLWconst [c] x)
+ // result: (SLWconst [c&31 | (c>>5&1*31)] x)
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -12072,7 +12072,7 @@
}
c := auxIntToInt64(v_1.AuxInt)
v.reset(OpPPC64SLWconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c&31 | (c >> 5 & 1 * 31))
v.AddArg(x)
return true
}
@@ -12082,7 +12082,7 @@
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (SRAD x (MOVDconst [c]))
- // result: (SRADconst [c] x)
+ // result: (SRADconst [c&63 | (c>>6&1*63)] x)
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -12090,7 +12090,7 @@
}
c := auxIntToInt64(v_1.AuxInt)
v.reset(OpPPC64SRADconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c&63 | (c >> 6 & 1 * 63))
v.AddArg(x)
return true
}
@@ -12100,7 +12100,7 @@
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (SRAW x (MOVDconst [c]))
- // result: (SRAWconst [c] x)
+ // result: (SRAWconst [c&31 | (c>>5&1*31)] x)
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -12108,7 +12108,7 @@
}
c := auxIntToInt64(v_1.AuxInt)
v.reset(OpPPC64SRAWconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c&31 | (c >> 5 & 1 * 31))
v.AddArg(x)
return true
}
@@ -12118,7 +12118,7 @@
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (SRD x (MOVDconst [c]))
- // result: (SRDconst [c] x)
+ // result: (SRDconst [c&63 | (c>>6&1*63)] x)
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -12126,7 +12126,7 @@
}
c := auxIntToInt64(v_1.AuxInt)
v.reset(OpPPC64SRDconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c&63 | (c >> 6 & 1 * 63))
v.AddArg(x)
return true
}
@@ -12136,7 +12136,7 @@
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (SRW x (MOVDconst [c]))
- // result: (SRWconst [c] x)
+ // result: (SRWconst [c&31 | (c>>5&1*31)] x)
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -12144,7 +12144,7 @@
}
c := auxIntToInt64(v_1.AuxInt)
v.reset(OpPPC64SRWconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c&31 | (c >> 5 & 1 * 31))
v.AddArg(x)
return true
}
@@ -12630,7 +12630,7 @@
typ := &b.Func.Config.Types
// match: (Rsh16Ux32 x (MOVDconst [c]))
// cond: uint32(c) < 16
- // result: (SRWconst (ZeroExt16to32 x) [c])
+ // result: (SRWconst (ZeroExt16to32 x) [c&15])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -12641,7 +12641,7 @@
break
}
v.reset(OpPPC64SRWconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c & 15)
v0 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
v0.AddArg(x)
v.AddArg(v0)
@@ -12851,7 +12851,7 @@
typ := &b.Func.Config.Types
// match: (Rsh16x32 x (MOVDconst [c]))
// cond: uint32(c) < 16
- // result: (SRAWconst (SignExt16to32 x) [c])
+ // result: (SRAWconst (SignExt16to32 x) [c&15])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -12862,7 +12862,7 @@
break
}
v.reset(OpPPC64SRAWconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c & 15)
v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
v0.AddArg(x)
v.AddArg(v0)
@@ -13072,7 +13072,7 @@
typ := &b.Func.Config.Types
// match: (Rsh32Ux32 x (MOVDconst [c]))
// cond: uint32(c) < 32
- // result: (SRWconst x [c])
+ // result: (SRWconst x [c&31])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -13083,7 +13083,7 @@
break
}
v.reset(OpPPC64SRWconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c & 31)
v.AddArg(x)
return true
}
@@ -13377,7 +13377,7 @@
typ := &b.Func.Config.Types
// match: (Rsh32x32 x (MOVDconst [c]))
// cond: uint32(c) < 32
- // result: (SRAWconst x [c])
+ // result: (SRAWconst x [c&31])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -13388,7 +13388,7 @@
break
}
v.reset(OpPPC64SRAWconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c & 31)
v.AddArg(x)
return true
}
@@ -13684,7 +13684,7 @@
typ := &b.Func.Config.Types
// match: (Rsh64Ux32 x (MOVDconst [c]))
// cond: uint32(c) < 64
- // result: (SRDconst x [c])
+ // result: (SRDconst x [c&63])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -13695,7 +13695,7 @@
break
}
v.reset(OpPPC64SRDconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c & 63)
v.AddArg(x)
return true
}
@@ -13989,7 +13989,7 @@
typ := &b.Func.Config.Types
// match: (Rsh64x32 x (MOVDconst [c]))
// cond: uint32(c) < 64
- // result: (SRADconst x [c])
+ // result: (SRADconst x [c&63])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -14000,7 +14000,7 @@
break
}
v.reset(OpPPC64SRADconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c & 63)
v.AddArg(x)
return true
}
@@ -14300,7 +14300,7 @@
typ := &b.Func.Config.Types
// match: (Rsh8Ux32 x (MOVDconst [c]))
// cond: uint32(c) < 8
- // result: (SRWconst (ZeroExt8to32 x) [c])
+ // result: (SRWconst (ZeroExt8to32 x) [c&7])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -14311,7 +14311,7 @@
break
}
v.reset(OpPPC64SRWconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c & 7)
v0 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
v0.AddArg(x)
v.AddArg(v0)
@@ -14521,7 +14521,7 @@
typ := &b.Func.Config.Types
// match: (Rsh8x32 x (MOVDconst [c]))
// cond: uint32(c) < 8
- // result: (SRAWconst (SignExt8to32 x) [c])
+ // result: (SRAWconst (SignExt8to32 x) [c&7])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -14532,7 +14532,7 @@
break
}
v.reset(OpPPC64SRAWconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c & 7)
v0 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
v0.AddArg(x)
v.AddArg(v0)
diff --git a/src/cmd/compile/internal/ssa/rewriteRISCV64.go b/src/cmd/compile/internal/ssa/rewriteRISCV64.go
index 6b91c08..c178290 100644
--- a/src/cmd/compile/internal/ssa/rewriteRISCV64.go
+++ b/src/cmd/compile/internal/ssa/rewriteRISCV64.go
@@ -5120,7 +5120,105 @@
}
func rewriteBlockRISCV64(b *Block) bool {
switch b.Kind {
+ case BlockRISCV64BEQ:
+ // match: (BEQ (MOVDconst [0]) cond yes no)
+ // result: (BEQZ cond yes no)
+ for b.Controls[0].Op == OpRISCV64MOVDconst {
+ v_0 := b.Controls[0]
+ if auxIntToInt64(v_0.AuxInt) != 0 {
+ break
+ }
+ cond := b.Controls[1]
+ b.resetWithControl(BlockRISCV64BEQZ, cond)
+ return true
+ }
+ // match: (BEQ cond (MOVDconst [0]) yes no)
+ // result: (BEQZ cond yes no)
+ for b.Controls[1].Op == OpRISCV64MOVDconst {
+ cond := b.Controls[0]
+ v_1 := b.Controls[1]
+ if auxIntToInt64(v_1.AuxInt) != 0 {
+ break
+ }
+ b.resetWithControl(BlockRISCV64BEQZ, cond)
+ return true
+ }
+ case BlockRISCV64BEQZ:
+ // match: (BEQZ (SEQZ x) yes no)
+ // result: (BNEZ x yes no)
+ for b.Controls[0].Op == OpRISCV64SEQZ {
+ v_0 := b.Controls[0]
+ x := v_0.Args[0]
+ b.resetWithControl(BlockRISCV64BNEZ, x)
+ return true
+ }
+ // match: (BEQZ (SNEZ x) yes no)
+ // result: (BEQZ x yes no)
+ for b.Controls[0].Op == OpRISCV64SNEZ {
+ v_0 := b.Controls[0]
+ x := v_0.Args[0]
+ b.resetWithControl(BlockRISCV64BEQZ, x)
+ return true
+ }
+ // match: (BEQZ (SUB x y) yes no)
+ // result: (BEQ x y yes no)
+ for b.Controls[0].Op == OpRISCV64SUB {
+ v_0 := b.Controls[0]
+ y := v_0.Args[1]
+ x := v_0.Args[0]
+ b.resetWithControl2(BlockRISCV64BEQ, x, y)
+ return true
+ }
+ // match: (BEQZ (SLT x y) yes no)
+ // result: (BGE x y yes no)
+ for b.Controls[0].Op == OpRISCV64SLT {
+ v_0 := b.Controls[0]
+ y := v_0.Args[1]
+ x := v_0.Args[0]
+ b.resetWithControl2(BlockRISCV64BGE, x, y)
+ return true
+ }
+ // match: (BEQZ (SLTU x y) yes no)
+ // result: (BGEU x y yes no)
+ for b.Controls[0].Op == OpRISCV64SLTU {
+ v_0 := b.Controls[0]
+ y := v_0.Args[1]
+ x := v_0.Args[0]
+ b.resetWithControl2(BlockRISCV64BGEU, x, y)
+ return true
+ }
+ case BlockRISCV64BNE:
+ // match: (BNE (MOVDconst [0]) cond yes no)
+ // result: (BNEZ cond yes no)
+ for b.Controls[0].Op == OpRISCV64MOVDconst {
+ v_0 := b.Controls[0]
+ if auxIntToInt64(v_0.AuxInt) != 0 {
+ break
+ }
+ cond := b.Controls[1]
+ b.resetWithControl(BlockRISCV64BNEZ, cond)
+ return true
+ }
+ // match: (BNE cond (MOVDconst [0]) yes no)
+ // result: (BNEZ cond yes no)
+ for b.Controls[1].Op == OpRISCV64MOVDconst {
+ cond := b.Controls[0]
+ v_1 := b.Controls[1]
+ if auxIntToInt64(v_1.AuxInt) != 0 {
+ break
+ }
+ b.resetWithControl(BlockRISCV64BNEZ, cond)
+ return true
+ }
case BlockRISCV64BNEZ:
+ // match: (BNEZ (SEQZ x) yes no)
+ // result: (BEQZ x yes no)
+ for b.Controls[0].Op == OpRISCV64SEQZ {
+ v_0 := b.Controls[0]
+ x := v_0.Args[0]
+ b.resetWithControl(BlockRISCV64BEQZ, x)
+ return true
+ }
// match: (BNEZ (SNEZ x) yes no)
// result: (BNEZ x yes no)
for b.Controls[0].Op == OpRISCV64SNEZ {
@@ -5129,6 +5227,33 @@
b.resetWithControl(BlockRISCV64BNEZ, x)
return true
}
+ // match: (BNEZ (SUB x y) yes no)
+ // result: (BNE x y yes no)
+ for b.Controls[0].Op == OpRISCV64SUB {
+ v_0 := b.Controls[0]
+ y := v_0.Args[1]
+ x := v_0.Args[0]
+ b.resetWithControl2(BlockRISCV64BNE, x, y)
+ return true
+ }
+ // match: (BNEZ (SLT x y) yes no)
+ // result: (BLT x y yes no)
+ for b.Controls[0].Op == OpRISCV64SLT {
+ v_0 := b.Controls[0]
+ y := v_0.Args[1]
+ x := v_0.Args[0]
+ b.resetWithControl2(BlockRISCV64BLT, x, y)
+ return true
+ }
+ // match: (BNEZ (SLTU x y) yes no)
+ // result: (BLTU x y yes no)
+ for b.Controls[0].Op == OpRISCV64SLTU {
+ v_0 := b.Controls[0]
+ y := v_0.Args[1]
+ x := v_0.Args[0]
+ b.resetWithControl2(BlockRISCV64BLTU, x, y)
+ return true
+ }
case BlockIf:
// match: (If cond yes no)
// result: (BNEZ cond yes no)
diff --git a/src/cmd/go.mod b/src/cmd/go.mod
index 1302449..9c78cd1 100644
--- a/src/cmd/go.mod
+++ b/src/cmd/go.mod
@@ -5,7 +5,7 @@
require (
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3
github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340 // indirect
- golang.org/x/arch v0.0.0-20200312215426-ff8b605520f4
+ golang.org/x/arch v0.0.0-20200511175325-f7c78586839d
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79
golang.org/x/mod v0.2.1-0.20200429172858-859b3ef565e2
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 // indirect
diff --git a/src/cmd/go.sum b/src/cmd/go.sum
index e66011d..f1b3754 100644
--- a/src/cmd/go.sum
+++ b/src/cmd/go.sum
@@ -7,8 +7,8 @@
github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340 h1:S1+yTUaFPXuDZnPDbO+TrDFIjPzQraYH8/CwSlu9Fac=
github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-golang.org/x/arch v0.0.0-20200312215426-ff8b605520f4 h1:cZG+Ns0n5bdEEsURGnDinFswSebRNMqspbLvxrLZoIc=
-golang.org/x/arch v0.0.0-20200312215426-ff8b605520f4/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
+golang.org/x/arch v0.0.0-20200511175325-f7c78586839d h1:YvwchuJby5xEAPdBGmdAVSiVME50C+RJfJJwJJsGEV8=
+golang.org/x/arch v0.0.0-20200511175325-f7c78586839d/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 h1:IaQbIIB2X/Mp/DKctl6ROxz1KyMlKp4uyvL6+kQ7C88=
diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go
index 81b4687..5c1f725 100644
--- a/src/cmd/go/alldocs.go
+++ b/src/cmd/go/alldocs.go
@@ -1313,10 +1313,10 @@
// and its test source files to identify significant problems. If go vet
// finds any problems, go test reports those and does not run the test
// binary. Only a high-confidence subset of the default go vet checks are
-// used. That subset is: 'atomic', 'bool', 'buildtags', 'nilfunc', and
-// 'printf'. You can see the documentation for these and other vet tests
-// via "go doc cmd/vet". To disable the running of go vet, use the
-// -vet=off flag.
+// used. That subset is: 'atomic', 'bool', 'buildtags', 'errorsas',
+// 'ifaceassert', 'nilfunc', 'printf', and 'stringintconv'. You can see
+// the documentation for these and other vet tests via "go doc cmd/vet".
+// To disable the running of go vet, use the -vet=off flag.
//
// All test output and summary lines are printed to the go command's
// standard output, even if the test printed them to its own standard
diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go
index d7f6b47..4c30de4 100644
--- a/src/cmd/go/go_test.go
+++ b/src/cmd/go/go_test.go
@@ -6,7 +6,6 @@
import (
"bytes"
- "context"
"debug/elf"
"debug/macho"
"debug/pe"
@@ -114,12 +113,6 @@
var testTmpDir string
var testBin string
-// testCtx is canceled when the test binary is about to time out.
-//
-// If https://golang.org/issue/28135 is accepted, uses of this variable in test
-// functions should be replaced by t.Context().
-var testCtx = context.Background()
-
// The TestMain function creates a go command for testing purposes and
// deletes it after the tests have been run.
func TestMain(m *testing.M) {
@@ -135,19 +128,6 @@
flag.Parse()
- timeoutFlag := flag.Lookup("test.timeout")
- if timeoutFlag != nil {
- // TODO(golang.org/issue/28147): The go command does not pass the
- // test.timeout flag unless either -timeout or -test.timeout is explicitly
- // set on the command line.
- if d := timeoutFlag.Value.(flag.Getter).Get().(time.Duration); d != 0 {
- aBitShorter := d * 95 / 100
- var cancel context.CancelFunc
- testCtx, cancel = context.WithTimeout(testCtx, aBitShorter)
- defer cancel()
- }
- }
-
if *proxyAddr != "" {
StartProxy()
select {}
@@ -829,10 +809,9 @@
// module cache has 0444 directories;
// make them writable in order to remove content.
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
- if err != nil {
- return nil // ignore errors walking in file system
- }
- if info.IsDir() {
+ // chmod not only directories, but also things that we couldn't even stat
+ // due to permission errors: they may also be unreadable directories.
+ if err != nil || info.IsDir() {
os.Chmod(path, 0777)
}
return nil
diff --git a/src/cmd/go/internal/modget/get.go b/src/cmd/go/internal/modget/get.go
index 8d74047..4c69824 100644
--- a/src/cmd/go/internal/modget/get.go
+++ b/src/cmd/go/internal/modget/get.go
@@ -350,11 +350,15 @@
// package in the main module. If the path contains wildcards but
// matches no packages, we'll warn after package loading.
if !strings.Contains(path, "...") {
- var pkgs []string
+ m := search.NewMatch(path)
if pkgPath := modload.DirImportPath(path); pkgPath != "." {
- pkgs = modload.TargetPackages(pkgPath)
+ m = modload.TargetPackages(pkgPath)
}
- if len(pkgs) == 0 {
+ if len(m.Pkgs) == 0 {
+ for _, err := range m.Errs {
+ base.Errorf("go get %s: %v", arg, err)
+ }
+
abs, err := filepath.Abs(path)
if err != nil {
abs = path
@@ -394,7 +398,7 @@
default:
// The argument is a package or module path.
if modload.HasModRoot() {
- if pkgs := modload.TargetPackages(path); len(pkgs) != 0 {
+ if m := modload.TargetPackages(path); len(m.Pkgs) != 0 {
// The path is in the main module. Nothing to query.
if vers != "upgrade" && vers != "patch" {
base.Errorf("go get %s: can't request explicit version of path in main module", arg)
diff --git a/src/cmd/go/internal/modload/import.go b/src/cmd/go/internal/modload/import.go
index 162c29d..4d2bc80 100644
--- a/src/cmd/go/internal/modload/import.go
+++ b/src/cmd/go/internal/modload/import.go
@@ -126,7 +126,9 @@
pathIsStd := search.IsStandardImportPath(path)
if pathIsStd && goroot.IsStandardPackage(cfg.GOROOT, cfg.BuildContext.Compiler, path) {
if targetInGorootSrc {
- if dir, ok := dirInModule(path, targetPrefix, ModRoot(), true); ok {
+ if dir, ok, err := dirInModule(path, targetPrefix, ModRoot(), true); err != nil {
+ return module.Version{}, dir, err
+ } else if ok {
return Target, dir, nil
}
}
@@ -137,8 +139,8 @@
// -mod=vendor is special.
// Everything must be in the main module or the main module's vendor directory.
if cfg.BuildMod == "vendor" {
- mainDir, mainOK := dirInModule(path, targetPrefix, ModRoot(), true)
- vendorDir, vendorOK := dirInModule(path, "", filepath.Join(ModRoot(), "vendor"), false)
+ mainDir, mainOK, mainErr := dirInModule(path, targetPrefix, ModRoot(), true)
+ vendorDir, vendorOK, _ := dirInModule(path, "", filepath.Join(ModRoot(), "vendor"), false)
if mainOK && vendorOK {
return module.Version{}, "", &AmbiguousImportError{importPath: path, Dirs: []string{mainDir, vendorDir}}
}
@@ -148,6 +150,9 @@
if !vendorOK && mainDir != "" {
return Target, mainDir, nil
}
+ if mainErr != nil {
+ return module.Version{}, "", mainErr
+ }
readVendorList()
return vendorPkgModule[path], vendorDir, nil
}
@@ -170,8 +175,9 @@
// not ambiguous.
return module.Version{}, "", err
}
- dir, ok := dirInModule(path, m.Path, root, isLocal)
- if ok {
+ if dir, ok, err := dirInModule(path, m.Path, root, isLocal); err != nil {
+ return module.Version{}, "", err
+ } else if ok {
mods = append(mods, m)
dirs = append(dirs, dir)
}
@@ -247,8 +253,9 @@
// Report fetch error as above.
return module.Version{}, "", err
}
- _, ok := dirInModule(path, m.Path, root, isLocal)
- if ok {
+ if _, ok, err := dirInModule(path, m.Path, root, isLocal); err != nil {
+ return m, "", err
+ } else if ok {
return m, "", &ImportMissingError{Path: path, Module: m}
}
}
@@ -319,19 +326,29 @@
len(path) > len(mpath) && path[len(mpath)] == '/' && path[:len(mpath)] == mpath
}
-var haveGoModCache, haveGoFilesCache par.Cache
+var (
+ haveGoModCache par.Cache // dir → bool
+ haveGoFilesCache par.Cache // dir → goFilesEntry
+)
+
+type goFilesEntry struct {
+ haveGoFiles bool
+ err error
+}
// dirInModule locates the directory that would hold the package named by the given path,
// if it were in the module with module path mpath and root mdir.
// If path is syntactically not within mpath,
// or if mdir is a local file tree (isLocal == true) and the directory
// that would hold path is in a sub-module (covered by a go.mod below mdir),
-// dirInModule returns "", false.
+// dirInModule returns "", false, nil.
//
// Otherwise, dirInModule returns the name of the directory where
// Go source files would be expected, along with a boolean indicating
// whether there are in fact Go source files in that directory.
-func dirInModule(path, mpath, mdir string, isLocal bool) (dir string, haveGoFiles bool) {
+// A non-nil error indicates that the existence of the directory and/or
+// source files could not be determined, for example due to a permission error.
+func dirInModule(path, mpath, mdir string, isLocal bool) (dir string, haveGoFiles bool, err error) {
// Determine where to expect the package.
if path == mpath {
dir = mdir
@@ -340,7 +357,7 @@
} else if len(path) > len(mpath) && path[len(mpath)] == '/' && path[:len(mpath)] == mpath {
dir = filepath.Join(mdir, path[len(mpath)+1:])
} else {
- return "", false
+ return "", false, nil
}
// Check that there aren't other modules in the way.
@@ -357,7 +374,7 @@
}).(bool)
if haveGoMod {
- return "", false
+ return "", false, nil
}
parent := filepath.Dir(d)
if parent == d {
@@ -374,23 +391,58 @@
// Are there Go source files in the directory?
// We don't care about build tags, not even "+build ignore".
// We're just looking for a plausible directory.
- haveGoFiles = haveGoFilesCache.Do(dir, func() interface{} {
- f, err := os.Open(dir)
- if err != nil {
- return false
+ res := haveGoFilesCache.Do(dir, func() interface{} {
+ ok, err := isDirWithGoFiles(dir)
+ return goFilesEntry{haveGoFiles: ok, err: err}
+ }).(goFilesEntry)
+
+ return dir, res.haveGoFiles, res.err
+}
+
+func isDirWithGoFiles(dir string) (bool, error) {
+ f, err := os.Open(dir)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return false, nil
}
- defer f.Close()
- names, _ := f.Readdirnames(-1)
- for _, name := range names {
- if strings.HasSuffix(name, ".go") {
- info, err := os.Stat(filepath.Join(dir, name))
- if err == nil && info.Mode().IsRegular() {
- return true
+ return false, err
+ }
+ defer f.Close()
+
+ names, firstErr := f.Readdirnames(-1)
+ if firstErr != nil {
+ if fi, err := f.Stat(); err == nil && !fi.IsDir() {
+ return false, nil
+ }
+
+ // Rewrite the error from ReadDirNames to include the path if not present.
+ // See https://golang.org/issue/38923.
+ var pe *os.PathError
+ if !errors.As(firstErr, &pe) {
+ firstErr = &os.PathError{Op: "readdir", Path: dir, Err: firstErr}
+ }
+ }
+
+ for _, name := range names {
+ if strings.HasSuffix(name, ".go") {
+ info, err := os.Stat(filepath.Join(dir, name))
+ if err == nil && info.Mode().IsRegular() {
+ // If any .go source file exists, the package exists regardless of
+ // errors for other source files. Leave further error reporting for
+ // later.
+ return true, nil
+ }
+ if firstErr == nil {
+ if os.IsNotExist(err) {
+ // If the file was concurrently deleted, or was a broken symlink,
+ // convert the error to an opaque error instead of one matching
+ // os.IsNotExist.
+ err = errors.New(err.Error())
}
+ firstErr = err
}
}
- return false
- }).(bool)
+ }
- return dir, haveGoFiles
+ return false, firstErr
}
diff --git a/src/cmd/go/internal/modload/load.go b/src/cmd/go/internal/modload/load.go
index 8a02c75..30992e0 100644
--- a/src/cmd/go/internal/modload/load.go
+++ b/src/cmd/go/internal/modload/load.go
@@ -99,14 +99,16 @@
m.Pkgs = []string{m.Pattern()}
case strings.Contains(m.Pattern(), "..."):
- m.Pkgs = matchPackages(m.Pattern(), loaded.tags, true, buildList)
+ m.Errs = m.Errs[:0]
+ matchPackages(m, loaded.tags, includeStd, buildList)
case m.Pattern() == "all":
loaded.testAll = true
if iterating {
// Enumerate the packages in the main module.
// We'll load the dependencies as we find them.
- m.Pkgs = matchPackages("...", loaded.tags, false, []module.Version{Target})
+ m.Errs = m.Errs[:0]
+ matchPackages(m, loaded.tags, omitStd, []module.Version{Target})
} else {
// Starting with the packages in the main module,
// enumerate the full list of "all".
@@ -273,7 +275,9 @@
}
pkg := targetPrefix + suffix
- if _, ok := dirInModule(pkg, targetPrefix, modRoot, true); !ok {
+ if _, ok, err := dirInModule(pkg, targetPrefix, modRoot, true); err != nil {
+ return "", err
+ } else if !ok {
return "", &PackageNotInModuleError{Mod: Target, Pattern: pkg}
}
return pkg, nil
@@ -422,7 +426,7 @@
loaded.testRoots = true
}
all := TargetPackages("...")
- loaded.load(func() []string { return all })
+ loaded.load(func() []string { return all.Pkgs })
checkMultiplePaths()
WriteGoMod()
@@ -434,6 +438,9 @@
}
paths = append(paths, pkg.path)
}
+ for _, err := range all.Errs {
+ base.Errorf("%v", err)
+ }
base.ExitIfErrors()
return paths
}
@@ -441,12 +448,14 @@
// TargetPackages returns the list of packages in the target (top-level) module
// matching pattern, which may be relative to the working directory, under all
// build tag settings.
-func TargetPackages(pattern string) []string {
+func TargetPackages(pattern string) *search.Match {
// TargetPackages is relative to the main module, so ensure that the main
// module is a thing that can contain packages.
ModRoot()
- return matchPackages(pattern, imports.AnyTags(), false, []module.Version{Target})
+ m := search.NewMatch(pattern)
+ matchPackages(m, imports.AnyTags(), omitStd, []module.Version{Target})
+ return m
}
// BuildList returns the module build list,
diff --git a/src/cmd/go/internal/modload/query.go b/src/cmd/go/internal/modload/query.go
index 5e9cfdc..acc886b 100644
--- a/src/cmd/go/internal/modload/query.go
+++ b/src/cmd/go/internal/modload/query.go
@@ -403,30 +403,42 @@
// possible modules.
func QueryPattern(pattern, query string, allowed func(module.Version) bool) ([]QueryResult, error) {
base := pattern
- var match func(m module.Version, root string, isLocal bool) (pkgs []string)
+
+ firstError := func(m *search.Match) error {
+ if len(m.Errs) == 0 {
+ return nil
+ }
+ return m.Errs[0]
+ }
+
+ var match func(mod module.Version, root string, isLocal bool) *search.Match
if i := strings.Index(pattern, "..."); i >= 0 {
base = pathpkg.Dir(pattern[:i+3])
- match = func(m module.Version, root string, isLocal bool) []string {
- return matchPackages(pattern, imports.AnyTags(), false, []module.Version{m})
+ match = func(mod module.Version, root string, isLocal bool) *search.Match {
+ m := search.NewMatch(pattern)
+ matchPackages(m, imports.AnyTags(), omitStd, []module.Version{mod})
+ return m
}
} else {
- match = func(m module.Version, root string, isLocal bool) []string {
- prefix := m.Path
- if m == Target {
+ match = func(mod module.Version, root string, isLocal bool) *search.Match {
+ m := search.NewMatch(pattern)
+ prefix := mod.Path
+ if mod == Target {
prefix = targetPrefix
}
- if _, ok := dirInModule(pattern, prefix, root, isLocal); ok {
- return []string{pattern}
- } else {
- return nil
+ if _, ok, err := dirInModule(pattern, prefix, root, isLocal); err != nil {
+ m.AddError(err)
+ } else if ok {
+ m.Pkgs = []string{pattern}
}
+ return m
}
}
if HasModRoot() {
- pkgs := match(Target, modRoot, true)
- if len(pkgs) > 0 {
+ m := match(Target, modRoot, true)
+ if len(m.Pkgs) > 0 {
if query != "latest" {
return nil, fmt.Errorf("can't query specific version for package %s in the main module (%s)", pattern, Target.Path)
}
@@ -436,9 +448,12 @@
return []QueryResult{{
Mod: Target,
Rev: &modfetch.RevInfo{Version: Target.Version},
- Packages: pkgs,
+ Packages: m.Pkgs,
}}, nil
}
+ if err := firstError(m); err != nil {
+ return nil, err
+ }
}
var (
@@ -466,8 +481,12 @@
if err != nil {
return r, err
}
- r.Packages = match(r.Mod, root, isLocal)
+ m := match(r.Mod, root, isLocal)
+ r.Packages = m.Pkgs
if len(r.Packages) == 0 {
+ if err := firstError(m); err != nil {
+ return r, err
+ }
return r, &PackageNotInModuleError{
Mod: r.Mod,
Replacement: Replacement(r.Mod),
@@ -684,8 +703,8 @@
if err != nil {
return false, err
}
- _, ok := dirInModule(m.Path, m.Path, root, isLocal)
- return ok, nil
+ _, ok, err := dirInModule(m.Path, m.Path, root, isLocal)
+ return ok, err
}
func versionHasGoMod(m module.Version) (bool, error) {
diff --git a/src/cmd/go/internal/modload/search.go b/src/cmd/go/internal/modload/search.go
index a303f51..c28e7c0 100644
--- a/src/cmd/go/internal/modload/search.go
+++ b/src/cmd/go/internal/modload/search.go
@@ -10,7 +10,6 @@
"path/filepath"
"strings"
- "cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/imports"
"cmd/go/internal/search"
@@ -18,14 +17,24 @@
"golang.org/x/mod/module"
)
-// matchPackages returns a list of packages in the list of modules
-// matching the pattern. Package loading assumes the given set of tags.
-func matchPackages(pattern string, tags map[string]bool, useStd bool, modules []module.Version) []string {
- match := func(string) bool { return true }
+type stdFilter int8
+
+const (
+ omitStd = stdFilter(iota)
+ includeStd
+)
+
+// matchPackages is like m.MatchPackages, but uses a local variable (rather than
+// a global) for tags, can include or exclude packages in the standard library,
+// and is restricted to the given list of modules.
+func matchPackages(m *search.Match, tags map[string]bool, filter stdFilter, modules []module.Version) {
+ m.Pkgs = []string{}
+
+ isMatch := func(string) bool { return true }
treeCanMatch := func(string) bool { return true }
- if !search.IsMetaPackage(pattern) {
- match = search.MatchPattern(pattern)
- treeCanMatch = search.TreeCanMatchPattern(pattern)
+ if !m.IsMeta() {
+ isMatch = search.MatchPattern(m.Pattern())
+ treeCanMatch = search.TreeCanMatchPattern(m.Pattern())
}
have := map[string]bool{
@@ -34,7 +43,6 @@
if !cfg.BuildContext.CgoEnabled {
have["runtime/cgo"] = true // ignore during walk
}
- var pkgs []string
type pruning int8
const (
@@ -44,8 +52,9 @@
walkPkgs := func(root, importPathRoot string, prune pruning) {
root = filepath.Clean(root)
- filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
+ err := filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
if err != nil {
+ m.AddError(err)
return nil
}
@@ -94,9 +103,9 @@
if !have[name] {
have[name] = true
- if match(name) {
+ if isMatch(name) {
if _, _, err := scanDir(path, tags); err != imports.ErrNoGo {
- pkgs = append(pkgs, name)
+ m.Pkgs = append(m.Pkgs, name)
}
}
}
@@ -106,9 +115,12 @@
}
return nil
})
+ if err != nil {
+ m.AddError(err)
+ }
}
- if useStd {
+ if filter == includeStd {
walkPkgs(cfg.GOROOTsrc, "", pruneGoMod)
if treeCanMatch("cmd") {
walkPkgs(filepath.Join(cfg.GOROOTsrc, "cmd"), "cmd", pruneGoMod)
@@ -120,7 +132,7 @@
walkPkgs(ModRoot(), targetPrefix, pruneGoMod|pruneVendor)
walkPkgs(filepath.Join(ModRoot(), "vendor"), "", pruneVendor)
}
- return pkgs
+ return
}
for _, mod := range modules {
@@ -143,7 +155,7 @@
var err error
root, isLocal, err = fetch(mod)
if err != nil {
- base.Errorf("go: %v", err)
+ m.AddError(err)
continue
}
modPrefix = mod.Path
@@ -156,5 +168,5 @@
walkPkgs(root, modPrefix, prune)
}
- return pkgs
+ return
}
diff --git a/src/cmd/go/internal/search/search.go b/src/cmd/go/internal/search/search.go
index b588c3e..4efef24 100644
--- a/src/cmd/go/internal/search/search.go
+++ b/src/cmd/go/internal/search/search.go
@@ -128,8 +128,11 @@
root += "cmd" + string(filepath.Separator)
}
err := filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
- if err != nil || path == src {
- return nil
+ if err != nil {
+ return err // Likely a permission error, which could interfere with matching.
+ }
+ if path == src {
+ return nil // GOROOT/src and GOPATH/src cannot contain packages.
}
want := true
@@ -261,7 +264,10 @@
}
err := filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
- if err != nil || !fi.IsDir() {
+ if err != nil {
+ return err // Likely a permission error, which could interfere with matching.
+ }
+ if !fi.IsDir() {
return nil
}
top := false
diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go
index 48a873e..880da28 100644
--- a/src/cmd/go/internal/test/test.go
+++ b/src/cmd/go/internal/test/test.go
@@ -73,10 +73,10 @@
and its test source files to identify significant problems. If go vet
finds any problems, go test reports those and does not run the test
binary. Only a high-confidence subset of the default go vet checks are
-used. That subset is: 'atomic', 'bool', 'buildtags', 'nilfunc', and
-'printf'. You can see the documentation for these and other vet tests
-via "go doc cmd/vet". To disable the running of go vet, use the
--vet=off flag.
+used. That subset is: 'atomic', 'bool', 'buildtags', 'errorsas',
+'ifaceassert', 'nilfunc', 'printf', and 'stringintconv'. You can see
+the documentation for these and other vet tests via "go doc cmd/vet".
+To disable the running of go vet, use the -vet=off flag.
All test output and summary lines are printed to the go command's
standard output, even if the test printed them to its own standard
@@ -548,12 +548,14 @@
// "-copylocks",
"-errorsas",
// "-httpresponse",
+ "-ifaceassert",
// "-lostcancel",
// "-methods",
"-nilfunc",
"-printf",
// "-rangeloops",
// "-shift",
+ "-stringintconv",
// "-structtags",
// "-tests",
// "-unreachable",
diff --git a/src/cmd/go/script_test.go b/src/cmd/go/script_test.go
index ebadce8..a49a705 100644
--- a/src/cmd/go/script_test.go
+++ b/src/cmd/go/script_test.go
@@ -10,6 +10,7 @@
import (
"bytes"
"context"
+ "errors"
"fmt"
"go/build"
"internal/testenv"
@@ -77,13 +78,16 @@
stderr string // standard error from last 'go' command; for 'stderr' command
stopped bool // test wants to stop early
start time.Time // time phase started
- background []backgroundCmd // backgrounded 'exec' and 'go' commands
+ background []*backgroundCmd // backgrounded 'exec' and 'go' commands
}
type backgroundCmd struct {
- cmd *exec.Cmd
- wait <-chan struct{}
- want simpleStatus
+ want simpleStatus
+ args []string
+ cancel context.CancelFunc
+ done <-chan struct{}
+ err error
+ stdout, stderr strings.Builder
}
type simpleStatus string
@@ -193,10 +197,10 @@
// before we print PASS. If we return early (e.g., due to a test failure),
// don't print anything about the processes that were still running.
for _, bg := range ts.background {
- interruptProcess(bg.cmd.Process)
+ bg.cancel()
}
for _, bg := range ts.background {
- <-bg.wait
+ <-bg.done
}
ts.background = nil
@@ -347,7 +351,7 @@
}
for _, bg := range ts.background {
- interruptProcess(bg.cmd.Process)
+ bg.cancel()
}
ts.cmdWait(success, nil)
@@ -633,40 +637,35 @@
ts.fatalf("usage: exec program [args...] [&]")
}
- var err error
+ background := false
if len(args) > 0 && args[len(args)-1] == "&" {
- var cmd *exec.Cmd
- cmd, err = ts.execBackground(args[0], args[1:len(args)-1]...)
- if err == nil {
- wait := make(chan struct{})
- go func() {
- ctxWait(testCtx, cmd)
- close(wait)
- }()
- ts.background = append(ts.background, backgroundCmd{cmd, wait, want})
- }
- ts.stdout, ts.stderr = "", ""
- } else {
- ts.stdout, ts.stderr, err = ts.exec(args[0], args[1:]...)
- if ts.stdout != "" {
- fmt.Fprintf(&ts.log, "[stdout]\n%s", ts.stdout)
- }
- if ts.stderr != "" {
- fmt.Fprintf(&ts.log, "[stderr]\n%s", ts.stderr)
- }
- if err == nil && want == failure {
- ts.fatalf("unexpected command success")
- }
+ background = true
+ args = args[:len(args)-1]
}
+ bg, err := ts.startBackground(want, args[0], args[1:]...)
if err != nil {
- fmt.Fprintf(&ts.log, "[%v]\n", err)
- if testCtx.Err() != nil {
- ts.fatalf("test timed out while running command")
- } else if want == success {
- ts.fatalf("unexpected command failure")
- }
+ ts.fatalf("unexpected error starting command: %v", err)
}
+ if background {
+ ts.stdout, ts.stderr = "", ""
+ ts.background = append(ts.background, bg)
+ return
+ }
+
+ <-bg.done
+ ts.stdout = bg.stdout.String()
+ ts.stderr = bg.stderr.String()
+ if ts.stdout != "" {
+ fmt.Fprintf(&ts.log, "[stdout]\n%s", ts.stdout)
+ }
+ if ts.stderr != "" {
+ fmt.Fprintf(&ts.log, "[stderr]\n%s", ts.stderr)
+ }
+ if bg.err != nil {
+ fmt.Fprintf(&ts.log, "[%v]\n", bg.err)
+ }
+ ts.checkCmd(bg)
}
// exists checks that the list of files exists.
@@ -759,7 +758,7 @@
// Before we mark the test as skipped, shut down any background processes and
// make sure they have returned the correct status.
for _, bg := range ts.background {
- interruptProcess(bg.cmd.Process)
+ bg.cancel()
}
ts.cmdWait(success, nil)
@@ -932,34 +931,24 @@
var stdouts, stderrs []string
for _, bg := range ts.background {
- <-bg.wait
+ <-bg.done
- args := append([]string{filepath.Base(bg.cmd.Args[0])}, bg.cmd.Args[1:]...)
- fmt.Fprintf(&ts.log, "[background] %s: %v\n", strings.Join(args, " "), bg.cmd.ProcessState)
+ args := append([]string{filepath.Base(bg.args[0])}, bg.args[1:]...)
+ fmt.Fprintf(&ts.log, "[background] %s: %v\n", strings.Join(args, " "), bg.err)
- cmdStdout := bg.cmd.Stdout.(*strings.Builder).String()
+ cmdStdout := bg.stdout.String()
if cmdStdout != "" {
fmt.Fprintf(&ts.log, "[stdout]\n%s", cmdStdout)
stdouts = append(stdouts, cmdStdout)
}
- cmdStderr := bg.cmd.Stderr.(*strings.Builder).String()
+ cmdStderr := bg.stderr.String()
if cmdStderr != "" {
fmt.Fprintf(&ts.log, "[stderr]\n%s", cmdStderr)
stderrs = append(stderrs, cmdStderr)
}
- if bg.cmd.ProcessState.Success() {
- if bg.want == failure {
- ts.fatalf("unexpected command success")
- }
- } else {
- if testCtx.Err() != nil {
- ts.fatalf("test timed out while running command")
- } else if bg.want == success {
- ts.fatalf("unexpected command failure")
- }
- }
+ ts.checkCmd(bg)
}
ts.stdout = strings.Join(stdouts, "")
@@ -987,58 +976,176 @@
}
}
+func (ts *testScript) checkCmd(bg *backgroundCmd) {
+ select {
+ case <-bg.done:
+ default:
+ panic("checkCmd called when not done")
+ }
+
+ if bg.err == nil {
+ if bg.want == failure {
+ ts.fatalf("unexpected command success")
+ }
+ return
+ }
+
+ if errors.Is(bg.err, context.DeadlineExceeded) {
+ ts.fatalf("test timed out while running command")
+ }
+
+ if errors.Is(bg.err, context.Canceled) {
+ // The process was still running at the end of the test.
+ // The test must not depend on its exit status.
+ if bg.want != successOrFailure {
+ ts.fatalf("unexpected background command remaining at test end")
+ }
+ return
+ }
+
+ if bg.want == success {
+ ts.fatalf("unexpected command failure")
+ }
+}
+
// exec runs the given command line (an actual subprocess, not simulated)
// in ts.cd with environment ts.env and then returns collected standard output and standard error.
func (ts *testScript) exec(command string, args ...string) (stdout, stderr string, err error) {
- cmd := exec.Command(command, args...)
- cmd.Dir = ts.cd
- cmd.Env = append(ts.env, "PWD="+ts.cd)
- var stdoutBuf, stderrBuf strings.Builder
- cmd.Stdout = &stdoutBuf
- cmd.Stderr = &stderrBuf
- if err = cmd.Start(); err == nil {
- err = ctxWait(testCtx, cmd)
+ bg, err := ts.startBackground(success, command, args...)
+ if err != nil {
+ return "", "", err
}
- return stdoutBuf.String(), stderrBuf.String(), err
+ <-bg.done
+ return bg.stdout.String(), bg.stderr.String(), bg.err
}
-// execBackground starts the given command line (an actual subprocess, not simulated)
+// startBackground starts the given command line (an actual subprocess, not simulated)
// in ts.cd with environment ts.env.
-func (ts *testScript) execBackground(command string, args ...string) (*exec.Cmd, error) {
+func (ts *testScript) startBackground(want simpleStatus, command string, args ...string) (*backgroundCmd, error) {
+ done := make(chan struct{})
+ bg := &backgroundCmd{
+ want: want,
+ args: append([]string{command}, args...),
+ done: done,
+ cancel: func() {},
+ }
+
+ ctx := context.Background()
+ gracePeriod := 100 * time.Millisecond
+ if deadline, ok := ts.t.Deadline(); ok {
+ timeout := time.Until(deadline)
+ // If time allows, increase the termination grace period to 5% of the
+ // remaining time.
+ if gp := timeout / 20; gp > gracePeriod {
+ gracePeriod = gp
+ }
+
+ // Send the first termination signal with two grace periods remaining.
+ // If it still hasn't finished after the first period has elapsed,
+ // we'll escalate to os.Kill with a second period remaining until the
+ // test deadline..
+ timeout -= 2 * gracePeriod
+
+ if timeout <= 0 {
+ // The test has less than the grace period remaining. There is no point in
+ // even starting the command, because it will be terminated immediately.
+ // Save the expense of starting it in the first place.
+ bg.err = context.DeadlineExceeded
+ close(done)
+ return bg, nil
+ }
+
+ ctx, bg.cancel = context.WithTimeout(ctx, timeout)
+ }
+
cmd := exec.Command(command, args...)
cmd.Dir = ts.cd
cmd.Env = append(ts.env, "PWD="+ts.cd)
- var stdoutBuf, stderrBuf strings.Builder
- cmd.Stdout = &stdoutBuf
- cmd.Stderr = &stderrBuf
- return cmd, cmd.Start()
-}
-
-// ctxWait is like cmd.Wait, but terminates cmd with os.Interrupt if ctx becomes done.
-//
-// This differs from exec.CommandContext in that it prefers os.Interrupt over os.Kill.
-// (See https://golang.org/issue/21135.)
-func ctxWait(ctx context.Context, cmd *exec.Cmd) error {
- errc := make(chan error, 1)
- go func() { errc <- cmd.Wait() }()
-
- select {
- case err := <-errc:
- return err
- case <-ctx.Done():
- interruptProcess(cmd.Process)
- return <-errc
+ cmd.Stdout = &bg.stdout
+ cmd.Stderr = &bg.stderr
+ if err := cmd.Start(); err != nil {
+ bg.cancel()
+ return nil, err
}
+
+ go func() {
+ bg.err = waitOrStop(ctx, cmd, stopSignal(), gracePeriod)
+ close(done)
+ }()
+ return bg, nil
}
-// interruptProcess sends os.Interrupt to p if supported, or os.Kill otherwise.
-func interruptProcess(p *os.Process) {
- if err := p.Signal(os.Interrupt); err != nil {
+// stopSignal returns the appropriate signal to use to request that a process
+// stop execution.
+func stopSignal() os.Signal {
+ if runtime.GOOS == "windows" {
// Per https://golang.org/pkg/os/#Signal, “Interrupt is not implemented on
// Windows; using it with os.Process.Signal will return an error.”
// Fall back to Kill instead.
- p.Kill()
+ return os.Kill
}
+ return os.Interrupt
+}
+
+// waitOrStop waits for the already-started command cmd by calling its Wait method.
+//
+// If cmd does not return before ctx is done, waitOrStop sends it the given interrupt signal.
+// If killDelay is positive, waitOrStop waits that additional period for Wait to return before sending os.Kill.
+//
+// This function is copied from the one added to x/playground/internal in
+// http://golang.org/cl/228438.
+func waitOrStop(ctx context.Context, cmd *exec.Cmd, interrupt os.Signal, killDelay time.Duration) error {
+ if cmd.Process == nil {
+ panic("waitOrStop called with a nil cmd.Process — missing Start call?")
+ }
+ if interrupt == nil {
+ panic("waitOrStop requires a non-nil interrupt signal")
+ }
+
+ errc := make(chan error)
+ go func() {
+ select {
+ case errc <- nil:
+ return
+ case <-ctx.Done():
+ }
+
+ err := cmd.Process.Signal(interrupt)
+ if err == nil {
+ err = ctx.Err() // Report ctx.Err() as the reason we interrupted.
+ } else if err.Error() == "os: process already finished" {
+ errc <- nil
+ return
+ }
+
+ if killDelay > 0 {
+ timer := time.NewTimer(killDelay)
+ select {
+ // Report ctx.Err() as the reason we interrupted the process...
+ case errc <- ctx.Err():
+ timer.Stop()
+ return
+ // ...but after killDelay has elapsed, fall back to a stronger signal.
+ case <-timer.C:
+ }
+
+ // Wait still hasn't returned.
+ // Kill the process harder to make sure that it exits.
+ //
+ // Ignore any error: if cmd.Process has already terminated, we still
+ // want to send ctx.Err() (or the error from the Interrupt call)
+ // to properly attribute the signal that may have terminated it.
+ _ = cmd.Process.Kill()
+ }
+
+ errc <- err
+ }()
+
+ waitErr := cmd.Wait()
+ if interruptErr := <-errc; interruptErr != nil {
+ return interruptErr
+ }
+ return waitErr
}
// expand applies environment variable expansion to the string s.
diff --git a/src/cmd/go/testdata/script/README b/src/cmd/go/testdata/script/README
index e22ddca..c7fa7cf 100644
--- a/src/cmd/go/testdata/script/README
+++ b/src/cmd/go/testdata/script/README
@@ -138,8 +138,9 @@
output and standard error of the previous command is cleared, but the output
of the background process is buffered — and checking of its exit status is
delayed — until the next call to 'wait', 'skip', or 'stop' or the end of the
- test. At the end of the test, any remaining background processes are
- terminated using os.Interrupt (if supported) or os.Kill.
+ test. If any background processes remain at the end of the test, they
+ are terminated using os.Interrupt (if supported) or os.Kill and the test
+ must not depend upon their exit status.
- [!] exists [-readonly] [-exec] file...
Each of the listed files or directories must (or must not) exist.
diff --git a/src/cmd/go/testdata/script/list_dedup_packages.txt b/src/cmd/go/testdata/script/list_dedup_packages.txt
index ab7068c..ebd497b 100644
--- a/src/cmd/go/testdata/script/list_dedup_packages.txt
+++ b/src/cmd/go/testdata/script/list_dedup_packages.txt
@@ -6,7 +6,7 @@
cd $WORK
# Check output of go list to ensure no duplicates
-go list xtestonly ./testdata/src/xtestonly/...
+go list xtestonly ./tmp/testdata/src/xtestonly/...
cmp stdout $WORK/gopath/src/wantstdout
-- wantstdout --
diff --git a/src/cmd/go/testdata/script/list_gofile_in_goroot.txt b/src/cmd/go/testdata/script/list_gofile_in_goroot.txt
index 604d8b4..6e48d7b 100644
--- a/src/cmd/go/testdata/script/list_gofile_in_goroot.txt
+++ b/src/cmd/go/testdata/script/list_gofile_in_goroot.txt
@@ -69,5 +69,8 @@
package foo
-- $WORK/goroot/src/fmt/fmt.go --
package fmt
+-- $WORK/goroot/src/cmd/README --
+This directory must exist in order for the 'cmd' pattern to have something to
+match against.
-- $GOPATH/src/foo.go --
package foo
diff --git a/src/cmd/go/testdata/script/list_permissions.txt b/src/cmd/go/testdata/script/list_permissions.txt
new file mode 100644
index 0000000..f65896c
--- /dev/null
+++ b/src/cmd/go/testdata/script/list_permissions.txt
@@ -0,0 +1,84 @@
+env GO111MODULE=on
+
+# Establish baseline behavior, before mucking with file permissions.
+
+go list ./noread/...
+stdout '^example.com/noread$'
+
+go list example.com/noread/...
+stdout '^example.com/noread$'
+
+go list ./empty/...
+stderr 'matched no packages'
+
+[root] stop # Root typically ignores file permissions.
+
+# Make the directory ./noread unreadable, and verify that 'go list' reports an
+# explicit error for a pattern that should match it (rather than treating it as
+# equivalent to an empty directory).
+
+[windows] skip # Does not have Unix-style directory permissions.
+[plan9] skip # Might not have Unix-style directory permissions.
+
+chmod 000 noread
+
+# Check explicit paths.
+
+! go list ./noread
+! stdout '^example.com/noread$'
+! stderr 'matched no packages'
+
+! go list example.com/noread
+! stdout '^example.com/noread$'
+! stderr 'matched no packages'
+
+# Check filesystem-relative patterns.
+
+! go list ./...
+! stdout '^example.com/noread$'
+! stderr 'matched no packages'
+stderr '^pattern ./...: '
+
+! go list ./noread/...
+! stdout '^example.com/noread$'
+! stderr 'matched no packages'
+stderr '^pattern ./noread/...: '
+
+
+# Check module-prefix patterns.
+
+! go list example.com/...
+! stdout '^example.com/noread$'
+! stderr 'matched no packages'
+stderr '^pattern example.com/...: '
+
+! go list example.com/noread/...
+! stdout '^example.com/noread$'
+! stderr 'matched no packages'
+stderr '^pattern example.com/noread/...: '
+
+
+[short] stop
+
+# Check global patterns, which should still
+# fail due to errors in the local module.
+
+! go list all
+! stdout '^example.com/noread$'
+! stderr 'matched no packages'
+stderr '^pattern all: '
+
+! go list ...
+! stdout '^example.com/noread$'
+! stderr 'matched no packages'
+stderr '^pattern ...: '
+
+
+-- go.mod --
+module example.com
+go 1.15
+-- noread/noread.go --
+// Package noread exists, but will be made unreadable.
+package noread
+-- empty/README.txt --
+This directory intentionally left empty.
diff --git a/src/cmd/go/testdata/script/script_wait.txt b/src/cmd/go/testdata/script/script_wait.txt
index 3cd4ded..acaccfe 100644
--- a/src/cmd/go/testdata/script/script_wait.txt
+++ b/src/cmd/go/testdata/script/script_wait.txt
@@ -19,6 +19,7 @@
stdout 'foo\nbar'
# The end of the test should interrupt or kill any remaining background
-# programs.
-[!exec:sleep] skip
-! exec sleep 86400 &
+# programs, but that should not cause the test to fail if it does not
+# care about the exit status of those programs.
+[!exec:sleep] stop
+? exec sleep 86400 &
diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go
index 9a1908a..7f5cba6 100644
--- a/src/cmd/internal/obj/arm64/asm7.go
+++ b/src/cmd/internal/obj/arm64/asm7.go
@@ -1639,12 +1639,12 @@
}
if isaddcon(int64(v)) {
if v <= 0xFFF {
- if isbitcon(uint64(v)) {
+ if isbitcon(uint64(a.Offset)) {
return C_ABCON0
}
return C_ADDCON0
}
- if isbitcon(uint64(v)) {
+ if isbitcon(uint64(a.Offset)) {
return C_ABCON
}
if movcon(int64(v)) >= 0 {
@@ -1658,7 +1658,7 @@
t := movcon(int64(v))
if t >= 0 {
- if isbitcon(uint64(v)) {
+ if isbitcon(uint64(a.Offset)) {
return C_MBCON
}
return C_MOVCON
@@ -1666,13 +1666,13 @@
t = movcon(int64(^v))
if t >= 0 {
- if isbitcon(uint64(v)) {
+ if isbitcon(uint64(a.Offset)) {
return C_MBCON
}
return C_MOVCON
}
- if isbitcon(uint64(v)) {
+ if isbitcon(uint64(a.Offset)) {
return C_BITCON
}
diff --git a/src/cmd/internal/obj/arm64/obj7.go b/src/cmd/internal/obj/arm64/obj7.go
index 09f603a..b046685 100644
--- a/src/cmd/internal/obj/arm64/obj7.go
+++ b/src/cmd/internal/obj/arm64/obj7.go
@@ -33,6 +33,7 @@
import (
"cmd/internal/obj"
"cmd/internal/objabi"
+ "cmd/internal/src"
"cmd/internal/sys"
"math"
)
@@ -593,6 +594,8 @@
p = c.stacksplit(p, c.autosize) // emit split check
}
+ var prologueEnd *obj.Prog
+
aoffset := c.autosize
if aoffset > 0xF0 {
aoffset = 0xF0
@@ -619,6 +622,8 @@
q.To.Type = obj.TYPE_REG
q.To.Reg = REGTMP
+ prologueEnd = q
+
q = obj.Appendp(q, c.newprog)
q.Pos = p.Pos
q.As = AMOVD
@@ -662,8 +667,12 @@
q1.To.Offset = int64(-aoffset)
q1.To.Reg = REGSP
q1.Spadj = aoffset
+
+ prologueEnd = q1
}
+ prologueEnd.Pos = prologueEnd.Pos.WithXlogue(src.PosPrologueEnd)
+
if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) {
q1 = obj.Appendp(q1, c.newprog)
q1.Pos = p.Pos
diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go
index badb388..2f402f3 100644
--- a/src/cmd/link/internal/ld/macho.go
+++ b/src/cmd/link/internal/ld/macho.go
@@ -779,7 +779,7 @@
continue
}
t := ldr.SymType(s)
- if t >= sym.SELFRXSECT && t < sym.SXREF { // data sections handled in dodata
+ if t >= sym.SELFRXSECT && t < sym.SXREF || t == sym.SCONST { // data sections handled in dodata
if t == sym.STLSBSS {
// TLSBSS is not used on darwin. See data.go:allocateDataSections
continue
@@ -791,7 +791,7 @@
}
switch t {
- case sym.SDYNIMPORT, sym.SHOSTOBJ, sym.SUNDEFEXT, sym.SCONST:
+ case sym.SDYNIMPORT, sym.SHOSTOBJ, sym.SUNDEFEXT:
addsym(s)
}
diff --git a/src/cmd/link/internal/ld/outbuf_linux.go b/src/cmd/link/internal/ld/outbuf_linux.go
index 93e621a..bd9a0c6 100644
--- a/src/cmd/link/internal/ld/outbuf_linux.go
+++ b/src/cmd/link/internal/ld/outbuf_linux.go
@@ -7,5 +7,5 @@
import "syscall"
func (out *OutBuf) fallocate(size uint64) error {
- return syscall.Fallocate(int(out.f.Fd()), outbufMode, 0, int64(size))
+ return syscall.Fallocate(int(out.f.Fd()), 0, 0, int64(size))
}
diff --git a/src/cmd/link/internal/ld/outbuf_mmap.go b/src/cmd/link/internal/ld/outbuf_mmap.go
index f5ccfc9..41c436e 100644
--- a/src/cmd/link/internal/ld/outbuf_mmap.go
+++ b/src/cmd/link/internal/ld/outbuf_mmap.go
@@ -10,8 +10,12 @@
"syscall"
)
-func (out *OutBuf) Mmap(filesize uint64) error {
- err := out.fallocate(filesize)
+func (out *OutBuf) Mmap(filesize uint64) (err error) {
+ for {
+ if err = out.fallocate(filesize); err != syscall.EINTR {
+ break
+ }
+ }
if err != nil {
// Some file systems do not support fallocate. We ignore that error as linking
// can still take place, but you might SIGBUS when you write to the mmapped
diff --git a/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/gnu.go b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/gnu.go
index fc29164..1849a29 100644
--- a/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/gnu.go
+++ b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/gnu.go
@@ -134,6 +134,19 @@
buf.WriteString("spr")
}
+ case "sync":
+ switch arg := inst.Args[0].(type) {
+ case Imm:
+ switch arg {
+ case 0:
+ buf.WriteString("hwsync")
+ case 1:
+ buf.WriteString("lwsync")
+ case 2:
+ buf.WriteString("ptesync")
+ }
+ }
+ startArg = 2
default:
buf.WriteString(inst.Op.String())
}
@@ -262,6 +275,8 @@
return true
case LHBRX, LWBRX, STHBRX, STWBRX:
return true
+ case LBARX, LWARX, LHARX, LDARX:
+ return true
}
return false
}
diff --git a/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/plan9.go b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/plan9.go
index d039d9d..858f9ac 100644
--- a/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/plan9.go
+++ b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/plan9.go
@@ -55,10 +55,24 @@
// laid out the instruction
switch inst.Op {
default: // dst, sA, sB, ...
- if len(args) == 0 {
+ switch len(args) {
+ case 0:
return op
- } else if len(args) == 1 {
+ case 1:
return fmt.Sprintf("%s %s", op, args[0])
+ case 2:
+ if inst.Op == COPY || inst.Op == PASTECC || inst.Op == FCMPO || inst.Op == FCMPU {
+ return op + " " + args[0] + "," + args[1]
+ }
+ return op + " " + args[1] + "," + args[0]
+ case 3:
+ if reverseOperandOrder(inst.Op) {
+ return op + " " + args[2] + "," + args[1] + "," + args[0]
+ }
+ case 4:
+ if reverseMiddleOps(inst.Op) {
+ return op + " " + args[1] + "," + args[3] + "," + args[2] + "," + args[0]
+ }
}
args = append(args, args[0])
return op + " " + strings.Join(args[1:], ",")
@@ -77,7 +91,7 @@
STH, STHU,
STW, STWU,
STD, STDU,
- STQ:
+ STQ, STFD, STFDU, STFS, STFSU:
return op + " " + strings.Join(args, ",")
case CMPD, CMPDI, CMPLD, CMPLDI, CMPW, CMPWI, CMPLW, CMPLWI:
@@ -92,28 +106,41 @@
return "ADDIS $0," + args[1] + "," + args[0]
// store instructions with index registers
case STBX, STBUX, STHX, STHUX, STWX, STWUX, STDX, STDUX,
- STHBRX, STWBRX, STDBRX, STSWX, STFSX, STFSUX, STFDX, STFDUX, STFIWX, STFDPX:
+ STHBRX, STWBRX, STDBRX, STSWX, STFIWX:
return "MOV" + op[2:len(op)-1] + " " + args[0] + ",(" + args[2] + ")(" + args[1] + ")"
case STDCXCC, STWCXCC, STHCXCC, STBCXCC:
return op + " " + args[0] + ",(" + args[2] + ")(" + args[1] + ")"
- case STXVD2X, STXVW4X:
+ case STXVD2X, STXVW4X, STXSDX, STVX, STVXL, STVEBX, STVEHX, STVEWX, STXSIWX, STFDX, STFDUX, STFDPX, STFSX, STFSUX:
return op + " " + args[0] + ",(" + args[2] + ")(" + args[1] + ")"
- // load instructions with index registers
- case LBZX, LBZUX, LHZX, LHZUX, LWZX, LWZUX, LDX, LDUX,
- LHBRX, LWBRX, LDBRX, LSWX, LFSX, LFSUX, LFDX, LFDUX, LFIWAX, LFIWZX:
- return "MOV" + op[1:len(op)-1] + " (" + args[2] + ")(" + args[1] + ")," + args[0]
+ case STXV:
+ return op + " " + args[0] + "," + args[1]
- case LDARX, LWARX, LHARX, LBARX:
+ case STXVL, STXVLL:
+ return op + " " + args[0] + "," + args[1] + "," + args[2]
+
+ case LWAX, LWAUX, LWZX, LHZX, LBZX, LDX, LHAX, LHAUX, LDARX, LWARX, LHARX, LBARX, LFDX, LFDUX, LFSX, LFSUX, LDBRX, LWBRX, LHBRX, LDUX, LWZUX, LHZUX, LBZUX:
+ if args[1] == "0" {
+ return op + " (" + args[2] + ")," + args[0]
+ }
return op + " (" + args[2] + ")(" + args[1] + ")," + args[0]
- case LXVD2X, LXVW4X:
+ case LXVD2X, LXVW4X, LVX, LVXL, LVSR, LVSL, LVEBX, LVEHX, LVEWX, LXSDX, LXSIWAX:
return op + " (" + args[2] + ")(" + args[1] + ")," + args[0]
- case DCBT, DCBTST, DCBZ, DCBST:
- return op + " (" + args[1] + ")"
+ case LXV:
+ return op + " " + args[1] + "," + args[0]
+
+ case LXVL, LXVLL:
+ return op + " " + args[1] + "," + args[2] + "," + args[0]
+
+ case DCBT, DCBTST, DCBZ, DCBST, DCBI, ICBI:
+ if args[0] == "0" || args[0] == "R0" {
+ return op + " (" + args[1] + ")"
+ }
+ return op + " (" + args[1] + ")(" + args[0] + ")"
// branch instructions needs additional handling
case BCLR:
@@ -173,12 +200,15 @@
if inst.Op == ISEL {
return fmt.Sprintf("$%d", (arg - Cond0LT))
}
- if arg == CR0 && strings.HasPrefix(inst.Op.String(), "cmp") {
+ if arg == CR0 && (strings.HasPrefix(inst.Op.String(), "cmp") || strings.HasPrefix(inst.Op.String(), "fcmp")) {
return "" // don't show cr0 for cmp instructions
} else if arg >= CR0 {
return fmt.Sprintf("CR%d", int(arg-CR0))
}
bit := [4]string{"LT", "GT", "EQ", "SO"}[(arg-Cond0LT)%4]
+ if strings.HasPrefix(inst.Op.String(), "cr") {
+ return fmt.Sprintf("CR%d%s", int(arg-Cond0LT)/4, bit)
+ }
if arg <= Cond0SO {
return bit
}
@@ -212,6 +242,37 @@
return fmt.Sprintf("???(%v)", arg)
}
+func reverseMiddleOps(op Op) bool {
+ switch op {
+ case FMADD, FMADDCC, FMADDS, FMADDSCC, FMSUB, FMSUBCC, FMSUBS, FMSUBSCC, FNMADD, FNMADDCC, FNMADDS, FNMADDSCC, FNMSUB, FNMSUBCC, FNMSUBS, FNMSUBSCC, FSEL, FSELCC:
+ return true
+ }
+ return false
+}
+
+func reverseOperandOrder(op Op) bool {
+ switch op {
+ // Special case for SUBF, SUBFC: not reversed
+ case ADD, ADDC, ADDE, ADDCC, ADDCCC:
+ return true
+ case MULLW, MULLWCC, MULHW, MULHWCC, MULLD, MULLDCC, MULHD, MULHDCC, MULLWO, MULLWOCC, MULHWU, MULHWUCC, MULLDO, MULLDOCC:
+ return true
+ case DIVD, DIVDCC, DIVDU, DIVDUCC, DIVDE, DIVDECC, DIVDEU, DIVDEUCC, DIVDO, DIVDOCC, DIVDUO, DIVDUOCC:
+ return true
+ case MODUD, MODSD, MODUW, MODSW:
+ return true
+ case FADD, FADDS, FSUB, FSUBS, FMUL, FMULS, FDIV, FDIVS, FMADD, FMADDS, FMSUB, FMSUBS, FNMADD, FNMADDS, FNMSUB, FNMSUBS, FMULSCC:
+ return true
+ case FADDCC, FADDSCC, FSUBCC, FMULCC, FDIVCC, FDIVSCC:
+ return true
+ case OR, ORC, AND, ANDC, XOR, NAND, EQV, NOR, ANDCC, ORCC, XORCC, EQVCC, NORCC, NANDCC:
+ return true
+ case SLW, SLWCC, SLD, SLDCC, SRW, SRAW, SRWCC, SRAWCC, SRD, SRDCC, SRAD, SRADCC:
+ return true
+ }
+ return false
+}
+
// revCondMap maps a conditional register bit to its inverse, if possible.
var revCondMap = map[string]string{
"LT": "GE", "GT": "LE", "EQ": "NE",
@@ -219,15 +280,65 @@
// plan9OpMap maps an Op to its Plan 9 mnemonics, if different than its GNU mnemonics.
var plan9OpMap = map[Op]string{
- LWARX: "LWAR",
- LDARX: "LDAR",
- LHARX: "LHAR",
- LBARX: "LBAR",
- ADDI: "ADD",
- SRADI: "SRAD",
- SUBF: "SUB",
- LI: "MOVD",
- LBZ: "MOVBZ", STB: "MOVB",
+ LWARX: "LWAR",
+ LDARX: "LDAR",
+ LHARX: "LHAR",
+ LBARX: "LBAR",
+ LWAX: "MOVW",
+ LHAX: "MOVH",
+ LWAUX: "MOVWU",
+ LHAU: "MOVHU",
+ LHAUX: "MOVHU",
+ LDX: "MOVD",
+ LDUX: "MOVDU",
+ LWZX: "MOVWZ",
+ LWZUX: "MOVWZU",
+ LHZX: "MOVHZ",
+ LHZUX: "MOVHZU",
+ LBZX: "MOVBZ",
+ LBZUX: "MOVBZU",
+ LDBRX: "MOVDBR",
+ LWBRX: "MOVWBR",
+ LHBRX: "MOVHBR",
+ MCRF: "MOVFL",
+ XORI: "XOR",
+ ORI: "OR",
+ ANDICC: "ANDCC",
+ ANDC: "ANDN",
+ ADDEO: "ADDEV",
+ ADDEOCC: "ADDEVCC",
+ ADDO: "ADDV",
+ ADDOCC: "ADDVCC",
+ ADDMEO: "ADDMEV",
+ ADDMEOCC: "ADDMEVCC",
+ ADDCO: "ADDCV",
+ ADDCOCC: "ADDCVCC",
+ ADDZEO: "ADDZEV",
+ ADDZEOCC: "ADDZEVCC",
+ SUBFME: "SUBME",
+ SUBFMECC: "SUBMECC",
+ SUBFZE: "SUBZE",
+ SUBFZECC: "SUBZECC",
+ SUBFZEO: "SUBZEV",
+ SUBFZEOCC: "SUBZEVCC",
+ SUBFC: "SUBC",
+ ORC: "ORN",
+ MULLWO: "MULLWV",
+ MULLWOCC: "MULLWVCC",
+ MULLDO: "MULLDV",
+ MULLDOCC: "MULLDVCC",
+ DIVDO: "DIVDV",
+ DIVDOCC: "DIVDVCC",
+ DIVDUO: "DIVDUV",
+ DIVDUOCC: "DIVDUVCC",
+ ADDI: "ADD",
+ SRADI: "SRAD",
+ SUBF: "SUB",
+ STBCXCC: "STBCCC",
+ STWCXCC: "STWCCC",
+ STDCXCC: "STDCCC",
+ LI: "MOVD",
+ LBZ: "MOVBZ", STB: "MOVB",
LBZU: "MOVBZU", STBU: "MOVBU",
LHZ: "MOVHZ", LHA: "MOVH", STH: "MOVH",
LHZU: "MOVHZU", STHU: "MOVHU",
@@ -235,6 +346,14 @@
LWZU: "MOVWZU", STWU: "MOVWU",
LD: "MOVD", STD: "MOVD",
LDU: "MOVDU", STDU: "MOVDU",
+ LFD: "FMOVD", STFD: "FMOVD",
+ LFS: "FMOVS", STFS: "FMOVS",
+ LFDX: "FMOVD", STFDX: "FMOVD",
+ LFDU: "FMOVDU", STFDU: "FMOVDU",
+ LFDUX: "FMOVDU", STFDUX: "FMOVDU",
+ LFSX: "FMOVS", STFSX: "FMOVS",
+ LFSU: "FMOVSU", STFSU: "FMOVSU",
+ LFSUX: "FMOVSU", STFSUX: "FMOVSU",
CMPD: "CMP", CMPDI: "CMP",
CMPW: "CMPW", CMPWI: "CMPW",
CMPLD: "CMPU", CMPLDI: "CMPU",
diff --git a/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/tables.go b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/tables.go
index f536926..250d3b7 100644
--- a/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/tables.go
+++ b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/tables.go
@@ -186,6 +186,10 @@
DIVDEUCC
DIVDEUO
DIVDEUOCC
+ MODSD
+ MODUD
+ MODSW
+ MODUW
CMPWI
CMPDI
CMPW
@@ -466,6 +470,7 @@
VSPLTISH
VSPLTISW
VPERM
+ VPERMR
VSEL
VSL
VSLDOI
@@ -524,6 +529,7 @@
VMSUMSHS
VMSUMUHM
VMSUMUHS
+ VMSUMUDM
VSUMSWS
VSUM2SWS
VSUM4SBS
@@ -559,6 +565,18 @@
VCMPEQUWCC
VCMPEQUD
VCMPEQUDCC
+ VCMPNEB
+ VCMPNEBCC
+ VCMPNEZB
+ VCMPNEZBCC
+ VCMPNEH
+ VCMPNEHCC
+ VCMPNEZH
+ VCMPNEZHCC
+ VCMPNEW
+ VCMPNEWCC
+ VCMPNEZW
+ VCMPNEZWCC
VCMPGTSB
VCMPGTSBCC
VCMPGTSD
@@ -647,6 +665,7 @@
VPOPCNTH
VPOPCNTW
VBPERMQ
+ VBPERMD
BCDADDCC
BCDSUBCC
MTVSCR
@@ -708,11 +727,17 @@
LXVD2X
LXVDSX
LXVW4X
+ LXV
+ LXVL
+ LXVLL
STXSDX
STXSIWX
STXSSPX
STXVD2X
STXVW4X
+ STXV
+ STXVL
+ STXVLL
XSABSDP
XSADDDP
XSADDSP
@@ -852,6 +877,7 @@
XXMRGHW
XXMRGLW
XXPERMDI
+ XXPERM
XXSEL
XXSLDWI
XXSPLTW
@@ -1528,6 +1554,10 @@
DIVDEUCC: "divdeu.",
DIVDEUO: "divdeuo",
DIVDEUOCC: "divdeuo.",
+ MODSD: "modsd",
+ MODUD: "modud",
+ MODSW: "modsw",
+ MODUW: "moduw",
CMPWI: "cmpwi",
CMPDI: "cmpdi",
CMPW: "cmpw",
@@ -1808,6 +1838,7 @@
VSPLTISH: "vspltish",
VSPLTISW: "vspltisw",
VPERM: "vperm",
+ VPERMR: "vpermr",
VSEL: "vsel",
VSL: "vsl",
VSLDOI: "vsldoi",
@@ -1866,6 +1897,7 @@
VMSUMSHS: "vmsumshs",
VMSUMUHM: "vmsumuhm",
VMSUMUHS: "vmsumuhs",
+ VMSUMUDM: "vmsumudm",
VSUMSWS: "vsumsws",
VSUM2SWS: "vsum2sws",
VSUM4SBS: "vsum4sbs",
@@ -1901,6 +1933,18 @@
VCMPEQUWCC: "vcmpequw.",
VCMPEQUD: "vcmpequd",
VCMPEQUDCC: "vcmpequd.",
+ VCMPNEB: "vcmpneb",
+ VCMPNEBCC: "vcmpneb.",
+ VCMPNEZB: "vcmpnezb",
+ VCMPNEZBCC: "vcmpnezb.",
+ VCMPNEH: "vcmpneh",
+ VCMPNEHCC: "vcmpneh.",
+ VCMPNEZH: "vcmpnezh",
+ VCMPNEZHCC: "vcmpnezh.",
+ VCMPNEW: "vcmpnew",
+ VCMPNEWCC: "vcmpnew.",
+ VCMPNEZW: "vcmpnezw",
+ VCMPNEZWCC: "vcmpnezw.",
VCMPGTSB: "vcmpgtsb",
VCMPGTSBCC: "vcmpgtsb.",
VCMPGTSD: "vcmpgtsd",
@@ -1989,6 +2033,7 @@
VPOPCNTH: "vpopcnth",
VPOPCNTW: "vpopcntw",
VBPERMQ: "vbpermq",
+ VBPERMD: "vbpermd",
BCDADDCC: "bcdadd.",
BCDSUBCC: "bcdsub.",
MTVSCR: "mtvscr",
@@ -2050,11 +2095,17 @@
LXVD2X: "lxvd2x",
LXVDSX: "lxvdsx",
LXVW4X: "lxvw4x",
+ LXV: "lxv",
+ LXVL: "lxvl",
+ LXVLL: "lxvll",
STXSDX: "stxsdx",
STXSIWX: "stxsiwx",
STXSSPX: "stxsspx",
STXVD2X: "stxvd2x",
STXVW4X: "stxvw4x",
+ STXV: "stxv",
+ STXVL: "stxvl",
+ STXVLL: "stxvll",
XSABSDP: "xsabsdp",
XSADDDP: "xsadddp",
XSADDSP: "xsaddsp",
@@ -2194,6 +2245,7 @@
XXMRGHW: "xxmrghw",
XXMRGLW: "xxmrglw",
XXPERMDI: "xxpermdi",
+ XXPERM: "xxperm",
XXSEL: "xxsel",
XXSLDWI: "xxsldwi",
XXSPLTW: "xxspltw",
@@ -2745,6 +2797,7 @@
ap_ImmUnsigned_21_22 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{21, 2}}}
ap_ImmUnsigned_11_12 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{11, 2}}}
ap_ImmUnsigned_11_11 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{11, 1}}}
+ ap_VecSReg_28_28_6_10 = &argField{Type: TypeVecSReg, Shift: 0, BitFields: BitFields{{28, 1}, {6, 5}}}
ap_VecSReg_30_30_16_20 = &argField{Type: TypeVecSReg, Shift: 0, BitFields: BitFields{{30, 1}, {16, 5}}}
ap_VecSReg_29_29_11_15 = &argField{Type: TypeVecSReg, Shift: 0, BitFields: BitFields{{29, 1}, {11, 5}}}
ap_ImmUnsigned_22_23 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{22, 2}}}
@@ -3125,6 +3178,14 @@
[5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
{DIVDEUOCC, 0xfc0007ff, 0x7c000713, 0x0, // Divide Doubleword Extended Unsigned XO-form (divdeuo. RT,RA,RB)
[5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MODSD, 0xfc0007fe, 0x7c000612, 0x1, // Modulo Signed Doubleword X-form (modsd RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MODUD, 0xfc0007fe, 0x7c000212, 0x1, // Modulo Unsigned Doubleword X-form (modud RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MODSW, 0xfc0007fe, 0x7c000616, 0x1, // Modulo Signed Word X-form (modsw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MODUW, 0xfc0007fe, 0x7c000216, 0x1, // Modulo Unsigned Word X-form (moduw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
{CMPWI, 0xfc200000, 0x2c000000, 0x400000, // Compare Immediate D-form (cmpwi BF,RA,SI)
[5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_ImmSigned_16_31}},
{CMPDI, 0xfc200000, 0x2c200000, 0x400000, // Compare Immediate D-form (cmpdi BF,RA,SI)
@@ -3685,6 +3746,8 @@
[5]*argField{ap_VecReg_6_10, ap_ImmSigned_11_15}},
{VPERM, 0xfc00003f, 0x1000002b, 0x0, // Vector Permute VA-form (vperm VRT,VRA,VRB,VRC)
[5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_VecReg_21_25}},
+ {VPERMR, 0xfc00003f, 0x1000003b, 0x0, // Vector Permute Right-indexed VA-form (vpermr VRT,VRA,VRB,VRC)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_VecReg_21_25}},
{VSEL, 0xfc00003f, 0x1000002a, 0x0, // Vector Select VA-form (vsel VRT,VRA,VRB,VRC)
[5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_VecReg_21_25}},
{VSL, 0xfc0007ff, 0x100001c4, 0x0, // Vector Shift Left VX-form (vsl VRT,VRA,VRB)
@@ -3801,6 +3864,8 @@
[5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_VecReg_21_25}},
{VMSUMUHS, 0xfc00003f, 0x10000027, 0x0, // Vector Multiply-Sum Unsigned Halfword Saturate VA-form (vmsumuhs VRT,VRA,VRB,VRC)
[5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_VecReg_21_25}},
+ {VMSUMUDM, 0xfc00003f, 0x10000023, 0x0, // Vector Multiply-Sum Unsigned Doubleword Modulo VA-form (vmsumudm VRT,VRA,VRB,VRC)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_VecReg_21_25}},
{VSUMSWS, 0xfc0007ff, 0x10000788, 0x0, // Vector Sum across Signed Word Saturate VX-form (vsumsws VRT,VRA,VRB)
[5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
{VSUM2SWS, 0xfc0007ff, 0x10000688, 0x0, // Vector Sum across Half Signed Word Saturate VX-form (vsum2sws VRT,VRA,VRB)
@@ -3871,6 +3936,30 @@
[5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
{VCMPEQUDCC, 0xfc0007ff, 0x100004c7, 0x0, // Vector Compare Equal To Unsigned Doubleword VX-form (vcmpequd. VRT,VRA,VRB)
[5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPNEB, 0xfc0007ff, 0x10000007, 0x0, // Vector Compare Not Equal Byte VX-form (vcmpneb VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPNEBCC, 0xfc0007ff, 0x10000407, 0x0, // Vector Compare Not Equal Byte VX-form (vcmpneb. VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPNEZB, 0xfc0007ff, 0x10000107, 0x0, // Vector Compare Not Equal or Zero Byte VX-form (vcmpnezb VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPNEZBCC, 0xfc0007ff, 0x10000507, 0x0, // Vector Compare Not Equal or Zero Byte VX-form (vcmpnezb. VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPNEH, 0xfc0007ff, 0x10000047, 0x0, // Vector Compare Not Equal Halfword VX-form (vcmpneh VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPNEHCC, 0xfc0007ff, 0x10000447, 0x0, // Vector Compare Not Equal Halfword VX-form (vcmpneh. VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPNEZH, 0xfc0007ff, 0x10000147, 0x0, // Vector Compare Not Equal or Zero Halfword VX-form (vcmpnezh VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPNEZHCC, 0xfc0007ff, 0x10000547, 0x0, // Vector Compare Not Equal or Zero Halfword VX-form (vcmpnezh. VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPNEW, 0xfc0007ff, 0x10000087, 0x0, // Vector Compare Not Equal Word VX-form (vcmpnew VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPNEWCC, 0xfc0007ff, 0x10000487, 0x0, // Vector Compare Not Equal Word VX-form (vcmpnew. VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPNEZW, 0xfc0007ff, 0x10000187, 0x0, // Vector Compare Not Equal or Zero Word VX-form (vcmpnezw VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPNEZWCC, 0xfc0007ff, 0x10000587, 0x0, // Vector Compare Not Equal or Zero Word VX-form (vcmpnezw. VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
{VCMPGTSB, 0xfc0007ff, 0x10000306, 0x0, // Vector Compare Greater Than Signed Byte VC-form (vcmpgtsb VRT,VRA,VRB)
[5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
{VCMPGTSBCC, 0xfc0007ff, 0x10000706, 0x0, // Vector Compare Greater Than Signed Byte VC-form (vcmpgtsb. VRT,VRA,VRB)
@@ -4047,6 +4136,8 @@
[5]*argField{ap_VecReg_6_10, ap_VecReg_16_20}},
{VBPERMQ, 0xfc0007ff, 0x1000054c, 0x0, // Vector Bit Permute Quadword VX-form (vbpermq VRT,VRA,VRB)
[5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VBPERMD, 0xfc0007ff, 0x100005cc, 0x0, // Vector Bit Permute Doubleword VX-form (vbpermd VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
{BCDADDCC, 0xfc0005ff, 0x10000401, 0x0, // Decimal Add Modulo VX-form (bcdadd. VRT,VRA,VRB,PS)
[5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_ImmUnsigned_22_22}},
{BCDSUBCC, 0xfc0005ff, 0x10000441, 0x0, // Decimal Subtract Modulo VX-form (bcdsub. VRT,VRA,VRB,PS)
@@ -4169,6 +4260,12 @@
[5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
{LXVW4X, 0xfc0007fe, 0x7c000618, 0x0, // Load VSX Vector Word*4 Indexed XX1-form (lxvw4x XT,RA,RB)
[5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LXV, 0xfc000007, 0xf4000001, 0x0, // Load VSX Vector DQ-form (lxv XT,DQ(RA))
+ [5]*argField{ap_VecSReg_28_28_6_10, ap_Offset_16_27_shift4, ap_Reg_11_15}},
+ {LXVL, 0xfc0007fe, 0x7c00021a, 0x0, // Load VSX Vector with Length X-form (lxvl XT,RA,RB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LXVLL, 0xfc0007fe, 0x7c00025a, 0x0, // Load VSX Vector Left-justified with Length X-form (lxvll XT,RA,RB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
{STXSDX, 0xfc0007fe, 0x7c000598, 0x0, // Store VSX Scalar Doubleword Indexed XX1-form (stxsdx XS,RA,RB)
[5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
{STXSIWX, 0xfc0007fe, 0x7c000118, 0x0, // Store VSX Scalar as Integer Word Indexed XX1-form (stxsiwx XS,RA,RB)
@@ -4179,6 +4276,12 @@
[5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
{STXVW4X, 0xfc0007fe, 0x7c000718, 0x0, // Store VSX Vector Word*4 Indexed XX1-form (stxvw4x XS,RA,RB)
[5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STXV, 0xfc000007, 0xf4000005, 0x0, // Store VSX Vector DQ-form (stxv XS,DQ(RA))
+ [5]*argField{ap_VecSReg_28_28_6_10, ap_Offset_16_27_shift4, ap_Reg_11_15}},
+ {STXVL, 0xfc0007fe, 0x7c00031a, 0x0, // Store VSX Vector with Length X-form (stxvl XS,RA,RB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STXVLL, 0xfc0007fe, 0x7c00035a, 0x0, // Store VSX Vector Left-justified with Length X-form (stxvll XS,RA,RB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
{XSABSDP, 0xfc0007fc, 0xf0000564, 0x1f0000, // VSX Scalar Absolute Value Double-Precision XX2-form (xsabsdp XT,XB)
[5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
{XSADDDP, 0xfc0007f8, 0xf0000100, 0x0, // VSX Scalar Add Double-Precision XX3-form (xsadddp XT,XA,XB)
@@ -4457,6 +4560,8 @@
[5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
{XXPERMDI, 0xfc0004f8, 0xf0000050, 0x0, // VSX Permute Doubleword Immediate XX3-form (xxpermdi XT,XA,XB,DM)
[5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20, ap_ImmUnsigned_22_23}},
+ {XXPERM, 0xfc0007f8, 0xf00000d0, 0x0, // VSX Permute XX3-form (xxperm XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
{XXSEL, 0xfc000030, 0xf0000030, 0x0, // VSX Select XX4-form (xxsel XT,XA,XB,XC)
[5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20, ap_VecSReg_28_28_21_25}},
{XXSLDWI, 0xfc0004f8, 0xf0000010, 0x0, // VSX Shift Left Double by Word Immediate XX3-form (xxsldwi XT,XA,XB,SHW)
diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt
index 10d7d4b..0a3ea66 100644
--- a/src/cmd/vendor/modules.txt
+++ b/src/cmd/vendor/modules.txt
@@ -18,7 +18,7 @@
# github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340
## explicit
github.com/ianlancetaylor/demangle
-# golang.org/x/arch v0.0.0-20200312215426-ff8b605520f4
+# golang.org/x/arch v0.0.0-20200511175325-f7c78586839d
## explicit
golang.org/x/arch/arm/armasm
golang.org/x/arch/arm64/arm64asm
diff --git a/src/encoding/json/decode.go b/src/encoding/json/decode.go
index 5f34af4..5acc6d8 100644
--- a/src/encoding/json/decode.go
+++ b/src/encoding/json/decode.go
@@ -677,7 +677,6 @@
return nil
}
- var mapElem reflect.Value
origErrorContext := d.errorContext
for {
@@ -701,17 +700,66 @@
}
// Figure out field corresponding to key.
- var subv reflect.Value
+ var kv, subv reflect.Value
destring := false // whether the value is wrapped in a string to be decoded first
if v.Kind() == reflect.Map {
- elemType := t.Elem()
- if !mapElem.IsValid() {
- mapElem = reflect.New(elemType).Elem()
- } else {
- mapElem.Set(reflect.Zero(elemType))
+ // First, figure out the key value from the input.
+ kt := t.Key()
+ switch {
+ case reflect.PtrTo(kt).Implements(textUnmarshalerType):
+ kv = reflect.New(kt)
+ if err := d.literalStore(item, kv, true); err != nil {
+ return err
+ }
+ kv = kv.Elem()
+ case kt.Kind() == reflect.String:
+ kv = reflect.ValueOf(key).Convert(kt)
+ default:
+ switch kt.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ s := string(key)
+ n, err := strconv.ParseInt(s, 10, 64)
+ if err != nil || reflect.Zero(kt).OverflowInt(n) {
+ d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)})
+ break
+ }
+ kv = reflect.ValueOf(n).Convert(kt)
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ s := string(key)
+ n, err := strconv.ParseUint(s, 10, 64)
+ if err != nil || reflect.Zero(kt).OverflowUint(n) {
+ d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)})
+ break
+ }
+ kv = reflect.ValueOf(n).Convert(kt)
+ default:
+ panic("json: Unexpected key type") // should never occur
+ }
}
- subv = mapElem
+
+ // Then, decide what element value we'll decode into.
+ et := t.Elem()
+ if kv.IsValid() {
+ if existing := v.MapIndex(kv); !existing.IsValid() {
+ // Nothing to reuse.
+ } else if et.Kind() == reflect.Ptr {
+ // Pointer; decode directly into it if non-nil.
+ if !existing.IsNil() {
+ subv = existing
+ }
+ } else {
+ // Non-pointer. Make a copy and decode into the
+ // addressable copy. Don't just use a new/zero
+ // value, as that would lose existing data.
+ subv = reflect.New(et).Elem()
+ subv.Set(existing)
+ }
+ }
+ if !subv.IsValid() {
+ // We couldn't reuse an existing value.
+ subv = reflect.New(et).Elem()
+ }
} else {
var f *field
if i, ok := fields.nameIndex[string(key)]; ok {
@@ -790,43 +838,8 @@
// Write value back to map;
// if using struct, subv points into struct already.
- if v.Kind() == reflect.Map {
- kt := t.Key()
- var kv reflect.Value
- switch {
- case reflect.PtrTo(kt).Implements(textUnmarshalerType):
- kv = reflect.New(kt)
- if err := d.literalStore(item, kv, true); err != nil {
- return err
- }
- kv = kv.Elem()
- case kt.Kind() == reflect.String:
- kv = reflect.ValueOf(key).Convert(kt)
- default:
- switch kt.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- s := string(key)
- n, err := strconv.ParseInt(s, 10, 64)
- if err != nil || reflect.Zero(kt).OverflowInt(n) {
- d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)})
- break
- }
- kv = reflect.ValueOf(n).Convert(kt)
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- s := string(key)
- n, err := strconv.ParseUint(s, 10, 64)
- if err != nil || reflect.Zero(kt).OverflowUint(n) {
- d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)})
- break
- }
- kv = reflect.ValueOf(n).Convert(kt)
- default:
- panic("json: Unexpected key type") // should never occur
- }
- }
- if kv.IsValid() {
- v.SetMapIndex(kv, subv)
- }
+ if v.Kind() == reflect.Map && kv.IsValid() {
+ v.SetMapIndex(kv, subv)
}
// Next token must be , or }.
diff --git a/src/encoding/json/decode_test.go b/src/encoding/json/decode_test.go
index 5ac1022..a62488d 100644
--- a/src/encoding/json/decode_test.go
+++ b/src/encoding/json/decode_test.go
@@ -2569,3 +2569,57 @@
}
}
}
+
+func TestUnmarshalMapPointerElem(t *testing.T) {
+ type S struct{ Unchanged, Changed int }
+ input := []byte(`{"S":{"Changed":5}}`)
+ want := S{1, 5}
+
+ // First, a map with struct pointer elements. The key-value pair exists,
+ // so reuse the existing value.
+ s := &S{1, 2}
+ ptrMap := map[string]*S{"S": s}
+ if err := Unmarshal(input, &ptrMap); err != nil {
+ t.Fatal(err)
+ }
+ if s != ptrMap["S"] {
+ t.Fatal("struct pointer element in map was completely replaced")
+ }
+ if got := *s; got != want {
+ t.Fatalf("want %#v, got %#v", want, got)
+ }
+
+ // Second, a map with struct elements. The key-value pair exists, but
+ // the value isn't addresable, so make a copy and use that.
+ s = &S{1, 2}
+ strMap := map[string]S{"S": *s}
+ if err := Unmarshal(input, &strMap); err != nil {
+ t.Fatal(err)
+ }
+ if *s == strMap["S"] {
+ t.Fatal("struct element in map wasn't copied")
+ }
+ if got := strMap["S"]; got != want {
+ t.Fatalf("want %#v, got %#v", want, got)
+ }
+
+ // Finally, check the cases where the key-value pair exists, but the
+ // value is zero.
+ want = S{0, 5}
+
+ ptrMap = map[string]*S{"S": nil}
+ if err := Unmarshal(input, &ptrMap); err != nil {
+ t.Fatal(err)
+ }
+ if got := *ptrMap["S"]; got != want {
+ t.Fatalf("want %#v, got %#v", want, got)
+ }
+
+ strMap = map[string]S{"S": {}}
+ if err := Unmarshal(input, &strMap); err != nil {
+ t.Fatal(err)
+ }
+ if got := strMap["S"]; got != want {
+ t.Fatalf("want %#v, got %#v", want, got)
+ }
+}
diff --git a/src/image/png/reader.go b/src/image/png/reader.go
index 5521b39..910520b 100644
--- a/src/image/png/reader.go
+++ b/src/image/png/reader.go
@@ -862,8 +862,7 @@
func (d *decoder) parseChunk() error {
// Read the length and chunk type.
- n, err := io.ReadFull(d.r, d.tmp[:8])
- if err != nil {
+ if _, err := io.ReadFull(d.r, d.tmp[:8]); err != nil {
return err
}
length := binary.BigEndian.Uint32(d.tmp[:4])
@@ -920,7 +919,7 @@
// Ignore this chunk (of a known length).
var ignored [4096]byte
for length > 0 {
- n, err = io.ReadFull(d.r, ignored[:min(len(ignored), int(length))])
+ n, err := io.ReadFull(d.r, ignored[:min(len(ignored), int(length))])
if err != nil {
return err
}
diff --git a/src/internal/poll/copy_file_range_linux.go b/src/internal/poll/copy_file_range_linux.go
index 98210cc..604607f 100644
--- a/src/internal/poll/copy_file_range_linux.go
+++ b/src/internal/poll/copy_file_range_linux.go
@@ -88,6 +88,12 @@
return 0, err
}
defer src.readUnlock()
- n, err := unix.CopyFileRange(src.Sysfd, nil, dst.Sysfd, nil, max, 0)
+ var n int
+ for {
+ n, err = unix.CopyFileRange(src.Sysfd, nil, dst.Sysfd, nil, max, 0)
+ if err != syscall.EINTR {
+ break
+ }
+ }
return int64(n), err
}
diff --git a/src/internal/poll/fd_unix.go b/src/internal/poll/fd_unix.go
index 4716d58..85c79bb 100644
--- a/src/internal/poll/fd_unix.go
+++ b/src/internal/poll/fd_unix.go
@@ -8,7 +8,6 @@
import (
"io"
- "runtime"
"sync/atomic"
"syscall"
)
@@ -153,7 +152,7 @@
p = p[:maxRW]
}
for {
- n, err := syscall.Read(fd.Sysfd, p)
+ n, err := ignoringEINTR(syscall.Read, fd.Sysfd, p)
if err != nil {
n = 0
if err == syscall.EAGAIN && fd.pd.pollable() {
@@ -161,12 +160,6 @@
continue
}
}
-
- // On MacOS we can see EINTR here if the user
- // pressed ^Z. See issue #22838.
- if runtime.GOOS == "darwin" && err == syscall.EINTR {
- continue
- }
}
err = fd.eofError(n, err)
return n, err
@@ -184,7 +177,16 @@
if fd.IsStream && len(p) > maxRW {
p = p[:maxRW]
}
- n, err := syscall.Pread(fd.Sysfd, p, off)
+ var (
+ n int
+ err error
+ )
+ for {
+ n, err = syscall.Pread(fd.Sysfd, p, off)
+ if err != syscall.EINTR {
+ break
+ }
+ }
if err != nil {
n = 0
}
@@ -205,6 +207,9 @@
for {
n, sa, err := syscall.Recvfrom(fd.Sysfd, p, 0)
if err != nil {
+ if err == syscall.EINTR {
+ continue
+ }
n = 0
if err == syscall.EAGAIN && fd.pd.pollable() {
if err = fd.pd.waitRead(fd.isFile); err == nil {
@@ -229,6 +234,9 @@
for {
n, oobn, flags, sa, err := syscall.Recvmsg(fd.Sysfd, p, oob, 0)
if err != nil {
+ if err == syscall.EINTR {
+ continue
+ }
// TODO(dfc) should n and oobn be set to 0
if err == syscall.EAGAIN && fd.pd.pollable() {
if err = fd.pd.waitRead(fd.isFile); err == nil {
@@ -256,7 +264,7 @@
if fd.IsStream && max-nn > maxRW {
max = nn + maxRW
}
- n, err := syscall.Write(fd.Sysfd, p[nn:max])
+ n, err := ignoringEINTR(syscall.Write, fd.Sysfd, p[nn:max])
if n > 0 {
nn += n
}
@@ -293,6 +301,9 @@
max = nn + maxRW
}
n, err := syscall.Pwrite(fd.Sysfd, p[nn:max], off+int64(nn))
+ if err == syscall.EINTR {
+ continue
+ }
if n > 0 {
nn += n
}
@@ -319,6 +330,9 @@
}
for {
err := syscall.Sendto(fd.Sysfd, p, 0, sa)
+ if err == syscall.EINTR {
+ continue
+ }
if err == syscall.EAGAIN && fd.pd.pollable() {
if err = fd.pd.waitWrite(fd.isFile); err == nil {
continue
@@ -342,6 +356,9 @@
}
for {
n, err := syscall.SendmsgN(fd.Sysfd, p, oob, sa, 0)
+ if err == syscall.EINTR {
+ continue
+ }
if err == syscall.EAGAIN && fd.pd.pollable() {
if err = fd.pd.waitWrite(fd.isFile); err == nil {
continue
@@ -370,6 +387,8 @@
return s, rsa, "", err
}
switch err {
+ case syscall.EINTR:
+ continue
case syscall.EAGAIN:
if fd.pd.pollable() {
if err = fd.pd.waitRead(fd.isFile); err == nil {
@@ -404,7 +423,7 @@
}
defer fd.decref()
for {
- n, err := syscall.ReadDirent(fd.Sysfd, buf)
+ n, err := ignoringEINTR(syscall.ReadDirent, fd.Sysfd, buf)
if err != nil {
n = 0
if err == syscall.EAGAIN && fd.pd.pollable() {
@@ -495,7 +514,7 @@
return 0, err
}
defer fd.writeUnlock()
- return syscall.Write(fd.Sysfd, p)
+ return ignoringEINTR(syscall.Write, fd.Sysfd, p)
}
// RawRead invokes the user-defined function f for a read operation.
@@ -535,3 +554,19 @@
}
}
}
+
+// ignoringEINTR makes a function call and repeats it if it returns
+// an EINTR error. This appears to be required even though we install
+// all signal handlers with SA_RESTART: see #22838, #38033, #38836.
+// Also #20400 and #36644 are issues in which a signal handler is
+// installed without setting SA_RESTART. None of these are the common case,
+// but there are enough of them that it seems that we can't avoid
+// an EINTR loop.
+func ignoringEINTR(fn func(fd int, p []byte) (int, error), fd int, p []byte) (int, error) {
+ for {
+ n, err := fn(fd, p)
+ if err != syscall.EINTR {
+ return n, err
+ }
+ }
+}
diff --git a/src/internal/poll/fd_writev_unix.go b/src/internal/poll/fd_writev_unix.go
index 86af795..daeec96c 100644
--- a/src/internal/poll/fd_writev_unix.go
+++ b/src/internal/poll/fd_writev_unix.go
@@ -12,9 +12,18 @@
)
func writev(fd int, iovecs []syscall.Iovec) (uintptr, error) {
- r, _, e := syscall.Syscall(syscall.SYS_WRITEV, uintptr(fd), uintptr(unsafe.Pointer(&iovecs[0])), uintptr(len(iovecs)))
+ var (
+ r uintptr
+ e syscall.Errno
+ )
+ for {
+ r, _, e = syscall.Syscall(syscall.SYS_WRITEV, uintptr(fd), uintptr(unsafe.Pointer(&iovecs[0])), uintptr(len(iovecs)))
+ if e != syscall.EINTR {
+ break
+ }
+ }
if e != 0 {
- return r, syscall.Errno(e)
+ return r, e
}
return r, nil
}
diff --git a/src/internal/poll/sendfile_bsd.go b/src/internal/poll/sendfile_bsd.go
index 40ae346..a24e41d 100644
--- a/src/internal/poll/sendfile_bsd.go
+++ b/src/internal/poll/sendfile_bsd.go
@@ -35,6 +35,9 @@
} else if n == 0 && err1 == nil {
break
}
+ if err1 == syscall.EINTR {
+ continue
+ }
if err1 == syscall.EAGAIN {
if err1 = dstFD.pd.waitWrite(dstFD.isFile); err1 == nil {
continue
diff --git a/src/internal/poll/sendfile_linux.go b/src/internal/poll/sendfile_linux.go
index 8e93806..d642830 100644
--- a/src/internal/poll/sendfile_linux.go
+++ b/src/internal/poll/sendfile_linux.go
@@ -32,6 +32,9 @@
} else if n == 0 && err1 == nil {
break
}
+ if err1 == syscall.EINTR {
+ continue
+ }
if err1 == syscall.EAGAIN {
if err1 = dstFD.pd.waitWrite(dstFD.isFile); err1 == nil {
continue
diff --git a/src/internal/poll/splice_linux.go b/src/internal/poll/splice_linux.go
index 5b17ae85..01baf14 100644
--- a/src/internal/poll/splice_linux.go
+++ b/src/internal/poll/splice_linux.go
@@ -87,6 +87,9 @@
}
for {
n, err := splice(pipefd, sock.Sysfd, max, spliceNonblock)
+ if err == syscall.EINTR {
+ continue
+ }
if err != syscall.EAGAIN {
return n, err
}
diff --git a/src/internal/poll/writev.go b/src/internal/poll/writev.go
index 6050d1f..305e2fd 100644
--- a/src/internal/poll/writev.go
+++ b/src/internal/poll/writev.go
@@ -68,7 +68,10 @@
iovecs[i] = syscall.Iovec{}
}
if err != nil {
- if err.(syscall.Errno) == syscall.EAGAIN {
+ if err == syscall.EINTR {
+ continue
+ }
+ if err == syscall.EAGAIN {
if err = fd.pd.waitWrite(fd.isFile); err == nil {
continue
}
diff --git a/src/internal/trace/writer.go b/src/internal/trace/writer.go
index af5fec8..dd0b9f1 100644
--- a/src/internal/trace/writer.go
+++ b/src/internal/trace/writer.go
@@ -1,3 +1,7 @@
+// Copyright 2017 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 trace
import "bytes"
diff --git a/src/net/http/pprof/pprof.go b/src/net/http/pprof/pprof.go
index 4fd19eb..81df044 100644
--- a/src/net/http/pprof/pprof.go
+++ b/src/net/http/pprof/pprof.go
@@ -36,15 +36,17 @@
//
// go tool pprof http://localhost:6060/debug/pprof/block
//
-// Or to collect a 5-second execution trace:
-//
-// wget http://localhost:6060/debug/pprof/trace?seconds=5
-//
// Or to look at the holders of contended mutexes, after calling
// runtime.SetMutexProfileFraction in your program:
//
// go tool pprof http://localhost:6060/debug/pprof/mutex
//
+// The package also exports a handler that serves execution trace data
+// for the "go tool trace" command. To collect a 5-second execution trace:
+//
+// wget -O trace.out http://localhost:6060/debug/pprof/trace?seconds=5
+// go tool trace trace.out
+//
// To view all available profiles, open http://localhost:6060/debug/pprof/
// in your browser.
//
diff --git a/src/net/sockopt_aix.go b/src/net/sockopt_aix.go
index b49c4d5..7729a44 100644
--- a/src/net/sockopt_aix.go
+++ b/src/net/sockopt_aix.go
@@ -16,8 +16,11 @@
// never admit this option.
syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only))
}
- // Allow broadcast.
- return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1))
+ if (sotype == syscall.SOCK_DGRAM || sotype == syscall.SOCK_RAW) && family != syscall.AF_UNIX {
+ // Allow broadcast.
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1))
+ }
+ return nil
}
func setDefaultListenerSockopts(s int) error {
diff --git a/src/net/sockopt_bsd.go b/src/net/sockopt_bsd.go
index 4ecc8cb..8fd1e88 100644
--- a/src/net/sockopt_bsd.go
+++ b/src/net/sockopt_bsd.go
@@ -31,8 +31,11 @@
// never admit this option.
syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only))
}
- // Allow broadcast.
- return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1))
+ if (sotype == syscall.SOCK_DGRAM || sotype == syscall.SOCK_RAW) && family != syscall.AF_UNIX {
+ // Allow broadcast.
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1))
+ }
+ return nil
}
func setDefaultListenerSockopts(s int) error {
diff --git a/src/net/sockopt_linux.go b/src/net/sockopt_linux.go
index 0f70b12..3d54429 100644
--- a/src/net/sockopt_linux.go
+++ b/src/net/sockopt_linux.go
@@ -16,8 +16,11 @@
// never admit this option.
syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only))
}
- // Allow broadcast.
- return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1))
+ if (sotype == syscall.SOCK_DGRAM || sotype == syscall.SOCK_RAW) && family != syscall.AF_UNIX {
+ // Allow broadcast.
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1))
+ }
+ return nil
}
func setDefaultListenerSockopts(s int) error {
diff --git a/src/net/sockopt_solaris.go b/src/net/sockopt_solaris.go
index 0f70b12..3d54429 100644
--- a/src/net/sockopt_solaris.go
+++ b/src/net/sockopt_solaris.go
@@ -16,8 +16,11 @@
// never admit this option.
syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only))
}
- // Allow broadcast.
- return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1))
+ if (sotype == syscall.SOCK_DGRAM || sotype == syscall.SOCK_RAW) && family != syscall.AF_UNIX {
+ // Allow broadcast.
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1))
+ }
+ return nil
}
func setDefaultListenerSockopts(s int) error {
diff --git a/src/net/sockopt_windows.go b/src/net/sockopt_windows.go
index 8017426..8afaf34 100644
--- a/src/net/sockopt_windows.go
+++ b/src/net/sockopt_windows.go
@@ -16,8 +16,10 @@
// never admit this option.
syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only))
}
- // Allow broadcast.
- syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
+ if (sotype == syscall.SOCK_DGRAM || sotype == syscall.SOCK_RAW) && family != syscall.AF_UNIX && family != syscall.AF_INET6 {
+ // Allow broadcast.
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1))
+ }
return nil
}
diff --git a/src/os/exec_unix.go b/src/os/exec_unix.go
index 6e4ffe8..7759a2d 100644
--- a/src/os/exec_unix.go
+++ b/src/os/exec_unix.go
@@ -33,9 +33,18 @@
p.sigMu.Unlock()
}
- var status syscall.WaitStatus
- var rusage syscall.Rusage
- pid1, e := syscall.Wait4(p.Pid, &status, 0, &rusage)
+ var (
+ status syscall.WaitStatus
+ rusage syscall.Rusage
+ pid1 int
+ e error
+ )
+ for {
+ pid1, e = syscall.Wait4(p.Pid, &status, 0, &rusage)
+ if e != syscall.EINTR {
+ break
+ }
+ }
if e != nil {
return nil, NewSyscallError("wait", e)
}
diff --git a/src/os/wait_wait6.go b/src/os/wait_wait6.go
index 45bf6490..5420b2d 100644
--- a/src/os/wait_wait6.go
+++ b/src/os/wait_wait6.go
@@ -18,15 +18,20 @@
// It does not actually call p.Wait.
func (p *Process) blockUntilWaitable() (bool, error) {
var errno syscall.Errno
- // The arguments on 32-bit FreeBSD look like the following:
- // - freebsd32_wait6_args{ idtype, id1, id2, status, options, wrusage, info } or
- // - freebsd32_wait6_args{ idtype, pad, id1, id2, status, options, wrusage, info } when PAD64_REQUIRED=1 on ARM, MIPS or PowerPC
- if runtime.GOARCH == "386" {
- _, _, errno = syscall.Syscall9(syscall.SYS_WAIT6, _P_PID, uintptr(p.Pid), 0, 0, syscall.WEXITED|syscall.WNOWAIT, 0, 0, 0, 0)
- } else if runtime.GOARCH == "arm" {
- _, _, errno = syscall.Syscall9(syscall.SYS_WAIT6, _P_PID, 0, uintptr(p.Pid), 0, 0, syscall.WEXITED|syscall.WNOWAIT, 0, 0, 0)
- } else {
- _, _, errno = syscall.Syscall6(syscall.SYS_WAIT6, _P_PID, uintptr(p.Pid), 0, syscall.WEXITED|syscall.WNOWAIT, 0, 0)
+ for {
+ // The arguments on 32-bit FreeBSD look like the following:
+ // - freebsd32_wait6_args{ idtype, id1, id2, status, options, wrusage, info } or
+ // - freebsd32_wait6_args{ idtype, pad, id1, id2, status, options, wrusage, info } when PAD64_REQUIRED=1 on ARM, MIPS or PowerPC
+ if runtime.GOARCH == "386" {
+ _, _, errno = syscall.Syscall9(syscall.SYS_WAIT6, _P_PID, uintptr(p.Pid), 0, 0, syscall.WEXITED|syscall.WNOWAIT, 0, 0, 0, 0)
+ } else if runtime.GOARCH == "arm" {
+ _, _, errno = syscall.Syscall9(syscall.SYS_WAIT6, _P_PID, 0, uintptr(p.Pid), 0, 0, syscall.WEXITED|syscall.WNOWAIT, 0, 0, 0)
+ } else {
+ _, _, errno = syscall.Syscall6(syscall.SYS_WAIT6, _P_PID, uintptr(p.Pid), 0, syscall.WEXITED|syscall.WNOWAIT, 0, 0)
+ }
+ if errno != syscall.EINTR {
+ break
+ }
}
runtime.KeepAlive(p)
if errno != 0 {
diff --git a/src/os/wait_waitid.go b/src/os/wait_waitid.go
index 6c904e5..9c56eb2 100644
--- a/src/os/wait_waitid.go
+++ b/src/os/wait_waitid.go
@@ -27,7 +27,13 @@
// We don't care about the values it returns.
var siginfo [16]uint64
psig := &siginfo[0]
- _, _, e := syscall.Syscall6(syscall.SYS_WAITID, _P_PID, uintptr(p.Pid), uintptr(unsafe.Pointer(psig)), syscall.WEXITED|syscall.WNOWAIT, 0, 0)
+ var e syscall.Errno
+ for {
+ _, _, e = syscall.Syscall6(syscall.SYS_WAITID, _P_PID, uintptr(p.Pid), uintptr(unsafe.Pointer(psig)), syscall.WEXITED|syscall.WNOWAIT, 0, 0)
+ if e != syscall.EINTR {
+ break
+ }
+ }
runtime.KeepAlive(p)
if e != 0 {
// waitid has been available since Linux 2.6.9, but
diff --git a/src/runtime/cgo/gcc_android.c b/src/runtime/cgo/gcc_android.c
index 321a515..7ea2135 100644
--- a/src/runtime/cgo/gcc_android.c
+++ b/src/runtime/cgo/gcc_android.c
@@ -35,7 +35,7 @@
// Truncated to a different magic value on 32-bit; that's ok.
#define magic1 (0x23581321345589ULL)
-// From https://android.googlesource.com/platform/bionic/+/refs/heads/master/libc/private/bionic_asm_tls.h#69.
+// From https://android.googlesource.com/platform/bionic/+/refs/heads/android10-tests-release/libc/private/bionic_asm_tls.h#69.
#define TLS_SLOT_APP 2
// inittls allocates a thread-local storage slot for g.
diff --git a/src/runtime/crash_cgo_test.go b/src/runtime/crash_cgo_test.go
index a4d0ebf..4872189 100644
--- a/src/runtime/crash_cgo_test.go
+++ b/src/runtime/crash_cgo_test.go
@@ -573,3 +573,30 @@
})
}
}
+
+// TestEINTR tests that we handle EINTR correctly.
+// See issue #20400 and friends.
+func TestEINTR(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9", "windows":
+ t.Skipf("no EINTR on %s", runtime.GOOS)
+ case "linux":
+ if runtime.GOARCH == "386" {
+ // On linux-386 the Go signal handler sets
+ // a restorer function that is not preserved
+ // by the C sigaction call in the test,
+ // causing the signal handler to crash when
+ // returning the normal code. The test is not
+ // architecture-specific, so just skip on 386
+ // rather than doing a complicated workaround.
+ t.Skip("skipping on linux-386; C sigaction does not preserve Go restorer")
+ }
+ }
+
+ t.Parallel()
+ output := runTestProg(t, "testprogcgo", "EINTR")
+ want := "OK\n"
+ if output != want {
+ t.Fatalf("want %s, got %s\n", want, output)
+ }
+}
diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go
index 37271e4..5ab03f3 100644
--- a/src/runtime/export_test.go
+++ b/src/runtime/export_test.go
@@ -876,13 +876,9 @@
// 64 bit and 32 bit platforms, allowing the tests to share code
// between the two.
//
-// On AIX, the arenaBaseOffset is 0x0a00000000000000. However, this
-// constant can't be used here because it is negative and will cause
-// a constant overflow.
-//
// This should not be higher than 0x100*pallocChunkBytes to support
// mips and mipsle, which only have 31-bit address spaces.
-var BaseChunkIdx = ChunkIdx(chunkIndex(((0xc000*pageAlloc64Bit + 0x100*pageAlloc32Bit) * pallocChunkBytes) + 0x0a00000000000000*sys.GoosAix))
+var BaseChunkIdx = ChunkIdx(chunkIndex(((0xc000*pageAlloc64Bit + 0x100*pageAlloc32Bit) * pallocChunkBytes) + arenaBaseOffset*sys.GoosAix))
// PageBase returns an address given a chunk index and a page index
// relative to that chunk.
diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go
index 0fbf45f..77a5a38 100644
--- a/src/runtime/malloc.go
+++ b/src/runtime/malloc.go
@@ -302,7 +302,7 @@
//
// On other platforms, the user address space is contiguous
// and starts at 0, so no offset is necessary.
- arenaBaseOffset = sys.GoarchAmd64*(1<<47) + (^0x0a00000000000000+1)&uintptrMask*sys.GoosAix
+ arenaBaseOffset = 0xffff800000000000*sys.GoarchAmd64 + 0x0a00000000000000*sys.GoosAix
// Max number of threads to run garbage collection.
// 2, 3, and 4 are all plausible maximums depending
diff --git a/src/runtime/mheap.go b/src/runtime/mheap.go
index 3f57b0b..6f7dc6e 100644
--- a/src/runtime/mheap.go
+++ b/src/runtime/mheap.go
@@ -576,13 +576,13 @@
//
//go:nosplit
func arenaIndex(p uintptr) arenaIdx {
- return arenaIdx((p + arenaBaseOffset) / heapArenaBytes)
+ return arenaIdx((p - arenaBaseOffset) / heapArenaBytes)
}
// arenaBase returns the low address of the region covered by heap
// arena i.
func arenaBase(i arenaIdx) uintptr {
- return uintptr(i)*heapArenaBytes - arenaBaseOffset
+ return uintptr(i)*heapArenaBytes + arenaBaseOffset
}
type arenaIdx uint
diff --git a/src/runtime/mpagealloc.go b/src/runtime/mpagealloc.go
index a28dd26..60f7f9f 100644
--- a/src/runtime/mpagealloc.go
+++ b/src/runtime/mpagealloc.go
@@ -99,12 +99,12 @@
// chunkIndex returns the global index of the palloc chunk containing the
// pointer p.
func chunkIndex(p uintptr) chunkIdx {
- return chunkIdx((p + arenaBaseOffset) / pallocChunkBytes)
+ return chunkIdx((p - arenaBaseOffset) / pallocChunkBytes)
}
// chunkIndex returns the base address of the palloc chunk at index ci.
func chunkBase(ci chunkIdx) uintptr {
- return uintptr(ci)*pallocChunkBytes - arenaBaseOffset
+ return uintptr(ci)*pallocChunkBytes + arenaBaseOffset
}
// chunkPageIndex computes the index of the page that contains p,
@@ -136,13 +136,13 @@
// offAddrToLevelIndex converts an address in the offset address space
// to the index into summary[level] containing addr.
func offAddrToLevelIndex(level int, addr offAddr) int {
- return int((addr.a + arenaBaseOffset) >> levelShift[level])
+ return int((addr.a - arenaBaseOffset) >> levelShift[level])
}
// levelIndexToOffAddr converts an index into summary[level] into
// the corresponding address in the offset address space.
func levelIndexToOffAddr(level, idx int) offAddr {
- return offAddr{(uintptr(idx) << levelShift[level]) - arenaBaseOffset}
+ return offAddr{(uintptr(idx) << levelShift[level]) + arenaBaseOffset}
}
// addrsToSummaryRange converts base and limit pointers into a range
@@ -159,8 +159,8 @@
// of a summary's max page count boundary for this level
// (1 << levelLogPages[level]). So, make limit an inclusive upper bound
// then shift, then add 1, so we get an exclusive upper bound at the end.
- lo = int((base + arenaBaseOffset) >> levelShift[level])
- hi = int(((limit-1)+arenaBaseOffset)>>levelShift[level]) + 1
+ lo = int((base - arenaBaseOffset) >> levelShift[level])
+ hi = int(((limit-1)-arenaBaseOffset)>>levelShift[level]) + 1
return
}
diff --git a/src/runtime/mranges.go b/src/runtime/mranges.go
index e574c2f..c2b8e71 100644
--- a/src/runtime/mranges.go
+++ b/src/runtime/mranges.go
@@ -31,7 +31,7 @@
// Throws if the base and limit are not in the same memory segment.
func makeAddrRange(base, limit uintptr) addrRange {
r := addrRange{offAddr{base}, offAddr{limit}}
- if (base+arenaBaseOffset >= arenaBaseOffset) != (limit+arenaBaseOffset >= arenaBaseOffset) {
+ if (base-arenaBaseOffset >= base) != (limit-arenaBaseOffset >= limit) {
throw("addr range base and limit are not in the same memory segment")
}
return r
@@ -71,33 +71,21 @@
var (
// minOffAddr is the minimum address in the offset space, and
- // it corresponds to the virtual address -arenaBaseOffset.
- //
- // We don't initialize this with offAddrFromRaw because allocation
- // may happen during bootstrapping, and we rely on this value
- // being initialized.
- //
- // As a result, creating this value in Go is tricky because of
- // overflow not being allowed in constants. In order to get
- // the value we want, we take arenaBaseOffset and do a manual
- // two's complement negation, then mask that into what can fit
- // into a uintptr.
- minOffAddr = offAddr{((^arenaBaseOffset) + 1) & uintptrMask}
+ // it corresponds to the virtual address arenaBaseOffset.
+ minOffAddr = offAddr{arenaBaseOffset}
// maxOffAddr is the maximum address in the offset address
- // space, and it corresponds to the virtual address
- // ^uintptr(0) - arenaBaseOffset.
- //
- // We don't initialize this with offAddrFromRaw because allocation
- // may happen during bootstrapping, and we rely on this value
- // being initialized.
- maxOffAddr = offAddr{^uintptr(0) - arenaBaseOffset}
+ // space. It corresponds to the highest virtual address representable
+ // by the page alloc chunk and heap arena maps.
+ maxOffAddr = offAddr{(((1 << heapAddrBits) - 1) + arenaBaseOffset) & uintptrMask}
)
// offAddr represents an address in a contiguous view
// of the address space on systems where the address space is
// segmented. On other systems, it's just a normal address.
type offAddr struct {
+ // a is just the virtual address, but should never be used
+ // directly. Call addr() to get this value instead.
a uintptr
}
@@ -120,13 +108,13 @@
// lessThan returns true if l1 is less than l2 in the offset
// address space.
func (l1 offAddr) lessThan(l2 offAddr) bool {
- return (l1.a + arenaBaseOffset) < (l2.a + arenaBaseOffset)
+ return (l1.a - arenaBaseOffset) < (l2.a - arenaBaseOffset)
}
// lessEqual returns true if l1 is less than or equal to l2 in
// the offset address space.
func (l1 offAddr) lessEqual(l2 offAddr) bool {
- return (l1.a + arenaBaseOffset) <= (l2.a + arenaBaseOffset)
+ return (l1.a - arenaBaseOffset) <= (l2.a - arenaBaseOffset)
}
// equal returns true if the two offAddr values are equal.
diff --git a/src/runtime/testdata/testprog/numcpu_freebsd.go b/src/runtime/testdata/testprog/numcpu_freebsd.go
index 42ee154..aff36ec 100644
--- a/src/runtime/testdata/testprog/numcpu_freebsd.go
+++ b/src/runtime/testdata/testprog/numcpu_freebsd.go
@@ -85,7 +85,13 @@
if err != nil {
return nil, fmt.Errorf("fail to execute '%s': %s", cmdline, err)
}
- pos := bytes.IndexRune(output, ':')
+ pos := bytes.IndexRune(output, '\n')
+ if pos == -1 {
+ return nil, fmt.Errorf("invalid output from '%s', '\\n' not found: %s", cmdline, output)
+ }
+ output = output[0:pos]
+
+ pos = bytes.IndexRune(output, ':')
if pos == -1 {
return nil, fmt.Errorf("invalid output from '%s', ':' not found: %s", cmdline, output)
}
diff --git a/src/runtime/testdata/testprogcgo/eintr.go b/src/runtime/testdata/testprogcgo/eintr.go
new file mode 100644
index 0000000..58f0dd2
--- /dev/null
+++ b/src/runtime/testdata/testprogcgo/eintr.go
@@ -0,0 +1,240 @@
+// Copyright 2020 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.
+
+// +build !plan9,!windows
+
+package main
+
+/*
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+
+static int clearRestart(int sig) {
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof sa);
+ if (sigaction(sig, NULL, &sa) < 0) {
+ return errno;
+ }
+ sa.sa_flags &=~ SA_RESTART;
+ if (sigaction(sig, &sa, NULL) < 0) {
+ return errno;
+ }
+ return 0;
+}
+*/
+import "C"
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "log"
+ "net"
+ "os"
+ "os/exec"
+ "os/signal"
+ "sync"
+ "syscall"
+ "time"
+)
+
+func init() {
+ register("EINTR", EINTR)
+ register("Block", Block)
+}
+
+// Test various operations when a signal handler is installed without
+// the SA_RESTART flag. This tests that the os and net APIs handle EINTR.
+func EINTR() {
+ if errno := C.clearRestart(C.int(syscall.SIGURG)); errno != 0 {
+ log.Fatal(syscall.Errno(errno))
+ }
+ if errno := C.clearRestart(C.int(syscall.SIGWINCH)); errno != 0 {
+ log.Fatal(syscall.Errno(errno))
+ }
+ if errno := C.clearRestart(C.int(syscall.SIGCHLD)); errno != 0 {
+ log.Fatal(syscall.Errno(errno))
+ }
+
+ var wg sync.WaitGroup
+ testPipe(&wg)
+ testNet(&wg)
+ testExec(&wg)
+ wg.Wait()
+ fmt.Println("OK")
+}
+
+// spin does CPU bound spinning and allocating for a millisecond,
+// to get a SIGURG.
+//go:noinline
+func spin() (float64, [][]byte) {
+ stop := time.Now().Add(time.Millisecond)
+ r1 := 0.0
+ var r2 [][]byte
+ for time.Now().Before(stop) {
+ for i := 1; i < 1e6; i++ {
+ r1 += r1 / float64(i)
+ r2 = append(r2, bytes.Repeat([]byte{byte(i)}, 100))
+ }
+ }
+ return r1, r2
+}
+
+// winch sends a few SIGWINCH signals to the process.
+func winch() {
+ ticker := time.NewTicker(100 * time.Microsecond)
+ defer ticker.Stop()
+ for n := 10; n > 0; n-- {
+ syscall.Kill(0, syscall.SIGWINCH)
+ <-ticker.C
+ }
+}
+
+// sendSomeSignals triggers a few SIGURG and SIGWINCH signals.
+func sendSomeSignals() {
+ spin()
+ winch()
+}
+
+// testPipe tests pipe operations.
+func testPipe(wg *sync.WaitGroup) {
+ r, w, err := os.Pipe()
+ if err != nil {
+ log.Fatal(err)
+ }
+ if err := syscall.SetNonblock(int(r.Fd()), false); err != nil {
+ log.Fatal(err)
+ }
+ if err := syscall.SetNonblock(int(w.Fd()), false); err != nil {
+ log.Fatal(err)
+ }
+ wg.Add(2)
+ go func() {
+ defer wg.Done()
+ defer w.Close()
+ // Spin before calling Write so that the first ReadFull
+ // in the other goroutine will likely be interrupted
+ // by a signal.
+ sendSomeSignals()
+ // This Write will likely be interrupted by a signal
+ // as the other goroutine spins in the middle of reading.
+ // We write enough data that we should always fill the
+ // pipe buffer and need multiple write system calls.
+ if _, err := w.Write(bytes.Repeat([]byte{0}, 2<<20)); err != nil {
+ log.Fatal(err)
+ }
+ }()
+ go func() {
+ defer wg.Done()
+ defer r.Close()
+ b := make([]byte, 1<<20)
+ // This ReadFull will likely be interrupted by a signal,
+ // as the other goroutine spins before writing anything.
+ if _, err := io.ReadFull(r, b); err != nil {
+ log.Fatal(err)
+ }
+ // Spin after reading half the data so that the Write
+ // in the other goroutine will likely be interrupted
+ // before it completes.
+ sendSomeSignals()
+ if _, err := io.ReadFull(r, b); err != nil {
+ log.Fatal(err)
+ }
+ }()
+}
+
+// testNet tests network operations.
+func testNet(wg *sync.WaitGroup) {
+ ln, err := net.Listen("tcp4", "127.0.0.1:0")
+ if err != nil {
+ if errors.Is(err, syscall.EAFNOSUPPORT) || errors.Is(err, syscall.EPROTONOSUPPORT) {
+ return
+ }
+ log.Fatal(err)
+ }
+ wg.Add(2)
+ go func() {
+ defer wg.Done()
+ defer ln.Close()
+ c, err := ln.Accept()
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer c.Close()
+ cf, err := c.(*net.TCPConn).File()
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer cf.Close()
+ if err := syscall.SetNonblock(int(cf.Fd()), false); err != nil {
+ log.Fatal(err)
+ }
+ // See comments in testPipe.
+ sendSomeSignals()
+ if _, err := cf.Write(bytes.Repeat([]byte{0}, 2<<20)); err != nil {
+ log.Fatal(err)
+ }
+ }()
+ go func() {
+ defer wg.Done()
+ sendSomeSignals()
+ c, err := net.Dial("tcp", ln.Addr().String())
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer c.Close()
+ cf, err := c.(*net.TCPConn).File()
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer cf.Close()
+ if err := syscall.SetNonblock(int(cf.Fd()), false); err != nil {
+ log.Fatal(err)
+ }
+ // See comments in testPipe.
+ b := make([]byte, 1<<20)
+ if _, err := io.ReadFull(cf, b); err != nil {
+ log.Fatal(err)
+ }
+ sendSomeSignals()
+ if _, err := io.ReadFull(cf, b); err != nil {
+ log.Fatal(err)
+ }
+ }()
+}
+
+func testExec(wg *sync.WaitGroup) {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ cmd := exec.Command(os.Args[0], "Block")
+ cmd.Stderr = new(bytes.Buffer)
+ cmd.Stdout = cmd.Stderr
+ if err := cmd.Start(); err != nil {
+ log.Fatal(err)
+ }
+
+ go func() {
+ sendSomeSignals()
+ if err := cmd.Process.Signal(os.Interrupt); err != nil {
+ panic(err)
+ }
+ }()
+
+ if err := cmd.Wait(); err != nil {
+ log.Fatalf("%v:\n%s", err, cmd.Stdout)
+ }
+ }()
+}
+
+// Block blocks until the process receives os.Interrupt.
+func Block() {
+ c := make(chan os.Signal, 1)
+ signal.Notify(c, os.Interrupt)
+ defer signal.Stop(c)
+ <-c
+}
diff --git a/src/runtime/trace/trace_stack_test.go b/src/runtime/trace/trace_stack_test.go
index e3608c6..cfc0419 100644
--- a/src/runtime/trace/trace_stack_test.go
+++ b/src/runtime/trace/trace_stack_test.go
@@ -252,6 +252,7 @@
{trace.EvGoSysCall, []frame{
{"syscall.read", 0},
{"syscall.Read", 0},
+ {"internal/poll.ignoringEINTR", 0},
{"internal/poll.(*FD).Read", 0},
{"os.(*File).read", 0},
{"os.(*File).Read", 0},
diff --git a/src/strconv/atoc_test.go b/src/strconv/atoc_test.go
index 5c817a2..3aa421d 100644
--- a/src/strconv/atoc_test.go
+++ b/src/strconv/atoc_test.go
@@ -17,6 +17,7 @@
infm0 = complex(math.Inf(-1), 0)
inf0p = complex(0, math.Inf(+1))
inf0m = complex(0, math.Inf(-1))
+
infpp = complex(math.Inf(+1), math.Inf(+1))
infpm = complex(math.Inf(+1), math.Inf(-1))
infmp = complex(math.Inf(-1), math.Inf(+1))
@@ -30,7 +31,6 @@
}
func TestParseComplex(t *testing.T) {
-
tests := []atocTest{
// Clearly invalid
{"", 0, ErrSyntax},
@@ -45,6 +45,7 @@
{"3+", 0, ErrSyntax},
{"3+5", 0, ErrSyntax},
{"3+5+5i", 0, ErrSyntax},
+
// Parentheses
{"()", 0, ErrSyntax},
{"(i)", 0, ErrSyntax},
@@ -54,6 +55,7 @@
{"(1)+1i", 0, ErrSyntax},
{"(3.0+5.5i", 0, ErrSyntax},
{"3.0+5.5i)", 0, ErrSyntax},
+
// NaNs
{"NaN", complex(math.NaN(), 0), nil},
{"NANi", complex(0, math.NaN()), nil},
@@ -61,6 +63,7 @@
{"+NaN", 0, ErrSyntax},
{"-NaN", 0, ErrSyntax},
{"NaN-NaNi", 0, ErrSyntax},
+
// Infs
{"Inf", infp0, nil},
{"+inf", infp0, nil},
@@ -74,6 +77,7 @@
{"+Inf-Infi", infpm, nil},
{"-Infinity+Infi", infmp, nil},
{"inf-inf", 0, ErrSyntax},
+
// Zeros
{"0", 0, nil},
{"0i", 0, nil},
@@ -88,6 +92,7 @@
{"+0e-0+0e-0i", 0, nil},
{"0e+0+0e+0i", 0, nil},
{"-0e+0-0e+0i", 0, nil},
+
// Regular non-zeroes
{"0.1", 0.1, nil},
{"0.1i", 0 + 0.1i, nil},
@@ -104,14 +109,17 @@
{"+3e+3-3e+3i", 3e+3 - 3e+3i, nil},
{"+3e+3+3e+3i", 3e+3 + 3e+3i, nil},
{"+3e+3+3e+3i+", 0, ErrSyntax},
+
// Separators
{"0.1", 0.1, nil},
{"0.1i", 0 + 0.1i, nil},
{"0.1_2_3", 0.123, nil},
{"+0x_3p3i", 0x3p3i, nil},
+ {"0_0+0x_0p0i", 0, nil},
{"0x_10.3p-8+0x3p3i", 0x10.3p-8 + 0x3p3i, nil},
- {"+0x_1_0.3p-8+0x3p3i", 0x10.3p-8 + 0x3p3i, nil},
- {"0x10.3p+8-0x_3p3i", 0x10.3p+8 - 0x3p3i, nil},
+ {"+0x_1_0.3p-8+0x_3_0p3i", 0x10.3p-8 + 0x30p3i, nil},
+ {"0x1_0.3p+8-0x_3p3i", 0x10.3p+8 - 0x3p3i, nil},
+
// Hexadecimals
{"0x10.3p-8+0x3p3i", 0x10.3p-8 + 0x3p3i, nil},
{"+0x10.3p-8+0x3p3i", 0x10.3p-8 + 0x3p3i, nil},
@@ -125,6 +133,7 @@
{"0x1e2", 0, ErrSyntax},
{"1p2", 0, ErrSyntax},
{"0x1e2i", 0, ErrSyntax},
+
// ErrRange
// next float64 - too large
{"+0x1p1024", infp0, ErrRange},
@@ -177,19 +186,17 @@
{"1e+4294967296+1e+4294967296i", infpp, ErrRange},
{"1e+4294967296-1e+4294967296i", infpm, ErrRange},
}
- for _, tt := range tests {
- tt := tt // for capture in Run closures below
- if tt.err != nil {
- tt.err = &NumError{Func: "ParseComplex", Num: tt.in, Err: tt.err}
+ for i := range tests {
+ test := &tests[i]
+ if test.err != nil {
+ test.err = &NumError{Func: "ParseComplex", Num: test.in, Err: test.err}
}
- t.Run(tt.in, func(t *testing.T) {
- got, err := ParseComplex(tt.in, 128)
- if !reflect.DeepEqual(err, tt.err) {
- t.Fatalf("ParseComplex(%q, 128) = %v, %v want %v, %v", tt.in, got, err, tt.out, tt.err)
- }
- if !(cmplx.IsNaN(tt.out) && cmplx.IsNaN(got)) && got != tt.out {
- t.Fatalf("ParseComplex(%q, 128) = %v, %v want %v, %v", tt.in, got, err, tt.out, tt.err)
- }
- })
+ got, err := ParseComplex(test.in, 128)
+ if !reflect.DeepEqual(err, test.err) {
+ t.Fatalf("ParseComplex(%q, 128) = %v, %v; want %v, %v", test.in, got, err, test.out, test.err)
+ }
+ if !(cmplx.IsNaN(test.out) && cmplx.IsNaN(got)) && got != test.out {
+ t.Fatalf("ParseComplex(%q, 128) = %v, %v; want %v, %v", test.in, got, err, test.out, test.err)
+ }
}
}
diff --git a/src/strconv/atof.go b/src/strconv/atof.go
index f20ae4a..901f27a 100644
--- a/src/strconv/atof.go
+++ b/src/strconv/atof.go
@@ -300,7 +300,7 @@
exp = dp - ndMant
}
- if underscores && !underscoreOK(s) {
+ if underscores && !underscoreOK(s[:i]) {
return
}
diff --git a/src/strconv/atof_test.go b/src/strconv/atof_test.go
index c30cb2e..545d989 100644
--- a/src/strconv/atof_test.go
+++ b/src/strconv/atof_test.go
@@ -480,7 +480,7 @@
}
func TestParseFloatPrefix(t *testing.T) {
- for i := 0; i < len(atoftests); i++ {
+ for i := range atoftests {
test := &atoftests[i]
if test.err != nil {
continue
diff --git a/src/syscall/exec_linux_test.go b/src/syscall/exec_linux_test.go
index b7a8df2..b79dee7 100644
--- a/src/syscall/exec_linux_test.go
+++ b/src/syscall/exec_linux_test.go
@@ -355,7 +355,7 @@
}
cmd := exec.Command(os.Args[0], "-test.run=TestUnshareMountNameSpaceHelper", d)
- cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
+ cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1")
cmd.SysProcAttr = &syscall.SysProcAttr{Unshareflags: syscall.CLONE_NEWNS}
o, err := cmd.CombinedOutput()
@@ -406,7 +406,7 @@
}
cmd = exec.Command("/syscall.test", "-test.run=TestUnshareMountNameSpaceHelper", "/")
- cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
+ cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1")
cmd.SysProcAttr = &syscall.SysProcAttr{Chroot: d, Unshareflags: syscall.CLONE_NEWNS}
o, err := cmd.CombinedOutput()
@@ -621,7 +621,7 @@
}
cmd := exec.Command(f.Name(), "-test.run=TestAmbientCapsHelper")
- cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
+ cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.SysProcAttr = &syscall.SysProcAttr{
diff --git a/src/syscall/exec_unix.go b/src/syscall/exec_unix.go
index 0345af4..cb08b70 100644
--- a/src/syscall/exec_unix.go
+++ b/src/syscall/exec_unix.go
@@ -217,7 +217,12 @@
// Read child error status from pipe.
Close(p[1])
- n, err = readlen(p[0], (*byte)(unsafe.Pointer(&err1)), int(unsafe.Sizeof(err1)))
+ for {
+ n, err = readlen(p[0], (*byte)(unsafe.Pointer(&err1)), int(unsafe.Sizeof(err1)))
+ if err != EINTR {
+ break
+ }
+ }
Close(p[0])
if err != nil || n != 0 {
if n == int(unsafe.Sizeof(err1)) {
diff --git a/src/syscall/js/js_test.go b/src/syscall/js/js_test.go
index fea4c13..5fc9107 100644
--- a/src/syscall/js/js_test.go
+++ b/src/syscall/js/js_test.go
@@ -591,3 +591,14 @@
document.Get("body").Call("removeChild", div)
}
}
+
+func TestGlobal(t *testing.T) {
+ ident := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
+ return args[0]
+ })
+ defer ident.Release()
+
+ if got := ident.Invoke(js.Global()); !got.Equal(js.Global()) {
+ t.Errorf("got %#v, want %#v", got, js.Global())
+ }
+}
diff --git a/src/syscall/syscall_linux_test.go b/src/syscall/syscall_linux_test.go
index e30a10b..c5008f2 100644
--- a/src/syscall/syscall_linux_test.go
+++ b/src/syscall/syscall_linux_test.go
@@ -187,7 +187,7 @@
}
cmd := exec.Command(tmpBinary)
- cmd.Env = []string{"GO_DEATHSIG_PARENT=1"}
+ cmd.Env = append(os.Environ(), "GO_DEATHSIG_PARENT=1")
chldStdin, err := cmd.StdinPipe()
if err != nil {
t.Fatalf("failed to create new stdin pipe: %v", err)
@@ -225,7 +225,10 @@
func deathSignalParent() {
cmd := exec.Command(os.Args[0])
- cmd.Env = []string{"GO_DEATHSIG_CHILD=1"}
+ cmd.Env = append(os.Environ(),
+ "GO_DEATHSIG_PARENT=",
+ "GO_DEATHSIG_CHILD=1",
+ )
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
attrs := syscall.SysProcAttr{
@@ -356,7 +359,7 @@
}
cmd := exec.Command(tmpBinary)
- cmd.Env = []string{"GO_SYSCALL_NOERROR=1"}
+ cmd.Env = append(os.Environ(), "GO_SYSCALL_NOERROR=1")
out, err := cmd.CombinedOutput()
if err != nil {
diff --git a/src/testing/testing.go b/src/testing/testing.go
index 90c15a2..216e46e 100644
--- a/src/testing/testing.go
+++ b/src/testing/testing.go
@@ -219,9 +219,12 @@
// directly. TestMain runs in the main goroutine and can do whatever setup
// and teardown is necessary around a call to m.Run. m.Run will return an exit
// code that may be passed to os.Exit. If TestMain returns, the test wrapper
-// will pass the result of m.Run to os.Exit itself. When TestMain is called,
-// flag.Parse has not been run. If TestMain depends on command-line flags,
-// including those of the testing package, it should call flag.Parse explicitly.
+// will pass the result of m.Run to os.Exit itself.
+//
+// When TestMain is called, flag.Parse has not been run. If TestMain depends on
+// command-line flags, including those of the testing package, it should call
+// flag.Parse explicitly. Command line flags are always parsed by the time test
+// or benchmark functions run.
//
// A simple implementation of TestMain is:
//
diff --git a/test/codegen/arithmetic.go b/test/codegen/arithmetic.go
index a076664..8f25974 100644
--- a/test/codegen/arithmetic.go
+++ b/test/codegen/arithmetic.go
@@ -451,3 +451,14 @@
c += 128
return a, b, c
}
+
+
+// Divide -> shift rules usually require fixup for negative inputs.
+// If the input is non-negative, make sure the fixup is eliminated.
+func divInt(v int64) int64 {
+ if v < 0 {
+ return 0
+ }
+ // amd64:-`.*SARQ.*63,`, -".*SHRQ", ".*SARQ.*[$]9,"
+ return v / 512
+}
diff --git a/test/fixedbugs/issue25727.go b/test/fixedbugs/issue25727.go
index 9b7c804..da7c94c 100644
--- a/test/fixedbugs/issue25727.go
+++ b/test/fixedbugs/issue25727.go
@@ -9,13 +9,13 @@
import "net/http"
var s = http.Server{}
-var _ = s.doneChan // ERROR "s.doneChan undefined .cannot refer to unexported field or method doneChan.$"
-var _ = s.DoneChan // ERROR "s.DoneChan undefined .type http.Server has no field or method DoneChan.$"
+var _ = s.doneChan // ERROR "s.doneChan undefined .cannot refer to unexported field or method doneChan.$"
+var _ = s.DoneChan // ERROR "s.DoneChan undefined .type http.Server has no field or method DoneChan.$"
var _ = http.Server{tlsConfig: nil} // ERROR "unknown field 'tlsConfig' in struct literal.+ .but does have TLSConfig.$"
-var _ = http.Server{DoneChan: nil} // ERROR "unknown field 'DoneChan' in struct literal of type http.Server$"
+var _ = http.Server{DoneChan: nil} // ERROR "unknown field 'DoneChan' in struct literal of type http.Server$"
type foo struct {
- bar int
+ bar int
}
var _ = &foo{bAr: 10} // ERROR "unknown field 'bAr' in struct literal.+ .but does have bar.$"
diff --git a/test/fixedbugs/issue31053.dir/f1.go b/test/fixedbugs/issue31053.dir/f1.go
new file mode 100644
index 0000000..610f393
--- /dev/null
+++ b/test/fixedbugs/issue31053.dir/f1.go
@@ -0,0 +1,18 @@
+// Copyright 2019 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 f1
+
+type Foo struct {
+ doneChan chan bool
+ Name string
+ fOO int
+ hook func()
+}
+
+func (f *Foo) Exported() {
+}
+
+func (f *Foo) unexported() {
+}
diff --git a/test/fixedbugs/issue31053.dir/main.go b/test/fixedbugs/issue31053.dir/main.go
new file mode 100644
index 0000000..895c262
--- /dev/null
+++ b/test/fixedbugs/issue31053.dir/main.go
@@ -0,0 +1,42 @@
+// errorcheck
+
+// Copyright 2019 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 p
+
+import "./f1"
+
+func main() {
+ f := f1.Foo{
+ doneChan: nil, // ERROR "cannot refer to unexported field 'doneChan' in struct literal of type f1.Foo"
+ DoneChan: nil, // ERROR "unknown field 'DoneChan' in struct literal of type f1.Foo"
+ Name: "hey",
+ name: "there", // ERROR "unknown field 'name' in struct literal of type f1.Foo .but does have Name."
+ noSuchPrivate: true, // ERROR "unknown field 'noSuchPrivate' in struct literal of type f1.Foo"
+ NoSuchPublic: true, // ERROR "unknown field 'NoSuchPublic' in struct literal of type f1.Foo"
+ foo: true, // ERROR "unknown field 'foo' in struct literal of type f1.Foo"
+ hook: func() {}, // ERROR "cannot refer to unexported field 'hook' in struct literal of type f1.Foo"
+ unexported: func() {}, // ERROR "unknown field 'unexported' in struct literal of type f1.Foo"
+ Exported: func() {}, // ERROR "unknown field 'Exported' in struct literal of type f1.Foo"
+ }
+ f.doneChan = nil // ERROR "f.doneChan undefined .cannot refer to unexported field or method doneChan."
+ f.DoneChan = nil // ERROR "f.DoneChan undefined .type f1.Foo has no field or method DoneChan."
+ f.name = nil // ERROR "f.name undefined .type f1.Foo has no field or method name, but does have Name."
+
+ _ = f.doneChan // ERROR "f.doneChan undefined .cannot refer to unexported field or method doneChan."
+ _ = f.DoneChan // ERROR "f.DoneChan undefined .type f1.Foo has no field or method DoneChan."
+ _ = f.Name
+ _ = f.name // ERROR "f.name undefined .type f1.Foo has no field or method name, but does have Name."
+ _ = f.noSuchPrivate // ERROR "f.noSuchPrivate undefined .type f1.Foo has no field or method noSuchPrivate."
+ _ = f.NoSuchPublic // ERROR "f.NoSuchPublic undefined .type f1.Foo has no field or method NoSuchPublic."
+ _ = f.foo // ERROR "f.foo undefined .type f1.Foo has no field or method foo."
+ _ = f.Exported
+ _ = f.exported // ERROR "f.exported undefined .type f1.Foo has no field or method exported, but does have Exported."
+ _ = f.Unexported // ERROR "f.Unexported undefined .type f1.Foo has no field or method Unexported."
+ _ = f.unexported // ERROR "f.unexported undefined .cannot refer to unexported field or method f1..\*Foo..unexported."
+ f.unexported = 10 // ERROR "f.unexported undefined .cannot refer to unexported field or method f1..\*Foo..unexported."
+ f.unexported() // ERROR "f.unexported undefined .cannot refer to unexported field or method f1..\*Foo..unexported."
+ _ = f.hook // ERROR "f.hook undefined .cannot refer to unexported field or method hook."
+}
diff --git a/test/fixedbugs/issue31053.go b/test/fixedbugs/issue31053.go
new file mode 100644
index 0000000..a33d3ff
--- /dev/null
+++ b/test/fixedbugs/issue31053.go
@@ -0,0 +1,7 @@
+// errorcheckdir
+
+// Copyright 2019 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 ignored
diff --git a/test/fixedbugs/issue36437.go b/test/fixedbugs/issue36437.go
new file mode 100644
index 0000000..f96544b
--- /dev/null
+++ b/test/fixedbugs/issue36437.go
@@ -0,0 +1,49 @@
+// run
+
+// +build !nacl,!js
+
+// Copyright 2020 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.
+
+// Tests that when non-existent files are passed to the
+// compiler, such as in:
+// go tool compile foo
+// we don't print the beginning position:
+// foo:0: open foo: no such file or directory
+// but instead omit it and print out:
+// open foo: no such file or directory
+
+package main
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "regexp"
+)
+
+func main() {
+ tmpDir, err := ioutil.TempDir("", "issue36437")
+ if err != nil {
+ panic(err)
+ }
+ defer os.RemoveAll(tmpDir)
+
+ msgOrErr := func(msg []byte, err error) string {
+ if len(msg) == 0 && err != nil {
+ return err.Error()
+ }
+ return string(msg)
+ }
+
+ filename := "non-existent.go"
+ output, err := exec.Command("go", "tool", "compile", filename).CombinedOutput()
+ got := msgOrErr(output, err)
+
+ regFilenamePos := regexp.MustCompile(filename + ":\\d+")
+ if regFilenamePos.MatchString(got) {
+ fmt.Printf("Error message must not contain filename:pos, but got:\n%q\n", got)
+ }
+}
diff --git a/test/fixedbugs/issue37246.go b/test/fixedbugs/issue37246.go
new file mode 100644
index 0000000..fe476da
--- /dev/null
+++ b/test/fixedbugs/issue37246.go
@@ -0,0 +1,23 @@
+// compile
+
+// Copyright 2020 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
+
+func main() {
+ var n, a, b int64
+ for i := int64(2); i < 10; i++ {
+ for j := i; j < 10; j++ {
+ if ((n % (i * j)) == 0) && (j > 1 && (n/(i*j)) == 1) {
+ a, b = i, 0
+ a = n / (i * j)
+ }
+ }
+ }
+
+ if a != b && a != n {
+ println("yes")
+ }
+}
diff --git a/test/fixedbugs/issue38916.go b/test/fixedbugs/issue38916.go
new file mode 100644
index 0000000..fb2ee34
--- /dev/null
+++ b/test/fixedbugs/issue38916.go
@@ -0,0 +1,14 @@
+// compile
+
+// Copyright 2020 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 p
+
+func f(b bool, c complex128) func(complex128) complex128 {
+ return func(p complex128) complex128 {
+ b = (p+1i == 0) && b
+ return (p + 2i) * (p + 3i - c)
+ }
+}
diff --git a/test/prove.go b/test/prove.go
index e5636a4..d37021d 100644
--- a/test/prove.go
+++ b/test/prove.go
@@ -956,6 +956,70 @@
useSlice(c)
}
+// Check that prove is zeroing these right shifts of positive ints by bit-width - 1.
+// e.g (Rsh64x64 <t> n (Const64 <typ.UInt64> [63])) && ft.isNonNegative(n) -> 0
+func sh64(n int64) int64 {
+ if n < 0 {
+ return n
+ }
+ return n >> 63 // ERROR "Proved Rsh64x64 shifts to zero"
+}
+
+func sh32(n int32) int32 {
+ if n < 0 {
+ return n
+ }
+ return n >> 31 // ERROR "Proved Rsh32x64 shifts to zero"
+}
+
+func sh32x64(n int32) int32 {
+ if n < 0 {
+ return n
+ }
+ return n >> uint64(31) // ERROR "Proved Rsh32x64 shifts to zero"
+}
+
+func sh16(n int16) int16 {
+ if n < 0 {
+ return n
+ }
+ return n >> 15 // ERROR "Proved Rsh16x64 shifts to zero"
+}
+
+func sh64noopt(n int64) int64 {
+ return n >> 63 // not optimized; n could be negative
+}
+
+// These cases are division of a positive signed integer by a power of 2.
+// The opt pass doesnt have sufficient information to see that n is positive.
+// So, instead, opt rewrites the division with a less-than-optimal replacement.
+// Prove, which can see that n is nonnegative, cannot see the division because
+// opt, an earlier pass, has already replaced it.
+// The fix for this issue allows prove to zero a right shift that was added as
+// part of the less-than-optimal reqwrite. That change by prove then allows
+// lateopt to clean up all the unneccesary parts of the original division
+// replacement. See issue #36159.
+func divShiftClean(n int) int {
+ if n < 0 {
+ return n
+ }
+ return n / int(8) // ERROR "Proved Rsh64x64 shifts to zero"
+}
+
+func divShiftClean64(n int64) int64 {
+ if n < 0 {
+ return n
+ }
+ return n / int64(16) // ERROR "Proved Rsh64x64 shifts to zero"
+}
+
+func divShiftClean32(n int32) int32 {
+ if n < 0 {
+ return n
+ }
+ return n / int32(16) // ERROR "Proved Rsh32x64 shifts to zero"
+}
+
//go:noinline
func useInt(a int) {
}