From a3dfcf51c6543ac1af853f1799d70eae83073f1a Mon Sep 17 00:00:00 2001
From: Josh Bleecher Snyder os:
-func (file *File) Read(buf []byte) (n int, err error) +func (f *File) Read(buf []byte) (n int, err error)
The method returns the number of bytes read and an error value, if
From 91d989eb6df17b0696cfd53e84b10ccb3f09c1dd Mon Sep 17 00:00:00 2001
From: Didier Spezia
-Expression = UnaryExpr | Expression binary_op UnaryExpr . +Expression = UnaryExpr | Expression binary_op Expression . UnaryExpr = PrimaryExpr | unary_op UnaryExpr . binary_op = "||" | "&&" | rel_op | add_op | mul_op . From d4472799277102e461968fa059f49bc8b9b6e433 Mon Sep 17 00:00:00 2001 From: Russ CoxDate: Wed, 6 May 2015 12:35:53 -0400 Subject: [PATCH 066/232] cmd/internal/gc: optimize slice + write barrier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code generated for a slice x[i:j] or x[i:j:k] computes the entire new slice (base, len, cap) and then uses it as the evaluation of the slice expression. If the slice is part of an update x = x[i:j] or x = x[i:j:k], there are opportunities to avoid computing some of these fields. For x = x[0:i], we know that only the len is changing; base can be ignored completely, and cap can be left unmodified. For x = x[0:i:j], we know that only len and cap are changing; base can be ignored completely. For x = x[i:i], we know that the resulting cap is zero, and we don't adjust the base during a slice producing a zero-cap result, so again base can be ignored completely. No write to base, no write barrier. The old slice code was trying to work at a Go syntax level, mainly because that was how you wrote code just once instead of once per architecture. Now the compiler is factored a bit better and we can implement slice during code generation but still have one copy of the code. So the new code is working at that lower level. (It must, to update only parts of the result.) This CL by itself: name old mean new mean delta BinaryTree17 5.81s × (0.98,1.03) 5.71s × (0.96,1.05) ~ (p=0.101) Fannkuch11 4.35s × (1.00,1.00) 4.39s × (1.00,1.00) +0.79% (p=0.000) FmtFprintfEmpty 86.0ns × (0.94,1.11) 82.6ns × (0.98,1.04) -3.86% (p=0.048) FmtFprintfString 276ns × (0.98,1.04) 273ns × (0.98,1.02) ~ (p=0.235) FmtFprintfInt 274ns × (0.98,1.06) 270ns × (0.99,1.01) ~ (p=0.119) FmtFprintfIntInt 506ns × (0.99,1.01) 475ns × (0.99,1.01) -6.02% (p=0.000) FmtFprintfPrefixedInt 391ns × (0.99,1.01) 393ns × (1.00,1.01) ~ (p=0.139) FmtFprintfFloat 566ns × (0.99,1.01) 574ns × (1.00,1.01) +1.33% (p=0.001) FmtManyArgs 1.91µs × (0.99,1.01) 1.87µs × (0.99,1.02) -1.83% (p=0.000) GobDecode 15.3ms × (0.99,1.02) 15.0ms × (0.98,1.05) -1.84% (p=0.042) GobEncode 11.5ms × (0.97,1.03) 11.4ms × (0.99,1.03) ~ (p=0.152) Gzip 645ms × (0.99,1.01) 647ms × (0.99,1.01) ~ (p=0.265) Gunzip 142ms × (1.00,1.00) 143ms × (1.00,1.01) +0.90% (p=0.000) HTTPClientServer 90.5µs × (0.97,1.04) 88.5µs × (0.99,1.03) -2.27% (p=0.014) JSONEncode 32.0ms × (0.98,1.03) 29.6ms × (0.98,1.01) -7.51% (p=0.000) JSONDecode 114ms × (0.99,1.01) 104ms × (1.00,1.01) -8.60% (p=0.000) Mandelbrot200 6.04ms × (1.00,1.01) 6.02ms × (1.00,1.00) ~ (p=0.057) GoParse 6.47ms × (0.97,1.05) 6.37ms × (0.97,1.04) ~ (p=0.105) RegexpMatchEasy0_32 171ns × (0.93,1.07) 152ns × (0.99,1.01) -11.09% (p=0.000) RegexpMatchEasy0_1K 550ns × (0.98,1.01) 530ns × (1.00,1.00) -3.78% (p=0.000) RegexpMatchEasy1_32 135ns × (0.99,1.02) 134ns × (0.99,1.01) -1.33% (p=0.002) RegexpMatchEasy1_1K 879ns × (1.00,1.01) 865ns × (1.00,1.00) -1.58% (p=0.000) RegexpMatchMedium_32 243ns × (1.00,1.00) 233ns × (1.00,1.00) -4.30% (p=0.000) RegexpMatchMedium_1K 70.3µs × (1.00,1.00) 69.5µs × (1.00,1.00) -1.13% (p=0.000) RegexpMatchHard_32 3.82µs × (1.00,1.01) 3.74µs × (1.00,1.00) -1.95% (p=0.000) RegexpMatchHard_1K 117µs × (1.00,1.00) 115µs × (1.00,1.00) -1.69% (p=0.000) Revcomp 917ms × (0.97,1.04) 920ms × (0.97,1.04) ~ (p=0.786) Template 114ms × (0.99,1.01) 117ms × (0.99,1.01) +2.58% (p=0.000) TimeParse 622ns × (0.99,1.01) 615ns × (0.99,1.00) -1.06% (p=0.000) TimeFormat 665ns × (0.99,1.01) 654ns × (0.99,1.00) -1.70% (p=0.000) This CL and previous CL (append) combined: name old mean new mean delta BinaryTree17 5.68s × (0.97,1.04) 5.71s × (0.96,1.05) ~ (p=0.638) Fannkuch11 4.41s × (0.98,1.03) 4.39s × (1.00,1.00) ~ (p=0.474) FmtFprintfEmpty 92.7ns × (0.91,1.16) 82.6ns × (0.98,1.04) -10.89% (p=0.004) FmtFprintfString 281ns × (0.96,1.08) 273ns × (0.98,1.02) ~ (p=0.078) FmtFprintfInt 288ns × (0.97,1.06) 270ns × (0.99,1.01) -6.37% (p=0.000) FmtFprintfIntInt 493ns × (0.97,1.04) 475ns × (0.99,1.01) -3.53% (p=0.002) FmtFprintfPrefixedInt 423ns × (0.97,1.04) 393ns × (1.00,1.01) -7.07% (p=0.000) FmtFprintfFloat 598ns × (0.99,1.01) 574ns × (1.00,1.01) -4.02% (p=0.000) FmtManyArgs 1.89µs × (0.98,1.05) 1.87µs × (0.99,1.02) ~ (p=0.305) GobDecode 14.8ms × (0.98,1.03) 15.0ms × (0.98,1.05) ~ (p=0.237) GobEncode 12.3ms × (0.98,1.01) 11.4ms × (0.99,1.03) -6.95% (p=0.000) Gzip 656ms × (0.99,1.05) 647ms × (0.99,1.01) ~ (p=0.101) Gunzip 142ms × (1.00,1.00) 143ms × (1.00,1.01) +0.58% (p=0.001) HTTPClientServer 91.2µs × (0.97,1.04) 88.5µs × (0.99,1.03) -3.02% (p=0.003) JSONEncode 32.6ms × (0.97,1.08) 29.6ms × (0.98,1.01) -9.10% (p=0.000) JSONDecode 114ms × (0.97,1.05) 104ms × (1.00,1.01) -8.74% (p=0.000) Mandelbrot200 6.11ms × (0.98,1.04) 6.02ms × (1.00,1.00) ~ (p=0.090) GoParse 6.66ms × (0.97,1.04) 6.37ms × (0.97,1.04) -4.41% (p=0.000) RegexpMatchEasy0_32 159ns × (0.99,1.00) 152ns × (0.99,1.01) -4.69% (p=0.000) RegexpMatchEasy0_1K 538ns × (1.00,1.01) 530ns × (1.00,1.00) -1.57% (p=0.000) RegexpMatchEasy1_32 138ns × (1.00,1.00) 134ns × (0.99,1.01) -2.91% (p=0.000) RegexpMatchEasy1_1K 869ns × (0.99,1.01) 865ns × (1.00,1.00) -0.51% (p=0.012) RegexpMatchMedium_32 252ns × (0.99,1.01) 233ns × (1.00,1.00) -7.85% (p=0.000) RegexpMatchMedium_1K 72.7µs × (1.00,1.00) 69.5µs × (1.00,1.00) -4.43% (p=0.000) RegexpMatchHard_32 3.85µs × (1.00,1.00) 3.74µs × (1.00,1.00) -2.74% (p=0.000) RegexpMatchHard_1K 118µs × (1.00,1.00) 115µs × (1.00,1.00) -2.24% (p=0.000) Revcomp 920ms × (0.97,1.07) 920ms × (0.97,1.04) ~ (p=0.998) Template 129ms × (0.98,1.03) 117ms × (0.99,1.01) -9.79% (p=0.000) TimeParse 619ns × (0.99,1.01) 615ns × (0.99,1.00) -0.57% (p=0.011) TimeFormat 661ns × (0.98,1.04) 654ns × (0.99,1.00) ~ (p=0.223) Change-Id: If054d81ab2c71d8d62cf54b5b1fac2af66b387fc Reviewed-on: https://go-review.googlesource.com/9813 Reviewed-by: David Chase Run-TryBot: Russ Cox TryBot-Result: Gobot Gobot --- src/cmd/8g/cgen.go | 2 +- src/cmd/internal/gc/cgen.go | 574 +++++++++++++++++++++++++++++++- src/cmd/internal/gc/gen.go | 116 ------- src/cmd/internal/gc/lex.go | 2 + src/cmd/internal/gc/order.go | 38 ++- src/cmd/internal/gc/racewalk.go | 3 +- src/cmd/internal/gc/subr.go | 2 +- src/cmd/internal/gc/walk.go | 290 +++------------- test/sliceopt.go | 41 ++- 9 files changed, 688 insertions(+), 380 deletions(-) diff --git a/src/cmd/8g/cgen.go b/src/cmd/8g/cgen.go index dfbdafefe3..48d9e9867a 100644 --- a/src/cmd/8g/cgen.go +++ b/src/cmd/8g/cgen.go @@ -17,7 +17,7 @@ import ( */ func igenindex(n *gc.Node, res *gc.Node, bounded bool) *obj.Prog { if !gc.Is64(n.Type) { - if n.Addable { + if n.Addable && (gc.Simtype[n.Etype] == gc.TUINT32 || gc.Simtype[n.Etype] == gc.TINT32) { // nothing to do. *res = *n } else { diff --git a/src/cmd/internal/gc/cgen.go b/src/cmd/internal/gc/cgen.go index 3763a367b0..a4b4f0b61b 100644 --- a/src/cmd/internal/gc/cgen.go +++ b/src/cmd/internal/gc/cgen.go @@ -43,14 +43,7 @@ func cgen_wb(n, res *Node, wb bool) { switch n.Op { case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR: - if res.Op != ONAME || !res.Addable || wb { - var n1 Node - Tempname(&n1, n.Type) - Cgen_slice(n, &n1) - cgen_wb(&n1, res, wb) - } else { - Cgen_slice(n, res) - } + cgen_slice(n, res, wb) return case OEFACE: @@ -2970,3 +2963,568 @@ func cgen_append(n, res *Node) { i++ } } + +// Generate res = n, where n is x[i:j] or x[i:j:k]. +// If wb is true, need write barrier updating res's base pointer. +// On systems with 32-bit ints, i, j, k are guaranteed to be 32-bit values. +func cgen_slice(n, res *Node, wb bool) { + needFullUpdate := !samesafeexpr(n.Left, res) + + // orderexpr has made sure that x is safe (but possibly expensive) + // and i, j, k are cheap. On a system with registers (anything but 386) + // we can evaluate x first and then know we have enough registers + // for i, j, k as well. + var x, xbase, xlen, xcap, i, j, k Node + if n.Op != OSLICEARR && n.Op != OSLICE3ARR { + Igen(n.Left, &x, nil) + } + + indexRegType := Types[TUINT] + if Widthreg > Widthptr { // amd64p32 + indexRegType = Types[TUINT64] + } + + // On most systems, we use registers. + // The 386 has basically no registers, so substitute functions + // that can work with temporaries instead. + regalloc := Regalloc + ginscon := Thearch.Ginscon + gins := Thearch.Gins + if Thearch.Thechar == '8' { + regalloc = func(n *Node, t *Type, reuse *Node) { + Tempname(n, t) + } + ginscon = func(as int, c int64, n *Node) { + var n1 Node + Regalloc(&n1, n.Type, n) + Thearch.Gmove(n, &n1) + Thearch.Ginscon(as, c, &n1) + Thearch.Gmove(&n1, n) + Regfree(&n1) + } + gins = func(as int, f, t *Node) *obj.Prog { + var n1 Node + Regalloc(&n1, t.Type, t) + Thearch.Gmove(t, &n1) + Thearch.Gins(as, f, &n1) + Thearch.Gmove(&n1, t) + Regfree(&n1) + return nil + } + } + + panics := make([]*obj.Prog, 0, 6) // 3 loads + 3 checks + + loadlen := func() { + if xlen.Op != 0 { + return + } + if n.Op == OSLICEARR || n.Op == OSLICE3ARR { + Nodconst(&xlen, indexRegType, n.Left.Type.Type.Bound) + return + } + if n.Op == OSLICESTR && Isconst(n.Left, CTSTR) { + Nodconst(&xlen, indexRegType, int64(len(n.Left.Val.U.Sval))) + return + } + regalloc(&xlen, indexRegType, nil) + x.Xoffset += int64(Widthptr) + x.Type = Types[TUINT] + Thearch.Gmove(&x, &xlen) + x.Xoffset -= int64(Widthptr) + } + + loadcap := func() { + if xcap.Op != 0 { + return + } + if n.Op == OSLICEARR || n.Op == OSLICE3ARR || n.Op == OSLICESTR { + loadlen() + xcap = xlen + if xcap.Op == OREGISTER { + Regrealloc(&xcap) + } + return + } + regalloc(&xcap, indexRegType, nil) + x.Xoffset += 2 * int64(Widthptr) + x.Type = Types[TUINT] + Thearch.Gmove(&x, &xcap) + x.Xoffset -= 2 * int64(Widthptr) + } + + var x1, x2, x3 *Node // unevaluated index arguments + x1 = n.Right.Left + switch n.Op { + default: + x2 = n.Right.Right + case OSLICE3, OSLICE3ARR: + x2 = n.Right.Right.Left + x3 = n.Right.Right.Right + } + + // load computes src into targ, but if src refers to the len or cap of n.Left, + // load copies those from xlen, xcap, loading xlen if needed. + // If targ.Op == OREGISTER on return, it must be Regfreed, + // but it should not be modified without first checking whether it is + // xlen or xcap's register. + load := func(src, targ *Node) { + if src == nil { + return + } + switch src.Op { + case OLITERAL: + *targ = *src + return + case OLEN: + // NOTE(rsc): This doesn't actually trigger, because order.go + // has pulled all the len and cap calls into separate assignments + // to temporaries. There are tests in test/sliceopt.go that could + // be enabled if this is fixed. + if samesafeexpr(n.Left, src.Left) { + if Debug_slice > 0 { + Warn("slice: reuse len") + } + loadlen() + *targ = xlen + if targ.Op == OREGISTER { + Regrealloc(targ) + } + return + } + case OCAP: + // NOTE(rsc): This doesn't actually trigger; see note in case OLEN above. + if samesafeexpr(n.Left, src.Left) { + if Debug_slice > 0 { + Warn("slice: reuse cap") + } + loadcap() + *targ = xcap + if targ.Op == OREGISTER { + Regrealloc(targ) + } + return + } + } + if i.Op != 0 && samesafeexpr(x1, src) { + if Debug_slice > 0 { + Warn("slice: reuse 1st index") + } + *targ = i + if targ.Op == OREGISTER { + Regrealloc(targ) + } + return + } + if j.Op != 0 && samesafeexpr(x2, src) { + if Debug_slice > 0 { + Warn("slice: reuse 2nd index") + } + *targ = j + if targ.Op == OREGISTER { + Regrealloc(targ) + } + return + } + if Thearch.Cgenindex != nil { + regalloc(targ, indexRegType, nil) + p := Thearch.Cgenindex(src, targ, false) + if p != nil { + panics = append(panics, p) + } + } else if Thearch.Igenindex != nil { + p := Thearch.Igenindex(src, targ, false) + if p != nil { + panics = append(panics, p) + } + } else { + regalloc(targ, indexRegType, nil) + var tmp Node + Cgenr(src, &tmp, targ) + Thearch.Gmove(&tmp, targ) + Regfree(&tmp) + } + } + + load(x1, &i) + load(x2, &j) + load(x3, &k) + + // i defaults to 0. + if i.Op == 0 { + Nodconst(&i, indexRegType, 0) + } + + // j defaults to len(x) + if j.Op == 0 { + loadlen() + j = xlen + if j.Op == OREGISTER { + Regrealloc(&j) + } + } + + // k defaults to cap(x) + // Only need to load it if we're recalculating cap or doing a full update. + if k.Op == 0 && n.Op != OSLICESTR && (!iszero(&i) || needFullUpdate) { + loadcap() + k = xcap + if k.Op == OREGISTER { + Regrealloc(&k) + } + } + + // Check constant indexes for negative values, and against constant length if known. + // The func obvious below checks for out-of-order constant indexes. + var bound int64 = -1 + if n.Op == OSLICEARR || n.Op == OSLICE3ARR { + bound = n.Left.Type.Type.Bound + } else if n.Op == OSLICESTR && Isconst(n.Left, CTSTR) { + bound = int64(len(n.Left.Val.U.Sval)) + } + if Isconst(&i, CTINT) { + if mpcmpfixc(i.Val.U.Xval, 0) < 0 || bound >= 0 && mpcmpfixc(i.Val.U.Xval, bound) > 0 { + Yyerror("slice index out of bounds") + } + } + if Isconst(&j, CTINT) { + if mpcmpfixc(j.Val.U.Xval, 0) < 0 || bound >= 0 && mpcmpfixc(j.Val.U.Xval, bound) > 0 { + Yyerror("slice index out of bounds") + } + } + if Isconst(&k, CTINT) { + if mpcmpfixc(k.Val.U.Xval, 0) < 0 || bound >= 0 && mpcmpfixc(k.Val.U.Xval, bound) > 0 { + Yyerror("slice index out of bounds") + } + } + + // same reports whether n1 and n2 are the same register or constant. + same := func(n1, n2 *Node) bool { + return n1.Op == OREGISTER && n2.Op == OREGISTER && n1.Reg == n2.Reg || + n1.Op == ONAME && n2.Op == ONAME && n1.Orig == n2.Orig && n1.Type == n2.Type && n1.Xoffset == n2.Xoffset || + n1.Op == OLITERAL && n2.Op == OLITERAL && Mpcmpfixfix(n1.Val.U.Xval, n2.Val.U.Xval) == 0 + } + + // obvious reports whether n1 <= n2 is obviously true, + // and it calls Yyerror if n1 <= n2 is obviously false. + obvious := func(n1, n2 *Node) bool { + if Debug['B'] != 0 { // -B disables bounds checks + return true + } + if same(n1, n2) { + return true // n1 == n2 + } + if iszero(n1) { + return true // using unsigned compare, so 0 <= n2 always true + } + if xlen.Op != 0 && same(n1, &xlen) && xcap.Op != 0 && same(n2, &xcap) { + return true // len(x) <= cap(x) always true + } + if Isconst(n1, CTINT) && Isconst(n2, CTINT) { + if Mpcmpfixfix(n1.Val.U.Xval, n2.Val.U.Xval) <= 0 { + return true // n1, n2 constants such that n1 <= n2 + } + Yyerror("slice index out of bounds") + return true + } + return false + } + + compare := func(n1, n2 *Node) { + p := Thearch.Ginscmp(OGT, indexRegType, n1, n2, -1) + panics = append(panics, p) + } + + loadcap() + max := &xcap + if k.Op != 0 && (n.Op == OSLICE3 || n.Op == OSLICE3ARR) { + if obvious(&k, max) { + if Debug_slice > 0 { + Warn("slice: omit check for 3rd index") + } + } else { + compare(&k, max) + } + max = &k + } + if j.Op != 0 { + if obvious(&j, max) { + if Debug_slice > 0 { + Warn("slice: omit check for 2nd index") + } + } else { + compare(&j, max) + } + max = &j + } + if i.Op != 0 { + if obvious(&i, max) { + if Debug_slice > 0 { + Warn("slice: omit check for 1st index") + } + } else { + compare(&i, max) + } + max = &i + } + if k.Op != 0 && i.Op != 0 { + obvious(&i, &k) // emit compile-time error for x[3:n:2] + } + + if len(panics) > 0 { + p := Gbranch(obj.AJMP, nil, 0) + for _, q := range panics { + Patch(q, Pc) + } + Ginscall(panicslice, -1) + Patch(p, Pc) + } + + // Checks are done. + // Compute new len as j-i, cap as k-i. + // If i and j are same register, len is constant 0. + // If i and k are same register, cap is constant 0. + // If j and k are same register, len and cap are same. + + // Done with xlen and xcap. + // Now safe to modify j and k even if they alias xlen, xcap. + if xlen.Op == OREGISTER { + Regfree(&xlen) + } + if xcap.Op == OREGISTER { + Regfree(&xcap) + } + + // are j and k the same value? + sameJK := same(&j, &k) + + if i.Op != 0 { + // j -= i + if same(&i, &j) { + if Debug_slice > 0 { + Warn("slice: result len == 0") + } + if j.Op == OREGISTER { + Regfree(&j) + } + Nodconst(&j, indexRegType, 0) + } else { + switch j.Op { + case OLITERAL: + if Isconst(&i, CTINT) { + Nodconst(&j, indexRegType, Mpgetfix(j.Val.U.Xval)-Mpgetfix(i.Val.U.Xval)) + if Debug_slice > 0 { + Warn("slice: result len == %d", Mpgetfix(j.Val.U.Xval)) + } + break + } + fallthrough + case ONAME: + if !istemp(&j) { + var r Node + regalloc(&r, indexRegType, nil) + Thearch.Gmove(&j, &r) + j = r + } + fallthrough + case OREGISTER: + if i.Op == OLITERAL { + v := Mpgetfix(i.Val.U.Xval) + if v != 0 { + ginscon(Thearch.Optoas(OSUB, indexRegType), v, &j) + } + } else { + gins(Thearch.Optoas(OSUB, indexRegType), &i, &j) + } + } + } + + // k -= i if k different from j and cap is needed.j + // (The modifications to j above cannot affect i: if j and i were aliased, + // we replace j with a constant 0 instead of doing a subtraction, + // leaving i unmodified.) + if k.Op == 0 { + if Debug_slice > 0 && n.Op != OSLICESTR { + Warn("slice: result cap not computed") + } + // no need + } else if same(&i, &k) { + if k.Op == OREGISTER { + Regfree(&k) + } + Nodconst(&k, indexRegType, 0) + if Debug_slice > 0 { + Warn("slice: result cap == 0") + } + } else if sameJK { + if Debug_slice > 0 { + Warn("slice: result cap == result len") + } + // k and j were the same value; make k-i the same as j-i. + if k.Op == OREGISTER { + Regfree(&k) + } + k = j + if k.Op == OREGISTER { + Regrealloc(&k) + } + } else { + switch k.Op { + case OLITERAL: + if Isconst(&i, CTINT) { + Nodconst(&k, indexRegType, Mpgetfix(k.Val.U.Xval)-Mpgetfix(i.Val.U.Xval)) + if Debug_slice > 0 { + Warn("slice: result cap == %d", Mpgetfix(k.Val.U.Xval)) + } + break + } + fallthrough + case ONAME: + if !istemp(&k) { + var r Node + regalloc(&r, indexRegType, nil) + Thearch.Gmove(&k, &r) + k = r + } + fallthrough + case OREGISTER: + if same(&i, &k) { + Regfree(&k) + Nodconst(&k, indexRegType, 0) + if Debug_slice > 0 { + Warn("slice: result cap == 0") + } + } else if i.Op == OLITERAL { + v := Mpgetfix(i.Val.U.Xval) + if v != 0 { + ginscon(Thearch.Optoas(OSUB, indexRegType), v, &k) + } + } else { + gins(Thearch.Optoas(OSUB, indexRegType), &i, &k) + } + } + } + } + + adjustBase := true + if i.Op == 0 || iszero(&i) { + if Debug_slice > 0 { + Warn("slice: skip base adjustment for 1st index 0") + } + adjustBase = false + } else if k.Op != 0 && iszero(&k) || k.Op == 0 && iszero(&j) { + if Debug_slice > 0 { + if n.Op == OSLICESTR { + Warn("slice: skip base adjustment for string len == 0") + } else { + Warn("slice: skip base adjustment for cap == 0") + } + } + adjustBase = false + } + + if !adjustBase && !needFullUpdate { + if Debug_slice > 0 { + if k.Op != 0 { + Warn("slice: len/cap-only update") + } else { + Warn("slice: len-only update") + } + } + if i.Op == OREGISTER { + Regfree(&i) + } + // Write len (and cap if needed) back to x. + x.Xoffset += int64(Widthptr) + x.Type = Types[TUINT] + Thearch.Gmove(&j, &x) + x.Xoffset -= int64(Widthptr) + if k.Op != 0 { + x.Xoffset += 2 * int64(Widthptr) + x.Type = Types[TUINT] + Thearch.Gmove(&k, &x) + x.Xoffset -= 2 * int64(Widthptr) + } + Regfree(&x) + } else { + // Compute new base. May smash i. + if n.Op == OSLICEARR || n.Op == OSLICE3ARR { + Cgenr(n.Left, &xbase, nil) + Cgen_checknil(&xbase) + } else { + regalloc(&xbase, Ptrto(res.Type.Type), nil) + x.Type = xbase.Type + Thearch.Gmove(&x, &xbase) + Regfree(&x) + } + if i.Op != 0 && adjustBase { + // Branch around the base adjustment if the resulting cap will be 0. + var p *obj.Prog + size := &k + if k.Op == 0 { + size = &j + } + if Isconst(size, CTINT) { + // zero was checked above, must be non-zero. + } else { + var tmp Node + Nodconst(&tmp, indexRegType, 0) + p = Thearch.Ginscmp(OEQ, indexRegType, size, &tmp, -1) + } + var w int64 + if n.Op == OSLICESTR { + w = 1 // res is string, elem size is 1 (byte) + } else { + w = res.Type.Type.Width // res is []T, elem size is T.width + } + if Isconst(&i, CTINT) { + ginscon(Thearch.Optoas(OADD, xbase.Type), Mpgetfix(i.Val.U.Xval)*w, &xbase) + } else if Thearch.AddIndex != nil && Thearch.AddIndex(&i, w, &xbase) { + // done by back end + } else if w == 1 { + gins(Thearch.Optoas(OADD, xbase.Type), &i, &xbase) + } else { + if i.Op == ONAME && !istemp(&i) { + var tmp Node + Tempname(&tmp, i.Type) + Thearch.Gmove(&i, &tmp) + i = tmp + } + ginscon(Thearch.Optoas(OMUL, i.Type), w, &i) + gins(Thearch.Optoas(OADD, xbase.Type), &i, &xbase) + } + if p != nil { + Patch(p, Pc) + } + } + if i.Op == OREGISTER { + Regfree(&i) + } + + // Write len, cap, base to result. + if res.Op == ONAME { + Gvardef(res) + } + Igen(res, &x, nil) + x.Xoffset += int64(Widthptr) + x.Type = Types[TUINT] + Thearch.Gmove(&j, &x) + x.Xoffset -= int64(Widthptr) + if k.Op != 0 { + x.Xoffset += 2 * int64(Widthptr) + Thearch.Gmove(&k, &x) + x.Xoffset -= 2 * int64(Widthptr) + } + x.Type = xbase.Type + cgen_wb(&xbase, &x, wb) + Regfree(&xbase) + Regfree(&x) + } + + if j.Op == OREGISTER { + Regfree(&j) + } + if k.Op == OREGISTER { + Regfree(&k) + } +} diff --git a/src/cmd/internal/gc/gen.go b/src/cmd/internal/gc/gen.go index 76e9a82392..a9c348da2d 100644 --- a/src/cmd/internal/gc/gen.go +++ b/src/cmd/internal/gc/gen.go @@ -551,122 +551,6 @@ func Cgen_As2dottype(n, res, resok *Node) { Patch(q, Pc) } -/* - * generate: - * res = s[lo, hi]; - * n->left is s - * n->list is (cap(s)-lo(TUINT), hi-lo(TUINT)[, lo*width(TUINTPTR)]) - * caller (cgen) guarantees res is an addable ONAME. - * - * called for OSLICE, OSLICE3, OSLICEARR, OSLICE3ARR, OSLICESTR. - */ -func Cgen_slice(n *Node, res *Node) { - cap := n.List.N - len := n.List.Next.N - var offs *Node - if n.List.Next.Next != nil { - offs = n.List.Next.Next.N - } - - // evaluate base pointer first, because it is the only - // possibly complex expression. once that is evaluated - // and stored, updating the len and cap can be done - // without making any calls, so without doing anything that - // might cause preemption or garbage collection. - // this makes the whole slice update atomic as far as the - // garbage collector can see. - base := temp(Types[TUINTPTR]) - - tmplen := temp(Types[TINT]) - var tmpcap *Node - if n.Op != OSLICESTR { - tmpcap = temp(Types[TINT]) - } else { - tmpcap = tmplen - } - - var src Node - if isnil(n.Left) { - Tempname(&src, n.Left.Type) - Cgen(n.Left, &src) - } else { - src = *n.Left - } - if n.Op == OSLICE || n.Op == OSLICE3 || n.Op == OSLICESTR { - src.Xoffset += int64(Array_array) - } - - if n.Op == OSLICEARR || n.Op == OSLICE3ARR { - if !Isptr[n.Left.Type.Etype] { - Fatal("slicearr is supposed to work on pointer: %v\n", Nconv(n, obj.FmtSign)) - } - Cgen(&src, base) - Cgen_checknil(base) - } else { - src.Type = Types[Tptr] - Cgen(&src, base) - } - - // committed to the update - Gvardef(res) - - // compute len and cap. - // len = n-i, cap = m-i, and offs = i*width. - // computing offs last lets the multiply overwrite i. - Cgen((*Node)(len), tmplen) - - if n.Op != OSLICESTR { - Cgen(cap, tmpcap) - } - - // if new cap != 0 { base += add } - // This avoids advancing base past the end of the underlying array/string, - // so that it cannot point at the next object in memory. - // If cap == 0, the base doesn't matter except insofar as it is 0 or non-zero. - // In essence we are replacing x[i:j:k] where i == j == k - // or x[i:j] where i == j == cap(x) with x[0:0:0]. - if offs != nil { - p1 := gjmp(nil) - p2 := gjmp(nil) - Patch(p1, Pc) - - var con Node - Nodconst(&con, tmpcap.Type, 0) - cmp := Nod(OEQ, tmpcap, &con) - typecheck(&cmp, Erv) - Bgen(cmp, true, -1, p2) - - add := Nod(OADD, base, offs) - typecheck(&add, Erv) - Cgen(add, base) - - Patch(p2, Pc) - } - - // dst.array = src.array [ + lo *width ] - dst := *res - - dst.Xoffset += int64(Array_array) - dst.Type = Types[Tptr] - Cgen(base, &dst) - - // dst.len = hi [ - lo ] - dst = *res - - dst.Xoffset += int64(Array_nel) - dst.Type = Types[Simtype[TUINT]] - Cgen(tmplen, &dst) - - if n.Op != OSLICESTR { - // dst.cap = cap [ - lo ] - dst = *res - - dst.Xoffset += int64(Array_cap) - dst.Type = Types[Simtype[TUINT]] - Cgen(tmpcap, &dst) - } -} - /* * gather series of offsets * >=0 is direct addressed field diff --git a/src/cmd/internal/gc/lex.go b/src/cmd/internal/gc/lex.go index be95138b6a..96a1a01aaa 100644 --- a/src/cmd/internal/gc/lex.go +++ b/src/cmd/internal/gc/lex.go @@ -38,6 +38,7 @@ var goroot string var ( Debug_wb int Debug_append int + Debug_slice int ) // Debug arguments. @@ -53,6 +54,7 @@ var debugtab = []struct { {"disablenil", &Disable_checknil}, // disable nil checks {"wb", &Debug_wb}, // print information about write barriers {"append", &Debug_append}, // print information about append compilation + {"slice", &Debug_slice}, // print information about slice compilation } // Our own isdigit, isspace, isalpha, isalnum that take care diff --git a/src/cmd/internal/gc/order.go b/src/cmd/internal/gc/order.go index 5de2aa391c..06a1490be4 100644 --- a/src/cmd/internal/gc/order.go +++ b/src/cmd/internal/gc/order.go @@ -104,9 +104,23 @@ func ordercopyexpr(n *Node, t *Type, order *Order, clear int) *Node { // If not, ordercheapexpr allocates a new tmp, emits tmp = n, // and then returns tmp. func ordercheapexpr(n *Node, order *Order) *Node { + if n == nil { + return nil + } switch n.Op { case ONAME, OLITERAL: return n + case OLEN, OCAP: + l := ordercheapexpr(n.Left, order) + if l == n.Left { + return n + } + a := Nod(OXXX, nil, nil) + *a = *n + a.Orig = a + a.Left = l + typecheck(&a, Erv) + return a } return ordercopyexpr(n, n.Type, order, 0) @@ -124,7 +138,7 @@ func ordersafeexpr(n *Node, order *Order) *Node { case ONAME, OLITERAL: return n - case ODOT: + case ODOT, OLEN, OCAP: l := ordersafeexpr(n.Left, order) if l == n.Left { return n @@ -1080,6 +1094,28 @@ func orderexpr(np **Node, order *Order, lhs *Node) { n = ordercopyexpr(n, n.Type, order, 0) } + case OSLICE, OSLICEARR, OSLICESTR: + orderexpr(&n.Left, order, nil) + orderexpr(&n.Right.Left, order, nil) + n.Right.Left = ordercheapexpr(n.Right.Left, order) + orderexpr(&n.Right.Right, order, nil) + n.Right.Right = ordercheapexpr(n.Right.Right, order) + if lhs == nil || flag_race != 0 || lhs.Op != ONAME && !samesafeexpr(lhs, n.Left) { + n = ordercopyexpr(n, n.Type, order, 0) + } + + case OSLICE3, OSLICE3ARR: + orderexpr(&n.Left, order, nil) + orderexpr(&n.Right.Left, order, nil) + n.Right.Left = ordercheapexpr(n.Right.Left, order) + orderexpr(&n.Right.Right.Left, order, nil) + n.Right.Right.Left = ordercheapexpr(n.Right.Right.Left, order) + orderexpr(&n.Right.Right.Right, order, nil) + n.Right.Right.Right = ordercheapexpr(n.Right.Right.Right, order) + if lhs == nil || flag_race != 0 || lhs.Op != ONAME && !samesafeexpr(lhs, n.Left) { + n = ordercopyexpr(n, n.Type, order, 0) + } + case OCLOSURE: if n.Noescape && n.Func.Cvars != nil { n.Alloc = ordertemp(Types[TUINT8], order, false) // walk will fill in correct type diff --git a/src/cmd/internal/gc/racewalk.go b/src/cmd/internal/gc/racewalk.go index e7f35006dc..446ec038c8 100644 --- a/src/cmd/internal/gc/racewalk.go +++ b/src/cmd/internal/gc/racewalk.go @@ -324,9 +324,8 @@ func racewalknode(np **Node, init **NodeList, wr int, skip int) { } goto ret - // Seems to only lead to double instrumentation. - //racewalknode(&n->left, init, 0, 0); case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR: + racewalknode(&n.Left, init, 0, 0) goto ret case OADDR: diff --git a/src/cmd/internal/gc/subr.go b/src/cmd/internal/gc/subr.go index 06ceff5844..dd84214dc8 100644 --- a/src/cmd/internal/gc/subr.go +++ b/src/cmd/internal/gc/subr.go @@ -1898,7 +1898,7 @@ func safeexpr(n *Node, init **NodeList) *Node { case ONAME, OLITERAL: return n - case ODOT: + case ODOT, OLEN, OCAP: l := safeexpr(n.Left, init) if l == n.Left { return n diff --git a/src/cmd/internal/gc/walk.go b/src/cmd/internal/gc/walk.go index bef08ae252..495acb1861 100644 --- a/src/cmd/internal/gc/walk.go +++ b/src/cmd/internal/gc/walk.go @@ -1280,56 +1280,39 @@ func walkexpr(np **Node, init **NodeList) { case ORECV: Fatal("walkexpr ORECV") // should see inside OAS only - case OSLICE: - if n.Right != nil && n.Right.Left == nil && n.Right.Right == nil { // noop - walkexpr(&n.Left, init) - n = n.Left - goto ret - } - fallthrough - - case OSLICEARR, OSLICESTR: - if n.Right == nil { // already processed - goto ret - } - + case OSLICE, OSLICEARR, OSLICESTR: walkexpr(&n.Left, init) - - // cgen_slice can't handle string literals as source - // TODO the OINDEX case is a bug elsewhere that needs to be traced. it causes a crash on ([2][]int{ ... })[1][lo:hi] - if (n.Op == OSLICESTR && n.Left.Op == OLITERAL) || (n.Left.Op == OINDEX) { - n.Left = copyexpr(n.Left, n.Left.Type, init) - } else { - n.Left = safeexpr(n.Left, init) - } walkexpr(&n.Right.Left, init) - n.Right.Left = safeexpr(n.Right.Left, init) + if n.Right.Left != nil && iszero(n.Right.Left) { + // Reduce x[0:j] to x[:j]. + n.Right.Left = nil + } walkexpr(&n.Right.Right, init) - n.Right.Right = safeexpr(n.Right.Right, init) - n = sliceany(n, init) // chops n.Right, sets n.List + n = reduceSlice(n) goto ret case OSLICE3, OSLICE3ARR: - if n.Right == nil { // already processed + walkexpr(&n.Left, init) + walkexpr(&n.Right.Left, init) + if n.Right.Left != nil && iszero(n.Right.Left) { + // Reduce x[0:j:k] to x[:j:k]. + n.Right.Left = nil + } + walkexpr(&n.Right.Right.Left, init) + walkexpr(&n.Right.Right.Right, init) + + r := n.Right.Right.Right + if r != nil && r.Op == OCAP && samesafeexpr(n.Left, r.Left) { + // Reduce x[i:j:cap(x)] to x[i:j]. + n.Right.Right = n.Right.Right.Left + if n.Op == OSLICE3 { + n.Op = OSLICE + } else { + n.Op = OSLICEARR + } + n = reduceSlice(n) goto ret } - - walkexpr(&n.Left, init) - - // TODO the OINDEX case is a bug elsewhere that needs to be traced. it causes a crash on ([2][]int{ ... })[1][lo:hi] - // TODO the comment on the previous line was copied from case OSLICE. it might not even be true. - if n.Left.Op == OINDEX { - n.Left = copyexpr(n.Left, n.Left.Type, init) - } else { - n.Left = safeexpr(n.Left, init) - } - walkexpr(&n.Right.Left, init) - n.Right.Left = safeexpr(n.Right.Left, init) - walkexpr(&n.Right.Right.Left, init) - n.Right.Right.Left = safeexpr(n.Right.Right.Left, init) - walkexpr(&n.Right.Right.Right, init) - n.Right.Right.Right = safeexpr(n.Right.Right.Right, init) - n = sliceany(n, init) // chops n.Right, sets n.List goto ret case OADDR: @@ -1660,6 +1643,22 @@ ret: *np = n } +func reduceSlice(n *Node) *Node { + r := n.Right.Right + if r != nil && r.Op == OLEN && samesafeexpr(n.Left, r.Left) { + // Reduce x[i:len(x)] to x[i:]. + n.Right.Right = nil + } + if (n.Op == OSLICE || n.Op == OSLICESTR) && n.Right.Left == nil && n.Right.Right == nil { + // Reduce x[:] to x. + if Debug_slice > 0 { + Warn("slice: omit slice operation") + } + return n.Left + } + return n +} + func ascompatee1(op int, l *Node, r *Node, init **NodeList) *Node { // convas will turn map assigns into function calls, // making it impossible for reorder3 to work. @@ -3178,213 +3177,6 @@ func copyany(n *Node, init **NodeList, runtimecall int) *Node { return nlen } -// Generate frontend part for OSLICE[3][ARR|STR] -// -func sliceany(n *Node, init **NodeList) *Node { - var hb *Node - var cb *Node - - // print("before sliceany: %+N\n", n); - - src := n.Left - - lb := n.Right.Left - slice3 := n.Op == OSLICE3 || n.Op == OSLICE3ARR - if slice3 { - hb = n.Right.Right.Left - cb = n.Right.Right.Right - } else { - hb = n.Right.Right - cb = nil - } - - bounded := int(n.Etype) - - var bound *Node - if n.Op == OSLICESTR { - bound = Nod(OLEN, src, nil) - } else { - bound = Nod(OCAP, src, nil) - } - - typecheck(&bound, Erv) - walkexpr(&bound, init) // if src is an array, bound will be a const now. - - // static checks if possible - bv := int64(1 << 50) - - if Isconst(bound, CTINT) { - if !Smallintconst(bound) { - Yyerror("array len too large") - } else { - bv = Mpgetfix(bound.Val.U.Xval) - } - } - - if Isconst(cb, CTINT) { - cbv := Mpgetfix(cb.Val.U.Xval) - if cbv < 0 || cbv > bv { - Yyerror("slice index out of bounds") - } - } - - if Isconst(hb, CTINT) { - hbv := Mpgetfix(hb.Val.U.Xval) - if hbv < 0 || hbv > bv { - Yyerror("slice index out of bounds") - } - } - - if Isconst(lb, CTINT) { - lbv := Mpgetfix(lb.Val.U.Xval) - if lbv < 0 || lbv > bv { - Yyerror("slice index out of bounds") - lbv = -1 - } - - if lbv == 0 { - lb = nil - } - } - - // Checking src[lb:hb:cb] or src[lb:hb]. - // if chk0 || chk1 || chk2 { panicslice() } - - // All comparisons are unsigned to avoid testing < 0. - bt := Types[Simtype[TUINT]] - - if cb != nil && cb.Type.Width > 4 { - bt = Types[TUINT64] - } - if hb != nil && hb.Type.Width > 4 { - bt = Types[TUINT64] - } - if lb != nil && lb.Type.Width > 4 { - bt = Types[TUINT64] - } - - bound = cheapexpr(conv(bound, bt), init) - - var chk0 *Node // cap(src) < cb - if cb != nil { - cb = cheapexpr(conv(cb, bt), init) - if bounded == 0 { - chk0 = Nod(OLT, bound, cb) - } - } else if slice3 { - // When we figure out what this means, implement it. - Fatal("slice3 with cb == N") // rejected by parser - } - - var chk1 *Node // cb < hb for src[lb:hb:cb]; cap(src) < hb for src[lb:hb] - if hb != nil { - hb = cheapexpr(conv(hb, bt), init) - if bounded == 0 { - if cb != nil { - chk1 = Nod(OLT, cb, hb) - } else { - chk1 = Nod(OLT, bound, hb) - } - } - } else if slice3 { - // When we figure out what this means, implement it. - Fatal("slice3 with hb == N") // rejected by parser - } else if n.Op == OSLICEARR { - hb = bound - } else { - hb = Nod(OLEN, src, nil) - typecheck(&hb, Erv) - walkexpr(&hb, init) - hb = cheapexpr(conv(hb, bt), init) - } - - var chk2 *Node // hb < lb - if lb != nil { - lb = cheapexpr(conv(lb, bt), init) - if bounded == 0 { - chk2 = Nod(OLT, hb, lb) - } - } - - if chk0 != nil || chk1 != nil || chk2 != nil { - chk := Nod(OIF, nil, nil) - chk.Nbody = list1(mkcall("panicslice", nil, init)) - chk.Likely = -1 - if chk0 != nil { - chk.Ntest = chk0 - } - if chk1 != nil { - if chk.Ntest == nil { - chk.Ntest = chk1 - } else { - chk.Ntest = Nod(OOROR, chk.Ntest, chk1) - } - } - - if chk2 != nil { - if chk.Ntest == nil { - chk.Ntest = chk2 - } else { - chk.Ntest = Nod(OOROR, chk.Ntest, chk2) - } - } - - typecheck(&chk, Etop) - walkstmt(&chk) - *init = concat(*init, chk.Ninit) - chk.Ninit = nil - *init = list(*init, chk) - } - - // prepare new cap, len and offs for backend cgen_slice - // cap = bound [ - lo ] - n.Right = nil - - n.List = nil - if !slice3 { - cb = bound - } - if lb == nil { - bound = conv(cb, Types[Simtype[TUINT]]) - } else { - bound = Nod(OSUB, conv(cb, Types[Simtype[TUINT]]), conv(lb, Types[Simtype[TUINT]])) - } - typecheck(&bound, Erv) - walkexpr(&bound, init) - n.List = list(n.List, bound) - - // len = hi [ - lo] - if lb == nil { - hb = conv(hb, Types[Simtype[TUINT]]) - } else { - hb = Nod(OSUB, conv(hb, Types[Simtype[TUINT]]), conv(lb, Types[Simtype[TUINT]])) - } - typecheck(&hb, Erv) - walkexpr(&hb, init) - n.List = list(n.List, hb) - - // offs = [width *] lo, but omit if zero - if lb != nil { - var w int64 - if n.Op == OSLICESTR { - w = 1 - } else { - w = n.Type.Type.Width - } - lb = conv(lb, Types[TUINTPTR]) - if w > 1 { - lb = Nod(OMUL, Nodintconst(w), lb) - } - typecheck(&lb, Erv) - walkexpr(&lb, init) - n.List = list(n.List, lb) - } - - // print("after sliceany: %+N\n", n); - - return n -} - func eqfor(t *Type, needsize *int) *Node { // Should only arrive here with large memory or // a struct/array containing a non-memory field/element. diff --git a/test/sliceopt.go b/test/sliceopt.go index dc30717ebf..c9d089f7d2 100644 --- a/test/sliceopt.go +++ b/test/sliceopt.go @@ -1,10 +1,10 @@ -// errorcheck -0 -d=append +// errorcheck -0 -d=append,slice // Copyright 2015 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. -// Check optimization results for append. +// Check optimization results for append and slicing. package main @@ -20,3 +20,40 @@ func a2(x []int, y int) []int { func a3(x *[]int, y int) { *x = append(*x, y) // ERROR "append: len-only update" } + +func s1(x **[]int, xs **string, i, j int) { + var z []int + z = (**x)[2:] // ERROR "slice: omit check for 2nd index" + z = (**x)[2:len(**x)] // not yet: "slice: reuse len" "slice: omit check for 2nd index" + z = (**x)[2:cap(**x)] // not yet: "slice: reuse cap" "slice: omit check for 2nd index" + z = (**x)[i:i] // ERROR "slice: reuse 1st index" "slice: omit check for 1st index" "slice: result len == 0" + z = (**x)[1:i:i] // ERROR "slice: reuse 2nd index" "slice: omit check for 2nd index" "slice: result cap == result len" + z = (**x)[i:j:0] // ERROR "slice: omit check for 3rd index" + z = (**x)[i:0:j] // ERROR "slice: omit check for 2nd index" + z = (**x)[0:i:j] // ERROR "slice: omit check for 1st index" "slice: skip base adjustment for 1st index 0" + z = (**x)[0:] // ERROR "slice: omit slice operation" + z = (**x)[2:8] // ERROR "slice: omit check for 1st index" "slice: result len == 6" + z = (**x)[2:2] // ERROR "slice: omit check for 1st index" "slice: result len == 0" + z = (**x)[0:i] // ERROR "slice: omit check for 1st index" "slice: skip base adjustment for 1st index 0" + z = (**x)[2:i:8] // ERROR "slice: result cap == 6" + z = (**x)[i:2:i] // ERROR "slice: reuse 1st index" "slice: result cap == 0" "slice: skip base adjustment for cap == 0" + + z = z[0:i] // ERROR "slice: omit check for 1st index" "slice: result cap not computed" "slice: skip base adjustment for 1st index 0" "slice: len-only update" + z = z[0:i : i+1] // ERROR "slice: omit check for 1st index" "slice: skip base adjustment for 1st index 0" "slice: len/cap-only update" + z = z[i : i+1] + + println(z) + + var zs string + zs = (**xs)[2:] // ERROR "slice: omit check for 2nd index" + zs = (**xs)[2:len(**xs)] // not yet: "slice: reuse len" "slice: omit check for 2nd index" + zs = (**xs)[i:i] // ERROR "slice: reuse 1st index" "slice: omit check for 1st index" "slice: result len == 0" "slice: skip base adjustment for string len == 0" + zs = (**xs)[0:] // ERROR "slice: omit slice operation" + zs = (**xs)[2:8] // ERROR "slice: omit check for 1st index" "slice: result len == 6" + zs = (**xs)[2:2] // ERROR "slice: omit check for 1st index" "slice: result len == 0" "slice: skip base adjustment for string len == 0" + zs = (**xs)[0:i] // ERROR "slice: omit check for 1st index" "slice: skip base adjustment for 1st index 0" + + zs = zs[0:i] // ERROR "slice: omit check for 1st index" "slice: skip base adjustment for 1st index 0" "slice: len-only update" + zs = zs[i : i+1] + println(zs) +} From 6f2c0f1585e50bf2d8bcc11058373e38f5321227 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Tue, 12 May 2015 10:01:37 -0700 Subject: [PATCH 067/232] runtime: add check for malloc in a signal handler Change-Id: Ic8ebbe81eb788626c01bfab238d54236e6e5ef2b Reviewed-on: https://go-review.googlesource.com/9964 Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot Reviewed-by: Russ Cox --- src/runtime/malloc.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index a0cd8bb433..2d7e55643f 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -509,6 +509,9 @@ func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer { if mp.mallocing != 0 { throw("malloc deadlock") } + if mp.gsignal == getg() { + throw("malloc during signal") + } mp.mallocing = 1 shouldhelpgc := false From 1e26df40fa2ee41da971338ab25299e27a221704 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Mon, 11 May 2015 13:31:05 -0700 Subject: [PATCH 068/232] cmd/doc: print BUGs after package docs Was otherwise absent unless bound to an exported symbol, as in the BUG with strings.Title. Fixes #10781. Change-Id: I1543137073a9dee9e546bc9d648ca54fc9632dde Reviewed-on: https://go-review.googlesource.com/9899 Reviewed-by: Russ Cox --- src/cmd/doc/pkg.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/cmd/doc/pkg.go b/src/cmd/doc/pkg.go index 3a0aa7ff89..835313e902 100644 --- a/src/cmd/doc/pkg.go +++ b/src/cmd/doc/pkg.go @@ -190,6 +190,7 @@ func (pkg *Package) packageDoc() { pkg.valueSummary(pkg.doc.Vars) pkg.funcSummary(pkg.doc.Funcs) pkg.typeSummary() + pkg.bugs() } // packageClause prints the package clause. @@ -253,6 +254,18 @@ func (pkg *Package) typeSummary() { } } +// bugs prints the BUGS information for the package. +// TODO: Provide access to TODOs and NOTEs as well (very noisy so off by default)? +func (pkg *Package) bugs() { + if pkg.doc.Notes["BUG"] == nil { + return + } + pkg.Printf("\n") + for _, note := range pkg.doc.Notes["BUG"] { + pkg.Printf("%s: %v\n", "BUG", note.Body) + } +} + // findValues finds the doc.Values that describe the symbol. func (pkg *Package) findValues(symbol string, docValues []*doc.Value) (values []*doc.Value) { for _, value := range docValues { From 647026a16ba7468855b9f83ab796080708879516 Mon Sep 17 00:00:00 2001 From: "Hyang-Ah (Hana) Kim" Date: Wed, 13 May 2015 17:26:19 -0400 Subject: [PATCH 069/232] misc/cgo/testcshared: remove use of 'env'. 'env' command is not available on some android devices. Change-Id: I68b1152ef7ea248c8e80c7f71e97da76e3ec6394 Reviewed-on: https://go-review.googlesource.com/9999 Reviewed-by: Minux Ma --- misc/cgo/testcshared/test.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/cgo/testcshared/test.bash b/misc/cgo/testcshared/test.bash index ed437577c7..492d25e134 100755 --- a/misc/cgo/testcshared/test.bash +++ b/misc/cgo/testcshared/test.bash @@ -46,7 +46,7 @@ function run() { case "$goos" in "android") local args=$@ - output=$(adb shell "cd ${androidpath}; env $@") + output=$(adb shell "cd ${androidpath}; $@") output=$(echo $output|tr -d '\r') case $output in *PASS) echo "PASS";; From 645e77ef10ef2367ab07669dc4e8be5b54d36fe7 Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Wed, 13 May 2015 14:06:43 +0900 Subject: [PATCH 070/232] net/internal/socktest: fix data race Fixes #10796. Change-Id: Ifcd2e771c64114e210fbfc5efaaceb53c534f745 Reviewed-on: https://go-review.googlesource.com/10007 Reviewed-by: Brad Fitzpatrick --- src/net/internal/socktest/main_test.go | 16 ++++++++++++++++ src/net/internal/socktest/switch.go | 14 +++++++------- src/net/internal/socktest/switch_unix.go | 2 +- src/net/internal/socktest/switch_windows.go | 2 +- src/net/internal/socktest/sys_unix.go | 2 ++ src/net/internal/socktest/sys_windows.go | 2 ++ 6 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/net/internal/socktest/main_test.go b/src/net/internal/socktest/main_test.go index 3ae1c6be3c..60e581f463 100644 --- a/src/net/internal/socktest/main_test.go +++ b/src/net/internal/socktest/main_test.go @@ -9,6 +9,7 @@ package socktest_test import ( "net/internal/socktest" "os" + "sync" "syscall" "testing" ) @@ -27,6 +28,21 @@ func TestMain(m *testing.M) { os.Exit(st) } +func TestSwitch(t *testing.T) { + const N = 10 + var wg sync.WaitGroup + wg.Add(N) + for i := 0; i < N; i++ { + go func() { + defer wg.Done() + for _, family := range []int{syscall.AF_INET, syscall.AF_INET6} { + socketFunc(family, syscall.SOCK_STREAM, syscall.IPPROTO_TCP) + } + }() + } + wg.Wait() +} + func TestSocket(t *testing.T) { for _, f := range []socktest.Filter{ func(st *socktest.Status) (socktest.AfterFilter, error) { return nil, nil }, diff --git a/src/net/internal/socktest/switch.go b/src/net/internal/socktest/switch.go index 5e558a2de3..4e38c7a85f 100644 --- a/src/net/internal/socktest/switch.go +++ b/src/net/internal/socktest/switch.go @@ -10,12 +10,6 @@ import ( "sync" ) -func switchInit(sw *Switch) { - sw.fltab = make(map[FilterType]Filter) - sw.sotab = make(Sockets) - sw.stats = make(stats) -} - // A Switch represents a callpath point switch for socket system // calls. type Switch struct { @@ -29,6 +23,12 @@ type Switch struct { stats stats } +func (sw *Switch) init() { + sw.fltab = make(map[FilterType]Filter) + sw.sotab = make(Sockets) + sw.stats = make(stats) +} + // Stats returns a list of per-cookie socket statistics. func (sw *Switch) Stats() []Stat { var st []Stat @@ -162,7 +162,7 @@ func (f AfterFilter) apply(st *Status) error { // Set deploys the socket system call filter f for the filter type t. func (sw *Switch) Set(t FilterType, f Filter) { - sw.once.Do(func() { switchInit(sw) }) + sw.once.Do(sw.init) sw.fmu.Lock() sw.fltab[t] = f sw.fmu.Unlock() diff --git a/src/net/internal/socktest/switch_unix.go b/src/net/internal/socktest/switch_unix.go index 2b89276fa1..14c0c228a2 100644 --- a/src/net/internal/socktest/switch_unix.go +++ b/src/net/internal/socktest/switch_unix.go @@ -22,7 +22,7 @@ func (sw *Switch) sockso(s int) *Status { // addLocked returns a new Status without locking. // sw.smu must be held before call. func (sw *Switch) addLocked(s, family, sotype, proto int) *Status { - sw.once.Do(func() { switchInit(sw) }) + sw.once.Do(sw.init) so := Status{Cookie: cookie(family, sotype, proto)} sw.sotab[s] = so return &so diff --git a/src/net/internal/socktest/switch_windows.go b/src/net/internal/socktest/switch_windows.go index 3cee49ba0b..4f1d597a27 100644 --- a/src/net/internal/socktest/switch_windows.go +++ b/src/net/internal/socktest/switch_windows.go @@ -22,7 +22,7 @@ func (sw *Switch) sockso(s syscall.Handle) *Status { // addLocked returns a new Status without locking. // sw.smu must be held before call. func (sw *Switch) addLocked(s syscall.Handle, family, sotype, proto int) *Status { - sw.once.Do(func() { switchInit(sw) }) + sw.once.Do(sw.init) so := Status{Cookie: cookie(family, sotype, proto)} sw.sotab[s] = so return &so diff --git a/src/net/internal/socktest/sys_unix.go b/src/net/internal/socktest/sys_unix.go index 4089f8cea2..f983e266f1 100644 --- a/src/net/internal/socktest/sys_unix.go +++ b/src/net/internal/socktest/sys_unix.go @@ -10,6 +10,8 @@ import "syscall" // Socket wraps syscall.Socket. func (sw *Switch) Socket(family, sotype, proto int) (s int, err error) { + sw.once.Do(sw.init) + so := &Status{Cookie: cookie(family, sotype, proto)} sw.fmu.RLock() f, _ := sw.fltab[FilterSocket] diff --git a/src/net/internal/socktest/sys_windows.go b/src/net/internal/socktest/sys_windows.go index 907e01b5a2..07af0e7046 100644 --- a/src/net/internal/socktest/sys_windows.go +++ b/src/net/internal/socktest/sys_windows.go @@ -8,6 +8,8 @@ import "syscall" // Socket wraps syscall.Socket. func (sw *Switch) Socket(family, sotype, proto int) (s syscall.Handle, err error) { + sw.once.Do(sw.init) + so := &Status{Cookie: cookie(family, sotype, proto)} sw.fmu.RLock() f, _ := sw.fltab[FilterSocket] From f6d1009431c4d4677a292be5a78f57c239929d4b Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Wed, 13 May 2015 10:06:20 +0900 Subject: [PATCH 071/232] doc: mention net.SocketConn, net.SocketPacketConn in go1.5.txt Change-Id: I6bda19877ae5148ad349cfb8929f1103740422bb Reviewed-on: https://go-review.googlesource.com/10005 Reviewed-by: Ian Lance Taylor --- doc/go1.5.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/go1.5.txt b/doc/go1.5.txt index b0602f9b77..571a9f17d0 100644 --- a/doc/go1.5.txt +++ b/doc/go1.5.txt @@ -53,6 +53,7 @@ mime: add ExtensionByType (https://golang.org/cl/7444) mime/quotedprintable: new package (https://golang.org/cl/5940 + others) net: add Source field to OpError (https://go-review.googlesource.com/9231) net: fix inconsistent errors (https://golang.org/cl/9236) +net: add SocketConn, SocketPacketConn (https://golang.org/cl/9275) net/http: support for setting trailers from a server Handler (https://golang.org/cl/2157) net/http: ignore the Unix epoch time in ServeContent (https://golang.org/cl/7915) net/http/cgi: fix REMOTE_ADDR, REMOTE_HOST, add REMOTE_PORT (https://golang.org/cl/4933) From f8fbcefa6cdd9901d5d9183bf6ad3fed73f1b455 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 13 May 2015 15:12:59 -0700 Subject: [PATCH 072/232] math/rand: shorten Float32 test for GOARM=5 Fixes #10749 Change-Id: I9d5f6f179fd117b0c358d7c8042daf5985b645c0 Reviewed-on: https://go-review.googlesource.com/10022 Reviewed-by: Dave Cheney --- src/math/rand/rand_test.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/math/rand/rand_test.go b/src/math/rand/rand_test.go index ab0dc49b41..c61494f8eb 100644 --- a/src/math/rand/rand_test.go +++ b/src/math/rand/rand_test.go @@ -8,6 +8,8 @@ import ( "errors" "fmt" "math" + "os" + "runtime" "testing" ) @@ -322,10 +324,17 @@ func TestExpTables(t *testing.T) { } } -// For issue 6721, the problem came after 7533753 calls, so check 10e6. func TestFloat32(t *testing.T) { + // For issue 6721, the problem came after 7533753 calls, so check 10e6. + num := int(10e6) + // But ARM5 floating point emulation is slow (Issue 10749), so + // do less for that builder: + if testing.Short() && runtime.GOARCH == "arm" && os.Getenv("GOARM") == "5" { + num /= 100 // 1.72 seconds instead of 172 seconds + } + r := New(NewSource(1)) - for ct := 0; ct < 10e6; ct++ { + for ct := 0; ct < num; ct++ { f := r.Float32() if f >= 1 { t.Fatal("Float32() should be in range [0,1). ct:", ct, "f:", f) From fd5b8aa7999e6710e14f4798dcb9e9387247511d Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 13 May 2015 16:07:33 -0700 Subject: [PATCH 073/232] text/scanner: avoid further reads after EOF Fixes #10735. Change-Id: I5c6e424653657c89da176136ac56597c7565abe5 Reviewed-on: https://go-review.googlesource.com/10039 Reviewed-by: Rob Pike --- src/text/scanner/scanner.go | 6 +++++- src/text/scanner/scanner_test.go | 36 +++++++++++++++++++++++++------- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/text/scanner/scanner.go b/src/text/scanner/scanner.go index d3eadfd7e1..eacc0a2245 100644 --- a/src/text/scanner/scanner.go +++ b/src/text/scanner/scanner.go @@ -314,7 +314,9 @@ func (s *Scanner) Next() rune { s.tokPos = -1 // don't collect token text s.Line = 0 // invalidate token position ch := s.Peek() - s.ch = s.next() + if ch != EOF { + s.ch = s.next() + } return ch } @@ -597,6 +599,8 @@ redo: } default: switch ch { + case EOF: + break case '"': if s.Mode&ScanStrings != 0 { s.scanString('"') diff --git a/src/text/scanner/scanner_test.go b/src/text/scanner/scanner_test.go index aca17b1b27..798bed7e92 100644 --- a/src/text/scanner/scanner_test.go +++ b/src/text/scanner/scanner_test.go @@ -619,13 +619,12 @@ func TestPos(t *testing.T) { type countReader int -func (c *countReader) Read([]byte) (int, error) { - *c++ - +func (r *countReader) Read([]byte) (int, error) { + *r++ return 0, io.EOF } -func TestPeekEOFHandling(t *testing.T) { +func TestNextEOFHandling(t *testing.T) { var r countReader // corner case: empty source @@ -633,15 +632,36 @@ func TestPeekEOFHandling(t *testing.T) { tok := s.Next() if tok != EOF { - t.Errorf("EOF not reported") + t.Error("1) EOF not reported") } tok = s.Peek() if tok != EOF { - t.Errorf("EOF not reported") + t.Error("2) EOF not reported") } - if r != 2 { - t.Errorf("scanner called Read %d times, not twice", r) + if r != 1 { + t.Errorf("scanner called Read %d times, not once", r) + } +} + +func TestScanEOFHandling(t *testing.T) { + var r countReader + + // corner case: empty source + s := new(Scanner).Init(&r) + + tok := s.Scan() + if tok != EOF { + t.Error("1) EOF not reported") + } + + tok = s.Peek() + if tok != EOF { + t.Error("2) EOF not reported") + } + + if r != 1 { + t.Errorf("scanner called Read %d times, not once", r) } } From 5c7f94421ef5eca55b37f778b427abd5ea174c26 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 13 May 2015 15:28:11 -0700 Subject: [PATCH 074/232] cmd/internal/obj: validate GOARM environment variable's value before use I was previously setting GOARM=arm5 (due to confusion with previously seeing buildall.sh's temporary of "arm5" as a GOARCH and misremembernig), but GOARM=arm5 was acting like GOARM=5 only on accident. See https://go-review.googlesource.com/#/c/10023/ Instead, fail if GOARM is not a known value. Change-Id: I9ba4fd7268df233d40b09f0431f37cd85a049847 Reviewed-on: https://go-review.googlesource.com/10024 Reviewed-by: Minux Ma --- src/cmd/internal/obj/util.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/cmd/internal/obj/util.go b/src/cmd/internal/obj/util.go index b0b209184f..ac49543fdf 100644 --- a/src/cmd/internal/obj/util.go +++ b/src/cmd/internal/obj/util.go @@ -213,10 +213,17 @@ func Getgoos() string { } func Getgoarm() string { - return envOr("GOARM", defaultGOARM) + switch v := envOr("GOARM", defaultGOARM); v { + case "5", "6", "7": + return v + } + // Fail here, rather than validate at multiple call sites. + log.Fatalf("Invalid GOARM value. Must be 5, 6, or 7.") + panic("unreachable") } func Getgo386() string { + // Validated by cmd/8g. return envOr("GO386", defaultGO386) } From e5febf957f5be9d3325c2d851bff6ec7c55e4662 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 13 May 2015 12:41:56 -0700 Subject: [PATCH 075/232] net/http: flush request body chunks in Transport The Transport's writer to the remote server is wrapped in a bufio.Writer to suppress many small writes while writing headers and trailers. However, when writing the request body, the buffering may get in the way if the request body is arriving slowly. Because the io.Copy from the Request.Body to the writer is already buffered, the outer bufio.Writer is unnecessary and prevents small Request.Body.Reads from going to the server right away. (and the io.Reader contract does say to return when you've got something, instead of blocking waiting for more). After the body is finished, the Transport's bufio.Writer is still used for any trailers following. A previous attempted fix for this made the chunk writer always flush if the underlying type was a bufio.Writer, but that is not quite correct. This CL instead makes it opt-in by using a private sentinel type (wrapping a *bufio.Writer) to the chunk writer that requests Flushes after each chunk body (the chunk header & chunk body are still buffered together into one write). Fixes #6574 Change-Id: Icefcdf17130c9e285c80b69af295bfd3e72c3a70 Reviewed-on: https://go-review.googlesource.com/10021 Reviewed-by: Andrew Gerrand Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/net/http/internal/chunked.go | 17 +++++- src/net/http/transfer.go | 5 ++ src/net/http/transport_test.go | 99 ++++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+), 2 deletions(-) diff --git a/src/net/http/internal/chunked.go b/src/net/http/internal/chunked.go index 9294deb3e5..6d7c69874d 100644 --- a/src/net/http/internal/chunked.go +++ b/src/net/http/internal/chunked.go @@ -173,8 +173,12 @@ func (cw *chunkedWriter) Write(data []byte) (n int, err error) { err = io.ErrShortWrite return } - _, err = io.WriteString(cw.Wire, "\r\n") - + if _, err = io.WriteString(cw.Wire, "\r\n"); err != nil { + return + } + if bw, ok := cw.Wire.(*FlushAfterChunkWriter); ok { + err = bw.Flush() + } return } @@ -183,6 +187,15 @@ func (cw *chunkedWriter) Close() error { return err } +// FlushAfterChunkWriter signals from the caller of NewChunkedWriter +// that each chunk should be followed by a flush. It is used by the +// http.Transport code to keep the buffering behavior for headers and +// trailers, but flush out chunks aggressively in the middle for +// request bodies which may be generated slowly. See Issue 6574. +type FlushAfterChunkWriter struct { + *bufio.Writer +} + func parseHexUint(v []byte) (n uint64, err error) { for _, b := range v { n <<= 4 diff --git a/src/net/http/transfer.go b/src/net/http/transfer.go index 5640344345..289d53dec0 100644 --- a/src/net/http/transfer.go +++ b/src/net/http/transfer.go @@ -43,6 +43,7 @@ type transferWriter struct { Close bool TransferEncoding []string Trailer Header + IsResponse bool } func newTransferWriter(r interface{}) (t *transferWriter, err error) { @@ -89,6 +90,7 @@ func newTransferWriter(r interface{}) (t *transferWriter, err error) { } } case *Response: + t.IsResponse = true if rr.Request != nil { t.Method = rr.Request.Method } @@ -206,6 +208,9 @@ func (t *transferWriter) WriteBody(w io.Writer) error { // Write body if t.Body != nil { if chunked(t.TransferEncoding) { + if bw, ok := w.(*bufio.Writer); ok && !t.IsResponse { + w = &internal.FlushAfterChunkWriter{bw} + } cw := internal.NewChunkedWriter(w) _, err = io.Copy(cw, t.Body) if err == nil { diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go index ace58896b8..ca1a3ab407 100644 --- a/src/net/http/transport_test.go +++ b/src/net/http/transport_test.go @@ -23,6 +23,7 @@ import ( "net/http/httptest" "net/url" "os" + "reflect" "runtime" "strconv" "strings" @@ -2447,6 +2448,104 @@ func TestTransportDialCancelRace(t *testing.T) { } } +// logWritesConn is a net.Conn that logs each Write call to writes +// and then proxies to w. +// It proxies Read calls to a reader it receives from rch. +type logWritesConn struct { + net.Conn // nil. crash on use. + + w io.Writer + + rch <-chan io.Reader + r io.Reader // nil until received by rch + + mu sync.Mutex + writes []string +} + +func (c *logWritesConn) Write(p []byte) (n int, err error) { + c.mu.Lock() + defer c.mu.Unlock() + c.writes = append(c.writes, string(p)) + return c.w.Write(p) +} + +func (c *logWritesConn) Read(p []byte) (n int, err error) { + if c.r == nil { + c.r = <-c.rch + } + return c.r.Read(p) +} + +func (c *logWritesConn) Close() error { return nil } + +// Issue 6574 +func TestTransportFlushesBodyChunks(t *testing.T) { + defer afterTest(t) + resBody := make(chan io.Reader, 1) + connr, connw := io.Pipe() // connection pipe pair + lw := &logWritesConn{ + rch: resBody, + w: connw, + } + tr := &Transport{ + Dial: func(network, addr string) (net.Conn, error) { + return lw, nil + }, + } + bodyr, bodyw := io.Pipe() // body pipe pair + go func() { + defer bodyw.Close() + for i := 0; i < 3; i++ { + fmt.Fprintf(bodyw, "num%d\n", i) + } + }() + resc := make(chan *Response) + go func() { + req, _ := NewRequest("POST", "http://localhost:8080", bodyr) + req.Header.Set("User-Agent", "x") // known value for test + res, err := tr.RoundTrip(req) + if err != nil { + t.Error("RoundTrip: %v", err) + close(resc) + return + } + resc <- res + + }() + // Fully consume the request before checking the Write log vs. want. + req, err := ReadRequest(bufio.NewReader(connr)) + if err != nil { + t.Fatal(err) + } + io.Copy(ioutil.Discard, req.Body) + + // Unblock the transport's roundTrip goroutine. + resBody <- strings.NewReader("HTTP/1.1 204 No Content\r\nConnection: close\r\n\r\n") + res, ok := <-resc + if !ok { + return + } + defer res.Body.Close() + + want := []string{ + // Because Request.ContentLength = 0, the body is sniffed for 1 byte to determine whether there's content. + // That explains the initial "num0" being split into "n" and "um0". + // The first byte is included with the request headers Write. Perhaps in the future + // we will want to flush the headers out early if the first byte of the request body is + // taking a long time to arrive. But not yet. + "POST / HTTP/1.1\r\nHost: localhost:8080\r\nUser-Agent: x\r\nTransfer-Encoding: chunked\r\nAccept-Encoding: gzip\r\n\r\n" + + "1\r\nn\r\n", + "4\r\num0\n\r\n", + "5\r\nnum1\n\r\n", + "5\r\nnum2\n\r\n", + "0\r\n\r\n", + } + if !reflect.DeepEqual(lw.writes, want) { + t.Errorf("Writes differed.\n Got: %q\nWant: %q\n", lw.writes, want) + } +} + func wantBody(res *http.Response, err error, want string) error { if err != nil { return err From ef54930ebb65f1d611cb321eb86062fd4accc0ff Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Thu, 14 May 2015 09:25:24 +0900 Subject: [PATCH 076/232] net: simplify sync.Once calls in tests Change-Id: I0c2e1a4a8261887a696e585dda46e72d691191e0 Reviewed-on: https://go-review.googlesource.com/10070 Reviewed-by: Brad Fitzpatrick --- src/net/dnsclient_unix_test.go | 6 +++--- src/net/dnsname_test.go | 2 +- src/net/interface_test.go | 12 ++++++------ src/net/ip_test.go | 6 +++--- src/net/main_test.go | 2 +- src/net/tcp_test.go | 4 ++-- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/net/dnsclient_unix_test.go b/src/net/dnsclient_unix_test.go index 1b88e7762b..4ea24b6014 100644 --- a/src/net/dnsclient_unix_test.go +++ b/src/net/dnsclient_unix_test.go @@ -227,7 +227,7 @@ func TestReloadResolvConfChange(t *testing.T) { } func BenchmarkGoLookupIP(b *testing.B) { - testHookUninstaller.Do(func() { uninstallTestHooks() }) + testHookUninstaller.Do(uninstallTestHooks) for i := 0; i < b.N; i++ { goLookupIP("www.example.com") @@ -235,7 +235,7 @@ func BenchmarkGoLookupIP(b *testing.B) { } func BenchmarkGoLookupIPNoSuchHost(b *testing.B) { - testHookUninstaller.Do(func() { uninstallTestHooks() }) + testHookUninstaller.Do(uninstallTestHooks) for i := 0; i < b.N; i++ { goLookupIP("some.nonexistent") @@ -243,7 +243,7 @@ func BenchmarkGoLookupIPNoSuchHost(b *testing.B) { } func BenchmarkGoLookupIPWithBrokenNameServer(b *testing.B) { - testHookUninstaller.Do(func() { uninstallTestHooks() }) + testHookUninstaller.Do(uninstallTestHooks) onceLoadConfig.Do(loadDefaultConfig) diff --git a/src/net/dnsname_test.go b/src/net/dnsname_test.go index cc660c9d42..be07dc6a16 100644 --- a/src/net/dnsname_test.go +++ b/src/net/dnsname_test.go @@ -68,7 +68,7 @@ func TestDNSName(t *testing.T) { } func BenchmarkDNSName(b *testing.B) { - testHookUninstaller.Do(func() { uninstallTestHooks() }) + testHookUninstaller.Do(uninstallTestHooks) benchmarks := append(dnsNameTests, []dnsNameTest{ {strings.Repeat("a", 63), true}, diff --git a/src/net/interface_test.go b/src/net/interface_test.go index 0e5c2e3ddf..567d18de44 100644 --- a/src/net/interface_test.go +++ b/src/net/interface_test.go @@ -229,7 +229,7 @@ func testMulticastAddrs(t *testing.T, ifmat []Addr) (nmaf4, nmaf6 int) { } func BenchmarkInterfaces(b *testing.B) { - testHookUninstaller.Do(func() { uninstallTestHooks() }) + testHookUninstaller.Do(uninstallTestHooks) for i := 0; i < b.N; i++ { if _, err := Interfaces(); err != nil { @@ -239,7 +239,7 @@ func BenchmarkInterfaces(b *testing.B) { } func BenchmarkInterfaceByIndex(b *testing.B) { - testHookUninstaller.Do(func() { uninstallTestHooks() }) + testHookUninstaller.Do(uninstallTestHooks) ifi := loopbackInterface() if ifi == nil { @@ -253,7 +253,7 @@ func BenchmarkInterfaceByIndex(b *testing.B) { } func BenchmarkInterfaceByName(b *testing.B) { - testHookUninstaller.Do(func() { uninstallTestHooks() }) + testHookUninstaller.Do(uninstallTestHooks) ifi := loopbackInterface() if ifi == nil { @@ -267,7 +267,7 @@ func BenchmarkInterfaceByName(b *testing.B) { } func BenchmarkInterfaceAddrs(b *testing.B) { - testHookUninstaller.Do(func() { uninstallTestHooks() }) + testHookUninstaller.Do(uninstallTestHooks) for i := 0; i < b.N; i++ { if _, err := InterfaceAddrs(); err != nil { @@ -277,7 +277,7 @@ func BenchmarkInterfaceAddrs(b *testing.B) { } func BenchmarkInterfacesAndAddrs(b *testing.B) { - testHookUninstaller.Do(func() { uninstallTestHooks() }) + testHookUninstaller.Do(uninstallTestHooks) ifi := loopbackInterface() if ifi == nil { @@ -291,7 +291,7 @@ func BenchmarkInterfacesAndAddrs(b *testing.B) { } func BenchmarkInterfacesAndMulticastAddrs(b *testing.B) { - testHookUninstaller.Do(func() { uninstallTestHooks() }) + testHookUninstaller.Do(uninstallTestHooks) ifi := loopbackInterface() if ifi == nil { diff --git a/src/net/ip_test.go b/src/net/ip_test.go index 24f67cac97..b1939cd08f 100644 --- a/src/net/ip_test.go +++ b/src/net/ip_test.go @@ -53,7 +53,7 @@ func TestParseIP(t *testing.T) { } func BenchmarkParseIP(b *testing.B) { - testHookUninstaller.Do(func() { uninstallTestHooks() }) + testHookUninstaller.Do(uninstallTestHooks) for i := 0; i < b.N; i++ { for _, tt := range parseIPTests { @@ -110,7 +110,7 @@ func TestIPString(t *testing.T) { } func BenchmarkIPString(b *testing.B) { - testHookUninstaller.Do(func() { uninstallTestHooks() }) + testHookUninstaller.Do(uninstallTestHooks) for i := 0; i < b.N; i++ { for _, tt := range ipStringTests { @@ -162,7 +162,7 @@ func TestIPMaskString(t *testing.T) { } func BenchmarkIPMaskString(b *testing.B) { - testHookUninstaller.Do(func() { uninstallTestHooks() }) + testHookUninstaller.Do(uninstallTestHooks) for i := 0; i < b.N; i++ { for _, tt := range ipMaskStringTests { diff --git a/src/net/main_test.go b/src/net/main_test.go index 4288e2add2..5e2f3da0e6 100644 --- a/src/net/main_test.go +++ b/src/net/main_test.go @@ -43,7 +43,7 @@ func TestMain(m *testing.M) { st := m.Run() - testHookUninstaller.Do(func() { uninstallTestHooks() }) + testHookUninstaller.Do(uninstallTestHooks) if !testing.Short() { printLeakedGoroutines() printLeakedSockets() diff --git a/src/net/tcp_test.go b/src/net/tcp_test.go index 6229df2869..64117449bd 100644 --- a/src/net/tcp_test.go +++ b/src/net/tcp_test.go @@ -58,7 +58,7 @@ func BenchmarkTCP6PersistentTimeout(b *testing.B) { } func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) { - testHookUninstaller.Do(func() { uninstallTestHooks() }) + testHookUninstaller.Do(uninstallTestHooks) const msgLen = 512 conns := b.N @@ -168,7 +168,7 @@ func BenchmarkTCP6ConcurrentReadWrite(b *testing.B) { } func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) { - testHookUninstaller.Do(func() { uninstallTestHooks() }) + testHookUninstaller.Do(uninstallTestHooks) // The benchmark creates GOMAXPROCS client/server pairs. // Each pair creates 4 goroutines: client reader/writer and server reader/writer. From dbf533a5460d7fcc7d7be77014fd74a8aff8c412 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Wed, 13 May 2015 19:27:59 -0700 Subject: [PATCH 077/232] encoding/json: make BenchmarkSkipValue more stable BenchmarkSkipValue was sensitive to the value of b.N due to its significant startup cost. Two adjacent runs before this CL: BenchmarkSkipValue 50 21047499 ns/op 93.37 MB/s BenchmarkSkipValue 100 17260554 ns/op 118.05 MB/s After this CL, using benchtime to recreate the difference in b.N: BenchmarkSkipValue 50 15204797 ns/op 131.67 MB/s BenchmarkSkipValue 100 15332319 ns/op 130.58 MB/s Change-Id: Iac86f86dd774d535302fa5e4c08f89f8da00be9e Reviewed-on: https://go-review.googlesource.com/10053 Reviewed-by: Andrew Gerrand --- src/encoding/json/scanner_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/encoding/json/scanner_test.go b/src/encoding/json/scanner_test.go index 7880342902..66383ef0ef 100644 --- a/src/encoding/json/scanner_test.go +++ b/src/encoding/json/scanner_test.go @@ -209,6 +209,7 @@ var benchScan scanner func BenchmarkSkipValue(b *testing.B) { initBig() + b.ResetTimer() for i := 0; i < b.N; i++ { nextValue(jsonBig, &benchScan) } From b3fb0fdd3f7c35e020788acf6d12278590b416cb Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Wed, 13 May 2015 19:05:50 -0400 Subject: [PATCH 078/232] cmd/internal/gc: fix vet detected printf problems Fixes #10805. Change-Id: Ia77639e606a0c18fc53cba9749d92f325014025f Reviewed-on: https://go-review.googlesource.com/10040 Reviewed-by: Josh Bleecher Snyder --- src/cmd/internal/gc/dcl.go | 2 +- src/cmd/internal/gc/gen.go | 2 +- src/cmd/internal/gc/go.y | 5 +- src/cmd/internal/gc/typecheck.go | 8 +- src/cmd/internal/gc/y.go | 553 +++++++++--------- src/cmd/internal/gc/y.output | 972 +++++++++++++++---------------- 6 files changed, 772 insertions(+), 770 deletions(-) diff --git a/src/cmd/internal/gc/dcl.go b/src/cmd/internal/gc/dcl.go index 08d2469094..627556eeef 100644 --- a/src/cmd/internal/gc/dcl.go +++ b/src/cmd/internal/gc/dcl.go @@ -183,7 +183,7 @@ func declare(n *Node, ctxt uint8) { } if ctxt == PEXTERN && s.Name == "init" { - Yyerror("cannot declare init - must be func", s) + Yyerror("cannot declare init - must be func") } gen := 0 diff --git a/src/cmd/internal/gc/gen.go b/src/cmd/internal/gc/gen.go index a9c348da2d..fcb2499d3b 100644 --- a/src/cmd/internal/gc/gen.go +++ b/src/cmd/internal/gc/gen.go @@ -965,7 +965,7 @@ func cgen_callmeth(n *Node, proc int) { l := n.Left if l.Op != ODOTMETH { - Fatal("cgen_callmeth: not dotmethod: %v") + Fatal("cgen_callmeth: not dotmethod: %v", l) } n2 := *n diff --git a/src/cmd/internal/gc/go.y b/src/cmd/internal/gc/go.y index f1904b0085..bbee200889 100644 --- a/src/cmd/internal/gc/go.y +++ b/src/cmd/internal/gc/go.y @@ -21,6 +21,7 @@ package gc import ( + "fmt" "strings" ) %} @@ -1975,9 +1976,9 @@ hidden_import: importlist = list(importlist, $2); if Debug['E'] > 0 { - print("import [%q] func %lN \n", importpkg.Path, $2); + fmt.Printf("import [%q] func %v \n", importpkg.Path, $2) if Debug['m'] > 2 && $2.Func.Inl != nil { - print("inl body:%+H\n", $2.Func.Inl); + fmt.Printf("inl body:%v\n", $2.Func.Inl) } } } diff --git a/src/cmd/internal/gc/typecheck.go b/src/cmd/internal/gc/typecheck.go index 185cfecc68..3061275da3 100644 --- a/src/cmd/internal/gc/typecheck.go +++ b/src/cmd/internal/gc/typecheck.go @@ -1303,7 +1303,7 @@ OpSwitch: if l.Op == OTYPE { if n.Isddd || l.Type.Bound == -100 { if l.Type.Broke == 0 { - Yyerror("invalid use of ... in type conversion", l) + Yyerror("invalid use of ... in type conversion to %v", l.Type) } n.Diag = 1 } @@ -1528,7 +1528,7 @@ OpSwitch: var t *Type switch l.Type.Etype { default: - Yyerror("invalid operation: %v (arguments have type %v, expected floating-point)", n, l.Type, r.Type) + Yyerror("invalid operation: %v (arguments have type %v, expected floating-point)", n, l.Type) n.Type = nil return @@ -1645,7 +1645,7 @@ OpSwitch: n.Type = t if !Isslice(t) { if Isconst(args.N, CTNIL) { - Yyerror("first argument to append must be typed slice; have untyped nil", t) + Yyerror("first argument to append must be typed slice; have untyped nil") n.Type = nil return } @@ -3526,7 +3526,7 @@ func typecheckfunc(n *Node) { func stringtoarraylit(np **Node) { n := *np if n.Left.Op != OLITERAL || n.Left.Val.Ctype != CTSTR { - Fatal("stringtoarraylit %N", n) + Fatal("stringtoarraylit %v", n) } s := n.Left.Val.U.Sval diff --git a/src/cmd/internal/gc/y.go b/src/cmd/internal/gc/y.go index f2c8b96982..fd3f2b3176 100644 --- a/src/cmd/internal/gc/y.go +++ b/src/cmd/internal/gc/y.go @@ -5,10 +5,11 @@ import __yyfmt__ "fmt" //line go.y:21 import ( + "fmt" "strings" ) -//line go.y:27 +//line go.y:28 type yySymType struct { yys int node *Node @@ -153,7 +154,7 @@ const yyEofCode = 1 const yyErrCode = 2 const yyMaxDepth = 200 -//line go.y:2242 +//line go.y:2243 func fixlbrace(lbr int) { // If the opening brace was an LBODY, // set up for another one now that we're done. @@ -1187,13 +1188,13 @@ yydefault: case 1: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:127 + //line go.y:128 { xtop = concat(xtop, yyDollar[4].list) } case 2: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:133 + //line go.y:134 { prevlineno = lineno Yyerror("package statement must be first") @@ -1201,13 +1202,13 @@ yydefault: } case 3: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:139 + //line go.y:140 { mkpackage(yyDollar[2].sym.Name) } case 4: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:149 + //line go.y:150 { importpkg = Runtimepkg @@ -1220,13 +1221,13 @@ yydefault: } case 5: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:161 + //line go.y:162 { importpkg = nil } case 11: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:175 + //line go.y:176 { ipkg := importpkg my := importmyname @@ -1263,7 +1264,7 @@ yydefault: } case 12: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:210 + //line go.y:211 { // When an invalid import path is passed to importfile, // it calls Yyerror and then sets up a fake import with @@ -1275,7 +1276,7 @@ yydefault: } case 15: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:226 + //line go.y:227 { // import with original name yyVAL.i = parserline() @@ -1284,7 +1285,7 @@ yydefault: } case 16: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:233 + //line go.y:234 { // import with given name yyVAL.i = parserline() @@ -1293,7 +1294,7 @@ yydefault: } case 17: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:240 + //line go.y:241 { // import into my name space yyVAL.i = parserline() @@ -1302,7 +1303,7 @@ yydefault: } case 18: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:249 + //line go.y:250 { if importpkg.Name == "" { importpkg.Name = yyDollar[2].sym.Name @@ -1319,7 +1320,7 @@ yydefault: } case 20: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:266 + //line go.y:267 { if yyDollar[1].sym.Name == "safe" { curio.importsafe = true @@ -1327,64 +1328,64 @@ yydefault: } case 21: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:273 + //line go.y:274 { defercheckwidth() } case 22: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:277 + //line go.y:278 { resumecheckwidth() unimportfile() } case 23: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:286 + //line go.y:287 { Yyerror("empty top-level declaration") yyVAL.list = nil } case 25: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:292 + //line go.y:293 { yyVAL.list = list1(yyDollar[1].node) } case 26: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:296 + //line go.y:297 { Yyerror("non-declaration statement outside function body") yyVAL.list = nil } case 27: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:301 + //line go.y:302 { yyVAL.list = nil } case 28: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:307 + //line go.y:308 { yyVAL.list = yyDollar[2].list } case 29: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:311 + //line go.y:312 { yyVAL.list = yyDollar[3].list } case 30: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:315 + //line go.y:316 { yyVAL.list = nil } case 31: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:319 + //line go.y:320 { yyVAL.list = yyDollar[2].list iota_ = -100000 @@ -1392,7 +1393,7 @@ yydefault: } case 32: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:325 + //line go.y:326 { yyVAL.list = yyDollar[3].list iota_ = -100000 @@ -1400,7 +1401,7 @@ yydefault: } case 33: yyDollar = yyS[yypt-7 : yypt+1] - //line go.y:331 + //line go.y:332 { yyVAL.list = concat(yyDollar[3].list, yyDollar[5].list) iota_ = -100000 @@ -1408,80 +1409,80 @@ yydefault: } case 34: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:337 + //line go.y:338 { yyVAL.list = nil iota_ = -100000 } case 35: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:342 + //line go.y:343 { yyVAL.list = list1(yyDollar[2].node) } case 36: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:346 + //line go.y:347 { yyVAL.list = yyDollar[3].list } case 37: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:350 + //line go.y:351 { yyVAL.list = nil } case 38: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:356 + //line go.y:357 { iota_ = 0 } case 39: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:362 + //line go.y:363 { yyVAL.list = variter(yyDollar[1].list, yyDollar[2].node, nil) } case 40: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:366 + //line go.y:367 { yyVAL.list = variter(yyDollar[1].list, yyDollar[2].node, yyDollar[4].list) } case 41: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:370 + //line go.y:371 { yyVAL.list = variter(yyDollar[1].list, nil, yyDollar[3].list) } case 42: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:376 + //line go.y:377 { yyVAL.list = constiter(yyDollar[1].list, yyDollar[2].node, yyDollar[4].list) } case 43: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:380 + //line go.y:381 { yyVAL.list = constiter(yyDollar[1].list, nil, yyDollar[3].list) } case 45: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:387 + //line go.y:388 { yyVAL.list = constiter(yyDollar[1].list, yyDollar[2].node, nil) } case 46: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:391 + //line go.y:392 { yyVAL.list = constiter(yyDollar[1].list, nil, nil) } case 47: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:397 + //line go.y:398 { // different from dclname because the name // becomes visible right here, not at the end @@ -1490,13 +1491,13 @@ yydefault: } case 48: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:406 + //line go.y:407 { yyVAL.node = typedcl1(yyDollar[1].node, yyDollar[2].node, true) } case 49: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:412 + //line go.y:413 { yyVAL.node = yyDollar[1].node @@ -1512,14 +1513,14 @@ yydefault: } case 50: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:426 + //line go.y:427 { yyVAL.node = Nod(OASOP, yyDollar[1].node, yyDollar[3].node) yyVAL.node.Etype = uint8(yyDollar[2].i) // rathole to pass opcode } case 51: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:431 + //line go.y:432 { if yyDollar[1].list.Next == nil && yyDollar[3].list.Next == nil { // simple @@ -1533,7 +1534,7 @@ yydefault: } case 52: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:443 + //line go.y:444 { if yyDollar[3].list.N.Op == OTYPESW { yyVAL.node = Nod(OTYPESW, nil, yyDollar[3].list.N.Right) @@ -1553,7 +1554,7 @@ yydefault: } case 53: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:461 + //line go.y:462 { yyVAL.node = Nod(OASOP, yyDollar[1].node, Nodintconst(1)) yyVAL.node.Implicit = true @@ -1561,7 +1562,7 @@ yydefault: } case 54: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:467 + //line go.y:468 { yyVAL.node = Nod(OASOP, yyDollar[1].node, Nodintconst(1)) yyVAL.node.Implicit = true @@ -1569,7 +1570,7 @@ yydefault: } case 55: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:475 + //line go.y:476 { var n, nn *Node @@ -1594,7 +1595,7 @@ yydefault: } case 56: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:498 + //line go.y:499 { var n *Node @@ -1614,7 +1615,7 @@ yydefault: } case 57: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:516 + //line go.y:517 { // will be converted to OCASE // right will point to next case @@ -1625,7 +1626,7 @@ yydefault: } case 58: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:525 + //line go.y:526 { var n, nn *Node @@ -1646,13 +1647,13 @@ yydefault: } case 59: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:546 + //line go.y:547 { markdcl() } case 60: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:550 + //line go.y:551 { if yyDollar[3].list == nil { yyVAL.node = Nod(OEMPTY, nil, nil) @@ -1663,7 +1664,7 @@ yydefault: } case 61: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:561 + //line go.y:562 { // If the last token read by the lexer was consumed // as part of the case, clear it (parser has cleared yychar). @@ -1676,7 +1677,7 @@ yydefault: } case 62: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:572 + //line go.y:573 { // This is the only place in the language where a statement // list is not allowed to drop the final semicolon, because @@ -1696,32 +1697,32 @@ yydefault: } case 63: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:591 + //line go.y:592 { yyVAL.list = nil } case 64: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:595 + //line go.y:596 { yyVAL.list = list(yyDollar[1].list, yyDollar[2].node) } case 65: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:601 + //line go.y:602 { markdcl() } case 66: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:605 + //line go.y:606 { yyVAL.list = yyDollar[3].list popdcl() } case 67: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:612 + //line go.y:613 { yyVAL.node = Nod(ORANGE, nil, yyDollar[4].node) yyVAL.node.List = yyDollar[1].list @@ -1729,7 +1730,7 @@ yydefault: } case 68: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:618 + //line go.y:619 { yyVAL.node = Nod(ORANGE, nil, yyDollar[4].node) yyVAL.node.List = yyDollar[1].list @@ -1738,14 +1739,14 @@ yydefault: } case 69: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:625 + //line go.y:626 { yyVAL.node = Nod(ORANGE, nil, yyDollar[2].node) yyVAL.node.Etype = 0 // := flag } case 70: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:632 + //line go.y:633 { // init ; test ; incr if yyDollar[5].node != nil && yyDollar[5].node.Colas { @@ -1760,7 +1761,7 @@ yydefault: } case 71: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:645 + //line go.y:646 { // normal test yyVAL.node = Nod(OFOR, nil, nil) @@ -1768,27 +1769,27 @@ yydefault: } case 73: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:654 + //line go.y:655 { yyVAL.node = yyDollar[1].node yyVAL.node.Nbody = concat(yyVAL.node.Nbody, yyDollar[2].list) } case 74: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:661 + //line go.y:662 { markdcl() } case 75: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:665 + //line go.y:666 { yyVAL.node = yyDollar[3].node popdcl() } case 76: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:672 + //line go.y:673 { // test yyVAL.node = Nod(OIF, nil, nil) @@ -1796,7 +1797,7 @@ yydefault: } case 77: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:678 + //line go.y:679 { // init ; test yyVAL.node = Nod(OIF, nil, nil) @@ -1807,13 +1808,13 @@ yydefault: } case 78: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:690 + //line go.y:691 { markdcl() } case 79: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:694 + //line go.y:695 { if yyDollar[3].node.Ntest == nil { Yyerror("missing condition in if statement") @@ -1821,13 +1822,13 @@ yydefault: } case 80: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:700 + //line go.y:701 { yyDollar[3].node.Nbody = yyDollar[5].list } case 81: yyDollar = yyS[yypt-8 : yypt+1] - //line go.y:704 + //line go.y:705 { var n *Node var nn *NodeList @@ -1845,13 +1846,13 @@ yydefault: } case 82: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:722 + //line go.y:723 { markdcl() } case 83: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:726 + //line go.y:727 { if yyDollar[4].node.Ntest == nil { Yyerror("missing condition in if statement") @@ -1861,25 +1862,25 @@ yydefault: } case 84: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:735 + //line go.y:736 { yyVAL.list = nil } case 85: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:739 + //line go.y:740 { yyVAL.list = concat(yyDollar[1].list, yyDollar[2].list) } case 86: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:744 + //line go.y:745 { yyVAL.list = nil } case 87: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:748 + //line go.y:749 { l := &NodeList{N: yyDollar[2].node} l.End = l @@ -1887,13 +1888,13 @@ yydefault: } case 88: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:756 + //line go.y:757 { markdcl() } case 89: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:760 + //line go.y:761 { var n *Node n = yyDollar[3].node.Ntest @@ -1904,7 +1905,7 @@ yydefault: } case 90: yyDollar = yyS[yypt-7 : yypt+1] - //line go.y:769 + //line go.y:770 { yyVAL.node = yyDollar[3].node yyVAL.node.Op = OSWITCH @@ -1914,13 +1915,13 @@ yydefault: } case 91: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:779 + //line go.y:780 { typesw = Nod(OXXX, typesw, nil) } case 92: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:783 + //line go.y:784 { yyVAL.node = Nod(OSELECT, nil, nil) yyVAL.node.Lineno = typesw.Lineno @@ -1929,133 +1930,133 @@ yydefault: } case 94: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:796 + //line go.y:797 { yyVAL.node = Nod(OOROR, yyDollar[1].node, yyDollar[3].node) } case 95: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:800 + //line go.y:801 { yyVAL.node = Nod(OANDAND, yyDollar[1].node, yyDollar[3].node) } case 96: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:804 + //line go.y:805 { yyVAL.node = Nod(OEQ, yyDollar[1].node, yyDollar[3].node) } case 97: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:808 + //line go.y:809 { yyVAL.node = Nod(ONE, yyDollar[1].node, yyDollar[3].node) } case 98: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:812 + //line go.y:813 { yyVAL.node = Nod(OLT, yyDollar[1].node, yyDollar[3].node) } case 99: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:816 + //line go.y:817 { yyVAL.node = Nod(OLE, yyDollar[1].node, yyDollar[3].node) } case 100: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:820 + //line go.y:821 { yyVAL.node = Nod(OGE, yyDollar[1].node, yyDollar[3].node) } case 101: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:824 + //line go.y:825 { yyVAL.node = Nod(OGT, yyDollar[1].node, yyDollar[3].node) } case 102: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:828 + //line go.y:829 { yyVAL.node = Nod(OADD, yyDollar[1].node, yyDollar[3].node) } case 103: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:832 + //line go.y:833 { yyVAL.node = Nod(OSUB, yyDollar[1].node, yyDollar[3].node) } case 104: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:836 + //line go.y:837 { yyVAL.node = Nod(OOR, yyDollar[1].node, yyDollar[3].node) } case 105: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:840 + //line go.y:841 { yyVAL.node = Nod(OXOR, yyDollar[1].node, yyDollar[3].node) } case 106: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:844 + //line go.y:845 { yyVAL.node = Nod(OMUL, yyDollar[1].node, yyDollar[3].node) } case 107: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:848 + //line go.y:849 { yyVAL.node = Nod(ODIV, yyDollar[1].node, yyDollar[3].node) } case 108: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:852 + //line go.y:853 { yyVAL.node = Nod(OMOD, yyDollar[1].node, yyDollar[3].node) } case 109: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:856 + //line go.y:857 { yyVAL.node = Nod(OAND, yyDollar[1].node, yyDollar[3].node) } case 110: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:860 + //line go.y:861 { yyVAL.node = Nod(OANDNOT, yyDollar[1].node, yyDollar[3].node) } case 111: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:864 + //line go.y:865 { yyVAL.node = Nod(OLSH, yyDollar[1].node, yyDollar[3].node) } case 112: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:868 + //line go.y:869 { yyVAL.node = Nod(ORSH, yyDollar[1].node, yyDollar[3].node) } case 113: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:873 + //line go.y:874 { yyVAL.node = Nod(OSEND, yyDollar[1].node, yyDollar[3].node) } case 115: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:880 + //line go.y:881 { yyVAL.node = Nod(OIND, yyDollar[2].node, nil) } case 116: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:884 + //line go.y:885 { if yyDollar[2].node.Op == OCOMPLIT { // Special case for &T{...}: turn into (*T){...}. @@ -2068,57 +2069,57 @@ yydefault: } case 117: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:895 + //line go.y:896 { yyVAL.node = Nod(OPLUS, yyDollar[2].node, nil) } case 118: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:899 + //line go.y:900 { yyVAL.node = Nod(OMINUS, yyDollar[2].node, nil) } case 119: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:903 + //line go.y:904 { yyVAL.node = Nod(ONOT, yyDollar[2].node, nil) } case 120: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:907 + //line go.y:908 { Yyerror("the bitwise complement operator is ^") yyVAL.node = Nod(OCOM, yyDollar[2].node, nil) } case 121: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:912 + //line go.y:913 { yyVAL.node = Nod(OCOM, yyDollar[2].node, nil) } case 122: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:916 + //line go.y:917 { yyVAL.node = Nod(ORECV, yyDollar[2].node, nil) } case 123: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:926 + //line go.y:927 { yyVAL.node = Nod(OCALL, yyDollar[1].node, nil) } case 124: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:930 + //line go.y:931 { yyVAL.node = Nod(OCALL, yyDollar[1].node, nil) yyVAL.node.List = yyDollar[3].list } case 125: yyDollar = yyS[yypt-6 : yypt+1] - //line go.y:935 + //line go.y:936 { yyVAL.node = Nod(OCALL, yyDollar[1].node, nil) yyVAL.node.List = yyDollar[3].list @@ -2126,13 +2127,13 @@ yydefault: } case 126: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:943 + //line go.y:944 { yyVAL.node = nodlit(yyDollar[1].val) } case 128: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:948 + //line go.y:949 { if yyDollar[1].node.Op == OPACK { var s *Sym @@ -2145,31 +2146,31 @@ yydefault: } case 129: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:959 + //line go.y:960 { yyVAL.node = Nod(ODOTTYPE, yyDollar[1].node, yyDollar[4].node) } case 130: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:963 + //line go.y:964 { yyVAL.node = Nod(OTYPESW, nil, yyDollar[1].node) } case 131: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:967 + //line go.y:968 { yyVAL.node = Nod(OINDEX, yyDollar[1].node, yyDollar[3].node) } case 132: yyDollar = yyS[yypt-6 : yypt+1] - //line go.y:971 + //line go.y:972 { yyVAL.node = Nod(OSLICE, yyDollar[1].node, Nod(OKEY, yyDollar[3].node, yyDollar[5].node)) } case 133: yyDollar = yyS[yypt-8 : yypt+1] - //line go.y:975 + //line go.y:976 { if yyDollar[5].node == nil { Yyerror("middle index required in 3-index slice") @@ -2181,7 +2182,7 @@ yydefault: } case 135: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:986 + //line go.y:987 { // conversion yyVAL.node = Nod(OCALL, yyDollar[1].node, nil) @@ -2189,7 +2190,7 @@ yydefault: } case 136: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:992 + //line go.y:993 { yyVAL.node = yyDollar[3].node yyVAL.node.Right = yyDollar[1].node @@ -2198,7 +2199,7 @@ yydefault: } case 137: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:999 + //line go.y:1000 { yyVAL.node = yyDollar[3].node yyVAL.node.Right = yyDollar[1].node @@ -2206,7 +2207,7 @@ yydefault: } case 138: yyDollar = yyS[yypt-7 : yypt+1] - //line go.y:1005 + //line go.y:1006 { Yyerror("cannot parenthesize type in composite literal") yyVAL.node = yyDollar[5].node @@ -2215,7 +2216,7 @@ yydefault: } case 140: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1014 + //line go.y:1015 { // composite expression. // make node early so we get the right line number. @@ -2223,13 +2224,13 @@ yydefault: } case 141: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1022 + //line go.y:1023 { yyVAL.node = Nod(OKEY, yyDollar[1].node, yyDollar[3].node) } case 142: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1028 + //line go.y:1029 { // These nodes do not carry line numbers. // Since a composite literal commonly spans several lines, @@ -2244,21 +2245,21 @@ yydefault: } case 143: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1041 + //line go.y:1042 { yyVAL.node = yyDollar[2].node yyVAL.node.List = yyDollar[3].list } case 145: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1049 + //line go.y:1050 { yyVAL.node = yyDollar[2].node yyVAL.node.List = yyDollar[3].list } case 147: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1057 + //line go.y:1058 { yyVAL.node = yyDollar[2].node @@ -2272,19 +2273,19 @@ yydefault: } case 151: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1078 + //line go.y:1079 { yyVAL.i = LBODY } case 152: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1082 + //line go.y:1083 { yyVAL.i = '{' } case 153: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1093 + //line go.y:1094 { if yyDollar[1].sym == nil { yyVAL.node = nil @@ -2294,19 +2295,19 @@ yydefault: } case 154: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1103 + //line go.y:1104 { yyVAL.node = dclname(yyDollar[1].sym) } case 155: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1108 + //line go.y:1109 { yyVAL.node = nil } case 157: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1115 + //line go.y:1116 { yyVAL.sym = yyDollar[1].sym // during imports, unqualified non-exported identifiers are from builtinpkg @@ -2316,13 +2317,13 @@ yydefault: } case 159: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1124 + //line go.y:1125 { yyVAL.sym = nil } case 160: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1130 + //line go.y:1131 { var p *Pkg @@ -2338,7 +2339,7 @@ yydefault: } case 161: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1144 + //line go.y:1145 { var p *Pkg @@ -2354,7 +2355,7 @@ yydefault: } case 162: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1160 + //line go.y:1161 { yyVAL.node = oldname(yyDollar[1].sym) if yyVAL.node.Pack != nil { @@ -2363,38 +2364,38 @@ yydefault: } case 164: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1181 + //line go.y:1182 { Yyerror("final argument in variadic function missing type") yyVAL.node = Nod(ODDD, typenod(typ(TINTER)), nil) } case 165: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1186 + //line go.y:1187 { yyVAL.node = Nod(ODDD, yyDollar[2].node, nil) } case 171: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1197 + //line go.y:1198 { yyVAL.node = yyDollar[2].node } case 175: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1206 + //line go.y:1207 { yyVAL.node = Nod(OIND, yyDollar[2].node, nil) } case 180: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1216 + //line go.y:1217 { yyVAL.node = yyDollar[2].node } case 190: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1237 + //line go.y:1238 { if yyDollar[1].node.Op == OPACK { var s *Sym @@ -2407,53 +2408,53 @@ yydefault: } case 191: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1250 + //line go.y:1251 { yyVAL.node = Nod(OTARRAY, yyDollar[2].node, yyDollar[4].node) } case 192: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1254 + //line go.y:1255 { // array literal of nelem yyVAL.node = Nod(OTARRAY, Nod(ODDD, nil, nil), yyDollar[4].node) } case 193: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1259 + //line go.y:1260 { yyVAL.node = Nod(OTCHAN, yyDollar[2].node, nil) yyVAL.node.Etype = Cboth } case 194: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1264 + //line go.y:1265 { yyVAL.node = Nod(OTCHAN, yyDollar[3].node, nil) yyVAL.node.Etype = Csend } case 195: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:1269 + //line go.y:1270 { yyVAL.node = Nod(OTMAP, yyDollar[3].node, yyDollar[5].node) } case 198: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1277 + //line go.y:1278 { yyVAL.node = Nod(OIND, yyDollar[2].node, nil) } case 199: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1283 + //line go.y:1284 { yyVAL.node = Nod(OTCHAN, yyDollar[3].node, nil) yyVAL.node.Etype = Crecv } case 200: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:1290 + //line go.y:1291 { yyVAL.node = Nod(OTSTRUCT, nil, nil) yyVAL.node.List = yyDollar[3].list @@ -2461,14 +2462,14 @@ yydefault: } case 201: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1296 + //line go.y:1297 { yyVAL.node = Nod(OTSTRUCT, nil, nil) fixlbrace(yyDollar[2].i) } case 202: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:1303 + //line go.y:1304 { yyVAL.node = Nod(OTINTER, nil, nil) yyVAL.node.List = yyDollar[3].list @@ -2476,14 +2477,14 @@ yydefault: } case 203: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1309 + //line go.y:1310 { yyVAL.node = Nod(OTINTER, nil, nil) fixlbrace(yyDollar[2].i) } case 204: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1320 + //line go.y:1321 { yyVAL.node = yyDollar[2].node if yyVAL.node == nil { @@ -2501,7 +2502,7 @@ yydefault: } case 205: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:1338 + //line go.y:1339 { var t *Node @@ -2534,7 +2535,7 @@ yydefault: } case 206: yyDollar = yyS[yypt-8 : yypt+1] - //line go.y:1369 + //line go.y:1370 { var rcvr, t *Node @@ -2572,7 +2573,7 @@ yydefault: } case 207: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:1407 + //line go.y:1408 { var s *Sym var t *Type @@ -2599,7 +2600,7 @@ yydefault: } case 208: yyDollar = yyS[yypt-8 : yypt+1] - //line go.y:1432 + //line go.y:1433 { yyVAL.node = methodname1(newname(yyDollar[4].sym), yyDollar[2].list.N.Right) yyVAL.node.Type = functype(yyDollar[2].list.N, yyDollar[6].list, yyDollar[8].list) @@ -2617,7 +2618,7 @@ yydefault: } case 209: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:1450 + //line go.y:1451 { yyDollar[3].list = checkarglist(yyDollar[3].list, 1) yyVAL.node = Nod(OTFUNC, nil, nil) @@ -2626,13 +2627,13 @@ yydefault: } case 210: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1458 + //line go.y:1459 { yyVAL.list = nil } case 211: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1462 + //line go.y:1463 { yyVAL.list = yyDollar[2].list if yyVAL.list == nil { @@ -2641,51 +2642,51 @@ yydefault: } case 212: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1471 + //line go.y:1472 { yyVAL.list = nil } case 213: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1475 + //line go.y:1476 { yyVAL.list = list1(Nod(ODCLFIELD, nil, yyDollar[1].node)) } case 214: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1479 + //line go.y:1480 { yyDollar[2].list = checkarglist(yyDollar[2].list, 0) yyVAL.list = yyDollar[2].list } case 215: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1486 + //line go.y:1487 { closurehdr(yyDollar[1].node) } case 216: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1492 + //line go.y:1493 { yyVAL.node = closurebody(yyDollar[3].list) fixlbrace(yyDollar[2].i) } case 217: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1497 + //line go.y:1498 { yyVAL.node = closurebody(nil) } case 218: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1508 + //line go.y:1509 { yyVAL.list = nil } case 219: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1512 + //line go.y:1513 { yyVAL.list = concat(yyDollar[1].list, yyDollar[2].list) if nsyntaxerrors == 0 { @@ -2698,49 +2699,49 @@ yydefault: } case 221: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1526 + //line go.y:1527 { yyVAL.list = concat(yyDollar[1].list, yyDollar[3].list) } case 223: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1533 + //line go.y:1534 { yyVAL.list = concat(yyDollar[1].list, yyDollar[3].list) } case 224: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1539 + //line go.y:1540 { yyVAL.list = list1(yyDollar[1].node) } case 225: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1543 + //line go.y:1544 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 227: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1550 + //line go.y:1551 { yyVAL.list = concat(yyDollar[1].list, yyDollar[3].list) } case 228: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1556 + //line go.y:1557 { yyVAL.list = list1(yyDollar[1].node) } case 229: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1560 + //line go.y:1561 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 230: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1566 + //line go.y:1567 { var l *NodeList @@ -2766,14 +2767,14 @@ yydefault: } case 231: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1590 + //line go.y:1591 { yyDollar[1].node.Val = yyDollar[2].val yyVAL.list = list1(yyDollar[1].node) } case 232: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1595 + //line go.y:1596 { yyDollar[2].node.Val = yyDollar[4].val yyVAL.list = list1(yyDollar[2].node) @@ -2781,7 +2782,7 @@ yydefault: } case 233: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1601 + //line go.y:1602 { yyDollar[2].node.Right = Nod(OIND, yyDollar[2].node.Right, nil) yyDollar[2].node.Val = yyDollar[3].val @@ -2789,7 +2790,7 @@ yydefault: } case 234: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:1607 + //line go.y:1608 { yyDollar[3].node.Right = Nod(OIND, yyDollar[3].node.Right, nil) yyDollar[3].node.Val = yyDollar[5].val @@ -2798,7 +2799,7 @@ yydefault: } case 235: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:1614 + //line go.y:1615 { yyDollar[3].node.Right = Nod(OIND, yyDollar[3].node.Right, nil) yyDollar[3].node.Val = yyDollar[5].val @@ -2807,7 +2808,7 @@ yydefault: } case 236: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1623 + //line go.y:1624 { var n *Node @@ -2819,7 +2820,7 @@ yydefault: } case 237: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1633 + //line go.y:1634 { var pkg *Pkg @@ -2834,33 +2835,33 @@ yydefault: } case 238: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1648 + //line go.y:1649 { yyVAL.node = embedded(yyDollar[1].sym, localpkg) } case 239: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1654 + //line go.y:1655 { yyVAL.node = Nod(ODCLFIELD, yyDollar[1].node, yyDollar[2].node) ifacedcl(yyVAL.node) } case 240: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1659 + //line go.y:1660 { yyVAL.node = Nod(ODCLFIELD, nil, oldname(yyDollar[1].sym)) } case 241: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1663 + //line go.y:1664 { yyVAL.node = Nod(ODCLFIELD, nil, oldname(yyDollar[2].sym)) Yyerror("cannot parenthesize embedded type") } case 242: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1670 + //line go.y:1671 { // without func keyword yyDollar[2].list = checkarglist(yyDollar[2].list, 1) @@ -2870,7 +2871,7 @@ yydefault: } case 244: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1684 + //line go.y:1685 { yyVAL.node = Nod(ONONAME, nil, nil) yyVAL.node.Sym = yyDollar[1].sym @@ -2878,7 +2879,7 @@ yydefault: } case 245: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1690 + //line go.y:1691 { yyVAL.node = Nod(ONONAME, nil, nil) yyVAL.node.Sym = yyDollar[1].sym @@ -2886,56 +2887,56 @@ yydefault: } case 247: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1699 + //line go.y:1700 { yyVAL.list = list1(yyDollar[1].node) } case 248: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1703 + //line go.y:1704 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 249: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1708 + //line go.y:1709 { yyVAL.list = nil } case 250: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1712 + //line go.y:1713 { yyVAL.list = yyDollar[1].list } case 251: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1720 + //line go.y:1721 { yyVAL.node = nil } case 253: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1725 + //line go.y:1726 { yyVAL.node = liststmt(yyDollar[1].list) } case 255: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1730 + //line go.y:1731 { yyVAL.node = nil } case 261: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1741 + //line go.y:1742 { yyDollar[1].node = Nod(OLABEL, yyDollar[1].node, nil) yyDollar[1].node.Sym = dclstack // context, for goto restrictions } case 262: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1746 + //line go.y:1747 { var l *NodeList @@ -2948,7 +2949,7 @@ yydefault: } case 263: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1757 + //line go.y:1758 { // will be converted to OFALL yyVAL.node = Nod(OXFALL, nil, nil) @@ -2956,38 +2957,38 @@ yydefault: } case 264: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1763 + //line go.y:1764 { yyVAL.node = Nod(OBREAK, yyDollar[2].node, nil) } case 265: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1767 + //line go.y:1768 { yyVAL.node = Nod(OCONTINUE, yyDollar[2].node, nil) } case 266: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1771 + //line go.y:1772 { yyVAL.node = Nod(OPROC, yyDollar[2].node, nil) } case 267: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1775 + //line go.y:1776 { yyVAL.node = Nod(ODEFER, yyDollar[2].node, nil) } case 268: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1779 + //line go.y:1780 { yyVAL.node = Nod(OGOTO, yyDollar[2].node, nil) yyVAL.node.Sym = dclstack // context, for goto restrictions } case 269: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1784 + //line go.y:1785 { yyVAL.node = Nod(ORETURN, nil, nil) yyVAL.node.List = yyDollar[2].list @@ -3009,7 +3010,7 @@ yydefault: } case 270: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1806 + //line go.y:1807 { yyVAL.list = nil if yyDollar[1].node != nil { @@ -3018,7 +3019,7 @@ yydefault: } case 271: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1813 + //line go.y:1814 { yyVAL.list = yyDollar[1].list if yyDollar[3].node != nil { @@ -3027,163 +3028,163 @@ yydefault: } case 272: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1822 + //line go.y:1823 { yyVAL.list = list1(yyDollar[1].node) } case 273: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1826 + //line go.y:1827 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 274: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1832 + //line go.y:1833 { yyVAL.list = list1(yyDollar[1].node) } case 275: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1836 + //line go.y:1837 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 276: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1842 + //line go.y:1843 { yyVAL.list = list1(yyDollar[1].node) } case 277: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1846 + //line go.y:1847 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 278: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1852 + //line go.y:1853 { yyVAL.list = list1(yyDollar[1].node) } case 279: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1856 + //line go.y:1857 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 280: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1865 + //line go.y:1866 { yyVAL.list = list1(yyDollar[1].node) } case 281: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1869 + //line go.y:1870 { yyVAL.list = list1(yyDollar[1].node) } case 282: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1873 + //line go.y:1874 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 283: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1877 + //line go.y:1878 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 284: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1882 + //line go.y:1883 { yyVAL.list = nil } case 285: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1886 + //line go.y:1887 { yyVAL.list = yyDollar[1].list } case 290: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1900 + //line go.y:1901 { yyVAL.node = nil } case 292: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1906 + //line go.y:1907 { yyVAL.list = nil } case 294: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1912 + //line go.y:1913 { yyVAL.node = nil } case 296: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1918 + //line go.y:1919 { yyVAL.list = nil } case 298: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1924 + //line go.y:1925 { yyVAL.list = nil } case 300: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1930 + //line go.y:1931 { yyVAL.list = nil } case 302: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1936 + //line go.y:1937 { yyVAL.val.Ctype = CTxxx } case 304: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1946 + //line go.y:1947 { importimport(yyDollar[2].sym, yyDollar[3].val.U.Sval) } case 305: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1950 + //line go.y:1951 { importvar(yyDollar[2].sym, yyDollar[3].typ) } case 306: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:1954 + //line go.y:1955 { importconst(yyDollar[2].sym, Types[TIDEAL], yyDollar[4].node) } case 307: yyDollar = yyS[yypt-6 : yypt+1] - //line go.y:1958 + //line go.y:1959 { importconst(yyDollar[2].sym, yyDollar[3].typ, yyDollar[5].node) } case 308: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1962 + //line go.y:1963 { importtype(yyDollar[2].typ, yyDollar[3].typ) } case 309: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1966 + //line go.y:1967 { if yyDollar[2].node == nil { dclcontext = PEXTERN // since we skip the funcbody below @@ -3196,35 +3197,35 @@ yydefault: importlist = list(importlist, yyDollar[2].node) if Debug['E'] > 0 { - print("import [%q] func %lN \n", importpkg.Path, yyDollar[2].node) + fmt.Printf("import [%q] func %v \n", importpkg.Path, yyDollar[2].node) if Debug['m'] > 2 && yyDollar[2].node.Func.Inl != nil { - print("inl body:%+H\n", yyDollar[2].node.Func.Inl) + fmt.Printf("inl body:%v\n", yyDollar[2].node.Func.Inl) } } } case 310: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1987 + //line go.y:1988 { yyVAL.sym = yyDollar[1].sym structpkg = yyVAL.sym.Pkg } case 311: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1994 + //line go.y:1995 { yyVAL.typ = pkgtype(yyDollar[1].sym) importsym(yyDollar[1].sym, OTYPE) } case 317: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:2014 + //line go.y:2015 { yyVAL.typ = pkgtype(yyDollar[1].sym) } case 318: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:2018 + //line go.y:2019 { // predefined name like uint8 yyDollar[1].sym = Pkglookup(yyDollar[1].sym.Name, builtinpkg) @@ -3237,43 +3238,43 @@ yydefault: } case 319: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:2029 + //line go.y:2030 { yyVAL.typ = aindex(nil, yyDollar[3].typ) } case 320: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:2033 + //line go.y:2034 { yyVAL.typ = aindex(nodlit(yyDollar[2].val), yyDollar[4].typ) } case 321: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:2037 + //line go.y:2038 { yyVAL.typ = maptype(yyDollar[3].typ, yyDollar[5].typ) } case 322: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:2041 + //line go.y:2042 { yyVAL.typ = tostruct(yyDollar[3].list) } case 323: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:2045 + //line go.y:2046 { yyVAL.typ = tointerface(yyDollar[3].list) } case 324: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:2049 + //line go.y:2050 { yyVAL.typ = Ptrto(yyDollar[2].typ) } case 325: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:2053 + //line go.y:2054 { yyVAL.typ = typ(TCHAN) yyVAL.typ.Type = yyDollar[2].typ @@ -3281,7 +3282,7 @@ yydefault: } case 326: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:2059 + //line go.y:2060 { yyVAL.typ = typ(TCHAN) yyVAL.typ.Type = yyDollar[3].typ @@ -3289,7 +3290,7 @@ yydefault: } case 327: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:2065 + //line go.y:2066 { yyVAL.typ = typ(TCHAN) yyVAL.typ.Type = yyDollar[3].typ @@ -3297,7 +3298,7 @@ yydefault: } case 328: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:2073 + //line go.y:2074 { yyVAL.typ = typ(TCHAN) yyVAL.typ.Type = yyDollar[3].typ @@ -3305,13 +3306,13 @@ yydefault: } case 329: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:2081 + //line go.y:2082 { yyVAL.typ = functype(nil, yyDollar[3].list, yyDollar[5].list) } case 330: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:2087 + //line go.y:2088 { yyVAL.node = Nod(ODCLFIELD, nil, typenod(yyDollar[2].typ)) if yyDollar[1].sym != nil { @@ -3321,7 +3322,7 @@ yydefault: } case 331: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:2095 + //line go.y:2096 { var t *Type @@ -3338,7 +3339,7 @@ yydefault: } case 332: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:2112 + //line go.y:2113 { var s *Sym var p *Pkg @@ -3362,43 +3363,43 @@ yydefault: } case 333: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:2136 + //line go.y:2137 { yyVAL.node = Nod(ODCLFIELD, newname(yyDollar[1].sym), typenod(functype(fakethis(), yyDollar[3].list, yyDollar[5].list))) } case 334: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:2140 + //line go.y:2141 { yyVAL.node = Nod(ODCLFIELD, nil, typenod(yyDollar[1].typ)) } case 335: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:2145 + //line go.y:2146 { yyVAL.list = nil } case 337: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:2152 + //line go.y:2153 { yyVAL.list = yyDollar[2].list } case 338: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:2156 + //line go.y:2157 { yyVAL.list = list1(Nod(ODCLFIELD, nil, typenod(yyDollar[1].typ))) } case 339: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:2166 + //line go.y:2167 { yyVAL.node = nodlit(yyDollar[1].val) } case 340: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:2170 + //line go.y:2171 { yyVAL.node = nodlit(yyDollar[2].val) switch yyVAL.node.Val.Ctype { @@ -3418,7 +3419,7 @@ yydefault: } case 341: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:2188 + //line go.y:2189 { yyVAL.node = oldname(Pkglookup(yyDollar[1].sym.Name, builtinpkg)) if yyVAL.node.Op != OLITERAL { @@ -3427,7 +3428,7 @@ yydefault: } case 343: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:2198 + //line go.y:2199 { if yyDollar[2].node.Val.Ctype == CTRUNE && yyDollar[4].node.Val.Ctype == CTINT { yyVAL.node = yyDollar[2].node @@ -3440,37 +3441,37 @@ yydefault: } case 346: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:2214 + //line go.y:2215 { yyVAL.list = list1(yyDollar[1].node) } case 347: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:2218 + //line go.y:2219 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 348: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:2224 + //line go.y:2225 { yyVAL.list = list1(yyDollar[1].node) } case 349: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:2228 + //line go.y:2229 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 350: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:2234 + //line go.y:2235 { yyVAL.list = list1(yyDollar[1].node) } case 351: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:2238 + //line go.y:2239 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } diff --git a/src/cmd/internal/gc/y.output b/src/cmd/internal/gc/y.output index e4a5e5c212..f105838a7f 100644 --- a/src/cmd/internal/gc/y.output +++ b/src/cmd/internal/gc/y.output @@ -3,7 +3,7 @@ state 0 $accept: .file $end $$4: . (4) - . reduce 4 (src line 148) + . reduce 4 (src line 149) file goto 1 loadsys goto 2 @@ -21,7 +21,7 @@ state 2 package: . (2) LPACKAGE shift 5 - . reduce 2 (src line 131) + . reduce 2 (src line 132) package goto 4 @@ -37,7 +37,7 @@ state 4 file: loadsys package.imports xdcl_list imports: . (6) - . reduce 6 (src line 165) + . reduce 6 (src line 166) imports goto 8 @@ -56,7 +56,7 @@ state 6 loadsys: $$4 import_package.import_there $$21: . (21) - . reduce 21 (src line 272) + . reduce 21 (src line 273) import_there goto 14 $$21 goto 15 @@ -74,7 +74,7 @@ state 8 xdcl_list: . (218) LIMPORT shift 19 - . reduce 218 (src line 1507) + . reduce 218 (src line 1508) xdcl_list goto 17 import goto 18 @@ -89,19 +89,19 @@ state 9 state 10 sym: LNAME. (157) - . reduce 157 (src line 1113) + . reduce 157 (src line 1114) state 11 sym: hidden_importsym. (158) - . reduce 158 (src line 1122) + . reduce 158 (src line 1123) state 12 sym: '?'. (159) - . reduce 159 (src line 1123) + . reduce 159 (src line 1124) state 13 @@ -115,14 +115,14 @@ state 13 state 14 loadsys: $$4 import_package import_there. (5) - . reduce 5 (src line 159) + . reduce 5 (src line 160) state 15 import_there: $$21.hidden_import_list '$' '$' hidden_import_list: . (344) - . reduce 344 (src line 2209) + . reduce 344 (src line 2210) hidden_import_list goto 22 @@ -131,7 +131,7 @@ state 16 import_safety: . (19) LNAME shift 24 - . reduce 19 (src line 264) + . reduce 19 (src line 265) import_safety goto 23 @@ -140,7 +140,7 @@ state 17 xdcl_list: xdcl_list.xdcl ';' xdcl: . (23) - $end reduce 1 (src line 122) + $end reduce 1 (src line 123) error shift 29 LLITERAL shift 68 LBREAK shift 41 @@ -170,7 +170,7 @@ state 17 '*' shift 58 '&' shift 59 '(' shift 67 - ';' reduce 23 (src line 285) + ';' reduce 23 (src line 286) '!' shift 62 '~' shift 63 '[' shift 77 @@ -236,7 +236,7 @@ state 19 state 20 package: LPACKAGE sym ';'. (3) - . reduce 3 (src line 138) + . reduce 3 (src line 139) state 21 @@ -271,7 +271,7 @@ state 23 state 24 import_safety: LNAME. (20) - . reduce 20 (src line 265) + . reduce 20 (src line 266) state 25 @@ -284,25 +284,25 @@ state 25 state 26 xdcl: common_dcl. (24) - . reduce 24 (src line 290) + . reduce 24 (src line 291) state 27 xdcl: xfndcl. (25) - . reduce 25 (src line 291) + . reduce 25 (src line 292) state 28 xdcl: non_dcl_stmt. (26) - . reduce 26 (src line 295) + . reduce 26 (src line 296) state 29 xdcl: error. (27) - . reduce 27 (src line 300) + . reduce 27 (src line 301) state 30 @@ -373,31 +373,31 @@ state 33 state 34 non_dcl_stmt: simple_stmt. (256) - . reduce 256 (src line 1734) + . reduce 256 (src line 1735) state 35 non_dcl_stmt: for_stmt. (257) - . reduce 257 (src line 1736) + . reduce 257 (src line 1737) state 36 non_dcl_stmt: switch_stmt. (258) - . reduce 258 (src line 1737) + . reduce 258 (src line 1738) state 37 non_dcl_stmt: select_stmt. (259) - . reduce 259 (src line 1738) + . reduce 259 (src line 1739) state 38 non_dcl_stmt: if_stmt. (260) - . reduce 260 (src line 1739) + . reduce 260 (src line 1740) state 39 @@ -410,7 +410,7 @@ state 39 state 40 non_dcl_stmt: LFALL. (263) - . reduce 263 (src line 1756) + . reduce 263 (src line 1757) state 41 @@ -420,7 +420,7 @@ state 41 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 155 (src line 1107) + . reduce 155 (src line 1108) sym goto 119 new_name goto 118 @@ -434,7 +434,7 @@ state 42 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 155 (src line 1107) + . reduce 155 (src line 1108) sym goto 119 new_name goto 118 @@ -538,7 +538,7 @@ state 46 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 292 (src line 1905) + . reduce 292 (src line 1906) sym goto 123 expr goto 129 @@ -562,7 +562,7 @@ state 46 state 47 lconst: LCONST. (38) - . reduce 38 (src line 354) + . reduce 38 (src line 355) state 48 @@ -593,7 +593,7 @@ state 48 expr_list: expr. (276) LASOP shift 130 - LCOLAS reduce 276 (src line 1840) + LCOLAS reduce 276 (src line 1841) LANDAND shift 134 LANDNOT shift 149 LCOMM shift 152 @@ -616,9 +616,9 @@ state 48 '/' shift 146 '%' shift 147 '&' shift 148 - '=' reduce 276 (src line 1840) - ',' reduce 276 (src line 1840) - . reduce 49 (src line 410) + '=' reduce 276 (src line 1841) + ',' reduce 276 (src line 1841) + . reduce 49 (src line 411) state 49 @@ -636,7 +636,7 @@ state 50 for_stmt: LFOR.$$74 for_body $$74: . (74) - . reduce 74 (src line 659) + . reduce 74 (src line 660) $$74 goto 156 @@ -644,7 +644,7 @@ state 51 switch_stmt: LSWITCH.$$88 if_header $$89 LBODY caseblock_list '}' $$88: . (88) - . reduce 88 (src line 754) + . reduce 88 (src line 755) $$88 goto 157 @@ -652,7 +652,7 @@ state 52 select_stmt: LSELECT.$$91 LBODY caseblock_list '}' $$91: . (91) - . reduce 91 (src line 777) + . reduce 91 (src line 778) $$91 goto 158 @@ -660,28 +660,28 @@ state 53 if_stmt: LIF.$$78 if_header $$79 loop_body $$80 elseif_list else $$78: . (78) - . reduce 78 (src line 688) + . reduce 78 (src line 689) $$78 goto 159 state 54 labelname: new_name. (163) - . reduce 163 (src line 1167) + . reduce 163 (src line 1168) state 55 expr: uexpr. (93) - . reduce 93 (src line 793) + . reduce 93 (src line 794) state 56 new_name: sym. (153) name: sym. (162) - ':' reduce 153 (src line 1091) - . reduce 162 (src line 1158) + ':' reduce 153 (src line 1092) + . reduce 162 (src line 1159) state 57 @@ -699,7 +699,7 @@ state 57 '(' shift 160 '.' shift 161 '[' shift 162 - . reduce 114 (src line 877) + . reduce 114 (src line 878) state 58 @@ -1027,7 +1027,7 @@ state 66 pexpr: pexpr_no_paren. (146) '{' shift 171 - . reduce 146 (src line 1054) + . reduce 146 (src line 1055) state 67 @@ -1078,19 +1078,19 @@ state 67 state 68 pexpr_no_paren: LLITERAL. (126) - . reduce 126 (src line 941) + . reduce 126 (src line 942) state 69 pexpr_no_paren: name. (127) - . reduce 127 (src line 946) + . reduce 127 (src line 947) state 70 pexpr_no_paren: pseudocall. (134) - . reduce 134 (src line 984) + . reduce 134 (src line 985) state 71 @@ -1112,23 +1112,23 @@ state 72 state 73 pexpr_no_paren: fnliteral. (139) - . reduce 139 (src line 1011) + . reduce 139 (src line 1012) state 74 convtype: fntype. (181) fnlitdcl: fntype. (215) - '(' reduce 181 (src line 1220) - . reduce 215 (src line 1484) + '(' reduce 181 (src line 1221) + . reduce 215 (src line 1485) state 75 convtype: othertype. (182) comptype: othertype. (183) - '(' reduce 182 (src line 1222) - . reduce 183 (src line 1224) + '(' reduce 182 (src line 1223) + . reduce 183 (src line 1225) state 76 @@ -1167,7 +1167,7 @@ state 77 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 290 (src line 1899) + . reduce 290 (src line 1900) sym goto 123 expr goto 188 @@ -1226,13 +1226,13 @@ state 79 state 80 othertype: structtype. (196) - . reduce 196 (src line 1272) + . reduce 196 (src line 1273) state 81 othertype: interfacetype. (197) - . reduce 197 (src line 1273) + . reduce 197 (src line 1274) state 82 @@ -1258,13 +1258,13 @@ state 83 state 84 imports: imports import ';'. (7) - . reduce 7 (src line 166) + . reduce 7 (src line 167) state 85 import: LIMPORT import_stmt. (8) - . reduce 8 (src line 168) + . reduce 8 (src line 169) state 86 @@ -1291,7 +1291,7 @@ state 87 $$21: . (21) LPACKAGE shift 7 - . reduce 21 (src line 272) + . reduce 21 (src line 273) import_package goto 204 import_there goto 205 @@ -1300,7 +1300,7 @@ state 87 state 88 import_here: LLITERAL. (15) - . reduce 15 (src line 224) + . reduce 15 (src line 225) state 89 @@ -1336,7 +1336,7 @@ state 92 state 93 hidden_import_list: hidden_import_list hidden_import. (345) - . reduce 345 (src line 2210) + . reduce 345 (src line 2211) state 94 @@ -1389,19 +1389,19 @@ state 98 state 99 import_package: LPACKAGE LNAME import_safety ';'. (18) - . reduce 18 (src line 247) + . reduce 18 (src line 248) state 100 xdcl_list: xdcl_list xdcl ';'. (219) - . reduce 219 (src line 1511) + . reduce 219 (src line 1512) state 101 common_dcl: LVAR vardcl. (28) - . reduce 28 (src line 305) + . reduce 28 (src line 306) state 102 @@ -1458,19 +1458,19 @@ state 103 state 104 dcl_name_list: dcl_name. (274) - . reduce 274 (src line 1830) + . reduce 274 (src line 1831) state 105 dcl_name: sym. (154) - . reduce 154 (src line 1101) + . reduce 154 (src line 1102) state 106 common_dcl: lconst constdcl. (31) - . reduce 31 (src line 318) + . reduce 31 (src line 319) state 107 @@ -1526,7 +1526,7 @@ state 108 state 109 common_dcl: LTYPE typedcl. (35) - . reduce 35 (src line 341) + . reduce 35 (src line 342) state 110 @@ -1577,7 +1577,7 @@ state 111 state 112 typedclname: sym. (47) - . reduce 47 (src line 395) + . reduce 47 (src line 396) state 113 @@ -1585,7 +1585,7 @@ state 113 fnbody: . (210) '{' shift 242 - . reduce 210 (src line 1457) + . reduce 210 (src line 1458) fnbody goto 241 @@ -1607,7 +1607,7 @@ state 114 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 249 (src line 1707) + . reduce 249 (src line 1708) sym goto 247 ntype goto 249 @@ -1637,43 +1637,43 @@ state 116 non_dcl_stmt: labelname ':'.$$261 stmt $$261: . (261) - . reduce 261 (src line 1740) + . reduce 261 (src line 1741) $$261 goto 252 state 117 non_dcl_stmt: LBREAK onew_name. (264) - . reduce 264 (src line 1762) + . reduce 264 (src line 1763) state 118 onew_name: new_name. (156) - . reduce 156 (src line 1111) + . reduce 156 (src line 1112) state 119 new_name: sym. (153) - . reduce 153 (src line 1091) + . reduce 153 (src line 1092) state 120 non_dcl_stmt: LCONTINUE onew_name. (265) - . reduce 265 (src line 1766) + . reduce 265 (src line 1767) state 121 pexpr_no_paren: pseudocall. (134) non_dcl_stmt: LGO pseudocall. (266) - '(' reduce 134 (src line 984) - '.' reduce 134 (src line 984) - '{' reduce 134 (src line 984) - '[' reduce 134 (src line 984) - . reduce 266 (src line 1770) + '(' reduce 134 (src line 985) + '.' reduce 134 (src line 985) + '{' reduce 134 (src line 985) + '[' reduce 134 (src line 985) + . reduce 266 (src line 1771) state 122 @@ -1696,7 +1696,7 @@ state 122 state 123 name: sym. (162) - . reduce 162 (src line 1158) + . reduce 162 (src line 1159) state 124 @@ -1710,23 +1710,23 @@ state 125 pexpr_no_paren: pseudocall. (134) non_dcl_stmt: LDEFER pseudocall. (267) - '(' reduce 134 (src line 984) - '.' reduce 134 (src line 984) - '{' reduce 134 (src line 984) - '[' reduce 134 (src line 984) - . reduce 267 (src line 1774) + '(' reduce 134 (src line 985) + '.' reduce 134 (src line 985) + '{' reduce 134 (src line 985) + '[' reduce 134 (src line 985) + . reduce 267 (src line 1775) state 126 non_dcl_stmt: LGOTO new_name. (268) - . reduce 268 (src line 1778) + . reduce 268 (src line 1779) state 127 non_dcl_stmt: LRETURN oexpr_list. (269) - . reduce 269 (src line 1783) + . reduce 269 (src line 1784) state 128 @@ -1734,7 +1734,7 @@ state 128 oexpr_list: expr_list. (293) ',' shift 155 - . reduce 293 (src line 1909) + . reduce 293 (src line 1910) state 129 @@ -1780,7 +1780,7 @@ state 129 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 276 (src line 1840) + . reduce 276 (src line 1841) state 130 @@ -1827,13 +1827,13 @@ state 130 state 131 simple_stmt: expr LINC. (53) - . reduce 53 (src line 460) + . reduce 53 (src line 461) state 132 simple_stmt: expr LDEC. (54) - . reduce 54 (src line 466) + . reduce 54 (src line 467) state 133 @@ -2805,7 +2805,7 @@ state 156 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 294 (src line 1911) + . reduce 294 (src line 1912) sym goto 123 expr goto 48 @@ -2853,7 +2853,7 @@ state 157 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 294 (src line 1911) + . reduce 294 (src line 1912) sym goto 123 expr goto 48 @@ -2906,7 +2906,7 @@ state 159 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 294 (src line 1911) + . reduce 294 (src line 1912) sym goto 123 expr goto 48 @@ -3016,7 +3016,7 @@ state 162 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 290 (src line 1899) + . reduce 290 (src line 1900) sym goto 123 expr goto 294 @@ -3039,56 +3039,56 @@ state 162 state 163 uexpr: '*' uexpr. (115) - . reduce 115 (src line 879) + . reduce 115 (src line 880) state 164 uexpr: '&' uexpr. (116) - . reduce 116 (src line 883) + . reduce 116 (src line 884) state 165 uexpr: '+' uexpr. (117) - . reduce 117 (src line 894) + . reduce 117 (src line 895) state 166 uexpr: '-' uexpr. (118) - . reduce 118 (src line 898) + . reduce 118 (src line 899) state 167 uexpr: '!' uexpr. (119) - . reduce 119 (src line 902) + . reduce 119 (src line 903) state 168 uexpr: '~' uexpr. (120) - . reduce 120 (src line 906) + . reduce 120 (src line 907) state 169 uexpr: '^' uexpr. (121) - . reduce 121 (src line 911) + . reduce 121 (src line 912) state 170 uexpr: LCOMM uexpr. (122) - . reduce 122 (src line 915) + . reduce 122 (src line 916) state 171 pexpr_no_paren: pexpr_no_paren '{'.start_complit braced_keyval_list '}' start_complit: . (140) - . reduce 140 (src line 1013) + . reduce 140 (src line 1014) start_complit goto 296 @@ -3143,19 +3143,19 @@ state 173 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 148 (src line 1069) + . reduce 148 (src line 1070) state 174 expr_or_type: non_expr_type. (149) - . reduce 149 (src line 1071) + . reduce 149 (src line 1072) state 175 non_expr_type: recvchantype. (172) - . reduce 172 (src line 1201) + . reduce 172 (src line 1202) state 176 @@ -3163,11 +3163,11 @@ state 176 convtype: fntype. (181) fnlitdcl: fntype. (215) - error reduce 215 (src line 1484) - LBODY reduce 215 (src line 1484) - '(' reduce 181 (src line 1220) - '{' reduce 215 (src line 1484) - . reduce 173 (src line 1203) + error reduce 215 (src line 1485) + LBODY reduce 215 (src line 1485) + '(' reduce 181 (src line 1221) + '{' reduce 215 (src line 1485) + . reduce 173 (src line 1204) state 177 @@ -3175,10 +3175,10 @@ state 177 convtype: othertype. (182) comptype: othertype. (183) - LBODY reduce 183 (src line 1224) - '(' reduce 182 (src line 1222) - '{' reduce 183 (src line 1224) - . reduce 174 (src line 1204) + LBODY reduce 183 (src line 1225) + '(' reduce 182 (src line 1223) + '{' reduce 183 (src line 1225) + . reduce 174 (src line 1205) state 178 @@ -3310,20 +3310,20 @@ state 181 pexpr_no_paren: comptype lbrace.start_complit braced_keyval_list '}' start_complit: . (140) - . reduce 140 (src line 1013) + . reduce 140 (src line 1014) start_complit goto 301 state 182 lbrace: LBODY. (151) - . reduce 151 (src line 1076) + . reduce 151 (src line 1077) state 183 lbrace: '{'. (152) - . reduce 152 (src line 1081) + . reduce 152 (src line 1082) state 184 @@ -3359,9 +3359,9 @@ state 184 '*' shift 58 '&' shift 59 '(' shift 67 - ';' reduce 251 (src line 1719) + ';' reduce 251 (src line 1720) '{' shift 308 - '}' reduce 251 (src line 1719) + '}' reduce 251 (src line 1720) '!' shift 62 '~' shift 63 '[' shift 77 @@ -3403,7 +3403,7 @@ state 184 state 185 fnliteral: fnlitdcl error. (217) - . reduce 217 (src line 1496) + . reduce 217 (src line 1497) state 186 @@ -3463,13 +3463,13 @@ state 188 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 291 (src line 1903) + . reduce 291 (src line 1904) state 189 othertype: LCHAN non_recvchantype. (193) - . reduce 193 (src line 1258) + . reduce 193 (src line 1259) state 190 @@ -3504,25 +3504,25 @@ state 190 state 191 non_recvchantype: fntype. (176) - . reduce 176 (src line 1210) + . reduce 176 (src line 1211) state 192 non_recvchantype: othertype. (177) - . reduce 177 (src line 1212) + . reduce 177 (src line 1213) state 193 non_recvchantype: ptrtype. (178) - . reduce 178 (src line 1213) + . reduce 178 (src line 1214) state 194 non_recvchantype: dotname. (179) - . reduce 179 (src line 1214) + . reduce 179 (src line 1215) state 195 @@ -3588,7 +3588,7 @@ state 197 dotname: name.'.' sym '.' shift 314 - . reduce 189 (src line 1234) + . reduce 189 (src line 1235) state 198 @@ -3665,27 +3665,27 @@ state 201 osemi: . (286) ';' shift 333 - . reduce 286 (src line 1893) + . reduce 286 (src line 1894) osemi goto 332 state 202 import: LIMPORT '(' ')'. (10) - . reduce 10 (src line 171) + . reduce 10 (src line 172) state 203 import_stmt_list: import_stmt. (13) - . reduce 13 (src line 220) + . reduce 13 (src line 221) state 204 import_stmt: import_here import_package.import_there $$21: . (21) - . reduce 21 (src line 272) + . reduce 21 (src line 273) import_there goto 334 $$21 goto 15 @@ -3693,37 +3693,37 @@ state 204 state 205 import_stmt: import_here import_there. (12) - . reduce 12 (src line 209) + . reduce 12 (src line 210) state 206 import_here: sym LLITERAL. (16) - . reduce 16 (src line 232) + . reduce 16 (src line 233) state 207 import_here: '.' LLITERAL. (17) - . reduce 17 (src line 239) + . reduce 17 (src line 240) state 208 hidden_importsym: '@' LLITERAL '.' LNAME. (160) - . reduce 160 (src line 1128) + . reduce 160 (src line 1129) state 209 hidden_importsym: '@' LLITERAL '.' '?'. (161) - . reduce 161 (src line 1143) + . reduce 161 (src line 1144) state 210 import_there: $$21 hidden_import_list '$' '$'. (22) - . reduce 22 (src line 276) + . reduce 22 (src line 277) state 211 @@ -3757,7 +3757,7 @@ state 212 state 213 hidden_pkg_importsym: hidden_importsym. (310) - . reduce 310 (src line 1985) + . reduce 310 (src line 1986) state 214 @@ -3807,7 +3807,7 @@ state 215 state 216 hidden_pkgtype: hidden_pkg_importsym. (311) - . reduce 311 (src line 1992) + . reduce 311 (src line 1993) state 217 @@ -3815,7 +3815,7 @@ state 217 fnbody: . (210) '{' shift 242 - . reduce 210 (src line 1457) + . reduce 210 (src line 1458) fnbody goto 353 @@ -3845,20 +3845,20 @@ state 220 osemi: . (286) ';' shift 359 - . reduce 286 (src line 1893) + . reduce 286 (src line 1894) osemi goto 358 state 221 common_dcl: LVAR '(' ')'. (30) - . reduce 30 (src line 314) + . reduce 30 (src line 315) state 222 vardcl_list: vardcl. (220) - . reduce 220 (src line 1523) + . reduce 220 (src line 1524) state 223 @@ -3866,7 +3866,7 @@ state 223 vardcl: dcl_name_list ntype.'=' expr_list '=' shift 360 - . reduce 39 (src line 360) + . reduce 39 (src line 361) state 224 @@ -3926,31 +3926,31 @@ state 225 state 226 ntype: recvchantype. (166) - . reduce 166 (src line 1190) + . reduce 166 (src line 1191) state 227 ntype: fntype. (167) - . reduce 167 (src line 1192) + . reduce 167 (src line 1193) state 228 ntype: othertype. (168) - . reduce 168 (src line 1193) + . reduce 168 (src line 1194) state 229 ntype: ptrtype. (169) - . reduce 169 (src line 1194) + . reduce 169 (src line 1195) state 230 ntype: dotname. (170) - . reduce 170 (src line 1195) + . reduce 170 (src line 1196) state 231 @@ -3995,14 +3995,14 @@ state 233 osemi: . (286) ';' shift 366 - . reduce 286 (src line 1893) + . reduce 286 (src line 1894) osemi goto 365 state 234 common_dcl: lconst '(' ')'. (34) - . reduce 34 (src line 336) + . reduce 34 (src line 337) state 235 @@ -4060,32 +4060,32 @@ state 237 osemi: . (286) ';' shift 370 - . reduce 286 (src line 1893) + . reduce 286 (src line 1894) osemi goto 369 state 238 common_dcl: LTYPE '(' ')'. (37) - . reduce 37 (src line 349) + . reduce 37 (src line 350) state 239 typedcl_list: typedcl. (224) - . reduce 224 (src line 1537) + . reduce 224 (src line 1538) state 240 typedcl: typedclname ntype. (48) - . reduce 48 (src line 404) + . reduce 48 (src line 405) state 241 xfndcl: LFUNC fndcl fnbody. (204) - . reduce 204 (src line 1318) + . reduce 204 (src line 1319) state 242 @@ -4121,9 +4121,9 @@ state 242 '*' shift 58 '&' shift 59 '(' shift 67 - ';' reduce 251 (src line 1719) + ';' reduce 251 (src line 1720) '{' shift 308 - '}' reduce 251 (src line 1719) + '}' reduce 251 (src line 1720) '!' shift 62 '~' shift 63 '[' shift 77 @@ -4176,20 +4176,20 @@ state 244 ocomma: . (288) ',' shift 373 - . reduce 288 (src line 1896) + . reduce 288 (src line 1897) ocomma goto 374 state 245 arg_type_list: arg_type. (247) - . reduce 247 (src line 1697) + . reduce 247 (src line 1698) state 246 arg_type: name_or_type. (243) - . reduce 243 (src line 1681) + . reduce 243 (src line 1682) state 247 @@ -4210,7 +4210,7 @@ state 247 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 162 (src line 1158) + . reduce 162 (src line 1159) sym goto 123 ntype goto 249 @@ -4229,13 +4229,13 @@ state 247 state 248 arg_type: dotdotdot. (246) - . reduce 246 (src line 1695) + . reduce 246 (src line 1696) state 249 name_or_type: ntype. (150) - . reduce 150 (src line 1073) + . reduce 150 (src line 1074) state 250 @@ -4254,7 +4254,7 @@ state 250 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 164 (src line 1179) + . reduce 164 (src line 1180) sym goto 123 ntype goto 377 @@ -4285,7 +4285,7 @@ state 251 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 249 (src line 1707) + . reduce 249 (src line 1708) sym goto 247 ntype goto 249 @@ -4311,11 +4311,11 @@ state 252 error shift 307 LLITERAL shift 68 LBREAK shift 41 - LCASE reduce 251 (src line 1719) + LCASE reduce 251 (src line 1720) LCHAN shift 78 LCONST shift 47 LCONTINUE shift 42 - LDEFAULT reduce 251 (src line 1719) + LDEFAULT reduce 251 (src line 1720) LDEFER shift 44 LFALL shift 40 LFOR shift 50 @@ -4339,9 +4339,9 @@ state 252 '*' shift 58 '&' shift 59 '(' shift 67 - ';' reduce 251 (src line 1719) + ';' reduce 251 (src line 1720) '{' shift 308 - '}' reduce 251 (src line 1719) + '}' reduce 251 (src line 1720) '!' shift 62 '~' shift 63 '[' shift 77 @@ -4396,7 +4396,7 @@ state 253 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 249 (src line 1707) + . reduce 249 (src line 1708) sym goto 247 ntype goto 249 @@ -4458,7 +4458,7 @@ state 254 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 50 (src line 425) + . reduce 50 (src line 426) state 255 @@ -4502,7 +4502,7 @@ state 255 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 94 (src line 795) + . reduce 94 (src line 796) state 256 @@ -4545,7 +4545,7 @@ state 256 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 95 (src line 799) + . reduce 95 (src line 800) state 257 @@ -4582,7 +4582,7 @@ state 257 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 96 (src line 803) + . reduce 96 (src line 804) state 258 @@ -4619,7 +4619,7 @@ state 258 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 97 (src line 807) + . reduce 97 (src line 808) state 259 @@ -4656,7 +4656,7 @@ state 259 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 98 (src line 811) + . reduce 98 (src line 812) state 260 @@ -4693,7 +4693,7 @@ state 260 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 99 (src line 815) + . reduce 99 (src line 816) state 261 @@ -4730,7 +4730,7 @@ state 261 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 100 (src line 819) + . reduce 100 (src line 820) state 262 @@ -4767,7 +4767,7 @@ state 262 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 101 (src line 823) + . reduce 101 (src line 824) state 263 @@ -4800,7 +4800,7 @@ state 263 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 102 (src line 827) + . reduce 102 (src line 828) state 264 @@ -4833,7 +4833,7 @@ state 264 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 103 (src line 831) + . reduce 103 (src line 832) state 265 @@ -4866,7 +4866,7 @@ state 265 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 104 (src line 835) + . reduce 104 (src line 836) state 266 @@ -4899,7 +4899,7 @@ state 266 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 105 (src line 839) + . reduce 105 (src line 840) state 267 @@ -4925,7 +4925,7 @@ state 267 expr: expr.LRSH expr expr: expr.LCOMM expr - . reduce 106 (src line 843) + . reduce 106 (src line 844) state 268 @@ -4951,7 +4951,7 @@ state 268 expr: expr.LRSH expr expr: expr.LCOMM expr - . reduce 107 (src line 847) + . reduce 107 (src line 848) state 269 @@ -4977,7 +4977,7 @@ state 269 expr: expr.LRSH expr expr: expr.LCOMM expr - . reduce 108 (src line 851) + . reduce 108 (src line 852) state 270 @@ -5003,7 +5003,7 @@ state 270 expr: expr.LRSH expr expr: expr.LCOMM expr - . reduce 109 (src line 855) + . reduce 109 (src line 856) state 271 @@ -5029,7 +5029,7 @@ state 271 expr: expr.LRSH expr expr: expr.LCOMM expr - . reduce 110 (src line 859) + . reduce 110 (src line 860) state 272 @@ -5055,7 +5055,7 @@ state 272 expr: expr.LRSH expr expr: expr.LCOMM expr - . reduce 111 (src line 863) + . reduce 111 (src line 864) state 273 @@ -5081,7 +5081,7 @@ state 273 expr: expr LRSH expr. (112) expr: expr.LCOMM expr - . reduce 112 (src line 867) + . reduce 112 (src line 868) state 274 @@ -5126,7 +5126,7 @@ state 274 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 113 (src line 872) + . reduce 113 (src line 873) state 275 @@ -5134,7 +5134,7 @@ state 275 expr_list: expr_list.',' expr ',' shift 155 - . reduce 51 (src line 430) + . reduce 51 (src line 431) state 276 @@ -5142,7 +5142,7 @@ state 276 expr_list: expr_list.',' expr ',' shift 155 - . reduce 52 (src line 442) + . reduce 52 (src line 443) state 277 @@ -5188,13 +5188,13 @@ state 277 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 277 (src line 1845) + . reduce 277 (src line 1846) state 278 for_stmt: LFOR $$74 for_body. (75) - . reduce 75 (src line 664) + . reduce 75 (src line 665) state 279 @@ -5210,19 +5210,19 @@ state 280 for_header: osimple_stmt. (71) ';' shift 383 - . reduce 71 (src line 644) + . reduce 71 (src line 645) state 281 for_header: range_stmt. (72) - . reduce 72 (src line 650) + . reduce 72 (src line 651) state 282 osimple_stmt: simple_stmt. (295) - . reduce 295 (src line 1915) + . reduce 295 (src line 1916) state 283 @@ -5283,7 +5283,7 @@ state 285 switch_stmt: LSWITCH $$88 if_header.$$89 LBODY caseblock_list '}' $$89: . (89) - . reduce 89 (src line 759) + . reduce 89 (src line 760) $$89 goto 387 @@ -5292,14 +5292,14 @@ state 286 if_header: osimple_stmt.';' osimple_stmt ';' shift 388 - . reduce 76 (src line 670) + . reduce 76 (src line 671) state 287 select_stmt: LSELECT $$91 LBODY.caseblock_list '}' caseblock_list: . (63) - . reduce 63 (src line 590) + . reduce 63 (src line 591) caseblock_list goto 389 @@ -5307,14 +5307,14 @@ state 288 if_stmt: LIF $$78 if_header.$$79 loop_body $$80 elseif_list else $$79: . (79) - . reduce 79 (src line 693) + . reduce 79 (src line 694) $$79 goto 390 state 289 pseudocall: pexpr '(' ')'. (123) - . reduce 123 (src line 924) + . reduce 123 (src line 925) state 290 @@ -5325,20 +5325,20 @@ state 290 LDDD shift 392 ',' shift 393 - . reduce 288 (src line 1896) + . reduce 288 (src line 1897) ocomma goto 391 state 291 expr_or_type_list: expr_or_type. (278) - . reduce 278 (src line 1850) + . reduce 278 (src line 1851) state 292 pexpr_no_paren: pexpr '.' sym. (128) - . reduce 128 (src line 947) + . reduce 128 (src line 948) state 293 @@ -5432,7 +5432,7 @@ state 294 '%' shift 147 '&' shift 148 ']' shift 396 - . reduce 291 (src line 1903) + . reduce 291 (src line 1904) state 295 @@ -5467,7 +5467,7 @@ state 296 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 284 (src line 1881) + . reduce 284 (src line 1882) sym goto 123 expr goto 402 @@ -5495,13 +5495,13 @@ state 297 pexpr: '(' expr_or_type ')'. (147) '{' shift 404 - . reduce 147 (src line 1056) + . reduce 147 (src line 1057) state 298 non_expr_type: '*' non_expr_type. (175) - . reduce 175 (src line 1205) + . reduce 175 (src line 1206) state 299 @@ -5581,7 +5581,7 @@ state 300 '%' shift 147 '&' shift 148 ',' shift 413 - . reduce 288 (src line 1896) + . reduce 288 (src line 1897) ocomma goto 412 @@ -5609,7 +5609,7 @@ state 301 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 284 (src line 1881) + . reduce 284 (src line 1882) sym goto 123 expr goto 402 @@ -5644,38 +5644,38 @@ state 302 state 303 stmt_list: stmt. (270) - . reduce 270 (src line 1804) + . reduce 270 (src line 1805) state 304 stmt: compound_stmt. (252) - . reduce 252 (src line 1723) + . reduce 252 (src line 1724) state 305 stmt: common_dcl. (253) - . reduce 253 (src line 1724) + . reduce 253 (src line 1725) state 306 stmt: non_dcl_stmt. (254) - . reduce 254 (src line 1728) + . reduce 254 (src line 1729) state 307 stmt: error. (255) - . reduce 255 (src line 1729) + . reduce 255 (src line 1730) state 308 compound_stmt: '{'.$$59 stmt_list '}' $$59: . (59) - . reduce 59 (src line 544) + . reduce 59 (src line 545) $$59 goto 417 @@ -5740,7 +5740,7 @@ state 310 state 311 othertype: LCHAN LCOMM ntype. (194) - . reduce 194 (src line 1263) + . reduce 194 (src line 1264) state 312 @@ -5753,7 +5753,7 @@ state 312 state 313 ptrtype: '*' ntype. (198) - . reduce 198 (src line 1275) + . reduce 198 (src line 1276) state 314 @@ -5780,20 +5780,20 @@ state 316 osemi: . (286) ';' shift 424 - . reduce 286 (src line 1893) + . reduce 286 (src line 1894) osemi goto 423 state 317 structtype: LSTRUCT lbrace '}'. (201) - . reduce 201 (src line 1295) + . reduce 201 (src line 1296) state 318 structdcl_list: structdcl. (226) - . reduce 226 (src line 1547) + . reduce 226 (src line 1548) state 319 @@ -5832,7 +5832,7 @@ state 320 oliteral: . (302) LLITERAL shift 428 - . reduce 302 (src line 1935) + . reduce 302 (src line 1936) oliteral goto 427 @@ -5861,13 +5861,13 @@ state 322 state 323 new_name_list: new_name. (272) - . reduce 272 (src line 1820) + . reduce 272 (src line 1821) state 324 embed: packname. (238) - . reduce 238 (src line 1646) + . reduce 238 (src line 1647) state 325 @@ -5875,11 +5875,11 @@ state 325 packname: LNAME. (236) packname: LNAME.'.' sym - LLITERAL reduce 236 (src line 1621) - ';' reduce 236 (src line 1621) + LLITERAL reduce 236 (src line 1622) + ';' reduce 236 (src line 1622) '.' shift 434 - '}' reduce 236 (src line 1621) - . reduce 157 (src line 1113) + '}' reduce 236 (src line 1622) + . reduce 157 (src line 1114) state 326 @@ -5888,20 +5888,20 @@ state 326 osemi: . (286) ';' shift 436 - . reduce 286 (src line 1893) + . reduce 286 (src line 1894) osemi goto 435 state 327 interfacetype: LINTERFACE lbrace '}'. (203) - . reduce 203 (src line 1308) + . reduce 203 (src line 1309) state 328 interfacedcl_list: interfacedcl. (228) - . reduce 228 (src line 1554) + . reduce 228 (src line 1555) state 329 @@ -5915,7 +5915,7 @@ state 329 state 330 interfacedcl: packname. (240) - . reduce 240 (src line 1658) + . reduce 240 (src line 1659) state 331 @@ -5942,7 +5942,7 @@ state 333 '.' shift 90 '?' shift 12 '@' shift 13 - . reduce 287 (src line 1894) + . reduce 287 (src line 1895) import_here goto 87 sym goto 89 @@ -5952,7 +5952,7 @@ state 333 state 334 import_stmt: import_here import_package import_there. (11) - . reduce 11 (src line 173) + . reduce 11 (src line 174) state 335 @@ -5972,31 +5972,31 @@ state 336 state 337 hidden_type: hidden_type_misc. (312) - . reduce 312 (src line 2003) + . reduce 312 (src line 2004) state 338 hidden_type: hidden_type_recv_chan. (313) - . reduce 313 (src line 2005) + . reduce 313 (src line 2006) state 339 hidden_type: hidden_type_func. (314) - . reduce 314 (src line 2006) + . reduce 314 (src line 2007) state 340 hidden_type_misc: hidden_importsym. (317) - . reduce 317 (src line 2012) + . reduce 317 (src line 2013) state 341 hidden_type_misc: LNAME. (318) - . reduce 318 (src line 2017) + . reduce 318 (src line 2018) state 342 @@ -6131,7 +6131,7 @@ state 354 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 296 (src line 1917) + . reduce 296 (src line 1918) sym goto 357 hidden_importsym goto 11 @@ -6151,7 +6151,7 @@ state 355 state 356 hidden_funarg_list: hidden_funarg. (346) - . reduce 346 (src line 2212) + . reduce 346 (src line 2213) state 357 @@ -6191,7 +6191,7 @@ state 359 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 287 (src line 1894) + . reduce 287 (src line 1895) sym goto 105 dcl_name goto 104 @@ -6246,13 +6246,13 @@ state 361 expr_list: expr_list.',' expr ',' shift 155 - . reduce 41 (src line 369) + . reduce 41 (src line 370) state 362 dcl_name_list: dcl_name_list ',' dcl_name. (275) - . reduce 275 (src line 1835) + . reduce 275 (src line 1836) state 363 @@ -6305,7 +6305,7 @@ state 366 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 287 (src line 1894) + . reduce 287 (src line 1895) sym goto 105 dcl_name goto 104 @@ -6362,7 +6362,7 @@ state 368 expr_list: expr_list.',' expr ',' shift 155 - . reduce 43 (src line 379) + . reduce 43 (src line 380) state 369 @@ -6379,7 +6379,7 @@ state 370 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 287 (src line 1894) + . reduce 287 (src line 1895) sym goto 112 typedclname goto 111 @@ -6412,7 +6412,7 @@ state 372 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 212 (src line 1469) + . reduce 212 (src line 1470) sym goto 485 dotname goto 493 @@ -6444,7 +6444,7 @@ state 373 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 289 (src line 1897) + . reduce 289 (src line 1898) sym goto 247 ntype goto 249 @@ -6464,25 +6464,25 @@ state 373 state 374 oarg_type_list_ocomma: arg_type_list ocomma. (250) - . reduce 250 (src line 1711) + . reduce 250 (src line 1712) state 375 arg_type: sym name_or_type. (244) - . reduce 244 (src line 1683) + . reduce 244 (src line 1684) state 376 arg_type: sym dotdotdot. (245) - . reduce 245 (src line 1689) + . reduce 245 (src line 1690) state 377 dotdotdot: LDDD ntype. (165) - . reduce 165 (src line 1185) + . reduce 165 (src line 1186) state 378 @@ -6495,7 +6495,7 @@ state 378 state 379 non_dcl_stmt: labelname ':' $$261 stmt. (262) - . reduce 262 (src line 1745) + . reduce 262 (src line 1746) state 380 @@ -6508,14 +6508,14 @@ state 380 state 381 for_body: for_header loop_body. (73) - . reduce 73 (src line 652) + . reduce 73 (src line 653) state 382 loop_body: LBODY.$$65 stmt_list '}' $$65: . (65) - . reduce 65 (src line 599) + . reduce 65 (src line 600) $$65 goto 497 @@ -6542,7 +6542,7 @@ state 383 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 294 (src line 1911) + . reduce 294 (src line 1912) sym goto 123 expr goto 48 @@ -6695,7 +6695,7 @@ state 386 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 69 (src line 624) + . reduce 69 (src line 625) state 387 @@ -6728,7 +6728,7 @@ state 388 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 294 (src line 1911) + . reduce 294 (src line 1912) sym goto 123 expr goto 48 @@ -6782,7 +6782,7 @@ state 392 ocomma: . (288) ',' shift 413 - . reduce 288 (src line 1896) + . reduce 288 (src line 1897) ocomma goto 510 @@ -6809,7 +6809,7 @@ state 393 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 289 (src line 1897) + . reduce 289 (src line 1898) sym goto 123 expr goto 173 @@ -6848,7 +6848,7 @@ state 395 state 396 pexpr_no_paren: pexpr '[' expr ']'. (131) - . reduce 131 (src line 966) + . reduce 131 (src line 967) state 397 @@ -6875,7 +6875,7 @@ state 397 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 290 (src line 1899) + . reduce 290 (src line 1900) sym goto 123 expr goto 188 @@ -6909,20 +6909,20 @@ state 399 ocomma: . (288) ',' shift 516 - . reduce 288 (src line 1896) + . reduce 288 (src line 1897) ocomma goto 517 state 400 keyval_list: keyval. (280) - . reduce 280 (src line 1863) + . reduce 280 (src line 1864) state 401 keyval_list: bare_complitexpr. (281) - . reduce 281 (src line 1868) + . reduce 281 (src line 1869) state 402 @@ -6970,14 +6970,14 @@ state 402 '%' shift 147 '&' shift 148 ':' shift 518 - . reduce 142 (src line 1026) + . reduce 142 (src line 1027) state 403 bare_complitexpr: '{'.start_complit braced_keyval_list '}' start_complit: . (140) - . reduce 140 (src line 1013) + . reduce 140 (src line 1014) start_complit goto 519 @@ -6985,7 +6985,7 @@ state 404 pexpr_no_paren: '(' expr_or_type ')' '{'.start_complit braced_keyval_list '}' start_complit: . (140) - . reduce 140 (src line 1013) + . reduce 140 (src line 1014) start_complit goto 520 @@ -7022,47 +7022,47 @@ state 405 state 406 recvchantype: LCOMM LCHAN ntype. (199) - . reduce 199 (src line 1281) + . reduce 199 (src line 1282) state 407 ntype: fntype. (167) non_recvchantype: fntype. (176) - LBODY reduce 176 (src line 1210) - '(' reduce 176 (src line 1210) - '{' reduce 176 (src line 1210) - . reduce 167 (src line 1192) + LBODY reduce 176 (src line 1211) + '(' reduce 176 (src line 1211) + '{' reduce 176 (src line 1211) + . reduce 167 (src line 1193) state 408 ntype: othertype. (168) non_recvchantype: othertype. (177) - LBODY reduce 177 (src line 1212) - '(' reduce 177 (src line 1212) - '{' reduce 177 (src line 1212) - . reduce 168 (src line 1193) + LBODY reduce 177 (src line 1213) + '(' reduce 177 (src line 1213) + '{' reduce 177 (src line 1213) + . reduce 168 (src line 1194) state 409 ntype: ptrtype. (169) non_recvchantype: ptrtype. (178) - LBODY reduce 178 (src line 1213) - '(' reduce 178 (src line 1213) - '{' reduce 178 (src line 1213) - . reduce 169 (src line 1194) + LBODY reduce 178 (src line 1214) + '(' reduce 178 (src line 1214) + '{' reduce 178 (src line 1214) + . reduce 169 (src line 1195) state 410 ntype: dotname. (170) non_recvchantype: dotname. (179) - LBODY reduce 179 (src line 1214) - '(' reduce 179 (src line 1214) - '{' reduce 179 (src line 1214) - . reduce 170 (src line 1195) + LBODY reduce 179 (src line 1215) + '(' reduce 179 (src line 1215) + '{' reduce 179 (src line 1215) + . reduce 170 (src line 1196) state 411 @@ -7105,7 +7105,7 @@ state 412 state 413 ocomma: ','. (289) - . reduce 289 (src line 1897) + . reduce 289 (src line 1898) state 414 @@ -7118,7 +7118,7 @@ state 414 state 415 fnliteral: fnlitdcl lbrace stmt_list '}'. (216) - . reduce 216 (src line 1490) + . reduce 216 (src line 1491) state 416 @@ -7128,11 +7128,11 @@ state 416 error shift 307 LLITERAL shift 68 LBREAK shift 41 - LCASE reduce 251 (src line 1719) + LCASE reduce 251 (src line 1720) LCHAN shift 78 LCONST shift 47 LCONTINUE shift 42 - LDEFAULT reduce 251 (src line 1719) + LDEFAULT reduce 251 (src line 1720) LDEFER shift 44 LFALL shift 40 LFOR shift 50 @@ -7156,9 +7156,9 @@ state 416 '*' shift 58 '&' shift 59 '(' shift 67 - ';' reduce 251 (src line 1719) + ';' reduce 251 (src line 1720) '{' shift 308 - '}' reduce 251 (src line 1719) + '}' reduce 251 (src line 1720) '!' shift 62 '~' shift 63 '[' shift 77 @@ -7229,9 +7229,9 @@ state 417 '*' shift 58 '&' shift 59 '(' shift 67 - ';' reduce 251 (src line 1719) + ';' reduce 251 (src line 1720) '{' shift 308 - '}' reduce 251 (src line 1719) + '}' reduce 251 (src line 1720) '!' shift 62 '~' shift 63 '[' shift 77 @@ -7273,25 +7273,25 @@ state 417 state 418 othertype: '[' oexpr ']' ntype. (191) - . reduce 191 (src line 1248) + . reduce 191 (src line 1249) state 419 othertype: '[' LDDD ']' ntype. (192) - . reduce 192 (src line 1253) + . reduce 192 (src line 1254) state 420 non_recvchantype: '(' ntype ')'. (180) - . reduce 180 (src line 1215) + . reduce 180 (src line 1216) state 421 dotname: name '.' sym. (190) - . reduce 190 (src line 1236) + . reduce 190 (src line 1237) state 422 @@ -7339,7 +7339,7 @@ state 424 '(' shift 321 '?' shift 12 '@' shift 13 - . reduce 287 (src line 1894) + . reduce 287 (src line 1895) sym goto 119 packname goto 324 @@ -7354,7 +7354,7 @@ state 425 oliteral: . (302) LLITERAL shift 428 - . reduce 302 (src line 1935) + . reduce 302 (src line 1936) oliteral goto 529 @@ -7373,13 +7373,13 @@ state 426 state 427 structdcl: embed oliteral. (231) - . reduce 231 (src line 1589) + . reduce 231 (src line 1590) state 428 oliteral: LLITERAL. (303) - . reduce 303 (src line 1939) + . reduce 303 (src line 1940) state 429 @@ -7403,7 +7403,7 @@ state 431 packname: LNAME.'.' sym '.' shift 434 - . reduce 236 (src line 1621) + . reduce 236 (src line 1622) state 432 @@ -7411,7 +7411,7 @@ state 432 oliteral: . (302) LLITERAL shift 428 - . reduce 302 (src line 1935) + . reduce 302 (src line 1936) oliteral goto 533 @@ -7450,7 +7450,7 @@ state 436 '(' shift 331 '?' shift 12 '@' shift 13 - . reduce 287 (src line 1894) + . reduce 287 (src line 1895) sym goto 119 packname goto 330 @@ -7461,7 +7461,7 @@ state 436 state 437 interfacedcl: new_name indcl. (239) - . reduce 239 (src line 1652) + . reduce 239 (src line 1653) state 438 @@ -7481,7 +7481,7 @@ state 438 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 249 (src line 1707) + . reduce 249 (src line 1708) sym goto 247 ntype goto 249 @@ -7510,25 +7510,25 @@ state 439 state 440 import: LIMPORT '(' import_stmt_list osemi ')'. (9) - . reduce 9 (src line 170) + . reduce 9 (src line 171) state 441 import_stmt_list: import_stmt_list ';' import_stmt. (14) - . reduce 14 (src line 222) + . reduce 14 (src line 223) state 442 hidden_import: LIMPORT LNAME LLITERAL ';'. (304) - . reduce 304 (src line 1944) + . reduce 304 (src line 1945) state 443 hidden_import: LVAR hidden_pkg_importsym hidden_type ';'. (305) - . reduce 305 (src line 1949) + . reduce 305 (src line 1950) state 444 @@ -7587,7 +7587,7 @@ state 447 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 298 (src line 1923) + . reduce 298 (src line 1924) sym goto 546 hidden_importsym goto 11 @@ -7610,7 +7610,7 @@ state 448 '[' shift 342 '?' shift 12 '@' shift 13 - . reduce 300 (src line 1929) + . reduce 300 (src line 1930) sym goto 550 hidden_importsym goto 553 @@ -7625,13 +7625,13 @@ state 448 state 449 hidden_type_misc: '*' hidden_type. (324) - . reduce 324 (src line 2048) + . reduce 324 (src line 2049) state 450 hidden_type_misc: LCHAN hidden_type_non_recv_chan. (325) - . reduce 325 (src line 2052) + . reduce 325 (src line 2053) state 451 @@ -7666,13 +7666,13 @@ state 452 state 453 hidden_type_non_recv_chan: hidden_type_misc. (315) - . reduce 315 (src line 2008) + . reduce 315 (src line 2009) state 454 hidden_type_non_recv_chan: hidden_type_func. (316) - . reduce 316 (src line 2010) + . reduce 316 (src line 2011) state 455 @@ -7703,7 +7703,7 @@ state 456 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 296 (src line 1917) + . reduce 296 (src line 1918) sym goto 357 hidden_importsym goto 11 @@ -7721,7 +7721,7 @@ state 457 state 458 hidden_constant: hidden_literal. (342) - . reduce 342 (src line 2195) + . reduce 342 (src line 2196) state 459 @@ -7741,7 +7741,7 @@ state 459 state 460 hidden_literal: LLITERAL. (339) - . reduce 339 (src line 2164) + . reduce 339 (src line 2165) state 461 @@ -7754,7 +7754,7 @@ state 461 state 462 hidden_literal: sym. (341) - . reduce 341 (src line 2187) + . reduce 341 (src line 2188) state 463 @@ -7776,13 +7776,13 @@ state 463 state 464 hidden_import: LTYPE hidden_pkgtype hidden_type ';'. (308) - . reduce 308 (src line 1961) + . reduce 308 (src line 1962) state 465 hidden_import: LFUNC hidden_fndcl fnbody ';'. (309) - . reduce 309 (src line 1965) + . reduce 309 (src line 1966) state 466 @@ -7797,7 +7797,7 @@ state 467 hidden_funarg_list: hidden_funarg_list.',' hidden_funarg ',' shift 469 - . reduce 297 (src line 1921) + . reduce 297 (src line 1922) state 468 @@ -7828,7 +7828,7 @@ state 470 oliteral: . (302) LLITERAL shift 428 - . reduce 302 (src line 1935) + . reduce 302 (src line 1936) oliteral goto 565 @@ -7856,13 +7856,13 @@ state 471 state 472 common_dcl: LVAR '(' vardcl_list osemi ')'. (29) - . reduce 29 (src line 310) + . reduce 29 (src line 311) state 473 vardcl_list: vardcl_list ';' vardcl. (221) - . reduce 221 (src line 1525) + . reduce 221 (src line 1526) state 474 @@ -7870,19 +7870,19 @@ state 474 expr_list: expr_list.',' expr ',' shift 155 - . reduce 40 (src line 365) + . reduce 40 (src line 366) state 475 ntype: '(' ntype ')'. (171) - . reduce 171 (src line 1196) + . reduce 171 (src line 1197) state 476 common_dcl: lconst '(' constdcl osemi ')'. (32) - . reduce 32 (src line 324) + . reduce 32 (src line 325) state 477 @@ -7891,20 +7891,20 @@ state 477 osemi: . (286) ';' shift 568 - . reduce 286 (src line 1893) + . reduce 286 (src line 1894) osemi goto 567 state 478 constdcl_list: constdcl1. (222) - . reduce 222 (src line 1530) + . reduce 222 (src line 1531) state 479 constdcl1: constdcl. (44) - . reduce 44 (src line 384) + . reduce 44 (src line 385) state 480 @@ -7928,7 +7928,7 @@ state 480 '?' shift 12 '@' shift 13 ',' shift 225 - . reduce 46 (src line 390) + . reduce 46 (src line 391) sym goto 123 ntype goto 569 @@ -7947,25 +7947,25 @@ state 481 expr_list: expr_list.',' expr ',' shift 155 - . reduce 42 (src line 374) + . reduce 42 (src line 375) state 482 common_dcl: LTYPE '(' typedcl_list osemi ')'. (36) - . reduce 36 (src line 345) + . reduce 36 (src line 346) state 483 typedcl_list: typedcl_list ';' typedcl. (225) - . reduce 225 (src line 1542) + . reduce 225 (src line 1543) state 484 fnbody: '{' stmt_list '}'. (211) - . reduce 211 (src line 1461) + . reduce 211 (src line 1462) state 485 @@ -7973,19 +7973,19 @@ state 485 fndcl: '(' oarg_type_list_ocomma ')' sym.'(' oarg_type_list_ocomma ')' fnres '(' shift 570 - . reduce 162 (src line 1158) + . reduce 162 (src line 1159) state 486 fntype: LFUNC '(' oarg_type_list_ocomma ')' fnres. (209) - . reduce 209 (src line 1448) + . reduce 209 (src line 1449) state 487 fnres: fnret_type. (213) - . reduce 213 (src line 1474) + . reduce 213 (src line 1475) state 488 @@ -8005,7 +8005,7 @@ state 488 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 249 (src line 1707) + . reduce 249 (src line 1708) sym goto 247 ntype goto 249 @@ -8027,37 +8027,37 @@ state 488 state 489 fnret_type: recvchantype. (184) - . reduce 184 (src line 1227) + . reduce 184 (src line 1228) state 490 fnret_type: fntype. (185) - . reduce 185 (src line 1229) + . reduce 185 (src line 1230) state 491 fnret_type: othertype. (186) - . reduce 186 (src line 1230) + . reduce 186 (src line 1231) state 492 fnret_type: ptrtype. (187) - . reduce 187 (src line 1231) + . reduce 187 (src line 1232) state 493 fnret_type: dotname. (188) - . reduce 188 (src line 1232) + . reduce 188 (src line 1233) state 494 arg_type_list: arg_type_list ',' arg_type. (248) - . reduce 248 (src line 1702) + . reduce 248 (src line 1703) state 495 @@ -8076,7 +8076,7 @@ state 495 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 212 (src line 1469) + . reduce 212 (src line 1470) sym goto 123 dotname goto 493 @@ -8107,7 +8107,7 @@ state 496 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 212 (src line 1469) + . reduce 212 (src line 1470) sym goto 123 dotname goto 493 @@ -8155,9 +8155,9 @@ state 497 '*' shift 58 '&' shift 59 '(' shift 67 - ';' reduce 251 (src line 1719) + ';' reduce 251 (src line 1720) '{' shift 308 - '}' reduce 251 (src line 1719) + '}' reduce 251 (src line 1720) '!' shift 62 '~' shift 63 '[' shift 77 @@ -8289,33 +8289,33 @@ state 501 switch_stmt: LSWITCH $$88 if_header $$89 LBODY.caseblock_list '}' caseblock_list: . (63) - . reduce 63 (src line 590) + . reduce 63 (src line 591) caseblock_list goto 577 state 502 if_header: osimple_stmt ';' osimple_stmt. (77) - . reduce 77 (src line 677) + . reduce 77 (src line 678) state 503 caseblock_list: caseblock_list caseblock. (64) - . reduce 64 (src line 594) + . reduce 64 (src line 595) state 504 select_stmt: LSELECT $$91 LBODY caseblock_list '}'. (92) - . reduce 92 (src line 782) + . reduce 92 (src line 783) state 505 caseblock: case.$$61 stmt_list $$61: . (61) - . reduce 61 (src line 559) + . reduce 61 (src line 560) $$61 goto 578 @@ -8377,14 +8377,14 @@ state 508 if_stmt: LIF $$78 if_header $$79 loop_body.$$80 elseif_list else $$80: . (80) - . reduce 80 (src line 699) + . reduce 80 (src line 700) $$80 goto 581 state 509 pseudocall: pexpr '(' expr_or_type_list ocomma ')'. (124) - . reduce 124 (src line 929) + . reduce 124 (src line 930) state 510 @@ -8397,19 +8397,19 @@ state 510 state 511 expr_or_type_list: expr_or_type_list ',' expr_or_type. (279) - . reduce 279 (src line 1855) + . reduce 279 (src line 1856) state 512 pexpr_no_paren: pexpr '.' '(' expr_or_type ')'. (129) - . reduce 129 (src line 958) + . reduce 129 (src line 959) state 513 pexpr_no_paren: pexpr '.' '(' LTYPE ')'. (130) - . reduce 130 (src line 962) + . reduce 130 (src line 963) state 514 @@ -8424,7 +8424,7 @@ state 514 state 515 pexpr_no_paren: pexpr_no_paren '{' start_complit braced_keyval_list '}'. (137) - . reduce 137 (src line 998) + . reduce 137 (src line 999) state 516 @@ -8452,7 +8452,7 @@ state 516 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 289 (src line 1897) + . reduce 289 (src line 1898) sym goto 123 expr goto 402 @@ -8476,7 +8476,7 @@ state 516 state 517 braced_keyval_list: keyval_list ocomma. (285) - . reduce 285 (src line 1885) + . reduce 285 (src line 1886) state 518 @@ -8546,7 +8546,7 @@ state 519 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 284 (src line 1881) + . reduce 284 (src line 1882) sym goto 123 expr goto 402 @@ -8593,7 +8593,7 @@ state 520 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 284 (src line 1881) + . reduce 284 (src line 1882) sym goto 123 expr goto 402 @@ -8627,19 +8627,19 @@ state 521 state 522 pexpr_no_paren: convtype '(' expr ocomma ')'. (135) - . reduce 135 (src line 985) + . reduce 135 (src line 986) state 523 pexpr_no_paren: comptype lbrace start_complit braced_keyval_list '}'. (136) - . reduce 136 (src line 991) + . reduce 136 (src line 992) state 524 stmt_list: stmt_list ';' stmt. (271) - . reduce 271 (src line 1812) + . reduce 271 (src line 1813) state 525 @@ -8654,31 +8654,31 @@ state 525 state 526 othertype: LMAP '[' ntype ']' ntype. (195) - . reduce 195 (src line 1268) + . reduce 195 (src line 1269) state 527 structtype: LSTRUCT lbrace structdcl_list osemi '}'. (200) - . reduce 200 (src line 1288) + . reduce 200 (src line 1289) state 528 structdcl_list: structdcl_list ';' structdcl. (227) - . reduce 227 (src line 1549) + . reduce 227 (src line 1550) state 529 structdcl: new_name_list ntype oliteral. (230) - . reduce 230 (src line 1564) + . reduce 230 (src line 1565) state 530 new_name_list: new_name_list ',' new_name. (273) - . reduce 273 (src line 1825) + . reduce 273 (src line 1826) state 531 @@ -8686,7 +8686,7 @@ state 531 oliteral: . (302) LLITERAL shift 428 - . reduce 302 (src line 1935) + . reduce 302 (src line 1936) oliteral goto 594 @@ -8700,7 +8700,7 @@ state 532 state 533 structdcl: '*' embed oliteral. (233) - . reduce 233 (src line 1600) + . reduce 233 (src line 1601) state 534 @@ -8713,19 +8713,19 @@ state 534 state 535 packname: LNAME '.' sym. (237) - . reduce 237 (src line 1632) + . reduce 237 (src line 1633) state 536 interfacetype: LINTERFACE lbrace interfacedcl_list osemi '}'. (202) - . reduce 202 (src line 1301) + . reduce 202 (src line 1302) state 537 interfacedcl_list: interfacedcl_list ';' interfacedcl. (229) - . reduce 229 (src line 1559) + . reduce 229 (src line 1560) state 538 @@ -8738,13 +8738,13 @@ state 538 state 539 interfacedcl: '(' packname ')'. (241) - . reduce 241 (src line 1662) + . reduce 241 (src line 1663) state 540 hidden_type_misc: '[' ']' hidden_type. (319) - . reduce 319 (src line 2028) + . reduce 319 (src line 2029) state 541 @@ -8787,13 +8787,13 @@ state 544 hidden_structdcl_list: hidden_structdcl_list.';' hidden_structdcl ';' shift 601 - . reduce 299 (src line 1927) + . reduce 299 (src line 1928) state 545 hidden_structdcl_list: hidden_structdcl. (348) - . reduce 348 (src line 2222) + . reduce 348 (src line 2223) state 546 @@ -8829,13 +8829,13 @@ state 548 hidden_interfacedcl_list: hidden_interfacedcl_list.';' hidden_interfacedcl ';' shift 604 - . reduce 301 (src line 1933) + . reduce 301 (src line 1934) state 549 hidden_interfacedcl_list: hidden_interfacedcl. (350) - . reduce 350 (src line 2232) + . reduce 350 (src line 2233) state 550 @@ -8848,23 +8848,23 @@ state 550 state 551 hidden_interfacedcl: hidden_type. (334) - . reduce 334 (src line 2139) + . reduce 334 (src line 2140) state 552 sym: LNAME. (157) hidden_type_misc: LNAME. (318) - '(' reduce 157 (src line 1113) - . reduce 318 (src line 2017) + '(' reduce 157 (src line 1114) + . reduce 318 (src line 2018) state 553 sym: hidden_importsym. (158) hidden_type_misc: hidden_importsym. (317) - '(' reduce 158 (src line 1122) - . reduce 317 (src line 2012) + '(' reduce 158 (src line 1123) + . reduce 317 (src line 2013) state 554 @@ -8877,13 +8877,13 @@ state 554 state 555 hidden_type_misc: LCHAN LCOMM hidden_type. (327) - . reduce 327 (src line 2064) + . reduce 327 (src line 2065) state 556 hidden_type_recv_chan: LCOMM LCHAN hidden_type. (328) - . reduce 328 (src line 2071) + . reduce 328 (src line 2072) state 557 @@ -8896,7 +8896,7 @@ state 557 state 558 hidden_import: LCONST hidden_pkg_importsym '=' hidden_constant ';'. (306) - . reduce 306 (src line 1953) + . reduce 306 (src line 1954) state 559 @@ -8909,7 +8909,7 @@ state 559 state 560 hidden_literal: '-' LLITERAL. (340) - . reduce 340 (src line 2169) + . reduce 340 (src line 2170) state 561 @@ -8934,7 +8934,7 @@ state 562 '(' shift 612 '[' shift 342 '@' shift 13 - . reduce 335 (src line 2144) + . reduce 335 (src line 2145) hidden_importsym goto 340 hidden_funres goto 611 @@ -8954,13 +8954,13 @@ state 563 state 564 hidden_funarg_list: hidden_funarg_list ',' hidden_funarg. (347) - . reduce 347 (src line 2217) + . reduce 347 (src line 2218) state 565 hidden_funarg: sym hidden_type oliteral. (330) - . reduce 330 (src line 2085) + . reduce 330 (src line 2086) state 566 @@ -8968,7 +8968,7 @@ state 566 oliteral: . (302) LLITERAL shift 428 - . reduce 302 (src line 1935) + . reduce 302 (src line 1936) oliteral goto 615 @@ -8986,7 +8986,7 @@ state 568 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 287 (src line 1894) + . reduce 287 (src line 1895) sym goto 105 dcl_name goto 104 @@ -9000,7 +9000,7 @@ state 569 constdcl1: dcl_name_list ntype. (45) '=' shift 367 - . reduce 45 (src line 386) + . reduce 45 (src line 387) state 570 @@ -9020,7 +9020,7 @@ state 570 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 249 (src line 1707) + . reduce 249 (src line 1708) sym goto 247 ntype goto 249 @@ -9049,7 +9049,7 @@ state 571 state 572 fndcl: sym '(' oarg_type_list_ocomma ')' fnres. (205) - . reduce 205 (src line 1336) + . reduce 205 (src line 1337) state 573 @@ -9084,7 +9084,7 @@ state 574 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 294 (src line 1911) + . reduce 294 (src line 1912) sym goto 123 expr goto 48 @@ -9149,7 +9149,7 @@ state 575 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 67 (src line 610) + . reduce 67 (src line 611) state 576 @@ -9195,7 +9195,7 @@ state 576 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 68 (src line 617) + . reduce 68 (src line 618) state 577 @@ -9217,11 +9217,11 @@ state 578 error shift 307 LLITERAL shift 68 LBREAK shift 41 - LCASE reduce 251 (src line 1719) + LCASE reduce 251 (src line 1720) LCHAN shift 78 LCONST shift 47 LCONTINUE shift 42 - LDEFAULT reduce 251 (src line 1719) + LDEFAULT reduce 251 (src line 1720) LDEFER shift 44 LFALL shift 40 LFOR shift 50 @@ -9245,9 +9245,9 @@ state 578 '*' shift 58 '&' shift 59 '(' shift 67 - ';' reduce 251 (src line 1719) + ';' reduce 251 (src line 1720) '{' shift 308 - '}' reduce 251 (src line 1719) + '}' reduce 251 (src line 1720) '!' shift 62 '~' shift 63 '[' shift 77 @@ -9302,27 +9302,27 @@ state 579 state 580 case: LDEFAULT ':'. (58) - . reduce 58 (src line 524) + . reduce 58 (src line 525) state 581 if_stmt: LIF $$78 if_header $$79 loop_body $$80.elseif_list else elseif_list: . (84) - . reduce 84 (src line 734) + . reduce 84 (src line 735) elseif_list goto 628 state 582 pseudocall: pexpr '(' expr_or_type_list LDDD ocomma ')'. (125) - . reduce 125 (src line 934) + . reduce 125 (src line 935) state 583 pexpr_no_paren: pexpr '[' oexpr ':' oexpr ']'. (132) - . reduce 132 (src line 970) + . reduce 132 (src line 971) state 584 @@ -9348,7 +9348,7 @@ state 584 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 290 (src line 1899) + . reduce 290 (src line 1900) sym goto 123 expr goto 188 @@ -9371,19 +9371,19 @@ state 584 state 585 keyval_list: keyval_list ',' keyval. (282) - . reduce 282 (src line 1872) + . reduce 282 (src line 1873) state 586 keyval_list: keyval_list ',' bare_complitexpr. (283) - . reduce 283 (src line 1876) + . reduce 283 (src line 1877) state 587 keyval: expr ':' complitexpr. (141) - . reduce 141 (src line 1020) + . reduce 141 (src line 1021) state 588 @@ -9429,14 +9429,14 @@ state 588 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 144 (src line 1046) + . reduce 144 (src line 1047) state 589 complitexpr: '{'.start_complit braced_keyval_list '}' start_complit: . (140) - . reduce 140 (src line 1013) + . reduce 140 (src line 1014) start_complit goto 630 @@ -9458,22 +9458,22 @@ state 592 ntype: '(' ntype ')'. (171) non_recvchantype: '(' ntype ')'. (180) - LBODY reduce 180 (src line 1215) - '(' reduce 180 (src line 1215) - '{' reduce 180 (src line 1215) - . reduce 171 (src line 1196) + LBODY reduce 180 (src line 1216) + '(' reduce 180 (src line 1216) + '{' reduce 180 (src line 1216) + . reduce 171 (src line 1197) state 593 compound_stmt: '{' $$59 stmt_list '}'. (60) - . reduce 60 (src line 549) + . reduce 60 (src line 550) state 594 structdcl: '(' embed ')' oliteral. (232) - . reduce 232 (src line 1594) + . reduce 232 (src line 1595) state 595 @@ -9481,7 +9481,7 @@ state 595 oliteral: . (302) LLITERAL shift 428 - . reduce 302 (src line 1935) + . reduce 302 (src line 1936) oliteral goto 633 @@ -9490,7 +9490,7 @@ state 596 oliteral: . (302) LLITERAL shift 428 - . reduce 302 (src line 1935) + . reduce 302 (src line 1936) oliteral goto 634 @@ -9510,7 +9510,7 @@ state 597 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 212 (src line 1469) + . reduce 212 (src line 1470) sym goto 123 dotname goto 493 @@ -9528,7 +9528,7 @@ state 597 state 598 hidden_type_misc: '[' LLITERAL ']' hidden_type. (320) - . reduce 320 (src line 2032) + . reduce 320 (src line 2033) state 599 @@ -9555,7 +9555,7 @@ state 599 state 600 hidden_type_misc: LSTRUCT '{' ohidden_structdcl_list '}'. (322) - . reduce 322 (src line 2040) + . reduce 322 (src line 2041) state 601 @@ -9575,14 +9575,14 @@ state 602 oliteral: . (302) LLITERAL shift 428 - . reduce 302 (src line 1935) + . reduce 302 (src line 1936) oliteral goto 638 state 603 hidden_type_misc: LINTERFACE '{' ohidden_interfacedcl_list '}'. (323) - . reduce 323 (src line 2044) + . reduce 323 (src line 2045) state 604 @@ -9616,7 +9616,7 @@ state 605 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 296 (src line 1917) + . reduce 296 (src line 1918) sym goto 357 hidden_importsym goto 11 @@ -9627,7 +9627,7 @@ state 605 state 606 hidden_type_misc: LCHAN '(' hidden_type_recv_chan ')'. (326) - . reduce 326 (src line 2058) + . reduce 326 (src line 2059) state 607 @@ -9645,7 +9645,7 @@ state 607 '(' shift 612 '[' shift 342 '@' shift 13 - . reduce 335 (src line 2144) + . reduce 335 (src line 2145) hidden_importsym goto 340 hidden_funres goto 611 @@ -9672,19 +9672,19 @@ state 608 state 609 hidden_import: LCONST hidden_pkg_importsym hidden_type '=' hidden_constant ';'. (307) - . reduce 307 (src line 1957) + . reduce 307 (src line 1958) state 610 hidden_fndcl: hidden_pkg_importsym '(' ohidden_funarg_list ')' ohidden_funres. (207) - . reduce 207 (src line 1405) + . reduce 207 (src line 1406) state 611 ohidden_funres: hidden_funres. (336) - . reduce 336 (src line 2148) + . reduce 336 (src line 2149) state 612 @@ -9694,7 +9694,7 @@ state 612 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 296 (src line 1917) + . reduce 296 (src line 1918) sym goto 357 hidden_importsym goto 11 @@ -9705,7 +9705,7 @@ state 612 state 613 hidden_funres: hidden_type. (338) - . reduce 338 (src line 2155) + . reduce 338 (src line 2156) state 614 @@ -9715,7 +9715,7 @@ state 614 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 296 (src line 1917) + . reduce 296 (src line 1918) sym goto 357 hidden_importsym goto 11 @@ -9726,19 +9726,19 @@ state 614 state 615 hidden_funarg: sym LDDD hidden_type oliteral. (331) - . reduce 331 (src line 2094) + . reduce 331 (src line 2095) state 616 common_dcl: lconst '(' constdcl ';' constdcl_list osemi ')'. (33) - . reduce 33 (src line 330) + . reduce 33 (src line 331) state 617 constdcl_list: constdcl_list ';' constdcl1. (223) - . reduce 223 (src line 1532) + . reduce 223 (src line 1533) state 618 @@ -9751,25 +9751,25 @@ state 618 state 619 fnres: '(' oarg_type_list_ocomma ')'. (214) - . reduce 214 (src line 1478) + . reduce 214 (src line 1479) state 620 loop_body: LBODY $$65 stmt_list '}'. (66) - . reduce 66 (src line 604) + . reduce 66 (src line 605) state 621 for_header: osimple_stmt ';' osimple_stmt ';' osimple_stmt. (70) - . reduce 70 (src line 630) + . reduce 70 (src line 631) state 622 switch_stmt: LSWITCH $$88 if_header $$89 LBODY caseblock_list '}'. (90) - . reduce 90 (src line 768) + . reduce 90 (src line 769) state 623 @@ -9777,13 +9777,13 @@ state 623 stmt_list: stmt_list.';' stmt ';' shift 416 - . reduce 62 (src line 571) + . reduce 62 (src line 572) state 624 case: LCASE expr_or_type_list ':'. (55) - . reduce 55 (src line 473) + . reduce 55 (src line 474) state 625 @@ -9918,7 +9918,7 @@ state 628 else: . (86) LELSE shift 650 - . reduce 86 (src line 743) + . reduce 86 (src line 744) elseif goto 649 else goto 648 @@ -9954,7 +9954,7 @@ state 630 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 284 (src line 1881) + . reduce 284 (src line 1882) sym goto 123 expr goto 402 @@ -9980,55 +9980,55 @@ state 630 state 631 bare_complitexpr: '{' start_complit braced_keyval_list '}'. (143) - . reduce 143 (src line 1040) + . reduce 143 (src line 1041) state 632 pexpr_no_paren: '(' expr_or_type ')' '{' start_complit braced_keyval_list '}'. (138) - . reduce 138 (src line 1004) + . reduce 138 (src line 1005) state 633 structdcl: '(' '*' embed ')' oliteral. (234) - . reduce 234 (src line 1606) + . reduce 234 (src line 1607) state 634 structdcl: '*' '(' embed ')' oliteral. (235) - . reduce 235 (src line 1613) + . reduce 235 (src line 1614) state 635 indcl: '(' oarg_type_list_ocomma ')' fnres. (242) - . reduce 242 (src line 1668) + . reduce 242 (src line 1669) state 636 hidden_type_misc: LMAP '[' hidden_type ']' hidden_type. (321) - . reduce 321 (src line 2036) + . reduce 321 (src line 2037) state 637 hidden_structdcl_list: hidden_structdcl_list ';' hidden_structdcl. (349) - . reduce 349 (src line 2227) + . reduce 349 (src line 2228) state 638 hidden_structdcl: sym hidden_type oliteral. (332) - . reduce 332 (src line 2110) + . reduce 332 (src line 2111) state 639 hidden_interfacedcl_list: hidden_interfacedcl_list ';' hidden_interfacedcl. (351) - . reduce 351 (src line 2237) + . reduce 351 (src line 2238) state 640 @@ -10041,7 +10041,7 @@ state 640 state 641 hidden_type_func: LFUNC '(' ohidden_funarg_list ')' ohidden_funres. (329) - . reduce 329 (src line 2079) + . reduce 329 (src line 2080) state 642 @@ -10081,7 +10081,7 @@ state 645 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 212 (src line 1469) + . reduce 212 (src line 1470) sym goto 123 dotname goto 493 @@ -10193,13 +10193,13 @@ state 647 state 648 if_stmt: LIF $$78 if_header $$79 loop_body $$80 elseif_list else. (81) - . reduce 81 (src line 703) + . reduce 81 (src line 704) state 649 elseif_list: elseif_list elseif. (85) - . reduce 85 (src line 738) + . reduce 85 (src line 739) state 650 @@ -10215,7 +10215,7 @@ state 650 state 651 pexpr_no_paren: pexpr '[' oexpr ':' oexpr ':' oexpr ']'. (133) - . reduce 133 (src line 974) + . reduce 133 (src line 975) state 652 @@ -10240,7 +10240,7 @@ state 653 '(' shift 612 '[' shift 342 '@' shift 13 - . reduce 335 (src line 2144) + . reduce 335 (src line 2145) hidden_importsym goto 340 hidden_funres goto 611 @@ -10253,13 +10253,13 @@ state 653 state 654 hidden_constant: '(' hidden_literal '+' hidden_literal ')'. (343) - . reduce 343 (src line 2197) + . reduce 343 (src line 2198) state 655 hidden_funres: '(' ohidden_funarg_list ')'. (337) - . reduce 337 (src line 2150) + . reduce 337 (src line 2151) state 656 @@ -10277,7 +10277,7 @@ state 656 '(' shift 612 '[' shift 342 '@' shift 13 - . reduce 335 (src line 2144) + . reduce 335 (src line 2145) hidden_importsym goto 340 hidden_funres goto 611 @@ -10290,51 +10290,51 @@ state 656 state 657 fndcl: '(' oarg_type_list_ocomma ')' sym '(' oarg_type_list_ocomma ')' fnres. (206) - . reduce 206 (src line 1368) + . reduce 206 (src line 1369) state 658 case: LCASE expr_or_type_list '=' expr ':'. (56) - . reduce 56 (src line 497) + . reduce 56 (src line 498) state 659 case: LCASE expr_or_type_list LCOLAS expr ':'. (57) - . reduce 57 (src line 515) + . reduce 57 (src line 516) state 660 elseif: LELSE LIF.$$82 if_header loop_body $$82: . (82) - . reduce 82 (src line 720) + . reduce 82 (src line 721) $$82 goto 665 state 661 else: LELSE compound_stmt. (87) - . reduce 87 (src line 747) + . reduce 87 (src line 748) state 662 complitexpr: '{' start_complit braced_keyval_list '}'. (145) - . reduce 145 (src line 1048) + . reduce 145 (src line 1049) state 663 hidden_interfacedcl: sym '(' ohidden_funarg_list ')' ohidden_funres. (333) - . reduce 333 (src line 2134) + . reduce 333 (src line 2135) state 664 hidden_fndcl: '(' hidden_funarg_list ')' sym '(' ohidden_funarg_list ')' ohidden_funres. (208) - . reduce 208 (src line 1431) + . reduce 208 (src line 1432) state 665 @@ -10360,7 +10360,7 @@ state 665 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 294 (src line 1911) + . reduce 294 (src line 1912) sym goto 123 expr goto 48 @@ -10394,7 +10394,7 @@ state 666 state 667 elseif: LELSE LIF $$82 if_header loop_body. (83) - . reduce 83 (src line 725) + . reduce 83 (src line 726) 76 terminals, 142 nonterminals From 85a15778005c8412005ef7366cf40b0a50ace5ba Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Wed, 13 May 2015 20:28:05 -0400 Subject: [PATCH 079/232] math/big, cmd/internal/gc/big: fix vet detected printf problem Change-Id: I54425d8cbe0277d7a0c9d66c37f2128a0dfa6441 Reviewed-on: https://go-review.googlesource.com/10041 Run-TryBot: Minux Ma Reviewed-by: Robert Griesemer --- src/cmd/internal/gc/big/float_test.go | 2 +- src/math/big/float_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/internal/gc/big/float_test.go b/src/cmd/internal/gc/big/float_test.go index 2a48ec4465..de79b07aaf 100644 --- a/src/cmd/internal/gc/big/float_test.go +++ b/src/cmd/internal/gc/big/float_test.go @@ -1656,7 +1656,7 @@ func TestFloatCmpSpecialValues(t *testing.T) { want = +1 } if got != want { - t.Errorf("(%g).Cmp(%g) = %s; want %s", x, y, got, want) + t.Errorf("(%g).Cmp(%g) = %v; want %v", x, y, got, want) } } } diff --git a/src/math/big/float_test.go b/src/math/big/float_test.go index 5b5a0247b1..5d241a503b 100644 --- a/src/math/big/float_test.go +++ b/src/math/big/float_test.go @@ -1659,7 +1659,7 @@ func TestFloatCmpSpecialValues(t *testing.T) { want = +1 } if got != want { - t.Errorf("(%g).Cmp(%g) = %s; want %s", x, y, got, want) + t.Errorf("(%g).Cmp(%g) = %v; want %v", x, y, got, want) } } } From b83b01110090c41fc24750ecabf0b87c5fbff233 Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Thu, 14 May 2015 12:26:27 +0900 Subject: [PATCH 080/232] net: fix vet missed format error in test Change-Id: I73c0aeb4b27fec84149c8e89753b27ff2190eabf Reviewed-on: https://go-review.googlesource.com/10074 Reviewed-by: Alex Brainman --- src/net/error_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net/error_test.go b/src/net/error_test.go index c65d3f9d8a..772e0c7f5f 100644 --- a/src/net/error_test.go +++ b/src/net/error_test.go @@ -521,7 +521,7 @@ third: func TestFileError(t *testing.T) { switch runtime.GOOS { case "windows": - t.Skip("not supported on %s", runtime.GOOS) + t.Skipf("not supported on %s", runtime.GOOS) } f, err := ioutil.TempFile("", "go-nettest") From 5b3739357aa409548a4c4f9ac7499726c8de9a23 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 7 May 2015 15:50:54 -0400 Subject: [PATCH 081/232] runtime: skip atomics in heapBitsSetType when GC is not running MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Suggested by Rick during code review of this code, but separated out for easier diagnosis in case it causes problems (and also easier rollback). name old mean new mean delta SetTypePtr 13.9ns × (0.98,1.05) 6.2ns × (0.99,1.01) -55.18% (p=0.000) SetTypePtr8 15.5ns × (0.95,1.10) 15.5ns × (0.99,1.05) ~ (p=0.952) SetTypePtr16 17.8ns × (0.99,1.05) 18.0ns × (1.00,1.00) ~ (p=0.157) SetTypePtr32 25.2ns × (0.99,1.01) 24.3ns × (0.99,1.01) -3.86% (p=0.000) SetTypePtr64 42.2ns × (0.93,1.13) 40.8ns × (0.99,1.01) ~ (p=0.239) SetTypePtr126 67.3ns × (1.00,1.00) 67.5ns × (0.99,1.02) ~ (p=0.365) SetTypePtr128 67.6ns × (1.00,1.01) 70.1ns × (0.97,1.10) ~ (p=0.063) SetTypePtrSlice 575ns × (0.98,1.06) 543ns × (0.95,1.17) -5.54% (p=0.034) SetTypeNode1 12.4ns × (0.98,1.09) 12.8ns × (0.99,1.01) +3.40% (p=0.021) SetTypeNode1Slice 97.1ns × (0.97,1.09) 89.5ns × (1.00,1.00) -7.78% (p=0.000) SetTypeNode8 29.8ns × (1.00,1.01) 17.7ns × (1.00,1.01) -40.74% (p=0.000) SetTypeNode8Slice 204ns × (0.99,1.04) 190ns × (0.97,1.06) -6.96% (p=0.000) SetTypeNode64 42.8ns × (0.99,1.01) 44.0ns × (0.95,1.12) ~ (p=0.163) SetTypeNode64Slice 1.00µs × (0.95,1.09) 0.98µs × (0.96,1.08) ~ (p=0.356) SetTypeNode64Dead 12.2ns × (0.99,1.04) 12.7ns × (1.00,1.01) +4.34% (p=0.000) SetTypeNode64DeadSlice 1.14µs × (0.94,1.11) 0.99µs × (0.99,1.03) -13.74% (p=0.000) SetTypeNode124 67.9ns × (0.99,1.03) 70.4ns × (0.95,1.15) ~ (p=0.115) SetTypeNode124Slice 1.76µs × (0.99,1.04) 1.88µs × (0.91,1.23) ~ (p=0.096) SetTypeNode126 67.7ns × (1.00,1.01) 68.2ns × (0.99,1.02) +0.72% (p=0.014) SetTypeNode126Slice 1.76µs × (1.00,1.01) 1.87µs × (0.93,1.15) +6.15% (p=0.035) SetTypeNode1024 462ns × (0.96,1.10) 451ns × (0.99,1.05) ~ (p=0.224) SetTypeNode1024Slice 14.4µs × (0.95,1.15) 14.2µs × (0.97,1.19) ~ (p=0.676) name old mean new mean delta BinaryTree17 5.87s × (0.98,1.04) 5.87s × (0.98,1.03) ~ (p=0.993) Fannkuch11 4.39s × (0.99,1.01) 4.34s × (1.00,1.01) -1.22% (p=0.000) FmtFprintfEmpty 90.6ns × (0.97,1.06) 89.4ns × (0.97,1.03) ~ (p=0.070) FmtFprintfString 305ns × (0.98,1.02) 296ns × (0.99,1.02) -2.94% (p=0.000) FmtFprintfInt 276ns × (0.97,1.04) 270ns × (0.98,1.03) -2.17% (p=0.001) FmtFprintfIntInt 490ns × (0.97,1.05) 473ns × (0.99,1.02) -3.59% (p=0.000) FmtFprintfPrefixedInt 402ns × (0.99,1.02) 397ns × (0.99,1.01) -1.15% (p=0.000) FmtFprintfFloat 577ns × (0.99,1.01) 549ns × (0.99,1.01) -4.78% (p=0.000) FmtManyArgs 1.89µs × (0.99,1.02) 1.87µs × (0.99,1.01) -1.43% (p=0.000) GobDecode 15.2ms × (0.99,1.01) 14.7ms × (0.99,1.02) -3.55% (p=0.000) GobEncode 11.7ms × (0.98,1.04) 11.5ms × (0.99,1.02) -1.63% (p=0.002) Gzip 647ms × (0.99,1.01) 647ms × (1.00,1.01) ~ (p=0.486) Gunzip 142ms × (1.00,1.00) 143ms × (1.00,1.00) ~ (p=0.234) HTTPClientServer 90.7µs × (0.99,1.01) 90.4µs × (0.98,1.04) ~ (p=0.331) JSONEncode 31.9ms × (0.97,1.06) 31.6ms × (0.98,1.02) ~ (p=0.206) JSONDecode 110ms × (0.99,1.01) 112ms × (0.99,1.02) +1.48% (p=0.000) Mandelbrot200 6.00ms × (1.00,1.00) 6.01ms × (1.00,1.00) ~ (p=0.058) GoParse 6.63ms × (0.98,1.03) 6.61ms × (0.98,1.02) ~ (p=0.353) RegexpMatchEasy0_32 162ns × (0.99,1.01) 161ns × (1.00,1.00) -0.33% (p=0.004) RegexpMatchEasy0_1K 539ns × (0.99,1.01) 540ns × (0.99,1.02) ~ (p=0.222) RegexpMatchEasy1_32 139ns × (0.99,1.01) 140ns × (0.97,1.03) ~ (p=0.054) RegexpMatchEasy1_1K 886ns × (1.00,1.00) 887ns × (1.00,1.00) +0.18% (p=0.001) RegexpMatchMedium_32 252ns × (1.00,1.01) 252ns × (1.00,1.00) +0.21% (p=0.010) RegexpMatchMedium_1K 72.7µs × (1.00,1.01) 72.6µs × (1.00,1.00) ~ (p=0.060) RegexpMatchHard_32 3.84µs × (1.00,1.00) 3.84µs × (1.00,1.00) ~ (p=0.065) RegexpMatchHard_1K 117µs × (1.00,1.00) 117µs × (1.00,1.00) -0.27% (p=0.000) Revcomp 916ms × (0.98,1.04) 909ms × (0.99,1.01) ~ (p=0.054) Template 126ms × (0.99,1.01) 128ms × (0.99,1.02) +1.43% (p=0.000) TimeParse 632ns × (0.99,1.01) 625ns × (1.00,1.01) -1.05% (p=0.000) TimeFormat 655ns × (0.99,1.02) 669ns × (0.99,1.02) +2.01% (p=0.000) Change-Id: I9477b7c9489c6fa98e860c190ce06cd73c53c6a1 Reviewed-on: https://go-review.googlesource.com/9829 Reviewed-by: Rick Hudson Reviewed-by: Austin Clements --- src/runtime/mbitmap.go | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go index 5472d28e02..56e773ad5e 100644 --- a/src/runtime/mbitmap.go +++ b/src/runtime/mbitmap.go @@ -549,11 +549,19 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) { // The bitmap byte is shared with the one-word object // next to it, and concurrent GC might be marking that // object, so we must use an atomic update. + // We can skip this if the GC is completely off. + // Note that there is some marking that happens during + // gcphase == _GCscan, for completely scalar objects, + // so it is not safe to check just for the marking phases. // TODO(rsc): It may make sense to set all the pointer bits // when initializing the span, and then the atomicor8 here // goes away - heapBitsSetType would be a no-op // in that case. - atomicor8(h.bitp, bitPointer< >= 2 nb -= 2 // Note: no bitMarker in hb because the first two words don't get markers from us. - atomicor8(hbitp, uint8(hb)) + if gcphase == _GCoff { + *hbitp |= uint8(hb) + } else { + atomicor8(hbitp, uint8(hb)) + } hbitp = subtractb(hbitp, 1) if w += 2; w >= nw { // We know that there is more data, because we handled 2-word objects above. From 94934f843ee8b0a4a09dc336d4e2b57601b34206 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Sun, 10 May 2015 20:22:32 -0400 Subject: [PATCH 082/232] runtime: rewrite addb/subtractb to be simpler to compile; introduce add1, subtract1 This reduces the depth of the inlining at a particular call site. The inliner introduces many temporary variables, and the compiler can do a better job with fewer. Being verbose in the bodies of these helper functions seems like a reasonable tradeoff: the uses are still just as readable, and they run faster in some important cases. Change-Id: I5323976ed3704d0acd18fb31176cfbf5ba23a89c Reviewed-on: https://go-review.googlesource.com/9883 Reviewed-by: Rick Hudson Reviewed-by: Austin Clements --- src/runtime/mbitmap.go | 66 ++++++++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 21 deletions(-) diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go index 56e773ad5e..db43e482d2 100644 --- a/src/runtime/mbitmap.go +++ b/src/runtime/mbitmap.go @@ -83,13 +83,37 @@ const ( // addb returns the byte pointer p+n. //go:nowritebarrier func addb(p *byte, n uintptr) *byte { - return (*byte)(add(unsafe.Pointer(p), n)) + // Note: wrote out full expression instead of calling add(p, n) + // to reduce the number of temporaries generated by the + // compiler for this trivial expression during inlining. + return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + n)) } // subtractb returns the byte pointer p-n. //go:nowritebarrier func subtractb(p *byte, n uintptr) *byte { - return (*byte)(add(unsafe.Pointer(p), -n)) + // Note: wrote out full expression instead of calling add(p, -n) + // to reduce the number of temporaries generated by the + // compiler for this trivial expression during inlining. + return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) - n)) +} + +// add1 returns the byte pointer p+1. +//go:nowritebarrier +func add1(p *byte) *byte { + // Note: wrote out full expression instead of calling addb(p, 1) + // to reduce the number of temporaries generated by the + // compiler for this trivial expression during inlining. + return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + 1)) +} + +// subtract1 returns the byte pointer p-1. +//go:nowritebarrier +func subtract1(p *byte) *byte { + // Note: wrote out full expression instead of calling subtractb(p, 1) + // to reduce the number of temporaries generated by the + // compiler for this trivial expression during inlining. + return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) - 1)) } // mHeap_MapBits is called each time arena_used is extended. @@ -220,7 +244,7 @@ func (h heapBits) next() heapBits { if h.shift < 3*heapBitsShift { return heapBits{h.bitp, h.shift + heapBitsShift} } - return heapBits{subtractb(h.bitp, 1), 0} + return heapBits{subtract1(h.bitp), 0} } // forward returns the heapBits describing n pointer-sized words ahead of h in memory. @@ -291,7 +315,7 @@ func (h heapBits) hasPointers(size uintptr) bool { if h.shift == 0 { return b&(bitMarked<<(2*heapBitsShift)) != 0 } - return uint32(*subtractb(h.bitp, 1))&bitMarked != 0 + return uint32(*subtract1(h.bitp))&bitMarked != 0 } // isCheckmarked reports whether the heap bits have the checkmarked bit set. @@ -378,7 +402,7 @@ func (h heapBits) initCheckmarkSpan(size, n, total uintptr) { bitp := h.bitp for i := uintptr(0); i < n; i += 4 { *bitp &^= bitPointerAll - bitp = subtractb(bitp, 1) + bitp = subtract1(bitp) } return } @@ -402,7 +426,7 @@ func (h heapBits) clearCheckmarkSpan(size, n, total uintptr) { bitp := h.bitp for i := uintptr(0); i < n; i += 4 { *bitp |= bitPointerAll - bitp = subtractb(bitp, 1) + bitp = subtract1(bitp) } } } @@ -449,7 +473,7 @@ func heapBitsSweepSpan(base, size, n uintptr, f func(uintptr)) { f(base + (i+3)*ptrSize) } *bitp = uint8(x) - bitp = subtractb(bitp, 1) + bitp = subtract1(bitp) } case size%(4*ptrSize) == 0: @@ -499,7 +523,7 @@ func heapBitsSweepSpan(base, size, n uintptr, f func(uintptr)) { x &^= (bitMarked|bitPointer)<<(2*heapBitsShift) | (bitMarked|bitPointer)<<(3*heapBitsShift) f(base + (i+1)*size) if size > 2*ptrSize { - *subtractb(bitp, 1) = 0 + *subtract1(bitp) = 0 } } *bitp = uint8(x) @@ -590,7 +614,7 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) { unrollgcprog_m(typ) }) } - ptrmask = addb(ptrmask, 1) // skip the unroll flag byte + ptrmask = add1(ptrmask) // skip the unroll flag byte } // Heap bitmap bits for 2-word object are only 4 bits, @@ -687,7 +711,7 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) { nb = typ.ptrdata / ptrSize for i := uintptr(0); i < nb; i += 8 { b |= uintptr(*p) << i - p = addb(p, 1) + p = add1(p) } nb = typ.size / ptrSize @@ -724,7 +748,7 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) { } if p != nil { b = uintptr(*p) - p = addb(p, 1) + p = add1(p) nb = 8 } @@ -776,7 +800,7 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) { goto Phase3 } *hbitp = uint8(hb) - hbitp = subtractb(hbitp, 1) + hbitp = subtract1(hbitp) b >>= 4 nb -= 4 @@ -800,7 +824,7 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) { } else { atomicor8(hbitp, uint8(hb)) } - hbitp = subtractb(hbitp, 1) + hbitp = subtract1(hbitp) if w += 2; w >= nw { // We know that there is more data, because we handled 2-word objects above. // This must be at least a 6-word object. If we're out of pointer words, @@ -830,7 +854,7 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) { break } *hbitp = uint8(hb) - hbitp = subtractb(hbitp, 1) + hbitp = subtract1(hbitp) b >>= 4 // Load more bits. b has nb right now. @@ -840,7 +864,7 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) { // and the next iteration will consume 8 bits, // leaving us with the same nb the next time we're here. b |= uintptr(*p) << nb - p = addb(p, 1) + p = add1(p) } else if p == nil { // Almost as fast path: track bit count and refill from pbits. // For short repetitions. @@ -856,7 +880,7 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) { nb += endnb if nb < 8 { b |= uintptr(*ptrmask) << nb - p = addb(ptrmask, 1) + p = add1(ptrmask) } else { nb -= 8 p = ptrmask @@ -870,7 +894,7 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) { break } *hbitp = uint8(hb) - hbitp = subtractb(hbitp, 1) + hbitp = subtract1(hbitp) b >>= 4 } @@ -891,11 +915,11 @@ Phase3: // The first is hb, the rest are zero. if w <= nw { *hbitp = uint8(hb) - hbitp = subtractb(hbitp, 1) + hbitp = subtract1(hbitp) hb = 0 // for possible final half-byte below for w += 4; w <= nw; w += 4 { *hbitp = 0 - hbitp = subtractb(hbitp, 1) + hbitp = subtract1(hbitp) } } @@ -1021,9 +1045,9 @@ func unrollgcprog1(maskp *byte, prog *byte, ppos *uintptr, inplace bool) *byte { throw("unrollgcprog: unknown instruction") case insData: - prog = addb(prog, 1) + prog = add1(prog) siz := int(*prog) - prog = addb(prog, 1) + prog = add1(prog) p := (*[1 << 30]byte)(unsafe.Pointer(prog)) for i := 0; i < siz; i++ { v := p[i/8] >> (uint(i) % 8) & 1 From ecfe42cab0c22da35aed6752cafaf0d3c7bb44d4 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Sun, 10 May 2015 13:43:51 -0400 Subject: [PATCH 083/232] runtime: keep pointer bits set always in 1-word spans MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's dumb to clear them in initSpan, set them in heapBitsSetType, clear them in heapBitsSweepSpan, set them again in heapBitsSetType, clear them again in heapBitsSweepSpan, and so on. Set them in initSpan and be done with it (until the span is reused for objects of a different size). This avoids an atomic operation in a common case (one-word allocation). Suggested by rlh. name old mean new mean delta BinaryTree17 5.87s × (0.97,1.03) 5.93s × (0.98,1.04) ~ (p=0.056) Fannkuch11 4.34s × (1.00,1.01) 4.41s × (1.00,1.00) +1.42% (p=0.000) FmtFprintfEmpty 86.1ns × (0.98,1.03) 88.9ns × (0.95,1.14) ~ (p=0.066) FmtFprintfString 292ns × (0.97,1.04) 284ns × (0.98,1.03) -2.64% (p=0.000) FmtFprintfInt 271ns × (0.98,1.06) 274ns × (0.98,1.05) ~ (p=0.148) FmtFprintfIntInt 478ns × (0.98,1.05) 487ns × (0.98,1.03) +1.85% (p=0.004) FmtFprintfPrefixedInt 397ns × (0.98,1.05) 394ns × (0.98,1.02) ~ (p=0.184) FmtFprintfFloat 553ns × (0.99,1.02) 543ns × (0.99,1.01) -1.71% (p=0.000) FmtManyArgs 1.90µs × (0.98,1.05) 1.88µs × (0.99,1.01) -0.97% (p=0.037) GobDecode 15.1ms × (0.99,1.01) 15.3ms × (0.99,1.01) +0.78% (p=0.001) GobEncode 11.7ms × (0.98,1.05) 11.6ms × (0.99,1.02) -1.39% (p=0.009) Gzip 646ms × (1.00,1.01) 647ms × (1.00,1.01) ~ (p=0.120) Gunzip 142ms × (1.00,1.00) 142ms × (1.00,1.00) ~ (p=0.068) HTTPClientServer 89.7µs × (0.99,1.01) 90.1µs × (0.98,1.03) ~ (p=0.224) JSONEncode 31.3ms × (0.99,1.01) 31.2ms × (0.99,1.02) ~ (p=0.149) JSONDecode 113ms × (0.99,1.01) 111ms × (0.99,1.01) -1.25% (p=0.000) Mandelbrot200 6.01ms × (1.00,1.00) 6.01ms × (1.00,1.00) +0.09% (p=0.015) GoParse 6.63ms × (0.98,1.03) 6.55ms × (0.99,1.02) -1.10% (p=0.006) RegexpMatchEasy0_32 161ns × (1.00,1.00) 161ns × (1.00,1.00) (sample has zero variance) RegexpMatchEasy0_1K 539ns × (0.99,1.01) 563ns × (0.99,1.01) +4.51% (p=0.000) RegexpMatchEasy1_32 140ns × (0.99,1.01) 141ns × (0.99,1.01) +1.34% (p=0.000) RegexpMatchEasy1_1K 886ns × (1.00,1.01) 888ns × (1.00,1.00) +0.20% (p=0.003) RegexpMatchMedium_32 252ns × (1.00,1.02) 255ns × (0.99,1.01) +1.32% (p=0.000) RegexpMatchMedium_1K 72.7µs × (1.00,1.00) 72.6µs × (1.00,1.00) ~ (p=0.296) RegexpMatchHard_32 3.84µs × (1.00,1.01) 3.84µs × (1.00,1.00) ~ (p=0.339) RegexpMatchHard_1K 117µs × (1.00,1.01) 117µs × (1.00,1.00) -0.28% (p=0.022) Revcomp 914ms × (0.99,1.01) 909ms × (0.99,1.01) -0.49% (p=0.031) Template 128ms × (0.99,1.01) 127ms × (0.99,1.01) -1.10% (p=0.000) TimeParse 628ns × (0.99,1.01) 639ns × (0.99,1.01) +1.69% (p=0.000) TimeFormat 660ns × (0.99,1.01) 662ns × (0.99,1.02) ~ (p=0.287) Change-Id: I3127b0ab89708267c74aa7d0eae1db1a1bcdfda5 Reviewed-on: https://go-review.googlesource.com/9884 Reviewed-by: Austin Clements --- src/runtime/mbitmap.go | 49 +++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go index db43e482d2..2d2abca643 100644 --- a/src/runtime/mbitmap.go +++ b/src/runtime/mbitmap.go @@ -387,6 +387,18 @@ func (h heapBits) initSpan(size, n, total uintptr) { throw("initSpan: unaligned length") } nbyte := total / heapBitmapScale + if ptrSize == 8 && size == ptrSize { + end := h.bitp + bitp := subtractb(end, nbyte-1) + for { + *bitp = bitPointerAll + if bitp == end { + break + } + bitp = add1(bitp) + } + return + } memclr(unsafe.Pointer(subtractb(h.bitp, nbyte-1)), nbyte) } @@ -443,33 +455,34 @@ func heapBitsSweepSpan(base, size, n uintptr, f func(uintptr)) { switch { default: throw("heapBitsSweepSpan") - case size == ptrSize: + case ptrSize == 8 && size == ptrSize: // Consider mark bits in all four 2-bit entries of each bitmap byte. bitp := h.bitp for i := uintptr(0); i < n; i += 4 { x := uint32(*bitp) + // Note that unlike the other size cases, we leave the pointer bits set here. + // These are initialized during initSpan when the span is created and left + // in place the whole time the span is used for pointer-sized objects. + // That lets heapBitsSetType avoid an atomic update to set the pointer bit + // during allocation. if x&bitMarked != 0 { x &^= bitMarked } else { - x &^= bitPointer f(base + i*ptrSize) } if x&(bitMarked< Date: Wed, 13 May 2015 12:59:33 -0700 Subject: [PATCH 084/232] text/template: need to validate type when an argument is a function call Missed a case; just need to call validateType. Fixes #10800. Change-Id: I81997ca7a9feb1be31c8b47e631b32712d7ffb86 Reviewed-on: https://go-review.googlesource.com/10031 Reviewed-by: Andrew Gerrand --- src/text/template/exec.go | 2 +- src/text/template/exec_test.go | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/text/template/exec.go b/src/text/template/exec.go index e6e1287993..ebafb4b5dc 100644 --- a/src/text/template/exec.go +++ b/src/text/template/exec.go @@ -660,7 +660,7 @@ func (s *state) evalArg(dot reflect.Value, typ reflect.Type, n parse.Node) refle case *parse.PipeNode: return s.validateType(s.evalPipeline(dot, arg), typ) case *parse.IdentifierNode: - return s.evalFunction(dot, arg, arg, nil, zero) + return s.validateType(s.evalFunction(dot, arg, arg, nil, zero), typ) case *parse.ChainNode: return s.validateType(s.evalChainNode(dot, arg, nil, zero), typ) } diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go index abce27ff3d..0f1ad62380 100644 --- a/src/text/template/exec_test.go +++ b/src/text/template/exec_test.go @@ -531,6 +531,8 @@ var execTests = []execTest{ {"bug14a", "{{(nil).True}}", "", tVal, false}, {"bug14b", "{{$x := nil}}{{$x.anything}}", "", tVal, false}, {"bug14c", `{{$x := (1.0)}}{{$y := ("hello")}}{{$x.anything}}{{$y.true}}`, "", tVal, false}, + // Didn't call validateType on function results. Issue 10800. + {"bug15", "{{valueString returnInt}}", "", tVal, false}, } func zeroArgs() string { @@ -570,6 +572,11 @@ func valueString(v string) string { return "value is ignored" } +// returnInt returns an int +func returnInt() int { + return 7 +} + func add(args ...int) int { sum := 0 for _, x := range args { @@ -611,6 +618,7 @@ func testExecute(execTests []execTest, template *Template, t *testing.T) { "makemap": makemap, "mapOfThree": mapOfThree, "oneArg": oneArg, + "returnInt": returnInt, "stringer": stringer, "typeOf": typeOf, "valueString": valueString, From d2130573e871dc7437b14713c2a7107a20bb0390 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 14 May 2015 11:20:08 -0700 Subject: [PATCH 085/232] go/scanner: don't return previous comment as literal value if none is expected Fixes #10213. Change-Id: Ia587dd51eea702058da926717ad305792c9fc42b Reviewed-on: https://go-review.googlesource.com/10081 Reviewed-by: Alan Donovan --- src/go/scanner/scanner.go | 3 ++- src/go/scanner/scanner_test.go | 35 ++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/go/scanner/scanner.go b/src/go/scanner/scanner.go index cec82ea10e..e9476c4dee 100644 --- a/src/go/scanner/scanner.go +++ b/src/go/scanner/scanner.go @@ -706,13 +706,14 @@ scanAgain: s.insertSemi = false // newline consumed return pos, token.SEMICOLON, "\n" } - lit = s.scanComment() + comment := s.scanComment() if s.mode&ScanComments == 0 { // skip comment s.insertSemi = false // newline consumed goto scanAgain } tok = token.COMMENT + lit = comment } else { tok = s.switch2(token.QUO, token.QUO_ASSIGN) } diff --git a/src/go/scanner/scanner_test.go b/src/go/scanner/scanner_test.go index fc450d8a6e..0d21905166 100644 --- a/src/go/scanner/scanner_test.go +++ b/src/go/scanner/scanner_test.go @@ -734,6 +734,41 @@ func TestScanErrors(t *testing.T) { } } +// Verify that no comments show up as literal values when skipping comments. +func TestIssue10213(t *testing.T) { + var src = ` + var ( + A = 1 // foo + ) + + var ( + B = 2 + // foo + ) + + var C = 3 // foo + + var D = 4 + // foo + + func anycode() { + // foo + } + ` + var s Scanner + s.Init(fset.AddFile("", fset.Base(), len(src)), []byte(src), nil, 0) + for { + pos, tok, lit := s.Scan() + class := tokenclass(tok) + if lit != "" && class != keyword && class != literal && tok != token.SEMICOLON { + t.Errorf("%s: tok = %s, lit = %q", fset.Position(pos), tok, lit) + } + if tok <= token.EOF { + break + } + } +} + func BenchmarkScan(b *testing.B) { b.StopTimer() fset := token.NewFileSet() From 138498183cb53382c115fc761cbf2898fb72eac8 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 14 May 2015 11:36:19 -0700 Subject: [PATCH 086/232] go/types: remove _ imports that are not needed anymore Change-Id: I392b0a0083d6bea80a65f9eef46dd06b02a70e1b Reviewed-on: https://go-review.googlesource.com/10082 Reviewed-by: Alan Donovan --- src/go/types/eval_test.go | 1 - src/go/types/self_test.go | 1 - 2 files changed, 2 deletions(-) diff --git a/src/go/types/eval_test.go b/src/go/types/eval_test.go index bc27a8bb23..36e1cb954e 100644 --- a/src/go/types/eval_test.go +++ b/src/go/types/eval_test.go @@ -14,7 +14,6 @@ import ( "strings" "testing" - _ "go/internal/gcimporter" . "go/types" ) diff --git a/src/go/types/self_test.go b/src/go/types/self_test.go index e52c5afdc8..4ff4e4d4a8 100644 --- a/src/go/types/self_test.go +++ b/src/go/types/self_test.go @@ -15,7 +15,6 @@ import ( "testing" "time" - _ "go/internal/gcimporter" . "go/types" ) From 30aacd4ce2d3ecd802aa281d54267608ca35a34c Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 14 May 2015 14:23:12 -0400 Subject: [PATCH 087/232] runtime: add Node128, Node130 benchmarks Change-Id: I815a7ceeea48cc652b3c8568967665af39b02834 Reviewed-on: https://go-review.googlesource.com/10045 Reviewed-by: Brad Fitzpatrick --- src/runtime/gc_test.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/runtime/gc_test.go b/src/runtime/gc_test.go index f049bad499..e3e0c3a583 100644 --- a/src/runtime/gc_test.go +++ b/src/runtime/gc_test.go @@ -308,6 +308,32 @@ func BenchmarkSetTypeNode126Slice(b *testing.B) { benchSetType(b, make([]Node126, 32)) } +type Node128 struct { + Value [128]uintptr + Left, Right *byte +} + +func BenchmarkSetTypeNode128(b *testing.B) { + benchSetType(b, new(Node128)) +} + +func BenchmarkSetTypeNode128Slice(b *testing.B) { + benchSetType(b, make([]Node128, 32)) +} + +type Node130 struct { + Value [130]uintptr + Left, Right *byte +} + +func BenchmarkSetTypeNode130(b *testing.B) { + benchSetType(b, new(Node130)) +} + +func BenchmarkSetTypeNode130Slice(b *testing.B) { + benchSetType(b, make([]Node130, 32)) +} + type Node1024 struct { Value [1024]uintptr Left, Right *byte From 1e7f57954baf8fa991e4551504856897f438f490 Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Thu, 14 May 2015 00:58:06 -0400 Subject: [PATCH 088/232] go/build: introduce go1.5 build tag Change-Id: Iab2f8e1c4443f39b79c1c63a7a30062074b48764 Signed-off-by: Shenghou Ma Reviewed-on: https://go-review.googlesource.com/10042 Reviewed-by: Brad Fitzpatrick --- src/go/build/build.go | 6 +----- src/go/build/doc.go | 1 + 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/go/build/build.go b/src/go/build/build.go index d91eb0b24d..820434bc4a 100644 --- a/src/go/build/build.go +++ b/src/go/build/build.go @@ -296,11 +296,7 @@ func defaultContext() Context { // in all releases >= Go 1.x. Code that requires Go 1.x or later should // say "+build go1.x", and code that should only be built before Go 1.x // (perhaps it is the stub to use in that case) should say "+build !go1.x". - // - // When we reach Go 1.5 the line will read - // c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4", "go1.5"} - // and so on. - c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4"} + c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4", "go1.5"} switch os.Getenv("CGO_ENABLED") { case "1": diff --git a/src/go/build/doc.go b/src/go/build/doc.go index 78e17b220a..233f8b989d 100644 --- a/src/go/build/doc.go +++ b/src/go/build/doc.go @@ -101,6 +101,7 @@ // - "go1.2", from Go version 1.2 onward // - "go1.3", from Go version 1.3 onward // - "go1.4", from Go version 1.4 onward +// - "go1.5", from Go version 1.5 onward // - any additional words listed in ctxt.BuildTags // // If a file's name, after stripping the extension and a possible _test suffix, From a901d7fb8f3126f5fbaf3be097449769b490503a Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Thu, 14 May 2015 13:03:02 -0700 Subject: [PATCH 089/232] cmd/dist: support test filtering via repurposed env variable, negation For upcoming sharded ARM builders. Updates #10029 Change-Id: I3b1df9560be697c514a8ced0462814d406e23132 Reviewed-on: https://go-review.googlesource.com/10055 Reviewed-by: Ian Lance Taylor Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/cmd/dist/test.go | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index 848790ad2c..addf61dad9 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -14,6 +14,7 @@ import ( "os/exec" "path/filepath" "regexp" + "runtime" "strconv" "strings" "time" @@ -24,7 +25,9 @@ func cmdtest() { flag.BoolVar(&t.listMode, "list", false, "list available tests") flag.BoolVar(&t.noRebuild, "no-rebuild", false, "don't rebuild std and cmd packages") flag.StringVar(&t.banner, "banner", "##### ", "banner prefix; blank means no section banners") - flag.StringVar(&t.runRxStr, "run", "", "run only those tests matching the regular expression; empty means to run all") + flag.StringVar(&t.runRxStr, "run", os.Getenv("GOTESTONLY"), + "run only those tests matching the regular expression; empty means to run all. "+ + "Special exception: if the string begins with '!', the match is inverted.") xflagparse(0) t.run() } @@ -35,6 +38,7 @@ type tester struct { noRebuild bool runRxStr string runRx *regexp.Regexp + runRxWant bool banner string // prefix, or "" for none goroot string @@ -129,6 +133,19 @@ func (t *tester) run() { } if t.runRxStr != "" { + // Temporary (2015-05-14) special case for "std", + // which the plan9 builder was using for ages. Delete + // this once we update dashboard/builders.go to use a + // regexp instead. + if runtime.GOOS == "plan9" && t.runRxStr == "std" { + t.runRxStr = "^go_test:" + } + if t.runRxStr[0] == '!' { + t.runRxWant = false + t.runRxStr = t.runRxStr[1:] + } else { + t.runRxWant = true + } t.runRx = regexp.MustCompile(t.runRxStr) } @@ -147,7 +164,7 @@ func (t *tester) run() { var lastHeading string for _, dt := range t.tests { - if t.runRx != nil && !t.runRx.MatchString(dt.name) { + if t.runRx != nil && (t.runRx.MatchString(dt.name) != t.runRxWant) { t.partial = true continue } @@ -214,13 +231,6 @@ func (t *tester) registerTests() { }) } - // Old hack for when Plan 9 on GCE was too slow. - // We're keeping this until test sharding (Issue 10029) is finished, though. - if os.Getenv("GOTESTONLY") == "std" { - t.partial = true - return - } - // Runtime CPU tests. testName := "runtime:cpu124" t.tests = append(t.tests, distTest{ From a4292c31206f798a3a4a8498006f4a055f581860 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 14 May 2015 16:21:01 -0400 Subject: [PATCH 090/232] api: refresh next.txt Change-Id: I5e902bb3a3a51620b21840783087ed3cc410dbc5 Reviewed-on: https://go-review.googlesource.com/10048 Reviewed-by: Brad Fitzpatrick --- api/next.txt | 172 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 130 insertions(+), 42 deletions(-) diff --git a/api/next.txt b/api/next.txt index cebbe877b6..b8e09df5c2 100644 --- a/api/next.txt +++ b/api/next.txt @@ -1,6 +1,7 @@ pkg archive/zip, method (*Writer) SetOffset(int64) pkg bufio, method (*Reader) Discard(int) (int, error) pkg bufio, method (ReadWriter) Discard(int) (int, error) +pkg bytes, func LastIndexByte([]uint8, uint8) int pkg bytes, method (*Buffer) Cap() int pkg bytes, method (*Reader) Size() int64 pkg crypto, type Decrypter interface { Decrypt, Public } @@ -18,16 +19,56 @@ pkg crypto/tls, const TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 49196 pkg crypto/tls, const TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16 pkg crypto/tls, const TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 49200 pkg crypto/tls, const TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16 +pkg crypto/tls, method (*Config) SetSessionTicketKeys([][32]uint8) +pkg crypto/tls, type Certificate struct, SignedCertificateTimestamps [][]uint8 +pkg crypto/tls, type ConnectionState struct, OCSPResponse []uint8 +pkg crypto/tls, type ConnectionState struct, SignedCertificateTimestamps [][]uint8 +pkg crypto/x509, method (*CertificateRequest) CheckSignature() error +pkg crypto/x509, type Certificate struct, UnhandledCriticalExtensions []asn1.ObjectIdentifier pkg crypto/x509/pkix, type Name struct, ExtraNames []AttributeTypeAndValue pkg database/sql, method (*DB) Stats() DBStats pkg database/sql, type DBStats struct pkg database/sql, type DBStats struct, OpenConnections int +pkg debug/dwarf, const ClassAddress = 1 +pkg debug/dwarf, const ClassAddress Class +pkg debug/dwarf, const ClassBlock = 2 +pkg debug/dwarf, const ClassBlock Class +pkg debug/dwarf, const ClassConstant = 3 +pkg debug/dwarf, const ClassConstant Class +pkg debug/dwarf, const ClassExprLoc = 4 +pkg debug/dwarf, const ClassExprLoc Class +pkg debug/dwarf, const ClassFlag = 5 +pkg debug/dwarf, const ClassFlag Class +pkg debug/dwarf, const ClassLinePtr = 6 +pkg debug/dwarf, const ClassLinePtr Class +pkg debug/dwarf, const ClassLocListPtr = 7 +pkg debug/dwarf, const ClassLocListPtr Class +pkg debug/dwarf, const ClassMacPtr = 8 +pkg debug/dwarf, const ClassMacPtr Class +pkg debug/dwarf, const ClassRangeListPtr = 9 +pkg debug/dwarf, const ClassRangeListPtr Class +pkg debug/dwarf, const ClassReference = 10 +pkg debug/dwarf, const ClassReference Class +pkg debug/dwarf, const ClassReferenceAlt = 13 +pkg debug/dwarf, const ClassReferenceAlt Class +pkg debug/dwarf, const ClassReferenceSig = 11 +pkg debug/dwarf, const ClassReferenceSig Class +pkg debug/dwarf, const ClassString = 12 +pkg debug/dwarf, const ClassString Class +pkg debug/dwarf, const ClassStringAlt = 14 +pkg debug/dwarf, const ClassStringAlt Class pkg debug/dwarf, method (*Data) LineReader(*Entry) (*LineReader, error) +pkg debug/dwarf, method (*Entry) AttrField(Attr) *Field pkg debug/dwarf, method (*LineReader) Next(*LineEntry) error pkg debug/dwarf, method (*LineReader) Reset() pkg debug/dwarf, method (*LineReader) Seek(LineReaderPos) pkg debug/dwarf, method (*LineReader) SeekPC(uint64, *LineEntry) error pkg debug/dwarf, method (*LineReader) Tell() LineReaderPos +pkg debug/dwarf, method (*Reader) AddressSize() int +pkg debug/dwarf, method (Class) GoString() string +pkg debug/dwarf, method (Class) String() string +pkg debug/dwarf, type Class int +pkg debug/dwarf, type Field struct, Class Class pkg debug/dwarf, type LineEntry struct pkg debug/dwarf, type LineEntry struct, Address uint64 pkg debug/dwarf, type LineEntry struct, BasicBlock bool @@ -227,48 +268,52 @@ pkg encoding/base64, var RawURLEncoding *Encoding pkg encoding/json, type UnmarshalTypeError struct, Offset int64 pkg flag, func UnquoteUsage(*Flag) (string, string) pkg go/ast, type EmptyStmt struct, Implicit bool -pkg go/exact, const Bool = 1 -pkg go/exact, const Bool Kind -pkg go/exact, const Complex = 5 -pkg go/exact, const Complex Kind -pkg go/exact, const Float = 4 -pkg go/exact, const Float Kind -pkg go/exact, const Int = 3 -pkg go/exact, const Int Kind -pkg go/exact, const String = 2 -pkg go/exact, const String Kind -pkg go/exact, const Unknown = 0 -pkg go/exact, const Unknown Kind -pkg go/exact, func BinaryOp(Value, token.Token, Value) Value -pkg go/exact, func BitLen(Value) int -pkg go/exact, func BoolVal(Value) bool -pkg go/exact, func Bytes(Value) []uint8 -pkg go/exact, func Compare(Value, token.Token, Value) bool -pkg go/exact, func Denom(Value) Value -pkg go/exact, func Float32Val(Value) (float32, bool) -pkg go/exact, func Float64Val(Value) (float64, bool) -pkg go/exact, func Imag(Value) Value -pkg go/exact, func Int64Val(Value) (int64, bool) -pkg go/exact, func MakeBool(bool) Value -pkg go/exact, func MakeFloat64(float64) Value -pkg go/exact, func MakeFromBytes([]uint8) Value -pkg go/exact, func MakeFromLiteral(string, token.Token) Value -pkg go/exact, func MakeImag(Value) Value -pkg go/exact, func MakeInt64(int64) Value -pkg go/exact, func MakeString(string) Value -pkg go/exact, func MakeUint64(uint64) Value -pkg go/exact, func MakeUnknown() Value -pkg go/exact, func Num(Value) Value -pkg go/exact, func Real(Value) Value -pkg go/exact, func Shift(Value, token.Token, uint) Value -pkg go/exact, func Sign(Value) int -pkg go/exact, func StringVal(Value) string -pkg go/exact, func Uint64Val(Value) (uint64, bool) -pkg go/exact, func UnaryOp(token.Token, Value, int) Value -pkg go/exact, type Kind int -pkg go/exact, type Value interface, Kind() Kind -pkg go/exact, type Value interface, String() string -pkg go/exact, type Value interface, unexported methods +pkg go/build, type Package struct, PkgTargetRoot string +pkg go/constant, const Bool = 1 +pkg go/constant, const Bool Kind +pkg go/constant, const Complex = 5 +pkg go/constant, const Complex Kind +pkg go/constant, const Float = 4 +pkg go/constant, const Float Kind +pkg go/constant, const Int = 3 +pkg go/constant, const Int Kind +pkg go/constant, const String = 2 +pkg go/constant, const String Kind +pkg go/constant, const Unknown = 0 +pkg go/constant, const Unknown Kind +pkg go/constant, func BinaryOp(Value, token.Token, Value) Value +pkg go/constant, func BitLen(Value) int +pkg go/constant, func BoolVal(Value) bool +pkg go/constant, func Bytes(Value) []uint8 +pkg go/constant, func Compare(Value, token.Token, Value) bool +pkg go/constant, func Denom(Value) Value +pkg go/constant, func Float32Val(Value) (float32, bool) +pkg go/constant, func Float64Val(Value) (float64, bool) +pkg go/constant, func Imag(Value) Value +pkg go/constant, func Int64Val(Value) (int64, bool) +pkg go/constant, func MakeBool(bool) Value +pkg go/constant, func MakeFloat64(float64) Value +pkg go/constant, func MakeFromBytes([]uint8) Value +pkg go/constant, func MakeFromLiteral(string, token.Token, uint) Value +pkg go/constant, func MakeImag(Value) Value +pkg go/constant, func MakeInt64(int64) Value +pkg go/constant, func MakeString(string) Value +pkg go/constant, func MakeUint64(uint64) Value +pkg go/constant, func MakeUnknown() Value +pkg go/constant, func Num(Value) Value +pkg go/constant, func Real(Value) Value +pkg go/constant, func Shift(Value, token.Token, uint) Value +pkg go/constant, func Sign(Value) int +pkg go/constant, func StringVal(Value) string +pkg go/constant, func Uint64Val(Value) (uint64, bool) +pkg go/constant, func UnaryOp(token.Token, Value, uint) Value +pkg go/constant, type Kind int +pkg go/constant, type Value interface, Kind() Kind +pkg go/constant, type Value interface, String() string +pkg go/constant, type Value interface, unexported methods +pkg go/importer, func Default() types.Importer +pkg go/importer, func For(string, Lookup) types.Importer +pkg go/importer, type Lookup func(string) (io.ReadCloser, error) pkg go/types, const Bool = 1 pkg go/types, const Bool BasicKind pkg go/types, const Byte = 8 @@ -376,6 +421,7 @@ pkg go/types, func New(string) Type pkg go/types, func NewArray(Type, int64) *Array pkg go/types, func NewChan(ChanDir, Type) *Chan pkg go/types, func NewChecker(*Config, *token.FileSet, *Package, *Info) *Checker +pkg go/types, func NewConst(token.Pos, *Package, string, Type, constant.Value) *Const pkg go/types, func NewConst(token.Pos, *Package, string, Type, exact.Value) *Const pkg go/types, func NewField(token.Pos, *Package, string, Type, bool) *Var pkg go/types, func NewFunc(token.Pos, *Package, string, *Signature) *Func @@ -432,6 +478,7 @@ pkg go/types, method (*Const) Pkg() *Package pkg go/types, method (*Const) Pos() token.Pos pkg go/types, method (*Const) String() string pkg go/types, method (*Const) Type() Type +pkg go/types, method (*Const) Val() constant.Value pkg go/types, method (*Const) Val() exact.Value pkg go/types, method (*Func) Exported() bool pkg go/types, method (*Func) FullName() string @@ -590,6 +637,7 @@ pkg go/types, type Config struct, Error func(error) pkg go/types, type Config struct, FakeImportC bool pkg go/types, type Config struct, IgnoreFuncBodies bool pkg go/types, type Config struct, Import Importer +pkg go/types, type Config struct, Importer Importer pkg go/types, type Config struct, Packages map[string]*Package pkg go/types, type Config struct, Sizes Sizes pkg go/types, type Const struct @@ -600,6 +648,8 @@ pkg go/types, type Error struct, Pos token.Pos pkg go/types, type Error struct, Soft bool pkg go/types, type Func struct pkg go/types, type Importer func(map[string]*Package, string) (*Package, error) +pkg go/types, type Importer interface { Import } +pkg go/types, type Importer interface, Import(string) (*Package, error) pkg go/types, type Info struct pkg go/types, type Info struct, Defs map[*ast.Ident]Object pkg go/types, type Info struct, Implicits map[ast.Node]Object @@ -649,6 +699,7 @@ pkg go/types, type Type interface, String() string pkg go/types, type Type interface, Underlying() Type pkg go/types, type TypeAndValue struct pkg go/types, type TypeAndValue struct, Type Type +pkg go/types, type TypeAndValue struct, Value constant.Value pkg go/types, type TypeAndValue struct, Value exact.Value pkg go/types, type TypeName struct pkg go/types, type Var struct @@ -690,6 +741,18 @@ pkg image/color, type CMYK struct, K uint8 pkg image/color, type CMYK struct, M uint8 pkg image/color, type CMYK struct, Y uint8 pkg image/color, var CMYKModel Model +pkg image/gif, const DisposalBackground = 2 +pkg image/gif, const DisposalBackground ideal-int +pkg image/gif, const DisposalNone = 1 +pkg image/gif, const DisposalNone ideal-int +pkg image/gif, const DisposalPrevious = 3 +pkg image/gif, const DisposalPrevious ideal-int +pkg image/gif, type GIF struct, BackgroundIndex uint8 +pkg image/gif, type GIF struct, Config image.Config +pkg image/gif, type GIF struct, Disposal []uint8 +pkg io, func CopyBuffer(Writer, Reader, []uint8) (int64, error) +pkg log, const LUTC = 32 +pkg log, const LUTC ideal-int pkg log, func Output(int, string) error pkg log, method (*Logger) SetOutput(io.Writer) pkg math/big, const Above = 1 @@ -716,6 +779,7 @@ pkg math/big, const ToPositiveInf = 5 pkg math/big, const ToPositiveInf RoundingMode pkg math/big, const ToZero = 2 pkg math/big, const ToZero RoundingMode +pkg math/big, func Jacobi(*Int, *Int) int pkg math/big, func NewFloat(float64) *Float pkg math/big, func ParseFloat(string, int, uint, RoundingMode) (*Float, int, error) pkg math/big, func ScanFloat(io.ByteScanner, int, uint, RoundingMode) (*Float, int, error) @@ -758,6 +822,7 @@ pkg math/big, method (*Float) Signbit() bool pkg math/big, method (*Float) String() string pkg math/big, method (*Float) Sub(*Float, *Float) *Float pkg math/big, method (*Float) Uint64() (uint64, Accuracy) +pkg math/big, method (*Int) ModSqrt(*Int, *Int) *Int pkg math/big, method (Accuracy) String() string pkg math/big, method (ErrNaN) Error() string pkg math/big, method (RoundingMode) String() string @@ -765,25 +830,48 @@ pkg math/big, type Accuracy int8 pkg math/big, type ErrNaN struct pkg math/big, type Float struct pkg math/big, type RoundingMode uint8 +pkg mime, const BEncoding = 98 +pkg mime, const BEncoding WordEncoder +pkg mime, const QEncoding = 113 +pkg mime, const QEncoding WordEncoder pkg mime, func ExtensionsByType(string) ([]string, error) +pkg mime, method (*WordDecoder) Decode(string) (string, error) +pkg mime, method (*WordDecoder) DecodeHeader(string) (string, error) +pkg mime, method (WordEncoder) Encode(string, string) string +pkg mime, type WordDecoder struct +pkg mime, type WordDecoder struct, CharsetReader func(string, io.Reader) (io.Reader, error) +pkg mime, type WordEncoder uint8 +pkg mime/quotedprintable, func NewReader(io.Reader) *Reader pkg mime/quotedprintable, func NewReader(io.Reader) io.Reader pkg mime/quotedprintable, func NewWriter(io.Writer) *Writer +pkg mime/quotedprintable, method (*Reader) Read([]uint8) (int, error) pkg mime/quotedprintable, method (*Writer) Close() error pkg mime/quotedprintable, method (*Writer) Write([]uint8) (int, error) +pkg mime/quotedprintable, type Reader struct pkg mime/quotedprintable, type Writer struct pkg mime/quotedprintable, type Writer struct, Binary bool +pkg net, func SocketConn(*os.File, SocketAddr) (Conn, error) +pkg net, func SocketPacketConn(*os.File, SocketAddr) (PacketConn, error) +pkg net, type OpError struct, Source Addr +pkg net, type SocketAddr interface { Addr, Raw } +pkg net, type SocketAddr interface, Addr([]uint8) Addr +pkg net, type SocketAddr interface, Raw(Addr) []uint8 pkg net/http/fcgi, var ErrConnClosed error pkg net/http/fcgi, var ErrRequestAborted error pkg net/http/pprof, func Trace(http.ResponseWriter, *http.Request) pkg net/smtp, method (*Client) TLSConnectionState() (tls.ConnectionState, bool) +pkg os, func LookupEnv(string) (string, bool) pkg os/signal, func Ignore(...os.Signal) pkg os/signal, func Reset(...os.Signal) +pkg reflect, func ArrayOf(int, Type) Type +pkg reflect, func FuncOf([]Type, []Type, bool) Type pkg runtime, func ReadTrace() []uint8 pkg runtime, func StartTrace() error pkg runtime, func StopTrace() pkg runtime/pprof, func StartTrace(io.Writer) error pkg runtime/pprof, func StopTrace() pkg strings, func Compare(string, string) int +pkg strings, func LastIndexByte(string, uint8) int pkg strings, method (*Reader) Size() int64 pkg syscall (darwin-386), type SysProcAttr struct, Ctty int pkg syscall (darwin-386), type SysProcAttr struct, Foreground bool From 5abdc24b006b98f32d5390691733a5c12b521b11 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 14 May 2015 15:14:57 -0700 Subject: [PATCH 091/232] go/types: remove "vendoring" script - not useful anymore Change-Id: I4f4e6b99a22054666cd2284679cb0eca7f1042b8 Reviewed-on: https://go-review.googlesource.com/10086 Reviewed-by: Rob Pike --- src/go/types.bash | 97 ----------------------------------------------- 1 file changed, 97 deletions(-) delete mode 100644 src/go/types.bash diff --git a/src/go/types.bash b/src/go/types.bash deleted file mode 100644 index 1a384d410a..0000000000 --- a/src/go/types.bash +++ /dev/null @@ -1,97 +0,0 @@ -#!/bin/bash - -# Copyright 2015 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. - -# Run this script to update the packages ./exact and ./types -# in the $GOROOT/src/go directory. They are vendored from the -# original sources in x/tools. Imports are renamed as needed. -# -# Delete this script once go/exact and go/types don't exist anymore in x/tools. -# -# NOTE(adonovan): the standard packages have intentionally diverged -# from x/tools, so this script is a unlikely to be useful. Upstream -# changes should be cherry-picked in to the standard library. - -set -e - -### Safety first. -if [ ! -d "$GOPATH" ]; then - echo 2>&1 '$GOPATH must be set.' - exit 1 -fi -if [ ! -d "$GOROOT" ]; then - echo 2>&1 '$GOROOT must be set.' - exit 1 -fi - -GODIR=$GOROOT/src/go - -function vendor() ( - SRCDIR=$GOPATH/src/golang.org/x/tools/$1 - DSTDIR=$GODIR/$2 - - echo 2>&1 "vendoring $SRCDIR => $DSTDIR" - - # create directory - rm -rf $DSTDIR - mkdir -p $DSTDIR - cd $DSTDIR - - # copy go sources and update import paths - for f in $SRCDIR/*.go; do - # copy $f and update imports - sed -e 's|"golang.org/x/tools/go/exact"|"go/exact"|' \ - -e 's|"golang.org/x/tools/go/types"|"go/types"|' \ - -e 's|"golang.org/x/tools/go/gcimporter"|"go/internal/gcimporter"|' \ - $f | gofmt > tmp.go - mv -f tmp.go `basename $f` - done - - # copy testdata, if any - if [ -e $SRCDIR/testdata ]; then - cp -R $SRCDIR/testdata/ $DSTDIR/testdata/ - fi -) - -function install() ( - PKG=$GODIR/$1 - - echo 2>&1 "installing $PKG" - cd $PKG - go install -) - -function test() ( - PKG=$GODIR/$1 - - echo 2>&1 "testing $PKG" - cd $PKG - if ! go test; then - echo 2>&1 "TESTING $PKG FAILED" - exit 1 - fi -) - -### go/exact -vendor go/exact exact -test exact -install exact - -### go/types -vendor go/types types -# cannot test w/o gcimporter -install types - -### go/gcimporter -vendor go/gcimporter internal/gcimporter -test internal/gcimporter -install internal/gcimporter - -### test go/types (requires gcimporter) -test types - -# All done. -echo 2>&1 "DONE" -exit 0 From fb7e2449b62e16313fec593329954f25e595dfff Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Thu, 14 May 2015 16:02:53 -0700 Subject: [PATCH 092/232] doc: update go1.5.txt Change-Id: Idbceaa44f4c823510632381b36b42302e63d8a29 Reviewed-on: https://go-review.googlesource.com/10057 Reviewed-by: Brad Fitzpatrick --- doc/go1.5.txt | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/doc/go1.5.txt b/doc/go1.5.txt index 571a9f17d0..10095d0c18 100644 --- a/doc/go1.5.txt +++ b/doc/go1.5.txt @@ -1,25 +1,27 @@ Overall: -toolchain in Go -new GC +- toolchain in Go +- new GC Language: -permit omission of key type in map composite literals where key is a composite literal (https://golang.org/cl/2591) +- permit omission of key type in map composite literals where key is a composite literal (https://golang.org/cl/2591) Build: -Go 1.4 required to build (https://golang.org/cl/2470, https://golang.org/cl/2993) +- Go 1.4 required to build (https://golang.org/cl/2470, https://golang.org/cl/2993) New Ports: -darwin/arm, a.k.a iOS. (https://golang.org/cl/2118, 2119, 3273, 2121, 2122, ..., 2127) -darwin/arm64 -linux/arm64 (cgo is supported, but only with external linking) -openbsd/arm (no cgo or external linking) -The port to Snow Leopard (OS X 10.6) is no longer actively maintained. - -Runtime: -goroutine scheduling order changed; never guaranteed by language, but can break tests that implicitly assume a specific execution order +- darwin/arm, a.k.a iOS. (https://golang.org/cl/2118, 2119, 3273, 2121, 2122, ..., 2127) +- darwin/arm64 +- linux/arm64 (cgo is supported, but only with external linking) +- openbsd/arm (no cgo or external linking) Removed Ports: -dragonfly/386 (https://golang.org/cl/7543) +- dragonfly/386 (https://golang.org/cl/7543) +- The port to Snow Leopard (OS X 10.6) is no longer actively maintained. + +Runtime: +- goroutine scheduling order changed; never guaranteed by language, + but can break tests that implicitly assume a specific execution + order API additions and behavior changes: @@ -107,6 +109,8 @@ cmd/gc: allocate backing storage for non-escaping interfaces on stack (https://g encoding/xml: avoid an allocation for tags without attributes (https://golang.org/cl/4160) image: many optimizations runtime: add ARM runtime.cmpstring and bytes.Compare (https://golang.org/cl/8010) +runtime: do not scan maps when k/v do not contain pointers (https://golang.org/cl/3288) +runtime: reduce thrashing of gs between ps (https://golang.org/cl/9872) sort: number of Sort performance optimizations (https://golang.org/cl/2100, https://golang.org/cl/2614, ...) strconv: optimize decimal to string conversion (https://golang.org/cl/2105) strconv: optimize float to string conversion (https://golang.org/cl/5600) From 83c7b60f2745e7b0e35e762e3fc2702f59169a7b Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Thu, 14 May 2015 15:45:10 -0700 Subject: [PATCH 093/232] cmd/doc: trim unexported methods from interfaces Fixes #10856. Change-Id: I5de65b8dd94eec3451ee0ba9c75698cdd88f5fea Reviewed-on: https://go-review.googlesource.com/10088 Reviewed-by: Andrew Gerrand --- src/cmd/doc/pkg.go | 56 ++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/src/cmd/doc/pkg.go b/src/cmd/doc/pkg.go index 835313e902..53f336ff1c 100644 --- a/src/cmd/doc/pkg.go +++ b/src/cmd/doc/pkg.go @@ -345,7 +345,7 @@ func (pkg *Package) symbolDoc(symbol string) { } decl := typ.Decl spec := pkg.findTypeSpec(decl, typ.Name) - trimUnexportedFields(spec) + trimUnexportedElems(spec) // If there are multiple types defined, reduce to just this one. if len(decl.Specs) > 1 { decl.Specs = []ast.Spec{spec} @@ -366,22 +366,26 @@ func (pkg *Package) symbolDoc(symbol string) { } } -// trimUnexportedFields modifies spec in place to elide unexported fields (unless -// the unexported flag is set). If spec is not a structure declartion, nothing happens. -func trimUnexportedFields(spec *ast.TypeSpec) { +// trimUnexportedElems modifies spec in place to elide unexported fields from +// structs and methods from interfaces (unless the unexported flag is set). +func trimUnexportedElems(spec *ast.TypeSpec) { if *unexported { - // We're printing all fields. - return + return fields } - // It must be a struct for us to care. (We show unexported methods in interfaces.) - structType, ok := spec.Type.(*ast.StructType) - if !ok { - return + switch typ := spec.Type.(type) { + case *ast.StructType: + typ.Fields = trimUnexportedFields(typ.Fields, "fields") + case *ast.InterfaceType: + typ.Methods = trimUnexportedFields(typ.Methods, "methods") } +} + +// trimUnexportedFields returns the field list trimmed of unexported fields. +func trimUnexportedFields(fields *ast.FieldList, what string) *ast.FieldList { trimmed := false - list := make([]*ast.Field, 0, len(structType.Fields.List)) - for _, field := range structType.Fields.List { - // Trims if any is unexported. Fine in practice. + list := make([]*ast.Field, 0, len(fields.List)) + for _, field := range fields.List { + // Trims if any is unexported. Good enough in practice. ok := true for _, name := range field.Names { if !isExported(name.Name) { @@ -394,19 +398,23 @@ func trimUnexportedFields(spec *ast.TypeSpec) { list = append(list, field) } } - if trimmed { - unexportedField := &ast.Field{ - Type: ast.NewIdent(""), // Hack: printer will treat this as a field with a named type. - Comment: &ast.CommentGroup{ - List: []*ast.Comment{ - &ast.Comment{ - Text: "// Has unexported fields.\n", - }, + if !trimmed { + return fields + } + unexportedField := &ast.Field{ + Type: ast.NewIdent(""), // Hack: printer will treat this as a field with a named type. + Comment: &ast.CommentGroup{ + List: []*ast.Comment{ + &ast.Comment{ + Text: fmt.Sprintf("// Has unexported %s.\n", what), }, }, - } - list = append(list, unexportedField) - structType.Fields.List = list + }, + } + return &ast.FieldList{ + Opening: fields.Opening, + List: append(list, unexportedField), + Closing: fields.Closing, } } From 5069452d6d23c9d1725305746ca948602f7a597c Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Thu, 14 May 2015 03:26:31 -0400 Subject: [PATCH 094/232] syscall: fix F_SETLK{,W} on linux/ppc64 Change-Id: Ia81675b0f01ceafada32bdd2bc59088016a7421e Reviewed-on: https://go-review.googlesource.com/10043 Reviewed-by: Ian Lance Taylor --- src/syscall/zerrors_linux_ppc64.go | 4 ++-- src/syscall/ztypes_linux_ppc64.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/syscall/zerrors_linux_ppc64.go b/src/syscall/zerrors_linux_ppc64.go index 15e0770c18..fbaf0dc9af 100644 --- a/src/syscall/zerrors_linux_ppc64.go +++ b/src/syscall/zerrors_linux_ppc64.go @@ -366,9 +366,9 @@ const ( F_SETFD = 0x2 F_SETFL = 0x4 F_SETLEASE = 0x400 - F_SETLK = 0xd + F_SETLK = 0x6 F_SETLK64 = 0xd - F_SETLKW = 0xe + F_SETLKW = 0x7 F_SETLKW64 = 0xe F_SETOWN = 0x8 F_SETOWN_EX = 0xf diff --git a/src/syscall/ztypes_linux_ppc64.go b/src/syscall/ztypes_linux_ppc64.go index fe438364d4..bce0350b86 100644 --- a/src/syscall/ztypes_linux_ppc64.go +++ b/src/syscall/ztypes_linux_ppc64.go @@ -549,7 +549,7 @@ type Sysinfo_t struct { Totalhigh uint64 Freehigh uint64 Unit uint32 - X_f [0]byte + X_f [0]uint8 Pad_cgo_1 [4]byte } From 37eb1d1964049df2feb847ccef501f2807fdf618 Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Fri, 15 May 2015 09:39:16 +0900 Subject: [PATCH 095/232] cmd/doc: fix build Change-Id: Ic8437a1d2aeb424d6d5ce9e608c1293bba4c7bbc Reviewed-on: https://go-review.googlesource.com/10093 Run-TryBot: Mikio Hara Reviewed-by: Josh Bleecher Snyder --- src/cmd/doc/pkg.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/doc/pkg.go b/src/cmd/doc/pkg.go index 53f336ff1c..ed4b0b82db 100644 --- a/src/cmd/doc/pkg.go +++ b/src/cmd/doc/pkg.go @@ -370,7 +370,7 @@ func (pkg *Package) symbolDoc(symbol string) { // structs and methods from interfaces (unless the unexported flag is set). func trimUnexportedElems(spec *ast.TypeSpec) { if *unexported { - return fields + return } switch typ := spec.Type.(type) { case *ast.StructType: From 38631846bf6f5c290bdef15c22a09695fd6018c4 Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Thu, 14 May 2015 21:01:52 -0400 Subject: [PATCH 096/232] syscall: add explicit build tags Auto-generated using the following bash script: for i in z*_*_*.go; do goosgoarch=`basename ${i/${i/_*/}_/} .go` goos=${goosgoarch/_*/} goarch=${goosgoarch/*_/} echo $i $goos $goarch [ "$goos" = "windows" ] && continue sed -i -e "/^package /i\/\/ +build $goarch,$goos\n" "$i" done Change-Id: I756fee551d1698080e4591fed8f058ae0450aaa5 Signed-off-by: Shenghou Ma Reviewed-on: https://go-review.googlesource.com/10113 Reviewed-by: Ian Lance Taylor --- src/syscall/zerrors_darwin_386.go | 2 ++ src/syscall/zerrors_darwin_amd64.go | 2 ++ src/syscall/zerrors_darwin_arm.go | 2 ++ src/syscall/zerrors_darwin_arm64.go | 2 ++ src/syscall/zerrors_dragonfly_amd64.go | 2 ++ src/syscall/zerrors_freebsd_386.go | 2 ++ src/syscall/zerrors_freebsd_amd64.go | 2 ++ src/syscall/zerrors_freebsd_arm.go | 2 ++ src/syscall/zerrors_linux_386.go | 2 ++ src/syscall/zerrors_linux_amd64.go | 2 ++ src/syscall/zerrors_linux_arm.go | 2 ++ src/syscall/zerrors_linux_arm64.go | 2 ++ src/syscall/zerrors_linux_ppc64.go | 2 ++ src/syscall/zerrors_linux_ppc64le.go | 2 ++ src/syscall/zerrors_netbsd_386.go | 2 ++ src/syscall/zerrors_netbsd_amd64.go | 2 ++ src/syscall/zerrors_netbsd_arm.go | 2 ++ src/syscall/zerrors_openbsd_386.go | 2 ++ src/syscall/zerrors_openbsd_amd64.go | 2 ++ src/syscall/zerrors_openbsd_arm.go | 2 ++ src/syscall/zerrors_solaris_amd64.go | 2 ++ src/syscall/zsyscall_darwin_386.go | 2 ++ src/syscall/zsyscall_darwin_amd64.go | 2 ++ src/syscall/zsyscall_darwin_arm.go | 2 ++ src/syscall/zsyscall_darwin_arm64.go | 2 ++ src/syscall/zsyscall_dragonfly_amd64.go | 2 ++ src/syscall/zsyscall_freebsd_386.go | 2 ++ src/syscall/zsyscall_freebsd_amd64.go | 2 ++ src/syscall/zsyscall_freebsd_arm.go | 2 ++ src/syscall/zsyscall_linux_386.go | 2 ++ src/syscall/zsyscall_linux_amd64.go | 2 ++ src/syscall/zsyscall_linux_arm.go | 2 ++ src/syscall/zsyscall_linux_arm64.go | 2 ++ src/syscall/zsyscall_linux_ppc64.go | 2 ++ src/syscall/zsyscall_linux_ppc64le.go | 2 ++ src/syscall/zsyscall_nacl_386.go | 2 ++ src/syscall/zsyscall_nacl_amd64p32.go | 2 ++ src/syscall/zsyscall_nacl_arm.go | 2 ++ src/syscall/zsyscall_netbsd_386.go | 2 ++ src/syscall/zsyscall_netbsd_amd64.go | 2 ++ src/syscall/zsyscall_netbsd_arm.go | 2 ++ src/syscall/zsyscall_openbsd_386.go | 2 ++ src/syscall/zsyscall_openbsd_amd64.go | 2 ++ src/syscall/zsyscall_openbsd_arm.go | 2 ++ src/syscall/zsyscall_plan9_386.go | 2 ++ src/syscall/zsyscall_plan9_amd64.go | 2 ++ src/syscall/zsyscall_solaris_amd64.go | 2 ++ src/syscall/zsysnum_darwin_386.go | 2 ++ src/syscall/zsysnum_darwin_amd64.go | 2 ++ src/syscall/zsysnum_darwin_arm.go | 2 ++ src/syscall/zsysnum_darwin_arm64.go | 2 ++ src/syscall/zsysnum_dragonfly_amd64.go | 2 ++ src/syscall/zsysnum_freebsd_386.go | 2 ++ src/syscall/zsysnum_freebsd_amd64.go | 2 ++ src/syscall/zsysnum_freebsd_arm.go | 2 ++ src/syscall/zsysnum_linux_386.go | 2 ++ src/syscall/zsysnum_linux_amd64.go | 2 ++ src/syscall/zsysnum_linux_arm.go | 2 ++ src/syscall/zsysnum_linux_arm64.go | 2 ++ src/syscall/zsysnum_linux_ppc64.go | 2 ++ src/syscall/zsysnum_linux_ppc64le.go | 2 ++ src/syscall/zsysnum_netbsd_386.go | 2 ++ src/syscall/zsysnum_netbsd_amd64.go | 2 ++ src/syscall/zsysnum_netbsd_arm.go | 2 ++ src/syscall/zsysnum_openbsd_386.go | 2 ++ src/syscall/zsysnum_openbsd_amd64.go | 2 ++ src/syscall/zsysnum_openbsd_arm.go | 2 ++ src/syscall/zsysnum_solaris_amd64.go | 2 ++ src/syscall/ztypes_darwin_386.go | 2 ++ src/syscall/ztypes_darwin_amd64.go | 2 ++ src/syscall/ztypes_darwin_arm.go | 2 ++ src/syscall/ztypes_darwin_arm64.go | 2 ++ src/syscall/ztypes_dragonfly_amd64.go | 2 ++ src/syscall/ztypes_freebsd_386.go | 2 ++ src/syscall/ztypes_freebsd_amd64.go | 2 ++ src/syscall/ztypes_freebsd_arm.go | 2 ++ src/syscall/ztypes_linux_386.go | 2 ++ src/syscall/ztypes_linux_amd64.go | 2 ++ src/syscall/ztypes_linux_arm.go | 2 ++ src/syscall/ztypes_linux_arm64.go | 2 ++ src/syscall/ztypes_linux_ppc64.go | 2 ++ src/syscall/ztypes_linux_ppc64le.go | 2 ++ src/syscall/ztypes_netbsd_386.go | 2 ++ src/syscall/ztypes_netbsd_amd64.go | 2 ++ src/syscall/ztypes_netbsd_arm.go | 2 ++ src/syscall/ztypes_openbsd_386.go | 2 ++ src/syscall/ztypes_openbsd_amd64.go | 2 ++ src/syscall/ztypes_openbsd_arm.go | 2 ++ src/syscall/ztypes_solaris_amd64.go | 2 ++ 89 files changed, 178 insertions(+) diff --git a/src/syscall/zerrors_darwin_386.go b/src/syscall/zerrors_darwin_386.go index bb3a1610c0..debadaa9ce 100644 --- a/src/syscall/zerrors_darwin_386.go +++ b/src/syscall/zerrors_darwin_386.go @@ -4,6 +4,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -m32 _const.go +// +build 386,darwin + package syscall const ( diff --git a/src/syscall/zerrors_darwin_amd64.go b/src/syscall/zerrors_darwin_amd64.go index 05ab48ee32..d4262ba55a 100644 --- a/src/syscall/zerrors_darwin_amd64.go +++ b/src/syscall/zerrors_darwin_amd64.go @@ -4,6 +4,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -m64 _const.go +// +build amd64,darwin + package syscall const ( diff --git a/src/syscall/zerrors_darwin_arm.go b/src/syscall/zerrors_darwin_arm.go index 7e800d4259..a64f3735e2 100644 --- a/src/syscall/zerrors_darwin_arm.go +++ b/src/syscall/zerrors_darwin_arm.go @@ -4,6 +4,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- _const.go +// +build arm,darwin + package syscall const ( diff --git a/src/syscall/zerrors_darwin_arm64.go b/src/syscall/zerrors_darwin_arm64.go index a3841a277a..98f431c4e7 100644 --- a/src/syscall/zerrors_darwin_arm64.go +++ b/src/syscall/zerrors_darwin_arm64.go @@ -4,6 +4,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -m64 _const.go +// +build arm64,darwin + package syscall const ( diff --git a/src/syscall/zerrors_dragonfly_amd64.go b/src/syscall/zerrors_dragonfly_amd64.go index 59bff751cb..15d300fd2d 100644 --- a/src/syscall/zerrors_dragonfly_amd64.go +++ b/src/syscall/zerrors_dragonfly_amd64.go @@ -4,6 +4,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -m64 _const.go +// +build amd64,dragonfly + package syscall const ( diff --git a/src/syscall/zerrors_freebsd_386.go b/src/syscall/zerrors_freebsd_386.go index cd3aa80a9c..bbad05f069 100644 --- a/src/syscall/zerrors_freebsd_386.go +++ b/src/syscall/zerrors_freebsd_386.go @@ -4,6 +4,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -m32 _const.go +// +build 386,freebsd + package syscall const ( diff --git a/src/syscall/zerrors_freebsd_amd64.go b/src/syscall/zerrors_freebsd_amd64.go index 9edce6e2fa..b36125b6d3 100644 --- a/src/syscall/zerrors_freebsd_amd64.go +++ b/src/syscall/zerrors_freebsd_amd64.go @@ -4,6 +4,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -m64 _const.go +// +build amd64,freebsd + package syscall const ( diff --git a/src/syscall/zerrors_freebsd_arm.go b/src/syscall/zerrors_freebsd_arm.go index f29dd057b6..0c844f1387 100644 --- a/src/syscall/zerrors_freebsd_arm.go +++ b/src/syscall/zerrors_freebsd_arm.go @@ -4,6 +4,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- _const.go +// +build arm,freebsd + package syscall const ( diff --git a/src/syscall/zerrors_linux_386.go b/src/syscall/zerrors_linux_386.go index 7aa8ff07a7..d433a4f1a4 100644 --- a/src/syscall/zerrors_linux_386.go +++ b/src/syscall/zerrors_linux_386.go @@ -4,6 +4,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -m32 _const.go +// +build 386,linux + package syscall const ( diff --git a/src/syscall/zerrors_linux_amd64.go b/src/syscall/zerrors_linux_amd64.go index 94d051d8aa..dd86a3b0a1 100644 --- a/src/syscall/zerrors_linux_amd64.go +++ b/src/syscall/zerrors_linux_amd64.go @@ -4,6 +4,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -m64 _const.go +// +build amd64,linux + package syscall const ( diff --git a/src/syscall/zerrors_linux_arm.go b/src/syscall/zerrors_linux_arm.go index dcaaef7423..2a9c0f93c1 100644 --- a/src/syscall/zerrors_linux_arm.go +++ b/src/syscall/zerrors_linux_arm.go @@ -4,6 +4,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- _const.go +// +build arm,linux + package syscall const ( diff --git a/src/syscall/zerrors_linux_arm64.go b/src/syscall/zerrors_linux_arm64.go index f3d708be9c..35d9acefe5 100644 --- a/src/syscall/zerrors_linux_arm64.go +++ b/src/syscall/zerrors_linux_arm64.go @@ -4,6 +4,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- _const.go +// +build arm64,linux + package syscall const ( diff --git a/src/syscall/zerrors_linux_ppc64.go b/src/syscall/zerrors_linux_ppc64.go index fbaf0dc9af..1c769cdc77 100644 --- a/src/syscall/zerrors_linux_ppc64.go +++ b/src/syscall/zerrors_linux_ppc64.go @@ -4,6 +4,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -m64 _const.go +// +build ppc64,linux + package syscall const ( diff --git a/src/syscall/zerrors_linux_ppc64le.go b/src/syscall/zerrors_linux_ppc64le.go index 17c4c4cf3a..73727a4197 100644 --- a/src/syscall/zerrors_linux_ppc64le.go +++ b/src/syscall/zerrors_linux_ppc64le.go @@ -4,6 +4,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -m64 _const.go +// +build ppc64le,linux + package syscall const ( diff --git a/src/syscall/zerrors_netbsd_386.go b/src/syscall/zerrors_netbsd_386.go index 1e3dff7fac..6f32def661 100644 --- a/src/syscall/zerrors_netbsd_386.go +++ b/src/syscall/zerrors_netbsd_386.go @@ -4,6 +4,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -m32 _const.go +// +build 386,netbsd + package syscall const ( diff --git a/src/syscall/zerrors_netbsd_amd64.go b/src/syscall/zerrors_netbsd_amd64.go index 1469d00b78..a6d1701f8c 100644 --- a/src/syscall/zerrors_netbsd_amd64.go +++ b/src/syscall/zerrors_netbsd_amd64.go @@ -4,6 +4,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -m64 _const.go +// +build amd64,netbsd + package syscall const ( diff --git a/src/syscall/zerrors_netbsd_arm.go b/src/syscall/zerrors_netbsd_arm.go index 1a88c0d225..7f99279e55 100644 --- a/src/syscall/zerrors_netbsd_arm.go +++ b/src/syscall/zerrors_netbsd_arm.go @@ -4,6 +4,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -marm _const.go +// +build arm,netbsd + package syscall const ( diff --git a/src/syscall/zerrors_openbsd_386.go b/src/syscall/zerrors_openbsd_386.go index 0829834943..540d310e9f 100644 --- a/src/syscall/zerrors_openbsd_386.go +++ b/src/syscall/zerrors_openbsd_386.go @@ -4,6 +4,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -m32 _const.go +// +build 386,openbsd + package syscall const ( diff --git a/src/syscall/zerrors_openbsd_amd64.go b/src/syscall/zerrors_openbsd_amd64.go index e9fa37cdee..ae5b8c955a 100644 --- a/src/syscall/zerrors_openbsd_amd64.go +++ b/src/syscall/zerrors_openbsd_amd64.go @@ -4,6 +4,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -m64 _const.go +// +build amd64,openbsd + package syscall const ( diff --git a/src/syscall/zerrors_openbsd_arm.go b/src/syscall/zerrors_openbsd_arm.go index 5376fe6e85..c49ebcfd03 100644 --- a/src/syscall/zerrors_openbsd_arm.go +++ b/src/syscall/zerrors_openbsd_arm.go @@ -4,6 +4,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- _const.go +// +build arm,openbsd + package syscall const ( diff --git a/src/syscall/zerrors_solaris_amd64.go b/src/syscall/zerrors_solaris_amd64.go index 3f4cbfd984..62ec81be6b 100644 --- a/src/syscall/zerrors_solaris_amd64.go +++ b/src/syscall/zerrors_solaris_amd64.go @@ -4,6 +4,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -m64 _const.go +// +build amd64,solaris + package syscall const ( diff --git a/src/syscall/zsyscall_darwin_386.go b/src/syscall/zsyscall_darwin_386.go index 0ce383fb3b..23e7b5e420 100644 --- a/src/syscall/zsyscall_darwin_386.go +++ b/src/syscall/zsyscall_darwin_386.go @@ -1,6 +1,8 @@ // mksyscall.pl -l32 syscall_bsd.go syscall_darwin.go syscall_darwin_386.go // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// +build 386,darwin + package syscall import "unsafe" diff --git a/src/syscall/zsyscall_darwin_amd64.go b/src/syscall/zsyscall_darwin_amd64.go index 2370630f09..6e63d9a074 100644 --- a/src/syscall/zsyscall_darwin_amd64.go +++ b/src/syscall/zsyscall_darwin_amd64.go @@ -1,6 +1,8 @@ // mksyscall.pl syscall_bsd.go syscall_darwin.go syscall_darwin_amd64.go // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// +build amd64,darwin + package syscall import "unsafe" diff --git a/src/syscall/zsyscall_darwin_arm.go b/src/syscall/zsyscall_darwin_arm.go index c9426ee85a..f996a508f0 100644 --- a/src/syscall/zsyscall_darwin_arm.go +++ b/src/syscall/zsyscall_darwin_arm.go @@ -1,6 +1,8 @@ // mksyscall.pl -l32 syscall_bsd.go syscall_darwin.go syscall_darwin_arm.go // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// +build arm,darwin + package syscall import "unsafe" diff --git a/src/syscall/zsyscall_darwin_arm64.go b/src/syscall/zsyscall_darwin_arm64.go index 828b167fea..c260cc7acd 100644 --- a/src/syscall/zsyscall_darwin_arm64.go +++ b/src/syscall/zsyscall_darwin_arm64.go @@ -1,6 +1,8 @@ // mksyscall.pl syscall_bsd.go syscall_darwin.go syscall_darwin_arm64.go // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// +build arm64,darwin + package syscall import "unsafe" diff --git a/src/syscall/zsyscall_dragonfly_amd64.go b/src/syscall/zsyscall_dragonfly_amd64.go index 5eef1380ff..88e09d3a14 100644 --- a/src/syscall/zsyscall_dragonfly_amd64.go +++ b/src/syscall/zsyscall_dragonfly_amd64.go @@ -1,6 +1,8 @@ // mksyscall.pl -dragonfly syscall_bsd.go syscall_dragonfly.go syscall_dragonfly_amd64.go // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// +build amd64,dragonfly + package syscall import "unsafe" diff --git a/src/syscall/zsyscall_freebsd_386.go b/src/syscall/zsyscall_freebsd_386.go index 7cb21c9b39..30f29e52a9 100644 --- a/src/syscall/zsyscall_freebsd_386.go +++ b/src/syscall/zsyscall_freebsd_386.go @@ -1,6 +1,8 @@ // mksyscall.pl -l32 syscall_bsd.go syscall_freebsd.go syscall_freebsd_386.go // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// +build 386,freebsd + package syscall import "unsafe" diff --git a/src/syscall/zsyscall_freebsd_amd64.go b/src/syscall/zsyscall_freebsd_amd64.go index 3cb87c1a02..93059d1b5b 100644 --- a/src/syscall/zsyscall_freebsd_amd64.go +++ b/src/syscall/zsyscall_freebsd_amd64.go @@ -1,6 +1,8 @@ // mksyscall.pl syscall_bsd.go syscall_freebsd.go syscall_freebsd_amd64.go // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// +build amd64,freebsd + package syscall import "unsafe" diff --git a/src/syscall/zsyscall_freebsd_arm.go b/src/syscall/zsyscall_freebsd_arm.go index 340418345b..84096b07a5 100644 --- a/src/syscall/zsyscall_freebsd_arm.go +++ b/src/syscall/zsyscall_freebsd_arm.go @@ -1,6 +1,8 @@ // mksyscall.pl -l32 -arm syscall_bsd.go syscall_freebsd.go syscall_freebsd_arm.go // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// +build arm,freebsd + package syscall import "unsafe" diff --git a/src/syscall/zsyscall_linux_386.go b/src/syscall/zsyscall_linux_386.go index 2584d61e2f..620fba287a 100644 --- a/src/syscall/zsyscall_linux_386.go +++ b/src/syscall/zsyscall_linux_386.go @@ -1,6 +1,8 @@ // mksyscall.pl -l32 syscall_linux.go syscall_linux_386.go // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// +build 386,linux + package syscall import "unsafe" diff --git a/src/syscall/zsyscall_linux_amd64.go b/src/syscall/zsyscall_linux_amd64.go index 141f4f39be..16cafbf06e 100644 --- a/src/syscall/zsyscall_linux_amd64.go +++ b/src/syscall/zsyscall_linux_amd64.go @@ -1,6 +1,8 @@ // mksyscall.pl syscall_linux.go syscall_linux_amd64.go // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// +build amd64,linux + package syscall import "unsafe" diff --git a/src/syscall/zsyscall_linux_arm.go b/src/syscall/zsyscall_linux_arm.go index ee4f6e1245..9bc3a54f31 100644 --- a/src/syscall/zsyscall_linux_arm.go +++ b/src/syscall/zsyscall_linux_arm.go @@ -1,6 +1,8 @@ // mksyscall.pl -l32 -arm syscall_linux.go syscall_linux_arm.go // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// +build arm,linux + package syscall import "unsafe" diff --git a/src/syscall/zsyscall_linux_arm64.go b/src/syscall/zsyscall_linux_arm64.go index a294eb6096..2ee58cfc8b 100644 --- a/src/syscall/zsyscall_linux_arm64.go +++ b/src/syscall/zsyscall_linux_arm64.go @@ -1,6 +1,8 @@ // mksyscall.pl syscall_linux.go syscall_linux_arm64.go // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// +build arm64,linux + package syscall import "unsafe" diff --git a/src/syscall/zsyscall_linux_ppc64.go b/src/syscall/zsyscall_linux_ppc64.go index ba287e27e1..4f61114d5f 100644 --- a/src/syscall/zsyscall_linux_ppc64.go +++ b/src/syscall/zsyscall_linux_ppc64.go @@ -1,6 +1,8 @@ // mksyscall.pl syscall_linux.go syscall_linux_ppc64x.go // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// +build ppc64,linux + package syscall import "unsafe" diff --git a/src/syscall/zsyscall_linux_ppc64le.go b/src/syscall/zsyscall_linux_ppc64le.go index ba287e27e1..4073a0fa34 100644 --- a/src/syscall/zsyscall_linux_ppc64le.go +++ b/src/syscall/zsyscall_linux_ppc64le.go @@ -1,6 +1,8 @@ // mksyscall.pl syscall_linux.go syscall_linux_ppc64x.go // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// +build ppc64le,linux + package syscall import "unsafe" diff --git a/src/syscall/zsyscall_nacl_386.go b/src/syscall/zsyscall_nacl_386.go index d0ff66c819..bf3f9e3dcd 100644 --- a/src/syscall/zsyscall_nacl_386.go +++ b/src/syscall/zsyscall_nacl_386.go @@ -1,6 +1,8 @@ // mksyscall.pl -l32 -nacl syscall_nacl.go syscall_nacl_386.go // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// +build 386,nacl + package syscall import "unsafe" diff --git a/src/syscall/zsyscall_nacl_amd64p32.go b/src/syscall/zsyscall_nacl_amd64p32.go index 592c8d84a5..3f08da6e77 100644 --- a/src/syscall/zsyscall_nacl_amd64p32.go +++ b/src/syscall/zsyscall_nacl_amd64p32.go @@ -1,6 +1,8 @@ // mksyscall.pl -nacl syscall_nacl.go syscall_nacl_amd64p32.go // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// +build amd64p32,nacl + package syscall import "unsafe" diff --git a/src/syscall/zsyscall_nacl_arm.go b/src/syscall/zsyscall_nacl_arm.go index 10657ad080..77d46c3d81 100644 --- a/src/syscall/zsyscall_nacl_arm.go +++ b/src/syscall/zsyscall_nacl_arm.go @@ -1,6 +1,8 @@ // mksyscall.pl -l32 -nacl -arm syscall_nacl.go syscall_nacl_arm.go // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// +build arm,nacl + package syscall import "unsafe" diff --git a/src/syscall/zsyscall_netbsd_386.go b/src/syscall/zsyscall_netbsd_386.go index 5131c25696..e24c3b71cd 100644 --- a/src/syscall/zsyscall_netbsd_386.go +++ b/src/syscall/zsyscall_netbsd_386.go @@ -1,6 +1,8 @@ // mksyscall.pl -l32 -netbsd syscall_bsd.go syscall_netbsd.go syscall_netbsd_386.go // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// +build 386,netbsd + package syscall import "unsafe" diff --git a/src/syscall/zsyscall_netbsd_amd64.go b/src/syscall/zsyscall_netbsd_amd64.go index 0e26f6869d..7aa75ab12d 100644 --- a/src/syscall/zsyscall_netbsd_amd64.go +++ b/src/syscall/zsyscall_netbsd_amd64.go @@ -1,6 +1,8 @@ // mksyscall.pl -netbsd syscall_bsd.go syscall_netbsd.go syscall_netbsd_amd64.go // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// +build amd64,netbsd + package syscall import "unsafe" diff --git a/src/syscall/zsyscall_netbsd_arm.go b/src/syscall/zsyscall_netbsd_arm.go index 4aae1040ad..21f482b40f 100644 --- a/src/syscall/zsyscall_netbsd_arm.go +++ b/src/syscall/zsyscall_netbsd_arm.go @@ -1,6 +1,8 @@ // mksyscall.pl -l32 -arm syscall_bsd.go syscall_netbsd.go syscall_netbsd_arm.go // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// +build arm,netbsd + package syscall import "unsafe" diff --git a/src/syscall/zsyscall_openbsd_386.go b/src/syscall/zsyscall_openbsd_386.go index f6a19833ec..df7df1e7e4 100644 --- a/src/syscall/zsyscall_openbsd_386.go +++ b/src/syscall/zsyscall_openbsd_386.go @@ -1,6 +1,8 @@ // mksyscall.pl -l32 -openbsd syscall_bsd.go syscall_openbsd.go syscall_openbsd_386.go // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// +build 386,openbsd + package syscall import "unsafe" diff --git a/src/syscall/zsyscall_openbsd_amd64.go b/src/syscall/zsyscall_openbsd_amd64.go index 93f5fc0085..1d640700f7 100644 --- a/src/syscall/zsyscall_openbsd_amd64.go +++ b/src/syscall/zsyscall_openbsd_amd64.go @@ -1,6 +1,8 @@ // mksyscall.pl -openbsd syscall_bsd.go syscall_openbsd.go syscall_openbsd_amd64.go // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// +build amd64,openbsd + package syscall import "unsafe" diff --git a/src/syscall/zsyscall_openbsd_arm.go b/src/syscall/zsyscall_openbsd_arm.go index f59739c1e0..f40fb31c98 100644 --- a/src/syscall/zsyscall_openbsd_arm.go +++ b/src/syscall/zsyscall_openbsd_arm.go @@ -1,6 +1,8 @@ // mksyscall.pl -l32 -openbsd -arm syscall_bsd.go syscall_openbsd.go syscall_openbsd_arm.go // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// +build arm,openbsd + package syscall import "unsafe" diff --git a/src/syscall/zsyscall_plan9_386.go b/src/syscall/zsyscall_plan9_386.go index 06f1f04114..a424e789e3 100644 --- a/src/syscall/zsyscall_plan9_386.go +++ b/src/syscall/zsyscall_plan9_386.go @@ -1,6 +1,8 @@ // mksyscall.pl -l32 -plan9 syscall_plan9.go // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// +build 386,plan9 + package syscall import "unsafe" diff --git a/src/syscall/zsyscall_plan9_amd64.go b/src/syscall/zsyscall_plan9_amd64.go index 06f1f04114..d58556b01a 100644 --- a/src/syscall/zsyscall_plan9_amd64.go +++ b/src/syscall/zsyscall_plan9_amd64.go @@ -1,6 +1,8 @@ // mksyscall.pl -l32 -plan9 syscall_plan9.go // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// +build amd64,plan9 + package syscall import "unsafe" diff --git a/src/syscall/zsyscall_solaris_amd64.go b/src/syscall/zsyscall_solaris_amd64.go index be9bc28474..cabab7ece3 100644 --- a/src/syscall/zsyscall_solaris_amd64.go +++ b/src/syscall/zsyscall_solaris_amd64.go @@ -1,6 +1,8 @@ // mksyscall_solaris.pl syscall_solaris.go syscall_solaris_amd64.go // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// +build amd64,solaris + package syscall import "unsafe" diff --git a/src/syscall/zsysnum_darwin_386.go b/src/syscall/zsysnum_darwin_386.go index abdef77436..c6f8342841 100644 --- a/src/syscall/zsysnum_darwin_386.go +++ b/src/syscall/zsysnum_darwin_386.go @@ -1,6 +1,8 @@ // mksysnum_darwin.pl /usr/include/sys/syscall.h // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// +build 386,darwin + package syscall const ( diff --git a/src/syscall/zsysnum_darwin_amd64.go b/src/syscall/zsysnum_darwin_amd64.go index abdef77436..7189abe3db 100644 --- a/src/syscall/zsysnum_darwin_amd64.go +++ b/src/syscall/zsysnum_darwin_amd64.go @@ -1,6 +1,8 @@ // mksysnum_darwin.pl /usr/include/sys/syscall.h // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// +build amd64,darwin + package syscall const ( diff --git a/src/syscall/zsysnum_darwin_arm.go b/src/syscall/zsysnum_darwin_arm.go index 1a53f13eff..1d76861204 100644 --- a/src/syscall/zsysnum_darwin_arm.go +++ b/src/syscall/zsysnum_darwin_arm.go @@ -1,6 +1,8 @@ // mksysnum_darwin.pl /usr/include/sys/syscall.h // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// +build arm,darwin + package syscall const ( diff --git a/src/syscall/zsysnum_darwin_arm64.go b/src/syscall/zsysnum_darwin_arm64.go index 723b1aa19e..ddf8e83c87 100644 --- a/src/syscall/zsysnum_darwin_arm64.go +++ b/src/syscall/zsysnum_darwin_arm64.go @@ -1,6 +1,8 @@ // mksysnum_darwin.pl /usr/include/sys/syscall.h // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// +build arm64,darwin + package syscall const ( diff --git a/src/syscall/zsysnum_dragonfly_amd64.go b/src/syscall/zsysnum_dragonfly_amd64.go index 4b086b9214..277478d208 100644 --- a/src/syscall/zsysnum_dragonfly_amd64.go +++ b/src/syscall/zsysnum_dragonfly_amd64.go @@ -1,6 +1,8 @@ // mksysnum_dragonfly.pl // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// +build amd64,dragonfly + package syscall const ( diff --git a/src/syscall/zsysnum_freebsd_386.go b/src/syscall/zsysnum_freebsd_386.go index dfca558bb5..5e47217957 100644 --- a/src/syscall/zsysnum_freebsd_386.go +++ b/src/syscall/zsysnum_freebsd_386.go @@ -1,6 +1,8 @@ // mksysnum_freebsd.pl // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// +build 386,freebsd + package syscall const ( diff --git a/src/syscall/zsysnum_freebsd_amd64.go b/src/syscall/zsysnum_freebsd_amd64.go index dfca558bb5..df8928cc68 100644 --- a/src/syscall/zsysnum_freebsd_amd64.go +++ b/src/syscall/zsysnum_freebsd_amd64.go @@ -1,6 +1,8 @@ // mksysnum_freebsd.pl // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// +build amd64,freebsd + package syscall const ( diff --git a/src/syscall/zsysnum_freebsd_arm.go b/src/syscall/zsysnum_freebsd_arm.go index dfca558bb5..f670a59179 100644 --- a/src/syscall/zsysnum_freebsd_arm.go +++ b/src/syscall/zsysnum_freebsd_arm.go @@ -1,6 +1,8 @@ // mksysnum_freebsd.pl // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// +build arm,freebsd + package syscall const ( diff --git a/src/syscall/zsysnum_linux_386.go b/src/syscall/zsysnum_linux_386.go index c40b5f1ace..c277ed9a25 100644 --- a/src/syscall/zsysnum_linux_386.go +++ b/src/syscall/zsysnum_linux_386.go @@ -1,6 +1,8 @@ // mksysnum_linux.pl /usr/include/asm/unistd_32.h // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// +build 386,linux + package syscall const ( diff --git a/src/syscall/zsysnum_linux_amd64.go b/src/syscall/zsysnum_linux_amd64.go index 7cf70a4d86..978a4d3c3d 100644 --- a/src/syscall/zsysnum_linux_amd64.go +++ b/src/syscall/zsysnum_linux_amd64.go @@ -1,6 +1,8 @@ // mksysnum_linux.pl /usr/include/asm/unistd_64.h // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// +build amd64,linux + package syscall const ( diff --git a/src/syscall/zsysnum_linux_arm.go b/src/syscall/zsysnum_linux_arm.go index 7068e4e210..5061cbab2b 100644 --- a/src/syscall/zsysnum_linux_arm.go +++ b/src/syscall/zsysnum_linux_arm.go @@ -1,6 +1,8 @@ // mksysnum_linux.pl // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// +build arm,linux + package syscall const ( diff --git a/src/syscall/zsysnum_linux_arm64.go b/src/syscall/zsysnum_linux_arm64.go index 4bcf0573e7..d53712c681 100644 --- a/src/syscall/zsysnum_linux_arm64.go +++ b/src/syscall/zsysnum_linux_arm64.go @@ -1,6 +1,8 @@ // mksysnum_linux.pl /usr/include/asm-generic/unistd.h // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// +build arm64,linux + package syscall const ( diff --git a/src/syscall/zsysnum_linux_ppc64.go b/src/syscall/zsysnum_linux_ppc64.go index 0567fd0ea8..82d253a1ab 100644 --- a/src/syscall/zsysnum_linux_ppc64.go +++ b/src/syscall/zsysnum_linux_ppc64.go @@ -1,6 +1,8 @@ // mksysnum_linux.pl /usr/include/asm/unistd.h // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// +build ppc64,linux + package syscall const ( diff --git a/src/syscall/zsysnum_linux_ppc64le.go b/src/syscall/zsysnum_linux_ppc64le.go index 52c63e3d3e..3af4e83822 100644 --- a/src/syscall/zsysnum_linux_ppc64le.go +++ b/src/syscall/zsysnum_linux_ppc64le.go @@ -1,6 +1,8 @@ // mksysnum_linux.pl /usr/include/powerpc64le-linux-gnu/asm/unistd.h // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// +build ppc64le,linux + package syscall const ( diff --git a/src/syscall/zsysnum_netbsd_386.go b/src/syscall/zsysnum_netbsd_386.go index c570965237..c8af210082 100644 --- a/src/syscall/zsysnum_netbsd_386.go +++ b/src/syscall/zsysnum_netbsd_386.go @@ -1,6 +1,8 @@ // mksysnum_netbsd.pl // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// +build 386,netbsd + package syscall const ( diff --git a/src/syscall/zsysnum_netbsd_amd64.go b/src/syscall/zsysnum_netbsd_amd64.go index c570965237..e342a3ce58 100644 --- a/src/syscall/zsysnum_netbsd_amd64.go +++ b/src/syscall/zsysnum_netbsd_amd64.go @@ -1,6 +1,8 @@ // mksysnum_netbsd.pl // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// +build amd64,netbsd + package syscall const ( diff --git a/src/syscall/zsysnum_netbsd_arm.go b/src/syscall/zsysnum_netbsd_arm.go index c570965237..1f5b569b8f 100644 --- a/src/syscall/zsysnum_netbsd_arm.go +++ b/src/syscall/zsysnum_netbsd_arm.go @@ -1,6 +1,8 @@ // mksysnum_netbsd.pl // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// +build arm,netbsd + package syscall const ( diff --git a/src/syscall/zsysnum_openbsd_386.go b/src/syscall/zsysnum_openbsd_386.go index 3b9ac4c941..c19f6de649 100644 --- a/src/syscall/zsysnum_openbsd_386.go +++ b/src/syscall/zsysnum_openbsd_386.go @@ -1,6 +1,8 @@ // mksysnum_openbsd.pl // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// +build 386,openbsd + package syscall const ( diff --git a/src/syscall/zsysnum_openbsd_amd64.go b/src/syscall/zsysnum_openbsd_amd64.go index 3b9ac4c941..86e04cd47e 100644 --- a/src/syscall/zsysnum_openbsd_amd64.go +++ b/src/syscall/zsysnum_openbsd_amd64.go @@ -1,6 +1,8 @@ // mksysnum_openbsd.pl // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// +build amd64,openbsd + package syscall const ( diff --git a/src/syscall/zsysnum_openbsd_arm.go b/src/syscall/zsysnum_openbsd_arm.go index 8457c14732..38b43caba6 100644 --- a/src/syscall/zsysnum_openbsd_arm.go +++ b/src/syscall/zsysnum_openbsd_arm.go @@ -1,6 +1,8 @@ // mksysnum_openbsd.pl // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// +build arm,openbsd + package syscall const ( diff --git a/src/syscall/zsysnum_solaris_amd64.go b/src/syscall/zsysnum_solaris_amd64.go index 43b3d8b40d..be198f899b 100644 --- a/src/syscall/zsysnum_solaris_amd64.go +++ b/src/syscall/zsysnum_solaris_amd64.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build amd64,solaris + package syscall // TODO(aram): remove these before Go 1.3. diff --git a/src/syscall/ztypes_darwin_386.go b/src/syscall/ztypes_darwin_386.go index 13724c3cc6..7298d0243d 100644 --- a/src/syscall/ztypes_darwin_386.go +++ b/src/syscall/ztypes_darwin_386.go @@ -1,6 +1,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_darwin.go +// +build 386,darwin + package syscall const ( diff --git a/src/syscall/ztypes_darwin_amd64.go b/src/syscall/ztypes_darwin_amd64.go index 65b02ae4f5..ec95d51f91 100644 --- a/src/syscall/ztypes_darwin_amd64.go +++ b/src/syscall/ztypes_darwin_amd64.go @@ -1,6 +1,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_darwin.go +// +build amd64,darwin + package syscall const ( diff --git a/src/syscall/ztypes_darwin_arm.go b/src/syscall/ztypes_darwin_arm.go index ec87f54fb2..91c4470e7c 100644 --- a/src/syscall/ztypes_darwin_arm.go +++ b/src/syscall/ztypes_darwin_arm.go @@ -2,6 +2,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_darwin.go +// +build arm,darwin + package syscall const ( diff --git a/src/syscall/ztypes_darwin_arm64.go b/src/syscall/ztypes_darwin_arm64.go index 65b02ae4f5..1d65cfde9d 100644 --- a/src/syscall/ztypes_darwin_arm64.go +++ b/src/syscall/ztypes_darwin_arm64.go @@ -1,6 +1,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_darwin.go +// +build arm64,darwin + package syscall const ( diff --git a/src/syscall/ztypes_dragonfly_amd64.go b/src/syscall/ztypes_dragonfly_amd64.go index 954ffd7ab2..00120d0a27 100644 --- a/src/syscall/ztypes_dragonfly_amd64.go +++ b/src/syscall/ztypes_dragonfly_amd64.go @@ -1,6 +1,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_dragonfly.go +// +build amd64,dragonfly + package syscall const ( diff --git a/src/syscall/ztypes_freebsd_386.go b/src/syscall/ztypes_freebsd_386.go index b809eea37a..d972fb6bdf 100644 --- a/src/syscall/ztypes_freebsd_386.go +++ b/src/syscall/ztypes_freebsd_386.go @@ -1,6 +1,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_freebsd.go +// +build 386,freebsd + package syscall const ( diff --git a/src/syscall/ztypes_freebsd_amd64.go b/src/syscall/ztypes_freebsd_amd64.go index a05908aed1..0a5a10bf7d 100644 --- a/src/syscall/ztypes_freebsd_amd64.go +++ b/src/syscall/ztypes_freebsd_amd64.go @@ -1,6 +1,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_freebsd.go +// +build amd64,freebsd + package syscall const ( diff --git a/src/syscall/ztypes_freebsd_arm.go b/src/syscall/ztypes_freebsd_arm.go index 9303816f91..5d7acd547b 100644 --- a/src/syscall/ztypes_freebsd_arm.go +++ b/src/syscall/ztypes_freebsd_arm.go @@ -1,6 +1,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -fsigned-char types_freebsd.go +// +build arm,freebsd + package syscall const ( diff --git a/src/syscall/ztypes_linux_386.go b/src/syscall/ztypes_linux_386.go index a887f31427..dd198cb394 100644 --- a/src/syscall/ztypes_linux_386.go +++ b/src/syscall/ztypes_linux_386.go @@ -1,6 +1,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_linux.go +// +build 386,linux + package syscall const ( diff --git a/src/syscall/ztypes_linux_amd64.go b/src/syscall/ztypes_linux_amd64.go index adf95caee7..a39489e4e5 100644 --- a/src/syscall/ztypes_linux_amd64.go +++ b/src/syscall/ztypes_linux_amd64.go @@ -1,6 +1,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_linux.go +// +build amd64,linux + package syscall const ( diff --git a/src/syscall/ztypes_linux_arm.go b/src/syscall/ztypes_linux_arm.go index 1ae9718945..f446e41be0 100644 --- a/src/syscall/ztypes_linux_arm.go +++ b/src/syscall/ztypes_linux_arm.go @@ -1,6 +1,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_linux.go +// +build arm,linux + package syscall const ( diff --git a/src/syscall/ztypes_linux_arm64.go b/src/syscall/ztypes_linux_arm64.go index 1cb1d435d8..dcb1178dc4 100644 --- a/src/syscall/ztypes_linux_arm64.go +++ b/src/syscall/ztypes_linux_arm64.go @@ -1,6 +1,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs -- -fsigned-char types_linux.go +// +build arm64,linux + package syscall const ( diff --git a/src/syscall/ztypes_linux_ppc64.go b/src/syscall/ztypes_linux_ppc64.go index bce0350b86..33d1b7f3e5 100644 --- a/src/syscall/ztypes_linux_ppc64.go +++ b/src/syscall/ztypes_linux_ppc64.go @@ -1,6 +1,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_linux.go +// +build ppc64,linux + package syscall const ( diff --git a/src/syscall/ztypes_linux_ppc64le.go b/src/syscall/ztypes_linux_ppc64le.go index 0de1770f7f..27ca004834 100644 --- a/src/syscall/ztypes_linux_ppc64le.go +++ b/src/syscall/ztypes_linux_ppc64le.go @@ -1,6 +1,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_linux.go +// +build ppc64le,linux + package syscall const ( diff --git a/src/syscall/ztypes_netbsd_386.go b/src/syscall/ztypes_netbsd_386.go index 6add325a37..1752c6c229 100644 --- a/src/syscall/ztypes_netbsd_386.go +++ b/src/syscall/ztypes_netbsd_386.go @@ -1,6 +1,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_netbsd.go +// +build 386,netbsd + package syscall const ( diff --git a/src/syscall/ztypes_netbsd_amd64.go b/src/syscall/ztypes_netbsd_amd64.go index 4451fc1f02..b8d4b0b02a 100644 --- a/src/syscall/ztypes_netbsd_amd64.go +++ b/src/syscall/ztypes_netbsd_amd64.go @@ -1,6 +1,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_netbsd.go +// +build amd64,netbsd + package syscall const ( diff --git a/src/syscall/ztypes_netbsd_arm.go b/src/syscall/ztypes_netbsd_arm.go index 4e853eaa23..c21d875a93 100644 --- a/src/syscall/ztypes_netbsd_arm.go +++ b/src/syscall/ztypes_netbsd_arm.go @@ -1,6 +1,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_netbsd.go +// +build arm,netbsd + package syscall const ( diff --git a/src/syscall/ztypes_openbsd_386.go b/src/syscall/ztypes_openbsd_386.go index 2e4d9dd174..0376d3acab 100644 --- a/src/syscall/ztypes_openbsd_386.go +++ b/src/syscall/ztypes_openbsd_386.go @@ -1,6 +1,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_openbsd.go +// +build 386,openbsd + package syscall const ( diff --git a/src/syscall/ztypes_openbsd_amd64.go b/src/syscall/ztypes_openbsd_amd64.go index f07bc714e9..bf23626ff2 100644 --- a/src/syscall/ztypes_openbsd_amd64.go +++ b/src/syscall/ztypes_openbsd_amd64.go @@ -1,6 +1,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_openbsd.go +// +build amd64,openbsd + package syscall const ( diff --git a/src/syscall/ztypes_openbsd_arm.go b/src/syscall/ztypes_openbsd_arm.go index 5f8fb1262f..e1d8938f0e 100644 --- a/src/syscall/ztypes_openbsd_arm.go +++ b/src/syscall/ztypes_openbsd_arm.go @@ -1,6 +1,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_openbsd.go +// +build arm,openbsd + package syscall const ( diff --git a/src/syscall/ztypes_solaris_amd64.go b/src/syscall/ztypes_solaris_amd64.go index 77275a54e3..2471519ade 100644 --- a/src/syscall/ztypes_solaris_amd64.go +++ b/src/syscall/ztypes_solaris_amd64.go @@ -1,6 +1,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs types_solaris.go +// +build amd64,solaris + package syscall const ( From ed8ae79282f1ad8d06f926b366725c1be798289c Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Tue, 12 May 2015 01:13:09 -0400 Subject: [PATCH 097/232] syscall: add test for Flock_t roundtrip See CL 9962 for the rationale. Change-Id: I73c714fce258430eea1e61d3835f5c8e9014ca1f Signed-off-by: Shenghou Ma Reviewed-on: https://go-review.googlesource.com/9925 Reviewed-by: Ian Lance Taylor --- src/syscall/syscall_unix_test.go | 59 +++++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/src/syscall/syscall_unix_test.go b/src/syscall/syscall_unix_test.go index 01fc670aba..90fd276f82 100644 --- a/src/syscall/syscall_unix_test.go +++ b/src/syscall/syscall_unix_test.go @@ -60,20 +60,55 @@ func _() { // TestFcntlFlock tests whether the file locking structure matches // the calling convention of each kernel. +// On some Linux systems, glibc uses another set of values for the +// commands and translates them to the correct value that the kernel +// expects just before the actual fcntl syscall. As Go uses raw +// syscalls directly, it must use the real value, not the glibc value. +// Thus this test also verifies that the Flock_t structure can be +// roundtripped with F_SETLK and F_GETLK. func TestFcntlFlock(t *testing.T) { - name := filepath.Join(os.TempDir(), "TestFcntlFlock") - fd, err := syscall.Open(name, syscall.O_CREAT|syscall.O_RDWR|syscall.O_CLOEXEC, 0) - if err != nil { - t.Fatalf("Open failed: %v", err) - } - defer syscall.Unlink(name) - defer syscall.Close(fd) flock := syscall.Flock_t{ - Type: syscall.F_RDLCK, - Start: 0, Len: 0, Whence: 1, + Type: syscall.F_WRLCK, + Start: 31415, Len: 271828, Whence: 1, } - if err := syscall.FcntlFlock(uintptr(fd), syscall.F_GETLK, &flock); err != nil { - t.Fatalf("FcntlFlock failed: %v", err) + if os.Getenv("GO_WANT_HELPER_PROCESS") == "" { + // parent + name := filepath.Join(os.TempDir(), "TestFcntlFlock") + fd, err := syscall.Open(name, syscall.O_CREAT|syscall.O_RDWR|syscall.O_CLOEXEC, 0) + if err != nil { + t.Fatalf("Open failed: %v", err) + } + defer syscall.Unlink(name) + defer syscall.Close(fd) + if err := syscall.Ftruncate(fd, 1<<20); err != nil { + t.Fatalf("Ftruncate(1<<20) failed: %v", err) + } + if err := syscall.FcntlFlock(uintptr(fd), syscall.F_SETLK, &flock); err != nil { + t.Fatalf("FcntlFlock(F_SETLK) failed: %v", err) + } + cmd := exec.Command(os.Args[0], "-test.run=^TestFcntlFlock$") + cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1") + cmd.ExtraFiles = []*os.File{os.NewFile(uintptr(fd), name)} + out, err := cmd.CombinedOutput() + if len(out) > 0 || err != nil { + t.Fatalf("child process: %q, %v", out, err) + } + } else { + // child + got := flock + // make sure the child lock is conflicting with the parent lock + got.Start-- + got.Len++ + if err := syscall.FcntlFlock(3, syscall.F_GETLK, &got); err != nil { + t.Fatalf("FcntlFlock(F_GETLK) failed: %v", err) + } + flock.Pid = int32(syscall.Getppid()) + // Linux kernel always set Whence to 0 + flock.Whence = 0 + if got.Type == flock.Type && got.Start == flock.Start && got.Len == flock.Len && got.Pid == flock.Pid && got.Whence == flock.Whence { + os.Exit(0) + } + t.Fatalf("FcntlFlock got %v, want %v", got, flock) } } @@ -121,7 +156,7 @@ func TestPassFD(t *testing.T) { defer readFile.Close() cmd := exec.Command(os.Args[0], "-test.run=^TestPassFD$", "--", tempDir) - cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} + cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1") cmd.ExtraFiles = []*os.File{writeFile} out, err := cmd.CombinedOutput() From 335e44d265e7b7741b00237f4fcd97a1b80bfd9a Mon Sep 17 00:00:00 2001 From: Patrick Mezard Date: Sat, 9 May 2015 15:51:45 +0200 Subject: [PATCH 098/232] internal/syscall/windows/registry: fix read overrun in GetStringsValue According to MSDN RegQueryValueEx page: If the data has the REG_SZ, REG_MULTI_SZ or REG_EXPAND_SZ type, the string may not have been stored with the proper terminating null characters. Therefore, even if the function returns ERROR_SUCCESS, the application should ensure that the string is properly terminated before using it; otherwise, it may overwrite a buffer. (Note that REG_MULTI_SZ strings should have two terminating null characters.) Test written by Alex Brainman Change-Id: I8c0852e0527e27ceed949134ed5e6de944189986 Reviewed-on: https://go-review.googlesource.com/9806 Reviewed-by: Alex Brainman Run-TryBot: Alex Brainman --- .../syscall/windows/registry/export_test.go | 11 ++++ .../syscall/windows/registry/registry_test.go | 65 +++++++++++++++++++ .../syscall/windows/registry/value.go | 12 +++- 3 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 src/internal/syscall/windows/registry/export_test.go diff --git a/src/internal/syscall/windows/registry/export_test.go b/src/internal/syscall/windows/registry/export_test.go new file mode 100644 index 0000000000..8badf6fdcf --- /dev/null +++ b/src/internal/syscall/windows/registry/export_test.go @@ -0,0 +1,11 @@ +// Copyright 2015 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 windows + +package registry + +func (k Key) SetValue(name string, valtype uint32, data []byte) error { + return k.setValue(name, valtype, data) +} diff --git a/src/internal/syscall/windows/registry/registry_test.go b/src/internal/syscall/windows/registry/registry_test.go index 5f75febd27..07eccb23d8 100644 --- a/src/internal/syscall/windows/registry/registry_test.go +++ b/src/internal/syscall/windows/registry/registry_test.go @@ -611,3 +611,68 @@ func TestExpandString(t *testing.T) { t.Errorf("want %q string expanded, got %q", want, got) } } + +func TestInvalidValues(t *testing.T) { + softwareK, err := registry.OpenKey(registry.CURRENT_USER, "Software", registry.QUERY_VALUE) + if err != nil { + t.Fatal(err) + } + defer softwareK.Close() + + testKName := randKeyName("TestInvalidValues_") + + k, exist, err := registry.CreateKey(softwareK, testKName, registry.CREATE_SUB_KEY|registry.QUERY_VALUE|registry.SET_VALUE) + if err != nil { + t.Fatal(err) + } + defer k.Close() + + if exist { + t.Fatalf("key %q already exists", testKName) + } + + defer registry.DeleteKey(softwareK, testKName) + + var tests = []struct { + Type uint32 + Name string + Data []byte + }{ + {registry.DWORD, "Dword1", nil}, + {registry.DWORD, "Dword2", []byte{1, 2, 3}}, + {registry.QWORD, "Qword1", nil}, + {registry.QWORD, "Qword2", []byte{1, 2, 3}}, + {registry.QWORD, "Qword3", []byte{1, 2, 3, 4, 5, 6, 7}}, + {registry.MULTI_SZ, "MultiString1", nil}, + {registry.MULTI_SZ, "MultiString2", []byte{0}}, + {registry.MULTI_SZ, "MultiString3", []byte{'a', 'b', 0}}, + {registry.MULTI_SZ, "MultiString4", []byte{'a', 0, 0, 'b', 0}}, + {registry.MULTI_SZ, "MultiString5", []byte{'a', 0, 0}}, + } + + for _, test := range tests { + err := k.SetValue(test.Name, test.Type, test.Data) + if err != nil { + t.Fatalf("SetValue for %q failed: %v", test.Name, err) + } + } + + for _, test := range tests { + switch test.Type { + case registry.DWORD, registry.QWORD: + value, valType, err := k.GetIntegerValue(test.Name) + if err == nil { + t.Errorf("GetIntegerValue(%q) succeeded. Returns type=%d value=%v", test.Name, valType, value) + } + case registry.MULTI_SZ: + value, valType, err := k.GetStringsValue(test.Name) + if err == nil { + if len(value) != 0 { + t.Errorf("GetStringsValue(%q) succeeded. Returns type=%d value=%v", test.Name, valType, value) + } + } + default: + t.Errorf("unsupported type %d for %s value", test.Type, test.Name) + } + } +} diff --git a/src/internal/syscall/windows/registry/value.go b/src/internal/syscall/windows/registry/value.go index 814fe445b9..bb45a23643 100644 --- a/src/internal/syscall/windows/registry/value.go +++ b/src/internal/syscall/windows/registry/value.go @@ -150,9 +150,17 @@ func (k Key) GetStringsValue(name string) (val []string, valtype uint32, err err if typ != MULTI_SZ { return nil, typ, ErrUnexpectedType } - val = make([]string, 0, 5) + if len(data) == 0 { + return nil, typ, nil + } p := (*[1 << 24]uint16)(unsafe.Pointer(&data[0]))[:len(data)/2] - p = p[:len(p)-1] // remove terminating nil + if len(p) == 0 { + return nil, typ, nil + } + if p[len(p)-1] == 0 { + p = p[:len(p)-1] // remove terminating null + } + val = make([]string, 0, 5) from := 0 for i, c := range p { if c == 0 { From 3b214175bcf1e1441f0411f4691ca9a0963c4564 Mon Sep 17 00:00:00 2001 From: David Symonds Date: Fri, 15 May 2015 15:37:40 +1000 Subject: [PATCH 099/232] cmd/go: fix count of number of reserved names (doc change). Change-Id: I2784f831453d929df64c66febb4982cdf1f08e06 Reviewed-on: https://go-review.googlesource.com/10133 Reviewed-by: Minux Ma --- src/cmd/go/alldocs.go | 3 ++- src/cmd/go/help.go | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index e0d4a6c0fe..2b1cbf98ec 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -503,6 +503,7 @@ syntax of package template. The default output is equivalent to -f Name string // package name Doc string // package documentation string Target string // install path + Shlib string // the shared library that contains this package (only set when -linkshared) Goroot bool // is this package in the Go root? Standard bool // is this package part of the standard Go library? Stale bool // would 'go install' do anything for this package? @@ -1053,7 +1054,7 @@ environment variable (see 'go help gopath'). If no import paths are given, the action applies to the package in the current directory. -There are three reserved names for paths that should not be used +There are four reserved names for paths that should not be used for packages to be built with the go tool: - "main" denotes the top-level package in a stand-alone executable. diff --git a/src/cmd/go/help.go b/src/cmd/go/help.go index 56e8493e1a..2062f0c4ee 100644 --- a/src/cmd/go/help.go +++ b/src/cmd/go/help.go @@ -47,7 +47,7 @@ environment variable (see 'go help gopath'). If no import paths are given, the action applies to the package in the current directory. -There are three reserved names for paths that should not be used +There are four reserved names for paths that should not be used for packages to be built with the go tool: - "main" denotes the top-level package in a stand-alone executable. From 497970f4213367d8c6980dd46c43ea522f412ef9 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 13 May 2015 10:48:05 -0400 Subject: [PATCH 100/232] runtime: use memmove during slice append MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The effect of this CL: name old mean new mean delta BinaryTree17 5.97s × (0.96,1.04) 5.95s × (0.98,1.02) ~ (p=0.697) Fannkuch11 4.39s × (1.00,1.01) 4.41s × (1.00,1.01) +0.52% (p=0.015) FmtFprintfEmpty 90.8ns × (0.97,1.05) 89.4ns × (0.94,1.13) ~ (p=0.571) FmtFprintfString 305ns × (0.99,1.01) 292ns × (0.98,1.05) -4.35% (p=0.000) FmtFprintfInt 278ns × (0.96,1.03) 279ns × (0.98,1.04) ~ (p=0.741) FmtFprintfIntInt 489ns × (0.99,1.02) 482ns × (0.98,1.03) -1.43% (p=0.024) FmtFprintfPrefixedInt 402ns × (0.98,1.02) 395ns × (0.98,1.03) -1.67% (p=0.014) FmtFprintfFloat 578ns × (1.00,1.00) 569ns × (0.99,1.01) -1.48% (p=0.000) FmtManyArgs 1.88µs × (0.99,1.01) 1.88µs × (1.00,1.01) ~ (p=0.055) GobDecode 15.3ms × (0.99,1.01) 15.2ms × (1.00,1.01) -0.61% (p=0.007) GobEncode 11.8ms × (0.98,1.05) 11.6ms × (0.99,1.01) ~ (p=0.075) Gzip 647ms × (0.99,1.01) 647ms × (1.00,1.00) ~ (p=0.790) Gunzip 143ms × (1.00,1.00) 142ms × (1.00,1.00) ~ (p=0.370) HTTPClientServer 91.2µs × (0.99,1.01) 91.7µs × (0.99,1.02) ~ (p=0.233) JSONEncode 31.5ms × (0.98,1.01) 31.8ms × (0.99,1.02) +1.09% (p=0.015) JSONDecode 110ms × (0.99,1.01) 110ms × (0.99,1.02) ~ (p=0.577) Mandelbrot200 6.00ms × (1.00,1.00) 6.02ms × (1.00,1.00) +0.24% (p=0.001) GoParse 6.68ms × (0.98,1.02) 6.61ms × (0.99,1.01) -1.10% (p=0.027) RegexpMatchEasy0_32 162ns × (1.00,1.00) 161ns × (1.00,1.01) -0.66% (p=0.001) RegexpMatchEasy0_1K 539ns × (1.00,1.00) 539ns × (0.99,1.01) ~ (p=0.509) RegexpMatchEasy1_32 140ns × (0.99,1.02) 139ns × (0.99,1.02) ~ (p=0.163) RegexpMatchEasy1_1K 886ns × (1.00,1.00) 887ns × (1.00,1.00) ~ (p=0.408) RegexpMatchMedium_32 252ns × (1.00,1.00) 255ns × (0.99,1.01) +1.01% (p=0.000) RegexpMatchMedium_1K 72.6µs × (1.00,1.00) 72.6µs × (1.00,1.00) ~ (p=0.176) RegexpMatchHard_32 3.84µs × (1.00,1.00) 3.84µs × (1.00,1.00) ~ (p=0.403) RegexpMatchHard_1K 117µs × (1.00,1.00) 117µs × (1.00,1.00) ~ (p=0.351) Revcomp 926ms × (0.99,1.01) 925ms × (0.99,1.01) ~ (p=0.541) Template 126ms × (0.99,1.02) 130ms × (0.99,1.01) +3.42% (p=0.000) TimeParse 632ns × (0.99,1.01) 626ns × (1.00,1.00) -0.88% (p=0.000) TimeFormat 658ns × (0.99,1.01) 662ns × (0.99,1.02) ~ (p=0.111) The effect of this CL combined with CL 9886: name old mean new mean delta BinaryTree17 5.90s × (0.98,1.03) 5.95s × (0.98,1.02) ~ (p=0.175) Fannkuch11 4.34s × (1.00,1.00) 4.41s × (1.00,1.01) +1.69% (p=0.000) FmtFprintfEmpty 87.3ns × (0.97,1.17) 89.4ns × (0.94,1.13) ~ (p=0.499) FmtFprintfString 288ns × (0.98,1.04) 292ns × (0.98,1.05) ~ (p=0.292) FmtFprintfInt 290ns × (0.98,1.05) 279ns × (0.98,1.04) -3.76% (p=0.001) FmtFprintfIntInt 493ns × (0.98,1.04) 482ns × (0.98,1.03) -2.27% (p=0.017) FmtFprintfPrefixedInt 399ns × (0.98,1.02) 395ns × (0.98,1.03) ~ (p=0.159) FmtFprintfFloat 569ns × (1.00,1.00) 569ns × (0.99,1.01) ~ (p=0.847) FmtManyArgs 1.90µs × (0.99,1.03) 1.88µs × (1.00,1.01) -1.14% (p=0.009) GobDecode 15.2ms × (1.00,1.01) 15.2ms × (1.00,1.01) ~ (p=0.170) GobEncode 11.8ms × (0.99,1.02) 11.6ms × (0.99,1.01) -1.47% (p=0.003) Gzip 649ms × (0.99,1.00) 647ms × (1.00,1.00) ~ (p=0.200) Gunzip 144ms × (0.99,1.01) 142ms × (1.00,1.00) -1.04% (p=0.000) HTTPClientServer 91.1µs × (0.98,1.03) 91.7µs × (0.99,1.02) ~ (p=0.345) JSONEncode 31.5ms × (0.99,1.01) 31.8ms × (0.99,1.02) +0.98% (p=0.021) JSONDecode 110ms × (1.00,1.01) 110ms × (0.99,1.02) ~ (p=0.259) Mandelbrot200 6.02ms × (1.00,1.01) 6.02ms × (1.00,1.00) ~ (p=0.500) GoParse 6.68ms × (1.00,1.01) 6.61ms × (0.99,1.01) -1.17% (p=0.001) RegexpMatchEasy0_32 161ns × (1.00,1.00) 161ns × (1.00,1.01) -0.39% (p=0.033) RegexpMatchEasy0_1K 539ns × (1.00,1.00) 539ns × (0.99,1.01) ~ (p=0.445) RegexpMatchEasy1_32 138ns × (1.00,1.01) 139ns × (0.99,1.02) ~ (p=0.281) RegexpMatchEasy1_1K 887ns × (1.00,1.01) 887ns × (1.00,1.00) ~ (p=0.610) RegexpMatchMedium_32 251ns × (1.00,1.02) 255ns × (0.99,1.01) +1.42% (p=0.000) RegexpMatchMedium_1K 72.7µs × (1.00,1.00) 72.6µs × (1.00,1.00) ~ (p=0.097) RegexpMatchHard_32 3.85µs × (1.00,1.00) 3.84µs × (1.00,1.00) -0.31% (p=0.000) RegexpMatchHard_1K 117µs × (1.00,1.00) 117µs × (1.00,1.00) ~ (p=0.704) Revcomp 923ms × (0.98,1.02) 925ms × (0.99,1.01) ~ (p=0.574) Template 126ms × (0.98,1.03) 130ms × (0.99,1.01) +3.28% (p=0.000) TimeParse 631ns × (0.99,1.02) 626ns × (1.00,1.00) ~ (p=0.053) TimeFormat 660ns × (0.99,1.01) 662ns × (0.99,1.02) ~ (p=0.398) Change-Id: I59c03d329fe7bc178a31477c6f1f01062b881041 Reviewed-on: https://go-review.googlesource.com/9993 Reviewed-by: Austin Clements --- src/runtime/mbarrier.go | 14 ++++++++++++++ src/runtime/slice.go | 9 ++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/runtime/mbarrier.go b/src/runtime/mbarrier.go index 409c1948c6..d3e4809737 100644 --- a/src/runtime/mbarrier.go +++ b/src/runtime/mbarrier.go @@ -200,6 +200,8 @@ func callwritebarrier(typ *_type, frame unsafe.Pointer, framesize, retoffset uin //go:nosplit func typedslicecopy(typ *_type, dst, src slice) int { + // TODO(rsc): If typedslicecopy becomes faster than calling + // typedmemmove repeatedly, consider using during func growslice. n := dst.len if n > src.len { n = src.len @@ -217,6 +219,10 @@ func typedslicecopy(typ *_type, dst, src slice) int { racereadrangepc(srcp, uintptr(n)*typ.size, callerpc, pc) } + // Note: No point in checking typ.kind&kindNoPointers here: + // compiler only emits calls to typedslicecopy for types with pointers, + // and growslice and reflect_typedslicecopy check for pointers + // before calling typedslicecopy. if !writeBarrierEnabled { memmove(dstp, srcp, uintptr(n)*typ.size) return n @@ -257,5 +263,13 @@ func typedslicecopy(typ *_type, dst, src slice) int { //go:linkname reflect_typedslicecopy reflect.typedslicecopy func reflect_typedslicecopy(elemType *_type, dst, src slice) int { + if elemType.kind&kindNoPointers != 0 { + n := dst.len + if n > src.len { + n = src.len + } + memmove(dst.array, src.array, uintptr(n)*elemType.size) + return n + } return typedslicecopy(elemType, dst, src) } diff --git a/src/runtime/slice.go b/src/runtime/slice.go index 5ccc6592bf..79b611839d 100644 --- a/src/runtime/slice.go +++ b/src/runtime/slice.go @@ -84,10 +84,13 @@ func growslice(t *slicetype, old slice, n int) slice { memclr(add(p, lenmem), capmem-lenmem) } else { // Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan unitialized memory. - // TODO(rsc): Use memmove when !writeBarrierEnabled. p = newarray(et, uintptr(newcap)) - for i := 0; i < old.len; i++ { - typedmemmove(et, add(p, uintptr(i)*et.size), add(old.array, uintptr(i)*et.size)) + if !writeBarrierEnabled { + memmove(p, old.array, lenmem) + } else { + for i := uintptr(0); i < lenmem; i += et.size { + typedmemmove(et, add(p, i), add(old.array, i)) + } } } From 65c4d7beabd4a49aa77a9dddf1b7cdde55c47bb4 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 13 May 2015 14:44:48 -0400 Subject: [PATCH 101/232] runtime: optimize heapBitsBulkBarrier a tiny amount MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This may be mostly noise but: name old mean new mean delta BinaryTree17 6.03s × (0.98,1.02) 5.98s × (0.97,1.03) ~ (p=0.306) Fannkuch11 4.42s × (0.99,1.01) 4.34s × (0.99,1.02) -1.83% (p=0.000) FmtFprintfEmpty 84.7ns × (0.99,1.01) 84.4ns × (1.00,1.00) ~ (p=0.138) FmtFprintfString 289ns × (0.98,1.02) 289ns × (1.00,1.01) ~ (p=0.509) FmtFprintfInt 280ns × (0.97,1.03) 272ns × (0.98,1.03) -2.64% (p=0.003) FmtFprintfIntInt 484ns × (0.98,1.02) 482ns × (0.98,1.03) ~ (p=0.606) FmtFprintfPrefixedInt 397ns × (0.98,1.03) 393ns × (0.99,1.02) ~ (p=0.064) FmtFprintfFloat 573ns × (0.99,1.01) 569ns × (0.99,1.01) -0.69% (p=0.023) FmtManyArgs 1.89µs × (0.99,1.02) 1.91µs × (0.98,1.02) ~ (p=0.219) GobDecode 15.4ms × (0.99,1.02) 15.1ms × (0.99,1.01) -2.05% (p=0.000) GobEncode 12.0ms × (0.97,1.04) 11.9ms × (0.97,1.03) ~ (p=0.458) Gzip 652ms × (0.99,1.01) 653ms × (0.99,1.01) ~ (p=0.743) Gunzip 144ms × (0.99,1.01) 143ms × (0.99,1.01) ~ (p=0.134) HTTPClientServer 91.6µs × (0.99,1.01) 91.8µs × (0.99,1.03) ~ (p=0.678) JSONEncode 31.9ms × (1.00,1.00) 32.0ms × (0.99,1.01) ~ (p=0.334) JSONDecode 110ms × (0.99,1.01) 110ms × (0.99,1.01) ~ (p=0.315) Mandelbrot200 6.04ms × (0.99,1.01) 6.04ms × (1.00,1.01) ~ (p=0.596) GoParse 6.72ms × (0.98,1.03) 6.74ms × (0.99,1.03) ~ (p=0.577) RegexpMatchEasy0_32 161ns × (0.99,1.01) 160ns × (1.00,1.00) -0.83% (p=0.002) RegexpMatchEasy0_1K 542ns × (0.99,1.02) 541ns × (0.99,1.01) ~ (p=0.396) RegexpMatchEasy1_32 140ns × (0.98,1.01) 137ns × (1.00,1.00) -2.12% (p=0.000) RegexpMatchEasy1_1K 892ns × (0.99,1.01) 891ns × (1.00,1.01) ~ (p=0.631) RegexpMatchMedium_32 255ns × (0.99,1.01) 253ns × (0.99,1.01) -0.76% (p=0.008) RegexpMatchMedium_1K 73.1µs × (1.00,1.01) 72.9µs × (1.00,1.00) ~ (p=0.229) RegexpMatchHard_32 3.86µs × (1.00,1.01) 3.85µs × (1.00,1.00) ~ (p=0.341) RegexpMatchHard_1K 117µs × (1.00,1.01) 117µs × (0.99,1.00) ~ (p=0.955) Revcomp 954ms × (0.97,1.03) 955ms × (0.98,1.02) ~ (p=0.894) Template 133ms × (0.97,1.05) 129ms × (0.99,1.02) -2.50% (p=0.014) TimeParse 629ns × (0.99,1.01) 626ns × (0.99,1.01) ~ (p=0.106) TimeFormat 663ns × (0.99,1.01) 660ns × (0.99,1.02) ~ (p=0.231) Change-Id: I580e03ed01b0629cb5eae4c4637618f20127f924 Reviewed-on: https://go-review.googlesource.com/9994 Reviewed-by: Austin Clements --- src/runtime/mbitmap.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go index 2d2abca643..fcfcc7261c 100644 --- a/src/runtime/mbitmap.go +++ b/src/runtime/mbitmap.go @@ -365,11 +365,13 @@ func heapBitsBulkBarrier(p, size uintptr) { return } + h := heapBitsForAddr(p) for i := uintptr(0); i < size; i += ptrSize { - if heapBitsForAddr(p + i).isPointer() { + if h.isPointer() { x := (*uintptr)(unsafe.Pointer(p + i)) writebarrierptr_nostore(x, *x) } + h = h.next() } } From 7e26a2d9a80b825d019c2cdaf6437d89001506a9 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 14 May 2015 17:27:04 -0400 Subject: [PATCH 102/232] runtime: allocate map element zero values for reflect-created types on demand Preallocating them in reflect means that (1) if you say _ = PtrTo(ArrayOf(1000000000, reflect.TypeOf(byte(0)))), you just allocated 1GB of data (2) if you say it again, that's *another* GB of data. The only use of t.zero in the runtime is for map elements. Delay the allocation until the creation of a map with that element type, and share the zeros. The one downside of the shared zero is that it's not garbage collected, but it's also never written, so the OS should be able to handle it fairly efficiently. Change-Id: I56b098a091abf3ac0945de28ebef9a6c08e76614 Reviewed-on: https://go-review.googlesource.com/10111 Reviewed-by: Keith Randall --- src/reflect/type.go | 9 -------- src/runtime/hashmap.go | 48 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 9 deletions(-) diff --git a/src/reflect/type.go b/src/reflect/type.go index 5a43805626..bffe2595dd 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -1087,7 +1087,6 @@ func (t *rtype) ptrTo() *rtype { p.uncommonType = nil p.ptrToThis = nil - p.zero = unsafe.Pointer(&make([]byte, p.size)[0]) p.elem = t ptrMap.m[t] = p @@ -1467,7 +1466,6 @@ func ChanOf(dir ChanDir, t Type) Type { ch.elem = typ ch.uncommonType = nil ch.ptrToThis = nil - ch.zero = unsafe.Pointer(&make([]byte, ch.size)[0]) return cachePut(ckey, &ch.rtype) } @@ -1530,7 +1528,6 @@ func MapOf(key, elem Type) Type { mt.reflexivekey = isReflexive(ktyp) mt.uncommonType = nil mt.ptrToThis = nil - mt.zero = unsafe.Pointer(&make([]byte, mt.size)[0]) return cachePut(ckey, &mt.rtype) } @@ -1610,7 +1607,6 @@ func FuncOf(in, out []Type, variadic bool) Type { ft.string = &str ft.uncommonType = nil ft.ptrToThis = nil - ft.zero = unsafe.Pointer(&make([]byte, ft.size)[0]) funcLookupCache.m[hash] = append(funcLookupCache.m[hash], &ft.rtype) return ft @@ -1857,7 +1853,6 @@ func SliceOf(t Type) Type { slice.elem = typ slice.uncommonType = nil slice.ptrToThis = nil - slice.zero = unsafe.Pointer(&make([]byte, slice.size)[0]) return cachePut(ckey, &slice.rtype) } @@ -1913,10 +1908,6 @@ func ArrayOf(count int, elem Type) Type { array.fieldAlign = typ.fieldAlign array.uncommonType = nil array.ptrToThis = nil - if array.size > 0 { - zero := make([]byte, array.size) - array.zero = unsafe.Pointer(&zero[0]) - } array.len = uintptr(count) array.slice = slice.(*rtype) diff --git a/src/runtime/hashmap.go b/src/runtime/hashmap.go index 9ca33992bb..2b3af301b3 100644 --- a/src/runtime/hashmap.go +++ b/src/runtime/hashmap.go @@ -233,6 +233,9 @@ func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap { throw("need padding in bucket (value)") } + // make sure zero of element type is available. + mapzero(t.elem) + // find size parameter which will hold the requested # of elements B := uint8(0) for ; hint > bucketCnt && float32(hint) > loadFactor*float32(uintptr(1)<2GB zero on 32-bit machine + throw("map element too large") + } + } + zerobuf.p = (*byte)(persistentalloc(zerobuf.size, 64, &memstats.other_sys)) + } + atomicstorep(unsafe.Pointer(&t.zero), unsafe.Pointer(zerobuf.p)) + unlock(&zerobuf.lock) +} From 0112f6f6b605b17194175aa7cfe15b4054f862fc Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Wed, 22 Apr 2015 20:08:03 -0700 Subject: [PATCH 103/232] cmd/5g, etc: prepare to unexport gc.Mp* Remove all uses of Mp* outside of the gc package. A subsequent, automated commit in the Go 1.6 cycle will unexport all Mp* functions and types. No functional changes. Passes toolstash -cmp. Change-Id: Ie1604cb5b84ffb30b47f4777d4235570f2c62709 Reviewed-on: https://go-review.googlesource.com/9263 Reviewed-by: Russ Cox --- src/cmd/5g/cgen64.go | 6 ++--- src/cmd/5g/ggen.go | 8 +++--- src/cmd/5g/gsubr.go | 6 ++--- src/cmd/6g/ggen.go | 6 ++--- src/cmd/6g/gsubr.go | 40 +++++++++++++--------------- src/cmd/7g/ggen.go | 6 ++--- src/cmd/7g/gsubr.go | 4 +-- src/cmd/8g/cgen64.go | 11 ++++---- src/cmd/8g/ggen.go | 6 ++--- src/cmd/8g/gsubr.go | 51 ++++++++++++++++++------------------ src/cmd/9g/ggen.go | 6 ++--- src/cmd/9g/gsubr.go | 37 +++++++++++++------------- src/cmd/internal/gc/const.go | 28 ++++++++++++++++++++ 13 files changed, 119 insertions(+), 96 deletions(-) diff --git a/src/cmd/5g/cgen64.go b/src/cmd/5g/cgen64.go index 699e555f71..c55e000adc 100644 --- a/src/cmd/5g/cgen64.go +++ b/src/cmd/5g/cgen64.go @@ -237,7 +237,7 @@ func cgen64(n *gc.Node, res *gc.Node) { // shld hi:lo, c // shld lo:t, c case gc.OLROT: - v := uint64(gc.Mpgetfix(r.Val.U.Xval)) + v := uint64(r.Int()) var bl gc.Node gc.Regalloc(&bl, lo1.Type, nil) @@ -291,7 +291,7 @@ func cgen64(n *gc.Node, res *gc.Node) { var p4 *obj.Prog var p5 *obj.Prog if r.Op == gc.OLITERAL { - v := uint64(gc.Mpgetfix(r.Val.U.Xval)) + v := uint64(r.Int()) if v >= 64 { // TODO(kaib): replace with gins(AMOVW, nodintconst(0), &al) // here and below (verify it optimizes to EOR) @@ -452,7 +452,7 @@ func cgen64(n *gc.Node, res *gc.Node) { var creg gc.Node var p3 *obj.Prog if r.Op == gc.OLITERAL { - v := uint64(gc.Mpgetfix(r.Val.U.Xval)) + v := uint64(r.Int()) if v >= 64 { if bh.Type.Etype == gc.TINT32 { // MOVW bh->31, al diff --git a/src/cmd/5g/ggen.go b/src/cmd/5g/ggen.go index c2bd6dda0a..e4612362a2 100644 --- a/src/cmd/5g/ggen.go +++ b/src/cmd/5g/ggen.go @@ -183,7 +183,7 @@ func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) { w := int(nl.Type.Width * 8) if op == gc.OLROT { - v := int(gc.Mpgetfix(nr.Val.U.Xval)) + v := nr.Int() var n1 gc.Node gc.Regalloc(&n1, nl.Type, res) if w == 32 { @@ -210,7 +210,7 @@ func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) { var n1 gc.Node gc.Regalloc(&n1, nl.Type, res) gc.Cgen(nl, &n1) - sc := uint64(gc.Mpgetfix(nr.Val.U.Xval)) + sc := uint64(nr.Int()) if sc == 0 { } else // nothing to do if sc >= uint64(nl.Type.Width*8) { @@ -480,7 +480,7 @@ func ginscon(as int, c int64, n *gc.Node) { } func ginscmp(op int, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog { - if gc.Isint[t.Etype] && n1.Op == gc.OLITERAL && gc.Mpgetfix(n1.Val.U.Xval) == 0 && n2.Op != gc.OLITERAL { + if gc.Isint[t.Etype] && n1.Op == gc.OLITERAL && n1.Int() == 0 && n2.Op != gc.OLITERAL { op = gc.Brrev(op) n1, n2 = n2, n1 } @@ -489,7 +489,7 @@ func ginscmp(op int, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog { gc.Regalloc(&g1, n1.Type, &r1) gc.Cgen(n1, &g1) gmove(&g1, &r1) - if gc.Isint[t.Etype] && n2.Op == gc.OLITERAL && gc.Mpgetfix(n2.Val.U.Xval) == 0 { + if gc.Isint[t.Etype] && n2.Op == gc.OLITERAL && n2.Int() == 0 { gins(arm.ACMP, &r1, n2) } else { gc.Regalloc(&r2, t, n2) diff --git a/src/cmd/5g/gsubr.go b/src/cmd/5g/gsubr.go index 57d511e6f6..db46d6e9ee 100644 --- a/src/cmd/5g/gsubr.go +++ b/src/cmd/5g/gsubr.go @@ -53,7 +53,7 @@ func ncon(i uint32) *gc.Node { if ncon_n.Type == nil { gc.Nodconst(&ncon_n, gc.Types[gc.TUINT32], 0) } - gc.Mpmovecfix(ncon_n.Val.U.Xval, int64(i)) + ncon_n.SetInt(int64(i)) return &ncon_n } @@ -112,7 +112,7 @@ func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) { case gc.OLITERAL: var n1 gc.Node gc.Convconst(&n1, n.Type, &n.Val) - i := gc.Mpgetfix(n1.Val.U.Xval) + i := n1.Int() gc.Nodconst(lo, gc.Types[gc.TUINT32], int64(uint32(i))) i >>= 32 if n.Type.Etype == gc.TINT64 { @@ -1118,7 +1118,7 @@ func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool { if !gc.Isconst(n, gc.CTINT) { break } - v := gc.Mpgetfix(n.Val.U.Xval) + v := n.Int() if v >= 32000 || v <= -32000 { break } diff --git a/src/cmd/6g/ggen.go b/src/cmd/6g/ggen.go index 6e5e6bc4ca..12198d7187 100644 --- a/src/cmd/6g/ggen.go +++ b/src/cmd/6g/ggen.go @@ -190,9 +190,9 @@ func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) { check := 0 if gc.Issigned[t.Etype] { check = 1 - if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -(1< = uint64(nl.Type.Width*8) { // large shift gets 2 shifts by width-1 var n3 gc.Node diff --git a/src/cmd/6g/gsubr.go b/src/cmd/6g/gsubr.go index 14e1a57cbd..4e54bc8de5 100644 --- a/src/cmd/6g/gsubr.go +++ b/src/cmd/6g/gsubr.go @@ -32,6 +32,7 @@ package main import ( "cmd/internal/gc" + "cmd/internal/gc/big" "cmd/internal/obj" "cmd/internal/obj/x86" "fmt" @@ -139,29 +140,27 @@ func ginsboolval(a int, n *gc.Node) { gins(jmptoset(a), nil, n) } -/* - * set up nodes representing 2^63 - */ -var bigi gc.Node - -var bigf gc.Node - -var bignodes_did int +// set up nodes representing 2^63 +var ( + bigi gc.Node + bigf gc.Node + bignodes_did bool +) func bignodes() { - if bignodes_did != 0 { + if bignodes_did { return } - bignodes_did = 1 + bignodes_did = true - gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 1) - gc.Mpshiftfix(bigi.Val.U.Xval, 63) + var i big.Int + i.SetInt64(1) + i.Lsh(&i, 63) - bigf = bigi - bigf.Type = gc.Types[gc.TFLOAT64] - bigf.Val.Ctype = gc.CTFLT - bigf.Val.U.Fval = new(gc.Mpflt) - gc.Mpmovefixflt(bigf.Val.U.Fval, bigi.Val.U.Xval) + gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0) + bigi.SetBigInt(&i) + + gc.Convconst(&bigf, gc.Types[gc.TFLOAT64], &bigi.Val) } /* @@ -206,10 +205,7 @@ func gmove(f *gc.Node, t *gc.Node) { // 64-bit immediates are really 32-bit sign-extended // unless moving into a register. if gc.Isint[tt] { - if gc.Mpcmpfixfix(con.Val.U.Xval, gc.Minintval[gc.TINT32]) < 0 { - goto hard - } - if gc.Mpcmpfixfix(con.Val.U.Xval, gc.Maxintval[gc.TINT32]) > 0 { + if i := con.Int(); int64(int32(i)) != i { goto hard } } @@ -1273,7 +1269,7 @@ func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool { if !gc.Isconst(n, gc.CTINT) { break } - v := gc.Mpgetfix(n.Val.U.Xval) + v := n.Int() if v >= 32000 || v <= -32000 { break } diff --git a/src/cmd/7g/ggen.go b/src/cmd/7g/ggen.go index b824a3a18c..af51c31648 100644 --- a/src/cmd/7g/ggen.go +++ b/src/cmd/7g/ggen.go @@ -147,9 +147,9 @@ func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) { check := 0 if gc.Issigned[t.Etype] { check = 1 - if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -(1< = uint64(nl.Type.Width*8) { // large shift gets 2 shifts by width-1 var n3 gc.Node diff --git a/src/cmd/7g/gsubr.go b/src/cmd/7g/gsubr.go index 60c3a7ad44..2f03b121b4 100644 --- a/src/cmd/7g/gsubr.go +++ b/src/cmd/7g/gsubr.go @@ -115,7 +115,7 @@ func ginscmp(op int, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog { gc.Cgen(n1, &g1) gmove(&g1, &r1) if gc.Isint[t.Etype] && gc.Isconst(n2, gc.CTINT) { - ginscon2(optoas(gc.OCMP, t), &r1, gc.Mpgetfix(n2.Val.U.Xval)) + ginscon2(optoas(gc.OCMP, t), &r1, n2.Int()) } else { gc.Regalloc(&r2, t, n2) gc.Regalloc(&g2, n1.Type, &r2) @@ -473,7 +473,7 @@ func intLiteral(n *gc.Node) (x int64, ok bool) { } switch n.Val.Ctype { case gc.CTINT, gc.CTRUNE: - return gc.Mpgetfix(n.Val.U.Xval), true + return n.Int(), true case gc.CTBOOL: return int64(obj.Bool2int(n.Val.U.Bval)), true } diff --git a/src/cmd/8g/cgen64.go b/src/cmd/8g/cgen64.go index a682e2fb44..80a9642f75 100644 --- a/src/cmd/8g/cgen64.go +++ b/src/cmd/8g/cgen64.go @@ -162,7 +162,7 @@ func cgen64(n *gc.Node, res *gc.Node) { // shld hi:lo, c // shld lo:t, c case gc.OLROT: - v := uint64(gc.Mpgetfix(r.Val.U.Xval)) + v := uint64(r.Int()) if v >= 32 { // reverse during load to do the first 32 bits of rotate @@ -189,7 +189,7 @@ func cgen64(n *gc.Node, res *gc.Node) { case gc.OLSH: if r.Op == gc.OLITERAL { - v := uint64(gc.Mpgetfix(r.Val.U.Xval)) + v := uint64(r.Int()) if v >= 64 { if gc.Is64(r.Type) { splitclean() @@ -278,7 +278,7 @@ func cgen64(n *gc.Node, res *gc.Node) { case gc.ORSH: if r.Op == gc.OLITERAL { - v := uint64(gc.Mpgetfix(r.Val.U.Xval)) + v := uint64(r.Int()) if v >= 64 { if gc.Is64(r.Type) { splitclean() @@ -400,9 +400,8 @@ func cgen64(n *gc.Node, res *gc.Node) { if lo2.Op == gc.OLITERAL { // special cases for constants. - lv := uint32(gc.Mpgetfix(lo2.Val.U.Xval)) - - hv := uint32(gc.Mpgetfix(hi2.Val.U.Xval)) + lv := uint32(lo2.Int()) + hv := uint32(hi2.Int()) splitclean() // right side split64(res, &lo2, &hi2) switch n.Op { diff --git a/src/cmd/8g/ggen.go b/src/cmd/8g/ggen.go index 59025525fa..baa1b64d1e 100644 --- a/src/cmd/8g/ggen.go +++ b/src/cmd/8g/ggen.go @@ -216,9 +216,9 @@ func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node, ax *gc.Node, dx *gc.N check := 0 if gc.Issigned[t.Etype] { check = 1 - if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -1< = uint64(nl.Type.Width*8) { // large shift gets 2 shifts by width-1 gins(a, ncon(uint32(w)-1), &n1) diff --git a/src/cmd/8g/gsubr.go b/src/cmd/8g/gsubr.go index d1134d2c74..6878883b28 100644 --- a/src/cmd/8g/gsubr.go +++ b/src/cmd/8g/gsubr.go @@ -32,6 +32,7 @@ package main import ( "cmd/internal/gc" + "cmd/internal/gc/big" "cmd/internal/obj" "cmd/internal/obj/x86" "fmt" @@ -641,7 +642,7 @@ func ncon(i uint32) *gc.Node { if ncon_n.Type == nil { gc.Nodconst(&ncon_n, gc.Types[gc.TUINT32], 0) } - gc.Mpmovecfix(ncon_n.Val.U.Xval, int64(i)) + ncon_n.SetInt(int64(i)) return &ncon_n } @@ -700,7 +701,7 @@ func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) { case gc.OLITERAL: var n1 gc.Node gc.Convconst(&n1, n.Type, &n.Val) - i := gc.Mpgetfix(n1.Val.U.Xval) + i := n1.Int() gc.Nodconst(lo, gc.Types[gc.TUINT32], int64(uint32(i))) i >>= 32 if n.Type.Etype == gc.TINT64 { @@ -721,36 +722,36 @@ func splitclean() { } } -/* - * set up nodes representing fp constants - */ -var zerof gc.Node - -var two64f gc.Node - -var two63f gc.Node - -var bignodes_did int +// set up nodes representing fp constants +var ( + zerof gc.Node + two63f gc.Node + two64f gc.Node + bignodes_did bool +) func bignodes() { - if bignodes_did != 0 { + if bignodes_did { return } - bignodes_did = 1 + bignodes_did = true - two64f = *ncon(0) - two64f.Type = gc.Types[gc.TFLOAT64] - two64f.Val.Ctype = gc.CTFLT - two64f.Val.U.Fval = new(gc.Mpflt) - gc.Mpmovecflt(two64f.Val.U.Fval, 18446744073709551616.) + gc.Nodconst(&zerof, gc.Types[gc.TINT64], 0) + gc.Convconst(&zerof, gc.Types[gc.TFLOAT64], &zerof.Val) - two63f = two64f - two63f.Val.U.Fval = new(gc.Mpflt) - gc.Mpmovecflt(two63f.Val.U.Fval, 9223372036854775808.) + var i big.Int + i.SetInt64(1) + i.Lsh(&i, 63) + var bigi gc.Node - zerof = two64f - zerof.Val.U.Fval = new(gc.Mpflt) - gc.Mpmovecflt(zerof.Val.U.Fval, 0) + gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0) + bigi.SetBigInt(&i) + gc.Convconst(&two63f, gc.Types[gc.TFLOAT64], &bigi.Val) + + gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0) + i.Lsh(&i, 1) + bigi.SetBigInt(&i) + gc.Convconst(&two64f, gc.Types[gc.TFLOAT64], &bigi.Val) } func memname(n *gc.Node, t *gc.Type) { diff --git a/src/cmd/9g/ggen.go b/src/cmd/9g/ggen.go index 28ebd9cc01..265536921a 100644 --- a/src/cmd/9g/ggen.go +++ b/src/cmd/9g/ggen.go @@ -141,9 +141,9 @@ func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) { check := 0 if gc.Issigned[t.Etype] { check = 1 - if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -(1< = uint64(nl.Type.Width*8) { // large shift gets 2 shifts by width-1 var n3 gc.Node diff --git a/src/cmd/9g/gsubr.go b/src/cmd/9g/gsubr.go index 61ba87ee3e..f14f93734c 100644 --- a/src/cmd/9g/gsubr.go +++ b/src/cmd/9g/gsubr.go @@ -32,6 +32,7 @@ package main import ( "cmd/internal/gc" + "cmd/internal/gc/big" "cmd/internal/obj" "cmd/internal/obj/ppc64" "fmt" @@ -129,7 +130,7 @@ func ginscmp(op int, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog { gc.Cgen(n1, &g1) gmove(&g1, &r1) if gc.Isint[t.Etype] && gc.Isconst(n2, gc.CTINT) { - ginscon2(optoas(gc.OCMP, t), &r1, gc.Mpgetfix(n2.Val.U.Xval)) + ginscon2(optoas(gc.OCMP, t), &r1, n2.Int()) } else { gc.Regalloc(&r2, t, n2) gc.Regalloc(&g2, n1.Type, &r2) @@ -144,29 +145,27 @@ func ginscmp(op int, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog { return gc.Gbranch(optoas(op, t), nil, likely) } -/* - * set up nodes representing 2^63 - */ -var bigi gc.Node - -var bigf gc.Node - -var bignodes_did int +// set up nodes representing 2^63 +var ( + bigi gc.Node + bigf gc.Node + bignodes_did bool +) func bignodes() { - if bignodes_did != 0 { + if bignodes_did { return } - bignodes_did = 1 + bignodes_did = true - gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 1) - gc.Mpshiftfix(bigi.Val.U.Xval, 63) + var i big.Int + i.SetInt64(1) + i.Lsh(&i, 63) - bigf = bigi - bigf.Type = gc.Types[gc.TFLOAT64] - bigf.Val.Ctype = gc.CTFLT - bigf.Val.U.Fval = new(gc.Mpflt) - gc.Mpmovefixflt(bigf.Val.U.Fval, bigi.Val.U.Xval) + gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0) + bigi.SetBigInt(&i) + + gc.Convconst(&bigf, gc.Types[gc.TFLOAT64], &bigi.Val) } /* @@ -552,7 +551,7 @@ func intLiteral(n *gc.Node) (x int64, ok bool) { } switch n.Val.Ctype { case gc.CTINT, gc.CTRUNE: - return gc.Mpgetfix(n.Val.U.Xval), true + return n.Int(), true case gc.CTBOOL: return int64(obj.Bool2int(n.Val.U.Bval)), true } diff --git a/src/cmd/internal/gc/const.go b/src/cmd/internal/gc/const.go index 84b133769c..748752679b 100644 --- a/src/cmd/internal/gc/const.go +++ b/src/cmd/internal/gc/const.go @@ -5,10 +5,38 @@ package gc import ( + "cmd/internal/gc/big" "cmd/internal/obj" "strings" ) +// Int returns n as an int. +// n must be an integer constant. +func (n *Node) Int() int64 { + if !Isconst(n, CTINT) { + Fatal("Int(%v)", n) + } + return Mpgetfix(n.Val.U.Xval) +} + +// SetInt sets n's value to i. +// n must be an integer constant. +func (n *Node) SetInt(i int64) { + if !Isconst(n, CTINT) { + Fatal("SetInt(%v)", n) + } + Mpmovecfix(n.Val.U.Xval, i) +} + +// SetBigInt sets n's value to x. +// n must be an integer constant. +func (n *Node) SetBigInt(x *big.Int) { + if !Isconst(n, CTINT) { + Fatal("SetBigInt(%v)", n) + } + n.Val.U.Xval.Val.Set(x) +} + /* * truncate float literal fv to 32-bit or 64-bit precision * according to type; return truncated value. From ba57781181b18187958756b7ad7ccb126728de2d Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Thu, 7 May 2015 18:43:03 -0700 Subject: [PATCH 104/232] cmd/5g, etc: prepare Node.Val to be unexported Remove all uses of Node.Val outside of the gc package. A subsequent, automated commit in the Go 1.6 cycle will unexport Node.Val. No functional changes. Passes toolstash -cmp. Change-Id: Ia92ae6a7766c83ab3e45c69edab24a9581c824f9 Reviewed-on: https://go-review.googlesource.com/9267 Reviewed-by: Russ Cox --- src/cmd/5g/gsubr.go | 8 ++++---- src/cmd/6g/gsubr.go | 4 ++-- src/cmd/7g/gsubr.go | 17 ++++++++--------- src/cmd/8g/gsubr.go | 12 ++++++------ src/cmd/9g/gsubr.go | 19 +++++++++---------- src/cmd/internal/gc/const.go | 28 +++++++++++++++++----------- 6 files changed, 46 insertions(+), 42 deletions(-) diff --git a/src/cmd/5g/gsubr.go b/src/cmd/5g/gsubr.go index db46d6e9ee..2f70bfd468 100644 --- a/src/cmd/5g/gsubr.go +++ b/src/cmd/5g/gsubr.go @@ -111,7 +111,7 @@ func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) { case gc.OLITERAL: var n1 gc.Node - gc.Convconst(&n1, n.Type, &n.Val) + n.Convconst(&n1, n.Type) i := n1.Int() gc.Nodconst(lo, gc.Types[gc.TUINT32], int64(uint32(i))) i >>= 32 @@ -160,12 +160,12 @@ func gmove(f *gc.Node, t *gc.Node) { var con gc.Node switch tt { default: - gc.Convconst(&con, t.Type, &f.Val) + f.Convconst(&con, t.Type) case gc.TINT16, gc.TINT8: var con gc.Node - gc.Convconst(&con, gc.Types[gc.TINT32], &f.Val) + f.Convconst(&con, gc.Types[gc.TINT32]) var r1 gc.Node gc.Regalloc(&r1, con.Type, t) gins(arm.AMOVW, &con, &r1) @@ -176,7 +176,7 @@ func gmove(f *gc.Node, t *gc.Node) { case gc.TUINT16, gc.TUINT8: var con gc.Node - gc.Convconst(&con, gc.Types[gc.TUINT32], &f.Val) + f.Convconst(&con, gc.Types[gc.TUINT32]) var r1 gc.Node gc.Regalloc(&r1, con.Type, t) gins(arm.AMOVW, &con, &r1) diff --git a/src/cmd/6g/gsubr.go b/src/cmd/6g/gsubr.go index 4e54bc8de5..9b9141468e 100644 --- a/src/cmd/6g/gsubr.go +++ b/src/cmd/6g/gsubr.go @@ -160,7 +160,7 @@ func bignodes() { gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0) bigi.SetBigInt(&i) - gc.Convconst(&bigf, gc.Types[gc.TFLOAT64], &bigi.Val) + bigi.Convconst(&bigf, gc.Types[gc.TFLOAT64]) } /* @@ -191,7 +191,7 @@ func gmove(f *gc.Node, t *gc.Node) { // convert constant to desired type if f.Op == gc.OLITERAL { var con gc.Node - gc.Convconst(&con, t.Type, &f.Val) + f.Convconst(&con, t.Type) f = &con ft = tt // so big switch will choose a simple mov diff --git a/src/cmd/7g/gsubr.go b/src/cmd/7g/gsubr.go index 2f03b121b4..0f617079ad 100644 --- a/src/cmd/7g/gsubr.go +++ b/src/cmd/7g/gsubr.go @@ -161,13 +161,13 @@ func gmove(f *gc.Node, t *gc.Node) { var con gc.Node switch tt { default: - gc.Convconst(&con, t.Type, &f.Val) + f.Convconst(&con, t.Type) case gc.TINT32, gc.TINT16, gc.TINT8: var con gc.Node - gc.Convconst(&con, gc.Types[gc.TINT64], &f.Val) + f.Convconst(&con, gc.Types[gc.TINT64]) var r1 gc.Node gc.Regalloc(&r1, con.Type, t) gins(arm64.AMOVD, &con, &r1) @@ -179,7 +179,7 @@ func gmove(f *gc.Node, t *gc.Node) { gc.TUINT16, gc.TUINT8: var con gc.Node - gc.Convconst(&con, gc.Types[gc.TUINT64], &f.Val) + f.Convconst(&con, gc.Types[gc.TUINT64]) var r1 gc.Node gc.Regalloc(&r1, con.Type, t) gins(arm64.AMOVD, &con, &r1) @@ -468,14 +468,13 @@ hard: } func intLiteral(n *gc.Node) (x int64, ok bool) { - if n == nil || n.Op != gc.OLITERAL { + switch { + case n == nil: return - } - switch n.Val.Ctype { - case gc.CTINT, gc.CTRUNE: + case gc.Isconst(n, gc.CTINT): return n.Int(), true - case gc.CTBOOL: - return int64(obj.Bool2int(n.Val.U.Bval)), true + case gc.Isconst(n, gc.CTBOOL): + return int64(obj.Bool2int(n.Bool())), true } return } diff --git a/src/cmd/8g/gsubr.go b/src/cmd/8g/gsubr.go index 6878883b28..b0b0aedabc 100644 --- a/src/cmd/8g/gsubr.go +++ b/src/cmd/8g/gsubr.go @@ -700,7 +700,7 @@ func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) { case gc.OLITERAL: var n1 gc.Node - gc.Convconst(&n1, n.Type, &n.Val) + n.Convconst(&n1, n.Type) i := n1.Int() gc.Nodconst(lo, gc.Types[gc.TUINT32], int64(uint32(i))) i >>= 32 @@ -737,7 +737,7 @@ func bignodes() { bignodes_did = true gc.Nodconst(&zerof, gc.Types[gc.TINT64], 0) - gc.Convconst(&zerof, gc.Types[gc.TFLOAT64], &zerof.Val) + zerof.Convconst(&zerof, gc.Types[gc.TFLOAT64]) var i big.Int i.SetInt64(1) @@ -746,12 +746,12 @@ func bignodes() { gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0) bigi.SetBigInt(&i) - gc.Convconst(&two63f, gc.Types[gc.TFLOAT64], &bigi.Val) + bigi.Convconst(&two63f, gc.Types[gc.TFLOAT64]) gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0) i.Lsh(&i, 1) bigi.SetBigInt(&i) - gc.Convconst(&two64f, gc.Types[gc.TFLOAT64], &bigi.Val) + bigi.Convconst(&two64f, gc.Types[gc.TFLOAT64]) } func memname(n *gc.Node, t *gc.Type) { @@ -790,7 +790,7 @@ func gmove(f *gc.Node, t *gc.Node) { // convert constant to desired type if f.Op == gc.OLITERAL { var con gc.Node - gc.Convconst(&con, t.Type, &f.Val) + f.Convconst(&con, t.Type) f = &con ft = gc.Simsimtype(con.Type) } @@ -1061,7 +1061,7 @@ func floatmove(f *gc.Node, t *gc.Node) { // convert constant to desired type if f.Op == gc.OLITERAL { var con gc.Node - gc.Convconst(&con, t.Type, &f.Val) + f.Convconst(&con, t.Type) f = &con ft = gc.Simsimtype(con.Type) diff --git a/src/cmd/9g/gsubr.go b/src/cmd/9g/gsubr.go index f14f93734c..3a7c884fd1 100644 --- a/src/cmd/9g/gsubr.go +++ b/src/cmd/9g/gsubr.go @@ -165,7 +165,7 @@ func bignodes() { gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0) bigi.SetBigInt(&i) - gc.Convconst(&bigf, gc.Types[gc.TFLOAT64], &bigi.Val) + bigi.Convconst(&bigf, gc.Types[gc.TFLOAT64]) } /* @@ -200,13 +200,13 @@ func gmove(f *gc.Node, t *gc.Node) { var con gc.Node switch tt { default: - gc.Convconst(&con, t.Type, &f.Val) + f.Convconst(&con, t.Type) case gc.TINT32, gc.TINT16, gc.TINT8: var con gc.Node - gc.Convconst(&con, gc.Types[gc.TINT64], &f.Val) + f.Convconst(&con, gc.Types[gc.TINT64]) var r1 gc.Node gc.Regalloc(&r1, con.Type, t) gins(ppc64.AMOVD, &con, &r1) @@ -218,7 +218,7 @@ func gmove(f *gc.Node, t *gc.Node) { gc.TUINT16, gc.TUINT8: var con gc.Node - gc.Convconst(&con, gc.Types[gc.TUINT64], &f.Val) + f.Convconst(&con, gc.Types[gc.TUINT64]) var r1 gc.Node gc.Regalloc(&r1, con.Type, t) gins(ppc64.AMOVD, &con, &r1) @@ -546,14 +546,13 @@ hard: } func intLiteral(n *gc.Node) (x int64, ok bool) { - if n == nil || n.Op != gc.OLITERAL { + switch { + case n == nil: return - } - switch n.Val.Ctype { - case gc.CTINT, gc.CTRUNE: + case gc.Isconst(n, gc.CTINT): return n.Int(), true - case gc.CTBOOL: - return int64(obj.Bool2int(n.Val.U.Bval)), true + case gc.Isconst(n, gc.CTBOOL): + return int64(obj.Bool2int(n.Bool())), true } return } diff --git a/src/cmd/internal/gc/const.go b/src/cmd/internal/gc/const.go index 748752679b..69f2e5c904 100644 --- a/src/cmd/internal/gc/const.go +++ b/src/cmd/internal/gc/const.go @@ -37,6 +37,15 @@ func (n *Node) SetBigInt(x *big.Int) { n.Val.U.Xval.Val.Set(x) } +// Bool returns n as an bool. +// n must be an boolean constant. +func (n *Node) Bool() bool { + if !Isconst(n, CTBOOL) { + Fatal("Int(%v)", n) + } + return n.Val.U.Bval +} + /* * truncate float literal fv to 32-bit or 64-bit precision * according to type; return truncated value. @@ -1426,32 +1435,30 @@ func iconv(x int64, et int) int64 { return x } -/* - * convert constant val to type t; leave in con. - * for back end. - */ -func Convconst(con *Node, t *Type, val *Val) { +// Convconst converts constant node n to type t and +// places the result in con. +func (n *Node) Convconst(con *Node, t *Type) { tt := Simsimtype(t) // copy the constant for conversion Nodconst(con, Types[TINT8], 0) con.Type = t - con.Val = *val + con.Val = n.Val if Isint[tt] { con.Val.Ctype = CTINT con.Val.U.Xval = new(Mpint) var i int64 - switch val.Ctype { + switch n.Val.Ctype { default: - Fatal("convconst ctype=%d %v", val.Ctype, Tconv(t, obj.FmtLong)) + Fatal("convconst ctype=%d %v", n.Val.Ctype, Tconv(t, obj.FmtLong)) case CTINT, CTRUNE: - i = Mpgetfix(val.U.Xval) + i = Mpgetfix(n.Val.U.Xval) case CTBOOL: - i = int64(obj.Bool2int(val.U.Bval)) + i = int64(obj.Bool2int(n.Val.U.Bval)) case CTNIL: i = 0 @@ -1479,7 +1486,6 @@ func Convconst(con *Node, t *Type, val *Val) { con.Val.U.Cval.Real = *truncfltlit(&con.Val.U.Cval.Real, Types[TFLOAT32]) con.Val.U.Cval.Imag = *truncfltlit(&con.Val.U.Cval.Imag, Types[TFLOAT32]) } - return } From 3c06cff7d1d7382b74ab39bd3bf0e46264ac845d Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Thu, 14 May 2015 17:32:07 -0700 Subject: [PATCH 105/232] cmd/internal/gc: explicitly set zero bool Val This trivial change is a prerequisite to converting Val.U to an interface{}. No functional changes. Passes toolstash -cmp. Change-Id: I17ff036f68d29a9ed0097a8b23ae1c91e6ce8c21 Reviewed-on: https://go-review.googlesource.com/10058 Reviewed-by: Russ Cox --- src/cmd/internal/gc/gen.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cmd/internal/gc/gen.go b/src/cmd/internal/gc/gen.go index fcb2499d3b..8f6a43c121 100644 --- a/src/cmd/internal/gc/gen.go +++ b/src/cmd/internal/gc/gen.go @@ -348,6 +348,7 @@ func Clearslim(n *Node) { case TBOOL: z.Val.Ctype = CTBOOL + z.Val.U.Bval = false case TINT8, TINT16, From 13485be939d73d6d2a5a8407c74c5fd502e35a6f Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Thu, 14 May 2015 17:57:42 -0700 Subject: [PATCH 106/232] cmd/internal/gc: convert Val.U to interface{} This CL was generated by updating Val in go.go and then running: sed -i "" 's/\.U\.[SBXFC]val = /.U = /' *.go sed -i "" 's/\.U\.Sval/.U.\(string\)/g' *.go *.y sed -i "" 's/\.U\.Bval/.U.\(bool\)/g' *.go *.y sed -i "" 's/\.U\.Xval/.U.\(\*Mpint\)/g' *.go *.y sed -i "" 's/\.U\.Fval/.U.\(\*Mpflt\)/g' *.go *.y sed -i "" 's/\.U\.Cval/.U.\(\*Mpcplx\)/g' *.go *.y No functional changes. Passes toolstash -cmp. This reduces the size of gc.Node from 424 to 392 bytes. This in turn reduces the permanent (pprof -inuse_space) memory usage while compiling the test/rotate?.go tests: test old(MB) new(MB) change rotate0 379.49 364.78 -3.87% rotate1 373.42 359.07 -3.84% rotate2 381.17 366.24 -3.91% rotate3 374.30 359.95 -3.83% CL 8445 was similar to this; gri asked that Val's implementation be hidden first. CLs 8912, 9263, and 9267 have at least isolated the changes to the cmd/internal/gc package. Updates #9933. Change-Id: I83ddfe003d48e0a73c92e819edd3b5e620023084 Reviewed-on: https://go-review.googlesource.com/10059 Reviewed-by: Russ Cox --- src/cmd/internal/gc/cgen.go | 60 ++++---- src/cmd/internal/gc/const.go | 228 +++++++++++++++---------------- src/cmd/internal/gc/cplx.go | 6 +- src/cmd/internal/gc/dcl.go | 2 +- src/cmd/internal/gc/fmt.go | 32 ++--- src/cmd/internal/gc/gen.go | 18 +-- src/cmd/internal/gc/go.go | 14 +- src/cmd/internal/gc/go.y | 28 ++-- src/cmd/internal/gc/gsubr.go | 8 +- src/cmd/internal/gc/lex.go | 54 ++++---- src/cmd/internal/gc/obj.go | 4 +- src/cmd/internal/gc/order.go | 2 +- src/cmd/internal/gc/sinit.go | 24 ++-- src/cmd/internal/gc/subr.go | 24 ++-- src/cmd/internal/gc/swt.go | 10 +- src/cmd/internal/gc/typecheck.go | 54 ++++---- src/cmd/internal/gc/unsafe.go | 4 +- src/cmd/internal/gc/walk.go | 48 +++---- src/cmd/internal/gc/y.go | 28 ++-- 19 files changed, 324 insertions(+), 324 deletions(-) diff --git a/src/cmd/internal/gc/cgen.go b/src/cmd/internal/gc/cgen.go index a4b4f0b61b..7237e863ca 100644 --- a/src/cmd/internal/gc/cgen.go +++ b/src/cmd/internal/gc/cgen.go @@ -542,7 +542,7 @@ func cgen_wb(n, res *Node, wb bool) { var n1 Node Regalloc(&n1, Types[Tptr], res) p1 := Thearch.Gins(Thearch.Optoas(OAS, n1.Type), nil, &n1) - Datastring(nl.Val.U.Sval, &p1.From) + Datastring(nl.Val.U.(string), &p1.From) p1.From.Type = obj.TYPE_ADDR Thearch.Gmove(&n1, res) Regfree(&n1) @@ -1030,7 +1030,7 @@ func Agenr(n *Node, a *Node, res *Node) { if Isconst(nl, CTSTR) { Fatal("constant string constant index") } - v := uint64(Mpgetfix(nr.Val.U.Xval)) + v := uint64(Mpgetfix(nr.Val.U.(*Mpint))) var n2 Node if Isslice(nl.Type) || nl.Type.Etype == TSTRING { if Debug['B'] == 0 && !n.Bounded { @@ -1066,7 +1066,7 @@ func Agenr(n *Node, a *Node, res *Node) { if Debug['B'] == 0 && !n.Bounded { // check bounds if Isconst(nl, CTSTR) { - Nodconst(&n4, Types[TUINT32], int64(len(nl.Val.U.Sval))) + Nodconst(&n4, Types[TUINT32], int64(len(nl.Val.U.(string)))) } else if Isslice(nl.Type) || nl.Type.Etype == TSTRING { n1 = n3 n1.Op = OINDREG @@ -1091,7 +1091,7 @@ func Agenr(n *Node, a *Node, res *Node) { if Isconst(nl, CTSTR) { Regalloc(&n3, Types[Tptr], res) p1 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &n3) - Datastring(nl.Val.U.Sval, &p1.From) + Datastring(nl.Val.U.(string), &p1.From) p1.From.Type = obj.TYPE_ADDR } else if Isslice(nl.Type) || nl.Type.Etype == TSTRING { n1 = n3 @@ -1182,7 +1182,7 @@ func Agenr(n *Node, a *Node, res *Node) { if Isconst(nl, CTSTR) { Fatal("constant string constant index") // front end should handle } - v := uint64(Mpgetfix(nr.Val.U.Xval)) + v := uint64(Mpgetfix(nr.Val.U.(*Mpint))) if Isslice(nl.Type) || nl.Type.Etype == TSTRING { if Debug['B'] == 0 && !n.Bounded { nlen := n3 @@ -1227,7 +1227,7 @@ func Agenr(n *Node, a *Node, res *Node) { var nlen Node if Isconst(nl, CTSTR) { - Nodconst(&nlen, t, int64(len(nl.Val.U.Sval))) + Nodconst(&nlen, t, int64(len(nl.Val.U.(string)))) } else if Isslice(nl.Type) || nl.Type.Etype == TSTRING { nlen = n3 nlen.Type = t @@ -1247,7 +1247,7 @@ func Agenr(n *Node, a *Node, res *Node) { if Isconst(nl, CTSTR) { Regalloc(&n3, Types[Tptr], res) p1 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &n3) - Datastring(nl.Val.U.Sval, &p1.From) + Datastring(nl.Val.U.(string), &p1.From) p1.From.Type = obj.TYPE_ADDR Thearch.Gins(Thearch.Optoas(OADD, n3.Type), &n2, &n3) goto indexdone1 @@ -1372,7 +1372,7 @@ func Agenr(n *Node, a *Node, res *Node) { if Isconst(nl, CTSTR) { Fatal("constant string constant index") // front end should handle } - v := uint64(Mpgetfix(nr.Val.U.Xval)) + v := uint64(Mpgetfix(nr.Val.U.(*Mpint))) if Isslice(nl.Type) || nl.Type.Etype == TSTRING { if Debug['B'] == 0 && !n.Bounded { p1 := Thearch.Ginscmp(OGT, Types[Simtype[TUINT]], &nlen, Nodintconst(int64(v)), +1) @@ -1410,7 +1410,7 @@ func Agenr(n *Node, a *Node, res *Node) { t = Types[TUINT64] } if Isconst(nl, CTSTR) { - Nodconst(&nlen, t, int64(len(nl.Val.U.Sval))) + Nodconst(&nlen, t, int64(len(nl.Val.U.(string)))) } else if Isslice(nl.Type) || nl.Type.Etype == TSTRING { // nlen already initialized } else { @@ -1425,7 +1425,7 @@ func Agenr(n *Node, a *Node, res *Node) { if Isconst(nl, CTSTR) { Regalloc(&n3, Types[Tptr], res) p1 := Thearch.Gins(Thearch.Optoas(OAS, n3.Type), nil, &n3) // XXX was LEAQ! - Datastring(nl.Val.U.Sval, &p1.From) + Datastring(nl.Val.U.(string), &p1.From) p1.From.Type = obj.TYPE_ADDR Thearch.Gins(Thearch.Optoas(OADD, n3.Type), &n2, &n3) goto indexdone @@ -1712,7 +1712,7 @@ func Igen(n *Node, a *Node, res *Node) { // Compute &a[i] as &a + i*width. a.Type = n.Type - a.Xoffset += Mpgetfix(n.Right.Val.U.Xval) * n.Type.Width + a.Xoffset += Mpgetfix(n.Right.Val.U.(*Mpint)) * n.Type.Width Fixlargeoffset(a) return } @@ -1862,11 +1862,11 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) { Fatal("bgen: non-bool const %v\n", Nconv(n, obj.FmtLong)) } if genval { - Cgen(Nodbool(wantTrue == n.Val.U.Bval), res) + Cgen(Nodbool(wantTrue == n.Val.U.(bool)), res) return } // If n == wantTrue, jump; otherwise do nothing. - if wantTrue == n.Val.U.Bval { + if wantTrue == n.Val.U.(bool) { Patch(Gbranch(obj.AJMP, nil, likely), to) } return @@ -2187,7 +2187,7 @@ func stkof(n *Node) int64 { return off } if Isconst(n.Right, CTINT) { - return off + t.Type.Width*Mpgetfix(n.Right.Val.U.Xval) + return off + t.Type.Width*Mpgetfix(n.Right.Val.U.(*Mpint)) } return 1000 @@ -2642,7 +2642,7 @@ func cgen_div(op int, nl *Node, nr *Node, res *Node) { case TUINT64: var m Magic m.W = w - m.Ud = uint64(Mpgetfix(nr.Val.U.Xval)) + m.Ud = uint64(Mpgetfix(nr.Val.U.(*Mpint))) Umagic(&m) if m.Bad != 0 { break @@ -2680,7 +2680,7 @@ func cgen_div(op int, nl *Node, nr *Node, res *Node) { case TINT64: var m Magic m.W = w - m.Sd = Mpgetfix(nr.Val.U.Xval) + m.Sd = Mpgetfix(nr.Val.U.(*Mpint)) Smagic(&m) if m.Bad != 0 { break @@ -3024,7 +3024,7 @@ func cgen_slice(n, res *Node, wb bool) { return } if n.Op == OSLICESTR && Isconst(n.Left, CTSTR) { - Nodconst(&xlen, indexRegType, int64(len(n.Left.Val.U.Sval))) + Nodconst(&xlen, indexRegType, int64(len(n.Left.Val.U.(string)))) return } regalloc(&xlen, indexRegType, nil) @@ -3180,20 +3180,20 @@ func cgen_slice(n, res *Node, wb bool) { if n.Op == OSLICEARR || n.Op == OSLICE3ARR { bound = n.Left.Type.Type.Bound } else if n.Op == OSLICESTR && Isconst(n.Left, CTSTR) { - bound = int64(len(n.Left.Val.U.Sval)) + bound = int64(len(n.Left.Val.U.(string))) } if Isconst(&i, CTINT) { - if mpcmpfixc(i.Val.U.Xval, 0) < 0 || bound >= 0 && mpcmpfixc(i.Val.U.Xval, bound) > 0 { + if mpcmpfixc(i.Val.U.(*Mpint), 0) < 0 || bound >= 0 && mpcmpfixc(i.Val.U.(*Mpint), bound) > 0 { Yyerror("slice index out of bounds") } } if Isconst(&j, CTINT) { - if mpcmpfixc(j.Val.U.Xval, 0) < 0 || bound >= 0 && mpcmpfixc(j.Val.U.Xval, bound) > 0 { + if mpcmpfixc(j.Val.U.(*Mpint), 0) < 0 || bound >= 0 && mpcmpfixc(j.Val.U.(*Mpint), bound) > 0 { Yyerror("slice index out of bounds") } } if Isconst(&k, CTINT) { - if mpcmpfixc(k.Val.U.Xval, 0) < 0 || bound >= 0 && mpcmpfixc(k.Val.U.Xval, bound) > 0 { + if mpcmpfixc(k.Val.U.(*Mpint), 0) < 0 || bound >= 0 && mpcmpfixc(k.Val.U.(*Mpint), bound) > 0 { Yyerror("slice index out of bounds") } } @@ -3202,7 +3202,7 @@ func cgen_slice(n, res *Node, wb bool) { same := func(n1, n2 *Node) bool { return n1.Op == OREGISTER && n2.Op == OREGISTER && n1.Reg == n2.Reg || n1.Op == ONAME && n2.Op == ONAME && n1.Orig == n2.Orig && n1.Type == n2.Type && n1.Xoffset == n2.Xoffset || - n1.Op == OLITERAL && n2.Op == OLITERAL && Mpcmpfixfix(n1.Val.U.Xval, n2.Val.U.Xval) == 0 + n1.Op == OLITERAL && n2.Op == OLITERAL && Mpcmpfixfix(n1.Val.U.(*Mpint), n2.Val.U.(*Mpint)) == 0 } // obvious reports whether n1 <= n2 is obviously true, @@ -3221,7 +3221,7 @@ func cgen_slice(n, res *Node, wb bool) { return true // len(x) <= cap(x) always true } if Isconst(n1, CTINT) && Isconst(n2, CTINT) { - if Mpcmpfixfix(n1.Val.U.Xval, n2.Val.U.Xval) <= 0 { + if Mpcmpfixfix(n1.Val.U.(*Mpint), n2.Val.U.(*Mpint)) <= 0 { return true // n1, n2 constants such that n1 <= n2 } Yyerror("slice index out of bounds") @@ -3312,9 +3312,9 @@ func cgen_slice(n, res *Node, wb bool) { switch j.Op { case OLITERAL: if Isconst(&i, CTINT) { - Nodconst(&j, indexRegType, Mpgetfix(j.Val.U.Xval)-Mpgetfix(i.Val.U.Xval)) + Nodconst(&j, indexRegType, Mpgetfix(j.Val.U.(*Mpint))-Mpgetfix(i.Val.U.(*Mpint))) if Debug_slice > 0 { - Warn("slice: result len == %d", Mpgetfix(j.Val.U.Xval)) + Warn("slice: result len == %d", Mpgetfix(j.Val.U.(*Mpint))) } break } @@ -3329,7 +3329,7 @@ func cgen_slice(n, res *Node, wb bool) { fallthrough case OREGISTER: if i.Op == OLITERAL { - v := Mpgetfix(i.Val.U.Xval) + v := Mpgetfix(i.Val.U.(*Mpint)) if v != 0 { ginscon(Thearch.Optoas(OSUB, indexRegType), v, &j) } @@ -3372,9 +3372,9 @@ func cgen_slice(n, res *Node, wb bool) { switch k.Op { case OLITERAL: if Isconst(&i, CTINT) { - Nodconst(&k, indexRegType, Mpgetfix(k.Val.U.Xval)-Mpgetfix(i.Val.U.Xval)) + Nodconst(&k, indexRegType, Mpgetfix(k.Val.U.(*Mpint))-Mpgetfix(i.Val.U.(*Mpint))) if Debug_slice > 0 { - Warn("slice: result cap == %d", Mpgetfix(k.Val.U.Xval)) + Warn("slice: result cap == %d", Mpgetfix(k.Val.U.(*Mpint))) } break } @@ -3395,7 +3395,7 @@ func cgen_slice(n, res *Node, wb bool) { Warn("slice: result cap == 0") } } else if i.Op == OLITERAL { - v := Mpgetfix(i.Val.U.Xval) + v := Mpgetfix(i.Val.U.(*Mpint)) if v != 0 { ginscon(Thearch.Optoas(OSUB, indexRegType), v, &k) } @@ -3478,7 +3478,7 @@ func cgen_slice(n, res *Node, wb bool) { w = res.Type.Type.Width // res is []T, elem size is T.width } if Isconst(&i, CTINT) { - ginscon(Thearch.Optoas(OADD, xbase.Type), Mpgetfix(i.Val.U.Xval)*w, &xbase) + ginscon(Thearch.Optoas(OADD, xbase.Type), Mpgetfix(i.Val.U.(*Mpint))*w, &xbase) } else if Thearch.AddIndex != nil && Thearch.AddIndex(&i, w, &xbase) { // done by back end } else if w == 1 { diff --git a/src/cmd/internal/gc/const.go b/src/cmd/internal/gc/const.go index 69f2e5c904..986e2c3337 100644 --- a/src/cmd/internal/gc/const.go +++ b/src/cmd/internal/gc/const.go @@ -16,7 +16,7 @@ func (n *Node) Int() int64 { if !Isconst(n, CTINT) { Fatal("Int(%v)", n) } - return Mpgetfix(n.Val.U.Xval) + return Mpgetfix(n.Val.U.(*Mpint)) } // SetInt sets n's value to i. @@ -25,7 +25,7 @@ func (n *Node) SetInt(i int64) { if !Isconst(n, CTINT) { Fatal("SetInt(%v)", n) } - Mpmovecfix(n.Val.U.Xval, i) + Mpmovecfix(n.Val.U.(*Mpint), i) } // SetBigInt sets n's value to x. @@ -34,7 +34,7 @@ func (n *Node) SetBigInt(x *big.Int) { if !Isconst(n, CTINT) { Fatal("SetBigInt(%v)", n) } - n.Val.U.Xval.Val.Set(x) + n.Val.U.(*Mpint).Val.Set(x) } // Bool returns n as an bool. @@ -43,7 +43,7 @@ func (n *Node) Bool() bool { if !Isconst(n, CTBOOL) { Fatal("Int(%v)", n) } - return n.Val.U.Bval + return n.Val.U.(bool) } /* @@ -57,7 +57,7 @@ func truncfltlit(oldv *Mpflt, t *Type) *Mpflt { var v Val v.Ctype = CTFLT - v.U.Fval = oldv + v.U = oldv overflow(v, t) fv := newMpflt() @@ -227,8 +227,8 @@ func convlit1(np **Node, t *Type, explicit bool) { // if it is an unsafe.Pointer case TUINTPTR: if n.Type.Etype == TUNSAFEPTR { - n.Val.U.Xval = new(Mpint) - Mpmovecfix(n.Val.U.Xval, 0) + n.Val.U = new(Mpint) + Mpmovecfix(n.Val.U.(*Mpint), 0) n.Val.Ctype = CTINT } else { goto bad @@ -269,7 +269,7 @@ func convlit1(np **Node, t *Type, explicit bool) { // flowthrough case CTFLT: - n.Val.U.Fval = truncfltlit(n.Val.U.Fval, t) + n.Val.U = truncfltlit(n.Val.U.(*Mpflt), t) } } else if Iscomplex[et] { switch ct { @@ -310,19 +310,19 @@ func copyval(v Val) Val { switch v.Ctype { case CTINT, CTRUNE: i := new(Mpint) - mpmovefixfix(i, v.U.Xval) - v.U.Xval = i + mpmovefixfix(i, v.U.(*Mpint)) + v.U = i case CTFLT: f := newMpflt() - mpmovefltflt(f, v.U.Fval) - v.U.Fval = f + mpmovefltflt(f, v.U.(*Mpflt)) + v.U = f case CTCPLX: c := new(Mpcplx) - mpmovefltflt(&c.Real, &v.U.Cval.Real) - mpmovefltflt(&c.Imag, &v.U.Cval.Imag) - v.U.Cval = c + mpmovefltflt(&c.Real, &v.U.(*Mpcplx).Real) + mpmovefltflt(&c.Imag, &v.U.(*Mpcplx).Imag) + v.U = c } return v @@ -332,17 +332,17 @@ func tocplx(v Val) Val { switch v.Ctype { case CTINT, CTRUNE: c := new(Mpcplx) - Mpmovefixflt(&c.Real, v.U.Xval) + Mpmovefixflt(&c.Real, v.U.(*Mpint)) Mpmovecflt(&c.Imag, 0.0) v.Ctype = CTCPLX - v.U.Cval = c + v.U = c case CTFLT: c := new(Mpcplx) - mpmovefltflt(&c.Real, v.U.Fval) + mpmovefltflt(&c.Real, v.U.(*Mpflt)) Mpmovecflt(&c.Imag, 0.0) v.Ctype = CTCPLX - v.U.Cval = c + v.U = c } return v @@ -352,18 +352,18 @@ func toflt(v Val) Val { switch v.Ctype { case CTINT, CTRUNE: f := newMpflt() - Mpmovefixflt(f, v.U.Xval) + Mpmovefixflt(f, v.U.(*Mpint)) v.Ctype = CTFLT - v.U.Fval = f + v.U = f case CTCPLX: f := newMpflt() - mpmovefltflt(f, &v.U.Cval.Real) - if mpcmpfltc(&v.U.Cval.Imag, 0) != 0 { - Yyerror("constant %v%vi truncated to real", Fconv(&v.U.Cval.Real, obj.FmtSharp), Fconv(&v.U.Cval.Imag, obj.FmtSharp|obj.FmtSign)) + mpmovefltflt(f, &v.U.(*Mpcplx).Real) + if mpcmpfltc(&v.U.(*Mpcplx).Imag, 0) != 0 { + Yyerror("constant %v%vi truncated to real", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp|obj.FmtSign)) } v.Ctype = CTFLT - v.U.Fval = f + v.U = f } return v @@ -376,22 +376,22 @@ func toint(v Val) Val { case CTFLT: i := new(Mpint) - if mpmovefltfix(i, v.U.Fval) < 0 { - Yyerror("constant %v truncated to integer", Fconv(v.U.Fval, obj.FmtSharp)) + if mpmovefltfix(i, v.U.(*Mpflt)) < 0 { + Yyerror("constant %v truncated to integer", Fconv(v.U.(*Mpflt), obj.FmtSharp)) } v.Ctype = CTINT - v.U.Xval = i + v.U = i case CTCPLX: i := new(Mpint) - if mpmovefltfix(i, &v.U.Cval.Real) < 0 { - Yyerror("constant %v%vi truncated to integer", Fconv(&v.U.Cval.Real, obj.FmtSharp), Fconv(&v.U.Cval.Imag, obj.FmtSharp|obj.FmtSign)) + if mpmovefltfix(i, &v.U.(*Mpcplx).Real) < 0 { + Yyerror("constant %v%vi truncated to integer", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp|obj.FmtSign)) } - if mpcmpfltc(&v.U.Cval.Imag, 0) != 0 { - Yyerror("constant %v%vi truncated to real", Fconv(&v.U.Cval.Real, obj.FmtSharp), Fconv(&v.U.Cval.Imag, obj.FmtSharp|obj.FmtSign)) + if mpcmpfltc(&v.U.(*Mpcplx).Imag, 0) != 0 { + Yyerror("constant %v%vi truncated to real", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp|obj.FmtSign)) } v.Ctype = CTINT - v.U.Xval = i + v.U = i } return v @@ -403,7 +403,7 @@ func doesoverflow(v Val, t *Type) bool { if !Isint[t.Etype] { Fatal("overflow: %v integer constant", t) } - if Mpcmpfixfix(v.U.Xval, Minintval[t.Etype]) < 0 || Mpcmpfixfix(v.U.Xval, Maxintval[t.Etype]) > 0 { + if Mpcmpfixfix(v.U.(*Mpint), Minintval[t.Etype]) < 0 || Mpcmpfixfix(v.U.(*Mpint), Maxintval[t.Etype]) > 0 { return true } @@ -411,7 +411,7 @@ func doesoverflow(v Val, t *Type) bool { if !Isfloat[t.Etype] { Fatal("overflow: %v floating-point constant", t) } - if mpcmpfltflt(v.U.Fval, minfltval[t.Etype]) <= 0 || mpcmpfltflt(v.U.Fval, maxfltval[t.Etype]) >= 0 { + if mpcmpfltflt(v.U.(*Mpflt), minfltval[t.Etype]) <= 0 || mpcmpfltflt(v.U.(*Mpflt), maxfltval[t.Etype]) >= 0 { return true } @@ -419,7 +419,7 @@ func doesoverflow(v Val, t *Type) bool { if !Iscomplex[t.Etype] { Fatal("overflow: %v complex constant", t) } - if mpcmpfltflt(&v.U.Cval.Real, minfltval[t.Etype]) <= 0 || mpcmpfltflt(&v.U.Cval.Real, maxfltval[t.Etype]) >= 0 || mpcmpfltflt(&v.U.Cval.Imag, minfltval[t.Etype]) <= 0 || mpcmpfltflt(&v.U.Cval.Imag, maxfltval[t.Etype]) >= 0 { + if mpcmpfltflt(&v.U.(*Mpcplx).Real, minfltval[t.Etype]) <= 0 || mpcmpfltflt(&v.U.(*Mpcplx).Real, maxfltval[t.Etype]) >= 0 || mpcmpfltflt(&v.U.(*Mpcplx).Imag, minfltval[t.Etype]) <= 0 || mpcmpfltflt(&v.U.(*Mpcplx).Imag, maxfltval[t.Etype]) >= 0 { return true } } @@ -445,26 +445,26 @@ func overflow(v Val, t *Type) { switch v.Ctype { case CTINT, CTRUNE: - Yyerror("constant %v overflows %v", v.U.Xval, t) + Yyerror("constant %v overflows %v", v.U.(*Mpint), t) case CTFLT: - Yyerror("constant %v overflows %v", Fconv(v.U.Fval, obj.FmtSharp), t) + Yyerror("constant %v overflows %v", Fconv(v.U.(*Mpflt), obj.FmtSharp), t) case CTCPLX: - Yyerror("constant %v overflows %v", Fconv(v.U.Fval, obj.FmtSharp), t) + Yyerror("constant %v overflows %v", Fconv(v.U.(*Mpflt), obj.FmtSharp), t) } } func tostr(v Val) Val { switch v.Ctype { case CTINT, CTRUNE: - if Mpcmpfixfix(v.U.Xval, Minintval[TINT]) < 0 || Mpcmpfixfix(v.U.Xval, Maxintval[TINT]) > 0 { + if Mpcmpfixfix(v.U.(*Mpint), Minintval[TINT]) < 0 || Mpcmpfixfix(v.U.(*Mpint), Maxintval[TINT]) > 0 { Yyerror("overflow in int -> string") } - r := uint(Mpgetfix(v.U.Xval)) + r := uint(Mpgetfix(v.U.(*Mpint))) v = Val{} v.Ctype = CTSTR - v.U.Sval = string(r) + v.U = string(r) case CTFLT: Yyerror("no float -> string") @@ -473,7 +473,7 @@ func tostr(v Val) Val { case CTNIL: v = Val{} v.Ctype = CTSTR - v.U.Sval = "" + v.U = "" } return v @@ -562,7 +562,7 @@ func evconst(n *Node) { l2 = l1 for l2 != nil && Isconst(l2.N, CTSTR) { nr = l2.N - strs = append(strs, nr.Val.U.Sval) + strs = append(strs, nr.Val.U.(string)) l2 = l2.Next } @@ -570,7 +570,7 @@ func evconst(n *Node) { *nl = *l1.N nl.Orig = nl nl.Val.Ctype = CTSTR - nl.Val.U.Sval = strings.Join(strs, "") + nl.Val.U = strings.Join(strs, "") l1.N = nl l1.Next = l2 } @@ -650,7 +650,7 @@ func evconst(n *Node) { case OMINUS<<16 | CTINT, OMINUS<<16 | CTRUNE: - mpnegfix(v.U.Xval) + mpnegfix(v.U.(*Mpint)) case OCOM<<16 | CTINT, OCOM<<16 | CTRUNE: @@ -677,23 +677,23 @@ func evconst(n *Node) { mpmovefixfix(&b, Maxintval[et]) } - mpxorfixfix(v.U.Xval, &b) + mpxorfixfix(v.U.(*Mpint), &b) case OPLUS<<16 | CTFLT: break case OMINUS<<16 | CTFLT: - mpnegflt(v.U.Fval) + mpnegflt(v.U.(*Mpflt)) case OPLUS<<16 | CTCPLX: break case OMINUS<<16 | CTCPLX: - mpnegflt(&v.U.Cval.Real) - mpnegflt(&v.U.Cval.Imag) + mpnegflt(&v.U.(*Mpcplx).Real) + mpnegflt(&v.U.(*Mpcplx).Imag) case ONOT<<16 | CTBOOL: - if !v.U.Bval { + if !v.U.(bool) { goto settrue } goto setfalse @@ -797,77 +797,77 @@ func evconst(n *Node) { case OADD<<16 | CTINT, OADD<<16 | CTRUNE: - mpaddfixfix(v.U.Xval, rv.U.Xval, 0) + mpaddfixfix(v.U.(*Mpint), rv.U.(*Mpint), 0) case OSUB<<16 | CTINT, OSUB<<16 | CTRUNE: - mpsubfixfix(v.U.Xval, rv.U.Xval) + mpsubfixfix(v.U.(*Mpint), rv.U.(*Mpint)) case OMUL<<16 | CTINT, OMUL<<16 | CTRUNE: - mpmulfixfix(v.U.Xval, rv.U.Xval) + mpmulfixfix(v.U.(*Mpint), rv.U.(*Mpint)) case ODIV<<16 | CTINT, ODIV<<16 | CTRUNE: - if mpcmpfixc(rv.U.Xval, 0) == 0 { + if mpcmpfixc(rv.U.(*Mpint), 0) == 0 { Yyerror("division by zero") - mpsetovf(v.U.Xval) + mpsetovf(v.U.(*Mpint)) break } - mpdivfixfix(v.U.Xval, rv.U.Xval) + mpdivfixfix(v.U.(*Mpint), rv.U.(*Mpint)) case OMOD<<16 | CTINT, OMOD<<16 | CTRUNE: - if mpcmpfixc(rv.U.Xval, 0) == 0 { + if mpcmpfixc(rv.U.(*Mpint), 0) == 0 { Yyerror("division by zero") - mpsetovf(v.U.Xval) + mpsetovf(v.U.(*Mpint)) break } - mpmodfixfix(v.U.Xval, rv.U.Xval) + mpmodfixfix(v.U.(*Mpint), rv.U.(*Mpint)) case OLSH<<16 | CTINT, OLSH<<16 | CTRUNE: - mplshfixfix(v.U.Xval, rv.U.Xval) + mplshfixfix(v.U.(*Mpint), rv.U.(*Mpint)) case ORSH<<16 | CTINT, ORSH<<16 | CTRUNE: - mprshfixfix(v.U.Xval, rv.U.Xval) + mprshfixfix(v.U.(*Mpint), rv.U.(*Mpint)) case OOR<<16 | CTINT, OOR<<16 | CTRUNE: - mporfixfix(v.U.Xval, rv.U.Xval) + mporfixfix(v.U.(*Mpint), rv.U.(*Mpint)) case OAND<<16 | CTINT, OAND<<16 | CTRUNE: - mpandfixfix(v.U.Xval, rv.U.Xval) + mpandfixfix(v.U.(*Mpint), rv.U.(*Mpint)) case OANDNOT<<16 | CTINT, OANDNOT<<16 | CTRUNE: - mpandnotfixfix(v.U.Xval, rv.U.Xval) + mpandnotfixfix(v.U.(*Mpint), rv.U.(*Mpint)) case OXOR<<16 | CTINT, OXOR<<16 | CTRUNE: - mpxorfixfix(v.U.Xval, rv.U.Xval) + mpxorfixfix(v.U.(*Mpint), rv.U.(*Mpint)) case OADD<<16 | CTFLT: - mpaddfltflt(v.U.Fval, rv.U.Fval) + mpaddfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) case OSUB<<16 | CTFLT: - mpsubfltflt(v.U.Fval, rv.U.Fval) + mpsubfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) case OMUL<<16 | CTFLT: - mpmulfltflt(v.U.Fval, rv.U.Fval) + mpmulfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) case ODIV<<16 | CTFLT: - if mpcmpfltc(rv.U.Fval, 0) == 0 { + if mpcmpfltc(rv.U.(*Mpflt), 0) == 0 { Yyerror("division by zero") - Mpmovecflt(v.U.Fval, 1.0) + Mpmovecflt(v.U.(*Mpflt), 1.0) break } - mpdivfltflt(v.U.Fval, rv.U.Fval) + mpdivfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) // The default case above would print 'ideal % ideal', // which is not quite an ideal error. @@ -880,25 +880,25 @@ func evconst(n *Node) { return case OADD<<16 | CTCPLX: - mpaddfltflt(&v.U.Cval.Real, &rv.U.Cval.Real) - mpaddfltflt(&v.U.Cval.Imag, &rv.U.Cval.Imag) + mpaddfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real) + mpaddfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag) case OSUB<<16 | CTCPLX: - mpsubfltflt(&v.U.Cval.Real, &rv.U.Cval.Real) - mpsubfltflt(&v.U.Cval.Imag, &rv.U.Cval.Imag) + mpsubfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real) + mpsubfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag) case OMUL<<16 | CTCPLX: - cmplxmpy(v.U.Cval, rv.U.Cval) + cmplxmpy(v.U.(*Mpcplx), rv.U.(*Mpcplx)) case ODIV<<16 | CTCPLX: - if mpcmpfltc(&rv.U.Cval.Real, 0) == 0 && mpcmpfltc(&rv.U.Cval.Imag, 0) == 0 { + if mpcmpfltc(&rv.U.(*Mpcplx).Real, 0) == 0 && mpcmpfltc(&rv.U.(*Mpcplx).Imag, 0) == 0 { Yyerror("complex division by zero") - Mpmovecflt(&rv.U.Cval.Real, 1.0) - Mpmovecflt(&rv.U.Cval.Imag, 0.0) + Mpmovecflt(&rv.U.(*Mpcplx).Real, 1.0) + Mpmovecflt(&rv.U.(*Mpcplx).Imag, 0.0) break } - cmplxdiv(v.U.Cval, rv.U.Cval) + cmplxdiv(v.U.(*Mpcplx), rv.U.(*Mpcplx)) case OEQ<<16 | CTNIL: goto settrue @@ -908,90 +908,90 @@ func evconst(n *Node) { case OEQ<<16 | CTINT, OEQ<<16 | CTRUNE: - if Mpcmpfixfix(v.U.Xval, rv.U.Xval) == 0 { + if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) == 0 { goto settrue } goto setfalse case ONE<<16 | CTINT, ONE<<16 | CTRUNE: - if Mpcmpfixfix(v.U.Xval, rv.U.Xval) != 0 { + if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) != 0 { goto settrue } goto setfalse case OLT<<16 | CTINT, OLT<<16 | CTRUNE: - if Mpcmpfixfix(v.U.Xval, rv.U.Xval) < 0 { + if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) < 0 { goto settrue } goto setfalse case OLE<<16 | CTINT, OLE<<16 | CTRUNE: - if Mpcmpfixfix(v.U.Xval, rv.U.Xval) <= 0 { + if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) <= 0 { goto settrue } goto setfalse case OGE<<16 | CTINT, OGE<<16 | CTRUNE: - if Mpcmpfixfix(v.U.Xval, rv.U.Xval) >= 0 { + if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) >= 0 { goto settrue } goto setfalse case OGT<<16 | CTINT, OGT<<16 | CTRUNE: - if Mpcmpfixfix(v.U.Xval, rv.U.Xval) > 0 { + if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) > 0 { goto settrue } goto setfalse case OEQ<<16 | CTFLT: - if mpcmpfltflt(v.U.Fval, rv.U.Fval) == 0 { + if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) == 0 { goto settrue } goto setfalse case ONE<<16 | CTFLT: - if mpcmpfltflt(v.U.Fval, rv.U.Fval) != 0 { + if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) != 0 { goto settrue } goto setfalse case OLT<<16 | CTFLT: - if mpcmpfltflt(v.U.Fval, rv.U.Fval) < 0 { + if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) < 0 { goto settrue } goto setfalse case OLE<<16 | CTFLT: - if mpcmpfltflt(v.U.Fval, rv.U.Fval) <= 0 { + if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) <= 0 { goto settrue } goto setfalse case OGE<<16 | CTFLT: - if mpcmpfltflt(v.U.Fval, rv.U.Fval) >= 0 { + if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) >= 0 { goto settrue } goto setfalse case OGT<<16 | CTFLT: - if mpcmpfltflt(v.U.Fval, rv.U.Fval) > 0 { + if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) > 0 { goto settrue } goto setfalse case OEQ<<16 | CTCPLX: - if mpcmpfltflt(&v.U.Cval.Real, &rv.U.Cval.Real) == 0 && mpcmpfltflt(&v.U.Cval.Imag, &rv.U.Cval.Imag) == 0 { + if mpcmpfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real) == 0 && mpcmpfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag) == 0 { goto settrue } goto setfalse case ONE<<16 | CTCPLX: - if mpcmpfltflt(&v.U.Cval.Real, &rv.U.Cval.Real) != 0 || mpcmpfltflt(&v.U.Cval.Imag, &rv.U.Cval.Imag) != 0 { + if mpcmpfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real) != 0 || mpcmpfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag) != 0 { goto settrue } goto setfalse @@ -1033,25 +1033,25 @@ func evconst(n *Node) { goto setfalse case OOROR<<16 | CTBOOL: - if v.U.Bval || rv.U.Bval { + if v.U.(bool) || rv.U.(bool) { goto settrue } goto setfalse case OANDAND<<16 | CTBOOL: - if v.U.Bval && rv.U.Bval { + if v.U.(bool) && rv.U.(bool) { goto settrue } goto setfalse case OEQ<<16 | CTBOOL: - if v.U.Bval == rv.U.Bval { + if v.U.(bool) == rv.U.(bool) { goto settrue } goto setfalse case ONE<<16 | CTBOOL: - if v.U.Bval != rv.U.Bval { + if v.U.(bool) != rv.U.(bool) { goto settrue } goto setfalse @@ -1076,7 +1076,7 @@ ret: // truncate precision for non-ideal float. if v.Ctype == CTFLT && n.Type.Etype != TIDEAL { - n.Val.U.Fval = truncfltlit(v.U.Fval, n.Type) + n.Val.U = truncfltlit(v.U.(*Mpflt), n.Type) } return @@ -1131,15 +1131,15 @@ func nodcplxlit(r Val, i Val) *Node { c := new(Mpcplx) n := Nod(OLITERAL, nil, nil) n.Type = Types[TIDEAL] - n.Val.U.Cval = c + n.Val.U = c n.Val.Ctype = CTCPLX if r.Ctype != CTFLT || i.Ctype != CTFLT { Fatal("nodcplxlit ctype %d/%d", r.Ctype, i.Ctype) } - mpmovefltflt(&c.Real, r.U.Fval) - mpmovefltflt(&c.Imag, i.U.Fval) + mpmovefltflt(&c.Real, r.U.(*Mpflt)) + mpmovefltflt(&c.Imag, i.U.(*Mpflt)) return n } @@ -1354,7 +1354,7 @@ func defaultlit2(lp **Node, rp **Node, force int) { } func cmpslit(l, r *Node) int { - return stringsCompare(l.Val.U.Sval, r.Val.U.Sval) + return stringsCompare(l.Val.U.(string), r.Val.U.(string)) } func Smallintconst(n *Node) bool { @@ -1371,7 +1371,7 @@ func Smallintconst(n *Node) bool { return true case TIDEAL, TINT64, TUINT64, TPTR64: - if Mpcmpfixfix(n.Val.U.Xval, Minintval[TINT32]) < 0 || Mpcmpfixfix(n.Val.U.Xval, Maxintval[TINT32]) > 0 { + if Mpcmpfixfix(n.Val.U.(*Mpint), Minintval[TINT32]) < 0 || Mpcmpfixfix(n.Val.U.(*Mpint), Maxintval[TINT32]) > 0 { break } return true @@ -1394,10 +1394,10 @@ func nonnegconst(n *Node) int { TINT64, TUINT64, TIDEAL: - if Mpcmpfixfix(n.Val.U.Xval, Minintval[TUINT32]) < 0 || Mpcmpfixfix(n.Val.U.Xval, Maxintval[TINT32]) > 0 { + if Mpcmpfixfix(n.Val.U.(*Mpint), Minintval[TUINT32]) < 0 || Mpcmpfixfix(n.Val.U.(*Mpint), Maxintval[TINT32]) > 0 { break } - return int(Mpgetfix(n.Val.U.Xval)) + return int(Mpgetfix(n.Val.U.(*Mpint))) } } @@ -1448,24 +1448,24 @@ func (n *Node) Convconst(con *Node, t *Type) { if Isint[tt] { con.Val.Ctype = CTINT - con.Val.U.Xval = new(Mpint) + con.Val.U = new(Mpint) var i int64 switch n.Val.Ctype { default: Fatal("convconst ctype=%d %v", n.Val.Ctype, Tconv(t, obj.FmtLong)) case CTINT, CTRUNE: - i = Mpgetfix(n.Val.U.Xval) + i = Mpgetfix(n.Val.U.(*Mpint)) case CTBOOL: - i = int64(obj.Bool2int(n.Val.U.Bval)) + i = int64(obj.Bool2int(n.Val.U.(bool))) case CTNIL: i = 0 } i = iconv(i, tt) - Mpmovecfix(con.Val.U.Xval, i) + Mpmovecfix(con.Val.U.(*Mpint), i) return } @@ -1475,7 +1475,7 @@ func (n *Node) Convconst(con *Node, t *Type) { Fatal("convconst ctype=%d %v", con.Val.Ctype, t) } if tt == TFLOAT32 { - con.Val.U.Fval = truncfltlit(con.Val.U.Fval, t) + con.Val.U = truncfltlit(con.Val.U.(*Mpflt), t) } return } @@ -1483,8 +1483,8 @@ func (n *Node) Convconst(con *Node, t *Type) { if Iscomplex[tt] { con.Val = tocplx(con.Val) if tt == TCOMPLEX64 { - con.Val.U.Cval.Real = *truncfltlit(&con.Val.U.Cval.Real, Types[TFLOAT32]) - con.Val.U.Cval.Imag = *truncfltlit(&con.Val.U.Cval.Imag, Types[TFLOAT32]) + con.Val.U.(*Mpcplx).Real = *truncfltlit(&con.Val.U.(*Mpcplx).Real, Types[TFLOAT32]) + con.Val.U.(*Mpcplx).Imag = *truncfltlit(&con.Val.U.(*Mpcplx).Imag, Types[TFLOAT32]) } return } diff --git a/src/cmd/internal/gc/cplx.go b/src/cmd/internal/gc/cplx.go index cf48c922d7..56a4892636 100644 --- a/src/cmd/internal/gc/cplx.go +++ b/src/cmd/internal/gc/cplx.go @@ -89,8 +89,8 @@ func subnode(nr *Node, ni *Node, nc *Node) { t := Types[tc] if nc.Op == OLITERAL { - nodfconst(nr, t, &nc.Val.U.Cval.Real) - nodfconst(ni, t, &nc.Val.U.Cval.Imag) + nodfconst(nr, t, &nc.Val.U.(*Mpcplx).Real) + nodfconst(ni, t, &nc.Val.U.(*Mpcplx).Imag) return } @@ -226,7 +226,7 @@ func nodfconst(n *Node, t *Type, fval *Mpflt) { n.Op = OLITERAL n.Addable = true ullmancalc(n) - n.Val.U.Fval = fval + n.Val.U = fval n.Val.Ctype = CTFLT n.Type = t diff --git a/src/cmd/internal/gc/dcl.go b/src/cmd/internal/gc/dcl.go index 627556eeef..85a33bec3f 100644 --- a/src/cmd/internal/gc/dcl.go +++ b/src/cmd/internal/gc/dcl.go @@ -830,7 +830,7 @@ func structfield(n *Node) *Type { switch n.Val.Ctype { case CTSTR: f.Note = new(string) - *f.Note = n.Val.U.Sval + *f.Note = n.Val.U.(string) default: Yyerror("field annotation must be string") diff --git a/src/cmd/internal/gc/fmt.go b/src/cmd/internal/gc/fmt.go index 4e3045a929..9d8482bf76 100644 --- a/src/cmd/internal/gc/fmt.go +++ b/src/cmd/internal/gc/fmt.go @@ -302,12 +302,12 @@ func Vconv(v *Val, flag int) string { switch v.Ctype { case CTINT: if (flag&obj.FmtSharp != 0) || fmtmode == FExp { - return Bconv(v.U.Xval, obj.FmtSharp) + return Bconv(v.U.(*Mpint), obj.FmtSharp) } - return Bconv(v.U.Xval, 0) + return Bconv(v.U.(*Mpint), 0) case CTRUNE: - x := Mpgetfix(v.U.Xval) + x := Mpgetfix(v.U.(*Mpint)) if ' ' <= x && x < 0x80 && x != '\\' && x != '\'' { return fmt.Sprintf("'%c'", int(x)) } @@ -317,34 +317,34 @@ func Vconv(v *Val, flag int) string { if 0 <= x && x <= utf8.MaxRune { return fmt.Sprintf("'\\U%08x'", uint64(x)) } - return fmt.Sprintf("('\\x00' + %v)", v.U.Xval) + return fmt.Sprintf("('\\x00' + %v)", v.U.(*Mpint)) case CTFLT: if (flag&obj.FmtSharp != 0) || fmtmode == FExp { - return Fconv(v.U.Fval, 0) + return Fconv(v.U.(*Mpflt), 0) } - return Fconv(v.U.Fval, obj.FmtSharp) + return Fconv(v.U.(*Mpflt), obj.FmtSharp) case CTCPLX: if (flag&obj.FmtSharp != 0) || fmtmode == FExp { - return fmt.Sprintf("(%v+%vi)", &v.U.Cval.Real, &v.U.Cval.Imag) + return fmt.Sprintf("(%v+%vi)", &v.U.(*Mpcplx).Real, &v.U.(*Mpcplx).Imag) } - if mpcmpfltc(&v.U.Cval.Real, 0) == 0 { - return fmt.Sprintf("%vi", Fconv(&v.U.Cval.Imag, obj.FmtSharp)) + if mpcmpfltc(&v.U.(*Mpcplx).Real, 0) == 0 { + return fmt.Sprintf("%vi", Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp)) } - if mpcmpfltc(&v.U.Cval.Imag, 0) == 0 { - return Fconv(&v.U.Cval.Real, obj.FmtSharp) + if mpcmpfltc(&v.U.(*Mpcplx).Imag, 0) == 0 { + return Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp) } - if mpcmpfltc(&v.U.Cval.Imag, 0) < 0 { - return fmt.Sprintf("(%v%vi)", Fconv(&v.U.Cval.Real, obj.FmtSharp), Fconv(&v.U.Cval.Imag, obj.FmtSharp)) + if mpcmpfltc(&v.U.(*Mpcplx).Imag, 0) < 0 { + return fmt.Sprintf("(%v%vi)", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp)) } - return fmt.Sprintf("(%v+%vi)", Fconv(&v.U.Cval.Real, obj.FmtSharp), Fconv(&v.U.Cval.Imag, obj.FmtSharp)) + return fmt.Sprintf("(%v+%vi)", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp)) case CTSTR: - return strconv.Quote(v.U.Sval) + return strconv.Quote(v.U.(string)) case CTBOOL: - if v.U.Bval { + if v.U.(bool) { return "true" } return "false" diff --git a/src/cmd/internal/gc/gen.go b/src/cmd/internal/gc/gen.go index 8f6a43c121..cd0e650ca9 100644 --- a/src/cmd/internal/gc/gen.go +++ b/src/cmd/internal/gc/gen.go @@ -333,22 +333,22 @@ func Clearslim(n *Node) { switch Simtype[n.Type.Etype] { case TCOMPLEX64, TCOMPLEX128: - z.Val.U.Cval = new(Mpcplx) - Mpmovecflt(&z.Val.U.Cval.Real, 0.0) - Mpmovecflt(&z.Val.U.Cval.Imag, 0.0) + z.Val.U = new(Mpcplx) + Mpmovecflt(&z.Val.U.(*Mpcplx).Real, 0.0) + Mpmovecflt(&z.Val.U.(*Mpcplx).Imag, 0.0) case TFLOAT32, TFLOAT64: var zero Mpflt Mpmovecflt(&zero, 0.0) z.Val.Ctype = CTFLT - z.Val.U.Fval = &zero + z.Val.U = &zero case TPTR32, TPTR64, TCHAN, TMAP: z.Val.Ctype = CTNIL case TBOOL: z.Val.Ctype = CTBOOL - z.Val.U.Bval = false + z.Val.U = false case TINT8, TINT16, @@ -359,8 +359,8 @@ func Clearslim(n *Node) { TUINT32, TUINT64: z.Val.Ctype = CTINT - z.Val.U.Xval = new(Mpint) - Mpmovecfix(z.Val.U.Xval, 0) + z.Val.U = new(Mpint) + Mpmovecfix(z.Val.U.(*Mpint), 0) default: Fatal("clearslim called on type %v", n.Type) @@ -1122,7 +1122,7 @@ func componentgen_wb(nr, nl *Node, wb bool) bool { nodl.Type = Ptrto(Types[TUINT8]) Regalloc(&nodr, Types[Tptr], nil) p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &nodr) - Datastring(nr.Val.U.Sval, &p.From) + Datastring(nr.Val.U.(string), &p.From) p.From.Type = obj.TYPE_ADDR Thearch.Gmove(&nodr, &nodl) Regfree(&nodr) @@ -1130,7 +1130,7 @@ func componentgen_wb(nr, nl *Node, wb bool) bool { // length nodl.Type = Types[Simtype[TUINT]] nodl.Xoffset += int64(Array_nel) - int64(Array_array) - Nodconst(&nodr, nodl.Type, int64(len(nr.Val.U.Sval))) + Nodconst(&nodr, nodl.Type, int64(len(nr.Val.U.(string)))) Thearch.Gmove(&nodr, &nodl) return true } diff --git a/src/cmd/internal/gc/go.go b/src/cmd/internal/gc/go.go index 404dcbb4ff..31692bdf00 100644 --- a/src/cmd/internal/gc/go.go +++ b/src/cmd/internal/gc/go.go @@ -83,13 +83,13 @@ type Mpcplx struct { type Val struct { Ctype int16 - U struct { - Bval bool // bool value CTBOOL - Xval *Mpint // int CTINT, rune CTRUNE - Fval *Mpflt // float CTFLT - Cval *Mpcplx // float CTCPLX - Sval string // string CTSTR - } + // U contains one of: + // bool bool when Ctype == CTBOOL + // *Mpint int when Ctype == CTINT, rune when Ctype == CTRUNE + // *Mpflt float when Ctype == CTFLT + // *Mpcplx pair of floats when Ctype == CTCPLX + // string string when Ctype == CTSTR + U interface{} } type Pkg struct { diff --git a/src/cmd/internal/gc/go.y b/src/cmd/internal/gc/go.y index bbee200889..e2e4331a77 100644 --- a/src/cmd/internal/gc/go.y +++ b/src/cmd/internal/gc/go.y @@ -1131,13 +1131,13 @@ hidden_importsym: { var p *Pkg - if $2.U.Sval == "" { + if $2.U.(string) == "" { p = importpkg; } else { - if isbadimport($2.U.Sval) { + if isbadimport($2.U.(string)) { errorexit(); } - p = mkpkg($2.U.Sval); + p = mkpkg($2.U.(string)); } $$ = Pkglookup($4.Name, p); } @@ -1145,13 +1145,13 @@ hidden_importsym: { var p *Pkg - if $2.U.Sval == "" { + if $2.U.(string) == "" { p = importpkg; } else { - if isbadimport($2.U.Sval) { + if isbadimport($2.U.(string)) { errorexit(); } - p = mkpkg($2.U.Sval); + p = mkpkg($2.U.(string)); } $$ = Pkglookup("?", p); } @@ -1945,7 +1945,7 @@ oliteral: hidden_import: LIMPORT LNAME LLITERAL ';' { - importimport($2, $3.U.Sval); + importimport($2, $3.U.(string)); } | LVAR hidden_pkg_importsym hidden_type ';' { @@ -2172,14 +2172,14 @@ hidden_literal: $$ = nodlit($2); switch($$.Val.Ctype){ case CTINT, CTRUNE: - mpnegfix($$.Val.U.Xval); + mpnegfix($$.Val.U.(*Mpint)); break; case CTFLT: - mpnegflt($$.Val.U.Fval); + mpnegflt($$.Val.U.(*Mpflt)); break; case CTCPLX: - mpnegflt(&$$.Val.U.Cval.Real); - mpnegflt(&$$.Val.U.Cval.Imag); + mpnegflt(&$$.Val.U.(*Mpcplx).Real); + mpnegflt(&$$.Val.U.(*Mpcplx).Imag); break; default: Yyerror("bad negated constant"); @@ -2199,11 +2199,11 @@ hidden_constant: { if $2.Val.Ctype == CTRUNE && $4.Val.Ctype == CTINT { $$ = $2; - mpaddfixfix($2.Val.U.Xval, $4.Val.U.Xval, 0); + mpaddfixfix($2.Val.U.(*Mpint), $4.Val.U.(*Mpint), 0); break; } - $4.Val.U.Cval.Real = $4.Val.U.Cval.Imag; - Mpmovecflt(&$4.Val.U.Cval.Imag, 0.0); + $4.Val.U.(*Mpcplx).Real = $4.Val.U.(*Mpcplx).Imag; + Mpmovecflt(&$4.Val.U.(*Mpcplx).Imag, 0.0); $$ = nodcplxlit($2.Val, $4.Val); } diff --git a/src/cmd/internal/gc/gsubr.go b/src/cmd/internal/gc/gsubr.go index 93e4852b6f..98d6346e2a 100644 --- a/src/cmd/internal/gc/gsubr.go +++ b/src/cmd/internal/gc/gsubr.go @@ -412,20 +412,20 @@ func Naddr(a *obj.Addr, n *Node) { case CTFLT: a.Type = obj.TYPE_FCONST - a.Val = mpgetflt(n.Val.U.Fval) + a.Val = mpgetflt(n.Val.U.(*Mpflt)) case CTINT, CTRUNE: a.Sym = nil a.Type = obj.TYPE_CONST - a.Offset = Mpgetfix(n.Val.U.Xval) + a.Offset = Mpgetfix(n.Val.U.(*Mpint)) case CTSTR: - datagostring(n.Val.U.Sval, a) + datagostring(n.Val.U.(string), a) case CTBOOL: a.Sym = nil a.Type = obj.TYPE_CONST - a.Offset = int64(obj.Bool2int(n.Val.U.Bval)) + a.Offset = int64(obj.Bool2int(n.Val.U.(bool))) case CTNIL: a.Sym = nil diff --git a/src/cmd/internal/gc/lex.go b/src/cmd/internal/gc/lex.go index 96a1a01aaa..1bf0758000 100644 --- a/src/cmd/internal/gc/lex.go +++ b/src/cmd/internal/gc/lex.go @@ -647,13 +647,13 @@ func importfile(f *Val, line int) { return } - if len(f.U.Sval) == 0 { + if len(f.U.(string)) == 0 { Yyerror("import path is empty") fakeimport() return } - if isbadimport(f.U.Sval) { + if isbadimport(f.U.(string)) { fakeimport() return } @@ -662,29 +662,29 @@ func importfile(f *Val, line int) { // but we reserve the import path "main" to identify // the main package, just as we reserve the import // path "math" to identify the standard math package. - if f.U.Sval == "main" { + if f.U.(string) == "main" { Yyerror("cannot import \"main\"") errorexit() } - if myimportpath != "" && f.U.Sval == myimportpath { - Yyerror("import %q while compiling that package (import cycle)", f.U.Sval) + if myimportpath != "" && f.U.(string) == myimportpath { + Yyerror("import %q while compiling that package (import cycle)", f.U.(string)) errorexit() } - if f.U.Sval == "unsafe" { + if f.U.(string) == "unsafe" { if safemode != 0 { Yyerror("cannot import package unsafe") errorexit() } - importpkg = mkpkg(f.U.Sval) + importpkg = mkpkg(f.U.(string)) cannedimports("unsafe.6", unsafeimport) imported_unsafe = 1 return } - path_ := f.U.Sval + path_ := f.U.(string) if islocalname(path_) { if path_[0] == '/' { Yyerror("import path cannot be absolute path") @@ -710,7 +710,7 @@ func importfile(f *Val, line int) { file, found := findpkg(path_) if !found { - Yyerror("can't find import: %q", f.U.Sval) + Yyerror("can't find import: %q", f.U.(string)) errorexit() } @@ -735,7 +735,7 @@ func importfile(f *Val, line int) { var imp *obj.Biobuf imp, err = obj.Bopenr(file) if err != nil { - Yyerror("can't open import: %q: %v", f.U.Sval, err) + Yyerror("can't open import: %q: %v", f.U.(string), err) errorexit() } @@ -798,7 +798,7 @@ func importfile(f *Val, line int) { return } - Yyerror("no import in %q", f.U.Sval) + Yyerror("no import in %q", f.U.(string)) unimportfile() } @@ -1066,8 +1066,8 @@ l0: ungetc(int(v)) } - yylval.val.U.Xval = new(Mpint) - Mpmovecfix(yylval.val.U.Xval, v) + yylval.val.U = new(Mpint) + Mpmovecfix(yylval.val.U.(*Mpint), v) yylval.val.Ctype = CTRUNE if Debug['x'] != 0 { fmt.Printf("lex: codepoint literal\n") @@ -1405,11 +1405,11 @@ ncu: ungetc(c) str = lexbuf.String() - yylval.val.U.Xval = new(Mpint) - mpatofix(yylval.val.U.Xval, str) - if yylval.val.U.Xval.Ovf { + yylval.val.U = new(Mpint) + mpatofix(yylval.val.U.(*Mpint), str) + if yylval.val.U.(*Mpint).Ovf { Yyerror("overflow in constant") - Mpmovecfix(yylval.val.U.Xval, 0) + Mpmovecfix(yylval.val.U.(*Mpint), 0) } yylval.val.Ctype = CTINT @@ -1461,12 +1461,12 @@ casei: cp = nil str = lexbuf.String() - yylval.val.U.Cval = new(Mpcplx) - Mpmovecflt(&yylval.val.U.Cval.Real, 0.0) - mpatoflt(&yylval.val.U.Cval.Imag, str) - if yylval.val.U.Cval.Imag.Val.IsInf() { + yylval.val.U = new(Mpcplx) + Mpmovecflt(&yylval.val.U.(*Mpcplx).Real, 0.0) + mpatoflt(&yylval.val.U.(*Mpcplx).Imag, str) + if yylval.val.U.(*Mpcplx).Imag.Val.IsInf() { Yyerror("overflow in imaginary constant") - Mpmovecflt(&yylval.val.U.Cval.Real, 0.0) + Mpmovecflt(&yylval.val.U.(*Mpcplx).Real, 0.0) } yylval.val.Ctype = CTCPLX @@ -1481,11 +1481,11 @@ caseout: ungetc(c) str = lexbuf.String() - yylval.val.U.Fval = newMpflt() - mpatoflt(yylval.val.U.Fval, str) - if yylval.val.U.Fval.Val.IsInf() { + yylval.val.U = newMpflt() + mpatoflt(yylval.val.U.(*Mpflt), str) + if yylval.val.U.(*Mpflt).Val.IsInf() { Yyerror("overflow in float constant") - Mpmovecflt(yylval.val.U.Fval, 0.0) + Mpmovecflt(yylval.val.U.(*Mpflt), 0.0) } yylval.val.Ctype = CTFLT @@ -1496,7 +1496,7 @@ caseout: return LLITERAL strlit: - yylval.val.U.Sval = internString(cp.Bytes()) + yylval.val.U = internString(cp.Bytes()) yylval.val.Ctype = CTSTR if Debug['x'] != 0 { fmt.Printf("lex: string literal\n") diff --git a/src/cmd/internal/gc/obj.go b/src/cmd/internal/gc/obj.go index 05c5b1a811..2afd786dc1 100644 --- a/src/cmd/internal/gc/obj.go +++ b/src/cmd/internal/gc/obj.go @@ -382,11 +382,11 @@ func gdata(nam *Node, nr *Node, wid int) { if nr.Op == OLITERAL { switch nr.Val.Ctype { case CTCPLX: - gdatacomplex(nam, nr.Val.U.Cval) + gdatacomplex(nam, nr.Val.U.(*Mpcplx)) return case CTSTR: - gdatastring(nam, nr.Val.U.Sval) + gdatastring(nam, nr.Val.U.(string)) return } } diff --git a/src/cmd/internal/gc/order.go b/src/cmd/internal/gc/order.go index 06a1490be4..b3fd282a68 100644 --- a/src/cmd/internal/gc/order.go +++ b/src/cmd/internal/gc/order.go @@ -995,7 +995,7 @@ func orderexpr(np **Node, order *Order, lhs *Node) { haslit := false for l := n.List; l != nil; l = l.Next { hasbyte = hasbyte || l.N.Op == OARRAYBYTESTR - haslit = haslit || l.N.Op == OLITERAL && len(l.N.Val.U.Sval) != 0 + haslit = haslit || l.N.Op == OLITERAL && len(l.N.Val.U.(string)) != 0 } if haslit && hasbyte { diff --git a/src/cmd/internal/gc/sinit.go b/src/cmd/internal/gc/sinit.go index a9af9450ae..4fdb2e9223 100644 --- a/src/cmd/internal/gc/sinit.go +++ b/src/cmd/internal/gc/sinit.go @@ -437,7 +437,7 @@ func staticassign(l *Node, r *Node, out **NodeList) bool { case OSTRARRAYBYTE: if l.Class == PEXTERN && r.Left.Op == OLITERAL { - sval := r.Left.Val.U.Sval + sval := r.Left.Val.U.(string) slicebytes(l, sval, len(sval)) return true } @@ -449,7 +449,7 @@ func staticassign(l *Node, r *Node, out **NodeList) bool { ta := typ(TARRAY) ta.Type = r.Type.Type - ta.Bound = Mpgetfix(r.Right.Val.U.Xval) + ta.Bound = Mpgetfix(r.Right.Val.U.(*Mpint)) a := staticname(ta, 1) r.Nname = a n1 = *l @@ -722,7 +722,7 @@ func slicelit(ctxt int, n *Node, var_ *Node, init **NodeList) { // make an array type t := shallow(n.Type) - t.Bound = Mpgetfix(n.Right.Val.U.Xval) + t.Bound = Mpgetfix(n.Right.Val.U.(*Mpint)) t.Width = 0 t.Sym = nil t.Haspointers = 0 @@ -1226,7 +1226,7 @@ func oaslit(n *Node, init **NodeList) bool { func getlit(lit *Node) int { if Smallintconst(lit) { - return int(Mpgetfix(lit.Val.U.Xval)) + return int(Mpgetfix(lit.Val.U.(*Mpint))) } return -1 } @@ -1290,7 +1290,7 @@ func initplan(n *Node) { if a.Op != OKEY || !Smallintconst(a.Left) { Fatal("initplan arraylit") } - addvalue(p, n.Type.Type.Width*Mpgetfix(a.Left.Val.U.Xval), nil, a.Right) + addvalue(p, n.Type.Type.Width*Mpgetfix(a.Left.Val.U.(*Mpint)), nil, a.Right) } case OSTRUCTLIT: @@ -1360,19 +1360,19 @@ func iszero(n *Node) bool { return true case CTSTR: - return n.Val.U.Sval == "" + return n.Val.U.(string) == "" case CTBOOL: - return !n.Val.U.Bval + return !n.Val.U.(bool) case CTINT, CTRUNE: - return mpcmpfixc(n.Val.U.Xval, 0) == 0 + return mpcmpfixc(n.Val.U.(*Mpint), 0) == 0 case CTFLT: - return mpcmpfltc(n.Val.U.Fval, 0) == 0 + return mpcmpfltc(n.Val.U.(*Mpflt), 0) == 0 case CTCPLX: - return mpcmpfltc(&n.Val.U.Cval.Real, 0) == 0 && mpcmpfltc(&n.Val.U.Cval.Imag, 0) == 0 + return mpcmpfltc(&n.Val.U.(*Mpcplx).Real, 0) == 0 && mpcmpfltc(&n.Val.U.(*Mpcplx).Imag, 0) == 0 } case OARRAYLIT: @@ -1510,10 +1510,10 @@ func gen_as_init(n *Node) bool { gdata(&nam, nr, int(nr.Type.Width)) case TCOMPLEX64, TCOMPLEX128: - gdatacomplex(&nam, nr.Val.U.Cval) + gdatacomplex(&nam, nr.Val.U.(*Mpcplx)) case TSTRING: - gdatastring(&nam, nr.Val.U.Sval) + gdatastring(&nam, nr.Val.U.(string)) } return true diff --git a/src/cmd/internal/gc/subr.go b/src/cmd/internal/gc/subr.go index dd84214dc8..b09f4232aa 100644 --- a/src/cmd/internal/gc/subr.go +++ b/src/cmd/internal/gc/subr.go @@ -666,8 +666,8 @@ func sortinter(t *Type) *Type { func Nodintconst(v int64) *Node { c := Nod(OLITERAL, nil, nil) c.Addable = true - c.Val.U.Xval = new(Mpint) - Mpmovecfix(c.Val.U.Xval, v) + c.Val.U = new(Mpint) + Mpmovecfix(c.Val.U.(*Mpint), v) c.Val.Ctype = CTINT c.Type = Types[TIDEAL] ullmancalc(c) @@ -677,8 +677,8 @@ func Nodintconst(v int64) *Node { func nodfltconst(v *Mpflt) *Node { c := Nod(OLITERAL, nil, nil) c.Addable = true - c.Val.U.Fval = newMpflt() - mpmovefltflt(c.Val.U.Fval, v) + c.Val.U = newMpflt() + mpmovefltflt(c.Val.U.(*Mpflt), v) c.Val.Ctype = CTFLT c.Type = Types[TIDEAL] ullmancalc(c) @@ -690,8 +690,8 @@ func Nodconst(n *Node, t *Type, v int64) { n.Op = OLITERAL n.Addable = true ullmancalc(n) - n.Val.U.Xval = new(Mpint) - Mpmovecfix(n.Val.U.Xval, v) + n.Val.U = new(Mpint) + Mpmovecfix(n.Val.U.(*Mpint), v) n.Val.Ctype = CTINT n.Type = t @@ -710,7 +710,7 @@ func nodnil() *Node { func Nodbool(b bool) *Node { c := Nodintconst(0) c.Val.Ctype = CTBOOL - c.Val.U.Bval = b + c.Val.U = b c.Type = idealbool return c } @@ -724,7 +724,7 @@ func aindex(b *Node, t *Type) *Type { Yyerror("array bound must be an integer expression") case CTINT, CTRUNE: - bound = Mpgetfix(b.Val.U.Xval) + bound = Mpgetfix(b.Val.U.(*Mpint)) if bound < 0 { Yyerror("array bound must be non negative") } @@ -2422,11 +2422,11 @@ func genwrapper(rcvr *Type, method *Type, newnam *Sym, iface int) { var v Val v.Ctype = CTSTR - v.U.Sval = rcvr.Type.Sym.Pkg.Name // package name + v.U = rcvr.Type.Sym.Pkg.Name // package name l = list(l, nodlit(v)) - v.U.Sval = rcvr.Type.Sym.Name // type name + v.U = rcvr.Type.Sym.Name // type name l = list(l, nodlit(v)) - v.U.Sval = method.Sym.Name + v.U = method.Sym.Name l = list(l, nodlit(v)) // method name call := Nod(OCALL, syslook("panicwrap", 0), nil) call.List = l @@ -3139,7 +3139,7 @@ func powtwo(n *Node) int { return -1 } - v := uint64(Mpgetfix(n.Val.U.Xval)) + v := uint64(Mpgetfix(n.Val.U.(*Mpint))) b := uint64(1) for i := 0; i < 64; i++ { if b == v { diff --git a/src/cmd/internal/gc/swt.go b/src/cmd/internal/gc/swt.go index 7cb632cebe..e8f15a5ce5 100644 --- a/src/cmd/internal/gc/swt.go +++ b/src/cmd/internal/gc/swt.go @@ -218,7 +218,7 @@ func (s *exprSwitch) walk(sw *Node) { s.kind = switchKindExpr if Isconst(sw.Ntest, CTBOOL) { s.kind = switchKindTrue - if !sw.Ntest.Val.U.Bval { + if !sw.Ntest.Val.U.(bool) { s.kind = switchKindFalse } } @@ -755,16 +755,16 @@ func exprcmp(c1, c2 *caseClause) int { // sort by constant value to enable binary search switch ct { case CTFLT: - return mpcmpfltflt(n1.Val.U.Fval, n2.Val.U.Fval) + return mpcmpfltflt(n1.Val.U.(*Mpflt), n2.Val.U.(*Mpflt)) case CTINT, CTRUNE: - return Mpcmpfixfix(n1.Val.U.Xval, n2.Val.U.Xval) + return Mpcmpfixfix(n1.Val.U.(*Mpint), n2.Val.U.(*Mpint)) case CTSTR: // Sort strings by length and then by value. // It is much cheaper to compare lengths than values, // and all we need here is consistency. // We respect this sorting in exprSwitch.walkCases. - a := n1.Val.U.Sval - b := n2.Val.U.Sval + a := n1.Val.U.(string) + b := n2.Val.U.(string) if len(a) < len(b) { return -1 } diff --git a/src/cmd/internal/gc/typecheck.go b/src/cmd/internal/gc/typecheck.go index 3061275da3..bc6bbdb7e3 100644 --- a/src/cmd/internal/gc/typecheck.go +++ b/src/cmd/internal/gc/typecheck.go @@ -392,7 +392,7 @@ OpSwitch: return } - t.Bound = Mpgetfix(v.U.Xval) + t.Bound = Mpgetfix(v.U.(*Mpint)) if doesoverflow(v, Types[TINT]) { Yyerror("array bound is too large") n.Type = nil @@ -770,7 +770,7 @@ OpSwitch: } if (op == ODIV || op == OMOD) && Isconst(r, CTINT) { - if mpcmpfixc(r.Val.U.Xval, 0) == 0 { + if mpcmpfixc(r.Val.U.(*Mpint), 0) == 0 { Yyerror("division by zero") n.Type = nil return @@ -1043,14 +1043,14 @@ OpSwitch: } if Isconst(n.Right, CTINT) { - x := Mpgetfix(n.Right.Val.U.Xval) + x := Mpgetfix(n.Right.Val.U.(*Mpint)) if x < 0 { Yyerror("invalid %s index %v (index must be non-negative)", why, n.Right) } else if Isfixedarray(t) && t.Bound > 0 && x >= t.Bound { Yyerror("invalid array index %v (out of bounds for %d-element array)", n.Right, t.Bound) - } else if Isconst(n.Left, CTSTR) && x >= int64(len(n.Left.Val.U.Sval)) { - Yyerror("invalid string index %v (out of bounds for %d-byte string)", n.Right, len(n.Left.Val.U.Sval)) - } else if Mpcmpfixfix(n.Right.Val.U.Xval, Maxintval[TINT]) > 0 { + } else if Isconst(n.Left, CTSTR) && x >= int64(len(n.Left.Val.U.(string))) { + Yyerror("invalid string index %v (out of bounds for %d-byte string)", n.Right, len(n.Left.Val.U.(string))) + } else if Mpcmpfixfix(n.Right.Val.U.(*Mpint), Maxintval[TINT]) > 0 { Yyerror("invalid %s index %v (index too large)", why, n.Right) } } @@ -1435,9 +1435,9 @@ OpSwitch: if Isconst(l, CTCPLX) { r := n if n.Op == OREAL { - n = nodfltconst(&l.Val.U.Cval.Real) + n = nodfltconst(&l.Val.U.(*Mpcplx).Real) } else { - n = nodfltconst(&l.Val.U.Cval.Imag) + n = nodfltconst(&l.Val.U.(*Mpcplx).Imag) } n.Orig = r } @@ -1451,7 +1451,7 @@ OpSwitch: case TSTRING: if Isconst(l, CTSTR) { r := Nod(OXXX, nil, nil) - Nodconst(r, Types[TINT], int64(len(l.Val.U.Sval))) + Nodconst(r, Types[TINT], int64(len(l.Val.U.(string)))) r.Orig = n n = r } @@ -1859,7 +1859,7 @@ OpSwitch: n.Type = nil return } - if Isconst(l, CTINT) && r != nil && Isconst(r, CTINT) && Mpcmpfixfix(l.Val.U.Xval, r.Val.U.Xval) > 0 { + if Isconst(l, CTINT) && r != nil && Isconst(r, CTINT) && Mpcmpfixfix(l.Val.U.(*Mpint), r.Val.U.(*Mpint)) > 0 { Yyerror("len larger than cap in make(%v)", t) n.Type = nil return @@ -2255,16 +2255,16 @@ func checksliceindex(l *Node, r *Node, tp *Type) int { } if r.Op == OLITERAL { - if Mpgetfix(r.Val.U.Xval) < 0 { + if Mpgetfix(r.Val.U.(*Mpint)) < 0 { Yyerror("invalid slice index %v (index must be non-negative)", r) return -1 - } else if tp != nil && tp.Bound > 0 && Mpgetfix(r.Val.U.Xval) > tp.Bound { + } else if tp != nil && tp.Bound > 0 && Mpgetfix(r.Val.U.(*Mpint)) > tp.Bound { Yyerror("invalid slice index %v (out of bounds for %d-element array)", r, tp.Bound) return -1 - } else if Isconst(l, CTSTR) && Mpgetfix(r.Val.U.Xval) > int64(len(l.Val.U.Sval)) { - Yyerror("invalid slice index %v (out of bounds for %d-byte string)", r, len(l.Val.U.Sval)) + } else if Isconst(l, CTSTR) && Mpgetfix(r.Val.U.(*Mpint)) > int64(len(l.Val.U.(string))) { + Yyerror("invalid slice index %v (out of bounds for %d-byte string)", r, len(l.Val.U.(string))) return -1 - } else if Mpcmpfixfix(r.Val.U.Xval, Maxintval[TINT]) > 0 { + } else if Mpcmpfixfix(r.Val.U.(*Mpint), Maxintval[TINT]) > 0 { Yyerror("invalid slice index %v (index too large)", r) return -1 } @@ -2274,7 +2274,7 @@ func checksliceindex(l *Node, r *Node, tp *Type) int { } func checksliceconst(lo *Node, hi *Node) int { - if lo != nil && hi != nil && lo.Op == OLITERAL && hi.Op == OLITERAL && Mpcmpfixfix(lo.Val.U.Xval, hi.Val.U.Xval) > 0 { + if lo != nil && hi != nil && lo.Op == OLITERAL && hi.Op == OLITERAL && Mpcmpfixfix(lo.Val.U.(*Mpint), hi.Val.U.(*Mpint)) > 0 { Yyerror("invalid slice index: %v > %v", lo, hi) return -1 } @@ -2824,10 +2824,10 @@ func keydup(n *Node, hash []*Node) { b = 23 case CTINT, CTRUNE: - b = uint32(Mpgetfix(n.Val.U.Xval)) + b = uint32(Mpgetfix(n.Val.U.(*Mpint))) case CTFLT: - d := mpgetflt(n.Val.U.Fval) + d := mpgetflt(n.Val.U.(*Mpflt)) x := math.Float64bits(d) for i := 0; i < 8; i++ { b = b*PRIME1 + uint32(x&0xFF) @@ -2836,8 +2836,8 @@ func keydup(n *Node, hash []*Node) { case CTSTR: b = 0 - s := n.Val.U.Sval - for i := len(n.Val.U.Sval); i > 0; i-- { + s := n.Val.U.(string) + for i := len(n.Val.U.(string)); i > 0; i-- { b = b*PRIME1 + uint32(s[0]) s = s[1:] } @@ -2853,12 +2853,12 @@ func keydup(n *Node, hash []*Node) { if Eqtype(a.Left.Type, n.Type) { cmp.Right = a.Left evconst(&cmp) - b = uint32(obj.Bool2int(cmp.Val.U.Bval)) + b = uint32(obj.Bool2int(cmp.Val.U.(bool))) } } else if Eqtype(a.Type, n.Type) { cmp.Right = a evconst(&cmp) - b = uint32(obj.Bool2int(cmp.Val.U.Bval)) + b = uint32(obj.Bool2int(cmp.Val.U.(bool))) } if b != 0 { @@ -2876,11 +2876,11 @@ func indexdup(n *Node, hash []*Node) { Fatal("indexdup: not OLITERAL") } - b := uint32(Mpgetfix(n.Val.U.Xval)) + b := uint32(Mpgetfix(n.Val.U.(*Mpint))) h := uint(b % uint32(len(hash))) var c uint32 for a := hash[h]; a != nil; a = a.Ntest { - c = uint32(Mpgetfix(a.Val.U.Xval)) + c = uint32(Mpgetfix(a.Val.U.(*Mpint))) if b == c { Yyerror("duplicate index in array literal: %d", b) return @@ -3529,7 +3529,7 @@ func stringtoarraylit(np **Node) { Fatal("stringtoarraylit %v", n) } - s := n.Left.Val.U.Sval + s := n.Left.Val.U.(string) var l *NodeList if n.Type.Type.Etype == TUINT8 { // []byte @@ -3886,12 +3886,12 @@ func checkmake(t *Type, arg string, n *Node) int { switch n.Val.Ctype { case CTINT, CTRUNE, CTFLT, CTCPLX: n.Val = toint(n.Val) - if mpcmpfixc(n.Val.U.Xval, 0) < 0 { + if mpcmpfixc(n.Val.U.(*Mpint), 0) < 0 { Yyerror("negative %s argument in make(%v)", arg, t) return -1 } - if Mpcmpfixfix(n.Val.U.Xval, Maxintval[TINT]) > 0 { + if Mpcmpfixfix(n.Val.U.(*Mpint), Maxintval[TINT]) > 0 { Yyerror("%s argument too large in make(%v)", arg, t) return -1 } diff --git a/src/cmd/internal/gc/unsafe.go b/src/cmd/internal/gc/unsafe.go index aa90a19308..824ecd0339 100644 --- a/src/cmd/internal/gc/unsafe.go +++ b/src/cmd/internal/gc/unsafe.go @@ -140,8 +140,8 @@ ret: var val Val val.Ctype = CTINT - val.U.Xval = new(Mpint) - Mpmovecfix(val.U.Xval, v) + val.U = new(Mpint) + Mpmovecfix(val.U.(*Mpint), v) n := Nod(OLITERAL, nil, nil) n.Orig = nn n.Val = val diff --git a/src/cmd/internal/gc/walk.go b/src/cmd/internal/gc/walk.go index 495acb1861..81bb8524b3 100644 --- a/src/cmd/internal/gc/walk.go +++ b/src/cmd/internal/gc/walk.go @@ -1206,7 +1206,7 @@ func walkexpr(np **Node, init **NodeList) { Yyerror("index out of bounds") } } else if Isconst(n.Left, CTSTR) { - n.Bounded = bounded(r, int64(len(n.Left.Val.U.Sval))) + n.Bounded = bounded(r, int64(len(n.Left.Val.U.(string)))) if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) { Warn("index bounds check elided") } @@ -1217,16 +1217,16 @@ func walkexpr(np **Node, init **NodeList) { // replace "abc"[1] with 'b'. // delayed until now because "abc"[1] is not // an ideal constant. - v := Mpgetfix(n.Right.Val.U.Xval) + v := Mpgetfix(n.Right.Val.U.(*Mpint)) - Nodconst(n, n.Type, int64(n.Left.Val.U.Sval[v])) + Nodconst(n, n.Type, int64(n.Left.Val.U.(string)[v])) n.Typecheck = 1 } } } if Isconst(n.Right, CTINT) { - if Mpcmpfixfix(n.Right.Val.U.Xval, &mpzero) < 0 || Mpcmpfixfix(n.Right.Val.U.Xval, Maxintval[TINT]) > 0 { + if Mpcmpfixfix(n.Right.Val.U.(*Mpint), &mpzero) < 0 || Mpcmpfixfix(n.Right.Val.U.(*Mpint), Maxintval[TINT]) > 0 { Yyerror("index out of bounds") } } @@ -1338,7 +1338,7 @@ func walkexpr(np **Node, init **NodeList) { // comparing the lengths instead will yield the same result // without the function call. case OCMPSTR: - if (Isconst(n.Left, CTSTR) && len(n.Left.Val.U.Sval) == 0) || (Isconst(n.Right, CTSTR) && len(n.Right.Val.U.Sval) == 0) { + if (Isconst(n.Left, CTSTR) && len(n.Left.Val.U.(string)) == 0) || (Isconst(n.Right, CTSTR) && len(n.Right.Val.U.(string)) == 0) { r := Nod(int(n.Etype), Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil)) typecheck(&r, Erv) walkexpr(&r, init) @@ -1458,7 +1458,7 @@ func walkexpr(np **Node, init **NodeList) { l = r } t := n.Type - if n.Esc == EscNone && Smallintconst(l) && Smallintconst(r) && (t.Type.Width == 0 || Mpgetfix(r.Val.U.Xval) < (1<<16)/t.Type.Width) { + if n.Esc == EscNone && Smallintconst(l) && Smallintconst(r) && (t.Type.Width == 0 || Mpgetfix(r.Val.U.(*Mpint)) < (1<<16)/t.Type.Width) { // var arr [r]T // n = arr[:l] t = aindex(r, t.Type) // [r]T @@ -2862,7 +2862,7 @@ func addstr(n *Node, init **NodeList) *Node { sz := int64(0) for l := n.List; l != nil; l = l.Next { if n.Op == OLITERAL { - sz += int64(len(n.Val.U.Sval)) + sz += int64(len(n.Val.U.(string))) } } @@ -3415,7 +3415,7 @@ func samecheap(a *Node, b *Node) bool { case OINDEX: ar = a.Right br = b.Right - if !Isconst(ar, CTINT) || !Isconst(br, CTINT) || Mpcmpfixfix(ar.Val.U.Xval, br.Val.U.Xval) != 0 { + if !Isconst(ar, CTINT) || !Isconst(br, CTINT) || Mpcmpfixfix(ar.Val.U.(*Mpint), br.Val.U.(*Mpint)) != 0 { return false } } @@ -3451,9 +3451,9 @@ func walkrotate(np **Node) { w := int(l.Type.Width * 8) if Smallintconst(l.Right) && Smallintconst(r.Right) { - sl := int(Mpgetfix(l.Right.Val.U.Xval)) + sl := int(Mpgetfix(l.Right.Val.U.(*Mpint))) if sl >= 0 { - sr := int(Mpgetfix(r.Right.Val.U.Xval)) + sr := int(Mpgetfix(r.Right.Val.U.(*Mpint))) if sr >= 0 && sl+sr == w { // Rewrite left shift half to left rotate. if l.Op == OLSH { @@ -3464,7 +3464,7 @@ func walkrotate(np **Node) { n.Op = OLROT // Remove rotate 0 and rotate w. - s := int(Mpgetfix(n.Right.Val.U.Xval)) + s := int(Mpgetfix(n.Right.Val.U.(*Mpint))) if s == 0 || s == w { n = n.Left @@ -3507,7 +3507,7 @@ func walkmul(np **Node, init **NodeList) { // x*0 is 0 (and side effects of x). var pow int var w int - if Mpgetfix(nr.Val.U.Xval) == 0 { + if Mpgetfix(nr.Val.U.(*Mpint)) == 0 { cheapexpr(nl, init) Nodconst(n, n.Type, 0) goto ret @@ -3600,10 +3600,10 @@ func walkdiv(np **Node, init **NodeList) { m.W = w if Issigned[nl.Type.Etype] { - m.Sd = Mpgetfix(nr.Val.U.Xval) + m.Sd = Mpgetfix(nr.Val.U.(*Mpint)) Smagic(&m) } else { - m.Ud = uint64(Mpgetfix(nr.Val.U.Xval)) + m.Ud = uint64(Mpgetfix(nr.Val.U.(*Mpint))) Umagic(&m) } @@ -3797,7 +3797,7 @@ func walkdiv(np **Node, init **NodeList) { // n = nl & (nr-1) n.Op = OAND - Nodconst(nc, nl.Type, Mpgetfix(nr.Val.U.Xval)-1) + Nodconst(nc, nl.Type, Mpgetfix(nr.Val.U.(*Mpint))-1) } else { // n = nl >> pow n.Op = ORSH @@ -3827,7 +3827,7 @@ func bounded(n *Node, max int64) bool { bits := int32(8 * n.Type.Width) if Smallintconst(n) { - v := Mpgetfix(n.Val.U.Xval) + v := Mpgetfix(n.Val.U.(*Mpint)) return 0 <= v && v < max } @@ -3835,9 +3835,9 @@ func bounded(n *Node, max int64) bool { case OAND: v := int64(-1) if Smallintconst(n.Left) { - v = Mpgetfix(n.Left.Val.U.Xval) + v = Mpgetfix(n.Left.Val.U.(*Mpint)) } else if Smallintconst(n.Right) { - v = Mpgetfix(n.Right.Val.U.Xval) + v = Mpgetfix(n.Right.Val.U.(*Mpint)) } if 0 <= v && v < max { @@ -3846,7 +3846,7 @@ func bounded(n *Node, max int64) bool { case OMOD: if !sign && Smallintconst(n.Right) { - v := Mpgetfix(n.Right.Val.U.Xval) + v := Mpgetfix(n.Right.Val.U.(*Mpint)) if 0 <= v && v <= max { return true } @@ -3854,7 +3854,7 @@ func bounded(n *Node, max int64) bool { case ODIV: if !sign && Smallintconst(n.Right) { - v := Mpgetfix(n.Right.Val.U.Xval) + v := Mpgetfix(n.Right.Val.U.(*Mpint)) for bits > 0 && v >= 2 { bits-- v >>= 1 @@ -3863,7 +3863,7 @@ func bounded(n *Node, max int64) bool { case ORSH: if !sign && Smallintconst(n.Right) { - v := Mpgetfix(n.Right.Val.U.Xval) + v := Mpgetfix(n.Right.Val.U.(*Mpint)) if v > int64(bits) { return true } @@ -3996,17 +3996,17 @@ func candiscard(n *Node) bool { // Discardable as long as we know it's not division by zero. case ODIV, OMOD: - if Isconst(n.Right, CTINT) && mpcmpfixc(n.Right.Val.U.Xval, 0) != 0 { + if Isconst(n.Right, CTINT) && mpcmpfixc(n.Right.Val.U.(*Mpint), 0) != 0 { break } - if Isconst(n.Right, CTFLT) && mpcmpfltc(n.Right.Val.U.Fval, 0) != 0 { + if Isconst(n.Right, CTFLT) && mpcmpfltc(n.Right.Val.U.(*Mpflt), 0) != 0 { break } return false // Discardable as long as we know it won't fail because of a bad size. case OMAKECHAN, OMAKEMAP: - if Isconst(n.Left, CTINT) && mpcmpfixc(n.Left.Val.U.Xval, 0) == 0 { + if Isconst(n.Left, CTINT) && mpcmpfixc(n.Left.Val.U.(*Mpint), 0) == 0 { break } return false diff --git a/src/cmd/internal/gc/y.go b/src/cmd/internal/gc/y.go index fd3f2b3176..06f6b13eb6 100644 --- a/src/cmd/internal/gc/y.go +++ b/src/cmd/internal/gc/y.go @@ -2327,13 +2327,13 @@ yydefault: { var p *Pkg - if yyDollar[2].val.U.Sval == "" { + if yyDollar[2].val.U.(string) == "" { p = importpkg } else { - if isbadimport(yyDollar[2].val.U.Sval) { + if isbadimport(yyDollar[2].val.U.(string)) { errorexit() } - p = mkpkg(yyDollar[2].val.U.Sval) + p = mkpkg(yyDollar[2].val.U.(string)) } yyVAL.sym = Pkglookup(yyDollar[4].sym.Name, p) } @@ -2343,13 +2343,13 @@ yydefault: { var p *Pkg - if yyDollar[2].val.U.Sval == "" { + if yyDollar[2].val.U.(string) == "" { p = importpkg } else { - if isbadimport(yyDollar[2].val.U.Sval) { + if isbadimport(yyDollar[2].val.U.(string)) { errorexit() } - p = mkpkg(yyDollar[2].val.U.Sval) + p = mkpkg(yyDollar[2].val.U.(string)) } yyVAL.sym = Pkglookup("?", p) } @@ -3156,7 +3156,7 @@ yydefault: yyDollar = yyS[yypt-4 : yypt+1] //line go.y:1947 { - importimport(yyDollar[2].sym, yyDollar[3].val.U.Sval) + importimport(yyDollar[2].sym, yyDollar[3].val.U.(string)) } case 305: yyDollar = yyS[yypt-4 : yypt+1] @@ -3404,14 +3404,14 @@ yydefault: yyVAL.node = nodlit(yyDollar[2].val) switch yyVAL.node.Val.Ctype { case CTINT, CTRUNE: - mpnegfix(yyVAL.node.Val.U.Xval) + mpnegfix(yyVAL.node.Val.U.(*Mpint)) break case CTFLT: - mpnegflt(yyVAL.node.Val.U.Fval) + mpnegflt(yyVAL.node.Val.U.(*Mpflt)) break case CTCPLX: - mpnegflt(&yyVAL.node.Val.U.Cval.Real) - mpnegflt(&yyVAL.node.Val.U.Cval.Imag) + mpnegflt(&yyVAL.node.Val.U.(*Mpcplx).Real) + mpnegflt(&yyVAL.node.Val.U.(*Mpcplx).Imag) break default: Yyerror("bad negated constant") @@ -3432,11 +3432,11 @@ yydefault: { if yyDollar[2].node.Val.Ctype == CTRUNE && yyDollar[4].node.Val.Ctype == CTINT { yyVAL.node = yyDollar[2].node - mpaddfixfix(yyDollar[2].node.Val.U.Xval, yyDollar[4].node.Val.U.Xval, 0) + mpaddfixfix(yyDollar[2].node.Val.U.(*Mpint), yyDollar[4].node.Val.U.(*Mpint), 0) break } - yyDollar[4].node.Val.U.Cval.Real = yyDollar[4].node.Val.U.Cval.Imag - Mpmovecflt(&yyDollar[4].node.Val.U.Cval.Imag, 0.0) + yyDollar[4].node.Val.U.(*Mpcplx).Real = yyDollar[4].node.Val.U.(*Mpcplx).Imag + Mpmovecflt(&yyDollar[4].node.Val.U.(*Mpcplx).Imag, 0.0) yyVAL.node = nodcplxlit(yyDollar[2].node.Val, yyDollar[4].node.Val) } case 346: From 76ec0ee53a5619b4ead4772c075105bf66c0ac67 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Fri, 3 Apr 2015 17:43:38 -0700 Subject: [PATCH 107/232] cmd/internal/gc: separate Name-only Node fields Name will be converted from an anonymous to a named field in a subsequent, automated CL. No functional changes. Passes toolstash -cmp. This reduces the size of gc.Node from 424 to 400 bytes. This in turn reduces the permanent (pprof -inuse_space) memory usage while compiling the test/rotate?.go tests: test old(MB) new(MB) change rotate0 379.49 367.30 -3.21% rotate1 373.42 361.59 -3.16% rotate2 381.17 368.77 -3.25% rotate3 374.30 362.48 -3.15% Updates #9933. Change-Id: I21479527c136add4f1efb9342774e3be3e276e83 Reviewed-on: https://go-review.googlesource.com/10120 Reviewed-by: Russ Cox --- src/cmd/internal/gc/subr.go | 3 ++- src/cmd/internal/gc/syntax.go | 33 +++++++++++++++++--------------- src/cmd/internal/gc/typecheck.go | 3 +++ 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/cmd/internal/gc/subr.go b/src/cmd/internal/gc/subr.go index b09f4232aa..7f9e78810f 100644 --- a/src/cmd/internal/gc/subr.go +++ b/src/cmd/internal/gc/subr.go @@ -380,6 +380,8 @@ func Nod(op int, nleft *Node, nright *Node) *Node { switch op { case OCLOSURE, ODCLFUNC: n.Func = new(Func) + case ONAME: + n.Name = new(Name) } return n } @@ -771,7 +773,6 @@ func treecopy(n *Node) *Node { } fallthrough - // fall through case ONAME, OLITERAL, OTYPE: m = n } diff --git a/src/cmd/internal/gc/syntax.go b/src/cmd/internal/gc/syntax.go index 70c6f3f567..9ef00a09cb 100644 --- a/src/cmd/internal/gc/syntax.go +++ b/src/cmd/internal/gc/syntax.go @@ -30,7 +30,6 @@ type Node struct { Etype uint8 // op for OASOP, etype for OTYPE, exclam for export Bounded bool // bounds check unnecessary Class uint8 // PPARAM, PAUTO, PEXTERN, etc - Method bool // OCALLMETH is direct method call Embedded uint8 // ODCLFIELD embedded type Colas bool // OAS resulting from := Diag uint8 // already printed error about this @@ -42,15 +41,11 @@ type Node struct { Initorder uint8 Used bool Isddd bool // is the argument variadic - Readonly bool Implicit bool Addrtaken bool // address taken, even if not moved to heap Assigned bool // is the variable ever assigned to - Captured bool // is the variable captured by a closure - Byval bool // is the variable captured by value or by reference Likely int8 // likeliness of if statement Hasbreak bool // has break statement - Needzero bool // if it contains pointers, needs to be zeroed on function entry Esc uint16 // EscXXX Funcdepth int32 @@ -69,15 +64,14 @@ type Node struct { Reg int16 // ONAME - Ntype *Node - Defn *Node // ONAME: initializing assignment; OLABEL: labeled statement - Pack *Node // real package for import . names - Curfn *Node // function for local variables - Paramfld *Type // TFIELD for this PPARAM; also for ODOT, curfn - Decldepth int // declaration loop depth, increased for every loop or label + *Name + Ntype *Node + Defn *Node // ONAME: initializing assignment; OLABEL: labeled statement + Pack *Node // real package for import . names + Curfn *Node // function for local variables + Paramfld *Type // TFIELD for this PPARAM; also for ODOT, curfn // ONAME func param with PHEAP - Heapaddr *Node // temp holding heap address of param Outerexpr *Node // expression copied into closure for variable Stackparam *Node // OPARAM node referring to stack copy of param Alloc *Node // allocation call @@ -87,9 +81,6 @@ type Node struct { Closure *Node // ONAME/PHEAP <-> ONAME/PPARAMREF Top int // top context (Ecall, Eproc, etc) - // ONAME substitute while inlining - Inlvar *Node - // OPACK Pkg *Pkg @@ -113,6 +104,18 @@ type Node struct { Opt interface{} // for optimization passes } +// Name holds Node fields used only by ONAME nodes. +type Name struct { + Heapaddr *Node // temp holding heap address of param + Inlvar *Node // ONAME substitute while inlining + Decldepth int // declaration loop depth, increased for every loop or label + Method bool // OCALLMETH name + Readonly bool + Captured bool // is the variable captured by a closure + Byval bool // is the variable captured by value or by reference + Needzero bool // if it contains pointers, needs to be zeroed on function entry +} + // Func holds Node fields used only with function-like nodes. type Func struct { Shortname *Node diff --git a/src/cmd/internal/gc/typecheck.go b/src/cmd/internal/gc/typecheck.go index bc6bbdb7e3..6ad8c82c32 100644 --- a/src/cmd/internal/gc/typecheck.go +++ b/src/cmd/internal/gc/typecheck.go @@ -891,6 +891,9 @@ OpSwitch: } n.Op = ONAME + if n.Name == nil { + n.Name = new(Name) + } n.Sym = n.Right.Sym n.Type = methodfunc(n.Type, n.Left.Type) n.Xoffset = 0 From 5726af54eb3a52b9446a834991110b945e780e99 Mon Sep 17 00:00:00 2001 From: Daniel Morsing Date: Wed, 29 Apr 2015 10:51:42 +0100 Subject: [PATCH 108/232] cmd/internal/gc: ignore declarations of types for goto validation Fixes #8042. Change-Id: I75080f24104256065fd73b07a13c5b8e7d6da94c Reviewed-on: https://go-review.googlesource.com/9442 Reviewed-by: Russ Cox --- src/cmd/internal/gc/dcl.go | 3 +++ src/cmd/internal/gc/gen.go | 21 ++++++++++++++++++--- src/cmd/internal/gc/go.go | 1 + test/goto.go | 16 ++++++++++++++++ 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/cmd/internal/gc/dcl.go b/src/cmd/internal/gc/dcl.go index 85a33bec3f..58b69ab8f9 100644 --- a/src/cmd/internal/gc/dcl.go +++ b/src/cmd/internal/gc/dcl.go @@ -65,6 +65,9 @@ func popdcl() { } s = Pkglookup(d.Name, d.Pkg) lno = int(s.Lastlineno) + if s.Def != nil { + d.whyPushed = s.Def.Op + } dcopy(s, d) d.Lastlineno = int32(lno) if dflag() { diff --git a/src/cmd/internal/gc/gen.go b/src/cmd/internal/gc/gen.go index cd0e650ca9..bba04d41ad 100644 --- a/src/cmd/internal/gc/gen.go +++ b/src/cmd/internal/gc/gen.go @@ -159,6 +159,21 @@ func checkgoto(from *Node, to *Node) { fs = fs.Link } if fs != to.Sym { + // more declarations at label than at goto. + // figure out if they are all types. + ts := to.Sym + ntt := nt + for ; ntt > nf; ntt-- { + if ts.whyPushed != OTYPE { + break + } + ts = ts.Link + } + // all types, nothing to see here. + if ntt == nf { + return + } + lno := int(lineno) setlineno(from) @@ -168,11 +183,11 @@ func checkgoto(from *Node, to *Node) { var block *Sym var dcl *Sym - ts := to.Sym + ts = to.Sym for ; nt > nf; nt-- { if ts.Pkg == nil { block = ts - } else { + } else if ts.whyPushed != OTYPE { dcl = ts } ts = ts.Link @@ -181,7 +196,7 @@ func checkgoto(from *Node, to *Node) { for ts != fs { if ts.Pkg == nil { block = ts - } else { + } else if ts.whyPushed != OTYPE { dcl = ts } ts = ts.Link diff --git a/src/cmd/internal/gc/go.go b/src/cmd/internal/gc/go.go index 31692bdf00..4800218c95 100644 --- a/src/cmd/internal/gc/go.go +++ b/src/cmd/internal/gc/go.go @@ -111,6 +111,7 @@ type Sym struct { Uniqgen uint32 Importdef *Pkg // where imported definition was found Linkname string // link name + whyPushed uint8 // why this symbol pushed onto dclstack. Same as Node.Op. Used by goto validation // saved and restored by dcopy Pkg *Pkg diff --git a/test/goto.go b/test/goto.go index ca477b3d0c..c626f3d1c1 100644 --- a/test/goto.go +++ b/test/goto.go @@ -536,3 +536,19 @@ func _() { goto L // ERROR "goto L jumps into block starting at LINE-4|goto jumps into block" } } + +// issue 8042 +func _() { + goto L + type a int + L: +} + +// make sure we only complain about variable declarations. +func _() { + goto L // ERROR "goto L jumps over declaration of x at LINE+2|goto jumps over declaration" + type a int + x := 1 // GCCGO_ERROR "defined here" + _ = x +L: +} From 4302fd0409da5e4f1d71471a6770dacdc3301197 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Haugen?= Date: Sun, 26 Apr 2015 23:52:42 +0200 Subject: [PATCH 109/232] encoding/json: fix decoding of types with '[]byte' as underlying type All slice types which have elements of kind reflect.Uint8 are marshalled into base64 for compactness. When decoding such data into a custom type based on []byte the decoder checked the slice kind instead of the slice element kind, so no appropriate decoder was found. Fixed by letting the decoder check slice element kind like the encoder. This guarantees that already encoded data can still be successfully decoded. Fixes #8962. Change-Id: Ia320d4dc2c6e9e5fe6d8dc15788c81da23d20c4f Reviewed-on: https://go-review.googlesource.com/9371 Reviewed-by: Peter Waldschmidt Reviewed-by: Russ Cox --- src/encoding/json/decode.go | 2 +- src/encoding/json/decode_test.go | 21 +++++++++++++++++++++ src/encoding/json/encode.go | 2 -- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/encoding/json/decode.go b/src/encoding/json/decode.go index f26a7d49f0..613641afbb 100644 --- a/src/encoding/json/decode.go +++ b/src/encoding/json/decode.go @@ -739,7 +739,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool default: d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) case reflect.Slice: - if v.Type() != byteSliceType { + if v.Type().Elem().Kind() != reflect.Uint8 { d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) break } diff --git a/src/encoding/json/decode_test.go b/src/encoding/json/decode_test.go index 7ecc8f4402..f208ee8a7c 100644 --- a/src/encoding/json/decode_test.go +++ b/src/encoding/json/decode_test.go @@ -1207,7 +1207,28 @@ func TestStringKind(t *testing.T) { if !reflect.DeepEqual(m1, m2) { t.Error("Items should be equal after encoding and then decoding") } +} +// Custom types with []byte as underlying type could not be marshalled +// and then unmarshalled. +// Issue 8962. +func TestByteKind(t *testing.T) { + type byteKind []byte + + a := byteKind("hello") + + data, err := Marshal(a) + if err != nil { + t.Error(err) + } + var b byteKind + err = Unmarshal(data, &b) + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(a, b) { + t.Errorf("expected %v == %v", a, b) + } } var decodeTypeErrorTests = []struct { diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go index 4db9f35e69..7789bb5141 100644 --- a/src/encoding/json/encode.go +++ b/src/encoding/json/encode.go @@ -275,8 +275,6 @@ func (e *encodeState) error(err error) { panic(err) } -var byteSliceType = reflect.TypeOf([]byte(nil)) - func isEmptyValue(v reflect.Value) bool { switch v.Kind() { case reflect.Array, reflect.Map, reflect.Slice, reflect.String: From 97494a45e21099c3a357785f31894a5e69e086c8 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 15 May 2015 16:35:43 +0000 Subject: [PATCH 110/232] Revert "cmd/internal/gc: ignore declarations of types for goto validation" This reverts commit 5726af54eb3a52b9446a834991110b945e780e99. It broke all the builds. Change-Id: I4b1dde86f9433717d303c1dabd6aa1a2bf97fab2 Reviewed-on: https://go-review.googlesource.com/10143 Reviewed-by: Brad Fitzpatrick --- src/cmd/internal/gc/dcl.go | 3 --- src/cmd/internal/gc/gen.go | 21 +++------------------ src/cmd/internal/gc/go.go | 1 - test/goto.go | 16 ---------------- 4 files changed, 3 insertions(+), 38 deletions(-) diff --git a/src/cmd/internal/gc/dcl.go b/src/cmd/internal/gc/dcl.go index 58b69ab8f9..85a33bec3f 100644 --- a/src/cmd/internal/gc/dcl.go +++ b/src/cmd/internal/gc/dcl.go @@ -65,9 +65,6 @@ func popdcl() { } s = Pkglookup(d.Name, d.Pkg) lno = int(s.Lastlineno) - if s.Def != nil { - d.whyPushed = s.Def.Op - } dcopy(s, d) d.Lastlineno = int32(lno) if dflag() { diff --git a/src/cmd/internal/gc/gen.go b/src/cmd/internal/gc/gen.go index bba04d41ad..cd0e650ca9 100644 --- a/src/cmd/internal/gc/gen.go +++ b/src/cmd/internal/gc/gen.go @@ -159,21 +159,6 @@ func checkgoto(from *Node, to *Node) { fs = fs.Link } if fs != to.Sym { - // more declarations at label than at goto. - // figure out if they are all types. - ts := to.Sym - ntt := nt - for ; ntt > nf; ntt-- { - if ts.whyPushed != OTYPE { - break - } - ts = ts.Link - } - // all types, nothing to see here. - if ntt == nf { - return - } - lno := int(lineno) setlineno(from) @@ -183,11 +168,11 @@ func checkgoto(from *Node, to *Node) { var block *Sym var dcl *Sym - ts = to.Sym + ts := to.Sym for ; nt > nf; nt-- { if ts.Pkg == nil { block = ts - } else if ts.whyPushed != OTYPE { + } else { dcl = ts } ts = ts.Link @@ -196,7 +181,7 @@ func checkgoto(from *Node, to *Node) { for ts != fs { if ts.Pkg == nil { block = ts - } else if ts.whyPushed != OTYPE { + } else { dcl = ts } ts = ts.Link diff --git a/src/cmd/internal/gc/go.go b/src/cmd/internal/gc/go.go index 4800218c95..31692bdf00 100644 --- a/src/cmd/internal/gc/go.go +++ b/src/cmd/internal/gc/go.go @@ -111,7 +111,6 @@ type Sym struct { Uniqgen uint32 Importdef *Pkg // where imported definition was found Linkname string // link name - whyPushed uint8 // why this symbol pushed onto dclstack. Same as Node.Op. Used by goto validation // saved and restored by dcopy Pkg *Pkg diff --git a/test/goto.go b/test/goto.go index c626f3d1c1..ca477b3d0c 100644 --- a/test/goto.go +++ b/test/goto.go @@ -536,19 +536,3 @@ func _() { goto L // ERROR "goto L jumps into block starting at LINE-4|goto jumps into block" } } - -// issue 8042 -func _() { - goto L - type a int - L: -} - -// make sure we only complain about variable declarations. -func _() { - goto L // ERROR "goto L jumps over declaration of x at LINE+2|goto jumps over declaration" - type a int - x := 1 // GCCGO_ERROR "defined here" - _ = x -L: -} From d4ed30612c9eead7b1d59179cae5d468fb900f35 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 15 May 2015 08:45:16 -0700 Subject: [PATCH 111/232] syscall: don't run fcntl child process test on iOS Fixes darwin-arm{,64} builds. Child processes aren't allowed on iOS. Change-Id: I9258ed4df757ec394ef6327dbda96f5b9705bcdd Reviewed-on: https://go-review.googlesource.com/10142 Reviewed-by: Hyang-Ah Hana Kim Run-TryBot: Brad Fitzpatrick --- src/syscall/syscall_unix_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/syscall/syscall_unix_test.go b/src/syscall/syscall_unix_test.go index 90fd276f82..af92013739 100644 --- a/src/syscall/syscall_unix_test.go +++ b/src/syscall/syscall_unix_test.go @@ -67,6 +67,9 @@ func _() { // Thus this test also verifies that the Flock_t structure can be // roundtripped with F_SETLK and F_GETLK. func TestFcntlFlock(t *testing.T) { + if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { + t.Skip("skipping; no child processes allowed on iOS") + } flock := syscall.Flock_t{ Type: syscall.F_WRLCK, Start: 31415, Len: 271828, Whence: 1, From 82e1651a246db496fa9598f46a6c6af999b699ba Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 7 Apr 2015 11:57:52 -0700 Subject: [PATCH 112/232] cmd/internal/gc, cmd/yacc: merge yaccerrors.go into cmd/yacc This extends cmd/yacc with support for %error { tokens } : message syntax to specify custom error messages to use instead of the default generic ones. This allows merging go.errors into go.y and removing the yaccerrors.go tool. Updates #9968. Change-Id: I781219c568b86472755f877f48401eaeab00ead5 Reviewed-on: https://go-review.googlesource.com/8563 Reviewed-by: Russ Cox --- src/cmd/internal/gc/go.errors | 81 --- src/cmd/internal/gc/go.y | 63 +- src/cmd/internal/gc/lex.go | 1 - src/cmd/internal/gc/subr.go | 15 - src/cmd/internal/gc/y.go | 584 +++++++++--------- src/cmd/internal/gc/y.output | 972 +++++++++++++++--------------- src/cmd/internal/gc/yaccerrors.go | 194 ------ src/cmd/internal/gc/yymsg.go | 83 --- src/cmd/yacc/yacc.go | 128 +++- 9 files changed, 981 insertions(+), 1140 deletions(-) delete mode 100644 src/cmd/internal/gc/go.errors delete mode 100644 src/cmd/internal/gc/yaccerrors.go delete mode 100644 src/cmd/internal/gc/yymsg.go diff --git a/src/cmd/internal/gc/go.errors b/src/cmd/internal/gc/go.errors deleted file mode 100644 index 8370a2007d..0000000000 --- a/src/cmd/internal/gc/go.errors +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2010 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. - -// Example-based syntax error messages. -// See yaccerrors.go. - -package gc - -var yymsg = []struct { - yystate int - yychar int - msg string -}{ - // Each line of the form % token list - // is converted by yaccerrors.go into the yystate and yychar caused - // by that token list. - - % loadsys package LIMPORT '(' LLITERAL import_package import_there ',' - "unexpected comma during import block"}, - - % loadsys package LIMPORT LNAME ';' - "missing import path; require quoted string"}, - - % loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header ';' - "missing { after if clause"}, - - % loadsys package imports LFUNC LNAME '(' ')' '{' LSWITCH if_header ';' - "missing { after switch clause"}, - - % loadsys package imports LFUNC LNAME '(' ')' '{' LFOR for_header ';' - "missing { after for clause"}, - - % loadsys package imports LFUNC LNAME '(' ')' '{' LFOR ';' LBODY - "missing { after for clause"}, - - % loadsys package imports LFUNC LNAME '(' ')' ';' '{' - "unexpected semicolon or newline before {"}, - - % loadsys package imports LTYPE LNAME ';' - "unexpected semicolon or newline in type declaration"}, - - % loadsys package imports LCHAN '}' - "unexpected } in channel type"}, - - % loadsys package imports LCHAN ')' - "unexpected ) in channel type"}, - - % loadsys package imports LCHAN ',' - "unexpected comma in channel type"}, - - % loadsys package imports LFUNC LNAME '(' ')' '{' if_stmt ';' LELSE - "unexpected semicolon or newline before else"}, - - % loadsys package imports LTYPE LNAME LINTERFACE '{' LNAME ',' LNAME - "name list not allowed in interface type"}, - - % loadsys package imports LFUNC LNAME '(' ')' '{' LFOR LVAR LNAME '=' LNAME - "var declaration not allowed in for initializer"}, - - % loadsys package imports LVAR LNAME '[' ']' LNAME '{' - "unexpected { at end of statement"}, - - % loadsys package imports LFUNC LNAME '(' ')' '{' LVAR LNAME '[' ']' LNAME '{' - "unexpected { at end of statement"}, - - % loadsys package imports LFUNC LNAME '(' ')' '{' LDEFER LNAME ';' - "argument to go/defer must be function call"}, - - % loadsys package imports LVAR LNAME '=' LNAME '{' LNAME ';' - "need trailing comma before newline in composite literal"}, - - % loadsys package imports LVAR LNAME '=' comptype '{' LNAME ';' - "need trailing comma before newline in composite literal"}, - - % loadsys package imports LFUNC LNAME '(' ')' '{' LFUNC LNAME - "nested func not allowed"}, - - % loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header loop_body LELSE ';' - "else must be followed by if or statement block"}, -} diff --git a/src/cmd/internal/gc/go.y b/src/cmd/internal/gc/go.y index e2e4331a77..7d523ae7c0 100644 --- a/src/cmd/internal/gc/go.y +++ b/src/cmd/internal/gc/go.y @@ -117,7 +117,68 @@ import ( %left ')' %left PreferToRightParen -// TODO(rsc): Add %error-verbose +%error loadsys package LIMPORT '(' LLITERAL import_package import_there ',': + "unexpected comma during import block" + +%error loadsys package LIMPORT LNAME ';': + "missing import path; require quoted string" + +%error loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header ';': + "missing { after if clause" + +%error loadsys package imports LFUNC LNAME '(' ')' '{' LSWITCH if_header ';': + "missing { after switch clause" + +%error loadsys package imports LFUNC LNAME '(' ')' '{' LFOR for_header ';': + "missing { after for clause" + +%error loadsys package imports LFUNC LNAME '(' ')' '{' LFOR ';' LBODY: + "missing { after for clause" + +%error loadsys package imports LFUNC LNAME '(' ')' ';' '{': + "unexpected semicolon or newline before {" + +%error loadsys package imports LTYPE LNAME ';': + "unexpected semicolon or newline in type declaration" + +%error loadsys package imports LCHAN '}': + "unexpected } in channel type" + +%error loadsys package imports LCHAN ')': + "unexpected ) in channel type" + +%error loadsys package imports LCHAN ',': + "unexpected comma in channel type" + +%error loadsys package imports LFUNC LNAME '(' ')' '{' if_stmt ';' LELSE: + "unexpected semicolon or newline before else" + +%error loadsys package imports LTYPE LNAME LINTERFACE '{' LNAME ',' LNAME: + "name list not allowed in interface type" + +%error loadsys package imports LFUNC LNAME '(' ')' '{' LFOR LVAR LNAME '=' LNAME: + "var declaration not allowed in for initializer" + +%error loadsys package imports LVAR LNAME '[' ']' LNAME '{': + "unexpected { at end of statement" + +%error loadsys package imports LFUNC LNAME '(' ')' '{' LVAR LNAME '[' ']' LNAME '{': + "unexpected { at end of statement" + +%error loadsys package imports LFUNC LNAME '(' ')' '{' LDEFER LNAME ';': + "argument to go/defer must be function call" + +%error loadsys package imports LVAR LNAME '=' LNAME '{' LNAME ';': + "need trailing comma before newline in composite literal" + +%error loadsys package imports LVAR LNAME '=' comptype '{' LNAME ';': + "need trailing comma before newline in composite literal" + +%error loadsys package imports LFUNC LNAME '(' ')' '{' LFUNC LNAME: + "nested func not allowed" + +%error loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header loop_body LELSE ';': + "else must be followed by if or statement block" %% file: diff --git a/src/cmd/internal/gc/lex.go b/src/cmd/internal/gc/lex.go index 1bf0758000..9e2baec220 100644 --- a/src/cmd/internal/gc/lex.go +++ b/src/cmd/internal/gc/lex.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. //go:generate go tool yacc go.y -//go:generate go run yaccerrors.go //go:generate go run mkbuiltin.go runtime unsafe package gc diff --git a/src/cmd/internal/gc/subr.go b/src/cmd/internal/gc/subr.go index 7f9e78810f..74415be49a 100644 --- a/src/cmd/internal/gc/subr.go +++ b/src/cmd/internal/gc/subr.go @@ -125,13 +125,6 @@ func Yyerror(format string, args ...interface{}) { if strings.HasPrefix(msg, "syntax error") { nsyntaxerrors++ - yystate := theparser.(*yyParserImpl).state() - yychar := theparser.Lookahead() - - if Debug['x'] != 0 { - fmt.Printf("yyerror: yystate=%d yychar=%d\n", yystate, yychar) - } - // An unexpected EOF caused a syntax error. Use the previous // line number since getc generated a fake newline character. if curio.eofnl != 0 { @@ -144,14 +137,6 @@ func Yyerror(format string, args ...interface{}) { } yyerror_lastsyntax = int(lexlineno) - // look for parse state-specific errors in list (see go.errors). - for i := range yymsg { - if yymsg[i].yystate == yystate && yymsg[i].yychar == yychar { - yyerrorl(int(lexlineno), "syntax error: %s", yymsg[i].msg) - return - } - } - // plain "syntax error" gets "near foo" added if msg == "syntax error" { yyerrorl(int(lexlineno), "syntax error near %s", lexbuf.String()) diff --git a/src/cmd/internal/gc/y.go b/src/cmd/internal/gc/y.go index 06f6b13eb6..72bce9a465 100644 --- a/src/cmd/internal/gc/y.go +++ b/src/cmd/internal/gc/y.go @@ -154,7 +154,7 @@ const yyEofCode = 1 const yyErrCode = 2 const yyMaxDepth = 200 -//line go.y:2243 +//line go.y:2304 func fixlbrace(lbr int) { // If the opening brace was an LBODY, // set up for another one now that we're done. @@ -857,6 +857,34 @@ var yyTok3 = [...]int{ 0, } +var yyErrorMessages = [...]struct { + state int + token int + msg string +}{ + {332, 76, "unexpected comma during import block"}, + {89, 63, "missing import path; require quoted string"}, + {390, 63, "missing { after if clause"}, + {387, 63, "missing { after switch clause"}, + {279, 63, "missing { after for clause"}, + {498, 36, "missing { after for clause"}, + {17, 68, "unexpected semicolon or newline before {"}, + {111, 63, "unexpected semicolon or newline in type declaration"}, + {78, 69, "unexpected } in channel type"}, + {78, 61, "unexpected ) in channel type"}, + {78, 76, "unexpected comma in channel type"}, + {416, 15, "unexpected semicolon or newline before else"}, + {329, 76, "name list not allowed in interface type"}, + {279, 33, "var declaration not allowed in for initializer"}, + {25, 68, "unexpected { at end of statement"}, + {371, 68, "unexpected { at end of statement"}, + {122, 63, "argument to go/defer must be function call"}, + {398, 63, "need trailing comma before newline in composite literal"}, + {414, 63, "need trailing comma before newline in composite literal"}, + {124, 25, "nested func not allowed"}, + {650, 63, "else must be followed by if or statement block"}, +} + //line yaccpar:1 /* parser for yacc output */ @@ -878,7 +906,6 @@ type yyParser interface { type yyParserImpl struct { lookahead func() int - state func() int } func (p *yyParserImpl) Lookahead() int { @@ -888,7 +915,6 @@ func (p *yyParserImpl) Lookahead() int { func yyNewParser() yyParser { p := &yyParserImpl{ lookahead: func() int { return -1 }, - state: func() int { return -1 }, } return p } @@ -919,6 +945,13 @@ func yyErrorMessage(state, lookAhead int) string { if !yyErrorVerbose { return "syntax error" } + + for _, e := range yyErrorMessages { + if e.state == state && e.token == lookAhead { + return "syntax error: " + e.msg + } + } + res := "syntax error: unexpected " + yyTokname(lookAhead) // To match Bison, suggest at most four expected tokens. @@ -1021,7 +1054,6 @@ func (yyrcvr *yyParserImpl) Parse(yylex yyLexer) int { yystate := 0 yychar := -1 yytoken := -1 // yychar translated into internal numbering - yyrcvr.state = func() int { return yystate } yyrcvr.lookahead = func() int { return yychar } defer func() { // Make sure we report no lookahead when not parsing. @@ -1188,13 +1220,13 @@ yydefault: case 1: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:128 + //line go.y:189 { xtop = concat(xtop, yyDollar[4].list) } case 2: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:134 + //line go.y:195 { prevlineno = lineno Yyerror("package statement must be first") @@ -1202,13 +1234,13 @@ yydefault: } case 3: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:140 + //line go.y:201 { mkpackage(yyDollar[2].sym.Name) } case 4: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:150 + //line go.y:211 { importpkg = Runtimepkg @@ -1221,13 +1253,13 @@ yydefault: } case 5: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:162 + //line go.y:223 { importpkg = nil } case 11: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:176 + //line go.y:237 { ipkg := importpkg my := importmyname @@ -1264,7 +1296,7 @@ yydefault: } case 12: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:211 + //line go.y:272 { // When an invalid import path is passed to importfile, // it calls Yyerror and then sets up a fake import with @@ -1276,7 +1308,7 @@ yydefault: } case 15: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:227 + //line go.y:288 { // import with original name yyVAL.i = parserline() @@ -1285,7 +1317,7 @@ yydefault: } case 16: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:234 + //line go.y:295 { // import with given name yyVAL.i = parserline() @@ -1294,7 +1326,7 @@ yydefault: } case 17: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:241 + //line go.y:302 { // import into my name space yyVAL.i = parserline() @@ -1303,7 +1335,7 @@ yydefault: } case 18: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:250 + //line go.y:311 { if importpkg.Name == "" { importpkg.Name = yyDollar[2].sym.Name @@ -1320,7 +1352,7 @@ yydefault: } case 20: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:267 + //line go.y:328 { if yyDollar[1].sym.Name == "safe" { curio.importsafe = true @@ -1328,64 +1360,64 @@ yydefault: } case 21: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:274 + //line go.y:335 { defercheckwidth() } case 22: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:278 + //line go.y:339 { resumecheckwidth() unimportfile() } case 23: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:287 + //line go.y:348 { Yyerror("empty top-level declaration") yyVAL.list = nil } case 25: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:293 + //line go.y:354 { yyVAL.list = list1(yyDollar[1].node) } case 26: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:297 + //line go.y:358 { Yyerror("non-declaration statement outside function body") yyVAL.list = nil } case 27: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:302 + //line go.y:363 { yyVAL.list = nil } case 28: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:308 + //line go.y:369 { yyVAL.list = yyDollar[2].list } case 29: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:312 + //line go.y:373 { yyVAL.list = yyDollar[3].list } case 30: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:316 + //line go.y:377 { yyVAL.list = nil } case 31: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:320 + //line go.y:381 { yyVAL.list = yyDollar[2].list iota_ = -100000 @@ -1393,7 +1425,7 @@ yydefault: } case 32: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:326 + //line go.y:387 { yyVAL.list = yyDollar[3].list iota_ = -100000 @@ -1401,7 +1433,7 @@ yydefault: } case 33: yyDollar = yyS[yypt-7 : yypt+1] - //line go.y:332 + //line go.y:393 { yyVAL.list = concat(yyDollar[3].list, yyDollar[5].list) iota_ = -100000 @@ -1409,80 +1441,80 @@ yydefault: } case 34: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:338 + //line go.y:399 { yyVAL.list = nil iota_ = -100000 } case 35: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:343 + //line go.y:404 { yyVAL.list = list1(yyDollar[2].node) } case 36: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:347 + //line go.y:408 { yyVAL.list = yyDollar[3].list } case 37: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:351 + //line go.y:412 { yyVAL.list = nil } case 38: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:357 + //line go.y:418 { iota_ = 0 } case 39: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:363 + //line go.y:424 { yyVAL.list = variter(yyDollar[1].list, yyDollar[2].node, nil) } case 40: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:367 + //line go.y:428 { yyVAL.list = variter(yyDollar[1].list, yyDollar[2].node, yyDollar[4].list) } case 41: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:371 + //line go.y:432 { yyVAL.list = variter(yyDollar[1].list, nil, yyDollar[3].list) } case 42: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:377 + //line go.y:438 { yyVAL.list = constiter(yyDollar[1].list, yyDollar[2].node, yyDollar[4].list) } case 43: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:381 + //line go.y:442 { yyVAL.list = constiter(yyDollar[1].list, nil, yyDollar[3].list) } case 45: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:388 + //line go.y:449 { yyVAL.list = constiter(yyDollar[1].list, yyDollar[2].node, nil) } case 46: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:392 + //line go.y:453 { yyVAL.list = constiter(yyDollar[1].list, nil, nil) } case 47: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:398 + //line go.y:459 { // different from dclname because the name // becomes visible right here, not at the end @@ -1491,13 +1523,13 @@ yydefault: } case 48: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:407 + //line go.y:468 { yyVAL.node = typedcl1(yyDollar[1].node, yyDollar[2].node, true) } case 49: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:413 + //line go.y:474 { yyVAL.node = yyDollar[1].node @@ -1513,14 +1545,14 @@ yydefault: } case 50: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:427 + //line go.y:488 { yyVAL.node = Nod(OASOP, yyDollar[1].node, yyDollar[3].node) yyVAL.node.Etype = uint8(yyDollar[2].i) // rathole to pass opcode } case 51: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:432 + //line go.y:493 { if yyDollar[1].list.Next == nil && yyDollar[3].list.Next == nil { // simple @@ -1534,7 +1566,7 @@ yydefault: } case 52: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:444 + //line go.y:505 { if yyDollar[3].list.N.Op == OTYPESW { yyVAL.node = Nod(OTYPESW, nil, yyDollar[3].list.N.Right) @@ -1554,7 +1586,7 @@ yydefault: } case 53: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:462 + //line go.y:523 { yyVAL.node = Nod(OASOP, yyDollar[1].node, Nodintconst(1)) yyVAL.node.Implicit = true @@ -1562,7 +1594,7 @@ yydefault: } case 54: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:468 + //line go.y:529 { yyVAL.node = Nod(OASOP, yyDollar[1].node, Nodintconst(1)) yyVAL.node.Implicit = true @@ -1570,7 +1602,7 @@ yydefault: } case 55: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:476 + //line go.y:537 { var n, nn *Node @@ -1595,7 +1627,7 @@ yydefault: } case 56: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:499 + //line go.y:560 { var n *Node @@ -1615,7 +1647,7 @@ yydefault: } case 57: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:517 + //line go.y:578 { // will be converted to OCASE // right will point to next case @@ -1626,7 +1658,7 @@ yydefault: } case 58: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:526 + //line go.y:587 { var n, nn *Node @@ -1647,13 +1679,13 @@ yydefault: } case 59: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:547 + //line go.y:608 { markdcl() } case 60: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:551 + //line go.y:612 { if yyDollar[3].list == nil { yyVAL.node = Nod(OEMPTY, nil, nil) @@ -1664,7 +1696,7 @@ yydefault: } case 61: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:562 + //line go.y:623 { // If the last token read by the lexer was consumed // as part of the case, clear it (parser has cleared yychar). @@ -1677,7 +1709,7 @@ yydefault: } case 62: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:573 + //line go.y:634 { // This is the only place in the language where a statement // list is not allowed to drop the final semicolon, because @@ -1697,32 +1729,32 @@ yydefault: } case 63: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:592 + //line go.y:653 { yyVAL.list = nil } case 64: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:596 + //line go.y:657 { yyVAL.list = list(yyDollar[1].list, yyDollar[2].node) } case 65: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:602 + //line go.y:663 { markdcl() } case 66: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:606 + //line go.y:667 { yyVAL.list = yyDollar[3].list popdcl() } case 67: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:613 + //line go.y:674 { yyVAL.node = Nod(ORANGE, nil, yyDollar[4].node) yyVAL.node.List = yyDollar[1].list @@ -1730,7 +1762,7 @@ yydefault: } case 68: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:619 + //line go.y:680 { yyVAL.node = Nod(ORANGE, nil, yyDollar[4].node) yyVAL.node.List = yyDollar[1].list @@ -1739,14 +1771,14 @@ yydefault: } case 69: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:626 + //line go.y:687 { yyVAL.node = Nod(ORANGE, nil, yyDollar[2].node) yyVAL.node.Etype = 0 // := flag } case 70: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:633 + //line go.y:694 { // init ; test ; incr if yyDollar[5].node != nil && yyDollar[5].node.Colas { @@ -1761,7 +1793,7 @@ yydefault: } case 71: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:646 + //line go.y:707 { // normal test yyVAL.node = Nod(OFOR, nil, nil) @@ -1769,27 +1801,27 @@ yydefault: } case 73: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:655 + //line go.y:716 { yyVAL.node = yyDollar[1].node yyVAL.node.Nbody = concat(yyVAL.node.Nbody, yyDollar[2].list) } case 74: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:662 + //line go.y:723 { markdcl() } case 75: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:666 + //line go.y:727 { yyVAL.node = yyDollar[3].node popdcl() } case 76: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:673 + //line go.y:734 { // test yyVAL.node = Nod(OIF, nil, nil) @@ -1797,7 +1829,7 @@ yydefault: } case 77: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:679 + //line go.y:740 { // init ; test yyVAL.node = Nod(OIF, nil, nil) @@ -1808,13 +1840,13 @@ yydefault: } case 78: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:691 + //line go.y:752 { markdcl() } case 79: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:695 + //line go.y:756 { if yyDollar[3].node.Ntest == nil { Yyerror("missing condition in if statement") @@ -1822,13 +1854,13 @@ yydefault: } case 80: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:701 + //line go.y:762 { yyDollar[3].node.Nbody = yyDollar[5].list } case 81: yyDollar = yyS[yypt-8 : yypt+1] - //line go.y:705 + //line go.y:766 { var n *Node var nn *NodeList @@ -1846,13 +1878,13 @@ yydefault: } case 82: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:723 + //line go.y:784 { markdcl() } case 83: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:727 + //line go.y:788 { if yyDollar[4].node.Ntest == nil { Yyerror("missing condition in if statement") @@ -1862,25 +1894,25 @@ yydefault: } case 84: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:736 + //line go.y:797 { yyVAL.list = nil } case 85: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:740 + //line go.y:801 { yyVAL.list = concat(yyDollar[1].list, yyDollar[2].list) } case 86: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:745 + //line go.y:806 { yyVAL.list = nil } case 87: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:749 + //line go.y:810 { l := &NodeList{N: yyDollar[2].node} l.End = l @@ -1888,13 +1920,13 @@ yydefault: } case 88: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:757 + //line go.y:818 { markdcl() } case 89: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:761 + //line go.y:822 { var n *Node n = yyDollar[3].node.Ntest @@ -1905,7 +1937,7 @@ yydefault: } case 90: yyDollar = yyS[yypt-7 : yypt+1] - //line go.y:770 + //line go.y:831 { yyVAL.node = yyDollar[3].node yyVAL.node.Op = OSWITCH @@ -1915,13 +1947,13 @@ yydefault: } case 91: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:780 + //line go.y:841 { typesw = Nod(OXXX, typesw, nil) } case 92: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:784 + //line go.y:845 { yyVAL.node = Nod(OSELECT, nil, nil) yyVAL.node.Lineno = typesw.Lineno @@ -1930,133 +1962,133 @@ yydefault: } case 94: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:797 + //line go.y:858 { yyVAL.node = Nod(OOROR, yyDollar[1].node, yyDollar[3].node) } case 95: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:801 + //line go.y:862 { yyVAL.node = Nod(OANDAND, yyDollar[1].node, yyDollar[3].node) } case 96: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:805 + //line go.y:866 { yyVAL.node = Nod(OEQ, yyDollar[1].node, yyDollar[3].node) } case 97: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:809 + //line go.y:870 { yyVAL.node = Nod(ONE, yyDollar[1].node, yyDollar[3].node) } case 98: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:813 + //line go.y:874 { yyVAL.node = Nod(OLT, yyDollar[1].node, yyDollar[3].node) } case 99: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:817 + //line go.y:878 { yyVAL.node = Nod(OLE, yyDollar[1].node, yyDollar[3].node) } case 100: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:821 + //line go.y:882 { yyVAL.node = Nod(OGE, yyDollar[1].node, yyDollar[3].node) } case 101: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:825 + //line go.y:886 { yyVAL.node = Nod(OGT, yyDollar[1].node, yyDollar[3].node) } case 102: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:829 + //line go.y:890 { yyVAL.node = Nod(OADD, yyDollar[1].node, yyDollar[3].node) } case 103: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:833 + //line go.y:894 { yyVAL.node = Nod(OSUB, yyDollar[1].node, yyDollar[3].node) } case 104: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:837 + //line go.y:898 { yyVAL.node = Nod(OOR, yyDollar[1].node, yyDollar[3].node) } case 105: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:841 + //line go.y:902 { yyVAL.node = Nod(OXOR, yyDollar[1].node, yyDollar[3].node) } case 106: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:845 + //line go.y:906 { yyVAL.node = Nod(OMUL, yyDollar[1].node, yyDollar[3].node) } case 107: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:849 + //line go.y:910 { yyVAL.node = Nod(ODIV, yyDollar[1].node, yyDollar[3].node) } case 108: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:853 + //line go.y:914 { yyVAL.node = Nod(OMOD, yyDollar[1].node, yyDollar[3].node) } case 109: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:857 + //line go.y:918 { yyVAL.node = Nod(OAND, yyDollar[1].node, yyDollar[3].node) } case 110: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:861 + //line go.y:922 { yyVAL.node = Nod(OANDNOT, yyDollar[1].node, yyDollar[3].node) } case 111: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:865 + //line go.y:926 { yyVAL.node = Nod(OLSH, yyDollar[1].node, yyDollar[3].node) } case 112: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:869 + //line go.y:930 { yyVAL.node = Nod(ORSH, yyDollar[1].node, yyDollar[3].node) } case 113: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:874 + //line go.y:935 { yyVAL.node = Nod(OSEND, yyDollar[1].node, yyDollar[3].node) } case 115: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:881 + //line go.y:942 { yyVAL.node = Nod(OIND, yyDollar[2].node, nil) } case 116: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:885 + //line go.y:946 { if yyDollar[2].node.Op == OCOMPLIT { // Special case for &T{...}: turn into (*T){...}. @@ -2069,57 +2101,57 @@ yydefault: } case 117: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:896 + //line go.y:957 { yyVAL.node = Nod(OPLUS, yyDollar[2].node, nil) } case 118: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:900 + //line go.y:961 { yyVAL.node = Nod(OMINUS, yyDollar[2].node, nil) } case 119: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:904 + //line go.y:965 { yyVAL.node = Nod(ONOT, yyDollar[2].node, nil) } case 120: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:908 + //line go.y:969 { Yyerror("the bitwise complement operator is ^") yyVAL.node = Nod(OCOM, yyDollar[2].node, nil) } case 121: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:913 + //line go.y:974 { yyVAL.node = Nod(OCOM, yyDollar[2].node, nil) } case 122: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:917 + //line go.y:978 { yyVAL.node = Nod(ORECV, yyDollar[2].node, nil) } case 123: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:927 + //line go.y:988 { yyVAL.node = Nod(OCALL, yyDollar[1].node, nil) } case 124: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:931 + //line go.y:992 { yyVAL.node = Nod(OCALL, yyDollar[1].node, nil) yyVAL.node.List = yyDollar[3].list } case 125: yyDollar = yyS[yypt-6 : yypt+1] - //line go.y:936 + //line go.y:997 { yyVAL.node = Nod(OCALL, yyDollar[1].node, nil) yyVAL.node.List = yyDollar[3].list @@ -2127,13 +2159,13 @@ yydefault: } case 126: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:944 + //line go.y:1005 { yyVAL.node = nodlit(yyDollar[1].val) } case 128: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:949 + //line go.y:1010 { if yyDollar[1].node.Op == OPACK { var s *Sym @@ -2146,31 +2178,31 @@ yydefault: } case 129: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:960 + //line go.y:1021 { yyVAL.node = Nod(ODOTTYPE, yyDollar[1].node, yyDollar[4].node) } case 130: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:964 + //line go.y:1025 { yyVAL.node = Nod(OTYPESW, nil, yyDollar[1].node) } case 131: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:968 + //line go.y:1029 { yyVAL.node = Nod(OINDEX, yyDollar[1].node, yyDollar[3].node) } case 132: yyDollar = yyS[yypt-6 : yypt+1] - //line go.y:972 + //line go.y:1033 { yyVAL.node = Nod(OSLICE, yyDollar[1].node, Nod(OKEY, yyDollar[3].node, yyDollar[5].node)) } case 133: yyDollar = yyS[yypt-8 : yypt+1] - //line go.y:976 + //line go.y:1037 { if yyDollar[5].node == nil { Yyerror("middle index required in 3-index slice") @@ -2182,7 +2214,7 @@ yydefault: } case 135: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:987 + //line go.y:1048 { // conversion yyVAL.node = Nod(OCALL, yyDollar[1].node, nil) @@ -2190,7 +2222,7 @@ yydefault: } case 136: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:993 + //line go.y:1054 { yyVAL.node = yyDollar[3].node yyVAL.node.Right = yyDollar[1].node @@ -2199,7 +2231,7 @@ yydefault: } case 137: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:1000 + //line go.y:1061 { yyVAL.node = yyDollar[3].node yyVAL.node.Right = yyDollar[1].node @@ -2207,7 +2239,7 @@ yydefault: } case 138: yyDollar = yyS[yypt-7 : yypt+1] - //line go.y:1006 + //line go.y:1067 { Yyerror("cannot parenthesize type in composite literal") yyVAL.node = yyDollar[5].node @@ -2216,7 +2248,7 @@ yydefault: } case 140: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1015 + //line go.y:1076 { // composite expression. // make node early so we get the right line number. @@ -2224,13 +2256,13 @@ yydefault: } case 141: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1023 + //line go.y:1084 { yyVAL.node = Nod(OKEY, yyDollar[1].node, yyDollar[3].node) } case 142: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1029 + //line go.y:1090 { // These nodes do not carry line numbers. // Since a composite literal commonly spans several lines, @@ -2245,21 +2277,21 @@ yydefault: } case 143: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1042 + //line go.y:1103 { yyVAL.node = yyDollar[2].node yyVAL.node.List = yyDollar[3].list } case 145: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1050 + //line go.y:1111 { yyVAL.node = yyDollar[2].node yyVAL.node.List = yyDollar[3].list } case 147: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1058 + //line go.y:1119 { yyVAL.node = yyDollar[2].node @@ -2273,19 +2305,19 @@ yydefault: } case 151: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1079 + //line go.y:1140 { yyVAL.i = LBODY } case 152: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1083 + //line go.y:1144 { yyVAL.i = '{' } case 153: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1094 + //line go.y:1155 { if yyDollar[1].sym == nil { yyVAL.node = nil @@ -2295,19 +2327,19 @@ yydefault: } case 154: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1104 + //line go.y:1165 { yyVAL.node = dclname(yyDollar[1].sym) } case 155: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1109 + //line go.y:1170 { yyVAL.node = nil } case 157: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1116 + //line go.y:1177 { yyVAL.sym = yyDollar[1].sym // during imports, unqualified non-exported identifiers are from builtinpkg @@ -2317,13 +2349,13 @@ yydefault: } case 159: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1125 + //line go.y:1186 { yyVAL.sym = nil } case 160: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1131 + //line go.y:1192 { var p *Pkg @@ -2339,7 +2371,7 @@ yydefault: } case 161: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1145 + //line go.y:1206 { var p *Pkg @@ -2355,7 +2387,7 @@ yydefault: } case 162: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1161 + //line go.y:1222 { yyVAL.node = oldname(yyDollar[1].sym) if yyVAL.node.Pack != nil { @@ -2364,38 +2396,38 @@ yydefault: } case 164: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1182 + //line go.y:1243 { Yyerror("final argument in variadic function missing type") yyVAL.node = Nod(ODDD, typenod(typ(TINTER)), nil) } case 165: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1187 + //line go.y:1248 { yyVAL.node = Nod(ODDD, yyDollar[2].node, nil) } case 171: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1198 + //line go.y:1259 { yyVAL.node = yyDollar[2].node } case 175: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1207 + //line go.y:1268 { yyVAL.node = Nod(OIND, yyDollar[2].node, nil) } case 180: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1217 + //line go.y:1278 { yyVAL.node = yyDollar[2].node } case 190: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1238 + //line go.y:1299 { if yyDollar[1].node.Op == OPACK { var s *Sym @@ -2408,53 +2440,53 @@ yydefault: } case 191: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1251 + //line go.y:1312 { yyVAL.node = Nod(OTARRAY, yyDollar[2].node, yyDollar[4].node) } case 192: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1255 + //line go.y:1316 { // array literal of nelem yyVAL.node = Nod(OTARRAY, Nod(ODDD, nil, nil), yyDollar[4].node) } case 193: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1260 + //line go.y:1321 { yyVAL.node = Nod(OTCHAN, yyDollar[2].node, nil) yyVAL.node.Etype = Cboth } case 194: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1265 + //line go.y:1326 { yyVAL.node = Nod(OTCHAN, yyDollar[3].node, nil) yyVAL.node.Etype = Csend } case 195: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:1270 + //line go.y:1331 { yyVAL.node = Nod(OTMAP, yyDollar[3].node, yyDollar[5].node) } case 198: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1278 + //line go.y:1339 { yyVAL.node = Nod(OIND, yyDollar[2].node, nil) } case 199: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1284 + //line go.y:1345 { yyVAL.node = Nod(OTCHAN, yyDollar[3].node, nil) yyVAL.node.Etype = Crecv } case 200: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:1291 + //line go.y:1352 { yyVAL.node = Nod(OTSTRUCT, nil, nil) yyVAL.node.List = yyDollar[3].list @@ -2462,14 +2494,14 @@ yydefault: } case 201: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1297 + //line go.y:1358 { yyVAL.node = Nod(OTSTRUCT, nil, nil) fixlbrace(yyDollar[2].i) } case 202: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:1304 + //line go.y:1365 { yyVAL.node = Nod(OTINTER, nil, nil) yyVAL.node.List = yyDollar[3].list @@ -2477,14 +2509,14 @@ yydefault: } case 203: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1310 + //line go.y:1371 { yyVAL.node = Nod(OTINTER, nil, nil) fixlbrace(yyDollar[2].i) } case 204: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1321 + //line go.y:1382 { yyVAL.node = yyDollar[2].node if yyVAL.node == nil { @@ -2502,7 +2534,7 @@ yydefault: } case 205: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:1339 + //line go.y:1400 { var t *Node @@ -2535,7 +2567,7 @@ yydefault: } case 206: yyDollar = yyS[yypt-8 : yypt+1] - //line go.y:1370 + //line go.y:1431 { var rcvr, t *Node @@ -2573,7 +2605,7 @@ yydefault: } case 207: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:1408 + //line go.y:1469 { var s *Sym var t *Type @@ -2600,7 +2632,7 @@ yydefault: } case 208: yyDollar = yyS[yypt-8 : yypt+1] - //line go.y:1433 + //line go.y:1494 { yyVAL.node = methodname1(newname(yyDollar[4].sym), yyDollar[2].list.N.Right) yyVAL.node.Type = functype(yyDollar[2].list.N, yyDollar[6].list, yyDollar[8].list) @@ -2618,7 +2650,7 @@ yydefault: } case 209: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:1451 + //line go.y:1512 { yyDollar[3].list = checkarglist(yyDollar[3].list, 1) yyVAL.node = Nod(OTFUNC, nil, nil) @@ -2627,13 +2659,13 @@ yydefault: } case 210: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1459 + //line go.y:1520 { yyVAL.list = nil } case 211: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1463 + //line go.y:1524 { yyVAL.list = yyDollar[2].list if yyVAL.list == nil { @@ -2642,51 +2674,51 @@ yydefault: } case 212: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1472 + //line go.y:1533 { yyVAL.list = nil } case 213: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1476 + //line go.y:1537 { yyVAL.list = list1(Nod(ODCLFIELD, nil, yyDollar[1].node)) } case 214: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1480 + //line go.y:1541 { yyDollar[2].list = checkarglist(yyDollar[2].list, 0) yyVAL.list = yyDollar[2].list } case 215: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1487 + //line go.y:1548 { closurehdr(yyDollar[1].node) } case 216: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1493 + //line go.y:1554 { yyVAL.node = closurebody(yyDollar[3].list) fixlbrace(yyDollar[2].i) } case 217: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1498 + //line go.y:1559 { yyVAL.node = closurebody(nil) } case 218: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1509 + //line go.y:1570 { yyVAL.list = nil } case 219: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1513 + //line go.y:1574 { yyVAL.list = concat(yyDollar[1].list, yyDollar[2].list) if nsyntaxerrors == 0 { @@ -2699,49 +2731,49 @@ yydefault: } case 221: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1527 + //line go.y:1588 { yyVAL.list = concat(yyDollar[1].list, yyDollar[3].list) } case 223: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1534 + //line go.y:1595 { yyVAL.list = concat(yyDollar[1].list, yyDollar[3].list) } case 224: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1540 + //line go.y:1601 { yyVAL.list = list1(yyDollar[1].node) } case 225: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1544 + //line go.y:1605 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 227: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1551 + //line go.y:1612 { yyVAL.list = concat(yyDollar[1].list, yyDollar[3].list) } case 228: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1557 + //line go.y:1618 { yyVAL.list = list1(yyDollar[1].node) } case 229: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1561 + //line go.y:1622 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 230: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1567 + //line go.y:1628 { var l *NodeList @@ -2767,14 +2799,14 @@ yydefault: } case 231: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1591 + //line go.y:1652 { yyDollar[1].node.Val = yyDollar[2].val yyVAL.list = list1(yyDollar[1].node) } case 232: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1596 + //line go.y:1657 { yyDollar[2].node.Val = yyDollar[4].val yyVAL.list = list1(yyDollar[2].node) @@ -2782,7 +2814,7 @@ yydefault: } case 233: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1602 + //line go.y:1663 { yyDollar[2].node.Right = Nod(OIND, yyDollar[2].node.Right, nil) yyDollar[2].node.Val = yyDollar[3].val @@ -2790,7 +2822,7 @@ yydefault: } case 234: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:1608 + //line go.y:1669 { yyDollar[3].node.Right = Nod(OIND, yyDollar[3].node.Right, nil) yyDollar[3].node.Val = yyDollar[5].val @@ -2799,7 +2831,7 @@ yydefault: } case 235: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:1615 + //line go.y:1676 { yyDollar[3].node.Right = Nod(OIND, yyDollar[3].node.Right, nil) yyDollar[3].node.Val = yyDollar[5].val @@ -2808,7 +2840,7 @@ yydefault: } case 236: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1624 + //line go.y:1685 { var n *Node @@ -2820,7 +2852,7 @@ yydefault: } case 237: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1634 + //line go.y:1695 { var pkg *Pkg @@ -2835,33 +2867,33 @@ yydefault: } case 238: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1649 + //line go.y:1710 { yyVAL.node = embedded(yyDollar[1].sym, localpkg) } case 239: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1655 + //line go.y:1716 { yyVAL.node = Nod(ODCLFIELD, yyDollar[1].node, yyDollar[2].node) ifacedcl(yyVAL.node) } case 240: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1660 + //line go.y:1721 { yyVAL.node = Nod(ODCLFIELD, nil, oldname(yyDollar[1].sym)) } case 241: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1664 + //line go.y:1725 { yyVAL.node = Nod(ODCLFIELD, nil, oldname(yyDollar[2].sym)) Yyerror("cannot parenthesize embedded type") } case 242: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1671 + //line go.y:1732 { // without func keyword yyDollar[2].list = checkarglist(yyDollar[2].list, 1) @@ -2871,7 +2903,7 @@ yydefault: } case 244: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1685 + //line go.y:1746 { yyVAL.node = Nod(ONONAME, nil, nil) yyVAL.node.Sym = yyDollar[1].sym @@ -2879,7 +2911,7 @@ yydefault: } case 245: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1691 + //line go.y:1752 { yyVAL.node = Nod(ONONAME, nil, nil) yyVAL.node.Sym = yyDollar[1].sym @@ -2887,56 +2919,56 @@ yydefault: } case 247: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1700 + //line go.y:1761 { yyVAL.list = list1(yyDollar[1].node) } case 248: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1704 + //line go.y:1765 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 249: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1709 + //line go.y:1770 { yyVAL.list = nil } case 250: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1713 + //line go.y:1774 { yyVAL.list = yyDollar[1].list } case 251: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1721 + //line go.y:1782 { yyVAL.node = nil } case 253: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1726 + //line go.y:1787 { yyVAL.node = liststmt(yyDollar[1].list) } case 255: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1731 + //line go.y:1792 { yyVAL.node = nil } case 261: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1742 + //line go.y:1803 { yyDollar[1].node = Nod(OLABEL, yyDollar[1].node, nil) yyDollar[1].node.Sym = dclstack // context, for goto restrictions } case 262: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1747 + //line go.y:1808 { var l *NodeList @@ -2949,7 +2981,7 @@ yydefault: } case 263: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1758 + //line go.y:1819 { // will be converted to OFALL yyVAL.node = Nod(OXFALL, nil, nil) @@ -2957,38 +2989,38 @@ yydefault: } case 264: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1764 + //line go.y:1825 { yyVAL.node = Nod(OBREAK, yyDollar[2].node, nil) } case 265: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1768 + //line go.y:1829 { yyVAL.node = Nod(OCONTINUE, yyDollar[2].node, nil) } case 266: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1772 + //line go.y:1833 { yyVAL.node = Nod(OPROC, yyDollar[2].node, nil) } case 267: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1776 + //line go.y:1837 { yyVAL.node = Nod(ODEFER, yyDollar[2].node, nil) } case 268: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1780 + //line go.y:1841 { yyVAL.node = Nod(OGOTO, yyDollar[2].node, nil) yyVAL.node.Sym = dclstack // context, for goto restrictions } case 269: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1785 + //line go.y:1846 { yyVAL.node = Nod(ORETURN, nil, nil) yyVAL.node.List = yyDollar[2].list @@ -3010,7 +3042,7 @@ yydefault: } case 270: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1807 + //line go.y:1868 { yyVAL.list = nil if yyDollar[1].node != nil { @@ -3019,7 +3051,7 @@ yydefault: } case 271: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1814 + //line go.y:1875 { yyVAL.list = yyDollar[1].list if yyDollar[3].node != nil { @@ -3028,163 +3060,163 @@ yydefault: } case 272: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1823 + //line go.y:1884 { yyVAL.list = list1(yyDollar[1].node) } case 273: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1827 + //line go.y:1888 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 274: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1833 + //line go.y:1894 { yyVAL.list = list1(yyDollar[1].node) } case 275: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1837 + //line go.y:1898 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 276: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1843 + //line go.y:1904 { yyVAL.list = list1(yyDollar[1].node) } case 277: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1847 + //line go.y:1908 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 278: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1853 + //line go.y:1914 { yyVAL.list = list1(yyDollar[1].node) } case 279: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1857 + //line go.y:1918 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 280: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1866 + //line go.y:1927 { yyVAL.list = list1(yyDollar[1].node) } case 281: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1870 + //line go.y:1931 { yyVAL.list = list1(yyDollar[1].node) } case 282: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1874 + //line go.y:1935 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 283: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:1878 + //line go.y:1939 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 284: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1883 + //line go.y:1944 { yyVAL.list = nil } case 285: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:1887 + //line go.y:1948 { yyVAL.list = yyDollar[1].list } case 290: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1901 + //line go.y:1962 { yyVAL.node = nil } case 292: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1907 + //line go.y:1968 { yyVAL.list = nil } case 294: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1913 + //line go.y:1974 { yyVAL.node = nil } case 296: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1919 + //line go.y:1980 { yyVAL.list = nil } case 298: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1925 + //line go.y:1986 { yyVAL.list = nil } case 300: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1931 + //line go.y:1992 { yyVAL.list = nil } case 302: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:1937 + //line go.y:1998 { yyVAL.val.Ctype = CTxxx } case 304: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1947 + //line go.y:2008 { importimport(yyDollar[2].sym, yyDollar[3].val.U.(string)) } case 305: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1951 + //line go.y:2012 { importvar(yyDollar[2].sym, yyDollar[3].typ) } case 306: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:1955 + //line go.y:2016 { importconst(yyDollar[2].sym, Types[TIDEAL], yyDollar[4].node) } case 307: yyDollar = yyS[yypt-6 : yypt+1] - //line go.y:1959 + //line go.y:2020 { importconst(yyDollar[2].sym, yyDollar[3].typ, yyDollar[5].node) } case 308: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1963 + //line go.y:2024 { importtype(yyDollar[2].typ, yyDollar[3].typ) } case 309: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:1967 + //line go.y:2028 { if yyDollar[2].node == nil { dclcontext = PEXTERN // since we skip the funcbody below @@ -3205,27 +3237,27 @@ yydefault: } case 310: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1988 + //line go.y:2049 { yyVAL.sym = yyDollar[1].sym structpkg = yyVAL.sym.Pkg } case 311: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:1995 + //line go.y:2056 { yyVAL.typ = pkgtype(yyDollar[1].sym) importsym(yyDollar[1].sym, OTYPE) } case 317: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:2015 + //line go.y:2076 { yyVAL.typ = pkgtype(yyDollar[1].sym) } case 318: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:2019 + //line go.y:2080 { // predefined name like uint8 yyDollar[1].sym = Pkglookup(yyDollar[1].sym.Name, builtinpkg) @@ -3238,43 +3270,43 @@ yydefault: } case 319: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:2030 + //line go.y:2091 { yyVAL.typ = aindex(nil, yyDollar[3].typ) } case 320: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:2034 + //line go.y:2095 { yyVAL.typ = aindex(nodlit(yyDollar[2].val), yyDollar[4].typ) } case 321: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:2038 + //line go.y:2099 { yyVAL.typ = maptype(yyDollar[3].typ, yyDollar[5].typ) } case 322: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:2042 + //line go.y:2103 { yyVAL.typ = tostruct(yyDollar[3].list) } case 323: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:2046 + //line go.y:2107 { yyVAL.typ = tointerface(yyDollar[3].list) } case 324: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:2050 + //line go.y:2111 { yyVAL.typ = Ptrto(yyDollar[2].typ) } case 325: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:2054 + //line go.y:2115 { yyVAL.typ = typ(TCHAN) yyVAL.typ.Type = yyDollar[2].typ @@ -3282,7 +3314,7 @@ yydefault: } case 326: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:2060 + //line go.y:2121 { yyVAL.typ = typ(TCHAN) yyVAL.typ.Type = yyDollar[3].typ @@ -3290,7 +3322,7 @@ yydefault: } case 327: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:2066 + //line go.y:2127 { yyVAL.typ = typ(TCHAN) yyVAL.typ.Type = yyDollar[3].typ @@ -3298,7 +3330,7 @@ yydefault: } case 328: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:2074 + //line go.y:2135 { yyVAL.typ = typ(TCHAN) yyVAL.typ.Type = yyDollar[3].typ @@ -3306,13 +3338,13 @@ yydefault: } case 329: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:2082 + //line go.y:2143 { yyVAL.typ = functype(nil, yyDollar[3].list, yyDollar[5].list) } case 330: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:2088 + //line go.y:2149 { yyVAL.node = Nod(ODCLFIELD, nil, typenod(yyDollar[2].typ)) if yyDollar[1].sym != nil { @@ -3322,7 +3354,7 @@ yydefault: } case 331: yyDollar = yyS[yypt-4 : yypt+1] - //line go.y:2096 + //line go.y:2157 { var t *Type @@ -3339,7 +3371,7 @@ yydefault: } case 332: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:2113 + //line go.y:2174 { var s *Sym var p *Pkg @@ -3363,43 +3395,43 @@ yydefault: } case 333: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:2137 + //line go.y:2198 { yyVAL.node = Nod(ODCLFIELD, newname(yyDollar[1].sym), typenod(functype(fakethis(), yyDollar[3].list, yyDollar[5].list))) } case 334: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:2141 + //line go.y:2202 { yyVAL.node = Nod(ODCLFIELD, nil, typenod(yyDollar[1].typ)) } case 335: yyDollar = yyS[yypt-0 : yypt+1] - //line go.y:2146 + //line go.y:2207 { yyVAL.list = nil } case 337: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:2153 + //line go.y:2214 { yyVAL.list = yyDollar[2].list } case 338: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:2157 + //line go.y:2218 { yyVAL.list = list1(Nod(ODCLFIELD, nil, typenod(yyDollar[1].typ))) } case 339: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:2167 + //line go.y:2228 { yyVAL.node = nodlit(yyDollar[1].val) } case 340: yyDollar = yyS[yypt-2 : yypt+1] - //line go.y:2171 + //line go.y:2232 { yyVAL.node = nodlit(yyDollar[2].val) switch yyVAL.node.Val.Ctype { @@ -3419,7 +3451,7 @@ yydefault: } case 341: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:2189 + //line go.y:2250 { yyVAL.node = oldname(Pkglookup(yyDollar[1].sym.Name, builtinpkg)) if yyVAL.node.Op != OLITERAL { @@ -3428,7 +3460,7 @@ yydefault: } case 343: yyDollar = yyS[yypt-5 : yypt+1] - //line go.y:2199 + //line go.y:2260 { if yyDollar[2].node.Val.Ctype == CTRUNE && yyDollar[4].node.Val.Ctype == CTINT { yyVAL.node = yyDollar[2].node @@ -3441,37 +3473,37 @@ yydefault: } case 346: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:2215 + //line go.y:2276 { yyVAL.list = list1(yyDollar[1].node) } case 347: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:2219 + //line go.y:2280 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 348: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:2225 + //line go.y:2286 { yyVAL.list = list1(yyDollar[1].node) } case 349: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:2229 + //line go.y:2290 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } case 350: yyDollar = yyS[yypt-1 : yypt+1] - //line go.y:2235 + //line go.y:2296 { yyVAL.list = list1(yyDollar[1].node) } case 351: yyDollar = yyS[yypt-3 : yypt+1] - //line go.y:2239 + //line go.y:2300 { yyVAL.list = list(yyDollar[1].list, yyDollar[3].node) } diff --git a/src/cmd/internal/gc/y.output b/src/cmd/internal/gc/y.output index f105838a7f..2821702aea 100644 --- a/src/cmd/internal/gc/y.output +++ b/src/cmd/internal/gc/y.output @@ -3,7 +3,7 @@ state 0 $accept: .file $end $$4: . (4) - . reduce 4 (src line 149) + . reduce 4 (src line 210) file goto 1 loadsys goto 2 @@ -21,7 +21,7 @@ state 2 package: . (2) LPACKAGE shift 5 - . reduce 2 (src line 132) + . reduce 2 (src line 193) package goto 4 @@ -37,7 +37,7 @@ state 4 file: loadsys package.imports xdcl_list imports: . (6) - . reduce 6 (src line 166) + . reduce 6 (src line 227) imports goto 8 @@ -56,7 +56,7 @@ state 6 loadsys: $$4 import_package.import_there $$21: . (21) - . reduce 21 (src line 273) + . reduce 21 (src line 334) import_there goto 14 $$21 goto 15 @@ -74,7 +74,7 @@ state 8 xdcl_list: . (218) LIMPORT shift 19 - . reduce 218 (src line 1508) + . reduce 218 (src line 1569) xdcl_list goto 17 import goto 18 @@ -89,19 +89,19 @@ state 9 state 10 sym: LNAME. (157) - . reduce 157 (src line 1114) + . reduce 157 (src line 1175) state 11 sym: hidden_importsym. (158) - . reduce 158 (src line 1123) + . reduce 158 (src line 1184) state 12 sym: '?'. (159) - . reduce 159 (src line 1124) + . reduce 159 (src line 1185) state 13 @@ -115,14 +115,14 @@ state 13 state 14 loadsys: $$4 import_package import_there. (5) - . reduce 5 (src line 160) + . reduce 5 (src line 221) state 15 import_there: $$21.hidden_import_list '$' '$' hidden_import_list: . (344) - . reduce 344 (src line 2210) + . reduce 344 (src line 2271) hidden_import_list goto 22 @@ -131,7 +131,7 @@ state 16 import_safety: . (19) LNAME shift 24 - . reduce 19 (src line 265) + . reduce 19 (src line 326) import_safety goto 23 @@ -140,7 +140,7 @@ state 17 xdcl_list: xdcl_list.xdcl ';' xdcl: . (23) - $end reduce 1 (src line 123) + $end reduce 1 (src line 184) error shift 29 LLITERAL shift 68 LBREAK shift 41 @@ -170,7 +170,7 @@ state 17 '*' shift 58 '&' shift 59 '(' shift 67 - ';' reduce 23 (src line 286) + ';' reduce 23 (src line 347) '!' shift 62 '~' shift 63 '[' shift 77 @@ -236,7 +236,7 @@ state 19 state 20 package: LPACKAGE sym ';'. (3) - . reduce 3 (src line 139) + . reduce 3 (src line 200) state 21 @@ -271,7 +271,7 @@ state 23 state 24 import_safety: LNAME. (20) - . reduce 20 (src line 266) + . reduce 20 (src line 327) state 25 @@ -284,25 +284,25 @@ state 25 state 26 xdcl: common_dcl. (24) - . reduce 24 (src line 291) + . reduce 24 (src line 352) state 27 xdcl: xfndcl. (25) - . reduce 25 (src line 292) + . reduce 25 (src line 353) state 28 xdcl: non_dcl_stmt. (26) - . reduce 26 (src line 296) + . reduce 26 (src line 357) state 29 xdcl: error. (27) - . reduce 27 (src line 301) + . reduce 27 (src line 362) state 30 @@ -373,31 +373,31 @@ state 33 state 34 non_dcl_stmt: simple_stmt. (256) - . reduce 256 (src line 1735) + . reduce 256 (src line 1796) state 35 non_dcl_stmt: for_stmt. (257) - . reduce 257 (src line 1737) + . reduce 257 (src line 1798) state 36 non_dcl_stmt: switch_stmt. (258) - . reduce 258 (src line 1738) + . reduce 258 (src line 1799) state 37 non_dcl_stmt: select_stmt. (259) - . reduce 259 (src line 1739) + . reduce 259 (src line 1800) state 38 non_dcl_stmt: if_stmt. (260) - . reduce 260 (src line 1740) + . reduce 260 (src line 1801) state 39 @@ -410,7 +410,7 @@ state 39 state 40 non_dcl_stmt: LFALL. (263) - . reduce 263 (src line 1757) + . reduce 263 (src line 1818) state 41 @@ -420,7 +420,7 @@ state 41 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 155 (src line 1108) + . reduce 155 (src line 1169) sym goto 119 new_name goto 118 @@ -434,7 +434,7 @@ state 42 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 155 (src line 1108) + . reduce 155 (src line 1169) sym goto 119 new_name goto 118 @@ -538,7 +538,7 @@ state 46 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 292 (src line 1906) + . reduce 292 (src line 1967) sym goto 123 expr goto 129 @@ -562,7 +562,7 @@ state 46 state 47 lconst: LCONST. (38) - . reduce 38 (src line 355) + . reduce 38 (src line 416) state 48 @@ -593,7 +593,7 @@ state 48 expr_list: expr. (276) LASOP shift 130 - LCOLAS reduce 276 (src line 1841) + LCOLAS reduce 276 (src line 1902) LANDAND shift 134 LANDNOT shift 149 LCOMM shift 152 @@ -616,9 +616,9 @@ state 48 '/' shift 146 '%' shift 147 '&' shift 148 - '=' reduce 276 (src line 1841) - ',' reduce 276 (src line 1841) - . reduce 49 (src line 411) + '=' reduce 276 (src line 1902) + ',' reduce 276 (src line 1902) + . reduce 49 (src line 472) state 49 @@ -636,7 +636,7 @@ state 50 for_stmt: LFOR.$$74 for_body $$74: . (74) - . reduce 74 (src line 660) + . reduce 74 (src line 721) $$74 goto 156 @@ -644,7 +644,7 @@ state 51 switch_stmt: LSWITCH.$$88 if_header $$89 LBODY caseblock_list '}' $$88: . (88) - . reduce 88 (src line 755) + . reduce 88 (src line 816) $$88 goto 157 @@ -652,7 +652,7 @@ state 52 select_stmt: LSELECT.$$91 LBODY caseblock_list '}' $$91: . (91) - . reduce 91 (src line 778) + . reduce 91 (src line 839) $$91 goto 158 @@ -660,28 +660,28 @@ state 53 if_stmt: LIF.$$78 if_header $$79 loop_body $$80 elseif_list else $$78: . (78) - . reduce 78 (src line 689) + . reduce 78 (src line 750) $$78 goto 159 state 54 labelname: new_name. (163) - . reduce 163 (src line 1168) + . reduce 163 (src line 1229) state 55 expr: uexpr. (93) - . reduce 93 (src line 794) + . reduce 93 (src line 855) state 56 new_name: sym. (153) name: sym. (162) - ':' reduce 153 (src line 1092) - . reduce 162 (src line 1159) + ':' reduce 153 (src line 1153) + . reduce 162 (src line 1220) state 57 @@ -699,7 +699,7 @@ state 57 '(' shift 160 '.' shift 161 '[' shift 162 - . reduce 114 (src line 878) + . reduce 114 (src line 939) state 58 @@ -1027,7 +1027,7 @@ state 66 pexpr: pexpr_no_paren. (146) '{' shift 171 - . reduce 146 (src line 1055) + . reduce 146 (src line 1116) state 67 @@ -1078,19 +1078,19 @@ state 67 state 68 pexpr_no_paren: LLITERAL. (126) - . reduce 126 (src line 942) + . reduce 126 (src line 1003) state 69 pexpr_no_paren: name. (127) - . reduce 127 (src line 947) + . reduce 127 (src line 1008) state 70 pexpr_no_paren: pseudocall. (134) - . reduce 134 (src line 985) + . reduce 134 (src line 1046) state 71 @@ -1112,23 +1112,23 @@ state 72 state 73 pexpr_no_paren: fnliteral. (139) - . reduce 139 (src line 1012) + . reduce 139 (src line 1073) state 74 convtype: fntype. (181) fnlitdcl: fntype. (215) - '(' reduce 181 (src line 1221) - . reduce 215 (src line 1485) + '(' reduce 181 (src line 1282) + . reduce 215 (src line 1546) state 75 convtype: othertype. (182) comptype: othertype. (183) - '(' reduce 182 (src line 1223) - . reduce 183 (src line 1225) + '(' reduce 182 (src line 1284) + . reduce 183 (src line 1286) state 76 @@ -1167,7 +1167,7 @@ state 77 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 290 (src line 1900) + . reduce 290 (src line 1961) sym goto 123 expr goto 188 @@ -1226,13 +1226,13 @@ state 79 state 80 othertype: structtype. (196) - . reduce 196 (src line 1273) + . reduce 196 (src line 1334) state 81 othertype: interfacetype. (197) - . reduce 197 (src line 1274) + . reduce 197 (src line 1335) state 82 @@ -1258,13 +1258,13 @@ state 83 state 84 imports: imports import ';'. (7) - . reduce 7 (src line 167) + . reduce 7 (src line 228) state 85 import: LIMPORT import_stmt. (8) - . reduce 8 (src line 169) + . reduce 8 (src line 230) state 86 @@ -1291,7 +1291,7 @@ state 87 $$21: . (21) LPACKAGE shift 7 - . reduce 21 (src line 273) + . reduce 21 (src line 334) import_package goto 204 import_there goto 205 @@ -1300,7 +1300,7 @@ state 87 state 88 import_here: LLITERAL. (15) - . reduce 15 (src line 225) + . reduce 15 (src line 286) state 89 @@ -1336,7 +1336,7 @@ state 92 state 93 hidden_import_list: hidden_import_list hidden_import. (345) - . reduce 345 (src line 2211) + . reduce 345 (src line 2272) state 94 @@ -1389,19 +1389,19 @@ state 98 state 99 import_package: LPACKAGE LNAME import_safety ';'. (18) - . reduce 18 (src line 248) + . reduce 18 (src line 309) state 100 xdcl_list: xdcl_list xdcl ';'. (219) - . reduce 219 (src line 1512) + . reduce 219 (src line 1573) state 101 common_dcl: LVAR vardcl. (28) - . reduce 28 (src line 306) + . reduce 28 (src line 367) state 102 @@ -1458,19 +1458,19 @@ state 103 state 104 dcl_name_list: dcl_name. (274) - . reduce 274 (src line 1831) + . reduce 274 (src line 1892) state 105 dcl_name: sym. (154) - . reduce 154 (src line 1102) + . reduce 154 (src line 1163) state 106 common_dcl: lconst constdcl. (31) - . reduce 31 (src line 319) + . reduce 31 (src line 380) state 107 @@ -1526,7 +1526,7 @@ state 108 state 109 common_dcl: LTYPE typedcl. (35) - . reduce 35 (src line 342) + . reduce 35 (src line 403) state 110 @@ -1577,7 +1577,7 @@ state 111 state 112 typedclname: sym. (47) - . reduce 47 (src line 396) + . reduce 47 (src line 457) state 113 @@ -1585,7 +1585,7 @@ state 113 fnbody: . (210) '{' shift 242 - . reduce 210 (src line 1458) + . reduce 210 (src line 1519) fnbody goto 241 @@ -1607,7 +1607,7 @@ state 114 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 249 (src line 1708) + . reduce 249 (src line 1769) sym goto 247 ntype goto 249 @@ -1637,43 +1637,43 @@ state 116 non_dcl_stmt: labelname ':'.$$261 stmt $$261: . (261) - . reduce 261 (src line 1741) + . reduce 261 (src line 1802) $$261 goto 252 state 117 non_dcl_stmt: LBREAK onew_name. (264) - . reduce 264 (src line 1763) + . reduce 264 (src line 1824) state 118 onew_name: new_name. (156) - . reduce 156 (src line 1112) + . reduce 156 (src line 1173) state 119 new_name: sym. (153) - . reduce 153 (src line 1092) + . reduce 153 (src line 1153) state 120 non_dcl_stmt: LCONTINUE onew_name. (265) - . reduce 265 (src line 1767) + . reduce 265 (src line 1828) state 121 pexpr_no_paren: pseudocall. (134) non_dcl_stmt: LGO pseudocall. (266) - '(' reduce 134 (src line 985) - '.' reduce 134 (src line 985) - '{' reduce 134 (src line 985) - '[' reduce 134 (src line 985) - . reduce 266 (src line 1771) + '(' reduce 134 (src line 1046) + '.' reduce 134 (src line 1046) + '{' reduce 134 (src line 1046) + '[' reduce 134 (src line 1046) + . reduce 266 (src line 1832) state 122 @@ -1696,7 +1696,7 @@ state 122 state 123 name: sym. (162) - . reduce 162 (src line 1159) + . reduce 162 (src line 1220) state 124 @@ -1710,23 +1710,23 @@ state 125 pexpr_no_paren: pseudocall. (134) non_dcl_stmt: LDEFER pseudocall. (267) - '(' reduce 134 (src line 985) - '.' reduce 134 (src line 985) - '{' reduce 134 (src line 985) - '[' reduce 134 (src line 985) - . reduce 267 (src line 1775) + '(' reduce 134 (src line 1046) + '.' reduce 134 (src line 1046) + '{' reduce 134 (src line 1046) + '[' reduce 134 (src line 1046) + . reduce 267 (src line 1836) state 126 non_dcl_stmt: LGOTO new_name. (268) - . reduce 268 (src line 1779) + . reduce 268 (src line 1840) state 127 non_dcl_stmt: LRETURN oexpr_list. (269) - . reduce 269 (src line 1784) + . reduce 269 (src line 1845) state 128 @@ -1734,7 +1734,7 @@ state 128 oexpr_list: expr_list. (293) ',' shift 155 - . reduce 293 (src line 1910) + . reduce 293 (src line 1971) state 129 @@ -1780,7 +1780,7 @@ state 129 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 276 (src line 1841) + . reduce 276 (src line 1902) state 130 @@ -1827,13 +1827,13 @@ state 130 state 131 simple_stmt: expr LINC. (53) - . reduce 53 (src line 461) + . reduce 53 (src line 522) state 132 simple_stmt: expr LDEC. (54) - . reduce 54 (src line 467) + . reduce 54 (src line 528) state 133 @@ -2805,7 +2805,7 @@ state 156 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 294 (src line 1912) + . reduce 294 (src line 1973) sym goto 123 expr goto 48 @@ -2853,7 +2853,7 @@ state 157 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 294 (src line 1912) + . reduce 294 (src line 1973) sym goto 123 expr goto 48 @@ -2906,7 +2906,7 @@ state 159 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 294 (src line 1912) + . reduce 294 (src line 1973) sym goto 123 expr goto 48 @@ -3016,7 +3016,7 @@ state 162 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 290 (src line 1900) + . reduce 290 (src line 1961) sym goto 123 expr goto 294 @@ -3039,56 +3039,56 @@ state 162 state 163 uexpr: '*' uexpr. (115) - . reduce 115 (src line 880) + . reduce 115 (src line 941) state 164 uexpr: '&' uexpr. (116) - . reduce 116 (src line 884) + . reduce 116 (src line 945) state 165 uexpr: '+' uexpr. (117) - . reduce 117 (src line 895) + . reduce 117 (src line 956) state 166 uexpr: '-' uexpr. (118) - . reduce 118 (src line 899) + . reduce 118 (src line 960) state 167 uexpr: '!' uexpr. (119) - . reduce 119 (src line 903) + . reduce 119 (src line 964) state 168 uexpr: '~' uexpr. (120) - . reduce 120 (src line 907) + . reduce 120 (src line 968) state 169 uexpr: '^' uexpr. (121) - . reduce 121 (src line 912) + . reduce 121 (src line 973) state 170 uexpr: LCOMM uexpr. (122) - . reduce 122 (src line 916) + . reduce 122 (src line 977) state 171 pexpr_no_paren: pexpr_no_paren '{'.start_complit braced_keyval_list '}' start_complit: . (140) - . reduce 140 (src line 1014) + . reduce 140 (src line 1075) start_complit goto 296 @@ -3143,19 +3143,19 @@ state 173 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 148 (src line 1070) + . reduce 148 (src line 1131) state 174 expr_or_type: non_expr_type. (149) - . reduce 149 (src line 1072) + . reduce 149 (src line 1133) state 175 non_expr_type: recvchantype. (172) - . reduce 172 (src line 1202) + . reduce 172 (src line 1263) state 176 @@ -3163,11 +3163,11 @@ state 176 convtype: fntype. (181) fnlitdcl: fntype. (215) - error reduce 215 (src line 1485) - LBODY reduce 215 (src line 1485) - '(' reduce 181 (src line 1221) - '{' reduce 215 (src line 1485) - . reduce 173 (src line 1204) + error reduce 215 (src line 1546) + LBODY reduce 215 (src line 1546) + '(' reduce 181 (src line 1282) + '{' reduce 215 (src line 1546) + . reduce 173 (src line 1265) state 177 @@ -3175,10 +3175,10 @@ state 177 convtype: othertype. (182) comptype: othertype. (183) - LBODY reduce 183 (src line 1225) - '(' reduce 182 (src line 1223) - '{' reduce 183 (src line 1225) - . reduce 174 (src line 1205) + LBODY reduce 183 (src line 1286) + '(' reduce 182 (src line 1284) + '{' reduce 183 (src line 1286) + . reduce 174 (src line 1266) state 178 @@ -3310,20 +3310,20 @@ state 181 pexpr_no_paren: comptype lbrace.start_complit braced_keyval_list '}' start_complit: . (140) - . reduce 140 (src line 1014) + . reduce 140 (src line 1075) start_complit goto 301 state 182 lbrace: LBODY. (151) - . reduce 151 (src line 1077) + . reduce 151 (src line 1138) state 183 lbrace: '{'. (152) - . reduce 152 (src line 1082) + . reduce 152 (src line 1143) state 184 @@ -3359,9 +3359,9 @@ state 184 '*' shift 58 '&' shift 59 '(' shift 67 - ';' reduce 251 (src line 1720) + ';' reduce 251 (src line 1781) '{' shift 308 - '}' reduce 251 (src line 1720) + '}' reduce 251 (src line 1781) '!' shift 62 '~' shift 63 '[' shift 77 @@ -3403,7 +3403,7 @@ state 184 state 185 fnliteral: fnlitdcl error. (217) - . reduce 217 (src line 1497) + . reduce 217 (src line 1558) state 186 @@ -3463,13 +3463,13 @@ state 188 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 291 (src line 1904) + . reduce 291 (src line 1965) state 189 othertype: LCHAN non_recvchantype. (193) - . reduce 193 (src line 1259) + . reduce 193 (src line 1320) state 190 @@ -3504,25 +3504,25 @@ state 190 state 191 non_recvchantype: fntype. (176) - . reduce 176 (src line 1211) + . reduce 176 (src line 1272) state 192 non_recvchantype: othertype. (177) - . reduce 177 (src line 1213) + . reduce 177 (src line 1274) state 193 non_recvchantype: ptrtype. (178) - . reduce 178 (src line 1214) + . reduce 178 (src line 1275) state 194 non_recvchantype: dotname. (179) - . reduce 179 (src line 1215) + . reduce 179 (src line 1276) state 195 @@ -3588,7 +3588,7 @@ state 197 dotname: name.'.' sym '.' shift 314 - . reduce 189 (src line 1235) + . reduce 189 (src line 1296) state 198 @@ -3665,27 +3665,27 @@ state 201 osemi: . (286) ';' shift 333 - . reduce 286 (src line 1894) + . reduce 286 (src line 1955) osemi goto 332 state 202 import: LIMPORT '(' ')'. (10) - . reduce 10 (src line 172) + . reduce 10 (src line 233) state 203 import_stmt_list: import_stmt. (13) - . reduce 13 (src line 221) + . reduce 13 (src line 282) state 204 import_stmt: import_here import_package.import_there $$21: . (21) - . reduce 21 (src line 273) + . reduce 21 (src line 334) import_there goto 334 $$21 goto 15 @@ -3693,37 +3693,37 @@ state 204 state 205 import_stmt: import_here import_there. (12) - . reduce 12 (src line 210) + . reduce 12 (src line 271) state 206 import_here: sym LLITERAL. (16) - . reduce 16 (src line 233) + . reduce 16 (src line 294) state 207 import_here: '.' LLITERAL. (17) - . reduce 17 (src line 240) + . reduce 17 (src line 301) state 208 hidden_importsym: '@' LLITERAL '.' LNAME. (160) - . reduce 160 (src line 1129) + . reduce 160 (src line 1190) state 209 hidden_importsym: '@' LLITERAL '.' '?'. (161) - . reduce 161 (src line 1144) + . reduce 161 (src line 1205) state 210 import_there: $$21 hidden_import_list '$' '$'. (22) - . reduce 22 (src line 277) + . reduce 22 (src line 338) state 211 @@ -3757,7 +3757,7 @@ state 212 state 213 hidden_pkg_importsym: hidden_importsym. (310) - . reduce 310 (src line 1986) + . reduce 310 (src line 2047) state 214 @@ -3807,7 +3807,7 @@ state 215 state 216 hidden_pkgtype: hidden_pkg_importsym. (311) - . reduce 311 (src line 1993) + . reduce 311 (src line 2054) state 217 @@ -3815,7 +3815,7 @@ state 217 fnbody: . (210) '{' shift 242 - . reduce 210 (src line 1458) + . reduce 210 (src line 1519) fnbody goto 353 @@ -3845,20 +3845,20 @@ state 220 osemi: . (286) ';' shift 359 - . reduce 286 (src line 1894) + . reduce 286 (src line 1955) osemi goto 358 state 221 common_dcl: LVAR '(' ')'. (30) - . reduce 30 (src line 315) + . reduce 30 (src line 376) state 222 vardcl_list: vardcl. (220) - . reduce 220 (src line 1524) + . reduce 220 (src line 1585) state 223 @@ -3866,7 +3866,7 @@ state 223 vardcl: dcl_name_list ntype.'=' expr_list '=' shift 360 - . reduce 39 (src line 361) + . reduce 39 (src line 422) state 224 @@ -3926,31 +3926,31 @@ state 225 state 226 ntype: recvchantype. (166) - . reduce 166 (src line 1191) + . reduce 166 (src line 1252) state 227 ntype: fntype. (167) - . reduce 167 (src line 1193) + . reduce 167 (src line 1254) state 228 ntype: othertype. (168) - . reduce 168 (src line 1194) + . reduce 168 (src line 1255) state 229 ntype: ptrtype. (169) - . reduce 169 (src line 1195) + . reduce 169 (src line 1256) state 230 ntype: dotname. (170) - . reduce 170 (src line 1196) + . reduce 170 (src line 1257) state 231 @@ -3995,14 +3995,14 @@ state 233 osemi: . (286) ';' shift 366 - . reduce 286 (src line 1894) + . reduce 286 (src line 1955) osemi goto 365 state 234 common_dcl: lconst '(' ')'. (34) - . reduce 34 (src line 337) + . reduce 34 (src line 398) state 235 @@ -4060,32 +4060,32 @@ state 237 osemi: . (286) ';' shift 370 - . reduce 286 (src line 1894) + . reduce 286 (src line 1955) osemi goto 369 state 238 common_dcl: LTYPE '(' ')'. (37) - . reduce 37 (src line 350) + . reduce 37 (src line 411) state 239 typedcl_list: typedcl. (224) - . reduce 224 (src line 1538) + . reduce 224 (src line 1599) state 240 typedcl: typedclname ntype. (48) - . reduce 48 (src line 405) + . reduce 48 (src line 466) state 241 xfndcl: LFUNC fndcl fnbody. (204) - . reduce 204 (src line 1319) + . reduce 204 (src line 1380) state 242 @@ -4121,9 +4121,9 @@ state 242 '*' shift 58 '&' shift 59 '(' shift 67 - ';' reduce 251 (src line 1720) + ';' reduce 251 (src line 1781) '{' shift 308 - '}' reduce 251 (src line 1720) + '}' reduce 251 (src line 1781) '!' shift 62 '~' shift 63 '[' shift 77 @@ -4176,20 +4176,20 @@ state 244 ocomma: . (288) ',' shift 373 - . reduce 288 (src line 1897) + . reduce 288 (src line 1958) ocomma goto 374 state 245 arg_type_list: arg_type. (247) - . reduce 247 (src line 1698) + . reduce 247 (src line 1759) state 246 arg_type: name_or_type. (243) - . reduce 243 (src line 1682) + . reduce 243 (src line 1743) state 247 @@ -4210,7 +4210,7 @@ state 247 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 162 (src line 1159) + . reduce 162 (src line 1220) sym goto 123 ntype goto 249 @@ -4229,13 +4229,13 @@ state 247 state 248 arg_type: dotdotdot. (246) - . reduce 246 (src line 1696) + . reduce 246 (src line 1757) state 249 name_or_type: ntype. (150) - . reduce 150 (src line 1074) + . reduce 150 (src line 1135) state 250 @@ -4254,7 +4254,7 @@ state 250 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 164 (src line 1180) + . reduce 164 (src line 1241) sym goto 123 ntype goto 377 @@ -4285,7 +4285,7 @@ state 251 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 249 (src line 1708) + . reduce 249 (src line 1769) sym goto 247 ntype goto 249 @@ -4311,11 +4311,11 @@ state 252 error shift 307 LLITERAL shift 68 LBREAK shift 41 - LCASE reduce 251 (src line 1720) + LCASE reduce 251 (src line 1781) LCHAN shift 78 LCONST shift 47 LCONTINUE shift 42 - LDEFAULT reduce 251 (src line 1720) + LDEFAULT reduce 251 (src line 1781) LDEFER shift 44 LFALL shift 40 LFOR shift 50 @@ -4339,9 +4339,9 @@ state 252 '*' shift 58 '&' shift 59 '(' shift 67 - ';' reduce 251 (src line 1720) + ';' reduce 251 (src line 1781) '{' shift 308 - '}' reduce 251 (src line 1720) + '}' reduce 251 (src line 1781) '!' shift 62 '~' shift 63 '[' shift 77 @@ -4396,7 +4396,7 @@ state 253 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 249 (src line 1708) + . reduce 249 (src line 1769) sym goto 247 ntype goto 249 @@ -4458,7 +4458,7 @@ state 254 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 50 (src line 426) + . reduce 50 (src line 487) state 255 @@ -4502,7 +4502,7 @@ state 255 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 94 (src line 796) + . reduce 94 (src line 857) state 256 @@ -4545,7 +4545,7 @@ state 256 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 95 (src line 800) + . reduce 95 (src line 861) state 257 @@ -4582,7 +4582,7 @@ state 257 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 96 (src line 804) + . reduce 96 (src line 865) state 258 @@ -4619,7 +4619,7 @@ state 258 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 97 (src line 808) + . reduce 97 (src line 869) state 259 @@ -4656,7 +4656,7 @@ state 259 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 98 (src line 812) + . reduce 98 (src line 873) state 260 @@ -4693,7 +4693,7 @@ state 260 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 99 (src line 816) + . reduce 99 (src line 877) state 261 @@ -4730,7 +4730,7 @@ state 261 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 100 (src line 820) + . reduce 100 (src line 881) state 262 @@ -4767,7 +4767,7 @@ state 262 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 101 (src line 824) + . reduce 101 (src line 885) state 263 @@ -4800,7 +4800,7 @@ state 263 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 102 (src line 828) + . reduce 102 (src line 889) state 264 @@ -4833,7 +4833,7 @@ state 264 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 103 (src line 832) + . reduce 103 (src line 893) state 265 @@ -4866,7 +4866,7 @@ state 265 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 104 (src line 836) + . reduce 104 (src line 897) state 266 @@ -4899,7 +4899,7 @@ state 266 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 105 (src line 840) + . reduce 105 (src line 901) state 267 @@ -4925,7 +4925,7 @@ state 267 expr: expr.LRSH expr expr: expr.LCOMM expr - . reduce 106 (src line 844) + . reduce 106 (src line 905) state 268 @@ -4951,7 +4951,7 @@ state 268 expr: expr.LRSH expr expr: expr.LCOMM expr - . reduce 107 (src line 848) + . reduce 107 (src line 909) state 269 @@ -4977,7 +4977,7 @@ state 269 expr: expr.LRSH expr expr: expr.LCOMM expr - . reduce 108 (src line 852) + . reduce 108 (src line 913) state 270 @@ -5003,7 +5003,7 @@ state 270 expr: expr.LRSH expr expr: expr.LCOMM expr - . reduce 109 (src line 856) + . reduce 109 (src line 917) state 271 @@ -5029,7 +5029,7 @@ state 271 expr: expr.LRSH expr expr: expr.LCOMM expr - . reduce 110 (src line 860) + . reduce 110 (src line 921) state 272 @@ -5055,7 +5055,7 @@ state 272 expr: expr.LRSH expr expr: expr.LCOMM expr - . reduce 111 (src line 864) + . reduce 111 (src line 925) state 273 @@ -5081,7 +5081,7 @@ state 273 expr: expr LRSH expr. (112) expr: expr.LCOMM expr - . reduce 112 (src line 868) + . reduce 112 (src line 929) state 274 @@ -5126,7 +5126,7 @@ state 274 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 113 (src line 873) + . reduce 113 (src line 934) state 275 @@ -5134,7 +5134,7 @@ state 275 expr_list: expr_list.',' expr ',' shift 155 - . reduce 51 (src line 431) + . reduce 51 (src line 492) state 276 @@ -5142,7 +5142,7 @@ state 276 expr_list: expr_list.',' expr ',' shift 155 - . reduce 52 (src line 443) + . reduce 52 (src line 504) state 277 @@ -5188,13 +5188,13 @@ state 277 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 277 (src line 1846) + . reduce 277 (src line 1907) state 278 for_stmt: LFOR $$74 for_body. (75) - . reduce 75 (src line 665) + . reduce 75 (src line 726) state 279 @@ -5210,19 +5210,19 @@ state 280 for_header: osimple_stmt. (71) ';' shift 383 - . reduce 71 (src line 645) + . reduce 71 (src line 706) state 281 for_header: range_stmt. (72) - . reduce 72 (src line 651) + . reduce 72 (src line 712) state 282 osimple_stmt: simple_stmt. (295) - . reduce 295 (src line 1916) + . reduce 295 (src line 1977) state 283 @@ -5283,7 +5283,7 @@ state 285 switch_stmt: LSWITCH $$88 if_header.$$89 LBODY caseblock_list '}' $$89: . (89) - . reduce 89 (src line 760) + . reduce 89 (src line 821) $$89 goto 387 @@ -5292,14 +5292,14 @@ state 286 if_header: osimple_stmt.';' osimple_stmt ';' shift 388 - . reduce 76 (src line 671) + . reduce 76 (src line 732) state 287 select_stmt: LSELECT $$91 LBODY.caseblock_list '}' caseblock_list: . (63) - . reduce 63 (src line 591) + . reduce 63 (src line 652) caseblock_list goto 389 @@ -5307,14 +5307,14 @@ state 288 if_stmt: LIF $$78 if_header.$$79 loop_body $$80 elseif_list else $$79: . (79) - . reduce 79 (src line 694) + . reduce 79 (src line 755) $$79 goto 390 state 289 pseudocall: pexpr '(' ')'. (123) - . reduce 123 (src line 925) + . reduce 123 (src line 986) state 290 @@ -5325,20 +5325,20 @@ state 290 LDDD shift 392 ',' shift 393 - . reduce 288 (src line 1897) + . reduce 288 (src line 1958) ocomma goto 391 state 291 expr_or_type_list: expr_or_type. (278) - . reduce 278 (src line 1851) + . reduce 278 (src line 1912) state 292 pexpr_no_paren: pexpr '.' sym. (128) - . reduce 128 (src line 948) + . reduce 128 (src line 1009) state 293 @@ -5432,7 +5432,7 @@ state 294 '%' shift 147 '&' shift 148 ']' shift 396 - . reduce 291 (src line 1904) + . reduce 291 (src line 1965) state 295 @@ -5467,7 +5467,7 @@ state 296 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 284 (src line 1882) + . reduce 284 (src line 1943) sym goto 123 expr goto 402 @@ -5495,13 +5495,13 @@ state 297 pexpr: '(' expr_or_type ')'. (147) '{' shift 404 - . reduce 147 (src line 1057) + . reduce 147 (src line 1118) state 298 non_expr_type: '*' non_expr_type. (175) - . reduce 175 (src line 1206) + . reduce 175 (src line 1267) state 299 @@ -5581,7 +5581,7 @@ state 300 '%' shift 147 '&' shift 148 ',' shift 413 - . reduce 288 (src line 1897) + . reduce 288 (src line 1958) ocomma goto 412 @@ -5609,7 +5609,7 @@ state 301 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 284 (src line 1882) + . reduce 284 (src line 1943) sym goto 123 expr goto 402 @@ -5644,38 +5644,38 @@ state 302 state 303 stmt_list: stmt. (270) - . reduce 270 (src line 1805) + . reduce 270 (src line 1866) state 304 stmt: compound_stmt. (252) - . reduce 252 (src line 1724) + . reduce 252 (src line 1785) state 305 stmt: common_dcl. (253) - . reduce 253 (src line 1725) + . reduce 253 (src line 1786) state 306 stmt: non_dcl_stmt. (254) - . reduce 254 (src line 1729) + . reduce 254 (src line 1790) state 307 stmt: error. (255) - . reduce 255 (src line 1730) + . reduce 255 (src line 1791) state 308 compound_stmt: '{'.$$59 stmt_list '}' $$59: . (59) - . reduce 59 (src line 545) + . reduce 59 (src line 606) $$59 goto 417 @@ -5740,7 +5740,7 @@ state 310 state 311 othertype: LCHAN LCOMM ntype. (194) - . reduce 194 (src line 1264) + . reduce 194 (src line 1325) state 312 @@ -5753,7 +5753,7 @@ state 312 state 313 ptrtype: '*' ntype. (198) - . reduce 198 (src line 1276) + . reduce 198 (src line 1337) state 314 @@ -5780,20 +5780,20 @@ state 316 osemi: . (286) ';' shift 424 - . reduce 286 (src line 1894) + . reduce 286 (src line 1955) osemi goto 423 state 317 structtype: LSTRUCT lbrace '}'. (201) - . reduce 201 (src line 1296) + . reduce 201 (src line 1357) state 318 structdcl_list: structdcl. (226) - . reduce 226 (src line 1548) + . reduce 226 (src line 1609) state 319 @@ -5832,7 +5832,7 @@ state 320 oliteral: . (302) LLITERAL shift 428 - . reduce 302 (src line 1936) + . reduce 302 (src line 1997) oliteral goto 427 @@ -5861,13 +5861,13 @@ state 322 state 323 new_name_list: new_name. (272) - . reduce 272 (src line 1821) + . reduce 272 (src line 1882) state 324 embed: packname. (238) - . reduce 238 (src line 1647) + . reduce 238 (src line 1708) state 325 @@ -5875,11 +5875,11 @@ state 325 packname: LNAME. (236) packname: LNAME.'.' sym - LLITERAL reduce 236 (src line 1622) - ';' reduce 236 (src line 1622) + LLITERAL reduce 236 (src line 1683) + ';' reduce 236 (src line 1683) '.' shift 434 - '}' reduce 236 (src line 1622) - . reduce 157 (src line 1114) + '}' reduce 236 (src line 1683) + . reduce 157 (src line 1175) state 326 @@ -5888,20 +5888,20 @@ state 326 osemi: . (286) ';' shift 436 - . reduce 286 (src line 1894) + . reduce 286 (src line 1955) osemi goto 435 state 327 interfacetype: LINTERFACE lbrace '}'. (203) - . reduce 203 (src line 1309) + . reduce 203 (src line 1370) state 328 interfacedcl_list: interfacedcl. (228) - . reduce 228 (src line 1555) + . reduce 228 (src line 1616) state 329 @@ -5915,7 +5915,7 @@ state 329 state 330 interfacedcl: packname. (240) - . reduce 240 (src line 1659) + . reduce 240 (src line 1720) state 331 @@ -5942,7 +5942,7 @@ state 333 '.' shift 90 '?' shift 12 '@' shift 13 - . reduce 287 (src line 1895) + . reduce 287 (src line 1956) import_here goto 87 sym goto 89 @@ -5952,7 +5952,7 @@ state 333 state 334 import_stmt: import_here import_package import_there. (11) - . reduce 11 (src line 174) + . reduce 11 (src line 235) state 335 @@ -5972,31 +5972,31 @@ state 336 state 337 hidden_type: hidden_type_misc. (312) - . reduce 312 (src line 2004) + . reduce 312 (src line 2065) state 338 hidden_type: hidden_type_recv_chan. (313) - . reduce 313 (src line 2006) + . reduce 313 (src line 2067) state 339 hidden_type: hidden_type_func. (314) - . reduce 314 (src line 2007) + . reduce 314 (src line 2068) state 340 hidden_type_misc: hidden_importsym. (317) - . reduce 317 (src line 2013) + . reduce 317 (src line 2074) state 341 hidden_type_misc: LNAME. (318) - . reduce 318 (src line 2018) + . reduce 318 (src line 2079) state 342 @@ -6131,7 +6131,7 @@ state 354 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 296 (src line 1918) + . reduce 296 (src line 1979) sym goto 357 hidden_importsym goto 11 @@ -6151,7 +6151,7 @@ state 355 state 356 hidden_funarg_list: hidden_funarg. (346) - . reduce 346 (src line 2213) + . reduce 346 (src line 2274) state 357 @@ -6191,7 +6191,7 @@ state 359 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 287 (src line 1895) + . reduce 287 (src line 1956) sym goto 105 dcl_name goto 104 @@ -6246,13 +6246,13 @@ state 361 expr_list: expr_list.',' expr ',' shift 155 - . reduce 41 (src line 370) + . reduce 41 (src line 431) state 362 dcl_name_list: dcl_name_list ',' dcl_name. (275) - . reduce 275 (src line 1836) + . reduce 275 (src line 1897) state 363 @@ -6305,7 +6305,7 @@ state 366 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 287 (src line 1895) + . reduce 287 (src line 1956) sym goto 105 dcl_name goto 104 @@ -6362,7 +6362,7 @@ state 368 expr_list: expr_list.',' expr ',' shift 155 - . reduce 43 (src line 380) + . reduce 43 (src line 441) state 369 @@ -6379,7 +6379,7 @@ state 370 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 287 (src line 1895) + . reduce 287 (src line 1956) sym goto 112 typedclname goto 111 @@ -6412,7 +6412,7 @@ state 372 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 212 (src line 1470) + . reduce 212 (src line 1531) sym goto 485 dotname goto 493 @@ -6444,7 +6444,7 @@ state 373 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 289 (src line 1898) + . reduce 289 (src line 1959) sym goto 247 ntype goto 249 @@ -6464,25 +6464,25 @@ state 373 state 374 oarg_type_list_ocomma: arg_type_list ocomma. (250) - . reduce 250 (src line 1712) + . reduce 250 (src line 1773) state 375 arg_type: sym name_or_type. (244) - . reduce 244 (src line 1684) + . reduce 244 (src line 1745) state 376 arg_type: sym dotdotdot. (245) - . reduce 245 (src line 1690) + . reduce 245 (src line 1751) state 377 dotdotdot: LDDD ntype. (165) - . reduce 165 (src line 1186) + . reduce 165 (src line 1247) state 378 @@ -6495,7 +6495,7 @@ state 378 state 379 non_dcl_stmt: labelname ':' $$261 stmt. (262) - . reduce 262 (src line 1746) + . reduce 262 (src line 1807) state 380 @@ -6508,14 +6508,14 @@ state 380 state 381 for_body: for_header loop_body. (73) - . reduce 73 (src line 653) + . reduce 73 (src line 714) state 382 loop_body: LBODY.$$65 stmt_list '}' $$65: . (65) - . reduce 65 (src line 600) + . reduce 65 (src line 661) $$65 goto 497 @@ -6542,7 +6542,7 @@ state 383 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 294 (src line 1912) + . reduce 294 (src line 1973) sym goto 123 expr goto 48 @@ -6695,7 +6695,7 @@ state 386 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 69 (src line 625) + . reduce 69 (src line 686) state 387 @@ -6728,7 +6728,7 @@ state 388 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 294 (src line 1912) + . reduce 294 (src line 1973) sym goto 123 expr goto 48 @@ -6782,7 +6782,7 @@ state 392 ocomma: . (288) ',' shift 413 - . reduce 288 (src line 1897) + . reduce 288 (src line 1958) ocomma goto 510 @@ -6809,7 +6809,7 @@ state 393 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 289 (src line 1898) + . reduce 289 (src line 1959) sym goto 123 expr goto 173 @@ -6848,7 +6848,7 @@ state 395 state 396 pexpr_no_paren: pexpr '[' expr ']'. (131) - . reduce 131 (src line 967) + . reduce 131 (src line 1028) state 397 @@ -6875,7 +6875,7 @@ state 397 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 290 (src line 1900) + . reduce 290 (src line 1961) sym goto 123 expr goto 188 @@ -6909,20 +6909,20 @@ state 399 ocomma: . (288) ',' shift 516 - . reduce 288 (src line 1897) + . reduce 288 (src line 1958) ocomma goto 517 state 400 keyval_list: keyval. (280) - . reduce 280 (src line 1864) + . reduce 280 (src line 1925) state 401 keyval_list: bare_complitexpr. (281) - . reduce 281 (src line 1869) + . reduce 281 (src line 1930) state 402 @@ -6970,14 +6970,14 @@ state 402 '%' shift 147 '&' shift 148 ':' shift 518 - . reduce 142 (src line 1027) + . reduce 142 (src line 1088) state 403 bare_complitexpr: '{'.start_complit braced_keyval_list '}' start_complit: . (140) - . reduce 140 (src line 1014) + . reduce 140 (src line 1075) start_complit goto 519 @@ -6985,7 +6985,7 @@ state 404 pexpr_no_paren: '(' expr_or_type ')' '{'.start_complit braced_keyval_list '}' start_complit: . (140) - . reduce 140 (src line 1014) + . reduce 140 (src line 1075) start_complit goto 520 @@ -7022,47 +7022,47 @@ state 405 state 406 recvchantype: LCOMM LCHAN ntype. (199) - . reduce 199 (src line 1282) + . reduce 199 (src line 1343) state 407 ntype: fntype. (167) non_recvchantype: fntype. (176) - LBODY reduce 176 (src line 1211) - '(' reduce 176 (src line 1211) - '{' reduce 176 (src line 1211) - . reduce 167 (src line 1193) + LBODY reduce 176 (src line 1272) + '(' reduce 176 (src line 1272) + '{' reduce 176 (src line 1272) + . reduce 167 (src line 1254) state 408 ntype: othertype. (168) non_recvchantype: othertype. (177) - LBODY reduce 177 (src line 1213) - '(' reduce 177 (src line 1213) - '{' reduce 177 (src line 1213) - . reduce 168 (src line 1194) + LBODY reduce 177 (src line 1274) + '(' reduce 177 (src line 1274) + '{' reduce 177 (src line 1274) + . reduce 168 (src line 1255) state 409 ntype: ptrtype. (169) non_recvchantype: ptrtype. (178) - LBODY reduce 178 (src line 1214) - '(' reduce 178 (src line 1214) - '{' reduce 178 (src line 1214) - . reduce 169 (src line 1195) + LBODY reduce 178 (src line 1275) + '(' reduce 178 (src line 1275) + '{' reduce 178 (src line 1275) + . reduce 169 (src line 1256) state 410 ntype: dotname. (170) non_recvchantype: dotname. (179) - LBODY reduce 179 (src line 1215) - '(' reduce 179 (src line 1215) - '{' reduce 179 (src line 1215) - . reduce 170 (src line 1196) + LBODY reduce 179 (src line 1276) + '(' reduce 179 (src line 1276) + '{' reduce 179 (src line 1276) + . reduce 170 (src line 1257) state 411 @@ -7105,7 +7105,7 @@ state 412 state 413 ocomma: ','. (289) - . reduce 289 (src line 1898) + . reduce 289 (src line 1959) state 414 @@ -7118,7 +7118,7 @@ state 414 state 415 fnliteral: fnlitdcl lbrace stmt_list '}'. (216) - . reduce 216 (src line 1491) + . reduce 216 (src line 1552) state 416 @@ -7128,11 +7128,11 @@ state 416 error shift 307 LLITERAL shift 68 LBREAK shift 41 - LCASE reduce 251 (src line 1720) + LCASE reduce 251 (src line 1781) LCHAN shift 78 LCONST shift 47 LCONTINUE shift 42 - LDEFAULT reduce 251 (src line 1720) + LDEFAULT reduce 251 (src line 1781) LDEFER shift 44 LFALL shift 40 LFOR shift 50 @@ -7156,9 +7156,9 @@ state 416 '*' shift 58 '&' shift 59 '(' shift 67 - ';' reduce 251 (src line 1720) + ';' reduce 251 (src line 1781) '{' shift 308 - '}' reduce 251 (src line 1720) + '}' reduce 251 (src line 1781) '!' shift 62 '~' shift 63 '[' shift 77 @@ -7229,9 +7229,9 @@ state 417 '*' shift 58 '&' shift 59 '(' shift 67 - ';' reduce 251 (src line 1720) + ';' reduce 251 (src line 1781) '{' shift 308 - '}' reduce 251 (src line 1720) + '}' reduce 251 (src line 1781) '!' shift 62 '~' shift 63 '[' shift 77 @@ -7273,25 +7273,25 @@ state 417 state 418 othertype: '[' oexpr ']' ntype. (191) - . reduce 191 (src line 1249) + . reduce 191 (src line 1310) state 419 othertype: '[' LDDD ']' ntype. (192) - . reduce 192 (src line 1254) + . reduce 192 (src line 1315) state 420 non_recvchantype: '(' ntype ')'. (180) - . reduce 180 (src line 1216) + . reduce 180 (src line 1277) state 421 dotname: name '.' sym. (190) - . reduce 190 (src line 1237) + . reduce 190 (src line 1298) state 422 @@ -7339,7 +7339,7 @@ state 424 '(' shift 321 '?' shift 12 '@' shift 13 - . reduce 287 (src line 1895) + . reduce 287 (src line 1956) sym goto 119 packname goto 324 @@ -7354,7 +7354,7 @@ state 425 oliteral: . (302) LLITERAL shift 428 - . reduce 302 (src line 1936) + . reduce 302 (src line 1997) oliteral goto 529 @@ -7373,13 +7373,13 @@ state 426 state 427 structdcl: embed oliteral. (231) - . reduce 231 (src line 1590) + . reduce 231 (src line 1651) state 428 oliteral: LLITERAL. (303) - . reduce 303 (src line 1940) + . reduce 303 (src line 2001) state 429 @@ -7403,7 +7403,7 @@ state 431 packname: LNAME.'.' sym '.' shift 434 - . reduce 236 (src line 1622) + . reduce 236 (src line 1683) state 432 @@ -7411,7 +7411,7 @@ state 432 oliteral: . (302) LLITERAL shift 428 - . reduce 302 (src line 1936) + . reduce 302 (src line 1997) oliteral goto 533 @@ -7450,7 +7450,7 @@ state 436 '(' shift 331 '?' shift 12 '@' shift 13 - . reduce 287 (src line 1895) + . reduce 287 (src line 1956) sym goto 119 packname goto 330 @@ -7461,7 +7461,7 @@ state 436 state 437 interfacedcl: new_name indcl. (239) - . reduce 239 (src line 1653) + . reduce 239 (src line 1714) state 438 @@ -7481,7 +7481,7 @@ state 438 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 249 (src line 1708) + . reduce 249 (src line 1769) sym goto 247 ntype goto 249 @@ -7510,25 +7510,25 @@ state 439 state 440 import: LIMPORT '(' import_stmt_list osemi ')'. (9) - . reduce 9 (src line 171) + . reduce 9 (src line 232) state 441 import_stmt_list: import_stmt_list ';' import_stmt. (14) - . reduce 14 (src line 223) + . reduce 14 (src line 284) state 442 hidden_import: LIMPORT LNAME LLITERAL ';'. (304) - . reduce 304 (src line 1945) + . reduce 304 (src line 2006) state 443 hidden_import: LVAR hidden_pkg_importsym hidden_type ';'. (305) - . reduce 305 (src line 1950) + . reduce 305 (src line 2011) state 444 @@ -7587,7 +7587,7 @@ state 447 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 298 (src line 1924) + . reduce 298 (src line 1985) sym goto 546 hidden_importsym goto 11 @@ -7610,7 +7610,7 @@ state 448 '[' shift 342 '?' shift 12 '@' shift 13 - . reduce 300 (src line 1930) + . reduce 300 (src line 1991) sym goto 550 hidden_importsym goto 553 @@ -7625,13 +7625,13 @@ state 448 state 449 hidden_type_misc: '*' hidden_type. (324) - . reduce 324 (src line 2049) + . reduce 324 (src line 2110) state 450 hidden_type_misc: LCHAN hidden_type_non_recv_chan. (325) - . reduce 325 (src line 2053) + . reduce 325 (src line 2114) state 451 @@ -7666,13 +7666,13 @@ state 452 state 453 hidden_type_non_recv_chan: hidden_type_misc. (315) - . reduce 315 (src line 2009) + . reduce 315 (src line 2070) state 454 hidden_type_non_recv_chan: hidden_type_func. (316) - . reduce 316 (src line 2011) + . reduce 316 (src line 2072) state 455 @@ -7703,7 +7703,7 @@ state 456 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 296 (src line 1918) + . reduce 296 (src line 1979) sym goto 357 hidden_importsym goto 11 @@ -7721,7 +7721,7 @@ state 457 state 458 hidden_constant: hidden_literal. (342) - . reduce 342 (src line 2196) + . reduce 342 (src line 2257) state 459 @@ -7741,7 +7741,7 @@ state 459 state 460 hidden_literal: LLITERAL. (339) - . reduce 339 (src line 2165) + . reduce 339 (src line 2226) state 461 @@ -7754,7 +7754,7 @@ state 461 state 462 hidden_literal: sym. (341) - . reduce 341 (src line 2188) + . reduce 341 (src line 2249) state 463 @@ -7776,13 +7776,13 @@ state 463 state 464 hidden_import: LTYPE hidden_pkgtype hidden_type ';'. (308) - . reduce 308 (src line 1962) + . reduce 308 (src line 2023) state 465 hidden_import: LFUNC hidden_fndcl fnbody ';'. (309) - . reduce 309 (src line 1966) + . reduce 309 (src line 2027) state 466 @@ -7797,7 +7797,7 @@ state 467 hidden_funarg_list: hidden_funarg_list.',' hidden_funarg ',' shift 469 - . reduce 297 (src line 1922) + . reduce 297 (src line 1983) state 468 @@ -7828,7 +7828,7 @@ state 470 oliteral: . (302) LLITERAL shift 428 - . reduce 302 (src line 1936) + . reduce 302 (src line 1997) oliteral goto 565 @@ -7856,13 +7856,13 @@ state 471 state 472 common_dcl: LVAR '(' vardcl_list osemi ')'. (29) - . reduce 29 (src line 311) + . reduce 29 (src line 372) state 473 vardcl_list: vardcl_list ';' vardcl. (221) - . reduce 221 (src line 1526) + . reduce 221 (src line 1587) state 474 @@ -7870,19 +7870,19 @@ state 474 expr_list: expr_list.',' expr ',' shift 155 - . reduce 40 (src line 366) + . reduce 40 (src line 427) state 475 ntype: '(' ntype ')'. (171) - . reduce 171 (src line 1197) + . reduce 171 (src line 1258) state 476 common_dcl: lconst '(' constdcl osemi ')'. (32) - . reduce 32 (src line 325) + . reduce 32 (src line 386) state 477 @@ -7891,20 +7891,20 @@ state 477 osemi: . (286) ';' shift 568 - . reduce 286 (src line 1894) + . reduce 286 (src line 1955) osemi goto 567 state 478 constdcl_list: constdcl1. (222) - . reduce 222 (src line 1531) + . reduce 222 (src line 1592) state 479 constdcl1: constdcl. (44) - . reduce 44 (src line 385) + . reduce 44 (src line 446) state 480 @@ -7928,7 +7928,7 @@ state 480 '?' shift 12 '@' shift 13 ',' shift 225 - . reduce 46 (src line 391) + . reduce 46 (src line 452) sym goto 123 ntype goto 569 @@ -7947,25 +7947,25 @@ state 481 expr_list: expr_list.',' expr ',' shift 155 - . reduce 42 (src line 375) + . reduce 42 (src line 436) state 482 common_dcl: LTYPE '(' typedcl_list osemi ')'. (36) - . reduce 36 (src line 346) + . reduce 36 (src line 407) state 483 typedcl_list: typedcl_list ';' typedcl. (225) - . reduce 225 (src line 1543) + . reduce 225 (src line 1604) state 484 fnbody: '{' stmt_list '}'. (211) - . reduce 211 (src line 1462) + . reduce 211 (src line 1523) state 485 @@ -7973,19 +7973,19 @@ state 485 fndcl: '(' oarg_type_list_ocomma ')' sym.'(' oarg_type_list_ocomma ')' fnres '(' shift 570 - . reduce 162 (src line 1159) + . reduce 162 (src line 1220) state 486 fntype: LFUNC '(' oarg_type_list_ocomma ')' fnres. (209) - . reduce 209 (src line 1449) + . reduce 209 (src line 1510) state 487 fnres: fnret_type. (213) - . reduce 213 (src line 1475) + . reduce 213 (src line 1536) state 488 @@ -8005,7 +8005,7 @@ state 488 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 249 (src line 1708) + . reduce 249 (src line 1769) sym goto 247 ntype goto 249 @@ -8027,37 +8027,37 @@ state 488 state 489 fnret_type: recvchantype. (184) - . reduce 184 (src line 1228) + . reduce 184 (src line 1289) state 490 fnret_type: fntype. (185) - . reduce 185 (src line 1230) + . reduce 185 (src line 1291) state 491 fnret_type: othertype. (186) - . reduce 186 (src line 1231) + . reduce 186 (src line 1292) state 492 fnret_type: ptrtype. (187) - . reduce 187 (src line 1232) + . reduce 187 (src line 1293) state 493 fnret_type: dotname. (188) - . reduce 188 (src line 1233) + . reduce 188 (src line 1294) state 494 arg_type_list: arg_type_list ',' arg_type. (248) - . reduce 248 (src line 1703) + . reduce 248 (src line 1764) state 495 @@ -8076,7 +8076,7 @@ state 495 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 212 (src line 1470) + . reduce 212 (src line 1531) sym goto 123 dotname goto 493 @@ -8107,7 +8107,7 @@ state 496 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 212 (src line 1470) + . reduce 212 (src line 1531) sym goto 123 dotname goto 493 @@ -8155,9 +8155,9 @@ state 497 '*' shift 58 '&' shift 59 '(' shift 67 - ';' reduce 251 (src line 1720) + ';' reduce 251 (src line 1781) '{' shift 308 - '}' reduce 251 (src line 1720) + '}' reduce 251 (src line 1781) '!' shift 62 '~' shift 63 '[' shift 77 @@ -8289,33 +8289,33 @@ state 501 switch_stmt: LSWITCH $$88 if_header $$89 LBODY.caseblock_list '}' caseblock_list: . (63) - . reduce 63 (src line 591) + . reduce 63 (src line 652) caseblock_list goto 577 state 502 if_header: osimple_stmt ';' osimple_stmt. (77) - . reduce 77 (src line 678) + . reduce 77 (src line 739) state 503 caseblock_list: caseblock_list caseblock. (64) - . reduce 64 (src line 595) + . reduce 64 (src line 656) state 504 select_stmt: LSELECT $$91 LBODY caseblock_list '}'. (92) - . reduce 92 (src line 783) + . reduce 92 (src line 844) state 505 caseblock: case.$$61 stmt_list $$61: . (61) - . reduce 61 (src line 560) + . reduce 61 (src line 621) $$61 goto 578 @@ -8377,14 +8377,14 @@ state 508 if_stmt: LIF $$78 if_header $$79 loop_body.$$80 elseif_list else $$80: . (80) - . reduce 80 (src line 700) + . reduce 80 (src line 761) $$80 goto 581 state 509 pseudocall: pexpr '(' expr_or_type_list ocomma ')'. (124) - . reduce 124 (src line 930) + . reduce 124 (src line 991) state 510 @@ -8397,19 +8397,19 @@ state 510 state 511 expr_or_type_list: expr_or_type_list ',' expr_or_type. (279) - . reduce 279 (src line 1856) + . reduce 279 (src line 1917) state 512 pexpr_no_paren: pexpr '.' '(' expr_or_type ')'. (129) - . reduce 129 (src line 959) + . reduce 129 (src line 1020) state 513 pexpr_no_paren: pexpr '.' '(' LTYPE ')'. (130) - . reduce 130 (src line 963) + . reduce 130 (src line 1024) state 514 @@ -8424,7 +8424,7 @@ state 514 state 515 pexpr_no_paren: pexpr_no_paren '{' start_complit braced_keyval_list '}'. (137) - . reduce 137 (src line 999) + . reduce 137 (src line 1060) state 516 @@ -8452,7 +8452,7 @@ state 516 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 289 (src line 1898) + . reduce 289 (src line 1959) sym goto 123 expr goto 402 @@ -8476,7 +8476,7 @@ state 516 state 517 braced_keyval_list: keyval_list ocomma. (285) - . reduce 285 (src line 1886) + . reduce 285 (src line 1947) state 518 @@ -8546,7 +8546,7 @@ state 519 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 284 (src line 1882) + . reduce 284 (src line 1943) sym goto 123 expr goto 402 @@ -8593,7 +8593,7 @@ state 520 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 284 (src line 1882) + . reduce 284 (src line 1943) sym goto 123 expr goto 402 @@ -8627,19 +8627,19 @@ state 521 state 522 pexpr_no_paren: convtype '(' expr ocomma ')'. (135) - . reduce 135 (src line 986) + . reduce 135 (src line 1047) state 523 pexpr_no_paren: comptype lbrace start_complit braced_keyval_list '}'. (136) - . reduce 136 (src line 992) + . reduce 136 (src line 1053) state 524 stmt_list: stmt_list ';' stmt. (271) - . reduce 271 (src line 1813) + . reduce 271 (src line 1874) state 525 @@ -8654,31 +8654,31 @@ state 525 state 526 othertype: LMAP '[' ntype ']' ntype. (195) - . reduce 195 (src line 1269) + . reduce 195 (src line 1330) state 527 structtype: LSTRUCT lbrace structdcl_list osemi '}'. (200) - . reduce 200 (src line 1289) + . reduce 200 (src line 1350) state 528 structdcl_list: structdcl_list ';' structdcl. (227) - . reduce 227 (src line 1550) + . reduce 227 (src line 1611) state 529 structdcl: new_name_list ntype oliteral. (230) - . reduce 230 (src line 1565) + . reduce 230 (src line 1626) state 530 new_name_list: new_name_list ',' new_name. (273) - . reduce 273 (src line 1826) + . reduce 273 (src line 1887) state 531 @@ -8686,7 +8686,7 @@ state 531 oliteral: . (302) LLITERAL shift 428 - . reduce 302 (src line 1936) + . reduce 302 (src line 1997) oliteral goto 594 @@ -8700,7 +8700,7 @@ state 532 state 533 structdcl: '*' embed oliteral. (233) - . reduce 233 (src line 1601) + . reduce 233 (src line 1662) state 534 @@ -8713,19 +8713,19 @@ state 534 state 535 packname: LNAME '.' sym. (237) - . reduce 237 (src line 1633) + . reduce 237 (src line 1694) state 536 interfacetype: LINTERFACE lbrace interfacedcl_list osemi '}'. (202) - . reduce 202 (src line 1302) + . reduce 202 (src line 1363) state 537 interfacedcl_list: interfacedcl_list ';' interfacedcl. (229) - . reduce 229 (src line 1560) + . reduce 229 (src line 1621) state 538 @@ -8738,13 +8738,13 @@ state 538 state 539 interfacedcl: '(' packname ')'. (241) - . reduce 241 (src line 1663) + . reduce 241 (src line 1724) state 540 hidden_type_misc: '[' ']' hidden_type. (319) - . reduce 319 (src line 2029) + . reduce 319 (src line 2090) state 541 @@ -8787,13 +8787,13 @@ state 544 hidden_structdcl_list: hidden_structdcl_list.';' hidden_structdcl ';' shift 601 - . reduce 299 (src line 1928) + . reduce 299 (src line 1989) state 545 hidden_structdcl_list: hidden_structdcl. (348) - . reduce 348 (src line 2223) + . reduce 348 (src line 2284) state 546 @@ -8829,13 +8829,13 @@ state 548 hidden_interfacedcl_list: hidden_interfacedcl_list.';' hidden_interfacedcl ';' shift 604 - . reduce 301 (src line 1934) + . reduce 301 (src line 1995) state 549 hidden_interfacedcl_list: hidden_interfacedcl. (350) - . reduce 350 (src line 2233) + . reduce 350 (src line 2294) state 550 @@ -8848,23 +8848,23 @@ state 550 state 551 hidden_interfacedcl: hidden_type. (334) - . reduce 334 (src line 2140) + . reduce 334 (src line 2201) state 552 sym: LNAME. (157) hidden_type_misc: LNAME. (318) - '(' reduce 157 (src line 1114) - . reduce 318 (src line 2018) + '(' reduce 157 (src line 1175) + . reduce 318 (src line 2079) state 553 sym: hidden_importsym. (158) hidden_type_misc: hidden_importsym. (317) - '(' reduce 158 (src line 1123) - . reduce 317 (src line 2013) + '(' reduce 158 (src line 1184) + . reduce 317 (src line 2074) state 554 @@ -8877,13 +8877,13 @@ state 554 state 555 hidden_type_misc: LCHAN LCOMM hidden_type. (327) - . reduce 327 (src line 2065) + . reduce 327 (src line 2126) state 556 hidden_type_recv_chan: LCOMM LCHAN hidden_type. (328) - . reduce 328 (src line 2072) + . reduce 328 (src line 2133) state 557 @@ -8896,7 +8896,7 @@ state 557 state 558 hidden_import: LCONST hidden_pkg_importsym '=' hidden_constant ';'. (306) - . reduce 306 (src line 1954) + . reduce 306 (src line 2015) state 559 @@ -8909,7 +8909,7 @@ state 559 state 560 hidden_literal: '-' LLITERAL. (340) - . reduce 340 (src line 2170) + . reduce 340 (src line 2231) state 561 @@ -8934,7 +8934,7 @@ state 562 '(' shift 612 '[' shift 342 '@' shift 13 - . reduce 335 (src line 2145) + . reduce 335 (src line 2206) hidden_importsym goto 340 hidden_funres goto 611 @@ -8954,13 +8954,13 @@ state 563 state 564 hidden_funarg_list: hidden_funarg_list ',' hidden_funarg. (347) - . reduce 347 (src line 2218) + . reduce 347 (src line 2279) state 565 hidden_funarg: sym hidden_type oliteral. (330) - . reduce 330 (src line 2086) + . reduce 330 (src line 2147) state 566 @@ -8968,7 +8968,7 @@ state 566 oliteral: . (302) LLITERAL shift 428 - . reduce 302 (src line 1936) + . reduce 302 (src line 1997) oliteral goto 615 @@ -8986,7 +8986,7 @@ state 568 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 287 (src line 1895) + . reduce 287 (src line 1956) sym goto 105 dcl_name goto 104 @@ -9000,7 +9000,7 @@ state 569 constdcl1: dcl_name_list ntype. (45) '=' shift 367 - . reduce 45 (src line 387) + . reduce 45 (src line 448) state 570 @@ -9020,7 +9020,7 @@ state 570 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 249 (src line 1708) + . reduce 249 (src line 1769) sym goto 247 ntype goto 249 @@ -9049,7 +9049,7 @@ state 571 state 572 fndcl: sym '(' oarg_type_list_ocomma ')' fnres. (205) - . reduce 205 (src line 1337) + . reduce 205 (src line 1398) state 573 @@ -9084,7 +9084,7 @@ state 574 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 294 (src line 1912) + . reduce 294 (src line 1973) sym goto 123 expr goto 48 @@ -9149,7 +9149,7 @@ state 575 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 67 (src line 611) + . reduce 67 (src line 672) state 576 @@ -9195,7 +9195,7 @@ state 576 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 68 (src line 618) + . reduce 68 (src line 679) state 577 @@ -9217,11 +9217,11 @@ state 578 error shift 307 LLITERAL shift 68 LBREAK shift 41 - LCASE reduce 251 (src line 1720) + LCASE reduce 251 (src line 1781) LCHAN shift 78 LCONST shift 47 LCONTINUE shift 42 - LDEFAULT reduce 251 (src line 1720) + LDEFAULT reduce 251 (src line 1781) LDEFER shift 44 LFALL shift 40 LFOR shift 50 @@ -9245,9 +9245,9 @@ state 578 '*' shift 58 '&' shift 59 '(' shift 67 - ';' reduce 251 (src line 1720) + ';' reduce 251 (src line 1781) '{' shift 308 - '}' reduce 251 (src line 1720) + '}' reduce 251 (src line 1781) '!' shift 62 '~' shift 63 '[' shift 77 @@ -9302,27 +9302,27 @@ state 579 state 580 case: LDEFAULT ':'. (58) - . reduce 58 (src line 525) + . reduce 58 (src line 586) state 581 if_stmt: LIF $$78 if_header $$79 loop_body $$80.elseif_list else elseif_list: . (84) - . reduce 84 (src line 735) + . reduce 84 (src line 796) elseif_list goto 628 state 582 pseudocall: pexpr '(' expr_or_type_list LDDD ocomma ')'. (125) - . reduce 125 (src line 935) + . reduce 125 (src line 996) state 583 pexpr_no_paren: pexpr '[' oexpr ':' oexpr ']'. (132) - . reduce 132 (src line 971) + . reduce 132 (src line 1032) state 584 @@ -9348,7 +9348,7 @@ state 584 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 290 (src line 1900) + . reduce 290 (src line 1961) sym goto 123 expr goto 188 @@ -9371,19 +9371,19 @@ state 584 state 585 keyval_list: keyval_list ',' keyval. (282) - . reduce 282 (src line 1873) + . reduce 282 (src line 1934) state 586 keyval_list: keyval_list ',' bare_complitexpr. (283) - . reduce 283 (src line 1877) + . reduce 283 (src line 1938) state 587 keyval: expr ':' complitexpr. (141) - . reduce 141 (src line 1021) + . reduce 141 (src line 1082) state 588 @@ -9429,14 +9429,14 @@ state 588 '/' shift 146 '%' shift 147 '&' shift 148 - . reduce 144 (src line 1047) + . reduce 144 (src line 1108) state 589 complitexpr: '{'.start_complit braced_keyval_list '}' start_complit: . (140) - . reduce 140 (src line 1014) + . reduce 140 (src line 1075) start_complit goto 630 @@ -9458,22 +9458,22 @@ state 592 ntype: '(' ntype ')'. (171) non_recvchantype: '(' ntype ')'. (180) - LBODY reduce 180 (src line 1216) - '(' reduce 180 (src line 1216) - '{' reduce 180 (src line 1216) - . reduce 171 (src line 1197) + LBODY reduce 180 (src line 1277) + '(' reduce 180 (src line 1277) + '{' reduce 180 (src line 1277) + . reduce 171 (src line 1258) state 593 compound_stmt: '{' $$59 stmt_list '}'. (60) - . reduce 60 (src line 550) + . reduce 60 (src line 611) state 594 structdcl: '(' embed ')' oliteral. (232) - . reduce 232 (src line 1595) + . reduce 232 (src line 1656) state 595 @@ -9481,7 +9481,7 @@ state 595 oliteral: . (302) LLITERAL shift 428 - . reduce 302 (src line 1936) + . reduce 302 (src line 1997) oliteral goto 633 @@ -9490,7 +9490,7 @@ state 596 oliteral: . (302) LLITERAL shift 428 - . reduce 302 (src line 1936) + . reduce 302 (src line 1997) oliteral goto 634 @@ -9510,7 +9510,7 @@ state 597 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 212 (src line 1470) + . reduce 212 (src line 1531) sym goto 123 dotname goto 493 @@ -9528,7 +9528,7 @@ state 597 state 598 hidden_type_misc: '[' LLITERAL ']' hidden_type. (320) - . reduce 320 (src line 2033) + . reduce 320 (src line 2094) state 599 @@ -9555,7 +9555,7 @@ state 599 state 600 hidden_type_misc: LSTRUCT '{' ohidden_structdcl_list '}'. (322) - . reduce 322 (src line 2041) + . reduce 322 (src line 2102) state 601 @@ -9575,14 +9575,14 @@ state 602 oliteral: . (302) LLITERAL shift 428 - . reduce 302 (src line 1936) + . reduce 302 (src line 1997) oliteral goto 638 state 603 hidden_type_misc: LINTERFACE '{' ohidden_interfacedcl_list '}'. (323) - . reduce 323 (src line 2045) + . reduce 323 (src line 2106) state 604 @@ -9616,7 +9616,7 @@ state 605 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 296 (src line 1918) + . reduce 296 (src line 1979) sym goto 357 hidden_importsym goto 11 @@ -9627,7 +9627,7 @@ state 605 state 606 hidden_type_misc: LCHAN '(' hidden_type_recv_chan ')'. (326) - . reduce 326 (src line 2059) + . reduce 326 (src line 2120) state 607 @@ -9645,7 +9645,7 @@ state 607 '(' shift 612 '[' shift 342 '@' shift 13 - . reduce 335 (src line 2145) + . reduce 335 (src line 2206) hidden_importsym goto 340 hidden_funres goto 611 @@ -9672,19 +9672,19 @@ state 608 state 609 hidden_import: LCONST hidden_pkg_importsym hidden_type '=' hidden_constant ';'. (307) - . reduce 307 (src line 1958) + . reduce 307 (src line 2019) state 610 hidden_fndcl: hidden_pkg_importsym '(' ohidden_funarg_list ')' ohidden_funres. (207) - . reduce 207 (src line 1406) + . reduce 207 (src line 1467) state 611 ohidden_funres: hidden_funres. (336) - . reduce 336 (src line 2149) + . reduce 336 (src line 2210) state 612 @@ -9694,7 +9694,7 @@ state 612 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 296 (src line 1918) + . reduce 296 (src line 1979) sym goto 357 hidden_importsym goto 11 @@ -9705,7 +9705,7 @@ state 612 state 613 hidden_funres: hidden_type. (338) - . reduce 338 (src line 2156) + . reduce 338 (src line 2217) state 614 @@ -9715,7 +9715,7 @@ state 614 LNAME shift 10 '?' shift 12 '@' shift 13 - . reduce 296 (src line 1918) + . reduce 296 (src line 1979) sym goto 357 hidden_importsym goto 11 @@ -9726,19 +9726,19 @@ state 614 state 615 hidden_funarg: sym LDDD hidden_type oliteral. (331) - . reduce 331 (src line 2095) + . reduce 331 (src line 2156) state 616 common_dcl: lconst '(' constdcl ';' constdcl_list osemi ')'. (33) - . reduce 33 (src line 331) + . reduce 33 (src line 392) state 617 constdcl_list: constdcl_list ';' constdcl1. (223) - . reduce 223 (src line 1533) + . reduce 223 (src line 1594) state 618 @@ -9751,25 +9751,25 @@ state 618 state 619 fnres: '(' oarg_type_list_ocomma ')'. (214) - . reduce 214 (src line 1479) + . reduce 214 (src line 1540) state 620 loop_body: LBODY $$65 stmt_list '}'. (66) - . reduce 66 (src line 605) + . reduce 66 (src line 666) state 621 for_header: osimple_stmt ';' osimple_stmt ';' osimple_stmt. (70) - . reduce 70 (src line 631) + . reduce 70 (src line 692) state 622 switch_stmt: LSWITCH $$88 if_header $$89 LBODY caseblock_list '}'. (90) - . reduce 90 (src line 769) + . reduce 90 (src line 830) state 623 @@ -9777,13 +9777,13 @@ state 623 stmt_list: stmt_list.';' stmt ';' shift 416 - . reduce 62 (src line 572) + . reduce 62 (src line 633) state 624 case: LCASE expr_or_type_list ':'. (55) - . reduce 55 (src line 474) + . reduce 55 (src line 535) state 625 @@ -9918,7 +9918,7 @@ state 628 else: . (86) LELSE shift 650 - . reduce 86 (src line 744) + . reduce 86 (src line 805) elseif goto 649 else goto 648 @@ -9954,7 +9954,7 @@ state 630 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 284 (src line 1882) + . reduce 284 (src line 1943) sym goto 123 expr goto 402 @@ -9980,55 +9980,55 @@ state 630 state 631 bare_complitexpr: '{' start_complit braced_keyval_list '}'. (143) - . reduce 143 (src line 1041) + . reduce 143 (src line 1102) state 632 pexpr_no_paren: '(' expr_or_type ')' '{' start_complit braced_keyval_list '}'. (138) - . reduce 138 (src line 1005) + . reduce 138 (src line 1066) state 633 structdcl: '(' '*' embed ')' oliteral. (234) - . reduce 234 (src line 1607) + . reduce 234 (src line 1668) state 634 structdcl: '*' '(' embed ')' oliteral. (235) - . reduce 235 (src line 1614) + . reduce 235 (src line 1675) state 635 indcl: '(' oarg_type_list_ocomma ')' fnres. (242) - . reduce 242 (src line 1669) + . reduce 242 (src line 1730) state 636 hidden_type_misc: LMAP '[' hidden_type ']' hidden_type. (321) - . reduce 321 (src line 2037) + . reduce 321 (src line 2098) state 637 hidden_structdcl_list: hidden_structdcl_list ';' hidden_structdcl. (349) - . reduce 349 (src line 2228) + . reduce 349 (src line 2289) state 638 hidden_structdcl: sym hidden_type oliteral. (332) - . reduce 332 (src line 2111) + . reduce 332 (src line 2172) state 639 hidden_interfacedcl_list: hidden_interfacedcl_list ';' hidden_interfacedcl. (351) - . reduce 351 (src line 2238) + . reduce 351 (src line 2299) state 640 @@ -10041,7 +10041,7 @@ state 640 state 641 hidden_type_func: LFUNC '(' ohidden_funarg_list ')' ohidden_funres. (329) - . reduce 329 (src line 2080) + . reduce 329 (src line 2141) state 642 @@ -10081,7 +10081,7 @@ state 645 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 212 (src line 1470) + . reduce 212 (src line 1531) sym goto 123 dotname goto 493 @@ -10193,13 +10193,13 @@ state 647 state 648 if_stmt: LIF $$78 if_header $$79 loop_body $$80 elseif_list else. (81) - . reduce 81 (src line 704) + . reduce 81 (src line 765) state 649 elseif_list: elseif_list elseif. (85) - . reduce 85 (src line 739) + . reduce 85 (src line 800) state 650 @@ -10215,7 +10215,7 @@ state 650 state 651 pexpr_no_paren: pexpr '[' oexpr ':' oexpr ':' oexpr ']'. (133) - . reduce 133 (src line 975) + . reduce 133 (src line 1036) state 652 @@ -10240,7 +10240,7 @@ state 653 '(' shift 612 '[' shift 342 '@' shift 13 - . reduce 335 (src line 2145) + . reduce 335 (src line 2206) hidden_importsym goto 340 hidden_funres goto 611 @@ -10253,13 +10253,13 @@ state 653 state 654 hidden_constant: '(' hidden_literal '+' hidden_literal ')'. (343) - . reduce 343 (src line 2198) + . reduce 343 (src line 2259) state 655 hidden_funres: '(' ohidden_funarg_list ')'. (337) - . reduce 337 (src line 2151) + . reduce 337 (src line 2212) state 656 @@ -10277,7 +10277,7 @@ state 656 '(' shift 612 '[' shift 342 '@' shift 13 - . reduce 335 (src line 2145) + . reduce 335 (src line 2206) hidden_importsym goto 340 hidden_funres goto 611 @@ -10290,51 +10290,51 @@ state 656 state 657 fndcl: '(' oarg_type_list_ocomma ')' sym '(' oarg_type_list_ocomma ')' fnres. (206) - . reduce 206 (src line 1369) + . reduce 206 (src line 1430) state 658 case: LCASE expr_or_type_list '=' expr ':'. (56) - . reduce 56 (src line 498) + . reduce 56 (src line 559) state 659 case: LCASE expr_or_type_list LCOLAS expr ':'. (57) - . reduce 57 (src line 516) + . reduce 57 (src line 577) state 660 elseif: LELSE LIF.$$82 if_header loop_body $$82: . (82) - . reduce 82 (src line 721) + . reduce 82 (src line 782) $$82 goto 665 state 661 else: LELSE compound_stmt. (87) - . reduce 87 (src line 748) + . reduce 87 (src line 809) state 662 complitexpr: '{' start_complit braced_keyval_list '}'. (145) - . reduce 145 (src line 1049) + . reduce 145 (src line 1110) state 663 hidden_interfacedcl: sym '(' ohidden_funarg_list ')' ohidden_funres. (333) - . reduce 333 (src line 2135) + . reduce 333 (src line 2196) state 664 hidden_fndcl: '(' hidden_funarg_list ')' sym '(' ohidden_funarg_list ')' ohidden_funres. (208) - . reduce 208 (src line 1432) + . reduce 208 (src line 1493) state 665 @@ -10360,7 +10360,7 @@ state 665 '[' shift 77 '?' shift 12 '@' shift 13 - . reduce 294 (src line 1912) + . reduce 294 (src line 1973) sym goto 123 expr goto 48 @@ -10394,7 +10394,7 @@ state 666 state 667 elseif: LELSE LIF $$82 if_header loop_body. (83) - . reduce 83 (src line 726) + . reduce 83 (src line 787) 76 terminals, 142 nonterminals diff --git a/src/cmd/internal/gc/yaccerrors.go b/src/cmd/internal/gc/yaccerrors.go deleted file mode 100644 index 9dc54d9c8c..0000000000 --- a/src/cmd/internal/gc/yaccerrors.go +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright 2010 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 ignore - -// This program implements the core idea from -// -// Clinton L. Jeffery, Generating LR syntax error messages from examples, -// ACM TOPLAS 25(5) (September 2003). http://doi.acm.org/10.1145/937563.937566 -// -// It reads Bison's summary of a grammar followed by a file -// like go.errors, replacing lines beginning with % by the -// yystate and yychar that will be active when an error happens -// while parsing that line. -// -// Unlike the system described in the paper, the lines in go.errors -// give grammar symbol name lists, not actual program fragments. -// This is a little less programmer-friendly but doesn't require being -// able to run the text through lex.c. - -package main - -import ( - "bufio" - "fmt" - "io" - "log" - "os" - "strconv" - "strings" -) - -func xatoi(s string) int { - n, err := strconv.Atoi(s) - if err != nil { - log.Fatal(err) - } - return n -} - -func trimParen(s string) string { - s = strings.TrimPrefix(s, "(") - s = strings.TrimSuffix(s, ")") - return s -} - -type action struct { - token string - n int -} - -var shift = map[int][]action{} -var reduce = map[int][]action{} - -type rule struct { - lhs string - size int -} - -var rules = map[int]rule{} - -func readYaccOutput() { - r, err := os.Open("y.output") - if err != nil { - log.Fatal(err) - } - defer r.Close() - - var state int - - scanner := bufio.NewScanner(r) - for scanner.Scan() { - f := strings.Fields(scanner.Text()) - nf := len(f) - - if nf >= 4 && f[1] == "terminals," && f[3] == "nonterminals" { - // We're done. - break - } - - if nf >= 2 && f[0] == "state" { - state = xatoi(f[1]) - continue - } - if nf >= 3 && (f[1] == "shift" || f[1] == "goto") { - shift[state] = append(shift[state], action{f[0], xatoi(f[2])}) - continue - } - if nf >= 3 && f[1] == "reduce" { - reduce[state] = append(reduce[state], action{f[0], xatoi(f[2])}) - continue - } - if nf >= 3 && strings.HasSuffix(f[0], ":") && strings.HasPrefix(f[nf-1], "(") && strings.HasSuffix(f[nf-1], ")") { - n := xatoi(trimParen(f[nf-1])) - - size := nf - 2 - if size == 1 && f[1] == "." { - size = 0 - } - - rules[n] = rule{strings.TrimSuffix(f[0], ":"), size} - continue - } - } -} - -func runMachine(w io.Writer, s string) { - f := strings.Fields(s) - - // Run it through the LR machine and print the induced "yystate, yychar," - // at the point where the error happens. - - var stack []int - state := 0 - i := 1 - tok := "" - -Loop: - if tok == "" && i < len(f) { - tok = f[i] - i++ - } - - for _, a := range shift[state] { - if a.token == tok { - if false { - fmt.Println("SHIFT ", tok, " ", state, " -> ", a) - } - stack = append(stack, state) - state = a.n - tok = "" - goto Loop - } - } - - for _, a := range reduce[state] { - if a.token == tok || a.token == "." { - stack = append(stack, state) - rule, ok := rules[a.n] - if !ok { - log.Fatal("missing rule") - } - stack = stack[:len(stack)-rule.size] - state = stack[len(stack)-1] - stack = stack[:len(stack)-1] - if tok != "" { - i-- - } - tok = rule.lhs - if false { - fmt.Println("REDUCE ", stack, " ", state, " ", tok, " rule ", rule) - } - goto Loop - } - } - - // No shift or reduce applied - found the error. - fmt.Fprintf(w, "\t{%d, %s,\n", state, tok) -} - -func processGoErrors() { - r, err := os.Open("go.errors") - if err != nil { - log.Fatal(err) - } - defer r.Close() - - w, err := os.Create("yymsg.go") - if err != nil { - log.Fatal(err) - } - defer w.Close() - - fmt.Fprintf(w, "// DO NOT EDIT - generated with go generate\n\n") - - scanner := bufio.NewScanner(r) - for scanner.Scan() { - s := scanner.Text() - - // Treat % as first field on line as introducing a pattern (token sequence). - if strings.HasPrefix(strings.TrimSpace(s), "%") { - runMachine(w, s) - continue - } - - fmt.Fprintln(w, s) - } -} - -func main() { - readYaccOutput() - processGoErrors() -} diff --git a/src/cmd/internal/gc/yymsg.go b/src/cmd/internal/gc/yymsg.go deleted file mode 100644 index cb45cb8d1b..0000000000 --- a/src/cmd/internal/gc/yymsg.go +++ /dev/null @@ -1,83 +0,0 @@ -// DO NOT EDIT - generated with go generate - -// Copyright 2010 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. - -// Example-based syntax error messages. -// See yaccerrors.go. - -package gc - -var yymsg = []struct { - yystate int - yychar int - msg string -}{ - // Each line of the form % token list - // is converted by yaccerrors.go into the yystate and yychar caused - // by that token list. - - {332, ',', - "unexpected comma during import block"}, - - {89, ';', - "missing import path; require quoted string"}, - - {390, ';', - "missing { after if clause"}, - - {387, ';', - "missing { after switch clause"}, - - {279, ';', - "missing { after for clause"}, - - {498, LBODY, - "missing { after for clause"}, - - {17, '{', - "unexpected semicolon or newline before {"}, - - {111, ';', - "unexpected semicolon or newline in type declaration"}, - - {78, '}', - "unexpected } in channel type"}, - - {78, ')', - "unexpected ) in channel type"}, - - {78, ',', - "unexpected comma in channel type"}, - - {416, LELSE, - "unexpected semicolon or newline before else"}, - - {329, ',', - "name list not allowed in interface type"}, - - {279, LVAR, - "var declaration not allowed in for initializer"}, - - {25, '{', - "unexpected { at end of statement"}, - - {371, '{', - "unexpected { at end of statement"}, - - {122, ';', - "argument to go/defer must be function call"}, - - {398, ';', - "need trailing comma before newline in composite literal"}, - - {414, ';', - "need trailing comma before newline in composite literal"}, - - {124, LNAME, - "nested func not allowed"}, - - {650, ';', - "else must be followed by if or statement block"}, -} diff --git a/src/cmd/yacc/yacc.go b/src/cmd/yacc/yacc.go index 5c7b0b71b1..53c0fab174 100644 --- a/src/cmd/yacc/yacc.go +++ b/src/cmd/yacc/yacc.go @@ -128,6 +128,7 @@ const ( TYPEDEF TYPENAME UNION + ERROR ) const ENDFILE = 0 @@ -325,8 +326,24 @@ var resrv = []Resrv{ {"type", TYPEDEF}, {"union", UNION}, {"struct", UNION}, + {"error", ERROR}, } +type Error struct { + lineno int + tokens []string + msg string +} + +var errors []Error + +type Row struct { + actions []int + defaultAction int +} + +var stateTable []Row + var zznewstate = 0 const EOF = -1 @@ -402,6 +419,27 @@ outer: } start = chfind(1, tokname) + case ERROR: + lno := lineno + var tokens []string + for { + t := gettok() + if t == ':' { + break + } + if t != IDENTIFIER && t != IDENTCOLON { + errorf("bad syntax in %%error") + } + tokens = append(tokens, tokname) + if t == IDENTCOLON { + break + } + } + if gettok() != IDENTIFIER { + errorf("bad syntax in %%error") + } + errors = append(errors, Error{lno, tokens, tokname}) + case TYPEDEF: t = gettok() if t != TYPENAME { @@ -2155,6 +2193,10 @@ func output() { } fmt.Fprintf(ftable, "\nvar %sExca = [...]int{\n", prefix) + if len(errors) > 0 { + stateTable = make([]Row, nstate) + } + noset := mkset() // output the stuff for state i @@ -2368,6 +2410,15 @@ func wrstate(i int) { var j0, j1, u int var pp, qq int + if len(errors) > 0 { + actions := append([]int(nil), temp1...) + defaultAction := ERRCODE + if lastred != 0 { + defaultAction = -lastred + } + stateTable[i] = Row{actions, defaultAction} + } + if foutput == nil { return } @@ -2914,6 +2965,20 @@ func others() { } fmt.Fprintf(ftable, "%d,\n}\n", 0) + // Custom error messages. + fmt.Fprintf(ftable, "\n") + fmt.Fprintf(ftable, "var %sErrorMessages = [...]struct {\n", prefix) + fmt.Fprintf(ftable, "\tstate int\n") + fmt.Fprintf(ftable, "\ttoken int\n") + fmt.Fprintf(ftable, "\tmsg string\n") + fmt.Fprintf(ftable, "}{\n") + for _, error := range errors { + lineno = error.lineno + state, token := runMachine(error.tokens) + fmt.Fprintf(ftable, "\t{%v, %v, %s},\n", state, token, error.msg) + } + fmt.Fprintf(ftable, "}\n") + // copy parser text ch := getrune(finput) for ch != EOF { @@ -2932,6 +2997,59 @@ func others() { fmt.Fprintf(ftable, "%v", parts[1]) } +func runMachine(tokens []string) (state, token int) { + var stack []int + i := 0 + token = -1 + +Loop: + if token < 0 { + token = chfind(2, tokens[i]) + i++ + } + + row := stateTable[state] + + c := token + if token >= NTBASE { + c = token - NTBASE + ntokens + } + action := row.actions[c] + if action == 0 { + action = row.defaultAction + } + + switch { + case action == ACCEPTCODE: + errorf("tokens are accepted") + return + case action == ERRCODE: + if token >= NTBASE { + errorf("error at non-terminal token %s", symnam(token)) + } + return + case action > 0: + // Shift to state action. + stack = append(stack, state) + state = action + token = -1 + goto Loop + default: + // Reduce by production -action. + prod := prdptr[-action] + if rhsLen := len(prod) - 2; rhsLen > 0 { + n := len(stack) - rhsLen + state = stack[n] + stack = stack[:n] + } + if token >= 0 { + i-- + } + token = prod[0] + goto Loop + } +} + func arout(s string, v []int, n int) { s = prefix + s fmt.Fprintf(ftable, "var %v = [...]int{\n", s) @@ -3212,7 +3330,6 @@ type $$Parser interface { type $$ParserImpl struct { lookahead func() int - state func() int } func (p *$$ParserImpl) Lookahead() int { @@ -3222,7 +3339,6 @@ func (p *$$ParserImpl) Lookahead() int { func $$NewParser() $$Parser { p := &$$ParserImpl{ lookahead: func() int { return -1 }, - state: func() int { return -1 }, } return p } @@ -3253,6 +3369,13 @@ func $$ErrorMessage(state, lookAhead int) string { if !$$ErrorVerbose { return "syntax error" } + + for _, e := range $$ErrorMessages { + if e.state == state && e.token == lookAhead { + return "syntax error: " + e.msg + } + } + res := "syntax error: unexpected " + $$Tokname(lookAhead) // To match Bison, suggest at most four expected tokens. @@ -3355,7 +3478,6 @@ func ($$rcvr *$$ParserImpl) Parse($$lex $$Lexer) int { $$state := 0 $$char := -1 $$token := -1 // $$char translated into internal numbering - $$rcvr.state = func() int { return $$state } $$rcvr.lookahead = func() int { return $$char } defer func() { // Make sure we report no lookahead when not parsing. From 1467776b17c7dc232f5586944785f85f48862b49 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 20 Apr 2015 13:32:40 -0700 Subject: [PATCH 113/232] cmd/internal/obj: update callers to Linkline{fmt,hist} and remove Does the TODOs added by https://golang.org/cl/7623. Passes rsc.io/toolstash/buildall. Change-Id: I23913a8f03834640e9795d48318febb3f88c10f9 Reviewed-on: https://go-review.googlesource.com/9160 Reviewed-by: Russ Cox --- src/cmd/asm/internal/lex/input.go | 3 +- src/cmd/asm/internal/lex/tokenizer.go | 6 ++-- src/cmd/internal/asm/lexbody.go | 4 +-- src/cmd/internal/asm/macbody.go | 5 ++-- src/cmd/internal/gc/lex.go | 8 +++--- src/cmd/internal/gc/subr.go | 40 +++++++++++++++------------ src/cmd/internal/gc/util.go | 3 +- src/cmd/internal/obj/line_test.go | 14 +++++----- src/cmd/internal/obj/obj.go | 33 ---------------------- src/cmd/internal/obj/util.go | 4 +-- 10 files changed, 44 insertions(+), 76 deletions(-) diff --git a/src/cmd/asm/internal/lex/input.go b/src/cmd/asm/internal/lex/input.go index 730042b149..7e495b8edf 100644 --- a/src/cmd/asm/internal/lex/input.go +++ b/src/cmd/asm/internal/lex/input.go @@ -13,7 +13,6 @@ import ( "text/scanner" "cmd/asm/internal/flags" - "cmd/internal/obj" ) // Input is the main input: a stack of readers and some macro definitions. @@ -436,7 +435,7 @@ func (in *Input) line() { if tok != '\n' { in.Error("unexpected token at end of #line: ", tok) } - obj.Linklinehist(linkCtxt, histLine, file, line) + linkCtxt.LineHist.Update(histLine, file, line) in.Stack.SetPos(line, file) } diff --git a/src/cmd/asm/internal/lex/tokenizer.go b/src/cmd/asm/internal/lex/tokenizer.go index 28a4b85253..6a4d95491f 100644 --- a/src/cmd/asm/internal/lex/tokenizer.go +++ b/src/cmd/asm/internal/lex/tokenizer.go @@ -10,8 +10,6 @@ import ( "strings" "text/scanner" "unicode" - - "cmd/internal/obj" ) // A Tokenizer is a simple wrapping of text/scanner.Scanner, configured @@ -40,7 +38,7 @@ func NewTokenizer(name string, r io.Reader, file *os.File) *Tokenizer { s.Position.Filename = name s.IsIdentRune = isIdentRune if file != nil { - obj.Linklinehist(linkCtxt, histLine, name, 0) + linkCtxt.LineHist.Push(histLine, name) } return &Tokenizer{ s: &s, @@ -149,6 +147,6 @@ func (t *Tokenizer) Close() { if t.file != nil { t.file.Close() // It's an open file, so pop the line history. - obj.Linklinehist(linkCtxt, histLine, " ", 0) + linkCtxt.LineHist.Pop(histLine) } } diff --git a/src/cmd/internal/asm/lexbody.go b/src/cmd/internal/asm/lexbody.go index b5e5d1eee2..a1519c8566 100644 --- a/src/cmd/internal/asm/lexbody.go +++ b/src/cmd/internal/asm/lexbody.go @@ -149,7 +149,7 @@ func newfile(s string, f *os.File) { } fi.P = nil - obj.Linklinehist(Ctxt, int(Lineno), s, 0) + Ctxt.LineHist.Push(int(Lineno), s) } var thetext *obj.LSym @@ -630,7 +630,7 @@ loop: n, _ = i.F.Read(i.B[:]) if n == 0 { i.F.Close() - obj.Linklinehist(Ctxt, int(Lineno), " ", 0) + Ctxt.LineHist.Pop(int(Lineno)) goto pop } fi.P = i.B[1:n] diff --git a/src/cmd/internal/asm/macbody.go b/src/cmd/internal/asm/macbody.go index c488ea1e56..4565d3a37f 100644 --- a/src/cmd/internal/asm/macbody.go +++ b/src/cmd/internal/asm/macbody.go @@ -32,7 +32,6 @@ package asm import ( "bytes" - "cmd/internal/obj" "fmt" "os" "strings" @@ -683,7 +682,7 @@ func maclin() { } nn: - obj.Linklinehist(Ctxt, int(Lineno), symb, int(n)) + Ctxt.LineHist.Update(int(Lineno), symb, int(n)) return bad: @@ -796,7 +795,7 @@ func macprag() { /* * put pragma-line in as a funny history */ - obj.Linklinehist(Ctxt, int(Lineno), symb, -1) + Ctxt.AddImport(symb) return } if s != nil && s.Name == "pack" { diff --git a/src/cmd/internal/gc/lex.go b/src/cmd/internal/gc/lex.go index 9e2baec220..92c079e154 100644 --- a/src/cmd/internal/gc/lex.go +++ b/src/cmd/internal/gc/lex.go @@ -313,7 +313,7 @@ func Main() { lexlineno = 1 for _, infile = range flag.Args() { - linehist(infile, 0, 0) + linehistpush(infile) curio.infile = infile var err error @@ -344,7 +344,7 @@ func Main() { errorexit() } - linehist(" ", 0, 0) + linehistpop() if curio.bin != nil { obj.Bterm(curio.bin) } @@ -763,7 +763,7 @@ func importfile(f *Val, line int) { // assume files move (get installed) // so don't record the full path. - linehist(file[len(file)-len(path_)-2:], -1, 1) // acts as #pragma lib + linehistpragma(file[len(file)-len(path_)-2:]) // acts as #pragma lib /* * position the input right @@ -1654,7 +1654,7 @@ func getlinepragma() int { } name = text[:linep-1] - linehist(name, int32(n), 0) + linehistupdate(name, n) return c out: diff --git a/src/cmd/internal/gc/subr.go b/src/cmd/internal/gc/subr.go index 74415be49a..33741c3baf 100644 --- a/src/cmd/internal/gc/subr.go +++ b/src/cmd/internal/gc/subr.go @@ -199,26 +199,32 @@ func Fatal(fmt_ string, args ...interface{}) { errorexit() } -func linehist(file string, off int32, relative int) { +func linehistpragma(file string) { if Debug['i'] != 0 { - if file != "" { - if off < 0 { - fmt.Printf("pragma %s", file) - } else if off > 0 { - fmt.Printf("line %s", file) - } else { - fmt.Printf("import %s", file) - } - } else { - fmt.Printf("end of import") - } - fmt.Printf(" at line %v\n", Ctxt.Line(int(lexlineno))) + fmt.Printf("pragma %s at line %v\n", file, Ctxt.Line(int(lexlineno))) } + Ctxt.AddImport(file) +} - if off < 0 && file[0] != '/' && relative == 0 { - file = fmt.Sprintf("%s/%s", Ctxt.Pathname, file) +func linehistpush(file string) { + if Debug['i'] != 0 { + fmt.Printf("import %s at line %v\n", file, Ctxt.Line(int(lexlineno))) } - obj.Linklinehist(Ctxt, int(lexlineno), file, int(off)) + Ctxt.LineHist.Push(int(lexlineno), file) +} + +func linehistpop() { + if Debug['i'] != 0 { + fmt.Printf("end of import at line %v\n", Ctxt.Line(int(lexlineno))) + } + Ctxt.LineHist.Pop(int(lexlineno)) +} + +func linehistupdate(file string, off int) { + if Debug['i'] != 0 { + fmt.Printf("line %s at line %v\n", file, Ctxt.Line(int(lexlineno))) + } + Ctxt.LineHist.Update(int(lexlineno), file, off) } func setlineno(n *Node) int32 { @@ -2345,7 +2351,7 @@ func genwrapper(rcvr *Type, method *Type, newnam *Sym, iface int) { lineno = lexlineno if genwrapper_linehistdone == 0 { // All the wrappers can share the same linehist entry. - linehist(" ", 0, 0) + linehistpush(" ") genwrapper_linehistdone = 1 } diff --git a/src/cmd/internal/gc/util.go b/src/cmd/internal/gc/util.go index 5dc6561b48..c59af0665b 100644 --- a/src/cmd/internal/gc/util.go +++ b/src/cmd/internal/gc/util.go @@ -1,7 +1,6 @@ package gc import ( - "cmd/internal/obj" "os" "runtime" "runtime/pprof" @@ -10,7 +9,7 @@ import ( ) func (n *Node) Line() string { - return obj.Linklinefmt(Ctxt, int(n.Lineno), false, false) + return Ctxt.LineHist.LineString(int(n.Lineno)) } func atoi(s string) int { diff --git a/src/cmd/internal/obj/line_test.go b/src/cmd/internal/obj/line_test.go index dde5d64e17..5486f0d648 100644 --- a/src/cmd/internal/obj/line_test.go +++ b/src/cmd/internal/obj/line_test.go @@ -13,13 +13,13 @@ func TestLineHist(t *testing.T) { ctxt := new(Link) ctxt.Hash = make(map[SymVer]*LSym) - Linklinehist(ctxt, 1, "a.c", 0) - Linklinehist(ctxt, 3, "a.h", 0) - Linklinehist(ctxt, 5, " ", 0) - Linklinehist(ctxt, 7, "linedir", 2) - Linklinehist(ctxt, 9, " ", 0) - Linklinehist(ctxt, 11, "b.c", 0) - Linklinehist(ctxt, 13, " ", 0) + ctxt.LineHist.Push(1, "a.c") + ctxt.LineHist.Push(3, "a.h") + ctxt.LineHist.Pop(5) + ctxt.LineHist.Update(7, "linedir", 2) + ctxt.LineHist.Pop(9) + ctxt.LineHist.Push(11, "b.c") + ctxt.LineHist.Pop(13) var expect = []string{ 0: "??:0", diff --git a/src/cmd/internal/obj/obj.go b/src/cmd/internal/obj/obj.go index 39db2396e7..af3290d3a5 100644 --- a/src/cmd/internal/obj/obj.go +++ b/src/cmd/internal/obj/obj.go @@ -241,12 +241,6 @@ func (h *LineHist) LineString(lineno int) string { return text } -// TODO(rsc): Replace call sites with use of ctxt.LineHist. -// Note that all call sites use showAll=false, showFullPath=false. -func Linklinefmt(ctxt *Link, lineno int, showAll, showFullPath bool) string { - return ctxt.LineHist.LineString(lineno) -} - // FileLine returns the file name and line number // at the top of the stack for the given lineno. func (h *LineHist) FileLine(lineno int) (file string, line int) { @@ -287,30 +281,3 @@ func linkgetline(ctxt *Link, lineno int32, f **LSym, l *int32) { func Linkprfile(ctxt *Link, line int) { fmt.Printf("%s ", ctxt.LineHist.LineString(line)) } - -// Linklinehist pushes, amends, or pops an entry on the line history stack. -// If f != " " and n == 0, the call pushes the start of a new file named f at lineno. -// If f != " " and n > 0, the call amends the top of the stack to record that lineno -// now corresponds to f at line n. -// If f == " ", the call pops the topmost entry from the stack, picking up -// the parent file at the line following the one where the corresponding push occurred. -// -// If n < 0, linklinehist records f as a package required by the current compilation -// (nothing to do with line numbers). -// -// TODO(rsc): Replace uses with direct calls to ctxt.Hist methods. -func Linklinehist(ctxt *Link, lineno int, f string, n int) { - switch { - case n < 0: - ctxt.AddImport(f) - - case f == " ": - ctxt.LineHist.Pop(lineno) - - case n == 0: - ctxt.LineHist.Push(lineno, f) - - default: - ctxt.LineHist.Update(lineno, f, n) - } -} diff --git a/src/cmd/internal/obj/util.go b/src/cmd/internal/obj/util.go index ac49543fdf..317ee4f14d 100644 --- a/src/cmd/internal/obj/util.go +++ b/src/cmd/internal/obj/util.go @@ -241,7 +241,7 @@ func Atoi(s string) int { } func (p *Prog) Line() string { - return Linklinefmt(p.Ctxt, int(p.Lineno), false, false) + return p.Ctxt.LineHist.LineString(int(p.Lineno)) } var armCondCode = []string{ @@ -340,7 +340,7 @@ func (ctxt *Link) NewProg() *Prog { } func (ctxt *Link) Line(n int) string { - return Linklinefmt(ctxt, n, false, false) + return ctxt.LineHist.LineString(n) } func Getcallerpc(interface{}) uintptr { From 40fad6c286ca57317e94aeca50b75fa3444ca1fa Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 14 May 2015 16:47:53 -0700 Subject: [PATCH 114/232] go/parser: better error message for missing ',' in lists Fixes #8940. Change-Id: Ie9e5149983518ba8d56ddd82ac8f4cde6b644167 Reviewed-on: https://go-review.googlesource.com/10089 Reviewed-by: Alan Donovan --- src/go/parser/parser.go | 21 ++++++++++++--------- src/go/parser/short_test.go | 5 +++-- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go index 0095d7facf..fb6ca76a77 100644 --- a/src/go/parser/parser.go +++ b/src/go/parser/parser.go @@ -412,14 +412,17 @@ func (p *parser) expectSemi() { } } -func (p *parser) atComma(context string) bool { +func (p *parser) atComma(context string, follow token.Token) bool { if p.tok == token.COMMA { return true } - if p.tok == token.SEMICOLON && p.lit == "\n" { - p.error(p.pos, "missing ',' before newline in "+context) - return true // "insert" the comma and continue - + if p.tok != follow { + msg := "missing ','" + if p.tok == token.SEMICOLON && p.lit == "\n" { + msg += " before newline" + } + p.error(p.pos, msg+" in "+context) + return true // "insert" comma and continue } return false } @@ -825,7 +828,7 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [ // parameter or result variable is the function body. p.declare(field, nil, scope, ast.Var, idents...) p.resolve(typ) - if !p.atComma("parameter list") { + if !p.atComma("parameter list", token.RPAREN) { return } p.next() @@ -838,7 +841,7 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [ // parameter or result variable is the function body. p.declare(field, nil, scope, ast.Var, idents...) p.resolve(typ) - if !p.atComma("parameter list") { + if !p.atComma("parameter list", token.RPAREN) { break } p.next() @@ -1248,7 +1251,7 @@ func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr { ellipsis = p.pos p.next() } - if !p.atComma("argument list") { + if !p.atComma("argument list", token.RPAREN) { break } p.next() @@ -1323,7 +1326,7 @@ func (p *parser) parseElementList() (list []ast.Expr) { for p.tok != token.RBRACE && p.tok != token.EOF { list = append(list, p.parseElement()) - if !p.atComma("composite literal") { + if !p.atComma("composite literal", token.RBRACE) { break } p.next() diff --git a/src/go/parser/short_test.go b/src/go/parser/short_test.go index 970ef2d3fa..ef2ffadbd9 100644 --- a/src/go/parser/short_test.go +++ b/src/go/parser/short_test.go @@ -99,8 +99,9 @@ var invalids = []string{ `package p; func f() { for i /* ERROR "boolean or range expression" */ , x := []string {} }`, `package p; func f() { go f /* ERROR HERE "function must be invoked" */ }`, `package p; func f() { defer func() {} /* ERROR HERE "function must be invoked" */ }`, - `package p; func f() { go func() { func() { f(x func /* ERROR "expected '\)'" */ (){}) } } }`, - `package p; func f() (a b string /* ERROR "expected '\)'" */ , ok bool)`, // issue 8656 + `package p; func f() { go func() { func() { f(x func /* ERROR "missing ','" */ (){}) } } }`, + `package p; func f(x func(), u v func /* ERROR "missing ','" */ ()){}`, + `package p; func f() (a b string /* ERROR "missing ','" */ , ok bool)`, // issue 8656 `package p; var x /* ERROR "missing variable type or initialization" */ , y, z;`, // issue 9639 `package p; const x /* ERROR "missing constant value" */ ;`, // issue 9639 `package p; const x /* ERROR "missing constant value" */ int;`, // issue 9639 From ef7e1085658de69b6a2e365e71a955105b3a4feb Mon Sep 17 00:00:00 2001 From: Alex A Skinner Date: Tue, 12 May 2015 23:56:56 -0400 Subject: [PATCH 115/232] net: redo resolv.conf recheck implementation The previous implementation spawned an extra goroutine to handle rechecking resolv.conf for changes. This change eliminates the extra goroutine, and has rechecking done as part of a lookup. A side effect of this change is that the first lookup after a resolv.conf change will now succeed, whereas previously it would have failed. It also fixes rechecking logic to ignore resolv.conf parsing errors as it should. Fixes #8652 Fixes #10576 Fixes #10649 Fixes #10650 Fixes #10845 Change-Id: I502b587c445fa8eca5207ca4f2c8ec8c339fec7f Reviewed-on: https://go-review.googlesource.com/9991 Run-TryBot: Matthew Dempsky TryBot-Result: Gobot Gobot Reviewed-by: Josh Bleecher Snyder Reviewed-by: Mikio Hara Reviewed-by: Brad Fitzpatrick --- src/net/dnsclient_unix.go | 119 ++++++++++++++++++--------------- src/net/dnsclient_unix_test.go | 38 +++-------- 2 files changed, 74 insertions(+), 83 deletions(-) diff --git a/src/net/dnsclient_unix.go b/src/net/dnsclient_unix.go index 5a4411f5c7..fab515f5c2 100644 --- a/src/net/dnsclient_unix.go +++ b/src/net/dnsclient_unix.go @@ -214,95 +214,106 @@ func convertRR_AAAA(records []dnsRR) []IP { return addrs } +// cfg is used for the storage and reparsing of /etc/resolv.conf var cfg struct { - ch chan struct{} + // ch is used as a semaphore that only allows one lookup at a time to + // recheck resolv.conf. It acts as guard for lastChecked and modTime. + ch chan struct{} + lastChecked time.Time // last time resolv.conf was checked + modTime time.Time // time of resolv.conf modification + mu sync.RWMutex // protects dnsConfig - dnsConfig *dnsConfig + dnsConfig *dnsConfig // parsed resolv.conf structure used in lookups } var onceLoadConfig sync.Once -// Assume dns config file is /etc/resolv.conf here -func loadDefaultConfig() { - loadConfig("/etc/resolv.conf", 5*time.Second, nil) -} - -func loadConfig(resolvConfPath string, reloadTime time.Duration, quit <-chan chan struct{}) { - var mtime time.Time - cfg.ch = make(chan struct{}, 1) - if fi, err := os.Stat(resolvConfPath); err == nil { - mtime = fi.ModTime() +func initCfg() { + // Set dnsConfig, modTime, and lastChecked so we don't parse + // resolv.conf twice the first time. + cfg.dnsConfig = systemConf().resolv + if cfg.dnsConfig == nil { + cfg.dnsConfig = dnsReadConfig("/etc/resolv.conf") } - cfg.dnsConfig = dnsReadConfig(resolvConfPath) + if fi, err := os.Stat("/etc/resolv.conf"); err == nil { + cfg.modTime = fi.ModTime() + } + cfg.lastChecked = time.Now() - go func() { - for { - time.Sleep(reloadTime) - select { - case qresp := <-quit: - qresp <- struct{}{} - return - case <-cfg.ch: - } + // Prepare ch so that only one loadConfig may run at once + cfg.ch = make(chan struct{}, 1) + cfg.ch <- struct{}{} +} - // In case of error, we keep the previous config - fi, err := os.Stat(resolvConfPath) - if err != nil { - continue - } - // If the resolv.conf mtime didn't change, do not reload - m := fi.ModTime() - if m.Equal(mtime) { - continue - } - mtime = m - // In case of error, we keep the previous config - if ncfg := dnsReadConfig(resolvConfPath); ncfg.err == nil { - cfg.mu.Lock() - cfg.dnsConfig = ncfg - cfg.mu.Unlock() - } +func loadConfig(resolvConfPath string) { + onceLoadConfig.Do(initCfg) + + // ensure only one loadConfig at a time checks /etc/resolv.conf + select { + case <-cfg.ch: + defer func() { cfg.ch <- struct{}{} }() + default: + return + } + + now := time.Now() + if cfg.lastChecked.After(now.Add(-5 * time.Second)) { + return + } + cfg.lastChecked = now + + if fi, err := os.Stat(resolvConfPath); err == nil { + if fi.ModTime().Equal(cfg.modTime) { + return } - }() + cfg.modTime = fi.ModTime() + } else { + // If modTime wasn't set prior, assume nothing has changed. + if cfg.modTime.IsZero() { + return + } + cfg.modTime = time.Time{} + } + + ncfg := dnsReadConfig(resolvConfPath) + cfg.mu.Lock() + cfg.dnsConfig = ncfg + cfg.mu.Unlock() } func lookup(name string, qtype uint16) (cname string, rrs []dnsRR, err error) { if !isDomainName(name) { return name, nil, &DNSError{Err: "invalid domain name", Name: name} } - onceLoadConfig.Do(loadDefaultConfig) - - select { - case cfg.ch <- struct{}{}: - default: - } + loadConfig("/etc/resolv.conf") cfg.mu.RLock() - defer cfg.mu.RUnlock() + resolv := cfg.dnsConfig + cfg.mu.RUnlock() // If name is rooted (trailing dot) or has enough dots, // try it by itself first. rooted := len(name) > 0 && name[len(name)-1] == '.' - if rooted || count(name, '.') >= cfg.dnsConfig.ndots { + if rooted || count(name, '.') >= resolv.ndots { rname := name if !rooted { rname += "." } // Can try as ordinary name. - cname, rrs, err = tryOneName(cfg.dnsConfig, rname, qtype) + cname, rrs, err = tryOneName(resolv, rname, qtype) if rooted || err == nil { return } } // Otherwise, try suffixes. - for i := 0; i < len(cfg.dnsConfig.search); i++ { - rname := name + "." + cfg.dnsConfig.search[i] + for _, suffix := range resolv.search { + rname := name + "." + suffix if rname[len(rname)-1] != '.' { rname += "." } - cname, rrs, err = tryOneName(cfg.dnsConfig, rname, qtype) + cname, rrs, err = tryOneName(resolv, rname, qtype) if err == nil { return } @@ -310,8 +321,8 @@ func lookup(name string, qtype uint16) (cname string, rrs []dnsRR, err error) { // Last ditch effort: try unsuffixed only if we haven't already, // that is, name is not rooted and has less than ndots dots. - if count(name, '.') < cfg.dnsConfig.ndots { - cname, rrs, err = tryOneName(cfg.dnsConfig, name+".", qtype) + if count(name, '.') < resolv.ndots { + cname, rrs, err = tryOneName(resolv, name+".", qtype) if err == nil { return } diff --git a/src/net/dnsclient_unix_test.go b/src/net/dnsclient_unix_test.go index 4ea24b6014..06c9ad3134 100644 --- a/src/net/dnsclient_unix_test.go +++ b/src/net/dnsclient_unix_test.go @@ -94,10 +94,8 @@ func TestSpecialDomainName(t *testing.T) { type resolvConfTest struct { *testing.T - dir string - path string - started bool - quitc chan chan struct{} + dir string + path string } func newResolvConfTest(t *testing.T) *resolvConfTest { @@ -106,24 +104,15 @@ func newResolvConfTest(t *testing.T) *resolvConfTest { t.Fatal(err) } - // Disable the default loadConfig - onceLoadConfig.Do(func() {}) - r := &resolvConfTest{ - T: t, - dir: dir, - path: path.Join(dir, "resolv.conf"), - quitc: make(chan chan struct{}), + T: t, + dir: dir, + path: path.Join(dir, "resolv.conf"), } return r } -func (r *resolvConfTest) Start() { - loadConfig(r.path, 100*time.Millisecond, r.quitc) - r.started = true -} - func (r *resolvConfTest) SetConf(s string) { // Make sure the file mtime will be different once we're done here, // even on systems with coarse (1s) mtime resolution. @@ -138,12 +127,8 @@ func (r *resolvConfTest) SetConf(s string) { r.Fatalf("failed to write temp file: %v", err) } f.Close() - - if r.started { - cfg.ch <- struct{}{} // fill buffer - cfg.ch <- struct{}{} // wait for reload to begin - cfg.ch <- struct{}{} // wait for reload to complete - } + cfg.lastChecked = time.Time{} + loadConfig(r.path) } func (r *resolvConfTest) WantServers(want []string) { @@ -155,9 +140,6 @@ func (r *resolvConfTest) WantServers(want []string) { } func (r *resolvConfTest) Close() { - resp := make(chan struct{}) - r.quitc <- resp - <-resp if err := os.RemoveAll(r.dir); err != nil { r.Logf("failed to remove temp dir %s: %v", r.dir, err) } @@ -171,7 +153,6 @@ func TestReloadResolvConfFail(t *testing.T) { r := newResolvConfTest(t) defer r.Close() - r.Start() r.SetConf("nameserver 8.8.8.8") if _, err := goLookupIP("golang.org"); err != nil { @@ -200,7 +181,6 @@ func TestReloadResolvConfChange(t *testing.T) { r := newResolvConfTest(t) defer r.Close() - r.Start() r.SetConf("nameserver 8.8.8.8") if _, err := goLookupIP("golang.org"); err != nil { @@ -245,14 +225,14 @@ func BenchmarkGoLookupIPNoSuchHost(b *testing.B) { func BenchmarkGoLookupIPWithBrokenNameServer(b *testing.B) { testHookUninstaller.Do(uninstallTestHooks) - onceLoadConfig.Do(loadDefaultConfig) - // This looks ugly but it's safe as long as benchmarks are run // sequentially in package testing. + <-cfg.ch // keep config from being reloaded upon lookup orig := cfg.dnsConfig cfg.dnsConfig.servers = append([]string{"203.0.113.254"}, cfg.dnsConfig.servers...) // use TEST-NET-3 block, see RFC 5737 for i := 0; i < b.N; i++ { goLookupIP("www.example.com") } cfg.dnsConfig = orig + cfg.ch <- struct{}{} } From 8fa14ea8b4744576bd28073901154c15813e29de Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Fri, 15 May 2015 10:02:19 -0700 Subject: [PATCH 116/232] cmd/internal/gc: unembed Name field This is an automated follow-up to CL 10120. It was generated with a combination of eg and gofmt -r. No functional changes. Passes toolstash -cmp. Change-Id: I0dc6d146372012b4cce9cc4064066daa6694eee6 Reviewed-on: https://go-review.googlesource.com/10144 Reviewed-by: Brad Fitzpatrick --- src/cmd/5g/ggen.go | 2 +- src/cmd/5g/gsubr.go | 2 +- src/cmd/6g/ggen.go | 2 +- src/cmd/7g/ggen.go | 2 +- src/cmd/8g/ggen.go | 2 +- src/cmd/8g/gsubr.go | 2 +- src/cmd/9g/ggen.go | 2 +- src/cmd/internal/gc/cgen.go | 4 ++-- src/cmd/internal/gc/closure.go | 28 ++++++++++++++-------------- src/cmd/internal/gc/esc.go | 2 +- src/cmd/internal/gc/gen.go | 8 ++++---- src/cmd/internal/gc/gsubr.go | 4 ++-- src/cmd/internal/gc/inl.go | 22 +++++++++++----------- src/cmd/internal/gc/pgen.go | 4 ++-- src/cmd/internal/gc/plive.go | 4 ++-- src/cmd/internal/gc/sinit.go | 2 +- src/cmd/internal/gc/syntax.go | 2 +- src/cmd/internal/gc/typecheck.go | 6 +++--- src/cmd/internal/gc/walk.go | 2 +- 19 files changed, 51 insertions(+), 51 deletions(-) diff --git a/src/cmd/5g/ggen.go b/src/cmd/5g/ggen.go index e4612362a2..2ab5d521bb 100644 --- a/src/cmd/5g/ggen.go +++ b/src/cmd/5g/ggen.go @@ -30,7 +30,7 @@ func defframe(ptxt *obj.Prog) { r0 := uint32(0) for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next { n = l.N - if !n.Needzero { + if !n.Name.Needzero { continue } if n.Class != gc.PAUTO { diff --git a/src/cmd/5g/gsubr.go b/src/cmd/5g/gsubr.go index 2f70bfd468..2a23580b58 100644 --- a/src/cmd/5g/gsubr.go +++ b/src/cmd/5g/gsubr.go @@ -89,7 +89,7 @@ func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) { case gc.ONAME: if n.Class == gc.PPARAMREF { var n1 gc.Node - gc.Cgen(n.Heapaddr, &n1) + gc.Cgen(n.Name.Heapaddr, &n1) sclean[nsclean-1] = n1 n = &n1 } diff --git a/src/cmd/6g/ggen.go b/src/cmd/6g/ggen.go index 12198d7187..7282ac53e0 100644 --- a/src/cmd/6g/ggen.go +++ b/src/cmd/6g/ggen.go @@ -32,7 +32,7 @@ func defframe(ptxt *obj.Prog) { // iterate through declarations - they are sorted in decreasing xoffset order. for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next { n = l.N - if !n.Needzero { + if !n.Name.Needzero { continue } if n.Class != gc.PAUTO { diff --git a/src/cmd/7g/ggen.go b/src/cmd/7g/ggen.go index af51c31648..ec2eb09e38 100644 --- a/src/cmd/7g/ggen.go +++ b/src/cmd/7g/ggen.go @@ -32,7 +32,7 @@ func defframe(ptxt *obj.Prog) { // iterate through declarations - they are sorted in decreasing xoffset order. for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next { n = l.N - if !n.Needzero { + if !n.Name.Needzero { continue } if n.Class != gc.PAUTO { diff --git a/src/cmd/8g/ggen.go b/src/cmd/8g/ggen.go index baa1b64d1e..bd2c13e867 100644 --- a/src/cmd/8g/ggen.go +++ b/src/cmd/8g/ggen.go @@ -30,7 +30,7 @@ func defframe(ptxt *obj.Prog) { ax := uint32(0) for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next { n = l.N - if !n.Needzero { + if !n.Name.Needzero { continue } if n.Class != gc.PAUTO { diff --git a/src/cmd/8g/gsubr.go b/src/cmd/8g/gsubr.go index b0b0aedabc..99bce6eaba 100644 --- a/src/cmd/8g/gsubr.go +++ b/src/cmd/8g/gsubr.go @@ -678,7 +678,7 @@ func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) { case gc.ONAME: if n.Class == gc.PPARAMREF { var n1 gc.Node - gc.Cgen(n.Heapaddr, &n1) + gc.Cgen(n.Name.Heapaddr, &n1) sclean[nsclean-1] = n1 n = &n1 } diff --git a/src/cmd/9g/ggen.go b/src/cmd/9g/ggen.go index 265536921a..3a10a2a760 100644 --- a/src/cmd/9g/ggen.go +++ b/src/cmd/9g/ggen.go @@ -32,7 +32,7 @@ func defframe(ptxt *obj.Prog) { // iterate through declarations - they are sorted in decreasing xoffset order. for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next { n = l.N - if !n.Needzero { + if !n.Name.Needzero { continue } if n.Class != gc.PAUTO { diff --git a/src/cmd/internal/gc/cgen.go b/src/cmd/internal/gc/cgen.go index 7237e863ca..bb022b8351 100644 --- a/src/cmd/internal/gc/cgen.go +++ b/src/cmd/internal/gc/cgen.go @@ -1579,7 +1579,7 @@ func Agen(n *Node, res *Node) { Fatal("agen: bad ONAME class %#x", n.Class) } - Cgen(n.Heapaddr, res) + Cgen(n.Name.Heapaddr, res) if n.Xoffset != 0 { addOffset(res, n.Xoffset) } @@ -2517,7 +2517,7 @@ func cgen_call(n *Node, proc int) { } // call direct - n.Left.Method = true + n.Left.Name.Method = true Ginscall(n.Left, proc) } diff --git a/src/cmd/internal/gc/closure.go b/src/cmd/internal/gc/closure.go index 8d5fd5a600..b51e74b77d 100644 --- a/src/cmd/internal/gc/closure.go +++ b/src/cmd/internal/gc/closure.go @@ -84,15 +84,15 @@ func typecheckclosure(func_ *Node, top int) { for l := func_.Func.Cvars; l != nil; l = l.Next { n = l.N.Closure - if !n.Captured { - n.Captured = true - if n.Decldepth == 0 { + if !n.Name.Captured { + n.Name.Captured = true + if n.Name.Decldepth == 0 { Fatal("typecheckclosure: var %v does not have decldepth assigned", Nconv(n, obj.FmtShort)) } // Ignore assignments to the variable in straightline code // preceding the first capturing by a closure. - if n.Decldepth == decldepth { + if n.Name.Decldepth == decldepth { n.Assigned = false } } @@ -100,7 +100,7 @@ func typecheckclosure(func_ *Node, top int) { for l := func_.Func.Dcl; l != nil; l = l.Next { if l.N.Op == ONAME && (l.N.Class == PPARAM || l.N.Class == PPARAMOUT) { - l.N.Decldepth = 1 + l.N.Name.Decldepth = 1 } } @@ -254,7 +254,7 @@ func capturevars(xfunc *Node) { // out parameters will be assigned to implicitly upon return. if outer.Class != PPARAMOUT && !v.Closure.Addrtaken && !v.Closure.Assigned && v.Type.Width <= 128 { - v.Byval = true + v.Name.Byval = true } else { v.Closure.Addrtaken = true outer = Nod(OADDR, outer, nil) @@ -266,7 +266,7 @@ func capturevars(xfunc *Node) { name = v.Curfn.Nname.Sym } how := "ref" - if v.Byval { + if v.Name.Byval { how = "value" } Warnl(int(v.Lineno), "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym, v.Closure.Addrtaken, v.Closure.Assigned, int32(v.Type.Width)) @@ -321,7 +321,7 @@ func transformclosure(xfunc *Node) { } fld = typ(TFIELD) fld.Funarg = 1 - if v.Byval { + if v.Name.Byval { // If v is captured by value, we merely downgrade it to PPARAM. v.Class = PPARAM @@ -335,7 +335,7 @@ func transformclosure(xfunc *Node) { addr = newname(Lookupf("&%s", v.Sym.Name)) addr.Type = Ptrto(v.Type) addr.Class = PPARAM - v.Heapaddr = addr + v.Name.Heapaddr = addr fld.Nname = addr } @@ -375,14 +375,14 @@ func transformclosure(xfunc *Node) { cv = Nod(OCLOSUREVAR, nil, nil) cv.Type = v.Type - if !v.Byval { + if !v.Name.Byval { cv.Type = Ptrto(v.Type) } offset = Rnd(offset, int64(cv.Type.Align)) cv.Xoffset = offset offset += cv.Type.Width - if v.Byval && v.Type.Width <= int64(2*Widthptr) && Thearch.Thechar == '6' { + if v.Name.Byval && v.Type.Width <= int64(2*Widthptr) && Thearch.Thechar == '6' { // If it is a small variable captured by value, downgrade it to PAUTO. // This optimization is currently enabled only for amd64, see: // https://github.com/golang/go/issues/9865 @@ -400,8 +400,8 @@ func transformclosure(xfunc *Node) { addr.Used = true addr.Curfn = xfunc xfunc.Func.Dcl = list(xfunc.Func.Dcl, addr) - v.Heapaddr = addr - if v.Byval { + v.Name.Heapaddr = addr + if v.Name.Byval { cv = Nod(OADDR, cv, nil) } body = list(body, Nod(OAS, addr, cv)) @@ -448,7 +448,7 @@ func walkclosure(func_ *Node, init **NodeList) *Node { continue } typ1 = typenod(v.Type) - if !v.Byval { + if !v.Name.Byval { typ1 = Nod(OIND, typ1, nil) } typ.List = list(typ.List, Nod(ODCLFIELD, newname(v.Sym), typ1)) diff --git a/src/cmd/internal/gc/esc.go b/src/cmd/internal/gc/esc.go index c816feaa7f..5fb2095bda 100644 --- a/src/cmd/internal/gc/esc.go +++ b/src/cmd/internal/gc/esc.go @@ -834,7 +834,7 @@ func esc(e *EscState, n *Node, up *Node) { continue } a = v.Closure - if !v.Byval { + if !v.Name.Byval { a = Nod(OADDR, a, nil) a.Lineno = v.Lineno a.Escloopdepth = e.loopdepth diff --git a/src/cmd/internal/gc/gen.go b/src/cmd/internal/gc/gen.go index cd0e650ca9..d3c6387a4e 100644 --- a/src/cmd/internal/gc/gen.go +++ b/src/cmd/internal/gc/gen.go @@ -78,10 +78,10 @@ func addrescapes(n *Node) { oldfn := Curfn Curfn = n.Curfn - n.Heapaddr = temp(Ptrto(n.Type)) + n.Name.Heapaddr = temp(Ptrto(n.Type)) buf := fmt.Sprintf("&%v", n.Sym) - n.Heapaddr.Sym = Lookup(buf) - n.Heapaddr.Orig.Sym = n.Heapaddr.Sym + n.Name.Heapaddr.Sym = Lookup(buf) + n.Name.Heapaddr.Orig.Sym = n.Name.Heapaddr.Sym n.Esc = EscHeap if Debug['m'] != 0 { fmt.Printf("%v: moved to heap: %v\n", n.Line(), n) @@ -262,7 +262,7 @@ func cgen_dcl(n *Node) { if n.Alloc == nil { n.Alloc = callnew(n.Type) } - Cgen_as(n.Heapaddr, n.Alloc) + Cgen_as(n.Name.Heapaddr, n.Alloc) } /* diff --git a/src/cmd/internal/gc/gsubr.go b/src/cmd/internal/gc/gsubr.go index 98d6346e2a..5ec4587e74 100644 --- a/src/cmd/internal/gc/gsubr.go +++ b/src/cmd/internal/gc/gsubr.go @@ -214,7 +214,7 @@ func ggloblnod(nam *Node) { p.To.Sym = nil p.To.Type = obj.TYPE_CONST p.To.Offset = nam.Type.Width - if nam.Readonly { + if nam.Name.Readonly { p.From3.Offset = obj.RODATA } if nam.Type != nil && !haspointers(nam.Type) { @@ -369,7 +369,7 @@ func Naddr(a *obj.Addr, n *Node) { if s == nil { s = Lookup(".noname") } - if n.Method { + if n.Name.Method { if n.Type != nil { if n.Type.Sym != nil { if n.Type.Sym.Pkg != nil { diff --git a/src/cmd/internal/gc/inl.go b/src/cmd/internal/gc/inl.go index dd2087dec3..22a5d3d9fe 100644 --- a/src/cmd/internal/gc/inl.go +++ b/src/cmd/internal/gc/inl.go @@ -511,10 +511,10 @@ func mkinlcall(np **Node, fn *Node, isddd bool) { func tinlvar(t *Type) *Node { if t.Nname != nil && !isblank(t.Nname) { - if t.Nname.Inlvar == nil { + if t.Nname.Name.Inlvar == nil { Fatal("missing inlvar for %v\n", t.Nname) } - return t.Nname.Inlvar + return t.Nname.Name.Inlvar } typecheck(&nblank, Erv|Easgn) @@ -577,13 +577,13 @@ func mkinlcall1(np **Node, fn *Node, isddd bool) { continue } if ll.N.Op == ONAME { - ll.N.Inlvar = inlvar(ll.N) + ll.N.Name.Inlvar = inlvar(ll.N) // Typecheck because inlvar is not necessarily a function parameter. - typecheck(&ll.N.Inlvar, Erv) + typecheck(&ll.N.Name.Inlvar, Erv) if ll.N.Class&^PHEAP != PAUTO { - ninit = list(ninit, Nod(ODCL, ll.N.Inlvar, nil)) // otherwise gen won't emit the allocations for heapallocs + ninit = list(ninit, Nod(ODCL, ll.N.Name.Inlvar, nil)) // otherwise gen won't emit the allocations for heapallocs } } } @@ -594,7 +594,7 @@ func mkinlcall1(np **Node, fn *Node, isddd bool) { if t != nil && t.Nname != nil && !isblank(t.Nname) { m = inlvar(t.Nname) typecheck(&m, Erv) - t.Nname.Inlvar = m + t.Nname.Name.Inlvar = m } else { // anonymous return values, synthesize names for use in assignment that replaces return m = retvar(t, i) @@ -611,7 +611,7 @@ func mkinlcall1(np **Node, fn *Node, isddd bool) { // method call with a receiver. t := getthisx(fn.Type).Type - if t != nil && t.Nname != nil && !isblank(t.Nname) && t.Nname.Inlvar == nil { + if t != nil && t.Nname != nil && !isblank(t.Nname) && t.Nname.Name.Inlvar == nil { Fatal("missing inlvar for %v\n", t.Nname) } if n.Left.Left == nil { @@ -680,7 +680,7 @@ func mkinlcall1(np **Node, fn *Node, isddd bool) { // append receiver inlvar to LHS. t := getthisx(fn.Type).Type - if t != nil && t.Nname != nil && !isblank(t.Nname) && t.Nname.Inlvar == nil { + if t != nil && t.Nname != nil && !isblank(t.Nname) && t.Nname.Name.Inlvar == nil { Fatal("missing inlvar for %v\n", t.Nname) } if t == nil { @@ -907,11 +907,11 @@ func inlsubst(n *Node) *Node { switch n.Op { case ONAME: - if n.Inlvar != nil { // These will be set during inlnode + if n.Name.Inlvar != nil { // These will be set during inlnode if Debug['m'] > 2 { - fmt.Printf("substituting name %v -> %v\n", Nconv(n, obj.FmtSign), Nconv(n.Inlvar, obj.FmtSign)) + fmt.Printf("substituting name %v -> %v\n", Nconv(n, obj.FmtSign), Nconv(n.Name.Inlvar, obj.FmtSign)) } - return n.Inlvar + return n.Name.Inlvar } if Debug['m'] > 2 { diff --git a/src/cmd/internal/gc/pgen.go b/src/cmd/internal/gc/pgen.go index f247a685ca..1b67cf2c3e 100644 --- a/src/cmd/internal/gc/pgen.go +++ b/src/cmd/internal/gc/pgen.go @@ -200,8 +200,8 @@ func cmpstackvar(a *Node, b *Node) int { return bp - ap } - ap = obj.Bool2int(a.Needzero) - bp = obj.Bool2int(b.Needzero) + ap = obj.Bool2int(a.Name.Needzero) + bp = obj.Bool2int(b.Name.Needzero) if ap != bp { return bp - ap } diff --git a/src/cmd/internal/gc/plive.go b/src/cmd/internal/gc/plive.go index 040a77814e..977789f3e4 100644 --- a/src/cmd/internal/gc/plive.go +++ b/src/cmd/internal/gc/plive.go @@ -1281,8 +1281,8 @@ func livenessepilogue(lv *Liveness) { } bvset(all, pos) // silence future warnings in this block n = lv.vars[pos] - if !n.Needzero { - n.Needzero = true + if !n.Name.Needzero { + n.Name.Needzero = true if debuglive >= 1 { Warnl(int(p.Lineno), "%v: %v is ambiguously live", Curfn.Nname, Nconv(n, obj.FmtLong)) } diff --git a/src/cmd/internal/gc/sinit.go b/src/cmd/internal/gc/sinit.go index 4fdb2e9223..dfaec74de2 100644 --- a/src/cmd/internal/gc/sinit.go +++ b/src/cmd/internal/gc/sinit.go @@ -510,7 +510,7 @@ func staticname(t *Type, ctxt int) *Node { n := newname(Lookupf("statictmp_%.4d", statuniqgen)) statuniqgen++ if ctxt == 0 { - n.Readonly = true + n.Name.Readonly = true } addvar(n, t, PEXTERN) return n diff --git a/src/cmd/internal/gc/syntax.go b/src/cmd/internal/gc/syntax.go index 9ef00a09cb..818d546970 100644 --- a/src/cmd/internal/gc/syntax.go +++ b/src/cmd/internal/gc/syntax.go @@ -64,7 +64,7 @@ type Node struct { Reg int16 // ONAME - *Name + Name *Name Ntype *Node Defn *Node // ONAME: initializing assignment; OLABEL: labeled statement Pack *Node // real package for import . names diff --git a/src/cmd/internal/gc/typecheck.go b/src/cmd/internal/gc/typecheck.go index 6ad8c82c32..06f8b34305 100644 --- a/src/cmd/internal/gc/typecheck.go +++ b/src/cmd/internal/gc/typecheck.go @@ -311,8 +311,8 @@ OpSwitch: break OpSwitch case ONAME: - if n.Decldepth == 0 { - n.Decldepth = decldepth + if n.Name.Decldepth == 0 { + n.Name.Decldepth = decldepth } if n.Etype != 0 { ok |= Ecall @@ -3521,7 +3521,7 @@ func typecheckfunc(n *Node) { for l := n.Func.Dcl; l != nil; l = l.Next { if l.N.Op == ONAME && (l.N.Class == PPARAM || l.N.Class == PPARAMOUT) { - l.N.Decldepth = 1 + l.N.Name.Decldepth = 1 } } } diff --git a/src/cmd/internal/gc/walk.go b/src/cmd/internal/gc/walk.go index 81bb8524b3..a7f5256b19 100644 --- a/src/cmd/internal/gc/walk.go +++ b/src/cmd/internal/gc/walk.go @@ -2719,7 +2719,7 @@ func paramstoheap(argin **Type, out int) *NodeList { if v.Alloc == nil { v.Alloc = callnew(v.Type) } - nn = list(nn, Nod(OAS, v.Heapaddr, v.Alloc)) + nn = list(nn, Nod(OAS, v.Name.Heapaddr, v.Alloc)) if v.Class&^PHEAP != PPARAMOUT { as = Nod(OAS, v, v.Stackparam) v.Stackparam.Typecheck = 1 From c3c047a6a32ab1f5344e7c0b074fb9d1ce365bbc Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 15 May 2015 14:23:23 -0400 Subject: [PATCH 117/232] runtime: test and fix heap bitmap for 1-pointer allocation on 32-bit system Change-Id: Ic064fe7c6bd3304dcc8c3f7b3b5393870b5387c2 Reviewed-on: https://go-review.googlesource.com/10119 Run-TryBot: Austin Clements Reviewed-by: Austin Clements --- src/runtime/export_test.go | 2 ++ src/runtime/gcinfo_test.go | 30 ++++++++++++++++++++++++------ src/runtime/mbitmap.go | 27 ++++++++++++++++++++++----- 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go index 2f8df78e13..3fddcc868f 100644 --- a/src/runtime/export_test.go +++ b/src/runtime/export_test.go @@ -150,3 +150,5 @@ func BenchSetType(n int, x interface{}) { } }) } + +const PtrSize = ptrSize diff --git a/src/runtime/gcinfo_test.go b/src/runtime/gcinfo_test.go index 7618d86a45..f330bf2430 100644 --- a/src/runtime/gcinfo_test.go +++ b/src/runtime/gcinfo_test.go @@ -13,11 +13,11 @@ import ( const ( typeScalar = 0 typePointer = 1 - typeDead = 255 ) // TestGCInfo tests that various objects in heap, data and bss receive correct GC pointer type info. func TestGCInfo(t *testing.T) { + verifyGCInfo(t, "bss Ptr", &bssPtr, infoPtr) verifyGCInfo(t, "bss ScalarPtr", &bssScalarPtr, infoScalarPtr) verifyGCInfo(t, "bss PtrScalar", &bssPtrScalar, infoPtrScalar) verifyGCInfo(t, "bss BigStruct", &bssBigStruct, infoBigStruct()) @@ -26,6 +26,7 @@ func TestGCInfo(t *testing.T) { verifyGCInfo(t, "bss eface", &bssEface, infoEface) verifyGCInfo(t, "bss iface", &bssIface, infoIface) + verifyGCInfo(t, "data Ptr", &dataPtr, infoPtr) verifyGCInfo(t, "data ScalarPtr", &dataScalarPtr, infoScalarPtr) verifyGCInfo(t, "data PtrScalar", &dataPtrScalar, infoPtrScalar) verifyGCInfo(t, "data BigStruct", &dataBigStruct, infoBigStruct()) @@ -34,6 +35,7 @@ func TestGCInfo(t *testing.T) { verifyGCInfo(t, "data eface", &dataEface, infoEface) verifyGCInfo(t, "data iface", &dataIface, infoIface) + verifyGCInfo(t, "stack Ptr", new(Ptr), infoPtr) verifyGCInfo(t, "stack ScalarPtr", new(ScalarPtr), infoScalarPtr) verifyGCInfo(t, "stack PtrScalar", new(PtrScalar), infoPtrScalar) verifyGCInfo(t, "stack BigStruct", new(BigStruct), infoBigStruct()) @@ -43,6 +45,7 @@ func TestGCInfo(t *testing.T) { verifyGCInfo(t, "stack iface", new(Iface), infoIface) for i := 0; i < 10; i++ { + verifyGCInfo(t, "heap Ptr", escape(new(Ptr)), trimDead(padDead(infoPtr))) verifyGCInfo(t, "heap PtrSlice", escape(&make([]*byte, 10)[0]), trimDead(infoPtr10)) verifyGCInfo(t, "heap ScalarPtr", escape(new(ScalarPtr)), trimDead(infoScalarPtr)) verifyGCInfo(t, "heap ScalarPtrSlice", escape(&make([]ScalarPtr, 4)[0]), trimDead(infoScalarPtr4)) @@ -52,21 +55,28 @@ func TestGCInfo(t *testing.T) { verifyGCInfo(t, "heap eface", escape(new(interface{})), trimDead(infoEface)) verifyGCInfo(t, "heap iface", escape(new(Iface)), trimDead(infoIface)) } - } func verifyGCInfo(t *testing.T, name string, p interface{}, mask0 []byte) { mask := runtime.GCMask(p) - if len(mask) > len(mask0) { - mask0 = append(mask0, typeDead) - mask = mask[:len(mask0)] - } if bytes.Compare(mask, mask0) != 0 { t.Errorf("bad GC program for %v:\nwant %+v\ngot %+v", name, mask0, mask) return } } +func padDead(mask []byte) []byte { + // Because the dead bit isn't encoded until the third word, + // and because on 32-bit systems a one-word allocation + // uses a two-word block, the pointer info for a one-word + // object needs to be expanded to include an extra scalar + // on 32-bit systems to match the heap bitmap. + if runtime.PtrSize == 4 && len(mask) == 1 { + return []byte{mask[0], 0} + } + return mask +} + func trimDead(mask []byte) []byte { for len(mask) > 2 && mask[len(mask)-1] == typeScalar { mask = mask[:len(mask)-1] @@ -81,6 +91,12 @@ func escape(p interface{}) interface{} { return p } +var infoPtr = []byte{typePointer} + +type Ptr struct { + *byte +} + var infoPtr10 = []byte{typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer} type ScalarPtr struct { @@ -160,6 +176,7 @@ func (IfaceImpl) f() { var ( // BSS + bssPtr Ptr bssScalarPtr ScalarPtr bssPtrScalar PtrScalar bssBigStruct BigStruct @@ -169,6 +186,7 @@ var ( bssIface Iface // DATA + dataPtr = Ptr{new(byte)} dataScalarPtr = ScalarPtr{q: 1} dataPtrScalar = PtrScalar{w: 1} dataBigStruct = BigStruct{w: 1} diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go index fcfcc7261c..546c331614 100644 --- a/src/runtime/mbitmap.go +++ b/src/runtime/mbitmap.go @@ -583,7 +583,7 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) { // The checks for size == ptrSize and size == 2*ptrSize can therefore // assume that dataSize == size without checking it explicitly. - if size == ptrSize { + if ptrSize == 8 && size == ptrSize { // It's one word and it has pointers, it must be a pointer. // In general we'd need an atomic update here if the // concurrent GC were marking objects in this span, @@ -635,11 +635,28 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) { // are 4-word aligned (because they're all 16-byte aligned). if size == 2*ptrSize { if typ.size == ptrSize { - // 2-element slice of pointer. - if gcphase == _GCoff { - *h.bitp |= (bitPointer | bitPointer< Date: Tue, 12 May 2015 15:40:13 +1200 Subject: [PATCH 118/232] cmd/5l, etc, cmd/internal/ld: consolidate implementations of adddynlib They were all essentially the same. Change-Id: I6e0b548cda6e4bbe2ec3b3025b746d1f6d332d48 Reviewed-on: https://go-review.googlesource.com/10000 Run-TryBot: Michael Hudson-Doyle TryBot-Result: Gobot Gobot Reviewed-by: Russ Cox --- src/cmd/5l/asm.go | 36 ------------------------------------ src/cmd/5l/obj.go | 1 - src/cmd/6l/asm.go | 38 +------------------------------------- src/cmd/6l/obj.go | 1 - src/cmd/7l/asm.go | 36 ------------------------------------ src/cmd/7l/obj.go | 1 - src/cmd/8l/asm.go | 36 ------------------------------------ src/cmd/8l/obj.go | 1 - src/cmd/9l/asm.go | 34 ---------------------------------- src/cmd/9l/obj.go | 1 - src/cmd/internal/ld/go.go | 23 ++++++++++++++++++++++- src/cmd/internal/ld/lib.go | 1 - 12 files changed, 23 insertions(+), 186 deletions(-) diff --git a/src/cmd/5l/asm.go b/src/cmd/5l/asm.go index 85ea684fc7..14302a5a38 100644 --- a/src/cmd/5l/asm.go +++ b/src/cmd/5l/asm.go @@ -37,24 +37,6 @@ import ( "log" ) -func needlib(name string) int { - if name[0] == '\x00' { - return 0 - } - - /* reuse hash code in symbol table */ - p := fmt.Sprintf(".dynlib.%s", name) - - s := ld.Linklookup(ld.Ctxt, p, 0) - - if s.Type == 0 { - s.Type = 100 // avoid SDATA, etc. - return 1 - } - - return 0 -} - func gentext() { } @@ -557,24 +539,6 @@ func adddynsym(ctxt *ld.Link, s *ld.LSym) { } } -func adddynlib(lib string) { - if needlib(lib) == 0 { - return - } - - if ld.Iself { - s := ld.Linklookup(ld.Ctxt, ".dynstr", 0) - if s.Size == 0 { - ld.Addstring(s, "") - } - ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib))) - } else if ld.HEADTYPE == obj.Hdarwin { - ld.Machoadddynlib(lib) - } else { - ld.Diag("adddynlib: unsupported binary format") - } -} - func asmb() { if ld.Debug['v'] != 0 { fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime()) diff --git a/src/cmd/5l/obj.go b/src/cmd/5l/obj.go index e4fffdec6a..d9485521ad 100644 --- a/src/cmd/5l/obj.go +++ b/src/cmd/5l/obj.go @@ -58,7 +58,6 @@ func linkarchinit() { ld.Thearch.Dwarfregsp = DWARFREGSP ld.Thearch.Dwarfreglr = DWARFREGLR - ld.Thearch.Adddynlib = adddynlib ld.Thearch.Adddynrel = adddynrel ld.Thearch.Adddynsym = adddynsym ld.Thearch.Archinit = archinit diff --git a/src/cmd/6l/asm.go b/src/cmd/6l/asm.go index a025ce6ea6..9b471a04ac 100644 --- a/src/cmd/6l/asm.go +++ b/src/cmd/6l/asm.go @@ -44,24 +44,6 @@ func PADDR(x uint32) uint32 { var zeroes string -func needlib(name string) int { - if name[0] == '\x00' { - return 0 - } - - /* reuse hash code in symbol table */ - p := fmt.Sprintf(".elfload.%s", name) - - s := ld.Linklookup(ld.Ctxt, p, 0) - - if s.Type == 0 { - s.Type = 100 // avoid SDATA, etc. - return 1 - } - - return 0 -} - func Addcall(ctxt *ld.Link, s *ld.LSym, t *ld.LSym) int64 { s.Reachable = true i := s.Size @@ -673,7 +655,7 @@ func adddynsym(ctxt *ld.Link, s *ld.LSym) { /* size of object */ ld.Adduint64(ctxt, d, uint64(s.Size)) - if s.Cgoexport&ld.CgoExportDynamic == 0 && s.Dynimplib != "" && needlib(s.Dynimplib) != 0 { + if s.Cgoexport&ld.CgoExportDynamic == 0 && s.Dynimplib != "" && !ld.Seenlib[s.Dynimplib] { ld.Elfwritedynent(ld.Linklookup(ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), s.Dynimplib))) } } else if ld.HEADTYPE == obj.Hdarwin { @@ -685,24 +667,6 @@ func adddynsym(ctxt *ld.Link, s *ld.LSym) { } } -func adddynlib(lib string) { - if needlib(lib) == 0 { - return - } - - if ld.Iself { - s := ld.Linklookup(ld.Ctxt, ".dynstr", 0) - if s.Size == 0 { - ld.Addstring(s, "") - } - ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib))) - } else if ld.HEADTYPE == obj.Hdarwin { - ld.Machoadddynlib(lib) - } else { - ld.Diag("adddynlib: unsupported binary format") - } -} - func asmb() { if ld.Debug['v'] != 0 { fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime()) diff --git a/src/cmd/6l/obj.go b/src/cmd/6l/obj.go index 8ee7bb28db..38ac0783b6 100644 --- a/src/cmd/6l/obj.go +++ b/src/cmd/6l/obj.go @@ -61,7 +61,6 @@ func linkarchinit() { ld.Thearch.Dwarfregsp = DWARFREGSP ld.Thearch.Dwarfreglr = DWARFREGLR - ld.Thearch.Adddynlib = adddynlib ld.Thearch.Adddynrel = adddynrel ld.Thearch.Adddynsym = adddynsym ld.Thearch.Archinit = archinit diff --git a/src/cmd/7l/asm.go b/src/cmd/7l/asm.go index a17899dcf0..a0e813cfa5 100644 --- a/src/cmd/7l/asm.go +++ b/src/cmd/7l/asm.go @@ -40,24 +40,6 @@ import ( func gentext() {} -func needlib(name string) int { - if name[0] == '\x00' { - return 0 - } - - /* reuse hash code in symbol table */ - p := fmt.Sprintf(".dynlib.%s", name) - - s := ld.Linklookup(ld.Ctxt, p, 0) - - if s.Type == 0 { - s.Type = 100 // avoid SDATA, etc. - return 1 - } - - return 0 -} - func adddynrela(rel *ld.LSym, s *ld.LSym, r *ld.Reloc) { log.Fatalf("adddynrela not implemented") } @@ -297,24 +279,6 @@ func adddynsym(ctxt *ld.Link, s *ld.LSym) { // TODO(minux): implement when needed. } -func adddynlib(lib string) { - if needlib(lib) == 0 { - return - } - - if ld.Iself { - s := ld.Linklookup(ld.Ctxt, ".dynstr", 0) - if s.Size == 0 { - ld.Addstring(s, "") - } - ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib))) - } else if ld.HEADTYPE == obj.Hdarwin { - ld.Machoadddynlib(lib) - } else { - ld.Diag("adddynlib: unsupported binary format") - } -} - func asmb() { if ld.Debug['v'] != 0 { fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime()) diff --git a/src/cmd/7l/obj.go b/src/cmd/7l/obj.go index aeea421bc2..7d0500387b 100644 --- a/src/cmd/7l/obj.go +++ b/src/cmd/7l/obj.go @@ -58,7 +58,6 @@ func linkarchinit() { ld.Thearch.Dwarfregsp = DWARFREGSP ld.Thearch.Dwarfreglr = DWARFREGLR - ld.Thearch.Adddynlib = adddynlib ld.Thearch.Adddynrel = adddynrel ld.Thearch.Adddynsym = adddynsym ld.Thearch.Archinit = archinit diff --git a/src/cmd/8l/asm.go b/src/cmd/8l/asm.go index 7231379108..873fd16470 100644 --- a/src/cmd/8l/asm.go +++ b/src/cmd/8l/asm.go @@ -37,24 +37,6 @@ import ( "log" ) -func needlib(name string) int { - if name[0] == '\x00' { - return 0 - } - - /* reuse hash code in symbol table */ - p := fmt.Sprintf(".dynlib.%s", name) - - s := ld.Linklookup(ld.Ctxt, p, 0) - - if s.Type == 0 { - s.Type = 100 // avoid SDATA, etc. - return 1 - } - - return 0 -} - func gentext() { } @@ -548,24 +530,6 @@ func adddynsym(ctxt *ld.Link, s *ld.LSym) { } } -func adddynlib(lib string) { - if needlib(lib) == 0 { - return - } - - if ld.Iself { - s := ld.Linklookup(ld.Ctxt, ".dynstr", 0) - if s.Size == 0 { - ld.Addstring(s, "") - } - ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib))) - } else if ld.HEADTYPE == obj.Hdarwin { - ld.Machoadddynlib(lib) - } else if ld.HEADTYPE != obj.Hwindows { - ld.Diag("adddynlib: unsupported binary format") - } -} - func asmb() { if ld.Debug['v'] != 0 { fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime()) diff --git a/src/cmd/8l/obj.go b/src/cmd/8l/obj.go index 5af3f9249b..9bbaa7ee1b 100644 --- a/src/cmd/8l/obj.go +++ b/src/cmd/8l/obj.go @@ -58,7 +58,6 @@ func linkarchinit() { ld.Thearch.Dwarfregsp = DWARFREGSP ld.Thearch.Dwarfreglr = DWARFREGLR - ld.Thearch.Adddynlib = adddynlib ld.Thearch.Adddynrel = adddynrel ld.Thearch.Adddynsym = adddynsym ld.Thearch.Archinit = archinit diff --git a/src/cmd/9l/asm.go b/src/cmd/9l/asm.go index 257f23e2ab..702ba2bb7c 100644 --- a/src/cmd/9l/asm.go +++ b/src/cmd/9l/asm.go @@ -38,24 +38,6 @@ import ( "log" ) -func needlib(name string) int { - if name[0] == '\x00' { - return 0 - } - - /* reuse hash code in symbol table */ - p := fmt.Sprintf(".dynlib.%s", name) - - s := ld.Linklookup(ld.Ctxt, p, 0) - - if s.Type == 0 { - s.Type = 100 // avoid SDATA, etc. - return 1 - } - - return 0 -} - func gentext() { var s *ld.LSym var stub *ld.LSym @@ -670,22 +652,6 @@ func adddynsym(ctxt *ld.Link, s *ld.LSym) { } } -func adddynlib(lib string) { - if needlib(lib) == 0 { - return - } - - if ld.Iself { - s := ld.Linklookup(ld.Ctxt, ".dynstr", 0) - if s.Size == 0 { - ld.Addstring(s, "") - } - ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib))) - } else { - ld.Diag("adddynlib: unsupported binary format") - } -} - func asmb() { if ld.Debug['v'] != 0 { fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime()) diff --git a/src/cmd/9l/obj.go b/src/cmd/9l/obj.go index 2da37561e9..f584ca43cd 100644 --- a/src/cmd/9l/obj.go +++ b/src/cmd/9l/obj.go @@ -62,7 +62,6 @@ func linkarchinit() { ld.Thearch.Dwarfregsp = DWARFREGSP ld.Thearch.Dwarfreglr = DWARFREGLR - ld.Thearch.Adddynlib = adddynlib ld.Thearch.Adddynrel = adddynrel ld.Thearch.Adddynsym = adddynsym ld.Thearch.Archinit = archinit diff --git a/src/cmd/internal/ld/go.go b/src/cmd/internal/ld/go.go index 0223bfae9d..c1defeb8a2 100644 --- a/src/cmd/internal/ld/go.go +++ b/src/cmd/internal/ld/go.go @@ -416,7 +416,7 @@ func loadcgo(file string, pkg string, p string) { // to force a link of foo.so. havedynamic = 1 - Thearch.Adddynlib(lib) + adddynlib(lib) continue } @@ -534,6 +534,27 @@ err: nerrors++ } +var Seenlib = make(map[string]bool) + +func adddynlib(lib string) { + if Seenlib[lib] { + return + } + Seenlib[lib] = true + + if Iself { + s := Linklookup(Ctxt, ".dynstr", 0) + if s.Size == 0 { + Addstring(s, "") + } + Elfwritedynent(Linklookup(Ctxt, ".dynamic", 0), DT_NEEDED, uint64(Addstring(s, lib))) + } else if HEADTYPE == obj.Hdarwin { + Machoadddynlib(lib) + } else { + Diag("adddynlib: unsupported binary format") + } +} + var markq *LSym var emarkq *LSym diff --git a/src/cmd/internal/ld/lib.go b/src/cmd/internal/ld/lib.go index d4e67800d2..5ab5f653f3 100644 --- a/src/cmd/internal/ld/lib.go +++ b/src/cmd/internal/ld/lib.go @@ -94,7 +94,6 @@ type Arch struct { Openbsddynld string Dragonflydynld string Solarisdynld string - Adddynlib func(string) Adddynrel func(*LSym, *Reloc) Adddynsym func(*Link, *LSym) Archinit func() From 4cfff271c2aacd4ef23f7eacd9adf61605c45e74 Mon Sep 17 00:00:00 2001 From: Michael Hudson-Doyle Date: Tue, 12 May 2015 15:59:15 +1200 Subject: [PATCH 119/232] cmd/5l, etc, cmd/internal/ld: consolidate implementations of adddynsym The only essential difference is elf32 vs elf64, I assume the other differences are bugs in one version or another... Change-Id: Ie6ff33d5574a6592b543df9983eff8fdf88c97a1 Reviewed-on: https://go-review.googlesource.com/10001 Run-TryBot: Michael Hudson-Doyle Reviewed-by: Russ Cox --- src/cmd/5l/asm.go | 54 ++--------------------- src/cmd/5l/obj.go | 1 - src/cmd/6l/asm.go | 64 ++-------------------------- src/cmd/6l/obj.go | 1 - src/cmd/7l/asm.go | 4 -- src/cmd/7l/obj.go | 1 - src/cmd/8l/asm.go | 60 ++------------------------ src/cmd/8l/obj.go | 1 - src/cmd/9l/asm.go | 52 +---------------------- src/cmd/9l/obj.go | 1 - src/cmd/internal/ld/elf.go | 87 ++++++++++++++++++++++++++++++++++++++ src/cmd/internal/ld/go.go | 24 +++++++++-- src/cmd/internal/ld/lib.go | 1 - 13 files changed, 120 insertions(+), 231 deletions(-) diff --git a/src/cmd/5l/asm.go b/src/cmd/5l/asm.go index 14302a5a38..1b69671b9f 100644 --- a/src/cmd/5l/asm.go +++ b/src/cmd/5l/asm.go @@ -176,7 +176,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) { break } if ld.Iself { - adddynsym(ld.Ctxt, targ) + ld.Adddynsym(ld.Ctxt, targ) rel := ld.Linklookup(ld.Ctxt, ".rel", 0) ld.Addaddrplus(ld.Ctxt, rel, s, int64(r.Off)) ld.Adduint32(ld.Ctxt, rel, ld.ELF32_R_INFO(uint32(targ.Dynid), ld.R_ARM_GLOB_DAT)) // we need a nil + A dynmic reloc @@ -422,7 +422,7 @@ func addpltsym(ctxt *ld.Link, s *ld.LSym) { return } - adddynsym(ctxt, s) + ld.Adddynsym(ctxt, s) if ld.Iself { plt := ld.Linklookup(ctxt, ".plt", 0) @@ -477,7 +477,7 @@ func addgotsym(ctxt *ld.Link, s *ld.LSym) { return } - adddynsym(ctxt, s) + ld.Adddynsym(ctxt, s) got := ld.Linklookup(ctxt, ".got", 0) s.Got = int32(got.Size) ld.Adduint32(ctxt, got, 0) @@ -491,54 +491,6 @@ func addgotsym(ctxt *ld.Link, s *ld.LSym) { } } -func adddynsym(ctxt *ld.Link, s *ld.LSym) { - if s.Dynid >= 0 { - return - } - - if ld.Iself { - s.Dynid = int32(ld.Nelfsym) - ld.Nelfsym++ - - d := ld.Linklookup(ctxt, ".dynsym", 0) - - /* name */ - name := s.Extname - - ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name))) - - /* value */ - if s.Type == obj.SDYNIMPORT { - ld.Adduint32(ctxt, d, 0) - } else { - ld.Addaddr(ctxt, d, s) - } - - /* size */ - ld.Adduint32(ctxt, d, 0) - - /* type */ - t := ld.STB_GLOBAL << 4 - - if (s.Cgoexport&ld.CgoExportDynamic != 0) && s.Type&obj.SMASK == obj.STEXT { - t |= ld.STT_FUNC - } else { - t |= ld.STT_OBJECT - } - ld.Adduint8(ctxt, d, uint8(t)) - ld.Adduint8(ctxt, d, 0) - - /* shndx */ - if s.Type == obj.SDYNIMPORT { - ld.Adduint16(ctxt, d, ld.SHN_UNDEF) - } else { - ld.Adduint16(ctxt, d, 1) - } - } else { - ld.Diag("adddynsym: unsupported binary format") - } -} - func asmb() { if ld.Debug['v'] != 0 { fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime()) diff --git a/src/cmd/5l/obj.go b/src/cmd/5l/obj.go index d9485521ad..9c9578343e 100644 --- a/src/cmd/5l/obj.go +++ b/src/cmd/5l/obj.go @@ -59,7 +59,6 @@ func linkarchinit() { ld.Thearch.Dwarfreglr = DWARFREGLR ld.Thearch.Adddynrel = adddynrel - ld.Thearch.Adddynsym = adddynsym ld.Thearch.Archinit = archinit ld.Thearch.Archreloc = archreloc ld.Thearch.Archrelocvariant = archrelocvariant diff --git a/src/cmd/6l/asm.go b/src/cmd/6l/asm.go index 9b471a04ac..5520a5acf1 100644 --- a/src/cmd/6l/asm.go +++ b/src/cmd/6l/asm.go @@ -274,7 +274,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) { break } if ld.Iself { - adddynsym(ld.Ctxt, targ) + ld.Adddynsym(ld.Ctxt, targ) rela := ld.Linklookup(ld.Ctxt, ".rela", 0) ld.Addaddrplus(ld.Ctxt, rela, s, int64(r.Off)) if r.Siz == 8 { @@ -298,7 +298,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) { // just in case the C code assigns to the variable, // and of course it only works for single pointers, // but we only need to support cgo and that's all it needs. - adddynsym(ld.Ctxt, targ) + ld.Adddynsym(ld.Ctxt, targ) got := ld.Linklookup(ld.Ctxt, ".got", 0) s.Type = got.Type | obj.SSUB @@ -526,7 +526,7 @@ func addpltsym(s *ld.LSym) { return } - adddynsym(ld.Ctxt, s) + ld.Adddynsym(ld.Ctxt, s) if ld.Iself { plt := ld.Linklookup(ld.Ctxt, ".plt", 0) @@ -594,7 +594,7 @@ func addgotsym(s *ld.LSym) { return } - adddynsym(ld.Ctxt, s) + ld.Adddynsym(ld.Ctxt, s) got := ld.Linklookup(ld.Ctxt, ".got", 0) s.Got = int32(got.Size) ld.Adduint64(ld.Ctxt, got, 0) @@ -611,62 +611,6 @@ func addgotsym(s *ld.LSym) { } } -func adddynsym(ctxt *ld.Link, s *ld.LSym) { - if s.Dynid >= 0 { - return - } - - if ld.Iself { - s.Dynid = int32(ld.Nelfsym) - ld.Nelfsym++ - - d := ld.Linklookup(ctxt, ".dynsym", 0) - - name := s.Extname - ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name))) - - /* type */ - t := ld.STB_GLOBAL << 4 - - if s.Cgoexport != 0 && s.Type&obj.SMASK == obj.STEXT { - t |= ld.STT_FUNC - } else { - t |= ld.STT_OBJECT - } - ld.Adduint8(ctxt, d, uint8(t)) - - /* reserved */ - ld.Adduint8(ctxt, d, 0) - - /* section where symbol is defined */ - if s.Type == obj.SDYNIMPORT { - ld.Adduint16(ctxt, d, ld.SHN_UNDEF) - } else { - ld.Adduint16(ctxt, d, 1) - } - - /* value */ - if s.Type == obj.SDYNIMPORT { - ld.Adduint64(ctxt, d, 0) - } else { - ld.Addaddr(ctxt, d, s) - } - - /* size of object */ - ld.Adduint64(ctxt, d, uint64(s.Size)) - - if s.Cgoexport&ld.CgoExportDynamic == 0 && s.Dynimplib != "" && !ld.Seenlib[s.Dynimplib] { - ld.Elfwritedynent(ld.Linklookup(ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), s.Dynimplib))) - } - } else if ld.HEADTYPE == obj.Hdarwin { - ld.Diag("adddynsym: missed symbol %s (%s)", s.Name, s.Extname) - } else if ld.HEADTYPE == obj.Hwindows { - } else // already taken care of - { - ld.Diag("adddynsym: unsupported binary format") - } -} - func asmb() { if ld.Debug['v'] != 0 { fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime()) diff --git a/src/cmd/6l/obj.go b/src/cmd/6l/obj.go index 38ac0783b6..1dc9e02a8b 100644 --- a/src/cmd/6l/obj.go +++ b/src/cmd/6l/obj.go @@ -62,7 +62,6 @@ func linkarchinit() { ld.Thearch.Dwarfreglr = DWARFREGLR ld.Thearch.Adddynrel = adddynrel - ld.Thearch.Adddynsym = adddynsym ld.Thearch.Archinit = archinit ld.Thearch.Archreloc = archreloc ld.Thearch.Archrelocvariant = archrelocvariant diff --git a/src/cmd/7l/asm.go b/src/cmd/7l/asm.go index a0e813cfa5..3dfb8c666d 100644 --- a/src/cmd/7l/asm.go +++ b/src/cmd/7l/asm.go @@ -275,10 +275,6 @@ func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 { return -1 } -func adddynsym(ctxt *ld.Link, s *ld.LSym) { - // TODO(minux): implement when needed. -} - func asmb() { if ld.Debug['v'] != 0 { fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime()) diff --git a/src/cmd/7l/obj.go b/src/cmd/7l/obj.go index 7d0500387b..f88584b938 100644 --- a/src/cmd/7l/obj.go +++ b/src/cmd/7l/obj.go @@ -59,7 +59,6 @@ func linkarchinit() { ld.Thearch.Dwarfreglr = DWARFREGLR ld.Thearch.Adddynrel = adddynrel - ld.Thearch.Adddynsym = adddynsym ld.Thearch.Archinit = archinit ld.Thearch.Archreloc = archreloc ld.Thearch.Archrelocvariant = archrelocvariant diff --git a/src/cmd/8l/asm.go b/src/cmd/8l/asm.go index 873fd16470..a63c51f58d 100644 --- a/src/cmd/8l/asm.go +++ b/src/cmd/8l/asm.go @@ -184,7 +184,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) { break } if ld.Iself { - adddynsym(ld.Ctxt, targ) + ld.Adddynsym(ld.Ctxt, targ) rel := ld.Linklookup(ld.Ctxt, ".rel", 0) ld.Addaddrplus(ld.Ctxt, rel, s, int64(r.Off)) ld.Adduint32(ld.Ctxt, rel, ld.ELF32_R_INFO(uint32(targ.Dynid), ld.R_386_32)) @@ -204,7 +204,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) { // just in case the C code assigns to the variable, // and of course it only works for single pointers, // but we only need to support cgo and that's all it needs. - adddynsym(ld.Ctxt, targ) + ld.Adddynsym(ld.Ctxt, targ) got := ld.Linklookup(ld.Ctxt, ".got", 0) s.Type = got.Type | obj.SSUB @@ -402,7 +402,7 @@ func addpltsym(ctxt *ld.Link, s *ld.LSym) { return } - adddynsym(ctxt, s) + ld.Adddynsym(ctxt, s) if ld.Iself { plt := ld.Linklookup(ctxt, ".plt", 0) @@ -462,7 +462,7 @@ func addgotsym(ctxt *ld.Link, s *ld.LSym) { return } - adddynsym(ctxt, s) + ld.Adddynsym(ctxt, s) got := ld.Linklookup(ctxt, ".got", 0) s.Got = int32(got.Size) ld.Adduint32(ctxt, got, 0) @@ -478,58 +478,6 @@ func addgotsym(ctxt *ld.Link, s *ld.LSym) { } } -func adddynsym(ctxt *ld.Link, s *ld.LSym) { - if s.Dynid >= 0 { - return - } - - if ld.Iself { - s.Dynid = int32(ld.Nelfsym) - ld.Nelfsym++ - - d := ld.Linklookup(ctxt, ".dynsym", 0) - - /* name */ - name := s.Extname - - ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name))) - - /* value */ - if s.Type == obj.SDYNIMPORT { - ld.Adduint32(ctxt, d, 0) - } else { - ld.Addaddr(ctxt, d, s) - } - - /* size */ - ld.Adduint32(ctxt, d, 0) - - /* type */ - t := ld.STB_GLOBAL << 4 - - if s.Cgoexport != 0 && s.Type&obj.SMASK == obj.STEXT { - t |= ld.STT_FUNC - } else { - t |= ld.STT_OBJECT - } - ld.Adduint8(ctxt, d, uint8(t)) - ld.Adduint8(ctxt, d, 0) - - /* shndx */ - if s.Type == obj.SDYNIMPORT { - ld.Adduint16(ctxt, d, ld.SHN_UNDEF) - } else { - ld.Adduint16(ctxt, d, 1) - } - } else if ld.HEADTYPE == obj.Hdarwin { - ld.Diag("adddynsym: missed symbol %s (%s)", s.Name, s.Extname) - } else if ld.HEADTYPE == obj.Hwindows { - } else // already taken care of - { - ld.Diag("adddynsym: unsupported binary format") - } -} - func asmb() { if ld.Debug['v'] != 0 { fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime()) diff --git a/src/cmd/8l/obj.go b/src/cmd/8l/obj.go index 9bbaa7ee1b..bea0d03cfe 100644 --- a/src/cmd/8l/obj.go +++ b/src/cmd/8l/obj.go @@ -59,7 +59,6 @@ func linkarchinit() { ld.Thearch.Dwarfreglr = DWARFREGLR ld.Thearch.Adddynrel = adddynrel - ld.Thearch.Adddynsym = adddynsym ld.Thearch.Archinit = archinit ld.Thearch.Archreloc = archreloc ld.Thearch.Archrelocvariant = archrelocvariant diff --git a/src/cmd/9l/asm.go b/src/cmd/9l/asm.go index 702ba2bb7c..45aa3f84c2 100644 --- a/src/cmd/9l/asm.go +++ b/src/cmd/9l/asm.go @@ -222,7 +222,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) { r.Type = obj.R_ADDR if targ.Type == obj.SDYNIMPORT { // These happen in .toc sections - adddynsym(ld.Ctxt, targ) + ld.Adddynsym(ld.Ctxt, targ) rela := ld.Linklookup(ld.Ctxt, ".rela", 0) ld.Addaddrplus(ld.Ctxt, rela, s, int64(r.Off)) @@ -502,7 +502,7 @@ func addpltsym(ctxt *ld.Link, s *ld.LSym) { return } - adddynsym(ctxt, s) + ld.Adddynsym(ctxt, s) if ld.Iself { plt := ld.Linklookup(ctxt, ".plt", 0) @@ -604,54 +604,6 @@ func ensureglinkresolver() *ld.LSym { return glink } -func adddynsym(ctxt *ld.Link, s *ld.LSym) { - if s.Dynid >= 0 { - return - } - - if ld.Iself { - s.Dynid = int32(ld.Nelfsym) - ld.Nelfsym++ - - d := ld.Linklookup(ctxt, ".dynsym", 0) - - name := s.Extname - ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name))) - - /* type */ - t := ld.STB_GLOBAL << 4 - - if s.Cgoexport != 0 && s.Type&obj.SMASK == obj.STEXT { - t |= ld.STT_FUNC - } else { - t |= ld.STT_OBJECT - } - ld.Adduint8(ctxt, d, uint8(t)) - - /* reserved */ - ld.Adduint8(ctxt, d, 0) - - /* section where symbol is defined */ - if s.Type == obj.SDYNIMPORT { - ld.Adduint16(ctxt, d, ld.SHN_UNDEF) - } else { - ld.Adduint16(ctxt, d, 1) - } - - /* value */ - if s.Type == obj.SDYNIMPORT { - ld.Adduint64(ctxt, d, 0) - } else { - ld.Addaddr(ctxt, d, s) - } - - /* size of object */ - ld.Adduint64(ctxt, d, uint64(s.Size)) - } else { - ld.Diag("adddynsym: unsupported binary format") - } -} - func asmb() { if ld.Debug['v'] != 0 { fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime()) diff --git a/src/cmd/9l/obj.go b/src/cmd/9l/obj.go index f584ca43cd..011f290298 100644 --- a/src/cmd/9l/obj.go +++ b/src/cmd/9l/obj.go @@ -63,7 +63,6 @@ func linkarchinit() { ld.Thearch.Dwarfreglr = DWARFREGLR ld.Thearch.Adddynrel = adddynrel - ld.Thearch.Adddynsym = adddynsym ld.Thearch.Archinit = archinit ld.Thearch.Archreloc = archreloc ld.Thearch.Archrelocvariant = archrelocvariant diff --git a/src/cmd/internal/ld/elf.go b/src/cmd/internal/ld/elf.go index 5c17b2da6f..b73a75b59b 100644 --- a/src/cmd/internal/ld/elf.go +++ b/src/cmd/internal/ld/elf.go @@ -2349,6 +2349,93 @@ elfobj: } } +func Elfadddynsym(ctxt *Link, s *LSym) { + if elf64 { + s.Dynid = int32(Nelfsym) + Nelfsym++ + + d := Linklookup(ctxt, ".dynsym", 0) + + name := s.Extname + Adduint32(ctxt, d, uint32(Addstring(Linklookup(ctxt, ".dynstr", 0), name))) + + /* type */ + t := STB_GLOBAL << 4 + + if s.Cgoexport != 0 && s.Type&obj.SMASK == obj.STEXT { + t |= STT_FUNC + } else { + t |= STT_OBJECT + } + Adduint8(ctxt, d, uint8(t)) + + /* reserved */ + Adduint8(ctxt, d, 0) + + /* section where symbol is defined */ + if s.Type == obj.SDYNIMPORT { + Adduint16(ctxt, d, SHN_UNDEF) + } else { + Adduint16(ctxt, d, 1) + } + + /* value */ + if s.Type == obj.SDYNIMPORT { + Adduint64(ctxt, d, 0) + } else { + Addaddr(ctxt, d, s) + } + + /* size of object */ + Adduint64(ctxt, d, uint64(s.Size)) + + if Thearch.Thechar == '6' && s.Cgoexport&CgoExportDynamic == 0 && s.Dynimplib != "" && !seenlib[s.Dynimplib] { + Elfwritedynent(Linklookup(ctxt, ".dynamic", 0), DT_NEEDED, uint64(Addstring(Linklookup(ctxt, ".dynstr", 0), s.Dynimplib))) + } + } else { + s.Dynid = int32(Nelfsym) + Nelfsym++ + + d := Linklookup(ctxt, ".dynsym", 0) + + /* name */ + name := s.Extname + + Adduint32(ctxt, d, uint32(Addstring(Linklookup(ctxt, ".dynstr", 0), name))) + + /* value */ + if s.Type == obj.SDYNIMPORT { + Adduint32(ctxt, d, 0) + } else { + Addaddr(ctxt, d, s) + } + + /* size */ + Adduint32(ctxt, d, 0) + + /* type */ + t := STB_GLOBAL << 4 + + // TODO(mwhudson): presumably the behaviour should actually be the same on both arm and 386. + if Thearch.Thechar == '8' && s.Cgoexport != 0 && s.Type&obj.SMASK == obj.STEXT { + t |= STT_FUNC + } else if Thearch.Thechar == '5' && s.Cgoexport&CgoExportDynamic != 0 && s.Type&obj.SMASK == obj.STEXT { + t |= STT_FUNC + } else { + t |= STT_OBJECT + } + Adduint8(ctxt, d, uint8(t)) + Adduint8(ctxt, d, 0) + + /* shndx */ + if s.Type == obj.SDYNIMPORT { + Adduint16(ctxt, d, SHN_UNDEF) + } else { + Adduint16(ctxt, d, 1) + } + } +} + func ELF32_R_SYM(info uint32) uint32 { return info >> 8 } diff --git a/src/cmd/internal/ld/go.go b/src/cmd/internal/ld/go.go index c1defeb8a2..a5b09202e8 100644 --- a/src/cmd/internal/ld/go.go +++ b/src/cmd/internal/ld/go.go @@ -534,13 +534,13 @@ err: nerrors++ } -var Seenlib = make(map[string]bool) +var seenlib = make(map[string]bool) func adddynlib(lib string) { - if Seenlib[lib] { + if seenlib[lib] { return } - Seenlib[lib] = true + seenlib[lib] = true if Iself { s := Linklookup(Ctxt, ".dynstr", 0) @@ -555,6 +555,22 @@ func adddynlib(lib string) { } } +func Adddynsym(ctxt *Link, s *LSym) { + if s.Dynid >= 0 { + return + } + + if Iself { + Elfadddynsym(ctxt, s) + } else if HEADTYPE == obj.Hdarwin { + Diag("adddynsym: missed symbol %s (%s)", s.Name, s.Extname) + } else if HEADTYPE == obj.Hwindows { + // already taken care of + } else { + Diag("adddynsym: unsupported binary format") + } +} + var markq *LSym var emarkq *LSym @@ -759,7 +775,7 @@ func addexport() { } for i := 0; i < len(dynexp); i++ { - Thearch.Adddynsym(Ctxt, dynexp[i]) + Adddynsym(Ctxt, dynexp[i]) } } diff --git a/src/cmd/internal/ld/lib.go b/src/cmd/internal/ld/lib.go index 5ab5f653f3..cc0840c04a 100644 --- a/src/cmd/internal/ld/lib.go +++ b/src/cmd/internal/ld/lib.go @@ -95,7 +95,6 @@ type Arch struct { Dragonflydynld string Solarisdynld string Adddynrel func(*LSym, *Reloc) - Adddynsym func(*Link, *LSym) Archinit func() Archreloc func(*Reloc, *LSym, *int64) int Archrelocvariant func(*Reloc, *LSym, int64) int64 From ddc4c146a46cd8ae3a4f1f9b7f0cd14f4bb2aca4 Mon Sep 17 00:00:00 2001 From: Michael Hudson-Doyle Date: Tue, 12 May 2015 16:07:05 +1200 Subject: [PATCH 120/232] cmd/internal/ld: prevent creation of .dynamic and .dynsym symbols when externally linking This allows the removal of a fudge in data.go. We have to defer the calls to adddynlib on non-Darwin until after we have decided whether we are externally or internally linking. The Macho/ELF separation could do with some cleaning up, but: code freeze. Fixing this once rather than per-arch is what inspired the previous CLs. Change-Id: I0166f7078a045dc09827745479211247466c0c54 Reviewed-on: https://go-review.googlesource.com/10002 Run-TryBot: Michael Hudson-Doyle TryBot-Result: Gobot Gobot Reviewed-by: Russ Cox --- src/cmd/internal/ld/data.go | 8 +------- src/cmd/internal/ld/go.go | 19 ++++++++++++------- src/cmd/internal/ld/lib.go | 1 + 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/cmd/internal/ld/data.go b/src/cmd/internal/ld/data.go index b0157547c3..b65b667f98 100644 --- a/src/cmd/internal/ld/data.go +++ b/src/cmd/internal/ld/data.go @@ -1127,13 +1127,7 @@ func proggenaddsym(g *ProgGen, s *LSym) { proggenskip(g, g.pos, s.Value-g.pos) g.pos = s.Value - // The test for names beginning with . here is meant - // to keep .dynamic and .dynsym from turning up as - // conservative symbols. They should be marked SELFSECT - // and not SDATA, but sometimes that doesn't happen. - // Leave debugging the SDATA issue for the Go rewrite. - - if s.Gotype == nil && s.Size >= int64(Thearch.Ptrsize) && s.Name[0] != '.' { + if s.Gotype == nil && s.Size >= int64(Thearch.Ptrsize) { Diag("missing Go type information for global symbol: %s size %d", s.Name, int(s.Size)) return } diff --git a/src/cmd/internal/ld/go.go b/src/cmd/internal/ld/go.go index a5b09202e8..875b8d2e17 100644 --- a/src/cmd/internal/ld/go.go +++ b/src/cmd/internal/ld/go.go @@ -416,7 +416,11 @@ func loadcgo(file string, pkg string, p string) { // to force a link of foo.so. havedynamic = 1 - adddynlib(lib) + if HEADTYPE == obj.Hdarwin { + Machoadddynlib(lib) + } else { + dynlib = append(dynlib, lib) + } continue } @@ -537,7 +541,7 @@ err: var seenlib = make(map[string]bool) func adddynlib(lib string) { - if seenlib[lib] { + if seenlib[lib] || Linkmode == LinkExternal { return } seenlib[lib] = true @@ -548,15 +552,13 @@ func adddynlib(lib string) { Addstring(s, "") } Elfwritedynent(Linklookup(Ctxt, ".dynamic", 0), DT_NEEDED, uint64(Addstring(s, lib))) - } else if HEADTYPE == obj.Hdarwin { - Machoadddynlib(lib) } else { Diag("adddynlib: unsupported binary format") } } func Adddynsym(ctxt *Link, s *LSym) { - if s.Dynid >= 0 { + if s.Dynid >= 0 || Linkmode == LinkExternal { return } @@ -774,8 +776,11 @@ func addexport() { return } - for i := 0; i < len(dynexp); i++ { - Adddynsym(Ctxt, dynexp[i]) + for _, exp := range dynexp { + Adddynsym(Ctxt, exp) + } + for _, lib := range dynlib { + adddynlib(lib) } } diff --git a/src/cmd/internal/ld/lib.go b/src/cmd/internal/ld/lib.go index cc0840c04a..a0d03ef22d 100644 --- a/src/cmd/internal/ld/lib.go +++ b/src/cmd/internal/ld/lib.go @@ -178,6 +178,7 @@ var ( Thelinkarch *LinkArch outfile string dynexp []*LSym + dynlib []string ldflag []string havedynamic int Funcalign int From d820d5f3ab49bec0fb5f8a177ed48b99502a0be1 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 15 May 2015 16:05:52 -0400 Subject: [PATCH 121/232] runtime: make mapzero not crash on arm Change-Id: I40e8a4a2e62253233b66f6a2e61e222437292c31 Reviewed-on: https://go-review.googlesource.com/10151 Reviewed-by: Minux Ma --- src/runtime/hashmap.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/runtime/hashmap.go b/src/runtime/hashmap.go index 2b3af301b3..b199330a1e 100644 --- a/src/runtime/hashmap.go +++ b/src/runtime/hashmap.go @@ -1008,6 +1008,18 @@ var zerotiny [1024]byte // Types allocated by package reflect are in writable memory and // start out with zero set to nil; we initialize those on demand. func mapzero(t *_type) { + // On ARM, atomicloadp is implemented as xadd(p, 0), + // so we cannot use atomicloadp on read-only memory. + // Check whether the pointer is in the heap; if not, it's not writable + // so the zero value must already be set. + if GOARCH == "arm" && !inheap(uintptr(unsafe.Pointer(t))) { + if t.zero == nil { + print("runtime: map element ", *t._string, " missing zero value\n") + throw("mapzero") + } + return + } + // Already done? // Check without lock, so must use atomicload to sync with atomicstore in allocation case below. if atomicloadp(unsafe.Pointer(&t.zero)) != nil { From ebe733cb40c49148b2fe53d27ce9b1f76993591e Mon Sep 17 00:00:00 2001 From: Didier Spezia Date: Thu, 14 May 2015 16:44:58 +0000 Subject: [PATCH 122/232] text/template: fix race condition on function maps The Template objects are supposed to be goroutine-safe once they have been parsed. This includes the text and html ones. For html/template, the escape mechanism is triggered at execution time. It may alter the internal structures of the template, so a mutex protects them against concurrent accesses. The text/template package is free of any synchronization primitive. A race condition may occur when nested templates are escaped: the escape algorithm alters the function maps of the associated text templates, while a concurrent template execution may access the function maps in read mode. The less invasive fix I have found is to introduce a RWMutex in text/template to protect the function maps. This is unfortunate but it should be effective. Fixes #9945 Change-Id: I1edb73c0ed0f1fcddd2f1516230b548b92ab1269 Reviewed-on: https://go-review.googlesource.com/10101 Reviewed-by: Rob Pike --- src/text/template/funcs.go | 2 ++ src/text/template/template.go | 12 ++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/text/template/funcs.go b/src/text/template/funcs.go index cdd187bda2..ccd0dfc80d 100644 --- a/src/text/template/funcs.go +++ b/src/text/template/funcs.go @@ -92,6 +92,8 @@ func goodFunc(typ reflect.Type) bool { // findFunction looks for a function in the template, and global map. func findFunction(name string, tmpl *Template) (reflect.Value, bool) { if tmpl != nil && tmpl.common != nil { + tmpl.muFuncs.RLock() + defer tmpl.muFuncs.RUnlock() if fn := tmpl.execFuncs[name]; fn.IsValid() { return fn, true } diff --git a/src/text/template/template.go b/src/text/template/template.go index 8611faad9f..a7c5c8cd2c 100644 --- a/src/text/template/template.go +++ b/src/text/template/template.go @@ -7,18 +7,20 @@ package template import ( "fmt" "reflect" + "sync" "text/template/parse" ) // common holds the information shared by related templates. type common struct { - tmpl map[string]*Template + tmpl map[string]*Template + option option // We use two maps, one for parsing and one for execution. // This separation makes the API cleaner since it doesn't // expose reflection to the client. + muFuncs sync.RWMutex // protects parseFuncs and execFuncs parseFuncs FuncMap execFuncs map[string]reflect.Value - option option } // Template is the representation of a parsed template. The *parse.Tree @@ -84,6 +86,8 @@ func (t *Template) Clone() (*Template, error) { tmpl := v.copy(nt.common) nt.tmpl[k] = tmpl } + t.muFuncs.RLock() + defer t.muFuncs.RUnlock() for k, v := range t.parseFuncs { nt.parseFuncs[k] = v } @@ -146,6 +150,8 @@ func (t *Template) Delims(left, right string) *Template { // value is the template, so calls can be chained. func (t *Template) Funcs(funcMap FuncMap) *Template { t.init() + t.muFuncs.Lock() + defer t.muFuncs.Unlock() addValueFuncs(t.execFuncs, funcMap) addFuncs(t.parseFuncs, funcMap) return t @@ -169,7 +175,9 @@ func (t *Template) Lookup(name string) *Template { // can contain text other than space, comments, and template definitions.) func (t *Template) Parse(text string) (*Template, error) { t.init() + t.muFuncs.RLock() trees, err := parse.Parse(t.name, text, t.leftDelim, t.rightDelim, t.parseFuncs, builtins) + t.muFuncs.RUnlock() if err != nil { return nil, err } From 512f75e8dfc7653c873971480c23ba308307b85a Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 8 May 2015 01:43:18 -0400 Subject: [PATCH 123/232] runtime: replace GC programs with simpler encoding, faster decoder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Small types record the location of pointers in their memory layout by using a simple bitmap. In Go 1.4 the bitmap held 4-bit entries, and in Go 1.5 the bitmap holds 1-bit entries, but in both cases using a bitmap for a large type containing arrays does not make sense: if someone refers to the type [1<<28]*byte in a program in such a way that the type information makes it into the binary, it would be a waste of space to write a 128 MB (for 4-bit entries) or even 32 MB (for 1-bit entries) bitmap full of 1s into the binary or even to keep one in memory during the execution of the program. For large types containing arrays, it is much more compact to describe the locations of pointers using a notation that can express repetition than to lay out a bitmap of pointers. Go 1.4 included such a notation, called ``GC programs'' but it was complex, required recursion during decoding, and was generally slow. Dmitriy measured the execution of these programs writing directly to the heap bitmap as being 7x slower than copying from a preunrolled 4-bit mask (and frankly that code was not terribly fast either). For some tests, unrollgcprog1 was seen costing as much as 3x more than the rest of malloc combined. This CL introduces a different form for the GC programs. They use a simple Lempel-Ziv-style encoding of the 1-bit pointer information, in which the only operations are (1) emit the following n bits and (2) repeat the last n bits c more times. This encoding can be generated directly from the Go type information (using repetition only for arrays or large runs of non-pointer data) and it can be decoded very efficiently. In particular the decoding requires little state and no recursion, so that the entire decoding can run without any memory accesses other than the reads of the encoding and the writes of the decoded form to the heap bitmap. For recursive types like arrays of arrays of arrays, the inner instructions are only executed once, not n times, so that large repetitions run at full speed. (In contrast, large repetitions in the old programs repeated the individual bit-level layout of the inner data over and over.) The result is as much as 25x faster decoding compared to the old form. Because the old decoder was so slow, Go 1.4 had three (or so) cases for how to set the heap bitmap bits for an allocation of a given type: (1) If the type had an even number of words up to 32 words, then the 4-bit pointer mask for the type fit in no more than 16 bytes; store the 4-bit pointer mask directly in the binary and copy from it. (1b) If the type had an odd number of words up to 15 words, then the 4-bit pointer mask for the type, doubled to end on a byte boundary, fit in no more than 16 bytes; store that doubled mask directly in the binary and copy from it. (2) If the type had an even number of words up to 128 words, or an odd number of words up to 63 words (again due to doubling), then the 4-bit pointer mask would fit in a 64-byte unrolled mask. Store a GC program in the binary, but leave space in the BSS for the unrolled mask. Execute the GC program to construct the mask the first time it is needed, and thereafter copy from the mask. (3) Otherwise, store a GC program and execute it to write directly to the heap bitmap each time an object of that type is allocated. (This is the case that was 7x slower than the other two.) Because the new pointer masks store 1-bit entries instead of 4-bit entries and because using the decoder no longer carries a significant overhead, after this CL (that is, for Go 1.5) there are only two cases: (1) If the type is 128 words or less (no condition about odd or even), store the 1-bit pointer mask directly in the binary and use it to initialize the heap bitmap during malloc. (Implemented in CL 9702.) (2) There is no case 2 anymore. (3) Otherwise, store a GC program and execute it to write directly to the heap bitmap each time an object of that type is allocated. Executing the GC program directly into the heap bitmap (case (3) above) was disabled for the Go 1.5 dev cycle, both to avoid needing to use GC programs for typedmemmove and to avoid updating that code as the heap bitmap format changed. Typedmemmove no longer uses this type information; as of CL 9886 it uses the heap bitmap directly. Now that the heap bitmap format is stable, we reintroduce GC programs and their space savings. Benchmarks for heapBitsSetType, before this CL vs this CL: name old mean new mean delta SetTypePtr 7.59ns × (0.99,1.02) 5.16ns × (1.00,1.00) -32.05% (p=0.000) SetTypePtr8 21.0ns × (0.98,1.05) 21.4ns × (1.00,1.00) ~ (p=0.179) SetTypePtr16 24.1ns × (0.99,1.01) 24.6ns × (1.00,1.00) +2.41% (p=0.001) SetTypePtr32 31.2ns × (0.99,1.01) 32.4ns × (0.99,1.02) +3.72% (p=0.001) SetTypePtr64 45.2ns × (1.00,1.00) 47.2ns × (1.00,1.00) +4.42% (p=0.000) SetTypePtr126 75.8ns × (0.99,1.01) 79.1ns × (1.00,1.00) +4.25% (p=0.000) SetTypePtr128 74.3ns × (0.99,1.01) 77.6ns × (1.00,1.01) +4.55% (p=0.000) SetTypePtrSlice 726ns × (1.00,1.01) 712ns × (1.00,1.00) -1.95% (p=0.001) SetTypeNode1 20.0ns × (0.99,1.01) 20.7ns × (1.00,1.00) +3.71% (p=0.000) SetTypeNode1Slice 112ns × (1.00,1.00) 113ns × (0.99,1.00) ~ (p=0.070) SetTypeNode8 23.9ns × (1.00,1.00) 24.7ns × (1.00,1.01) +3.18% (p=0.000) SetTypeNode8Slice 294ns × (0.99,1.02) 287ns × (0.99,1.01) -2.38% (p=0.015) SetTypeNode64 52.8ns × (0.99,1.03) 51.8ns × (0.99,1.01) ~ (p=0.069) SetTypeNode64Slice 1.13µs × (0.99,1.05) 1.14µs × (0.99,1.00) ~ (p=0.767) SetTypeNode64Dead 36.0ns × (1.00,1.01) 32.5ns × (0.99,1.00) -9.67% (p=0.000) SetTypeNode64DeadSlice 1.43µs × (0.99,1.01) 1.40µs × (1.00,1.00) -2.39% (p=0.001) SetTypeNode124 75.7ns × (1.00,1.01) 79.0ns × (1.00,1.00) +4.44% (p=0.000) SetTypeNode124Slice 1.94µs × (1.00,1.01) 2.04µs × (0.99,1.01) +4.98% (p=0.000) SetTypeNode126 75.4ns × (1.00,1.01) 77.7ns × (0.99,1.01) +3.11% (p=0.000) SetTypeNode126Slice 1.95µs × (0.99,1.01) 2.03µs × (1.00,1.00) +3.74% (p=0.000) SetTypeNode128 85.4ns × (0.99,1.01) 122.0ns × (1.00,1.00) +42.89% (p=0.000) SetTypeNode128Slice 2.20µs × (1.00,1.01) 2.36µs × (0.98,1.02) +7.48% (p=0.001) SetTypeNode130 83.3ns × (1.00,1.00) 123.0ns × (1.00,1.00) +47.61% (p=0.000) SetTypeNode130Slice 2.30µs × (0.99,1.01) 2.40µs × (0.98,1.01) +4.37% (p=0.000) SetTypeNode1024 498ns × (1.00,1.00) 537ns × (1.00,1.00) +7.96% (p=0.000) SetTypeNode1024Slice 15.5µs × (0.99,1.01) 17.8µs × (1.00,1.00) +15.27% (p=0.000) The above compares always using a cached pointer mask (and the corresponding waste of memory) against using the programs directly. Some slowdown is expected, in exchange for having a better general algorithm. The GC programs kick in for SetTypeNode128, SetTypeNode130, SetTypeNode1024, along with the slice variants of those. It is possible that the cutoff of 128 words (bits) should be raised in a followup CL, but even with this low cutoff the GC programs are faster than Go 1.4's "fast path" non-GC program case. Benchmarks for heapBitsSetType, Go 1.4 vs this CL: name old mean new mean delta SetTypePtr 6.89ns × (1.00,1.00) 5.17ns × (1.00,1.00) -25.02% (p=0.000) SetTypePtr8 25.8ns × (0.97,1.05) 21.5ns × (1.00,1.00) -16.70% (p=0.000) SetTypePtr16 39.8ns × (0.97,1.02) 24.7ns × (0.99,1.01) -37.81% (p=0.000) SetTypePtr32 68.8ns × (0.98,1.01) 32.2ns × (1.00,1.01) -53.18% (p=0.000) SetTypePtr64 130ns × (1.00,1.00) 47ns × (1.00,1.00) -63.67% (p=0.000) SetTypePtr126 241ns × (0.99,1.01) 79ns × (1.00,1.01) -67.25% (p=0.000) SetTypePtr128 2.07µs × (1.00,1.00) 0.08µs × (1.00,1.00) -96.27% (p=0.000) SetTypePtrSlice 1.05µs × (0.99,1.01) 0.72µs × (0.99,1.02) -31.70% (p=0.000) SetTypeNode1 16.0ns × (0.99,1.01) 20.8ns × (0.99,1.03) +29.91% (p=0.000) SetTypeNode1Slice 184ns × (0.99,1.01) 112ns × (0.99,1.01) -39.26% (p=0.000) SetTypeNode8 29.5ns × (0.97,1.02) 24.6ns × (1.00,1.00) -16.50% (p=0.000) SetTypeNode8Slice 624ns × (0.98,1.02) 285ns × (1.00,1.00) -54.31% (p=0.000) SetTypeNode64 135ns × (0.96,1.08) 52ns × (0.99,1.02) -61.32% (p=0.000) SetTypeNode64Slice 3.83µs × (1.00,1.00) 1.14µs × (0.99,1.01) -70.16% (p=0.000) SetTypeNode64Dead 134ns × (0.99,1.01) 32ns × (1.00,1.01) -75.74% (p=0.000) SetTypeNode64DeadSlice 3.83µs × (0.99,1.00) 1.40µs × (1.00,1.01) -63.42% (p=0.000) SetTypeNode124 240ns × (0.99,1.01) 79ns × (1.00,1.01) -67.05% (p=0.000) SetTypeNode124Slice 7.27µs × (1.00,1.00) 2.04µs × (1.00,1.00) -71.95% (p=0.000) SetTypeNode126 2.06µs × (0.99,1.01) 0.08µs × (0.99,1.01) -96.23% (p=0.000) SetTypeNode126Slice 64.4µs × (1.00,1.00) 2.0µs × (1.00,1.00) -96.85% (p=0.000) SetTypeNode128 2.09µs × (1.00,1.01) 0.12µs × (1.00,1.00) -94.15% (p=0.000) SetTypeNode128Slice 65.4µs × (1.00,1.00) 2.4µs × (0.99,1.03) -96.39% (p=0.000) SetTypeNode130 2.11µs × (1.00,1.00) 0.12µs × (1.00,1.00) -94.18% (p=0.000) SetTypeNode130Slice 66.3µs × (1.00,1.00) 2.4µs × (0.97,1.08) -96.34% (p=0.000) SetTypeNode1024 16.0µs × (1.00,1.01) 0.5µs × (1.00,1.00) -96.65% (p=0.000) SetTypeNode1024Slice 512µs × (1.00,1.00) 18µs × (0.98,1.04) -96.45% (p=0.000) SetTypeNode124 uses a 124 data + 2 ptr = 126-word allocation. Both Go 1.4 and this CL are using pointer bitmaps for this case, so that's an overall 3x speedup for using pointer bitmaps. SetTypeNode128 uses a 128 data + 2 ptr = 130-word allocation. Both Go 1.4 and this CL are running the GC program for this case, so that's an overall 17x speedup when using GC programs (and I've seen >20x on other systems). Comparing Go 1.4's SetTypeNode124 (pointer bitmap) against this CL's SetTypeNode128 (GC program), the slow path in the code in this CL is 2x faster than the fast path in Go 1.4. The Go 1 benchmarks are basically unaffected compared to just before this CL. Go 1 benchmarks, before this CL vs this CL: name old mean new mean delta BinaryTree17 5.87s × (0.97,1.04) 5.91s × (0.96,1.04) ~ (p=0.306) Fannkuch11 4.38s × (1.00,1.00) 4.37s × (1.00,1.01) -0.22% (p=0.006) FmtFprintfEmpty 90.7ns × (0.97,1.10) 89.3ns × (0.96,1.09) ~ (p=0.280) FmtFprintfString 282ns × (0.98,1.04) 287ns × (0.98,1.07) +1.72% (p=0.039) FmtFprintfInt 269ns × (0.99,1.03) 282ns × (0.97,1.04) +4.87% (p=0.000) FmtFprintfIntInt 478ns × (0.99,1.02) 481ns × (0.99,1.02) +0.61% (p=0.048) FmtFprintfPrefixedInt 399ns × (0.98,1.03) 400ns × (0.98,1.05) ~ (p=0.533) FmtFprintfFloat 563ns × (0.99,1.01) 570ns × (1.00,1.01) +1.37% (p=0.000) FmtManyArgs 1.89µs × (0.99,1.01) 1.92µs × (0.99,1.02) +1.88% (p=0.000) GobDecode 15.2ms × (0.99,1.01) 15.2ms × (0.98,1.05) ~ (p=0.609) GobEncode 11.6ms × (0.98,1.03) 11.9ms × (0.98,1.04) +2.17% (p=0.000) Gzip 648ms × (0.99,1.01) 648ms × (1.00,1.01) ~ (p=0.835) Gunzip 142ms × (1.00,1.00) 143ms × (1.00,1.01) ~ (p=0.169) HTTPClientServer 90.5µs × (0.98,1.03) 91.5µs × (0.98,1.04) +1.04% (p=0.045) JSONEncode 31.5ms × (0.98,1.03) 31.4ms × (0.98,1.03) ~ (p=0.549) JSONDecode 111ms × (0.99,1.01) 107ms × (0.99,1.01) -3.21% (p=0.000) Mandelbrot200 6.01ms × (1.00,1.00) 6.01ms × (1.00,1.00) ~ (p=0.878) GoParse 6.54ms × (0.99,1.02) 6.61ms × (0.99,1.03) +1.08% (p=0.004) RegexpMatchEasy0_32 160ns × (1.00,1.01) 161ns × (1.00,1.00) +0.40% (p=0.000) RegexpMatchEasy0_1K 560ns × (0.99,1.01) 559ns × (0.99,1.01) ~ (p=0.088) RegexpMatchEasy1_32 138ns × (0.99,1.01) 138ns × (1.00,1.00) ~ (p=0.380) RegexpMatchEasy1_1K 877ns × (1.00,1.00) 878ns × (1.00,1.00) ~ (p=0.157) RegexpMatchMedium_32 251ns × (0.99,1.00) 251ns × (1.00,1.01) +0.28% (p=0.021) RegexpMatchMedium_1K 72.6µs × (1.00,1.00) 72.6µs × (1.00,1.00) ~ (p=0.539) RegexpMatchHard_32 3.84µs × (1.00,1.00) 3.84µs × (1.00,1.00) ~ (p=0.378) RegexpMatchHard_1K 117µs × (1.00,1.00) 117µs × (1.00,1.00) ~ (p=0.067) Revcomp 904ms × (0.99,1.02) 904ms × (0.99,1.01) ~ (p=0.943) Template 125ms × (0.99,1.02) 127ms × (0.99,1.01) +1.79% (p=0.000) TimeParse 627ns × (0.99,1.01) 622ns × (0.99,1.01) -0.88% (p=0.000) TimeFormat 655ns × (0.99,1.02) 655ns × (0.99,1.02) ~ (p=0.976) For the record, Go 1 benchmarks, Go 1.4 vs this CL: name old mean new mean delta BinaryTree17 4.61s × (0.97,1.05) 5.91s × (0.98,1.03) +28.35% (p=0.000) Fannkuch11 4.40s × (0.99,1.03) 4.41s × (0.99,1.01) ~ (p=0.212) FmtFprintfEmpty 102ns × (0.99,1.01) 84ns × (0.99,1.02) -18.38% (p=0.000) FmtFprintfString 302ns × (0.98,1.01) 303ns × (0.99,1.02) ~ (p=0.203) FmtFprintfInt 313ns × (0.97,1.05) 270ns × (0.99,1.01) -13.69% (p=0.000) FmtFprintfIntInt 524ns × (0.98,1.02) 477ns × (0.99,1.00) -8.87% (p=0.000) FmtFprintfPrefixedInt 424ns × (0.98,1.02) 386ns × (0.99,1.01) -8.96% (p=0.000) FmtFprintfFloat 652ns × (0.98,1.02) 594ns × (0.97,1.05) -8.97% (p=0.000) FmtManyArgs 2.13µs × (0.99,1.02) 1.94µs × (0.99,1.01) -8.92% (p=0.000) GobDecode 17.1ms × (0.99,1.02) 14.9ms × (0.98,1.03) -13.07% (p=0.000) GobEncode 13.5ms × (0.98,1.03) 11.5ms × (0.98,1.03) -15.25% (p=0.000) Gzip 656ms × (0.99,1.02) 647ms × (0.99,1.01) -1.29% (p=0.000) Gunzip 143ms × (0.99,1.02) 144ms × (0.99,1.01) ~ (p=0.204) HTTPClientServer 88.2µs × (0.98,1.02) 90.8µs × (0.98,1.01) +2.93% (p=0.000) JSONEncode 32.2ms × (0.98,1.02) 30.9ms × (0.97,1.04) -4.06% (p=0.001) JSONDecode 121ms × (0.98,1.02) 110ms × (0.98,1.05) -8.95% (p=0.000) Mandelbrot200 6.06ms × (0.99,1.01) 6.11ms × (0.98,1.04) ~ (p=0.184) GoParse 6.76ms × (0.97,1.04) 6.58ms × (0.98,1.05) -2.63% (p=0.003) RegexpMatchEasy0_32 195ns × (1.00,1.01) 155ns × (0.99,1.01) -20.43% (p=0.000) RegexpMatchEasy0_1K 479ns × (0.98,1.03) 535ns × (0.99,1.02) +11.59% (p=0.000) RegexpMatchEasy1_32 169ns × (0.99,1.02) 131ns × (0.99,1.03) -22.44% (p=0.000) RegexpMatchEasy1_1K 1.53µs × (0.99,1.01) 0.87µs × (0.99,1.02) -43.07% (p=0.000) RegexpMatchMedium_32 334ns × (0.99,1.01) 242ns × (0.99,1.01) -27.53% (p=0.000) RegexpMatchMedium_1K 125µs × (1.00,1.01) 72µs × (0.99,1.03) -42.53% (p=0.000) RegexpMatchHard_32 6.03µs × (0.99,1.01) 3.79µs × (0.99,1.01) -37.12% (p=0.000) RegexpMatchHard_1K 189µs × (0.99,1.02) 115µs × (0.99,1.01) -39.20% (p=0.000) Revcomp 935ms × (0.96,1.03) 926ms × (0.98,1.02) ~ (p=0.083) Template 146ms × (0.97,1.05) 119ms × (0.99,1.01) -18.37% (p=0.000) TimeParse 660ns × (0.99,1.01) 624ns × (0.99,1.02) -5.43% (p=0.000) TimeFormat 670ns × (0.98,1.02) 710ns × (1.00,1.01) +5.97% (p=0.000) This CL is a bit larger than I would like, but the compiler, linker, runtime, and package reflect all need to be in sync about the format of these programs, so there is no easy way to split this into independent changes (at least while keeping the build working at each change). Fixes #9625. Fixes #10524. Change-Id: I9e3e20d6097099d0f8532d1cb5b1af528804989a Reviewed-on: https://go-review.googlesource.com/9888 Reviewed-by: Austin Clements Run-TryBot: Russ Cox --- src/cmd/dist/buildtool.go | 1 + src/cmd/internal/gc/lex.go | 9 +- src/cmd/internal/gc/plive.go | 2 +- src/cmd/internal/gc/reflect.go | 384 ++++++--------- src/cmd/internal/gcprog/gcprog.go | 298 ++++++++++++ src/cmd/internal/ld/data.go | 191 +++----- src/cmd/internal/ld/decodesym.go | 4 +- src/cmd/internal/ld/lib.go | 2 +- src/cmd/internal/ld/link.go | 8 + src/cmd/internal/ld/objfile.go | 2 +- src/reflect/all_test.go | 135 +++++- src/reflect/export_test.go | 18 +- src/reflect/type.go | 389 ++++++++------- src/reflect/value.go | 2 +- src/runtime/mbitmap.go | 766 +++++++++++++++++++++--------- src/runtime/mgc.go | 4 +- src/runtime/symtab.go | 2 + src/runtime/traceback.go | 2 +- src/runtime/type.go | 15 +- 19 files changed, 1418 insertions(+), 816 deletions(-) create mode 100644 src/cmd/internal/gcprog/gcprog.go diff --git a/src/cmd/dist/buildtool.go b/src/cmd/dist/buildtool.go index e25367b25c..946229d827 100644 --- a/src/cmd/dist/buildtool.go +++ b/src/cmd/dist/buildtool.go @@ -39,6 +39,7 @@ var bootstrapDirs = []string{ "asm/internal/flags", "asm/internal/lex", "internal/asm", + "internal/gcprog", "internal/gc/big", "internal/gc", "internal/ld", diff --git a/src/cmd/internal/gc/lex.go b/src/cmd/internal/gc/lex.go index 92c079e154..f9211407fb 100644 --- a/src/cmd/internal/gc/lex.go +++ b/src/cmd/internal/gc/lex.go @@ -48,12 +48,13 @@ var debugtab = []struct { name string val *int }{ - {"nil", &Debug_checknil}, // print information about nil checks - {"typeassert", &Debug_typeassert}, // print information about type assertion inlining - {"disablenil", &Disable_checknil}, // disable nil checks - {"wb", &Debug_wb}, // print information about write barriers {"append", &Debug_append}, // print information about append compilation + {"disablenil", &Disable_checknil}, // disable nil checks + {"gcprog", &Debug_gcprog}, // print dump of GC programs + {"nil", &Debug_checknil}, // print information about nil checks {"slice", &Debug_slice}, // print information about slice compilation + {"typeassert", &Debug_typeassert}, // print information about type assertion inlining + {"wb", &Debug_wb}, // print information about write barriers } // Our own isdigit, isspace, isalpha, isalnum that take care diff --git a/src/cmd/internal/gc/plive.go b/src/cmd/internal/gc/plive.go index 977789f3e4..b4d0699d1f 100644 --- a/src/cmd/internal/gc/plive.go +++ b/src/cmd/internal/gc/plive.go @@ -944,7 +944,7 @@ func onebitwalktype1(t *Type, xoffset *int64, bv Bvec) { *xoffset += t.Width case TARRAY: - // The value of t->bound is -1 for slices types and >0 for + // The value of t->bound is -1 for slices types and >=0 for // for fixed array types. All other values are invalid. if t.Bound < -1 { Fatal("onebitwalktype1: invalid bound, %v", t) diff --git a/src/cmd/internal/gc/reflect.go b/src/cmd/internal/gc/reflect.go index 061b17b3ae..6c0962f258 100644 --- a/src/cmd/internal/gc/reflect.go +++ b/src/cmd/internal/gc/reflect.go @@ -5,8 +5,10 @@ package gc import ( + "cmd/internal/gcprog" "cmd/internal/obj" "fmt" + "os" ) /* @@ -771,6 +773,8 @@ func dcommontype(s *Sym, ot int, t *Type) int { // The linker magically takes the max of all the sizes. zero := Pkglookup("zerovalue", Runtimepkg) + gcsym, useGCProg, ptrdata := dgcsym(t) + // We use size 0 here so we get the pointer to the zero value, // but don't allocate space for the zero value unless we need it. // TODO: how do we get this symbol into bss? We really want @@ -787,14 +791,14 @@ func dcommontype(s *Sym, ot int, t *Type) int { // fieldAlign uint8 // kind uint8 // alg unsafe.Pointer - // gc unsafe.Pointer + // gcdata unsafe.Pointer // string *string // *extraType // ptrToThis *Type // zero unsafe.Pointer // } ot = duintptr(s, ot, uint64(t.Width)) - ot = duintptr(s, ot, uint64(typeptrdata(t))) + ot = duintptr(s, ot, uint64(ptrdata)) ot = duint32(s, ot, typehash(t)) ot = duint8(s, ot, 0) // unused @@ -811,8 +815,6 @@ func dcommontype(s *Sym, ot int, t *Type) int { ot = duint8(s, ot, t.Align) // align ot = duint8(s, ot, t.Align) // fieldAlign - gcprog := usegcprog(t) - i = kinds[t.Etype] if t.Etype == TARRAY && t.Bound < 0 { i = obj.KindSlice @@ -823,7 +825,7 @@ func dcommontype(s *Sym, ot int, t *Type) int { if isdirectiface(t) { i |= obj.KindDirectIface } - if gcprog { + if useGCProg { i |= obj.KindGCProg } ot = duint8(s, ot, uint8(i)) // kind @@ -832,48 +834,7 @@ func dcommontype(s *Sym, ot int, t *Type) int { } else { ot = dsymptr(s, ot, algsym, 0) } - - // gc - if gcprog { - var gcprog1 *Sym - var gcprog0 *Sym - gengcprog(t, &gcprog0, &gcprog1) - if gcprog0 != nil { - ot = dsymptr(s, ot, gcprog0, 0) - } else { - ot = duintptr(s, ot, 0) - } - ot = dsymptr(s, ot, gcprog1, 0) - } else { - var gcmask [16]uint8 - gengcmask(t, gcmask[:]) - x1 := uint64(0) - for i := 0; i < 8; i++ { - x1 = x1<<8 | uint64(gcmask[i]) - } - var p string - if Widthptr == 4 { - p = fmt.Sprintf("gcbits.0x%016x", x1) - } else { - x2 := uint64(0) - for i := 0; i < 8; i++ { - x2 = x2<<8 | uint64(gcmask[i+8]) - } - p = fmt.Sprintf("gcbits.0x%016x%016x", x1, x2) - } - - sbits := Pkglookup(p, Runtimepkg) - if sbits.Flags&SymUniq == 0 { - sbits.Flags |= SymUniq - for i := 0; i < 2*Widthptr; i++ { - duint8(sbits, i, gcmask[i]) - } - ggloblsym(sbits, 2*int32(Widthptr), obj.DUPOK|obj.RODATA|obj.LOCAL) - } - - ot = dsymptr(s, ot, sbits, 0) - ot = duintptr(s, ot, 0) - } + ot = dsymptr(s, ot, gcsym, 0) p := Tconv(t, obj.FmtLeft|obj.FmtUnsigned) @@ -1419,228 +1380,193 @@ func dalgsym(t *Type) *Sym { return s } -func usegcprog(t *Type) bool { - if !haspointers(t) { - return false - } - if t.Width == BADWIDTH { - dowidth(t) +// maxPtrmaskBytes is the maximum length of a GC ptrmask bitmap, +// which holds 1-bit entries describing where pointers are in a given type. +// 16 bytes is enough to describe 128 pointer-sized words, 512 or 1024 bytes +// depending on the system. Above this length, the GC information is +// recorded as a GC program, which can express repetition compactly. +// In either form, the information is used by the runtime to initialize the +// heap bitmap, and for large types (like 128 or more words), they are +// roughly the same speed. GC programs are never much larger and often +// more compact. (If large arrays are involved, they can be arbitrarily more +// compact.) +// +// The cutoff must be large enough that any allocation large enough to +// use a GC program is large enough that it does not share heap bitmap +// bytes with any other objects, allowing the GC program execution to +// assume an aligned start and not use atomic operations. In the current +// runtime, this means all malloc size classes larger than the cutoff must +// be multiples of four words. On 32-bit systems that's 16 bytes, and +// all size classes >= 16 bytes are 16-byte aligned, so no real constraint. +// On 64-bit systems, that's 32 bytes, and 32-byte alignment is guaranteed +// for size classes >= 256 bytes. On a 64-bit sytem, 256 bytes allocated +// is 32 pointers, the bits for which fit in 4 bytes. So maxPtrmaskBytes +// must be >= 4. +// +// We use 16 because the GC programs do have some constant overhead +// to get started, and processing 128 pointers seems to be enough to +// amortize that overhead well. +const maxPtrmaskBytes = 16 + +// dgcsym emits and returns a data symbol containing GC information for type t, +// along with a boolean reporting whether the UseGCProg bit should be set in +// the type kind, and the ptrdata field to record in the reflect type information. +func dgcsym(t *Type) (sym *Sym, useGCProg bool, ptrdata int64) { + ptrdata = typeptrdata(t) + if ptrdata/int64(Widthptr) <= maxPtrmaskBytes*8 { + sym = dgcptrmask(t) + return } - // Calculate size of the unrolled GC mask. - nptr := typeptrdata(t) / int64(Widthptr) - - // Decide whether to use unrolled GC mask or GC program. - // We could use a more elaborate condition, but this seems to work well in practice. - // For small objects, the GC program can't give significant reduction. - return nptr > int64(2*Widthptr*8) + useGCProg = true + sym, ptrdata = dgcprog(t) + return } -// Generates GC bitmask (1 bit per word). -func gengcmask(t *Type, gcmask []byte) { - for i := int64(0); i < 16; i++ { - gcmask[i] = 0 +// dgcptrmask emits and returns the symbol containing a pointer mask for type t. +func dgcptrmask(t *Type) *Sym { + ptrmask := make([]byte, (typeptrdata(t)/int64(Widthptr)+7)/8) + fillptrmask(t, ptrmask) + p := fmt.Sprintf("gcbits.%x", ptrmask) + + sym := Pkglookup(p, Runtimepkg) + if sym.Flags&SymUniq == 0 { + sym.Flags |= SymUniq + for i, x := range ptrmask { + duint8(sym, i, x) + } + ggloblsym(sym, int32(len(ptrmask)), obj.DUPOK|obj.RODATA|obj.LOCAL) + } + return sym +} + +// fillptrmask fills in ptrmask with 1s corresponding to the +// word offsets in t that hold pointers. +// ptrmask is assumed to fit at least typeptrdata(t)/Widthptr bits. +func fillptrmask(t *Type, ptrmask []byte) { + for i := range ptrmask { + ptrmask[i] = 0 } if !haspointers(t) { return } - vec := bvalloc(int32(2 * Widthptr * 8)) + vec := bvalloc(8 * int32(len(ptrmask))) xoffset := int64(0) onebitwalktype1(t, &xoffset, vec) nptr := typeptrdata(t) / int64(Widthptr) for i := int64(0); i < nptr; i++ { if bvget(vec, int32(i)) == 1 { - gcmask[i/8] |= 1 << (uint(i) % 8) + ptrmask[i/8] |= 1 << (uint(i) % 8) } } } -// Helper object for generation of GC programs. -type ProgGen struct { - s *Sym - datasize int32 - data [256 / 8]uint8 - ot int64 +// dgcprog emits and returns the symbol containing a GC program for type t +// along with the size of the data described by the program (in the range [typeptrdata(t), t.Width]). +// In practice, the size is typeptrdata(t) except for non-trivial arrays. +// For non-trivial arrays, the program describes the full t.Width size. +func dgcprog(t *Type) (*Sym, int64) { + dowidth(t) + if t.Width == BADWIDTH { + Fatal("dgcprog: %v badwidth", t) + } + sym := typesymprefix(".gcprog", t) + var p GCProg + p.init(sym) + p.emit(t, 0) + offset := p.w.BitIndex() * int64(Widthptr) + p.end() + if ptrdata := typeptrdata(t); offset < ptrdata || offset > t.Width { + Fatal("dgcprog: %v: offset=%d but ptrdata=%d size=%d", t, offset, ptrdata, t.Width) + } + return sym, offset } -func proggeninit(g *ProgGen, s *Sym) { - g.s = s - g.datasize = 0 - g.ot = 0 - g.data = [256 / 8]uint8{} +type GCProg struct { + sym *Sym + symoff int + w gcprog.Writer } -func proggenemit(g *ProgGen, v uint8) { - g.ot = int64(duint8(g.s, int(g.ot), v)) +var Debug_gcprog int // set by -d gcprog + +func (p *GCProg) init(sym *Sym) { + p.sym = sym + p.symoff = 4 // first 4 bytes hold program length + p.w.Init(p.writeByte) + if Debug_gcprog > 0 { + fmt.Fprintf(os.Stderr, "compile: start GCProg for %v\n", sym) + p.w.Debug(os.Stderr) + } } -// Emits insData block from g->data. -func proggendataflush(g *ProgGen) { - if g.datasize == 0 { +func (p *GCProg) writeByte(x byte) { + p.symoff = duint8(p.sym, p.symoff, x) +} + +func (p *GCProg) end() { + p.w.End() + duint32(p.sym, 0, uint32(p.symoff-4)) + ggloblsym(p.sym, int32(p.symoff), obj.DUPOK|obj.RODATA|obj.LOCAL) + if Debug_gcprog > 0 { + fmt.Fprintf(os.Stderr, "compile: end GCProg for %v\n", p.sym) + } +} + +func (p *GCProg) emit(t *Type, offset int64) { + dowidth(t) + if !haspointers(t) { return } - proggenemit(g, obj.InsData) - proggenemit(g, uint8(g.datasize)) - s := (g.datasize + 7) / 8 - for i := int32(0); i < s; i++ { - proggenemit(g, g.data[i]) + if t.Width == int64(Widthptr) { + p.w.Ptr(offset / int64(Widthptr)) + return } - g.datasize = 0 - g.data = [256 / 8]uint8{} -} - -func proggendata(g *ProgGen, d uint8) { - g.data[g.datasize/8] |= d << uint(g.datasize%8) - g.datasize++ - if g.datasize == 255 { - proggendataflush(g) - } -} - -// Skip v bytes due to alignment, etc. -func proggenskip(g *ProgGen, off int64, v int64) { - for i := off; i < off+v; i++ { - if (i % int64(Widthptr)) == 0 { - proggendata(g, 0) - } - } -} - -// Emit insArray instruction. -func proggenarray(g *ProgGen, len int64) { - proggendataflush(g) - proggenemit(g, obj.InsArray) - for i := int32(0); i < int32(Widthptr); i, len = i+1, len>>8 { - proggenemit(g, uint8(len)) - } -} - -func proggenarrayend(g *ProgGen) { - proggendataflush(g) - proggenemit(g, obj.InsArrayEnd) -} - -func proggenfini(g *ProgGen) int64 { - proggendataflush(g) - proggenemit(g, obj.InsEnd) - return g.ot -} - -// Generates GC program for large types. -func gengcprog(t *Type, pgc0 **Sym, pgc1 **Sym) { - nptr := (t.Width + int64(Widthptr) - 1) / int64(Widthptr) - size := nptr + 1 // unroll flag in the beginning, used by runtime (see runtime.markallocated) - - // emity space in BSS for unrolled program - *pgc0 = nil - - // Don't generate it if it's too large, runtime will unroll directly into GC bitmap. - if size <= obj.MaxGCMask { - gc0 := typesymprefix(".gc", t) - ggloblsym(gc0, int32(size), obj.DUPOK|obj.NOPTR) - *pgc0 = gc0 - } - - // program in RODATA - gc1 := typesymprefix(".gcprog", t) - - var g ProgGen - proggeninit(&g, gc1) - xoffset := int64(0) - gengcprog1(&g, t, &xoffset) - ot := proggenfini(&g) - ggloblsym(gc1, int32(ot), obj.DUPOK|obj.RODATA) - *pgc1 = gc1 -} - -// Recursively walks type t and writes GC program into g. -func gengcprog1(g *ProgGen, t *Type, xoffset *int64) { switch t.Etype { - case TINT8, - TUINT8, - TINT16, - TUINT16, - TINT32, - TUINT32, - TINT64, - TUINT64, - TINT, - TUINT, - TUINTPTR, - TBOOL, - TFLOAT32, - TFLOAT64, - TCOMPLEX64, - TCOMPLEX128: - proggenskip(g, *xoffset, t.Width) - *xoffset += t.Width - - case TPTR32, - TPTR64, - TUNSAFEPTR, - TFUNC, - TCHAN, - TMAP: - proggendata(g, 1) - *xoffset += t.Width + default: + Fatal("GCProg.emit: unexpected type %v", t) case TSTRING: - proggendata(g, 1) - proggendata(g, 0) - *xoffset += t.Width + p.w.Ptr(offset / int64(Widthptr)) - // Assuming IfacePointerOnly=1. case TINTER: - proggendata(g, 1) - proggendata(g, 1) - *xoffset += t.Width + p.w.Ptr(offset / int64(Widthptr)) + p.w.Ptr(offset/int64(Widthptr) + 1) case TARRAY: if Isslice(t) { - proggendata(g, 1) - proggendata(g, 0) - proggendata(g, 0) - } else { - t1 := t.Type - if t1.Width == 0 { - } - // ignore - if t.Bound <= 1 || t.Bound*t1.Width < int64(32*Widthptr) { - for i := int64(0); i < t.Bound; i++ { - gengcprog1(g, t1, xoffset) - } - } else if !haspointers(t1) { - n := t.Width - n -= -*xoffset & (int64(Widthptr) - 1) // skip to next ptr boundary - proggenarray(g, (n+int64(Widthptr)-1)/int64(Widthptr)) - proggendata(g, 0) - proggenarrayend(g) - *xoffset -= (n+int64(Widthptr)-1)/int64(Widthptr)*int64(Widthptr) - t.Width - } else { - proggenarray(g, t.Bound) - gengcprog1(g, t1, xoffset) - *xoffset += (t.Bound - 1) * t1.Width - proggenarrayend(g) - } + p.w.Ptr(offset / int64(Widthptr)) + return } + if t.Bound == 0 { + // should have been handled by haspointers check above + Fatal("GCProg.emit: empty array") + } + + // Flatten array-of-array-of-array to just a big array by multiplying counts. + count := t.Bound + elem := t.Type + for Isfixedarray(elem) { + count *= elem.Bound + elem = elem.Type + } + + if !p.w.ShouldRepeat(elem.Width/int64(Widthptr), count) { + // Cheaper to just emit the bits. + for i := int64(0); i < count; i++ { + p.emit(elem, offset+i*elem.Width) + } + return + } + p.emit(elem, offset) + p.w.ZeroUntil((offset + elem.Width) / int64(Widthptr)) + p.w.Repeat(elem.Width/int64(Widthptr), count-1) case TSTRUCT: - o := int64(0) - var fieldoffset int64 for t1 := t.Type; t1 != nil; t1 = t1.Down { - fieldoffset = t1.Width - proggenskip(g, *xoffset, fieldoffset-o) - *xoffset += fieldoffset - o - gengcprog1(g, t1.Type, xoffset) - o = fieldoffset + t1.Type.Width + p.emit(t1.Type, offset+t1.Width) } - - proggenskip(g, *xoffset, t.Width-o) - *xoffset += t.Width - o - - default: - Fatal("gengcprog1: unexpected type, %v", t) } } diff --git a/src/cmd/internal/gcprog/gcprog.go b/src/cmd/internal/gcprog/gcprog.go new file mode 100644 index 0000000000..5845f7d65e --- /dev/null +++ b/src/cmd/internal/gcprog/gcprog.go @@ -0,0 +1,298 @@ +// Copyright 2015 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 gcprog implements an encoder for packed GC pointer bitmaps, +// known as GC programs. +// +// Program Format +// +// The GC program encodes a sequence of 0 and 1 bits indicating scalar or pointer words in an object. +// The encoding is a simple Lempel-Ziv program, with codes to emit literal bits and to repeat the +// last n bits c times. +// +// The possible codes are: +// +// 00000000: stop +// 0nnnnnnn: emit n bits copied from the next (n+7)/8 bytes, least significant bit first +// 10000000 n c: repeat the previous n bits c times; n, c are varints +// 1nnnnnnn c: repeat the previous n bits c times; c is a varint +// +// The numbers n and c, when they follow a code, are encoded as varints +// using the same encoding as encoding/binary's Uvarint. +// +package gcprog + +import ( + "fmt" + "io" +) + +const progMaxLiteral = 127 // maximum n for literal n bit code + +// A Writer is an encoder for GC programs. +// +// The typical use of a Writer is to call Init, maybe call Debug, +// make a sequence of Ptr, Advance, Repeat, and Append calls +// to describe the data type, and then finally call End. +type Writer struct { + writeByte func(byte) + symoff int + index int64 + b [progMaxLiteral]byte + nb int + debug io.Writer + debugBuf []byte +} + +// Init initializes w to write a new GC program +// by calling writeByte for each byte in the program. +func (w *Writer) Init(writeByte func(byte)) { + w.writeByte = writeByte +} + +// Debug causes the writer to print a debugging trace to out +// during future calls to methods like Ptr, Advance, and End. +// It also enables debugging checks during the encoding. +func (w *Writer) Debug(out io.Writer) { + w.debug = out +} + +// BitIndex returns the number of bits written to the bit stream so far. +func (w *Writer) BitIndex() int64 { + return w.index +} + +// byte writes the byte x to the output. +func (w *Writer) byte(x byte) { + if w.debug != nil { + w.debugBuf = append(w.debugBuf, x) + } + w.writeByte(x) +} + +// End marks the end of the program, writing any remaining bytes. +func (w *Writer) End() { + w.flushlit() + w.byte(0) + if w.debug != nil { + index := progbits(w.debugBuf) + if index != w.index { + println("gcprog: End wrote program for", index, "bits, but current index is", w.index) + panic("gcprog: out of sync") + } + } +} + +// Ptr emits a 1 into the bit stream at the given bit index. +// that is, it records that the index'th word in the object memory is a pointer. +// Any bits between the current index and the new index +// are set to zero, meaning the corresponding words are scalars. +func (w *Writer) Ptr(index int64) { + if index < w.index { + println("gcprog: Ptr at index", index, "but current index is", w.index) + panic("gcprog: invalid Ptr index") + } + w.ZeroUntil(index) + if w.debug != nil { + fmt.Fprintf(w.debug, "gcprog: ptr at %d\n", index) + } + w.lit(1) +} + +// ShouldRepeat reports whether it would be worthwhile to +// use a Repeat to describe c elements of n bits each, +// compared to just emitting c copies of the n-bit description. +func (w *Writer) ShouldRepeat(n, c int64) bool { + // Should we lay out the bits directly instead of + // encoding them as a repetition? Certainly if count==1, + // since there's nothing to repeat, but also if the total + // size of the plain pointer bits for the type will fit in + // 4 or fewer bytes, since using a repetition will require + // flushing the current bits plus at least one byte for + // the repeat size and one for the repeat count. + return c > 1 && c*n > 4*8 +} + +// Repeat emits an instruction to repeat the description +// of the last n words c times (including the initial description, c+1 times in total). +func (w *Writer) Repeat(n, c int64) { + if n == 0 || c == 0 { + return + } + w.flushlit() + if w.debug != nil { + fmt.Fprintf(w.debug, "gcprog: repeat %d × %d\n", n, c) + } + if n < 128 { + w.byte(0x80 | byte(n)) + } else { + w.byte(0x80) + w.varint(n) + } + w.varint(c) + w.index += n * c +} + +// ZeroUntil adds zeros to the bit stream until reaching the given index; +// that is, it records that the words from the most recent pointer until +// the index'th word are scalars. +// ZeroUntil is usually called in preparation for a call to Repeat, Append, or End. +func (w *Writer) ZeroUntil(index int64) { + if index < w.index { + println("gcprog: Advance", index, "but index is", w.index) + panic("gcprog: invalid Advance index") + } + skip := (index - w.index) + if skip == 0 { + return + } + if skip < 4*8 { + if w.debug != nil { + fmt.Fprintf(w.debug, "gcprog: advance to %d by literals\n", index) + } + for i := int64(0); i < skip; i++ { + w.lit(0) + } + return + } + + if w.debug != nil { + fmt.Fprintf(w.debug, "gcprog: advance to %d by repeat\n", index) + } + w.lit(0) + w.flushlit() + w.Repeat(1, skip-1) +} + +// Append emits the given GC program into the current output. +// The caller asserts that the program emits n bits (describes n words), +// and Append panics if that is not true. +func (w *Writer) Append(prog []byte, n int64) { + w.flushlit() + if w.debug != nil { + fmt.Fprintf(w.debug, "gcprog: append prog for %d ptrs\n", n) + fmt.Fprintf(w.debug, "\t") + } + n1 := progbits(prog) + if n1 != n { + panic("gcprog: wrong bit count in append") + } + // The last byte of the prog terminates the program. + // Don't emit that, or else our own program will end. + for i, x := range prog[:len(prog)-1] { + if w.debug != nil { + if i > 0 { + fmt.Fprintf(w.debug, " ") + } + fmt.Fprintf(w.debug, "%02x", x) + } + w.byte(x) + } + if w.debug != nil { + fmt.Fprintf(w.debug, "\n") + } + w.index += n +} + +// progbits returns the length of the bit stream encoded by the program p. +func progbits(p []byte) int64 { + var n int64 + for len(p) > 0 { + x := p[0] + p = p[1:] + if x == 0 { + break + } + if x&0x80 == 0 { + count := x &^ 0x80 + n += int64(count) + p = p[(count+7)/8:] + continue + } + nbit := int64(x &^ 0x80) + if nbit == 0 { + nbit, p = readvarint(p) + } + var count int64 + count, p = readvarint(p) + n += nbit * count + } + if len(p) > 0 { + println("gcprog: found end instruction after", n, "ptrs, with", len(p), "bytes remaining") + panic("gcprog: extra data at end of program") + } + return n +} + +// readvarint reads a varint from p, returning the value and the remainder of p. +func readvarint(p []byte) (int64, []byte) { + var v int64 + var nb uint + for { + c := p[0] + p = p[1:] + v |= int64(c&^0x80) << nb + nb += 7 + if c&0x80 == 0 { + break + } + } + return v, p +} + +// lit adds a single literal bit to w. +func (w *Writer) lit(x byte) { + if w.nb == progMaxLiteral { + w.flushlit() + } + w.b[w.nb] = x + w.nb++ + w.index++ +} + +// varint emits the varint encoding of x. +func (w *Writer) varint(x int64) { + if x < 0 { + panic("gcprog: negative varint") + } + for x >= 0x80 { + w.byte(byte(0x80 | x)) + x >>= 7 + } + w.byte(byte(x)) +} + +// flushlit flushes any pending literal bits. +func (w *Writer) flushlit() { + if w.nb == 0 { + return + } + if w.debug != nil { + fmt.Fprintf(w.debug, "gcprog: flush %d literals\n", w.nb) + fmt.Fprintf(w.debug, "\t%v\n", w.b[:w.nb]) + fmt.Fprintf(w.debug, "\t%02x", byte(w.nb)) + } + w.byte(byte(w.nb)) + var bits uint8 + for i := 0; i < w.nb; i++ { + bits |= w.b[i] << uint(i%8) + if (i+1)%8 == 0 { + if w.debug != nil { + fmt.Fprintf(w.debug, " %02x", bits) + } + w.byte(bits) + bits = 0 + } + } + if w.nb%8 != 0 { + if w.debug != nil { + fmt.Fprintf(w.debug, " %02x", bits) + } + w.byte(bits) + } + if w.debug != nil { + fmt.Fprintf(w.debug, "\n") + } + w.nb = 0 +} diff --git a/src/cmd/internal/ld/data.go b/src/cmd/internal/ld/data.go index b65b667f98..f9aacf0e19 100644 --- a/src/cmd/internal/ld/data.go +++ b/src/cmd/internal/ld/data.go @@ -32,9 +32,11 @@ package ld import ( + "cmd/internal/gcprog" "cmd/internal/obj" "fmt" "log" + "os" "strings" ) @@ -1044,141 +1046,65 @@ func maxalign(s *LSym, type_ int) int32 { return max } -// Helper object for building GC type programs. -type ProgGen struct { - s *LSym - datasize int32 - data [256 / 8]uint8 - pos int64 +const debugGCProg = false + +type GCProg struct { + sym *LSym + w gcprog.Writer } -func proggeninit(g *ProgGen, s *LSym) { - g.s = s - g.datasize = 0 - g.pos = 0 - g.data = [256 / 8]uint8{} -} - -func proggenemit(g *ProgGen, v uint8) { - Adduint8(Ctxt, g.s, v) -} - -// Writes insData block from g->data. -func proggendataflush(g *ProgGen) { - if g.datasize == 0 { - return - } - proggenemit(g, obj.InsData) - proggenemit(g, uint8(g.datasize)) - s := (g.datasize + 7) / 8 - for i := int32(0); i < s; i++ { - proggenemit(g, g.data[i]) - } - g.datasize = 0 - g.data = [256 / 8]uint8{} -} - -func proggendata(g *ProgGen, d uint8) { - g.data[g.datasize/8] |= d << uint(g.datasize%8) - g.datasize++ - if g.datasize == 255 { - proggendataflush(g) +func (p *GCProg) Init(name string) { + p.sym = Linklookup(Ctxt, name, 0) + p.w.Init(p.writeByte) + if debugGCProg { + fmt.Fprintf(os.Stderr, "ld: start GCProg %s\n", name) + p.w.Debug(os.Stderr) } } -// Skip v bytes due to alignment, etc. -func proggenskip(g *ProgGen, off int64, v int64) { - for i := off; i < off+v; i++ { - if (i % int64(Thearch.Ptrsize)) == 0 { - proggendata(g, 0) - } +func (p *GCProg) writeByte(x byte) { + Adduint8(Ctxt, p.sym, x) +} + +func (p *GCProg) End(size int64) { + p.w.ZeroUntil(size / int64(Thearch.Ptrsize)) + p.w.End() + if debugGCProg { + fmt.Fprintf(os.Stderr, "ld: end GCProg\n") } } -// Emit insArray instruction. -func proggenarray(g *ProgGen, length int64) { - var i int32 - - proggendataflush(g) - proggenemit(g, obj.InsArray) - for i = 0; i < int32(Thearch.Ptrsize); i, length = i+1, length>>8 { - proggenemit(g, uint8(length)) - } -} - -func proggenarrayend(g *ProgGen) { - proggendataflush(g) - proggenemit(g, obj.InsArrayEnd) -} - -func proggenfini(g *ProgGen, size int64) { - proggenskip(g, g.pos, size-g.pos) - proggendataflush(g) - proggenemit(g, obj.InsEnd) -} - -// This function generates GC pointer info for global variables. -func proggenaddsym(g *ProgGen, s *LSym) { - if s.Size == 0 { - return - } - - // Skip alignment hole from the previous symbol. - proggenskip(g, g.pos, s.Value-g.pos) - g.pos = s.Value - - if s.Gotype == nil && s.Size >= int64(Thearch.Ptrsize) { +func (p *GCProg) AddSym(s *LSym) { + typ := s.Gotype + // Things without pointers should be in SNOPTRDATA or SNOPTRBSS; + // everything we see should have pointers and should therefore have a type. + if typ == nil { Diag("missing Go type information for global symbol: %s size %d", s.Name, int(s.Size)) return } - if s.Gotype == nil || decodetype_noptr(s.Gotype) != 0 || s.Size < int64(Thearch.Ptrsize) || s.Name[0] == '.' { - // no scan - if s.Size < int64(32*Thearch.Ptrsize) { - // Emit small symbols as data. - // This case also handles unaligned and tiny symbols, so tread carefully. - for i := s.Value; i < s.Value+s.Size; i++ { - if (i % int64(Thearch.Ptrsize)) == 0 { - proggendata(g, 0) - } - } - } else { - // Emit large symbols as array. - if (s.Size%int64(Thearch.Ptrsize) != 0) || (g.pos%int64(Thearch.Ptrsize) != 0) { - Diag("proggenaddsym: unaligned noscan symbol %s: size=%d pos=%d", s.Name, s.Size, g.pos) - } - proggenarray(g, s.Size/int64(Thearch.Ptrsize)) - proggendata(g, 0) - proggenarrayend(g) - } - g.pos = s.Value + s.Size - } else if decodetype_usegcprog(s.Gotype) != 0 { - // gc program, copy directly - // TODO(rsc): Maybe someday the gc program will only describe - // the first decodetype_ptrdata(s.Gotype) bytes instead of the full size. - proggendataflush(g) - gcprog := decodetype_gcprog(s.Gotype) - size := decodetype_size(s.Gotype) - if (size%int64(Thearch.Ptrsize) != 0) || (g.pos%int64(Thearch.Ptrsize) != 0) { - Diag("proggenaddsym: unaligned gcprog symbol %s: size=%d pos=%d", s.Name, size, g.pos) - } - for i := int64(0); i < int64(len(gcprog.P)-1); i++ { - proggenemit(g, uint8(gcprog.P[i])) - } - g.pos = s.Value + size - } else { - // gc mask, it's small so emit as data - mask := decodetype_gcmask(s.Gotype) - ptrdata := decodetype_ptrdata(s.Gotype) - if (ptrdata%int64(Thearch.Ptrsize) != 0) || (g.pos%int64(Thearch.Ptrsize) != 0) { - Diag("proggenaddsym: unaligned gcmask symbol %s: size=%d pos=%d", s.Name, ptrdata, g.pos) - } - for i := int64(0); i < ptrdata; i += int64(Thearch.Ptrsize) { - word := uint(i / int64(Thearch.Ptrsize)) - proggendata(g, (mask[word/8]>>(word%8))&1) - } - g.pos = s.Value + ptrdata + ptrsize := int64(Thearch.Ptrsize) + nptr := decodetype_ptrdata(typ) / ptrsize + + if debugGCProg { + fmt.Fprintf(os.Stderr, "gcprog sym: %s at %d (ptr=%d+%d)\n", s.Name, s.Value, s.Value/ptrsize, nptr) } + + if decodetype_usegcprog(typ) == 0 { + // Copy pointers from mask into program. + mask := decodetype_gcmask(typ) + for i := int64(0); i < nptr; i++ { + if (mask[i/8]>>uint(i%8))&1 != 0 { + p.w.Ptr(s.Value/ptrsize + i) + } + } + return + } + + // Copy program. + prog := decodetype_gcprog(typ) + p.w.ZeroUntil(s.Value / ptrsize) + p.w.Append(prog.P[4:prog.Size], nptr) } func growdatsize(datsizep *int64, s *LSym) { @@ -1386,15 +1312,13 @@ func dodata() { /* data */ sect = addsection(&Segdata, ".data", 06) - sect.Align = maxalign(s, obj.SBSS-1) datsize = Rnd(datsize, int64(sect.Align)) sect.Vaddr = uint64(datsize) Linklookup(Ctxt, "runtime.data", 0).Sect = sect Linklookup(Ctxt, "runtime.edata", 0).Sect = sect - gcdata := Linklookup(Ctxt, "runtime.gcdata", 0) - var gen ProgGen - proggeninit(&gen, gcdata) + var gc GCProg + gc.Init("runtime.gcdata") for ; s != nil && s.Type < obj.SBSS; s = s.Next { if s.Type == obj.SINITARR { Ctxt.Cursym = s @@ -1405,33 +1329,30 @@ func dodata() { s.Type = obj.SDATA datsize = aligndatsize(datsize, s) s.Value = int64(uint64(datsize) - sect.Vaddr) - proggenaddsym(&gen, s) // gc + gc.AddSym(s) growdatsize(&datsize, s) } - sect.Length = uint64(datsize) - sect.Vaddr - proggenfini(&gen, int64(sect.Length)) // gc + gc.End(int64(sect.Length)) /* bss */ sect = addsection(&Segdata, ".bss", 06) - sect.Align = maxalign(s, obj.SNOPTRBSS-1) datsize = Rnd(datsize, int64(sect.Align)) sect.Vaddr = uint64(datsize) Linklookup(Ctxt, "runtime.bss", 0).Sect = sect Linklookup(Ctxt, "runtime.ebss", 0).Sect = sect - gcbss := Linklookup(Ctxt, "runtime.gcbss", 0) - proggeninit(&gen, gcbss) + gc = GCProg{} + gc.Init("runtime.gcbss") for ; s != nil && s.Type < obj.SNOPTRBSS; s = s.Next { s.Sect = sect datsize = aligndatsize(datsize, s) s.Value = int64(uint64(datsize) - sect.Vaddr) - proggenaddsym(&gen, s) // gc + gc.AddSym(s) growdatsize(&datsize, s) } - sect.Length = uint64(datsize) - sect.Vaddr - proggenfini(&gen, int64(sect.Length)) // gc + gc.End(int64(sect.Length)) /* pointer-free bss */ sect = addsection(&Segdata, ".noptrbss", 06) diff --git a/src/cmd/internal/ld/decodesym.go b/src/cmd/internal/ld/decodesym.go index b9333857fd..fcc664dde7 100644 --- a/src/cmd/internal/ld/decodesym.go +++ b/src/cmd/internal/ld/decodesym.go @@ -44,7 +44,7 @@ func decode_inuxi(p []byte, sz int) uint64 { // commonsize returns the size of the common prefix for all type // structures (runtime._type). func commonsize() int { - return 9*Thearch.Ptrsize + 8 + return 8*Thearch.Ptrsize + 8 } // Type.commonType.kind @@ -79,7 +79,7 @@ func decodetype_gcprog(s *LSym) *LSym { x := "type..gcprog." + s.Name[5:] return Linklookup(Ctxt, x, 0) } - return decode_reloc_sym(s, 2*int32(Thearch.Ptrsize)+8+2*int32(Thearch.Ptrsize)) + return decode_reloc_sym(s, 2*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize)) } func decodetype_gcprog_shlib(s *LSym) uint64 { diff --git a/src/cmd/internal/ld/lib.go b/src/cmd/internal/ld/lib.go index a0d03ef22d..753e8eebd8 100644 --- a/src/cmd/internal/ld/lib.go +++ b/src/cmd/internal/ld/lib.go @@ -1200,7 +1200,7 @@ func ldshlibsyms(shlib string) { if strings.HasPrefix(s.Name, "_") { continue } - if strings.HasPrefix(s.Name, "runtime.gcbits.0x") { + if strings.HasPrefix(s.Name, "runtime.gcbits.") { gcmasks[s.Value] = readelfsymboldata(f, &s) } if s.Name == "go.link.abihashbytes" { diff --git a/src/cmd/internal/ld/link.go b/src/cmd/internal/ld/link.go index a314ca1370..3098147819 100644 --- a/src/cmd/internal/ld/link.go +++ b/src/cmd/internal/ld/link.go @@ -34,6 +34,7 @@ import ( "cmd/internal/obj" "debug/elf" "encoding/binary" + "fmt" ) type LSym struct { @@ -86,6 +87,13 @@ type LSym struct { gcmask []byte } +func (s *LSym) String() string { + if s.Version == 0 { + return s.Name + } + return fmt.Sprintf("%s<%d>", s.Name, s.Version) +} + type Reloc struct { Off int32 Siz uint8 diff --git a/src/cmd/internal/ld/objfile.go b/src/cmd/internal/ld/objfile.go index 3d59323dba..613fcb2a40 100644 --- a/src/cmd/internal/ld/objfile.go +++ b/src/cmd/internal/ld/objfile.go @@ -347,7 +347,7 @@ func rdsym(ctxt *Link, f *obj.Biobuf, pkg string) *LSym { s.Reachable = false } } - if v == 0 && strings.HasPrefix(s.Name, "runtime.gcbits.0x") { + if v == 0 && strings.HasPrefix(s.Name, "runtime.gcbits.") { s.Local = true } return s diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index 373583d471..9214577c2e 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -4395,11 +4395,9 @@ type funcLayoutTest struct { var funcLayoutTests []funcLayoutTest func init() { - var argAlign = PtrSize - var naclExtra []byte + var argAlign uintptr = PtrSize if runtime.GOARCH == "amd64p32" { argAlign = 2 * PtrSize - naclExtra = append(naclExtra, 0) } roundup := func(x uintptr, a uintptr) uintptr { return (x + a - 1) / a * a @@ -4413,16 +4411,14 @@ func init() { 4 * PtrSize, 4 * PtrSize, []byte{1, 0, 1}, - []byte{1, 0, 1, 0, 1, 0}, + []byte{1, 0, 1, 0, 1}, }) - var r, s []byte + var r []byte if PtrSize == 4 { r = []byte{0, 0, 0, 1} - s = append([]byte{0, 0, 0, 1, 0}, naclExtra...) } else { r = []byte{0, 0, 1} - s = []byte{0, 0, 1, 0} } funcLayoutTests = append(funcLayoutTests, funcLayoutTest{ @@ -4432,7 +4428,7 @@ func init() { roundup(3*4, PtrSize) + PtrSize + 2, roundup(roundup(3*4, PtrSize)+PtrSize+2, argAlign), r, - s, + r, }) funcLayoutTests = append(funcLayoutTests, @@ -4469,7 +4465,7 @@ func init() { 3 * PtrSize, roundup(3*PtrSize, argAlign), []byte{1, 0, 1}, - append([]byte{1, 0, 1}, naclExtra...), + []byte{1, 0, 1}, }) funcLayoutTests = append(funcLayoutTests, @@ -4480,7 +4476,7 @@ func init() { PtrSize, roundup(PtrSize, argAlign), []byte{}, - append([]byte{0}, naclExtra...), + []byte{}, }) funcLayoutTests = append(funcLayoutTests, @@ -4491,7 +4487,7 @@ func init() { 0, 0, []byte{}, - []byte{0}, + []byte{}, }) funcLayoutTests = append(funcLayoutTests, @@ -4502,7 +4498,7 @@ func init() { 2 * PtrSize, 2 * PtrSize, []byte{1}, - []byte{1, 0}, + []byte{1}, // Note: this one is tricky, as the receiver is not a pointer. But we // pass the receiver by reference to the autogenerated pointer-receiver // version of the function. @@ -4532,3 +4528,118 @@ func TestFuncLayout(t *testing.T) { } } } + +func verifyGCBits(t *testing.T, typ Type, bits []byte) { + heapBits := GCBits(New(typ).Interface()) + if !bytes.Equal(heapBits, bits) { + t.Errorf("heapBits incorrect for %v\nhave %v\nwant %v", typ, heapBits, bits) + } +} + +func TestGCBits(t *testing.T) { + verifyGCBits(t, TypeOf((*byte)(nil)), []byte{1}) + + // Building blocks for types seen by the compiler (like [2]Xscalar). + // The compiler will create the type structures for the derived types, + // including their GC metadata. + type Xscalar struct{ x uintptr } + type Xptr struct{ x *byte } + type Xptrscalar struct { + *byte + uintptr + } + type Xscalarptr struct { + uintptr + *byte + } + + var Tscalar, Tptr, Tscalarptr, Tptrscalar Type + { + // Building blocks for types constructed by reflect. + // This code is in a separate block so that code below + // cannot accidentally refer to these. + // The compiler must NOT see types derived from these + // (for example, [2]Scalar must NOT appear in the program), + // or else reflect will use it instead of having to construct one. + // The goal is to test the construction. + type Scalar struct{ x uintptr } + type Ptr struct{ x *byte } + type Ptrscalar struct { + *byte + uintptr + } + type Scalarptr struct { + uintptr + *byte + } + Tscalar = TypeOf(Scalar{}) + Tptr = TypeOf(Ptr{}) + Tscalarptr = TypeOf(Scalarptr{}) + Tptrscalar = TypeOf(Ptrscalar{}) + } + + empty := []byte{} + + verifyGCBits(t, TypeOf(Xscalar{}), empty) + verifyGCBits(t, Tscalar, empty) + verifyGCBits(t, TypeOf(Xptr{}), lit(1)) + verifyGCBits(t, Tptr, lit(1)) + verifyGCBits(t, TypeOf(Xscalarptr{}), lit(0, 1)) + verifyGCBits(t, Tscalarptr, lit(0, 1)) + verifyGCBits(t, TypeOf(Xptrscalar{}), lit(1)) + verifyGCBits(t, Tptrscalar, lit(1)) + + verifyGCBits(t, TypeOf([0]Xptr{}), empty) + verifyGCBits(t, ArrayOf(0, Tptr), empty) + verifyGCBits(t, TypeOf([1]Xptrscalar{}), lit(1)) + verifyGCBits(t, ArrayOf(1, Tptrscalar), lit(1)) + verifyGCBits(t, TypeOf([2]Xscalar{}), empty) + verifyGCBits(t, ArrayOf(2, Tscalar), empty) + verifyGCBits(t, TypeOf([100]Xscalar{}), empty) + verifyGCBits(t, ArrayOf(100, Tscalar), empty) + verifyGCBits(t, TypeOf([2]Xptr{}), lit(1, 1)) + verifyGCBits(t, ArrayOf(2, Tptr), lit(1, 1)) + verifyGCBits(t, TypeOf([100]Xptr{}), rep(100, lit(1))) + verifyGCBits(t, ArrayOf(100, Tptr), rep(100, lit(1))) + verifyGCBits(t, TypeOf([2]Xscalarptr{}), lit(0, 1, 0, 1)) + verifyGCBits(t, ArrayOf(2, Tscalarptr), lit(0, 1, 0, 1)) + verifyGCBits(t, TypeOf([100]Xscalarptr{}), rep(100, lit(0, 1))) + verifyGCBits(t, ArrayOf(100, Tscalarptr), rep(100, lit(0, 1))) + verifyGCBits(t, TypeOf([2]Xptrscalar{}), lit(1, 0, 1)) + verifyGCBits(t, ArrayOf(2, Tptrscalar), lit(1, 0, 1)) + verifyGCBits(t, TypeOf([100]Xptrscalar{}), rep(100, lit(1, 0))) + verifyGCBits(t, ArrayOf(100, Tptrscalar), rep(100, lit(1, 0))) + verifyGCBits(t, TypeOf([1][100]Xptrscalar{}), rep(100, lit(1, 0))) + verifyGCBits(t, ArrayOf(1, ArrayOf(100, Tptrscalar)), rep(100, lit(1, 0))) + verifyGCBits(t, TypeOf([2][100]Xptrscalar{}), rep(200, lit(1, 0))) + verifyGCBits(t, ArrayOf(2, ArrayOf(100, Tptrscalar)), rep(200, lit(1, 0))) + + verifyGCBits(t, TypeOf((chan [100]Xscalar)(nil)), lit(1)) + verifyGCBits(t, ChanOf(BothDir, ArrayOf(100, Tscalar)), lit(1)) + + verifyGCBits(t, TypeOf((func([100]Xscalarptr))(nil)), lit(1)) + //verifyGCBits(t, FuncOf([]Type{ArrayOf(100, Tscalarptr)}, nil, false), lit(1)) + + verifyGCBits(t, TypeOf((map[[100]Xscalarptr]Xscalar)(nil)), lit(1)) + verifyGCBits(t, MapOf(ArrayOf(100, Tscalarptr), Tscalar), lit(1)) + + verifyGCBits(t, TypeOf((*[100]Xscalar)(nil)), lit(1)) + verifyGCBits(t, PtrTo(ArrayOf(100, Tscalar)), lit(1)) + + verifyGCBits(t, TypeOf(([][100]Xscalar)(nil)), lit(1)) + verifyGCBits(t, SliceOf(ArrayOf(100, Tscalar)), lit(1)) + + hdr := make([]byte, 8/PtrSize) + verifyGCBits(t, MapBucketOf(Tscalar, Tptr), join(hdr, rep(8, lit(0)), rep(8, lit(1)), lit(1))) + verifyGCBits(t, MapBucketOf(Tscalarptr, Tptr), join(hdr, rep(8, lit(0, 1)), rep(8, lit(1)), lit(1))) + verifyGCBits(t, MapBucketOf(Tscalar, Tscalar), empty) + verifyGCBits(t, MapBucketOf(ArrayOf(2, Tscalarptr), ArrayOf(3, Tptrscalar)), join(hdr, rep(8*2, lit(0, 1)), rep(8*3, lit(1, 0)), lit(1))) + verifyGCBits(t, MapBucketOf(ArrayOf(64/PtrSize, Tscalarptr), ArrayOf(64/PtrSize, Tptrscalar)), join(hdr, rep(8*64/PtrSize, lit(0, 1)), rep(8*64/PtrSize, lit(1, 0)), lit(1))) + verifyGCBits(t, MapBucketOf(ArrayOf(64/PtrSize+1, Tscalarptr), ArrayOf(64/PtrSize, Tptrscalar)), join(hdr, rep(8, lit(1)), rep(8*64/PtrSize, lit(1, 0)), lit(1))) + verifyGCBits(t, MapBucketOf(ArrayOf(64/PtrSize, Tscalarptr), ArrayOf(64/PtrSize+1, Tptrscalar)), join(hdr, rep(8*64/PtrSize, lit(0, 1)), rep(8, lit(1)), lit(1))) + verifyGCBits(t, MapBucketOf(ArrayOf(64/PtrSize+1, Tscalarptr), ArrayOf(64/PtrSize+1, Tptrscalar)), join(hdr, rep(8, lit(1)), rep(8, lit(1)), lit(1))) +} + +func rep(n int, b []byte) []byte { return bytes.Repeat(b, n) } +func join(b ...[]byte) []byte { return bytes.Join(b, nil) } +func lit(x ...byte) []byte { return x } diff --git a/src/reflect/export_test.go b/src/reflect/export_test.go index 6748eba3d1..a4e2e7e28c 100644 --- a/src/reflect/export_test.go +++ b/src/reflect/export_test.go @@ -4,6 +4,8 @@ package reflect +import "unsafe" + // MakeRO returns a copy of v with the read-only flag set. func MakeRO(v Value) Value { v.flag |= flagRO @@ -28,14 +30,14 @@ func FuncLayout(t Type, rcvr Type) (frametype Type, argSize, retOffset uintptr, ft, argSize, retOffset, s, _ = funcLayout(t.(*rtype), nil) } frametype = ft - for i := uint32(0); i < s.n; i += 2 { - stack = append(stack, s.data[i/8]>>(i%8)&3) + for i := uint32(0); i < s.n; i++ { + stack = append(stack, s.data[i/8]>>(i%8)&1) } if ft.kind&kindGCProg != 0 { panic("can't handle gc programs") } - gcdata := (*[1000]byte)(ft.gc[0]) - for i := uintptr(0); i < ft.size/ptrSize; i++ { + gcdata := (*[1000]byte)(unsafe.Pointer(ft.gcdata)) + for i := uintptr(0); i < ft.ptrdata/ptrSize; i++ { gc = append(gc, gcdata[i/8]>>(i%8)&1) } ptrs = ft.kind&kindNoPointers == 0 @@ -51,3 +53,11 @@ func TypeLinks() []string { } return r } + +var GCBits = gcbits + +func gcbits(interface{}) []byte // provided by runtime + +func MapBucketOf(x, y Type) Type { + return bucketOf(x.(*rtype), y.(*rtype)) +} diff --git a/src/reflect/type.go b/src/reflect/type.go index bffe2595dd..f39ba52a42 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -247,17 +247,17 @@ const ( type rtype struct { size uintptr ptrdata uintptr - hash uint32 // hash of type; avoids computation in hash tables - _ uint8 // unused/padding - align uint8 // alignment of variable with this type - fieldAlign uint8 // alignment of struct field with this type - kind uint8 // enumeration for C - alg *typeAlg // algorithm table - gc [2]unsafe.Pointer // garbage collection data - string *string // string form; unnecessary but undeniably useful - *uncommonType // (relatively) uncommon fields - ptrToThis *rtype // type for pointer to this type, if used in binary or has methods - zero unsafe.Pointer // pointer to zero value + hash uint32 // hash of type; avoids computation in hash tables + _ uint8 // unused/padding + align uint8 // alignment of variable with this type + fieldAlign uint8 // alignment of struct field with this type + kind uint8 // enumeration for C + alg *typeAlg // algorithm table + gcdata *byte // garbage collection data + string *string // string form; unnecessary but undeniably useful + *uncommonType // (relatively) uncommon fields + ptrToThis *rtype // type for pointer to this type, if used in binary or has methods + zero unsafe.Pointer // pointer to zero value } // a copy of runtime.typeAlg @@ -1670,111 +1670,14 @@ func isReflexive(t *rtype) bool { } } -// gcProg is a helper type for generatation of GC pointer info. -type gcProg struct { - gc []byte - size uintptr // size of type in bytes - hasPtr bool - lastZero uintptr // largest offset of a zero-byte field -} - -func (gc *gcProg) append(v byte) { - gc.align(unsafe.Sizeof(uintptr(0))) - gc.appendWord(v) -} - -// Appends t's type info to the current program. -func (gc *gcProg) appendProg(t *rtype) { - gc.align(uintptr(t.align)) - if !t.pointers() { - gc.size += t.size - if t.size == 0 { - gc.lastZero = gc.size - } - return - } - switch t.Kind() { - default: - panic("reflect: non-pointer type marked as having pointers") - case Ptr, UnsafePointer, Chan, Func, Map: - gc.appendWord(1) - case Slice: - gc.appendWord(1) - gc.appendWord(0) - gc.appendWord(0) - case String: - gc.appendWord(1) - gc.appendWord(0) - case Array: - c := t.Len() - e := t.Elem().common() - for i := 0; i < c; i++ { - gc.appendProg(e) - } - case Interface: - gc.appendWord(1) - gc.appendWord(1) - case Struct: - oldsize := gc.size - c := t.NumField() - for i := 0; i < c; i++ { - gc.appendProg(t.Field(i).Type.common()) - } - if gc.size > oldsize+t.size { - panic("reflect: struct components are larger than the struct itself") - } - gc.size = oldsize + t.size - } -} - -func (gc *gcProg) appendWord(v byte) { - ptrsize := unsafe.Sizeof(uintptr(0)) - if gc.size%ptrsize != 0 { - panic("reflect: unaligned GC program") - } - nptr := gc.size / ptrsize - for uintptr(len(gc.gc)) <= nptr/8 { - gc.gc = append(gc.gc, 0) - } - gc.gc[nptr/8] |= v << (nptr % 8) - gc.size += ptrsize - if v == 1 { - gc.hasPtr = true - } -} - -func (gc *gcProg) finalize() (unsafe.Pointer, bool) { - if gc.size == 0 { - return nil, false - } - if gc.lastZero == gc.size { - gc.size++ - } - ptrsize := unsafe.Sizeof(uintptr(0)) - gc.align(ptrsize) - nptr := gc.size / ptrsize - for uintptr(len(gc.gc)) <= nptr/8 { - gc.gc = append(gc.gc, 0) - } - return unsafe.Pointer(&gc.gc[0]), gc.hasPtr -} - -func extractGCWord(gc []byte, i uintptr) byte { - return gc[i/8] >> (i % 8) & 1 -} - -func (gc *gcProg) align(a uintptr) { - gc.size = align(gc.size, a) -} - // Make sure these routines stay in sync with ../../runtime/hashmap.go! // These types exist only for GC, so we only fill out GC relevant info. // Currently, that's just size and the GC program. We also fill in string // for possible debugging use. const ( - bucketSize = 8 - maxKeySize = 128 - maxValSize = 128 + bucketSize uintptr = 8 + maxKeySize uintptr = 128 + maxValSize uintptr = 128 ) func bucketOf(ktyp, etyp *rtype) *rtype { @@ -1791,33 +1694,70 @@ func bucketOf(ktyp, etyp *rtype) *rtype { if etyp.size > maxValSize { etyp = PtrTo(etyp).(*rtype) } - ptrsize := unsafe.Sizeof(uintptr(0)) - var gc gcProg - // topbits - for i := 0; i < int(bucketSize*unsafe.Sizeof(uint8(0))/ptrsize); i++ { - gc.append(0) + // Prepare GC data if any. + // A bucket is at most bucketSize*(1+maxKeySize+maxValSize)+2*ptrSize bytes, + // or 2072 bytes, or 259 pointer-size words, or 33 bytes of pointer bitmap. + // Normally the enforced limit on pointer maps is 16 bytes, + // but larger ones are acceptable, 33 bytes isn't too too big, + // and it's easier to generate a pointer bitmap than a GC program. + // Note that since the key and value are known to be <= 128 bytes, + // they're guaranteed to have bitmaps instead of GC programs. + var gcdata *byte + var ptrdata uintptr + if kind != kindNoPointers { + nptr := (bucketSize*(1+ktyp.size+etyp.size) + ptrSize) / ptrSize + mask := make([]byte, (nptr+7)/8) + base := bucketSize / ptrSize + + if ktyp.kind&kindNoPointers == 0 { + if ktyp.kind&kindGCProg != 0 { + panic("reflect: unexpected GC program in MapOf") + } + kmask := (*[16]byte)(unsafe.Pointer(ktyp.gcdata)) + for i := uintptr(0); i < ktyp.size/ptrSize; i++ { + if (kmask[i/8]>>(i%8))&1 != 0 { + for j := uintptr(0); j < bucketSize; j++ { + word := base + j*ktyp.size/ptrSize + i + mask[word/8] |= 1 << (word % 8) + } + } + } + } + base += bucketSize * ktyp.size / ptrSize + + if etyp.kind&kindNoPointers == 0 { + if etyp.kind&kindGCProg != 0 { + panic("reflect: unexpected GC program in MapOf") + } + emask := (*[16]byte)(unsafe.Pointer(etyp.gcdata)) + for i := uintptr(0); i < etyp.size/ptrSize; i++ { + if (emask[i/8]>>(i%8))&1 != 0 { + for j := uintptr(0); j < bucketSize; j++ { + word := base + j*etyp.size/ptrSize + i + mask[word/8] |= 1 << (word % 8) + } + } + } + } + base += bucketSize * etyp.size / ptrSize + + word := base + mask[word/8] |= 1 << (word % 8) + gcdata = &mask[0] + ptrdata = (word + 1) * ptrSize } - // keys - for i := 0; i < bucketSize; i++ { - gc.appendProg(ktyp) - } - // values - for i := 0; i < bucketSize; i++ { - gc.appendProg(etyp) - } - // overflow - gc.append(1) - ptrdata := gc.size + + size := bucketSize*(1+ktyp.size+etyp.size) + ptrSize if runtime.GOARCH == "amd64p32" { - gc.append(0) + size += ptrSize } b := new(rtype) - b.size = gc.size + b.size = size b.ptrdata = ptrdata b.kind = kind - b.gc[0], _ = gc.finalize() + b.gcdata = gcdata s := "bucket(" + *ktyp.string + "," + *etyp.string + ")" b.string = &s return b @@ -1911,19 +1851,83 @@ func ArrayOf(count int, elem Type) Type { array.len = uintptr(count) array.slice = slice.(*rtype) - var gc gcProg - // TODO(sbinet): count could be possibly very large. - // use insArray directives from ../runtime/mbitmap.go. - for i := 0; i < count; i++ { - gc.appendProg(typ) - } - - var hasPtr bool - array.gc[0], hasPtr = gc.finalize() - if !hasPtr { + array.kind &^= kindNoPointers + switch { + case typ.kind&kindNoPointers != 0 || array.size == 0: + // No pointers. array.kind |= kindNoPointers - } else { - array.kind &^= kindNoPointers + array.gcdata = nil + array.ptrdata = 0 + + case count == 1: + // In memory, 1-element array looks just like the element. + array.kind |= typ.kind & kindGCProg + array.gcdata = typ.gcdata + array.ptrdata = typ.ptrdata + + case typ.kind&kindGCProg == 0 && array.size <= 16*8*ptrSize: + // Element is small with pointer mask; array is still small. + // Create direct pointer mask by turning each 1 bit in elem + // into count 1 bits in larger mask. + mask := make([]byte, (array.ptrdata/ptrSize+7)/8) + elemMask := (*[1 << 30]byte)(unsafe.Pointer(typ.gcdata))[:] + elemWords := typ.size / ptrSize + for j := uintptr(0); j < typ.ptrdata/ptrSize; j++ { + if (elemMask[j/8]>>(j%8))&1 != 0 { + for i := uintptr(0); i < array.len; i++ { + k := i*elemWords + j + mask[k/8] |= 1 << (k % 8) + } + } + } + array.gcdata = &mask[0] + + default: + // Create program that emits one element + // and then repeats to make the array. + prog := []byte{0, 0, 0, 0} // will be length of prog + elemGC := (*[1 << 30]byte)(unsafe.Pointer(typ.gcdata))[:] + elemPtrs := typ.ptrdata / ptrSize + if typ.kind&kindGCProg == 0 { + // Element is small with pointer mask; use as literal bits. + mask := elemGC + // Emit 120-bit chunks of full bytes (max is 127 but we avoid using partial bytes). + var n uintptr + for n = elemPtrs; n > 120; n -= 120 { + prog = append(prog, 120) + prog = append(prog, mask[:15]...) + mask = mask[15:] + } + prog = append(prog, byte(n)) + prog = append(prog, mask[:(n+7)/8]...) + } else { + // Element has GC program; emit one element. + elemProg := elemGC[4 : 4+*(*uint32)(unsafe.Pointer(&elemGC[0]))-1] + prog = append(prog, elemProg...) + } + // Pad from ptrdata to size. + elemWords := typ.size / ptrSize + if elemPtrs < elemWords { + // Emit literal 0 bit, then repeat as needed. + prog = append(prog, 0x01, 0x00) + if elemPtrs+1 < elemWords { + prog = append(prog, 0x81) + prog = appendVarint(prog, elemWords-elemPtrs-1) + } + } + // Repeat count-1 times. + if elemWords < 0x80 { + prog = append(prog, byte(elemWords|0x80)) + } else { + prog = append(prog, 0x80) + prog = appendVarint(prog, elemWords) + } + prog = appendVarint(prog, uintptr(count)-1) + prog = append(prog, 0) + *(*uint32)(unsafe.Pointer(&prog[0])) = uint32(len(prog) - 4) + array.kind |= kindGCProg + array.gcdata = &prog[0] + array.ptrdata = array.size // overestimate but ok; must match program } etyp := typ.common() @@ -1967,6 +1971,14 @@ func ArrayOf(count int, elem Type) Type { return cachePut(ckey, &array.rtype) } +func appendVarint(x []byte, v uintptr) []byte { + for ; v >= 0x80; v >>= 7 { + x = append(x, byte(v|0x80)) + } + x = append(x, byte(v)) + return x +} + // toType converts from a *rtype to a Type that can be returned // to the client of package reflect. In gc, the only concern is that // a nil *rtype must be replaced by a nil Type, but in gccgo this @@ -2003,7 +2015,7 @@ var layoutCache struct { // The returned type exists only for GC, so we only fill out GC relevant info. // Currently, that's just size and the GC program. We also fill in // the name for possible debugging use. -func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uintptr, stack *bitVector, framePool *sync.Pool) { +func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uintptr, stk *bitVector, framePool *sync.Pool) { if t.Kind() != Func { panic("reflect: funcLayout of non-func type") } @@ -2026,53 +2038,47 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin tt := (*funcType)(unsafe.Pointer(t)) // compute gc program & stack bitmap for arguments - stack = new(bitVector) - var gc gcProg + ptrmap := new(bitVector) var offset uintptr if rcvr != nil { // Reflect uses the "interface" calling convention for // methods, where receivers take one word of argument // space no matter how big they actually are. - if ifaceIndir(rcvr) { - // we pass a pointer to the receiver. - gc.append(1) - stack.append2(1) - } else if rcvr.pointers() { - // rcvr is a one-word pointer object. Its gc program - // is just what we need here. - gc.append(1) - stack.append2(1) - } else { - gc.append(0) - stack.append2(0) + if ifaceIndir(rcvr) || rcvr.pointers() { + ptrmap.append(1) } offset += ptrSize } for _, arg := range tt.in { - gc.appendProg(arg) - addTypeBits(stack, &offset, arg) + offset += -offset & uintptr(arg.align-1) + addTypeBits(ptrmap, offset, arg) + offset += arg.size } - argSize = gc.size + argN := ptrmap.n + argSize = offset if runtime.GOARCH == "amd64p32" { - gc.align(8) + offset += -offset & (8 - 1) } - gc.align(ptrSize) - retOffset = gc.size + offset += -offset & (ptrSize - 1) + retOffset = offset for _, res := range tt.out { - gc.appendProg(res) - // stack map does not need result bits + offset += -offset & uintptr(res.align-1) + addTypeBits(ptrmap, offset, res) + offset += res.size } - gc.align(ptrSize) + offset += -offset & (ptrSize - 1) // build dummy rtype holding gc program x := new(rtype) - x.size = gc.size - x.ptrdata = gc.size // over-approximation - var hasPtr bool - x.gc[0], hasPtr = gc.finalize() - if !hasPtr { + x.size = offset + x.ptrdata = uintptr(ptrmap.n) * ptrSize + if ptrmap.n > 0 { + x.gcdata = &ptrmap.data[0] + } else { x.kind |= kindNoPointers } + ptrmap.n = argN + var s string if rcvr != nil { s = "methodargs(" + *rcvr.string + ")(" + *t.string + ")" @@ -2092,11 +2098,11 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin t: x, argSize: argSize, retOffset: retOffset, - stack: stack, + stack: ptrmap, framePool: framePool, } layoutCache.Unlock() - return x, argSize, retOffset, stack, framePool + return x, argSize, retOffset, ptrmap, framePool } // ifaceIndir reports whether t is stored indirectly in an interface value. @@ -2110,56 +2116,49 @@ type bitVector struct { data []byte } -// append a bit pair to the bitmap. -func (bv *bitVector) append2(bits uint8) { - // assume bv.n is a multiple of 2, since append2 is the only operation. +// append a bit to the bitmap. +func (bv *bitVector) append(bit uint8) { if bv.n%8 == 0 { bv.data = append(bv.data, 0) } - bv.data[bv.n/8] |= bits << (bv.n % 8) - bv.n += 2 + bv.data[bv.n/8] |= bit << (bv.n % 8) + bv.n++ } -func addTypeBits(bv *bitVector, offset *uintptr, t *rtype) { - *offset = align(*offset, uintptr(t.align)) - if !t.pointers() { - *offset += t.size +func addTypeBits(bv *bitVector, offset uintptr, t *rtype) { + if t.kind&kindNoPointers != 0 { return } switch Kind(t.kind & kindMask) { case Chan, Func, Map, Ptr, Slice, String, UnsafePointer: // 1 pointer at start of representation - for bv.n < 2*uint32(*offset/uintptr(ptrSize)) { - bv.append2(0) + for bv.n < uint32(offset/uintptr(ptrSize)) { + bv.append(0) } - bv.append2(1) + bv.append(1) case Interface: // 2 pointers - for bv.n < 2*uint32(*offset/uintptr(ptrSize)) { - bv.append2(0) + for bv.n < uint32(offset/uintptr(ptrSize)) { + bv.append(0) } - bv.append2(1) - bv.append2(1) + bv.append(1) + bv.append(1) case Array: // repeat inner type tt := (*arrayType)(unsafe.Pointer(t)) for i := 0; i < int(tt.len); i++ { - addTypeBits(bv, offset, tt.elem) + addTypeBits(bv, offset+uintptr(i)*tt.elem.size, tt.elem) } case Struct: // apply fields tt := (*structType)(unsafe.Pointer(t)) - start := *offset for i := range tt.fields { f := &tt.fields[i] - off := start + f.offset - addTypeBits(bv, &off, f.typ) + addTypeBits(bv, offset+f.offset, f.typ) } } - - *offset += t.size } diff --git a/src/reflect/value.go b/src/reflect/value.go index fb9e85a8cf..91c38c9ffc 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -10,7 +10,7 @@ import ( "unsafe" ) -const ptrSize = unsafe.Sizeof((*byte)(nil)) +const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const const cannotSet = "cannot set value obtained from unexported struct field" // Value is the reflection interface to a Go value. diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go index 546c331614..39bb4217b3 100644 --- a/src/runtime/mbitmap.go +++ b/src/runtime/mbitmap.go @@ -547,8 +547,6 @@ func heapBitsSweepSpan(base, size, n uintptr, f func(uintptr)) { } } -// TODO(rsc): Clean up the next two functions. - // heapBitsSetType records that the new allocation [x, x+size) // holds in [x, x+dataSize) one or more values of type typ. // (The number of values is given by dataSize / typ.size.) @@ -569,11 +567,7 @@ func heapBitsSweepSpan(base, size, n uintptr, f func(uintptr)) { // but if the start or end of x shares a bitmap byte with an adjacent // object, the GC marker is racing with updates to those object's mark bits. func heapBitsSetType(x, size, dataSize uintptr, typ *_type) { - const doubleCheck = false // slow but helpful; enable to test modifications to this function - - // From here till marked label marking the object as allocated - // and storing type info in the GC bitmap. - h := heapBitsForAddr(x) + const doubleCheck = false // slow but helpful; enable to test modifications to this code // dataSize is always size rounded up to the next malloc size class, // except in the case of allocating a defer block, in which case @@ -593,6 +587,7 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) { // (non-pointers are aggregated into tinySize allocations), // initSpan sets the pointer bits for us. Nothing to do here. if doubleCheck { + h := heapBitsForAddr(x) if !h.isPointer() { throw("heapBitsSetType: pointer bit missing") } @@ -600,33 +595,8 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) { return } - ptrmask := (*uint8)(unsafe.Pointer(typ.gc[0])) // pointer to unrolled mask - if typ.kind&kindGCProg != 0 { - nptr := typ.ptrdata / ptrSize - masksize := (nptr + 7) / 8 - masksize++ // unroll flag in the beginning - if masksize > maxGCMask && typ.gc[1] != 0 { - // write barriers have not been updated to deal with this case yet. - throw("maxGCMask too small for now") - // If the mask is too large, unroll the program directly - // into the GC bitmap. It's 7 times slower than copying - // from the pre-unrolled mask, but saves 1/16 of type size - // memory for the mask. - systemstack(func() { - unrollgcproginplace_m(unsafe.Pointer(x), typ, size, dataSize) - }) - return - } - // Check whether the program is already unrolled - // by checking if the unroll flag byte is set - maskword := uintptr(atomicloadp(unsafe.Pointer(ptrmask))) - if *(*uint8)(unsafe.Pointer(&maskword)) == 0 { - systemstack(func() { - unrollgcprog_m(typ) - }) - } - ptrmask = add1(ptrmask) // skip the unroll flag byte - } + h := heapBitsForAddr(x) + ptrmask := typ.gcdata // start of 1-bit pointer mask (or GC program, handled below) // Heap bitmap bits for 2-word object are only 4 bits, // so also shared with objects next to it; use atomic updates. @@ -661,6 +631,12 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) { return } // Otherwise typ.size must be 2*ptrSize, and typ.kind&kindGCProg == 0. + if doubleCheck { + if typ.size != 2*ptrSize || typ.kind&kindGCProg != 0 { + print("runtime: heapBitsSetType size=", size, " but typ.size=", typ.size, " gcprog=", typ.kind&kindGCProg != 0, "\n") + throw("heapBitsSetType") + } + } b := uint32(*ptrmask) hb := b & 3 if gcphase == _GCoff { @@ -678,16 +654,49 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) { // This is a lot of lines of code, but it compiles into relatively few // machine instructions. - // Ptrmask buffer. var ( + // Ptrmask input. p *byte // last ptrmask byte read b uintptr // ptrmask bits already loaded nb uintptr // number of bits in b at next read endp *byte // final ptrmask byte to read (then repeat) endnb uintptr // number of valid bits in *endp pbits uintptr // alternate source of bits + + // Heap bitmap output. + w uintptr // words processed + nw uintptr // number of words to process + hbitp *byte // next heap bitmap byte to write + hb uintptr // bits being prepared for *hbitp ) + hbitp = h.bitp + + // Handle GC program. Delayed until this part of the code + // so that we can use the same double-checking mechanism + // as the 1-bit case. Nothing above could have encountered + // GC programs: the cases were all too small. + if typ.kind&kindGCProg != 0 { + heapBitsSetTypeGCProg(h, typ.ptrdata, typ.size, dataSize, size, addb(typ.gcdata, 4)) + if doubleCheck { + // Double-check the heap bits written by GC program + // by running the GC program to create a 1-bit pointer mask + // and then jumping to the double-check code below. + // This doesn't catch bugs shared between the 1-bit and 4-bit + // GC program execution, but it does catch mistakes specific + // to just one of those and bugs in heapBitsSetTypeGCProg's + // implementation of arrays. + lock(&debugPtrmask.lock) + if debugPtrmask.data == nil { + debugPtrmask.data = (*byte)(persistentalloc(1<<20, 1, &memstats.other_sys)) + } + ptrmask = debugPtrmask.data + runGCProg(addb(typ.gcdata, 4), nil, ptrmask, 1) + goto Phase4 + } + return + } + // Note about sizes: // // typ.size is the number of words in the object, @@ -780,8 +789,6 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) { nb = 8 } - var w uintptr // words processed - var nw uintptr // number of words to process if typ.size == dataSize { // Single entry: can stop once we reach the non-pointer data. nw = typ.ptrdata / ptrSize @@ -803,9 +810,6 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) { nw = 2 } - hbitp := h.bitp // next heap bitmap byte to write - var hb uintptr // bits being preapred for *h.bitp - // Phase 1: Special case for leading byte (shift==0) or half-byte (shift==4). // The leading byte is special because it contains the bits for words 0 and 1, // which do not have the marked bits set. @@ -967,10 +971,11 @@ Phase3: } } +Phase4: // Phase 4: all done, but perhaps double check. if doubleCheck { end := heapBitsForAddr(x + size) - if hbitp != end.bitp || (w == nw+2) != (end.shift == 2) { + if typ.kind&kindGCProg == 0 && (hbitp != end.bitp || (w == nw+2) != (end.shift == 2)) { println("ended at wrong bitmap byte for", *typ._string, "x", dataSize/typ.size) print("typ.size=", typ.size, " typ.ptrdata=", typ.ptrdata, " dataSize=", dataSize, " size=", size, "\n") print("w=", w, " nw=", nw, " b=", hex(b), " nb=", nb, " hb=", hex(hb), "\n") @@ -986,15 +991,16 @@ Phase3: nptr := typ.ptrdata / ptrSize ndata := typ.size / ptrSize count := dataSize / typ.size - for i := uintptr(0); i <= dataSize/ptrSize; i++ { + totalptr := ((count-1)*typ.size + typ.ptrdata) / ptrSize + for i := uintptr(0); i < size/ptrSize; i++ { j := i % ndata var have, want uint8 - if i == dataSize/ptrSize && dataSize >= size { - break - } have = (*h.bitp >> h.shift) & (bitPointer | bitMarked) - if i == dataSize/ptrSize || i/ndata == count-1 && j >= nptr { - want = 0 // dead marker + if i >= totalptr { + want = 0 // deadmarker + if typ.kind&kindGCProg != 0 && i < (totalptr+3)/4*4 { + want = bitMarked + } } else { if j < nptr && (*addb(ptrmask, j/8)>>(j%8))&1 != 0 { want |= bitPointer @@ -1008,177 +1014,483 @@ Phase3: if have != want { println("mismatch writing bits for", *typ._string, "x", dataSize/typ.size) print("typ.size=", typ.size, " typ.ptrdata=", typ.ptrdata, " dataSize=", dataSize, " size=", size, "\n") + print("kindGCProg=", typ.kind&kindGCProg != 0, "\n") print("w=", w, " nw=", nw, " b=", hex(b), " nb=", nb, " hb=", hex(hb), "\n") h0 := heapBitsForAddr(x) print("initial bits h0.bitp=", h0.bitp, " h0.shift=", h0.shift, "\n") print("current bits h.bitp=", h.bitp, " h.shift=", h.shift, " *h.bitp=", hex(*h.bitp), "\n") print("ptrmask=", ptrmask, " p=", p, " endp=", endp, " endnb=", endnb, " pbits=", hex(pbits), " b=", hex(b), " nb=", nb, "\n") println("at word", i, "offset", i*ptrSize, "have", have, "want", want) + if typ.kind&kindGCProg != 0 { + println("GC program:") + dumpGCProg(addb(typ.gcdata, 4)) + } throw("bad heapBitsSetType") } h = h.next() } + if ptrmask == debugPtrmask.data { + unlock(&debugPtrmask.lock) + } } } -// GC type info programs +var debugPtrmask struct { + lock mutex + data *byte +} + +// heapBitsSetTypeGCProg implements heapBitsSetType using a GC program. +// progSize is the size of the memory described by the program. +// elemSize is the size of the element that the GC program describes (a prefix of). +// dataSize is the total size of the intended data, a multiple of elemSize. +// allocSize is the total size of the allocated memory. // -// TODO(rsc): Clean up and enable. +// GC programs are only used for large allocations. +// heapBitsSetType requires that allocSize is a multiple of 4 words, +// so that the relevant bitmap bytes are not shared with surrounding +// objects and need not be accessed with atomic instructions. +func heapBitsSetTypeGCProg(h heapBits, progSize, elemSize, dataSize, allocSize uintptr, prog *byte) { + if ptrSize == 8 && allocSize%(4*ptrSize) != 0 { + // Alignment will be wrong. + throw("heapBitsSetTypeGCProg: small allocation") + } + var totalBits uintptr + if elemSize == dataSize { + totalBits = runGCProg(prog, nil, h.bitp, 2) + if totalBits*ptrSize != progSize { + println("runtime: heapBitsSetTypeGCProg: total bits", totalBits, "but progSize", progSize) + throw("heapBitsSetTypeGCProg: unexpected bit count") + } + } else { + count := dataSize / elemSize -const ( - // GC type info programs. - // The programs allow to store type info required for GC in a compact form. - // Most importantly arrays take O(1) space instead of O(n). - // The program grammar is: - // - // Program = {Block} "insEnd" - // Block = Data | Array - // Data = "insData" DataSize DataBlock - // DataSize = int // size of the DataBlock in bit pairs, 1 byte - // DataBlock = binary // dense GC mask (2 bits per word) of size ]DataSize/4[ bytes - // Array = "insArray" ArrayLen Block "insArrayEnd" - // ArrayLen = int // length of the array, 8 bytes (4 bytes for 32-bit arch) - // - // Each instruction (insData, insArray, etc) is 1 byte. - // For example, for type struct { x []byte; y [20]struct{ z int; w *byte }; } - // the program looks as: - // - // insData 3 (typePointer typeScalar typeScalar) - // insArray 20 insData 2 (typeScalar typePointer) insArrayEnd insEnd - // - // Total size of the program is 17 bytes (13 bytes on 32-bits). - // The corresponding GC mask would take 43 bytes (it would be repeated - // because the type has odd number of words). - insData = 1 + iota - insArray - insArrayEnd - insEnd + // Piece together program trailer to run after prog that does: + // literal(0) + // repeat(1, elemSize-progSize-1) // zeros to fill element size + // repeat(elemSize, count-1) // repeat that element for count + // This zero-pads the data remaining in the first element and then + // repeats that first element to fill the array. + var trailer [40]byte // 3 varints (max 10 each) + some bytes + i := 0 + if n := elemSize/ptrSize - progSize/ptrSize; n > 0 { + // literal(0) + trailer[i] = 0x01 + i++ + trailer[i] = 0 + i++ + if n > 1 { + // repeat(1, n-1) + trailer[i] = 0x81 + i++ + n-- + for ; n >= 0x80; n >>= 7 { + trailer[i] = byte(n | 0x80) + i++ + } + trailer[i] = byte(n) + i++ + } + } + // repeat(elemSize/ptrSize, count-1) + trailer[i] = 0x80 + i++ + n := elemSize / ptrSize + for ; n >= 0x80; n >>= 7 { + trailer[i] = byte(n | 0x80) + i++ + } + trailer[i] = byte(n) + i++ + n = count + for ; n >= 0x80; n >>= 7 { + trailer[i] = byte(n | 0x80) + i++ + } + trailer[i] = byte(n) + i++ + trailer[i] = 0 + i++ - // 64 bytes cover objects of size 1024/512 on 64/32 bits, respectively. - maxGCMask = 65536 // TODO(rsc): change back to 64 -) + runGCProg(prog, &trailer[0], h.bitp, 2) -// Recursively unrolls GC program in prog. -// mask is where to store the result. -// If inplace is true, store the result not in mask but in the heap bitmap for mask. -// ppos is a pointer to position in mask, in bits. -// sparse says to generate 4-bits per word mask for heap (1-bit for data/bss otherwise). -//go:nowritebarrier -func unrollgcprog1(maskp *byte, prog *byte, ppos *uintptr, inplace bool) *byte { - pos := *ppos - mask := (*[1 << 30]byte)(unsafe.Pointer(maskp)) + // Even though we filled in the full array just now, + // record that we only filled in up to the ptrdata of the + // last element. This will cause the code below to + // memclr the dead section of the final array element, + // so that scanobject can stop early in the final element. + totalBits = (elemSize*(count-1) + progSize) / ptrSize + } + endProg := unsafe.Pointer(subtractb(h.bitp, (totalBits+3)/4)) + endAlloc := unsafe.Pointer(subtractb(h.bitp, allocSize/heapBitmapScale)) + memclr(add(endAlloc, 1), uintptr(endProg)-uintptr(endAlloc)) +} + +// progToPointerMask returns the 1-bit pointer mask output by the GC program prog. +// size the size of the region described by prog, in bytes. +// The resulting bitvector will have no more than size/ptrSize bits. +func progToPointerMask(prog *byte, size uintptr) bitvector { + n := (size/ptrSize + 7) / 8 + x := (*[1 << 30]byte)(persistentalloc(n+1, 1, &memstats.buckhash_sys))[:n+1] + x[len(x)-1] = 0xa1 // overflow check sentinel + n = runGCProg(prog, nil, &x[0], 1) + if x[len(x)-1] != 0xa1 { + throw("progToPointerMask: overflow") + } + return bitvector{int32(n), &x[0]} +} + +// Packed GC pointer bitmaps, aka GC programs. +// +// For large types containing arrays, the type information has a +// natural repetition that can be encoded to save space in the +// binary and in the memory representation of the type information. +// +// The encoding is a simple Lempel-Ziv style bytecode machine +// with the following instructions: +// +// 00000000: stop +// 0nnnnnnn: emit n bits copied from the next (n+7)/8 bytes +// 10000000 n c: repeat the previous n bits c times; n, c are varints +// 1nnnnnnn c: repeat the previous n bits c times; c is a varint + +// runGCProg executes the GC program prog, and then trailer if non-nil, +// writing to dst with entries of the given size. +// If size == 1, dst is a 1-bit pointer mask laid out moving forward from dst. +// If size == 2, dst is the 2-bit heap bitmap, and writes move backward +// starting at dst (because the heap bitmap does). In this case, the caller guarantees +// that only whole bytes in dst need to be written. +// +// runGCProg returns the number of 1- or 2-bit entries written to memory. +func runGCProg(prog, trailer, dst *byte, size int) uintptr { + dstStart := dst + + // Bits waiting to be written to memory. + var bits uintptr + var nbits uintptr + + p := prog +Run: for { - switch *prog { - default: - throw("unrollgcprog: unknown instruction") + // Flush accumulated full bytes. + // The rest of the loop assumes that nbits <= 7. + for ; nbits >= 8; nbits -= 8 { + if size == 1 { + *dst = uint8(bits) + dst = add1(dst) + bits >>= 8 + } else { + v := bits&bitPointerAll | bitMarkedAll + *dst = uint8(v) + dst = subtract1(dst) + bits >>= 4 + v = bits&bitPointerAll | bitMarkedAll + *dst = uint8(v) + dst = subtract1(dst) + bits >>= 4 + } + } - case insData: - prog = add1(prog) - siz := int(*prog) - prog = add1(prog) - p := (*[1 << 30]byte)(unsafe.Pointer(prog)) - for i := 0; i < siz; i++ { - v := p[i/8] >> (uint(i) % 8) & 1 - if inplace { - throw("gc inplace") - const typeShift = 2 - // Store directly into GC bitmap. - h := heapBitsForAddr(uintptr(unsafe.Pointer(&mask[pos]))) - if h.shift == 0 { - *h.bitp = v << typeShift - } else { - *h.bitp |= v << (4 + typeShift) - } - pos += ptrSize + // Process one instruction. + inst := uintptr(*p) + p = add1(p) + n := inst & 0x7F + if inst&0x80 == 0 { + // Literal bits; n == 0 means end of program. + if n == 0 { + // Program is over; continue in trailer if present. + if trailer != nil { + //println("trailer") + p = trailer + trailer = nil + continue + } + //println("done") + break Run + } + //println("lit", n, dst) + nbyte := n / 8 + for i := uintptr(0); i < nbyte; i++ { + bits |= uintptr(*p) << nbits + p = add1(p) + if size == 1 { + *dst = uint8(bits) + dst = add1(dst) + bits >>= 8 } else { - // 1 bit per word, for data/bss bitmap - mask[pos/8] |= v << (pos % 8) - pos++ + v := bits&0xf | bitMarkedAll + *dst = uint8(v) + dst = subtract1(dst) + bits >>= 4 + v = bits&0xf | bitMarkedAll + *dst = uint8(v) + dst = subtract1(dst) + bits >>= 4 } } - prog = addb(prog, (uintptr(siz)+7)/8) + if n %= 8; n > 0 { + bits |= uintptr(*p) << nbits + p = add1(p) + nbits += n + } + continue Run + } - case insArray: - prog = (*byte)(add(unsafe.Pointer(prog), 1)) - siz := uintptr(0) - for i := uintptr(0); i < ptrSize; i++ { - siz = (siz << 8) + uintptr(*(*byte)(add(unsafe.Pointer(prog), ptrSize-i-1))) + // Repeat. If n == 0, it is encoded in a varint in the next bytes. + if n == 0 { + for off := uint(0); ; off += 7 { + x := uintptr(*p) + p = add1(p) + n |= (x & 0x7F) << off + if x&0x80 == 0 { + break + } } - prog = (*byte)(add(unsafe.Pointer(prog), ptrSize)) - var prog1 *byte - for i := uintptr(0); i < siz; i++ { - prog1 = unrollgcprog1(&mask[0], prog, &pos, inplace) - } - if *prog1 != insArrayEnd { - throw("unrollgcprog: array does not end with insArrayEnd") - } - prog = (*byte)(add(unsafe.Pointer(prog1), 1)) + } - case insArrayEnd, insEnd: - *ppos = pos - return prog + // Count is encoded in a varint in the next bytes. + c := uintptr(0) + for off := uint(0); ; off += 7 { + x := uintptr(*p) + p = add1(p) + c |= (x & 0x7F) << off + if x&0x80 == 0 { + break + } + } + c *= n // now total number of bits to copy + + // If the number of bits being repeated is small, load them + // into a register and use that register for the entire loop + // instead of repeatedly reading from memory. + // Handling fewer than 8 bits here makes the general loop simpler. + // The cutoff is ptrSize*8 - 7 to guarantee that when we add + // the pattern to a bit buffer holding at most 7 bits (a partial byte) + // it will not overflow. + src := dst + const maxBits = ptrSize*8 - 7 + if n <= maxBits { + // Start with bits in output buffer. + pattern := bits + npattern := nbits + + // If we need more bits, fetch them from memory. + if size == 1 { + src = subtract1(src) + for npattern < n { + pattern <<= 8 + pattern |= uintptr(*src) + src = subtract1(src) + npattern += 8 + } + } else { + src = add1(src) + for npattern < n { + pattern <<= 4 + pattern |= uintptr(*src) & 0xf + src = add1(src) + npattern += 4 + } + } + + // We started with the whole bit output buffer, + // and then we loaded bits from whole bytes. + // Either way, we might now have too many instead of too few. + // Discard the extra. + if npattern > n { + pattern >>= npattern - n + npattern = n + } + + // Replicate pattern to at most maxBits. + if npattern == 1 { + // One bit being repeated. + // If the bit is 1, make the pattern all 1s. + // If the bit is 0, the pattern is already all 0s, + // but we can claim that the number of bits + // in the word is equal to the number we need (c), + // because right shift of bits will zero fill. + if pattern == 1 { + pattern = 1< 8 bits, there will be full bytes to flush + // on each iteration. + for ; c >= npattern; c -= npattern { + bits |= pattern << nbits + nbits += npattern + if size == 1 { + for nbits >= 8 { + *dst = uint8(bits) + dst = add1(dst) + bits >>= 8 + nbits -= 8 + } + } else { + for nbits >= 4 { + *dst = uint8(bits&0xf | bitMarkedAll) + dst = subtract1(dst) + bits >>= 4 + nbits -= 4 + } + } + } + + // Add final fragment to bit buffer. + if c > 0 { + pattern &= 1< nbits because n > maxBits and nbits <= 7 + if size == 1 { + // Leading src fragment. + src = subtractb(src, (off+7)/8) + if frag := off & 7; frag != 0 { + bits |= uintptr(*src) >> (8 - frag) << nbits + src = add1(src) + nbits += frag + c -= frag + } + // Main loop: load one byte, write another. + // The bits are rotating through the bit buffer. + for i := c / 8; i > 0; i-- { + bits |= uintptr(*src) << nbits + src = add1(src) + *dst = uint8(bits) + dst = add1(dst) + bits >>= 8 + } + // Final src fragment. + if c %= 8; c > 0 { + bits |= (uintptr(*src) & (1< > (4 - frag) << nbits + src = subtract1(src) + nbits += frag + c -= frag + } + // Main loop: load one byte, write another. + // The bits are rotating through the bit buffer. + for i := c / 4; i > 0; i-- { + bits |= (uintptr(*src) & 0xf) << nbits + src = subtract1(src) + *dst = uint8(bits&0xf | bitMarkedAll) + dst = subtract1(dst) + bits >>= 4 + } + // Final src fragment. + if c %= 4; c > 0 { + bits |= (uintptr(*src) & (1< 0; nbits -= 8 { + *dst = uint8(bits) + dst = add1(dst) + bits >>= 8 + } + } else { + totalBits = (uintptr(unsafe.Pointer(dstStart))-uintptr(unsafe.Pointer(dst)))*4 + nbits + nbits += -nbits & 3 + for ; nbits > 0; nbits -= 4 { + v := bits&0xf | bitMarkedAll + *dst = uint8(v) + dst = subtract1(dst) + bits >>= 4 + } + // Clear the mark bits in the first two entries. + // They are the actual mark and checkmark bits, + // not non-dead markers. It simplified the code + // above to set the marker in every bit written and + // then clear these two as a special case at the end. + *dstStart &^= bitMarked | bitMarked< nptr && ret[len(ret)-1] == 0 { + ret = ret[:len(ret)-1] + } + return ret +} + // Returns GC type info for object p for testing. func getgcmask(ep interface{}) (mask []byte) { e := *(*eface)(unsafe.Pointer(&ep)) @@ -1243,36 +1568,43 @@ func getgcmask(ep interface{}) (mask []byte) { } // stack - var frame stkframe - frame.sp = uintptr(p) - _g_ := getg() - gentraceback(_g_.m.curg.sched.pc, _g_.m.curg.sched.sp, 0, _g_.m.curg, 0, nil, 1000, getgcmaskcb, noescape(unsafe.Pointer(&frame)), 0) - if frame.fn != nil { - f := frame.fn - targetpc := frame.continpc - if targetpc == 0 { - return - } - if targetpc != f.entry { - targetpc-- - } - pcdata := pcdatavalue(f, _PCDATA_StackMapIndex, targetpc) - if pcdata == -1 { - return - } - stkmap := (*stackmap)(funcdata(f, _FUNCDATA_LocalsPointerMaps)) - if stkmap == nil || stkmap.n <= 0 { - return - } - bv := stackmapdata(stkmap, pcdata) - size := uintptr(bv.n) * ptrSize - n := (*ptrtype)(unsafe.Pointer(t)).elem.size - mask = make([]byte, n/ptrSize) - for i := uintptr(0); i < n; i += ptrSize { - bitmap := bv.bytedata - off := (uintptr(p) + i - frame.varp + size) / ptrSize - mask[i/ptrSize] = (*addb(bitmap, off/8) >> (off % 8)) & 1 + if _g_ := getg(); _g_.m.curg.stack.lo <= uintptr(p) && uintptr(p) < _g_.m.curg.stack.hi { + var frame stkframe + frame.sp = uintptr(p) + _g_ := getg() + gentraceback(_g_.m.curg.sched.pc, _g_.m.curg.sched.sp, 0, _g_.m.curg, 0, nil, 1000, getgcmaskcb, noescape(unsafe.Pointer(&frame)), 0) + if frame.fn != nil { + f := frame.fn + targetpc := frame.continpc + if targetpc == 0 { + return + } + if targetpc != f.entry { + targetpc-- + } + pcdata := pcdatavalue(f, _PCDATA_StackMapIndex, targetpc) + if pcdata == -1 { + return + } + stkmap := (*stackmap)(funcdata(f, _FUNCDATA_LocalsPointerMaps)) + if stkmap == nil || stkmap.n <= 0 { + return + } + bv := stackmapdata(stkmap, pcdata) + size := uintptr(bv.n) * ptrSize + n := (*ptrtype)(unsafe.Pointer(t)).elem.size + mask = make([]byte, n/ptrSize) + for i := uintptr(0); i < n; i += ptrSize { + bitmap := bv.bytedata + off := (uintptr(p) + i - frame.varp + size) / ptrSize + mask[i/ptrSize] = (*addb(bitmap, off/8) >> (off % 8)) & 1 + } } + return } + + // otherwise, not something the GC knows about. + // possibly read-only data, like malloc(0). + // must not have pointers return } diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index 11e885f928..d33fbf11de 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -146,8 +146,8 @@ func gcinit() { work.markfor = parforalloc(_MaxGcproc) _ = setGCPercent(readgogc()) for datap := &firstmoduledata; datap != nil; datap = datap.next { - datap.gcdatamask = unrollglobgcprog((*byte)(unsafe.Pointer(datap.gcdata)), datap.edata-datap.data) - datap.gcbssmask = unrollglobgcprog((*byte)(unsafe.Pointer(datap.gcbss)), datap.ebss-datap.bss) + datap.gcdatamask = progToPointerMask((*byte)(unsafe.Pointer(datap.gcdata)), datap.edata-datap.data) + datap.gcbssmask = progToPointerMask((*byte)(unsafe.Pointer(datap.gcbss)), datap.ebss-datap.bss) } memstats.next_gc = heapminimum } diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go index 9afa954259..687f067cb9 100644 --- a/src/runtime/symtab.go +++ b/src/runtime/symtab.go @@ -32,6 +32,8 @@ const ( // moduledata records information about the layout of the executable // image. It is written by the linker. Any changes here must be // matched changes to the code in cmd/internal/ld/symtab.go:symtab. +// moduledata is stored in read-only memory; none of the pointers here +// are visible to the garbage collector. type moduledata struct { pclntable []byte ftab []functab diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index 0f29608aae..12b2a53603 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -469,7 +469,7 @@ func setArgInfo(frame *stkframe, f *_func, needArgMap bool) { throw("reflect mismatch") } bv := (*bitvector)(unsafe.Pointer(fn[1])) - frame.arglen = uintptr(bv.n / 2 * ptrSize) + frame.arglen = uintptr(bv.n * ptrSize) frame.argmap = bv } } diff --git a/src/runtime/type.go b/src/runtime/type.go index 48df2a4382..45bdac8b91 100644 --- a/src/runtime/type.go +++ b/src/runtime/type.go @@ -20,17 +20,10 @@ type _type struct { fieldalign uint8 kind uint8 alg *typeAlg - // gc stores type info required for garbage collector. - // If (kind&KindGCProg)==0, then gc[0] points at sparse GC bitmap - // (no indirection), 4 bits per word. - // If (kind&KindGCProg)!=0, then gc[1] points to a compiler-generated - // read-only GC program; and gc[0] points to BSS space for sparse GC bitmap. - // For huge types (>maxGCMask), runtime unrolls the program directly into - // GC bitmap and gc[0] is not used. For moderately-sized types, runtime - // unrolls the program into gc[0] space on first use. The first byte of gc[0] - // (gc[0][0]) contains 'unroll' flag saying whether the program is already - // unrolled into gc[0] or not. - gc [2]uintptr + // gcdata stores the GC type data for the garbage collector. + // If the KindGCProg bit is set in kind, gcdata is a GC program. + // Otherwise it is a ptrmask bitmap. See mbitmap.go for details. + gcdata *byte _string *string x *uncommontype ptrto *_type From d36cc027959170c9927a52f139482d2369f173af Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 15 May 2015 14:46:20 -0400 Subject: [PATCH 124/232] reflect: make PtrTo(FuncOf(...)) not crash Change-Id: Ie67e295bf327126dfdc75b73979fe33fbcb79ad9 Reviewed-on: https://go-review.googlesource.com/10150 Reviewed-by: Austin Clements --- src/reflect/all_test.go | 23 ++++++++++++++++++++++- src/reflect/type.go | 2 +- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index 9214577c2e..9a99f742d6 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -4618,7 +4618,7 @@ func TestGCBits(t *testing.T) { verifyGCBits(t, ChanOf(BothDir, ArrayOf(100, Tscalar)), lit(1)) verifyGCBits(t, TypeOf((func([100]Xscalarptr))(nil)), lit(1)) - //verifyGCBits(t, FuncOf([]Type{ArrayOf(100, Tscalarptr)}, nil, false), lit(1)) + verifyGCBits(t, FuncOf([]Type{ArrayOf(100, Tscalarptr)}, nil, false), lit(1)) verifyGCBits(t, TypeOf((map[[100]Xscalarptr]Xscalar)(nil)), lit(1)) verifyGCBits(t, MapOf(ArrayOf(100, Tscalarptr), Tscalar), lit(1)) @@ -4643,3 +4643,24 @@ func TestGCBits(t *testing.T) { func rep(n int, b []byte) []byte { return bytes.Repeat(b, n) } func join(b ...[]byte) []byte { return bytes.Join(b, nil) } func lit(x ...byte) []byte { return x } + +func TestTypeOfTypeOf(t *testing.T) { + // Check that all the type constructors return concrete *rtype implementations. + // It's difficult to test directly because the reflect package is only at arm's length. + // The easiest thing to do is just call a function that crashes if it doesn't get an *rtype. + check := func(name string, typ Type) { + if underlying := TypeOf(typ).String(); underlying != "*reflect.rtype" { + t.Errorf("%v returned %v, not *reflect.rtype", name, underlying) + } + } + + type T struct{ int } + check("TypeOf", TypeOf(T{})) + + check("ArrayOf", ArrayOf(10, TypeOf(T{}))) + check("ChanOf", ChanOf(BothDir, TypeOf(T{}))) + check("FuncOf", FuncOf([]Type{TypeOf(T{})}, nil, false)) + check("MapOf", MapOf(TypeOf(T{}), TypeOf(T{}))) + check("PtrTo", PtrTo(TypeOf(T{}))) + check("SliceOf", SliceOf(TypeOf(T{}))) +} diff --git a/src/reflect/type.go b/src/reflect/type.go index f39ba52a42..e55a0d146c 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -1609,7 +1609,7 @@ func FuncOf(in, out []Type, variadic bool) Type { ft.ptrToThis = nil funcLookupCache.m[hash] = append(funcLookupCache.m[hash], &ft.rtype) - return ft + return &ft.rtype } // funcStr builds a string representation of a funcType. From 6e8bcbbe8987d9b06ef2c349913cde11e6dd8339 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 15 May 2015 16:11:25 -0400 Subject: [PATCH 125/232] cmd/internal/gc: refine ginscmp comment Change-Id: I2ebb36c6c5de9d34e52ed523e9c888452591924a Reviewed-on: https://go-review.googlesource.com/10152 Reviewed-by: Minux Ma --- src/cmd/internal/gc/go.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cmd/internal/gc/go.go b/src/cmd/internal/gc/go.go index 31692bdf00..5fa85e25a7 100644 --- a/src/cmd/internal/gc/go.go +++ b/src/cmd/internal/gc/go.go @@ -786,8 +786,9 @@ type Arch struct { // // Ginscmp must be able to handle all kinds of arguments for n1 and n2, // not just simple registers, although it can assume that there are no - // function calls needed during the evaluation, so no in-memory temporaries - // are necessary. + // function calls needed during the evaluation, and on 32-bit systems + // the values are guaranteed not to be 64-bit values, so no in-memory + // temporaries are necessary. Ginscmp func(op int, t *Type, n1, n2 *Node, likely int) *obj.Prog // Ginsboolval inserts instructions to convert the result From ab4e7988bb30eaf43ef9c5b4dcedc30502a0b0e6 Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Fri, 1 May 2015 22:23:04 -0400 Subject: [PATCH 126/232] cmd/dist: add -k to "dist test" to keep going after error Fixes #10336. Change-Id: Idc3f60851aea590575dc293165d4d6f85ae001bc Reviewed-on: https://go-review.googlesource.com/9645 Reviewed-by: Brad Fitzpatrick --- src/cmd/dist/test.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index addf61dad9..1f26eef5ee 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -24,6 +24,7 @@ func cmdtest() { var t tester flag.BoolVar(&t.listMode, "list", false, "list available tests") flag.BoolVar(&t.noRebuild, "no-rebuild", false, "don't rebuild std and cmd packages") + flag.BoolVar(&t.keepGoing, "k", false, "keep going even when error occurred") flag.StringVar(&t.banner, "banner", "##### ", "banner prefix; blank means no section banners") flag.StringVar(&t.runRxStr, "run", os.Getenv("GOTESTONLY"), "run only those tests matching the regular expression; empty means to run all. "+ @@ -36,6 +37,7 @@ func cmdtest() { type tester struct { listMode bool noRebuild bool + keepGoing bool runRxStr string runRx *regexp.Regexp runRxWant bool @@ -163,6 +165,7 @@ func (t *tester) run() { os.Unsetenv("GOROOT_FINAL") var lastHeading string + ok := true for _, dt := range t.tests { if t.runRx != nil && (t.runRx.MatchString(dt.name) != t.runRxWant) { t.partial = true @@ -176,10 +179,18 @@ func (t *tester) run() { fmt.Printf("# go tool dist test -run=^%s$\n", dt.name) } if err := dt.fn(); err != nil { - log.Fatalf("Failed: %v", err) + ok = false + if t.keepGoing { + log.Printf("Failed: %v", err) + } else { + log.Fatalf("Failed: %v", err) + } } } - if t.partial { + if !ok { + fmt.Println("\nFAILED") + os.Exit(1) + } else if t.partial { fmt.Println("\nALL TESTS PASSED (some were excluded)") } else { fmt.Println("\nALL TESTS PASSED") From a0fc306023d77e5605203c14ca92f368bdbce3ae Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Wed, 13 May 2015 17:08:16 -0400 Subject: [PATCH 127/232] runtime: eliminate runqvictims and a copy from runqsteal Currently, runqsteal steals Gs from another P into an intermediate buffer and then copies those Gs into the current P's run queue. This intermediate buffer itself was moved from the stack to the P in commit c4fe503 to eliminate the cost of zeroing it on every steal. This commit follows up c4fe503 by stealing directly into the current P's run queue, which eliminates the copy and the need for the intermediate buffer. The update to the tail pointer is only committed once the entire steal operation has succeeded, so the semantics of stealing do not change. Change-Id: Icdd7a0eb82668980bf42c0154b51eef6419fdd51 Reviewed-on: https://go-review.googlesource.com/9998 Reviewed-by: Russ Cox Run-TryBot: Austin Clements --- src/runtime/proc1.go | 21 ++++++++++----------- src/runtime/runtime2.go | 7 +++---- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/runtime/proc1.go b/src/runtime/proc1.go index 8aeacee747..4ce756b692 100644 --- a/src/runtime/proc1.go +++ b/src/runtime/proc1.go @@ -3460,10 +3460,11 @@ func runqget(_p_ *p) (gp *g, inheritTime bool) { } } -// Grabs a batch of goroutines from local runnable queue. -// batch array must be of size len(p->runq)/2. Returns number of grabbed goroutines. +// Grabs a batch of goroutines from _p_'s runnable queue into batch. +// Batch is a ring buffer starting at batchHead. +// Returns number of grabbed goroutines. // Can be executed by any P. -func runqgrab(_p_ *p, batch []*g, stealRunNextG bool) uint32 { +func runqgrab(_p_ *p, batch *[256]*g, batchHead uint32, stealRunNextG bool) uint32 { for { h := atomicload(&_p_.runqhead) // load-acquire, synchronize with other consumers t := atomicload(&_p_.runqtail) // load-acquire, synchronize with the producer @@ -3484,7 +3485,7 @@ func runqgrab(_p_ *p, batch []*g, stealRunNextG bool) uint32 { if !_p_.runnext.cas(next, 0) { continue } - batch[0] = next.ptr() + batch[batchHead%uint32(len(batch))] = next.ptr() return 1 } } @@ -3494,7 +3495,8 @@ func runqgrab(_p_ *p, batch []*g, stealRunNextG bool) uint32 { continue } for i := uint32(0); i < n; i++ { - batch[i] = _p_.runq[(h+i)%uint32(len(_p_.runq))] + g := _p_.runq[(h+i)%uint32(len(_p_.runq))] + batch[(batchHead+i)%uint32(len(batch))] = g } if cas(&_p_.runqhead, h, h+n) { // cas-release, commits consume return n @@ -3506,23 +3508,20 @@ func runqgrab(_p_ *p, batch []*g, stealRunNextG bool) uint32 { // and put onto local runnable queue of p. // Returns one of the stolen elements (or nil if failed). func runqsteal(_p_, p2 *p, stealRunNextG bool) *g { - n := runqgrab(p2, _p_.runqvictims[:], stealRunNextG) + t := _p_.runqtail + n := runqgrab(p2, &_p_.runq, t, stealRunNextG) if n == 0 { return nil } n-- - gp := _p_.runqvictims[n] + gp := _p_.runq[(t+n)%uint32(len(_p_.runq))] if n == 0 { return gp } h := atomicload(&_p_.runqhead) // load-acquire, synchronize with consumers - t := _p_.runqtail if t-h+n >= uint32(len(_p_.runq)) { throw("runqsteal: runq overflow") } - for i := uint32(0); i < n; i++ { - _p_.runq[(t+i)%uint32(len(_p_.runq))] = _p_.runqvictims[i] - } atomicstore(&_p_.runqtail, t+n) // store-release, makes the item available for consumption return gp } diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go index ae93bb8dcb..8dfece5845 100644 --- a/src/runtime/runtime2.go +++ b/src/runtime/runtime2.go @@ -353,10 +353,9 @@ type p struct { goidcacheend uint64 // Queue of runnable goroutines. Accessed without lock. - runqhead uint32 - runqtail uint32 - runq [256]*g - runqvictims [128]*g // Used to stage victims from another p's runq + runqhead uint32 + runqtail uint32 + runq [256]*g // runnext, if non-nil, is a runnable G that was ready'd by // the current G and should be run next instead of what's in // runq if there's time remaining in the running G's time From 0b9866fd561d5ecebee14d73c0a4938dec5abe7d Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Sat, 16 May 2015 20:05:58 -0400 Subject: [PATCH 128/232] buildall.bash: exit 1 when make.bash fails If make.bash fails, there is no point continuing any further. Fixes #10880. Change-Id: I350cc16999372422ad3d2e0327d52d467886a5b1 Reviewed-on: https://go-review.googlesource.com/10180 Reviewed-by: Brad Fitzpatrick --- src/buildall.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/buildall.bash b/src/buildall.bash index a07529e733..ba23d31a50 100755 --- a/src/buildall.bash +++ b/src/buildall.bash @@ -36,7 +36,7 @@ fi targets="$((ls runtime | sed -n 's/^rt0_\(.*\)_\(.*\)\.s/\1-\2/p'; echo linux-386-387 linux-arm-arm5) | sort | egrep -v android-arm | egrep "$pattern" | egrep 'linux|nacl') $(ls runtime | sed -n 's/^rt0_\(.*\)_\(.*\)\.s/\1-\2/p' | egrep -v 'android-arm|darwin-arm' | egrep "$pattern" | egrep -v 'linux|nacl')" -./make.bash +./make.bash || exit 1 GOROOT="$(cd .. && pwd)" failed=false From e544bee1ddf4a2869221b68ef8cec6c97b6d827b Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Tue, 21 Apr 2015 10:56:45 +1000 Subject: [PATCH 129/232] runtime: correct exception stack trace output It is misleading when stack trace say: signal arrived during cgo execution but we are not in cgo call. Change-Id: I627e2f2bdc7755074677f77f21befc070a101914 Reviewed-on: https://go-review.googlesource.com/9190 Reviewed-by: Russ Cox --- src/runtime/signal_windows.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/runtime/signal_windows.go b/src/runtime/signal_windows.go index da8a1c5801..b2fce53534 100644 --- a/src/runtime/signal_windows.go +++ b/src/runtime/signal_windows.go @@ -131,7 +131,9 @@ func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 { print("PC=", hex(r.ip()), "\n") if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 { - print("signal arrived during cgo execution\n") + if iscgo { + print("signal arrived during external code execution\n") + } gp = _g_.m.lockedg } print("\n") From 5f7060afd2dea927ac64804c7e4639f6635c3bb7 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 15 May 2015 16:03:27 -0400 Subject: [PATCH 130/232] runtime: don't start GC if preemptoff is set In order to avoid deadlocks, startGC avoids kicking off GC if locks are held by the calling M. However, it currently fails to check preemptoff, which is the other way to disable preemption. Fix this by adding a check for preemptoff. Change-Id: Ie1083166e5ba4af5c9d6c5a42efdfaaef41ca997 Reviewed-on: https://go-review.googlesource.com/10153 Reviewed-by: Russ Cox --- src/runtime/mgc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index d33fbf11de..848b46804c 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -703,7 +703,7 @@ func startGC(mode int) { // trying to run gc while holding a lock. The next mallocgc without a lock // will do the gc instead. mp := acquirem() - if gp := getg(); gp == mp.g0 || mp.locks > 1 || !memstats.enablegc || panicking != 0 || gcpercent < 0 { + if gp := getg(); gp == mp.g0 || mp.locks > 1 || mp.preemptoff != "" || !memstats.enablegc || panicking != 0 || gcpercent < 0 { releasem(mp) return } From a1da255aa0b962231d80e594abe300200e6b4c73 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 15 May 2015 16:00:50 -0400 Subject: [PATCH 131/232] runtime: factor stoptheworld/starttheworld pattern There are several steps to stopping and starting the world and currently they're open-coded in several places. The garbage collector is the only thing that needs to stop and start the world in a non-trivial pattern. Replace all other uses with calls to higher-level functions that implement the entire pattern necessary to stop and start the world. This is a pure refectoring and should not change any code semantics. In the following commits, we'll make changes that are easier to do with this abstraction in place. This commit renames the old starttheworld to startTheWorldWithSema. This is a slight misnomer right now because the callers release worldsema just before calling this. However, a later commit will swap these and I don't want to think of another name in the mean time. Change-Id: I5dc97f87b44fb98963c49c777d7053653974c911 Reviewed-on: https://go-review.googlesource.com/10154 Reviewed-by: Russ Cox --- src/runtime/debug.go | 11 ++---- src/runtime/heapdump.go | 13 +++---- src/runtime/mgc.go | 10 +++--- src/runtime/mprof.go | 18 +++------- src/runtime/mstats.go | 17 +++------ src/runtime/proc.go | 2 +- src/runtime/proc1.go | 80 +++++++++++++++++++++++++++++------------ src/runtime/trace.go | 34 ++++++------------ 8 files changed, 88 insertions(+), 97 deletions(-) diff --git a/src/runtime/debug.go b/src/runtime/debug.go index 3ecaac10bc..9aec3b03e0 100644 --- a/src/runtime/debug.go +++ b/src/runtime/debug.go @@ -22,17 +22,12 @@ func GOMAXPROCS(n int) int { return ret } - semacquire(&worldsema, false) - gp := getg() - gp.m.preemptoff = "GOMAXPROCS" - systemstack(stoptheworld) + stopTheWorld("GOMAXPROCS") - // newprocs will be processed by starttheworld + // newprocs will be processed by startTheWorld newprocs = int32(n) - gp.m.preemptoff = "" - semrelease(&worldsema) - systemstack(starttheworld) + startTheWorld() return ret } diff --git a/src/runtime/heapdump.go b/src/runtime/heapdump.go index 0add63acb4..196cb3fcb5 100644 --- a/src/runtime/heapdump.go +++ b/src/runtime/heapdump.go @@ -15,20 +15,15 @@ import "unsafe" //go:linkname runtime_debug_WriteHeapDump runtime/debug.WriteHeapDump func runtime_debug_WriteHeapDump(fd uintptr) { - semacquire(&worldsema, false) - gp := getg() - gp.m.preemptoff = "write heap dump" - systemstack(stoptheworld) + stopTheWorld("write heap dump") systemstack(func() { writeheapdump_m(fd) }) - gp.m.preemptoff = "" - gp.m.locks++ - semrelease(&worldsema) - systemstack(starttheworld) - gp.m.locks-- + getg().m.locks++ // TODO: Is this necessary? + startTheWorld() + getg().m.locks-- } const ( diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index 848b46804c..68636740a6 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -699,7 +699,7 @@ const ( func startGC(mode int) { // The gc is turned off (via enablegc) until the bootstrap has completed. // Also, malloc gets called in the guts of a number of libraries that might be - // holding locks. To avoid deadlocks during stoptheworld, don't bother + // holding locks. To avoid deadlocks during stop-the-world, don't bother // trying to run gc while holding a lock. The next mallocgc without a lock // will do the gc instead. mp := acquirem() @@ -797,7 +797,7 @@ func gc(mode int) { traceGCStart() } - systemstack(stoptheworld) + systemstack(stopTheWorldWithSema) systemstack(finishsweep_m) // finish sweep before we start concurrent scan. // clearpools before we start the GC. If we wait they memory will not be // reclaimed until the next GC cycle. @@ -814,7 +814,7 @@ func gc(mode int) { setGCPhase(_GCscan) // Concurrent scan. - starttheworld() + startTheWorldWithSema() if debug.gctrace > 0 { tScan = nanotime() } @@ -858,7 +858,7 @@ func gc(mode int) { if debug.gctrace > 0 { tMarkTerm = nanotime() } - systemstack(stoptheworld) + systemstack(stopTheWorldWithSema) // The gcphase is _GCmark, it will transition to _GCmarktermination // below. The important thing is that the wb remains active until // all marking is complete. This includes writes made by the GC. @@ -958,7 +958,7 @@ func gc(mode int) { throw("gc done but gcphase != _GCoff") } - systemstack(starttheworld) + systemstack(startTheWorldWithSema) releasem(mp) mp = nil diff --git a/src/runtime/mprof.go b/src/runtime/mprof.go index 4544344780..a618bd5e81 100644 --- a/src/runtime/mprof.go +++ b/src/runtime/mprof.go @@ -521,9 +521,7 @@ func GoroutineProfile(p []StackRecord) (n int, ok bool) { n = NumGoroutine() if n <= len(p) { gp := getg() - semacquire(&worldsema, false) - gp.m.preemptoff = "profile" - systemstack(stoptheworld) + stopTheWorld("profile") n = NumGoroutine() if n <= len(p) { @@ -544,9 +542,7 @@ func GoroutineProfile(p []StackRecord) (n int, ok bool) { } } - gp.m.preemptoff = "" - semrelease(&worldsema) - systemstack(starttheworld) + startTheWorld() } return n, ok @@ -565,10 +561,7 @@ func saveg(pc, sp uintptr, gp *g, r *StackRecord) { // into buf after the trace for the current goroutine. func Stack(buf []byte, all bool) int { if all { - semacquire(&worldsema, false) - gp := getg() - gp.m.preemptoff = "stack trace" - systemstack(stoptheworld) + stopTheWorld("stack trace") } n := 0 @@ -590,10 +583,7 @@ func Stack(buf []byte, all bool) int { } if all { - gp := getg() - gp.m.preemptoff = "" - semrelease(&worldsema) - systemstack(starttheworld) + startTheWorld() } return n } diff --git a/src/runtime/mstats.go b/src/runtime/mstats.go index c8e5249156..bd6ac1a4d5 100644 --- a/src/runtime/mstats.go +++ b/src/runtime/mstats.go @@ -153,24 +153,15 @@ func init() { // ReadMemStats populates m with memory allocator statistics. func ReadMemStats(m *MemStats) { - // Have to acquire worldsema to stop the world, - // because stoptheworld can only be used by - // one goroutine at a time, and there might be - // a pending garbage collection already calling it. - semacquire(&worldsema, false) - gp := getg() - gp.m.preemptoff = "read mem stats" - systemstack(stoptheworld) + stopTheWorld("read mem stats") systemstack(func() { readmemstats_m(m) }) - gp.m.preemptoff = "" - gp.m.locks++ - semrelease(&worldsema) - systemstack(starttheworld) - gp.m.locks-- + getg().m.locks++ // TODO: Is this necessary? + startTheWorld() + getg().m.locks-- } func readmemstats_m(stats *MemStats) { diff --git a/src/runtime/proc.go b/src/runtime/proc.go index f725fc890b..805b96e627 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -203,7 +203,7 @@ func acquireSudog() *sudog { // acquireSudog, acquireSudog calls new(sudog), // new calls malloc, malloc can call the garbage collector, // and the garbage collector calls the semaphore implementation - // in stoptheworld. + // in stopTheWorld. // Break the cycle by doing acquirem/releasem around new(sudog). // The acquirem/releasem increments m.locks during new(sudog), // which keeps the garbage collector from being invoked. diff --git a/src/runtime/proc1.go b/src/runtime/proc1.go index 4ce756b692..3d86d40654 100644 --- a/src/runtime/proc1.go +++ b/src/runtime/proc1.go @@ -211,7 +211,7 @@ func helpgc(nproc int32) { // sched.stopwait to in order to request that all Gs permanently stop. const freezeStopWait = 0x7fffffff -// Similar to stoptheworld but best-effort and can be called several times. +// Similar to stopTheWorld but best-effort and can be called several times. // There is no reverse operation, used during crashing. // This function must not lock any mutexes. func freezetheworld() { @@ -528,31 +528,65 @@ func quiesce(mastergp *g) { mcall(mquiesce) } +// stopTheWorld stops all P's from executing goroutines, interrupting +// all goroutines at GC safe points and records reason as the reason +// for the stop. On return, only the current goroutine's P is running. +// stopTheWorld must not be called from a system stack and the caller +// must not hold worldsema. The caller must call startTheWorld when +// other P's should resume execution. +// +// stopTheWorld is safe for multiple goroutines to call at the +// same time. Each will execute its own stop, and the stops will +// be serialized. +// +// This is also used by routines that do stack dumps. If the system is +// in panic or being exited, this may not reliably stop all +// goroutines. +func stopTheWorld(reason string) { + semacquire(&worldsema, false) + getg().m.preemptoff = reason + systemstack(stopTheWorldWithSema) +} + +// startTheWorld undoes the effects of stopTheWorld. +func startTheWorld() { + getg().m.preemptoff = "" + semrelease(&worldsema) + systemstack(startTheWorldWithSema) +} + // Holding worldsema grants an M the right to try to stop the world. -// The procedure is: -// -// semacquire(&worldsema); -// m.preemptoff = "reason"; -// stoptheworld(); -// -// ... do stuff ... -// -// m.preemptoff = ""; -// semrelease(&worldsema); -// starttheworld(); -// var worldsema uint32 = 1 -// This is used by the GC as well as the routines that do stack dumps. In the case -// of GC all the routines can be reliably stopped. This is not always the case -// when the system is in panic or being exited. -func stoptheworld() { +// stopTheWorldWithSema is the core implementation of stopTheWorld. +// The caller is responsible for acquiring worldsema and disabling +// preemption first and then should stopTheWorldWithSema on the system +// stack: +// +// semacquire(&worldsema, false) +// m.preemptoff = "reason" +// systemstack(stopTheWorldWithSema) +// +// When finished, the caller must either call startTheWorld or undo +// these three operations separately: +// +// m.preemptoff = "" +// semrelease(&worldsema) +// systemstack(startTheWorldWithSema) +// +// It is allowed to acquire worldsema once and then execute multiple +// startTheWorldWithSema/stopTheWorldWithSema pairs. +// Other P's are able to execute between successive calls to +// startTheWorldWithSema and stopTheWorldWithSema. +// Holding worldsema causes any other goroutines invoking +// stopTheWorld to block. +func stopTheWorldWithSema() { _g_ := getg() // If we hold a lock, then we won't be able to stop another M // that is blocked trying to acquire the lock. if _g_.m.locks > 0 { - throw("stoptheworld: holding locks") + throw("stopTheWorld: holding locks") } lock(&sched.lock) @@ -599,12 +633,12 @@ func stoptheworld() { } } if sched.stopwait != 0 { - throw("stoptheworld: not stopped") + throw("stopTheWorld: not stopped") } for i := 0; i < int(gomaxprocs); i++ { p := allp[i] if p.status != _Pgcstop { - throw("stoptheworld: not stopped") + throw("stopTheWorld: not stopped") } } } @@ -614,7 +648,7 @@ func mhelpgc() { _g_.m.helpgc = -1 } -func starttheworld() { +func startTheWorldWithSema() { _g_ := getg() _g_.m.locks++ // disable preemption because it can be holding p in a local var @@ -643,7 +677,7 @@ func starttheworld() { mp := p.m.ptr() p.m = 0 if mp.nextp != 0 { - throw("starttheworld: inconsistent mp->nextp") + throw("startTheWorld: inconsistent mp->nextp") } mp.nextp.set(p) notewakeup(&mp.park) @@ -1304,7 +1338,7 @@ func startlockedm(gp *g) { stopm() } -// Stops the current m for stoptheworld. +// Stops the current m for stopTheWorld. // Returns when the world is restarted. func gcstopm() { _g_ := getg() diff --git a/src/runtime/trace.go b/src/runtime/trace.go index 3b7501b9b4..6da7baddc5 100644 --- a/src/runtime/trace.go +++ b/src/runtime/trace.go @@ -132,10 +132,7 @@ type traceBuf struct { func StartTrace() error { // Stop the world, so that we can take a consistent snapshot // of all goroutines at the beginning of the trace. - semacquire(&worldsema, false) - _g_ := getg() - _g_.m.preemptoff = "start tracing" - systemstack(stoptheworld) + stopTheWorld("start tracing") // We are in stop-the-world, but syscalls can finish and write to trace concurrently. // Exitsyscall could check trace.enabled long before and then suddenly wake up @@ -146,9 +143,7 @@ func StartTrace() error { if trace.enabled || trace.shutdown { unlock(&trace.bufLock) - _g_.m.preemptoff = "" - semrelease(&worldsema) - systemstack(starttheworld) + startTheWorld() return errorString("tracing is already enabled") } @@ -175,9 +170,7 @@ func StartTrace() error { unlock(&trace.bufLock) - _g_.m.preemptoff = "" - semrelease(&worldsema) - systemstack(starttheworld) + startTheWorld() return nil } @@ -186,19 +179,14 @@ func StartTrace() error { func StopTrace() { // Stop the world so that we can collect the trace buffers from all p's below, // and also to avoid races with traceEvent. - semacquire(&worldsema, false) - _g_ := getg() - _g_.m.preemptoff = "stop tracing" - systemstack(stoptheworld) + stopTheWorld("stop tracing") // See the comment in StartTrace. lock(&trace.bufLock) if !trace.enabled { unlock(&trace.bufLock) - _g_.m.preemptoff = "" - semrelease(&worldsema) - systemstack(starttheworld) + startTheWorld() return } @@ -236,9 +224,7 @@ func StopTrace() { unlock(&trace.bufLock) - _g_.m.preemptoff = "" - semrelease(&worldsema) - systemstack(starttheworld) + startTheWorld() // The world is started but we've set trace.shutdown, so new tracing can't start. // Wait for the trace reader to flush pending buffers and stop. @@ -428,9 +414,9 @@ func traceEvent(ev byte, skip int, args ...uint64) { // The caller checked that trace.enabled == true, but trace.enabled might have been // turned off between the check and now. Check again. traceLockBuffer did mp.locks++, - // StopTrace does stoptheworld, and stoptheworld waits for mp.locks to go back to zero, + // StopTrace does stopTheWorld, and stopTheWorld waits for mp.locks to go back to zero, // so if we see trace.enabled == true now, we know it's true for the rest of the function. - // Exitsyscall can run even during stoptheworld. The race with StartTrace/StopTrace + // Exitsyscall can run even during stopTheWorld. The race with StartTrace/StopTrace // during tracing in exitsyscall is resolved by locking trace.bufLock in traceLockBuffer. if !trace.enabled { traceReleaseBuffer(pid) @@ -733,7 +719,7 @@ func traceProcStart() { } func traceProcStop(pp *p) { - // Sysmon and stoptheworld can stop Ps blocked in syscalls, + // Sysmon and stopTheWorld can stop Ps blocked in syscalls, // to handle this we temporary employ the P. mp := acquirem() oldp := mp.p @@ -807,7 +793,7 @@ func traceGoSysExit(ts int64) { } func traceGoSysBlock(pp *p) { - // Sysmon and stoptheworld can declare syscalls running on remote Ps as blocked, + // Sysmon and stopTheWorld can declare syscalls running on remote Ps as blocked, // to handle this we temporary employ the P. mp := acquirem() oldp := mp.p From 9c44a41dd56660b7685da61bf1efb00cc7c1e198 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 15 May 2015 16:10:00 -0400 Subject: [PATCH 132/232] runtime: disallow preemption during startTheWorld Currently, startTheWorld clears preemptoff for the current M before starting the world. A few callers increment m.locks around startTheWorld, presumably to prevent preemption any time during starting the world. This is almost certainly pointless (none of the other callers do this), but there's no harm in making startTheWorld keep preemption disabled until it's all done, which definitely lets us drop these m.locks manipulations. Change-Id: I8a93658abd0c72276c9bafa3d2c7848a65b4691a Reviewed-on: https://go-review.googlesource.com/10155 Reviewed-by: Russ Cox --- src/runtime/heapdump.go | 2 -- src/runtime/mstats.go | 2 -- src/runtime/proc1.go | 2 +- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/runtime/heapdump.go b/src/runtime/heapdump.go index 196cb3fcb5..c0fff3f1ce 100644 --- a/src/runtime/heapdump.go +++ b/src/runtime/heapdump.go @@ -21,9 +21,7 @@ func runtime_debug_WriteHeapDump(fd uintptr) { writeheapdump_m(fd) }) - getg().m.locks++ // TODO: Is this necessary? startTheWorld() - getg().m.locks-- } const ( diff --git a/src/runtime/mstats.go b/src/runtime/mstats.go index bd6ac1a4d5..3eff7f6b3e 100644 --- a/src/runtime/mstats.go +++ b/src/runtime/mstats.go @@ -159,9 +159,7 @@ func ReadMemStats(m *MemStats) { readmemstats_m(m) }) - getg().m.locks++ // TODO: Is this necessary? startTheWorld() - getg().m.locks-- } func readmemstats_m(stats *MemStats) { diff --git a/src/runtime/proc1.go b/src/runtime/proc1.go index 3d86d40654..ab0566b470 100644 --- a/src/runtime/proc1.go +++ b/src/runtime/proc1.go @@ -550,9 +550,9 @@ func stopTheWorld(reason string) { // startTheWorld undoes the effects of stopTheWorld. func startTheWorld() { - getg().m.preemptoff = "" semrelease(&worldsema) systemstack(startTheWorldWithSema) + getg().m.preemptoff = "" } // Holding worldsema grants an M the right to try to stop the world. From 277acca286e47fd704aae10d030c74927ba2a8d2 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 15 May 2015 16:13:14 -0400 Subject: [PATCH 133/232] runtime: hold worldsema while starting the world Currently, startTheWorld releases worldsema before starting the world. Since startTheWorld can change gomaxprocs after allowing Ps to run, this means that gomaxprocs can change while another P holds worldsema. Unfortunately, the garbage collector and forEachP assume that holding worldsema protects against changes in gomaxprocs (which it *almost* does). In particular, this is causing somewhat frequent "P did not run fn" crashes in forEachP in the runtime tests because gomaxprocs is changing between the several loops that forEachP does over all the Ps. Fix this by only releasing worldsema after the world is started. This relates to issue #10618. forEachP still fails under stress testing, but much less frequently. Change-Id: I085d627b70cca9ebe9af28fe73b9872f1bb224ff Reviewed-on: https://go-review.googlesource.com/10156 Reviewed-by: Russ Cox --- src/runtime/mgc.go | 3 +-- src/runtime/proc1.go | 9 ++++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index 68636740a6..a16d7603a6 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -952,13 +952,12 @@ func gc(mode int) { // all done mp.preemptoff = "" - semrelease(&worldsema) - if gcphase != _GCoff { throw("gc done but gcphase != _GCoff") } systemstack(startTheWorldWithSema) + semrelease(&worldsema) releasem(mp) mp = nil diff --git a/src/runtime/proc1.go b/src/runtime/proc1.go index ab0566b470..31247db02a 100644 --- a/src/runtime/proc1.go +++ b/src/runtime/proc1.go @@ -550,12 +550,15 @@ func stopTheWorld(reason string) { // startTheWorld undoes the effects of stopTheWorld. func startTheWorld() { - semrelease(&worldsema) systemstack(startTheWorldWithSema) + // worldsema must be held over startTheWorldWithSema to ensure + // gomaxprocs cannot change while worldsema is held. + semrelease(&worldsema) getg().m.preemptoff = "" } -// Holding worldsema grants an M the right to try to stop the world. +// Holding worldsema grants an M the right to try to stop the world +// and prevents gomaxprocs from changing concurrently. var worldsema uint32 = 1 // stopTheWorldWithSema is the core implementation of stopTheWorld. @@ -571,8 +574,8 @@ var worldsema uint32 = 1 // these three operations separately: // // m.preemptoff = "" -// semrelease(&worldsema) // systemstack(startTheWorldWithSema) +// semrelease(&worldsema) // // It is allowed to acquire worldsema once and then execute multiple // startTheWorldWithSema/stopTheWorldWithSema pairs. From f0dd002895b48595f6c14f2bf606775289f59d5f Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 15 May 2015 16:31:17 -0400 Subject: [PATCH 134/232] runtime: use separate count and note for forEachP Currently, forEachP reuses the stopwait and stopnote fields from stopTheWorld to track how many Ps have not responded to the safe-point request and to sleep until all Ps have responded. It was assumed this was safe because both stopTheWorld and forEachP must occur under the worlsema and hence stopwait and stopnote cannot be used for both purposes simultaneously and callers could always determine the appropriate use based on sched.gcwaiting (which is only set by stopTheWorld). However, this is not the case, since it's possible for there to be a window between when an M observes that gcwaiting is set and when it checks stopwait during which stopwait could have changed meanings. When this happens, the M decrements stopwait and may wakeup stopnote, but does not otherwise participate in the forEachP protocol. As a result, stopwait is decremented too many times, so it may reach zero before all Ps have run the safe-point function, causing forEachP to wake up early. It will then either observe that some P has not run the safe-point function and panic with "P did not run fn", or the remaining P (or Ps) will run the safe-point function before it wakes up and it will observe that stopwait is negative and panic with "not stopped". Fix this problem by giving forEachP its own safePointWait and safePointNote fields. One known sequence of events that can cause this race is as follows. It involves three actors: G1 is running on M1 on P1. P1 has an empty run queue. G2/M2 is in a blocked syscall and has lost its P. (The details of this don't matter, it just needs to be in a position where it needs to grab an idle P.) GC just started on G3/M3/P3. (These aren't very involved, they just have to be separate from the other G's, M's, and P's.) 1. GC calls stopTheWorld(), which sets sched.gcwaiting to 1. Now G1/M1 begins to enter a syscall: 2. G1/M1 invokes reentersyscall, which sets the P1's status to _Psyscall. 3. G1/M1's reentersyscall observes gcwaiting != 0 and calls entersyscall_gcwait. 4. G1/M1's entersyscall_gcwait blocks acquiring sched.lock. Back on GC: 5. stopTheWorld cas's P1's status to _Pgcstop, does other stuff, and returns. 6. GC does stuff and then calls startTheWorld(). 7. startTheWorld() calls procresize(), which sets P1's status to _Pidle and puts P1 on the idle list. Now G2/M2 returns from its syscall and takes over P1: 8. G2/M2 returns from its blocked syscall and gets P1 from the idle list. 9. G2/M2 acquires P1, which sets P1's status to _Prunning. 10. G2/M2 starts a new syscall and invokes reentersyscall, which sets P1's status to _Psyscall. Back on G1/M1: 11. G1/M1 finally acquires sched.lock in entersyscall_gcwait. At this point, G1/M1 still thinks it's running on P1. P1's status is _Psyscall, which is consistent with what G1/M1 is doing, but it's _Psyscall because *G2/M2* put it in to _Psyscall, not G1/M1. This is basically an ABA race on P1's status. Because forEachP currently shares stopwait with stopTheWorld. G1/M1's entersyscall_gcwait observes the non-zero stopwait set by forEachP, but mistakes it for a stopTheWorld. It cas's P1's status from _Psyscall (set by G2/M2) to _Pgcstop and proceeds to decrement stopwait one more time than forEachP was expecting. Fixes #10618. (See the issue for details on why the above race is safe when forEachP is not involved.) Prior to this commit, the command stress ./runtime.test -test.run TestFutexsleep\|TestGoroutineProfile would reliably fail after a few hundred runs. With this commit, it ran for over 2 million runs and never crashed. Change-Id: I9a91ea20035b34b6e5f07ef135b144115f281f30 Reviewed-on: https://go-review.googlesource.com/10157 Reviewed-by: Russ Cox --- src/runtime/proc1.go | 30 +++++++++++++++--------------- src/runtime/runtime2.go | 4 +++- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/runtime/proc1.go b/src/runtime/proc1.go index 31247db02a..b0b3bf7711 100644 --- a/src/runtime/proc1.go +++ b/src/runtime/proc1.go @@ -790,10 +790,10 @@ func forEachP(fn func(*p)) { _p_ := getg().m.p.ptr() lock(&sched.lock) - if sched.stopwait != 0 { - throw("forEachP: sched.stopwait != 0") + if sched.safePointWait != 0 { + throw("forEachP: sched.safePointWait != 0") } - sched.stopwait = gomaxprocs - 1 + sched.safePointWait = gomaxprocs - 1 sched.safePointFn = fn // Ask all Ps to run the safe point function. @@ -813,11 +813,11 @@ func forEachP(fn func(*p)) { for p := sched.pidle.ptr(); p != nil; p = p.link.ptr() { if cas(&p.runSafePointFn, 1, 0) { fn(p) - sched.stopwait-- + sched.safePointWait-- } } - wait := sched.stopwait > 0 + wait := sched.safePointWait > 0 unlock(&sched.lock) // Run fn for the current P. @@ -843,15 +843,15 @@ func forEachP(fn func(*p)) { for { // Wait for 100us, then try to re-preempt in // case of any races. - if notetsleep(&sched.stopnote, 100*1000) { - noteclear(&sched.stopnote) + if notetsleep(&sched.safePointNote, 100*1000) { + noteclear(&sched.safePointNote) break } preemptall() } } - if sched.stopwait != 0 { - throw("forEachP: not stopped") + if sched.safePointWait != 0 { + throw("forEachP: not done") } for i := 0; i < int(gomaxprocs); i++ { p := allp[i] @@ -887,9 +887,9 @@ func runSafePointFn() { } sched.safePointFn(p) lock(&sched.lock) - sched.stopwait-- - if sched.stopwait == 0 { - notewakeup(&sched.stopnote) + sched.safePointWait-- + if sched.safePointWait == 0 { + notewakeup(&sched.safePointNote) } unlock(&sched.lock) } @@ -1262,9 +1262,9 @@ func handoffp(_p_ *p) { } if _p_.runSafePointFn != 0 && cas(&_p_.runSafePointFn, 1, 0) { sched.safePointFn(_p_) - sched.stopwait-- - if sched.stopwait == 0 { - notewakeup(&sched.stopnote) + sched.safePointWait-- + if sched.safePointWait == 0 { + notewakeup(&sched.safePointNote) } } if sched.runqsize != 0 { diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go index 8dfece5845..83d8062baf 100644 --- a/src/runtime/runtime2.go +++ b/src/runtime/runtime2.go @@ -441,7 +441,9 @@ type schedt struct { // safepointFn should be called on each P at the next GC // safepoint if p.runSafePointFn is set. - safePointFn func(*p) + safePointFn func(*p) + safePointWait int32 + safePointNote note profilehz int32 // cpu profiling rate From a21cf5b6a281df2c3506105cecfbeeda70afca1c Mon Sep 17 00:00:00 2001 From: David Chase Date: Fri, 15 May 2015 12:19:07 -0400 Subject: [PATCH 135/232] cmd/internal/gc: extend escape analysis to pointers in slices Modified esc.go to allow slice literals (before append) to be non-escaping. Modified tests to account for changes in escape behavior and to also test the two cases that were previously not tested. Also minor cleanups to debug-printing within esc.go Allocation stats for running compiler ( cd src/html/template; for i in {1..5} ; do go tool 6g -memprofile=testzz.${i}.prof -memprofilerate=1 *.go ; go tool pprof -alloc_objects -text testzz.${i}.prof ; done ; ) before about 86k allocations after about 83k allocations Fixes #8972 Change-Id: Ib61dd70dc74adb40d6f6fdda6eaa4bf7d83481de Reviewed-on: https://go-review.googlesource.com/10118 Reviewed-by: Russ Cox --- src/cmd/internal/gc/esc.go | 100 +++++++++++++++++-------------------- test/escape2.go | 14 +++--- test/escape2n.go | 14 +++--- test/escape_slice.go | 81 ++++++++++++++++++++++++++++-- 4 files changed, 138 insertions(+), 71 deletions(-) diff --git a/src/cmd/internal/gc/esc.go b/src/cmd/internal/gc/esc.go index 5fb2095bda..a5b6a9b2b1 100644 --- a/src/cmd/internal/gc/esc.go +++ b/src/cmd/internal/gc/esc.go @@ -387,6 +387,19 @@ type EscState struct { recursive bool // recursive function or group of mutually recursive functions. } +// funcSym returns n.Nname.Sym if no nils are encountered along the way. +func funcSym(n *Node) *Sym { + if n == nil || n.Nname == nil { + return nil + } + return n.Nname.Sym +} + +// curfnSym returns n.Curfn.Nname.Sym if no nils are encountered along the way. +func curfnSym(n *Node) *Sym { + return funcSym(n.Curfn) +} + func escAnalyze(all *NodeList, recursive bool) { var es EscState e := &es @@ -428,13 +441,7 @@ func escAnalyze(all *NodeList, recursive bool) { if Debug['m'] != 0 { for l := e.noesc; l != nil; l = l.Next { if l.N.Esc == EscNone { - var tmp *Sym - if l.N.Curfn != nil && l.N.Curfn.Nname != nil { - tmp = l.N.Curfn.Nname.Sym - } else { - tmp = nil - } - Warnl(int(l.N.Lineno), "%v %v does not escape", tmp, Nconv(l.N, obj.FmtShort)) + Warnl(int(l.N.Lineno), "%v %v does not escape", curfnSym(l.N), Nconv(l.N, obj.FmtShort)) } } } @@ -593,13 +600,7 @@ func esc(e *EscState, n *Node, up *Node) { } if Debug['m'] > 1 { - var tmp *Sym - if Curfn != nil && Curfn.Nname != nil { - tmp = Curfn.Nname.Sym - } else { - tmp = nil - } - fmt.Printf("%v:[%d] %v esc: %v\n", Ctxt.Line(int(lineno)), e.loopdepth, tmp, n) + fmt.Printf("%v:[%d] %v esc: %v\n", Ctxt.Line(int(lineno)), e.loopdepth, funcSym(Curfn), n) } switch n.Op { @@ -629,8 +630,12 @@ func esc(e *EscState, n *Node, up *Node) { // Everything but fixed array is a dereference. case ORANGE: - if Isfixedarray(n.Type) && n.List != nil && n.List.Next != nil { - escassign(e, n.List.Next.N, n.Right) + if n.List != nil && n.List.Next != nil { + if Isfixedarray(n.Type) { + escassign(e, n.List.Next.N, n.Right) + } else { + escassign(e, n.List.Next.N, addDereference(n.Right)) + } } case OSWITCH: @@ -670,13 +675,7 @@ func esc(e *EscState, n *Node, up *Node) { // b escapes as well. If we ignore such OSLICEARR, we will conclude // that b does not escape when b contents do. if Debug['m'] != 0 { - var tmp *Sym - if n.Curfn != nil && n.Curfn.Nname != nil { - tmp = n.Curfn.Nname.Sym - } else { - tmp = nil - } - Warnl(int(n.Lineno), "%v ignoring self-assignment to %v", tmp, Nconv(n.Left, obj.FmtShort)) + Warnl(int(n.Lineno), "%v ignoring self-assignment to %v", curfnSym(n), Nconv(n.Left, obj.FmtShort)) } break @@ -763,7 +762,15 @@ func esc(e *EscState, n *Node, up *Node) { for ll := n.List.Next; ll != nil; ll = ll.Next { escassign(e, &e.theSink, ll.N) // lose track of assign to dereference } + } else { + // append(slice1, slice2...) -- slice2 itself does not escape, but contents do. + slice2 := n.List.Next.N + escassign(e, &e.theSink, addDereference(slice2)) // lose track of assign of dereference + if Debug['m'] > 2 { + Warnl(int(n.Lineno), "%v special treatment of append(slice1, slice2...) %v", curfnSym(n), Nconv(n, obj.FmtShort)) + } } + escassign(e, &e.theSink, addDereference(n.List.N)) // The original elements are now leaked, too case OCONV, OCONVNOP: escassign(e, n, n.Left) @@ -776,19 +783,15 @@ func esc(e *EscState, n *Node, up *Node) { case OARRAYLIT: if Isslice(n.Type) { - n.Esc = EscNone // until proven otherwise + // Slice itself is not leaked until proven otherwise + n.Esc = EscNone e.noesc = list(e.noesc, n) n.Escloopdepth = e.loopdepth + } - // Values make it to memory, lose track. - for ll := n.List; ll != nil; ll = ll.Next { - escassign(e, &e.theSink, ll.N.Right) - } - } else { - // Link values to array. - for ll := n.List; ll != nil; ll = ll.Next { - escassign(e, n, ll.N.Right) - } + // Link values to array/slice + for ll := n.List; ll != nil; ll = ll.Next { + escassign(e, n, ll.N.Right) } // Link values to struct. @@ -909,14 +912,8 @@ func escassign(e *EscState, dst *Node, src *Node) { } if Debug['m'] > 1 { - var tmp *Sym - if Curfn != nil && Curfn.Nname != nil { - tmp = Curfn.Nname.Sym - } else { - tmp = nil - } fmt.Printf("%v:[%d] %v escassign: %v(%v)[%v] = %v(%v)[%v]\n", - Ctxt.Line(int(lineno)), e.loopdepth, tmp, + Ctxt.Line(int(lineno)), e.loopdepth, funcSym(Curfn), Nconv(dst, obj.FmtShort), Jconv(dst, obj.FmtShort), Oconv(int(dst.Op), 0), Nconv(src, obj.FmtShort), Jconv(src, obj.FmtShort), Oconv(int(src.Op), 0)) } @@ -1038,12 +1035,15 @@ func escassign(e *EscState, dst *Node, src *Node) { case OAPPEND: // Append returns first argument. + // Subsequent arguments are already leaked because they are operands to append. escassign(e, dst, src.List.N) case OINDEX: // Index of array preserves input value. if Isfixedarray(src.Left.Type) { escassign(e, dst, src.Left) + } else { + escflows(e, dst, src) } // Might be pointer arithmetic, in which case @@ -1510,13 +1510,7 @@ func escflood(e *EscState, dst *Node) { } if Debug['m'] > 1 { - var tmp *Sym - if dst.Curfn != nil && dst.Curfn.Nname != nil { - tmp = dst.Curfn.Nname.Sym - } else { - tmp = nil - } - fmt.Printf("\nescflood:%d: dst %v scope:%v[%d]\n", walkgen, Nconv(dst, obj.FmtShort), tmp, dst.Escloopdepth) + fmt.Printf("\nescflood:%d: dst %v scope:%v[%d]\n", walkgen, Nconv(dst, obj.FmtShort), curfnSym(dst), dst.Escloopdepth) } for l := dst.Escflowsrc; l != nil; l = l.Next { @@ -1548,14 +1542,8 @@ func escwalk(e *EscState, level Level, dst *Node, src *Node) { src.Esclevel = level if Debug['m'] > 1 { - var tmp *Sym - if src.Curfn != nil && src.Curfn.Nname != nil { - tmp = src.Curfn.Nname.Sym - } else { - tmp = nil - } fmt.Printf("escwalk: level:%d depth:%d %.*s op=%v %v(%v) scope:%v[%d]\n", - level, e.pdepth, e.pdepth, "\t\t\t\t\t\t\t\t\t\t", Oconv(int(src.Op), 0), Nconv(src, obj.FmtShort), Jconv(src, obj.FmtShort), tmp, src.Escloopdepth) + level, e.pdepth, e.pdepth, "\t\t\t\t\t\t\t\t\t\t", Oconv(int(src.Op), 0), Nconv(src, obj.FmtShort), Jconv(src, obj.FmtShort), curfnSym(src), src.Escloopdepth) } e.pdepth++ @@ -1657,6 +1645,10 @@ func escwalk(e *EscState, level Level, dst *Node, src *Node) { if Isfixedarray(src.Type) { break } + for ll := src.List; ll != nil; ll = ll.Next { + escwalk(e, level.dec(), dst, ll.N.Right) + } + fallthrough case ODDDARG, diff --git a/test/escape2.go b/test/escape2.go index cc714711cf..dfc37ed45f 100644 --- a/test/escape2.go +++ b/test/escape2.go @@ -787,7 +787,7 @@ func foo93(c chan *int) *int { // ERROR "foo93 c does not escape$" } // does not leak m -func foo94(m map[*int]*int, b bool) *int { // ERROR "foo94 m does not escape$" +func foo94(m map[*int]*int, b bool) *int { // ERROR "leaking param: m to result ~r2 level=1" for k, v := range m { if b { return k @@ -802,8 +802,8 @@ func foo95(m map[*int]*int, x *int) { // ERROR "foo95 m does not escape$" "leaki m[x] = x } -// does not leak m -func foo96(m []*int) *int { // ERROR "foo96 m does not escape$" +// does not leak m but does leak content +func foo96(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1" return m[0] } @@ -823,7 +823,7 @@ func foo99(m *[1]*int) []*int { // ERROR "leaking param: m to result ~r1 level=0 } // does not leak m -func foo100(m []*int) *int { // ERROR "foo100 m does not escape$" +func foo100(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1" for _, v := range m { return v } @@ -863,8 +863,8 @@ func foo104(x []*int) { // ERROR "foo104 x does not escape$" copy(y, x) } -// does not leak x -func foo105(x []*int) { // ERROR "foo105 x does not escape$" +// does not leak x but does leak content +func foo105(x []*int) { // ERROR "leaking param content: x" _ = append(y, x...) } @@ -894,7 +894,7 @@ func foo110(x *int) *int { // ERROR "leaking param: x$" return m[nil] } -func foo111(x *int) *int { // ERROR "leaking param: x$" +func foo111(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0" m := []*int{x} // ERROR "foo111 \[\]\*int literal does not escape$" return m[0] } diff --git a/test/escape2n.go b/test/escape2n.go index bf8c534a91..56f05eba30 100644 --- a/test/escape2n.go +++ b/test/escape2n.go @@ -787,7 +787,7 @@ func foo93(c chan *int) *int { // ERROR "foo93 c does not escape$" } // does not leak m -func foo94(m map[*int]*int, b bool) *int { // ERROR "foo94 m does not escape$" +func foo94(m map[*int]*int, b bool) *int { // ERROR "leaking param: m to result ~r2 level=1" for k, v := range m { if b { return k @@ -802,8 +802,8 @@ func foo95(m map[*int]*int, x *int) { // ERROR "foo95 m does not escape$" "leaki m[x] = x } -// does not leak m -func foo96(m []*int) *int { // ERROR "foo96 m does not escape$" +// does not leak m but does leak content +func foo96(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1" return m[0] } @@ -823,7 +823,7 @@ func foo99(m *[1]*int) []*int { // ERROR "leaking param: m to result ~r1 level=0 } // does not leak m -func foo100(m []*int) *int { // ERROR "foo100 m does not escape$" +func foo100(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1" for _, v := range m { return v } @@ -863,8 +863,8 @@ func foo104(x []*int) { // ERROR "foo104 x does not escape$" copy(y, x) } -// does not leak x -func foo105(x []*int) { // ERROR "foo105 x does not escape$" +// does not leak x but does leak content +func foo105(x []*int) { // ERROR "leaking param content: x" _ = append(y, x...) } @@ -894,7 +894,7 @@ func foo110(x *int) *int { // ERROR "leaking param: x$" return m[nil] } -func foo111(x *int) *int { // ERROR "leaking param: x$" +func foo111(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0" m := []*int{x} // ERROR "foo111 \[\]\*int literal does not escape$" return m[0] } diff --git a/test/escape_slice.go b/test/escape_slice.go index 9315e27682..0b6599719d 100644 --- a/test/escape_slice.go +++ b/test/escape_slice.go @@ -8,6 +8,11 @@ package escape +import ( + "os" + "strings" +) + var sink interface{} func slice0() { @@ -71,9 +76,8 @@ func slice7() *int { } func slice8() { - // BAD: i should not escape here - i := 0 // ERROR "moved to heap: i" - s := []*int{&i} // ERROR "&i escapes to heap" "literal does not escape" + i := 0 + s := []*int{&i} // ERROR "&i does not escape" "literal does not escape" _ = s } @@ -88,3 +92,74 @@ func slice10() []*int { s := []*int{&i} // ERROR "&i escapes to heap" "literal escapes to heap" return s } + +func envForDir(dir string) []string { // ERROR "dir does not escape" + env := os.Environ() + return mergeEnvLists([]string{"PWD=" + dir}, env) // ERROR ".PWD=. \+ dir escapes to heap" "\[\]string literal does not escape" +} + +func mergeEnvLists(in, out []string) []string { // ERROR "leaking param content: in" "leaking param content: out" "leaking param: out to result ~r2 level=0" +NextVar: + for _, inkv := range in { + k := strings.SplitAfterN(inkv, "=", 2)[0] + for i, outkv := range out { + if strings.HasPrefix(outkv, k) { + out[i] = inkv + continue NextVar + } + } + out = append(out, inkv) + } + return out +} + +const ( + IPv4len = 4 + IPv6len = 16 +) + +var v4InV6Prefix = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff} + +func IPv4(a, b, c, d byte) IP { + p := make(IP, IPv6len) // ERROR "make\(IP, IPv6len\) escapes to heap" + copy(p, v4InV6Prefix) + p[12] = a + p[13] = b + p[14] = c + p[15] = d + return p +} + +type IP []byte + +type IPAddr struct { + IP IP + Zone string // IPv6 scoped addressing zone +} + +type resolveIPAddrTest struct { + network string + litAddrOrName string + addr *IPAddr + err error +} + +var resolveIPAddrTests = []resolveIPAddrTest{ + {"ip", "127.0.0.1", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil}, + {"ip4", "127.0.0.1", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil}, + {"ip4:icmp", "127.0.0.1", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil}, +} + +func setupTestData() { + resolveIPAddrTests = append(resolveIPAddrTests, + []resolveIPAddrTest{ // ERROR "\[\]resolveIPAddrTest literal does not escape" + {"ip", + "localhost", + &IPAddr{IP: IPv4(127, 0, 0, 1)}, // ERROR "&IPAddr literal escapes to heap" + nil}, + {"ip4", + "localhost", + &IPAddr{IP: IPv4(127, 0, 0, 1)}, // ERROR "&IPAddr literal escapes to heap" + nil}, + }...) +} From f9ec929aafeec42eea7234c1fa6c6c817c7a6548 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 18 May 2015 11:18:58 -0700 Subject: [PATCH 136/232] spec: fix typo Fixes #10893. Change-Id: I8afeb55acda1e1c8e181379dbaf443716d63ded1 Reviewed-on: https://go-review.googlesource.com/10201 Reviewed-by: Rob Pike --- doc/go_spec.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/go_spec.html b/doc/go_spec.html index 4e2f911388..cdcca6be57 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,6 +1,6 @@ @@ -2605,7 +2605,7 @@ one may write: t.z // t.z t.y // t.T1.y -t.x // (*t.TO).x +t.x // (*t.T0).x p.z // (*p).z p.y // (*p).T1.y From 362a40e37da849696e1af6874d0d5f1275a1a386 Mon Sep 17 00:00:00 2001 From: Michael Hudson-DoyleDate: Thu, 7 May 2015 21:29:47 +1200 Subject: [PATCH 137/232] misc/cgo/testshared: rewrite in Go And fix to work on filesystems with only 1s resolution. Fixes #10724 Change-Id: Ia07463f090b4290fc27f5953fa94186463d7afc7 Reviewed-on: https://go-review.googlesource.com/9768 Reviewed-by: Brad Fitzpatrick --- misc/cgo/testshared/shared_test.go | 364 +++++++++++++++++++++++++++++ misc/cgo/testshared/test.bash | 137 ----------- src/cmd/dist/test.go | 2 +- 3 files changed, 365 insertions(+), 138 deletions(-) create mode 100644 misc/cgo/testshared/shared_test.go delete mode 100755 misc/cgo/testshared/test.bash diff --git a/misc/cgo/testshared/shared_test.go b/misc/cgo/testshared/shared_test.go new file mode 100644 index 0000000000..81b9dffb07 --- /dev/null +++ b/misc/cgo/testshared/shared_test.go @@ -0,0 +1,364 @@ +// Copyright 2015 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 shared_test + +import ( + "bufio" + "bytes" + "debug/elf" + "errors" + "flag" + "fmt" + "go/build" + "io/ioutil" + "log" + "math/rand" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" + "time" +) + +var gopathInstallDir, gorootInstallDir, suffix string + +// This is the smallest set of packages we can link into a shared +// library (runtime/cgo is built implicitly). +var minpkgs = []string{"runtime", "sync/atomic"} +var soname = "libruntime,sync-atomic.so" + +// run runs a command and calls t.Errorf if it fails. +func run(t *testing.T, msg string, args ...string) { + c := exec.Command(args[0], args[1:]...) + if output, err := c.CombinedOutput(); err != nil { + t.Errorf("executing %s (%s) failed %s:\n%s", strings.Join(args, " "), msg, err, output) + } +} + +// goCmd invokes the go tool with the installsuffix set up by TestMain. It calls +// t.Errorf if the command fails. +func goCmd(t *testing.T, args ...string) { + newargs := []string{args[0], "-installsuffix=" + suffix} + if testing.Verbose() { + newargs = append(newargs, "-v") + } + newargs = append(newargs, args[1:]...) + c := exec.Command("go", newargs...) + if testing.Verbose() { + fmt.Printf("+ go %s\n", strings.Join(newargs, " ")) + } + if output, err := c.CombinedOutput(); err != nil { + if t != nil { + t.Errorf("executing %s failed %v:\n%s", strings.Join(c.Args, " "), err, output) + } else { + log.Fatalf("executing %s failed %v:\n%s", strings.Join(c.Args, " "), err, output) + } + } +} + +// TestMain calls testMain so that the latter can use defer (TestMain exits with os.Exit). +func testMain(m *testing.M) (int, error) { + // Because go install -buildmode=shared $standard_library_package always + // installs into $GOROOT, here are some gymnastics to come up with a unique + // installsuffix to use in this test that we can clean up afterwards. + myContext := build.Default + runtimeP, err := myContext.Import("runtime", ".", build.ImportComment) + if err != nil { + return 0, fmt.Errorf("import failed: %v", err) + } + for i := 0; i < 10000; i++ { + try := fmt.Sprintf("%s_%d_dynlink", runtimeP.PkgTargetRoot, rand.Int63()) + err = os.Mkdir(try, 0700) + if os.IsExist(err) { + continue + } + if err == nil { + gorootInstallDir = try + } + break + } + if err != nil { + return 0, fmt.Errorf("can't create temporary directory: %v", err) + } + if gorootInstallDir == "" { + return 0, errors.New("could not create temporary directory after 10000 tries") + } + defer os.RemoveAll(gorootInstallDir) + + // Some tests need to edit the source in GOPATH, so copy this directory to a + // temporary directory and chdir to that. + scratchDir, err := ioutil.TempDir("", "testshared") + if err != nil { + return 0, fmt.Errorf("TempDir failed: %v", err) + } + defer os.RemoveAll(scratchDir) + err = filepath.Walk(".", func(path string, info os.FileInfo, err error) error { + scratchPath := filepath.Join(scratchDir, path) + if info.IsDir() { + if path == "." { + return nil + } + return os.Mkdir(scratchPath, info.Mode()) + } else { + fromBytes, err := ioutil.ReadFile(path) + if err != nil { + return err + } + return ioutil.WriteFile(scratchPath, fromBytes, info.Mode()) + } + }) + if err != nil { + return 0, fmt.Errorf("walk failed: %v", err) + } + os.Setenv("GOPATH", scratchDir) + myContext.GOPATH = scratchDir + os.Chdir(scratchDir) + + // All tests depend on runtime being built into a shared library. Because + // that takes a few seconds, do it here and have all tests use the version + // built here. + suffix = strings.Split(filepath.Base(gorootInstallDir), "_")[2] + goCmd(nil, append([]string{"install", "-buildmode=shared"}, minpkgs...)...) + + myContext.InstallSuffix = suffix + "_dynlink" + depP, err := myContext.Import("dep", ".", build.ImportComment) + if err != nil { + return 0, fmt.Errorf("import failed: %v", err) + } + gopathInstallDir = depP.PkgTargetRoot + return m.Run(), nil +} + +func TestMain(m *testing.M) { + flag.Parse() + exitCode, err := testMain(m) + if err != nil { + log.Fatal(err) + } + os.Exit(exitCode) +} + +// The shared library was built at the expected location. +func TestSOBuilt(t *testing.T) { + _, err := os.Stat(filepath.Join(gorootInstallDir, soname)) + if err != nil { + t.Error(err) + } +} + +// The install command should have created a "shlibname" file for the +// listed packages (and runtime/cgo) indicating the name of the shared +// library containing it. +func TestShlibnameFiles(t *testing.T) { + pkgs := append([]string{}, minpkgs...) + pkgs = append(pkgs, "runtime/cgo") + for _, pkg := range pkgs { + shlibnamefile := filepath.Join(gorootInstallDir, pkg+".shlibname") + contentsb, err := ioutil.ReadFile(shlibnamefile) + if err != nil { + t.Errorf("error reading shlibnamefile for %s: %v", pkg, err) + continue + } + contents := strings.TrimSpace(string(contentsb)) + if contents != soname { + t.Errorf("shlibnamefile for %s has wrong contents: %q", pkg, contents) + } + } +} + +func dynStrings(path string, flag elf.DynTag) []string { + f, err := elf.Open(path) + defer f.Close() + if err != nil { + log.Fatal("elf.Open failed: ", err) + } + dynstrings, err := f.DynString(flag) + if err != nil { + log.Fatal("dynstring failed: ", err) + } + return dynstrings +} + +func AssertIsLinkedTo(t *testing.T, path, lib string) { + for _, dynstring := range dynStrings(path, elf.DT_NEEDED) { + if dynstring == lib { + return + } + } + t.Errorf("%s is not linked to %s", path, lib) +} + +func AssertHasRPath(t *testing.T, path, dir string) { + for _, dynstring := range dynStrings(path, elf.DT_RPATH) { + for _, rpath := range strings.Split(dynstring, ":") { + if filepath.Clean(rpath) == filepath.Clean(dir) { + return + } + } + } + t.Errorf("%s does not have rpath %s", path, dir) +} + +// Build a trivial program that links against the shared runtime and check it runs. +func TestTrivialExecutable(t *testing.T) { + goCmd(t, "install", "-linkshared", "trivial") + run(t, "trivial executable", "./bin/trivial") + AssertIsLinkedTo(t, "./bin/trivial", soname) + AssertHasRPath(t, "./bin/trivial", gorootInstallDir) +} + +// Build a GOPATH package into a shared library that links against the goroot runtime +// and an executable that links against both. +func TestGOPathShlib(t *testing.T) { + goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep") + AssertIsLinkedTo(t, filepath.Join(gopathInstallDir, "libdep.so"), soname) + goCmd(t, "install", "-linkshared", "exe") + AssertIsLinkedTo(t, "./bin/exe", soname) + AssertIsLinkedTo(t, "./bin/exe", "libdep.so") + AssertHasRPath(t, "./bin/exe", gorootInstallDir) + AssertHasRPath(t, "./bin/exe", gopathInstallDir) + // And check it runs. + run(t, "executable linked to GOPATH library", "./bin/exe") +} + +// Testing rebuilding of shared libraries when they are stale is a bit more +// complicated that it seems like it should be. First, we make everything "old": but +// only a few seconds old, or it might be older than 6g (or the runtime source) and +// everything will get rebuilt. Then define a timestamp slightly newer than this +// time, which is what we set the mtime to of a file to cause it to be seen as new, +// and finally another slightly even newer one that we can compare files against to +// see if they have been rebuilt. +var oldTime = time.Now().Add(-9 * time.Second) +var nearlyNew = time.Now().Add(-6 * time.Second) +var stampTime = time.Now().Add(-3 * time.Second) + +// resetFileStamps makes "everything" (bin, src, pkg from GOPATH and the +// test-specific parts of GOROOT) appear old. +func resetFileStamps() { + chtime := func(path string, info os.FileInfo, err error) error { + return os.Chtimes(path, oldTime, oldTime) + } + reset := func(path string) { + if err := filepath.Walk(path, chtime); err != nil { + log.Fatalf("resetFileStamps failed: %v", err) + } + + } + reset("bin") + reset("pkg") + reset("src") + reset(gorootInstallDir) +} + +// touch makes path newer than the "old" time stamp used by resetFileStamps. +func touch(path string) { + if err := os.Chtimes(path, nearlyNew, nearlyNew); err != nil { + log.Fatalf("os.Chtimes failed: %v", err) + } +} + +// isNew returns if the path is newer than the time stamp used by touch. +func isNew(path string) bool { + fi, err := os.Stat(path) + if err != nil { + log.Fatalf("os.Stat failed: %v", err) + } + return fi.ModTime().After(stampTime) +} + +// Fail unless path has been rebuilt (i.e. is newer than the time stamp used by +// isNew) +func AssertRebuilt(t *testing.T, msg, path string) { + if !isNew(path) { + t.Errorf("%s was not rebuilt (%s)", msg, path) + } +} + +// Fail if path has been rebuilt (i.e. is newer than the time stamp used by isNew) +func AssertNotRebuilt(t *testing.T, msg, path string) { + if isNew(path) { + t.Errorf("%s was rebuilt (%s)", msg, path) + } +} + +func TestRebuilding(t *testing.T) { + goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep") + goCmd(t, "install", "-linkshared", "exe") + + // If the source is newer than both the .a file and the .so, both are rebuilt. + resetFileStamps() + touch("src/dep/dep.go") + goCmd(t, "install", "-linkshared", "exe") + AssertRebuilt(t, "new source", filepath.Join(gopathInstallDir, "dep.a")) + AssertRebuilt(t, "new source", filepath.Join(gopathInstallDir, "libdep.so")) + + // If the .a file is newer than the .so, the .so is rebuilt (but not the .a) + resetFileStamps() + touch(filepath.Join(gopathInstallDir, "dep.a")) + goCmd(t, "install", "-linkshared", "exe") + AssertNotRebuilt(t, "new .a file", filepath.Join(gopathInstallDir, "dep.a")) + AssertRebuilt(t, "new .a file", filepath.Join(gopathInstallDir, "libdep.so")) +} + +func appendFile(path, content string) { + f, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND, 0660) + if err != nil { + log.Fatalf("os.OpenFile failed: %v", err) + } + defer func() { + err := f.Close() + if err != nil { + log.Fatalf("f.Close failed: %v", err) + } + }() + _, err = f.WriteString(content) + if err != nil { + log.Fatalf("f.WriteString failed: %v", err) + } +} + +func TestABIChecking(t *testing.T) { + goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep") + goCmd(t, "install", "-linkshared", "exe") + + // If we make an ABI-breaking change to dep and rebuild libp.so but not exe, + // exe will abort with a complaint on startup. + // This assumes adding an exported function breaks ABI, which is not true in + // some senses but suffices for the narrow definition of ABI compatiblity the + // toolchain uses today. + appendFile("src/dep/dep.go", "func ABIBreak() {}\n") + goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep") + c := exec.Command("./bin/exe") + output, err := c.CombinedOutput() + if err == nil { + t.Fatal("executing exe did not fail after ABI break") + } + scanner := bufio.NewScanner(bytes.NewReader(output)) + foundMsg := false + const wantLine = "abi mismatch detected between the executable and libdep.so" + for scanner.Scan() { + if scanner.Text() == wantLine { + foundMsg = true + break + } + } + if err = scanner.Err(); err != nil { + t.Errorf("scanner encountered error: %v", err) + } + if !foundMsg { + t.Fatalf("exe failed, but without line %q; got output:\n%s", wantLine, output) + } + + // Rebuilding exe makes it work again. + goCmd(t, "install", "-linkshared", "exe") + run(t, "rebuilt exe", "./bin/exe") + + // If we make a change which does not break ABI (such as adding an unexported + // function) and rebuild libdep.so, exe still works. + appendFile("src/dep/dep.go", "func noABIBreak() {}\n") + goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep") + run(t, "after non-ABI breaking change", "./bin/exe") +} diff --git a/misc/cgo/testshared/test.bash b/misc/cgo/testshared/test.bash deleted file mode 100755 index 0d67ff1719..0000000000 --- a/misc/cgo/testshared/test.bash +++ /dev/null @@ -1,137 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2015 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# Test that -buildmode=shared can produce a shared library and that -# -linkshared can link against it to produce a working executable. - -set -eu - - -die () { - echo $@ - exit 1 -} - -# Because go install -buildmode=shared $standard_library_package always -# installs into $GOROOT, here are some gymnastics to come up with a -# unique installsuffix to use in this test that we can clean up -# afterwards. -rootdir="$(dirname $(go list -f '{{.Target}}' runtime))" -template="${rootdir}_XXXXXXXX_dynlink" -std_install_dir=$(mktemp -d "$template") - -scratch_dir=$(mktemp -d) -cp -a . $scratch_dir -opwd="$(pwd)" -cd $scratch_dir -export GOPATH="$(pwd)" - -cleanup () { - rm -rf $std_install_dir $scratch_dir -} -trap cleanup EXIT - -mysuffix=$(echo $std_install_dir | sed -e 's/.*_\([^_]*\)_dynlink/\1/') - -# This is the smallest set of packages we can link into a shared -# library (runtime/cgo is built implicitly). Check they are built into -# a library with the expected name. -minpkgs="runtime sync/atomic" -soname=libruntime,sync-atomic.so - -go install -installsuffix="$mysuffix" -buildmode=shared $minpkgs || die "install -buildmode=shared failed" - -if [ ! -f "$std_install_dir/$soname" ]; then - echo "$std_install_dir/$soname not found!" - exit 1 -fi - -# The install command should have created a "shlibname" file for the -# listed packages (and runtime/cgo) indicating the name of the shared -# library containing it. -for pkg in $minpkgs runtime/cgo; do - if [ ! -f "$std_install_dir/$pkg.shlibname" ]; then - die "no shlibname file for $pkg" - fi - if [ "$(cat "$std_install_dir/$pkg.shlibname")" != "$soname" ]; then - die "shlibname file for $pkg has wrong contents" - fi -done - -# Build a trivial program that links against the shared library we -# just made and check it runs. -go install -installsuffix="$mysuffix" -linkshared trivial || die "build -linkshared failed" -./bin/trivial || die "./bin/trivial failed" - -# And check that it is actually dynamically linked against the library -# we hope it is linked against. - -ensure_ldd () { - a="$(ldd $1)" || die "ldd $1 failed: $a" - { echo "$a" | grep -q "$2"; } || die "$1 does not appear to be linked against $2" -} - -ensure_ldd ./bin/trivial $std_install_dir/$soname - -# Build a GOPATH package into a shared library that links against the above one. -rootdir="$(dirname $(go list -installsuffix="$mysuffix" -linkshared -f '{{.Target}}' dep))" -go install -installsuffix="$mysuffix" -buildmode=shared -linkshared dep -ensure_ldd $rootdir/libdep.so $std_install_dir/$soname - - -# And exe that links against both -go install -installsuffix="$mysuffix" -linkshared exe -./bin/exe || die "./bin/exe failed with code $?" -ensure_ldd ./bin/exe $rootdir/libdep.so -ensure_ldd ./bin/exe $std_install_dir/$soname - -# Now, test rebuilding of shared libraries when they are stale. - -will_check_rebuilt () { - for f in $@; do cp $f $f.bak; done -} - -assert_rebuilt () { - find $1 -newer $1.bak | grep -q . || die "$1 was not rebuilt" -} - -assert_not_rebuilt () { - find $1 -newer $1.bak | grep . && die "$1 was rebuilt" || true -} - -# If the source is newer than both the .a file and the .so, both are rebuilt. -touch src/dep/dep.go -will_check_rebuilt $rootdir/libdep.so $rootdir/dep.a -go install -installsuffix="$mysuffix" -linkshared exe -assert_rebuilt $rootdir/dep.a -assert_rebuilt $rootdir/libdep.so - -# If the .a file is newer than the .so, the .so is rebuilt (but not the .a) -touch $rootdir/dep.a -will_check_rebuilt $rootdir/libdep.so $rootdir/dep.a -go install -installsuffix="$mysuffix" -linkshared exe -assert_not_rebuilt $rootdir/dep.a -assert_rebuilt $rootdir/libdep.so - -# If we make an ABI-breaking change to dep and rebuild libp.so but not exe, exe will -# abort with a complaint on startup. -# This assumes adding an exported function breaks ABI, which is not true in some -# senses but suffices for the narrow definition of ABI compatiblity the toolchain -# uses today. -echo "func ABIBreak() {}" >> src/dep/dep.go -go install -installsuffix="$mysuffix" -buildmode=shared -linkshared dep -output="$(./bin/exe 2>&1)" && die "exe succeeded after ABI break" || true -msg="abi mismatch detected between the executable and libdep.so" -{ echo "$output" | grep -q "$msg"; } || die "exe did not fail with expected message" - -# Rebuilding exe makes it work again. -go install -installsuffix="$mysuffix" -linkshared exe -./bin/exe || die "exe failed after rebuild" - -# If we make a change which does not break ABI (such as adding an -# unexported function) and rebuild libdep.so, exe still works. -echo "func noABIBreak() {}" >> src/dep/dep.go -go install -installsuffix="$mysuffix" -buildmode=shared -linkshared dep -./bin/exe || die "exe failed after non-ABI breaking change" diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index 1f26eef5ee..0b6b592eef 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -324,7 +324,7 @@ func (t *tester) registerTests() { t.registerTest("testcshared", "../misc/cgo/testcshared", "./test.bash") } if t.supportedBuildmode("shared") { - t.registerTest("testshared", "../misc/cgo/testshared", "./test.bash") + t.registerTest("testshared", "../misc/cgo/testshared", "go", "test") } if t.gohostos == "linux" && t.goarch == "amd64" { t.registerTest("testasan", "../misc/cgo/testasan", "go", "run", "main.go") From 6f7b4e893871775b74e57d5d048ff0565d32ef79 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Fri, 15 May 2015 13:30:42 -0700 Subject: [PATCH 138/232] cmd/doc: put blank lines around comment for types, etc. Better layout. Fixes #10859. The issue suggests rearranging so the comment comes out after the methods. I tried this and it looks good but it is less useful, since the stuff you're probably looking for - the methods - are scrolled away by the comment. The most important information should be last because that leaves it on your screen after the print if the output is long. Change-Id: I560f992601ccbe2293c347fa1b1018a3f5346c82 Reviewed-on: https://go-review.googlesource.com/10160 Reviewed-by: Russ Cox --- src/cmd/doc/pkg.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/cmd/doc/pkg.go b/src/cmd/doc/pkg.go index ed4b0b82db..5c8976b663 100644 --- a/src/cmd/doc/pkg.go +++ b/src/cmd/doc/pkg.go @@ -115,7 +115,7 @@ func (pkg *Package) emit(comment string, node ast.Node) { log.Fatal(err) } if comment != "" { - pkg.newlines(1) + pkg.newlines(2) // Guarantee blank line before comment. doc.ToText(&pkg.buf, comment, " ", "\t", 80) } pkg.newlines(1) @@ -352,6 +352,9 @@ func (pkg *Package) symbolDoc(symbol string) { } pkg.emit(typ.Doc, decl) // Show associated methods, constants, etc. + if len(typ.Consts) > 0 || len(typ.Vars) > 0 || len(typ.Funcs) > 0 || len(typ.Methods) > 0 { + pkg.Printf("\n") + } pkg.valueSummary(typ.Consts) pkg.valueSummary(typ.Vars) pkg.funcSummary(typ.Funcs) From 19354b9dc87d62dbb5280354be7fd90bdf196a24 Mon Sep 17 00:00:00 2001 From: Daniel Morsing Date: Sat, 2 May 2015 13:08:12 +0100 Subject: [PATCH 139/232] cmd/pprof/internal/profile: ignore comments when parsing heap profiles Fixes #10659. Change-Id: I22dc306ce6f398dd40010ac430928a718d67d466 Reviewed-on: https://go-review.googlesource.com/9623 Reviewed-by: Russ Cox --- src/cmd/pprof/internal/profile/legacy_profile.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cmd/pprof/internal/profile/legacy_profile.go b/src/cmd/pprof/internal/profile/legacy_profile.go index bfc8110e45..e4c92cdd19 100644 --- a/src/cmd/pprof/internal/profile/legacy_profile.go +++ b/src/cmd/pprof/internal/profile/legacy_profile.go @@ -554,9 +554,10 @@ func parseHeap(b []byte) (p *Profile, err error) { } } - if l = strings.TrimSpace(l); l == "" { + if isSpaceOrComment(l) { continue } + l = strings.TrimSpace(l) if sectionTrigger(l) != unrecognizedSection { break From 79986e24e0152ba448fd41d65eeb24ebdb6c7ec7 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Mon, 18 May 2015 19:38:56 +0000 Subject: [PATCH 140/232] runtime/pprof: write heap statistics to heap profile always This is a duplicate of CL 9491. That CL broke the build due to pprof shortcomings and was reverted in CL 9565. CL 9623 fixed pprof, so this can go in again. Fixes #10659. Change-Id: If470fc90b3db2ade1d161b4417abd2f5c6c330b8 Reviewed-on: https://go-review.googlesource.com/10212 Reviewed-by: Matthew Dempsky --- doc/go1.5.txt | 1 + src/runtime/pprof/pprof.go | 50 ++++++++++++++++++-------------------- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/doc/go1.5.txt b/doc/go1.5.txt index 10095d0c18..54a4c6e349 100644 --- a/doc/go1.5.txt +++ b/doc/go1.5.txt @@ -66,6 +66,7 @@ reflect: add ArrayOf (https://golang.org/cl/4111) reflect: add FuncOf (https://golang.org/cl/1996) runtime, syscall: use SYSCALL instruction on FreeBSD (Go 1.5 now requires FreeBSD 8-STABLE+) (https://golang.org/cl/3020) runtime, syscall: use get_random_bytes syscall for NaCl (Go 1.5 now requires NaCl SDK pepper-39 or above) (https://golang.org/cl/1755) +runtime/pprof: memory profiles include overall memory statistics by default (https://golang.org/cl/9491) strings: add Compare(x, y string) int, for symmetry with bytes.Compare (https://golang.org/cl/2828) syscall: Add Foreground and Pgid to SysProcAttr (https://golang.org/cl/5130) syscall: add missing Syscall9 for darwin/amd64 (https://golang.org/cl/6555) diff --git a/src/runtime/pprof/pprof.go b/src/runtime/pprof/pprof.go index b3d0ae9b64..4290edb7be 100644 --- a/src/runtime/pprof/pprof.go +++ b/src/runtime/pprof/pprof.go @@ -442,35 +442,33 @@ func writeHeap(w io.Writer, debug int) error { // Print memstats information too. // Pprof will ignore, but useful for people - if debug > 0 { - s := new(runtime.MemStats) - runtime.ReadMemStats(s) - fmt.Fprintf(w, "\n# runtime.MemStats\n") - fmt.Fprintf(w, "# Alloc = %d\n", s.Alloc) - fmt.Fprintf(w, "# TotalAlloc = %d\n", s.TotalAlloc) - fmt.Fprintf(w, "# Sys = %d\n", s.Sys) - fmt.Fprintf(w, "# Lookups = %d\n", s.Lookups) - fmt.Fprintf(w, "# Mallocs = %d\n", s.Mallocs) - fmt.Fprintf(w, "# Frees = %d\n", s.Frees) + s := new(runtime.MemStats) + runtime.ReadMemStats(s) + fmt.Fprintf(w, "\n# runtime.MemStats\n") + fmt.Fprintf(w, "# Alloc = %d\n", s.Alloc) + fmt.Fprintf(w, "# TotalAlloc = %d\n", s.TotalAlloc) + fmt.Fprintf(w, "# Sys = %d\n", s.Sys) + fmt.Fprintf(w, "# Lookups = %d\n", s.Lookups) + fmt.Fprintf(w, "# Mallocs = %d\n", s.Mallocs) + fmt.Fprintf(w, "# Frees = %d\n", s.Frees) - fmt.Fprintf(w, "# HeapAlloc = %d\n", s.HeapAlloc) - fmt.Fprintf(w, "# HeapSys = %d\n", s.HeapSys) - fmt.Fprintf(w, "# HeapIdle = %d\n", s.HeapIdle) - fmt.Fprintf(w, "# HeapInuse = %d\n", s.HeapInuse) - fmt.Fprintf(w, "# HeapReleased = %d\n", s.HeapReleased) - fmt.Fprintf(w, "# HeapObjects = %d\n", s.HeapObjects) + fmt.Fprintf(w, "# HeapAlloc = %d\n", s.HeapAlloc) + fmt.Fprintf(w, "# HeapSys = %d\n", s.HeapSys) + fmt.Fprintf(w, "# HeapIdle = %d\n", s.HeapIdle) + fmt.Fprintf(w, "# HeapInuse = %d\n", s.HeapInuse) + fmt.Fprintf(w, "# HeapReleased = %d\n", s.HeapReleased) + fmt.Fprintf(w, "# HeapObjects = %d\n", s.HeapObjects) - fmt.Fprintf(w, "# Stack = %d / %d\n", s.StackInuse, s.StackSys) - fmt.Fprintf(w, "# MSpan = %d / %d\n", s.MSpanInuse, s.MSpanSys) - fmt.Fprintf(w, "# MCache = %d / %d\n", s.MCacheInuse, s.MCacheSys) - fmt.Fprintf(w, "# BuckHashSys = %d\n", s.BuckHashSys) + fmt.Fprintf(w, "# Stack = %d / %d\n", s.StackInuse, s.StackSys) + fmt.Fprintf(w, "# MSpan = %d / %d\n", s.MSpanInuse, s.MSpanSys) + fmt.Fprintf(w, "# MCache = %d / %d\n", s.MCacheInuse, s.MCacheSys) + fmt.Fprintf(w, "# BuckHashSys = %d\n", s.BuckHashSys) - fmt.Fprintf(w, "# NextGC = %d\n", s.NextGC) - fmt.Fprintf(w, "# PauseNs = %d\n", s.PauseNs) - fmt.Fprintf(w, "# NumGC = %d\n", s.NumGC) - fmt.Fprintf(w, "# EnableGC = %v\n", s.EnableGC) - fmt.Fprintf(w, "# DebugGC = %v\n", s.DebugGC) - } + fmt.Fprintf(w, "# NextGC = %d\n", s.NextGC) + fmt.Fprintf(w, "# PauseNs = %d\n", s.PauseNs) + fmt.Fprintf(w, "# NumGC = %d\n", s.NumGC) + fmt.Fprintf(w, "# EnableGC = %v\n", s.EnableGC) + fmt.Fprintf(w, "# DebugGC = %v\n", s.DebugGC) if tw != nil { tw.Flush() From 2b063bdff1a61961936db7ef1e963aecf1ae3db7 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Thu, 14 May 2015 19:33:31 -0700 Subject: [PATCH 141/232] cmd/internal/gc: make all Node depths int32 Funcdepth was already int32. Make Escloopdepth and Decldepth also int32 instead of int. No functional changes for non-absurd code. Passes toolstash -cmp. Change-Id: I47e145dd732b6a73cfcc6d45956df0dbccdcd999 Reviewed-on: https://go-review.googlesource.com/10129 Reviewed-by: Russ Cox --- src/cmd/internal/gc/esc.go | 2 +- src/cmd/internal/gc/go.go | 2 +- src/cmd/internal/gc/syntax.go | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cmd/internal/gc/esc.go b/src/cmd/internal/gc/esc.go index a5b6a9b2b1..a9a1748b9a 100644 --- a/src/cmd/internal/gc/esc.go +++ b/src/cmd/internal/gc/esc.go @@ -379,7 +379,7 @@ type EscState struct { theSink Node dsts *NodeList // all dst nodes - loopdepth int // for detecting nested loop scopes + loopdepth int32 // for detecting nested loop scopes pdepth int // for debug printing in recursions. dstcount int // diagnostic edgecount int // diagnostic diff --git a/src/cmd/internal/gc/go.go b/src/cmd/internal/gc/go.go index 5fa85e25a7..6a3379b896 100644 --- a/src/cmd/internal/gc/go.go +++ b/src/cmd/internal/gc/go.go @@ -448,7 +448,7 @@ var nsavederrors int var nsyntaxerrors int -var decldepth int +var decldepth int32 var safemode int diff --git a/src/cmd/internal/gc/syntax.go b/src/cmd/internal/gc/syntax.go index 818d546970..50de7f74de 100644 --- a/src/cmd/internal/gc/syntax.go +++ b/src/cmd/internal/gc/syntax.go @@ -90,7 +90,7 @@ type Node struct { // Escape analysis. Escflowsrc *NodeList // flow(this, src) Escretval *NodeList // on OCALLxxx, list of dummy return values - Escloopdepth int // -1: global, 0: return variables, 1:function top level, increased inside function for every loop or label to mark scopes + Escloopdepth int32 // -1: global, 0: return variables, 1:function top level, increased inside function for every loop or label to mark scopes Sym *Sym // various Vargen int32 // unique name for OTYPE/ONAME within a function. Function outputs are numbered starting at one. @@ -108,7 +108,7 @@ type Node struct { type Name struct { Heapaddr *Node // temp holding heap address of param Inlvar *Node // ONAME substitute while inlining - Decldepth int // declaration loop depth, increased for every loop or label + Decldepth int32 // declaration loop depth, increased for every loop or label Method bool // OCALLMETH name Readonly bool Captured bool // is the variable captured by a closure From ddc93398b955a4d71683c8019d87d2ff9c739070 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Thu, 14 May 2015 19:50:41 -0700 Subject: [PATCH 142/232] cmd/6g, cmd/internal/gc: use Etype instead of Ostk Change-Id: Ifda5d84b28717986c93b63767298180a6d6236c0 Reviewed-on: https://go-review.googlesource.com/10140 Reviewed-by: Russ Cox --- src/cmd/6g/ggen.go | 6 +++--- src/cmd/internal/gc/syntax.go | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/cmd/6g/ggen.go b/src/cmd/6g/ggen.go index 7282ac53e0..e0e1b8a4df 100644 --- a/src/cmd/6g/ggen.go +++ b/src/cmd/6g/ggen.go @@ -306,7 +306,7 @@ func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) { * known to be dead. */ func savex(dr int, x *gc.Node, oldx *gc.Node, res *gc.Node, t *gc.Type) { - r := int(reg[dr]) + r := reg[dr] // save current ax and dx if they are live // and not the destination @@ -318,7 +318,7 @@ func savex(dr int, x *gc.Node, oldx *gc.Node, res *gc.Node, t *gc.Type) { x.Type = gc.Types[gc.TINT64] gmove(x, oldx) x.Type = t - oldx.Ostk = int32(r) // squirrel away old r value + oldx.Etype = r // squirrel away old r value reg[dr] = 1 } } @@ -326,7 +326,7 @@ func savex(dr int, x *gc.Node, oldx *gc.Node, res *gc.Node, t *gc.Type) { func restx(x *gc.Node, oldx *gc.Node) { if oldx.Op != 0 { x.Type = gc.Types[gc.TINT64] - reg[x.Reg] = uint8(oldx.Ostk) + reg[x.Reg] = oldx.Etype gmove(oldx, x) gc.Regfree(oldx) } diff --git a/src/cmd/internal/gc/syntax.go b/src/cmd/internal/gc/syntax.go index 50de7f74de..d4ede60c90 100644 --- a/src/cmd/internal/gc/syntax.go +++ b/src/cmd/internal/gc/syntax.go @@ -27,7 +27,7 @@ type Node struct { Nointerface bool Ullman uint8 // sethi/ullman number Addable bool // addressable - Etype uint8 // op for OASOP, etype for OTYPE, exclam for export + Etype uint8 // op for OASOP, etype for OTYPE, exclam for export, 6g saved reg Bounded bool // bounds check unnecessary Class uint8 // PPARAM, PAUTO, PEXTERN, etc Embedded uint8 // ODCLFIELD embedded type @@ -97,7 +97,6 @@ type Node struct { Lineno int32 Xoffset int64 Stkdelta int64 // offset added by stack frame compaction phase. - Ostk int32 // 6g only Iota int32 Walkgen uint32 Esclevel Level From f4ab8203bab58b3c4ae53a99535719a747d05332 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Mon, 18 May 2015 10:27:59 -0700 Subject: [PATCH 143/232] cmd/internal/gc: separate Node param fields Param will be converted from an anonymous to a named field in a subsequent, automated CL. Reduces Node size from 368 to 328. Reduces inuse_space on the rotate tests by about 3%. No functional changes. Passes toolstash -cmp. Updates #9933. Change-Id: I5867b00328abf17ee24aea6ca58876bae9d8bfed Reviewed-on: https://go-review.googlesource.com/10210 Reviewed-by: Russ Cox --- src/cmd/internal/gc/export.go | 2 +- src/cmd/internal/gc/subr.go | 4 ++++ src/cmd/internal/gc/syntax.go | 26 +++++++++++++++----------- src/cmd/internal/gc/typecheck.go | 8 ++++---- 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/cmd/internal/gc/export.go b/src/cmd/internal/gc/export.go index 1efc8150c5..614de4e2ce 100644 --- a/src/cmd/internal/gc/export.go +++ b/src/cmd/internal/gc/export.go @@ -64,7 +64,7 @@ func autoexport(n *Node, ctxt uint8) { if (ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN { return } - if n.Ntype != nil && n.Ntype.Op == OTFUNC && n.Ntype.Left != nil { // method + if n.Param != nil && n.Ntype != nil && n.Ntype.Op == OTFUNC && n.Ntype.Left != nil { // method return } diff --git a/src/cmd/internal/gc/subr.go b/src/cmd/internal/gc/subr.go index 33741c3baf..b10a6b3d3d 100644 --- a/src/cmd/internal/gc/subr.go +++ b/src/cmd/internal/gc/subr.go @@ -371,8 +371,12 @@ func Nod(op int, nleft *Node, nright *Node) *Node { switch op { case OCLOSURE, ODCLFUNC: n.Func = new(Func) + n.Param = new(Param) case ONAME: n.Name = new(Name) + n.Param = new(Param) + case ODCLFIELD: + n.Param = new(Param) } return n } diff --git a/src/cmd/internal/gc/syntax.go b/src/cmd/internal/gc/syntax.go index d4ede60c90..d52a3d4fe7 100644 --- a/src/cmd/internal/gc/syntax.go +++ b/src/cmd/internal/gc/syntax.go @@ -65,21 +65,12 @@ type Node struct { // ONAME Name *Name - Ntype *Node Defn *Node // ONAME: initializing assignment; OLABEL: labeled statement Pack *Node // real package for import . names Curfn *Node // function for local variables Paramfld *Type // TFIELD for this PPARAM; also for ODOT, curfn - - // ONAME func param with PHEAP - Outerexpr *Node // expression copied into closure for variable - Stackparam *Node // OPARAM node referring to stack copy of param - Alloc *Node // allocation call - - // ONAME closure param with PPARAMREF - Outer *Node // outer PPARAMREF in nested closure - Closure *Node // ONAME/PHEAP <-> ONAME/PPARAMREF - Top int // top context (Ecall, Eproc, etc) + Alloc *Node // allocation call + *Param // OPACK Pkg *Pkg @@ -115,6 +106,19 @@ type Name struct { Needzero bool // if it contains pointers, needs to be zeroed on function entry } +type Param struct { + Ntype *Node + + // ONAME func param with PHEAP + Outerexpr *Node // expression copied into closure for variable + Stackparam *Node // OPARAM node referring to stack copy of param + + // ONAME closure param with PPARAMREF + Outer *Node // outer PPARAMREF in nested closure + Closure *Node // ONAME/PHEAP <-> ONAME/PPARAMREF + Top int // top context (Ecall, Eproc, etc) +} + // Func holds Node fields used only with function-like nodes. type Func struct { Shortname *Node diff --git a/src/cmd/internal/gc/typecheck.go b/src/cmd/internal/gc/typecheck.go index 06f8b34305..8af9f084e2 100644 --- a/src/cmd/internal/gc/typecheck.go +++ b/src/cmd/internal/gc/typecheck.go @@ -813,7 +813,7 @@ OpSwitch: var l *Node for l = n.Left; l != r; l = l.Left { l.Addrtaken = true - if l.Closure != nil { + if l.Param != nil && l.Closure != nil { l.Closure.Addrtaken = true } } @@ -822,7 +822,7 @@ OpSwitch: Fatal("found non-orig name node %v", l) } l.Addrtaken = true - if l.Closure != nil { + if l.Param != nil && l.Closure != nil { l.Closure.Addrtaken = true } defaultlit(&n.Left, nil) @@ -3273,13 +3273,13 @@ func checkassign(stmt *Node, n *Node) { var l *Node for l = n; l != r; l = l.Left { l.Assigned = true - if l.Closure != nil { + if l.Param != nil && l.Closure != nil { l.Closure.Assigned = true } } l.Assigned = true - if l.Closure != nil { + if l.Param != nil && l.Closure != nil { l.Closure.Assigned = true } } From 82833b313e5e23f67d5ed1141d9a2464bf78f277 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Mon, 18 May 2015 15:49:02 -0700 Subject: [PATCH 144/232] cmd/internal/gc: rearrange Node fields Rearrange Node fields to enable better struct packing. This reduces readability in favor of shrinking the size of Nodes. This reduces the size of Node from 328 to 312. This reduces the memory usage to compile the rotate tests by about 4.4%. No functional changes. Passes toolstash -cmp. Updates #9933. Change-Id: I2764c5847fb1635ddc898e2ee385d007d67f03c5 Reviewed-on: https://go-review.googlesource.com/10141 Reviewed-by: Russ Cox --- src/cmd/internal/gc/syntax.go | 108 ++++++++++++++++++---------------- 1 file changed, 58 insertions(+), 50 deletions(-) diff --git a/src/cmd/internal/gc/syntax.go b/src/cmd/internal/gc/syntax.go index d52a3d4fe7..69348d1c2f 100644 --- a/src/cmd/internal/gc/syntax.go +++ b/src/cmd/internal/gc/syntax.go @@ -23,6 +23,60 @@ type Node struct { List *NodeList Rlist *NodeList + // most nodes + Type *Type + Orig *Node // original form, for printing, and tracking copies of ONAMEs + Nname *Node + + // func + Func *Func + + // ONAME + Name *Name + Defn *Node // ONAME: initializing assignment; OLABEL: labeled statement + Pack *Node // real package for import . names + Curfn *Node // function for local variables + Paramfld *Type // TFIELD for this PPARAM; also for ODOT, curfn + Alloc *Node // allocation call + *Param + + // OPACK + Pkg *Pkg + + // OARRAYLIT, OMAPLIT, OSTRUCTLIT. + Initplan *InitPlan + + // Escape analysis. + Escflowsrc *NodeList // flow(this, src) + Escretval *NodeList // on OCALLxxx, list of dummy return values + + Sym *Sym // various + + Opt interface{} // for optimization passes + + // OLITERAL + Val Val + + Xoffset int64 + Stkdelta int64 // offset added by stack frame compaction phase. + + // Escape analysis. + Escloopdepth int32 // -1: global, 0: return variables, 1:function top level, increased inside function for every loop or label to mark scopes + + Vargen int32 // unique name for OTYPE/ONAME within a function. Function outputs are numbered starting at one. + Lineno int32 + Iota int32 + Walkgen uint32 + + Funcdepth int32 + + // OREGISTER, OINDREG + Reg int16 + + // most nodes - smaller fields + Esclevel Level + Esc uint16 // EscXXX + Op uint8 Nointerface bool Ullman uint8 // sethi/ullman number @@ -42,56 +96,10 @@ type Node struct { Used bool Isddd bool // is the argument variadic Implicit bool - Addrtaken bool // address taken, even if not moved to heap - Assigned bool // is the variable ever assigned to - Likely int8 // likeliness of if statement - Hasbreak bool // has break statement - Esc uint16 // EscXXX - Funcdepth int32 - - // most nodes - Type *Type - Orig *Node // original form, for printing, and tracking copies of ONAMEs - Nname *Node - - // func - Func *Func - - // OLITERAL - Val Val - - // OREGISTER, OINDREG - Reg int16 - - // ONAME - Name *Name - Defn *Node // ONAME: initializing assignment; OLABEL: labeled statement - Pack *Node // real package for import . names - Curfn *Node // function for local variables - Paramfld *Type // TFIELD for this PPARAM; also for ODOT, curfn - Alloc *Node // allocation call - *Param - - // OPACK - Pkg *Pkg - - // OARRAYLIT, OMAPLIT, OSTRUCTLIT. - Initplan *InitPlan - - // Escape analysis. - Escflowsrc *NodeList // flow(this, src) - Escretval *NodeList // on OCALLxxx, list of dummy return values - Escloopdepth int32 // -1: global, 0: return variables, 1:function top level, increased inside function for every loop or label to mark scopes - - Sym *Sym // various - Vargen int32 // unique name for OTYPE/ONAME within a function. Function outputs are numbered starting at one. - Lineno int32 - Xoffset int64 - Stkdelta int64 // offset added by stack frame compaction phase. - Iota int32 - Walkgen uint32 - Esclevel Level - Opt interface{} // for optimization passes + Addrtaken bool // address taken, even if not moved to heap + Assigned bool // is the variable ever assigned to + Likely int8 // likeliness of if statement + Hasbreak bool // has break statement } // Name holds Node fields used only by ONAME nodes. From b21ff39679486c03648b1abda7ce206fcf09bc36 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 19 May 2015 10:47:24 +1000 Subject: [PATCH 145/232] flag: Fix up a package comment a bit. I think "the flag" was a typo, and the word "after" was repetitive. Change-Id: I81c034ca11a3a778ff1eb4b3af5b96bc525ab985 Reviewed-on: https://go-review.googlesource.com/10195 Reviewed-by: Rob Pike Reviewed-by: Andrew Gerrand --- src/flag/flag.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flag/flag.go b/src/flag/flag.go index 4e4279069f..060660248e 100644 --- a/src/flag/flag.go +++ b/src/flag/flag.go @@ -31,7 +31,7 @@ fmt.Println("ip has value ", *ip) fmt.Println("flagvar has value ", flagvar) - After parsing, the arguments after the flag are available as the + After parsing, the arguments following the flags are available as the slice flag.Args() or individually as flag.Arg(i). The arguments are indexed from 0 through flag.NArg()-1. From f3fc8b024530c6b67367667455748d9b1f19eafe Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Tue, 19 May 2015 00:25:47 -0400 Subject: [PATCH 146/232] time: document that not all Unix time can be represented Fixes #10906. Change-Id: I7ae25a500df493c1e78183d69d89b3e2a64a0d1a Reviewed-on: https://go-review.googlesource.com/10223 Reviewed-by: Andrew Gerrand --- src/time/time.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/time/time.go b/src/time/time.go index 0300e846a4..fbf3f8d3c8 100644 --- a/src/time/time.go +++ b/src/time/time.go @@ -966,6 +966,8 @@ func (t *Time) UnmarshalText(data []byte) (err error) { // Unix returns the local Time corresponding to the given Unix time, // sec seconds and nsec nanoseconds since January 1, 1970 UTC. // It is valid to pass nsec outside the range [0, 999999999]. +// Not all sec values have a corresponding time value. Notable such +// values are -1<<63 and 1<<63-1. func Unix(sec int64, nsec int64) Time { if nsec < 0 || nsec >= 1e9 { n := nsec / 1e9 From 366ba526e88f5b523298d3ad5014e04a495add82 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 18 May 2015 16:54:59 -0400 Subject: [PATCH 147/232] cmd/internal/gc: add missing write barrier in append(x, BigStructWithPointers) Fixes #10897. Change-Id: I5c2d1f9d26333e2b2a0613ebf496daa465e07c24 Reviewed-on: https://go-review.googlesource.com/10221 Reviewed-by: Austin Clements --- src/cmd/internal/gc/cgen.go | 31 ++++++++++++++++++++++--------- test/writebarrier.go | 16 ++++++++++++++++ 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/src/cmd/internal/gc/cgen.go b/src/cmd/internal/gc/cgen.go index bb022b8351..002439ce36 100644 --- a/src/cmd/internal/gc/cgen.go +++ b/src/cmd/internal/gc/cgen.go @@ -2156,14 +2156,27 @@ func bins(typ *Type, res *Node, a, likely int, to *obj.Prog) { } } -/* - * n is on stack, either local variable - * or return value from function call. - * return n's offset from SP. - */ +// stkof returns n's offset from SP if n is on the stack +// (either a local variable or the return value from a function call +// or the arguments to a function call). +// If n is not on the stack, stkof returns -1000. +// If n is on the stack but in an unknown location +// (due to array index arithmetic), stkof returns +1000. +// +// NOTE(rsc): It is possible that the ODOT and OINDEX cases +// are not relevant here, since it shouldn't be possible for them +// to be involved in an overlapping copy. Only function results +// from one call and the arguments to the next can overlap in +// any non-trivial way. If they can be dropped, then this function +// becomes much simpler and also more trustworthy. +// The fact that it works at all today is probably due to the fact +// that ODOT and OINDEX are irrelevant. func stkof(n *Node) int64 { switch n.Op { case OINDREG: + if n.Reg != int16(Thearch.REGSP) { + return -1000 // not on stack + } return n.Xoffset case ODOT: @@ -2172,7 +2185,7 @@ func stkof(n *Node) int64 { break } off := stkof(n.Left) - if off == -1000 || off == 1000 { + if off == -1000 || off == +1000 { return off } return off + n.Xoffset @@ -2183,13 +2196,13 @@ func stkof(n *Node) int64 { break } off := stkof(n.Left) - if off == -1000 || off == 1000 { + if off == -1000 || off == +1000 { return off } if Isconst(n.Right, CTINT) { return off + t.Type.Width*Mpgetfix(n.Right.Val.U.(*Mpint)) } - return 1000 + return +1000 // on stack but not sure exactly where case OCALLMETH, OCALLINTER, OCALLFUNC: t := n.Left.Type @@ -2210,7 +2223,7 @@ func stkof(n *Node) int64 { // botch - probably failing to recognize address // arithmetic on the above. eg INDEX and DOT - return -1000 + return -1000 // not on stack } /* diff --git a/test/writebarrier.go b/test/writebarrier.go index b24af9a14d..9b741a60df 100644 --- a/test/writebarrier.go +++ b/test/writebarrier.go @@ -128,3 +128,19 @@ func f13(x []int, y *[]int) { func f14(y *[]int) { *y = append(*y, 1) // ERROR "write barrier" } + +type T1 struct { + X *int +} + +func f15(x []T1, y T1) []T1 { + return append(x, y) // ERROR "write barrier" +} + +type T8 struct { + X [8]*int +} + +func f16(x []T8, y T8) []T8 { + return append(x, y) // ERROR "write barrier" +} From 8903b3db0e889f08587a09566927d6252c9f9ebc Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 18 May 2015 11:40:29 -0400 Subject: [PATCH 148/232] runtime: add fast check for self-loop pointer in scanobject MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses a problem reported on the mailing list. This will come up mainly in programs custom allocators that batch allocations, but it still helps in our programs, which mainly do not have such allocations. name old mean new mean delta BinaryTree17 5.95s × (0.97,1.03) 5.93s × (0.97,1.04) ~ (p=0.613) Fannkuch11 4.46s × (0.98,1.04) 4.33s × (0.99,1.01) -2.93% (p=0.000) FmtFprintfEmpty 86.6ns × (0.98,1.03) 86.8ns × (0.98,1.02) ~ (p=0.523) FmtFprintfString 290ns × (0.98,1.05) 287ns × (0.98,1.03) ~ (p=0.061) FmtFprintfInt 271ns × (0.98,1.04) 286ns × (0.99,1.01) +5.54% (p=0.000) FmtFprintfIntInt 495ns × (0.98,1.04) 489ns × (0.99,1.01) -1.24% (p=0.015) FmtFprintfPrefixedInt 391ns × (0.99,1.02) 407ns × (0.99,1.01) +4.00% (p=0.000) FmtFprintfFloat 578ns × (0.99,1.01) 559ns × (0.99,1.01) -3.35% (p=0.000) FmtManyArgs 1.96µs × (0.98,1.05) 1.94µs × (0.99,1.01) -1.33% (p=0.030) GobDecode 15.9ms × (0.97,1.05) 15.7ms × (0.99,1.01) -1.35% (p=0.044) GobEncode 11.4ms × (0.97,1.05) 11.3ms × (0.98,1.03) ~ (p=0.141) Gzip 658ms × (0.98,1.05) 648ms × (0.99,1.01) -1.59% (p=0.009) Gunzip 144ms × (0.99,1.03) 144ms × (0.99,1.01) ~ (p=0.867) HTTPClientServer 92.1µs × (0.97,1.05) 90.3µs × (0.99,1.01) -1.89% (p=0.005) JSONEncode 31.0ms × (0.96,1.07) 30.2ms × (0.98,1.03) -2.66% (p=0.001) JSONDecode 110ms × (0.97,1.04) 107ms × (0.99,1.01) -2.59% (p=0.000) Mandelbrot200 6.15ms × (0.98,1.04) 6.07ms × (0.99,1.02) -1.32% (p=0.045) GoParse 6.79ms × (0.97,1.04) 6.74ms × (0.97,1.04) ~ (p=0.242) RegexpMatchEasy0_32 158ns × (0.98,1.05) 155ns × (0.99,1.01) -1.64% (p=0.010) RegexpMatchEasy0_1K 548ns × (0.97,1.04) 540ns × (0.99,1.01) -1.34% (p=0.042) RegexpMatchEasy1_32 133ns × (0.97,1.04) 132ns × (0.97,1.05) ~ (p=0.466) RegexpMatchEasy1_1K 899ns × (0.96,1.05) 878ns × (0.99,1.01) -2.32% (p=0.002) RegexpMatchMedium_32 250ns × (0.96,1.03) 243ns × (0.99,1.01) -2.90% (p=0.000) RegexpMatchMedium_1K 73.4µs × (0.98,1.04) 73.0µs × (0.98,1.04) ~ (p=0.411) RegexpMatchHard_32 3.87µs × (0.97,1.07) 3.84µs × (0.98,1.04) ~ (p=0.273) RegexpMatchHard_1K 120µs × (0.97,1.08) 117µs × (0.99,1.01) -2.06% (p=0.010) Revcomp 940ms × (0.96,1.07) 924ms × (0.97,1.07) ~ (p=0.071) Template 128ms × (0.96,1.05) 128ms × (0.99,1.01) ~ (p=0.502) TimeParse 632ns × (0.96,1.07) 616ns × (0.99,1.01) -2.58% (p=0.001) TimeFormat 671ns × (0.97,1.06) 657ns × (0.99,1.02) -2.10% (p=0.002) In contrast to the one in test/bench/go1 (above), the binarytree program on the shootout site uses more goroutines, batches allocations, and sets GOMAXPROCS to runtime.NumCPU()*2. Using that version, before vs after: name old mean new mean delta BinaryTree20 18.6s × (0.96,1.05) 11.3s × (0.98,1.02) -39.46% (p=0.000) And Go 1.4 vs after: name old mean new mean delta BinaryTree20 13.0s × (0.97,1.02) 11.3s × (0.98,1.02) -13.21% (p=0.000) There is still a scheduling problem - the raw run times are hiding the fact that this chews up 2x the CPU - but we'll take care of that separately. Change-Id: I3f5da879b24ae73a0d06745381ffb88c3744948b Reviewed-on: https://go-review.googlesource.com/10220 Reviewed-by: Austin Clements --- src/runtime/mgcmark.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go index 460997880b..0c4e6eba51 100644 --- a/src/runtime/mgcmark.go +++ b/src/runtime/mgcmark.go @@ -611,8 +611,8 @@ func scanobject(b uintptr, gcw *gcWork) { obj := *(*uintptr)(unsafe.Pointer(b + i)) // At this point we have extracted the next potential pointer. - // Check if it points into heap. - if obj != 0 && arena_start <= obj && obj < arena_used { + // Check if it points into heap and not back at the current object. + if obj != 0 && arena_start <= obj && obj < arena_used && obj-b >= n { // Mark the object. if obj, hbits, span := heapBitsForObject(obj); obj != 0 { greyobject(obj, b, i, hbits, span, gcw) From f4d51eb2f567d12c8b908f9fe3f9650e8a175eb7 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Sat, 16 May 2015 21:14:37 -0400 Subject: [PATCH 149/232] runtime: minor clean up to heapminimum Currently setGCPercent sets heapminimum to heapminimum*GOGC/100. The real intent is to set heapminimum to a scaled multiple of a fixed default heap minimum, not to scale heapminimum based on its current value. This turns out to be okay because setGCPercent is only called once and heapminimum is initially set to this default heap minimum. However, the code as written is confusing, especially since setGCPercent is otherwise written so it could be called again to change GOGC. Fix this by introducing a defaultHeapMinimum constant and using this instead of the current value of heapminimum to compute the scaled heap minimum. As part of this, this commit improves the documentation on heapminimum. Change-Id: I4eb82c73dc2eb44a6e5a17c780a747a2e73d7493 Reviewed-on: https://go-review.googlesource.com/10181 Reviewed-by: Russ Cox --- src/runtime/mgc.go | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index a16d7603a6..fb2b210020 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -127,13 +127,22 @@ const ( _RootCount = 5 ) -// heapminimum is the minimum number of bytes in the heap. -// This cleans up the corner case of where we have a very small live set but a lot -// of allocations and collecting every GOGC * live set is expensive. -// heapminimum is adjust by multiplying it by GOGC/100. In -// the special case of GOGC==0 this will set heapminimum to 0 resulting -// collecting at every allocation even when the heap size is small. -var heapminimum = uint64(4 << 20) +// heapminimum is the minimum heap size at which to trigger GC. +// For small heaps, this overrides the usual GOGC*live set rule. +// +// When there is a very small live set but a lot of allocation, simply +// collecting when the heap reaches GOGC*live results in many GC +// cycles and high total per-GC overhead. This minimum amortizes this +// per-GC overhead while keeping the heap reasonably small. +// +// During initialization this is set to 4MB*GOGC/100. In the case of +// GOGC==0, this will set heapminimum to 0, resulting in constant +// collection even when the heap size is small, which is useful for +// debugging. +var heapminimum uint64 = defaultHeapMinimum + +// defaultHeapMinimum is the value of heapminimum for GOGC==100. +const defaultHeapMinimum = 4 << 20 // Initialized from $GOGC. GOGC=off means no GC. var gcpercent int32 @@ -180,7 +189,7 @@ func setGCPercent(in int32) (out int32) { in = -1 } gcpercent = in - heapminimum = heapminimum * uint64(gcpercent) / 100 + heapminimum = defaultHeapMinimum * uint64(gcpercent) / 100 unlock(&mheap_.lock) return out } From 913db7685ec80bc9c56f357b09ced127fbf09a1e Mon Sep 17 00:00:00 2001 From: Rick Hudson Date: Mon, 18 May 2015 16:02:37 -0400 Subject: [PATCH 150/232] runtime: run background mark helpers only if work is available Prior to this CL whenever the GC marking was enabled and a P was looking for work we supplied a G to help the GC do its marking tasks. Once this G finished all the marking available it would release the P to find another available G. In the case where there was no work the P would drop into findrunnable which would execute the mark helper G which would immediately return and the P would drop into findrunnable again repeating the process. Since the P was always given a G to run it never blocks. This CL first checks if the GC mark helper G has available work and if not the P immediately falls through to its blocking logic. Fixes #10901 Change-Id: I94ac9646866ba64b7892af358888bc9950de23b5 Reviewed-on: https://go-review.googlesource.com/10189 Reviewed-by: Austin Clements --- src/runtime/mgc.go | 12 ++++++++++++ src/runtime/mgcwork.go | 7 +++++++ src/runtime/proc1.go | 2 +- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index fb2b210020..ebecc4ffa8 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -1168,6 +1168,18 @@ func gcBgMarkDone() { } } +// gcMarkWorkAvailable determines if mark work is readily available. +// It is used by the scheduler to decide if this p run a mark work. +func gcMarkWorkAvailable(p *p) bool { + if !p.gcw.empty() { + return true + } + if atomicload64(&work.full) != 0 || atomicload64(&work.partial) != 0 { + return true // global work available + } + return false +} + // gcFlushGCWork disposes the gcWork caches of all Ps. The world must // be stopped. //go:nowritebarrier diff --git a/src/runtime/mgcwork.go b/src/runtime/mgcwork.go index 9c32ae8880..930c644c0a 100644 --- a/src/runtime/mgcwork.go +++ b/src/runtime/mgcwork.go @@ -182,6 +182,13 @@ func (w *gcWork) balance() { } } +// empty returns true if w has no mark work available. +//go:nowritebarrier +func (w *gcWork) empty() bool { + wbuf := w.wbuf + return wbuf == 0 || wbuf.ptr().nobj == 0 +} + // Internally, the GC work pool is kept in arrays in work buffers. // The gcWork interface caches a work buffer until full (or empty) to // avoid contending on the global work buffer lists. diff --git a/src/runtime/proc1.go b/src/runtime/proc1.go index b0b3bf7711..54d6698b3f 100644 --- a/src/runtime/proc1.go +++ b/src/runtime/proc1.go @@ -1479,7 +1479,7 @@ stop: // We have nothing to do. If we're in the GC mark phase and can // safely scan and blacken objects, run idle-time marking // rather than give up the P. - if _p_ := _g_.m.p.ptr(); gcBlackenEnabled != 0 && _p_.gcBgMarkWorker != nil { + if _p_ := _g_.m.p.ptr(); gcBlackenEnabled != 0 && _p_.gcBgMarkWorker != nil && gcMarkWorkAvailable(_p_) { _p_.gcMarkWorkerMode = gcMarkWorkerIdleMode gp := _p_.gcBgMarkWorker casgstatus(gp, _Gwaiting, _Grunnable) From c735064cdeb6bf4ec84a0a4b2b48a5cafc4b83dd Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 19 May 2015 14:00:27 -0400 Subject: [PATCH 151/232] cmd/internal/gc: type of str[i] is byte, not uint8 Fixes #8745. Change-Id: Id0641e3c0f259812b41ed871e83c68740feb2b19 Reviewed-on: https://go-review.googlesource.com/10261 Reviewed-by: Austin Clements --- src/cmd/internal/gc/typecheck.go | 2 +- test/fixedbugs/issue8745.go | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 test/fixedbugs/issue8745.go diff --git a/src/cmd/internal/gc/typecheck.go b/src/cmd/internal/gc/typecheck.go index 8af9f084e2..0395ec5f5b 100644 --- a/src/cmd/internal/gc/typecheck.go +++ b/src/cmd/internal/gc/typecheck.go @@ -1027,7 +1027,7 @@ OpSwitch: case TSTRING, TARRAY: indexlit(&n.Right) if t.Etype == TSTRING { - n.Type = Types[TUINT8] + n.Type = bytetype } else { n.Type = t.Type } diff --git a/test/fixedbugs/issue8745.go b/test/fixedbugs/issue8745.go new file mode 100644 index 0000000000..f3a70aff71 --- /dev/null +++ b/test/fixedbugs/issue8745.go @@ -0,0 +1,13 @@ +// errorcheck + +// Copyright 2015 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. + +// Check that the error says s[2] is a byte, not a uint8. + +package p + +func f(s string) { + var _ float64 = s[2] // ERROR "cannot use.*type byte.*as type float64" +} From 9c9e36b34040d33b9f9a0b6fd918ef470338aec4 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 19 May 2015 15:15:52 -0400 Subject: [PATCH 152/232] cmd/internal/gc: sync nowritebarrier checks and write barrier insertion Change-Id: I348223d0336e28d95b8e68d7653aa547acc7c9c3 Reviewed-on: https://go-review.googlesource.com/10262 Reviewed-by: Austin Clements --- src/cmd/internal/gc/cgen.go | 6 ++++++ src/cmd/internal/gc/walk.go | 3 +++ 2 files changed, 9 insertions(+) diff --git a/src/cmd/internal/gc/cgen.go b/src/cmd/internal/gc/cgen.go index 002439ce36..e003ea9f4f 100644 --- a/src/cmd/internal/gc/cgen.go +++ b/src/cmd/internal/gc/cgen.go @@ -785,6 +785,9 @@ abop: // asymmetric binary var sys_wbptr *Node func cgen_wbptr(n, res *Node) { + if Curfn != nil && Curfn.Func.Nowritebarrier { + Yyerror("write barrier prohibited") + } if Debug_wb > 0 { Warn("write barrier") } @@ -828,6 +831,9 @@ func cgen_wbptr(n, res *Node) { } func cgen_wbfat(n, res *Node) { + if Curfn != nil && Curfn.Func.Nowritebarrier { + Yyerror("write barrier prohibited") + } if Debug_wb > 0 { Warn("write barrier") } diff --git a/src/cmd/internal/gc/walk.go b/src/cmd/internal/gc/walk.go index a7f5256b19..36e4d66b33 100644 --- a/src/cmd/internal/gc/walk.go +++ b/src/cmd/internal/gc/walk.go @@ -2217,6 +2217,9 @@ func applywritebarrier(n *Node, init **NodeList) *Node { return n } // Use slow path always for race detector. + if Curfn != nil && Curfn.Func.Nowritebarrier { + Yyerror("write barrier prohibited") + } if Debug_wb > 0 { Warnl(int(n.Lineno), "write barrier") } From 8b83306cf20abed54d7cb23a3f3091b7e6202056 Mon Sep 17 00:00:00 2001 From: Ryan Brown Date: Wed, 8 Apr 2015 12:55:34 -0700 Subject: [PATCH 153/232] cmd/internal/ld: output dwarf in external link mode on darwin Fixes #8973 Change-Id: Idd53fc6d9e6971ae31ed72a3df3cfdce0bfbc1fd Reviewed-on: https://go-review.googlesource.com/8661 Reviewed-by: Russ Cox Run-TryBot: Russ Cox --- src/cmd/5l/asm.go | 14 +- src/cmd/6l/asm.go | 2 +- src/cmd/7l/asm.go | 14 +- src/cmd/8l/asm.go | 2 +- src/cmd/internal/ld/dwarf.go | 155 +++++++-- src/cmd/internal/ld/lib.go | 21 +- src/cmd/internal/ld/macho.go | 8 +- src/cmd/internal/ld/macho_combine_dwarf.go | 369 +++++++++++++++++++++ 8 files changed, 527 insertions(+), 58 deletions(-) create mode 100644 src/cmd/internal/ld/macho_combine_dwarf.go diff --git a/src/cmd/5l/asm.go b/src/cmd/5l/asm.go index 1b69671b9f..70d6790fc1 100644 --- a/src/cmd/5l/asm.go +++ b/src/cmd/5l/asm.go @@ -533,14 +533,12 @@ func asmb() { fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime()) } - if ld.Debug['w'] == 0 { // TODO(minux): enable DWARF Support - dwarfoff := uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) - ld.Cseek(int64(dwarfoff)) + dwarfoff := uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) + ld.Cseek(int64(dwarfoff)) - ld.Segdwarf.Fileoff = uint64(ld.Cpos()) - ld.Dwarfemitdebugsections() - ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff - } + ld.Segdwarf.Fileoff = uint64(ld.Cpos()) + ld.Dwarfemitdebugsections() + ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff machlink = uint32(ld.Domacholink()) } @@ -567,7 +565,7 @@ func asmb() { symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen) case obj.Hdarwin: - symo = uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Filelen), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)) + int64(machlink)) + symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink)) } ld.Cseek(int64(symo)) diff --git a/src/cmd/6l/asm.go b/src/cmd/6l/asm.go index 5520a5acf1..02b4c7cdd2 100644 --- a/src/cmd/6l/asm.go +++ b/src/cmd/6l/asm.go @@ -710,7 +710,7 @@ func asmb() { symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen) case obj.Hdarwin: - symo = int64(ld.Segdata.Fileoff + uint64(ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) + uint64(machlink)) + symo = int64(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink)) case obj.Hlinux, obj.Hfreebsd, diff --git a/src/cmd/7l/asm.go b/src/cmd/7l/asm.go index 3dfb8c666d..064ff56283 100644 --- a/src/cmd/7l/asm.go +++ b/src/cmd/7l/asm.go @@ -317,14 +317,12 @@ func asmb() { fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime()) } - if ld.Debug['w'] == 0 { // TODO(minux): enable DWARF Support - dwarfoff := uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) - ld.Cseek(int64(dwarfoff)) + dwarfoff := uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) + ld.Cseek(int64(dwarfoff)) - ld.Segdwarf.Fileoff = uint64(ld.Cpos()) - ld.Dwarfemitdebugsections() - ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff - } + ld.Segdwarf.Fileoff = uint64(ld.Cpos()) + ld.Dwarfemitdebugsections() + ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff machlink = uint32(ld.Domacholink()) } @@ -351,7 +349,7 @@ func asmb() { symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen) case obj.Hdarwin: - symo = uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Filelen), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)) + int64(machlink)) + symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink)) } ld.Cseek(int64(symo)) diff --git a/src/cmd/8l/asm.go b/src/cmd/8l/asm.go index a63c51f58d..a736d43686 100644 --- a/src/cmd/8l/asm.go +++ b/src/cmd/8l/asm.go @@ -551,7 +551,7 @@ func asmb() { symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen) case obj.Hdarwin: - symo = uint32(ld.Segdata.Fileoff + uint64(ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) + uint64(machlink)) + symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink)) case obj.Hwindows: symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen) diff --git a/src/cmd/internal/ld/dwarf.go b/src/cmd/internal/ld/dwarf.go index 476b329e7a..841ef9abf9 100644 --- a/src/cmd/internal/ld/dwarf.go +++ b/src/cmd/internal/ld/dwarf.go @@ -17,6 +17,7 @@ package ld import ( "cmd/internal/obj" "fmt" + "os" "strings" ) @@ -240,6 +241,7 @@ var abbrevs = [DW_NABRV]DWAbbrev{ {DW_AT_low_pc, DW_FORM_addr}, {DW_AT_high_pc, DW_FORM_addr}, {DW_AT_stmt_list, DW_FORM_data4}, + {DW_AT_comp_dir, DW_FORM_string}, }, }, @@ -694,6 +696,9 @@ func adddwarfrel(sec *LSym, sym *LSym, offsetbase int64, siz int, addend int64) if Iself && Thearch.Thechar == '6' { addend = 0 } + if HEADTYPE == obj.Hdarwin { + addend += sym.Value + } switch siz { case 4: Thearch.Lput(uint32(addend)) @@ -1547,6 +1552,13 @@ func flushunit(dwinfo *DWDie, pc int64, pcsym *LSym, unitstart int64, header_len } } +func getCompilationDir() string { + if dir, err := os.Getwd(); err == nil { + return dir + } + return "/" +} + func writelines() { if linesec == nil { linesec = Linklookup(Ctxt, ".dwarfline", 0) @@ -1571,6 +1583,9 @@ func writelines() { newattr(dwinfo, DW_AT_language, DW_CLS_CONSTANT, int64(lang), 0) newattr(dwinfo, DW_AT_stmt_list, DW_CLS_PTR, unitstart-lineo, 0) newattr(dwinfo, DW_AT_low_pc, DW_CLS_ADDRESS, s.Value, s) + // OS X linker requires compilation dir or absolute path in comp unit name to output debug info. + compDir := getCompilationDir() + newattr(dwinfo, DW_AT_comp_dir, DW_CLS_STRING, int64(len(compDir)), compDir) // Write .debug_line Line Number Program Header (sec 6.2.4) // Fields marked with (*) must be changed for 64-bit dwarf @@ -2083,6 +2098,14 @@ func writedwarfreloc(s *LSym) int64 { return start } +func addmachodwarfsect(prev *Section, name string) *Section { + sect := addsection(&Segdwarf, name, 04) + sect.Extnum = prev.Extnum + 1 + sym := Linklookup(Ctxt, name, 0) + sym.Sect = sect + return sect +} + /* * This is the main entry point for generating dwarf. After emitting * the mandatory debug_abbrev section, it calls writelines() to set up @@ -2097,8 +2120,32 @@ func Dwarfemitdebugsections() { return } - if Linkmode == LinkExternal && !Iself { - return + if Linkmode == LinkExternal { + if !Iself && HEADTYPE != obj.Hdarwin { + return + } + if HEADTYPE == obj.Hdarwin { + sect := Segdata.Sect + // find the last section. + for sect.Next != nil { + sect = sect.Next + } + sect = addmachodwarfsect(sect, ".debug_abbrev") + sect = addmachodwarfsect(sect, ".debug_line") + sect = addmachodwarfsect(sect, ".debug_frame") + sect = addmachodwarfsect(sect, ".debug_info") + } + infosym = Linklookup(Ctxt, ".debug_info", 0) + infosym.Hide = 1 + + abbrevsym = Linklookup(Ctxt, ".debug_abbrev", 0) + abbrevsym.Hide = 1 + + linesym = Linklookup(Ctxt, ".debug_line", 0) + linesym.Hide = 1 + + framesym = Linklookup(Ctxt, ".debug_frame", 0) + framesym.Hide = 1 } // For diagnostic messages. @@ -2191,6 +2238,15 @@ func Dwarfemitdebugsections() { for Cpos()&7 != 0 { Cput(0) } + if HEADTYPE != obj.Hdarwin { + dwarfemitreloc() + } +} + +func dwarfemitreloc() { + if Debug['w'] != 0 { // disable dwarf + return + } inforeloco = writedwarfreloc(infosec) inforelocsize = Cpos() - inforeloco align(inforelocsize) @@ -2263,18 +2319,6 @@ func dwarfaddshstrings(shstrtab *LSym) { elfstrdbg[ElfStrRelDebugLine] = Addstring(shstrtab, ".rel.debug_line") elfstrdbg[ElfStrRelDebugFrame] = Addstring(shstrtab, ".rel.debug_frame") } - - infosym = Linklookup(Ctxt, ".debug_info", 0) - infosym.Hide = 1 - - abbrevsym = Linklookup(Ctxt, ".debug_abbrev", 0) - abbrevsym.Hide = 1 - - linesym = Linklookup(Ctxt, ".debug_line", 0) - linesym.Hide = 1 - - framesym = Linklookup(Ctxt, ".debug_frame", 0) - framesym.Hide = 1 } } @@ -2420,14 +2464,15 @@ func dwarfaddelfheaders() { /* * Macho */ -func dwarfaddmachoheaders() { +func dwarfaddmachoheaders(ms *MachoSeg) { if Debug['w'] != 0 { // disable dwarf return } // Zero vsize segments won't be loaded in memory, even so they // have to be page aligned in the file. - fakestart := abbrevo &^ 0xfff + fakestart := Rnd(int64(Segdwarf.Fileoff), 0x1000) + addr := Segdata.Vaddr + Segdata.Length nsect := 4 if pubnamessize > 0 { @@ -2443,57 +2488,94 @@ func dwarfaddmachoheaders() { nsect++ } - ms := newMachoSeg("__DWARF", nsect) - ms.fileoffset = uint64(fakestart) - ms.filesize = uint64(abbrevo) - uint64(fakestart) - ms.vaddr = ms.fileoffset + Segdata.Vaddr - Segdata.Fileoff + if Linkmode != LinkExternal { + ms = newMachoSeg("__DWARF", nsect) + ms.fileoffset = uint64(fakestart) + ms.filesize = Segdwarf.Filelen + ms.vaddr = addr + } msect := newMachoSect(ms, "__debug_abbrev", "__DWARF") msect.off = uint32(abbrevo) msect.size = uint64(abbrevsize) - msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff - ms.filesize += msect.size + msect.addr = addr + addr += msect.size + msect.flag = 0x02000000 + if abbrevsym != nil { + abbrevsym.Value = int64(msect.addr) + } msect = newMachoSect(ms, "__debug_line", "__DWARF") msect.off = uint32(lineo) msect.size = uint64(linesize) - msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff - ms.filesize += msect.size + msect.addr = addr + addr += msect.size + msect.flag = 0x02000000 + if linesym != nil { + linesym.Value = int64(msect.addr) + } + if linerelocsize > 0 { + msect.nreloc = uint32(len(linesec.R)) + msect.reloc = uint32(linereloco) + } msect = newMachoSect(ms, "__debug_frame", "__DWARF") msect.off = uint32(frameo) msect.size = uint64(framesize) - msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff - ms.filesize += msect.size + msect.addr = addr + addr += msect.size + msect.flag = 0x02000000 + if framesym != nil { + framesym.Value = int64(msect.addr) + } + if framerelocsize > 0 { + msect.nreloc = uint32(len(framesec.R)) + msect.reloc = uint32(framereloco) + } msect = newMachoSect(ms, "__debug_info", "__DWARF") msect.off = uint32(infoo) msect.size = uint64(infosize) - msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff - ms.filesize += msect.size + msect.addr = addr + addr += msect.size + msect.flag = 0x02000000 + if infosym != nil { + infosym.Value = int64(msect.addr) + } + if inforelocsize > 0 { + msect.nreloc = uint32(len(infosec.R)) + msect.reloc = uint32(inforeloco) + } if pubnamessize > 0 { msect := newMachoSect(ms, "__debug_pubnames", "__DWARF") msect.off = uint32(pubnameso) msect.size = uint64(pubnamessize) - msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff - ms.filesize += msect.size + msect.addr = addr + addr += msect.size + msect.flag = 0x02000000 } if pubtypessize > 0 { msect := newMachoSect(ms, "__debug_pubtypes", "__DWARF") msect.off = uint32(pubtypeso) msect.size = uint64(pubtypessize) - msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff - ms.filesize += msect.size + msect.addr = addr + addr += msect.size + msect.flag = 0x02000000 } if arangessize > 0 { msect := newMachoSect(ms, "__debug_aranges", "__DWARF") msect.off = uint32(arangeso) msect.size = uint64(arangessize) - msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff - ms.filesize += msect.size + msect.addr = addr + addr += msect.size + msect.flag = 0x02000000 + if arangesrelocsize > 0 { + msect.nreloc = uint32(len(arangessec.R)) + msect.reloc = uint32(arangesreloco) + } } // TODO(lvd) fix gdb/python to load MachO (16 char section name limit) @@ -2501,8 +2583,9 @@ func dwarfaddmachoheaders() { msect := newMachoSect(ms, "__debug_gdb_scripts", "__DWARF") msect.off = uint32(gdbscripto) msect.size = uint64(gdbscriptsize) - msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff - ms.filesize += msect.size + msect.addr = addr + addr += msect.size + msect.flag = 0x02000000 } } diff --git a/src/cmd/internal/ld/lib.go b/src/cmd/internal/ld/lib.go index 753e8eebd8..a36cd0f8f4 100644 --- a/src/cmd/internal/ld/lib.go +++ b/src/cmd/internal/ld/lib.go @@ -922,7 +922,7 @@ func hostlink() { } if HEADTYPE == obj.Hdarwin { - argv = append(argv, "-Wl,-no_pie,-pagezero_size,4000000") + argv = append(argv, "-Wl,-no_pie,-pagezero_size,4000000,-headerpad,1144") } if HEADTYPE == obj.Hopenbsd { argv = append(argv, "-Wl,-nopie") @@ -1029,6 +1029,25 @@ func hostlink() { if out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput(); err != nil { Exitf("running %s failed: %v\n%s", argv[0], err, out) } + + if Debug['s'] == 0 && debug_s == 0 && HEADTYPE == obj.Hdarwin { + dsym := fmt.Sprintf("%s/go.dwarf", tmpdir) + if out, err := exec.Command("dsymutil", "-f", outfile, "-o", dsym).CombinedOutput(); err != nil { + Ctxt.Cursym = nil + Exitf("%s: running dsymutil failed: %v\n%s", os.Args[0], err, out) + } + combinedOutput := fmt.Sprintf("%s/go.combined", tmpdir) + if err := machoCombineDwarf(outfile, dsym, combinedOutput); err != nil { + Ctxt.Cursym = nil + Exitf("%s: combining dwarf failed: %v", os.Args[0], err) + } + origOutput := fmt.Sprintf("%s/go.orig", tmpdir) + os.Rename(outfile, origOutput) + if err := os.Rename(combinedOutput, outfile); err != nil { + Ctxt.Cursym = nil + Exitf("%s: rename(%s, %s) failed: %v", os.Args[0], combinedOutput, outfile, err) + } + } } func ldobj(f *obj.Biobuf, pkg string, length int64, pn string, file string, whence int) { diff --git a/src/cmd/internal/ld/macho.go b/src/cmd/internal/ld/macho.go index ceeb7b0f5d..0258aff104 100644 --- a/src/cmd/internal/ld/macho.go +++ b/src/cmd/internal/ld/macho.go @@ -443,7 +443,8 @@ func Asmbmacho() { ms = newMachoSeg("", 40) ms.fileoffset = Segtext.Fileoff - ms.filesize = Segdata.Fileoff + Segdata.Filelen - Segtext.Fileoff + ms.filesize = Segdwarf.Fileoff + Segdwarf.Filelen - Segtext.Fileoff + ms.vsize = ms.filesize } /* segment for zero page */ @@ -561,8 +562,8 @@ func Asmbmacho() { } // TODO: dwarf headers go in ms too - if Debug['s'] == 0 && Linkmode != LinkExternal { - dwarfaddmachoheaders() + if Debug['s'] == 0 { + dwarfaddmachoheaders(ms) } a := machowrite() @@ -850,4 +851,5 @@ func Machoemitreloc() { for sect := Segdata.Sect; sect != nil; sect = sect.Next { machorelocsect(sect, datap) } + dwarfemitreloc() } diff --git a/src/cmd/internal/ld/macho_combine_dwarf.go b/src/cmd/internal/ld/macho_combine_dwarf.go new file mode 100644 index 0000000000..9134373a52 --- /dev/null +++ b/src/cmd/internal/ld/macho_combine_dwarf.go @@ -0,0 +1,369 @@ +// Copyright 2015 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 ld + +import ( + "bytes" + "debug/macho" + "encoding/binary" + "fmt" + "io" + "os" + "reflect" + "unsafe" +) + +var fakedwarf, realdwarf, linkseg *macho.Segment +var dwarfstart, linkstart int64 +var linkoffset uint32 +var machHeader *macho.FileHeader +var mappedHeader []byte + +const ( + LC_LOAD_DYLINKER = 0xe + LC_PREBOUND_DYLIB = 0x10 + LC_LOAD_WEAK_DYLIB = 0x18 + LC_UUID = 0x1b + LC_RPATH = 0x8000001c + LC_CODE_SIGNATURE = 0x1d + LC_SEGMENT_SPLIT_INFO = 0x1e + LC_REEXPORT_DYLIB = 0x8000001f + LC_ENCRYPTION_INFO = 0x21 + LC_DYLD_INFO = 0x22 + LC_DYLD_INFO_ONLY = 0x80000022 + LC_VERSION_MIN_MACOSX = 0x24 + LC_VERSION_MIN_IPHONEOS = 0x25 + LC_FUNCTION_STARTS = 0x26 + LC_MAIN = 0x80000028 + LC_DATA_IN_CODE = 0x29 + LC_SOURCE_VERSION = 0x2A + LC_DYLIB_CODE_SIGN_DRS = 0x2B + LC_ENCRYPTION_INFO_64 = 0x2C + + dwarfMinAlign = 6 // 64 = 1 << 6 + pageAlign = 12 // 4096 = 1 << 12 +) + +type loadCmd struct { + Cmd macho.LoadCmd + Len uint32 +} + +type dyldInfoCmd struct { + Cmd macho.LoadCmd + Len uint32 + RebaseOff, RebaseLen uint32 + BindOff, BindLen uint32 + WeakBindOff, WeakBindLen uint32 + LazyBindOff, LazyBindLen uint32 + ExportOff, ExportLen uint32 +} + +type linkEditDataCmd struct { + Cmd macho.LoadCmd + Len uint32 + DataOff, DataLen uint32 +} + +type encryptionInfoCmd struct { + Cmd macho.LoadCmd + Len uint32 + CryptOff, CryptLen uint32 + CryptId uint32 +} + +type loadCmdReader struct { + offset, next int64 + f *os.File + order binary.ByteOrder +} + +func (r *loadCmdReader) Next() (cmd loadCmd, err error) { + r.offset = r.next + if _, err = r.f.Seek(r.offset, 0); err != nil { + return + } + if err = binary.Read(r.f, r.order, &cmd); err != nil { + return + } + r.next = r.offset + int64(cmd.Len) + return +} + +func (r loadCmdReader) ReadAt(offset int64, data interface{}) error { + if _, err := r.f.Seek(r.offset+offset, 0); err != nil { + return err + } + return binary.Read(r.f, r.order, data) +} + +func (r loadCmdReader) WriteAt(offset int64, data interface{}) error { + if _, err := r.f.Seek(r.offset+offset, 0); err != nil { + return err + } + return binary.Write(r.f, r.order, data) +} + +// machoCombineDwarf merges dwarf info generated by dsymutil into a macho executable. +// With internal linking, DWARF is embedded into the executable, this lets us do the +// same for external linking. +// inexe is the path to the executable with no DWARF. It must have enough room in the macho +// header to add the DWARF sections. (Use ld's -headerpad option) +// dsym is the path to the macho file containing DWARF from dsymutil. +// outexe is the path where the combined executable should be saved. +func machoCombineDwarf(inexe, dsym, outexe string) error { + exef, err := os.Open(inexe) + if err != nil { + return err + } + dwarff, err := os.Open(dsym) + if err != nil { + return err + } + outf, err := os.Create(outexe) + if err != nil { + return err + } + outf.Chmod(0755) + + exem, err := macho.NewFile(exef) + if err != nil { + return err + } + dwarfm, err := macho.NewFile(dwarff) + if err != nil { + return err + } + + // The string table needs to be the last thing in the file + // for code signing to work. So we'll need to move the + // linkedit section, but all the others can be copied directly. + linkseg = exem.Segment("__LINKEDIT") + if linkseg == nil { + return fmt.Errorf("missing __LINKEDIT segment") + } + + if _, err = exef.Seek(0, 0); err != nil { + return err + } + if _, err := io.CopyN(outf, exef, int64(linkseg.Offset)); err != nil { + return err + } + + realdwarf = dwarfm.Segment("__DWARF") + if realdwarf == nil { + return fmt.Errorf("missing __DWARF segment") + } + + // Now copy the dwarf data into the output. + maxalign := uint32(dwarfMinAlign) // + for _, sect := range dwarfm.Sections { + if sect.Align > maxalign { + maxalign = sect.Align + } + } + dwarfstart = machoCalcStart(realdwarf.Offset, linkseg.Offset, maxalign) + if _, err = outf.Seek(dwarfstart, 0); err != nil { + return err + } + + if _, err = dwarff.Seek(int64(realdwarf.Offset), 0); err != nil { + return err + } + if _, err := io.CopyN(outf, dwarff, int64(realdwarf.Filesz)); err != nil { + return err + } + + // And finally the linkedit section. + if _, err = exef.Seek(int64(linkseg.Offset), 0); err != nil { + return err + } + linkstart = machoCalcStart(linkseg.Offset, uint64(dwarfstart)+realdwarf.Filesz, pageAlign) + linkoffset = uint32(linkstart - int64(linkseg.Offset)) + if _, err = outf.Seek(linkstart, 0); err != nil { + return err + } + if _, err := io.Copy(outf, exef); err != nil { + return err + } + + // Now we need to update the headers. + cmdOffset := unsafe.Sizeof(exem.FileHeader) + is64bit := exem.Magic == macho.Magic64 + if is64bit { + // mach_header_64 has one extra uint32. + cmdOffset += unsafe.Sizeof(exem.Magic) + } + + textsect := exem.Section("__text") + if linkseg == nil { + return fmt.Errorf("missing __text section") + } + + dwarfCmdOffset := int64(cmdOffset) + int64(exem.FileHeader.Cmdsz) + availablePadding := int64(textsect.Offset) - dwarfCmdOffset + if availablePadding < int64(realdwarf.Len) { + return fmt.Errorf("No room to add dwarf info. Need at least %d padding bytes, found %d", realdwarf.Len, availablePadding) + } + // First, copy the dwarf load command into the header + if _, err = outf.Seek(dwarfCmdOffset, 0); err != nil { + return err + } + if _, err := io.CopyN(outf, bytes.NewReader(realdwarf.Raw()), int64(realdwarf.Len)); err != nil { + return err + } + + if _, err = outf.Seek(int64(unsafe.Offsetof(exem.FileHeader.Ncmd)), 0); err != nil { + return err + } + if err = binary.Write(outf, exem.ByteOrder, exem.Ncmd+1); err != nil { + return err + } + if err = binary.Write(outf, exem.ByteOrder, exem.Cmdsz+realdwarf.Len); err != nil { + return err + } + + reader := loadCmdReader{next: int64(cmdOffset), f: outf, order: exem.ByteOrder} + for i := uint32(0); i < exem.Ncmd; i++ { + cmd, err := reader.Next() + if err != nil { + return err + } + switch cmd.Cmd { + case macho.LoadCmdSegment64: + err = machoUpdateSegment(reader, &macho.Segment64{}, &macho.Section64{}) + case macho.LoadCmdSegment: + err = machoUpdateSegment(reader, &macho.Segment32{}, &macho.Section32{}) + case LC_DYLD_INFO, LC_DYLD_INFO_ONLY: + err = machoUpdateLoadCommand(reader, &dyldInfoCmd{}, "RebaseOff", "BindOff", "WeakBindOff", "LazyBindOff", "ExportOff") + case macho.LoadCmdSymtab: + err = machoUpdateLoadCommand(reader, &macho.SymtabCmd{}, "Symoff", "Stroff") + case macho.LoadCmdDysymtab: + err = machoUpdateLoadCommand(reader, &macho.DysymtabCmd{}, "Tocoffset", "Modtaboff", "Extrefsymoff", "Indirectsymoff", "Extreloff", "Locreloff") + case LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS, LC_DATA_IN_CODE, LC_DYLIB_CODE_SIGN_DRS: + err = machoUpdateLoadCommand(reader, &linkEditDataCmd{}, "DataOff") + case LC_ENCRYPTION_INFO, LC_ENCRYPTION_INFO_64: + err = machoUpdateLoadCommand(reader, &encryptionInfoCmd{}, "CryptOff") + case macho.LoadCmdDylib, macho.LoadCmdThread, macho.LoadCmdUnixThread, LC_PREBOUND_DYLIB, LC_UUID, LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_SOURCE_VERSION, LC_MAIN, LC_LOAD_DYLINKER, LC_LOAD_WEAK_DYLIB, LC_REEXPORT_DYLIB, LC_RPATH: + // Nothing to update + default: + err = fmt.Errorf("Unknown load command 0x%x (%s)\n", int(cmd.Cmd), cmd.Cmd) + } + if err != nil { + return err + } + } + return machoUpdateDwarfHeader(&reader) +} + +// machoUpdateSegment updates the load command for a moved segment. +// Only the linkedit segment should move, and it should have 0 sections. +// seg should be a macho.Segment32 or macho.Segment64 as appropriate. +// sect should be a macho.Section32 or macho.Section64 as appropriate. +func machoUpdateSegment(r loadCmdReader, seg, sect interface{}) error { + if err := r.ReadAt(0, seg); err != nil { + return err + } + segValue := reflect.ValueOf(seg) + offset := reflect.Indirect(segValue).FieldByName("Offset") + + // Only the linkedit segment moved, any thing before that is fine. + if offset.Uint() < linkseg.Offset { + return nil + } + offset.SetUint(offset.Uint() + uint64(linkoffset)) + if err := r.WriteAt(0, seg); err != nil { + return err + } + // There shouldn't be any sections, but just to make sure... + return machoUpdateSections(r, segValue, reflect.ValueOf(sect), uint64(linkoffset)) +} + +func machoUpdateSections(r loadCmdReader, seg, sect reflect.Value, delta uint64) error { + iseg := reflect.Indirect(seg) + nsect := iseg.FieldByName("Nsect").Uint() + if nsect == 0 { + return nil + } + sectOffset := int64(iseg.Type().Size()) + + isect := reflect.Indirect(sect) + offsetField := isect.FieldByName("Offset") + reloffField := isect.FieldByName("Reloff") + sectSize := int64(isect.Type().Size()) + for i := uint64(0); i < nsect; i++ { + if err := r.ReadAt(sectOffset, sect.Interface()); err != nil { + return err + } + if offsetField.Uint() != 0 { + offsetField.SetUint(offsetField.Uint() + delta) + } + if reloffField.Uint() != 0 { + reloffField.SetUint(reloffField.Uint() + delta) + } + if err := r.WriteAt(sectOffset, sect.Interface()); err != nil { + return err + } + sectOffset += sectSize + } + return nil +} + +// machoUpdateDwarfHeader updates the DWARF segment load command. +func machoUpdateDwarfHeader(r *loadCmdReader) error { + var seg, sect interface{} + cmd, err := r.Next() + if err != nil { + return err + } + if cmd.Cmd == macho.LoadCmdSegment64 { + seg = new(macho.Segment64) + sect = new(macho.Section64) + } else { + seg = new(macho.Segment32) + sect = new(macho.Section32) + } + if err := r.ReadAt(0, seg); err != nil { + return err + } + segValue := reflect.ValueOf(seg) + offset := reflect.Indirect(segValue).FieldByName("Offset") + + delta := uint64(dwarfstart) - realdwarf.Offset + offset.SetUint(offset.Uint() + delta) + if err := r.WriteAt(0, seg); err != nil { + return err + } + return machoUpdateSections(*r, segValue, reflect.ValueOf(sect), delta) +} + +func machoUpdateLoadCommand(r loadCmdReader, cmd interface{}, fields ...string) error { + if err := r.ReadAt(0, cmd); err != nil { + return err + } + value := reflect.Indirect(reflect.ValueOf(cmd)) + + for _, name := range fields { + field := value.FieldByName(name) + fieldval := field.Uint() + if fieldval >= linkseg.Offset { + field.SetUint(fieldval + uint64(linkoffset)) + } + } + if err := r.WriteAt(0, cmd); err != nil { + return err + } + return nil +} + +func machoCalcStart(origAddr, newAddr uint64, alignExp uint32) int64 { + align := uint64(1 << alignExp) + if (origAddr % align) == (newAddr % align) { + return int64(newAddr) + } + padding := (align - (newAddr % align)) + padding += origAddr % align + return int64(padding + newAddr) +} From b3241912ff62ab64ec3c61bc8c198b6e12890a77 Mon Sep 17 00:00:00 2001 From: Alexander Zolotov Date: Sat, 9 May 2015 16:41:32 +0300 Subject: [PATCH 154/232] cmd/go: run gofmt from current GOROOT The existing implementation executes `gofmt` binary from PATH environment variable on invocation `go fmt` command. Relying on PATH might lead to confusions for users with several Go installations. It's more appropriate to run `gofmt` from GOBIN (if defined) or GOROOT. Fixes #10755 Change-Id: I56d42a747319c766f2911508fab3994c3a366d12 Reviewed-on: https://go-review.googlesource.com/9900 Reviewed-by: Rob Pike --- src/cmd/go/fmt.go | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/cmd/go/fmt.go b/src/cmd/go/fmt.go index 65dc3ca599..e40b0dc65f 100644 --- a/src/cmd/go/fmt.go +++ b/src/cmd/go/fmt.go @@ -4,6 +4,12 @@ package main +import ( + "os" + "path/filepath" + "runtime" +) + func init() { addBuildFlagsNX(cmdFmt) } @@ -29,10 +35,31 @@ See also: go fix, go vet. } func runFmt(cmd *Command, args []string) { + gofmt := gofmtPath() for _, pkg := range packages(args) { // Use pkg.gofiles instead of pkg.Dir so that // the command only applies to this package, // not to packages in subdirectories. - run(stringList("gofmt", "-l", "-w", relPaths(pkg.allgofiles))) + run(stringList(gofmt, "-l", "-w", relPaths(pkg.allgofiles))) } } + +func gofmtPath() string { + gofmt := "gofmt" + if toolIsWindows { + gofmt += toolWindowsExtension + } + + gofmtPath := filepath.Join(gobin, gofmt) + if _, err := os.Stat(gofmtPath); err == nil { + return gofmtPath + } + + gofmtPath = filepath.Join(goroot, "bin", gofmt) + if _, err := os.Stat(gofmtPath); err == nil { + return gofmtPath + } + + // fallback to looking for gofmt in $PATH + return "gofmt" +} From f763da3d3404673484bcc9d0d911c75a40e326c2 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Tue, 19 May 2015 16:58:14 -0400 Subject: [PATCH 155/232] cmd/internal/gc: remove incorrect "write barrier prohibited" error Commit 9c9e36b pushed these errors down to where the write barriers are actually emitted, but forgot to remove the original error that was being pushed down. Change-Id: I751752a896e78fb9e63d69f88e7fb8d1ff5d344c Reviewed-on: https://go-review.googlesource.com/10264 Reviewed-by: Russ Cox --- src/cmd/internal/gc/walk.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/cmd/internal/gc/walk.go b/src/cmd/internal/gc/walk.go index 36e4d66b33..b5b8611e5b 100644 --- a/src/cmd/internal/gc/walk.go +++ b/src/cmd/internal/gc/walk.go @@ -2206,9 +2206,6 @@ var applywritebarrier_bv Bvec func applywritebarrier(n *Node, init **NodeList) *Node { if n.Left != nil && n.Right != nil && needwritebarrier(n.Left, n.Right) { - if Curfn != nil && Curfn.Func.Nowritebarrier { - Yyerror("write barrier prohibited") - } if flag_race == 0 { if Debug_wb > 1 { Warnl(int(n.Lineno), "marking %v for barrier", Nconv(n.Left, 0)) From d6bbcea22a3d4cbcf8350b4b861f0d73ab142ac2 Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Tue, 19 May 2015 18:25:22 -0400 Subject: [PATCH 156/232] cmd/go: fix build Change-Id: Ib6c121414c74f8a40eb87a52af8737502ce7216d Reviewed-on: https://go-review.googlesource.com/10265 Reviewed-by: Josh Bleecher Snyder --- src/cmd/go/fmt.go | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cmd/go/fmt.go b/src/cmd/go/fmt.go index e40b0dc65f..1722b9d568 100644 --- a/src/cmd/go/fmt.go +++ b/src/cmd/go/fmt.go @@ -7,7 +7,6 @@ package main import ( "os" "path/filepath" - "runtime" ) func init() { From a1c1a763bc7c8d10ec30a7fa60ecf7d5f9a6f1c8 Mon Sep 17 00:00:00 2001 From: Didier Spezia Date: Thu, 14 May 2015 22:36:59 +0000 Subject: [PATCH 157/232] html/template: fix string iteration in replacement operations In css, js, and html, the replacement operations are implemented by iterating on strings (rune by rune). The for/range statement is used. The length of the rune is required and added to the index to properly slice the string. This is potentially wrong because there is a discrepancy between the result of utf8.RuneLen and the increment of the index (set by the for/range statement). For invalid strings, utf8.RuneLen('\ufffd') == 3, while the index is incremented only by 1 byte. htmlReplacer triggers a panic at slicing time for some invalid strings. Use a more robust iteration mechanism based on utf8.DecodeRuneInString, and make sure the same pattern is used for all similar functions in this package. Fixes #10799 Change-Id: Ibad3857b2819435d9fa564f06fc2ca8774102841 Reviewed-on: https://go-review.googlesource.com/10105 Reviewed-by: Rob Pike --- src/html/template/css.go | 76 ++++++++++++++-------------------- src/html/template/html.go | 13 +++--- src/html/template/html_test.go | 9 ++-- src/html/template/js.go | 8 ++-- 4 files changed, 51 insertions(+), 55 deletions(-) diff --git a/src/html/template/css.go b/src/html/template/css.go index 634f183f79..318464835f 100644 --- a/src/html/template/css.go +++ b/src/html/template/css.go @@ -157,56 +157,20 @@ func isCSSSpace(b byte) bool { func cssEscaper(args ...interface{}) string { s, _ := stringify(args...) var b bytes.Buffer - written := 0 - for i, r := range s { + r, w, written := rune(0), 0, 0 + for i := 0; i < len(s); i += w { + // See comment in htmlEscaper. + r, w = utf8.DecodeRuneInString(s[i:]) var repl string - switch r { - case 0: - repl = `\0` - case '\t': - repl = `\9` - case '\n': - repl = `\a` - case '\f': - repl = `\c` - case '\r': - repl = `\d` - // Encode HTML specials as hex so the output can be embedded - // in HTML attributes without further encoding. - case '"': - repl = `\22` - case '&': - repl = `\26` - case '\'': - repl = `\27` - case '(': - repl = `\28` - case ')': - repl = `\29` - case '+': - repl = `\2b` - case '/': - repl = `\2f` - case ':': - repl = `\3a` - case ';': - repl = `\3b` - case '<': - repl = `\3c` - case '>': - repl = `\3e` - case '\\': - repl = `\\` - case '{': - repl = `\7b` - case '}': - repl = `\7d` + switch { + case int(r) < len(cssReplacementTable) && cssReplacementTable[r] != "": + repl = cssReplacementTable[r] default: continue } b.WriteString(s[written:i]) b.WriteString(repl) - written = i + utf8.RuneLen(r) + written = i + w if repl != `\\` && (written == len(s) || isHex(s[written]) || isCSSSpace(s[written])) { b.WriteByte(' ') } @@ -218,6 +182,30 @@ func cssEscaper(args ...interface{}) string { return b.String() } +var cssReplacementTable = []string{ + 0: `\0`, + '\t': `\9`, + '\n': `\a`, + '\f': `\c`, + '\r': `\d`, + // Encode HTML specials as hex so the output can be embedded + // in HTML attributes without further encoding. + '"': `\22`, + '&': `\26`, + '\'': `\27`, + '(': `\28`, + ')': `\29`, + '+': `\2b`, + '/': `\2f`, + ':': `\3a`, + ';': `\3b`, + '<': `\3c`, + '>': `\3e`, + '\\': `\\`, + '{': `\7b`, + '}': `\7d`, +} + var expressionBytes = []byte("expression") var mozBindingBytes = []byte("mozbinding") diff --git a/src/html/template/html.go b/src/html/template/html.go index 9c069efd1d..de4aa4abb2 100644 --- a/src/html/template/html.go +++ b/src/html/template/html.go @@ -138,21 +138,24 @@ var htmlNospaceNormReplacementTable = []string{ // and when badRunes is true, certain bad runes are allowed through unescaped. func htmlReplacer(s string, replacementTable []string, badRunes bool) string { written, b := 0, new(bytes.Buffer) - for i, r := range s { + r, w := rune(0), 0 + for i := 0; i < len(s); i += w { + // Cannot use 'for range s' because we need to preserve the width + // of the runes in the input. If we see a decoding error, the input + // width will not be utf8.Runelen(r) and we will overrun the buffer. + r, w = utf8.DecodeRuneInString(s[i:]) if int(r) < len(replacementTable) { if repl := replacementTable[r]; len(repl) != 0 { b.WriteString(s[written:i]) b.WriteString(repl) - // Valid as long as replacementTable doesn't - // include anything above 0x7f. - written = i + utf8.RuneLen(r) + written = i + w } } else if badRunes { // No-op. // IE does not allow these ranges in unquoted attrs. } else if 0xfdd0 <= r && r <= 0xfdef || 0xfff0 <= r && r <= 0xffff { fmt.Fprintf(b, "%s%x;", s[written:i], r) - written = i + utf8.RuneLen(r) + written = i + w } } if written == 0 { diff --git a/src/html/template/html_test.go b/src/html/template/html_test.go index b9b9703875..f04ee04c27 100644 --- a/src/html/template/html_test.go +++ b/src/html/template/html_test.go @@ -19,7 +19,8 @@ func TestHTMLNospaceEscaper(t *testing.T) { `PQRSTUVWXYZ[\]^_` + "`abcdefghijklmno" + "pqrstuvwxyz{|}~\x7f" + - "\u00A0\u0100\u2028\u2029\ufeff\ufdec\U0001D11E") + "\u00A0\u0100\u2028\u2029\ufeff\ufdec\U0001D11E" + + "erroneous\x960") // keep at the end want := ("�\x01\x02\x03\x04\x05\x06\x07" + "\x08 \x0E\x0F" + @@ -31,14 +32,16 @@ func TestHTMLNospaceEscaper(t *testing.T) { `PQRSTUVWXYZ[\]^_` + ``abcdefghijklmno` + `pqrstuvwxyz{|}~` + "\u007f" + - "\u00A0\u0100\u2028\u2029\ufeff\U0001D11E") + "\u00A0\u0100\u2028\u2029\ufeff\U0001D11E" + + "erroneous�0") // keep at the end got := htmlNospaceEscaper(input) if got != want { t.Errorf("encode: want\n\t%q\nbut got\n\t%q", want, got) } - got, want = html.UnescapeString(got), strings.Replace(input, "\x00", "\ufffd", 1) + r := strings.NewReplacer("\x00", "\ufffd", "\x96", "\ufffd") + got, want = html.UnescapeString(got), r.Replace(input) if want != got { t.Errorf("decode: want\n\t%q\nbut got\n\t%q", want, got) } diff --git a/src/html/template/js.go b/src/html/template/js.go index 999a61ed07..f6d166b311 100644 --- a/src/html/template/js.go +++ b/src/html/template/js.go @@ -246,8 +246,10 @@ func jsRegexpEscaper(args ...interface{}) string { // `\u2029`. func replace(s string, replacementTable []string) string { var b bytes.Buffer - written := 0 - for i, r := range s { + r, w, written := rune(0), 0, 0 + for i := 0; i < len(s); i += w { + // See comment in htmlEscaper. + r, w = utf8.DecodeRuneInString(s[i:]) var repl string switch { case int(r) < len(replacementTable) && replacementTable[r] != "": @@ -261,7 +263,7 @@ func replace(s string, replacementTable []string) string { } b.WriteString(s[written:i]) b.WriteString(repl) - written = i + utf8.RuneLen(r) + written = i + w } if written == 0 { return s From 791bb4f5aefdf3d7ae8aea7d360dec6cb238698a Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Tue, 19 May 2015 03:39:30 -0400 Subject: [PATCH 158/232] cmd/internal/gc: handle 64-bit const i/j/k in cgen_slice on ARM 386 is not affected because it doesn't use ginscmp. Fixes #10843. Change-Id: I1b3a133bd1e5fabc85236f15d060dbaa4c391cf3 Reviewed-on: https://go-review.googlesource.com/10116 Reviewed-by: Russ Cox --- src/cmd/internal/gc/cgen.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/cmd/internal/gc/cgen.go b/src/cmd/internal/gc/cgen.go index e003ea9f4f..ca58b1c6a3 100644 --- a/src/cmd/internal/gc/cgen.go +++ b/src/cmd/internal/gc/cgen.go @@ -2987,6 +2987,11 @@ func cgen_append(n, res *Node) { // If wb is true, need write barrier updating res's base pointer. // On systems with 32-bit ints, i, j, k are guaranteed to be 32-bit values. func cgen_slice(n, res *Node, wb bool) { + if Debug['g'] != 0 { + Dump("cgen_slice-n", n) + Dump("cgen_slice-res", res) + } + needFullUpdate := !samesafeexpr(n.Left, res) // orderexpr has made sure that x is safe (but possibly expensive) @@ -3250,6 +3255,16 @@ func cgen_slice(n, res *Node, wb bool) { } compare := func(n1, n2 *Node) { + // n1 might be a 64-bit constant, even on 32-bit architectures, + // but it will be represented in 32 bits. + if Ctxt.Arch.Regsize == 4 && Is64(n1.Type) { + if mpcmpfixc(n1.Val.U.(*Mpint), 1<<31) >= 0 { + Fatal("missed slice out of bounds check") + } + var tmp Node + Nodconst(&tmp, indexRegType, Mpgetfix(n1.Val.U.(*Mpint))) + n1 = &tmp + } p := Thearch.Ginscmp(OGT, indexRegType, n1, n2, -1) panics = append(panics, p) } From c013417a45fbf950e8eb5a5e2ae37d2219c9e1d8 Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Tue, 19 May 2015 02:48:15 -0400 Subject: [PATCH 159/232] misc/cgo/testshared: when checking for RPATHs also look for DT_RUNPATH On my systems, ld -rpath sets DT_RUNPATH instead of DT_RPATH. Change-Id: I5047e795fb7ef9336f5fa13ba24bb6245c0b0582 Reviewed-on: https://go-review.googlesource.com/10260 Reviewed-by: Michael Hudson-Doyle Reviewed-by: Ian Lance Taylor --- misc/cgo/testshared/shared_test.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/misc/cgo/testshared/shared_test.go b/misc/cgo/testshared/shared_test.go index 81b9dffb07..fd577b03b5 100644 --- a/misc/cgo/testshared/shared_test.go +++ b/misc/cgo/testshared/shared_test.go @@ -192,10 +192,12 @@ func AssertIsLinkedTo(t *testing.T, path, lib string) { } func AssertHasRPath(t *testing.T, path, dir string) { - for _, dynstring := range dynStrings(path, elf.DT_RPATH) { - for _, rpath := range strings.Split(dynstring, ":") { - if filepath.Clean(rpath) == filepath.Clean(dir) { - return + for _, tag := range []elf.DynTag{elf.DT_RPATH, elf.DT_RUNPATH} { + for _, dynstring := range dynStrings(path, tag) { + for _, rpath := range strings.Split(dynstring, ":") { + if filepath.Clean(rpath) == filepath.Clean(dir) { + return + } } } } From 7bdb4a28a87f24a6c00ae3194598934e0fa142f0 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Tue, 19 May 2015 23:49:24 +0000 Subject: [PATCH 160/232] Revert "cmd/internal/ld: output dwarf in external link mode on darwin" This reverts commit 8b83306cf20abed54d7cb23a3f3091b7e6202056. Change-Id: I3fb998bdf11eceef13e3997e336d86e7c5d47a60 Reviewed-on: https://go-review.googlesource.com/10254 Reviewed-by: Minux Ma --- src/cmd/5l/asm.go | 14 +- src/cmd/6l/asm.go | 2 +- src/cmd/7l/asm.go | 14 +- src/cmd/8l/asm.go | 2 +- src/cmd/internal/ld/dwarf.go | 155 ++------- src/cmd/internal/ld/lib.go | 21 +- src/cmd/internal/ld/macho.go | 8 +- src/cmd/internal/ld/macho_combine_dwarf.go | 369 --------------------- 8 files changed, 58 insertions(+), 527 deletions(-) delete mode 100644 src/cmd/internal/ld/macho_combine_dwarf.go diff --git a/src/cmd/5l/asm.go b/src/cmd/5l/asm.go index 70d6790fc1..1b69671b9f 100644 --- a/src/cmd/5l/asm.go +++ b/src/cmd/5l/asm.go @@ -533,12 +533,14 @@ func asmb() { fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime()) } - dwarfoff := uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) - ld.Cseek(int64(dwarfoff)) + if ld.Debug['w'] == 0 { // TODO(minux): enable DWARF Support + dwarfoff := uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) + ld.Cseek(int64(dwarfoff)) - ld.Segdwarf.Fileoff = uint64(ld.Cpos()) - ld.Dwarfemitdebugsections() - ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff + ld.Segdwarf.Fileoff = uint64(ld.Cpos()) + ld.Dwarfemitdebugsections() + ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff + } machlink = uint32(ld.Domacholink()) } @@ -565,7 +567,7 @@ func asmb() { symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen) case obj.Hdarwin: - symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink)) + symo = uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Filelen), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)) + int64(machlink)) } ld.Cseek(int64(symo)) diff --git a/src/cmd/6l/asm.go b/src/cmd/6l/asm.go index 02b4c7cdd2..5520a5acf1 100644 --- a/src/cmd/6l/asm.go +++ b/src/cmd/6l/asm.go @@ -710,7 +710,7 @@ func asmb() { symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen) case obj.Hdarwin: - symo = int64(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink)) + symo = int64(ld.Segdata.Fileoff + uint64(ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) + uint64(machlink)) case obj.Hlinux, obj.Hfreebsd, diff --git a/src/cmd/7l/asm.go b/src/cmd/7l/asm.go index 064ff56283..3dfb8c666d 100644 --- a/src/cmd/7l/asm.go +++ b/src/cmd/7l/asm.go @@ -317,12 +317,14 @@ func asmb() { fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime()) } - dwarfoff := uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) - ld.Cseek(int64(dwarfoff)) + if ld.Debug['w'] == 0 { // TODO(minux): enable DWARF Support + dwarfoff := uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) + ld.Cseek(int64(dwarfoff)) - ld.Segdwarf.Fileoff = uint64(ld.Cpos()) - ld.Dwarfemitdebugsections() - ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff + ld.Segdwarf.Fileoff = uint64(ld.Cpos()) + ld.Dwarfemitdebugsections() + ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff + } machlink = uint32(ld.Domacholink()) } @@ -349,7 +351,7 @@ func asmb() { symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen) case obj.Hdarwin: - symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink)) + symo = uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Filelen), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)) + int64(machlink)) } ld.Cseek(int64(symo)) diff --git a/src/cmd/8l/asm.go b/src/cmd/8l/asm.go index a736d43686..a63c51f58d 100644 --- a/src/cmd/8l/asm.go +++ b/src/cmd/8l/asm.go @@ -551,7 +551,7 @@ func asmb() { symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen) case obj.Hdarwin: - symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink)) + symo = uint32(ld.Segdata.Fileoff + uint64(ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) + uint64(machlink)) case obj.Hwindows: symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen) diff --git a/src/cmd/internal/ld/dwarf.go b/src/cmd/internal/ld/dwarf.go index 841ef9abf9..476b329e7a 100644 --- a/src/cmd/internal/ld/dwarf.go +++ b/src/cmd/internal/ld/dwarf.go @@ -17,7 +17,6 @@ package ld import ( "cmd/internal/obj" "fmt" - "os" "strings" ) @@ -241,7 +240,6 @@ var abbrevs = [DW_NABRV]DWAbbrev{ {DW_AT_low_pc, DW_FORM_addr}, {DW_AT_high_pc, DW_FORM_addr}, {DW_AT_stmt_list, DW_FORM_data4}, - {DW_AT_comp_dir, DW_FORM_string}, }, }, @@ -696,9 +694,6 @@ func adddwarfrel(sec *LSym, sym *LSym, offsetbase int64, siz int, addend int64) if Iself && Thearch.Thechar == '6' { addend = 0 } - if HEADTYPE == obj.Hdarwin { - addend += sym.Value - } switch siz { case 4: Thearch.Lput(uint32(addend)) @@ -1552,13 +1547,6 @@ func flushunit(dwinfo *DWDie, pc int64, pcsym *LSym, unitstart int64, header_len } } -func getCompilationDir() string { - if dir, err := os.Getwd(); err == nil { - return dir - } - return "/" -} - func writelines() { if linesec == nil { linesec = Linklookup(Ctxt, ".dwarfline", 0) @@ -1583,9 +1571,6 @@ func writelines() { newattr(dwinfo, DW_AT_language, DW_CLS_CONSTANT, int64(lang), 0) newattr(dwinfo, DW_AT_stmt_list, DW_CLS_PTR, unitstart-lineo, 0) newattr(dwinfo, DW_AT_low_pc, DW_CLS_ADDRESS, s.Value, s) - // OS X linker requires compilation dir or absolute path in comp unit name to output debug info. - compDir := getCompilationDir() - newattr(dwinfo, DW_AT_comp_dir, DW_CLS_STRING, int64(len(compDir)), compDir) // Write .debug_line Line Number Program Header (sec 6.2.4) // Fields marked with (*) must be changed for 64-bit dwarf @@ -2098,14 +2083,6 @@ func writedwarfreloc(s *LSym) int64 { return start } -func addmachodwarfsect(prev *Section, name string) *Section { - sect := addsection(&Segdwarf, name, 04) - sect.Extnum = prev.Extnum + 1 - sym := Linklookup(Ctxt, name, 0) - sym.Sect = sect - return sect -} - /* * This is the main entry point for generating dwarf. After emitting * the mandatory debug_abbrev section, it calls writelines() to set up @@ -2120,32 +2097,8 @@ func Dwarfemitdebugsections() { return } - if Linkmode == LinkExternal { - if !Iself && HEADTYPE != obj.Hdarwin { - return - } - if HEADTYPE == obj.Hdarwin { - sect := Segdata.Sect - // find the last section. - for sect.Next != nil { - sect = sect.Next - } - sect = addmachodwarfsect(sect, ".debug_abbrev") - sect = addmachodwarfsect(sect, ".debug_line") - sect = addmachodwarfsect(sect, ".debug_frame") - sect = addmachodwarfsect(sect, ".debug_info") - } - infosym = Linklookup(Ctxt, ".debug_info", 0) - infosym.Hide = 1 - - abbrevsym = Linklookup(Ctxt, ".debug_abbrev", 0) - abbrevsym.Hide = 1 - - linesym = Linklookup(Ctxt, ".debug_line", 0) - linesym.Hide = 1 - - framesym = Linklookup(Ctxt, ".debug_frame", 0) - framesym.Hide = 1 + if Linkmode == LinkExternal && !Iself { + return } // For diagnostic messages. @@ -2238,15 +2191,6 @@ func Dwarfemitdebugsections() { for Cpos()&7 != 0 { Cput(0) } - if HEADTYPE != obj.Hdarwin { - dwarfemitreloc() - } -} - -func dwarfemitreloc() { - if Debug['w'] != 0 { // disable dwarf - return - } inforeloco = writedwarfreloc(infosec) inforelocsize = Cpos() - inforeloco align(inforelocsize) @@ -2319,6 +2263,18 @@ func dwarfaddshstrings(shstrtab *LSym) { elfstrdbg[ElfStrRelDebugLine] = Addstring(shstrtab, ".rel.debug_line") elfstrdbg[ElfStrRelDebugFrame] = Addstring(shstrtab, ".rel.debug_frame") } + + infosym = Linklookup(Ctxt, ".debug_info", 0) + infosym.Hide = 1 + + abbrevsym = Linklookup(Ctxt, ".debug_abbrev", 0) + abbrevsym.Hide = 1 + + linesym = Linklookup(Ctxt, ".debug_line", 0) + linesym.Hide = 1 + + framesym = Linklookup(Ctxt, ".debug_frame", 0) + framesym.Hide = 1 } } @@ -2464,15 +2420,14 @@ func dwarfaddelfheaders() { /* * Macho */ -func dwarfaddmachoheaders(ms *MachoSeg) { +func dwarfaddmachoheaders() { if Debug['w'] != 0 { // disable dwarf return } // Zero vsize segments won't be loaded in memory, even so they // have to be page aligned in the file. - fakestart := Rnd(int64(Segdwarf.Fileoff), 0x1000) - addr := Segdata.Vaddr + Segdata.Length + fakestart := abbrevo &^ 0xfff nsect := 4 if pubnamessize > 0 { @@ -2488,94 +2443,57 @@ func dwarfaddmachoheaders(ms *MachoSeg) { nsect++ } - if Linkmode != LinkExternal { - ms = newMachoSeg("__DWARF", nsect) - ms.fileoffset = uint64(fakestart) - ms.filesize = Segdwarf.Filelen - ms.vaddr = addr - } + ms := newMachoSeg("__DWARF", nsect) + ms.fileoffset = uint64(fakestart) + ms.filesize = uint64(abbrevo) - uint64(fakestart) + ms.vaddr = ms.fileoffset + Segdata.Vaddr - Segdata.Fileoff msect := newMachoSect(ms, "__debug_abbrev", "__DWARF") msect.off = uint32(abbrevo) msect.size = uint64(abbrevsize) - msect.addr = addr - addr += msect.size - msect.flag = 0x02000000 - if abbrevsym != nil { - abbrevsym.Value = int64(msect.addr) - } + msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff + ms.filesize += msect.size msect = newMachoSect(ms, "__debug_line", "__DWARF") msect.off = uint32(lineo) msect.size = uint64(linesize) - msect.addr = addr - addr += msect.size - msect.flag = 0x02000000 - if linesym != nil { - linesym.Value = int64(msect.addr) - } - if linerelocsize > 0 { - msect.nreloc = uint32(len(linesec.R)) - msect.reloc = uint32(linereloco) - } + msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff + ms.filesize += msect.size msect = newMachoSect(ms, "__debug_frame", "__DWARF") msect.off = uint32(frameo) msect.size = uint64(framesize) - msect.addr = addr - addr += msect.size - msect.flag = 0x02000000 - if framesym != nil { - framesym.Value = int64(msect.addr) - } - if framerelocsize > 0 { - msect.nreloc = uint32(len(framesec.R)) - msect.reloc = uint32(framereloco) - } + msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff + ms.filesize += msect.size msect = newMachoSect(ms, "__debug_info", "__DWARF") msect.off = uint32(infoo) msect.size = uint64(infosize) - msect.addr = addr - addr += msect.size - msect.flag = 0x02000000 - if infosym != nil { - infosym.Value = int64(msect.addr) - } - if inforelocsize > 0 { - msect.nreloc = uint32(len(infosec.R)) - msect.reloc = uint32(inforeloco) - } + msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff + ms.filesize += msect.size if pubnamessize > 0 { msect := newMachoSect(ms, "__debug_pubnames", "__DWARF") msect.off = uint32(pubnameso) msect.size = uint64(pubnamessize) - msect.addr = addr - addr += msect.size - msect.flag = 0x02000000 + msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff + ms.filesize += msect.size } if pubtypessize > 0 { msect := newMachoSect(ms, "__debug_pubtypes", "__DWARF") msect.off = uint32(pubtypeso) msect.size = uint64(pubtypessize) - msect.addr = addr - addr += msect.size - msect.flag = 0x02000000 + msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff + ms.filesize += msect.size } if arangessize > 0 { msect := newMachoSect(ms, "__debug_aranges", "__DWARF") msect.off = uint32(arangeso) msect.size = uint64(arangessize) - msect.addr = addr - addr += msect.size - msect.flag = 0x02000000 - if arangesrelocsize > 0 { - msect.nreloc = uint32(len(arangessec.R)) - msect.reloc = uint32(arangesreloco) - } + msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff + ms.filesize += msect.size } // TODO(lvd) fix gdb/python to load MachO (16 char section name limit) @@ -2583,9 +2501,8 @@ func dwarfaddmachoheaders(ms *MachoSeg) { msect := newMachoSect(ms, "__debug_gdb_scripts", "__DWARF") msect.off = uint32(gdbscripto) msect.size = uint64(gdbscriptsize) - msect.addr = addr - addr += msect.size - msect.flag = 0x02000000 + msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff + ms.filesize += msect.size } } diff --git a/src/cmd/internal/ld/lib.go b/src/cmd/internal/ld/lib.go index a36cd0f8f4..753e8eebd8 100644 --- a/src/cmd/internal/ld/lib.go +++ b/src/cmd/internal/ld/lib.go @@ -922,7 +922,7 @@ func hostlink() { } if HEADTYPE == obj.Hdarwin { - argv = append(argv, "-Wl,-no_pie,-pagezero_size,4000000,-headerpad,1144") + argv = append(argv, "-Wl,-no_pie,-pagezero_size,4000000") } if HEADTYPE == obj.Hopenbsd { argv = append(argv, "-Wl,-nopie") @@ -1029,25 +1029,6 @@ func hostlink() { if out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput(); err != nil { Exitf("running %s failed: %v\n%s", argv[0], err, out) } - - if Debug['s'] == 0 && debug_s == 0 && HEADTYPE == obj.Hdarwin { - dsym := fmt.Sprintf("%s/go.dwarf", tmpdir) - if out, err := exec.Command("dsymutil", "-f", outfile, "-o", dsym).CombinedOutput(); err != nil { - Ctxt.Cursym = nil - Exitf("%s: running dsymutil failed: %v\n%s", os.Args[0], err, out) - } - combinedOutput := fmt.Sprintf("%s/go.combined", tmpdir) - if err := machoCombineDwarf(outfile, dsym, combinedOutput); err != nil { - Ctxt.Cursym = nil - Exitf("%s: combining dwarf failed: %v", os.Args[0], err) - } - origOutput := fmt.Sprintf("%s/go.orig", tmpdir) - os.Rename(outfile, origOutput) - if err := os.Rename(combinedOutput, outfile); err != nil { - Ctxt.Cursym = nil - Exitf("%s: rename(%s, %s) failed: %v", os.Args[0], combinedOutput, outfile, err) - } - } } func ldobj(f *obj.Biobuf, pkg string, length int64, pn string, file string, whence int) { diff --git a/src/cmd/internal/ld/macho.go b/src/cmd/internal/ld/macho.go index 0258aff104..ceeb7b0f5d 100644 --- a/src/cmd/internal/ld/macho.go +++ b/src/cmd/internal/ld/macho.go @@ -443,8 +443,7 @@ func Asmbmacho() { ms = newMachoSeg("", 40) ms.fileoffset = Segtext.Fileoff - ms.filesize = Segdwarf.Fileoff + Segdwarf.Filelen - Segtext.Fileoff - ms.vsize = ms.filesize + ms.filesize = Segdata.Fileoff + Segdata.Filelen - Segtext.Fileoff } /* segment for zero page */ @@ -562,8 +561,8 @@ func Asmbmacho() { } // TODO: dwarf headers go in ms too - if Debug['s'] == 0 { - dwarfaddmachoheaders(ms) + if Debug['s'] == 0 && Linkmode != LinkExternal { + dwarfaddmachoheaders() } a := machowrite() @@ -851,5 +850,4 @@ func Machoemitreloc() { for sect := Segdata.Sect; sect != nil; sect = sect.Next { machorelocsect(sect, datap) } - dwarfemitreloc() } diff --git a/src/cmd/internal/ld/macho_combine_dwarf.go b/src/cmd/internal/ld/macho_combine_dwarf.go deleted file mode 100644 index 9134373a52..0000000000 --- a/src/cmd/internal/ld/macho_combine_dwarf.go +++ /dev/null @@ -1,369 +0,0 @@ -// Copyright 2015 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 ld - -import ( - "bytes" - "debug/macho" - "encoding/binary" - "fmt" - "io" - "os" - "reflect" - "unsafe" -) - -var fakedwarf, realdwarf, linkseg *macho.Segment -var dwarfstart, linkstart int64 -var linkoffset uint32 -var machHeader *macho.FileHeader -var mappedHeader []byte - -const ( - LC_LOAD_DYLINKER = 0xe - LC_PREBOUND_DYLIB = 0x10 - LC_LOAD_WEAK_DYLIB = 0x18 - LC_UUID = 0x1b - LC_RPATH = 0x8000001c - LC_CODE_SIGNATURE = 0x1d - LC_SEGMENT_SPLIT_INFO = 0x1e - LC_REEXPORT_DYLIB = 0x8000001f - LC_ENCRYPTION_INFO = 0x21 - LC_DYLD_INFO = 0x22 - LC_DYLD_INFO_ONLY = 0x80000022 - LC_VERSION_MIN_MACOSX = 0x24 - LC_VERSION_MIN_IPHONEOS = 0x25 - LC_FUNCTION_STARTS = 0x26 - LC_MAIN = 0x80000028 - LC_DATA_IN_CODE = 0x29 - LC_SOURCE_VERSION = 0x2A - LC_DYLIB_CODE_SIGN_DRS = 0x2B - LC_ENCRYPTION_INFO_64 = 0x2C - - dwarfMinAlign = 6 // 64 = 1 << 6 - pageAlign = 12 // 4096 = 1 << 12 -) - -type loadCmd struct { - Cmd macho.LoadCmd - Len uint32 -} - -type dyldInfoCmd struct { - Cmd macho.LoadCmd - Len uint32 - RebaseOff, RebaseLen uint32 - BindOff, BindLen uint32 - WeakBindOff, WeakBindLen uint32 - LazyBindOff, LazyBindLen uint32 - ExportOff, ExportLen uint32 -} - -type linkEditDataCmd struct { - Cmd macho.LoadCmd - Len uint32 - DataOff, DataLen uint32 -} - -type encryptionInfoCmd struct { - Cmd macho.LoadCmd - Len uint32 - CryptOff, CryptLen uint32 - CryptId uint32 -} - -type loadCmdReader struct { - offset, next int64 - f *os.File - order binary.ByteOrder -} - -func (r *loadCmdReader) Next() (cmd loadCmd, err error) { - r.offset = r.next - if _, err = r.f.Seek(r.offset, 0); err != nil { - return - } - if err = binary.Read(r.f, r.order, &cmd); err != nil { - return - } - r.next = r.offset + int64(cmd.Len) - return -} - -func (r loadCmdReader) ReadAt(offset int64, data interface{}) error { - if _, err := r.f.Seek(r.offset+offset, 0); err != nil { - return err - } - return binary.Read(r.f, r.order, data) -} - -func (r loadCmdReader) WriteAt(offset int64, data interface{}) error { - if _, err := r.f.Seek(r.offset+offset, 0); err != nil { - return err - } - return binary.Write(r.f, r.order, data) -} - -// machoCombineDwarf merges dwarf info generated by dsymutil into a macho executable. -// With internal linking, DWARF is embedded into the executable, this lets us do the -// same for external linking. -// inexe is the path to the executable with no DWARF. It must have enough room in the macho -// header to add the DWARF sections. (Use ld's -headerpad option) -// dsym is the path to the macho file containing DWARF from dsymutil. -// outexe is the path where the combined executable should be saved. -func machoCombineDwarf(inexe, dsym, outexe string) error { - exef, err := os.Open(inexe) - if err != nil { - return err - } - dwarff, err := os.Open(dsym) - if err != nil { - return err - } - outf, err := os.Create(outexe) - if err != nil { - return err - } - outf.Chmod(0755) - - exem, err := macho.NewFile(exef) - if err != nil { - return err - } - dwarfm, err := macho.NewFile(dwarff) - if err != nil { - return err - } - - // The string table needs to be the last thing in the file - // for code signing to work. So we'll need to move the - // linkedit section, but all the others can be copied directly. - linkseg = exem.Segment("__LINKEDIT") - if linkseg == nil { - return fmt.Errorf("missing __LINKEDIT segment") - } - - if _, err = exef.Seek(0, 0); err != nil { - return err - } - if _, err := io.CopyN(outf, exef, int64(linkseg.Offset)); err != nil { - return err - } - - realdwarf = dwarfm.Segment("__DWARF") - if realdwarf == nil { - return fmt.Errorf("missing __DWARF segment") - } - - // Now copy the dwarf data into the output. - maxalign := uint32(dwarfMinAlign) // - for _, sect := range dwarfm.Sections { - if sect.Align > maxalign { - maxalign = sect.Align - } - } - dwarfstart = machoCalcStart(realdwarf.Offset, linkseg.Offset, maxalign) - if _, err = outf.Seek(dwarfstart, 0); err != nil { - return err - } - - if _, err = dwarff.Seek(int64(realdwarf.Offset), 0); err != nil { - return err - } - if _, err := io.CopyN(outf, dwarff, int64(realdwarf.Filesz)); err != nil { - return err - } - - // And finally the linkedit section. - if _, err = exef.Seek(int64(linkseg.Offset), 0); err != nil { - return err - } - linkstart = machoCalcStart(linkseg.Offset, uint64(dwarfstart)+realdwarf.Filesz, pageAlign) - linkoffset = uint32(linkstart - int64(linkseg.Offset)) - if _, err = outf.Seek(linkstart, 0); err != nil { - return err - } - if _, err := io.Copy(outf, exef); err != nil { - return err - } - - // Now we need to update the headers. - cmdOffset := unsafe.Sizeof(exem.FileHeader) - is64bit := exem.Magic == macho.Magic64 - if is64bit { - // mach_header_64 has one extra uint32. - cmdOffset += unsafe.Sizeof(exem.Magic) - } - - textsect := exem.Section("__text") - if linkseg == nil { - return fmt.Errorf("missing __text section") - } - - dwarfCmdOffset := int64(cmdOffset) + int64(exem.FileHeader.Cmdsz) - availablePadding := int64(textsect.Offset) - dwarfCmdOffset - if availablePadding < int64(realdwarf.Len) { - return fmt.Errorf("No room to add dwarf info. Need at least %d padding bytes, found %d", realdwarf.Len, availablePadding) - } - // First, copy the dwarf load command into the header - if _, err = outf.Seek(dwarfCmdOffset, 0); err != nil { - return err - } - if _, err := io.CopyN(outf, bytes.NewReader(realdwarf.Raw()), int64(realdwarf.Len)); err != nil { - return err - } - - if _, err = outf.Seek(int64(unsafe.Offsetof(exem.FileHeader.Ncmd)), 0); err != nil { - return err - } - if err = binary.Write(outf, exem.ByteOrder, exem.Ncmd+1); err != nil { - return err - } - if err = binary.Write(outf, exem.ByteOrder, exem.Cmdsz+realdwarf.Len); err != nil { - return err - } - - reader := loadCmdReader{next: int64(cmdOffset), f: outf, order: exem.ByteOrder} - for i := uint32(0); i < exem.Ncmd; i++ { - cmd, err := reader.Next() - if err != nil { - return err - } - switch cmd.Cmd { - case macho.LoadCmdSegment64: - err = machoUpdateSegment(reader, &macho.Segment64{}, &macho.Section64{}) - case macho.LoadCmdSegment: - err = machoUpdateSegment(reader, &macho.Segment32{}, &macho.Section32{}) - case LC_DYLD_INFO, LC_DYLD_INFO_ONLY: - err = machoUpdateLoadCommand(reader, &dyldInfoCmd{}, "RebaseOff", "BindOff", "WeakBindOff", "LazyBindOff", "ExportOff") - case macho.LoadCmdSymtab: - err = machoUpdateLoadCommand(reader, &macho.SymtabCmd{}, "Symoff", "Stroff") - case macho.LoadCmdDysymtab: - err = machoUpdateLoadCommand(reader, &macho.DysymtabCmd{}, "Tocoffset", "Modtaboff", "Extrefsymoff", "Indirectsymoff", "Extreloff", "Locreloff") - case LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS, LC_DATA_IN_CODE, LC_DYLIB_CODE_SIGN_DRS: - err = machoUpdateLoadCommand(reader, &linkEditDataCmd{}, "DataOff") - case LC_ENCRYPTION_INFO, LC_ENCRYPTION_INFO_64: - err = machoUpdateLoadCommand(reader, &encryptionInfoCmd{}, "CryptOff") - case macho.LoadCmdDylib, macho.LoadCmdThread, macho.LoadCmdUnixThread, LC_PREBOUND_DYLIB, LC_UUID, LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_SOURCE_VERSION, LC_MAIN, LC_LOAD_DYLINKER, LC_LOAD_WEAK_DYLIB, LC_REEXPORT_DYLIB, LC_RPATH: - // Nothing to update - default: - err = fmt.Errorf("Unknown load command 0x%x (%s)\n", int(cmd.Cmd), cmd.Cmd) - } - if err != nil { - return err - } - } - return machoUpdateDwarfHeader(&reader) -} - -// machoUpdateSegment updates the load command for a moved segment. -// Only the linkedit segment should move, and it should have 0 sections. -// seg should be a macho.Segment32 or macho.Segment64 as appropriate. -// sect should be a macho.Section32 or macho.Section64 as appropriate. -func machoUpdateSegment(r loadCmdReader, seg, sect interface{}) error { - if err := r.ReadAt(0, seg); err != nil { - return err - } - segValue := reflect.ValueOf(seg) - offset := reflect.Indirect(segValue).FieldByName("Offset") - - // Only the linkedit segment moved, any thing before that is fine. - if offset.Uint() < linkseg.Offset { - return nil - } - offset.SetUint(offset.Uint() + uint64(linkoffset)) - if err := r.WriteAt(0, seg); err != nil { - return err - } - // There shouldn't be any sections, but just to make sure... - return machoUpdateSections(r, segValue, reflect.ValueOf(sect), uint64(linkoffset)) -} - -func machoUpdateSections(r loadCmdReader, seg, sect reflect.Value, delta uint64) error { - iseg := reflect.Indirect(seg) - nsect := iseg.FieldByName("Nsect").Uint() - if nsect == 0 { - return nil - } - sectOffset := int64(iseg.Type().Size()) - - isect := reflect.Indirect(sect) - offsetField := isect.FieldByName("Offset") - reloffField := isect.FieldByName("Reloff") - sectSize := int64(isect.Type().Size()) - for i := uint64(0); i < nsect; i++ { - if err := r.ReadAt(sectOffset, sect.Interface()); err != nil { - return err - } - if offsetField.Uint() != 0 { - offsetField.SetUint(offsetField.Uint() + delta) - } - if reloffField.Uint() != 0 { - reloffField.SetUint(reloffField.Uint() + delta) - } - if err := r.WriteAt(sectOffset, sect.Interface()); err != nil { - return err - } - sectOffset += sectSize - } - return nil -} - -// machoUpdateDwarfHeader updates the DWARF segment load command. -func machoUpdateDwarfHeader(r *loadCmdReader) error { - var seg, sect interface{} - cmd, err := r.Next() - if err != nil { - return err - } - if cmd.Cmd == macho.LoadCmdSegment64 { - seg = new(macho.Segment64) - sect = new(macho.Section64) - } else { - seg = new(macho.Segment32) - sect = new(macho.Section32) - } - if err := r.ReadAt(0, seg); err != nil { - return err - } - segValue := reflect.ValueOf(seg) - offset := reflect.Indirect(segValue).FieldByName("Offset") - - delta := uint64(dwarfstart) - realdwarf.Offset - offset.SetUint(offset.Uint() + delta) - if err := r.WriteAt(0, seg); err != nil { - return err - } - return machoUpdateSections(*r, segValue, reflect.ValueOf(sect), delta) -} - -func machoUpdateLoadCommand(r loadCmdReader, cmd interface{}, fields ...string) error { - if err := r.ReadAt(0, cmd); err != nil { - return err - } - value := reflect.Indirect(reflect.ValueOf(cmd)) - - for _, name := range fields { - field := value.FieldByName(name) - fieldval := field.Uint() - if fieldval >= linkseg.Offset { - field.SetUint(fieldval + uint64(linkoffset)) - } - } - if err := r.WriteAt(0, cmd); err != nil { - return err - } - return nil -} - -func machoCalcStart(origAddr, newAddr uint64, alignExp uint32) int64 { - align := uint64(1 << alignExp) - if (origAddr % align) == (newAddr % align) { - return int64(newAddr) - } - padding := (align - (newAddr % align)) - padding += origAddr % align - return int64(padding + newAddr) -} From 17177a0daa7d08c7031fe10b9be8d070db5fe278 Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Mon, 18 May 2015 17:27:33 +0900 Subject: [PATCH 161/232] net: fix data race in TestSocket{Conn,PacketConn} Fixes #10891. Change-Id: Ie432c9c5520ac29cea8fe6452628ec467567eea5 Reviewed-on: https://go-review.googlesource.com/10194 Reviewed-by: Ian Lance Taylor --- src/net/file_bsd_test.go | 5 +++-- src/net/file_linux_test.go | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/net/file_bsd_test.go b/src/net/file_bsd_test.go index 6e6cf126ad..ffe3c612b4 100644 --- a/src/net/file_bsd_test.go +++ b/src/net/file_bsd_test.go @@ -49,8 +49,11 @@ func TestSocketConn(t *testing.T) { defer c.Close() const N = 3 + var wg sync.WaitGroup + wg.Add(2 * N) for i := 0; i < N; i++ { go func(i int) { + defer wg.Done() l := syscall.SizeofRtMsghdr + syscall.SizeofSockaddrInet4 if freebsd32o64 { l += syscall.SizeofRtMetrics // see syscall/route_freebsd_32bit.go @@ -73,8 +76,6 @@ func TestSocketConn(t *testing.T) { } }(i + 1) } - var wg sync.WaitGroup - wg.Add(N) for i := 0; i < N; i++ { go func() { defer wg.Done() diff --git a/src/net/file_linux_test.go b/src/net/file_linux_test.go index 58f74d2cc5..e04fea38f6 100644 --- a/src/net/file_linux_test.go +++ b/src/net/file_linux_test.go @@ -59,9 +59,12 @@ func TestSocketPacketConn(t *testing.T) { defer c.Close() const N = 3 + var wg sync.WaitGroup + wg.Add(2 * N) dst := &netlinkAddr{PID: 0} for i := 0; i < N; i++ { go func() { + defer wg.Done() l := syscall.NLMSG_HDRLEN + syscall.SizeofRtGenmsg b := make([]byte, l) *(*uint32)(unsafe.Pointer(&b[0:4][0])) = uint32(l) @@ -76,8 +79,6 @@ func TestSocketPacketConn(t *testing.T) { } }() } - var wg sync.WaitGroup - wg.Add(N) for i := 0; i < N; i++ { go func() { defer wg.Done() From 7eec656bfd111531f548dbb5c7f3b6d18525f4ab Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Wed, 13 May 2015 12:44:45 +0900 Subject: [PATCH 162/232] net: fix the series of TestLookup and external tests On Windows, we need to make sure that the node under test has external connectivity. Fixes #10795. Change-Id: I99f2336180c7b56474fa90a4a6cdd5a6c4dd3805 Reviewed-on: https://go-review.googlesource.com/10006 Reviewed-by: Ian Lance Taylor --- src/net/external_test.go | 43 ++----- src/net/lookup_test.go | 236 +++++++++++++++++++++++++++------------ src/net/main_test.go | 6 + 3 files changed, 178 insertions(+), 107 deletions(-) diff --git a/src/net/external_test.go b/src/net/external_test.go index 20611ff420..d5ff2be20a 100644 --- a/src/net/external_test.go +++ b/src/net/external_test.go @@ -15,33 +15,23 @@ func TestResolveGoogle(t *testing.T) { if testing.Short() || !*testExternal { t.Skip("avoid external network") } - if !supportsIPv4 && !supportsIPv6 { - t.Skip("ipv4 and ipv6 are not supported") + if !supportsIPv4 || !supportsIPv6 || !*testIPv4 || !*testIPv6 { + t.Skip("both IPv4 and IPv6 are required") } for _, network := range []string{"tcp", "tcp4", "tcp6"} { addr, err := ResolveTCPAddr(network, "www.google.com:http") if err != nil { - switch { - case network == "tcp" && !supportsIPv4: - fallthrough - case network == "tcp4" && !supportsIPv4: - t.Logf("skipping test; ipv4 is not supported: %v", err) - case network == "tcp6" && !supportsIPv6: - t.Logf("skipping test; ipv6 is not supported: %v", err) - default: - t.Error(err) - } + t.Error(err) continue } - switch { case network == "tcp" && addr.IP.To4() == nil: fallthrough case network == "tcp4" && addr.IP.To4() == nil: - t.Errorf("got %v; want an ipv4 address on %s", addr, network) + t.Errorf("got %v; want an IPv4 address on %s", addr, network) case network == "tcp6" && (addr.IP.To16() == nil || addr.IP.To4() != nil): - t.Errorf("got %v; want an ipv6 address on %s", addr, network) + t.Errorf("got %v; want an IPv6 address on %s", addr, network) } } } @@ -73,8 +63,8 @@ func TestDialGoogle(t *testing.T) { if testing.Short() || !*testExternal { t.Skip("avoid external network") } - if !supportsIPv4 && !supportsIPv6 { - t.Skip("ipv4 and ipv6 are not supported") + if !supportsIPv4 || !supportsIPv6 || !*testIPv4 || !*testIPv6 { + t.Skip("both IPv4 and IPv6 are required") } var err error @@ -84,25 +74,6 @@ func TestDialGoogle(t *testing.T) { } for _, tt := range dialGoogleTests { for _, network := range tt.networks { - switch { - case network == "tcp4" && !supportsIPv4: - t.Log("skipping test; ipv4 is not supported") - continue - case network == "tcp4" && !*testIPv4: - fallthrough - case tt.unreachableNetwork == "tcp6" && !*testIPv4: - t.Log("disabled; use -ipv4 to enable") - continue - case network == "tcp6" && !supportsIPv6: - t.Log("skipping test; ipv6 is not supported") - continue - case network == "tcp6" && !*testIPv6: - fallthrough - case tt.unreachableNetwork == "tcp4" && !*testIPv6: - t.Log("disabled; use -ipv6 to enable") - continue - } - disableSocketConnect(tt.unreachableNetwork) for _, addr := range tt.addrs { if err := fetchGoogle(tt.dial, network, addr); err != nil { diff --git a/src/net/lookup_test.go b/src/net/lookup_test.go index 1f36184d55..064bc0b9f1 100644 --- a/src/net/lookup_test.go +++ b/src/net/lookup_test.go @@ -23,17 +23,34 @@ func lookupLocalhost(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, } } +// The Lookup APIs use various sources such as local database, DNS or +// mDNS, and may use platform-dependent DNS stub resolver if possible. +// The APIs accept any of forms for a query; host name in various +// encodings, UTF-8 encoded net name, domain name, FQDN or absolute +// FQDN, but the result would be one of the forms and it depends on +// the circumstances. + var lookupGoogleSRVTests = []struct { service, proto, name string cname, target string }{ { "xmpp-server", "tcp", "google.com", - ".google.com", ".google.com", + "google.com", "google.com", }, { - "", "", "_xmpp-server._tcp.google.com", // non-standard back door - ".google.com", ".google.com", + "xmpp-server", "tcp", "google.com.", + "google.com", "google.com", + }, + + // non-standard back door + { + "", "", "_xmpp-server._tcp.google.com", + "google.com", "google.com", + }, + { + "", "", "_xmpp-server._tcp.google.com.", + "google.com", "google.com", }, } @@ -41,6 +58,9 @@ func TestLookupGoogleSRV(t *testing.T) { if testing.Short() || !*testExternal { t.Skip("avoid external network") } + if !supportsIPv4 || !*testIPv4 { + t.Skip("IPv4 is required") + } for _, tt := range lookupGoogleSRVTests { cname, srvs, err := LookupSRV(tt.service, tt.proto, tt.name) @@ -50,88 +70,126 @@ func TestLookupGoogleSRV(t *testing.T) { if len(srvs) == 0 { t.Error("got no record") } - if !strings.Contains(cname, tt.cname) { - t.Errorf("got %q; want %q", cname, tt.cname) + if !strings.HasSuffix(cname, tt.cname) && !strings.HasSuffix(cname, tt.cname+".") { + t.Errorf("got %s; want %s", cname, tt.cname) } for _, srv := range srvs { - if !strings.Contains(srv.Target, tt.target) { - t.Errorf("got %v; want a record containing %q", srv, tt.target) + if !strings.HasSuffix(srv.Target, tt.target) && !strings.HasSuffix(srv.Target, tt.target+".") { + t.Errorf("got %v; want a record containing %s", srv, tt.target) } } } } +var lookupGmailMXTests = []struct { + name, host string +}{ + {"gmail.com", "google.com"}, + {"gmail.com.", "google.com"}, +} + func TestLookupGmailMX(t *testing.T) { if testing.Short() || !*testExternal { t.Skip("avoid external network") } + if !supportsIPv4 || !*testIPv4 { + t.Skip("IPv4 is required") + } - mxs, err := LookupMX("gmail.com") - if err != nil { - t.Fatal(err) - } - if len(mxs) == 0 { - t.Error("got no record") - } - for _, mx := range mxs { - if !strings.Contains(mx.Host, ".google.com") { - t.Errorf("got %v; want a record containing .google.com.", mx) + for _, tt := range lookupGmailMXTests { + mxs, err := LookupMX(tt.name) + if err != nil { + t.Fatal(err) + } + if len(mxs) == 0 { + t.Error("got no record") + } + for _, mx := range mxs { + if !strings.HasSuffix(mx.Host, tt.host) && !strings.HasSuffix(mx.Host, tt.host+".") { + t.Errorf("got %v; want a record containing %s", mx, tt.host) + } } } } +var lookupGmailNSTests = []struct { + name, host string +}{ + {"gmail.com", "google.com"}, + {"gmail.com.", "google.com"}, +} + func TestLookupGmailNS(t *testing.T) { if testing.Short() || !*testExternal { t.Skip("avoid external network") } + if !supportsIPv4 || !*testIPv4 { + t.Skip("IPv4 is required") + } - nss, err := LookupNS("gmail.com") - if err != nil { - t.Fatal(err) - } - if len(nss) == 0 { - t.Error("got no record") - } - for _, ns := range nss { - if !strings.Contains(ns.Host, ".google.com") { - t.Errorf("got %v; want a record containing .google.com.", ns) + for _, tt := range lookupGmailNSTests { + nss, err := LookupNS(tt.name) + if err != nil { + t.Fatal(err) + } + if len(nss) == 0 { + t.Error("got no record") + } + for _, ns := range nss { + if !strings.HasSuffix(ns.Host, tt.host) && !strings.HasSuffix(ns.Host, tt.host+".") { + t.Errorf("got %v; want a record containing %s", ns, tt.host) + } } } } +var lookupGmailTXTTests = []struct { + name, txt, host string +}{ + {"gmail.com", "spf", "google.com"}, + {"gmail.com.", "spf", "google.com"}, +} + func TestLookupGmailTXT(t *testing.T) { if testing.Short() || !*testExternal { t.Skip("avoid external network") } + if !supportsIPv4 || !*testIPv4 { + t.Skip("IPv4 is required") + } - txts, err := LookupTXT("gmail.com") - if err != nil { - t.Fatal(err) - } - if len(txts) == 0 { - t.Error("got no record") - } - for _, txt := range txts { - if !strings.Contains(txt, "spf") { - t.Errorf("got %q; want a spf record", txt) + for _, tt := range lookupGmailTXTTests { + txts, err := LookupTXT(tt.name) + if err != nil { + t.Fatal(err) + } + if len(txts) == 0 { + t.Error("got no record") + } + for _, txt := range txts { + if !strings.Contains(txt, tt.txt) || (!strings.HasSuffix(txt, tt.host) && !strings.HasSuffix(txt, tt.host+".")) { + t.Errorf("got %s; want a record containing %s, %s", txt, tt.txt, tt.host) + } } } } var lookupGooglePublicDNSAddrs = []struct { - addr string - name string + addr, name string }{ - {"8.8.8.8", ".google.com."}, - {"8.8.4.4", ".google.com."}, - {"2001:4860:4860::8888", ".google.com."}, - {"2001:4860:4860::8844", ".google.com."}, + {"8.8.8.8", ".google.com"}, + {"8.8.4.4", ".google.com"}, + {"2001:4860:4860::8888", ".google.com"}, + {"2001:4860:4860::8844", ".google.com"}, } func TestLookupGooglePublicDNSAddr(t *testing.T) { if testing.Short() || !*testExternal { t.Skip("avoid external network") } + if !supportsIPv4 || !supportsIPv6 || !*testIPv4 || !*testIPv6 { + t.Skip("both IPv4 and IPv6 are required") + } for _, tt := range lookupGooglePublicDNSAddrs { names, err := LookupAddr(tt.addr) @@ -142,61 +200,97 @@ func TestLookupGooglePublicDNSAddr(t *testing.T) { t.Error("got no record") } for _, name := range names { - if !strings.HasSuffix(name, tt.name) { - t.Errorf("got %q; want a record containing %q", name, tt.name) + if !strings.HasSuffix(name, tt.name) && !strings.HasSuffix(name, tt.name+".") { + t.Errorf("got %s; want a record containing %s", name, tt.name) } } } } +var lookupIANACNAMETests = []struct { + name, cname string +}{ + {"www.iana.org", "icann.org"}, + {"www.iana.org.", "icann.org"}, +} + func TestLookupIANACNAME(t *testing.T) { if testing.Short() || !*testExternal { t.Skip("avoid external network") } + if !supportsIPv4 || !*testIPv4 { + t.Skip("IPv4 is required") + } - cname, err := LookupCNAME("www.iana.org") - if err != nil { - t.Fatal(err) - } - if !strings.HasSuffix(cname, ".icann.org.") { - t.Errorf("got %q; want a record containing .icann.org.", cname) + for _, tt := range lookupIANACNAMETests { + cname, err := LookupCNAME(tt.name) + if err != nil { + t.Fatal(err) + } + if !strings.HasSuffix(cname, tt.cname) && !strings.HasSuffix(cname, tt.cname+".") { + t.Errorf("got %s; want a record containing %s", cname, tt.cname) + } } } +var lookupGoogleHostTests = []struct { + name string +}{ + {"google.com"}, + {"google.com."}, +} + func TestLookupGoogleHost(t *testing.T) { if testing.Short() || !*testExternal { t.Skip("avoid external network") } + if !supportsIPv4 || !*testIPv4 { + t.Skip("IPv4 is required") + } - addrs, err := LookupHost("google.com") - if err != nil { - t.Fatal(err) - } - if len(addrs) == 0 { - t.Error("got no record") - } - for _, addr := range addrs { - if ParseIP(addr) == nil { - t.Errorf("got %q; want a literal ip address", addr) + for _, tt := range lookupGoogleHostTests { + addrs, err := LookupHost(tt.name) + if err != nil { + t.Fatal(err) + } + if len(addrs) == 0 { + t.Error("got no record") + } + for _, addr := range addrs { + if ParseIP(addr) == nil { + t.Errorf("got %q; want a literal IP address", addr) + } } } } +var lookupGoogleIPTests = []struct { + name string +}{ + {"google.com"}, + {"google.com."}, +} + func TestLookupGoogleIP(t *testing.T) { if testing.Short() || !*testExternal { t.Skip("avoid external network") } + if !supportsIPv4 || !*testIPv4 { + t.Skip("IPv4 is required") + } - ips, err := LookupIP("google.com") - if err != nil { - t.Fatal(err) - } - if len(ips) == 0 { - t.Error("got no record") - } - for _, ip := range ips { - if ip.To4() == nil && ip.To16() == nil { - t.Errorf("got %v; want an ip address", ip) + for _, tt := range lookupGoogleIPTests { + ips, err := LookupIP(tt.name) + if err != nil { + t.Fatal(err) + } + if len(ips) == 0 { + t.Error("got no record") + } + for _, ip := range ips { + if ip.To4() == nil && ip.To16() == nil { + t.Errorf("got %v; want an IP address", ip) + } } } } diff --git a/src/net/main_test.go b/src/net/main_test.go index 5e2f3da0e6..ceec08911e 100644 --- a/src/net/main_test.go +++ b/src/net/main_test.go @@ -30,10 +30,16 @@ var ( // If external IPv4 connectivity exists, we can try dialing // non-node/interface local scope IPv4 addresses. + // On Windows, Lookup APIs may not return IPv4-related + // resource records when a node has no external IPv4 + // connectivity. testIPv4 = flag.Bool("ipv4", true, "assume external IPv4 connectivity exists") // If external IPv6 connectivity exists, we can try dialing // non-node/interface local scope IPv6 addresses. + // On Windows, Lookup APIs may not return IPv6-related + // resource records when a node has no external IPv6 + // connectivity. testIPv6 = flag.Bool("ipv6", false, "assume external IPv6 connectivity exists") ) From ae3e3610d5ea9814fcc8bff5c4cea51795465565 Mon Sep 17 00:00:00 2001 From: Michael Hudson-Doyle Date: Mon, 18 May 2015 13:03:22 +1200 Subject: [PATCH 163/232] cmd/go: change Package.Shlib to be the absolute path of the shared library Makes little difference internally but makes go list output more useful. Change-Id: I1fa1f839107de08818427382b2aef8dc4d765b36 Reviewed-on: https://go-review.googlesource.com/10192 Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor