Compare commits

..

59 Commits

Author SHA1 Message Date
Chris Broadfoot
7f40c1214d [release-branch.go1.9] go1.9.1
Change-Id: I711b38738a7f6fade42a2821908234940f3cf280
Reviewed-on: https://go-review.googlesource.com/68233
Reviewed-by: Russ Cox <rsc@golang.org>
2017-10-04 18:39:31 +00:00
Chris Broadfoot
598433b17a [release-branch.go1.9] doc: document go1.9.1 and go1.8.4
Change-Id: Ib42fabc6829b6033373c0378713733f88e73e73d
Reviewed-on: https://go-review.googlesource.com/68230
Reviewed-by: Russ Cox <rsc@golang.org>
Reviewed-on: https://go-review.googlesource.com/68231
Reviewed-by: Chris Broadfoot <cbro@golang.org>
2017-10-04 18:36:02 +00:00
Tom Bergan
815cad3ed0 [release-branch.go1.9] doc/1.9: add mention of net/http.LocalAddrContextKey
Fixes #21603

Reviewed-on: https://go-review.googlesource.com/59530
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-on: https://go-review.googlesource.com/59670
Reviewed-by: Chris Broadfoot <cbro@golang.org>
Reviewed-by: Tom Bergan <tombergan@google.com>

Change-Id: Ie9732d57948593dc0306a4a649664eedb3de370c
Reviewed-on: https://go-review.googlesource.com/68232
Reviewed-by: Chris Broadfoot <cbro@golang.org>
2017-10-04 18:35:59 +00:00
Russ Cox
1900d34a10 [release-branch.go1.9] net/smtp: fix PlainAuth to refuse to send passwords to non-TLS servers
PlainAuth originally refused to send passwords to non-TLS servers
and was documented as such.

In 2013, issue #5184 was filed objecting to the TLS requirement,
despite the fact that it is spelled out clearly in RFC 4954.
The only possibly legitimate use case raised was using PLAIN auth
for connections to localhost, and the suggested fix was to let the
server decide: if it advertises that PLAIN auth is OK, believe it.
That approach was adopted in CL 8279043 and released in Go 1.1.

Unfortunately, this is exactly wrong. The whole point of the TLS
requirement is to make sure not to send the password to the wrong
server or to a man-in-the-middle. Instead of implementing this rule,
CL 8279043 blindly trusts the server, so that if a man-in-the-middle
says "it's OK, you can send me your password," PlainAuth does.
And the documentation was not updated to reflect any of this.

This CL restores the original TLS check, as required by RFC 4954
and as promised in the documentation for PlainAuth.
It then carves out a documented exception for connections made
to localhost (defined as "localhost", "127.0.0.1", or "::1").

Cherry-pick of CL 68170.

Change-Id: I1d3729bbd33aa2f11a03f4c000e6bb473164957b
Reviewed-on: https://go-review.googlesource.com/68210
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Chris Broadfoot <cbro@golang.org>
2017-10-04 18:19:11 +00:00
Russ Cox
a39bcecea6 [release-branch.go1.9] cmd/go: reject update of VCS inside VCS
Cherry-pick of CL 68110.

Change-Id: Iae84c6404ab5eeb6950faa2364f97a017c67c506
Reviewed-on: https://go-review.googlesource.com/68022
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Chris Broadfoot <cbro@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2017-10-04 18:15:57 +00:00
Russ Cox
d9e64910af [release-branch.go1.9] runtime: deflake TestPeriodicGC
It was only waiting 0.1 seconds for the two GCs it wanted.
Let it wait 1 second.

Change-Id: Ib3cdc8127cbf95694a9f173643c02529a85063af
Reviewed-on: https://go-review.googlesource.com/68118
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Chris Broadfoot <cbro@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2017-10-04 16:47:06 +00:00
Chris Broadfoot
c8aec4095e [release-branch.go1.9] go1.9
Change-Id: I0899ec0150f2a051b7572879b446a8548f742ae0
Reviewed-on: https://go-review.googlesource.com/58731
Run-TryBot: Chris Broadfoot <cbro@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-08-24 20:52:14 +00:00
Chris Broadfoot
b8c9ef9f09 [release-branch.go1.9] doc: add go1.9 to golang.org/project
Pre-emptive. Go 1.9 is expected to be released in August.

Change-Id: I0f58c012c4110bf490022dc2c1d69c0988d73bfa
Reviewed-on: https://go-review.googlesource.com/52351
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-on: https://go-review.googlesource.com/58730
Reviewed-by: Chris Broadfoot <cbro@golang.org>
2017-08-24 19:57:08 +00:00
Chris Broadfoot
136f4a6b2a [release-branch.go1.9] doc: document go1.9
Change-Id: I97075f24319a4b96cbeb9e3ff2e7b2056ff59e32
Reviewed-on: https://go-review.googlesource.com/58651
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-on: https://go-review.googlesource.com/58710
Reviewed-by: Chris Broadfoot <cbro@golang.org>
2017-08-24 19:55:44 +00:00
Ryuji IWATA
867be4c60c [release-branch.go1.9] doc/go1.9: fix typo in Moved GOROOT
Change-Id: I71bfff6a3462e6dfd7a65ef76ec56644bae37c34
Reviewed-on: https://go-review.googlesource.com/57272
Reviewed-by: Avelino <t@avelino.xxx>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-on: https://go-review.googlesource.com/58650
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2017-08-24 19:54:21 +00:00
Josh Bleecher Snyder
9a4e7942ea [release-branch.go1.9] cmd/compile: remove gc.Sysfunc calls from 387 backend
[This is a cherry-pick of CL 54090 to the 1.9 release branch.]

gc.Sysfunc must not be called concurrently.
We set up runtime routines used by the backend
prior to doing any backend compilation.
I missed the 387 ones; fix that.

Sysfunc should have been unexported during 1.9.
I will rectify that in a subsequent CL.

Fixes #21352

Change-Id: I485bb1867b46d8e5cf64bc820b8963576dc16174
Reviewed-on: https://go-review.googlesource.com/55970
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
2017-08-22 18:24:54 +00:00
Ian Lance Taylor
ff38035a62 [release-branch.go1.9] doc/go1.9: fix typo in crypto/x509 of "Minor changes to the library".
Backport of https://golang.org/cl/57390 to 1.9 release branch.

Change-Id: Ieea5a048732db7ee5dc5cf13f06e11ca4f5313cc
Reviewed-on: https://go-review.googlesource.com/57450
Reviewed-by: Keith Randall <khr@golang.org>
2017-08-22 18:21:23 +00:00
Austin Clements
42046e8989 [release-branch.go1.9] runtime: fix false positive race in profile label reading
Because profile labels are copied from the goroutine into the tag
buffer by the signal handler, there's a carefully-crafted set of race
detector annotations to create the necessary happens-before edges
between setting a goroutine's profile label and retrieving it from the
profile tag buffer.

Given the constraints of the signal handler, we have to approximate
the true synchronization behavior. Currently, that approximation is
too weak.

Ideally, runtime_setProfLabel would perform a store-release on
&getg().labels and copying each label into the profile would perform a
load-acquire on &getg().labels. This would create the necessary
happens-before edges through each individual g.labels object.

Since we can't do this in the signal handler, we instead synchronize
on a "labelSync" global. The problem occurs with the following
sequence:

1. Goroutine 1 calls setProfLabel, which does a store-release on
   labelSync.

2. Goroutine 2 calls setProfLabel, which does a store-release on
   labelSync.

3. Goroutine 3 reads the profile, which does a load-acquire on
   labelSync.

The problem is that the load-acquire only synchronizes with the *most
recent* store-release to labelSync, and the two store-releases don't
synchronize with each other. So, once goroutine 3 touches the label
set by goroutine 1, we report a race.

The solution is to use racereleasemerge. This is like a
read-modify-write, rather than just a store-release. Each RMW of
labelSync in runtime_setProfLabel synchronizes with the previous RMW
of labelSync, and this ultimately carries forward to the load-acquire,
so it synchronizes with *all* setProfLabel operations, not just the
most recent.

Change-Id: Iab58329b156122002fff12cfe64fbeacb31c9613
Reviewed-on: https://go-review.googlesource.com/57190
Run-TryBot: Austin Clements <austin@google.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-08-18 23:07:14 +00:00
Ian Lance Taylor
fbf7e1f295 [release-branch.go1.9] testing: don't fail all tests after racy test failure
The code was adding race.Errors to t.raceErrors before checking
Failed, but Failed was using t.raceErrors+race.Errors. We don't want
to change Failed, since that would affect tests themselves, so modify
the harness to not unnecessarily change t.raceErrors.

Updates #19851
Fixes #21338

Change-Id: I483f27c68c340928f1cbdef160abc0a5716efb5d
Reviewed-on: https://go-review.googlesource.com/57151
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2017-08-18 21:10:46 +00:00
Ian Lance Taylor
21312a4b5e [release-branch.go1.9] cmd/dist: update deps.go for current dependencies
Fixes #21456

Change-Id: I7841d816e8c1c581e61db4f24124f99f5184fead
Reviewed-on: https://go-review.googlesource.com/57170
Run-TryBot: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2017-08-18 21:10:29 +00:00
Cherry Zhang
5927854f7d [release-branch.go1.9] cmd/compile: add rules handling unsigned div/mod by constant 1<<63
Cherry-pick CL 56890.

Normally 64-bit div/mod is turned into runtime calls on 32-bit
arch, but the front end leaves power-of-two constant division
and hopes the SSA backend turns into a shift or AND. The SSA rule is

(Mod64u <t> n (Const64 [c])) && isPowerOfTwo(c) -> (And64 n (Const64 <t> [c-1]))

But isPowerOfTwo returns true only for positive int64, which leaves
out 1<<63 unhandled. Add a special case for 1<<63.

Fixes #21517.

Change-Id: Ic91f86fd5e035a8bb64b937c15cb1c38fec917d6
Reviewed-on: https://go-review.googlesource.com/57070
Run-TryBot: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2017-08-18 18:43:00 +00:00
pvoicu
65717b2dca [release-branch.go1.9] runtime: fix usleep by correctly setting nanoseconds parameter for pselect6
Fixes #21518

Change-Id: Idd67e3f0410d0ce991b34dcc0c8f15e0d5c529c9
Reviewed-on: https://go-review.googlesource.com/56891
Run-TryBot: Austin Clements <austin@google.com>
Reviewed-by: Petrica Voicu <pvoicu@paypal.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2017-08-18 14:14:39 +00:00
Chris Broadfoot
048c9cfaac [release-branch.go1.9] go1.9rc2
Change-Id: If95cec0ec7e32cdb450818c4c55e2d03b847ab65
Reviewed-on: https://go-review.googlesource.com/53630
Reviewed-by: Austin Clements <austin@google.com>
2017-08-07 20:29:01 +00:00
Chris Broadfoot
cff0de3da3 [release-branch.go1.9] all: merge master into release-branch.go1.9
579120323f runtime: mapassign_* should use typedmemmove to update keys
380525598c all: remove some manual hyphenation
f096b5b340 runtime: mark activeModules nosplit/nowritebarrier
3e3da54633 math/bits: fix example for OnesCount64
9b1e7cf2ac math/bits: add examples for OnesCount functions
b01db023b1 misc/cgo/testsanitizers: also skip tsan11/tsan12 when using GCC
a279b53a18 reflect: document how DeepEqual handles cycles
909f409a8d doc: mention handling of moved GOROOT in 1.9 release notes
58ad0176ca doc: use better wording to explain type-aware completion
92dac21d29 doc: replace paid with commercial
9bb98e02de doc/1.9: add CL 43712, ReverseProxy of HTTP/2 trailers to the release notes.
78d74fc2cd doc: clarify that Gogland is for paid IntelliJ platform IDEs
5495047223 doc/1.9: fix broken html link in CL 53030/53210
890e0e862f doc: fix bad link in go1.9 release notes
be596f049a doc/1.9: fix stray html in CL 53030
0173631d53 encoding/binary: add examples for varint functions
ac0ccf3cd2 doc/1.9: add CL 36696 for crypto/x509 to the release notes
cc402c2c4d doc: hide blog content for golang.google.cn
f396fa4285 internal/poll: don't add non-sockets to runtime poller
664cd26c89 cmd/vet: don't exit with failure on type checking error
a8730cd93a doc: hide video and share if being served from CN
b63db76c4a testsanitizers: check that tsan program runs, skip tsan10 on gcc
193eda7291 time: skip ZoneAbbr test in timezones with no abbreviation
6f08c935a9 cmd/go: show examples with empty output in go test -list
f20944de78 cmd/compile: set/unset base register for better assembly print
623e2c4603 runtime: map bitmap and spans during heap initialization
780249eed4 runtime: fall back to small mmaps if we fail to grow reservation
31b2c4cc25 .github: add .md extension to SUPPORT file
ac29f30dbb plugin: mention that there are known bugs with plugins
45a4609c0a cmd/dist: skip moved GOROOT on Go's Windows builders when not sharding tests
e157fac02d test: add README
835dfef939 runtime/pprof: prevent a deadlock that SIGPROF might create on mips{,le}
df91b8044d doc: list editor options by name, not plugin name
3d9475c04b doc: cleanup editor page
b9661a14ea doc: add Atom to editor guide
ee392ac10c cmd/compile: consider exported flag in namedata

Change-Id: I3a48493e8c05d97cb3b61635503ef0ccd646e5cb
2017-08-07 10:28:35 -07:00
Keith Randall
579120323f runtime: mapassign_* should use typedmemmove to update keys
We need to make sure that when the key contains a pointer, we use
a write barrier to update the key.

Also mapdelete_* should use typedmemclr.

Fixes #21297

Change-Id: I63dc90bec1cb909c2c6e08676c9ec853d736cdf8
Reviewed-on: https://go-review.googlesource.com/53414
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-08-07 06:24:42 +00:00
Josh Bleecher Snyder
380525598c all: remove some manual hyphenation
Manual hyphenation doesn't work well when text gets reflown,
for example by godoc.

There are a few other manual hyphenations in the tree,
but they are in local comments or comments for unexported functions.

Change-Id: I17c9b1fee1def650da48903b3aae2fa1e1119a65
Reviewed-on: https://go-review.googlesource.com/53510
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2017-08-06 16:14:46 +00:00
Ian Lance Taylor
f096b5b340 runtime: mark activeModules nosplit/nowritebarrier
The activeModules function is called by the cgo pointer checking code,
which is called by the write barrier (when GODEBUG=cgocheck=2), and as
such must be nosplit/nowritebarrier.

Fixes #21306

Change-Id: I57f2124f14de7f3872b2de9532abab15df95d45a
Reviewed-on: https://go-review.googlesource.com/53352
Reviewed-by: Austin Clements <austin@google.com>
2017-08-05 18:05:41 +00:00
Francesc Campoy Flores
3e3da54633 math/bits: fix example for OnesCount64
Erroneously called OnesCount instead of OnesCount64

Change-Id: Ie877e43f213253e45d31f64931c4a15915849586
Reviewed-on: https://go-review.googlesource.com/53410
Reviewed-by: Chris Broadfoot <cbro@golang.org>
2017-08-05 00:20:37 +00:00
Francesc Campoy
9b1e7cf2ac math/bits: add examples for OnesCount functions
Change-Id: Ie673f9665825a40281c2584d478ba1260f725856
Reviewed-on: https://go-review.googlesource.com/53357
Run-TryBot: Chris Broadfoot <cbro@golang.org>
Reviewed-by: Chris Broadfoot <cbro@golang.org>
2017-08-04 23:24:07 +00:00
Ian Lance Taylor
b01db023b1 misc/cgo/testsanitizers: also skip tsan11/tsan12 when using GCC
Updates #21196

Change-Id: I307cacc963448b90a23f633bec15498ba7bf1937
Reviewed-on: https://go-review.googlesource.com/53356
Run-TryBot: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Bryan Mills <bcmills@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2017-08-04 23:05:00 +00:00
Ian Lance Taylor
a279b53a18 reflect: document how DeepEqual handles cycles
Fixes #20428

Change-Id: Ia450e615728efd4ccb6e42117b547cac162f13a3
Reviewed-on: https://go-review.googlesource.com/52931
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2017-08-04 22:22:03 +00:00
Ian Lance Taylor
909f409a8d doc: mention handling of moved GOROOT in 1.9 release notes
Updates #20587

Change-Id: Ia131b9a4dc4986950d9ecbfcbd6b026ade234fc0
Reviewed-on: https://go-review.googlesource.com/53370
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2017-08-04 22:14:38 +00:00
Jaana Burcu Dogan
58ad0176ca doc: use better wording to explain type-aware completion
Some editors can filter the autocompletion suggestions based on
whether the code will compile once autocompleted. Explain this
feature with better wording.

Change-Id: I29e4b0396878f18c79208915402c0a209a813b04
Reviewed-on: https://go-review.googlesource.com/53355
Reviewed-by: Florin Patan <florinpatan@gmail.com>
Reviewed-by: Andrew Bonventre <andybons@golang.org>
2017-08-04 20:18:16 +00:00
Jaana Burcu Dogan
92dac21d29 doc: replace paid with commercial
Change-Id: I3e6de4da0648f61e254c7597f316df3e5791321a
Reviewed-on: https://go-review.googlesource.com/53354
Reviewed-by: Andrew Bonventre <andybons@golang.org>
2017-08-04 19:55:05 +00:00
Tristan Colgate
9bb98e02de doc/1.9: add CL 43712, ReverseProxy of HTTP/2 trailers to the release notes.
Add https://go-review.googlesource.com/c/43712,
"net/http/httputil: ReverseProxy should pass on unannounced Trailers"
to the relase notes.

Fixes #21307

Change-Id: I52c126987a5d0abc4153c0e71b535529c46cd457
Reviewed-on: https://go-review.googlesource.com/53290
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2017-08-04 18:36:20 +00:00
Jaana Burcu Dogan
78d74fc2cd doc: clarify that Gogland is for paid IntelliJ platform IDEs
Fixes #21213.

Change-Id: I7b8a84de92bbd1d3f78f8a9612f3af8cd092cb94
Reviewed-on: https://go-review.googlesource.com/53351
Reviewed-by: Andrew Bonventre <andybons@golang.org>
2017-08-04 16:53:33 +00:00
Dmitry Savintsev
5495047223 doc/1.9: fix broken html link in CL 53030/53210
Change-Id: I7176becd10ad84cbfc3fb9427e190028626e5baf
Reviewed-on: https://go-review.googlesource.com/53291
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-08-04 14:49:52 +00:00
Alberto Donizetti
890e0e862f doc: fix bad link in go1.9 release notes
Change-Id: I64ba37428f5cc560f0f20fe039feaecf5fcda93e
Reviewed-on: https://go-review.googlesource.com/53330
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-08-04 13:23:09 +00:00
Dmitry Savintsev
be596f049a doc/1.9: fix stray html in CL 53030
Change-Id: Ib4102b1e2a8863712f725c4d1e37fdbe3dfe3c07
Reviewed-on: https://go-review.googlesource.com/53210
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2017-08-03 21:30:23 +00:00
Axel Wagner
0173631d53 encoding/binary: add examples for varint functions
Change-Id: I191f6e46b452fadde9f641140445d843b0c7d534
Reviewed-on: https://go-review.googlesource.com/48604
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2017-08-03 21:00:45 +00:00
Dmitry Savintsev
ac0ccf3cd2 doc/1.9: add CL 36696 for crypto/x509 to the release notes
add https://go-review.googlesource.com/c/36696
"crypto/x509: ignore CN if SAN extension present"
to the release notes.

Fixes #21289

Change-Id: Ifa184d3816806a8da3c67b68476c923329acf13e
Reviewed-on: https://go-review.googlesource.com/53030
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-08-03 18:22:36 +00:00
Andrew Bonventre
cc402c2c4d doc: hide blog content for golang.google.cn
/blog redirects to blog.golang.org (currently blocked in China)
unless there is a local checkout of golang.org/x/blog, which is
not possible on App Engine Classic.

Change-Id: Ia695e663c9bebcc6c3bedea324c630299eaad4dc
Reviewed-on: https://go-review.googlesource.com/53051
Reviewed-by: Chris Broadfoot <cbro@golang.org>
2017-08-03 17:32:52 +00:00
Ian Lance Taylor
f396fa4285 internal/poll: don't add non-sockets to runtime poller
Updates #21172

Change-Id: I0fec6e645328bbc85f3e47f4f71dd8d1d68c75ab
Reviewed-on: https://go-review.googlesource.com/52551
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
2017-08-03 04:22:44 +00:00
Ian Lance Taylor
664cd26c89 cmd/vet: don't exit with failure on type checking error
The vet tool only reports a type checking error when invoked with -v.
Don't let that by itself cause vet to exit with an error exit status.

Updates #21188

Change-Id: I172c13d46c35d49e229e96e833683d8c82a77de7
Reviewed-on: https://go-review.googlesource.com/52851
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
Reviewed-by: Rob Pike <r@golang.org>
2017-08-03 04:22:02 +00:00
Andrew Bonventre
a8730cd93a doc: hide video and share if being served from CN
In the case where requests are coming from mainland China, hide
links to locations that are blocked and functionality that is
not permitted.

Additionally, some very small cleanup of the JS.

This change requires https://go-review.googlesource.com/c/52873

Change-Id: I7fc68748e629dbe5b966d6bf117e7f7b546966eb
Reviewed-on: https://go-review.googlesource.com/52872
Reviewed-by: Chris Broadfoot <cbro@golang.org>
2017-08-02 21:09:49 +00:00
Ian Lance Taylor
b63db76c4a testsanitizers: check that tsan program runs, skip tsan10 on gcc
Check not only that a tsan program can be built, but also that it runs.
This fails with some installations of GCC 7.

Skip the tsan10 program when using GCC, as it reportedly hangs.

This is a patch to help people build 1.9; we may be able to do a
better fix for 1.10.

Updates #21196

Change-Id: Icd1ffbd018dc65a97ff45cab1264b9b0c7fa0ab2
Reviewed-on: https://go-review.googlesource.com/52790
Run-TryBot: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Bryan Mills <bcmills@google.com>
Reviewed-by: Bryan Mills <bcmills@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2017-08-02 18:32:24 +00:00
Alberto Donizetti
193eda7291 time: skip ZoneAbbr test in timezones with no abbreviation
The testZoneAbbr assumes that

  Parse(RFC1123, t1.Format(RFC1123))

will always succeed. This is not true because Format will fall back to
the numeric zone (ex. -07) for timezones with no abbreviation, but
Parse won't accept the numeric zone when the layout specifies 'MST'
(an abbreviation).

Skip the zone abbreviation test in timezones with no abbreviation.

Fixes #21183

Change-Id: If04691cc23ae1075d8a953733024e17f5a7646de
Reviewed-on: https://go-review.googlesource.com/52430
Run-TryBot: Alberto Donizetti <alb.donizetti@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2017-08-02 16:22:49 +00:00
Seiji Takahashi
6f08c935a9 cmd/go: show examples with empty output in go test -list
Fixes #21205

Change-Id: I81b001eb42cbf2a5d5b7b82eb63548b22f501be5
Reviewed-on: https://go-review.googlesource.com/52110
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
2017-08-02 14:30:08 +00:00
Cherry Zhang
f20944de78 cmd/compile: set/unset base register for better assembly print
For address of an auto or arg, on all non-x86 architectures
the assembler backend encodes the actual SP offset in the
instruction but leaves the offset in Prog unchanged. When the
assembly is printed in compile -S, it shows an offset
relative to pseudo FP/SP with an actual hardware SP base
register (e.g. R13 on ARM). This is confusing. Unset the
base register if it is indeed SP, so the assembly output is
consistent. If the base register isn't SP, it should be an
error and the error output contains the actual base register.

For address loading instructions, the base register isn't set
in the compiler on non-x86 architectures. Set it. Normally it
is SP and will be unset in the change mentioned above for
printing. If it is not, it will be an error and the error
output contains the actual base register.

No change in generated binary, only printed assembly. Passes
"go build -a -toolexec 'toolstash -cmp' std cmd" on all
architectures.

Fixes #21064.

Change-Id: Ifafe8d5f9b437efbe824b63b3cbc2f5f6cdc1fd5
Reviewed-on: https://go-review.googlesource.com/49432
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
2017-08-02 12:24:02 +00:00
Austin Clements
196492a299 [release-branch.go1.9] runtime: map bitmap and spans during heap initialization
We lazily map the bitmap and spans areas as the heap grows. However,
right now we're very slightly too lazy. Specifically, the following
can happen on 32-bit:

1. mallocinit fails to allocate any heap arena, so
   arena_used == arena_alloc == arena_end == bitmap.

2. There's less than 256MB between the end of the bitmap mapping and
   the next mapping.

3. On the first allocation, mheap.sysAlloc sees that there's not
   enough room in [arena_alloc, arena_end) because there's no room at
   all. It gets a 256MB mapping from somewhere *lower* in the address
   space than arena_used and sets arena_alloc and arena_end to this
   hole.

4. Since the new arena_alloc is lower than arena_used, mheap.sysAlloc
   doesn't bother to call mheap.setArenaUsed, so we still don't have a
   bitmap mapping or a spans array mapping.

5. mheap.grow, which called mheap.sysAlloc, attempts to fill in the
   spans array and crashes.

Fix this by mapping the metadata regions for the initial arena_used
when the heap is initialized, rather than trying to wait for an
allocation. This maintains the intended invariant that the structures
are always mapped for [arena_start, arena_used).

Fixes #21044.

Cherry-pick of CL 51714. Fixes #21234.

Change-Id: I4422375a6e234b9f979d22135fc63ae3395946b0
Reviewed-on: https://go-review.googlesource.com/52191
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-07-31 17:46:03 +00:00
Austin Clements
1a6d87d4bf [release-branch.go1.9] runtime: fall back to small mmaps if we fail to grow reservation
Right now, if it's possible to grow the arena reservation but
mheap.sysAlloc fails to get 256MB more of memory, it simply fails.
However, on 32-bit we have a fallback path that uses much smaller
mmaps that could take in this situation, but fail to.

This commit fixes mheap.sysAlloc to use a common failure path in case
it can't grow the reservation. On 32-bit, this path includes the
fallback.

Ideally, mheap.sysAlloc would attempt smaller reservation growths
first, but taking the fallback path is a simple change for Go 1.9.

Updates #21044 (fixes one of two issues).

Cherry-pick of CL 51713. Updates #21234.

Change-Id: I1e0035ffba986c3551479d5742809e43da5e7c73
Reviewed-on: https://go-review.googlesource.com/52190
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-07-31 17:45:59 +00:00
Austin Clements
623e2c4603 runtime: map bitmap and spans during heap initialization
We lazily map the bitmap and spans areas as the heap grows. However,
right now we're very slightly too lazy. Specifically, the following
can happen on 32-bit:

1. mallocinit fails to allocate any heap arena, so
   arena_used == arena_alloc == arena_end == bitmap.

2. There's less than 256MB between the end of the bitmap mapping and
   the next mapping.

3. On the first allocation, mheap.sysAlloc sees that there's not
   enough room in [arena_alloc, arena_end) because there's no room at
   all. It gets a 256MB mapping from somewhere *lower* in the address
   space than arena_used and sets arena_alloc and arena_end to this
   hole.

4. Since the new arena_alloc is lower than arena_used, mheap.sysAlloc
   doesn't bother to call mheap.setArenaUsed, so we still don't have a
   bitmap mapping or a spans array mapping.

5. mheap.grow, which called mheap.sysAlloc, attempts to fill in the
   spans array and crashes.

Fix this by mapping the metadata regions for the initial arena_used
when the heap is initialized, rather than trying to wait for an
allocation. This maintains the intended invariant that the structures
are always mapped for [arena_start, arena_used).

Fixes #21044.

Change-Id: I4422375a6e234b9f979d22135fc63ae3395946b0
Reviewed-on: https://go-review.googlesource.com/51714
Run-TryBot: Austin Clements <austin@google.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-07-31 16:52:36 +00:00
Austin Clements
780249eed4 runtime: fall back to small mmaps if we fail to grow reservation
Right now, if it's possible to grow the arena reservation but
mheap.sysAlloc fails to get 256MB more of memory, it simply fails.
However, on 32-bit we have a fallback path that uses much smaller
mmaps that could take in this situation, but fail to.

This commit fixes mheap.sysAlloc to use a common failure path in case
it can't grow the reservation. On 32-bit, this path includes the
fallback.

Ideally, mheap.sysAlloc would attempt smaller reservation growths
first, but taking the fallback path is a simple change for Go 1.9.

Updates #21044 (fixes one of two issues).

Change-Id: I1e0035ffba986c3551479d5742809e43da5e7c73
Reviewed-on: https://go-review.googlesource.com/51713
Run-TryBot: Austin Clements <austin@google.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2017-07-31 14:05:58 +00:00
Gustav Westling
31b2c4cc25 .github: add .md extension to SUPPORT file
This makes GitHub render the markdown file automatically
on their web UI.

SUPPORT.md is the recommended file name according to the GitHub
documentation:
https://help.github.com/articles/adding-support-resources-to-your-project/

Fixes #21223

Change-Id: I9f9b9daced9c29a16850e8c446656f353f50b1ae
Reviewed-on: https://go-review.googlesource.com/52013
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2017-07-30 21:46:28 +00:00
Ian Lance Taylor
ac29f30dbb plugin: mention that there are known bugs with plugins
Change-Id: I9e63661cac2bebc41d7aa3cd80e1920eec22b894
Reviewed-on: https://go-review.googlesource.com/51250
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: David Crawshaw <crawshaw@golang.org>
2017-07-28 00:29:08 +00:00
Brad Fitzpatrick
7320506bc5 [release-branch.go1.9] cmd/dist: skip moved GOROOT on Go's Windows builders when not sharding tests
Change-Id: I0bcae339624e7d61037d9ea0885b7bd07491bbb6
Reviewed-on: https://go-review.googlesource.com/51430
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
(cherry picked from commit 4833e920c1d7f6b23458e6ff3c73951fcf754219)
Reviewed-on: https://go-review.googlesource.com/51450
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2017-07-27 05:56:03 +00:00
Brad Fitzpatrick
45a4609c0a cmd/dist: skip moved GOROOT on Go's Windows builders when not sharding tests
Change-Id: I0bcae339624e7d61037d9ea0885b7bd07491bbb6
Reviewed-on: https://go-review.googlesource.com/51430
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-07-27 05:04:28 +00:00
Josh Bleecher Snyder
e157fac02d test: add README
Updates #21034

Change-Id: I951fb48ab3b9ed54d225c11879db8f09048a36a3
Reviewed-on: https://go-review.googlesource.com/50950
Reviewed-by: Rob Pike <r@golang.org>
2017-07-26 23:37:25 +00:00
Vladimir Stefanovic
835dfef939 runtime/pprof: prevent a deadlock that SIGPROF might create on mips{,le}
64bit atomics on mips/mipsle are implemented using spinlocks. If SIGPROF
is received while the program is in the critical section, it will try to
write the sample using the same spinlock, creating a deadloop.
Prevent it by creating a counter of SIGPROFs during atomic64 and
postpone writing the sample(s) until called from elsewhere, with
pc set to _LostSIGPROFDuringAtomic64.

Added a test case, per Cherry's suggestion. Works around #20146.

Change-Id: Icff504180bae4ee83d78b19c0d9d6a80097087f9
Reviewed-on: https://go-review.googlesource.com/42652
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
2017-07-26 13:29:59 +00:00
Jaana Burcu Dogan
df91b8044d doc: list editor options by name, not plugin name
So the users can recognize their option by their editor's name.

Fixes #20398.

Change-Id: Id314d4dbe26f40231a479b179620d7e66512b506
Reviewed-on: https://go-review.googlesource.com/51114
Reviewed-by: Chris Broadfoot <cbro@golang.org>
2017-07-25 20:31:25 +00:00
Zac Bergquist
3d9475c04b doc: cleanup editor page
Fix some UI issues introduced with CL50952:
- increase header colspan to account for additional column
- remove ':' character from footnotes

