[dev.power64] all: merge default into dev.power64

This brings dev.power64 up-to-date with the current tip of
default.  go_bootstrap is still panicking with a bad defer
when initializing the runtime (even on amd64).

LGTM=rsc
R=rsc
CC=golang-codereviews
https://golang.org/cl/152570049
This commit is contained in:
Austin Clements 2014-10-22 15:51:54 -04:00
commit f0bd539c59
663 changed files with 60112 additions and 34009 deletions

View file

@ -23,16 +23,12 @@ _test
_testmain.go
build.out
test.out
doc/tmpltohtml
doc/articles/wiki/*.bin
include/plan9/libc_plan9.h
misc/cgo/life/run.out
misc/cgo/stdio/run.out
misc/cgo/testso/main
misc/dashboard/builder/builder
misc/goplay/goplay
misc/osx/*.pkg
misc/osx/*.dmg
src/cmd/?a/y.output
src/liblink/anames?.c
src/cmd/cc/y.output
@ -43,7 +39,6 @@ src/cmd/gc/opnames.h
src/cmd/gc/y.output
src/cmd/go/zdefaultcc.go
src/go/doc/headscan
src/runtime/goc2c
src/runtime/mkversion
src/runtime/z*
src/unicode/maketables

View file

@ -132,4 +132,6 @@ f8b50ad4cac4d4c4ecf48324b4f512f65e82cc1c go1.3beta1
3f66a43d5180052e2e1e38d979d1aa5ad05b21f9 go1.3rc2
9895f9e36435468d503eaa74ee217f28d5e28dd4 go1.3
073fc578434bf3e1e22749b559d273c8da728ebb go1.3.1
073fc578434bf3e1e22749b559d273c8da728ebb release
85518b1d6f8d6e16133b9ed2c9db6807522d37de go1.3.2
f44017549ff9c3cc5eef74ebe7276cd0dfc066b6 go1.3.3
f44017549ff9c3cc5eef74ebe7276cd0dfc066b6 release

View file

@ -13,6 +13,7 @@ Abhinav Gupta <abhinav.g90@gmail.com>
Adrian Nos <nos.adrian@gmail.com>
Adrian O'Grady <elpollouk@gmail.com>
Adrien Bustany <adrien-xx-google@bustany.org>
Ahmed Waheed Moanes <oneofone@gmail.com>
Akshat Kumar <seed@mail.nanosouffle.net>
Alan Shreve <alan@inconshreveable.com>
Albert Strasheim <fullung@gmail.com>
@ -182,6 +183,7 @@ Gustavo Niemeyer <gustavo@niemeyer.net>
Gwenael Treguier <gwenn.kahz@gmail.com>
Harley Laue <losinggeneration@gmail.com>
Hector Chu <hectorchu@gmail.com>
Hector Martin Cantero <hector@marcansoft.com>
Henning Schmiedehausen <henning@schmiedehausen.org>
Henrik Edwards <henrik.edwards@gmail.com>
Herbert Georg Fischer <herbert.fischer@gmail.com>
@ -212,6 +214,7 @@ Jeff Hodges <jeff@somethingsimilar.com>
Jeff R. Allen <jra@nella.org>
Jeff Sickel <jas@corpus-callosum.com>
Jeff Wendling <jeff@spacemonkey.com>
Jens Frederich <jfrederich@gmail.com>
Jeremy Jackins <jeremyjackins@gmail.com>
Jim McGrath <jimmc2@gmail.com>
Jimmy Zelinskie <jimmyzelinskie@gmail.com>
@ -225,6 +228,7 @@ John C Barstow <jbowtie@amathaine.com>
John Graham-Cumming <jgc@jgc.org> <jgrahamc@gmail.com>
John Howard Palevich <jack.palevich@gmail.com>
John Shahid <jvshahid@gmail.com>
John Tuley <john@tuley.org>
Jonathan Gold <jgold.bg@gmail.com>
Jonathan Mark <jhmark@xenops.com>
Jonathan Rudenberg <jonathan@titanous.com>
@ -236,6 +240,7 @@ Josh Bleecher Snyder <josharian@gmail.com>
Josh Goebel <dreamer3@gmail.com>
Josh Holland <jrh@joshh.co.uk>
Joshua Chase <jcjoshuachase@gmail.com>
JT Olds <jtolds@xnet5.com>
Jukka-Pekka Kekkonen <karatepekka@gmail.com>
Julian Phillips <julian@quantumfyre.co.uk>
Julien Schmidt <google@julienschmidt.com>
@ -290,6 +295,7 @@ Michael Fraenkel <michael.fraenkel@gmail.com>
Michael Gehring <mg@ebfe.org> <gnirheg.leahcim@gmail.com>
Michael Hoisie <hoisie@gmail.com>
Michael Lewis <mikelikespie@gmail.com>
Michael MacInnis <Michael.P.MacInnis@gmail.com>
Michael Pearson <mipearson@gmail.com>
Michael Stapelberg <michael@stapelberg.de>
Michael Teichgräber <mteichgraeber@gmx.de>
@ -355,6 +361,7 @@ Pietro Gagliardi <pietro10@mac.com>
Preetam Jinka <pj@preet.am>
Quan Yong Zhai <qyzhai@gmail.com>
Raif S. Naffah <go@naffah-raif.name>
Red Hat, Inc.
Rémy Oudompheng <oudomphe@phare.normalesup.org>
Richard Crowley <r@rcrowley.org>
Richard Eric Gavaletz <gavaletz@gmail.com>
@ -371,6 +378,7 @@ Rodrigo Moraes de Oliveira <rodrigo.moraes@gmail.com>
Rodrigo Rafael Monti Kochenburger <divoxx@gmail.com>
Roger Pau Monné <royger@gmail.com>
Roger Peppe <rogpeppe@gmail.com>
Ron Hashimoto <mail@h2so5.net>
Ron Minnich <rminnich@gmail.com>
Ross Light <rlight2@gmail.com>
Rowan Worth <sqweek@gmail.com>
@ -413,6 +421,7 @@ Thomas Kappler <tkappler@gmail.com>
Timo Savola <timo.savola@gmail.com>
Timo Truyts <alkaloid.btx@gmail.com>
Tobias Columbus <tobias.columbus@gmail.com>
Tom Linford <tomlinford@gmail.com>
Tor Andersson <tor.andersson@gmail.com>
Travis Cline <travis.cline@gmail.com>
Tudor Golubenco <tudor.g@gmail.com>

View file

@ -38,6 +38,7 @@ Adam Langley <agl@golang.org>
Adrian Nos <nos.adrian@gmail.com>
Adrian O'Grady <elpollouk@gmail.com>
Adrien Bustany <adrien-xx-google@bustany.org>
Ahmed Waheed Moanes <oneofone@gmail.com>
Akshat Kumar <seed@mail.nanosouffle.net>
Alan Donovan <adonovan@google.com>
Alan Shreve <alan@inconshreveable.com>
@ -65,6 +66,7 @@ Amrut Joshi <amrut.joshi@gmail.com>
Andrea Spadaccini <spadaccio@google.com>
Andreas Jellinghaus <andreas@ionisiert.de> <anj@google.com>
Andrei Vieru <euvieru@gmail.com>
Andres Erbsen <andreser@google.com>
Andrew Balholm <andybalholm@gmail.com>
Andrew Bonventre <andybons@chromium.org>
Andrew Bursavich <abursavich@gmail.com>
@ -94,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>
@ -158,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>
@ -254,9 +257,11 @@ Gustav Paul <gustav.paul@gmail.com>
Gustavo Franco <gustavorfranco@gmail.com>
Gustavo Niemeyer <gustavo@niemeyer.net> <n13m3y3r@gmail.com>
Gwenael Treguier <gwenn.kahz@gmail.com>
Hana Kim <hyangah@gmail.com>
Han-Wen Nienhuys <hanwen@google.com>
Harley Laue <losinggeneration@gmail.com>
Hector Chu <hectorchu@gmail.com>
Hector Martin Cantero <hector@marcansoft.com>
Henning Schmiedehausen <henning@schmiedehausen.org>
Henrik Edwards <henrik.edwards@gmail.com>
Herbert Georg Fischer <herbert.fischer@gmail.com>
@ -276,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>
@ -297,6 +303,7 @@ Jeff Hodges <jeff@somethingsimilar.com>
Jeff R. Allen <jra@nella.org> <jeff.allen@gmail.com>
Jeff Sickel <jas@corpus-callosum.com>
Jeff Wendling <jeff@spacemonkey.com>
Jens Frederich <jfrederich@gmail.com>
Jeremiah Harmsen <jeremiah@google.com>
Jeremy Jackins <jeremyjackins@gmail.com>
Jeremy Schlatter <jeremy.schlatter@gmail.com>
@ -317,6 +324,7 @@ John Graham-Cumming <jgc@jgc.org> <jgrahamc@gmail.com>
John Howard Palevich <jack.palevich@gmail.com>
John Newlin <jnewlin@google.com>
John Shahid <jvshahid@gmail.com>
John Tuley <john@tuley.org>
Jonathan Allie <jonallie@google.com>
Jonathan Feinberg <feinberg@google.com>
Jonathan Gold <jgold.bg@gmail.com>
@ -337,6 +345,7 @@ Josh Hoak <jhoak@google.com>
Josh Holland <jrh@joshh.co.uk>
Joshua Chase <jcjoshuachase@gmail.com>
JP Sugarbroad <jpsugar@google.com>
JT Olds <jtolds@xnet5.com>
Jukka-Pekka Kekkonen <karatepekka@gmail.com>
Julian Phillips <julian@quantumfyre.co.uk>
Julien Schmidt <google@julienschmidt.com>
@ -409,6 +418,7 @@ Michael Hoisie <hoisie@gmail.com>
Michael Hudson-Doyle <michael.hudson@linaro.org>
Michael Kelly <mjk@google.com>
Michael Lewis <mikelikespie@gmail.com>
Michael MacInnis <Michael.P.MacInnis@gmail.com>
Michael Matloob <matloob@google.com>
Michael Pearson <mipearson@gmail.com>
Michael Piatek <piatek@google.com>
@ -431,6 +441,7 @@ Mikkel Krautz <mikkel@krautz.dk> <krautz@gmail.com>
Miquel Sabaté Solà <mikisabate@gmail.com>
Moriyoshi Koizumi <mozo@mozo.jp>
Môshe van der Sterre <moshevds@gmail.com>
Mrunal Patel <mrunalp@gmail.com>
Nan Deng <monnand@gmail.com>
Nathan John Youngman <nj@nathany.com>
Nicholas Katsaros <nick@nickkatsaros.com>
@ -490,6 +501,7 @@ Preetam Jinka <pj@preet.am>
Quan Yong Zhai <qyzhai@gmail.com>
Raif S. Naffah <go@naffah-raif.name>
Raph Levien <raph@google.com>
Raul Silvera <rsilvera@google.com>
Rémy Oudompheng <oudomphe@phare.normalesup.org> <remyoudompheng@gmail.com>
Richard Crowley <r@rcrowley.org>
Richard Eric Gavaletz <gavaletz@gmail.com>
@ -511,6 +523,7 @@ Rodrigo Moraes de Oliveira <rodrigo.moraes@gmail.com>
Rodrigo Rafael Monti Kochenburger <divoxx@gmail.com>
Roger Pau Monné <royger@gmail.com>
Roger Peppe <rogpeppe@gmail.com>
Ron Hashimoto <mail@h2so5.net>
Ron Minnich <rminnich@gmail.com>
Ross Light <rlight2@gmail.com>
Rowan Worth <sqweek@gmail.com>
@ -565,6 +578,7 @@ Timo Savola <timo.savola@gmail.com>
Timo Truyts <alkaloid.btx@gmail.com>
Tobias Columbus <tobias.columbus@gmail.com> <tobias.columbus@googlemail.com>
Todd Wang <toddwang@gmail.com>
Tom Linford <tomlinford@gmail.com>
Tom Szymanski <tgs@google.com>
Tor Andersson <tor.andersson@gmail.com>
Travis Cline <travis.cline@gmail.com>

View file

@ -27,6 +27,16 @@ go1.3.1 (released 2014/08/13) includes bug fixes to the compiler and the <code>r
See the <a href="//code.google.com/p/go/source/list?name=release-branch.go1.3&r=073fc578434bf3e1e22749b559d273c8da728ebb">change history</a> for details.
</p>
<p>
go1.3.2 (released 2014/09/25) includes bug fixes to cgo and the crypto/tls packages.
See the <a href="//code.google.com/p/go/source/list?name=release-branch.go1.3&r=go1.3.2">change history</a> for details.
</p>
<p>
go1.3.3 (released 2014/09/30) includes further bug fixes to cgo, the runtime package, and the nacl port.
See the <a href="//code.google.com/p/go/source/list?name=release-branch.go1.3&r=go1.3.3">change history</a> for details.
</p>
<h2 id="go1.2">go1.2 (released 2013/12/01)</h2>
<p>

View file

@ -13,23 +13,39 @@ cmd/6l, liblink: use pc-relative addressing for all memory references, so that l
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)
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/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)
syscal: now frozen (CL 129820043)
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).
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

View file

@ -2035,4 +2035,4 @@ They are available for many combinations of architecture and operating system
Installation details are described on the
<a href="/doc/install">Getting Started</a> page, while
the distributions themselves are listed on the
<a href="/dl/">downloads page</a>.
<a href="https://golang.org/dl/">downloads page</a>.

View file

@ -83,16 +83,16 @@ break if the bug is fixed. We reserve the right to fix such bugs.
<li>
Struct literals. For the addition of features in later point
releases, it may be necessary to add fields to exported structs in
the API. Code that uses untagged struct literals (such as pkg.T{3,
the API. Code that uses unkeyed struct literals (such as pkg.T{3,
"x"}) to create values of these types would fail to compile after
such a change. However, code that uses tagged literals (pkg.T{A:
such a change. However, code that uses keyed literals (pkg.T{A:
3, B: "x"}) will continue to compile after such a change. We will
update such data structures in a way that allows tagged struct
literals to remain compatible, although untagged literals may fail
update such data structures in a way that allows keyed struct
literals to remain compatible, although unkeyed literals may fail
to compile. (There are also more intricate cases involving nested
data structures or interfaces, but they have the same resolution.)
We therefore recommend that composite literals whose type is defined
in a separate package should use the tagged notation.
in a separate package should use the keyed notation.
</li>
<li>

View file

@ -889,6 +889,11 @@ type is generic; if you care about how many bits an integer holds, Go
encourages you to be explicit.
</p>
<p>
A blog post, title <a href="http://blog.golang.org/constants">Constants</a>,
explores this topic in more detail.
</p>
<h3 id="builtin_maps">
Why are maps built in?</h3>
<p>
@ -971,7 +976,7 @@ It is a handy reference for people doing code reviews for Go projects.
How do I submit patches to the Go libraries?</h3>
<p>
The library sources are in <code>go/src</code>.
The library sources are in the <code>src</code> directory of the repository.
If you want to make a significant change, please discuss on the mailing list before embarking.
</p>
@ -1590,30 +1595,40 @@ and uses a variant of the Plan 9 loader to generate ELF/Mach-O/PE binaries.
</p>
<p>
We considered writing <code>gc</code>, the original Go compiler, in Go itself but
elected not to do so because of the difficulties of bootstrapping and
especially of open source distribution&mdash;you'd need a Go compiler to
set up a Go environment. <code>Gccgo</code>, which came later, makes it possible to
consider writing a compiler in Go, which might well happen.
(Go would be a
fine language in which to implement a compiler; a native lexer and
parser are already available in the <a href="/pkg/go/"><code>go</code></a> package
and a type checker is in the works.)
We considered using LLVM for <code>gc</code> but we felt it was too large and
slow to meet our performance goals.
</p>
<p>
We also considered using LLVM for <code>gc</code> but we felt it was too large and
slow to meet our performance goals.
We also considered writing <code>gc</code>, the original Go compiler, in Go itself but
elected not to do so because of the difficulties of bootstrapping and
especially of open source distribution&mdash;you'd need a Go compiler to
set up a Go environment. <code>Gccgo</code>, which came later, makes it possible to
consider writing a compiler in Go.
A plan to do that by machine translation of the existing compiler is under development.
<a href="http://golang.org/s/go13compiler">A separate document</a>
explains the reason for this approach.
</p>
<p>
That plan aside,
Go is a
fine language in which to implement a self-hosting compiler: a native lexer and
parser are already available in the <a href="/pkg/go/"><code>go</code></a> package
and a separate type checking
<a href="http://godoc.org/code.google.com/p/go.tools/go/types">package</a>
has also been written.
</p>
<h3 id="How_is_the_run_time_support_implemented">
How is the run-time support implemented?</h3>
<p>
Again due to bootstrapping issues, the run-time code is mostly in C (with a
tiny bit of assembler) although Go is capable of implementing most of
it now. <code>Gccgo</code>'s run-time support uses <code>glibc</code>.
<code>Gc</code> uses a custom library to keep the footprint under
Again due to bootstrapping issues, the run-time code was originally written mostly in C (with a
tiny bit of assembler) although much of it has been translated to Go since then
and one day all of it might be (except for the assembler bits).
<code>Gccgo</code>'s run-time support uses <code>glibc</code>.
<code>Gc</code> uses a custom C library to keep the footprint under
control; it is
compiled with a version of the Plan 9 C compiler that supports
resizable stacks for goroutines.
@ -1637,8 +1652,8 @@ A simple C "hello, world" program compiled and linked statically using gcc
on Linux is around 750 kB,
including an implementation of <code>printf</code>.
An equivalent Go program using <code>fmt.Printf</code>
is around 1.2 MB, but
that includes more powerful run-time support.
is around 1.9 MB, but
that includes more powerful run-time support and type information.
</p>
<h3 id="unused_variables_and_imports">
@ -1646,14 +1661,17 @@ Can I stop these complaints about my unused variable/import?</h3>
<p>
The presence of an unused variable may indicate a bug, while
unused imports just slow down compilation.
Accumulate enough unused imports in your code tree and
things can get very slow.
For these reasons, Go allows neither.
unused imports just slow down compilation,
an effect that can become substantial as a program accumulates
code and programmers over time.
For these reasons, Go refuses to compile programs with unused
variables or imports,
trading short-term convenience for long-term build speed and
program clarity.
</p>
<p>
When developing code, it's common to create these situations
Still, when developing code, it's common to create these situations
temporarily and it can be annoying to have to edit them out before the
program will compile.
</p>
@ -1695,6 +1713,14 @@ func main() {
}
</pre>
<p>
Nowadays, most Go programmers use a tool,
<a href="http://godoc.org/code.google.com/p/go.tools/cmd/goimports">goimports</a>,
which automatically rewrites a Go source file to have the correct imports,
eliminating the unused imports issue in practice.
This program is easily connected to most editors to run automatically when a Go source file is written.
</p>
<h2 id="Performance">Performance</h2>
<h3 id="Why_does_Go_perform_badly_on_benchmark_x">

View file

@ -1,6 +1,6 @@
<!--{
"Title": "The Go Programming Language Specification",
"Subtitle": "Version of August 28, 2014",
"Subtitle": "Version of October 16, 2014",
"Path": "/ref/spec"
}-->
@ -577,7 +577,7 @@ Numeric constants represent values of arbitrary precision and do not overflow.
</p>
<p>
Constants may be <a href="#Types">typed</a> or untyped.
Constants may be <a href="#Types">typed</a> or <i>untyped</i>.
Literal constants, <code>true</code>, <code>false</code>, <code>iota</code>,
and certain <a href="#Constant_expressions">constant expressions</a>
containing only untyped constant operands are untyped.
@ -597,6 +597,17 @@ can be given the types <code>float32</code>, <code>float64</code>, or <code>uint
not <code>int32</code> or <code>string</code>.
</p>
<p>
An untyped constant has a <i>default type</i> which is the type to which the
constant is implicitly converted in contexts where a typed value is required,
for instance, in a <a href="#Short_variable_declarations">short variable declaration</a>
such as <code>i := 0</code> where there is no explicit type.
The default type of an untyped constant is <code>bool</code>, <code>rune</code>,
<code>int</code>, <code>float64</code>, <code>complex128</code> or <code>string</code>
respectively, depending on whether it is a boolean, rune, integer, floating-point,
complex, or string constant.
</p>
<p>
There are no constants denoting the IEEE-754 infinity and not-a-number values,
but the <a href="/pkg/math/"><code>math</code> package</a>'s
@ -636,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>
@ -661,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,
@ -1027,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>
@ -1154,11 +1213,11 @@ interface{}
<p>
Similarly, consider this interface specification,
which appears within a <a href="#Type_declarations">type declaration</a>
to define an interface called <code>Lock</code>:
to define an interface called <code>Locker</code>:
</p>
<pre>
type Lock interface {
type Locker interface {
Lock()
Unlock()
}
@ -1174,28 +1233,35 @@ func (p T) Unlock() { … }
</pre>
<p>
they implement the <code>Lock</code> interface as well
they implement the <code>Locker</code> interface as well
as the <code>File</code> interface.
</p>
<p>
An interface may use an interface type name <code>T</code>
in place of a method specification.
The effect, called embedding an interface,
is equivalent to enumerating the methods of <code>T</code> explicitly
in the interface.
An interface <code>T</code> may use a (possibly qualified) interface type
name <code>E</code> in place of a method specification. This is called
<i>embedding</i> interface <code>E</code> in <code>T</code>; it adds
all (exported and non-exported) methods of <code>E</code> to the interface
<code>T</code>.
</p>
<pre>
type ReadWrite interface {
type ReadWriter interface {
Read(b Buffer) bool
Write(b Buffer) bool
}
type File interface {
ReadWrite // same as enumerating the methods in ReadWrite
Lock // same as enumerating the methods in Lock
ReadWriter // same as adding the methods of ReadWriter
Locker // same as adding the methods of Locker
Close()
}
type LockedFile interface {
Locker
File // illegal: Lock, Unlock not unique
Lock() // illegal: Lock not unique
}
</pre>
<p>
@ -1443,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>
@ -1875,9 +1941,10 @@ func (tz TimeZone) String() string {
<h3 id="Variable_declarations">Variable declarations</h3>
<p>
A variable declaration creates a variable, binds an identifier to it and
gives it a type and optionally an initial value.
A variable declaration creates one or more variables, binds corresponding
identifiers to them, and gives each a type and an initial value.
</p>
<pre class="ebnf">
VarDecl = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) .
VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) .
@ -1898,22 +1965,27 @@ var _, found = entries[name] // map lookup; only interested in "found"
<p>
If a list of expressions is given, the variables are initialized
by <a href="#Assignments">assigning</a> the expressions to the variables
in order; all expressions must be consumed and all variables initialized from them.
with the expressions following the rules for <a href="#Assignments">assignments</a>.
Otherwise, each variable is initialized to its <a href="#The_zero_value">zero value</a>.
</p>
<p>
If the type is present, each variable is given that type.
Otherwise, the types are deduced from the assignment
of the expression list.
If a type is present, each variable is given that type.
Otherwise, each variable is given the type of the corresponding
initialization value in the assignment.
If that value is an untyped constant, it is first
<a href="#Conversions">converted</a> to its <a href="#Constants">default type</a>;
if it is an untyped boolean value, it is first converted to type <code>bool</code>.
The predeclared value <code>nil</code> cannot be used to initialize a variable
with no explicit type.
</p>
<p>
If the type is absent and the corresponding expression evaluates to an
untyped <a href="#Constants">constant</a>, the type of the declared variable
is as described in §<a href="#Assignments">Assignments</a>.
</p>
<pre>
var d = math.Sin(0.5) // d is int64
var i = 42 // i is int
var t, ok = x.(T) // t is T, ok is bool
var n = nil // illegal
</pre>
<p>
Implementation restriction: A compiler may make it illegal to declare a variable
@ -2242,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}
@ -3604,7 +3677,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>.
@ -4311,7 +4384,7 @@ a[i] = 23
<p>
An <i>assignment operation</i> <code>x</code> <i>op</i><code>=</code>
<code>y</code> where <i>op</i> is a binary arithmetic operation equivalent
<code>y</code> where <i>op</i> is a binary arithmetic operation is equivalent
to <code>x</code> <code>=</code> <code>x</code> <i>op</i>
<code>y</code> but evaluates <code>x</code>
only once. The <i>op</i><code>=</code> construct is a single token.
@ -4329,8 +4402,8 @@ i &amp;^= 1&lt;&lt;n
A tuple assignment assigns the individual elements of a multi-valued
operation to a list of variables. There are two forms. In the
first, the right hand operand is a single multi-valued expression
such as a function evaluation or <a href="#Channel_types">channel</a> or
<a href="#Map_types">map</a> operation or a <a href="#Type_assertions">type assertion</a>.
such as a function call, a <a href="#Channel_types">channel</a> or
<a href="#Map_types">map</a> operation, or a <a href="#Type_assertions">type assertion</a>.
The number of operands on the left
hand side must match the number of values. For instance, if
<code>f</code> is a function returning two values,
@ -4404,23 +4477,21 @@ to the type of the operand to which it is assigned, with the following special c
</p>
<ol>
<li><p>
If an untyped <a href="#Constants">constant</a>
is assigned to a variable of interface type or the blank identifier,
the constant is first <a href="#Conversions">converted</a> to type
<code>bool</code>, <code>rune</code>, <code>int</code>, <code>float64</code>,
<code>complex128</code> or <code>string</code> respectively, depending on
whether the value is a boolean, rune, integer, floating-point, complex, or
string constant.
</p></li>
<li>
Any typed value may be assigned to the blank identifier.
</li>
<li><p>
<!-- Note that the result of a comparison is an untyped bool that may not be constant. -->
If a left-hand side is the blank identifier, any typed or non-constant
value except for the predeclared identifier
<a href="#Predeclared_identifiers"><code>nil</code></a>
may be assigned to it.
</p></li>
<li>
If an untyped constant
is assigned to a variable of interface type or the blank identifier,
the constant is first <a href="#Conversions">converted</a> to its
<a href="#Constants">default type</a>.
</li>
<li>
If an untyped boolean value is assigned to a variable of interface type or
the blank identifier, it is first converted to type <code>bool</code>.
</li>
</ol>
<h3 id="If_statements">If statements</h3>
@ -4675,6 +4746,7 @@ additionally it may specify an <i>init</i>
and a <i>post</i> statement, such as an assignment,
an increment or decrement statement. The init statement may be a
<a href="#Short_variable_declarations">short variable declaration</a>, but the post statement must not.
Variables declared by the init statement are re-used in each iteration.
</p>
<pre class="ebnf">
@ -4801,7 +4873,7 @@ The iteration variables may be declared by the "range" clause using a form of
<a href="#Short_variable_declarations">short variable declaration</a>
(<code>:=</code>).
In this case their types are set to the types of the respective iteration values
and their <a href="#Declarations_and_scope">scope</a> ends at the end of the "for"
and their <a href="#Declarations_and_scope">scope</a> is the block of the "for"
statement; they are re-used in each iteration.
If the iteration variables are declared outside the "for" statement,
after execution their values will be those of the last iteration.
@ -5243,13 +5315,16 @@ Calls of built-in functions are restricted as for
</p>
<p>
Each time the "defer" statement
Each time a "defer" statement
executes, the function value and parameters to the call are
<a href="#Calls">evaluated as usual</a>
and saved anew but the actual function body is not executed.
Instead, deferred functions are executed immediately before
and saved anew but the actual function is not invoked.
Instead, deferred functions are invoked immediately before
the surrounding function returns, in the reverse order
they were deferred.
If a deferred function value evaluates
to <code>nil</code>, execution <a href="#Handling_panics">panics</a>
when the function is invoked, not when the "defer" statement is executed.
</p>
<p>
@ -5379,9 +5454,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>
@ -5399,10 +5476,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>
@ -5869,10 +5946,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.
@ -5916,20 +5995,42 @@ var t T
</pre>
<h3 id="Package_initialization">Package initialization</h3>
<p>
Within a package, package-level variables are initialized according
to their <i>dependencies</i>: if a variable <code>x</code> depends on
a variable <code>y</code>, <code>x</code> will be initialized after
<code>y</code>.
Within a package, package-level variables are initialized in
<i>declaration order</i> but after any of the variables
they <i>depend</i> on.
</p>
<p>
More precisely, a package-level variable is considered <i>ready for
initialization</i> if it is not yet initialized and either has
no <a href="#Variable_declarations">initialization expression</a> or
its initialization expression has no dependencies on uninitialized variables.
Initialization proceeds by repeatedly initializing the next package-level
variable that is earliest in declaration order and ready for initialization,
until there are no variables ready for initialization.
</p>
<p>
If any variables are still uninitialized when this
process ends, those variables are part of one or more initialization cycles,
and the program is not valid.
</p>
<p>
The declaration order of variables declared in multiple files is determined
by the order in which the files are presented to the compiler: Variables
declared in the first file are declared before any of the variables declared
in the second file, and so on.
</p>
<p>
Dependency analysis does not rely on the actual values of the
variables, only on lexical <i>references</i> to them in the source,
analyzed transitively. For instance, a variable <code>x</code>'s
<a href="#Variable_declarations">initialization expression</a>
may refer to a function whose body refers to variable <code>y</code>;
if so, <code>x</code> depends on <code>y</code>.
analyzed transitively. For instance, if a variable <code>x</code>'s
initialization expression refers to a function whose body refers to
variable <code>y</code> then <code>x</code> depends on <code>y</code>.
Specifically:
</p>
@ -5962,11 +6063,6 @@ or to a function or method that depends on <code>y</code>.
Dependency analysis is performed per package; only references referring
to variables, functions, and methods declared in the current package
are considered.
It is an error if variable dependencies form a cycle
(but dependency cycles containing no variables are permitted).
If two variables are independent of each other,
they are initialized in the order they are declared
in the source, possibly in multiple files, as presented to the compiler.
</p>
<p>
@ -5989,8 +6085,6 @@ func f() int {
<p>
the initialization order is <code>d</code>, <code>b</code>, <code>c</code>, <code>a</code>.
Since <code>b</code> and <code>c</code> are independent of each other, they are
initialized in declaration order (<code>b</code> before <code>c</code>).
</p>
<p>
@ -6033,6 +6127,12 @@ the <code>init</code> functions: it will not invoke the next one
until the previous one has returned.
</p>
<p>
To ensure reproducible initialization behavior, build systems are encouraged
to present multiple files belonging to the same package in lexical file name
order to a compiler.
</p>
<h3 id="Program_execution">Program execution</h3>
<p>

BIN
doc/gopher/biplane.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 KiB

View file

@ -6,14 +6,14 @@
<h2 id="download">Download the Go distribution</h2>
<p>
<a href="/dl/" id="start" class="download" target="_blank">
<a href="https://golang.org/dl/" id="start" class="download" target="_blank">
<span class="big">Download Go</span>
<span class="desc">Click here to visit the downloads page</span>
</a>
</p>
<p>
<a href="https://code.google.com/p/go/wiki/Downloads?tm=2" target="_blank">Official binary
<a href="https://golang.org/dl/" target="_blank">Official binary
distributions</a> are available for the FreeBSD (release 8 and above), Linux, Mac OS X (Snow Leopard
and above), and Windows operating systems and the 32-bit (<code>386</code>) and
64-bit (<code>amd64</code>) x86 processor architectures.
@ -70,7 +70,7 @@ first <a href="#uninstall">remove the existing version</a>.
<h3 id="tarball">Linux, Mac OS X, and FreeBSD tarballs</h3>
<p>
<a href="https://code.google.com/p/go/wiki/Downloads?tm=2">Download the archive</a>
<a href="https://golang.org/dl/">Download the archive</a>
and extract it into <code>/usr/local</code>, creating a Go tree in
<code>/usr/local/go</code>. For example:
</p>
@ -127,7 +127,7 @@ location.
<h3 id="osx">Mac OS X package installer</h3>
<p>
<a href="https://code.google.com/p/go/wiki/Downloads?tm=2">Download the package file</a>,
<a href="https://golang.org/dl/">Download the package file</a>,
open it, and follow the prompts to install the Go tools.
The package installs the Go distribution to <code>/usr/local/go</code>.
</p>
@ -150,7 +150,7 @@ MSI installer that configures your installation automatically.
<h4 id="windows_msi">MSI installer</h4>
<p>
Open the <a href="https://code.google.com/p/go/wiki/Downloads?tm=2">MSI file</a>
Open the <a href="https://golang.org/dl/">MSI file</a>
and follow the prompts to install the Go tools.
By default, the installer puts the Go distribution in <code>c:\Go</code>.
</p>
@ -164,7 +164,7 @@ command prompts for the change to take effect.
<h4 id="windows_zip">Zip archive</h4>
<p>
<a href="https://code.google.com/p/go/wiki/Downloads?tm=2">Download the zip file</a> and extract it into the directory of your choice (we suggest <code>c:\Go</code>).
<a href="https://golang.org/dl/">Download the zip file</a> and extract it into the directory of your choice (we suggest <code>c:\Go</code>).
</p>
<p>
@ -224,19 +224,12 @@ If you see the "hello, world" message then your Go installation is working.
<p>
You're almost done.
You just need to do a little more setup.
You just need to set up your environment.
</p>
<p>
<a href="/doc/code.html" class="download" id="writing">
<span class="big">How to Write Go Code</span>
<span class="desc">Learn how to set up and use the Go tools</span>
</a>
</p>
<p>
The <a href="/doc/code.html">How to Write Go Code</a> document
provides <b>essential setup instructions</b> for using the Go tools.
Read the <a href="/doc/code.html">How to Write Go Code</a> document,
which provides <b>essential setup instructions</b> for using the Go tools.
</p>
@ -277,5 +270,3 @@ The official mailing list for discussion of the Go language is
Report bugs using the
<a href="//golang.org/issue">Go issue tracker</a>.
</p>

View file

@ -205,10 +205,10 @@ enum
SELFSECT,
SMACHO, /* Mach-O __nl_symbol_ptr */
SMACHOGOT,
SWINDOWS,
SNOPTRDATA,
SINITARR,
SDATA,
SWINDOWS,
SBSS,
SNOPTRBSS,
STLSBSS,
@ -376,6 +376,7 @@ struct Link
char* trimpath;
char* goroot;
char* goroot_final;
int32 enforce_data_order; // for use by assembler
// hash table of all symbols
LSym* hash[LINKHASH];
@ -395,7 +396,7 @@ struct Link
LSym* sym_divu;
LSym* sym_mod;
LSym* sym_modu;
LSym* symmorestack[20];
LSym* symmorestack[2];
LSym* tlsg;
LSym* plan9privates;
Prog* curp;
@ -474,6 +475,7 @@ struct LinkArch
int D_PARAM;
int D_SCONST;
int D_STATIC;
int D_OREG;
int ACALL;
int ADATA;
@ -547,6 +549,7 @@ vlong adduint8(Link *ctxt, LSym *s, uint8 v);
vlong adduintxx(Link *ctxt, LSym *s, uint64 v, int wid);
void mangle(char *file);
void savedata(Link *ctxt, LSym *s, Prog *p, char *pn);
void savedata1(Link *ctxt, LSym *s, Prog *p, char *pn, int enforce_order);
vlong setaddr(Link *ctxt, LSym *s, vlong off, LSym *t);
vlong setaddrplus(Link *ctxt, LSym *s, vlong off, LSym *t, vlong add);
vlong setuint16(Link *ctxt, LSym *s, vlong r, uint16 v);

View file

@ -4,5 +4,4 @@
package backdoor
func LockedOSThread() bool // in runtime.c
func Issue7695(x1, x2, x3, x4, x5, x6, x7, x8 uintptr)
func LockedOSThread() bool // in thunk.s

View file

@ -1,18 +0,0 @@
// Copyright 2011 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.
// Expose some runtime functions for testing.
// Must be in a non-cgo-using package so that
// the go command compiles this file with 6c, not gcc.
// +build gc
typedef char bool;
// This is what a cgo-compiled stub declaration looks like.
void
·Issue7695(struct{void *y[8*sizeof(void*)];}p)
{
USED(p);
}

View file

@ -157,3 +157,8 @@ func testUnsignedInt(t *testing.T) {
t.Errorf("Incorrect unsigned int - got %x, want %x", a, b)
}
}
// Static (build-time) test that syntax traversal visits all operands of s[i:j:k].
func sliceOperands(array [2000]int) {
_ = array[C.KILO:C.KILO:C.KILO] // no type error
}

View file

@ -9,6 +9,10 @@ void callback(void *f);
void callGoFoo(void);
void callGoStackCheck(void);
void callPanic(void);
void callCgoAllocate(void);
int callGoReturnVal(void);
int returnAfterGrow(void);
int returnAfterGrowFromGo(void);
*/
import "C"
@ -207,6 +211,52 @@ func testPanicFromC(t *testing.T) {
C.callPanic()
}
func testAllocateFromC(t *testing.T) {
C.callCgoAllocate() // crashes or exits on failure
}
// Test that C code can return a value if it calls a Go function that
// causes a stack copy.
func testReturnAfterGrow(t *testing.T) {
// Use a new goroutine so that we get a small stack.
c := make(chan int)
go func() {
c <- int(C.returnAfterGrow())
}()
if got, want := <-c, 123456; got != want {
t.Errorf("got %d want %d", got, want)
}
}
// Test that we can return a value from Go->C->Go if the Go code
// causes a stack copy.
func testReturnAfterGrowFromGo(t *testing.T) {
// Use a new goroutine so that we get a small stack.
c := make(chan int)
go func() {
c <- int(C.returnAfterGrowFromGo())
}()
if got, want := <-c, 129*128/2; got != want {
t.Errorf("got %d want %d", got, want)
}
}
//export goReturnVal
func goReturnVal() (r C.int) {
// Force a stack copy.
var f func(int) int
f = func(i int) int {
var buf [256]byte
use(buf[:])
if i == 0 {
return 0
}
return i + f(i-1)
}
r = C.int(f(128))
return
}
func testCallbackStack(t *testing.T) {
// Make cgo call and callback with different amount of stack stack available.
// We do not do any explicit checks, just ensure that it does not crash.

View file

@ -64,3 +64,19 @@ callGoStackCheck(void)
extern void goStackCheck(void);
goStackCheck();
}
int
returnAfterGrow(void)
{
extern int goReturnVal(void);
goReturnVal();
return 123456;
}
int
returnAfterGrowFromGo(void)
{
extern int goReturnVal(void);
return goReturnVal();
}

View file

@ -5,11 +5,15 @@
// +build gc
#include "_cgo_export.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
/* Test calling panic from C. This is what SWIG does. */
extern void crosscall2(void (*fn)(void *, int), void *, int);
extern void _cgo_panic(void *, int);
extern void _cgo_allocate(void *, int);
void
callPanic(void)
@ -19,3 +23,58 @@ callPanic(void)
crosscall2(_cgo_panic, &a, sizeof a);
*(int*)1 = 1;
}
/* Test calling cgo_allocate from C. This is what SWIG does. */
typedef struct List List;
struct List
{
List *next;
int x;
};
void
callCgoAllocate(void)
{
int i;
struct { size_t n; void *ret; } a;
List *l, *head, **tail;
// Make sure this doesn't crash.
// And make sure it returns non-nil.
a.n = 0;
a.ret = 0;
crosscall2(_cgo_allocate, &a, sizeof a);
if(a.ret == 0) {
fprintf(stderr, "callCgoAllocate: alloc 0 returned nil\n");
exit(2);
}
head = 0;
tail = &head;
for(i=0; i<100; i++) {
a.n = sizeof *l;
crosscall2(_cgo_allocate, &a, sizeof a);
l = a.ret;
l->x = i;
l->next = 0;
*tail = l;
tail = &l->next;
}
gc();
l = head;
for(i=0; i<100; i++) {
if(l->x != i) {
fprintf(stderr, "callCgoAllocate: lost memory\n");
exit(2);
}
l = l->next;
}
if(l != 0) {
fprintf(stderr, "callCgoAllocate: lost memory\n");
exit(2);
}
}

View file

@ -5,13 +5,66 @@
// +build gccgo
#include "_cgo_export.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
/* Test calling panic from C. This is what SWIG does. */
extern void _cgo_panic(const char *);
extern void *_cgo_allocate(size_t);
void
callPanic(void)
{
_cgo_panic("panic from C");
}
/* Test calling cgo_allocate from C. This is what SWIG does. */
typedef struct List List;
struct List
{
List *next;
int x;
};
void
callCgoAllocate(void)
{
int i;
List *l, *head, **tail;
// Make sure this doesn't crash.
// And make sure it returns non-nil.
if(_cgo_allocate(0) == 0) {
fprintf(stderr, "callCgoAllocate: alloc 0 returned nil\n");
exit(2);
}
head = 0;
tail = &head;
for(i=0; i<100; i++) {
l = _cgo_allocate(sizeof *l);
l->x = i;
l->next = 0;
*tail = l;
tail = &l->next;
}
gc();
l = head;
for(i=0; i<100; i++) {
if(l->x != i) {
fprintf(stderr, "callCgoAllocate: lost memory\n");
exit(2);
}
l = l->next;
}
if(l != 0) {
fprintf(stderr, "callCgoAllocate: lost memory\n");
exit(2);
}
}

View file

@ -10,50 +10,57 @@ import "testing"
// so that they can use cgo (import "C").
// These wrappers are here for gotest to find.
func TestAlign(t *testing.T) { testAlign(t) }
func TestConst(t *testing.T) { testConst(t) }
func TestEnum(t *testing.T) { testEnum(t) }
func TestAtol(t *testing.T) { testAtol(t) }
func TestErrno(t *testing.T) { testErrno(t) }
func TestMultipleAssign(t *testing.T) { testMultipleAssign(t) }
func TestUnsignedInt(t *testing.T) { testUnsignedInt(t) }
func TestCallback(t *testing.T) { testCallback(t) }
func TestCallbackGC(t *testing.T) { testCallbackGC(t) }
func TestCallbackPanic(t *testing.T) { testCallbackPanic(t) }
func TestCallbackPanicLoop(t *testing.T) { testCallbackPanicLoop(t) }
func TestCallbackPanicLocked(t *testing.T) { testCallbackPanicLocked(t) }
func TestPanicFromC(t *testing.T) { testPanicFromC(t) }
func TestZeroArgCallback(t *testing.T) { testZeroArgCallback(t) }
func TestBlocking(t *testing.T) { testBlocking(t) }
func Test1328(t *testing.T) { test1328(t) }
func TestParallelSleep(t *testing.T) { testParallelSleep(t) }
func TestSetEnv(t *testing.T) { testSetEnv(t) }
func TestHelpers(t *testing.T) { testHelpers(t) }
func TestLibgcc(t *testing.T) { testLibgcc(t) }
func Test1635(t *testing.T) { test1635(t) }
func TestPrintf(t *testing.T) { testPrintf(t) }
func Test4029(t *testing.T) { test4029(t) }
func TestBoolAlign(t *testing.T) { testBoolAlign(t) }
func Test3729(t *testing.T) { test3729(t) }
func Test3775(t *testing.T) { test3775(t) }
func TestCthread(t *testing.T) { testCthread(t) }
func TestCallbackCallers(t *testing.T) { testCallbackCallers(t) }
func Test5227(t *testing.T) { test5227(t) }
func TestCflags(t *testing.T) { testCflags(t) }
func Test5337(t *testing.T) { test5337(t) }
func Test5548(t *testing.T) { test5548(t) }
func Test5603(t *testing.T) { test5603(t) }
func Test6833(t *testing.T) { test6833(t) }
func Test3250(t *testing.T) { test3250(t) }
func TestCallbackStack(t *testing.T) { testCallbackStack(t) }
func TestFpVar(t *testing.T) { testFpVar(t) }
func Test4339(t *testing.T) { test4339(t) }
func Test6390(t *testing.T) { test6390(t) }
func Test5986(t *testing.T) { test5986(t) }
func Test7665(t *testing.T) { test7665(t) }
func TestNaming(t *testing.T) { testNaming(t) }
func Test7560(t *testing.T) { test7560(t) }
func Test5242(t *testing.T) { test5242(t) }
func Test8092(t *testing.T) { test8092(t) }
func TestAlign(t *testing.T) { testAlign(t) }
func TestConst(t *testing.T) { testConst(t) }
func TestEnum(t *testing.T) { testEnum(t) }
func TestAtol(t *testing.T) { testAtol(t) }
func TestErrno(t *testing.T) { testErrno(t) }
func TestMultipleAssign(t *testing.T) { testMultipleAssign(t) }
func TestUnsignedInt(t *testing.T) { testUnsignedInt(t) }
func TestCallback(t *testing.T) { testCallback(t) }
func TestCallbackGC(t *testing.T) { testCallbackGC(t) }
func TestCallbackPanic(t *testing.T) { testCallbackPanic(t) }
func TestCallbackPanicLoop(t *testing.T) { testCallbackPanicLoop(t) }
func TestCallbackPanicLocked(t *testing.T) { testCallbackPanicLocked(t) }
func TestPanicFromC(t *testing.T) { testPanicFromC(t) }
func TestAllocateFromC(t *testing.T) { testAllocateFromC(t) }
func TestZeroArgCallback(t *testing.T) { testZeroArgCallback(t) }
func TestBlocking(t *testing.T) { testBlocking(t) }
func Test1328(t *testing.T) { test1328(t) }
func TestParallelSleep(t *testing.T) { testParallelSleep(t) }
func TestSetEnv(t *testing.T) { testSetEnv(t) }
func TestHelpers(t *testing.T) { testHelpers(t) }
func TestLibgcc(t *testing.T) { testLibgcc(t) }
func Test1635(t *testing.T) { test1635(t) }
func TestPrintf(t *testing.T) { testPrintf(t) }
func Test4029(t *testing.T) { test4029(t) }
func TestBoolAlign(t *testing.T) { testBoolAlign(t) }
func Test3729(t *testing.T) { test3729(t) }
func Test3775(t *testing.T) { test3775(t) }
func TestCthread(t *testing.T) { testCthread(t) }
func TestCallbackCallers(t *testing.T) { testCallbackCallers(t) }
func Test5227(t *testing.T) { test5227(t) }
func TestCflags(t *testing.T) { testCflags(t) }
func Test5337(t *testing.T) { test5337(t) }
func Test5548(t *testing.T) { test5548(t) }
func Test5603(t *testing.T) { test5603(t) }
func Test6833(t *testing.T) { test6833(t) }
func Test3250(t *testing.T) { test3250(t) }
func TestCallbackStack(t *testing.T) { testCallbackStack(t) }
func TestFpVar(t *testing.T) { testFpVar(t) }
func Test4339(t *testing.T) { test4339(t) }
func Test6390(t *testing.T) { test6390(t) }
func Test5986(t *testing.T) { test5986(t) }
func Test7665(t *testing.T) { test7665(t) }
func TestNaming(t *testing.T) { testNaming(t) }
func Test7560(t *testing.T) { test7560(t) }
func Test5242(t *testing.T) { test5242(t) }
func Test8092(t *testing.T) { test8092(t) }
func Test7978(t *testing.T) { test7978(t) }
func Test8694(t *testing.T) { test8694(t) }
func Test8517(t *testing.T) { test8517(t) }
func Test8811(t *testing.T) { test8811(t) }
func TestReturnAfterGrow(t *testing.T) { testReturnAfterGrow(t) }
func TestReturnAfterGrowFromGo(t *testing.T) { testReturnAfterGrowFromGo(t) }
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }

View file

@ -5,8 +5,14 @@
package cgotest
import "C"
import "runtime"
//export ReturnIntLong
func ReturnIntLong() (int, C.long) {
return 1, 2
}
//export gc
func gc() {
runtime.GC()
}

View file

@ -1,30 +0,0 @@
// 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.
// +build ignore
// This test depends on running C code on Go stacks. Not allowed anymore.
// Demo of deferred C function with untrue prototype
// breaking stack copying. See golang.org/issue/7695.
package cgotest
import (
"testing"
"./backdoor"
)
func TestIssue7695(t *testing.T) {
defer backdoor.Issue7695(1, 0, 2, 0, 0, 3, 0, 4)
recurse(100)
}
func recurse(n int) {
var x [128]int
n += x[0]
if n > 0 {
recurse(n - 1)
}
}

103
misc/cgo/test/issue7978.go Normal file
View file

@ -0,0 +1,103 @@
// 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 7978. Stack tracing didn't work during cgo code after calling a Go
// callback. Make sure GC works and the stack trace is correct.
package cgotest
/*
#include <stdint.h>
void issue7978cb(void);
// use ugly atomic variable sync since that doesn't require calling back into
// Go code or OS dependencies
static void issue7978c(uint32_t *sync) {
while(__sync_fetch_and_add(sync, 0) != 0)
;
__sync_fetch_and_add(sync, 1);
while(__sync_fetch_and_add(sync, 0) != 2)
;
issue7978cb();
__sync_fetch_and_add(sync, 1);
while(__sync_fetch_and_add(sync, 0) != 6)
;
}
*/
import "C"
import (
"os"
"runtime"
"strings"
"sync/atomic"
"testing"
)
var issue7978sync uint32
func issue7978check(t *testing.T, wantFunc string, badFunc string, depth int) {
runtime.GC()
buf := make([]byte, 65536)
trace := string(buf[:runtime.Stack(buf, true)])
for _, goroutine := range strings.Split(trace, "\n\n") {
if strings.Contains(goroutine, "test.issue7978go") {
trace := strings.Split(goroutine, "\n")
// look for the expected function in the stack
for i := 0; i < depth; i++ {
if badFunc != "" && strings.Contains(trace[1+2*i], badFunc) {
t.Errorf("bad stack: found %s in the stack:\n%s", badFunc, goroutine)
return
}
if strings.Contains(trace[1+2*i], wantFunc) {
return
}
}
t.Errorf("bad stack: didn't find %s in the stack:\n%s", wantFunc, goroutine)
return
}
}
t.Errorf("bad stack: goroutine not found. Full stack dump:\n%s", trace)
}
func issue7978wait(store uint32, wait uint32) {
if store != 0 {
atomic.StoreUint32(&issue7978sync, store)
}
for atomic.LoadUint32(&issue7978sync) != wait {
runtime.Gosched()
}
}
//export issue7978cb
func issue7978cb() {
issue7978wait(3, 4)
}
func issue7978go() {
C.issue7978c((*C.uint32_t)(&issue7978sync))
issue7978wait(7, 8)
}
func test7978(t *testing.T) {
if os.Getenv("GOTRACEBACK") != "2" {
t.Fatalf("GOTRACEBACK must be 2")
}
issue7978sync = 0
go issue7978go()
// test in c code, before callback
issue7978wait(0, 1)
issue7978check(t, "runtime.cgocall_errno(", "", 1)
// test in go code, during callback
issue7978wait(2, 3)
issue7978check(t, "test.issue7978cb(", "test.issue7978go", 3)
// test in c code, after callback
issue7978wait(4, 5)
issue7978check(t, "runtime.cgocall_errno(", "runtime.cgocallback", 1)
// test in go code, after return from cgo
issue7978wait(6, 7)
issue7978check(t, "test.issue7978go(", "", 3)
atomic.StoreUint32(&issue7978sync, 8)
}

View file

@ -0,0 +1,13 @@
// 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.
// +build !windows
package cgotest
import "testing"
func test8517(t *testing.T) {
t.Skip("skipping windows only test")
}

View file

@ -0,0 +1,24 @@
// 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.
#include "windows.h"
extern void testHandleLeaksCallback();
DWORD WINAPI testHandleLeaksFunc(LPVOID lpThreadParameter)
{
int i;
for(i = 0; i < 100; i++) {
testHandleLeaksCallback();
}
return 0;
}
void testHandleLeaks()
{
HANDLE h;
h = CreateThread(NULL, 0, &testHandleLeaksFunc, 0, 0, NULL);
WaitForSingleObject(h, INFINITE);
CloseHandle(h);
}

View file

@ -0,0 +1,45 @@
// 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 cgotest
//void testHandleLeaks();
import "C"
import (
"syscall"
"testing"
"unsafe"
)
var issue8517counter int
var (
kernel32 = syscall.MustLoadDLL("kernel32.dll")
getProcessHandleCount = kernel32.MustFindProc("GetProcessHandleCount")
)
func processHandleCount(t *testing.T) int {
const current_process = ^uintptr(0)
var c uint32
r, _, err := getProcessHandleCount.Call(current_process, uintptr(unsafe.Pointer(&c)))
if r == 0 {
t.Fatal(err)
}
return int(c)
}
func test8517(t *testing.T) {
c1 := processHandleCount(t)
C.testHandleLeaks()
c2 := processHandleCount(t)
if c1+issue8517counter <= c2 {
t.Fatalf("too many handles leaked: issue8517counter=%v c1=%v c2=%v", issue8517counter, c1, c2)
}
}
//export testHandleLeaksCallback
func testHandleLeaksCallback() {
issue8517counter++
}

View file

