mirror of https://github.com/golang/go.git
[dev.power64] all: merge default into dev.power64
This brings dev.power64 up-to-date with the current tip of default. go_bootstrap is still panicking with a bad defer when initializing the runtime (even on amd64). LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/152570049
This commit is contained in:
commit
f0bd539c59
|
|
@ -23,16 +23,12 @@ _test
|
||||||
_testmain.go
|
_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
|
||||||
|
|
|
||||||
4
.hgtags
4
.hgtags
|
|
@ -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
|
||||||
|
|
|
||||||
9
AUTHORS
9
AUTHORS
|
|
@ -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>
|
||||||
|
|
|
||||||
16
CONTRIBUTORS
16
CONTRIBUTORS
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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>.
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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—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—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">
|
||||||
|
|
|
||||||
274
doc/go_spec.html
274
doc/go_spec.html
|
|
@ -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—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 = &Point3D{y: 1000}
|
var pointer *Point3D = &Point3D{y: 1000}
|
||||||
|
|
@ -3604,7 +3677,7 @@ then the evaluation of <code>&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 &^= 1<<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>
|
||||||
|
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 199 KiB |
|
|
@ -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>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
|
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Expose some runtime functions for testing.
|
|
||||||
// Must be in a non-cgo-using package so that
|
|
||||||
// the go command compiles this file with 6c, not gcc.
|
|
||||||
|
|
||||||
// +build gc
|
|
||||||
|
|
||||||
typedef char bool;
|
|
||||||
|
|
||||||
// This is what a cgo-compiled stub declaration looks like.
|
|
||||||
void
|
|
||||||
·Issue7695(struct{void *y[8*sizeof(void*)];}p)
|
|
||||||
{
|
|
||||||
USED(p);
|
|
||||||
}
|
|
||||||
|
|
@ -157,3 +157,8 @@ func testUnsignedInt(t *testing.T) {
|
||||||
t.Errorf("Incorrect unsigned int - got %x, want %x", a, b)
|
t.Errorf("Incorrect unsigned int - got %x, want %x", a, b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Static (build-time) test that syntax traversal visits all operands of s[i:j:k].
|
||||||
|
func sliceOperands(array [2000]int) {
|
||||||
|
_ = array[C.KILO:C.KILO:C.KILO] // no type error
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,10 @@ void callback(void *f);
|
||||||
void callGoFoo(void);
|
void 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.
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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) }
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
@ -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")
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
@ -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++
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package cgotest
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <complex.h>
|
||||||
|
|
||||||
|
complex float complexFloatSquared(complex float a) { return a*a; }
|
||||||
|
complex double complexDoubleSquared(complex double a) { return a*a; }
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func test8694(t *testing.T) {
|
||||||
|
// Really just testing that this compiles, but check answer anyway.
|
||||||
|
x := complex64(2 + 3i)
|
||||||
|
x2 := x * x
|
||||||
|
cx2 := C.complexFloatSquared(x)
|
||||||
|
if cx2 != x2 {
|
||||||
|
t.Errorf("C.complexFloatSquared(%v) = %v, want %v", x, cx2, x2)
|
||||||
|
}
|
||||||
|
|
||||||
|
y := complex128(2 + 3i)
|
||||||
|
y2 := y * y
|
||||||
|
cy2 := C.complexDoubleSquared(y)
|
||||||
|
if cy2 != y2 {
|
||||||
|
t.Errorf("C.complexDoubleSquared(%v) = %v, want %v", y, cy2, y2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,10 +2,7 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// 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) {}
|
|
||||||
|
|
@ -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()
|
||||||
|
}
|
||||||
|
|
@ -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()
|
||||||
|
}
|
||||||
|
|
@ -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()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
package issue8828
|
||||||
|
|
||||||
|
//void foo();
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
func Bar() {
|
||||||
|
C.foo()
|
||||||
|
}
|
||||||
|
|
@ -437,7 +437,8 @@ func (b *Build) Do() error {
|
||||||
// Build package.
|
// 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.
|
||||||
|
|
|
||||||
|
|
@ -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='*'
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
--------------------
|
--------------------
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
// Copyright 2013 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// This file is here just to make the go tool happy.
|
|
||||||
|
|
@ -85,6 +85,7 @@ main(int argc, char *argv[])
|
||||||
ctxt = linknew(&linkarm);
|
ctxt = 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);
|
||||||
|
|
|
||||||
|
|
@ -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]--;
|
||||||
|
|
|
||||||
|
|
@ -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];
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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];
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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];
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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];
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
// Copyright 2013 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
#include <u.h>
|
|
||||||
#include "cc.h"
|
|
||||||
|
|
||||||
enum {
|
|
||||||
WORDSIZE = sizeof(uint32),
|
|
||||||
WORDBITS = 32,
|
|
||||||
};
|
|
||||||
|
|
||||||
uintptr
|
|
||||||
bvsize(uintptr n)
|
|
||||||
{
|
|
||||||
return ((n + WORDBITS - 1) / WORDBITS) * WORDSIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bvec*
|
|
||||||
bvalloc(int32 n)
|
|
||||||
{
|
|
||||||
Bvec *bv;
|
|
||||||
uintptr nbytes;
|
|
||||||
|
|
||||||
if(n < 0)
|
|
||||||
fatal(Z, "bvalloc: initial size is negative\n");
|
|
||||||
nbytes = sizeof(Bvec) + bvsize(n);
|
|
||||||
bv = malloc(nbytes);
|
|
||||||
if(bv == nil)
|
|
||||||
fatal(Z, "bvalloc: malloc failed\n");
|
|
||||||
memset(bv, 0, nbytes);
|
|
||||||
bv->n = n;
|
|
||||||
return bv;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
bvset(Bvec *bv, int32 i)
|
|
||||||
{
|
|
||||||
uint32 mask;
|
|
||||||
|
|
||||||
if(i < 0 || i >= bv->n)
|
|
||||||
fatal(Z, "bvset: index %d is out of bounds with length %d\n", i, bv->n);
|
|
||||||
mask = 1 << (i % WORDBITS);
|
|
||||||
bv->b[i / WORDBITS] |= mask;
|
|
||||||
}
|
|
||||||
|
|
@ -761,12 +761,6 @@ Bits blsh(uint);
|
||||||
int beq(Bits, Bits);
|
int 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
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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]);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
1025
src/cmd/cc/y.tab.c
1025
src/cmd/cc/y.tab.c
File diff suppressed because it is too large
Load Diff
|
|
@ -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 */
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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++;
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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*);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
@ -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 != "" {
|
||||||
|
|
|
||||||
|
|
@ -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
Loading…
Reference in New Issue