mirror of
https://github.com/golang/go.git
synced 2026-02-01 16:42:04 +03:00
Compare commits
113 Commits
go1.8beta2
...
dev.garbag
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1d4942afe0 | ||
|
|
8b25a00e6d | ||
|
|
d9a0579156 | ||
|
|
2817e77024 | ||
|
|
7f1ff65c39 | ||
|
|
f412bd31ce | ||
|
|
a8871194f2 | ||
|
|
ffedff7e50 | ||
|
|
3156736189 | ||
|
|
1ede11d13a | ||
|
|
067bab00a8 | ||
|
|
8fa2344e98 | ||
|
|
1fbdae5c3a | ||
|
|
66063b2da8 | ||
|
|
5ddfa69fef | ||
|
|
116da1c64a | ||
|
|
41d2278eef | ||
|
|
a37b9e8e70 | ||
|
|
b902a63ade | ||
|
|
5dd978a283 | ||
|
|
618c291544 | ||
|
|
cb91dccd86 | ||
|
|
7aefdfded0 | ||
|
|
867dcb5570 | ||
|
|
b07363da16 | ||
|
|
b03dce927b | ||
|
|
ea53e61c6c | ||
|
|
7d977e4279 | ||
|
|
b820ef5c33 | ||
|
|
a2b615d527 | ||
|
|
f5608c20f7 | ||
|
|
c3fc9b4b81 | ||
|
|
2547aec42a | ||
|
|
2815045a50 | ||
|
|
ecac827573 | ||
|
|
7fb1640613 | ||
|
|
3fa53f1229 | ||
|
|
20cdb62c49 | ||
|
|
f64b7d301d | ||
|
|
6a1cac2700 | ||
|
|
d698e614a2 | ||
|
|
161cd34f78 | ||
|
|
f09462707f | ||
|
|
155d314e50 | ||
|
|
af7bc07049 | ||
|
|
9def857072 | ||
|
|
f78cd569f5 | ||
|
|
e776975ae6 | ||
|
|
b63ca1e974 | ||
|
|
9e199702c8 | ||
|
|
9719ca9c0e | ||
|
|
5bfba30d33 | ||
|
|
d160982a2e | ||
|
|
a3f4cc0669 | ||
|
|
c8f1436948 | ||
|
|
db07c9ecb6 | ||
|
|
8887be4654 | ||
|
|
6e36811c37 | ||
|
|
f419b56354 | ||
|
|
17190343e3 | ||
|
|
d2512aff87 | ||
|
|
d51046b37c | ||
|
|
f24384f686 | ||
|
|
c44da14440 | ||
|
|
d296c3235d | ||
|
|
0ef4815150 | ||
|
|
8599c0da1f | ||
|
|
09c411da1d | ||
|
|
27fb26c77c | ||
|
|
9c6a5ef922 | ||
|
|
86f2c5fe93 | ||
|
|
985a574991 | ||
|
|
6e87f88961 | ||
|
|
2eae691d56 | ||
|
|
8df54c92c0 | ||
|
|
2f9dee9293 | ||
|
|
0c942e8f2c | ||
|
|
860c9c0b8d | ||
|
|
5a72bad87a | ||
|
|
c5f16d4e40 | ||
|
|
3357daa96e | ||
|
|
4d02833c2e | ||
|
|
a1c835f57b | ||
|
|
5df59a4fc9 | ||
|
|
7eee512773 | ||
|
|
a0667be8ef | ||
|
|
ddd558e7e4 | ||
|
|
8d21691044 | ||
|
|
0919fd7068 | ||
|
|
75d367e34b | ||
|
|
12979345b1 | ||
|
|
1ec64e9b63 | ||
|
|
1106512db5 | ||
|
|
61db2e4efa | ||
|
|
1716add3dc | ||
|
|
7799022cdd | ||
|
|
ecc4474341 | ||
|
|
115e9cac80 | ||
|
|
29cb72154d | ||
|
|
c1d449c42c | ||
|
|
0cd2bf4f98 | ||
|
|
6e542dce21 | ||
|
|
42afbd9e63 | ||
|
|
f9f6c90ed1 | ||
|
|
69161e279e | ||
|
|
fb4c718209 | ||
|
|
81b74bf9c5 | ||
|
|
edb54c300f | ||
|
|
312aa09996 | ||
|
|
d491e550c3 | ||
|
|
641c32dafa | ||
|
|
2e495a1df6 | ||
|
|
344476d23c |
48
.gitignore
vendored
48
.gitignore
vendored
@@ -18,28 +18,28 @@ _cgo_*
|
||||
_obj
|
||||
_test
|
||||
_testmain.go
|
||||
build.out
|
||||
test.out
|
||||
doc/articles/wiki/*.bin
|
||||
misc/cgo/life/run.out
|
||||
misc/cgo/stdio/run.out
|
||||
misc/cgo/testso/main
|
||||
src/cmd/cgo/zdefaultcc.go
|
||||
src/cmd/go/zdefaultcc.go
|
||||
src/cmd/go/zosarch.go
|
||||
src/cmd/internal/obj/zbootstrap.go
|
||||
src/go/build/zcgo.go
|
||||
src/go/doc/headscan
|
||||
src/runtime/internal/sys/zversion.go
|
||||
src/unicode/maketables
|
||||
src/*.*/
|
||||
test/pass.out
|
||||
test/run.out
|
||||
test/times.out
|
||||
test/garbage/*.out
|
||||
goinstall.log
|
||||
last-change
|
||||
VERSION.cache
|
||||
|
||||
bin/
|
||||
pkg/
|
||||
/VERSION.cache
|
||||
/bin/
|
||||
/build.out
|
||||
/doc/articles/wiki/*.bin
|
||||
/goinstall.log
|
||||
/last-change
|
||||
/misc/cgo/life/run.out
|
||||
/misc/cgo/stdio/run.out
|
||||
/misc/cgo/testso/main
|
||||
/pkg/
|
||||
/src/*.*/
|
||||
/src/cmd/cgo/zdefaultcc.go
|
||||
/src/cmd/go/zdefaultcc.go
|
||||
/src/cmd/go/zosarch.go
|
||||
/src/cmd/internal/obj/zbootstrap.go
|
||||
/src/go/build/zcgo.go
|
||||
/src/go/doc/headscan
|
||||
/src/runtime/internal/sys/zversion.go
|
||||
/src/unicode/maketables
|
||||
/test.out
|
||||
/test/garbage/*.out
|
||||
/test/pass.out
|
||||
/test/run.out
|
||||
/test/times.out
|
||||
|
||||
21
AUTHORS
21
AUTHORS
@@ -29,11 +29,13 @@ Akshat Kumar <seed@mail.nanosouffle.net>
|
||||
Alan Shreve <alan@inconshreveable.com>
|
||||
Albert Nigmatzianov <albertnigma@gmail.com>
|
||||
Albert Strasheim <fullung@gmail.com>
|
||||
Albert Yu <yukinying@gmail.com>
|
||||
Alberto Bertogli <albertito@blitiri.com.ar>
|
||||
Alberto Donizetti <alb.donizetti@gmail.com>
|
||||
Alberto García Hierro <alberto@garciahierro.com> <alberto.garcia.hierro@gmail.com>
|
||||
Aleksandar Dezelin <dezelin@gmail.com>
|
||||
Alessandro Arzilli <alessandro.arzilli@gmail.com>
|
||||
Alessandro Baffa <alessandro.baffa@gmail.com>
|
||||
Alex A Skinner <alex@lx.lc>
|
||||
Alex Brainman <alex.brainman@gmail.com>
|
||||
Alex Browne <stephenalexbrowne@gmail.com>
|
||||
@@ -54,6 +56,7 @@ Alexander Surma <surma@surmair.de>
|
||||
Alexander Zhavnerchik <alex.vizor@gmail.com>
|
||||
Alexander Zolotov <goldifit@gmail.com>
|
||||
Alexandre Cesaro <alexandre.cesaro@gmail.com>
|
||||
Alexandre Fiori <fiorix@gmail.com>
|
||||
Alexandre Normand <alexandre.normand@gmail.com>
|
||||
Alexei Sholik <alcosholik@gmail.com>
|
||||
Alexey Borzenkov <snaury@gmail.com>
|
||||
@@ -70,6 +73,7 @@ Andreas Auernhammer <aead@mail.de>
|
||||
Andreas Litt <andreas.litt@gmail.com>
|
||||
Andrei Korzhevskii <a.korzhevskiy@gmail.com>
|
||||
Andrei Vieru <euvieru@gmail.com>
|
||||
Andrew Austin <andrewaclt@gmail.com>
|
||||
Andrew Balholm <andybalholm@gmail.com>
|
||||
Andrew Bonventre <andybons@chromium.org>
|
||||
Andrew Bursavich <abursavich@gmail.com>
|
||||
@@ -89,6 +93,7 @@ Andrey Petrov <andrey.petrov@shazow.net>
|
||||
Andriy Lytvynov <lytvynov.a.v@gmail.com>
|
||||
Andy Balholm <andy@balholm.com>
|
||||
Andy Davis <andy@bigandian.com>
|
||||
Andy Finkenstadt <afinkenstadt@zynga.com>
|
||||
Andy Maloney <asmaloney@gmail.com>
|
||||
Anfernee Yongkun Gui <anfernee.gui@gmail.com>
|
||||
Angelo Bulfone <mbulfone@gmail.com>
|
||||
@@ -100,6 +105,7 @@ Anthony Eufemio <anthony.eufemio@gmail.com>
|
||||
Anthony Martin <ality@pbrane.org>
|
||||
Anthony Starks <ajstarks@gmail.com>
|
||||
Anthony Woods <awoods@raintank.io>
|
||||
Antonio Bibiano <antbbn@gmail.com>
|
||||
Apisak Darakananda <pongad@gmail.com>
|
||||
Aram Hăvărneanu <aram@mgk.ro>
|
||||
Areski Belaid <areski@gmail.com>
|
||||
@@ -119,7 +125,9 @@ Aulus Egnatius Varialus <varialus@gmail.com>
|
||||
awaw fumin <awawfumin@gmail.com>
|
||||
Ayanamist Yang <ayanamist@gmail.com>
|
||||
Aymerick Jéhanne <aymerick@jehanne.org>
|
||||
Baiju Muthukadan <baiju.m.mail@gmail.com>
|
||||
Ben Burkert <ben@benburkert.com>
|
||||
Ben Lubar <ben.lubar@gmail.com>
|
||||
Ben Olive <sionide21@gmail.com>
|
||||
Benjamin Black <b@b3k.us>
|
||||
Benny Siegert <bsiegert@gmail.com>
|
||||
@@ -277,6 +285,7 @@ Erik St. Martin <alakriti@gmail.com>
|
||||
Erik Westrup <erik.westrup@gmail.com>
|
||||
Ernest Chiang <ernest_chiang@htc.com>
|
||||
Esko Luontola <esko.luontola@gmail.com>
|
||||
Euan Kemp <euank@euank.com>
|
||||
Evan Phoenix <evan@phx.io>
|
||||
Evan Shaw <chickencha@gmail.com>
|
||||
Ewan Chou <coocood@gmail.com>
|
||||
@@ -332,6 +341,7 @@ Hajime Hoshi <hajimehoshi@gmail.com>
|
||||
Hari haran <hariharan.uno@gmail.com>
|
||||
Hariharan Srinath <srinathh@gmail.com>
|
||||
Harley Laue <losinggeneration@gmail.com>
|
||||
Harry Moreno <morenoh149@gmail.com>
|
||||
Harshavardhana <hrshvardhana@gmail.com>
|
||||
Håvard Haugen <havard.haugen@gmail.com>
|
||||
Hector Chu <hectorchu@gmail.com>
|
||||
@@ -434,6 +444,7 @@ Jonathan Rudenberg <jonathan@titanous.com>
|
||||
Jonathan Wills <runningwild@gmail.com>
|
||||
Jongmin Kim <atomaths@gmail.com>
|
||||
Joonas Kuorilehto <joneskoo@derbian.fi>
|
||||
Joop Kiefte <ikojba@gmail.com> <joop@kiefte.net>
|
||||
Jordan Lewis <jordanthelewis@gmail.com>
|
||||
Jose Luis Vázquez González <josvazg@gmail.com>
|
||||
Joseph Holsten <joseph@josephholsten.com>
|
||||
@@ -500,6 +511,7 @@ Luigi Riefolo <luigi.riefolo@gmail.com>
|
||||
Luit van Drongelen <luitvd@gmail.com>
|
||||
Luka Zakrajšek <tr00.g33k@gmail.com>
|
||||
Luke Curley <qpingu@gmail.com>
|
||||
Maksym Trykur <maksym.trykur@gmail.com>
|
||||
Mal Curtis <mal@mal.co.nz>
|
||||
Manfred Touron <m@42.am>
|
||||
Manu S Ajith <neo@codingarena.in>
|
||||
@@ -545,6 +557,7 @@ Matthew Denton <mdenton@skyportsystems.com>
|
||||
Matthew Holt <Matthew.Holt+git@gmail.com>
|
||||
Matthew Horsnell <matthew.horsnell@gmail.com>
|
||||
Matthieu Hauglustaine <matt.hauglustaine@gmail.com>
|
||||
Matthieu Olivier <olivier.matthieu@gmail.com>
|
||||
Max Riveiro <kavu13@gmail.com>
|
||||
Maxim Khitrov <max@mxcrypt.com>
|
||||
Maxwell Krohn <themax@gmail.com>
|
||||
@@ -610,6 +623,7 @@ Nicholas Presta <nick@nickpresta.ca> <nick1presta@gmail.com>
|
||||
Nicholas Sullivan <nicholas.sullivan@gmail.com>
|
||||
Nicholas Waples <nwaples@gmail.com>
|
||||
Nick Craig-Wood <nick@craig-wood.com> <nickcw@gmail.com>
|
||||
Nick Leli <nicholasleli@gmail.com>
|
||||
Nick Patavalis <nick.patavalis@gmail.com>
|
||||
Nick Petroni <npetroni@cs.umd.edu>
|
||||
Nicolas Kaiser <nikai@nikai.net>
|
||||
@@ -617,6 +631,7 @@ Nicolas Owens <mischief@offblast.org>
|
||||
Nicolas S. Dade <nic.dade@gmail.com>
|
||||
Niels Widger <niels.widger@gmail.com>
|
||||
Nigel Kerr <nigel.kerr@gmail.com>
|
||||
Nik Nyby <nnyby@columbia.edu>
|
||||
Niko Dziemba <niko@dziemba.com>
|
||||
Nikolay Turpitko <nikolay@turpitko.com>
|
||||
Noah Campbell <noahcampbell@gmail.com>
|
||||
@@ -686,9 +701,11 @@ Quentin Perez <qperez@ocs.online.net>
|
||||
Quoc-Viet Nguyen <afelion@gmail.com>
|
||||
RackTop Systems Inc.
|
||||
Radu Berinde <radu@cockroachlabs.com>
|
||||
Rafal Jeczalik <rjeczalik@gmail.com>
|
||||
Raif S. Naffah <go@naffah-raif.name>
|
||||
Rajat Goel <rajat.goel2010@gmail.com>
|
||||
Ralph Corderoy <ralph@inputplus.co.uk>
|
||||
Raphael Geronimi <raphael.geronimi@gmail.com>
|
||||
Red Hat, Inc.
|
||||
Reinaldo de Souza Jr <juniorz@gmail.com>
|
||||
Rémy Oudompheng <oudomphe@phare.normalesup.org>
|
||||
@@ -719,6 +736,7 @@ Ron Minnich <rminnich@gmail.com>
|
||||
Ross Light <rlight2@gmail.com>
|
||||
Rowan Worth <sqweek@gmail.com>
|
||||
Russell Haering <russellhaering@gmail.com>
|
||||
Ryan Bagwell <ryanbagwell@outlook.com>
|
||||
Ryan Hitchman <hitchmanr@gmail.com>
|
||||
Ryan Lower <rpjlower@gmail.com>
|
||||
Ryan Seys <ryan@ryanseys.com>
|
||||
@@ -758,6 +776,7 @@ Simon Whitehead <chemnova@gmail.com>
|
||||
Sina Siadat <siadat@gmail.com>
|
||||
Sokolov Yura <funny.falcon@gmail.com>
|
||||
Song Gao <song@gao.io>
|
||||
Sourcegraph Inc
|
||||
Spencer Nelson <s@spenczar.com>
|
||||
Spring Mc <heresy.mc@gmail.com>
|
||||
Square, Inc.
|
||||
@@ -814,6 +833,7 @@ Totoro W <tw19881113@gmail.com>
|
||||
Travis Cline <travis.cline@gmail.com>
|
||||
Trey Lawrence <lawrence.trey@gmail.com>
|
||||
Trey Tacon <ttacon@gmail.com>
|
||||
Tristan Colgate <tcolgate@gmail.com>
|
||||
Tristan Ooohry <ooohry@gmail.com>
|
||||
Tudor Golubenco <tudor.g@gmail.com>
|
||||
Tuo Shan <sturbo89@gmail.com>
|
||||
@@ -866,4 +886,5 @@ Zemanta d.o.o.
|
||||
Zev Goldstein <zev.goldstein@gmail.com>
|
||||
Ziad Hatahet <hatahet@gmail.com>
|
||||
Zorion Arrizabalaga <zorionk@gmail.com>
|
||||
Фахриддин Балтаев <faxriddinjon@gmail.com>
|
||||
申习之 <bronze1man@gmail.com>
|
||||
|
||||
@@ -7,6 +7,11 @@ It is the work of hundreds of contributors. We appreciate your help!
|
||||
|
||||
## Filing issues
|
||||
|
||||
General questions should go to the
|
||||
[golang-nuts mailing list](https://groups.google.com/group/golang-nuts) or
|
||||
[other forum](https://golang.org/wiki/Questions) instead of the issue tracker.
|
||||
The gophers there will answer or ask you to file an issue if you've tripped over a bug.
|
||||
|
||||
When filing an issue, make sure to answer these five questions:
|
||||
|
||||
1. What version of Go are you using (`go version`)?
|
||||
@@ -15,8 +20,7 @@ When filing an issue, make sure to answer these five questions:
|
||||
4. What did you expect to see?
|
||||
5. What did you see instead?
|
||||
|
||||
General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker.
|
||||
The gophers there will answer or ask you to file an issue if you've tripped over a bug.
|
||||
For change proposals, see [Proposing Changes To Go](https://github.com/golang/proposal/).
|
||||
|
||||
Sensitive security-related issues should be reported to [security@golang.org](mailto:security@golang.org).
|
||||
|
||||
@@ -28,6 +32,7 @@ before sending patches.
|
||||
**We do not accept GitHub pull requests**
|
||||
(we use [an instance](https://go-review.googlesource.com/) of the
|
||||
[Gerrit](https://www.gerritcodereview.com/) code review system instead).
|
||||
Also, please do not post patches on the issue tracker.
|
||||
|
||||
Unless otherwise noted, the Go source files are distributed under
|
||||
the BSD-style license found in the LICENSE file.
|
||||
|
||||
23
CONTRIBUTORS
23
CONTRIBUTORS
@@ -55,11 +55,13 @@ Alan Donovan <adonovan@google.com>
|
||||
Alan Shreve <alan@inconshreveable.com>
|
||||
Albert Nigmatzianov <albertnigma@gmail.com>
|
||||
Albert Strasheim <fullung@gmail.com>
|
||||
Albert Yu <yukinying@gmail.com>
|
||||
Alberto Bertogli <albertito@blitiri.com.ar>
|
||||
Alberto Donizetti <alb.donizetti@gmail.com>
|
||||
Alberto García Hierro <alberto@garciahierro.com> <alberto.garcia.hierro@gmail.com>
|
||||
Aleksandar Dezelin <dezelin@gmail.com>
|
||||
Alessandro Arzilli <alessandro.arzilli@gmail.com>
|
||||
Alessandro Baffa <alessandro.baffa@gmail.com>
|
||||
Alex A Skinner <alex@lx.lc>
|
||||
Alex Brainman <alex.brainman@gmail.com>
|
||||
Alex Bramley <abramley@google.com>
|
||||
@@ -82,6 +84,7 @@ Alexander Surma <surma@surmair.de>
|
||||
Alexander Zhavnerchik <alex.vizor@gmail.com>
|
||||
Alexander Zolotov <goldifit@gmail.com>
|
||||
Alexandre Cesaro <alexandre.cesaro@gmail.com>
|
||||
Alexandre Fiori <fiorix@gmail.com>
|
||||
Alexandre Normand <alexandre.normand@gmail.com>
|
||||
Alexandru Moșoi <brtzsnr@gmail.com>
|
||||
Alexei Sholik <alcosholik@gmail.com>
|
||||
@@ -102,6 +105,7 @@ Andreas Litt <andreas.litt@gmail.com>
|
||||
Andrei Korzhevskii <a.korzhevskiy@gmail.com>
|
||||
Andrei Vieru <euvieru@gmail.com>
|
||||
Andres Erbsen <andreser@google.com>
|
||||
Andrew Austin <andrewaclt@gmail.com>
|
||||
Andrew Balholm <andybalholm@gmail.com>
|
||||
Andrew Bonventre <andybons@chromium.org>
|
||||
Andrew Bursavich <abursavich@gmail.com>
|
||||
@@ -124,6 +128,7 @@ Andrey Petrov <andrey.petrov@shazow.net>
|
||||
Andriy Lytvynov <lytvynov.a.v@gmail.com>
|
||||
Andy Balholm <andy@balholm.com>
|
||||
Andy Davis <andy@bigandian.com>
|
||||
Andy Finkenstadt <afinkenstadt@zynga.com>
|
||||
Andy Maloney <asmaloney@gmail.com>
|
||||
Anfernee Yongkun Gui <anfernee.gui@gmail.com>
|
||||
Angelo Bulfone <mbulfone@gmail.com>
|
||||
@@ -135,6 +140,7 @@ Anthony Eufemio <anthony.eufemio@gmail.com>
|
||||
Anthony Martin <ality@pbrane.org>
|
||||
Anthony Starks <ajstarks@gmail.com>
|
||||
Anthony Woods <awoods@raintank.io>
|
||||
Antonio Bibiano <antbbn@gmail.com>
|
||||
Antonio Murdaca <runcom@redhat.com>
|
||||
Apisak Darakananda <pongad@gmail.com>
|
||||
Aram Hăvărneanu <aram@mgk.ro>
|
||||
@@ -157,10 +163,12 @@ Austin Clements <austin@google.com> <aclements@csail.mit.edu>
|
||||
awaw fumin <awawfumin@gmail.com>
|
||||
Ayanamist Yang <ayanamist@gmail.com>
|
||||
Aymerick Jéhanne <aymerick@jehanne.org>
|
||||
Baiju Muthukadan <baiju.m.mail@gmail.com>
|
||||
Balazs Lecz <leczb@google.com>
|
||||
Ben Burkert <ben@benburkert.com>
|
||||
Ben Eitzen <eitzenb@golang.org>
|
||||
Ben Fried <ben.fried@gmail.com>
|
||||
Ben Lubar <ben.lubar@gmail.com>
|
||||
Ben Lynn <benlynn@gmail.com>
|
||||
Ben Olive <sionide21@gmail.com>
|
||||
Benjamin Black <b@b3k.us>
|
||||
@@ -384,6 +392,7 @@ Ernest Chiang <ernest_chiang@htc.com>
|
||||
Esko Luontola <esko.luontola@gmail.com>
|
||||
Ethan Burns <eaburns@google.com>
|
||||
Ethan Miller <eamiller@us.ibm.com>
|
||||
Euan Kemp <euank@euank.com>
|
||||
Evan Broder <evan@stripe.com>
|
||||
Evan Brown <evanbrown@google.com>
|
||||
Evan Kroske <evankroske@google.com>
|
||||
@@ -454,6 +463,7 @@ Han-Wen Nienhuys <hanwen@google.com>
|
||||
Hari haran <hariharan.uno@gmail.com>
|
||||
Hariharan Srinath <srinathh@gmail.com>
|
||||
Harley Laue <losinggeneration@gmail.com>
|
||||
Harry Moreno <morenoh149@gmail.com>
|
||||
Harshavardhana <hrshvardhana@gmail.com>
|
||||
Håvard Haugen <havard.haugen@gmail.com>
|
||||
Hector Chu <hectorchu@gmail.com>
|
||||
@@ -524,6 +534,7 @@ Jan Ziak <0xe2.0x9a.0x9b@gmail.com>
|
||||
Jani Monoses <jani.monoses@ubuntu.com> <jani.monoses@gmail.com>
|
||||
Jaroslavas Počepko <jp@webmaster.ms>
|
||||
Jason Barnett <jason.w.barnett@gmail.com>
|
||||
Jason Buberel <jbuberel@google.com>
|
||||
Jason Del Ponte <delpontej@gmail.com>
|
||||
Jason Hall <jasonhall@google.com>
|
||||
Jason Smale <jsmale@zendesk.com>
|
||||
@@ -593,6 +604,7 @@ Jonathan Rudenberg <jonathan@titanous.com>
|
||||
Jonathan Wills <runningwild@gmail.com>
|
||||
Jongmin Kim <atomaths@gmail.com>
|
||||
Joonas Kuorilehto <joneskoo@derbian.fi>
|
||||
Joop Kiefte <ikojba@gmail.com> <joop@kiefte.net>
|
||||
Jordan Lewis <jordanthelewis@gmail.com>
|
||||
Jos Visser <josv@google.com>
|
||||
Jose Luis Vázquez González <josvazg@gmail.com>
|
||||
@@ -680,6 +692,7 @@ Luke Curley <qpingu@gmail.com>
|
||||
Luna Duclos <luna.duclos@palmstonegames.com>
|
||||
Luuk van Dijk <lvd@golang.org> <lvd@google.com>
|
||||
Lynn Boger <laboger@linux.vnet.ibm.com>
|
||||
Maksym Trykur <maksym.trykur@gmail.com>
|
||||
Mal Curtis <mal@mal.co.nz>
|
||||
Manfred Touron <m@42.am>
|
||||
Manoj Dayaram <platform-dev@moovweb.com> <manoj.dayaram@moovweb.com>
|
||||
@@ -736,6 +749,7 @@ Matthew Denton <mdenton@skyportsystems.com>
|
||||
Matthew Holt <Matthew.Holt+git@gmail.com>
|
||||
Matthew Horsnell <matthew.horsnell@gmail.com>
|
||||
Matthieu Hauglustaine <matt.hauglustaine@gmail.com>
|
||||
Matthieu Olivier <olivier.matthieu@gmail.com>
|
||||
Max Riveiro <kavu13@gmail.com>
|
||||
Maxim Khitrov <max@mxcrypt.com>
|
||||
Maxim Pimenov <mpimenov@google.com>
|
||||
@@ -820,6 +834,7 @@ Nicholas Waples <nwaples@gmail.com>
|
||||
Nick Cooper <nmvc@google.com>
|
||||
Nick Craig-Wood <nick@craig-wood.com> <nickcw@gmail.com>
|
||||
Nick Harper <nharper@google.com>
|
||||
Nick Leli <nicholasleli@gmail.com>
|
||||
Nick Patavalis <nick.patavalis@gmail.com>
|
||||
Nick Petroni <npetroni@cs.umd.edu>
|
||||
Nicolas Kaiser <nikai@nikai.net>
|
||||
@@ -828,6 +843,7 @@ Nicolas S. Dade <nic.dade@gmail.com>
|
||||
Niels Widger <niels.widger@gmail.com>
|
||||
Nigel Kerr <nigel.kerr@gmail.com>
|
||||
Nigel Tao <nigeltao@golang.org>
|
||||
Nik Nyby <nnyby@columbia.edu>
|
||||
Niko Dziemba <niko@dziemba.com>
|
||||
Nikolay Turpitko <nikolay@turpitko.com>
|
||||
Noah Campbell <noahcampbell@gmail.com>
|
||||
@@ -910,14 +926,17 @@ Quan Tran <qeed.quan@gmail.com>
|
||||
Quan Yong Zhai <qyzhai@gmail.com>
|
||||
Quentin Perez <qperez@ocs.online.net>
|
||||
Quentin Smith <quentin@golang.org>
|
||||
Quinn Slack <sqs@sourcegraph.com>
|
||||
Quoc-Viet Nguyen <afelion@gmail.com>
|
||||
Radu Berinde <radu@cockroachlabs.com>
|
||||
Rafal Jeczalik <rjeczalik@gmail.com>
|
||||
Rahul Chaudhry <rahulchaudhry@chromium.org>
|
||||
Raif S. Naffah <go@naffah-raif.name>
|
||||
Rajat Goel <rajat.goel2010@gmail.com>
|
||||
Ralph Corderoy <ralph@inputplus.co.uk>
|
||||
Ramesh Dharan <dharan@google.com>
|
||||
Raph Levien <raph@google.com>
|
||||
Raphael Geronimi <raphael.geronimi@gmail.com>
|
||||
Raul Silvera <rsilvera@google.com>
|
||||
Rebecca Stambler <rstambler@golang.org>
|
||||
Reinaldo de Souza Jr <juniorz@gmail.com>
|
||||
@@ -960,6 +979,7 @@ Rowan Worth <sqweek@gmail.com>
|
||||
Rui Ueyama <ruiu@google.com>
|
||||
Russ Cox <rsc@golang.org>
|
||||
Russell Haering <russellhaering@gmail.com>
|
||||
Ryan Bagwell <ryanbagwell@outlook.com>
|
||||
Ryan Barrett <ryanb@google.com>
|
||||
Ryan Brown <ribrdb@google.com>
|
||||
Ryan Hitchman <hitchmanr@gmail.com>
|
||||
@@ -1030,6 +1050,7 @@ Stéphane Travostino <stephane.travostino@gmail.com>
|
||||
Stephen Ma <stephenm@golang.org>
|
||||
Stephen McQuay <stephen@mcquay.me>
|
||||
Stephen Weinberg <stephen@q5comm.com>
|
||||
Steve Francia <spf@golang.org>
|
||||
Steve McCoy <mccoyst@gmail.com>
|
||||
Steve Newman <snewman@google.com>
|
||||
Steve Phillips <elimisteve@gmail.com>
|
||||
@@ -1092,6 +1113,7 @@ Trevor Strohman <trevor.strohman@gmail.com>
|
||||
Trey Lawrence <lawrence.trey@gmail.com>
|
||||
Trey Tacon <ttacon@gmail.com>
|
||||
Tristan Amini <tamini01@ca.ibm.com>
|
||||
Tristan Colgate <tcolgate@gmail.com>
|
||||
Tristan Ooohry <ooohry@gmail.com>
|
||||
Tudor Golubenco <tudor.g@gmail.com>
|
||||
Tuo Shan <sturbo89@gmail.com> <shantuo@google.com>
|
||||
@@ -1157,4 +1179,5 @@ Zev Goldstein <zev.goldstein@gmail.com>
|
||||
Zhongwei Yao <zhongwei.yao@arm.com>
|
||||
Ziad Hatahet <hatahet@gmail.com>
|
||||
Zorion Arrizabalaga <zorionk@gmail.com>
|
||||
Фахриддин Балтаев <faxriddinjon@gmail.com>
|
||||
申习之 <bronze1man@gmail.com>
|
||||
|
||||
@@ -176,7 +176,6 @@ pkg expvar, method (*Float) Value() float64
|
||||
pkg expvar, method (Func) Value() interface{}
|
||||
pkg expvar, method (*Int) Value() int64
|
||||
pkg expvar, method (*String) Value() string
|
||||
pkg go/build, type NoGoError struct, Ignored bool
|
||||
pkg go/doc, func IsPredeclared(string) bool
|
||||
pkg go/types, func Default(Type) Type
|
||||
pkg go/types, func IdenticalIgnoreTags(Type, Type) bool
|
||||
|
||||
38
doc/asm.html
38
doc/asm.html
@@ -838,6 +838,44 @@ It is a scaled mode as on the x86, but the only scale allowed is <code>1</code>.
|
||||
|
||||
</ul>
|
||||
|
||||
<h3 id="mips">MIPS, MIPS64</h3>
|
||||
|
||||
<p>
|
||||
General purpose registers are named <code>R0</code> through <code>R31</code>,
|
||||
floating point registers are <code>F0</code> through <code>F31</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<code>R30</code> is reserved to point to <code>g</code>.
|
||||
<code>R23</code> is used as a temporary register.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In a <code>TEXT</code> directive, the frame size <code>$-4</code> for MIPS or
|
||||
<code>$-8</code> for MIPS64 instructs the linker not to save <code>LR</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<code>SP</code> refers to the virtual stack pointer.
|
||||
For the hardware register, use <code>R29</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Addressing modes:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
<code>16(R1)</code>: The location at <code>R1</code> plus 16.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<code>(R1)</code>: Alias for <code>0(R1)</code>.
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<h3 id="unsupported_opcodes">Unsupported opcodes</h3>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -160,9 +160,13 @@ $ <b>export GOPATH=$(go env GOPATH)</b>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
To learn more about setting up the <code>GOPATH</code> environment variable,
|
||||
please see
|
||||
<a href="/cmd/go/#hdr-GOPATH_environment_variable"><code>'go help gopath'</code></a>
|
||||
To learn more about the <code>GOPATH</code> environment variable, see
|
||||
<a href="/cmd/go/#hdr-GOPATH_environment_variable"><code>'go help gopath'</code></a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To use a custom workspace location,
|
||||
<a href="https://golang.org/wiki/SettingGOPATH">set the <code>GOPATH</code> environment variable</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="ImportPaths">Import paths</h3>
|
||||
|
||||
@@ -327,6 +327,18 @@ see improvements closer to the 32-bit ARM numbers.
|
||||
|
||||
<h3 id="cmd_cgo">Cgo</h3>
|
||||
|
||||
<p> <!-- CL 31141 -->
|
||||
The Go tool now remembers the value of the <code>CGO_ENABLED</code> environment
|
||||
variable set during <code>make.bash</code> and applies it to all future compilations
|
||||
by default to fix issue <a href="https://golang.org/issue/12808">#12808</a>.
|
||||
When doing native compilation, it is rarely necessary to explicitly set
|
||||
the <code>CGO_ENABLED</code> environment variable as <code>make.bash</code>
|
||||
will detect the correct setting automatically. The main reason to explicitly
|
||||
set the <code>CGO_ENABLED</code> environment variable is when your environment
|
||||
supports cgo, but you explicitly do not want cgo support, in which case, set
|
||||
<code>CGO_ENABLED=0</code> during <code>make.bash</code> or <code>all.bash</code>.
|
||||
</p>
|
||||
|
||||
<p> <!-- CL 29991 -->
|
||||
The environment variable <code>PKG_CONFIG</code> may now be used to
|
||||
set the program to run to handle <code>#cgo</code> <code>pkg-config</code>
|
||||
@@ -379,6 +391,15 @@ version of gccgo.
|
||||
<code>%USERPROFILE%/go</code> on Windows.
|
||||
</p>
|
||||
|
||||
<h3 id="go_get">Go get</h3>
|
||||
|
||||
<p> <!-- CL 34818 -->
|
||||
The “<code>go</code> <code>get</code>” command now always respects
|
||||
HTTP proxy environment variables, regardless of whether
|
||||
the <code style='white-space:nowrap'>-insecure</code> flag is used. In previous releases, the
|
||||
<code style='white-space:nowrap'>-insecure</code> flag had the side effect of not using proxies.
|
||||
</p>
|
||||
|
||||
<h3 id="go_bug">Go bug</h3>
|
||||
|
||||
<p>
|
||||
@@ -619,6 +640,13 @@ now implements the new
|
||||
<a href="/pkg/runtime/#SetMutexProfileFraction"><code>SetMutexProfileFraction</code></a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A known limitation for Go 1.8 is that the profile only reports contention for
|
||||
<a href="/pkg/sync/#Mutex"><code>sync.Mutex</code></a>,
|
||||
not
|
||||
<a href="/pkg/sync/#RWMutex"><code>sync.RWMutex</code></a>.
|
||||
</p>
|
||||
|
||||
<h3 id="minor_library_changes">Minor changes to the library</h3>
|
||||
|
||||
<p>
|
||||
@@ -642,23 +670,6 @@ Optimizations and minor bug fixes are not listed.
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="archive_zip"><dt><a href="/pkg/archive/zip/">archive/zip</a></dt>
|
||||
<dd>
|
||||
|
||||
<p> <!-- CL 18274 -->
|
||||
The
|
||||
<a href="/pkg/archive/zip/#Reader"><code>Reader</code></a>
|
||||
now supports modification times in
|
||||
the NTFS, UNIX, and Extended Time Stamp metadata fields.
|
||||
<!-- CL 30811 -->
|
||||
The
|
||||
<a href="/pkg/archive/zip/#Writer"><code>Writer</code></a>
|
||||
now writes Extended Time Stamp fields.
|
||||
</p>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="compress_flate"><dt><a href="/pkg/compress/flate/">compress/flate</a></dt>
|
||||
<dd>
|
||||
|
||||
@@ -1288,9 +1299,17 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
|
||||
</li>
|
||||
|
||||
<li><!-- CL 31733, CL 29852 -->
|
||||
The <code>Client</code> now supports 307 and 308 redirects.
|
||||
If the redirect requires resending the request body,
|
||||
the request must have the new
|
||||
The <code>Client</code> now supports 301, 307, and 308 redirects.
|
||||
|
||||
For example, <code>Client.Post</code> now follows 301
|
||||
redirects, converting them to <code>GET</code> requests
|
||||
without bodies, like it did for 302 and 303 redirect responses
|
||||
previously.
|
||||
|
||||
The <code>Client</code> now also follows 307 and 308
|
||||
redirects, preserving the original request method and body, if
|
||||
any. If the redirect requires resending the request body, the
|
||||
request must have the new
|
||||
<a href="/pkg/net/http/#Request"><code>Request.GetBody</code></a>
|
||||
field defined.
|
||||
<a href="pkg/net/http/#NewRequest"><code>NewRequest</code></a>
|
||||
|
||||
@@ -246,12 +246,12 @@ Then build it with the <code>go</code> tool:
|
||||
</p>
|
||||
|
||||
<pre class="testUnix">
|
||||
$ <b>cd $HOME/go/src/hello
|
||||
$ <b>cd $HOME/go/src/hello</b>
|
||||
$ <b>go build</b>
|
||||
</pre>
|
||||
|
||||
<pre class="testWindows" style="display: none">
|
||||
C:\> <b>cd %USERPROFILE%\go\src\hello<b>
|
||||
C:\> <b>cd %USERPROFILE%\go\src\hello</b>
|
||||
C:\Users\Gopher\go\src\hello> <b>go build</b>
|
||||
</pre>
|
||||
|
||||
@@ -313,16 +313,10 @@ environment variables under Windows</a>.
|
||||
<h2 id="help">Getting help</h2>
|
||||
|
||||
<p>
|
||||
For real-time help, ask the helpful gophers in <code>#go-nuts</code> on the
|
||||
<a href="http://freenode.net/">Freenode</a> IRC server.
|
||||
For help, see the <a href="/help/">list of Go mailing lists, forums, and places to chat</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The official mailing list for discussion of the Go language is
|
||||
<a href="//groups.google.com/group/golang-nuts">Go Nuts</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Report bugs using the
|
||||
<a href="//golang.org/issue">Go issue tracker</a>.
|
||||
Report bugs either by running “<b><code>go</code> <code>bug</code></b>”, or
|
||||
manually at the <a href="https://golang.org/issue">Go issue tracker</a>.
|
||||
</p>
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
# Consult http://www.iana.org/time-zones for the latest versions.
|
||||
|
||||
# Versions to use.
|
||||
CODE=2016i
|
||||
DATA=2016i
|
||||
CODE=2016j
|
||||
DATA=2016j
|
||||
|
||||
set -e
|
||||
rm -rf work
|
||||
|
||||
Binary file not shown.
@@ -37,6 +37,31 @@ func test18146(t *testing.T) {
|
||||
attempts = 100
|
||||
}
|
||||
|
||||
// Restrict the number of attempts based on RLIMIT_NPROC.
|
||||
// Tediously, RLIMIT_NPROC was left out of the syscall package,
|
||||
// probably because it is not in POSIX.1, so we define it here.
|
||||
// It is not defined on Solaris.
|
||||
var nproc int
|
||||
setNproc := true
|
||||
switch runtime.GOOS {
|
||||
default:
|
||||
setNproc = false
|
||||
case "linux":
|
||||
nproc = 6
|
||||
case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd":
|
||||
nproc = 7
|
||||
}
|
||||
if setNproc {
|
||||
var rlim syscall.Rlimit
|
||||
if syscall.Getrlimit(nproc, &rlim) == nil {
|
||||
max := int(rlim.Cur) / (threads + 5)
|
||||
if attempts > max {
|
||||
t.Logf("lowering attempts from %d to %d for RLIMIT_NPROC", attempts, max)
|
||||
attempts = max
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if os.Getenv("test18146") == "exec" {
|
||||
runtime.GOMAXPROCS(1)
|
||||
for n := threads; n > 0; n-- {
|
||||
|
||||
@@ -21,7 +21,7 @@ int main(void) {
|
||||
|
||||
// The descriptor will be initialized in a thread, so we have to
|
||||
// give a chance to get opened.
|
||||
for (i = 0; i < 100; i++) {
|
||||
for (i = 0; i < 1000; i++) {
|
||||
n = read(fd, buf, sizeof buf);
|
||||
if (n >= 0)
|
||||
break;
|
||||
|
||||
@@ -24,8 +24,14 @@ msan=yes
|
||||
|
||||
TMPDIR=${TMPDIR:-/tmp}
|
||||
echo 'int main() { return 0; }' > ${TMPDIR}/testsanitizers$$.c
|
||||
if $CC -fsanitize=memory -c ${TMPDIR}/testsanitizers$$.c -o ${TMPDIR}/testsanitizers$$.o 2>&1 | grep "unrecognized" >& /dev/null; then
|
||||
echo "skipping msan tests: -fsanitize=memory not supported"
|
||||
if $CC -fsanitize=memory -o ${TMPDIR}/testsanitizers$$ ${TMPDIR}/testsanitizers$$.c 2>&1 | grep "unrecognized" >& /dev/null; then
|
||||
echo "skipping msan tests: $CC -fsanitize=memory not supported"
|
||||
msan=no
|
||||
elif ! test -x ${TMPDIR}/testsanitizers$$; then
|
||||
echo "skipping msan tests: $CC -fsanitize-memory did not generate an executable"
|
||||
msan=no
|
||||
elif ! ${TMPDIR}/testsanitizers$$ >/dev/null 2>&1; then
|
||||
echo "skipping msan tests: $CC -fsanitize-memory generates broken executable"
|
||||
msan=no
|
||||
fi
|
||||
rm -f ${TMPDIR}/testsanitizers$$.*
|
||||
|
||||
@@ -6,7 +6,8 @@ package main
|
||||
|
||||
// This program failed when run under the C/C++ ThreadSanitizer. The
|
||||
// TSAN library was not keeping track of whether signals should be
|
||||
// delivered on the alternate signal stack.
|
||||
// delivered on the alternate signal stack, and the Go signal handler
|
||||
// was not preserving callee-saved registers from C callers.
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -g -fsanitize=thread
|
||||
@@ -19,10 +20,14 @@ void spin() {
|
||||
size_t n;
|
||||
struct timeval tvstart, tvnow;
|
||||
int diff;
|
||||
void *prev = NULL, *cur;
|
||||
|
||||
gettimeofday(&tvstart, NULL);
|
||||
for (n = 0; n < 1<<20; n++) {
|
||||
free(malloc(n));
|
||||
cur = malloc(n);
|
||||
free(prev);
|
||||
prev = cur;
|
||||
|
||||
gettimeofday(&tvnow, NULL);
|
||||
diff = (tvnow.tv_sec - tvstart.tv_sec) * 1000 * 1000 + (tvnow.tv_usec - tvstart.tv_usec);
|
||||
|
||||
@@ -32,6 +37,8 @@ void spin() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(prev);
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
@@ -12,6 +12,13 @@ import (
|
||||
func DeclaredInMain() {
|
||||
}
|
||||
|
||||
type C struct {
|
||||
}
|
||||
|
||||
func F() *C {
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
defer depBase.ImplementedInAsm()
|
||||
// This code below causes various go.itab.* symbols to be generated in
|
||||
@@ -20,4 +27,9 @@ func main() {
|
||||
reflect.TypeOf(os.Stdout).Elem()
|
||||
runtime.GC()
|
||||
depBase.V = depBase.F() + 1
|
||||
|
||||
var c *C
|
||||
if reflect.TypeOf(F).Out(0) != reflect.TypeOf(c) {
|
||||
panic("bad reflection results, see golang.org/issue/18252")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,4 +17,4 @@ else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec $CLANG -arch $CLANGARCH -isysroot $SDK_PATH "$@"
|
||||
exec $CLANG -arch $CLANGARCH -isysroot $SDK_PATH -mios-version-min=6.0 "$@"
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"hash/crc32"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -290,16 +289,13 @@ func readDirectoryHeader(f *File, r io.Reader) error {
|
||||
// Other zip authors might not even follow the basic format,
|
||||
// and we'll just ignore the Extra content in that case.
|
||||
b := readBuf(f.Extra)
|
||||
|
||||
Extras:
|
||||
for len(b) >= 4 { // need at least tag and size
|
||||
tag := b.uint16()
|
||||
size := b.uint16()
|
||||
if int(size) > len(b) {
|
||||
break
|
||||
}
|
||||
switch tag {
|
||||
case zip64ExtraId:
|
||||
if tag == zip64ExtraId {
|
||||
// update directory values from the zip64 extra block.
|
||||
// They should only be consulted if the sizes read earlier
|
||||
// are maxed out.
|
||||
@@ -327,42 +323,7 @@ func readDirectoryHeader(f *File, r io.Reader) error {
|
||||
}
|
||||
f.headerOffset = int64(eb.uint64())
|
||||
}
|
||||
break Extras
|
||||
|
||||
case ntfsExtraId:
|
||||
if size == 32 {
|
||||
eb := readBuf(b[:size])
|
||||
eb.uint32() // reserved
|
||||
eb.uint16() // tag1
|
||||
size1 := eb.uint16()
|
||||
if size1 == 24 {
|
||||
sub := readBuf(eb[:size1])
|
||||
lo := sub.uint32()
|
||||
hi := sub.uint32()
|
||||
tick := (uint64(uint64(lo)|uint64(hi)<<32) - 116444736000000000) / 10000000
|
||||
f.SetModTime(time.Unix(int64(tick), 0))
|
||||
}
|
||||
}
|
||||
break Extras
|
||||
|
||||
case unixExtraId:
|
||||
if size >= 12 {
|
||||
eb := readBuf(b[:size])
|
||||
eb.uint32() // AcTime
|
||||
epoch := eb.uint32() // ModTime
|
||||
f.SetModTime(time.Unix(int64(epoch), 0))
|
||||
break Extras
|
||||
}
|
||||
case exttsExtraId:
|
||||
if size >= 3 {
|
||||
eb := readBuf(b[:size])
|
||||
flags := eb.uint8() // Flags
|
||||
epoch := eb.uint32() // AcTime/ModTime/CrTime
|
||||
if flags&1 != 0 {
|
||||
f.SetModTime(time.Unix(int64(epoch), 0))
|
||||
}
|
||||
break Extras
|
||||
}
|
||||
break
|
||||
}
|
||||
b = b[size:]
|
||||
}
|
||||
@@ -547,12 +508,6 @@ func findSignatureInBlock(b []byte) int {
|
||||
|
||||
type readBuf []byte
|
||||
|
||||
func (b *readBuf) uint8() uint8 {
|
||||
v := uint8((*b)[0])
|
||||
*b = (*b)[1:]
|
||||
return v
|
||||
}
|
||||
|
||||
func (b *readBuf) uint16() uint16 {
|
||||
v := binary.LittleEndian.Uint16(*b)
|
||||
*b = (*b)[2:]
|
||||
|
||||
@@ -65,13 +65,13 @@ var tests = []ZipTest{
|
||||
{
|
||||
Name: "test.txt",
|
||||
Content: []byte("This is a test text file.\n"),
|
||||
Mtime: "09-05-10 02:12:00",
|
||||
Mtime: "09-05-10 12:12:02",
|
||||
Mode: 0644,
|
||||
},
|
||||
{
|
||||
Name: "gophercolor16x16.png",
|
||||
File: "gophercolor16x16.png",
|
||||
Mtime: "09-05-10 05:52:58",
|
||||
Mtime: "09-05-10 15:52:58",
|
||||
Mode: 0644,
|
||||
},
|
||||
},
|
||||
@@ -83,13 +83,13 @@ var tests = []ZipTest{
|
||||
{
|
||||
Name: "test.txt",
|
||||
Content: []byte("This is a test text file.\n"),
|
||||
Mtime: "09-05-10 02:12:00",
|
||||
Mtime: "09-05-10 12:12:02",
|
||||
Mode: 0644,
|
||||
},
|
||||
{
|
||||
Name: "gophercolor16x16.png",
|
||||
File: "gophercolor16x16.png",
|
||||
Mtime: "09-05-10 05:52:58",
|
||||
Mtime: "09-05-10 15:52:58",
|
||||
Mode: 0644,
|
||||
},
|
||||
},
|
||||
@@ -144,17 +144,6 @@ var tests = []ZipTest{
|
||||
Name: "unix.zip",
|
||||
File: crossPlatform,
|
||||
},
|
||||
{
|
||||
Name: "extra-timestamp.zip",
|
||||
File: []ZipTestFile{
|
||||
{
|
||||
Name: "hello.txt",
|
||||
Content: []byte(""),
|
||||
Mtime: "01-06-16 12:25:56",
|
||||
Mode: 0666,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// created by Go, before we wrote the "optional" data
|
||||
// descriptor signatures (which are required by OS X)
|
||||
@@ -163,13 +152,13 @@ var tests = []ZipTest{
|
||||
{
|
||||
Name: "foo.txt",
|
||||
Content: []byte("foo\n"),
|
||||
Mtime: "03-09-12 00:59:10",
|
||||
Mtime: "03-08-12 16:59:10",
|
||||
Mode: 0644,
|
||||
},
|
||||
{
|
||||
Name: "bar.txt",
|
||||
Content: []byte("bar\n"),
|
||||
Mtime: "03-09-12 00:59:12",
|
||||
Mtime: "03-08-12 16:59:12",
|
||||
Mode: 0644,
|
||||
},
|
||||
},
|
||||
@@ -216,13 +205,13 @@ var tests = []ZipTest{
|
||||
{
|
||||
Name: "foo.txt",
|
||||
Content: []byte("foo\n"),
|
||||
Mtime: "03-09-12 00:59:10",
|
||||
Mtime: "03-08-12 16:59:10",
|
||||
Mode: 0644,
|
||||
},
|
||||
{
|
||||
Name: "bar.txt",
|
||||
Content: []byte("bar\n"),
|
||||
Mtime: "03-09-12 00:59:12",
|
||||
Mtime: "03-08-12 16:59:12",
|
||||
Mode: 0644,
|
||||
},
|
||||
},
|
||||
@@ -236,14 +225,14 @@ var tests = []ZipTest{
|
||||
{
|
||||
Name: "foo.txt",
|
||||
Content: []byte("foo\n"),
|
||||
Mtime: "03-09-12 00:59:10",
|
||||
Mtime: "03-08-12 16:59:10",
|
||||
Mode: 0644,
|
||||
ContentErr: ErrChecksum,
|
||||
},
|
||||
{
|
||||
Name: "bar.txt",
|
||||
Content: []byte("bar\n"),
|
||||
Mtime: "03-09-12 00:59:12",
|
||||
Mtime: "03-08-12 16:59:12",
|
||||
Mode: 0644,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -63,9 +63,6 @@ const (
|
||||
|
||||
// extra header id's
|
||||
zip64ExtraId = 0x0001 // zip64 Extended Information Extra Field
|
||||
ntfsExtraId = 0x000a // NTFS Extra Field
|
||||
unixExtraId = 0x000d // UNIX Extra Field
|
||||
exttsExtraId = 0x5455 // Extended Timestamp Extra Field
|
||||
)
|
||||
|
||||
// FileHeader describes a file within a zip file.
|
||||
|
||||
BIN
src/archive/zip/testdata/extra-timestamp.zip
vendored
BIN
src/archive/zip/testdata/extra-timestamp.zip
vendored
Binary file not shown.
@@ -103,18 +103,6 @@ func (w *Writer) Close() error {
|
||||
b.uint32(h.UncompressedSize)
|
||||
}
|
||||
|
||||
// use Extended Timestamp Extra Field.
|
||||
if h.ModifiedTime != 0 || h.ModifiedDate != 0 {
|
||||
mt := uint32(h.ModTime().Unix())
|
||||
var mbuf [9]byte // 2x uint16 + uint8 + uint32
|
||||
eb := writeBuf(mbuf[:])
|
||||
eb.uint16(exttsExtraId)
|
||||
eb.uint16(5) // size = uint8 + uint32
|
||||
eb.uint8(1) // flags = modtime
|
||||
eb.uint32(mt) // ModTime
|
||||
h.Extra = append(h.Extra, mbuf[:]...)
|
||||
}
|
||||
|
||||
b.uint16(uint16(len(h.Name)))
|
||||
b.uint16(uint16(len(h.Extra)))
|
||||
b.uint16(uint16(len(h.Comment)))
|
||||
@@ -397,11 +385,6 @@ func (w nopCloser) Close() error {
|
||||
|
||||
type writeBuf []byte
|
||||
|
||||
func (b *writeBuf) uint8(v uint8) {
|
||||
(*b)[0] = v
|
||||
*b = (*b)[1:]
|
||||
}
|
||||
|
||||
func (b *writeBuf) uint16(v uint16) {
|
||||
binary.LittleEndian.PutUint16(*b, v)
|
||||
*b = (*b)[2:]
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"math/rand"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TODO(adg): a more sophisticated test suite
|
||||
@@ -21,7 +20,6 @@ type WriteTest struct {
|
||||
Data []byte
|
||||
Method uint16
|
||||
Mode os.FileMode
|
||||
Mtime string
|
||||
}
|
||||
|
||||
var writeTests = []WriteTest{
|
||||
@@ -30,35 +28,30 @@ var writeTests = []WriteTest{
|
||||
Data: []byte("Rabbits, guinea pigs, gophers, marsupial rats, and quolls."),
|
||||
Method: Store,
|
||||
Mode: 0666,
|
||||
Mtime: "02-01-08 00:01:02",
|
||||
},
|
||||
{
|
||||
Name: "bar",
|
||||
Data: nil, // large data set in the test
|
||||
Method: Deflate,
|
||||
Mode: 0644,
|
||||
Mtime: "03-02-08 01:02:03",
|
||||
},
|
||||
{
|
||||
Name: "setuid",
|
||||
Data: []byte("setuid file"),
|
||||
Method: Deflate,
|
||||
Mode: 0755 | os.ModeSetuid,
|
||||
Mtime: "04-03-08 02:03:04",
|
||||
},
|
||||
{
|
||||
Name: "setgid",
|
||||
Data: []byte("setgid file"),
|
||||
Method: Deflate,
|
||||
Mode: 0755 | os.ModeSetgid,
|
||||
Mtime: "05-04-08 03:04:04",
|
||||
},
|
||||
{
|
||||
Name: "symlink",
|
||||
Data: []byte("../link/target"),
|
||||
Method: Deflate,
|
||||
Mode: 0755 | os.ModeSymlink,
|
||||
Mtime: "03-02-08 11:22:33",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -155,11 +148,6 @@ func testCreate(t *testing.T, w *Writer, wt *WriteTest) {
|
||||
if wt.Mode != 0 {
|
||||
header.SetMode(wt.Mode)
|
||||
}
|
||||
mtime, err := time.Parse("01-02-06 15:04:05", wt.Mtime)
|
||||
if err != nil {
|
||||
t.Fatal("time.Parse:", err)
|
||||
}
|
||||
header.SetModTime(mtime)
|
||||
f, err := w.CreateHeader(header)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -190,21 +178,6 @@ func testReadFile(t *testing.T, f *File, wt *WriteTest) {
|
||||
if !bytes.Equal(b, wt.Data) {
|
||||
t.Errorf("File contents %q, want %q", b, wt.Data)
|
||||
}
|
||||
|
||||
mtime, err := time.Parse("01-02-06 15:04:05", wt.Mtime)
|
||||
if err != nil {
|
||||
t.Fatal("time.Parse:", err)
|
||||
}
|
||||
|
||||
diff := mtime.Sub(f.ModTime())
|
||||
if diff < 0 {
|
||||
diff = -diff
|
||||
}
|
||||
|
||||
// allow several time span
|
||||
if diff > 5*time.Second {
|
||||
t.Errorf("File modtime %v, want %v", mtime, f.ModTime())
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCompressedZipGarbage(b *testing.B) {
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
"internal/testenv"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -114,44 +113,6 @@ func TestFileHeaderRoundTrip64(t *testing.T) {
|
||||
testHeaderRoundTrip(fh, uint32max, fh.UncompressedSize64, t)
|
||||
}
|
||||
|
||||
func TestZeroFileRoundTrip(t *testing.T) {
|
||||
var b bytes.Buffer
|
||||
w := NewWriter(&b)
|
||||
if _, err := w.Create(""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := w.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
r, err := NewReader(bytes.NewReader(b.Bytes()), int64(b.Len()))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Verify that fields that should reasonably be the zero value stays
|
||||
// as the zero value.
|
||||
var want FileHeader
|
||||
if len(r.File) != 1 {
|
||||
t.Fatalf("len(r.File) = %d, want 1", len(r.File))
|
||||
}
|
||||
fh := r.File[0].FileHeader
|
||||
got := FileHeader{
|
||||
Name: fh.Name,
|
||||
ModifiedTime: fh.ModifiedTime,
|
||||
ModifiedDate: fh.ModifiedDate,
|
||||
UncompressedSize: fh.UncompressedSize,
|
||||
UncompressedSize64: fh.UncompressedSize64,
|
||||
ExternalAttrs: fh.ExternalAttrs,
|
||||
Comment: fh.Comment,
|
||||
}
|
||||
if len(fh.Extra) > 0 {
|
||||
got.Extra = fh.Extra
|
||||
}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("FileHeader mismatch:\ngot %#v\nwant %#v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
type repeatedByte struct {
|
||||
off int64
|
||||
b byte
|
||||
|
||||
@@ -23,7 +23,7 @@ type Buffer struct {
|
||||
|
||||
// The readOp constants describe the last action performed on
|
||||
// the buffer, so that UnreadRune and UnreadByte can check for
|
||||
// invalid usage. opReadRuneX constants are choosen such that
|
||||
// invalid usage. opReadRuneX constants are chosen such that
|
||||
// converted to int they correspond to the rune size that was read.
|
||||
type readOp int
|
||||
|
||||
|
||||
@@ -175,6 +175,14 @@ func f(b []byte, i int) uint64 {
|
||||
},
|
||||
{"amd64", "linux", `
|
||||
import "encoding/binary"
|
||||
func f(b []byte, v uint64) {
|
||||
binary.BigEndian.PutUint64(b, v)
|
||||
}
|
||||
`,
|
||||
[]string{"\tBSWAPQ\t"},
|
||||
},
|
||||
{"amd64", "linux", `
|
||||
import "encoding/binary"
|
||||
func f(b []byte) uint32 {
|
||||
return binary.BigEndian.Uint32(b)
|
||||
}
|
||||
@@ -186,6 +194,14 @@ import "encoding/binary"
|
||||
func f(b []byte, i int) uint32 {
|
||||
return binary.BigEndian.Uint32(b[i:])
|
||||
}
|
||||
`,
|
||||
[]string{"\tBSWAPL\t"},
|
||||
},
|
||||
{"amd64", "linux", `
|
||||
import "encoding/binary"
|
||||
func f(b []byte, v uint32) {
|
||||
binary.BigEndian.PutUint32(b, v)
|
||||
}
|
||||
`,
|
||||
[]string{"\tBSWAPL\t"},
|
||||
},
|
||||
@@ -205,6 +221,19 @@ func f(b []byte, i int) uint32 {
|
||||
`,
|
||||
[]string{"\tMOVL\t\\(.*\\)\\(.*\\*1\\),"},
|
||||
},
|
||||
|
||||
// Structure zeroing. See issue #18370.
|
||||
{"amd64", "linux", `
|
||||
type T struct {
|
||||
a, b, c int
|
||||
}
|
||||
func f(t *T) {
|
||||
*t = T{}
|
||||
}
|
||||
`,
|
||||
[]string{"\tMOVQ\t\\$0, \\(.*\\)", "\tMOVQ\t\\$0, 8\\(.*\\)", "\tMOVQ\t\\$0, 16\\(.*\\)"},
|
||||
},
|
||||
// TODO: add a test for *t = T{3,4,5} when we fix that.
|
||||
}
|
||||
|
||||
// mergeEnvLists merges the two environment lists such that
|
||||
|
||||
@@ -1000,7 +1000,7 @@ func parName(f *Field, numbered bool) string {
|
||||
Fatalf("invalid symbol name: %s", name)
|
||||
}
|
||||
|
||||
// Functions that can be inlined use numbered parameters so we can distingish them
|
||||
// Functions that can be inlined use numbered parameters so we can distinguish them
|
||||
// from other names in their context after inlining (i.e., the parameter numbering
|
||||
// is a form of parameter rewriting). See issue 4326 for an example and test case.
|
||||
if forceObjFileStability || numbered {
|
||||
|
||||
@@ -15,6 +15,7 @@ var runtimeDecls = [...]struct {
|
||||
{"panicwrap", funcTag, 7},
|
||||
{"gopanic", funcTag, 9},
|
||||
{"gorecover", funcTag, 12},
|
||||
{"goschedguarded", funcTag, 5},
|
||||
{"printbool", funcTag, 14},
|
||||
{"printfloat", funcTag, 16},
|
||||
{"printint", funcTag, 18},
|
||||
|
||||
@@ -21,6 +21,7 @@ func panicwrap(string, string, string)
|
||||
|
||||
func gopanic(interface{})
|
||||
func gorecover(*int32) interface{}
|
||||
func goschedguarded()
|
||||
|
||||
func printbool(bool)
|
||||
func printfloat(float64)
|
||||
|
||||
@@ -1055,6 +1055,7 @@ func (p *noder) pragma(pos, line int, text string) syntax.Pragma {
|
||||
lookup(f[1]).Linkname = f[2]
|
||||
|
||||
case strings.HasPrefix(text, "go:cgo_"):
|
||||
lineno = p.baseline + int32(line) - 1 // pragcgo may call yyerror
|
||||
pragcgobuf += pragcgo(text)
|
||||
fallthrough // because of //go:cgo_unsafe_args
|
||||
default:
|
||||
@@ -1062,6 +1063,7 @@ func (p *noder) pragma(pos, line int, text string) syntax.Pragma {
|
||||
if i := strings.Index(text, " "); i >= 0 {
|
||||
verb = verb[:i]
|
||||
}
|
||||
lineno = p.baseline + int32(line) - 1 // pragmaValue may call yyerror
|
||||
return syntax.Pragma(pragmaValue(verb))
|
||||
}
|
||||
|
||||
|
||||
@@ -998,7 +998,6 @@ func itabname(t, itype *Type) *Node {
|
||||
Fatalf("itabname(%v, %v)", t, itype)
|
||||
}
|
||||
s := Pkglookup(t.tconv(FmtLeft)+","+itype.tconv(FmtLeft), itabpkg)
|
||||
Linksym(s).Set(obj.AttrLocal, true)
|
||||
if s.Def == nil {
|
||||
n := newname(s)
|
||||
n.Type = Types[TUINT8]
|
||||
@@ -1411,15 +1410,15 @@ func dumptypestructs() {
|
||||
// }
|
||||
o := dsymptr(i.sym, 0, dtypesym(i.itype), 0)
|
||||
o = dsymptr(i.sym, o, dtypesym(i.t), 0)
|
||||
o += Widthptr + 8 // skip link/bad/unused fields
|
||||
o += Widthptr + 8 // skip link/bad/inhash fields
|
||||
o += len(imethods(i.itype)) * Widthptr // skip fun method pointers
|
||||
// at runtime the itab will contain pointers to types, other itabs and
|
||||
// method functions. None are allocated on heap, so we can use obj.NOPTR.
|
||||
ggloblsym(i.sym, int32(o), int16(obj.DUPOK|obj.NOPTR|obj.LOCAL))
|
||||
ggloblsym(i.sym, int32(o), int16(obj.DUPOK|obj.NOPTR))
|
||||
|
||||
ilink := Pkglookup(i.t.tconv(FmtLeft)+","+i.itype.tconv(FmtLeft), itablinkpkg)
|
||||
dsymptr(ilink, 0, i.sym, 0)
|
||||
ggloblsym(ilink, int32(Widthptr), int16(obj.DUPOK|obj.RODATA|obj.LOCAL))
|
||||
ggloblsym(ilink, int32(Widthptr), int16(obj.DUPOK|obj.RODATA))
|
||||
}
|
||||
|
||||
// process ptabs
|
||||
|
||||
@@ -1078,6 +1078,8 @@ func anylit(n *Node, var_ *Node, init *Nodes) {
|
||||
|
||||
var r *Node
|
||||
if n.Right != nil {
|
||||
// n.Right is stack temporary used as backing store.
|
||||
init.Append(nod(OAS, n.Right, nil)) // zero backing store, just in case (#18410)
|
||||
r = nod(OADDR, n.Right, nil)
|
||||
r = typecheck(r, Erv)
|
||||
} else {
|
||||
@@ -1195,7 +1197,7 @@ func getlit(lit *Node) int {
|
||||
return -1
|
||||
}
|
||||
|
||||
// stataddr sets nam to the static address of n and reports whether it succeeeded.
|
||||
// stataddr sets nam to the static address of n and reports whether it succeeded.
|
||||
func stataddr(nam *Node, n *Node) bool {
|
||||
if n == nil {
|
||||
return false
|
||||
|
||||
@@ -64,6 +64,9 @@ func buildssa(fn *Node) *ssa.Func {
|
||||
s.config = initssa()
|
||||
s.f = s.config.NewFunc()
|
||||
s.f.Name = name
|
||||
if fn.Func.Pragma&Nosplit != 0 {
|
||||
s.f.NoSplit = true
|
||||
}
|
||||
s.exitCode = fn.Func.Exit
|
||||
s.panics = map[funcLine]*ssa.Block{}
|
||||
s.config.DebugTest = s.config.DebugHashMatch("GOSSAHASH", name)
|
||||
|
||||
@@ -213,7 +213,7 @@ func (t *Type) FuncType() *FuncType {
|
||||
return t.Extra.(*FuncType)
|
||||
}
|
||||
|
||||
// InterMethType contains Type fields specific to interface method psuedo-types.
|
||||
// InterMethType contains Type fields specific to interface method pseudo-types.
|
||||
type InterMethType struct {
|
||||
Nname *Node
|
||||
}
|
||||
|
||||
@@ -859,7 +859,7 @@ OpSwitch:
|
||||
}
|
||||
|
||||
if n.Type.Etype != TFUNC || !n.IsMethod() {
|
||||
yyerror("type %v has no method %S", n.Left.Type, n.Right.Sym)
|
||||
yyerror("type %v has no method %S", n.Left.Type, n.Sym)
|
||||
n.Type = nil
|
||||
return n
|
||||
}
|
||||
|
||||
@@ -694,6 +694,10 @@ opswitch:
|
||||
break
|
||||
}
|
||||
|
||||
if !instrumenting && iszero(n.Right) && !needwritebarrier(n.Left, n.Right) {
|
||||
break
|
||||
}
|
||||
|
||||
switch n.Right.Op {
|
||||
default:
|
||||
n.Right = walkexpr(n.Right, init)
|
||||
|
||||
@@ -6,7 +6,7 @@ package ssa
|
||||
|
||||
// checkbce prints all bounds checks that are present in the function.
|
||||
// Useful to find regressions. checkbce is only activated when with
|
||||
// corresponsing debug options, so it's off by default.
|
||||
// corresponding debug options, so it's off by default.
|
||||
// See test/checkbce.go
|
||||
func checkbce(f *Func) {
|
||||
if f.pass.debug <= 0 {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
package ssa
|
||||
|
||||
import (
|
||||
"cmd/internal/obj"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
@@ -349,6 +350,8 @@ var passes = [...]pass{
|
||||
{name: "writebarrier", fn: writebarrier, required: true}, // expand write barrier ops
|
||||
{name: "fuse", fn: fuse},
|
||||
{name: "dse", fn: dse},
|
||||
{name: "insert resched checks", fn: insertLoopReschedChecks,
|
||||
disabled: obj.Preemptibleloops_enabled == 0}, // insert resched checks in loops.
|
||||
{name: "tighten", fn: tighten}, // move values closer to their uses
|
||||
{name: "lower", fn: lower, required: true},
|
||||
{name: "lowered cse", fn: cse},
|
||||
@@ -378,7 +381,13 @@ type constraint struct {
|
||||
}
|
||||
|
||||
var passOrder = [...]constraint{
|
||||
// prove reliese on common-subexpression elimination for maximum benefits.
|
||||
// "insert resched checks" uses mem, better to clean out stores first.
|
||||
{"dse", "insert resched checks"},
|
||||
// insert resched checks adds new blocks containing generic instructions
|
||||
{"insert resched checks", "lower"},
|
||||
{"insert resched checks", "tighten"},
|
||||
|
||||
// prove relies on common-subexpression elimination for maximum benefits.
|
||||
{"generic cse", "prove"},
|
||||
// deadcode after prove to eliminate all new dead blocks.
|
||||
{"prove", "generic deadcode"},
|
||||
|
||||
@@ -93,7 +93,7 @@ type Logger interface {
|
||||
// Warnl writes compiler messages in the form expected by "errorcheck" tests
|
||||
Warnl(line int32, fmt_ string, args ...interface{})
|
||||
|
||||
// Fowards the Debug flags from gc
|
||||
// Forwards the Debug flags from gc
|
||||
Debug_checknil() bool
|
||||
Debug_wb() bool
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ type Func struct {
|
||||
vid idAlloc // value ID allocator
|
||||
|
||||
scheduled bool // Values in Blocks are in final order
|
||||
NoSplit bool // true if function is marked as nosplit. Used by schedule check pass.
|
||||
|
||||
// when register allocation is done, maps value ids to locations
|
||||
RegAlloc []Location
|
||||
|
||||
@@ -12,7 +12,7 @@ import "strings"
|
||||
// - Integer types live in the low portion of registers. Upper portions are junk.
|
||||
// - Boolean types use the low-order byte of a register. 0=false, 1=true.
|
||||
// Upper bytes are junk.
|
||||
// - *const instructions may use a constant larger than the instuction can encode.
|
||||
// - *const instructions may use a constant larger than the instruction can encode.
|
||||
// In this case the assembler expands to multiple instructions and uses tmp
|
||||
// register (R27).
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import "strings"
|
||||
// - Integer types live in the low portion of registers. Upper portions are junk.
|
||||
// - Boolean types use the low-order byte of a register. 0=false, 1=true.
|
||||
// Upper bytes are junk.
|
||||
// - *const instructions may use a constant larger than the instuction can encode.
|
||||
// - *const instructions may use a constant larger than the instruction can encode.
|
||||
// In this case the assembler expands to multiple instructions and uses tmp
|
||||
// register (R11).
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import "strings"
|
||||
// - Integer types live in the low portion of registers. Upper portions are junk.
|
||||
// - Boolean types use the low-order byte of a register. 0=false, 1=true.
|
||||
// Upper bytes are junk.
|
||||
// - *const instructions may use a constant larger than the instuction can encode.
|
||||
// - *const instructions may use a constant larger than the instruction can encode.
|
||||
// In this case the assembler expands to multiple instructions and uses tmp
|
||||
// register (R23).
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import "strings"
|
||||
// - Boolean types use the low-order byte of a register. 0=false, 1=true.
|
||||
// Upper bytes are junk.
|
||||
// - Unused portions of AuxInt are filled by sign-extending the used portion.
|
||||
// - *const instructions may use a constant larger than the instuction can encode.
|
||||
// - *const instructions may use a constant larger than the instruction can encode.
|
||||
// In this case the assembler expands to multiple instructions and uses tmp
|
||||
// register (R23).
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import "strings"
|
||||
// - Less-than-64-bit integer types live in the low portion of registers.
|
||||
// For now, the upper portion is junk; sign/zero-extension might be optimized in the future, but not yet.
|
||||
// - Boolean types are zero or 1; stored in a byte, but loaded with AMOVBZ so the upper bytes of a register are zero.
|
||||
// - *const instructions may use a constant larger than the instuction can encode.
|
||||
// - *const instructions may use a constant larger than the instruction can encode.
|
||||
// In this case the assembler expands to multiple instructions and uses tmp
|
||||
// register (R31).
|
||||
|
||||
|
||||
517
src/cmd/compile/internal/ssa/loopreschedchecks.go
Normal file
517
src/cmd/compile/internal/ssa/loopreschedchecks.go
Normal file
@@ -0,0 +1,517 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ssa
|
||||
|
||||
import "fmt"
|
||||
|
||||
// an edgeMemCtr records a backedge, together with the memory and
|
||||
// counter phi functions at the target of the backedge that must
|
||||
// be updated when a rescheduling check replaces the backedge.
|
||||
type edgeMemCtr struct {
|
||||
e Edge
|
||||
m *Value // phi for memory at dest of e
|
||||
c *Value // phi for counter at dest of e
|
||||
}
|
||||
|
||||
// a rewriteTarget is a a value-argindex pair indicating
|
||||
// where a rewrite is applied. Note that this is for values,
|
||||
// not for block controls, because block controls are not targets
|
||||
// for the rewrites performed in inserting rescheduling checks.
|
||||
type rewriteTarget struct {
|
||||
v *Value
|
||||
i int
|
||||
}
|
||||
|
||||
type rewrite struct {
|
||||
before, after *Value // before is the expected value before rewrite, after is the new value installed.
|
||||
rewrites []rewriteTarget // all the targets for this rewrite.
|
||||
}
|
||||
|
||||
func (r *rewrite) String() string {
|
||||
s := "\n\tbefore=" + r.before.String() + ", after=" + r.after.String()
|
||||
for _, rw := range r.rewrites {
|
||||
s += ", (i=" + fmt.Sprint(rw.i) + ", v=" + rw.v.LongString() + ")"
|
||||
}
|
||||
s += "\n"
|
||||
return s
|
||||
}
|
||||
|
||||
const initialRescheduleCounterValue = 1021 // Largest 10-bit prime. 97 nSec loop bodies will check every 100 uSec.
|
||||
|
||||
// insertLoopReschedChecks inserts rescheduling checks on loop backedges.
|
||||
func insertLoopReschedChecks(f *Func) {
|
||||
// TODO: when split information is recorded in export data, insert checks only on backedges that can be reached on a split-call-free path.
|
||||
|
||||
// Loop reschedule checks decrement a per-function counter
|
||||
// shared by all loops, and when the counter becomes non-positive
|
||||
// a call is made to a rescheduling check in the runtime.
|
||||
//
|
||||
// Steps:
|
||||
// 1. locate backedges.
|
||||
// 2. Record memory definitions at block end so that
|
||||
// the SSA graph for mem can be prperly modified.
|
||||
// 3. Define a counter and record its future uses (at backedges)
|
||||
// (Same process as 2, applied to a single definition of the counter.
|
||||
// difference for mem is that there are zero-to-many existing mem
|
||||
// definitions, versus exactly one for the new counter.)
|
||||
// 4. Ensure that phi functions that will-be-needed for mem and counter
|
||||
// are present in the graph, initially with trivial inputs.
|
||||
// 5. Record all to-be-modified uses of mem and counter;
|
||||
// apply modifications (split into two steps to simplify and
|
||||
// avoided nagging order-dependences).
|
||||
// 6. Rewrite backedges to include counter check, reschedule check,
|
||||
// and modify destination phi function appropriately with new
|
||||
// definitions for mem and counter.
|
||||
|
||||
if f.NoSplit { // nosplit functions don't reschedule.
|
||||
return
|
||||
}
|
||||
|
||||
backedges := backedges(f)
|
||||
if len(backedges) == 0 { // no backedges means no rescheduling checks.
|
||||
return
|
||||
}
|
||||
|
||||
lastMems := findLastMems(f)
|
||||
|
||||
idom := f.Idom()
|
||||
sdom := f.sdom()
|
||||
|
||||
if f.pass.debug > 2 {
|
||||
fmt.Printf("before %s = %s\n", f.Name, sdom.treestructure(f.Entry))
|
||||
}
|
||||
|
||||
tofixBackedges := []edgeMemCtr{}
|
||||
|
||||
for _, e := range backedges { // TODO: could filter here by calls in loops, if declared and inferred nosplit are recorded in export data.
|
||||
tofixBackedges = append(tofixBackedges, edgeMemCtr{e, nil, nil})
|
||||
}
|
||||
|
||||
// It's possible that there is no memory state (no global/pointer loads/stores or calls)
|
||||
if lastMems[f.Entry.ID] == nil {
|
||||
lastMems[f.Entry.ID] = f.Entry.NewValue0(f.Entry.Line, OpInitMem, TypeMem)
|
||||
}
|
||||
|
||||
memDefsAtBlockEnds := make([]*Value, f.NumBlocks()) // For each block, the mem def seen at its bottom. Could be from earlier block.
|
||||
|
||||
// Propagate last mem definitions forward through successor blocks.
|
||||
po := f.postorder()
|
||||
for i := len(po) - 1; i >= 0; i-- {
|
||||
b := po[i]
|
||||
mem := lastMems[b.ID]
|
||||
for j := 0; mem == nil; j++ { // if there's no def, then there's no phi, so the visible mem is identical in all predecessors.
|
||||
// loop because there might be backedges that haven't been visited yet.
|
||||
mem = memDefsAtBlockEnds[b.Preds[j].b.ID]
|
||||
}
|
||||
memDefsAtBlockEnds[b.ID] = mem
|
||||
}
|
||||
|
||||
// Set up counter. There are no phis etc pre-existing for it.
|
||||
counter0 := f.Entry.NewValue0I(f.Entry.Line, OpConst32, f.Config.fe.TypeInt32(), initialRescheduleCounterValue)
|
||||
ctrDefsAtBlockEnds := make([]*Value, f.NumBlocks()) // For each block, def visible at its end, if that def will be used.
|
||||
|
||||
// There's a minor difference between memDefsAtBlockEnds and ctrDefsAtBlockEnds;
|
||||
// because the counter only matter for loops and code that reaches them, it is nil for blocks where the ctr is no
|
||||
// longer live. This will avoid creation of dead phi functions. This optimization is ignored for the mem variable
|
||||
// because it is harder and also less likely to be helpful, though dead code elimination ought to clean this out anyhow.
|
||||
|
||||
for _, emc := range tofixBackedges {
|
||||
e := emc.e
|
||||
// set initial uses of counter zero (note available-at-bottom and use are the same thing initially.)
|
||||
// each back-edge will be rewritten to include a reschedule check, and that will use the counter.
|
||||
src := e.b.Preds[e.i].b
|
||||
ctrDefsAtBlockEnds[src.ID] = counter0
|
||||
}
|
||||
|
||||
// Push uses towards root
|
||||
for _, b := range f.postorder() {
|
||||
bd := ctrDefsAtBlockEnds[b.ID]
|
||||
if bd == nil {
|
||||
continue
|
||||
}
|
||||
for _, e := range b.Preds {
|
||||
p := e.b
|
||||
if ctrDefsAtBlockEnds[p.ID] == nil {
|
||||
ctrDefsAtBlockEnds[p.ID] = bd
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Maps from block to newly-inserted phi function in block.
|
||||
newmemphis := make(map[*Block]rewrite)
|
||||
newctrphis := make(map[*Block]rewrite)
|
||||
|
||||
// Insert phi functions as necessary for future changes to flow graph.
|
||||
for i, emc := range tofixBackedges {
|
||||
e := emc.e
|
||||
h := e.b
|
||||
|
||||
// find the phi function for the memory input at "h", if there is one.
|
||||
var headerMemPhi *Value // look for header mem phi
|
||||
|
||||
for _, v := range h.Values {
|
||||
if v.Op == OpPhi && v.Type.IsMemory() {
|
||||
headerMemPhi = v
|
||||
}
|
||||
}
|
||||
|
||||
if headerMemPhi == nil {
|
||||
// if the header is nil, make a trivial phi from the dominator
|
||||
mem0 := memDefsAtBlockEnds[idom[h.ID].ID]
|
||||
headerMemPhi = newPhiFor(h, mem0)
|
||||
newmemphis[h] = rewrite{before: mem0, after: headerMemPhi}
|
||||
addDFphis(mem0, h, h, f, memDefsAtBlockEnds, newmemphis)
|
||||
|
||||
}
|
||||
tofixBackedges[i].m = headerMemPhi
|
||||
|
||||
var headerCtrPhi *Value
|
||||
rw, ok := newctrphis[h]
|
||||
if !ok {
|
||||
headerCtrPhi = newPhiFor(h, counter0)
|
||||
newctrphis[h] = rewrite{before: counter0, after: headerCtrPhi}
|
||||
addDFphis(counter0, h, h, f, ctrDefsAtBlockEnds, newctrphis)
|
||||
} else {
|
||||
headerCtrPhi = rw.after
|
||||
}
|
||||
tofixBackedges[i].c = headerCtrPhi
|
||||
}
|
||||
|
||||
rewriteNewPhis(f.Entry, f.Entry, f, memDefsAtBlockEnds, newmemphis)
|
||||
rewriteNewPhis(f.Entry, f.Entry, f, ctrDefsAtBlockEnds, newctrphis)
|
||||
|
||||
if f.pass.debug > 0 {
|
||||
for b, r := range newmemphis {
|
||||
fmt.Printf("b=%s, rewrite=%s\n", b, r.String())
|
||||
}
|
||||
|
||||
for b, r := range newctrphis {
|
||||
fmt.Printf("b=%s, rewrite=%s\n", b, r.String())
|
||||
}
|
||||
}
|
||||
|
||||
// Apply collected rewrites.
|
||||
for _, r := range newmemphis {
|
||||
for _, rw := range r.rewrites {
|
||||
rw.v.SetArg(rw.i, r.after)
|
||||
}
|
||||
}
|
||||
|
||||
for _, r := range newctrphis {
|
||||
for _, rw := range r.rewrites {
|
||||
rw.v.SetArg(rw.i, r.after)
|
||||
}
|
||||
}
|
||||
|
||||
zero := f.Entry.NewValue0I(f.Entry.Line, OpConst32, f.Config.fe.TypeInt32(), 0)
|
||||
one := f.Entry.NewValue0I(f.Entry.Line, OpConst32, f.Config.fe.TypeInt32(), 1)
|
||||
|
||||
// Rewrite backedges to include reschedule checks.
|
||||
for _, emc := range tofixBackedges {
|
||||
e := emc.e
|
||||
headerMemPhi := emc.m
|
||||
headerCtrPhi := emc.c
|
||||
h := e.b
|
||||
i := e.i
|
||||
p := h.Preds[i]
|
||||
bb := p.b
|
||||
mem0 := headerMemPhi.Args[i]
|
||||
ctr0 := headerCtrPhi.Args[i]
|
||||
// bb e->p h,
|
||||
// Because we're going to insert a rare-call, make sure the
|
||||
// looping edge still looks likely.
|
||||
likely := BranchLikely
|
||||
if p.i != 0 {
|
||||
likely = BranchUnlikely
|
||||
}
|
||||
bb.Likely = likely
|
||||
|
||||
// rewrite edge to include reschedule check
|
||||
// existing edges:
|
||||
//
|
||||
// bb.Succs[p.i] == Edge{h, i}
|
||||
// h.Preds[i] == p == Edge{bb,p.i}
|
||||
//
|
||||
// new block(s):
|
||||
// test:
|
||||
// ctr1 := ctr0 - 1
|
||||
// if ctr1 <= 0 { goto sched }
|
||||
// goto join
|
||||
// sched:
|
||||
// mem1 := call resched (mem0)
|
||||
// goto join
|
||||
// join:
|
||||
// ctr2 := phi(ctr1, counter0) // counter0 is the constant
|
||||
// mem2 := phi(mem0, mem1)
|
||||
// goto h
|
||||
//
|
||||
// and correct arg i of headerMemPhi and headerCtrPhi
|
||||
//
|
||||
// EXCEPT: block containing only phi functions is bad
|
||||
// for the register allocator. Therefore, there is no
|
||||
// join, and instead branches targeting join instead target
|
||||
// the header, and the other phi functions within header are
|
||||
// adjusted for the additional input.
|
||||
|
||||
test := f.NewBlock(BlockIf)
|
||||
sched := f.NewBlock(BlockPlain)
|
||||
|
||||
test.Line = bb.Line
|
||||
sched.Line = bb.Line
|
||||
|
||||
// ctr1 := ctr0 - 1
|
||||
// if ctr1 <= 0 { goto sched }
|
||||
// goto header
|
||||
ctr1 := test.NewValue2(bb.Line, OpSub32, f.Config.fe.TypeInt32(), ctr0, one)
|
||||
cmp := test.NewValue2(bb.Line, OpLeq32, f.Config.fe.TypeBool(), ctr1, zero)
|
||||
test.SetControl(cmp)
|
||||
test.AddEdgeTo(sched) // if true
|
||||
// if false -- rewrite edge to header.
|
||||
// do NOT remove+add, because that will perturb all the other phi functions
|
||||
// as well as messing up other edges to the header.
|
||||
test.Succs = append(test.Succs, Edge{h, i})
|
||||
h.Preds[i] = Edge{test, 1}
|
||||
headerMemPhi.SetArg(i, mem0)
|
||||
headerCtrPhi.SetArg(i, ctr1)
|
||||
|
||||
test.Likely = BranchUnlikely
|
||||
|
||||
// sched:
|
||||
// mem1 := call resched (mem0)
|
||||
// goto header
|
||||
resched := f.Config.fe.Syslook("goschedguarded")
|
||||
mem1 := sched.NewValue1A(bb.Line, OpStaticCall, TypeMem, resched, mem0)
|
||||
sched.AddEdgeTo(h)
|
||||
headerMemPhi.AddArg(mem1)
|
||||
headerCtrPhi.AddArg(counter0)
|
||||
|
||||
bb.Succs[p.i] = Edge{test, 0}
|
||||
test.Preds = append(test.Preds, Edge{bb, p.i})
|
||||
|
||||
// Must correct all the other phi functions in the header for new incoming edge.
|
||||
// Except for mem and counter phis, it will be the same value seen on the original
|
||||
// backedge at index i.
|
||||
for _, v := range h.Values {
|
||||
if v.Op == OpPhi && v != headerMemPhi && v != headerCtrPhi {
|
||||
v.AddArg(v.Args[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
f.invalidateCFG()
|
||||
|
||||
if f.pass.debug > 2 {
|
||||
sdom = newSparseTree(f, f.Idom())
|
||||
fmt.Printf("after %s = %s\n", f.Name, sdom.treestructure(f.Entry))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// newPhiFor inserts a new Phi function into b,
|
||||
// with all inputs set to v.
|
||||
func newPhiFor(b *Block, v *Value) *Value {
|
||||
phiV := b.NewValue0(b.Line, OpPhi, v.Type)
|
||||
|
||||
for range b.Preds {
|
||||
phiV.AddArg(v)
|
||||
}
|
||||
return phiV
|
||||
}
|
||||
|
||||
// rewriteNewPhis updates newphis[h] to record all places where the new phi function inserted
|
||||
// in block h will replace a previous definition. Block b is the block currently being processed;
|
||||
// if b has its own phi definition then it takes the place of h.
|
||||
// defsForUses provides information about other definitions of the variable that are present
|
||||
// (and if nil, indicates that the variable is no longer live)
|
||||
func rewriteNewPhis(h, b *Block, f *Func, defsForUses []*Value, newphis map[*Block]rewrite) {
|
||||
// If b is a block with a new phi, then a new rewrite applies below it in the dominator tree.
|
||||
if _, ok := newphis[b]; ok {
|
||||
h = b
|
||||
}
|
||||
change := newphis[h]
|
||||
x := change.before
|
||||
y := change.after
|
||||
|
||||
// Apply rewrites to this block
|
||||
if x != nil { // don't waste time on the common case of no definition.
|
||||
p := &change.rewrites
|
||||
for _, v := range b.Values {
|
||||
if v == y { // don't rewrite self -- phi inputs are handled below.
|
||||
continue
|
||||
}
|
||||
for i, w := range v.Args {
|
||||
if w != x {
|
||||
continue
|
||||
}
|
||||
*p = append(*p, rewriteTarget{v, i})
|
||||
}
|
||||
}
|
||||
|
||||
// Rewrite appropriate inputs of phis reached in successors
|
||||
// in dominance frontier, self, and dominated.
|
||||
// If the variable def reaching uses in b is itself defined in b, then the new phi function
|
||||
// does not reach the successors of b. (This assumes a bit about the structure of the
|
||||
// phi use-def graph, but it's true for memory and the inserted counter.)
|
||||
if dfu := defsForUses[b.ID]; dfu != nil && dfu.Block != b {
|
||||
for _, e := range b.Succs {
|
||||
s := e.b
|
||||
if sphi, ok := newphis[s]; ok { // saves time to find the phi this way.
|
||||
*p = append(*p, rewriteTarget{sphi.after, e.i})
|
||||
continue
|
||||
}
|
||||
for _, v := range s.Values {
|
||||
if v.Op == OpPhi && v.Args[e.i] == x {
|
||||
*p = append(*p, rewriteTarget{v, e.i})
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
newphis[h] = change
|
||||
}
|
||||
|
||||
sdom := f.sdom()
|
||||
|
||||
for c := sdom[b.ID].child; c != nil; c = sdom[c.ID].sibling {
|
||||
rewriteNewPhis(h, c, f, defsForUses, newphis) // TODO: convert to explicit stack from recursion.
|
||||
}
|
||||
}
|
||||
|
||||
// addDFphis creates new trivial phis that are necessary to correctly reflect (within SSA)
|
||||
// a new definition for variable "x" inserted at h (usually but not necessarily a phi).
|
||||
// These new phis can only occur at the dominance frontier of h; block s is in the dominance
|
||||
// frontier of h if h does not strictly dominate s and if s is a successor of a block b where
|
||||
// either b = h or h strictly dominates b.
|
||||
// These newly created phis are themselves new definitions that may require addition of their
|
||||
// own trivial phi functions in their own dominance frontier, and this is handled recursively.
|
||||
func addDFphis(x *Value, h, b *Block, f *Func, defForUses []*Value, newphis map[*Block]rewrite) {
|
||||
oldv := defForUses[b.ID]
|
||||
if oldv != x { // either a new definition replacing x, or nil if it is proven that there are no uses reachable from b
|
||||
return
|
||||
}
|
||||
sdom := f.sdom()
|
||||
idom := f.Idom()
|
||||
outer:
|
||||
for _, e := range b.Succs {
|
||||
s := e.b
|
||||
// check phi functions in the dominance frontier
|
||||
if sdom.isAncestor(h, s) {
|
||||
continue // h dominates s, successor of b, therefore s is not in the frontier.
|
||||
}
|
||||
if _, ok := newphis[s]; ok {
|
||||
continue // successor s of b already has a new phi function, so there is no need to add another.
|
||||
}
|
||||
if x != nil {
|
||||
for _, v := range s.Values {
|
||||
if v.Op == OpPhi && v.Args[e.i] == x {
|
||||
continue outer // successor s of b has an old phi function, so there is no need to add another.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
old := defForUses[idom[s.ID].ID] // new phi function is correct-but-redundant, combining value "old" on all inputs.
|
||||
headerPhi := newPhiFor(s, old)
|
||||
// the new phi will replace "old" in block s and all blocks dominated by s.
|
||||
newphis[s] = rewrite{before: old, after: headerPhi} // record new phi, to have inputs labeled "old" rewritten to "headerPhi"
|
||||
addDFphis(old, s, s, f, defForUses, newphis) // the new definition may also create new phi functions.
|
||||
}
|
||||
for c := sdom[b.ID].child; c != nil; c = sdom[c.ID].sibling {
|
||||
addDFphis(x, h, c, f, defForUses, newphis) // TODO: convert to explicit stack from recursion.
|
||||
}
|
||||
}
|
||||
|
||||
// findLastMems maps block ids to last memory-output op in a block, if any
|
||||
func findLastMems(f *Func) []*Value {
|
||||
|
||||
var stores []*Value
|
||||
lastMems := make([]*Value, f.NumBlocks())
|
||||
storeUse := f.newSparseSet(f.NumValues())
|
||||
defer f.retSparseSet(storeUse)
|
||||
for _, b := range f.Blocks {
|
||||
// Find all the stores in this block. Categorize their uses:
|
||||
// storeUse contains stores which are used by a subsequent store.
|
||||
storeUse.clear()
|
||||
stores = stores[:0]
|
||||
var memPhi *Value
|
||||
for _, v := range b.Values {
|
||||
if v.Op == OpPhi {
|
||||
if v.Type.IsMemory() {
|
||||
memPhi = v
|
||||
}
|
||||
continue
|
||||
}
|
||||
if v.Type.IsMemory() {
|
||||
stores = append(stores, v)
|
||||
if v.Op == OpSelect1 {
|
||||
// Use the arg of the tuple-generating op.
|
||||
v = v.Args[0]
|
||||
}
|
||||
for _, a := range v.Args {
|
||||
if a.Block == b && a.Type.IsMemory() {
|
||||
storeUse.add(a.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(stores) == 0 {
|
||||
lastMems[b.ID] = memPhi
|
||||
continue
|
||||
}
|
||||
|
||||
// find last store in the block
|
||||
var last *Value
|
||||
for _, v := range stores {
|
||||
if storeUse.contains(v.ID) {
|
||||
continue
|
||||
}
|
||||
if last != nil {
|
||||
b.Fatalf("two final stores - simultaneous live stores %s %s", last, v)
|
||||
}
|
||||
last = v
|
||||
}
|
||||
if last == nil {
|
||||
b.Fatalf("no last store found - cycle?")
|
||||
}
|
||||
lastMems[b.ID] = last
|
||||
}
|
||||
return lastMems
|
||||
}
|
||||
|
||||
type backedgesState struct {
|
||||
b *Block
|
||||
i int
|
||||
}
|
||||
|
||||
// backedges returns a slice of successor edges that are back
|
||||
// edges. For reducible loops, edge.b is the header.
|
||||
func backedges(f *Func) []Edge {
|
||||
edges := []Edge{}
|
||||
mark := make([]markKind, f.NumBlocks())
|
||||
stack := []backedgesState{}
|
||||
|
||||
mark[f.Entry.ID] = notExplored
|
||||
stack = append(stack, backedgesState{f.Entry, 0})
|
||||
|
||||
for len(stack) > 0 {
|
||||
l := len(stack)
|
||||
x := stack[l-1]
|
||||
if x.i < len(x.b.Succs) {
|
||||
e := x.b.Succs[x.i]
|
||||
stack[l-1].i++
|
||||
s := e.b
|
||||
if mark[s.ID] == notFound {
|
||||
mark[s.ID] = notExplored
|
||||
stack = append(stack, backedgesState{s, 0})
|
||||
} else if mark[s.ID] == notExplored {
|
||||
edges = append(edges, e)
|
||||
}
|
||||
} else {
|
||||
mark[x.b.ID] = done
|
||||
stack = stack[0 : l-1]
|
||||
}
|
||||
}
|
||||
return edges
|
||||
}
|
||||
@@ -132,6 +132,8 @@ func nilcheckelim(f *Func) {
|
||||
}
|
||||
|
||||
// All platforms are guaranteed to fault if we load/store to anything smaller than this address.
|
||||
//
|
||||
// This should agree with minLegalPointer in the runtime.
|
||||
const minZeroPage = 4096
|
||||
|
||||
// nilcheckelim2 eliminates unnecessary nil checks.
|
||||
|
||||
@@ -21,7 +21,7 @@ type opInfo struct {
|
||||
name string
|
||||
reg regInfo
|
||||
auxType auxType
|
||||
argLen int32 // the number of arugments, -1 if variable length
|
||||
argLen int32 // the number of arguments, -1 if variable length
|
||||
asm obj.As
|
||||
generic bool // this is a generic (arch-independent) opcode
|
||||
rematerializeable bool // this op is rematerializeable
|
||||
|
||||
@@ -759,7 +759,7 @@ func (s *regAllocState) regalloc(f *Func) {
|
||||
liveSet.add(e.ID)
|
||||
}
|
||||
if v := b.Control; v != nil && s.values[v.ID].needReg {
|
||||
s.addUse(v.ID, int32(len(b.Values)), b.Line) // psuedo-use by control value
|
||||
s.addUse(v.ID, int32(len(b.Values)), b.Line) // pseudo-use by control value
|
||||
liveSet.add(v.ID)
|
||||
}
|
||||
for i := len(b.Values) - 1; i >= 0; i-- {
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
|
||||
package ssa
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type SparseTreeNode struct {
|
||||
child *Block
|
||||
@@ -67,6 +70,34 @@ func newSparseTree(f *Func, parentOf []*Block) SparseTree {
|
||||
return t
|
||||
}
|
||||
|
||||
// treestructure provides a string description of the dominator
|
||||
// tree and flow structure of block b and all blocks that it
|
||||
// dominates.
|
||||
func (t SparseTree) treestructure(b *Block) string {
|
||||
return t.treestructure1(b, 0)
|
||||
}
|
||||
func (t SparseTree) treestructure1(b *Block, i int) string {
|
||||
s := "\n" + strings.Repeat("\t", i) + b.String() + "->["
|
||||
for i, e := range b.Succs {
|
||||
if i > 0 {
|
||||
s = s + ","
|
||||
}
|
||||
s = s + e.b.String()
|
||||
}
|
||||
s += "]"
|
||||
if c0 := t[b.ID].child; c0 != nil {
|
||||
s += "("
|
||||
for c := c0; c != nil; c = t[c.ID].sibling {
|
||||
if c != c0 {
|
||||
s += " "
|
||||
}
|
||||
s += t.treestructure1(c, i+1)
|
||||
}
|
||||
s += ")"
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// numberBlock assigns entry and exit numbers for b and b's
|
||||
// children in an in-order walk from a gappy sequence, where n
|
||||
// is the first number not yet assigned or reserved. N should
|
||||
|
||||
@@ -151,11 +151,12 @@ type Block struct {
|
||||
// File is a wrapper for the state of a file used in the parser.
|
||||
// The basic parse tree walker is a method of this type.
|
||||
type File struct {
|
||||
fset *token.FileSet
|
||||
name string // Name of file.
|
||||
astFile *ast.File
|
||||
blocks []Block
|
||||
atomicPkg string // Package name for "sync/atomic" in this file.
|
||||
fset *token.FileSet
|
||||
name string // Name of file.
|
||||
astFile *ast.File
|
||||
blocks []Block
|
||||
atomicPkg string // Package name for "sync/atomic" in this file.
|
||||
directives map[*ast.Comment]bool // Map of compiler directives to whether it's processed in ast.Visitor or not.
|
||||
}
|
||||
|
||||
// Visit implements the ast.Visitor interface.
|
||||
@@ -247,8 +248,11 @@ func (f *File) Visit(node ast.Node) ast.Visitor {
|
||||
// to appear in syntactically incorrect places. //go: appears at the beginning of
|
||||
// the line and is syntactically safe.
|
||||
for _, c := range n.List {
|
||||
if strings.HasPrefix(c.Text, "//go:") && f.fset.Position(c.Slash).Column == 1 {
|
||||
if f.isDirective(c) {
|
||||
list = append(list, c)
|
||||
|
||||
// Mark compiler directive as handled.
|
||||
f.directives[c] = true
|
||||
}
|
||||
}
|
||||
n.List = list
|
||||
@@ -360,17 +364,27 @@ func annotate(name string) {
|
||||
if err != nil {
|
||||
log.Fatalf("cover: %s: %s", name, err)
|
||||
}
|
||||
// Remove comments. Or else they interfere with new AST.
|
||||
parsedFile.Comments = nil
|
||||
|
||||
file := &File{
|
||||
fset: fset,
|
||||
name: name,
|
||||
astFile: parsedFile,
|
||||
fset: fset,
|
||||
name: name,
|
||||
astFile: parsedFile,
|
||||
directives: map[*ast.Comment]bool{},
|
||||
}
|
||||
if *mode == "atomic" {
|
||||
file.atomicPkg = file.addImport(atomicPackagePath)
|
||||
}
|
||||
|
||||
for _, cg := range parsedFile.Comments {
|
||||
for _, c := range cg.List {
|
||||
if file.isDirective(c) {
|
||||
file.directives[c] = false
|
||||
}
|
||||
}
|
||||
}
|
||||
// Remove comments. Or else they interfere with new AST.
|
||||
parsedFile.Comments = nil
|
||||
|
||||
ast.Walk(file, file.astFile)
|
||||
fd := os.Stdout
|
||||
if *output != "" {
|
||||
@@ -381,6 +395,17 @@ func annotate(name string) {
|
||||
}
|
||||
}
|
||||
fd.Write(initialComments(content)) // Retain '// +build' directives.
|
||||
|
||||
// Retain compiler directives that are not processed in ast.Visitor.
|
||||
// Some compiler directives like "go:linkname" and "go:cgo_"
|
||||
// can be not attached to anything in the tree and hence will not be printed by printer.
|
||||
// So, we have to explicitly print them here.
|
||||
for cd, handled := range file.directives {
|
||||
if !handled {
|
||||
fmt.Fprintln(fd, cd.Text)
|
||||
}
|
||||
}
|
||||
|
||||
file.print(fd)
|
||||
// After printing the source tree, add some declarations for the counters etc.
|
||||
// We could do this by adding to the tree, but it's easier just to print the text.
|
||||
@@ -391,6 +416,11 @@ func (f *File) print(w io.Writer) {
|
||||
printer.Fprint(w, f.fset, f.astFile)
|
||||
}
|
||||
|
||||
// isDirective reports whether a comment is a compiler directive.
|
||||
func (f *File) isDirective(c *ast.Comment) bool {
|
||||
return strings.HasPrefix(c.Text, "//go:") && f.fset.Position(c.Slash).Column == 1
|
||||
}
|
||||
|
||||
// intLiteral returns an ast.BasicLit representing the integer value.
|
||||
func (f *File) intLiteral(i int) *ast.BasicLit {
|
||||
node := &ast.BasicLit{
|
||||
|
||||
@@ -90,6 +90,11 @@ func TestCover(t *testing.T) {
|
||||
if got, err := regexp.MatchString(".*\n//go:nosplit\nfunc someFunction().*", string(file)); err != nil || !got {
|
||||
t.Errorf("misplaced compiler directive: got=(%v, %v); want=(true; nil)", got, err)
|
||||
}
|
||||
// "go:linkname" compiler directive should be present.
|
||||
if got, err := regexp.MatchString(`.*go\:linkname some\_name some\_name.*`, string(file)); err != nil || !got {
|
||||
t.Errorf("'go:linkname' compiler directive not found: got=(%v, %v); want=(true; nil)", got, err)
|
||||
}
|
||||
|
||||
// No other comments should be present in generated code.
|
||||
c := ".*// This comment shouldn't appear in generated go code.*"
|
||||
if got, err := regexp.MatchString(c, string(file)); err != nil || got {
|
||||
|
||||
4
src/cmd/cover/testdata/test.go
vendored
4
src/cmd/cover/testdata/test.go
vendored
@@ -10,6 +10,10 @@
|
||||
|
||||
package main
|
||||
|
||||
import _ "unsafe" // for go:linkname
|
||||
|
||||
//go:linkname some_name some_name
|
||||
|
||||
const anything = 1e9 // Just some unlikely value that means "we got here, don't care how often"
|
||||
|
||||
func testAll() {
|
||||
|
||||
2
src/cmd/dist/test.go
vendored
2
src/cmd/dist/test.go
vendored
@@ -704,7 +704,7 @@ func (t *tester) extLink() bool {
|
||||
"darwin-arm", "darwin-arm64",
|
||||
"dragonfly-386", "dragonfly-amd64",
|
||||
"freebsd-386", "freebsd-amd64", "freebsd-arm",
|
||||
"linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-mips64", "linux-mips64le",
|
||||
"linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-mips64", "linux-mips64le", "linux-mips", "linux-mipsle", "linux-s390x",
|
||||
"netbsd-386", "netbsd-amd64",
|
||||
"openbsd-386", "openbsd-amd64",
|
||||
"windows-386", "windows-amd64":
|
||||
|
||||
@@ -935,6 +935,8 @@
|
||||
// unless that directory holds a Go distribution.
|
||||
// Run "go env GOPATH" to see the current GOPATH.
|
||||
//
|
||||
// See https://golang.org/wiki/SettingGOPATH to set a custom GOPATH.
|
||||
//
|
||||
// Each directory listed in GOPATH must have a prescribed structure:
|
||||
//
|
||||
// The src directory holds source code. The path below src
|
||||
@@ -1474,7 +1476,7 @@
|
||||
// text from Log and Logf calls even if the test succeeds.
|
||||
//
|
||||
// The following flags are also recognized by 'go test' and can be used to
|
||||
// profile the tests during execution::
|
||||
// profile the tests during execution:
|
||||
//
|
||||
// -benchmem
|
||||
// Print memory allocation statistics for benchmarks.
|
||||
@@ -1517,7 +1519,7 @@
|
||||
// Writes test binary as -c would.
|
||||
//
|
||||
// -mutexprofilefraction n
|
||||
// Sample 1 in n stack traces of goroutines holding a
|
||||
// Sample 1 in n stack traces of goroutines holding a
|
||||
// contended mutex.
|
||||
//
|
||||
// -outputdir directory
|
||||
@@ -1606,7 +1608,8 @@
|
||||
// is compared exactly against the comment (see examples below). If the last
|
||||
// comment begins with "Unordered output:" then the output is compared to the
|
||||
// comment, however the order of the lines is ignored. An example with no such
|
||||
// comment, or with no text after "Output:" is compiled but not executed.
|
||||
// comment is compiled but not executed. An example with no text after
|
||||
// "Output:" is compiled, executed, and expected to produce no output.
|
||||
//
|
||||
// Godoc displays the body of ExampleXXX to demonstrate the use
|
||||
// of the function, constant, or variable XXX. An example of a method M with
|
||||
|
||||
@@ -1885,6 +1885,26 @@ func TestGoTestCpuprofileDashOControlsBinaryLocation(t *testing.T) {
|
||||
tg.wantExecutable("myerrors.test"+exeSuffix, "go test -cpuprofile -o myerrors.test did not create myerrors.test")
|
||||
}
|
||||
|
||||
func TestGoTestMutexprofileLeavesBinaryBehind(t *testing.T) {
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
// TODO: tg.parallel()
|
||||
tg.makeTempdir()
|
||||
tg.cd(tg.path("."))
|
||||
tg.run("test", "-mutexprofile", "errors.prof", "errors")
|
||||
tg.wantExecutable("errors.test"+exeSuffix, "go test -mutexprofile did not create errors.test")
|
||||
}
|
||||
|
||||
func TestGoTestMutexprofileDashOControlsBinaryLocation(t *testing.T) {
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
// TODO: tg.parallel()
|
||||
tg.makeTempdir()
|
||||
tg.cd(tg.path("."))
|
||||
tg.run("test", "-mutexprofile", "errors.prof", "-o", "myerrors.test"+exeSuffix, "errors")
|
||||
tg.wantExecutable("myerrors.test"+exeSuffix, "go test -mutexprofile -o myerrors.test did not create myerrors.test")
|
||||
}
|
||||
|
||||
func TestGoTestDashCDashOControlsBinaryLocation(t *testing.T) {
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
@@ -2247,6 +2267,28 @@ func TestCoverageImportMainLoop(t *testing.T) {
|
||||
tg.grepStderr("not an importable package", "did not detect import main")
|
||||
}
|
||||
|
||||
func TestTestEmpty(t *testing.T) {
|
||||
if !canRace {
|
||||
t.Skip("no race detector")
|
||||
}
|
||||
|
||||
wd, _ := os.Getwd()
|
||||
testdata := filepath.Join(wd, "testdata")
|
||||
|
||||
for _, dir := range []string{"pkg", "test", "xtest", "pkgtest", "pkgxtest", "pkgtestxtest", "testxtest"} {
|
||||
t.Run(dir, func(t *testing.T) {
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.setenv("GOPATH", testdata)
|
||||
tg.cd(filepath.Join(testdata, "src/empty/"+dir))
|
||||
tg.run("test", "-cover", "-coverpkg=.", "-race")
|
||||
})
|
||||
if testing.Short() {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildDryRunWithCgo(t *testing.T) {
|
||||
if !canCgo {
|
||||
t.Skip("skipping because cgo not enabled")
|
||||
@@ -3357,9 +3399,11 @@ func TestCgoConsistentResults(t *testing.T) {
|
||||
if !canCgo {
|
||||
t.Skip("skipping because cgo not enabled")
|
||||
}
|
||||
if runtime.GOOS == "solaris" {
|
||||
// See https://golang.org/issue/13247
|
||||
t.Skip("skipping because Solaris builds are known to be inconsistent; see #13247")
|
||||
switch runtime.GOOS {
|
||||
case "freebsd":
|
||||
testenv.SkipFlaky(t, 15405)
|
||||
case "solaris":
|
||||
testenv.SkipFlaky(t, 13247)
|
||||
}
|
||||
|
||||
tg := testgo(t)
|
||||
|
||||
@@ -295,6 +295,8 @@ to a subdirectory named "go" in the user's home directory
|
||||
unless that directory holds a Go distribution.
|
||||
Run "go env GOPATH" to see the current GOPATH.
|
||||
|
||||
See https://golang.org/wiki/SettingGOPATH to set a custom GOPATH.
|
||||
|
||||
Each directory listed in GOPATH must have a prescribed structure:
|
||||
|
||||
The src directory holds source code. The path below src
|
||||
|
||||
@@ -33,6 +33,7 @@ var httpClient = http.DefaultClient
|
||||
var impatientInsecureHTTPClient = &http.Client{
|
||||
Timeout: 5 * time.Second,
|
||||
Transport: &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
},
|
||||
|
||||
@@ -955,6 +955,10 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
|
||||
if p.Name == "main" && goarch == "arm" {
|
||||
importPaths = append(importPaths, "math")
|
||||
}
|
||||
// In coverage atomic mode everything depends on sync/atomic.
|
||||
if testCoverMode == "atomic" && (!p.Standard || (p.ImportPath != "runtime/cgo" && p.ImportPath != "runtime/race" && p.ImportPath != "sync/atomic")) {
|
||||
importPaths = append(importPaths, "sync/atomic")
|
||||
}
|
||||
}
|
||||
|
||||
// Runtime and its internal packages depend on runtime/internal/sys,
|
||||
|
||||
@@ -200,7 +200,7 @@ const testFlag2 = `
|
||||
text from Log and Logf calls even if the test succeeds.
|
||||
|
||||
The following flags are also recognized by 'go test' and can be used to
|
||||
profile the tests during execution::
|
||||
profile the tests during execution:
|
||||
|
||||
-benchmem
|
||||
Print memory allocation statistics for benchmarks.
|
||||
@@ -243,7 +243,7 @@ profile the tests during execution::
|
||||
Writes test binary as -c would.
|
||||
|
||||
-mutexprofilefraction n
|
||||
Sample 1 in n stack traces of goroutines holding a
|
||||
Sample 1 in n stack traces of goroutines holding a
|
||||
contended mutex.
|
||||
|
||||
-outputdir directory
|
||||
@@ -334,7 +334,8 @@ If the last comment in the function starts with "Output:" then the output
|
||||
is compared exactly against the comment (see examples below). If the last
|
||||
comment begins with "Unordered output:" then the output is compared to the
|
||||
comment, however the order of the lines is ignored. An example with no such
|
||||
comment, or with no text after "Output:" is compiled but not executed.
|
||||
comment is compiled but not executed. An example with no text after
|
||||
"Output:" is compiled, executed, and expected to produce no output.
|
||||
|
||||
Godoc displays the body of ExampleXXX to demonstrate the use
|
||||
of the function, constant, or variable XXX. An example of a method M with
|
||||
|
||||
1
src/cmd/go/testdata/src/empty/pkg/pkg.go
vendored
Normal file
1
src/cmd/go/testdata/src/empty/pkg/pkg.go
vendored
Normal file
@@ -0,0 +1 @@
|
||||
package p
|
||||
1
src/cmd/go/testdata/src/empty/pkgtest/pkg.go
vendored
Normal file
1
src/cmd/go/testdata/src/empty/pkgtest/pkg.go
vendored
Normal file
@@ -0,0 +1 @@
|
||||
package p
|
||||
1
src/cmd/go/testdata/src/empty/pkgtest/test_test.go
vendored
Normal file
1
src/cmd/go/testdata/src/empty/pkgtest/test_test.go
vendored
Normal file
@@ -0,0 +1 @@
|
||||
package p
|
||||
1
src/cmd/go/testdata/src/empty/pkgtestxtest/pkg.go
vendored
Normal file
1
src/cmd/go/testdata/src/empty/pkgtestxtest/pkg.go
vendored
Normal file
@@ -0,0 +1 @@
|
||||
package p
|
||||
1
src/cmd/go/testdata/src/empty/pkgtestxtest/test_test.go
vendored
Normal file
1
src/cmd/go/testdata/src/empty/pkgtestxtest/test_test.go
vendored
Normal file
@@ -0,0 +1 @@
|
||||
package p
|
||||
1
src/cmd/go/testdata/src/empty/pkgtestxtest/xtest_test.go
vendored
Normal file
1
src/cmd/go/testdata/src/empty/pkgtestxtest/xtest_test.go
vendored
Normal file
@@ -0,0 +1 @@
|
||||
package p_test
|
||||
1
src/cmd/go/testdata/src/empty/pkgxtest/pkg.go
vendored
Normal file
1
src/cmd/go/testdata/src/empty/pkgxtest/pkg.go
vendored
Normal file
@@ -0,0 +1 @@
|
||||
package p
|
||||
1
src/cmd/go/testdata/src/empty/pkgxtest/xtest_test.go
vendored
Normal file
1
src/cmd/go/testdata/src/empty/pkgxtest/xtest_test.go
vendored
Normal file
@@ -0,0 +1 @@
|
||||
package p_test
|
||||
1
src/cmd/go/testdata/src/empty/test/test_test.go
vendored
Normal file
1
src/cmd/go/testdata/src/empty/test/test_test.go
vendored
Normal file
@@ -0,0 +1 @@
|
||||
package p
|
||||
1
src/cmd/go/testdata/src/empty/testxtest/test_test.go
vendored
Normal file
1
src/cmd/go/testdata/src/empty/testxtest/test_test.go
vendored
Normal file
@@ -0,0 +1 @@
|
||||
package p
|
||||
1
src/cmd/go/testdata/src/empty/testxtest/xtest_test.go
vendored
Normal file
1
src/cmd/go/testdata/src/empty/testxtest/xtest_test.go
vendored
Normal file
@@ -0,0 +1 @@
|
||||
package p_test
|
||||
1
src/cmd/go/testdata/src/empty/xtest/xtest_test.go
vendored
Normal file
1
src/cmd/go/testdata/src/empty/xtest/xtest_test.go
vendored
Normal file
@@ -0,0 +1 @@
|
||||
package p_test
|
||||
@@ -151,10 +151,10 @@ func testFlags(args []string) (packageNames, passToTest []string) {
|
||||
testBench = true
|
||||
case "timeout":
|
||||
testTimeout = value
|
||||
case "blockprofile", "cpuprofile", "memprofile":
|
||||
case "blockprofile", "cpuprofile", "memprofile", "mutexprofile":
|
||||
testProfile = true
|
||||
testNeedBinary = true
|
||||
case "mutexprofile", "trace":
|
||||
case "trace":
|
||||
testProfile = true
|
||||
case "coverpkg":
|
||||
testCover = true
|
||||
|
||||
@@ -13,8 +13,9 @@ import (
|
||||
// go-specific code shared across loaders (5l, 6l, 8l).
|
||||
|
||||
var (
|
||||
framepointer_enabled int
|
||||
Fieldtrack_enabled int
|
||||
framepointer_enabled int
|
||||
Fieldtrack_enabled int
|
||||
Preemptibleloops_enabled int
|
||||
)
|
||||
|
||||
// Toolchain experiments.
|
||||
@@ -27,6 +28,7 @@ var exper = []struct {
|
||||
}{
|
||||
{"fieldtrack", &Fieldtrack_enabled},
|
||||
{"framepointer", &framepointer_enabled},
|
||||
{"preemptibleloops", &Preemptibleloops_enabled},
|
||||
}
|
||||
|
||||
func addexp(s string) {
|
||||
|
||||
@@ -41,8 +41,6 @@ Flags:
|
||||
Set the value of the string variable in importpath named name to value.
|
||||
Note that before Go 1.5 this option took two separate arguments.
|
||||
Now it takes one argument split on the first = sign.
|
||||
To discover which name to use, run `go tool nm PROGRAM`;
|
||||
usable variables will be tagged "D" or "d".
|
||||
-buildmode mode
|
||||
Set build mode (default exe).
|
||||
-cpuprofile file
|
||||
|
||||
@@ -104,7 +104,7 @@ func archinit(ctxt *ld.Link) {
|
||||
*ld.FlagDataAddr = 0
|
||||
}
|
||||
if *ld.FlagRound == -1 {
|
||||
*ld.FlagRound = 4096
|
||||
*ld.FlagRound = 0x10000
|
||||
}
|
||||
|
||||
case obj.Hnacl:
|
||||
|
||||
@@ -248,6 +248,9 @@ func (ctxt *Link) pclntab() {
|
||||
setaddr(ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize), s)
|
||||
setuintxx(ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize)+int64(SysArch.PtrSize), uint64(funcstart), int64(SysArch.PtrSize))
|
||||
|
||||
// Write runtime._func. Keep in sync with ../../../../runtime/runtime2.go:/_func
|
||||
// and package debug/gosym.
|
||||
|
||||
// fixed size of struct, checked below
|
||||
off := funcstart
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ func symbolsFromBinaries(prof *profile.Profile, g graph, rx *regexp.Regexp, addr
|
||||
// Walk all mappings looking for matching functions with samples.
|
||||
var objSyms []*objSymbol
|
||||
for _, m := range prof.Mapping {
|
||||
if !hasSamples[filepath.Base(m.File)] {
|
||||
if !hasSamples[m.File] {
|
||||
if address == nil || !(m.Start <= *address && *address <= m.Limit) {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -229,7 +229,7 @@ func assemblyPerSourceLine(objSyms []*objSymbol, rs nodes, src string, obj plugi
|
||||
func findMatchingSymbol(objSyms []*objSymbol, ns nodes) *objSymbol {
|
||||
for _, n := range ns {
|
||||
for _, o := range objSyms {
|
||||
if filepath.Base(o.sym.File) == n.info.objfile &&
|
||||
if o.sym.File == n.info.objfile &&
|
||||
o.sym.Start <= n.info.address-o.base &&
|
||||
n.info.address-o.base <= o.sym.End {
|
||||
return o
|
||||
|
||||
@@ -44,7 +44,7 @@ func checkCgoCall(f *File, node ast.Node) {
|
||||
}
|
||||
|
||||
for _, arg := range x.Args {
|
||||
if !typeOKForCgoCall(cgoBaseType(f, arg)) {
|
||||
if !typeOKForCgoCall(cgoBaseType(f, arg), make(map[types.Type]bool)) {
|
||||
f.Badf(arg.Pos(), "possibly passing Go type with embedded pointer to C")
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ func checkCgoCall(f *File, node ast.Node) {
|
||||
arg = conv.Args[0]
|
||||
}
|
||||
if u, ok := arg.(*ast.UnaryExpr); ok && u.Op == token.AND {
|
||||
if !typeOKForCgoCall(cgoBaseType(f, u.X)) {
|
||||
if !typeOKForCgoCall(cgoBaseType(f, u.X), make(map[types.Type]bool)) {
|
||||
f.Badf(arg.Pos(), "possibly passing Go type with embedded pointer to C")
|
||||
}
|
||||
}
|
||||
@@ -110,23 +110,24 @@ func cgoBaseType(f *File, arg ast.Expr) types.Type {
|
||||
return f.pkg.types[arg].Type
|
||||
}
|
||||
|
||||
// typeOKForCgoCall returns true if the type of arg is OK to pass to a
|
||||
// typeOKForCgoCall reports whether the type of arg is OK to pass to a
|
||||
// C function using cgo. This is not true for Go types with embedded
|
||||
// pointers.
|
||||
func typeOKForCgoCall(t types.Type) bool {
|
||||
if t == nil {
|
||||
// pointers. m is used to avoid infinite recursion on recursive types.
|
||||
func typeOKForCgoCall(t types.Type, m map[types.Type]bool) bool {
|
||||
if t == nil || m[t] {
|
||||
return true
|
||||
}
|
||||
m[t] = true
|
||||
switch t := t.Underlying().(type) {
|
||||
case *types.Chan, *types.Map, *types.Signature, *types.Slice:
|
||||
return false
|
||||
case *types.Pointer:
|
||||
return typeOKForCgoCall(t.Elem())
|
||||
return typeOKForCgoCall(t.Elem(), m)
|
||||
case *types.Array:
|
||||
return typeOKForCgoCall(t.Elem())
|
||||
return typeOKForCgoCall(t.Elem(), m)
|
||||
case *types.Struct:
|
||||
for i := 0; i < t.NumFields(); i++ {
|
||||
if !typeOKForCgoCall(t.Field(i).Type()) {
|
||||
if !typeOKForCgoCall(t.Field(i).Type(), m) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,13 +93,15 @@ func checkCopyLocksReturnStmt(f *File, rs *ast.ReturnStmt) {
|
||||
|
||||
// checkCopyLocksCallExpr detects lock copy in the arguments to a function call
|
||||
func checkCopyLocksCallExpr(f *File, ce *ast.CallExpr) {
|
||||
if id, ok := ce.Fun.(*ast.Ident); ok && id.Name == "new" && f.pkg.types[id].IsBuiltin() {
|
||||
// Skip 'new(Type)' for built-in 'new'
|
||||
return
|
||||
if id, ok := ce.Fun.(*ast.Ident); ok && f.pkg.types[id].IsBuiltin() {
|
||||
switch id.Name {
|
||||
case "new", "len", "cap":
|
||||
return
|
||||
}
|
||||
}
|
||||
for _, x := range ce.Args {
|
||||
if path := lockPathRhs(f, x); path != nil {
|
||||
f.Badf(x.Pos(), "function call copies lock value: %v", path)
|
||||
f.Badf(x.Pos(), "call of %s copies lock value: %v", f.gofmt(ce.Fun), path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
3
src/cmd/vet/testdata/cgo/cgo.go
vendored
3
src/cmd/vet/testdata/cgo/cgo.go
vendored
@@ -52,5 +52,8 @@ func CgoTests() {
|
||||
C.f(*(*unsafe.Pointer)(unsafe.Pointer(&st2)))
|
||||
C.f(unsafe.Pointer(&st2))
|
||||
|
||||
type cgoStruct struct{ p *cgoStruct }
|
||||
C.f(unsafe.Pointer(&cgoStruct{}))
|
||||
|
||||
C.CBytes([]byte("hello"))
|
||||
}
|
||||
|
||||
16
src/cmd/vet/testdata/copylock.go
vendored
16
src/cmd/vet/testdata/copylock.go
vendored
@@ -67,7 +67,7 @@ func BadFunc() {
|
||||
|
||||
// override 'new' keyword
|
||||
new := func(interface{}) {}
|
||||
new(t) // ERROR "function call copies lock value: testdata.Tlock contains sync.Once contains sync.Mutex"
|
||||
new(t) // ERROR "call of new copies lock value: testdata.Tlock contains sync.Once contains sync.Mutex"
|
||||
|
||||
// copy of array of locks
|
||||
var muA [5]sync.Mutex
|
||||
@@ -88,6 +88,20 @@ func BadFunc() {
|
||||
fmuSlice := fmuA[:] // OK
|
||||
}
|
||||
|
||||
func LenAndCapOnLockArrays() {
|
||||
var a [5]sync.Mutex
|
||||
aLen := len(a) // OK
|
||||
aCap := cap(a) // OK
|
||||
|
||||
// override 'len' and 'cap' keywords
|
||||
|
||||
len := func(interface{}) {}
|
||||
len(a) // ERROR "call of len copies lock value: sync.Mutex"
|
||||
|
||||
cap := func(interface{}) {}
|
||||
cap(a) // ERROR "call of cap copies lock value: sync.Mutex"
|
||||
}
|
||||
|
||||
// SyncTypesCheck checks copying of sync.* types except sync.Mutex
|
||||
func SyncTypesCheck() {
|
||||
// sync.RWMutex copying
|
||||
|
||||
6
src/cmd/vet/testdata/copylock_func.go
vendored
6
src/cmd/vet/testdata/copylock_func.go
vendored
@@ -86,8 +86,10 @@ func FuncCallInterfaceArg(f func(a int, b interface{})) {
|
||||
f(1, "foo")
|
||||
f(2, &t)
|
||||
f(3, &sync.Mutex{})
|
||||
f(4, m) // ERROR "function call copies lock value: sync.Mutex"
|
||||
f(5, t) // ERROR "function call copies lock value: struct{lock sync.Mutex} contains sync.Mutex"
|
||||
f(4, m) // ERROR "call of f copies lock value: sync.Mutex"
|
||||
f(5, t) // ERROR "call of f copies lock value: struct{lock sync.Mutex} contains sync.Mutex"
|
||||
var fntab []func(t)
|
||||
fntab[0](t) // ERROR "call of fntab.0. copies lock value: struct{lock sync.Mutex} contains sync.Mutex"
|
||||
}
|
||||
|
||||
// Returning lock via interface value
|
||||
|
||||
@@ -143,6 +143,7 @@ func TestVetDirs(t *testing.T) {
|
||||
"divergent",
|
||||
"buildtag",
|
||||
"incomplete", // incomplete examples
|
||||
"cgo",
|
||||
} {
|
||||
dir := dir
|
||||
t.Run(dir, func(t *testing.T) {
|
||||
|
||||
@@ -225,7 +225,7 @@ end:
|
||||
RET
|
||||
|
||||
|
||||
// This is the implementation using AVX2. It is based on:
|
||||
// This is the implementation using AVX2, BMI1 and BMI2. It is based on:
|
||||
// "SHA-1 implementation with Intel(R) AVX2 instruction set extensions"
|
||||
// From http://software.intel.com/en-us/articles
|
||||
// (look for improving-the-performance-of-the-secure-hash-algorithm-1)
|
||||
@@ -1459,15 +1459,19 @@ TEXT ·blockAVX2(SB),$1408-32
|
||||
|
||||
|
||||
// func checkAVX2() bool
|
||||
// returns whether AVX2 is supported
|
||||
// returns whether AVX2, BMI1 and BMI2 are supported
|
||||
TEXT ·checkAVX2(SB),NOSPLIT,$0
|
||||
CMPB runtime·support_avx2(SB), $1
|
||||
JE has
|
||||
MOVB $0, ret+0(FP)
|
||||
RET
|
||||
has:
|
||||
CMPB runtime·support_avx2(SB), $0
|
||||
JE noavx2
|
||||
CMPB runtime·support_bmi1(SB), $0 // check for ANDNL instruction
|
||||
JE noavx2
|
||||
CMPB runtime·support_bmi2(SB), $0 // check for RORXL instruction
|
||||
JE noavx2
|
||||
MOVB $1, ret+0(FP)
|
||||
RET
|
||||
noavx2:
|
||||
MOVB $0, ret+0(FP)
|
||||
RET
|
||||
|
||||
|
||||
DATA K_XMM_AR<>+0x00(SB)/4,$0x5a827999
|
||||
|
||||
@@ -559,8 +559,11 @@
|
||||
ADDL y3, h // h = t1 + S0 + MAJ // --
|
||||
|
||||
TEXT ·block(SB), 0, $536-32
|
||||
CMPB runtime·support_avx2(SB), $1
|
||||
CMPB runtime·support_avx2(SB), $0
|
||||
JE noavx2bmi2
|
||||
CMPB runtime·support_bmi2(SB), $1 // check for RORXL instruction
|
||||
JE avx2
|
||||
noavx2bmi2:
|
||||
|
||||
MOVQ p_base+8(FP), SI
|
||||
MOVQ p_len+16(FP), DX
|
||||
|
||||
@@ -37,7 +37,7 @@ type Conn struct {
|
||||
vers uint16 // TLS version
|
||||
haveVers bool // version has been negotiated
|
||||
config *Config // configuration passed to constructor
|
||||
// handshakeComplete is true if the connection is currently transfering
|
||||
// handshakeComplete is true if the connection is currently transferring
|
||||
// application data (i.e. is not currently processing a handshake).
|
||||
handshakeComplete bool
|
||||
// handshakes counts the number of handshakes performed on the
|
||||
|
||||
@@ -7,17 +7,22 @@
|
||||
package x509
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto/sha1"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
var debugExecDarwinRoots = strings.Contains(os.Getenv("GODEBUG"), "x509roots=1")
|
||||
|
||||
func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -27,7 +32,35 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
|
||||
// even if the tests are run with cgo enabled.
|
||||
// The linker will not include these unused functions in binaries built with cgo enabled.
|
||||
|
||||
// execSecurityRoots finds the macOS list of trusted root certificates
|
||||
// using only command-line tools. This is our fallback path when cgo isn't available.
|
||||
//
|
||||
// The strategy is as follows:
|
||||
//
|
||||
// 1. Run "security trust-settings-export" and "security
|
||||
// trust-settings-export -d" to discover the set of certs with some
|
||||
// user-tweaked trust policy. We're too lazy to parse the XML (at
|
||||
// least at this stage of Go 1.8) to understand what the trust
|
||||
// policy actually is. We just learn that there is _some_ policy.
|
||||
//
|
||||
// 2. Run "security find-certificate" to dump the list of system root
|
||||
// CAs in PEM format.
|
||||
//
|
||||
// 3. For each dumped cert, conditionally verify it with "security
|
||||
// verify-cert" if that cert was in the set discovered in Step 1.
|
||||
// Without the Step 1 optimization, running "security verify-cert"
|
||||
// 150-200 times takes 3.5 seconds. With the optimization, the
|
||||
// whole process takes about 180 milliseconds with 1 untrusted root
|
||||
// CA. (Compared to 110ms in the cgo path)
|
||||
func execSecurityRoots() (*CertPool, error) {
|
||||
hasPolicy, err := getCertsWithTrustPolicy()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if debugExecDarwinRoots {
|
||||
println(fmt.Sprintf("crypto/x509: %d certs have a trust policy", len(hasPolicy)))
|
||||
}
|
||||
|
||||
cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain")
|
||||
data, err := cmd.Output()
|
||||
if err != nil {
|
||||
@@ -35,22 +68,49 @@ func execSecurityRoots() (*CertPool, error) {
|
||||
}
|
||||
|
||||
var (
|
||||
mu sync.Mutex
|
||||
roots = NewCertPool()
|
||||
mu sync.Mutex
|
||||
roots = NewCertPool()
|
||||
numVerified int // number of execs of 'security verify-cert', for debug stats
|
||||
)
|
||||
add := func(cert *Certificate) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
roots.AddCert(cert)
|
||||
}
|
||||
|
||||
blockCh := make(chan *pem.Block)
|
||||
var wg sync.WaitGroup
|
||||
|
||||
// Using 4 goroutines to pipe into verify-cert seems to be
|
||||
// about the best we can do. The verify-cert binary seems to
|
||||
// just RPC to another server with coarse locking anyway, so
|
||||
// running 16 at a time for instance doesn't help at all. Due
|
||||
// to the "if hasPolicy" check below, though, we will rarely
|
||||
// (or never) call verify-cert on stock macOS systems, though.
|
||||
// The hope is that we only call verify-cert when the user has
|
||||
// tweaked their trust policy. These 4 goroutines are only
|
||||
// defensive in the pathological case of many trust edits.
|
||||
for i := 0; i < 4; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for block := range blockCh {
|
||||
verifyCertWithSystem(block, add)
|
||||
cert, err := ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
sha1CapHex := fmt.Sprintf("%X", sha1.Sum(block.Bytes))
|
||||
|
||||
valid := true
|
||||
verifyChecks := 0
|
||||
if hasPolicy[sha1CapHex] {
|
||||
verifyChecks++
|
||||
if !verifyCertWithSystem(block, cert) {
|
||||
valid = false
|
||||
}
|
||||
}
|
||||
|
||||
mu.Lock()
|
||||
numVerified += verifyChecks
|
||||
if valid {
|
||||
roots.AddCert(cert)
|
||||
}
|
||||
mu.Unlock()
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -67,67 +127,118 @@ func execSecurityRoots() (*CertPool, error) {
|
||||
}
|
||||
close(blockCh)
|
||||
wg.Wait()
|
||||
|
||||
if debugExecDarwinRoots {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
println(fmt.Sprintf("crypto/x509: ran security verify-cert %d times", numVerified))
|
||||
}
|
||||
|
||||
return roots, nil
|
||||
}
|
||||
|
||||
func verifyCertWithSystem(block *pem.Block, add func(*Certificate)) {
|
||||
func verifyCertWithSystem(block *pem.Block, cert *Certificate) bool {
|
||||
data := pem.EncodeToMemory(block)
|
||||
var cmd *exec.Cmd
|
||||
if needsTmpFiles() {
|
||||
f, err := ioutil.TempFile("", "cert")
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "can't create temporary file for cert: %v", err)
|
||||
return
|
||||
}
|
||||
defer os.Remove(f.Name())
|
||||
if _, err := f.Write(data); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "can't write temporary file for cert: %v", err)
|
||||
return
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "can't write temporary file for cert: %v", err)
|
||||
return
|
||||
}
|
||||
cmd = exec.Command("/usr/bin/security", "verify-cert", "-c", f.Name(), "-l")
|
||||
} else {
|
||||
cmd = exec.Command("/usr/bin/security", "verify-cert", "-c", "/dev/stdin", "-l")
|
||||
cmd.Stdin = bytes.NewReader(data)
|
||||
}
|
||||
if cmd.Run() == nil {
|
||||
// Non-zero exit means untrusted
|
||||
cert, err := ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
add(cert)
|
||||
f, err := ioutil.TempFile("", "cert")
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "can't create temporary file for cert: %v", err)
|
||||
return false
|
||||
}
|
||||
defer os.Remove(f.Name())
|
||||
if _, err := f.Write(data); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "can't write temporary file for cert: %v", err)
|
||||
return false
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "can't write temporary file for cert: %v", err)
|
||||
return false
|
||||
}
|
||||
cmd := exec.Command("/usr/bin/security", "verify-cert", "-c", f.Name(), "-l", "-L")
|
||||
var stderr bytes.Buffer
|
||||
if debugExecDarwinRoots {
|
||||
cmd.Stderr = &stderr
|
||||
}
|
||||
if err := cmd.Run(); err != nil {
|
||||
if debugExecDarwinRoots {
|
||||
println(fmt.Sprintf("crypto/x509: verify-cert rejected %s: %q", cert.Subject.CommonName, bytes.TrimSpace(stderr.Bytes())))
|
||||
}
|
||||
return false
|
||||
}
|
||||
if debugExecDarwinRoots {
|
||||
println(fmt.Sprintf("crypto/x509: verify-cert approved %s", cert.Subject.CommonName))
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
var versionCache struct {
|
||||
sync.Once
|
||||
major int
|
||||
}
|
||||
|
||||
// needsTmpFiles reports whether the OS is <= 10.11 (which requires real
|
||||
// files as arguments to the security command).
|
||||
func needsTmpFiles() bool {
|
||||
versionCache.Do(func() {
|
||||
release, err := syscall.Sysctl("kern.osrelease")
|
||||
if err != nil {
|
||||
return
|
||||
// getCertsWithTrustPolicy returns the set of certs that have a
|
||||
// possibly-altered trust policy. The keys of the map are capitalized
|
||||
// sha1 hex of the raw cert.
|
||||
// They are the certs that should be checked against `security
|
||||
// verify-cert` to see whether the user altered the default trust
|
||||
// settings. This code is only used for cgo-disabled builds.
|
||||
func getCertsWithTrustPolicy() (map[string]bool, error) {
|
||||
set := map[string]bool{}
|
||||
td, err := ioutil.TempDir("", "x509trustpolicy")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer os.RemoveAll(td)
|
||||
run := func(file string, args ...string) error {
|
||||
file = filepath.Join(td, file)
|
||||
args = append(args, file)
|
||||
cmd := exec.Command("/usr/bin/security", args...)
|
||||
var stderr bytes.Buffer
|
||||
cmd.Stderr = &stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
// If there are no trust settings, the
|
||||
// `security trust-settings-export` command
|
||||
// fails with:
|
||||
// exit status 1, SecTrustSettingsCreateExternalRepresentation: No Trust Settings were found.
|
||||
// Rather than match on English substrings that are probably
|
||||
// localized on macOS, just interpret any failure to mean that
|
||||
// there are no trust settings.
|
||||
if debugExecDarwinRoots {
|
||||
println(fmt.Sprintf("crypto/x509: exec %q: %v, %s", cmd.Args, err, stderr.Bytes()))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
for i, c := range release {
|
||||
if c == '.' {
|
||||
release = release[:i]
|
||||
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// Gather all the runs of 40 capitalized hex characters.
|
||||
br := bufio.NewReader(f)
|
||||
var hexBuf bytes.Buffer
|
||||
for {
|
||||
b, err := br.ReadByte()
|
||||
isHex := ('A' <= b && b <= 'F') || ('0' <= b && b <= '9')
|
||||
if isHex {
|
||||
hexBuf.WriteByte(b)
|
||||
} else {
|
||||
if hexBuf.Len() == 40 {
|
||||
set[hexBuf.String()] = true
|
||||
}
|
||||
hexBuf.Reset()
|
||||
}
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
major, err := strconv.Atoi(release)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
versionCache.major = major
|
||||
})
|
||||
return versionCache.major <= 15
|
||||
|
||||
return nil
|
||||
}
|
||||
if err := run("user", "trust-settings-export"); err != nil {
|
||||
return nil, fmt.Errorf("dump-trust-settings (user): %v", err)
|
||||
}
|
||||
if err := run("admin", "trust-settings-export", "-d"); err != nil {
|
||||
return nil, fmt.Errorf("dump-trust-settings (admin): %v", err)
|
||||
}
|
||||
return set, nil
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ package x509
|
||||
import (
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestSystemRoots(t *testing.T) {
|
||||
@@ -15,13 +16,21 @@ func TestSystemRoots(t *testing.T) {
|
||||
t.Skipf("skipping on %s/%s, no system root", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
|
||||
sysRoots := systemRootsPool() // actual system roots
|
||||
t0 := time.Now()
|
||||
sysRoots := systemRootsPool() // actual system roots
|
||||
sysRootsDuration := time.Since(t0)
|
||||
|
||||
t1 := time.Now()
|
||||
execRoots, err := execSecurityRoots() // non-cgo roots
|
||||
execSysRootsDuration := time.Since(t1)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("failed to read system roots: %v", err)
|
||||
}
|
||||
|
||||
t.Logf(" cgo sys roots: %v", sysRootsDuration)
|
||||
t.Logf("non-cgo sys roots: %v", execSysRootsDuration)
|
||||
|
||||
for _, tt := range []*CertPool{sysRoots, execRoots} {
|
||||
if tt == nil {
|
||||
t.Fatal("no system roots")
|
||||
|
||||
@@ -1421,10 +1421,9 @@ func (tx *Tx) isDone() bool {
|
||||
// that has already been committed or rolled back.
|
||||
var ErrTxDone = errors.New("sql: Transaction has already been committed or rolled back")
|
||||
|
||||
// close returns the connection to the pool and
|
||||
// must only be called by Tx.rollback or Tx.Commit.
|
||||
func (tx *Tx) close(err error) {
|
||||
if !atomic.CompareAndSwapInt32(&tx.done, 0, 1) {
|
||||
panic("double close") // internal error
|
||||
}
|
||||
tx.db.putConn(tx.dc, err)
|
||||
tx.cancel()
|
||||
tx.dc = nil
|
||||
@@ -1449,7 +1448,7 @@ func (tx *Tx) closePrepared() {
|
||||
|
||||
// Commit commits the transaction.
|
||||
func (tx *Tx) Commit() error {
|
||||
if tx.isDone() {
|
||||
if !atomic.CompareAndSwapInt32(&tx.done, 0, 1) {
|
||||
return ErrTxDone
|
||||
}
|
||||
select {
|
||||
@@ -1471,7 +1470,7 @@ func (tx *Tx) Commit() error {
|
||||
// rollback aborts the transaction and optionally forces the pool to discard
|
||||
// the connection.
|
||||
func (tx *Tx) rollback(discardConn bool) error {
|
||||
if tx.isDone() {
|
||||
if !atomic.CompareAndSwapInt32(&tx.done, 0, 1) {
|
||||
return ErrTxDone
|
||||
}
|
||||
var err error
|
||||
@@ -2087,7 +2086,7 @@ func (rs *Rows) Next() bool {
|
||||
}
|
||||
// The driver is at the end of the current result set.
|
||||
// Test to see if there is another result set after the current one.
|
||||
// Only close Rows if there is no futher result sets to read.
|
||||
// Only close Rows if there is no further result sets to read.
|
||||
if !nextResultSet.HasNextResultSet() {
|
||||
rs.Close()
|
||||
}
|
||||
|
||||
@@ -2607,6 +2607,54 @@ func TestIssue6081(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestIssue18429 attempts to stress rolling back the transaction from a
|
||||
// context cancel while simultaneously calling Tx.Rollback. Rolling back from a
|
||||
// context happens concurrently so tx.rollback and tx.Commit must guard against
|
||||
// double entry.
|
||||
//
|
||||
// In the test, a context is canceled while the query is in process so
|
||||
// the internal rollback will run concurrently with the explicitly called
|
||||
// Tx.Rollback.
|
||||
func TestIssue18429(t *testing.T) {
|
||||
db := newTestDB(t, "people")
|
||||
defer closeDB(t, db)
|
||||
|
||||
ctx := context.Background()
|
||||
sem := make(chan bool, 20)
|
||||
var wg sync.WaitGroup
|
||||
|
||||
const milliWait = 30
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
sem <- true
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer func() {
|
||||
<-sem
|
||||
wg.Done()
|
||||
}()
|
||||
qwait := (time.Duration(rand.Intn(milliWait)) * time.Millisecond).String()
|
||||
|
||||
ctx, cancel := context.WithTimeout(ctx, time.Duration(rand.Intn(milliWait))*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
rows, err := tx.QueryContext(ctx, "WAIT|"+qwait+"|SELECT|people|name|")
|
||||
if rows != nil {
|
||||
rows.Close()
|
||||
}
|
||||
// This call will race with the context cancel rollback to complete
|
||||
// if the rollback itself isn't guarded.
|
||||
tx.Rollback()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
time.Sleep(milliWait * 3 * time.Millisecond)
|
||||
}
|
||||
|
||||
func TestConcurrency(t *testing.T) {
|
||||
doConcurrentTest(t, new(concurrentDBQueryTest))
|
||||
doConcurrentTest(t, new(concurrentDBExecTest))
|
||||
|
||||
@@ -439,16 +439,11 @@ func (ctxt *Context) ImportDir(dir string, mode ImportMode) (*Package, error) {
|
||||
// containing no buildable Go source files. (It may still contain
|
||||
// test files, files hidden by build tags, and so on.)
|
||||
type NoGoError struct {
|
||||
Dir string
|
||||
Ignored bool // whether any Go files were ignored due to build tags
|
||||
Dir string
|
||||
}
|
||||
|
||||
func (e *NoGoError) Error() string {
|
||||
msg := "no buildable Go source files in " + e.Dir
|
||||
if e.Ignored {
|
||||
msg += " (.go files ignored due to build tags)"
|
||||
}
|
||||
return msg
|
||||
return "no buildable Go source files in " + e.Dir
|
||||
}
|
||||
|
||||
// MultiplePackageError describes a directory containing
|
||||
@@ -880,7 +875,7 @@ Found:
|
||||
return p, badGoError
|
||||
}
|
||||
if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
|
||||
return p, &NoGoError{Dir: p.Dir, Ignored: len(p.IgnoredGoFiles) > 0}
|
||||
return p, &NoGoError{p.Dir}
|
||||
}
|
||||
|
||||
for tag := range allTags {
|
||||
|
||||
@@ -93,17 +93,6 @@ func TestEmptyFolderImport(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestIgnoredGoFilesImport(t *testing.T) {
|
||||
_, err := Import(".", "testdata/ignored", 0)
|
||||
e, ok := err.(*NoGoError)
|
||||
if !ok {
|
||||
t.Fatal(`Import("testdata/ignored") did not return NoGoError.`)
|
||||
}
|
||||
if !e.Ignored {
|
||||
t.Fatal(`Import("testdata/ignored") should have ignored Go files.`)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultiplePackageImport(t *testing.T) {
|
||||
_, err := Import(".", "testdata/multi", 0)
|
||||
mpe, ok := err.(*MultiplePackageError)
|
||||
|
||||
3
src/go/build/testdata/ignored/ignored.go
vendored
3
src/go/build/testdata/ignored/ignored.go
vendored
@@ -1,3 +0,0 @@
|
||||
// +build alwaysignore
|
||||
|
||||
package ignored
|
||||
@@ -173,7 +173,7 @@ func ParseDir(fset *token.FileSet, path string, filter func(os.FileInfo) bool, m
|
||||
}
|
||||
|
||||
// ParseExprFrom is a convenience function for parsing an expression.
|
||||
// The arguments have the same meaning as for Parse, but the source must
|
||||
// The arguments have the same meaning as for ParseFile, but the source must
|
||||
// be a valid Go (type or value) expression. Specifically, fset must not
|
||||
// be nil.
|
||||
//
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
// Package types declares the data types and implements
|
||||
// the algorithms for type-checking of Go packages. Use
|
||||
// Config.Check to invoke the type checker for a package.
|
||||
// Alternatively, create a new type checked with NewChecker
|
||||
// Alternatively, create a new type checker with NewChecker
|
||||
// and invoke it incrementally by calling Checker.Files.
|
||||
//
|
||||
// Type-checking consists of several interdependent phases:
|
||||
|
||||
@@ -157,6 +157,7 @@ func TestStdFixed(t *testing.T) {
|
||||
"issue11362.go", // canonical import path check
|
||||
"issue15002.go", // uses Mmap; testTestDir should consult build tags
|
||||
"issue16369.go", // go/types handles this correctly - not an issue
|
||||
"issue18459.go", // go/types doesn't check validity of //go:xxx directives
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -85,6 +85,7 @@ func (p *pipe) write(b []byte) (n int, err error) {
|
||||
}
|
||||
if p.werr != nil {
|
||||
err = ErrClosedPipe
|
||||
break
|
||||
}
|
||||
p.wwait.Wait()
|
||||
}
|
||||
|
||||
@@ -247,6 +247,18 @@ func TestPipeWriteClose(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Test close on Write side during Write.
|
||||
func TestPipeWriteClose2(t *testing.T) {
|
||||
c := make(chan int, 1)
|
||||
_, w := Pipe()
|
||||
go delayClose(t, w, c, pipeTest{})
|
||||
n, err := w.Write(make([]byte, 64))
|
||||
<-c
|
||||
if n != 0 || err != ErrClosedPipe {
|
||||
t.Errorf("write to closed pipe: %v, %v want %v, %v", n, err, 0, ErrClosedPipe)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteEmpty(t *testing.T) {
|
||||
r, w := Pipe()
|
||||
go func() {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user