1
0
mirror of https://github.com/golang/go synced 2024-11-12 03:40:21 -07:00
Commit Graph

17189 Commits

Author SHA1 Message Date
Dmitriy Vyukov
71c6da39ce runtime/pprof: fix test
R=golang-dev, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/12790043
2013-08-13 12:18:29 -04:00
Dmitriy Vyukov
aaab946943 runtime: fix handling of network deadlines
Ensure that deadlines affect already issued IO.

R=golang-dev, mikioh.mikioh, bradfitz
CC=golang-dev
https://golang.org/cl/12847043
2013-08-13 19:11:42 +04:00
Dmitriy Vyukov
d1cefd6b6d doc: update go1.2.txt
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/12851043
2013-08-13 17:21:33 +04:00
Dmitriy Vyukov
0e15b03f93 sync/atomic: add Swap functions
Fixes #5722.

R=golang-dev, khr, cshapiro, rsc, r
CC=golang-dev
https://golang.org/cl/12670045
2013-08-13 15:26:48 +04:00
Mikio Hara
39a7017c26 net: make deadline helpers join to netFD as its methods
Just for readability reasons; to prevent overlooking deadline stuff
across over platforms.

R=golang-dev, dvyukov
CC=golang-dev
https://golang.org/cl/8656044
2013-08-13 20:00:58 +09:00
Dmitriy Vyukov
5a20b4a6a9 sync: faster Cond
The new version does not require any memory allocations and is 30-50% faster.
Also detect and painc if Cond is copied after first.

benchmark            old ns/op    new ns/op    delta
BenchmarkCond1             317          195  -38.49%
BenchmarkCond1-2           875          607  -30.63%
BenchmarkCond1-4          1116          548  -50.90%
BenchmarkCond1-8          1013          613  -39.49%
BenchmarkCond1-16          983          450  -54.22%
BenchmarkCond2             559          352  -37.03%
BenchmarkCond2-2          1916         1378  -28.08%
BenchmarkCond2-4          1518         1322  -12.91%
BenchmarkCond2-8          2313         1291  -44.19%
BenchmarkCond2-16         1885         1078  -42.81%
BenchmarkCond4            1070          614  -42.62%
BenchmarkCond4-2          4899         3047  -37.80%
BenchmarkCond4-4          3813         3006  -21.16%
BenchmarkCond4-8          3605         3045  -15.53%
BenchmarkCond4-16         4148         2637  -36.43%
BenchmarkCond8            2086         1264  -39.41%
BenchmarkCond8-2          9961         6736  -32.38%
BenchmarkCond8-4          8135         7689   -5.48%
BenchmarkCond8-8          9623         7517  -21.89%
BenchmarkCond8-16        11661         8093  -30.60%

R=sougou, rsc, bradfitz, r
CC=golang-dev
https://golang.org/cl/11573043
2013-08-13 14:45:36 +04:00
Dmitriy Vyukov
d1b66439f9 runtime: eliminate excessive notewakeup calls in timers
If the timer goroutine is wakeup by timeout,
other goroutines will still notewakeup because sleeping is still set.

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/12763043
2013-08-13 14:14:24 +04:00
Dmitriy Vyukov
e33e476e07 syscall: disable cpu profiling around fork
Fixes #5517.
Fixes #5659.

R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/12183044
2013-08-13 13:01:30 +04:00
Dmitriy Vyukov
9707f269c1 runtime: fix network timers related crash
Fixes #6103.

R=golang-dev, alex.brainman
CC=golang-dev
https://golang.org/cl/12686045
2013-08-13 12:55:57 +04:00
Andrew Gerrand
1ee21701c7 tag go1.1.2
R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/12836044
2013-08-13 16:33:59 +10:00
David Symonds
c272fd14a8 go/doc: permit a package synopsis to end with ":\n".
R=gri, r
CC=golang-dev
https://golang.org/cl/12822043
2013-08-13 16:20:17 +10:00
Andrew Gerrand
f7ab3917f9 doc: release notes for go1.1.2
R=golang-dev, go.peter.90, rsc, r
CC=golang-dev
https://golang.org/cl/12016043
2013-08-13 15:08:10 +10:00
Russ Cox
fa72679f07 cmd/gc: add temporary-merging optimization pass
The compilers assume they can generate temporary variables
as needed to preserve the right semantics or simplify code
generation and the back end will still generate good code.
This turns out not to be true. The back ends will only
track the first 128 variables per function and give up
on the remainder. That needs to be fixed too, in a later CL.

This CL merges temporary variables with equal types and
non-overlapping lifetimes using the greedy algorithm in
Poletto and Sarkar, "Linear Scan Register Allocation",
ACM TOPLAS 1999.

The result can be striking in the right functions.

Top 20 frame size changes in a 6g godoc binary by bytes saved:

5464 1984 (-3480, -63.7%) go/build.(*Context).Import
4456 1824 (-2632, -59.1%) go/printer.(*printer).expr1
2560   80 (-2480, -96.9%) time.nextStdChunk
3496 1608 (-1888, -54.0%) go/printer.(*printer).stmt
1896  272 (-1624, -85.7%) net/http.init
2688 1400 (-1288, -47.9%) fmt.(*pp).printReflectValue
2800 1512 (-1288, -46.0%) main.main
3296 2016 (-1280, -38.8%) crypto/tls.(*Conn).clientHandshake
1664  488 (-1176, -70.7%) time.loadZoneZip
1760  608 (-1152, -65.5%) time.parse
4104 3072 (-1032, -25.1%) runtime/pprof.writeHeap
1680  712 ( -968, -57.6%) go/ast.Walk
2488 1560 ( -928, -37.3%) crypto/x509.parseCertificate
1128  392 ( -736, -65.2%) math/big.nat.divLarge
1528  864 ( -664, -43.5%) go/printer.(*printer).fieldList
1360  712 ( -648, -47.6%) regexp/syntax.(*parser).factor
2104 1528 ( -576, -27.4%) encoding/asn1.parseField
1064  504 ( -560, -52.6%) encoding/xml.(*Decoder).text
 584   48 ( -536, -91.8%) html.init
1400  864 ( -536, -38.3%) go/doc.playExample

In the same godoc build, cuts the number of functions with
too many vars from 83 to 32.

R=ken2
CC=golang-dev
https://golang.org/cl/12829043
2013-08-13 00:09:31 -04:00
Rob Pike
306c29e963 doc/go1.2.txt: bufio.{Writer,Reader}.Reset
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/12830043
2013-08-13 13:39:45 +10:00
Brad Fitzpatrick
4d2494330e cmd/api: don't fail API check if there's no network
If the hg checkout of go.tools fails, check for Internet
connectivity before failing.

R=golang-dev, shivakumar.gn
CC=golang-dev
https://golang.org/cl/12814043
2013-08-12 19:18:47 -07:00
Russ Cox
4984e6e9fd cmd/6l: fix printing of frame size in TEXT instruction
R=ken2
CC=golang-dev
https://golang.org/cl/12827043
2013-08-12 22:04:24 -04:00
Russ Cox
dbf96addfb cmd/gc: move flow graph into portable opt
Now there's only one copy of the flow graph construction
and dominator computation, and different optimizations
can attach different annotations to the instructions.

R=ken2
CC=golang-dev
https://golang.org/cl/12797045
2013-08-12 22:02:10 -04:00
Rob Pike
954d14741d go/build: change the wording of NoGoError and comment it better
Out of context, it can be very confusing because there can be lots of Go
files in the directory, but the error message says there aren't.

R=golang-dev, dsymonds, rsc
CC=golang-dev
https://golang.org/cl/12823043
2013-08-13 11:32:32 +10:00
Elias Naur
83348a13fb text/template: Make function call builtin handle nil errors correctly
The call builtin unconditionally tries to convert a second return value from a function to the error type. This fails in case nil is returned, effectively making call useless for functions returning two values.

This CL adds a nil check for the second return value, and adds a test.

