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

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

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

View File

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

View File

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

View File

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

View File

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

View File

@ -27,6 +27,16 @@ go1.3.1 (released 2014/08/13) includes bug fixes to the compiler and the <code>r
See the <a href="//code.google.com/p/go/source/list?name=release-branch.go1.3&r=073fc578434bf3e1e22749b559d273c8da728ebb">change history</a> for details. 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>
<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> <h2 id="go1.2">go1.2 (released 2013/12/01)</h2>
<p> <p>

View File

@ -13,23 +13,39 @@ cmd/6l, liblink: use pc-relative addressing for all memory references, so that l
cmd/go: import comments (CL 124940043) cmd/go: import comments (CL 124940043)
cmd/go: implement "internal" (CL 120600043) cmd/go: implement "internal" (CL 120600043)
cmd/go: implement "generate" (CL 125580044) 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) 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: add support for ALPN (RFC 7301) (CL 108710046)
crypto/tls: support programmatic selection of server certificates (CL 107400043) 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) encoding/gob: remove unsafe (CL 102680045)
misc: deleted editor support; refer to https://code.google.com/p/go-wiki/wiki/IDEsAndTextEditorPlugins instead (CL 105470043) 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 Request.BasicAuth method (CL 76540043)
net/http: add Transport.DialTLS hook (CL 137940043) net/http: add Transport.DialTLS hook (CL 137940043)
net/http/httputil: add ReverseProxy.ErrorLog (CL 132750043) net/http/httputil: add ReverseProxy.ErrorLog (CL 132750043)
os: implement symlink support for windows (CL 86160044) os: implement symlink support for windows (CL 86160044)
reflect: add type.Comparable (CL 144020043)
runtime: implement monotonic clocks on windows (CL 108700045) 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) runtime/race: freebsd is supported (CL 107270043)
swig: Due to runtime changes Go 1.4 will require SWIG 3.0.3 (not yet released)
sync/atomic: add Value (CL 136710045)
syscall: Setuid, Setgid are disabled on linux platforms. On linux those syscalls operate on the calling thread, not the whole process. This does not match the semantics of other platforms, nor the expectations of the caller, so the operations have been disabled until issue 1435 is resolved (CL 106170043) syscall: 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 Coverage (CL 98150043)
testing: add TestMain support (CL 148770043)
text/scanner: add IsIdentRune field of Scanner. (CL 108030044) 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) 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 go.sys subrepo created: http://golang.org/s/go1.4-syscall

View File

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

View File

@ -83,16 +83,16 @@ break if the bug is fixed. We reserve the right to fix such bugs.
<li> <li>
Struct literals. For the addition of features in later point Struct literals. For the addition of features in later point
releases, it may be necessary to add fields to exported structs in 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 "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 3, B: "x"}) will continue to compile after such a change. We will
update such data structures in a way that allows tagged struct update such data structures in a way that allows keyed struct
literals to remain compatible, although untagged literals may fail literals to remain compatible, although unkeyed literals may fail
to compile. (There are also more intricate cases involving nested to compile. (There are also more intricate cases involving nested
data structures or interfaces, but they have the same resolution.) data structures or interfaces, but they have the same resolution.)
We therefore recommend that composite literals whose type is defined 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>
<li> <li>

View File

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

View File