Change-Id: I56f59b8e4b2852612b3c6c7c0dfe99125dd8b57b
Reviewed-on: https://go-review.googlesource.com/51113
Reviewed-by: Jaana Burcu Dogan <jbd@google.com>
2017-07-25 18:32:59 +00:00
Zac Bergquist
b9661a14ea doc: add Atom to editor guide
Fixes #20569

Change-Id: I752a49ed50c1567f8db7112859ac073f37dd77dc
Reviewed-on: https://go-review.googlesource.com/50952
Reviewed-by: Jaana Burcu Dogan <jbd@google.com>
2017-07-25 17:20:27 +00:00
Chris Broadfoot
65c6c88a94 [release-branch.go1.9] go1.9rc1
Change-Id: I6251fc128990f9494a0b037cabb24ada5eabb6b5
Reviewed-on: https://go-review.googlesource.com/50951
Run-TryBot: Chris Broadfoot <cbro@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Chris Broadfoot <cbro@golang.org>
2017-07-24 19:35:04 +00:00
Ian Lance Taylor
fbc9b49790 [release-branch.go1.9] cmd/compile: consider exported flag in namedata
It is possible to have an unexported name with a nil package,
for an embedded field whose type is a pointer to an unexported type.
We must encode that fact in the type..namedata symbol name,
to avoid incorrectly merging an unexported name with an exported name.

Fixes #21120

Change-Id: I2e3879d77fa15c05ad92e0bf8e55f74082db5111
Reviewed-on: https://go-review.googlesource.com/50710
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Crawshaw <crawshaw@golang.org>
Reviewed-on: https://go-review.googlesource.com/50970
Reviewed-by: Chris Broadfoot <cbro@golang.org>
2017-07-24 18:12:06 +00:00
96 changed files with 1938 additions and 1737 deletions

1
VERSION Normal file
View File

@@ -0,0 +1 @@
go1.9.1

View File

@@ -34,6 +34,7 @@ We encourage all Go users to subscribe to
<p>A <a href="/doc/devel/release.html">summary</a> of the changes between Go releases. Notes for the major releases:</p>
<ul>
<li><a href="/doc/go1.9">Go 1.9</a> <small>(August 2017)</small></li>
<li><a href="/doc/go1.8">Go 1.8</a> <small>(February 2017)</small></li>
<li><a href="/doc/go1.7">Go 1.7</a> <small>(August 2016)</small></li>
<li><a href="/doc/go1.6">Go 1.6</a> <small>(February 2016)</small></li>

View File

@@ -20,7 +20,20 @@ For example, Go 1.8 is supported until Go 1.10 is released,
and Go 1.9 is supported until Go 1.11 is released.
We fix critical problems, including <a href="/security">critical security problems</a>,
in supported releases as needed by issuing minor revisions
(for example, Go 1.8.1, Go 1.8.2, and so on).
(for example, Go 1.9.1, Go 1.9.2, and so on).
</p>
<h2 id="go1.9">go1.9 (released 2017/08/24)</h2>
<p>
Go 1.9 is a major release of Go.
Read the <a href="/doc/go1.9">Go 1.9 Release Notes</a> for more information.
</p>
<p>
go1.9.1 (released 2017/10/04) includes two security fixes.
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.9.1">Go
1.9.1 milestone</a> on our issue tracker for details.
</p>
<h2 id="go1.8">go1.8 (released 2017/02/16)</h2>
@@ -56,6 +69,13 @@ See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.8.3">Go
1.8.3 milestone</a> on our issue tracker for details.
</p>
<p>
go1.8.4 (released 2017/10/04) includes two security fixes.
It contains the same fixes as Go 1.9.1 and was released at the same time.
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.8.4">Go
1.8.4 milestone</a> on our issue tracker for details.
</p>
<h2 id="go1.7">go1.7 (released 2016/08/15)</h2>
<p>

View File

@@ -19,11 +19,12 @@ editing, navigation, testing, and debugging experience.
</p>
<ul>
<li><a href="https://github.com/fatih/vim-go">Vim Go</a>: a plugin for Vim to provide Go programming language support</li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=lukehoban.Go">Visual Studio Code Go</a>:
an extension for Visual Studio Code to provide support for the Go programming language</li>
<li><a href="https://github.com/fatih/vim-go">vim</a>: vim-go plugin provides Go programming language support</li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=lukehoban.Go">Visual Studio Code</a>:
Go extension provides support for the Go programming language</li>
<li><a href="https://www.jetbrains.com/go">Gogland</a>: Gogland is distributed either as a standalone IDE
or as a plugin for the IntelliJ Platform IDEs</li>
or as a plugin for the commercial IntelliJ Platform IDEs</li>
<li><a href="https://atom.io/packages/go-plus">Atom</a>: Go-Plus is an Atom package that provides enhanced Go support</li>
</ul>
<p>
@@ -41,133 +42,155 @@ The following feature matrix lists and compares the most significant features.
<table class="features-matrix">
<tr>
<th></th>
<th><img title="Vim Go" src="/doc/editors/vimgo.png"><br>Vim Go</th>
<th><img title="Visual Studio Code" src="/doc/editors/vscodego.png"><br>Visual Studio Code Go</th>
<th><img title="Vim Go" src="/doc/editors/vimgo.png"><br>vim</th>
<th><img title="Visual Studio Code" src="/doc/editors/vscodego.png"><br>Visual Studio Code</th>
<th><img title="Gogland" src="/doc/editors/gogland.png"><br>Gogland</th>
<th><img title="Go-Plus" src="/doc/editors/go-plus.png"><br>Atom</th>
</tr>
<tr>
<td class="feature-row" colspan="4">Editing features</td>
<td class="feature-row" colspan="5">Editing features</td>
</tr>
<tr>
<td>Build and run from the editor/IDE</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
</tr>
<tr>
<td>Autocompletion of identifers (variable, method, and function names)</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
</tr>
<tr>
<td>Autocompletion based on type</td>
<td class="no">No</td>
<td class="no">No</td>
<td class="yes">Yes</td>
</tr>
<tr>
<td>Type-aware autocompletion</td>
<td class="no">No</td>
<td class="no">No</td>
<td class="yes">Yes</td>
<td class="no">No</td>
</tr>
<tr>
<td>Rename identifiers</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
</tr>
<tr>
<td>Auto format, build, vet, and lint on save</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
<td class="yes">Yes<sup>1</sup></td>
<td class="yes">Yes</td>
</tr>
<tr>
<td>Auto insert import paths and remove unused on save</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
<td class="yes">Yes<sup>2</sup></td>
<td class="yes">Yes</td>
</tr>
<tr>
<td>Auto generate JSON, XML tags for struct fields</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
</tr>
<tr>
<td class="feature-row" colspan="4">Navigation features</td>
<td class="feature-row" colspan="5">Navigation features</td>
</tr>
<tr>
<td>Display documentation inline, or open godoc in browser</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
</tr>
<tr>
<td>Switch between <code>*.go</code> and <code>*_test.go</code> file</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
<td class="yes">No</td>
</tr>
<tr>
<td>Jump to definition and referees</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
</tr>
<tr>
<td>Look up for interface implementations</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
</tr>
<tr>
<td>Search for callers and callees</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
</tr>
<tr>
<td class="feature-row" colspan="4">Testing and debugging features</td>
<td class="feature-row" colspan="5">Testing and debugging features</td>
</tr>
<tr>
<td>Debugger support</td>
<td class="no">No</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
<td class="yes">Yes<sup>3</sup></td>
</tr>
<tr>
<td>Run a single test case, all tests from file, or all tests from a package</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
<td class="no">No</td>
</tr>
<tr>
<td>Auto generate tests for packages, files and identifiers</td>
<td class="no">No</td>
<td class="yes">Yes</td>
<td class="no">No</td>
<td class="no">No</td>
</tr>
<tr>
<td>Debug tests</td>
<td class="no">No</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
<td class="yes">Yes<sup>3</sup></td>
</tr>
<tr>
<td>Display test coverage</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
<td class="yes">Yes</td>
</tr>
<tr class="download">
<td></td>
<td><a href="https://github.com/fatih/vim-go">Install<a/></td>
<td><a href="https://marketplace.visualstudio.com/items?itemName=lukehoban.Go">Install<a/></td>
<td><a href="https://www.jetbrains.com/go">Install<a/></td>
<td><a href="https://atom.io/packages/go-plus">Install</a></td>
</tr>
</table>
<p>
<sup>1</sup>: Possible when enabled via Settings &gt; Go &gt; On Save, <code>go</code> <code>vet</code> and <code>golint</code> are available via plugins. Also runs tests on save if configured.
<sup>1</sup>Possible when enabled via Settings &gt; Go &gt; On Save, <code>go</code> <code>vet</code> and <code>golint</code> are available via plugins. Also runs tests on save if configured.
<br>
<sup>2</sup>: Additionally, user input can disambiguate when two or more options are available.
<sup>2</sup>Additionally, user input can disambiguate when two or more options are available.
<br>
<sup>3</sup>Available if the <a href="https://atom.io/packages/go-debug">go-debug</a> package is installed.
</p>
</div>
@@ -206,5 +229,3 @@ The following feature matrix lists and compares the most significant features.
font-weight: bold;
}
</style>
<!--TODO(jbd): Add the Atom comparison-->

BIN
doc/editors/go-plus.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -15,12 +15,7 @@ Do not send CLs removing the interior tags from such phrases.
ul li { margin: 0.5em 0; }
</style>
<h2 id="introduction">DRAFT RELEASE NOTES - Introduction to Go 1.9</h2>
<p><strong>
Go 1.9 is not yet released. These are work-in-progress
release notes. Go 1.9 is expected to be released in August 2017.
</strong></p>
<h2 id="introduction">Introduction to Go 1.9</h2>
<p>
The latest Go release, version 1.9, arrives six months
@@ -156,6 +151,21 @@ type T1 = T2
directories, write <code>./vendor/...</code>.
</p>
<h3 id="goroot">Moved GOROOT</h3>
<p><!-- CL 42533 -->
The <a href="/cmd/go/">go tool</a> will now use the path from which it
was invoked to attempt to locate the root of the Go install tree.
This means that if the entire Go installation is moved to a new
location, the go tool should continue to work as usual.
This may be overridden by setting <code>GOROOT</code> in the environment,
which should only be done in unusual circumstances.
Note that this does not affect the result of
the <a href="/pkg/runtime/#GOROOT">runtime.GOROOT</a> function, which
will continue to report the original installation location;
this may be fixed in later releases.
</p>
<h3 id="compiler">Compiler Toolchain</h3>
<p><!-- CL 37441 -->
@@ -473,6 +483,15 @@ version of gccgo.
populated.
</p>
<p><!-- CL 36696 -->
If any SAN extension, including with no DNS names, is present
in the certificate, then the Common Name from
<a href="/pkg/crypto/x509/#Certificate.Subject"><code>Subject</code></a> is ignored.
In previous releases, the code tested only whether DNS-name SANs were
present in a certificate.
</p>
</dl><!-- crypto/x509 -->
<dl id="database/sql"><dt><a href="/pkg/database/sql/">database/sql</a></dt>
@@ -721,6 +740,11 @@ version of gccgo.
and
<a href="/pkg/context/#WithValue"><code>context.WithValue</code></a> instead.
</li>
<li><!-- CL 35490 -->
<a href="/pkg/net/http/#LocalAddrContextKey"><code>LocalAddrContextKey</code></a> now contains
the connection's actual network address instead of the interface address used by the listener.
</li>
</ul>
<p>Client &amp; Transport changes:</p>
@@ -728,7 +752,7 @@ version of gccgo.
<li><!-- CL 35488 -->
The <a href="/pkg/net/http/#Transport"><code>Transport</code></a>
now supports making requests via SOCKS5 proxy when the URL returned by
<a href="/net/http/#Transport.Proxy"><code>Transport.Proxy</code></a>
<a href="/pkg/net/http/#Transport.Proxy"><code>Transport.Proxy</code></a>
has the scheme <code>socks5</code>.
</li>
</ul>
@@ -764,6 +788,16 @@ version of gccgo.
</dl><!-- net/http/httptest -->
<dl id="net/http/httputil"><dt><a href="/pkg/net/http/httputil/">net/http/httputil</a></dt>
<dd>
<p><!-- CL 43712 -->
The <a href="/pkg/net/http/httputil/#ReverseProxy"><code>ReverseProxy</code></a>
now proxies all HTTP/2 response trailers, even those not declared in the initial response
header. Such undeclared trailers are used by the gRPC protocol.
</p>
</dl><!-- net/http/httputil -->
<dl id="os"><dt><a href="/pkg/os/">os</a></dt>
<dd>
<p><!-- CL 36800 -->

View File

@@ -221,7 +221,7 @@ To build without <code>cgo</code>, set the environment variable
Change to the directory that will be its parent
and make sure the <code>go</code> directory does not exist.
Then clone the repository and check out the latest release tag
(<code class="versionTag">go1.8.1</code>, for example):</p>
(<code class="versionTag">go1.9</code>, for example):</p>
<pre>
$ git clone https://go.googlesource.com/go
@@ -409,7 +409,7 @@ New releases are announced on the
<a href="//groups.google.com/group/golang-announce">golang-announce</a>
mailing list.
Each announcement mentions the latest release tag, for instance,
<code class="versionTag">go1.8.1</code>.
<code class="versionTag">go1.9</code>.
</p>
<p>

View File