Note that for regular function and method calls the nil error case is handled correctly and is verified by a test.

R=r
CC=golang-dev
https://golang.org/cl/12804043
2013-08-13 11:11:05 +10:00
Russ Cox
9a0a59f171 cmd/6g, cmd/8g: proginfo carry fixes
Bugs pointed out by cshapiro in CL 12637051.

R=cshapiro
CC=golang-dev
https://golang.org/cl/12815043
2013-08-12 21:02:55 -04:00
Russ Cox
b3b87143f2 cmd/gc: support for "portable" optimization logic
Code in gc/popt.c is compiled as part of 5g, 6g, and 8g,
meaning it can use arch-specific headers but there's
just one copy of the code.

This is the same arrangement we use for the portable
code generation logic in gc/pgen.c.

Move fixjmp and noreturn there to get the ball rolling.

R=ken2
CC=golang-dev
https://golang.org/cl/12789043
2013-08-12 19:14:02 -04:00
Volker Dobler
4f86a96ac9 net/http: do not send malformed cookie domain attribute
Malformed domain attributes are not sent in a Set-Cookie header.
Instead the domain attribute is dropped which turns the cookie
into a host-only cookie. This is much safer than dropping characters
from domain attribute.

Domain attributes with a leading dot '.' are still allowed, even
if discouraged by RFC 6265 section 4.1.1.

Fixes #6013

R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/12745043
2013-08-12 15:14:34 -07:00
Keith Randall
e838334beb runtime: change textflags from numbers to symbols
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/12798043
2013-08-12 13:47:18 -07:00
Dmitriy Vyukov
2791ef0b67 runtime/race: add end-to-end test
Fixes #5933.

R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/12699051
2013-08-12 22:04:10 +04:00
Dmitriy Vyukov
fa4628346b runtime: remove unused m->racepc
The original plan was to collect allocation stacks
for all memory blocks. But it was never implemented
and it's not in near plans and it's unclear how to do it at all.

R=golang-dev, dave, bradfitz
CC=golang-dev
https://golang.org/cl/12724044
2013-08-12 21:48:19 +04:00
Dmitriy Vyukov
f3c1070fa4 sync/atomic: specify argsize for asm routines
Fixes #6098.

R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/12717043
2013-08-12 21:46:33 +04:00
Russ Cox
a07218385c cmd/5g: factor out prog information
Like CL 12637051, but for 5g instead of 6g.

R=ken2
CC=golang-dev
https://golang.org/cl/12779043
2013-08-12 13:42:23 -04:00
Russ Cox
5636b60b70 cmd/5l: fix encoding of new MOVB, MOVH instructions
They are just like MOVW and should be setting only
two register fields, not three.

R=ken2
CC=golang-dev, remyoudompheng
https://golang.org/cl/12781043
2013-08-12 13:42:04 -04:00
Dmitriy Vyukov
92254d4463 runtime: fix ARM assembly formatting
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/12702048
2013-08-12 21:36:33 +04:00
Keith Randall
8b789e1738 all: change textflags from numbers to symbols.
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/12774043
2013-08-12 10:25:36 -07:00
Keith Randall
1f7966346e math: convert textflags from numbers to symbols
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/12773044
2013-08-12 10:25:18 -07:00
Keith Randall
db324ccd72 syscall: Convert textflags from numbers to symbols.
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/12773043
2013-08-12 10:24:30 -07:00
Russ Cox
ac0df6ce89 cmd/8g: factor out prog information
Like CL 12637051, but for 8g instead of 6g.
Fix a few minor 6g errors too.

R=ken2
CC=golang-dev
https://golang.org/cl/12778043
2013-08-12 13:05:40 -04:00
Andrew Gerrand
8eb8ad2454 bufio: add Writer example
Update #5530

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/12504044
2013-08-12 13:03:50 +10:00
Rob Pike
6b706cf50d bufio: make it clear that the client must call Writer.Flush
Fixes #5530.