@ -1,6 +1,6 @@
<!--{ <!--{
"Title": "The Go Programming Language Specification", "Title": "The Go Programming Language Specification",
"Subtitle": "Version of August 28, 2014", "Subtitle": "Version of October 16, 2014",
"Path": "/ref/spec" "Path": "/ref/spec"
}--> }-->
@ -577,7 +577,7 @@ Numeric constants represent values of arbitrary precision and do not overflow.
</p> </p>
<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>, Literal constants, <code>true</code>, <code>false</code>, <code>iota</code>,
and certain <a href="#Constant_expressions">constant expressions</a> and certain <a href="#Constant_expressions">constant expressions</a>
containing only untyped constant operands are untyped. 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>. not <code>int32</code> or <code>string</code>.
</p> </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> <p>
There are no constants denoting the IEEE-754 infinity and not-a-number values, 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 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>. expressions</a>.
</p> </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> <h2 id="Types">Types</h2>
<p> <p>
@ -661,17 +731,6 @@ interface, slice, map, and channel types&mdash;may be constructed using
type literals. type literals.
</p> </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> <p>
Each type <code>T</code> has an <i>underlying type</i>: If <code>T</code> 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, 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> <h3 id="Pointer_types">Pointer types</h3>
<p> <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. type, called the <i>base type</i> of the pointer.
The value of an uninitialized pointer is <code>nil</code>. The value of an uninitialized pointer is <code>nil</code>.
</p> </p>
@ -1154,11 +1213,11 @@ interface{}
<p> <p>
Similarly, consider this interface specification, Similarly, consider this interface specification,
which appears within a <a href="#Type_declarations">type declaration</a> 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> </p>
<pre> <pre>
type Lock interface { type Locker interface {
Lock() Lock()
Unlock() Unlock()
} }
@ -1174,28 +1233,35 @@ func (p T) Unlock() { … }
</pre> </pre>
<p> <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. as the <code>File</code> interface.
</p> </p>
<p> <p>
An interface may use an interface type name <code>T</code> An interface <code>T</code> may use a (possibly qualified) interface type
in place of a method specification. name <code>E</code> in place of a method specification. This is called
The effect, called embedding an interface, <i>embedding</i> interface <code>E</code> in <code>T</code>; it adds
is equivalent to enumerating the methods of <code>T</code> explicitly all (exported and non-exported) methods of <code>E</code> to the interface
in the interface. <code>T</code>.
</p> </p>
<pre> <pre>
type ReadWrite interface { type ReadWriter interface {
Read(b Buffer) bool Read(b Buffer) bool
Write(b Buffer) bool Write(b Buffer) bool
} }
type File interface { type File interface {
ReadWrite // same as enumerating the methods in ReadWrite ReadWriter // same as adding the methods of ReadWriter
Lock // same as enumerating the methods in Lock Locker // same as adding the methods of Locker
Close() Close()
} }
type LockedFile interface {
Locker
File // illegal: Lock, Unlock not unique
Lock() // illegal: Lock not unique
}
</pre> </pre>
<p> <p>
@ -1443,7 +1509,7 @@ is different from <code>[]string</code>.
<h3 id="Assignability">Assignability</h3> <h3 id="Assignability">Assignability</h3>
<p> <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: ("<code>x</code> is assignable to <code>T</code>") in any of these cases:
</p> </p>
@ -1875,9 +1941,10 @@ func (tz TimeZone) String() string {
<h3 id="Variable_declarations">Variable declarations</h3> <h3 id="Variable_declarations">Variable declarations</h3>
<p> <p>
A variable declaration creates a variable, binds an identifier to it and A variable declaration creates one or more variables, binds corresponding
gives it a type and optionally an initial value. identifiers to them, and gives each a type and an initial value.
</p> </p>
<pre class="ebnf"> <pre class="ebnf">
VarDecl = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) . VarDecl = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) .
VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) . VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) .
@ -1898,22 +1965,27 @@ var _, found = entries[name] // map lookup; only interested in "found"
<p> <p>
If a list of expressions is given, the variables are initialized If a list of expressions is given, the variables are initialized
by <a href="#Assignments">assigning</a> the expressions to the variables with the expressions following the rules for <a href="#Assignments">assignments</a>.
in order; all expressions must be consumed and all variables initialized from them.
Otherwise, each variable is initialized to its <a href="#The_zero_value">zero value</a>. Otherwise, each variable is initialized to its <a href="#The_zero_value">zero value</a>.
</p> </p>
<p> <p>
If the type is present, each variable is given that type. If a type is present, each variable is given that type.
Otherwise, the types are deduced from the assignment Otherwise, each variable is given the type of the corresponding
of the expression list. 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>
<p> <pre>
If the type is absent and the corresponding expression evaluates to an var d = math.Sin(0.5) // d is int64
untyped <a href="#Constants">constant</a>, the type of the declared variable var i = 42 // i is int
is as described in §<a href="#Assignments">Assignments</a>. var t, ok = x.(T) // t is T, ok is bool
</p> var n = nil // illegal
</pre>
<p> <p>
Implementation restriction: A compiler may make it illegal to declare a variable 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> <p>
<a href="#Address_operators">Taking the address</a> of a composite literal <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> </p>
<pre> <pre>
var pointer *Point3D = &amp;Point3D{y: 1000} var pointer *Point3D = &amp;Point3D{y: 1000}
@ -3604,7 +3677,7 @@ then the evaluation of <code>&amp;x</code> does too.
<p> <p>
For an operand <code>x</code> of pointer type <code>*T</code>, the pointer 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>. to by <code>x</code>.
If <code>x</code> is <code>nil</code>, an attempt to evaluate <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>. will cause a <a href="#Run_time_panics">run-time panic</a>.
@ -4311,7 +4384,7 @@ a[i] = 23
<p> <p>
An <i>assignment operation</i> <code>x</code> <i>op</i><code>=</code> 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> to <code>x</code> <code>=</code> <code>x</code> <i>op</i>
<code>y</code> but evaluates <code>x</code> <code>y</code> but evaluates <code>x</code>
only once. The <i>op</i><code>=</code> construct is a single token. only once. The <i>op</i><code>=</code> construct is a single token.
@ -4329,8 +4402,8 @@ i &amp;^= 1&lt;&lt;n
A tuple assignment assigns the individual elements of a multi-valued A tuple assignment assigns the individual elements of a multi-valued
operation to a list of variables. There are two forms. In the operation to a list of variables. There are two forms. In the
first, the right hand operand is a single multi-valued expression first, the right hand operand is a single multi-valued expression
such as a function evaluation or <a href="#Channel_types">channel</a> or 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>. <a href="#Map_types">map</a> operation, or a <a href="#Type_assertions">type assertion</a>.
The number of operands on the left The number of operands on the left
hand side must match the number of values. For instance, if hand side must match the number of values. For instance, if
<code>f</code> is a function returning two values, <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> </p>
<ol> <ol>
<li><p> <li>
If an untyped <a href="#Constants">constant</a> Any typed value may be assigned to the blank identifier.
is assigned to a variable of interface type or the blank identifier, </li>
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><p> <li>
<!-- Note that the result of a comparison is an untyped bool that may not be constant. --> If an untyped constant
If a left-hand side is the blank identifier, any typed or non-constant is assigned to a variable of interface type or the blank identifier,
value except for the predeclared identifier the constant is first <a href="#Conversions">converted</a> to its
<a href="#Predeclared_identifiers"><code>nil</code></a> <a href="#Constants">default type</a>.
may be assigned to it. </li>
</p></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> </ol>
<h3 id="If_statements">If statements</h3> <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, and a <i>post</i> statement, such as an assignment,
an increment or decrement statement. The init statement may be a 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. <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> </p>
<pre class="ebnf"> <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> <a href="#Short_variable_declarations">short variable declaration</a>
(<code>:=</code>). (<code>:=</code>).
In this case their types are set to the types of the respective iteration values 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. statement; they are re-used in each iteration.
If the iteration variables are declared outside the "for" statement, If the iteration variables are declared outside the "for" statement,
after execution their values will be those of the last iteration. 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>
<p> <p>
Each time the "defer" statement Each time a "defer" statement
executes, the function value and parameters to the call are executes, the function value and parameters to the call are
<a href="#Calls">evaluated as usual</a> <a href="#Calls">evaluated as usual</a>
and saved anew but the actual function body is not executed. and saved anew but the actual function is not invoked.
Instead, deferred functions are executed immediately before Instead, deferred functions are invoked immediately before
the surrounding function returns, in the reverse order the surrounding function returns, in the reverse order
they were deferred. 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>
<p> <p>
@ -5379,9 +5454,11 @@ var z complex128
<h3 id="Allocation">Allocation</h3> <h3 id="Allocation">Allocation</h3>
<p> <p>
The built-in function <code>new</code> takes a type <code>T</code> and The built-in function <code>new</code> takes a type <code>T</code>,
returns a value of type <code>*T</code>. allocates storage for a <a href="#Variables">variable</a> of that type
The memory is initialized as described in the section on 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>. <a href="#The_zero_value">initial values</a>.
</p> </p>
@ -5399,10 +5476,10 @@ new(S)
</pre> </pre>
<p> <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>), initializes it (<code>a=0</code>, <code>b=0.0</code>),
and returns a value of type <code>*S</code> containing the address and returns a value of type <code>*S</code> containing the address
of the memory. of the location.
</p> </p>
<h3 id="Making_slices_maps_and_channels">Making slices, maps and channels</h3> <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> <h3 id="The_zero_value">The zero value</h3>
<p> <p>
When memory is allocated to store a value, either through a declaration When storage is allocated for a <a href="#Variables">variable</a>,
or a call of <code>make</code> or <code>new</code>, either through a declaration or a call of <code>new</code>, or when
and no explicit initialization is provided, the memory is a new value is created, either through a composite literal or a call
given a default initialization. Each element of such a value is 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, 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> <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. for strings, and <code>nil</code> for pointers, functions, interfaces, slices, channels, and maps.
@ -5916,20 +5995,42 @@ var t T
</pre> </pre>
<h3 id="Package_initialization">Package initialization</h3> <h3 id="Package_initialization">Package initialization</h3>
<p> <p>
Within a package, package-level variables are initialized according Within a package, package-level variables are initialized in
to their <i>dependencies</i>: if a variable <code>x</code> depends on <i>declaration order</i> but after any of the variables
a variable <code>y</code>, <code>x</code> will be initialized after they <i>depend</i> on.
<code>y</code>. </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>
<p> <p>
Dependency analysis does not rely on the actual values of the Dependency analysis does not rely on the actual values of the
variables, only on lexical <i>references</i> to them in the source, variables, only on lexical <i>references</i> to them in the source,
analyzed transitively. For instance, a variable <code>x</code>'s analyzed transitively. For instance, if a variable <code>x</code>'s
<a href="#Variable_declarations">initialization expression</a> initialization expression refers to a function whose body refers to
may refer to a function whose body refers to variable <code>y</code>; variable <code>y</code> then <code>x</code> depends on <code>y</code>.
if so, <code>x</code> depends on <code>y</code>.
Specifically: Specifically:
</p> </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 Dependency analysis is performed per package; only references referring
to variables, functions, and methods declared in the current package to variables, functions, and methods declared in the current package
are considered. 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>
<p> <p>
@ -5989,8 +6085,6 @@ func f() int {
<p> <p>
the initialization order is <code>d</code>, <code>b</code>, <code>c</code>, <code>a</code>. 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>
<p> <p>
@ -6033,6 +6127,12 @@ the <code>init</code> functions: it will not invoke the next one
until the previous one has returned. until the previous one has returned.
</p> </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> <h3 id="Program_execution">Program execution</h3>
<p> <p>

BIN
doc/gopher/biplane.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 KiB

View File

@ -6,14 +6,14 @@
<h2 id="download">Download the Go distribution</h2> <h2 id="download">Download the Go distribution</h2>
<p> <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="big">Download Go</span>
<span class="desc">Click here to visit the downloads page</span> <span class="desc">Click here to visit the downloads page</span>
</a> </a>
</p> </p>
<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 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 and above), and Windows operating systems and the 32-bit (<code>386</code>) and
64-bit (<code>amd64</code>) x86 processor architectures. 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> <h3 id="tarball">Linux, Mac OS X, and FreeBSD tarballs</h3>
<p> <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 and extract it into <code>/usr/local</code>, creating a Go tree in
<code>/usr/local/go</code>. For example: <code>/usr/local/go</code>. For example:
</p> </p>
@ -127,7 +127,7 @@ location.
<h3 id="osx">Mac OS X package installer</h3> <h3 id="osx">Mac OS X package installer</h3>
<p> <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. open it, and follow the prompts to install the Go tools.
The package installs the Go distribution to <code>/usr/local/go</code>. The package installs the Go distribution to <code>/usr/local/go</code>.
</p> </p>
@ -150,7 +150,7 @@ MSI installer that configures your installation automatically.
<h4 id="windows_msi">MSI installer</h4> <h4 id="windows_msi">MSI installer</h4>
<p> <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. and follow the prompts to install the Go tools.
By default, the installer puts the Go distribution in <code>c:\Go</code>. By default, the installer puts the Go distribution in <code>c:\Go</code>.
</p> </p>
@ -164,7 +164,7 @@ command prompts for the change to take effect.
<h4 id="windows_zip">Zip archive</h4> <h4 id="windows_zip">Zip archive</h4>
<p> <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>
<p> <p>
@ -224,19 +224,12 @@ If you see the "hello, world" message then your Go installation is working.
<p> <p>
You're almost done. You're almost done.
You just need to do a little more setup. You just need to set up your environment.
</p> </p>
<p> <p>
<a href="/doc/code.html" class="download" id="writing"> Read the <a href="/doc/code.html">How to Write Go Code</a> document,
<span class="big">How to Write Go Code</span> which provides <b>essential setup instructions</b> for using the Go tools.
<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.
</p> </p>
@ -277,5 +270,3 @@ The official mailing list for discussion of the Go language is
Report bugs using the Report bugs using the
<a href="//golang.org/issue">Go issue tracker</a>. <a href="//golang.org/issue">Go issue tracker</a>.
</p> </p>

View File

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

View File

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

View File

@ -1,18 +0,0 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Expose some runtime functions for testing.
// Must be in a non-cgo-using package so that
// the go command compiles this file with 6c, not gcc.
// +build gc
typedef char bool;
// This is what a cgo-compiled stub declaration looks like.
void
·Issue7695(struct{void *y[8*sizeof(void*)];}p)
{
USED(p);
}

View File

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

View File