@ -0,0 +1,32 @@
// 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 cgotest
/*
#include <complex.h>
complex float complexFloatSquared(complex float a) { return a*a; }
complex double complexDoubleSquared(complex double a) { return a*a; }
*/
import "C"
import "testing"
func test8694(t *testing.T) {
// Really just testing that this compiles, but check answer anyway.
x := complex64(2 + 3i)
x2 := x * x
cx2 := C.complexFloatSquared(x)
if cx2 != x2 {
t.Errorf("C.complexFloatSquared(%v) = %v, want %v", x, cx2, x2)
}
y := complex128(2 + 3i)
y2 := y * y
cy2 := C.complexDoubleSquared(y)
if cy2 != y2 {
t.Errorf("C.complexDoubleSquared(%v) = %v, want %v", y, cy2, y2)
}
}

View file

@ -2,10 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This is the gccgo version of the stub in runtime.c.
int issue8811Initialized = 0;
// +build gccgo
package backdoor
func Issue7695(x1, x2, x3, x4, x5, x6, x7, x8 uintptr) {}
void issue8811Init() {
}

View file

@ -0,0 +1,22 @@
// 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 cgotest
/*
extern int issue8811Initialized;
extern void issue8811Init();
void issue8811Execute() {
if(!issue8811Initialized)
issue8811Init();
}
*/
import "C"
import "testing"
func test8811(t *testing.T) {
C.issue8811Execute()
}

View file

@ -0,0 +1,16 @@
// compile
// 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 8828: compiling a file with -compiler=gccgo fails if a .c file
// has the same name as compiled directory.
package cgotest
import "./issue8828"
func p() {
issue8828.Bar()
}

View file

@ -0,0 +1,7 @@
// 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.
void foo()
{
}

View file

@ -0,0 +1,8 @@
package issue8828
//void foo();
import "C"
func Bar() {
C.foo()
}

View 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.

View file

@ -18,13 +18,12 @@
<Product
Id="FF5B30B2-08C2-11E1-85A2-6ACA4824019B"
Name="Go Programming Language $(var.Arch) $(var.Version)"
Name="Go Programming Language $(var.Arch) $(var.GoVersion)"
Language="1033"
Codepage="1252"
Version="0.0.0.0"
Version="$(var.WixGoVersion)"
Manufacturer="http://golang.org"
UpgradeCode="$(var.UpgradeCode)" >
<!-- Version="$(var.Version)" TODO: Version requires X.X.X.X format -->
<Package
Id='*'

View file

@ -59,9 +59,9 @@ Support scripts
Symlink the two scripts in this directory into your $PATH, just as you did with
NaCl sdk above.
% ln -nfs $GOROOT/go/misc/nacl/go_nacl_amd64p32_exec $GOPATH/bin/go_nacl_amd64p32_exec
% ln -nfs $GOROOT/go/misc/nacl/go_nacl_386_exec $GOPATH/bin/go_nacl_386_exec
% ln -nfs $GOROOT/go/misc/nacl/go_nacl_arm_exec $GOPATH/bin/go_nacl_arm_exec
% ln -nfs $GOROOT/misc/nacl/go_nacl_amd64p32_exec $GOPATH/bin/go_nacl_amd64p32_exec
% ln -nfs $GOROOT/misc/nacl/go_nacl_386_exec $GOPATH/bin/go_nacl_386_exec
% ln -nfs $GOROOT/misc/nacl/go_nacl_arm_exec $GOPATH/bin/go_nacl_arm_exec
Building and testing
--------------------

View file

@ -42,7 +42,7 @@ GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH go build \
# into a subdirectory of /data.
export ANDROID_PRODUCT_OUT=/tmp/androidtest-$$
FAKE_GOROOT=$ANDROID_PRODUCT_OUT/data/local/tmp/goroot
mkdir -p $FAKE_GOROOT/src
mkdir -p $FAKE_GOROOT
ln -s $GOROOT/src $FAKE_GOROOT/src
ln -s $GOROOT/test $FAKE_GOROOT/test
ln -s $GOROOT/lib $FAKE_GOROOT/lib

View file

@ -112,7 +112,9 @@ func (s *Scanner) Scan() bool {
// Loop until we have a token.
for {
// See if we can get a token with what we already have.
if s.end > s.start {
// If we've run out of data but have an error, give the split function
// a chance to recover any remaining, possibly empty token.
if s.end > s.start || s.err != nil {
advance, token, err := s.split(s.buf[s.start:s.end], s.err != nil)
if err != nil {
s.setErr(err)

View file

@ -419,3 +419,39 @@ func TestScanWordsExcessiveWhiteSpace(t *testing.T) {
t.Fatalf("unexpected token: %v", token)
}
}
// Test that empty tokens, including at end of line or end of file, are found by the scanner.
// Issue 8672: Could miss final empty token.
func commaSplit(data []byte, atEOF bool) (advance int, token []byte, err error) {
for i := 0; i < len(data); i++ {
if data[i] == ',' {
return i + 1, data[:i], nil
}
}
if !atEOF {
return 0, nil, nil
}
return 0, data, nil
}
func TestEmptyTokens(t *testing.T) {
s := NewScanner(strings.NewReader("1,2,3,"))
values := []string{"1", "2", "3", ""}
s.Split(commaSplit)
var i int
for i = 0; i < len(values); i++ {
if !s.Scan() {
break
}
if s.Text() != values[i] {
t.Errorf("%d: expected %q got %q", i, values[i], s.Text())
}
}
if i != len(values) {
t.Errorf("got %d fields, expected %d", i, len(values))
}
if err := s.Err(); err != nil {
t.Fatal(err)
}
}

View file

@ -267,6 +267,8 @@ func Fields(s []byte) [][]byte {
// It splits the slice s at each run of code points c satisfying f(c) and
// returns a slice of subslices of s. If all code points in s satisfy f(c), or
// len(s) == 0, an empty slice is returned.
// FieldsFunc makes no guarantees about the order in which it calls f(c).
// If f does not return consistent results for a given c, FieldsFunc may crash.
func FieldsFunc(s []byte, f func(rune) bool) [][]byte {
n := 0
inField := false

View file

@ -1,5 +0,0 @@
// Copyright 2013 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.
// This file is here just to make the go tool happy.

View file

@ -85,6 +85,7 @@ main(int argc, char *argv[])
ctxt = linknew(&linkarm);
ctxt->diag = yyerror;
ctxt->bso = &bstdout;
ctxt->enforce_data_order = 1;
Binit(&bstdout, 1, OWRITE);
listinit5();
fmtinstall('L', Lconv);

View file

@ -366,14 +366,12 @@ _cgen(Node *n, Node *nn, int inrel)
if(REGARG >= 0)
o = reg[REGARG];
gargs(r, &nod, &nod1);
gpcdata(PCDATA_ArgSize, curarg);
if(l->addable < INDEXED) {
reglcgen(&nod, l, Z);
gopcode(OFUNC, Z, Z, &nod);
regfree(&nod);
} else
gopcode(OFUNC, Z, Z, l);
gpcdata(PCDATA_ArgSize, -1);
if(REGARG >= 0)
if(o != reg[REGARG])
reg[REGARG]--;

View file

@ -406,7 +406,7 @@ loop2:
rgp->cost = change;
nregion++;
if(nregion >= NRGN) {
warn(Z, "too many regions");
fatal(Z, "too many regions");
goto brk;
}
rgp++;
@ -642,11 +642,8 @@ mkvar(Addr *a, int docon)
if(s)
if(s->name[0] == '.')
goto none;
if(nvar >= NVAR) {
if(debug['w'] > 1 && s)
warn(Z, "variable not optimized: %s", s->name);
goto none;
}
if(nvar >= NVAR)
fatal(Z, "variable not optimized: %s", s->name);
i = nvar;
nvar++;
v = &var[i];

View file

@ -109,7 +109,6 @@ void split64(Node*, Node*, Node*);
void splitclean(void);
Node* ncon(uint32 i);
void gtrack(Sym*);
void gargsize(int32);
/*
* obj.c

View file

@ -179,28 +179,12 @@ fixautoused(Prog* p)
void
ginscall(Node *f, int proc)
{
int32 arg;
Prog *p;
Node n1, r, r1, con;
if(f->type != T)
setmaxarg(f->type);
arg = -1;
// Most functions have a fixed-size argument block, so traceback uses that during unwind.
// Not all, though: there are some variadic functions in package runtime,
// and for those we emit call-specific metadata recorded by caller.
// Reflect generates functions with variable argsize (see reflect.methodValueCall/makeFuncStub),
// so we do this for all indirect calls as well.
if(f->type != T && (f->sym == S || (f->sym != S && f->sym->pkg == runtimepkg) || proc == 1 || proc == 2)) {
arg = f->type->argwid;
if(proc == 1 || proc == 2)
arg += 3*widthptr;
}
if(arg != -1)
gargsize(arg);
switch(proc) {
default:
fatal("ginscall: bad proc %d", proc);
@ -297,9 +281,6 @@ ginscall(Node *f, int proc)
}
break;
}
if(arg != -1)
gargsize(-1);
}
/*

View file

@ -205,16 +205,6 @@ ggloblnod(Node *nam)
p->reg |= NOPTR;
}
void
gargsize(int32 size)
{
Node n1, n2;
nodconst(&n1, types[TINT32], PCDATA_ArgSize);
nodconst(&n2, types[TINT32], size);
gins(APCDATA, &n1, &n2);
}
void
ggloblsym(Sym *s, int32 width, int8 flags)
{
@ -371,7 +361,7 @@ regalloc(Node *n, Type *t, Node *o)
print("registers allocated at\n");
for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++)
print("%d %p\n", i, regpc[i]);
yyerror("out of fixed registers");
fatal("out of fixed registers");
goto err;
case TFLOAT32:
@ -384,7 +374,7 @@ regalloc(Node *n, Type *t, Node *o)
for(i=REGALLOC_F0; i<=REGALLOC_FMAX; i++)
if(reg[i] == 0)
goto out;
yyerror("out of floating point registers");
fatal("out of floating point registers");
goto err;
case TCOMPLEX64:

View file

@ -101,6 +101,7 @@ main(int argc, char *argv[])
ctxt = linknew(thelinkarch);
ctxt->diag = yyerror;
ctxt->bso = &bstdout;
ctxt->enforce_data_order = 1;
Binit(&bstdout, 1, OWRITE);
listinit6();
fmtinstall('L', Lconv);

View file

@ -945,7 +945,6 @@ cgen(Node *n, Node *nn)
return;
}
gargs(r, &nod, &nod1);
gpcdata(PCDATA_ArgSize, curarg);
if(l->addable < INDEXED) {
reglcgen(&nod, l, nn);
nod.op = OREGISTER;
@ -953,12 +952,9 @@ cgen(Node *n, Node *nn)
regfree(&nod);
} else
gopcode(OFUNC, n->type, Z, l);
gpcdata(PCDATA_ArgSize, -1);
if(REGARG >= 0 && reg[REGARG])
reg[REGARG]--;
regret(&nod, n, l->type, 1); // update maxarg if nothing else
gpcdata(PCDATA_ArgSize, curarg);
gpcdata(PCDATA_ArgSize, -1);
if(nn != Z)
gmove(&nod, nn);
if(nod.op == OREGISTER)

View file

@ -585,14 +585,11 @@ loop2:
}
rgp->cost = change;
nregion++;
if(nregion >= NRGN) {
warn(Z, "too many regions");
goto brk;
}
if(nregion >= NRGN)
fatal(Z, "too many regions");
rgp++;
}
}
brk:
qsort(region, nregion, sizeof(region[0]), rcmp);
/*
@ -808,11 +805,8 @@ mkvar(Reg *r, Addr *a)
goto out;
v++;
}
if(nvar >= NVAR) {
if(debug['w'] > 1 && s)
warn(Z, "variable not optimized: %s", s->name);
goto none;
}
if(nvar >= NVAR)
fatal(Z, "variable not optimized: %s", s->name);
i = nvar;
nvar++;
v = &var[i];

View file

@ -99,7 +99,6 @@ int sudoaddable(int, Node*, Addr*);
void afunclit(Addr*, Node*);
void nodfconst(Node*, Type*, Mpflt*);
void gtrack(Sym*);
void gargsize(vlong);
void fixlargeoffset(Node *n);
/*

View file

@ -175,7 +175,6 @@ fixautoused(Prog *p)
void
ginscall(Node *f, int proc)
{
int32 arg;
Prog *p;
Node reg, con;
Node r1;
@ -183,21 +182,6 @@ ginscall(Node *f, int proc)
if(f->type != T)
setmaxarg(f->type);
arg = -1;
// Most functions have a fixed-size argument block, so traceback uses that during unwind.
// Not all, though: there are some variadic functions in package runtime,
// and for those we emit call-specific metadata recorded by caller.
// Reflect generates functions with variable argsize (see reflect.methodValueCall/makeFuncStub),
// so we do this for all indirect calls as well.
if(f->type != T && (f->sym == S || (f->sym != S && f->sym->pkg == runtimepkg) || proc == 1 || proc == 2)) {
arg = f->type->argwid;
if(proc == 1 || proc == 2)
arg += 2*widthptr;
}
if(arg != -1)
gargsize(arg);
switch(proc) {
default:
fatal("ginscall: bad proc %d", proc);
@ -275,9 +259,6 @@ ginscall(Node *f, int proc)
}
break;
}
if(arg != -1)
gargsize(-1);
}
/*
@ -1121,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;

View file

@ -214,16 +214,6 @@ gtrack(Sym *s)
p->from.sym = linksym(s);
}
void
gargsize(vlong size)
{
Node n1, n2;
nodconst(&n1, types[TINT32], PCDATA_ArgSize);
nodconst(&n2, types[TINT32], size);
gins(APCDATA, &n1, &n2);
}
void
ggloblsym(Sym *s, int32 width, int8 flags)
{

View file

@ -90,6 +90,7 @@ main(int argc, char *argv[])
ctxt = linknew(&link386);
ctxt->diag = yyerror;
ctxt->bso = &bstdout;
ctxt->enforce_data_order = 1;
Binit(&bstdout, 1, OWRITE);
listinit8();
fmtinstall('L', Lconv);

View file

@ -938,7 +938,6 @@ cgen(Node *n, Node *nn)
return;
}
gargs(r, &nod, &nod1);
gpcdata(PCDATA_ArgSize, curarg);
if(l->addable < INDEXED) {
reglcgen(&nod, l, nn);
nod.op = OREGISTER;
@ -946,7 +945,6 @@ cgen(Node *n, Node *nn)
regfree(&nod);
} else
gopcode(OFUNC, n->type, Z, l);
gpcdata(PCDATA_ArgSize, -1);
if(REGARG >= 0 && reg[REGARG])
reg[REGARG]--;
regret(&nod, n, l->type, 1); // update maxarg if nothing else

View file

@ -518,7 +518,7 @@ loop2:
rgp->cost = change;
nregion++;
if(nregion >= NRGN) {
warn(Z, "too many regions");
fatal(Z, "too many regions");
goto brk;
}
rgp++;
@ -746,11 +746,8 @@ mkvar(Reg *r, Addr *a)
goto out;
v++;
}
if(nvar >= NVAR) {
if(debug['w'] > 1 && s)
warn(Z, "variable not optimized: %s", s->name);
goto none;
}
if(nvar >= NVAR)
fatal(Z, "variable not optimized: %s", s->name);
i = nvar;
nvar++;
v = &var[i];

View file

@ -114,7 +114,6 @@ void split64(Node*, Node*, Node*);
void splitclean(void);
void nswap(Node*, Node*);
void gtrack(Sym*);
void gargsize(int32);
/*
* cplx.c
*/

View 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);
@ -210,28 +236,12 @@ clearfat(Node *nl)
void
ginscall(Node *f, int proc)
{
int32 arg;
Prog *p;
Node reg, r1, con;
if(f->type != T)
setmaxarg(f->type);
arg = -1;
// Most functions have a fixed-size argument block, so traceback uses that during unwind.
// Not all, though: there are some variadic functions in package runtime,
// and for those we emit call-specific metadata recorded by caller.
// Reflect generates functions with variable argsize (see reflect.methodValueCall/makeFuncStub),
// so we do this for all indirect calls as well.
if(f->type != T && (f->sym == S || (f->sym != S && f->sym->pkg == runtimepkg) || proc == 1 || proc == 2)) {
arg = f->type->argwid;
if(proc == 1 || proc == 2)
arg += 2*widthptr;
}
if(arg != -1)
gargsize(arg);
switch(proc) {
default:
fatal("ginscall: bad proc %d", proc);
@ -293,9 +303,6 @@ ginscall(Node *f, int proc)
}
break;
}
if(arg != -1)
gargsize(-1);
}
/*

View file

@ -205,16 +205,6 @@ ggloblnod(Node *nam)
p->from.scale |= NOPTR;
}
void
gargsize(int32 size)
{
Node n1, n2;
nodconst(&n1, types[TINT32], PCDATA_ArgSize);
nodconst(&n2, types[TINT32], size);
gins(APCDATA, &n1, &n2);
}
void
ggloblsym(Sym *s, int32 width, int8 flags)
{
@ -948,7 +938,7 @@ regalloc(Node *n, Type *t, Node *o)
fprint(2, "registers allocated at\n");
for(i=D_AX; i<=D_DI; i++)
fprint(2, "\t%R\t%#lux\n", i, regpc[i]);
yyerror("out of fixed registers");
fatal("out of fixed registers");
goto err;
case TFLOAT32:

View file

@ -117,13 +117,21 @@ adddynrel(LSym *s, Reloc *r)
case 256 + R_386_GOT32:
if(targ->type != SDYNIMPORT) {
// have symbol
// turn MOVL of GOT entry into LEAL of symbol itself
if(r->off < 2 || s->p[r->off-2] != 0x8b) {
diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
if(r->off >= 2 && s->p[r->off-2] == 0x8b) {
// turn MOVL of GOT entry into LEAL of symbol address, relative to GOT.
s->p[r->off-2] = 0x8d;
r->type = R_GOTOFF;
return;
}
s->p[r->off-2] = 0x8d;
r->type = R_GOTOFF;
if(r->off >= 2 && s->p[r->off-2] == 0xff && s->p[r->off-1] == 0xb3) {
// turn PUSHL of GOT entry into PUSHL of symbol itself.
// use unnecessary SS prefix to keep instruction same length.
s->p[r->off-2] = 0x36;
s->p[r->off-1] = 0x68;
r->type = R_ADDR;
return;
}
diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
return;
}
addgotsym(ctxt, targ);

View file

@ -100,6 +100,7 @@ main(int argc, char *argv[])
ctxt = linknew(thelinkarch);
ctxt->diag = yyerror;
ctxt->bso = &bstdout;
ctxt->enforce_data_order = 1;
Binit(&bstdout, 1, OWRITE);
listinit9();
fmtinstall('L', Lconv);

View file

@ -342,20 +342,16 @@ cgen(Node *n, Node *nn)
if(REGARG >= 0)
o = reg[REGARG];
gargs(r, &nod, &nod1);
gpcdata(PCDATA_ArgSize, curarg);
if(l->addable < INDEXED) {
reglcgen(&nod, l, Z);
gopcode(OFUNC, Z, Z, &nod);
regfree(&nod);
} else
gopcode(OFUNC, Z, Z, l);
gpcdata(PCDATA_ArgSize, -1);
if(REGARG>=0)
if(o != reg[REGARG])
reg[REGARG]--;
regret(&nod, n, l->type, 1); // update maxarg if nothing else
gpcdata(PCDATA_ArgSize, curarg);
gpcdata(PCDATA_ArgSize, -1);
if(nn != Z)
gopcode(OAS, &nod, Z, nn);
if(nod.op == OREGISTER)

View file

@ -378,14 +378,11 @@ loop2:
}
rgp->cost = change;
nregion++;
if(nregion >= NRGN) {
warn(Z, "too many regions");
goto brk;
}
if(nregion >= NRGN)
fatal(Z, "too many regions");
rgp++;
}
}
brk:
qsort(region, nregion, sizeof(region[0]), rcmp);
/*
@ -591,11 +588,8 @@ mkvar(Addr *a, int docon)
if(s)
if(s->name[0] == '.')
goto none;
if(nvar >= NVAR) {
if(debug['w'] > 1 && s)
warn(Z, "variable not optimized: %s", s->name);
goto none;
}
if(nvar >= NVAR)
fatal(Z, "variable not optimized: %s", s->name);
i = nvar;
nvar++;
v = &var[i];

View file

@ -94,7 +94,6 @@ int sudoaddable(int, Node*, Addr*);
void afunclit(Addr*, Node*);
void nodfconst(Node*, Type*, Mpflt*);
void gtrack(Sym*);
void gargsize(vlong);
void fixlargeoffset(Node *n);
/*

View file

@ -191,7 +191,6 @@ ginsBL(Node *reg, Node *f)
void
ginscall(Node *f, int proc)
{
int32 arg;
Prog *p;
Node reg, con, reg2;
Node r1;
@ -199,21 +198,6 @@ ginscall(Node *f, int proc)
if(f->type != T)
setmaxarg(f->type);
arg = -1;
// Most functions have a fixed-size argument block, so traceback uses that during unwind.
// Not all, though: there are some variadic functions in package runtime,
// and for those we emit call-specific metadata recorded by caller.
// Reflect generates functions with variable argsize (see reflect.methodValueCall/makeFuncStub),
// so we do this for all indirect calls as well.
if(f->type != T && (f->sym == S || (f->sym != S && f->sym->pkg == runtimepkg) || proc == 1 || proc == 2)) {
arg = f->type->argwid;
if(proc == 1 || proc == 2)
arg += 3*widthptr;
}
if(arg != -1)
gargsize(arg);
switch(proc) {
default:
fatal("ginscall: bad proc %d", proc);
@ -303,9 +287,6 @@ ginscall(Node *f, int proc)
}
break;
}
if(arg != -1)
gargsize(-1);
}
/*

View file

@ -216,16 +216,6 @@ gtrack(Sym *s)
p->from.sym = linksym(s);
}
void
gargsize(vlong size)
{
Node n1, n2;
nodconst(&n1, types[TINT32], PCDATA_ArgSize);
nodconst(&n2, types[TINT32], size);
gins(APCDATA, &n1, &n2);
}
void
ggloblsym(Sym *s, int32 width, int8 flags)
{

View file

@ -377,7 +377,7 @@ func (w *Walker) parseFile(dir, file string) (*ast.File, error) {
}
}
if w.context != nil && file == fmt.Sprintf("zruntime_defs_%s_%s.go", w.context.GOOS, w.context.GOARCH) {
// Just enough to keep the api checker happy.
// Just enough to keep the api checker happy. Keep sorted.
src := "package runtime; type (" +
" _defer struct{};" +
" _func struct{};" +
@ -388,6 +388,7 @@ func (w *Walker) parseFile(dir, file string) (*ast.File, error) {
" chantype struct{};" +
" context struct{};" + // windows
" eface struct{};" +
" epollevent struct{};" +
" funcval struct{};" +
" g struct{};" +
" gobuf struct{};" +
@ -395,20 +396,21 @@ func (w *Walker) parseFile(dir, file string) (*ast.File, error) {
" iface struct{};" +
" interfacetype struct{};" +
" itab struct{};" +
" keventt struct{};" +
" m struct{};" +
" maptype struct{};" +
" mcache struct{};" +
" mspan struct{};" +
" mutex struct{};" +
" note struct{};" +
" p struct{};" +
" parfor struct{};" +
" slicetype struct{};" +
" stkframe struct{};" +
" sudog struct{};" +
" timespec struct{};" +
" waitq struct{};" +
" wincallbackcontext struct{};" +
" keventt struct{};" +
" timespec struct{};" +
" epollevent struct{};" +
"); " +
"const (" +
" cb_max = 2000;" +
@ -422,6 +424,52 @@ func (w *Walker) parseFile(dir, file string) (*ast.File, error) {
" _Genqueue = 7;" +
" _Gcopystack = 8;" +
" _NSIG = 32;" +
" _FlagNoScan = iota;" +
" _FlagNoZero;" +
" _TinySize;" +
" _TinySizeClass;" +
" _MaxSmallSize;" +
" _PageShift;" +
" _PageSize;" +
" _PageMask;" +
" _BitsPerPointer;" +
" _BitsMask;" +
" _PointersPerByte;" +
" _MaxGCMask;" +
" _BitsDead;" +
" _BitsPointer;" +
" _MSpanInUse;" +
" _ConcurrentSweep;" +
" _KindBool;" +
" _KindInt;" +
" _KindInt8;" +
" _KindInt16;" +
" _KindInt32;" +
" _KindInt64;" +
" _KindUint;" +
" _KindUint8;" +
" _KindUint16;" +
" _KindUint32;" +
" _KindUint64;" +
" _KindUintptr;" +
" _KindFloat32;" +
" _KindFloat64;" +
" _KindComplex64;" +
" _KindComplex128;" +
" _KindArray;" +
" _KindChan;" +
" _KindFunc;" +
" _KindInterface;" +
" _KindMap;" +
" _KindPtr;" +
" _KindSlice;" +
" _KindString;" +
" _KindStruct;" +
" _KindUnsafePointer;" +
" _KindDirectIface;" +
" _KindGCProg;" +
" _KindNoPointers;" +
" _KindMask;" +
")"
f, err = parser.ParseFile(fset, filename, src, 0)
if err != nil {
@ -449,6 +497,11 @@ func contains(list []string, s string) bool {
return false
}
// The package cache doesn't operate correctly in rare (so far artificial)
// circumstances (issue 8425). Disable before debugging non-obvious errors
// from the type-checker.
const usePkgCache = true
var (
pkgCache = map[string]*types.Package{} // map tagKey to package
pkgTags = map[string][]string{} // map import dir to list of relevant tags
@ -510,11 +563,13 @@ func (w *Walker) Import(name string) (pkg *types.Package) {
// If we've already done an import with the same set
// of relevant tags, reuse the result.
var key string
if tags, ok := pkgTags[dir]; ok {
key = tagKey(dir, context, tags)
if pkg := pkgCache[key]; pkg != nil {
w.imported[name] = pkg
return pkg
if usePkgCache {
if tags, ok := pkgTags[dir]; ok {
key = tagKey(dir, context, tags)
if pkg := pkgCache[key]; pkg != nil {
w.imported[name] = pkg
return pkg
}
}
}
@ -527,9 +582,11 @@ func (w *Walker) Import(name string) (pkg *types.Package) {
}
// Save tags list first time we see a directory.
if _, ok := pkgTags[dir]; !ok {
pkgTags[dir] = info.AllTags
key = tagKey(dir, context, info.AllTags)
if usePkgCache {
if _, ok := pkgTags[dir]; !ok {
pkgTags[dir] = info.AllTags
key = tagKey(dir, context, info.AllTags)
}
}
filenames := append(append([]string{}, info.GoFiles...), info.CgoFiles...)
@ -582,7 +639,9 @@ func (w *Walker) Import(name string) (pkg *types.Package) {
log.Fatalf("error typechecking package %s: %s (%s)", name, err, ctxt)
}
pkgCache[key] = pkg
if usePkgCache {
pkgCache[key] = pkg
}
w.imported[name] = pkg
return

View file

@ -1,45 +0,0 @@
// Copyright 2013 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.
#include <u.h>
#include "cc.h"
enum {
WORDSIZE = sizeof(uint32),
WORDBITS = 32,
};
uintptr
bvsize(uintptr n)
{
return ((n + WORDBITS - 1) / WORDBITS) * WORDSIZE;
}
Bvec*
bvalloc(int32 n)
{
Bvec *bv;
uintptr nbytes;
if(n < 0)
fatal(Z, "bvalloc: initial size is negative\n");
nbytes = sizeof(Bvec) + bvsize(n);
bv = malloc(nbytes);
if(bv == nil)
fatal(Z, "bvalloc: malloc failed\n");
memset(bv, 0, nbytes);
bv->n = n;
return bv;
}
void
bvset(Bvec *bv, int32 i)
{
uint32 mask;
if(i < 0 || i >= bv->n)
fatal(Z, "bvset: index %d is out of bounds with length %d\n", i, bv->n);
mask = 1 << (i % WORDBITS);
bv->b[i / WORDBITS] |= mask;
}

View file

@ -761,12 +761,6 @@ Bits blsh(uint);
int beq(Bits, Bits);
int bset(Bits, uint);
/*
* bv.c
*/
Bvec* bvalloc(int32 n);
void bvset(Bvec *bv, int32 i);
/*
* dpchk.c
*/

View file

@ -30,6 +30,9 @@
#include <u.h>
#include "cc.h"
#include "../ld/textflag.h"
static int haspointers(Type*);
Node*
dodecl(void (*f)(int,Type*,Sym*), int c, Type *t, Node *n)
@ -123,7 +126,8 @@ loop:
if(dataflag) {
s->dataflag = dataflag;
dataflag = 0;
}
} else if(s->type != T && !haspointers(s->type))
s->dataflag = NOPTR;
firstbit = 0;
n->sym = s;
n->type = s->type;
@ -568,9 +572,8 @@ haspointers(Type *t)
return 0;
case TARRAY:
return haspointers(t->link);
case TFUNC:
case TIND:
return 1;
return t->link->etype != TFUNC;
default:
return 0;
}

View file

@ -353,8 +353,10 @@ godefvar(Sym *s)
case CSTATIC:
case CEXTERN:
case CGLOBL:
if(strchr(s->name, '$') != nil) // TODO(lvd)
break;
if(strchr(s->name, '$') != nil)
break;
if(strncmp(s->name, "go.weak.", 8) == 0)
break;
Bprint(&outbuf, "var %U\t", s->name);
printtypename(t);
Bprint(&outbuf, "\n");

View file

@ -31,6 +31,7 @@
#include <u.h>
#include "cc.h"
#include "y.tab.h"
#include "../ld/textflag.h"
#ifndef CPP
#define CPP "cpp"
@ -1317,6 +1318,7 @@ cinit(void)
t->width = 0;
symstring = slookup(".string");
symstring->class = CSTATIC;
symstring->dataflag = NOPTR;
symstring->type = t;
t = typ(TARRAY, types[TCHAR]);

View file

@ -31,30 +31,6 @@
#include "gc.h"
#include "../../runtime/funcdata.h"
enum { BitsPerPointer = 2 };
static void dumpgcargs(Type *fn, Sym *sym);
static Sym*
makefuncdatasym(char *namefmt, int64 funcdatakind)
{
Node nod;
Sym *sym;
static int32 nsym;
static char namebuf[40];
snprint(namebuf, sizeof(namebuf), namefmt, nsym++);
sym = slookup(namebuf);
sym->class = CSTATIC;
memset(&nod, 0, sizeof nod);
nod.op = ONAME;
nod.sym = sym;
nod.class = CSTATIC;
gins(AFUNCDATA, nodconst(funcdatakind), &nod);
linksym(sym)->type = SRODATA;
return sym;
}
int
hasdotdotdot(Type *t)
{
@ -109,9 +85,6 @@ codgen(Node *n, Node *nn)
{
Prog *sp;
Node *n1, nod, nod1;
Sym *gcargs;
Sym *gclocals;
int isvarargs;
cursafe = 0;
curarg = 0;
@ -134,16 +107,6 @@ codgen(Node *n, Node *nn)
p->from.sym->cfunc = 1;
sp = p;
/*
* generate funcdata symbol for this function.
* data is filled in at the end of codgen().
*/
isvarargs = hasdotdotdot(thisfn);
gcargs = nil;
if(!isvarargs)
gcargs = makefuncdatasym("gcargs·%d", FUNCDATA_ArgsPointerMaps);
gclocals = makefuncdatasym("gclocals·%d", FUNCDATA_LocalsPointerMaps);
/*
* isolate first argument
*/
@ -178,22 +141,6 @@ codgen(Node *n, Node *nn)
if(thechar=='6' || thechar=='7') /* [sic] */
maxargsafe = xround(maxargsafe, 8);
sp->to.offset += maxargsafe;
if(!isvarargs)
dumpgcargs(thisfn, gcargs);
// TODO(rsc): "stkoff" is not right. It does not account for
// the possibility of data stored in .safe variables.
// Unfortunately those move up and down just like
// the argument frame (and in fact dovetail with it)
// so the number we need is not available or even
// well-defined. Probably we need to make the safe
// area its own section.
// That said, we've been using stkoff for months
// and nothing too terrible has happened.
gextern(gclocals, nodconst(-stkoff), 0, 4); // locals
gclocals->type = typ(0, T);
gclocals->type->width = 4;
}
void
@ -673,113 +620,3 @@ bcomplex(Node *n, Node *c)
boolgen(n, 1, Z);
return 0;
}
// Updates the bitvector with a set bit for each pointer containing
// value in the type description starting at offset.
static void
walktype1(Type *t, int32 offset, Bvec *bv, int param)
{
Type *t1;
int32 o;
int32 widthptr;
widthptr = ewidth[TIND];
switch(t->etype) {
case TCHAR:
case TUCHAR:
case TSHORT:
case TUSHORT:
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TVLONG:
case TUVLONG:
case TFLOAT:
case TDOUBLE:
// non-pointer types
for(o = 0; o < t->width; o++)
bvset(bv, ((offset + t->offset + o) / widthptr) * BitsPerPointer); // 1 = live scalar
break;
case TIND:
pointer:
// pointer types
if((offset + t->offset) % widthptr != 0)
yyerror("unaligned pointer");
bvset(bv, ((offset + t->offset) / widthptr)*BitsPerPointer + 1); // 2 = live ptr
break;
case TARRAY:
if(param) // unlike Go, C passes arrays by reference
goto pointer;
// array in struct or union is an actual array
for(o = 0; o < t->width; o += t->link->width)
walktype1(t->link, offset+o, bv, 0);
break;
case TSTRUCT:
// build map recursively
for(t1 = t->link; t1 != T; t1 = t1->down)
walktype1(t1, offset, bv, 0);
break;
case TUNION:
walktype1(t->link, offset, bv, 0);
break;
default:
yyerror("can't handle arg type %s\n", tnames[t->etype]);
}
}
// Compute a bit vector to describe the pointer containing locations
// in the argument list. Adds the data to gcsym and returns the offset
// of end of the bit vector.
static void
dumpgcargs(Type *fn, Sym *sym)
{
Bvec *bv;
Type *t;
int32 i;
int32 argbytes;
int32 symoffset, argoffset;
// Dump the length of the bitmap array. This value is always one for
// functions written in C.
symoffset = 0;
gextern(sym, nodconst(1), symoffset, 4);
symoffset += 4;
argbytes = (argsize(1) + ewidth[TIND] - 1);
bv = bvalloc((argbytes / ewidth[TIND]) * BitsPerPointer);
argoffset = 0;
if(hasdotdotdot(thisfn))
argoffset = align(0, fn->link, Aarg0, nil);
if(argoffset > 0) {
// The C calling convention returns structs by copying them to a
// location pointed to by a hidden first argument. This first
// argument is a pointer.
if(argoffset != ewidth[TIND])
yyerror("passbyptr arg not the right size");
bvset(bv, 1); // 2 = live ptr
}
for(t = fn->down; t != T; t = t->down) {
if(t->etype == TVOID)
continue;
argoffset = align(argoffset, t, Aarg1, nil);
walktype1(t, argoffset, bv, 1);
argoffset = align(argoffset, t, Aarg2, nil);
}
// Dump the length of the bitmap.
gextern(sym, nodconst(bv->n), symoffset, 4);
symoffset += 4;
// Dump the words of the bitmap.
for(i = 0; i < bv->n; i += 32) {
gextern(sym, nodconst(bv->b[i/32]), symoffset, 4);
symoffset += 4;
}
free(bv);
// Finalize the gc symbol.
sym->type = typ(0, T);
sym->type->width = symoffset;
}

File diff suppressed because it is too large Load diff

View file

@ -1,21 +1,24 @@
/* A Bison parser, made by GNU Bison 2.7.12-4996. */
/* A Bison parser, made by GNU Bison 2.3. */
/* Bison interface for Yacc-like parsers in C
Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
/* Skeleton interface for Bison's Yacc-like parsers in C
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
@ -26,20 +29,10 @@
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
#ifndef YY_YY_Y_TAB_H_INCLUDED
# define YY_YY_Y_TAB_H_INCLUDED
/* Enabling traces. */
#ifndef YYDEBUG
# define YYDEBUG 0
#endif
#if YYDEBUG
extern int yydebug;
#endif
/* Tokens. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
@ -196,12 +189,11 @@ extern int yydebug;
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
{
/* Line 2053 of yacc.c */
#line 36 "cc.y"
{
Node* node;
Sym* sym;
Type* type;
@ -225,30 +217,14 @@ typedef union YYSTYPE
int32 lval;
double dval;
vlong vval;
/* Line 2053 of yacc.c */
#line 232 "y.tab.h"
} YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
}
/* Line 1529 of yacc.c. */
#line 223 "y.tab.h"
YYSTYPE;
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
# define YYSTYPE_IS_TRIVIAL 1
#endif
extern YYSTYPE yylval;
#ifdef YYPARSE_PARAM
#if defined __STDC__ || defined __cplusplus
int yyparse (void *YYPARSE_PARAM);
#else
int yyparse ();
#endif
#else /* ! YYPARSE_PARAM */
#if defined __STDC__ || defined __cplusplus
int yyparse (void);
#else
int yyparse ();
#endif
#endif /* ! YYPARSE_PARAM */
#endif /* !YY_YY_Y_TAB_H_INCLUDED */

View file

@ -308,6 +308,9 @@ func (f *File) walk(x interface{}, context string, visit func(*File, interface{}
if n.High != nil {
f.walk(&n.High, "expr", visit)
}
if n.Max != nil {
f.walk(&n.Max, "expr", visit)
}
case *ast.TypeAssertExpr:
f.walk(&n.X, "expr", visit)
f.walk(&n.Type, "type", visit)

View file

@ -44,6 +44,7 @@ func (p *Package) writeDefs() {
fmt.Fprintf(fm, "int main() { return 0; }\n")
if *importRuntimeCgo {
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c) { }\n")
fmt.Fprintf(fm, "char* _cgo_topofstack(void) { return (char*)0; }\n")
} else {
// If we're not importing runtime/cgo, we *are* runtime/cgo,
// which provides crosscall2. We just need a prototype.
@ -129,6 +130,7 @@ func (p *Package) writeDefs() {
fmt.Fprintf(fc, `extern void *%s __asm__("%s.%s");`, n.Mangle, gccgoSymbolPrefix, n.Mangle)
fmt.Fprintf(&gccgoInit, "\t%s = %s%s;\n", n.Mangle, amp, n.C)
} else {
fmt.Fprintf(fc, "#pragma dataflag NOPTR /* C pointer, not heap pointer */ \n")
fmt.Fprintf(fc, "void *·%s = %s%s;\n", n.Mangle, amp, n.C)
}
fmt.Fprintf(fc, "\n")
@ -397,6 +399,7 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
// C wrapper calls into gcc, passing a pointer to the argument frame.
fmt.Fprintf(fc, "#pragma cgo_import_static %s\n", cname)
fmt.Fprintf(fc, "void %s(void*);\n", cname)
fmt.Fprintf(fc, "#pragma dataflag NOPTR\n")
fmt.Fprintf(fc, "void *·%s = %s;\n", cname, cname)
nret := 0
@ -517,9 +520,13 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
// Use packed attribute to force no padding in this struct in case
// gcc has different packing requirements.
fmt.Fprintf(fgcc, "\t%s %v *a = v;\n", ctype, p.packedAttribute())
if n.FuncType.Result != nil {
// Save the stack top for use below.
fmt.Fprintf(fgcc, "\tchar *stktop = _cgo_topofstack();\n")
}
fmt.Fprintf(fgcc, "\t")
if t := n.FuncType.Result; t != nil {
fmt.Fprintf(fgcc, "a->r = ")
fmt.Fprintf(fgcc, "__typeof__(a->r) r = ")
if c := t.C.String(); c[len(c)-1] == '*' {
fmt.Fprint(fgcc, "(__typeof__(a->r)) ")
}
@ -542,6 +549,13 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
fmt.Fprintf(fgcc, "a->p%d", i)
}
fmt.Fprintf(fgcc, ");\n")
if n.FuncType.Result != nil {
// The cgo call may have caused a stack copy (via a callback).
// Adjust the return value pointer appropriately.
fmt.Fprintf(fgcc, "\ta = (void*)((char*)a + (_cgo_topofstack() - stktop));\n")
// Save the return value.
fmt.Fprintf(fgcc, "\ta->r = r;\n")
}
if n.AddError {
fmt.Fprintf(fgcc, "\treturn errno;\n")
}
@ -1129,6 +1143,8 @@ __cgo_size_assert(__cgo_long_long, 8)
__cgo_size_assert(float, 4)
__cgo_size_assert(double, 8)
extern char* _cgo_topofstack(void);
#include <errno.h>
#include <string.h>
`
@ -1151,20 +1167,31 @@ void *_CMalloc(size_t);
const cProlog = `
#include "runtime.h"
#include "cgocall.h"
#include "textflag.h"
#pragma dataflag NOPTR
static void *cgocall_errno = runtime·cgocall_errno;
#pragma dataflag NOPTR
void *·_cgo_runtime_cgocall_errno = &cgocall_errno;
#pragma dataflag NOPTR
static void *runtime_gostring = runtime·gostring;
#pragma dataflag NOPTR
void *·_cgo_runtime_gostring = &runtime_gostring;
#pragma dataflag NOPTR
static void *runtime_gostringn = runtime·gostringn;
#pragma dataflag NOPTR
void *·_cgo_runtime_gostringn = &runtime_gostringn;
#pragma dataflag NOPTR
static void *runtime_gobytes = runtime·gobytes;
#pragma dataflag NOPTR
void *·_cgo_runtime_gobytes = &runtime_gobytes;
#pragma dataflag NOPTR
static void *runtime_cmalloc = runtime·cmalloc;
#pragma dataflag NOPTR
void *·_cgo_runtime_cmalloc = &runtime_cmalloc;
void ·_Cerrno(void*, int32);

View file

@ -918,6 +918,8 @@ install(char *dir)
bpathf(&b1, "%s/signals_%s.h", bstr(&path), goos), 0);
copyfile(bpathf(&b, "%s/pkg/%s_%s/textflag.h", goroot, goos, goarch),
bpathf(&b1, "%s/src/cmd/ld/textflag.h", goroot), 0);
copyfile(bpathf(&b, "%s/pkg/%s_%s/funcdata.h", goroot, goos, goarch),
bpathf(&b1, "%s/src/runtime/funcdata.h", goroot), 0);
}
// Generate any missing files; regenerate existing ones.

View file

@ -253,6 +253,8 @@ ok:
aggr = "alg";
else if(streq(fields.p[1], "Panic"))
aggr = "panic";
else if(streq(fields.p[1], "Stack"))
aggr = "stack";
}
if(hasprefix(lines.p[i], "}"))
aggr = nil;
@ -334,16 +336,20 @@ mkzsys(char *dir, char *file)
static char *runtimedefs[] = {
"defs.c",
"malloc.c",
"mcache.c",
"mgc0.c",
"proc.c",
"parfor.c",
"stack.c",
};
// mkzruntimedefs writes zruntime_defs_$GOOS_$GOARCH.h,
// which contains Go struct definitions equivalent to the C ones.
// Mostly we just write the output of 6c -q to the file.
// However, we run it on multiple files, so we have to delete
// the duplicated definitions, and we don't care about the funcs
// and consts, so we delete those too.
// the duplicated definitions, and we don't care about the funcs,
// so we delete those too.
//
void
mkzruntimedefs(char *dir, char *file)

View file

@ -119,8 +119,10 @@ dowidth(Type *t)
if(t->width == -2) {
lno = lineno;
lineno = t->lineno;
if(!t->broke)
if(!t->broke) {
t->broke = 1;
yyerror("invalid recursive type %T", t);
}
t->width = 0;
lineno = lno;
return;

View file

@ -83,6 +83,14 @@ char *runtimeimport =
"func @\"\".chanrecv2 (@\"\".chanType·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any) (? bool)\n"
"func @\"\".chansend1 (@\"\".chanType·1 *byte, @\"\".hchan·2 chan<- any, @\"\".elem·3 *any)\n"
"func @\"\".closechan (@\"\".hchan·1 any)\n"
"func @\"\".writebarrierptr (@\"\".dst·1 *any, @\"\".src·2 any)\n"
"func @\"\".writebarrierstring (@\"\".dst·1 *any, @\"\".src·2 any)\n"
"func @\"\".writebarrierslice (@\"\".dst·1 *any, @\"\".src·2 any)\n"
"func @\"\".writebarrieriface (@\"\".dst·1 *any, @\"\".src·2 any)\n"
"func @\"\".writebarrierfat2 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
"func @\"\".writebarrierfat3 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
"func @\"\".writebarrierfat4 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
"func @\"\".writebarrierfat (@\"\".typ·1 *byte, @\"\".dst·2 *any, @\"\".src·3 *any)\n"
"func @\"\".selectnbsend (@\"\".chanType·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 *any) (? bool)\n"
"func @\"\".selectnbrecv (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".hchan·4 <-chan any) (? bool)\n"
"func @\"\".selectnbrecv2 (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".received·4 *bool, @\"\".hchan·5 <-chan any) (? bool)\n"

View file

@ -488,6 +488,10 @@ colasdefn(NodeList *left, Node *defn)
NodeList *l;
Node *n;
for(l=left; l; l=l->next)
if(l->n->sym != S)
l->n->sym->flags |= SymUniq;
nnew = 0;
nerr = 0;
for(l=left; l; l=l->next) {
@ -499,6 +503,13 @@ colasdefn(NodeList *left, Node *defn)
nerr++;
continue;
}
if((n->sym->flags & SymUniq) == 0) {
yyerrorl(defn->lineno, "%S repeated on left side of :=", n->sym);
n->diag++;
nerr++;
continue;
}
n->sym->flags &= ~SymUniq;
if(n->sym->block == block)
continue;
@ -547,6 +558,9 @@ ifacedcl(Node *n)
if(n->op != ODCLFIELD || n->right == N)
fatal("ifacedcl");
if(isblank(n->left))
yyerror("methods must have a unique non-blank name");
dclcontext = PPARAM;
markdcl();
funcdepth++;

View file

@ -810,6 +810,13 @@ stmtfmt(Fmt *f, Node *n)
break;
case OASOP:
if(n->implicit) {
if(n->etype == OADD)
fmtprint(f, "%N++", n->left);
else
fmtprint(f, "%N--", n->left);
break;
}
fmtprint(f, "%N %#O= %N", n->left, n->etype, n->right);
break;
@ -1108,16 +1115,11 @@ exprfmt(Fmt *f, Node *n, int prec)
case ONAME:
// Special case: name used as local variable in export.
switch(n->class&~PHEAP){
case PAUTO:
case PPARAM:
case PPARAMOUT:
// _ becomes ~b%d internally; print as _ for export
if(fmtmode == FExp && n->sym && n->sym->name[0] == '~' && n->sym->name[1] == 'b')
return fmtprint(f, "_");
if(fmtmode == FExp && n->sym && !isblank(n) && n->vargen > 0)
return fmtprint(f, "%S·%d", n->sym, n->vargen);
}
// _ becomes ~b%d internally; print as _ for export
if(fmtmode == FExp && n->sym && n->sym->name[0] == '~' && n->sym->name[1] == 'b')
return fmtprint(f, "_");
if(fmtmode == FExp && n->sym && !isblank(n) && n->vargen > 0)
return fmtprint(f, "%S·%d", n->sym, n->vargen);
// Special case: explicit name of func (*T) method(...) is turned into pkg.(*T).method,
// but for export, this should be rendered as (*pkg.T).meth.

View file

@ -54,9 +54,6 @@ addrescapes(Node *n)
if(n->class == PAUTO && n->esc == EscNever)
break;
if(debug['N'] && n->esc != EscUnknown)
fatal("without escape analysis, only PAUTO's should have esc: %N", n);
switch(n->class) {
case PPARAMREF:
addrescapes(n->defn);
@ -91,8 +88,7 @@ addrescapes(Node *n)
snprint(buf, sizeof buf, "&%S", n->sym);
n->heapaddr->sym = lookup(buf);
n->heapaddr->orig->sym = n->heapaddr->sym;
if(!debug['N'])
n->esc = EscHeap;
n->esc = EscHeap;
if(debug['m'])
print("%L: moved to heap: %N\n", n->lineno, n);
curfn = oldfn;
@ -585,7 +581,7 @@ cgen_dcl(Node *n)
if(!(n->class & PHEAP))
return;
if(compiling_runtime)
fatal("%N escapes to heap, not allowed in runtime.", n);
yyerror("%N escapes to heap, not allowed in runtime.", n);
if(n->alloc == nil)
n->alloc = callnew(n->type);
cgen_as(n->heapaddr, n->alloc);
@ -735,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)

View 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
@ -973,6 +974,7 @@ EXTERN int funcdepth;
EXTERN int typecheckok;
EXTERN int compiling_runtime;
EXTERN int compiling_wrappers;
EXTERN int use_writebarrier;
EXTERN int pure_go;
EXTERN char* flag_installsuffix;
EXTERN int flag_race;
@ -1284,6 +1286,7 @@ LSym* linksym(Sym*);
* order.c
*/
void order(Node *fn);
void orderstmtinplace(Node **stmt);
/*
* range.c
@ -1372,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);
@ -1464,6 +1468,7 @@ void walkstmt(Node **np);
void walkstmtlist(NodeList *l);
Node* conv(Node*, Type*);
int candiscard(Node*);
int needwritebarrier(Node*, Node*);
Node* outervalue(Node*);
void usefield(Node*);

View file

@ -460,11 +460,13 @@ simple_stmt:
| expr LINC
{
$$ = nod(OASOP, $1, nodintconst(1));
$$->implicit = 1;
$$->etype = OADD;
}
| expr LDEC
{
$$ = nod(OASOP, $1, nodintconst(1));
$$->implicit = 1;
$$->etype = OSUB;
}

View file

@ -312,6 +312,8 @@ main(int argc, char *argv[])
flagcount("u", "reject unsafe code", &safemode);
flagcount("v", "increase debug verbosity", &debug['v']);
flagcount("w", "debug type checking", &debug['w']);
use_writebarrier = 1;
flagcount("wb", "enable write barrier", &use_writebarrier);
flagcount("x", "debug lexer", &debug['x']);
flagcount("y", "debug declarations in canned imports (with -d)", &debug['y']);
if(thechar == '6')
@ -479,8 +481,12 @@ main(int argc, char *argv[])
}
// Phase 5: Escape analysis.
if(!debug['N'])
escapes(xtop);
// Required for moving heap allocations onto stack,
// which in turn is required by the closure implementation,
// which stores the addresses of stack variables into the closure.
// If the closure does not escape, it needs to be on the stack
// or else the stack copier will not update it.
escapes(xtop);
// Escape analysis moved escaped values off stack.
// Move large values off stack too.

View 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);
}

View file

@ -317,7 +317,7 @@ orderexprinplace(Node **np, Order *outer)
// Orderstmtinplace orders the side effects of the single statement *np
// and replaces it with the resulting statement list.
static void
void
orderstmtinplace(Node **np)
{
Node *n;
@ -438,6 +438,9 @@ ordercall(Node *n, Order *order)
// cases they are also typically registerizable, so not much harm done.
// And this only applies to the multiple-assignment form.
// We could do a more precise analysis if needed, like in walk.c.
//
// Ordermapassign also inserts these temporaries if needed for
// calling writebarrierfat with a pointer to n->right.
static void
ordermapassign(Node *n, Order *order)
{
@ -451,7 +454,8 @@ ordermapassign(Node *n, Order *order)
case OAS:
order->out = list(order->out, n);
if(n->left->op == OINDEXMAP && !isaddrokay(n->right)) {
// We call writebarrierfat only for values > 4 pointers long. See walk.c.
if((n->left->op == OINDEXMAP || (needwritebarrier(n->left, n->right) && n->left->type->width > 4*widthptr)) && !isaddrokay(n->right)) {
m = n->left;
n->left = ordertemp(m->type, order, 0);
a = nod(OAS, m, n->left);
@ -1028,11 +1032,21 @@ orderexpr(Node **np, Order *order)
orderexprinplace(&n->right, order);
break;
case OCALLFUNC:
case OCALLMETH:
case OCALLINTER:
case OAPPEND:
case OCALLFUNC:
case OCALLINTER:
case OCALLMETH:
case OCAP:
case OCOMPLEX:
case OCOPY:
case OIMAG:
case OLEN:
case OMAKECHAN:
case OMAKEMAP:
case OMAKESLICE:
case ONEW:
case OREAL:
case ORECOVER:
ordercall(n, order);
n = ordercopyexpr(n, n->type, order, 0);
break;

View file

@ -14,6 +14,7 @@
#include "../../runtime/funcdata.h"
static void allocauto(Prog* p);
static void emitptrargsmap(void);
static Sym*
makefuncdatasym(char *namefmt, int64 funcdatakind)
@ -173,9 +174,17 @@ compile(Node *fn)
lno = setlineno(fn);
curfn = fn;
dowidth(curfn->type);
if(fn->nbody == nil) {
if(pure_go || strncmp(fn->nname->sym->name, "init·", 6) == 0)
if(pure_go || strncmp(fn->nname->sym->name, "init·", 6) == 0) {
yyerror("missing function body", fn);
goto ret;
}
if(debug['A'])
goto ret;
emitptrargsmap();
goto ret;
}
@ -184,9 +193,6 @@ compile(Node *fn)
// set up domain for labels
clearlabels();
curfn = fn;
dowidth(curfn->type);
if(curfn->type->outnamed) {
// add clearing of the output parameters
t = structfirst(&save, getoutarg(curfn->type));
@ -329,6 +335,43 @@ ret:
lineno = lno;
}
static void
emitptrargsmap(void)
{
int nptr, nbitmap, j, off;
vlong xoffset;
Bvec *bv;
Sym *sym;
sym = lookup(smprint("%s.args_stackmap", curfn->nname->sym->name));
nptr = curfn->type->argwid / widthptr;
bv = bvalloc(nptr*2);
nbitmap = 1;
if(curfn->type->outtuple > 0)
nbitmap = 2;
off = duint32(sym, 0, nbitmap);
off = duint32(sym, off, bv->n);
if(curfn->type->thistuple > 0) {
xoffset = 0;
twobitwalktype1(getthisx(curfn->type), &xoffset, bv);
}
if(curfn->type->intuple > 0) {
xoffset = 0;
twobitwalktype1(getinargx(curfn->type), &xoffset, bv);
}
for(j = 0; j < bv->n; j += 32)
off = duint32(sym, off, bv->b[j/32]);
if(curfn->type->outtuple > 0) {
xoffset = 0;
twobitwalktype1(getoutargx(curfn->type), &xoffset, bv);
for(j = 0; j < bv->n; j += 32)
off = duint32(sym, off, bv->b[j/32]);
}
ggloblsym(sym, off, RODATA);
free(bv);
}
// Sort the list of stack variables. Autos after anything else,
// within autos, unused after used, within used, things with
// pointers first, zeroed things first, and then decreasing size.

View file

@ -208,6 +208,26 @@ racewalknode(Node **np, NodeList **init, int wr, int skip)
goto ret;
case OCALLFUNC:
// Instrument dst argument of runtime.writebarrier* calls
// as we do not instrument runtime code.
if(n->left->sym != S && n->left->sym->pkg == runtimepkg && strncmp(n->left->sym->name, "writebarrier", 12) == 0) {
// Find the dst argument.
// The list can be reordered, so it's not necessary just the first or the second element.
for(l = n->list; l; l = l->next) {
if(strcmp(n->left->sym->name, "writebarrierfat") == 0) {
if(l->n->left->xoffset == widthptr)
break;
} else {
if(l->n->left->xoffset == 0)
break;
}
}
if(l == nil)
fatal("racewalk: writebarrier no arg");
if(l->n->right->op != OADDR)
fatal("racewalk: writebarrier bad arg");
callinstr(&l->n->right->left, init, 1, 0);
}
racewalknode(&n->left, init, 0, 0);
goto ret;

View file

@ -716,9 +716,10 @@ static int
dcommontype(Sym *s, int ot, Type *t)
{
int i, alg, sizeofAlg, gcprog;
Sym *sptr, *algsym, *zero, *gcprog0, *gcprog1;
Sym *sptr, *algsym, *zero, *gcprog0, *gcprog1, *sbits;
uint8 gcmask[16];
static Sym *algarray;
uint64 x1, x2;
char *p;
if(ot != 0)
@ -727,12 +728,12 @@ dcommontype(Sym *s, int ot, Type *t)
sizeofAlg = 2*widthptr;
if(algarray == nil)
algarray = pkglookup("algarray", runtimepkg);
dowidth(t);
alg = algtype(t);
algsym = S;
if(alg < 0)
algsym = dalgsym(t);
dowidth(t);
if(t->sym != nil && !isptr[t->etype])
sptr = dtypesym(ptrto(t));
else
@ -804,8 +805,26 @@ dcommontype(Sym *s, int ot, Type *t)
ot = dsymptr(s, ot, gcprog1, 0);
} else {
gengcmask(t, gcmask);
for(i = 0; i < 2*widthptr; i++)
ot = duint8(s, ot, gcmask[i]);
x1 = 0;
for(i=0; i<8; i++)
x1 = x1<<8 | gcmask[i];
if(widthptr == 4) {
p = smprint("gcbits.%#016llux", x1);
} else {
x2 = 0;
for(i=0; i<8; i++)
x2 = x2<<8 | gcmask[i+8];
p = smprint("gcbits.%#016llux%016llux", x1, x2);
}
sbits = pkglookup(p, runtimepkg);
if((sbits->flags & SymUniq) == 0) {
sbits->flags |= SymUniq;
for(i = 0; i < 2*widthptr; i++)
duint8(sbits, i, gcmask[i]);
ggloblsym(sbits, 2*widthptr, DUPOK|RODATA);
}
ot = dsymptr(s, ot, sbits, 0);
ot = duintptr(s, ot, 0);
}
p = smprint("%-uT", t);
//print("dcommontype: %s\n", p);

View file

@ -107,6 +107,20 @@ func chanrecv2(chanType *byte, hchan <-chan any, elem *any) bool
func chansend1(chanType *byte, hchan chan<- any, elem *any)
func closechan(hchan any)
// *byte is really *runtime.Type
func writebarrierptr(dst *any, src any)
func writebarrierstring(dst *any, src any)
func writebarrierslice(dst *any, src any)
func writebarrieriface(dst *any, src any)
// The unused *byte argument makes sure that src is 2-pointer-aligned,
// which is the maximum alignment on NaCl amd64p32
// (and possibly on 32-bit systems if we start 64-bit aligning uint64s).
func writebarrierfat2(dst *any, _ *byte, src any)
func writebarrierfat3(dst *any, _ *byte, src any)
func writebarrierfat4(dst *any, _ *byte, src any)
func writebarrierfat(typ *byte, dst *any, src *any)
func selectnbsend(chanType *byte, hchan chan<- any, elem *any) bool
func selectnbrecv(chanType *byte, elem *any, hchan <-chan any) bool
func selectnbrecv2(chanType *byte, elem *any, received *bool, hchan <-chan any) bool

View file

@ -17,7 +17,6 @@ enum
InitPending = 2,
};
static int iszero(Node*);
static void initplan(Node*);
static NodeList *initlist;
static void init2(Node*, NodeList**);
@ -207,7 +206,7 @@ init2(Node *n, NodeList **out)
if(n->op == OCLOSURE)
init2list(n->closure->nbody, out);
if(n->op == ODOTMETH)
if(n->op == ODOTMETH || n->op == OCALLPART)
init2(n->type->nname, out);
}
@ -633,11 +632,14 @@ structlit(int ctxt, int pass, Node *n, Node *var, NodeList **init)
a = nod(ODOT, var, newname(index->sym));
a = nod(OAS, a, value);
typecheck(&a, Etop);
walkexpr(&a, init);
if(pass == 1) {
walkexpr(&a, init); // add any assignments in r to top
if(a->op != OAS)
fatal("structlit: not as");
a->dodata = 2;
} else {
orderstmtinplace(&a);
walkstmt(&a);
}
*init = list(*init, a);
}
@ -693,11 +695,14 @@ arraylit(int ctxt, int pass, Node *n, Node *var, NodeList **init)
a = nod(OINDEX, var, index);
a = nod(OAS, a, value);
typecheck(&a, Etop);
walkexpr(&a, init); // add any assignments in r to top
if(pass == 1) {
walkexpr(&a, init);
if(a->op != OAS)
fatal("structlit: not as");
fatal("arraylit: not as");
a->dodata = 2;
} else {
orderstmtinplace(&a);
walkstmt(&a);
}
*init = list(*init, a);
}
@ -807,7 +812,8 @@ slicelit(int ctxt, Node *n, Node *var, NodeList **init)
// make slice out of heap (5)
a = nod(OAS, var, nod(OSLICE, vauto, nod(OKEY, N, N)));
typecheck(&a, Etop);
walkexpr(&a, init);
orderstmtinplace(&a);
walkstmt(&a);
*init = list(*init, a);
// put dynamics into slice (6)
@ -839,7 +845,8 @@ slicelit(int ctxt, Node *n, Node *var, NodeList **init)
// build list of var[c] = expr
a = nod(OAS, a, value);
typecheck(&a, Etop);
walkexpr(&a, init);
orderstmtinplace(&a);
walkstmt(&a);
*init = list(*init, a);
}
}
@ -1060,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
@ -1083,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);
@ -1100,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
@ -1123,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);
@ -1348,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*);
@ -1432,7 +1438,7 @@ addvalue(InitPlan *p, vlong xoffset, Node *key, Node *n)
e->expr = n;
}
static int
int
iszero(Node *n)
{
NodeList *l;

View file

@ -529,7 +529,8 @@ algtype1(Type *t, Type **bad)
if(bad)
*bad = T;
if(t->broke)
return AMEM;
if(t->noalg)
return ANOEQ;
@ -3466,7 +3467,7 @@ smagic(Magic *m)
p = m->w-1;
ad = m->sd;
if(m->sd < 0)
ad = -m->sd;
ad = -(uvlong)m->sd;
// bad denominators
if(ad == 0 || ad == 1 || ad == two31) {

View file

@ -33,7 +33,7 @@ static void stringtoarraylit(Node**);
static Node* resolve(Node*);
static void checkdefergo(Node*);
static int checkmake(Type*, char*, Node*);
static int checksliceindex(Node*, Type*);
static int checksliceindex(Node*, Node*, Type*);
static int checksliceconst(Node*, Node*);
static NodeList* typecheckdefstack;
@ -311,6 +311,7 @@ typecheck1(Node **np, int top)
Type *t, *tp, *missing, *have, *badtype;
Val v;
char *why, *desc, descbuf[64];
vlong x;
n = *np;
@ -408,7 +409,10 @@ reswitch:
v = toint(l->val);
break;
default:
yyerror("invalid array bound %N", l);
if(l->type != T && isint[l->type->etype] && l->op != OLITERAL)
yyerror("non-constant array bound %N", l);
else
yyerror("invalid array bound %N", l);
goto error;
}
t->bound = mpgetfix(v.u.xval);
@ -597,6 +601,10 @@ reswitch:
}
if(t->etype != TIDEAL && !eqtype(l->type, r->type)) {
defaultlit2(&l, &r, 1);
if(n->op == OASOP && n->implicit) {
yyerror("invalid operation: %N (non-numeric type %T)", n, l->type);
goto error;
}
yyerror("invalid operation: %N (mismatched types %T and %T)", n, l->type, r->type);
goto error;
}
@ -733,10 +741,6 @@ reswitch:
l = n->left;
if((t = l->type) == T)
goto error;
// top&Eindir means this is &x in *&x. (or the arg to built-in print)
// n->etype means code generator flagged it as non-escaping.
if(debug['N'] && !(top & Eindir) && !n->etype)
addrescapes(n->left);
n->type = ptrto(t);
goto ret;
@ -892,11 +896,12 @@ reswitch:
break;
}
if(isconst(n->right, CTINT)) {
if(mpgetfix(n->right->val.u.xval) < 0)
x = mpgetfix(n->right->val.u.xval);
if(x < 0)
yyerror("invalid %s index %N (index must be non-negative)", why, n->right);
else if(isfixedarray(t) && t->bound > 0 && mpgetfix(n->right->val.u.xval) >= t->bound)
else if(isfixedarray(t) && t->bound > 0 && x >= t->bound)
yyerror("invalid array index %N (out of bounds for %d-element array)", n->right, t->bound);
else if(isconst(n->left, CTSTR) && mpgetfix(n->right->val.u.xval) >= n->left->val.u.sval->len)
else if(isconst(n->left, CTSTR) && x >= n->left->val.u.sval->len)
yyerror("invalid string index %N (out of bounds for %d-byte string)", n->right, n->left->val.u.sval->len);
else if(mpcmpfixfix(n->right->val.u.xval, maxintval[TINT]) > 0)
yyerror("invalid %s index %N (index too large)", why, n->right);
@ -996,9 +1001,9 @@ reswitch:
yyerror("cannot slice %N (type %T)", l, t);
goto error;
}
if((lo = n->right->left) != N && checksliceindex(lo, tp) < 0)
if((lo = n->right->left) != N && checksliceindex(l, lo, tp) < 0)
goto error;
if((hi = n->right->right) != N && checksliceindex(hi, tp) < 0)
if((hi = n->right->right) != N && checksliceindex(l, hi, tp) < 0)
goto error;
if(checksliceconst(lo, hi) < 0)
goto error;
@ -1045,11 +1050,11 @@ reswitch:
yyerror("cannot slice %N (type %T)", l, t);
goto error;
}
if((lo = n->right->left) != N && checksliceindex(lo, tp) < 0)
if((lo = n->right->left) != N && checksliceindex(l, lo, tp) < 0)
goto error;
if((mid = n->right->right->left) != N && checksliceindex(mid, tp) < 0)
if((mid = n->right->right->left) != N && checksliceindex(l, mid, tp) < 0)
goto error;
if((hi = n->right->right->right) != N && checksliceindex(hi, tp) < 0)
if((hi = n->right->right->right) != N && checksliceindex(l, hi, tp) < 0)
goto error;
if(checksliceconst(lo, hi) < 0 || checksliceconst(lo, mid) < 0 || checksliceconst(mid, hi) < 0)
goto error;
@ -1819,7 +1824,7 @@ out:
}
static int
checksliceindex(Node *r, Type *tp)
checksliceindex(Node *l, Node *r, Type *tp)
{
Type *t;
@ -1836,6 +1841,9 @@ checksliceindex(Node *r, Type *tp)
} else if(tp != nil && tp->bound > 0 && mpgetfix(r->val.u.xval) > tp->bound) {
yyerror("invalid slice index %N (out of bounds for %d-element array)", r, tp->bound);
return -1;
} else if(isconst(l, CTSTR) && mpgetfix(r->val.u.xval) > l->val.u.sval->len) {
yyerror("invalid slice index %N (out of bounds for %d-byte string)", r, l->val.u.sval->len);
return -1;
} else if(mpcmpfixfix(r->val.u.xval, maxintval[TINT]) > 0) {
yyerror("invalid slice index %N (index too large)", r);
return -1;
@ -2116,18 +2124,19 @@ lookdot(Node *n, Type *t, int dostrcmp)
if(!eqtype(rcvr, tt)) {
if(rcvr->etype == tptr && eqtype(rcvr->type, tt)) {
checklvalue(n->left, "call pointer method on");
if(debug['N'])
addrescapes(n->left);
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);
@ -2808,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,
@ -2845,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

View file

@ -8,6 +8,8 @@
#include "../ld/textflag.h"
static Node* walkprint(Node*, NodeList**, int);
static Node* writebarrierfn(char*, Type*, Type*);
static Node* applywritebarrier(Node*, NodeList**);
static Node* mapfn(char*, Type*);
static Node* mapfndel(char*, Type*);
static Node* ascompatee1(int, Node*, Node*, NodeList**);
@ -135,6 +137,8 @@ walkstmt(Node **np)
n = *np;
if(n == N)
return;
if(n->dodata == 2) // don't walk, generated by anylit.
return;
setlineno(n);
@ -633,6 +637,7 @@ walkexpr(Node **np, NodeList **init)
r = convas(nod(OAS, n->left, n->right), init);
r->dodata = n->dodata;
n = r;
n = applywritebarrier(n, init);
}
goto ret;
@ -644,6 +649,8 @@ walkexpr(Node **np, NodeList **init)
walkexprlistsafe(n->rlist, init);
ll = ascompatee(OAS, n->list, n->rlist, init);
ll = reorder3(ll);
for(lr = ll; lr != nil; lr = lr->next)
lr->n = applywritebarrier(lr->n, init);
n = liststmt(ll);
goto ret;
@ -656,6 +663,8 @@ walkexpr(Node **np, NodeList **init)
walkexpr(&r, init);
ll = ascompatet(n->op, n->list, &r->type, 0, init);
for(lr = ll; lr != nil; lr = lr->next)
lr->n = applywritebarrier(lr->n, init);
n = liststmt(concat(list1(r), ll));
goto ret;
@ -1381,7 +1390,12 @@ walkexpr(Node **np, NodeList **init)
case OMAPLIT:
case OSTRUCTLIT:
case OPTRLIT:
// XXX TODO do we need to clear var?
// NOTE(rsc): Race detector cannot handle seeing
// a STRUCTLIT or ARRAYLIT representing a zero value,
// so make a temporary for those always in race mode.
// Otherwise, leave zero values in place.
if(iszero(n) && !flag_race)
goto ret;
var = temp(n->type);
anylit(0, n, var, init);
n = var;
@ -1481,8 +1495,13 @@ ascompatee(int op, NodeList *nl, NodeList *nr, NodeList **init)
static int
fncall(Node *l, Type *rt)
{
Node r;
if(l->ullman >= UINF || l->op == OINDEXMAP)
return 1;
memset(&r, 0, sizeof r);
if(needwritebarrier(l, &r))
return 1;
if(eqtype(l->type, rt))
return 0;
return 1;
@ -1533,8 +1552,10 @@ ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init)
a = nod(OAS, l, nodarg(r, fp));
a = convas(a, init);
ullmancalc(a);
if(a->ullman >= UINF)
if(a->ullman >= UINF) {
dump("ascompatet ucount", a);
ucount++;
}
nn = list(nn, a);
r = structnext(&saver);
}
@ -1932,6 +1953,161 @@ callnew(Type *t)
return mkcall1(fn, ptrto(t), nil, typename(t));
}
static int
isstack(Node *n)
{
while(n->op == ODOT || n->op == OPAREN || n->op == OCONVNOP || n->op == OINDEX && isfixedarray(n->left->type))
n = n->left;
switch(n->op) {
case OINDREG:
// OINDREG only ends up in walk if it's indirect of SP.
return 1;
case ONAME:
switch(n->class) {
case PAUTO:
case PPARAM:
case PPARAMOUT:
return 1;
}
break;
}
return 0;
}
static int
isglobal(Node *n)
{
while(n->op == ODOT || n->op == OPAREN || n->op == OCONVNOP || n->op == OINDEX && isfixedarray(n->left->type))
n = n->left;
switch(n->op) {
case ONAME:
switch(n->class) {
case PEXTERN:
return 1;
}
break;
}
return 0;
}
// Do we need a write barrier for the assignment l = r?
int
needwritebarrier(Node *l, Node *r)
{
if(!use_writebarrier)
return 0;
if(l == N || isblank(l))
return 0;
// No write barrier for write of non-pointers.
dowidth(l->type);
if(!haspointers(l->type))
return 0;
// No write barrier for write to stack.
if(isstack(l))
return 0;
// No write barrier for implicit or explicit zeroing.
if(r == N || iszero(r))
return 0;
// No write barrier for initialization to constant.
if(r->op == OLITERAL)
return 0;
// No write barrier for storing static (read-only) data.
if(r->op == ONAME && strncmp(r->sym->name, "statictmp_", 10) == 0)
return 0;
// No write barrier for storing address of stack values,
// which are guaranteed only to be written to the stack.
if(r->op == OADDR && isstack(r->left))
return 0;
// No write barrier for storing address of global, which
// is live no matter what.
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;
}
// TODO(rsc): Perhaps componentgen should run before this.
static Node*
applywritebarrier(Node *n, NodeList **init)
{
Node *l, *r;
Type *t;
if(n->left && n->right && needwritebarrier(n->left, n->right)) {
t = n->left->type;
l = nod(OADDR, n->left, N);
l->etype = 1; // addr does not escape
if(t->width == widthptr) {
n = mkcall1(writebarrierfn("writebarrierptr", t, n->right->type), T, init,
l, n->right);
} else if(t->etype == TSTRING) {
n = mkcall1(writebarrierfn("writebarrierstring", t, n->right->type), T, init,
l, n->right);
} else if(isslice(t)) {
n = mkcall1(writebarrierfn("writebarrierslice", t, n->right->type), T, init,
l, n->right);
} else if(isinter(t)) {
n = mkcall1(writebarrierfn("writebarrieriface", t, n->right->type), T, init,
l, n->right);
} else if(t->width == 2*widthptr) {
n = mkcall1(writebarrierfn("writebarrierfat2", t, n->right->type), T, init,
l, nodnil(), n->right);
} else if(t->width == 3*widthptr) {
n = mkcall1(writebarrierfn("writebarrierfat3", t, n->right->type), T, init,
l, nodnil(), n->right);
} else if(t->width == 4*widthptr) {
n = mkcall1(writebarrierfn("writebarrierfat4", t, n->right->type), T, init,
l, nodnil(), n->right);
} else {
r = n->right;
while(r->op == OCONVNOP)
r = r->left;
r = nod(OADDR, r, N);
r->etype = 1; // addr does not escape
//warnl(n->lineno, "writebarrierfat %T %N", t, r);
n = mkcall1(writebarrierfn("writebarrierfat", t, r->left->type), T, init,
typename(t), l, r);
}
}
return n;
}
static Node*
convas(Node *n, NodeList **init)
{
@ -1971,11 +2147,10 @@ convas(Node *n, NodeList **init)
goto out;
}
if(eqtype(lt, rt))
goto out;
n->right = assignconv(n->right, lt, "assignment");
walkexpr(&n->right, init);
if(!eqtype(lt, rt)) {
n->right = assignconv(n->right, lt, "assignment");
walkexpr(&n->right, init);
}
out:
ullmancalc(n);
@ -2369,7 +2544,7 @@ paramstoheap(Type **argin, int out)
// generate allocation & copying code
if(compiling_runtime)
fatal("%N escapes to heap, not allowed in runtime.", v);
yyerror("%N escapes to heap, not allowed in runtime.", v);
if(v->alloc == nil)
v->alloc = callnew(v->type);
nn = list(nn, nod(OAS, v->heapaddr, v->alloc));
@ -2526,6 +2701,17 @@ mapfndel(char *name, Type *t)
return fn;
}
static Node*
writebarrierfn(char *name, Type *l, Type *r)
{
Node *fn;
fn = syslook(name, 1);
argtype(fn, l);
argtype(fn, r);
return fn;
}
static Node*
addstr(Node *n, NodeList **init)
{

File diff suppressed because it is too large Load diff

View file

@ -57,6 +57,7 @@ and test commands:
-a
force rebuilding of packages that are already up-to-date.
In Go releases, does not apply to the standard library.
-n
print the commands but do not run them.
-p n
@ -284,6 +285,11 @@ func runBuild(cmd *Command, args []string) {
}
}
depMode := modeBuild
if buildI {
depMode = modeInstall
}
if *buildO != "" {
if len(pkgs) > 1 {
fatalf("go build: cannot use -o with multiple packages")
@ -292,17 +298,13 @@ func runBuild(cmd *Command, args []string) {
}
p := pkgs[0]
p.target = "" // must build - not up to date
a := b.action(modeInstall, modeBuild, p)
a := b.action(modeInstall, depMode, p)
a.target = *buildO
b.do(a)
return
}
a := &action{}
depMode := modeBuild
if buildI {
depMode = modeInstall
}
for _, p := range packages(args) {
a.deps = append(a.deps, b.action(modeBuild, depMode, p))
}
@ -504,8 +506,13 @@ func goFilesPackage(gofiles []string) *Package {
}
ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil }
if !filepath.IsAbs(dir) {
dir = filepath.Join(cwd, dir)
var err error
if dir == "" {
dir = cwd
}
dir, err = filepath.Abs(dir)
if err != nil {
fatalf("%s", err)
}
bp, err := ctxt.ImportDir(dir, 0)
@ -824,12 +831,17 @@ func (b *builder) build(a *action) (err error) {
}
}
var gofiles, cfiles, sfiles, objects, cgoObjects []string
var gofiles, cfiles, sfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string
gofiles = append(gofiles, a.p.GoFiles...)
cfiles = append(cfiles, a.p.CFiles...)
sfiles = append(sfiles, a.p.SFiles...)
if a.p.usesCgo() || a.p.usesSwig() {
if pcCFLAGS, pcLDFLAGS, err = b.getPkgConfigFlags(a.p); err != nil {
return
}
}
// Run cgo.
if a.p.usesCgo() {
// In a package using cgo, cgo compiles the C, C++ and assembly files with gcc.
@ -860,7 +872,7 @@ func (b *builder) build(a *action) (err error) {
if a.cgo != nil && a.cgo.target != "" {
cgoExe = a.cgo.target
}
outGo, outObj, err := b.cgo(a.p, cgoExe, obj, gccfiles, a.p.CXXFiles, a.p.MFiles)
outGo, outObj, err := b.cgo(a.p, cgoExe, obj, pcCFLAGS, pcLDFLAGS, gccfiles, a.p.CXXFiles, a.p.MFiles)
if err != nil {
return err
}
@ -873,9 +885,18 @@ func (b *builder) build(a *action) (err error) {
// In a package using SWIG, any .c or .s files are
// compiled with gcc.
gccfiles := append(cfiles, sfiles...)
cxxfiles, mfiles := a.p.CXXFiles, a.p.MFiles
cfiles = nil
sfiles = nil
outGo, outObj, err := b.swig(a.p, obj, gccfiles, a.p.CXXFiles, a.p.MFiles)
// Don't build c/c++ files twice if cgo is enabled (mainly for pkg-config).
if a.p.usesCgo() {
cxxfiles = nil
gccfiles = nil
mfiles = nil
}
outGo, outObj, err := b.swig(a.p, obj, pcCFLAGS, gccfiles, cxxfiles, mfiles)
if err != nil {
return err
}
@ -1019,6 +1040,34 @@ func (b *builder) build(a *action) (err error) {
return nil
}
// Calls pkg-config if needed and returns the cflags/ldflags needed to build the package.
func (b *builder) getPkgConfigFlags(p *Package) (cflags, ldflags []string, err error) {
if pkgs := p.CgoPkgConfig; len(pkgs) > 0 {
var out []byte
out, err = b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--cflags", pkgs)
if err != nil {
b.showOutput(p.Dir, "pkg-config --cflags "+strings.Join(pkgs, " "), string(out))
b.print(err.Error() + "\n")
err = errPrintedOutput
return
}
if len(out) > 0 {
cflags = strings.Fields(string(out))
}
out, err = b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--libs", pkgs)
if err != nil {
b.showOutput(p.Dir, "pkg-config --libs "+strings.Join(pkgs, " "), string(out))
b.print(err.Error() + "\n")
err = errPrintedOutput
return
}
if len(out) > 0 {
ldflags = strings.Fields(string(out))
}
}
return
}
// install is the action for installing a single package or executable.
func (b *builder) install(a *action) (err error) {
defer func() {
@ -1426,6 +1475,14 @@ func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...inter
continue
}
// err can be something like 'exit status 1'.
// Add information about what program was running.
// Note that if buf.Bytes() is non-empty, the caller usually
// shows buf.Bytes() and does not print err at all, so the
// prefix here does not make most output any more verbose.
if err != nil {
err = errors.New(cmdline[0] + ": " + err.Error())
}
return buf.Bytes(), err
}
}
@ -1588,7 +1645,7 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []
extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.MFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles)
if p.Standard {
switch p.ImportPath {
case "os", "runtime/pprof", "sync", "time":
case "bytes", "net", "os", "runtime/pprof", "sync", "time":
extFiles++
}
}
@ -1795,7 +1852,7 @@ func (gccgoToolchain) linker() string {
}
func (gccgoToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
out := p.Name + ".o"
out := "_go_.o"
ofile = obj + out
gcargs := []string{"-g"}
gcargs = append(gcargs, b.gccArchArgs()...)
@ -2100,36 +2157,16 @@ var (
cgoLibGccFileOnce sync.Once
)
func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) {
func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) {
cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoLDFLAGS := b.cflags(p, true)
_, cgoexeCFLAGS, _, _ := b.cflags(p, false)
cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...)
cgoLDFLAGS = append(cgoLDFLAGS, pcLDFLAGS...)
// If we are compiling Objective-C code, then we need to link against libobjc
if len(mfiles) > 0 {
cgoLDFLAGS = append(cgoLDFLAGS, "-lobjc")
}
if pkgs := p.CgoPkgConfig; len(pkgs) > 0 {
out, err := b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--cflags", pkgs)
if err != nil {
b.showOutput(p.Dir, "pkg-config --cflags "+strings.Join(pkgs, " "), string(out))
b.print(err.Error() + "\n")
return nil, nil, errPrintedOutput
}
if len(out) > 0 {
cgoCPPFLAGS = append(cgoCPPFLAGS, strings.Fields(string(out))...)
}
out, err = b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--libs", pkgs)
if err != nil {
b.showOutput(p.Dir, "pkg-config --libs "+strings.Join(pkgs, " "), string(out))
b.print(err.Error() + "\n")
return nil, nil, errPrintedOutput
}
if len(out) > 0 {
cgoLDFLAGS = append(cgoLDFLAGS, strings.Fields(string(out))...)
}
}
// Allows including _cgo_export.h from .[ch] files in the package.
cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", obj)
@ -2206,6 +2243,14 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles
strings.HasSuffix(f, ".so"),
strings.HasSuffix(f, ".dll"):
continue
// Remove any -fsanitize=foo flags.
// Otherwise the compiler driver thinks that we are doing final link
// and links sanitizer runtime into the object file. But we are not doing
// the final link, we will link the resulting object file again. And
// so the program ends up with two copies of sanitizer runtime.
// See issue 8788 for details.
case strings.HasPrefix(f, "-fsanitize="):
continue
default:
bareLDFLAGS = append(bareLDFLAGS, f)
}
@ -2344,7 +2389,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles
// Run SWIG on all SWIG input files.
// TODO: Don't build a shared library, once SWIG emits the necessary
// pragmas for external linking.
func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) {
func (b *builder) swig(p *Package, obj string, pcCFLAGS, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) {
cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true)
cflags := stringList(cgoCPPFLAGS, cgoCFLAGS)
cxxflags := stringList(cgoCPPFLAGS, cgoCXXFLAGS)
@ -2385,7 +2430,7 @@ func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles, mfiles []stri
}
for _, f := range p.SwigFiles {
goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, false, intgosize)
goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, pcCFLAGS, false, intgosize)
if err != nil {
return nil, nil, err
}
@ -2400,7 +2445,7 @@ func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles, mfiles []stri
}
}
for _, f := range p.SwigCXXFiles {
goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, true, intgosize)
goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, pcCFLAGS, true, intgosize)
if err != nil {
return nil, nil, err
}
@ -2479,13 +2524,13 @@ func (b *builder) swigIntSize(obj string) (intsize string, err error) {
}
// Run SWIG on one SWIG input file.
func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize string) (outGo, outObj, objGccObj string, err error) {
func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx bool, intgosize string) (outGo, outObj, objGccObj string, err error) {
cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true)
var cflags []string
if cxx {
cflags = stringList(cgoCPPFLAGS, cgoCXXFLAGS)
cflags = stringList(cgoCPPFLAGS, pcCFLAGS, cgoCXXFLAGS)
} else {
cflags = stringList(cgoCPPFLAGS, cgoCFLAGS)
cflags = stringList(cgoCPPFLAGS, pcCFLAGS, cgoCFLAGS)
}
n := 5 // length of ".swig"
@ -2511,6 +2556,13 @@ func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize stri
"-o", obj + gccBase + gccExt,
"-outdir", obj,
}
for _, f := range cflags {
if len(f) > 3 && f[:2] == "-I" {
args = append(args, f)
}
}
if gccgo {
args = append(args, "-gccgo")
if pkgpath := gccgoPkgpath(p); pkgpath != "" {

View file

@ -76,6 +76,7 @@ and test commands:
-a
force rebuilding of packages that are already up-to-date.
In Go releases, does not apply to the standard library.
-n
print the commands but do not run them.
-p n
@ -384,28 +385,29 @@ syntax of package template. The default output is equivalent to -f
'{{.ImportPath}}'. The struct being passed to the template is:
type Package struct {
Dir string // directory containing package sources
ImportPath string // import path of package in dir
Name string // package name
Doc string // package documentation string
Target string // install path
Goroot bool // is this package in the Go root?
Standard bool // is this package part of the standard Go library?
Stale bool // would 'go install' do anything for this package?
Root string // Go root or Go path dir containing this package
Dir string // directory containing package sources
ImportPath string // import path of package in dir
ImportComment string // path in import comment on package statement
Name string // package name
Doc string // package documentation string
Target string // install path
Goroot bool // is this package in the Go root?
Standard bool // is this package part of the standard Go library?
Stale bool // would 'go install' do anything for this package?
Root string // Go root or Go path dir containing this package
// Source files
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
CgoFiles []string // .go sources files that import "C"
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
CgoFiles []string // .go sources files that import "C"
IgnoredGoFiles []string // .go sources ignored due to build constraints
CFiles []string // .c source files
CXXFiles []string // .cc, .cxx and .cpp source files
MFiles []string // .m source files
HFiles []string // .h, .hh, .hpp and .hxx source files
SFiles []string // .s source files
SwigFiles []string // .swig files
SwigCXXFiles []string // .swigcxx files
SysoFiles []string // .syso object files to add to archive
CFiles []string // .c source files
CXXFiles []string // .cc, .cxx and .cpp source files
MFiles []string // .m source files
HFiles []string // .h, .hh, .hpp and .hxx source files
SFiles []string // .s source files
SwigFiles []string // .swig files
SwigCXXFiles []string // .swigcxx files
SysoFiles []string // .syso object files to add to archive
// Cgo directives
CgoCFLAGS []string // cgo: flags for C compiler
@ -524,16 +526,23 @@ non-test installation.
In addition to the build flags, the flags handled by 'go test' itself are:
-c Compile the test binary to pkg.test but do not run it.
(Where pkg is the last element of the package's import path.)
-c
Compile the test binary to pkg.test but do not run it
(where pkg is the last element of the package's import path).
The file name can be changed with the -o flag.
-exec xprog
Run the test binary using xprog. The behavior is the same as
in 'go run'. See 'go help run' for details.
-i
Install packages that are dependencies of the test.
Do not run the test.
-exec xprog
Run the test binary using xprog. The behavior is the same as
in 'go run'. See 'go help run' for details.
-o file
Compile the test binary to the named file.
The test still runs (unless -c or -i is specified).
The test binary also accepts flags that control execution of the test; these
flags are also accessible by 'go test'. See 'go help testflag' for details.
@ -910,7 +919,8 @@ single directory, the command is applied to a single synthesized
package made up of exactly those files, ignoring any build constraints
in those files and ignoring any other files in the directory.
File names that begin with "." or "_" are ignored by the go tool.
Directory and file names that begin with "." or "_" are ignored
by the go tool, as are directories named "testdata".
Description of testing flags
@ -942,6 +952,7 @@ control the execution of any test:
-blockprofile block.out
Write a goroutine blocking profile to the specified file
when all tests are complete.
Writes test binary as -c would.
-blockprofilerate n
Control the detail provided in goroutine blocking profiles by
@ -973,8 +984,7 @@ control the execution of any test:
Sets -cover.
-coverprofile cover.out
Write a coverage profile to the specified file after all tests
have passed.
Write a coverage profile to the file after all tests have passed.
Sets -cover.
-cpu 1,2,4
@ -984,10 +994,11 @@ control the execution of any test:
-cpuprofile cpu.out
Write a CPU profile to the specified file before exiting.
Writes test binary as -c would.
-memprofile mem.out
Write a memory profile to the specified file after all tests
have passed.
Write a memory profile to the file after all tests have passed.
Writes test binary as -c would.
-memprofilerate n
Enable more precise (and expensive) memory profiles by setting

Some files were not shown because too many files have changed in this diff Show more