]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.garbage] all: merge default (dd5014ed9b01) into dev.garbage
authorRuss Cox <rsc@golang.org>
Wed, 29 Oct 2014 15:54:48 +0000 (11:54 -0400)
committerRuss Cox <rsc@golang.org>
Wed, 29 Oct 2014 15:54:48 +0000 (11:54 -0400)
LGTM=rlh
R=rlh
CC=golang-codereviews
https://golang.org/cl/170730043

124 files changed:
CONTRIBUTORS
doc/asm.html
doc/gccgo_install.html
doc/go1.4.html [new file with mode: 0644]
doc/go1.4.txt [deleted file]
doc/go1compat.html
doc/go_faq.html
doc/go_mem.html
doc/go_spec.html
misc/makerelease/makerelease.go
misc/makerelease/windows/installer.wxs
src/cmd/6g/ggen.c
src/cmd/8g/ggen.c
src/cmd/gc/builtin.c
src/cmd/gc/gen.c
src/cmd/gc/go.h
src/cmd/gc/mparith2.c
src/cmd/gc/runtime.go
src/cmd/gc/sinit.c
src/cmd/gc/typecheck.c
src/cmd/gc/walk.c
src/cmd/go/build.go
src/cmd/go/generate.go
src/cmd/go/get.go
src/cmd/go/test.bash
src/cmd/go/vcs.go
src/cmd/ld/data.c
src/cmd/ld/ldelf.c
src/cmd/objdump/main.go
src/cmd/objdump/objdump_test.go
src/compress/flate/inflate.go
src/compress/flate/inflate_test.go [new file with mode: 0644]
src/compress/gzip/gunzip.go
src/compress/gzip/gunzip_test.go
src/compress/zlib/reader.go
src/crypto/tls/alert.go
src/crypto/tls/cipher_suites.go
src/crypto/tls/handshake_server.go
src/crypto/tls/handshake_server_test.go
src/crypto/tls/testdata/Server-TLSv11-FallbackSCSV [new file with mode: 0644]
src/debug/pe/file.go
src/encoding/csv/writer.go
src/encoding/csv/writer_test.go
src/encoding/gob/codec_test.go
src/encoding/gob/dec_helpers.go [new file with mode: 0644]
src/encoding/gob/decgen.go [new file with mode: 0644]
src/encoding/gob/decode.go
src/encoding/gob/decoder.go
src/encoding/gob/enc_helpers.go [new file with mode: 0644]
src/encoding/gob/encgen.go [new file with mode: 0644]
src/encoding/gob/encode.go
src/encoding/gob/encoder.go
src/encoding/gob/timing_test.go
src/encoding/json/encode.go
src/encoding/json/encode_test.go
src/flag/flag.go
src/fmt/doc.go
src/html/template/js_test.go
src/net/http/pprof/pprof.go
src/net/lookup.go
src/net/singleflight.go
src/net/z_last_test.go
src/os/dir_unix.go
src/os/exec/exec_test.go
src/os/file.go
src/os/file_plan9.go
src/os/file_posix.go
src/os/file_unix.go
src/os/file_windows.go
src/reflect/all_test.go
src/reflect/makefunc.go
src/reflect/type.go
src/reflect/value.go
src/regexp/all_test.go
src/regexp/regexp.go
src/regexp/syntax/parse.go
src/runtime/asm_386.s
src/runtime/asm_amd64.s
src/runtime/asm_amd64p32.s
src/runtime/asm_arm.s
src/runtime/cgo/gcc_arm.S
src/runtime/chan_test.go
src/runtime/crash_cgo_test.go
src/runtime/crash_test.go
src/runtime/debug/garbage.go
src/runtime/debug/garbage_test.go
src/runtime/env_plan9.go
src/runtime/extern.go
src/runtime/funcdata.h
src/runtime/malloc.h
src/runtime/mem.go
src/runtime/mgc0.c
src/runtime/mprof.go
src/runtime/pprof/mprof_test.go [new file with mode: 0644]
src/runtime/pprof/pprof_test.go
src/runtime/print1.go
src/runtime/proc.c
src/runtime/rt0_nacl_amd64p32.s
src/runtime/runtime.c
src/runtime/runtime.h
src/runtime/select.go
src/runtime/stack.c
src/runtime/stubs.go
src/runtime/symtab.go
src/runtime/sys_nacl_amd64p32.s
src/runtime/time.go
src/sync/pool.go
src/sync/pool_test.go
src/syscall/env_plan9.go
src/syscall/fs_nacl.go
src/syscall/route_bsd.go
src/testing/testing.go
src/text/template/exec.go
src/text/template/exec_test.go
src/time/sleep.go
src/time/sleep_test.go
src/unicode/utf8/utf8.go
src/unsafe/unsafe.go
test/fixedbugs/bug371.go
test/fixedbugs/issue8947.go [new file with mode: 0644]
test/fixedbugs/issue8961.go [new file with mode: 0644]
test/fixedbugs/issue9006.go [new file with mode: 0644]
test/maplinear.go
test/recover.go

index a24178b528dab54f86b8bf7cbca6bd96cf68c8ed..7679f787422cec76ef41a7191033b3564718bed9 100644 (file)
@@ -96,7 +96,7 @@ Arvindh Rajesh Tamilmani <art@a-30.net>
 Asim Shankar <asimshankar@gmail.com>
 Ato Araki <ato.araki@gmail.com>
 Aulus Egnatius Varialus <varialus@gmail.com>
-Austin Clements <aclements@csail.mit.edu>
+Austin Clements <austin@google.com> <aclements@csail.mit.edu>
 Balazs Lecz <leczb@google.com>
 Ben Eitzen <eitzenb@golang.org>
 Ben Fried <ben.fried@gmail.com>
@@ -160,6 +160,7 @@ Corey Thomasson <cthom.lists@gmail.com>
 Cosmos Nicolaou <cnicolaou@google.com>
 Cristian Staretu <unclejacksons@gmail.com>
 Damian Gryski <dgryski@gmail.com>
+Damien Neil <dneil@google.com>
 Dan Callahan <dan.callahan@gmail.com>
 Dan Peterson <dpiddy@gmail.com>
 Dan Sinclair <dan.sinclair@gmail.com>
@@ -280,6 +281,7 @@ James Fysh <james.fysh@gmail.com>
 James Gray <james@james4k.com>
 James Meneghello <rawrz0r@gmail.com>
 James P. Cooper <jamespcooper@gmail.com>
+James Robinson <jamesr@google.com> <jamesr.gatech@gmail.com>
 James Toy <nil@opensesame.st>
 James Tucker <raggi@google.com>
 James Whitehead <jnwhiteh@gmail.com>
index 943347216ec7e6c0f3d97c8b02fe75aadd6f9823..771c493cc2f593d0b0dd9b4625b7da1718d41ba4 100644 (file)
@@ -117,6 +117,9 @@ All user-defined symbols other than jump labels are written as offsets to these
 <p>
 The <code>SB</code> pseudo-register can be thought of as the origin of memory, so the symbol <code>foo(SB)</code>
 is the name <code>foo</code> as an address in memory.
+This form is used to name global functions and data.
+Adding <code>&lt;&gt;</code> to the name, as in <code>foo&lt;&gt;(SB)</code>, makes the name
+visible only in the current source file, like a top-level <code>static</code> declaration in a C file.
 </p>
 
 <p>
@@ -128,8 +131,11 @@ Thus <code>0(FP)</code> is the first argument to the function,
 When referring to a function argument this way, it is conventional to place the name
 at the beginning, as in <code>first_arg+0(FP)</code> and <code>second_arg+8(FP)</code>.
 Some of the assemblers enforce this convention, rejecting plain <code>0(FP)</code> and <code>8(FP)</code>.
-For assembly functions with Go prototypes, <code>go vet</code> will check that the argument names
+For assembly functions with Go prototypes, <code>go</code> <code>vet</code> will check that the argument names
 and offsets match.
+On 32-bit systems, the low and high 32 bits of a 64-bit value are distinguished by adding
+a <code>_lo</code> or <code>_hi</code> suffix to the name, as in <code>arg_lo+0(FP)</code> or <code>arg_hi+4(FP)</code>.
+If a Go prototype does not name its result, the expected assembly name is <code>ret</code>.
 </p>
 
 <p>
@@ -206,6 +212,8 @@ The frame size <code>$24-8</code> states that the function has a 24-byte frame
 and is called with 8 bytes of argument, which live on the caller's frame.
 If <code>NOSPLIT</code> is not specified for the <code>TEXT</code>,
 the argument size must be provided.
+For assembly functions with Go prototypes, <code>go</code> <code>vet</code> will check that the
+argument size is correct.
 </p>
 
 <p>
@@ -216,19 +224,20 @@ simple name <code>profileloop</code>.
 </p>
 
 <p>
-For <code>DATA</code> directives, the symbol is followed by a slash and the number
-of bytes the memory associated with the symbol occupies.
-The arguments are optional flags and the data itself.
-For instance,
-</p>
+Global data symbols are defined by a sequence of initializing
+<code>DATA</code> directives followed by a <code>GLOBL</code> directive.
+Each <code>DATA</code> directive initializes a section of the
+corresponding memory.
+The memory not explicitly initialized is zeroed.
+The general form of the <code>DATA</code> directive is
 
 <pre>
-DATA  runtime·isplan9(SB)/4, $1
+DATA   symbol+offset(SB)/width, value
 </pre>
 
 <p>
-declares the local symbol <code>runtime·isplan9</code> of size 4 and value 1.
-Again the symbol has the middle dot and is offset from <code>SB</code>.
+which initializes the symbol memory at the given offset and width with the given value.
+The <code>DATA</code> directives for a given symbol must be written with increasing offsets.
 </p>
 
 <p>
@@ -237,15 +246,26 @@ The arguments are optional flags and the size of the data being declared as a gl
 which will have initial value all zeros unless a <code>DATA</code> directive
 has initialized it.
 The <code>GLOBL</code> directive must follow any corresponding <code>DATA</code> directives.
-This example
+</p>
+
+<p>
+For example,
 </p>
 
 <pre>
-GLOBL runtime·tlsoffset(SB),$4
+DATA divtab&lt;&gt;+0x00(SB)/4, $0xf4f8fcff
+DATA divtab&lt;&gt;+0x04(SB)/4, $0xe6eaedf0
+...
+DATA divtab&lt;&gt;+0x3c(SB)/4, $0x81828384
+GLOBL divtab&lt;&gt;(SB), RODATA, $64
+
+GLOBL runtime·tlsoffset(SB), NOPTR, $4
 </pre>
 
 <p>
-declares <code>runtime·tlsoffset</code> to have size 4.
+declares and initializes <code>divtab&lt;&gt;</code>, a read-only 64-byte table of 4-byte integer values,
+and declares <code>runtime·tlsoffset</code>, a 4-byte, implicitly zeroed variable that
+contains no pointers.
 </p>
 
 <p>
@@ -299,6 +319,80 @@ This is a wrapper function and should not count as disabling <code>recover</code
 </li>
 </ul>
 
+<h3 id="runtime">Runtime Coordination</h3>
+
+<p>
+For garbage collection to run correctly, the runtime must know the
+location of pointers in all global data and in most stack frames.
+The Go compiler emits this information when compiling Go source files,
+but assembly programs must define it explicitly.
+</p>
+
+<p>
+A data symbol marked with the <code>NOPTR</code> flag (see above)
+is treated as containing no pointers to runtime-allocated data.
+A data symbol with the <code>RODATA</code> flag
+is allocated in read-only memory and is therefore treated
+as implicitly marked <code>NOPTR</code>.
+A data symbol with a total size smaller than a pointer
+is also treated as implicitly marked <code>NOPTR</code>.
+It is not possible to define a symbol containing pointers in an assembly source file;
+such a symbol must be defined in a Go source file instead.
+Assembly source can still refer to the symbol by name
+even without <code>DATA</code> and <code>GLOBL</code> directives.
+A good general rule of thumb is to define all non-<code>RODATA</code>
+symbols in Go instead of in assembly.
+</p>
+
+<p>
+Each function also needs annotations giving the location of
+live pointers in its arguments, results, and local stack frame.
+For an assembly function with no pointer results and
+either no local stack frame or no function calls,
+the only requirement is to define a Go prototype for the function
+in a Go source file in the same package.
+For more complex situations, explicit annotation is needed.
+These annotations use pseudo-instructions defined in the standard
+<code>#include</code> file <code>funcdata.h</code>.
+</p>
+
+<p>
+If a function has no arguments and no results,
+the pointer information can be omitted.
+This is indicated by an argument size annotation of <code>$<i>n</i>-0</code>
+on the <code>TEXT</code> instruction.
+Otherwise, pointer information must be provided by
+a Go prototype for the function in a Go source file,
+even for assembly functions not called directly from Go.
+(The prototype will also let <code>go</code> <code>vet</code> check the argument references.)
+At the start of the function, the arguments are assumed
+to be initialized but the results are assumed uninitialized.
+If the results will hold live pointers during a call instruction,
+the function should start by zeroing the results and then 
+executing the pseudo-instruction <code>GO_RESULTS_INITIALIZED</code>.
+This instruction records that the results are now initialized
+and should be scanned during stack movement and garbage collection.
+It is typically easier to arrange that assembly functions do not
+return pointers or do not contain call instructions;
+no assembly functions in the standard library use
+<code>GO_RESULTS_INITIALIZED</code>.
+</p>
+
+<p>
+If a function has no local stack frame,
+the pointer information can be omitted.
+This is indicated by a local frame size annotation of <code>$0-<i>n</i></code>
+on the <code>TEXT</code> instruction.
+The pointer information can also be omitted if the
+function contains no call instructions.
+Otherwise, the local stack frame must not contain pointers,
+and the assembly must confirm this fact by executing the 
+pseudo-instruction <code>NO_LOCAL_POINTERS</code>.
+Because stack resizing is implemented by moving the stack,
+the stack pointer may change during any function call:
+even pointers to stack data must not be kept in local variables.
+</p>
+
 <h2 id="architectures">Architecture-specific details</h2>
 
 <p>
@@ -434,13 +528,10 @@ Here's how the 386 runtime defines the 64-bit atomic load function.
 // so actually
 // void atomicload64(uint64 *res, uint64 volatile *addr);
 TEXT runtime·atomicload64(SB), NOSPLIT, $0-8
-       MOVL    4(SP), BX
-       MOVL    8(SP), AX
-       // MOVQ (%EAX), %MM0
-       BYTE $0x0f; BYTE $0x6f; BYTE $0x00
-       // MOVQ %MM0, 0(%EBX)
-       BYTE $0x0f; BYTE $0x7f; BYTE $0x03
-       // EMMS
-       BYTE $0x0F; BYTE $0x77
+       MOVL    ptr+0(FP), AX
+       LEAL    ret_lo+4(FP), BX
+       BYTE $0x0f; BYTE $0x6f; BYTE $0x00      // MOVQ (%EAX), %MM0
+       BYTE $0x0f; BYTE $0x7f; BYTE $0x03      // MOVQ %MM0, 0(%EBX)
+       BYTE $0x0F; BYTE $0x77                  // EMMS
        RET
 </pre>
index 4c1a8c2f57f938dfbebe8a646bd02090c01746dc..acb315a0ac66398ebcc81616a20aa78fb40dced3 100644 (file)
@@ -42,6 +42,10 @@ identical to Go 1.1.  The GCC 4.8.2 release includes a complete Go
 1.1.2 implementation.
 </p>
 
+<p>
+The GCC 4.9 releases include a complete Go 1.2 implementation.
+</p>
+
 <h2 id="Source_code">Source code</h2>
 
 <p>