R=golang-dev, iant, com.liigo
CC=golang-dev
https://golang.org/cl/12688044
2013-08-12 12:55:33 +10:00
Rob Pike
ce00562607 crypto/rand: simplify example to exploit properties of ReadFull
No need for the complex condition.
Fixes #6089

R=golang-dev, mischief, adg
CC=golang-dev
https://golang.org/cl/12731043
2013-08-12 12:52:23 +10:00
Russ Cox
24c8035fbe cmd/6g: move opt instruction decode into common function
Add new proginfo function that returns information about a
Prog*. The information includes various instruction
description bits as well as a list of required registers set
and used and indexing registers used.

Convert the large instruction switches to use proginfo.

This information was formerly duplicated in multiple
optimization passes, inconsistently. For example, the
information about which registers an instruction requires
appeared three times for most instructions.

Most of the switches were incomplete or incorrect in some way.
For example, the switch in copyu did not list cases for INCB,
JPS, MOVAPD, MOVBWSX, MOVBWZX, PCDATA, POPQ, PUSHQ, STD,
TESTB, TESTQ, and XCHGL. Those were all falling into the
"unknown instruction" default case and stopping the rewrite,
perhaps unnecessarily. Similarly, the switch in needc only
listed a handful of the instructions that use or set the carry bit.

We still need to decide whether to use proginfo to generalize
a few of the remaining smaller switches in peep.c.

If this goes well, we'll make similar changes in 8g and 5g.

R=ken2
CC=golang-dev
https://golang.org/cl/12637051
2013-08-11 21:46:38 -04:00
Rob Pike
9baac2bf15 doc/go1.2.txt: json and ampersands
R=golang-dev, adg
CC=golang-dev
https://golang.org/cl/12698047
2013-08-12 11:28:25 +10:00
Dmitriy Vyukov
2758101b9d runtime/pprof: add block profile test
Fixes #5993.

R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/12665046
2013-08-11 13:05:51 +04:00
Brad Fitzpatrick
3e38b7f246 net/http: simplify server, use bufio Reader.Reset and Writer.Reset
Update #5100
Update #6086

Remove switchReader, switchWriter, switchReaderPair,
switchWriterPair, etc.

Now it only maintains pools of bufio Readers and Writers, but
uses Reset instead of working around all their
previously-associated state.

Compared to before the bufio Reset change, it's the same number of
allocations, and also faster:

benchmark                                   old ns/op    new ns/op    delta
BenchmarkClientServer                          111218       109828   -1.25%
BenchmarkClientServerParallel4                  70580        70013   -0.80%
BenchmarkClientServerParallel64                 72636        68919   -5.12%
BenchmarkServer                                139858       137068   -1.99%
BenchmarkServerFakeConnNoKeepAlive              14619        14314   -2.09%
BenchmarkServerFakeConnWithKeepAlive            12390        11361   -8.31%
BenchmarkServerFakeConnWithKeepAliveLite         7630         7306   -4.25%
BenchmarkServerHandlerTypeLen                    9688         9342   -3.57%
BenchmarkServerHandlerNoLen                      8700         8470   -2.64%
BenchmarkServerHandlerNoType                     9255         8949   -3.31%
BenchmarkServerHandlerNoHeader                   7058         6806   -3.57%

benchmark                                  old allocs   new allocs    delta
BenchmarkClientServer                              61           61    0.00%
BenchmarkClientServerParallel4                     61           61    0.00%
BenchmarkClientServerParallel64                    61           61    0.00%
BenchmarkServer                                    16           16    0.00%
BenchmarkServerFakeConnNoKeepAlive                 24           24    0.00%
BenchmarkServerFakeConnWithKeepAlive               19           19    0.00%
BenchmarkServerFakeConnWithKeepAliveLite            9            9    0.00%
BenchmarkServerHandlerTypeLen                      17           17    0.00%
BenchmarkServerHandlerNoLen                        14           14    0.00%
BenchmarkServerHandlerNoType                       15           15    0.00%
BenchmarkServerHandlerNoHeader                      9            9    0.00%