@ -9,6 +9,10 @@ void callback(void *f);
void callGoFoo(void); void callGoFoo(void);
void callGoStackCheck(void); void callGoStackCheck(void);
void callPanic(void); void callPanic(void);
void callCgoAllocate(void);
int callGoReturnVal(void);
int returnAfterGrow(void);
int returnAfterGrowFromGo(void);
*/ */
import "C" import "C"
@ -207,6 +211,52 @@ func testPanicFromC(t *testing.T) {
C.callPanic() 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) { func testCallbackStack(t *testing.T) {
// Make cgo call and callback with different amount of stack stack available. // 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. // We do not do any explicit checks, just ensure that it does not crash.

View File

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

View File

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

View File

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

View File

@ -23,6 +23,7 @@ func TestCallbackPanic(t *testing.T) { testCallbackPanic(t) }
func TestCallbackPanicLoop(t *testing.T) { testCallbackPanicLoop(t) } func TestCallbackPanicLoop(t *testing.T) { testCallbackPanicLoop(t) }
func TestCallbackPanicLocked(t *testing.T) { testCallbackPanicLocked(t) } func TestCallbackPanicLocked(t *testing.T) { testCallbackPanicLocked(t) }
func TestPanicFromC(t *testing.T) { testPanicFromC(t) } func TestPanicFromC(t *testing.T) { testPanicFromC(t) }
func TestAllocateFromC(t *testing.T) { testAllocateFromC(t) }
func TestZeroArgCallback(t *testing.T) { testZeroArgCallback(t) } func TestZeroArgCallback(t *testing.T) { testZeroArgCallback(t) }
func TestBlocking(t *testing.T) { testBlocking(t) } func TestBlocking(t *testing.T) { testBlocking(t) }
func Test1328(t *testing.T) { test1328(t) } func Test1328(t *testing.T) { test1328(t) }
@ -55,5 +56,11 @@ func TestNaming(t *testing.T) { testNaming(t) }
func Test7560(t *testing.T) { test7560(t) } func Test7560(t *testing.T) { test7560(t) }
func Test5242(t *testing.T) { test5242(t) } func Test5242(t *testing.T) { test5242(t) }
func Test8092(t *testing.T) { test8092(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) } func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }

View File

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

View File

@ -1,30 +0,0 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
// This test depends on running C code on Go stacks. Not allowed anymore.
// Demo of deferred C function with untrue prototype
// breaking stack copying. See golang.org/issue/7695.
package cgotest
import (
"testing"
"./backdoor"
)
func TestIssue7695(t *testing.T) {
defer backdoor.Issue7695(1, 0, 2, 0, 0, 3, 0, 4)
recurse(100)
}
func recurse(n int) {
var x [128]int
n += x[0]
if n > 0 {
recurse(n - 1)
}
}

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

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

View File

@ -0,0 +1,13 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !windows
package cgotest
import "testing"
func test8517(t *testing.T) {
t.Skip("skipping windows only test")
}

View File

@ -0,0 +1,24 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "windows.h"
extern void testHandleLeaksCallback();
DWORD WINAPI testHandleLeaksFunc(LPVOID lpThreadParameter)
{
int i;
for(i = 0; i < 100; i++) {
testHandleLeaksCallback();
}
return 0;
}
void testHandleLeaks()
{
HANDLE h;
h = CreateThread(NULL, 0, &testHandleLeaksFunc, 0, 0, NULL);
WaitForSingleObject(h, INFINITE);
CloseHandle(h);
}

View File

@ -0,0 +1,45 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package cgotest
//void testHandleLeaks();
import "C"
import (
"syscall"
"testing"
"unsafe"
)
var issue8517counter int
var (
kernel32 = syscall.MustLoadDLL("kernel32.dll")
getProcessHandleCount = kernel32.MustFindProc("GetProcessHandleCount")
)
func processHandleCount(t *testing.T) int {
const current_process = ^uintptr(0)
var c uint32
r, _, err := getProcessHandleCount.Call(current_process, uintptr(unsafe.Pointer(&c)))
if r == 0 {
t.Fatal(err)
}
return int(c)
}
func test8517(t *testing.T) {
c1 := processHandleCount(t)
C.testHandleLeaks()
c2 := processHandleCount(t)
if c1+issue8517counter <= c2 {
t.Fatalf("too many handles leaked: issue8517counter=%v c1=%v c2=%v", issue8517counter, c1, c2)
}
}
//export testHandleLeaksCallback
func testHandleLeaksCallback() {
issue8517counter++
}

View File

@ -0,0 +1,32 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package cgotest
/*
#include <complex.h>
complex float complexFloatSquared(complex float a) { return a*a; }
complex double complexDoubleSquared(complex double a) { return a*a; }
*/
import "C"
import "testing"
func test8694(t *testing.T) {
// Really just testing that this compiles, but check answer anyway.
x := complex64(2 + 3i)
x2 := x * x
cx2 := C.complexFloatSquared(x)
if cx2 != x2 {
t.Errorf("C.complexFloatSquared(%v) = %v, want %v", x, cx2, x2)
}
y := complex128(2 + 3i)
y2 := y * y
cy2 := C.complexDoubleSquared(y)
if cy2 != y2 {
t.Errorf("C.complexDoubleSquared(%v) = %v, want %v", y, cy2, y2)
}
}

View File

@ -2,10 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // 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 void issue8811Init() {
}
package backdoor
func Issue7695(x1, x2, x3, x4, x5, x6, x7, x8 uintptr) {}

View File

@ -0,0 +1,22 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package cgotest
/*
extern int issue8811Initialized;
extern void issue8811Init();
void issue8811Execute() {
if(!issue8811Initialized)
issue8811Init();
}
*/
import "C"
import "testing"
func test8811(t *testing.T) {
C.issue8811Execute()
}

View File

@ -0,0 +1,16 @@
// compile
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Issue 8828: compiling a file with -compiler=gccgo fails if a .c file
// has the same name as compiled directory.
package cgotest
import "./issue8828"
func p() {
issue8828.Bar()
}

View File

@ -0,0 +1,7 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
void foo()
{
}

View File

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

View File

