| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
|
|
|
|
|
|
|
|
|
| |
runtime/cgo
Frankly, I don't understand how the current code could possibly work except
when every android program is using cgo. Discovered this while working on
the iOS port.
LGTM=crawshaw, rsc
R=rsc, crawshaw
CC=golang-codereviews
https://codereview.appspot.com/177470043
|
|\
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
This brings dev.power64 up-to-date with the current tip of
default. go_bootstrap is still panicking with a bad defer
when initializing the runtime (even on amd64).
LGTM=rsc
R=rsc
CC=golang-codereviews
https://codereview.appspot.com/152570049
|
| |\
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
This also removes pkg/runtime/traceback_lr.c, which was ported
to Go in an earlier commit and then moved to
runtime/traceback.go.
Reviewer: rsc@golang.org
rsc: LGTM
|
| |\ \
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
LGTM=rsc
R=rsc
CC=golang-codereviews
https://codereview.appspot.com/160200044
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
LGTM=minux
R=minux
CC=golang-codereviews
https://codereview.appspot.com/121690043
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
1. disable nonsplit stack overflow check
2. disable OLROT recognition
3. emit correct instructions for adding offsets to an address
LGTM=rsc
R=rsc, iant
CC=golang-codereviews
https://codereview.appspot.com/123310043
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
It was accidentally removed.
LGTM=dave
R=rsc, iant, dave
CC=golang-codereviews
https://codereview.appspot.com/124880043
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
LGTM=rsc
R=rsc, iant
CC=golang-codereviews
https://codereview.appspot.com/121380043
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
LGTM=rsc
R=minux, rsc
CC=golang-codereviews
https://codereview.appspot.com/158280043
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
Fixes issue 8348.
Clang's internal assembler (introduced by default in clang 3.4) understands the .arch directive, but doesn't change the default value of -march. This causes the build to fail when we use BLX (armv5 and above) when clang is compiled for the default armv4t architecture (which appears to be the default on all the distros I've used).
This is probably a clang bug, so work around it for the time being by disabling the integrated assembler when compiling the cgo assembly shim.
This CL also includes a small change to ldelf.c which was required as clang 3.4 and above generate more weird symtab entries.
LGTM=iant
R=golang-codereviews, iant
CC=golang-codereviews
https://codereview.appspot.com/156430044
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
Our current pe object reader assumes that every symbol starting with
'.' is section. It appeared to be true, until now gcc 4.9.1 generates
some symbols with '.' at the front. Change that logic to check other
symbol fields in addition to checking for '.'. I am not an expert
here, but it seems reasonable to me.
Added test, but it is only good, if tested with gcc 4.9.1. Otherwise
the test PASSes regardless.
Fixes issue 8811.
Fixes issue 8856.
LGTM=jfrederich, iant, stephen.gutekanst
R=golang-codereviews, jfrederich, stephen.gutekanst, iant
CC=alex.brainman, golang-codereviews
https://codereview.appspot.com/152410043
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
gcc 4.9.1 generates pe sections with names longer then 8 charters.
From IMAGE_SECTION_HEADER definition:
Name
An 8-byte, null-padded UTF-8 string. There is no terminating null character
if the string is exactly eight characters long. For longer names, this
member contains a forward slash (/) followed by an ASCII representation
of a decimal number that is an offset into the string table.
Our current pe object file reader does not read string table when section
names starts with /. Do that, so (issue 8811 example)
c:\go\path\src\isssue8811>go build
# isssue8811
isssue8811/glfw(.text): isssue8811/glfw(/76): not defined
isssue8811/glfw(.text): undefined: isssue8811/glfw(/76)
becomes
c:\go\path\src\isssue8811>go build
# isssue8811
isssue8811/glfw(.text): isssue8811/glfw(.rdata$.refptr._glfwInitialized): not defined
isssue8811/glfw(.text): undefined: isssue8811/glfw(.rdata$.refptr._glfwInitialized)
Small progress to
Update issue 8811
LGTM=iant, jfrederich
R=golang-codereviews, iant, jfrederich
CC=golang-codereviews
https://codereview.appspot.com/154210044
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
I diffed the output of `nm -n gofmt' before and after this change,
and verified that all changes are correct and all corrupted symbol
names are fixed.
Fixes issue 8906.
LGTM=iant, cookieo9
R=golang-codereviews, iant, cookieo9
CC=golang-codereviews
https://codereview.appspot.com/159750043
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
This makes dwardump --verify happy.
Update issue 8846
LGTM=r
R=golang-codereviews, r
CC=golang-codereviews
https://codereview.appspot.com/150370043
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
Depending on flags&KindGCProg,
gc[0] and gc[1] are either pointers or inlined bitmap bits.
That's not compatible with a precise garbage collector:
it needs to be always pointers or never pointers.
Change the inlined bitmap case to store a pointer to an
out-of-line bitmap in gc[0]. The out-of-line bitmaps are
dedup'ed, so that for example all pointer types share the
same out-of-line bitmap.
Fixes issue 8864.
LGTM=r
R=golang-codereviews, dvyukov, r
CC=golang-codereviews, iant, khr, rlh
https://codereview.appspot.com/155820043
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
http://build.golang.org/log/c7a91b6eac8f8daa2bd17801be273e58403a15f2
# cmd/pprof
/linux-386-clang-9115aad1dc4a/go/pkg/linux_386/net.a(_all.o): sym#16: ignoring .Linfo_string0 in section 16 (type 0)
/linux-386-clang-9115aad1dc4a/go/pkg/linux_386/net.a(_all.o): sym#17: ignoring .Linfo_string1 in section 16 (type 0)
/linux-386-clang-9115aad1dc4a/go/pkg/linux_386/net.a(_all.o): sym#18: ignoring .Linfo_string2 in section 16 (type 0)
/linux-386-clang-9115aad1dc4a/go/pkg/linux_386/net.a(_all.o): sym#20: ignoring .Linfo_string0 in section 16 (type 0)
/linux-386-clang-9115aad1dc4a/go/pkg/linux_386/net.a(_all.o): sym#21: ignoring .Linfo_string1 in section 16 (type 0)
...
I don't know what these are. Let's ignore them and see if we get any further.
TBR=iant
CC=golang-codereviews
https://codereview.appspot.com/155030043
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
Unnecessary; covered by https://codereview.appspot.com/141690043
Verified by jonathan@titanous.com on golang-dev.
??? original CL description
cmd/ld: close outfile before cleanup
This prevents the temporary directory from being leaked when
the linker is run on a FUSE filesystem.
Fixes issue 8684.
LGTM=bradfitz
R=golang-codereviews, rsc, bradfitz
CC=golang-codereviews
https://codereview.appspot.com/141840043
Committer: Brad Fitzpatrick <bradfitz@golang.org>
???
LGTM=jonathan, iant
R=iant, jonathan
CC=golang-codereviews
https://codereview.appspot.com/150250045
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
This prevents the temporary directory from being leaked when
the linker is run on a FUSE filesystem.
Fixes issue 8684.
LGTM=bradfitz
R=golang-codereviews, rsc, bradfitz
CC=golang-codereviews
https://codereview.appspot.com/141840043
Committer: Brad Fitzpatrick <bradfitz@golang.org>
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
This fixes the bug in which the linker reports "missing Go
type information" when a -X option refers to a symbol that is
not used.
Fixes issue 8821.
LGTM=rsc
R=rsc, r
CC=golang-codereviews
https://codereview.appspot.com/151000043
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
Fix by atom (from CL 89190044), comment and test by me.
Fixes issue 6823.
LGTM=crawshaw
R=golang-codereviews, crawshaw
CC=0xe2.0x9a.0x9b, adg, golang-codereviews, iant, r
https://codereview.appspot.com/148180043
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
Corrections due to new strict type rules for data+bss.
Also disable misc/cgo/cdefstest since you can't compile C code anymore.
TBR=iant
CC=golang-codereviews
https://codereview.appspot.com/148050044
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
In linker, refuse to write conservative (array of pointers) as the
garbage collection type for any variable in the data/bss GC program.
In the linker, attach the Go type to an already-read C declaration
during dedup. This gives us Go types for C globals for free as long
as the cmd/dist-generated Go code contains the declaration.
(Most runtime C declarations have a corresponding Go declaration.
Both are bss declarations and so the linker dedups them.)
In cmd/dist, add a few more C files to the auto-Go-declaration list
in order to get Go type information for the C declarations into the linker.
In C compiler, mark all non-pointer-containing global declarations
and all string data as NOPTR. This allows them to exist in C files
without any corresponding Go declaration. Count C function pointers
as "non-pointer-containing", since we have no heap-allocated C functions.
In runtime, add NOPTR to the remaining pointer-containing declarations,
none of which refer to Go heap objects.
In runtime, also move os.Args and syscall.envs data into runtime-owned
variables. Otherwise, in programs that do not import os or syscall, the
runtime variables named os.Args and syscall.envs will be missing type
information.
I believe that this CL eliminates the final source of conservative GC scanning
in non-SWIG Go programs, and therefore...
Fixes issue 909.
LGTM=iant
R=iant
CC=golang-codereviews
https://codereview.appspot.com/149770043
|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
This fixes a couple of problems that occur when the linker
removes its temporary directory on Windows. The linker only
creates and removes a temporary directory when doing external
linking. Windows does not yet support external linking.
Therefore, these problems are only seen when using a
cross-compiler hosted on Windows.
In lib9, FindFirstFileW returns just the file name, not the
full path name. Don't assume that we will find a slash.
Changed the code to work either way just in case.
In ld, Windows requires that files be closed before they are
removed, so close the output file before we might try to
remove it.
Fixes issue 8723.
LGTM=alex.brainman
R=golang-codereviews, alex.brainman
CC=golang-codereviews
https://codereview.appspot.com/141690043
|
| |_|/
|/| |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
Fixes issue 7626.
LGTM=iant
R=rsc, iant
CC=golang-codereviews
https://codereview.appspot.com/144870045
|
| |/
|/|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
This CL adjusts code referring to src/pkg to refer to src.
Immediately after submitting this CL, I will submit
a change doing 'hg mv src/pkg/* src'.
That change will be too large to review with Rietveld
but will contain only the 'hg mv'.
This CL will break the build.
The followup 'hg mv' will fix it.
For more about the move, see golang.org/s/go14nopkg.
LGTM=r
R=r
CC=golang-codereviews
https://codereview.appspot.com/134570043
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
For example:
go build -ldflags -C cmd/go 2>&1 | awk '{print $NF}' | sort | uniq -c | sort -nr
LGTM=khr
R=khr, josharian
CC=golang-codereviews
https://codereview.appspot.com/135170044
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
into runtime package
Fixes issue 8092.
LGTM=rsc
R=iant, rsc
CC=golang-codereviews
https://codereview.appspot.com/126790043
Committer: Russ Cox <rsc@golang.org>
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
Update issue 8527
Fixes, src/cmd/6l/../ld/pcln.c:93:18: runtime error: left shift of negative value -2
LGTM=r
R=golang-codereviews, r
CC=golang-codereviews
https://codereview.appspot.com/127440043
|
| |
| |
| |
| |
| |
| |
| | |
LGTM=rminnich, iant
R=golang-codereviews, rminnich, iant
CC=golang-codereviews, r
https://codereview.appspot.com/125140043
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
Fixes issue 8480.
This CL reapplies CL 114420043. This attempt doesn't blow up when encountering hidden symbols.
LGTM=minux
R=minux
CC=golang-codereviews
https://codereview.appspot.com/128310043
|
| |
| |
| |
| |
| |
| |
| |
| |
| | |
LGTM=rsc
R=gobot, dave
CC=golang-codereviews, iant, rsc
https://codereview.appspot.com/114420043
Committer: Dave Cheney <dave@cheney.net>
|
|/
|
|
|
|
|
|
|
|
| |
codeblk and datblk were truncating their
arguments to int32. Don't do that.
LGTM=dvyukov, rminnich
R=iant, dvyukov, rminnich
CC=golang-codereviews
https://codereview.appspot.com/126050043
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Broke freebsd/amd64 due to exposure of a latent bug.
??? original CL description
cmd/ld: fix operator precedence
LGTM=rsc
R=rsc, iant
CC=golang-codereviews
https://codereview.appspot.com/114420043
???
TBR=dfc
R=dave
CC=golang-codereviews
https://codereview.appspot.com/120630043
|
|
|
|
|
|
|
| |
LGTM=rsc
R=rsc, iant
CC=golang-codereviews
https://codereview.appspot.com/120220043
|
|
|
|
|
|
|
| |
LGTM=rsc
R=rsc, iant
CC=golang-codereviews
https://codereview.appspot.com/114420043
|
|
|
|
|
|
|
|
|
|
|
| |
We have an autogenerated version in zruntime_defs.
I am not sure what are the consequences as gdb never printed any values for me.
But it looks unnecessary to manually duplicate it.
LGTM=rsc
R=golang-codereviews, rsc
CC=golang-codereviews, iant, khr
https://codereview.appspot.com/115660043
|
|
|
|
|
|
|
|
|
|
| |
Want to see why builders are failing.
Then decide whether to rollback or fix.
TBR=khr
R=khr
CC=golang-codereviews
https://codereview.appspot.com/114510043
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Implement the design described in:
https://docs.google.com/document/d/1v4Oqa0WwHunqlb8C3ObL_uNQw3DfSY-ztoA-4wWbKcg/pub
Summary of the changes:
GC uses "2-bits per word" pointer type info embed directly into bitmap.
Scanning of stacks/data/heap is unified.
The old spans types go away.
Compiler generates "sparse" 4-bits type info for GC (directly for GC bitmap).
Linker generates "dense" 2-bits type info for data/bss (the same as stacks use).
Summary of results:
-1680 lines of code total (-1000+ in mgc0.c only)
-25% memory consumption
-3-7% binary size
-15% GC pause reduction
-7% run time reduction
LGTM=khr
R=golang-codereviews, rsc, christoph, khr
CC=golang-codereviews, rlh
https://codereview.appspot.com/106260045
|
|
|
|
|
|
|
|
|
| |
It is already called by linknew().
LGTM=dave
R=rsc, dave
CC=golang-codereviews
https://codereview.appspot.com/120760043
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Currently they are scanned conservatively.
But there is no reason to scan them. C world must not contain
pointers into Go heap. Moreover, we don't have enough information
to emit write barriers nor update pointers there in future.
The immediate need is that it breaks the new GC because
these are weird symbols as if with pointers but not necessary
pointer aligned.
LGTM=rsc
R=golang-codereviews, rlh, rsc
CC=golang-codereviews, iant, khr
https://codereview.appspot.com/117000043
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
It's a bit slower, but not painfully so. There is still room for
improvement (saving space so we can use nosplit, and removing the
requirement for hash/eq stubs).
benchmark old ns/op new ns/op delta
BenchmarkMegMap 23.5 24.2 +2.98%
BenchmarkMegOneMap 14.9 15.7 +5.37%
BenchmarkMegEqMap 71668 72234 +0.79%
BenchmarkMegEmptyMap 4.05 4.93 +21.73%
BenchmarkSmallStrMap 21.9 22.5 +2.74%
BenchmarkMapStringKeysEight_16 23.1 26.3 +13.85%
BenchmarkMapStringKeysEight_32 21.9 25.0 +14.16%
BenchmarkMapStringKeysEight_64 21.9 25.1 +14.61%
BenchmarkMapStringKeysEight_1M 21.9 25.0 +14.16%
BenchmarkIntMap 21.8 12.5 -42.66%
BenchmarkRepeatedLookupStrMapKey32 39.3 30.2 -23.16%
BenchmarkRepeatedLookupStrMapKey1M 322353 322675 +0.10%
BenchmarkNewEmptyMap 129 136 +5.43%
BenchmarkMapIter 137 107 -21.90%
BenchmarkMapIterEmpty 7.14 8.71 +21.99%
BenchmarkSameLengthMap 5.24 6.82 +30.15%
BenchmarkBigKeyMap 34.5 35.3 +2.32%
BenchmarkBigValMap 36.1 36.1 +0.00%
BenchmarkSmallKeyMap 26.9 26.7 -0.74%
LGTM=rsc
R=golang-codereviews, dave, dvyukov, rsc, gobot, khr
CC=golang-codereviews
https://codereview.appspot.com/99380043
|
|
|
|
|
|
|
|
|
|
|
| |
DWARF says only one is necessary.
The count is preferable because it admits 0-length arrays.
Update debug/dwarf to handle either form.
LGTM=rsc
R=rsc
CC=golang-codereviews
https://codereview.appspot.com/111230044
|
|
|
|
|
|
|
|
|
| |
They can be large, so use a varint encoding rather than only one byte.
LGTM=iant, rsc
R=rsc, iant
CC=golang-codereviews
https://codereview.appspot.com/113180043
|
|
|
|
|
|
|
|
|
| |
LGTM=minux, rsc
R=golang-codereviews, minux, rsc
CC=golang-codereviews
https://codereview.appspot.com/113970044
Committer: Shenghou Ma <minux@golang.org>
|
|
|
|
|
|
|
| |
LGTM=rsc
R=rsc
CC=golang-codereviews
https://codereview.appspot.com/115820043
|
|
|
|
|
|
|
| |
LGTM=r
R=r
CC=golang-codereviews
https://codereview.appspot.com/116720043
|
|
|
|
|
|
|
|
|
|
|
|
| |
The debug/dwarf package cannot parse the format generated here,
but the format can be changed so it does.
After this edit, tweaking the expression defining the offset
of a struct field, the dwarf package can parse the tables (again?).
LGTM=rsc
R=rsc
CC=golang-codereviews
https://codereview.appspot.com/105710043
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The code generating the .debug_frame section emits pairs of "advance PC",
"set SP offset" pseudo-instructions. Before the fix, the PC advance comes
out before the SP setting, which means the emitted offset for a block is
actually the value at the end of the block, which is incorrect for the
block itself.
The easiest way to fix this problem is to emit the SP offset before the
PC advance.
One delicate point: the last instruction to come out is now an
"advance PC", which means that if there are padding intsructions after
the final RET, they will appear to have a non-zero offset. This is odd
but harmless because there is no legal way to have a PC in that range,
or to put it another way, if you get here the SP is certainly screwed up
so getting the wrong (virtual) frame pointer is the least of your worries.
LGTM=iant
R=rsc, iant, lvd
CC=golang-codereviews
https://codereview.appspot.com/112750043
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Based on cl/69170045 by Elias Naur.
There are currently several schemes for acquiring a TLS
slot to save the g register. None of them appear to work
for android. The closest are linux and darwin.
Linux uses a linker TLS relocation. This is not supported
by the android linker.
Darwin uses a fixed offset, and calls pthread_key_create
until it gets the slot it wants. As the runtime loads
late in the android process lifecycle, after an
arbitrary number of other libraries, we cannot rely on
any particular slot being available.
So we call pthread_key_create, take the first slot we are
given, and put it in runtime.tlsg, which we turn into a
regular variable in cmd/ld.
Makes android/arm cgo binaries work.
LGTM=minux
R=elias.naur, minux, dave, josharian
CC=golang-codereviews
https://codereview.appspot.com/106380043
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The main changes fall into a few patterns:
1. Replace #define with enum.
2. Add /*c2go */ comment giving effect of #define.
This is necessary for function-like #defines and
non-enum-able #defined constants.
(Not all compilers handle negative or large enums.)
3. Add extra braces in struct initializer.
(c2go does not implement the full rules.)
This is enough to let c2go typecheck the source tree.
There may be more changes once it is doing
other semantic analyses.
LGTM=minux, iant
R=minux, dave, iant
CC=golang-codereviews
https://codereview.appspot.com/106860045
|