diff --git a/doc/go1.4.html b/doc/go1.4.html
new file mode 100644 (file)
index 0000000..7e670c4
--- /dev/null
@@ -0,0 +1,598 @@
+<!--{
+       "Title": "Go 1.4 Release Notes",
+       "Path":  "/doc/go1.4",
+       "Template": true
+}-->
+
+<h2 id="introduction">Introduction to Go 1.4</h2>
+
+<p>
+The latest Go release, version 1.4, arrives as scheduled six months after 1.3
+and contains only one tiny language change,
+a possibly breaking change to the compiler,
+a backwards-compatible simple form of <code>for</code>-<code>range</code> loop.
+The release focuses primarily on implementation work, improving the garbage collector
+and preparing the ground for a fully concurrent collector to be rolled out in the
+next few releases.
+Stacks are now contiguous, reallocated when necessary rather than linking on new
+"segments";
+this release therefore eliminates the notorious "hot stack split" problem.
+There are some new tools available including support in the <code>go</code> command
+for build-time source code generation
+and TODO.
+The release also adds support for ARM processors on Android and Native Client (NaCl)
+and AMD64 on Plan 9.
+As always, Go 1.4 keeps the <a href="/doc/go1compat.html">promise
+of compatibility</a>,
+and almost everything 
+will continue to compile and run without change when moved to 1.4.
+</p>
+
+<h2 id="language">Changes to the language</h2>
+
+<h3 id="forrange">For-range loops</h3>
+<p>
+Up until Go 1.3, <code>for</code>-<code>range</code> loop had two forms
+</p>
+
+<pre>
+for k, v := range x {
+       ...
+}
+</pre>
+
+<p>
+and
+</p>
+
+<pre>
+for k := range x {
+       ...
+}
+</pre>
+
+<p>
+If one was not interested in the loop values, only the iteration itself, it was still
+necessary to mention a variable (probably the <a href="/ref/spec#Blank_identifier">blank identifier</a>, as in
+<code>for</code> <code>_</code> <code>=</code> <code>range</code> <code>x</code>), because
+the form
+</p>
+
+<pre>
+for range x {
+       ...
+}
+</pre>
+
+<p>
+was not syntactically permitted.
+</p>
+
+<p>
+This situation seemed awkward, so as of Go 1.4 the variable-free form is now legal.
+The pattern arises rarely but the code can be cleaner when it does.
+</p>
+
+<p>
+<em>Updating</em>: The change is strictly backwards compatible to existing Go
+programs, but tools that analyze Go parse trees may need to be modified to accept
+this new form as the
+<code>Key</code> field of <a href="/pkg/go/ast/#RangeStmt"><code>RangeStmt</code></a>
+may now be <code>nil</code>.
+</p>
+
+<h3 id="methodonpointertopointer">Method calls on **T</h3>
+
+<p>
+Given these declarations,
+</p>
+
+<pre>
+type T int
+func (T) M() {}
+var x **T
+</pre>
+
+<p>
+both <code>gc</code> and <code>gccgo</code> accepted the method call
+</p>
+
+<pre>
+x.M()
+</pre>
+
+<p>
+which is a double dereference of the pointer-to-pointer <code>x</code>.
+The Go specification allows a single dereference to be inserted automatically,
+but not two, so this call is erroneous according to the language definition.
+It has therefore been disallowed in Go 1.4, which is a breaking change,
+although very few programs will be affected.
+</p>
+
+<p>
+<em>Updating</em>: Code that depends on the old, erroneous behavior will no longer
+compile but is easy to fix by adding an explicit dereference.
+</p>
+
+<h2 id="os">Changes to the supported operating systems and architectures</h2>
+
+<h3 id="android">Android</h3>
+
+<p>
+Go 1.4 can build binaries for ARM processors running the Android operating system.
+It can also build a <code>.so</code> library that can be loaded by an Android application
+using the supporting packages in the <a href="http://code.google.com/p/go.mobile">go.mobile</a> repository.
+A brief description of the plans for this experimental port are available
+<a href="/s/go14android">here</a>.
+</p>
+
+<h3 id="naclarm">NaCl on ARM</h3>
+
+<p>
+The previous release introduced Native Client (NaCl) support for the 32-bit x86
+(<code>GOARCH=386</code>)
+and 64-bit x86 using 32-bit pointers (GOARCH=amd64p32).
+The 1.4 release adds NaCl support for ARM (GOARCH=arm).
+</p>
+
+<h3 id="plan9amd64">Plan9 on AMD64</h3>
+
+<p>
+This release adds support for the Plan 9 operating system on AMD64 processors,
+provided the kernel supports the <code>nsec</code> system call and uses 4K pages.
+</p>
+
+<h2 id="compatibility">Changes to the compatibility guidelines</h2>
+
+<p>
+The <a href="/pkg/unsafe/"><code>unsafe</code></a> package allows one
+to defeat Go's type system by exploiting internal details of the implementation
+or machine representation of data.
+It was never explicitly specified what use of <code>unsafe</code> meant
+with respect to compatibility as specified in the
+<a href="go1compat.html">Go compatibility guidelines</a>.
+The answer, of course, is that we can make no promise of compatibility
+for code that does unsafe things.
+</p>
+
+<p>
+We have clarified this situation in the documentation included in the release.
+The <a href="go1compat.html">Go compatibility guidelines</a> and the
+docs for the <a href="/pkg/unsafe/"><code>unsafe</code></a> package
+are now explicit that unsafe code is not guaranteed to remain compatible.
+</p>
+  
+<p>
+<em>Updating</em>: Nothing technical has changed; this is just a clarification
+of the documentation.
+</p>
+
+
+<h2 id="impl">Changes to the implementations and tools</h2>
+
+<h3 id="runtime">Changes to the runtime</h3>
+
+<p>
+Up to Go 1.4, the runtime (garbage collector, concurrency support, interface management,
+maps, slices, strings, ...) was mostly written in C, with some assembler support.
+In 1.4, much of the code has been translated to Go so that the garbage collector can scan
+the stacks of programs in the runtime and get accurate information about what variables
+are active.
+This change was large but should have no semantic effect on programs.
+</p>
+
+<p>
+This rewrite allows the garbage collector in 1.4 to be fully precise,
+meaning that it is aware of the location of all active pointers in the program.
+This means the heap will be smaller as there will be no false positives keeping non-pointers alive.
+Other related changes also reduce the heap size, which is smaller by 10%-30% overall
+relative to the previous release.
+</p>
+
+<p>
+A consequence is that stacks are no longer segmented, eliminating the "hot split" problem.
+When a stack limit is reached, a new, larger stack is allocated, all active frames for
+the goroutine are copied there, and any pointers into the stack are updated.
+Performance can be noticeably better in some cases and is always more predictable.
+Details are available in <a href="/s/contigstacks">the design document</a>.
+</p>
+
+<p>
+The use of contiguous stacks means that stacks can start smaller without triggering performance issues,
+so the default starting size for a goroutine's stack in 1.4 has been reduced to 2048 bytes from 8192 bytes.
+TODO: It may be bumped to 4096 for the release.
+</p>
+
+<p>
+As preparation for the concurrent garbage collector scheduled for the 1.5 release,
+writes to pointer values in the heap are now done by a function call,
+called a write barrier, rather than directly from the function updating the value.
+In this next release, this will permit the garbage collector to mediate writes to the heap while it is running.
+This change has no semantic effect on programs in 1.4, but was
+included in the release to test the compiler and the resulting performance.
+</p>
+
+<p>
+The implementation of interface values has been modified.
+In earlier releases, the interface contained a word that was either a pointer or a one-word
+scalar value, depending on the type of the concrete object stored.
+This implementation was problematical for the garbage collector,
+so as of 1.4 interface values always hold a pointer.
+In running programs, most interface values were pointers anyway,
+so the effect is minimal, but programs that store integers (for example) in
+interfaces will see more allocations.
+</p>
+
+<p>
+As of Go 1.3, the runtime crashes if it finds a memory word that should contain
+a valid pointer but instead contains an obviously invalid pointer (for example, the value 3).
+Programs that store integers in pointer values may run afoul of this check and crash.
+In Go 1.4, setting the <a href="/pkg/runtime/"><code>GODEBUG</code></a> variable
+<code>invalidptr=0</code> disables
+the crash as a workaround, but we cannot guarantee that future releases will be
+able to avoid the crash; the correct fix is to rewrite code not to alias integers and pointers.
+</p>
+
+<h3 id="asm">Assembly</h3>
+
+<p>
+The language accepted by the assemblers <code>cmd/5a</code>, <code>cmd/6a</code>
+and <code>cmd/8a</code> has had several changes,
+mostly to make it easier to deliver type information to the runtime.
+</p>
+
+<p>
+First, the <code>textflag.h</code> file that defines flags for <code>TEXT</code> directives
+has been copied from the linker source directory to a standard location so it can be
+included with the simple directive
+</p>
+
+<pre>
+#include "textflag.h"
+</pre>
+
+<p>
+The more important changes are in how assembler source can define the necessary
+type information.
+For most programs it will suffice to move data
+definitions (<code>DATA</code> and <code>GLOBL</code> directives)
+out of assembly into Go files
+and to write a Go declaration for each assembly function.
+The <a href="/doc/asm#runtime">assembly document</a> describes what to do.
+</p>
+
+<p>
+<em>Updating</em>:
+Assembly files that include <code>textflag.h</code> from its old
+location will still work, but should be updated.
+For the type information, most assembly routines will need no change,
+but all should be examined.
+Assembly source files that define data,
+functions with non-empty stack frames, or functions that return pointers
+need particular attention.
+A description of the necessary (but simple) changes
+is in the <a href="/doc/asm#runtime">assembly document</a>.
+</p>
+
+<p>
+More information about these changes is in the <a href="/doc/asm">assembly document</a>.
+</p>
+
+<h3 id="gccgo">Status of gccgo</h3>
+
+<p>
+TODO gccgo news
+</p>
+
+<h3 id="internalpackages">Internal packages</h3>
+
+<p>
+Go's package system makes it easy to structure programs into components with clean boundaries,
+but there are only two forms of access: local (unexported) and global (exported).
+Sometimes one wishes to have components that are not exported,
+for instance to avoid acquiring clients of interfaces to code that is part of a public repository
+but not intended for use outside the program to which it belongs.
+</p>
+
+<p>
+The Go language does not have the power to enforce this distinction, but as of Go 1.4 the
+<a href="/cmd/go/"><code>go</code></a> command introduces
+a mechanism to define "internal" packages that may not be imported by packages outside
+the source subtree in which they reside.
+</p>
+
+<p>
+To create such a package, place it in a directory named <code>internal</code> or in a subdirectory of a directory
+named internal.
+When the <code>go</code> command sees an import of a package with <code>internal</code> in its path,
+it verifies that the package doing the import
+is within the tree rooted at the parent of the <code>internal</code> directory.
+For example, a package <code>.../a/b/c/internal/d/e/f</code>
+can be imported only by code in the directory tree rooted at <code>.../a/b/c</code>.
+It cannot be imported by code in <code>.../a/b/g</code> or in any other repository.
+</p>
+
+<p>
+For Go 1.4, the internal package mechanism is enforced for the main Go repository;
+from 1.5 and onward it will be enforced for any repository.
+</p>
+
+<p>
+Full details of the mechanism are in
+<a href="http://golang.org/s/go14internal">the design document</a>.
+</p>
+
+<h3 id="canonicalimports">Canonical import paths</h3>
+
+<p>
+Code often lives in repositories hosted by public services such as <code>github.com</code>,
+meaning that the import paths for packages begin with the name of the hosting service,
+<code>github.com/rsc/pdf</code> for example.
+One can use
+<a href="/cmd/go/#hdr-Remote_import_paths">an existing mechanism</a>
+to provide a "custom" or "vanity" import path such as
+<code>rsc.io/pdf</code>, but
+that creates two valid import paths for the package.
+That is a problem: one may inadvertently import the package through the two
+distinct paths in a single program, which is wasteful;
+miss an update to a package because the path being used is not recognized to be
+out of date;
+or break clients using the old path by moving the package to a different hosting service.
+</p>
+
+<p>
+Go 1.4 introduces an annotation for package clauses in Go source that identify a canonical
+import path for the package.
+If an import is attempted using a path that is not canonical,
+the <a href="/cmd/go/"><code>go</code></a> command
+will refuse to compile the importing package.
+</p>
+
+<p>
+The syntax is simple: put an identifying comment on the package line.
+For our example, the package clause would read:
+</p>
+
+<pre>
+package pdf // import "rsc.io/pdf"
+</pre>
+
+<p>
+With this in place,
+the <code>go</code> command will
+refuse to compile a package that imports <code>github.com/rsc/pdf</code>, 
+ensuring that the code can be moved without breaking users.
+</p>
+
+<p>
+The check is at build time, not download time, so if <code>go</code> <code>get</code>
+fails because of this check, the mis-imported package has been copied to the local machine
+and should be removed manually.
+</p>
+
+<p>
+Further information is in
+<a href="http://golang.org/s/go14customimport">the design document</a>.
+</p>
+
+<h3 id="gogenerate">The go generate subcommand</h3>
+
+<p>
+The <a href="/cmd/go/"><code>go</code></a> command has a new subcommand,
+<a href="/cmd/go/#hdr-Generate_Go_files_by_processing_source"><code>go generate</code></a>,
+to automate the running of tools to generate source code before compilation.
+For example, it can be used to run the <a href="/cmd/yacc"><code>yacc</code></a>
+compiler-compiler on a <code>.y</code> file to produce the Go source file implementing the grammar,
+or to automate the generation of <code>String</code> methods for typed constants using the new
+<a href="http://godoc.org/code.google.com/p/go.tools/cmd/stringer">stringer</a>
+tool in the <code>go.tools</code> repository.
+</p>
+
+<p>
+For more information, see the 
+<a href="http://golang.org/s/go1.4-generate">design document</a>.
+</p>
+
+<h3 id="filenames">Change to file name handling</h3>
+
+<p>
+Build constraints, also known as build tags, control compilation by including or excluding files
+(see the documentation <a href="/pkg/go/build/"><code>/go/build</code></a>).
+Compilation can also be controlled by the name of the file itself by "tagging" the file with
+a suffix (before the <code>.go</code> or <code>.s</code> extension) with an underscore
+and the name of the architecture or operating system.
+For instance, the file <code>gopher_arm.go</code> will only be compiled if the target
+processor is an ARM.
+</p>
+
+<p>
+Before Go 1.4, a file called just <code>arm.go</code> was similarly tagged, but this behavior
+can break sources when new architectures are added, causing files to suddenly become tagged.
+In 1.4, therefore, a file will be tagged in this manner only if the tag (architecture or operating
+system name) is preceded by an underscore.
+</p>
+
+<p>
+<em>Updating</em>: Packages that depend on the old behavior will no longer compile correctly.
+Files with names like <code>windows.go</code> or <code>amd64.go</code> should either
+have explicit build tags added to the source or be renamed to something like
+<code>os_windows.go</code> or <code>support_amd64.go</code>.
+</p>
+
+<h3 id="gocmd">Other changes to the go command</h3>
+
+<p>
+There were a number of minor changes to the
+<a href="/cmd/go/"><code>cmd/go</code></a>
+command worth noting.
+</p>
+
+<ul>
+
+<li>
+Unless <a href="/cmd/cgo/"><code>cgo</code></a> is being used to build the package,
+the <code>go</code> command now refuses to compile C source files,
+since the relevant C compilers
+(<a href="/cmd/6c/"><code>6c</code></a> etc.)
+are intended to be removed from the installation in some future release.
+(They are used today only to build part of the runtime.)
+It is difficult to use them correctly in any case, so any extant uses are likely incorrect,
+so we have disabled them.
+</li>
+
+<li>
+The <a href="/cmd/go/#hdr-Test_packages"><code>go</code> <code>test</code></a>
+subcommand has a new flag, <code>-o</code>, to set the name of the resulting binary,
+corresponding to the same flag in other subcommands.
+The non-functional <code>-file</code> flag has been removed.
+</li>
+
+<li>
+The <a href="/cmd/go/#hdr-Test_packages"><code>go</code> <code>test</code></a>
+subcommand will compile and link all <code>*_test.go</code> files in the package,
+even when there are no <code>Test</code> functions in them. 
+It previously ignored such files.
+</li>
+
+<li>
+The behavior of the
+<a href="/cmd/go/#hdr-Test_packages"><code>go</code> <code>build</code></a>
+subcommand's
+<code>-a</code> flag has been changed for non-development installations.
+For installations running a released distribution, the <code>-a</code> flag will no longer
+rebuild the standard library and commands, to avoid overwriting the installation's files.
+</li>
+
+</ul>
+
+<h3 id="godoc">Changes to godoc</h3>
+<p>
+TODO godoc news
+</p>
+
+<h3 id="pkg">Changes to package source layout</h3>
+
+<p>
+In the main Go source repository, the source code for the packages was kept in
+the directory <code>src/pkg</code>, which made sense but differed from
+other repositories, including the Go sub-repositories such as <code>go.tools</code>.
+In Go 1.4, the<code> pkg</code> level of the source tree is now gone, so for example
+the <a href="/pkg/fmt/"><code>fmt</code></a> package's source, once kept in
+directory <code>src/pkg/fmt</code>, now lives one level higher in <code>src/fmt</code>.
+</p>
+
+<p>
+<em>Updating</em>: Tools like <code>godoc</code> that discover source code
+need to know about the new location. All tools and services maintained by the Go team
+have been updated.
+</p>
+
+<h3 id="misc">Miscellany</h3>
+
+<p>
+The standard repository's top-level <code>misc</code> directory used to contain
+Go support for editors and IDEs: plugins, initialization scripts and so on.
+Maintaining these was becoming time-consuming
+and needed external help because many of the editors listed were not used by
+members of the core team.
+It also required us to make decisions about which plugin was best for a given
+editor, even for editors we do not use.
+</p>
+
+<p>
+The Go community at large is much better suited to managing this information.
+In Go 1.4, therefore, this support has been removed from the repository.
+Instead, there is a curated, informative list of what's available on
+a <a href="https://code.google.com/p/go-wiki/wiki/IDEsAndTextEditorPlugins">wiki page</a>.
+</p>
+
+<h2 id="performance">Performance</h2>
+
+<p>
+Most programs will run about the same speed or slightly faster in 1.4 than in 1.3;
+some will be slightly slower.
+There are many changes, making it hard to be precise about what to expect.
+</p>
+
+<p>
+As mentioned above, much of the runtime was translated to Go from C,
+which led to some reduction in heap sizes.
+It also improved performance slightly because the Go compiler is better
+at optimization, due to things like inlining, than the C compiler used to build
+the runtime.
+</p>
+
+<p>
+The garbage collector was sped up, leading to measurable improvements for
+garbage-heavy programs.
+On the other hand, the new write barriers slow things down again, typically
+by about the same amount but, depending on their behavior, some programs
+may be somewhat slower or faster.
+</p>
+
+<p>
+Library changes that affect performance are documented below.
+</p>
+
+<h2 id="library">Changes to the standard library</h2>
+
+<h3 id="new_packages">New packages</h3>
+
+<p>
+There are no new packages in this release.
+</p>
+
+<h3 id="major_library_changes">Major changes to the library</h3>
+
+<p>
+TODO major changes
+</p>
+
+<pre>
+encoding/gob: remove unsafe (CL 102680045)
+syscall: now frozen (CL 129820043); go.sys subrepo created: http://golang.org/s/go1.4-syscall
+</pre>
+
+<h3 id="minor_library_changes">Minor changes to the library</h3>
+
+<p>
+The following list summarizes a number of minor changes to the library, mostly additions.
+See the relevant package documentation for more information about each change.
+</p>
+
+<ul>
+
+<li> TODO changes
+</li>
+</ul>
+
+<pre>
+
+cmd/6l, liblink: use pc-relative addressing for all memory references, so that linking Go binaries at high addresses works (CL 125140043). This cuts the maximum size of a Go binary's text+data+bss from 4GB to 2GB.
+
+bufio: handling of empty tokens at EOF changed, may require scanner change (CL 145390043)
+compress/flate, compress/gzip, compress/zlib: Reset support (https://codereview.appspot.com/97140043)
+crypto/tls: add support for ALPN (RFC 7301) (CL 108710046)
+crypto/tls: support programmatic selection of server certificates (CL 107400043)
+encoding/asn1: optional elements with a default value will now only be omitted if they have that value (CL 86960045)
+fmt: print type *map[T]T as &amp;map[k:v] (CL 154870043)
+encoding/csv: do not quote empty strings, quote \. (CL 164760043)
+net/http: add Request.BasicAuth method (CL 76540043)
+net/http: add Transport.DialTLS hook (CL 137940043)
+net/http/httputil: add ReverseProxy.ErrorLog (CL 132750043)
+os: implement symlink support for windows (CL 86160044)
+reflect: add type.Comparable (CL 144020043)
+reflect: Value is one word smaller
+runtime: implement monotonic clocks on windows (CL 108700045)
+runtime: MemStats.Mallocs now counts very small allocations missed in Go 1.3. This may break tests using runtime.ReadMemStats or testing.AllocsPerRun by giving a more accurate answer than Go 1.3 did (CL 143150043).
+runtime/race: freebsd is supported (CL 107270043)
+runtime: add PauseEnd array to MemStats and GCStats (CL 153670043)
+swig: Due to runtime changes Go 1.4 will require SWIG 3.0.3 (not yet released)
+sync/atomic: add Value (CL 136710045)
+syscall: Setuid, Setgid are disabled on linux platforms. On linux those syscalls operate on the calling thread, not the whole process. This does not match the semantics of other platforms, nor the expectations of the caller, so the operations have been disabled until issue 1435 is resolved (CL 106170043)
+testing: add Coverage (CL 98150043)
+testing: add TestMain support (CL 148770043)
+text/scanner: add IsIdentRune field of Scanner. (CL 108030044)
+text/template: allow comparison of signed and unsigned integers (CL 149780043)
+time: use the micro symbol (µ (U+00B5)) to print microsecond duration (CL 105030046)
+</pre>
diff --git a/doc/go1.4.txt b/doc/go1.4.txt
deleted file mode 100644 (file)
index 833d331..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-This file collects notes about what has changed since Go 1.3
-and should be mentioned in the Go 1.4 release notes.
-
-Please keep the descriptions to a single line, starting with the
-package or cmd/xxx directory name, and ending in a CL number.
-Please keep the list sorted (as in sort.Strings of the lines).
-
-spec: permit for range x (CL 104680043)
-
-the directory src/pkg has been deleted, for instance src/pkg/fmt is now just src/fmt (CL 134570043)
-
-cmd/6l, liblink: use pc-relative addressing for all memory references, so that linking Go binaries at high addresses works (CL 125140043). This cuts the maximum size of a Go binary's text+data+bss from 4GB to 2GB.
-cmd/go: import comments (CL 124940043)
-cmd/go: implement "internal" (CL 120600043)
-cmd/go: implement "generate" (CL 125580044)
-cmd/go: disallow C sources except when using cgo (CL 149720043)
-cmd/go: add test -o flag (CL 149070043)
-cmd/go: redefine build -a to skip standard library in releases (CL 151730045)
-cmd/go: compile and link all _test.go files during 'go test', even in packages where there are no Test functions (CL 150980043)
-cmd/go: (via go/build): a GOOS prefix acts as a tag only if preceded by an underscore. this is a breaking change. (CL 147690043)
-
-asm: make textflag.h available outside of cmd/ld (CL 128050043)
-bufio: handling of empty tokens at EOF changed, may require scanner change (CL 145390043)
-crypto/tls: add support for ALPN (RFC 7301) (CL 108710046)
-crypto/tls: support programmatic selection of server certificates (CL 107400043)
-fmt: print type *map[T]T as &map[k:v] (CL 154870043)
-encoding/gob: remove unsafe (CL 102680045)
-misc: deleted editor support; refer to https://code.google.com/p/go-wiki/wiki/IDEsAndTextEditorPlugins instead (CL 105470043)
-net/http: add Request.BasicAuth method (CL 76540043)
-net/http: add Transport.DialTLS hook (CL 137940043)
-net/http/httputil: add ReverseProxy.ErrorLog (CL 132750043)
-os: implement symlink support for windows (CL 86160044)
-reflect: add type.Comparable (CL 144020043)
-runtime: implement monotonic clocks on windows (CL 108700045)
-runtime: memory consumption is reduced by 10-30% (CL 106260045 removes type info from heap, CL 145790043 reduces stack size to 2K (4K on plan 9 and windows))
-runtime: MemStats.Mallocs now counts very small allocations missed in Go 1.3. This may break tests using runtime.ReadMemStats or testing.AllocsPerRun by giving a more accurate answer than Go 1.3 did (CL 143150043).
-runtime/race: freebsd is supported (CL 107270043)
-swig: Due to runtime changes Go 1.4 will require SWIG 3.0.3 (not yet released)
-sync/atomic: add Value (CL 136710045)
-syscall: Setuid, Setgid are disabled on linux platforms. On linux those syscalls operate on the calling thread, not the whole process. This does not match the semantics of other platforms, nor the expectations of the caller, so the operations have been disabled until issue 1435 is resolved (CL 106170043)
-syscall: now frozen (CL 129820043)
-testing: add Coverage (CL 98150043)
-testing: add TestMain support (CL 148770043)
-text/scanner: add IsIdentRune field of Scanner. (CL 108030044)
-text/template: allow comparison of signed and unsigned integers (CL 149780043)
-time: use the micro symbol (µ (U+00B5)) to print microsecond duration (CL 105030046)
-encoding/asn1: optional elements with a default value will now only be omitted if they have that value (CL 86960045)
-
-go.sys subrepo created: http://golang.org/s/go1.4-syscall
index 04a6c1124b88aa0997318d6eec615caaa9932a90..94c48d2ce368945beb6ade82c5818b8fb6adba0d 100644 (file)
@@ -104,6 +104,14 @@ outside of tests, and using it may cause a program to fail
 to compile in future releases.
 </li>
 
+<li>
+Use of package <code>unsafe</code>. Packages that import
+<a href="/pkg/unsafe/"><code>unsafe</code></a>
+may depend on internal properties of the Go implementation.
+We reserve the right to make changes to the implementation
+that may break such programs.
+</li>
+
 </ul>
 
 <p>
index ec3689aeb0b7227f9482427fc7bc3e31c632615f..9aac0583889c523daa63366be865fa6f9f5c0836 100644 (file)
@@ -1115,7 +1115,7 @@ error but the situation can still be confusing, because sometimes a
 <a href="#different_method_sets">pointer
 is necessary to satisfy an interface</a>.
 The insight is that although a pointer to a concrete type can satisfy
-an interface, with one exception <em>a pointer to an interface can never satisfy a interface</em>.
+an interface, with one exception <em>a pointer to an interface can never satisfy an interface</em>.
 </p>
 
 <p>
@@ -1356,7 +1356,7 @@ to speed it up.
 </p>
 
 <p>
-Go's goroutine scheduler is not as good as it needs to be. In future, it
+Go's goroutine scheduler is not as good as it needs to be. In the future, it
 should recognize such cases and optimize its use of OS threads. For now,
 <code>GOMAXPROCS</code> should be set on a per-application basis.
 </p>
index 2ea1ded7a39fd26806521edd7e84c2a2024a60a4..5dd48ff7fbdea77ccaba39402f0c0c22fcdc1efe 100644 (file)
@@ -21,6 +21,29 @@ reads of a variable in one goroutine can be guaranteed to
 observe values produced by writes to the same variable in a different goroutine.
 </p>
 
+
+<h2>Advice</h2>
+
+<p>
+Programs that modify data being simultaneously accessed by multiple goroutines
+must serialize such access.
+</p>
+
+<p>
+To serialize access, protect the data with channel operations or other synchronization primitives
+such as those in the <a href="/pkg/sync/"><code>sync</code></a>
+and <a href="/pkg/sync/atomic/"><code>sync/atomic</code></a> packages.
+</p>
+
+<p>
+If you must read the rest of this document to understand the behavior of your program,
+you are being too clever.
+</p>
+
+<p>
+Don't be clever.
+</p>
+
 <h2>Happens Before</h2>
 
 <p>
index 7fa02e41922c293352da37a30b0c93af582f6e66..050c06465de602daf2f79e28a2cc2abf181fae1d 100644 (file)
@@ -1,6 +1,6 @@
 <!--{
        "Title": "The Go Programming Language Specification",
-       "Subtitle": "Version of September 30, 2014",
+       "Subtitle": "Version of October 27, 2014",
        "Path": "/ref/spec"
 }-->
 
@@ -647,6 +647,65 @@ of evaluating <a href="#Constant_expressions">constant
 expressions</a>.
 </p>
 
+<h2 id="Variables">Variables</h2>
+
+<p>
+A variable is a storage location for holding a <i>value</i>.
+The set of permissible values is determined by the
+variable's <i><a href="#Types">type</a></i>.
+</p>
+
+<p>
+A <a href="#Variable_declarations">variable declaration</a>
+or, for function parameters and results, the signature
+of a <a href="#Function_declarations">function declaration</a>
+or <a href="#Function_literals">function literal</a> reserves
+storage for a named variable.
+
+Calling the built-in function <a href="#Allocation"><code>new</code></a>
+or taking the address of a <a href="#Composite_literals">composite literal</a>
+allocates storage for a variable at run time.
+Such an anonymous variable is referred to via a (possibly implicit)
+<a href="#Address_operators">pointer indirection</a>.
+</p>
+
+<p>
+<i>Structured</i> variables of <a href="#Array_types">array</a>, <a href="#Slice_types">slice</a>,
+and <a href="#Struct_types">struct</a> types have elements and fields that may
+be <a href="#Address_operators">addressed</a> individually. Each such element
+acts like a variable.
+</p>
+
+<p>
+The <i>static type</i> (or just <i>type</i>) of a variable is the      
+type given in its declaration, the type provided in the
+<code>new</code> call or composite literal, or the type of
+an element of a structured variable.
+Variables of interface type also have a distinct <i>dynamic type</i>,
+which is the concrete type of the value assigned to the variable at run time
+(unless the value is the predeclared identifier <code>nil</code>,
+which has no type).
+The dynamic type may vary during execution but values stored in interface
+variables are always <a href="#Assignability">assignable</a>
+to the static type of the variable.    
+</p>   
+
+<pre>
+var x interface{}  // x is nil and has static type interface{}
+var v *T           // v has value nil, static type *T
+x = 42             // x has value 42 and dynamic type int
+x = v              // x has value (*T)(nil) and dynamic type *T
+</pre>
+
+<p>
+A variable's value is retrieved by referring to the variable in an
+<a href="#Expressions">expression</a>; it is the most recent value
+<a href="#Assignments">assigned</a> to the variable.
+If a variable has not yet been assigned a value, its value is the
+<a href="#The_zero_value">zero value</a> for its type.
+</p>
+
+
 <h2 id="Types">Types</h2>
 
 <p>
@@ -672,17 +731,6 @@ interface, slice, map, and channel types&mdash;may be constructed using
 type literals.
 </p>
 
-<p>
-The <i>static type</i> (or just <i>type</i>) of a variable is the
-type defined by its declaration.  Variables of interface type
-also have a distinct <i>dynamic type</i>, which
-is the actual type of the value stored in the variable at run time.
-The dynamic type may vary during execution but is always
-<a href="#Assignability">assignable</a>
-to the static type of the interface variable.  For non-interface
-types, the dynamic type is always the static type.
-</p>
-
 <p>
 Each type <code>T</code> has an <i>underlying type</i>: If <code>T</code>
 is one of the predeclared boolean, numeric, or string types, or a type literal,
@@ -1038,7 +1086,7 @@ struct {
 <h3 id="Pointer_types">Pointer types</h3>
 
 <p>
-A pointer type denotes the set of all pointers to variables of a given
+A pointer type denotes the set of all pointers to <a href="#Variables">variables</a> of a given
 type, called the <i>base type</i> of the pointer.
 The value of an uninitialized pointer is <code>nil</code>.
 </p>
@@ -1461,7 +1509,7 @@ is different from <code>[]string</code>.
 <h3 id="Assignability">Assignability</h3>
 
 <p>
-A value <code>x</code> is <i>assignable</i> to a variable of type <code>T</code>
+A value <code>x</code> is <i>assignable</i> to a <a href="#Variables">variable</a> of type <code>T</code>
 ("<code>x</code> is assignable to <code>T</code>") in any of these cases:
 </p>
 
@@ -2266,7 +2314,8 @@ For array and slice literals the following rules apply:
 
 <p>
 <a href="#Address_operators">Taking the address</a> of a composite literal
-generates a pointer to a unique instance of the literal's value.
+generates a pointer to a unique <a href="#Variables">variable</a> initialized
+with the literal's value.
 </p>
 <pre>
 var pointer *Point3D = &amp;Point3D{y: 1000}
@@ -2400,12 +2449,11 @@ Primary expressions are the operands for unary and binary expressions.
 PrimaryExpr =
        Operand |
        Conversion |
-       BuiltinCall |
        PrimaryExpr Selector |
        PrimaryExpr Index |
        PrimaryExpr Slice |
        PrimaryExpr TypeAssertion |
-       PrimaryExpr Call .
+       PrimaryExpr Arguments .
 
 Selector       = "." identifier .
 Index          = "[" Expression "]" .
@@ -2413,8 +2461,7 @@ Slice          = "[" ( [ Expression ] ":" [ Expression ] ) |
                      ( [ Expression ] ":" Expression ":" Expression )
                  "]" .
 TypeAssertion  = "." "(" Type ")" .
-Call           = "(" [ ArgumentList [ "," ] ] ")" .
-ArgumentList   = ExpressionList [ "..." ] .
+Arguments      = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .
 </pre>
 
 
@@ -3117,7 +3164,7 @@ the method.
 <pre>
 math.Atan2(x, y)  // function call
 var pt *Point
-pt.Scale(3.5)  // method call with receiver pt
+pt.Scale(3.5)     // method call with receiver pt
 </pre>
 
 <p>
@@ -3628,7 +3675,7 @@ then the evaluation of <code>&amp;x</code> does too.
 
 <p>
 For an operand <code>x</code> of pointer type <code>*T</code>, the pointer
-indirection <code>*x</code> denotes the value of type <code>T</code> pointed
+indirection <code>*x</code> denotes the <a href="#Variables">variable</a> of type <code>T</code> pointed
 to by <code>x</code>.
 If <code>x</code> is <code>nil</code>, an attempt to evaluate <code>*x</code>
 will cause a <a href="#Run_time_panics">run-time panic</a>.
@@ -5322,11 +5369,6 @@ so they can only appear in <a href="#Calls">call expressions</a>;
 they cannot be used as function values.
 </p>
 
-<pre class="ebnf">
-BuiltinCall = identifier "(" [ BuiltinArgs [ "," ] ] ")" .
-BuiltinArgs = Type [ "," ArgumentList ] | ArgumentList .
-</pre>
-
 <h3 id="Close">Close</h3>
 
 <p>
@@ -5405,9 +5447,11 @@ var z complex128
 <h3 id="Allocation">Allocation</h3>
 
 <p>
-The built-in function <code>new</code> takes a type <code>T</code> and
-returns a value of type <code>*T</code>.
-The memory is initialized as described in the section on
+The built-in function <code>new</code> takes a type <code>T</code>,
+allocates storage for a <a href="#Variables">variable</a> of that type
+at run time, and returns a value of type <code>*T</code>
+<a href="#Pointer_types">pointing</a> to it.
+The variable is initialized as described in the section on
 <a href="#The_zero_value">initial values</a>.
 </p>
 
@@ -5425,10 +5469,10 @@ new(S)
 </pre>
 
 <p>
-dynamically allocates memory for a variable of type <code>S</code>,
+allocates storage for a variable of type <code>S</code>,
 initializes it (<code>a=0</code>, <code>b=0.0</code>),
 and returns a value of type <code>*S</code> containing the address
-of the memory.
+of the location.
 </p>
 
 <h3 id="Making_slices_maps_and_channels">Making slices, maps and channels</h3>
@@ -5895,10 +5939,12 @@ func main() {
 
 <h3 id="The_zero_value">The zero value</h3>
 <p>
-When memory is allocated to store a value, either through a declaration
-or a call of <code>make</code> or <code>new</code>,
-and no explicit initialization is provided, the memory is
-given a default initialization.  Each element of such a value is
+When storage is allocated for a <a href="#Variables">variable</a>,
+either through a declaration or a call of <code>new</code>, or when
+a new value is created, either through a composite literal or a call
+of <code>make</code>,
+and no explicit initialization is provided, the variable or value is
+given a default value.  Each element of such a variable or value is
 set to the <i>zero value</i> for its type: <code>false</code> for booleans,
 <code>0</code> for integers, <code>0.0</code> for floats, <code>""</code>
 for strings, and <code>nil</code> for pointers, functions, interfaces, slices, channels, and maps.
@@ -6154,8 +6200,8 @@ type Error interface {
 The built-in package <code>unsafe</code>, known to the compiler,
 provides facilities for low-level programming including operations
 that violate the type system. A package using <code>unsafe</code>
-must be vetted manually for type safety.  The package provides the
-following interface:
+must be vetted manually for type safety and may not be portable.
+The package provides the following interface:
 </p>
 
 <pre class="grammar">
@@ -6170,10 +6216,11 @@ func Sizeof(variable ArbitraryType) uintptr
 </pre>
 
 <p>
-Any pointer or value of <a href="#Types">underlying type</a> <code>uintptr</code> can be converted to
-a <code>Pointer</code> type and vice versa.
 A <code>Pointer</code> is a <a href="#Pointer_types">pointer type</a> but a <code>Pointer</code>
 value may not be <a href="#Address_operators">dereferenced</a>.
+Any pointer or value of <a href="#Types">underlying type</a> <code>uintptr</code> can be converted to
+a <code>Pointer</code> type and vice versa.
+The effect of converting between <code>Pointer</code> and <code>uintptr</code> is implementation-defined.
 </p>
 
 <pre>
index 3094856dd44561440f4dfe5ea3761613ebdb5591..9b2373307fa388bd4bf9ab1d90c78174035aa466 100644 (file)
@@ -437,7 +437,8 @@ func (b *Build) Do() error {
                // Build package.
                _, err = b.run(work, "candle",
                        "-nologo",
-                       "-dVersion="+version,
+                       "-dGoVersion="+version,
+                       "-dWixGoVersion="+wixVersion(version),
                        "-dArch="+b.Arch,
                        "-dSourceDir=go",
                        installer, appfiles)
@@ -471,6 +472,22 @@ func (b *Build) Do() error {
        return err
 }
 
+var versionRe = regexp.MustCompile(`^go([0-9]+(\.[0-9]+)*)`)
+
+// The Microsoft installer requires version format major.minor.build
+// (http://msdn.microsoft.com/en-us/library/aa370859%28v=vs.85%29.aspx).
+// Where the major and minor field has a maximum value of 255 and build 65535.
+// The offical Go version format is goMAJOR.MINOR.PATCH at $GOROOT/VERSION.
+// It's based on the Mercurial tag. Remove prefix and suffix to make the
+// installer happy.
+func wixVersion(v string) string {
+       m := versionRe.FindStringSubmatch(v)
+       if m == nil {
+               return "0.0.0"
+       }
+       return m[1]
+}
+
 // extras fetches the go.tools, go.blog, and go-tour repositories,
 // builds them and copies the resulting binaries and static assets
 // to the new GOROOT.
index b170b98dc4572c50b50a0a699d629114f4d8e29f..01178e26514266652e014ba174f99c0a5aea5cb1 100644 (file)
 \r
 <Product\r
     Id="FF5B30B2-08C2-11E1-85A2-6ACA4824019B"\r
-    Name="Go Programming Language $(var.Arch) $(var.Version)"\r
+    Name="Go Programming Language $(var.Arch) $(var.GoVersion)"\r
     Language="1033"\r
     Codepage="1252"\r
-    Version="0.0.0.0"\r
+    Version="$(var.WixGoVersion)"\r
     Manufacturer="http://golang.org"\r
     UpgradeCode="$(var.UpgradeCode)" >\r
-    <!-- Version="$(var.Version)" TODO: Version requires X.X.X.X format -->\r
 \r
 <Package\r
     Id='*' \r
@@ -40,9 +39,9 @@
 \r
 <Property Id="ARPCOMMENTS" Value="The Go programming language is a fast, statically typed, compiled language that feels like a dynamically typed, interpreted language." />\r
 <Property Id="ARPCONTACT" Value="golang-nuts@googlegroups.com" />\r
-<Property Id="ARPHELPLINK" Value="golang.org/doc/community.html" />\r
-<Property Id="ARPREADME" Value="golang.org" />\r
-<Property Id="ARPURLINFOABOUT" Value="golang.org" />\r
+<Property Id="ARPHELPLINK" Value="https://golang.org/help/" />\r
+<Property Id="ARPREADME" Value="https://golang.org" />\r
+<Property Id="ARPURLINFOABOUT" Value="https://golang.org" />\r
 <Property Id="LicenseAccepted">1</Property>\r
 <Icon Id="gopher.ico" SourceFile="images\gopher.ico"/>\r
 <Property Id="ARPPRODUCTICON" Value="gopher.ico" />\r
index 987473ccab60908acd7d4cbea6fe74c8bbd79c90..363620769d911d414c57d85ab6055e4b16c68a97 100644 (file)
@@ -1102,26 +1102,54 @@ clearfat(Node *nl)
        c = w % 8;      // bytes
        q = w / 8;      // quads
 
+       if(q < 4) {
+               // Write sequence of MOV 0, off(base) instead of using STOSQ.
+               // The hope is that although the code will be slightly longer,
+               // the MOVs will have no dependencies and pipeline better
+               // than the unrolled STOSQ loop.
+               // NOTE: Must use agen, not igen, so that optimizer sees address
+               // being taken. We are not writing on field boundaries.
+               agenr(nl, &n1, N);
+               n1.op = OINDREG;
+               nodconst(&z, types[TUINT64], 0);
+               while(q-- > 0) {
+                       n1.type = z.type;
+                       gins(AMOVQ, &z, &n1);
+                       n1.xoffset += 8;
+               }
+               if(c >= 4) {
+                       nodconst(&z, types[TUINT32], 0);
+                       n1.type = z.type;
+                       gins(AMOVL, &z, &n1);
+                       n1.xoffset += 4;
+                       c -= 4;
+               }
+               nodconst(&z, types[TUINT8], 0);
+               while(c-- > 0) {
+                       n1.type = z.type;
+                       gins(AMOVB, &z, &n1);
+                       n1.xoffset++;
+               }
+               regfree(&n1);
+               return;
+       }
+
        savex(D_DI, &n1, &oldn1, N, types[tptr]);
        agen(nl, &n1);
 
        savex(D_AX, &ax, &oldax, N, types[tptr]);
        gconreg(AMOVL, 0, D_AX);
 
-       if(q > 128 || (q >= 4 && nacl)) {
+       if(q > 128 || nacl) {
                gconreg(movptr, q, D_CX);
                gins(AREP, N, N);       // repeat
                gins(ASTOSQ, N, N);     // STOQ AL,*(DI)+
-       } else if(q >= 4) {
+       } else {
                p = gins(ADUFFZERO, N, N);
                p->to.type = D_ADDR;
                p->to.sym = linksym(pkglookup("duffzero", runtimepkg));
                // 2 and 128 = magic constants: see ../../runtime/asm_amd64.s
                p->to.offset = 2*(128-q);
-       } else
-       while(q > 0) {
-               gins(ASTOSQ, N, N);     // STOQ AL,*(DI)+
-               q--;
        }
 
        z = ax;
index 7c986cc6457b4c7d207800fefcd1f6ba9e1e5790..6333a60bb8a7d433dee97f4bfdc606933924fce6 100644 (file)
@@ -157,7 +157,7 @@ void
 clearfat(Node *nl)
 {
        uint32 w, c, q;
-       Node n1;
+       Node n1, z;
        Prog *p;
 
        /* clear a fat object */
@@ -172,6 +172,32 @@ clearfat(Node *nl)
        c = w % 4;      // bytes
        q = w / 4;      // quads
 
+       if(q < 4) {
+               // Write sequence of MOV 0, off(base) instead of using STOSL.
+               // The hope is that although the code will be slightly longer,
+               // the MOVs will have no dependencies and pipeline better
+               // than the unrolled STOSL loop.
+               // NOTE: Must use agen, not igen, so that optimizer sees address
+               // being taken. We are not writing on field boundaries.
+               regalloc(&n1, types[tptr], N);
+               agen(nl, &n1);
+               n1.op = OINDREG;
+               nodconst(&z, types[TUINT64], 0);
+               while(q-- > 0) {
+                       n1.type = z.type;
+                       gins(AMOVL, &z, &n1);
+                       n1.xoffset += 4;
+               }
+               nodconst(&z, types[TUINT8], 0);
+               while(c-- > 0) {
+                       n1.type = z.type;
+                       gins(AMOVB, &z, &n1);
+                       n1.xoffset++;
+               }
+               regfree(&n1);
+               return;
+       }
+
        nodreg(&n1, types[tptr], D_DI);
        agen(nl, &n1);
        gconreg(AMOVL, 0, D_AX);
index 5fbb4f0cf364d2e5b8d7faf4ba765fa870812f82..fbca4ee5f6bb270325fea4f21eda2fb91d028cb5 100644 (file)
@@ -24,7 +24,6 @@ char *runtimeimport =
        "func @\"\".printslice (? any)\n"
        "func @\"\".printnl ()\n"
        "func @\"\".printsp ()\n"
-       "func @\"\".goprintf ()\n"
        "func @\"\".concatstring2 (? string, ? string) (? string)\n"
        "func @\"\".concatstring3 (? string, ? string, ? string) (? string)\n"
        "func @\"\".concatstring4 (? string, ? string, ? string, ? string) (? string)\n"
index eb9eacca8f133d39c73ff2553d32b3dc27fc6b9f..c7c9fcdaff8763fc347cd7219f6b9024859c0444 100644 (file)
@@ -731,14 +731,10 @@ cgen_as(Node *nl, Node *nr)
                return;
        }
 
-       if(nr == N || isnil(nr)) {
-               // externals and heaps should already be clear
-               if(nr == N) {
-                       if(nl->class == PEXTERN)
-                               return;
-                       if(nl->class & PHEAP)
-                               return;
-               }
+       if(nr == N || iszero(nr)) {
+               // heaps should already be clear
+               if(nr == N && (nl->class & PHEAP))
+                       return;
 
                tl = nl->type;
                if(tl == T)
index 8178f7272f5427f7409e912f1f0c613fb0baf06d..965a0550d3683b64c097e8a6f07bb586d4180504 100644 (file)
@@ -283,6 +283,7 @@ struct      Node
        uchar   addrtaken;      // address taken, even if not moved to heap
        uchar   dupok;  // duplicate definitions ok (for func)
        uchar   wrapper;        // is method wrapper (for func)
+       uchar   reslice;        // this is a reslice x = x[0:y] or x = append(x, ...)
        schar   likely; // likeliness of if statement
        uchar   hasbreak;       // has break statement
        uchar   needzero; // if it contains pointers, needs to be zeroed on function entry
@@ -1374,6 +1375,7 @@ int       isnilinter(Type *t);
 int    isptrto(Type *t, int et);
 int    isslice(Type *t);
 int    istype(Type *t, int et);
+int    iszero(Node *n);
 void   linehist(char *file, int32 off, int relative);
 NodeList*      list(NodeList *l, Node *n);
 NodeList*      list1(Node *n);
index 5cf98c62c634cdfd91ae3328a69f57c662b3452c..fd9f591ceae2ac164b48b6be4ffdad8a04af04b4 100644 (file)
@@ -656,7 +656,7 @@ mpdivmodfixfix(Mpint *q, Mpint *r, Mpint *n, Mpint *d)
 }
 
 static int
-iszero(Mpint *a)
+mpiszero(Mpint *a)
 {
        long *a1;
        int i;
@@ -687,7 +687,7 @@ mpdivfract(Mpint *a, Mpint *b)
                for(j=0; j<Mpscale; j++) {
                        x <<= 1;
                        if(mpcmp(&d, &n) <= 0) {
-                               if(!iszero(&d))
+                               if(!mpiszero(&d))
                                        x |= 1;
                                mpsubfixfix(&n, &d);
                        }
index 86afe67f1700dfb767e2881452d91d83542648af..0fb15c26510f8bb29eea1ce27d6d3f1a1392b052 100644 (file)
@@ -36,7 +36,6 @@ func printeface(any)
 func printslice(any)
 func printnl()
 func printsp()
-func goprintf()
 
 func concatstring2(string, string) string
 func concatstring3(string, string, string) string
index f050026d9d07d570e71b909657f698b0b1a9d64e..8ad7ae7abb3a6264e7bb66818305f0abc3036833 100644 (file)
@@ -17,7 +17,6 @@ enum
        InitPending = 2,
 };
 
-static int iszero(Node*);
 static void initplan(Node*);
 static NodeList *initlist;
 static void init2(Node*, NodeList**);
@@ -1068,7 +1067,7 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init)
                if(t->etype != TSTRUCT)
                        fatal("anylit: not struct");
 
-               if(simplename(var)) {
+               if(simplename(var) && count(n->list) > 4) {
 
                        if(ctxt == 0) {
                                // lay out static data
@@ -1091,7 +1090,7 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init)
                }
 
                // initialize of not completely specified
-               if(count(n->list) < structcount(t)) {
+               if(simplename(var) || count(n->list) < structcount(t)) {
                        a = nod(OAS, var, N);
                        typecheck(&a, Etop);
                        walkexpr(&a, init);
@@ -1108,7 +1107,7 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init)
                        break;
                }
 
-               if(simplename(var)) {
+               if(simplename(var) && count(n->list) > 4) {
 
                        if(ctxt == 0) {
                                // lay out static data
@@ -1131,7 +1130,7 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init)
                }
 
                // initialize of not completely specified
-               if(count(n->list) < t->bound) {
+               if(simplename(var) || count(n->list) < t->bound) {
                        a = nod(OAS, var, N);
                        typecheck(&a, Etop);
                        walkexpr(&a, init);
@@ -1356,7 +1355,6 @@ no:
        return 0;
 }
 
-static int iszero(Node*);
 static int isvaluelit(Node*);
 static InitEntry* entry(InitPlan*);
 static void addvalue(InitPlan*, vlong, Node*, Node*);
@@ -1440,7 +1438,7 @@ addvalue(InitPlan *p, vlong xoffset, Node *key, Node *n)
        e->expr = n;
 }
 
-static int
+int
 iszero(Node *n)
 {
        NodeList *l;
index ff49fe6f92e5fa6e8b153660052e17fd9b19dd6f..714c662681e92b58adbd9249b6641ea42c5ca11e 100644 (file)
@@ -2127,13 +2127,16 @@ lookdot(Node *n, Type *t, int dostrcmp)
                                n->left = nod(OADDR, n->left, N);
                                n->left->implicit = 1;
                                typecheck(&n->left, Etype|Erv);
-                       } else if(tt->etype == tptr && eqtype(tt->type, rcvr)) {
+                       } else if(tt->etype == tptr && rcvr->etype != tptr && eqtype(tt->type, rcvr)) {
                                n->left = nod(OIND, n->left, N);
                                n->left->implicit = 1;
                                typecheck(&n->left, Etype|Erv);
-                       } else if(tt->etype == tptr && tt->type->etype == tptr && eqtype(derefall(tt), rcvr)) {
+                       } else if(tt->etype == tptr && tt->type->etype == tptr && eqtype(derefall(tt), derefall(rcvr))) {
                                yyerror("calling method %N with receiver %lN requires explicit dereference", n->right, n->left);
                                while(tt->etype == tptr) {
+                                       // Stop one level early for method with pointer receiver.
+                                       if(rcvr->etype == tptr && tt->type->etype != tptr)
+                                               break;
                                        n->left = nod(OIND, n->left, N);
                                        n->left->implicit = 1;
                                        typecheck(&n->left, Etype|Erv);
@@ -2814,6 +2817,33 @@ checkassignlist(NodeList *l)
                checkassign(l->n);
 }
 
+// Check whether l and r are the same side effect-free expression,
+// so that it is safe to reuse one instead of computing both.
+static int
+samesafeexpr(Node *l, Node *r)
+{
+       if(l->op != r->op || !eqtype(l->type, r->type))
+               return 0;
+       
+       switch(l->op) {
+       case ONAME:
+       case OCLOSUREVAR:
+               return l == r;
+       
+       case ODOT:
+       case ODOTPTR:
+               return l->right != nil && r->right != nil && l->right->sym == r->right->sym && samesafeexpr(l->left, r->left);
+       
+       case OIND:
+               return samesafeexpr(l->left, r->left);
+       
+       case OINDEX:
+               return samesafeexpr(l->left, r->left) && samesafeexpr(l->right, r->right);
+       }
+       
+       return 0;
+}
+
 /*
  * type check assignment.
  * if this assignment is the definition of a var on the left side,
@@ -2851,6 +2881,29 @@ typecheckas(Node *n)
        n->typecheck = 1;
        if(n->left->typecheck == 0)
                typecheck(&n->left, Erv | Easgn);
+       
+       // Recognize slices being updated in place, for better code generation later.
+       // Don't rewrite if using race detector, to avoid needing to teach race detector
+       // about this optimization.
+       if(n->left && n->left->op != OINDEXMAP && n->right && !flag_race) {
+               switch(n->right->op) {
+               case OSLICE:
+               case OSLICE3:
+               case OSLICESTR:
+                       // For x = x[0:y], x can be updated in place, without touching pointer.
+                       if(samesafeexpr(n->left, n->right->left) && (n->right->right->left == N || iszero(n->right->right->left)))
+                               n->right->reslice = 1;
+                       break;
+               
+               case OAPPEND:
+                       // For x = append(x, ...), x can be updated in place when there is capacity,
+                       // without touching the pointer; otherwise the emitted code to growslice
+                       // can take care of updating the pointer, and only in that case.
+                       if(n->right->list != nil && samesafeexpr(n->left, n->right->list->n))
+                               n->right->reslice = 1;
+                       break;
+               }
+       }
 }
 
 static void
index 241d7d74adbc9029c12a02c12de63e0c0fbbd628..ff9b362083e7892bc920bc02fd142719a618cf52 100644 (file)
@@ -7,7 +7,7 @@
 #include       "go.h"
 #include       "../ld/textflag.h"
 
-static Node*   walkprint(Node*, NodeList**, int);
+static Node*   walkprint(Node*, NodeList**);
 static Node*   writebarrierfn(char*, Type*, Type*);
 static Node*   applywritebarrier(Node*, NodeList**);
 static Node*   mapfn(char*, Type*);
@@ -32,6 +32,7 @@ static        void    walkmul(Node**, NodeList**);
 static void    walkdiv(Node**, NodeList**);
 static int     bounded(Node*, int64);
 static Mpint   mpzero;
+static void    walkprintfunc(Node**, NodeList**);
 
 void
 walk(Node *fn)
@@ -226,8 +227,7 @@ walkstmt(Node **np)
                switch(n->left->op) {
                case OPRINT:
                case OPRINTN:
-                       walkexprlist(n->left->list, &n->ninit);
-                       n->left = walkprint(n->left, &n->ninit, 1);
+                       walkprintfunc(&n->left, &n->ninit);
                        break;
                case OCOPY:
                        n->left = copyany(n->left, &n->ninit, 1);
@@ -260,8 +260,7 @@ walkstmt(Node **np)
                switch(n->left->op) {
                case OPRINT:
                case OPRINTN:
-                       walkexprlist(n->left->list, &n->ninit);
-                       n->left = walkprint(n->left, &n->ninit, 1);
+                       walkprintfunc(&n->left, &n->ninit);
                        break;
                case OCOPY:
                        n->left = copyany(n->left, &n->ninit, 1);
@@ -543,7 +542,7 @@ walkexpr(Node **np, NodeList **init)
        case OPRINT:
        case OPRINTN:
                walkexprlist(n->list, init);
-               n = walkprint(n, init, 0);
+               n = walkprint(n, init);
                goto ret;
 
        case OPANIC:
@@ -614,7 +613,7 @@ walkexpr(Node **np, NodeList **init)
                if(oaslit(n, init))
                        goto ret;
 
-               if(n->right == N)
+               if(n->right == N || iszero(n->right) && !flag_race)
                        goto ret;
 
                switch(n->right->op) {
@@ -1390,7 +1389,6 @@ walkexpr(Node **np, NodeList **init)
        case OMAPLIT:
        case OSTRUCTLIT:
        case OPTRLIT:
-               // XXX TODO do we need to clear var?
                var = temp(n->type);
                anylit(0, n, var, init);
                n = var;
@@ -1494,7 +1492,7 @@ fncall(Node *l, Type *rt)
 
        if(l->ullman >= UINF || l->op == OINDEXMAP)
                return 1;
-       r.op = 0;
+       memset(&r, 0, sizeof r);
        if(needwritebarrier(l, &r))
                return 1;
        if(eqtype(l->type, rt))
@@ -1758,7 +1756,7 @@ ret:
 
 // generate code for print
 static Node*
-walkprint(Node *nn, NodeList **init, int defer)
+walkprint(Node *nn, NodeList **init)
 {
        Node *r;
        Node *n;
@@ -1766,31 +1764,17 @@ walkprint(Node *nn, NodeList **init, int defer)
        Node *on;
        Type *t;
        int notfirst, et, op;
-       NodeList *calls, *intypes, *args;
-       Fmt fmt;
+       NodeList *calls;
 
        on = nil;
        op = nn->op;
        all = nn->list;
        calls = nil;
        notfirst = 0;
-       intypes = nil;
-       args = nil;
-
-       memset(&fmt, 0, sizeof fmt);
-       if(defer) {
-               // defer print turns into defer printf with format string
-               fmtstrinit(&fmt);
-               intypes = list(intypes, nod(ODCLFIELD, N, typenod(types[TSTRING])));
-               args = list1(nod(OXXX, N, N));
-       }
 
        for(l=all; l; l=l->next) {
                if(notfirst) {
-                       if(defer)
-                               fmtprint(&fmt, " ");
-                       else
-                               calls = list(calls, mkcall("printsp", T, init));
+                       calls = list(calls, mkcall("printsp", T, init));
                }
                notfirst = op == OPRINTN;
 
@@ -1818,122 +1802,63 @@ walkprint(Node *nn, NodeList **init, int defer)
                t = n->type;
                et = n->type->etype;
                if(isinter(n->type)) {
-                       if(defer) {
-                               if(isnilinter(n->type))
-                                       fmtprint(&fmt, "%%e");
-                               else
-                                       fmtprint(&fmt, "%%i");
-                       } else {
-                               if(isnilinter(n->type))
-                                       on = syslook("printeface", 1);
-                               else
-                                       on = syslook("printiface", 1);
-                               argtype(on, n->type);           // any-1
-                       }
+                       if(isnilinter(n->type))
+                               on = syslook("printeface", 1);
+                       else
+                               on = syslook("printiface", 1);
+                       argtype(on, n->type);           // any-1
                } else if(isptr[et] || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR) {
-                       if(defer) {
-                               fmtprint(&fmt, "%%p");
-                       } else {
-                               on = syslook("printpointer", 1);
-                               argtype(on, n->type);   // any-1
-                       }
+                       on = syslook("printpointer", 1);
+                       argtype(on, n->type);   // any-1
                } else if(isslice(n->type)) {
-                       if(defer) {
-                               fmtprint(&fmt, "%%a");
-                       } else {
-                               on = syslook("printslice", 1);
-                               argtype(on, n->type);   // any-1
-                       }
+                       on = syslook("printslice", 1);
+                       argtype(on, n->type);   // any-1
                } else if(isint[et]) {
-                       if(defer) {
-                               if(et == TUINT64)
-                                       fmtprint(&fmt, "%%U");
-                               else {
-                                       fmtprint(&fmt, "%%D");
-                                       t = types[TINT64];
-                               }
-                       } else {
-                               if(et == TUINT64) {
-                                       if((t->sym->pkg == runtimepkg || compiling_runtime) && strcmp(t->sym->name, "hex") == 0)
-                                               on = syslook("printhex", 0);
-                                       else
-                                               on = syslook("printuint", 0);
-                               } else
-                                       on = syslook("printint", 0);
-                       }
-               } else if(isfloat[et]) {
-                       if(defer) {
-                               fmtprint(&fmt, "%%f");
-                               t = types[TFLOAT64];
+                       if(et == TUINT64) {
+                               if((t->sym->pkg == runtimepkg || compiling_runtime) && strcmp(t->sym->name, "hex") == 0)
+                                       on = syslook("printhex", 0);
+                               else
+                                       on = syslook("printuint", 0);
                        } else
-                               on = syslook("printfloat", 0);
+                               on = syslook("printint", 0);
+               } else if(isfloat[et]) {
+                       on = syslook("printfloat", 0);
                } else if(iscomplex[et]) {
-                       if(defer) {
-                               fmtprint(&fmt, "%%C");
-                               t = types[TCOMPLEX128];
-                       } else
-                               on = syslook("printcomplex", 0);
+                       on = syslook("printcomplex", 0);
                } else if(et == TBOOL) {
-                       if(defer)
-                               fmtprint(&fmt, "%%t");
-                       else
-                               on = syslook("printbool", 0);
+                       on = syslook("printbool", 0);
                } else if(et == TSTRING) {
-                       if(defer)
-                               fmtprint(&fmt, "%%S");
-                       else
-                               on = syslook("printstring", 0);
+                       on = syslook("printstring", 0);
                } else {
                        badtype(OPRINT, n->type, T);
                        continue;
                }
 
-               if(!defer) {
-                       t = *getinarg(on->type);
-                       if(t != nil)
-                               t = t->type;
-                       if(t != nil)
-                               t = t->type;
-               }
+               t = *getinarg(on->type);
+               if(t != nil)
+                       t = t->type;
+               if(t != nil)
+                       t = t->type;
 
                if(!eqtype(t, n->type)) {
                        n = nod(OCONV, n, N);
                        n->type = t;
                }
 
-               if(defer) {
-                       intypes = list(intypes, nod(ODCLFIELD, N, typenod(t)));
-                       args = list(args, n);
-               } else {
-                       r = nod(OCALL, on, N);
-                       r->list = list1(n);
-                       calls = list(calls, r);
-               }
+               r = nod(OCALL, on, N);
+               r->list = list1(n);
+               calls = list(calls, r);
        }
 
-       if(defer) {
-               if(op == OPRINTN)
-                       fmtprint(&fmt, "\n");
-               on = syslook("goprintf", 1);
-               on->type = functype(nil, intypes, nil);
-               args->n = nod(OLITERAL, N, N);
-               args->n->val.ctype = CTSTR;
-               args->n->val.u.sval = strlit(fmtstrflush(&fmt));
-               r = nod(OCALL, on, N);
-               r->list = args;
-               typecheck(&r, Etop);
-               walkexpr(&r, init);
-       } else {
-               if(op == OPRINTN)
-                       calls = list(calls, mkcall("printnl", T, nil));
-               typechecklist(calls, Etop);
-               walkexprlist(calls, init);
+       if(op == OPRINTN)
+               calls = list(calls, mkcall("printnl", T, nil));
+       typechecklist(calls, Etop);
+       walkexprlist(calls, init);
 
-               r = nod(OEMPTY, N, N);
-               typecheck(&r, Etop);
-               walkexpr(&r, init);
-               r->ninit = calls;
-       }
+       r = nod(OEMPTY, N, N);
+       typecheck(&r, Etop);
+       walkexpr(&r, init);
+       r->ninit = calls;
        return r;
 }
 
@@ -2009,8 +1934,8 @@ needwritebarrier(Node *l, Node *r)
        if(isstack(l))
                return 0;
 
-       // No write barrier for zeroing.
-       if(r == N)
+       // No write barrier for implicit or explicit zeroing.
+       if(r == N || iszero(r))
                return 0;
 
        // No write barrier for initialization to constant.
@@ -2031,6 +1956,28 @@ needwritebarrier(Node *l, Node *r)
        if(r->op == OADDR && isglobal(r->left))
                return 0;
 
+       // No write barrier for reslice: x = x[0:y] or x = append(x, ...).
+       // Both are compiled to modify x directly.
+       // In the case of append, a write barrier may still be needed
+       // if the underlying array grows, but the append code can
+       // generate the write barrier directly in that case.
+       // (It does not yet, but the cost of the write barrier will be
+       // small compared to the cost of the allocation.)
+       if(r->reslice) {
+               switch(r->op) {
+               case OSLICE:
+               case OSLICE3:
+               case OSLICESTR:
+               case OAPPEND:
+                       break;
+               default:
+                       dump("bad reslice-l", l);
+                       dump("bad reslice-r", r);
+                       break;
+               }
+               return 0;
+       }
+
        // Otherwise, be conservative and use write barrier.
        return 1;
 }
@@ -3208,7 +3155,7 @@ countfield(Type *t)
 static void
 walkcompare(Node **np, NodeList **init)
 {
-       Node *n, *l, *r, *call, *a, *li, *ri, *expr;
+       Node *n, *l, *r, *call, *a, *li, *ri, *expr, *cmpl, *cmpr;
        int andor, i;
        Type *t, *t1;
        
@@ -3228,18 +3175,25 @@ walkcompare(Node **np, NodeList **init)
                break;
        }
        
-       if(!islvalue(n->left) || !islvalue(n->right)) {
-               fatal("arguments of comparison must be lvalues");
+       cmpl = n->left;
+       while(cmpl != N && cmpl->op == OCONVNOP)
+               cmpl = cmpl->left;
+       cmpr = n->right;
+       while(cmpr != N && cmpr->op == OCONVNOP)
+               cmpr = cmpr->left;
+       
+       if(!islvalue(cmpl) || !islvalue(cmpr)) {
+               fatal("arguments of comparison must be lvalues - %N %N", cmpl, cmpr);
        }
 
        l = temp(ptrto(t));
-       a = nod(OAS, l, nod(OADDR, n->left, N));
+       a = nod(OAS, l, nod(OADDR, cmpl, N));
        a->right->etype = 1;  // addr does not escape
        typecheck(&a, Etop);
        *init = list(*init, a);
 
        r = temp(ptrto(t));
-       a = nod(OAS, r, nod(OADDR, n->right, N));
+       a = nod(OAS, r, nod(OADDR, cmpr, N));
        a->right->etype = 1;  // addr does not escape
        typecheck(&a, Etop);
        *init = list(*init, a);
@@ -3913,3 +3867,71 @@ candiscard(Node *n)
        
        return 1;
 }
+
+// rewrite
+//     print(x, y, z)
+// into
+//     func(a1, a2, a3) {
+//             print(a1, a2, a3)
+//     }(x, y, z)
+// and same for println.
+static void
+walkprintfunc(Node **np, NodeList **init)
+{
+       Node *n;
+       Node *a, *fn, *t, *oldfn;
+       NodeList *l, *printargs;
+       int num;
+       char buf[100];
+       static int prgen;
+       
+       n = *np;
+
+       if(n->ninit != nil) {
+               walkstmtlist(n->ninit);
+               *init = concat(*init, n->ninit);
+               n->ninit = nil;
+       }
+
+       t = nod(OTFUNC, N, N);
+       num = 0;
+       printargs = nil;
+       for(l=n->list; l != nil; l=l->next) {
+               snprint(buf, sizeof buf, "a%d", num++);
+               a = nod(ODCLFIELD, newname(lookup(buf)), typenod(l->n->type));
+               t->list = list(t->list, a);
+               printargs = list(printargs, a->left);
+       }
+
+       fn = nod(ODCLFUNC, N, N);
+       snprint(buf, sizeof buf, "print·%d", ++prgen);
+       fn->nname = newname(lookup(buf));
+       fn->nname->defn = fn;
+       fn->nname->ntype = t;
+       declare(fn->nname, PFUNC);
+
+       oldfn = curfn;
+       curfn = nil;
+       funchdr(fn);
+       
+       a = nod(n->op, N, N);
+       a->list = printargs;
+       typecheck(&a, Etop);
+       walkstmt(&a);
+       
+       fn->nbody = list1(a);
+
+       funcbody(fn);
+       
+       typecheck(&fn, Etop);
+       typechecklist(fn->nbody, Etop);
+       xtop = list(xtop, fn);
+       curfn = oldfn;
+
+       a = nod(OCALL, N, N);
+       a->left = fn->nname;
+       a->list = n->list;
+       typecheck(&a, Etop);
+       walkexpr(&a, init);
+       *np = a;
+}
index 49b84709e2db68adfab9a08d53bc79bf80554768..79a27116a1751e20d5c6ce5156ea2cfbc30a7794 100644 (file)
@@ -1945,6 +1945,7 @@ func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions []
        }
        ldflags = append(ldflags, afiles...)
        ldflags = append(ldflags, cgoldflags...)
+       ldflags = append(ldflags, envList("CGO_LDFLAGS", "")...)
        ldflags = append(ldflags, p.CgoLDFLAGS...)
        if usesCgo && goos == "linux" {
                ldflags = append(ldflags, "-Wl,-E")
index 167758207e3301a8703a80fdddc0ab090728a8c2..4227abbe7c50a66bbf29f07447c5869d7d56a120 100644 (file)
@@ -169,6 +169,7 @@ func (g *Generator) run() (ok bool) {
                        if e != stop {
                                panic(e)
                        }
+                       setExitStatus(1)
                }
        }()
        g.dir, g.file = filepath.Split(g.path)
@@ -267,7 +268,8 @@ Words:
 var stop = fmt.Errorf("error in generation")
 
 // errorf logs an error message prefixed with the file and line number.
-// It then exits the program because generation stops at the first error.
+// It then exits the program (with exit status 1) because generation stops
+// at the first error.
 func (g *Generator) errorf(format string, args ...interface{}) {
        fmt.Fprintf(os.Stderr, "%s:%d: %s\n", shortPath(g.path), g.lineNum,
                fmt.Sprintf(format, args...))
index 2640339414a5ce62a4a430c71f2aae4aca93fb4b..86e1697618ab4d6e21f8e5d78ef1d5b547abc2ac 100644 (file)
@@ -16,7 +16,7 @@ import (
 )
 
 var cmdGet = &Command{
-       UsageLine: "get [-d] [-fix] [-t] [-u] [build flags] [packages]",
+       UsageLine: "get [-d] [-f] [-fix] [-t] [-u] [build flags] [packages]",
        Short:     "download and install packages and dependencies",
        Long: `
 Get downloads and installs the packages named by the import paths,
@@ -25,6 +25,11 @@ along with their dependencies.
 The -d flag instructs get to stop after downloading the packages; that is,
 it instructs get not to install the packages.
 
+The -f flag, valid only when -u is set, forces get -u not to verify that
+each package has been checked out from the source control repository
+implied by its import path. This can be useful if the source is a local fork
+of the original.
+
 The -fix flag instructs get to run the fix tool on the downloaded packages
 before resolving dependencies or building the code.
 
@@ -53,6 +58,7 @@ See also: go build, go install, go clean.
 }
 
 var getD = cmdGet.Flag.Bool("d", false, "")
+var getF = cmdGet.Flag.Bool("f", false, "")
 var getT = cmdGet.Flag.Bool("t", false, "")
 var getU = cmdGet.Flag.Bool("u", false, "")
 var getFix = cmdGet.Flag.Bool("fix", false, "")
@@ -63,6 +69,10 @@ func init() {
 }
 
 func runGet(cmd *Command, args []string) {
+       if *getF && !*getU {
+               fatalf("go get: cannot use -f flag without -u")
+       }
+
        // Phase 1.  Download/update.
        var stk importStack
        for _, arg := range downloadPaths(args) {
@@ -268,12 +278,19 @@ func downloadPackage(p *Package) error {
                repo = "<local>" // should be unused; make distinctive
 
                // Double-check where it came from.
-               if *getU && vcs.remoteRepo != nil {
+               if *getU && vcs.remoteRepo != nil && !*getF {
                        dir := filepath.Join(p.build.SrcRoot, rootPath)
                        if remote, err := vcs.remoteRepo(vcs, dir); err == nil {
                                if rr, err := repoRootForImportPath(p.ImportPath); err == nil {
-                                       if remote != rr.repo {
-                                               return fmt.Errorf("%s is from %s, should be from %s", dir, remote, rr.repo)
+                                       repo := rr.repo
+                                       if rr.vcs.resolveRepo != nil {
+                                               resolved, err := rr.vcs.resolveRepo(rr.vcs, dir, repo)
+                                               if err == nil {
+                                                       repo = resolved
+                                               }
+                                       }
+                                       if remote != repo {
+                                               return fmt.Errorf("%s is from %s, should be from %s", dir, remote, repo)
                                        }
                                }
                        }
index 652ef3b5b6ad0e0f68dd988401f858408ead2d4c..2b5230b1aac3580a2d7a98972eae437c2f750d3f 100755 (executable)
@@ -219,6 +219,16 @@ q' | ed $d/src/$config >/dev/null 2>&1
                        cat $d/err
                        ok=false
                fi
+               
+               if GOPATH=$d ./testgo get -d -f -u $url 2>$d/err; then
+                       echo "go get -d -u $url succeeded with wrong remote repo"
+                       cat $d/err
+                       ok=false
+               elif ! egrep -i 'validating server certificate|not found' $d/err >/dev/null; then
+                       echo "go get -d -f -u $url failed for wrong reason"
+                       cat $d/err
+                       ok=false
+               fi
        fi
        rm -rf $d
 }
index 0834a7d192df7fe32176e6d4234c2a34d2d8345a..1cac6133889be6e4724cb3899e9f2306066dbf8c 100644 (file)
@@ -34,7 +34,8 @@ type vcsCmd struct {
        scheme  []string
        pingCmd string
 
-       remoteRepo func(v *vcsCmd, rootDir string) (remoteRepo string, err error)
+       remoteRepo  func(v *vcsCmd, rootDir string) (remoteRepo string, err error)
+       resolveRepo func(v *vcsCmd, rootDir, remoteRepo string) (realRepo string, err error)
 }
 
 // A tagCmd describes a command to list available tags
@@ -164,8 +165,51 @@ var vcsBzr = &vcsCmd{
        tagSyncCmd:     "update -r {tag}",
        tagSyncDefault: "update -r revno:-1",
 
-       scheme:  []string{"https", "http", "bzr", "bzr+ssh"},
-       pingCmd: "info {scheme}://{repo}",
+       scheme:      []string{"https", "http", "bzr", "bzr+ssh"},
+       pingCmd:     "info {scheme}://{repo}",
+       remoteRepo:  bzrRemoteRepo,
+       resolveRepo: bzrResolveRepo,
+}
+
+func bzrRemoteRepo(vcsBzr *vcsCmd, rootDir string) (remoteRepo string, err error) {
+       outb, err := vcsBzr.runOutput(rootDir, "config parent_location")
+       if err != nil {
+               return "", err
+       }
+       return strings.TrimSpace(string(outb)), nil
+}
+
+func bzrResolveRepo(vcsBzr *vcsCmd, rootDir, remoteRepo string) (realRepo string, err error) {
+       outb, err := vcsBzr.runOutput(rootDir, "info "+remoteRepo)
+       if err != nil {
+               return "", err
+       }
+       out := string(outb)
+
+       // Expect:
+       // ...
+       //   (branch root|repository branch): <URL>
+       // ...
+
+       found := false
+       for _, prefix := range []string{"\n  branch root: ", "\n  repository branch: "} {
+               i := strings.Index(out, prefix)
+               if i >= 0 {
+                       out = out[i+len(prefix):]
+                       found = true
+                       break
+               }
+       }
+       if !found {
+               return "", fmt.Errorf("unable to parse output of bzr info")
+       }
+
+       i := strings.Index(out, "\n")
+       if i < 0 {
+               return "", fmt.Errorf("unable to parse output of bzr info")
+       }
+       out = out[:i]
+       return strings.TrimSpace(string(out)), nil
 }
 
 // vcsSvn describes how to use Subversion.
index 9983a9281cb07f6238d421719d8aa78f5ccbe35e..61847546a33d5ba95fedb5967283e7068950b377 100644 (file)
@@ -633,9 +633,7 @@ addstrdata(char *name, char *value)
        s->dupok = 1;
        reachable = s->reachable;
        addaddr(ctxt, s, sp);
-       adduint32(ctxt, s, strlen(value));
-       if(PtrSize == 8)
-               adduint32(ctxt, s, 0);  // round struct to pointer width
+       adduintxx(ctxt, s, strlen(value), PtrSize);
 
        // addstring, addaddr, etc., mark the symbols as reachable.
        // In this case that is not necessarily true, so stick to what
index 35f8b49856ba23d8d7f32a2270366dff971ec791..b5d0819493f2a5ffcc89e6bfc2fcffff6aa8c81f 100644 (file)
@@ -819,7 +819,7 @@ readsym(ElfObj *obj, int i, ElfSym *sym, int needSym)
                        }
                        break;
                case ElfSymBindLocal:
-                       if(!(thechar == '5' && (strcmp(sym->name, "$a") == 0 || strcmp(sym->name, "$d") == 0))) // binutils for arm generate these mapping symbols, ignore these
+                       if(!(thechar == '5' && (strncmp(sym->name, "$a", 2) == 0 || strncmp(sym->name, "$d", 2) == 0))) // binutils for arm generate these mapping symbols, ignore these
                                if(needSym) {
                                        // local names and hidden visiblity global names are unique
                                        // and should only reference by its index, not name, so we
index aafc501110a82dca7bee7fb38e5ba3fc03bd2770..0f66f20a400131cf34b63559eb3eaa300b5d1c87 100644 (file)
@@ -159,7 +159,7 @@ func dump(tab *gosym.Table, lookup lookupFunc, disasm disasmFunc, goarch string,
 
        printed := false
        for _, sym := range syms {
-               if sym.Code != 'T' || sym.Size == 0 || sym.Name == "_text" || sym.Name == "text" || sym.Addr < textStart || symRE != nil && !symRE.MatchString(sym.Name) {
+               if (sym.Code != 'T' && sym.Code != 't') || sym.Size == 0 || sym.Name == "_text" || sym.Name == "text" || sym.Addr < textStart || symRE != nil && !symRE.MatchString(sym.Name) {
                        continue
                }
                if sym.Addr >= textStart+uint64(len(textData)) || sym.Addr+uint64(sym.Size) > textStart+uint64(len(textData)) {
index 541085626213b47cab00d2f2d3c33d73fad8179d..0a2d2565a74db58758fd1755a5ab23b630fc2882 100644 (file)
@@ -157,12 +157,15 @@ var armNeed = []string{
 // binary for the current system (only) and test that objdump
 // can handle that one.
 
-func TestDisasm(t *testing.T) {
+func testDisasm(t *testing.T, flags ...string) {
        tmp, exe := buildObjdump(t)
        defer os.RemoveAll(tmp)
 
        hello := filepath.Join(tmp, "hello.exe")
-       out, err := exec.Command("go", "build", "-o", hello, "testdata/fmthello.go").CombinedOutput()
+       args := []string{"build", "-o", hello}
+       args = append(args, flags...)
+       args = append(args, "testdata/fmthello.go")
+       out, err := exec.Command("go", args...).CombinedOutput()
        if err != nil {
                t.Fatalf("go build fmthello.go: %v\n%s", err, out)
        }
@@ -194,3 +197,15 @@ func TestDisasm(t *testing.T) {
                t.Logf("full disassembly:\n%s", text)
        }
 }
+
+func TestDisasm(t *testing.T) {
+       testDisasm(t)
+}
+
+func TestDisasmExtld(t *testing.T) {
+       switch runtime.GOOS {
+       case "plan9", "windows":
+               t.Skipf("skipping on %s", runtime.GOOS)
+       }
+       testDisasm(t, "-ldflags=-linkmode=external")
+}
index a7fe94c50c1635966b0eb567a7377d4ac234fd21..76519bbf4274f89a95372f07d48c4ff869866f12 100644 (file)
@@ -56,6 +56,15 @@ func (e *WriteError) Error() string {
        return "flate: write error at offset " + strconv.FormatInt(e.Offset, 10) + ": " + e.Err.Error()
 }
 
+// Resetter resets a ReadCloser returned by NewReader or NewReaderDict to
+// to switch to a new underlying Reader. This permits reusing a ReadCloser
+// instead of allocating a new one.
+type Resetter interface {
+       // Reset discards any buffered data and resets the Resetter as if it was
+       // newly initialized with the given reader.
+       Reset(r io.Reader, dict []byte) error
+}
+
 // Note that much of the implementation of huffmanDecoder is also copied
 // into gen.go (in package main) for the purpose of precomputing the
 // fixed huffman tables so they can be included statically.
@@ -679,12 +688,28 @@ func makeReader(r io.Reader) Reader {
        return bufio.NewReader(r)
 }
 
+func (f *decompressor) Reset(r io.Reader, dict []byte) error {
+       *f = decompressor{
+               r:        makeReader(r),
+               bits:     f.bits,
+               codebits: f.codebits,
+               hist:     f.hist,
+               step:     (*decompressor).nextBlock,
+       }
+       if dict != nil {
+               f.setDict(dict)
+       }
+       return nil
+}
+
 // NewReader returns a new ReadCloser that can be used
 // to read the uncompressed version of r.
 // If r does not also implement io.ByteReader,
 // the decompressor may read more data than necessary from r.
 // It is the caller's responsibility to call Close on the ReadCloser
 // when finished reading.
+//
+// The ReadCloser returned by NewReader also implements Resetter.
 func NewReader(r io.Reader) io.ReadCloser {
        var f decompressor
        f.bits = new([maxLit + maxDist]int)
@@ -700,6 +725,8 @@ func NewReader(r io.Reader) io.ReadCloser {
 // the uncompressed data stream started with the given dictionary,
 // which has already been read.  NewReaderDict is typically used
 // to read data compressed by NewWriterDict.
+//
+// The ReadCloser returned by NewReader also implements Resetter.
 func NewReaderDict(r io.Reader, dict []byte) io.ReadCloser {
        var f decompressor
        f.r = makeReader(r)
diff --git a/src/compress/flate/inflate_test.go b/src/compress/flate/inflate_test.go
new file mode 100644 (file)
index 0000000..9f25d30
--- /dev/null
@@ -0,0 +1,39 @@
+// Copyright 2014 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 flate
+
+import (
+       "bytes"
+       "io"
+       "testing"
+)
+
+func TestReset(t *testing.T) {
+       ss := []string{
+               "lorem ipsum izzle fo rizzle",
+               "the quick brown fox jumped over",
+       }
+
+       deflated := make([]bytes.Buffer, 2)
+       for i, s := range ss {
+               w, _ := NewWriter(&deflated[i], 1)
+               w.Write([]byte(s))
+               w.Close()
+       }
+
+       inflated := make([]bytes.Buffer, 2)
+
+       f := NewReader(&deflated[0])
+       io.Copy(&inflated[0], f)
+       f.(Resetter).Reset(&deflated[1], nil)
+       io.Copy(&inflated[1], f)
+       f.Close()
+
+       for i, s := range ss {
+               if s != inflated[i].String() {
+                       t.Errorf("inflated[%d]:\ngot  %q\nwant %q", i, inflated[i], s)
+               }
+       }
+}
index fc08c7a48c53e80079180ae59835f5da11a4057f..72ee55c4fabdf5a310688bd7fda031c389510e1c 100644 (file)
@@ -74,6 +74,7 @@ type Reader struct {
        flg          byte
        buf          [512]byte
        err          error
+       multistream  bool
 }
 
 // NewReader creates a new Reader reading the given reader.
@@ -83,6 +84,7 @@ type Reader struct {
 func NewReader(r io.Reader) (*Reader, error) {
        z := new(Reader)
        z.r = makeReader(r)
+       z.multistream = true
        z.digest = crc32.NewIEEE()
        if err := z.readHeader(true); err != nil {
                return nil, err
@@ -102,9 +104,30 @@ func (z *Reader) Reset(r io.Reader) error {
        }
        z.size = 0
        z.err = nil
+       z.multistream = true
        return z.readHeader(true)
 }
 
+// Multistream controls whether the reader supports multistream files.
+//
+// If enabled (the default), the Reader expects the input to be a sequence
+// of individually gzipped data streams, each with its own header and
+// trailer, ending at EOF. The effect is that the concatenation of a sequence
+// of gzipped files is treated as equivalent to the gzip of the concatenation
+// of the sequence. This is standard behavior for gzip readers.
+//
+// Calling Multistream(false) disables this behavior; disabling the behavior
+// can be useful when reading file formats that distinguish individual gzip
+// data streams or mix gzip data streams with other data streams.
+// In this mode, when the Reader reaches the end of the data stream,
+// Read returns io.EOF. If the underlying reader implements io.ByteReader,
+// it will be left positioned just after the gzip stream.
+// To start the next stream, call z.Reset(r) followed by z.Multistream(false).
+// If there is no next stream, z.Reset(r) will return io.EOF.
+func (z *Reader) Multistream(ok bool) {
+       z.multistream = ok
+}
+
 // GZIP (RFC 1952) is little-endian, unlike ZLIB (RFC 1950).
 func get4(p []byte) uint32 {
        return uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24
@@ -208,7 +231,11 @@ func (z *Reader) readHeader(save bool) error {
        }
 
        z.digest.Reset()
-       z.decompressor = flate.NewReader(z.r)
+       if z.decompressor == nil {
+               z.decompressor = flate.NewReader(z.r)
+       } else {
+               z.decompressor.(flate.Resetter).Reset(z.r, nil)
+       }
        return nil
 }
 
@@ -241,6 +268,10 @@ func (z *Reader) Read(p []byte) (n int, err error) {
        }
 
        // File is ok; is there another?
+       if !z.multistream {
+               return 0, io.EOF
+       }
+
        if err = z.readHeader(false); err != nil {
                z.err = err
                return
index 2471038f53690476f06db1ce68c62e805e7a67d7..0636dec9ab01d208857673d7f8e566444eda9627 100644 (file)
@@ -9,6 +9,7 @@ import (
        "io"
        "io/ioutil"
        "os"
+       "strings"
        "testing"
        "time"
 )
@@ -367,3 +368,43 @@ func TestInitialReset(t *testing.T) {
                t.Errorf("got %q want %q", s, gunzipTests[1].raw)
        }
 }
+
+func TestMultistreamFalse(t *testing.T) {
+       // Find concatenation test.
+       var tt gunzipTest
+       for _, tt = range gunzipTests {
+               if strings.HasSuffix(tt.desc, " x2") {
+                       goto Found
+               }
+       }
+       t.Fatal("cannot find hello.txt x2 in gunzip tests")
+
+Found:
+       br := bytes.NewReader(tt.gzip)
+       var r Reader
+       if err := r.Reset(br); err != nil {
+               t.Fatalf("first reset: %v", err)
+       }
+
+       // Expect two streams with "hello world\n", then real EOF.
+       const hello = "hello world\n"
+
+       r.Multistream(false)
+       data, err := ioutil.ReadAll(&r)
+       if string(data) != hello || err != nil {
+               t.Fatalf("first stream = %q, %v, want %q, %v", string(data), err, hello, nil)
+       }
+
+       if err := r.Reset(br); err != nil {
+               t.Fatalf("second reset: %v", err)
+       }
+       r.Multistream(false)
+       data, err = ioutil.ReadAll(&r)
+       if string(data) != hello || err != nil {
+               t.Fatalf("second stream = %q, %v, want %q, %v", string(data), err, hello, nil)
+       }
+
+       if err := r.Reset(br); err != io.EOF {
+               t.Fatalf("third reset: err=%v, want io.EOF", err)
+       }
+}
index e1191816d6a87af5ce992d615c9e2f613769b639..816f1bf6bd06e73dd24b781a2af8839fb08e25b9 100644 (file)
@@ -51,10 +51,21 @@ type reader struct {
        scratch      [4]byte
 }
 
-// NewReader creates a new io.ReadCloser.
-// Reads from the returned io.ReadCloser read and decompress data from r.
+// Resetter resets a ReadCloser returned by NewReader or NewReaderDict to
+// to switch to a new underlying Reader. This permits reusing a ReadCloser
+// instead of allocating a new one.
+type Resetter interface {
+       // Reset discards any buffered data and resets the Resetter as if it was
+       // newly initialized with the given reader.
+       Reset(r io.Reader, dict []byte) error
+}
+
+// NewReader creates a new ReadCloser.
+// Reads from the returned ReadCloser read and decompress data from r.
 // The implementation buffers input and may read more data than necessary from r.
 // It is the caller's responsibility to call Close on the ReadCloser when done.
+//
+// The ReadCloser returned by NewReader also implements Resetter.
 func NewReader(r io.Reader) (io.ReadCloser, error) {
        return NewReaderDict(r, nil)
 }
@@ -62,35 +73,14 @@ func NewReader(r io.Reader) (io.ReadCloser, error) {
 // NewReaderDict is like NewReader but uses a preset dictionary.
 // NewReaderDict ignores the dictionary if the compressed data does not refer to it.
 // If the compressed data refers to a different dictionary, NewReaderDict returns ErrDictionary.
+//
+// The ReadCloser returned by NewReaderDict also implements Resetter.
 func NewReaderDict(r io.Reader, dict []byte) (io.ReadCloser, error) {
        z := new(reader)
-       if fr, ok := r.(flate.Reader); ok {
-               z.r = fr
-       } else {
-               z.r = bufio.NewReader(r)
-       }
-       _, err := io.ReadFull(z.r, z.scratch[0:2])
+       err := z.Reset(r, dict)
        if err != nil {
                return nil, err
        }
-       h := uint(z.scratch[0])<<8 | uint(z.scratch[1])
-       if (z.scratch[0]&0x0f != zlibDeflate) || (h%31 != 0) {
-               return nil, ErrHeader
-       }
-       if z.scratch[1]&0x20 != 0 {
-               _, err = io.ReadFull(z.r, z.scratch[0:4])
-               if err != nil {
-                       return nil, err
-               }
-               checksum := uint32(z.scratch[0])<<24 | uint32(z.scratch[1])<<16 | uint32(z.scratch[2])<<8 | uint32(z.scratch[3])
-               if checksum != adler32.Checksum(dict) {
-                       return nil, ErrDictionary
-               }
-               z.decompressor = flate.NewReaderDict(z.r, dict)
-       } else {
-               z.decompressor = flate.NewReader(z.r)
-       }
-       z.digest = adler32.New()
        return z, nil
 }
 
@@ -131,3 +121,41 @@ func (z *reader) Close() error {
        z.err = z.decompressor.Close()
        return z.err
 }
+
+func (z *reader) Reset(r io.Reader, dict []byte) error {
+       if fr, ok := r.(flate.Reader); ok {
+               z.r = fr
+       } else {
+               z.r = bufio.NewReader(r)
+       }
+       _, err := io.ReadFull(z.r, z.scratch[0:2])
+       if err != nil {
+               return err
+       }
+       h := uint(z.scratch[0])<<8 | uint(z.scratch[1])
+       if (z.scratch[0]&0x0f != zlibDeflate) || (h%31 != 0) {
+               return ErrHeader
+       }
+       haveDict := z.scratch[1]&0x20 != 0
+       if haveDict {
+               _, err = io.ReadFull(z.r, z.scratch[0:4])
+               if err != nil {
+                       return err
+               }
+               checksum := uint32(z.scratch[0])<<24 | uint32(z.scratch[1])<<16 | uint32(z.scratch[2])<<8 | uint32(z.scratch[3])
+               if checksum != adler32.Checksum(dict) {
+                       return ErrDictionary
+               }
+       }
+       if z.decompressor == nil {
+               if haveDict {
+                       z.decompressor = flate.NewReaderDict(z.r, dict)
+               } else {
+                       z.decompressor = flate.NewReader(z.r)
+               }
+       } else {
+               z.decompressor.(flate.Resetter).Reset(z.r, dict)
+       }
+       z.digest = adler32.New()
+       return nil
+}
index 0856311e4cba288461c0f83ba9d5c18ba99610fa..3de4834d3f5b83ec3165396788345bd6fe612c0b 100644 (file)
@@ -35,6 +35,7 @@ const (
        alertProtocolVersion        alert = 70
        alertInsufficientSecurity   alert = 71
        alertInternalError          alert = 80
+       alertInappropriateFallback  alert = 86
        alertUserCanceled           alert = 90
        alertNoRenegotiation        alert = 100
 )
@@ -60,6 +61,7 @@ var alertText = map[alert]string{
        alertProtocolVersion:        "protocol version not supported",
        alertInsufficientSecurity:   "insufficient security level",
        alertInternalError:          "internal error",
+       alertInappropriateFallback:  "inappropriate fallback",
        alertUserCanceled:           "user canceled",
        alertNoRenegotiation:        "no renegotiation",
 }
index 39a51459d288fc516248af612c6fabb0a8989258..226e06d68d63acb4b314b38210e747565a85f65c 100644 (file)
@@ -267,4 +267,9 @@ const (
        TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA      uint16 = 0xc014
        TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256   uint16 = 0xc02f
        TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02b
+
+       // TLS_FALLBACK_SCSV isn't a standard cipher suite but an indicator
+       // that the client is doing version fallback. See
+       // https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00.
+       TLS_FALLBACK_SCSV uint16 = 0x5600
 )
index 520675dfb5adca445c57dd6d1ff4a36307827719..0d907656c6c20cc0698baaaaa2db1ad2cede83b6 100644 (file)
@@ -224,6 +224,18 @@ Curves:
                return false, errors.New("tls: no cipher suite supported by both client and server")
        }
 
+       // See https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00.
+       for _, id := range hs.clientHello.cipherSuites {
+               if id == TLS_FALLBACK_SCSV {
+                       // The client is doing a fallback connection.
+                       if hs.clientHello.vers < c.config.MaxVersion {
+                               c.sendAlert(alertInappropriateFallback)
+                               return false, errors.New("tls: client using inppropriate protocol fallback")
+                       }
+                       break
+               }
+       }
+
        return false, nil
 }
 
index 580fbc0bfbdb1e6fb8e61acc9336b9bc9bdfd7c4..0338af457ee5f8bedccc9b24c646499fe32857be 100644 (file)
@@ -260,6 +260,9 @@ type serverTest struct {
        // expectAlert, if true, indicates that a fatal alert should be returned
        // when handshaking with the server.
        expectAlert bool
+       // expectHandshakeErrorIncluding, when not empty, contains a string
+       // that must be a substring of the error resulting from the handshake.
+       expectHandshakeErrorIncluding string
        // validate, if not nil, is a function that will be called with the
        // ConnectionState of the resulting connection. It returns false if the
        // ConnectionState is unacceptable.
@@ -362,9 +365,17 @@ func (test *serverTest) run(t *testing.T, write bool) {
        server := Server(serverConn, config)
        connStateChan := make(chan ConnectionState, 1)
        go func() {
-               if _, err := server.Write([]byte("hello, world\n")); err != nil {
+               var err error
+               if _, err = server.Write([]byte("hello, world\n")); err != nil {
                        t.Logf("Error from Server.Write: %s", err)
                }
+               if len(test.expectHandshakeErrorIncluding) > 0 {
+                       if err == nil {
+                               t.Errorf("Error expected, but no error returned")
+                       } else if s := err.Error(); !strings.Contains(s, test.expectHandshakeErrorIncluding) {
+                               t.Errorf("Error expected containing '%s' but got '%s'", test.expectHandshakeErrorIncluding, s)
+                       }
+               }
                server.Close()
                serverConn.Close()
                connStateChan <- server.ConnectionState()
@@ -429,7 +440,9 @@ func (test *serverTest) run(t *testing.T, write bool) {
                recordingConn.Close()
                if len(recordingConn.flows) < 3 {
                        childProcess.Stdout.(*bytes.Buffer).WriteTo(os.Stdout)
-                       t.Fatalf("Handshake failed")
+                       if len(test.expectHandshakeErrorIncluding) == 0 {
+                               t.Fatalf("Handshake failed")
+                       }
                }
                recordingConn.WriteTo(out)
                fmt.Printf("Wrote %s\n", path)
@@ -702,6 +715,16 @@ func TestResumptionDisabled(t *testing.T) {
        // file for ResumeDisabled does not include a resumption handshake.
 }
 
+func TestFallbackSCSV(t *testing.T) {
+       test := &serverTest{
+               name: "FallbackSCSV",
+               // OpenSSL 1.0.1j is needed for the -fallback_scsv option.
+               command: []string{"openssl", "s_client", "-fallback_scsv"},
+               expectHandshakeErrorIncluding: "inppropriate protocol fallback",
+       }
+       runServerTestTLS11(t, test)
+}
+
 // cert.pem and key.pem were generated with generate_cert.go
 // Thus, they have no ExtKeyUsage fields and trigger an error
 // when verification is turned on.
diff --git a/src/crypto/tls/testdata/Server-TLSv11-FallbackSCSV b/src/crypto/tls/testdata/Server-TLSv11-FallbackSCSV
new file mode 100644 (file)
index 0000000..2d8dfbc
--- /dev/null
@@ -0,0 +1,17 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 d4 01 00 00  d0 03 02 74 2d da 6d 98  |...........t-.m.|
+00000010  ad 3e a5 ec 90 ea d1 5b  f0 e0 a7 45 33 d9 5e 8d  |.>.....[...E3.^.|
+00000020  0f 1d 01 16 6d 00 31 65  ed 50 88 00 00 5e c0 14  |....m.1e.P...^..|
+00000030  c0 0a 00 39 00 38 00 88  00 87 c0 0f c0 05 00 35  |...9.8.........5|
+00000040  00 84 c0 13 c0 09 00 33  00 32 00 9a 00 99 00 45  |.......3.2.....E|
+00000050  00 44 c0 0e c0 04 00 2f  00 96 00 41 00 07 c0 11  |.D...../...A....|
+00000060  c0 07 c0 0c c0 02 00 05  00 04 c0 12 c0 08 00 16  |................|
+00000070  00 13 c0 0d c0 03 00 0a  00 15 00 12 00 09 00 14  |................|
+00000080  00 11 00 08 00 06 00 03  00 ff 56 00 01 00 00 49  |..........V....I|
+00000090  00 0b 00 04 03 00 01 02  00 0a 00 34 00 32 00 0e  |...........4.2..|
+000000a0  00 0d 00 19 00 0b 00 0c  00 18 00 09 00 0a 00 16  |................|
+000000b0  00 17 00 08 00 06 00 07  00 14 00 15 00 04 00 05  |................|
+000000c0  00 12 00 13 00 01 00 02  00 03 00 0f 00 10 00 11  |................|
+000000d0  00 23 00 00 00 0f 00 01  01                       |.#.......|
+>>> Flow 2 (server to client)
+00000000  15 03 02 00 02 02 56                              |......V|
index ce6f1408fe98f43e1c2afe516482b9c4dc098928..759e5674fd623de32fcf6e8d8c523179d86492f4 100644 (file)
@@ -13,7 +13,6 @@ import (
        "io"
        "os"
        "strconv"
-       "unsafe"
 )
 
 // A File represents an open PE file.
@@ -125,6 +124,11 @@ func (f *File) Close() error {
        return err
 }
 
+var (
+       sizeofOptionalHeader32 = uint16(binary.Size(OptionalHeader32{}))
+       sizeofOptionalHeader64 = uint16(binary.Size(OptionalHeader64{}))
+)
+
 // NewFile creates a new File for accessing a PE binary in an underlying reader.
 func NewFile(r io.ReaderAt) (*File, error) {
        f := new(File)
@@ -205,8 +209,8 @@ func NewFile(r io.ReaderAt) (*File, error) {
        }
        var oh32 OptionalHeader32
        var oh64 OptionalHeader64
-       switch uintptr(f.FileHeader.SizeOfOptionalHeader) {
-       case unsafe.Sizeof(oh32):
+       switch f.FileHeader.SizeOfOptionalHeader {
+       case sizeofOptionalHeader32:
                if err := binary.Read(sr, binary.LittleEndian, &oh32); err != nil {
                        return nil, err
                }
@@ -214,7 +218,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
                        return nil, fmt.Errorf("pe32 optional header has unexpected Magic of 0x%x", oh32.Magic)
                }
                f.OptionalHeader = &oh32
-       case unsafe.Sizeof(oh64):
+       case sizeofOptionalHeader64:
                if err := binary.Read(sr, binary.LittleEndian, &oh64); err != nil {
                        return nil, err
                }
index 1faecb6648061986846062a472c72908844d1e4e..17e7bb7f5c79bf53f5693a36538d3f6efc1c695f 100644 (file)
@@ -115,10 +115,22 @@ func (w *Writer) WriteAll(records [][]string) (err error) {
 }
 
 // fieldNeedsQuotes returns true if our field must be enclosed in quotes.
-// Empty fields, files with a Comma, fields with a quote or newline, and
+// Fields with a Comma, fields with a quote or newline, and
 // fields which start with a space must be enclosed in quotes.
+// We used to quote empty strings, but we do not anymore (as of Go 1.4).
+// The two representations should be equivalent, but Postgres distinguishes
+// quoted vs non-quoted empty string during database imports, and it has
+// an option to force the quoted behavior for non-quoted CSV but it has
+// no option to force the non-quoted behavior for quoted CSV, making
+// CSV with quoted empty strings strictly less useful.
+// Not quoting the empty string also makes this package match the behavior
+// of Microsoft Excel and Google Drive.
+// For Postgres, quote the data termating string `\.`.
 func (w *Writer) fieldNeedsQuotes(field string) bool {
-       if len(field) == 0 || strings.IndexRune(field, w.Comma) >= 0 || strings.IndexAny(field, "\"\r\n") >= 0 {
+       if field == "" {
+               return false
+       }
+       if field == `\.` || strings.IndexRune(field, w.Comma) >= 0 || strings.IndexAny(field, "\"\r\n") >= 0 {
                return true
        }
 
index 22b740c0745297edf0db0da8f9561846b04e7276..8ddca0abe0c13f09e13bc4a30718d09d17829541 100644 (file)
@@ -28,6 +28,17 @@ var writeTests = []struct {
        {Input: [][]string{{"abc\ndef"}}, Output: "\"abc\r\ndef\"\r\n", UseCRLF: true},
        {Input: [][]string{{"abc\rdef"}}, Output: "\"abcdef\"\r\n", UseCRLF: true},
        {Input: [][]string{{"abc\rdef"}}, Output: "\"abc\rdef\"\n", UseCRLF: false},
+       {Input: [][]string{{""}}, Output: "\n"},
+       {Input: [][]string{{"", ""}}, Output: ",\n"},
+       {Input: [][]string{{"", "", ""}}, Output: ",,\n"},
+       {Input: [][]string{{"", "", "a"}}, Output: ",,a\n"},
+       {Input: [][]string{{"", "a", ""}}, Output: ",a,\n"},
+       {Input: [][]string{{"", "a", "a"}}, Output: ",a,a\n"},
+       {Input: [][]string{{"a", "", ""}}, Output: "a,,\n"},
+       {Input: [][]string{{"a", "", "a"}}, Output: "a,,a\n"},
+       {Input: [][]string{{"a", "a", ""}}, Output: "a,a,\n"},
+       {Input: [][]string{{"a", "a", "a"}}, Output: "a,a,a\n"},
+       {Input: [][]string{{`\.`}}, Output: "\"\\.\"\n"},
 }
 
 func TestWrite(t *testing.T) {
index 4f17a28931d85b77de5b1c4d3f09cd86cc411f94..56a7298fa5583603fa22c68423850830c714eba0 100644 (file)
@@ -50,10 +50,16 @@ func testError(t *testing.T) {
        return
 }
 
+func newDecBuffer(data []byte) *decBuffer {
+       return &decBuffer{
+               data: data,
+       }
+}
+
 // Test basic encode/decode routines for unsigned integers
 func TestUintCodec(t *testing.T) {
        defer testError(t)
-       b := new(bytes.Buffer)
+       b := new(encBuffer)
        encState := newEncoderState(b)
        for _, tt := range encodeT {
                b.Reset()
@@ -62,10 +68,10 @@ func TestUintCodec(t *testing.T) {
                        t.Errorf("encodeUint: %#x encode: expected % x got % x", tt.x, tt.b, b.Bytes())
                }
        }
-       decState := newDecodeState(b)
        for u := uint64(0); ; u = (u + 1) * 7 {
                b.Reset()
                encState.encodeUint(u)
+               decState := newDecodeState(newDecBuffer(b.Bytes()))
                v := decState.decodeUint()
                if u != v {
                        t.Errorf("Encode/Decode: sent %#x received %#x", u, v)
@@ -78,10 +84,10 @@ func TestUintCodec(t *testing.T) {
 
 func verifyInt(i int64, t *testing.T) {
        defer testError(t)
-       var b = new(bytes.Buffer)
+       var b = new(encBuffer)
        encState := newEncoderState(b)
        encState.encodeInt(i)
-       decState := newDecodeState(b)
+       decState := newDecodeState(newDecBuffer(b.Bytes()))
        decState.buf = make([]byte, 8)
        j := decState.decodeInt()
        if i != j {
@@ -118,14 +124,14 @@ var complexResult = []byte{0x07, 0xFE, 0x31, 0x40, 0xFE, 0x33, 0x40}
 // The result of encoding "hello" with field number 7
 var bytesResult = []byte{0x07, 0x05, 'h', 'e', 'l', 'l', 'o'}
 
-func newDecodeState(buf *bytes.Buffer) *decoderState {
+func newDecodeState(buf *decBuffer) *decoderState {
        d := new(decoderState)
        d.b = buf
        d.buf = make([]byte, uint64Size)
        return d
 }
 
-func newEncoderState(b *bytes.Buffer) *encoderState {
+func newEncoderState(b *encBuffer) *encoderState {
        b.Reset()
        state := &encoderState{enc: nil, b: b}
        state.fieldnum = -1
@@ -135,7 +141,7 @@ func newEncoderState(b *bytes.Buffer) *encoderState {
 // Test instruction execution for encoding.
 // Do not run the machine yet; instead do individual instructions crafted by hand.
 func TestScalarEncInstructions(t *testing.T) {
-       var b = new(bytes.Buffer)
+       var b = new(encBuffer)
 
        // bool
        {
@@ -328,7 +334,7 @@ func execDec(typ string, instr *decInstr, state *decoderState, t *testing.T, val
 }
 
 func newDecodeStateFromData(data []byte) *decoderState {
-       b := bytes.NewBuffer(data)
+       b := newDecBuffer(data)
        state := newDecodeState(b)
        state.fieldnum = -1
        return state
diff --git a/src/encoding/gob/dec_helpers.go b/src/encoding/gob/dec_helpers.go
new file mode 100644 (file)
index 0000000..a1b6766
--- /dev/null
@@ -0,0 +1,468 @@
+// Created by decgen --output dec_helpers.go; DO NOT EDIT
+
+// Copyright 2014 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 gob
+
+import (
+       "math"
+       "reflect"
+)
+
+var decArrayHelper = map[reflect.Kind]decHelper{
+       reflect.Bool:       decBoolArray,
+       reflect.Complex64:  decComplex64Array,
+       reflect.Complex128: decComplex128Array,
+       reflect.Float32:    decFloat32Array,
+       reflect.Float64:    decFloat64Array,
+       reflect.Int:        decIntArray,
+       reflect.Int16:      decInt16Array,
+       reflect.Int32:      decInt32Array,
+       reflect.Int64:      decInt64Array,
+       reflect.Int8:       decInt8Array,
+       reflect.String:     decStringArray,
+       reflect.Uint:       decUintArray,
+       reflect.Uint16:     decUint16Array,
+       reflect.Uint32:     decUint32Array,
+       reflect.Uint64:     decUint64Array,
+       reflect.Uintptr:    decUintptrArray,
+}
+
+var decSliceHelper = map[reflect.Kind]decHelper{
+       reflect.Bool:       decBoolSlice,
+       reflect.Complex64:  decComplex64Slice,
+       reflect.Complex128: decComplex128Slice,
+       reflect.Float32:    decFloat32Slice,
+       reflect.Float64:    decFloat64Slice,
+       reflect.Int:        decIntSlice,
+       reflect.Int16:      decInt16Slice,
+       reflect.Int32:      decInt32Slice,
+       reflect.Int64:      decInt64Slice,
+       reflect.Int8:       decInt8Slice,
+       reflect.String:     decStringSlice,
+       reflect.Uint:       decUintSlice,
+       reflect.Uint16:     decUint16Slice,
+       reflect.Uint32:     decUint32Slice,
+       reflect.Uint64:     decUint64Slice,
+       reflect.Uintptr:    decUintptrSlice,
+}
+
+func decBoolArray(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return decBoolSlice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decBoolSlice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       slice, ok := v.Interface().([]bool)
+       if !ok {
+               // It is kind bool but not type bool. TODO: We can handle this unsafely.
+               return false
+       }
+       for i := 0; i < length; i++ {
+               if state.b.Len() == 0 {
+                       errorf("decoding bool array or slice: length exceeds input size (%d elements)", length)
+               }
+               slice[i] = state.decodeUint() != 0
+       }
+       return true
+}
+
+func decComplex64Array(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return decComplex64Slice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decComplex64Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       slice, ok := v.Interface().([]complex64)
+       if !ok {
+               // It is kind complex64 but not type complex64. TODO: We can handle this unsafely.
+               return false
+       }
+       for i := 0; i < length; i++ {
+               if state.b.Len() == 0 {
+                       errorf("decoding complex64 array or slice: length exceeds input size (%d elements)", length)
+               }
+               real := float32FromBits(state.decodeUint(), ovfl)
+               imag := float32FromBits(state.decodeUint(), ovfl)
+               slice[i] = complex(float32(real), float32(imag))
+       }
+       return true
+}
+
+func decComplex128Array(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return decComplex128Slice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decComplex128Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       slice, ok := v.Interface().([]complex128)
+       if !ok {
+               // It is kind complex128 but not type complex128. TODO: We can handle this unsafely.
+               return false
+       }
+       for i := 0; i < length; i++ {
+               if state.b.Len() == 0 {
+                       errorf("decoding complex128 array or slice: length exceeds input size (%d elements)", length)
+               }
+               real := float64FromBits(state.decodeUint())
+               imag := float64FromBits(state.decodeUint())
+               slice[i] = complex(real, imag)
+       }
+       return true
+}
+
+func decFloat32Array(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return decFloat32Slice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decFloat32Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       slice, ok := v.Interface().([]float32)
+       if !ok {
+               // It is kind float32 but not type float32. TODO: We can handle this unsafely.
+               return false
+       }
+       for i := 0; i < length; i++ {
+               if state.b.Len() == 0 {
+                       errorf("decoding float32 array or slice: length exceeds input size (%d elements)", length)
+               }
+               slice[i] = float32(float32FromBits(state.decodeUint(), ovfl))
+       }
+       return true
+}
+
+func decFloat64Array(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return decFloat64Slice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decFloat64Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       slice, ok := v.Interface().([]float64)
+       if !ok {
+               // It is kind float64 but not type float64. TODO: We can handle this unsafely.
+               return false
+       }
+       for i := 0; i < length; i++ {
+               if state.b.Len() == 0 {
+                       errorf("decoding float64 array or slice: length exceeds input size (%d elements)", length)
+               }
+               slice[i] = float64FromBits(state.decodeUint())
+       }
+       return true
+}
+
+func decIntArray(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return decIntSlice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decIntSlice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       slice, ok := v.Interface().([]int)
+       if !ok {
+               // It is kind int but not type int. TODO: We can handle this unsafely.
+               return false
+       }
+       for i := 0; i < length; i++ {
+               if state.b.Len() == 0 {
+                       errorf("decoding int array or slice: length exceeds input size (%d elements)", length)
+               }
+               x := state.decodeInt()
+               // MinInt and MaxInt
+               if x < ^int64(^uint(0)>>1) || int64(^uint(0)>>1) < x {
+                       error_(ovfl)
+               }
+               slice[i] = int(x)
+       }
+       return true
+}
+
+func decInt16Array(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return decInt16Slice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decInt16Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       slice, ok := v.Interface().([]int16)
+       if !ok {
+               // It is kind int16 but not type int16. TODO: We can handle this unsafely.
+               return false
+       }
+       for i := 0; i < length; i++ {
+               if state.b.Len() == 0 {
+                       errorf("decoding int16 array or slice: length exceeds input size (%d elements)", length)
+               }
+               x := state.decodeInt()
+               if x < math.MinInt16 || math.MaxInt16 < x {
+                       error_(ovfl)
+               }
+               slice[i] = int16(x)
+       }
+       return true
+}
+
+func decInt32Array(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return decInt32Slice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decInt32Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       slice, ok := v.Interface().([]int32)
+       if !ok {
+               // It is kind int32 but not type int32. TODO: We can handle this unsafely.
+               return false
+       }
+       for i := 0; i < length; i++ {
+               if state.b.Len() == 0 {
+                       errorf("decoding int32 array or slice: length exceeds input size (%d elements)", length)
+               }
+               x := state.decodeInt()
+               if x < math.MinInt32 || math.MaxInt32 < x {
+                       error_(ovfl)
+               }
+               slice[i] = int32(x)
+       }
+       return true
+}
+
+func decInt64Array(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return decInt64Slice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decInt64Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       slice, ok := v.Interface().([]int64)
+       if !ok {
+               // It is kind int64 but not type int64. TODO: We can handle this unsafely.
+               return false
+       }
+       for i := 0; i < length; i++ {
+               if state.b.Len() == 0 {
+                       errorf("decoding int64 array or slice: length exceeds input size (%d elements)", length)
+               }
+               slice[i] = state.decodeInt()
+       }
+       return true
+}
+
+func decInt8Array(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return decInt8Slice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decInt8Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       slice, ok := v.Interface().([]int8)
+       if !ok {
+               // It is kind int8 but not type int8. TODO: We can handle this unsafely.
+               return false
+       }
+       for i := 0; i < length; i++ {
+               if state.b.Len() == 0 {
+                       errorf("decoding int8 array or slice: length exceeds input size (%d elements)", length)
+               }
+               x := state.decodeInt()
+               if x < math.MinInt8 || math.MaxInt8 < x {
+                       error_(ovfl)
+               }
+               slice[i] = int8(x)
+       }
+       return true
+}
+
+func decStringArray(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return decStringSlice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decStringSlice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       slice, ok := v.Interface().([]string)
+       if !ok {
+               // It is kind string but not type string. TODO: We can handle this unsafely.
+               return false
+       }
+       for i := 0; i < length; i++ {
+               if state.b.Len() == 0 {
+                       errorf("decoding string array or slice: length exceeds input size (%d elements)", length)
+               }
+               u := state.decodeUint()
+               n := int(u)
+               if n < 0 || uint64(n) != u || n > state.b.Len() {
+                       errorf("length of string exceeds input size (%d bytes)", u)
+               }
+               if n > state.b.Len() {
+                       errorf("string data too long for buffer: %d", n)
+               }
+               // Read the data.
+               data := make([]byte, n)
+               if _, err := state.b.Read(data); err != nil {
+                       errorf("error decoding string: %s", err)
+               }
+               slice[i] = string(data)
+       }
+       return true
+}
+
+func decUintArray(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return decUintSlice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decUintSlice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       slice, ok := v.Interface().([]uint)
+       if !ok {
+               // It is kind uint but not type uint. TODO: We can handle this unsafely.
+               return false
+       }
+       for i := 0; i < length; i++ {
+               if state.b.Len() == 0 {
+                       errorf("decoding uint array or slice: length exceeds input size (%d elements)", length)
+               }
+               x := state.decodeUint()
+               /*TODO if math.MaxUint32 < x {
+                       error_(ovfl)
+               }*/
+               slice[i] = uint(x)
+       }
+       return true
+}
+
+func decUint16Array(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return decUint16Slice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decUint16Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       slice, ok := v.Interface().([]uint16)
+       if !ok {
+               // It is kind uint16 but not type uint16. TODO: We can handle this unsafely.
+               return false
+       }
+       for i := 0; i < length; i++ {
+               if state.b.Len() == 0 {
+                       errorf("decoding uint16 array or slice: length exceeds input size (%d elements)", length)
+               }
+               x := state.decodeUint()
+               if math.MaxUint16 < x {
+                       error_(ovfl)
+               }
+               slice[i] = uint16(x)
+       }
+       return true
+}
+
+func decUint32Array(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return decUint32Slice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decUint32Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       slice, ok := v.Interface().([]uint32)
+       if !ok {
+               // It is kind uint32 but not type uint32. TODO: We can handle this unsafely.
+               return false
+       }
+       for i := 0; i < length; i++ {
+               if state.b.Len() == 0 {
+                       errorf("decoding uint32 array or slice: length exceeds input size (%d elements)", length)
+               }
+               x := state.decodeUint()
+               if math.MaxUint32 < x {
+                       error_(ovfl)
+               }
+               slice[i] = uint32(x)
+       }
+       return true
+}
+
+func decUint64Array(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return decUint64Slice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decUint64Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       slice, ok := v.Interface().([]uint64)
+       if !ok {
+               // It is kind uint64 but not type uint64. TODO: We can handle this unsafely.
+               return false
+       }
+       for i := 0; i < length; i++ {
+               if state.b.Len() == 0 {
+                       errorf("decoding uint64 array or slice: length exceeds input size (%d elements)", length)
+               }
+               slice[i] = state.decodeUint()
+       }
+       return true
+}
+
+func decUintptrArray(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return decUintptrSlice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+
+func decUintptrSlice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       slice, ok := v.Interface().([]uintptr)
+       if !ok {
+               // It is kind uintptr but not type uintptr. TODO: We can handle this unsafely.
+               return false
+       }
+       for i := 0; i < length; i++ {
+               if state.b.Len() == 0 {
+                       errorf("decoding uintptr array or slice: length exceeds input size (%d elements)", length)
+               }
+               x := state.decodeUint()
+               if uint64(^uintptr(0)) < x {
+                       error_(ovfl)
+               }
+               slice[i] = uintptr(x)
+       }
+       return true
+}
diff --git a/src/encoding/gob/decgen.go b/src/encoding/gob/decgen.go
new file mode 100644 (file)
index 0000000..da41a89
--- /dev/null
@@ -0,0 +1,240 @@
+// Copyright 2009 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.
+
+// +build ignore
+
+// encgen writes the helper functions for encoding. Intended to be
+// used with go generate; see the invocation in encode.go.
+
+// TODO: We could do more by being unsafe. Add a -unsafe flag?
+
+package main
+
+import (
+       "bytes"
+       "flag"
+       "fmt"
+       "go/format"
+       "log"
+       "os"
+)
+
+var output = flag.String("output", "dec_helpers.go", "file name to write")
+
+type Type struct {
+       lower   string
+       upper   string
+       decoder string
+}
+
+var types = []Type{
+       {
+               "bool",
+               "Bool",
+               `slice[i] = state.decodeUint() != 0`,
+       },
+       {
+               "complex64",
+               "Complex64",
+               `real := float32FromBits(state.decodeUint(), ovfl)
+               imag := float32FromBits(state.decodeUint(), ovfl)
+               slice[i] = complex(float32(real), float32(imag))`,
+       },
+       {
+               "complex128",
+               "Complex128",
+               `real := float64FromBits(state.decodeUint())
+               imag := float64FromBits(state.decodeUint())
+               slice[i] = complex(real, imag)`,
+       },
+       {
+               "float32",
+               "Float32",
+               `slice[i] = float32(float32FromBits(state.decodeUint(), ovfl))`,
+       },
+       {
+               "float64",
+               "Float64",
+               `slice[i] = float64FromBits(state.decodeUint())`,
+       },
+       {
+               "int",
+               "Int",
+               `x := state.decodeInt()
+               // MinInt and MaxInt
+               if x < ^int64(^uint(0)>>1) || int64(^uint(0)>>1) < x {
+                       error_(ovfl)
+               }
+               slice[i] = int(x)`,
+       },
+       {
+               "int16",
+               "Int16",
+               `x := state.decodeInt()
+               if x < math.MinInt16 || math.MaxInt16 < x {
+                       error_(ovfl)
+               }
+               slice[i] = int16(x)`,
+       },
+       {
+               "int32",
+               "Int32",
+               `x := state.decodeInt()
+               if x < math.MinInt32 || math.MaxInt32 < x {
+                       error_(ovfl)
+               }
+               slice[i] = int32(x)`,
+       },
+       {
+               "int64",
+               "Int64",
+               `slice[i] = state.decodeInt()`,
+       },
+       {
+               "int8",
+               "Int8",
+               `x := state.decodeInt()
+               if x < math.MinInt8 || math.MaxInt8 < x {
+                       error_(ovfl)
+               }
+               slice[i] = int8(x)`,
+       },
+       {
+               "string",
+               "String",
+               `u := state.decodeUint()
+               n := int(u)
+               if n < 0 || uint64(n) != u || n > state.b.Len() {
+                       errorf("length of string exceeds input size (%d bytes)", u)
+               }
+               if n > state.b.Len() {
+                       errorf("string data too long for buffer: %d", n)
+               }
+               // Read the data.
+               data := make([]byte, n)
+               if _, err := state.b.Read(data); err != nil {
+                       errorf("error decoding string: %s", err)
+               }
+               slice[i] = string(data)`,
+       },
+       {
+               "uint",
+               "Uint",
+               `x := state.decodeUint()
+               /*TODO if math.MaxUint32 < x {
+                       error_(ovfl)
+               }*/
+               slice[i] = uint(x)`,
+       },
+       {
+               "uint16",
+               "Uint16",
+               `x := state.decodeUint()
+               if math.MaxUint16 < x {
+                       error_(ovfl)
+               }
+               slice[i] = uint16(x)`,
+       },
+       {
+               "uint32",
+               "Uint32",
+               `x := state.decodeUint()
+               if math.MaxUint32 < x {
+                       error_(ovfl)
+               }
+               slice[i] = uint32(x)`,
+       },
+       {
+               "uint64",
+               "Uint64",
+               `slice[i] = state.decodeUint()`,
+       },
+       {
+               "uintptr",
+               "Uintptr",
+               `x := state.decodeUint()
+               if uint64(^uintptr(0)) < x {
+                       error_(ovfl)
+               }
+               slice[i] = uintptr(x)`,
+       },
+       // uint8 Handled separately.
+}
+
+func main() {
+       log.SetFlags(0)
+       log.SetPrefix("decgen: ")
+       flag.Parse()
+       if flag.NArg() != 0 {
+               log.Fatal("usage: decgen [--output filename]")
+       }
+       var b bytes.Buffer
+       fmt.Fprintf(&b, "// Created by decgen --output %s; DO NOT EDIT\n", *output)
+       fmt.Fprint(&b, header)
+       printMaps(&b, "Array")
+       fmt.Fprint(&b, "\n")
+       printMaps(&b, "Slice")
+       for _, t := range types {
+               fmt.Fprintf(&b, arrayHelper, t.lower, t.upper)
+               fmt.Fprintf(&b, sliceHelper, t.lower, t.upper, t.decoder)
+       }
+       source, err := format.Source(b.Bytes())
+       if err != nil {
+               log.Fatal("source format error:", err)
+       }
+       fd, err := os.Create(*output)
+       _, err = fd.Write(source)
+       if err != nil {
+               log.Fatal(err)
+       }
+}
+
+func printMaps(b *bytes.Buffer, upperClass string) {
+       fmt.Fprintf(b, "var dec%sHelper = map[reflect.Kind]decHelper{\n", upperClass)
+       for _, t := range types {
+               fmt.Fprintf(b, "reflect.%s: dec%s%s,\n", t.upper, t.upper, upperClass)
+       }
+       fmt.Fprintf(b, "}\n")
+}
+
+const header = `
+// Copyright 2014 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 gob
+
+import (
+       "math"
+       "reflect"
+)
+
+`
+
+const arrayHelper = `
+func dec%[2]sArray(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return dec%[2]sSlice(state, v.Slice(0, v.Len()), length, ovfl)
+}
+`
+
+const sliceHelper = `
+func dec%[2]sSlice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
+       slice, ok := v.Interface().([]%[1]s)
+       if !ok {
+               // It is kind %[1]s but not type %[1]s. TODO: We can handle this unsafely.
+               return false
+       }
+       for i := 0; i < length; i++ {
+               if state.b.Len() == 0 {
+                       errorf("decoding %[1]s array or slice: length exceeds input size (%%d elements)", length)
+               }
+               %[3]s
+       }
+       return true
+}
+`
index 6a9213fb3cb6c7f8dcb21efafaee1de4006ca1d3..a5bef93141b7adf29796a2276f1c83a45e40ece0 100644 (file)
@@ -2,10 +2,11 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+//go:generate go run decgen.go -output dec_helpers.go
+
 package gob
 
 import (
-       "bytes"
        "encoding"
        "errors"
        "io"
@@ -19,21 +20,79 @@ var (
        errRange   = errors.New("gob: bad data: field numbers out of bounds")
 )
 
+type decHelper func(state *decoderState, v reflect.Value, length int, ovfl error) bool
+
 // decoderState is the execution state of an instance of the decoder. A new state
 // is created for nested objects.
 type decoderState struct {
        dec *Decoder
        // The buffer is stored with an extra indirection because it may be replaced
        // if we load a type during decode (when reading an interface value).
-       b        *bytes.Buffer
+       b        *decBuffer
        fieldnum int // the last field number read.
        buf      []byte
        next     *decoderState // for free list
 }
 
+// decBuffer is an extremely simple, fast implementation of a read-only byte buffer.
+// It is initialized by calling Size and then copying the data into the slice returned by Bytes().
+type decBuffer struct {
+       data   []byte
+       offset int // Read offset.
+}
+
+func (d *decBuffer) Read(p []byte) (int, error) {
+       n := copy(p, d.data[d.offset:])
+       if n == 0 && len(p) != 0 {
+               return 0, io.EOF
+       }
+       d.offset += n
+       return n, nil
+}
+
+func (d *decBuffer) Drop(n int) {
+       if n > d.Len() {
+               panic("drop")
+       }
+       d.offset += n
+}
+
+// Size grows the buffer to exactly n bytes, so d.Bytes() will
+// return a slice of length n. Existing data is first discarded.
+func (d *decBuffer) Size(n int) {
+       d.Reset()
+       if cap(d.data) < n {
+               d.data = make([]byte, n)
+       } else {
+               d.data = d.data[0:n]
+       }
+}
+
+func (d *decBuffer) ReadByte() (byte, error) {
+       if d.offset >= len(d.data) {
+               return 0, io.EOF
+       }
+       c := d.data[d.offset]
+       d.offset++
+       return c, nil
+}
+
+func (d *decBuffer) Len() int {
+       return len(d.data) - d.offset
+}
+
+func (d *decBuffer) Bytes() []byte {
+       return d.data[d.offset:]
+}
+
+func (d *decBuffer) Reset() {
+       d.data = d.data[0:0]
+       d.offset = 0
+}
+
 // We pass the bytes.Buffer separately for easier testing of the infrastructure
 // without requiring a full Decoder.
-func (dec *Decoder) newDecoderState(buf *bytes.Buffer) *decoderState {
+func (dec *Decoder) newDecoderState(buf *decBuffer) *decoderState {
        d := dec.freeList
        if d == nil {
                d = new(decoderState)
@@ -257,7 +316,7 @@ func float64FromBits(u uint64) float64 {
 // number, and returns it. It's a helper function for float32 and complex64.
 // It returns a float64 because that's what reflection needs, but its return
 // value is known to be accurately representable in a float32.
-func float32FromBits(i *decInstr, u uint64) float64 {
+func float32FromBits(u uint64, ovfl error) float64 {
        v := float64FromBits(u)
        av := v
        if av < 0 {
@@ -265,7 +324,7 @@ func float32FromBits(i *decInstr, u uint64) float64 {
        }
        // +Inf is OK in both 32- and 64-bit floats.  Underflow is always OK.
        if math.MaxFloat32 < av && av <= math.MaxFloat64 {
-               error_(i.ovfl)
+               error_(ovfl)
        }
        return v
 }
@@ -273,7 +332,7 @@ func float32FromBits(i *decInstr, u uint64) float64 {
 // decFloat32 decodes an unsigned integer, treats it as a 32-bit floating-point
 // number, and stores it in value.
 func decFloat32(i *decInstr, state *decoderState, value reflect.Value) {
-       value.SetFloat(float32FromBits(i, state.decodeUint()))
+       value.SetFloat(float32FromBits(state.decodeUint(), i.ovfl))
 }
 
 // decFloat64 decodes an unsigned integer, treats it as a 64-bit floating-point
@@ -286,8 +345,8 @@ func decFloat64(i *decInstr, state *decoderState, value reflect.Value) {
 // pair of floating point numbers, and stores them as a complex64 in value.
 // The real part comes first.
 func decComplex64(i *decInstr, state *decoderState, value reflect.Value) {
-       real := float32FromBits(i, state.decodeUint())
-       imag := float32FromBits(i, state.decodeUint())
+       real := float32FromBits(state.decodeUint(), i.ovfl)
+       imag := float32FromBits(state.decodeUint(), i.ovfl)
        value.SetComplex(complex(real, imag))
 }
 
@@ -450,7 +509,10 @@ func (dec *Decoder) ignoreSingle(engine *decEngine) {
 }
 
 // decodeArrayHelper does the work for decoding arrays and slices.
-func (dec *Decoder) decodeArrayHelper(state *decoderState, value reflect.Value, elemOp decOp, length int, ovfl error) {
+func (dec *Decoder) decodeArrayHelper(state *decoderState, value reflect.Value, elemOp decOp, length int, ovfl error, helper decHelper) {
+       if helper != nil && helper(state, value, length, ovfl) {
+               return
+       }
        instr := &decInstr{elemOp, 0, nil, ovfl}
        isPtr := value.Type().Elem().Kind() == reflect.Ptr
        for i := 0; i < length; i++ {
@@ -468,11 +530,11 @@ func (dec *Decoder) decodeArrayHelper(state *decoderState, value reflect.Value,
 // decodeArray decodes an array and stores it in value.
 // The length is an unsigned integer preceding the elements.  Even though the length is redundant
 // (it's part of the type), it's a useful check and is included in the encoding.
-func (dec *Decoder) decodeArray(atyp reflect.Type, state *decoderState, value reflect.Value, elemOp decOp, length int, ovfl error) {
+func (dec *Decoder) decodeArray(atyp reflect.Type, state *decoderState, value reflect.Value, elemOp decOp, length int, ovfl error, helper decHelper) {
        if n := state.decodeUint(); n != uint64(length) {
                errorf("length mismatch in decodeArray")
        }
-       dec.decodeArrayHelper(state, value, elemOp, length, ovfl)
+       dec.decodeArrayHelper(state, value, elemOp, length, ovfl, helper)
 }
 
 // decodeIntoValue is a helper for map decoding.
@@ -534,7 +596,7 @@ func (dec *Decoder) ignoreMap(state *decoderState, keyOp, elemOp decOp) {
 
 // decodeSlice decodes a slice and stores it in value.
 // Slices are encoded as an unsigned length followed by the elements.
-func (dec *Decoder) decodeSlice(state *decoderState, value reflect.Value, elemOp decOp, ovfl error) {
+func (dec *Decoder) decodeSlice(state *decoderState, value reflect.Value, elemOp decOp, ovfl error, helper decHelper) {
        u := state.decodeUint()
        typ := value.Type()
        size := uint64(typ.Elem().Size())
@@ -551,7 +613,7 @@ func (dec *Decoder) decodeSlice(state *decoderState, value reflect.Value, elemOp
        } else {
                value.Set(value.Slice(0, n))
        }
-       dec.decodeArrayHelper(state, value, elemOp, n, ovfl)
+       dec.decodeArrayHelper(state, value, elemOp, n, ovfl, helper)
 }
 
 // ignoreSlice skips over the data for a slice value with no destination.
@@ -626,7 +688,7 @@ func (dec *Decoder) ignoreInterface(state *decoderState) {
                error_(dec.err)
        }
        // At this point, the decoder buffer contains a delimited value. Just toss it.
-       state.b.Next(int(state.decodeUint()))
+       state.b.Drop(int(state.decodeUint()))
 }
 
 // decodeGobDecoder decodes something implementing the GobDecoder interface.
@@ -720,8 +782,9 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg
                        elemId := dec.wireType[wireId].ArrayT.Elem
                        elemOp := dec.decOpFor(elemId, t.Elem(), name, inProgress)
                        ovfl := overflow(name)
+                       helper := decArrayHelper[t.Elem().Kind()]
                        op = func(i *decInstr, state *decoderState, value reflect.Value) {
-                               state.dec.decodeArray(t, state, value, *elemOp, t.Len(), ovfl)
+                               state.dec.decodeArray(t, state, value, *elemOp, t.Len(), ovfl, helper)
                        }
 
                case reflect.Map:
@@ -748,8 +811,9 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg
                        }
                        elemOp := dec.decOpFor(elemId, t.Elem(), name, inProgress)
                        ovfl := overflow(name)
+                       helper := decSliceHelper[t.Elem().Kind()]
                        op = func(i *decInstr, state *decoderState, value reflect.Value) {
-                               state.dec.decodeSlice(state, value, *elemOp, ovfl)
+                               state.dec.decodeSlice(state, value, *elemOp, ovfl, helper)
                        }
 
                case reflect.Struct:
index dcad7a0e480d07bb42b98caed2d3259aeb24e6e8..c453e9ba397d3c568d05116a5d4398be1d555bcb 100644 (file)
@@ -6,7 +6,6 @@ package gob
 
 import (
        "bufio"
-       "bytes"
        "errors"
        "io"
        "reflect"
@@ -23,13 +22,12 @@ const tooBig = 1 << 30
 type Decoder struct {
        mutex        sync.Mutex                              // each item must be received atomically
        r            io.Reader                               // source of the data
-       buf          bytes.Buffer                            // buffer for more efficient i/o from r
+       buf          decBuffer                               // buffer for more efficient i/o from r
        wireType     map[typeId]*wireType                    // map from remote ID to local description
        decoderCache map[reflect.Type]map[typeId]**decEngine // cache of compiled engines
        ignorerCache map[typeId]**decEngine                  // ditto for ignored objects
        freeList     *decoderState                           // list of free decoderStates; avoids reallocation
        countBuf     []byte                                  // used for decoding integers while parsing messages
-       tmp          []byte                                  // temporary storage for i/o; saves reallocating
        err          error
 }
 
@@ -90,37 +88,17 @@ func (dec *Decoder) recvMessage() bool {
 
 // readMessage reads the next nbytes bytes from the input.
 func (dec *Decoder) readMessage(nbytes int) {
-       // Allocate the dec.tmp buffer, up to 10KB.
-       const maxBuf = 10 * 1024
-       nTmp := nbytes
-       if nTmp > maxBuf {
-               nTmp = maxBuf
+       if dec.buf.Len() != 0 {
+               // The buffer should always be empty now.
+               panic("non-empty decoder buffer")
        }
-       if cap(dec.tmp) < nTmp {
-               nAlloc := nTmp + 100 // A little extra for growth.
-               if nAlloc > maxBuf {
-                       nAlloc = maxBuf
-               }
-               dec.tmp = make([]byte, nAlloc)
-       }
-       dec.tmp = dec.tmp[:nTmp]
-
        // Read the data
-       dec.buf.Grow(nbytes)
-       for nbytes > 0 {
-               if nbytes < nTmp {
-                       dec.tmp = dec.tmp[:nbytes]
-               }
-               var nRead int
-               nRead, dec.err = io.ReadFull(dec.r, dec.tmp)
-               if dec.err != nil {
-                       if dec.err == io.EOF {
-                               dec.err = io.ErrUnexpectedEOF
-                       }
-                       return
+       dec.buf.Size(nbytes)
+       _, dec.err = io.ReadFull(dec.r, dec.buf.Bytes())
+       if dec.err != nil {
+               if dec.err == io.EOF {
+                       dec.err = io.ErrUnexpectedEOF
                }
-               dec.buf.Write(dec.tmp)
-               nbytes -= nRead
        }
 }
 
@@ -212,7 +190,7 @@ func (dec *Decoder) Decode(e interface{}) error {
 // Otherwise, it stores the value into v.  In that case, v must represent
 // a non-nil pointer to data or be an assignable reflect.Value (v.CanSet())
 // If the input is at EOF, DecodeValue returns io.EOF and
-// does not modify e.
+// does not modify v.
 func (dec *Decoder) DecodeValue(v reflect.Value) error {
        if v.IsValid() {
                if v.Kind() == reflect.Ptr && !v.IsNil() {
diff --git a/src/encoding/gob/enc_helpers.go b/src/encoding/gob/enc_helpers.go
new file mode 100644 (file)
index 0000000..804e539
--- /dev/null
@@ -0,0 +1,414 @@
+// Created by encgen --output enc_helpers.go; DO NOT EDIT
+
+// Copyright 2014 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 gob
+
+import (
+       "reflect"
+)
+
+var encArrayHelper = map[reflect.Kind]encHelper{
+       reflect.Bool:       encBoolArray,
+       reflect.Complex64:  encComplex64Array,
+       reflect.Complex128: encComplex128Array,
+       reflect.Float32:    encFloat32Array,
+       reflect.Float64:    encFloat64Array,
+       reflect.Int:        encIntArray,
+       reflect.Int16:      encInt16Array,
+       reflect.Int32:      encInt32Array,
+       reflect.Int64:      encInt64Array,
+       reflect.Int8:       encInt8Array,
+       reflect.String:     encStringArray,
+       reflect.Uint:       encUintArray,
+       reflect.Uint16:     encUint16Array,
+       reflect.Uint32:     encUint32Array,
+       reflect.Uint64:     encUint64Array,
+       reflect.Uintptr:    encUintptrArray,
+}
+
+var encSliceHelper = map[reflect.Kind]encHelper{
+       reflect.Bool:       encBoolSlice,
+       reflect.Complex64:  encComplex64Slice,
+       reflect.Complex128: encComplex128Slice,
+       reflect.Float32:    encFloat32Slice,
+       reflect.Float64:    encFloat64Slice,
+       reflect.Int:        encIntSlice,
+       reflect.Int16:      encInt16Slice,
+       reflect.Int32:      encInt32Slice,
+       reflect.Int64:      encInt64Slice,
+       reflect.Int8:       encInt8Slice,
+       reflect.String:     encStringSlice,
+       reflect.Uint:       encUintSlice,
+       reflect.Uint16:     encUint16Slice,
+       reflect.Uint32:     encUint32Slice,
+       reflect.Uint64:     encUint64Slice,
+       reflect.Uintptr:    encUintptrSlice,
+}
+
+func encBoolArray(state *encoderState, v reflect.Value) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return encBoolSlice(state, v.Slice(0, v.Len()))
+}
+
+func encBoolSlice(state *encoderState, v reflect.Value) bool {
+       slice, ok := v.Interface().([]bool)
+       if !ok {
+               // It is kind bool but not type bool. TODO: We can handle this unsafely.
+               return false
+       }
+       for _, x := range slice {
+               if x != false || state.sendZero {
+                       if x {
+                               state.encodeUint(1)
+                       } else {
+                               state.encodeUint(0)
+                       }
+               }
+       }
+       return true
+}
+
+func encComplex64Array(state *encoderState, v reflect.Value) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return encComplex64Slice(state, v.Slice(0, v.Len()))
+}
+
+func encComplex64Slice(state *encoderState, v reflect.Value) bool {
+       slice, ok := v.Interface().([]complex64)
+       if !ok {
+               // It is kind complex64 but not type complex64. TODO: We can handle this unsafely.
+               return false
+       }
+       for _, x := range slice {
+               if x != 0+0i || state.sendZero {
+                       rpart := floatBits(float64(real(x)))
+                       ipart := floatBits(float64(imag(x)))
+                       state.encodeUint(rpart)
+                       state.encodeUint(ipart)
+               }
+       }
+       return true
+}
+
+func encComplex128Array(state *encoderState, v reflect.Value) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return encComplex128Slice(state, v.Slice(0, v.Len()))
+}
+
+func encComplex128Slice(state *encoderState, v reflect.Value) bool {
+       slice, ok := v.Interface().([]complex128)
+       if !ok {
+               // It is kind complex128 but not type complex128. TODO: We can handle this unsafely.
+               return false
+       }
+       for _, x := range slice {
+               if x != 0+0i || state.sendZero {
+                       rpart := floatBits(real(x))
+                       ipart := floatBits(imag(x))
+                       state.encodeUint(rpart)
+                       state.encodeUint(ipart)
+               }
+       }
+       return true
+}
+
+func encFloat32Array(state *encoderState, v reflect.Value) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return encFloat32Slice(state, v.Slice(0, v.Len()))
+}
+
+func encFloat32Slice(state *encoderState, v reflect.Value) bool {
+       slice, ok := v.Interface().([]float32)
+       if !ok {
+               // It is kind float32 but not type float32. TODO: We can handle this unsafely.
+               return false
+       }
+       for _, x := range slice {
+               if x != 0 || state.sendZero {
+                       bits := floatBits(float64(x))
+                       state.encodeUint(bits)
+               }
+       }
+       return true
+}
+
+func encFloat64Array(state *encoderState, v reflect.Value) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return encFloat64Slice(state, v.Slice(0, v.Len()))
+}
+
+func encFloat64Slice(state *encoderState, v reflect.Value) bool {
+       slice, ok := v.Interface().([]float64)
+       if !ok {
+               // It is kind float64 but not type float64. TODO: We can handle this unsafely.
+               return false
+       }
+       for _, x := range slice {
+               if x != 0 || state.sendZero {
+                       bits := floatBits(x)
+                       state.encodeUint(bits)
+               }
+       }
+       return true
+}
+
+func encIntArray(state *encoderState, v reflect.Value) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return encIntSlice(state, v.Slice(0, v.Len()))
+}
+
+func encIntSlice(state *encoderState, v reflect.Value) bool {
+       slice, ok := v.Interface().([]int)
+       if !ok {
+               // It is kind int but not type int. TODO: We can handle this unsafely.
+               return false
+       }
+       for _, x := range slice {
+               if x != 0 || state.sendZero {
+                       state.encodeInt(int64(x))
+               }
+       }
+       return true
+}
+
+func encInt16Array(state *encoderState, v reflect.Value) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return encInt16Slice(state, v.Slice(0, v.Len()))
+}
+
+func encInt16Slice(state *encoderState, v reflect.Value) bool {
+       slice, ok := v.Interface().([]int16)
+       if !ok {
+               // It is kind int16 but not type int16. TODO: We can handle this unsafely.
+               return false
+       }
+       for _, x := range slice {
+               if x != 0 || state.sendZero {
+                       state.encodeInt(int64(x))
+               }
+       }
+       return true
+}
+
+func encInt32Array(state *encoderState, v reflect.Value) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return encInt32Slice(state, v.Slice(0, v.Len()))
+}
+
+func encInt32Slice(state *encoderState, v reflect.Value) bool {
+       slice, ok := v.Interface().([]int32)
+       if !ok {
+               // It is kind int32 but not type int32. TODO: We can handle this unsafely.
+               return false
+       }
+       for _, x := range slice {
+               if x != 0 || state.sendZero {
+                       state.encodeInt(int64(x))
+               }
+       }
+       return true
+}
+
+func encInt64Array(state *encoderState, v reflect.Value) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return encInt64Slice(state, v.Slice(0, v.Len()))
+}
+
+func encInt64Slice(state *encoderState, v reflect.Value) bool {
+       slice, ok := v.Interface().([]int64)
+       if !ok {
+               // It is kind int64 but not type int64. TODO: We can handle this unsafely.
+               return false
+       }
+       for _, x := range slice {
+               if x != 0 || state.sendZero {
+                       state.encodeInt(x)
+               }
+       }
+       return true
+}
+
+func encInt8Array(state *encoderState, v reflect.Value) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return encInt8Slice(state, v.Slice(0, v.Len()))
+}
+
+func encInt8Slice(state *encoderState, v reflect.Value) bool {
+       slice, ok := v.Interface().([]int8)
+       if !ok {
+               // It is kind int8 but not type int8. TODO: We can handle this unsafely.
+               return false
+       }
+       for _, x := range slice {
+               if x != 0 || state.sendZero {
+                       state.encodeInt(int64(x))
+               }
+       }
+       return true
+}
+
+func encStringArray(state *encoderState, v reflect.Value) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return encStringSlice(state, v.Slice(0, v.Len()))
+}
+
+func encStringSlice(state *encoderState, v reflect.Value) bool {
+       slice, ok := v.Interface().([]string)
+       if !ok {
+               // It is kind string but not type string. TODO: We can handle this unsafely.
+               return false
+       }
+       for _, x := range slice {
+               if x != "" || state.sendZero {
+                       state.encodeUint(uint64(len(x)))
+                       state.b.WriteString(x)
+               }
+       }
+       return true
+}
+
+func encUintArray(state *encoderState, v reflect.Value) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return encUintSlice(state, v.Slice(0, v.Len()))
+}
+
+func encUintSlice(state *encoderState, v reflect.Value) bool {
+       slice, ok := v.Interface().([]uint)
+       if !ok {
+               // It is kind uint but not type uint. TODO: We can handle this unsafely.
+               return false
+       }
+       for _, x := range slice {
+               if x != 0 || state.sendZero {
+                       state.encodeUint(uint64(x))
+               }
+       }
+       return true
+}
+
+func encUint16Array(state *encoderState, v reflect.Value) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return encUint16Slice(state, v.Slice(0, v.Len()))
+}
+
+func encUint16Slice(state *encoderState, v reflect.Value) bool {
+       slice, ok := v.Interface().([]uint16)
+       if !ok {
+               // It is kind uint16 but not type uint16. TODO: We can handle this unsafely.
+               return false
+       }
+       for _, x := range slice {
+               if x != 0 || state.sendZero {
+                       state.encodeUint(uint64(x))
+               }
+       }
+       return true
+}
+
+func encUint32Array(state *encoderState, v reflect.Value) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return encUint32Slice(state, v.Slice(0, v.Len()))
+}
+
+func encUint32Slice(state *encoderState, v reflect.Value) bool {
+       slice, ok := v.Interface().([]uint32)
+       if !ok {
+               // It is kind uint32 but not type uint32. TODO: We can handle this unsafely.
+               return false
+       }
+       for _, x := range slice {
+               if x != 0 || state.sendZero {
+                       state.encodeUint(uint64(x))
+               }
+       }
+       return true
+}
+
+func encUint64Array(state *encoderState, v reflect.Value) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return encUint64Slice(state, v.Slice(0, v.Len()))
+}
+
+func encUint64Slice(state *encoderState, v reflect.Value) bool {
+       slice, ok := v.Interface().([]uint64)
+       if !ok {
+               // It is kind uint64 but not type uint64. TODO: We can handle this unsafely.
+               return false
+       }
+       for _, x := range slice {
+               if x != 0 || state.sendZero {
+                       state.encodeUint(x)
+               }
+       }
+       return true
+}
+
+func encUintptrArray(state *encoderState, v reflect.Value) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return encUintptrSlice(state, v.Slice(0, v.Len()))
+}
+
+func encUintptrSlice(state *encoderState, v reflect.Value) bool {
+       slice, ok := v.Interface().([]uintptr)
+       if !ok {
+               // It is kind uintptr but not type uintptr. TODO: We can handle this unsafely.
+               return false
+       }
+       for _, x := range slice {
+               if x != 0 || state.sendZero {
+                       state.encodeUint(uint64(x))
+               }
+       }
+       return true
+}
diff --git a/src/encoding/gob/encgen.go b/src/encoding/gob/encgen.go
new file mode 100644 (file)
index 0000000..efdd928
--- /dev/null
@@ -0,0 +1,218 @@
+// Copyright 2009 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.
+
+// +build ignore
+
+// encgen writes the helper functions for encoding. Intended to be
+// used with go generate; see the invocation in encode.go.
+
+// TODO: We could do more by being unsafe. Add a -unsafe flag?
+
+package main
+
+import (
+       "bytes"
+       "flag"
+       "fmt"
+       "go/format"
+       "log"
+       "os"
+)
+
+var output = flag.String("output", "enc_helpers.go", "file name to write")
+
+type Type struct {
+       lower   string
+       upper   string
+       zero    string
+       encoder string
+}
+
+var types = []Type{
+       {
+               "bool",
+               "Bool",
+               "false",
+               `if x {
+                       state.encodeUint(1)
+               } else {
+                       state.encodeUint(0)
+               }`,
+       },
+       {
+               "complex64",
+               "Complex64",
+               "0+0i",
+               `rpart := floatBits(float64(real(x)))
+               ipart := floatBits(float64(imag(x)))
+               state.encodeUint(rpart)
+               state.encodeUint(ipart)`,
+       },
+       {
+               "complex128",
+               "Complex128",
+               "0+0i",
+               `rpart := floatBits(real(x))
+               ipart := floatBits(imag(x))
+               state.encodeUint(rpart)
+               state.encodeUint(ipart)`,
+       },
+       {
+               "float32",
+               "Float32",
+               "0",
+               `bits := floatBits(float64(x))
+               state.encodeUint(bits)`,
+       },
+       {
+               "float64",
+               "Float64",
+               "0",
+               `bits := floatBits(x)
+               state.encodeUint(bits)`,
+       },
+       {
+               "int",
+               "Int",
+               "0",
+               `state.encodeInt(int64(x))`,
+       },
+       {
+               "int16",
+               "Int16",
+               "0",
+               `state.encodeInt(int64(x))`,
+       },
+       {
+               "int32",
+               "Int32",
+               "0",
+               `state.encodeInt(int64(x))`,
+       },
+       {
+               "int64",
+               "Int64",
+               "0",
+               `state.encodeInt(x)`,
+       },
+       {
+               "int8",
+               "Int8",
+               "0",
+               `state.encodeInt(int64(x))`,
+       },
+       {
+               "string",
+               "String",
+               `""`,
+               `state.encodeUint(uint64(len(x)))
+               state.b.WriteString(x)`,
+       },
+       {
+               "uint",
+               "Uint",
+               "0",
+               `state.encodeUint(uint64(x))`,
+       },
+       {
+               "uint16",
+               "Uint16",
+               "0",
+               `state.encodeUint(uint64(x))`,
+       },
+       {
+               "uint32",
+               "Uint32",
+               "0",
+               `state.encodeUint(uint64(x))`,
+       },
+       {
+               "uint64",
+               "Uint64",
+               "0",
+               `state.encodeUint(x)`,
+       },
+       {
+               "uintptr",
+               "Uintptr",
+               "0",
+               `state.encodeUint(uint64(x))`,
+       },
+       // uint8 Handled separately.
+}
+
+func main() {
+       log.SetFlags(0)
+       log.SetPrefix("encgen: ")
+       flag.Parse()
+       if flag.NArg() != 0 {
+               log.Fatal("usage: encgen [--output filename]")
+       }
+       var b bytes.Buffer
+       fmt.Fprintf(&b, "// Created by encgen --output %s; DO NOT EDIT\n", *output)
+       fmt.Fprint(&b, header)
+       printMaps(&b, "Array")
+       fmt.Fprint(&b, "\n")
+       printMaps(&b, "Slice")
+       for _, t := range types {
+               fmt.Fprintf(&b, arrayHelper, t.lower, t.upper)
+               fmt.Fprintf(&b, sliceHelper, t.lower, t.upper, t.zero, t.encoder)
+       }
+       source, err := format.Source(b.Bytes())
+       if err != nil {
+               log.Fatal("source format error:", err)
+       }
+       fd, err := os.Create(*output)
+       _, err = fd.Write(source)
+       if err != nil {
+               log.Fatal(err)
+       }
+}
+
+func printMaps(b *bytes.Buffer, upperClass string) {
+       fmt.Fprintf(b, "var enc%sHelper = map[reflect.Kind]encHelper{\n", upperClass)
+       for _, t := range types {
+               fmt.Fprintf(b, "reflect.%s: enc%s%s,\n", t.upper, t.upper, upperClass)
+       }
+       fmt.Fprintf(b, "}\n")
+}
+
+const header = `
+// Copyright 2014 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 gob
+
+import (
+       "reflect"
+)
+
+`
+
+const arrayHelper = `
+func enc%[2]sArray(state *encoderState, v reflect.Value) bool {
+       // Can only slice if it is addressable.
+       if !v.CanAddr() {
+               return false
+       }
+       return enc%[2]sSlice(state, v.Slice(0, v.Len()))
+}
+`
+
+const sliceHelper = `
+func enc%[2]sSlice(state *encoderState, v reflect.Value) bool {
+       slice, ok := v.Interface().([]%[1]s)
+       if !ok {
+               // It is kind %[1]s but not type %[1]s. TODO: We can handle this unsafely.
+               return false
+       }
+       for _, x := range slice {
+               if x != %[3]s || state.sendZero {
+                       %[4]s
+               }
+       }
+       return true
+}
+`
index 04a85410c6e233394eff90beef740e9691857deb..f66279f14134b505825c803f15483e89816493e9 100644 (file)
@@ -2,10 +2,11 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+//go:generate go run encgen.go -output enc_helpers.go
+
 package gob
 
 import (
-       "bytes"
        "encoding"
        "math"
        "reflect"
@@ -13,20 +14,54 @@ import (
 
 const uint64Size = 8
 
+type encHelper func(state *encoderState, v reflect.Value) bool
+
 // encoderState is the global execution state of an instance of the encoder.
 // Field numbers are delta encoded and always increase. The field
 // number is initialized to -1 so 0 comes out as delta(1). A delta of
 // 0 terminates the structure.
 type encoderState struct {
        enc      *Encoder
-       b        *bytes.Buffer
+       b        *encBuffer
        sendZero bool                 // encoding an array element or map key/value pair; send zero values
        fieldnum int                  // the last field number written.
        buf      [1 + uint64Size]byte // buffer used by the encoder; here to avoid allocation.
        next     *encoderState        // for free list
 }
 
-func (enc *Encoder) newEncoderState(b *bytes.Buffer) *encoderState {
+// encBuffer is an extremely simple, fast implementation of a write-only byte buffer.
+// It never returns a non-nil error, but Write returns an error value so it matches io.Writer.
+type encBuffer struct {
+       data    []byte
+       scratch [64]byte
+}
+
+func (e *encBuffer) WriteByte(c byte) {
+       e.data = append(e.data, c)
+}
+
+func (e *encBuffer) Write(p []byte) (int, error) {
+       e.data = append(e.data, p...)
+       return len(p), nil
+}
+
+func (e *encBuffer) WriteString(s string) {
+       e.data = append(e.data, s...)
+}
+
+func (e *encBuffer) Len() int {
+       return len(e.data)
+}
+
+func (e *encBuffer) Bytes() []byte {
+       return e.data
+}
+
+func (e *encBuffer) Reset() {
+       e.data = e.data[0:0]
+}
+
+func (enc *Encoder) newEncoderState(b *encBuffer) *encoderState {
        e := enc.freeList
        if e == nil {
                e = new(encoderState)
@@ -37,6 +72,9 @@ func (enc *Encoder) newEncoderState(b *bytes.Buffer) *encoderState {
        e.sendZero = false
        e.fieldnum = 0
        e.b = b
+       if len(b.data) == 0 {
+               b.data = b.scratch[0:0]
+       }
        return e
 }
 
@@ -53,10 +91,7 @@ func (enc *Encoder) freeEncoderState(e *encoderState) {
 // encodeUint writes an encoded unsigned integer to state.b.
 func (state *encoderState) encodeUint(x uint64) {
        if x <= 0x7F {
-               err := state.b.WriteByte(uint8(x))
-               if err != nil {
-                       error_(err)
-               }
+               state.b.WriteByte(uint8(x))
                return
        }
        i := uint64Size
@@ -66,10 +101,7 @@ func (state *encoderState) encodeUint(x uint64) {
                i--
        }
        state.buf[i] = uint8(i - uint64Size) // = loop count, negated
-       _, err := state.b.Write(state.buf[i : uint64Size+1])
-       if err != nil {
-               error_(err)
-       }
+       state.b.Write(state.buf[i : uint64Size+1])
 }
 
 // encodeInt writes an encoded signed integer to state.w.
@@ -247,7 +279,7 @@ func valid(v reflect.Value) bool {
 }
 
 // encodeSingle encodes a single top-level non-struct value.
-func (enc *Encoder) encodeSingle(b *bytes.Buffer, engine *encEngine, value reflect.Value) {
+func (enc *Encoder) encodeSingle(b *encBuffer, engine *encEngine, value reflect.Value) {
        state := enc.newEncoderState(b)
        defer enc.freeEncoderState(state)
        state.fieldnum = singletonField
@@ -264,7 +296,7 @@ func (enc *Encoder) encodeSingle(b *bytes.Buffer, engine *encEngine, value refle
 }
 
 // encodeStruct encodes a single struct value.
-func (enc *Encoder) encodeStruct(b *bytes.Buffer, engine *encEngine, value reflect.Value) {
+func (enc *Encoder) encodeStruct(b *encBuffer, engine *encEngine, value reflect.Value) {
        if !valid(value) {
                return
        }
@@ -291,12 +323,15 @@ func (enc *Encoder) encodeStruct(b *bytes.Buffer, engine *encEngine, value refle
 }
 
 // encodeArray encodes an array.
-func (enc *Encoder) encodeArray(b *bytes.Buffer, value reflect.Value, op encOp, elemIndir int, length int) {
+func (enc *Encoder) encodeArray(b *encBuffer, value reflect.Value, op encOp, elemIndir int, length int, helper encHelper) {
        state := enc.newEncoderState(b)
        defer enc.freeEncoderState(state)
        state.fieldnum = -1
        state.sendZero = true
        state.encodeUint(uint64(length))
+       if helper != nil && helper(state, value) {
+               return
+       }
        for i := 0; i < length; i++ {
                elem := value.Index(i)
                if elemIndir > 0 {
@@ -322,7 +357,7 @@ func encodeReflectValue(state *encoderState, v reflect.Value, op encOp, indir in
 }
 
 // encodeMap encodes a map as unsigned count followed by key:value pairs.
-func (enc *Encoder) encodeMap(b *bytes.Buffer, mv reflect.Value, keyOp, elemOp encOp, keyIndir, elemIndir int) {
+func (enc *Encoder) encodeMap(b *encBuffer, mv reflect.Value, keyOp, elemOp encOp, keyIndir, elemIndir int) {
        state := enc.newEncoderState(b)
        state.fieldnum = -1
        state.sendZero = true
@@ -340,7 +375,7 @@ func (enc *Encoder) encodeMap(b *bytes.Buffer, mv reflect.Value, keyOp, elemOp e
 // by the type identifier (which might require defining that type right now), followed
 // by the concrete value.  A nil value gets sent as the empty string for the name,
 // followed by no value.
-func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv reflect.Value) {
+func (enc *Encoder) encodeInterface(b *encBuffer, iv reflect.Value) {
        // Gobs can encode nil interface values but not typed interface
        // values holding nil pointers, since nil pointers point to no value.
        elem := iv.Elem()
@@ -364,10 +399,7 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv reflect.Value) {
        }
        // Send the name.
        state.encodeUint(uint64(len(name)))
-       _, err := state.b.WriteString(name)
-       if err != nil {
-               error_(err)
-       }
+       state.b.WriteString(name)
        // Define the type id if necessary.
        enc.sendTypeDescriptor(enc.writer(), state, ut)
        // Send the type id.
@@ -375,7 +407,7 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv reflect.Value) {
        // Encode the value into a new buffer.  Any nested type definitions
        // should be written to b, before the encoded value.
        enc.pushWriter(b)
-       data := new(bytes.Buffer)
+       data := new(encBuffer)
        data.Write(spaceForLength)
        enc.encode(data, elem, ut)
        if enc.err != nil {
@@ -384,7 +416,7 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv reflect.Value) {
        enc.popWriter()
        enc.writeMessage(b, data)
        if enc.err != nil {
-               error_(err)
+               error_(enc.err)
        }
        enc.freeEncoderState(state)
 }
@@ -426,7 +458,7 @@ func isZero(val reflect.Value) bool {
 
 // encGobEncoder encodes a value that implements the GobEncoder interface.
 // The data is sent as a byte array.
-func (enc *Encoder) encodeGobEncoder(b *bytes.Buffer, ut *userTypeInfo, v reflect.Value) {
+func (enc *Encoder) encodeGobEncoder(b *encBuffer, ut *userTypeInfo, v reflect.Value) {
        // TODO: should we catch panics from the called method?
 
        var data []byte
@@ -501,19 +533,21 @@ func encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp, building map[
                        }
                        // Slices have a header; we decode it to find the underlying array.
                        elemOp, elemIndir := encOpFor(t.Elem(), inProgress, building)
+                       helper := encSliceHelper[t.Elem().Kind()]
                        op = func(i *encInstr, state *encoderState, slice reflect.Value) {
                                if !state.sendZero && slice.Len() == 0 {
                                        return
                                }
                                state.update(i)
-                               state.enc.encodeArray(state.b, slice, *elemOp, elemIndir, slice.Len())
+                               state.enc.encodeArray(state.b, slice, *elemOp, elemIndir, slice.Len(), helper)
                        }
                case reflect.Array:
                        // True arrays have size in the type.
                        elemOp, elemIndir := encOpFor(t.Elem(), inProgress, building)
+                       helper := encArrayHelper[t.Elem().Kind()]
                        op = func(i *encInstr, state *encoderState, array reflect.Value) {
                                state.update(i)
-                               state.enc.encodeArray(state.b, array, *elemOp, elemIndir, array.Len())
+                               state.enc.encodeArray(state.b, array, *elemOp, elemIndir, array.Len(), helper)
                        }
                case reflect.Map:
                        keyOp, keyIndir := encOpFor(t.Key(), inProgress, building)
@@ -644,7 +678,7 @@ func buildEncEngine(info *typeInfo, ut *userTypeInfo, building map[*typeInfo]boo
        return enc
 }
 
-func (enc *Encoder) encode(b *bytes.Buffer, value reflect.Value, ut *userTypeInfo) {
+func (enc *Encoder) encode(b *encBuffer, value reflect.Value, ut *userTypeInfo) {
        defer catchError(&enc.err)
        engine := getEncEngine(ut, nil)
        indir := ut.indir
index 4b5dc16c7965bce4b7641c71b89bc8196835e061..a340e47b5ed6a903cc954738421e1e52a2327790 100644 (file)
@@ -5,7 +5,6 @@
 package gob
 
 import (
-       "bytes"
        "io"
        "reflect"
        "sync"
@@ -19,7 +18,7 @@ type Encoder struct {
        sent       map[reflect.Type]typeId // which types we've already sent
        countState *encoderState           // stage for writing counts
        freeList   *encoderState           // list of free encoderStates; avoids reallocation
-       byteBuf    bytes.Buffer            // buffer for top-level encoderState
+       byteBuf    encBuffer               // buffer for top-level encoderState
        err        error
 }
 
@@ -34,7 +33,7 @@ func NewEncoder(w io.Writer) *Encoder {
        enc := new(Encoder)
        enc.w = []io.Writer{w}
        enc.sent = make(map[reflect.Type]typeId)
-       enc.countState = enc.newEncoderState(new(bytes.Buffer))
+       enc.countState = enc.newEncoderState(new(encBuffer))
        return enc
 }
 
@@ -60,7 +59,7 @@ func (enc *Encoder) setError(err error) {
 }
 
 // writeMessage sends the data item preceded by a unsigned count of its length.
-func (enc *Encoder) writeMessage(w io.Writer, b *bytes.Buffer) {
+func (enc *Encoder) writeMessage(w io.Writer, b *encBuffer) {
        // Space has been reserved for the length at the head of the message.
        // This is a little dirty: we grab the slice from the bytes.Buffer and massage
        // it by hand.
index ec55c4d63dbeab4e2b002fd7f54f4fea250543a6..940e5ad4126a7f025de32624d62eede74759548b 100644 (file)
@@ -131,3 +131,195 @@ func TestCountDecodeMallocs(t *testing.T) {
                t.Fatalf("mallocs per decode of type Bench: %v; wanted 4\n", allocs)
        }
 }
+
+func BenchmarkEncodeComplex128Slice(b *testing.B) {
+       var buf bytes.Buffer
+       enc := NewEncoder(&buf)
+       a := make([]complex128, 1000)
+       for i := range a {
+               a[i] = 1.2 + 3.4i
+       }
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               buf.Reset()
+               err := enc.Encode(a)
+               if err != nil {
+                       b.Fatal(err)
+               }
+       }
+}
+
+func BenchmarkEncodeFloat64Slice(b *testing.B) {
+       var buf bytes.Buffer
+       enc := NewEncoder(&buf)
+       a := make([]float64, 1000)
+       for i := range a {
+               a[i] = 1.23e4
+       }
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               buf.Reset()
+               err := enc.Encode(a)
+               if err != nil {
+                       b.Fatal(err)
+               }
+       }
+}
+
+func BenchmarkEncodeInt32Slice(b *testing.B) {
+       var buf bytes.Buffer
+       enc := NewEncoder(&buf)
+       a := make([]int32, 1000)
+       for i := range a {
+               a[i] = 1234
+       }
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               buf.Reset()
+               err := enc.Encode(a)
+               if err != nil {
+                       b.Fatal(err)
+               }
+       }
+}
+
+func BenchmarkEncodeStringSlice(b *testing.B) {
+       var buf bytes.Buffer
+       enc := NewEncoder(&buf)
+       a := make([]string, 1000)
+       for i := range a {
+               a[i] = "now is the time"
+       }
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               buf.Reset()
+               err := enc.Encode(a)
+               if err != nil {
+                       b.Fatal(err)
+               }
+       }
+}
+
+// benchmarkBuf is a read buffer we can reset
+type benchmarkBuf struct {
+       offset int
+       data   []byte
+}
+
+func (b *benchmarkBuf) Read(p []byte) (n int, err error) {
+       n = copy(p, b.data[b.offset:])
+       if n == 0 {
+               return 0, io.EOF
+       }
+       b.offset += n
+       return
+}
+
+func (b *benchmarkBuf) ReadByte() (c byte, err error) {
+       if b.offset >= len(b.data) {
+               return 0, io.EOF
+       }
+       c = b.data[b.offset]
+       b.offset++
+       return
+}
+
+func (b *benchmarkBuf) reset() {
+       b.offset = 0
+}
+
+func BenchmarkDecodeComplex128Slice(b *testing.B) {
+       var buf bytes.Buffer
+       enc := NewEncoder(&buf)
+       a := make([]complex128, 1000)
+       for i := range a {
+               a[i] = 1.2 + 3.4i
+       }
+       err := enc.Encode(a)
+       if err != nil {
+               b.Fatal(err)
+       }
+       x := make([]complex128, 1000)
+       bbuf := benchmarkBuf{data: buf.Bytes()}
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               bbuf.reset()
+               dec := NewDecoder(&bbuf)
+               err := dec.Decode(&x)
+               if err != nil {
+                       b.Fatal(i, err)
+               }
+       }
+}
+
+func BenchmarkDecodeFloat64Slice(b *testing.B) {
+       var buf bytes.Buffer
+       enc := NewEncoder(&buf)
+       a := make([]float64, 1000)
+       for i := range a {
+               a[i] = 1.23e4
+       }
+       err := enc.Encode(a)
+       if err != nil {
+               b.Fatal(err)
+       }
+       x := make([]float64, 1000)
+       bbuf := benchmarkBuf{data: buf.Bytes()}
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               bbuf.reset()
+               dec := NewDecoder(&bbuf)
+               err := dec.Decode(&x)
+               if err != nil {
+                       b.Fatal(i, err)
+               }
+       }
+}
+
+func BenchmarkDecodeInt32Slice(b *testing.B) {
+       var buf bytes.Buffer
+       enc := NewEncoder(&buf)
+       a := make([]int32, 1000)
+       for i := range a {
+               a[i] = 1234
+       }
+       err := enc.Encode(a)
+       if err != nil {
+               b.Fatal(err)
+       }
+       x := make([]int32, 1000)
+       bbuf := benchmarkBuf{data: buf.Bytes()}
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               bbuf.reset()
+               dec := NewDecoder(&bbuf)
+               err := dec.Decode(&x)
+               if err != nil {
+                       b.Fatal(i, err)
+               }
+       }
+}
+
+func BenchmarkDecodeStringSlice(b *testing.B) {
+       var buf bytes.Buffer
+       enc := NewEncoder(&buf)
+       a := make([]string, 1000)
+       for i := range a {
+               a[i] = "now is the time"
+       }
+       err := enc.Encode(a)
+       if err != nil {
+               b.Fatal(err)
+       }
+       x := make([]string, 1000)
+       bbuf := benchmarkBuf{data: buf.Bytes()}
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               bbuf.reset()
+               dec := NewDecoder(&bbuf)
+               err := dec.Decode(&x)
+               if err != nil {
+                       b.Fatal(i, err)
+               }
+       }
+}
index 9b7b9d5fd18b860c8a938c7556703f3620a1eb45..fca2a0980b2a36a30e8d80f79e1261088acea4c8 100644 (file)
@@ -805,6 +805,9 @@ func (e *encodeState) string(s string) (int, error) {
                        case '\r':
                                e.WriteByte('\\')
                                e.WriteByte('r')
+                       case '\t':
+                               e.WriteByte('\\')
+                               e.WriteByte('t')
                        default:
                                // This encodes bytes < 0x20 except for \n and \r,
                                // as well as <, > and &. The latter are escaped because they
@@ -878,9 +881,12 @@ func (e *encodeState) stringBytes(s []byte) (int, error) {
                        case '\r':
                                e.WriteByte('\\')
                                e.WriteByte('r')
+                       case '\t':
+                               e.WriteByte('\\')
+                               e.WriteByte('t')
                        default:
                                // This encodes bytes < 0x20 except for \n and \r,
-                               // as well as < and >. The latter are escaped because they
+                               // as well as <, >, and &. The latter are escaped because they
                                // can lead to security holes when user-controlled strings
                                // are rendered into JSON and served to some browsers.
                                e.WriteString(`\u00`)
index eb84cbae14ca79580ed9a7dfac80ab21e9ea3d61..7abfa85db7bc243c6c057a476297dce62cc9c5f7 100644 (file)
@@ -478,3 +478,55 @@ func TestEncodePointerString(t *testing.T) {
                t.Fatalf("*N = %d; want 42", *back.N)
        }
 }
+
+var encodeStringTests = []struct {
+       in  string
+       out string
+}{
+       {"\x00", `"\u0000"`},
+       {"\x01", `"\u0001"`},
+       {"\x02", `"\u0002"`},
+       {"\x03", `"\u0003"`},
+       {"\x04", `"\u0004"`},
+       {"\x05", `"\u0005"`},
+       {"\x06", `"\u0006"`},
+       {"\x07", `"\u0007"`},
+       {"\x08", `"\u0008"`},
+       {"\x09", `"\t"`},
+       {"\x0a", `"\n"`},
+       {"\x0b", `"\u000b"`},
+       {"\x0c", `"\u000c"`},
+       {"\x0d", `"\r"`},
+       {"\x0e", `"\u000e"`},
+       {"\x0f", `"\u000f"`},
+       {"\x10", `"\u0010"`},
+       {"\x11", `"\u0011"`},
+       {"\x12", `"\u0012"`},
+       {"\x13", `"\u0013"`},
+       {"\x14", `"\u0014"`},
+       {"\x15", `"\u0015"`},
+       {"\x16", `"\u0016"`},
+       {"\x17", `"\u0017"`},
+       {"\x18", `"\u0018"`},
+       {"\x19", `"\u0019"`},
+       {"\x1a", `"\u001a"`},
+       {"\x1b", `"\u001b"`},
+       {"\x1c", `"\u001c"`},
+       {"\x1d", `"\u001d"`},
+       {"\x1e", `"\u001e"`},
+       {"\x1f", `"\u001f"`},
+}
+
+func TestEncodeString(t *testing.T) {
+       for _, tt := range encodeStringTests {
+               b, err := Marshal(tt.in)
+               if err != nil {
+                       t.Errorf("Marshal(%q): %v", tt.in, err)
+                       continue
+               }
+               out := string(b)
+               if out != tt.out {
+                       t.Errorf("Marshal(%q) = %#q, want %#q", tt.in, out, tt.out)
+               }
+       }
+}
index 323e452a832dea87f8dccc966212b0bd4b4b9a59..60aef5d806c748d6d1f22b5d006781f24a859967 100644 (file)
@@ -760,6 +760,7 @@ func (f *FlagSet) parseOne() (bool, error) {
                }
                return false, f.failf("flag provided but not defined: -%s", name)
        }
+
        if fv, ok := flag.Value.(boolFlag); ok && fv.IsBoolFlag() { // special case: doesn't need an arg
                if has_value {
                        if err := fv.Set(value); err != nil {
index 304b9e9581eb2ddb5cb77baf360176f8a21a58d1..ee54463e275bd43d6f7542e8455b6f5eed29f2c4 100644 (file)
@@ -38,8 +38,8 @@
                %E      scientific notation, e.g. -1234.456E+78
                %f      decimal point but no exponent, e.g. 123.456
                %F      synonym for %f
-               %g      whichever of %e or %f produces more compact output
-               %G      whichever of %E or %f produces more compact output
+               %g      %e for large exponents, %f otherwise
+               %G      %E for large exponents, %F otherwise
        String and slice of bytes:
                %s      the uninterpreted bytes of the string or slice
                %q      a double-quoted string safely escaped with Go syntax
index 311e1d2c4ea2c1e7736e4a7b45e5c75edc8a2326..7af7997de9b6c3dbf8c7016238370965d910c42b 100644 (file)
@@ -138,7 +138,7 @@ func TestJSValEscaper(t *testing.T) {
                // Newlines.
                {"\r\n\u2028\u2029", `"\r\n\u2028\u2029"`},
                // "\v" == "v" on IE 6 so use "\x0b" instead.
-               {"\t\x0b", `"\u0009\u000b"`},
+               {"\t\x0b", `"\t\u000b"`},
                {struct{ X, Y int }{1, 2}, `{"X":1,"Y":2}`},
                {[]interface{}{}, "[]"},
                {[]interface{}{42, "foo", nil}, `[42,"foo",null]`},
index 0c7548e3ef3792adaeb6866081f6bf6aa0bc4159..a23f1bc4bc6026973a1faac1cd8bda9e82f70d5b 100644 (file)
@@ -162,6 +162,10 @@ func (name handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
                fmt.Fprintf(w, "Unknown profile: %s\n", name)
                return
        }
+       gc, _ := strconv.Atoi(r.FormValue("gc"))
+       if name == "heap" && gc > 0 {
+               runtime.GC()
+       }
        p.WriteTo(w, debug)
        return
 }
index 20f20578cded9ab74deb58e46f8ae6e462c16ca2..aeffe6c9b725312f8bab3669a129bfb563ae71c8 100644 (file)
@@ -40,10 +40,16 @@ func lookupIPMerge(host string) (addrs []IP, err error) {
        addrsi, err, shared := lookupGroup.Do(host, func() (interface{}, error) {
                return lookupIP(host)
        })
+       return lookupIPReturn(addrsi, err, shared)
+}
+
+// lookupIPReturn turns the return values from singleflight.Do into
+// the return values from LookupIP.
+func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IP, error) {
        if err != nil {
                return nil, err
        }
-       addrs = addrsi.([]IP)
+       addrs := addrsi.([]IP)
        if shared {
                clone := make([]IP, len(addrs))
                copy(clone, addrs)
@@ -52,41 +58,40 @@ func lookupIPMerge(host string) (addrs []IP, err error) {
        return addrs, nil
 }
 
+// lookupIPDeadline looks up a hostname with a deadline.
 func lookupIPDeadline(host string, deadline time.Time) (addrs []IP, err error) {
        if deadline.IsZero() {
                return lookupIPMerge(host)
        }
 
-       // TODO(bradfitz): consider pushing the deadline down into the
-       // name resolution functions. But that involves fixing it for
-       // the native Go resolver, cgo, Windows, etc.
-       //
-       // In the meantime, just use a goroutine. Most users affected
-       // by http://golang.org/issue/2631 are due to TCP connections
-       // to unresponsive hosts, not DNS.
+       // We could push the deadline down into the name resolution
+       // functions.  However, the most commonly used implementation
+       // calls getaddrinfo, which has no timeout.
+
        timeout := deadline.Sub(time.Now())
        if timeout <= 0 {
-               err = errTimeout
-               return
+               return nil, errTimeout
        }
        t := time.NewTimer(timeout)
        defer t.Stop()
-       type res struct {
-               addrs []IP
-               err   error
-       }
-       resc := make(chan res, 1)
-       go func() {
-               a, err := lookupIPMerge(host)
-               resc <- res{a, err}
-       }()
+
+       ch := lookupGroup.DoChan(host, func() (interface{}, error) {
+               return lookupIP(host)
+       })
+
        select {
        case <-t.C:
-               err = errTimeout
-       case r := <-resc:
-               addrs, err = r.addrs, r.err
+               // The DNS lookup timed out for some reason.  Force
+               // future requests to start the DNS lookup again
+               // rather than waiting for the current lookup to
+               // complete.  See issue 8602.
+               lookupGroup.Forget(host)
+
+               return nil, errTimeout
+
+       case r := <-ch:
+               return lookupIPReturn(r.v, r.err, r.shared)
        }
-       return
 }
 
 // LookupPort looks up the port for the given network and service.
index dc58affdaac89952d4c82e34a795f97702f918a1..bf599f0cc948b8ce61bd4db6c0f5890de4df26d0 100644 (file)
@@ -8,10 +8,18 @@ import "sync"
 
 // call is an in-flight or completed singleflight.Do call
 type call struct {
-       wg   sync.WaitGroup
-       val  interface{}
-       err  error
-       dups int
+       wg sync.WaitGroup
+
+       // These fields are written once before the WaitGroup is done
+       // and are only read after the WaitGroup is done.
+       val interface{}
+       err error
+
+       // These fields are read and written with the singleflight
+       // mutex held before the WaitGroup is done, and are read but
+       // not written after the WaitGroup is done.
+       dups  int
+       chans []chan<- singleflightResult
 }
 
 // singleflight represents a class of work and forms a namespace in
@@ -21,6 +29,14 @@ type singleflight struct {
        m  map[string]*call // lazily initialized
 }
 
+// singleflightResult holds the results of Do, so they can be passed
+// on a channel.
+type singleflightResult struct {
+       v      interface{}
+       err    error
+       shared bool
+}
+
 // Do executes and returns the results of the given function, making
 // sure that only one execution is in-flight for a given key at a
 // time. If a duplicate comes in, the duplicate caller waits for the
@@ -42,12 +58,52 @@ func (g *singleflight) Do(key string, fn func() (interface{}, error)) (v interfa
        g.m[key] = c
        g.mu.Unlock()
 
+       g.doCall(c, key, fn)
+       return c.val, c.err, c.dups > 0
+}
+
+// DoChan is like Do but returns a channel that will receive the
+// results when they are ready.
+func (g *singleflight) DoChan(key string, fn func() (interface{}, error)) <-chan singleflightResult {
+       ch := make(chan singleflightResult, 1)
+       g.mu.Lock()
+       if g.m == nil {
+               g.m = make(map[string]*call)
+       }
+       if c, ok := g.m[key]; ok {
+               c.dups++
+               c.chans = append(c.chans, ch)
+               g.mu.Unlock()
+               return ch
+       }
+       c := &call{chans: []chan<- singleflightResult{ch}}
+       c.wg.Add(1)
+       g.m[key] = c
+       g.mu.Unlock()
+
+       go g.doCall(c, key, fn)
+
+       return ch
+}
+
+// doCall handles the single call for a key.
+func (g *singleflight) doCall(c *call, key string, fn func() (interface{}, error)) {
        c.val, c.err = fn()
        c.wg.Done()
 
        g.mu.Lock()
        delete(g.m, key)
+       for _, ch := range c.chans {
+               ch <- singleflightResult{c.val, c.err, c.dups > 0}
+       }
        g.mu.Unlock()
+}
 
-       return c.val, c.err, c.dups > 0
+// Forget tells the singleflight to forget about a key.  Future calls
+// to Do for this key will call the function rather than waiting for
+// an earlier call to complete.
+func (g *singleflight) Forget(key string) {
+       g.mu.Lock()
+       delete(g.m, key)
+       g.mu.Unlock()
 }
index 4f6a54a560acab2f44c446983fbbe0702029b7cd..716c103db26bf78344e624cdf570a3b0ec37bd7d 100644 (file)
@@ -8,6 +8,7 @@ import (
        "flag"
        "fmt"
        "testing"
+       "time"
 )
 
 var testDNSFlood = flag.Bool("dnsflood", false, "whether to test dns query flooding")
@@ -35,3 +36,64 @@ func TestDNSThreadLimit(t *testing.T) {
 
        // If we're still here, it worked.
 }
+
+func TestLookupIPDeadline(t *testing.T) {
+       if !*testDNSFlood {
+               t.Skip("test disabled; use -dnsflood to enable")
+       }
+
+       const N = 5000
+       const timeout = 3 * time.Second
+       c := make(chan error, 2*N)
+       for i := 0; i < N; i++ {
+               name := fmt.Sprintf("%d.net-test.golang.org", i)
+               go func() {
+                       _, err := lookupIPDeadline(name, time.Now().Add(timeout/2))
+                       c <- err
+               }()
+               go func() {
+                       _, err := lookupIPDeadline(name, time.Now().Add(timeout))
+                       c <- err
+               }()
+       }
+       qstats := struct {
+               succeeded, failed         int
+               timeout, temporary, other int
+               unknown                   int
+       }{}
+       deadline := time.After(timeout + time.Second)
+       for i := 0; i < 2*N; i++ {
+               select {
+               case <-deadline:
+                       t.Fatal("deadline exceeded")
+               case err := <-c:
+                       switch err := err.(type) {
+                       case nil:
+                               qstats.succeeded++
+                       case Error:
+                               qstats.failed++
+                               if err.Timeout() {
+                                       qstats.timeout++
+                               }
+                               if err.Temporary() {
+                                       qstats.temporary++
+                               }
+                               if !err.Timeout() && !err.Temporary() {
+                                       qstats.other++
+                               }
+                       default:
+                               qstats.failed++
+                               qstats.unknown++
+                       }
+               }
+       }
+
+       // A high volume of DNS queries for sub-domain of golang.org
+       // would be coordinated by authoritative or recursive server,
+       // or stub resolver which implements query-response rate
+       // limitation, so we can expect some query successes and more
+       // failures including timeout, temporary and other here.
+       // As a rule, unknown must not be shown but it might possibly
+       // happen due to issue 4856 for now.
+       t.Logf("%v succeeded, %v failed (%v timeout, %v temporary, %v other, %v unknown)", qstats.succeeded, qstats.failed, qstats.timeout, qstats.temporary, qstats.other, qstats.unknown)
+}
index d353e405e54178088608408609ede466248fcfbb..589db85274077b2e09ddd1596be40cd2f9d1ebbc 100644 (file)
@@ -36,7 +36,7 @@ func (f *File) readdirnames(n int) (names []string, err error) {
                if d.bufp >= d.nbuf {
                        d.bufp = 0
                        var errno error
-                       d.nbuf, errno = syscall.ReadDirent(f.fd, d.buf)
+                       d.nbuf, errno = fixCount(syscall.ReadDirent(f.fd, d.buf))
                        if errno != nil {
                                return names, NewSyscallError("readdirent", errno)
                        }
index 5fd439b8bb297c5e0b5fd463ea409c07d4e60a18..bc9c00effe554db124c15cde971dc93a02281bb4 100644 (file)
@@ -258,15 +258,7 @@ var testedAlreadyLeaked = false
 // basefds returns the number of expected file descriptors
 // to be present in a process at start.
 func basefds() uintptr {
-       n := os.Stderr.Fd() + 1
-
-       // Go runtime for 32-bit Plan 9 requires that /dev/bintime
-       // be kept open.
-       // See ../../runtime/time_plan9_386.c:/^runtime·nanotime
-       if runtime.GOOS == "plan9" && runtime.GOARCH == "386" {
-               n++
-       }
-       return n
+       return os.Stderr.Fd() + 1
 }
 
 func closeUnexpectedFds(t *testing.T, m string) {
index b4a745801621585eaf6197b678d286da2c839c2c..e12428cbe129cf0615ea8cba2eb1c43256d9020f 100644 (file)
@@ -255,3 +255,12 @@ var lstat = Lstat
 func Rename(oldpath, newpath string) error {
        return rename(oldpath, newpath)
 }
+
+// Many functions in package syscall return a count of -1 instead of 0.
+// Using fixCount(call()) instead of call() corrects the count.
+func fixCount(n int, err error) (int, error) {
+       if n < 0 {
+               n = 0
+       }
+       return n, err
+}
index a804b81973135590061f07cd00db17c7a1a3e12b..5efc2a4f1dbb375f9f8db90c0dc177ea04309e14 100644 (file)
@@ -244,14 +244,14 @@ func (f *File) Sync() (err error) {
 // read reads up to len(b) bytes from the File.
 // It returns the number of bytes read and an error, if any.
 func (f *File) read(b []byte) (n int, err error) {
-       return syscall.Read(f.fd, b)
+       return fixCount(syscall.Read(f.fd, b))
 }
 
 // pread reads len(b) bytes from the File starting at byte offset off.
 // It returns the number of bytes read and the error, if any.
 // EOF is signaled by a zero count with err set to nil.
 func (f *File) pread(b []byte, off int64) (n int, err error) {
-       return syscall.Pread(f.fd, b, off)
+       return fixCount(syscall.Pread(f.fd, b, off))
 }
 
 // write writes len(b) bytes to the File.
@@ -262,7 +262,7 @@ func (f *File) write(b []byte) (n int, err error) {
        if len(b) == 0 {
                return 0, nil
        }
-       return syscall.Write(f.fd, b)
+       return fixCount(syscall.Write(f.fd, b))
 }
 
 // pwrite writes len(b) bytes to the File starting at byte offset off.
@@ -273,7 +273,7 @@ func (f *File) pwrite(b []byte, off int64) (n int, err error) {
        if len(b) == 0 {
                return 0, nil
        }
-       return syscall.Pwrite(f.fd, b, off)
+       return fixCount(syscall.Pwrite(f.fd, b, off))
 }
 
 // seek sets the offset for the next Read or Write on file to offset, interpreted
index 9cff7e5bcc65b69d2564e9ac0b7f15b72436cbe5..fbb3b5e4d816d856107796a3f18dcabbf8404169 100644 (file)
@@ -18,7 +18,7 @@ func sigpipe() // implemented in package runtime
 func Readlink(name string) (string, error) {
        for len := 128; ; len *= 2 {
                b := make([]byte, len)
-               n, e := syscall.Readlink(name, b)
+               n, e := fixCount(syscall.Readlink(name, b))
                if e != nil {
                        return "", &PathError{"readlink", name, e}
                }
index bba0d9c0f685b3b142132ca1fc55b8472de2bb55..f59d563e697f032e020ac17020810a87b95584c1 100644 (file)
@@ -187,7 +187,7 @@ func (f *File) read(b []byte) (n int, err error) {
        if needsMaxRW && len(b) > maxRW {
                b = b[:maxRW]
        }
-       return syscall.Read(f.fd, b)
+       return fixCount(syscall.Read(f.fd, b))
 }
 
 // pread reads len(b) bytes from the File starting at byte offset off.
@@ -197,7 +197,7 @@ func (f *File) pread(b []byte, off int64) (n int, err error) {
        if needsMaxRW && len(b) > maxRW {
                b = b[:maxRW]
        }
-       return syscall.Pread(f.fd, b, off)
+       return fixCount(syscall.Pread(f.fd, b, off))
 }
 
 // write writes len(b) bytes to the File.
@@ -208,7 +208,7 @@ func (f *File) write(b []byte) (n int, err error) {
                if needsMaxRW && len(bcap) > maxRW {
                        bcap = bcap[:maxRW]
                }
-               m, err := syscall.Write(f.fd, bcap)
+               m, err := fixCount(syscall.Write(f.fd, bcap))
                n += m
 
                // If the syscall wrote some data but not all (short write)
@@ -234,7 +234,7 @@ func (f *File) pwrite(b []byte, off int64) (n int, err error) {
        if needsMaxRW && len(b) > maxRW {
                b = b[:maxRW]
        }
-       return syscall.Pwrite(f.fd, b, off)
+       return fixCount(syscall.Pwrite(f.fd, b, off))
 }
 
 // seek sets the offset for the next Read or Write on file to offset, interpreted
index e78d4abf642e0e47d38591e330a68a88ac0bcc9c..3b5519390ba338dce0e1a3cebbb6905027564ddb 100644 (file)
@@ -295,7 +295,7 @@ func (f *File) read(b []byte) (n int, err error) {
        if f.isConsole {
                return f.readConsole(b)
        }
-       return syscall.Read(f.fd, b)
+       return fixCount(syscall.Read(f.fd, b))
 }
 
 // pread reads len(b) bytes from the File starting at byte offset off.
@@ -376,7 +376,7 @@ func (f *File) write(b []byte) (n int, err error) {
        if f.isConsole {
                return f.writeConsole(b)
        }
-       return syscall.Write(f.fd, b)
+       return fixCount(syscall.Write(f.fd, b))
 }
 
 // pwrite writes len(b) bytes to the File starting at byte offset off.
index 6bdc9be9dd3b185af4708190e668ed9c68137b9f..268a9e319f6758adfc0cac38cdb179f64c0795a0 100644 (file)
@@ -2502,10 +2502,21 @@ func TestAllocations(t *testing.T) {
        noAlloc(t, 100, func(j int) {
                var i interface{}
                var v Value
-               i = 42 + j
+
+               // We can uncomment this when compiler escape analysis
+               // is good enough to see that the integer assigned to i
+               // does not escape and therefore need not be allocated.
+               //
+               // i = 42 + j
+               // v = ValueOf(i)
+               // if int(v.Int()) != 42+j {
+               //      panic("wrong int")
+               // }
+
+               i = func(j int) int { return j }
                v = ValueOf(i)
-               if int(v.Int()) != 42+j {
-                       panic("wrong int")
+               if v.Interface().(func(int) int)(j) != j {
+                       panic("wrong result")
                }
        })
 }
@@ -2678,6 +2689,26 @@ func TestFuncArg(t *testing.T) {
        }
 }
 
+func TestStructArg(t *testing.T) {
+       type padded struct {
+               B string
+               C int32
+       }
+       var (
+               gotA  padded
+               gotB  uint32
+               wantA = padded{"3", 4}
+               wantB = uint32(5)
+       )
+       f := func(a padded, b uint32) {
+               gotA, gotB = a, b
+       }
+       ValueOf(f).Call([]Value{ValueOf(wantA), ValueOf(wantB)})
+       if gotA != wantA || gotB != wantB {
+               t.Errorf("function called with (%v, %v), want (%v, %v)", gotA, gotB, wantA, wantB)
+       }
+}
+
 var tagGetTests = []struct {
        Tag   StructTag
        Key   string
index 1072c7fabe6bd2a196584de26de4052271667c01..d89f7f6811daecb2b07ca9221e1fcc9b0a204d4a 100644 (file)
@@ -60,7 +60,7 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
 
        impl := &makeFuncImpl{code: code, stack: stack, typ: ftyp, fn: fn}
 
-       return Value{t, unsafe.Pointer(impl), flag(Func) << flagKindShift}
+       return Value{t, unsafe.Pointer(impl), flag(Func)}
 }
 
 // makeFuncStub is an assembly function that is the code half of
@@ -91,7 +91,7 @@ func makeMethodValue(op string, v Value) Value {
 
        // Ignoring the flagMethod bit, v describes the receiver, not the method type.
        fl := v.flag & (flagRO | flagAddr | flagIndir)
-       fl |= flag(v.typ.Kind()) << flagKindShift
+       fl |= flag(v.typ.Kind())
        rcvr := Value{v.typ, v.ptr, fl}
 
        // v.Type returns the actual type of the method value.
@@ -118,7 +118,7 @@ func makeMethodValue(op string, v Value) Value {
        // but we want Interface() and other operations to fail early.
        methodReceiver(op, fv.rcvr, fv.method)
 
-       return Value{funcType, unsafe.Pointer(fv), v.flag&flagRO | flag(Func)<<flagKindShift}
+       return Value{funcType, unsafe.Pointer(fv), v.flag&flagRO | flag(Func)}
 }
 
 // methodValueCall is an assembly function that is the code half of
index 26328e74b97907b7cffd0966fd0ac8c6d8fdea0e..2064922f6363e51767f27351a5bbfd5228547283 100644 (file)
@@ -490,7 +490,7 @@ func (t *uncommonType) Method(i int) (m Method) {
        if p.name != nil {
                m.Name = *p.name
        }
-       fl := flag(Func) << flagKindShift
+       fl := flag(Func)
        if p.pkgPath != nil {
                m.PkgPath = *p.pkgPath
                fl |= flagRO
@@ -1540,6 +1540,7 @@ func (gc *gcProg) appendProg(t *rtype) {
                for i := 0; i < c; i++ {
                        gc.appendProg(t.Field(i).Type.common())
                }
+               gc.align(uintptr(t.align))
        }
 }
 
index c6e8038eb3798483ebe082e6bd3250981523d222..43843e963a4a73e52ffd51fc0948b40a3ca1756b 100644 (file)
@@ -61,18 +61,17 @@ type Value struct {
 type flag uintptr
 
 const (
-       flagRO flag = 1 << iota
-       flagIndir
-       flagAddr
-       flagMethod
-       flagKindShift        = iota
        flagKindWidth        = 5 // there are 27 kinds
        flagKindMask    flag = 1<<flagKindWidth - 1
-       flagMethodShift      = flagKindShift + flagKindWidth
+       flagRO          flag = 1 << 5
+       flagIndir       flag = 1 << 6
+       flagAddr        flag = 1 << 7
+       flagMethod      flag = 1 << 8
+       flagMethodShift      = 9
 )
 
 func (f flag) kind() Kind {
-       return Kind((f >> flagKindShift) & flagKindMask)
+       return Kind(f & flagKindMask)
 }
 
 // pointer returns the underlying pointer represented by v.
@@ -107,14 +106,14 @@ func packEface(v Value) interface{} {
                        memmove(c, ptr, t.size)
                        ptr = c
                }
-               e.word = iword(ptr)
+               e.word = ptr
        case v.flag&flagIndir != 0:
                // Value is indirect, but interface is direct.  We need
                // to load the data at v.ptr into the interface data word.
-               e.word = iword(*(*unsafe.Pointer)(v.ptr))
+               e.word = *(*unsafe.Pointer)(v.ptr)
        default:
                // Value is direct, and so is the interface.
-               e.word = iword(v.ptr)
+               e.word = v.ptr
        }
        // Now, fill in the type portion.  We're very careful here not
        // to have any operation between the e.word and e.typ assignments
@@ -132,7 +131,7 @@ func unpackEface(i interface{}) Value {
        if t == nil {
                return Value{}
        }
-       f := flag(t.Kind()) << flagKindShift
+       f := flag(t.Kind())
        if ifaceIndir(t) {
                f |= flagIndir
        }
@@ -165,20 +164,10 @@ func methodName() string {
        return f.Name()
 }
 
-// An iword is the word that would be stored in an
-// interface to represent a given value v.  Specifically, if v is
-// bigger than a pointer, its word is a pointer to v's data.
-// Otherwise, its word holds the data stored
-// in its leading bytes (so is not a pointer).
-// This type is very dangerous for the garbage collector because
-// it must be treated conservatively.  We try to never expose it
-// to the GC here so that GC remains precise.
-type iword unsafe.Pointer
-
 // emptyInterface is the header for an interface{} value.
 type emptyInterface struct {
        typ  *rtype
-       word iword
+       word unsafe.Pointer
 }
 
 // nonEmptyInterface is the header for a interface value with methods.
@@ -192,7 +181,7 @@ type nonEmptyInterface struct {
                unused int32
                fun    [100000]unsafe.Pointer // method table
        }
-       word iword
+       word unsafe.Pointer
 }
 
 // mustBe panics if f's kind is not expected.
@@ -202,9 +191,8 @@ type nonEmptyInterface struct {
 // v.flag.mustBe(Bool), which will only bother to copy the
 // single important word for the receiver.
 func (f flag) mustBe(expected Kind) {
-       k := f.kind()
-       if k != expected {
-               panic(&ValueError{methodName(), k})
+       if f.kind() != expected {
+               panic(&ValueError{methodName(), f.kind()})
        }
 }
 
@@ -244,7 +232,7 @@ func (v Value) Addr() Value {
        if v.flag&flagAddr == 0 {
                panic("reflect.Value.Addr of unaddressable value")
        }
-       return Value{v.typ.ptrTo(), v.ptr, (v.flag & flagRO) | flag(Ptr)<<flagKindShift}
+       return Value{v.typ.ptrTo(), v.ptr, (v.flag & flagRO) | flag(Ptr)}
 }
 
 // Bool returns v's underlying value.
@@ -418,7 +406,7 @@ func (v Value) call(op string, in []Value) []Value {
                off = (off + a - 1) &^ (a - 1)
                n := targ.size
                addr := unsafe.Pointer(uintptr(args) + off)
-               v = v.assignTo("reflect.Value.Call", targ, (*interface{})(addr))
+               v = v.assignTo("reflect.Value.Call", targ, addr)
                if v.flag&flagIndir != 0 {
                        memmove(addr, v.ptr, n)
                } else {
@@ -442,7 +430,7 @@ func (v Value) call(op string, in []Value) []Value {
                tv := t.Out(i)
                a := uintptr(tv.Align())
                off = (off + a - 1) &^ (a - 1)
-               fl := flagIndir | flag(tv.Kind())<<flagKindShift
+               fl := flagIndir | flag(tv.Kind())
                ret[i] = Value{tv.common(), unsafe.Pointer(uintptr(args) + off), fl}
                off += tv.Size()
        }
@@ -474,7 +462,7 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
                typ := arg
                off += -off & uintptr(typ.align-1)
                addr := unsafe.Pointer(uintptr(ptr) + off)
-               v := Value{typ, nil, flag(typ.Kind()) << flagKindShift}
+               v := Value{typ, nil, flag(typ.Kind())}
                if ifaceIndir(typ) {
                        // value cannot be inlined in interface data.
                        // Must make a copy, because f might keep a reference to it,
@@ -537,7 +525,7 @@ func methodReceiver(op string, v Value, methodIndex int) (rcvrtype, t *rtype, fn
        i := methodIndex
        if v.typ.Kind() == Interface {
                tt := (*interfaceType)(unsafe.Pointer(v.typ))
-               if i < 0 || i >= len(tt.methods) {
+               if uint(i) >= uint(len(tt.methods)) {
                        panic("reflect: internal error: invalid method index")
                }
                m := &tt.methods[i]
@@ -554,7 +542,7 @@ func methodReceiver(op string, v Value, methodIndex int) (rcvrtype, t *rtype, fn
        } else {
                rcvrtype = v.typ
                ut := v.typ.uncommon()
-               if ut == nil || i < 0 || i >= len(ut.methods) {
+               if ut == nil || uint(i) >= uint(len(ut.methods)) {
                        panic("reflect: internal error: invalid method index")
                }
                m := &ut.methods[i]
@@ -652,7 +640,7 @@ func (v Value) Cap() int {
                // Slice is always bigger than a word; assume flagIndir.
                return (*sliceHeader)(v.ptr).Cap
        }
-       panic(&ValueError{"reflect.Value.Cap", k})
+       panic(&ValueError{"reflect.Value.Cap", v.kind()})
 }
 
 // Close closes the channel v.
@@ -673,7 +661,7 @@ func (v Value) Complex() complex128 {
        case Complex128:
                return *(*complex128)(v.ptr)
        }
-       panic(&ValueError{"reflect.Value.Complex", k})
+       panic(&ValueError{"reflect.Value.Complex", v.kind()})
 }
 
 // Elem returns the value that the interface v contains
@@ -709,42 +697,37 @@ func (v Value) Elem() Value {
                tt := (*ptrType)(unsafe.Pointer(v.typ))
                typ := tt.elem
                fl := v.flag&flagRO | flagIndir | flagAddr
-               fl |= flag(typ.Kind() << flagKindShift)
+               fl |= flag(typ.Kind())
                return Value{typ, ptr, fl}
        }
-       panic(&ValueError{"reflect.Value.Elem", k})
+       panic(&ValueError{"reflect.Value.Elem", v.kind()})
 }
 
 // Field returns the i'th field of the struct v.
 // It panics if v's Kind is not Struct or i is out of range.
 func (v Value) Field(i int) Value {
-       v.mustBe(Struct)
+       if v.kind() != Struct {
+               panic(&ValueError{"reflect.Value.Field", v.kind()})
+       }
        tt := (*structType)(unsafe.Pointer(v.typ))
-       if i < 0 || i >= len(tt.fields) {
+       if uint(i) >= uint(len(tt.fields)) {
                panic("reflect: Field index out of range")
        }
        field := &tt.fields[i]
        typ := field.typ
 
        // Inherit permission bits from v.
-       fl := v.flag & (flagRO | flagIndir | flagAddr)
+       fl := v.flag&(flagRO|flagIndir|flagAddr) | flag(typ.Kind())
        // Using an unexported field forces flagRO.
        if field.pkgPath != nil {
                fl |= flagRO
        }
-       fl |= flag(typ.Kind()) << flagKindShift
-
-       var ptr unsafe.Pointer
-       if fl&flagIndir != 0 {
-               // Indirect.  Just bump pointer.
-               ptr = unsafe.Pointer(uintptr(v.ptr) + field.offset)
-       } else {
-               if field.offset != 0 {
-                       panic("field access of ptr value isn't at offset 0")
-               }
-               ptr = v.ptr
-       }
-
+       // Either flagIndir is set and v.ptr points at struct,
+       // or flagIndir is not set and v.ptr is the actual struct data.
+       // In the former case, we want v.ptr + offset.
+       // In the latter case, we must be have field.offset = 0,
+       // so v.ptr + field.offset is still okay.
+       ptr := unsafe.Pointer(uintptr(v.ptr) + field.offset)
        return Value{typ, ptr, fl}
 }
 
@@ -785,7 +768,6 @@ func (v Value) FieldByName(name string) Value {
 // It panics if v's Kind is not struct.
 // It returns the zero Value if no field was found.
 func (v Value) FieldByNameFunc(match func(string) bool) Value {
-       v.mustBe(Struct)
        if f, ok := v.typ.FieldByNameFunc(match); ok {
                return v.FieldByIndex(f.Index)
        }
@@ -802,7 +784,7 @@ func (v Value) Float() float64 {
        case Float64:
                return *(*float64)(v.ptr)
        }
-       panic(&ValueError{"reflect.Value.Float", k})
+       panic(&ValueError{"reflect.Value.Float", v.kind()})
 }
 
 var uint8Type = TypeOf(uint8(0)).(*rtype)
@@ -810,60 +792,47 @@ var uint8Type = TypeOf(uint8(0)).(*rtype)
 // Index returns v's i'th element.
 // It panics if v's Kind is not Array, Slice, or String or i is out of range.
 func (v Value) Index(i int) Value {
-       k := v.kind()
-       switch k {
+       switch v.kind() {
        case Array:
                tt := (*arrayType)(unsafe.Pointer(v.typ))
-               if i < 0 || i > int(tt.len) {
+               if uint(i) >= uint(tt.len) {
                        panic("reflect: array index out of range")
                }
                typ := tt.elem
-               fl := v.flag & (flagRO | flagIndir | flagAddr) // bits same as overall array
-               fl |= flag(typ.Kind()) << flagKindShift
                offset := uintptr(i) * typ.size
 
-               var val unsafe.Pointer
-               if fl&flagIndir != 0 {
-                       // Indirect.  Just bump pointer.
-                       val = unsafe.Pointer(uintptr(v.ptr) + offset)
-               } else {
-                       if offset != 0 {
-                               // This is an array stored inline in an interface value.
-                               // And the array element type has pointers.
-                               // Since the inline storage space is only a single word,
-                               // this implies we must be holding an array of length 1
-                               // with an element type that is a single pointer.
-                               // If the offset is not 0, something has gone wrong.
-                               panic("reflect: internal error: unexpected array index")
-                       }
-                       val = v.ptr
-               }
+               // Either flagIndir is set and v.ptr points at array,
+               // or flagIndir is not set and v.ptr is the actual array data.
+               // In the former case, we want v.ptr + offset.
+               // In the latter case, we must be doing Index(0), so offset = 0,
+               // so v.ptr + offset is still okay.
+               val := unsafe.Pointer(uintptr(v.ptr) + offset)
+               fl := v.flag&(flagRO|flagIndir|flagAddr) | flag(typ.Kind()) // bits same as overall array
                return Value{typ, val, fl}
 
        case Slice:
                // Element flag same as Elem of Ptr.
                // Addressable, indirect, possibly read-only.
-               fl := flagAddr | flagIndir | v.flag&flagRO
                s := (*sliceHeader)(v.ptr)
-               if i < 0 || i >= s.Len {
+               if uint(i) >= uint(s.Len) {
                        panic("reflect: slice index out of range")
                }
                tt := (*sliceType)(unsafe.Pointer(v.typ))
                typ := tt.elem
-               fl |= flag(typ.Kind()) << flagKindShift
                val := unsafe.Pointer(uintptr(s.Data) + uintptr(i)*typ.size)
+               fl := flagAddr | flagIndir | v.flag&flagRO | flag(typ.Kind())
                return Value{typ, val, fl}
 
        case String:
-               fl := v.flag&flagRO | flag(Uint8<<flagKindShift) | flagIndir
                s := (*stringHeader)(v.ptr)
-               if i < 0 || i >= s.Len {
+               if uint(i) >= uint(s.Len) {
                        panic("reflect: string index out of range")
                }
                p := unsafe.Pointer(uintptr(s.Data) + uintptr(i))
+               fl := v.flag&flagRO | flag(Uint8) | flagIndir
                return Value{uint8Type, p, fl}
        }
-       panic(&ValueError{"reflect.Value.Index", k})
+       panic(&ValueError{"reflect.Value.Index", v.kind()})
 }
 
 // Int returns v's underlying value, as an int64.
@@ -883,7 +852,7 @@ func (v Value) Int() int64 {
        case Int64:
                return int64(*(*int64)(p))
        }
-       panic(&ValueError{"reflect.Value.Int", k})
+       panic(&ValueError{"reflect.Value.Int", v.kind()})
 }
 
 // CanInterface returns true if Interface can be used without panicking.
@@ -970,7 +939,7 @@ func (v Value) IsNil() bool {
                // Both are always bigger than a word; assume flagIndir.
                return *(*unsafe.Pointer)(v.ptr) == nil
        }
-       panic(&ValueError{"reflect.Value.IsNil", k})
+       panic(&ValueError{"reflect.Value.IsNil", v.kind()})
 }
 
 // IsValid returns true if v represents a value.
@@ -1007,7 +976,7 @@ func (v Value) Len() int {
                // String is bigger than a word; assume flagIndir.
                return (*stringHeader)(v.ptr).Len
        }
-       panic(&ValueError{"reflect.Value.Len", k})
+       panic(&ValueError{"reflect.Value.Len", v.kind()})
 }
 
 // MapIndex returns the value associated with key in the map v.
@@ -1039,7 +1008,7 @@ func (v Value) MapIndex(key Value) Value {
        }
        typ := tt.elem
        fl := (v.flag | key.flag) & flagRO
-       fl |= flag(typ.Kind()) << flagKindShift
+       fl |= flag(typ.Kind())
        if ifaceIndir(typ) {
                // Copy result so future changes to the map
                // won't change the underlying value.
@@ -1060,7 +1029,7 @@ func (v Value) MapKeys() []Value {
        tt := (*mapType)(unsafe.Pointer(v.typ))
        keyType := tt.key
 
-       fl := v.flag&flagRO | flag(keyType.Kind())<<flagKindShift
+       fl := v.flag&flagRO | flag(keyType.Kind())
 
        m := v.pointer()
        mlen := int(0)
@@ -1100,14 +1069,14 @@ func (v Value) Method(i int) Value {
        if v.typ == nil {
                panic(&ValueError{"reflect.Value.Method", Invalid})
        }
-       if v.flag&flagMethod != 0 || i < 0 || i >= v.typ.NumMethod() {
+       if v.flag&flagMethod != 0 || uint(i) >= uint(v.typ.NumMethod()) {
                panic("reflect: Method index out of range")
        }
        if v.typ.Kind() == Interface && v.IsNil() {
                panic("reflect: Method on nil interface value")
        }
        fl := v.flag & (flagRO | flagIndir)
-       fl |= flag(Func) << flagKindShift
+       fl |= flag(Func)
        fl |= flag(i)<<flagMethodShift | flagMethod
        return Value{v.typ, v.ptr, fl}
 }
@@ -1160,7 +1129,7 @@ func (v Value) OverflowComplex(x complex128) bool {
        case Complex128:
                return false
        }
-       panic(&ValueError{"reflect.Value.OverflowComplex", k})
+       panic(&ValueError{"reflect.Value.OverflowComplex", v.kind()})
 }
 
 // OverflowFloat returns true if the float64 x cannot be represented by v's type.
@@ -1173,7 +1142,7 @@ func (v Value) OverflowFloat(x float64) bool {
        case Float64:
                return false
        }
-       panic(&ValueError{"reflect.Value.OverflowFloat", k})
+       panic(&ValueError{"reflect.Value.OverflowFloat", v.kind()})
 }
 
 func overflowFloat32(x float64) bool {
@@ -1193,7 +1162,7 @@ func (v Value) OverflowInt(x int64) bool {
                trunc := (x << (64 - bitSize)) >> (64 - bitSize)
                return x != trunc
        }
-       panic(&ValueError{"reflect.Value.OverflowInt", k})
+       panic(&ValueError{"reflect.Value.OverflowInt", v.kind()})
 }
 
 // OverflowUint returns true if the uint64 x cannot be represented by v's type.
@@ -1206,7 +1175,7 @@ func (v Value) OverflowUint(x uint64) bool {
                trunc := (x << (64 - bitSize)) >> (64 - bitSize)
                return x != trunc
        }
-       panic(&ValueError{"reflect.Value.OverflowUint", k})
+       panic(&ValueError{"reflect.Value.OverflowUint", v.kind()})
 }
 
 // Pointer returns v's value as a uintptr.
@@ -1251,7 +1220,7 @@ func (v Value) Pointer() uintptr {
        case Slice:
                return (*SliceHeader)(v.ptr).Data
        }
-       panic(&ValueError{"reflect.Value.Pointer", k})
+       panic(&ValueError{"reflect.Value.Pointer", v.kind()})
 }
 
 // Recv receives and returns a value from the channel v.
@@ -1273,7 +1242,7 @@ func (v Value) recv(nb bool) (val Value, ok bool) {
                panic("reflect: recv on send-only channel")
        }
        t := tt.elem
-       val = Value{t, nil, flag(t.Kind()) << flagKindShift}
+       val = Value{t, nil, flag(t.Kind())}
        var p unsafe.Pointer
        if ifaceIndir(t) {
                p = unsafe_New(t)
@@ -1322,9 +1291,9 @@ func (v Value) send(x Value, nb bool) (selected bool) {
 func (v Value) Set(x Value) {
        v.mustBeAssignable()
        x.mustBeExported() // do not let unexported x leak
-       var target *interface{}
+       var target unsafe.Pointer
        if v.kind() == Interface {
-               target = (*interface{})(v.ptr)
+               target = v.ptr
        }
        x = x.assignTo("reflect.Set", v.typ, target)
        if x.flag&flagIndir != 0 {
@@ -1370,7 +1339,7 @@ func (v Value) SetComplex(x complex128) {
        v.mustBeAssignable()
        switch k := v.kind(); k {
        default:
-               panic(&ValueError{"reflect.Value.SetComplex", k})
+               panic(&ValueError{"reflect.Value.SetComplex", v.kind()})
        case Complex64:
                *(*complex64)(v.ptr) = complex64(x)
        case Complex128:
@@ -1384,7 +1353,7 @@ func (v Value) SetFloat(x float64) {
        v.mustBeAssignable()
        switch k := v.kind(); k {
        default:
-               panic(&ValueError{"reflect.Value.SetFloat", k})
+               panic(&ValueError{"reflect.Value.SetFloat", v.kind()})
        case Float32:
                *(*float32)(v.ptr) = float32(x)
        case Float64:
@@ -1398,7 +1367,7 @@ func (v Value) SetInt(x int64) {
        v.mustBeAssignable()
        switch k := v.kind(); k {
        default:
-               panic(&ValueError{"reflect.Value.SetInt", k})
+               panic(&ValueError{"reflect.Value.SetInt", v.kind()})
        case Int:
                *(*int)(v.ptr) = int(x)
        case Int8:
@@ -1419,7 +1388,7 @@ func (v Value) SetLen(n int) {
        v.mustBeAssignable()
        v.mustBe(Slice)
        s := (*sliceHeader)(v.ptr)
-       if n < 0 || n > int(s.Cap) {
+       if uint(n) > uint(s.Cap) {
                panic("reflect: slice length out of range in SetLen")
        }
        s.Len = n
@@ -1477,7 +1446,7 @@ func (v Value) SetUint(x uint64) {
        v.mustBeAssignable()
        switch k := v.kind(); k {
        default:
-               panic(&ValueError{"reflect.Value.SetUint", k})
+               panic(&ValueError{"reflect.Value.SetUint", v.kind()})
        case Uint:
                *(*uint)(v.ptr) = uint(x)
        case Uint8:
@@ -1520,7 +1489,7 @@ func (v Value) Slice(i, j int) Value {
        )
        switch kind := v.kind(); kind {
        default:
-               panic(&ValueError{"reflect.Value.Slice", kind})
+               panic(&ValueError{"reflect.Value.Slice", v.kind()})
 
        case Array:
                if v.flag&flagAddr == 0 {
@@ -1564,7 +1533,7 @@ func (v Value) Slice(i, j int) Value {
                s.Data = base
        }
 
-       fl := v.flag&flagRO | flagIndir | flag(Slice)<<flagKindShift
+       fl := v.flag&flagRO | flagIndir | flag(Slice)
        return Value{typ.common(), unsafe.Pointer(&x), fl}
 }
 
@@ -1579,7 +1548,7 @@ func (v Value) Slice3(i, j, k int) Value {
        )
        switch kind := v.kind(); kind {
        default:
-               panic(&ValueError{"reflect.Value.Slice3", kind})
+               panic(&ValueError{"reflect.Value.Slice3", v.kind()})
 
        case Array:
                if v.flag&flagAddr == 0 {
@@ -1616,7 +1585,7 @@ func (v Value) Slice3(i, j, k int) Value {
                s.Data = base
        }
 
-       fl := v.flag&flagRO | flagIndir | flag(Slice)<<flagKindShift
+       fl := v.flag&flagRO | flagIndir | flag(Slice)
        return Value{typ.common(), unsafe.Pointer(&x), fl}
 }
 
@@ -1674,7 +1643,7 @@ func (v Value) Type() Type {
        if v.typ.Kind() == Interface {
                // Method on interface.
                tt := (*interfaceType)(unsafe.Pointer(v.typ))
-               if i < 0 || i >= len(tt.methods) {
+               if uint(i) >= uint(len(tt.methods)) {
                        panic("reflect: internal error: invalid method index")
                }
                m := &tt.methods[i]
@@ -1682,7 +1651,7 @@ func (v Value) Type() Type {
        }
        // Method on concrete type.
        ut := v.typ.uncommon()
-       if ut == nil || i < 0 || i >= len(ut.methods) {
+       if ut == nil || uint(i) >= uint(len(ut.methods)) {
                panic("reflect: internal error: invalid method index")
        }
        m := &ut.methods[i]
@@ -1708,7 +1677,7 @@ func (v Value) Uint() uint64 {
        case Uintptr:
                return uint64(*(*uintptr)(p))
        }
-       panic(&ValueError{"reflect.Value.Uint", k})
+       panic(&ValueError{"reflect.Value.Uint", v.kind()})
 }
 
 // UnsafeAddr returns a pointer to v's data.
@@ -1998,7 +1967,7 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) {
                tt := (*chanType)(unsafe.Pointer(runcases[chosen].typ))
                t := tt.elem
                p := runcases[chosen].val
-               fl := flag(t.Kind()) << flagKindShift
+               fl := flag(t.Kind())
                if ifaceIndir(t) {
                        recv = Value{t, p, fl | flagIndir}
                } else {
@@ -2033,7 +2002,7 @@ func MakeSlice(typ Type, len, cap int) Value {
        }
 
        s := sliceHeader{unsafe_NewArray(typ.Elem().(*rtype), cap), len, cap}
-       return Value{typ.common(), unsafe.Pointer(&s), flagIndir | flag(Slice)<<flagKindShift}
+       return Value{typ.common(), unsafe.Pointer(&s), flagIndir | flag(Slice)}
 }
 
 // MakeChan creates a new channel with the specified type and buffer size.
@@ -2048,7 +2017,7 @@ func MakeChan(typ Type, buffer int) Value {
                panic("reflect.MakeChan: unidirectional channel type")
        }
        ch := makechan(typ.(*rtype), uint64(buffer))
-       return Value{typ.common(), ch, flag(Chan) << flagKindShift}
+       return Value{typ.common(), ch, flag(Chan)}
 }
 
 // MakeMap creates a new map of the specified type.
@@ -2057,7 +2026,7 @@ func MakeMap(typ Type) Value {
                panic("reflect.MakeMap of non-map type")
        }
        m := makemap(typ.(*rtype))
-       return Value{typ.common(), m, flag(Map) << flagKindShift}
+       return Value{typ.common(), m, flag(Map)}
 }
 
 // Indirect returns the value that v points to.
@@ -2097,7 +2066,7 @@ func Zero(typ Type) Value {
                panic("reflect: Zero(nil)")
        }
        t := typ.common()
-       fl := flag(t.Kind()) << flagKindShift
+       fl := flag(t.Kind())
        if ifaceIndir(t) {
                return Value{t, unsafe_New(typ.(*rtype)), fl | flagIndir}
        }
@@ -2111,21 +2080,21 @@ func New(typ Type) Value {
                panic("reflect: New(nil)")
        }
        ptr := unsafe_New(typ.(*rtype))
-       fl := flag(Ptr) << flagKindShift
+       fl := flag(Ptr)
        return Value{typ.common().ptrTo(), ptr, fl}
 }
 
 // NewAt returns a Value representing a pointer to a value of the
 // specified type, using p as that pointer.
 func NewAt(typ Type, p unsafe.Pointer) Value {
-       fl := flag(Ptr) << flagKindShift
+       fl := flag(Ptr)
        return Value{typ.common().ptrTo(), p, fl}
 }
 
 // assignTo returns a value v that can be assigned directly to typ.
 // It panics if v is not assignable to typ.
 // For a conversion to an interface type, target is a suggested scratch space to use.
-func (v Value) assignTo(context string, dst *rtype, target *interface{}) Value {
+func (v Value) assignTo(context string, dst *rtype, target unsafe.Pointer) Value {
        if v.flag&flagMethod != 0 {
                v = makeMethodValue(context, v)
        }
@@ -2136,20 +2105,20 @@ func (v Value) assignTo(context string, dst *rtype, target *interface{}) Value {
                // Same memory layout, so no harm done.
                v.typ = dst
                fl := v.flag & (flagRO | flagAddr | flagIndir)
-               fl |= flag(dst.Kind()) << flagKindShift
+               fl |= flag(dst.Kind())
                return Value{dst, v.ptr, fl}
 
        case implements(dst, v.typ):
                if target == nil {
-                       target = new(interface{})
+                       target = unsafe_New(dst)
                }
                x := valueInterface(v, false)
                if dst.NumMethod() == 0 {
-                       *target = x
+                       *(*interface{})(target) = x
                } else {
-                       ifaceE2I(dst, x, unsafe.Pointer(target))
+                       ifaceE2I(dst, x, target)
                }
-               return Value{dst, unsafe.Pointer(target), flagIndir | flag(Interface)<<flagKindShift}
+               return Value{dst, target, flagIndir | flag(Interface)}
        }
 
        // Failed.
@@ -2268,7 +2237,7 @@ func makeInt(f flag, bits uint64, t Type) Value {
        case 8:
                *(*uint64)(unsafe.Pointer(ptr)) = bits
        }
-       return Value{typ, ptr, f | flagIndir | flag(typ.Kind())<<flagKindShift}
+       return Value{typ, ptr, f | flagIndir | flag(typ.Kind())}
 }
 
 // makeFloat returns a Value of type t equal to v (possibly truncated to float32),
@@ -2282,7 +2251,7 @@ func makeFloat(f flag, v float64, t Type) Value {
        case 8:
                *(*float64)(unsafe.Pointer(ptr)) = v
        }
-       return Value{typ, ptr, f | flagIndir | flag(typ.Kind())<<flagKindShift}
+       return Value{typ, ptr, f | flagIndir | flag(typ.Kind())}
 }
 
 // makeComplex returns a Value of type t equal to v (possibly truncated to complex64),
@@ -2296,7 +2265,7 @@ func makeComplex(f flag, v complex128, t Type) Value {
        case 16:
                *(*complex128)(unsafe.Pointer(ptr)) = v
        }
-       return Value{typ, ptr, f | flagIndir | flag(typ.Kind())<<flagKindShift}
+       return Value{typ, ptr, f | flagIndir | flag(typ.Kind())}
 }
 
 func makeString(f flag, v string, t Type) Value {
@@ -2412,14 +2381,14 @@ func cvtDirect(v Value, typ Type) Value {
 
 // convertOp: concrete -> interface
 func cvtT2I(v Value, typ Type) Value {
-       target := new(interface{})
+       target := unsafe_New(typ.common())
        x := valueInterface(v, false)
        if typ.NumMethod() == 0 {
-               *target = x
+               *(*interface{})(target) = x
        } else {
-               ifaceE2I(typ.(*rtype), x, unsafe.Pointer(target))
+               ifaceE2I(typ.(*rtype), x, target)
        }
-       return Value{typ.common(), unsafe.Pointer(target), v.flag&flagRO | flagIndir | flag(Interface)<<flagKindShift}
+       return Value{typ.common(), target, v.flag&flagRO | flagIndir | flag(Interface)}
 }
 
 // convertOp: interface -> interface
index 5fadb67c0980502345180cd89ccae6cf08933987..01ea3742a8b47bf0f09ed77cf17e27160651d262 100644 (file)
@@ -6,6 +6,7 @@ package regexp
 
 import (
        "reflect"
+       "regexp/syntax"
        "strings"
        "testing"
 )
@@ -473,12 +474,19 @@ func TestSplit(t *testing.T) {
        }
 }
 
-// This ran out of stack before issue 7608 was fixed.
+// Check that one-pass cutoff does trigger.
 func TestOnePassCutoff(t *testing.T) {
-       if testing.Short() {
-               t.Skip("Skipping in short mode")
+       re, err := syntax.Parse(`^x{1,1000}y{1,1000}$`, syntax.Perl)
+       if err != nil {
+               t.Fatalf("parse: %v", err)
+       }
+       p, err := syntax.Compile(re.Simplify())
+       if err != nil {
+               t.Fatalf("compile: %v", err)
+       }
+       if compileOnePass(p) != notOnePass {
+               t.Fatalf("makeOnePass succeeded; wanted notOnePass")
        }
-       MustCompile(`^(?:x{1,1000}){1,1000}$`)
 }
 
 func BenchmarkLiteral(b *testing.B) {
index 0b8336a04fbba9be3168ae2762892f4113267b0a..b615acdf0e54f2db8cac515ab41bf81d76cf520d 100644 (file)
@@ -452,7 +452,7 @@ func (re *Regexp) ReplaceAllString(src, repl string) string {
        return string(b)
 }
 
-// ReplaceAllStringLiteral returns a copy of src, replacing matches of the Regexp
+// ReplaceAllLiteralString returns a copy of src, replacing matches of the Regexp
 // with the replacement string repl.  The replacement repl is substituted directly,
 // without using Expand.
 func (re *Regexp) ReplaceAllLiteralString(src, repl string) string {
index 3dc8ccf503a5e20fea7c237f78796ef30ae45698..d579a4069b16021b11438e9d04543c2d6c68d028 100644 (file)
@@ -272,13 +272,18 @@ func (p *parser) repeat(op Op, min, max int, before, after, lastRepeat string) (
 func repeatIsValid(re *Regexp, n int) bool {
        if re.Op == OpRepeat {
                m := re.Max
+               if m == 0 {
+                       return true
+               }
                if m < 0 {
                        m = re.Min
                }
                if m > n {
                        return false
                }
-               n /= m
+               if m > 0 {
+                       n /= m
+               }
        }
        for _, sub := range re.Sub {
                if !repeatIsValid(sub, n) {
index b0ed2d8ceb785e278dd24cb849f6d60d8c79803e..0d46a9eff78035a6fca583a0f4b6800c32cabcde 100644 (file)
@@ -732,6 +732,20 @@ needm:
        MOVL    g(CX), BP
        MOVL    g_m(BP), BP
 
+       // Set m->sched.sp = SP, so that if a panic happens
+       // during the function we are about to execute, it will
+       // have a valid SP to run on the g0 stack.
+       // The next few lines (after the havem label)
+       // will save this SP onto the stack and then write
+       // the same SP back to m->sched.sp. That seems redundant,
+       // but if an unrecovered panic happens, unwindm will
+       // restore the g->sched.sp from the stack location
+       // and then onM will try to use it. If we don't set it here,
+       // that restored SP will be uninitialized (typically 0) and
+       // will not be usable.
+       MOVL    m_g0(BP), SI
+       MOVL    SP, (g_sched+gobuf_sp)(SI)
+
 havem:
        // Now there's a valid m, and we're running on its m->g0.
        // Save current m->g0->sched.sp on stack and then set it to SP.
@@ -871,12 +885,6 @@ TEXT runtime·cputicks(SB),NOSPLIT,$0-8
        MOVL    DX, ret_hi+4(FP)
        RET
 
-TEXT runtime·gocputicks(SB),NOSPLIT,$0-8
-       RDTSC
-       MOVL    AX, ret_lo+0(FP)
-       MOVL    DX, ret_hi+4(FP)
-       RET
-
 TEXT runtime·ldt0setup(SB),NOSPLIT,$16-0
        // set up ldt 7 to point at tls0
        // ldt 1 would be fine on Linux, but on OS X, 7 is as low as we can go.
index 2ee3312086133b8ce47d557b42c7b6a287aa312c..a9b082beb82a66f28d9e808166f66e334415de3e 100644 (file)
@@ -717,6 +717,20 @@ needm:
        get_tls(CX)
        MOVQ    g(CX), BP
        MOVQ    g_m(BP), BP
+       
+       // Set m->sched.sp = SP, so that if a panic happens
+       // during the function we are about to execute, it will
+       // have a valid SP to run on the g0 stack.
+       // The next few lines (after the havem label)
+       // will save this SP onto the stack and then write
+       // the same SP back to m->sched.sp. That seems redundant,
+       // but if an unrecovered panic happens, unwindm will
+       // restore the g->sched.sp from the stack location
+       // and then onM will try to use it. If we don't set it here,
+       // that restored SP will be uninitialized (typically 0) and
+       // will not be usable.
+       MOVQ    m_g0(BP), SI
+       MOVQ    SP, (g_sched+gobuf_sp)(SI)
 
 havem:
        // Now there's a valid m, and we're running on its m->g0.
@@ -855,13 +869,6 @@ TEXT runtime·cputicks(SB),NOSPLIT,$0-0
        MOVQ    AX, ret+0(FP)
        RET
 
-TEXT runtime·gocputicks(SB),NOSPLIT,$0-8
-       RDTSC
-       SHLQ    $32, DX
-       ADDQ    DX, AX
-       MOVQ    AX, ret+0(FP)
-       RET
-
 // hash function using AES hardware instructions
 TEXT runtime·aeshash(SB),NOSPLIT,$0-32
        MOVQ    p+0(FP), AX     // ptr to data
index e27f67e1eecb54b5cc2c05d712411e6f00263329..28875bc55a146a4e386b68c58f4731f3de0288ea 100644 (file)
@@ -657,13 +657,6 @@ TEXT runtime·cputicks(SB),NOSPLIT,$0-0
        MOVQ    AX, ret+0(FP)
        RET
 
-TEXT runtime·gocputicks(SB),NOSPLIT,$0-8
-       RDTSC
-       SHLQ    $32, DX
-       ADDQ    DX, AX
-       MOVQ    AX, ret+0(FP)
-       RET
-
 // hash function using AES hardware instructions
 // For now, our one amd64p32 system (NaCl) does not
 // support using AES instructions, so have not bothered to
index b21441488a6e77c39e867bd2093d536a1f132fa9..e94b4c1ff61560f3424b45ff0dc9c758980e1dae 100644 (file)
@@ -556,6 +556,21 @@ TEXT       Â·cgocallback_gofunc(SB),NOSPLIT,$8-12
        MOVW    $runtime·needm(SB), R0
        BL      (R0)
 
+       // Set m->sched.sp = SP, so that if a panic happens
+       // during the function we are about to execute, it will
+       // have a valid SP to run on the g0 stack.
+       // The next few lines (after the havem label)
+       // will save this SP onto the stack and then write
+       // the same SP back to m->sched.sp. That seems redundant,
+       // but if an unrecovered panic happens, unwindm will
+       // restore the g->sched.sp from the stack location
+       // and then onM will try to use it. If we don't set it here,
+       // that restored SP will be uninitialized (typically 0) and
+       // will not be usable.
+       MOVW    g_m(g), R8
+       MOVW    m_g0(R8), R3
+       MOVW    R13, (g_sched+gobuf_sp)(R3)
+
 havem:
        MOVW    g_m(g), R8
        MOVW    R8, savedm-4(SP)
@@ -1275,9 +1290,6 @@ TEXT runtime·fastrand1(SB),NOSPLIT,$-4-4
        MOVW    R0, ret+0(FP)
        RET
 
-TEXT runtime·gocputicks(SB),NOSPLIT,$0
-       B runtime·cputicks(SB)
-
 TEXT runtime·return0(SB),NOSPLIT,$0
        MOVW    $0, R0
        RET
index 2e4b3528ba29d62179f75739933c8e724a4248bb..d5833bfad01bdc8445fe6cd0a7c51fdd09d03776 100644 (file)
 #define EXT(s) s
 #endif
 
-/*
- * Because the assembler might target an earlier revision of the ISA
- * by default, we must explicitly specify the ISA revision to ensure
- * BLX is recognized as a valid instruction.
- */    
-.arch armv5t
-
 /*
  * void crosscall_arm1(void (*fn)(void), void (*setg_gcc)(void *g), void *g)
  *
@@ -31,8 +24,12 @@ EXT(crosscall_arm1):
        mov r4, r0
        mov r5, r1
        mov r0, r2
-       blx r5 // setg(g) 
-       blx r4 // fn() 
+
+       // Because the assembler might target an earlier revision of the ISA
+       // by default, we encode BLX as a .word.
+       .word 0xe12fff35 // blx r5 // setg(g)
+       .word 0xe12fff34 // blx r4 // fn()
+
        pop {r4, r5, r6, r7, r8, r9, r10, r11, ip, pc}
 
 .globl EXT(__stack_chk_fail_local)
index 01632892ed2de8a1b69a31322bfc5720f74506d4..e689ceaed1e1b2eecebfad8bb37c4ed15e41d39c 100644 (file)
@@ -482,6 +482,35 @@ func TestShrinkStackDuringBlockedSend(t *testing.T) {
        <-done
 }
 
+func TestSelectDuplicateChannel(t *testing.T) {
+       // This test makes sure we can queue a G on
+       // the same channel multiple times.
+       c := make(chan int)
+       d := make(chan int)
+       e := make(chan int)
+
+       // goroutine A
+       go func() {
+               select {
+               case <-c:
+               case <-c:
+               case <-d:
+               }
+               e <- 9
+       }()
+       time.Sleep(time.Millisecond) // make sure goroutine A gets qeueued first on c
+
+       // goroutine B
+       go func() {
+               <-c
+       }()
+       time.Sleep(time.Millisecond) // make sure goroutine B gets queued on c before continuing
+
+       d <- 7 // wake up A, it dequeues itself from c.  This operation used to corrupt c.recvq.
+       <-e    // A tells us it's done
+       c <- 8 // wake up B.  This operation used to fail because c.recvq was corrupted (it tries to wake up an already running G instead of B)
+}
+
 func BenchmarkChanNonblocking(b *testing.B) {
        myc := make(chan int)
        b.RunParallel(func(pb *testing.PB) {
index 4ff0084c2286776900ac543f792a0ad5c93ad363..5958ad8914637f9ddacc31b489638c0c8b7f0f3c 100644 (file)
@@ -8,6 +8,7 @@ package runtime_test
 
 import (
        "runtime"
+       "strings"
        "testing"
 )
 
@@ -34,6 +35,17 @@ func TestCgoTraceback(t *testing.T) {
        }
 }
 
+func TestCgoExternalThreadPanic(t *testing.T) {
+       if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+               t.Skipf("no pthreads on %s", runtime.GOOS)
+       }
+       got := executeTest(t, cgoExternalThreadPanicSource, nil, "main.c", cgoExternalThreadPanicC)
+       want := "panic: BOOM"
+       if !strings.Contains(got, want) {
+               t.Fatalf("want failure containing %q. output:\n%s\n", want, got)
+       }
+}
+
 const cgoSignalDeadlockSource = `
 package main
 
@@ -117,3 +129,43 @@ func main() {
        fmt.Printf("OK\n")
 }
 `
+
+const cgoExternalThreadPanicSource = `
+package main
+
+// void start(void);
+import "C"
+
+func main() {
+       C.start()
+       select {}
+}
+
+//export gopanic
+func gopanic() {
+       panic("BOOM")
+}
+`
+
+const cgoExternalThreadPanicC = `
+#include <stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+
+void gopanic(void);
+
+static void*
+die(void* x)
+{
+       gopanic();
+       return 0;
+}
+
+void
+start(void)
+{
+       pthread_t t;
+       if(pthread_create(&t, 0, die, 0) != 0)
+               printf("pthread_create failed\n");
+}
+`
index 783b4c48f521f9aa593f4bff03f0269ad9232417..211a0476fd51eef065946c6837cd2a5959f71e8a 100644 (file)
@@ -31,7 +31,7 @@ func testEnv(cmd *exec.Cmd) *exec.Cmd {
        return cmd
 }
 
-func executeTest(t *testing.T, templ string, data interface{}) string {
+func executeTest(t *testing.T, templ string, data interface{}, extra ...string) string {
        switch runtime.GOOS {
        case "android", "nacl":
                t.Skipf("skipping on %s", runtime.GOOS)
@@ -61,7 +61,20 @@ func executeTest(t *testing.T, templ string, data interface{}) string {
                t.Fatalf("failed to close file: %v", err)
        }
 
-       got, _ := testEnv(exec.Command("go", "run", src)).CombinedOutput()
+       for i := 0; i < len(extra); i += 2 {
+               if err := ioutil.WriteFile(filepath.Join(dir, extra[i]), []byte(extra[i+1]), 0666); err != nil {
+                       t.Fatal(err)
+               }
+       }
+
+       cmd := exec.Command("go", "build", "-o", "a.exe")
+       cmd.Dir = dir
+       out, err := testEnv(cmd).CombinedOutput()
+       if err != nil {
+               t.Fatalf("building source: %v\n%s", err, out)
+       }
+
+       got, _ := testEnv(exec.Command(filepath.Join(dir, "a.exe"))).CombinedOutput()
        return string(got)
 }
 
index 30994f21962ad7fb08b99988d5dee0f059ae4b99..4a77dcfcd689d40bbc6fddb1a67543e9bbabd4d9 100644 (file)
@@ -16,6 +16,7 @@ type GCStats struct {
        NumGC          int64           // number of garbage collections
        PauseTotal     time.Duration   // total pause for all collections
        Pause          []time.Duration // pause history, most recent first
+       PauseEnd       []time.Time     // pause end times history, most recent first
        PauseQuantiles []time.Duration
 }
 
@@ -30,25 +31,36 @@ type GCStats struct {
 func ReadGCStats(stats *GCStats) {
        // Create a buffer with space for at least two copies of the
        // pause history tracked by the runtime. One will be returned
-       // to the caller and the other will be used as a temporary buffer
-       // for computing quantiles.
+       // to the caller and the other will be used as transfer buffer
+       // for end times history and as a temporary buffer for
+       // computing quantiles.
        const maxPause = len(((*runtime.MemStats)(nil)).PauseNs)
-       if cap(stats.Pause) < 2*maxPause {
-               stats.Pause = make([]time.Duration, 2*maxPause)
+       if cap(stats.Pause) < 2*maxPause+3 {
+               stats.Pause = make([]time.Duration, 2*maxPause+3)
        }
 
-       // readGCStats fills in the pause history (up to maxPause entries)
-       // and then three more: Unix ns time of last GC, number of GC,
-       // and total pause time in nanoseconds. Here we depend on the
-       // fact that time.Duration's native unit is nanoseconds, so the
-       // pauses and the total pause time do not need any conversion.
+       // readGCStats fills in the pause and end times histories (up to
+       // maxPause entries) and then three more: Unix ns time of last GC,
+       // number of GC, and total pause time in nanoseconds. Here we
+       // depend on the fact that time.Duration's native unit is
+       // nanoseconds, so the pauses and the total pause time do not need
+       // any conversion.
        readGCStats(&stats.Pause)
        n := len(stats.Pause) - 3
        stats.LastGC = time.Unix(0, int64(stats.Pause[n]))
        stats.NumGC = int64(stats.Pause[n+1])
        stats.PauseTotal = stats.Pause[n+2]
+       n /= 2 // buffer holds pauses and end times
        stats.Pause = stats.Pause[:n]
 
+       if cap(stats.PauseEnd) < maxPause {
+               stats.PauseEnd = make([]time.Time, 0, maxPause)
+       }
+       stats.PauseEnd = stats.PauseEnd[:0]
+       for _, ns := range stats.Pause[n : n+n] {
+               stats.PauseEnd = append(stats.PauseEnd, time.Unix(0, int64(ns)))
+       }
+
        if len(stats.PauseQuantiles) > 0 {
                if n == 0 {
                        for i := range stats.PauseQuantiles {
index 149bafc6f3c106e375d6af17121e31fc8ce97563..54c33bd4f3f4e48da2fa8a64051741fc04fdbb5f 100644 (file)
@@ -70,6 +70,19 @@ func TestReadGCStats(t *testing.T) {
                        t.Errorf("stats.PauseQuantiles[%d]=%d > stats.PauseQuantiles[%d]=%d", i, q[i], i+1, q[i+1])
                }
        }
+
+       // compare memory stats with gc stats:
+       if len(stats.PauseEnd) != n {
+               t.Fatalf("len(stats.PauseEnd) = %d, want %d", len(stats.PauseEnd), n)
+       }
+       off := (int(mstats.NumGC) + len(mstats.PauseEnd) - 1) % len(mstats.PauseEnd)
+       for i := 0; i < n; i++ {
+               dt := stats.PauseEnd[i]
+               if dt.UnixNano() != int64(mstats.PauseEnd[off]) {
+                       t.Errorf("stats.PauseEnd[%d] = %d, want %d", i, dt, mstats.PauseEnd[off])
+               }
+               off = (off + len(mstats.PauseEnd) - 1) % len(mstats.PauseEnd)
+       }
 }
 
 var big = make([]byte, 1<<20)
index 76e9867e030a5fea9fbdae6a56ea0dc212dfe821..e442c34835ef9c5b79d3ad9fe6fe7e514d827236 100644 (file)
@@ -30,7 +30,7 @@ func gogetenv(key string) string {
        if fd < 0 {
                return ""
        }
-       n := seek(fd, 0, 2) - 1
+       n := seek(fd, 0, 2)
        if n <= 0 {
                close(fd)
                return ""
@@ -44,6 +44,10 @@ func gogetenv(key string) string {
                return ""
        }
 
+       if p[r-1] == 0 {
+               r--
+       }
+
        var s string
        sp := (*_string)(unsafe.Pointer(&s))
        sp.str = &p[0]
index b8db5d0c4b7658f2299277bbb05f0268c0496fe6..1b8052bb563d7e6abc540cfffa093ac5e539ee81 100644 (file)
@@ -39,6 +39,12 @@ a comma-separated list of name=val pairs. Supported names are:
        gcdead: setting gcdead=1 causes the garbage collector to clobber all stack slots
        that it thinks are dead.
 
+       invalidptr: defaults to invalidptr=1, causing the garbage collector and stack
+       copier to crash the program if an invalid pointer value (for example, 1)
+       is found in a pointer-typed location. Setting invalidptr=0 disables this check.
+       This should only be used as a temporary workaround to diagnose buggy code.
+       The real fix is to not store integers in pointer-typed locations.
+
        scheddetail: setting schedtrace=X and scheddetail=1 causes the scheduler to emit
        detailed multiline info every X milliseconds, describing state of the scheduler,
        processors, threads and goroutines.
index a2667a4c027e803ba47d1945d0b278cc2ab6132c..d6c14fcb41a60044f74ae8b181d827bf21d99e1f 100644 (file)
@@ -28,6 +28,9 @@
 // defines the pointer map for the function's arguments.
 // GO_ARGS should be the first instruction in a function that uses it.
 // It can be omitted if there are no arguments at all.
+// GO_ARGS is inserted implicitly by the linker for any function
+// that also has a Go prototype and therefore is usually not necessary
+// to write explicitly.
 #define GO_ARGS        FUNCDATA $FUNCDATA_ArgsPointerMaps, go_args_stackmap(SB)
 
 // GO_RESULTS_INITIALIZED indicates that the assembly function
index e606b0c7afbd70b969df87ea414c925296548b06..522b11bbada2496bb9c8fd99121cdf1b1265c4b5 100644 (file)
@@ -268,7 +268,8 @@ struct MStats
        uint64  next_gc;        // next GC (in heap_alloc time)
        uint64  last_gc;        // last GC (in absolute time)
        uint64  pause_total_ns;
-       uint64  pause_ns[256];
+       uint64  pause_ns[256];  // circular buffer of recent GC pause lengths
+       uint64  pause_end[256]; // circular buffer of recent GC end times (nanoseconds since 1970)
        uint32  numgc;
        bool    enablegc;
        bool    debuggc;
index 438f22ec09fc0aee7828a742d54b50cd16b3d699..e6f1eb0e64f1da9f4f141fe6813bc9cdd4570b4e 100644 (file)
@@ -44,7 +44,8 @@ type MemStats struct {
        NextGC       uint64 // next collection will happen when HeapAlloc â‰¥ this amount
        LastGC       uint64 // end time of last collection (nanoseconds since 1970)
        PauseTotalNs uint64
-       PauseNs      [256]uint64 // circular buffer of recent GC pause times, most recent at [(NumGC+255)%256]
+       PauseNs      [256]uint64 // circular buffer of recent GC pause durations, most recent at [(NumGC+255)%256]
+       PauseEnd     [256]uint64 // circular buffer of recent GC pause end times
        NumGC        uint32
        EnableGC     bool
        DebugGC      bool
index cc1f8112341d929cbf1cf36cafc2739e29addcfa..bcc5a2f39dd4f3bb3ed8366968456de6ee5ec6a6 100644 (file)
@@ -687,7 +687,7 @@ putpartial(Workbuf *b)
        else if (b->nobj == nelem(b->obj))
                runtime·lfstackpush(&runtime·work.full, &b->node);
        else {
-               runtime·printf("b=%p, b->nobj=%d, nelem(b->obj)=%d\n", b, b->nobj, (uint32)nelem(b->obj));
+               runtime·printf("b=%p, b->nobj=%d, nelem(b->obj)=%d\n", b, (uint32)b->nobj, (uint32)nelem(b->obj));
                runtime·throw("putpartial: bad Workbuf b->nobj");
        }
 }
@@ -1725,6 +1725,7 @@ gc(struct gc_args *args)
        t4 = runtime·nanotime();
        runtime·atomicstore64(&mstats.last_gc, runtime·unixnanotime());  // must be Unix time to make sense to user
        mstats.pause_ns[mstats.numgc%nelem(mstats.pause_ns)] = t4 - t0;
+       mstats.pause_end[mstats.numgc%nelem(mstats.pause_end)] = t4;
        mstats.pause_total_ns += t4 - t0;
        mstats.numgc++;
        if(mstats.debuggc)
@@ -1773,7 +1774,6 @@ gc(struct gc_args *args)
        runtime·sweep.spanidx = 0;
        runtime·unlock(&runtime·mheap.lock);
 
-       // Temporary disable concurrent sweep, because we see failures on builders.
        if(ConcurrentSweep && !args->eagersweep) {
                runtime·lock(&runtime·gclock);
                if(runtime·sweep.g == nil)
@@ -1787,6 +1787,8 @@ gc(struct gc_args *args)
                // Sweep all spans eagerly.
                while(runtime·sweepone() != -1)
                        runtime·sweep.npausesweep++;
+               // Do an additional mProf_GC, because all 'free' events are now real as well.
+               runtime·mProf_GC();
        }
 
        runtime·mProf_GC();
@@ -1834,7 +1836,7 @@ readgcstats_m(void)
 {
        Slice *pauses;  
        uint64 *p;
-       uint32 i, n;
+       uint32 i, j, n;
        
        pauses = g->m->ptrarg[0];
        g->m->ptrarg[0] = nil;
@@ -1843,25 +1845,29 @@ readgcstats_m(void)
        if(pauses->cap < nelem(mstats.pause_ns)+3)
                runtime·throw("runtime: short slice passed to readGCStats");
 
-       // Pass back: pauses, last GC (absolute time), number of GC, total pause ns.
+       // Pass back: pauses, pause ends, last gc (absolute time), number of gc, total pause ns.
        p = (uint64*)pauses->array;
        runtime·lock(&runtime·mheap.lock);
+
        n = mstats.numgc;
        if(n > nelem(mstats.pause_ns))
                n = nelem(mstats.pause_ns);
-       
+
        // The pause buffer is circular. The most recent pause is at
        // pause_ns[(numgc-1)%nelem(pause_ns)], and then backward
        // from there to go back farther in time. We deliver the times
        // most recent first (in p[0]).
-       for(i=0; i<n; i++)
-               p[i] = mstats.pause_ns[(mstats.numgc-1-i)%nelem(mstats.pause_ns)];
+       for(i=0; i<n; i++) {
+               j = (mstats.numgc-1-i)%nelem(mstats.pause_ns);
+               p[i] = mstats.pause_ns[j];
+               p[n+i] = mstats.pause_end[j];
+       }
 
-       p[n] = mstats.last_gc;
-       p[n+1] = mstats.numgc;
-       p[n+2] = mstats.pause_total_ns; 
+       p[n+n] = mstats.last_gc;
+       p[n+n+1] = mstats.numgc;
+       p[n+n+2] = mstats.pause_total_ns;       
        runtime·unlock(&runtime·mheap.lock);
-       pauses->len = n+3;
+       pauses->len = n+n+3;
 }
 
 void
@@ -2041,7 +2047,7 @@ runtime·unrollgcprog_m(void)
        Type *typ;
        byte *mask, *prog;
        uintptr pos;
-       uint32 x;
+       uintptr x;
 
        typ = g->m->ptrarg[0];
        g->m->ptrarg[0] = nil;
@@ -2060,8 +2066,9 @@ runtime·unrollgcprog_m(void)
                        unrollgcprog1(mask, prog, &pos, false, true);
                }
                // atomic way to say mask[0] = 1
-               x = ((uint32*)mask)[0];
-               runtime·atomicstore((uint32*)mask, x|1);
+               x = *(uintptr*)mask;
+               ((byte*)&x)[0] = 1;
+               runtime·atomicstorep((void**)mask, (void*)x);
        }
        runtime·unlock(&lock);
 }
index 89e991523692fa517192850b5eb9d9241d1ea662..803da56670bd9eb1215d92ef7d7894db1cd2656b 100644 (file)
@@ -234,7 +234,7 @@ func mProf_GC() {
 // Called by malloc to record a profiled block.
 func mProf_Malloc(p unsafe.Pointer, size uintptr) {
        var stk [maxStack]uintptr
-       nstk := callers(1, &stk[0], len(stk))
+       nstk := callers(4, &stk[0], len(stk))
        lock(&proflock)
        b := stkbucket(memProfile, size, stk[:nstk], true)
        mp := b.mp()
@@ -284,6 +284,8 @@ func SetBlockProfileRate(rate int) {
        var r int64
        if rate <= 0 {
                r = 0 // disable profiling
+       } else if rate == 1 {
+               r = 1 // profile everything
        } else {
                // convert ns to cycles, use float64 to prevent overflow during multiplication
                r = int64(float64(rate) * float64(tickspersecond()) / (1000 * 1000 * 1000))
@@ -297,7 +299,7 @@ func SetBlockProfileRate(rate int) {
 
 func blockevent(cycles int64, skip int) {
        if cycles <= 0 {
-               return
+               cycles = 1
        }
        rate := int64(atomicload64(&blockprofilerate))
        if rate <= 0 || (rate > cycles && int64(fastrand1())%rate > cycles) {
diff --git a/src/runtime/pprof/mprof_test.go b/src/runtime/pprof/mprof_test.go
new file mode 100644 (file)
index 0000000..ebf53dd
--- /dev/null
@@ -0,0 +1,99 @@
+// Copyright 2014 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 pprof_test
+
+import (
+       "bytes"
+       "fmt"
+       "regexp"
+       "runtime"
+       . "runtime/pprof"
+       "testing"
+       "unsafe"
+)
+
+var memSink interface{}
+
+func allocateTransient1M() {
+       for i := 0; i < 1024; i++ {
+               memSink = &struct{ x [1024]byte }{}
+       }
+}
+
+func allocateTransient2M() {
+       // prevent inlining
+       if memSink == nil {
+               panic("bad")
+       }
+       memSink = make([]byte, 2<<20)
+}
+
+type Obj32 struct {
+       link *Obj32
+       pad  [32 - unsafe.Sizeof(uintptr(0))]byte
+}
+
+var persistentMemSink *Obj32
+
+func allocatePersistent1K() {
+       for i := 0; i < 32; i++ {
+               // Can't use slice because that will introduce implicit allocations.
+               obj := &Obj32{link: persistentMemSink}
+               persistentMemSink = obj
+       }
+}
+
+var memoryProfilerRun = 0
+
+func TestMemoryProfiler(t *testing.T) {
+       // Disable sampling, otherwise it's difficult to assert anything.
+       oldRate := runtime.MemProfileRate
+       runtime.MemProfileRate = 1
+       defer func() {
+               runtime.MemProfileRate = oldRate
+       }()
+
+       // Allocate a meg to ensure that mcache.next_sample is updated to 1.
+       for i := 0; i < 1024; i++ {
+               memSink = make([]byte, 1024)
+       }
+
+       // Do the interesting allocations.
+       allocateTransient1M()
+       allocateTransient2M()
+       allocatePersistent1K()
+       memSink = nil
+
+       runtime.GC() // materialize stats
+       var buf bytes.Buffer
+       if err := Lookup("heap").WriteTo(&buf, 1); err != nil {
+               t.Fatalf("failed to write heap profile: %v", err)
+       }
+
+       memoryProfilerRun++
+
+       tests := []string{
+               fmt.Sprintf(`%v: %v \[%v: %v\] @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
+#      0x[0-9,a-f]+    runtime/pprof_test\.allocatePersistent1K\+0x[0-9,a-f]+  .*/runtime/pprof/mprof_test\.go:43
+#      0x[0-9,a-f]+    runtime/pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+    .*/runtime/pprof/mprof_test\.go:66
+`, 32*memoryProfilerRun, 1024*memoryProfilerRun, 32*memoryProfilerRun, 1024*memoryProfilerRun),
+
+               fmt.Sprintf(`0: 0 \[%v: %v\] @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
+#      0x[0-9,a-f]+    runtime/pprof_test\.allocateTransient1M\+0x[0-9,a-f]+   .*/runtime/pprof/mprof_test.go:21
+#      0x[0-9,a-f]+    runtime/pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+    .*/runtime/pprof/mprof_test.go:64
+`, (1<<10)*memoryProfilerRun, (1<<20)*memoryProfilerRun),
+
+               fmt.Sprintf(`0: 0 \[%v: %v\] @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
+#      0x[0-9,a-f]+    runtime/pprof_test\.allocateTransient2M\+0x[0-9,a-f]+   .*/runtime/pprof/mprof_test.go:30
+#      0x[0-9,a-f]+    runtime/pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+    .*/runtime/pprof/mprof_test.go:65
+`, memoryProfilerRun, (2<<20)*memoryProfilerRun),
+       }
+
+       for _, test := range tests {
+               if !regexp.MustCompile(test).Match(buf.Bytes()) {
+                       t.Fatalf("The entry did not match:\n%v\n\nProfile:\n%v\n", test, buf.String())
+               }
+       }
+}
index edd471a0c9843b2ff132c2b65aa15a89a6df5b5d..8677cb30c5556ef794e6b64e8358019bb66baf64 100644 (file)
@@ -249,7 +249,7 @@ func TestGoroutineSwitch(t *testing.T) {
                        // exists to record a PC without a traceback. Those are okay.
                        if len(stk) == 2 {
                                f := runtime.FuncForPC(stk[1])
-                               if f != nil && (f.Name() == "System" || f.Name() == "ExternalCode") {
+                               if f != nil && (f.Name() == "System" || f.Name() == "ExternalCode" || f.Name() == "GC") {
                                        return
                                }
                        }
index 0fa1fb63c48ea878e5ee0090f608d6cfda50ec43..8f8268873b21ede2e671f453179651a74e396b81 100644 (file)
@@ -19,32 +19,17 @@ func bytes(s string) (ret []byte) {
        return
 }
 
-// goprintf is the function call that is actually deferred when you write
-//     defer print(...)
-// It is otherwise unused. In particular it is not used for ordinary prints.
-// Right now a dynamically allocated string that is being passed as an
-// argument is invisible to the garbage collector and might be collected
-// if that argument list is the only reference. For now we ignore that possibility.
-// To fix, we should change to defer a call to vprintf with a pointer to
-// an argument list on the stack, stored in an appropriately typed
-// struct. golang.org/issue/8614.
-//go:nosplit
-func goprintf(s string) {
-       vprintf(s, add(unsafe.Pointer(&s), unsafe.Sizeof(s)))
-}
-
-// printf is only called from C code. It has the same problem as goprintf
-// with strings possibly being collected from underneath.
-// However, the runtime never prints dynamically allocated
-// Go strings using printf. The strings it prints come from the symbol
-// and type tables.
+// printf is only called from C code. It has no type information for the args,
+// but C stacks are ignored by the garbage collector anyway, so having
+// type information would not add anything.
 //go:nosplit
 func printf(s *byte) {
        vprintf(gostringnocopy(s), add(unsafe.Pointer(&s), unsafe.Sizeof(s)))
 }
 
-// sprintf is only called from C code.
-// It has the same problem as goprintf.
+// sprintf is only called from C code. It has no type information for the args,
+// but C stacks are ignored by the garbage collector anyway, so having
+// type information would not add anything.
 //go:nosplit
 func snprintf(dst *byte, n int32, s *byte) {
        buf := (*[1 << 30]byte)(unsafe.Pointer(dst))[0:n:n]
index b824f574d948008327e45e59cf7036de1eb69f26..ab6812329fd0d11a840235bf00787947c75bdb57 100644 (file)
@@ -2764,6 +2764,8 @@ static void
 checkdead(void)
 {
        G *gp;
+       P *p;
+       M *mp;
        int32 run, grunning, s;
        uintptr i;
 
@@ -2805,6 +2807,24 @@ checkdead(void)
        runtime·unlock(&runtime·allglock);
        if(grunning == 0)  // possible if main goroutine calls runtime·Goexit()
                runtime·throw("no goroutines (main called runtime.Goexit) - deadlock!");
+
+       // Maybe jump time forward for playground.
+       if((gp = runtime·timejump()) != nil) {
+               runtime·casgstatus(gp, Gwaiting, Grunnable);
+               globrunqput(gp);
+               p = pidleget();
+               if(p == nil)
+                       runtime·throw("checkdead: no p for timer");
+               mp = mget();
+               if(mp == nil)
+                       newm(nil, p);
+               else {
+                       mp->nextp = p;
+                       runtime·notewakeup(&mp->park);
+               }
+               return;
+       }
+
        g->m->throwing = -1;  // do not dump full stacks
        runtime·throw("all goroutines are asleep - deadlock!");
 }
index d8703dc0f028a2f2d1a9dda9296395908b575de8..54e4b1de89e7b7e469aef6442670970b2f54c374 100644 (file)
@@ -26,5 +26,5 @@ TEXT _rt0_amd64p32_nacl(SB),NOSPLIT,$16
 TEXT main(SB),NOSPLIT,$0
        // Uncomment for fake time like on Go Playground.
        //MOVQ  $1257894000000000000, AX
-       //MOVQ  AX, runtime·timens(SB)
+       //MOVQ  AX, runtime·faketime(SB)
        JMP     runtime·rt0_go(SB)
index b3503fb909a2777fbddf3bee15d9e02783f277c9..c823691ec5a178ca27f1ef5f2d60cdede2be83a1 100644 (file)
@@ -276,9 +276,13 @@ struct DbgVar
        int32*  value;
 };
 
+// Do we report invalid pointers found during stack or heap scans?
+int32 runtime·invalidptr = 1;
+
 #pragma dataflag NOPTR /* dbgvar has no heap pointers */
 static DbgVar dbgvar[] = {
        {"allocfreetrace", &runtime·debug.allocfreetrace},
+       {"invalidptr", &runtime·invalidptr},
        {"efence", &runtime·debug.efence},
        {"gctrace", &runtime·debug.gctrace},
        {"gcdead", &runtime·debug.gcdead},
index c1bba423a15798d41a359b5783a57ff4a49380e5..6a02ef1d31d47fa9ad7ef1a1dcde0c985c717e07 100644 (file)
@@ -672,6 +672,8 @@ enum {
 byte*  runtime·startup_random_data;
 uint32 runtime·startup_random_data_len;
 
+int32  runtime·invalidptr;
+
 enum {
        // hashinit wants this many random bytes
        HashRandomBytes = 32
index 2d0787bd96b9911f9e0dcd069e53035ef4b44c85..d703e1d79bedb8048973e30c62c412f71eceb0e8 100644 (file)
@@ -393,9 +393,9 @@ loop:
                } else {
                        c = k._chan
                        if k.kind == _CaseSend {
-                               c.sendq.dequeueg(gp)
+                               c.sendq.dequeueSudoG(sglist)
                        } else {
-                               c.recvq.dequeueg(gp)
+                               c.recvq.dequeueSudoG(sglist)
                        }
                }
                sgnext = sglist.waitlink
@@ -623,7 +623,7 @@ func reflect_rselect(cases []runtimeSelect) (chosen int, recvOK bool) {
        return
 }
 
-func (q *waitq) dequeueg(gp *g) {
+func (q *waitq) dequeueSudoG(s *sudog) {
        var prevsgp *sudog
        l := &q.first
        for {
@@ -631,7 +631,7 @@ func (q *waitq) dequeueg(gp *g) {
                if sgp == nil {
                        return
                }
-               if sgp.g == gp {
+               if sgp == s {
                        *l = sgp.next
                        if q.last == sgp {
                                q.last = prevsgp
index e06e48a93d43652717d37abfa519cf4be2032930..f18171ea5c8f45ef1cf1756e468672d1d09b060e 100644 (file)
@@ -401,12 +401,12 @@ adjustpointers(byte **scanp, BitVector *bv, AdjustInfo *adjinfo, Func *f)
                        break;
                case BitsPointer:
                        p = scanp[i];
-                       if(f != nil && (byte*)0 < p && (p < (byte*)PageSize || (uintptr)p == PoisonGC || (uintptr)p == PoisonStack)) {
+                       if(f != nil && (byte*)0 < p && (p < (byte*)PageSize && runtime·invalidptr || (uintptr)p == PoisonGC || (uintptr)p == PoisonStack)) {
                                // Looks like a junk value in a pointer slot.
                                // Live analysis wrong?
                                g->m->traceback = 2;
                                runtime·printf("runtime: bad pointer in frame %s at %p: %p\n", runtime·funcname(f), &scanp[i], p);
-                               runtime·throw("bad pointer!");
+                               runtime·throw("invalid stack pointer");
                        }
                        if(minp <= p && p < maxp) {
                                if(StackDebug >= 3)
index 32dfed7d3922d61a834cfbad97a3689a70c22e37..2d5e41c1c55d1b239a59a163e0a35ebd9f1fbbbf 100644 (file)
@@ -182,7 +182,11 @@ func exit(code int32)
 func breakpoint()
 func nanotime() int64
 func usleep(usec uint32)
+
+// careful: cputicks is not guaranteed to be monotonic!  In particular, we have
+// noticed drift between cpus on certain os/arch combinations.  See issue 8976.
 func cputicks() int64
+
 func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer
 func munmap(addr unsafe.Pointer, n uintptr)
 func madvise(addr unsafe.Pointer, n uintptr, flags int32)
index 48d4023b9aa6e1d8bfff3f35fb3dd135c366d016..45d107b777869e1a0cd7e4bcd7c38922e85eeba4 100644 (file)
@@ -84,10 +84,13 @@ func symtabinit() {
                }
        }
 
-       // file table follows ftab.
+       // The ftab ends with a half functab consisting only of
+       // 'entry', followed by a uint32 giving the pcln-relative
+       // offset of the file table.
        sp = (*sliceStruct)(unsafe.Pointer(&filetab))
-       p = unsafe.Pointer(add(unsafe.Pointer(pcln), ftab[nftab].funcoff))
-       sp.array = unsafe.Pointer(add(unsafe.Pointer(pcln), ftab[nftab].funcoff))
+       end := unsafe.Pointer(&ftab[nftab].funcoff) // just beyond ftab
+       fileoffset := *(*uint32)(end)
+       sp.array = unsafe.Pointer(&pclntable[fileoffset])
        // length is in first element of array.
        // set len to 1 so we can get first element.
        sp.len = 1
@@ -224,7 +227,7 @@ func funcline(f *_func, targetpc uintptr, file *string) int32 {
 func funcspdelta(f *_func, targetpc uintptr) int32 {
        x := pcvalue(f, f.pcsp, targetpc, true)
        if x&(ptrSize-1) != 0 {
-               print("invalid spdelta ", f.pcsp, " ", x, "\n")
+               print("invalid spdelta ", hex(f.entry), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n")
        }
        return x
 }
index c30c2a8933f2d69c0e70b860cfef52521d801bd3..4eb4aacdd58cad0dd2d3b02b6b60d75292ee0b35 100644 (file)
@@ -60,7 +60,7 @@ TEXT syscall·naclWrite(SB), NOSPLIT, $24-20
 TEXT runtime·write(SB),NOSPLIT,$16-20
        // If using fake time and writing to stdout or stderr,
        // emit playback header before actual data.
-       MOVQ runtime·timens(SB), AX
+       MOVQ runtime·faketime(SB), AX
        CMPQ AX, $0
        JEQ write
        MOVL fd+0(FP), DI
@@ -242,7 +242,7 @@ TEXT runtime·mmap(SB),NOSPLIT,$8
        RET
 
 TEXT time·now(SB),NOSPLIT,$16
-       MOVQ runtime·timens(SB), AX
+       MOVQ runtime·faketime(SB), AX
        CMPQ AX, $0
        JEQ realtime
        MOVQ $0, DX
@@ -277,7 +277,7 @@ TEXT runtime·nacl_clock_gettime(SB),NOSPLIT,$0
        RET
 
 TEXT runtime·nanotime(SB),NOSPLIT,$16
-       MOVQ runtime·timens(SB), AX
+       MOVQ runtime·faketime(SB), AX
        CMPQ AX, $0
        JEQ 3(PC)
        MOVQ    AX, ret+0(FP)
index 8cf9eecf834d99d4b4d9e0fef2dec9bc2cf368e9..11862c7e23520fe9e31ad1690ee0b36c98948832 100644 (file)
@@ -35,8 +35,8 @@ var timers struct {
        t            []*timer
 }
 
-// nacl fake time support.
-var timens int64
+// nacl fake time support - time in nanoseconds since 1970
+var faketime int64
 
 // Package time APIs.
 // Godoc uses the comments in package time, not these.
@@ -194,7 +194,7 @@ func timerproc() {
                        f(arg, seq)
                        lock(&timers.lock)
                }
-               if delta < 0 {
+               if delta < 0 || faketime > 0 {
                        // No timers left - put goroutine to sleep.
                        timers.rescheduling = true
                        goparkunlock(&timers.lock, "timer goroutine (idle)")
@@ -208,6 +208,29 @@ func timerproc() {
        }
 }
 
+func timejump() *g {
+       if faketime == 0 {
+               return nil
+       }
+
+       lock(&timers.lock)
+       if !timers.created || len(timers.t) == 0 {
+               unlock(&timers.lock)
+               return nil
+       }
+
+       var gp *g
+       if faketime < timers.t[0].when {
+               faketime = timers.t[0].when
+               if timers.rescheduling {
+                       timers.rescheduling = false
+                       gp = timers.gp
+               }
+       }
+       unlock(&timers.lock)
+       return gp
+}
+
 // Heap maintenance algorithms.
 
 func siftupTimer(i int) {
index 1f08707cd42269dbc654d4a2cf9e8f88753984a4..0cf0637024402a9fb0f5a9bf99b28463286f5dd9 100644 (file)
@@ -200,6 +200,8 @@ func poolCleanup() {
                        }
                        l.shared = nil
                }
+               p.local = nil
+               p.localSize = 0
        }
        allPools = []*Pool{}
 }
index cf5c8bd903f8d37d469bd1309dd57d7c40d64c7a..fa1a27beac998254f235baa5c22d81588ba97b54 100644 (file)
@@ -69,32 +69,44 @@ func TestPoolNew(t *testing.T) {
        }
 }
 
-// Test that Pool does not hold pointers to previously cached
-// resources
+// Test that Pool does not hold pointers to previously cached resources.
 func TestPoolGC(t *testing.T) {
+       testPool(t, true)
+}
+
+// Test that Pool releases resources on GC.
+func TestPoolRelease(t *testing.T) {
+       testPool(t, false)
+}
+
+func testPool(t *testing.T, drain bool) {
        var p Pool
-       var fin uint32
        const N = 100
-       for i := 0; i < N; i++ {
-               v := new(string)
-               runtime.SetFinalizer(v, func(vv *string) {
-                       atomic.AddUint32(&fin, 1)
-               })
-               p.Put(v)
-       }
-       for i := 0; i < N; i++ {
-               p.Get()
-       }
-       for i := 0; i < 5; i++ {
-               runtime.GC()
-               time.Sleep(time.Duration(i*100+10) * time.Millisecond)
-               // 1 pointer can remain on stack or elsewhere
-               if atomic.LoadUint32(&fin) >= N-1 {
-                       return
+loop:
+       for try := 0; try < 3; try++ {
+               var fin, fin1 uint32
+               for i := 0; i < N; i++ {
+                       v := new(string)
+                       runtime.SetFinalizer(v, func(vv *string) {
+                               atomic.AddUint32(&fin, 1)
+                       })
+                       p.Put(v)
+               }
+               if drain {
+                       for i := 0; i < N; i++ {
+                               p.Get()
+                       }
+               }
+               for i := 0; i < 5; i++ {
+                       runtime.GC()
+                       time.Sleep(time.Duration(i*100+10) * time.Millisecond)
+                       // 1 pointer can remain on stack or elsewhere
+                       if fin1 = atomic.LoadUint32(&fin); fin1 >= N-1 {
+                               continue loop
+                       }
                }
+               t.Fatalf("only %v out of %v resources are finalized on try %v", fin1, N, try)
        }
-       t.Fatalf("only %v out of %v resources are finalized",
-               atomic.LoadUint32(&fin), N)
 }
 
 func TestPoolStress(t *testing.T) {
index 934507905297445a039df14fb99b299d2be85e6d..9ea36c886abd1e6b80590081e3f7ed184c8745f1 100644 (file)
@@ -8,28 +8,9 @@ package syscall
 
 import (
        "errors"
-       "sync"
 )
 
 var (
-       // envOnce guards copyenv, which populates env, envi and envs.
-       envOnce sync.Once
-
-       // envLock guards env, envi and envs.
-       envLock sync.RWMutex
-
-       // env maps from an environment variable to its value.
-       // TODO: remove this? golang.org/issue/8849
-       env = make(map[string]string)
-
-       // envi maps from an environment variable to its index in envs.
-       // TODO: remove this? golang.org/issue/8849
-       envi = make(map[string]int)
-
-       // envs contains elements of env in the form "key=value".
-       // empty strings mean deleted.
-       envs []string
-
        errZeroLengthKey = errors.New("zero length key")
        errShortWrite    = errors.New("i/o count too small")
 )
@@ -70,47 +51,14 @@ func writeenv(key, value string) error {
        return nil
 }
 
-func copyenv() {
-       fd, err := Open("/env", O_RDONLY)
-       if err != nil {
-               return
-       }
-       defer Close(fd)
-       files, err := readdirnames(fd)
-       if err != nil {
-               return
-       }
-       envs = make([]string, len(files))
-       i := 0
-       for _, key := range files {
-               v, err := readenv(key)
-               if err != nil {
-                       continue
-               }
-               env[key] = v
-               envs[i] = key + "=" + v
-               envi[key] = i
-               i++
-       }
-}
-
 func Getenv(key string) (value string, found bool) {
        if len(key) == 0 {
                return "", false
        }
-
-       envLock.RLock()
-       defer envLock.RUnlock()
-
-       if v, ok := env[key]; ok {
-               return v, true
-       }
        v, err := readenv(key)
        if err != nil {
                return "", false
        }
-       env[key] = v
-       envs = append(envs, key+"="+v)
        return v, true
 }
 
@@ -118,27 +66,14 @@ func Setenv(key, value string) error {
        if len(key) == 0 {
                return errZeroLengthKey
        }
-
-       envLock.Lock()
-       defer envLock.Unlock()
-
        err := writeenv(key, value)
        if err != nil {
                return err
        }
-       env[key] = value
-       envs = append(envs, key+"="+value)
-       envi[key] = len(envs) - 1
        return nil
 }
 
 func Clearenv() {
-       envLock.Lock()
-       defer envLock.Unlock()
-
-       env = make(map[string]string)
-       envi = make(map[string]int)
-       envs = []string{}
        RawSyscall(SYS_RFORK, RFCENVG, 0, 0)
 }
 
@@ -146,30 +81,28 @@ func Unsetenv(key string) error {
        if len(key) == 0 {
                return errZeroLengthKey
        }
-
-       envLock.Lock()
-       defer envLock.Unlock()
-
        Remove("/env/" + key)
-
-       if i, ok := envi[key]; ok {
-               delete(env, key)
-               delete(envi, key)
-               envs[i] = ""
-       }
        return nil
 }
 
 func Environ() []string {
-       envLock.RLock()
-       defer envLock.RUnlock()
+       fd, err := Open("/env", O_RDONLY)
+       if err != nil {
+               return nil
+       }
+       defer Close(fd)
+       files, err := readdirnames(fd)
+       if err != nil {
+               return nil
+       }
+       ret := make([]string, 0, len(files))
 
-       envOnce.Do(copyenv)
-       ret := make([]string, 0, len(envs))
-       for _, pair := range envs {
-               if pair != "" {
-                       ret = append(ret, pair)
+       for _, key := range files {
+               v, err := readenv(key)
+               if err != nil {
+                       continue
                }
+               ret = append(ret, key+"="+v)
        }
        return ret
 }
index 4abc9b81c92085b5991e256d0420c6c38e2e1a0e..6e6ce2ab7bc186bf6fe65c0893e7247a79a14d1f 100644 (file)
@@ -818,6 +818,12 @@ func create(name string, mode uint32, sec int64, data []byte) error {
        fs.mu.Unlock()
        f, err := fs.open(name, O_CREATE|O_EXCL, mode)
        if err != nil {
+               if mode&S_IFMT == S_IFDIR {
+                       ip, _, err := fs.namei(name, false)
+                       if err == nil && (ip.Mode&S_IFMT) == S_IFDIR {
+                               return nil // directory already exists
+                       }
+               }
                return err
        }
        ip := f.(*fsysFile).inode
index 48af587450ba1eca15cbd56abc775c41f3c36670..1dabe42531b77da5e407d7f1009de20129e697a8 100644 (file)
@@ -153,7 +153,7 @@ func (m *InterfaceAddrMessage) sockaddr() (sas []Sockaddr) {
        // RTAX_NETMASK socket address on the FreeBSD kernel.
        preferredFamily := uint8(AF_UNSPEC)
        for i := uint(0); i < RTAX_MAX; i++ {
-               if m.Header.Addrs&rtaIfaMask&(1<<i) == 0 {
+               if m.Header.Addrs&(1<<i) == 0 {
                        continue
                }
                rsa := (*RawSockaddr)(unsafe.Pointer(&b[0]))
index f91d860a945607ae04e30c884f599662ec4e40ac..e54a3b8ce4dfca3a0e01dc2d35f95d269d035141 100644 (file)
@@ -620,6 +620,7 @@ func after() {
                        fmt.Fprintf(os.Stderr, "testing: %s\n", err)
                        os.Exit(2)
                }
+               runtime.GC() // materialize all statistics
                if err = pprof.WriteHeapProfile(f); err != nil {
                        fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *memProfile, err)
                        os.Exit(2)
index f6eed662b7c807b34fd10476a89fc8a0a70c6ad7..b00e10c7e418460b4b6ba082e6e53172abdd14c9 100644 (file)
@@ -546,7 +546,7 @@ func (s *state) evalCall(dot, fun reflect.Value, node parse.Node, name string, a
        argv := make([]reflect.Value, numIn)
        // Args must be evaluated. Fixed args first.
        i := 0
-       for ; i < numFixed; i++ {
+       for ; i < numFixed && i < len(args); i++ {
                argv[i] = s.evalArg(dot, typ.In(i), args[i])
        }
        // Now the ... args.
index e2cf2d370574c3829670ca0b4b371f8cfe4c9632..69c213ed24503b59487fed5efc03d00f484d063d 100644 (file)
@@ -893,6 +893,18 @@ func TestMessageForExecuteEmpty(t *testing.T) {
        }
 }
 
+func TestFinalForPrintf(t *testing.T) {
+       tmpl, err := New("").Parse(`{{"x" | printf}}`)
+       if err != nil {
+               t.Fatal(err)
+       }
+       var b bytes.Buffer
+       err = tmpl.Execute(&b, 0)
+       if err != nil {
+               t.Fatal(err)
+       }
+}
+
 type cmpTest struct {
        expr  string
        truth string
index 61660d14ff94449f694d4ecf5c9074f4c3e4c401..e7a2ee2059867bd545d3f36d46f01efba3934155 100644 (file)
@@ -55,6 +55,9 @@ type Timer struct {
 // Stop does not close the channel, to prevent a read from the channel succeeding
 // incorrectly.
 func (t *Timer) Stop() bool {
+       if t.r.f == nil {
+               panic("time: Stop called on uninitialized Timer")
+       }
        return stopTimer(&t.r)
 }
 
@@ -78,6 +81,9 @@ func NewTimer(d Duration) *Timer {
 // It returns true if the timer had been active, false if the timer had
 // expired or been stopped.
 func (t *Timer) Reset(d Duration) bool {
+       if t.r.f == nil {
+               panic("time: Reset called on uninitialized Timer")
+       }
        w := when(d)
        active := stopTimer(&t.r)
        t.r.when = w
index 2cfb6a59c22f72e628942717cdec8201540fd5dd..c9b2956b7845e58e1d5bf0c766bade121ce3a8c6 100644 (file)
@@ -9,6 +9,7 @@ import (
        "fmt"
        "runtime"
        "sort"
+       "strings"
        "sync"
        "sync/atomic"
        "testing"
@@ -407,3 +408,23 @@ func TestOverflowRuntimeTimer(t *testing.T) {
        // the end of CheckRuntimeTimerOverflow in internal_test.go.
        CheckRuntimeTimerOverflow()
 }
+
+func checkZeroPanicString(t *testing.T) {
+       e := recover()
+       s, _ := e.(string)
+       if want := "called on uninitialized Timer"; !strings.Contains(s, want) {
+               t.Errorf("panic = %v; want substring %q", e, want)
+       }
+}
+
+func TestZeroTimerResetPanics(t *testing.T) {
+       defer checkZeroPanicString(t)
+       var tr Timer
+       tr.Reset(1)
+}
+
+func TestZeroTimerStopPanics(t *testing.T) {
+       defer checkZeroPanicString(t)
+       var tr Timer
+       tr.Stop()
+}
index 253295ad35d334e26ffefe01a6ea81fd5caaeb4a..9ac37184d69aa4fd308db2280cfc1b343a779c7f 100644 (file)
@@ -211,8 +211,11 @@ func FullRuneInString(s string) bool {
        return !short
 }
 
-// DecodeRune unpacks the first UTF-8 encoding in p and returns the rune and its width in bytes.
-// If the encoding is invalid, it returns (RuneError, 1), an impossible result for correct UTF-8.
+// DecodeRune unpacks the first UTF-8 encoding in p and returns the rune and
+// its width in bytes. If p is empty it returns (RuneError, 0). Otherwise, if
+// the encoding is invalid, it returns (RuneError, 1). Both are impossible
+// results for correct UTF-8.
+//
 // An encoding is invalid if it is incorrect UTF-8, encodes a rune that is
 // out of range, or is not the shortest possible UTF-8 encoding for the
 // value. No other validation is performed.
@@ -221,8 +224,10 @@ func DecodeRune(p []byte) (r rune, size int) {
        return
 }
 
-// DecodeRuneInString is like DecodeRune but its input is a string.
-// If the encoding is invalid, it returns (RuneError, 1), an impossible result for correct UTF-8.
+// DecodeRuneInString is like DecodeRune but its input is a string. If s is
+// empty it returns (RuneError, 0). Otherwise, if the encoding is invalid, it
+// returns (RuneError, 1). Both are impossible results for correct UTF-8.
+//
 // An encoding is invalid if it is incorrect UTF-8, encodes a rune that is
 // out of range, or is not the shortest possible UTF-8 encoding for the
 // value. No other validation is performed.
@@ -231,8 +236,11 @@ func DecodeRuneInString(s string) (r rune, size int) {
        return
 }
 
-// DecodeLastRune unpacks the last UTF-8 encoding in p and returns the rune and its width in bytes.
-// If the encoding is invalid, it returns (RuneError, 1), an impossible result for correct UTF-8.
+// DecodeLastRune unpacks the last UTF-8 encoding in p and returns the rune and
+// its width in bytes. If p is empty it returns (RuneError, 0). Otherwise, if
+// the encoding is invalid, it returns (RuneError, 1). Both are impossible
+// results for correct UTF-8.
+//
 // An encoding is invalid if it is incorrect UTF-8, encodes a rune that is
 // out of range, or is not the shortest possible UTF-8 encoding for the
 // value. No other validation is performed.
@@ -268,8 +276,10 @@ func DecodeLastRune(p []byte) (r rune, size int) {
        return r, size
 }
 
-// DecodeLastRuneInString is like DecodeLastRune but its input is a string.
-// If the encoding is invalid, it returns (RuneError, 1), an impossible result for correct UTF-8.
+// DecodeLastRuneInString is like DecodeLastRune but its input is a string. If
+// s is empty it returns (RuneError, 0). Otherwise, if the encoding is invalid,
+// it returns (RuneError, 1). Both are impossible results for correct UTF-8.
+//
 // An encoding is invalid if it is incorrect UTF-8, encodes a rune that is
 // out of range, or is not the shortest possible UTF-8 encoding for the
 // value. No other validation is performed.
index 83b2e140523fb58ecaa64b6239ac5a0e1ff447da..79499b2955f633b50d6da71c1cc658168a71d5fd 100644 (file)
@@ -4,6 +4,9 @@
 
 /*
        Package unsafe contains operations that step around the type safety of Go programs.
+
+       Packages that import unsafe may be non-portable and are not protected by the
+       Go 1 compatibility guidelines.
 */
 package unsafe
 
index 6329e9635a2dadbaed3b2c59a475c7fcd4898c7e..86c73bf4a8f1be3e197c5b7ab9c1bc69de39b520 100644 (file)
@@ -8,10 +8,10 @@
 
 package main
 
-type T struct {}
+type T struct{}
 
 func (t *T) pm() {}
-func (t T) m() {}
+func (t T) m()   {}
 
 func main() {
        p := &T{}
@@ -20,5 +20,5 @@ func main() {
 
        q := &p
        q.m()  // ERROR "requires explicit dereference"
-       q.pm()
+       q.pm() // ERROR "requires explicit dereference"
 }
diff --git a/test/fixedbugs/issue8947.go b/test/fixedbugs/issue8947.go
new file mode 100644 (file)
index 0000000..f40c02e
--- /dev/null
@@ -0,0 +1,53 @@
+// run
+
+// Copyright 2014 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.
+
+// Some uses of zeroed constants in non-assignment
+// expressions broke with our more aggressive zeroing
+// of assignments (internal compiler errors).
+
+package main
+
+func f1() {
+       type T [2]int
+       p := T{0, 1}
+       switch p {
+       case T{0, 0}:
+               panic("wrong1")
+       case T{0, 1}:
+               // ok
+       default:
+               panic("wrong2")
+       }
+
+       if p == (T{0, 0}) {
+               panic("wrong3")
+       } else if p == (T{0, 1}) {
+               // ok
+       } else {
+               panic("wrong4")
+       }
+}
+
+type T struct {
+       V int
+}
+
+var X = T{}.V
+
+func f2() {
+       var x = T{}.V
+       if x != 0 {
+               panic("wrongx")
+       }
+       if X != 0 {
+               panic("wrongX")
+       }
+}
+
+func main() {
+       f1()
+       f2()
+}
diff --git a/test/fixedbugs/issue8961.go b/test/fixedbugs/issue8961.go
new file mode 100644 (file)
index 0000000..fbfb7e6
--- /dev/null
@@ -0,0 +1,20 @@
+// run
+
+// Copyright 2014 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.
+
+// Issue 8961. Empty composite literals to small globals were not filled in
+package main
+
+type small struct { a int }
+var foo small
+
+func main() {
+       foo.a = 1
+       foo = small{}
+       if foo.a != 0 {
+               println("expected foo.a to be 0, was", foo.a)
+               panic("composite literal not filled in")
+       }
+}
diff --git a/test/fixedbugs/issue9006.go b/test/fixedbugs/issue9006.go
new file mode 100644 (file)
index 0000000..c559f58
--- /dev/null
@@ -0,0 +1,37 @@
+// run
+
+// Copyright 2014 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 main
+
+type T1 struct {
+       X int
+}
+
+func NewT1(x int) T1 { return T1{x} }
+
+type T2 int
+
+func NewT2(x int) T2 { return T2(x) }
+
+func main() {
+       switch (T1{}) {
+       case NewT1(1):
+               panic("bad1")
+       case NewT1(0):
+               // ok
+       default:
+               panic("bad2")
+       }
+
+       switch T2(0) {
+       case NewT2(2):
+               panic("bad3")
+       case NewT2(0):
+               // ok
+       default:
+               panic("bad4")
+       }
+}
index 2494becb89ca95ac1660b580a83242e7127996cb..34d091491480d741e51288c65ee267582d467afb 100644 (file)
@@ -44,14 +44,21 @@ func checkLinear(typ string, tries int, f func(n int)) {
                        }
                        return
                }
-               fails++
-               if fails == 12 {
+               // If n ops run in under a second and the ratio
+               // doesn't work out, make n bigger, trying to reduce
+               // the effect that a constant amount of overhead has
+               // on the computed ratio.
+               if t1 < 1*time.Second {
+                       n *= 2
+                       continue
+               }
+               // Once the test runs long enough for n ops,
+               // try to get the right ratio at least once.
+               // If five in a row all fail, give up.
+               if fails++; fails >= 5 {
                        panic(fmt.Sprintf("%s: too slow: %d inserts: %v; %d inserts: %v\n",
                                typ, n, t1, 2*n, t2))
                }
-               if fails < 10 {
-                       n *= 2
-               }
        }
 }
 
index 6287d65076d333eb7157d5c148040986e75a38f4..f92c15c1d6c9cea42bf5ca1ef95874b75c52d0b0 100644 (file)
@@ -63,6 +63,7 @@ func main() {
                test14reflect1()
                test14reflect2()
                test15()
+               test16()
        }
 }
 
@@ -114,10 +115,23 @@ func withoutRecover() {
        mustNotRecover() // because it's a sub-call
 }
 
+func withoutRecoverRecursive(n int) {
+       if n == 0 {
+               withoutRecoverRecursive(1)
+       } else {
+               v := recover()
+               if v != nil {
+                       println("spurious recover (recursive)", v)
+                       die()
+               }
+       }
+}
+
 func test1() {
-       defer mustNotRecover() // because mustRecover will squelch it
-       defer mustRecover(1)   // because of panic below
-       defer withoutRecover() // should be no-op, leaving for mustRecover to find
+       defer mustNotRecover()           // because mustRecover will squelch it
+       defer mustRecover(1)             // because of panic below
+       defer withoutRecover()           // should be no-op, leaving for mustRecover to find
+       defer withoutRecoverRecursive(0) // ditto
        panic(1)
 }
 
@@ -547,3 +561,27 @@ func test15() {
        defer f()
        panic(15)
 }
+
+func reflectFunc2(args []reflect.Value) (results []reflect.Value) {
+       // This will call reflectFunc3
+       args[0].Interface().(func())()
+       return nil
+}
+
+func reflectFunc3(args []reflect.Value) (results []reflect.Value) {
+       if v := recover(); v != nil {
+               println("spurious recover", v)
+               die()
+       }
+       return nil
+}
+
+func test16() {
+       defer mustRecover(16)
+
+       f2 := reflect.MakeFunc(reflect.TypeOf((func(func()))(nil)), reflectFunc2).Interface().(func(func()))
+       f3 := reflect.MakeFunc(reflect.TypeOf((func())(nil)), reflectFunc3).Interface().(func())
+       defer f2(f3)
+
+       panic(16)
+}