Scanning through all path patterns is not necessary, since the
paths do not change frequently. Instead, maintain a sorted list
of path prefixes and return the first match.
name old time/op new time/op delta
ServerMatch-12 134ns ± 3% 17ns ± 4% -86.95% (p=0.000 n=19+20)
Change-Id: I15b4483dc30db413321435ee6815fc9bf2bcc546
Reviewed-on: https://go-review.googlesource.com/c/144937
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Go documentation style for boolean funcs is to say:
// Foo reports whether ...
func Foo() bool
(rather than "returns true if")
This CL also replaces 4 uses of "iff" with the same "reports whether"
wording, which doesn't lose any meaning, and will prevent people from
sending typo fixes when they don't realize it's "if and only if". In
the past I think we've had the typo CLs updated to just say "reports
whether". So do them all at once.
(Inspired by the addition of another "returns true if" in CL 146938
in fd_plan9.go)
Created with:
$ perl -i -npe 's/returns true if/reports whether/' $(git grep -l "returns true iff" | grep -v vendor)
$ perl -i -npe 's/returns true if/reports whether/' $(git grep -l "returns true if" | grep -v vendor)
Change-Id: Ided502237f5ab0d25cb625dbab12529c361a8b9f
Reviewed-on: https://go-review.googlesource.com/c/147037
Reviewed-by: Ian Lance Taylor <iant@golang.org>
The compiler must first be built with the constant enableTrace set
to true (typecheck.go). After that, the -t flag becomes available
which enables tracing output of type-checking functions.
With enableTrace == false, the tracing code becomes dead code
and won't affect the compiler.
Typical output might look like this:
path/y.go:4:6: typecheck 0xc00033e180 DCLTYPE <node DCLTYPE> tc=0
path/y.go:4:6: . typecheck1 0xc00033e180 DCLTYPE <node DCLTYPE> tc=2
path/y.go:4:6: . . typecheck 0xc000331a40 TYPE T tc=1
path/y.go:4:6: . . . typecheck1 0xc000331a40 TYPE T tc=2
path/y.go:4:6: . . . . typecheckdef 0xc000331a40 TYPE T tc=2
path/y.go:4:6: . . . . => 0xc000331a40 TYPE T tc=2 type=*T
path/y.go:4:6: . . . => 0xc000331a40 TYPE T tc=2 type=*T
path/y.go:4:6: . . => 0xc000331a40 TYPE T tc=1 type=*T
path/y.go:4:6: . => 0xc00033e180 DCLTYPE <node DCLTYPE> tc=2 type=<T>
path/y.go:4:6: => 0xc00033e180 DCLTYPE <node DCLTYPE> tc=1 type=<T>
Disabled by default.
Change-Id: Ifd8385290d1cf0d3fc5e8468b2f4ab84e8eff338
Reviewed-on: https://go-review.googlesource.com/c/146782
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Implement a basic TLS 1.3 server handshake, only enabled if explicitly
requested with MaxVersion.
This CL intentionally leaves for future CLs:
- PSK modes and resumption
- client authentication
- compatibility mode ChangeCipherSpecs
- early data skipping
- post-handshake messages
- downgrade protection
- KeyLogWriter support
- TLS_FALLBACK_SCSV processing
It also leaves a few areas up for a wider refactor (maybe in Go 1.13):
- the certificate selection logic can be significantly improved,
including supporting and surfacing signature_algorithms_cert, but
this isn't new in TLS 1.3 (see comment in processClientHello)
- handshake_server_tls13.go can be dried up and broken into more
meaningful, smaller functions, but it felt premature to do before
PSK and client auth support
- the monstrous ClientHello equality check in doHelloRetryRequest can
get both cleaner and more complete with collaboration from the
parsing layer, which can come at the same time as extension
duplicates detection
Updates #9671
Change-Id: Id9db2b6ecc2eea21bf9b59b6d1d9c84a7435151c
Reviewed-on: https://go-review.googlesource.com/c/147017
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
crypto/x509 already supports PSS signatures (with rsaEncryption OID),
and crypto/tls support was added in CL 79736. Advertise support for the
algorithms and accept them as a peer.
Note that this is about PSS signatures from regular RSA public keys.
RSA-PSS only public keys (with RSASSA-PSS OID) are supported in neither
crypto/tls nor crypto/x509. See RFC 8446, Section 4.2.3.
testdata/Server-TLSv12-ClientAuthRequested* got modified because the
CertificateRequest carries the supported signature algorithms.
The net/smtp tests changed because 512 bits keys are too small for PSS.
Based on Peter Wu's CL 79738, who did all the actual work in CL 79736.
Updates #9671
Change-Id: I4a31e9c6e152ff4c50a5c8a274edd610d5fff231
Reviewed-on: https://go-review.googlesource.com/c/146258
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
RFC 8446 recommends using the supported_versions extension to negotiate
lower versions as well, so begin by implementing it to negotiate the
currently supported versions.
Note that pickTLSVersion was incorrectly negotiating the ServerHello
version down on the client. If the server had illegally sent a version
higher than the ClientHello version, the client would have just
downgraded it, hopefully failing later in the handshake.
In TestGetConfigForClient, we were hitting the record version check
because the server would select TLS 1.1, the handshake would fail on the
client which required TLS 1.2, which would then send a TLS 1.0 record
header on its fatal alert (not having negotiated a version), while the
server would expect a TLS 1.1 header at that point. Now, the client gets
to communicate the minimum version through the extension and the
handshake fails on the server.
Updates #9671
Change-Id: Ie33c7124c0c769f62e10baad51cbed745c424e5b
Reviewed-on: https://go-review.googlesource.com/c/146217
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
Note that there is significant code duplication due to extensions with
the same format appearing in different messages in TLS 1.3. This will be
cleaned up in a future refactor once CL 145317 is merged.
Enforcing the presence/absence of each extension in each message is left
to the upper layer, based on both protocol version and extensions
advertised in CH and CR. Duplicated extensions and unknown extensions in
SH, EE, HRR, and CT will be tightened up in a future CL.
The TLS 1.2 CertificateStatus message was restricted to accepting only
type OCSP as any other type (none of which are specified so far) would
have to be negotiated.
Updates #9671
Change-Id: I7c42394c5cc0af01faa84b9b9f25fdc6e7cfbb9e
Reviewed-on: https://go-review.googlesource.com/c/145477
Reviewed-by: Adam Langley <agl@golang.org>
Unlikely to happen in practice, but easy enough to prevent and might
as well do so for completeness.
Fixes#28243.
Change-Id: I848c3af49cb923f088e9490c6a79373e182fad08
Reviewed-on: https://go-review.googlesource.com/c/142719
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Austin Clements <austin@google.com>
There are some OpenGL functions that take more than 15 arguments.
This CL adds Syscall18 to enable to call such functions on Windows
via syscall functions.
Fixes#28434
Change-Id: Ic7e37dda9cadf4516183e98166bfc52844ad2bbe
Reviewed-on: https://go-review.googlesource.com/c/147117
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
This commit skips tests which aren't yet supported on AIX.
nosplit.go is disabled because stackGuardMultiplier is increased for
syscalls.
Change-Id: Ib5ff9a4539c7646bcb6caee159f105ff8a160ad7
Reviewed-on: https://go-review.googlesource.com/c/146939
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
This commit fixes tests which fail on some versions of AIX 7.2 due
to internal bugs.
getsockname isn't working properly with unix networks.
Timezone files aren't returning a correct output.
Change-Id: I4ff15683912be62ab86dfbeeb63b73513404d086
Reviewed-on: https://go-review.googlesource.com/c/146940
Run-TryBot: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit changes poll.PollDescriptor by poll.IsPollDescriptor. This
is needed for OS like AIX which have more than one FD using inside their
netpoll implementation.
Change-Id: I49e12a8d74045c501e19fdd8527cf166a3c64850
Reviewed-on: https://go-review.googlesource.com/c/146938
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
We only need the memory barrier from these stores,
and we only store nil over nil or over a static function value.
The write barrier is unnecessary.
name old time/op new time/op delta
TCP4OneShotTimeout-6 17.0µs ± 0% 17.0µs ± 0% -0.43% (p=0.032 n=5+5)
SetReadDeadline-6 205ns ± 1% 205ns ± 1% ~ (p=0.683 n=5+5)
Update #25729
Change-Id: I66c097a1db7188697ddfc381f31acec053dfed2c
Reviewed-on: https://go-review.googlesource.com/c/146345
Run-TryBot: Dmitry Vyukov <dvyukov@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Follow CL 146020 and enable RemoveAll based on Unlinkat and Openat on
aix.
Updates #27029
Change-Id: I78b34ed671166ee6fa651d5f2025b88548ee6c68
Reviewed-on: https://go-review.googlesource.com/c/146937
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
Reviewed-by: Clément Chigot <clement.chigot@atos.net>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
runtimeNano is slower than nanotime, so pass the duration
to runtime_pollSetDeadline as is. netpoll can add nanotime itself.
Arguably a bit simpler because, say, a negative duration
clearly represents already expired timer, no need to compare to
nanotime again.
This may also fix an obscure corner case when a deadline in past
which happens to be nanotime 0 is confused with no deadline at all,
which are radically different things.
Also don't compute any durations and times if Time is zero
(currently we first compute everything and then reset d back to 0,
which is wasteful).
name old time/op new time/op delta
TCP4OneShotTimeout-6 17.1µs ± 0% 17.0µs ± 0% ~ (p=0.421 n=5+5)
SetReadDeadline-6 230ns ± 0% 205ns ± 1% -10.63% (p=0.008 n=5+5)
Change-Id: I2aad699270289a5b9ead68f5e44ec4ec6d96baa0
Reviewed-on: https://go-review.googlesource.com/c/146344
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Dmitry Vyukov <dvyukov@google.com>
We only need the memory barrier in poll_runtime_pollSetDeadline only
when one of the timers has fired, which is not the expected case.
Memory barrier can be somewhat expensive on some archs,
so execute it only if one of the timers has in fact fired.
name old time/op new time/op delta
TCP4OneShotTimeout-6 17.0µs ± 0% 17.1µs ± 0% +0.35% (p=0.032 n=5+5)
SetReadDeadline-6 232ns ± 0% 230ns ± 0% -1.03% (p=0.000 n=4+5)
Update #25729
Change-Id: Ifce6f505b9e7ba3717bad8f454077a2e94ea6e75
Reviewed-on: https://go-review.googlesource.com/c/146343
Reviewed-by: Ian Lance Taylor <iant@golang.org>
time.now is somewhat expensive (much more expensive than nanotime),
in the common case when Time has monotonic time we don't actually
need to call time.now in Since/Until as we can do calculation
based purely on monotonic times.
name old time/op new time/op delta
TCP4OneShotTimeout-6 17.0µs ± 0% 17.1µs ± 1% ~ (p=0.151 n=5+5)
SetReadDeadline-6 261ns ± 0% 234ns ± 1% -10.35% (p=0.008 n=5+5)
Benchmark that only calls Until:
benchmark old ns/op new ns/op delta
BenchmarkUntil 54.0 29.5 -45.37%
Update #25729
Change-Id: I5ac5af3eb1fe9f583cf79299f10b84501b1a0d7d
Reviewed-on: https://go-review.googlesource.com/c/146341
Run-TryBot: Dmitry Vyukov <dvyukov@google.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Move startNano from runtime to time package.
In preparation for a subsequent change that speeds up Since and Until.
This also makes code simpler as we have less assembly as the result,
monotonic time handling is better localized in time package.
This changes values returned from nanotime on windows
(it does not account for startNano anymore), current comments state
that it's important, but it's unclear how it can be important
since no other OS does this.
Update #25729
Change-Id: I2275d57b7b5ed8fd0d53eb0f19d55a86136cc555
Reviewed-on: https://go-review.googlesource.com/c/146340
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Currently when netpoll deadline is incrementally prolonged,
we delete and re-add timer each time.
Add modtimer function that does both and use it when we need
to modify an existing netpoll timer to avoid unnecessary lock/unlock.
TCP4OneShotTimeout-6 17.2µs ± 0% 17.0µs ± 0% -0.82% (p=0.008 n=5+5)
SetReadDeadline-6 274ns ± 2% 261ns ± 0% -4.89% (p=0.008 n=5+5)
Update #25729
Change-Id: I08b89dbbc1785dd180e967a37b0aa23b0c4613a8
Reviewed-on: https://go-review.googlesource.com/c/146339
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Currently we always delete both read and write timers and then
add them again. However, if user setups read and write deadline
separately, then we don't need to touch the other one.
name old time/op new time/op delta
TCP4OneShotTimeout-6 17.2µs ± 0% 17.2µs ± 0% ~ (p=0.310 n=5+5)
SetReadDeadline-6 319ns ± 1% 274ns ± 2% -13.94% (p=0.008 n=5+5)
Update #25729
Change-Id: I4c869c3083521de6d0cd6ca99a7609d4dd84b4e4
Reviewed-on: https://go-review.googlesource.com/c/146338
Reviewed-by: Ian Lance Taylor <iant@golang.org>
It's not always necessary to wake timerproc even if we add
a new timer to the top of the heap. Since we don't wake and
reset timerproc when we remove timers, it still can be sleeping
with shorter timeout. It such case it's more profitable to let it
sleep and then update timeout when it wakes on its own rather than
proactively wake it, let it update timeout and go to sleep again.
name old time/op new time/op delta
TCP4OneShotTimeout-6 18.6µs ± 1% 17.2µs ± 0% -7.66% (p=0.008 n=5+5)
SetReadDeadline-6 562ns ± 5% 319ns ± 1% -43.27% (p=0.008 n=5+5)
Update #25729
Change-Id: Iec8eacb8563dbc574a82358b3bac7ac479c16826
Reviewed-on: https://go-review.googlesource.com/c/146337
Reviewed-by: Ian Lance Taylor <iant@golang.org>
This change uses library functions such as bits.RotateLeft32 to
reduce the amount of code needed in the generic implementation.
Since the code is now shorter I've also removed the option to
generate a non-unrolled version of the code.
I've also tried to remove bounds checks where possible to make
the new version performant, however that is not the primary goal
of this change since most architectures have assembly
implementations already.
Assembly performance:
name old speed new speed delta
Hash8Bytes 50.3MB/s ± 1% 59.1MB/s ± 0% +17.63% (p=0.000 n=9+8)
Hash1K 590MB/s ± 0% 597MB/s ± 0% +1.25% (p=0.000 n=9+9)
Hash8K 636MB/s ± 1% 638MB/s ± 1% ~ (p=0.072 n=10+10)
Hash8BytesUnaligned 50.5MB/s ± 0% 59.1MB/s ± 1% +17.09% (p=0.000 n=10+10)
Hash1KUnaligned 589MB/s ± 1% 596MB/s ± 1% +1.23% (p=0.000 n=9+10)
Hash8KUnaligned 638MB/s ± 1% 640MB/s ± 0% +0.35% (p=0.002 n=10+10)
Pure Go performance:
name old speed new speed delta
Hash8Bytes 30.3MB/s ± 1% 42.8MB/s ± 0% +41.20% (p=0.000 n=9+9)
Hash1K 364MB/s ± 4% 394MB/s ± 1% +8.27% (p=0.000 n=10+10)
Hash8K 404MB/s ± 1% 420MB/s ± 0% +4.17% (p=0.000 n=10+9)
Hash8BytesUnaligned 30.3MB/s ± 1% 42.8MB/s ± 1% +40.92% (p=0.000 n=9+10)
Hash1KUnaligned 368MB/s ± 0% 394MB/s ± 0% +7.07% (p=0.000 n=9+9)
Hash8KUnaligned 404MB/s ± 1% 411MB/s ± 3% +1.91% (p=0.026 n=9+10)
Change-Id: I9a91fb52ea8d62964d5351bdf121e9fbc9282852
Reviewed-on: https://go-review.googlesource.com/c/137355
Run-TryBot: Michael Munday <mike.munday@ibm.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Stat uses Windows FindFirstFile + CreateFile to gather symlink
information - FindFirstFile determines if file is a symlink,
and then CreateFile follows symlink to capture target details.
Lstat only uses FindFirstFile.
This CL replaces current approach with just a call to CreateFile.
Lstat uses FILE_FLAG_OPEN_REPARSE_POINT flag, that instructs
CreateFile not to follow symlink. Other than that both Stat and
Lstat look the same now. New code is simpler.
CreateFile + GetFileInformationByHandle (unlike FindFirstFile)
does not report reparse tag of a file. I tried to ignore reparse
tag altogether. And it works for symlinks and mount points.
Unfortunately (see https://github.com/moby/moby/issues/37026),
files on deduped disk volumes are reported with
FILE_ATTRIBUTE_REPARSE_POINT attribute set and reparse tag set
to IO_REPARSE_TAG_DEDUP. So, if we ignore reparse tag, Lstat
interprets deduped volume files as symlinks. That is incorrect.
So I had to add GetFileInformationByHandleEx call to gather
reparse tag after calling CreateFile and GetFileInformationByHandle.
Fixes#27225Fixes#27515
Change-Id: If60233bcf18836c147597cc17450d82f3f88c623
Reviewed-on: https://go-review.googlesource.com/c/143578
Run-TryBot: Alex Brainman <alex.brainman@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Kirill Kolyshkin <kolyshkin@gmail.com>
This CL changes IsAbs to return true for "NUL" and other Windows
reserved filenames (search
https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file
for NUL for details). os.Open("NUL") and os.Stat("NUL") work
regardless of what current directory is, and it is mistake to join
"NUL" with current directory when building full path. Changing
IsAbs("NUL") to return true fixes that mistake.
Fixes#28035
Change-Id: Ife8f8aee48400702613ede8fc6834fd43e6e0f03
Reviewed-on: https://go-review.googlesource.com/c/145220
Run-TryBot: Alex Brainman <alex.brainman@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Updating each call in place broke when there were multiple cgo calls
used as arguments to another cgo call where some required rewriting.
Instead, rewrite calls to strings via the existing mangling mechanism,
and only substitute the top level call in place.
Fixes#28540
Change-Id: Ifd66f04c205adc4ad6dd5ee8e79e57dce17e86bb
Reviewed-on: https://go-review.googlesource.com/c/146860
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
As discussed in golang.org/cl/28499:
Only test that all expected variables are listed in 'info locals' since
different versions of gdb print variables in different order and with
differing amount of information and formats.
Fixes#28499
Change-Id: I76627351170b5fdf2bf8cbf143e54f628b45dc4e
Reviewed-on: https://go-review.googlesource.com/c/146598
Reviewed-by: Heschi Kreinick <heschi@google.com>
For many build systems, modular static analysis is most conveniently
implemented by saving analysis facts (which are analogous to export
data) in an additional section in the archive file, similar to
__PKGDEF. See golang.org/x/tools/go/analysis for an overview.
Because such sections are not object files, the linker must not
attempt to link them. This change causes the linker to skip special
sections whose name does not end with .o (and is short enough not to
be truncated).
Fixes#28429
Change-Id: I830852decf868cb017263308b114f72838032993
Reviewed-on: https://go-review.googlesource.com/c/146297
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Follow CL 146020 and enable RemoveAll based on Unlinkat and Openat on
freebsd.
Since the layout of syscall.Stat_t changes in FreeBSD 12, Fstatat needs
a compatibility wrapper akin to Fstatat in x/sys/unix. See CL 138595 and
CL 136816 for details.
Updates #27029
Change-Id: I8851a5b7fa658eaa6e69a1693150b16d9a68f36a
Reviewed-on: https://go-review.googlesource.com/c/146597
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Yuval Pavel Zholkover <paulzhol@gmail.com>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
The Dialer.DualStack field is now meaningless and documented as
deprecated.
To disable fallback, set FallbackDelay to a negative value.
Fixes#22225
Change-Id: Icc212fe07bb69d7651ab81e539b8b3e3d3372fa9
Reviewed-on: https://go-review.googlesource.com/c/146659
Reviewed-by: Ian Lance Taylor <iant@golang.org>
readContinuedLineSlice intends to buffer a continued line of text, where
a continued line can continue through newlines so long as the next line
begins with a space or tab.
The current optimization is to not try to buffer and build a line if we
immediately see that the next line begins with an ASCII character.
This adds avoiding copying the line if we see that the next line is \n
or \r\n as well.
Notably, headers always end in \r\n\r\n. In the general, well formatted
header case, we can now avoid ever allocating textproto.Reader's
internal reusable buf.
This can mildly be seen in net/http's BenchmarkClientServer:
name old time/op new time/op delta
ClientServer-4 66.4µs ± 0% 66.2µs ± 0% -0.35% (p=0.004 n=10+10)
name old alloc/op new alloc/op delta
ClientServer-4 4.87kB ± 0% 4.82kB ± 0% -1.01% (p=0.000 n=6+10)
name old allocs/op new allocs/op delta
ClientServer-4 64.0 ± 0% 63.0 ± 0% -1.56% (p=0.000 n=10+10)
Change-Id: Id8c2ab69086ac481b90abda289396dcb7bfe8851
Reviewed-on: https://go-review.googlesource.com/c/134227
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Also, use a random temporary directory rather than os.TempDir. Defer
removal of existing random temporary directories.
Change-Id: Id7549031cdf78a2bab28c07b6eeff621bdf6e49c
Reviewed-on: https://go-review.googlesource.com/c/146457
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Tobias Klauser <tobias.klauser@gmail.com>