From 189931296f6b56090d9d7f49b7936b817189d87d Mon Sep 17 00:00:00 2001 From: Michael Munday Date: Tue, 10 Nov 2020 02:31:28 -0800 Subject: cmd/internal/obj/s390x: fix SYNC instruction encoding SYNC is supposed to correspond to 'fast-BCR-serialization' which is encoded as 'bcr 14,0'. In CL 197178 I accidentally modified the encoding to 'bcr 7,0' which is a no-op. This CL reverses that change. Fixes #42479. Change-Id: I9918d93d720f5e12acc3014cde20d2d32cc87ee5 Reviewed-on: https://go-review.googlesource.com/c/go/+/268797 Run-TryBot: Michael Munday Trust: Michael Munday TryBot-Result: Go Bot Reviewed-by: Cherry Zhang --- src/cmd/internal/obj/s390x/asmz.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/cmd/internal') diff --git a/src/cmd/internal/obj/s390x/asmz.go b/src/cmd/internal/obj/s390x/asmz.go index f0f9d5cefc..06921085c9 100644 --- a/src/cmd/internal/obj/s390x/asmz.go +++ b/src/cmd/internal/obj/s390x/asmz.go @@ -3700,7 +3700,7 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) { } case 80: // sync - zRR(op_BCR, uint32(NotEqual), 0, asm) + zRR(op_BCR, 14, 0, asm) // fast-BCR-serialization case 81: // float to fixed and fixed to float moves (no conversion) switch p.As { -- cgit v1.3-5-g9baa From 9ef65ff137c17bb7975859017abae4e27600c684 Mon Sep 17 00:00:00 2001 From: Alessandro Arzilli Date: Tue, 10 Nov 2020 17:02:27 +0100 Subject: cmd/compile: do not emit an extra debug_line entry for the end of seq addr Uses DW_LNS_advance_pc directly, instead of calling putpclcdelta because the latter will create a new debug_line entry for the end of sequence address. Fixes #42484 Change-Id: Ib6355605cac101b9bf37a3b4961ab0cee678a839 Reviewed-on: https://go-review.googlesource.com/c/go/+/268937 Trust: Than McIntosh Run-TryBot: Than McIntosh TryBot-Result: Go Bot Reviewed-by: Than McIntosh Reviewed-by: Cherry Zhang --- src/cmd/internal/obj/dwarf.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/cmd/internal') diff --git a/src/cmd/internal/obj/dwarf.go b/src/cmd/internal/obj/dwarf.go index 328fb03b24..87c62e2981 100644 --- a/src/cmd/internal/obj/dwarf.go +++ b/src/cmd/internal/obj/dwarf.go @@ -104,7 +104,8 @@ func (ctxt *Link) generateDebugLinesSymbol(s, lines *LSym) { // GDB will assign a line number of zero the last row in the line // table, which we don't want. lastlen := uint64(s.Size - (lastpc - s.Func().Text.Pc)) - putpclcdelta(ctxt, dctxt, lines, lastlen, 0) + dctxt.AddUint8(lines, dwarf.DW_LNS_advance_pc) + dwarf.Uleb128put(dctxt, lines, int64(lastlen)) dctxt.AddUint8(lines, 0) // start extended opcode dwarf.Uleb128put(dctxt, lines, 1) dctxt.AddUint8(lines, dwarf.DW_LNE_end_sequence) -- cgit v1.3-5-g9baa From 05082c90d5b35935ccc27acb070e00702df91a3a Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Mon, 17 Aug 2020 14:17:07 -0400 Subject: cmd/compile: clean up buggy DWARF inlined info PC ranges Repair the code that generates PC ranges for DWARF inlined routine instances to insure that if II Y is a child of II X within the inline tree, X's ranges include the ranges from Y. This is similar to what we're already doing for DWARF scopes. Updates #33188. Change-Id: I9bb552777fcd1ae93dc01872707667ad092b1dd9 Reviewed-on: https://go-review.googlesource.com/c/go/+/248724 Run-TryBot: Than McIntosh TryBot-Result: Go Bot Reviewed-by: Cherry Zhang Reviewed-by: David Chase Trust: Than McIntosh --- src/cmd/compile/internal/gc/dwinl.go | 92 ++++++++++++++++++++++++++++++++++++ src/cmd/internal/dwarf/dwarf.go | 31 +++++++----- 2 files changed, 110 insertions(+), 13 deletions(-) (limited to 'src/cmd/internal') diff --git a/src/cmd/compile/internal/gc/dwinl.go b/src/cmd/compile/internal/gc/dwinl.go index 5120fa1166..bb5ae61cbb 100644 --- a/src/cmd/compile/internal/gc/dwinl.go +++ b/src/cmd/compile/internal/gc/dwinl.go @@ -8,6 +8,7 @@ import ( "cmd/internal/dwarf" "cmd/internal/obj" "cmd/internal/src" + "fmt" "strings" ) @@ -170,12 +171,32 @@ func assembleInlines(fnsym *obj.LSym, dwVars []*dwarf.Var) dwarf.InlCalls { addRange(inlcalls.Calls, start, fnsym.Size, curii, imap) } + // Issue 33188: if II foo is a child of II bar, then ensure that + // bar's ranges include the ranges of foo (the loop above will produce + // disjoint ranges). + for k, c := range inlcalls.Calls { + if c.Root { + unifyCallRanges(inlcalls, k) + } + } + // Debugging if Debug_gendwarfinl != 0 { dumpInlCalls(inlcalls) dumpInlVars(dwVars) } + // Perform a consistency check on inlined routine PC ranges + // produced by unifyCallRanges above. In particular, complain in + // cases where you have A -> B -> C (e.g. C is inlined into B, and + // B is inlined into A) and the ranges for B are not enclosed + // within the ranges for A, or C within B. + for k, c := range inlcalls.Calls { + if c.Root { + checkInlCall(fnsym.Name, inlcalls, fnsym.Size, k, -1) + } + } + return inlcalls } @@ -355,3 +376,74 @@ func dumpInlVars(dwvars []*dwarf.Var) { Ctxt.Logf("V%d: %s CI:%d II:%d IA:%d %s\n", i, dwv.Name, dwv.ChildIndex, dwv.InlIndex-1, ia, typ) } } + +func rangesContains(par []dwarf.Range, rng dwarf.Range) (bool, string) { + for _, r := range par { + if rng.Start >= r.Start && rng.End <= r.End { + return true, "" + } + } + msg := fmt.Sprintf("range [%d,%d) not contained in {", rng.Start, rng.End) + for _, r := range par { + msg += fmt.Sprintf(" [%d,%d)", r.Start, r.End) + } + msg += " }" + return false, msg +} + +func rangesContainsAll(parent, child []dwarf.Range) (bool, string) { + for _, r := range child { + c, m := rangesContains(parent, r) + if !c { + return false, m + } + } + return true, "" +} + +// checkInlCall verifies that the PC ranges for inline info 'idx' are +// enclosed/contained within the ranges of its parent inline (or if +// this is a root/toplevel inline, checks that the ranges fall within +// the extent of the top level function). A panic is issued if a +// malformed range is found. +func checkInlCall(funcName string, inlCalls dwarf.InlCalls, funcSize int64, idx, parentIdx int) { + + // Callee + ic := inlCalls.Calls[idx] + callee := Ctxt.InlTree.InlinedFunction(ic.InlIndex).Name + calleeRanges := ic.Ranges + + // Caller + caller := funcName + parentRanges := []dwarf.Range{dwarf.Range{Start: int64(0), End: funcSize}} + if parentIdx != -1 { + pic := inlCalls.Calls[parentIdx] + caller = Ctxt.InlTree.InlinedFunction(pic.InlIndex).Name + parentRanges = pic.Ranges + } + + // Callee ranges contained in caller ranges? + c, m := rangesContainsAll(parentRanges, calleeRanges) + if !c { + Fatalf("** malformed inlined routine range in %s: caller %s callee %s II=%d %s\n", funcName, caller, callee, idx, m) + } + + // Now visit kids + for _, k := range ic.Children { + checkInlCall(funcName, inlCalls, funcSize, k, idx) + } +} + +// unifyCallRanges ensures that the ranges for a given inline +// transitively include all of the ranges for its child inlines. +func unifyCallRanges(inlcalls dwarf.InlCalls, idx int) { + ic := &inlcalls.Calls[idx] + for _, childIdx := range ic.Children { + // First make sure child ranges are unified. + unifyCallRanges(inlcalls, childIdx) + + // Then merge child ranges into ranges for this inline. + cic := inlcalls.Calls[childIdx] + ic.Ranges = dwarf.MergeRanges(ic.Ranges, cic.Ranges) + } +} diff --git a/src/cmd/internal/dwarf/dwarf.go b/src/cmd/internal/dwarf/dwarf.go index b2fd5262bb..e1a70ef853 100644 --- a/src/cmd/internal/dwarf/dwarf.go +++ b/src/cmd/internal/dwarf/dwarf.go @@ -101,26 +101,26 @@ func EnableLogging(doit bool) { logDwarf = doit } -// UnifyRanges merges the list of ranges of c into the list of ranges of s -func (s *Scope) UnifyRanges(c *Scope) { - out := make([]Range, 0, len(s.Ranges)+len(c.Ranges)) - +// MergeRanges creates a new range list by merging the ranges from +// its two arguments, then returns the new list. +func MergeRanges(in1, in2 []Range) []Range { + out := make([]Range, 0, len(in1)+len(in2)) i, j := 0, 0 for { var cur Range - if i < len(s.Ranges) && j < len(c.Ranges) { - if s.Ranges[i].Start < c.Ranges[j].Start { - cur = s.Ranges[i] + if i < len(in2) && j < len(in1) { + if in2[i].Start < in1[j].Start { + cur = in2[i] i++ } else { - cur = c.Ranges[j] + cur = in1[j] j++ } - } else if i < len(s.Ranges) { - cur = s.Ranges[i] + } else if i < len(in2) { + cur = in2[i] i++ - } else if j < len(c.Ranges) { - cur = c.Ranges[j] + } else if j < len(in1) { + cur = in1[j] j++ } else { break @@ -133,7 +133,12 @@ func (s *Scope) UnifyRanges(c *Scope) { } } - s.Ranges = out + return out +} + +// UnifyRanges merges the ranges from 'c' into the list of ranges for 's'. +func (s *Scope) UnifyRanges(c *Scope) { + s.Ranges = MergeRanges(s.Ranges, c.Ranges) } // AppendRange adds r to s, if r is non-empty. -- cgit v1.3-5-g9baa From cb674b5c13d331fd5cef5bae7a2a67e5e0d41f7d Mon Sep 17 00:00:00 2001 From: "Paul E. Murphy" Date: Fri, 13 Nov 2020 14:44:25 -0600 Subject: cmd/compile,cmd/asm: fix function pointer call perf regression on ppc64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit by inserting hint when using bclrl. Using this instruction as subroutine call is not the expected default behavior, and as a result confuses the branch predictor. The default expected behavior is a conditional return from a subroutine. We can change this assumption by encoding a hint this is not a subroutine return. The regex benchmarks are a pretty good example of how much this hint can help generic ppc64le code on a power9 machine: name old time/op new time/op delta Find 606ns ± 0% 447ns ± 0% -26.27% FindAllNoMatches 309ns ± 0% 205ns ± 0% -33.72% FindString 609ns ± 0% 451ns ± 0% -26.04% FindSubmatch 734ns ± 0% 594ns ± 0% -19.07% FindStringSubmatch 706ns ± 0% 574ns ± 0% -18.83% Literal 177ns ± 0% 136ns ± 0% -22.89% NotLiteral 4.69µs ± 0% 2.34µs ± 0% -50.14% MatchClass 6.05µs ± 0% 3.26µs ± 0% -46.08% MatchClass_InRange 5.93µs ± 0% 3.15µs ± 0% -46.86% ReplaceAll 3.15µs ± 0% 2.18µs ± 0% -30.77% AnchoredLiteralShortNonMatch 156ns ± 0% 109ns ± 0% -30.61% AnchoredLiteralLongNonMatch 192ns ± 0% 136ns ± 0% -29.34% AnchoredShortMatch 268ns ± 0% 209ns ± 0% -22.00% AnchoredLongMatch 472ns ± 0% 357ns ± 0% -24.30% OnePassShortA 1.16µs ± 0% 0.87µs ± 0% -25.03% NotOnePassShortA 1.34µs ± 0% 1.20µs ± 0% -10.63% OnePassShortB 940ns ± 0% 655ns ± 0% -30.29% NotOnePassShortB 873ns ± 0% 703ns ± 0% -19.52% OnePassLongPrefix 258ns ± 0% 155ns ± 0% -40.13% OnePassLongNotPrefix 943ns ± 0% 529ns ± 0% -43.89% MatchParallelShared 591ns ± 0% 436ns ± 0% -26.31% MatchParallelCopied 596ns ± 0% 435ns ± 0% -27.10% QuoteMetaAll 186ns ± 0% 186ns ± 0% -0.16% QuoteMetaNone 55.9ns ± 0% 55.9ns ± 0% +0.02% Compile/Onepass 9.64µs ± 0% 9.26µs ± 0% -3.97% Compile/Medium 21.7µs ± 0% 20.6µs ± 0% -4.90% Compile/Hard 174µs ± 0% 174µs ± 0% +0.07% Match/Easy0/16 7.35ns ± 0% 7.34ns ± 0% -0.11% Match/Easy0/32 116ns ± 0% 97ns ± 0% -16.27% Match/Easy0/1K 592ns ± 0% 562ns ± 0% -5.04% Match/Easy0/32K 12.6µs ± 0% 12.5µs ± 0% -0.64% Match/Easy0/1M 556µs ± 0% 556µs ± 0% -0.00% Match/Easy0/32M 17.7ms ± 0% 17.7ms ± 0% +0.05% Match/Easy0i/16 7.34ns ± 0% 7.35ns ± 0% +0.10% Match/Easy0i/32 2.82µs ± 0% 1.64µs ± 0% -41.71% Match/Easy0i/1K 83.2µs ± 0% 48.2µs ± 0% -42.06% Match/Easy0i/32K 2.13ms ± 0% 1.80ms ± 0% -15.34% Match/Easy0i/1M 68.1ms ± 0% 57.6ms ± 0% -15.31% Match/Easy0i/32M 2.18s ± 0% 1.80s ± 0% -17.52% Match/Easy1/16 7.36ns ± 0% 7.34ns ± 0% -0.24% Match/Easy1/32 118ns ± 0% 96ns ± 0% -18.72% Match/Easy1/1K 2.46µs ± 0% 1.58µs ± 0% -35.65% Match/Easy1/32K 80.2µs ± 0% 54.6µs ± 0% -31.92% Match/Easy1/1M 2.75ms ± 0% 1.88ms ± 0% -31.66% Match/Easy1/32M 87.5ms ± 0% 59.8ms ± 0% -31.62% Match/Medium/16 7.34ns ± 0% 7.34ns ± 0% +0.01% Match/Medium/32 2.60µs ± 0% 1.50µs ± 0% -42.61% Match/Medium/1K 78.1µs ± 0% 43.7µs ± 0% -44.06% Match/Medium/32K 2.08ms ± 0% 1.52ms ± 0% -27.11% Match/Medium/1M 66.5ms ± 0% 48.6ms ± 0% -26.96% Match/Medium/32M 2.14s ± 0% 1.60s ± 0% -25.18% Match/Hard/16 7.35ns ± 0% 7.35ns ± 0% +0.03% Match/Hard/32 3.58µs ± 0% 2.44µs ± 0% -31.82% Match/Hard/1K 108µs ± 0% 75µs ± 0% -31.04% Match/Hard/32K 2.79ms ± 0% 2.25ms ± 0% -19.30% Match/Hard/1M 89.4ms ± 0% 72.2ms ± 0% -19.26% Match/Hard/32M 2.91s ± 0% 2.37s ± 0% -18.60% Match/Hard1/16 11.1µs ± 0% 8.3µs ± 0% -25.07% Match/Hard1/32 21.4µs ± 0% 16.1µs ± 0% -24.85% Match/Hard1/1K 658µs ± 0% 498µs ± 0% -24.27% Match/Hard1/32K 12.2ms ± 0% 11.7ms ± 0% -4.60% Match/Hard1/1M 391ms ± 0% 374ms ± 0% -4.40% Match/Hard1/32M 12.6s ± 0% 12.0s ± 0% -4.68% Match_onepass_regex/16 870ns ± 0% 611ns ± 0% -29.79% Match_onepass_regex/32 1.58µs ± 0% 1.08µs ± 0% -31.48% Match_onepass_regex/1K 45.7µs ± 0% 30.3µs ± 0% -33.58% Match_onepass_regex/32K 1.45ms ± 0% 0.97ms ± 0% -33.20% Match_onepass_regex/1M 46.2ms ± 0% 30.9ms ± 0% -33.01% Match_onepass_regex/32M 1.46s ± 0% 0.99s ± 0% -32.02% name old alloc/op new alloc/op delta Find 0.00B 0.00B 0.00% FindAllNoMatches 0.00B 0.00B 0.00% FindString 0.00B 0.00B 0.00% FindSubmatch 48.0B ± 0% 48.0B ± 0% 0.00% FindStringSubmatch 32.0B ± 0% 32.0B ± 0% 0.00% Compile/Onepass 4.02kB ± 0% 4.02kB ± 0% 0.00% Compile/Medium 9.39kB ± 0% 9.39kB ± 0% 0.00% Compile/Hard 84.7kB ± 0% 84.7kB ± 0% 0.00% Match_onepass_regex/16 0.00B 0.00B 0.00% Match_onepass_regex/32 0.00B 0.00B 0.00% Match_onepass_regex/1K 0.00B 0.00B 0.00% Match_onepass_regex/32K 0.00B 0.00B 0.00% Match_onepass_regex/1M 5.00B ± 0% 3.00B ± 0% -40.00% Match_onepass_regex/32M 136B ± 0% 68B ± 0% -50.00% name old allocs/op new allocs/op delta Find 0.00 0.00 0.00% FindAllNoMatches 0.00 0.00 0.00% FindString 0.00 0.00 0.00% FindSubmatch 1.00 ± 0% 1.00 ± 0% 0.00% FindStringSubmatch 1.00 ± 0% 1.00 ± 0% 0.00% Compile/Onepass 52.0 ± 0% 52.0 ± 0% 0.00% Compile/Medium 112 ± 0% 112 ± 0% 0.00% Compile/Hard 424 ± 0% 424 ± 0% 0.00% Match_onepass_regex/16 0.00 0.00 0.00% Match_onepass_regex/32 0.00 0.00 0.00% Match_onepass_regex/1K 0.00 0.00 0.00% Match_onepass_regex/32K 0.00 0.00 0.00% Match_onepass_regex/1M 0.00 0.00 0.00% Match_onepass_regex/32M 2.00 ± 0% 1.00 ± 0% -50.00% name old speed new speed delta QuoteMetaAll 75.2MB/s ± 0% 75.3MB/s ± 0% +0.15% QuoteMetaNone 465MB/s ± 0% 465MB/s ± 0% -0.02% Match/Easy0/16 2.18GB/s ± 0% 2.18GB/s ± 0% +0.10% Match/Easy0/32 276MB/s ± 0% 330MB/s ± 0% +19.46% Match/Easy0/1K 1.73GB/s ± 0% 1.82GB/s ± 0% +5.29% Match/Easy0/32K 2.60GB/s ± 0% 2.62GB/s ± 0% +0.64% Match/Easy0/1M 1.89GB/s ± 0% 1.89GB/s ± 0% +0.00% Match/Easy0/32M 1.89GB/s ± 0% 1.89GB/s ± 0% -0.05% Match/Easy0i/16 2.18GB/s ± 0% 2.18GB/s ± 0% -0.10% Match/Easy0i/32 11.4MB/s ± 0% 19.5MB/s ± 0% +71.48% Match/Easy0i/1K 12.3MB/s ± 0% 21.2MB/s ± 0% +72.62% Match/Easy0i/32K 15.4MB/s ± 0% 18.2MB/s ± 0% +18.12% Match/Easy0i/1M 15.4MB/s ± 0% 18.2MB/s ± 0% +18.12% Match/Easy0i/32M 15.4MB/s ± 0% 18.6MB/s ± 0% +21.21% Match/Easy1/16 2.17GB/s ± 0% 2.18GB/s ± 0% +0.24% Match/Easy1/32 271MB/s ± 0% 333MB/s ± 0% +23.07% Match/Easy1/1K 417MB/s ± 0% 648MB/s ± 0% +55.38% Match/Easy1/32K 409MB/s ± 0% 600MB/s ± 0% +46.88% Match/Easy1/1M 381MB/s ± 0% 558MB/s ± 0% +46.33% Match/Easy1/32M 383MB/s ± 0% 561MB/s ± 0% +46.25% Match/Medium/16 2.18GB/s ± 0% 2.18GB/s ± 0% -0.01% Match/Medium/32 12.3MB/s ± 0% 21.4MB/s ± 0% +74.13% Match/Medium/1K 13.1MB/s ± 0% 23.4MB/s ± 0% +78.73% Match/Medium/32K 15.7MB/s ± 0% 21.6MB/s ± 0% +37.23% Match/Medium/1M 15.8MB/s ± 0% 21.6MB/s ± 0% +36.93% Match/Medium/32M 15.7MB/s ± 0% 21.0MB/s ± 0% +33.67% Match/Hard/16 2.18GB/s ± 0% 2.18GB/s ± 0% -0.03% Match/Hard/32 8.93MB/s ± 0% 13.10MB/s ± 0% +46.70% Match/Hard/1K 9.48MB/s ± 0% 13.74MB/s ± 0% +44.94% Match/Hard/32K 11.7MB/s ± 0% 14.5MB/s ± 0% +23.87% Match/Hard/1M 11.7MB/s ± 0% 14.5MB/s ± 0% +23.87% Match/Hard/32M 11.6MB/s ± 0% 14.2MB/s ± 0% +22.86% Match/Hard1/16 1.44MB/s ± 0% 1.93MB/s ± 0% +34.03% Match/Hard1/32 1.49MB/s ± 0% 1.99MB/s ± 0% +33.56% Match/Hard1/1K 1.56MB/s ± 0% 2.05MB/s ± 0% +31.41% Match/Hard1/32K 2.68MB/s ± 0% 2.80MB/s ± 0% +4.48% Match/Hard1/1M 2.68MB/s ± 0% 2.80MB/s ± 0% +4.48% Match/Hard1/32M 2.66MB/s ± 0% 2.79MB/s ± 0% +4.89% Match_onepass_regex/16 18.4MB/s ± 0% 26.2MB/s ± 0% +42.41% Match_onepass_regex/32 20.2MB/s ± 0% 29.5MB/s ± 0% +45.92% Match_onepass_regex/1K 22.4MB/s ± 0% 33.8MB/s ± 0% +50.54% Match_onepass_regex/32K 22.6MB/s ± 0% 33.9MB/s ± 0% +49.67% Match_onepass_regex/1M 22.7MB/s ± 0% 33.9MB/s ± 0% +49.27% Match_onepass_regex/32M 23.0MB/s ± 0% 33.9MB/s ± 0% +47.14% Fixes #42709 Change-Id: Ice07fec2de4c5b1302febf8c2978ae8c1e4fd3e5 Reviewed-on: https://go-review.googlesource.com/c/go/+/271337 Reviewed-by: Cherry Zhang Trust: Lynn Boger Trust: Carlos Eduardo Seo --- src/cmd/compile/internal/ppc64/ssa.go | 3 +++ src/cmd/internal/obj/ppc64/asm9.go | 11 +++++++++++ 2 files changed, 14 insertions(+) (limited to 'src/cmd/internal') diff --git a/src/cmd/compile/internal/ppc64/ssa.go b/src/cmd/compile/internal/ppc64/ssa.go index 3888aa6527..3e20c44a4c 100644 --- a/src/cmd/compile/internal/ppc64/ssa.go +++ b/src/cmd/compile/internal/ppc64/ssa.go @@ -1781,6 +1781,9 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { pp := s.Call(v) pp.To.Reg = ppc64.REG_LR + // Insert a hint this is not a subroutine return. + pp.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: 1}) + if gc.Ctxt.Flag_shared { // When compiling Go into PIC, the function we just // called via pointer might have been implemented in diff --git a/src/cmd/internal/obj/ppc64/asm9.go b/src/cmd/internal/obj/ppc64/asm9.go index 775d27d8e8..41e263b2c0 100644 --- a/src/cmd/internal/obj/ppc64/asm9.go +++ b/src/cmd/internal/obj/ppc64/asm9.go @@ -334,6 +334,7 @@ var optab = []Optab{ {ABC, C_SCON, C_REG, C_NONE, C_SBRA, 16, 4, 0}, {ABC, C_SCON, C_REG, C_NONE, C_LBRA, 17, 4, 0}, {ABR, C_NONE, C_NONE, C_NONE, C_LR, 18, 4, 0}, + {ABR, C_NONE, C_NONE, C_SCON, C_LR, 18, 4, 0}, {ABR, C_NONE, C_NONE, C_NONE, C_CTR, 18, 4, 0}, {ABR, C_REG, C_NONE, C_NONE, C_CTR, 18, 4, 0}, {ABR, C_NONE, C_NONE, C_NONE, C_ZOREG, 15, 8, 0}, @@ -2844,6 +2845,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { case 18: /* br/bl (lr/ctr); bc/bcl bo,bi,(lr/ctr) */ var v int32 + var bh uint32 = 0 if p.As == ABC || p.As == ABCL { v = c.regoff(&p.From) & 31 } else { @@ -2865,6 +2867,15 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { v = 0 } + // Insert optional branch hint for bclr[l]/bcctr[l] + if p.From3Type() != obj.TYPE_NONE { + bh = uint32(p.GetFrom3().Offset) + if bh == 2 || bh > 3 { + log.Fatalf("BH must be 0,1,3 for %v", p) + } + o1 |= bh << 11 + } + if p.As == ABL || p.As == ABCL { o1 |= 1 } -- cgit v1.3-5-g9baa From c47eac7db00e03776c3975025184e1938fbced75 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 20 Nov 2020 12:54:18 -0800 Subject: cmd/cgo, cmd/internal/pkgpath: support gofrontend mangler v3 The gofrontend mangling scheme used by gccgo and GoLLVM has changed again. Support the new version. This is a port of the relevant parts of https://golang.org/cl/271726. For #41862 Change-Id: I9c961c8e17ec960a83a23e1d49ea900962b63393 Reviewed-on: https://go-review.googlesource.com/c/go/+/272127 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor Reviewed-by: Than McIntosh TryBot-Result: Go Bot --- src/cmd/cgo/out.go | 23 ++++++----- src/cmd/internal/pkgpath/pkgpath.go | 68 ++++++++++++++++++++++++++++++-- src/cmd/internal/pkgpath/pkgpath_test.go | 22 ++++++++++- 3 files changed, 98 insertions(+), 15 deletions(-) (limited to 'src/cmd/internal') diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index bb963799f6..11c53facf8 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -186,7 +186,7 @@ func (p *Package) writeDefs() { panic(fmt.Errorf("invalid var kind %q", n.Kind)) } if *gccgo { - fmt.Fprintf(fc, `extern void *%s __asm__("%s.%s");`, n.Mangle, gccgoSymbolPrefix, n.Mangle) + fmt.Fprintf(fc, `extern void *%s __asm__("%s.%s");`, n.Mangle, gccgoSymbolPrefix, gccgoToSymbol(n.Mangle)) fmt.Fprintf(&gccgoInit, "\t%s = &%s;\n", n.Mangle, n.C) fmt.Fprintf(fc, "\n") } @@ -1148,7 +1148,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) { // will not be able to link against it from the C // code. goName := "Cgoexp_" + exp.ExpName - fmt.Fprintf(fgcc, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, goName) + fmt.Fprintf(fgcc, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, gccgoToSymbol(goName)) fmt.Fprint(fgcc, "\n") fmt.Fprint(fgcc, "\nCGO_NO_SANITIZE_THREAD\n") @@ -1182,7 +1182,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) { fmt.Fprint(fgcc, "}\n") // Dummy declaration for _cgo_main.c - fmt.Fprintf(fm, `char %s[1] __asm__("%s.%s");`, goName, gccgoSymbolPrefix, goName) + fmt.Fprintf(fm, `char %s[1] __asm__("%s.%s");`, goName, gccgoSymbolPrefix, gccgoToSymbol(goName)) fmt.Fprint(fm, "\n") // For gccgo we use a wrapper function in Go, in order @@ -1266,9 +1266,8 @@ func (p *Package) writeExportHeader(fgcch io.Writer) { fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog()) } -// gccgoPkgpathToSymbol converts a package path to a mangled packagepath -// symbol. -func gccgoPkgpathToSymbol(ppath string) string { +// gccgoToSymbol converts a name to a mangled symbol for gccgo. +func gccgoToSymbol(ppath string) string { if gccgoMangler == nil { var err error cmd := os.Getenv("GCCGO") @@ -1293,12 +1292,12 @@ func (p *Package) gccgoSymbolPrefix() string { } if *gccgopkgpath != "" { - return gccgoPkgpathToSymbol(*gccgopkgpath) + return gccgoToSymbol(*gccgopkgpath) } if *gccgoprefix == "" && p.PackageName == "main" { return "main" } - prefix := gccgoPkgpathToSymbol(*gccgoprefix) + prefix := gccgoToSymbol(*gccgoprefix) if prefix == "" { prefix = "go" } @@ -1687,8 +1686,12 @@ void _cgoPREFIX_Cfunc__Cmalloc(void *v) { ` func (p *Package) cPrologGccgo() string { - return strings.Replace(strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1), - "GCCGOSYMBOLPREF", p.gccgoSymbolPrefix(), -1) + r := strings.NewReplacer( + "PREFIX", cPrefix, + "GCCGOSYMBOLPREF", p.gccgoSymbolPrefix(), + "_cgoCheckPointer", gccgoToSymbol("_cgoCheckPointer"), + "_cgoCheckResult", gccgoToSymbol("_cgoCheckResult")) + return r.Replace(cPrologGccgo) } const cPrologGccgo = ` diff --git a/src/cmd/internal/pkgpath/pkgpath.go b/src/cmd/internal/pkgpath/pkgpath.go index 0b24468be6..40a040a81a 100644 --- a/src/cmd/internal/pkgpath/pkgpath.go +++ b/src/cmd/internal/pkgpath/pkgpath.go @@ -50,9 +50,12 @@ func ToSymbolFunc(cmd, tmpdir string) (func(string) string, error) { return nil, err } - // New mangling: expect go.l..u00e4ufer.Run - // Old mangling: expect go.l__ufer.Run - if bytes.Contains(buf, []byte("go.l..u00e4ufer.Run")) { + // Original mangling: go.l__ufer.Run + // Mangling v2: go.l..u00e4ufer.Run + // Mangling v3: go_0l_u00e4ufer.Run + if bytes.Contains(buf, []byte("go_0l_u00e4ufer.Run")) { + return toSymbolV3, nil + } else if bytes.Contains(buf, []byte("go.l..u00e4ufer.Run")) { return toSymbolV2, nil } else if bytes.Contains(buf, []byte("go.l__ufer.Run")) { return toSymbolV1, nil @@ -82,7 +85,7 @@ func toSymbolV1(ppath string) string { return strings.Map(clean, ppath) } -// toSymbolV2 converts a package path using the newer mangling scheme. +// toSymbolV2 converts a package path using the second mangling scheme. func toSymbolV2(ppath string) string { // This has to build at boostrap time, so it has to build // with Go 1.4, so we don't use strings.Builder. @@ -112,3 +115,60 @@ func toSymbolV2(ppath string) string { } return string(bsl) } + +// v3UnderscoreCodes maps from a character that supports an underscore +// encoding to the underscore encoding character. +var v3UnderscoreCodes = map[byte]byte{ + '_': '_', + '.': '0', + '/': '1', + '*': '2', + ',': '3', + '{': '4', + '}': '5', + '[': '6', + ']': '7', + '(': '8', + ')': '9', + '"': 'a', + ' ': 'b', + ';': 'c', +} + +// toSymbolV3 converts a package path using the third mangling scheme. +func toSymbolV3(ppath string) string { + // This has to build at boostrap time, so it has to build + // with Go 1.4, so we don't use strings.Builder. + bsl := make([]byte, 0, len(ppath)) + changed := false + for _, c := range ppath { + if ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') || ('0' <= c && c <= '9') { + bsl = append(bsl, byte(c)) + continue + } + + if c < 0x80 { + if u, ok := v3UnderscoreCodes[byte(c)]; ok { + bsl = append(bsl, '_', u) + changed = true + continue + } + } + + var enc string + switch { + case c < 0x80: + enc = fmt.Sprintf("_x%02x", c) + case c < 0x10000: + enc = fmt.Sprintf("_u%04x", c) + default: + enc = fmt.Sprintf("_U%08x", c) + } + bsl = append(bsl, enc...) + changed = true + } + if !changed { + return ppath + } + return string(bsl) +} diff --git a/src/cmd/internal/pkgpath/pkgpath_test.go b/src/cmd/internal/pkgpath/pkgpath_test.go index 7355f81bae..232e803a60 100644 --- a/src/cmd/internal/pkgpath/pkgpath_test.go +++ b/src/cmd/internal/pkgpath/pkgpath_test.go @@ -24,6 +24,9 @@ func init() { case "v2": os.Stdout.WriteString(`.string "go.l..u00e4ufer.Run"`) os.Exit(0) + case "v3": + os.Stdout.WriteString(`.string "go_0l_u00e4ufer.Run"`) + os.Exit(0) case "error": os.Stdout.WriteString(`unknown string`) os.Exit(0) @@ -45,6 +48,10 @@ func TestToSymbolFunc(t *testing.T) { env: "v2", mangled: "p..u00e4..u4e16..U0001f703", }, + { + env: "v3", + mangled: "p_u00e4_u4e16_U0001f703", + }, { env: "error", fail: true, @@ -75,32 +82,37 @@ func TestToSymbolFunc(t *testing.T) { } var symbolTests = []struct { - input, v1, v2 string + input, v1, v2, v3 string }{ { "", "", "", + "", }, { "bytes", "bytes", "bytes", + "bytes", }, { "net/http", "net_http", "net..z2fhttp", + "net_1http", }, { "golang.org/x/net/http", "golang_org_x_net_http", "golang.x2eorg..z2fx..z2fnet..z2fhttp", + "golang_0org_1x_1net_1http", }, { "pä世.🜃", "p____", "p..u00e4..u4e16.x2e..U0001f703", + "p_u00e4_u4e16_0_U0001f703", }, } @@ -119,3 +131,11 @@ func TestV2(t *testing.T) { } } } + +func TestV3(t *testing.T) { + for _, test := range symbolTests { + if got, want := toSymbolV3(test.input), test.v3; got != want { + t.Errorf("toSymbolV3(%q) = %q, want %q", test.input, got, want) + } + } +} -- cgit v1.3-5-g9baa From 1308f118974fab4bd08d04a6a982db6dde6f9e52 Mon Sep 17 00:00:00 2001 From: eric fang Date: Wed, 18 Nov 2020 04:00:57 +0000 Subject: cmd/link: add relocation type R_AARCH64_LDST16_ABS_LO12_NC for arm64 The linker already has R_AARCH64_LDST{8,32,64,128}_ABS_LO12_NC, some cgo tests require R_AARCH64_LDST16_ABS_LO12_NC, this CL adds this relocation type. Fixes #42660 Change-Id: I9a5120cd872f5095c61175cb602427c6ab3225cc Reviewed-on: https://go-review.googlesource.com/c/go/+/271017 Reviewed-by: eric fang Reviewed-by: Cherry Zhang Run-TryBot: eric fang TryBot-Result: Go Bot Trust: eric fang Trust: Benny Siegert --- src/cmd/internal/objabi/reloctype.go | 3 ++ src/cmd/internal/objabi/reloctype_string.go | 47 +++++++++++++++-------------- src/cmd/link/internal/arm64/asm.go | 16 ++++++++++ src/cmd/link/internal/loadelf/ldelf.go | 1 + 4 files changed, 44 insertions(+), 23 deletions(-) (limited to 'src/cmd/internal') diff --git a/src/cmd/internal/objabi/reloctype.go b/src/cmd/internal/objabi/reloctype.go index 938954e07a..649f690194 100644 --- a/src/cmd/internal/objabi/reloctype.go +++ b/src/cmd/internal/objabi/reloctype.go @@ -156,6 +156,9 @@ const ( // R_ARM64_LDST8 sets a LD/ST immediate value to bits [11:0] of a local address. R_ARM64_LDST8 + // R_ARM64_LDST16 sets a LD/ST immediate value to bits [11:1] of a local address. + R_ARM64_LDST16 + // R_ARM64_LDST32 sets a LD/ST immediate value to bits [11:2] of a local address. R_ARM64_LDST32 diff --git a/src/cmd/internal/objabi/reloctype_string.go b/src/cmd/internal/objabi/reloctype_string.go index 693d9631f5..658a44f8b8 100644 --- a/src/cmd/internal/objabi/reloctype_string.go +++ b/src/cmd/internal/objabi/reloctype_string.go @@ -46,32 +46,33 @@ func _() { _ = x[R_ARM64_GOT-36] _ = x[R_ARM64_PCREL-37] _ = x[R_ARM64_LDST8-38] - _ = x[R_ARM64_LDST32-39] - _ = x[R_ARM64_LDST64-40] - _ = x[R_ARM64_LDST128-41] - _ = x[R_POWER_TLS_LE-42] - _ = x[R_POWER_TLS_IE-43] - _ = x[R_POWER_TLS-44] - _ = x[R_ADDRPOWER_DS-45] - _ = x[R_ADDRPOWER_GOT-46] - _ = x[R_ADDRPOWER_PCREL-47] - _ = x[R_ADDRPOWER_TOCREL-48] - _ = x[R_ADDRPOWER_TOCREL_DS-49] - _ = x[R_RISCV_PCREL_ITYPE-50] - _ = x[R_RISCV_PCREL_STYPE-51] - _ = x[R_RISCV_TLS_IE_ITYPE-52] - _ = x[R_RISCV_TLS_IE_STYPE-53] - _ = x[R_PCRELDBL-54] - _ = x[R_ADDRMIPSU-55] - _ = x[R_ADDRMIPSTLS-56] - _ = x[R_ADDRCUOFF-57] - _ = x[R_WASMIMPORT-58] - _ = x[R_XCOFFREF-59] + _ = x[R_ARM64_LDST16-39] + _ = x[R_ARM64_LDST32-40] + _ = x[R_ARM64_LDST64-41] + _ = x[R_ARM64_LDST128-42] + _ = x[R_POWER_TLS_LE-43] + _ = x[R_POWER_TLS_IE-44] + _ = x[R_POWER_TLS-45] + _ = x[R_ADDRPOWER_DS-46] + _ = x[R_ADDRPOWER_GOT-47] + _ = x[R_ADDRPOWER_PCREL-48] + _ = x[R_ADDRPOWER_TOCREL-49] + _ = x[R_ADDRPOWER_TOCREL_DS-50] + _ = x[R_RISCV_PCREL_ITYPE-51] + _ = x[R_RISCV_PCREL_STYPE-52] + _ = x[R_RISCV_TLS_IE_ITYPE-53] + _ = x[R_RISCV_TLS_IE_STYPE-54] + _ = x[R_PCRELDBL-55] + _ = x[R_ADDRMIPSU-56] + _ = x[R_ADDRMIPSTLS-57] + _ = x[R_ADDRCUOFF-58] + _ = x[R_WASMIMPORT-59] + _ = x[R_XCOFFREF-60] } -const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_WEAKADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CALLRISCVR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_USEIFACER_USEIFACEMETHODR_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_LDST8R_ARM64_LDST32R_ARM64_LDST64R_ARM64_LDST128R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_RISCV_PCREL_ITYPER_RISCV_PCREL_STYPER_RISCV_TLS_IE_ITYPER_RISCV_TLS_IE_STYPER_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREF" +const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_WEAKADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CALLRISCVR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_USEIFACER_USEIFACEMETHODR_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_LDST8R_ARM64_LDST16R_ARM64_LDST32R_ARM64_LDST64R_ARM64_LDST128R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_RISCV_PCREL_ITYPER_RISCV_PCREL_STYPER_RISCV_TLS_IE_ITYPER_RISCV_TLS_IE_STYPER_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREF" -var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 60, 66, 72, 81, 92, 101, 112, 122, 133, 140, 147, 155, 163, 171, 177, 183, 189, 199, 208, 218, 234, 245, 256, 266, 275, 288, 302, 316, 330, 346, 357, 370, 383, 397, 411, 426, 440, 454, 465, 479, 494, 511, 529, 550, 569, 588, 608, 628, 638, 649, 662, 673, 685, 695} +var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 60, 66, 72, 81, 92, 101, 112, 122, 133, 140, 147, 155, 163, 171, 177, 183, 189, 199, 208, 218, 234, 245, 256, 266, 275, 288, 302, 316, 330, 346, 357, 370, 383, 397, 411, 425, 440, 454, 468, 479, 493, 508, 525, 543, 564, 583, 602, 622, 642, 652, 663, 676, 687, 699, 709} func (i RelocType) String() string { i -= 1 diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go index cb16180657..a7af855646 100644 --- a/src/cmd/link/internal/arm64/asm.go +++ b/src/cmd/link/internal/arm64/asm.go @@ -177,6 +177,14 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade su.SetRelocType(rIdx, objabi.R_ARM64_LDST8) return true + case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST16_ABS_LO12_NC): + if targType == sym.SDYNIMPORT { + ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ)) + } + su := ldr.MakeSymbolUpdater(s) + su.SetRelocType(rIdx, objabi.R_ARM64_LDST16) + return true + case objabi.ElfRelocOffset + objabi.RelocType(elf.R_AARCH64_LDST32_ABS_LO12_NC): if targType == sym.SDYNIMPORT { ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ)) @@ -769,6 +777,14 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade o0 := uint32(t&0xfff) << 10 return val | int64(o0), noExtReloc, true + case objabi.R_ARM64_LDST16: + t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff) + if t&1 != 0 { + ldr.Errorf(s, "invalid address: %x for relocation type: R_AARCH64_LDST16_ABS_LO12_NC", t) + } + o0 := (uint32(t&0xfff) >> 1) << 10 + return val | int64(o0), noExtReloc, true + case objabi.R_ARM64_LDST32: t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff) if t&3 != 0 { diff --git a/src/cmd/link/internal/loadelf/ldelf.go b/src/cmd/link/internal/loadelf/ldelf.go index 5260c6bdcb..db543a5e50 100644 --- a/src/cmd/link/internal/loadelf/ldelf.go +++ b/src/cmd/link/internal/loadelf/ldelf.go @@ -1019,6 +1019,7 @@ func relSize(arch *sys.Arch, pn string, elftype uint32) (uint8, error) { ARM64 | uint32(elf.R_AARCH64_ADR_PREL_PG_HI21)<<16, ARM64 | uint32(elf.R_AARCH64_ADD_ABS_LO12_NC)<<16, ARM64 | uint32(elf.R_AARCH64_LDST8_ABS_LO12_NC)<<16, + ARM64 | uint32(elf.R_AARCH64_LDST16_ABS_LO12_NC)<<16, ARM64 | uint32(elf.R_AARCH64_LDST32_ABS_LO12_NC)<<16, ARM64 | uint32(elf.R_AARCH64_LDST64_ABS_LO12_NC)<<16, ARM64 | uint32(elf.R_AARCH64_LDST128_ABS_LO12_NC)<<16, -- cgit v1.3-5-g9baa From b9365488f017ba88540f21927a69e34351941db1 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Tue, 24 Nov 2020 17:48:38 +0100 Subject: cmd/internal/objabi: assume GOARM=7 on Android CL 34641 changed the Go runtime to assume GOARM=7 support on Android. This change completes that by assuming GOARM=7 in the toolchain, fixing the gotcha of inexplicably slow performance on non-arm64 Android devices. There is already code in cmd/dist to force GOARM to 7 on GOOS=android. However, dist is most likely run with GOOS != android. Change-Id: I5e2bf11c3ecd0f6c193229eaa8ddc570722799d1 Reviewed-on: https://go-review.googlesource.com/c/go/+/272846 Run-TryBot: Elias Naur TryBot-Result: Go Bot Reviewed-by: Cherry Zhang Trust: Elias Naur --- src/cmd/dist/util.go | 6 ------ src/cmd/internal/objabi/util.go | 7 ++++++- 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'src/cmd/internal') diff --git a/src/cmd/dist/util.go b/src/cmd/dist/util.go index 0a419e465f..9b4f8d2dec 100644 --- a/src/cmd/dist/util.go +++ b/src/cmd/dist/util.go @@ -383,12 +383,6 @@ func xsamefile(f1, f2 string) bool { } func xgetgoarm() string { - if goos == "android" { - // Assume all android devices have VFPv3. - // These ports are also mostly cross-compiled, so it makes little - // sense to auto-detect the setting. - return "7" - } if gohostarch != "arm" || goos != gohostos { // Conservative default for cross-compilation. return "5" diff --git a/src/cmd/internal/objabi/util.go b/src/cmd/internal/objabi/util.go index 9479ab2cd9..d36e743580 100644 --- a/src/cmd/internal/objabi/util.go +++ b/src/cmd/internal/objabi/util.go @@ -40,7 +40,12 @@ const ( ) func goarm() int { - switch v := envOr("GOARM", defaultGOARM); v { + def := defaultGOARM + if GOOS == "android" { + // Android devices always support GOARM=7. + def = "7" + } + switch v := envOr("GOARM", def); v { case "5": return 5 case "6": -- cgit v1.3-5-g9baa From ef603bead5d336e81954f890e20efa0261581792 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Wed, 25 Nov 2020 19:12:13 +0100 Subject: cmd/dist: restore GOARM=7 default for android/arm Fixes the android/arm builder. Without it, the builder reported unexpected stale targets during bootstrap: https://build.golang.org/log/b951f1171be54cf4a12c2a0720ffaf07f8a11377 Tighten the GOARM=7 default in cmd/internal/objabi while here. Change-Id: I944744910193e72e91bc37b5bf0783076b45e579 Reviewed-on: https://go-review.googlesource.com/c/go/+/273167 Run-TryBot: Elias Naur Reviewed-by: Cherry Zhang TryBot-Result: Go Bot Trust: Elias Naur --- src/cmd/dist/util.go | 6 ++++++ src/cmd/internal/objabi/util.go | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'src/cmd/internal') diff --git a/src/cmd/dist/util.go b/src/cmd/dist/util.go index 9b4f8d2dec..0a419e465f 100644 --- a/src/cmd/dist/util.go +++ b/src/cmd/dist/util.go @@ -383,6 +383,12 @@ func xsamefile(f1, f2 string) bool { } func xgetgoarm() string { + if goos == "android" { + // Assume all android devices have VFPv3. + // These ports are also mostly cross-compiled, so it makes little + // sense to auto-detect the setting. + return "7" + } if gohostarch != "arm" || goos != gohostos { // Conservative default for cross-compilation. return "5" diff --git a/src/cmd/internal/objabi/util.go b/src/cmd/internal/objabi/util.go index d36e743580..a73ab479a1 100644 --- a/src/cmd/internal/objabi/util.go +++ b/src/cmd/internal/objabi/util.go @@ -41,8 +41,8 @@ const ( func goarm() int { def := defaultGOARM - if GOOS == "android" { - // Android devices always support GOARM=7. + if GOOS == "android" && GOARCH == "arm" { + // Android arm devices always support GOARM=7. def = "7" } switch v := envOr("GOARM", def); v { -- cgit v1.3-5-g9baa From f5978a09589badb927d3aa96998fc785524cae02 Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Sun, 22 Nov 2020 11:52:55 +1100 Subject: cmd/internal/obj/riscv: add tests for BGE/BGEU/BLT/BLTU Add tests for BGE/BGEU/BLT/BLTU branch instructions. Also add pure Go variants of these to ensure that the test data, Go and assembly all match up. Change-Id: I84c68605e116a4e57f6c5c765bf0aaecab84b675 Reviewed-on: https://go-review.googlesource.com/c/go/+/271913 Trust: Joel Sing Reviewed-by: Quey-Liang Kao Reviewed-by: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Go Bot --- .../obj/riscv/testdata/testbranch/branch_test.go | 54 +++++++++++++++++++++- .../obj/riscv/testdata/testbranch/branch_test.s | 44 ++++++++++++++++++ 2 files changed, 97 insertions(+), 1 deletion(-) (limited to 'src/cmd/internal') diff --git a/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go b/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go index 803ba8c77c..5412577a05 100644 --- a/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go +++ b/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go @@ -11,6 +11,8 @@ import ( ) func testBEQZ(a int64) (r bool) +func testBGE(a, b int64) (r bool) +func testBGEU(a, b int64) (r bool) func testBGEZ(a int64) (r bool) func testBGT(a, b int64) (r bool) func testBGTU(a, b int64) (r bool) @@ -18,6 +20,8 @@ func testBGTZ(a int64) (r bool) func testBLE(a, b int64) (r bool) func testBLEU(a, b int64) (r bool) func testBLEZ(a int64) (r bool) +func testBLT(a, b int64) (r bool) +func testBLTU(a, b int64) (r bool) func testBLTZ(a int64) (r bool) func testBNEZ(a int64) (r bool) @@ -29,6 +33,16 @@ func TestBranchCondition(t *testing.T) { fn func(a, b int64) bool want bool }{ + {"BGE", 0, 1, testBGE, false}, + {"BGE", 0, 0, testBGE, true}, + {"BGE", 0, -1, testBGE, true}, + {"BGE", -1, 0, testBGE, false}, + {"BGE", 1, 0, testBGE, true}, + {"BGEU", 0, 1, testBGEU, false}, + {"BGEU", 0, 0, testBGEU, true}, + {"BGEU", 0, -1, testBGEU, false}, + {"BGEU", -1, 0, testBGEU, true}, + {"BGEU", 1, 0, testBGEU, true}, {"BGT", 0, 1, testBGT, true}, {"BGT", 0, 0, testBGT, false}, {"BGT", 0, -1, testBGT, false}, @@ -48,11 +62,49 @@ func TestBranchCondition(t *testing.T) { {"BLEU", 0, 0, testBLEU, true}, {"BLEU", -1, 0, testBLEU, true}, {"BLEU", 1, 0, testBLEU, true}, + {"BLT", 0, 1, testBLT, true}, + {"BLT", 0, -1, testBLT, false}, + {"BLT", 0, 0, testBLT, false}, + {"BLT", -1, 0, testBLT, true}, + {"BLT", 1, 0, testBLT, false}, + {"BLTU", 0, 1, testBLTU, true}, + {"BLTU", 0, -1, testBLTU, true}, + {"BLTU", 0, 0, testBLTU, false}, + {"BLTU", -1, 0, testBLTU, false}, + {"BLTU", 1, 0, testBLTU, false}, } for _, test := range tests { t.Run(test.ins, func(t *testing.T) { + var fn func(a, b int64) bool + switch test.ins { + case "BGE": + fn = func(a, b int64) bool { return a >= b } + case "BGEU": + fn = func(a, b int64) bool { return uint64(a) >= uint64(b) } + case "BGT": + // TODO: Currently reversed. + fn = func(a, b int64) bool { return b > a } + case "BGTU": + // TODO: Currently reversed. + fn = func(a, b int64) bool { return uint64(b) > uint64(a) } + case "BLE": + // TODO: Currently reversed. + fn = func(a, b int64) bool { return b <= a } + case "BLEU": + // TODO: Currently reversed. + fn = func(a, b int64) bool { return uint64(b) <= uint64(a) } + case "BLT": + fn = func(a, b int64) bool { return a < b } + case "BLTU": + fn = func(a, b int64) bool { return uint64(a) < uint64(b) } + default: + t.Fatalf("Unknown instruction %q", test.ins) + } + if got := fn(test.a, test.b); got != test.want { + t.Errorf("Go %v %v, %v = %v, want %v", test.ins, test.a, test.b, got, test.want) + } if got := test.fn(test.a, test.b); got != test.want { - t.Errorf("%v %v, %v = %v, want %v", test.ins, test.a, test.b, got, test.want) + t.Errorf("Assembly %v %v, %v = %v, want %v", test.ins, test.a, test.b, got, test.want) } }) } diff --git a/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.s b/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.s index 6cff235848..8dd6f563af 100644 --- a/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.s +++ b/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.s @@ -16,6 +16,28 @@ b: MOV X6, r+8(FP) RET +// func testBGE(a, b int64) (r bool) +TEXT ·testBGE(SB),NOSPLIT,$0-0 + MOV a+0(FP), X5 + MOV b+8(FP), X6 + MOV $1, X7 + BGE X5, X6, b + MOV $0, X7 +b: + MOV X7, r+16(FP) + RET + +// func testBGEU(a, b int64) (r bool) +TEXT ·testBGEU(SB),NOSPLIT,$0-0 + MOV a+0(FP), X5 + MOV b+8(FP), X6 + MOV $1, X7 + BGEU X5, X6, b + MOV $0, X7 +b: + MOV X7, r+16(FP) + RET + // func testBGEZ(a int64) (r bool) TEXT ·testBGEZ(SB),NOSPLIT,$0-0 MOV a+0(FP), X5 @@ -90,6 +112,28 @@ b: MOV X6, r+8(FP) RET +// func testBLT(a, b int64) (r bool) +TEXT ·testBLT(SB),NOSPLIT,$0-0 + MOV a+0(FP), X5 + MOV b+8(FP), X6 + MOV $1, X7 + BLT X5, X6, b + MOV $0, X7 +b: + MOV X7, r+16(FP) + RET + +// func testBLTU(a, b int64) (r bool) +TEXT ·testBLTU(SB),NOSPLIT,$0-0 + MOV a+0(FP), X5 + MOV b+8(FP), X6 + MOV $1, X7 + BLTU X5, X6, b + MOV $0, X7 +b: + MOV X7, r+16(FP) + RET + // func testBLTZ(a int64) (r bool) TEXT ·testBLTZ(SB),NOSPLIT,$0-0 MOV a+0(FP), X5 -- cgit v1.3-5-g9baa From 7430266af4f951df3c113f2c817bc600650e2295 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Sat, 21 Nov 2020 21:33:18 -0500 Subject: cmd/internal/codesign: new package On macOS/ARM64, the kernel requires that binaries must have a valid code signature to run. The C toolchain code-signs the binary at link time. We do the same. It is more subtle for Go because we stamp the buildid after linking. As the signature contains hashes of the entire file (except the signature itself), we must (re)generate the signature after stamping the buildid. This CL adds a new codesign package, which provides functionality to generate the code signature. It is a separate internal package so it can be used both in the linker and by the go command. The next CLs will add code-signing to the linker and the go command. Updates #38485, #42684. Change-Id: Id46801a6665beebaab0eb413ff2e64c5b9467059 Reviewed-on: https://go-review.googlesource.com/c/go/+/272254 Trust: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Go Bot Reviewed-by: Austin Clements Reviewed-by: Than McIntosh --- src/cmd/dist/buildtool.go | 1 + src/cmd/internal/codesign/codesign.go | 268 ++++++++++++++++++++++++++++++++++ 2 files changed, 269 insertions(+) create mode 100644 src/cmd/internal/codesign/codesign.go (limited to 'src/cmd/internal') diff --git a/src/cmd/dist/buildtool.go b/src/cmd/dist/buildtool.go index 37b3d45977..e7bedfb84e 100644 --- a/src/cmd/dist/buildtool.go +++ b/src/cmd/dist/buildtool.go @@ -53,6 +53,7 @@ var bootstrapDirs = []string{ "cmd/compile/internal/x86", "cmd/compile/internal/wasm", "cmd/internal/bio", + "cmd/internal/codesign", "cmd/internal/gcprog", "cmd/internal/dwarf", "cmd/internal/edit", diff --git a/src/cmd/internal/codesign/codesign.go b/src/cmd/internal/codesign/codesign.go new file mode 100644 index 0000000000..0517a10640 --- /dev/null +++ b/src/cmd/internal/codesign/codesign.go @@ -0,0 +1,268 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package codesign provides basic functionalities for +// ad-hoc code signing of Mach-O files. +// +// This is not a general tool for code-signing. It is made +// specifically for the Go toolchain. It uses the same +// ad-hoc signing algorithm as the Darwin linker. +package codesign + +import ( + "crypto/sha256" + "debug/macho" + "encoding/binary" + "io" +) + +// Code signature layout. +// +// The code signature is a block of bytes that contains +// a SuperBlob, which contains one or more Blobs. For ad-hoc +// signing, a single CodeDirectory Blob suffices. +// +// A SuperBlob starts with its header (the binary representation +// of the SuperBlob struct), followed by a list of (in our case, +// one) Blobs (offset and size). A CodeDirectory Blob starts +// with its head (the binary representation of CodeDirectory struct), +// followed by the identifier (as a C string) and the hashes, at +// the corresponding offsets. +// +// The signature data must be included in the __LINKEDIT segment. +// In the Mach-O file header, an LC_CODE_SIGNATURE load command +// points to the data. + +const ( + pageSizeBits = 12 + pageSize = 1 << pageSizeBits +) + +const LC_CODE_SIGNATURE = 0x1d + +// Constants and struct layouts are from +// https://opensource.apple.com/source/xnu/xnu-4903.270.47/osfmk/kern/cs_blobs.h + +const ( + CSMAGIC_REQUIREMENT = 0xfade0c00 // single Requirement blob + CSMAGIC_REQUIREMENTS = 0xfade0c01 // Requirements vector (internal requirements) + CSMAGIC_CODEDIRECTORY = 0xfade0c02 // CodeDirectory blob + CSMAGIC_EMBEDDED_SIGNATURE = 0xfade0cc0 // embedded form of signature data + CSMAGIC_DETACHED_SIGNATURE = 0xfade0cc1 // multi-arch collection of embedded signatures + + CSSLOT_CODEDIRECTORY = 0 // slot index for CodeDirectory +) + +const ( + CS_HASHTYPE_SHA1 = 1 + CS_HASHTYPE_SHA256 = 2 + CS_HASHTYPE_SHA256_TRUNCATED = 3 + CS_HASHTYPE_SHA384 = 4 +) + +const ( + CS_EXECSEG_MAIN_BINARY = 0x1 // executable segment denotes main binary + CS_EXECSEG_ALLOW_UNSIGNED = 0x10 // allow unsigned pages (for debugging) + CS_EXECSEG_DEBUGGER = 0x20 // main binary is debugger + CS_EXECSEG_JIT = 0x40 // JIT enabled + CS_EXECSEG_SKIP_LV = 0x80 // skip library validation + CS_EXECSEG_CAN_LOAD_CDHASH = 0x100 // can bless cdhash for execution + CS_EXECSEG_CAN_EXEC_CDHASH = 0x200 // can execute blessed cdhash +) + +type Blob struct { + typ uint32 // type of entry + offset uint32 // offset of entry + // data follows +} + +func (b *Blob) put(out []byte) []byte { + out = put32be(out, b.typ) + out = put32be(out, b.offset) + return out +} + +const blobSize = 2 * 4 + +type SuperBlob struct { + magic uint32 // magic number + length uint32 // total length of SuperBlob + count uint32 // number of index entries following + // blobs []Blob +} + +func (s *SuperBlob) put(out []byte) []byte { + out = put32be(out, s.magic) + out = put32be(out, s.length) + out = put32be(out, s.count) + return out +} + +const superBlobSize = 3 * 4 + +type CodeDirectory struct { + magic uint32 // magic number (CSMAGIC_CODEDIRECTORY) + length uint32 // total length of CodeDirectory blob + version uint32 // compatibility version + flags uint32 // setup and mode flags + hashOffset uint32 // offset of hash slot element at index zero + identOffset uint32 // offset of identifier string + nSpecialSlots uint32 // number of special hash slots + nCodeSlots uint32 // number of ordinary (code) hash slots + codeLimit uint32 // limit to main image signature range + hashSize uint8 // size of each hash in bytes + hashType uint8 // type of hash (cdHashType* constants) + _pad1 uint8 // unused (must be zero) + pageSize uint8 // log2(page size in bytes); 0 => infinite + _pad2 uint32 // unused (must be zero) + scatterOffset uint32 + teamOffset uint32 + _pad3 uint32 + codeLimit64 uint64 + execSegBase uint64 + execSegLimit uint64 + execSegFlags uint64 + // data follows +} + +func (c *CodeDirectory) put(out []byte) []byte { + out = put32be(out, c.magic) + out = put32be(out, c.length) + out = put32be(out, c.version) + out = put32be(out, c.flags) + out = put32be(out, c.hashOffset) + out = put32be(out, c.identOffset) + out = put32be(out, c.nSpecialSlots) + out = put32be(out, c.nCodeSlots) + out = put32be(out, c.codeLimit) + out = put8(out, c.hashSize) + out = put8(out, c.hashType) + out = put8(out, c._pad1) + out = put8(out, c.pageSize) + out = put32be(out, c._pad2) + out = put32be(out, c.scatterOffset) + out = put32be(out, c.teamOffset) + out = put32be(out, c._pad3) + out = put64be(out, c.codeLimit64) + out = put64be(out, c.execSegBase) + out = put64be(out, c.execSegLimit) + out = put64be(out, c.execSegFlags) + return out +} + +const codeDirectorySize = 13*4 + 4 + 4*8 + +// CodeSigCmd is Mach-O LC_CODE_SIGNATURE load command. +type CodeSigCmd struct { + Cmd uint32 // LC_CODE_SIGNATURE + Cmdsize uint32 // sizeof this command (16) + Dataoff uint32 // file offset of data in __LINKEDIT segment + Datasize uint32 // file size of data in __LINKEDIT segment +} + +func FindCodeSigCmd(f *macho.File) (CodeSigCmd, bool) { + get32 := f.ByteOrder.Uint32 + for _, l := range f.Loads { + data := l.Raw() + cmd := get32(data) + if cmd == LC_CODE_SIGNATURE { + return CodeSigCmd{ + cmd, + get32(data[4:]), + get32(data[8:]), + get32(data[12:]), + }, true + } + } + return CodeSigCmd{}, false +} + +func put32be(b []byte, x uint32) []byte { binary.BigEndian.PutUint32(b, x); return b[4:] } +func put64be(b []byte, x uint64) []byte { binary.BigEndian.PutUint64(b, x); return b[8:] } +func put8(b []byte, x uint8) []byte { b[0] = x; return b[1:] } +func puts(b, s []byte) []byte { n := copy(b, s); return b[n:] } + +// Size computes the size of the code signature. +// id is the identifier used for signing (a field in CodeDirectory blob, which +// has no significance in ad-hoc signing). +func Size(codeSize int64, id string) int64 { + nhashes := (codeSize + pageSize - 1) / pageSize + idOff := int64(codeDirectorySize) + hashOff := idOff + int64(len(id)+1) + cdirSz := hashOff + nhashes*sha256.Size + return int64(superBlobSize+blobSize) + cdirSz +} + +// Sign generates an ad-hoc code signature and writes it to out. +// out must have length at least Size(codeSize, id). +// data is the file content without the signature, of size codeSize. +// textOff and textSize is the file offset and size of the text segment. +// isMain is true if this is a main executable. +// id is the identifier used for signing (a field in CodeDirectory blob, which +// has no significance in ad-hoc signing). +func Sign(out []byte, data io.Reader, id string, codeSize, textOff, textSize int64, isMain bool) { + nhashes := (codeSize + pageSize - 1) / pageSize + idOff := int64(codeDirectorySize) + hashOff := idOff + int64(len(id)+1) + sz := Size(codeSize, id) + + // emit blob headers + sb := SuperBlob{ + magic: CSMAGIC_EMBEDDED_SIGNATURE, + length: uint32(sz), + count: 1, + } + blob := Blob{ + typ: CSSLOT_CODEDIRECTORY, + offset: superBlobSize + blobSize, + } + cdir := CodeDirectory{ + magic: CSMAGIC_CODEDIRECTORY, + length: uint32(sz) - (superBlobSize + blobSize), + version: 0x20400, + flags: 0x20002, // adhoc | linkerSigned + hashOffset: uint32(hashOff), + identOffset: uint32(idOff), + nCodeSlots: uint32(nhashes), + codeLimit: uint32(codeSize), + hashSize: sha256.Size, + hashType: CS_HASHTYPE_SHA256, + pageSize: uint8(pageSizeBits), + execSegBase: uint64(textOff), + execSegLimit: uint64(textSize), + } + if isMain { + cdir.execSegFlags = CS_EXECSEG_MAIN_BINARY + } + + outp := out + outp = sb.put(outp) + outp = blob.put(outp) + outp = cdir.put(outp) + + // emit the identifier + outp = puts(outp, []byte(id+"\000")) + + // emit hashes + var buf [pageSize]byte + h := sha256.New() + p := 0 + for p < int(codeSize) { + n, err := io.ReadFull(data, buf[:]) + if err == io.EOF { + break + } + if err != nil && err != io.ErrUnexpectedEOF { + panic(err) + } + if p+n > int(codeSize) { + n = int(codeSize) - p + } + p += n + h.Reset() + h.Write(buf[:n]) + b := h.Sum(nil) + outp = puts(outp, b[:]) + } +} -- cgit v1.3-5-g9baa From 7fca39aa05ad3c60abac1ae51ae9847dfbe017d6 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Sat, 21 Nov 2020 17:43:16 -0500 Subject: cmd/internal/buildid: exclude Mach-O code signature in hash calculation The code signature contains hashes of the entire file (except the signature itself), including the buildid. Therefore, the buildid cannot depend on the signature. Otherwise updating buildid will invalidate the signature, and vice versa. As we cannot change the code-signing algorithm, we can only change buildid calculation. This CL changes the buildid calculation to exclude the Mach-O code signature. So updating code signature after stamping the buildid will not invalidate the buildid. Updates #38485, #42684. Change-Id: I8a9e2e25ca9dc00d9556d13b81652f43bbf6a084 Reviewed-on: https://go-review.googlesource.com/c/go/+/272255 Trust: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Go Bot Reviewed-by: Austin Clements Reviewed-by: Than McIntosh --- src/cmd/internal/buildid/buildid_test.go | 31 ++++++++++++++++++++ src/cmd/internal/buildid/rewrite.go | 50 ++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) (limited to 'src/cmd/internal') diff --git a/src/cmd/internal/buildid/buildid_test.go b/src/cmd/internal/buildid/buildid_test.go index 904c2c6f37..e832f9987e 100644 --- a/src/cmd/internal/buildid/buildid_test.go +++ b/src/cmd/internal/buildid/buildid_test.go @@ -11,6 +11,7 @@ import ( "io/ioutil" "os" "reflect" + "strings" "testing" ) @@ -146,3 +147,33 @@ func TestFindAndHash(t *testing.T) { } } } + +func TestExcludedReader(t *testing.T) { + const s = "0123456789abcdefghijklmn" + tests := []struct { + start, end int64 // excluded range + results []string // expected results of reads + }{ + {12, 15, []string{"0123456789", "ab\x00\x00\x00fghij", "klmn"}}, // within one read + {8, 21, []string{"01234567\x00\x00", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", "\x00lmn"}}, // across multiple reads + {10, 20, []string{"0123456789", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", "klmn"}}, // a whole read + {0, 5, []string{"\x00\x00\x00\x00\x0056789", "abcdefghij", "klmn"}}, // start + {12, 24, []string{"0123456789", "ab\x00\x00\x00\x00\x00\x00\x00\x00", "\x00\x00\x00\x00"}}, // end + } + p := make([]byte, 10) + for _, test := range tests { + r := &excludedReader{strings.NewReader(s), 0, test.start, test.end} + for _, res := range test.results { + n, err := r.Read(p) + if err != nil { + t.Errorf("read failed: %v", err) + } + if n != len(res) { + t.Errorf("unexpected number of bytes read: want %d, got %d", len(res), n) + } + if string(p[:n]) != res { + t.Errorf("unexpected bytes: want %q, got %q", res, p[:n]) + } + } + } +} diff --git a/src/cmd/internal/buildid/rewrite.go b/src/cmd/internal/buildid/rewrite.go index 5be54552a6..d3d2009d1c 100644 --- a/src/cmd/internal/buildid/rewrite.go +++ b/src/cmd/internal/buildid/rewrite.go @@ -6,7 +6,9 @@ package buildid import ( "bytes" + "cmd/internal/codesign" "crypto/sha256" + "debug/macho" "fmt" "io" ) @@ -26,6 +28,11 @@ func FindAndHash(r io.Reader, id string, bufSize int) (matches []int64, hash [32 zeros := make([]byte, len(id)) idBytes := []byte(id) + // For Mach-O files, we want to exclude the code signature. + // The code signature contains hashes of the whole file (except the signature + // itself), including the buildid. So the buildid cannot contain the signature. + r = excludeMachoCodeSignature(r) + // The strategy is to read the file through buf, looking for id, // but we need to worry about what happens if id is broken up // and returned in parts by two different reads. @@ -89,3 +96,46 @@ func Rewrite(w io.WriterAt, pos []int64, id string) error { } return nil } + +func excludeMachoCodeSignature(r io.Reader) io.Reader { + ra, ok := r.(io.ReaderAt) + if !ok { + return r + } + f, err := macho.NewFile(ra) + if err != nil { + return r + } + cmd, ok := codesign.FindCodeSigCmd(f) + if !ok { + return r + } + return &excludedReader{r, 0, int64(cmd.Dataoff), int64(cmd.Dataoff + cmd.Datasize)} +} + +// excludedReader wraps an io.Reader. Reading from it returns the bytes from +// the underlying reader, except that when the byte offset is within the +// range between start and end, it returns zero bytes. +type excludedReader struct { + r io.Reader + off int64 // current offset + start, end int64 // the range to be excluded (read as zero) +} + +func (r *excludedReader) Read(p []byte) (int, error) { + n, err := r.r.Read(p) + if n > 0 && r.off+int64(n) > r.start && r.off < r.end { + cstart := r.start - r.off + if cstart < 0 { + cstart = 0 + } + cend := r.end - r.off + if cend > int64(n) { + cend = int64(n) + } + zeros := make([]byte, cend-cstart) + copy(p[cstart:cend], zeros) + } + r.off += int64(n) + return n, err +} -- cgit v1.3-5-g9baa From 8cd35e00bd413e68e6b9ae6403aa4209fc89b90f Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Sat, 21 Nov 2020 21:24:57 -0500 Subject: cmd/internal/buildid: update Mach-O code signature when rewriting buildid As the code signature contains hashes of the entire file (except the signature itself), rewriting buildid will invalidate the signature. This CL makes it regenerate the signature when rewriting the buildid. It only does it when the file already has a code signature, with proper size (darwin/arm64 binaries generated by the Go linker should have). Updates #38485, #42684. Change-Id: I082d9e5808b0ee6a35f9c362d7262aadd9113c81 Reviewed-on: https://go-review.googlesource.com/c/go/+/272257 Trust: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Go Bot Reviewed-by: Austin Clements Reviewed-by: Than McIntosh --- src/cmd/buildid/buildid.go | 2 +- src/cmd/go/internal/work/buildid.go | 2 +- src/cmd/internal/buildid/rewrite.go | 39 ++++++++++++++++++++++++++++--------- 3 files changed, 32 insertions(+), 11 deletions(-) (limited to 'src/cmd/internal') diff --git a/src/cmd/buildid/buildid.go b/src/cmd/buildid/buildid.go index 699d977950..8e02a7ae10 100644 --- a/src/cmd/buildid/buildid.go +++ b/src/cmd/buildid/buildid.go @@ -62,7 +62,7 @@ func main() { return } - f, err = os.OpenFile(file, os.O_WRONLY, 0) + f, err = os.OpenFile(file, os.O_RDWR, 0) if err != nil { log.Fatal(err) } diff --git a/src/cmd/go/internal/work/buildid.go b/src/cmd/go/internal/work/buildid.go index a88544e1af..3c7be5a3e3 100644 --- a/src/cmd/go/internal/work/buildid.go +++ b/src/cmd/go/internal/work/buildid.go @@ -647,7 +647,7 @@ func (b *Builder) updateBuildID(a *Action, target string, rewrite bool) error { } if rewrite { - w, err := os.OpenFile(target, os.O_WRONLY, 0) + w, err := os.OpenFile(target, os.O_RDWR, 0) if err != nil { return err } diff --git a/src/cmd/internal/buildid/rewrite.go b/src/cmd/internal/buildid/rewrite.go index d3d2009d1c..a7928959c4 100644 --- a/src/cmd/internal/buildid/rewrite.go +++ b/src/cmd/internal/buildid/rewrite.go @@ -94,19 +94,27 @@ func Rewrite(w io.WriterAt, pos []int64, id string) error { return err } } + + // Update Mach-O code signature, if any. + if f, cmd, ok := findMachoCodeSignature(w); ok { + if codesign.Size(int64(cmd.Dataoff), "a.out") == int64(cmd.Datasize) { + // Update the signature if the size matches, so we don't need to + // fix up headers. Binaries generated by the Go linker should have + // the expected size. Otherwise skip. + text := f.Segment("__TEXT") + cs := make([]byte, cmd.Datasize) + codesign.Sign(cs, w.(io.Reader), "a.out", int64(cmd.Dataoff), int64(text.Offset), int64(text.Filesz), f.Type == macho.TypeExec) + if _, err := w.WriteAt(cs, int64(cmd.Dataoff)); err != nil { + return err + } + } + } + return nil } func excludeMachoCodeSignature(r io.Reader) io.Reader { - ra, ok := r.(io.ReaderAt) - if !ok { - return r - } - f, err := macho.NewFile(ra) - if err != nil { - return r - } - cmd, ok := codesign.FindCodeSigCmd(f) + _, cmd, ok := findMachoCodeSignature(r) if !ok { return r } @@ -139,3 +147,16 @@ func (r *excludedReader) Read(p []byte) (int, error) { r.off += int64(n) return n, err } + +func findMachoCodeSignature(r interface{}) (*macho.File, codesign.CodeSigCmd, bool) { + ra, ok := r.(io.ReaderAt) + if !ok { + return nil, codesign.CodeSigCmd{}, false + } + f, err := macho.NewFile(ra) + if err != nil { + return nil, codesign.CodeSigCmd{}, false + } + cmd, ok := codesign.FindCodeSigCmd(f) + return f, cmd, ok +} -- cgit v1.3-5-g9baa From 0433845ad18a355413033bb3495ba3195f4c69ec Mon Sep 17 00:00:00 2001 From: Quey-Liang Kao Date: Sat, 21 Nov 2020 22:48:55 +0800 Subject: cmd/asm, cmd/internal/obj/riscv: fix branch pseudo-instructions Pseudo branch instructions BGT, BGTU, BLE, and BLEU implemented In CL 226397 were translated inconsistently compared to other ones due to the inversion of registers. For instance, while "BLT a, b" generates "jump if a < b", "BLE a, b" generates "jump if b <= a." This CL fixes the translation in the assembler and the tests. Change-Id: Ia757be73e848734ca5b3a790e081f7c4f98c30f2 Reviewed-on: https://go-review.googlesource.com/c/go/+/271911 Reviewed-by: Cherry Zhang Reviewed-by: Joel Sing Run-TryBot: Joel Sing --- src/cmd/asm/internal/asm/testdata/riscvenc.s | 8 ++-- src/cmd/internal/obj/riscv/obj.go | 8 ++-- .../obj/riscv/testdata/testbranch/branch_test.go | 49 ++++++++++------------ 3 files changed, 31 insertions(+), 34 deletions(-) (limited to 'src/cmd/internal') diff --git a/src/cmd/asm/internal/asm/testdata/riscvenc.s b/src/cmd/asm/internal/asm/testdata/riscvenc.s index e30a576473..9a49d96ca0 100644 --- a/src/cmd/asm/internal/asm/testdata/riscvenc.s +++ b/src/cmd/asm/internal/asm/testdata/riscvenc.s @@ -340,11 +340,11 @@ start: // Branch pseudo-instructions BEQZ X5, start // BEQZ X5, 2 // e38602c0 BGEZ X5, start // BGEZ X5, 2 // e3d402c0 - BGT X5, X6, start // BGT X5, X6, 2 // e3c262c0 - BGTU X5, X6, start // BGTU X5, X6, 2 // e3e062c0 + BGT X5, X6, start // BGT X5, X6, 2 // e34253c0 + BGTU X5, X6, start // BGTU X5, X6, 2 // e36053c0 BGTZ X5, start // BGTZ X5, 2 // e34e50be - BLE X5, X6, start // BLE X5, X6, 2 // e3dc62be - BLEU X5, X6, start // BLEU X5, X6, 2 // e3fa62be + BLE X5, X6, start // BLE X5, X6, 2 // e35c53be + BLEU X5, X6, start // BLEU X5, X6, 2 // e37a53be BLEZ X5, start // BLEZ X5, 2 // e35850be BLTZ X5, start // BLTZ X5, 2 // e3c602be BNEZ X5, start // BNEZ X5, 2 // e39402be diff --git a/src/cmd/internal/obj/riscv/obj.go b/src/cmd/internal/obj/riscv/obj.go index 0cffa54fa6..9257a6453a 100644 --- a/src/cmd/internal/obj/riscv/obj.go +++ b/src/cmd/internal/obj/riscv/obj.go @@ -1777,15 +1777,15 @@ func instructionsForProg(p *obj.Prog) []*instruction { case ABGEZ: ins.as, ins.rs1, ins.rs2 = ABGE, REG_ZERO, uint32(p.From.Reg) case ABGT: - ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.Reg), uint32(p.From.Reg) + ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.From.Reg), uint32(p.Reg) case ABGTU: - ins.as, ins.rs1, ins.rs2 = ABLTU, uint32(p.Reg), uint32(p.From.Reg) + ins.as, ins.rs1, ins.rs2 = ABLTU, uint32(p.From.Reg), uint32(p.Reg) case ABGTZ: ins.as, ins.rs1, ins.rs2 = ABLT, uint32(p.From.Reg), REG_ZERO case ABLE: - ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.Reg), uint32(p.From.Reg) + ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.From.Reg), uint32(p.Reg) case ABLEU: - ins.as, ins.rs1, ins.rs2 = ABGEU, uint32(p.Reg), uint32(p.From.Reg) + ins.as, ins.rs1, ins.rs2 = ABGEU, uint32(p.From.Reg), uint32(p.Reg) case ABLEZ: ins.as, ins.rs1, ins.rs2 = ABGE, uint32(p.From.Reg), REG_ZERO case ABLTZ: diff --git a/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go b/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go index 5412577a05..279aeb2c32 100644 --- a/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go +++ b/src/cmd/internal/obj/riscv/testdata/testbranch/branch_test.go @@ -43,33 +43,34 @@ func TestBranchCondition(t *testing.T) { {"BGEU", 0, -1, testBGEU, false}, {"BGEU", -1, 0, testBGEU, true}, {"BGEU", 1, 0, testBGEU, true}, - {"BGT", 0, 1, testBGT, true}, + {"BGT", 0, 1, testBGT, false}, {"BGT", 0, 0, testBGT, false}, - {"BGT", 0, -1, testBGT, false}, - {"BGT", -1, 0, testBGT, true}, - {"BGT", 1, 0, testBGT, false}, - {"BGTU", 0, 1, testBGTU, true}, - {"BGTU", 0, -1, testBGTU, true}, - {"BGTU", -1, 0, testBGTU, false}, - {"BGTU", 1, 0, testBGTU, false}, - {"BLE", 0, 1, testBLE, false}, - {"BLE", 0, -1, testBLE, true}, + {"BGT", 0, -1, testBGT, true}, + {"BGT", -1, 0, testBGT, false}, + {"BGT", 1, 0, testBGT, true}, + {"BGTU", 0, 1, testBGTU, false}, + {"BGTU", 0, 0, testBGTU, false}, + {"BGTU", 0, -1, testBGTU, false}, + {"BGTU", -1, 0, testBGTU, true}, + {"BGTU", 1, 0, testBGTU, true}, + {"BLE", 0, 1, testBLE, true}, {"BLE", 0, 0, testBLE, true}, - {"BLE", -1, 0, testBLE, false}, - {"BLE", 1, 0, testBLE, true}, - {"BLEU", 0, 1, testBLEU, false}, - {"BLEU", 0, -1, testBLEU, false}, + {"BLE", 0, -1, testBLE, false}, + {"BLE", -1, 0, testBLE, true}, + {"BLE", 1, 0, testBLE, false}, + {"BLEU", 0, 1, testBLEU, true}, {"BLEU", 0, 0, testBLEU, true}, - {"BLEU", -1, 0, testBLEU, true}, - {"BLEU", 1, 0, testBLEU, true}, + {"BLEU", 0, -1, testBLEU, true}, + {"BLEU", -1, 0, testBLEU, false}, + {"BLEU", 1, 0, testBLEU, false}, {"BLT", 0, 1, testBLT, true}, - {"BLT", 0, -1, testBLT, false}, {"BLT", 0, 0, testBLT, false}, + {"BLT", 0, -1, testBLT, false}, {"BLT", -1, 0, testBLT, true}, {"BLT", 1, 0, testBLT, false}, {"BLTU", 0, 1, testBLTU, true}, - {"BLTU", 0, -1, testBLTU, true}, {"BLTU", 0, 0, testBLTU, false}, + {"BLTU", 0, -1, testBLTU, true}, {"BLTU", -1, 0, testBLTU, false}, {"BLTU", 1, 0, testBLTU, false}, } @@ -82,17 +83,13 @@ func TestBranchCondition(t *testing.T) { case "BGEU": fn = func(a, b int64) bool { return uint64(a) >= uint64(b) } case "BGT": - // TODO: Currently reversed. - fn = func(a, b int64) bool { return b > a } + fn = func(a, b int64) bool { return a > b } case "BGTU": - // TODO: Currently reversed. - fn = func(a, b int64) bool { return uint64(b) > uint64(a) } + fn = func(a, b int64) bool { return uint64(a) > uint64(b) } case "BLE": - // TODO: Currently reversed. - fn = func(a, b int64) bool { return b <= a } + fn = func(a, b int64) bool { return a <= b } case "BLEU": - // TODO: Currently reversed. - fn = func(a, b int64) bool { return uint64(b) <= uint64(a) } + fn = func(a, b int64) bool { return uint64(a) <= uint64(b) } case "BLT": fn = func(a, b int64) bool { return a < b } case "BLTU": -- cgit v1.3-5-g9baa From c32140fa94cfc51a2152855825f57e27ae3ba133 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 4 Nov 2020 18:20:17 -0500 Subject: all: update to use filepath.WalkDir instead of filepath.Walk Now that filepath.WalkDir is available, it is more efficient and should be used in place of filepath.Walk. Update the tree to reflect best practices. As usual, the code compiled with Go 1.4 during bootstrap is excluded. (In this CL, that's only cmd/dist.) For #42027. Change-Id: Ib0f7b1e43e50b789052f9835a63ced701d8c411c Reviewed-on: https://go-review.googlesource.com/c/go/+/267719 Trust: Russ Cox Run-TryBot: Russ Cox TryBot-Result: Go Bot Reviewed-by: Rob Pike --- src/cmd/compile/fmt_test.go | 3 ++- src/cmd/dist/test.go | 1 + src/cmd/fix/main.go | 6 +++--- src/cmd/go/go_test.go | 9 +++------ src/cmd/go/internal/modfetch/fetch.go | 9 +++++---- src/cmd/go/internal/version/version.go | 12 ++++++++++-- src/cmd/go/testdata/addmod.go | 4 ++-- src/cmd/go/testdata/savedir.go | 4 ++-- src/cmd/gofmt/gofmt.go | 6 +++--- src/cmd/gofmt/long_test.go | 17 +++++++++++++---- src/cmd/internal/moddeps/moddeps_test.go | 2 +- src/compress/gzip/issue14937_test.go | 2 +- src/go/build/deps_test.go | 6 +++--- src/go/doc/headscan.go | 4 ++-- src/index/suffixarray/suffixarray_test.go | 2 +- test/run.go | 17 ++++++++++------- test/winbatch.go | 6 +++--- 17 files changed, 65 insertions(+), 45 deletions(-) (limited to 'src/cmd/internal') diff --git a/src/cmd/compile/fmt_test.go b/src/cmd/compile/fmt_test.go index e372259c78..6625ccf5e2 100644 --- a/src/cmd/compile/fmt_test.go +++ b/src/cmd/compile/fmt_test.go @@ -52,6 +52,7 @@ import ( "go/types" "internal/testenv" "io" + "io/fs" "io/ioutil" "log" "os" @@ -89,7 +90,7 @@ func TestFormats(t *testing.T) { testenv.MustHaveGoBuild(t) // more restrictive than necessary, but that's ok // process all directories - filepath.Walk(".", func(path string, info os.FileInfo, err error) error { + filepath.WalkDir(".", func(path string, info fs.DirEntry, err error) error { if info.IsDir() { if info.Name() == "testdata" { return filepath.SkipDir diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index 2a17ab9cae..955ce2a063 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -1509,6 +1509,7 @@ func (t *tester) makeGOROOTUnwritable() (undo func()) { } gocacheSubdir, _ := filepath.Rel(dir, gocache) + // Note: Can't use WalkDir here, because this has to compile with Go 1.4. filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { if suffix := strings.TrimPrefix(path, dir+string(filepath.Separator)); suffix != "" { if suffix == gocacheSubdir { diff --git a/src/cmd/fix/main.go b/src/cmd/fix/main.go index 1cea9a876a..1cedf992cf 100644 --- a/src/cmd/fix/main.go +++ b/src/cmd/fix/main.go @@ -234,10 +234,10 @@ func report(err error) { } func walkDir(path string) { - filepath.Walk(path, visitFile) + filepath.WalkDir(path, visitFile) } -func visitFile(path string, f fs.FileInfo, err error) error { +func visitFile(path string, f fs.DirEntry, err error) error { if err == nil && isGoFile(f) { err = processFile(path, false) } @@ -247,7 +247,7 @@ func visitFile(path string, f fs.FileInfo, err error) error { return nil } -func isGoFile(f fs.FileInfo) bool { +func isGoFile(f fs.DirEntry) bool { // ignore non-Go files name := f.Name() return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index a02231fa98..a730c87f97 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -774,7 +774,7 @@ func (tg *testgoData) cleanup() { func removeAll(dir string) error { // module cache has 0444 directories; // make them writable in order to remove content. - filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error { + filepath.WalkDir(dir, func(path string, info fs.DirEntry, err error) error { // chmod not only directories, but also things that we couldn't even stat // due to permission errors: they may also be unreadable directories. if err != nil || info.IsDir() { @@ -820,8 +820,8 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) { } { srcdir := filepath.Join(testGOROOT, copydir) tg.tempDir(filepath.Join("goroot", copydir)) - err := filepath.Walk(srcdir, - func(path string, info fs.FileInfo, err error) error { + err := filepath.WalkDir(srcdir, + func(path string, info fs.DirEntry, err error) error { if err != nil { return err } @@ -838,9 +838,6 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) { return err } tg.tempFile(dest, string(data)) - if err := os.Chmod(tg.path(dest), info.Mode()|0200); err != nil { - return err - } return nil }) if err != nil { diff --git a/src/cmd/go/internal/modfetch/fetch.go b/src/cmd/go/internal/modfetch/fetch.go index a3e2cd1f9d..2ee78de5b2 100644 --- a/src/cmd/go/internal/modfetch/fetch.go +++ b/src/cmd/go/internal/modfetch/fetch.go @@ -318,9 +318,10 @@ func makeDirsReadOnly(dir string) { mode fs.FileMode } var dirs []pathMode // in lexical order - filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error { - if err == nil && info.Mode()&0222 != 0 { - if info.IsDir() { + filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error { + if err == nil && d.IsDir() { + info, err := d.Info() + if err == nil && info.Mode()&0222 != 0 { dirs = append(dirs, pathMode{path, info.Mode()}) } } @@ -337,7 +338,7 @@ func makeDirsReadOnly(dir string) { // any permission changes needed to do so. func RemoveAll(dir string) error { // Module cache has 0555 directories; make them writable in order to remove content. - filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error { + filepath.WalkDir(dir, func(path string, info fs.DirEntry, err error) error { if err != nil { return nil // ignore errors walking in file system } diff --git a/src/cmd/go/internal/version/version.go b/src/cmd/go/internal/version/version.go index 44ac24c62d..58cbd32e78 100644 --- a/src/cmd/go/internal/version/version.go +++ b/src/cmd/go/internal/version/version.go @@ -88,8 +88,15 @@ func runVersion(ctx context.Context, cmd *base.Command, args []string) { // scanDir scans a directory for executables to run scanFile on. func scanDir(dir string) { - filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error { - if info.Mode().IsRegular() || info.Mode()&fs.ModeSymlink != 0 { + filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error { + if d.Type().IsRegular() || d.Type()&fs.ModeSymlink != 0 { + info, err := d.Info() + if err != nil { + if *versionV { + fmt.Fprintf(os.Stderr, "%s: %v\n", path, err) + } + return nil + } scanFile(path, info, *versionV) } return nil @@ -120,6 +127,7 @@ func scanFile(file string, info fs.FileInfo, mustPrint bool) { } info = i } + if !isExe(file, info) { if mustPrint { fmt.Fprintf(os.Stderr, "%s: not executable file\n", file) diff --git a/src/cmd/go/testdata/addmod.go b/src/cmd/go/testdata/addmod.go index d1b6467c5d..71ac47fdc1 100644 --- a/src/cmd/go/testdata/addmod.go +++ b/src/cmd/go/testdata/addmod.go @@ -122,8 +122,8 @@ func main() { {Name: ".info", Data: info}, } dir = filepath.Clean(dir) - err = filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error { - if !info.Mode().IsRegular() { + err = filepath.WalkDir(dir, func(path string, info fs.DirEntry, err error) error { + if !info.Type().IsRegular() { return nil } name := info.Name() diff --git a/src/cmd/go/testdata/savedir.go b/src/cmd/go/testdata/savedir.go index 04902df61e..75895ee279 100644 --- a/src/cmd/go/testdata/savedir.go +++ b/src/cmd/go/testdata/savedir.go @@ -49,7 +49,7 @@ func main() { a := new(txtar.Archive) dir = filepath.Clean(dir) - filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error { + filepath.WalkDir(dir, func(path string, info fs.DirEntry, err error) error { if path == dir { return nil } @@ -60,7 +60,7 @@ func main() { } return nil } - if !info.Mode().IsRegular() { + if !info.Type().IsRegular() { return nil } data, err := ioutil.ReadFile(path) diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go index dba2411eed..719c681a3e 100644 --- a/src/cmd/gofmt/gofmt.go +++ b/src/cmd/gofmt/gofmt.go @@ -74,7 +74,7 @@ func initParserMode() { } } -func isGoFile(f fs.FileInfo) bool { +func isGoFile(f fs.DirEntry) bool { // ignore non-Go files name := f.Name() return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") @@ -164,7 +164,7 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error return err } -func visitFile(path string, f fs.FileInfo, err error) error { +func visitFile(path string, f fs.DirEntry, err error) error { if err == nil && isGoFile(f) { err = processFile(path, nil, os.Stdout, false) } @@ -177,7 +177,7 @@ func visitFile(path string, f fs.FileInfo, err error) error { } func walkDir(path string) { - filepath.Walk(path, visitFile) + filepath.WalkDir(path, visitFile) } func main() { diff --git a/src/cmd/gofmt/long_test.go b/src/cmd/gofmt/long_test.go index 28306ce83e..4a821705f1 100644 --- a/src/cmd/gofmt/long_test.go +++ b/src/cmd/gofmt/long_test.go @@ -108,12 +108,12 @@ func testFiles(t *testing.T, filenames <-chan string, done chan<- int) { func genFilenames(t *testing.T, filenames chan<- string) { defer close(filenames) - handleFile := func(filename string, fi fs.FileInfo, err error) error { + handleFile := func(filename string, d fs.DirEntry, err error) error { if err != nil { t.Error(err) return nil } - if isGoFile(fi) { + if isGoFile(d) { filenames <- filename nfiles++ } @@ -124,13 +124,13 @@ func genFilenames(t *testing.T, filenames chan<- string) { if *files != "" { for _, filename := range strings.Split(*files, ",") { fi, err := os.Stat(filename) - handleFile(filename, fi, err) + handleFile(filename, &statDirEntry{fi}, err) } return // ignore files under -root } // otherwise, test all Go files under *root - filepath.Walk(*root, handleFile) + filepath.WalkDir(*root, handleFile) } func TestAll(t *testing.T) { @@ -164,3 +164,12 @@ func TestAll(t *testing.T) { fmt.Printf("processed %d files\n", nfiles) } } + +type statDirEntry struct { + info fs.FileInfo +} + +func (d *statDirEntry) Name() string { return d.info.Name() } +func (d *statDirEntry) IsDir() bool { return d.info.IsDir() } +func (d *statDirEntry) Type() fs.FileMode { return d.info.Mode().Type() } +func (d *statDirEntry) Info() (fs.FileInfo, error) { return d.info, nil } diff --git a/src/cmd/internal/moddeps/moddeps_test.go b/src/cmd/internal/moddeps/moddeps_test.go index 7362e7868b..9ea21873c5 100644 --- a/src/cmd/internal/moddeps/moddeps_test.go +++ b/src/cmd/internal/moddeps/moddeps_test.go @@ -33,7 +33,7 @@ func findGorootModules(t *testing.T) []gorootModule { goBin := testenv.GoToolPath(t) goroot.once.Do(func() { - goroot.err = filepath.Walk(runtime.GOROOT(), func(path string, info fs.FileInfo, err error) error { + goroot.err = filepath.WalkDir(runtime.GOROOT(), func(path string, info fs.DirEntry, err error) error { if err != nil { return err } diff --git a/src/compress/gzip/issue14937_test.go b/src/compress/gzip/issue14937_test.go index 24db3641aa..20da0b6824 100644 --- a/src/compress/gzip/issue14937_test.go +++ b/src/compress/gzip/issue14937_test.go @@ -31,7 +31,7 @@ func TestGZIPFilesHaveZeroMTimes(t *testing.T) { t.Fatal("error evaluating GOROOT: ", err) } var files []string - err = filepath.Walk(goroot, func(path string, info fs.FileInfo, err error) error { + err = filepath.WalkDir(goroot, func(path string, info fs.DirEntry, err error) error { if err != nil { return err } diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index bf1367355d..e9ed26aa5f 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -510,8 +510,8 @@ func listStdPkgs(goroot string) ([]string, error) { var pkgs []string src := filepath.Join(goroot, "src") + string(filepath.Separator) - walkFn := func(path string, fi fs.FileInfo, err error) error { - if err != nil || !fi.IsDir() || path == src { + walkFn := func(path string, d fs.DirEntry, err error) error { + if err != nil || !d.IsDir() || path == src { return nil } @@ -528,7 +528,7 @@ func listStdPkgs(goroot string) ([]string, error) { pkgs = append(pkgs, strings.TrimPrefix(name, "vendor/")) return nil } - if err := filepath.Walk(src, walkFn); err != nil { + if err := filepath.WalkDir(src, walkFn); err != nil { return nil, err } return pkgs, nil diff --git a/src/go/doc/headscan.go b/src/go/doc/headscan.go index 8ea462366e..fe26a0ea84 100644 --- a/src/go/doc/headscan.go +++ b/src/go/doc/headscan.go @@ -69,8 +69,8 @@ func main() { flag.Parse() fset := token.NewFileSet() nheadings := 0 - err := filepath.Walk(*root, func(path string, fi fs.FileInfo, err error) error { - if !fi.IsDir() { + err := filepath.WalkDir(*root, func(path string, info fs.DirEntry, err error) error { + if !info.IsDir() { return nil } pkgs, err := parser.ParseDir(fset, path, isGoFile, parser.ParseComments) diff --git a/src/index/suffixarray/suffixarray_test.go b/src/index/suffixarray/suffixarray_test.go index b6a81123b7..a11a98dae0 100644 --- a/src/index/suffixarray/suffixarray_test.go +++ b/src/index/suffixarray/suffixarray_test.go @@ -503,7 +503,7 @@ func makeText(name string) ([]byte, error) { return nil, err } case "go": - err := filepath.Walk("../..", func(path string, info fs.FileInfo, err error) error { + err := filepath.WalkDir("../..", func(path string, info fs.DirEntry, err error) error { if err == nil && strings.HasSuffix(path, ".go") && !info.IsDir() { file, err := ioutil.ReadFile(path) if err != nil { diff --git a/test/run.go b/test/run.go index 672861c8d7..4abf32d25c 100644 --- a/test/run.go +++ b/test/run.go @@ -14,6 +14,7 @@ import ( "fmt" "hash/fnv" "io" + "io/fs" "io/ioutil" "log" "os" @@ -1793,7 +1794,7 @@ func overlayDir(dstRoot, srcRoot string) error { return err } - return filepath.Walk(srcRoot, func(srcPath string, info os.FileInfo, err error) error { + return filepath.WalkDir(srcRoot, func(srcPath string, d fs.DirEntry, err error) error { if err != nil || srcPath == srcRoot { return err } @@ -1804,14 +1805,16 @@ func overlayDir(dstRoot, srcRoot string) error { } dstPath := filepath.Join(dstRoot, suffix) - perm := info.Mode() & os.ModePerm - if info.Mode()&os.ModeSymlink != 0 { + var info fs.FileInfo + if d.Type()&os.ModeSymlink != 0 { info, err = os.Stat(srcPath) - if err != nil { - return err - } - perm = info.Mode() & os.ModePerm + } else { + info, err = d.Info() } + if err != nil { + return err + } + perm := info.Mode() & os.ModePerm // Always copy directories (don't symlink them). // If we add a file in the overlay, we don't want to add it in the original. diff --git a/test/winbatch.go b/test/winbatch.go index c3b48d385c..54c2fff134 100644 --- a/test/winbatch.go +++ b/test/winbatch.go @@ -27,11 +27,11 @@ func main() { // Walk the entire Go repository source tree (without GOROOT/pkg), // skipping directories that start with "." and named "testdata", // and ensure all .bat files found have exact CRLF line endings. - err := filepath.Walk(runtime.GOROOT(), func(path string, fi os.FileInfo, err error) error { + err := filepath.WalkDir(runtime.GOROOT(), func(path string, d os.DirEntry, err error) error { if err != nil { return err } - if fi.IsDir() && (strings.HasPrefix(fi.Name(), ".") || fi.Name() == "testdata") { + if d.IsDir() && (strings.HasPrefix(d.Name(), ".") || d.Name() == "testdata") { return filepath.SkipDir } if path == filepath.Join(runtime.GOROOT(), "pkg") { @@ -39,7 +39,7 @@ func main() { // Skip it to avoid false positives. (Also see golang.org/issue/37929.) return filepath.SkipDir } - if filepath.Ext(fi.Name()) == ".bat" { + if filepath.Ext(d.Name()) == ".bat" { enforceBatchStrictCRLF(path) } return nil -- cgit v1.3-5-g9baa From 1a98ab0e2dad7029d9db18fc1fae0b7e4fa4970c Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 7 Dec 2020 17:15:44 -0800 Subject: [dev.regabi] cmd/compile: add ssa.Aux tag interface for Value.Aux It's currently hard to automate refactorings around the Value.Aux field, because we don't have any static typing information for it. Adding a tag interface will make subsequent CLs easier and safer. Passes buildall w/ toolstash -cmp. Updates #42982. Change-Id: I41ae8e411a66bda3195a0957b60c2fe8a8002893 Reviewed-on: https://go-review.googlesource.com/c/go/+/275756 Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Keith Randall Trust: Matthew Dempsky --- src/cmd/compile/fmtmap_test.go | 3 ++ src/cmd/compile/internal/gc/ssa.go | 22 +++++++------- src/cmd/compile/internal/ir/mini.go | 3 +- src/cmd/compile/internal/ir/node.go | 1 + src/cmd/compile/internal/ssa/block.go | 2 +- src/cmd/compile/internal/ssa/check.go | 2 +- src/cmd/compile/internal/ssa/cse.go | 2 +- src/cmd/compile/internal/ssa/cse_test.go | 2 ++ src/cmd/compile/internal/ssa/debug.go | 4 +-- src/cmd/compile/internal/ssa/func.go | 22 +++++--------- src/cmd/compile/internal/ssa/func_test.go | 8 ++--- src/cmd/compile/internal/ssa/nilcheck_test.go | 2 +- src/cmd/compile/internal/ssa/op.go | 3 ++ src/cmd/compile/internal/ssa/rewrite.go | 42 +++++++++++++++++---------- src/cmd/compile/internal/ssa/value.go | 5 +++- src/cmd/compile/internal/ssa/zcse.go | 2 +- src/cmd/compile/internal/types/type.go | 2 ++ src/cmd/internal/obj/link.go | 4 +-- src/cmd/internal/obj/s390x/condition_code.go | 2 ++ src/cmd/internal/obj/s390x/rotate.go | 2 ++ 20 files changed, 79 insertions(+), 56 deletions(-) (limited to 'src/cmd/internal') diff --git a/src/cmd/compile/fmtmap_test.go b/src/cmd/compile/fmtmap_test.go index 756320285c..e62b9613e1 100644 --- a/src/cmd/compile/fmtmap_test.go +++ b/src/cmd/compile/fmtmap_test.go @@ -43,6 +43,9 @@ var knownFormats = map[string]string{ "cmd/compile/internal/ir.Nodes %+v": "", "cmd/compile/internal/ir.Nodes %.v": "", "cmd/compile/internal/ir.Op %+v": "", + "cmd/compile/internal/ssa.Aux %#v": "", + "cmd/compile/internal/ssa.Aux %q": "", + "cmd/compile/internal/ssa.Aux %s": "", "cmd/compile/internal/ssa.BranchPrediction %d": "", "cmd/compile/internal/ssa.ID %d": "", "cmd/compile/internal/ssa.LocalSlot %s": "", diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index add50c35d7..95650328b1 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -772,7 +772,7 @@ func (s *state) newValue0(op ssa.Op, t *types.Type) *ssa.Value { } // newValue0A adds a new value with no arguments and an aux value to the current block. -func (s *state) newValue0A(op ssa.Op, t *types.Type, aux interface{}) *ssa.Value { +func (s *state) newValue0A(op ssa.Op, t *types.Type, aux ssa.Aux) *ssa.Value { return s.curBlock.NewValue0A(s.peekPos(), op, t, aux) } @@ -787,14 +787,14 @@ func (s *state) newValue1(op ssa.Op, t *types.Type, arg *ssa.Value) *ssa.Value { } // newValue1A adds a new value with one argument and an aux value to the current block. -func (s *state) newValue1A(op ssa.Op, t *types.Type, aux interface{}, arg *ssa.Value) *ssa.Value { +func (s *state) newValue1A(op ssa.Op, t *types.Type, aux ssa.Aux, arg *ssa.Value) *ssa.Value { return s.curBlock.NewValue1A(s.peekPos(), op, t, aux, arg) } // newValue1Apos adds a new value with one argument and an aux value to the current block. // isStmt determines whether the created values may be a statement or not // (i.e., false means never, yes means maybe). -func (s *state) newValue1Apos(op ssa.Op, t *types.Type, aux interface{}, arg *ssa.Value, isStmt bool) *ssa.Value { +func (s *state) newValue1Apos(op ssa.Op, t *types.Type, aux ssa.Aux, arg *ssa.Value, isStmt bool) *ssa.Value { if isStmt { return s.curBlock.NewValue1A(s.peekPos(), op, t, aux, arg) } @@ -812,14 +812,14 @@ func (s *state) newValue2(op ssa.Op, t *types.Type, arg0, arg1 *ssa.Value) *ssa. } // newValue2A adds a new value with two arguments and an aux value to the current block. -func (s *state) newValue2A(op ssa.Op, t *types.Type, aux interface{}, arg0, arg1 *ssa.Value) *ssa.Value { +func (s *state) newValue2A(op ssa.Op, t *types.Type, aux ssa.Aux, arg0, arg1 *ssa.Value) *ssa.Value { return s.curBlock.NewValue2A(s.peekPos(), op, t, aux, arg0, arg1) } // newValue2Apos adds a new value with two arguments and an aux value to the current block. // isStmt determines whether the created values may be a statement or not // (i.e., false means never, yes means maybe). -func (s *state) newValue2Apos(op ssa.Op, t *types.Type, aux interface{}, arg0, arg1 *ssa.Value, isStmt bool) *ssa.Value { +func (s *state) newValue2Apos(op ssa.Op, t *types.Type, aux ssa.Aux, arg0, arg1 *ssa.Value, isStmt bool) *ssa.Value { if isStmt { return s.curBlock.NewValue2A(s.peekPos(), op, t, aux, arg0, arg1) } @@ -842,14 +842,14 @@ func (s *state) newValue3I(op ssa.Op, t *types.Type, aux int64, arg0, arg1, arg2 } // newValue3A adds a new value with three arguments and an aux value to the current block. -func (s *state) newValue3A(op ssa.Op, t *types.Type, aux interface{}, arg0, arg1, arg2 *ssa.Value) *ssa.Value { +func (s *state) newValue3A(op ssa.Op, t *types.Type, aux ssa.Aux, arg0, arg1, arg2 *ssa.Value) *ssa.Value { return s.curBlock.NewValue3A(s.peekPos(), op, t, aux, arg0, arg1, arg2) } // newValue3Apos adds a new value with three arguments and an aux value to the current block. // isStmt determines whether the created values may be a statement or not // (i.e., false means never, yes means maybe). -func (s *state) newValue3Apos(op ssa.Op, t *types.Type, aux interface{}, arg0, arg1, arg2 *ssa.Value, isStmt bool) *ssa.Value { +func (s *state) newValue3Apos(op ssa.Op, t *types.Type, aux ssa.Aux, arg0, arg1, arg2 *ssa.Value, isStmt bool) *ssa.Value { if isStmt { return s.curBlock.NewValue3A(s.peekPos(), op, t, aux, arg0, arg1, arg2) } @@ -872,7 +872,7 @@ func (s *state) entryNewValue0(op ssa.Op, t *types.Type) *ssa.Value { } // entryNewValue0A adds a new value with no arguments and an aux value to the entry block. -func (s *state) entryNewValue0A(op ssa.Op, t *types.Type, aux interface{}) *ssa.Value { +func (s *state) entryNewValue0A(op ssa.Op, t *types.Type, aux ssa.Aux) *ssa.Value { return s.f.Entry.NewValue0A(src.NoXPos, op, t, aux) } @@ -887,7 +887,7 @@ func (s *state) entryNewValue1I(op ssa.Op, t *types.Type, auxint int64, arg *ssa } // entryNewValue1A adds a new value with one argument and an aux value to the entry block. -func (s *state) entryNewValue1A(op ssa.Op, t *types.Type, aux interface{}, arg *ssa.Value) *ssa.Value { +func (s *state) entryNewValue1A(op ssa.Op, t *types.Type, aux ssa.Aux, arg *ssa.Value) *ssa.Value { return s.f.Entry.NewValue1A(src.NoXPos, op, t, aux, arg) } @@ -897,7 +897,7 @@ func (s *state) entryNewValue2(op ssa.Op, t *types.Type, arg0, arg1 *ssa.Value) } // entryNewValue2A adds a new value with two arguments and an aux value to the entry block. -func (s *state) entryNewValue2A(op ssa.Op, t *types.Type, aux interface{}, arg0, arg1 *ssa.Value) *ssa.Value { +func (s *state) entryNewValue2A(op ssa.Op, t *types.Type, aux ssa.Aux, arg0, arg1 *ssa.Value) *ssa.Value { return s.f.Entry.NewValue2A(src.NoXPos, op, t, aux, arg0, arg1) } @@ -2060,7 +2060,7 @@ func (s *state) expr(n ir.Node) *ssa.Value { if i == "" { return s.constEmptyString(n.Type()) } - return s.entryNewValue0A(ssa.OpConstString, n.Type(), i) + return s.entryNewValue0A(ssa.OpConstString, n.Type(), ssa.StringToAux(i)) case constant.Bool: return s.constBool(constant.BoolVal(u)) case constant.Float: diff --git a/src/cmd/compile/internal/ir/mini.go b/src/cmd/compile/internal/ir/mini.go index 612e7d62c3..edb3b197da 100644 --- a/src/cmd/compile/internal/ir/mini.go +++ b/src/cmd/compile/internal/ir/mini.go @@ -198,5 +198,6 @@ func (n *miniNode) MarkReadonly() { panic(n.no("MarkReadonly")) } func (n *miniNode) TChanDir() types.ChanDir { panic(n.no("TChanDir")) } func (n *miniNode) SetTChanDir(types.ChanDir) { panic(n.no("SetTChanDir")) } -// TODO: Delete when CanBeAnSSASym is removed from Node itself. +// TODO: Delete when these are removed from Node itself. func (*miniNode) CanBeAnSSASym() {} +func (*miniNode) CanBeAnSSAAux() {} diff --git a/src/cmd/compile/internal/ir/node.go b/src/cmd/compile/internal/ir/node.go index ba7eaae1b9..b878b00546 100644 --- a/src/cmd/compile/internal/ir/node.go +++ b/src/cmd/compile/internal/ir/node.go @@ -113,6 +113,7 @@ type Node interface { // Only for SSA and should be removed when SSA starts // using a more specific type than Node. CanBeAnSSASym() + CanBeAnSSAAux() } // Line returns n's position as a string. If n has been inlined, diff --git a/src/cmd/compile/internal/ssa/block.go b/src/cmd/compile/internal/ssa/block.go index 519ac214ca..937c757b21 100644 --- a/src/cmd/compile/internal/ssa/block.go +++ b/src/cmd/compile/internal/ssa/block.go @@ -52,7 +52,7 @@ type Block struct { Controls [2]*Value // Auxiliary info for the block. Its value depends on the Kind. - Aux interface{} + Aux Aux AuxInt int64 // The unordered set of Values that define the operation of this block. diff --git a/src/cmd/compile/internal/ssa/check.go b/src/cmd/compile/internal/ssa/check.go index 5f5dfc328a..4d57eef556 100644 --- a/src/cmd/compile/internal/ssa/check.go +++ b/src/cmd/compile/internal/ssa/check.go @@ -161,7 +161,7 @@ func checkFunc(f *Func) { f.Fatalf("value %v has an AuxInt that encodes a NaN", v) } case auxString: - if _, ok := v.Aux.(string); !ok { + if _, ok := v.Aux.(stringAux); !ok { f.Fatalf("value %v has Aux type %T, want string", v, v.Aux) } canHaveAux = true diff --git a/src/cmd/compile/internal/ssa/cse.go b/src/cmd/compile/internal/ssa/cse.go index 3b4f2be37e..f78527410c 100644 --- a/src/cmd/compile/internal/ssa/cse.go +++ b/src/cmd/compile/internal/ssa/cse.go @@ -275,7 +275,7 @@ func lt2Cmp(isLt bool) types.Cmp { return types.CMPgt } -type auxmap map[interface{}]int32 +type auxmap map[Aux]int32 func cmpVal(v, w *Value, auxIDs auxmap) types.Cmp { // Try to order these comparison by cost (cheaper first) diff --git a/src/cmd/compile/internal/ssa/cse_test.go b/src/cmd/compile/internal/ssa/cse_test.go index 9e76645f54..8052016f3a 100644 --- a/src/cmd/compile/internal/ssa/cse_test.go +++ b/src/cmd/compile/internal/ssa/cse_test.go @@ -14,6 +14,8 @@ type tstAux struct { s string } +func (*tstAux) CanBeAnSSAAux() {} + // This tests for a bug found when partitioning, but not sorting by the Aux value. func TestCSEAuxPartitionBug(t *testing.T) { c := testConfig(t) diff --git a/src/cmd/compile/internal/ssa/debug.go b/src/cmd/compile/internal/ssa/debug.go index 0d660361b1..44e91270fa 100644 --- a/src/cmd/compile/internal/ssa/debug.go +++ b/src/cmd/compile/internal/ssa/debug.go @@ -143,13 +143,13 @@ func (loc VarLoc) absent() bool { var BlockStart = &Value{ ID: -10000, Op: OpInvalid, - Aux: "BlockStart", + Aux: StringToAux("BlockStart"), } var BlockEnd = &Value{ ID: -20000, Op: OpInvalid, - Aux: "BlockEnd", + Aux: StringToAux("BlockEnd"), } // RegisterSet is a bitmap of registers, indexed by Register.num. diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go index e6f899a2c7..e6c4798a78 100644 --- a/src/cmd/compile/internal/ssa/func.go +++ b/src/cmd/compile/internal/ssa/func.go @@ -377,13 +377,7 @@ func (b *Block) NewValue0I(pos src.XPos, op Op, t *types.Type, auxint int64) *Va } // NewValue returns a new value in the block with no arguments and an aux value. -func (b *Block) NewValue0A(pos src.XPos, op Op, t *types.Type, aux interface{}) *Value { - if _, ok := aux.(int64); ok { - // Disallow int64 aux values. They should be in the auxint field instead. - // Maybe we want to allow this at some point, but for now we disallow it - // to prevent errors like using NewValue1A instead of NewValue1I. - b.Fatalf("aux field has int64 type op=%s type=%s aux=%v", op, t, aux) - } +func (b *Block) NewValue0A(pos src.XPos, op Op, t *types.Type, aux Aux) *Value { v := b.Func.newValue(op, t, b, pos) v.AuxInt = 0 v.Aux = aux @@ -392,7 +386,7 @@ func (b *Block) NewValue0A(pos src.XPos, op Op, t *types.Type, aux interface{}) } // NewValue returns a new value in the block with no arguments and both an auxint and aux values. -func (b *Block) NewValue0IA(pos src.XPos, op Op, t *types.Type, auxint int64, aux interface{}) *Value { +func (b *Block) NewValue0IA(pos src.XPos, op Op, t *types.Type, auxint int64, aux Aux) *Value { v := b.Func.newValue(op, t, b, pos) v.AuxInt = auxint v.Aux = aux @@ -421,7 +415,7 @@ func (b *Block) NewValue1I(pos src.XPos, op Op, t *types.Type, auxint int64, arg } // NewValue1A returns a new value in the block with one argument and an aux value. -func (b *Block) NewValue1A(pos src.XPos, op Op, t *types.Type, aux interface{}, arg *Value) *Value { +func (b *Block) NewValue1A(pos src.XPos, op Op, t *types.Type, aux Aux, arg *Value) *Value { v := b.Func.newValue(op, t, b, pos) v.AuxInt = 0 v.Aux = aux @@ -432,7 +426,7 @@ func (b *Block) NewValue1A(pos src.XPos, op Op, t *types.Type, aux interface{}, } // NewValue1IA returns a new value in the block with one argument and both an auxint and aux values. -func (b *Block) NewValue1IA(pos src.XPos, op Op, t *types.Type, auxint int64, aux interface{}, arg *Value) *Value { +func (b *Block) NewValue1IA(pos src.XPos, op Op, t *types.Type, auxint int64, aux Aux, arg *Value) *Value { v := b.Func.newValue(op, t, b, pos) v.AuxInt = auxint v.Aux = aux @@ -455,7 +449,7 @@ func (b *Block) NewValue2(pos src.XPos, op Op, t *types.Type, arg0, arg1 *Value) } // NewValue2A returns a new value in the block with two arguments and one aux values. -func (b *Block) NewValue2A(pos src.XPos, op Op, t *types.Type, aux interface{}, arg0, arg1 *Value) *Value { +func (b *Block) NewValue2A(pos src.XPos, op Op, t *types.Type, aux Aux, arg0, arg1 *Value) *Value { v := b.Func.newValue(op, t, b, pos) v.AuxInt = 0 v.Aux = aux @@ -480,7 +474,7 @@ func (b *Block) NewValue2I(pos src.XPos, op Op, t *types.Type, auxint int64, arg } // NewValue2IA returns a new value in the block with two arguments and both an auxint and aux values. -func (b *Block) NewValue2IA(pos src.XPos, op Op, t *types.Type, auxint int64, aux interface{}, arg0, arg1 *Value) *Value { +func (b *Block) NewValue2IA(pos src.XPos, op Op, t *types.Type, auxint int64, aux Aux, arg0, arg1 *Value) *Value { v := b.Func.newValue(op, t, b, pos) v.AuxInt = auxint v.Aux = aux @@ -521,7 +515,7 @@ func (b *Block) NewValue3I(pos src.XPos, op Op, t *types.Type, auxint int64, arg } // NewValue3A returns a new value in the block with three argument and an aux value. -func (b *Block) NewValue3A(pos src.XPos, op Op, t *types.Type, aux interface{}, arg0, arg1, arg2 *Value) *Value { +func (b *Block) NewValue3A(pos src.XPos, op Op, t *types.Type, aux Aux, arg0, arg1, arg2 *Value) *Value { v := b.Func.newValue(op, t, b, pos) v.AuxInt = 0 v.Aux = aux @@ -633,7 +627,7 @@ func (f *Func) ConstNil(t *types.Type) *Value { } func (f *Func) ConstEmptyString(t *types.Type) *Value { v := f.constVal(OpConstString, t, constEmptyStringMagic, false) - v.Aux = "" + v.Aux = StringToAux("") return v } func (f *Func) ConstOffPtrSP(t *types.Type, c int64, sp *Value) *Value { diff --git a/src/cmd/compile/internal/ssa/func_test.go b/src/cmd/compile/internal/ssa/func_test.go index 568c6436f5..276c444b9a 100644 --- a/src/cmd/compile/internal/ssa/func_test.go +++ b/src/cmd/compile/internal/ssa/func_test.go @@ -232,7 +232,7 @@ func Bloc(name string, entries ...interface{}) bloc { } // Valu defines a value in a block. -func Valu(name string, op Op, t *types.Type, auxint int64, aux interface{}, args ...string) valu { +func Valu(name string, op Op, t *types.Type, auxint int64, aux Aux, args ...string) valu { return valu{name, op, t, auxint, aux, args} } @@ -277,7 +277,7 @@ type valu struct { op Op t *types.Type auxint int64 - aux interface{} + aux Aux args []string } @@ -402,12 +402,12 @@ func TestEquiv(t *testing.T) { cfg.Fun("entry", Bloc("entry", Valu("mem", OpInitMem, types.TypeMem, 0, nil), - Valu("a", OpConst64, cfg.config.Types.Int64, 0, 14), + Valu("a", OpConstString, cfg.config.Types.String, 0, StringToAux("foo")), Exit("mem"))), cfg.Fun("entry", Bloc("entry", Valu("mem", OpInitMem, types.TypeMem, 0, nil), - Valu("a", OpConst64, cfg.config.Types.Int64, 0, 26), + Valu("a", OpConstString, cfg.config.Types.String, 0, StringToAux("bar")), Exit("mem"))), }, // value args different diff --git a/src/cmd/compile/internal/ssa/nilcheck_test.go b/src/cmd/compile/internal/ssa/nilcheck_test.go index 16d94614d8..2e32afe2a6 100644 --- a/src/cmd/compile/internal/ssa/nilcheck_test.go +++ b/src/cmd/compile/internal/ssa/nilcheck_test.go @@ -212,7 +212,7 @@ func TestNilcheckPhi(t *testing.T) { Valu("mem", OpInitMem, types.TypeMem, 0, nil), Valu("sb", OpSB, c.config.Types.Uintptr, 0, nil), Valu("sp", OpSP, c.config.Types.Uintptr, 0, nil), - Valu("baddr", OpLocalAddr, c.config.Types.Bool, 0, "b", "sp", "mem"), + Valu("baddr", OpLocalAddr, c.config.Types.Bool, 0, StringToAux("b"), "sp", "mem"), Valu("bool1", OpLoad, c.config.Types.Bool, 0, nil, "baddr", "mem"), If("bool1", "b1", "b2")), Bloc("b1", diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go index 6f029a421e..97726a6f95 100644 --- a/src/cmd/compile/internal/ssa/op.go +++ b/src/cmd/compile/internal/ssa/op.go @@ -197,6 +197,8 @@ func ClosureAuxCall(args []Param, results []Param) *AuxCall { return &AuxCall{Fn: nil, args: args, results: results} } +func (*AuxCall) CanBeAnSSAAux() {} + const ( auxNone auxType = iota auxBool // auxInt is 0/1 for false/true @@ -248,6 +250,7 @@ const ( type Sym interface { String() string CanBeAnSSASym() + CanBeAnSSAAux() } // A ValAndOff is used by the several opcodes. It holds diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index 24efd38fb7..9abfe0938b 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -678,43 +678,53 @@ func opToAuxInt(o Op) int64 { return int64(o) } -func auxToString(i interface{}) string { - return i.(string) +// Aux is an interface to hold miscellaneous data in Blocks and Values. +type Aux interface { + CanBeAnSSAAux() } -func auxToSym(i interface{}) Sym { + +// stringAux wraps string values for use in Aux. +type stringAux string + +func (stringAux) CanBeAnSSAAux() {} + +func auxToString(i Aux) string { + return string(i.(stringAux)) +} +func auxToSym(i Aux) Sym { // TODO: kind of a hack - allows nil interface through s, _ := i.(Sym) return s } -func auxToType(i interface{}) *types.Type { +func auxToType(i Aux) *types.Type { return i.(*types.Type) } -func auxToCall(i interface{}) *AuxCall { +func auxToCall(i Aux) *AuxCall { return i.(*AuxCall) } -func auxToS390xCCMask(i interface{}) s390x.CCMask { +func auxToS390xCCMask(i Aux) s390x.CCMask { return i.(s390x.CCMask) } -func auxToS390xRotateParams(i interface{}) s390x.RotateParams { +func auxToS390xRotateParams(i Aux) s390x.RotateParams { return i.(s390x.RotateParams) } -func stringToAux(s string) interface{} { - return s +func StringToAux(s string) Aux { + return stringAux(s) } -func symToAux(s Sym) interface{} { +func symToAux(s Sym) Aux { return s } -func callToAux(s *AuxCall) interface{} { +func callToAux(s *AuxCall) Aux { return s } -func typeToAux(t *types.Type) interface{} { +func typeToAux(t *types.Type) Aux { return t } -func s390xCCMaskToAux(c s390x.CCMask) interface{} { +func s390xCCMaskToAux(c s390x.CCMask) Aux { return c } -func s390xRotateParamsToAux(r s390x.RotateParams) interface{} { +func s390xRotateParamsToAux(r s390x.RotateParams) Aux { return r } @@ -725,7 +735,7 @@ func uaddOvf(a, b int64) bool { // de-virtualize an InterCall // 'sym' is the symbol for the itab -func devirt(v *Value, aux interface{}, sym Sym, offset int64) *AuxCall { +func devirt(v *Value, aux Aux, sym Sym, offset int64) *AuxCall { f := v.Block.Func n, ok := sym.(*obj.LSym) if !ok { @@ -748,7 +758,7 @@ func devirt(v *Value, aux interface{}, sym Sym, offset int64) *AuxCall { // de-virtualize an InterLECall // 'sym' is the symbol for the itab -func devirtLESym(v *Value, aux interface{}, sym Sym, offset int64) *obj.LSym { +func devirtLESym(v *Value, aux Aux, sym Sym, offset int64) *obj.LSym { n, ok := sym.(*obj.LSym) if !ok { return nil diff --git a/src/cmd/compile/internal/ssa/value.go b/src/cmd/compile/internal/ssa/value.go index edc43aaae7..993c5a580f 100644 --- a/src/cmd/compile/internal/ssa/value.go +++ b/src/cmd/compile/internal/ssa/value.go @@ -36,7 +36,7 @@ type Value struct { // Users of AuxInt which interpret AuxInt as unsigned (e.g. shifts) must be careful. // Use Value.AuxUnsigned to get the zero-extended value of AuxInt. AuxInt int64 - Aux interface{} + Aux Aux // Arguments of this value Args []*Value @@ -492,3 +492,6 @@ func (v *Value) removeable() bool { } return true } + +// TODO(mdempsky): Shouldn't be necessary; see discussion at golang.org/cl/275756 +func (*Value) CanBeAnSSAAux() {} diff --git a/src/cmd/compile/internal/ssa/zcse.go b/src/cmd/compile/internal/ssa/zcse.go index ec38b7d1ba..e08272c345 100644 --- a/src/cmd/compile/internal/ssa/zcse.go +++ b/src/cmd/compile/internal/ssa/zcse.go @@ -57,7 +57,7 @@ func zcse(f *Func) { type vkey struct { op Op ai int64 // aux int - ax interface{} // aux + ax Aux // aux t *types.Type // type } diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go index c5807af199..e968a799e3 100644 --- a/src/cmd/compile/internal/types/type.go +++ b/src/cmd/compile/internal/types/type.go @@ -164,6 +164,8 @@ type Type struct { flags bitset8 } +func (*Type) CanBeAnSSAAux() {} + const ( typeNotInHeap = 1 << iota // type cannot be heap allocated typeBroke // broken type definition diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go index 8c8ff587ff..eaebfaf4b6 100644 --- a/src/cmd/internal/obj/link.go +++ b/src/cmd/internal/obj/link.go @@ -723,8 +723,8 @@ func (s *LSym) String() string { } // The compiler needs *LSym to be assignable to cmd/compile/internal/ssa.Sym. -func (s *LSym) CanBeAnSSASym() { -} +func (*LSym) CanBeAnSSASym() {} +func (*LSym) CanBeAnSSAAux() {} type Pcln struct { // Aux symbols for pcln diff --git a/src/cmd/internal/obj/s390x/condition_code.go b/src/cmd/internal/obj/s390x/condition_code.go index 764fc5bc6a..f498fd6f77 100644 --- a/src/cmd/internal/obj/s390x/condition_code.go +++ b/src/cmd/internal/obj/s390x/condition_code.go @@ -124,3 +124,5 @@ func (c CCMask) String() string { // invalid return fmt.Sprintf("Invalid (%#x)", c) } + +func (CCMask) CanBeAnSSAAux() {} diff --git a/src/cmd/internal/obj/s390x/rotate.go b/src/cmd/internal/obj/s390x/rotate.go index 7dbc45e648..c999880492 100644 --- a/src/cmd/internal/obj/s390x/rotate.go +++ b/src/cmd/internal/obj/s390x/rotate.go @@ -113,3 +113,5 @@ func (r RotateParams) OutMerge(mask uint64) *RotateParams { func (r RotateParams) InMerge(mask uint64) *RotateParams { return r.OutMerge(bits.RotateLeft64(mask, int(r.Amount))) } + +func (RotateParams) CanBeAnSSAAux() {} -- cgit v1.3-5-g9baa From 6a64f6dc31b3038187ce9246bdf438be9cc94bae Mon Sep 17 00:00:00 2001 From: Jeremy Faller Date: Tue, 24 Nov 2020 12:58:21 -0500 Subject: cmd/go: encode backslash and newline in response files Fixes #42295 Change-Id: Ie324bc99a74c1d864c6c2da2e7b929b338c2e033 Reviewed-on: https://go-review.googlesource.com/c/go/+/272870 Trust: Jeremy Faller Run-TryBot: Jeremy Faller TryBot-Result: Go Bot Reviewed-by: Austin Clements Reviewed-by: Bryan C. Mills --- src/cmd/go/go_test.go | 25 ++++++++++ src/cmd/go/internal/work/exec.go | 36 ++++++++++++--- src/cmd/go/internal/work/exec_test.go | 86 +++++++++++++++++++++++++++++++++++ src/cmd/internal/objabi/flag.go | 39 ++++++++++++++++ src/cmd/internal/objabi/flag_test.go | 26 +++++++++++ 5 files changed, 206 insertions(+), 6 deletions(-) create mode 100644 src/cmd/go/internal/work/exec_test.go create mode 100644 src/cmd/internal/objabi/flag_test.go (limited to 'src/cmd/internal') diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index 19764bfc60..c472620db2 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -31,6 +31,7 @@ import ( "cmd/go/internal/cache" "cmd/go/internal/cfg" "cmd/go/internal/robustio" + "cmd/go/internal/work" "cmd/internal/sys" ) @@ -1365,6 +1366,30 @@ func TestLdflagsArgumentsWithSpacesIssue3941(t *testing.T) { tg.grepStderr("^hello world", `ldflags -X "main.extern=hello world"' failed`) } +func TestLdFlagsLongArgumentsIssue42295(t *testing.T) { + // Test the extremely long command line arguments that contain '\n' characters + // get encoded and passed correctly. + skipIfGccgo(t, "gccgo does not support -ldflags -X") + tooSlow(t) + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempFile("main.go", `package main + var extern string + func main() { + print(extern) + }`) + testStr := "test test test test test \n\\ " + var buf bytes.Buffer + for buf.Len() < work.ArgLengthForResponseFile+1 { + buf.WriteString(testStr) + } + tg.run("run", "-ldflags", fmt.Sprintf(`-X "main.extern=%s"`, buf.String()), tg.path("main.go")) + if tg.stderr.String() != buf.String() { + t.Errorf("strings differ") + } +} + func TestGoTestDashCDashOControlsBinaryLocation(t *testing.T) { skipIfGccgo(t, "gccgo has no standard packages") tooSlow(t) diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index 336751df27..feb2299d40 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -3236,7 +3236,7 @@ func passLongArgsInResponseFiles(cmd *exec.Cmd) (cleanup func()) { cleanup = func() { os.Remove(tf.Name()) } var buf bytes.Buffer for _, arg := range cmd.Args[1:] { - fmt.Fprintf(&buf, "%s\n", arg) + fmt.Fprintf(&buf, "%s\n", encodeArg(arg)) } if _, err := tf.Write(buf.Bytes()); err != nil { tf.Close() @@ -3251,6 +3251,12 @@ func passLongArgsInResponseFiles(cmd *exec.Cmd) (cleanup func()) { return cleanup } +// Windows has a limit of 32 KB arguments. To be conservative and not worry +// about whether that includes spaces or not, just use 30 KB. Darwin's limit is +// less clear. The OS claims 256KB, but we've seen failures with arglen as +// small as 50KB. +const ArgLengthForResponseFile = (30 << 10) + func useResponseFile(path string, argLen int) bool { // Unless the program uses objabi.Flagparse, which understands // response files, don't use response files. @@ -3262,11 +3268,7 @@ func useResponseFile(path string, argLen int) bool { return false } - // Windows has a limit of 32 KB arguments. To be conservative and not - // worry about whether that includes spaces or not, just use 30 KB. - // Darwin's limit is less clear. The OS claims 256KB, but we've seen - // failures with arglen as small as 50KB. - if argLen > (30 << 10) { + if argLen > ArgLengthForResponseFile { return true } @@ -3279,3 +3281,25 @@ func useResponseFile(path string, argLen int) bool { return false } + +// encodeArg encodes an argument for response file writing. +func encodeArg(arg string) string { + // If there aren't any characters we need to reencode, fastpath out. + if !strings.ContainsAny(arg, "\\\n") { + return arg + } + var b strings.Builder + for _, r := range arg { + switch r { + case '\\': + b.WriteByte('\\') + b.WriteByte('\\') + case '\n': + b.WriteByte('\\') + b.WriteByte('n') + default: + b.WriteRune(r) + } + } + return b.String() +} diff --git a/src/cmd/go/internal/work/exec_test.go b/src/cmd/go/internal/work/exec_test.go new file mode 100644 index 0000000000..4eb762cb28 --- /dev/null +++ b/src/cmd/go/internal/work/exec_test.go @@ -0,0 +1,86 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package work + +import ( + "bytes" + "cmd/internal/objabi" + "fmt" + "math/rand" + "testing" + "time" + "unicode/utf8" +) + +func TestEncodeArgs(t *testing.T) { + t.Parallel() + tests := []struct { + arg, want string + }{ + {"", ""}, + {"hello", "hello"}, + {"hello\n", "hello\\n"}, + {"hello\\", "hello\\\\"}, + {"hello\nthere", "hello\\nthere"}, + {"\\\n", "\\\\\\n"}, + } + for _, test := range tests { + if got := encodeArg(test.arg); got != test.want { + t.Errorf("encodeArg(%q) = %q, want %q", test.arg, got, test.want) + } + } +} + +func TestEncodeDecode(t *testing.T) { + t.Parallel() + tests := []string{ + "", + "hello", + "hello\\there", + "hello\nthere", + "hello 中国", + "hello \n中\\国", + } + for _, arg := range tests { + if got := objabi.DecodeArg(encodeArg(arg)); got != arg { + t.Errorf("objabi.DecodeArg(encodeArg(%q)) = %q", arg, got) + } + } +} + +func TestEncodeDecodeFuzz(t *testing.T) { + if testing.Short() { + t.Skip("fuzz test is slow") + } + t.Parallel() + + nRunes := ArgLengthForResponseFile + 100 + rBuffer := make([]rune, nRunes) + buf := bytes.NewBuffer([]byte(string(rBuffer))) + + seed := time.Now().UnixNano() + t.Logf("rand seed: %v", seed) + rng := rand.New(rand.NewSource(seed)) + + for i := 0; i < 50; i++ { + // Generate a random string of runes. + buf.Reset() + for buf.Len() < ArgLengthForResponseFile+1 { + var r rune + for { + r = rune(rng.Intn(utf8.MaxRune + 1)) + if utf8.ValidRune(r) { + break + } + } + fmt.Fprintf(buf, "%c", r) + } + arg := buf.String() + + if got := objabi.DecodeArg(encodeArg(arg)); got != arg { + t.Errorf("[%d] objabi.DecodeArg(encodeArg(%q)) = %q [seed: %v]", i, arg, got, seed) + } + } +} diff --git a/src/cmd/internal/objabi/flag.go b/src/cmd/internal/objabi/flag.go index 79ad2ccf74..3fd73f3c57 100644 --- a/src/cmd/internal/objabi/flag.go +++ b/src/cmd/internal/objabi/flag.go @@ -5,6 +5,7 @@ package objabi import ( + "bytes" "flag" "fmt" "io" @@ -59,6 +60,9 @@ func expandArgs(in []string) (out []string) { log.Fatal(err) } args := strings.Split(strings.TrimSpace(strings.Replace(string(slurp), "\r", "", -1)), "\n") + for i, arg := range args { + args[i] = DecodeArg(arg) + } out = append(out, expandArgs(args)...) } else if out != nil { out = append(out, s) @@ -160,3 +164,38 @@ func (f fn1) Set(s string) error { } func (f fn1) String() string { return "" } + +// DecodeArg decodes an argument. +// +// This function is public for testing with the parallel encoder. +func DecodeArg(arg string) string { + // If no encoding, fastpath out. + if !strings.ContainsAny(arg, "\\\n") { + return arg + } + + // We can't use strings.Builder as this must work at bootstrap. + var b bytes.Buffer + var wasBS bool + for _, r := range arg { + if wasBS { + switch r { + case '\\': + b.WriteByte('\\') + case 'n': + b.WriteByte('\n') + default: + // This shouldn't happen. The only backslashes that reach here + // should encode '\n' and '\\' exclusively. + panic("badly formatted input") + } + } else if r == '\\' { + wasBS = true + continue + } else { + b.WriteRune(r) + } + wasBS = false + } + return b.String() +} diff --git a/src/cmd/internal/objabi/flag_test.go b/src/cmd/internal/objabi/flag_test.go new file mode 100644 index 0000000000..935b9c2193 --- /dev/null +++ b/src/cmd/internal/objabi/flag_test.go @@ -0,0 +1,26 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package objabi + +import "testing" + +func TestDecodeArg(t *testing.T) { + t.Parallel() + tests := []struct { + arg, want string + }{ + {"", ""}, + {"hello", "hello"}, + {"hello\\n", "hello\n"}, + {"hello\\nthere", "hello\nthere"}, + {"hello\\\\there", "hello\\there"}, + {"\\\\\\n", "\\\n"}, + } + for _, test := range tests { + if got := DecodeArg(test.arg); got != test.want { + t.Errorf("decodoeArg(%q) = %q, want %q", test.arg, got, test.want) + } + } +} -- cgit v1.3-5-g9baa From a58be734eacd832be27a021b8ffac323061212f2 Mon Sep 17 00:00:00 2001 From: Ruixin Bao Date: Wed, 9 Dec 2020 13:55:37 -0800 Subject: cmd/compile: fix incorrect shift count type with s390x rules The type of the shift count must be an unsigned integer. Some s390x rules for shift have their auxint type being int8. This results in a compilation failure on s390x with an invalid operation when running make.bash using older versions of go (e.g: go1.10.4). This CL adds an auxint type of uint8 and changes the ops for shift and rotate to use auxint with type uint8. The related rules are also modified to address this change. Fixes #43090 Change-Id: I594274b6e3d9b23092fc9e9f4b354870164f2f19 Reviewed-on: https://go-review.googlesource.com/c/go/+/277078 Reviewed-by: Keith Randall Trust: Dmitri Shuralyov --- src/cmd/compile/internal/ssa/check.go | 5 + src/cmd/compile/internal/ssa/gen/S390X.rules | 24 +-- src/cmd/compile/internal/ssa/gen/S390XOps.go | 30 +-- src/cmd/compile/internal/ssa/gen/rulegen.go | 4 +- src/cmd/compile/internal/ssa/op.go | 1 + src/cmd/compile/internal/ssa/opGen.go | 14 +- src/cmd/compile/internal/ssa/rewriteS390X.go | 290 +++++++++++++-------------- src/cmd/internal/obj/s390x/rotate.go | 14 +- src/cmd/internal/obj/s390x/rotate_test.go | 2 +- 9 files changed, 196 insertions(+), 188 deletions(-) (limited to 'src/cmd/internal') diff --git a/src/cmd/compile/internal/ssa/check.go b/src/cmd/compile/internal/ssa/check.go index 5f5dfc328a..2dade7a88d 100644 --- a/src/cmd/compile/internal/ssa/check.go +++ b/src/cmd/compile/internal/ssa/check.go @@ -147,6 +147,11 @@ func checkFunc(f *Func) { canHaveAuxInt = true case auxInt128: // AuxInt must be zero, so leave canHaveAuxInt set to false. + case auxUInt8: + if v.AuxInt != int64(uint8(v.AuxInt)) { + f.Fatalf("bad uint8 AuxInt value for %v", v) + } + canHaveAuxInt = true case auxFloat32: canHaveAuxInt = true if math.IsNaN(v.AuxFloat()) { diff --git a/src/cmd/compile/internal/ssa/gen/S390X.rules b/src/cmd/compile/internal/ssa/gen/S390X.rules index 39949edbc2..384f2e807e 100644 --- a/src/cmd/compile/internal/ssa/gen/S390X.rules +++ b/src/cmd/compile/internal/ssa/gen/S390X.rules @@ -663,8 +663,8 @@ ((OR|XOR)W x (MOVDconst [c])) => ((OR|XOR)Wconst [int32(c)] x) // Constant shifts. -(S(LD|RD|RAD) x (MOVDconst [c])) => (S(LD|RD|RAD)const x [int8(c&63)]) -(S(LW|RW|RAW) x (MOVDconst [c])) && c&32 == 0 => (S(LW|RW|RAW)const x [int8(c&31)]) +(S(LD|RD|RAD) x (MOVDconst [c])) => (S(LD|RD|RAD)const x [uint8(c&63)]) +(S(LW|RW|RAW) x (MOVDconst [c])) && c&32 == 0 => (S(LW|RW|RAW)const x [uint8(c&31)]) (S(LW|RW) _ (MOVDconst [c])) && c&32 != 0 => (MOVDconst [0]) (SRAW x (MOVDconst [c])) && c&32 != 0 => (SRAWconst x [31]) @@ -685,8 +685,8 @@ (SRAW x (MOV(W|H|B|WZ|HZ|BZ)reg y)) => (SRAW x y) // Match rotate by constant. -(RLLG x (MOVDconst [c])) => (RISBGZ x {s390x.NewRotateParams(0, 63, int8(c&63))}) -(RLL x (MOVDconst [c])) => (RLLconst x [int8(c&31)]) +(RLLG x (MOVDconst [c])) => (RISBGZ x {s390x.NewRotateParams(0, 63, uint8(c&63))}) +(RLL x (MOVDconst [c])) => (RLLconst x [uint8(c&31)]) // Match rotate by constant pattern. ((ADD|OR|XOR) (SLDconst x [c]) (SRDconst x [64-c])) => (RISBGZ x {s390x.NewRotateParams(0, 63, c)}) @@ -705,10 +705,10 @@ (CMP(W|WU) (MOVDconst [c]) x) => (InvertFlags (CMP(W|WU)const x [int32(c)])) // Match (x >> c) << d to 'rotate then insert selected bits [into zero]'. -(SLDconst (SRDconst x [c]) [d]) => (RISBGZ x {s390x.NewRotateParams(max8(0, c-d), 63-d, (d-c)&63)}) +(SLDconst (SRDconst x [c]) [d]) => (RISBGZ x {s390x.NewRotateParams(uint8(max8(0, int8(c-d))), 63-d, uint8(int8(d-c)&63))}) // Match (x << c) >> d to 'rotate then insert selected bits [into zero]'. -(SRDconst (SLDconst x [c]) [d]) => (RISBGZ x {s390x.NewRotateParams(d, min8(63, 63-c+d), (c-d)&63)}) +(SRDconst (SLDconst x [c]) [d]) => (RISBGZ x {s390x.NewRotateParams(d, uint8(min8(63, int8(63-c+d))), uint8(int8(c-d)&63))}) // Absorb input zero extension into 'rotate then insert selected bits [into zero]'. (RISBGZ (MOVWZreg x) {r}) && r.InMerge(0xffffffff) != nil => (RISBGZ x {*r.InMerge(0xffffffff)}) @@ -818,18 +818,18 @@ // c = 2ˣ + 2ʸ => c - 2ˣ = 2ʸ (MULL(D|W)const x [c]) && isPowerOfTwo32(c&(c-1)) - => ((ADD|ADDW) (SL(D|W)const x [int8(log32(c&(c-1)))]) - (SL(D|W)const x [int8(log32(c&^(c-1)))])) + => ((ADD|ADDW) (SL(D|W)const x [uint8(log32(c&(c-1)))]) + (SL(D|W)const x [uint8(log32(c&^(c-1)))])) // c = 2ʸ - 2ˣ => c + 2ˣ = 2ʸ (MULL(D|W)const x [c]) && isPowerOfTwo32(c+(c&^(c-1))) - => ((SUB|SUBW) (SL(D|W)const x [int8(log32(c+(c&^(c-1))))]) - (SL(D|W)const x [int8(log32(c&^(c-1)))])) + => ((SUB|SUBW) (SL(D|W)const x [uint8(log32(c+(c&^(c-1))))]) + (SL(D|W)const x [uint8(log32(c&^(c-1)))])) // c = 2ˣ - 2ʸ => -c + 2ˣ = 2ʸ (MULL(D|W)const x [c]) && isPowerOfTwo32(-c+(-c&^(-c-1))) - => ((SUB|SUBW) (SL(D|W)const x [int8(log32(-c&^(-c-1)))]) - (SL(D|W)const x [int8(log32(-c+(-c&^(-c-1))))])) + => ((SUB|SUBW) (SL(D|W)const x [uint8(log32(-c&^(-c-1)))]) + (SL(D|W)const x [uint8(log32(-c+(-c&^(-c-1))))])) // Fold ADD into MOVDaddr. Odd offsets from SB shouldn't be folded (LARL can't handle them). (ADDconst [c] (MOVDaddr [d] {s} x:(SB))) && ((c+d)&1 == 0) && is32Bit(int64(c)+int64(d)) => (MOVDaddr [c+d] {s} x) diff --git a/src/cmd/compile/internal/ssa/gen/S390XOps.go b/src/cmd/compile/internal/ssa/gen/S390XOps.go index f0cf2f2f6e..b24fd61942 100644 --- a/src/cmd/compile/internal/ssa/gen/S390XOps.go +++ b/src/cmd/compile/internal/ssa/gen/S390XOps.go @@ -330,27 +330,27 @@ func init() { {name: "LTDBR", argLength: 1, reg: fp1flags, asm: "LTDBR", typ: "Flags"}, // arg0 compare to 0, f64 {name: "LTEBR", argLength: 1, reg: fp1flags, asm: "LTEBR", typ: "Flags"}, // arg0 compare to 0, f32 - {name: "SLD", argLength: 2, reg: sh21, asm: "SLD"}, // arg0 << arg1, shift amount is mod 64 - {name: "SLW", argLength: 2, reg: sh21, asm: "SLW"}, // arg0 << arg1, shift amount is mod 64 - {name: "SLDconst", argLength: 1, reg: gp11, asm: "SLD", aux: "Int8"}, // arg0 << auxint, shift amount 0-63 - {name: "SLWconst", argLength: 1, reg: gp11, asm: "SLW", aux: "Int8"}, // arg0 << auxint, shift amount 0-31 + {name: "SLD", argLength: 2, reg: sh21, asm: "SLD"}, // arg0 << arg1, shift amount is mod 64 + {name: "SLW", argLength: 2, reg: sh21, asm: "SLW"}, // arg0 << arg1, shift amount is mod 64 + {name: "SLDconst", argLength: 1, reg: gp11, asm: "SLD", aux: "UInt8"}, // arg0 << auxint, shift amount 0-63 + {name: "SLWconst", argLength: 1, reg: gp11, asm: "SLW", aux: "UInt8"}, // arg0 << auxint, shift amount 0-31 - {name: "SRD", argLength: 2, reg: sh21, asm: "SRD"}, // unsigned arg0 >> arg1, shift amount is mod 64 - {name: "SRW", argLength: 2, reg: sh21, asm: "SRW"}, // unsigned uint32(arg0) >> arg1, shift amount is mod 64 - {name: "SRDconst", argLength: 1, reg: gp11, asm: "SRD", aux: "Int8"}, // unsigned arg0 >> auxint, shift amount 0-63 - {name: "SRWconst", argLength: 1, reg: gp11, asm: "SRW", aux: "Int8"}, // unsigned uint32(arg0) >> auxint, shift amount 0-31 + {name: "SRD", argLength: 2, reg: sh21, asm: "SRD"}, // unsigned arg0 >> arg1, shift amount is mod 64 + {name: "SRW", argLength: 2, reg: sh21, asm: "SRW"}, // unsigned uint32(arg0) >> arg1, shift amount is mod 64 + {name: "SRDconst", argLength: 1, reg: gp11, asm: "SRD", aux: "UInt8"}, // unsigned arg0 >> auxint, shift amount 0-63 + {name: "SRWconst", argLength: 1, reg: gp11, asm: "SRW", aux: "UInt8"}, // unsigned uint32(arg0) >> auxint, shift amount 0-31 // Arithmetic shifts clobber flags. - {name: "SRAD", argLength: 2, reg: sh21, asm: "SRAD", clobberFlags: true}, // signed arg0 >> arg1, shift amount is mod 64 - {name: "SRAW", argLength: 2, reg: sh21, asm: "SRAW", clobberFlags: true}, // signed int32(arg0) >> arg1, shift amount is mod 64 - {name: "SRADconst", argLength: 1, reg: gp11, asm: "SRAD", aux: "Int8", clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-63 - {name: "SRAWconst", argLength: 1, reg: gp11, asm: "SRAW", aux: "Int8", clobberFlags: true}, // signed int32(arg0) >> auxint, shift amount 0-31 + {name: "SRAD", argLength: 2, reg: sh21, asm: "SRAD", clobberFlags: true}, // signed arg0 >> arg1, shift amount is mod 64 + {name: "SRAW", argLength: 2, reg: sh21, asm: "SRAW", clobberFlags: true}, // signed int32(arg0) >> arg1, shift amount is mod 64 + {name: "SRADconst", argLength: 1, reg: gp11, asm: "SRAD", aux: "UInt8", clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-63 + {name: "SRAWconst", argLength: 1, reg: gp11, asm: "SRAW", aux: "UInt8", clobberFlags: true}, // signed int32(arg0) >> auxint, shift amount 0-31 // Rotate instructions. // Note: no RLLGconst - use RISBGZ instead. - {name: "RLLG", argLength: 2, reg: sh21, asm: "RLLG"}, // arg0 rotate left arg1, rotate amount 0-63 - {name: "RLL", argLength: 2, reg: sh21, asm: "RLL"}, // arg0 rotate left arg1, rotate amount 0-31 - {name: "RLLconst", argLength: 1, reg: gp11, asm: "RLL", aux: "Int8"}, // arg0 rotate left auxint, rotate amount 0-31 + {name: "RLLG", argLength: 2, reg: sh21, asm: "RLLG"}, // arg0 rotate left arg1, rotate amount 0-63 + {name: "RLL", argLength: 2, reg: sh21, asm: "RLL"}, // arg0 rotate left arg1, rotate amount 0-31 + {name: "RLLconst", argLength: 1, reg: gp11, asm: "RLL", aux: "UInt8"}, // arg0 rotate left auxint, rotate amount 0-31 // Rotate then (and|or|xor|insert) selected bits instructions. // diff --git a/src/cmd/compile/internal/ssa/gen/rulegen.go b/src/cmd/compile/internal/ssa/gen/rulegen.go index 120ccbbdb3..aaf9101368 100644 --- a/src/cmd/compile/internal/ssa/gen/rulegen.go +++ b/src/cmd/compile/internal/ssa/gen/rulegen.go @@ -1395,7 +1395,7 @@ func parseValue(val string, arch arch, loc string) (op opData, oparch, typ, auxi func opHasAuxInt(op opData) bool { switch op.aux { - case "Bool", "Int8", "Int16", "Int32", "Int64", "Int128", "Float32", "Float64", + case "Bool", "Int8", "Int16", "Int32", "Int64", "Int128", "UInt8", "Float32", "Float64", "SymOff", "CallOff", "SymValAndOff", "TypSize", "ARM64BitField", "FlagConstant", "CCop": return true } @@ -1780,6 +1780,8 @@ func (op opData) auxIntType() string { return "int64" case "Int128": return "int128" + case "UInt8": + return "uint8" case "Float32": return "float32" case "Float64": diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go index 6f029a421e..d1673352bd 100644 --- a/src/cmd/compile/internal/ssa/op.go +++ b/src/cmd/compile/internal/ssa/op.go @@ -205,6 +205,7 @@ const ( auxInt32 // auxInt is a 32-bit integer auxInt64 // auxInt is a 64-bit integer auxInt128 // auxInt represents a 128-bit integer. Always 0. + auxUInt8 // auxInt is an 8-bit unsigned integer auxFloat32 // auxInt is a float32 (encoded with math.Float64bits) auxFloat64 // auxInt is a float64 (encoded with math.Float64bits) auxFlagConstant // auxInt is a flagConstant diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index eceef1d91a..83d35cf7e1 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -30569,7 +30569,7 @@ var opcodeTable = [...]opInfo{ }, { name: "SLDconst", - auxType: auxInt8, + auxType: auxUInt8, argLen: 1, asm: s390x.ASLD, reg: regInfo{ @@ -30583,7 +30583,7 @@ var opcodeTable = [...]opInfo{ }, { name: "SLWconst", - auxType: auxInt8, + auxType: auxUInt8, argLen: 1, asm: s390x.ASLW, reg: regInfo{ @@ -30625,7 +30625,7 @@ var opcodeTable = [...]opInfo{ }, { name: "SRDconst", - auxType: auxInt8, + auxType: auxUInt8, argLen: 1, asm: s390x.ASRD, reg: regInfo{ @@ -30639,7 +30639,7 @@ var opcodeTable = [...]opInfo{ }, { name: "SRWconst", - auxType: auxInt8, + auxType: auxUInt8, argLen: 1, asm: s390x.ASRW, reg: regInfo{ @@ -30683,7 +30683,7 @@ var opcodeTable = [...]opInfo{ }, { name: "SRADconst", - auxType: auxInt8, + auxType: auxUInt8, argLen: 1, clobberFlags: true, asm: s390x.ASRAD, @@ -30698,7 +30698,7 @@ var opcodeTable = [...]opInfo{ }, { name: "SRAWconst", - auxType: auxInt8, + auxType: auxUInt8, argLen: 1, clobberFlags: true, asm: s390x.ASRAW, @@ -30741,7 +30741,7 @@ var opcodeTable = [...]opInfo{ }, { name: "RLLconst", - auxType: auxInt8, + auxType: auxUInt8, argLen: 1, asm: s390x.ARLL, reg: regInfo{ diff --git a/src/cmd/compile/internal/ssa/rewriteS390X.go b/src/cmd/compile/internal/ssa/rewriteS390X.go index d66113d111..a9722b820c 100644 --- a/src/cmd/compile/internal/ssa/rewriteS390X.go +++ b/src/cmd/compile/internal/ssa/rewriteS390X.go @@ -1240,7 +1240,7 @@ func rewriteValueS390X_OpAvg64u(v *Value) bool { y := v_1 v.reset(OpS390XADD) v0 := b.NewValue0(v.Pos, OpS390XSRDconst, t) - v0.AuxInt = int8ToAuxInt(1) + v0.AuxInt = uint8ToAuxInt(1) v1 := b.NewValue0(v.Pos, OpS390XSUB, t) v1.AddArg2(x, y) v0.AddArg(v1) @@ -1737,7 +1737,7 @@ func rewriteValueS390X_OpHmul32(v *Value) bool { x := v_0 y := v_1 v.reset(OpS390XSRDconst) - v.AuxInt = int8ToAuxInt(32) + v.AuxInt = uint8ToAuxInt(32) v0 := b.NewValue0(v.Pos, OpS390XMULLD, typ.Int64) v1 := b.NewValue0(v.Pos, OpS390XMOVWreg, typ.Int64) v1.AddArg(x) @@ -1759,7 +1759,7 @@ func rewriteValueS390X_OpHmul32u(v *Value) bool { x := v_0 y := v_1 v.reset(OpS390XSRDconst) - v.AuxInt = int8ToAuxInt(32) + v.AuxInt = uint8ToAuxInt(32) v0 := b.NewValue0(v.Pos, OpS390XMULLD, typ.Int64) v1 := b.NewValue0(v.Pos, OpS390XMOVWZreg, typ.UInt64) v1.AddArg(x) @@ -5281,9 +5281,9 @@ func rewriteValueS390X_OpS390XADD(v *Value) bool { if v_0.Op != OpS390XSLDconst { continue } - c := auxIntToInt8(v_0.AuxInt) + c := auxIntToUint8(v_0.AuxInt) x := v_0.Args[0] - if v_1.Op != OpS390XSRDconst || auxIntToInt8(v_1.AuxInt) != 64-c || x != v_1.Args[0] { + if v_1.Op != OpS390XSRDconst || auxIntToUint8(v_1.AuxInt) != 64-c || x != v_1.Args[0] { continue } v.reset(OpS390XRISBGZ) @@ -5474,13 +5474,13 @@ func rewriteValueS390X_OpS390XADDW(v *Value) bool { if v_0.Op != OpS390XSLWconst { continue } - c := auxIntToInt8(v_0.AuxInt) + c := auxIntToUint8(v_0.AuxInt) x := v_0.Args[0] - if v_1.Op != OpS390XSRWconst || auxIntToInt8(v_1.AuxInt) != 32-c || x != v_1.Args[0] { + if v_1.Op != OpS390XSRWconst || auxIntToUint8(v_1.AuxInt) != 32-c || x != v_1.Args[0] { continue } v.reset(OpS390XRLLconst) - v.AuxInt = int8ToAuxInt(c) + v.AuxInt = uint8ToAuxInt(c) v.AddArg(x) return true } @@ -6460,7 +6460,7 @@ func rewriteValueS390X_OpS390XCMPUconst(v *Value) bool { if v_0.Op != OpS390XSRDconst { break } - c := auxIntToInt8(v_0.AuxInt) + c := auxIntToUint8(v_0.AuxInt) if !(c > 0 && c < 64 && (1< 0 && c < 32 && (1< 0 && n < 0) { break } @@ -7020,7 +7020,7 @@ func rewriteValueS390X_OpS390XCMPWconst(v *Value) bool { if x.Op != OpS390XSRWconst { break } - c := auxIntToInt8(x.AuxInt) + c := auxIntToUint8(x.AuxInt) if !(c > 0 && n >= 0) { break } @@ -7112,7 +7112,7 @@ func rewriteValueS390X_OpS390XCMPconst(v *Value) bool { if v_0.Op != OpS390XSRDconst { break } - c := auxIntToInt8(v_0.AuxInt) + c := auxIntToUint8(v_0.AuxInt) if !(c > 0 && n < 0) { break } @@ -7250,7 +7250,7 @@ func rewriteValueS390X_OpS390XCMPconst(v *Value) bool { if x.Op != OpS390XSRDconst { break } - c := auxIntToInt8(x.AuxInt) + c := auxIntToUint8(x.AuxInt) if !(c > 0 && n >= 0) { break } @@ -8673,7 +8673,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value) bool { break } x_1 := x.Args[1] - if x_1.Op != OpS390XSRDconst || auxIntToInt8(x_1.AuxInt) != 8 || w != x_1.Args[0] || !(p.Op != OpSB && x.Uses == 1 && clobber(x)) { + if x_1.Op != OpS390XSRDconst || auxIntToUint8(x_1.AuxInt) != 8 || w != x_1.Args[0] || !(p.Op != OpSB && x.Uses == 1 && clobber(x)) { break } v.reset(OpS390XMOVHstore) @@ -8693,7 +8693,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value) bool { if w0.Op != OpS390XSRDconst { break } - j := auxIntToInt8(w0.AuxInt) + j := auxIntToUint8(w0.AuxInt) w := w0.Args[0] x := v_2 if x.Op != OpS390XMOVBstore || auxIntToInt32(x.AuxInt) != i-1 || auxToSym(x.Aux) != s { @@ -8704,7 +8704,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value) bool { break } x_1 := x.Args[1] - if x_1.Op != OpS390XSRDconst || auxIntToInt8(x_1.AuxInt) != j+8 || w != x_1.Args[0] || !(p.Op != OpSB && x.Uses == 1 && clobber(x)) { + if x_1.Op != OpS390XSRDconst || auxIntToUint8(x_1.AuxInt) != j+8 || w != x_1.Args[0] || !(p.Op != OpSB && x.Uses == 1 && clobber(x)) { break } v.reset(OpS390XMOVHstore) @@ -8730,7 +8730,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value) bool { break } x_1 := x.Args[1] - if x_1.Op != OpS390XSRWconst || auxIntToInt8(x_1.AuxInt) != 8 || w != x_1.Args[0] || !(p.Op != OpSB && x.Uses == 1 && clobber(x)) { + if x_1.Op != OpS390XSRWconst || auxIntToUint8(x_1.AuxInt) != 8 || w != x_1.Args[0] || !(p.Op != OpSB && x.Uses == 1 && clobber(x)) { break } v.reset(OpS390XMOVHstore) @@ -8750,7 +8750,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value) bool { if w0.Op != OpS390XSRWconst { break } - j := auxIntToInt8(w0.AuxInt) + j := auxIntToUint8(w0.AuxInt) w := w0.Args[0] x := v_2 if x.Op != OpS390XMOVBstore || auxIntToInt32(x.AuxInt) != i-1 || auxToSym(x.Aux) != s { @@ -8761,7 +8761,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value) bool { break } x_1 := x.Args[1] - if x_1.Op != OpS390XSRWconst || auxIntToInt8(x_1.AuxInt) != j+8 || w != x_1.Args[0] || !(p.Op != OpSB && x.Uses == 1 && clobber(x)) { + if x_1.Op != OpS390XSRWconst || auxIntToUint8(x_1.AuxInt) != j+8 || w != x_1.Args[0] || !(p.Op != OpSB && x.Uses == 1 && clobber(x)) { break } v.reset(OpS390XMOVHstore) @@ -8777,7 +8777,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value) bool { i := auxIntToInt32(v.AuxInt) s := auxToSym(v.Aux) p := v_0 - if v_1.Op != OpS390XSRDconst || auxIntToInt8(v_1.AuxInt) != 8 { + if v_1.Op != OpS390XSRDconst || auxIntToUint8(v_1.AuxInt) != 8 { break } w := v_1.Args[0] @@ -8805,7 +8805,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value) bool { if v_1.Op != OpS390XSRDconst { break } - j := auxIntToInt8(v_1.AuxInt) + j := auxIntToUint8(v_1.AuxInt) w := v_1.Args[0] x := v_2 if x.Op != OpS390XMOVBstore || auxIntToInt32(x.AuxInt) != i-1 || auxToSym(x.Aux) != s { @@ -8816,7 +8816,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value) bool { break } w0 := x.Args[1] - if w0.Op != OpS390XSRDconst || auxIntToInt8(w0.AuxInt) != j-8 || w != w0.Args[0] || !(p.Op != OpSB && x.Uses == 1 && clobber(x)) { + if w0.Op != OpS390XSRDconst || auxIntToUint8(w0.AuxInt) != j-8 || w != w0.Args[0] || !(p.Op != OpSB && x.Uses == 1 && clobber(x)) { break } v.reset(OpS390XMOVHBRstore) @@ -8832,7 +8832,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value) bool { i := auxIntToInt32(v.AuxInt) s := auxToSym(v.Aux) p := v_0 - if v_1.Op != OpS390XSRWconst || auxIntToInt8(v_1.AuxInt) != 8 { + if v_1.Op != OpS390XSRWconst || auxIntToUint8(v_1.AuxInt) != 8 { break } w := v_1.Args[0] @@ -8860,7 +8860,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value) bool { if v_1.Op != OpS390XSRWconst { break } - j := auxIntToInt8(v_1.AuxInt) + j := auxIntToUint8(v_1.AuxInt) w := v_1.Args[0] x := v_2 if x.Op != OpS390XMOVBstore || auxIntToInt32(x.AuxInt) != i-1 || auxToSym(x.Aux) != s { @@ -8871,7 +8871,7 @@ func rewriteValueS390X_OpS390XMOVBstore(v *Value) bool { break } w0 := x.Args[1] - if w0.Op != OpS390XSRWconst || auxIntToInt8(w0.AuxInt) != j-8 || w != w0.Args[0] || !(p.Op != OpSB && x.Uses == 1 && clobber(x)) { + if w0.Op != OpS390XSRWconst || auxIntToUint8(w0.AuxInt) != j-8 || w != w0.Args[0] || !(p.Op != OpSB && x.Uses == 1 && clobber(x)) { break } v.reset(OpS390XMOVHBRstore) @@ -9345,7 +9345,7 @@ func rewriteValueS390X_OpS390XMOVHBRstore(v *Value) bool { i := auxIntToInt32(v.AuxInt) s := auxToSym(v.Aux) p := v_0 - if v_1.Op != OpS390XSRDconst || auxIntToInt8(v_1.AuxInt) != 16 { + if v_1.Op != OpS390XSRDconst || auxIntToUint8(v_1.AuxInt) != 16 { break } w := v_1.Args[0] @@ -9373,7 +9373,7 @@ func rewriteValueS390X_OpS390XMOVHBRstore(v *Value) bool { if v_1.Op != OpS390XSRDconst { break } - j := auxIntToInt8(v_1.AuxInt) + j := auxIntToUint8(v_1.AuxInt) w := v_1.Args[0] x := v_2 if x.Op != OpS390XMOVHBRstore || auxIntToInt32(x.AuxInt) != i-2 || auxToSym(x.Aux) != s { @@ -9384,7 +9384,7 @@ func rewriteValueS390X_OpS390XMOVHBRstore(v *Value) bool { break } w0 := x.Args[1] - if w0.Op != OpS390XSRDconst || auxIntToInt8(w0.AuxInt) != j-16 || w != w0.Args[0] || !(x.Uses == 1 && clobber(x)) { + if w0.Op != OpS390XSRDconst || auxIntToUint8(w0.AuxInt) != j-16 || w != w0.Args[0] || !(x.Uses == 1 && clobber(x)) { break } v.reset(OpS390XMOVWBRstore) @@ -9400,7 +9400,7 @@ func rewriteValueS390X_OpS390XMOVHBRstore(v *Value) bool { i := auxIntToInt32(v.AuxInt) s := auxToSym(v.Aux) p := v_0 - if v_1.Op != OpS390XSRWconst || auxIntToInt8(v_1.AuxInt) != 16 { + if v_1.Op != OpS390XSRWconst || auxIntToUint8(v_1.AuxInt) != 16 { break } w := v_1.Args[0] @@ -9428,7 +9428,7 @@ func rewriteValueS390X_OpS390XMOVHBRstore(v *Value) bool { if v_1.Op != OpS390XSRWconst { break } - j := auxIntToInt8(v_1.AuxInt) + j := auxIntToUint8(v_1.AuxInt) w := v_1.Args[0] x := v_2 if x.Op != OpS390XMOVHBRstore || auxIntToInt32(x.AuxInt) != i-2 || auxToSym(x.Aux) != s { @@ -9439,7 +9439,7 @@ func rewriteValueS390X_OpS390XMOVHBRstore(v *Value) bool { break } w0 := x.Args[1] - if w0.Op != OpS390XSRWconst || auxIntToInt8(w0.AuxInt) != j-16 || w != w0.Args[0] || !(x.Uses == 1 && clobber(x)) { + if w0.Op != OpS390XSRWconst || auxIntToUint8(w0.AuxInt) != j-16 || w != w0.Args[0] || !(x.Uses == 1 && clobber(x)) { break } v.reset(OpS390XMOVWBRstore) @@ -10086,7 +10086,7 @@ func rewriteValueS390X_OpS390XMOVHstore(v *Value) bool { break } x_1 := x.Args[1] - if x_1.Op != OpS390XSRDconst || auxIntToInt8(x_1.AuxInt) != 16 || w != x_1.Args[0] || !(p.Op != OpSB && x.Uses == 1 && clobber(x)) { + if x_1.Op != OpS390XSRDconst || auxIntToUint8(x_1.AuxInt) != 16 || w != x_1.Args[0] || !(p.Op != OpSB && x.Uses == 1 && clobber(x)) { break } v.reset(OpS390XMOVWstore) @@ -10106,7 +10106,7 @@ func rewriteValueS390X_OpS390XMOVHstore(v *Value) bool { if w0.Op != OpS390XSRDconst { break } - j := auxIntToInt8(w0.AuxInt) + j := auxIntToUint8(w0.AuxInt) w := w0.Args[0] x := v_2 if x.Op != OpS390XMOVHstore || auxIntToInt32(x.AuxInt) != i-2 || auxToSym(x.Aux) != s { @@ -10117,7 +10117,7 @@ func rewriteValueS390X_OpS390XMOVHstore(v *Value) bool { break } x_1 := x.Args[1] - if x_1.Op != OpS390XSRDconst || auxIntToInt8(x_1.AuxInt) != j+16 || w != x_1.Args[0] || !(p.Op != OpSB && x.Uses == 1 && clobber(x)) { + if x_1.Op != OpS390XSRDconst || auxIntToUint8(x_1.AuxInt) != j+16 || w != x_1.Args[0] || !(p.Op != OpSB && x.Uses == 1 && clobber(x)) { break } v.reset(OpS390XMOVWstore) @@ -10143,7 +10143,7 @@ func rewriteValueS390X_OpS390XMOVHstore(v *Value) bool { break } x_1 := x.Args[1] - if x_1.Op != OpS390XSRWconst || auxIntToInt8(x_1.AuxInt) != 16 || w != x_1.Args[0] || !(p.Op != OpSB && x.Uses == 1 && clobber(x)) { + if x_1.Op != OpS390XSRWconst || auxIntToUint8(x_1.AuxInt) != 16 || w != x_1.Args[0] || !(p.Op != OpSB && x.Uses == 1 && clobber(x)) { break } v.reset(OpS390XMOVWstore) @@ -10163,7 +10163,7 @@ func rewriteValueS390X_OpS390XMOVHstore(v *Value) bool { if w0.Op != OpS390XSRWconst { break } - j := auxIntToInt8(w0.AuxInt) + j := auxIntToUint8(w0.AuxInt) w := w0.Args[0] x := v_2 if x.Op != OpS390XMOVHstore || auxIntToInt32(x.AuxInt) != i-2 || auxToSym(x.Aux) != s { @@ -10174,7 +10174,7 @@ func rewriteValueS390X_OpS390XMOVHstore(v *Value) bool { break } x_1 := x.Args[1] - if x_1.Op != OpS390XSRWconst || auxIntToInt8(x_1.AuxInt) != j+16 || w != x_1.Args[0] || !(p.Op != OpSB && x.Uses == 1 && clobber(x)) { + if x_1.Op != OpS390XSRWconst || auxIntToUint8(x_1.AuxInt) != j+16 || w != x_1.Args[0] || !(p.Op != OpSB && x.Uses == 1 && clobber(x)) { break } v.reset(OpS390XMOVWstore) @@ -10273,7 +10273,7 @@ func rewriteValueS390X_OpS390XMOVWBRstore(v *Value) bool { i := auxIntToInt32(v.AuxInt) s := auxToSym(v.Aux) p := v_0 - if v_1.Op != OpS390XSRDconst || auxIntToInt8(v_1.AuxInt) != 32 { + if v_1.Op != OpS390XSRDconst || auxIntToUint8(v_1.AuxInt) != 32 { break } w := v_1.Args[0] @@ -10301,7 +10301,7 @@ func rewriteValueS390X_OpS390XMOVWBRstore(v *Value) bool { if v_1.Op != OpS390XSRDconst { break } - j := auxIntToInt8(v_1.AuxInt) + j := auxIntToUint8(v_1.AuxInt) w := v_1.Args[0] x := v_2 if x.Op != OpS390XMOVWBRstore || auxIntToInt32(x.AuxInt) != i-4 || auxToSym(x.Aux) != s { @@ -10312,7 +10312,7 @@ func rewriteValueS390X_OpS390XMOVWBRstore(v *Value) bool { break } w0 := x.Args[1] - if w0.Op != OpS390XSRDconst || auxIntToInt8(w0.AuxInt) != j-32 || w != w0.Args[0] || !(x.Uses == 1 && clobber(x)) { + if w0.Op != OpS390XSRDconst || auxIntToUint8(w0.AuxInt) != j-32 || w != w0.Args[0] || !(x.Uses == 1 && clobber(x)) { break } v.reset(OpS390XMOVDBRstore) @@ -10914,7 +10914,7 @@ func rewriteValueS390X_OpS390XMOVWstore(v *Value) bool { i := auxIntToInt32(v.AuxInt) s := auxToSym(v.Aux) p := v_0 - if v_1.Op != OpS390XSRDconst || auxIntToInt8(v_1.AuxInt) != 32 { + if v_1.Op != OpS390XSRDconst || auxIntToUint8(v_1.AuxInt) != 32 { break } w := v_1.Args[0] @@ -10943,7 +10943,7 @@ func rewriteValueS390X_OpS390XMOVWstore(v *Value) bool { if w0.Op != OpS390XSRDconst { break } - j := auxIntToInt8(w0.AuxInt) + j := auxIntToUint8(w0.AuxInt) w := w0.Args[0] x := v_2 if x.Op != OpS390XMOVWstore || auxIntToInt32(x.AuxInt) != i-4 || auxToSym(x.Aux) != s { @@ -10954,7 +10954,7 @@ func rewriteValueS390X_OpS390XMOVWstore(v *Value) bool { break } x_1 := x.Args[1] - if x_1.Op != OpS390XSRDconst || auxIntToInt8(x_1.AuxInt) != j+32 || w != x_1.Args[0] || !(p.Op != OpSB && x.Uses == 1 && clobber(x)) { + if x_1.Op != OpS390XSRDconst || auxIntToUint8(x_1.AuxInt) != j+32 || w != x_1.Args[0] || !(p.Op != OpSB && x.Uses == 1 && clobber(x)) { break } v.reset(OpS390XMOVDstore) @@ -11180,7 +11180,7 @@ func rewriteValueS390X_OpS390XMULLDconst(v *Value) bool { b := v.Block // match: (MULLDconst x [c]) // cond: isPowerOfTwo32(c&(c-1)) - // result: (ADD (SLDconst x [int8(log32(c&(c-1)))]) (SLDconst x [int8(log32(c&^(c-1)))])) + // result: (ADD (SLDconst x [uint8(log32(c&(c-1)))]) (SLDconst x [uint8(log32(c&^(c-1)))])) for { t := v.Type c := auxIntToInt32(v.AuxInt) @@ -11190,17 +11190,17 @@ func rewriteValueS390X_OpS390XMULLDconst(v *Value) bool { } v.reset(OpS390XADD) v0 := b.NewValue0(v.Pos, OpS390XSLDconst, t) - v0.AuxInt = int8ToAuxInt(int8(log32(c & (c - 1)))) + v0.AuxInt = uint8ToAuxInt(uint8(log32(c & (c - 1)))) v0.AddArg(x) v1 := b.NewValue0(v.Pos, OpS390XSLDconst, t) - v1.AuxInt = int8ToAuxInt(int8(log32(c &^ (c - 1)))) + v1.AuxInt = uint8ToAuxInt(uint8(log32(c &^ (c - 1)))) v1.AddArg(x) v.AddArg2(v0, v1) return true } // match: (MULLDconst x [c]) // cond: isPowerOfTwo32(c+(c&^(c-1))) - // result: (SUB (SLDconst x [int8(log32(c+(c&^(c-1))))]) (SLDconst x [int8(log32(c&^(c-1)))])) + // result: (SUB (SLDconst x [uint8(log32(c+(c&^(c-1))))]) (SLDconst x [uint8(log32(c&^(c-1)))])) for { t := v.Type c := auxIntToInt32(v.AuxInt) @@ -11210,17 +11210,17 @@ func rewriteValueS390X_OpS390XMULLDconst(v *Value) bool { } v.reset(OpS390XSUB) v0 := b.NewValue0(v.Pos, OpS390XSLDconst, t) - v0.AuxInt = int8ToAuxInt(int8(log32(c + (c &^ (c - 1))))) + v0.AuxInt = uint8ToAuxInt(uint8(log32(c + (c &^ (c - 1))))) v0.AddArg(x) v1 := b.NewValue0(v.Pos, OpS390XSLDconst, t) - v1.AuxInt = int8ToAuxInt(int8(log32(c &^ (c - 1)))) + v1.AuxInt = uint8ToAuxInt(uint8(log32(c &^ (c - 1)))) v1.AddArg(x) v.AddArg2(v0, v1) return true } // match: (MULLDconst x [c]) // cond: isPowerOfTwo32(-c+(-c&^(-c-1))) - // result: (SUB (SLDconst x [int8(log32(-c&^(-c-1)))]) (SLDconst x [int8(log32(-c+(-c&^(-c-1))))])) + // result: (SUB (SLDconst x [uint8(log32(-c&^(-c-1)))]) (SLDconst x [uint8(log32(-c+(-c&^(-c-1))))])) for { t := v.Type c := auxIntToInt32(v.AuxInt) @@ -11230,10 +11230,10 @@ func rewriteValueS390X_OpS390XMULLDconst(v *Value) bool { } v.reset(OpS390XSUB) v0 := b.NewValue0(v.Pos, OpS390XSLDconst, t) - v0.AuxInt = int8ToAuxInt(int8(log32(-c &^ (-c - 1)))) + v0.AuxInt = uint8ToAuxInt(uint8(log32(-c &^ (-c - 1)))) v0.AddArg(x) v1 := b.NewValue0(v.Pos, OpS390XSLDconst, t) - v1.AuxInt = int8ToAuxInt(int8(log32(-c + (-c &^ (-c - 1))))) + v1.AuxInt = uint8ToAuxInt(uint8(log32(-c + (-c &^ (-c - 1))))) v1.AddArg(x) v.AddArg2(v0, v1) return true @@ -11407,7 +11407,7 @@ func rewriteValueS390X_OpS390XMULLWconst(v *Value) bool { b := v.Block // match: (MULLWconst x [c]) // cond: isPowerOfTwo32(c&(c-1)) - // result: (ADDW (SLWconst x [int8(log32(c&(c-1)))]) (SLWconst x [int8(log32(c&^(c-1)))])) + // result: (ADDW (SLWconst x [uint8(log32(c&(c-1)))]) (SLWconst x [uint8(log32(c&^(c-1)))])) for { t := v.Type c := auxIntToInt32(v.AuxInt) @@ -11417,17 +11417,17 @@ func rewriteValueS390X_OpS390XMULLWconst(v *Value) bool { } v.reset(OpS390XADDW) v0 := b.NewValue0(v.Pos, OpS390XSLWconst, t) - v0.AuxInt = int8ToAuxInt(int8(log32(c & (c - 1)))) + v0.AuxInt = uint8ToAuxInt(uint8(log32(c & (c - 1)))) v0.AddArg(x) v1 := b.NewValue0(v.Pos, OpS390XSLWconst, t) - v1.AuxInt = int8ToAuxInt(int8(log32(c &^ (c - 1)))) + v1.AuxInt = uint8ToAuxInt(uint8(log32(c &^ (c - 1)))) v1.AddArg(x) v.AddArg2(v0, v1) return true } // match: (MULLWconst x [c]) // cond: isPowerOfTwo32(c+(c&^(c-1))) - // result: (SUBW (SLWconst x [int8(log32(c+(c&^(c-1))))]) (SLWconst x [int8(log32(c&^(c-1)))])) + // result: (SUBW (SLWconst x [uint8(log32(c+(c&^(c-1))))]) (SLWconst x [uint8(log32(c&^(c-1)))])) for { t := v.Type c := auxIntToInt32(v.AuxInt) @@ -11437,17 +11437,17 @@ func rewriteValueS390X_OpS390XMULLWconst(v *Value) bool { } v.reset(OpS390XSUBW) v0 := b.NewValue0(v.Pos, OpS390XSLWconst, t) - v0.AuxInt = int8ToAuxInt(int8(log32(c + (c &^ (c - 1))))) + v0.AuxInt = uint8ToAuxInt(uint8(log32(c + (c &^ (c - 1))))) v0.AddArg(x) v1 := b.NewValue0(v.Pos, OpS390XSLWconst, t) - v1.AuxInt = int8ToAuxInt(int8(log32(c &^ (c - 1)))) + v1.AuxInt = uint8ToAuxInt(uint8(log32(c &^ (c - 1)))) v1.AddArg(x) v.AddArg2(v0, v1) return true } // match: (MULLWconst x [c]) // cond: isPowerOfTwo32(-c+(-c&^(-c-1))) - // result: (SUBW (SLWconst x [int8(log32(-c&^(-c-1)))]) (SLWconst x [int8(log32(-c+(-c&^(-c-1))))])) + // result: (SUBW (SLWconst x [uint8(log32(-c&^(-c-1)))]) (SLWconst x [uint8(log32(-c+(-c&^(-c-1))))])) for { t := v.Type c := auxIntToInt32(v.AuxInt) @@ -11457,10 +11457,10 @@ func rewriteValueS390X_OpS390XMULLWconst(v *Value) bool { } v.reset(OpS390XSUBW) v0 := b.NewValue0(v.Pos, OpS390XSLWconst, t) - v0.AuxInt = int8ToAuxInt(int8(log32(-c &^ (-c - 1)))) + v0.AuxInt = uint8ToAuxInt(uint8(log32(-c &^ (-c - 1)))) v0.AddArg(x) v1 := b.NewValue0(v.Pos, OpS390XSLWconst, t) - v1.AuxInt = int8ToAuxInt(int8(log32(-c + (-c &^ (-c - 1))))) + v1.AuxInt = uint8ToAuxInt(uint8(log32(-c + (-c &^ (-c - 1))))) v1.AddArg(x) v.AddArg2(v0, v1) return true @@ -11640,9 +11640,9 @@ func rewriteValueS390X_OpS390XOR(v *Value) bool { if v_0.Op != OpS390XSLDconst { continue } - c := auxIntToInt8(v_0.AuxInt) + c := auxIntToUint8(v_0.AuxInt) x := v_0.Args[0] - if v_1.Op != OpS390XSRDconst || auxIntToInt8(v_1.AuxInt) != 64-c || x != v_1.Args[0] { + if v_1.Op != OpS390XSRDconst || auxIntToUint8(v_1.AuxInt) != 64-c || x != v_1.Args[0] { continue } v.reset(OpS390XRISBGZ) @@ -11804,7 +11804,7 @@ func rewriteValueS390X_OpS390XOR(v *Value) bool { mem := x1.Args[1] p := x1.Args[0] sh := v_1 - if sh.Op != OpS390XSLDconst || auxIntToInt8(sh.AuxInt) != 8 { + if sh.Op != OpS390XSLDconst || auxIntToUint8(sh.AuxInt) != 8 { continue } x0 := sh.Args[0] @@ -11843,7 +11843,7 @@ func rewriteValueS390X_OpS390XOR(v *Value) bool { mem := x1.Args[1] p := x1.Args[0] sh := v_1 - if sh.Op != OpS390XSLDconst || auxIntToInt8(sh.AuxInt) != 16 { + if sh.Op != OpS390XSLDconst || auxIntToUint8(sh.AuxInt) != 16 { continue } x0 := sh.Args[0] @@ -11882,7 +11882,7 @@ func rewriteValueS390X_OpS390XOR(v *Value) bool { mem := x1.Args[1] p := x1.Args[0] sh := v_1 - if sh.Op != OpS390XSLDconst || auxIntToInt8(sh.AuxInt) != 32 { + if sh.Op != OpS390XSLDconst || auxIntToUint8(sh.AuxInt) != 32 { continue } x0 := sh.Args[0] @@ -11916,7 +11916,7 @@ func rewriteValueS390X_OpS390XOR(v *Value) bool { if s0.Op != OpS390XSLDconst { continue } - j0 := auxIntToInt8(s0.AuxInt) + j0 := auxIntToUint8(s0.AuxInt) x0 := s0.Args[0] if x0.Op != OpS390XMOVBZload { continue @@ -11937,7 +11937,7 @@ func rewriteValueS390X_OpS390XOR(v *Value) bool { if s1.Op != OpS390XSLDconst { continue } - j1 := auxIntToInt8(s1.AuxInt) + j1 := auxIntToUint8(s1.AuxInt) x1 := s1.Args[0] if x1.Op != OpS390XMOVBZload { continue @@ -11958,7 +11958,7 @@ func rewriteValueS390X_OpS390XOR(v *Value) bool { v0 := b.NewValue0(x1.Pos, OpS390XOR, v.Type) v.copyOf(v0) v1 := b.NewValue0(x1.Pos, OpS390XSLDconst, v.Type) - v1.AuxInt = int8ToAuxInt(j1) + v1.AuxInt = uint8ToAuxInt(j1) v2 := b.NewValue0(x1.Pos, OpS390XMOVHZload, typ.UInt16) v2.AuxInt = int32ToAuxInt(i0) v2.Aux = symToAux(s) @@ -11979,7 +11979,7 @@ func rewriteValueS390X_OpS390XOR(v *Value) bool { if s0.Op != OpS390XSLDconst { continue } - j0 := auxIntToInt8(s0.AuxInt) + j0 := auxIntToUint8(s0.AuxInt) x0 := s0.Args[0] if x0.Op != OpS390XMOVHZload { continue @@ -12000,7 +12000,7 @@ func rewriteValueS390X_OpS390XOR(v *Value) bool { if s1.Op != OpS390XSLDconst { continue } - j1 := auxIntToInt8(s1.AuxInt) + j1 := auxIntToUint8(s1.AuxInt) x1 := s1.Args[0] if x1.Op != OpS390XMOVHZload { continue @@ -12021,7 +12021,7 @@ func rewriteValueS390X_OpS390XOR(v *Value) bool { v0 := b.NewValue0(x1.Pos, OpS390XOR, v.Type) v.copyOf(v0) v1 := b.NewValue0(x1.Pos, OpS390XSLDconst, v.Type) - v1.AuxInt = int8ToAuxInt(j1) + v1.AuxInt = uint8ToAuxInt(j1) v2 := b.NewValue0(x1.Pos, OpS390XMOVWZload, typ.UInt32) v2.AuxInt = int32ToAuxInt(i0) v2.Aux = symToAux(s) @@ -12047,7 +12047,7 @@ func rewriteValueS390X_OpS390XOR(v *Value) bool { mem := x0.Args[1] p := x0.Args[0] sh := v_1 - if sh.Op != OpS390XSLDconst || auxIntToInt8(sh.AuxInt) != 8 { + if sh.Op != OpS390XSLDconst || auxIntToUint8(sh.AuxInt) != 8 { continue } x1 := sh.Args[0] @@ -12092,7 +12092,7 @@ func rewriteValueS390X_OpS390XOR(v *Value) bool { mem := x0.Args[1] p := x0.Args[0] sh := v_1 - if sh.Op != OpS390XSLDconst || auxIntToInt8(sh.AuxInt) != 16 { + if sh.Op != OpS390XSLDconst || auxIntToUint8(sh.AuxInt) != 16 { continue } r1 := sh.Args[0] @@ -12141,7 +12141,7 @@ func rewriteValueS390X_OpS390XOR(v *Value) bool { mem := x0.Args[1] p := x0.Args[0] sh := v_1 - if sh.Op != OpS390XSLDconst || auxIntToInt8(sh.AuxInt) != 32 { + if sh.Op != OpS390XSLDconst || auxIntToUint8(sh.AuxInt) != 32 { continue } r1 := sh.Args[0] @@ -12179,7 +12179,7 @@ func rewriteValueS390X_OpS390XOR(v *Value) bool { if s1.Op != OpS390XSLDconst { continue } - j1 := auxIntToInt8(s1.AuxInt) + j1 := auxIntToUint8(s1.AuxInt) x1 := s1.Args[0] if x1.Op != OpS390XMOVBZload { continue @@ -12200,7 +12200,7 @@ func rewriteValueS390X_OpS390XOR(v *Value) bool { if s0.Op != OpS390XSLDconst { continue } - j0 := auxIntToInt8(s0.AuxInt) + j0 := auxIntToUint8(s0.AuxInt) x0 := s0.Args[0] if x0.Op != OpS390XMOVBZload { continue @@ -12221,7 +12221,7 @@ func rewriteValueS390X_OpS390XOR(v *Value) bool { v0 := b.NewValue0(x0.Pos, OpS390XOR, v.Type) v.copyOf(v0) v1 := b.NewValue0(x0.Pos, OpS390XSLDconst, v.Type) - v1.AuxInt = int8ToAuxInt(j0) + v1.AuxInt = uint8ToAuxInt(j0) v2 := b.NewValue0(x0.Pos, OpS390XMOVHZreg, typ.UInt64) v3 := b.NewValue0(x0.Pos, OpS390XMOVHBRload, typ.UInt16) v3.AuxInt = int32ToAuxInt(i0) @@ -12244,7 +12244,7 @@ func rewriteValueS390X_OpS390XOR(v *Value) bool { if s1.Op != OpS390XSLDconst { continue } - j1 := auxIntToInt8(s1.AuxInt) + j1 := auxIntToUint8(s1.AuxInt) r1 := s1.Args[0] if r1.Op != OpS390XMOVHZreg { continue @@ -12269,7 +12269,7 @@ func rewriteValueS390X_OpS390XOR(v *Value) bool { if s0.Op != OpS390XSLDconst { continue } - j0 := auxIntToInt8(s0.AuxInt) + j0 := auxIntToUint8(s0.AuxInt) r0 := s0.Args[0] if r0.Op != OpS390XMOVHZreg { continue @@ -12294,7 +12294,7 @@ func rewriteValueS390X_OpS390XOR(v *Value) bool { v0 := b.NewValue0(x0.Pos, OpS390XOR, v.Type) v.copyOf(v0) v1 := b.NewValue0(x0.Pos, OpS390XSLDconst, v.Type) - v1.AuxInt = int8ToAuxInt(j0) + v1.AuxInt = uint8ToAuxInt(j0) v2 := b.NewValue0(x0.Pos, OpS390XMOVWZreg, typ.UInt64) v3 := b.NewValue0(x0.Pos, OpS390XMOVWBRload, typ.UInt32) v3.AuxInt = int32ToAuxInt(i0) @@ -12338,13 +12338,13 @@ func rewriteValueS390X_OpS390XORW(v *Value) bool { if v_0.Op != OpS390XSLWconst { continue } - c := auxIntToInt8(v_0.AuxInt) + c := auxIntToUint8(v_0.AuxInt) x := v_0.Args[0] - if v_1.Op != OpS390XSRWconst || auxIntToInt8(v_1.AuxInt) != 32-c || x != v_1.Args[0] { + if v_1.Op != OpS390XSRWconst || auxIntToUint8(v_1.AuxInt) != 32-c || x != v_1.Args[0] { continue } v.reset(OpS390XRLLconst) - v.AuxInt = int8ToAuxInt(c) + v.AuxInt = uint8ToAuxInt(c) v.AddArg(x) return true } @@ -12428,7 +12428,7 @@ func rewriteValueS390X_OpS390XORW(v *Value) bool { mem := x1.Args[1] p := x1.Args[0] sh := v_1 - if sh.Op != OpS390XSLWconst || auxIntToInt8(sh.AuxInt) != 8 { + if sh.Op != OpS390XSLWconst || auxIntToUint8(sh.AuxInt) != 8 { continue } x0 := sh.Args[0] @@ -12467,7 +12467,7 @@ func rewriteValueS390X_OpS390XORW(v *Value) bool { mem := x1.Args[1] p := x1.Args[0] sh := v_1 - if sh.Op != OpS390XSLWconst || auxIntToInt8(sh.AuxInt) != 16 { + if sh.Op != OpS390XSLWconst || auxIntToUint8(sh.AuxInt) != 16 { continue } x0 := sh.Args[0] @@ -12501,7 +12501,7 @@ func rewriteValueS390X_OpS390XORW(v *Value) bool { if s0.Op != OpS390XSLWconst { continue } - j0 := auxIntToInt8(s0.AuxInt) + j0 := auxIntToUint8(s0.AuxInt) x0 := s0.Args[0] if x0.Op != OpS390XMOVBZload { continue @@ -12522,7 +12522,7 @@ func rewriteValueS390X_OpS390XORW(v *Value) bool { if s1.Op != OpS390XSLWconst { continue } - j1 := auxIntToInt8(s1.AuxInt) + j1 := auxIntToUint8(s1.AuxInt) x1 := s1.Args[0] if x1.Op != OpS390XMOVBZload { continue @@ -12543,7 +12543,7 @@ func rewriteValueS390X_OpS390XORW(v *Value) bool { v0 := b.NewValue0(x1.Pos, OpS390XORW, v.Type) v.copyOf(v0) v1 := b.NewValue0(x1.Pos, OpS390XSLWconst, v.Type) - v1.AuxInt = int8ToAuxInt(j1) + v1.AuxInt = uint8ToAuxInt(j1) v2 := b.NewValue0(x1.Pos, OpS390XMOVHZload, typ.UInt16) v2.AuxInt = int32ToAuxInt(i0) v2.Aux = symToAux(s) @@ -12569,7 +12569,7 @@ func rewriteValueS390X_OpS390XORW(v *Value) bool { mem := x0.Args[1] p := x0.Args[0] sh := v_1 - if sh.Op != OpS390XSLWconst || auxIntToInt8(sh.AuxInt) != 8 { + if sh.Op != OpS390XSLWconst || auxIntToUint8(sh.AuxInt) != 8 { continue } x1 := sh.Args[0] @@ -12614,7 +12614,7 @@ func rewriteValueS390X_OpS390XORW(v *Value) bool { mem := x0.Args[1] p := x0.Args[0] sh := v_1 - if sh.Op != OpS390XSLWconst || auxIntToInt8(sh.AuxInt) != 16 { + if sh.Op != OpS390XSLWconst || auxIntToUint8(sh.AuxInt) != 16 { continue } r1 := sh.Args[0] @@ -12652,7 +12652,7 @@ func rewriteValueS390X_OpS390XORW(v *Value) bool { if s1.Op != OpS390XSLWconst { continue } - j1 := auxIntToInt8(s1.AuxInt) + j1 := auxIntToUint8(s1.AuxInt) x1 := s1.Args[0] if x1.Op != OpS390XMOVBZload { continue @@ -12673,7 +12673,7 @@ func rewriteValueS390X_OpS390XORW(v *Value) bool { if s0.Op != OpS390XSLWconst { continue } - j0 := auxIntToInt8(s0.AuxInt) + j0 := auxIntToUint8(s0.AuxInt) x0 := s0.Args[0] if x0.Op != OpS390XMOVBZload { continue @@ -12694,7 +12694,7 @@ func rewriteValueS390X_OpS390XORW(v *Value) bool { v0 := b.NewValue0(x0.Pos, OpS390XORW, v.Type) v.copyOf(v0) v1 := b.NewValue0(x0.Pos, OpS390XSLWconst, v.Type) - v1.AuxInt = int8ToAuxInt(j0) + v1.AuxInt = uint8ToAuxInt(j0) v2 := b.NewValue0(x0.Pos, OpS390XMOVHZreg, typ.UInt64) v3 := b.NewValue0(x0.Pos, OpS390XMOVHBRload, typ.UInt16) v3.AuxInt = int32ToAuxInt(i0) @@ -12974,7 +12974,7 @@ func rewriteValueS390X_OpS390XRISBGZ(v *Value) bool { if v_0.Op != OpS390XSLDconst { break } - c := auxIntToInt8(v_0.AuxInt) + c := auxIntToUint8(v_0.AuxInt) x := v_0.Args[0] if !(r.InMerge(^uint64(0)<>c) != nil) { break @@ -13030,7 +13030,7 @@ func rewriteValueS390X_OpS390XRISBGZ(v *Value) bool { break } v.reset(OpS390XSRDconst) - v.AuxInt = int8ToAuxInt(-r.Amount & 63) + v.AuxInt = uint8ToAuxInt(-r.Amount & 63) v.AddArg(x) return true } @@ -13044,7 +13044,7 @@ func rewriteValueS390X_OpS390XRISBGZ(v *Value) bool { break } v.reset(OpS390XSLDconst) - v.AuxInt = int8ToAuxInt(r.Amount) + v.AuxInt = uint8ToAuxInt(r.Amount) v.AddArg(x) return true } @@ -13056,7 +13056,7 @@ func rewriteValueS390X_OpS390XRISBGZ(v *Value) bool { if v_0.Op != OpS390XSRADconst { break } - c := auxIntToInt8(v_0.AuxInt) + c := auxIntToUint8(v_0.AuxInt) x := v_0.Args[0] if !(r.Start == r.End && (r.Start+r.Amount)&63 <= c) { break @@ -13131,7 +13131,7 @@ func rewriteValueS390X_OpS390XRLL(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] // match: (RLL x (MOVDconst [c])) - // result: (RLLconst x [int8(c&31)]) + // result: (RLLconst x [uint8(c&31)]) for { x := v_0 if v_1.Op != OpS390XMOVDconst { @@ -13139,7 +13139,7 @@ func rewriteValueS390X_OpS390XRLL(v *Value) bool { } c := auxIntToInt64(v_1.AuxInt) v.reset(OpS390XRLLconst) - v.AuxInt = int8ToAuxInt(int8(c & 31)) + v.AuxInt = uint8ToAuxInt(uint8(c & 31)) v.AddArg(x) return true } @@ -13149,7 +13149,7 @@ func rewriteValueS390X_OpS390XRLLG(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] // match: (RLLG x (MOVDconst [c])) - // result: (RISBGZ x {s390x.NewRotateParams(0, 63, int8(c&63))}) + // result: (RISBGZ x {s390x.NewRotateParams(0, 63, uint8(c&63))}) for { x := v_0 if v_1.Op != OpS390XMOVDconst { @@ -13157,7 +13157,7 @@ func rewriteValueS390X_OpS390XRLLG(v *Value) bool { } c := auxIntToInt64(v_1.AuxInt) v.reset(OpS390XRISBGZ) - v.Aux = s390xRotateParamsToAux(s390x.NewRotateParams(0, 63, int8(c&63))) + v.Aux = s390xRotateParamsToAux(s390x.NewRotateParams(0, 63, uint8(c&63))) v.AddArg(x) return true } @@ -13169,7 +13169,7 @@ func rewriteValueS390X_OpS390XSLD(v *Value) bool { b := v.Block typ := &b.Func.Config.Types // match: (SLD x (MOVDconst [c])) - // result: (SLDconst x [int8(c&63)]) + // result: (SLDconst x [uint8(c&63)]) for { x := v_0 if v_1.Op != OpS390XMOVDconst { @@ -13177,7 +13177,7 @@ func rewriteValueS390X_OpS390XSLD(v *Value) bool { } c := auxIntToInt64(v_1.AuxInt) v.reset(OpS390XSLDconst) - v.AuxInt = int8ToAuxInt(int8(c & 63)) + v.AuxInt = uint8ToAuxInt(uint8(c & 63)) v.AddArg(x) return true } @@ -13317,16 +13317,16 @@ func rewriteValueS390X_OpS390XSLD(v *Value) bool { func rewriteValueS390X_OpS390XSLDconst(v *Value) bool { v_0 := v.Args[0] // match: (SLDconst (SRDconst x [c]) [d]) - // result: (RISBGZ x {s390x.NewRotateParams(max8(0, c-d), 63-d, (d-c)&63)}) + // result: (RISBGZ x {s390x.NewRotateParams(uint8(max8(0, int8(c-d))), 63-d, uint8(int8(d-c)&63))}) for { - d := auxIntToInt8(v.AuxInt) + d := auxIntToUint8(v.AuxInt) if v_0.Op != OpS390XSRDconst { break } - c := auxIntToInt8(v_0.AuxInt) + c := auxIntToUint8(v_0.AuxInt) x := v_0.Args[0] v.reset(OpS390XRISBGZ) - v.Aux = s390xRotateParamsToAux(s390x.NewRotateParams(max8(0, c-d), 63-d, (d-c)&63)) + v.Aux = s390xRotateParamsToAux(s390x.NewRotateParams(uint8(max8(0, int8(c-d))), 63-d, uint8(int8(d-c)&63))) v.AddArg(x) return true } @@ -13334,7 +13334,7 @@ func rewriteValueS390X_OpS390XSLDconst(v *Value) bool { // cond: s390x.NewRotateParams(0, 63-c, c).InMerge(r.OutMask()) != nil // result: (RISBGZ x {(*s390x.NewRotateParams(0, 63-c, c).InMerge(r.OutMask())).RotateLeft(r.Amount)}) for { - c := auxIntToInt8(v.AuxInt) + c := auxIntToUint8(v.AuxInt) if v_0.Op != OpS390XRISBGZ { break } @@ -13351,7 +13351,7 @@ func rewriteValueS390X_OpS390XSLDconst(v *Value) bool { // match: (SLDconst x [0]) // result: x for { - if auxIntToInt8(v.AuxInt) != 0 { + if auxIntToUint8(v.AuxInt) != 0 { break } x := v_0 @@ -13367,7 +13367,7 @@ func rewriteValueS390X_OpS390XSLW(v *Value) bool { typ := &b.Func.Config.Types // match: (SLW x (MOVDconst [c])) // cond: c&32 == 0 - // result: (SLWconst x [int8(c&31)]) + // result: (SLWconst x [uint8(c&31)]) for { x := v_0 if v_1.Op != OpS390XMOVDconst { @@ -13378,7 +13378,7 @@ func rewriteValueS390X_OpS390XSLW(v *Value) bool { break } v.reset(OpS390XSLWconst) - v.AuxInt = int8ToAuxInt(int8(c & 31)) + v.AuxInt = uint8ToAuxInt(uint8(c & 31)) v.AddArg(x) return true } @@ -13535,7 +13535,7 @@ func rewriteValueS390X_OpS390XSLWconst(v *Value) bool { // match: (SLWconst x [0]) // result: x for { - if auxIntToInt8(v.AuxInt) != 0 { + if auxIntToUint8(v.AuxInt) != 0 { break } x := v_0 @@ -13550,7 +13550,7 @@ func rewriteValueS390X_OpS390XSRAD(v *Value) bool { b := v.Block typ := &b.Func.Config.Types // match: (SRAD x (MOVDconst [c])) - // result: (SRADconst x [int8(c&63)]) + // result: (SRADconst x [uint8(c&63)]) for { x := v_0 if v_1.Op != OpS390XMOVDconst { @@ -13558,7 +13558,7 @@ func rewriteValueS390X_OpS390XSRAD(v *Value) bool { } c := auxIntToInt64(v_1.AuxInt) v.reset(OpS390XSRADconst) - v.AuxInt = int8ToAuxInt(int8(c & 63)) + v.AuxInt = uint8ToAuxInt(uint8(c & 63)) v.AddArg(x) return true } @@ -13700,7 +13700,7 @@ func rewriteValueS390X_OpS390XSRADconst(v *Value) bool { // match: (SRADconst x [0]) // result: x for { - if auxIntToInt8(v.AuxInt) != 0 { + if auxIntToUint8(v.AuxInt) != 0 { break } x := v_0 @@ -13710,7 +13710,7 @@ func rewriteValueS390X_OpS390XSRADconst(v *Value) bool { // match: (SRADconst [c] (MOVDconst [d])) // result: (MOVDconst [d>>uint64(c)]) for { - c := auxIntToInt8(v.AuxInt) + c := auxIntToUint8(v.AuxInt) if v_0.Op != OpS390XMOVDconst { break } @@ -13728,7 +13728,7 @@ func rewriteValueS390X_OpS390XSRAW(v *Value) bool { typ := &b.Func.Config.Types // match: (SRAW x (MOVDconst [c])) // cond: c&32 == 0 - // result: (SRAWconst x [int8(c&31)]) + // result: (SRAWconst x [uint8(c&31)]) for { x := v_0 if v_1.Op != OpS390XMOVDconst { @@ -13739,7 +13739,7 @@ func rewriteValueS390X_OpS390XSRAW(v *Value) bool { break } v.reset(OpS390XSRAWconst) - v.AuxInt = int8ToAuxInt(int8(c & 31)) + v.AuxInt = uint8ToAuxInt(uint8(c & 31)) v.AddArg(x) return true } @@ -13756,7 +13756,7 @@ func rewriteValueS390X_OpS390XSRAW(v *Value) bool { break } v.reset(OpS390XSRAWconst) - v.AuxInt = int8ToAuxInt(31) + v.AuxInt = uint8ToAuxInt(31) v.AddArg(x) return true } @@ -13898,7 +13898,7 @@ func rewriteValueS390X_OpS390XSRAWconst(v *Value) bool { // match: (SRAWconst x [0]) // result: x for { - if auxIntToInt8(v.AuxInt) != 0 { + if auxIntToUint8(v.AuxInt) != 0 { break } x := v_0 @@ -13908,7 +13908,7 @@ func rewriteValueS390X_OpS390XSRAWconst(v *Value) bool { // match: (SRAWconst [c] (MOVDconst [d])) // result: (MOVDconst [int64(int32(d))>>uint64(c)]) for { - c := auxIntToInt8(v.AuxInt) + c := auxIntToUint8(v.AuxInt) if v_0.Op != OpS390XMOVDconst { break } @@ -13925,7 +13925,7 @@ func rewriteValueS390X_OpS390XSRD(v *Value) bool { b := v.Block typ := &b.Func.Config.Types // match: (SRD x (MOVDconst [c])) - // result: (SRDconst x [int8(c&63)]) + // result: (SRDconst x [uint8(c&63)]) for { x := v_0 if v_1.Op != OpS390XMOVDconst { @@ -13933,7 +13933,7 @@ func rewriteValueS390X_OpS390XSRD(v *Value) bool { } c := auxIntToInt64(v_1.AuxInt) v.reset(OpS390XSRDconst) - v.AuxInt = int8ToAuxInt(int8(c & 63)) + v.AuxInt = uint8ToAuxInt(uint8(c & 63)) v.AddArg(x) return true } @@ -14073,16 +14073,16 @@ func rewriteValueS390X_OpS390XSRD(v *Value) bool { func rewriteValueS390X_OpS390XSRDconst(v *Value) bool { v_0 := v.Args[0] // match: (SRDconst (SLDconst x [c]) [d]) - // result: (RISBGZ x {s390x.NewRotateParams(d, min8(63, 63-c+d), (c-d)&63)}) + // result: (RISBGZ x {s390x.NewRotateParams(d, uint8(min8(63, int8(63-c+d))), uint8(int8(c-d)&63))}) for { - d := auxIntToInt8(v.AuxInt) + d := auxIntToUint8(v.AuxInt) if v_0.Op != OpS390XSLDconst { break } - c := auxIntToInt8(v_0.AuxInt) + c := auxIntToUint8(v_0.AuxInt) x := v_0.Args[0] v.reset(OpS390XRISBGZ) - v.Aux = s390xRotateParamsToAux(s390x.NewRotateParams(d, min8(63, 63-c+d), (c-d)&63)) + v.Aux = s390xRotateParamsToAux(s390x.NewRotateParams(d, uint8(min8(63, int8(63-c+d))), uint8(int8(c-d)&63))) v.AddArg(x) return true } @@ -14090,7 +14090,7 @@ func rewriteValueS390X_OpS390XSRDconst(v *Value) bool { // cond: s390x.NewRotateParams(c, 63, -c&63).InMerge(r.OutMask()) != nil // result: (RISBGZ x {(*s390x.NewRotateParams(c, 63, -c&63).InMerge(r.OutMask())).RotateLeft(r.Amount)}) for { - c := auxIntToInt8(v.AuxInt) + c := auxIntToUint8(v.AuxInt) if v_0.Op != OpS390XRISBGZ { break } @@ -14107,7 +14107,7 @@ func rewriteValueS390X_OpS390XSRDconst(v *Value) bool { // match: (SRDconst x [0]) // result: x for { - if auxIntToInt8(v.AuxInt) != 0 { + if auxIntToUint8(v.AuxInt) != 0 { break } x := v_0 @@ -14123,7 +14123,7 @@ func rewriteValueS390X_OpS390XSRW(v *Value) bool { typ := &b.Func.Config.Types // match: (SRW x (MOVDconst [c])) // cond: c&32 == 0 - // result: (SRWconst x [int8(c&31)]) + // result: (SRWconst x [uint8(c&31)]) for { x := v_0 if v_1.Op != OpS390XMOVDconst { @@ -14134,7 +14134,7 @@ func rewriteValueS390X_OpS390XSRW(v *Value) bool { break } v.reset(OpS390XSRWconst) - v.AuxInt = int8ToAuxInt(int8(c & 31)) + v.AuxInt = uint8ToAuxInt(uint8(c & 31)) v.AddArg(x) return true } @@ -14291,7 +14291,7 @@ func rewriteValueS390X_OpS390XSRWconst(v *Value) bool { // match: (SRWconst x [0]) // result: x for { - if auxIntToInt8(v.AuxInt) != 0 { + if auxIntToUint8(v.AuxInt) != 0 { break } x := v_0 @@ -14339,7 +14339,7 @@ func rewriteValueS390X_OpS390XSTM2(v *Value) bool { i := auxIntToInt32(v.AuxInt) s := auxToSym(v.Aux) p := v_0 - if v_1.Op != OpS390XSRDconst || auxIntToInt8(v_1.AuxInt) != 32 { + if v_1.Op != OpS390XSRDconst || auxIntToUint8(v_1.AuxInt) != 32 { break } x := v_1.Args[0] @@ -14851,7 +14851,7 @@ func rewriteValueS390X_OpS390XSumBytes2(v *Value) bool { x := v_0 v.reset(OpS390XADDW) v0 := b.NewValue0(v.Pos, OpS390XSRWconst, typ.UInt8) - v0.AuxInt = int8ToAuxInt(8) + v0.AuxInt = uint8ToAuxInt(8) v0.AddArg(x) v.AddArg2(v0, x) return true @@ -14868,7 +14868,7 @@ func rewriteValueS390X_OpS390XSumBytes4(v *Value) bool { v.reset(OpS390XSumBytes2) v0 := b.NewValue0(v.Pos, OpS390XADDW, typ.UInt16) v1 := b.NewValue0(v.Pos, OpS390XSRWconst, typ.UInt16) - v1.AuxInt = int8ToAuxInt(16) + v1.AuxInt = uint8ToAuxInt(16) v1.AddArg(x) v0.AddArg2(v1, x) v.AddArg(v0) @@ -14886,7 +14886,7 @@ func rewriteValueS390X_OpS390XSumBytes8(v *Value) bool { v.reset(OpS390XSumBytes4) v0 := b.NewValue0(v.Pos, OpS390XADDW, typ.UInt32) v1 := b.NewValue0(v.Pos, OpS390XSRDconst, typ.UInt32) - v1.AuxInt = int8ToAuxInt(32) + v1.AuxInt = uint8ToAuxInt(32) v1.AddArg(x) v0.AddArg2(v1, x) v.AddArg(v0) @@ -14923,9 +14923,9 @@ func rewriteValueS390X_OpS390XXOR(v *Value) bool { if v_0.Op != OpS390XSLDconst { continue } - c := auxIntToInt8(v_0.AuxInt) + c := auxIntToUint8(v_0.AuxInt) x := v_0.Args[0] - if v_1.Op != OpS390XSRDconst || auxIntToInt8(v_1.AuxInt) != 64-c || x != v_1.Args[0] { + if v_1.Op != OpS390XSRDconst || auxIntToUint8(v_1.AuxInt) != 64-c || x != v_1.Args[0] { continue } v.reset(OpS390XRISBGZ) @@ -15019,13 +15019,13 @@ func rewriteValueS390X_OpS390XXORW(v *Value) bool { if v_0.Op != OpS390XSLWconst { continue } - c := auxIntToInt8(v_0.AuxInt) + c := auxIntToUint8(v_0.AuxInt) x := v_0.Args[0] - if v_1.Op != OpS390XSRWconst || auxIntToInt8(v_1.AuxInt) != 32-c || x != v_1.Args[0] { + if v_1.Op != OpS390XSRWconst || auxIntToUint8(v_1.AuxInt) != 32-c || x != v_1.Args[0] { continue } v.reset(OpS390XRLLconst) - v.AuxInt = int8ToAuxInt(c) + v.AuxInt = uint8ToAuxInt(c) v.AddArg(x) return true } @@ -15649,7 +15649,7 @@ func rewriteValueS390X_OpSlicemask(v *Value) bool { t := v.Type x := v_0 v.reset(OpS390XSRADconst) - v.AuxInt = int8ToAuxInt(63) + v.AuxInt = uint8ToAuxInt(63) v0 := b.NewValue0(v.Pos, OpS390XNEG, t) v0.AddArg(x) v.AddArg(v0) diff --git a/src/cmd/internal/obj/s390x/rotate.go b/src/cmd/internal/obj/s390x/rotate.go index 7dbc45e648..388bd40f41 100644 --- a/src/cmd/internal/obj/s390x/rotate.go +++ b/src/cmd/internal/obj/s390x/rotate.go @@ -28,9 +28,9 @@ import ( // input left by. Note that this rotation is performed // before the masked region is used. type RotateParams struct { - Start int8 // big-endian start bit index [0..63] - End int8 // big-endian end bit index [0..63] - Amount int8 // amount to rotate left + Start uint8 // big-endian start bit index [0..63] + End uint8 // big-endian end bit index [0..63] + Amount uint8 // amount to rotate left } // NewRotateParams creates a set of parameters representing a @@ -39,7 +39,7 @@ type RotateParams struct { // // The start and end indexes and the rotation amount must all // be in the range 0-63 inclusive or this function will panic. -func NewRotateParams(start, end, amount int8) RotateParams { +func NewRotateParams(start, end, amount uint8) RotateParams { if start&^63 != 0 { panic("start out of bounds") } @@ -58,7 +58,7 @@ func NewRotateParams(start, end, amount int8) RotateParams { // RotateLeft generates a new set of parameters with the rotation amount // increased by the given value. The selected bits are left unchanged. -func (r RotateParams) RotateLeft(amount int8) RotateParams { +func (r RotateParams) RotateLeft(amount uint8) RotateParams { r.Amount += amount r.Amount &= 63 return r @@ -100,8 +100,8 @@ func (r RotateParams) OutMerge(mask uint64) *RotateParams { } // update start and end positions (rotation amount remains the same) - r.Start = int8(o+z) & 63 - r.End = (r.Start + int8(l) - 1) & 63 + r.Start = uint8(o+z) & 63 + r.End = (r.Start + uint8(l) - 1) & 63 return &r } diff --git a/src/cmd/internal/obj/s390x/rotate_test.go b/src/cmd/internal/obj/s390x/rotate_test.go index fa5b5bdecd..88421b1b83 100644 --- a/src/cmd/internal/obj/s390x/rotate_test.go +++ b/src/cmd/internal/obj/s390x/rotate_test.go @@ -10,7 +10,7 @@ import ( func TestRotateParamsMask(t *testing.T) { tests := []struct { - start, end, amount int8 + start, end, amount uint8 inMask, outMask uint64 }{ // start before end, no rotation -- cgit v1.3-5-g9baa From f4e7a6b905ce60448e506a3f6578d01b60602cdd Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Tue, 15 Dec 2020 15:54:25 -0500 Subject: cmd/internal/goobj: fix buglet in object file reader The code in the new (introduced in 1.15) Go object file reader was casting a pointer-mmaped-memory into a large array prior to performing a read of the relocations section: return (*[1<<20]Reloc)(unsafe.Pointer(&r.b[off]))[:n:n] For very large object files, this artificial array isn't large enough (that is, there are more than 1048576 relocs to read), so update the code to use a larger artifical array size. Fixes #41621. Change-Id: Ic047c8aef4f8a3839f2e7e3594bce652ebd6bd5b Reviewed-on: https://go-review.googlesource.com/c/go/+/278492 Run-TryBot: Than McIntosh TryBot-Result: Go Bot Reviewed-by: Cherry Zhang Reviewed-by: Jeremy Faller Trust: Than McIntosh --- src/cmd/internal/goobj/objfile.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src/cmd/internal') diff --git a/src/cmd/internal/goobj/objfile.go b/src/cmd/internal/goobj/objfile.go index 6e76bea111..e6447e455d 100644 --- a/src/cmd/internal/goobj/objfile.go +++ b/src/cmd/internal/goobj/objfile.go @@ -483,6 +483,11 @@ func (r *RefFlags) SetFlag2(x uint8) { r[9] = x } func (r *RefFlags) Write(w *Writer) { w.Bytes(r[:]) } +// Used to construct an artifically large array type when reading an +// item from the object file relocs section or aux sym section (needs +// to work on 32-bit as well as 64-bit). See issue 41621. +const huge = (1<<31 - 1) / RelocSize + // Referenced symbol name. // // Serialized format: @@ -792,7 +797,7 @@ func (r *Reader) Reloc(i uint32, j int) *Reloc { func (r *Reader) Relocs(i uint32) []Reloc { off := r.RelocOff(i, 0) n := r.NReloc(i) - return (*[1 << 20]Reloc)(unsafe.Pointer(&r.b[off]))[:n:n] + return (*[huge]Reloc)(unsafe.Pointer(&r.b[off]))[:n:n] } // NAux returns the number of aux symbols of the i-th symbol. @@ -818,7 +823,7 @@ func (r *Reader) Aux(i uint32, j int) *Aux { func (r *Reader) Auxs(i uint32) []Aux { off := r.AuxOff(i, 0) n := r.NAux(i) - return (*[1 << 20]Aux)(unsafe.Pointer(&r.b[off]))[:n:n] + return (*[huge]Aux)(unsafe.Pointer(&r.b[off]))[:n:n] } // DataOff returns the offset of the i-th symbol's data. -- cgit v1.3-5-g9baa From 2153a99914c3c24b98cd4cfccd1d2f670273a4ac Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 21 Dec 2020 01:14:36 -0500 Subject: [dev.regabi] cmd/compile: setup to move Addrconst, Patch into cmd/internal/obj Deleting the Pc assignment from Patch is safe because the actual PCs are not assigned until well after the compiler is done patching jumps. And it proves that replacing uses of Patch with SetTarget will be safe later. Change-Id: Iffcbe03f0b5949ccd4c91e79c1272cd06be0f434 Reviewed-on: https://go-review.googlesource.com/c/go/+/279296 Trust: Russ Cox Run-TryBot: Russ Cox TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/gc/gsubr.go | 8 +------- src/cmd/internal/obj/link.go | 6 ++++++ 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src/cmd/internal') diff --git a/src/cmd/compile/internal/gc/gsubr.go b/src/cmd/compile/internal/gc/gsubr.go index 79ca669dfb..ddb431d5ab 100644 --- a/src/cmd/compile/internal/gc/gsubr.go +++ b/src/cmd/compile/internal/gc/gsubr.go @@ -321,15 +321,9 @@ func ggloblsym(s *obj.LSym, width int32, flags int16) { } func Addrconst(a *obj.Addr, v int64) { - a.Sym = nil - a.Type = obj.TYPE_CONST - a.Offset = v + a.SetConst(v) } func Patch(p *obj.Prog, to *obj.Prog) { - if p.To.Type != obj.TYPE_BRANCH { - base.Fatalf("patch: not a branch") - } p.To.SetTarget(to) - p.To.Offset = to.Pc } diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go index eaebfaf4b6..7b5c990a5d 100644 --- a/src/cmd/internal/obj/link.go +++ b/src/cmd/internal/obj/link.go @@ -250,6 +250,12 @@ func (a *Addr) SetTarget(t *Prog) { a.Val = t } +func (a *Addr) SetConst(v int64) { + a.Sym = nil + a.Type = TYPE_CONST + a.Offset = v +} + // Prog describes a single machine instruction. // // The general instruction form is: -- cgit v1.3-5-g9baa From cb28c96be8b8010dd979e0723bf5a94b11962a93 Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Thu, 24 Sep 2020 13:14:46 -0400 Subject: [dev.regabi] cmd/compile,cmd/link: initial support for ABI wrappers Add compiler support for emitting ABI wrappers by creating real IR as opposed to introducing ABI aliases. At the moment these are "no-op" wrappers in the sense that they make a simple call (using the existing ABI) to their target. The assumption here is that once late call expansion can handle both ABI0 and the "new" ABIInternal (register version), it can expand the call to do the right thing. Note that the runtime contains functions that do not strictly follow the rules of the current Go ABI0; this has been handled in most cases by treating these as ABIInternal instead (these changes have been made in previous patches). Generation of ABI wrappers (as opposed to ABI aliases) is currently gated by GOEXPERIMENT=regabi -- wrapper generation is on by default if GOEXPERIMENT=regabi is set and off otherwise (but can be turned on using "-gcflags=all=-abiwrap -ldflags=-abiwrap"). Wrapper generation currently only workd on AMD64; explicitly enabling wrapper for other architectures (via the command line) is not supported. Also in this patch are a few other command line options for debugging (tracing and/or limiting wrapper creation). These will presumably go away at some point. Updates #27539, #40724. Change-Id: I1ee3226fc15a3c32ca2087b8ef8e41dbe6df4a75 Reviewed-on: https://go-review.googlesource.com/c/go/+/270863 Run-TryBot: Than McIntosh TryBot-Result: Go Bot Reviewed-by: Cherry Zhang Trust: Than McIntosh --- src/cmd/compile/internal/base/debug.go | 1 + src/cmd/compile/internal/base/flag.go | 3 + src/cmd/compile/internal/gc/gsubr.go | 191 +++++++++++++++++++++++++++----- src/cmd/compile/internal/gc/main.go | 23 ++++ src/cmd/compile/internal/gc/pgen.go | 7 +- src/cmd/compile/internal/gc/racewalk.go | 2 +- src/cmd/compile/internal/gc/ssa.go | 49 +++++++- src/cmd/compile/internal/types/sym.go | 17 +++ src/cmd/internal/obj/link.go | 6 + src/cmd/internal/obj/plist.go | 6 + src/cmd/internal/obj/textflag.go | 3 + src/cmd/internal/obj/x86/obj6.go | 4 +- src/cmd/link/internal/ld/main.go | 12 +- src/cmd/link/internal/ld/symtab.go | 37 ++++++- src/runtime/textflag.h | 2 + test/nosplit.go | 9 +- 16 files changed, 328 insertions(+), 44 deletions(-) (limited to 'src/cmd/internal') diff --git a/src/cmd/compile/internal/base/debug.go b/src/cmd/compile/internal/base/debug.go index 45a552a4d9..3acdcea846 100644 --- a/src/cmd/compile/internal/base/debug.go +++ b/src/cmd/compile/internal/base/debug.go @@ -51,6 +51,7 @@ type DebugFlags struct { TypeAssert int `help:"print information about type assertion inlining"` TypecheckInl int `help:"eager typechecking of inline function bodies"` WB int `help:"print information about write barriers"` + ABIWrap int `help:"print information about ABI wrapper generation"` any bool // set when any of the values have been set } diff --git a/src/cmd/compile/internal/base/flag.go b/src/cmd/compile/internal/base/flag.go index aadc70f496..ce87ff730e 100644 --- a/src/cmd/compile/internal/base/flag.go +++ b/src/cmd/compile/internal/base/flag.go @@ -81,6 +81,8 @@ type CmdFlags struct { CompilingRuntime bool "flag:\"+\" help:\"compiling runtime\"" // Longer names + ABIWrap bool "help:\"enable generation of ABI wrappers\"" + ABIWrapLimit int "help:\"emit at most N ABI wrappers (for debugging)\"" AsmHdr string "help:\"write assembly header to `file`\"" Bench string "help:\"append benchmark times to `file`\"" BlockProfile string "help:\"write block profile to `file`\"" @@ -140,6 +142,7 @@ func ParseFlags() { Flag.LowerP = &Ctxt.Pkgpath Flag.LowerV = &Ctxt.Debugvlog + Flag.ABIWrap = objabi.Regabi_enabled != 0 Flag.Dwarf = objabi.GOARCH != "wasm" Flag.DwarfBASEntries = &Ctxt.UseBASEntries Flag.DwarfLocationLists = &Ctxt.Flag_locationlists diff --git a/src/cmd/compile/internal/gc/gsubr.go b/src/cmd/compile/internal/gc/gsubr.go index ddb431d5ab..f3ef14c99b 100644 --- a/src/cmd/compile/internal/gc/gsubr.go +++ b/src/cmd/compile/internal/gc/gsubr.go @@ -34,9 +34,12 @@ import ( "cmd/compile/internal/base" "cmd/compile/internal/ir" "cmd/compile/internal/ssa" + "cmd/compile/internal/types" "cmd/internal/obj" "cmd/internal/objabi" "cmd/internal/src" + "fmt" + "os" ) var sharedProgArray = new([10000]obj.Prog) // *T instead of T to work around issue 19839 @@ -187,32 +190,154 @@ func (pp *Progs) settext(fn *ir.Func) { ptxt.From.Sym = fn.LSym } +// makeABIWrapper creates a new function that wraps a cross-ABI call +// to "f". The wrapper is marked as an ABIWRAPPER. +func makeABIWrapper(f *ir.Func, wrapperABI obj.ABI) { + + // Q: is this needed? + savepos := base.Pos + savedclcontext := dclcontext + savedcurfn := Curfn + + base.Pos = autogeneratedPos + dclcontext = ir.PEXTERN + + // At the moment we don't support wrapping a method, we'd need machinery + // below to handle the receiver. Panic if we see this scenario. + ft := f.Nname.Ntype.Type() + if ft.NumRecvs() != 0 { + panic("makeABIWrapper support for wrapping methods not implemented") + } + + // Manufacture a new func type to use for the wrapper. + var noReceiver *ir.Field + tfn := ir.NewFuncType(base.Pos, + noReceiver, + structargs(ft.Params(), true), + structargs(ft.Results(), false)) + + // Reuse f's types.Sym to create a new ODCLFUNC/function. + fn := dclfunc(f.Nname.Sym(), tfn) + fn.SetDupok(true) + fn.SetWrapper(true) // ignore frame for panic+recover matching + + // Select LSYM now. + asym := base.Ctxt.LookupABI(f.LSym.Name, wrapperABI) + asym.Type = objabi.STEXT + if fn.LSym != nil { + panic("unexpected") + } + fn.LSym = asym + + // ABI0-to-ABIInternal wrappers will be mainly loading params from + // stack into registers (and/or storing stack locations back to + // registers after the wrapped call); in most cases they won't + // need to allocate stack space, so it should be OK to mark them + // as NOSPLIT in these cases. In addition, my assumption is that + // functions written in assembly are NOSPLIT in most (but not all) + // cases. In the case of an ABIInternal target that has too many + // parameters to fit into registers, the wrapper would need to + // allocate stack space, but this seems like an unlikely scenario. + // Hence: mark these wrappers NOSPLIT. + // + // ABIInternal-to-ABI0 wrappers on the other hand will be taking + // things in registers and pushing them onto the stack prior to + // the ABI0 call, meaning that they will always need to allocate + // stack space. If the compiler marks them as NOSPLIT this seems + // as though it could lead to situations where the the linker's + // nosplit-overflow analysis would trigger a link failure. On the + // other hand if they not tagged NOSPLIT then this could cause + // problems when building the runtime (since there may be calls to + // asm routine in cases where it's not safe to grow the stack). In + // most cases the wrapper would be (in effect) inlined, but are + // there (perhaps) indirect calls from the runtime that could run + // into trouble here. + // FIXME: at the moment all.bash does not pass when I leave out + // NOSPLIT for these wrappers, so all are currently tagged with NOSPLIT. + setupTextLSym(fn, obj.NOSPLIT|obj.ABIWRAPPER) + + // Generate call. Use tail call if no params and no returns, + // but a regular call otherwise. + // + // Note: ideally we would be using a tail call in cases where + // there are params but no returns for ABI0->ABIInternal wrappers, + // provided that all params fit into registers (e.g. we don't have + // to allocate any stack space). Doing this will require some + // extra work in typecheck/walk/ssa, might want to add a new node + // OTAILCALL or something to this effect. + var call ir.Node + if tfn.Type().NumResults() == 0 && tfn.Type().NumParams() == 0 && tfn.Type().NumRecvs() == 0 { + call = nodSym(ir.ORETJMP, nil, f.Nname.Sym()) + } else { + call = ir.Nod(ir.OCALL, f.Nname, nil) + call.PtrList().Set(paramNnames(tfn.Type())) + call.SetIsDDD(tfn.Type().IsVariadic()) + if tfn.Type().NumResults() > 0 { + n := ir.Nod(ir.ORETURN, nil, nil) + n.PtrList().Set1(call) + call = n + } + } + fn.PtrBody().Append(call) + + funcbody() + if base.Debug.DclStack != 0 { + testdclstack() + } + + typecheckFunc(fn) + Curfn = fn + typecheckslice(fn.Body().Slice(), ctxStmt) + + escapeFuncs([]*ir.Func{fn}, false) + + Target.Decls = append(Target.Decls, fn) + + // Restore previous context. + base.Pos = savepos + dclcontext = savedclcontext + Curfn = savedcurfn +} + // initLSym defines f's obj.LSym and initializes it based on the // properties of f. This includes setting the symbol flags and ABI and // creating and initializing related DWARF symbols. // // initLSym must be called exactly once per function and must be // called for both functions with bodies and functions without bodies. +// For body-less functions, we only create the LSym; for functions +// with bodies call a helper to setup up / populate the LSym. func initLSym(f *ir.Func, hasBody bool) { + // FIXME: for new-style ABI wrappers, we set up the lsym at the + // point the wrapper is created. + if f.LSym != nil && base.Flag.ABIWrap { + return + } + selectLSym(f, hasBody) + if hasBody { + setupTextLSym(f, 0) + } +} + +// selectLSym sets up the LSym for a given function, and +// makes calls to helpers to create ABI wrappers if needed. +func selectLSym(f *ir.Func, hasBody bool) { if f.LSym != nil { base.Fatalf("Func.initLSym called twice") } if nam := f.Nname; !ir.IsBlank(nam) { - f.LSym = nam.Sym().Linksym() - if f.Pragma&ir.Systemstack != 0 { - f.LSym.Set(obj.AttrCFunc, true) - } - var aliasABI obj.ABI - needABIAlias := false - defABI, hasDefABI := symabiDefs[f.LSym.Name] + var wrapperABI obj.ABI + needABIWrapper := false + defABI, hasDefABI := symabiDefs[nam.Sym().LinksymName()] if hasDefABI && defABI == obj.ABI0 { // Symbol is defined as ABI0. Create an // Internal -> ABI0 wrapper. - f.LSym.SetABI(obj.ABI0) - needABIAlias, aliasABI = true, obj.ABIInternal + f.LSym = nam.Sym().LinksymABI0() + needABIWrapper, wrapperABI = true, obj.ABIInternal } else { + f.LSym = nam.Sym().Linksym() // No ABI override. Check that the symbol is // using the expected ABI. want := obj.ABIInternal @@ -220,6 +345,9 @@ func initLSym(f *ir.Func, hasBody bool) { base.Fatalf("function symbol %s has the wrong ABI %v, expected %v", f.LSym.Name, f.LSym.ABI(), want) } } + if f.Pragma&ir.Systemstack != 0 { + f.LSym.Set(obj.AttrCFunc, true) + } isLinknameExported := nam.Sym().Linkname != "" && (hasBody || hasDefABI) if abi, ok := symabiRefs[f.LSym.Name]; (ok && abi == obj.ABI0) || isLinknameExported { @@ -235,32 +363,39 @@ func initLSym(f *ir.Func, hasBody bool) { // using linkname and we don't want to create // duplicate ABI wrappers. if f.LSym.ABI() != obj.ABI0 { - needABIAlias, aliasABI = true, obj.ABI0 + needABIWrapper, wrapperABI = true, obj.ABI0 } } - if needABIAlias { - // These LSyms have the same name as the - // native function, so we create them directly - // rather than looking them up. The uniqueness - // of f.lsym ensures uniqueness of asym. - asym := &obj.LSym{ - Name: f.LSym.Name, - Type: objabi.SABIALIAS, - R: []obj.Reloc{{Sym: f.LSym}}, // 0 size, so "informational" + if needABIWrapper { + if !useABIWrapGen(f) { + // Fallback: use alias instead. FIXME. + + // These LSyms have the same name as the + // native function, so we create them directly + // rather than looking them up. The uniqueness + // of f.lsym ensures uniqueness of asym. + asym := &obj.LSym{ + Name: f.LSym.Name, + Type: objabi.SABIALIAS, + R: []obj.Reloc{{Sym: f.LSym}}, // 0 size, so "informational" + } + asym.SetABI(wrapperABI) + asym.Set(obj.AttrDuplicateOK, true) + base.Ctxt.ABIAliases = append(base.Ctxt.ABIAliases, asym) + } else { + if base.Debug.ABIWrap != 0 { + fmt.Fprintf(os.Stderr, "=-= %v to %v wrapper for %s.%s\n", + wrapperABI, 1-wrapperABI, types.LocalPkg.Path, f.LSym.Name) + } + makeABIWrapper(f, wrapperABI) } - asym.SetABI(aliasABI) - asym.Set(obj.AttrDuplicateOK, true) - base.Ctxt.ABIAliases = append(base.Ctxt.ABIAliases, asym) } } +} - if !hasBody { - // For body-less functions, we only create the LSym. - return - } - - var flag int +// setupTextLsym initializes the LSym for a with-body text symbol. +func setupTextLSym(f *ir.Func, flag int) { if f.Dupok() { flag |= obj.DUPOK } diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index 7f7cd63cdf..de2b3db36a 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -1144,3 +1144,26 @@ func initializeTypesPackage() { initUniverse() } + +// useNewABIWrapGen returns TRUE if the compiler should generate an +// ABI wrapper for the function 'f'. +func useABIWrapGen(f *ir.Func) bool { + if !base.Flag.ABIWrap { + return false + } + + // Support limit option for bisecting. + if base.Flag.ABIWrapLimit == 1 { + return false + } + if base.Flag.ABIWrapLimit < 1 { + return true + } + base.Flag.ABIWrapLimit-- + if base.Debug.ABIWrap != 0 && base.Flag.ABIWrapLimit == 1 { + fmt.Fprintf(os.Stderr, "=-= limit reached after new wrapper for %s\n", + f.LSym.Name) + } + + return true +} diff --git a/src/cmd/compile/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go index 5b5288c389..dae9d79147 100644 --- a/src/cmd/compile/internal/gc/pgen.go +++ b/src/cmd/compile/internal/gc/pgen.go @@ -32,7 +32,6 @@ func emitptrargsmap(fn *ir.Func) { return } lsym := base.Ctxt.Lookup(fn.LSym.Name + ".args_stackmap") - nptr := int(fn.Type().ArgWidth() / int64(Widthptr)) bv := bvalloc(int32(nptr) * 2) nbitmap := 1 @@ -399,7 +398,11 @@ func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.S fn := curfn.(*ir.Func) if fn.Nname != nil { - if expect := fn.Sym().Linksym(); fnsym != expect { + expect := fn.Sym().Linksym() + if fnsym.ABI() == obj.ABI0 { + expect = fn.Sym().LinksymABI0() + } + if fnsym != expect { base.Fatalf("unexpected fnsym: %v != %v", fnsym, expect) } } diff --git a/src/cmd/compile/internal/gc/racewalk.go b/src/cmd/compile/internal/gc/racewalk.go index 472deb16e3..61a65368af 100644 --- a/src/cmd/compile/internal/gc/racewalk.go +++ b/src/cmd/compile/internal/gc/racewalk.go @@ -61,7 +61,7 @@ func ispkgin(pkgs []string) bool { } func instrument(fn *ir.Func) { - if fn.Pragma&ir.Norace != 0 { + if fn.Pragma&ir.Norace != 0 || (fn.Sym().Linksym() != nil && fn.Sym().Linksym().ABIWrapper()) { return } diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index a5340e7f11..b4cf8b6dc7 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -1421,7 +1421,7 @@ func (s *state) stmt(n ir.Node) { case ir.ORETJMP: b := s.exit() b.Kind = ssa.BlockRetJmp // override BlockRet - b.Aux = n.Sym().Linksym() + b.Aux = callTargetLSym(n.Sym(), s.curfn.LSym) case ir.OCONTINUE, ir.OBREAK: var to *ssa.Block @@ -4826,11 +4826,11 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val } case sym != nil: if testLateExpansion { - aux := ssa.StaticAuxCall(sym.Linksym(), ACArgs, ACResults) + aux := ssa.StaticAuxCall(callTargetLSym(sym, s.curfn.LSym), ACArgs, ACResults) call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux) call.AddArgs(callArgs...) } else { - call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(sym.Linksym(), ACArgs, ACResults), s.mem()) + call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(callTargetLSym(sym, s.curfn.LSym), ACArgs, ACResults), s.mem()) } default: s.Fatalf("bad call type %v %v", n.Op(), n) @@ -7291,3 +7291,46 @@ func clobberBase(n ir.Node) ir.Node { } return n } + +// callTargetLSym determines the correct LSym for 'callee' when called +// from function 'caller'. There are a couple of different scenarios +// to contend with here: +// +// 1. if 'caller' is an ABI wrapper, then we always want to use the +// LSym from the Func for the callee. +// +// 2. if 'caller' is not an ABI wrapper, then we looked at the callee +// to see if it corresponds to a "known" ABI0 symbol (e.g. assembly +// routine defined in the current package); if so, we want the call to +// directly target the ABI0 symbol (effectively bypassing the +// ABIInternal->ABI0 wrapper for 'callee'). +// +// 3. in all other cases, want the regular ABIInternal linksym +// +func callTargetLSym(callee *types.Sym, callerLSym *obj.LSym) *obj.LSym { + lsym := callee.Linksym() + if !base.Flag.ABIWrap { + return lsym + } + if ir.AsNode(callee.Def) == nil { + return lsym + } + ndclfunc := ir.AsNode(callee.Def).Name().Defn + if ndclfunc == nil { + return lsym + } + // check for case 1 above + if callerLSym.ABIWrapper() { + if nlsym := ndclfunc.Func().LSym; nlsym != nil { + lsym = nlsym + } + } else { + // check for case 2 above + nam := ndclfunc.Func().Nname + defABI, hasDefABI := symabiDefs[nam.Sym().LinksymName()] + if hasDefABI && defABI == obj.ABI0 { + lsym = nam.Sym().LinksymABI0() + } + } + return lsym +} diff --git a/src/cmd/compile/internal/types/sym.go b/src/cmd/compile/internal/types/sym.go index 19f06fcf5b..c512e3a003 100644 --- a/src/cmd/compile/internal/types/sym.go +++ b/src/cmd/compile/internal/types/sym.go @@ -93,6 +93,23 @@ func (sym *Sym) Linksym() *obj.LSym { return base.Ctxt.LookupInit(sym.LinksymName(), initPkg) } +// LinksymABI0 looks up or creates an ABI0 linker symbol for "sym", +// in cases where we want to specifically select the ABI0 version of +// a symbol (typically used only for ABI wrappers). +func (sym *Sym) LinksymABI0() *obj.LSym { + if sym == nil { + return nil + } + initPkg := func(r *obj.LSym) { + if sym.Linkname != "" { + r.Pkg = "_" + } else { + r.Pkg = sym.Pkg.Prefix + } + } + return base.Ctxt.LookupABIInit(sym.LinksymName(), obj.ABI0, initPkg) +} + // Less reports whether symbol a is ordered before symbol b. // // Symbols are ordered exported before non-exported, then by name, and diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go index 7b5c990a5d..977c5c3303 100644 --- a/src/cmd/internal/obj/link.go +++ b/src/cmd/internal/obj/link.go @@ -635,6 +635,10 @@ const ( // ContentAddressable indicates this is a content-addressable symbol. AttrContentAddressable + // ABI wrapper is set for compiler-generated text symbols that + // convert between ABI0 and ABIInternal calling conventions. + AttrABIWrapper + // attrABIBase is the value at which the ABI is encoded in // Attribute. This must be last; all bits after this are // assumed to be an ABI value. @@ -660,6 +664,7 @@ func (a Attribute) TopFrame() bool { return a&AttrTopFrame != 0 } func (a Attribute) Indexed() bool { return a&AttrIndexed != 0 } func (a Attribute) UsedInIface() bool { return a&AttrUsedInIface != 0 } func (a Attribute) ContentAddressable() bool { return a&AttrContentAddressable != 0 } +func (a Attribute) ABIWrapper() bool { return a&AttrABIWrapper != 0 } func (a *Attribute) Set(flag Attribute, value bool) { if value { @@ -695,6 +700,7 @@ var textAttrStrings = [...]struct { {bit: AttrTopFrame, s: "TOPFRAME"}, {bit: AttrIndexed, s: ""}, {bit: AttrContentAddressable, s: ""}, + {bit: AttrABIWrapper, s: "ABIWRAPPER"}, } // TextAttrString formats a for printing in as part of a TEXT prog. diff --git a/src/cmd/internal/obj/plist.go b/src/cmd/internal/obj/plist.go index 2b096996f7..679ce7eb8f 100644 --- a/src/cmd/internal/obj/plist.go +++ b/src/cmd/internal/obj/plist.go @@ -80,6 +80,11 @@ func Flushplist(ctxt *Link, plist *Plist, newprog ProgAlloc, myimportpath string if !strings.HasPrefix(s.Name, "\"\".") { continue } + if s.ABIWrapper() { + // Don't create an args_stackmap symbol reference for an ABI + // wrapper function + continue + } found := false for p := s.Func().Text; p != nil; p = p.Link { if p.As == AFUNCDATA && p.From.Type == TYPE_CONST && p.From.Offset == objabi.FUNCDATA_ArgsPointerMaps { @@ -134,6 +139,7 @@ func (ctxt *Link) InitTextSym(s *LSym, flag int) { s.Set(AttrNoSplit, flag&NOSPLIT != 0) s.Set(AttrReflectMethod, flag&REFLECTMETHOD != 0) s.Set(AttrWrapper, flag&WRAPPER != 0) + s.Set(AttrABIWrapper, flag&ABIWRAPPER != 0) s.Set(AttrNeedCtxt, flag&NEEDCTXT != 0) s.Set(AttrNoFrame, flag&NOFRAME != 0) s.Set(AttrTopFrame, flag&TOPFRAME != 0) diff --git a/src/cmd/internal/obj/textflag.go b/src/cmd/internal/obj/textflag.go index d2cec734b1..fcc4014aa2 100644 --- a/src/cmd/internal/obj/textflag.go +++ b/src/cmd/internal/obj/textflag.go @@ -51,4 +51,7 @@ const ( // Function is the top of the call stack. Call stack unwinders should stop // at this function. TOPFRAME = 2048 + + // Function is an ABI wrapper. + ABIWRAPPER = 4096 ) diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go index 184fb4308b..839aeb8fe3 100644 --- a/src/cmd/internal/obj/x86/obj6.go +++ b/src/cmd/internal/obj/x86/obj6.go @@ -637,7 +637,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { } } - if !p.From.Sym.NoSplit() || p.From.Sym.Wrapper() { + if !p.From.Sym.NoSplit() || (p.From.Sym.Wrapper() && !p.From.Sym.ABIWrapper()) { p = obj.Appendp(p, newprog) p = load_g_cx(ctxt, p, newprog) // load g into CX } @@ -690,7 +690,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { p.To.Reg = REG_BP } - if cursym.Func().Text.From.Sym.Wrapper() { + if cursym.Func().Text.From.Sym.Wrapper() && !cursym.Func().Text.From.Sym.ABIWrapper() { // if g._panic != nil && g._panic.argp == FP { // g._panic.argp = bottom-of-frame // } diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go index 5c8293810f..1420030eec 100644 --- a/src/cmd/link/internal/ld/main.go +++ b/src/cmd/link/internal/ld/main.go @@ -92,11 +92,10 @@ var ( FlagRound = flag.Int("R", -1, "set address rounding `quantum`") FlagTextAddr = flag.Int64("T", -1, "set text segment `address`") flagEntrySymbol = flag.String("E", "", "set `entry` symbol name") - - cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`") - memprofile = flag.String("memprofile", "", "write memory profile to `file`") - memprofilerate = flag.Int64("memprofilerate", 0, "set runtime.MemProfileRate to `rate`") - + cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`") + memprofile = flag.String("memprofile", "", "write memory profile to `file`") + memprofilerate = flag.Int64("memprofilerate", 0, "set runtime.MemProfileRate to `rate`") + flagAbiWrap = false benchmarkFlag = flag.String("benchmark", "", "set to 'mem' or 'cpu' to enable phase benchmarking") benchmarkFileFlag = flag.String("benchmarkprofile", "", "emit phase profiles to `base`_phase.{cpu,mem}prof") ) @@ -135,6 +134,9 @@ func Main(arch *sys.Arch, theArch Arch) { objabi.Flagfn1("X", "add string value `definition` of the form importpath.name=value", func(s string) { addstrdata1(ctxt, s) }) objabi.Flagcount("v", "print link trace", &ctxt.Debugvlog) objabi.Flagfn1("importcfg", "read import configuration from `file`", ctxt.readImportCfg) + if objabi.Regabi_enabled != 0 { + flag.BoolVar(&flagAbiWrap, "abiwrap", true, "support ABI wrapper functions") + } objabi.Flagparse(usage) diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go index c98e4de03f..3b709baf75 100644 --- a/src/cmd/link/internal/ld/symtab.go +++ b/src/cmd/link/internal/ld/symtab.go @@ -102,6 +102,41 @@ func putelfsym(ctxt *Link, x loader.Sym, typ elf.SymType, curbind elf.SymBind) { elfshnum = xosect.Elfsect.(*ElfShdr).shnum } + sname := ldr.SymExtname(x) + + // For functions with ABI wrappers, we have to make sure that we + // don't wind up with two elf symbol table entries with the same + // name (since this will generated an error from the external + // linker). In the CgoExportStatic case, we want the ABI0 symbol + // to have the primary symbol table entry (since it's going to be + // called from C), so we rename the ABIInternal symbol. In all + // other cases, we rename the ABI0 symbol, since we want + // cross-load-module calls to target ABIInternal. + // + // TODO: generalize this for non-ELF (put the rename code in the + // loader, and store the rename result in SymExtname). + // + // TODO: avoid the ldr.Lookup calls below by instead using an aux + // sym or marker relocation to associate the wrapper with the + // wrapped function. + // + if flagAbiWrap { + if !ldr.IsExternal(x) && ldr.SymType(x) == sym.STEXT { + // First case + if ldr.SymVersion(x) == sym.SymVerABIInternal { + if s2 := ldr.Lookup(sname, sym.SymVerABI0); s2 != 0 && ldr.AttrCgoExportStatic(s2) && ldr.SymType(s2) == sym.STEXT { + sname = sname + ".abiinternal" + } + } + // Second case + if ldr.SymVersion(x) == sym.SymVerABI0 && !ldr.AttrCgoExportStatic(x) { + if s2 := ldr.Lookup(sname, sym.SymVerABIInternal); s2 != 0 && ldr.SymType(s2) == sym.STEXT { + sname = sname + ".abi0" + } + } + } + } + // One pass for each binding: elf.STB_LOCAL, elf.STB_GLOBAL, // maybe one day elf.STB_WEAK. bind := elf.STB_GLOBAL @@ -140,8 +175,6 @@ func putelfsym(ctxt *Link, x loader.Sym, typ elf.SymType, curbind elf.SymBind) { other |= 3 << 5 } - sname := ldr.SymExtname(x) - // When dynamically linking, we create Symbols by reading the names from // the symbol tables of the shared libraries and so the names need to // match exactly. Tools like DTrace will have to wait for now. diff --git a/src/runtime/textflag.h b/src/runtime/textflag.h index daca36d948..e727208cd0 100644 --- a/src/runtime/textflag.h +++ b/src/runtime/textflag.h @@ -35,3 +35,5 @@ // Function is the top of the call stack. Call stack unwinders should stop // at this function. #define TOPFRAME 2048 +// Function is an ABI wrapper. +#define ABIWRAPPER 4096 diff --git a/test/nosplit.go b/test/nosplit.go index faa7b8c2d8..8a3fa9bf35 100644 --- a/test/nosplit.go +++ b/test/nosplit.go @@ -353,7 +353,14 @@ TestCases: log.Fatal(err) } - cmd := exec.Command("go", "build") + // Turn off ABI0 wrapper generation for now. The problem here is + // that in these test cases main.main is an assembly routine, + // thus calls to it will have to go through an ABI wrapper. The + // ABI wrapper will consume some stack space, which throws off + // the numbers. + workaround := "-gcflags=-abiwrap=0" + + cmd := exec.Command("go", "build", workaround) cmd.Dir = dir output, err := cmd.CombinedOutput() if err == nil { -- cgit v1.3-5-g9baa From 6d03cde88a0599bd0a8d6cb1e5b08c5d0a06020a Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 22 Dec 2020 19:32:57 -0800 Subject: [dev.regabi] cmd/dist: automatically bootstrap cmd subdirs We want almost all cmd subdirectories anyway, and relative to the cost of the rest of toolchain bootstrapping, copying/rewriting a few extra source files is way cheaper than the engineering cost of forgetting to maintain these lists as we split out new packages. While here, also add cmd/internal/archive (and make it compile with Go 1.4) because it'll be needed in subsequent refactorings anyway; and skip files starting with # (emacs temporary files) and test files ending with _test.go. Change-Id: Ic86e680a5fdfaecd617c36d5d04413293b2d6f52 Reviewed-on: https://go-review.googlesource.com/c/go/+/279832 Run-TryBot: Matthew Dempsky Reviewed-by: Russ Cox Trust: Matthew Dempsky --- src/cmd/dist/buildtool.go | 113 ++++++++++++++---------------------- src/cmd/internal/archive/archive.go | 10 ++-- 2 files changed, 49 insertions(+), 74 deletions(-) (limited to 'src/cmd/internal') diff --git a/src/cmd/dist/buildtool.go b/src/cmd/dist/buildtool.go index 5e1647cbf0..eb8729149c 100644 --- a/src/cmd/dist/buildtool.go +++ b/src/cmd/dist/buildtool.go @@ -23,78 +23,35 @@ import ( // compiled with a Go 1.4 toolchain to produce the bootstrapTargets. // All directories in this list are relative to and must be below $GOROOT/src. // -// The list has have two kinds of entries: names beginning with cmd/ with +// The list has two kinds of entries: names beginning with cmd/ with // no other slashes, which are commands, and other paths, which are packages // supporting the commands. Packages in the standard library can be listed // if a newer copy needs to be substituted for the Go 1.4 copy when used -// by the command packages. +// by the command packages. Paths ending with /... automatically +// include all packages within subdirectories as well. // These will be imported during bootstrap as bootstrap/name, like bootstrap/math/big. var bootstrapDirs = []string{ "cmd/asm", - "cmd/asm/internal/arch", - "cmd/asm/internal/asm", - "cmd/asm/internal/flags", - "cmd/asm/internal/lex", + "cmd/asm/internal/...", "cmd/cgo", "cmd/compile", - "cmd/compile/internal/amd64", - "cmd/compile/internal/base", - "cmd/compile/internal/arm", - "cmd/compile/internal/arm64", - "cmd/compile/internal/gc", - "cmd/compile/internal/ir", - "cmd/compile/internal/logopt", - "cmd/compile/internal/mips", - "cmd/compile/internal/mips64", - "cmd/compile/internal/ppc64", - "cmd/compile/internal/riscv64", - "cmd/compile/internal/s390x", - "cmd/compile/internal/ssa", - "cmd/compile/internal/syntax", - "cmd/compile/internal/types", - "cmd/compile/internal/x86", - "cmd/compile/internal/wasm", + "cmd/compile/internal/...", + "cmd/internal/archive", "cmd/internal/bio", "cmd/internal/codesign", - "cmd/internal/gcprog", "cmd/internal/dwarf", "cmd/internal/edit", + "cmd/internal/gcprog", "cmd/internal/goobj", + "cmd/internal/obj/...", "cmd/internal/objabi", - "cmd/internal/obj", - "cmd/internal/obj/arm", - "cmd/internal/obj/arm64", - "cmd/internal/obj/mips", - "cmd/internal/obj/ppc64", - "cmd/internal/obj/riscv", - "cmd/internal/obj/s390x", - "cmd/internal/obj/x86", - "cmd/internal/obj/wasm", "cmd/internal/pkgpath", "cmd/internal/src", "cmd/internal/sys", "cmd/link", - "cmd/link/internal/amd64", - "cmd/compile/internal/base", - "cmd/link/internal/arm", - "cmd/link/internal/arm64", - "cmd/link/internal/benchmark", - "cmd/link/internal/ld", - "cmd/link/internal/loadelf", - "cmd/link/internal/loader", - "cmd/link/internal/loadmacho", - "cmd/link/internal/loadpe", - "cmd/link/internal/loadxcoff", - "cmd/link/internal/mips", - "cmd/link/internal/mips64", - "cmd/link/internal/ppc64", - "cmd/link/internal/riscv64", - "cmd/link/internal/s390x", - "cmd/link/internal/sym", - "cmd/link/internal/x86", + "cmd/link/internal/...", "compress/flate", "compress/zlib", - "cmd/link/internal/wasm", "container/heap", "debug/dwarf", "debug/elf", @@ -116,6 +73,7 @@ var bootstrapDirs = []string{ var ignorePrefixes = []string{ ".", "_", + "#", } // File suffixes that use build tags introduced since Go 1.4. @@ -129,6 +87,7 @@ var ignoreSuffixes = []string{ "_wasm.s", "_wasm.go", "_test.s", + "_test.go", } func bootstrapBuildTools() { @@ -154,31 +113,47 @@ func bootstrapBuildTools() { // Copy source code into $GOROOT/pkg/bootstrap and rewrite import paths. writefile("module bootstrap\n", pathf("%s/%s", base, "go.mod"), 0) for _, dir := range bootstrapDirs { - src := pathf("%s/src/%s", goroot, dir) - dst := pathf("%s/%s", base, dir) - xmkdirall(dst) - if dir == "cmd/cgo" { - // Write to src because we need the file both for bootstrap - // and for later in the main build. - mkzdefaultcc("", pathf("%s/zdefaultcc.go", src)) - } - Dir: - for _, name := range xreaddirfiles(src) { + recurse := strings.HasSuffix(dir, "/...") + dir = strings.TrimSuffix(dir, "/...") + filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if err != nil { + fatalf("walking bootstrap dirs failed: %v: %v", path, err) + } + + name := filepath.Base(path) + src := pathf("%s/src/%s", goroot, path) + dst := pathf("%s/%s", base, path) + + if info.IsDir() { + if !recurse && path != dir || name == "testdata" { + return filepath.SkipDir + } + + xmkdirall(dst) + if path == "cmd/cgo" { + // Write to src because we need the file both for bootstrap + // and for later in the main build. + mkzdefaultcc("", pathf("%s/zdefaultcc.go", src)) + mkzdefaultcc("", pathf("%s/zdefaultcc.go", dst)) + } + return nil + } + for _, pre := range ignorePrefixes { if strings.HasPrefix(name, pre) { - continue Dir + return nil } } for _, suf := range ignoreSuffixes { if strings.HasSuffix(name, suf) { - continue Dir + return nil } } - srcFile := pathf("%s/%s", src, name) - dstFile := pathf("%s/%s", dst, name) - text := bootstrapRewriteFile(srcFile) - writefile(text, dstFile, 0) - } + + text := bootstrapRewriteFile(src) + writefile(text, dst, 0) + return nil + }) } // Set up environment for invoking Go 1.4 go command. diff --git a/src/cmd/internal/archive/archive.go b/src/cmd/internal/archive/archive.go index c1661d7711..762e888a04 100644 --- a/src/cmd/internal/archive/archive.go +++ b/src/cmd/internal/archive/archive.go @@ -118,9 +118,9 @@ type objReader struct { func (r *objReader) init(f *os.File) { r.a = &Archive{f, nil} - r.offset, _ = f.Seek(0, io.SeekCurrent) - r.limit, _ = f.Seek(0, io.SeekEnd) - f.Seek(r.offset, io.SeekStart) + r.offset, _ = f.Seek(0, os.SEEK_CUR) + r.limit, _ = f.Seek(0, os.SEEK_END) + f.Seek(r.offset, os.SEEK_SET) r.b = bio.NewReader(f) } @@ -221,7 +221,7 @@ func (r *objReader) skip(n int64) { r.readFull(r.tmp[:n]) } else { // Seek, giving up buffered data. - r.b.MustSeek(r.offset+n, io.SeekStart) + r.b.MustSeek(r.offset+n, os.SEEK_SET) r.offset += n } } @@ -426,7 +426,7 @@ func (r *objReader) parseObject(o *GoObj, size int64) error { // AddEntry adds an entry to the end of a, with the content from r. func (a *Archive) AddEntry(typ EntryType, name string, mtime int64, uid, gid int, mode os.FileMode, size int64, r io.Reader) { - off, err := a.f.Seek(0, io.SeekEnd) + off, err := a.f.Seek(0, os.SEEK_END) if err != nil { log.Fatal(err) } -- cgit v1.3-5-g9baa From fbc82f03b104ba9bde67ad202e9cb00a13842dca Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 23 Dec 2020 00:52:53 -0500 Subject: [dev.regabi] cmd/compile: split out package noder [generated] [git-generate] cd src/cmd/compile/internal/gc rf ' mv ArhdrSize HeaderSize mv arsize ReadHeader mv formathdr FormatHeader mv HeaderSize ReadHeader FormatHeader archive.go mv archive.go cmd/internal/archive mv makePos main.go mv checkDotImports CheckDotImports mv parseFiles ParseFiles mv Pragma pragmas mv PragmaEmbed pragmaEmbed mv PragmaPos pragmaPos mv FuncPragmas funcPragmas mv TypePragmas typePragmas mv fakeRecv noder.funcLit renameinitgen renameinit oldname varEmbed noder.go mv isDriveLetter islocalname findpkg myheight importfile \ reservedimports isbadimport \ pkgnotused \ mkpackage clearImports \ CheckDotImports dotImports importDot \ importName \ import.go mv noder _noder mv import.go lex.go lex_test.go noder.go cmd/compile/internal/noder ' cd ../noder rf ' mv _noder noder ' Change-Id: Iac2b856f7b86143c666d818e4b7c5b261cf387d5 Reviewed-on: https://go-review.googlesource.com/c/go/+/279473 Trust: Russ Cox Run-TryBot: Russ Cox Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/gc/closure.go | 60 - src/cmd/compile/internal/gc/dcl.go | 64 - src/cmd/compile/internal/gc/embed.go | 53 - src/cmd/compile/internal/gc/init.go | 12 - src/cmd/compile/internal/gc/lex.go | 195 --- src/cmd/compile/internal/gc/lex_test.go | 121 -- src/cmd/compile/internal/gc/main.go | 380 +----- src/cmd/compile/internal/gc/noder.go | 1763 ------------------------- src/cmd/compile/internal/gc/obj.go | 16 +- src/cmd/compile/internal/gc/subr.go | 105 -- src/cmd/compile/internal/noder/import.go | 493 +++++++ src/cmd/compile/internal/noder/lex.go | 190 +++ src/cmd/compile/internal/noder/lex_test.go | 122 ++ src/cmd/compile/internal/noder/noder.go | 1938 ++++++++++++++++++++++++++++ src/cmd/internal/archive/archive.go | 21 + 15 files changed, 2776 insertions(+), 2757 deletions(-) delete mode 100644 src/cmd/compile/internal/gc/lex.go delete mode 100644 src/cmd/compile/internal/gc/lex_test.go delete mode 100644 src/cmd/compile/internal/gc/noder.go create mode 100644 src/cmd/compile/internal/noder/import.go create mode 100644 src/cmd/compile/internal/noder/lex.go create mode 100644 src/cmd/compile/internal/noder/lex_test.go create mode 100644 src/cmd/compile/internal/noder/noder.go (limited to 'src/cmd/internal') diff --git a/src/cmd/compile/internal/gc/closure.go b/src/cmd/compile/internal/gc/closure.go index 29455bffd8..4679b6535b 100644 --- a/src/cmd/compile/internal/gc/closure.go +++ b/src/cmd/compile/internal/gc/closure.go @@ -7,71 +7,11 @@ package gc import ( "cmd/compile/internal/base" "cmd/compile/internal/ir" - "cmd/compile/internal/syntax" "cmd/compile/internal/typecheck" "cmd/compile/internal/types" "cmd/internal/src" ) -func (p *noder) funcLit(expr *syntax.FuncLit) ir.Node { - xtype := p.typeExpr(expr.Type) - ntype := p.typeExpr(expr.Type) - - fn := ir.NewFunc(p.pos(expr)) - fn.SetIsHiddenClosure(ir.CurFunc != nil) - fn.Nname = ir.NewFuncNameAt(p.pos(expr), ir.BlankNode.Sym(), fn) // filled in by typecheckclosure - fn.Nname.Ntype = xtype - fn.Nname.Defn = fn - - clo := ir.NewClosureExpr(p.pos(expr), fn) - fn.ClosureType = ntype - fn.OClosure = clo - - p.funcBody(fn, expr.Body) - - // closure-specific variables are hanging off the - // ordinary ones in the symbol table; see oldname. - // unhook them. - // make the list of pointers for the closure call. - for _, v := range fn.ClosureVars { - // Unlink from v1; see comment in syntax.go type Param for these fields. - v1 := v.Defn - v1.Name().Innermost = v.Outer - - // If the closure usage of v is not dense, - // we need to make it dense; now that we're out - // of the function in which v appeared, - // look up v.Sym in the enclosing function - // and keep it around for use in the compiled code. - // - // That is, suppose we just finished parsing the innermost - // closure f4 in this code: - // - // func f() { - // v := 1 - // func() { // f2 - // use(v) - // func() { // f3 - // func() { // f4 - // use(v) - // }() - // }() - // }() - // } - // - // At this point v.Outer is f2's v; there is no f3's v. - // To construct the closure f4 from within f3, - // we need to use f3's v and in this case we need to create f3's v. - // We are now in the context of f3, so calling oldname(v.Sym) - // obtains f3's v, creating it if necessary (as it is in the example). - // - // capturevars will decide whether to use v directly or &v. - v.Outer = oldname(v.Sym()).(*ir.Name) - } - - return clo -} - // transformclosure is called in a separate phase after escape analysis. // It transform closure bodies to properly reference captured variables. func transformclosure(fn *ir.Func) { diff --git a/src/cmd/compile/internal/gc/dcl.go b/src/cmd/compile/internal/gc/dcl.go index e53bba44ad..aaf5b35057 100644 --- a/src/cmd/compile/internal/gc/dcl.go +++ b/src/cmd/compile/internal/gc/dcl.go @@ -28,70 +28,6 @@ func NoWriteBarrierRecCheck() { var nowritebarrierrecCheck *nowritebarrierrecChecker -// oldname returns the Node that declares symbol s in the current scope. -// If no such Node currently exists, an ONONAME Node is returned instead. -// Automatically creates a new closure variable if the referenced symbol was -// declared in a different (containing) function. -func oldname(s *types.Sym) ir.Node { - if s.Pkg != types.LocalPkg { - return ir.NewIdent(base.Pos, s) - } - - n := ir.AsNode(s.Def) - if n == nil { - // Maybe a top-level declaration will come along later to - // define s. resolve will check s.Def again once all input - // source has been processed. - return ir.NewIdent(base.Pos, s) - } - - if ir.CurFunc != nil && n.Op() == ir.ONAME && n.Name().Curfn != nil && n.Name().Curfn != ir.CurFunc { - // Inner func is referring to var in outer func. - // - // TODO(rsc): If there is an outer variable x and we - // are parsing x := 5 inside the closure, until we get to - // the := it looks like a reference to the outer x so we'll - // make x a closure variable unnecessarily. - n := n.(*ir.Name) - c := n.Name().Innermost - if c == nil || c.Curfn != ir.CurFunc { - // Do not have a closure var for the active closure yet; make one. - c = typecheck.NewName(s) - c.Class_ = ir.PAUTOHEAP - c.SetIsClosureVar(true) - c.SetIsDDD(n.IsDDD()) - c.Defn = n - - // Link into list of active closure variables. - // Popped from list in func funcLit. - c.Outer = n.Name().Innermost - n.Name().Innermost = c - - ir.CurFunc.ClosureVars = append(ir.CurFunc.ClosureVars, c) - } - - // return ref to closure var, not original - return c - } - - return n -} - -// importName is like oldname, -// but it reports an error if sym is from another package and not exported. -func importName(sym *types.Sym) ir.Node { - n := oldname(sym) - if !types.IsExported(sym.Name) && sym.Pkg != types.LocalPkg { - n.SetDiag(true) - base.Errorf("cannot refer to unexported name %s.%s", sym.Pkg.Name, sym.Name) - } - return n -} - -func fakeRecv() *ir.Field { - return ir.NewField(base.Pos, nil, nil, types.FakeRecvType()) -} - // funcsym returns s·f. func funcsym(s *types.Sym) *types.Sym { // funcsymsmu here serves to protect not just mutations of funcsyms (below), diff --git a/src/cmd/compile/internal/gc/embed.go b/src/cmd/compile/internal/gc/embed.go index 282e718b29..959d8cd7fe 100644 --- a/src/cmd/compile/internal/gc/embed.go +++ b/src/cmd/compile/internal/gc/embed.go @@ -8,14 +8,12 @@ import ( "cmd/compile/internal/base" "cmd/compile/internal/ir" "cmd/compile/internal/objw" - "cmd/compile/internal/syntax" "cmd/compile/internal/typecheck" "cmd/compile/internal/types" "cmd/internal/obj" "path" "sort" - "strconv" "strings" ) @@ -26,57 +24,6 @@ const ( embedFiles ) -func varEmbed(p *noder, names []*ir.Name, typ ir.Ntype, exprs []ir.Node, embeds []PragmaEmbed) (newExprs []ir.Node) { - haveEmbed := false - for _, decl := range p.file.DeclList { - imp, ok := decl.(*syntax.ImportDecl) - if !ok { - // imports always come first - break - } - path, _ := strconv.Unquote(imp.Path.Value) - if path == "embed" { - haveEmbed = true - break - } - } - - pos := embeds[0].Pos - if !haveEmbed { - p.errorAt(pos, "invalid go:embed: missing import \"embed\"") - return exprs - } - if base.Flag.Cfg.Embed.Patterns == nil { - p.errorAt(pos, "invalid go:embed: build system did not supply embed configuration") - return exprs - } - if len(names) > 1 { - p.errorAt(pos, "go:embed cannot apply to multiple vars") - return exprs - } - if len(exprs) > 0 { - p.errorAt(pos, "go:embed cannot apply to var with initializer") - return exprs - } - if typ == nil { - // Should not happen, since len(exprs) == 0 now. - p.errorAt(pos, "go:embed cannot apply to var without type") - return exprs - } - if typecheck.DeclContext != ir.PEXTERN { - p.errorAt(pos, "go:embed cannot apply to var inside func") - return exprs - } - - v := names[0] - typecheck.Target.Embeds = append(typecheck.Target.Embeds, v) - v.Embed = new([]ir.Embed) - for _, e := range embeds { - *v.Embed = append(*v.Embed, ir.Embed{Pos: p.makeXPos(e.Pos), Patterns: e.Patterns}) - } - return exprs -} - func embedFileList(v *ir.Name) []string { kind := embedKind(v.Type()) if kind == embedUnknown { diff --git a/src/cmd/compile/internal/gc/init.go b/src/cmd/compile/internal/gc/init.go index da3f40f4e8..a299b8688b 100644 --- a/src/cmd/compile/internal/gc/init.go +++ b/src/cmd/compile/internal/gc/init.go @@ -13,18 +13,6 @@ import ( "cmd/internal/obj" ) -// A function named init is a special case. -// It is called by the initialization before main is run. -// To make it unique within a package and also uncallable, -// the name, normally "pkg.init", is altered to "pkg.init.0". -var renameinitgen int - -func renameinit() *types.Sym { - s := typecheck.LookupNum("init.", renameinitgen) - renameinitgen++ - return s -} - // fninit makes and returns an initialization record for the package. // See runtime/proc.go:initTask for its layout. // The 3 tasks for initialization are: diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go deleted file mode 100644 index 39d73867e4..0000000000 --- a/src/cmd/compile/internal/gc/lex.go +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package gc - -import ( - "cmd/compile/internal/base" - "cmd/compile/internal/ir" - "cmd/compile/internal/syntax" - "cmd/internal/objabi" - "cmd/internal/src" - "fmt" - "strings" -) - -func makePos(b *src.PosBase, line, col uint) src.XPos { - return base.Ctxt.PosTable.XPos(src.MakePos(b, line, col)) -} - -func isSpace(c rune) bool { - return c == ' ' || c == '\t' || c == '\n' || c == '\r' -} - -func isQuoted(s string) bool { - return len(s) >= 2 && s[0] == '"' && s[len(s)-1] == '"' -} - -const ( - FuncPragmas = ir.Nointerface | - ir.Noescape | - ir.Norace | - ir.Nosplit | - ir.Noinline | - ir.NoCheckPtr | - ir.CgoUnsafeArgs | - ir.UintptrEscapes | - ir.Systemstack | - ir.Nowritebarrier | - ir.Nowritebarrierrec | - ir.Yeswritebarrierrec - - TypePragmas = ir.NotInHeap -) - -func pragmaFlag(verb string) ir.PragmaFlag { - switch verb { - case "go:build": - return ir.GoBuildPragma - case "go:nointerface": - if objabi.Fieldtrack_enabled != 0 { - return ir.Nointerface - } - case "go:noescape": - return ir.Noescape - case "go:norace": - return ir.Norace - case "go:nosplit": - return ir.Nosplit | ir.NoCheckPtr // implies NoCheckPtr (see #34972) - case "go:noinline": - return ir.Noinline - case "go:nocheckptr": - return ir.NoCheckPtr - case "go:systemstack": - return ir.Systemstack - case "go:nowritebarrier": - return ir.Nowritebarrier - case "go:nowritebarrierrec": - return ir.Nowritebarrierrec | ir.Nowritebarrier // implies Nowritebarrier - case "go:yeswritebarrierrec": - return ir.Yeswritebarrierrec - case "go:cgo_unsafe_args": - return ir.CgoUnsafeArgs | ir.NoCheckPtr // implies NoCheckPtr (see #34968) - case "go:uintptrescapes": - // For the next function declared in the file - // any uintptr arguments may be pointer values - // converted to uintptr. This directive - // ensures that the referenced allocated - // object, if any, is retained and not moved - // until the call completes, even though from - // the types alone it would appear that the - // object is no longer needed during the - // call. The conversion to uintptr must appear - // in the argument list. - // Used in syscall/dll_windows.go. - return ir.UintptrEscapes - case "go:notinheap": - return ir.NotInHeap - } - return 0 -} - -// pragcgo is called concurrently if files are parsed concurrently. -func (p *noder) pragcgo(pos syntax.Pos, text string) { - f := pragmaFields(text) - - verb := strings.TrimPrefix(f[0], "go:") - f[0] = verb - - switch verb { - case "cgo_export_static", "cgo_export_dynamic": - switch { - case len(f) == 2 && !isQuoted(f[1]): - case len(f) == 3 && !isQuoted(f[1]) && !isQuoted(f[2]): - default: - p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf(`usage: //go:%s local [remote]`, verb)}) - return - } - case "cgo_import_dynamic": - switch { - case len(f) == 2 && !isQuoted(f[1]): - case len(f) == 3 && !isQuoted(f[1]) && !isQuoted(f[2]): - case len(f) == 4 && !isQuoted(f[1]) && !isQuoted(f[2]) && isQuoted(f[3]): - f[3] = strings.Trim(f[3], `"`) - if objabi.GOOS == "aix" && f[3] != "" { - // On Aix, library pattern must be "lib.a/object.o" - // or "lib.a/libname.so.X" - n := strings.Split(f[3], "/") - if len(n) != 2 || !strings.HasSuffix(n[0], ".a") || (!strings.HasSuffix(n[1], ".o") && !strings.Contains(n[1], ".so.")) { - p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_import_dynamic local [remote ["lib.a/object.o"]]`}) - return - } - } - default: - p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_import_dynamic local [remote ["library"]]`}) - return - } - case "cgo_import_static": - switch { - case len(f) == 2 && !isQuoted(f[1]): - default: - p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_import_static local`}) - return - } - case "cgo_dynamic_linker": - switch { - case len(f) == 2 && isQuoted(f[1]): - f[1] = strings.Trim(f[1], `"`) - default: - p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_dynamic_linker "path"`}) - return - } - case "cgo_ldflag": - switch { - case len(f) == 2 && isQuoted(f[1]): - f[1] = strings.Trim(f[1], `"`) - default: - p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_ldflag "arg"`}) - return - } - default: - return - } - p.pragcgobuf = append(p.pragcgobuf, f) -} - -// pragmaFields is similar to strings.FieldsFunc(s, isSpace) -// but does not split when inside double quoted regions and always -// splits before the start and after the end of a double quoted region. -// pragmaFields does not recognize escaped quotes. If a quote in s is not -// closed the part after the opening quote will not be returned as a field. -func pragmaFields(s string) []string { - var a []string - inQuote := false - fieldStart := -1 // Set to -1 when looking for start of field. - for i, c := range s { - switch { - case c == '"': - if inQuote { - inQuote = false - a = append(a, s[fieldStart:i+1]) - fieldStart = -1 - } else { - inQuote = true - if fieldStart >= 0 { - a = append(a, s[fieldStart:i]) - } - fieldStart = i - } - case !inQuote && isSpace(c): - if fieldStart >= 0 { - a = append(a, s[fieldStart:i]) - fieldStart = -1 - } - default: - if fieldStart == -1 { - fieldStart = i - } - } - } - if !inQuote && fieldStart >= 0 { // Last field might end at the end of the string. - a = append(a, s[fieldStart:]) - } - return a -} diff --git a/src/cmd/compile/internal/gc/lex_test.go b/src/cmd/compile/internal/gc/lex_test.go deleted file mode 100644 index b2081a1732..0000000000 --- a/src/cmd/compile/internal/gc/lex_test.go +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2016 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 gc - -import ( - "cmd/compile/internal/syntax" - "reflect" - "runtime" - "testing" -) - -func eq(a, b []string) bool { - if len(a) != len(b) { - return false - } - for i := 0; i < len(a); i++ { - if a[i] != b[i] { - return false - } - } - return true -} - -func TestPragmaFields(t *testing.T) { - var tests = []struct { - in string - want []string - }{ - {"", []string{}}, - {" \t ", []string{}}, - {`""""`, []string{`""`, `""`}}, - {" a'b'c ", []string{"a'b'c"}}, - {"1 2 3 4", []string{"1", "2", "3", "4"}}, - {"\n☺\t☹\n", []string{"☺", "☹"}}, - {`"1 2 " 3 " 4 5"`, []string{`"1 2 "`, `3`, `" 4 5"`}}, - {`"1""2 3""4"`, []string{`"1"`, `"2 3"`, `"4"`}}, - {`12"34"`, []string{`12`, `"34"`}}, - {`12"34 `, []string{`12`}}, - } - - for _, tt := range tests { - got := pragmaFields(tt.in) - if !eq(got, tt.want) { - t.Errorf("pragmaFields(%q) = %v; want %v", tt.in, got, tt.want) - continue - } - } -} - -func TestPragcgo(t *testing.T) { - type testStruct struct { - in string - want []string - } - - var tests = []testStruct{ - {`go:cgo_export_dynamic local`, []string{`cgo_export_dynamic`, `local`}}, - {`go:cgo_export_dynamic local remote`, []string{`cgo_export_dynamic`, `local`, `remote`}}, - {`go:cgo_export_dynamic local' remote'`, []string{`cgo_export_dynamic`, `local'`, `remote'`}}, - {`go:cgo_export_static local`, []string{`cgo_export_static`, `local`}}, - {`go:cgo_export_static local remote`, []string{`cgo_export_static`, `local`, `remote`}}, - {`go:cgo_export_static local' remote'`, []string{`cgo_export_static`, `local'`, `remote'`}}, - {`go:cgo_import_dynamic local`, []string{`cgo_import_dynamic`, `local`}}, - {`go:cgo_import_dynamic local remote`, []string{`cgo_import_dynamic`, `local`, `remote`}}, - {`go:cgo_import_static local`, []string{`cgo_import_static`, `local`}}, - {`go:cgo_import_static local'`, []string{`cgo_import_static`, `local'`}}, - {`go:cgo_dynamic_linker "/path/"`, []string{`cgo_dynamic_linker`, `/path/`}}, - {`go:cgo_dynamic_linker "/p ath/"`, []string{`cgo_dynamic_linker`, `/p ath/`}}, - {`go:cgo_ldflag "arg"`, []string{`cgo_ldflag`, `arg`}}, - {`go:cgo_ldflag "a rg"`, []string{`cgo_ldflag`, `a rg`}}, - } - - if runtime.GOOS != "aix" { - tests = append(tests, []testStruct{ - {`go:cgo_import_dynamic local remote "library"`, []string{`cgo_import_dynamic`, `local`, `remote`, `library`}}, - {`go:cgo_import_dynamic local' remote' "lib rary"`, []string{`cgo_import_dynamic`, `local'`, `remote'`, `lib rary`}}, - }...) - } else { - // cgo_import_dynamic with a library is slightly different on AIX - // as the library field must follow the pattern [libc.a/object.o]. - tests = append(tests, []testStruct{ - {`go:cgo_import_dynamic local remote "lib.a/obj.o"`, []string{`cgo_import_dynamic`, `local`, `remote`, `lib.a/obj.o`}}, - // This test must fail. - {`go:cgo_import_dynamic local' remote' "library"`, []string{`: usage: //go:cgo_import_dynamic local [remote ["lib.a/object.o"]]`}}, - }...) - - } - - var p noder - var nopos syntax.Pos - for _, tt := range tests { - - p.err = make(chan syntax.Error) - gotch := make(chan [][]string, 1) - go func() { - p.pragcgobuf = nil - p.pragcgo(nopos, tt.in) - if p.pragcgobuf != nil { - gotch <- p.pragcgobuf - } - }() - - select { - case e := <-p.err: - want := tt.want[0] - if e.Error() != want { - t.Errorf("pragcgo(%q) = %q; want %q", tt.in, e, want) - continue - } - case got := <-gotch: - want := [][]string{tt.want} - if !reflect.DeepEqual(got, want) { - t.Errorf("pragcgo(%q) = %q; want %q", tt.in, got, want) - continue - } - } - - } -} diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index cda00fb9ae..7b540d8675 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -14,26 +14,21 @@ import ( "cmd/compile/internal/inline" "cmd/compile/internal/ir" "cmd/compile/internal/logopt" + "cmd/compile/internal/noder" "cmd/compile/internal/ssa" "cmd/compile/internal/typecheck" "cmd/compile/internal/types" - "cmd/internal/bio" "cmd/internal/dwarf" - "cmd/internal/goobj" "cmd/internal/obj" "cmd/internal/objabi" "cmd/internal/src" "flag" "fmt" - "go/constant" - "io" "io/ioutil" "log" "os" - "path" "runtime" "sort" - "strconv" "strings" ) @@ -212,7 +207,7 @@ func Main(archInit func(*Arch)) { // Parse input. base.Timer.Start("fe", "parse") - lines := parseFiles(flag.Args()) + lines := noder.ParseFiles(flag.Args()) cgoSymABIs() base.Timer.Stop() base.Timer.AddEvent(int64(lines), "lines") @@ -222,7 +217,7 @@ func Main(archInit func(*Arch)) { typecheck.Package() // With all user code typechecked, it's now safe to verify unused dot imports. - checkDotImports() + noder.CheckDotImports() base.ExitIfErrors() // Build init task. @@ -468,371 +463,6 @@ func readSymABIs(file, myimportpath string) { } } -func arsize(b *bufio.Reader, name string) int { - var buf [ArhdrSize]byte - if _, err := io.ReadFull(b, buf[:]); err != nil { - return -1 - } - aname := strings.Trim(string(buf[0:16]), " ") - if !strings.HasPrefix(aname, name) { - return -1 - } - asize := strings.Trim(string(buf[48:58]), " ") - i, _ := strconv.Atoi(asize) - return i -} - -func isDriveLetter(b byte) bool { - return 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z' -} - -// is this path a local name? begins with ./ or ../ or / -func islocalname(name string) bool { - return strings.HasPrefix(name, "/") || - runtime.GOOS == "windows" && len(name) >= 3 && isDriveLetter(name[0]) && name[1] == ':' && name[2] == '/' || - strings.HasPrefix(name, "./") || name == "." || - strings.HasPrefix(name, "../") || name == ".." -} - -func findpkg(name string) (file string, ok bool) { - if islocalname(name) { - if base.Flag.NoLocalImports { - return "", false - } - - if base.Flag.Cfg.PackageFile != nil { - file, ok = base.Flag.Cfg.PackageFile[name] - return file, ok - } - - // try .a before .6. important for building libraries: - // if there is an array.6 in the array.a library, - // want to find all of array.a, not just array.6. - file = fmt.Sprintf("%s.a", name) - if _, err := os.Stat(file); err == nil { - return file, true - } - file = fmt.Sprintf("%s.o", name) - if _, err := os.Stat(file); err == nil { - return file, true - } - return "", false - } - - // local imports should be canonicalized already. - // don't want to see "encoding/../encoding/base64" - // as different from "encoding/base64". - if q := path.Clean(name); q != name { - base.Errorf("non-canonical import path %q (should be %q)", name, q) - return "", false - } - - if base.Flag.Cfg.PackageFile != nil { - file, ok = base.Flag.Cfg.PackageFile[name] - return file, ok - } - - for _, dir := range base.Flag.Cfg.ImportDirs { - file = fmt.Sprintf("%s/%s.a", dir, name) - if _, err := os.Stat(file); err == nil { - return file, true - } - file = fmt.Sprintf("%s/%s.o", dir, name) - if _, err := os.Stat(file); err == nil { - return file, true - } - } - - if objabi.GOROOT != "" { - suffix := "" - suffixsep := "" - if base.Flag.InstallSuffix != "" { - suffixsep = "_" - suffix = base.Flag.InstallSuffix - } else if base.Flag.Race { - suffixsep = "_" - suffix = "race" - } else if base.Flag.MSan { - suffixsep = "_" - suffix = "msan" - } - - file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.a", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffixsep, suffix, name) - if _, err := os.Stat(file); err == nil { - return file, true - } - file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.o", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffixsep, suffix, name) - if _, err := os.Stat(file); err == nil { - return file, true - } - } - - return "", false -} - -// myheight tracks the local package's height based on packages -// imported so far. -var myheight int - -func importfile(f constant.Value) *types.Pkg { - if f.Kind() != constant.String { - base.Errorf("import path must be a string") - return nil - } - - path_ := constant.StringVal(f) - if len(path_) == 0 { - base.Errorf("import path is empty") - return nil - } - - if isbadimport(path_, false) { - return nil - } - - // The package name main is no longer reserved, - // 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 path_ == "main" { - base.Errorf("cannot import \"main\"") - base.ErrorExit() - } - - if base.Ctxt.Pkgpath != "" && path_ == base.Ctxt.Pkgpath { - base.Errorf("import %q while compiling that package (import cycle)", path_) - base.ErrorExit() - } - - if mapped, ok := base.Flag.Cfg.ImportMap[path_]; ok { - path_ = mapped - } - - if path_ == "unsafe" { - return ir.Pkgs.Unsafe - } - - if islocalname(path_) { - if path_[0] == '/' { - base.Errorf("import path cannot be absolute path") - return nil - } - - prefix := base.Ctxt.Pathname - if base.Flag.D != "" { - prefix = base.Flag.D - } - path_ = path.Join(prefix, path_) - - if isbadimport(path_, true) { - return nil - } - } - - file, found := findpkg(path_) - if !found { - base.Errorf("can't find import: %q", path_) - base.ErrorExit() - } - - importpkg := types.NewPkg(path_, "") - if importpkg.Imported { - return importpkg - } - - importpkg.Imported = true - - imp, err := bio.Open(file) - if err != nil { - base.Errorf("can't open import: %q: %v", path_, err) - base.ErrorExit() - } - defer imp.Close() - - // check object header - p, err := imp.ReadString('\n') - if err != nil { - base.Errorf("import %s: reading input: %v", file, err) - base.ErrorExit() - } - - if p == "!\n" { // package archive - // package export block should be first - sz := arsize(imp.Reader, "__.PKGDEF") - if sz <= 0 { - base.Errorf("import %s: not a package file", file) - base.ErrorExit() - } - p, err = imp.ReadString('\n') - if err != nil { - base.Errorf("import %s: reading input: %v", file, err) - base.ErrorExit() - } - } - - if !strings.HasPrefix(p, "go object ") { - base.Errorf("import %s: not a go object file: %s", file, p) - base.ErrorExit() - } - q := fmt.Sprintf("%s %s %s %s\n", objabi.GOOS, objabi.GOARCH, objabi.Version, objabi.Expstring()) - if p[10:] != q { - base.Errorf("import %s: object is [%s] expected [%s]", file, p[10:], q) - base.ErrorExit() - } - - // process header lines - for { - p, err = imp.ReadString('\n') - if err != nil { - base.Errorf("import %s: reading input: %v", file, err) - base.ErrorExit() - } - if p == "\n" { - break // header ends with blank line - } - } - - // Expect $$B\n to signal binary import format. - - // look for $$ - var c byte - for { - c, err = imp.ReadByte() - if err != nil { - break - } - if c == '$' { - c, err = imp.ReadByte() - if c == '$' || err != nil { - break - } - } - } - - // get character after $$ - if err == nil { - c, _ = imp.ReadByte() - } - - var fingerprint goobj.FingerprintType - switch c { - case '\n': - base.Errorf("cannot import %s: old export format no longer supported (recompile library)", path_) - return nil - - case 'B': - if base.Debug.Export != 0 { - fmt.Printf("importing %s (%s)\n", path_, file) - } - imp.ReadByte() // skip \n after $$B - - c, err = imp.ReadByte() - if err != nil { - base.Errorf("import %s: reading input: %v", file, err) - base.ErrorExit() - } - - // Indexed format is distinguished by an 'i' byte, - // whereas previous export formats started with 'c', 'd', or 'v'. - if c != 'i' { - base.Errorf("import %s: unexpected package format byte: %v", file, c) - base.ErrorExit() - } - fingerprint = typecheck.ReadImports(importpkg, imp) - - default: - base.Errorf("no import in %q", path_) - base.ErrorExit() - } - - // assume files move (get installed) so don't record the full path - if base.Flag.Cfg.PackageFile != nil { - // If using a packageFile map, assume path_ can be recorded directly. - base.Ctxt.AddImport(path_, fingerprint) - } else { - // For file "/Users/foo/go/pkg/darwin_amd64/math.a" record "math.a". - base.Ctxt.AddImport(file[len(file)-len(path_)-len(".a"):], fingerprint) - } - - if importpkg.Height >= myheight { - myheight = importpkg.Height + 1 - } - - return importpkg -} - -func pkgnotused(lineno src.XPos, path string, name string) { - // If the package was imported with a name other than the final - // import path element, show it explicitly in the error message. - // Note that this handles both renamed imports and imports of - // packages containing unconventional package declarations. - // Note that this uses / always, even on Windows, because Go import - // paths always use forward slashes. - elem := path - if i := strings.LastIndex(elem, "/"); i >= 0 { - elem = elem[i+1:] - } - if name == "" || elem == name { - base.ErrorfAt(lineno, "imported and not used: %q", path) - } else { - base.ErrorfAt(lineno, "imported and not used: %q as %s", path, name) - } -} - -func mkpackage(pkgname string) { - if types.LocalPkg.Name == "" { - if pkgname == "_" { - base.Errorf("invalid package name _") - } - types.LocalPkg.Name = pkgname - } else { - if pkgname != types.LocalPkg.Name { - base.Errorf("package %s; expected %s", pkgname, types.LocalPkg.Name) - } - } -} - -func clearImports() { - type importedPkg struct { - pos src.XPos - path string - name string - } - var unused []importedPkg - - for _, s := range types.LocalPkg.Syms { - n := ir.AsNode(s.Def) - if n == nil { - continue - } - if n.Op() == ir.OPACK { - // throw away top-level package name left over - // from previous file. - // leave s->block set to cause redeclaration - // errors if a conflicting top-level name is - // introduced by a different file. - p := n.(*ir.PkgName) - if !p.Used && base.SyntaxErrors() == 0 { - unused = append(unused, importedPkg{p.Pos(), p.Pkg.Path, s.Name}) - } - s.Def = nil - continue - } - if types.IsDotAlias(s) { - // throw away top-level name left over - // from previous import . "x" - // We'll report errors after type checking in checkDotImports. - s.Def = nil - continue - } - } - - sort.Slice(unused, func(i, j int) bool { return unused[i].pos.Before(unused[j].pos) }) - for _, pkg := range unused { - pkgnotused(pkg.pos, pkg.path, pkg.name) - } -} - // recordFlags records the specified command-line flags to be placed // in the DWARF info. func recordFlags(flags ...string) { @@ -922,3 +552,7 @@ func useABIWrapGen(f *ir.Func) bool { return true } + +func makePos(b *src.PosBase, line, col uint) src.XPos { + return base.Ctxt.PosTable.XPos(src.MakePos(b, line, col)) +} diff --git a/src/cmd/compile/internal/gc/noder.go b/src/cmd/compile/internal/gc/noder.go deleted file mode 100644 index 3e8703f050..0000000000 --- a/src/cmd/compile/internal/gc/noder.go +++ /dev/null @@ -1,1763 +0,0 @@ -// Copyright 2016 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 gc - -import ( - "fmt" - "go/constant" - "go/token" - "os" - "path/filepath" - "runtime" - "strconv" - "strings" - "unicode" - "unicode/utf8" - - "cmd/compile/internal/base" - "cmd/compile/internal/ir" - "cmd/compile/internal/syntax" - "cmd/compile/internal/typecheck" - "cmd/compile/internal/types" - "cmd/internal/objabi" - "cmd/internal/src" -) - -// parseFiles concurrently parses files into *syntax.File structures. -// Each declaration in every *syntax.File is converted to a syntax tree -// and its root represented by *Node is appended to Target.Decls. -// Returns the total count of parsed lines. -func parseFiles(filenames []string) uint { - noders := make([]*noder, 0, len(filenames)) - // Limit the number of simultaneously open files. - sem := make(chan struct{}, runtime.GOMAXPROCS(0)+10) - - for _, filename := range filenames { - p := &noder{ - basemap: make(map[*syntax.PosBase]*src.PosBase), - err: make(chan syntax.Error), - trackScopes: base.Flag.Dwarf, - } - noders = append(noders, p) - - go func(filename string) { - sem <- struct{}{} - defer func() { <-sem }() - defer close(p.err) - base := syntax.NewFileBase(filename) - - f, err := os.Open(filename) - if err != nil { - p.error(syntax.Error{Msg: err.Error()}) - return - } - defer f.Close() - - p.file, _ = syntax.Parse(base, f, p.error, p.pragma, syntax.CheckBranches) // errors are tracked via p.error - }(filename) - } - - var lines uint - for _, p := range noders { - for e := range p.err { - p.errorAt(e.Pos, "%s", e.Msg) - } - - p.node() - lines += p.file.Lines - p.file = nil // release memory - - if base.SyntaxErrors() != 0 { - base.ErrorExit() - } - // Always run testdclstack here, even when debug_dclstack is not set, as a sanity measure. - types.CheckDclstack() - } - - for _, p := range noders { - p.processPragmas() - } - - types.LocalPkg.Height = myheight - - return lines -} - -// makeSrcPosBase translates from a *syntax.PosBase to a *src.PosBase. -func (p *noder) makeSrcPosBase(b0 *syntax.PosBase) *src.PosBase { - // fast path: most likely PosBase hasn't changed - if p.basecache.last == b0 { - return p.basecache.base - } - - b1, ok := p.basemap[b0] - if !ok { - fn := b0.Filename() - if b0.IsFileBase() { - b1 = src.NewFileBase(fn, absFilename(fn)) - } else { - // line directive base - p0 := b0.Pos() - p0b := p0.Base() - if p0b == b0 { - panic("infinite recursion in makeSrcPosBase") - } - p1 := src.MakePos(p.makeSrcPosBase(p0b), p0.Line(), p0.Col()) - b1 = src.NewLinePragmaBase(p1, fn, fileh(fn), b0.Line(), b0.Col()) - } - p.basemap[b0] = b1 - } - - // update cache - p.basecache.last = b0 - p.basecache.base = b1 - - return b1 -} - -func (p *noder) makeXPos(pos syntax.Pos) (_ src.XPos) { - return base.Ctxt.PosTable.XPos(src.MakePos(p.makeSrcPosBase(pos.Base()), pos.Line(), pos.Col())) -} - -func (p *noder) errorAt(pos syntax.Pos, format string, args ...interface{}) { - base.ErrorfAt(p.makeXPos(pos), format, args...) -} - -// TODO(gri) Can we eliminate fileh in favor of absFilename? -func fileh(name string) string { - return objabi.AbsFile("", name, base.Flag.TrimPath) -} - -func absFilename(name string) string { - return objabi.AbsFile(base.Ctxt.Pathname, name, base.Flag.TrimPath) -} - -// noder transforms package syntax's AST into a Node tree. -type noder struct { - basemap map[*syntax.PosBase]*src.PosBase - basecache struct { - last *syntax.PosBase - base *src.PosBase - } - - file *syntax.File - linknames []linkname - pragcgobuf [][]string - err chan syntax.Error - scope ir.ScopeID - importedUnsafe bool - importedEmbed bool - - // scopeVars is a stack tracking the number of variables declared in the - // current function at the moment each open scope was opened. - trackScopes bool - scopeVars []int - - lastCloseScopePos syntax.Pos -} - -func (p *noder) funcBody(fn *ir.Func, block *syntax.BlockStmt) { - oldScope := p.scope - p.scope = 0 - typecheck.StartFuncBody(fn) - - if block != nil { - body := p.stmts(block.List) - if body == nil { - body = []ir.Node{ir.NewBlockStmt(base.Pos, nil)} - } - fn.Body.Set(body) - - base.Pos = p.makeXPos(block.Rbrace) - fn.Endlineno = base.Pos - } - - typecheck.FinishFuncBody() - p.scope = oldScope -} - -func (p *noder) openScope(pos syntax.Pos) { - types.Markdcl() - - if p.trackScopes { - ir.CurFunc.Parents = append(ir.CurFunc.Parents, p.scope) - p.scopeVars = append(p.scopeVars, len(ir.CurFunc.Dcl)) - p.scope = ir.ScopeID(len(ir.CurFunc.Parents)) - - p.markScope(pos) - } -} - -func (p *noder) closeScope(pos syntax.Pos) { - p.lastCloseScopePos = pos - types.Popdcl() - - if p.trackScopes { - scopeVars := p.scopeVars[len(p.scopeVars)-1] - p.scopeVars = p.scopeVars[:len(p.scopeVars)-1] - if scopeVars == len(ir.CurFunc.Dcl) { - // no variables were declared in this scope, so we can retract it. - - if int(p.scope) != len(ir.CurFunc.Parents) { - base.Fatalf("scope tracking inconsistency, no variables declared but scopes were not retracted") - } - - p.scope = ir.CurFunc.Parents[p.scope-1] - ir.CurFunc.Parents = ir.CurFunc.Parents[:len(ir.CurFunc.Parents)-1] - - nmarks := len(ir.CurFunc.Marks) - ir.CurFunc.Marks[nmarks-1].Scope = p.scope - prevScope := ir.ScopeID(0) - if nmarks >= 2 { - prevScope = ir.CurFunc.Marks[nmarks-2].Scope - } - if ir.CurFunc.Marks[nmarks-1].Scope == prevScope { - ir.CurFunc.Marks = ir.CurFunc.Marks[:nmarks-1] - } - return - } - - p.scope = ir.CurFunc.Parents[p.scope-1] - - p.markScope(pos) - } -} - -func (p *noder) markScope(pos syntax.Pos) { - xpos := p.makeXPos(pos) - if i := len(ir.CurFunc.Marks); i > 0 && ir.CurFunc.Marks[i-1].Pos == xpos { - ir.CurFunc.Marks[i-1].Scope = p.scope - } else { - ir.CurFunc.Marks = append(ir.CurFunc.Marks, ir.Mark{Pos: xpos, Scope: p.scope}) - } -} - -// closeAnotherScope is like closeScope, but it reuses the same mark -// position as the last closeScope call. This is useful for "for" and -// "if" statements, as their implicit blocks always end at the same -// position as an explicit block. -func (p *noder) closeAnotherScope() { - p.closeScope(p.lastCloseScopePos) -} - -// linkname records a //go:linkname directive. -type linkname struct { - pos syntax.Pos - local string - remote string -} - -func (p *noder) node() { - types.Block = 1 - p.importedUnsafe = false - p.importedEmbed = false - - p.setlineno(p.file.PkgName) - mkpackage(p.file.PkgName.Value) - - if pragma, ok := p.file.Pragma.(*Pragma); ok { - pragma.Flag &^= ir.GoBuildPragma - p.checkUnused(pragma) - } - - typecheck.Target.Decls = append(typecheck.Target.Decls, p.decls(p.file.DeclList)...) - - base.Pos = src.NoXPos - clearImports() -} - -func (p *noder) processPragmas() { - for _, l := range p.linknames { - if !p.importedUnsafe { - p.errorAt(l.pos, "//go:linkname only allowed in Go files that import \"unsafe\"") - continue - } - n := ir.AsNode(typecheck.Lookup(l.local).Def) - if n == nil || n.Op() != ir.ONAME { - // TODO(mdempsky): Change to p.errorAt before Go 1.17 release. - // base.WarnfAt(p.makeXPos(l.pos), "//go:linkname must refer to declared function or variable (will be an error in Go 1.17)") - continue - } - if n.Sym().Linkname != "" { - p.errorAt(l.pos, "duplicate //go:linkname for %s", l.local) - continue - } - n.Sym().Linkname = l.remote - } - typecheck.Target.CgoPragmas = append(typecheck.Target.CgoPragmas, p.pragcgobuf...) -} - -func (p *noder) decls(decls []syntax.Decl) (l []ir.Node) { - var cs constState - - for _, decl := range decls { - p.setlineno(decl) - switch decl := decl.(type) { - case *syntax.ImportDecl: - p.importDecl(decl) - - case *syntax.VarDecl: - l = append(l, p.varDecl(decl)...) - - case *syntax.ConstDecl: - l = append(l, p.constDecl(decl, &cs)...) - - case *syntax.TypeDecl: - l = append(l, p.typeDecl(decl)) - - case *syntax.FuncDecl: - l = append(l, p.funcDecl(decl)) - - default: - panic("unhandled Decl") - } - } - - return -} - -func (p *noder) importDecl(imp *syntax.ImportDecl) { - if imp.Path.Bad { - return // avoid follow-on errors if there was a syntax error - } - - if pragma, ok := imp.Pragma.(*Pragma); ok { - p.checkUnused(pragma) - } - - ipkg := importfile(p.basicLit(imp.Path)) - if ipkg == nil { - if base.Errors() == 0 { - base.Fatalf("phase error in import") - } - return - } - - if ipkg == ir.Pkgs.Unsafe { - p.importedUnsafe = true - } - if ipkg.Path == "embed" { - p.importedEmbed = true - } - - if !ipkg.Direct { - typecheck.Target.Imports = append(typecheck.Target.Imports, ipkg) - } - ipkg.Direct = true - - var my *types.Sym - if imp.LocalPkgName != nil { - my = p.name(imp.LocalPkgName) - } else { - my = typecheck.Lookup(ipkg.Name) - } - - pack := ir.NewPkgName(p.pos(imp), my, ipkg) - - switch my.Name { - case ".": - importDot(pack) - return - case "init": - base.ErrorfAt(pack.Pos(), "cannot import package as init - init must be a func") - return - case "_": - return - } - if my.Def != nil { - typecheck.Redeclared(pack.Pos(), my, "as imported package name") - } - my.Def = pack - my.Lastlineno = pack.Pos() - my.Block = 1 // at top level -} - -func (p *noder) varDecl(decl *syntax.VarDecl) []ir.Node { - names := p.declNames(ir.ONAME, decl.NameList) - typ := p.typeExprOrNil(decl.Type) - - var exprs []ir.Node - if decl.Values != nil { - exprs = p.exprList(decl.Values) - } - - if pragma, ok := decl.Pragma.(*Pragma); ok { - if len(pragma.Embeds) > 0 { - if !p.importedEmbed { - // This check can't be done when building the list pragma.Embeds - // because that list is created before the noder starts walking over the file, - // so at that point it hasn't seen the imports. - // We're left to check now, just before applying the //go:embed lines. - for _, e := range pragma.Embeds { - p.errorAt(e.Pos, "//go:embed only allowed in Go files that import \"embed\"") - } - } else { - exprs = varEmbed(p, names, typ, exprs, pragma.Embeds) - } - pragma.Embeds = nil - } - p.checkUnused(pragma) - } - - p.setlineno(decl) - return typecheck.DeclVars(names, typ, exprs) -} - -// constState tracks state between constant specifiers within a -// declaration group. This state is kept separate from noder so nested -// constant declarations are handled correctly (e.g., issue 15550). -type constState struct { - group *syntax.Group - typ ir.Ntype - values []ir.Node - iota int64 -} - -func (p *noder) constDecl(decl *syntax.ConstDecl, cs *constState) []ir.Node { - if decl.Group == nil || decl.Group != cs.group { - *cs = constState{ - group: decl.Group, - } - } - - if pragma, ok := decl.Pragma.(*Pragma); ok { - p.checkUnused(pragma) - } - - names := p.declNames(ir.OLITERAL, decl.NameList) - typ := p.typeExprOrNil(decl.Type) - - var values []ir.Node - if decl.Values != nil { - values = p.exprList(decl.Values) - cs.typ, cs.values = typ, values - } else { - if typ != nil { - base.Errorf("const declaration cannot have type without expression") - } - typ, values = cs.typ, cs.values - } - - nn := make([]ir.Node, 0, len(names)) - for i, n := range names { - if i >= len(values) { - base.Errorf("missing value in const declaration") - break - } - v := values[i] - if decl.Values == nil { - v = ir.DeepCopy(n.Pos(), v) - } - typecheck.Declare(n, typecheck.DeclContext) - - n.Ntype = typ - n.Defn = v - n.SetIota(cs.iota) - - nn = append(nn, ir.NewDecl(p.pos(decl), ir.ODCLCONST, n)) - } - - if len(values) > len(names) { - base.Errorf("extra expression in const declaration") - } - - cs.iota++ - - return nn -} - -func (p *noder) typeDecl(decl *syntax.TypeDecl) ir.Node { - n := p.declName(ir.OTYPE, decl.Name) - typecheck.Declare(n, typecheck.DeclContext) - - // decl.Type may be nil but in that case we got a syntax error during parsing - typ := p.typeExprOrNil(decl.Type) - - n.Ntype = typ - n.SetAlias(decl.Alias) - if pragma, ok := decl.Pragma.(*Pragma); ok { - if !decl.Alias { - n.SetPragma(pragma.Flag & TypePragmas) - pragma.Flag &^= TypePragmas - } - p.checkUnused(pragma) - } - - nod := ir.NewDecl(p.pos(decl), ir.ODCLTYPE, n) - if n.Alias() && !types.AllowsGoVersion(types.LocalPkg, 1, 9) { - base.ErrorfAt(nod.Pos(), "type aliases only supported as of -lang=go1.9") - } - return nod -} - -func (p *noder) declNames(op ir.Op, names []*syntax.Name) []*ir.Name { - nodes := make([]*ir.Name, 0, len(names)) - for _, name := range names { - nodes = append(nodes, p.declName(op, name)) - } - return nodes -} - -func (p *noder) declName(op ir.Op, name *syntax.Name) *ir.Name { - return ir.NewDeclNameAt(p.pos(name), op, p.name(name)) -} - -func (p *noder) funcDecl(fun *syntax.FuncDecl) ir.Node { - name := p.name(fun.Name) - t := p.signature(fun.Recv, fun.Type) - f := ir.NewFunc(p.pos(fun)) - - if fun.Recv == nil { - if name.Name == "init" { - name = renameinit() - if len(t.Params) > 0 || len(t.Results) > 0 { - base.ErrorfAt(f.Pos(), "func init must have no arguments and no return values") - } - typecheck.Target.Inits = append(typecheck.Target.Inits, f) - } - - if types.LocalPkg.Name == "main" && name.Name == "main" { - if len(t.Params) > 0 || len(t.Results) > 0 { - base.ErrorfAt(f.Pos(), "func main must have no arguments and no return values") - } - } - } else { - f.Shortname = name - name = ir.BlankNode.Sym() // filled in by typecheckfunc - } - - f.Nname = ir.NewFuncNameAt(p.pos(fun.Name), name, f) - f.Nname.Defn = f - f.Nname.Ntype = t - - if pragma, ok := fun.Pragma.(*Pragma); ok { - f.Pragma = pragma.Flag & FuncPragmas - if pragma.Flag&ir.Systemstack != 0 && pragma.Flag&ir.Nosplit != 0 { - base.ErrorfAt(f.Pos(), "go:nosplit and go:systemstack cannot be combined") - } - pragma.Flag &^= FuncPragmas - p.checkUnused(pragma) - } - - if fun.Recv == nil { - typecheck.Declare(f.Nname, ir.PFUNC) - } - - p.funcBody(f, fun.Body) - - if fun.Body != nil { - if f.Pragma&ir.Noescape != 0 { - base.ErrorfAt(f.Pos(), "can only use //go:noescape with external func implementations") - } - } else { - if base.Flag.Complete || strings.HasPrefix(ir.FuncName(f), "init.") { - // Linknamed functions are allowed to have no body. Hopefully - // the linkname target has a body. See issue 23311. - isLinknamed := false - for _, n := range p.linknames { - if ir.FuncName(f) == n.local { - isLinknamed = true - break - } - } - if !isLinknamed { - base.ErrorfAt(f.Pos(), "missing function body") - } - } - } - - return f -} - -func (p *noder) signature(recv *syntax.Field, typ *syntax.FuncType) *ir.FuncType { - var rcvr *ir.Field - if recv != nil { - rcvr = p.param(recv, false, false) - } - return ir.NewFuncType(p.pos(typ), rcvr, - p.params(typ.ParamList, true), - p.params(typ.ResultList, false)) -} - -func (p *noder) params(params []*syntax.Field, dddOk bool) []*ir.Field { - nodes := make([]*ir.Field, 0, len(params)) - for i, param := range params { - p.setlineno(param) - nodes = append(nodes, p.param(param, dddOk, i+1 == len(params))) - } - return nodes -} - -func (p *noder) param(param *syntax.Field, dddOk, final bool) *ir.Field { - var name *types.Sym - if param.Name != nil { - name = p.name(param.Name) - } - - typ := p.typeExpr(param.Type) - n := ir.NewField(p.pos(param), name, typ, nil) - - // rewrite ...T parameter - if typ, ok := typ.(*ir.SliceType); ok && typ.DDD { - if !dddOk { - // We mark these as syntax errors to get automatic elimination - // of multiple such errors per line (see ErrorfAt in subr.go). - base.Errorf("syntax error: cannot use ... in receiver or result parameter list") - } else if !final { - if param.Name == nil { - base.Errorf("syntax error: cannot use ... with non-final parameter") - } else { - p.errorAt(param.Name.Pos(), "syntax error: cannot use ... with non-final parameter %s", param.Name.Value) - } - } - typ.DDD = false - n.IsDDD = true - } - - return n -} - -func (p *noder) exprList(expr syntax.Expr) []ir.Node { - if list, ok := expr.(*syntax.ListExpr); ok { - return p.exprs(list.ElemList) - } - return []ir.Node{p.expr(expr)} -} - -func (p *noder) exprs(exprs []syntax.Expr) []ir.Node { - nodes := make([]ir.Node, 0, len(exprs)) - for _, expr := range exprs { - nodes = append(nodes, p.expr(expr)) - } - return nodes -} - -func (p *noder) expr(expr syntax.Expr) ir.Node { - p.setlineno(expr) - switch expr := expr.(type) { - case nil, *syntax.BadExpr: - return nil - case *syntax.Name: - return p.mkname(expr) - case *syntax.BasicLit: - n := ir.NewLiteral(p.basicLit(expr)) - if expr.Kind == syntax.RuneLit { - n.SetType(types.UntypedRune) - } - n.SetDiag(expr.Bad) // avoid follow-on errors if there was a syntax error - return n - case *syntax.CompositeLit: - n := ir.NewCompLitExpr(p.pos(expr), ir.OCOMPLIT, nil, nil) - if expr.Type != nil { - n.Ntype = ir.Node(p.expr(expr.Type)).(ir.Ntype) - } - l := p.exprs(expr.ElemList) - for i, e := range l { - l[i] = p.wrapname(expr.ElemList[i], e) - } - n.List.Set(l) - base.Pos = p.makeXPos(expr.Rbrace) - return n - case *syntax.KeyValueExpr: - // use position of expr.Key rather than of expr (which has position of ':') - return ir.NewKeyExpr(p.pos(expr.Key), p.expr(expr.Key), p.wrapname(expr.Value, p.expr(expr.Value))) - case *syntax.FuncLit: - return p.funcLit(expr) - case *syntax.ParenExpr: - return ir.NewParenExpr(p.pos(expr), p.expr(expr.X)) - case *syntax.SelectorExpr: - // parser.new_dotname - obj := p.expr(expr.X) - if obj.Op() == ir.OPACK { - pack := obj.(*ir.PkgName) - pack.Used = true - return importName(pack.Pkg.Lookup(expr.Sel.Value)) - } - n := ir.NewSelectorExpr(base.Pos, ir.OXDOT, obj, p.name(expr.Sel)) - n.SetPos(p.pos(expr)) // lineno may have been changed by p.expr(expr.X) - return n - case *syntax.IndexExpr: - return ir.NewIndexExpr(p.pos(expr), p.expr(expr.X), p.expr(expr.Index)) - case *syntax.SliceExpr: - op := ir.OSLICE - if expr.Full { - op = ir.OSLICE3 - } - n := ir.NewSliceExpr(p.pos(expr), op, p.expr(expr.X)) - var index [3]ir.Node - for i, x := range &expr.Index { - if x != nil { - index[i] = p.expr(x) - } - } - n.SetSliceBounds(index[0], index[1], index[2]) - return n - case *syntax.AssertExpr: - return ir.NewTypeAssertExpr(p.pos(expr), p.expr(expr.X), p.typeExpr(expr.Type).(ir.Ntype)) - case *syntax.Operation: - if expr.Op == syntax.Add && expr.Y != nil { - return p.sum(expr) - } - x := p.expr(expr.X) - if expr.Y == nil { - pos, op := p.pos(expr), p.unOp(expr.Op) - switch op { - case ir.OADDR: - return typecheck.NodAddrAt(pos, x) - case ir.ODEREF: - return ir.NewStarExpr(pos, x) - } - return ir.NewUnaryExpr(pos, op, x) - } - - pos, op, y := p.pos(expr), p.binOp(expr.Op), p.expr(expr.Y) - switch op { - case ir.OANDAND, ir.OOROR: - return ir.NewLogicalExpr(pos, op, x, y) - } - return ir.NewBinaryExpr(pos, op, x, y) - case *syntax.CallExpr: - n := ir.NewCallExpr(p.pos(expr), ir.OCALL, p.expr(expr.Fun), nil) - n.Args.Set(p.exprs(expr.ArgList)) - n.IsDDD = expr.HasDots - return n - - case *syntax.ArrayType: - var len ir.Node - if expr.Len != nil { - len = p.expr(expr.Len) - } - return ir.NewArrayType(p.pos(expr), len, p.typeExpr(expr.Elem)) - case *syntax.SliceType: - return ir.NewSliceType(p.pos(expr), p.typeExpr(expr.Elem)) - case *syntax.DotsType: - t := ir.NewSliceType(p.pos(expr), p.typeExpr(expr.Elem)) - t.DDD = true - return t - case *syntax.StructType: - return p.structType(expr) - case *syntax.InterfaceType: - return p.interfaceType(expr) - case *syntax.FuncType: - return p.signature(nil, expr) - case *syntax.MapType: - return ir.NewMapType(p.pos(expr), - p.typeExpr(expr.Key), p.typeExpr(expr.Value)) - case *syntax.ChanType: - return ir.NewChanType(p.pos(expr), - p.typeExpr(expr.Elem), p.chanDir(expr.Dir)) - - case *syntax.TypeSwitchGuard: - var tag *ir.Ident - if expr.Lhs != nil { - tag = ir.NewIdent(p.pos(expr.Lhs), p.name(expr.Lhs)) - if ir.IsBlank(tag) { - base.Errorf("invalid variable name %v in type switch", tag) - } - } - return ir.NewTypeSwitchGuard(p.pos(expr), tag, p.expr(expr.X)) - } - panic("unhandled Expr") -} - -// sum efficiently handles very large summation expressions (such as -// in issue #16394). In particular, it avoids left recursion and -// collapses string literals. -func (p *noder) sum(x syntax.Expr) ir.Node { - // While we need to handle long sums with asymptotic - // efficiency, the vast majority of sums are very small: ~95% - // have only 2 or 3 operands, and ~99% of string literals are - // never concatenated. - - adds := make([]*syntax.Operation, 0, 2) - for { - add, ok := x.(*syntax.Operation) - if !ok || add.Op != syntax.Add || add.Y == nil { - break - } - adds = append(adds, add) - x = add.X - } - - // nstr is the current rightmost string literal in the - // summation (if any), and chunks holds its accumulated - // substrings. - // - // Consider the expression x + "a" + "b" + "c" + y. When we - // reach the string literal "a", we assign nstr to point to - // its corresponding Node and initialize chunks to {"a"}. - // Visiting the subsequent string literals "b" and "c", we - // simply append their values to chunks. Finally, when we - // reach the non-constant operand y, we'll join chunks to form - // "abc" and reassign the "a" string literal's value. - // - // N.B., we need to be careful about named string constants - // (indicated by Sym != nil) because 1) we can't modify their - // value, as doing so would affect other uses of the string - // constant, and 2) they may have types, which we need to - // handle correctly. For now, we avoid these problems by - // treating named string constants the same as non-constant - // operands. - var nstr ir.Node - chunks := make([]string, 0, 1) - - n := p.expr(x) - if ir.IsConst(n, constant.String) && n.Sym() == nil { - nstr = n - chunks = append(chunks, ir.StringVal(nstr)) - } - - for i := len(adds) - 1; i >= 0; i-- { - add := adds[i] - - r := p.expr(add.Y) - if ir.IsConst(r, constant.String) && r.Sym() == nil { - if nstr != nil { - // Collapse r into nstr instead of adding to n. - chunks = append(chunks, ir.StringVal(r)) - continue - } - - nstr = r - chunks = append(chunks, ir.StringVal(nstr)) - } else { - if len(chunks) > 1 { - nstr.SetVal(constant.MakeString(strings.Join(chunks, ""))) - } - nstr = nil - chunks = chunks[:0] - } - n = ir.NewBinaryExpr(p.pos(add), ir.OADD, n, r) - } - if len(chunks) > 1 { - nstr.SetVal(constant.MakeString(strings.Join(chunks, ""))) - } - - return n -} - -func (p *noder) typeExpr(typ syntax.Expr) ir.Ntype { - // TODO(mdempsky): Be stricter? typecheck should handle errors anyway. - n := p.expr(typ) - if n == nil { - return nil - } - if _, ok := n.(ir.Ntype); !ok { - ir.Dump("NOT NTYPE", n) - } - return n.(ir.Ntype) -} - -func (p *noder) typeExprOrNil(typ syntax.Expr) ir.Ntype { - if typ != nil { - return p.typeExpr(typ) - } - return nil -} - -func (p *noder) chanDir(dir syntax.ChanDir) types.ChanDir { - switch dir { - case 0: - return types.Cboth - case syntax.SendOnly: - return types.Csend - case syntax.RecvOnly: - return types.Crecv - } - panic("unhandled ChanDir") -} - -func (p *noder) structType(expr *syntax.StructType) ir.Node { - l := make([]*ir.Field, 0, len(expr.FieldList)) - for i, field := range expr.FieldList { - p.setlineno(field) - var n *ir.Field - if field.Name == nil { - n = p.embedded(field.Type) - } else { - n = ir.NewField(p.pos(field), p.name(field.Name), p.typeExpr(field.Type), nil) - } - if i < len(expr.TagList) && expr.TagList[i] != nil { - n.Note = constant.StringVal(p.basicLit(expr.TagList[i])) - } - l = append(l, n) - } - - p.setlineno(expr) - return ir.NewStructType(p.pos(expr), l) -} - -func (p *noder) interfaceType(expr *syntax.InterfaceType) ir.Node { - l := make([]*ir.Field, 0, len(expr.MethodList)) - for _, method := range expr.MethodList { - p.setlineno(method) - var n *ir.Field - if method.Name == nil { - n = ir.NewField(p.pos(method), nil, importName(p.packname(method.Type)).(ir.Ntype), nil) - } else { - mname := p.name(method.Name) - if mname.IsBlank() { - base.Errorf("methods must have a unique non-blank name") - continue - } - sig := p.typeExpr(method.Type).(*ir.FuncType) - sig.Recv = fakeRecv() - n = ir.NewField(p.pos(method), mname, sig, nil) - } - l = append(l, n) - } - - return ir.NewInterfaceType(p.pos(expr), l) -} - -func (p *noder) packname(expr syntax.Expr) *types.Sym { - switch expr := expr.(type) { - case *syntax.Name: - name := p.name(expr) - if n := oldname(name); n.Name() != nil && n.Name().PkgName != nil { - n.Name().PkgName.Used = true - } - return name - case *syntax.SelectorExpr: - name := p.name(expr.X.(*syntax.Name)) - def := ir.AsNode(name.Def) - if def == nil { - base.Errorf("undefined: %v", name) - return name - } - var pkg *types.Pkg - if def.Op() != ir.OPACK { - base.Errorf("%v is not a package", name) - pkg = types.LocalPkg - } else { - def := def.(*ir.PkgName) - def.Used = true - pkg = def.Pkg - } - return pkg.Lookup(expr.Sel.Value) - } - panic(fmt.Sprintf("unexpected packname: %#v", expr)) -} - -func (p *noder) embedded(typ syntax.Expr) *ir.Field { - op, isStar := typ.(*syntax.Operation) - if isStar { - if op.Op != syntax.Mul || op.Y != nil { - panic("unexpected Operation") - } - typ = op.X - } - - sym := p.packname(typ) - n := ir.NewField(p.pos(typ), typecheck.Lookup(sym.Name), importName(sym).(ir.Ntype), nil) - n.Embedded = true - - if isStar { - n.Ntype = ir.NewStarExpr(p.pos(op), n.Ntype) - } - return n -} - -func (p *noder) stmts(stmts []syntax.Stmt) []ir.Node { - return p.stmtsFall(stmts, false) -} - -func (p *noder) stmtsFall(stmts []syntax.Stmt, fallOK bool) []ir.Node { - var nodes []ir.Node - for i, stmt := range stmts { - s := p.stmtFall(stmt, fallOK && i+1 == len(stmts)) - if s == nil { - } else if s.Op() == ir.OBLOCK && len(s.(*ir.BlockStmt).List) > 0 { - // Inline non-empty block. - // Empty blocks must be preserved for checkreturn. - nodes = append(nodes, s.(*ir.BlockStmt).List...) - } else { - nodes = append(nodes, s) - } - } - return nodes -} - -func (p *noder) stmt(stmt syntax.Stmt) ir.Node { - return p.stmtFall(stmt, false) -} - -func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) ir.Node { - p.setlineno(stmt) - switch stmt := stmt.(type) { - case *syntax.EmptyStmt: - return nil - case *syntax.LabeledStmt: - return p.labeledStmt(stmt, fallOK) - case *syntax.BlockStmt: - l := p.blockStmt(stmt) - if len(l) == 0 { - // TODO(mdempsky): Line number? - return ir.NewBlockStmt(base.Pos, nil) - } - return ir.NewBlockStmt(src.NoXPos, l) - case *syntax.ExprStmt: - return p.wrapname(stmt, p.expr(stmt.X)) - case *syntax.SendStmt: - return ir.NewSendStmt(p.pos(stmt), p.expr(stmt.Chan), p.expr(stmt.Value)) - case *syntax.DeclStmt: - return ir.NewBlockStmt(src.NoXPos, p.decls(stmt.DeclList)) - case *syntax.AssignStmt: - if stmt.Op != 0 && stmt.Op != syntax.Def { - n := ir.NewAssignOpStmt(p.pos(stmt), p.binOp(stmt.Op), p.expr(stmt.Lhs), p.expr(stmt.Rhs)) - n.IncDec = stmt.Rhs == syntax.ImplicitOne - return n - } - - rhs := p.exprList(stmt.Rhs) - if list, ok := stmt.Lhs.(*syntax.ListExpr); ok && len(list.ElemList) != 1 || len(rhs) != 1 { - n := ir.NewAssignListStmt(p.pos(stmt), ir.OAS2, nil, nil) - n.Def = stmt.Op == syntax.Def - n.Lhs.Set(p.assignList(stmt.Lhs, n, n.Def)) - n.Rhs.Set(rhs) - return n - } - - n := ir.NewAssignStmt(p.pos(stmt), nil, nil) - n.Def = stmt.Op == syntax.Def - n.X = p.assignList(stmt.Lhs, n, n.Def)[0] - n.Y = rhs[0] - return n - - case *syntax.BranchStmt: - var op ir.Op - switch stmt.Tok { - case syntax.Break: - op = ir.OBREAK - case syntax.Continue: - op = ir.OCONTINUE - case syntax.Fallthrough: - if !fallOK { - base.Errorf("fallthrough statement out of place") - } - op = ir.OFALL - case syntax.Goto: - op = ir.OGOTO - default: - panic("unhandled BranchStmt") - } - var sym *types.Sym - if stmt.Label != nil { - sym = p.name(stmt.Label) - } - return ir.NewBranchStmt(p.pos(stmt), op, sym) - case *syntax.CallStmt: - var op ir.Op - switch stmt.Tok { - case syntax.Defer: - op = ir.ODEFER - case syntax.Go: - op = ir.OGO - default: - panic("unhandled CallStmt") - } - return ir.NewGoDeferStmt(p.pos(stmt), op, p.expr(stmt.Call)) - case *syntax.ReturnStmt: - var results []ir.Node - if stmt.Results != nil { - results = p.exprList(stmt.Results) - } - n := ir.NewReturnStmt(p.pos(stmt), nil) - n.Results.Set(results) - if len(n.Results) == 0 && ir.CurFunc != nil { - for _, ln := range ir.CurFunc.Dcl { - if ln.Class_ == ir.PPARAM { - continue - } - if ln.Class_ != ir.PPARAMOUT { - break - } - if ln.Sym().Def != ln { - base.Errorf("%s is shadowed during return", ln.Sym().Name) - } - } - } - return n - case *syntax.IfStmt: - return p.ifStmt(stmt) - case *syntax.ForStmt: - return p.forStmt(stmt) - case *syntax.SwitchStmt: - return p.switchStmt(stmt) - case *syntax.SelectStmt: - return p.selectStmt(stmt) - } - panic("unhandled Stmt") -} - -func (p *noder) assignList(expr syntax.Expr, defn ir.Node, colas bool) []ir.Node { - if !colas { - return p.exprList(expr) - } - - var exprs []syntax.Expr - if list, ok := expr.(*syntax.ListExpr); ok { - exprs = list.ElemList - } else { - exprs = []syntax.Expr{expr} - } - - res := make([]ir.Node, len(exprs)) - seen := make(map[*types.Sym]bool, len(exprs)) - - newOrErr := false - for i, expr := range exprs { - p.setlineno(expr) - res[i] = ir.BlankNode - - name, ok := expr.(*syntax.Name) - if !ok { - p.errorAt(expr.Pos(), "non-name %v on left side of :=", p.expr(expr)) - newOrErr = true - continue - } - - sym := p.name(name) - if sym.IsBlank() { - continue - } - - if seen[sym] { - p.errorAt(expr.Pos(), "%v repeated on left side of :=", sym) - newOrErr = true - continue - } - seen[sym] = true - - if sym.Block == types.Block { - res[i] = oldname(sym) - continue - } - - newOrErr = true - n := typecheck.NewName(sym) - typecheck.Declare(n, typecheck.DeclContext) - n.Defn = defn - defn.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, n)) - res[i] = n - } - - if !newOrErr { - base.ErrorfAt(defn.Pos(), "no new variables on left side of :=") - } - return res -} - -func (p *noder) blockStmt(stmt *syntax.BlockStmt) []ir.Node { - p.openScope(stmt.Pos()) - nodes := p.stmts(stmt.List) - p.closeScope(stmt.Rbrace) - return nodes -} - -func (p *noder) ifStmt(stmt *syntax.IfStmt) ir.Node { - p.openScope(stmt.Pos()) - n := ir.NewIfStmt(p.pos(stmt), nil, nil, nil) - if stmt.Init != nil { - *n.PtrInit() = []ir.Node{p.stmt(stmt.Init)} - } - if stmt.Cond != nil { - n.Cond = p.expr(stmt.Cond) - } - n.Body.Set(p.blockStmt(stmt.Then)) - if stmt.Else != nil { - e := p.stmt(stmt.Else) - if e.Op() == ir.OBLOCK { - e := e.(*ir.BlockStmt) - n.Else.Set(e.List) - } else { - n.Else = []ir.Node{e} - } - } - p.closeAnotherScope() - return n -} - -func (p *noder) forStmt(stmt *syntax.ForStmt) ir.Node { - p.openScope(stmt.Pos()) - if r, ok := stmt.Init.(*syntax.RangeClause); ok { - if stmt.Cond != nil || stmt.Post != nil { - panic("unexpected RangeClause") - } - - n := ir.NewRangeStmt(p.pos(r), nil, p.expr(r.X), nil) - if r.Lhs != nil { - n.Def = r.Def - n.Vars.Set(p.assignList(r.Lhs, n, n.Def)) - } - n.Body.Set(p.blockStmt(stmt.Body)) - p.closeAnotherScope() - return n - } - - n := ir.NewForStmt(p.pos(stmt), nil, nil, nil, nil) - if stmt.Init != nil { - *n.PtrInit() = []ir.Node{p.stmt(stmt.Init)} - } - if stmt.Cond != nil { - n.Cond = p.expr(stmt.Cond) - } - if stmt.Post != nil { - n.Post = p.stmt(stmt.Post) - } - n.Body.Set(p.blockStmt(stmt.Body)) - p.closeAnotherScope() - return n -} - -func (p *noder) switchStmt(stmt *syntax.SwitchStmt) ir.Node { - p.openScope(stmt.Pos()) - n := ir.NewSwitchStmt(p.pos(stmt), nil, nil) - if stmt.Init != nil { - *n.PtrInit() = []ir.Node{p.stmt(stmt.Init)} - } - if stmt.Tag != nil { - n.Tag = p.expr(stmt.Tag) - } - - var tswitch *ir.TypeSwitchGuard - if l := n.Tag; l != nil && l.Op() == ir.OTYPESW { - tswitch = l.(*ir.TypeSwitchGuard) - } - n.Cases.Set(p.caseClauses(stmt.Body, tswitch, stmt.Rbrace)) - - p.closeScope(stmt.Rbrace) - return n -} - -func (p *noder) caseClauses(clauses []*syntax.CaseClause, tswitch *ir.TypeSwitchGuard, rbrace syntax.Pos) []ir.Node { - nodes := make([]ir.Node, 0, len(clauses)) - for i, clause := range clauses { - p.setlineno(clause) - if i > 0 { - p.closeScope(clause.Pos()) - } - p.openScope(clause.Pos()) - - n := ir.NewCaseStmt(p.pos(clause), nil, nil) - if clause.Cases != nil { - n.List.Set(p.exprList(clause.Cases)) - } - if tswitch != nil && tswitch.Tag != nil { - nn := typecheck.NewName(tswitch.Tag.Sym()) - typecheck.Declare(nn, typecheck.DeclContext) - n.Vars = []ir.Node{nn} - // keep track of the instances for reporting unused - nn.Defn = tswitch - } - - // Trim trailing empty statements. We omit them from - // the Node AST anyway, and it's easier to identify - // out-of-place fallthrough statements without them. - body := clause.Body - for len(body) > 0 { - if _, ok := body[len(body)-1].(*syntax.EmptyStmt); !ok { - break - } - body = body[:len(body)-1] - } - - n.Body.Set(p.stmtsFall(body, true)) - if l := len(n.Body); l > 0 && n.Body[l-1].Op() == ir.OFALL { - if tswitch != nil { - base.Errorf("cannot fallthrough in type switch") - } - if i+1 == len(clauses) { - base.Errorf("cannot fallthrough final case in switch") - } - } - - nodes = append(nodes, n) - } - if len(clauses) > 0 { - p.closeScope(rbrace) - } - return nodes -} - -func (p *noder) selectStmt(stmt *syntax.SelectStmt) ir.Node { - n := ir.NewSelectStmt(p.pos(stmt), nil) - n.Cases.Set(p.commClauses(stmt.Body, stmt.Rbrace)) - return n -} - -func (p *noder) commClauses(clauses []*syntax.CommClause, rbrace syntax.Pos) []ir.Node { - nodes := make([]ir.Node, 0, len(clauses)) - for i, clause := range clauses { - p.setlineno(clause) - if i > 0 { - p.closeScope(clause.Pos()) - } - p.openScope(clause.Pos()) - - n := ir.NewCaseStmt(p.pos(clause), nil, nil) - if clause.Comm != nil { - n.List = []ir.Node{p.stmt(clause.Comm)} - } - n.Body.Set(p.stmts(clause.Body)) - nodes = append(nodes, n) - } - if len(clauses) > 0 { - p.closeScope(rbrace) - } - return nodes -} - -func (p *noder) labeledStmt(label *syntax.LabeledStmt, fallOK bool) ir.Node { - sym := p.name(label.Label) - lhs := ir.NewLabelStmt(p.pos(label), sym) - - var ls ir.Node - if label.Stmt != nil { // TODO(mdempsky): Should always be present. - ls = p.stmtFall(label.Stmt, fallOK) - // Attach label directly to control statement too. - if ls != nil { - switch ls.Op() { - case ir.OFOR: - ls := ls.(*ir.ForStmt) - ls.Label = sym - case ir.ORANGE: - ls := ls.(*ir.RangeStmt) - ls.Label = sym - case ir.OSWITCH: - ls := ls.(*ir.SwitchStmt) - ls.Label = sym - case ir.OSELECT: - ls := ls.(*ir.SelectStmt) - ls.Label = sym - } - } - } - - l := []ir.Node{lhs} - if ls != nil { - if ls.Op() == ir.OBLOCK { - ls := ls.(*ir.BlockStmt) - l = append(l, ls.List...) - } else { - l = append(l, ls) - } - } - return ir.NewBlockStmt(src.NoXPos, l) -} - -var unOps = [...]ir.Op{ - syntax.Recv: ir.ORECV, - syntax.Mul: ir.ODEREF, - syntax.And: ir.OADDR, - - syntax.Not: ir.ONOT, - syntax.Xor: ir.OBITNOT, - syntax.Add: ir.OPLUS, - syntax.Sub: ir.ONEG, -} - -func (p *noder) unOp(op syntax.Operator) ir.Op { - if uint64(op) >= uint64(len(unOps)) || unOps[op] == 0 { - panic("invalid Operator") - } - return unOps[op] -} - -var binOps = [...]ir.Op{ - syntax.OrOr: ir.OOROR, - syntax.AndAnd: ir.OANDAND, - - syntax.Eql: ir.OEQ, - syntax.Neq: ir.ONE, - syntax.Lss: ir.OLT, - syntax.Leq: ir.OLE, - syntax.Gtr: ir.OGT, - syntax.Geq: ir.OGE, - - syntax.Add: ir.OADD, - syntax.Sub: ir.OSUB, - syntax.Or: ir.OOR, - syntax.Xor: ir.OXOR, - - syntax.Mul: ir.OMUL, - syntax.Div: ir.ODIV, - syntax.Rem: ir.OMOD, - syntax.And: ir.OAND, - syntax.AndNot: ir.OANDNOT, - syntax.Shl: ir.OLSH, - syntax.Shr: ir.ORSH, -} - -func (p *noder) binOp(op syntax.Operator) ir.Op { - if uint64(op) >= uint64(len(binOps)) || binOps[op] == 0 { - panic("invalid Operator") - } - return binOps[op] -} - -// checkLangCompat reports an error if the representation of a numeric -// literal is not compatible with the current language version. -func checkLangCompat(lit *syntax.BasicLit) { - s := lit.Value - if len(s) <= 2 || types.AllowsGoVersion(types.LocalPkg, 1, 13) { - return - } - // len(s) > 2 - if strings.Contains(s, "_") { - base.ErrorfVers("go1.13", "underscores in numeric literals") - return - } - if s[0] != '0' { - return - } - radix := s[1] - if radix == 'b' || radix == 'B' { - base.ErrorfVers("go1.13", "binary literals") - return - } - if radix == 'o' || radix == 'O' { - base.ErrorfVers("go1.13", "0o/0O-style octal literals") - return - } - if lit.Kind != syntax.IntLit && (radix == 'x' || radix == 'X') { - base.ErrorfVers("go1.13", "hexadecimal floating-point literals") - } -} - -func (p *noder) basicLit(lit *syntax.BasicLit) constant.Value { - // We don't use the errors of the conversion routines to determine - // if a literal string is valid because the conversion routines may - // accept a wider syntax than the language permits. Rely on lit.Bad - // instead. - if lit.Bad { - return constant.MakeUnknown() - } - - switch lit.Kind { - case syntax.IntLit, syntax.FloatLit, syntax.ImagLit: - checkLangCompat(lit) - } - - v := constant.MakeFromLiteral(lit.Value, tokenForLitKind[lit.Kind], 0) - if v.Kind() == constant.Unknown { - // TODO(mdempsky): Better error message? - p.errorAt(lit.Pos(), "malformed constant: %s", lit.Value) - } - - // go/constant uses big.Rat by default, which is more precise, but - // causes toolstash -cmp and some tests to fail. For now, convert - // to big.Float to match cmd/compile's historical precision. - // TODO(mdempsky): Remove. - if v.Kind() == constant.Float { - v = constant.Make(ir.BigFloat(v)) - } - - return v -} - -var tokenForLitKind = [...]token.Token{ - syntax.IntLit: token.INT, - syntax.RuneLit: token.CHAR, - syntax.FloatLit: token.FLOAT, - syntax.ImagLit: token.IMAG, - syntax.StringLit: token.STRING, -} - -func (p *noder) name(name *syntax.Name) *types.Sym { - return typecheck.Lookup(name.Value) -} - -func (p *noder) mkname(name *syntax.Name) ir.Node { - // TODO(mdempsky): Set line number? - return mkname(p.name(name)) -} - -func (p *noder) wrapname(n syntax.Node, x ir.Node) ir.Node { - // These nodes do not carry line numbers. - // Introduce a wrapper node to give them the correct line. - switch x.Op() { - case ir.OTYPE, ir.OLITERAL: - if x.Sym() == nil { - break - } - fallthrough - case ir.ONAME, ir.ONONAME, ir.OPACK: - p := ir.NewParenExpr(p.pos(n), x) - p.SetImplicit(true) - return p - } - return x -} - -func (p *noder) pos(n syntax.Node) src.XPos { - // TODO(gri): orig.Pos() should always be known - fix package syntax - xpos := base.Pos - if pos := n.Pos(); pos.IsKnown() { - xpos = p.makeXPos(pos) - } - return xpos -} - -func (p *noder) setlineno(n syntax.Node) { - if n != nil { - base.Pos = p.pos(n) - } -} - -// error is called concurrently if files are parsed concurrently. -func (p *noder) error(err error) { - p.err <- err.(syntax.Error) -} - -// pragmas that are allowed in the std lib, but don't have -// a syntax.Pragma value (see lex.go) associated with them. -var allowedStdPragmas = map[string]bool{ - "go:cgo_export_static": true, - "go:cgo_export_dynamic": true, - "go:cgo_import_static": true, - "go:cgo_import_dynamic": true, - "go:cgo_ldflag": true, - "go:cgo_dynamic_linker": true, - "go:embed": true, - "go:generate": true, -} - -// *Pragma is the value stored in a syntax.Pragma during parsing. -type Pragma struct { - Flag ir.PragmaFlag // collected bits - Pos []PragmaPos // position of each individual flag - Embeds []PragmaEmbed -} - -type PragmaPos struct { - Flag ir.PragmaFlag - Pos syntax.Pos -} - -type PragmaEmbed struct { - Pos syntax.Pos - Patterns []string -} - -func (p *noder) checkUnused(pragma *Pragma) { - for _, pos := range pragma.Pos { - if pos.Flag&pragma.Flag != 0 { - p.errorAt(pos.Pos, "misplaced compiler directive") - } - } - if len(pragma.Embeds) > 0 { - for _, e := range pragma.Embeds { - p.errorAt(e.Pos, "misplaced go:embed directive") - } - } -} - -func (p *noder) checkUnusedDuringParse(pragma *Pragma) { - for _, pos := range pragma.Pos { - if pos.Flag&pragma.Flag != 0 { - p.error(syntax.Error{Pos: pos.Pos, Msg: "misplaced compiler directive"}) - } - } - if len(pragma.Embeds) > 0 { - for _, e := range pragma.Embeds { - p.error(syntax.Error{Pos: e.Pos, Msg: "misplaced go:embed directive"}) - } - } -} - -// pragma is called concurrently if files are parsed concurrently. -func (p *noder) pragma(pos syntax.Pos, blankLine bool, text string, old syntax.Pragma) syntax.Pragma { - pragma, _ := old.(*Pragma) - if pragma == nil { - pragma = new(Pragma) - } - - if text == "" { - // unused pragma; only called with old != nil. - p.checkUnusedDuringParse(pragma) - return nil - } - - if strings.HasPrefix(text, "line ") { - // line directives are handled by syntax package - panic("unreachable") - } - - if !blankLine { - // directive must be on line by itself - p.error(syntax.Error{Pos: pos, Msg: "misplaced compiler directive"}) - return pragma - } - - switch { - case strings.HasPrefix(text, "go:linkname "): - f := strings.Fields(text) - if !(2 <= len(f) && len(f) <= 3) { - p.error(syntax.Error{Pos: pos, Msg: "usage: //go:linkname localname [linkname]"}) - break - } - // The second argument is optional. If omitted, we use - // the default object symbol name for this and - // linkname only serves to mark this symbol as - // something that may be referenced via the object - // symbol name from another package. - var target string - if len(f) == 3 { - target = f[2] - } else if base.Ctxt.Pkgpath != "" { - // Use the default object symbol name if the - // user didn't provide one. - target = objabi.PathToPrefix(base.Ctxt.Pkgpath) + "." + f[1] - } else { - p.error(syntax.Error{Pos: pos, Msg: "//go:linkname requires linkname argument or -p compiler flag"}) - break - } - p.linknames = append(p.linknames, linkname{pos, f[1], target}) - - case text == "go:embed", strings.HasPrefix(text, "go:embed "): - args, err := parseGoEmbed(text[len("go:embed"):]) - if err != nil { - p.error(syntax.Error{Pos: pos, Msg: err.Error()}) - } - if len(args) == 0 { - p.error(syntax.Error{Pos: pos, Msg: "usage: //go:embed pattern..."}) - break - } - pragma.Embeds = append(pragma.Embeds, PragmaEmbed{pos, args}) - - case strings.HasPrefix(text, "go:cgo_import_dynamic "): - // This is permitted for general use because Solaris - // code relies on it in golang.org/x/sys/unix and others. - fields := pragmaFields(text) - if len(fields) >= 4 { - lib := strings.Trim(fields[3], `"`) - if lib != "" && !safeArg(lib) && !isCgoGeneratedFile(pos) { - p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("invalid library name %q in cgo_import_dynamic directive", lib)}) - } - p.pragcgo(pos, text) - pragma.Flag |= pragmaFlag("go:cgo_import_dynamic") - break - } - fallthrough - case strings.HasPrefix(text, "go:cgo_"): - // For security, we disallow //go:cgo_* directives other - // than cgo_import_dynamic outside cgo-generated files. - // Exception: they are allowed in the standard library, for runtime and syscall. - if !isCgoGeneratedFile(pos) && !base.Flag.Std { - p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("//%s only allowed in cgo-generated code", text)}) - } - p.pragcgo(pos, text) - fallthrough // because of //go:cgo_unsafe_args - default: - verb := text - if i := strings.Index(text, " "); i >= 0 { - verb = verb[:i] - } - flag := pragmaFlag(verb) - const runtimePragmas = ir.Systemstack | ir.Nowritebarrier | ir.Nowritebarrierrec | ir.Yeswritebarrierrec - if !base.Flag.CompilingRuntime && flag&runtimePragmas != 0 { - p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("//%s only allowed in runtime", verb)}) - } - if flag == 0 && !allowedStdPragmas[verb] && base.Flag.Std { - p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("//%s is not allowed in the standard library", verb)}) - } - pragma.Flag |= flag - pragma.Pos = append(pragma.Pos, PragmaPos{flag, pos}) - } - - return pragma -} - -// isCgoGeneratedFile reports whether pos is in a file -// generated by cgo, which is to say a file with name -// beginning with "_cgo_". Such files are allowed to -// contain cgo directives, and for security reasons -// (primarily misuse of linker flags), other files are not. -// See golang.org/issue/23672. -func isCgoGeneratedFile(pos syntax.Pos) bool { - return strings.HasPrefix(filepath.Base(filepath.Clean(fileh(pos.Base().Filename()))), "_cgo_") -} - -// safeArg reports whether arg is a "safe" command-line argument, -// meaning that when it appears in a command-line, it probably -// doesn't have some special meaning other than its own name. -// This is copied from SafeArg in cmd/go/internal/load/pkg.go. -func safeArg(name string) bool { - if name == "" { - return false - } - c := name[0] - return '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || c == '.' || c == '_' || c == '/' || c >= utf8.RuneSelf -} - -func mkname(sym *types.Sym) ir.Node { - n := oldname(sym) - if n.Name() != nil && n.Name().PkgName != nil { - n.Name().PkgName.Used = true - } - return n -} - -// parseGoEmbed parses the text following "//go:embed" to extract the glob patterns. -// It accepts unquoted space-separated patterns as well as double-quoted and back-quoted Go strings. -// go/build/read.go also processes these strings and contains similar logic. -func parseGoEmbed(args string) ([]string, error) { - var list []string - for args = strings.TrimSpace(args); args != ""; args = strings.TrimSpace(args) { - var path string - Switch: - switch args[0] { - default: - i := len(args) - for j, c := range args { - if unicode.IsSpace(c) { - i = j - break - } - } - path = args[:i] - args = args[i:] - - case '`': - i := strings.Index(args[1:], "`") - if i < 0 { - return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args) - } - path = args[1 : 1+i] - args = args[1+i+1:] - - case '"': - i := 1 - for ; i < len(args); i++ { - if args[i] == '\\' { - i++ - continue - } - if args[i] == '"' { - q, err := strconv.Unquote(args[:i+1]) - if err != nil { - return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args[:i+1]) - } - path = q - args = args[i+1:] - break Switch - } - } - if i >= len(args) { - return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args) - } - } - - if args != "" { - r, _ := utf8.DecodeRuneInString(args) - if !unicode.IsSpace(r) { - return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args) - } - } - list = append(list, path) - } - return list, nil -} diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go index 1d0a0f7a04..0dbe1da8d4 100644 --- a/src/cmd/compile/internal/gc/obj.go +++ b/src/cmd/compile/internal/gc/obj.go @@ -10,6 +10,7 @@ import ( "cmd/compile/internal/objw" "cmd/compile/internal/typecheck" "cmd/compile/internal/types" + "cmd/internal/archive" "cmd/internal/bio" "cmd/internal/obj" "cmd/internal/objabi" @@ -25,13 +26,6 @@ import ( "strconv" ) -// architecture-independent object file output -const ArhdrSize = 60 - -func formathdr(arhdr []byte, name string, size int64) { - copy(arhdr[:], fmt.Sprintf("%-16s%-12d%-6d%-6d%-8o%-10d`\n", name, 0, 0, 0, 0644, size)) -} - // These modes say which kind of object file to generate. // The default use of the toolchain is to set both bits, // generating a combined compiler+linker object, one that @@ -93,7 +87,7 @@ func printObjHeader(bout *bio.Writer) { } func startArchiveEntry(bout *bio.Writer) int64 { - var arhdr [ArhdrSize]byte + var arhdr [archive.HeaderSize]byte bout.Write(arhdr[:]) return bout.Offset() } @@ -104,10 +98,10 @@ func finishArchiveEntry(bout *bio.Writer, start int64, name string) { if size&1 != 0 { bout.WriteByte(0) } - bout.MustSeek(start-ArhdrSize, 0) + bout.MustSeek(start-archive.HeaderSize, 0) - var arhdr [ArhdrSize]byte - formathdr(arhdr[:], name, size) + var arhdr [archive.HeaderSize]byte + archive.FormatHeader(arhdr[:], name, size) bout.Write(arhdr[:]) bout.Flush() bout.MustSeek(start+size+(size&1), 0) diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go index cba9bdc253..362c5162b6 100644 --- a/src/cmd/compile/internal/gc/subr.go +++ b/src/cmd/compile/internal/gc/subr.go @@ -13,10 +13,7 @@ import ( "cmd/compile/internal/types" "cmd/internal/src" "fmt" - "strings" "sync" - "unicode" - "unicode/utf8" ) // largeStack is info about a function whose stack frame is too large (rare). @@ -32,55 +29,6 @@ var ( largeStackFrames []largeStack ) -// dotImports tracks all PkgNames that have been dot-imported. -var dotImports []*ir.PkgName - -// find all the exported symbols in package referenced by PkgName, -// and make them available in the current package -func importDot(pack *ir.PkgName) { - if typecheck.DotImportRefs == nil { - typecheck.DotImportRefs = make(map[*ir.Ident]*ir.PkgName) - } - - opkg := pack.Pkg - for _, s := range opkg.Syms { - if s.Def == nil { - if _, ok := typecheck.DeclImporter[s]; !ok { - continue - } - } - if !types.IsExported(s.Name) || strings.ContainsRune(s.Name, 0xb7) { // 0xb7 = center dot - continue - } - s1 := typecheck.Lookup(s.Name) - if s1.Def != nil { - pkgerror := fmt.Sprintf("during import %q", opkg.Path) - typecheck.Redeclared(base.Pos, s1, pkgerror) - continue - } - - id := ir.NewIdent(src.NoXPos, s) - typecheck.DotImportRefs[id] = pack - s1.Def = id - s1.Block = 1 - } - - dotImports = append(dotImports, pack) -} - -// checkDotImports reports errors for any unused dot imports. -func checkDotImports() { - for _, pack := range dotImports { - if !pack.Used { - base.ErrorfAt(pack.Pos(), "imported and not used: %q", pack.Pkg.Path) - } - } - - // No longer needed; release memory. - dotImports = nil - typecheck.DotImportRefs = nil -} - // backingArrayPtrLen extracts the pointer and length from a slice or string. // This constructs two nodes referring to n, so n must be a cheapexpr. func backingArrayPtrLen(n ir.Node) (ptr, length ir.Node) { @@ -513,59 +461,6 @@ func ngotype(n ir.Node) *types.Sym { return nil } -// The linker uses the magic symbol prefixes "go." and "type." -// Avoid potential confusion between import paths and symbols -// by rejecting these reserved imports for now. Also, people -// "can do weird things in GOPATH and we'd prefer they didn't -// do _that_ weird thing" (per rsc). See also #4257. -var reservedimports = []string{ - "go", - "type", -} - -func isbadimport(path string, allowSpace bool) bool { - if strings.Contains(path, "\x00") { - base.Errorf("import path contains NUL") - return true - } - - for _, ri := range reservedimports { - if path == ri { - base.Errorf("import path %q is reserved and cannot be used", path) - return true - } - } - - for _, r := range path { - if r == utf8.RuneError { - base.Errorf("import path contains invalid UTF-8 sequence: %q", path) - return true - } - - if r < 0x20 || r == 0x7f { - base.Errorf("import path contains control character: %q", path) - return true - } - - if r == '\\' { - base.Errorf("import path contains backslash; use slash: %q", path) - return true - } - - if !allowSpace && unicode.IsSpace(r) { - base.Errorf("import path contains space character: %q", path) - return true - } - - if strings.ContainsRune("!\"#$%&'()*,:;<=>?[]^`{|}", r) { - base.Errorf("import path contains invalid character '%c': %q", r, path) - return true - } - } - - return false -} - // itabType loads the _type field from a runtime.itab struct. func itabType(itab ir.Node) ir.Node { typ := ir.NewSelectorExpr(base.Pos, ir.ODOTPTR, itab, nil) diff --git a/src/cmd/compile/internal/noder/import.go b/src/cmd/compile/internal/noder/import.go new file mode 100644 index 0000000000..a39be9864b --- /dev/null +++ b/src/cmd/compile/internal/noder/import.go @@ -0,0 +1,493 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:generate go run mkbuiltin.go + +package noder + +import ( + "fmt" + "go/constant" + "os" + "path" + "runtime" + "sort" + "strings" + "unicode" + "unicode/utf8" + + "cmd/compile/internal/base" + "cmd/compile/internal/ir" + "cmd/compile/internal/typecheck" + "cmd/compile/internal/types" + "cmd/internal/archive" + "cmd/internal/bio" + "cmd/internal/goobj" + "cmd/internal/objabi" + "cmd/internal/src" +) + +func isDriveLetter(b byte) bool { + return 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z' +} + +// is this path a local name? begins with ./ or ../ or / +func islocalname(name string) bool { + return strings.HasPrefix(name, "/") || + runtime.GOOS == "windows" && len(name) >= 3 && isDriveLetter(name[0]) && name[1] == ':' && name[2] == '/' || + strings.HasPrefix(name, "./") || name == "." || + strings.HasPrefix(name, "../") || name == ".." +} + +func findpkg(name string) (file string, ok bool) { + if islocalname(name) { + if base.Flag.NoLocalImports { + return "", false + } + + if base.Flag.Cfg.PackageFile != nil { + file, ok = base.Flag.Cfg.PackageFile[name] + return file, ok + } + + // try .a before .6. important for building libraries: + // if there is an array.6 in the array.a library, + // want to find all of array.a, not just array.6. + file = fmt.Sprintf("%s.a", name) + if _, err := os.Stat(file); err == nil { + return file, true + } + file = fmt.Sprintf("%s.o", name) + if _, err := os.Stat(file); err == nil { + return file, true + } + return "", false + } + + // local imports should be canonicalized already. + // don't want to see "encoding/../encoding/base64" + // as different from "encoding/base64". + if q := path.Clean(name); q != name { + base.Errorf("non-canonical import path %q (should be %q)", name, q) + return "", false + } + + if base.Flag.Cfg.PackageFile != nil { + file, ok = base.Flag.Cfg.PackageFile[name] + return file, ok + } + + for _, dir := range base.Flag.Cfg.ImportDirs { + file = fmt.Sprintf("%s/%s.a", dir, name) + if _, err := os.Stat(file); err == nil { + return file, true + } + file = fmt.Sprintf("%s/%s.o", dir, name) + if _, err := os.Stat(file); err == nil { + return file, true + } + } + + if objabi.GOROOT != "" { + suffix := "" + suffixsep := "" + if base.Flag.InstallSuffix != "" { + suffixsep = "_" + suffix = base.Flag.InstallSuffix + } else if base.Flag.Race { + suffixsep = "_" + suffix = "race" + } else if base.Flag.MSan { + suffixsep = "_" + suffix = "msan" + } + + file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.a", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffixsep, suffix, name) + if _, err := os.Stat(file); err == nil { + return file, true + } + file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.o", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffixsep, suffix, name) + if _, err := os.Stat(file); err == nil { + return file, true + } + } + + return "", false +} + +// myheight tracks the local package's height based on packages +// imported so far. +var myheight int + +func importfile(f constant.Value) *types.Pkg { + if f.Kind() != constant.String { + base.Errorf("import path must be a string") + return nil + } + + path_ := constant.StringVal(f) + if len(path_) == 0 { + base.Errorf("import path is empty") + return nil + } + + if isbadimport(path_, false) { + return nil + } + + // The package name main is no longer reserved, + // 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 path_ == "main" { + base.Errorf("cannot import \"main\"") + base.ErrorExit() + } + + if base.Ctxt.Pkgpath != "" && path_ == base.Ctxt.Pkgpath { + base.Errorf("import %q while compiling that package (import cycle)", path_) + base.ErrorExit() + } + + if mapped, ok := base.Flag.Cfg.ImportMap[path_]; ok { + path_ = mapped + } + + if path_ == "unsafe" { + return ir.Pkgs.Unsafe + } + + if islocalname(path_) { + if path_[0] == '/' { + base.Errorf("import path cannot be absolute path") + return nil + } + + prefix := base.Ctxt.Pathname + if base.Flag.D != "" { + prefix = base.Flag.D + } + path_ = path.Join(prefix, path_) + + if isbadimport(path_, true) { + return nil + } + } + + file, found := findpkg(path_) + if !found { + base.Errorf("can't find import: %q", path_) + base.ErrorExit() + } + + importpkg := types.NewPkg(path_, "") + if importpkg.Imported { + return importpkg + } + + importpkg.Imported = true + + imp, err := bio.Open(file) + if err != nil { + base.Errorf("can't open import: %q: %v", path_, err) + base.ErrorExit() + } + defer imp.Close() + + // check object header + p, err := imp.ReadString('\n') + if err != nil { + base.Errorf("import %s: reading input: %v", file, err) + base.ErrorExit() + } + + if p == "!\n" { // package archive + // package export block should be first + sz := archive.ReadHeader(imp.Reader, "__.PKGDEF") + if sz <= 0 { + base.Errorf("import %s: not a package file", file) + base.ErrorExit() + } + p, err = imp.ReadString('\n') + if err != nil { + base.Errorf("import %s: reading input: %v", file, err) + base.ErrorExit() + } + } + + if !strings.HasPrefix(p, "go object ") { + base.Errorf("import %s: not a go object file: %s", file, p) + base.ErrorExit() + } + q := fmt.Sprintf("%s %s %s %s\n", objabi.GOOS, objabi.GOARCH, objabi.Version, objabi.Expstring()) + if p[10:] != q { + base.Errorf("import %s: object is [%s] expected [%s]", file, p[10:], q) + base.ErrorExit() + } + + // process header lines + for { + p, err = imp.ReadString('\n') + if err != nil { + base.Errorf("import %s: reading input: %v", file, err) + base.ErrorExit() + } + if p == "\n" { + break // header ends with blank line + } + } + + // Expect $$B\n to signal binary import format. + + // look for $$ + var c byte + for { + c, err = imp.ReadByte() + if err != nil { + break + } + if c == '$' { + c, err = imp.ReadByte() + if c == '$' || err != nil { + break + } + } + } + + // get character after $$ + if err == nil { + c, _ = imp.ReadByte() + } + + var fingerprint goobj.FingerprintType + switch c { + case '\n': + base.Errorf("cannot import %s: old export format no longer supported (recompile library)", path_) + return nil + + case 'B': + if base.Debug.Export != 0 { + fmt.Printf("importing %s (%s)\n", path_, file) + } + imp.ReadByte() // skip \n after $$B + + c, err = imp.ReadByte() + if err != nil { + base.Errorf("import %s: reading input: %v", file, err) + base.ErrorExit() + } + + // Indexed format is distinguished by an 'i' byte, + // whereas previous export formats started with 'c', 'd', or 'v'. + if c != 'i' { + base.Errorf("import %s: unexpected package format byte: %v", file, c) + base.ErrorExit() + } + fingerprint = typecheck.ReadImports(importpkg, imp) + + default: + base.Errorf("no import in %q", path_) + base.ErrorExit() + } + + // assume files move (get installed) so don't record the full path + if base.Flag.Cfg.PackageFile != nil { + // If using a packageFile map, assume path_ can be recorded directly. + base.Ctxt.AddImport(path_, fingerprint) + } else { + // For file "/Users/foo/go/pkg/darwin_amd64/math.a" record "math.a". + base.Ctxt.AddImport(file[len(file)-len(path_)-len(".a"):], fingerprint) + } + + if importpkg.Height >= myheight { + myheight = importpkg.Height + 1 + } + + return importpkg +} + +// The linker uses the magic symbol prefixes "go." and "type." +// Avoid potential confusion between import paths and symbols +// by rejecting these reserved imports for now. Also, people +// "can do weird things in GOPATH and we'd prefer they didn't +// do _that_ weird thing" (per rsc). See also #4257. +var reservedimports = []string{ + "go", + "type", +} + +func isbadimport(path string, allowSpace bool) bool { + if strings.Contains(path, "\x00") { + base.Errorf("import path contains NUL") + return true + } + + for _, ri := range reservedimports { + if path == ri { + base.Errorf("import path %q is reserved and cannot be used", path) + return true + } + } + + for _, r := range path { + if r == utf8.RuneError { + base.Errorf("import path contains invalid UTF-8 sequence: %q", path) + return true + } + + if r < 0x20 || r == 0x7f { + base.Errorf("import path contains control character: %q", path) + return true + } + + if r == '\\' { + base.Errorf("import path contains backslash; use slash: %q", path) + return true + } + + if !allowSpace && unicode.IsSpace(r) { + base.Errorf("import path contains space character: %q", path) + return true + } + + if strings.ContainsRune("!\"#$%&'()*,:;<=>?[]^`{|}", r) { + base.Errorf("import path contains invalid character '%c': %q", r, path) + return true + } + } + + return false +} + +func pkgnotused(lineno src.XPos, path string, name string) { + // If the package was imported with a name other than the final + // import path element, show it explicitly in the error message. + // Note that this handles both renamed imports and imports of + // packages containing unconventional package declarations. + // Note that this uses / always, even on Windows, because Go import + // paths always use forward slashes. + elem := path + if i := strings.LastIndex(elem, "/"); i >= 0 { + elem = elem[i+1:] + } + if name == "" || elem == name { + base.ErrorfAt(lineno, "imported and not used: %q", path) + } else { + base.ErrorfAt(lineno, "imported and not used: %q as %s", path, name) + } +} + +func mkpackage(pkgname string) { + if types.LocalPkg.Name == "" { + if pkgname == "_" { + base.Errorf("invalid package name _") + } + types.LocalPkg.Name = pkgname + } else { + if pkgname != types.LocalPkg.Name { + base.Errorf("package %s; expected %s", pkgname, types.LocalPkg.Name) + } + } +} + +func clearImports() { + type importedPkg struct { + pos src.XPos + path string + name string + } + var unused []importedPkg + + for _, s := range types.LocalPkg.Syms { + n := ir.AsNode(s.Def) + if n == nil { + continue + } + if n.Op() == ir.OPACK { + // throw away top-level package name left over + // from previous file. + // leave s->block set to cause redeclaration + // errors if a conflicting top-level name is + // introduced by a different file. + p := n.(*ir.PkgName) + if !p.Used && base.SyntaxErrors() == 0 { + unused = append(unused, importedPkg{p.Pos(), p.Pkg.Path, s.Name}) + } + s.Def = nil + continue + } + if types.IsDotAlias(s) { + // throw away top-level name left over + // from previous import . "x" + // We'll report errors after type checking in checkDotImports. + s.Def = nil + continue + } + } + + sort.Slice(unused, func(i, j int) bool { return unused[i].pos.Before(unused[j].pos) }) + for _, pkg := range unused { + pkgnotused(pkg.pos, pkg.path, pkg.name) + } +} + +// CheckDotImports reports errors for any unused dot imports. +func CheckDotImports() { + for _, pack := range dotImports { + if !pack.Used { + base.ErrorfAt(pack.Pos(), "imported and not used: %q", pack.Pkg.Path) + } + } + + // No longer needed; release memory. + dotImports = nil + typecheck.DotImportRefs = nil +} + +// dotImports tracks all PkgNames that have been dot-imported. +var dotImports []*ir.PkgName + +// find all the exported symbols in package referenced by PkgName, +// and make them available in the current package +func importDot(pack *ir.PkgName) { + if typecheck.DotImportRefs == nil { + typecheck.DotImportRefs = make(map[*ir.Ident]*ir.PkgName) + } + + opkg := pack.Pkg + for _, s := range opkg.Syms { + if s.Def == nil { + if _, ok := typecheck.DeclImporter[s]; !ok { + continue + } + } + if !types.IsExported(s.Name) || strings.ContainsRune(s.Name, 0xb7) { // 0xb7 = center dot + continue + } + s1 := typecheck.Lookup(s.Name) + if s1.Def != nil { + pkgerror := fmt.Sprintf("during import %q", opkg.Path) + typecheck.Redeclared(base.Pos, s1, pkgerror) + continue + } + + id := ir.NewIdent(src.NoXPos, s) + typecheck.DotImportRefs[id] = pack + s1.Def = id + s1.Block = 1 + } + + dotImports = append(dotImports, pack) +} + +// importName is like oldname, +// but it reports an error if sym is from another package and not exported. +func importName(sym *types.Sym) ir.Node { + n := oldname(sym) + if !types.IsExported(sym.Name) && sym.Pkg != types.LocalPkg { + n.SetDiag(true) + base.Errorf("cannot refer to unexported name %s.%s", sym.Pkg.Name, sym.Name) + } + return n +} diff --git a/src/cmd/compile/internal/noder/lex.go b/src/cmd/compile/internal/noder/lex.go new file mode 100644 index 0000000000..1095f3344a --- /dev/null +++ b/src/cmd/compile/internal/noder/lex.go @@ -0,0 +1,190 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package noder + +import ( + "fmt" + "strings" + + "cmd/compile/internal/ir" + "cmd/compile/internal/syntax" + "cmd/internal/objabi" +) + +func isSpace(c rune) bool { + return c == ' ' || c == '\t' || c == '\n' || c == '\r' +} + +func isQuoted(s string) bool { + return len(s) >= 2 && s[0] == '"' && s[len(s)-1] == '"' +} + +const ( + funcPragmas = ir.Nointerface | + ir.Noescape | + ir.Norace | + ir.Nosplit | + ir.Noinline | + ir.NoCheckPtr | + ir.CgoUnsafeArgs | + ir.UintptrEscapes | + ir.Systemstack | + ir.Nowritebarrier | + ir.Nowritebarrierrec | + ir.Yeswritebarrierrec + + typePragmas = ir.NotInHeap +) + +func pragmaFlag(verb string) ir.PragmaFlag { + switch verb { + case "go:build": + return ir.GoBuildPragma + case "go:nointerface": + if objabi.Fieldtrack_enabled != 0 { + return ir.Nointerface + } + case "go:noescape": + return ir.Noescape + case "go:norace": + return ir.Norace + case "go:nosplit": + return ir.Nosplit | ir.NoCheckPtr // implies NoCheckPtr (see #34972) + case "go:noinline": + return ir.Noinline + case "go:nocheckptr": + return ir.NoCheckPtr + case "go:systemstack": + return ir.Systemstack + case "go:nowritebarrier": + return ir.Nowritebarrier + case "go:nowritebarrierrec": + return ir.Nowritebarrierrec | ir.Nowritebarrier // implies Nowritebarrier + case "go:yeswritebarrierrec": + return ir.Yeswritebarrierrec + case "go:cgo_unsafe_args": + return ir.CgoUnsafeArgs | ir.NoCheckPtr // implies NoCheckPtr (see #34968) + case "go:uintptrescapes": + // For the next function declared in the file + // any uintptr arguments may be pointer values + // converted to uintptr. This directive + // ensures that the referenced allocated + // object, if any, is retained and not moved + // until the call completes, even though from + // the types alone it would appear that the + // object is no longer needed during the + // call. The conversion to uintptr must appear + // in the argument list. + // Used in syscall/dll_windows.go. + return ir.UintptrEscapes + case "go:notinheap": + return ir.NotInHeap + } + return 0 +} + +// pragcgo is called concurrently if files are parsed concurrently. +func (p *noder) pragcgo(pos syntax.Pos, text string) { + f := pragmaFields(text) + + verb := strings.TrimPrefix(f[0], "go:") + f[0] = verb + + switch verb { + case "cgo_export_static", "cgo_export_dynamic": + switch { + case len(f) == 2 && !isQuoted(f[1]): + case len(f) == 3 && !isQuoted(f[1]) && !isQuoted(f[2]): + default: + p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf(`usage: //go:%s local [remote]`, verb)}) + return + } + case "cgo_import_dynamic": + switch { + case len(f) == 2 && !isQuoted(f[1]): + case len(f) == 3 && !isQuoted(f[1]) && !isQuoted(f[2]): + case len(f) == 4 && !isQuoted(f[1]) && !isQuoted(f[2]) && isQuoted(f[3]): + f[3] = strings.Trim(f[3], `"`) + if objabi.GOOS == "aix" && f[3] != "" { + // On Aix, library pattern must be "lib.a/object.o" + // or "lib.a/libname.so.X" + n := strings.Split(f[3], "/") + if len(n) != 2 || !strings.HasSuffix(n[0], ".a") || (!strings.HasSuffix(n[1], ".o") && !strings.Contains(n[1], ".so.")) { + p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_import_dynamic local [remote ["lib.a/object.o"]]`}) + return + } + } + default: + p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_import_dynamic local [remote ["library"]]`}) + return + } + case "cgo_import_static": + switch { + case len(f) == 2 && !isQuoted(f[1]): + default: + p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_import_static local`}) + return + } + case "cgo_dynamic_linker": + switch { + case len(f) == 2 && isQuoted(f[1]): + f[1] = strings.Trim(f[1], `"`) + default: + p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_dynamic_linker "path"`}) + return + } + case "cgo_ldflag": + switch { + case len(f) == 2 && isQuoted(f[1]): + f[1] = strings.Trim(f[1], `"`) + default: + p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_ldflag "arg"`}) + return + } + default: + return + } + p.pragcgobuf = append(p.pragcgobuf, f) +} + +// pragmaFields is similar to strings.FieldsFunc(s, isSpace) +// but does not split when inside double quoted regions and always +// splits before the start and after the end of a double quoted region. +// pragmaFields does not recognize escaped quotes. If a quote in s is not +// closed the part after the opening quote will not be returned as a field. +func pragmaFields(s string) []string { + var a []string + inQuote := false + fieldStart := -1 // Set to -1 when looking for start of field. + for i, c := range s { + switch { + case c == '"': + if inQuote { + inQuote = false + a = append(a, s[fieldStart:i+1]) + fieldStart = -1 + } else { + inQuote = true + if fieldStart >= 0 { + a = append(a, s[fieldStart:i]) + } + fieldStart = i + } + case !inQuote && isSpace(c): + if fieldStart >= 0 { + a = append(a, s[fieldStart:i]) + fieldStart = -1 + } + default: + if fieldStart == -1 { + fieldStart = i + } + } + } + if !inQuote && fieldStart >= 0 { // Last field might end at the end of the string. + a = append(a, s[fieldStart:]) + } + return a +} diff --git a/src/cmd/compile/internal/noder/lex_test.go b/src/cmd/compile/internal/noder/lex_test.go new file mode 100644 index 0000000000..85a3f06759 --- /dev/null +++ b/src/cmd/compile/internal/noder/lex_test.go @@ -0,0 +1,122 @@ +// Copyright 2016 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 noder + +import ( + "reflect" + "runtime" + "testing" + + "cmd/compile/internal/syntax" +) + +func eq(a, b []string) bool { + if len(a) != len(b) { + return false + } + for i := 0; i < len(a); i++ { + if a[i] != b[i] { + return false + } + } + return true +} + +func TestPragmaFields(t *testing.T) { + var tests = []struct { + in string + want []string + }{ + {"", []string{}}, + {" \t ", []string{}}, + {`""""`, []string{`""`, `""`}}, + {" a'b'c ", []string{"a'b'c"}}, + {"1 2 3 4", []string{"1", "2", "3", "4"}}, + {"\n☺\t☹\n", []string{"☺", "☹"}}, + {`"1 2 " 3 " 4 5"`, []string{`"1 2 "`, `3`, `" 4 5"`}}, + {`"1""2 3""4"`, []string{`"1"`, `"2 3"`, `"4"`}}, + {`12"34"`, []string{`12`, `"34"`}}, + {`12"34 `, []string{`12`}}, + } + + for _, tt := range tests { + got := pragmaFields(tt.in) + if !eq(got, tt.want) { + t.Errorf("pragmaFields(%q) = %v; want %v", tt.in, got, tt.want) + continue + } + } +} + +func TestPragcgo(t *testing.T) { + type testStruct struct { + in string + want []string + } + + var tests = []testStruct{ + {`go:cgo_export_dynamic local`, []string{`cgo_export_dynamic`, `local`}}, + {`go:cgo_export_dynamic local remote`, []string{`cgo_export_dynamic`, `local`, `remote`}}, + {`go:cgo_export_dynamic local' remote'`, []string{`cgo_export_dynamic`, `local'`, `remote'`}}, + {`go:cgo_export_static local`, []string{`cgo_export_static`, `local`}}, + {`go:cgo_export_static local remote`, []string{`cgo_export_static`, `local`, `remote`}}, + {`go:cgo_export_static local' remote'`, []string{`cgo_export_static`, `local'`, `remote'`}}, + {`go:cgo_import_dynamic local`, []string{`cgo_import_dynamic`, `local`}}, + {`go:cgo_import_dynamic local remote`, []string{`cgo_import_dynamic`, `local`, `remote`}}, + {`go:cgo_import_static local`, []string{`cgo_import_static`, `local`}}, + {`go:cgo_import_static local'`, []string{`cgo_import_static`, `local'`}}, + {`go:cgo_dynamic_linker "/path/"`, []string{`cgo_dynamic_linker`, `/path/`}}, + {`go:cgo_dynamic_linker "/p ath/"`, []string{`cgo_dynamic_linker`, `/p ath/`}}, + {`go:cgo_ldflag "arg"`, []string{`cgo_ldflag`, `arg`}}, + {`go:cgo_ldflag "a rg"`, []string{`cgo_ldflag`, `a rg`}}, + } + + if runtime.GOOS != "aix" { + tests = append(tests, []testStruct{ + {`go:cgo_import_dynamic local remote "library"`, []string{`cgo_import_dynamic`, `local`, `remote`, `library`}}, + {`go:cgo_import_dynamic local' remote' "lib rary"`, []string{`cgo_import_dynamic`, `local'`, `remote'`, `lib rary`}}, + }...) + } else { + // cgo_import_dynamic with a library is slightly different on AIX + // as the library field must follow the pattern [libc.a/object.o]. + tests = append(tests, []testStruct{ + {`go:cgo_import_dynamic local remote "lib.a/obj.o"`, []string{`cgo_import_dynamic`, `local`, `remote`, `lib.a/obj.o`}}, + // This test must fail. + {`go:cgo_import_dynamic local' remote' "library"`, []string{`: usage: //go:cgo_import_dynamic local [remote ["lib.a/object.o"]]`}}, + }...) + + } + + var p noder + var nopos syntax.Pos + for _, tt := range tests { + + p.err = make(chan syntax.Error) + gotch := make(chan [][]string, 1) + go func() { + p.pragcgobuf = nil + p.pragcgo(nopos, tt.in) + if p.pragcgobuf != nil { + gotch <- p.pragcgobuf + } + }() + + select { + case e := <-p.err: + want := tt.want[0] + if e.Error() != want { + t.Errorf("pragcgo(%q) = %q; want %q", tt.in, e, want) + continue + } + case got := <-gotch: + want := [][]string{tt.want} + if !reflect.DeepEqual(got, want) { + t.Errorf("pragcgo(%q) = %q; want %q", tt.in, got, want) + continue + } + } + + } +} diff --git a/src/cmd/compile/internal/noder/noder.go b/src/cmd/compile/internal/noder/noder.go new file mode 100644 index 0000000000..a684673c8f --- /dev/null +++ b/src/cmd/compile/internal/noder/noder.go @@ -0,0 +1,1938 @@ +// Copyright 2016 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 noder + +import ( + "fmt" + "go/constant" + "go/token" + "os" + "path/filepath" + "runtime" + "strconv" + "strings" + "unicode" + "unicode/utf8" + + "cmd/compile/internal/base" + "cmd/compile/internal/ir" + "cmd/compile/internal/syntax" + "cmd/compile/internal/typecheck" + "cmd/compile/internal/types" + "cmd/internal/objabi" + "cmd/internal/src" +) + +// ParseFiles concurrently parses files into *syntax.File structures. +// Each declaration in every *syntax.File is converted to a syntax tree +// and its root represented by *Node is appended to Target.Decls. +// Returns the total count of parsed lines. +func ParseFiles(filenames []string) uint { + noders := make([]*noder, 0, len(filenames)) + // Limit the number of simultaneously open files. + sem := make(chan struct{}, runtime.GOMAXPROCS(0)+10) + + for _, filename := range filenames { + p := &noder{ + basemap: make(map[*syntax.PosBase]*src.PosBase), + err: make(chan syntax.Error), + trackScopes: base.Flag.Dwarf, + } + noders = append(noders, p) + + go func(filename string) { + sem <- struct{}{} + defer func() { <-sem }() + defer close(p.err) + base := syntax.NewFileBase(filename) + + f, err := os.Open(filename) + if err != nil { + p.error(syntax.Error{Msg: err.Error()}) + return + } + defer f.Close() + + p.file, _ = syntax.Parse(base, f, p.error, p.pragma, syntax.CheckBranches) // errors are tracked via p.error + }(filename) + } + + var lines uint + for _, p := range noders { + for e := range p.err { + p.errorAt(e.Pos, "%s", e.Msg) + } + + p.node() + lines += p.file.Lines + p.file = nil // release memory + + if base.SyntaxErrors() != 0 { + base.ErrorExit() + } + // Always run testdclstack here, even when debug_dclstack is not set, as a sanity measure. + types.CheckDclstack() + } + + for _, p := range noders { + p.processPragmas() + } + + types.LocalPkg.Height = myheight + + return lines +} + +// makeSrcPosBase translates from a *syntax.PosBase to a *src.PosBase. +func (p *noder) makeSrcPosBase(b0 *syntax.PosBase) *src.PosBase { + // fast path: most likely PosBase hasn't changed + if p.basecache.last == b0 { + return p.basecache.base + } + + b1, ok := p.basemap[b0] + if !ok { + fn := b0.Filename() + if b0.IsFileBase() { + b1 = src.NewFileBase(fn, absFilename(fn)) + } else { + // line directive base + p0 := b0.Pos() + p0b := p0.Base() + if p0b == b0 { + panic("infinite recursion in makeSrcPosBase") + } + p1 := src.MakePos(p.makeSrcPosBase(p0b), p0.Line(), p0.Col()) + b1 = src.NewLinePragmaBase(p1, fn, fileh(fn), b0.Line(), b0.Col()) + } + p.basemap[b0] = b1 + } + + // update cache + p.basecache.last = b0 + p.basecache.base = b1 + + return b1 +} + +func (p *noder) makeXPos(pos syntax.Pos) (_ src.XPos) { + return base.Ctxt.PosTable.XPos(src.MakePos(p.makeSrcPosBase(pos.Base()), pos.Line(), pos.Col())) +} + +func (p *noder) errorAt(pos syntax.Pos, format string, args ...interface{}) { + base.ErrorfAt(p.makeXPos(pos), format, args...) +} + +// TODO(gri) Can we eliminate fileh in favor of absFilename? +func fileh(name string) string { + return objabi.AbsFile("", name, base.Flag.TrimPath) +} + +func absFilename(name string) string { + return objabi.AbsFile(base.Ctxt.Pathname, name, base.Flag.TrimPath) +} + +// noder transforms package syntax's AST into a Node tree. +type noder struct { + basemap map[*syntax.PosBase]*src.PosBase + basecache struct { + last *syntax.PosBase + base *src.PosBase + } + + file *syntax.File + linknames []linkname + pragcgobuf [][]string + err chan syntax.Error + scope ir.ScopeID + importedUnsafe bool + importedEmbed bool + + // scopeVars is a stack tracking the number of variables declared in the + // current function at the moment each open scope was opened. + trackScopes bool + scopeVars []int + + lastCloseScopePos syntax.Pos +} + +func (p *noder) funcBody(fn *ir.Func, block *syntax.BlockStmt) { + oldScope := p.scope + p.scope = 0 + typecheck.StartFuncBody(fn) + + if block != nil { + body := p.stmts(block.List) + if body == nil { + body = []ir.Node{ir.NewBlockStmt(base.Pos, nil)} + } + fn.Body.Set(body) + + base.Pos = p.makeXPos(block.Rbrace) + fn.Endlineno = base.Pos + } + + typecheck.FinishFuncBody() + p.scope = oldScope +} + +func (p *noder) openScope(pos syntax.Pos) { + types.Markdcl() + + if p.trackScopes { + ir.CurFunc.Parents = append(ir.CurFunc.Parents, p.scope) + p.scopeVars = append(p.scopeVars, len(ir.CurFunc.Dcl)) + p.scope = ir.ScopeID(len(ir.CurFunc.Parents)) + + p.markScope(pos) + } +} + +func (p *noder) closeScope(pos syntax.Pos) { + p.lastCloseScopePos = pos + types.Popdcl() + + if p.trackScopes { + scopeVars := p.scopeVars[len(p.scopeVars)-1] + p.scopeVars = p.scopeVars[:len(p.scopeVars)-1] + if scopeVars == len(ir.CurFunc.Dcl) { + // no variables were declared in this scope, so we can retract it. + + if int(p.scope) != len(ir.CurFunc.Parents) { + base.Fatalf("scope tracking inconsistency, no variables declared but scopes were not retracted") + } + + p.scope = ir.CurFunc.Parents[p.scope-1] + ir.CurFunc.Parents = ir.CurFunc.Parents[:len(ir.CurFunc.Parents)-1] + + nmarks := len(ir.CurFunc.Marks) + ir.CurFunc.Marks[nmarks-1].Scope = p.scope + prevScope := ir.ScopeID(0) + if nmarks >= 2 { + prevScope = ir.CurFunc.Marks[nmarks-2].Scope + } + if ir.CurFunc.Marks[nmarks-1].Scope == prevScope { + ir.CurFunc.Marks = ir.CurFunc.Marks[:nmarks-1] + } + return + } + + p.scope = ir.CurFunc.Parents[p.scope-1] + + p.markScope(pos) + } +} + +func (p *noder) markScope(pos syntax.Pos) { + xpos := p.makeXPos(pos) + if i := len(ir.CurFunc.Marks); i > 0 && ir.CurFunc.Marks[i-1].Pos == xpos { + ir.CurFunc.Marks[i-1].Scope = p.scope + } else { + ir.CurFunc.Marks = append(ir.CurFunc.Marks, ir.Mark{Pos: xpos, Scope: p.scope}) + } +} + +// closeAnotherScope is like closeScope, but it reuses the same mark +// position as the last closeScope call. This is useful for "for" and +// "if" statements, as their implicit blocks always end at the same +// position as an explicit block. +func (p *noder) closeAnotherScope() { + p.closeScope(p.lastCloseScopePos) +} + +// linkname records a //go:linkname directive. +type linkname struct { + pos syntax.Pos + local string + remote string +} + +func (p *noder) node() { + types.Block = 1 + p.importedUnsafe = false + p.importedEmbed = false + + p.setlineno(p.file.PkgName) + mkpackage(p.file.PkgName.Value) + + if pragma, ok := p.file.Pragma.(*pragmas); ok { + pragma.Flag &^= ir.GoBuildPragma + p.checkUnused(pragma) + } + + typecheck.Target.Decls = append(typecheck.Target.Decls, p.decls(p.file.DeclList)...) + + base.Pos = src.NoXPos + clearImports() +} + +func (p *noder) processPragmas() { + for _, l := range p.linknames { + if !p.importedUnsafe { + p.errorAt(l.pos, "//go:linkname only allowed in Go files that import \"unsafe\"") + continue + } + n := ir.AsNode(typecheck.Lookup(l.local).Def) + if n == nil || n.Op() != ir.ONAME { + // TODO(mdempsky): Change to p.errorAt before Go 1.17 release. + // base.WarnfAt(p.makeXPos(l.pos), "//go:linkname must refer to declared function or variable (will be an error in Go 1.17)") + continue + } + if n.Sym().Linkname != "" { + p.errorAt(l.pos, "duplicate //go:linkname for %s", l.local) + continue + } + n.Sym().Linkname = l.remote + } + typecheck.Target.CgoPragmas = append(typecheck.Target.CgoPragmas, p.pragcgobuf...) +} + +func (p *noder) decls(decls []syntax.Decl) (l []ir.Node) { + var cs constState + + for _, decl := range decls { + p.setlineno(decl) + switch decl := decl.(type) { + case *syntax.ImportDecl: + p.importDecl(decl) + + case *syntax.VarDecl: + l = append(l, p.varDecl(decl)...) + + case *syntax.ConstDecl: + l = append(l, p.constDecl(decl, &cs)...) + + case *syntax.TypeDecl: + l = append(l, p.typeDecl(decl)) + + case *syntax.FuncDecl: + l = append(l, p.funcDecl(decl)) + + default: + panic("unhandled Decl") + } + } + + return +} + +func (p *noder) importDecl(imp *syntax.ImportDecl) { + if imp.Path.Bad { + return // avoid follow-on errors if there was a syntax error + } + + if pragma, ok := imp.Pragma.(*pragmas); ok { + p.checkUnused(pragma) + } + + ipkg := importfile(p.basicLit(imp.Path)) + if ipkg == nil { + if base.Errors() == 0 { + base.Fatalf("phase error in import") + } + return + } + + if ipkg == ir.Pkgs.Unsafe { + p.importedUnsafe = true + } + if ipkg.Path == "embed" { + p.importedEmbed = true + } + + if !ipkg.Direct { + typecheck.Target.Imports = append(typecheck.Target.Imports, ipkg) + } + ipkg.Direct = true + + var my *types.Sym + if imp.LocalPkgName != nil { + my = p.name(imp.LocalPkgName) + } else { + my = typecheck.Lookup(ipkg.Name) + } + + pack := ir.NewPkgName(p.pos(imp), my, ipkg) + + switch my.Name { + case ".": + importDot(pack) + return + case "init": + base.ErrorfAt(pack.Pos(), "cannot import package as init - init must be a func") + return + case "_": + return + } + if my.Def != nil { + typecheck.Redeclared(pack.Pos(), my, "as imported package name") + } + my.Def = pack + my.Lastlineno = pack.Pos() + my.Block = 1 // at top level +} + +func (p *noder) varDecl(decl *syntax.VarDecl) []ir.Node { + names := p.declNames(ir.ONAME, decl.NameList) + typ := p.typeExprOrNil(decl.Type) + + var exprs []ir.Node + if decl.Values != nil { + exprs = p.exprList(decl.Values) + } + + if pragma, ok := decl.Pragma.(*pragmas); ok { + if len(pragma.Embeds) > 0 { + if !p.importedEmbed { + // This check can't be done when building the list pragma.Embeds + // because that list is created before the noder starts walking over the file, + // so at that point it hasn't seen the imports. + // We're left to check now, just before applying the //go:embed lines. + for _, e := range pragma.Embeds { + p.errorAt(e.Pos, "//go:embed only allowed in Go files that import \"embed\"") + } + } else { + exprs = varEmbed(p, names, typ, exprs, pragma.Embeds) + } + pragma.Embeds = nil + } + p.checkUnused(pragma) + } + + p.setlineno(decl) + return typecheck.DeclVars(names, typ, exprs) +} + +// constState tracks state between constant specifiers within a +// declaration group. This state is kept separate from noder so nested +// constant declarations are handled correctly (e.g., issue 15550). +type constState struct { + group *syntax.Group + typ ir.Ntype + values []ir.Node + iota int64 +} + +func (p *noder) constDecl(decl *syntax.ConstDecl, cs *constState) []ir.Node { + if decl.Group == nil || decl.Group != cs.group { + *cs = constState{ + group: decl.Group, + } + } + + if pragma, ok := decl.Pragma.(*pragmas); ok { + p.checkUnused(pragma) + } + + names := p.declNames(ir.OLITERAL, decl.NameList) + typ := p.typeExprOrNil(decl.Type) + + var values []ir.Node + if decl.Values != nil { + values = p.exprList(decl.Values) + cs.typ, cs.values = typ, values + } else { + if typ != nil { + base.Errorf("const declaration cannot have type without expression") + } + typ, values = cs.typ, cs.values + } + + nn := make([]ir.Node, 0, len(names)) + for i, n := range names { + if i >= len(values) { + base.Errorf("missing value in const declaration") + break + } + v := values[i] + if decl.Values == nil { + v = ir.DeepCopy(n.Pos(), v) + } + typecheck.Declare(n, typecheck.DeclContext) + + n.Ntype = typ + n.Defn = v + n.SetIota(cs.iota) + + nn = append(nn, ir.NewDecl(p.pos(decl), ir.ODCLCONST, n)) + } + + if len(values) > len(names) { + base.Errorf("extra expression in const declaration") + } + + cs.iota++ + + return nn +} + +func (p *noder) typeDecl(decl *syntax.TypeDecl) ir.Node { + n := p.declName(ir.OTYPE, decl.Name) + typecheck.Declare(n, typecheck.DeclContext) + + // decl.Type may be nil but in that case we got a syntax error during parsing + typ := p.typeExprOrNil(decl.Type) + + n.Ntype = typ + n.SetAlias(decl.Alias) + if pragma, ok := decl.Pragma.(*pragmas); ok { + if !decl.Alias { + n.SetPragma(pragma.Flag & typePragmas) + pragma.Flag &^= typePragmas + } + p.checkUnused(pragma) + } + + nod := ir.NewDecl(p.pos(decl), ir.ODCLTYPE, n) + if n.Alias() && !types.AllowsGoVersion(types.LocalPkg, 1, 9) { + base.ErrorfAt(nod.Pos(), "type aliases only supported as of -lang=go1.9") + } + return nod +} + +func (p *noder) declNames(op ir.Op, names []*syntax.Name) []*ir.Name { + nodes := make([]*ir.Name, 0, len(names)) + for _, name := range names { + nodes = append(nodes, p.declName(op, name)) + } + return nodes +} + +func (p *noder) declName(op ir.Op, name *syntax.Name) *ir.Name { + return ir.NewDeclNameAt(p.pos(name), op, p.name(name)) +} + +func (p *noder) funcDecl(fun *syntax.FuncDecl) ir.Node { + name := p.name(fun.Name) + t := p.signature(fun.Recv, fun.Type) + f := ir.NewFunc(p.pos(fun)) + + if fun.Recv == nil { + if name.Name == "init" { + name = renameinit() + if len(t.Params) > 0 || len(t.Results) > 0 { + base.ErrorfAt(f.Pos(), "func init must have no arguments and no return values") + } + typecheck.Target.Inits = append(typecheck.Target.Inits, f) + } + + if types.LocalPkg.Name == "main" && name.Name == "main" { + if len(t.Params) > 0 || len(t.Results) > 0 { + base.ErrorfAt(f.Pos(), "func main must have no arguments and no return values") + } + } + } else { + f.Shortname = name + name = ir.BlankNode.Sym() // filled in by typecheckfunc + } + + f.Nname = ir.NewFuncNameAt(p.pos(fun.Name), name, f) + f.Nname.Defn = f + f.Nname.Ntype = t + + if pragma, ok := fun.Pragma.(*pragmas); ok { + f.Pragma = pragma.Flag & funcPragmas + if pragma.Flag&ir.Systemstack != 0 && pragma.Flag&ir.Nosplit != 0 { + base.ErrorfAt(f.Pos(), "go:nosplit and go:systemstack cannot be combined") + } + pragma.Flag &^= funcPragmas + p.checkUnused(pragma) + } + + if fun.Recv == nil { + typecheck.Declare(f.Nname, ir.PFUNC) + } + + p.funcBody(f, fun.Body) + + if fun.Body != nil { + if f.Pragma&ir.Noescape != 0 { + base.ErrorfAt(f.Pos(), "can only use //go:noescape with external func implementations") + } + } else { + if base.Flag.Complete || strings.HasPrefix(ir.FuncName(f), "init.") { + // Linknamed functions are allowed to have no body. Hopefully + // the linkname target has a body. See issue 23311. + isLinknamed := false + for _, n := range p.linknames { + if ir.FuncName(f) == n.local { + isLinknamed = true + break + } + } + if !isLinknamed { + base.ErrorfAt(f.Pos(), "missing function body") + } + } + } + + return f +} + +func (p *noder) signature(recv *syntax.Field, typ *syntax.FuncType) *ir.FuncType { + var rcvr *ir.Field + if recv != nil { + rcvr = p.param(recv, false, false) + } + return ir.NewFuncType(p.pos(typ), rcvr, + p.params(typ.ParamList, true), + p.params(typ.ResultList, false)) +} + +func (p *noder) params(params []*syntax.Field, dddOk bool) []*ir.Field { + nodes := make([]*ir.Field, 0, len(params)) + for i, param := range params { + p.setlineno(param) + nodes = append(nodes, p.param(param, dddOk, i+1 == len(params))) + } + return nodes +} + +func (p *noder) param(param *syntax.Field, dddOk, final bool) *ir.Field { + var name *types.Sym + if param.Name != nil { + name = p.name(param.Name) + } + + typ := p.typeExpr(param.Type) + n := ir.NewField(p.pos(param), name, typ, nil) + + // rewrite ...T parameter + if typ, ok := typ.(*ir.SliceType); ok && typ.DDD { + if !dddOk { + // We mark these as syntax errors to get automatic elimination + // of multiple such errors per line (see ErrorfAt in subr.go). + base.Errorf("syntax error: cannot use ... in receiver or result parameter list") + } else if !final { + if param.Name == nil { + base.Errorf("syntax error: cannot use ... with non-final parameter") + } else { + p.errorAt(param.Name.Pos(), "syntax error: cannot use ... with non-final parameter %s", param.Name.Value) + } + } + typ.DDD = false + n.IsDDD = true + } + + return n +} + +func (p *noder) exprList(expr syntax.Expr) []ir.Node { + if list, ok := expr.(*syntax.ListExpr); ok { + return p.exprs(list.ElemList) + } + return []ir.Node{p.expr(expr)} +} + +func (p *noder) exprs(exprs []syntax.Expr) []ir.Node { + nodes := make([]ir.Node, 0, len(exprs)) + for _, expr := range exprs { + nodes = append(nodes, p.expr(expr)) + } + return nodes +} + +func (p *noder) expr(expr syntax.Expr) ir.Node { + p.setlineno(expr) + switch expr := expr.(type) { + case nil, *syntax.BadExpr: + return nil + case *syntax.Name: + return p.mkname(expr) + case *syntax.BasicLit: + n := ir.NewLiteral(p.basicLit(expr)) + if expr.Kind == syntax.RuneLit { + n.SetType(types.UntypedRune) + } + n.SetDiag(expr.Bad) // avoid follow-on errors if there was a syntax error + return n + case *syntax.CompositeLit: + n := ir.NewCompLitExpr(p.pos(expr), ir.OCOMPLIT, nil, nil) + if expr.Type != nil { + n.Ntype = ir.Node(p.expr(expr.Type)).(ir.Ntype) + } + l := p.exprs(expr.ElemList) + for i, e := range l { + l[i] = p.wrapname(expr.ElemList[i], e) + } + n.List.Set(l) + base.Pos = p.makeXPos(expr.Rbrace) + return n + case *syntax.KeyValueExpr: + // use position of expr.Key rather than of expr (which has position of ':') + return ir.NewKeyExpr(p.pos(expr.Key), p.expr(expr.Key), p.wrapname(expr.Value, p.expr(expr.Value))) + case *syntax.FuncLit: + return p.funcLit(expr) + case *syntax.ParenExpr: + return ir.NewParenExpr(p.pos(expr), p.expr(expr.X)) + case *syntax.SelectorExpr: + // parser.new_dotname + obj := p.expr(expr.X) + if obj.Op() == ir.OPACK { + pack := obj.(*ir.PkgName) + pack.Used = true + return importName(pack.Pkg.Lookup(expr.Sel.Value)) + } + n := ir.NewSelectorExpr(base.Pos, ir.OXDOT, obj, p.name(expr.Sel)) + n.SetPos(p.pos(expr)) // lineno may have been changed by p.expr(expr.X) + return n + case *syntax.IndexExpr: + return ir.NewIndexExpr(p.pos(expr), p.expr(expr.X), p.expr(expr.Index)) + case *syntax.SliceExpr: + op := ir.OSLICE + if expr.Full { + op = ir.OSLICE3 + } + n := ir.NewSliceExpr(p.pos(expr), op, p.expr(expr.X)) + var index [3]ir.Node + for i, x := range &expr.Index { + if x != nil { + index[i] = p.expr(x) + } + } + n.SetSliceBounds(index[0], index[1], index[2]) + return n + case *syntax.AssertExpr: + return ir.NewTypeAssertExpr(p.pos(expr), p.expr(expr.X), p.typeExpr(expr.Type).(ir.Ntype)) + case *syntax.Operation: + if expr.Op == syntax.Add && expr.Y != nil { + return p.sum(expr) + } + x := p.expr(expr.X) + if expr.Y == nil { + pos, op := p.pos(expr), p.unOp(expr.Op) + switch op { + case ir.OADDR: + return typecheck.NodAddrAt(pos, x) + case ir.ODEREF: + return ir.NewStarExpr(pos, x) + } + return ir.NewUnaryExpr(pos, op, x) + } + + pos, op, y := p.pos(expr), p.binOp(expr.Op), p.expr(expr.Y) + switch op { + case ir.OANDAND, ir.OOROR: + return ir.NewLogicalExpr(pos, op, x, y) + } + return ir.NewBinaryExpr(pos, op, x, y) + case *syntax.CallExpr: + n := ir.NewCallExpr(p.pos(expr), ir.OCALL, p.expr(expr.Fun), nil) + n.Args.Set(p.exprs(expr.ArgList)) + n.IsDDD = expr.HasDots + return n + + case *syntax.ArrayType: + var len ir.Node + if expr.Len != nil { + len = p.expr(expr.Len) + } + return ir.NewArrayType(p.pos(expr), len, p.typeExpr(expr.Elem)) + case *syntax.SliceType: + return ir.NewSliceType(p.pos(expr), p.typeExpr(expr.Elem)) + case *syntax.DotsType: + t := ir.NewSliceType(p.pos(expr), p.typeExpr(expr.Elem)) + t.DDD = true + return t + case *syntax.StructType: + return p.structType(expr) + case *syntax.InterfaceType: + return p.interfaceType(expr) + case *syntax.FuncType: + return p.signature(nil, expr) + case *syntax.MapType: + return ir.NewMapType(p.pos(expr), + p.typeExpr(expr.Key), p.typeExpr(expr.Value)) + case *syntax.ChanType: + return ir.NewChanType(p.pos(expr), + p.typeExpr(expr.Elem), p.chanDir(expr.Dir)) + + case *syntax.TypeSwitchGuard: + var tag *ir.Ident + if expr.Lhs != nil { + tag = ir.NewIdent(p.pos(expr.Lhs), p.name(expr.Lhs)) + if ir.IsBlank(tag) { + base.Errorf("invalid variable name %v in type switch", tag) + } + } + return ir.NewTypeSwitchGuard(p.pos(expr), tag, p.expr(expr.X)) + } + panic("unhandled Expr") +} + +// sum efficiently handles very large summation expressions (such as +// in issue #16394). In particular, it avoids left recursion and +// collapses string literals. +func (p *noder) sum(x syntax.Expr) ir.Node { + // While we need to handle long sums with asymptotic + // efficiency, the vast majority of sums are very small: ~95% + // have only 2 or 3 operands, and ~99% of string literals are + // never concatenated. + + adds := make([]*syntax.Operation, 0, 2) + for { + add, ok := x.(*syntax.Operation) + if !ok || add.Op != syntax.Add || add.Y == nil { + break + } + adds = append(adds, add) + x = add.X + } + + // nstr is the current rightmost string literal in the + // summation (if any), and chunks holds its accumulated + // substrings. + // + // Consider the expression x + "a" + "b" + "c" + y. When we + // reach the string literal "a", we assign nstr to point to + // its corresponding Node and initialize chunks to {"a"}. + // Visiting the subsequent string literals "b" and "c", we + // simply append their values to chunks. Finally, when we + // reach the non-constant operand y, we'll join chunks to form + // "abc" and reassign the "a" string literal's value. + // + // N.B., we need to be careful about named string constants + // (indicated by Sym != nil) because 1) we can't modify their + // value, as doing so would affect other uses of the string + // constant, and 2) they may have types, which we need to + // handle correctly. For now, we avoid these problems by + // treating named string constants the same as non-constant + // operands. + var nstr ir.Node + chunks := make([]string, 0, 1) + + n := p.expr(x) + if ir.IsConst(n, constant.String) && n.Sym() == nil { + nstr = n + chunks = append(chunks, ir.StringVal(nstr)) + } + + for i := len(adds) - 1; i >= 0; i-- { + add := adds[i] + + r := p.expr(add.Y) + if ir.IsConst(r, constant.String) && r.Sym() == nil { + if nstr != nil { + // Collapse r into nstr instead of adding to n. + chunks = append(chunks, ir.StringVal(r)) + continue + } + + nstr = r + chunks = append(chunks, ir.StringVal(nstr)) + } else { + if len(chunks) > 1 { + nstr.SetVal(constant.MakeString(strings.Join(chunks, ""))) + } + nstr = nil + chunks = chunks[:0] + } + n = ir.NewBinaryExpr(p.pos(add), ir.OADD, n, r) + } + if len(chunks) > 1 { + nstr.SetVal(constant.MakeString(strings.Join(chunks, ""))) + } + + return n +} + +func (p *noder) typeExpr(typ syntax.Expr) ir.Ntype { + // TODO(mdempsky): Be stricter? typecheck should handle errors anyway. + n := p.expr(typ) + if n == nil { + return nil + } + if _, ok := n.(ir.Ntype); !ok { + ir.Dump("NOT NTYPE", n) + } + return n.(ir.Ntype) +} + +func (p *noder) typeExprOrNil(typ syntax.Expr) ir.Ntype { + if typ != nil { + return p.typeExpr(typ) + } + return nil +} + +func (p *noder) chanDir(dir syntax.ChanDir) types.ChanDir { + switch dir { + case 0: + return types.Cboth + case syntax.SendOnly: + return types.Csend + case syntax.RecvOnly: + return types.Crecv + } + panic("unhandled ChanDir") +} + +func (p *noder) structType(expr *syntax.StructType) ir.Node { + l := make([]*ir.Field, 0, len(expr.FieldList)) + for i, field := range expr.FieldList { + p.setlineno(field) + var n *ir.Field + if field.Name == nil { + n = p.embedded(field.Type) + } else { + n = ir.NewField(p.pos(field), p.name(field.Name), p.typeExpr(field.Type), nil) + } + if i < len(expr.TagList) && expr.TagList[i] != nil { + n.Note = constant.StringVal(p.basicLit(expr.TagList[i])) + } + l = append(l, n) + } + + p.setlineno(expr) + return ir.NewStructType(p.pos(expr), l) +} + +func (p *noder) interfaceType(expr *syntax.InterfaceType) ir.Node { + l := make([]*ir.Field, 0, len(expr.MethodList)) + for _, method := range expr.MethodList { + p.setlineno(method) + var n *ir.Field + if method.Name == nil { + n = ir.NewField(p.pos(method), nil, importName(p.packname(method.Type)).(ir.Ntype), nil) + } else { + mname := p.name(method.Name) + if mname.IsBlank() { + base.Errorf("methods must have a unique non-blank name") + continue + } + sig := p.typeExpr(method.Type).(*ir.FuncType) + sig.Recv = fakeRecv() + n = ir.NewField(p.pos(method), mname, sig, nil) + } + l = append(l, n) + } + + return ir.NewInterfaceType(p.pos(expr), l) +} + +func (p *noder) packname(expr syntax.Expr) *types.Sym { + switch expr := expr.(type) { + case *syntax.Name: + name := p.name(expr) + if n := oldname(name); n.Name() != nil && n.Name().PkgName != nil { + n.Name().PkgName.Used = true + } + return name + case *syntax.SelectorExpr: + name := p.name(expr.X.(*syntax.Name)) + def := ir.AsNode(name.Def) + if def == nil { + base.Errorf("undefined: %v", name) + return name + } + var pkg *types.Pkg + if def.Op() != ir.OPACK { + base.Errorf("%v is not a package", name) + pkg = types.LocalPkg + } else { + def := def.(*ir.PkgName) + def.Used = true + pkg = def.Pkg + } + return pkg.Lookup(expr.Sel.Value) + } + panic(fmt.Sprintf("unexpected packname: %#v", expr)) +} + +func (p *noder) embedded(typ syntax.Expr) *ir.Field { + op, isStar := typ.(*syntax.Operation) + if isStar { + if op.Op != syntax.Mul || op.Y != nil { + panic("unexpected Operation") + } + typ = op.X + } + + sym := p.packname(typ) + n := ir.NewField(p.pos(typ), typecheck.Lookup(sym.Name), importName(sym).(ir.Ntype), nil) + n.Embedded = true + + if isStar { + n.Ntype = ir.NewStarExpr(p.pos(op), n.Ntype) + } + return n +} + +func (p *noder) stmts(stmts []syntax.Stmt) []ir.Node { + return p.stmtsFall(stmts, false) +} + +func (p *noder) stmtsFall(stmts []syntax.Stmt, fallOK bool) []ir.Node { + var nodes []ir.Node + for i, stmt := range stmts { + s := p.stmtFall(stmt, fallOK && i+1 == len(stmts)) + if s == nil { + } else if s.Op() == ir.OBLOCK && len(s.(*ir.BlockStmt).List) > 0 { + // Inline non-empty block. + // Empty blocks must be preserved for checkreturn. + nodes = append(nodes, s.(*ir.BlockStmt).List...) + } else { + nodes = append(nodes, s) + } + } + return nodes +} + +func (p *noder) stmt(stmt syntax.Stmt) ir.Node { + return p.stmtFall(stmt, false) +} + +func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) ir.Node { + p.setlineno(stmt) + switch stmt := stmt.(type) { + case *syntax.EmptyStmt: + return nil + case *syntax.LabeledStmt: + return p.labeledStmt(stmt, fallOK) + case *syntax.BlockStmt: + l := p.blockStmt(stmt) + if len(l) == 0 { + // TODO(mdempsky): Line number? + return ir.NewBlockStmt(base.Pos, nil) + } + return ir.NewBlockStmt(src.NoXPos, l) + case *syntax.ExprStmt: + return p.wrapname(stmt, p.expr(stmt.X)) + case *syntax.SendStmt: + return ir.NewSendStmt(p.pos(stmt), p.expr(stmt.Chan), p.expr(stmt.Value)) + case *syntax.DeclStmt: + return ir.NewBlockStmt(src.NoXPos, p.decls(stmt.DeclList)) + case *syntax.AssignStmt: + if stmt.Op != 0 && stmt.Op != syntax.Def { + n := ir.NewAssignOpStmt(p.pos(stmt), p.binOp(stmt.Op), p.expr(stmt.Lhs), p.expr(stmt.Rhs)) + n.IncDec = stmt.Rhs == syntax.ImplicitOne + return n + } + + rhs := p.exprList(stmt.Rhs) + if list, ok := stmt.Lhs.(*syntax.ListExpr); ok && len(list.ElemList) != 1 || len(rhs) != 1 { + n := ir.NewAssignListStmt(p.pos(stmt), ir.OAS2, nil, nil) + n.Def = stmt.Op == syntax.Def + n.Lhs.Set(p.assignList(stmt.Lhs, n, n.Def)) + n.Rhs.Set(rhs) + return n + } + + n := ir.NewAssignStmt(p.pos(stmt), nil, nil) + n.Def = stmt.Op == syntax.Def + n.X = p.assignList(stmt.Lhs, n, n.Def)[0] + n.Y = rhs[0] + return n + + case *syntax.BranchStmt: + var op ir.Op + switch stmt.Tok { + case syntax.Break: + op = ir.OBREAK + case syntax.Continue: + op = ir.OCONTINUE + case syntax.Fallthrough: + if !fallOK { + base.Errorf("fallthrough statement out of place") + } + op = ir.OFALL + case syntax.Goto: + op = ir.OGOTO + default: + panic("unhandled BranchStmt") + } + var sym *types.Sym + if stmt.Label != nil { + sym = p.name(stmt.Label) + } + return ir.NewBranchStmt(p.pos(stmt), op, sym) + case *syntax.CallStmt: + var op ir.Op + switch stmt.Tok { + case syntax.Defer: + op = ir.ODEFER + case syntax.Go: + op = ir.OGO + default: + panic("unhandled CallStmt") + } + return ir.NewGoDeferStmt(p.pos(stmt), op, p.expr(stmt.Call)) + case *syntax.ReturnStmt: + var results []ir.Node + if stmt.Results != nil { + results = p.exprList(stmt.Results) + } + n := ir.NewReturnStmt(p.pos(stmt), nil) + n.Results.Set(results) + if len(n.Results) == 0 && ir.CurFunc != nil { + for _, ln := range ir.CurFunc.Dcl { + if ln.Class_ == ir.PPARAM { + continue + } + if ln.Class_ != ir.PPARAMOUT { + break + } + if ln.Sym().Def != ln { + base.Errorf("%s is shadowed during return", ln.Sym().Name) + } + } + } + return n + case *syntax.IfStmt: + return p.ifStmt(stmt) + case *syntax.ForStmt: + return p.forStmt(stmt) + case *syntax.SwitchStmt: + return p.switchStmt(stmt) + case *syntax.SelectStmt: + return p.selectStmt(stmt) + } + panic("unhandled Stmt") +} + +func (p *noder) assignList(expr syntax.Expr, defn ir.Node, colas bool) []ir.Node { + if !colas { + return p.exprList(expr) + } + + var exprs []syntax.Expr + if list, ok := expr.(*syntax.ListExpr); ok { + exprs = list.ElemList + } else { + exprs = []syntax.Expr{expr} + } + + res := make([]ir.Node, len(exprs)) + seen := make(map[*types.Sym]bool, len(exprs)) + + newOrErr := false + for i, expr := range exprs { + p.setlineno(expr) + res[i] = ir.BlankNode + + name, ok := expr.(*syntax.Name) + if !ok { + p.errorAt(expr.Pos(), "non-name %v on left side of :=", p.expr(expr)) + newOrErr = true + continue + } + + sym := p.name(name) + if sym.IsBlank() { + continue + } + + if seen[sym] { + p.errorAt(expr.Pos(), "%v repeated on left side of :=", sym) + newOrErr = true + continue + } + seen[sym] = true + + if sym.Block == types.Block { + res[i] = oldname(sym) + continue + } + + newOrErr = true + n := typecheck.NewName(sym) + typecheck.Declare(n, typecheck.DeclContext) + n.Defn = defn + defn.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, n)) + res[i] = n + } + + if !newOrErr { + base.ErrorfAt(defn.Pos(), "no new variables on left side of :=") + } + return res +} + +func (p *noder) blockStmt(stmt *syntax.BlockStmt) []ir.Node { + p.openScope(stmt.Pos()) + nodes := p.stmts(stmt.List) + p.closeScope(stmt.Rbrace) + return nodes +} + +func (p *noder) ifStmt(stmt *syntax.IfStmt) ir.Node { + p.openScope(stmt.Pos()) + n := ir.NewIfStmt(p.pos(stmt), nil, nil, nil) + if stmt.Init != nil { + *n.PtrInit() = []ir.Node{p.stmt(stmt.Init)} + } + if stmt.Cond != nil { + n.Cond = p.expr(stmt.Cond) + } + n.Body.Set(p.blockStmt(stmt.Then)) + if stmt.Else != nil { + e := p.stmt(stmt.Else) + if e.Op() == ir.OBLOCK { + e := e.(*ir.BlockStmt) + n.Else.Set(e.List) + } else { + n.Else = []ir.Node{e} + } + } + p.closeAnotherScope() + return n +} + +func (p *noder) forStmt(stmt *syntax.ForStmt) ir.Node { + p.openScope(stmt.Pos()) + if r, ok := stmt.Init.(*syntax.RangeClause); ok { + if stmt.Cond != nil || stmt.Post != nil { + panic("unexpected RangeClause") + } + + n := ir.NewRangeStmt(p.pos(r), nil, p.expr(r.X), nil) + if r.Lhs != nil { + n.Def = r.Def + n.Vars.Set(p.assignList(r.Lhs, n, n.Def)) + } + n.Body.Set(p.blockStmt(stmt.Body)) + p.closeAnotherScope() + return n + } + + n := ir.NewForStmt(p.pos(stmt), nil, nil, nil, nil) + if stmt.Init != nil { + *n.PtrInit() = []ir.Node{p.stmt(stmt.Init)} + } + if stmt.Cond != nil { + n.Cond = p.expr(stmt.Cond) + } + if stmt.Post != nil { + n.Post = p.stmt(stmt.Post) + } + n.Body.Set(p.blockStmt(stmt.Body)) + p.closeAnotherScope() + return n +} + +func (p *noder) switchStmt(stmt *syntax.SwitchStmt) ir.Node { + p.openScope(stmt.Pos()) + n := ir.NewSwitchStmt(p.pos(stmt), nil, nil) + if stmt.Init != nil { + *n.PtrInit() = []ir.Node{p.stmt(stmt.Init)} + } + if stmt.Tag != nil { + n.Tag = p.expr(stmt.Tag) + } + + var tswitch *ir.TypeSwitchGuard + if l := n.Tag; l != nil && l.Op() == ir.OTYPESW { + tswitch = l.(*ir.TypeSwitchGuard) + } + n.Cases.Set(p.caseClauses(stmt.Body, tswitch, stmt.Rbrace)) + + p.closeScope(stmt.Rbrace) + return n +} + +func (p *noder) caseClauses(clauses []*syntax.CaseClause, tswitch *ir.TypeSwitchGuard, rbrace syntax.Pos) []ir.Node { + nodes := make([]ir.Node, 0, len(clauses)) + for i, clause := range clauses { + p.setlineno(clause) + if i > 0 { + p.closeScope(clause.Pos()) + } + p.openScope(clause.Pos()) + + n := ir.NewCaseStmt(p.pos(clause), nil, nil) + if clause.Cases != nil { + n.List.Set(p.exprList(clause.Cases)) + } + if tswitch != nil && tswitch.Tag != nil { + nn := typecheck.NewName(tswitch.Tag.Sym()) + typecheck.Declare(nn, typecheck.DeclContext) + n.Vars = []ir.Node{nn} + // keep track of the instances for reporting unused + nn.Defn = tswitch + } + + // Trim trailing empty statements. We omit them from + // the Node AST anyway, and it's easier to identify + // out-of-place fallthrough statements without them. + body := clause.Body + for len(body) > 0 { + if _, ok := body[len(body)-1].(*syntax.EmptyStmt); !ok { + break + } + body = body[:len(body)-1] + } + + n.Body.Set(p.stmtsFall(body, true)) + if l := len(n.Body); l > 0 && n.Body[l-1].Op() == ir.OFALL { + if tswitch != nil { + base.Errorf("cannot fallthrough in type switch") + } + if i+1 == len(clauses) { + base.Errorf("cannot fallthrough final case in switch") + } + } + + nodes = append(nodes, n) + } + if len(clauses) > 0 { + p.closeScope(rbrace) + } + return nodes +} + +func (p *noder) selectStmt(stmt *syntax.SelectStmt) ir.Node { + n := ir.NewSelectStmt(p.pos(stmt), nil) + n.Cases.Set(p.commClauses(stmt.Body, stmt.Rbrace)) + return n +} + +func (p *noder) commClauses(clauses []*syntax.CommClause, rbrace syntax.Pos) []ir.Node { + nodes := make([]ir.Node, 0, len(clauses)) + for i, clause := range clauses { + p.setlineno(clause) + if i > 0 { + p.closeScope(clause.Pos()) + } + p.openScope(clause.Pos()) + + n := ir.NewCaseStmt(p.pos(clause), nil, nil) + if clause.Comm != nil { + n.List = []ir.Node{p.stmt(clause.Comm)} + } + n.Body.Set(p.stmts(clause.Body)) + nodes = append(nodes, n) + } + if len(clauses) > 0 { + p.closeScope(rbrace) + } + return nodes +} + +func (p *noder) labeledStmt(label *syntax.LabeledStmt, fallOK bool) ir.Node { + sym := p.name(label.Label) + lhs := ir.NewLabelStmt(p.pos(label), sym) + + var ls ir.Node + if label.Stmt != nil { // TODO(mdempsky): Should always be present. + ls = p.stmtFall(label.Stmt, fallOK) + // Attach label directly to control statement too. + if ls != nil { + switch ls.Op() { + case ir.OFOR: + ls := ls.(*ir.ForStmt) + ls.Label = sym + case ir.ORANGE: + ls := ls.(*ir.RangeStmt) + ls.Label = sym + case ir.OSWITCH: + ls := ls.(*ir.SwitchStmt) + ls.Label = sym + case ir.OSELECT: + ls := ls.(*ir.SelectStmt) + ls.Label = sym + } + } + } + + l := []ir.Node{lhs} + if ls != nil { + if ls.Op() == ir.OBLOCK { + ls := ls.(*ir.BlockStmt) + l = append(l, ls.List...) + } else { + l = append(l, ls) + } + } + return ir.NewBlockStmt(src.NoXPos, l) +} + +var unOps = [...]ir.Op{ + syntax.Recv: ir.ORECV, + syntax.Mul: ir.ODEREF, + syntax.And: ir.OADDR, + + syntax.Not: ir.ONOT, + syntax.Xor: ir.OBITNOT, + syntax.Add: ir.OPLUS, + syntax.Sub: ir.ONEG, +} + +func (p *noder) unOp(op syntax.Operator) ir.Op { + if uint64(op) >= uint64(len(unOps)) || unOps[op] == 0 { + panic("invalid Operator") + } + return unOps[op] +} + +var binOps = [...]ir.Op{ + syntax.OrOr: ir.OOROR, + syntax.AndAnd: ir.OANDAND, + + syntax.Eql: ir.OEQ, + syntax.Neq: ir.ONE, + syntax.Lss: ir.OLT, + syntax.Leq: ir.OLE, + syntax.Gtr: ir.OGT, + syntax.Geq: ir.OGE, + + syntax.Add: ir.OADD, + syntax.Sub: ir.OSUB, + syntax.Or: ir.OOR, + syntax.Xor: ir.OXOR, + + syntax.Mul: ir.OMUL, + syntax.Div: ir.ODIV, + syntax.Rem: ir.OMOD, + syntax.And: ir.OAND, + syntax.AndNot: ir.OANDNOT, + syntax.Shl: ir.OLSH, + syntax.Shr: ir.ORSH, +} + +func (p *noder) binOp(op syntax.Operator) ir.Op { + if uint64(op) >= uint64(len(binOps)) || binOps[op] == 0 { + panic("invalid Operator") + } + return binOps[op] +} + +// checkLangCompat reports an error if the representation of a numeric +// literal is not compatible with the current language version. +func checkLangCompat(lit *syntax.BasicLit) { + s := lit.Value + if len(s) <= 2 || types.AllowsGoVersion(types.LocalPkg, 1, 13) { + return + } + // len(s) > 2 + if strings.Contains(s, "_") { + base.ErrorfVers("go1.13", "underscores in numeric literals") + return + } + if s[0] != '0' { + return + } + radix := s[1] + if radix == 'b' || radix == 'B' { + base.ErrorfVers("go1.13", "binary literals") + return + } + if radix == 'o' || radix == 'O' { + base.ErrorfVers("go1.13", "0o/0O-style octal literals") + return + } + if lit.Kind != syntax.IntLit && (radix == 'x' || radix == 'X') { + base.ErrorfVers("go1.13", "hexadecimal floating-point literals") + } +} + +func (p *noder) basicLit(lit *syntax.BasicLit) constant.Value { + // We don't use the errors of the conversion routines to determine + // if a literal string is valid because the conversion routines may + // accept a wider syntax than the language permits. Rely on lit.Bad + // instead. + if lit.Bad { + return constant.MakeUnknown() + } + + switch lit.Kind { + case syntax.IntLit, syntax.FloatLit, syntax.ImagLit: + checkLangCompat(lit) + } + + v := constant.MakeFromLiteral(lit.Value, tokenForLitKind[lit.Kind], 0) + if v.Kind() == constant.Unknown { + // TODO(mdempsky): Better error message? + p.errorAt(lit.Pos(), "malformed constant: %s", lit.Value) + } + + // go/constant uses big.Rat by default, which is more precise, but + // causes toolstash -cmp and some tests to fail. For now, convert + // to big.Float to match cmd/compile's historical precision. + // TODO(mdempsky): Remove. + if v.Kind() == constant.Float { + v = constant.Make(ir.BigFloat(v)) + } + + return v +} + +var tokenForLitKind = [...]token.Token{ + syntax.IntLit: token.INT, + syntax.RuneLit: token.CHAR, + syntax.FloatLit: token.FLOAT, + syntax.ImagLit: token.IMAG, + syntax.StringLit: token.STRING, +} + +func (p *noder) name(name *syntax.Name) *types.Sym { + return typecheck.Lookup(name.Value) +} + +func (p *noder) mkname(name *syntax.Name) ir.Node { + // TODO(mdempsky): Set line number? + return mkname(p.name(name)) +} + +func (p *noder) wrapname(n syntax.Node, x ir.Node) ir.Node { + // These nodes do not carry line numbers. + // Introduce a wrapper node to give them the correct line. + switch x.Op() { + case ir.OTYPE, ir.OLITERAL: + if x.Sym() == nil { + break + } + fallthrough + case ir.ONAME, ir.ONONAME, ir.OPACK: + p := ir.NewParenExpr(p.pos(n), x) + p.SetImplicit(true) + return p + } + return x +} + +func (p *noder) pos(n syntax.Node) src.XPos { + // TODO(gri): orig.Pos() should always be known - fix package syntax + xpos := base.Pos + if pos := n.Pos(); pos.IsKnown() { + xpos = p.makeXPos(pos) + } + return xpos +} + +func (p *noder) setlineno(n syntax.Node) { + if n != nil { + base.Pos = p.pos(n) + } +} + +// error is called concurrently if files are parsed concurrently. +func (p *noder) error(err error) { + p.err <- err.(syntax.Error) +} + +// pragmas that are allowed in the std lib, but don't have +// a syntax.Pragma value (see lex.go) associated with them. +var allowedStdPragmas = map[string]bool{ + "go:cgo_export_static": true, + "go:cgo_export_dynamic": true, + "go:cgo_import_static": true, + "go:cgo_import_dynamic": true, + "go:cgo_ldflag": true, + "go:cgo_dynamic_linker": true, + "go:embed": true, + "go:generate": true, +} + +// *pragmas is the value stored in a syntax.pragmas during parsing. +type pragmas struct { + Flag ir.PragmaFlag // collected bits + Pos []pragmaPos // position of each individual flag + Embeds []pragmaEmbed +} + +type pragmaPos struct { + Flag ir.PragmaFlag + Pos syntax.Pos +} + +type pragmaEmbed struct { + Pos syntax.Pos + Patterns []string +} + +func (p *noder) checkUnused(pragma *pragmas) { + for _, pos := range pragma.Pos { + if pos.Flag&pragma.Flag != 0 { + p.errorAt(pos.Pos, "misplaced compiler directive") + } + } + if len(pragma.Embeds) > 0 { + for _, e := range pragma.Embeds { + p.errorAt(e.Pos, "misplaced go:embed directive") + } + } +} + +func (p *noder) checkUnusedDuringParse(pragma *pragmas) { + for _, pos := range pragma.Pos { + if pos.Flag&pragma.Flag != 0 { + p.error(syntax.Error{Pos: pos.Pos, Msg: "misplaced compiler directive"}) + } + } + if len(pragma.Embeds) > 0 { + for _, e := range pragma.Embeds { + p.error(syntax.Error{Pos: e.Pos, Msg: "misplaced go:embed directive"}) + } + } +} + +// pragma is called concurrently if files are parsed concurrently. +func (p *noder) pragma(pos syntax.Pos, blankLine bool, text string, old syntax.Pragma) syntax.Pragma { + pragma, _ := old.(*pragmas) + if pragma == nil { + pragma = new(pragmas) + } + + if text == "" { + // unused pragma; only called with old != nil. + p.checkUnusedDuringParse(pragma) + return nil + } + + if strings.HasPrefix(text, "line ") { + // line directives are handled by syntax package + panic("unreachable") + } + + if !blankLine { + // directive must be on line by itself + p.error(syntax.Error{Pos: pos, Msg: "misplaced compiler directive"}) + return pragma + } + + switch { + case strings.HasPrefix(text, "go:linkname "): + f := strings.Fields(text) + if !(2 <= len(f) && len(f) <= 3) { + p.error(syntax.Error{Pos: pos, Msg: "usage: //go:linkname localname [linkname]"}) + break + } + // The second argument is optional. If omitted, we use + // the default object symbol name for this and + // linkname only serves to mark this symbol as + // something that may be referenced via the object + // symbol name from another package. + var target string + if len(f) == 3 { + target = f[2] + } else if base.Ctxt.Pkgpath != "" { + // Use the default object symbol name if the + // user didn't provide one. + target = objabi.PathToPrefix(base.Ctxt.Pkgpath) + "." + f[1] + } else { + p.error(syntax.Error{Pos: pos, Msg: "//go:linkname requires linkname argument or -p compiler flag"}) + break + } + p.linknames = append(p.linknames, linkname{pos, f[1], target}) + + case text == "go:embed", strings.HasPrefix(text, "go:embed "): + args, err := parseGoEmbed(text[len("go:embed"):]) + if err != nil { + p.error(syntax.Error{Pos: pos, Msg: err.Error()}) + } + if len(args) == 0 { + p.error(syntax.Error{Pos: pos, Msg: "usage: //go:embed pattern..."}) + break + } + pragma.Embeds = append(pragma.Embeds, pragmaEmbed{pos, args}) + + case strings.HasPrefix(text, "go:cgo_import_dynamic "): + // This is permitted for general use because Solaris + // code relies on it in golang.org/x/sys/unix and others. + fields := pragmaFields(text) + if len(fields) >= 4 { + lib := strings.Trim(fields[3], `"`) + if lib != "" && !safeArg(lib) && !isCgoGeneratedFile(pos) { + p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("invalid library name %q in cgo_import_dynamic directive", lib)}) + } + p.pragcgo(pos, text) + pragma.Flag |= pragmaFlag("go:cgo_import_dynamic") + break + } + fallthrough + case strings.HasPrefix(text, "go:cgo_"): + // For security, we disallow //go:cgo_* directives other + // than cgo_import_dynamic outside cgo-generated files. + // Exception: they are allowed in the standard library, for runtime and syscall. + if !isCgoGeneratedFile(pos) && !base.Flag.Std { + p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("//%s only allowed in cgo-generated code", text)}) + } + p.pragcgo(pos, text) + fallthrough // because of //go:cgo_unsafe_args + default: + verb := text + if i := strings.Index(text, " "); i >= 0 { + verb = verb[:i] + } + flag := pragmaFlag(verb) + const runtimePragmas = ir.Systemstack | ir.Nowritebarrier | ir.Nowritebarrierrec | ir.Yeswritebarrierrec + if !base.Flag.CompilingRuntime && flag&runtimePragmas != 0 { + p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("//%s only allowed in runtime", verb)}) + } + if flag == 0 && !allowedStdPragmas[verb] && base.Flag.Std { + p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("//%s is not allowed in the standard library", verb)}) + } + pragma.Flag |= flag + pragma.Pos = append(pragma.Pos, pragmaPos{flag, pos}) + } + + return pragma +} + +// isCgoGeneratedFile reports whether pos is in a file +// generated by cgo, which is to say a file with name +// beginning with "_cgo_". Such files are allowed to +// contain cgo directives, and for security reasons +// (primarily misuse of linker flags), other files are not. +// See golang.org/issue/23672. +func isCgoGeneratedFile(pos syntax.Pos) bool { + return strings.HasPrefix(filepath.Base(filepath.Clean(fileh(pos.Base().Filename()))), "_cgo_") +} + +// safeArg reports whether arg is a "safe" command-line argument, +// meaning that when it appears in a command-line, it probably +// doesn't have some special meaning other than its own name. +// This is copied from SafeArg in cmd/go/internal/load/pkg.go. +func safeArg(name string) bool { + if name == "" { + return false + } + c := name[0] + return '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || c == '.' || c == '_' || c == '/' || c >= utf8.RuneSelf +} + +func mkname(sym *types.Sym) ir.Node { + n := oldname(sym) + if n.Name() != nil && n.Name().PkgName != nil { + n.Name().PkgName.Used = true + } + return n +} + +// parseGoEmbed parses the text following "//go:embed" to extract the glob patterns. +// It accepts unquoted space-separated patterns as well as double-quoted and back-quoted Go strings. +// go/build/read.go also processes these strings and contains similar logic. +func parseGoEmbed(args string) ([]string, error) { + var list []string + for args = strings.TrimSpace(args); args != ""; args = strings.TrimSpace(args) { + var path string + Switch: + switch args[0] { + default: + i := len(args) + for j, c := range args { + if unicode.IsSpace(c) { + i = j + break + } + } + path = args[:i] + args = args[i:] + + case '`': + i := strings.Index(args[1:], "`") + if i < 0 { + return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args) + } + path = args[1 : 1+i] + args = args[1+i+1:] + + case '"': + i := 1 + for ; i < len(args); i++ { + if args[i] == '\\' { + i++ + continue + } + if args[i] == '"' { + q, err := strconv.Unquote(args[:i+1]) + if err != nil { + return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args[:i+1]) + } + path = q + args = args[i+1:] + break Switch + } + } + if i >= len(args) { + return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args) + } + } + + if args != "" { + r, _ := utf8.DecodeRuneInString(args) + if !unicode.IsSpace(r) { + return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args) + } + } + list = append(list, path) + } + return list, nil +} + +func fakeRecv() *ir.Field { + return ir.NewField(base.Pos, nil, nil, types.FakeRecvType()) +} + +func (p *noder) funcLit(expr *syntax.FuncLit) ir.Node { + xtype := p.typeExpr(expr.Type) + ntype := p.typeExpr(expr.Type) + + fn := ir.NewFunc(p.pos(expr)) + fn.SetIsHiddenClosure(ir.CurFunc != nil) + fn.Nname = ir.NewFuncNameAt(p.pos(expr), ir.BlankNode.Sym(), fn) // filled in by typecheckclosure + fn.Nname.Ntype = xtype + fn.Nname.Defn = fn + + clo := ir.NewClosureExpr(p.pos(expr), fn) + fn.ClosureType = ntype + fn.OClosure = clo + + p.funcBody(fn, expr.Body) + + // closure-specific variables are hanging off the + // ordinary ones in the symbol table; see oldname. + // unhook them. + // make the list of pointers for the closure call. + for _, v := range fn.ClosureVars { + // Unlink from v1; see comment in syntax.go type Param for these fields. + v1 := v.Defn + v1.Name().Innermost = v.Outer + + // If the closure usage of v is not dense, + // we need to make it dense; now that we're out + // of the function in which v appeared, + // look up v.Sym in the enclosing function + // and keep it around for use in the compiled code. + // + // That is, suppose we just finished parsing the innermost + // closure f4 in this code: + // + // func f() { + // v := 1 + // func() { // f2 + // use(v) + // func() { // f3 + // func() { // f4 + // use(v) + // }() + // }() + // }() + // } + // + // At this point v.Outer is f2's v; there is no f3's v. + // To construct the closure f4 from within f3, + // we need to use f3's v and in this case we need to create f3's v. + // We are now in the context of f3, so calling oldname(v.Sym) + // obtains f3's v, creating it if necessary (as it is in the example). + // + // capturevars will decide whether to use v directly or &v. + v.Outer = oldname(v.Sym()).(*ir.Name) + } + + return clo +} + +// A function named init is a special case. +// It is called by the initialization before main is run. +// To make it unique within a package and also uncallable, +// the name, normally "pkg.init", is altered to "pkg.init.0". +var renameinitgen int + +func renameinit() *types.Sym { + s := typecheck.LookupNum("init.", renameinitgen) + renameinitgen++ + return s +} + +// oldname returns the Node that declares symbol s in the current scope. +// If no such Node currently exists, an ONONAME Node is returned instead. +// Automatically creates a new closure variable if the referenced symbol was +// declared in a different (containing) function. +func oldname(s *types.Sym) ir.Node { + if s.Pkg != types.LocalPkg { + return ir.NewIdent(base.Pos, s) + } + + n := ir.AsNode(s.Def) + if n == nil { + // Maybe a top-level declaration will come along later to + // define s. resolve will check s.Def again once all input + // source has been processed. + return ir.NewIdent(base.Pos, s) + } + + if ir.CurFunc != nil && n.Op() == ir.ONAME && n.Name().Curfn != nil && n.Name().Curfn != ir.CurFunc { + // Inner func is referring to var in outer func. + // + // TODO(rsc): If there is an outer variable x and we + // are parsing x := 5 inside the closure, until we get to + // the := it looks like a reference to the outer x so we'll + // make x a closure variable unnecessarily. + n := n.(*ir.Name) + c := n.Name().Innermost + if c == nil || c.Curfn != ir.CurFunc { + // Do not have a closure var for the active closure yet; make one. + c = typecheck.NewName(s) + c.Class_ = ir.PAUTOHEAP + c.SetIsClosureVar(true) + c.SetIsDDD(n.IsDDD()) + c.Defn = n + + // Link into list of active closure variables. + // Popped from list in func funcLit. + c.Outer = n.Name().Innermost + n.Name().Innermost = c + + ir.CurFunc.ClosureVars = append(ir.CurFunc.ClosureVars, c) + } + + // return ref to closure var, not original + return c + } + + return n +} + +func varEmbed(p *noder, names []*ir.Name, typ ir.Ntype, exprs []ir.Node, embeds []pragmaEmbed) (newExprs []ir.Node) { + haveEmbed := false + for _, decl := range p.file.DeclList { + imp, ok := decl.(*syntax.ImportDecl) + if !ok { + // imports always come first + break + } + path, _ := strconv.Unquote(imp.Path.Value) + if path == "embed" { + haveEmbed = true + break + } + } + + pos := embeds[0].Pos + if !haveEmbed { + p.errorAt(pos, "invalid go:embed: missing import \"embed\"") + return exprs + } + if base.Flag.Cfg.Embed.Patterns == nil { + p.errorAt(pos, "invalid go:embed: build system did not supply embed configuration") + return exprs + } + if len(names) > 1 { + p.errorAt(pos, "go:embed cannot apply to multiple vars") + return exprs + } + if len(exprs) > 0 { + p.errorAt(pos, "go:embed cannot apply to var with initializer") + return exprs + } + if typ == nil { + // Should not happen, since len(exprs) == 0 now. + p.errorAt(pos, "go:embed cannot apply to var without type") + return exprs + } + if typecheck.DeclContext != ir.PEXTERN { + p.errorAt(pos, "go:embed cannot apply to var inside func") + return exprs + } + + v := names[0] + typecheck.Target.Embeds = append(typecheck.Target.Embeds, v) + v.Embed = new([]ir.Embed) + for _, e := range embeds { + *v.Embed = append(*v.Embed, ir.Embed{Pos: p.makeXPos(e.Pos), Patterns: e.Patterns}) + } + return exprs +} diff --git a/src/cmd/internal/archive/archive.go b/src/cmd/internal/archive/archive.go index 762e888a04..e9b25fe240 100644 --- a/src/cmd/internal/archive/archive.go +++ b/src/cmd/internal/archive/archive.go @@ -464,3 +464,24 @@ func exactly16Bytes(s string) string { s += sixteenSpaces[:16-len(s)] return s } + +// architecture-independent object file output +const HeaderSize = 60 + +func ReadHeader(b *bufio.Reader, name string) int { + var buf [HeaderSize]byte + if _, err := io.ReadFull(b, buf[:]); err != nil { + return -1 + } + aname := strings.Trim(string(buf[0:16]), " ") + if !strings.HasPrefix(aname, name) { + return -1 + } + asize := strings.Trim(string(buf[48:58]), " ") + i, _ := strconv.Atoi(asize) + return i +} + +func FormatHeader(arhdr []byte, name string, size int64) { + copy(arhdr[:], fmt.Sprintf("%-16s%-12d%-6d%-6d%-8o%-10d`\n", name, 0, 0, 0, 0644, size)) +} -- cgit v1.3-5-g9baa From c3b4c7093ac46431b6e15cf1979bd9a251a400da Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Wed, 23 Dec 2020 17:33:18 -0500 Subject: cmd/internal/objfile: don't require runtime.symtab symbol for XCOFF For some reason (that I didn't look into), externally linked AIX binaries don't have runtime.symtab symbol. Since recent Go releases (Go 1.3 maybe?), that symbol is empty and not necessary anyway. Don't require it. Fixes #40972. Change-Id: I73a1f0142195ea6debdba8a4f6e12cadc3980dc5 Reviewed-on: https://go-review.googlesource.com/c/go/+/279995 Trust: Cherry Zhang Reviewed-by: Than McIntosh --- src/cmd/internal/objfile/xcoff.go | 4 +--- src/cmd/objdump/objdump_test.go | 5 ----- 2 files changed, 1 insertion(+), 8 deletions(-) (limited to 'src/cmd/internal') diff --git a/src/cmd/internal/objfile/xcoff.go b/src/cmd/internal/objfile/xcoff.go index d438c80226..d6df4db8f0 100644 --- a/src/cmd/internal/objfile/xcoff.go +++ b/src/cmd/internal/objfile/xcoff.go @@ -94,9 +94,7 @@ func (f *xcoffFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) if pclntab, err = loadXCOFFTable(f.xcoff, "runtime.pclntab", "runtime.epclntab"); err != nil { return 0, nil, nil, err } - if symtab, err = loadXCOFFTable(f.xcoff, "runtime.symtab", "runtime.esymtab"); err != nil { - return 0, nil, nil, err - } + symtab, _ = loadXCOFFTable(f.xcoff, "runtime.symtab", "runtime.esymtab") // ignore error, this symbol is not useful anyway return textStart, symtab, pclntab, nil } diff --git a/src/cmd/objdump/objdump_test.go b/src/cmd/objdump/objdump_test.go index edaca774f7..1748e13a53 100644 --- a/src/cmd/objdump/objdump_test.go +++ b/src/cmd/objdump/objdump_test.go @@ -237,9 +237,6 @@ func testGoAndCgoDisasm(t *testing.T, printCode bool, printGnuAsm bool) { t.Parallel() testDisasm(t, "fmthello.go", printCode, printGnuAsm) if build.Default.CgoEnabled { - if runtime.GOOS == "aix" { - return // issue 40972 - } testDisasm(t, "fmthellocgo.go", printCode, printGnuAsm) } } @@ -261,8 +258,6 @@ func TestDisasmExtld(t *testing.T) { switch runtime.GOOS { case "plan9", "windows": t.Skipf("skipping on %s", runtime.GOOS) - case "aix": - t.Skipf("skipping on AIX, see issue 40972") } t.Parallel() testDisasm(t, "fmthello.go", false, false, "-ldflags=-linkmode=external") -- cgit v1.3-5-g9baa From c1370e918fd88a13f77a133f8e431197cd3a1fc6 Mon Sep 17 00:00:00 2001 From: David Chase Date: Mon, 28 Sep 2020 17:42:30 -0400 Subject: [dev.regabi] cmd/compile: add code to support register ABI spills around morestack calls This is a selected copy from the register ABI experiment CL, focused on the files and data structures that handle spilling around morestack. Unnecessary code from the experiment was removed, other code was adapted. Would it make sense to leave comments in the experiment as pieces are brought over? Experiment CL (for comparison purposes) https://go-review.googlesource.com/c/go/+/28832 Change-Id: I92136f070351d4fcca1407b52ecf9b80898fed95 Reviewed-on: https://go-review.googlesource.com/c/go/+/279520 Trust: David Chase Run-TryBot: David Chase TryBot-Result: Go Bot Reviewed-by: Jeremy Faller --- src/cmd/compile/internal/ssa/func.go | 3 +++ src/cmd/compile/internal/ssa/location.go | 26 +++++++++++++++++++ src/cmd/internal/obj/link.go | 44 +++++++++++++++++++++++++++++--- src/cmd/internal/obj/x86/obj6.go | 10 +++++--- 4 files changed, 76 insertions(+), 7 deletions(-) (limited to 'src/cmd/internal') diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go index e6c4798a78..f753b4407b 100644 --- a/src/cmd/compile/internal/ssa/func.go +++ b/src/cmd/compile/internal/ssa/func.go @@ -58,6 +58,9 @@ type Func struct { // of keys to make iteration order deterministic. Names []LocalSlot + // RegArgs is a slice of register-memory pairs that must be spilled and unspilled in the uncommon path of function entry. + RegArgs []ArgPair + // WBLoads is a list of Blocks that branch on the write // barrier flag. Safe-points are disabled from the OpLoad that // reads the write-barrier flag until the control flow rejoins diff --git a/src/cmd/compile/internal/ssa/location.go b/src/cmd/compile/internal/ssa/location.go index 69f90d9ab4..4cd0ac8d77 100644 --- a/src/cmd/compile/internal/ssa/location.go +++ b/src/cmd/compile/internal/ssa/location.go @@ -87,3 +87,29 @@ func (t LocPair) String() string { } return fmt.Sprintf("<%s,%s>", n0, n1) } + +type ArgPair struct { + reg *Register + mem LocalSlot +} + +func (ap *ArgPair) Reg() int16 { + return ap.reg.objNum +} + +func (ap *ArgPair) Type() *types.Type { + return ap.mem.Type +} + +func (ap *ArgPair) Mem() *LocalSlot { + return &ap.mem +} + +func (t ArgPair) String() string { + n0 := "nil" + if t.reg != nil { + n0 = t.reg.String() + } + n1 := t.mem.String() + return fmt.Sprintf("<%s,%s>", n0, n1) +} diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go index 977c5c3303..7ba8c6d317 100644 --- a/src/cmd/internal/obj/link.go +++ b/src/cmd/internal/obj/link.go @@ -766,6 +766,17 @@ type Auto struct { Gotype *LSym } +// RegArg provides spill/fill information for a register-resident argument +// to a function. These need spilling/filling in the safepoint/stackgrowth case. +// At the time of fill/spill, the offset must be adjusted by the architecture-dependent +// adjustment to hardware SP that occurs in a call instruction. E.g., for AMD64, +// at Offset+8 because the return address was pushed. +type RegArg struct { + Addr Addr + Reg int16 + Spill, Unspill As +} + // Link holds the context for writing object code from a compiler // to be linker input or for reading that input into the linker. type Link struct { @@ -796,10 +807,11 @@ type Link struct { DebugInfo func(fn *LSym, info *LSym, curfn interface{}) ([]dwarf.Scope, dwarf.InlCalls) // if non-nil, curfn is a *gc.Node GenAbstractFunc func(fn *LSym) Errors int + RegArgs []RegArg - InParallel bool // parallel backend phase in effect - UseBASEntries bool // use Base Address Selection Entries in location lists and PC ranges - IsAsm bool // is the source assembly language, which may contain surprising idioms (e.g., call tables) + InParallel bool // parallel backend phase in effect + UseBASEntries bool // use Base Address Selection Entries in location lists and PC ranges + IsAsm bool // is the source assembly language, which may contain surprising idioms (e.g., call tables) // state for writing objects Text []*LSym @@ -844,6 +856,32 @@ func (ctxt *Link) Logf(format string, args ...interface{}) { ctxt.Bso.Flush() } +func (ctxt *Link) SpillRegisterArgs(last *Prog, pa ProgAlloc) *Prog { + // Spill register args. + for _, ra := range ctxt.RegArgs { + spill := Appendp(last, pa) + spill.As = ra.Spill + spill.From.Type = TYPE_REG + spill.From.Reg = ra.Reg + spill.To = ra.Addr + last = spill + } + return last +} + +func (ctxt *Link) UnspillRegisterArgs(last *Prog, pa ProgAlloc) *Prog { + // Unspill any spilled register args + for _, ra := range ctxt.RegArgs { + unspill := Appendp(last, pa) + unspill.As = ra.Unspill + unspill.From = ra.Addr + unspill.To.Type = TYPE_REG + unspill.To.Reg = ra.Reg + last = unspill + } + return last +} + // The smallest possible offset from the hardware stack pointer to a local // variable on the stack. Architectures that use a link register save its value // on the stack in the function prologue and so always have a pointer between diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go index 839aeb8fe3..1674db626f 100644 --- a/src/cmd/internal/obj/x86/obj6.go +++ b/src/cmd/internal/obj/x86/obj6.go @@ -1114,7 +1114,8 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA spfix.Spadj = -framesize pcdata := ctxt.EmitEntryStackMap(cursym, spfix, newprog) - pcdata = ctxt.StartUnsafePoint(pcdata, newprog) + spill := ctxt.StartUnsafePoint(pcdata, newprog) + pcdata = ctxt.SpillRegisterArgs(spill, newprog) call := obj.Appendp(pcdata, newprog) call.Pos = cursym.Func().Text.Pos @@ -1139,7 +1140,8 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA progedit(ctxt, callend.Link, newprog) } - pcdata = ctxt.EndUnsafePoint(callend, newprog, -1) + pcdata = ctxt.UnspillRegisterArgs(callend, newprog) + pcdata = ctxt.EndUnsafePoint(pcdata, newprog, -1) jmp := obj.Appendp(pcdata, newprog) jmp.As = obj.AJMP @@ -1147,9 +1149,9 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA jmp.To.SetTarget(cursym.Func().Text.Link) jmp.Spadj = +framesize - jls.To.SetTarget(call) + jls.To.SetTarget(spill) if q1 != nil { - q1.To.SetTarget(call) + q1.To.SetTarget(spill) } return end -- cgit v1.3-5-g9baa From a956a0e909e1d60c8d55339e5e591a9d1db885c4 Mon Sep 17 00:00:00 2001 From: Dan Scales Date: Fri, 15 Jan 2021 14:12:35 -0800 Subject: [dev.regabi] cmd/compile, runtime: fix up comments/error messages from recent renames Went in a semi-automated way through the clearest renames of functions, and updated comments and error messages where it made sense. Change-Id: Ied8e152b562b705da7f52f715991a77dab60da35 Reviewed-on: https://go-review.googlesource.com/c/go/+/284216 Trust: Dan Scales Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/asm/internal/asm/parse.go | 2 +- src/cmd/compile/internal/base/flag.go | 2 +- src/cmd/compile/internal/base/print.go | 2 +- src/cmd/compile/internal/bitvec/bv.go | 2 +- src/cmd/compile/internal/escape/escape.go | 4 +-- src/cmd/compile/internal/gc/compile.go | 2 +- src/cmd/compile/internal/gc/main.go | 8 ++--- src/cmd/compile/internal/gc/obj.go | 2 +- src/cmd/compile/internal/inline/inl.go | 10 +++--- src/cmd/compile/internal/ir/const.go | 2 +- src/cmd/compile/internal/ir/func.go | 2 +- src/cmd/compile/internal/ir/stmt.go | 4 +-- src/cmd/compile/internal/liveness/bvset.go | 2 +- src/cmd/compile/internal/liveness/plive.go | 2 +- src/cmd/compile/internal/noder/import.go | 2 +- src/cmd/compile/internal/noder/noder.go | 8 ++--- src/cmd/compile/internal/objw/prog.go | 2 +- src/cmd/compile/internal/pkginit/init.go | 4 +-- src/cmd/compile/internal/reflectdata/alg.go | 2 +- src/cmd/compile/internal/reflectdata/reflect.go | 20 +++++------ src/cmd/compile/internal/ssagen/abi.go | 2 +- src/cmd/compile/internal/ssagen/nowb.go | 4 +-- src/cmd/compile/internal/ssagen/pgen.go | 2 +- src/cmd/compile/internal/ssagen/ssa.go | 8 ++--- src/cmd/compile/internal/staticdata/data.go | 30 ++++++++-------- src/cmd/compile/internal/staticdata/embed.go | 2 +- src/cmd/compile/internal/staticinit/sched.go | 2 +- src/cmd/compile/internal/test/abiutilsaux_test.go | 2 +- .../test/testdata/reproducible/issue38068.go | 2 +- src/cmd/compile/internal/typebits/typebits.go | 12 +++---- src/cmd/compile/internal/typecheck/const.go | 2 +- src/cmd/compile/internal/typecheck/dcl.go | 12 +++---- src/cmd/compile/internal/typecheck/expr.go | 6 ++-- src/cmd/compile/internal/typecheck/func.go | 20 +++++------ src/cmd/compile/internal/typecheck/iimport.go | 4 +-- src/cmd/compile/internal/typecheck/stmt.go | 8 ++--- src/cmd/compile/internal/typecheck/subr.go | 10 +++--- src/cmd/compile/internal/typecheck/syms.go | 4 +-- src/cmd/compile/internal/typecheck/typecheck.go | 8 ++--- src/cmd/compile/internal/types/alg.go | 4 +-- src/cmd/compile/internal/types/fmt.go | 2 +- src/cmd/compile/internal/types/size.go | 41 +++++++++++----------- src/cmd/compile/internal/types/type.go | 4 +-- src/cmd/compile/internal/walk/builtin.go | 6 ++-- src/cmd/compile/internal/walk/closure.go | 2 +- src/cmd/compile/internal/walk/compare.go | 4 +-- src/cmd/compile/internal/walk/convert.go | 4 +-- src/cmd/compile/internal/walk/expr.go | 14 ++++---- src/cmd/compile/internal/walk/order.go | 6 ++-- src/cmd/compile/internal/walk/range.go | 8 ++--- src/cmd/compile/internal/walk/select.go | 4 +-- src/cmd/compile/internal/walk/switch.go | 4 +-- src/cmd/compile/internal/walk/walk.go | 10 +++--- src/cmd/internal/goobj/mkbuiltin.go | 4 +-- src/cmd/internal/obj/textflag.go | 2 +- src/embed/embed.go | 4 +-- src/reflect/type.go | 2 +- src/runtime/runtime2.go | 2 +- src/runtime/type.go | 2 +- 59 files changed, 176 insertions(+), 177 deletions(-) (limited to 'src/cmd/internal') diff --git a/src/cmd/asm/internal/asm/parse.go b/src/cmd/asm/internal/asm/parse.go index 154cf9c7a7..f1d37bc2c8 100644 --- a/src/cmd/asm/internal/asm/parse.go +++ b/src/cmd/asm/internal/asm/parse.go @@ -305,7 +305,7 @@ func (p *Parser) pseudo(word string, operands [][]lex.Token) bool { // references and writes symabis information to w. // // The symabis format is documented at -// cmd/compile/internal/gc.readSymABIs. +// cmd/compile/internal/ssagen.ReadSymABIs. func (p *Parser) symDefRef(w io.Writer, word string, operands [][]lex.Token) { switch word { case "TEXT": diff --git a/src/cmd/compile/internal/base/flag.go b/src/cmd/compile/internal/base/flag.go index d35b8452f9..c38bbe6272 100644 --- a/src/cmd/compile/internal/base/flag.go +++ b/src/cmd/compile/internal/base/flag.go @@ -174,7 +174,7 @@ func ParseFlags() { if (*Flag.Shared || *Flag.Dynlink || *Flag.LinkShared) && !Ctxt.Arch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.I386, sys.PPC64, sys.RISCV64, sys.S390X) { log.Fatalf("%s/%s does not support -shared", objabi.GOOS, objabi.GOARCH) } - parseSpectre(Flag.Spectre) // left as string for recordFlags + parseSpectre(Flag.Spectre) // left as string for RecordFlags Ctxt.Flag_shared = Ctxt.Flag_dynlink || Ctxt.Flag_shared Ctxt.Flag_optimize = Flag.N == 0 diff --git a/src/cmd/compile/internal/base/print.go b/src/cmd/compile/internal/base/print.go index 9855dfdad0..668c600d31 100644 --- a/src/cmd/compile/internal/base/print.go +++ b/src/cmd/compile/internal/base/print.go @@ -121,7 +121,7 @@ func ErrorfAt(pos src.XPos, format string, args ...interface{}) { lasterror.syntax = pos } else { // only one of multiple equal non-syntax errors per line - // (flusherrors shows only one of them, so we filter them + // (FlushErrors shows only one of them, so we filter them // here as best as we can (they may not appear in order) // so that we don't count them here and exit early, and // then have nothing to show for.) diff --git a/src/cmd/compile/internal/bitvec/bv.go b/src/cmd/compile/internal/bitvec/bv.go index 1e084576d1..bcac1fe351 100644 --- a/src/cmd/compile/internal/bitvec/bv.go +++ b/src/cmd/compile/internal/bitvec/bv.go @@ -37,7 +37,7 @@ func NewBulk(nbit int32, count int32) Bulk { nword := (nbit + wordBits - 1) / wordBits size := int64(nword) * int64(count) if int64(int32(size*4)) != size*4 { - base.Fatalf("bvbulkalloc too big: nbit=%d count=%d nword=%d size=%d", nbit, count, nword, size) + base.Fatalf("NewBulk too big: nbit=%d count=%d nword=%d size=%d", nbit, count, nword, size) } return Bulk{ words: make([]uint32, size), diff --git a/src/cmd/compile/internal/escape/escape.go b/src/cmd/compile/internal/escape/escape.go index 79e5a98c91..96c2e02146 100644 --- a/src/cmd/compile/internal/escape/escape.go +++ b/src/cmd/compile/internal/escape/escape.go @@ -856,7 +856,7 @@ func (e *escape) discards(l ir.Nodes) { } } -// addr evaluates an addressable expression n and returns an EscHole +// addr evaluates an addressable expression n and returns a hole // that represents storing into the represented location. func (e *escape) addr(n ir.Node) hole { if n == nil || ir.IsBlank(n) { @@ -1785,7 +1785,7 @@ func (l leaks) Encode() string { return s } -// parseLeaks parses a binary string representing an EscLeaks. +// parseLeaks parses a binary string representing a leaks func parseLeaks(s string) leaks { var l leaks if !strings.HasPrefix(s, "esc:") { diff --git a/src/cmd/compile/internal/gc/compile.go b/src/cmd/compile/internal/gc/compile.go index 6e347bf0f1..ba67c58c45 100644 --- a/src/cmd/compile/internal/gc/compile.go +++ b/src/cmd/compile/internal/gc/compile.go @@ -72,7 +72,7 @@ func enqueueFunc(fn *ir.Func) { func prepareFunc(fn *ir.Func) { // Set up the function's LSym early to avoid data races with the assemblers. // Do this before walk, as walk needs the LSym to set attributes/relocations - // (e.g. in markTypeUsedInInterface). + // (e.g. in MarkTypeUsedInInterface). ssagen.InitLSym(fn, true) // Calculate parameter offsets. diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index 9ecdd510b1..e9ac243527 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -121,7 +121,7 @@ func Main(archInit func(*ssagen.ArchInfo)) { log.Fatalf("compiler not built with support for -t") } - // Enable inlining (after recordFlags, to avoid recording the rewritten -l). For now: + // Enable inlining (after RecordFlags, to avoid recording the rewritten -l). For now: // default: inlining on. (Flag.LowerL == 1) // -l: inlining off (Flag.LowerL == 0) // -l=2, -l=3: inlining on again, with extra debugging (Flag.LowerL > 1) @@ -193,7 +193,7 @@ func Main(archInit func(*ssagen.ArchInfo)) { typecheck.Target = new(ir.Package) typecheck.NeedITab = func(t, iface *types.Type) { reflectdata.ITabAddr(t, iface) } - typecheck.NeedRuntimeType = reflectdata.NeedRuntimeType // TODO(rsc): typenamesym for lock? + typecheck.NeedRuntimeType = reflectdata.NeedRuntimeType // TODO(rsc): TypeSym for lock? base.AutogeneratedPos = makePos(src.NewFileBase("", ""), 1, 0) @@ -261,7 +261,7 @@ func Main(archInit func(*ssagen.ArchInfo)) { escape.Funcs(typecheck.Target.Decls) // Collect information for go:nowritebarrierrec - // checking. This must happen before transformclosure. + // checking. This must happen before transforming closures during Walk // We'll do the final check after write barriers are // inserted. if base.Flag.CompilingRuntime { @@ -269,7 +269,7 @@ func Main(archInit func(*ssagen.ArchInfo)) { } // Prepare for SSA compilation. - // This must be before peekitabs, because peekitabs + // This must be before CompileITabs, because CompileITabs // can trigger function compilation. typecheck.InitRuntime() ssagen.InitConfig() diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go index 3e55b7688e..847d849666 100644 --- a/src/cmd/compile/internal/gc/obj.go +++ b/src/cmd/compile/internal/gc/obj.go @@ -121,7 +121,7 @@ func dumpdata() { reflectdata.WriteBasicTypes() dumpembeds() - // Calls to dumpsignats can generate functions, + // Calls to WriteRuntimeTypes can generate functions, // like method wrappers and hash and equality routines. // Compile any generated functions, process any new resulting types, repeat. // This can't loop forever, because there is no way to generate an infinite diff --git a/src/cmd/compile/internal/inline/inl.go b/src/cmd/compile/internal/inline/inl.go index 1811feebe9..4bb849cdae 100644 --- a/src/cmd/compile/internal/inline/inl.go +++ b/src/cmd/compile/internal/inline/inl.go @@ -4,7 +4,7 @@ // // The inlining facility makes 2 passes: first caninl determines which // functions are suitable for inlining, and for those that are it -// saves a copy of the body. Then inlcalls walks each function body to +// saves a copy of the body. Then InlineCalls walks each function body to // expand calls to inlinable functions. // // The Debug.l flag controls the aggressiveness. Note that main() swaps level 0 and 1, @@ -79,7 +79,7 @@ func InlinePackage() { // fn and ->nbody will already have been typechecked. func CanInline(fn *ir.Func) { if fn.Nname == nil { - base.Fatalf("caninl no nname %+v", fn) + base.Fatalf("CanInline no nname %+v", fn) } var reason string // reason, if any, that the function was not inlined @@ -144,7 +144,7 @@ func CanInline(fn *ir.Func) { } if fn.Typecheck() == 0 { - base.Fatalf("caninl on non-typechecked function %v", fn) + base.Fatalf("CanInline on non-typechecked function %v", fn) } n := fn.Nname @@ -200,11 +200,11 @@ func Inline_Flood(n *ir.Name, exportsym func(*ir.Name)) { return } if n.Op() != ir.ONAME || n.Class != ir.PFUNC { - base.Fatalf("inlFlood: unexpected %v, %v, %v", n, n.Op(), n.Class) + base.Fatalf("Inline_Flood: unexpected %v, %v, %v", n, n.Op(), n.Class) } fn := n.Func if fn == nil { - base.Fatalf("inlFlood: missing Func on %v", n) + base.Fatalf("Inline_Flood: missing Func on %v", n) } if fn.Inl == nil { return diff --git a/src/cmd/compile/internal/ir/const.go b/src/cmd/compile/internal/ir/const.go index bfa0136232..eaa4d5b6b1 100644 --- a/src/cmd/compile/internal/ir/const.go +++ b/src/cmd/compile/internal/ir/const.go @@ -77,7 +77,7 @@ func ConstOverflow(v constant.Value, t *types.Type) bool { ft := types.FloatForComplex(t) return ConstOverflow(constant.Real(v), ft) || ConstOverflow(constant.Imag(v), ft) } - base.Fatalf("doesoverflow: %v, %v", v, t) + base.Fatalf("ConstOverflow: %v, %v", v, t) panic("unreachable") } diff --git a/src/cmd/compile/internal/ir/func.go b/src/cmd/compile/internal/ir/func.go index 30cddd298e..4afdadf57b 100644 --- a/src/cmd/compile/internal/ir/func.go +++ b/src/cmd/compile/internal/ir/func.go @@ -63,7 +63,7 @@ type Func struct { Exit Nodes // ONAME nodes for all params/locals for this func/closure, does NOT - // include closurevars until transformclosure runs. + // include closurevars until transforming closures during walk. // Names must be listed PPARAMs, PPARAMOUTs, then PAUTOs, // with PPARAMs and PPARAMOUTs in order corresponding to the function signature. // However, as anonymous or blank PPARAMs are not actually declared, diff --git a/src/cmd/compile/internal/ir/stmt.go b/src/cmd/compile/internal/ir/stmt.go index b13c6b7795..4e4c0df993 100644 --- a/src/cmd/compile/internal/ir/stmt.go +++ b/src/cmd/compile/internal/ir/stmt.go @@ -343,7 +343,7 @@ type SelectStmt struct { HasBreak bool // TODO(rsc): Instead of recording here, replace with a block? - Compiled Nodes // compiled form, after walkswitch + Compiled Nodes // compiled form, after walkSwitch } func NewSelectStmt(pos src.XPos, cases []*CommClause) *SelectStmt { @@ -376,7 +376,7 @@ type SwitchStmt struct { HasBreak bool // TODO(rsc): Instead of recording here, replace with a block? - Compiled Nodes // compiled form, after walkswitch + Compiled Nodes // compiled form, after walkSwitch } func NewSwitchStmt(pos src.XPos, tag Node, cases []*CaseClause) *SwitchStmt { diff --git a/src/cmd/compile/internal/liveness/bvset.go b/src/cmd/compile/internal/liveness/bvset.go index 21bc1fee4d..3431f54ede 100644 --- a/src/cmd/compile/internal/liveness/bvset.go +++ b/src/cmd/compile/internal/liveness/bvset.go @@ -47,7 +47,7 @@ func (m *bvecSet) grow() { m.index = newIndex } -// add adds bv to the set and returns its index in m.extractUniqe. +// add adds bv to the set and returns its index in m.extractUnique. // The caller must not modify bv after this. func (m *bvecSet) add(bv bitvec.BitVec) int { if len(m.uniq)*4 >= len(m.index) { diff --git a/src/cmd/compile/internal/liveness/plive.go b/src/cmd/compile/internal/liveness/plive.go index abc9583d5a..c70db6ed18 100644 --- a/src/cmd/compile/internal/liveness/plive.go +++ b/src/cmd/compile/internal/liveness/plive.go @@ -1060,7 +1060,7 @@ func (lv *liveness) printDebug() { func (lv *liveness) emit() (argsSym, liveSym *obj.LSym) { // Size args bitmaps to be just large enough to hold the largest pointer. // First, find the largest Xoffset node we care about. - // (Nodes without pointers aren't in lv.vars; see livenessShouldTrack.) + // (Nodes without pointers aren't in lv.vars; see ShouldTrack.) var maxArgNode *ir.Name for _, n := range lv.vars { switch n.Class { diff --git a/src/cmd/compile/internal/noder/import.go b/src/cmd/compile/internal/noder/import.go index 08f19a4028..ca041a156c 100644 --- a/src/cmd/compile/internal/noder/import.go +++ b/src/cmd/compile/internal/noder/import.go @@ -418,7 +418,7 @@ func clearImports() { if types.IsDotAlias(s) { // throw away top-level name left over // from previous import . "x" - // We'll report errors after type checking in checkDotImports. + // We'll report errors after type checking in CheckDotImports. s.Def = nil continue } diff --git a/src/cmd/compile/internal/noder/noder.go b/src/cmd/compile/internal/noder/noder.go index edd30a1fc1..99c0e4adde 100644 --- a/src/cmd/compile/internal/noder/noder.go +++ b/src/cmd/compile/internal/noder/noder.go @@ -86,7 +86,7 @@ func ParseFiles(filenames []string) uint { if base.SyntaxErrors() != 0 { base.ErrorExit() } - // Always run testdclstack here, even when debug_dclstack is not set, as a sanity measure. + // Always run CheckDclstack here, even when debug_dclstack is not set, as a sanity measure. types.CheckDclstack() } @@ -638,7 +638,7 @@ func (p *noder) funcDecl(fun *syntax.FuncDecl) ir.Node { } } else { f.Shortname = name - name = ir.BlankNode.Sym() // filled in by typecheckfunc + name = ir.BlankNode.Sym() // filled in by tcFunc } f.Nname = ir.NewNameAt(p.pos(fun.Name), name) @@ -1084,7 +1084,7 @@ func (p *noder) stmtsFall(stmts []syntax.Stmt, fallOK bool) []ir.Node { if s == nil { } else if s.Op() == ir.OBLOCK && len(s.(*ir.BlockStmt).List) > 0 { // Inline non-empty block. - // Empty blocks must be preserved for checkreturn. + // Empty blocks must be preserved for CheckReturn. nodes = append(nodes, s.(*ir.BlockStmt).List...) } else { nodes = append(nodes, s) @@ -1860,7 +1860,7 @@ func (p *noder) funcLit(expr *syntax.FuncLit) ir.Node { fn := ir.NewFunc(p.pos(expr)) fn.SetIsHiddenClosure(ir.CurFunc != nil) - fn.Nname = ir.NewNameAt(p.pos(expr), ir.BlankNode.Sym()) // filled in by typecheckclosure + fn.Nname = ir.NewNameAt(p.pos(expr), ir.BlankNode.Sym()) // filled in by tcClosure fn.Nname.Func = fn fn.Nname.Ntype = xtype fn.Nname.Defn = fn diff --git a/src/cmd/compile/internal/objw/prog.go b/src/cmd/compile/internal/objw/prog.go index 8d24f94aa5..b5ac4dda1e 100644 --- a/src/cmd/compile/internal/objw/prog.go +++ b/src/cmd/compile/internal/objw/prog.go @@ -205,7 +205,7 @@ func (pp *Progs) Append(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int16, func (pp *Progs) SetText(fn *ir.Func) { if pp.Text != nil { - base.Fatalf("Progs.settext called twice") + base.Fatalf("Progs.SetText called twice") } ptxt := pp.Prog(obj.ATEXT) pp.Text = ptxt diff --git a/src/cmd/compile/internal/pkginit/init.go b/src/cmd/compile/internal/pkginit/init.go index 5bc66c7e1b..7cad262214 100644 --- a/src/cmd/compile/internal/pkginit/init.go +++ b/src/cmd/compile/internal/pkginit/init.go @@ -60,10 +60,10 @@ func Task() *ir.Name { fns = append(fns, fn.Linksym()) } if typecheck.InitTodoFunc.Dcl != nil { - // We only generate temps using initTodo if there + // We only generate temps using InitTodoFunc if there // are package-scope initialization statements, so // something's weird if we get here. - base.Fatalf("initTodo still has declarations") + base.Fatalf("InitTodoFunc still has declarations") } typecheck.InitTodoFunc = nil diff --git a/src/cmd/compile/internal/reflectdata/alg.go b/src/cmd/compile/internal/reflectdata/alg.go index d576053753..fcd824f164 100644 --- a/src/cmd/compile/internal/reflectdata/alg.go +++ b/src/cmd/compile/internal/reflectdata/alg.go @@ -689,7 +689,7 @@ func EqString(s, t ir.Node) (eqlen *ir.BinaryExpr, eqmem *ir.CallExpr) { // eqtab must be evaluated before eqdata, and shortcircuiting is required. func EqInterface(s, t ir.Node) (eqtab *ir.BinaryExpr, eqdata *ir.CallExpr) { if !types.Identical(s.Type(), t.Type()) { - base.Fatalf("eqinterface %v %v", s.Type(), t.Type()) + base.Fatalf("EqInterface %v %v", s.Type(), t.Type()) } // func ifaceeq(tab *uintptr, x, y unsafe.Pointer) (ret bool) // func efaceeq(typ *uintptr, x, y unsafe.Pointer) (ret bool) diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index 989bcf9ab9..efe863cc3f 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -32,7 +32,7 @@ type itabEntry struct { // symbols of each method in // the itab, sorted by byte offset; - // filled in by peekitabs + // filled in by CompileITabs entries []*obj.LSym } @@ -401,7 +401,7 @@ func dimportpath(p *types.Pkg) { } // If we are compiling the runtime package, there are two runtime packages around - // -- localpkg and Runtimepkg. We don't want to produce import path symbols for + // -- localpkg and Pkgs.Runtime. We don't want to produce import path symbols for // both of them, so just produce one for localpkg. if base.Ctxt.Pkgpath == "runtime" && p == ir.Pkgs.Runtime { return @@ -811,7 +811,7 @@ func TypeSymPrefix(prefix string, t *types.Type) *types.Sym { func TypeSym(t *types.Type) *types.Sym { if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() { - base.Fatalf("typenamesym %v", t) + base.Fatalf("TypeSym %v", t) } if t.Kind() == types.TFUNC && t.Recv() != nil { base.Fatalf("misuse of method type: %v", t) @@ -853,7 +853,7 @@ func TypePtr(t *types.Type) *ir.AddrExpr { func ITabAddr(t, itype *types.Type) *ir.AddrExpr { if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() || !itype.IsInterface() || itype.IsEmptyInterface() { - base.Fatalf("itabname(%v, %v)", t, itype) + base.Fatalf("ITabAddr(%v, %v)", t, itype) } s := ir.Pkgs.Itab.Lookup(t.ShortString() + "," + itype.ShortString()) if s.Def == nil { @@ -936,7 +936,7 @@ func formalType(t *types.Type) *types.Type { func writeType(t *types.Type) *obj.LSym { t = formalType(t) if t.IsUntyped() { - base.Fatalf("dtypesym %v", t) + base.Fatalf("writeType %v", t) } s := types.TypeSym(t) @@ -1275,7 +1275,7 @@ func genfun(t, it *types.Type) []*obj.LSym { } // ITabSym uses the information gathered in -// peekitabs to de-virtualize interface methods. +// CompileITabs to de-virtualize interface methods. // Since this is called by the SSA backend, it shouldn't // generate additional Nodes, Syms, etc. func ITabSym(it *obj.LSym, offset int64) *obj.LSym { @@ -1312,7 +1312,7 @@ func NeedRuntimeType(t *types.Type) { } func WriteRuntimeTypes() { - // Process signatset. Use a loop, as dtypesym adds + // Process signatset. Use a loop, as writeType adds // entries to signatset while it is being processed. signats := make([]typeAndStr, len(signatslice)) for len(signatslice) > 0 { @@ -1617,13 +1617,13 @@ func (p *gcProg) emit(t *types.Type, offset int64) { } switch t.Kind() { default: - base.Fatalf("GCProg.emit: unexpected type %v", t) + base.Fatalf("gcProg.emit: unexpected type %v", t) case types.TSTRING: p.w.Ptr(offset / int64(types.PtrSize)) case types.TINTER: - // Note: the first word isn't a pointer. See comment in plive.go:onebitwalktype1. + // Note: the first word isn't a pointer. See comment in typebits.Set p.w.Ptr(offset/int64(types.PtrSize) + 1) case types.TSLICE: @@ -1632,7 +1632,7 @@ func (p *gcProg) emit(t *types.Type, offset int64) { case types.TARRAY: if t.NumElem() == 0 { // should have been handled by haspointers check above - base.Fatalf("GCProg.emit: empty array") + base.Fatalf("gcProg.emit: empty array") } // Flatten array-of-array-of-array to just a big array by multiplying counts. diff --git a/src/cmd/compile/internal/ssagen/abi.go b/src/cmd/compile/internal/ssagen/abi.go index 7ff8e21a48..274c543ca5 100644 --- a/src/cmd/compile/internal/ssagen/abi.go +++ b/src/cmd/compile/internal/ssagen/abi.go @@ -154,7 +154,7 @@ func InitLSym(f *ir.Func, hasBody bool) { // makes calls to helpers to create ABI wrappers if needed. func selectLSym(f *ir.Func, hasBody bool) { if f.LSym != nil { - base.FatalfAt(f.Pos(), "Func.initLSym called twice on %v", f) + base.FatalfAt(f.Pos(), "InitLSym called twice on %v", f) } if nam := f.Nname; !ir.IsBlank(nam) { diff --git a/src/cmd/compile/internal/ssagen/nowb.go b/src/cmd/compile/internal/ssagen/nowb.go index 60cfb2f698..a2434366a0 100644 --- a/src/cmd/compile/internal/ssagen/nowb.go +++ b/src/cmd/compile/internal/ssagen/nowb.go @@ -45,7 +45,7 @@ type nowritebarrierrecCall struct { } // newNowritebarrierrecChecker creates a nowritebarrierrecChecker. It -// must be called before transformclosure and walk. +// must be called before walk func newNowritebarrierrecChecker() *nowritebarrierrecChecker { c := &nowritebarrierrecChecker{ extraCalls: make(map[*ir.Func][]nowritebarrierrecCall), @@ -54,7 +54,7 @@ func newNowritebarrierrecChecker() *nowritebarrierrecChecker { // Find all systemstack calls and record their targets. In // general, flow analysis can't see into systemstack, but it's // important to handle it for this check, so we model it - // directly. This has to happen before transformclosure since + // directly. This has to happen before transforming closures in walk since // it's a lot harder to work out the argument after. for _, n := range typecheck.Target.Decls { if n.Op() != ir.ODCLFUNC { diff --git a/src/cmd/compile/internal/ssagen/pgen.go b/src/cmd/compile/internal/ssagen/pgen.go index bbd319d735..182f8408cf 100644 --- a/src/cmd/compile/internal/ssagen/pgen.go +++ b/src/cmd/compile/internal/ssagen/pgen.go @@ -96,7 +96,7 @@ func (s *ssafn) AllocFrame(f *ssa.Func) { if n, ok := v.Aux.(*ir.Name); ok { switch n.Class { case ir.PPARAM, ir.PPARAMOUT: - // Don't modify nodfp; it is a global. + // Don't modify RegFP; it is a global. if n != ir.RegFP { n.SetUsed(true) } diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 097cfacc23..7726ecac55 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -1508,10 +1508,10 @@ func (s *state) stmt(n ir.Node) { // Currently doesn't really work because (*p)[:len(*p)] appears here as: // tmp = len(*p) // (*p)[:tmp] - //if j != nil && (j.Op == OLEN && samesafeexpr(j.Left, n.Left)) { + //if j != nil && (j.Op == OLEN && SameSafeExpr(j.Left, n.Left)) { // j = nil //} - //if k != nil && (k.Op == OCAP && samesafeexpr(k.Left, n.Left)) { + //if k != nil && (k.Op == OCAP && SameSafeExpr(k.Left, n.Left)) { // k = nil //} if i == nil { @@ -6462,7 +6462,7 @@ func (s *State) DebugFriendlySetPosFrom(v *ssa.Value) { // in the generated code. if p.IsStmt() != src.PosIsStmt { p = p.WithNotStmt() - // Calls use the pos attached to v, but copy the statement mark from SSAGenState + // Calls use the pos attached to v, but copy the statement mark from State } s.SetPos(p) } else { @@ -7260,7 +7260,7 @@ func (e *ssafn) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot if n.Type().IsEmptyInterface() { f = ".type" } - c := e.SplitSlot(&name, f, 0, u) // see comment in plive.go:onebitwalktype1. + c := e.SplitSlot(&name, f, 0, u) // see comment in typebits.Set d := e.SplitSlot(&name, ".data", u.Size(), t) return c, d } diff --git a/src/cmd/compile/internal/staticdata/data.go b/src/cmd/compile/internal/staticdata/data.go index 4b12590fde..4dbc11c3c4 100644 --- a/src/cmd/compile/internal/staticdata/data.go +++ b/src/cmd/compile/internal/staticdata/data.go @@ -29,13 +29,13 @@ import ( // Neither n nor a is modified. func InitAddr(n *ir.Name, noff int64, a *ir.Name, aoff int64) { if n.Op() != ir.ONAME { - base.Fatalf("addrsym n op %v", n.Op()) + base.Fatalf("InitAddr n op %v", n.Op()) } if n.Sym() == nil { - base.Fatalf("addrsym nil n sym") + base.Fatalf("InitAddr nil n sym") } if a.Op() != ir.ONAME { - base.Fatalf("addrsym a op %v", a.Op()) + base.Fatalf("InitAddr a op %v", a.Op()) } s := n.Linksym() s.WriteAddr(base.Ctxt, noff, types.PtrSize, a.Linksym(), aoff) @@ -45,13 +45,13 @@ func InitAddr(n *ir.Name, noff int64, a *ir.Name, aoff int64) { // Neither n nor f is modified. func InitFunc(n *ir.Name, noff int64, f *ir.Name) { if n.Op() != ir.ONAME { - base.Fatalf("pfuncsym n op %v", n.Op()) + base.Fatalf("InitFunc n op %v", n.Op()) } if n.Sym() == nil { - base.Fatalf("pfuncsym nil n sym") + base.Fatalf("InitFunc nil n sym") } if f.Class != ir.PFUNC { - base.Fatalf("pfuncsym class not PFUNC %d", f.Class) + base.Fatalf("InitFunc class not PFUNC %d", f.Class) } s := n.Linksym() s.WriteAddr(base.Ctxt, noff, types.PtrSize, FuncLinksym(f), 0) @@ -62,7 +62,7 @@ func InitFunc(n *ir.Name, noff int64, f *ir.Name) { func InitSlice(n *ir.Name, noff int64, arr *ir.Name, lencap int64) { s := n.Linksym() if arr.Op() != ir.ONAME { - base.Fatalf("slicesym non-name arr %v", arr) + base.Fatalf("InitSlice non-name arr %v", arr) } s.WriteAddr(base.Ctxt, noff, types.PtrSize, arr.Linksym(), 0) s.WriteInt(base.Ctxt, noff+types.SliceLenOffset, types.PtrSize, lencap) @@ -71,7 +71,7 @@ func InitSlice(n *ir.Name, noff int64, arr *ir.Name, lencap int64) { func InitSliceBytes(nam *ir.Name, off int64, s string) { if nam.Op() != ir.ONAME { - base.Fatalf("slicebytes %v", nam) + base.Fatalf("InitSliceBytes %v", nam) } InitSlice(nam, off, slicedata(nam.Pos(), s), int64(len(s))) } @@ -243,14 +243,14 @@ func FuncSym(s *types.Sym) *types.Sym { // except for the types package, which is protected separately. // Reusing funcsymsmu to also cover this package lookup // avoids a general, broader, expensive package lookup mutex. - // Note makefuncsym also does package look-up of func sym names, + // Note NeedFuncSym also does package look-up of func sym names, // but that it is only called serially, from the front end. funcsymsmu.Lock() sf, existed := s.Pkg.LookupOK(ir.FuncSymName(s)) // Don't export s·f when compiling for dynamic linking. // When dynamically linking, the necessary function - // symbols will be created explicitly with makefuncsym. - // See the makefuncsym comment for details. + // symbols will be created explicitly with NeedFuncSym. + // See the NeedFuncSym comment for details. if !base.Ctxt.Flag_dynlink && !existed { funcsyms = append(funcsyms, s) } @@ -310,16 +310,16 @@ func WriteFuncSyms() { // Neither n nor c is modified. func InitConst(n *ir.Name, noff int64, c ir.Node, wid int) { if n.Op() != ir.ONAME { - base.Fatalf("litsym n op %v", n.Op()) + base.Fatalf("InitConst n op %v", n.Op()) } if n.Sym() == nil { - base.Fatalf("litsym nil n sym") + base.Fatalf("InitConst nil n sym") } if c.Op() == ir.ONIL { return } if c.Op() != ir.OLITERAL { - base.Fatalf("litsym c op %v", c.Op()) + base.Fatalf("InitConst c op %v", c.Op()) } s := n.Linksym() switch u := c.Val(); u.Kind() { @@ -358,6 +358,6 @@ func InitConst(n *ir.Name, noff int64, c ir.Node, wid int) { s.WriteInt(base.Ctxt, noff+int64(types.PtrSize), types.PtrSize, int64(len(i))) default: - base.Fatalf("litsym unhandled OLITERAL %v", c) + base.Fatalf("InitConst unhandled OLITERAL %v", c) } } diff --git a/src/cmd/compile/internal/staticdata/embed.go b/src/cmd/compile/internal/staticdata/embed.go index 2e551f0b2c..2e15841fe2 100644 --- a/src/cmd/compile/internal/staticdata/embed.go +++ b/src/cmd/compile/internal/staticdata/embed.go @@ -82,7 +82,7 @@ func embedKindApprox(typ ir.Node) int { // These are not guaranteed to match only string and []byte - // maybe the local package has redefined one of those words. // But it's the best we can do now during the noder. - // The stricter check happens later, in initEmbed calling embedKind. + // The stricter check happens later, in WriteEmbed calling embedKind. if typ.Sym() != nil && typ.Sym().Name == "string" && typ.Sym().Pkg == types.LocalPkg { return embedString } diff --git a/src/cmd/compile/internal/staticinit/sched.go b/src/cmd/compile/internal/staticinit/sched.go index 64946ad247..8c195742e6 100644 --- a/src/cmd/compile/internal/staticinit/sched.go +++ b/src/cmd/compile/internal/staticinit/sched.go @@ -455,7 +455,7 @@ var statuniqgen int // name generator for static temps // StaticName returns a name backed by a (writable) static data symbol. // Use readonlystaticname for read-only node. func StaticName(t *types.Type) *ir.Name { - // Don't use lookupN; it interns the resulting string, but these are all unique. + // Don't use LookupNum; it interns the resulting string, but these are all unique. n := typecheck.NewName(typecheck.Lookup(fmt.Sprintf("%s%d", obj.StaticNamePref, statuniqgen))) statuniqgen++ typecheck.Declare(n, ir.PEXTERN) diff --git a/src/cmd/compile/internal/test/abiutilsaux_test.go b/src/cmd/compile/internal/test/abiutilsaux_test.go index 7b84e73947..10fb668745 100644 --- a/src/cmd/compile/internal/test/abiutilsaux_test.go +++ b/src/cmd/compile/internal/test/abiutilsaux_test.go @@ -127,7 +127,7 @@ func abitest(t *testing.T, ft *types.Type, exp expectedDump) { emptyResString := emptyRes.String() // Walk the results and make sure the offsets assigned match - // up with those assiged by dowidth. This checks to make sure that + // up with those assiged by CalcSize. This checks to make sure that // when we have no available registers the ABI assignment degenerates // back to the original ABI0. diff --git a/src/cmd/compile/internal/test/testdata/reproducible/issue38068.go b/src/cmd/compile/internal/test/testdata/reproducible/issue38068.go index db5ca7dcbe..b87daed8e9 100644 --- a/src/cmd/compile/internal/test/testdata/reproducible/issue38068.go +++ b/src/cmd/compile/internal/test/testdata/reproducible/issue38068.go @@ -53,7 +53,7 @@ func G(x *A, n int) { return } // Address-taken local of type A, which will insure that the - // compiler's dtypesym() routine will create a method wrapper. + // compiler's writeType() routine will create a method wrapper. var a, b A a.next = x a.prev = &b diff --git a/src/cmd/compile/internal/typebits/typebits.go b/src/cmd/compile/internal/typebits/typebits.go index 63a2bb3ffa..1c1b077423 100644 --- a/src/cmd/compile/internal/typebits/typebits.go +++ b/src/cmd/compile/internal/typebits/typebits.go @@ -15,7 +15,7 @@ import ( // on future calls with the same type t. func Set(t *types.Type, off int64, bv bitvec.BitVec) { if t.Align > 0 && off&int64(t.Align-1) != 0 { - base.Fatalf("onebitwalktype1: invalid initial alignment: type %v has alignment %d, but offset is %v", t, t.Align, off) + base.Fatalf("typebits.Set: invalid initial alignment: type %v has alignment %d, but offset is %v", t, t.Align, off) } if !t.HasPointers() { // Note: this case ensures that pointers to go:notinheap types @@ -26,14 +26,14 @@ func Set(t *types.Type, off int64, bv bitvec.BitVec) { switch t.Kind() { case types.TPTR, types.TUNSAFEPTR, types.TFUNC, types.TCHAN, types.TMAP: if off&int64(types.PtrSize-1) != 0 { - base.Fatalf("onebitwalktype1: invalid alignment, %v", t) + base.Fatalf("typebits.Set: invalid alignment, %v", t) } bv.Set(int32(off / int64(types.PtrSize))) // pointer case types.TSTRING: // struct { byte *str; intgo len; } if off&int64(types.PtrSize-1) != 0 { - base.Fatalf("onebitwalktype1: invalid alignment, %v", t) + base.Fatalf("typebits.Set: invalid alignment, %v", t) } bv.Set(int32(off / int64(types.PtrSize))) //pointer in first slot @@ -42,7 +42,7 @@ func Set(t *types.Type, off int64, bv bitvec.BitVec) { // or, when isnilinter(t)==true: // struct { Type *type; void *data; } if off&int64(types.PtrSize-1) != 0 { - base.Fatalf("onebitwalktype1: invalid alignment, %v", t) + base.Fatalf("typebits.Set: invalid alignment, %v", t) } // The first word of an interface is a pointer, but we don't // treat it as such. @@ -61,7 +61,7 @@ func Set(t *types.Type, off int64, bv bitvec.BitVec) { case types.TSLICE: // struct { byte *array; uintgo len; uintgo cap; } if off&int64(types.PtrSize-1) != 0 { - base.Fatalf("onebitwalktype1: invalid TARRAY alignment, %v", t) + base.Fatalf("typebits.Set: invalid TARRAY alignment, %v", t) } bv.Set(int32(off / int64(types.PtrSize))) // pointer in first slot (BitsPointer) @@ -82,6 +82,6 @@ func Set(t *types.Type, off int64, bv bitvec.BitVec) { } default: - base.Fatalf("onebitwalktype1: unexpected type, %v", t) + base.Fatalf("typebits.Set: unexpected type, %v", t) } } diff --git a/src/cmd/compile/internal/typecheck/const.go b/src/cmd/compile/internal/typecheck/const.go index d6bf101974..1a8e58383a 100644 --- a/src/cmd/compile/internal/typecheck/const.go +++ b/src/cmd/compile/internal/typecheck/const.go @@ -623,7 +623,7 @@ func OrigInt(n ir.Node, v int64) ir.Node { return OrigConst(n, constant.MakeInt64(v)) } -// defaultlit on both nodes simultaneously; +// DefaultLit on both nodes simultaneously; // if they're both ideal going in they better // get the same type going out. // force means must assign concrete (non-ideal) type. diff --git a/src/cmd/compile/internal/typecheck/dcl.go b/src/cmd/compile/internal/typecheck/dcl.go index c7d7506fd1..c324238bf1 100644 --- a/src/cmd/compile/internal/typecheck/dcl.go +++ b/src/cmd/compile/internal/typecheck/dcl.go @@ -41,7 +41,7 @@ func Declare(n *ir.Name, ctxt ir.Class) { s := n.Sym() - // kludgy: typecheckok means we're past parsing. Eg genwrapper may declare out of package names later. + // kludgy: TypecheckAllowed means we're past parsing. Eg reflectdata.methodWrapper may declare out of package names later. if !inimport && !TypecheckAllowed && s.Pkg != types.LocalPkg { base.ErrorfAt(n.Pos(), "cannot declare name %v", s) } @@ -308,7 +308,7 @@ func fakeRecvField() *types.Field { return types.NewField(src.NoXPos, nil, types.FakeRecvType()) } -var funcStack []funcStackEnt // stack of previous values of Curfn/dclcontext +var funcStack []funcStackEnt // stack of previous values of ir.CurFunc/DeclContext type funcStackEnt struct { curfn *ir.Func @@ -398,14 +398,14 @@ func Temp(t *types.Type) *ir.Name { // make a new Node off the books func TempAt(pos src.XPos, curfn *ir.Func, t *types.Type) *ir.Name { if curfn == nil { - base.Fatalf("no curfn for tempAt") + base.Fatalf("no curfn for TempAt") } if curfn.Op() == ir.OCLOSURE { - ir.Dump("tempAt", curfn) - base.Fatalf("adding tempAt to wrong closure function") + ir.Dump("TempAt", curfn) + base.Fatalf("adding TempAt to wrong closure function") } if t == nil { - base.Fatalf("tempAt called with nil type") + base.Fatalf("TempAt called with nil type") } if t.Kind() == types.TFUNC && t.Recv() != nil { base.Fatalf("misuse of method type: %v", t) diff --git a/src/cmd/compile/internal/typecheck/expr.go b/src/cmd/compile/internal/typecheck/expr.go index 12bfae67a8..339fb00aa4 100644 --- a/src/cmd/compile/internal/typecheck/expr.go +++ b/src/cmd/compile/internal/typecheck/expr.go @@ -68,7 +68,7 @@ func tcShift(n, l, r ir.Node) (ir.Node, ir.Node, *types.Type) { return l, r, nil } - // no defaultlit for left + // no DefaultLit for left // the outer context gives the type t = l.Type() if (l.Type() == types.UntypedFloat || l.Type() == types.UntypedComplex) && r.Op() == ir.OLITERAL { @@ -201,7 +201,7 @@ func tcArith(n ir.Node, op ir.Op, l, r ir.Node) (ir.Node, ir.Node, *types.Type) // n.Left = tcCompLit(n.Left) func tcCompLit(n *ir.CompLitExpr) (res ir.Node) { if base.EnableTrace && base.Flag.LowerT { - defer tracePrint("typecheckcomplit", n)(&res) + defer tracePrint("tcCompLit", n)(&res) } lno := base.Pos @@ -838,7 +838,7 @@ func tcStar(n *ir.StarExpr, top int) ir.Node { } if l.Op() == ir.OTYPE { n.SetOTYPE(types.NewPtr(l.Type())) - // Ensure l.Type gets dowidth'd for the backend. Issue 20174. + // Ensure l.Type gets CalcSize'd for the backend. Issue 20174. types.CheckSize(l.Type()) return n } diff --git a/src/cmd/compile/internal/typecheck/func.go b/src/cmd/compile/internal/typecheck/func.go index 03a10f594a..c832d9700f 100644 --- a/src/cmd/compile/internal/typecheck/func.go +++ b/src/cmd/compile/internal/typecheck/func.go @@ -100,7 +100,7 @@ func PartialCallType(n *ir.SelectorExpr) *types.Type { return t } -// Lazy typechecking of imported bodies. For local functions, caninl will set ->typecheck +// Lazy typechecking of imported bodies. For local functions, CanInline will set ->typecheck // because they're a copy of an already checked body. func ImportedBody(fn *ir.Func) { lno := ir.SetPos(fn.Nname) @@ -122,14 +122,14 @@ func ImportedBody(fn *ir.Func) { ImportBody(fn) - // typecheckinl is only for imported functions; + // Stmts(fn.Inl.Body) below is only for imported functions; // their bodies may refer to unsafe as long as the package // was marked safe during import (which was checked then). - // the ->inl of a local function has been typechecked before caninl copied it. + // the ->inl of a local function has been typechecked before CanInline copied it. pkg := fnpkg(fn.Nname) if pkg == types.LocalPkg || pkg == nil { - return // typecheckinl on local function + return // ImportedBody on local function } if base.Flag.LowerM > 2 || base.Debug.Export != 0 { @@ -141,10 +141,10 @@ func ImportedBody(fn *ir.Func) { Stmts(fn.Inl.Body) ir.CurFunc = savefn - // During expandInline (which imports fn.Func.Inl.Body), - // declarations are added to fn.Func.Dcl by funcHdr(). Move them + // During ImportBody (which imports fn.Func.Inl.Body), + // declarations are added to fn.Func.Dcl by funcBody(). Move them // to fn.Func.Inl.Dcl for consistency with how local functions - // behave. (Append because typecheckinl may be called multiple + // behave. (Append because ImportedBody may be called multiple // times.) fn.Inl.Dcl = append(fn.Inl.Dcl, fn.Dcl...) fn.Dcl = nil @@ -296,7 +296,7 @@ func tcClosure(clo *ir.ClosureExpr, top int) { fn.SetClosureCalled(top&ctxCallee != 0) // Do not typecheck fn twice, otherwise, we will end up pushing - // fn to Target.Decls multiple times, causing initLSym called twice. + // fn to Target.Decls multiple times, causing InitLSym called twice. // See #30709 if fn.Typecheck() == 1 { clo.SetType(fn.Type()) @@ -343,10 +343,10 @@ func tcClosure(clo *ir.ClosureExpr, top int) { // type check function definition // To be called by typecheck, not directly. -// (Call typecheckFunc instead.) +// (Call typecheck.Func instead.) func tcFunc(n *ir.Func) { if base.EnableTrace && base.Flag.LowerT { - defer tracePrint("typecheckfunc", n)(nil) + defer tracePrint("tcFunc", n)(nil) } n.Nname = AssignExpr(n.Nname).(*ir.Name) diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 396d09263a..c2610229ec 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -37,7 +37,7 @@ var ( // and offset where that identifier's declaration can be read. DeclImporter = map[*types.Sym]iimporterAndOffset{} - // inlineImporter is like declImporter, but for inline bodies + // inlineImporter is like DeclImporter, but for inline bodies // for function and method symbols. inlineImporter = map[*types.Sym]iimporterAndOffset{} ) @@ -334,7 +334,7 @@ func (r *importReader) doDecl(sym *types.Sym) *ir.Name { recv := r.param() mtyp := r.signature(recv) - // methodSym already marked m.Sym as a function. + // MethodSym already marked m.Sym as a function. m := ir.NewNameAt(mpos, ir.MethodSym(recv.Type, msym)) m.Class = ir.PFUNC m.SetType(mtyp) diff --git a/src/cmd/compile/internal/typecheck/stmt.go b/src/cmd/compile/internal/typecheck/stmt.go index 8baa5dda78..14ed175be9 100644 --- a/src/cmd/compile/internal/typecheck/stmt.go +++ b/src/cmd/compile/internal/typecheck/stmt.go @@ -25,7 +25,7 @@ func typecheckrangeExpr(n *ir.RangeStmt) { } t := RangeExprType(n.X.Type()) - // delicate little dance. see typecheckas2 + // delicate little dance. see tcAssignList if n.Key != nil && !ir.DeclaredBy(n.Key, n) { n.Key = AssignExpr(n.Key) } @@ -90,7 +90,7 @@ func typecheckrangeExpr(n *ir.RangeStmt) { // fill in the var's type. func tcAssign(n *ir.AssignStmt) { if base.EnableTrace && base.Flag.LowerT { - defer tracePrint("typecheckas", n)(nil) + defer tracePrint("tcAssign", n)(nil) } if n.Y == nil { @@ -110,7 +110,7 @@ func tcAssign(n *ir.AssignStmt) { func tcAssignList(n *ir.AssignListStmt) { if base.EnableTrace && base.Flag.LowerT { - defer tracePrint("typecheckas2", n)(nil) + defer tracePrint("tcAssignList", n)(nil) } assign(n, n.Lhs, n.Rhs) @@ -119,7 +119,7 @@ func tcAssignList(n *ir.AssignListStmt) { func assign(stmt ir.Node, lhs, rhs []ir.Node) { // delicate little dance. // the definition of lhs may refer to this assignment - // as its definition, in which case it will call typecheckas. + // as its definition, in which case it will call tcAssign. // in that case, do not call typecheck back, or it will cycle. // if the variable has a type (ntype) then typechecking // will not look at defn, so it is okay (and desirable, diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go index 569075d684..b6a0870672 100644 --- a/src/cmd/compile/internal/typecheck/subr.go +++ b/src/cmd/compile/internal/typecheck/subr.go @@ -81,7 +81,7 @@ func markAddrOf(n ir.Node) ir.Node { // main typecheck has completed. // The argument to OADDR needs to be typechecked because &x[i] takes // the address of x if x is an array, but not if x is a slice. - // Note: outervalue doesn't work correctly until n is typechecked. + // Note: OuterValue doesn't work correctly until n is typechecked. n = typecheck(n, ctxExpr) if x := ir.OuterValue(n); x.Op() == ir.ONAME { x.Name().SetAddrtaken(true) @@ -368,10 +368,10 @@ func assignop(src, dst *types.Type) (ir.Op, string) { var missing, have *types.Field var ptr int if implements(src, dst, &missing, &have, &ptr) { - // Call itabname so that (src, dst) + // Call NeedITab/ITabAddr so that (src, dst) // gets added to itabs early, which allows // us to de-virtualize calls through this - // type/interface pair later. See peekitabs in reflect.go + // type/interface pair later. See CompileITabs in reflect.go if types.IsDirectIface(src) && !dst.IsEmptyInterface() { NeedITab(src, dst) } @@ -441,7 +441,7 @@ func assignop(src, dst *types.Type) (ir.Op, string) { } } - // 6. rule about untyped constants - already converted by defaultlit. + // 6. rule about untyped constants - already converted by DefaultLit. // 7. Any typed value can be assigned to the blank identifier. if dst.Kind() == types.TBLANK { @@ -835,7 +835,7 @@ func lookdot0(s *types.Sym, t *types.Type, save **types.Field, ignorecase bool) var slist []symlink // Code to help generate trampoline functions for methods on embedded -// types. These are approx the same as the corresponding adddot +// types. These are approx the same as the corresponding AddImplicitDots // routines except that they expect to be called with unique tasks and // they return the actual methods. diff --git a/src/cmd/compile/internal/typecheck/syms.go b/src/cmd/compile/internal/typecheck/syms.go index 28db40db91..f6ff2ee5da 100644 --- a/src/cmd/compile/internal/typecheck/syms.go +++ b/src/cmd/compile/internal/typecheck/syms.go @@ -15,7 +15,7 @@ import ( func LookupRuntime(name string) *ir.Name { s := ir.Pkgs.Runtime.Lookup(name) if s == nil || s.Def == nil { - base.Fatalf("syslook: can't find runtime.%s", name) + base.Fatalf("LookupRuntime: can't find runtime.%s", name) } return ir.AsNode(s.Def).(*ir.Name) } @@ -33,7 +33,7 @@ func SubstArgTypes(old *ir.Name, types_ ...*types.Type) *ir.Name { n.Class = old.Class n.SetType(types.SubstAny(old.Type(), &types_)) if len(types_) > 0 { - base.Fatalf("substArgTypes: too many argument types") + base.Fatalf("SubstArgTypes: too many argument types") } return n } diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go index 814af59772..3530e76972 100644 --- a/src/cmd/compile/internal/typecheck/typecheck.go +++ b/src/cmd/compile/internal/typecheck/typecheck.go @@ -456,7 +456,7 @@ func typecheck(n ir.Node, top int) (res ir.Node) { } // indexlit implements typechecking of untyped values as -// array/slice indexes. It is almost equivalent to defaultlit +// array/slice indexes. It is almost equivalent to DefaultLit // but also accepts untyped numeric values representable as // value of type int (see also checkmake for comparison). // The result of indexlit MUST be assigned back to n, e.g. @@ -938,7 +938,7 @@ func typecheckargs(n ir.InitNode) { // If we're outside of function context, then this call will // be executed during the generated init function. However, // init.go hasn't yet created it. Instead, associate the - // temporary variables with initTodo for now, and init.go + // temporary variables with InitTodoFunc for now, and init.go // will reassociate them later when it's appropriate. static := ir.CurFunc == nil if static { @@ -1890,7 +1890,7 @@ func checkmake(t *types.Type, arg string, np *ir.Node) bool { return false } - // Do range checks for constants before defaultlit + // Do range checks for constants before DefaultLit // to avoid redundant "constant NNN overflows int" errors. if n.Op() == ir.OLITERAL { v := toint(n.Val()) @@ -1904,7 +1904,7 @@ func checkmake(t *types.Type, arg string, np *ir.Node) bool { } } - // defaultlit is necessary for non-constants too: n might be 1.1<ninit when walking n, // because we might replace n with some other node // and would lose the init list. - base.Fatalf("walkexpr init == &n->ninit") + base.Fatalf("walkExpr init == &n->ninit") } if len(n.Init()) != 0 { @@ -81,7 +81,7 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node { switch n.Op() { default: ir.Dump("walk", n) - base.Fatalf("walkexpr: switch 1 unknown op %+v", n.Op()) + base.Fatalf("walkExpr: switch 1 unknown op %+v", n.Op()) panic("unreachable") case ir.ONONAME, ir.OGETG: @@ -91,7 +91,7 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node { // TODO(mdempsky): Just return n; see discussion on CL 38655. // Perhaps refactor to use Node.mayBeShared for these instead. // If these return early, make sure to still call - // stringsym for constant strings. + // StringSym for constant strings. return n case ir.OMETHEXPR: @@ -221,7 +221,7 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node { return walkIndexMap(n, init) case ir.ORECV: - base.Fatalf("walkexpr ORECV") // should see inside OAS only + base.Fatalf("walkExpr ORECV") // should see inside OAS only panic("unreachable") case ir.OSLICEHEADER: @@ -413,7 +413,7 @@ func safeExpr(n ir.Node, init *ir.Nodes) ir.Node { // make a copy; must not be used as an lvalue if ir.IsAddressable(n) { - base.Fatalf("missing lvalue case in safeexpr: %v", n) + base.Fatalf("missing lvalue case in safeExpr: %v", n) } return cheapExpr(n, init) } @@ -428,7 +428,7 @@ func walkAddString(n *ir.AddStringExpr, init *ir.Nodes) ir.Node { c := len(n.List) if c < 2 { - base.Fatalf("addstr count %d too small", c) + base.Fatalf("walkAddString count %d too small", c) } buf := typecheck.NodNil() @@ -534,7 +534,7 @@ func walkCall1(n *ir.CallExpr, init *ir.Nodes) { // Determine param type. t := params.Field(i).Type if base.Flag.Cfg.Instrumenting || fncall(arg, t) { - // make assignment of fncall to tempAt + // make assignment of fncall to Temp tmp := typecheck.Temp(t) a := convas(ir.NewAssignStmt(base.Pos, tmp, arg), init) tempAssigns = append(tempAssigns, a) diff --git a/src/cmd/compile/internal/walk/order.go b/src/cmd/compile/internal/walk/order.go index 38a9bec6e3..78063c4db2 100644 --- a/src/cmd/compile/internal/walk/order.go +++ b/src/cmd/compile/internal/walk/order.go @@ -849,7 +849,7 @@ func (o *orderState) stmt(n ir.Node) { n.X = o.copyExpr(r) // n.Prealloc is the temp for the iterator. - // hiter contains pointers and needs to be zeroed. + // MapIterType contains pointers and needs to be zeroed. n.Prealloc = o.newTemp(reflectdata.MapIterType(xt), true) } n.Key = o.exprInPlace(n.Key) @@ -962,7 +962,7 @@ func (o *orderState) stmt(n ir.Node) { cas.Body.Prepend(o.cleanTempNoPop(t)...) // TODO(mdempsky): Is this actually necessary? - // walkselect appears to walk Ninit. + // walkSelect appears to walk Ninit. cas.Body.Prepend(ir.TakeInit(cas)...) } @@ -986,7 +986,7 @@ func (o *orderState) stmt(n ir.Node) { o.cleanTemp(t) // TODO(rsc): Clean temporaries more aggressively. - // Note that because walkswitch will rewrite some of the + // Note that because walkSwitch will rewrite some of the // switch into a binary search, this is not as easy as it looks. // (If we ran that code here we could invoke order.stmt on // the if-else chain instead.) diff --git a/src/cmd/compile/internal/walk/range.go b/src/cmd/compile/internal/walk/range.go index 9225c429f0..2b28e7442d 100644 --- a/src/cmd/compile/internal/walk/range.go +++ b/src/cmd/compile/internal/walk/range.go @@ -71,7 +71,7 @@ func walkRange(nrange *ir.RangeStmt) ir.Node { } if v1 == nil && v2 != nil { - base.Fatalf("walkrange: v2 != nil while v1 == nil") + base.Fatalf("walkRange: v2 != nil while v1 == nil") } var ifGuard *ir.IfStmt @@ -80,7 +80,7 @@ func walkRange(nrange *ir.RangeStmt) ir.Node { var init []ir.Node switch t.Kind() { default: - base.Fatalf("walkrange") + base.Fatalf("walkRange") case types.TARRAY, types.TSLICE: if nn := arrayClear(nrange, v1, v2, a); nn != nil { @@ -168,7 +168,7 @@ func walkRange(nrange *ir.RangeStmt) ir.Node { hit := nrange.Prealloc th := hit.Type() - keysym := th.Field(0).Sym // depends on layout of iterator struct. See reflect.go:hiter + keysym := th.Field(0).Sym // depends on layout of iterator struct. See reflect.go:MapIterType elemsym := th.Field(1).Sym // ditto fn := typecheck.LookupRuntime("mapiterinit") @@ -388,7 +388,7 @@ func mapClear(m ir.Node) ir.Node { // // in which the evaluation of a is side-effect-free. // -// Parameters are as in walkrange: "for v1, v2 = range a". +// Parameters are as in walkRange: "for v1, v2 = range a". func arrayClear(loop *ir.RangeStmt, v1, v2, a ir.Node) ir.Node { if base.Flag.N != 0 || base.Flag.Cfg.Instrumenting { return nil diff --git a/src/cmd/compile/internal/walk/select.go b/src/cmd/compile/internal/walk/select.go index 776b020155..56ba0fa758 100644 --- a/src/cmd/compile/internal/walk/select.go +++ b/src/cmd/compile/internal/walk/select.go @@ -14,7 +14,7 @@ import ( func walkSelect(sel *ir.SelectStmt) { lno := ir.SetPos(sel) if len(sel.Compiled) != 0 { - base.Fatalf("double walkselect") + base.Fatalf("double walkSelect") } init := ir.TakeInit(sel) @@ -218,7 +218,7 @@ func walkSelectCases(cases []*ir.CommClause) []ir.Node { } } if nsends+nrecvs != ncas { - base.Fatalf("walkselectcases: miscount: %v + %v != %v", nsends, nrecvs, ncas) + base.Fatalf("walkSelectCases: miscount: %v + %v != %v", nsends, nrecvs, ncas) } // run the select diff --git a/src/cmd/compile/internal/walk/switch.go b/src/cmd/compile/internal/walk/switch.go index 0cc1830d3f..162de018f6 100644 --- a/src/cmd/compile/internal/walk/switch.go +++ b/src/cmd/compile/internal/walk/switch.go @@ -49,8 +49,8 @@ func walkSwitchExpr(sw *ir.SwitchStmt) { // Given "switch string(byteslice)", // with all cases being side-effect free, // use a zero-cost alias of the byte slice. - // Do this before calling walkexpr on cond, - // because walkexpr will lower the string + // Do this before calling walkExpr on cond, + // because walkExpr will lower the string // conversion into a runtime call. // See issue 24937 for more discussion. if cond.Op() == ir.OBYTES2STR && allCaseExprsAreSideEffectFree(sw) { diff --git a/src/cmd/compile/internal/walk/walk.go b/src/cmd/compile/internal/walk/walk.go index 4ba81b82fe..f95440d60d 100644 --- a/src/cmd/compile/internal/walk/walk.go +++ b/src/cmd/compile/internal/walk/walk.go @@ -208,7 +208,7 @@ func mapfast(t *types.Type) int { func walkAppendArgs(n *ir.CallExpr, init *ir.Nodes) { walkExprListSafe(n.Args, init) - // walkexprlistsafe will leave OINDEX (s[n]) alone if both s + // walkExprListSafe will leave OINDEX (s[n]) alone if both s // and n are name or literal, but those may index the slice we're // modifying here. Fix explicitly. ls := n.Args @@ -240,8 +240,8 @@ func appendWalkStmt(init *ir.Nodes, stmt ir.Node) { op := stmt.Op() n := typecheck.Stmt(stmt) if op == ir.OAS || op == ir.OAS2 { - // If the assignment has side effects, walkexpr will append them - // directly to init for us, while walkstmt will wrap it in an OBLOCK. + // If the assignment has side effects, walkExpr will append them + // directly to init for us, while walkStmt will wrap it in an OBLOCK. // We need to append them directly. // TODO(rsc): Clean this up. n = walkExpr(n, init) @@ -256,7 +256,7 @@ func appendWalkStmt(init *ir.Nodes, stmt ir.Node) { const maxOpenDefers = 8 // backingArrayPtrLen extracts the pointer and length from a slice or string. -// This constructs two nodes referring to n, so n must be a cheapexpr. +// This constructs two nodes referring to n, so n must be a cheapExpr. func backingArrayPtrLen(n ir.Node) (ptr, length ir.Node) { var init ir.Nodes c := cheapExpr(n, &init) @@ -423,7 +423,7 @@ func runtimeField(name string, offset int64, typ *types.Type) *types.Field { // ifaceData loads the data field from an interface. // The concrete type must be known to have type t. -// It follows the pointer if !isdirectiface(t). +// It follows the pointer if !IsDirectIface(t). func ifaceData(pos src.XPos, n ir.Node, t *types.Type) ir.Node { if t.IsInterface() { base.Fatalf("ifaceData interface: %v", t) diff --git a/src/cmd/internal/goobj/mkbuiltin.go b/src/cmd/internal/goobj/mkbuiltin.go index 07c3406681..22608e7e69 100644 --- a/src/cmd/internal/goobj/mkbuiltin.go +++ b/src/cmd/internal/goobj/mkbuiltin.go @@ -118,8 +118,8 @@ func mkbuiltin(w io.Writer) { // addBasicTypes returns the symbol names for basic types that are // defined in the runtime and referenced in other packages. -// Needs to be kept in sync with reflect.go:dumpbasictypes() and -// reflect.go:dtypesym() in the compiler. +// Needs to be kept in sync with reflect.go:WriteBasicTypes() and +// reflect.go:writeType() in the compiler. func enumerateBasicTypes() []extra { names := [...]string{ "int8", "uint8", "int16", "uint16", diff --git a/src/cmd/internal/obj/textflag.go b/src/cmd/internal/obj/textflag.go index fcc4014aa2..2f55793285 100644 --- a/src/cmd/internal/obj/textflag.go +++ b/src/cmd/internal/obj/textflag.go @@ -33,7 +33,7 @@ const ( // This function uses its incoming context register. NEEDCTXT = 64 - // When passed to ggloblsym, causes Local to be set to true on the LSym it creates. + // When passed to objw.Global, causes Local to be set to true on the LSym it creates. LOCAL = 128 // Allocate a word of thread local storage and store the offset from the diff --git a/src/embed/embed.go b/src/embed/embed.go index 29e0adf1a6..5f35cd13b6 100644 --- a/src/embed/embed.go +++ b/src/embed/embed.go @@ -133,7 +133,7 @@ import ( // See the package documentation for more details about initializing an FS. type FS struct { // The compiler knows the layout of this struct. - // See cmd/compile/internal/gc's initEmbed. + // See cmd/compile/internal/staticdata's WriteEmbed. // // The files list is sorted by name but not by simple string comparison. // Instead, each file's name takes the form "dir/elem" or "dir/elem/". @@ -203,7 +203,7 @@ var ( // It implements fs.FileInfo and fs.DirEntry. type file struct { // The compiler knows the layout of this struct. - // See cmd/compile/internal/gc's initEmbed. + // See cmd/compile/internal/staticdata's WriteEmbed. name string data string hash [16]byte // truncated SHA256 hash diff --git a/src/reflect/type.go b/src/reflect/type.go index 1f1e70d485..13e3d71228 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -1890,7 +1890,7 @@ func MapOf(key, elem Type) Type { // Make a map type. // Note: flag values must match those used in the TMAP case - // in ../cmd/compile/internal/gc/reflect.go:dtypesym. + // in ../cmd/compile/internal/gc/reflect.go:writeType. var imap interface{} = (map[unsafe.Pointer]unsafe.Pointer)(nil) mt := **(**mapType)(unsafe.Pointer(&imap)) mt.str = resolveReflectName(newName(s, "", false)) diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go index c9376827da..9c3ceabd18 100644 --- a/src/runtime/runtime2.go +++ b/src/runtime/runtime2.go @@ -853,7 +853,7 @@ type funcinl struct { // layout of Itab known to compilers // allocated in non-garbage-collected memory // Needs to be in sync with -// ../cmd/compile/internal/gc/reflect.go:/^func.dumptabs. +// ../cmd/compile/internal/gc/reflect.go:/^func.WriteTabs. type itab struct { inter *interfacetype _type *_type diff --git a/src/runtime/type.go b/src/runtime/type.go index 81455f3532..18fc4bbfad 100644 --- a/src/runtime/type.go +++ b/src/runtime/type.go @@ -383,7 +383,7 @@ type maptype struct { } // Note: flag values must match those used in the TMAP case -// in ../cmd/compile/internal/gc/reflect.go:dtypesym. +// in ../cmd/compile/internal/gc/reflect.go:writeType. func (mt *maptype) indirectkey() bool { // store ptr to key instead of key itself return mt.flags&1 != 0 } -- cgit v1.3-5-g9baa From ecf4ebf10054f70e51a0ce759b2ae91aa4febd1a Mon Sep 17 00:00:00 2001 From: Dmitri Shuralyov Date: Sat, 5 Dec 2020 15:03:27 -0500 Subject: cmd/internal/moddeps: check content of all modules in GOROOT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Expand the scope of the TestAllDependenciesVendored test to check that all modules in GOROOT are tidy, that packages are vendored, the vendor content matches the upstream copy exactly, and that bundled packages are re-generated (using x/tools/cmd/bundle at the version selected in cmd module; this is deterministic and guaranteed to be updated over time). This is done in a conceptually simple way: 1. Make a temporary copy of the entire GOROOT tree (except .git), one that is safe to modify. 2. Run a list of high-level commands, the same commands we expect Go developers should be able to run in a normal complete GOROOT tree to make it clean and tidy. 3. Diff the end result with the original GOROOT tree being tested to catch any unexpected differences. The current set of commands that are run require the cmd/go command, and a functional compiler itself (because re-generating the syscall package involves a directive like //go:generate go run [...]). As a result, copying a large majority of the GOROOT tree is a requirement. Instead of looking for the few files or directories that can we can get away not copying (e.g., the testdata directories aren't strictly needed at this time), we opt not to optimize and just do the simple copy. This is motivated by these reasons: • We end up having a complete, normal GOROOT tree, one that happens to be located at another path. There's a very high likelihood that module management/code generation commands, both the ones we run today and any additional ones that we might want to add in the future, will result in correct results even as the Go project evolves over time. • Having a completely stand-alone copy of the GOROOT tree without symlinks minimizes the risk of some of the module management/code generation commands, either now or in the future, from modifying the user's original GOROOT tree, something that should not happen during test execution. Overlays achieved with symlinks work well when we can guarantee only new files are added, but that isn't the case here. • Copying the entire GOROOT (without .git), takes around 5 seconds on a fairly modern computer with an SSD. The most we can save is a couple of seconds. (We make some minor exceptions: the GOROOT/.git directory isn't copied, and GOROOT/{bin,pkg} are deemed safe to share and thus symlink instead of copying. If these optimizations cease to be viable to make, we'll need to remove them.) Since this functionality is fairly expensive to execute and requires network access, it runs only when the test is executed without -short flag. The previous behavior of the TestAllDependenciesVendored test is kept in -short test mode. all.bash runs package tests with -short flag, so its behavior is unchanged. The expectation is that the new test will run on some of the longtest builders to catch problems. Users can invoke the test manually 'go test cmd/internal/moddeps' (and it's run as part of 'go test cmd', again, only when -short flag isn't provided). On a 2017 MacBook Pro, a successful long test takes under 15 seconds, which should be within scope of all long tests that are selected by 'go test std cmd'. We may further adjust when and where the test runs by default based on our experience. Fixes #36852. Fixes #41409. Fixes #43687. Updates #43440. Change-Id: I9eb85205fec7ec62e3f867831a0a82e3c767f618 Reviewed-on: https://go-review.googlesource.com/c/go/+/283643 Run-TryBot: Dmitri Shuralyov TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills Trust: Dmitri Shuralyov --- src/cmd/internal/moddeps/moddeps_test.go | 400 ++++++++++++++++++++++++------- 1 file changed, 316 insertions(+), 84 deletions(-) (limited to 'src/cmd/internal') diff --git a/src/cmd/internal/moddeps/moddeps_test.go b/src/cmd/internal/moddeps/moddeps_test.go index 9ea21873c5..cba401c896 100644 --- a/src/cmd/internal/moddeps/moddeps_test.go +++ b/src/cmd/internal/moddeps/moddeps_test.go @@ -8,6 +8,7 @@ import ( "encoding/json" "fmt" "internal/testenv" + "io" "io/fs" "io/ioutil" "os" @@ -21,93 +22,34 @@ import ( "golang.org/x/mod/module" ) -type gorootModule struct { - Path string - Dir string - hasVendor bool -} - -// findGorootModules returns the list of modules found in the GOROOT source tree. -func findGorootModules(t *testing.T) []gorootModule { - t.Helper() - goBin := testenv.GoToolPath(t) - - goroot.once.Do(func() { - goroot.err = filepath.WalkDir(runtime.GOROOT(), func(path string, info fs.DirEntry, err error) error { - if err != nil { - return err - } - if info.IsDir() && (info.Name() == "vendor" || info.Name() == "testdata") { - return filepath.SkipDir - } - if path == filepath.Join(runtime.GOROOT(), "pkg") { - // GOROOT/pkg contains generated artifacts, not source code. - // - // In https://golang.org/issue/37929 it was observed to somehow contain - // a module cache, so it is important to skip. (That helps with the - // running time of this test anyway.) - return filepath.SkipDir - } - if info.IsDir() || info.Name() != "go.mod" { - return nil - } - dir := filepath.Dir(path) - - // Use 'go list' to describe the module contained in this directory (but - // not its dependencies). - cmd := exec.Command(goBin, "list", "-json", "-m") - cmd.Env = append(os.Environ(), "GO111MODULE=on") - cmd.Dir = dir - cmd.Stderr = new(strings.Builder) - out, err := cmd.Output() - if err != nil { - return fmt.Errorf("'go list -json -m' in %s: %w\n%s", dir, err, cmd.Stderr) - } - - var m gorootModule - if err := json.Unmarshal(out, &m); err != nil { - return fmt.Errorf("decoding 'go list -json -m' in %s: %w", dir, err) - } - if m.Path == "" || m.Dir == "" { - return fmt.Errorf("'go list -json -m' in %s failed to populate Path and/or Dir", dir) - } - if _, err := os.Stat(filepath.Join(dir, "vendor")); err == nil { - m.hasVendor = true - } - goroot.modules = append(goroot.modules, m) - return nil - }) - }) - - if goroot.err != nil { - t.Fatal(goroot.err) - } - return goroot.modules -} - -// goroot caches the list of modules found in the GOROOT source tree. -var goroot struct { - once sync.Once - modules []gorootModule - err error -} - -// TestAllDependenciesVendored ensures that all packages imported within GOROOT -// are vendored in the corresponding GOROOT module. +// TestAllDependencies ensures dependencies of all +// modules in GOROOT are in a consistent state. // -// This property allows offline development within the Go project, and ensures -// that all dependency changes are presented in the usual code review process. +// In short mode, it does a limited quick check and stops there. +// In long mode, it also makes a copy of the entire GOROOT tree +// and requires network access to perform more thorough checks. +// Keep this distinction in mind when adding new checks. // -// This test does NOT ensure that the vendored contents match the unmodified -// contents of the corresponding dependency versions. Such as test would require -// network access, and would currently either need to copy the entire GOROOT module -// or explicitly invoke version control to check for changes. -// (See golang.org/issue/36852 and golang.org/issue/27348.) -func TestAllDependenciesVendored(t *testing.T) { +// See issues 36852, 41409, and 43687. +// (Also see golang.org/issue/27348.) +func TestAllDependencies(t *testing.T) { goBin := testenv.GoToolPath(t) + // Ensure that all packages imported within GOROOT + // are vendored in the corresponding GOROOT module. + // + // This property allows offline development within the Go project, and ensures + // that all dependency changes are presented in the usual code review process. + // + // As a quick first-order check, avoid network access and the need to copy the + // entire GOROOT tree or explicitly invoke version control to check for changes. + // Just check that packages are vendored. (In non-short mode, we go on to also + // copy the GOROOT tree and perform more rigorous consistency checks. Jump below + // for more details.) for _, m := range findGorootModules(t) { - t.Run(m.Path, func(t *testing.T) { + // This short test does NOT ensure that the vendored contents match + // the unmodified contents of the corresponding dependency versions. + t.Run(m.Path+"(quick)", func(t *testing.T) { if m.hasVendor { // Load all of the packages in the module to ensure that their // dependencies are vendored. If any imported package is missing, @@ -140,6 +82,226 @@ func TestAllDependenciesVendored(t *testing.T) { } }) } + + // We now get to the slow, but more thorough part of the test. + // Only run it in long test mode. + if testing.Short() { + return + } + + // Ensure that all modules within GOROOT are tidy, vendored, and bundled. + // Ensure that the vendored contents match the unmodified contents of the + // corresponding dependency versions. + // + // The non-short section of this test requires network access and the diff + // command. + // + // It makes a temporary copy of the entire GOROOT tree (where it can safely + // perform operations that may mutate the tree), executes the same module + // maintenance commands that we expect Go developers to run, and then + // diffs the potentially modified module copy with the real one in GOROOT. + // (We could try to rely on Git to do things differently, but that's not the + // path we've chosen at this time. This allows the test to run when the tree + // is not checked into Git.) + + testenv.MustHaveExternalNetwork(t) + if haveDiff := func() bool { + diff, err := exec.Command("diff", "--recursive", "--unified", ".", ".").CombinedOutput() + if err != nil || len(diff) != 0 { + return false + } + diff, err = exec.Command("diff", "--recursive", "--unified", ".", "..").CombinedOutput() + if err == nil || len(diff) == 0 { + return false + } + return true + }(); !haveDiff { + // For now, the diff command is a mandatory dependency of this test. + // This test will primarily run on longtest builders, since few people + // would test the cmd/internal/moddeps package directly, and all.bash + // runs tests in short mode. It's fine to skip if diff is unavailable. + t.Skip("skipping because a diff command with support for --recursive and --unified flags is unavailable") + } + + // Build the bundle binary at the golang.org/x/tools + // module version specified in GOROOT/src/cmd/go.mod. + bundleDir := t.TempDir() + r := runner{Dir: filepath.Join(runtime.GOROOT(), "src/cmd")} + r.run(t, goBin, "build", "-mod=readonly", "-o", bundleDir, "golang.org/x/tools/cmd/bundle") + + var gorootCopyDir string + for _, m := range findGorootModules(t) { + // Create a test-wide GOROOT copy. It can be created once + // and reused between subtests whenever they don't fail. + // + // This is a relatively expensive operation, but it's a pre-requisite to + // be able to safely run commands like "go mod tidy", "go mod vendor", and + // "go generate" on the GOROOT tree content. Those commands may modify the + // tree, and we don't want to happen to the real tree as part of executing + // a test. + if gorootCopyDir == "" { + gorootCopyDir = makeGOROOTCopy(t) + } + + t.Run(m.Path+"(thorough)", func(t *testing.T) { + defer func() { + if t.Failed() { + // The test failed, which means it's possible the GOROOT copy + // may have been modified. No choice but to reset it for next + // module test case. (This is slow, but it happens only during + // test failures.) + gorootCopyDir = "" + } + }() + + rel, err := filepath.Rel(runtime.GOROOT(), m.Dir) + if err != nil { + t.Fatalf("filepath.Rel(%q, %q): %v", runtime.GOROOT(), m.Dir, err) + } + r := runner{ + Dir: filepath.Join(gorootCopyDir, rel), + Env: append(os.Environ(), + // Set GOROOT. + "GOROOT="+gorootCopyDir, + // Explicitly clear PWD and GOROOT_FINAL so that GOROOT=gorootCopyDir is definitely used. + "PWD=", + "GOROOT_FINAL=", + // Add GOROOTcopy/bin and bundleDir to front of PATH. + "PATH="+filepath.Join(gorootCopyDir, "bin")+string(filepath.ListSeparator)+ + bundleDir+string(filepath.ListSeparator)+os.Getenv("PATH"), + ), + } + goBinCopy := filepath.Join(gorootCopyDir, "bin", "go") + r.run(t, goBinCopy, "mod", "tidy") // See issue 43687. + r.run(t, goBinCopy, "mod", "verify") // Verify should be a no-op, but test it just in case. + r.run(t, goBinCopy, "mod", "vendor") // See issue 36852. + pkgs := packagePattern(m.Path) + r.run(t, goBinCopy, "generate", `-run=^//go:generate bundle `, pkgs) // See issue 41409. + advice := "$ cd " + m.Dir + "\n" + + "$ go mod tidy # to remove extraneous dependencies\n" + + "$ go mod vendor # to vendor dependecies\n" + + "$ go generate -run=bundle " + pkgs + " # to regenerate bundled packages\n" + if m.Path == "std" { + r.run(t, goBinCopy, "generate", "syscall", "internal/syscall/...") // See issue 43440. + advice += "$ go generate syscall internal/syscall/... # to regenerate syscall packages\n" + } + // TODO(golang.org/issue/43440): Check anything else influenced by dependency versions. + + diff, err := exec.Command("diff", "--recursive", "--unified", r.Dir, m.Dir).CombinedOutput() + if err != nil || len(diff) != 0 { + t.Errorf(`Module %s in %s is not tidy (-want +got): + +%s +To fix it, run: + +%s +(If module %[1]s is definitely tidy, this could mean +there's a problem in the go or bundle command.)`, m.Path, m.Dir, diff, advice) + } + }) + } +} + +// packagePattern returns a package pattern that matches all packages +// in the module modulePath, and ideally as few others as possible. +func packagePattern(modulePath string) string { + if modulePath == "std" { + return "std" + } + return modulePath + "/..." +} + +// makeGOROOTCopy makes a temporary copy of the current GOROOT tree. +// The goal is to allow the calling test t to safely mutate a GOROOT +// copy without also modifying the original GOROOT. +// +// It copies the entire tree as is, with the exception of the GOROOT/.git +// directory, which is skipped, and the GOROOT/{bin,pkg} directories, +// which are symlinked. This is done for speed, since a GOROOT tree is +// functional without being in a Git repository, and bin and pkg are +// deemed safe to share for the purpose of the TestAllDependencies test. +func makeGOROOTCopy(t *testing.T) string { + t.Helper() + gorootCopyDir := t.TempDir() + err := filepath.Walk(runtime.GOROOT(), func(src string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if src == filepath.Join(runtime.GOROOT(), ".git") { + return filepath.SkipDir + } + + rel, err := filepath.Rel(runtime.GOROOT(), src) + if err != nil { + return fmt.Errorf("filepath.Rel(%q, %q): %v", runtime.GOROOT(), src, err) + } + dst := filepath.Join(gorootCopyDir, rel) + + switch src { + case filepath.Join(runtime.GOROOT(), "bin"), + filepath.Join(runtime.GOROOT(), "pkg"): + // If the OS supports symlinks, use them instead + // of copying the bin and pkg directories. + if err := os.Symlink(src, dst); err == nil { + return filepath.SkipDir + } + } + + perm := info.Mode() & os.ModePerm + if info.Mode()&os.ModeSymlink != 0 { + info, err = os.Stat(src) + if err != nil { + return err + } + perm = info.Mode() & os.ModePerm + } + + // If it's a directory, make a corresponding directory. + if info.IsDir() { + return os.MkdirAll(dst, perm|0200) + } + + // Copy the file bytes. + // We can't create a symlink because the file may get modified; + // we need to ensure that only the temporary copy is affected. + s, err := os.Open(src) + if err != nil { + return err + } + defer s.Close() + d, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_EXCL, perm) + if err != nil { + return err + } + _, err = io.Copy(d, s) + if err != nil { + d.Close() + return err + } + return d.Close() + }) + if err != nil { + t.Fatal(err) + } + return gorootCopyDir +} + +type runner struct { + Dir string + Env []string +} + +// run runs the command and requires that it succeeds. +func (r runner) run(t *testing.T, args ...string) { + t.Helper() + cmd := exec.Command(args[0], args[1:]...) + cmd.Dir = r.Dir + cmd.Env = r.Env + out, err := cmd.CombinedOutput() + if err != nil { + t.Logf("> %s\n", strings.Join(args, " ")) + t.Fatalf("command failed: %s\n%s", err, out) + } } // TestDependencyVersionsConsistent verifies that each module in GOROOT that @@ -159,8 +321,7 @@ func TestDependencyVersionsConsistent(t *testing.T) { seen := map[string]map[requirement][]gorootModule{} // module path → requirement → set of modules with that requirement for _, m := range findGorootModules(t) { if !m.hasVendor { - // TestAllDependenciesVendored will ensure that the module has no - // dependencies. + // TestAllDependencies will ensure that the module has no dependencies. continue } @@ -233,3 +394,74 @@ func TestDependencyVersionsConsistent(t *testing.T) { } } } + +type gorootModule struct { + Path string + Dir string + hasVendor bool +} + +// findGorootModules returns the list of modules found in the GOROOT source tree. +func findGorootModules(t *testing.T) []gorootModule { + t.Helper() + goBin := testenv.GoToolPath(t) + + goroot.once.Do(func() { + goroot.err = filepath.WalkDir(runtime.GOROOT(), func(path string, info fs.DirEntry, err error) error { + if err != nil { + return err + } + if info.IsDir() && (info.Name() == "vendor" || info.Name() == "testdata") { + return filepath.SkipDir + } + if path == filepath.Join(runtime.GOROOT(), "pkg") { + // GOROOT/pkg contains generated artifacts, not source code. + // + // In https://golang.org/issue/37929 it was observed to somehow contain + // a module cache, so it is important to skip. (That helps with the + // running time of this test anyway.) + return filepath.SkipDir + } + if info.IsDir() || info.Name() != "go.mod" { + return nil + } + dir := filepath.Dir(path) + + // Use 'go list' to describe the module contained in this directory (but + // not its dependencies). + cmd := exec.Command(goBin, "list", "-json", "-m") + cmd.Env = append(os.Environ(), "GO111MODULE=on") + cmd.Dir = dir + cmd.Stderr = new(strings.Builder) + out, err := cmd.Output() + if err != nil { + return fmt.Errorf("'go list -json -m' in %s: %w\n%s", dir, err, cmd.Stderr) + } + + var m gorootModule + if err := json.Unmarshal(out, &m); err != nil { + return fmt.Errorf("decoding 'go list -json -m' in %s: %w", dir, err) + } + if m.Path == "" || m.Dir == "" { + return fmt.Errorf("'go list -json -m' in %s failed to populate Path and/or Dir", dir) + } + if _, err := os.Stat(filepath.Join(dir, "vendor")); err == nil { + m.hasVendor = true + } + goroot.modules = append(goroot.modules, m) + return nil + }) + }) + + if goroot.err != nil { + t.Fatal(goroot.err) + } + return goroot.modules +} + +// goroot caches the list of modules found in the GOROOT source tree. +var goroot struct { + once sync.Once + modules []gorootModule + err error +} -- cgit v1.3-5-g9baa From 953d1feca9b21af075ad5fc8a3dad096d3ccc3a0 Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Fri, 15 Jan 2021 12:14:06 -0800 Subject: all: introduce and use internal/execabs Introduces a wrapper around os/exec, internal/execabs, for use in all commands. This wrapper prevents exec.LookPath and exec.Command from running executables in the current directory. All imports of os/exec in non-test files in cmd/ are replaced with imports of internal/execabs. This issue was reported by RyotaK. Fixes CVE-2021-3115 Fixes #43783 Change-Id: I0423451a6e27ec1e1d6f3fe929ab1ef69145c08f Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/955304 Reviewed-by: Russ Cox Reviewed-by: Katie Hockman Reviewed-on: https://go-review.googlesource.com/c/go/+/284783 Run-TryBot: Roland Shoemaker Reviewed-by: Katie Hockman Trust: Roland Shoemaker --- src/cmd/api/goapi.go | 2 +- src/cmd/api/run.go | 2 +- src/cmd/cgo/out.go | 2 +- src/cmd/cgo/util.go | 2 +- src/cmd/compile/internal/ssa/html.go | 2 +- src/cmd/cover/func.go | 2 +- src/cmd/cover/testdata/toolexec.go | 2 +- src/cmd/dist/buildtool.go | 4 +- src/cmd/doc/dirs.go | 2 +- src/cmd/fix/typecheck.go | 2 +- src/cmd/go/internal/base/base.go | 2 +- src/cmd/go/internal/bug/bug.go | 2 +- src/cmd/go/internal/generate/generate.go | 2 +- src/cmd/go/internal/modfetch/codehost/codehost.go | 2 +- src/cmd/go/internal/modfetch/codehost/git.go | 2 +- src/cmd/go/internal/test/genflags.go | 2 +- src/cmd/go/internal/test/test.go | 2 +- src/cmd/go/internal/tool/tool.go | 2 +- src/cmd/go/internal/vcs/vcs.go | 2 +- src/cmd/go/internal/vet/vetflag.go | 2 +- src/cmd/go/internal/work/build.go | 2 +- src/cmd/go/internal/work/buildid.go | 2 +- src/cmd/go/internal/work/exec.go | 2 +- src/cmd/go/internal/work/gccgo.go | 2 +- src/cmd/go/testdata/addmod.go | 2 +- src/cmd/internal/browser/browser.go | 2 +- src/cmd/internal/diff/diff.go | 2 +- src/cmd/internal/dwarf/dwarf.go | 2 +- src/cmd/internal/pkgpath/pkgpath.go | 2 +- src/cmd/link/internal/ld/execarchive.go | 2 +- src/cmd/link/internal/ld/lib.go | 2 +- src/cmd/test2json/main.go | 2 +- src/cmd/trace/pprof.go | 2 +- src/go/build/build.go | 2 +- src/go/build/deps_test.go | 8 +- src/go/internal/gccgoimporter/gccgoinstallation.go | 2 +- src/go/internal/srcimporter/srcimporter.go | 2 +- src/internal/execabs/execabs.go | 70 ++++++++++++++ src/internal/execabs/execabs_test.go | 104 +++++++++++++++++++++ src/internal/goroot/gc.go | 2 +- 40 files changed, 220 insertions(+), 38 deletions(-) create mode 100644 src/internal/execabs/execabs.go create mode 100644 src/internal/execabs/execabs_test.go (limited to 'src/cmd/internal') diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go index ba42812fa6..efc2696f8f 100644 --- a/src/cmd/api/goapi.go +++ b/src/cmd/api/goapi.go @@ -16,10 +16,10 @@ import ( "go/parser" "go/token" "go/types" + exec "internal/execabs" "io" "log" "os" - "os/exec" "path/filepath" "regexp" "runtime" diff --git a/src/cmd/api/run.go b/src/cmd/api/run.go index a36f1179c1..ecb1d0f81a 100644 --- a/src/cmd/api/run.go +++ b/src/cmd/api/run.go @@ -10,9 +10,9 @@ package main import ( "fmt" + exec "internal/execabs" "log" "os" - "os/exec" "path/filepath" "runtime" "strings" diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index fa6f0efbbe..8e83f02202 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -14,10 +14,10 @@ import ( "go/ast" "go/printer" "go/token" + exec "internal/execabs" "internal/xcoff" "io" "os" - "os/exec" "path/filepath" "regexp" "sort" diff --git a/src/cmd/cgo/util.go b/src/cmd/cgo/util.go index 779f7be225..00d931b98a 100644 --- a/src/cmd/cgo/util.go +++ b/src/cmd/cgo/util.go @@ -8,9 +8,9 @@ import ( "bytes" "fmt" "go/token" + exec "internal/execabs" "io/ioutil" "os" - "os/exec" ) // run runs the command argv, feeding in stdin on standard input. diff --git a/src/cmd/compile/internal/ssa/html.go b/src/cmd/compile/internal/ssa/html.go index a9d52fa4ee..c06b5808e1 100644 --- a/src/cmd/compile/internal/ssa/html.go +++ b/src/cmd/compile/internal/ssa/html.go @@ -9,9 +9,9 @@ import ( "cmd/internal/src" "fmt" "html" + exec "internal/execabs" "io" "os" - "os/exec" "path/filepath" "strconv" "strings" diff --git a/src/cmd/cover/func.go b/src/cmd/cover/func.go index 988c4caebf..ce7c771ac9 100644 --- a/src/cmd/cover/func.go +++ b/src/cmd/cover/func.go @@ -15,9 +15,9 @@ import ( "go/ast" "go/parser" "go/token" + exec "internal/execabs" "io" "os" - "os/exec" "path" "path/filepath" "runtime" diff --git a/src/cmd/cover/testdata/toolexec.go b/src/cmd/cover/testdata/toolexec.go index 1769efedbe..386de79038 100644 --- a/src/cmd/cover/testdata/toolexec.go +++ b/src/cmd/cover/testdata/toolexec.go @@ -16,7 +16,7 @@ package main import ( "os" - "os/exec" + exec "internal/execabs" "strings" ) diff --git a/src/cmd/dist/buildtool.go b/src/cmd/dist/buildtool.go index e7bedfb84e..cf85f2ac8e 100644 --- a/src/cmd/dist/buildtool.go +++ b/src/cmd/dist/buildtool.go @@ -305,8 +305,10 @@ func bootstrapFixImports(srcFile string) string { continue } if strings.HasPrefix(line, `import "`) || strings.HasPrefix(line, `import . "`) || - inBlock && (strings.HasPrefix(line, "\t\"") || strings.HasPrefix(line, "\t. \"")) { + inBlock && (strings.HasPrefix(line, "\t\"") || strings.HasPrefix(line, "\t. \"") || strings.HasPrefix(line, "\texec \"")) { line = strings.Replace(line, `"cmd/`, `"bootstrap/cmd/`, -1) + // During bootstrap, must use plain os/exec. + line = strings.Replace(line, `exec "internal/execabs"`, `"os/exec"`, -1) for _, dir := range bootstrapDirs { if strings.HasPrefix(dir, "cmd/") { continue diff --git a/src/cmd/doc/dirs.go b/src/cmd/doc/dirs.go index 38cbe7fa02..661624cfe4 100644 --- a/src/cmd/doc/dirs.go +++ b/src/cmd/doc/dirs.go @@ -7,9 +7,9 @@ package main import ( "bytes" "fmt" + exec "internal/execabs" "log" "os" - "os/exec" "path/filepath" "regexp" "strings" diff --git a/src/cmd/fix/typecheck.go b/src/cmd/fix/typecheck.go index 40b2287f26..39a53785b7 100644 --- a/src/cmd/fix/typecheck.go +++ b/src/cmd/fix/typecheck.go @@ -9,8 +9,8 @@ import ( "go/ast" "go/parser" "go/token" + exec "internal/execabs" "os" - "os/exec" "path/filepath" "reflect" "runtime" diff --git a/src/cmd/go/internal/base/base.go b/src/cmd/go/internal/base/base.go index 004588c732..954ce47a98 100644 --- a/src/cmd/go/internal/base/base.go +++ b/src/cmd/go/internal/base/base.go @@ -10,9 +10,9 @@ import ( "context" "flag" "fmt" + exec "internal/execabs" "log" "os" - "os/exec" "strings" "sync" diff --git a/src/cmd/go/internal/bug/bug.go b/src/cmd/go/internal/bug/bug.go index 1085feaaee..4aa08b4ff6 100644 --- a/src/cmd/go/internal/bug/bug.go +++ b/src/cmd/go/internal/bug/bug.go @@ -9,10 +9,10 @@ import ( "bytes" "context" "fmt" + exec "internal/execabs" "io" urlpkg "net/url" "os" - "os/exec" "path/filepath" "regexp" "runtime" diff --git a/src/cmd/go/internal/generate/generate.go b/src/cmd/go/internal/generate/generate.go index b1e001c800..a48311d51b 100644 --- a/src/cmd/go/internal/generate/generate.go +++ b/src/cmd/go/internal/generate/generate.go @@ -12,10 +12,10 @@ import ( "fmt" "go/parser" "go/token" + exec "internal/execabs" "io" "log" "os" - "os/exec" "path/filepath" "regexp" "strconv" diff --git a/src/cmd/go/internal/modfetch/codehost/codehost.go b/src/cmd/go/internal/modfetch/codehost/codehost.go index 86c1c14d4a..378fbae34f 100644 --- a/src/cmd/go/internal/modfetch/codehost/codehost.go +++ b/src/cmd/go/internal/modfetch/codehost/codehost.go @@ -10,10 +10,10 @@ import ( "bytes" "crypto/sha256" "fmt" + exec "internal/execabs" "io" "io/fs" "os" - "os/exec" "path/filepath" "strings" "sync" diff --git a/src/cmd/go/internal/modfetch/codehost/git.go b/src/cmd/go/internal/modfetch/codehost/git.go index 8abc039e7f..72005e27d5 100644 --- a/src/cmd/go/internal/modfetch/codehost/git.go +++ b/src/cmd/go/internal/modfetch/codehost/git.go @@ -8,11 +8,11 @@ import ( "bytes" "errors" "fmt" + exec "internal/execabs" "io" "io/fs" "net/url" "os" - "os/exec" "path/filepath" "sort" "strconv" diff --git a/src/cmd/go/internal/test/genflags.go b/src/cmd/go/internal/test/genflags.go index 5e83d53980..30334b0f30 100644 --- a/src/cmd/go/internal/test/genflags.go +++ b/src/cmd/go/internal/test/genflags.go @@ -9,9 +9,9 @@ package main import ( "bytes" "flag" + exec "internal/execabs" "log" "os" - "os/exec" "strings" "testing" "text/template" diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go index 50fe2dbf39..7fc9e8fbdc 100644 --- a/src/cmd/go/internal/test/test.go +++ b/src/cmd/go/internal/test/test.go @@ -11,10 +11,10 @@ import ( "errors" "fmt" "go/build" + exec "internal/execabs" "io" "io/fs" "os" - "os/exec" "path" "path/filepath" "regexp" diff --git a/src/cmd/go/internal/tool/tool.go b/src/cmd/go/internal/tool/tool.go index 6a755bc436..95c90ea7c8 100644 --- a/src/cmd/go/internal/tool/tool.go +++ b/src/cmd/go/internal/tool/tool.go @@ -8,8 +8,8 @@ package tool import ( "context" "fmt" + exec "internal/execabs" "os" - "os/exec" "os/signal" "sort" "strings" diff --git a/src/cmd/go/internal/vcs/vcs.go b/src/cmd/go/internal/vcs/vcs.go index 327ea7cc86..9feffe0765 100644 --- a/src/cmd/go/internal/vcs/vcs.go +++ b/src/cmd/go/internal/vcs/vcs.go @@ -8,13 +8,13 @@ import ( "encoding/json" "errors" "fmt" + exec "internal/execabs" "internal/lazyregexp" "internal/singleflight" "io/fs" "log" urlpkg "net/url" "os" - "os/exec" "path/filepath" "regexp" "strings" diff --git a/src/cmd/go/internal/vet/vetflag.go b/src/cmd/go/internal/vet/vetflag.go index ef995ef835..5bf5cf4446 100644 --- a/src/cmd/go/internal/vet/vetflag.go +++ b/src/cmd/go/internal/vet/vetflag.go @@ -10,9 +10,9 @@ import ( "errors" "flag" "fmt" + exec "internal/execabs" "log" "os" - "os/exec" "path/filepath" "strings" diff --git a/src/cmd/go/internal/work/build.go b/src/cmd/go/internal/work/build.go index 873d85de4e..780d639c5d 100644 --- a/src/cmd/go/internal/work/build.go +++ b/src/cmd/go/internal/work/build.go @@ -9,9 +9,9 @@ import ( "errors" "fmt" "go/build" + exec "internal/execabs" "internal/goroot" "os" - "os/exec" "path" "path/filepath" "runtime" diff --git a/src/cmd/go/internal/work/buildid.go b/src/cmd/go/internal/work/buildid.go index d76988145b..c555d4a9f1 100644 --- a/src/cmd/go/internal/work/buildid.go +++ b/src/cmd/go/internal/work/buildid.go @@ -7,8 +7,8 @@ package work import ( "bytes" "fmt" + exec "internal/execabs" "os" - "os/exec" "strings" "cmd/go/internal/base" diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index e750904266..16a4ebaa0f 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -13,13 +13,13 @@ import ( "encoding/json" "errors" "fmt" + exec "internal/execabs" "internal/lazyregexp" "io" "io/fs" "log" "math/rand" "os" - "os/exec" "path/filepath" "regexp" "runtime" diff --git a/src/cmd/go/internal/work/gccgo.go b/src/cmd/go/internal/work/gccgo.go index 45ff7c9838..b58c8aa885 100644 --- a/src/cmd/go/internal/work/gccgo.go +++ b/src/cmd/go/internal/work/gccgo.go @@ -6,8 +6,8 @@ package work import ( "fmt" + exec "internal/execabs" "os" - "os/exec" "path/filepath" "strings" "sync" diff --git a/src/cmd/go/testdata/addmod.go b/src/cmd/go/testdata/addmod.go index 58376b7ed4..09fc8e713b 100644 --- a/src/cmd/go/testdata/addmod.go +++ b/src/cmd/go/testdata/addmod.go @@ -25,7 +25,7 @@ import ( "io/fs" "log" "os" - "os/exec" + exec "internal/execabs" "path/filepath" "strings" diff --git a/src/cmd/internal/browser/browser.go b/src/cmd/internal/browser/browser.go index 6867c85d23..577d31789f 100644 --- a/src/cmd/internal/browser/browser.go +++ b/src/cmd/internal/browser/browser.go @@ -6,8 +6,8 @@ package browser import ( + exec "internal/execabs" "os" - "os/exec" "runtime" "time" ) diff --git a/src/cmd/internal/diff/diff.go b/src/cmd/internal/diff/diff.go index e9d2c23780..c0ca2f3106 100644 --- a/src/cmd/internal/diff/diff.go +++ b/src/cmd/internal/diff/diff.go @@ -7,9 +7,9 @@ package diff import ( + exec "internal/execabs" "io/ioutil" "os" - "os/exec" "runtime" ) diff --git a/src/cmd/internal/dwarf/dwarf.go b/src/cmd/internal/dwarf/dwarf.go index e1a70ef853..8de4096f06 100644 --- a/src/cmd/internal/dwarf/dwarf.go +++ b/src/cmd/internal/dwarf/dwarf.go @@ -12,7 +12,7 @@ import ( "cmd/internal/objabi" "errors" "fmt" - "os/exec" + exec "internal/execabs" "sort" "strconv" "strings" diff --git a/src/cmd/internal/pkgpath/pkgpath.go b/src/cmd/internal/pkgpath/pkgpath.go index 40a040a81a..72e3bdb631 100644 --- a/src/cmd/internal/pkgpath/pkgpath.go +++ b/src/cmd/internal/pkgpath/pkgpath.go @@ -10,9 +10,9 @@ import ( "bytes" "errors" "fmt" + exec "internal/execabs" "io/ioutil" "os" - "os/exec" "strings" ) diff --git a/src/cmd/link/internal/ld/execarchive.go b/src/cmd/link/internal/ld/execarchive.go index fe5cc40865..4687c624de 100644 --- a/src/cmd/link/internal/ld/execarchive.go +++ b/src/cmd/link/internal/ld/execarchive.go @@ -7,8 +7,8 @@ package ld import ( + exec "internal/execabs" "os" - "os/exec" "path/filepath" "syscall" ) diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 014969664b..17d5040827 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -49,11 +49,11 @@ import ( "encoding/base64" "encoding/binary" "fmt" + exec "internal/execabs" "io" "io/ioutil" "log" "os" - "os/exec" "path/filepath" "runtime" "sort" diff --git a/src/cmd/test2json/main.go b/src/cmd/test2json/main.go index e40881ab3f..fdf681a8ff 100644 --- a/src/cmd/test2json/main.go +++ b/src/cmd/test2json/main.go @@ -86,9 +86,9 @@ package main import ( "flag" "fmt" + exec "internal/execabs" "io" "os" - "os/exec" "cmd/internal/test2json" ) diff --git a/src/cmd/trace/pprof.go b/src/cmd/trace/pprof.go index a73ff5336a..c4d3742820 100644 --- a/src/cmd/trace/pprof.go +++ b/src/cmd/trace/pprof.go @@ -9,11 +9,11 @@ package main import ( "bufio" "fmt" + exec "internal/execabs" "internal/trace" "io" "net/http" "os" - "os/exec" "path/filepath" "runtime" "sort" diff --git a/src/go/build/build.go b/src/go/build/build.go index 72311c7d2c..217fadf5bd 100644 --- a/src/go/build/build.go +++ b/src/go/build/build.go @@ -11,13 +11,13 @@ import ( "go/ast" "go/doc" "go/token" + exec "internal/execabs" "internal/goroot" "internal/goversion" "io" "io/fs" "io/ioutil" "os" - "os/exec" pathpkg "path" "path/filepath" "runtime" diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index 99cd59e5b5..c97c668cc4 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -178,7 +178,7 @@ var depsRules = ` reflect !< OS; OS - < golang.org/x/sys/cpu, internal/goroot; + < golang.org/x/sys/cpu; # FMT is OS (which includes string routines) plus reflect and fmt. # It does not include package log, which should be avoided in core packages. @@ -194,6 +194,12 @@ var depsRules = ` log !< FMT; + OS, FMT + < internal/execabs; + + OS, internal/execabs + < internal/goroot; + # Misc packages needing only FMT. FMT < flag, diff --git a/src/go/internal/gccgoimporter/gccgoinstallation.go b/src/go/internal/gccgoimporter/gccgoinstallation.go index 8fc7ce3232..e90a3cc0b0 100644 --- a/src/go/internal/gccgoimporter/gccgoinstallation.go +++ b/src/go/internal/gccgoimporter/gccgoinstallation.go @@ -7,8 +7,8 @@ package gccgoimporter import ( "bufio" "go/types" + exec "internal/execabs" "os" - "os/exec" "path/filepath" "strings" ) diff --git a/src/go/internal/srcimporter/srcimporter.go b/src/go/internal/srcimporter/srcimporter.go index c4d501dcd9..438ae0ff2e 100644 --- a/src/go/internal/srcimporter/srcimporter.go +++ b/src/go/internal/srcimporter/srcimporter.go @@ -13,9 +13,9 @@ import ( "go/parser" "go/token" "go/types" + exec "internal/execabs" "io" "os" - "os/exec" "path/filepath" "strings" "sync" diff --git a/src/internal/execabs/execabs.go b/src/internal/execabs/execabs.go new file mode 100644 index 0000000000..9a05d971da --- /dev/null +++ b/src/internal/execabs/execabs.go @@ -0,0 +1,70 @@ +// Copyright 2021 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 execabs is a drop-in replacement for os/exec +// that requires PATH lookups to find absolute paths. +// That is, execabs.Command("cmd") runs the same PATH lookup +// as exec.Command("cmd"), but if the result is a path +// which is relative, the Run and Start methods will report +// an error instead of running the executable. +package execabs + +import ( + "context" + "fmt" + "os/exec" + "path/filepath" + "reflect" + "unsafe" +) + +var ErrNotFound = exec.ErrNotFound + +type ( + Cmd = exec.Cmd + Error = exec.Error + ExitError = exec.ExitError +) + +func relError(file, path string) error { + return fmt.Errorf("%s resolves to executable relative to current directory (.%c%s)", file, filepath.Separator, path) +} + +func LookPath(file string) (string, error) { + path, err := exec.LookPath(file) + if err != nil { + return "", err + } + if filepath.Base(file) == file && !filepath.IsAbs(path) { + return "", relError(file, path) + } + return path, nil +} + +func fixCmd(name string, cmd *exec.Cmd) { + if filepath.Base(name) == name && !filepath.IsAbs(cmd.Path) { + // exec.Command was called with a bare binary name and + // exec.LookPath returned a path which is not absolute. + // Set cmd.lookPathErr and clear cmd.Path so that it + // cannot be run. + lookPathErr := (*error)(unsafe.Pointer(reflect.ValueOf(cmd).Elem().FieldByName("lookPathErr").Addr().Pointer())) + if *lookPathErr == nil { + *lookPathErr = relError(name, cmd.Path) + } + cmd.Path = "" + } +} + +func CommandContext(ctx context.Context, name string, arg ...string) *exec.Cmd { + cmd := exec.CommandContext(ctx, name, arg...) + fixCmd(name, cmd) + return cmd + +} + +func Command(name string, arg ...string) *exec.Cmd { + cmd := exec.Command(name, arg...) + fixCmd(name, cmd) + return cmd +} diff --git a/src/internal/execabs/execabs_test.go b/src/internal/execabs/execabs_test.go new file mode 100644 index 0000000000..b71458587c --- /dev/null +++ b/src/internal/execabs/execabs_test.go @@ -0,0 +1,104 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package execabs + +import ( + "context" + "fmt" + "internal/testenv" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "runtime" + "testing" +) + +func TestFixCmd(t *testing.T) { + cmd := &exec.Cmd{Path: "hello"} + fixCmd("hello", cmd) + if cmd.Path != "" { + t.Error("fixCmd didn't clear cmd.Path") + } + expectedErr := fmt.Sprintf("hello resolves to executable relative to current directory (.%chello)", filepath.Separator) + if err := cmd.Run(); err == nil { + t.Fatal("Command.Run didn't fail") + } else if err.Error() != expectedErr { + t.Fatalf("Command.Run returned unexpected error: want %q, got %q", expectedErr, err.Error()) + } +} + +func TestCommand(t *testing.T) { + testenv.MustHaveExec(t) + + for _, cmd := range []func(string) *Cmd{ + func(s string) *Cmd { return Command(s) }, + func(s string) *Cmd { return CommandContext(context.Background(), s) }, + } { + tmpDir := t.TempDir() + executable := "execabs-test" + if runtime.GOOS == "windows" { + executable += ".exe" + } + if err := ioutil.WriteFile(filepath.Join(tmpDir, executable), []byte{1, 2, 3}, 0111); err != nil { + t.Fatalf("ioutil.WriteFile failed: %s", err) + } + cwd, err := os.Getwd() + if err != nil { + t.Fatalf("os.Getwd failed: %s", err) + } + defer os.Chdir(cwd) + if err = os.Chdir(tmpDir); err != nil { + t.Fatalf("os.Chdir failed: %s", err) + } + if runtime.GOOS != "windows" { + // add "." to PATH so that exec.LookPath looks in the current directory on + // non-windows platforms as well + origPath := os.Getenv("PATH") + defer os.Setenv("PATH", origPath) + os.Setenv("PATH", fmt.Sprintf(".:%s", origPath)) + } + expectedErr := fmt.Sprintf("execabs-test resolves to executable relative to current directory (.%c%s)", filepath.Separator, executable) + if err = cmd("execabs-test").Run(); err == nil { + t.Fatalf("Command.Run didn't fail when exec.LookPath returned a relative path") + } else if err.Error() != expectedErr { + t.Errorf("Command.Run returned unexpected error: want %q, got %q", expectedErr, err.Error()) + } + } +} + +func TestLookPath(t *testing.T) { + testenv.MustHaveExec(t) + + tmpDir := t.TempDir() + executable := "execabs-test" + if runtime.GOOS == "windows" { + executable += ".exe" + } + if err := ioutil.WriteFile(filepath.Join(tmpDir, executable), []byte{1, 2, 3}, 0111); err != nil { + t.Fatalf("ioutil.WriteFile failed: %s", err) + } + cwd, err := os.Getwd() + if err != nil { + t.Fatalf("os.Getwd failed: %s", err) + } + defer os.Chdir(cwd) + if err = os.Chdir(tmpDir); err != nil { + t.Fatalf("os.Chdir failed: %s", err) + } + if runtime.GOOS != "windows" { + // add "." to PATH so that exec.LookPath looks in the current directory on + // non-windows platforms as well + origPath := os.Getenv("PATH") + defer os.Setenv("PATH", origPath) + os.Setenv("PATH", fmt.Sprintf(".:%s", origPath)) + } + expectedErr := fmt.Sprintf("execabs-test resolves to executable relative to current directory (.%c%s)", filepath.Separator, executable) + if _, err := LookPath("execabs-test"); err == nil { + t.Fatalf("LookPath didn't fail when finding a non-relative path") + } else if err.Error() != expectedErr { + t.Errorf("LookPath returned unexpected error: want %q, got %q", expectedErr, err.Error()) + } +} diff --git a/src/internal/goroot/gc.go b/src/internal/goroot/gc.go index 0f541d734b..ce72bc3896 100644 --- a/src/internal/goroot/gc.go +++ b/src/internal/goroot/gc.go @@ -7,8 +7,8 @@ package goroot import ( + exec "internal/execabs" "os" - "os/exec" "path/filepath" "strings" "sync" -- cgit v1.3-5-g9baa From cd99385ff4a4b7534c71bb92420da6f462c5598e Mon Sep 17 00:00:00 2001 From: eric fang Date: Thu, 14 Jan 2021 07:14:02 +0000 Subject: cmd/internal/obj/arm64: fix VMOVQ instruction encoding error The VMOVQ instruction moves a 128-bit constant into a V register, as 128-bit constant can't be loaded into a register directly, we split it into two 64-bit constants and load it from constant pool. Currently we add the 128-bit constant to literal pool by calling the 'addpool' function twice, this is not the right way because it doesn't guarantee the two DWORD instructions are consecutive, and the second call of addpool will overwrite the p.Pool field,resulting in a wrong PC-relative offset value of the Prog. This CL renames the flag LFROM3 to LFROM128, and adds a new function addpool128 to add a 128-bit constant to the literal pool. Change-Id: I616f043c99a9a18a663f8768842cc980de2e6f79 Reviewed-on: https://go-review.googlesource.com/c/go/+/282334 Reviewed-by: eric fang Reviewed-by: Cherry Zhang Run-TryBot: eric fang Trust: eric fang --- src/cmd/internal/obj/arm64/asm7.go | 38 ++++++- src/cmd/internal/obj/arm64/asm_arm64_test.go | 162 +++++++++++++++++++++++++++ src/cmd/internal/obj/arm64/asm_arm64_test.s | 14 +++ src/cmd/internal/obj/arm64/asm_test.go | 152 ------------------------- 4 files changed, 210 insertions(+), 156 deletions(-) create mode 100644 src/cmd/internal/obj/arm64/asm_arm64_test.go create mode 100644 src/cmd/internal/obj/arm64/asm_arm64_test.s delete mode 100644 src/cmd/internal/obj/arm64/asm_test.go (limited to 'src/cmd/internal') diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go index 1a359f1921..70072cfba4 100644 --- a/src/cmd/internal/obj/arm64/asm7.go +++ b/src/cmd/internal/obj/arm64/asm7.go @@ -280,7 +280,7 @@ func MOVCONST(d int64, s int, rt int) uint32 { const ( // Optab.flag LFROM = 1 << 0 // p.From uses constant pool - LFROM3 = 1 << 1 // p.From3 uses constant pool + LFROM128 = 1 << 1 // p.From3<<64+p.From forms a 128-bit constant in literal pool LTO = 1 << 2 // p.To uses constant pool NOTUSETMP = 1 << 3 // p expands to multiple instructions, but does NOT use REGTMP ) @@ -419,7 +419,7 @@ var optab = []Optab{ {AMOVD, C_LACON, C_NONE, C_NONE, C_RSP, 34, 8, REGSP, LFROM, 0}, // Move a large constant to a vector register. - {AVMOVQ, C_VCON, C_NONE, C_VCON, C_VREG, 101, 4, 0, LFROM | LFROM3, 0}, + {AVMOVQ, C_VCON, C_NONE, C_VCON, C_VREG, 101, 4, 0, LFROM128, 0}, {AVMOVD, C_VCON, C_NONE, C_NONE, C_VREG, 101, 4, 0, LFROM, 0}, {AVMOVS, C_LCON, C_NONE, C_NONE, C_VREG, 101, 4, 0, LFROM, 0}, @@ -995,8 +995,8 @@ func span7(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { if o.flag&LFROM != 0 { c.addpool(p, &p.From) } - if o.flag&LFROM3 != 0 { - c.addpool(p, p.GetFrom3()) + if o.flag&LFROM128 != 0 { + c.addpool128(p, &p.From, p.GetFrom3()) } if o.flag<O != 0 { c.addpool(p, &p.To) @@ -1201,6 +1201,36 @@ func (c *ctxt7) flushpool(p *obj.Prog, skip int) { } } +// addpool128 adds a 128-bit constant to literal pool by two consecutive DWORD +// instructions, the 128-bit constant is formed by ah.Offset<<64+al.Offset. +func (c *ctxt7) addpool128(p *obj.Prog, al, ah *obj.Addr) { + lit := al.Offset + q := c.newprog() + q.As = ADWORD + q.To.Type = obj.TYPE_CONST + q.To.Offset = lit + q.Pc = int64(c.pool.size) + + lit = ah.Offset + t := c.newprog() + t.As = ADWORD + t.To.Type = obj.TYPE_CONST + t.To.Offset = lit + t.Pc = int64(c.pool.size + 8) + q.Link = t + + if c.blitrl == nil { + c.blitrl = q + c.pool.start = uint32(p.Pc) + } else { + c.elitrl.Link = q + } + + c.elitrl = t + c.pool.size += 16 + p.Pool = q +} + /* * MOVD foo(SB), R is actually * MOVD addr, REGTMP diff --git a/src/cmd/internal/obj/arm64/asm_arm64_test.go b/src/cmd/internal/obj/arm64/asm_arm64_test.go new file mode 100644 index 0000000000..c6a00f5b94 --- /dev/null +++ b/src/cmd/internal/obj/arm64/asm_arm64_test.go @@ -0,0 +1,162 @@ +// Copyright 2016 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 arm64 + +import ( + "bytes" + "fmt" + "internal/testenv" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "regexp" + "testing" +) + +// TestLarge generates a very large file to verify that large +// program builds successfully, in particular, too-far +// conditional branches are fixed, and also verify that the +// instruction's pc can be correctly aligned even when branches +// need to be fixed. +func TestLarge(t *testing.T) { + if testing.Short() { + t.Skip("Skip in short mode") + } + testenv.MustHaveGoBuild(t) + + dir, err := ioutil.TempDir("", "testlarge") + if err != nil { + t.Fatalf("could not create directory: %v", err) + } + defer os.RemoveAll(dir) + + // generate a very large function + buf := bytes.NewBuffer(make([]byte, 0, 7000000)) + gen(buf) + + tmpfile := filepath.Join(dir, "x.s") + err = ioutil.WriteFile(tmpfile, buf.Bytes(), 0644) + if err != nil { + t.Fatalf("can't write output: %v\n", err) + } + + pattern := `0x0080\s00128\s\(.*\)\tMOVD\t\$3,\sR3` + + // assemble generated file + cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-S", "-o", filepath.Join(dir, "test.o"), tmpfile) + cmd.Env = append(os.Environ(), "GOOS=linux") + out, err := cmd.CombinedOutput() + if err != nil { + t.Errorf("Assemble failed: %v, output: %s", err, out) + } + matched, err := regexp.MatchString(pattern, string(out)) + if err != nil { + t.Fatal(err) + } + if !matched { + t.Errorf("The alignment is not correct: %t, output:%s\n", matched, out) + } + + // build generated file + cmd = exec.Command(testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "x.o"), tmpfile) + cmd.Env = append(os.Environ(), "GOOS=linux") + out, err = cmd.CombinedOutput() + if err != nil { + t.Errorf("Build failed: %v, output: %s", err, out) + } +} + +// gen generates a very large program, with a very far conditional branch. +func gen(buf *bytes.Buffer) { + fmt.Fprintln(buf, "TEXT f(SB),0,$0-0") + fmt.Fprintln(buf, "TBZ $5, R0, label") + fmt.Fprintln(buf, "CBZ R0, label") + fmt.Fprintln(buf, "BEQ label") + fmt.Fprintln(buf, "PCALIGN $128") + fmt.Fprintln(buf, "MOVD $3, R3") + for i := 0; i < 1<<19; i++ { + fmt.Fprintln(buf, "MOVD R0, R1") + } + fmt.Fprintln(buf, "label:") + fmt.Fprintln(buf, "RET") +} + +// Issue 20348. +func TestNoRet(t *testing.T) { + dir, err := ioutil.TempDir("", "testnoret") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + tmpfile := filepath.Join(dir, "x.s") + if err := ioutil.WriteFile(tmpfile, []byte("TEXT ·stub(SB),$0-0\nNOP\n"), 0644); err != nil { + t.Fatal(err) + } + cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "x.o"), tmpfile) + cmd.Env = append(os.Environ(), "GOOS=linux") + if out, err := cmd.CombinedOutput(); err != nil { + t.Errorf("%v\n%s", err, out) + } +} + +// TestPCALIGN verifies the correctness of the PCALIGN by checking if the +// code can be aligned to the alignment value. +func TestPCALIGN(t *testing.T) { + testenv.MustHaveGoBuild(t) + dir, err := ioutil.TempDir("", "testpcalign") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + tmpfile := filepath.Join(dir, "test.s") + tmpout := filepath.Join(dir, "test.o") + + code1 := []byte("TEXT ·foo(SB),$0-0\nMOVD $0, R0\nPCALIGN $8\nMOVD $1, R1\nRET\n") + code2 := []byte("TEXT ·foo(SB),$0-0\nMOVD $0, R0\nPCALIGN $16\nMOVD $2, R2\nRET\n") + // If the output contains this pattern, the pc-offsite of "MOVD $1, R1" is 8 bytes aligned. + out1 := `0x0008\s00008\s\(.*\)\tMOVD\t\$1,\sR1` + // If the output contains this pattern, the pc-offsite of "MOVD $2, R2" is 16 bytes aligned. + out2 := `0x0010\s00016\s\(.*\)\tMOVD\t\$2,\sR2` + var testCases = []struct { + name string + code []byte + out string + }{ + {"8-byte alignment", code1, out1}, + {"16-byte alignment", code2, out2}, + } + + for _, test := range testCases { + if err := ioutil.WriteFile(tmpfile, test.code, 0644); err != nil { + t.Fatal(err) + } + cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-S", "-o", tmpout, tmpfile) + cmd.Env = append(os.Environ(), "GOOS=linux") + out, err := cmd.CombinedOutput() + if err != nil { + t.Errorf("The %s build failed: %v, output: %s", test.name, err, out) + continue + } + + matched, err := regexp.MatchString(test.out, string(out)) + if err != nil { + t.Fatal(err) + } + if !matched { + t.Errorf("The %s testing failed!\ninput: %s\noutput: %s\n", test.name, test.code, out) + } + } +} + +func testvmovq() (r1, r2 uint64) + +// TestVMOVQ checks if the arm64 VMOVQ instruction is working properly. +func TestVMOVQ(t *testing.T) { + a, b := testvmovq() + if a != 0x7040201008040201 || b != 0x3040201008040201 { + t.Errorf("TestVMOVQ got: a=0x%x, b=0x%x, want: a=0x7040201008040201, b=0x3040201008040201", a, b) + } +} diff --git a/src/cmd/internal/obj/arm64/asm_arm64_test.s b/src/cmd/internal/obj/arm64/asm_arm64_test.s new file mode 100644 index 0000000000..9d337a4fd1 --- /dev/null +++ b/src/cmd/internal/obj/arm64/asm_arm64_test.s @@ -0,0 +1,14 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "textflag.h" + +// testvmovq() (r1, r2 uint64) +TEXT ·testvmovq(SB), NOSPLIT, $0-16 + VMOVQ $0x7040201008040201, $0x3040201008040201, V1 + VMOV V1.D[0], R0 + VMOV V1.D[1], R1 + MOVD R0, r1+0(FP) + MOVD R1, r2+8(FP) + RET diff --git a/src/cmd/internal/obj/arm64/asm_test.go b/src/cmd/internal/obj/arm64/asm_test.go deleted file mode 100644 index 9efdb0217f..0000000000 --- a/src/cmd/internal/obj/arm64/asm_test.go +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2016 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 arm64 - -import ( - "bytes" - "fmt" - "internal/testenv" - "io/ioutil" - "os" - "os/exec" - "path/filepath" - "regexp" - "testing" -) - -// TestLarge generates a very large file to verify that large -// program builds successfully, in particular, too-far -// conditional branches are fixed, and also verify that the -// instruction's pc can be correctly aligned even when branches -// need to be fixed. -func TestLarge(t *testing.T) { - if testing.Short() { - t.Skip("Skip in short mode") - } - testenv.MustHaveGoBuild(t) - - dir, err := ioutil.TempDir("", "testlarge") - if err != nil { - t.Fatalf("could not create directory: %v", err) - } - defer os.RemoveAll(dir) - - // generate a very large function - buf := bytes.NewBuffer(make([]byte, 0, 7000000)) - gen(buf) - - tmpfile := filepath.Join(dir, "x.s") - err = ioutil.WriteFile(tmpfile, buf.Bytes(), 0644) - if err != nil { - t.Fatalf("can't write output: %v\n", err) - } - - pattern := `0x0080\s00128\s\(.*\)\tMOVD\t\$3,\sR3` - - // assemble generated file - cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-S", "-o", filepath.Join(dir, "test.o"), tmpfile) - cmd.Env = append(os.Environ(), "GOARCH=arm64", "GOOS=linux") - out, err := cmd.CombinedOutput() - if err != nil { - t.Errorf("Assemble failed: %v, output: %s", err, out) - } - matched, err := regexp.MatchString(pattern, string(out)) - if err != nil { - t.Fatal(err) - } - if !matched { - t.Errorf("The alignment is not correct: %t, output:%s\n", matched, out) - } - - // build generated file - cmd = exec.Command(testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "x.o"), tmpfile) - cmd.Env = append(os.Environ(), "GOARCH=arm64", "GOOS=linux") - out, err = cmd.CombinedOutput() - if err != nil { - t.Errorf("Build failed: %v, output: %s", err, out) - } -} - -// gen generates a very large program, with a very far conditional branch. -func gen(buf *bytes.Buffer) { - fmt.Fprintln(buf, "TEXT f(SB),0,$0-0") - fmt.Fprintln(buf, "TBZ $5, R0, label") - fmt.Fprintln(buf, "CBZ R0, label") - fmt.Fprintln(buf, "BEQ label") - fmt.Fprintln(buf, "PCALIGN $128") - fmt.Fprintln(buf, "MOVD $3, R3") - for i := 0; i < 1<<19; i++ { - fmt.Fprintln(buf, "MOVD R0, R1") - } - fmt.Fprintln(buf, "label:") - fmt.Fprintln(buf, "RET") -} - -// Issue 20348. -func TestNoRet(t *testing.T) { - dir, err := ioutil.TempDir("", "testnoret") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) - tmpfile := filepath.Join(dir, "x.s") - if err := ioutil.WriteFile(tmpfile, []byte("TEXT ·stub(SB),$0-0\nNOP\n"), 0644); err != nil { - t.Fatal(err) - } - cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "x.o"), tmpfile) - cmd.Env = append(os.Environ(), "GOARCH=arm64", "GOOS=linux") - if out, err := cmd.CombinedOutput(); err != nil { - t.Errorf("%v\n%s", err, out) - } -} - -// TestPCALIGN verifies the correctness of the PCALIGN by checking if the -// code can be aligned to the alignment value. -func TestPCALIGN(t *testing.T) { - testenv.MustHaveGoBuild(t) - dir, err := ioutil.TempDir("", "testpcalign") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(dir) - tmpfile := filepath.Join(dir, "test.s") - tmpout := filepath.Join(dir, "test.o") - - code1 := []byte("TEXT ·foo(SB),$0-0\nMOVD $0, R0\nPCALIGN $8\nMOVD $1, R1\nRET\n") - code2 := []byte("TEXT ·foo(SB),$0-0\nMOVD $0, R0\nPCALIGN $16\nMOVD $2, R2\nRET\n") - // If the output contains this pattern, the pc-offsite of "MOVD $1, R1" is 8 bytes aligned. - out1 := `0x0008\s00008\s\(.*\)\tMOVD\t\$1,\sR1` - // If the output contains this pattern, the pc-offsite of "MOVD $2, R2" is 16 bytes aligned. - out2 := `0x0010\s00016\s\(.*\)\tMOVD\t\$2,\sR2` - var testCases = []struct { - name string - code []byte - out string - }{ - {"8-byte alignment", code1, out1}, - {"16-byte alignment", code2, out2}, - } - - for _, test := range testCases { - if err := ioutil.WriteFile(tmpfile, test.code, 0644); err != nil { - t.Fatal(err) - } - cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-S", "-o", tmpout, tmpfile) - cmd.Env = append(os.Environ(), "GOARCH=arm64", "GOOS=linux") - out, err := cmd.CombinedOutput() - if err != nil { - t.Errorf("The %s build failed: %v, output: %s", test.name, err, out) - continue - } - - matched, err := regexp.MatchString(test.out, string(out)) - if err != nil { - t.Fatal(err) - } - if !matched { - t.Errorf("The %s testing failed!\ninput: %s\noutput: %s\n", test.name, test.code, out) - } - } -} -- cgit v1.3-5-g9baa From 063c72f06d8673f3a2a03fd549c61935ca3e5cc5 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Sun, 24 Jan 2021 10:52:00 -0800 Subject: [dev.regabi] cmd/compile: backport changes from dev.typeparams (9456804) This CL backports a bunch of changes that landed on dev.typeparams, but are not dependent on types2 or generics. By backporting, we reduce the divergence between development branches, hopefully improving test coverage and reducing risk of merge conflicts. Updates #43866. Change-Id: I382510855c9b5fac52b17066e44a00bd07fe86f5 Reviewed-on: https://go-review.googlesource.com/c/go/+/286172 Trust: Matthew Dempsky Trust: Robert Griesemer Run-TryBot: Matthew Dempsky Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/dwarfgen/marker.go | 94 +++++++++ src/cmd/compile/internal/noder/import.go | 239 ++++++++++----------- src/cmd/compile/internal/noder/noder.go | 268 ++++++++---------------- src/cmd/compile/internal/noder/posmap.go | 83 ++++++++ src/cmd/compile/internal/reflectdata/reflect.go | 2 +- src/cmd/compile/internal/typecheck/dcl.go | 5 +- src/cmd/compile/internal/typecheck/func.go | 4 +- src/cmd/compile/internal/typecheck/subr.go | 7 +- src/cmd/compile/internal/typecheck/typecheck.go | 8 +- src/cmd/compile/internal/types/pkg.go | 3 +- src/cmd/compile/internal/types/scope.go | 2 +- src/cmd/compile/internal/walk/walk.go | 5 + src/cmd/internal/obj/link.go | 6 +- test/fixedbugs/issue11362.go | 2 +- 14 files changed, 398 insertions(+), 330 deletions(-) create mode 100644 src/cmd/compile/internal/dwarfgen/marker.go create mode 100644 src/cmd/compile/internal/noder/posmap.go (limited to 'src/cmd/internal') diff --git a/src/cmd/compile/internal/dwarfgen/marker.go b/src/cmd/compile/internal/dwarfgen/marker.go new file mode 100644 index 0000000000..ec6ce45a90 --- /dev/null +++ b/src/cmd/compile/internal/dwarfgen/marker.go @@ -0,0 +1,94 @@ +// Copyright 2021 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 dwarfgen + +import ( + "cmd/compile/internal/base" + "cmd/compile/internal/ir" + "cmd/internal/src" +) + +// A ScopeMarker tracks scope nesting and boundaries for later use +// during DWARF generation. +type ScopeMarker struct { + parents []ir.ScopeID + marks []ir.Mark +} + +// checkPos validates the given position and returns the current scope. +func (m *ScopeMarker) checkPos(pos src.XPos) ir.ScopeID { + if !pos.IsKnown() { + base.Fatalf("unknown scope position") + } + + if len(m.marks) == 0 { + return 0 + } + + last := &m.marks[len(m.marks)-1] + if xposBefore(pos, last.Pos) { + base.FatalfAt(pos, "non-monotonic scope positions\n\t%v: previous scope position", base.FmtPos(last.Pos)) + } + return last.Scope +} + +// Push records a transition to a new child scope of the current scope. +func (m *ScopeMarker) Push(pos src.XPos) { + current := m.checkPos(pos) + + m.parents = append(m.parents, current) + child := ir.ScopeID(len(m.parents)) + + m.marks = append(m.marks, ir.Mark{Pos: pos, Scope: child}) +} + +// Pop records a transition back to the current scope's parent. +func (m *ScopeMarker) Pop(pos src.XPos) { + current := m.checkPos(pos) + + parent := m.parents[current-1] + + m.marks = append(m.marks, ir.Mark{Pos: pos, Scope: parent}) +} + +// Unpush removes the current scope, which must be empty. +func (m *ScopeMarker) Unpush() { + i := len(m.marks) - 1 + current := m.marks[i].Scope + + if current != ir.ScopeID(len(m.parents)) { + base.FatalfAt(m.marks[i].Pos, "current scope is not empty") + } + + m.parents = m.parents[:current-1] + m.marks = m.marks[:i] +} + +// WriteTo writes the recorded scope marks to the given function, +// and resets the marker for reuse. +func (m *ScopeMarker) WriteTo(fn *ir.Func) { + m.compactMarks() + + fn.Parents = make([]ir.ScopeID, len(m.parents)) + copy(fn.Parents, m.parents) + m.parents = m.parents[:0] + + fn.Marks = make([]ir.Mark, len(m.marks)) + copy(fn.Marks, m.marks) + m.marks = m.marks[:0] +} + +func (m *ScopeMarker) compactMarks() { + n := 0 + for _, next := range m.marks { + if n > 0 && next.Pos == m.marks[n-1].Pos { + m.marks[n-1].Scope = next.Scope + continue + } + m.marks[n] = next + n++ + } + m.marks = m.marks[:n] +} diff --git a/src/cmd/compile/internal/noder/import.go b/src/cmd/compile/internal/noder/import.go index ca041a156c..747c30e6ff 100644 --- a/src/cmd/compile/internal/noder/import.go +++ b/src/cmd/compile/internal/noder/import.go @@ -5,18 +5,20 @@ package noder import ( + "errors" "fmt" - "go/constant" "os" - "path" + pathpkg "path" "runtime" "sort" + "strconv" "strings" "unicode" "unicode/utf8" "cmd/compile/internal/base" "cmd/compile/internal/ir" + "cmd/compile/internal/syntax" "cmd/compile/internal/typecheck" "cmd/compile/internal/types" "cmd/internal/archive" @@ -38,160 +40,157 @@ func islocalname(name string) bool { strings.HasPrefix(name, "../") || name == ".." } -func findpkg(name string) (file string, ok bool) { - if islocalname(name) { +func openPackage(path string) (*os.File, error) { + if islocalname(path) { if base.Flag.NoLocalImports { - return "", false + return nil, errors.New("local imports disallowed") } if base.Flag.Cfg.PackageFile != nil { - file, ok = base.Flag.Cfg.PackageFile[name] - return file, ok + return os.Open(base.Flag.Cfg.PackageFile[path]) } - // try .a before .6. important for building libraries: - // if there is an array.6 in the array.a library, - // want to find all of array.a, not just array.6. - file = fmt.Sprintf("%s.a", name) - if _, err := os.Stat(file); err == nil { - return file, true + // try .a before .o. important for building libraries: + // if there is an array.o in the array.a library, + // want to find all of array.a, not just array.o. + if file, err := os.Open(fmt.Sprintf("%s.a", path)); err == nil { + return file, nil } - file = fmt.Sprintf("%s.o", name) - if _, err := os.Stat(file); err == nil { - return file, true + if file, err := os.Open(fmt.Sprintf("%s.o", path)); err == nil { + return file, nil } - return "", false + return nil, errors.New("file not found") } // local imports should be canonicalized already. // don't want to see "encoding/../encoding/base64" // as different from "encoding/base64". - if q := path.Clean(name); q != name { - base.Errorf("non-canonical import path %q (should be %q)", name, q) - return "", false + if q := pathpkg.Clean(path); q != path { + return nil, fmt.Errorf("non-canonical import path %q (should be %q)", path, q) } if base.Flag.Cfg.PackageFile != nil { - file, ok = base.Flag.Cfg.PackageFile[name] - return file, ok + return os.Open(base.Flag.Cfg.PackageFile[path]) } for _, dir := range base.Flag.Cfg.ImportDirs { - file = fmt.Sprintf("%s/%s.a", dir, name) - if _, err := os.Stat(file); err == nil { - return file, true + if file, err := os.Open(fmt.Sprintf("%s/%s.a", dir, path)); err == nil { + return file, nil } - file = fmt.Sprintf("%s/%s.o", dir, name) - if _, err := os.Stat(file); err == nil { - return file, true + if file, err := os.Open(fmt.Sprintf("%s/%s.o", dir, path)); err == nil { + return file, nil } } if objabi.GOROOT != "" { suffix := "" - suffixsep := "" if base.Flag.InstallSuffix != "" { - suffixsep = "_" - suffix = base.Flag.InstallSuffix + suffix = "_" + base.Flag.InstallSuffix } else if base.Flag.Race { - suffixsep = "_" - suffix = "race" + suffix = "_race" } else if base.Flag.MSan { - suffixsep = "_" - suffix = "msan" + suffix = "_msan" } - file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.a", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffixsep, suffix, name) - if _, err := os.Stat(file); err == nil { - return file, true + if file, err := os.Open(fmt.Sprintf("%s/pkg/%s_%s%s/%s.a", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffix, path)); err == nil { + return file, nil } - file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.o", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffixsep, suffix, name) - if _, err := os.Stat(file); err == nil { - return file, true + if file, err := os.Open(fmt.Sprintf("%s/pkg/%s_%s%s/%s.o", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffix, path)); err == nil { + return file, nil } } - - return "", false + return nil, errors.New("file not found") } // myheight tracks the local package's height based on packages // imported so far. var myheight int -func importfile(f constant.Value) *types.Pkg { - if f.Kind() != constant.String { - base.Errorf("import path must be a string") - return nil - } - - path_ := constant.StringVal(f) - if len(path_) == 0 { - base.Errorf("import path is empty") - return nil - } - - if isbadimport(path_, false) { - return nil - } - +// resolveImportPath resolves an import path as it appears in a Go +// source file to the package's full path. +func resolveImportPath(path string) (string, error) { // The package name main is no longer reserved, // 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 path_ == "main" { - base.Errorf("cannot import \"main\"") - base.ErrorExit() - } - - if base.Ctxt.Pkgpath != "" && path_ == base.Ctxt.Pkgpath { - base.Errorf("import %q while compiling that package (import cycle)", path_) - base.ErrorExit() + if path == "main" { + return "", errors.New("cannot import \"main\"") } - if mapped, ok := base.Flag.Cfg.ImportMap[path_]; ok { - path_ = mapped + if base.Ctxt.Pkgpath != "" && path == base.Ctxt.Pkgpath { + return "", fmt.Errorf("import %q while compiling that package (import cycle)", path) } - if path_ == "unsafe" { - return ir.Pkgs.Unsafe + if mapped, ok := base.Flag.Cfg.ImportMap[path]; ok { + path = mapped } - if islocalname(path_) { - if path_[0] == '/' { - base.Errorf("import path cannot be absolute path") - return nil + if islocalname(path) { + if path[0] == '/' { + return "", errors.New("import path cannot be absolute path") } - prefix := base.Ctxt.Pathname - if base.Flag.D != "" { - prefix = base.Flag.D + prefix := base.Flag.D + if prefix == "" { + // Questionable, but when -D isn't specified, historically we + // resolve local import paths relative to the directory the + // compiler's current directory, not the respective source + // file's directory. + prefix = base.Ctxt.Pathname } - path_ = path.Join(prefix, path_) + path = pathpkg.Join(prefix, path) - if isbadimport(path_, true) { - return nil + if err := checkImportPath(path, true); err != nil { + return "", err } } - file, found := findpkg(path_) - if !found { - base.Errorf("can't find import: %q", path_) - base.ErrorExit() + return path, nil +} + +// TODO(mdempsky): Return an error instead. +func importfile(decl *syntax.ImportDecl) *types.Pkg { + if decl.Path.Kind != syntax.StringLit { + base.Errorf("import path must be a string") + return nil } - importpkg := types.NewPkg(path_, "") - if importpkg.Imported { - return importpkg + path, err := strconv.Unquote(decl.Path.Value) + if err != nil { + base.Errorf("import path must be a string") + return nil + } + + if err := checkImportPath(path, false); err != nil { + base.Errorf("%s", err.Error()) + return nil } - importpkg.Imported = true + path, err = resolveImportPath(path) + if err != nil { + base.Errorf("%s", err) + return nil + } + + importpkg := types.NewPkg(path, "") + if importpkg.Direct { + return importpkg // already fully loaded + } + importpkg.Direct = true + typecheck.Target.Imports = append(typecheck.Target.Imports, importpkg) + + if path == "unsafe" { + return importpkg // initialized with universe + } - imp, err := bio.Open(file) + f, err := openPackage(path) if err != nil { - base.Errorf("can't open import: %q: %v", path_, err) + base.Errorf("could not import %q: %v", path, err) base.ErrorExit() } + imp := bio.NewReader(f) defer imp.Close() + file := f.Name() // check object header p, err := imp.ReadString('\n') @@ -261,12 +260,12 @@ func importfile(f constant.Value) *types.Pkg { var fingerprint goobj.FingerprintType switch c { case '\n': - base.Errorf("cannot import %s: old export format no longer supported (recompile library)", path_) + base.Errorf("cannot import %s: old export format no longer supported (recompile library)", path) return nil case 'B': if base.Debug.Export != 0 { - fmt.Printf("importing %s (%s)\n", path_, file) + fmt.Printf("importing %s (%s)\n", path, file) } imp.ReadByte() // skip \n after $$B @@ -285,17 +284,17 @@ func importfile(f constant.Value) *types.Pkg { fingerprint = typecheck.ReadImports(importpkg, imp) default: - base.Errorf("no import in %q", path_) + base.Errorf("no import in %q", path) base.ErrorExit() } // assume files move (get installed) so don't record the full path if base.Flag.Cfg.PackageFile != nil { // If using a packageFile map, assume path_ can be recorded directly. - base.Ctxt.AddImport(path_, fingerprint) + base.Ctxt.AddImport(path, fingerprint) } else { // For file "/Users/foo/go/pkg/darwin_amd64/math.a" record "math.a". - base.Ctxt.AddImport(file[len(file)-len(path_)-len(".a"):], fingerprint) + base.Ctxt.AddImport(file[len(file)-len(path)-len(".a"):], fingerprint) } if importpkg.Height >= myheight { @@ -315,47 +314,37 @@ var reservedimports = []string{ "type", } -func isbadimport(path string, allowSpace bool) bool { +func checkImportPath(path string, allowSpace bool) error { + if path == "" { + return errors.New("import path is empty") + } + if strings.Contains(path, "\x00") { - base.Errorf("import path contains NUL") - return true + return errors.New("import path contains NUL") } for _, ri := range reservedimports { if path == ri { - base.Errorf("import path %q is reserved and cannot be used", path) - return true + return fmt.Errorf("import path %q is reserved and cannot be used", path) } } for _, r := range path { - if r == utf8.RuneError { - base.Errorf("import path contains invalid UTF-8 sequence: %q", path) - return true - } - - if r < 0x20 || r == 0x7f { - base.Errorf("import path contains control character: %q", path) - return true - } - - if r == '\\' { - base.Errorf("import path contains backslash; use slash: %q", path) - return true - } - - if !allowSpace && unicode.IsSpace(r) { - base.Errorf("import path contains space character: %q", path) - return true - } - - if strings.ContainsRune("!\"#$%&'()*,:;<=>?[]^`{|}", r) { - base.Errorf("import path contains invalid character '%c': %q", r, path) - return true + switch { + case r == utf8.RuneError: + return fmt.Errorf("import path contains invalid UTF-8 sequence: %q", path) + case r < 0x20 || r == 0x7f: + return fmt.Errorf("import path contains control character: %q", path) + case r == '\\': + return fmt.Errorf("import path contains backslash; use slash: %q", path) + case !allowSpace && unicode.IsSpace(r): + return fmt.Errorf("import path contains space character: %q", path) + case strings.ContainsRune("!\"#$%&'()*,:;<=>?[]^`{|}", r): + return fmt.Errorf("import path contains invalid character '%c': %q", r, path) } } - return false + return nil } func pkgnotused(lineno src.XPos, path string, name string) { diff --git a/src/cmd/compile/internal/noder/noder.go b/src/cmd/compile/internal/noder/noder.go index 5bb01895cc..6aab18549a 100644 --- a/src/cmd/compile/internal/noder/noder.go +++ b/src/cmd/compile/internal/noder/noder.go @@ -17,6 +17,7 @@ import ( "unicode/utf8" "cmd/compile/internal/base" + "cmd/compile/internal/dwarfgen" "cmd/compile/internal/ir" "cmd/compile/internal/syntax" "cmd/compile/internal/typecheck" @@ -27,40 +28,26 @@ import ( func LoadPackage(filenames []string) { base.Timer.Start("fe", "parse") - lines := ParseFiles(filenames) - base.Timer.Stop() - base.Timer.AddEvent(int64(lines), "lines") - // Typecheck. - Package() + mode := syntax.CheckBranches - // With all user code typechecked, it's now safe to verify unused dot imports. - CheckDotImports() - base.ExitIfErrors() -} - -// ParseFiles concurrently parses files into *syntax.File structures. -// Each declaration in every *syntax.File is converted to a syntax tree -// and its root represented by *Node is appended to Target.Decls. -// Returns the total count of parsed lines. -func ParseFiles(filenames []string) uint { - noders := make([]*noder, 0, len(filenames)) // Limit the number of simultaneously open files. sem := make(chan struct{}, runtime.GOMAXPROCS(0)+10) - for _, filename := range filenames { - p := &noder{ - basemap: make(map[*syntax.PosBase]*src.PosBase), + noders := make([]*noder, len(filenames)) + for i, filename := range filenames { + p := noder{ err: make(chan syntax.Error), trackScopes: base.Flag.Dwarf, } - noders = append(noders, p) + noders[i] = &p - go func(filename string) { + filename := filename + go func() { sem <- struct{}{} defer func() { <-sem }() defer close(p.err) - base := syntax.NewFileBase(filename) + fbase := syntax.NewFileBase(filename) f, err := os.Open(filename) if err != nil { @@ -69,8 +56,8 @@ func ParseFiles(filenames []string) uint { } defer f.Close() - p.file, _ = syntax.Parse(base, f, p.error, p.pragma, syntax.CheckBranches) // errors are tracked via p.error - }(filename) + p.file, _ = syntax.Parse(fbase, f, p.error, p.pragma, mode) // errors are tracked via p.error + }() } var lines uint @@ -78,30 +65,27 @@ func ParseFiles(filenames []string) uint { for e := range p.err { p.errorAt(e.Pos, "%s", e.Msg) } + lines += p.file.Lines + } + base.Timer.AddEvent(int64(lines), "lines") + for _, p := range noders { p.node() - lines += p.file.Lines p.file = nil // release memory + } - if base.SyntaxErrors() != 0 { - base.ErrorExit() - } - // Always run CheckDclstack here, even when debug_dclstack is not set, as a sanity measure. - types.CheckDclstack() + if base.SyntaxErrors() != 0 { + base.ErrorExit() } + types.CheckDclstack() for _, p := range noders { p.processPragmas() } + // Typecheck. types.LocalPkg.Height = myheight - - return lines -} - -func Package() { typecheck.DeclareUniverse() - typecheck.TypecheckAllowed = true // Process top-level declarations in phases. @@ -166,44 +150,10 @@ func Package() { } // Phase 5: With all user code type-checked, it's now safe to verify map keys. + // With all user code typechecked, it's now safe to verify unused dot imports. typecheck.CheckMapKeys() - -} - -// makeSrcPosBase translates from a *syntax.PosBase to a *src.PosBase. -func (p *noder) makeSrcPosBase(b0 *syntax.PosBase) *src.PosBase { - // fast path: most likely PosBase hasn't changed - if p.basecache.last == b0 { - return p.basecache.base - } - - b1, ok := p.basemap[b0] - if !ok { - fn := b0.Filename() - if b0.IsFileBase() { - b1 = src.NewFileBase(fn, absFilename(fn)) - } else { - // line directive base - p0 := b0.Pos() - p0b := p0.Base() - if p0b == b0 { - panic("infinite recursion in makeSrcPosBase") - } - p1 := src.MakePos(p.makeSrcPosBase(p0b), p0.Line(), p0.Col()) - b1 = src.NewLinePragmaBase(p1, fn, fileh(fn), b0.Line(), b0.Col()) - } - p.basemap[b0] = b1 - } - - // update cache - p.basecache.last = b0 - p.basecache.base = b1 - - return b1 -} - -func (p *noder) makeXPos(pos syntax.Pos) (_ src.XPos) { - return base.Ctxt.PosTable.XPos(src.MakePos(p.makeSrcPosBase(pos.Base()), pos.Line(), pos.Col())) + CheckDotImports() + base.ExitIfErrors() } func (p *noder) errorAt(pos syntax.Pos, format string, args ...interface{}) { @@ -221,31 +171,33 @@ func absFilename(name string) string { // noder transforms package syntax's AST into a Node tree. type noder struct { - basemap map[*syntax.PosBase]*src.PosBase - basecache struct { - last *syntax.PosBase - base *src.PosBase - } + posMap file *syntax.File linknames []linkname pragcgobuf [][]string err chan syntax.Error - scope ir.ScopeID importedUnsafe bool importedEmbed bool + trackScopes bool - // scopeVars is a stack tracking the number of variables declared in the - // current function at the moment each open scope was opened. - trackScopes bool - scopeVars []int + funcState *funcState +} + +// funcState tracks all per-function state to make handling nested +// functions easier. +type funcState struct { + // scopeVars is a stack tracking the number of variables declared in + // the current function at the moment each open scope was opened. + scopeVars []int + marker dwarfgen.ScopeMarker lastCloseScopePos syntax.Pos } func (p *noder) funcBody(fn *ir.Func, block *syntax.BlockStmt) { - oldScope := p.scope - p.scope = 0 + outerFuncState := p.funcState + p.funcState = new(funcState) typecheck.StartFuncBody(fn) if block != nil { @@ -260,62 +212,34 @@ func (p *noder) funcBody(fn *ir.Func, block *syntax.BlockStmt) { } typecheck.FinishFuncBody() - p.scope = oldScope + p.funcState.marker.WriteTo(fn) + p.funcState = outerFuncState } func (p *noder) openScope(pos syntax.Pos) { + fs := p.funcState types.Markdcl() if p.trackScopes { - ir.CurFunc.Parents = append(ir.CurFunc.Parents, p.scope) - p.scopeVars = append(p.scopeVars, len(ir.CurFunc.Dcl)) - p.scope = ir.ScopeID(len(ir.CurFunc.Parents)) - - p.markScope(pos) + fs.scopeVars = append(fs.scopeVars, len(ir.CurFunc.Dcl)) + fs.marker.Push(p.makeXPos(pos)) } } func (p *noder) closeScope(pos syntax.Pos) { - p.lastCloseScopePos = pos + fs := p.funcState + fs.lastCloseScopePos = pos types.Popdcl() if p.trackScopes { - scopeVars := p.scopeVars[len(p.scopeVars)-1] - p.scopeVars = p.scopeVars[:len(p.scopeVars)-1] + scopeVars := fs.scopeVars[len(fs.scopeVars)-1] + fs.scopeVars = fs.scopeVars[:len(fs.scopeVars)-1] if scopeVars == len(ir.CurFunc.Dcl) { // no variables were declared in this scope, so we can retract it. - - if int(p.scope) != len(ir.CurFunc.Parents) { - base.Fatalf("scope tracking inconsistency, no variables declared but scopes were not retracted") - } - - p.scope = ir.CurFunc.Parents[p.scope-1] - ir.CurFunc.Parents = ir.CurFunc.Parents[:len(ir.CurFunc.Parents)-1] - - nmarks := len(ir.CurFunc.Marks) - ir.CurFunc.Marks[nmarks-1].Scope = p.scope - prevScope := ir.ScopeID(0) - if nmarks >= 2 { - prevScope = ir.CurFunc.Marks[nmarks-2].Scope - } - if ir.CurFunc.Marks[nmarks-1].Scope == prevScope { - ir.CurFunc.Marks = ir.CurFunc.Marks[:nmarks-1] - } - return + fs.marker.Unpush() + } else { + fs.marker.Pop(p.makeXPos(pos)) } - - p.scope = ir.CurFunc.Parents[p.scope-1] - - p.markScope(pos) - } -} - -func (p *noder) markScope(pos syntax.Pos) { - xpos := p.makeXPos(pos) - if i := len(ir.CurFunc.Marks); i > 0 && ir.CurFunc.Marks[i-1].Pos == xpos { - ir.CurFunc.Marks[i-1].Scope = p.scope - } else { - ir.CurFunc.Marks = append(ir.CurFunc.Marks, ir.Mark{Pos: xpos, Scope: p.scope}) } } @@ -324,7 +248,7 @@ func (p *noder) markScope(pos syntax.Pos) { // "if" statements, as their implicit blocks always end at the same // position as an explicit block. func (p *noder) closeAnotherScope() { - p.closeScope(p.lastCloseScopePos) + p.closeScope(p.funcState.lastCloseScopePos) } // linkname records a //go:linkname directive. @@ -335,7 +259,6 @@ type linkname struct { } func (p *noder) node() { - types.Block = 1 p.importedUnsafe = false p.importedEmbed = false @@ -404,7 +327,7 @@ func (p *noder) decls(decls []syntax.Decl) (l []ir.Node) { } func (p *noder) importDecl(imp *syntax.ImportDecl) { - if imp.Path.Bad { + if imp.Path == nil || imp.Path.Bad { return // avoid follow-on errors if there was a syntax error } @@ -412,7 +335,7 @@ func (p *noder) importDecl(imp *syntax.ImportDecl) { p.checkUnused(pragma) } - ipkg := importfile(p.basicLit(imp.Path)) + ipkg := importfile(imp) if ipkg == nil { if base.Errors() == 0 { base.Fatalf("phase error in import") @@ -427,11 +350,6 @@ func (p *noder) importDecl(imp *syntax.ImportDecl) { p.importedEmbed = true } - if !ipkg.Direct { - typecheck.Target.Imports = append(typecheck.Target.Imports, ipkg) - } - ipkg.Direct = true - var my *types.Sym if imp.LocalPkgName != nil { my = p.name(imp.LocalPkgName) @@ -465,20 +383,7 @@ func (p *noder) varDecl(decl *syntax.VarDecl) []ir.Node { exprs := p.exprList(decl.Values) if pragma, ok := decl.Pragma.(*pragmas); ok { - if len(pragma.Embeds) > 0 { - if !p.importedEmbed { - // This check can't be done when building the list pragma.Embeds - // because that list is created before the noder starts walking over the file, - // so at that point it hasn't seen the imports. - // We're left to check now, just before applying the //go:embed lines. - for _, e := range pragma.Embeds { - p.errorAt(e.Pos, "//go:embed only allowed in Go files that import \"embed\"") - } - } else { - varEmbed(p, names, typ, exprs, pragma.Embeds) - } - pragma.Embeds = nil - } + varEmbed(p.makeXPos, names[0], decl, pragma, p.importedEmbed) p.checkUnused(pragma) } @@ -1126,9 +1031,16 @@ func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) ir.Node { case *syntax.DeclStmt: return ir.NewBlockStmt(src.NoXPos, p.decls(stmt.DeclList)) case *syntax.AssignStmt: + if stmt.Rhs == syntax.ImplicitOne { + one := constant.MakeInt64(1) + pos := p.pos(stmt) + n := ir.NewAssignOpStmt(pos, p.binOp(stmt.Op), p.expr(stmt.Lhs), ir.NewBasicLit(pos, one)) + n.IncDec = true + return n + } + if stmt.Op != 0 && stmt.Op != syntax.Def { n := ir.NewAssignOpStmt(p.pos(stmt), p.binOp(stmt.Op), p.expr(stmt.Lhs), p.expr(stmt.Rhs)) - n.IncDec = stmt.Rhs == syntax.ImplicitOne return n } @@ -1588,15 +1500,6 @@ func (p *noder) wrapname(n syntax.Node, x ir.Node) ir.Node { return x } -func (p *noder) pos(n syntax.Node) src.XPos { - // TODO(gri): orig.Pos() should always be known - fix package syntax - xpos := base.Pos - if pos := n.Pos(); pos.IsKnown() { - xpos = p.makeXPos(pos) - } - return xpos -} - func (p *noder) setlineno(n syntax.Node) { if n != nil { base.Pos = p.pos(n) @@ -1923,48 +1826,41 @@ func oldname(s *types.Sym) ir.Node { return n } -func varEmbed(p *noder, names []*ir.Name, typ ir.Ntype, exprs []ir.Node, embeds []pragmaEmbed) { - haveEmbed := false - for _, decl := range p.file.DeclList { - imp, ok := decl.(*syntax.ImportDecl) - if !ok { - // imports always come first - break - } - path, _ := strconv.Unquote(imp.Path.Value) - if path == "embed" { - haveEmbed = true - break - } +func varEmbed(makeXPos func(syntax.Pos) src.XPos, name *ir.Name, decl *syntax.VarDecl, pragma *pragmas, haveEmbed bool) { + if pragma.Embeds == nil { + return } - pos := embeds[0].Pos + pragmaEmbeds := pragma.Embeds + pragma.Embeds = nil + pos := makeXPos(pragmaEmbeds[0].Pos) + if !haveEmbed { - p.errorAt(pos, "invalid go:embed: missing import \"embed\"") + base.ErrorfAt(pos, "go:embed only allowed in Go files that import \"embed\"") return } - if len(names) > 1 { - p.errorAt(pos, "go:embed cannot apply to multiple vars") + if len(decl.NameList) > 1 { + base.ErrorfAt(pos, "go:embed cannot apply to multiple vars") return } - if len(exprs) > 0 { - p.errorAt(pos, "go:embed cannot apply to var with initializer") + if decl.Values != nil { + base.ErrorfAt(pos, "go:embed cannot apply to var with initializer") return } - if typ == nil { - // Should not happen, since len(exprs) == 0 now. - p.errorAt(pos, "go:embed cannot apply to var without type") + if decl.Type == nil { + // Should not happen, since Values == nil now. + base.ErrorfAt(pos, "go:embed cannot apply to var without type") return } if typecheck.DeclContext != ir.PEXTERN { - p.errorAt(pos, "go:embed cannot apply to var inside func") + base.ErrorfAt(pos, "go:embed cannot apply to var inside func") return } - v := names[0] - typecheck.Target.Embeds = append(typecheck.Target.Embeds, v) - v.Embed = new([]ir.Embed) - for _, e := range embeds { - *v.Embed = append(*v.Embed, ir.Embed{Pos: p.makeXPos(e.Pos), Patterns: e.Patterns}) + var embeds []ir.Embed + for _, e := range pragmaEmbeds { + embeds = append(embeds, ir.Embed{Pos: makeXPos(e.Pos), Patterns: e.Patterns}) } + typecheck.Target.Embeds = append(typecheck.Target.Embeds, name) + name.Embed = &embeds } diff --git a/src/cmd/compile/internal/noder/posmap.go b/src/cmd/compile/internal/noder/posmap.go new file mode 100644 index 0000000000..a6d3e2d7ef --- /dev/null +++ b/src/cmd/compile/internal/noder/posmap.go @@ -0,0 +1,83 @@ +// Copyright 2021 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 noder + +import ( + "cmd/compile/internal/base" + "cmd/compile/internal/syntax" + "cmd/internal/src" +) + +// A posMap handles mapping from syntax.Pos to src.XPos. +type posMap struct { + bases map[*syntax.PosBase]*src.PosBase + cache struct { + last *syntax.PosBase + base *src.PosBase + } +} + +type poser interface{ Pos() syntax.Pos } +type ender interface{ End() syntax.Pos } + +func (m *posMap) pos(p poser) src.XPos { return m.makeXPos(p.Pos()) } +func (m *posMap) end(p ender) src.XPos { return m.makeXPos(p.End()) } + +func (m *posMap) makeXPos(pos syntax.Pos) src.XPos { + if !pos.IsKnown() { + // TODO(mdempsky): Investigate restoring base.Fatalf. + return src.NoXPos + } + + posBase := m.makeSrcPosBase(pos.Base()) + return base.Ctxt.PosTable.XPos(src.MakePos(posBase, pos.Line(), pos.Col())) +} + +// makeSrcPosBase translates from a *syntax.PosBase to a *src.PosBase. +func (m *posMap) makeSrcPosBase(b0 *syntax.PosBase) *src.PosBase { + // fast path: most likely PosBase hasn't changed + if m.cache.last == b0 { + return m.cache.base + } + + b1, ok := m.bases[b0] + if !ok { + fn := b0.Filename() + if b0.IsFileBase() { + b1 = src.NewFileBase(fn, absFilename(fn)) + } else { + // line directive base + p0 := b0.Pos() + p0b := p0.Base() + if p0b == b0 { + panic("infinite recursion in makeSrcPosBase") + } + p1 := src.MakePos(m.makeSrcPosBase(p0b), p0.Line(), p0.Col()) + b1 = src.NewLinePragmaBase(p1, fn, fileh(fn), b0.Line(), b0.Col()) + } + if m.bases == nil { + m.bases = make(map[*syntax.PosBase]*src.PosBase) + } + m.bases[b0] = b1 + } + + // update cache + m.cache.last = b0 + m.cache.base = b1 + + return b1 +} + +func (m *posMap) join(other *posMap) { + if m.bases == nil { + m.bases = make(map[*syntax.PosBase]*src.PosBase) + } + for k, v := range other.bases { + if m.bases[k] != nil { + base.Fatalf("duplicate posmap bases") + } + m.bases[k] = v + } +} diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index 1ec92e3dd0..3ff14c87f4 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -791,7 +791,7 @@ func dcommontype(lsym *obj.LSym, t *types.Type) int { // TrackSym returns the symbol for tracking use of field/method f, assumed // to be a member of struct/interface type t. func TrackSym(t *types.Type, f *types.Field) *obj.LSym { - return base.PkgLinksym("go.track", t.ShortString() + "." + f.Sym.Name, obj.ABI0) + return base.PkgLinksym("go.track", t.ShortString()+"."+f.Sym.Name, obj.ABI0) } func TypeSymPrefix(prefix string, t *types.Type) *types.Sym { diff --git a/src/cmd/compile/internal/typecheck/dcl.go b/src/cmd/compile/internal/typecheck/dcl.go index c324238bf1..eab0bb09b2 100644 --- a/src/cmd/compile/internal/typecheck/dcl.go +++ b/src/cmd/compile/internal/typecheck/dcl.go @@ -304,10 +304,13 @@ func checkembeddedtype(t *types.Type) { } } -func fakeRecvField() *types.Field { +// TODO(mdempsky): Move to package types. +func FakeRecv() *types.Field { return types.NewField(src.NoXPos, nil, types.FakeRecvType()) } +var fakeRecvField = FakeRecv + var funcStack []funcStackEnt // stack of previous values of ir.CurFunc/DeclContext type funcStackEnt struct { diff --git a/src/cmd/compile/internal/typecheck/func.go b/src/cmd/compile/internal/typecheck/func.go index f624773c8f..7ab5f68ce3 100644 --- a/src/cmd/compile/internal/typecheck/func.go +++ b/src/cmd/compile/internal/typecheck/func.go @@ -174,7 +174,7 @@ func fnpkg(fn *ir.Name) *types.Pkg { // closurename generates a new unique name for a closure within // outerfunc. -func closurename(outerfunc *ir.Func) *types.Sym { +func ClosureName(outerfunc *ir.Func) *types.Sym { outer := "glob." prefix := "func" gen := &globClosgen @@ -309,7 +309,7 @@ func tcClosure(clo *ir.ClosureExpr, top int) { // explicitly in (*inlsubst).node()). inTypeCheckInl := ir.CurFunc != nil && ir.CurFunc.Body == nil if !inTypeCheckInl { - fn.Nname.SetSym(closurename(ir.CurFunc)) + fn.Nname.SetSym(ClosureName(ir.CurFunc)) ir.MarkFunc(fn.Nname) } Func(fn) diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go index b6a0870672..b88a9f2283 100644 --- a/src/cmd/compile/internal/typecheck/subr.go +++ b/src/cmd/compile/internal/typecheck/subr.go @@ -127,10 +127,9 @@ func NodNil() ir.Node { return n } -// in T.field -// find missing fields that -// will give shortest unique addressing. -// modify the tree with missing type names. +// AddImplicitDots finds missing fields in obj.field that +// will give the shortest unique addressing and +// modifies the tree with missing field names. func AddImplicitDots(n *ir.SelectorExpr) *ir.SelectorExpr { n.X = typecheck(n.X, ctxType|ctxExpr) if n.X.Diag() { diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go index 7881ea308d..cb434578dd 100644 --- a/src/cmd/compile/internal/typecheck/typecheck.go +++ b/src/cmd/compile/internal/typecheck/typecheck.go @@ -1674,10 +1674,10 @@ func CheckMapKeys() { mapqueue = nil } -// typegen tracks the number of function-scoped defined types that +// TypeGen tracks the number of function-scoped defined types that // have been declared. It's used to generate unique linker symbols for // their runtime type descriptors. -var typegen int32 +var TypeGen int32 func typecheckdeftype(n *ir.Name) { if base.EnableTrace && base.Flag.LowerT { @@ -1686,8 +1686,8 @@ func typecheckdeftype(n *ir.Name) { t := types.NewNamed(n) if n.Curfn != nil { - typegen++ - t.Vargen = typegen + TypeGen++ + t.Vargen = TypeGen } if n.Pragma()&ir.NotInHeap != 0 { diff --git a/src/cmd/compile/internal/types/pkg.go b/src/cmd/compile/internal/types/pkg.go index de45d32bfa..a6d2e2007b 100644 --- a/src/cmd/compile/internal/types/pkg.go +++ b/src/cmd/compile/internal/types/pkg.go @@ -31,8 +31,7 @@ type Pkg struct { // height of their imported packages. Height int - Imported bool // export data of this package was parsed - Direct bool // imported directly + Direct bool // imported directly } // NewPkg returns a new Pkg for the given package path and name. diff --git a/src/cmd/compile/internal/types/scope.go b/src/cmd/compile/internal/types/scope.go index a9669ffafc..d7c454f379 100644 --- a/src/cmd/compile/internal/types/scope.go +++ b/src/cmd/compile/internal/types/scope.go @@ -12,7 +12,7 @@ import ( // Declaration stack & operations var blockgen int32 = 1 // max block number -var Block int32 // current block number +var Block int32 = 1 // current block number // A dsym stores a symbol's shadowed declaration so that it can be // restored once the block scope ends. diff --git a/src/cmd/compile/internal/walk/walk.go b/src/cmd/compile/internal/walk/walk.go index 4273a62fe5..b47d96dc4c 100644 --- a/src/cmd/compile/internal/walk/walk.go +++ b/src/cmd/compile/internal/walk/walk.go @@ -49,6 +49,11 @@ func Walk(fn *ir.Func) { if base.Flag.Cfg.Instrumenting { instrument(fn) } + + // Eagerly compute sizes of all variables for SSA. + for _, n := range fn.Dcl { + types.CalcSize(n.Type()) + } } // walkRecv walks an ORECV node. diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go index 7ba8c6d317..35cb53cbf6 100644 --- a/src/cmd/internal/obj/link.go +++ b/src/cmd/internal/obj/link.go @@ -809,9 +809,9 @@ type Link struct { Errors int RegArgs []RegArg - InParallel bool // parallel backend phase in effect - UseBASEntries bool // use Base Address Selection Entries in location lists and PC ranges - IsAsm bool // is the source assembly language, which may contain surprising idioms (e.g., call tables) + InParallel bool // parallel backend phase in effect + UseBASEntries bool // use Base Address Selection Entries in location lists and PC ranges + IsAsm bool // is the source assembly language, which may contain surprising idioms (e.g., call tables) // state for writing objects Text []*LSym diff --git a/test/fixedbugs/issue11362.go b/test/fixedbugs/issue11362.go index 964e5fdf6b..9492ec1273 100644 --- a/test/fixedbugs/issue11362.go +++ b/test/fixedbugs/issue11362.go @@ -8,7 +8,7 @@ package main -import _ "unicode//utf8" // GC_ERROR "non-canonical import path .unicode//utf8. \(should be .unicode/utf8.\)" "can't find import: .unicode//utf8." +import _ "unicode//utf8" // GC_ERROR "non-canonical import path .unicode//utf8. \(should be .unicode/utf8.\)" func main() { } -- cgit v1.3-5-g9baa From bfc7418e6d3a505fe348718fd113473c9d92b135 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Fri, 29 Jan 2021 12:03:32 -0500 Subject: [dev.regabi] runtime, syscall, etc.: mark Darwin syscall wrappers as ABIInternal Mark the syscall wrappers as ABIInternal, as they have addresses taken from Go code, and it is important to call to them without wrappers. Previously, the wrapper is just a single JMP instruction, which makes it not matter. In the next CL we'll make the wrapper actually have a frame. The real wrappers will mess up things such as stack alignment for C ABI. This doesn't look really nice, but I don't know how we can do better... TODO: other OSes. Change-Id: Ifb3920494990a7775e3e6902fbcaf137df3cc653 Reviewed-on: https://go-review.googlesource.com/c/go/+/288092 Trust: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Go Bot Reviewed-by: Than McIntosh --- src/cmd/dist/build.go | 2 + src/cmd/internal/objabi/path.go | 2 + src/crypto/x509/internal/macos/corefoundation.s | 21 +- src/crypto/x509/internal/macos/security.s | 11 +- src/runtime/sys_darwin_amd64.s | 96 ++++----- src/syscall/mkasm.go | 3 +- src/syscall/zsyscall_darwin_amd64.s | 250 ++++++++++++------------ src/syscall/zsyscall_darwin_arm64.s | 250 ++++++++++++------------ src/syscall/zsyscall_openbsd_amd64.s | 230 +++++++++++----------- src/syscall/zsyscall_openbsd_arm64.s | 230 +++++++++++----------- 10 files changed, 554 insertions(+), 541 deletions(-) (limited to 'src/cmd/internal') diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go index c8c3212d16..332f2fab58 100644 --- a/src/cmd/dist/build.go +++ b/src/cmd/dist/build.go @@ -1765,6 +1765,8 @@ func IsRuntimePackagePath(pkgpath string) bool { rval = true case "syscall": rval = true + case "crypto/x509/internal/macos": // libc function wrappers need to be ABIInternal + rval = true default: rval = strings.HasPrefix(pkgpath, "runtime/internal") } diff --git a/src/cmd/internal/objabi/path.go b/src/cmd/internal/objabi/path.go index fd1c9981c6..1a0784cf7f 100644 --- a/src/cmd/internal/objabi/path.go +++ b/src/cmd/internal/objabi/path.go @@ -56,6 +56,8 @@ func IsRuntimePackagePath(pkgpath string) bool { rval = true case "syscall": rval = true + case "crypto/x509/internal/macos": // libc function wrappers need to be ABIInternal + rval = true default: rval = strings.HasPrefix(pkgpath, "runtime/internal") } diff --git a/src/crypto/x509/internal/macos/corefoundation.s b/src/crypto/x509/internal/macos/corefoundation.s index a4495d68dd..1ce39fac9d 100644 --- a/src/crypto/x509/internal/macos/corefoundation.s +++ b/src/crypto/x509/internal/macos/corefoundation.s @@ -6,21 +6,24 @@ #include "textflag.h" -TEXT ·x509_CFArrayGetCount_trampoline(SB),NOSPLIT,$0-0 +// The trampolines are ABIInternal as they are address-taken in +// Go code. + +TEXT ·x509_CFArrayGetCount_trampoline(SB),NOSPLIT,$0-0 JMP x509_CFArrayGetCount(SB) -TEXT ·x509_CFArrayGetValueAtIndex_trampoline(SB),NOSPLIT,$0-0 +TEXT ·x509_CFArrayGetValueAtIndex_trampoline(SB),NOSPLIT,$0-0 JMP x509_CFArrayGetValueAtIndex(SB) -TEXT ·x509_CFDataGetBytePtr_trampoline(SB),NOSPLIT,$0-0 +TEXT ·x509_CFDataGetBytePtr_trampoline(SB),NOSPLIT,$0-0 JMP x509_CFDataGetBytePtr(SB) -TEXT ·x509_CFDataGetLength_trampoline(SB),NOSPLIT,$0-0 +TEXT ·x509_CFDataGetLength_trampoline(SB),NOSPLIT,$0-0 JMP x509_CFDataGetLength(SB) -TEXT ·x509_CFStringCreateWithBytes_trampoline(SB),NOSPLIT,$0-0 +TEXT ·x509_CFStringCreateWithBytes_trampoline(SB),NOSPLIT,$0-0 JMP x509_CFStringCreateWithBytes(SB) -TEXT ·x509_CFRelease_trampoline(SB),NOSPLIT,$0-0 +TEXT ·x509_CFRelease_trampoline(SB),NOSPLIT,$0-0 JMP x509_CFRelease(SB) -TEXT ·x509_CFDictionaryGetValueIfPresent_trampoline(SB),NOSPLIT,$0-0 +TEXT ·x509_CFDictionaryGetValueIfPresent_trampoline(SB),NOSPLIT,$0-0 JMP x509_CFDictionaryGetValueIfPresent(SB) -TEXT ·x509_CFNumberGetValue_trampoline(SB),NOSPLIT,$0-0 +TEXT ·x509_CFNumberGetValue_trampoline(SB),NOSPLIT,$0-0 JMP x509_CFNumberGetValue(SB) -TEXT ·x509_CFEqual_trampoline(SB),NOSPLIT,$0-0 +TEXT ·x509_CFEqual_trampoline(SB),NOSPLIT,$0-0 JMP x509_CFEqual(SB) diff --git a/src/crypto/x509/internal/macos/security.s b/src/crypto/x509/internal/macos/security.s index bd446dbcbe..bea265a5ef 100644 --- a/src/crypto/x509/internal/macos/security.s +++ b/src/crypto/x509/internal/macos/security.s @@ -6,11 +6,14 @@ #include "textflag.h" -TEXT ·x509_SecTrustSettingsCopyCertificates_trampoline(SB),NOSPLIT,$0-0 +// The trampolines are ABIInternal as they are address-taken in +// Go code. + +TEXT ·x509_SecTrustSettingsCopyCertificates_trampoline(SB),NOSPLIT,$0-0 JMP x509_SecTrustSettingsCopyCertificates(SB) -TEXT ·x509_SecItemExport_trampoline(SB),NOSPLIT,$0-0 +TEXT ·x509_SecItemExport_trampoline(SB),NOSPLIT,$0-0 JMP x509_SecItemExport(SB) -TEXT ·x509_SecTrustSettingsCopyTrustSettings_trampoline(SB),NOSPLIT,$0-0 +TEXT ·x509_SecTrustSettingsCopyTrustSettings_trampoline(SB),NOSPLIT,$0-0 JMP x509_SecTrustSettingsCopyTrustSettings(SB) -TEXT ·x509_SecPolicyCopyProperties_trampoline(SB),NOSPLIT,$0-0 +TEXT ·x509_SecPolicyCopyProperties_trampoline(SB),NOSPLIT,$0-0 JMP x509_SecPolicyCopyProperties(SB) diff --git a/src/runtime/sys_darwin_amd64.s b/src/runtime/sys_darwin_amd64.s index 630fb5df64..0fe8c7e172 100644 --- a/src/runtime/sys_darwin_amd64.s +++ b/src/runtime/sys_darwin_amd64.s @@ -5,6 +5,8 @@ // System calls and other sys.stuff for AMD64, Darwin // System calls are implemented in libSystem, this file contains // trampolines that convert from Go to C calling convention. +// The trampolines are ABIInternal as they are referenced from +// Go code with funcPC. #include "go_asm.h" #include "go_tls.h" @@ -13,7 +15,7 @@ #define CLOCK_REALTIME 0 // Exit the entire program (like C exit) -TEXT runtime·exit_trampoline(SB),NOSPLIT,$0 +TEXT runtime·exit_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP MOVL 0(DI), DI // arg 1 exit status @@ -22,7 +24,7 @@ TEXT runtime·exit_trampoline(SB),NOSPLIT,$0 POPQ BP RET -TEXT runtime·open_trampoline(SB),NOSPLIT,$0 +TEXT runtime·open_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP MOVL 8(DI), SI // arg 2 flags @@ -33,7 +35,7 @@ TEXT runtime·open_trampoline(SB),NOSPLIT,$0 POPQ BP RET -TEXT runtime·close_trampoline(SB),NOSPLIT,$0 +TEXT runtime·close_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP MOVL 0(DI), DI // arg 1 fd @@ -41,7 +43,7 @@ TEXT runtime·close_trampoline(SB),NOSPLIT,$0 POPQ BP RET -TEXT runtime·read_trampoline(SB),NOSPLIT,$0 +TEXT runtime·read_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP MOVQ 8(DI), SI // arg 2 buf @@ -57,7 +59,7 @@ noerr: POPQ BP RET -TEXT runtime·write_trampoline(SB),NOSPLIT,$0 +TEXT runtime·write_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP MOVQ 8(DI), SI // arg 2 buf @@ -73,7 +75,7 @@ noerr: POPQ BP RET -TEXT runtime·pipe_trampoline(SB),NOSPLIT,$0 +TEXT runtime·pipe_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP CALL libc_pipe(SB) // pointer already in DI @@ -84,7 +86,7 @@ TEXT runtime·pipe_trampoline(SB),NOSPLIT,$0 POPQ BP RET -TEXT runtime·setitimer_trampoline(SB),NOSPLIT,$0 +TEXT runtime·setitimer_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP MOVQ 8(DI), SI // arg 2 new @@ -94,7 +96,7 @@ TEXT runtime·setitimer_trampoline(SB),NOSPLIT,$0 POPQ BP RET -TEXT runtime·madvise_trampoline(SB), NOSPLIT, $0 +TEXT runtime·madvise_trampoline(SB), NOSPLIT, $0 PUSHQ BP MOVQ SP, BP MOVQ 8(DI), SI // arg 2 len @@ -105,12 +107,12 @@ TEXT runtime·madvise_trampoline(SB), NOSPLIT, $0 POPQ BP RET -TEXT runtime·mlock_trampoline(SB), NOSPLIT, $0 +TEXT runtime·mlock_trampoline(SB), NOSPLIT, $0 UNDEF // unimplemented GLOBL timebase<>(SB),NOPTR,$(machTimebaseInfo__size) -TEXT runtime·nanotime_trampoline(SB),NOSPLIT,$0 +TEXT runtime·nanotime_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP MOVQ DI, BX @@ -139,7 +141,7 @@ initialized: POPQ BP RET -TEXT runtime·walltime_trampoline(SB),NOSPLIT,$0 +TEXT runtime·walltime_trampoline(SB),NOSPLIT,$0 PUSHQ BP // make a frame; keep stack aligned MOVQ SP, BP MOVQ DI, SI // arg 2 timespec @@ -148,7 +150,7 @@ TEXT runtime·walltime_trampoline(SB),NOSPLIT,$0 POPQ BP RET -TEXT runtime·sigaction_trampoline(SB),NOSPLIT,$0 +TEXT runtime·sigaction_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP MOVQ 8(DI), SI // arg 2 new @@ -161,7 +163,7 @@ TEXT runtime·sigaction_trampoline(SB),NOSPLIT,$0 POPQ BP RET -TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0 +TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP MOVQ 8(DI), SI // arg 2 new @@ -174,7 +176,7 @@ TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0 POPQ BP RET -TEXT runtime·sigaltstack_trampoline(SB),NOSPLIT,$0 +TEXT runtime·sigaltstack_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP MOVQ 8(DI), SI // arg 2 old @@ -186,7 +188,7 @@ TEXT runtime·sigaltstack_trampoline(SB),NOSPLIT,$0 POPQ BP RET -TEXT runtime·raiseproc_trampoline(SB),NOSPLIT,$0 +TEXT runtime·raiseproc_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP MOVL 0(DI), BX // signal @@ -212,7 +214,7 @@ TEXT runtime·sigfwd(SB),NOSPLIT,$0-32 // This is the function registered during sigaction and is invoked when // a signal is received. It just redirects to the Go function sigtrampgo. -TEXT runtime·sigtramp(SB),NOSPLIT,$0 +TEXT runtime·sigtramp(SB),NOSPLIT,$0 // This runs on the signal stack, so we have lots of stack available. // We allocate our own stack space, because if we tell the linker // how much we're using, the NOSPLIT check fails. @@ -246,7 +248,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0 // Used instead of sigtramp in programs that use cgo. // Arguments from kernel are in DI, SI, DX. -TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0 +TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0 // If no traceback function, do usual sigtramp. MOVQ runtime·cgoTraceback(SB), AX TESTQ AX, AX @@ -289,12 +291,12 @@ TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0 // The first three arguments, and the fifth, are already in registers. // Set the two remaining arguments now. MOVQ runtime·cgoTraceback(SB), CX - MOVQ $runtime·sigtramp(SB), R9 + MOVQ $runtime·sigtramp(SB), R9 MOVQ _cgo_callers(SB), AX JMP AX sigtramp: - JMP runtime·sigtramp(SB) + JMP runtime·sigtramp(SB) sigtrampnog: // Signal arrived on a non-Go thread. If this is SIGPROF, get a @@ -320,7 +322,7 @@ sigtrampnog: MOVQ _cgo_callers(SB), AX JMP AX -TEXT runtime·mmap_trampoline(SB),NOSPLIT,$0 +TEXT runtime·mmap_trampoline(SB),NOSPLIT,$0 PUSHQ BP // make a frame; keep stack aligned MOVQ SP, BP MOVQ DI, BX @@ -343,7 +345,7 @@ ok: POPQ BP RET -TEXT runtime·munmap_trampoline(SB),NOSPLIT,$0 +TEXT runtime·munmap_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP MOVQ 8(DI), SI // arg 2 len @@ -355,7 +357,7 @@ TEXT runtime·munmap_trampoline(SB),NOSPLIT,$0 POPQ BP RET -TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0 +TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP MOVL 0(DI), DI // arg 1 usec @@ -367,7 +369,7 @@ TEXT runtime·settls(SB),NOSPLIT,$32 // Nothing to do on Darwin, pthread already set thread-local storage up. RET -TEXT runtime·sysctl_trampoline(SB),NOSPLIT,$0 +TEXT runtime·sysctl_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP MOVL 8(DI), SI // arg 2 miblen @@ -380,7 +382,7 @@ TEXT runtime·sysctl_trampoline(SB),NOSPLIT,$0 POPQ BP RET -TEXT runtime·sysctlbyname_trampoline(SB),NOSPLIT,$0 +TEXT runtime·sysctlbyname_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP MOVQ 8(DI), SI // arg 2 oldp @@ -392,14 +394,14 @@ TEXT runtime·sysctlbyname_trampoline(SB),NOSPLIT,$0 POPQ BP RET -TEXT runtime·kqueue_trampoline(SB),NOSPLIT,$0 +TEXT runtime·kqueue_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP CALL libc_kqueue(SB) POPQ BP RET -TEXT runtime·kevent_trampoline(SB),NOSPLIT,$0 +TEXT runtime·kevent_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP MOVQ 8(DI), SI // arg 2 keventt @@ -418,7 +420,7 @@ ok: POPQ BP RET -TEXT runtime·fcntl_trampoline(SB),NOSPLIT,$0 +TEXT runtime·fcntl_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP MOVL 4(DI), SI // arg 2 cmd @@ -475,7 +477,7 @@ TEXT runtime·mstart_stub(SB),NOSPLIT,$0 // A pointer to the arguments is passed in DI. // A single int32 result is returned in AX. // (For more results, make an args/results structure.) -TEXT runtime·pthread_attr_init_trampoline(SB),NOSPLIT,$0 +TEXT runtime·pthread_attr_init_trampoline(SB),NOSPLIT,$0 PUSHQ BP // make frame, keep stack 16-byte aligned. MOVQ SP, BP MOVQ 0(DI), DI // arg 1 attr @@ -483,7 +485,7 @@ TEXT runtime·pthread_attr_init_trampoline(SB),NOSPLIT,$0 POPQ BP RET -TEXT runtime·pthread_attr_getstacksize_trampoline(SB),NOSPLIT,$0 +TEXT runtime·pthread_attr_getstacksize_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP MOVQ 8(DI), SI // arg 2 size @@ -492,7 +494,7 @@ TEXT runtime·pthread_attr_getstacksize_trampoline(SB),NOSPLIT,$0 POPQ BP RET -TEXT runtime·pthread_attr_setdetachstate_trampoline(SB),NOSPLIT,$0 +TEXT runtime·pthread_attr_setdetachstate_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP MOVQ 8(DI), SI // arg 2 state @@ -501,7 +503,7 @@ TEXT runtime·pthread_attr_setdetachstate_trampoline(SB),NOSPLIT,$0 POPQ BP RET -TEXT runtime·pthread_create_trampoline(SB),NOSPLIT,$0 +TEXT runtime·pthread_create_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP SUBQ $16, SP @@ -514,7 +516,7 @@ TEXT runtime·pthread_create_trampoline(SB),NOSPLIT,$0 POPQ BP RET -TEXT runtime·raise_trampoline(SB),NOSPLIT,$0 +TEXT runtime·raise_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP MOVL 0(DI), DI // arg 1 signal @@ -522,7 +524,7 @@ TEXT runtime·raise_trampoline(SB),NOSPLIT,$0 POPQ BP RET -TEXT runtime·pthread_mutex_init_trampoline(SB),NOSPLIT,$0 +TEXT runtime·pthread_mutex_init_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP MOVQ 8(DI), SI // arg 2 attr @@ -531,7 +533,7 @@ TEXT runtime·pthread_mutex_init_trampoline(SB),NOSPLIT,$0 POPQ BP RET -TEXT runtime·pthread_mutex_lock_trampoline(SB),NOSPLIT,$0 +TEXT runtime·pthread_mutex_lock_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP MOVQ 0(DI), DI // arg 1 mutex @@ -539,7 +541,7 @@ TEXT runtime·pthread_mutex_lock_trampoline(SB),NOSPLIT,$0 POPQ BP RET -TEXT runtime·pthread_mutex_unlock_trampoline(SB),NOSPLIT,$0 +TEXT runtime·pthread_mutex_unlock_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP MOVQ 0(DI), DI // arg 1 mutex @@ -547,7 +549,7 @@ TEXT runtime·pthread_mutex_unlock_trampoline(SB),NOSPLIT,$0 POPQ BP RET -TEXT runtime·pthread_cond_init_trampoline(SB),NOSPLIT,$0 +TEXT runtime·pthread_cond_init_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP MOVQ 8(DI), SI // arg 2 attr @@ -556,7 +558,7 @@ TEXT runtime·pthread_cond_init_trampoline(SB),NOSPLIT,$0 POPQ BP RET -TEXT runtime·pthread_cond_wait_trampoline(SB),NOSPLIT,$0 +TEXT runtime·pthread_cond_wait_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP MOVQ 8(DI), SI // arg 2 mutex @@ -565,7 +567,7 @@ TEXT runtime·pthread_cond_wait_trampoline(SB),NOSPLIT,$0 POPQ BP RET -TEXT runtime·pthread_cond_timedwait_relative_np_trampoline(SB),NOSPLIT,$0 +TEXT runtime·pthread_cond_timedwait_relative_np_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP MOVQ 8(DI), SI // arg 2 mutex @@ -575,7 +577,7 @@ TEXT runtime·pthread_cond_timedwait_relative_np_trampoline(SB),NOSPLIT,$0 POPQ BP RET -TEXT runtime·pthread_cond_signal_trampoline(SB),NOSPLIT,$0 +TEXT runtime·pthread_cond_signal_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP MOVQ 0(DI), DI // arg 1 cond @@ -583,7 +585,7 @@ TEXT runtime·pthread_cond_signal_trampoline(SB),NOSPLIT,$0 POPQ BP RET -TEXT runtime·pthread_self_trampoline(SB),NOSPLIT,$0 +TEXT runtime·pthread_self_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP MOVQ DI, BX // BX is caller-save @@ -592,7 +594,7 @@ TEXT runtime·pthread_self_trampoline(SB),NOSPLIT,$0 POPQ BP RET -TEXT runtime·pthread_kill_trampoline(SB),NOSPLIT,$0 +TEXT runtime·pthread_kill_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP MOVQ 8(DI), SI // arg 2 sig @@ -617,7 +619,7 @@ TEXT runtime·pthread_kill_trampoline(SB),NOSPLIT,$0 // // syscall expects a 32-bit result and tests for 32-bit -1 // to decide there was an error. -TEXT runtime·syscall(SB),NOSPLIT,$0 +TEXT runtime·syscall(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP SUBQ $16, SP @@ -667,7 +669,7 @@ ok: // // syscallX is like syscall but expects a 64-bit result // and tests for 64-bit -1 to decide there was an error. -TEXT runtime·syscallX(SB),NOSPLIT,$0 +TEXT runtime·syscallX(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP SUBQ $16, SP @@ -703,7 +705,7 @@ ok: // syscallPtr is like syscallX except that the libc function reports an // error by returning NULL and setting errno. -TEXT runtime·syscallPtr(SB),NOSPLIT,$0 +TEXT runtime·syscallPtr(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP SUBQ $16, SP @@ -756,7 +758,7 @@ ok: // // syscall6 expects a 32-bit result and tests for 32-bit -1 // to decide there was an error. -TEXT runtime·syscall6(SB),NOSPLIT,$0 +TEXT runtime·syscall6(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP SUBQ $16, SP @@ -809,7 +811,7 @@ ok: // // syscall6X is like syscall6 but expects a 64-bit result // and tests for 64-bit -1 to decide there was an error. -TEXT runtime·syscall6X(SB),NOSPLIT,$0 +TEXT runtime·syscall6X(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP SUBQ $16, SP @@ -845,7 +847,7 @@ ok: // syscallNoErr is like syscall6 but does not check for errors, and // only returns one value, for use with standard C ABI library functions. -TEXT runtime·syscallNoErr(SB),NOSPLIT,$0 +TEXT runtime·syscallNoErr(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP SUBQ $16, SP diff --git a/src/syscall/mkasm.go b/src/syscall/mkasm.go index 2ebaf8d351..e53d14bed1 100644 --- a/src/syscall/mkasm.go +++ b/src/syscall/mkasm.go @@ -53,7 +53,8 @@ func main() { fn := line[5 : len(line)-13] if !trampolines[fn] { trampolines[fn] = true - fmt.Fprintf(&out, "TEXT ·%s_trampoline(SB),NOSPLIT,$0-0\n", fn) + // The trampolines are ABIInternal as they are address-taken in Go code. + fmt.Fprintf(&out, "TEXT ·%s_trampoline(SB),NOSPLIT,$0-0\n", fn) fmt.Fprintf(&out, "\tJMP\t%s(SB)\n", fn) } } diff --git a/src/syscall/zsyscall_darwin_amd64.s b/src/syscall/zsyscall_darwin_amd64.s index 492f947855..5eb48cee44 100644 --- a/src/syscall/zsyscall_darwin_amd64.s +++ b/src/syscall/zsyscall_darwin_amd64.s @@ -1,253 +1,253 @@ // go run mkasm.go darwin amd64 // Code generated by the command above; DO NOT EDIT. #include "textflag.h" -TEXT ·libc_getfsstat_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getfsstat_trampoline(SB),NOSPLIT,$0-0 JMP libc_getfsstat(SB) -TEXT ·libc_setattrlist_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setattrlist_trampoline(SB),NOSPLIT,$0-0 JMP libc_setattrlist(SB) -TEXT ·libc_fdopendir_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fdopendir_trampoline(SB),NOSPLIT,$0-0 JMP libc_fdopendir(SB) -TEXT ·libc_sendfile_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_sendfile_trampoline(SB),NOSPLIT,$0-0 JMP libc_sendfile(SB) -TEXT ·libc_getgroups_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getgroups_trampoline(SB),NOSPLIT,$0-0 JMP libc_getgroups(SB) -TEXT ·libc_setgroups_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setgroups_trampoline(SB),NOSPLIT,$0-0 JMP libc_setgroups(SB) -TEXT ·libc_wait4_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_wait4_trampoline(SB),NOSPLIT,$0-0 JMP libc_wait4(SB) -TEXT ·libc_accept_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_accept_trampoline(SB),NOSPLIT,$0-0 JMP libc_accept(SB) -TEXT ·libc_bind_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_bind_trampoline(SB),NOSPLIT,$0-0 JMP libc_bind(SB) -TEXT ·libc_connect_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_connect_trampoline(SB),NOSPLIT,$0-0 JMP libc_connect(SB) -TEXT ·libc_socket_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_socket_trampoline(SB),NOSPLIT,$0-0 JMP libc_socket(SB) -TEXT ·libc_getsockopt_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getsockopt_trampoline(SB),NOSPLIT,$0-0 JMP libc_getsockopt(SB) -TEXT ·libc_setsockopt_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setsockopt_trampoline(SB),NOSPLIT,$0-0 JMP libc_setsockopt(SB) -TEXT ·libc_getpeername_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getpeername_trampoline(SB),NOSPLIT,$0-0 JMP libc_getpeername(SB) -TEXT ·libc_getsockname_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getsockname_trampoline(SB),NOSPLIT,$0-0 JMP libc_getsockname(SB) -TEXT ·libc_shutdown_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_shutdown_trampoline(SB),NOSPLIT,$0-0 JMP libc_shutdown(SB) -TEXT ·libc_socketpair_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_socketpair_trampoline(SB),NOSPLIT,$0-0 JMP libc_socketpair(SB) -TEXT ·libc_recvfrom_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_recvfrom_trampoline(SB),NOSPLIT,$0-0 JMP libc_recvfrom(SB) -TEXT ·libc_sendto_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_sendto_trampoline(SB),NOSPLIT,$0-0 JMP libc_sendto(SB) -TEXT ·libc_recvmsg_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_recvmsg_trampoline(SB),NOSPLIT,$0-0 JMP libc_recvmsg(SB) -TEXT ·libc_sendmsg_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_sendmsg_trampoline(SB),NOSPLIT,$0-0 JMP libc_sendmsg(SB) -TEXT ·libc_kevent_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_kevent_trampoline(SB),NOSPLIT,$0-0 JMP libc_kevent(SB) -TEXT ·libc_utimes_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_utimes_trampoline(SB),NOSPLIT,$0-0 JMP libc_utimes(SB) -TEXT ·libc_futimes_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_futimes_trampoline(SB),NOSPLIT,$0-0 JMP libc_futimes(SB) -TEXT ·libc_fcntl_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fcntl_trampoline(SB),NOSPLIT,$0-0 JMP libc_fcntl(SB) -TEXT ·libc_pipe_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_pipe_trampoline(SB),NOSPLIT,$0-0 JMP libc_pipe(SB) -TEXT ·libc_kill_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_kill_trampoline(SB),NOSPLIT,$0-0 JMP libc_kill(SB) -TEXT ·libc_access_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_access_trampoline(SB),NOSPLIT,$0-0 JMP libc_access(SB) -TEXT ·libc_adjtime_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_adjtime_trampoline(SB),NOSPLIT,$0-0 JMP libc_adjtime(SB) -TEXT ·libc_chdir_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_chdir_trampoline(SB),NOSPLIT,$0-0 JMP libc_chdir(SB) -TEXT ·libc_chflags_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_chflags_trampoline(SB),NOSPLIT,$0-0 JMP libc_chflags(SB) -TEXT ·libc_chmod_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_chmod_trampoline(SB),NOSPLIT,$0-0 JMP libc_chmod(SB) -TEXT ·libc_chown_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_chown_trampoline(SB),NOSPLIT,$0-0 JMP libc_chown(SB) -TEXT ·libc_chroot_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_chroot_trampoline(SB),NOSPLIT,$0-0 JMP libc_chroot(SB) -TEXT ·libc_close_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_close_trampoline(SB),NOSPLIT,$0-0 JMP libc_close(SB) -TEXT ·libc_closedir_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_closedir_trampoline(SB),NOSPLIT,$0-0 JMP libc_closedir(SB) -TEXT ·libc_dup_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_dup_trampoline(SB),NOSPLIT,$0-0 JMP libc_dup(SB) -TEXT ·libc_dup2_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_dup2_trampoline(SB),NOSPLIT,$0-0 JMP libc_dup2(SB) -TEXT ·libc_exchangedata_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_exchangedata_trampoline(SB),NOSPLIT,$0-0 JMP libc_exchangedata(SB) -TEXT ·libc_fchdir_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fchdir_trampoline(SB),NOSPLIT,$0-0 JMP libc_fchdir(SB) -TEXT ·libc_fchflags_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fchflags_trampoline(SB),NOSPLIT,$0-0 JMP libc_fchflags(SB) -TEXT ·libc_fchmod_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fchmod_trampoline(SB),NOSPLIT,$0-0 JMP libc_fchmod(SB) -TEXT ·libc_fchown_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fchown_trampoline(SB),NOSPLIT,$0-0 JMP libc_fchown(SB) -TEXT ·libc_flock_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_flock_trampoline(SB),NOSPLIT,$0-0 JMP libc_flock(SB) -TEXT ·libc_fpathconf_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fpathconf_trampoline(SB),NOSPLIT,$0-0 JMP libc_fpathconf(SB) -TEXT ·libc_fsync_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fsync_trampoline(SB),NOSPLIT,$0-0 JMP libc_fsync(SB) -TEXT ·libc_ftruncate_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_ftruncate_trampoline(SB),NOSPLIT,$0-0 JMP libc_ftruncate(SB) -TEXT ·libc_getdtablesize_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getdtablesize_trampoline(SB),NOSPLIT,$0-0 JMP libc_getdtablesize(SB) -TEXT ·libc_getegid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getegid_trampoline(SB),NOSPLIT,$0-0 JMP libc_getegid(SB) -TEXT ·libc_geteuid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_geteuid_trampoline(SB),NOSPLIT,$0-0 JMP libc_geteuid(SB) -TEXT ·libc_getgid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getgid_trampoline(SB),NOSPLIT,$0-0 JMP libc_getgid(SB) -TEXT ·libc_getpgid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getpgid_trampoline(SB),NOSPLIT,$0-0 JMP libc_getpgid(SB) -TEXT ·libc_getpgrp_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getpgrp_trampoline(SB),NOSPLIT,$0-0 JMP libc_getpgrp(SB) -TEXT ·libc_getpid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getpid_trampoline(SB),NOSPLIT,$0-0 JMP libc_getpid(SB) -TEXT ·libc_getppid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getppid_trampoline(SB),NOSPLIT,$0-0 JMP libc_getppid(SB) -TEXT ·libc_getpriority_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getpriority_trampoline(SB),NOSPLIT,$0-0 JMP libc_getpriority(SB) -TEXT ·libc_getrlimit_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getrlimit_trampoline(SB),NOSPLIT,$0-0 JMP libc_getrlimit(SB) -TEXT ·libc_getrusage_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getrusage_trampoline(SB),NOSPLIT,$0-0 JMP libc_getrusage(SB) -TEXT ·libc_getsid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getsid_trampoline(SB),NOSPLIT,$0-0 JMP libc_getsid(SB) -TEXT ·libc_getuid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getuid_trampoline(SB),NOSPLIT,$0-0 JMP libc_getuid(SB) -TEXT ·libc_issetugid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_issetugid_trampoline(SB),NOSPLIT,$0-0 JMP libc_issetugid(SB) -TEXT ·libc_kqueue_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_kqueue_trampoline(SB),NOSPLIT,$0-0 JMP libc_kqueue(SB) -TEXT ·libc_lchown_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_lchown_trampoline(SB),NOSPLIT,$0-0 JMP libc_lchown(SB) -TEXT ·libc_link_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_link_trampoline(SB),NOSPLIT,$0-0 JMP libc_link(SB) -TEXT ·libc_listen_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_listen_trampoline(SB),NOSPLIT,$0-0 JMP libc_listen(SB) -TEXT ·libc_mkdir_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_mkdir_trampoline(SB),NOSPLIT,$0-0 JMP libc_mkdir(SB) -TEXT ·libc_mkfifo_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_mkfifo_trampoline(SB),NOSPLIT,$0-0 JMP libc_mkfifo(SB) -TEXT ·libc_mknod_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_mknod_trampoline(SB),NOSPLIT,$0-0 JMP libc_mknod(SB) -TEXT ·libc_mlock_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_mlock_trampoline(SB),NOSPLIT,$0-0 JMP libc_mlock(SB) -TEXT ·libc_mlockall_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_mlockall_trampoline(SB),NOSPLIT,$0-0 JMP libc_mlockall(SB) -TEXT ·libc_mprotect_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_mprotect_trampoline(SB),NOSPLIT,$0-0 JMP libc_mprotect(SB) -TEXT ·libc_munlock_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_munlock_trampoline(SB),NOSPLIT,$0-0 JMP libc_munlock(SB) -TEXT ·libc_munlockall_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_munlockall_trampoline(SB),NOSPLIT,$0-0 JMP libc_munlockall(SB) -TEXT ·libc_open_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_open_trampoline(SB),NOSPLIT,$0-0 JMP libc_open(SB) -TEXT ·libc_pathconf_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_pathconf_trampoline(SB),NOSPLIT,$0-0 JMP libc_pathconf(SB) -TEXT ·libc_pread_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_pread_trampoline(SB),NOSPLIT,$0-0 JMP libc_pread(SB) -TEXT ·libc_pwrite_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_pwrite_trampoline(SB),NOSPLIT,$0-0 JMP libc_pwrite(SB) -TEXT ·libc_read_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_read_trampoline(SB),NOSPLIT,$0-0 JMP libc_read(SB) -TEXT ·libc_readdir_r_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_readdir_r_trampoline(SB),NOSPLIT,$0-0 JMP libc_readdir_r(SB) -TEXT ·libc_readlink_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_readlink_trampoline(SB),NOSPLIT,$0-0 JMP libc_readlink(SB) -TEXT ·libc_rename_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_rename_trampoline(SB),NOSPLIT,$0-0 JMP libc_rename(SB) -TEXT ·libc_revoke_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_revoke_trampoline(SB),NOSPLIT,$0-0 JMP libc_revoke(SB) -TEXT ·libc_rmdir_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_rmdir_trampoline(SB),NOSPLIT,$0-0 JMP libc_rmdir(SB) -TEXT ·libc_lseek_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_lseek_trampoline(SB),NOSPLIT,$0-0 JMP libc_lseek(SB) -TEXT ·libc_select_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_select_trampoline(SB),NOSPLIT,$0-0 JMP libc_select(SB) -TEXT ·libc_setegid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setegid_trampoline(SB),NOSPLIT,$0-0 JMP libc_setegid(SB) -TEXT ·libc_seteuid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_seteuid_trampoline(SB),NOSPLIT,$0-0 JMP libc_seteuid(SB) -TEXT ·libc_setgid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setgid_trampoline(SB),NOSPLIT,$0-0 JMP libc_setgid(SB) -TEXT ·libc_setlogin_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setlogin_trampoline(SB),NOSPLIT,$0-0 JMP libc_setlogin(SB) -TEXT ·libc_setpgid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setpgid_trampoline(SB),NOSPLIT,$0-0 JMP libc_setpgid(SB) -TEXT ·libc_setpriority_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setpriority_trampoline(SB),NOSPLIT,$0-0 JMP libc_setpriority(SB) -TEXT ·libc_setprivexec_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setprivexec_trampoline(SB),NOSPLIT,$0-0 JMP libc_setprivexec(SB) -TEXT ·libc_setregid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setregid_trampoline(SB),NOSPLIT,$0-0 JMP libc_setregid(SB) -TEXT ·libc_setreuid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setreuid_trampoline(SB),NOSPLIT,$0-0 JMP libc_setreuid(SB) -TEXT ·libc_setrlimit_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setrlimit_trampoline(SB),NOSPLIT,$0-0 JMP libc_setrlimit(SB) -TEXT ·libc_setsid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setsid_trampoline(SB),NOSPLIT,$0-0 JMP libc_setsid(SB) -TEXT ·libc_settimeofday_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_settimeofday_trampoline(SB),NOSPLIT,$0-0 JMP libc_settimeofday(SB) -TEXT ·libc_setuid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setuid_trampoline(SB),NOSPLIT,$0-0 JMP libc_setuid(SB) -TEXT ·libc_symlink_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_symlink_trampoline(SB),NOSPLIT,$0-0 JMP libc_symlink(SB) -TEXT ·libc_sync_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_sync_trampoline(SB),NOSPLIT,$0-0 JMP libc_sync(SB) -TEXT ·libc_truncate_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_truncate_trampoline(SB),NOSPLIT,$0-0 JMP libc_truncate(SB) -TEXT ·libc_umask_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_umask_trampoline(SB),NOSPLIT,$0-0 JMP libc_umask(SB) -TEXT ·libc_undelete_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_undelete_trampoline(SB),NOSPLIT,$0-0 JMP libc_undelete(SB) -TEXT ·libc_unlink_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_unlink_trampoline(SB),NOSPLIT,$0-0 JMP libc_unlink(SB) -TEXT ·libc_unmount_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_unmount_trampoline(SB),NOSPLIT,$0-0 JMP libc_unmount(SB) -TEXT ·libc_write_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_write_trampoline(SB),NOSPLIT,$0-0 JMP libc_write(SB) -TEXT ·libc_writev_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_writev_trampoline(SB),NOSPLIT,$0-0 JMP libc_writev(SB) -TEXT ·libc_mmap_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_mmap_trampoline(SB),NOSPLIT,$0-0 JMP libc_mmap(SB) -TEXT ·libc_munmap_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_munmap_trampoline(SB),NOSPLIT,$0-0 JMP libc_munmap(SB) -TEXT ·libc_fork_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fork_trampoline(SB),NOSPLIT,$0-0 JMP libc_fork(SB) -TEXT ·libc_ioctl_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_ioctl_trampoline(SB),NOSPLIT,$0-0 JMP libc_ioctl(SB) -TEXT ·libc_execve_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_execve_trampoline(SB),NOSPLIT,$0-0 JMP libc_execve(SB) -TEXT ·libc_exit_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_exit_trampoline(SB),NOSPLIT,$0-0 JMP libc_exit(SB) -TEXT ·libc_sysctl_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_sysctl_trampoline(SB),NOSPLIT,$0-0 JMP libc_sysctl(SB) -TEXT ·libc_unlinkat_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_unlinkat_trampoline(SB),NOSPLIT,$0-0 JMP libc_unlinkat(SB) -TEXT ·libc_openat_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_openat_trampoline(SB),NOSPLIT,$0-0 JMP libc_openat(SB) -TEXT ·libc_getcwd_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getcwd_trampoline(SB),NOSPLIT,$0-0 JMP libc_getcwd(SB) -TEXT ·libc_fstat64_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fstat64_trampoline(SB),NOSPLIT,$0-0 JMP libc_fstat64(SB) -TEXT ·libc_fstatfs64_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fstatfs64_trampoline(SB),NOSPLIT,$0-0 JMP libc_fstatfs64(SB) -TEXT ·libc_gettimeofday_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_gettimeofday_trampoline(SB),NOSPLIT,$0-0 JMP libc_gettimeofday(SB) -TEXT ·libc_lstat64_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_lstat64_trampoline(SB),NOSPLIT,$0-0 JMP libc_lstat64(SB) -TEXT ·libc_stat64_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_stat64_trampoline(SB),NOSPLIT,$0-0 JMP libc_stat64(SB) -TEXT ·libc_statfs64_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_statfs64_trampoline(SB),NOSPLIT,$0-0 JMP libc_statfs64(SB) -TEXT ·libc_fstatat64_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fstatat64_trampoline(SB),NOSPLIT,$0-0 JMP libc_fstatat64(SB) -TEXT ·libc_ptrace_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_ptrace_trampoline(SB),NOSPLIT,$0-0 JMP libc_ptrace(SB) diff --git a/src/syscall/zsyscall_darwin_arm64.s b/src/syscall/zsyscall_darwin_arm64.s index b606c6e49e..73e4a3fd8d 100644 --- a/src/syscall/zsyscall_darwin_arm64.s +++ b/src/syscall/zsyscall_darwin_arm64.s @@ -1,253 +1,253 @@ // go run mkasm.go darwin arm64 // Code generated by the command above; DO NOT EDIT. #include "textflag.h" -TEXT ·libc_getfsstat_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getfsstat_trampoline(SB),NOSPLIT,$0-0 JMP libc_getfsstat(SB) -TEXT ·libc_setattrlist_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setattrlist_trampoline(SB),NOSPLIT,$0-0 JMP libc_setattrlist(SB) -TEXT ·libc_fdopendir_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fdopendir_trampoline(SB),NOSPLIT,$0-0 JMP libc_fdopendir(SB) -TEXT ·libc_sendfile_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_sendfile_trampoline(SB),NOSPLIT,$0-0 JMP libc_sendfile(SB) -TEXT ·libc_getgroups_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getgroups_trampoline(SB),NOSPLIT,$0-0 JMP libc_getgroups(SB) -TEXT ·libc_setgroups_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setgroups_trampoline(SB),NOSPLIT,$0-0 JMP libc_setgroups(SB) -TEXT ·libc_wait4_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_wait4_trampoline(SB),NOSPLIT,$0-0 JMP libc_wait4(SB) -TEXT ·libc_accept_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_accept_trampoline(SB),NOSPLIT,$0-0 JMP libc_accept(SB) -TEXT ·libc_bind_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_bind_trampoline(SB),NOSPLIT,$0-0 JMP libc_bind(SB) -TEXT ·libc_connect_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_connect_trampoline(SB),NOSPLIT,$0-0 JMP libc_connect(SB) -TEXT ·libc_socket_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_socket_trampoline(SB),NOSPLIT,$0-0 JMP libc_socket(SB) -TEXT ·libc_getsockopt_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getsockopt_trampoline(SB),NOSPLIT,$0-0 JMP libc_getsockopt(SB) -TEXT ·libc_setsockopt_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setsockopt_trampoline(SB),NOSPLIT,$0-0 JMP libc_setsockopt(SB) -TEXT ·libc_getpeername_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getpeername_trampoline(SB),NOSPLIT,$0-0 JMP libc_getpeername(SB) -TEXT ·libc_getsockname_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getsockname_trampoline(SB),NOSPLIT,$0-0 JMP libc_getsockname(SB) -TEXT ·libc_shutdown_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_shutdown_trampoline(SB),NOSPLIT,$0-0 JMP libc_shutdown(SB) -TEXT ·libc_socketpair_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_socketpair_trampoline(SB),NOSPLIT,$0-0 JMP libc_socketpair(SB) -TEXT ·libc_recvfrom_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_recvfrom_trampoline(SB),NOSPLIT,$0-0 JMP libc_recvfrom(SB) -TEXT ·libc_sendto_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_sendto_trampoline(SB),NOSPLIT,$0-0 JMP libc_sendto(SB) -TEXT ·libc_recvmsg_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_recvmsg_trampoline(SB),NOSPLIT,$0-0 JMP libc_recvmsg(SB) -TEXT ·libc_sendmsg_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_sendmsg_trampoline(SB),NOSPLIT,$0-0 JMP libc_sendmsg(SB) -TEXT ·libc_kevent_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_kevent_trampoline(SB),NOSPLIT,$0-0 JMP libc_kevent(SB) -TEXT ·libc_utimes_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_utimes_trampoline(SB),NOSPLIT,$0-0 JMP libc_utimes(SB) -TEXT ·libc_futimes_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_futimes_trampoline(SB),NOSPLIT,$0-0 JMP libc_futimes(SB) -TEXT ·libc_fcntl_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fcntl_trampoline(SB),NOSPLIT,$0-0 JMP libc_fcntl(SB) -TEXT ·libc_pipe_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_pipe_trampoline(SB),NOSPLIT,$0-0 JMP libc_pipe(SB) -TEXT ·libc_kill_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_kill_trampoline(SB),NOSPLIT,$0-0 JMP libc_kill(SB) -TEXT ·libc_access_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_access_trampoline(SB),NOSPLIT,$0-0 JMP libc_access(SB) -TEXT ·libc_adjtime_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_adjtime_trampoline(SB),NOSPLIT,$0-0 JMP libc_adjtime(SB) -TEXT ·libc_chdir_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_chdir_trampoline(SB),NOSPLIT,$0-0 JMP libc_chdir(SB) -TEXT ·libc_chflags_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_chflags_trampoline(SB),NOSPLIT,$0-0 JMP libc_chflags(SB) -TEXT ·libc_chmod_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_chmod_trampoline(SB),NOSPLIT,$0-0 JMP libc_chmod(SB) -TEXT ·libc_chown_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_chown_trampoline(SB),NOSPLIT,$0-0 JMP libc_chown(SB) -TEXT ·libc_chroot_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_chroot_trampoline(SB),NOSPLIT,$0-0 JMP libc_chroot(SB) -TEXT ·libc_close_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_close_trampoline(SB),NOSPLIT,$0-0 JMP libc_close(SB) -TEXT ·libc_closedir_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_closedir_trampoline(SB),NOSPLIT,$0-0 JMP libc_closedir(SB) -TEXT ·libc_dup_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_dup_trampoline(SB),NOSPLIT,$0-0 JMP libc_dup(SB) -TEXT ·libc_dup2_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_dup2_trampoline(SB),NOSPLIT,$0-0 JMP libc_dup2(SB) -TEXT ·libc_exchangedata_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_exchangedata_trampoline(SB),NOSPLIT,$0-0 JMP libc_exchangedata(SB) -TEXT ·libc_fchdir_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fchdir_trampoline(SB),NOSPLIT,$0-0 JMP libc_fchdir(SB) -TEXT ·libc_fchflags_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fchflags_trampoline(SB),NOSPLIT,$0-0 JMP libc_fchflags(SB) -TEXT ·libc_fchmod_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fchmod_trampoline(SB),NOSPLIT,$0-0 JMP libc_fchmod(SB) -TEXT ·libc_fchown_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fchown_trampoline(SB),NOSPLIT,$0-0 JMP libc_fchown(SB) -TEXT ·libc_flock_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_flock_trampoline(SB),NOSPLIT,$0-0 JMP libc_flock(SB) -TEXT ·libc_fpathconf_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fpathconf_trampoline(SB),NOSPLIT,$0-0 JMP libc_fpathconf(SB) -TEXT ·libc_fsync_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fsync_trampoline(SB),NOSPLIT,$0-0 JMP libc_fsync(SB) -TEXT ·libc_ftruncate_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_ftruncate_trampoline(SB),NOSPLIT,$0-0 JMP libc_ftruncate(SB) -TEXT ·libc_getdtablesize_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getdtablesize_trampoline(SB),NOSPLIT,$0-0 JMP libc_getdtablesize(SB) -TEXT ·libc_getegid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getegid_trampoline(SB),NOSPLIT,$0-0 JMP libc_getegid(SB) -TEXT ·libc_geteuid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_geteuid_trampoline(SB),NOSPLIT,$0-0 JMP libc_geteuid(SB) -TEXT ·libc_getgid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getgid_trampoline(SB),NOSPLIT,$0-0 JMP libc_getgid(SB) -TEXT ·libc_getpgid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getpgid_trampoline(SB),NOSPLIT,$0-0 JMP libc_getpgid(SB) -TEXT ·libc_getpgrp_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getpgrp_trampoline(SB),NOSPLIT,$0-0 JMP libc_getpgrp(SB) -TEXT ·libc_getpid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getpid_trampoline(SB),NOSPLIT,$0-0 JMP libc_getpid(SB) -TEXT ·libc_getppid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getppid_trampoline(SB),NOSPLIT,$0-0 JMP libc_getppid(SB) -TEXT ·libc_getpriority_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getpriority_trampoline(SB),NOSPLIT,$0-0 JMP libc_getpriority(SB) -TEXT ·libc_getrlimit_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getrlimit_trampoline(SB),NOSPLIT,$0-0 JMP libc_getrlimit(SB) -TEXT ·libc_getrusage_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getrusage_trampoline(SB),NOSPLIT,$0-0 JMP libc_getrusage(SB) -TEXT ·libc_getsid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getsid_trampoline(SB),NOSPLIT,$0-0 JMP libc_getsid(SB) -TEXT ·libc_getuid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getuid_trampoline(SB),NOSPLIT,$0-0 JMP libc_getuid(SB) -TEXT ·libc_issetugid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_issetugid_trampoline(SB),NOSPLIT,$0-0 JMP libc_issetugid(SB) -TEXT ·libc_kqueue_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_kqueue_trampoline(SB),NOSPLIT,$0-0 JMP libc_kqueue(SB) -TEXT ·libc_lchown_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_lchown_trampoline(SB),NOSPLIT,$0-0 JMP libc_lchown(SB) -TEXT ·libc_link_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_link_trampoline(SB),NOSPLIT,$0-0 JMP libc_link(SB) -TEXT ·libc_listen_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_listen_trampoline(SB),NOSPLIT,$0-0 JMP libc_listen(SB) -TEXT ·libc_mkdir_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_mkdir_trampoline(SB),NOSPLIT,$0-0 JMP libc_mkdir(SB) -TEXT ·libc_mkfifo_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_mkfifo_trampoline(SB),NOSPLIT,$0-0 JMP libc_mkfifo(SB) -TEXT ·libc_mknod_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_mknod_trampoline(SB),NOSPLIT,$0-0 JMP libc_mknod(SB) -TEXT ·libc_mlock_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_mlock_trampoline(SB),NOSPLIT,$0-0 JMP libc_mlock(SB) -TEXT ·libc_mlockall_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_mlockall_trampoline(SB),NOSPLIT,$0-0 JMP libc_mlockall(SB) -TEXT ·libc_mprotect_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_mprotect_trampoline(SB),NOSPLIT,$0-0 JMP libc_mprotect(SB) -TEXT ·libc_munlock_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_munlock_trampoline(SB),NOSPLIT,$0-0 JMP libc_munlock(SB) -TEXT ·libc_munlockall_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_munlockall_trampoline(SB),NOSPLIT,$0-0 JMP libc_munlockall(SB) -TEXT ·libc_open_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_open_trampoline(SB),NOSPLIT,$0-0 JMP libc_open(SB) -TEXT ·libc_pathconf_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_pathconf_trampoline(SB),NOSPLIT,$0-0 JMP libc_pathconf(SB) -TEXT ·libc_pread_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_pread_trampoline(SB),NOSPLIT,$0-0 JMP libc_pread(SB) -TEXT ·libc_pwrite_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_pwrite_trampoline(SB),NOSPLIT,$0-0 JMP libc_pwrite(SB) -TEXT ·libc_read_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_read_trampoline(SB),NOSPLIT,$0-0 JMP libc_read(SB) -TEXT ·libc_readdir_r_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_readdir_r_trampoline(SB),NOSPLIT,$0-0 JMP libc_readdir_r(SB) -TEXT ·libc_readlink_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_readlink_trampoline(SB),NOSPLIT,$0-0 JMP libc_readlink(SB) -TEXT ·libc_rename_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_rename_trampoline(SB),NOSPLIT,$0-0 JMP libc_rename(SB) -TEXT ·libc_revoke_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_revoke_trampoline(SB),NOSPLIT,$0-0 JMP libc_revoke(SB) -TEXT ·libc_rmdir_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_rmdir_trampoline(SB),NOSPLIT,$0-0 JMP libc_rmdir(SB) -TEXT ·libc_lseek_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_lseek_trampoline(SB),NOSPLIT,$0-0 JMP libc_lseek(SB) -TEXT ·libc_select_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_select_trampoline(SB),NOSPLIT,$0-0 JMP libc_select(SB) -TEXT ·libc_setegid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setegid_trampoline(SB),NOSPLIT,$0-0 JMP libc_setegid(SB) -TEXT ·libc_seteuid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_seteuid_trampoline(SB),NOSPLIT,$0-0 JMP libc_seteuid(SB) -TEXT ·libc_setgid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setgid_trampoline(SB),NOSPLIT,$0-0 JMP libc_setgid(SB) -TEXT ·libc_setlogin_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setlogin_trampoline(SB),NOSPLIT,$0-0 JMP libc_setlogin(SB) -TEXT ·libc_setpgid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setpgid_trampoline(SB),NOSPLIT,$0-0 JMP libc_setpgid(SB) -TEXT ·libc_setpriority_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setpriority_trampoline(SB),NOSPLIT,$0-0 JMP libc_setpriority(SB) -TEXT ·libc_setprivexec_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setprivexec_trampoline(SB),NOSPLIT,$0-0 JMP libc_setprivexec(SB) -TEXT ·libc_setregid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setregid_trampoline(SB),NOSPLIT,$0-0 JMP libc_setregid(SB) -TEXT ·libc_setreuid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setreuid_trampoline(SB),NOSPLIT,$0-0 JMP libc_setreuid(SB) -TEXT ·libc_setrlimit_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setrlimit_trampoline(SB),NOSPLIT,$0-0 JMP libc_setrlimit(SB) -TEXT ·libc_setsid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setsid_trampoline(SB),NOSPLIT,$0-0 JMP libc_setsid(SB) -TEXT ·libc_settimeofday_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_settimeofday_trampoline(SB),NOSPLIT,$0-0 JMP libc_settimeofday(SB) -TEXT ·libc_setuid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setuid_trampoline(SB),NOSPLIT,$0-0 JMP libc_setuid(SB) -TEXT ·libc_symlink_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_symlink_trampoline(SB),NOSPLIT,$0-0 JMP libc_symlink(SB) -TEXT ·libc_sync_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_sync_trampoline(SB),NOSPLIT,$0-0 JMP libc_sync(SB) -TEXT ·libc_truncate_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_truncate_trampoline(SB),NOSPLIT,$0-0 JMP libc_truncate(SB) -TEXT ·libc_umask_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_umask_trampoline(SB),NOSPLIT,$0-0 JMP libc_umask(SB) -TEXT ·libc_undelete_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_undelete_trampoline(SB),NOSPLIT,$0-0 JMP libc_undelete(SB) -TEXT ·libc_unlink_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_unlink_trampoline(SB),NOSPLIT,$0-0 JMP libc_unlink(SB) -TEXT ·libc_unmount_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_unmount_trampoline(SB),NOSPLIT,$0-0 JMP libc_unmount(SB) -TEXT ·libc_write_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_write_trampoline(SB),NOSPLIT,$0-0 JMP libc_write(SB) -TEXT ·libc_writev_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_writev_trampoline(SB),NOSPLIT,$0-0 JMP libc_writev(SB) -TEXT ·libc_mmap_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_mmap_trampoline(SB),NOSPLIT,$0-0 JMP libc_mmap(SB) -TEXT ·libc_munmap_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_munmap_trampoline(SB),NOSPLIT,$0-0 JMP libc_munmap(SB) -TEXT ·libc_fork_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fork_trampoline(SB),NOSPLIT,$0-0 JMP libc_fork(SB) -TEXT ·libc_ioctl_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_ioctl_trampoline(SB),NOSPLIT,$0-0 JMP libc_ioctl(SB) -TEXT ·libc_execve_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_execve_trampoline(SB),NOSPLIT,$0-0 JMP libc_execve(SB) -TEXT ·libc_exit_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_exit_trampoline(SB),NOSPLIT,$0-0 JMP libc_exit(SB) -TEXT ·libc_sysctl_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_sysctl_trampoline(SB),NOSPLIT,$0-0 JMP libc_sysctl(SB) -TEXT ·libc_unlinkat_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_unlinkat_trampoline(SB),NOSPLIT,$0-0 JMP libc_unlinkat(SB) -TEXT ·libc_openat_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_openat_trampoline(SB),NOSPLIT,$0-0 JMP libc_openat(SB) -TEXT ·libc_getcwd_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getcwd_trampoline(SB),NOSPLIT,$0-0 JMP libc_getcwd(SB) -TEXT ·libc_fstat_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fstat_trampoline(SB),NOSPLIT,$0-0 JMP libc_fstat(SB) -TEXT ·libc_fstatfs_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fstatfs_trampoline(SB),NOSPLIT,$0-0 JMP libc_fstatfs(SB) -TEXT ·libc_gettimeofday_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_gettimeofday_trampoline(SB),NOSPLIT,$0-0 JMP libc_gettimeofday(SB) -TEXT ·libc_lstat_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_lstat_trampoline(SB),NOSPLIT,$0-0 JMP libc_lstat(SB) -TEXT ·libc_stat_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_stat_trampoline(SB),NOSPLIT,$0-0 JMP libc_stat(SB) -TEXT ·libc_statfs_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_statfs_trampoline(SB),NOSPLIT,$0-0 JMP libc_statfs(SB) -TEXT ·libc_fstatat_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fstatat_trampoline(SB),NOSPLIT,$0-0 JMP libc_fstatat(SB) -TEXT ·libc_ptrace_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_ptrace_trampoline(SB),NOSPLIT,$0-0 JMP libc_ptrace(SB) diff --git a/src/syscall/zsyscall_openbsd_amd64.s b/src/syscall/zsyscall_openbsd_amd64.s index e5c5dde930..8256a451f5 100644 --- a/src/syscall/zsyscall_openbsd_amd64.s +++ b/src/syscall/zsyscall_openbsd_amd64.s @@ -1,233 +1,233 @@ // go run mkasm.go openbsd amd64 // Code generated by the command above; DO NOT EDIT. #include "textflag.h" -TEXT ·libc_getgroups_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getgroups_trampoline(SB),NOSPLIT,$0-0 JMP libc_getgroups(SB) -TEXT ·libc_setgroups_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setgroups_trampoline(SB),NOSPLIT,$0-0 JMP libc_setgroups(SB) -TEXT ·libc_wait4_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_wait4_trampoline(SB),NOSPLIT,$0-0 JMP libc_wait4(SB) -TEXT ·libc_accept_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_accept_trampoline(SB),NOSPLIT,$0-0 JMP libc_accept(SB) -TEXT ·libc_bind_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_bind_trampoline(SB),NOSPLIT,$0-0 JMP libc_bind(SB) -TEXT ·libc_connect_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_connect_trampoline(SB),NOSPLIT,$0-0 JMP libc_connect(SB) -TEXT ·libc_socket_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_socket_trampoline(SB),NOSPLIT,$0-0 JMP libc_socket(SB) -TEXT ·libc_getsockopt_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getsockopt_trampoline(SB),NOSPLIT,$0-0 JMP libc_getsockopt(SB) -TEXT ·libc_setsockopt_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setsockopt_trampoline(SB),NOSPLIT,$0-0 JMP libc_setsockopt(SB) -TEXT ·libc_getpeername_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getpeername_trampoline(SB),NOSPLIT,$0-0 JMP libc_getpeername(SB) -TEXT ·libc_getsockname_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getsockname_trampoline(SB),NOSPLIT,$0-0 JMP libc_getsockname(SB) -TEXT ·libc_shutdown_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_shutdown_trampoline(SB),NOSPLIT,$0-0 JMP libc_shutdown(SB) -TEXT ·libc_socketpair_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_socketpair_trampoline(SB),NOSPLIT,$0-0 JMP libc_socketpair(SB) -TEXT ·libc_recvfrom_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_recvfrom_trampoline(SB),NOSPLIT,$0-0 JMP libc_recvfrom(SB) -TEXT ·libc_sendto_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_sendto_trampoline(SB),NOSPLIT,$0-0 JMP libc_sendto(SB) -TEXT ·libc_recvmsg_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_recvmsg_trampoline(SB),NOSPLIT,$0-0 JMP libc_recvmsg(SB) -TEXT ·libc_sendmsg_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_sendmsg_trampoline(SB),NOSPLIT,$0-0 JMP libc_sendmsg(SB) -TEXT ·libc_kevent_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_kevent_trampoline(SB),NOSPLIT,$0-0 JMP libc_kevent(SB) -TEXT ·libc_utimes_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_utimes_trampoline(SB),NOSPLIT,$0-0 JMP libc_utimes(SB) -TEXT ·libc_futimes_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_futimes_trampoline(SB),NOSPLIT,$0-0 JMP libc_futimes(SB) -TEXT ·libc_fcntl_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fcntl_trampoline(SB),NOSPLIT,$0-0 JMP libc_fcntl(SB) -TEXT ·libc_pipe2_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_pipe2_trampoline(SB),NOSPLIT,$0-0 JMP libc_pipe2(SB) -TEXT ·libc_accept4_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_accept4_trampoline(SB),NOSPLIT,$0-0 JMP libc_accept4(SB) -TEXT ·libc_getdents_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getdents_trampoline(SB),NOSPLIT,$0-0 JMP libc_getdents(SB) -TEXT ·libc_access_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_access_trampoline(SB),NOSPLIT,$0-0 JMP libc_access(SB) -TEXT ·libc_adjtime_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_adjtime_trampoline(SB),NOSPLIT,$0-0 JMP libc_adjtime(SB) -TEXT ·libc_chdir_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_chdir_trampoline(SB),NOSPLIT,$0-0 JMP libc_chdir(SB) -TEXT ·libc_chflags_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_chflags_trampoline(SB),NOSPLIT,$0-0 JMP libc_chflags(SB) -TEXT ·libc_chmod_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_chmod_trampoline(SB),NOSPLIT,$0-0 JMP libc_chmod(SB) -TEXT ·libc_chown_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_chown_trampoline(SB),NOSPLIT,$0-0 JMP libc_chown(SB) -TEXT ·libc_chroot_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_chroot_trampoline(SB),NOSPLIT,$0-0 JMP libc_chroot(SB) -TEXT ·libc_close_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_close_trampoline(SB),NOSPLIT,$0-0 JMP libc_close(SB) -TEXT ·libc_dup_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_dup_trampoline(SB),NOSPLIT,$0-0 JMP libc_dup(SB) -TEXT ·libc_dup2_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_dup2_trampoline(SB),NOSPLIT,$0-0 JMP libc_dup2(SB) -TEXT ·libc_fchdir_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fchdir_trampoline(SB),NOSPLIT,$0-0 JMP libc_fchdir(SB) -TEXT ·libc_fchflags_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fchflags_trampoline(SB),NOSPLIT,$0-0 JMP libc_fchflags(SB) -TEXT ·libc_fchmod_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fchmod_trampoline(SB),NOSPLIT,$0-0 JMP libc_fchmod(SB) -TEXT ·libc_fchown_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fchown_trampoline(SB),NOSPLIT,$0-0 JMP libc_fchown(SB) -TEXT ·libc_flock_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_flock_trampoline(SB),NOSPLIT,$0-0 JMP libc_flock(SB) -TEXT ·libc_fpathconf_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fpathconf_trampoline(SB),NOSPLIT,$0-0 JMP libc_fpathconf(SB) -TEXT ·libc_fstat_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fstat_trampoline(SB),NOSPLIT,$0-0 JMP libc_fstat(SB) -TEXT ·libc_fstatfs_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fstatfs_trampoline(SB),NOSPLIT,$0-0 JMP libc_fstatfs(SB) -TEXT ·libc_fsync_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fsync_trampoline(SB),NOSPLIT,$0-0 JMP libc_fsync(SB) -TEXT ·libc_ftruncate_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_ftruncate_trampoline(SB),NOSPLIT,$0-0 JMP libc_ftruncate(SB) -TEXT ·libc_getegid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getegid_trampoline(SB),NOSPLIT,$0-0 JMP libc_getegid(SB) -TEXT ·libc_geteuid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_geteuid_trampoline(SB),NOSPLIT,$0-0 JMP libc_geteuid(SB) -TEXT ·libc_getgid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getgid_trampoline(SB),NOSPLIT,$0-0 JMP libc_getgid(SB) -TEXT ·libc_getpgid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getpgid_trampoline(SB),NOSPLIT,$0-0 JMP libc_getpgid(SB) -TEXT ·libc_getpgrp_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getpgrp_trampoline(SB),NOSPLIT,$0-0 JMP libc_getpgrp(SB) -TEXT ·libc_getpid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getpid_trampoline(SB),NOSPLIT,$0-0 JMP libc_getpid(SB) -TEXT ·libc_getppid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getppid_trampoline(SB),NOSPLIT,$0-0 JMP libc_getppid(SB) -TEXT ·libc_getpriority_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getpriority_trampoline(SB),NOSPLIT,$0-0 JMP libc_getpriority(SB) -TEXT ·libc_getrlimit_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getrlimit_trampoline(SB),NOSPLIT,$0-0 JMP libc_getrlimit(SB) -TEXT ·libc_getrusage_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getrusage_trampoline(SB),NOSPLIT,$0-0 JMP libc_getrusage(SB) -TEXT ·libc_getsid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getsid_trampoline(SB),NOSPLIT,$0-0 JMP libc_getsid(SB) -TEXT ·libc_gettimeofday_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_gettimeofday_trampoline(SB),NOSPLIT,$0-0 JMP libc_gettimeofday(SB) -TEXT ·libc_getuid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getuid_trampoline(SB),NOSPLIT,$0-0 JMP libc_getuid(SB) -TEXT ·libc_issetugid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_issetugid_trampoline(SB),NOSPLIT,$0-0 JMP libc_issetugid(SB) -TEXT ·libc_kill_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_kill_trampoline(SB),NOSPLIT,$0-0 JMP libc_kill(SB) -TEXT ·libc_kqueue_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_kqueue_trampoline(SB),NOSPLIT,$0-0 JMP libc_kqueue(SB) -TEXT ·libc_lchown_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_lchown_trampoline(SB),NOSPLIT,$0-0 JMP libc_lchown(SB) -TEXT ·libc_link_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_link_trampoline(SB),NOSPLIT,$0-0 JMP libc_link(SB) -TEXT ·libc_listen_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_listen_trampoline(SB),NOSPLIT,$0-0 JMP libc_listen(SB) -TEXT ·libc_lstat_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_lstat_trampoline(SB),NOSPLIT,$0-0 JMP libc_lstat(SB) -TEXT ·libc_mkdir_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_mkdir_trampoline(SB),NOSPLIT,$0-0 JMP libc_mkdir(SB) -TEXT ·libc_mkfifo_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_mkfifo_trampoline(SB),NOSPLIT,$0-0 JMP libc_mkfifo(SB) -TEXT ·libc_mknod_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_mknod_trampoline(SB),NOSPLIT,$0-0 JMP libc_mknod(SB) -TEXT ·libc_nanosleep_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_nanosleep_trampoline(SB),NOSPLIT,$0-0 JMP libc_nanosleep(SB) -TEXT ·libc_open_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_open_trampoline(SB),NOSPLIT,$0-0 JMP libc_open(SB) -TEXT ·libc_pathconf_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_pathconf_trampoline(SB),NOSPLIT,$0-0 JMP libc_pathconf(SB) -TEXT ·libc_pread_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_pread_trampoline(SB),NOSPLIT,$0-0 JMP libc_pread(SB) -TEXT ·libc_pwrite_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_pwrite_trampoline(SB),NOSPLIT,$0-0 JMP libc_pwrite(SB) -TEXT ·libc_read_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_read_trampoline(SB),NOSPLIT,$0-0 JMP libc_read(SB) -TEXT ·libc_readlink_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_readlink_trampoline(SB),NOSPLIT,$0-0 JMP libc_readlink(SB) -TEXT ·libc_rename_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_rename_trampoline(SB),NOSPLIT,$0-0 JMP libc_rename(SB) -TEXT ·libc_revoke_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_revoke_trampoline(SB),NOSPLIT,$0-0 JMP libc_revoke(SB) -TEXT ·libc_rmdir_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_rmdir_trampoline(SB),NOSPLIT,$0-0 JMP libc_rmdir(SB) -TEXT ·libc_select_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_select_trampoline(SB),NOSPLIT,$0-0 JMP libc_select(SB) -TEXT ·libc_setegid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setegid_trampoline(SB),NOSPLIT,$0-0 JMP libc_setegid(SB) -TEXT ·libc_seteuid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_seteuid_trampoline(SB),NOSPLIT,$0-0 JMP libc_seteuid(SB) -TEXT ·libc_setgid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setgid_trampoline(SB),NOSPLIT,$0-0 JMP libc_setgid(SB) -TEXT ·libc_setlogin_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setlogin_trampoline(SB),NOSPLIT,$0-0 JMP libc_setlogin(SB) -TEXT ·libc_setpgid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setpgid_trampoline(SB),NOSPLIT,$0-0 JMP libc_setpgid(SB) -TEXT ·libc_setpriority_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setpriority_trampoline(SB),NOSPLIT,$0-0 JMP libc_setpriority(SB) -TEXT ·libc_setregid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setregid_trampoline(SB),NOSPLIT,$0-0 JMP libc_setregid(SB) -TEXT ·libc_setreuid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setreuid_trampoline(SB),NOSPLIT,$0-0 JMP libc_setreuid(SB) -TEXT ·libc_setrlimit_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setrlimit_trampoline(SB),NOSPLIT,$0-0 JMP libc_setrlimit(SB) -TEXT ·libc_setsid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setsid_trampoline(SB),NOSPLIT,$0-0 JMP libc_setsid(SB) -TEXT ·libc_settimeofday_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_settimeofday_trampoline(SB),NOSPLIT,$0-0 JMP libc_settimeofday(SB) -TEXT ·libc_setuid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setuid_trampoline(SB),NOSPLIT,$0-0 JMP libc_setuid(SB) -TEXT ·libc_stat_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_stat_trampoline(SB),NOSPLIT,$0-0 JMP libc_stat(SB) -TEXT ·libc_statfs_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_statfs_trampoline(SB),NOSPLIT,$0-0 JMP libc_statfs(SB) -TEXT ·libc_symlink_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_symlink_trampoline(SB),NOSPLIT,$0-0 JMP libc_symlink(SB) -TEXT ·libc_sync_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_sync_trampoline(SB),NOSPLIT,$0-0 JMP libc_sync(SB) -TEXT ·libc_truncate_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_truncate_trampoline(SB),NOSPLIT,$0-0 JMP libc_truncate(SB) -TEXT ·libc_umask_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_umask_trampoline(SB),NOSPLIT,$0-0 JMP libc_umask(SB) -TEXT ·libc_unlink_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_unlink_trampoline(SB),NOSPLIT,$0-0 JMP libc_unlink(SB) -TEXT ·libc_unmount_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_unmount_trampoline(SB),NOSPLIT,$0-0 JMP libc_unmount(SB) -TEXT ·libc_write_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_write_trampoline(SB),NOSPLIT,$0-0 JMP libc_write(SB) -TEXT ·libc_mmap_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_mmap_trampoline(SB),NOSPLIT,$0-0 JMP libc_mmap(SB) -TEXT ·libc_munmap_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_munmap_trampoline(SB),NOSPLIT,$0-0 JMP libc_munmap(SB) -TEXT ·libc_utimensat_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_utimensat_trampoline(SB),NOSPLIT,$0-0 JMP libc_utimensat(SB) -TEXT ·libc_syscall_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_syscall_trampoline(SB),NOSPLIT,$0-0 JMP libc_syscall(SB) -TEXT ·libc_lseek_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_lseek_trampoline(SB),NOSPLIT,$0-0 JMP libc_lseek(SB) -TEXT ·libc_getcwd_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getcwd_trampoline(SB),NOSPLIT,$0-0 JMP libc_getcwd(SB) -TEXT ·libc_sysctl_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_sysctl_trampoline(SB),NOSPLIT,$0-0 JMP libc_sysctl(SB) -TEXT ·libc_fork_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fork_trampoline(SB),NOSPLIT,$0-0 JMP libc_fork(SB) -TEXT ·libc_ioctl_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_ioctl_trampoline(SB),NOSPLIT,$0-0 JMP libc_ioctl(SB) -TEXT ·libc_execve_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_execve_trampoline(SB),NOSPLIT,$0-0 JMP libc_execve(SB) -TEXT ·libc_exit_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_exit_trampoline(SB),NOSPLIT,$0-0 JMP libc_exit(SB) -TEXT ·libc_ptrace_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_ptrace_trampoline(SB),NOSPLIT,$0-0 JMP libc_ptrace(SB) -TEXT ·libc_getentropy_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getentropy_trampoline(SB),NOSPLIT,$0-0 JMP libc_getentropy(SB) -TEXT ·libc_fstatat_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fstatat_trampoline(SB),NOSPLIT,$0-0 JMP libc_fstatat(SB) -TEXT ·libc_unlinkat_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_unlinkat_trampoline(SB),NOSPLIT,$0-0 JMP libc_unlinkat(SB) -TEXT ·libc_openat_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_openat_trampoline(SB),NOSPLIT,$0-0 JMP libc_openat(SB) diff --git a/src/syscall/zsyscall_openbsd_arm64.s b/src/syscall/zsyscall_openbsd_arm64.s index 37778b1db5..f6e0a8da94 100644 --- a/src/syscall/zsyscall_openbsd_arm64.s +++ b/src/syscall/zsyscall_openbsd_arm64.s @@ -1,233 +1,233 @@ // go run mkasm.go openbsd arm64 // Code generated by the command above; DO NOT EDIT. #include "textflag.h" -TEXT ·libc_getgroups_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getgroups_trampoline(SB),NOSPLIT,$0-0 JMP libc_getgroups(SB) -TEXT ·libc_setgroups_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setgroups_trampoline(SB),NOSPLIT,$0-0 JMP libc_setgroups(SB) -TEXT ·libc_wait4_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_wait4_trampoline(SB),NOSPLIT,$0-0 JMP libc_wait4(SB) -TEXT ·libc_accept_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_accept_trampoline(SB),NOSPLIT,$0-0 JMP libc_accept(SB) -TEXT ·libc_bind_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_bind_trampoline(SB),NOSPLIT,$0-0 JMP libc_bind(SB) -TEXT ·libc_connect_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_connect_trampoline(SB),NOSPLIT,$0-0 JMP libc_connect(SB) -TEXT ·libc_socket_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_socket_trampoline(SB),NOSPLIT,$0-0 JMP libc_socket(SB) -TEXT ·libc_getsockopt_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getsockopt_trampoline(SB),NOSPLIT,$0-0 JMP libc_getsockopt(SB) -TEXT ·libc_setsockopt_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setsockopt_trampoline(SB),NOSPLIT,$0-0 JMP libc_setsockopt(SB) -TEXT ·libc_getpeername_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getpeername_trampoline(SB),NOSPLIT,$0-0 JMP libc_getpeername(SB) -TEXT ·libc_getsockname_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getsockname_trampoline(SB),NOSPLIT,$0-0 JMP libc_getsockname(SB) -TEXT ·libc_shutdown_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_shutdown_trampoline(SB),NOSPLIT,$0-0 JMP libc_shutdown(SB) -TEXT ·libc_socketpair_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_socketpair_trampoline(SB),NOSPLIT,$0-0 JMP libc_socketpair(SB) -TEXT ·libc_recvfrom_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_recvfrom_trampoline(SB),NOSPLIT,$0-0 JMP libc_recvfrom(SB) -TEXT ·libc_sendto_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_sendto_trampoline(SB),NOSPLIT,$0-0 JMP libc_sendto(SB) -TEXT ·libc_recvmsg_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_recvmsg_trampoline(SB),NOSPLIT,$0-0 JMP libc_recvmsg(SB) -TEXT ·libc_sendmsg_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_sendmsg_trampoline(SB),NOSPLIT,$0-0 JMP libc_sendmsg(SB) -TEXT ·libc_kevent_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_kevent_trampoline(SB),NOSPLIT,$0-0 JMP libc_kevent(SB) -TEXT ·libc_utimes_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_utimes_trampoline(SB),NOSPLIT,$0-0 JMP libc_utimes(SB) -TEXT ·libc_futimes_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_futimes_trampoline(SB),NOSPLIT,$0-0 JMP libc_futimes(SB) -TEXT ·libc_fcntl_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fcntl_trampoline(SB),NOSPLIT,$0-0 JMP libc_fcntl(SB) -TEXT ·libc_pipe2_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_pipe2_trampoline(SB),NOSPLIT,$0-0 JMP libc_pipe2(SB) -TEXT ·libc_accept4_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_accept4_trampoline(SB),NOSPLIT,$0-0 JMP libc_accept4(SB) -TEXT ·libc_getdents_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getdents_trampoline(SB),NOSPLIT,$0-0 JMP libc_getdents(SB) -TEXT ·libc_access_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_access_trampoline(SB),NOSPLIT,$0-0 JMP libc_access(SB) -TEXT ·libc_adjtime_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_adjtime_trampoline(SB),NOSPLIT,$0-0 JMP libc_adjtime(SB) -TEXT ·libc_chdir_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_chdir_trampoline(SB),NOSPLIT,$0-0 JMP libc_chdir(SB) -TEXT ·libc_chflags_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_chflags_trampoline(SB),NOSPLIT,$0-0 JMP libc_chflags(SB) -TEXT ·libc_chmod_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_chmod_trampoline(SB),NOSPLIT,$0-0 JMP libc_chmod(SB) -TEXT ·libc_chown_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_chown_trampoline(SB),NOSPLIT,$0-0 JMP libc_chown(SB) -TEXT ·libc_chroot_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_chroot_trampoline(SB),NOSPLIT,$0-0 JMP libc_chroot(SB) -TEXT ·libc_close_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_close_trampoline(SB),NOSPLIT,$0-0 JMP libc_close(SB) -TEXT ·libc_dup_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_dup_trampoline(SB),NOSPLIT,$0-0 JMP libc_dup(SB) -TEXT ·libc_dup2_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_dup2_trampoline(SB),NOSPLIT,$0-0 JMP libc_dup2(SB) -TEXT ·libc_fchdir_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fchdir_trampoline(SB),NOSPLIT,$0-0 JMP libc_fchdir(SB) -TEXT ·libc_fchflags_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fchflags_trampoline(SB),NOSPLIT,$0-0 JMP libc_fchflags(SB) -TEXT ·libc_fchmod_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fchmod_trampoline(SB),NOSPLIT,$0-0 JMP libc_fchmod(SB) -TEXT ·libc_fchown_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fchown_trampoline(SB),NOSPLIT,$0-0 JMP libc_fchown(SB) -TEXT ·libc_flock_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_flock_trampoline(SB),NOSPLIT,$0-0 JMP libc_flock(SB) -TEXT ·libc_fpathconf_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fpathconf_trampoline(SB),NOSPLIT,$0-0 JMP libc_fpathconf(SB) -TEXT ·libc_fstat_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fstat_trampoline(SB),NOSPLIT,$0-0 JMP libc_fstat(SB) -TEXT ·libc_fstatfs_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fstatfs_trampoline(SB),NOSPLIT,$0-0 JMP libc_fstatfs(SB) -TEXT ·libc_fsync_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fsync_trampoline(SB),NOSPLIT,$0-0 JMP libc_fsync(SB) -TEXT ·libc_ftruncate_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_ftruncate_trampoline(SB),NOSPLIT,$0-0 JMP libc_ftruncate(SB) -TEXT ·libc_getegid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getegid_trampoline(SB),NOSPLIT,$0-0 JMP libc_getegid(SB) -TEXT ·libc_geteuid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_geteuid_trampoline(SB),NOSPLIT,$0-0 JMP libc_geteuid(SB) -TEXT ·libc_getgid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getgid_trampoline(SB),NOSPLIT,$0-0 JMP libc_getgid(SB) -TEXT ·libc_getpgid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getpgid_trampoline(SB),NOSPLIT,$0-0 JMP libc_getpgid(SB) -TEXT ·libc_getpgrp_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getpgrp_trampoline(SB),NOSPLIT,$0-0 JMP libc_getpgrp(SB) -TEXT ·libc_getpid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getpid_trampoline(SB),NOSPLIT,$0-0 JMP libc_getpid(SB) -TEXT ·libc_getppid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getppid_trampoline(SB),NOSPLIT,$0-0 JMP libc_getppid(SB) -TEXT ·libc_getpriority_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getpriority_trampoline(SB),NOSPLIT,$0-0 JMP libc_getpriority(SB) -TEXT ·libc_getrlimit_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getrlimit_trampoline(SB),NOSPLIT,$0-0 JMP libc_getrlimit(SB) -TEXT ·libc_getrusage_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getrusage_trampoline(SB),NOSPLIT,$0-0 JMP libc_getrusage(SB) -TEXT ·libc_getsid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getsid_trampoline(SB),NOSPLIT,$0-0 JMP libc_getsid(SB) -TEXT ·libc_gettimeofday_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_gettimeofday_trampoline(SB),NOSPLIT,$0-0 JMP libc_gettimeofday(SB) -TEXT ·libc_getuid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getuid_trampoline(SB),NOSPLIT,$0-0 JMP libc_getuid(SB) -TEXT ·libc_issetugid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_issetugid_trampoline(SB),NOSPLIT,$0-0 JMP libc_issetugid(SB) -TEXT ·libc_kill_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_kill_trampoline(SB),NOSPLIT,$0-0 JMP libc_kill(SB) -TEXT ·libc_kqueue_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_kqueue_trampoline(SB),NOSPLIT,$0-0 JMP libc_kqueue(SB) -TEXT ·libc_lchown_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_lchown_trampoline(SB),NOSPLIT,$0-0 JMP libc_lchown(SB) -TEXT ·libc_link_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_link_trampoline(SB),NOSPLIT,$0-0 JMP libc_link(SB) -TEXT ·libc_listen_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_listen_trampoline(SB),NOSPLIT,$0-0 JMP libc_listen(SB) -TEXT ·libc_lstat_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_lstat_trampoline(SB),NOSPLIT,$0-0 JMP libc_lstat(SB) -TEXT ·libc_mkdir_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_mkdir_trampoline(SB),NOSPLIT,$0-0 JMP libc_mkdir(SB) -TEXT ·libc_mkfifo_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_mkfifo_trampoline(SB),NOSPLIT,$0-0 JMP libc_mkfifo(SB) -TEXT ·libc_mknod_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_mknod_trampoline(SB),NOSPLIT,$0-0 JMP libc_mknod(SB) -TEXT ·libc_nanosleep_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_nanosleep_trampoline(SB),NOSPLIT,$0-0 JMP libc_nanosleep(SB) -TEXT ·libc_open_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_open_trampoline(SB),NOSPLIT,$0-0 JMP libc_open(SB) -TEXT ·libc_pathconf_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_pathconf_trampoline(SB),NOSPLIT,$0-0 JMP libc_pathconf(SB) -TEXT ·libc_pread_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_pread_trampoline(SB),NOSPLIT,$0-0 JMP libc_pread(SB) -TEXT ·libc_pwrite_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_pwrite_trampoline(SB),NOSPLIT,$0-0 JMP libc_pwrite(SB) -TEXT ·libc_read_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_read_trampoline(SB),NOSPLIT,$0-0 JMP libc_read(SB) -TEXT ·libc_readlink_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_readlink_trampoline(SB),NOSPLIT,$0-0 JMP libc_readlink(SB) -TEXT ·libc_rename_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_rename_trampoline(SB),NOSPLIT,$0-0 JMP libc_rename(SB) -TEXT ·libc_revoke_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_revoke_trampoline(SB),NOSPLIT,$0-0 JMP libc_revoke(SB) -TEXT ·libc_rmdir_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_rmdir_trampoline(SB),NOSPLIT,$0-0 JMP libc_rmdir(SB) -TEXT ·libc_select_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_select_trampoline(SB),NOSPLIT,$0-0 JMP libc_select(SB) -TEXT ·libc_setegid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setegid_trampoline(SB),NOSPLIT,$0-0 JMP libc_setegid(SB) -TEXT ·libc_seteuid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_seteuid_trampoline(SB),NOSPLIT,$0-0 JMP libc_seteuid(SB) -TEXT ·libc_setgid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setgid_trampoline(SB),NOSPLIT,$0-0 JMP libc_setgid(SB) -TEXT ·libc_setlogin_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setlogin_trampoline(SB),NOSPLIT,$0-0 JMP libc_setlogin(SB) -TEXT ·libc_setpgid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setpgid_trampoline(SB),NOSPLIT,$0-0 JMP libc_setpgid(SB) -TEXT ·libc_setpriority_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setpriority_trampoline(SB),NOSPLIT,$0-0 JMP libc_setpriority(SB) -TEXT ·libc_setregid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setregid_trampoline(SB),NOSPLIT,$0-0 JMP libc_setregid(SB) -TEXT ·libc_setreuid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setreuid_trampoline(SB),NOSPLIT,$0-0 JMP libc_setreuid(SB) -TEXT ·libc_setrlimit_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setrlimit_trampoline(SB),NOSPLIT,$0-0 JMP libc_setrlimit(SB) -TEXT ·libc_setsid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setsid_trampoline(SB),NOSPLIT,$0-0 JMP libc_setsid(SB) -TEXT ·libc_settimeofday_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_settimeofday_trampoline(SB),NOSPLIT,$0-0 JMP libc_settimeofday(SB) -TEXT ·libc_setuid_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_setuid_trampoline(SB),NOSPLIT,$0-0 JMP libc_setuid(SB) -TEXT ·libc_stat_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_stat_trampoline(SB),NOSPLIT,$0-0 JMP libc_stat(SB) -TEXT ·libc_statfs_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_statfs_trampoline(SB),NOSPLIT,$0-0 JMP libc_statfs(SB) -TEXT ·libc_symlink_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_symlink_trampoline(SB),NOSPLIT,$0-0 JMP libc_symlink(SB) -TEXT ·libc_sync_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_sync_trampoline(SB),NOSPLIT,$0-0 JMP libc_sync(SB) -TEXT ·libc_truncate_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_truncate_trampoline(SB),NOSPLIT,$0-0 JMP libc_truncate(SB) -TEXT ·libc_umask_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_umask_trampoline(SB),NOSPLIT,$0-0 JMP libc_umask(SB) -TEXT ·libc_unlink_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_unlink_trampoline(SB),NOSPLIT,$0-0 JMP libc_unlink(SB) -TEXT ·libc_unmount_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_unmount_trampoline(SB),NOSPLIT,$0-0 JMP libc_unmount(SB) -TEXT ·libc_write_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_write_trampoline(SB),NOSPLIT,$0-0 JMP libc_write(SB) -TEXT ·libc_mmap_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_mmap_trampoline(SB),NOSPLIT,$0-0 JMP libc_mmap(SB) -TEXT ·libc_munmap_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_munmap_trampoline(SB),NOSPLIT,$0-0 JMP libc_munmap(SB) -TEXT ·libc_utimensat_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_utimensat_trampoline(SB),NOSPLIT,$0-0 JMP libc_utimensat(SB) -TEXT ·libc_syscall_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_syscall_trampoline(SB),NOSPLIT,$0-0 JMP libc_syscall(SB) -TEXT ·libc_lseek_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_lseek_trampoline(SB),NOSPLIT,$0-0 JMP libc_lseek(SB) -TEXT ·libc_getcwd_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getcwd_trampoline(SB),NOSPLIT,$0-0 JMP libc_getcwd(SB) -TEXT ·libc_sysctl_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_sysctl_trampoline(SB),NOSPLIT,$0-0 JMP libc_sysctl(SB) -TEXT ·libc_fork_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fork_trampoline(SB),NOSPLIT,$0-0 JMP libc_fork(SB) -TEXT ·libc_ioctl_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_ioctl_trampoline(SB),NOSPLIT,$0-0 JMP libc_ioctl(SB) -TEXT ·libc_execve_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_execve_trampoline(SB),NOSPLIT,$0-0 JMP libc_execve(SB) -TEXT ·libc_exit_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_exit_trampoline(SB),NOSPLIT,$0-0 JMP libc_exit(SB) -TEXT ·libc_ptrace_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_ptrace_trampoline(SB),NOSPLIT,$0-0 JMP libc_ptrace(SB) -TEXT ·libc_getentropy_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_getentropy_trampoline(SB),NOSPLIT,$0-0 JMP libc_getentropy(SB) -TEXT ·libc_fstatat_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_fstatat_trampoline(SB),NOSPLIT,$0-0 JMP libc_fstatat(SB) -TEXT ·libc_unlinkat_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_unlinkat_trampoline(SB),NOSPLIT,$0-0 JMP libc_unlinkat(SB) -TEXT ·libc_openat_trampoline(SB),NOSPLIT,$0-0 +TEXT ·libc_openat_trampoline(SB),NOSPLIT,$0-0 JMP libc_openat(SB) -- cgit v1.3-5-g9baa From 52d5cb2822966c00ce2ef97eb08bec4850d76fb2 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Wed, 3 Feb 2021 18:10:04 -0500 Subject: [dev.regabi] cmd/internal/obj: access Attribute atomically Symbol's Attributes and ABI are in the same word. In the concurrent backend, we may read one symbol's ABI (the callee) while setting its attributes in another goroutine. Fix racecompile build. Change-Id: I500e869bafdd72080119ab243db94eee3afcf926 Reviewed-on: https://go-review.googlesource.com/c/go/+/289290 Trust: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Go Bot Reviewed-by: Than McIntosh --- src/cmd/internal/obj/link.go | 64 +++++++++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 24 deletions(-) (limited to 'src/cmd/internal') diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go index 35cb53cbf6..8206902328 100644 --- a/src/cmd/internal/obj/link.go +++ b/src/cmd/internal/obj/link.go @@ -39,6 +39,7 @@ import ( "cmd/internal/sys" "fmt" "sync" + "sync/atomic" ) // An Addr is an argument to an instruction. @@ -647,37 +648,52 @@ const ( attrABIBase ) -func (a Attribute) DuplicateOK() bool { return a&AttrDuplicateOK != 0 } -func (a Attribute) MakeTypelink() bool { return a&AttrMakeTypelink != 0 } -func (a Attribute) CFunc() bool { return a&AttrCFunc != 0 } -func (a Attribute) NoSplit() bool { return a&AttrNoSplit != 0 } -func (a Attribute) Leaf() bool { return a&AttrLeaf != 0 } -func (a Attribute) OnList() bool { return a&AttrOnList != 0 } -func (a Attribute) ReflectMethod() bool { return a&AttrReflectMethod != 0 } -func (a Attribute) Local() bool { return a&AttrLocal != 0 } -func (a Attribute) Wrapper() bool { return a&AttrWrapper != 0 } -func (a Attribute) NeedCtxt() bool { return a&AttrNeedCtxt != 0 } -func (a Attribute) NoFrame() bool { return a&AttrNoFrame != 0 } -func (a Attribute) Static() bool { return a&AttrStatic != 0 } -func (a Attribute) WasInlined() bool { return a&AttrWasInlined != 0 } -func (a Attribute) TopFrame() bool { return a&AttrTopFrame != 0 } -func (a Attribute) Indexed() bool { return a&AttrIndexed != 0 } -func (a Attribute) UsedInIface() bool { return a&AttrUsedInIface != 0 } -func (a Attribute) ContentAddressable() bool { return a&AttrContentAddressable != 0 } -func (a Attribute) ABIWrapper() bool { return a&AttrABIWrapper != 0 } +func (a *Attribute) load() Attribute { return Attribute(atomic.LoadUint32((*uint32)(a))) } + +func (a *Attribute) DuplicateOK() bool { return a.load()&AttrDuplicateOK != 0 } +func (a *Attribute) MakeTypelink() bool { return a.load()&AttrMakeTypelink != 0 } +func (a *Attribute) CFunc() bool { return a.load()&AttrCFunc != 0 } +func (a *Attribute) NoSplit() bool { return a.load()&AttrNoSplit != 0 } +func (a *Attribute) Leaf() bool { return a.load()&AttrLeaf != 0 } +func (a *Attribute) OnList() bool { return a.load()&AttrOnList != 0 } +func (a *Attribute) ReflectMethod() bool { return a.load()&AttrReflectMethod != 0 } +func (a *Attribute) Local() bool { return a.load()&AttrLocal != 0 } +func (a *Attribute) Wrapper() bool { return a.load()&AttrWrapper != 0 } +func (a *Attribute) NeedCtxt() bool { return a.load()&AttrNeedCtxt != 0 } +func (a *Attribute) NoFrame() bool { return a.load()&AttrNoFrame != 0 } +func (a *Attribute) Static() bool { return a.load()&AttrStatic != 0 } +func (a *Attribute) WasInlined() bool { return a.load()&AttrWasInlined != 0 } +func (a *Attribute) TopFrame() bool { return a.load()&AttrTopFrame != 0 } +func (a *Attribute) Indexed() bool { return a.load()&AttrIndexed != 0 } +func (a *Attribute) UsedInIface() bool { return a.load()&AttrUsedInIface != 0 } +func (a *Attribute) ContentAddressable() bool { return a.load()&AttrContentAddressable != 0 } +func (a *Attribute) ABIWrapper() bool { return a.load()&AttrABIWrapper != 0 } func (a *Attribute) Set(flag Attribute, value bool) { - if value { - *a |= flag - } else { - *a &^= flag + for { + v0 := a.load() + v := v0 + if value { + v |= flag + } else { + v &^= flag + } + if atomic.CompareAndSwapUint32((*uint32)(a), uint32(v0), uint32(v)) { + break + } } } -func (a Attribute) ABI() ABI { return ABI(a / attrABIBase) } +func (a *Attribute) ABI() ABI { return ABI(a.load() / attrABIBase) } func (a *Attribute) SetABI(abi ABI) { const mask = 1 // Only one ABI bit for now. - *a = (*a &^ (mask * attrABIBase)) | Attribute(abi)*attrABIBase + for { + v0 := a.load() + v := (v0 &^ (mask * attrABIBase)) | Attribute(abi)*attrABIBase + if atomic.CompareAndSwapUint32((*uint32)(a), uint32(v0), uint32(v)) { + break + } + } } var textAttrStrings = [...]struct { -- cgit v1.3-5-g9baa From 397a46a10a2cc8557e965af269915909cb5c0a80 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Wed, 3 Feb 2021 12:09:53 -0500 Subject: [dev.regabi] cmd/asm: define g register on AMD64 Define g register as R14 on AMD64. It is not used now, but will be in later CLs. The name "R14" is still recognized. Change-Id: I9a066b15bf1051113db8c6640605e350cea397b9 Reviewed-on: https://go-review.googlesource.com/c/go/+/289195 Trust: Cherry Zhang Reviewed-by: Than McIntosh --- src/cmd/asm/internal/arch/arch.go | 4 ++++ src/cmd/asm/internal/asm/operand_test.go | 1 + src/cmd/internal/obj/x86/a.out.go | 1 + 3 files changed, 6 insertions(+) (limited to 'src/cmd/internal') diff --git a/src/cmd/asm/internal/arch/arch.go b/src/cmd/asm/internal/arch/arch.go index a62e55191e..026d8abf81 100644 --- a/src/cmd/asm/internal/arch/arch.go +++ b/src/cmd/asm/internal/arch/arch.go @@ -109,6 +109,10 @@ func archX86(linkArch *obj.LinkArch) *Arch { register["SB"] = RSB register["FP"] = RFP register["PC"] = RPC + if linkArch == &x86.Linkamd64 { + // Alias g to R14 + register["g"] = x86.REGG + } // Register prefix not used on this architecture. instructions := make(map[string]obj.As) diff --git a/src/cmd/asm/internal/asm/operand_test.go b/src/cmd/asm/internal/asm/operand_test.go index 2e83e176b2..c6def15e20 100644 --- a/src/cmd/asm/internal/asm/operand_test.go +++ b/src/cmd/asm/internal/asm/operand_test.go @@ -259,6 +259,7 @@ var amd64OperandTests = []operandTest{ {"R15", "R15"}, {"R8", "R8"}, {"R9", "R9"}, + {"g", "R14"}, {"SI", "SI"}, {"SP", "SP"}, {"X0", "X0"}, diff --git a/src/cmd/internal/obj/x86/a.out.go b/src/cmd/internal/obj/x86/a.out.go index 30c1a6a445..3be4b59da4 100644 --- a/src/cmd/internal/obj/x86/a.out.go +++ b/src/cmd/internal/obj/x86/a.out.go @@ -263,6 +263,7 @@ const ( FREGRET = REG_X0 REGSP = REG_SP REGCTXT = REG_DX + REGG = REG_R14 // g register in ABIInternal REGEXT = REG_R15 // compiler allocates external registers R15 down FREGMIN = REG_X0 + 5 // first register variable FREGEXT = REG_X0 + 15 // first external register -- cgit v1.3-5-g9baa From 2e60c00f56cdab9bb02e649e089b2ee5761acf26 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Thu, 4 Feb 2021 11:43:24 -0500 Subject: [dev.regabi] cmd/internal/obj/x86: use g register in stack bounds check In ABIInternal context, we can directly use the g register for stack bounds check. Change-Id: I8b1073a3343984a6cd76cf5734ddc4a8cd5dc73f Reviewed-on: https://go-review.googlesource.com/c/go/+/289711 Trust: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Go Bot Reviewed-by: David Chase --- src/cmd/internal/obj/x86/obj6.go | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) (limited to 'src/cmd/internal') diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go index 1674db626f..84de58a4c4 100644 --- a/src/cmd/internal/obj/x86/obj6.go +++ b/src/cmd/internal/obj/x86/obj6.go @@ -637,13 +637,19 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { } } + var regg int16 if !p.From.Sym.NoSplit() || (p.From.Sym.Wrapper() && !p.From.Sym.ABIWrapper()) { - p = obj.Appendp(p, newprog) - p = load_g_cx(ctxt, p, newprog) // load g into CX + if ctxt.Arch.Family == sys.AMD64 && objabi.Regabi_enabled != 0 && cursym.ABI() == obj.ABIInternal { + regg = REGG // use the g register directly in ABIInternal + } else { + p = obj.Appendp(p, newprog) + p = load_g_cx(ctxt, p, newprog) // load g into CX + regg = REG_CX + } } if !cursym.Func().Text.From.Sym.NoSplit() { - p = stacksplit(ctxt, cursym, p, newprog, autoffset, int32(textarg)) // emit split check + p = stacksplit(ctxt, cursym, p, newprog, autoffset, int32(textarg), regg) // emit split check } // Delve debugger would like the next instruction to be noted as the end of the function prologue. @@ -695,7 +701,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { // g._panic.argp = bottom-of-frame // } // - // MOVQ g_panic(CX), BX + // MOVQ g_panic(g), BX // TESTQ BX, BX // JNE checkargp // end: @@ -718,7 +724,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { p = obj.Appendp(p, newprog) p.As = AMOVQ p.From.Type = obj.TYPE_MEM - p.From.Reg = REG_CX + p.From.Reg = regg p.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // g_panic p.To.Type = obj.TYPE_REG p.To.Reg = REG_BX @@ -969,9 +975,9 @@ func load_g_cx(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) *obj.Prog { // Append code to p to check for stack split. // Appends to (does not overwrite) p. -// Assumes g is in CX. +// Assumes g is in rg. // Returns last new instruction. -func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgAlloc, framesize int32, textarg int32) *obj.Prog { +func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgAlloc, framesize int32, textarg int32, rg int16) *obj.Prog { cmp := ACMPQ lea := ALEAQ mov := AMOVQ @@ -993,7 +999,8 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA p.As = cmp p.From.Type = obj.TYPE_REG p.From.Reg = REG_SP - indir_cx(ctxt, &p.To) + p.To.Type = obj.TYPE_MEM + p.To.Reg = rg p.To.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0 if cursym.CFunc() { p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1 @@ -1021,7 +1028,8 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA p.As = cmp p.From.Type = obj.TYPE_REG p.From.Reg = REG_AX - indir_cx(ctxt, &p.To) + p.To.Type = obj.TYPE_MEM + p.To.Reg = rg p.To.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0 if cursym.CFunc() { p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1 @@ -1047,7 +1055,8 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA p = obj.Appendp(p, newprog) p.As = mov - indir_cx(ctxt, &p.From) + p.From.Type = obj.TYPE_MEM + p.From.Reg = rg p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0 if cursym.CFunc() { p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1 -- cgit v1.3-5-g9baa