1
0
mirror of https://github.com/golang/go synced 2024-11-12 04:50:21 -07:00

[dev.power64] all: merge default (dd5014ed9b01) into dev.power64

Still passes on amd64.

LGTM=austin
R=austin
CC=golang-codereviews
https://golang.org/cl/165110043
This commit is contained in:
Russ Cox 2014-10-29 11:45:01 -04:00
commit 599199fd9f
47 changed files with 1339 additions and 291 deletions

View File

@ -117,6 +117,9 @@ All user-defined symbols other than jump labels are written as offsets to these
<p> <p>
The <code>SB</code> pseudo-register can be thought of as the origin of memory, so the symbol <code>foo(SB)</code> 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. 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>
<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 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>. 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>. 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. 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>
<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. 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>, If <code>NOSPLIT</code> is not specified for the <code>TEXT</code>,
the argument size must be provided. 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>
<p> <p>
@ -216,19 +224,20 @@ simple name <code>profileloop</code>.
</p> </p>
<p> <p>
For <code>DATA</code> directives, the symbol is followed by a slash and the number Global data symbols are defined by a sequence of initializing
of bytes the memory associated with the symbol occupies. <code>DATA</code> directives followed by a <code>GLOBL</code> directive.
The arguments are optional flags and the data itself. Each <code>DATA</code> directive initializes a section of the
For instance, corresponding memory.
</p> The memory not explicitly initialized is zeroed.
The general form of the <code>DATA</code> directive is
<pre> <pre>
DATA runtime·isplan9(SB)/4, $1 DATA symbol+offset(SB)/width, value
</pre> </pre>
<p> <p>
declares the local symbol <code>runtime·isplan9</code> of size 4 and value 1. which initializes the symbol memory at the given offset and width with the given value.
Again the symbol has the middle dot and is offset from <code>SB</code>. The <code>DATA</code> directives for a given symbol must be written with increasing offsets.
</p> </p>
<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 which will have initial value all zeros unless a <code>DATA</code> directive
has initialized it. has initialized it.
The <code>GLOBL</code> directive must follow any corresponding <code>DATA</code> directives. The <code>GLOBL</code> directive must follow any corresponding <code>DATA</code> directives.
This example </p>
<p>
For example,
</p> </p>
<pre> <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> </pre>
<p> <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>
<p> <p>
@ -299,6 +319,80 @@ This is a wrapper function and should not count as disabling <code>recover</code
</li> </li>
</ul> </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> <h2 id="architectures">Architecture-specific details</h2>
<p> <p>
@ -434,13 +528,10 @@ Here's how the 386 runtime defines the 64-bit atomic load function.
// so actually // so actually
// void atomicload64(uint64 *res, uint64 volatile *addr); // void atomicload64(uint64 *res, uint64 volatile *addr);
TEXT runtime·atomicload64(SB), NOSPLIT, $0-8 TEXT runtime·atomicload64(SB), NOSPLIT, $0-8
MOVL 4(SP), BX MOVL ptr+0(FP), AX
MOVL 8(SP), AX LEAL ret_lo+4(FP), BX
// MOVQ (%EAX), %MM0 BYTE $0x0f; BYTE $0x6f; BYTE $0x00 // MOVQ (%EAX), %MM0
BYTE $0x0f; BYTE $0x6f; BYTE $0x00 BYTE $0x0f; BYTE $0x7f; BYTE $0x03 // MOVQ %MM0, 0(%EBX)
// MOVQ %MM0, 0(%EBX) BYTE $0x0F; BYTE $0x77 // EMMS
BYTE $0x0f; BYTE $0x7f; BYTE $0x03
// EMMS
BYTE $0x0F; BYTE $0x77
RET RET
</pre> </pre>

598
doc/go1.4.html Normal file
View File

@ -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>

View File

@ -1,53 +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)
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)
flag: it is now an error to set a flag multiple times (CL 156390043)
fmt: print type *map[T]T as &map[k:v] (CL 154870043)
encoding/csv: do not quote empty strings, quote \. (CL 164760043)
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)
unsafe: document the existing situation that unsafe programs are not go1-guaranteed (CL 162060043)
go.sys subrepo created: http://golang.org/s/go1.4-syscall

View 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. observe values produced by writes to the same variable in a different goroutine.
</p> </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> <h2>Happens Before</h2>
<p> <p>

View File

@ -1,6 +1,6 @@
<!--{ <!--{
"Title": "The Go Programming Language Specification", "Title": "The Go Programming Language Specification",
"Subtitle": "Version of October 23, 2014", "Subtitle": "Version of October 27, 2014",
"Path": "/ref/spec" "Path": "/ref/spec"
}--> }-->
@ -2449,12 +2449,11 @@ Primary expressions are the operands for unary and binary expressions.
PrimaryExpr = PrimaryExpr =
Operand | Operand |
Conversion | Conversion |
BuiltinCall |
PrimaryExpr Selector | PrimaryExpr Selector |
PrimaryExpr Index | PrimaryExpr Index |
PrimaryExpr Slice | PrimaryExpr Slice |
PrimaryExpr TypeAssertion | PrimaryExpr TypeAssertion |
PrimaryExpr Call . PrimaryExpr Arguments .
Selector = "." identifier . Selector = "." identifier .
Index = "[" Expression "]" . Index = "[" Expression "]" .
@ -2462,8 +2461,7 @@ Slice = "[" ( [ Expression ] ":" [ Expression ] ) |
( [ Expression ] ":" Expression ":" Expression ) ( [ Expression ] ":" Expression ":" Expression )
"]" . "]" .
TypeAssertion = "." "(" Type ")" . TypeAssertion = "." "(" Type ")" .
Call = "(" [ ArgumentList [ "," ] ] ")" . Arguments = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .
ArgumentList = ExpressionList [ "..." ] .
</pre> </pre>
@ -3166,7 +3164,7 @@ the method.
<pre> <pre>
math.Atan2(x, y) // function call math.Atan2(x, y) // function call
var pt *Point var pt *Point
pt.Scale(3.5) // method call with receiver pt pt.Scale(3.5) // method call with receiver pt
</pre> </pre>
<p> <p>
@ -5371,11 +5369,6 @@ so they can only appear in <a href="#Calls">call expressions</a>;
they cannot be used as function values. they cannot be used as function values.
</p> </p>
<pre class="ebnf">
BuiltinCall = identifier "(" [ BuiltinArgs [ "," ] ] ")" .
BuiltinArgs = Type [ "," ArgumentList ] | ArgumentList .
</pre>
<h3 id="Close">Close</h3> <h3 id="Close">Close</h3>
<p> <p>

View File

@ -24,7 +24,6 @@ char *runtimeimport =
"func @\"\".printslice (? any)\n" "func @\"\".printslice (? any)\n"
"func @\"\".printnl ()\n" "func @\"\".printnl ()\n"
"func @\"\".printsp ()\n" "func @\"\".printsp ()\n"
"func @\"\".goprintf ()\n"
"func @\"\".concatstring2 (? string, ? string) (? string)\n" "func @\"\".concatstring2 (? string, ? string) (? string)\n"
"func @\"\".concatstring3 (? string, ? string, ? string) (? string)\n" "func @\"\".concatstring3 (? string, ? string, ? string) (? string)\n"
"func @\"\".concatstring4 (? string, ? string, ? string, ? string) (? string)\n" "func @\"\".concatstring4 (? string, ? string, ? string, ? string) (? string)\n"

View File

@ -36,7 +36,6 @@ func printeface(any)
func printslice(any) func printslice(any)
func printnl() func printnl()
func printsp() func printsp()
func goprintf()
func concatstring2(string, string) string func concatstring2(string, string) string
func concatstring3(string, string, string) string func concatstring3(string, string, string) string

View File