@@ -6,7 +6,9 @@
<div class="left">
<div id="learn">
{{if not $.GoogleCN}}
<a class="popout share">Pop-out</a>
{{end}}
<div class="rootHeading">Try Go</div>
<div class="input">
<textarea spellcheck="false" class="code">// You can edit this code!
@@ -26,10 +28,10 @@ Hello, 世界
</div>
<div class="buttons">
<a class="run" href="#" title="Run this code [shift-enter]">Run</a>
{{if $.Share}}
{{if not $.GoogleCN}}
<a class="share" href="#" title="Share this code">Share</a>
{{end}}
<a class="tour" href="//tour.golang.org/" title="Learn Go from your browser">Tour</a>
{{end}}
</div>
<div class="toys">
<select>
@@ -68,85 +70,91 @@ Linux, Mac OS X, Windows, and more.
<div style="clear: both"></div>
{{if not $.GoogleCN}}
<div class="left">
<div id="video">
<div class="rootHeading">Featured video</div>
<iframe width="415" height="241" src="//www.youtube.com/embed/ytEkHepK08c" frameborder="0" allowfullscreen></iframe>
</div>
<div id="video">
<div class="rootHeading">Featured video</div>
<iframe width="415" height="241" src="//www.youtube.com/embed/ytEkHepK08c" frameborder="0" allowfullscreen></iframe>
</div>
</div>
<div class="right">
<div id="blog">
<div class="rootHeading">Featured articles</div>
<div class="read"><a href="//blog.golang.org/">Read more</a></div>
</div>
<div id="blog">
<div class="rootHeading">Featured articles</div>
<div class="read"><a href="//blog.golang.org/">Read more</a></div>
</div>
</div>
{{end}}
<div style="clear: both;"></div>
<script type="text/javascript">
<script>
(function() {
'use strict';
function readableTime(t) {
var m = ["January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December"];
var p = t.substring(0, t.indexOf("T")).split("-");
var d = new Date(p[0], p[1]-1, p[2]);
return d.getDate() + " " + m[d.getMonth()] + " " + d.getFullYear();
}
window.initFuncs.push(function() {
// Set up playground if enabled.
if (window.playground) {
window.playground({
"codeEl": "#learn .code",
"outputEl": "#learn .output",
"runEl": "#learn .run",
"shareEl": "#learn .share",
"shareRedirect": "//play.golang.org/p/",
"toysEl": "#learn .toys select"
});
} else {
$('#learn').hide()
}
});
function feedLoaded(result) {
var blog = document.getElementById("blog");
var read = blog.getElementsByClassName("read")[0];
for (var i = 0; i < result.length && i < 2; i++) {
var entry = result[i];
var title = document.createElement("a");
title.className = "title";
title.href = entry.Link;
title.innerHTML = entry.Title;
blog.insertBefore(title, read);
var extract = document.createElement("div");
extract.className = "extract";
extract.innerHTML = entry.Summary;
blog.insertBefore(extract, read);
var when = document.createElement("div");
when.className = "when";
when.innerHTML = "Published " + readableTime(entry.Time);
blog.insertBefore(when, read);
}
}
{{if not $.GoogleCN}}
window.initFuncs.push(function() {
// Set up playground if enabled.
if (window.playground) {
window.playground({
"codeEl": "#learn .code",
"outputEl": "#learn .output",
"runEl": "#learn .run",
"shareEl": "#learn .share",
"shareRedirect": "//play.golang.org/p/",
"toysEl": "#learn .toys select"
});
} else {
$('#learn').hide()
function readableTime(t) {
var m = ["January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December"];
var p = t.substring(0, t.indexOf("T")).split("-");
var d = new Date(p[0], p[1]-1, p[2]);
return d.getDate() + " " + m[d.getMonth()] + " " + d.getFullYear();
}
// Load blog feed.
$('<script/>').attr('text', 'text/javascript')
.attr('src', '//blog.golang.org/.json?jsonp=feedLoaded')
.appendTo('body');
window.feedLoaded = function(result) {
var blog = document.getElementById("blog");
var read = blog.getElementsByClassName("read")[0];
for (var i = 0; i < result.length && i < 2; i++) {
var entry = result[i];
var title = document.createElement("a");
title.className = "title";
title.href = entry.Link;
title.innerHTML = entry.Title;
blog.insertBefore(title, read);
var extract = document.createElement("div");
extract.className = "extract";
extract.innerHTML = entry.Summary;
blog.insertBefore(extract, read);
var when = document.createElement("div");
when.className = "when";
when.innerHTML = "Published " + readableTime(entry.Time);
blog.insertBefore(when, read);
}
}
// Set the video at random.
var videos = [
{h: 241, s: "//www.youtube.com/embed/ytEkHepK08c"}, // Tour of Go
{h: 241, s: "//www.youtube.com/embed/f6kdp27TYZs"}, // Concurrency Patterns
{h: 233, s: "//player.vimeo.com/video/69237265"} // Simple environment
];
var v = videos[Math.floor(Math.random()*videos.length)];
$('#video iframe').attr('height', v.h).attr('src', v.s);
});
window.initFuncs.push(function() {
// Load blog feed.
$('<script/>').attr('text', 'text/javascript')
.attr('src', '//blog.golang.org/.json?jsonp=feedLoaded')
.appendTo('body');
// Set the video at random.
var videos = [
{h: 241, s: "//www.youtube.com/embed/ytEkHepK08c"}, // Tour of Go
{h: 241, s: "//www.youtube.com/embed/f6kdp27TYZs"}, // Concurrency Patterns
{h: 233, s: "//player.vimeo.com/video/69237265"} // Simple environment
];
var v = videos[Math.floor(Math.random()*videos.length)];
$('#video iframe').attr('height', v.h).attr('src', v.s);
});
{{end}}
})();
</script>

View File

@@ -343,6 +343,14 @@ var ptrTests = []ptrTest{
body: `var b C.char; p := &b; C.f((*C.u)(unsafe.Pointer(&p)))`,
fail: false,
},
{
// Issue #21306.
name: "preempt-during-call",
c: `void f() {}`,
imports: []string{"runtime", "sync"},
body: `var wg sync.WaitGroup; wg.Add(100); for i := 0; i < 100; i++ { go func(i int) { for j := 0; j < 100; j++ { C.f(); runtime.GOMAXPROCS(i) }; wg.Done() }(i) }; wg.Wait()`,
fail: false,
},
}
func main() {

View File

@@ -156,15 +156,18 @@ if test "$tsan" = "yes"; then
if ! $CC -fsanitize=thread ${TMPDIR}/testsanitizers$$.c -o ${TMPDIR}/testsanitizers$$ &> ${TMPDIR}/testsanitizers$$.err; then
ok=no
fi
if grep "unrecognized" ${TMPDIR}/testsanitizers$$.err >& /dev/null; then
if grep "unrecognized" ${TMPDIR}/testsanitizers$$.err >& /dev/null; then
echo "skipping tsan tests: -fsanitize=thread not supported"
tsan=no
elif test "$ok" != "yes"; then
cat ${TMPDIR}/testsanitizers$$.err
echo "skipping tsan tests: -fsanitizer=thread build failed"
tsan=no
fi
rm -f ${TMPDIR}/testsanitizers$$*
elif test "$ok" != "yes"; then
cat ${TMPDIR}/testsanitizers$$.err
echo "skipping tsan tests: -fsanitizer=thread build failed"
tsan=no
elif ! ${TMPDIR}/testsanitizers$$ 2>&1; then
echo "skipping tsan tests: running tsan program failed"
tsan=no
fi
rm -f ${TMPDIR}/testsanitizers$$*
fi
# Run a TSAN test.
@@ -196,8 +199,10 @@ if test "$tsan" = "yes"; then
# These tests are only reliable using clang or GCC version 7 or later.
# Otherwise runtime/cgo/libcgo.h can't tell whether TSAN is in use.
ok=false
clang=false
if ${CC} --version | grep clang >/dev/null 2>&1; then
ok=true
clang=true
else
ver=$($CC -dumpversion)
major=$(echo $ver | sed -e 's/\([0-9]*\).*/\1/')
@@ -213,9 +218,13 @@ if test "$tsan" = "yes"; then
testtsan tsan5.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
testtsan tsan6.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
testtsan tsan7.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
testtsan tsan10.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
testtsan tsan11.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
testtsan tsan12.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
# The remaining tests reportedly hang when built with GCC; issue #21196.
if test "$clang" = "true"; then
testtsan tsan10.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
testtsan tsan11.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
testtsan tsan12.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
fi
testtsanshared
fi

View File

@@ -571,16 +571,9 @@ var knownFormats = map[string]string{
"*cmd/compile/internal/ssa.Block %s": "",
"*cmd/compile/internal/ssa.Block %v": "",
"*cmd/compile/internal/ssa.Func %s": "",
"*cmd/compile/internal/ssa.Func %v": "",
"*cmd/compile/internal/ssa.FuncDebug %v": "",
"*cmd/compile/internal/ssa.LocalSlot %+v": "",
"*cmd/compile/internal/ssa.LocalSlot %v": "",
"*cmd/compile/internal/ssa.Register %v": "",
"*cmd/compile/internal/ssa.SparseTreeNode %v": "",
"*cmd/compile/internal/ssa.Value %s": "",
"*cmd/compile/internal/ssa.Value %v": "",
"*cmd/compile/internal/ssa.VarLoc %+v": "",
"*cmd/compile/internal/ssa.VarLoc %v": "",
"*cmd/compile/internal/ssa.sparseTreeMapEntry %v": "",
"*cmd/compile/internal/types.Field %p": "",
"*cmd/compile/internal/types.Field %v": "",
@@ -599,7 +592,6 @@ var knownFormats = map[string]string{
"*cmd/compile/internal/types.Type %p": "",
"*cmd/compile/internal/types.Type %s": "",
"*cmd/compile/internal/types.Type %v": "",
"*cmd/internal/dwarf.Location %#v": "",
"*cmd/internal/obj.Addr %v": "",
"*cmd/internal/obj.LSym %v": "",
"*cmd/internal/obj.Prog %s": "",
@@ -608,21 +600,17 @@ var knownFormats = map[string]string{
"[16]byte %x": "",
"[]*cmd/compile/internal/gc.Node %v": "",
"[]*cmd/compile/internal/gc.Sig %#v": "",
"[]*cmd/compile/internal/ssa.Block %+v": "",
"[]*cmd/compile/internal/ssa.Value %v": "",
"[][]cmd/compile/internal/ssa.SlotID %v": "",
"[]byte %s": "",
"[]byte %x": "",
"[]cmd/compile/internal/ssa.Edge %v": "",
"[]cmd/compile/internal/ssa.ID %v": "",
"[]cmd/compile/internal/ssa.VarLocList %v": "",
"[]string %v": "",
"bool %v": "",
"byte %08b": "",
"byte %c": "",
"cmd/compile/internal/arm.shift %d": "",
"cmd/compile/internal/gc.Class %d": "",
"cmd/compile/internal/gc.Class %v": "",
"cmd/compile/internal/gc.Ctype %d": "",
"cmd/compile/internal/gc.Ctype %v": "",
"cmd/compile/internal/gc.Level %d": "",
@@ -642,13 +630,11 @@ var knownFormats = map[string]string{
"cmd/compile/internal/ssa.Edge %v": "",
"cmd/compile/internal/ssa.GCNode %v": "",
"cmd/compile/internal/ssa.ID %d": "",
"cmd/compile/internal/ssa.ID %v": "",
"cmd/compile/internal/ssa.LocalSlot %v": "",
"cmd/compile/internal/ssa.Location %v": "",
"cmd/compile/internal/ssa.Op %s": "",
"cmd/compile/internal/ssa.Op %v": "",
"cmd/compile/internal/ssa.ValAndOff %s": "",
"cmd/compile/internal/ssa.VarLocList %v": "",
"cmd/compile/internal/ssa.rbrank %d": "",
"cmd/compile/internal/ssa.regMask %d": "",
"cmd/compile/internal/ssa.register %d": "",
@@ -662,7 +648,6 @@ var knownFormats = map[string]string{
"cmd/compile/internal/types.EType %d": "",
"cmd/compile/internal/types.EType %s": "",
"cmd/compile/internal/types.EType %v": "",
"cmd/internal/dwarf.Location %#v": "",
"cmd/internal/src.Pos %s": "",
"cmd/internal/src.Pos %v": "",
"error %v": "",

View File

@@ -464,6 +464,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
case ssa.OpARMMOVWaddr:
p := s.Prog(arm.AMOVW)
p.From.Type = obj.TYPE_ADDR
p.From.Reg = v.Args[0].Reg()
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
@@ -485,7 +486,6 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
case nil:
// No sym, just MOVW $off(SP), R
wantreg = "SP"
p.From.Reg = arm.REGSP
p.From.Offset = v.AuxInt
}
if reg := v.Args[0].RegName(); reg != wantreg {

View File

@@ -260,6 +260,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
case ssa.OpARM64MOVDaddr:
p := s.Prog(arm64.AMOVD)
p.From.Type = obj.TYPE_ADDR
p.From.Reg = v.Args[0].Reg()
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
@@ -281,7 +282,6 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
case nil:
// No sym, just MOVD $off(SP), R
wantreg = "SP"
p.From.Reg = arm64.REGSP
p.From.Offset = v.AuxInt
}
if reg := v.Args[0].RegName(); reg != wantreg {

View File

@@ -898,6 +898,17 @@ var linuxAMD64Tests = []*asmTest{
}`,
[]string{"\tCMPL\t[A-Z]"},
},
{
// make sure assembly output has matching offset and base register.
`
func f72(a, b int) int {
var x [16]byte // use some frame
_ = x
return b
}
`,
[]string{"b\\+40\\(SP\\)"},
},
}
var linux386Tests = []*asmTest{
@@ -1302,6 +1313,17 @@ var linuxARMTests = []*asmTest{
`,
[]string{"\tCLZ\t"},
},
{
// make sure assembly output has matching offset and base register.
`
func f13(a, b int) int {
var x [16]byte // use some frame
_ = x
return b
}
`,
[]string{"b\\+4\\(FP\\)"},
},
}
var linuxARM64Tests = []*asmTest{
@@ -1473,7 +1495,7 @@ var linuxARM64Tests = []*asmTest{
return
}
`,
[]string{"\tMOVD\t\"\"\\.a\\+[0-9]+\\(RSP\\), R[0-9]+", "\tMOVD\tR[0-9]+, \"\"\\.b\\+[0-9]+\\(RSP\\)"},
[]string{"\tMOVD\t\"\"\\.a\\+[0-9]+\\(FP\\), R[0-9]+", "\tMOVD\tR[0-9]+, \"\"\\.b\\+[0-9]+\\(FP\\)"},
},
}

View File

@@ -293,4 +293,8 @@ var (
typedmemmove,
typedmemclr,
Udiv *obj.LSym
// GO386=387
ControlWord64trunc,
ControlWord32 *obj.LSym
)

View File

@@ -44,7 +44,6 @@ var (
Debug_vlog bool
Debug_wb int
Debug_pctab string
Debug_locationlist int
)
// Debug arguments.
@@ -70,7 +69,6 @@ var debugtab = []struct {
{"wb", "print information about write barriers", &Debug_wb},
{"export", "print export data", &Debug_export},
{"pctab", "print named pc-value table", &Debug_pctab},
{"locationlists", "print information about DWARF location list creation", &Debug_locationlist},
}
const debugHelpHeader = `usage: -d arg[,arg]* and arg is <key>[=<value>]
@@ -194,7 +192,6 @@ func Main(archInit func(*Arch)) {
flag.BoolVar(&pure_go, "complete", false, "compiling complete package (no C or assembly)")
flag.StringVar(&debugstr, "d", "", "print debug information about items in `list`; try -d help")
flag.BoolVar(&flagDWARF, "dwarf", true, "generate DWARF symbols")
flag.BoolVar(&Ctxt.Flag_locationlists, "dwarflocationlists", false, "add location lists to DWARF in optimized mode")
objabi.Flagcount("e", "no limit on number of errors reported", &Debug['e'])
objabi.Flagcount("f", "debug stack frames", &Debug['f'])
objabi.Flagcount("h", "halt on error", &Debug['h'])
@@ -301,9 +298,6 @@ func Main(archInit func(*Arch)) {
if nBackendWorkers > 1 && !concurrentBackendAllowed() {
log.Fatalf("cannot use concurrent backend compilation with provided flags; invoked as %v", os.Args)
}
if Ctxt.Flag_locationlists && len(Ctxt.Arch.DWARFRegisters) == 0 {
log.Fatalf("location lists requested but register mapping not available on %v", Ctxt.Arch.Name)
}
// parse -d argument
if debugstr != "" {
@@ -389,7 +383,7 @@ func Main(archInit func(*Arch)) {
Debug['l'] = 1 - Debug['l']
}
trackScopes = flagDWARF && ((Debug['l'] == 0 && Debug['N'] != 0) || Ctxt.Flag_locationlists)
trackScopes = flagDWARF && Debug['l'] == 0 && Debug['N'] != 0
Widthptr = thearch.LinkArch.PtrSize
Widthreg = thearch.LinkArch.RegSize

View File

@@ -13,7 +13,6 @@ import (
"cmd/internal/src"
"cmd/internal/sys"
"fmt"
"math"
"math/rand"
"sort"
"sync"
@@ -304,77 +303,29 @@ func compileFunctions() {
func debuginfo(fnsym *obj.LSym, curfn interface{}) []dwarf.Scope {
fn := curfn.(*Node)
debugInfo := fn.Func.DebugInfo
fn.Func.DebugInfo = nil
if expect := fn.Func.Nname.Sym.Linksym(); fnsym != expect {
Fatalf("unexpected fnsym: %v != %v", fnsym, expect)
}
var automDecls []*Node
// Populate Automs for fn.
var dwarfVars []*dwarf.Var
var varScopes []ScopeID
for _, n := range fn.Func.Dcl {
if n.Op != ONAME { // might be OTYPE or OLITERAL
continue
}
var name obj.AddrName
var abbrev int
offs := n.Xoffset
switch n.Class() {
case PAUTO:
if !n.Name.Used() {
Fatalf("debuginfo unused node (AllocFrame should truncate fn.Func.Dcl)")
}
name = obj.NAME_AUTO
case PPARAM, PPARAMOUT:
name = obj.NAME_PARAM
default:
continue
}
automDecls = append(automDecls, n)
gotype := ngotype(n).Linksym()
fnsym.Func.Autom = append(fnsym.Func.Autom, &obj.Auto{
Asym: Ctxt.Lookup(n.Sym.Name),
Aoffset: int32(n.Xoffset),
Name: name,
Gotype: gotype,
})
}
var dwarfVars []*dwarf.Var
var decls []*Node
if Ctxt.Flag_locationlists && Ctxt.Flag_optimize {
decls, dwarfVars = createComplexVars(fn, debugInfo)
} else {
decls, dwarfVars = createSimpleVars(automDecls)
}
var varScopes []ScopeID
for _, decl := range decls {
var scope ScopeID
if !decl.Name.Captured() && !decl.Name.Byval() {
// n.Pos of captured variables is their first
// use in the closure but they should always
// be assigned to scope 0 instead.
// TODO(mdempsky): Verify this.
scope = findScope(fn.Func.Marks, decl.Pos)
}
varScopes = append(varScopes, scope)
}
return assembleScopes(fnsym, fn, dwarfVars, varScopes)
}
// createSimpleVars creates a DWARF entry for every variable declared in the
// function, claiming that they are permanently on the stack.
func createSimpleVars(automDecls []*Node) ([]*Node, []*dwarf.Var) {
var vars []*dwarf.Var
var decls []*Node
for _, n := range automDecls {
if n.IsAutoTmp() {
continue
}
var abbrev int
offs := n.Xoffset
switch n.Class() {
case PAUTO:
abbrev = dwarf.DW_ABRV_AUTO
if Ctxt.FixedFrameSize() == 0 {
offs -= int64(Widthptr)
@@ -384,288 +335,48 @@ func createSimpleVars(automDecls []*Node) ([]*Node, []*dwarf.Var) {
}
case PPARAM, PPARAMOUT:
name = obj.NAME_PARAM
abbrev = dwarf.DW_ABRV_PARAM
offs += Ctxt.FixedFrameSize()
default:
Fatalf("createSimpleVars unexpected type %v for node %v", n.Class(), n)
continue
}
typename := dwarf.InfoPrefix + typesymname(n.Type)
decls = append(decls, n)
vars = append(vars, &dwarf.Var{
Name: n.Sym.Name,
Abbrev: abbrev,
StackOffset: int32(offs),
Type: Ctxt.Lookup(typename),
gotype := ngotype(n).Linksym()
fnsym.Func.Autom = append(fnsym.Func.Autom, &obj.Auto{
Asym: Ctxt.Lookup(n.Sym.Name),
Aoffset: int32(n.Xoffset),
Name: name,
Gotype: gotype,
})
}
return decls, vars
}
type varPart struct {
varOffset int64
slot ssa.SlotID
locs ssa.VarLocList
}
func createComplexVars(fn *Node, debugInfo *ssa.FuncDebug) ([]*Node, []*dwarf.Var) {
for _, locList := range debugInfo.Variables {
for _, loc := range locList.Locations {
if loc.StartProg != nil {
loc.StartPC = loc.StartProg.Pc
}
if loc.EndProg != nil {
loc.EndPC = loc.EndProg.Pc
}
if Debug_locationlist == 0 {
loc.EndProg = nil
loc.StartProg = nil
}
}
}
// Group SSA variables by the user variable they were decomposed from.
varParts := map[*Node][]varPart{}
for slotID, locList := range debugInfo.Variables {
if len(locList.Locations) == 0 {
continue
}
slot := debugInfo.Slots[slotID]
for slot.SplitOf != nil {
slot = slot.SplitOf
}
n := slot.N.(*Node)
varParts[n] = append(varParts[n], varPart{varOffset(slot), ssa.SlotID(slotID), locList})
}
// Produce a DWARF variable entry for each user variable.
// Don't iterate over the map -- that's nondeterministic, and
// createComplexVar has side effects. Instead, go by slot.
var decls []*Node
var vars []*dwarf.Var
for _, slot := range debugInfo.Slots {
for slot.SplitOf != nil {
slot = slot.SplitOf
}
n := slot.N.(*Node)
parts := varParts[n]
if parts == nil {
if n.IsAutoTmp() {
continue
}
// Get the order the parts need to be in to represent the memory
// of the decomposed user variable.
sort.Sort(partsByVarOffset(parts))
typename := dwarf.InfoPrefix + gotype.Name[len("type."):]
dwarfVars = append(dwarfVars, &dwarf.Var{
Name: n.Sym.Name,
Abbrev: abbrev,
Offset: int32(offs),
Type: Ctxt.Lookup(typename),
})
if dvar := createComplexVar(debugInfo, n, parts); dvar != nil {
decls = append(decls, n)
vars = append(vars, dvar)
}
}
return decls, vars
}
// varOffset returns the offset of slot within the user variable it was
// decomposed from. This has nothing to do with its stack offset.
func varOffset(slot *ssa.LocalSlot) int64 {
offset := slot.Off
for ; slot.SplitOf != nil; slot = slot.SplitOf {
offset += slot.SplitOffset
}
return offset
}
type partsByVarOffset []varPart
func (a partsByVarOffset) Len() int { return len(a) }
func (a partsByVarOffset) Less(i, j int) bool { return a[i].varOffset < a[j].varOffset }
func (a partsByVarOffset) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
// createComplexVar builds a DWARF variable entry and location list representing n.
func createComplexVar(debugInfo *ssa.FuncDebug, n *Node, parts []varPart) *dwarf.Var {
slots := debugInfo.Slots
var offs int64 // base stack offset for this kind of variable
var abbrev int
switch n.Class() {
case PAUTO:
abbrev = dwarf.DW_ABRV_AUTO_LOCLIST
if Ctxt.FixedFrameSize() == 0 {
offs -= int64(Widthptr)
}
if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) {
offs -= int64(Widthptr)
var scope ScopeID
if !n.Name.Captured() && !n.Name.Byval() {
// n.Pos of captured variables is their first
// use in the closure but they should always
// be assigned to scope 0 instead.
// TODO(mdempsky): Verify this.
scope = findScope(fn.Func.Marks, n.Pos)
}
case PPARAM, PPARAMOUT:
abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
offs += Ctxt.FixedFrameSize()
default:
return nil
varScopes = append(varScopes, scope)
}
gotype := ngotype(n).Linksym()
typename := dwarf.InfoPrefix + gotype.Name[len("type."):]
// The stack offset is used as a sorting key, so for decomposed
// variables just give it the lowest one. It's not used otherwise.
stackOffset := debugInfo.Slots[parts[0].slot].N.(*Node).Xoffset + offs
dvar := &dwarf.Var{
Name: n.Sym.Name,
Abbrev: abbrev,
Type: Ctxt.Lookup(typename),
StackOffset: int32(stackOffset),
}
if Debug_locationlist != 0 {
Ctxt.Logf("Building location list for %+v. Parts:\n", n)
for _, part := range parts {
Ctxt.Logf("\t%v => %v\n", debugInfo.Slots[part.slot], part.locs)
}
}
// Given a variable that's been decomposed into multiple parts,
// its location list may need a new entry after the beginning or
// end of every location entry for each of its parts. For example:
//
// [variable] [pc range]
// string.ptr |----|-----| |----|
// string.len |------------| |--|
// ... needs a location list like:
// string |----|-----|-| |--|-|
//
// Note that location entries may or may not line up with each other,
// and some of the result will only have one or the other part.
//
// To build the resulting list:
// - keep a "current" pointer for each part
// - find the next transition point
// - advance the current pointer for each part up to that transition point
// - build the piece for the range between that transition point and the next
// - repeat
curLoc := make([]int, len(slots))
// findBoundaryAfter finds the next beginning or end of a piece after currentPC.
findBoundaryAfter := func(currentPC int64) int64 {
min := int64(math.MaxInt64)
for slot, part := range parts {
// For each part, find the first PC greater than current. Doesn't
// matter if it's a start or an end, since we're looking for any boundary.
// If it's the new winner, save it.
onePart:
for i := curLoc[slot]; i < len(part.locs.Locations); i++ {
for _, pc := range [2]int64{part.locs.Locations[i].StartPC, part.locs.Locations[i].EndPC} {
if pc > currentPC {
if pc < min {
min = pc
}
break onePart
}
}
}
}
return min
}
var start int64
end := findBoundaryAfter(0)
for {
// Advance to the next chunk.
start = end
end = findBoundaryAfter(start)
if end == math.MaxInt64 {
break
}
dloc := dwarf.Location{StartPC: start, EndPC: end}
if Debug_locationlist != 0 {
Ctxt.Logf("Processing range %x -> %x\n", start, end)
}
// Advance curLoc to the last location that starts before/at start.
// After this loop, if there's a location that covers [start, end), it will be current.
// Otherwise the current piece will be too early.
for _, part := range parts {
choice := -1
for i := curLoc[part.slot]; i < len(part.locs.Locations); i++ {
if part.locs.Locations[i].StartPC > start {
break //overshot
}
choice = i // best yet
}
if choice != -1 {
curLoc[part.slot] = choice
}
if Debug_locationlist != 0 {
Ctxt.Logf("\t %v => %v", slots[part.slot], curLoc[part.slot])
}
}
if Debug_locationlist != 0 {
Ctxt.Logf("\n")
}
// Assemble the location list entry for this chunk.
present := 0
for _, part := range parts {
dpiece := dwarf.Piece{
Length: slots[part.slot].Type.Size(),
}
locIdx := curLoc[part.slot]
if locIdx >= len(part.locs.Locations) ||
start >= part.locs.Locations[locIdx].EndPC ||
end <= part.locs.Locations[locIdx].StartPC {
if Debug_locationlist != 0 {
Ctxt.Logf("\t%v: missing", slots[part.slot])
}
dpiece.Missing = true
dloc.Pieces = append(dloc.Pieces, dpiece)
continue
}
present++
loc := part.locs.Locations[locIdx]
if Debug_locationlist != 0 {
Ctxt.Logf("\t%v: %v", slots[part.slot], loc)
}
if loc.OnStack {
dpiece.OnStack = true
dpiece.StackOffset = int32(offs + slots[part.slot].Off + slots[part.slot].N.(*Node).Xoffset)
} else {
for reg := 0; reg < len(debugInfo.Registers); reg++ {
if loc.Registers&(1<<uint8(reg)) != 0 {
dpiece.RegNum = Ctxt.Arch.DWARFRegisters[debugInfo.Registers[reg].ObjNum()]
}
}
}
dloc.Pieces = append(dloc.Pieces, dpiece)
}
if present == 0 {
if Debug_locationlist != 0 {
Ctxt.Logf(" -> totally missing\n")
}
continue
}
// Extend the previous entry if possible.
if len(dvar.LocationList) > 0 {
prev := &dvar.LocationList[len(dvar.LocationList)-1]
if prev.EndPC == dloc.StartPC && len(prev.Pieces) == len(dloc.Pieces) {
equal := true
for i := range prev.Pieces {
if prev.Pieces[i] != dloc.Pieces[i] {
equal = false
}
}
if equal {
prev.EndPC = end
if Debug_locationlist != 0 {
Ctxt.Logf("-> merged with previous, now %#v\n", prev)
}
continue
}
}
}
dvar.LocationList = append(dvar.LocationList, dloc)
if Debug_locationlist != 0 {
Ctxt.Logf("-> added: %#v\n", dloc)
}
}
return dvar
return assembleScopes(fnsym, fn, dwarfVars, varScopes)
}
// fieldtrack adds R_USEFIELD relocations to fnsym to record any

View File

@@ -168,7 +168,7 @@ func (v varsByScopeAndOffset) Less(i, j int) bool {
if v.scopes[i] != v.scopes[j] {
return v.scopes[i] < v.scopes[j]
}
return v.vars[i].StackOffset < v.vars[j].StackOffset
return v.vars[i].Offset < v.vars[j].Offset
}
func (v varsByScopeAndOffset) Swap(i, j int) {

View File

@@ -22,7 +22,7 @@ func TestSizeof(t *testing.T) {
_32bit uintptr // size on 32bit platforms
_64bit uintptr // size on 64bit platforms
}{
{Func{}, 128, 224},
{Func{}, 124, 216},
{Name{}, 36, 56},
{Param{}, 28, 56},
{Node{}, 76, 128},

View File

@@ -92,6 +92,10 @@ func initssaconfig() {
typedmemmove = Sysfunc("typedmemmove")
typedmemclr = Sysfunc("typedmemclr")
Udiv = Sysfunc("udiv")
// GO386=387 runtime functions
ControlWord64trunc = Sysfunc("controlWord64trunc")
ControlWord32 = Sysfunc("controlWord32")
}
// buildssa builds an SSA function for fn.
@@ -4382,15 +4386,14 @@ func genssa(f *ssa.Func, pp *Progs) {
// Remember where each block starts.
s.bstart = make([]*obj.Prog, f.NumBlocks())
s.pp = pp
var progToValue map[*obj.Prog]*ssa.Value
var progToBlock map[*obj.Prog]*ssa.Block
var valueToProg []*obj.Prog
var valueProgs map[*obj.Prog]*ssa.Value
var blockProgs map[*obj.Prog]*ssa.Block
var logProgs = e.log
if logProgs {
progToValue = make(map[*obj.Prog]*ssa.Value, f.NumValues())
progToBlock = make(map[*obj.Prog]*ssa.Block, f.NumBlocks())
valueProgs = make(map[*obj.Prog]*ssa.Value, f.NumValues())
blockProgs = make(map[*obj.Prog]*ssa.Block, f.NumBlocks())
f.Logf("genssa %s\n", f.Name)
progToBlock[s.pp.next] = f.Blocks[0]
blockProgs[s.pp.next] = f.Blocks[0]
}
if thearch.Use387 {
@@ -4399,11 +4402,6 @@ func genssa(f *ssa.Func, pp *Progs) {
s.ScratchFpMem = e.scratchFpMem
logLocationLists := Debug_locationlist != 0
if Ctxt.Flag_locationlists {
e.curfn.Func.DebugInfo = ssa.BuildFuncDebug(f, logLocationLists)
valueToProg = make([]*obj.Prog, f.NumValues())
}
// Emit basic blocks
for i, b := range f.Blocks {
s.bstart[b.ID] = s.pp.next
@@ -4444,19 +4442,15 @@ func genssa(f *ssa.Func, pp *Progs) {
}
case ssa.OpPhi:
CheckLoweredPhi(v)
case ssa.OpRegKill:
// nothing to do
default:
// let the backend handle it
thearch.SSAGenValue(&s, v)
}
if Ctxt.Flag_locationlists {
valueToProg[v.ID] = x
}
if logProgs {
for ; x != s.pp.next; x = x.Link {
progToValue[x] = v
valueProgs[x] = v
}
}
}
@@ -4474,23 +4468,7 @@ func genssa(f *ssa.Func, pp *Progs) {
thearch.SSAGenBlock(&s, b, next)
if logProgs {
for ; x != s.pp.next; x = x.Link {
progToBlock[x] = b
}
}
}
if Ctxt.Flag_locationlists {
for _, locList := range e.curfn.Func.DebugInfo.Variables {
for _, loc := range locList.Locations {
loc.StartProg = valueToProg[loc.Start.ID]
if loc.End == nil {
Fatalf("empty loc %v compiling %v", loc, f.Name)
}
loc.EndProg = valueToProg[loc.End.ID]
if !logLocationLists {
loc.Start = nil
loc.End = nil
}
blockProgs[x] = b
}
}
}
@@ -4503,9 +4481,9 @@ func genssa(f *ssa.Func, pp *Progs) {
if logProgs {
for p := pp.Text; p != nil; p = p.Link {
var s string
if v, ok := progToValue[p]; ok {
if v, ok := valueProgs[p]; ok {
s = v.String()
} else if b, ok := progToBlock[p]; ok {
} else if b, ok := blockProgs[p]; ok {
s = b.String()
} else {
s = " " // most value and branch strings are 2-3 characters long
@@ -4523,9 +4501,9 @@ func genssa(f *ssa.Func, pp *Progs) {
buf.WriteString("<dl class=\"ssa-gen\">")
for p := pp.Text; p != nil; p = p.Link {
buf.WriteString("<dt class=\"ssa-prog-src\">")
if v, ok := progToValue[p]; ok {
if v, ok := valueProgs[p]; ok {
buf.WriteString(v.HTML())
} else if b, ok := progToBlock[p]; ok {
} else if b, ok := blockProgs[p]; ok {
buf.WriteString(b.HTML())
}
buf.WriteString("</dt>")
@@ -4902,9 +4880,9 @@ func (e *ssafn) SplitString(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
lenType := types.Types[TINT]
if n.Class() == PAUTO && !n.Addrtaken() {
// Split this string up into two separate variables.
p := e.splitSlot(&name, ".ptr", 0, ptrType)
l := e.splitSlot(&name, ".len", ptrType.Size(), lenType)
return p, l
p := e.namedAuto(n.Sym.Name+".ptr", ptrType, n.Pos)
l := e.namedAuto(n.Sym.Name+".len", lenType, n.Pos)
return ssa.LocalSlot{N: p, Type: ptrType, Off: 0}, ssa.LocalSlot{N: l, Type: lenType, Off: 0}
}
// Return the two parts of the larger variable.
return ssa.LocalSlot{N: n, Type: ptrType, Off: name.Off}, ssa.LocalSlot{N: n, Type: lenType, Off: name.Off + int64(Widthptr)}
@@ -4919,9 +4897,9 @@ func (e *ssafn) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot
if n.Type.IsEmptyInterface() {
f = ".type"
}
c := e.splitSlot(&name, f, 0, t)
d := e.splitSlot(&name, ".data", t.Size(), t)
return c, d
c := e.namedAuto(n.Sym.Name+f, t, n.Pos)
d := e.namedAuto(n.Sym.Name+".data", t, n.Pos)
return ssa.LocalSlot{N: c, Type: t, Off: 0}, ssa.LocalSlot{N: d, Type: t, Off: 0}
}
// Return the two parts of the larger variable.
return ssa.LocalSlot{N: n, Type: t, Off: name.Off}, ssa.LocalSlot{N: n, Type: t, Off: name.Off + int64(Widthptr)}
@@ -4933,10 +4911,10 @@ func (e *ssafn) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ss
lenType := types.Types[TINT]
if n.Class() == PAUTO && !n.Addrtaken() {
// Split this slice up into three separate variables.
p := e.splitSlot(&name, ".ptr", 0, ptrType)
l := e.splitSlot(&name, ".len", ptrType.Size(), lenType)
c := e.splitSlot(&name, ".cap", ptrType.Size()+lenType.Size(), lenType)
return p, l, c
p := e.namedAuto(n.Sym.Name+".ptr", ptrType, n.Pos)
l := e.namedAuto(n.Sym.Name+".len", lenType, n.Pos)
c := e.namedAuto(n.Sym.Name+".cap", lenType, n.Pos)
return ssa.LocalSlot{N: p, Type: ptrType, Off: 0}, ssa.LocalSlot{N: l, Type: lenType, Off: 0}, ssa.LocalSlot{N: c, Type: lenType, Off: 0}
}
// Return the three parts of the larger variable.
return ssa.LocalSlot{N: n, Type: ptrType, Off: name.Off},
@@ -4955,9 +4933,9 @@ func (e *ssafn) SplitComplex(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot)
}
if n.Class() == PAUTO && !n.Addrtaken() {
// Split this complex up into two separate variables.
r := e.splitSlot(&name, ".real", 0, t)
i := e.splitSlot(&name, ".imag", t.Size(), t)
return r, i
c := e.namedAuto(n.Sym.Name+".real", t, n.Pos)
d := e.namedAuto(n.Sym.Name+".imag", t, n.Pos)
return ssa.LocalSlot{N: c, Type: t, Off: 0}, ssa.LocalSlot{N: d, Type: t, Off: 0}
}
// Return the two parts of the larger variable.
return ssa.LocalSlot{N: n, Type: t, Off: name.Off}, ssa.LocalSlot{N: n, Type: t, Off: name.Off + s}
@@ -4973,10 +4951,9 @@ func (e *ssafn) SplitInt64(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
}
if n.Class() == PAUTO && !n.Addrtaken() {
// Split this int64 up into two separate variables.
if thearch.LinkArch.ByteOrder == binary.BigEndian {
return e.splitSlot(&name, ".hi", 0, t), e.splitSlot(&name, ".lo", t.Size(), types.Types[TUINT32])
}
return e.splitSlot(&name, ".hi", t.Size(), t), e.splitSlot(&name, ".lo", 0, types.Types[TUINT32])
h := e.namedAuto(n.Sym.Name+".hi", t, n.Pos)
l := e.namedAuto(n.Sym.Name+".lo", types.Types[TUINT32], n.Pos)
return ssa.LocalSlot{N: h, Type: t, Off: 0}, ssa.LocalSlot{N: l, Type: types.Types[TUINT32], Off: 0}
}
// Return the two parts of the larger variable.
if thearch.LinkArch.ByteOrder == binary.BigEndian {
@@ -4989,15 +4966,12 @@ func (e *ssafn) SplitStruct(name ssa.LocalSlot, i int) ssa.LocalSlot {
n := name.N.(*Node)
st := name.Type
ft := st.FieldType(i)
var offset int64
for f := 0; f < i; f++ {
offset += st.FieldType(f).Size()
}
if n.Class() == PAUTO && !n.Addrtaken() {
// Note: the _ field may appear several times. But
// have no fear, identically-named but distinct Autos are
// ok, albeit maybe confusing for a debugger.
return e.splitSlot(&name, "."+st.FieldName(i), offset, ft)
x := e.namedAuto(n.Sym.Name+"."+st.FieldName(i), ft, n.Pos)
return ssa.LocalSlot{N: x, Type: ft, Off: 0}
}
return ssa.LocalSlot{N: n, Type: ft, Off: name.Off + st.FieldOff(i)}
}
@@ -5010,7 +4984,8 @@ func (e *ssafn) SplitArray(name ssa.LocalSlot) ssa.LocalSlot {
}
et := at.ElemType()
if n.Class() == PAUTO && !n.Addrtaken() {
return e.splitSlot(&name, "[0]", 0, et)
x := e.namedAuto(n.Sym.Name+"[0]", et, n.Pos)
return ssa.LocalSlot{N: x, Type: et, Off: 0}
}
return ssa.LocalSlot{N: n, Type: et, Off: name.Off}
}
@@ -5019,14 +4994,16 @@ func (e *ssafn) DerefItab(it *obj.LSym, offset int64) *obj.LSym {
return itabsym(it, offset)
}
// splitSlot returns a slot representing the data of parent starting at offset.
func (e *ssafn) splitSlot(parent *ssa.LocalSlot, suffix string, offset int64, t *types.Type) ssa.LocalSlot {
s := &types.Sym{Name: parent.N.(*Node).Sym.Name + suffix, Pkg: localpkg}
// namedAuto returns a new AUTO variable with the given name and type.
// These are exposed to the debugger.
func (e *ssafn) namedAuto(name string, typ *types.Type, pos src.XPos) ssa.GCNode {
t := typ
s := &types.Sym{Name: name, Pkg: localpkg}
n := new(Node)
n.Name = new(Name)
n.Op = ONAME
n.Pos = parent.N.(*Node).Pos
n.Pos = pos
n.Orig = n
s.Def = asTypesNode(n)
@@ -5039,7 +5016,7 @@ func (e *ssafn) splitSlot(parent *ssa.LocalSlot, suffix string, offset int64, t
n.Name.Curfn = e.curfn
e.curfn.Func.Dcl = append(e.curfn.Func.Dcl, n)
dowidth(t)
return ssa.LocalSlot{N: n, Type: t, Off: 0, SplitOf: parent, SplitOffset: offset}
return n
}
func (e *ssafn) CanSSA(t *types.Type) bool {

View File

@@ -7,7 +7,6 @@
package gc
import (
"cmd/compile/internal/ssa"
"cmd/compile/internal/syntax"
"cmd/compile/internal/types"
"cmd/internal/obj"
@@ -370,7 +369,6 @@ type Func struct {
Closgen int
Outerfunc *Node // outer function (for closure)
FieldTrack map[*types.Sym]struct{}
DebugInfo *ssa.FuncDebug
Ntype *Node // signature
Top int // top context (Ecall, Eproc, etc)
Closure *Node // OCLOSURE <-> ODCLFUNC

View File

@@ -35,6 +35,16 @@ func add_4294967296_uint64_ssa(a uint64) uint64 {
return 4294967296 + a
}
//go:noinline
func add_uint64_9223372036854775808_ssa(a uint64) uint64 {
return a + 9223372036854775808
}
//go:noinline
func add_9223372036854775808_uint64_ssa(a uint64) uint64 {
return 9223372036854775808 + a
}
//go:noinline
func add_uint64_18446744073709551615_ssa(a uint64) uint64 {
return a + 18446744073709551615
@@ -75,6 +85,16 @@ func sub_4294967296_uint64_ssa(a uint64) uint64 {
return 4294967296 - a
}
//go:noinline
func sub_uint64_9223372036854775808_ssa(a uint64) uint64 {
return a - 9223372036854775808
}
//go:noinline
func sub_9223372036854775808_uint64_ssa(a uint64) uint64 {
return 9223372036854775808 - a
}
//go:noinline
func sub_uint64_18446744073709551615_ssa(a uint64) uint64 {
return a - 18446744073709551615
@@ -110,6 +130,16 @@ func div_4294967296_uint64_ssa(a uint64) uint64 {
return 4294967296 / a
}
//go:noinline
func div_uint64_9223372036854775808_ssa(a uint64) uint64 {
return a / 9223372036854775808
}
//go:noinline
func div_9223372036854775808_uint64_ssa(a uint64) uint64 {
return 9223372036854775808 / a
}
//go:noinline
func div_uint64_18446744073709551615_ssa(a uint64) uint64 {
return a / 18446744073709551615
@@ -150,6 +180,16 @@ func mul_4294967296_uint64_ssa(a uint64) uint64 {
return 4294967296 * a
}
//go:noinline
func mul_uint64_9223372036854775808_ssa(a uint64) uint64 {
return a * 9223372036854775808
}
//go:noinline
func mul_9223372036854775808_uint64_ssa(a uint64) uint64 {
return 9223372036854775808 * a
}
//go:noinline
func mul_uint64_18446744073709551615_ssa(a uint64) uint64 {
return a * 18446744073709551615
@@ -190,6 +230,16 @@ func lsh_4294967296_uint64_ssa(a uint64) uint64 {
return 4294967296 << a
}
//go:noinline
func lsh_uint64_9223372036854775808_ssa(a uint64) uint64 {
return a << uint64(9223372036854775808)
}
//go:noinline
func lsh_9223372036854775808_uint64_ssa(a uint64) uint64 {
return 9223372036854775808 << a
}
//go:noinline
func lsh_uint64_18446744073709551615_ssa(a uint64) uint64 {
return a << uint64(18446744073709551615)
@@ -230,6 +280,16 @@ func rsh_4294967296_uint64_ssa(a uint64) uint64 {
return 4294967296 >> a
}
//go:noinline
func rsh_uint64_9223372036854775808_ssa(a uint64) uint64 {
return a >> uint64(9223372036854775808)
}
//go:noinline
func rsh_9223372036854775808_uint64_ssa(a uint64) uint64 {
return 9223372036854775808 >> a
}
//go:noinline
func rsh_uint64_18446744073709551615_ssa(a uint64) uint64 {
return a >> uint64(18446744073709551615)
@@ -265,6 +325,16 @@ func mod_4294967296_uint64_ssa(a uint64) uint64 {
return 4294967296 % a
}
//go:noinline
func mod_uint64_9223372036854775808_ssa(a uint64) uint64 {
return a % 9223372036854775808
}
//go:noinline
func mod_9223372036854775808_uint64_ssa(a uint64) uint64 {
return 9223372036854775808 % a
}
//go:noinline
func mod_uint64_18446744073709551615_ssa(a uint64) uint64 {
return a % 18446744073709551615
@@ -2319,6 +2389,16 @@ func main() {
failed = true
}
if got := add_0_uint64_ssa(9223372036854775808); got != 9223372036854775808 {
fmt.Printf("add_uint64 0%s9223372036854775808 = %d, wanted 9223372036854775808\n", `+`, got)
failed = true
}
if got := add_uint64_0_ssa(9223372036854775808); got != 9223372036854775808 {
fmt.Printf("add_uint64 9223372036854775808%s0 = %d, wanted 9223372036854775808\n", `+`, got)
failed = true
}
if got := add_0_uint64_ssa(18446744073709551615); got != 18446744073709551615 {
fmt.Printf("add_uint64 0%s18446744073709551615 = %d, wanted 18446744073709551615\n", `+`, got)
failed = true
@@ -2359,6 +2439,16 @@ func main() {
failed = true
}
if got := add_1_uint64_ssa(9223372036854775808); got != 9223372036854775809 {
fmt.Printf("add_uint64 1%s9223372036854775808 = %d, wanted 9223372036854775809\n", `+`, got)
failed = true
}
if got := add_uint64_1_ssa(9223372036854775808); got != 9223372036854775809 {
fmt.Printf("add_uint64 9223372036854775808%s1 = %d, wanted 9223372036854775809\n", `+`, got)
failed = true
}
if got := add_1_uint64_ssa(18446744073709551615); got != 0 {
fmt.Printf("add_uint64 1%s18446744073709551615 = %d, wanted 0\n", `+`, got)
failed = true
@@ -2399,6 +2489,16 @@ func main() {
failed = true
}
if got := add_4294967296_uint64_ssa(9223372036854775808); got != 9223372041149743104 {
fmt.Printf("add_uint64 4294967296%s9223372036854775808 = %d, wanted 9223372041149743104\n", `+`, got)
failed = true
}
if got := add_uint64_4294967296_ssa(9223372036854775808); got != 9223372041149743104 {
fmt.Printf("add_uint64 9223372036854775808%s4294967296 = %d, wanted 9223372041149743104\n", `+`, got)
failed = true
}
if got := add_4294967296_uint64_ssa(18446744073709551615); got != 4294967295 {
fmt.Printf("add_uint64 4294967296%s18446744073709551615 = %d, wanted 4294967295\n", `+`, got)
failed = true
@@ -2409,6 +2509,56 @@ func main() {
failed = true
}
if got := add_9223372036854775808_uint64_ssa(0); got != 9223372036854775808 {
fmt.Printf("add_uint64 9223372036854775808%s0 = %d, wanted 9223372036854775808\n", `+`, got)
failed = true
}
if got := add_uint64_9223372036854775808_ssa(0); got != 9223372036854775808 {
fmt.Printf("add_uint64 0%s9223372036854775808 = %d, wanted 9223372036854775808\n", `+`, got)
failed = true
}
if got := add_9223372036854775808_uint64_ssa(1); got != 9223372036854775809 {
fmt.Printf("add_uint64 9223372036854775808%s1 = %d, wanted 9223372036854775809\n", `+`, got)
failed = true
}
if got := add_uint64_9223372036854775808_ssa(1); got != 9223372036854775809 {
fmt.Printf("add_uint64 1%s9223372036854775808 = %d, wanted 9223372036854775809\n", `+`, got)
failed = true
}
if got := add_9223372036854775808_uint64_ssa(4294967296); got != 9223372041149743104 {
fmt.Printf("add_uint64 9223372036854775808%s4294967296 = %d, wanted 9223372041149743104\n", `+`, got)
failed = true
}
if got := add_uint64_9223372036854775808_ssa(4294967296); got != 9223372041149743104 {
fmt.Printf("add_uint64 4294967296%s9223372036854775808 = %d, wanted 9223372041149743104\n", `+`, got)
failed = true
}
if got := add_9223372036854775808_uint64_ssa(9223372036854775808); got != 0 {
fmt.Printf("add_uint64 9223372036854775808%s9223372036854775808 = %d, wanted 0\n", `+`, got)
failed = true
}
if got := add_uint64_9223372036854775808_ssa(9223372036854775808); got != 0 {
fmt.Printf("add_uint64 9223372036854775808%s9223372036854775808 = %d, wanted 0\n", `+`, got)
failed = true
}
if got := add_9223372036854775808_uint64_ssa(18446744073709551615); got != 9223372036854775807 {
fmt.Printf("add_uint64 9223372036854775808%s18446744073709551615 = %d, wanted 9223372036854775807\n", `+`, got)
failed = true
}
if got := add_uint64_9223372036854775808_ssa(18446744073709551615); got != 9223372036854775807 {
fmt.Printf("add_uint64 18446744073709551615%s9223372036854775808 = %d, wanted 9223372036854775807\n", `+`, got)
failed = true
}
if got := add_18446744073709551615_uint64_ssa(0); got != 18446744073709551615 {
fmt.Printf("add_uint64 18446744073709551615%s0 = %d, wanted 18446744073709551615\n", `+`, got)
failed = true
@@ -2439,6 +2589,16 @@ func main() {
failed = true
}
if got := add_18446744073709551615_uint64_ssa(9223372036854775808); got != 9223372036854775807 {
fmt.Printf("add_uint64 18446744073709551615%s9223372036854775808 = %d, wanted 9223372036854775807\n", `+`, got)
failed = true
}
if got := add_uint64_18446744073709551615_ssa(9223372036854775808); got != 9223372036854775807 {
fmt.Printf("add_uint64 9223372036854775808%s18446744073709551615 = %d, wanted 9223372036854775807\n", `+`, got)
failed = true
}
if got := add_18446744073709551615_uint64_ssa(18446744073709551615); got != 18446744073709551614 {
fmt.Printf("add_uint64 18446744073709551615%s18446744073709551615 = %d, wanted 18446744073709551614\n", `+`, got)
failed = true
@@ -2479,6 +2639,16 @@ func main() {
failed = true
}
if got := sub_0_uint64_ssa(9223372036854775808); got != 9223372036854775808 {
fmt.Printf("sub_uint64 0%s9223372036854775808 = %d, wanted 9223372036854775808\n", `-`, got)
failed = true
}
if got := sub_uint64_0_ssa(9223372036854775808); got != 9223372036854775808 {
fmt.Printf("sub_uint64 9223372036854775808%s0 = %d, wanted 9223372036854775808\n", `-`, got)
failed = true
}
if got := sub_0_uint64_ssa(18446744073709551615); got != 1 {
fmt.Printf("sub_uint64 0%s18446744073709551615 = %d, wanted 1\n", `-`, got)
failed = true
@@ -2519,6 +2689,16 @@ func main() {
failed = true
}
if got := sub_1_uint64_ssa(9223372036854775808); got != 9223372036854775809 {
fmt.Printf("sub_uint64 1%s9223372036854775808 = %d, wanted 9223372036854775809\n", `-`, got)
failed = true
}
if got := sub_uint64_1_ssa(9223372036854775808); got != 9223372036854775807 {
fmt.Printf("sub_uint64 9223372036854775808%s1 = %d, wanted 9223372036854775807\n", `-`, got)
failed = true
}
if got := sub_1_uint64_ssa(18446744073709551615); got != 2 {
fmt.Printf("sub_uint64 1%s18446744073709551615 = %d, wanted 2\n", `-`, got)
failed = true
@@ -2559,6 +2739,16 @@ func main() {
failed = true
}
if got := sub_4294967296_uint64_ssa(9223372036854775808); got != 9223372041149743104 {
fmt.Printf("sub_uint64 4294967296%s9223372036854775808 = %d, wanted 9223372041149743104\n", `-`, got)
failed = true
}
if got := sub_uint64_4294967296_ssa(9223372036854775808); got != 9223372032559808512 {
fmt.Printf("sub_uint64 9223372036854775808%s4294967296 = %d, wanted 9223372032559808512\n", `-`, got)
failed = true
}
if got := sub_4294967296_uint64_ssa(18446744073709551615); got != 4294967297 {
fmt.Printf("sub_uint64 4294967296%s18446744073709551615 = %d, wanted 4294967297\n", `-`, got)
failed = true
@@ -2569,6 +2759,56 @@ func main() {
failed = true
}
if got := sub_9223372036854775808_uint64_ssa(0); got != 9223372036854775808 {
fmt.Printf("sub_uint64 9223372036854775808%s0 = %d, wanted 9223372036854775808\n", `-`, got)
failed = true
}
if got := sub_uint64_9223372036854775808_ssa(0); got != 9223372036854775808 {
fmt.Printf("sub_uint64 0%s9223372036854775808 = %d, wanted 9223372036854775808\n", `-`, got)
failed = true
}
if got := sub_9223372036854775808_uint64_ssa(1); got != 9223372036854775807 {
fmt.Printf("sub_uint64 9223372036854775808%s1 = %d, wanted 9223372036854775807\n", `-`, got)
failed = true
}
if got := sub_uint64_9223372036854775808_ssa(1); got != 9223372036854775809 {
fmt.Printf("sub_uint64 1%s9223372036854775808 = %d, wanted 9223372036854775809\n", `-`, got)
failed = true
}
if got := sub_9223372036854775808_uint64_ssa(4294967296); got != 9223372032559808512 {
fmt.Printf("sub_uint64 9223372036854775808%s4294967296 = %d, wanted 9223372032559808512\n", `-`, got)
failed = true
}
if got := sub_uint64_9223372036854775808_ssa(4294967296); got != 9223372041149743104 {
fmt.Printf("sub_uint64 4294967296%s9223372036854775808 = %d, wanted 9223372041149743104\n", `-`, got)
failed = true
}
if got := sub_9223372036854775808_uint64_ssa(9223372036854775808); got != 0 {
fmt.Printf("sub_uint64 9223372036854775808%s9223372036854775808 = %d, wanted 0\n", `-`, got)
failed = true
}
if got := sub_uint64_9223372036854775808_ssa(9223372036854775808); got != 0 {
fmt.Printf("sub_uint64 9223372036854775808%s9223372036854775808 = %d, wanted 0\n", `-`, got)
failed = true
}
if got := sub_9223372036854775808_uint64_ssa(18446744073709551615); got != 9223372036854775809 {
fmt.Printf("sub_uint64 9223372036854775808%s18446744073709551615 = %d, wanted 9223372036854775809\n", `-`, got)
failed = true
}
if got := sub_uint64_9223372036854775808_ssa(18446744073709551615); got != 9223372036854775807 {
fmt.Printf("sub_uint64 18446744073709551615%s9223372036854775808 = %d, wanted 9223372036854775807\n", `-`, got)
failed = true
}
if got := sub_18446744073709551615_uint64_ssa(0); got != 18446744073709551615 {
fmt.Printf("sub_uint64 18446744073709551615%s0 = %d, wanted 18446744073709551615\n", `-`, got)
failed = true
@@ -2599,6 +2839,16 @@ func main() {
failed = true
}
if got := sub_18446744073709551615_uint64_ssa(9223372036854775808); got != 9223372036854775807 {
fmt.Printf("sub_uint64 18446744073709551615%s9223372036854775808 = %d, wanted 9223372036854775807\n", `-`, got)
failed = true
}
if got := sub_uint64_18446744073709551615_ssa(9223372036854775808); got != 9223372036854775809 {
fmt.Printf("sub_uint64 9223372036854775808%s18446744073709551615 = %d, wanted 9223372036854775809\n", `-`, got)
failed = true
}
if got := sub_18446744073709551615_uint64_ssa(18446744073709551615); got != 0 {
fmt.Printf("sub_uint64 18446744073709551615%s18446744073709551615 = %d, wanted 0\n", `-`, got)
failed = true
@@ -2619,6 +2869,11 @@ func main() {
failed = true
}
if got := div_0_uint64_ssa(9223372036854775808); got != 0 {
fmt.Printf("div_uint64 0%s9223372036854775808 = %d, wanted 0\n", `/`, got)
failed = true
}
if got := div_0_uint64_ssa(18446744073709551615); got != 0 {
fmt.Printf("div_uint64 0%s18446744073709551615 = %d, wanted 0\n", `/`, got)
failed = true
@@ -2649,6 +2904,16 @@ func main() {
failed = true
}
if got := div_1_uint64_ssa(9223372036854775808); got != 0 {
fmt.Printf("div_uint64 1%s9223372036854775808 = %d, wanted 0\n", `/`, got)
failed = true
}
if got := div_uint64_1_ssa(9223372036854775808); got != 9223372036854775808 {
fmt.Printf("div_uint64 9223372036854775808%s1 = %d, wanted 9223372036854775808\n", `/`, got)
failed = true
}
if got := div_1_uint64_ssa(18446744073709551615); got != 0 {
fmt.Printf("div_uint64 1%s18446744073709551615 = %d, wanted 0\n", `/`, got)
failed = true
@@ -2684,6 +2949,16 @@ func main() {
failed = true
}
if got := div_4294967296_uint64_ssa(9223372036854775808); got != 0 {
fmt.Printf("div_uint64 4294967296%s9223372036854775808 = %d, wanted 0\n", `/`, got)
failed = true
}
if got := div_uint64_4294967296_ssa(9223372036854775808); got != 2147483648 {
fmt.Printf("div_uint64 9223372036854775808%s4294967296 = %d, wanted 2147483648\n", `/`, got)
failed = true
}
if got := div_4294967296_uint64_ssa(18446744073709551615); got != 0 {
fmt.Printf("div_uint64 4294967296%s18446744073709551615 = %d, wanted 0\n", `/`, got)
failed = true
@@ -2694,6 +2969,51 @@ func main() {
failed = true
}
if got := div_uint64_9223372036854775808_ssa(0); got != 0 {
fmt.Printf("div_uint64 0%s9223372036854775808 = %d, wanted 0\n", `/`, got)
failed = true
}
if got := div_9223372036854775808_uint64_ssa(1); got != 9223372036854775808 {
fmt.Printf("div_uint64 9223372036854775808%s1 = %d, wanted 9223372036854775808\n", `/`, got)
failed = true
}
if got := div_uint64_9223372036854775808_ssa(1); got != 0 {
fmt.Printf("div_uint64 1%s9223372036854775808 = %d, wanted 0\n", `/`, got)
failed = true
}
if got := div_9223372036854775808_uint64_ssa(4294967296); got != 2147483648 {
fmt.Printf("div_uint64 9223372036854775808%s4294967296 = %d, wanted 2147483648\n", `/`, got)
failed = true
}
if got := div_uint64_9223372036854775808_ssa(4294967296); got != 0 {
fmt.Printf("div_uint64 4294967296%s9223372036854775808 = %d, wanted 0\n", `/`, got)
failed = true
}
if got := div_9223372036854775808_uint64_ssa(9223372036854775808); got != 1 {
fmt.Printf("div_uint64 9223372036854775808%s9223372036854775808 = %d, wanted 1\n", `/`, got)
failed = true
}
if got := div_uint64_9223372036854775808_ssa(9223372036854775808); got != 1 {
fmt.Printf("div_uint64 9223372036854775808%s9223372036854775808 = %d, wanted 1\n", `/`, got)
failed = true
}
if got := div_9223372036854775808_uint64_ssa(18446744073709551615); got != 0 {
fmt.Printf("div_uint64 9223372036854775808%s18446744073709551615 = %d, wanted 0\n", `/`, got)
failed = true
}
if got := div_uint64_9223372036854775808_ssa(18446744073709551615); got != 1 {
fmt.Printf("div_uint64 18446744073709551615%s9223372036854775808 = %d, wanted 1\n", `/`, got)
failed = true
}
if got := div_uint64_18446744073709551615_ssa(0); got != 0 {
fmt.Printf("div_uint64 0%s18446744073709551615 = %d, wanted 0\n", `/`, got)
failed = true
@@ -2719,6 +3039,16 @@ func main() {
failed = true
}
if got := div_18446744073709551615_uint64_ssa(9223372036854775808); got != 1 {
fmt.Printf("div_uint64 18446744073709551615%s9223372036854775808 = %d, wanted 1\n", `/`, got)
failed = true
}
if got := div_uint64_18446744073709551615_ssa(9223372036854775808); got != 0 {
fmt.Printf("div_uint64 9223372036854775808%s18446744073709551615 = %d, wanted 0\n", `/`, got)
failed = true
}
if got := div_18446744073709551615_uint64_ssa(18446744073709551615); got != 1 {
fmt.Printf("div_uint64 18446744073709551615%s18446744073709551615 = %d, wanted 1\n", `/`, got)
failed = true
@@ -2759,6 +3089,16 @@ func main() {
failed = true
}
if got := mul_0_uint64_ssa(9223372036854775808); got != 0 {
fmt.Printf("mul_uint64 0%s9223372036854775808 = %d, wanted 0\n", `*`, got)
failed = true
}
if got := mul_uint64_0_ssa(9223372036854775808); got != 0 {
fmt.Printf("mul_uint64 9223372036854775808%s0 = %d, wanted 0\n", `*`, got)
failed = true
}
if got := mul_0_uint64_ssa(18446744073709551615); got != 0 {
fmt.Printf("mul_uint64 0%s18446744073709551615 = %d, wanted 0\n", `*`, got)
failed = true
@@ -2799,6 +3139,16 @@ func main() {
failed = true
}
if got := mul_1_uint64_ssa(9223372036854775808); got != 9223372036854775808 {
fmt.Printf("mul_uint64 1%s9223372036854775808 = %d, wanted 9223372036854775808\n", `*`, got)
failed = true
}
if got := mul_uint64_1_ssa(9223372036854775808); got != 9223372036854775808 {
fmt.Printf("mul_uint64 9223372036854775808%s1 = %d, wanted 9223372036854775808\n", `*`, got)
failed = true
}
if got := mul_1_uint64_ssa(18446744073709551615); got != 18446744073709551615 {
fmt.Printf("mul_uint64 1%s18446744073709551615 = %d, wanted 18446744073709551615\n", `*`, got)
failed = true
@@ -2839,6 +3189,16 @@ func main() {
failed = true
}
if got := mul_4294967296_uint64_ssa(9223372036854775808); got != 0 {
fmt.Printf("mul_uint64 4294967296%s9223372036854775808 = %d, wanted 0\n", `*`, got)
failed = true
}
if got := mul_uint64_4294967296_ssa(9223372036854775808); got != 0 {
fmt.Printf("mul_uint64 9223372036854775808%s4294967296 = %d, wanted 0\n", `*`, got)
failed = true
}
if got := mul_4294967296_uint64_ssa(18446744073709551615); got != 18446744069414584320 {
fmt.Printf("mul_uint64 4294967296%s18446744073709551615 = %d, wanted 18446744069414584320\n", `*`, got)
failed = true
@@ -2849,6 +3209,56 @@ func main() {
failed = true
}
if got := mul_9223372036854775808_uint64_ssa(0); got != 0 {
fmt.Printf("mul_uint64 9223372036854775808%s0 = %d, wanted 0\n", `*`, got)
failed = true
}
if got := mul_uint64_9223372036854775808_ssa(0); got != 0 {
fmt.Printf("mul_uint64 0%s9223372036854775808 = %d, wanted 0\n", `*`, got)
failed = true
}
if got := mul_9223372036854775808_uint64_ssa(1); got != 9223372036854775808 {
fmt.Printf("mul_uint64 9223372036854775808%s1 = %d, wanted 9223372036854775808\n", `*`, got)
failed = true
}
if got := mul_uint64_9223372036854775808_ssa(1); got != 9223372036854775808 {
fmt.Printf("mul_uint64 1%s9223372036854775808 = %d, wanted 9223372036854775808\n", `*`, got)
failed = true
}
if got := mul_9223372036854775808_uint64_ssa(4294967296); got != 0 {
fmt.Printf("mul_uint64 9223372036854775808%s4294967296 = %d, wanted 0\n", `*`, got)
failed = true
}
if got := mul_uint64_9223372036854775808_ssa(4294967296); got != 0 {
fmt.Printf("mul_uint64 4294967296%s9223372036854775808 = %d, wanted 0\n", `*`, got)
failed = true
}
if got := mul_9223372036854775808_uint64_ssa(9223372036854775808); got != 0 {
fmt.Printf("mul_uint64 9223372036854775808%s9223372036854775808 = %d, wanted 0\n", `*`, got)
failed = true
}
if got := mul_uint64_9223372036854775808_ssa(9223372036854775808); got != 0 {
fmt.Printf("mul_uint64 9223372036854775808%s9223372036854775808 = %d, wanted 0\n", `*`, got)
failed = true
}
if got := mul_9223372036854775808_uint64_ssa(18446744073709551615); got != 9223372036854775808 {
fmt.Printf("mul_uint64 9223372036854775808%s18446744073709551615 = %d, wanted 9223372036854775808\n", `*`, got)
failed = true
}
if got := mul_uint64_9223372036854775808_ssa(18446744073709551615); got != 9223372036854775808 {
fmt.Printf("mul_uint64 18446744073709551615%s9223372036854775808 = %d, wanted 9223372036854775808\n", `*`, got)
failed = true
}
if got := mul_18446744073709551615_uint64_ssa(0); got != 0 {
fmt.Printf("mul_uint64 18446744073709551615%s0 = %d, wanted 0\n", `*`, got)
failed = true
@@ -2879,6 +3289,16 @@ func main() {
failed = true
}
if got := mul_18446744073709551615_uint64_ssa(9223372036854775808); got != 9223372036854775808 {
fmt.Printf("mul_uint64 18446744073709551615%s9223372036854775808 = %d, wanted 9223372036854775808\n", `*`, got)
failed = true
}
if got := mul_uint64_18446744073709551615_ssa(9223372036854775808); got != 9223372036854775808 {
fmt.Printf("mul_uint64 9223372036854775808%s18446744073709551615 = %d, wanted 9223372036854775808\n", `*`, got)
failed = true
}
if got := mul_18446744073709551615_uint64_ssa(18446744073709551615); got != 1 {
fmt.Printf("mul_uint64 18446744073709551615%s18446744073709551615 = %d, wanted 1\n", `*`, got)
failed = true
@@ -2919,6 +3339,16 @@ func main() {
failed = true
}
if got := lsh_0_uint64_ssa(9223372036854775808); got != 0 {
fmt.Printf("lsh_uint64 0%s9223372036854775808 = %d, wanted 0\n", `<<`, got)
failed = true
}
if got := lsh_uint64_0_ssa(9223372036854775808); got != 9223372036854775808 {
fmt.Printf("lsh_uint64 9223372036854775808%s0 = %d, wanted 9223372036854775808\n", `<<`, got)
failed = true
}
if got := lsh_0_uint64_ssa(18446744073709551615); got != 0 {
fmt.Printf("lsh_uint64 0%s18446744073709551615 = %d, wanted 0\n", `<<`, got)
failed = true
@@ -2959,6 +3389,16 @@ func main() {
failed = true
}
if got := lsh_1_uint64_ssa(9223372036854775808); got != 0 {
fmt.Printf("lsh_uint64 1%s9223372036854775808 = %d, wanted 0\n", `<<`, got)
failed = true
}
if got := lsh_uint64_1_ssa(9223372036854775808); got != 0 {
fmt.Printf("lsh_uint64 9223372036854775808%s1 = %d, wanted 0\n", `<<`, got)
failed = true
}
if got := lsh_1_uint64_ssa(18446744073709551615); got != 0 {
fmt.Printf("lsh_uint64 1%s18446744073709551615 = %d, wanted 0\n", `<<`, got)
failed = true
@@ -2999,6 +3439,16 @@ func main() {
failed = true
}
if got := lsh_4294967296_uint64_ssa(9223372036854775808); got != 0 {
fmt.Printf("lsh_uint64 4294967296%s9223372036854775808 = %d, wanted 0\n", `<<`, got)
failed = true
}
if got := lsh_uint64_4294967296_ssa(9223372036854775808); got != 0 {
fmt.Printf("lsh_uint64 9223372036854775808%s4294967296 = %d, wanted 0\n", `<<`, got)
failed = true
}
if got := lsh_4294967296_uint64_ssa(18446744073709551615); got != 0 {
fmt.Printf("lsh_uint64 4294967296%s18446744073709551615 = %d, wanted 0\n", `<<`, got)
failed = true
@@ -3009,6 +3459,56 @@ func main() {
failed = true
}
if got := lsh_9223372036854775808_uint64_ssa(0); got != 9223372036854775808 {
fmt.Printf("lsh_uint64 9223372036854775808%s0 = %d, wanted 9223372036854775808\n", `<<`, got)
failed = true
}
if got := lsh_uint64_9223372036854775808_ssa(0); got != 0 {
fmt.Printf("lsh_uint64 0%s9223372036854775808 = %d, wanted 0\n", `<<`, got)
failed = true
}
if got := lsh_9223372036854775808_uint64_ssa(1); got != 0 {
fmt.Printf("lsh_uint64 9223372036854775808%s1 = %d, wanted 0\n", `<<`, got)
failed = true
}
if got := lsh_uint64_9223372036854775808_ssa(1); got != 0 {
fmt.Printf("lsh_uint64 1%s9223372036854775808 = %d, wanted 0\n", `<<`, got)
failed = true
}
if got := lsh_9223372036854775808_uint64_ssa(4294967296); got != 0 {
fmt.Printf("lsh_uint64 9223372036854775808%s4294967296 = %d, wanted 0\n", `<<`, got)
failed = true
}
if got := lsh_uint64_9223372036854775808_ssa(4294967296); got != 0 {
fmt.Printf("lsh_uint64 4294967296%s9223372036854775808 = %d, wanted 0\n", `<<`, got)
failed = true
}
if got := lsh_9223372036854775808_uint64_ssa(9223372036854775808); got != 0 {
fmt.Printf("lsh_uint64 9223372036854775808%s9223372036854775808 = %d, wanted 0\n", `<<`, got)
failed = true
}
if got := lsh_uint64_9223372036854775808_ssa(9223372036854775808); got != 0 {
fmt.Printf("lsh_uint64 9223372036854775808%s9223372036854775808 = %d, wanted 0\n", `<<`, got)
failed = true
}
if got := lsh_9223372036854775808_uint64_ssa(18446744073709551615); got != 0 {
fmt.Printf("lsh_uint64 9223372036854775808%s18446744073709551615 = %d, wanted 0\n", `<<`, got)
failed = true
}
if got := lsh_uint64_9223372036854775808_ssa(18446744073709551615); got != 0 {
fmt.Printf("lsh_uint64 18446744073709551615%s9223372036854775808 = %d, wanted 0\n", `<<`, got)
failed = true
}
if got := lsh_18446744073709551615_uint64_ssa(0); got != 18446744073709551615 {
fmt.Printf("lsh_uint64 18446744073709551615%s0 = %d, wanted 18446744073709551615\n", `<<`, got)
failed = true
@@ -3039,6 +3539,16 @@ func main() {
failed = true
}
if got := lsh_18446744073709551615_uint64_ssa(9223372036854775808); got != 0 {
fmt.Printf("lsh_uint64 18446744073709551615%s9223372036854775808 = %d, wanted 0\n", `<<`, got)
failed = true
}
if got := lsh_uint64_18446744073709551615_ssa(9223372036854775808); got != 0 {
fmt.Printf("lsh_uint64 9223372036854775808%s18446744073709551615 = %d, wanted 0\n", `<<`, got)
failed = true
}
if got := lsh_18446744073709551615_uint64_ssa(18446744073709551615); got != 0 {
fmt.Printf("lsh_uint64 18446744073709551615%s18446744073709551615 = %d, wanted 0\n", `<<`, got)
failed = true
@@ -3079,6 +3589,16 @@ func main() {
failed = true
}
if got := rsh_0_uint64_ssa(9223372036854775808); got != 0 {
fmt.Printf("rsh_uint64 0%s9223372036854775808 = %d, wanted 0\n", `>>`, got)
failed = true
}
if got := rsh_uint64_0_ssa(9223372036854775808); got != 9223372036854775808 {
fmt.Printf("rsh_uint64 9223372036854775808%s0 = %d, wanted 9223372036854775808\n", `>>`, got)
failed = true
}
if got := rsh_0_uint64_ssa(18446744073709551615); got != 0 {
fmt.Printf("rsh_uint64 0%s18446744073709551615 = %d, wanted 0\n", `>>`, got)
failed = true
@@ -3119,6 +3639,16 @@ func main() {
failed = true
}
if got := rsh_1_uint64_ssa(9223372036854775808); got != 0 {
fmt.Printf("rsh_uint64 1%s9223372036854775808 = %d, wanted 0\n", `>>`, got)
failed = true
}
if got := rsh_uint64_1_ssa(9223372036854775808); got != 4611686018427387904 {
fmt.Printf("rsh_uint64 9223372036854775808%s1 = %d, wanted 4611686018427387904\n", `>>`, got)
failed = true
}
if got := rsh_1_uint64_ssa(18446744073709551615); got != 0 {
fmt.Printf("rsh_uint64 1%s18446744073709551615 = %d, wanted 0\n", `>>`, got)
failed = true
@@ -3159,6 +3689,16 @@ func main() {
failed = true
}
if got := rsh_4294967296_uint64_ssa(9223372036854775808); got != 0 {
fmt.Printf("rsh_uint64 4294967296%s9223372036854775808 = %d, wanted 0\n", `>>`, got)
failed = true
}
if got := rsh_uint64_4294967296_ssa(9223372036854775808); got != 0 {
fmt.Printf("rsh_uint64 9223372036854775808%s4294967296 = %d, wanted 0\n", `>>`, got)
failed = true
}
if got := rsh_4294967296_uint64_ssa(18446744073709551615); got != 0 {
fmt.Printf("rsh_uint64 4294967296%s18446744073709551615 = %d, wanted 0\n", `>>`, got)
failed = true
@@ -3169,6 +3709,56 @@ func main() {
failed = true
}
if got := rsh_9223372036854775808_uint64_ssa(0); got != 9223372036854775808 {
fmt.Printf("rsh_uint64 9223372036854775808%s0 = %d, wanted 9223372036854775808\n", `>>`, got)
failed = true
}
if got := rsh_uint64_9223372036854775808_ssa(0); got != 0 {
fmt.Printf("rsh_uint64 0%s9223372036854775808 = %d, wanted 0\n", `>>`, got)
failed = true
}
if got := rsh_9223372036854775808_uint64_ssa(1); got != 4611686018427387904 {
fmt.Printf("rsh_uint64 9223372036854775808%s1 = %d, wanted 4611686018427387904\n", `>>`, got)
failed = true
}
if got := rsh_uint64_9223372036854775808_ssa(1); got != 0 {
fmt.Printf("rsh_uint64 1%s9223372036854775808 = %d, wanted 0\n", `>>`, got)
failed = true
}
if got := rsh_9223372036854775808_uint64_ssa(4294967296); got != 0 {
fmt.Printf("rsh_uint64 9223372036854775808%s4294967296 = %d, wanted 0\n", `>>`, got)
failed = true
}
if got := rsh_uint64_9223372036854775808_ssa(4294967296); got != 0 {
fmt.Printf("rsh_uint64 4294967296%s9223372036854775808 = %d, wanted 0\n", `>>`, got)
failed = true
}
if got := rsh_9223372036854775808_uint64_ssa(9223372036854775808); got != 0 {
fmt.Printf("rsh_uint64 9223372036854775808%s9223372036854775808 = %d, wanted 0\n", `>>`, got)
failed = true
}
if got := rsh_uint64_9223372036854775808_ssa(9223372036854775808); got != 0 {
fmt.Printf("rsh_uint64 9223372036854775808%s9223372036854775808 = %d, wanted 0\n", `>>`, got)
failed = true
}
if got := rsh_9223372036854775808_uint64_ssa(18446744073709551615); got != 0 {
fmt.Printf("rsh_uint64 9223372036854775808%s18446744073709551615 = %d, wanted 0\n", `>>`, got)
failed = true
}
if got := rsh_uint64_9223372036854775808_ssa(18446744073709551615); got != 0 {
fmt.Printf("rsh_uint64 18446744073709551615%s9223372036854775808 = %d, wanted 0\n", `>>`, got)
failed = true
}
if got := rsh_18446744073709551615_uint64_ssa(0); got != 18446744073709551615 {
fmt.Printf("rsh_uint64 18446744073709551615%s0 = %d, wanted 18446744073709551615\n", `>>`, got)
failed = true
@@ -3199,6 +3789,16 @@ func main() {
failed = true
}
if got := rsh_18446744073709551615_uint64_ssa(9223372036854775808); got != 0 {
fmt.Printf("rsh_uint64 18446744073709551615%s9223372036854775808 = %d, wanted 0\n", `>>`, got)
failed = true
}
if got := rsh_uint64_18446744073709551615_ssa(9223372036854775808); got != 0 {
fmt.Printf("rsh_uint64 9223372036854775808%s18446744073709551615 = %d, wanted 0\n", `>>`, got)
failed = true
}
if got := rsh_18446744073709551615_uint64_ssa(18446744073709551615); got != 0 {
fmt.Printf("rsh_uint64 18446744073709551615%s18446744073709551615 = %d, wanted 0\n", `>>`, got)
failed = true
@@ -3219,6 +3819,11 @@ func main() {
failed = true
}
if got := mod_0_uint64_ssa(9223372036854775808); got != 0 {
fmt.Printf("mod_uint64 0%s9223372036854775808 = %d, wanted 0\n", `%`, got)
failed = true
}
if got := mod_0_uint64_ssa(18446744073709551615); got != 0 {
fmt.Printf("mod_uint64 0%s18446744073709551615 = %d, wanted 0\n", `%`, got)
failed = true
@@ -3249,6 +3854,16 @@ func main() {
failed = true
}
if got := mod_1_uint64_ssa(9223372036854775808); got != 1 {
fmt.Printf("mod_uint64 1%s9223372036854775808 = %d, wanted 1\n", `%`, got)
failed = true
}
if got := mod_uint64_1_ssa(9223372036854775808); got != 0 {
fmt.Printf("mod_uint64 9223372036854775808%s1 = %d, wanted 0\n", `%`, got)
failed = true
}
if got := mod_1_uint64_ssa(18446744073709551615); got != 1 {
fmt.Printf("mod_uint64 1%s18446744073709551615 = %d, wanted 1\n", `%`, got)
failed = true
@@ -3284,6 +3899,16 @@ func main() {
failed = true
}
if got := mod_4294967296_uint64_ssa(9223372036854775808); got != 4294967296 {
fmt.Printf("mod_uint64 4294967296%s9223372036854775808 = %d, wanted 4294967296\n", `%`, got)
failed = true
}
if got := mod_uint64_4294967296_ssa(9223372036854775808); got != 0 {
fmt.Printf("mod_uint64 9223372036854775808%s4294967296 = %d, wanted 0\n", `%`, got)
failed = true
}
if got := mod_4294967296_uint64_ssa(18446744073709551615); got != 4294967296 {
fmt.Printf("mod_uint64 4294967296%s18446744073709551615 = %d, wanted 4294967296\n", `%`, got)
failed = true
@@ -3294,6 +3919,51 @@ func main() {
failed = true
}
if got := mod_uint64_9223372036854775808_ssa(0); got != 0 {
fmt.Printf("mod_uint64 0%s9223372036854775808 = %d, wanted 0\n", `%`, got)
failed = true
}
if got := mod_9223372036854775808_uint64_ssa(1); got != 0 {
fmt.Printf("mod_uint64 9223372036854775808%s1 = %d, wanted 0\n", `%`, got)
failed = true
}
if got := mod_uint64_9223372036854775808_ssa(1); got != 1 {
fmt.Printf("mod_uint64 1%s9223372036854775808 = %d, wanted 1\n", `%`, got)
failed = true
}
if got := mod_9223372036854775808_uint64_ssa(4294967296); got != 0 {
fmt.Printf("mod_uint64 9223372036854775808%s4294967296 = %d, wanted 0\n", `%`, got)
failed = true
}
if got := mod_uint64_9223372036854775808_ssa(4294967296); got != 4294967296 {
fmt.Printf("mod_uint64 4294967296%s9223372036854775808 = %d, wanted 4294967296\n", `%`, got)
failed = true
}
if got := mod_9223372036854775808_uint64_ssa(9223372036854775808); got != 0 {
fmt.Printf("mod_uint64 9223372036854775808%s9223372036854775808 = %d, wanted 0\n", `%`, got)
failed = true
}
if got := mod_uint64_9223372036854775808_ssa(9223372036854775808); got != 0 {
fmt.Printf("mod_uint64 9223372036854775808%s9223372036854775808 = %d, wanted 0\n", `%`, got)
failed = true
}
if got := mod_9223372036854775808_uint64_ssa(18446744073709551615); got != 9223372036854775808 {
fmt.Printf("mod_uint64 9223372036854775808%s18446744073709551615 = %d, wanted 9223372036854775808\n", `%`, got)
failed = true
}
if got := mod_uint64_9223372036854775808_ssa(18446744073709551615); got != 9223372036854775807 {
fmt.Printf("mod_uint64 18446744073709551615%s9223372036854775808 = %d, wanted 9223372036854775807\n", `%`, got)
failed = true
}
if got := mod_uint64_18446744073709551615_ssa(0); got != 0 {
fmt.Printf("mod_uint64 0%s18446744073709551615 = %d, wanted 0\n", `%`, got)
failed = true
@@ -3319,6 +3989,16 @@ func main() {
failed = true
}
if got := mod_18446744073709551615_uint64_ssa(9223372036854775808); got != 9223372036854775807 {
fmt.Printf("mod_uint64 18446744073709551615%s9223372036854775808 = %d, wanted 9223372036854775807\n", `%`, got)
failed = true
}
if got := mod_uint64_18446744073709551615_ssa(9223372036854775808); got != 9223372036854775808 {
fmt.Printf("mod_uint64 9223372036854775808%s18446744073709551615 = %d, wanted 9223372036854775808\n", `%`, got)
failed = true
}
if got := mod_18446744073709551615_uint64_ssa(18446744073709551615); got != 0 {
fmt.Printf("mod_uint64 18446744073709551615%s18446744073709551615 = %d, wanted 0\n", `%`, got)
failed = true

View File

@@ -31,7 +31,7 @@ type szD struct {
}
var szs = []szD{
{name: "uint64", sn: "64", u: []uint64{0, 1, 4294967296, 0xffffFFFFffffFFFF}},
{name: "uint64", sn: "64", u: []uint64{0, 1, 4294967296, 0x8000000000000000, 0xffffFFFFffffFFFF}},
{name: "int64", sn: "64", i: []int64{-0x8000000000000000, -0x7FFFFFFFFFFFFFFF,
-4294967296, -1, 0, 1, 4294967296, 0x7FFFFFFFFFFFFFFE, 0x7FFFFFFFFFFFFFFF}},

View File

@@ -273,6 +273,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
case ssa.OpMIPSMOVWaddr:
p := s.Prog(mips.AMOVW)
p.From.Type = obj.TYPE_ADDR
p.From.Reg = v.Args[0].Reg()
var wantreg string
// MOVW $sym+off(base), R
// the assembler expands it as the following:
@@ -291,7 +292,6 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
case nil:
// No sym, just MOVW $off(SP), R
wantreg = "SP"
p.From.Reg = mips.REGSP
p.From.Offset = v.AuxInt
}
if reg := v.Args[0].RegName(); reg != wantreg {

View File

@@ -247,6 +247,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
case ssa.OpMIPS64MOVVaddr:
p := s.Prog(mips.AMOVV)
p.From.Type = obj.TYPE_ADDR
p.From.Reg = v.Args[0].Reg()
var wantreg string
// MOVV $sym+off(base), R
// the assembler expands it as the following:
@@ -265,7 +266,6 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
case nil:
// No sym, just MOVV $off(SP), R
wantreg = "SP"
p.From.Reg = mips.REGSP
p.From.Offset = v.AuxInt
}
if reg := v.Args[0].RegName(); reg != wantreg {

View File

@@ -638,6 +638,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
case ssa.OpPPC64MOVDaddr:
p := s.Prog(ppc64.AMOVD)
p.From.Type = obj.TYPE_ADDR
p.From.Reg = v.Args[0].Reg()
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
@@ -660,7 +661,6 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
case nil:
// No sym, just MOVD $off(SP), R
wantreg = "SP"
p.From.Reg = ppc64.REGSP
p.From.Offset = v.AuxInt
}
if reg := v.Args[0].RegName(); reg != wantreg {

View File

@@ -14,11 +14,6 @@ type Cache struct {
blocks [200]Block
locs [2000]Location
// Storage for DWARF variable locations. Lazily allocated
// since location lists are off by default.
varLocs []VarLoc
curVarLoc int
// Reusable stackAllocState.
// See stackalloc.go's {new,put}StackAllocState.
stackAllocState *stackAllocState
@@ -43,21 +38,4 @@ func (c *Cache) Reset() {
for i := range xl {
xl[i] = nil
}
xvl := c.varLocs[:c.curVarLoc]
for i := range xvl {
xvl[i] = VarLoc{}
}
c.curVarLoc = 0
}
func (c *Cache) NewVarLoc() *VarLoc {
if c.varLocs == nil {
c.varLocs = make([]VarLoc, 4000)
}
if c.curVarLoc == len(c.varLocs) {
return &VarLoc{}
}
vl := &c.varLocs[c.curVarLoc]
c.curVarLoc++
return vl
}

View File

@@ -1,559 +0,0 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ssa
import (
"cmd/internal/obj"
"fmt"
"strings"
)
type SlotID int32
// A FuncDebug contains all the debug information for the variables in a
// function. Variables are identified by their LocalSlot, which may be the
// result of decomposing a larger variable.
type FuncDebug struct {
Slots []*LocalSlot
Variables []VarLocList
Registers []Register
}
// append adds a location to the location list for slot.
func (f *FuncDebug) append(slot SlotID, loc *VarLoc) {
f.Variables[slot].append(loc)
}
// lastLoc returns the last VarLoc for slot, or nil if it has none.
func (f *FuncDebug) lastLoc(slot SlotID) *VarLoc {
return f.Variables[slot].last()
}
func (f *FuncDebug) String() string {
var vars []string
for slot, list := range f.Variables {
if len(list.Locations) == 0 {
continue
}
vars = append(vars, fmt.Sprintf("%v = %v", f.Slots[slot], list))
}
return fmt.Sprintf("{%v}", strings.Join(vars, ", "))
}
// A VarLocList contains the locations for a variable, in program text order.
// It will often have gaps.
type VarLocList struct {
Locations []*VarLoc
}
func (l *VarLocList) append(loc *VarLoc) {
l.Locations = append(l.Locations, loc)
}
// last returns the last location in the list.
func (l *VarLocList) last() *VarLoc {
if l == nil || len(l.Locations) == 0 {
return nil
}
return l.Locations[len(l.Locations)-1]
}
// A VarLoc describes a variable's location in a single contiguous range
// of program text. It is generated from the SSA representation, but it
// refers to the generated machine code, so the Values referenced are better
// understood as PCs than actual Values, and the ranges can cross blocks.
// The range is defined first by Values, which are then mapped to Progs
// during genssa and finally to function PCs after assembly.
// A variable can be on the stack and in any number of registers.
type VarLoc struct {
// Inclusive -- the first SSA value that the range covers. The value
// doesn't necessarily have anything to do with the variable; it just
// identifies a point in the program text.
Start *Value
// Exclusive -- the first SSA value after start that the range doesn't
// cover. A location with start == end is empty.
End *Value
// The prog/PCs corresponding to Start and End above. These are for the
// convenience of later passes, since code generation isn't done when
// BuildFuncDebug runs.
StartProg, EndProg *obj.Prog
StartPC, EndPC int64
// The registers this variable is available in. There can be more than
// one in various situations, e.g. it's being moved between registers.
Registers RegisterSet
// Indicates whether the variable is on the stack. The stack position is
// stored in the associated gc.Node.
OnStack bool
// Used only during generation. Indicates whether this location lasts
// past the block's end. Without this, there would be no way to distinguish
// between a range that ended on the last Value of a block and one that
// didn't end at all.
survivedBlock bool
}
// RegisterSet is a bitmap of registers, indexed by Register.num.
type RegisterSet uint64
func (v *VarLoc) String() string {
var registers []Register
if v.Start != nil {
registers = v.Start.Block.Func.Config.registers
}
loc := ""
if !v.OnStack && v.Registers == 0 {
loc = "!!!no location!!!"
}
if v.OnStack {
loc += "stack,"
}
var regnames []string
for reg := 0; reg < 64; reg++ {
if v.Registers&(1<<uint8(reg)) == 0 {
continue
}
if registers != nil {
regnames = append(regnames, registers[reg].Name())
} else {
regnames = append(regnames, fmt.Sprintf("reg%v", reg))
}
}
loc += strings.Join(regnames, ",")
pos := func(v *Value, p *obj.Prog, pc int64) string {
if v == nil {
return "?"
}
if p == nil {
return fmt.Sprintf("v%v", v.ID)
}
return fmt.Sprintf("v%v/%x", v.ID, pc)
}
surv := ""
if v.survivedBlock {
surv = "+"
}
return fmt.Sprintf("%v-%v%s@%s", pos(v.Start, v.StartProg, v.StartPC), pos(v.End, v.EndProg, v.EndPC), surv, loc)
}
// unexpected is used to indicate an inconsistency or bug in the debug info
// generation process. These are not fixable by users. At time of writing,
// changing this to a Fprintf(os.Stderr) and running make.bash generates
// thousands of warnings.
func (s *debugState) unexpected(v *Value, msg string, args ...interface{}) {
s.f.Logf("unexpected at "+fmt.Sprint(v.ID)+":"+msg, args...)
}
func (s *debugState) logf(msg string, args ...interface{}) {
s.f.Logf(msg, args...)
}
type debugState struct {
loggingEnabled bool
slots []*LocalSlot
f *Func
cache *Cache
numRegisters int
// working storage for BuildFuncDebug, reused between blocks.
registerContents [][]SlotID
}
// BuildFuncDebug returns debug information for f.
// f must be fully processed, so that each Value is where it will be when
// machine code is emitted.
func BuildFuncDebug(f *Func, loggingEnabled bool) *FuncDebug {
if f.RegAlloc == nil {
f.Fatalf("BuildFuncDebug on func %v that has not been fully processed", f)
}
state := &debugState{
loggingEnabled: loggingEnabled,
slots: make([]*LocalSlot, len(f.Names)),
cache: f.Cache,
f: f,
numRegisters: len(f.Config.registers),
registerContents: make([][]SlotID, len(f.Config.registers)),
}
// TODO: consider storing this in Cache and reusing across functions.
valueNames := make([][]SlotID, f.NumValues())
for i, slot := range f.Names {
slot := slot
state.slots[i] = &slot
if isSynthetic(&slot) {
continue
}
for _, value := range f.NamedValues[slot] {
valueNames[value.ID] = append(valueNames[value.ID], SlotID(i))
}
}
if state.loggingEnabled {
var names []string
for i, name := range f.Names {
names = append(names, fmt.Sprintf("%v = %v", i, name))
}
state.logf("Name table: %v\n", strings.Join(names, ", "))
}
// Build up block states, starting with the first block, then
// processing blocks once their predecessors have been processed.
// TODO: use a reverse post-order traversal instead of the work queue.
// Location list entries for each block.
blockLocs := make([]*FuncDebug, f.NumBlocks())
// Work queue of blocks to visit. Some of them may already be processed.
work := []*Block{f.Entry}
for len(work) > 0 {
b := work[0]
work = work[1:]
if blockLocs[b.ID] != nil {
continue // already processed
}
if !state.predecessorsDone(b, blockLocs) {
continue // not ready yet
}
for _, edge := range b.Succs {
if blockLocs[edge.Block().ID] != nil {
continue
}
work = append(work, edge.Block())
}
// Build the starting state for the block from the final
// state of its predecessors.
locs := state.mergePredecessors(b, blockLocs)
if state.loggingEnabled {
state.logf("Processing %v, initial locs %v, regs %v\n", b, locs, state.registerContents)
}
// Update locs/registers with the effects of each Value.
for _, v := range b.Values {
slots := valueNames[v.ID]
// Loads and stores inherit the names of their sources.
var source *Value
switch v.Op {
case OpStoreReg:
source = v.Args[0]
case OpLoadReg:
switch a := v.Args[0]; a.Op {
case OpArg:
source = a
case OpStoreReg:
source = a.Args[0]
default:
state.unexpected(v, "load with unexpected source op %v", a)
}
}
if source != nil {
slots = append(slots, valueNames[source.ID]...)
// As of writing, the compiler never uses a load/store as a
// source of another load/store, so there's no reason this should
// ever be consulted. Update just in case, and so that when
// valueNames is cached, we can reuse the memory.
valueNames[v.ID] = slots
}
if len(slots) == 0 {
continue
}
reg, _ := f.getHome(v.ID).(*Register)
state.processValue(locs, v, slots, reg)
}
// The block is done; end the locations for all its slots.
for _, locList := range locs.Variables {
last := locList.last()
if last == nil || last.End != nil {
continue
}
if len(b.Values) != 0 {
last.End = b.Values[len(b.Values)-1]
} else {
// This happens when a value survives into an empty block from its predecessor.
// Just carry it forward for liveness's sake.
last.End = last.Start
}
last.survivedBlock = true
}
if state.loggingEnabled {
f.Logf("Block done: locs %v, regs %v. work = %+v\n", locs, state.registerContents, work)
}
blockLocs[b.ID] = locs
}
// Build the complete debug info by concatenating each of the blocks'
// locations together.
info := &FuncDebug{
Variables: make([]VarLocList, len(state.slots)),
Slots: state.slots,
Registers: f.Config.registers,
}
for _, b := range f.Blocks {
// Ignore empty blocks; there will be some records for liveness
// but they're all useless.
if len(b.Values) == 0 {
continue
}
if blockLocs[b.ID] == nil {
state.unexpected(b.Values[0], "Never processed block %v\n", b)
continue
}
for slot, blockLocList := range blockLocs[b.ID].Variables {
for _, loc := range blockLocList.Locations {
if !loc.OnStack && loc.Registers == 0 {
state.unexpected(loc.Start, "Location for %v with no storage: %+v\n", state.slots[slot], loc)
continue // don't confuse downstream with our bugs
}
if loc.Start == nil || loc.End == nil {
state.unexpected(b.Values[0], "Location for %v missing start or end: %v\n", state.slots[slot], loc)
continue
}
info.append(SlotID(slot), loc)
}
}
}
if state.loggingEnabled {
f.Logf("Final result:\n")
for slot, locList := range info.Variables {
f.Logf("\t%v => %v\n", state.slots[slot], locList)
}
}
return info
}
// isSynthetic reports whether if slot represents a compiler-inserted variable,
// e.g. an autotmp or an anonymous return value that needed a stack slot.
func isSynthetic(slot *LocalSlot) bool {
c := slot.Name()[0]
return c == '.' || c == '~'
}
// predecessorsDone reports whether block is ready to be processed.
func (state *debugState) predecessorsDone(b *Block, blockLocs []*FuncDebug) bool {
f := b.Func
for _, edge := range b.Preds {
// Ignore back branches, e.g. the continuation of a for loop.
// This may not work for functions with mutual gotos, which are not
// reducible, in which case debug information will be missing for any
// code after that point in the control flow.
if f.sdom().isAncestorEq(b, edge.b) {
if state.loggingEnabled {
f.Logf("ignoring back branch from %v to %v\n", edge.b, b)
}
continue // back branch
}
if blockLocs[edge.b.ID] == nil {
if state.loggingEnabled {
f.Logf("%v is not ready because %v isn't done\n", b, edge.b)
}
return false
}
}
return true
}
// mergePredecessors takes the end state of each of b's predecessors and
// intersects them to form the starting state for b.
// The registers slice (the second return value) will be reused for each call to mergePredecessors.
func (state *debugState) mergePredecessors(b *Block, blockLocs []*FuncDebug) *FuncDebug {
live := make([]VarLocList, len(state.slots))
// Filter out back branches.
var preds []*Block
for _, pred := range b.Preds {
if blockLocs[pred.b.ID] != nil {
preds = append(preds, pred.b)
}
}
if len(preds) > 0 {
p := preds[0]
for slot, locList := range blockLocs[p.ID].Variables {
last := locList.last()
if last == nil || !last.survivedBlock {
continue
}
// If this block is empty, carry forward the end value for liveness.
// It'll be ignored later.
start := last.End
if len(b.Values) != 0 {
start = b.Values[0]
}
loc := state.cache.NewVarLoc()
loc.Start = start
loc.OnStack = last.OnStack
loc.Registers = last.Registers
live[slot].append(loc)
}
}
if state.loggingEnabled && len(b.Preds) > 1 {
state.logf("Starting merge with state from %v: %v\n", b.Preds[0].b, blockLocs[b.Preds[0].b.ID])
}
for i := 1; i < len(preds); i++ {
p := preds[i]
if state.loggingEnabled {
state.logf("Merging in state from %v: %v &= %v\n", p, live, blockLocs[p.ID])
}
for slot, liveVar := range live {
liveLoc := liveVar.last()
if liveLoc == nil {
continue
}
predLoc := blockLocs[p.ID].lastLoc(SlotID(slot))
// Clear out slots missing/dead in p.
if predLoc == nil || !predLoc.survivedBlock {
live[slot].Locations = nil
continue
}
// Unify storage locations.
liveLoc.OnStack = liveLoc.OnStack && predLoc.OnStack
liveLoc.Registers &= predLoc.Registers
}
}
// Create final result.
locs := &FuncDebug{Variables: live, Slots: state.slots}
for reg := range state.registerContents {
state.registerContents[reg] = state.registerContents[reg][:0]
}
for slot, locList := range live {
loc := locList.last()
if loc == nil {
continue
}
for reg := 0; reg < state.numRegisters; reg++ {
if loc.Registers&(1<<uint8(reg)) != 0 {
state.registerContents[reg] = append(state.registerContents[reg], SlotID(slot))
}
}
}
return locs
}
// processValue updates locs and state.registerContents to reflect v, a value with
// the names in vSlots and homed in vReg.
func (state *debugState) processValue(locs *FuncDebug, v *Value, vSlots []SlotID, vReg *Register) {
switch {
case v.Op == OpRegKill:
if state.loggingEnabled {
existingSlots := make([]bool, len(state.slots))
for _, slot := range state.registerContents[vReg.num] {
existingSlots[slot] = true
}
for _, slot := range vSlots {
if existingSlots[slot] {
existingSlots[slot] = false
} else {
state.unexpected(v, "regkill of unassociated name %v\n", state.slots[slot])
}
}
for slot, live := range existingSlots {
if live {
state.unexpected(v, "leftover register name: %v\n", state.slots[slot])
}
}
}
state.registerContents[vReg.num] = nil
for _, slot := range vSlots {
last := locs.lastLoc(slot)
if last == nil {
state.unexpected(v, "regkill of already dead %v, %+v\n", vReg, state.slots[slot])
continue
}
if state.loggingEnabled {
state.logf("at %v: %v regkilled out of %v\n", v.ID, state.slots[slot], vReg.Name())
}
if last.End != nil {
state.unexpected(v, "regkill of dead slot, died at %v\n", last.End)
}
last.End = v
regs := last.Registers &^ (1 << uint8(vReg.num))
if !last.OnStack && regs == 0 {
continue
}
loc := state.cache.NewVarLoc()
loc.Start = v
loc.OnStack = last.OnStack
loc.Registers = regs
locs.append(slot, loc)
}
case v.Op == OpArg:
for _, slot := range vSlots {
if state.loggingEnabled {
state.logf("at %v: %v now on stack from arg\n", v.ID, state.slots[slot])
}
loc := state.cache.NewVarLoc()
loc.Start = v
loc.OnStack = true
locs.append(slot, loc)
}
case v.Op == OpStoreReg:
for _, slot := range vSlots {
if state.loggingEnabled {
state.logf("at %v: %v spilled to stack\n", v.ID, state.slots[slot])
}
last := locs.lastLoc(slot)
if last == nil {
state.unexpected(v, "spill of unnamed register %v\n", vReg)
break
}
last.End = v
loc := state.cache.NewVarLoc()
loc.Start = v
loc.OnStack = true
loc.Registers = last.Registers
locs.append(slot, loc)
}
case vReg != nil:
if state.loggingEnabled {
newSlots := make([]bool, len(state.slots))
for _, slot := range vSlots {
newSlots[slot] = true
}
for _, slot := range state.registerContents[vReg.num] {
if !newSlots[slot] {
state.unexpected(v, "%v clobbered\n", state.slots[slot])
}
}
}
for _, slot := range vSlots {
if state.loggingEnabled {
state.logf("at %v: %v now in %v\n", v.ID, state.slots[slot], vReg.Name())
}
last := locs.lastLoc(slot)
if last != nil && last.End == nil {
last.End = v
}
state.registerContents[vReg.num] = append(state.registerContents[vReg.num], slot)
loc := state.cache.NewVarLoc()
loc.Start = v
if last != nil {
loc.OnStack = last.OnStack
loc.Registers = last.Registers
}
loc.Registers |= 1 << uint8(vReg.num)
locs.append(slot, loc)
}
default:
state.unexpected(v, "named value with no reg\n")
}
}

View File

@@ -98,7 +98,6 @@ func decomposeBuiltIn(f *Func) {
delete(f.NamedValues, name)
case t.IsFloat():
// floats are never decomposed, even ones bigger than RegSize
newNames = append(newNames, name)
case t.Size() > f.Config.RegSize:
f.Fatalf("undecomposed named type %v %v", name, t)
default:

View File

@@ -82,33 +82,33 @@ func (DummyFrontend) Auto(pos src.XPos, t *types.Type) GCNode {
return &DummyAuto{t: t, s: "aDummyAuto"}
}
func (d DummyFrontend) SplitString(s LocalSlot) (LocalSlot, LocalSlot) {
return LocalSlot{N: s.N, Type: dummyTypes.BytePtr, Off: s.Off}, LocalSlot{N: s.N, Type: dummyTypes.Int, Off: s.Off + 8}
return LocalSlot{s.N, dummyTypes.BytePtr, s.Off}, LocalSlot{s.N, dummyTypes.Int, s.Off + 8}
}
func (d DummyFrontend) SplitInterface(s LocalSlot) (LocalSlot, LocalSlot) {
return LocalSlot{N: s.N, Type: dummyTypes.BytePtr, Off: s.Off}, LocalSlot{N: s.N, Type: dummyTypes.BytePtr, Off: s.Off + 8}
return LocalSlot{s.N, dummyTypes.BytePtr, s.Off}, LocalSlot{s.N, dummyTypes.BytePtr, s.Off + 8}
}
func (d DummyFrontend) SplitSlice(s LocalSlot) (LocalSlot, LocalSlot, LocalSlot) {
return LocalSlot{N: s.N, Type: s.Type.ElemType().PtrTo(), Off: s.Off},
LocalSlot{N: s.N, Type: dummyTypes.Int, Off: s.Off + 8},
LocalSlot{N: s.N, Type: dummyTypes.Int, Off: s.Off + 16}
return LocalSlot{s.N, s.Type.ElemType().PtrTo(), s.Off},
LocalSlot{s.N, dummyTypes.Int, s.Off + 8},
LocalSlot{s.N, dummyTypes.Int, s.Off + 16}
}
func (d DummyFrontend) SplitComplex(s LocalSlot) (LocalSlot, LocalSlot) {
if s.Type.Size() == 16 {
return LocalSlot{N: s.N, Type: dummyTypes.Float64, Off: s.Off}, LocalSlot{N: s.N, Type: dummyTypes.Float64, Off: s.Off + 8}
return LocalSlot{s.N, dummyTypes.Float64, s.Off}, LocalSlot{s.N, dummyTypes.Float64, s.Off + 8}
}
return LocalSlot{N: s.N, Type: dummyTypes.Float32, Off: s.Off}, LocalSlot{N: s.N, Type: dummyTypes.Float32, Off: s.Off + 4}
return LocalSlot{s.N, dummyTypes.Float32, s.Off}, LocalSlot{s.N, dummyTypes.Float32, s.Off + 4}
}
func (d DummyFrontend) SplitInt64(s LocalSlot) (LocalSlot, LocalSlot) {
if s.Type.IsSigned() {
return LocalSlot{N: s.N, Type: dummyTypes.Int32, Off: s.Off + 4}, LocalSlot{N: s.N, Type: dummyTypes.UInt32, Off: s.Off}
return LocalSlot{s.N, dummyTypes.Int32, s.Off + 4}, LocalSlot{s.N, dummyTypes.UInt32, s.Off}
}
return LocalSlot{N: s.N, Type: dummyTypes.UInt32, Off: s.Off + 4}, LocalSlot{N: s.N, Type: dummyTypes.UInt32, Off: s.Off}
return LocalSlot{s.N, dummyTypes.UInt32, s.Off + 4}, LocalSlot{s.N, dummyTypes.UInt32, s.Off}
}
func (d DummyFrontend) SplitStruct(s LocalSlot, i int) LocalSlot {
return LocalSlot{N: s.N, Type: s.Type.FieldType(i), Off: s.Off + s.Type.FieldOff(i)}
return LocalSlot{s.N, s.Type.FieldType(i), s.Off + s.Type.FieldOff(i)}
}
func (d DummyFrontend) SplitArray(s LocalSlot) LocalSlot {
return LocalSlot{N: s.N, Type: s.Type.ElemType(), Off: s.Off}
return LocalSlot{s.N, s.Type.ElemType(), s.Off}
}
func (DummyFrontend) Line(_ src.XPos) string {
return "unknown.go:0"

View File

@@ -945,6 +945,7 @@
(Div16u n (Const16 [c])) && isPowerOfTwo(c&0xffff) -> (Rsh16Ux64 n (Const64 <typ.UInt64> [log2(c&0xffff)]))
(Div32u n (Const32 [c])) && isPowerOfTwo(c&0xffffffff) -> (Rsh32Ux64 n (Const64 <typ.UInt64> [log2(c&0xffffffff)]))
(Div64u n (Const64 [c])) && isPowerOfTwo(c) -> (Rsh64Ux64 n (Const64 <typ.UInt64> [log2(c)]))
(Div64u n (Const64 [-1<<63])) -> (Rsh64Ux64 n (Const64 <typ.UInt64> [63]))
// Unsigned divide, not a power of 2. Strength reduce to a multiply.
// For 8-bit divides, we just do a direct 9-bit by 8-bit multiply.
@@ -1177,6 +1178,7 @@
(Mod16u <t> n (Const16 [c])) && isPowerOfTwo(c&0xffff) -> (And16 n (Const16 <t> [(c&0xffff)-1]))
(Mod32u <t> n (Const32 [c])) && isPowerOfTwo(c&0xffffffff) -> (And32 n (Const32 <t> [(c&0xffffffff)-1]))
(Mod64u <t> n (Const64 [c])) && isPowerOfTwo(c) -> (And64 n (Const64 <t> [c-1]))
(Mod64u <t> n (Const64 [-1<<63])) -> (And64 n (Const64 <t> [1<<63-1]))
// Signed mod by negative constant.
(Mod8 <t> n (Const8 [c])) && c < 0 && c != -1<<7 -> (Mod8 <t> n (Const8 <t> [-c]))

View File

@@ -417,7 +417,6 @@ var genericOps = []opData{
{name: "VarKill", argLength: 1, aux: "Sym", symEffect: "None"}, // aux is a *gc.Node of a variable that is known to be dead. arg0=mem, returns mem
{name: "VarLive", argLength: 1, aux: "Sym", symEffect: "None"}, // aux is a *gc.Node of a variable that must be kept live. arg0=mem, returns mem
{name: "KeepAlive", argLength: 2, typ: "Mem"}, // arg[0] is a value that must be kept alive until this mark. arg[1]=mem, returns mem
{name: "RegKill"}, // regalloc has determined that the value in this register is dead
// Ops for breaking 64-bit operations on 32-bit architectures
{name: "Int64Make", argLength: 2, typ: "UInt64"}, // arg0=hi, arg1=lo

View File

@@ -11,7 +11,6 @@ import (
"html"
"io"
"os"
"strings"
)
type HTMLWriter struct {
@@ -363,18 +362,6 @@ func (v *Value) LongHTML() string {
if int(v.ID) < len(r) && r[v.ID] != nil {
s += " : " + html.EscapeString(r[v.ID].Name())
}
var names []string
for name, values := range v.Block.Func.NamedValues {
for _, value := range values {
if value == v {
names = append(names, name.Name())
break // drop duplicates.
}
}
}
if len(names) != 0 {
s += " (" + strings.Join(names, ", ") + ")"
}
s += "</span>"
return s
}

View File

@@ -26,38 +26,12 @@ func (r *Register) Name() string {
return r.name
}
// ObjNum returns the register number from cmd/internal/obj/$ARCH that
// corresponds to this register.
func (r *Register) ObjNum() int16 {
return r.objNum
}
// A LocalSlot is a location in the stack frame, which identifies and stores
// part or all of a PPARAM, PPARAMOUT, or PAUTO ONAME node.
// It can represent a whole variable, part of a larger stack slot, or part of a
// variable that has been decomposed into multiple stack slots.
// As an example, a string could have the following configurations:
//
// stack layout LocalSlots
//
// Optimizations are disabled. s is on the stack and represented in its entirety.
// [ ------- s string ---- ] { N: s, Type: string, Off: 0 }
//
// s was not decomposed, but the SSA operates on its parts individually, so
// there is a LocalSlot for each of its fields that points into the single stack slot.
// [ ------- s string ---- ] { N: s, Type: *uint8, Off: 0 }, {N: s, Type: int, Off: 8}
//
// s was decomposed. Each of its fields is in its own stack slot and has its own LocalSLot.
// [ ptr *uint8 ] [ len int] { N: ptr, Type: *uint8, Off: 0, SplitOf: parent, SplitOffset: 0},
// { N: len, Type: int, Off: 0, SplitOf: parent, SplitOffset: 8}
// parent = &{N: s, Type: string}
// A LocalSlot is a location in the stack frame.
// It is (possibly a subpiece of) a PPARAM, PPARAMOUT, or PAUTO ONAME node.
type LocalSlot struct {
N GCNode // an ONAME *gc.Node representing a stack location.
N GCNode // an ONAME *gc.Node representing a variable on the stack
Type *types.Type // type of slot
Off int64 // offset of slot in N
SplitOf *LocalSlot // slot is a decomposition of SplitOf
SplitOffset int64 // .. at this offset.
}
func (s LocalSlot) Name() string {

View File

@@ -1897,7 +1897,6 @@ const (
OpVarKill
OpVarLive
OpKeepAlive
OpRegKill
OpInt64Make
OpInt64Hi
OpInt64Lo
@@ -22498,11 +22497,6 @@ var opcodeTable = [...]opInfo{
argLen: 2,
generic: true,
},
{
name: "RegKill",
argLen: 0,
generic: true,
},
{
name: "Int64Make",
argLen: 2,

View File

@@ -242,9 +242,6 @@ type regAllocState struct {
// current state of each (preregalloc) Value
values []valState
// names associated with each Value
valueNames [][]LocalSlot
// ID of SP, SB values
sp, sb ID
@@ -303,13 +300,6 @@ type startReg struct {
// freeReg frees up register r. Any current user of r is kicked out.
func (s *regAllocState) freeReg(r register) {
s.freeOrResetReg(r, false)
}
// freeOrResetReg frees up register r. Any current user of r is kicked out.
// resetting indicates that the operation is only for bookkeeping,
// e.g. when clearing out state upon entry to a new block.
func (s *regAllocState) freeOrResetReg(r register, resetting bool) {
v := s.regs[r].v
if v == nil {
s.f.Fatalf("tried to free an already free register %d\n", r)
@@ -319,16 +309,6 @@ func (s *regAllocState) freeOrResetReg(r register, resetting bool) {
if s.f.pass.debug > regDebug {
fmt.Printf("freeReg %s (dump %s/%s)\n", s.registers[r].Name(), v, s.regs[r].c)
}
if !resetting && s.f.Config.ctxt.Flag_locationlists && len(s.valueNames[v.ID]) != 0 {
kill := s.curBlock.NewValue0(src.NoXPos, OpRegKill, types.TypeVoid)
for int(kill.ID) >= len(s.orig) {
s.orig = append(s.orig, nil)
}
for _, name := range s.valueNames[v.ID] {
s.f.NamedValues[name] = append(s.f.NamedValues[name], kill)
}
s.f.setHome(kill, &s.registers[r])
}
s.regs[r] = regState{}
s.values[v.ID].regs &^= regMask(1) << r
s.used &^= regMask(1) << r
@@ -619,17 +599,6 @@ func (s *regAllocState) init(f *Func) {
s.values = make([]valState, f.NumValues())
s.orig = make([]*Value, f.NumValues())
s.copies = make(map[*Value]bool)
if s.f.Config.ctxt.Flag_locationlists {
s.valueNames = make([][]LocalSlot, f.NumValues())
for slot, values := range f.NamedValues {
if isSynthetic(&slot) {
continue
}
for _, value := range values {
s.valueNames[value.ID] = append(s.valueNames[value.ID], slot)
}
}
}
for _, b := range f.Blocks {
for _, v := range b.Values {
if !v.Type.IsMemory() && !v.Type.IsVoid() && !v.Type.IsFlags() && !v.Type.IsTuple() {
@@ -723,9 +692,7 @@ func (s *regAllocState) liveAfterCurrentInstruction(v *Value) bool {
// Sets the state of the registers to that encoded in regs.
func (s *regAllocState) setState(regs []endReg) {
for s.used != 0 {
s.freeOrResetReg(pickReg(s.used), true)
}
s.freeRegs(s.used)
for _, x := range regs {
s.assignReg(x.r, x.v, x.c)
}
@@ -768,9 +735,6 @@ func (s *regAllocState) regalloc(f *Func) {
}
for _, b := range f.Blocks {
if s.f.pass.debug > regDebug {
fmt.Printf("Begin processing block %v\n", b)
}
s.curBlock = b
// Initialize regValLiveSet and uses fields for this block.
@@ -866,6 +830,9 @@ func (s *regAllocState) regalloc(f *Func) {
// This is the complicated case. We have more than one predecessor,
// which means we may have Phi ops.
// Copy phi ops into new schedule.
b.Values = append(b.Values, phis...)
// Start with the final register state of the primary predecessor
idx := s.primary[b.ID]
if idx < 0 {
@@ -943,9 +910,6 @@ func (s *regAllocState) regalloc(f *Func) {
}
}
// Copy phi ops into new schedule.
b.Values = append(b.Values, phis...)
// Third pass - pick registers for phis whose inputs
// were not in a register.
for i, v := range phis {
@@ -1041,7 +1005,7 @@ func (s *regAllocState) regalloc(f *Func) {
pidx := e.i
for _, v := range succ.Values {
if v.Op != OpPhi {
continue
break
}
if !s.values[v.ID].needReg {
continue
@@ -1601,9 +1565,6 @@ func (s *regAllocState) placeSpills() {
for _, b := range f.Blocks {
var m regMask
for _, v := range b.Values {
if v.Op == OpRegKill {
continue
}
if v.Op != OpPhi {
break
}
@@ -1714,7 +1675,7 @@ func (s *regAllocState) placeSpills() {
for _, b := range f.Blocks {
nphi := 0
for _, v := range b.Values {
if v.Op != OpRegKill && v.Op != OpPhi {
if v.Op != OpPhi {
break
}
nphi++
@@ -1839,9 +1800,6 @@ func (e *edgeState) setup(idx int, srcReg []endReg, dstReg []startReg, stacklive
}
// Phis need their args to end up in a specific location.
for _, v := range e.b.Values {
if v.Op == OpRegKill {
continue
}
if v.Op != OpPhi {
break
}
@@ -1920,7 +1878,6 @@ func (e *edgeState) process() {
if e.s.f.pass.debug > regDebug {
fmt.Printf("breaking cycle with v%d in %s:%s\n", vid, loc.Name(), c)
}
e.erase(r)
if _, isReg := loc.(*Register); isReg {
c = e.p.NewValue1(d.pos, OpCopy, c.Type, c)
} else {
@@ -1986,18 +1943,6 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value, pos src.XP
}
}
_, dstReg := loc.(*Register)
// Pre-clobber destination. This avoids the
// following situation:
// - v is currently held in R0 and stacktmp0.
// - We want to copy stacktmp1 to stacktmp0.
// - We choose R0 as the temporary register.
// During the copy, both R0 and stacktmp0 are
// clobbered, losing both copies of v. Oops!
// Erasing the destination early means R0 will not
// be chosen as the temp register, as it will then
// be the last copy of v.
e.erase(loc)
var x *Value
if c == nil {
if !e.s.values[vid].rematerializeable {
@@ -2008,8 +1953,8 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value, pos src.XP
} else {
// Rematerialize into stack slot. Need a free
// register to accomplish this.
e.erase(loc) // see pre-clobber comment below
r := e.findRegFor(v.Type)
e.erase(r)
x = v.copyIntoNoXPos(e.p)
e.set(r, vid, x, false, pos)
// Make sure we spill with the size of the slot, not the
@@ -2031,8 +1976,20 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value, pos src.XP
x = e.p.NewValue1(pos, OpLoadReg, c.Type, c)
} else {
// mem->mem. Use temp register.
// Pre-clobber destination. This avoids the
// following situation:
// - v is currently held in R0 and stacktmp0.
// - We want to copy stacktmp1 to stacktmp0.
// - We choose R0 as the temporary register.
// During the copy, both R0 and stacktmp0 are
// clobbered, losing both copies of v. Oops!
// Erasing the destination early means R0 will not
// be chosen as the temp register, as it will then
// be the last copy of v.
e.erase(loc)
r := e.findRegFor(c.Type)
e.erase(r)
t := e.p.NewValue1(pos, OpLoadReg, c.Type, c)
e.set(r, vid, t, false, pos)
x = e.p.NewValue1(pos, OpStoreReg, loc.(LocalSlot).Type, t)
@@ -2051,6 +2008,7 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value, pos src.XP
// set changes the contents of location loc to hold the given value and its cached representative.
func (e *edgeState) set(loc Location, vid ID, c *Value, final bool, pos src.XPos) {
e.s.f.setHome(c, loc)
e.erase(loc)
e.contents[loc] = contentRecord{vid, c, final, pos}
a := e.cache[vid]
if len(a) == 0 {
@@ -2101,16 +2059,6 @@ func (e *edgeState) erase(loc Location) {
fmt.Printf("v%d no longer available in %s:%s\n", vid, loc.Name(), c)
}
a[i], a = a[len(a)-1], a[:len(a)-1]
if e.s.f.Config.ctxt.Flag_locationlists {
if _, isReg := loc.(*Register); isReg && int(c.ID) < len(e.s.valueNames) && len(e.s.valueNames[c.ID]) != 0 {
kill := e.p.NewValue0(src.NoXPos, OpRegKill, types.TypeVoid)
e.s.f.setHome(kill, loc)
for _, name := range e.s.valueNames[c.ID] {
e.s.f.NamedValues[name] = append(e.s.f.NamedValues[name], kill)
}
}
}
break
}
}
@@ -2170,8 +2118,8 @@ func (e *edgeState) findRegFor(typ *types.Type) Location {
// Allocate a temp location to spill a register to.
// The type of the slot is immaterial - it will not be live across
// any safepoint. Just use a type big enough to hold any register.
t := LocalSlot{N: e.s.f.fe.Auto(c.Pos, types.Int64), Type: types.Int64}
// TODO: reuse these slots. They'll need to be erased first.
t := LocalSlot{e.s.f.fe.Auto(c.Pos, types.Int64), types.Int64, 0}
// TODO: reuse these slots.
e.set(t, vid, x, false, c.Pos)
if e.s.f.pass.debug > regDebug {
fmt.Printf(" SPILL %s->%s %s\n", r.Name(), t.Name(), x.LongString())

View File

@@ -7240,6 +7240,26 @@ func rewriteValuegeneric_OpDiv64u_0(v *Value) bool {
v.AddArg(v0)
return true
}
// match: (Div64u n (Const64 [-1<<63]))
// cond:
// result: (Rsh64Ux64 n (Const64 <typ.UInt64> [63]))
for {
_ = v.Args[1]
n := v.Args[0]
v_1 := v.Args[1]
if v_1.Op != OpConst64 {
break
}
if v_1.AuxInt != -1<<63 {
break
}
v.reset(OpRsh64Ux64)
v.AddArg(n)
v0 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
v0.AuxInt = 63
v.AddArg(v0)
return true
}
// match: (Div64u x (Const64 [c]))
// cond: umagicOK(64, c) && config.RegSize == 8 && umagic(64,c).m&1 == 0
// result: (Rsh64Ux64 <typ.UInt64> (Hmul64u <typ.UInt64> (Const64 <typ.UInt64> [int64(1<<63+umagic(64,c).m/2)]) x) (Const64 <typ.UInt64> [umagic(64,c).s-1]))
@@ -12061,6 +12081,27 @@ func rewriteValuegeneric_OpMod64u_0(v *Value) bool {
v.AddArg(v0)
return true
}
// match: (Mod64u <t> n (Const64 [-1<<63]))
// cond:
// result: (And64 n (Const64 <t> [1<<63-1]))
for {
t := v.Type
_ = v.Args[1]
n := v.Args[0]
v_1 := v.Args[1]
if v_1.Op != OpConst64 {
break
}
if v_1.AuxInt != -1<<63 {
break
}
v.reset(OpAnd64)
v.AddArg(n)
v0 := b.NewValue0(v.Pos, OpConst64, t)
v0.AuxInt = 1<<63 - 1
v.AddArg(v0)
return true
}
// match: (Mod64u <t> x (Const64 [c]))
// cond: x.Op != OpConst64 && c > 0 && umagicOK(64,c)
// result: (Sub64 x (Mul64 <t> (Div64u <t> x (Const64 <t> [c])) (Const64 <t> [c])))

View File

@@ -24,7 +24,6 @@ func TestSizeof(t *testing.T) {
}{
{Value{}, 68, 112},
{Block{}, 152, 288},
{LocalSlot{}, 32, 48},
{valState{}, 28, 40},
}

View File

@@ -151,7 +151,7 @@ func (s *stackAllocState) stackalloc() {
if v.Op != OpArg {
continue
}
loc := LocalSlot{N: v.Aux.(GCNode), Type: v.Type, Off: v.AuxInt}
loc := LocalSlot{v.Aux.(GCNode), v.Type, v.AuxInt}
if f.pass.debug > stackDebug {
fmt.Printf("stackalloc %s to %s\n", v, loc.Name())
}

View File

@@ -10,7 +10,6 @@ import (
"cmd/internal/src"
"fmt"
"math"
"strings"
)
// A Value represents a value in the SSA representation of the program.
@@ -99,7 +98,7 @@ func (v *Value) AuxValAndOff() ValAndOff {
return ValAndOff(v.AuxInt)
}
// long form print. v# = opcode <type> [aux] args [: reg] (names)
// long form print. v# = opcode <type> [aux] args [: reg]
func (v *Value) LongString() string {
s := fmt.Sprintf("v%d = %s", v.ID, v.Op)
s += " <" + v.Type.String() + ">"
@@ -111,18 +110,6 @@ func (v *Value) LongString() string {
if int(v.ID) < len(r) && r[v.ID] != nil {
s += " : " + r[v.ID].Name()
}
var names []string
for name, values := range v.Block.Func.NamedValues {
for _, value := range values {
if value == v {
names = append(names, name.Name())
break // drop duplicates.
}
}
}
if len(names) != 0 {
s += " (" + strings.Join(names, ", ") + ")"
}
return s
}

View File

@@ -120,7 +120,7 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) {
p = s.Prog(x86.AFLDCW)
p.From.Type = obj.TYPE_MEM
p.From.Name = obj.NAME_EXTERN
p.From.Sym = gc.Sysfunc("controlWord32")
p.From.Sym = gc.ControlWord32
}
var op obj.As
@@ -210,7 +210,7 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) {
p = s.Prog(x86.AFLDCW)
p.From.Type = obj.TYPE_MEM
p.From.Name = obj.NAME_EXTERN
p.From.Sym = gc.Sysfunc("controlWord64trunc")
p.From.Sym = gc.ControlWord64trunc
// Now do the conversion.
p = s.Prog(x86.AFMOVLP)

18
src/cmd/dist/deps.go vendored
View File

@@ -31,8 +31,8 @@ var builddeps = map[string][]string{
"cmd/internal/objabi": {"errors", "flag", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "log", "math", "os", "path/filepath", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
"compress/flate": {"bufio", "bytes", "errors", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "math/bits", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
"compress/zlib": {"bufio", "bytes", "compress/flate", "errors", "fmt", "hash", "hash/adler32", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "math/bits", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
"container/heap": {"errors", "internal/cpu", "internal/race", "math", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "unicode/utf8"},
"context": {"errors", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
"container/heap": {"errors", "internal/cpu", "internal/race", "math", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "unicode", "unicode/utf8"},
"context": {"errors", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
"crypto": {"errors", "hash", "internal/cpu", "internal/race", "io", "math", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
"crypto/sha1": {"crypto", "errors", "hash", "internal/cpu", "internal/race", "io", "math", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
"debug/dwarf": {"encoding/binary", "errors", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "path", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
@@ -40,18 +40,18 @@ var builddeps = map[string][]string{
"debug/macho": {"bytes", "debug/dwarf", "encoding/binary", "errors", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "path", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
"encoding": {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
"encoding/base64": {"errors", "internal/cpu", "internal/race", "io", "math", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
"encoding/binary": {"errors", "internal/cpu", "internal/race", "io", "math", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
"encoding/binary": {"errors", "internal/cpu", "internal/race", "io", "math", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode", "unicode/utf8"},
"encoding/json": {"bytes", "encoding", "encoding/base64", "errors", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
"encoding/xml": {"bufio", "bytes", "encoding", "errors", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
"errors": {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
"flag": {"errors", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
"fmt": {"errors", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
"flag": {"errors", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
"fmt": {"errors", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
"go/ast": {"bytes", "errors", "fmt", "go/scanner", "go/token", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "path/filepath", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
"go/build": {"bufio", "bytes", "errors", "fmt", "go/ast", "go/doc", "go/parser", "go/scanner", "go/token", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
"go/doc": {"bytes", "errors", "fmt", "go/ast", "go/scanner", "go/token", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "math", "net/url", "os", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
"go/parser": {"bytes", "errors", "fmt", "go/ast", "go/scanner", "go/token", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "math", "os", "path/filepath", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
"go/scanner": {"bytes", "errors", "fmt", "go/token", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "path/filepath", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
"go/token": {"errors", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
"go/token": {"errors", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
"hash": {"errors", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic"},
"hash/adler32": {"errors", "hash", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic"},
"internal/cpu": {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
@@ -63,7 +63,7 @@ var builddeps = map[string][]string{
"internal/syscall/windows/sysdll": {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
"io": {"errors", "internal/race", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic"},
"io/ioutil": {"bytes", "errors", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "path/filepath", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
"log": {"errors", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
"log": {"errors", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
"math": {"internal/cpu", "runtime", "runtime/internal/atomic", "runtime/internal/sys"},
"math/bits": {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
"net/url": {"bytes", "errors", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
@@ -72,13 +72,13 @@ var builddeps = map[string][]string{
"os/signal": {"errors", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "os", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
"path": {"errors", "internal/cpu", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strings", "sync", "sync/atomic", "unicode", "unicode/utf8"},
"path/filepath": {"errors", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
"reflect": {"errors", "internal/cpu", "internal/race", "math", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
"reflect": {"errors", "internal/cpu", "internal/race", "math", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode", "unicode/utf8"},
"regexp": {"bytes", "errors", "internal/cpu", "internal/race", "io", "math", "reflect", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "unicode", "unicode/utf8"},
"regexp/syntax": {"bytes", "errors", "internal/cpu", "internal/race", "io", "math", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "unicode", "unicode/utf8"},
"runtime": {"runtime/internal/atomic", "runtime/internal/sys"},
"runtime/internal/atomic": {"runtime/internal/sys"},
"runtime/internal/sys": {},
"sort": {"errors", "internal/cpu", "internal/race", "math", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
"sort": {"errors", "internal/cpu", "internal/race", "math", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode", "unicode/utf8"},
"strconv": {"errors", "internal/cpu", "math", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "unicode/utf8"},
"strings": {"errors", "internal/cpu", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "unicode", "unicode/utf8"},
"sync": {"internal/race", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync/atomic"},

11
src/cmd/dist/test.go vendored
View File

@@ -447,6 +447,17 @@ func (t *tester) registerTests() {
t.runPending(dt)
moved := t.goroot + "-moved"
if err := os.Rename(t.goroot, moved); err != nil {
if t.goos == "windows" {
// Fails on Windows (with "Access is denied") if a process
// or binary is in this directory. For instance, using all.bat
// when run from c:\workdir\go\src fails here
// if GO_BUILDER_NAME is set. Our builders invoke tests
// a different way which happens to work when sharding
// tests, but we should be tolerant of the non-sharded
// all.bat case.
log.Printf("skipping test on Windows")
return nil
}
return err
}

View File

@@ -1317,6 +1317,25 @@ func TestGetGitDefaultBranch(t *testing.T) {
tg.grepStdout(`\* another-branch`, "not on correct default branch")
}
func TestAccidentalGitCheckout(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
if _, err := exec.LookPath("git"); err != nil {
t.Skip("skipping because git binary not found")
}
tg := testgo(t)
defer tg.cleanup()
tg.parallel()
tg.tempDir("src")
tg.setenv("GOPATH", tg.path("."))
tg.runFail("get", "-u", "vcs-test.golang.org/go/test1-svn-git")
tg.grepStderr("src[\\\\/]vcs-test.* uses git, but parent .*src[\\\\/]vcs-test.* uses svn", "get did not fail for right reason")
tg.runFail("get", "-u", "vcs-test.golang.org/go/test2-svn-git/test2main")
tg.grepStderr("src[\\\\/]vcs-test.* uses git, but parent .*src[\\\\/]vcs-test.* uses svn", "get did not fail for right reason")
}
func TestErrorMessageForSyntaxErrorInTestGoFileSaysFAIL(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
@@ -4314,3 +4333,20 @@ func TestTestRegexps(t *testing.T) {
t.Errorf("reduced output:<<<\n%s>>> want:<<<\n%s>>>", have, want)
}
}
func TestListTests(t *testing.T) {
var tg *testgoData
testWith := func(listName, expected string) func(*testing.T) {
return func(t *testing.T) {
tg = testgo(t)
defer tg.cleanup()
tg.run("test", "./testdata/src/testlist/...", fmt.Sprintf("-list=%s", listName))
tg.grepStdout(expected, fmt.Sprintf("-test.list=%s returned %q, expected %s", listName, tg.getStdout(), expected))
}
}
t.Run("Test", testWith("Test", "TestSimple"))
t.Run("Bench", testWith("Benchmark", "BenchmarkSimple"))
t.Run("Example1", testWith("Example", "ExampleSimple"))
t.Run("Example2", testWith("Example", "ExampleWithEmptyOutput"))
}

View File

@@ -439,6 +439,11 @@ func downloadPackage(p *load.Package) error {
p.Internal.Build.PkgRoot = filepath.Join(list[0], "pkg")
}
root := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath))
if err := checkNestedVCS(vcs, root, p.Internal.Build.SrcRoot); err != nil {
return err
}
// If we've considered this repository already, don't do it again.
if downloadRootCache[root] {
return nil

View File

@@ -506,11 +506,28 @@ func vcsFromDir(dir, srcRoot string) (vcs *vcsCmd, root string, err error) {
return nil, "", fmt.Errorf("directory %q is outside source root %q", dir, srcRoot)
}
var vcsRet *vcsCmd
var rootRet string
origDir := dir
for len(dir) > len(srcRoot) {
for _, vcs := range vcsList {
if _, err := os.Stat(filepath.Join(dir, "."+vcs.cmd)); err == nil {
return vcs, filepath.ToSlash(dir[len(srcRoot)+1:]), nil
root := filepath.ToSlash(dir[len(srcRoot)+1:])
// Record first VCS we find, but keep looking,
// to detect mistakes like one kind of VCS inside another.
if vcsRet == nil {
vcsRet = vcs
rootRet = root
continue
}
// Allow .git inside .git, which can arise due to submodules.
if vcsRet == vcs && vcs.cmd == "git" {
continue
}
// Otherwise, we have one VCS inside a different VCS.
return nil, "", fmt.Errorf("directory %q uses %s, but parent %q uses %s",
filepath.Join(srcRoot, rootRet), vcsRet.cmd, filepath.Join(srcRoot, root), vcs.cmd)
}
}
@@ -523,9 +540,48 @@ func vcsFromDir(dir, srcRoot string) (vcs *vcsCmd, root string, err error) {
dir = ndir
}
if vcsRet != nil {
return vcsRet, rootRet, nil
}
return nil, "", fmt.Errorf("directory %q is not using a known version control system", origDir)
}
// checkNestedVCS checks for an incorrectly-nested VCS-inside-VCS
// situation for dir, checking parents up until srcRoot.
func checkNestedVCS(vcs *vcsCmd, dir, srcRoot string) error {
if len(dir) <= len(srcRoot) || dir[len(srcRoot)] != filepath.Separator {
return fmt.Errorf("directory %q is outside source root %q", dir, srcRoot)
}
otherDir := dir
for len(otherDir) > len(srcRoot) {
for _, otherVCS := range vcsList {
if _, err := os.Stat(filepath.Join(dir, "."+otherVCS.cmd)); err == nil {
// Allow expected vcs in original dir.
if otherDir == dir && otherVCS == vcs {
continue
}
// Allow .git inside .git, which can arise due to submodules.
if otherVCS == vcs && vcs.cmd == "git" {
continue
}
// Otherwise, we have one VCS inside a different VCS.
return fmt.Errorf("directory %q uses %s, but parent %q uses %s", dir, vcs.cmd, otherDir, otherVCS.cmd)
}
}
// Move to parent.
newDir := filepath.Dir(otherDir)
if len(newDir) >= len(otherDir) {
// Shouldn't happen, but just in case, stop.
break
}
otherDir = newDir
}
return nil
}
// repoRoot represents a version control system, a repo, and a root of
// where to put it on disk.
type repoRoot struct {

View File

@@ -0,0 +1,14 @@
package testlist
import (
"fmt"
"testing"
)
func BenchmarkSimplefunc(b *testing.B) {
b.StopTimer()
b.StartTimer()
for i := 0; i < b.N; i++ {
_ = fmt.Sprint("Test for bench")
}
}

View File

@@ -0,0 +1,21 @@
package testlist
import (
"fmt"
)
func ExampleSimple() {
fmt.Println("Test with Output.")
// Output: Test with Output.
}
func ExampleWithEmptyOutput() {
fmt.Println("")
// Output:
}
func ExampleNoOutput() {
_ = fmt.Sprint("Test with no output")
}

View File

@@ -0,0 +1,10 @@
package testlist
import (
"fmt"
"testing"
)
func TestSimple(t *testing.T) {
_ = fmt.Sprint("Test simple")
}

View File

@@ -15,9 +15,6 @@ import (
// InfoPrefix is the prefix for all the symbols containing DWARF info entries.
const InfoPrefix = "go.info."
// RangePrefix is the prefix for all the symbols containing DWARF location lists.
const LocPrefix = "go.loc."
// RangePrefix is the prefix for all the symbols containing DWARF range lists.
const RangePrefix = "go.range."
@@ -26,31 +23,13 @@ type Sym interface {
Len() int64
}
// A Location represents a variable's location at a particular PC range.
// It becomes a location list entry in the DWARF.
type Location struct {
StartPC, EndPC int64
Pieces []Piece
}
// A Piece represents the location of a particular part of a variable.
// It becomes part of a location list entry (a DW_OP_piece) in the DWARF.
type Piece struct {
Length int64
StackOffset int32
RegNum int16
Missing bool
OnStack bool // if true, RegNum is unset.
}
// A Var represents a local variable or a function parameter.
type Var struct {
Name string
Abbrev int // Either DW_ABRV_AUTO or DW_ABRV_PARAM
StackOffset int32
LocationList []Location
Scope int32
Type Sym
Name string
Abbrev int // Either DW_ABRV_AUTO or DW_ABRV_PARAM
Offset int32
Scope int32
Type Sym
}
// A Scope represents a lexical scope. All variables declared within a
@@ -226,7 +205,7 @@ const (
)
// Index into the abbrevs table below.
// Keep in sync with ispubname() and ispubtype() in ld/dwarf.go.
// Keep in sync with ispubname() and ispubtype() below.
// ispubtype considers >= NULLTYPE public
const (
DW_ABRV_NULL = iota
@@ -234,9 +213,7 @@ const (
DW_ABRV_FUNCTION
DW_ABRV_VARIABLE
DW_ABRV_AUTO
DW_ABRV_AUTO_LOCLIST
DW_ABRV_PARAM
DW_ABRV_PARAM_LOCLIST
DW_ABRV_LEXICAL_BLOCK_RANGES
DW_ABRV_LEXICAL_BLOCK_SIMPLE
DW_ABRV_STRUCTFIELD
@@ -320,17 +297,6 @@ var abbrevs = [DW_NABRV]dwAbbrev{
},
},
/* AUTO_LOCLIST */
{
DW_TAG_variable,
DW_CHILDREN_no,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_location, DW_FORM_sec_offset},
{DW_AT_type, DW_FORM_ref_addr},
},
},
/* PARAM */
{
DW_TAG_formal_parameter,
@@ -341,18 +307,6 @@ var abbrevs = [DW_NABRV]dwAbbrev{
{DW_AT_type, DW_FORM_ref_addr},
},
},
/* PARAM_LOCLIST */
{
DW_TAG_formal_parameter,
DW_CHILDREN_no,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_location, DW_FORM_sec_offset},
{DW_AT_type, DW_FORM_ref_addr},
},
},
/* LEXICAL_BLOCK_RANGES */
{
DW_TAG_lexical_block,
@@ -730,30 +684,31 @@ func HasChildren(die *DWDie) bool {
// PutFunc writes a DIE for a function to s.
// It also writes child DIEs for each variable in vars.
func PutFunc(ctxt Context, info, loc, ranges Sym, name string, external bool, startPC Sym, size int64, scopes []Scope) error {
Uleb128put(ctxt, info, DW_ABRV_FUNCTION)
putattr(ctxt, info, DW_ABRV_FUNCTION, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name)
putattr(ctxt, info, DW_ABRV_FUNCTION, DW_FORM_addr, DW_CLS_ADDRESS, 0, startPC)
putattr(ctxt, info, DW_ABRV_FUNCTION, DW_FORM_addr, DW_CLS_ADDRESS, size, startPC)
putattr(ctxt, info, DW_ABRV_FUNCTION, DW_FORM_block1, DW_CLS_BLOCK, 1, []byte{DW_OP_call_frame_cfa})
func PutFunc(ctxt Context, s, ranges Sym, name string, external bool, startPC Sym, size int64, scopes []Scope) error {
Uleb128put(ctxt, s, DW_ABRV_FUNCTION)
putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name)
putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_addr, DW_CLS_ADDRESS, 0, startPC)
putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_addr, DW_CLS_ADDRESS, size, startPC)
putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_block1, DW_CLS_BLOCK, 1, []byte{DW_OP_call_frame_cfa})
var ev int64
if external {
ev = 1
}
putattr(ctxt, info, DW_ABRV_FUNCTION, DW_FORM_flag, DW_CLS_FLAG, ev, 0)
putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_flag, DW_CLS_FLAG, ev, 0)
if len(scopes) > 0 {
var encbuf [20]byte
if putscope(ctxt, info, loc, ranges, startPC, 0, scopes, encbuf[:0]) < int32(len(scopes)) {
if putscope(ctxt, s, ranges, startPC, 0, scopes, encbuf[:0]) < int32(len(scopes)) {
return errors.New("multiple toplevel scopes")
}
}
Uleb128put(ctxt, info, 0)
Uleb128put(ctxt, s, 0)
return nil
}
func putscope(ctxt Context, info, loc, ranges, startPC Sym, curscope int32, scopes []Scope, encbuf []byte) int32 {
func putscope(ctxt Context, s, ranges Sym, startPC Sym, curscope int32, scopes []Scope, encbuf []byte) int32 {
for _, v := range scopes[curscope].Vars {
putvar(ctxt, info, loc, v, startPC, encbuf)
putvar(ctxt, s, v, encbuf)
}
this := curscope
curscope++
@@ -764,12 +719,12 @@ func putscope(ctxt Context, info, loc, ranges, startPC Sym, curscope int32, scop
}
if len(scope.Ranges) == 1 {
Uleb128put(ctxt, info, DW_ABRV_LEXICAL_BLOCK_SIMPLE)
putattr(ctxt, info, DW_ABRV_LEXICAL_BLOCK_SIMPLE, DW_FORM_addr, DW_CLS_ADDRESS, scope.Ranges[0].Start, startPC)
putattr(ctxt, info, DW_ABRV_LEXICAL_BLOCK_SIMPLE, DW_FORM_addr, DW_CLS_ADDRESS, scope.Ranges[0].End, startPC)
Uleb128put(ctxt, s, DW_ABRV_LEXICAL_BLOCK_SIMPLE)
putattr(ctxt, s, DW_ABRV_LEXICAL_BLOCK_SIMPLE, DW_FORM_addr, DW_CLS_ADDRESS, scope.Ranges[0].Start, startPC)
putattr(ctxt, s, DW_ABRV_LEXICAL_BLOCK_SIMPLE, DW_FORM_addr, DW_CLS_ADDRESS, scope.Ranges[0].End, startPC)
} else {
Uleb128put(ctxt, info, DW_ABRV_LEXICAL_BLOCK_RANGES)
putattr(ctxt, info, DW_ABRV_LEXICAL_BLOCK_RANGES, DW_FORM_sec_offset, DW_CLS_PTR, ranges.Len(), ranges)
Uleb128put(ctxt, s, DW_ABRV_LEXICAL_BLOCK_RANGES)
putattr(ctxt, s, DW_ABRV_LEXICAL_BLOCK_RANGES, DW_FORM_sec_offset, DW_CLS_PTR, ranges.Len(), ranges)
ctxt.AddAddress(ranges, nil, -1)
ctxt.AddAddress(ranges, startPC, 0)
@@ -781,72 +736,32 @@ func putscope(ctxt Context, info, loc, ranges, startPC Sym, curscope int32, scop
ctxt.AddAddress(ranges, nil, 0)
}
curscope = putscope(ctxt, info, loc, ranges, startPC, curscope, scopes, encbuf)
curscope = putscope(ctxt, s, ranges, startPC, curscope, scopes, encbuf)
Uleb128put(ctxt, info, 0)
Uleb128put(ctxt, s, 0)
}
return curscope
}
func putvar(ctxt Context, info, loc Sym, v *Var, startPC Sym, encbuf []byte) {
func putvar(ctxt Context, s Sym, v *Var, encbuf []byte) {
n := v.Name
Uleb128put(ctxt, info, int64(v.Abbrev))
putattr(ctxt, info, v.Abbrev, DW_FORM_string, DW_CLS_STRING, int64(len(n)), n)
if v.Abbrev == DW_ABRV_AUTO_LOCLIST || v.Abbrev == DW_ABRV_PARAM_LOCLIST {
putattr(ctxt, info, v.Abbrev, DW_FORM_sec_offset, DW_CLS_PTR, int64(loc.Len()), loc)
addLocList(ctxt, loc, startPC, v, encbuf)
} else {
loc := append(encbuf[:0], DW_OP_call_frame_cfa)
if v.StackOffset != 0 {
loc = append(loc, DW_OP_consts)
loc = AppendSleb128(loc, int64(v.StackOffset))
loc = append(loc, DW_OP_plus)
}
putattr(ctxt, info, v.Abbrev, DW_FORM_block1, DW_CLS_BLOCK, int64(len(loc)), loc)
Uleb128put(ctxt, s, int64(v.Abbrev))
putattr(ctxt, s, v.Abbrev, DW_FORM_string, DW_CLS_STRING, int64(len(n)), n)
loc := append(encbuf[:0], DW_OP_call_frame_cfa)
if v.Offset != 0 {
loc = append(loc, DW_OP_consts)
loc = AppendSleb128(loc, int64(v.Offset))
loc = append(loc, DW_OP_plus)
}
putattr(ctxt, info, v.Abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, v.Type)
}
func addLocList(ctxt Context, listSym, startPC Sym, v *Var, encbuf []byte) {
// Base address entry: max ptr followed by the base address.
ctxt.AddInt(listSym, ctxt.PtrSize(), ^0)
ctxt.AddAddress(listSym, startPC, 0)
for _, entry := range v.LocationList {
ctxt.AddInt(listSym, ctxt.PtrSize(), entry.StartPC)
ctxt.AddInt(listSym, ctxt.PtrSize(), entry.EndPC)
locBuf := encbuf[:0]
for _, piece := range entry.Pieces {
if !piece.Missing {
if piece.OnStack {
locBuf = append(locBuf, DW_OP_fbreg)
locBuf = AppendSleb128(locBuf, int64(piece.StackOffset))
} else {
if piece.RegNum < 32 {
locBuf = append(locBuf, DW_OP_reg0+byte(piece.RegNum))
} else {
locBuf = append(locBuf, DW_OP_regx)
locBuf = AppendUleb128(locBuf, uint64(piece.RegNum))
}
}
}
if len(entry.Pieces) > 1 {
locBuf = append(locBuf, DW_OP_piece)
locBuf = AppendUleb128(locBuf, uint64(piece.Length))
}
}
ctxt.AddInt(listSym, 2, int64(len(locBuf)))
ctxt.AddBytes(listSym, locBuf)
}
// End list
ctxt.AddInt(listSym, ctxt.PtrSize(), 0)
ctxt.AddInt(listSym, ctxt.PtrSize(), 0)
putattr(ctxt, s, v.Abbrev, DW_FORM_block1, DW_CLS_BLOCK, int64(len(loc)), loc)
putattr(ctxt, s, v.Abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, v.Type)
}
// VarsByOffset attaches the methods of sort.Interface to []*Var,
// sorting in increasing StackOffset.
// sorting in increasing Offset.
type VarsByOffset []*Var
func (s VarsByOffset) Len() int { return len(s) }
func (s VarsByOffset) Less(i, j int) bool { return s[i].StackOffset < s[j].StackOffset }
func (s VarsByOffset) Less(i, j int) bool { return s[i].Offset < s[j].Offset }
func (s VarsByOffset) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

View File

@@ -1167,6 +1167,11 @@ func (c *ctxt5) aclass(a *obj.Addr) int {
return C_ADDR
case obj.NAME_AUTO:
if a.Reg == REGSP {
// unset base register for better printing, since
// a.Offset is still relative to pseudo-SP.
a.Reg = obj.REG_NONE
}
c.instoffset = c.autosize + a.Offset
if t := immaddr(int32(c.instoffset)); t != 0 {
if immhalf(int32(c.instoffset)) {
@@ -1185,6 +1190,11 @@ func (c *ctxt5) aclass(a *obj.Addr) int {
return C_LAUTO
case obj.NAME_PARAM:
if a.Reg == REGSP {
// unset base register for better printing, since
// a.Offset is still relative to pseudo-FP.
a.Reg = obj.REG_NONE
}
c.instoffset = c.autosize + a.Offset + 4
if t := immaddr(int32(c.instoffset)); t != 0 {
if immhalf(int32(c.instoffset)) {
@@ -1285,10 +1295,20 @@ func (c *ctxt5) aclass(a *obj.Addr) int {
return C_LCONADDR
case obj.NAME_AUTO:
if a.Reg == REGSP {
// unset base register for better printing, since
// a.Offset is still relative to pseudo-SP.
a.Reg = obj.REG_NONE
}
c.instoffset = c.autosize + a.Offset
return c.aconsize()
case obj.NAME_PARAM:
if a.Reg == REGSP {
// unset base register for better printing, since
// a.Offset is still relative to pseudo-FP.
a.Reg = obj.REG_NONE
}
c.instoffset = c.autosize + a.Offset + 4
return c.aconsize()
}

View File

@@ -1149,10 +1149,20 @@ func (c *ctxt7) aclass(a *obj.Addr) int {
return C_GOTADDR
case obj.NAME_AUTO:
if a.Reg == REGSP {
// unset base register for better printing, since
// a.Offset is still relative to pseudo-SP.
a.Reg = obj.REG_NONE
}
c.instoffset = int64(c.autosize) + a.Offset
return autoclass(c.instoffset)
case obj.NAME_PARAM:
if a.Reg == REGSP {
// unset base register for better printing, since
// a.Offset is still relative to pseudo-FP.
a.Reg = obj.REG_NONE
}
c.instoffset = int64(c.autosize) + a.Offset + 8
return autoclass(c.instoffset)
@@ -1228,10 +1238,20 @@ func (c *ctxt7) aclass(a *obj.Addr) int {
return C_VCONADDR
case obj.NAME_AUTO:
if a.Reg == REGSP {
// unset base register for better printing, since
// a.Offset is still relative to pseudo-SP.
a.Reg = obj.REG_NONE
}
c.instoffset = int64(c.autosize) + a.Offset
goto aconsize
case obj.NAME_PARAM:
if a.Reg == REGSP {
// unset base register for better printing, since
// a.Offset is still relative to pseudo-FP.
a.Reg = obj.REG_NONE
}
c.instoffset = int64(c.autosize) + a.Offset + 8
goto aconsize
}

View File

@@ -330,8 +330,7 @@ type FuncInfo struct {
Autom []*Auto
Pcln Pcln
dwarfInfoSym *LSym
dwarfLocSym *LSym
dwarfSym *LSym
dwarfRangesSym *LSym
GCArgs LSym
@@ -477,26 +476,25 @@ type Pcdata struct {
// 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 {
Headtype objabi.HeadType
Arch *LinkArch
Debugasm bool
Debugvlog bool
Debugpcln string
Flag_shared bool
Flag_dynlink bool
Flag_optimize bool
Flag_locationlists bool
Bso *bufio.Writer
Pathname string
hashmu sync.Mutex // protects hash
hash map[string]*LSym // name -> sym mapping
statichash map[string]*LSym // name -> sym mapping for static syms
PosTable src.PosTable
InlTree InlTree // global inlining tree used by gc/inl.go
Imports []string
DiagFunc func(string, ...interface{})
DebugInfo func(fn *LSym, curfn interface{}) []dwarf.Scope // if non-nil, curfn is a *gc.Node
Errors int
Headtype objabi.HeadType
Arch *LinkArch
Debugasm bool
Debugvlog bool
Debugpcln string
Flag_shared bool
Flag_dynlink bool
Flag_optimize bool
Bso *bufio.Writer
Pathname string
hashmu sync.Mutex // protects hash
hash map[string]*LSym // name -> sym mapping
statichash map[string]*LSym // name -> sym mapping for static syms
PosTable src.PosTable
InlTree InlTree // global inlining tree used by gc/inl.go
Imports []string
DiagFunc func(string, ...interface{})
DebugInfo func(fn *LSym, curfn interface{}) []dwarf.Scope // if non-nil, curfn is a *gc.Node
Errors int
Framepointer_enabled bool
@@ -535,10 +533,9 @@ func (ctxt *Link) FixedFrameSize() int64 {
// LinkArch is the definition of a single architecture.
type LinkArch struct {
*sys.Arch
Init func(*Link)
Preprocess func(*Link, *LSym, ProgAlloc)
Assemble func(*Link, *LSym, ProgAlloc)
Progedit func(*Link, *Prog, ProgAlloc)
UnaryDst map[As]bool // Instruction takes one operand, a destination.
DWARFRegisters map[int16]int16
Init func(*Link)
Preprocess func(*Link, *LSym, ProgAlloc)
Assemble func(*Link, *LSym, ProgAlloc)
Progedit func(*Link, *Prog, ProgAlloc)
UnaryDst map[As]bool // Instruction takes one operand, a destination.
}

View File

@@ -556,6 +556,11 @@ func (c *ctxt0) aclass(a *obj.Addr) int {
return C_LEXT
case obj.NAME_AUTO:
if a.Reg == REGSP {
// unset base register for better printing, since
// a.Offset is still relative to pseudo-SP.
a.Reg = obj.REG_NONE
}
c.instoffset = int64(c.autosize) + a.Offset
if c.instoffset >= -BIG && c.instoffset < BIG {
return C_SAUTO
@@ -563,6 +568,11 @@ func (c *ctxt0) aclass(a *obj.Addr) int {
return C_LAUTO
case obj.NAME_PARAM:
if a.Reg == REGSP {
// unset base register for better printing, since
// a.Offset is still relative to pseudo-FP.
a.Reg = obj.REG_NONE
}
c.instoffset = int64(c.autosize) + a.Offset + c.ctxt.FixedFrameSize()
if c.instoffset >= -BIG && c.instoffset < BIG {
return C_SAUTO
@@ -616,6 +626,11 @@ func (c *ctxt0) aclass(a *obj.Addr) int {
return C_LECON
case obj.NAME_AUTO:
if a.Reg == REGSP {
// unset base register for better printing, since
// a.Offset is still relative to pseudo-SP.
a.Reg = obj.REG_NONE
}
c.instoffset = int64(c.autosize) + a.Offset
if c.instoffset >= -BIG && c.instoffset < BIG {
return C_SACON
@@ -623,6 +638,11 @@ func (c *ctxt0) aclass(a *obj.Addr) int {
return C_LACON
case obj.NAME_PARAM:
if a.Reg == REGSP {
// unset base register for better printing, since
// a.Offset is still relative to pseudo-FP.
a.Reg = obj.REG_NONE
}
c.instoffset = int64(c.autosize) + a.Offset + c.ctxt.FixedFrameSize()
if c.instoffset >= -BIG && c.instoffset < BIG {
return C_SACON

View File

@@ -465,18 +465,15 @@ func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64
}
// dwarfSym returns the DWARF symbols for TEXT symbol.
func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym *LSym) {
func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfRangesSym *LSym) {
if s.Type != objabi.STEXT {
ctxt.Diag("dwarfSym of non-TEXT %v", s)
}
if s.Func.dwarfInfoSym == nil {
s.Func.dwarfInfoSym = ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name)
if ctxt.Flag_locationlists {
s.Func.dwarfLocSym = ctxt.LookupDerived(s, dwarf.LocPrefix+s.Name)
}
if s.Func.dwarfSym == nil {
s.Func.dwarfSym = ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name)
s.Func.dwarfRangesSym = ctxt.LookupDerived(s, dwarf.RangePrefix+s.Name)
}
return s.Func.dwarfInfoSym, s.Func.dwarfLocSym, s.Func.dwarfRangesSym
return s.Func.dwarfSym, s.Func.dwarfRangesSym
}
func (s *LSym) Len() int64 {
@@ -486,15 +483,15 @@ func (s *LSym) Len() int64 {
// populateDWARF fills in the DWARF Debugging Information Entries for TEXT symbol s.
// The DWARFs symbol must already have been initialized in InitTextSym.
func (ctxt *Link) populateDWARF(curfn interface{}, s *LSym) {
info, loc, ranges := ctxt.dwarfSym(s)
if info.Size != 0 {
dsym, drsym := ctxt.dwarfSym(s)
if dsym.Size != 0 {
ctxt.Diag("makeFuncDebugEntry double process %v", s)
}
var scopes []dwarf.Scope
if ctxt.DebugInfo != nil {
scopes = ctxt.DebugInfo(s, curfn)
}
err := dwarf.PutFunc(dwCtxt{ctxt}, info, loc, ranges, s.Name, !s.Static(), s, s.Size, scopes)
err := dwarf.PutFunc(dwCtxt{ctxt}, dsym, drsym, s.Name, !s.Static(), s, s.Size, scopes)
if err != nil {
ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
}

View File

@@ -136,17 +136,13 @@ func (ctxt *Link) InitTextSym(s *LSym, flag int) {
ctxt.Text = append(ctxt.Text, s)
// Set up DWARF entries for s.
info, loc, ranges := ctxt.dwarfSym(s)
info.Type = objabi.SDWARFINFO
info.Set(AttrDuplicateOK, s.DuplicateOK())
if loc != nil {
loc.Type = objabi.SDWARFLOC
loc.Set(AttrDuplicateOK, s.DuplicateOK())
ctxt.Data = append(ctxt.Data, loc)
}
ranges.Type = objabi.SDWARFRANGE
ranges.Set(AttrDuplicateOK, s.DuplicateOK())
ctxt.Data = append(ctxt.Data, info, ranges)
dsym, drsym := ctxt.dwarfSym(s)
dsym.Type = objabi.SDWARFINFO
dsym.Set(AttrDuplicateOK, s.DuplicateOK())
drsym.Type = objabi.SDWARFRANGE
drsym.Set(AttrDuplicateOK, s.DuplicateOK())
ctxt.Data = append(ctxt.Data, dsym)
ctxt.Data = append(ctxt.Data, drsym)
// Set up the function's gcargs and gclocals.
// They will be filled in later if needed.

View File

@@ -758,6 +758,11 @@ func (c *ctxt9) aclass(a *obj.Addr) int {
return C_GOTADDR
case obj.NAME_AUTO:
if a.Reg == REGSP {
// unset base register for better printing, since
// a.Offset is still relative to pseudo-SP.
a.Reg = obj.REG_NONE
}
c.instoffset = int64(c.autosize) + a.Offset
if c.instoffset >= -BIG && c.instoffset < BIG {
return C_SAUTO
@@ -765,6 +770,11 @@ func (c *ctxt9) aclass(a *obj.Addr) int {
return C_LAUTO
case obj.NAME_PARAM:
if a.Reg == REGSP {
// unset base register for better printing, since
// a.Offset is still relative to pseudo-FP.
a.Reg = obj.REG_NONE
}
c.instoffset = int64(c.autosize) + a.Offset + c.ctxt.FixedFrameSize()
if c.instoffset >= -BIG && c.instoffset < BIG {
return C_SAUTO
@@ -817,6 +827,11 @@ func (c *ctxt9) aclass(a *obj.Addr) int {
return C_LCON
case obj.NAME_AUTO:
if a.Reg == REGSP {
// unset base register for better printing, since
// a.Offset is still relative to pseudo-SP.
a.Reg = obj.REG_NONE
}
c.instoffset = int64(c.autosize) + a.Offset
if c.instoffset >= -BIG && c.instoffset < BIG {
return C_SACON
@@ -824,6 +839,11 @@ func (c *ctxt9) aclass(a *obj.Addr) int {
return C_LACON
case obj.NAME_PARAM:
if a.Reg == REGSP {
// unset base register for better printing, since
// a.Offset is still relative to pseudo-FP.
a.Reg = obj.REG_NONE
}
c.instoffset = int64(c.autosize) + a.Offset + c.ctxt.FixedFrameSize()
if c.instoffset >= -BIG && c.instoffset < BIG {
return C_SACON

View File

@@ -505,6 +505,11 @@ func (c *ctxtz) aclass(a *obj.Addr) int {
return C_GOTADDR
case obj.NAME_AUTO:
if a.Reg == REGSP {
// unset base register for better printing, since
// a.Offset is still relative to pseudo-SP.
a.Reg = obj.REG_NONE
}
c.instoffset = int64(c.autosize) + a.Offset
if c.instoffset >= -BIG && c.instoffset < BIG {
return C_SAUTO
@@ -512,6 +517,11 @@ func (c *ctxtz) aclass(a *obj.Addr) int {
return C_LAUTO
case obj.NAME_PARAM:
if a.Reg == REGSP {
// unset base register for better printing, since
// a.Offset is still relative to pseudo-FP.
a.Reg = obj.REG_NONE
}
c.instoffset = int64(c.autosize) + a.Offset + c.ctxt.FixedFrameSize()
if c.instoffset >= -BIG && c.instoffset < BIG {
return C_SAUTO
@@ -567,6 +577,11 @@ func (c *ctxtz) aclass(a *obj.Addr) int {
return C_SYMADDR
case obj.NAME_AUTO:
if a.Reg == REGSP {
// unset base register for better printing, since
// a.Offset is still relative to pseudo-SP.
a.Reg = obj.REG_NONE
}
c.instoffset = int64(c.autosize) + a.Offset
if c.instoffset >= -BIG && c.instoffset < BIG {
return C_SACON
@@ -574,6 +589,11 @@ func (c *ctxtz) aclass(a *obj.Addr) int {
return C_LACON
case obj.NAME_PARAM:
if a.Reg == REGSP {
// unset base register for better printing, since
// a.Offset is still relative to pseudo-FP.
a.Reg = obj.REG_NONE
}
c.instoffset = int64(c.autosize) + a.Offset + c.ctxt.FixedFrameSize()
if c.instoffset >= -BIG && c.instoffset < BIG {
return C_SACON

View File

@@ -1006,120 +1006,3 @@ const (
T_64 = 1 << 6
T_GOTYPE = 1 << 7
)
// https://www.uclibc.org/docs/psABI-x86_64.pdf, figure 3.36
var AMD64DWARFRegisters = map[int16]int16{
REG_AX: 0,
REG_DX: 1,
REG_CX: 2,
REG_BX: 3,
REG_SI: 4,
REG_DI: 5,
REG_BP: 6,
REG_SP: 7,
REG_R8: 8,
REG_R9: 9,
REG_R10: 10,
REG_R11: 11,
REG_R12: 12,
REG_R13: 13,
REG_R14: 14,
REG_R15: 15,
// 16 is "Return Address RA", whatever that is.
// XMM registers. %xmmN => XN.
REG_X0: 17,
REG_X1: 18,
REG_X2: 19,
REG_X3: 20,
REG_X4: 21,
REG_X5: 22,
REG_X6: 23,
REG_X7: 24,
REG_X8: 25,
REG_X9: 26,
REG_X10: 27,
REG_X11: 28,
REG_X12: 29,
REG_X13: 30,
REG_X14: 31,
REG_X15: 32,
// ST registers. %stN => FN.
REG_F0: 33,
REG_F1: 34,
REG_F2: 35,
REG_F3: 36,
REG_F4: 37,
REG_F5: 38,
REG_F6: 39,
REG_F7: 40,
// MMX registers. %mmN => MN.
REG_M0: 41,
REG_M1: 42,
REG_M2: 43,
REG_M3: 44,
REG_M4: 45,
REG_M5: 46,
REG_M6: 47,
REG_M7: 48,
// 48 is flags, which doesn't have a name.
REG_ES: 50,
REG_CS: 51,
REG_SS: 52,
REG_DS: 53,
REG_FS: 54,
REG_GS: 55,
// 58 and 59 are {fs,gs}base, which don't have names.
REG_TR: 62,
REG_LDTR: 63,
// 64-66 are mxcsr, fcw, fsw, which don't have names.
}
// https://www.uclibc.org/docs/psABI-i386.pdf, table 2.14
var X86DWARFRegisters = map[int16]int16{
REG_AX: 0,
REG_CX: 1,
REG_DX: 2,
REG_BX: 3,
REG_SP: 4,
REG_BP: 5,
REG_SI: 6,
REG_DI: 7,
// 8 is "Return Address RA", whatever that is.
// 9 is flags, which doesn't have a name.
// ST registers. %stN => FN.
REG_F0: 11,
REG_F1: 12,
REG_F2: 13,
REG_F3: 14,
REG_F4: 15,
REG_F5: 16,
REG_F6: 17,
REG_F7: 18,
// XMM registers. %xmmN => XN.
REG_X0: 21,
REG_X1: 22,
REG_X2: 23,
REG_X3: 24,
REG_X4: 25,
REG_X5: 26,
REG_X6: 27,
REG_X7: 28,
// MMX registers. %mmN => MN.
REG_M0: 29,
REG_M1: 30,
REG_M2: 31,
REG_M3: 32,
REG_M4: 33,
REG_M5: 34,
REG_M6: 35,
REG_M7: 36,
// 39 is mxcsr, which doesn't have a name.
REG_ES: 40,
REG_CS: 41,
REG_SS: 42,
REG_DS: 43,
REG_FS: 44,
REG_GS: 45,
REG_TR: 48,
REG_LDTR: 49,
}

View File

@@ -1231,31 +1231,28 @@ var unaryDst = map[obj.As]bool{
}
var Linkamd64 = obj.LinkArch{
Arch: sys.ArchAMD64,
Init: instinit,
Preprocess: preprocess,
Assemble: span6,
Progedit: progedit,
UnaryDst: unaryDst,
DWARFRegisters: AMD64DWARFRegisters,
Arch: sys.ArchAMD64,
Init: instinit,
Preprocess: preprocess,
Assemble: span6,
Progedit: progedit,
UnaryDst: unaryDst,
}
var Linkamd64p32 = obj.LinkArch{
Arch: sys.ArchAMD64P32,
Init: instinit,
Preprocess: preprocess,
Assemble: span6,
Progedit: progedit,
UnaryDst: unaryDst,
DWARFRegisters: AMD64DWARFRegisters,
Arch: sys.ArchAMD64P32,
Init: instinit,
Preprocess: preprocess,
Assemble: span6,
Progedit: progedit,
UnaryDst: unaryDst,
}
var Link386 = obj.LinkArch{
Arch: sys.Arch386,
Init: instinit,
Preprocess: preprocess,
Assemble: span6,
Progedit: progedit,
UnaryDst: unaryDst,
DWARFRegisters: AMD64DWARFRegisters,
Arch: sys.Arch386,
Init: instinit,
Preprocess: preprocess,
Assemble: span6,
Progedit: progedit,
UnaryDst: unaryDst,
}

View File

@@ -57,5 +57,4 @@ const (
// Debugging data
SDWARFINFO
SDWARFRANGE
SDWARFLOC
)

View File

@@ -4,9 +4,9 @@ package objabi
import "fmt"
const _SymKind_name = "SxxxSTEXTSRODATASNOPTRDATASDATASBSSSNOPTRBSSSTLSBSSSDWARFINFOSDWARFRANGESDWARFLOC"
const _SymKind_name = "SxxxSTEXTSRODATASNOPTRDATASDATASBSSSNOPTRBSSSTLSBSSSDWARFINFOSDWARFRANGE"
var _SymKind_index = [...]uint8{0, 4, 9, 16, 26, 31, 35, 44, 51, 61, 72, 81}
var _SymKind_index = [...]uint8{0, 4, 9, 16, 26, 31, 35, 44, 51, 61, 72}
func (i SymKind) String() string {
if i >= SymKind(len(_SymKind_index)-1) {

View File

@@ -592,7 +592,15 @@ func relocsym(ctxt *Link, s *Symbol) {
}
case objabi.R_DWARFREF:
if r.Sym.Sect == nil {
var sectName string
var vaddr int64
switch {
case r.Sym.Sect != nil:
sectName = r.Sym.Sect.Name
vaddr = int64(r.Sym.Sect.Vaddr)
case r.Sym.Type == SDWARFRANGE:
sectName = ".debug_ranges"
default:
Errorf(s, "missing DWARF section for relocation target %s", r.Sym.Name)
}
@@ -607,8 +615,8 @@ func relocsym(ctxt *Link, s *Symbol) {
r.Type = objabi.R_ADDR
}
r.Xsym = ctxt.Syms.ROLookup(r.Sym.Sect.Name, 0)
r.Xadd = r.Add + Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr)
r.Xsym = ctxt.Syms.ROLookup(sectName, 0)
r.Xadd = r.Add + Symaddr(r.Sym) - vaddr
o = r.Xadd
rs = r.Xsym
@@ -617,7 +625,7 @@ func relocsym(ctxt *Link, s *Symbol) {
}
break
}
o = Symaddr(r.Sym) + r.Add - int64(r.Sym.Sect.Vaddr)
o = Symaddr(r.Sym) + r.Add - vaddr
case objabi.R_WEAKADDROFF:
if !r.Sym.Attr.Reachable() {
@@ -1835,9 +1843,9 @@ func (ctxt *Link) dodata() {
dwarfgeneratedebugsyms(ctxt)
var s *Symbol
var i int
for ; i < len(dwarfp); i++ {
s := dwarfp[i]
for i, s = range dwarfp {
if s.Type != SDWARFSECT {
break
}
@@ -1854,26 +1862,13 @@ func (ctxt *Link) dodata() {
}
checkdatsize(ctxt, datsize, SDWARFSECT)
for i < len(dwarfp) {
curType := dwarfp[i].Type
var sect *Section
switch curType {
case SDWARFINFO:
sect = addsection(&Segdwarf, ".debug_info", 04)
case SDWARFRANGE:
sect = addsection(&Segdwarf, ".debug_ranges", 04)
case SDWARFLOC:
sect = addsection(&Segdwarf, ".debug_loc", 04)
default:
Errorf(dwarfp[i], "unknown DWARF section %v", curType)
}
if i < len(dwarfp) {
sect = addsection(&Segdwarf, ".debug_info", 04)
sect.Align = 1
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
for ; i < len(dwarfp); i++ {
s := dwarfp[i]
if s.Type != curType {
for _, s := range dwarfp[i:] {
if s.Type != SDWARFINFO {
break
}
s.Sect = sect
@@ -1883,7 +1878,7 @@ func (ctxt *Link) dodata() {
datsize += s.Size
}
sect.Length = uint64(datsize) - sect.Vaddr
checkdatsize(ctxt, datsize, curType)
checkdatsize(ctxt, datsize, SDWARFINFO)
}
/* number the sections */

View File

@@ -67,15 +67,26 @@ func (c dwctxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64
r.Add = ofs
}
/*
* Offsets and sizes of the debug_* sections in the cout file.
*/
var abbrevsym *Symbol
var arangessec *Symbol
var framesec *Symbol
var infosec *Symbol
var linesec *Symbol
var rangesec *Symbol
var gdbscript string
var dwarfp []*Symbol
func writeabbrev(ctxt *Link) *Symbol {
func writeabbrev(ctxt *Link, syms []*Symbol) []*Symbol {
s := ctxt.Syms.Lookup(".debug_abbrev", 0)
s.Type = SDWARFSECT
abbrevsym = s
Addbytes(s, dwarf.GetAbbrev())
return s
return append(syms, s)
}
/*
@@ -982,10 +993,13 @@ func getCompilationDir() string {
func writelines(ctxt *Link, syms []*Symbol) ([]*Symbol, []*Symbol) {
var dwarfctxt dwarf.Context = dwctxt{ctxt}
ls := ctxt.Syms.Lookup(".debug_line", 0)
ls.Type = SDWARFSECT
ls.R = ls.R[:0]
if linesec == nil {
linesec = ctxt.Syms.Lookup(".debug_line", 0)
}
linesec.Type = SDWARFSECT
linesec.R = linesec.R[:0]
ls := linesec
syms = append(syms, ls)
var funcs []*Symbol
@@ -1005,7 +1019,7 @@ func writelines(ctxt *Link, syms []*Symbol) ([]*Symbol, []*Symbol) {
dwinfo = newdie(ctxt, &dwroot, dwarf.DW_ABRV_COMPUNIT, "go", 0)
newattr(dwinfo, dwarf.DW_AT_language, dwarf.DW_CLS_CONSTANT, int64(lang), 0)
newattr(dwinfo, dwarf.DW_AT_stmt_list, dwarf.DW_CLS_PTR, 0, ls)
newattr(dwinfo, dwarf.DW_AT_stmt_list, dwarf.DW_CLS_PTR, 0, linesec)
newattr(dwinfo, dwarf.DW_AT_low_pc, dwarf.DW_CLS_ADDRESS, s.Value, s)
// OS X linker requires compilation dir or absolute path in comp unit name to output debug info.
compDir := getCompilationDir()
@@ -1164,9 +1178,12 @@ func appendPCDeltaCFA(b []byte, deltapc, cfa int64) []byte {
func writeframes(ctxt *Link, syms []*Symbol) []*Symbol {
var dwarfctxt dwarf.Context = dwctxt{ctxt}
fs := ctxt.Syms.Lookup(".debug_frame", 0)
fs.Type = SDWARFSECT
fs.R = fs.R[:0]
if framesec == nil {
framesec = ctxt.Syms.Lookup(".debug_frame", 0)
}
framesec.Type = SDWARFSECT
framesec.R = framesec.R[:0]
fs := framesec
syms = append(syms, fs)
// Emit the CIE, Section 6.4.1
@@ -1263,7 +1280,7 @@ func writeframes(ctxt *Link, syms []*Symbol) []*Symbol {
// ptrsize: address range
Adduint32(ctxt, fs, uint32(4+2*SysArch.PtrSize+len(deltaBuf))) // length (excludes itself)
if Linkmode == LinkExternal {
adddwarfref(ctxt, fs, fs, 4)
adddwarfref(ctxt, fs, framesec, 4)
} else {
Adduint32(ctxt, fs, 0) // CIE offset
}
@@ -1275,24 +1292,27 @@ func writeframes(ctxt *Link, syms []*Symbol) []*Symbol {
}
func writeranges(ctxt *Link, syms []*Symbol) []*Symbol {
empty := true
if rangesec == nil {
rangesec = ctxt.Syms.Lookup(".debug_ranges", 0)
}
rangesec.Type = SDWARFSECT
rangesec.Attr |= AttrReachable
rangesec.R = rangesec.R[:0]
for _, s := range ctxt.Textp {
rangeSym := ctxt.Syms.Lookup(dwarf.RangePrefix+s.Name, int(s.Version))
if rangeSym.Size == 0 {
continue
}
rangeSym.Attr |= AttrReachable | AttrNotInSymbolTable
rangeSym.Attr |= AttrReachable
rangeSym.Type = SDWARFRANGE
syms = append(syms, rangeSym)
empty = false
rangeSym.Value = rangesec.Size
rangesec.P = append(rangesec.P, rangeSym.P...)
for _, r := range rangeSym.R {
r.Off += int32(rangesec.Size)
rangesec.R = append(rangesec.R, r)
}
rangesec.Size += rangeSym.Size
}
if !empty {
if rangesec.Size > 0 {
// PE does not like empty sections
rangesec := ctxt.Syms.Lookup(".debug_ranges", 0)
rangesec.Type = SDWARFRANGE
rangesec.Attr |= AttrReachable
rangesec.R = rangesec.R[:0]
syms = append(syms, rangesec)
}
return syms
@@ -1305,14 +1325,18 @@ const (
COMPUNITHEADERSIZE = 4 + 2 + 4 + 1
)
func writeinfo(ctxt *Link, syms []*Symbol, funcs []*Symbol, abbrevsym *Symbol) []*Symbol {
infosec := ctxt.Syms.Lookup(".debug_info", 0)
func writeinfo(ctxt *Link, syms []*Symbol, funcs []*Symbol) []*Symbol {
if infosec == nil {
infosec = ctxt.Syms.Lookup(".debug_info", 0)
}
infosec.R = infosec.R[:0]
infosec.Type = SDWARFINFO
infosec.Attr |= AttrReachable
syms = append(syms, infosec)
arangessec := ctxt.Syms.Lookup(".dwarfaranges", 0)
if arangessec == nil {
arangessec = ctxt.Syms.Lookup(".dwarfaranges", 0)
}
arangessec.R = arangessec.R[:0]
var dwarfctxt dwarf.Context = dwctxt{ctxt}
@@ -1553,10 +1577,10 @@ func dwarfgeneratedebugsyms(ctxt *Link) {
genasmsym(ctxt, defdwsymb)
abbrev := writeabbrev(ctxt)
syms := []*Symbol{abbrev}
syms := writeabbrev(ctxt, nil)
syms, funcs := writelines(ctxt, syms)
syms = writeframes(ctxt, syms)
syms = writeranges(ctxt, syms)
synthesizestringtypes(ctxt, dwtypes.Child)
synthesizeslicetypes(ctxt, dwtypes.Child)
@@ -1572,42 +1596,16 @@ func dwarfgeneratedebugsyms(ctxt *Link) {
// Need to reorder symbols so SDWARFINFO is after all SDWARFSECT
// (but we need to generate dies before writepub)
infosyms := writeinfo(ctxt, nil, funcs, abbrev)
infosyms := writeinfo(ctxt, nil, funcs)
syms = writepub(ctxt, ".debug_pubnames", ispubname, syms)
syms = writepub(ctxt, ".debug_pubtypes", ispubtype, syms)
syms = writearanges(ctxt, syms)
syms = writegdbscript(ctxt, syms)
syms = append(syms, infosyms...)
syms = collectlocs(ctxt, syms, funcs)
syms = writeranges(ctxt, syms)
dwarfp = syms
}
func collectlocs(ctxt *Link, syms []*Symbol, funcs []*Symbol) []*Symbol {
empty := true
for _, fn := range funcs {
for _, reloc := range fn.R {
if reloc.Type == objabi.R_DWARFREF && strings.HasPrefix(reloc.Sym.Name, dwarf.LocPrefix) {
reloc.Sym.Attr |= AttrReachable | AttrNotInSymbolTable
syms = append(syms, reloc.Sym)
empty = false
// One location list entry per function, but many relocations to it. Don't duplicate.
break
}
}
}
// Don't emit .debug_loc if it's empty -- it makes the ARM linker mad.
if !empty {
locsym := ctxt.Syms.Lookup(".debug_loc", 0)
locsym.R = locsym.R[:0]
locsym.Type = SDWARFLOC
locsym.Attr |= AttrReachable
syms = append(syms, locsym)
}
return syms
}
/*
* Elf.
*/
@@ -1620,7 +1618,6 @@ func dwarfaddshstrings(ctxt *Link, shstrtab *Symbol) {
Addstring(shstrtab, ".debug_aranges")
Addstring(shstrtab, ".debug_frame")
Addstring(shstrtab, ".debug_info")
Addstring(shstrtab, ".debug_loc")
Addstring(shstrtab, ".debug_line")
Addstring(shstrtab, ".debug_pubnames")
Addstring(shstrtab, ".debug_pubtypes")
@@ -1628,7 +1625,6 @@ func dwarfaddshstrings(ctxt *Link, shstrtab *Symbol) {
Addstring(shstrtab, ".debug_ranges")
if Linkmode == LinkExternal {
Addstring(shstrtab, elfRelType+".debug_info")
Addstring(shstrtab, elfRelType+".debug_loc")
Addstring(shstrtab, elfRelType+".debug_aranges")
Addstring(shstrtab, elfRelType+".debug_line")
Addstring(shstrtab, elfRelType+".debug_frame")
@@ -1655,10 +1651,6 @@ func dwarfaddelfsectionsyms(ctxt *Link) {
putelfsectionsym(sym, sym.Sect.Elfsect.shnum)
sym = ctxt.Syms.Lookup(".debug_frame", 0)
putelfsectionsym(sym, sym.Sect.Elfsect.shnum)
sym = ctxt.Syms.Lookup(".debug_loc", 0)
if sym.Sect != nil {
putelfsectionsym(sym, sym.Sect.Elfsect.shnum)
}
sym = ctxt.Syms.Lookup(".debug_ranges", 0)
if sym.Sect != nil {
putelfsectionsym(sym, sym.Sect.Elfsect.shnum)

View File

@@ -1808,7 +1808,7 @@ func elfrelocsect(ctxt *Link, sect *Section, syms []*Symbol) {
continue
}
if r.Xsym == nil {
Errorf(sym, "missing xsym in relocation %#v %#v", r.Sym.Name, sym)
Errorf(sym, "missing xsym in relocation")
continue
}
if r.Xsym.ElfsymForReloc() == 0 {
@@ -2596,9 +2596,12 @@ elfobj:
elfshreloc(sect)
}
for _, s := range dwarfp {
if len(s.R) > 0 || s.Type == SDWARFINFO || s.Type == SDWARFLOC {
if len(s.R) > 0 || s.Type == SDWARFINFO {
elfshreloc(s.Sect)
}
if s.Type == SDWARFINFO {
break
}
}
// add a .note.GNU-stack section to mark the stack as non-executable
sh := elfshname(".note.GNU-stack")

View File

@@ -105,7 +105,6 @@ const (
SDWARFSECT
SDWARFINFO
SDWARFRANGE
SDWARFLOC
SSUB = SymKind(1 << 8)
SMASK = SymKind(SSUB - 1)
SHIDDEN = SymKind(1 << 9)
@@ -125,7 +124,6 @@ var abiSymKindToSymKind = [...]SymKind{
STLSBSS,
SDWARFINFO,
SDWARFRANGE,
SDWARFLOC,
}
// readOnly are the symbol kinds that form read-only sections. In some

View File

@@ -4,9 +4,9 @@ package ld
import "fmt"
const _SymKind_name = "SxxxSTEXTSELFRXSECTSTYPESSTRINGSGOSTRINGSGOFUNCSGCBITSSRODATASFUNCTABSELFROSECTSMACHOPLTSTYPERELROSSTRINGRELROSGOSTRINGRELROSGOFUNCRELROSGCBITSRELROSRODATARELROSFUNCTABRELROSTYPELINKSITABLINKSSYMTABSPCLNTABSELFSECTSMACHOSMACHOGOTSWINDOWSSELFGOTSNOPTRDATASINITARRSDATASBSSSNOPTRBSSSTLSBSSSXREFSMACHOSYMSTRSMACHOSYMTABSMACHOINDIRECTPLTSMACHOINDIRECTGOTSFILESFILEPATHSCONSTSDYNIMPORTSHOSTOBJSDWARFSECTSDWARFINFOSDWARFRANGESDWARFLOC"
const _SymKind_name = "SxxxSTEXTSELFRXSECTSTYPESSTRINGSGOSTRINGSGOFUNCSGCBITSSRODATASFUNCTABSELFROSECTSMACHOPLTSTYPERELROSSTRINGRELROSGOSTRINGRELROSGOFUNCRELROSGCBITSRELROSRODATARELROSFUNCTABRELROSTYPELINKSITABLINKSSYMTABSPCLNTABSELFSECTSMACHOSMACHOGOTSWINDOWSSELFGOTSNOPTRDATASINITARRSDATASBSSSNOPTRBSSSTLSBSSSXREFSMACHOSYMSTRSMACHOSYMTABSMACHOINDIRECTPLTSMACHOINDIRECTGOTSFILESFILEPATHSCONSTSDYNIMPORTSHOSTOBJSDWARFSECTSDWARFINFOSDWARFRANGE"
var _SymKind_index = [...]uint16{0, 4, 9, 19, 24, 31, 40, 47, 54, 61, 69, 79, 88, 98, 110, 124, 136, 148, 160, 173, 182, 191, 198, 206, 214, 220, 229, 237, 244, 254, 262, 267, 271, 280, 287, 292, 304, 316, 333, 350, 355, 364, 370, 380, 388, 398, 408, 419, 428}
var _SymKind_index = [...]uint16{0, 4, 9, 19, 24, 31, 40, 47, 54, 61, 69, 79, 88, 98, 110, 124, 136, 148, 160, 173, 182, 191, 198, 206, 214, 220, 229, 237, 244, 254, 262, 267, 271, 280, 287, 292, 304, 316, 333, 350, 355, 364, 370, 380, 388, 398, 408, 419}
func (i SymKind) String() string {
if i < 0 || i >= SymKind(len(_SymKind_index)-1) {

View File

@@ -349,8 +349,9 @@ func doPackage(directory string, names []string, basePkg *Package) *Package {
pkg.files = files
// Type check the package.
err := pkg.check(fs, astFiles)
if err != nil && *verbose {
warnf("%s", err)
if err != nil {
// Note that we only report this error when *verbose.
Println(err)
}
// Check.

13
src/cmd/vet/testdata/cgo/cgo3.go vendored Normal file
View File

@@ -0,0 +1,13 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Used by TestVetVerbose to test that vet -v doesn't fail because it
// can't find "C".
package testdata
import "C"
func F() {
}

View File

@@ -205,3 +205,15 @@ func TestTags(t *testing.T) {
})
}
}
// Issue #21188.
func TestVetVerbose(t *testing.T) {
t.Parallel()
Build(t)
cmd := exec.Command("./"+binary, "-v", "-all", "testdata/cgo/cgo3.go")
out, err := cmd.CombinedOutput()
if err != nil {
t.Logf("%s", out)
t.Error(err)
}
}

View File

@@ -68,3 +68,94 @@ func ExampleByteOrder_get() {
// Output:
// 0x03e8 0x07d0
}
func ExamplePutUvarint() {
buf := make([]byte, binary.MaxVarintLen64)
for _, x := range []uint64{1, 2, 127, 128, 255, 256} {
n := binary.PutUvarint(buf, x)
fmt.Printf("%x\n", buf[:n])
}
// Output:
// 01
// 02
// 7f
// 8001
// ff01
// 8002
}
func ExamplePutVarint() {
buf := make([]byte, binary.MaxVarintLen64)
for _, x := range []int64{-65, -64, -2, -1, 0, 1, 2, 63, 64} {
n := binary.PutVarint(buf, x)
fmt.Printf("%x\n", buf[:n])
}
// Output:
// 8101
// 7f
// 03
// 01
// 00
// 02
// 04
// 7e
// 8001
}
func ExampleUvarint() {
inputs := [][]byte{
[]byte{0x01},
[]byte{0x02},
[]byte{0x7f},
[]byte{0x80, 0x01},
[]byte{0xff, 0x01},
[]byte{0x80, 0x02},
}
for _, b := range inputs {
x, n := binary.Uvarint(b)
if n != len(b) {
fmt.Println("Uvarint did not consume all of in")
}
fmt.Println(x)
}
// Output:
// 1
// 2
// 127
// 128
// 255
// 256
}
func ExampleVarint() {
inputs := [][]byte{
[]byte{0x81, 0x01},
[]byte{0x7f},
[]byte{0x03},
[]byte{0x01},
[]byte{0x00},
[]byte{0x02},
[]byte{0x04},
[]byte{0x7e},
[]byte{0x80, 0x01},
}
for _, b := range inputs {
x, n := binary.Varint(b)
if n != len(b) {
fmt.Println("Varint did not consume all of in")
}
fmt.Println(x)
}
// Output:
// -65
// -64
// -2
// -1
// 0
// 1
// 2
// 63
// 64
}

View File

@@ -969,14 +969,14 @@ func (*FuncDecl) declNode() {}
//
// For correct printing of source code containing comments (using packages
// go/format and go/printer), special care must be taken to update comments
// when a File's syntax tree is modified: For printing, comments are inter-
// spersed between tokens based on their position. If syntax tree nodes are
// when a File's syntax tree is modified: For printing, comments are interspersed
// between tokens based on their position. If syntax tree nodes are
// removed or moved, relevant comments in their vicinity must also be removed
// (from the File.Comments list) or moved accordingly (by updating their
// positions). A CommentMap may be used to facilitate some of these operations.
//
// Whether and how a comment is associated with a node depends on the inter-
// pretation of the syntax tree by the manipulating program: Except for Doc
// Whether and how a comment is associated with a node depends on the
// interpretation of the syntax tree by the manipulating program: Except for Doc
// and Comment comments directly associated with nodes, the remaining comments
// are "free-floating" (see also issues #18593, #20744).
//

View File

@@ -1707,8 +1707,8 @@ func (p *parser) parseSimpleStmt(mode int) (ast.Stmt, bool) {
}
// The label declaration typically starts at x[0].Pos(), but the label
// declaration may be erroneous due to a token after that position (and
// before the ':'). If SpuriousErrors is not set, the (only) error re-
// ported for the line is the illegal label error instead of the token
// before the ':'). If SpuriousErrors is not set, the (only) error
// reported for the line is the illegal label error instead of the token
// before the ':' that caused the problem. Thus, use the (latest) colon
// position for error reporting.
p.error(colon, "illegal label declaration")

View File

@@ -154,6 +154,10 @@ func (s *ioSrv) ProcessRemoteIO() {
// is available. Alternatively, it passes the request onto
// runtime netpoll and waits for completion or cancels request.
func (s *ioSrv) ExecIO(o *operation, submit func(o *operation) error) (int, error) {
if o.fd.pd.runtimeCtx == 0 {
return 0, errors.New("internal error: polling on unsupported descriptor type")
}
if !canCancelIO {
onceStartServer.Do(startServer)
}
@@ -315,8 +319,21 @@ func (fd *FD) Init(net string) (string, error) {
return "", errors.New("internal error: unknown network type " + net)
}
if err := fd.pd.init(fd); err != nil {
return "", err
if !fd.isFile && !fd.isConsole && !fd.isDir {
// Only call init for a network socket.
// This means that we don't add files to the runtime poller.
// Adding files to the runtime poller can confuse matters
// if the user is doing their own overlapped I/O.
// See issue #21172.
//
// In general the code below avoids calling the ExecIO
// method for non-network sockets. If some method does
// somehow call ExecIO, then ExecIO, and therefore the
// calling method, will return an error, because
// fd.pd.runtimeCtx will be 0.
if err := fd.pd.init(fd); err != nil {
return "", err
}
}
if hasLoadSetFileCompletionNotificationModes {
// We do not use events, so we can skip them always.

View File

@@ -40,8 +40,8 @@ func (z *Rat) Scan(s fmt.ScanState, ch rune) error {
// SetString sets z to the value of s and returns z and a boolean indicating
// success. s can be given as a fraction "a/b" or as a floating-point number
// optionally followed by an exponent. The entire string (not just a prefix)
// must be valid for success. If the operation failed, the value of z is un-
// defined but the returned value is nil.
// must be valid for success. If the operation failed, the value of z is
// undefined but the returned value is nil.
func (z *Rat) SetString(s string) (*Rat, bool) {
if len(s) == 0 {
return nil, false

View File

@@ -36,3 +36,43 @@ func ExampleLeadingZeros64() {
// 64
// 63
}
func ExampleOnesCount() {
fmt.Printf("%b\n", 14)
fmt.Println(bits.OnesCount(14))
// Output:
// 1110
// 3
}
func ExampleOnesCount8() {
fmt.Printf("%b\n", 14)
fmt.Println(bits.OnesCount8(14))
// Output:
// 1110
// 3
}
func ExampleOnesCount16() {
fmt.Printf("%b\n", 14)
fmt.Println(bits.OnesCount16(14))
// Output:
// 1110
// 3
}
func ExampleOnesCount32() {
fmt.Printf("%b\n", 14)
fmt.Println(bits.OnesCount32(14))
// Output:
// 1110
// 3
}
func ExampleOnesCount64() {
fmt.Printf("%b\n", 14)
fmt.Println(bits.OnesCount64(14))
// Output:
// 1110
// 3
}

View File

@@ -44,26 +44,29 @@ type plainAuth struct {
}
// PlainAuth returns an Auth that implements the PLAIN authentication
// mechanism as defined in RFC 4616.
// The returned Auth uses the given username and password to authenticate
// on TLS connections to host and act as identity. Usually identity will be
// left blank to act as username.
// mechanism as defined in RFC 4616. The returned Auth uses the given
// username and password to authenticate to host and act as identity.
// Usually identity should be the empty string, to act as username.
//
// PlainAuth will only send the credentials if the connection is using TLS
// or is connected to localhost. Otherwise authentication will fail with an
// error, without sending the credentials.
func PlainAuth(identity, username, password, host string) Auth {
return &plainAuth{identity, username, password, host}
}
func isLocalhost(name string) bool {
return name == "localhost" || name == "127.0.0.1" || name == "::1"
}
func (a *plainAuth) Start(server *ServerInfo) (string, []byte, error) {
if !server.TLS {
advertised := false
for _, mechanism := range server.Auth {
if mechanism == "PLAIN" {
advertised = true
break
}
}
if !advertised {
return "", nil, errors.New("unencrypted connection")
}
// Must have TLS, or else localhost server.
// Note: If TLS is not true, then we can't trust ANYTHING in ServerInfo.
// In particular, it doesn't matter if the server advertises PLAIN auth.
// That might just be the attacker saying
// "it's ok, you can trust me with your password."
if !server.TLS && !isLocalhost(server.Name) {
return "", nil, errors.New("unencrypted connection")
}
if server.Name != a.host {
return "", nil, errors.New("wrong host name")

View File

@@ -62,29 +62,41 @@ testLoop:
}
func TestAuthPlain(t *testing.T) {
auth := PlainAuth("foo", "bar", "baz", "servername")
tests := []struct {
server *ServerInfo
err string
authName string
server *ServerInfo
err string
}{
{
server: &ServerInfo{Name: "servername", TLS: true},
authName: "servername",
server: &ServerInfo{Name: "servername", TLS: true},
},
{
// Okay; explicitly advertised by server.
server: &ServerInfo{Name: "servername", Auth: []string{"PLAIN"}},
// OK to use PlainAuth on localhost without TLS
authName: "localhost",
server: &ServerInfo{Name: "localhost", TLS: false},
},
{
server: &ServerInfo{Name: "servername", Auth: []string{"CRAM-MD5"}},
err: "unencrypted connection",
// NOT OK on non-localhost, even if server says PLAIN is OK.
// (We don't know that the server is the real server.)
authName: "servername",
server: &ServerInfo{Name: "servername", Auth: []string{"PLAIN"}},
err: "unencrypted connection",
},
{
server: &ServerInfo{Name: "attacker", TLS: true},
err: "wrong host name",
authName: "servername",
server: &ServerInfo{Name: "servername", Auth: []string{"CRAM-MD5"}},
err: "unencrypted connection",
},
{
authName: "servername",
server: &ServerInfo{Name: "attacker", TLS: true},
err: "wrong host name",
},
}
for i, tt := range tests {
auth := PlainAuth("foo", "bar", "baz", tt.authName)
_, _, err := auth.Start(tt.server)
got := ""
if err != nil {

View File

@@ -4,8 +4,6 @@
// Package plugin implements loading and symbol resolution of Go plugins.
//
// Currently plugins only work on Linux.
//
// A plugin is a Go main package with exported functions and variables that
// has been built with:
//
@@ -14,6 +12,9 @@
// When a plugin is first opened, the init functions of all packages not
// already part of the program are called. The main function is not run.
// A plugin is only initialized once, and cannot be closed.
//
// The plugin support is currently incomplete, only supports Linux,
// and has known bugs. Please report any issues.
package plugin
// Plugin is a loaded Go plugin.

View File

@@ -178,6 +178,12 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool {
// DeepEqual has been defined so that the same short-cut applies
// to slices and maps: if x and y are the same slice or the same map,
// they are deeply equal regardless of content.
//
// As DeepEqual traverses the data values it may find a cycle. The
// second and subsequent times that DeepEqual compares two pointer
// values that have been compared before, it treats the values as
// equal rather than examining the values to which they point.
// This ensures that DeepEqual terminates.
func DeepEqual(x, y interface{}) bool {
if x == nil || y == nil {
return x == y

View File

@@ -163,6 +163,15 @@ func (p *cpuProfile) addExtra() {
}
}
func (p *cpuProfile) addLostAtomic64(count uint64) {
hdr := [1]uint64{count}
lostStk := [2]uintptr{
funcPC(_LostSIGPROFDuringAtomic64) + sys.PCQuantum,
funcPC(_System) + sys.PCQuantum,
}
cpuprof.log.write(nil, 0, hdr[:], lostStk[:])
}
// CPUProfile panics.
// It formerly provided raw access to chunks of
// a pprof-format profile generated by the runtime.

View File

@@ -170,7 +170,7 @@ func TestPeriodicGC(t *testing.T) {
// slack if things are slow.
var numGCs uint32
const want = 2
for i := 0; i < 20 && numGCs < want; i++ {
for i := 0; i < 200 && numGCs < want; i++ {
time.Sleep(5 * time.Millisecond)
// Test that periodic GC actually happened.

View File

@@ -495,7 +495,7 @@ again:
}
// store new key/value at insert position
*((*uint32)(insertk)) = key
typedmemmove(t.key, insertk, unsafe.Pointer(&key))
*inserti = top
h.count++
@@ -583,7 +583,7 @@ again:
}
// store new key/value at insert position
*((*uint64)(insertk)) = key
typedmemmove(t.key, insertk, unsafe.Pointer(&key))
*inserti = top
h.count++
@@ -723,7 +723,7 @@ func mapdelete_fast32(t *maptype, h *hmap, key uint32) {
if key != *k {
continue
}
*k = 0
typedmemclr(t.key, unsafe.Pointer(k))
v := unsafe.Pointer(uintptr(unsafe.Pointer(b)) + dataOffset + bucketCnt*4 + i*uintptr(t.valuesize))
typedmemclr(t.elem, v)
b.tophash[i] = empty
@@ -778,7 +778,7 @@ func mapdelete_fast64(t *maptype, h *hmap, key uint64) {
if key != *k {
continue
}
*k = 0
typedmemclr(t.key, unsafe.Pointer(k))
v := unsafe.Pointer(uintptr(unsafe.Pointer(b)) + dataOffset + bucketCnt*8 + i*uintptr(t.valuesize))
typedmemclr(t.elem, v)
b.tophash[i] = empty

View File

@@ -416,7 +416,10 @@ func (h *mheap) sysAlloc(n uintptr) unsafe.Pointer {
var reserved bool
p := uintptr(sysReserve(unsafe.Pointer(h.arena_end), p_size, &reserved))
if p == 0 {
return nil
// TODO: Try smaller reservation
// growths in case we're in a crowded
// 32-bit address space.
goto reservationFailed
}
// p can be just about anywhere in the address
// space, including before arena_end.
@@ -476,6 +479,7 @@ func (h *mheap) sysAlloc(n uintptr) unsafe.Pointer {
return unsafe.Pointer(p)
}
reservationFailed:
// If using 64-bit, our reservation is all we have.
if sys.PtrSize != 4 {
return nil

View File

@@ -503,6 +503,11 @@ func (h *mheap) init(spansStart, spansBytes uintptr) {
sp.array = unsafe.Pointer(spansStart)
sp.len = 0
sp.cap = int(spansBytes / sys.PtrSize)
// Map metadata structures. But don't map race detector memory
// since we're not actually growing the arena here (and TSAN
// gets mad if you map 0 bytes).
h.setArenaUsed(h.arena_used, false)
}
// setArenaUsed extends the usable arena to address arena_used and

View File

@@ -12,6 +12,7 @@ import (
"fmt"
"internal/testenv"
"io"
"io/ioutil"
"math/big"
"os"
"os/exec"
@@ -20,11 +21,12 @@ import (
"runtime/pprof/internal/profile"
"strings"
"sync"
"sync/atomic"
"testing"
"time"
)
func cpuHogger(f func(), dur time.Duration) {
func cpuHogger(f func() int, dur time.Duration) {
// We only need to get one 100 Hz clock tick, so we've got
// a large safety buffer.
// But do at least 500 iterations (which should take about 100ms),
@@ -44,7 +46,7 @@ var (
// The actual CPU hogging function.
// Must not call other functions nor access heap/globals in the loop,
// otherwise under race detector the samples will be in the race runtime.
func cpuHog1() {
func cpuHog1() int {
foo := salt1
for i := 0; i < 1e5; i++ {
if foo > 0 {
@@ -53,10 +55,10 @@ func cpuHog1() {
foo *= foo + 1
}
}
salt1 = foo
return foo
}
func cpuHog2() {
func cpuHog2() int {
foo := salt2
for i := 0; i < 1e5; i++ {
if foo > 0 {
@@ -65,7 +67,7 @@ func cpuHog2() {
foo *= foo + 2
}
}
salt2 = foo
return foo
}
func TestCPUProfile(t *testing.T) {
@@ -93,8 +95,9 @@ func TestCPUProfileInlining(t *testing.T) {
})
}
func inlinedCaller() {
func inlinedCaller() int {
inlinedCallee()
return 0
}
func inlinedCallee() {
@@ -713,3 +716,54 @@ func TestCPUProfileLabel(t *testing.T) {
})
})
}
func TestLabelRace(t *testing.T) {
// Test the race detector annotations for synchronization
// between settings labels and consuming them from the
// profile.
testCPUProfile(t, []string{"runtime/pprof.cpuHogger;key=value"}, func(dur time.Duration) {
start := time.Now()
var wg sync.WaitGroup
for time.Since(start) < dur {
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
Do(context.Background(), Labels("key", "value"), func(context.Context) {
cpuHogger(cpuHog1, time.Millisecond)
})
wg.Done()
}()
}
wg.Wait()
}
})
}
// Check that there is no deadlock when the program receives SIGPROF while in
// 64bit atomics' critical section. Used to happen on mips{,le}. See #20146.
func TestAtomicLoadStore64(t *testing.T) {
f, err := ioutil.TempFile("", "profatomic")
if err != nil {
t.Fatalf("TempFile: %v", err)
}
defer os.Remove(f.Name())
defer f.Close()
if err := StartCPUProfile(f); err != nil {
t.Fatal(err)
}
defer StopCPUProfile()
var flag uint64
done := make(chan bool, 1)
go func() {
for atomic.LoadUint64(&flag) == 0 {
runtime.Gosched()
}
done <- true
}()
time.Sleep(50 * time.Millisecond)
atomic.StoreUint64(&flag, 1)
<-done
}

View File

@@ -3232,10 +3232,14 @@ var prof struct {
hz int32
}
func _System() { _System() }
func _ExternalCode() { _ExternalCode() }
func _LostExternalCode() { _LostExternalCode() }
func _GC() { _GC() }
func _System() { _System() }
func _ExternalCode() { _ExternalCode() }
func _LostExternalCode() { _LostExternalCode() }
func _GC() { _GC() }
func _LostSIGPROFDuringAtomic64() { _LostSIGPROFDuringAtomic64() }
// Counts SIGPROFs received while in atomic64 critical section, on mips{,le}
var lostAtomic64Count uint64
// Called if we receive a SIGPROF signal.
// Called by the signal handler, may run during STW.
@@ -3245,6 +3249,21 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
return
}
// On mips{,le}, 64bit atomics are emulated with spinlocks, in
// runtime/internal/atomic. If SIGPROF arrives while the program is inside
// the critical section, it creates a deadlock (when writing the sample).
// As a workaround, create a counter of SIGPROFs while in critical section
// to store the count, and pass it to sigprof.add() later when SIGPROF is
// received from somewhere else (with _LostSIGPROFDuringAtomic64 as pc).
if GOARCH == "mips" || GOARCH == "mipsle" {
if f := findfunc(pc); f.valid() {
if hasprefix(funcname(f), "runtime/internal/atomic") {
lostAtomic64Count++
return
}
}
}
// Profiling runs concurrently with GC, so it must not allocate.
// Set a trap in case the code does allocate.
// Note that on windows, one thread takes profiles of all the
@@ -3371,6 +3390,10 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
}
if prof.hz != 0 {
if (GOARCH == "mips" || GOARCH == "mipsle") && lostAtomic64Count > 0 {
cpuprof.addLostAtomic64(lostAtomic64Count)
lostAtomic64Count = 0
}
cpuprof.add(gp, stk[:n])
}
getg().m.mallocing--

View File

@@ -545,7 +545,7 @@ Read:
b.rNext = br.addCountsAndClearFlags(skip+di, ti)
if raceenabled {
// Match racewritepc in runtime_setProfLabel,
// Match racereleasemerge in runtime_setProfLabel,
// so that the setting of the labels in runtime_setProfLabel
// is treated as happening before any use of the labels
// by our caller. The synchronization on labelSync itself is a fiction

View File

@@ -13,8 +13,23 @@ func runtime_setProfLabel(labels unsafe.Pointer) {
// Introduce race edge for read-back via profile.
// This would more properly use &getg().labels as the sync address,
// but we do the read in a signal handler and can't call the race runtime then.
//
// This uses racereleasemerge rather than just racerelease so
// the acquire in profBuf.read synchronizes with *all* prior
// setProfLabel operations, not just the most recent one. This
// is important because profBuf.read will observe different
// labels set by different setProfLabel operations on
// different goroutines, so it needs to synchronize with all
// of them (this wouldn't be an issue if we could synchronize
// on &getg().labels since we would synchronize with each
// most-recent labels write separately.)
//
// racereleasemerge is like a full read-modify-write on
// labelSync, rather than just a store-release, so it carries
// a dependency on the previous racereleasemerge, which
// ultimately carries forward to the acquire in profBuf.read.
if raceenabled {
racerelease(unsafe.Pointer(&labelSync))
racereleasemerge(unsafe.Pointer(&labelSync))
}
getg().labels = labels
}

View File

@@ -259,4 +259,25 @@ Goroutine [0-9] \(running\) created at:
runtime\.newextram\(\)
.*/runtime/proc.go:[0-9]+ \+0x[0-9,a-f]+
==================`},
{"second_test_passes", "test", "", "atexit_sleep_ms=0", `
package main_test
import "testing"
func TestFail(t *testing.T) {
done := make(chan bool)
x := 0
go func() {
x = 42
done <- true
}()
x = 43
<-done
}
func TestPass(t *testing.T) {
}
`, `
==================
--- FAIL: TestFail \(0...s\)
.*testing.go:.*: race detected during execution of test
FAIL`},
}

View File

@@ -409,6 +409,11 @@ var modulesSlice unsafe.Pointer // see activeModules
//
// A module is active once its gcdatamask and gcbssmask have been
// assembled and it is usable by the GC.
//
// This is nosplit/nowritebarrier because it is called by the
// cgo pointer checking code.
//go:nosplit
//go:nowritebarrier
func activeModules() []*moduledata {
p := (*[]*moduledata)(atomic.Loadp(unsafe.Pointer(&modulesSlice)))
if p == nil {

View File

@@ -100,7 +100,7 @@ TEXT runtime·usleep(SB),NOSPLIT,$8
MOVL AX, 0(SP)
MOVL $1000, AX // usec to nsec
MULL DX
MOVL DX, 4(SP)
MOVL AX, 4(SP)
// pselect6(0, 0, 0, 0, &ts, 0)
MOVL $308, AX

View File

@@ -695,8 +695,7 @@ func tRunner(t *T, fn func(t *T)) {
// a call to runtime.Goexit, record the duration and send
// a signal saying that the test is done.
defer func() {
t.raceErrors += race.Errors()
if t.raceErrors > 0 {
if t.raceErrors+race.Errors() > 0 {
t.Errorf("race detected during execution of test")
}
@@ -970,7 +969,7 @@ func listTests(matchString func(pat, str string) (bool, error), tests []Internal
}
}
for _, example := range examples {
if ok, _ := matchString(*matchList, example.Name); ok && example.Output != "" {
if ok, _ := matchString(*matchList, example.Name); ok {
fmt.Println(example.Name)
}
}

View File

@@ -14,6 +14,14 @@ func testZoneAbbr(t *testing.T) {
t1 := Now()
// discard nsec
t1 = Date(t1.Year(), t1.Month(), t1.Day(), t1.Hour(), t1.Minute(), t1.Second(), 0, t1.Location())
// Skip the test if we're in a timezone with no abbreviation.
// Format will fallback to the numeric abbreviation, and
// Parse(RFC1123, ..) will fail (see Issue 21183).
if tz := t1.Format("MST"); tz[0] == '-' || tz[0] == '+' {
t.Skip("No zone abbreviation")
}
t2, err := Parse(RFC1123, t1.Format(RFC1123))
if err != nil {
t.Fatalf("Parse failed: %v", err)

15
test/README.md Normal file
View File

@@ -0,0 +1,15 @@
The test directory contains tests of the Go tool chain and runtime.
It includes black box tests, regression tests, and error output tests.
They are run as part of all.bash.
To run just these tests, execute:
go run run.go
Standard library tests should be written as regular Go tests in the appropriate package.
The tool chain and runtime also have regular Go tests in their packages.
The main reasons to add a new test to this directory are:
* it is most naturally expressed using the test runner; or
* it is also applicable to `gccgo` and other Go tool chains.