benchmark                                   old bytes    new bytes    delta
BenchmarkClientServer                            6988         6985   -0.04%
BenchmarkClientServerParallel4                   6979         6985    0.09%
BenchmarkClientServerParallel64                  7002         7019    0.24%
BenchmarkServer                                  1846         1848    0.11%
BenchmarkServerFakeConnNoKeepAlive               2420         2412   -0.33%
BenchmarkServerFakeConnWithKeepAlive             2126         2129    0.14%
BenchmarkServerFakeConnWithKeepAliveLite          989          990    0.10%
BenchmarkServerHandlerTypeLen                    1818         1819    0.06%
BenchmarkServerHandlerNoLen                      1775         1777    0.11%
BenchmarkServerHandlerNoType                     1783         1785    0.11%
BenchmarkServerHandlerNoHeader                    989          990    0.10%

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/12708046
2013-08-10 19:22:44 -07:00
Brad Fitzpatrick
ede9aa9e02 bufio: drop buffer recycling, add Reader.Reset and Writer.Reset
Fixes #6086

R=golang-dev, pieter, r, rsc
CC=golang-dev
https://golang.org/cl/12603049
2013-08-10 19:22:19 -07:00
Russ Cox
7910cd68b5 cmd/gc: zero pointers on entry to function
On entry to a function, zero the results and zero the pointer
section of the local variables.

This is an intermediate step on the way to precise collection
of Go frames.

This can incur a significant (up to 30%) slowdown, but it also ensures
that the garbage collector never looks at a word in a Go frame
and sees a stale pointer value that could cause a space leak.
(C frames and assembly frames are still possibly problematic.)

This CL is required to start making collection of interface values
as precise as collection of pointer values are today.
Since we have to dereference the interface type to understand
whether the value is a pointer, it is critical that the type field be
initialized.

A future CL by Carl will make the garbage collection pointer
bitmaps context-sensitive. At that point it will be possible to
remove most of the zeroing. The only values that will still need
zeroing are values whose addresses escape the block scoping
of the function but do not escape to the heap.

benchmark                         old ns/op    new ns/op    delta
BenchmarkBinaryTree17            4420289180   4331060459   -2.02%
BenchmarkFannkuch11              3442469663   3277706251   -4.79%
BenchmarkFmtFprintfEmpty                100          142  +42.00%
BenchmarkFmtFprintfString               262          310  +18.32%
BenchmarkFmtFprintfInt                  213          281  +31.92%
BenchmarkFmtFprintfIntInt               355          431  +21.41%
BenchmarkFmtFprintfPrefixedInt          321          383  +19.31%
BenchmarkFmtFprintfFloat                444          533  +20.05%
BenchmarkFmtManyArgs                   1380         1559  +12.97%
BenchmarkGobDecode                 10240054     11794915  +15.18%
BenchmarkGobEncode                 17350274     19970478  +15.10%
BenchmarkGzip                     455179460    460699139   +1.21%
BenchmarkGunzip                   114271814    119291574   +4.39%
BenchmarkHTTPClientServer             89051        89894   +0.95%
BenchmarkJSONEncode                40486799     52691558  +30.15%
BenchmarkJSONDecode                94193361    112428781  +19.36%
BenchmarkMandelbrot200              4747060      4748043   +0.02%
BenchmarkGoParse                    6363798      6675098   +4.89%
BenchmarkRegexpMatchEasy0_32            129          171  +32.56%
BenchmarkRegexpMatchEasy0_1K            365          395   +8.22%
BenchmarkRegexpMatchEasy1_32            106          152  +43.40%
BenchmarkRegexpMatchEasy1_1K            952         1245  +30.78%
BenchmarkRegexpMatchMedium_32           198          283  +42.93%
BenchmarkRegexpMatchMedium_1K         79006       101097  +27.96%
BenchmarkRegexpMatchHard_32            3478         5115  +47.07%
BenchmarkRegexpMatchHard_1K          110245       163582  +48.38%
BenchmarkRevcomp                  777384355    793270857   +2.04%
BenchmarkTemplate                 136713089    157093609  +14.91%
BenchmarkTimeParse                     1511         1761  +16.55%
BenchmarkTimeFormat                     535          850  +58.88%