@ -7,7 +7,7 @@
#include "go.h" #include "go.h"
#include "../ld/textflag.h" #include "../ld/textflag.h"
static Node* walkprint(Node*, NodeList**, int); static Node* walkprint(Node*, NodeList**);
static Node* writebarrierfn(char*, Type*, Type*); static Node* writebarrierfn(char*, Type*, Type*);
static Node* applywritebarrier(Node*, NodeList**); static Node* applywritebarrier(Node*, NodeList**);
static Node* mapfn(char*, Type*); static Node* mapfn(char*, Type*);
@ -32,6 +32,7 @@ static void walkmul(Node**, NodeList**);
static void walkdiv(Node**, NodeList**); static void walkdiv(Node**, NodeList**);
static int bounded(Node*, int64); static int bounded(Node*, int64);
static Mpint mpzero; static Mpint mpzero;
static void walkprintfunc(Node**, NodeList**);
void void
walk(Node *fn) walk(Node *fn)
@ -226,8 +227,7 @@ walkstmt(Node **np)
switch(n->left->op) { switch(n->left->op) {
case OPRINT: case OPRINT:
case OPRINTN: case OPRINTN:
walkexprlist(n->left->list, &n->ninit); walkprintfunc(&n->left, &n->ninit);
n->left = walkprint(n->left, &n->ninit, 1);
break; break;
case OCOPY: case OCOPY:
n->left = copyany(n->left, &n->ninit, 1); n->left = copyany(n->left, &n->ninit, 1);
@ -260,8 +260,7 @@ walkstmt(Node **np)
switch(n->left->op) { switch(n->left->op) {
case OPRINT: case OPRINT:
case OPRINTN: case OPRINTN:
walkexprlist(n->left->list, &n->ninit); walkprintfunc(&n->left, &n->ninit);
n->left = walkprint(n->left, &n->ninit, 1);
break; break;
case OCOPY: case OCOPY:
n->left = copyany(n->left, &n->ninit, 1); n->left = copyany(n->left, &n->ninit, 1);
@ -543,7 +542,7 @@ walkexpr(Node **np, NodeList **init)
case OPRINT: case OPRINT:
case OPRINTN: case OPRINTN:
walkexprlist(n->list, init); walkexprlist(n->list, init);
n = walkprint(n, init, 0); n = walkprint(n, init);
goto ret; goto ret;
case OPANIC: case OPANIC:
@ -1757,7 +1756,7 @@ ret:
// generate code for print // generate code for print
static Node* static Node*
walkprint(Node *nn, NodeList **init, int defer) walkprint(Node *nn, NodeList **init)
{ {
Node *r; Node *r;
Node *n; Node *n;
@ -1765,31 +1764,17 @@ walkprint(Node *nn, NodeList **init, int defer)
Node *on; Node *on;
Type *t; Type *t;
int notfirst, et, op; int notfirst, et, op;
NodeList *calls, *intypes, *args; NodeList *calls;
Fmt fmt;
on = nil; on = nil;
op = nn->op; op = nn->op;
all = nn->list; all = nn->list;
calls = nil; calls = nil;
notfirst = 0; 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) { for(l=all; l; l=l->next) {
if(notfirst) { if(notfirst) {
if(defer) calls = list(calls, mkcall("printsp", T, init));
fmtprint(&fmt, " ");
else
calls = list(calls, mkcall("printsp", T, init));
} }
notfirst = op == OPRINTN; notfirst = op == OPRINTN;
@ -1817,122 +1802,63 @@ walkprint(Node *nn, NodeList **init, int defer)
t = n->type; t = n->type;
et = n->type->etype; et = n->type->etype;
if(isinter(n->type)) { if(isinter(n->type)) {
if(defer) { if(isnilinter(n->type))
if(isnilinter(n->type)) on = syslook("printeface", 1);
fmtprint(&fmt, "%%e"); else
else on = syslook("printiface", 1);
fmtprint(&fmt, "%%i"); argtype(on, n->type); // any-1
} else {
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) { } else if(isptr[et] || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR) {
if(defer) { on = syslook("printpointer", 1);
fmtprint(&fmt, "%%p"); argtype(on, n->type); // any-1
} else {
on = syslook("printpointer", 1);
argtype(on, n->type); // any-1
}
} else if(isslice(n->type)) { } else if(isslice(n->type)) {
if(defer) { on = syslook("printslice", 1);
fmtprint(&fmt, "%%a"); argtype(on, n->type); // any-1
} else {
on = syslook("printslice", 1);
argtype(on, n->type); // any-1
}
} else if(isint[et]) { } else if(isint[et]) {
if(defer) { if(et == TUINT64) {
if(et == TUINT64) if((t->sym->pkg == runtimepkg || compiling_runtime) && strcmp(t->sym->name, "hex") == 0)
fmtprint(&fmt, "%%U"); on = syslook("printhex", 0);
else { else
fmtprint(&fmt, "%%D"); on = syslook("printuint", 0);
t = types[TINT64]; } else
} on = syslook("printint", 0);
} 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]) { } else if(isfloat[et]) {
if(defer) { on = syslook("printfloat", 0);
fmtprint(&fmt, "%%f");
t = types[TFLOAT64];
} else
on = syslook("printfloat", 0);
} else if(iscomplex[et]) { } else if(iscomplex[et]) {
if(defer) { on = syslook("printcomplex", 0);
fmtprint(&fmt, "%%C");
t = types[TCOMPLEX128];
} else
on = syslook("printcomplex", 0);
} else if(et == TBOOL) { } else if(et == TBOOL) {
if(defer) on = syslook("printbool", 0);
fmtprint(&fmt, "%%t");
else
on = syslook("printbool", 0);
} else if(et == TSTRING) { } else if(et == TSTRING) {
if(defer) on = syslook("printstring", 0);
fmtprint(&fmt, "%%S");
else
on = syslook("printstring", 0);
} else { } else {
badtype(OPRINT, n->type, T); badtype(OPRINT, n->type, T);
continue; continue;
} }
if(!defer) { t = *getinarg(on->type);
t = *getinarg(on->type); if(t != nil)
if(t != nil) t = t->type;
t = t->type; if(t != nil)
if(t != nil) t = t->type;
t = t->type;
}
if(!eqtype(t, n->type)) { if(!eqtype(t, n->type)) {
n = nod(OCONV, n, N); n = nod(OCONV, n, N);
n->type = t; 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);
}
}
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 = nod(OCALL, on, N);
r->list = args; r->list = list1(n);
typecheck(&r, Etop); calls = list(calls, r);
walkexpr(&r, init);
} else {
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;
} }
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;
return r; return r;
} }
@ -3229,7 +3155,7 @@ countfield(Type *t)
static void static void
walkcompare(Node **np, NodeList **init) 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; int andor, i;
Type *t, *t1; Type *t, *t1;
@ -3249,18 +3175,25 @@ walkcompare(Node **np, NodeList **init)
break; break;
} }
if(!islvalue(n->left) || !islvalue(n->right)) { cmpl = n->left;
fatal("arguments of comparison must be lvalues"); 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)); 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 a->right->etype = 1; // addr does not escape
typecheck(&a, Etop); typecheck(&a, Etop);
*init = list(*init, a); *init = list(*init, a);
r = temp(ptrto(t)); 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 a->right->etype = 1; // addr does not escape
typecheck(&a, Etop); typecheck(&a, Etop);
*init = list(*init, a); *init = list(*init, a);
@ -3941,3 +3874,71 @@ candiscard(Node *n)
return 1; 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;
}

View File

@ -16,7 +16,7 @@ import (
) )
var cmdGet = &Command{ 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", Short: "download and install packages and dependencies",
Long: ` Long: `
Get downloads and installs the packages named by the import paths, 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, The -d flag instructs get to stop after downloading the packages; that is,
it instructs get not to install the packages. 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 The -fix flag instructs get to run the fix tool on the downloaded packages
before resolving dependencies or building the code. 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 getD = cmdGet.Flag.Bool("d", false, "")
var getF = cmdGet.Flag.Bool("f", false, "")
var getT = cmdGet.Flag.Bool("t", false, "") var getT = cmdGet.Flag.Bool("t", false, "")
var getU = cmdGet.Flag.Bool("u", false, "") var getU = cmdGet.Flag.Bool("u", false, "")
var getFix = cmdGet.Flag.Bool("fix", false, "") var getFix = cmdGet.Flag.Bool("fix", false, "")
@ -63,6 +69,10 @@ func init() {
} }
func runGet(cmd *Command, args []string) { func runGet(cmd *Command, args []string) {
if *getF && !*getU {
fatalf("go get: cannot use -f flag without -u")
}
// Phase 1. Download/update. // Phase 1. Download/update.
var stk importStack var stk importStack
for _, arg := range downloadPaths(args) { for _, arg := range downloadPaths(args) {
@ -268,7 +278,7 @@ func downloadPackage(p *Package) error {
repo = "<local>" // should be unused; make distinctive repo = "<local>" // should be unused; make distinctive
// Double-check where it came from. // Double-check where it came from.
if *getU && vcs.remoteRepo != nil { if *getU && vcs.remoteRepo != nil && !*getF {
dir := filepath.Join(p.build.SrcRoot, rootPath) dir := filepath.Join(p.build.SrcRoot, rootPath)
if remote, err := vcs.remoteRepo(vcs, dir); err == nil { if remote, err := vcs.remoteRepo(vcs, dir); err == nil {
if rr, err := repoRootForImportPath(p.ImportPath); err == nil { if rr, err := repoRootForImportPath(p.ImportPath); err == nil {

View File

@ -219,6 +219,16 @@ q' | ed $d/src/$config >/dev/null 2>&1
cat $d/err cat $d/err
ok=false ok=false
fi 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 fi
rm -rf $d rm -rf $d
} }

View File

@ -159,7 +159,7 @@ func dump(tab *gosym.Table, lookup lookupFunc, disasm disasmFunc, goarch string,
printed := false printed := false
for _, sym := range syms { 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 continue
} }
if sym.Addr >= textStart+uint64(len(textData)) || sym.Addr+uint64(sym.Size) > textStart+uint64(len(textData)) { if sym.Addr >= textStart+uint64(len(textData)) || sym.Addr+uint64(sym.Size) > textStart+uint64(len(textData)) {

View File

@ -157,12 +157,15 @@ var armNeed = []string{
// binary for the current system (only) and test that objdump // binary for the current system (only) and test that objdump
// can handle that one. // can handle that one.
func TestDisasm(t *testing.T) { func testDisasm(t *testing.T, flags ...string) {
tmp, exe := buildObjdump(t) tmp, exe := buildObjdump(t)
defer os.RemoveAll(tmp) defer os.RemoveAll(tmp)
hello := filepath.Join(tmp, "hello.exe") 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 { if err != nil {
t.Fatalf("go build fmthello.go: %v\n%s", err, out) 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) 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")
}

View File

@ -805,6 +805,9 @@ func (e *encodeState) string(s string) (int, error) {
case '\r': case '\r':
e.WriteByte('\\') e.WriteByte('\\')
e.WriteByte('r') e.WriteByte('r')
case '\t':
e.WriteByte('\\')
e.WriteByte('t')
default: default:
// This encodes bytes < 0x20 except for \n and \r, // 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
@ -878,9 +881,12 @@ func (e *encodeState) stringBytes(s []byte) (int, error) {
case '\r': case '\r':
e.WriteByte('\\') e.WriteByte('\\')
e.WriteByte('r') e.WriteByte('r')
case '\t':
e.WriteByte('\\')
e.WriteByte('t')
default: default:
// This encodes bytes < 0x20 except for \n and \r, // 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 // can lead to security holes when user-controlled strings
// are rendered into JSON and served to some browsers. // are rendered into JSON and served to some browsers.
e.WriteString(`\u00`) e.WriteString(`\u00`)

View File

@ -478,3 +478,55 @@ func TestEncodePointerString(t *testing.T) {
t.Fatalf("*N = %d; want 42", *back.N) 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)
}
}
}

View File

@ -38,8 +38,8 @@
%E scientific notation, e.g. -1234.456E+78 %E scientific notation, e.g. -1234.456E+78
%f decimal point but no exponent, e.g. 123.456 %f decimal point but no exponent, e.g. 123.456
%F synonym for %f %F synonym for %f
%g whichever of %e or %f produces more compact output %g %e for large exponents, %f otherwise
%G whichever of %E or %f produces more compact output %G %E for large exponents, %F otherwise
String and slice of bytes: String and slice of bytes:
%s the uninterpreted bytes of the string or slice %s the uninterpreted bytes of the string or slice
%q a double-quoted string safely escaped with Go syntax %q a double-quoted string safely escaped with Go syntax

View File

@ -138,7 +138,7 @@ func TestJSValEscaper(t *testing.T) {
// Newlines. // Newlines.
{"\r\n\u2028\u2029", `"\r\n\u2028\u2029"`}, {"\r\n\u2028\u2029", `"\r\n\u2028\u2029"`},
// "\v" == "v" on IE 6 so use "\x0b" instead. // "\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}`}, {struct{ X, Y int }{1, 2}, `{"X":1,"Y":2}`},
{[]interface{}{}, "[]"}, {[]interface{}{}, "[]"},
{[]interface{}{42, "foo", nil}, `[42,"foo",null]`}, {[]interface{}{42, "foo", nil}, `[42,"foo",null]`},

View File

@ -8,6 +8,7 @@ import (
"flag" "flag"
"fmt" "fmt"
"testing" "testing"
"time"
) )
var testDNSFlood = flag.Bool("dnsflood", false, "whether to test dns query flooding") 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. // 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)
}

View File

@ -36,7 +36,7 @@ func (f *File) readdirnames(n int) (names []string, err error) {
if d.bufp >= d.nbuf { if d.bufp >= d.nbuf {
d.bufp = 0 d.bufp = 0
var errno error 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 { if errno != nil {
return names, NewSyscallError("readdirent", errno) return names, NewSyscallError("readdirent", errno)
} }

View File

@ -255,3 +255,12 @@ var lstat = Lstat
func Rename(oldpath, newpath string) error { func Rename(oldpath, newpath string) error {
return rename(oldpath, newpath) 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
}

View File

@ -244,14 +244,14 @@ func (f *File) Sync() (err error) {
// read reads up to len(b) bytes from the File. // read reads up to len(b) bytes from the File.
// It returns the number of bytes read and an error, if any. // It returns the number of bytes read and an error, if any.
func (f *File) read(b []byte) (n int, err error) { 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. // 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. // It returns the number of bytes read and the error, if any.
// EOF is signaled by a zero count with err set to nil. // EOF is signaled by a zero count with err set to nil.
func (f *File) pread(b []byte, off int64) (n int, err error) { 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. // 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 { if len(b) == 0 {
return 0, nil 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. // 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 { if len(b) == 0 {
return 0, nil 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 // seek sets the offset for the next Read or Write on file to offset, interpreted

View File

@ -18,7 +18,7 @@ func sigpipe() // implemented in package runtime
func Readlink(name string) (string, error) { func Readlink(name string) (string, error) {
for len := 128; ; len *= 2 { for len := 128; ; len *= 2 {
b := make([]byte, len) b := make([]byte, len)
n, e := syscall.Readlink(name, b) n, e := fixCount(syscall.Readlink(name, b))
if e != nil { if e != nil {
return "", &PathError{"readlink", name, e} return "", &PathError{"readlink", name, e}
} }

View File

@ -187,7 +187,7 @@ func (f *File) read(b []byte) (n int, err error) {
if needsMaxRW && len(b) > maxRW { if needsMaxRW && len(b) > maxRW {
b = 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. // 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 { if needsMaxRW && len(b) > maxRW {
b = 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. // 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 { if needsMaxRW && len(bcap) > maxRW {
bcap = bcap[:maxRW] bcap = bcap[:maxRW]
} }
m, err := syscall.Write(f.fd, bcap) m, err := fixCount(syscall.Write(f.fd, bcap))
n += m n += m
// If the syscall wrote some data but not all (short write) // 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 { if needsMaxRW && len(b) > maxRW {
b = 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 // seek sets the offset for the next Read or Write on file to offset, interpreted

View File

@ -295,7 +295,7 @@ func (f *File) read(b []byte) (n int, err error) {
if f.isConsole { if f.isConsole {
return f.readConsole(b) 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. // 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 { if f.isConsole {
return f.writeConsole(b) 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. // pwrite writes len(b) bytes to the File starting at byte offset off.

View File

@ -732,6 +732,20 @@ needm:
MOVL g(CX), BP MOVL g(CX), BP
MOVL g_m(BP), 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: havem:
// Now there's a valid m, and we're running on its m->g0. // 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. // Save current m->g0->sched.sp on stack and then set it to SP.

View File

@ -717,6 +717,20 @@ needm:
get_tls(CX) get_tls(CX)
MOVQ g(CX), BP MOVQ g(CX), BP
MOVQ g_m(BP), 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: havem:
// Now there's a valid m, and we're running on its m->g0. // Now there's a valid m, and we're running on its m->g0.

View File

@ -556,6 +556,21 @@ TEXT ·cgocallback_gofunc(SB),NOSPLIT,$8-12
MOVW $runtime·needm(SB), R0 MOVW $runtime·needm(SB), R0
BL (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: havem:
MOVW g_m(g), R8 MOVW g_m(g), R8
MOVW R8, savedm-4(SP) MOVW R8, savedm-4(SP)

View File

@ -8,6 +8,7 @@ package runtime_test
import ( import (
"runtime" "runtime"
"strings"
"testing" "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 = ` const cgoSignalDeadlockSource = `
package main package main
@ -117,3 +129,43 @@ func main() {
fmt.Printf("OK\n") 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");
}
`

View File

@ -31,7 +31,7 @@ func testEnv(cmd *exec.Cmd) *exec.Cmd {
return 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 { switch runtime.GOOS {
case "android", "nacl": case "android", "nacl":
t.Skipf("skipping on %s", runtime.GOOS) 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) 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) return string(got)
} }

View File

@ -16,6 +16,7 @@ type GCStats struct {
NumGC int64 // number of garbage collections NumGC int64 // number of garbage collections
PauseTotal time.Duration // total pause for all collections PauseTotal time.Duration // total pause for all collections
Pause []time.Duration // pause history, most recent first Pause []time.Duration // pause history, most recent first
PauseEnd []time.Time // pause end times history, most recent first
PauseQuantiles []time.Duration PauseQuantiles []time.Duration
} }
@ -30,25 +31,36 @@ type GCStats struct {
func ReadGCStats(stats *GCStats) { func ReadGCStats(stats *GCStats) {
// Create a buffer with space for at least two copies of the // Create a buffer with space for at least two copies of the
// pause history tracked by the runtime. One will be returned // pause history tracked by the runtime. One will be returned
// to the caller and the other will be used as a temporary buffer // to the caller and the other will be used as transfer buffer
// for computing quantiles. // for end times history and as a temporary buffer for
// computing quantiles.
const maxPause = len(((*runtime.MemStats)(nil)).PauseNs) const maxPause = len(((*runtime.MemStats)(nil)).PauseNs)
if cap(stats.Pause) < 2*maxPause { if cap(stats.Pause) < 2*maxPause+3 {
stats.Pause = make([]time.Duration, 2*maxPause) stats.Pause = make([]time.Duration, 2*maxPause+3)
} }
// readGCStats fills in the pause history (up to maxPause entries) // readGCStats fills in the pause and end times histories (up to
// and then three more: Unix ns time of last GC, number of GC, // maxPause entries) and then three more: Unix ns time of last GC,
// and total pause time in nanoseconds. Here we depend on the // number of GC, and total pause time in nanoseconds. Here we
// fact that time.Duration's native unit is nanoseconds, so the // depend on the fact that time.Duration's native unit is
// pauses and the total pause time do not need any conversion. // nanoseconds, so the pauses and the total pause time do not need
// any conversion.
readGCStats(&stats.Pause) readGCStats(&stats.Pause)
n := len(stats.Pause) - 3 n := len(stats.Pause) - 3
stats.LastGC = time.Unix(0, int64(stats.Pause[n])) stats.LastGC = time.Unix(0, int64(stats.Pause[n]))
stats.NumGC = int64(stats.Pause[n+1]) stats.NumGC = int64(stats.Pause[n+1])
stats.PauseTotal = stats.Pause[n+2] stats.PauseTotal = stats.Pause[n+2]
n /= 2 // buffer holds pauses and end times
stats.Pause = stats.Pause[:n] 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 len(stats.PauseQuantiles) > 0 {
if n == 0 { if n == 0 {
for i := range stats.PauseQuantiles { for i := range stats.PauseQuantiles {

View 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]) 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) var big = make([]byte, 1<<20)

View 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 gcdead: setting gcdead=1 causes the garbage collector to clobber all stack slots
that it thinks are dead. 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 scheddetail: setting schedtrace=X and scheddetail=1 causes the scheduler to emit
detailed multiline info every X milliseconds, describing state of the scheduler, detailed multiline info every X milliseconds, describing state of the scheduler,
processors, threads and goroutines. processors, threads and goroutines.

View File

@ -28,6 +28,9 @@
// defines the pointer map for the function's arguments. // defines the pointer map for the function's arguments.
// GO_ARGS should be the first instruction in a function that uses it. // GO_ARGS should be the first instruction in a function that uses it.
// It can be omitted if there are no arguments at all. // 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) #define GO_ARGS FUNCDATA $FUNCDATA_ArgsPointerMaps, go_args_stackmap(SB)
// GO_RESULTS_INITIALIZED indicates that the assembly function // GO_RESULTS_INITIALIZED indicates that the assembly function

View File

@ -267,7 +267,8 @@ struct MStats
uint64 next_gc; // next GC (in heap_alloc time) uint64 next_gc; // next GC (in heap_alloc time)
uint64 last_gc; // last GC (in absolute time) uint64 last_gc; // last GC (in absolute time)
uint64 pause_total_ns; 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; uint32 numgc;
bool enablegc; bool enablegc;
bool debuggc; bool debuggc;

View File

@ -44,7 +44,8 @@ type MemStats struct {
NextGC uint64 // next collection will happen when HeapAlloc ≥ this amount NextGC uint64 // next collection will happen when HeapAlloc ≥ this amount
LastGC uint64 // end time of last collection (nanoseconds since 1970) LastGC uint64 // end time of last collection (nanoseconds since 1970)
PauseTotalNs uint64 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 NumGC uint32
EnableGC bool EnableGC bool
DebugGC bool DebugGC bool

View File

@ -330,7 +330,7 @@ scanblock(byte *b, uintptr n, byte *ptrmask)
if(obj == nil) if(obj == nil)
continue; continue;
if(obj < arena_start || obj >= arena_used) { if(obj < arena_start || obj >= arena_used) {
if((uintptr)obj < PhysPageSize) { if((uintptr)obj < PhysPageSize && runtime·invalidptr) {
s = nil; s = nil;
goto badobj; goto badobj;
} }
@ -375,7 +375,7 @@ scanblock(byte *b, uintptr n, byte *ptrmask)
else else
runtime·printf(" span=%p-%p-%p state=%d\n", (uintptr)s->start<<PageShift, s->limit, (uintptr)(s->start+s->npages)<<PageShift, s->state); runtime·printf(" span=%p-%p-%p state=%d\n", (uintptr)s->start<<PageShift, s->limit, (uintptr)(s->start+s->npages)<<PageShift, s->state);
if(ptrmask != nil) if(ptrmask != nil)
runtime·throw("bad pointer"); runtime·throw("invalid heap pointer");
// Add to badblock list, which will cause the garbage collection // Add to badblock list, which will cause the garbage collection
// to keep repeating until it has traced the chain of pointers // to keep repeating until it has traced the chain of pointers
// leading to obj all the way back to a root. // leading to obj all the way back to a root.
@ -1459,6 +1459,7 @@ gc(struct gc_args *args)
t4 = runtime·nanotime(); t4 = runtime·nanotime();
runtime·atomicstore64(&mstats.last_gc, runtime·unixnanotime()); // must be Unix time to make sense to user 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_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.pause_total_ns += t4 - t0;
mstats.numgc++; mstats.numgc++;
if(mstats.debuggc) if(mstats.debuggc)
@ -1572,7 +1573,7 @@ readgcstats_m(void)
{ {
Slice *pauses; Slice *pauses;
uint64 *p; uint64 *p;
uint32 i, n; uint32 i, j, n;
pauses = g->m->ptrarg[0]; pauses = g->m->ptrarg[0];
g->m->ptrarg[0] = nil; g->m->ptrarg[0] = nil;
@ -1581,25 +1582,29 @@ readgcstats_m(void)
if(pauses->cap < nelem(mstats.pause_ns)+3) if(pauses->cap < nelem(mstats.pause_ns)+3)
runtime·throw("runtime: short slice passed to readGCStats"); 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; p = (uint64*)pauses->array;
runtime·lock(&runtime·mheap.lock); runtime·lock(&runtime·mheap.lock);
n = mstats.numgc; n = mstats.numgc;
if(n > nelem(mstats.pause_ns)) if(n > nelem(mstats.pause_ns))
n = nelem(mstats.pause_ns); n = nelem(mstats.pause_ns);
// The pause buffer is circular. The most recent pause is at // The pause buffer is circular. The most recent pause is at
// pause_ns[(numgc-1)%nelem(pause_ns)], and then backward // pause_ns[(numgc-1)%nelem(pause_ns)], and then backward
// from there to go back farther in time. We deliver the times // from there to go back farther in time. We deliver the times
// most recent first (in p[0]). // most recent first (in p[0]).
for(i=0; i<n; i++) for(i=0; i<n; i++) {
p[i] = mstats.pause_ns[(mstats.numgc-1-i)%nelem(mstats.pause_ns)]; 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+n] = mstats.last_gc;
p[n+1] = mstats.numgc; p[n+n+1] = mstats.numgc;
p[n+2] = mstats.pause_total_ns; p[n+n+2] = mstats.pause_total_ns;
runtime·unlock(&runtime·mheap.lock); runtime·unlock(&runtime·mheap.lock);
pauses->len = n+3; pauses->len = n+n+3;
} }
void void

View File

@ -19,32 +19,17 @@ func bytes(s string) (ret []byte) {
return return
} }
// goprintf is the function call that is actually deferred when you write // printf is only called from C code. It has no type information for the args,
// defer print(...) // but C stacks are ignored by the garbage collector anyway, so having
// It is otherwise unused. In particular it is not used for ordinary prints. // type information would not add anything.
// 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.
//go:nosplit //go:nosplit
func printf(s *byte) { func printf(s *byte) {
vprintf(gostringnocopy(s), add(unsafe.Pointer(&s), unsafe.Sizeof(s))) vprintf(gostringnocopy(s), add(unsafe.Pointer(&s), unsafe.Sizeof(s)))
} }
// sprintf is only called from C code. // sprintf is only called from C code. It has no type information for the args,
// It has the same problem as goprintf. // but C stacks are ignored by the garbage collector anyway, so having
// type information would not add anything.
//go:nosplit //go:nosplit
func snprintf(dst *byte, n int32, s *byte) { func snprintf(dst *byte, n int32, s *byte) {
buf := (*[1 << 30]byte)(unsafe.Pointer(dst))[0:n:n] buf := (*[1 << 30]byte)(unsafe.Pointer(dst))[0:n:n]

View File

@ -2758,6 +2758,8 @@ static void
checkdead(void) checkdead(void)
{ {
G *gp; G *gp;
P *p;
M *mp;
int32 run, grunning, s; int32 run, grunning, s;
uintptr i; uintptr i;
@ -2799,6 +2801,24 @@ checkdead(void)
runtime·unlock(&runtime·allglock); runtime·unlock(&runtime·allglock);
if(grunning == 0) // possible if main goroutine calls runtime·Goexit() if(grunning == 0) // possible if main goroutine calls runtime·Goexit()
runtime·throw("no goroutines (main called runtime.Goexit) - deadlock!"); 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 g->m->throwing = -1; // do not dump full stacks
runtime·throw("all goroutines are asleep - deadlock!"); runtime·throw("all goroutines are asleep - deadlock!");
} }

View File

@ -26,5 +26,5 @@ TEXT _rt0_amd64p32_nacl(SB),NOSPLIT,$16
TEXT main(SB),NOSPLIT,$0 TEXT main(SB),NOSPLIT,$0
// Uncomment for fake time like on Go Playground. // Uncomment for fake time like on Go Playground.
//MOVQ $1257894000000000000, AX //MOVQ $1257894000000000000, AX
//MOVQ AX, runtime·timens(SB) //MOVQ AX, runtime·faketime(SB)
JMP runtime·rt0_go(SB) JMP runtime·rt0_go(SB)

View File

@ -282,9 +282,13 @@ struct DbgVar
int32* value; 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 */ #pragma dataflag NOPTR /* dbgvar has no heap pointers */
static DbgVar dbgvar[] = { static DbgVar dbgvar[] = {
{"allocfreetrace", &runtime·debug.allocfreetrace}, {"allocfreetrace", &runtime·debug.allocfreetrace},
{"invalidptr", &runtime·invalidptr},
{"efence", &runtime·debug.efence}, {"efence", &runtime·debug.efence},
{"gctrace", &runtime·debug.gctrace}, {"gctrace", &runtime·debug.gctrace},
{"gcdead", &runtime·debug.gcdead}, {"gcdead", &runtime·debug.gcdead},

View File

@ -657,6 +657,8 @@ enum {
byte* runtime·startup_random_data; byte* runtime·startup_random_data;
uint32 runtime·startup_random_data_len; uint32 runtime·startup_random_data_len;
int32 runtime·invalidptr;
enum { enum {
// hashinit wants this many random bytes // hashinit wants this many random bytes
HashRandomBytes = 32 HashRandomBytes = 32

View File

@ -401,12 +401,12 @@ adjustpointers(byte **scanp, BitVector *bv, AdjustInfo *adjinfo, Func *f)
break; break;
case BitsPointer: case BitsPointer:
p = scanp[i]; 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. // Looks like a junk value in a pointer slot.
// Live analysis wrong? // Live analysis wrong?
g->m->traceback = 2; g->m->traceback = 2;
runtime·printf("runtime: bad pointer in frame %s at %p: %p\n", runtime·funcname(f), &scanp[i], p); 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(minp <= p && p < maxp) {
if(StackDebug >= 3) if(StackDebug >= 3)

View File

@ -60,7 +60,7 @@ TEXT syscall·naclWrite(SB), NOSPLIT, $24-20
TEXT runtime·write(SB),NOSPLIT,$16-20 TEXT runtime·write(SB),NOSPLIT,$16-20
// If using fake time and writing to stdout or stderr, // If using fake time and writing to stdout or stderr,
// emit playback header before actual data. // emit playback header before actual data.
MOVQ runtime·timens(SB), AX MOVQ runtime·faketime(SB), AX
CMPQ AX, $0 CMPQ AX, $0
JEQ write JEQ write
MOVL fd+0(FP), DI MOVL fd+0(FP), DI
@ -242,7 +242,7 @@ TEXT runtime·mmap(SB),NOSPLIT,$8
RET RET
TEXT time·now(SB),NOSPLIT,$16 TEXT time·now(SB),NOSPLIT,$16
MOVQ runtime·timens(SB), AX MOVQ runtime·faketime(SB), AX
CMPQ AX, $0 CMPQ AX, $0
JEQ realtime JEQ realtime
MOVQ $0, DX MOVQ $0, DX
@ -277,7 +277,7 @@ TEXT runtime·nacl_clock_gettime(SB),NOSPLIT,$0
RET RET
TEXT runtime·nanotime(SB),NOSPLIT,$16 TEXT runtime·nanotime(SB),NOSPLIT,$16
MOVQ runtime·timens(SB), AX MOVQ runtime·faketime(SB), AX
CMPQ AX, $0 CMPQ AX, $0
JEQ 3(PC) JEQ 3(PC)
MOVQ AX, ret+0(FP) MOVQ AX, ret+0(FP)

View File

@ -35,8 +35,8 @@ var timers struct {
t []*timer t []*timer
} }
// nacl fake time support. // nacl fake time support - time in nanoseconds since 1970
var timens int64 var faketime int64
// Package time APIs. // Package time APIs.
// Godoc uses the comments in package time, not these. // Godoc uses the comments in package time, not these.
@ -194,7 +194,7 @@ func timerproc() {
f(arg, seq) f(arg, seq)
lock(&timers.lock) lock(&timers.lock)
} }
if delta < 0 { if delta < 0 || faketime > 0 {
// No timers left - put goroutine to sleep. // No timers left - put goroutine to sleep.
timers.rescheduling = true timers.rescheduling = true
goparkunlock(&timers.lock, "timer goroutine (idle)") 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. // Heap maintenance algorithms.
func siftupTimer(i int) { func siftupTimer(i int) {

View File

@ -818,6 +818,12 @@ func create(name string, mode uint32, sec int64, data []byte) error {
fs.mu.Unlock() fs.mu.Unlock()
f, err := fs.open(name, O_CREATE|O_EXCL, mode) f, err := fs.open(name, O_CREATE|O_EXCL, mode)
if err != nil { 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 return err
} }
ip := f.(*fsysFile).inode ip := f.(*fsysFile).inode

View File

@ -153,7 +153,7 @@ func (m *InterfaceAddrMessage) sockaddr() (sas []Sockaddr) {
// RTAX_NETMASK socket address on the FreeBSD kernel. // RTAX_NETMASK socket address on the FreeBSD kernel.
preferredFamily := uint8(AF_UNSPEC) preferredFamily := uint8(AF_UNSPEC)
for i := uint(0); i < RTAX_MAX; i++ { for i := uint(0); i < RTAX_MAX; i++ {
if m.Header.Addrs&rtaIfaMask&(1<<i) == 0 { if m.Header.Addrs&(1<<i) == 0 {
continue continue
} }
rsa := (*RawSockaddr)(unsafe.Pointer(&b[0])) rsa := (*RawSockaddr)(unsafe.Pointer(&b[0]))

View File

@ -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")
}
}

View File

@ -44,14 +44,21 @@ func checkLinear(typ string, tries int, f func(n int)) {
} }
return return
} }
fails++ // If n ops run in under a second and the ratio
if fails == 6 { // 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", panic(fmt.Sprintf("%s: too slow: %d inserts: %v; %d inserts: %v\n",
typ, n, t1, 2*n, t2)) typ, n, t1, 2*n, t2))
} }
if fails < 4 {
n *= 2
}
} }
} }