@ -437,7 +437,8 @@ func (b *Build) Do() error {
// Build package. // Build package.
_, err = b.run(work, "candle", _, err = b.run(work, "candle",
"-nologo", "-nologo",
"-dVersion="+version, "-dGoVersion="+version,
"-dWixGoVersion="+wixVersion(version),
"-dArch="+b.Arch, "-dArch="+b.Arch,
"-dSourceDir=go", "-dSourceDir=go",
installer, appfiles) installer, appfiles)
@ -471,6 +472,22 @@ func (b *Build) Do() error {
return err 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, // extras fetches the go.tools, go.blog, and go-tour repositories,
// builds them and copies the resulting binaries and static assets // builds them and copies the resulting binaries and static assets
// to the new GOROOT. // to the new GOROOT.

View File

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

View File

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

View File

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

View File

@ -112,7 +112,9 @@ func (s *Scanner) Scan() bool {
// Loop until we have a token. // Loop until we have a token.
for { for {
// See if we can get a token with what we already have. // 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) advance, token, err := s.split(s.buf[s.start:s.end], s.err != nil)
if err != nil { if err != nil {
s.setErr(err) s.setErr(err)

View File

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

View File

@ -267,6 +267,8 @@ func Fields(s []byte) [][]byte {
// It splits the slice s at each run of code points c satisfying f(c) and // 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 // 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. // 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 { func FieldsFunc(s []byte, f func(rune) bool) [][]byte {
n := 0 n := 0
inField := false inField := false

View File

@ -1,5 +0,0 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file is here just to make the go tool happy.

View File

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

View File

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

View File

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

View File

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

View File

@ -179,28 +179,12 @@ fixautoused(Prog* p)
void void
ginscall(Node *f, int proc) ginscall(Node *f, int proc)
{ {
int32 arg;
Prog *p; Prog *p;
Node n1, r, r1, con; Node n1, r, r1, con;
if(f->type != T) if(f->type != T)
setmaxarg(f->type); 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) { switch(proc) {
default: default:
fatal("ginscall: bad proc %d", proc); fatal("ginscall: bad proc %d", proc);
@ -297,9 +281,6 @@ ginscall(Node *f, int proc)
} }
break; break;
} }
if(arg != -1)
gargsize(-1);
} }
/* /*

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -175,7 +175,6 @@ fixautoused(Prog *p)
void void
ginscall(Node *f, int proc) ginscall(Node *f, int proc)
{ {
int32 arg;
Prog *p; Prog *p;
Node reg, con; Node reg, con;
Node r1; Node r1;
@ -183,21 +182,6 @@ ginscall(Node *f, int proc)
if(f->type != T) if(f->type != T)
setmaxarg(f->type); 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) { switch(proc) {
default: default:
fatal("ginscall: bad proc %d", proc); fatal("ginscall: bad proc %d", proc);
@ -275,9 +259,6 @@ ginscall(Node *f, int proc)
} }
break; break;
} }
if(arg != -1)
gargsize(-1);
} }
/* /*
@ -1121,26 +1102,54 @@ clearfat(Node *nl)
c = w % 8; // bytes c = w % 8; // bytes
q = w / 8; // quads 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]); savex(D_DI, &n1, &oldn1, N, types[tptr]);
agen(nl, &n1); agen(nl, &n1);
savex(D_AX, &ax, &oldax, N, types[tptr]); savex(D_AX, &ax, &oldax, N, types[tptr]);
gconreg(AMOVL, 0, D_AX); gconreg(AMOVL, 0, D_AX);
if(q > 128 || (q >= 4 && nacl)) { if(q > 128 || nacl) {
gconreg(movptr, q, D_CX); gconreg(movptr, q, D_CX);
gins(AREP, N, N); // repeat gins(AREP, N, N); // repeat
gins(ASTOSQ, N, N); // STOQ AL,*(DI)+ gins(ASTOSQ, N, N); // STOQ AL,*(DI)+
} else if(q >= 4) { } else {
p = gins(ADUFFZERO, N, N); p = gins(ADUFFZERO, N, N);
p->to.type = D_ADDR; p->to.type = D_ADDR;
p->to.sym = linksym(pkglookup("duffzero", runtimepkg)); p->to.sym = linksym(pkglookup("duffzero", runtimepkg));
// 2 and 128 = magic constants: see ../../runtime/asm_amd64.s // 2 and 128 = magic constants: see ../../runtime/asm_amd64.s
p->to.offset = 2*(128-q); p->to.offset = 2*(128-q);
} else
while(q > 0) {
gins(ASTOSQ, N, N); // STOQ AL,*(DI)+
q--;
} }
z = ax; z = ax;

View File

@ -214,16 +214,6 @@ gtrack(Sym *s)
p->from.sym = linksym(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 void
ggloblsym(Sym *s, int32 width, int8 flags) ggloblsym(Sym *s, int32 width, int8 flags)
{ {

View File

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

View File

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

View File

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

View File

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

View File

@ -157,7 +157,7 @@ void
clearfat(Node *nl) clearfat(Node *nl)
{ {
uint32 w, c, q; uint32 w, c, q;
Node n1; Node n1, z;
Prog *p; Prog *p;
/* clear a fat object */ /* clear a fat object */
@ -172,6 +172,32 @@ clearfat(Node *nl)
c = w % 4; // bytes c = w % 4; // bytes
q = w / 4; // quads 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); nodreg(&n1, types[tptr], D_DI);
agen(nl, &n1); agen(nl, &n1);
gconreg(AMOVL, 0, D_AX); gconreg(AMOVL, 0, D_AX);
@ -210,28 +236,12 @@ clearfat(Node *nl)
void void
ginscall(Node *f, int proc) ginscall(Node *f, int proc)
{ {
int32 arg;
Prog *p; Prog *p;
Node reg, r1, con; Node reg, r1, con;
if(f->type != T) if(f->type != T)
setmaxarg(f->type); 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) { switch(proc) {
default: default:
fatal("ginscall: bad proc %d", proc); fatal("ginscall: bad proc %d", proc);
@ -293,9 +303,6 @@ ginscall(Node *f, int proc)
} }
break; break;
} }
if(arg != -1)
gargsize(-1);
} }
/* /*

View File

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

View File

@ -117,15 +117,23 @@ adddynrel(LSym *s, Reloc *r)
case 256 + R_386_GOT32: case 256 + R_386_GOT32:
if(targ->type != SDYNIMPORT) { if(targ->type != SDYNIMPORT) {
// have symbol // have symbol
// turn MOVL of GOT entry into LEAL of symbol itself if(r->off >= 2 && s->p[r->off-2] == 0x8b) {
if(r->off < 2 || s->p[r->off-2] != 0x8b) { // turn MOVL of GOT entry into LEAL of symbol address, relative to GOT.
diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
return;
}
s->p[r->off-2] = 0x8d; s->p[r->off-2] = 0x8d;
r->type = R_GOTOFF; r->type = R_GOTOFF;
return; return;
} }
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); addgotsym(ctxt, targ);
r->type = R_CONST; // write r->add during relocsym r->type = R_CONST; // write r->add during relocsym
r->sym = S; r->sym = S;

View File

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

View File

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

View File

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

View File

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

View File

@ -191,7 +191,6 @@ ginsBL(Node *reg, Node *f)
void void
ginscall(Node *f, int proc) ginscall(Node *f, int proc)
{ {
int32 arg;
Prog *p; Prog *p;
Node reg, con, reg2; Node reg, con, reg2;
Node r1; Node r1;
@ -199,21 +198,6 @@ ginscall(Node *f, int proc)
if(f->type != T) if(f->type != T)
setmaxarg(f->type); 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) { switch(proc) {
default: default:
fatal("ginscall: bad proc %d", proc); fatal("ginscall: bad proc %d", proc);
@ -303,9 +287,6 @@ ginscall(Node *f, int proc)
} }
break; break;
} }
if(arg != -1)
gargsize(-1);
} }
/* /*

View File

@ -216,16 +216,6 @@ gtrack(Sym *s)
p->from.sym = linksym(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 void
ggloblsym(Sym *s, int32 width, int8 flags) ggloblsym(Sym *s, int32 width, int8 flags)
{ {

View File

@ -377,7 +377,7 @@ func (w *Walker) parseFile(dir, file string) (*ast.File, error) {
} }
} }
if w.context != nil && file == fmt.Sprintf("zruntime_defs_%s_%s.go", w.context.GOOS, w.context.GOARCH) { 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 (" + src := "package runtime; type (" +
" _defer struct{};" + " _defer struct{};" +
" _func struct{};" + " _func struct{};" +
@ -388,6 +388,7 @@ func (w *Walker) parseFile(dir, file string) (*ast.File, error) {
" chantype struct{};" + " chantype struct{};" +
" context struct{};" + // windows " context struct{};" + // windows
" eface struct{};" + " eface struct{};" +
" epollevent struct{};" +
" funcval struct{};" + " funcval struct{};" +
" g struct{};" + " g struct{};" +
" gobuf struct{};" + " gobuf struct{};" +
@ -395,20 +396,21 @@ func (w *Walker) parseFile(dir, file string) (*ast.File, error) {
" iface struct{};" + " iface struct{};" +
" interfacetype struct{};" + " interfacetype struct{};" +
" itab struct{};" + " itab struct{};" +
" keventt struct{};" +
" m struct{};" + " m struct{};" +
" maptype struct{};" + " maptype struct{};" +
" mcache struct{};" + " mcache struct{};" +
" mspan struct{};" + " mspan struct{};" +
" mutex struct{};" + " mutex struct{};" +
" note struct{};" + " note struct{};" +
" p struct{};" +
" parfor struct{};" +
" slicetype struct{};" + " slicetype struct{};" +
" stkframe struct{};" + " stkframe struct{};" +
" sudog struct{};" + " sudog struct{};" +
" timespec struct{};" +
" waitq struct{};" + " waitq struct{};" +
" wincallbackcontext struct{};" + " wincallbackcontext struct{};" +
" keventt struct{};" +
" timespec struct{};" +
" epollevent struct{};" +
"); " + "); " +
"const (" + "const (" +
" cb_max = 2000;" + " cb_max = 2000;" +
@ -422,6 +424,52 @@ func (w *Walker) parseFile(dir, file string) (*ast.File, error) {
" _Genqueue = 7;" + " _Genqueue = 7;" +
" _Gcopystack = 8;" + " _Gcopystack = 8;" +
" _NSIG = 32;" + " _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) f, err = parser.ParseFile(fset, filename, src, 0)
if err != nil { if err != nil {
@ -449,6 +497,11 @@ func contains(list []string, s string) bool {
return false 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 ( var (
pkgCache = map[string]*types.Package{} // map tagKey to package pkgCache = map[string]*types.Package{} // map tagKey to package
pkgTags = map[string][]string{} // map import dir to list of relevant tags pkgTags = map[string][]string{} // map import dir to list of relevant tags
@ -510,6 +563,7 @@ func (w *Walker) Import(name string) (pkg *types.Package) {
// If we've already done an import with the same set // If we've already done an import with the same set
// of relevant tags, reuse the result. // of relevant tags, reuse the result.
var key string var key string
if usePkgCache {
if tags, ok := pkgTags[dir]; ok { if tags, ok := pkgTags[dir]; ok {
key = tagKey(dir, context, tags) key = tagKey(dir, context, tags)
if pkg := pkgCache[key]; pkg != nil { if pkg := pkgCache[key]; pkg != nil {
@ -517,6 +571,7 @@ func (w *Walker) Import(name string) (pkg *types.Package) {
return pkg return pkg
} }
} }
}
info, err := context.ImportDir(dir, 0) info, err := context.ImportDir(dir, 0)
if err != nil { if err != nil {
@ -527,10 +582,12 @@ func (w *Walker) Import(name string) (pkg *types.Package) {
} }
// Save tags list first time we see a directory. // Save tags list first time we see a directory.
if usePkgCache {
if _, ok := pkgTags[dir]; !ok { if _, ok := pkgTags[dir]; !ok {
pkgTags[dir] = info.AllTags pkgTags[dir] = info.AllTags
key = tagKey(dir, context, info.AllTags) key = tagKey(dir, context, info.AllTags)
} }
}
filenames := append(append([]string{}, info.GoFiles...), info.CgoFiles...) 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) log.Fatalf("error typechecking package %s: %s (%s)", name, err, ctxt)
} }
if usePkgCache {
pkgCache[key] = pkg pkgCache[key] = pkg
}
w.imported[name] = pkg w.imported[name] = pkg
return return

View File

@ -1,45 +0,0 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include <u.h>
#include "cc.h"
enum {
WORDSIZE = sizeof(uint32),
WORDBITS = 32,
};
uintptr
bvsize(uintptr n)
{
return ((n + WORDBITS - 1) / WORDBITS) * WORDSIZE;
}
Bvec*
bvalloc(int32 n)
{
Bvec *bv;
uintptr nbytes;
if(n < 0)
fatal(Z, "bvalloc: initial size is negative\n");
nbytes = sizeof(Bvec) + bvsize(n);
bv = malloc(nbytes);
if(bv == nil)
fatal(Z, "bvalloc: malloc failed\n");
memset(bv, 0, nbytes);
bv->n = n;
return bv;
}
void
bvset(Bvec *bv, int32 i)
{
uint32 mask;
if(i < 0 || i >= bv->n)
fatal(Z, "bvset: index %d is out of bounds with length %d\n", i, bv->n);
mask = 1 << (i % WORDBITS);
bv->b[i / WORDBITS] |= mask;
}

View File

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

View File

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

View File

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

View File

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

View File

@ -31,30 +31,6 @@
#include "gc.h" #include "gc.h"
#include "../../runtime/funcdata.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 int
hasdotdotdot(Type *t) hasdotdotdot(Type *t)
{ {
@ -109,9 +85,6 @@ codgen(Node *n, Node *nn)
{ {
Prog *sp; Prog *sp;
Node *n1, nod, nod1; Node *n1, nod, nod1;
Sym *gcargs;
Sym *gclocals;
int isvarargs;
cursafe = 0; cursafe = 0;
curarg = 0; curarg = 0;
@ -134,16 +107,6 @@ codgen(Node *n, Node *nn)
p->from.sym->cfunc = 1; p->from.sym->cfunc = 1;
sp = p; 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 * isolate first argument
*/ */
@ -178,22 +141,6 @@ codgen(Node *n, Node *nn)
if(thechar=='6' || thechar=='7') /* [sic] */ if(thechar=='6' || thechar=='7') /* [sic] */
maxargsafe = xround(maxargsafe, 8); maxargsafe = xround(maxargsafe, 8);
sp->to.offset += maxargsafe; 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 void
@ -673,113 +620,3 @@ bcomplex(Node *n, Node *c)
boolgen(n, 1, Z); boolgen(n, 1, Z);
return 0; return 0;
} }
// Updates the bitvector with a set bit for each pointer containing
// value in the type description starting at offset.
static void
walktype1(Type *t, int32 offset, Bvec *bv, int param)
{
Type *t1;
int32 o;
int32 widthptr;
widthptr = ewidth[TIND];
switch(t->etype) {
case TCHAR:
case TUCHAR:
case TSHORT:
case TUSHORT:
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TVLONG:
case TUVLONG:
case TFLOAT:
case TDOUBLE:
// non-pointer types
for(o = 0; o < t->width; o++)
bvset(bv, ((offset + t->offset + o) / widthptr) * BitsPerPointer); // 1 = live scalar
break;
case TIND:
pointer:
// pointer types
if((offset + t->offset) % widthptr != 0)
yyerror("unaligned pointer");
bvset(bv, ((offset + t->offset) / widthptr)*BitsPerPointer + 1); // 2 = live ptr
break;
case TARRAY:
if(param) // unlike Go, C passes arrays by reference
goto pointer;
// array in struct or union is an actual array
for(o = 0; o < t->width; o += t->link->width)
walktype1(t->link, offset+o, bv, 0);
break;
case TSTRUCT:
// build map recursively
for(t1 = t->link; t1 != T; t1 = t1->down)
walktype1(t1, offset, bv, 0);
break;
case TUNION:
walktype1(t->link, offset, bv, 0);
break;
default:
yyerror("can't handle arg type %s\n", tnames[t->etype]);
}
}
// Compute a bit vector to describe the pointer containing locations
// in the argument list. Adds the data to gcsym and returns the offset
// of end of the bit vector.
static void
dumpgcargs(Type *fn, Sym *sym)
{
Bvec *bv;
Type *t;
int32 i;
int32 argbytes;
int32 symoffset, argoffset;
// Dump the length of the bitmap array. This value is always one for
// functions written in C.
symoffset = 0;
gextern(sym, nodconst(1), symoffset, 4);
symoffset += 4;
argbytes = (argsize(1) + ewidth[TIND] - 1);
bv = bvalloc((argbytes / ewidth[TIND]) * BitsPerPointer);
argoffset = 0;
if(hasdotdotdot(thisfn))
argoffset = align(0, fn->link, Aarg0, nil);
if(argoffset > 0) {
// The C calling convention returns structs by copying them to a
// location pointed to by a hidden first argument. This first
// argument is a pointer.
if(argoffset != ewidth[TIND])
yyerror("passbyptr arg not the right size");
bvset(bv, 1); // 2 = live ptr
}
for(t = fn->down; t != T; t = t->down) {
if(t->etype == TVOID)
continue;
argoffset = align(argoffset, t, Aarg1, nil);
walktype1(t, argoffset, bv, 1);
argoffset = align(argoffset, t, Aarg2, nil);
}
// Dump the length of the bitmap.
gextern(sym, nodconst(bv->n), symoffset, 4);
symoffset += 4;
// Dump the words of the bitmap.
for(i = 0; i < bv->n; i += 32) {
gextern(sym, nodconst(bv->b[i/32]), symoffset, 4);
symoffset += 4;
}
free(bv);
// Finalize the gc symbol.
sym->type = typ(0, T);
sym->type->width = symoffset;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,14 @@
/* 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 /* Skeleton interface for Bison's Yacc-like parsers in C
Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. 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 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation; either version 2, or (at your option)
(at your option) any later version. any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
@ -15,7 +16,9 @@
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License 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 /* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work part or all of the Bison parser skeleton and distribute that work
@ -30,16 +33,6 @@
This special exception was added by the Free Software Foundation in This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */ 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. */ /* Tokens. */
#ifndef YYTOKENTYPE #ifndef YYTOKENTYPE
# define YYTOKENTYPE # define YYTOKENTYPE
@ -196,12 +189,11 @@ extern int yydebug;
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE typedef union YYSTYPE
{
/* Line 2053 of yacc.c */
#line 36 "cc.y" #line 36 "cc.y"
{
Node* node; Node* node;
Sym* sym; Sym* sym;
Type* type; Type* type;
@ -225,30 +217,14 @@ typedef union YYSTYPE
int32 lval; int32 lval;
double dval; double dval;
vlong vval; vlong vval;
}
/* Line 1529 of yacc.c. */
/* Line 2053 of yacc.c */ #line 223 "y.tab.h"
#line 232 "y.tab.h" YYSTYPE;
} YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1 # define YYSTYPE_IS_DECLARED 1
# define YYSTYPE_IS_TRIVIAL 1
#endif #endif
extern YYSTYPE yylval; extern YYSTYPE yylval;
#ifdef YYPARSE_PARAM
#if defined __STDC__ || defined __cplusplus
int yyparse (void *YYPARSE_PARAM);
#else
int yyparse ();
#endif
#else /* ! YYPARSE_PARAM */
#if defined __STDC__ || defined __cplusplus
int yyparse (void);
#else
int yyparse ();
#endif
#endif /* ! YYPARSE_PARAM */
#endif /* !YY_YY_Y_TAB_H_INCLUDED */

View File

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

View File

@ -44,6 +44,7 @@ func (p *Package) writeDefs() {
fmt.Fprintf(fm, "int main() { return 0; }\n") fmt.Fprintf(fm, "int main() { return 0; }\n")
if *importRuntimeCgo { if *importRuntimeCgo {
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c) { }\n") 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 { } else {
// If we're not importing runtime/cgo, we *are* runtime/cgo, // If we're not importing runtime/cgo, we *are* runtime/cgo,
// which provides crosscall2. We just need a prototype. // 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(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) fmt.Fprintf(&gccgoInit, "\t%s = %s%s;\n", n.Mangle, amp, n.C)
} else { } 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, "void *·%s = %s%s;\n", n.Mangle, amp, n.C)
} }
fmt.Fprintf(fc, "\n") 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. // 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, "#pragma cgo_import_static %s\n", cname)
fmt.Fprintf(fc, "void %s(void*);\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) fmt.Fprintf(fc, "void *·%s = %s;\n", cname, cname)
nret := 0 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 // Use packed attribute to force no padding in this struct in case
// gcc has different packing requirements. // gcc has different packing requirements.
fmt.Fprintf(fgcc, "\t%s %v *a = v;\n", ctype, p.packedAttribute()) 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") fmt.Fprintf(fgcc, "\t")
if t := n.FuncType.Result; t != nil { 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] == '*' { if c := t.C.String(); c[len(c)-1] == '*' {
fmt.Fprint(fgcc, "(__typeof__(a->r)) ") 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, "a->p%d", i)
} }
fmt.Fprintf(fgcc, ");\n") 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 { if n.AddError {
fmt.Fprintf(fgcc, "\treturn errno;\n") 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(float, 4)
__cgo_size_assert(double, 8) __cgo_size_assert(double, 8)
extern char* _cgo_topofstack(void);
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
` `
@ -1151,20 +1167,31 @@ void *_CMalloc(size_t);
const cProlog = ` const cProlog = `
#include "runtime.h" #include "runtime.h"
#include "cgocall.h" #include "cgocall.h"
#include "textflag.h"
#pragma dataflag NOPTR
static void *cgocall_errno = runtime·cgocall_errno; static void *cgocall_errno = runtime·cgocall_errno;
#pragma dataflag NOPTR
void *·_cgo_runtime_cgocall_errno = &cgocall_errno; void *·_cgo_runtime_cgocall_errno = &cgocall_errno;
#pragma dataflag NOPTR
static void *runtime_gostring = runtime·gostring; static void *runtime_gostring = runtime·gostring;
#pragma dataflag NOPTR
void *·_cgo_runtime_gostring = &runtime_gostring; void *·_cgo_runtime_gostring = &runtime_gostring;
#pragma dataflag NOPTR
static void *runtime_gostringn = runtime·gostringn; static void *runtime_gostringn = runtime·gostringn;
#pragma dataflag NOPTR
void *·_cgo_runtime_gostringn = &runtime_gostringn; void *·_cgo_runtime_gostringn = &runtime_gostringn;
#pragma dataflag NOPTR
static void *runtime_gobytes = runtime·gobytes; static void *runtime_gobytes = runtime·gobytes;
#pragma dataflag NOPTR
void *·_cgo_runtime_gobytes = &runtime_gobytes; void *·_cgo_runtime_gobytes = &runtime_gobytes;
#pragma dataflag NOPTR
static void *runtime_cmalloc = runtime·cmalloc; static void *runtime_cmalloc = runtime·cmalloc;
#pragma dataflag NOPTR
void *·_cgo_runtime_cmalloc = &runtime_cmalloc; void *·_cgo_runtime_cmalloc = &runtime_cmalloc;
void ·_Cerrno(void*, int32); void ·_Cerrno(void*, int32);

View File

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

View File

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

View File

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

View File

@ -83,6 +83,14 @@ char *runtimeimport =
"func @\"\".chanrecv2 (@\"\".chanType·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any) (? bool)\n" "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 @\"\".chansend1 (@\"\".chanType·1 *byte, @\"\".hchan·2 chan<- any, @\"\".elem·3 *any)\n"
"func @\"\".closechan (@\"\".hchan·1 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 @\"\".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 @\"\".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" "func @\"\".selectnbrecv2 (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".received·4 *bool, @\"\".hchan·5 <-chan any) (? bool)\n"

View File

@ -488,6 +488,10 @@ colasdefn(NodeList *left, Node *defn)
NodeList *l; NodeList *l;
Node *n; Node *n;
for(l=left; l; l=l->next)
if(l->n->sym != S)
l->n->sym->flags |= SymUniq;
nnew = 0; nnew = 0;
nerr = 0; nerr = 0;
for(l=left; l; l=l->next) { for(l=left; l; l=l->next) {
@ -499,6 +503,13 @@ colasdefn(NodeList *left, Node *defn)
nerr++; nerr++;
continue; 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) if(n->sym->block == block)
continue; continue;
@ -547,6 +558,9 @@ ifacedcl(Node *n)
if(n->op != ODCLFIELD || n->right == N) if(n->op != ODCLFIELD || n->right == N)
fatal("ifacedcl"); fatal("ifacedcl");
if(isblank(n->left))
yyerror("methods must have a unique non-blank name");
dclcontext = PPARAM; dclcontext = PPARAM;
markdcl(); markdcl();
funcdepth++; funcdepth++;

View File

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

View File

@ -54,9 +54,6 @@ addrescapes(Node *n)
if(n->class == PAUTO && n->esc == EscNever) if(n->class == PAUTO && n->esc == EscNever)
break; break;
if(debug['N'] && n->esc != EscUnknown)
fatal("without escape analysis, only PAUTO's should have esc: %N", n);
switch(n->class) { switch(n->class) {
case PPARAMREF: case PPARAMREF:
addrescapes(n->defn); addrescapes(n->defn);
@ -91,7 +88,6 @@ addrescapes(Node *n)
snprint(buf, sizeof buf, "&%S", n->sym); snprint(buf, sizeof buf, "&%S", n->sym);
n->heapaddr->sym = lookup(buf); n->heapaddr->sym = lookup(buf);
n->heapaddr->orig->sym = n->heapaddr->sym; n->heapaddr->orig->sym = n->heapaddr->sym;
if(!debug['N'])
n->esc = EscHeap; n->esc = EscHeap;
if(debug['m']) if(debug['m'])
print("%L: moved to heap: %N\n", n->lineno, n); print("%L: moved to heap: %N\n", n->lineno, n);
@ -585,7 +581,7 @@ cgen_dcl(Node *n)
if(!(n->class & PHEAP)) if(!(n->class & PHEAP))
return; return;
if(compiling_runtime) 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) if(n->alloc == nil)
n->alloc = callnew(n->type); n->alloc = callnew(n->type);
cgen_as(n->heapaddr, n->alloc); cgen_as(n->heapaddr, n->alloc);
@ -735,14 +731,10 @@ cgen_as(Node *nl, Node *nr)
return; return;
} }
if(nr == N || isnil(nr)) { if(nr == N || iszero(nr)) {
// externals and heaps should already be clear // heaps should already be clear
if(nr == N) { if(nr == N && (nl->class & PHEAP))
if(nl->class == PEXTERN)
return; return;
if(nl->class & PHEAP)
return;
}
tl = nl->type; tl = nl->type;
if(tl == T) if(tl == T)

View File

@ -283,6 +283,7 @@ struct Node
uchar addrtaken; // address taken, even if not moved to heap uchar addrtaken; // address taken, even if not moved to heap
uchar dupok; // duplicate definitions ok (for func) uchar dupok; // duplicate definitions ok (for func)
uchar wrapper; // is method wrapper (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 schar likely; // likeliness of if statement
uchar hasbreak; // has break statement uchar hasbreak; // has break statement
uchar needzero; // if it contains pointers, needs to be zeroed on function entry 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 typecheckok;
EXTERN int compiling_runtime; EXTERN int compiling_runtime;
EXTERN int compiling_wrappers; EXTERN int compiling_wrappers;
EXTERN int use_writebarrier;
EXTERN int pure_go; EXTERN int pure_go;
EXTERN char* flag_installsuffix; EXTERN char* flag_installsuffix;
EXTERN int flag_race; EXTERN int flag_race;
@ -1284,6 +1286,7 @@ LSym* linksym(Sym*);
* order.c * order.c
*/ */
void order(Node *fn); void order(Node *fn);
void orderstmtinplace(Node **stmt);
/* /*
* range.c * range.c
@ -1372,6 +1375,7 @@ int isnilinter(Type *t);
int isptrto(Type *t, int et); int isptrto(Type *t, int et);
int isslice(Type *t); int isslice(Type *t);
int istype(Type *t, int et); int istype(Type *t, int et);
int iszero(Node *n);
void linehist(char *file, int32 off, int relative); void linehist(char *file, int32 off, int relative);
NodeList* list(NodeList *l, Node *n); NodeList* list(NodeList *l, Node *n);
NodeList* list1(Node *n); NodeList* list1(Node *n);
@ -1464,6 +1468,7 @@ void walkstmt(Node **np);
void walkstmtlist(NodeList *l); void walkstmtlist(NodeList *l);
Node* conv(Node*, Type*); Node* conv(Node*, Type*);
int candiscard(Node*); int candiscard(Node*);
int needwritebarrier(Node*, Node*);
Node* outervalue(Node*); Node* outervalue(Node*);
void usefield(Node*); void usefield(Node*);

View File

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

View File

@ -312,6 +312,8 @@ main(int argc, char *argv[])
flagcount("u", "reject unsafe code", &safemode); flagcount("u", "reject unsafe code", &safemode);
flagcount("v", "increase debug verbosity", &debug['v']); flagcount("v", "increase debug verbosity", &debug['v']);
flagcount("w", "debug type checking", &debug['w']); flagcount("w", "debug type checking", &debug['w']);
use_writebarrier = 1;
flagcount("wb", "enable write barrier", &use_writebarrier);
flagcount("x", "debug lexer", &debug['x']); flagcount("x", "debug lexer", &debug['x']);
flagcount("y", "debug declarations in canned imports (with -d)", &debug['y']); flagcount("y", "debug declarations in canned imports (with -d)", &debug['y']);
if(thechar == '6') if(thechar == '6')
@ -479,7 +481,11 @@ main(int argc, char *argv[])
} }
// Phase 5: Escape analysis. // Phase 5: Escape analysis.
if(!debug['N']) // 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); escapes(xtop);
// Escape analysis moved escaped values off stack. // Escape analysis moved escaped values off stack.

View File

@ -656,7 +656,7 @@ mpdivmodfixfix(Mpint *q, Mpint *r, Mpint *n, Mpint *d)
} }
static int static int
iszero(Mpint *a) mpiszero(Mpint *a)
{ {
long *a1; long *a1;
int i; int i;
@ -687,7 +687,7 @@ mpdivfract(Mpint *a, Mpint *b)
for(j=0; j<Mpscale; j++) { for(j=0; j<Mpscale; j++) {
x <<= 1; x <<= 1;
if(mpcmp(&d, &n) <= 0) { if(mpcmp(&d, &n) <= 0) {
if(!iszero(&d)) if(!mpiszero(&d))
x |= 1; x |= 1;
mpsubfixfix(&n, &d); mpsubfixfix(&n, &d);
} }

View File

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

View File

@ -14,6 +14,7 @@
#include "../../runtime/funcdata.h" #include "../../runtime/funcdata.h"
static void allocauto(Prog* p); static void allocauto(Prog* p);
static void emitptrargsmap(void);
static Sym* static Sym*
makefuncdatasym(char *namefmt, int64 funcdatakind) makefuncdatasym(char *namefmt, int64 funcdatakind)
@ -173,20 +174,25 @@ compile(Node *fn)
lno = setlineno(fn); lno = setlineno(fn);
curfn = fn;
dowidth(curfn->type);
if(fn->nbody == nil) { 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); yyerror("missing function body", fn);
goto ret; goto ret;
} }
if(debug['A'])
goto ret;
emitptrargsmap();
goto ret;
}
saveerrors(); saveerrors();
// set up domain for labels // set up domain for labels
clearlabels(); clearlabels();
curfn = fn;
dowidth(curfn->type);
if(curfn->type->outnamed) { if(curfn->type->outnamed) {
// add clearing of the output parameters // add clearing of the output parameters
t = structfirst(&save, getoutarg(curfn->type)); t = structfirst(&save, getoutarg(curfn->type));
@ -329,6 +335,43 @@ ret:
lineno = lno; 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, // Sort the list of stack variables. Autos after anything else,
// within autos, unused after used, within used, things with // within autos, unused after used, within used, things with
// pointers first, zeroed things first, and then decreasing size. // pointers first, zeroed things first, and then decreasing size.

View File

@ -208,6 +208,26 @@ racewalknode(Node **np, NodeList **init, int wr, int skip)
goto ret; goto ret;
case OCALLFUNC: 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); racewalknode(&n->left, init, 0, 0);
goto ret; goto ret;

View File

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

View File

@ -107,6 +107,20 @@ func chanrecv2(chanType *byte, hchan <-chan any, elem *any) bool
func chansend1(chanType *byte, hchan chan<- any, elem *any) func chansend1(chanType *byte, hchan chan<- any, elem *any)
func closechan(hchan 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 selectnbsend(chanType *byte, hchan chan<- any, elem *any) bool
func selectnbrecv(chanType *byte, elem *any, hchan <-chan any) bool func selectnbrecv(chanType *byte, elem *any, hchan <-chan any) bool
func selectnbrecv2(chanType *byte, elem *any, received *bool, hchan <-chan any) bool func selectnbrecv2(chanType *byte, elem *any, received *bool, hchan <-chan any) bool

View File

@ -17,7 +17,6 @@ enum
InitPending = 2, InitPending = 2,
}; };
static int iszero(Node*);
static void initplan(Node*); static void initplan(Node*);
static NodeList *initlist; static NodeList *initlist;
static void init2(Node*, NodeList**); static void init2(Node*, NodeList**);
@ -207,7 +206,7 @@ init2(Node *n, NodeList **out)
if(n->op == OCLOSURE) if(n->op == OCLOSURE)
init2list(n->closure->nbody, out); init2list(n->closure->nbody, out);
if(n->op == ODOTMETH) if(n->op == ODOTMETH || n->op == OCALLPART)
init2(n->type->nname, out); 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(ODOT, var, newname(index->sym));
a = nod(OAS, a, value); a = nod(OAS, a, value);
typecheck(&a, Etop); typecheck(&a, Etop);
walkexpr(&a, init);
if(pass == 1) { if(pass == 1) {
walkexpr(&a, init); // add any assignments in r to top
if(a->op != OAS) if(a->op != OAS)
fatal("structlit: not as"); fatal("structlit: not as");
a->dodata = 2; a->dodata = 2;
} else {
orderstmtinplace(&a);
walkstmt(&a);
} }
*init = list(*init, 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(OINDEX, var, index);
a = nod(OAS, a, value); a = nod(OAS, a, value);
typecheck(&a, Etop); typecheck(&a, Etop);
walkexpr(&a, init); // add any assignments in r to top
if(pass == 1) { if(pass == 1) {
walkexpr(&a, init);
if(a->op != OAS) if(a->op != OAS)
fatal("structlit: not as"); fatal("arraylit: not as");
a->dodata = 2; a->dodata = 2;
} else {
orderstmtinplace(&a);
walkstmt(&a);
} }
*init = list(*init, a); *init = list(*init, a);
} }
@ -807,7 +812,8 @@ slicelit(int ctxt, Node *n, Node *var, NodeList **init)
// make slice out of heap (5) // make slice out of heap (5)
a = nod(OAS, var, nod(OSLICE, vauto, nod(OKEY, N, N))); a = nod(OAS, var, nod(OSLICE, vauto, nod(OKEY, N, N)));
typecheck(&a, Etop); typecheck(&a, Etop);
walkexpr(&a, init); orderstmtinplace(&a);
walkstmt(&a);
*init = list(*init, a); *init = list(*init, a);
// put dynamics into slice (6) // put dynamics into slice (6)
@ -839,7 +845,8 @@ slicelit(int ctxt, Node *n, Node *var, NodeList **init)
// build list of var[c] = expr // build list of var[c] = expr
a = nod(OAS, a, value); a = nod(OAS, a, value);
typecheck(&a, Etop); typecheck(&a, Etop);
walkexpr(&a, init); orderstmtinplace(&a);
walkstmt(&a);
*init = list(*init, a); *init = list(*init, a);
} }
} }
@ -1060,7 +1067,7 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init)
if(t->etype != TSTRUCT) if(t->etype != TSTRUCT)
fatal("anylit: not struct"); fatal("anylit: not struct");
if(simplename(var)) { if(simplename(var) && count(n->list) > 4) {
if(ctxt == 0) { if(ctxt == 0) {
// lay out static data // lay out static data
@ -1083,7 +1090,7 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init)
} }
// initialize of not completely specified // initialize of not completely specified
if(count(n->list) < structcount(t)) { if(simplename(var) || count(n->list) < structcount(t)) {
a = nod(OAS, var, N); a = nod(OAS, var, N);
typecheck(&a, Etop); typecheck(&a, Etop);
walkexpr(&a, init); walkexpr(&a, init);
@ -1100,7 +1107,7 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init)
break; break;
} }
if(simplename(var)) { if(simplename(var) && count(n->list) > 4) {
if(ctxt == 0) { if(ctxt == 0) {
// lay out static data // lay out static data
@ -1123,7 +1130,7 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init)
} }
// initialize of not completely specified // initialize of not completely specified
if(count(n->list) < t->bound) { if(simplename(var) || count(n->list) < t->bound) {
a = nod(OAS, var, N); a = nod(OAS, var, N);
typecheck(&a, Etop); typecheck(&a, Etop);
walkexpr(&a, init); walkexpr(&a, init);
@ -1348,7 +1355,6 @@ no:
return 0; return 0;
} }
static int iszero(Node*);
static int isvaluelit(Node*); static int isvaluelit(Node*);
static InitEntry* entry(InitPlan*); static InitEntry* entry(InitPlan*);
static void addvalue(InitPlan*, vlong, Node*, Node*); static void addvalue(InitPlan*, vlong, Node*, Node*);
@ -1432,7 +1438,7 @@ addvalue(InitPlan *p, vlong xoffset, Node *key, Node *n)
e->expr = n; e->expr = n;
} }
static int int
iszero(Node *n) iszero(Node *n)
{ {
NodeList *l; NodeList *l;

View File

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

View File

@ -33,7 +33,7 @@ static void stringtoarraylit(Node**);
static Node* resolve(Node*); static Node* resolve(Node*);
static void checkdefergo(Node*); static void checkdefergo(Node*);
static int checkmake(Type*, char*, Node*); static int checkmake(Type*, char*, Node*);
static int checksliceindex(Node*, Type*); static int checksliceindex(Node*, Node*, Type*);
static int checksliceconst(Node*, Node*); static int checksliceconst(Node*, Node*);
static NodeList* typecheckdefstack; static NodeList* typecheckdefstack;
@ -311,6 +311,7 @@ typecheck1(Node **np, int top)
Type *t, *tp, *missing, *have, *badtype; Type *t, *tp, *missing, *have, *badtype;
Val v; Val v;
char *why, *desc, descbuf[64]; char *why, *desc, descbuf[64];
vlong x;
n = *np; n = *np;
@ -408,6 +409,9 @@ reswitch:
v = toint(l->val); v = toint(l->val);
break; break;
default: default:
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); yyerror("invalid array bound %N", l);
goto error; goto error;
} }
@ -597,6 +601,10 @@ reswitch:
} }
if(t->etype != TIDEAL && !eqtype(l->type, r->type)) { if(t->etype != TIDEAL && !eqtype(l->type, r->type)) {
defaultlit2(&l, &r, 1); 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); yyerror("invalid operation: %N (mismatched types %T and %T)", n, l->type, r->type);
goto error; goto error;
} }
@ -733,10 +741,6 @@ reswitch:
l = n->left; l = n->left;
if((t = l->type) == T) if((t = l->type) == T)
goto error; 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); n->type = ptrto(t);
goto ret; goto ret;
@ -892,11 +896,12 @@ reswitch:
break; break;
} }
if(isconst(n->right, CTINT)) { 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); 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); 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); 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) else if(mpcmpfixfix(n->right->val.u.xval, maxintval[TINT]) > 0)
yyerror("invalid %s index %N (index too large)", why, n->right); yyerror("invalid %s index %N (index too large)", why, n->right);
@ -996,9 +1001,9 @@ reswitch:
yyerror("cannot slice %N (type %T)", l, t); yyerror("cannot slice %N (type %T)", l, t);
goto error; 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; 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; goto error;
if(checksliceconst(lo, hi) < 0) if(checksliceconst(lo, hi) < 0)
goto error; goto error;
@ -1045,11 +1050,11 @@ reswitch:
yyerror("cannot slice %N (type %T)", l, t); yyerror("cannot slice %N (type %T)", l, t);
goto error; 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; 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; 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; goto error;
if(checksliceconst(lo, hi) < 0 || checksliceconst(lo, mid) < 0 || checksliceconst(mid, hi) < 0) if(checksliceconst(lo, hi) < 0 || checksliceconst(lo, mid) < 0 || checksliceconst(mid, hi) < 0)
goto error; goto error;
@ -1819,7 +1824,7 @@ out:
} }
static int static int
checksliceindex(Node *r, Type *tp) checksliceindex(Node *l, Node *r, Type *tp)
{ {
Type *t; 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) { } 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); yyerror("invalid slice index %N (out of bounds for %d-element array)", r, tp->bound);
return -1; 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) { } else if(mpcmpfixfix(r->val.u.xval, maxintval[TINT]) > 0) {
yyerror("invalid slice index %N (index too large)", r); yyerror("invalid slice index %N (index too large)", r);
return -1; return -1;
@ -2116,18 +2124,19 @@ lookdot(Node *n, Type *t, int dostrcmp)
if(!eqtype(rcvr, tt)) { if(!eqtype(rcvr, tt)) {
if(rcvr->etype == tptr && eqtype(rcvr->type, tt)) { if(rcvr->etype == tptr && eqtype(rcvr->type, tt)) {
checklvalue(n->left, "call pointer method on"); checklvalue(n->left, "call pointer method on");
if(debug['N'])
addrescapes(n->left);
n->left = nod(OADDR, n->left, N); n->left = nod(OADDR, n->left, N);
n->left->implicit = 1; n->left->implicit = 1;
typecheck(&n->left, Etype|Erv); 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 = nod(OIND, n->left, N);
n->left->implicit = 1; n->left->implicit = 1;
typecheck(&n->left, Etype|Erv); 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); yyerror("calling method %N with receiver %lN requires explicit dereference", n->right, n->left);
while(tt->etype == tptr) { 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 = nod(OIND, n->left, N);
n->left->implicit = 1; n->left->implicit = 1;
typecheck(&n->left, Etype|Erv); typecheck(&n->left, Etype|Erv);
@ -2808,6 +2817,33 @@ checkassignlist(NodeList *l)
checkassign(l->n); 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. * type check assignment.
* if this assignment is the definition of a var on the left side, * if this assignment is the definition of a var on the left side,
@ -2845,6 +2881,29 @@ typecheckas(Node *n)
n->typecheck = 1; n->typecheck = 1;
if(n->left->typecheck == 0) if(n->left->typecheck == 0)
typecheck(&n->left, Erv | Easgn); 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 static void

View File

@ -8,6 +8,8 @@
#include "../ld/textflag.h" #include "../ld/textflag.h"
static Node* walkprint(Node*, NodeList**, int); static Node* walkprint(Node*, NodeList**, int);
static Node* writebarrierfn(char*, Type*, Type*);
static Node* applywritebarrier(Node*, NodeList**);
static Node* mapfn(char*, Type*); static Node* mapfn(char*, Type*);
static Node* mapfndel(char*, Type*); static Node* mapfndel(char*, Type*);
static Node* ascompatee1(int, Node*, Node*, NodeList**); static Node* ascompatee1(int, Node*, Node*, NodeList**);
@ -135,6 +137,8 @@ walkstmt(Node **np)
n = *np; n = *np;
if(n == N) if(n == N)
return; return;
if(n->dodata == 2) // don't walk, generated by anylit.
return;
setlineno(n); setlineno(n);
@ -633,6 +637,7 @@ walkexpr(Node **np, NodeList **init)
r = convas(nod(OAS, n->left, n->right), init); r = convas(nod(OAS, n->left, n->right), init);
r->dodata = n->dodata; r->dodata = n->dodata;
n = r; n = r;
n = applywritebarrier(n, init);
} }
goto ret; goto ret;
@ -644,6 +649,8 @@ walkexpr(Node **np, NodeList **init)
walkexprlistsafe(n->rlist, init); walkexprlistsafe(n->rlist, init);
ll = ascompatee(OAS, n->list, n->rlist, init); ll = ascompatee(OAS, n->list, n->rlist, init);
ll = reorder3(ll); ll = reorder3(ll);
for(lr = ll; lr != nil; lr = lr->next)
lr->n = applywritebarrier(lr->n, init);
n = liststmt(ll); n = liststmt(ll);
goto ret; goto ret;
@ -656,6 +663,8 @@ walkexpr(Node **np, NodeList **init)
walkexpr(&r, init); walkexpr(&r, init);
ll = ascompatet(n->op, n->list, &r->type, 0, 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)); n = liststmt(concat(list1(r), ll));
goto ret; goto ret;
@ -1381,7 +1390,12 @@ walkexpr(Node **np, NodeList **init)
case OMAPLIT: case OMAPLIT:
case OSTRUCTLIT: case OSTRUCTLIT:
case OPTRLIT: 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); var = temp(n->type);
anylit(0, n, var, init); anylit(0, n, var, init);
n = var; n = var;
@ -1481,8 +1495,13 @@ ascompatee(int op, NodeList *nl, NodeList *nr, NodeList **init)
static int static int
fncall(Node *l, Type *rt) fncall(Node *l, Type *rt)
{ {
Node r;
if(l->ullman >= UINF || l->op == OINDEXMAP) if(l->ullman >= UINF || l->op == OINDEXMAP)
return 1; return 1;
memset(&r, 0, sizeof r);
if(needwritebarrier(l, &r))
return 1;
if(eqtype(l->type, rt)) if(eqtype(l->type, rt))
return 0; return 0;
return 1; 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 = nod(OAS, l, nodarg(r, fp));
a = convas(a, init); a = convas(a, init);
ullmancalc(a); ullmancalc(a);
if(a->ullman >= UINF) if(a->ullman >= UINF) {
dump("ascompatet ucount", a);
ucount++; ucount++;
}
nn = list(nn, a); nn = list(nn, a);
r = structnext(&saver); r = structnext(&saver);
} }
@ -1932,6 +1953,161 @@ callnew(Type *t)
return mkcall1(fn, ptrto(t), nil, typename(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* static Node*
convas(Node *n, NodeList **init) convas(Node *n, NodeList **init)
{ {
@ -1971,11 +2147,10 @@ convas(Node *n, NodeList **init)
goto out; goto out;
} }
if(eqtype(lt, rt)) if(!eqtype(lt, rt)) {
goto out;
n->right = assignconv(n->right, lt, "assignment"); n->right = assignconv(n->right, lt, "assignment");
walkexpr(&n->right, init); walkexpr(&n->right, init);
}
out: out:
ullmancalc(n); ullmancalc(n);
@ -2369,7 +2544,7 @@ paramstoheap(Type **argin, int out)
// generate allocation & copying code // generate allocation & copying code
if(compiling_runtime) 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) if(v->alloc == nil)
v->alloc = callnew(v->type); v->alloc = callnew(v->type);
nn = list(nn, nod(OAS, v->heapaddr, v->alloc)); nn = list(nn, nod(OAS, v->heapaddr, v->alloc));
@ -2526,6 +2701,17 @@ mapfndel(char *name, Type *t)
return fn; 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* static Node*
addstr(Node *n, NodeList **init) addstr(Node *n, NodeList **init)
{ {

File diff suppressed because it is too large Load Diff

View File

@ -57,6 +57,7 @@ and test commands:
-a -a
force rebuilding of packages that are already up-to-date. force rebuilding of packages that are already up-to-date.
In Go releases, does not apply to the standard library.
-n -n
print the commands but do not run them. print the commands but do not run them.
-p n -p n
@ -284,6 +285,11 @@ func runBuild(cmd *Command, args []string) {
} }
} }
depMode := modeBuild
if buildI {
depMode = modeInstall
}
if *buildO != "" { if *buildO != "" {
if len(pkgs) > 1 { if len(pkgs) > 1 {
fatalf("go build: cannot use -o with multiple packages") fatalf("go build: cannot use -o with multiple packages")
@ -292,17 +298,13 @@ func runBuild(cmd *Command, args []string) {
} }
p := pkgs[0] p := pkgs[0]
p.target = "" // must build - not up to date p.target = "" // must build - not up to date
a := b.action(modeInstall, modeBuild, p) a := b.action(modeInstall, depMode, p)
a.target = *buildO a.target = *buildO
b.do(a) b.do(a)
return return
} }
a := &action{} a := &action{}
depMode := modeBuild
if buildI {
depMode = modeInstall
}
for _, p := range packages(args) { for _, p := range packages(args) {
a.deps = append(a.deps, b.action(modeBuild, depMode, p)) 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 } ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil }
if !filepath.IsAbs(dir) { var err error
dir = filepath.Join(cwd, dir) if dir == "" {
dir = cwd
}
dir, err = filepath.Abs(dir)
if err != nil {
fatalf("%s", err)
} }
bp, err := ctxt.ImportDir(dir, 0) 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...) gofiles = append(gofiles, a.p.GoFiles...)
cfiles = append(cfiles, a.p.CFiles...) cfiles = append(cfiles, a.p.CFiles...)
sfiles = append(sfiles, a.p.SFiles...) 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. // Run cgo.
if a.p.usesCgo() { if a.p.usesCgo() {
// In a package using cgo, cgo compiles the C, C++ and assembly files with gcc. // 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 != "" { if a.cgo != nil && a.cgo.target != "" {
cgoExe = 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 { if err != nil {
return err 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 // In a package using SWIG, any .c or .s files are
// compiled with gcc. // compiled with gcc.
gccfiles := append(cfiles, sfiles...) gccfiles := append(cfiles, sfiles...)
cxxfiles, mfiles := a.p.CXXFiles, a.p.MFiles
cfiles = nil cfiles = nil
sfiles = 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 { if err != nil {
return err return err
} }
@ -1019,6 +1040,34 @@ func (b *builder) build(a *action) (err error) {
return nil 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. // install is the action for installing a single package or executable.
func (b *builder) install(a *action) (err error) { func (b *builder) install(a *action) (err error) {
defer func() { defer func() {
@ -1426,6 +1475,14 @@ func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...inter
continue 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 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) 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 { if p.Standard {
switch p.ImportPath { switch p.ImportPath {
case "os", "runtime/pprof", "sync", "time": case "bytes", "net", "os", "runtime/pprof", "sync", "time":
extFiles++ 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) { 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 ofile = obj + out
gcargs := []string{"-g"} gcargs := []string{"-g"}
gcargs = append(gcargs, b.gccArchArgs()...) gcargs = append(gcargs, b.gccArchArgs()...)
@ -2100,36 +2157,16 @@ var (
cgoLibGccFileOnce sync.Once 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) cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoLDFLAGS := b.cflags(p, true)
_, cgoexeCFLAGS, _, _ := b.cflags(p, false) _, 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 we are compiling Objective-C code, then we need to link against libobjc
if len(mfiles) > 0 { if len(mfiles) > 0 {
cgoLDFLAGS = append(cgoLDFLAGS, "-lobjc") 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. // Allows including _cgo_export.h from .[ch] files in the package.
cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", obj) 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, ".so"),
strings.HasSuffix(f, ".dll"): strings.HasSuffix(f, ".dll"):
continue 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: default:
bareLDFLAGS = append(bareLDFLAGS, f) 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. // Run SWIG on all SWIG input files.
// TODO: Don't build a shared library, once SWIG emits the necessary // TODO: Don't build a shared library, once SWIG emits the necessary
// pragmas for external linking. // 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) cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true)
cflags := stringList(cgoCPPFLAGS, cgoCFLAGS) cflags := stringList(cgoCPPFLAGS, cgoCFLAGS)
cxxflags := stringList(cgoCPPFLAGS, cgoCXXFLAGS) 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 { 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 { if err != nil {
return nil, nil, err 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 { 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 { if err != nil {
return nil, nil, err 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. // 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) cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true)
var cflags []string var cflags []string
if cxx { if cxx {
cflags = stringList(cgoCPPFLAGS, cgoCXXFLAGS) cflags = stringList(cgoCPPFLAGS, pcCFLAGS, cgoCXXFLAGS)
} else { } else {
cflags = stringList(cgoCPPFLAGS, cgoCFLAGS) cflags = stringList(cgoCPPFLAGS, pcCFLAGS, cgoCFLAGS)
} }
n := 5 // length of ".swig" 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, "-o", obj + gccBase + gccExt,
"-outdir", obj, "-outdir", obj,
} }
for _, f := range cflags {
if len(f) > 3 && f[:2] == "-I" {
args = append(args, f)
}
}
if gccgo { if gccgo {
args = append(args, "-gccgo") args = append(args, "-gccgo")
if pkgpath := gccgoPkgpath(p); pkgpath != "" { if pkgpath := gccgoPkgpath(p); pkgpath != "" {

View File

@ -76,6 +76,7 @@ and test commands:
-a -a
force rebuilding of packages that are already up-to-date. force rebuilding of packages that are already up-to-date.
In Go releases, does not apply to the standard library.
-n -n
print the commands but do not run them. print the commands but do not run them.
-p n -p n
@ -386,6 +387,7 @@ syntax of package template. The default output is equivalent to -f
type Package struct { type Package struct {
Dir string // directory containing package sources Dir string // directory containing package sources
ImportPath string // import path of package in dir ImportPath string // import path of package in dir
ImportComment string // path in import comment on package statement
Name string // package name Name string // package name
Doc string // package documentation string Doc string // package documentation string
Target string // install path Target string // install path
@ -524,16 +526,23 @@ non-test installation.
In addition to the build flags, the flags handled by 'go test' itself are: 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. -c
(Where pkg is the last element of the package's import path.) 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 -i
Install packages that are dependencies of the test. Install packages that are dependencies of the test.
Do not run the test. Do not run the test.
-exec xprog -o file
Run the test binary using xprog. The behavior is the same as Compile the test binary to the named file.
in 'go run'. See 'go help run' for details. The test still runs (unless -c or -i is specified).
The test binary also accepts flags that control execution of the test; these 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. 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 package made up of exactly those files, ignoring any build constraints
in those files and ignoring any other files in the directory. 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 Description of testing flags
@ -942,6 +952,7 @@ control the execution of any test:
-blockprofile block.out -blockprofile block.out
Write a goroutine blocking profile to the specified file Write a goroutine blocking profile to the specified file
when all tests are complete. when all tests are complete.
Writes test binary as -c would.
-blockprofilerate n -blockprofilerate n
Control the detail provided in goroutine blocking profiles by Control the detail provided in goroutine blocking profiles by
@ -973,8 +984,7 @@ control the execution of any test:
Sets -cover. Sets -cover.
-coverprofile cover.out -coverprofile cover.out
Write a coverage profile to the specified file after all tests Write a coverage profile to the file after all tests have passed.
have passed.
Sets -cover. Sets -cover.
-cpu 1,2,4 -cpu 1,2,4
@ -984,10 +994,11 @@ control the execution of any test:
-cpuprofile cpu.out -cpuprofile cpu.out
Write a CPU profile to the specified file before exiting. Write a CPU profile to the specified file before exiting.
Writes test binary as -c would.
-memprofile mem.out -memprofile mem.out
Write a memory profile to the specified file after all tests Write a memory profile to the file after all tests have passed.
have passed. Writes test binary as -c would.
-memprofilerate n -memprofilerate n
Enable more precise (and expensive) memory profiles by setting 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