benchmark                          old MB/s     new MB/s  speedup
BenchmarkGobDecode                    74.95        65.07    0.87x
BenchmarkGobEncode                    44.24        38.43    0.87x
BenchmarkGzip                         42.63        42.12    0.99x
BenchmarkGunzip                      169.81       162.67    0.96x
BenchmarkJSONEncode                   47.93        36.83    0.77x
BenchmarkJSONDecode                   20.60        17.26    0.84x
BenchmarkGoParse                       9.10         8.68    0.95x
BenchmarkRegexpMatchEasy0_32         247.24       186.31    0.75x
BenchmarkRegexpMatchEasy0_1K        2799.20      2591.93    0.93x
BenchmarkRegexpMatchEasy1_32         299.31       210.44    0.70x
BenchmarkRegexpMatchEasy1_1K        1074.71       822.45    0.77x
BenchmarkRegexpMatchMedium_32          5.04         3.53    0.70x
BenchmarkRegexpMatchMedium_1K         12.96        10.13    0.78x
BenchmarkRegexpMatchHard_32            9.20         6.26    0.68x
BenchmarkRegexpMatchHard_1K            9.29         6.26    0.67x
BenchmarkRevcomp                     326.95       320.40    0.98x
BenchmarkTemplate                     14.19        12.35    0.87x

R=cshapiro
CC=golang-dev
https://golang.org/cl/12616045
2013-08-09 23:10:58 -04:00
Russ Cox
207289660a doc: update go1.2.txt
I skimmed the submitted CLs back to Monday.

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/12696045
2013-08-09 22:25:49 -04:00
ChaiShushan
418e2f6aae strconv: fix typo in docs
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/12709044
2013-08-10 11:38:42 +10:00
Mikio Hara
db84a450d7 net: move InvalidAddrError type into net.go
Probably we should remove this type before Go 1 contract has settled,
but too late. Instead, keep InvalidAddrError close to package generic
error types.

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/12670044
2013-08-10 09:46:22 +09:00
Pieter Droogendijk
e486cefec2 doc/go1.2.txt: Added missing changes since 1st of August
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/12714043
2013-08-10 09:48:43 +10:00
Carl Shapiro
abc516e420 cmd/cc, cmd/gc, runtime: Uniquely encode iface and eface pointers in the pointer map.
Prior to this change, pointer maps encoded the disposition of
a word using a single bit.  A zero signaled a non-pointer
value and a one signaled a pointer value.  Interface values,
which are a effectively a union type, were conservatively
labeled as a pointer.

This change widens the logical element size of the pointer map
to two bits per word.  As before, zero signals a non-pointer
value and one signals a pointer value.  Additionally, a two
signals an iface pointer and a three signals an eface pointer.

Following other changes to the runtime, values two and three
will allow a type information to drive interpretation of the
subsequent word so only those interface values containing a
pointer value will be scanned.

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/12689046
2013-08-09 16:48:12 -07:00
Rob Pike
556b337ece encoding/binary: better description for intReadSize
It used to be called intDestSize; the new name is better too.

R=bradfitz
CC=golang-dev
https://golang.org/cl/12713043
2013-08-10 09:11:58 +10:00
Russ Cox
b78410bda1 cmd/api: eliminate duplicate package import work
On my Mac, cuts the API checks from 15 seconds to 6 seconds.
Also clean up some tag confusion: go run list-of-files ignores tags.

R=bradfitz, gri
CC=golang-dev
https://golang.org/cl/12699048
2013-08-09 18:44:00 -04:00
Rob Pike
1f25f5ad48 encoding/binary: fast path for reading slices
Again, it still allocates but the code is simple.

benchmark                       old ns/op    new ns/op    delta
BenchmarkReadSlice1000Int32s        35580        11465  -67.78%

benchmark                        old MB/s     new MB/s  speedup
BenchmarkReadSlice1000Int32s       112.42       348.86    3.10x

R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/12694048
2013-08-10 08:40:32 +10:00