mirror of
https://github.com/golang/go
synced 2024-10-14 03:43:28 +00:00
[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:
commit
f0bd539c59
|
@ -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
|
||||
|
|
4
.hgtags
4
.hgtags
|
@ -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
|
||||
|
|
9
AUTHORS
9
AUTHORS
|
@ -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>
|
||||
|
|
16
CONTRIBUTORS
16
CONTRIBUTORS
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>.
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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—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—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">
|
||||
|
|
274
doc/go_spec.html
274
doc/go_spec.html
|
@ -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—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 = &Point3D{y: 1000}
|
||||
|
@ -3604,7 +3677,7 @@ then the evaluation of <code>&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 &^= 1<<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
BIN
doc/gopher/biplane.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 199 KiB |
|
@ -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>
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) }
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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
103
misc/cgo/test/issue7978.go
Normal 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)
|
||||
}
|
13
misc/cgo/test/issue8517.go
Normal file
13
misc/cgo/test/issue8517.go
Normal 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")
|
||||
}
|
24
misc/cgo/test/issue8517_windows.c
Normal file
24
misc/cgo/test/issue8517_windows.c
Normal 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);
|
||||
}
|
45
misc/cgo/test/issue8517_windows.go
Normal file
45
misc/cgo/test/issue8517_windows.go
Normal 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++
|
||||
}
|
32
misc/cgo/test/issue8694.go
Normal file
32
misc/cgo/test/issue8694.go
Normal 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)
|
||||
}
|
||||
}
|
|
@ -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() {
|
||||
}
|
22
misc/cgo/test/issue8811.go
Normal file
22
misc/cgo/test/issue8811.go
Normal 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()
|
||||
}
|
16
misc/cgo/test/issue8828.go
Normal file
16
misc/cgo/test/issue8828.go
Normal 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()
|
||||
}
|
7
misc/cgo/test/issue8828/issue8828.c
Normal file
7
misc/cgo/test/issue8828/issue8828.c
Normal 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()
|
||||
{
|
||||
}
|
8
misc/cgo/test/issue8828/trivial.go
Normal file
8
misc/cgo/test/issue8828/trivial.go
Normal file
|
@ -0,0 +1,8 @@
|
|||
package issue8828
|
||||
|
||||
//void foo();
|
||||
import "C"
|
||||
|
||||
func Bar() {
|
||||
C.foo()
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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='*'
|
||||
|
|
|
@ -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
|
||||
--------------------
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
|
@ -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);
|
||||
|
|
|
@ -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]--;
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -109,7 +109,6 @@ void split64(Node*, Node*, Node*);
|
|||
void splitclean(void);
|
||||
Node* ncon(uint32 i);
|
||||
void gtrack(Sym*);
|
||||
void gargsize(int32);
|
||||
|
||||
/*
|
||||
* obj.c
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -114,7 +114,6 @@ void split64(Node*, Node*, Node*);
|
|||
void splitclean(void);
|
||||
void nswap(Node*, Node*);
|
||||
void gtrack(Sym*);
|
||||
void gargsize(int32);
|
||||
/*
|
||||
* cplx.c
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
||||
/*
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
1149
src/cmd/cc/y.tab.c
1149
src/cmd/cc/y.tab.c
File diff suppressed because it is too large
Load diff
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
2
src/cmd/dist/build.c
vendored
2
src/cmd/dist/build.c
vendored
|
@ -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.
|
||||
|
|
10
src/cmd/dist/buildruntime.c
vendored
10
src/cmd/dist/buildruntime.c
vendored
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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++;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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*);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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 != "" {
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue