mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.ssa] Merge branch 'master' into dev.ssa
Change-Id: Iabc80b6e0734efbd234d998271e110d2eaad41dd
This commit is contained in:
commit
31e13c83c2
507 changed files with 31557 additions and 5826 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -26,6 +26,7 @@ misc/cgo/stdio/run.out
|
||||||
misc/cgo/testso/main
|
misc/cgo/testso/main
|
||||||
src/cmd/cgo/zdefaultcc.go
|
src/cmd/cgo/zdefaultcc.go
|
||||||
src/cmd/go/zdefaultcc.go
|
src/cmd/go/zdefaultcc.go
|
||||||
|
src/cmd/go/zosarch.go
|
||||||
src/cmd/internal/obj/zbootstrap.go
|
src/cmd/internal/obj/zbootstrap.go
|
||||||
src/go/build/zcgo.go
|
src/go/build/zcgo.go
|
||||||
src/go/doc/headscan
|
src/go/doc/headscan
|
||||||
|
|
|
||||||
90
AUTHORS
90
AUTHORS
|
|
@ -14,13 +14,17 @@ A Medium Corporation
|
||||||
Aamir Khan <syst3m.w0rm@gmail.com>
|
Aamir Khan <syst3m.w0rm@gmail.com>
|
||||||
Aaron France <aaron.l.france@gmail.com>
|
Aaron France <aaron.l.france@gmail.com>
|
||||||
Aaron Torres <tcboox@gmail.com>
|
Aaron Torres <tcboox@gmail.com>
|
||||||
|
Abe Haskins <abeisgreat@abeisgreat.com>
|
||||||
Abhinav Gupta <abhinav.g90@gmail.com>
|
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>
|
||||||
Aécio Júnior <aeciodantasjunior@gmail.com>
|
Aécio Júnior <aeciodantasjunior@gmail.com>
|
||||||
Ahmed Waheed Moanes <oneofone@gmail.com>
|
Ahmed Waheed Moanes <oneofone@gmail.com>
|
||||||
|
Ahmy Yulrizka <yulrizka@gmail.com>
|
||||||
|
Aiden Scandella <ai@uber.com>
|
||||||
Ainar Garipov <gugl.zadolbal@gmail.com>
|
Ainar Garipov <gugl.zadolbal@gmail.com>
|
||||||
|
Akihiro Suda <suda.kyoto@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>
|
||||||
|
|
@ -28,6 +32,7 @@ Alberto Bertogli <albertito@blitiri.com.ar>
|
||||||
Alberto Donizetti <alb.donizetti@gmail.com>
|
Alberto Donizetti <alb.donizetti@gmail.com>
|
||||||
Alberto García Hierro <alberto@garciahierro.com> <alberto.garcia.hierro@gmail.com>
|
Alberto García Hierro <alberto@garciahierro.com> <alberto.garcia.hierro@gmail.com>
|
||||||
Aleksandar Dezelin <dezelin@gmail.com>
|
Aleksandar Dezelin <dezelin@gmail.com>
|
||||||
|
Alessandro Arzilli <alessandro.arzilli@gmail.com>
|
||||||
Alex A Skinner <alex@lx.lc>
|
Alex A Skinner <alex@lx.lc>
|
||||||
Alex Brainman <alex.brainman@gmail.com>
|
Alex Brainman <alex.brainman@gmail.com>
|
||||||
Alex Jin <toalexjin@gmail.com>
|
Alex Jin <toalexjin@gmail.com>
|
||||||
|
|
@ -50,8 +55,10 @@ Alexey Borzenkov <snaury@gmail.com>
|
||||||
Alexey Palazhchenko <alexey.palazhchenko@gmail.com>
|
Alexey Palazhchenko <alexey.palazhchenko@gmail.com>
|
||||||
Aliaksandr Valialkin <valyala@gmail.com>
|
Aliaksandr Valialkin <valyala@gmail.com>
|
||||||
Alif Rachmawadi <subosito@gmail.com>
|
Alif Rachmawadi <subosito@gmail.com>
|
||||||
|
Amazon.com, Inc
|
||||||
Amir Mohammad Saied <amir@gluegadget.com>
|
Amir Mohammad Saied <amir@gluegadget.com>
|
||||||
Amrut Joshi <amrut.joshi@gmail.com>
|
Amrut Joshi <amrut.joshi@gmail.com>
|
||||||
|
Andre Nathan <andrenth@gmail.com>
|
||||||
Andrei Korzhevskii <a.korzhevskiy@gmail.com>
|
Andrei Korzhevskii <a.korzhevskiy@gmail.com>
|
||||||
Andrei Vieru <euvieru@gmail.com>
|
Andrei Vieru <euvieru@gmail.com>
|
||||||
Andrew Balholm <andybalholm@gmail.com>
|
Andrew Balholm <andybalholm@gmail.com>
|
||||||
|
|
@ -85,6 +92,8 @@ Anthony Starks <ajstarks@gmail.com>
|
||||||
Apisak Darakananda <pongad@gmail.com>
|
Apisak Darakananda <pongad@gmail.com>
|
||||||
Aram Hăvărneanu <aram@mgk.ro>
|
Aram Hăvărneanu <aram@mgk.ro>
|
||||||
Areski Belaid <areski@gmail.com>
|
Areski Belaid <areski@gmail.com>
|
||||||
|
Arlo Breault <arlolra@gmail.com>
|
||||||
|
ARM Ltd.
|
||||||
Arnaud Ysmal <arnaud.ysmal@gmail.com>
|
Arnaud Ysmal <arnaud.ysmal@gmail.com>
|
||||||
Arne Hormann <arnehormann@gmail.com>
|
Arne Hormann <arnehormann@gmail.com>
|
||||||
Arnout Engelen <arnout@bzzt.net>
|
Arnout Engelen <arnout@bzzt.net>
|
||||||
|
|
@ -92,6 +101,8 @@ Aron Nopanen <aron.nopanen@gmail.com>
|
||||||
Artyom Pervukhin <artyom.pervukhin@gmail.com>
|
Artyom Pervukhin <artyom.pervukhin@gmail.com>
|
||||||
Arvindh Rajesh Tamilmani <art@a-30.net>
|
Arvindh Rajesh Tamilmani <art@a-30.net>
|
||||||
Ato Araki <ato.araki@gmail.com>
|
Ato Araki <ato.araki@gmail.com>
|
||||||
|
Audrey Lim <audreylh@gmail.com>
|
||||||
|
Augusto Roman <aroman@gmail.com>
|
||||||
Aulus Egnatius Varialus <varialus@gmail.com>
|
Aulus Egnatius Varialus <varialus@gmail.com>
|
||||||
awaw fumin <awawfumin@gmail.com>
|
awaw fumin <awawfumin@gmail.com>
|
||||||
Aymerick Jéhanne <aymerick@jehanne.org>
|
Aymerick Jéhanne <aymerick@jehanne.org>
|
||||||
|
|
@ -107,6 +118,8 @@ Bjorn Tipling <bjorn.tipling@gmail.com>
|
||||||
Blake Gentry <blakesgentry@gmail.com>
|
Blake Gentry <blakesgentry@gmail.com>
|
||||||
Blake Mizerany <blake.mizerany@gmail.com>
|
Blake Mizerany <blake.mizerany@gmail.com>
|
||||||
Bobby Powers <bobbypowers@gmail.com>
|
Bobby Powers <bobbypowers@gmail.com>
|
||||||
|
Brady Catherman <brady@gmail.com>
|
||||||
|
Brady Sullivan <brady@bsull.com>
|
||||||
Brendan Daniel Tracey <tracey.brendan@gmail.com>
|
Brendan Daniel Tracey <tracey.brendan@gmail.com>
|
||||||
Brett Cannon <bcannon@gmail.com>
|
Brett Cannon <bcannon@gmail.com>
|
||||||
Brian Dellisanti <briandellisanti@gmail.com>
|
Brian Dellisanti <briandellisanti@gmail.com>
|
||||||
|
|
@ -140,17 +153,21 @@ Christoffer Buchholz <christoffer.buchholz@gmail.com>
|
||||||
Christoph Hack <christoph@tux21b.org>
|
Christoph Hack <christoph@tux21b.org>
|
||||||
Christopher Cahoon <chris.cahoon@gmail.com>
|
Christopher Cahoon <chris.cahoon@gmail.com>
|
||||||
Christopher Guiney <chris@guiney.net>
|
Christopher Guiney <chris@guiney.net>
|
||||||
|
Christopher Nelson <nadiasvertex@gmail.com>
|
||||||
Christopher Nielsen <m4dh4tt3r@gmail.com>
|
Christopher Nielsen <m4dh4tt3r@gmail.com>
|
||||||
Christopher Redden <christopher.redden@gmail.com>
|
Christopher Redden <christopher.redden@gmail.com>
|
||||||
Christopher Wedgwood <cw@f00f.org>
|
Christopher Wedgwood <cw@f00f.org>
|
||||||
CL Sung <clsung@gmail.com> <cl_sung@htc.com>
|
CL Sung <clsung@gmail.com> <cl_sung@htc.com>
|
||||||
Clement Skau <clementskau@gmail.com>
|
Clement Skau <clementskau@gmail.com>
|
||||||
CloudFlare Inc.
|
CloudFlare Inc.
|
||||||
|
Colin Edwards <colin@recursivepenguin.com>
|
||||||
Colin Kennedy <moshen.colin@gmail.com>
|
Colin Kennedy <moshen.colin@gmail.com>
|
||||||
|
Conrad Irwin <conrad.irwin@gmail.com>
|
||||||
Conrad Meyer <cemeyer@cs.washington.edu>
|
Conrad Meyer <cemeyer@cs.washington.edu>
|
||||||
CoreOS, Inc.
|
CoreOS, Inc.
|
||||||
Corey Thomasson <cthom.lists@gmail.com>
|
Corey Thomasson <cthom.lists@gmail.com>
|
||||||
Cristian Staretu <unclejacksons@gmail.com>
|
Cristian Staretu <unclejacksons@gmail.com>
|
||||||
|
Currant
|
||||||
Damian Gryski <dgryski@gmail.com>
|
Damian Gryski <dgryski@gmail.com>
|
||||||
Dan Caddigan <goldcaddy77@gmail.com>
|
Dan Caddigan <goldcaddy77@gmail.com>
|
||||||
Dan Callahan <dan.callahan@gmail.com>
|
Dan Callahan <dan.callahan@gmail.com>
|
||||||
|
|
@ -164,9 +181,12 @@ Daniel Lidén <daniel.liden.87@gmail.com>
|
||||||
Daniel Morsing <daniel.morsing@gmail.com>
|
Daniel Morsing <daniel.morsing@gmail.com>
|
||||||
Daniel Ortiz Pereira da Silva <daniel.particular@gmail.com>
|
Daniel Ortiz Pereira da Silva <daniel.particular@gmail.com>
|
||||||
Daniel Skinner <daniel@dasa.cc>
|
Daniel Skinner <daniel@dasa.cc>
|
||||||
|
Daniel Speichert <daniel@speichert.pl>
|
||||||
Daniel Theophanes <kardianos@gmail.com>
|
Daniel Theophanes <kardianos@gmail.com>
|
||||||
Darren Elwood <darren@textnode.com>
|
Darren Elwood <darren@textnode.com>
|
||||||
|
Datong Sun <dndx@idndx.com>
|
||||||
Dave Cheney <dave@cheney.net>
|
Dave Cheney <dave@cheney.net>
|
||||||
|
David Brophy <dave@brophy.uk>
|
||||||
David Bürgin <676c7473@gmail.com>
|
David Bürgin <676c7473@gmail.com>
|
||||||
David Calavera <david.calavera@gmail.com>
|
David Calavera <david.calavera@gmail.com>
|
||||||
David du Colombier <0intro@gmail.com>
|
David du Colombier <0intro@gmail.com>
|
||||||
|
|
@ -176,21 +196,26 @@ David Howden <dhowden@gmail.com>
|
||||||
David Jakob Fritz <david.jakob.fritz@gmail.com>
|
David Jakob Fritz <david.jakob.fritz@gmail.com>
|
||||||
David Leon Gil <coruus@gmail.com>
|
David Leon Gil <coruus@gmail.com>
|
||||||
David R. Jenni <david.r.jenni@gmail.com>
|
David R. Jenni <david.r.jenni@gmail.com>
|
||||||
|
David Sansome <me@davidsansome.com>
|
||||||
David Thomas <davidthomas426@gmail.com>
|
David Thomas <davidthomas426@gmail.com>
|
||||||
David Titarenco <david.titarenco@gmail.com>
|
David Titarenco <david.titarenco@gmail.com>
|
||||||
Davies Liu <davies.liu@gmail.com>
|
Davies Liu <davies.liu@gmail.com>
|
||||||
Dean Prichard <dean.prichard@gmail.com>
|
Dean Prichard <dean.prichard@gmail.com>
|
||||||
Denis Bernard <db047h@gmail.com>
|
Denis Bernard <db047h@gmail.com>
|
||||||
Denis Brandolini <denis.brandolini@gmail.com>
|
Denis Brandolini <denis.brandolini@gmail.com>
|
||||||
|
Denys Honsiorovskyi <honsiorovskyi@gmail.com>
|
||||||
Derek Buitenhuis <derek.buitenhuis@gmail.com>
|
Derek Buitenhuis <derek.buitenhuis@gmail.com>
|
||||||
Derek Parker <parkerderek86@gmail.com>
|
Derek Parker <parkerderek86@gmail.com>
|
||||||
|
Derek Shockey <derek.shockey@gmail.com>
|
||||||
Develer SRL
|
Develer SRL
|
||||||
Devon H. O'Dell <devon.odell@gmail.com>
|
Devon H. O'Dell <devon.odell@gmail.com>
|
||||||
Dhiru Kholia <dhiru.kholia@gmail.com>
|
Dhiru Kholia <dhiru.kholia@gmail.com>
|
||||||
Didier Spezia <didier.06@gmail.com>
|
Didier Spezia <didier.06@gmail.com>
|
||||||
Dimitri Tcaciuc <dtcaciuc@gmail.com>
|
Dimitri Tcaciuc <dtcaciuc@gmail.com>
|
||||||
Dirk Gadsden <dirk@esherido.com>
|
Dirk Gadsden <dirk@esherido.com>
|
||||||
|
Diwaker Gupta <diwakergupta@gmail.com>
|
||||||
Dmitri Shuralyov <shurcooL@gmail.com>
|
Dmitri Shuralyov <shurcooL@gmail.com>
|
||||||
|
Dmitriy Dudkin <dudkin.dmitriy@gmail.com>
|
||||||
Dmitriy Shelenin <deemok@googlemail.com> <deemok@gmail.com>
|
Dmitriy Shelenin <deemok@googlemail.com> <deemok@gmail.com>
|
||||||
Dmitry Chestnykh <dchest@gmail.com>
|
Dmitry Chestnykh <dchest@gmail.com>
|
||||||
Dmitry Savintsev <dsavints@gmail.com>
|
Dmitry Savintsev <dsavints@gmail.com>
|
||||||
|
|
@ -200,6 +225,7 @@ Donald Huang <don.hcd@gmail.com>
|
||||||
Donovan Hide <donovanhide@gmail.com>
|
Donovan Hide <donovanhide@gmail.com>
|
||||||
Dropbox, Inc.
|
Dropbox, Inc.
|
||||||
Duncan Holm <mail@frou.org>
|
Duncan Holm <mail@frou.org>
|
||||||
|
Dustin Herbison <djherbis@gmail.com>
|
||||||
Dustin Sallings <dsallings@gmail.com>
|
Dustin Sallings <dsallings@gmail.com>
|
||||||
Dustin Shields-Cloues <dcloues@gmail.com>
|
Dustin Shields-Cloues <dcloues@gmail.com>
|
||||||
Dvir Volk <dvir@everything.me> <dvirsky@gmail.com>
|
Dvir Volk <dvir@everything.me> <dvirsky@gmail.com>
|
||||||
|
|
@ -220,6 +246,7 @@ Erik Aigner <aigner.erik@gmail.com>
|
||||||
Erik Dubbelboer <erik@dubbelboer.com>
|
Erik Dubbelboer <erik@dubbelboer.com>
|
||||||
Erik St. Martin <alakriti@gmail.com>
|
Erik St. Martin <alakriti@gmail.com>
|
||||||
Erik Westrup <erik.westrup@gmail.com>
|
Erik Westrup <erik.westrup@gmail.com>
|
||||||
|
Ernest Chiang <ernest_chiang@htc.com>
|
||||||
Esko Luontola <esko.luontola@gmail.com>
|
Esko Luontola <esko.luontola@gmail.com>
|
||||||
Evan Phoenix <evan@phx.io>
|
Evan Phoenix <evan@phx.io>
|
||||||
Evan Shaw <chickencha@gmail.com>
|
Evan Shaw <chickencha@gmail.com>
|
||||||
|
|
@ -241,6 +268,7 @@ Francisco Souza <franciscossouza@gmail.com>
|
||||||
Frederick Kelly Mayle III <frederickmayle@gmail.com>
|
Frederick Kelly Mayle III <frederickmayle@gmail.com>
|
||||||
Fredrik Enestad <fredrik.enestad@soundtrackyourbrand.com>
|
Fredrik Enestad <fredrik.enestad@soundtrackyourbrand.com>
|
||||||
Frithjof Schulze <schulze@math.uni-hannover.de> <sfrithjof@gmail.com>
|
Frithjof Schulze <schulze@math.uni-hannover.de> <sfrithjof@gmail.com>
|
||||||
|
Frits van Bommel <fvbommel@gmail.com>
|
||||||
Gabriel Aszalos <gabriel.aszalos@gmail.com>
|
Gabriel Aszalos <gabriel.aszalos@gmail.com>
|
||||||
Gary Burd <gary@beagledreams.com>
|
Gary Burd <gary@beagledreams.com>
|
||||||
Gaurish Sharma <contact@gaurishsharma.com>
|
Gaurish Sharma <contact@gaurishsharma.com>
|
||||||
|
|
@ -266,30 +294,37 @@ Hajime Hoshi <hajimehoshi@gmail.com>
|
||||||
Hari haran <hariharan.uno@gmail.com>
|
Hari haran <hariharan.uno@gmail.com>
|
||||||
Hariharan Srinath <srinathh@gmail.com>
|
Hariharan Srinath <srinathh@gmail.com>
|
||||||
Harley Laue <losinggeneration@gmail.com>
|
Harley Laue <losinggeneration@gmail.com>
|
||||||
|
Harshavardhana <hrshvardhana@gmail.com>
|
||||||
Håvard Haugen <havard.haugen@gmail.com>
|
Håvard Haugen <havard.haugen@gmail.com>
|
||||||
Hector Chu <hectorchu@gmail.com>
|
Hector Chu <hectorchu@gmail.com>
|
||||||
Hector Martin Cantero <hector@marcansoft.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>
|
||||||
|
Hironao OTSUBO <motemen@gmail.com>
|
||||||
Hiroshi Ioka <hirochachacha@gmail.com>
|
Hiroshi Ioka <hirochachacha@gmail.com>
|
||||||
|
Hitoshi Mitake <mitake.hitoshi@gmail.com>
|
||||||
|
Holden Huang <ttyh061@gmail.com>
|
||||||
Hong Ruiqi <hongruiqi@gmail.com>
|
Hong Ruiqi <hongruiqi@gmail.com>
|
||||||
Hsin-Ho Yeh <yhh92u@gmail.com>
|
Hsin-Ho Yeh <yhh92u@gmail.com>
|
||||||
Hu Keping <hukeping@huawei.com>
|
Hu Keping <hukeping@huawei.com>
|
||||||
Ian Gudger <ian@loosescre.ws>
|
Ian Gudger <ian@loosescre.ws>
|
||||||
IBM
|
IBM
|
||||||
Icarus Sparry <golang@icarus.freeuk.com>
|
Icarus Sparry <golang@icarus.freeuk.com>
|
||||||
|
Idora Shinatose <idora.shinatose@gmail.com>
|
||||||
Igneous Systems, Inc.
|
Igneous Systems, Inc.
|
||||||
Igor Dolzhikov <bluesriverz@gmail.com>
|
Igor Dolzhikov <bluesriverz@gmail.com>
|
||||||
INADA Naoki <songofacandy@gmail.com>
|
INADA Naoki <songofacandy@gmail.com>
|
||||||
Ingo Krabbe <ikrabbe.ask@gmail.com>
|
Ingo Krabbe <ikrabbe.ask@gmail.com>
|
||||||
Ingo Oeser <nightlyone@googlemail.com>
|
Ingo Oeser <nightlyone@googlemail.com>
|
||||||
Intel Corporation
|
Intel Corporation
|
||||||
|
Irieda Noboru <irieda@gmail.com>
|
||||||
Isaac Wagner <ibw@isaacwagner.me>
|
Isaac Wagner <ibw@isaacwagner.me>
|
||||||
Ivan Ukhov <ivan.ukhov@gmail.com>
|
Ivan Ukhov <ivan.ukhov@gmail.com>
|
||||||
Jae Kwon <jae@tendermint.com>
|
Jae Kwon <jae@tendermint.com>
|
||||||
Jakob Borg <jakob@nym.se>
|
Jakob Borg <jakob@nym.se>
|
||||||
Jakub Ryszard Czarnowicz <j.czarnowicz@gmail.com>
|
Jakub Ryszard Czarnowicz <j.czarnowicz@gmail.com>
|
||||||
|
James Bardin <j.bardin@gmail.com>
|
||||||
James David Chalfant <james.chalfant@gmail.com>
|
James David Chalfant <james.chalfant@gmail.com>
|
||||||
James Fysh <james.fysh@gmail.com>
|
James Fysh <james.fysh@gmail.com>
|
||||||
James Gray <james@james4k.com>
|
James Gray <james@james4k.com>
|
||||||
|
|
@ -299,6 +334,7 @@ James Schofield <james@shoeboxapp.com>
|
||||||
James Sweet <james.sweet88@googlemail.com>
|
James Sweet <james.sweet88@googlemail.com>
|
||||||
James Toy <nil@opensesame.st>
|
James Toy <nil@opensesame.st>
|
||||||
James Whitehead <jnwhiteh@gmail.com>
|
James Whitehead <jnwhiteh@gmail.com>
|
||||||
|
Jamil Djadala <djadala@gmail.com>
|
||||||
Jan H. Hosang <jan.hosang@gmail.com>
|
Jan H. Hosang <jan.hosang@gmail.com>
|
||||||
Jan Mercl <0xjnml@gmail.com>
|
Jan Mercl <0xjnml@gmail.com>
|
||||||
Jan Mercl <befelemepeseveze@gmail.com>
|
Jan Mercl <befelemepeseveze@gmail.com>
|
||||||
|
|
@ -315,6 +351,7 @@ Jeff Sickel <jas@corpus-callosum.com>
|
||||||
Jeff Wendling <jeff@spacemonkey.com>
|
Jeff Wendling <jeff@spacemonkey.com>
|
||||||
Jens Frederich <jfrederich@gmail.com>
|
Jens Frederich <jfrederich@gmail.com>
|
||||||
Jeremy Jackins <jeremyjackins@gmail.com>
|
Jeremy Jackins <jeremyjackins@gmail.com>
|
||||||
|
Jess Frazelle <me@jessfraz.com>
|
||||||
Jihyun Yu <yjh0502@gmail.com>
|
Jihyun Yu <yjh0502@gmail.com>
|
||||||
Jim McGrath <jimmc2@gmail.com>
|
Jim McGrath <jimmc2@gmail.com>
|
||||||
Jimmy Zelinskie <jimmyzelinskie@gmail.com>
|
Jimmy Zelinskie <jimmyzelinskie@gmail.com>
|
||||||
|
|
@ -323,16 +360,21 @@ Jingguo Yao <yaojingguo@gmail.com>
|
||||||
Jiong Du <londevil@gmail.com>
|
Jiong Du <londevil@gmail.com>
|
||||||
Joakim Sernbrant <serbaut@gmail.com>
|
Joakim Sernbrant <serbaut@gmail.com>
|
||||||
Joe Harrison <joehazzers@gmail.com>
|
Joe Harrison <joehazzers@gmail.com>
|
||||||
|
Joe Henke <joed.henke@gmail.com>
|
||||||
Joe Poirier <jdpoirier@gmail.com>
|
Joe Poirier <jdpoirier@gmail.com>
|
||||||
Joe Shaw <joe@joeshaw.org>
|
Joe Shaw <joe@joeshaw.org>
|
||||||
|
Joe Sylve <joe.sylve@gmail.com>
|
||||||
Joe Tsai <joetsai@digital-static.net>
|
Joe Tsai <joetsai@digital-static.net>
|
||||||
Joel Stemmer <stemmertech@gmail.com>
|
Joel Stemmer <stemmertech@gmail.com>
|
||||||
|
Johan Sageryd <j@1616.se>
|
||||||
John Asmuth <jasmuth@gmail.com>
|
John Asmuth <jasmuth@gmail.com>
|
||||||
John C Barstow <jbowtie@amathaine.com>
|
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 Jeffery <jjeffery@sp.com.au>
|
||||||
John Jenkins <twodopeshaggy@gmail.com>
|
John Jenkins <twodopeshaggy@gmail.com>
|
||||||
John Potocny <johnp@vividcortex.com>
|
John Potocny <johnp@vividcortex.com>
|
||||||
|
John Schnake <schnake.john@gmail.com>
|
||||||
John Shahid <jvshahid@gmail.com>
|
John Shahid <jvshahid@gmail.com>
|
||||||
John Tuley <john@tuley.org>
|
John Tuley <john@tuley.org>
|
||||||
Jonathan Boulle <jonathanboulle@gmail.com>
|
Jonathan Boulle <jonathanboulle@gmail.com>
|
||||||
|
|
@ -366,8 +408,13 @@ Kelvin Foo Chuan Lyi <vmirage@gmail.com>
|
||||||
Ken Friedenbach <kenliz@cruzio.com>
|
Ken Friedenbach <kenliz@cruzio.com>
|
||||||
Ken Rockot <ken@oz.gs>
|
Ken Rockot <ken@oz.gs>
|
||||||
Ken Sedgwick <ken@bonsai.com>
|
Ken Sedgwick <ken@bonsai.com>
|
||||||
|
Kenji Kaneda <kenji.kaneda@gmail.com>
|
||||||
|
Kenneth Shaw <kenshaw@gmail.com>
|
||||||
Kenny Grant <kennygrant@gmail.com>
|
Kenny Grant <kennygrant@gmail.com>
|
||||||
Kevin Ballard <kevin@sb.org>
|
Kevin Ballard <kevin@sb.org>
|
||||||
|
Kevin Burke <kev@inburke.com>
|
||||||
|
Kevin Kirsche <kev.kirsche@gmail.com>
|
||||||
|
Kevin Vu <kevin.m.vu@gmail.com>
|
||||||
Klaus Post <klauspost@gmail.com>
|
Klaus Post <klauspost@gmail.com>
|
||||||
Konstantin Shaposhnikov <k.shaposhnikov@gmail.com>
|
Konstantin Shaposhnikov <k.shaposhnikov@gmail.com>
|
||||||
KPCompass, Inc.
|
KPCompass, Inc.
|
||||||
|
|
@ -379,12 +426,14 @@ Kyle Lemons <kyle@kylelemons.net>
|
||||||
L Campbell <unpantsu@gmail.com>
|
L Campbell <unpantsu@gmail.com>
|
||||||
Lai Jiangshan <eag0628@gmail.com>
|
Lai Jiangshan <eag0628@gmail.com>
|
||||||
Larz Conwell <larzconwell@gmail.com>
|
Larz Conwell <larzconwell@gmail.com>
|
||||||
|
Lee Hinman <hinman@gmail.com>
|
||||||
Lee Packham <lpackham@gmail.com>
|
Lee Packham <lpackham@gmail.com>
|
||||||
Lewin Bormann <lewin.bormann@gmail.com>
|
Lewin Bormann <lewin.bormann@gmail.com>
|
||||||
Liberty Fund Inc
|
Liberty Fund Inc
|
||||||
Linaro Limited
|
Linaro Limited
|
||||||
Lloyd Dewolf <foolswisdom@gmail.com>
|
Lloyd Dewolf <foolswisdom@gmail.com>
|
||||||
Lorenzo Stoakes <lstoakes@gmail.com>
|
Lorenzo Stoakes <lstoakes@gmail.com>
|
||||||
|
Luan Santos <cfcluan@gmail.com>
|
||||||
Luca Greco <luca.greco@alcacoop.it>
|
Luca Greco <luca.greco@alcacoop.it>
|
||||||
Lucien Stuker <lucien.stuker@gmail.com>
|
Lucien Stuker <lucien.stuker@gmail.com>
|
||||||
Lucio De Re <lucio.dere@gmail.com>
|
Lucio De Re <lucio.dere@gmail.com>
|
||||||
|
|
@ -397,6 +446,7 @@ Manuel Mendez <mmendez534@gmail.com>
|
||||||
Marc Weistroff <marc@weistroff.net>
|
Marc Weistroff <marc@weistroff.net>
|
||||||
Marco Hennings <marco.hennings@freiheit.com>
|
Marco Hennings <marco.hennings@freiheit.com>
|
||||||
Mark Bucciarelli <mkbucc@gmail.com>
|
Mark Bucciarelli <mkbucc@gmail.com>
|
||||||
|
Mark Severson <miquella@gmail.com>
|
||||||
Mark Theunissen <mark.theunissen@gmail.com>
|
Mark Theunissen <mark.theunissen@gmail.com>
|
||||||
Marko Juhani Silokunnas <marko.silokunnas@gmail.com>
|
Marko Juhani Silokunnas <marko.silokunnas@gmail.com>
|
||||||
Marko Tiikkaja <marko@joh.to>
|
Marko Tiikkaja <marko@joh.to>
|
||||||
|
|
@ -404,12 +454,14 @@ Markover Inc. DBA Poptip
|
||||||
Markus Duft <markus.duft@salomon.at>
|
Markus Duft <markus.duft@salomon.at>
|
||||||
Markus Sonderegger <marraison@gmail.com>
|
Markus Sonderegger <marraison@gmail.com>
|
||||||
Markus Zimmermann <zimmski@gmail.com>
|
Markus Zimmermann <zimmski@gmail.com>
|
||||||
|
Martin Garton <garton@gmail.com>
|
||||||
Martin Möhrmann <martisch@uos.de>
|
Martin Möhrmann <martisch@uos.de>
|
||||||
Martin Neubauer <m.ne@gmx.net>
|
Martin Neubauer <m.ne@gmx.net>
|
||||||
Martin Olsson <martin@minimum.se>
|
Martin Olsson <martin@minimum.se>
|
||||||
Marvin Stenger <marvin.stenger94@gmail.com>
|
Marvin Stenger <marvin.stenger94@gmail.com>
|
||||||
Mateusz Czapliński <czapkofan@gmail.com>
|
Mateusz Czapliński <czapkofan@gmail.com>
|
||||||
Mathias Beke <git@denbeke.be>
|
Mathias Beke <git@denbeke.be>
|
||||||
|
Mathias Leppich <mleppich@muhqu.de>
|
||||||
Mathieu Lonjaret <mathieu.lonjaret@gmail.com>
|
Mathieu Lonjaret <mathieu.lonjaret@gmail.com>
|
||||||
Mats Lidell <mats.lidell@cag.se>
|
Mats Lidell <mats.lidell@cag.se>
|
||||||
Matt Aimonetti <mattaimonetti@gmail.com>
|
Matt Aimonetti <mattaimonetti@gmail.com>
|
||||||
|
|
@ -419,6 +471,7 @@ Matt Jibson <matt.jibson@gmail.com>
|
||||||
Matt Joiner <anacrolix@gmail.com>
|
Matt Joiner <anacrolix@gmail.com>
|
||||||
Matt Layher <mdlayher@gmail.com>
|
Matt Layher <mdlayher@gmail.com>
|
||||||
Matt Reiferson <mreiferson@gmail.com>
|
Matt Reiferson <mreiferson@gmail.com>
|
||||||
|
Matt Robenolt <matt@ydekproductions.com>
|
||||||
Matt T. Proud <matt.proud@gmail.com>
|
Matt T. Proud <matt.proud@gmail.com>
|
||||||
Matt Williams <gh@mattyw.net>
|
Matt Williams <gh@mattyw.net>
|
||||||
Matthew Brennan <matty.brennan@gmail.com>
|
Matthew Brennan <matty.brennan@gmail.com>
|
||||||
|
|
@ -426,6 +479,7 @@ Matthew Cottingham <mattcottingham@gmail.com>
|
||||||
Matthew Holt <Matthew.Holt+git@gmail.com>
|
Matthew Holt <Matthew.Holt+git@gmail.com>
|
||||||
Matthew Horsnell <matthew.horsnell@gmail.com>
|
Matthew Horsnell <matthew.horsnell@gmail.com>
|
||||||
Maxim Khitrov <max@mxcrypt.com>
|
Maxim Khitrov <max@mxcrypt.com>
|
||||||
|
Maxwell Krohn <themax@gmail.com>
|
||||||
Meir Fischer <meirfischer@gmail.com>
|
Meir Fischer <meirfischer@gmail.com>
|
||||||
Meng Zhuo <mengzhuo1203@gmail.com>
|
Meng Zhuo <mengzhuo1203@gmail.com>
|
||||||
Meteor Development Group
|
Meteor Development Group
|
||||||
|
|
@ -439,6 +493,7 @@ Michael Hoisie <hoisie@gmail.com>
|
||||||
Michael Käufl <golang@c.michael-kaeufl.de>
|
Michael Käufl <golang@c.michael-kaeufl.de>
|
||||||
Michael Lewis <mikelikespie@gmail.com>
|
Michael Lewis <mikelikespie@gmail.com>
|
||||||
Michael MacInnis <Michael.P.MacInnis@gmail.com>
|
Michael MacInnis <Michael.P.MacInnis@gmail.com>
|
||||||
|
Michael McConville <momcconville@gmail.com>
|
||||||
Michael Pearson <mipearson@gmail.com>
|
Michael Pearson <mipearson@gmail.com>
|
||||||
Michael Schaller <michael@5challer.de>
|
Michael Schaller <michael@5challer.de>
|
||||||
Michael Stapelberg <michael@stapelberg.de>
|
Michael Stapelberg <michael@stapelberg.de>
|
||||||
|
|
@ -451,15 +506,19 @@ Mihai Borobocea <MihaiBorobocea@gmail.com>
|
||||||
Mikael Tillenius <mikti42@gmail.com>
|
Mikael Tillenius <mikti42@gmail.com>
|
||||||
Mike Andrews <mra@xoba.com>
|
Mike Andrews <mra@xoba.com>
|
||||||
Mike Rosset <mike.rosset@gmail.com>
|
Mike Rosset <mike.rosset@gmail.com>
|
||||||
|
Mikhail Gusarov <dottedmag@dottedmag.net>
|
||||||
Mikhail Panchenko <m@mihasya.com>
|
Mikhail Panchenko <m@mihasya.com>
|
||||||
Miki Tebeka <miki.tebeka@gmail.com>
|
Miki Tebeka <miki.tebeka@gmail.com>
|
||||||
Mikio Hara <mikioh.mikioh@gmail.com>
|
Mikio Hara <mikioh.mikioh@gmail.com>
|
||||||
Mikkel Krautz <mikkel@krautz.dk>
|
Mikkel Krautz <mikkel@krautz.dk>
|
||||||
Miquel Sabaté Solà <mikisabate@gmail.com>
|
Miquel Sabaté Solà <mikisabate@gmail.com>
|
||||||
Mohit Agarwal <mohit@sdf.org>
|
Mohit Agarwal <mohit@sdf.org>
|
||||||
|
Monty Taylor <mordred@inaugust.com>
|
||||||
Moov Corporation
|
Moov Corporation
|
||||||
Moriyoshi Koizumi <mozo@mozo.jp>
|
Moriyoshi Koizumi <mozo@mozo.jp>
|
||||||
|
Morten Siebuhr <sbhr@sbhr.dk>
|
||||||
Môshe van der Sterre <moshevds@gmail.com>
|
Môshe van der Sterre <moshevds@gmail.com>
|
||||||
|
Muhammed Uluyol <uluyol0@gmail.com>
|
||||||
Nan Deng <monnand@gmail.com>
|
Nan Deng <monnand@gmail.com>
|
||||||
Nathan John Youngman <nj@nathany.com>
|
Nathan John Youngman <nj@nathany.com>
|
||||||
Nathan Otterness <otternes@cs.unc.edu>
|
Nathan Otterness <otternes@cs.unc.edu>
|
||||||
|
|
@ -467,17 +526,23 @@ Nathan P Finch <nate.finch@gmail.com>
|
||||||
Nathan VanBenschoten <nvanbenschoten@gmail.com>
|
Nathan VanBenschoten <nvanbenschoten@gmail.com>
|
||||||
Nathan Youngman <git@nathany.com>
|
Nathan Youngman <git@nathany.com>
|
||||||
Neelesh Chandola <neelesh.c98@gmail.com>
|
Neelesh Chandola <neelesh.c98@gmail.com>
|
||||||
|
Netflix, Inc.
|
||||||
Nevins Bartolomeo <nevins.bartolomeo@gmail.com>
|
Nevins Bartolomeo <nevins.bartolomeo@gmail.com>
|
||||||
ngmoco, LLC
|
ngmoco, LLC
|
||||||
|
Niall Sheridan <nsheridan@gmail.com>
|
||||||
Nicholas Katsaros <nick@nickkatsaros.com>
|
Nicholas Katsaros <nick@nickkatsaros.com>
|
||||||
Nicholas Presta <nick@nickpresta.ca> <nick1presta@gmail.com>
|
Nicholas Presta <nick@nickpresta.ca> <nick1presta@gmail.com>
|
||||||
Nicholas Sullivan <nicholas.sullivan@gmail.com>
|
Nicholas Sullivan <nicholas.sullivan@gmail.com>
|
||||||
Nicholas Waples <nwaples@gmail.com>
|
Nicholas Waples <nwaples@gmail.com>
|
||||||
Nick Craig-Wood <nick@craig-wood.com> <nickcw@gmail.com>
|
Nick Craig-Wood <nick@craig-wood.com> <nickcw@gmail.com>
|
||||||
|
Nick Patavalis <nick.patavalis@gmail.com>
|
||||||
|
Nick Petroni <npetroni@cs.umd.edu>
|
||||||
Nicolas Kaiser <nikai@nikai.net>
|
Nicolas Kaiser <nikai@nikai.net>
|
||||||
Nicolas Owens <mischief@offblast.org>
|
Nicolas Owens <mischief@offblast.org>
|
||||||
Nicolas S. Dade <nic.dade@gmail.com>
|
Nicolas S. Dade <nic.dade@gmail.com>
|
||||||
|
Niels Widger <niels.widger@gmail.com>
|
||||||
Nigel Kerr <nigel.kerr@gmail.com>
|
Nigel Kerr <nigel.kerr@gmail.com>
|
||||||
|
Niko Dziemba <niko@dziemba.com>
|
||||||
Nikolay Turpitko <nikolay@turpitko.com>
|
Nikolay Turpitko <nikolay@turpitko.com>
|
||||||
Noah Campbell <noahcampbell@gmail.com>
|
Noah Campbell <noahcampbell@gmail.com>
|
||||||
Norberto Lopes <nlopes.ml@gmail.com>
|
Norberto Lopes <nlopes.ml@gmail.com>
|
||||||
|
|
@ -486,8 +551,11 @@ Oling Cat <olingcat@gmail.com>
|
||||||
Oliver Hookins <ohookins@gmail.com>
|
Oliver Hookins <ohookins@gmail.com>
|
||||||
Olivier Antoine <olivier.antoine@gmail.com>
|
Olivier Antoine <olivier.antoine@gmail.com>
|
||||||
Olivier Duperray <duperray.olivier@gmail.com>
|
Olivier Duperray <duperray.olivier@gmail.com>
|
||||||
|
Olivier Poitrey <rs@dailymotion.com>
|
||||||
Olivier Saingre <osaingre@gmail.com>
|
Olivier Saingre <osaingre@gmail.com>
|
||||||
Oracle
|
Oracle
|
||||||
|
Orange
|
||||||
|
Özgür Kesim <oec-go@kesim.org>
|
||||||
Padraig Kitterick <padraigkitterick@gmail.com>
|
Padraig Kitterick <padraigkitterick@gmail.com>
|
||||||
Palm Stone Games
|
Palm Stone Games
|
||||||
Paolo Giarrusso <p.giarrusso@gmail.com>
|
Paolo Giarrusso <p.giarrusso@gmail.com>
|
||||||
|
|
@ -523,10 +591,13 @@ Péter Szilágyi <peterke@gmail.com>
|
||||||
Peter Waldschmidt <peter@waldschmidt.com>
|
Peter Waldschmidt <peter@waldschmidt.com>
|
||||||
Peter Waller <peter.waller@gmail.com>
|
Peter Waller <peter.waller@gmail.com>
|
||||||
Peter Williams <pwil3058@gmail.com>
|
Peter Williams <pwil3058@gmail.com>
|
||||||
|
Philip Hofer <phofer@umich.edu>
|
||||||
Philip K. Warren <pkwarren@gmail.com>
|
Philip K. Warren <pkwarren@gmail.com>
|
||||||
|
Pierre Durand <pierredurand@gmail.com>
|
||||||
Pierre Roullon <pierre.roullon@gmail.com>
|
Pierre Roullon <pierre.roullon@gmail.com>
|
||||||
Pieter Droogendijk <pieter@binky.org.uk>
|
Pieter Droogendijk <pieter@binky.org.uk>
|
||||||
Pietro Gagliardi <pietro10@mac.com>
|
Pietro Gagliardi <pietro10@mac.com>
|
||||||
|
Prashant Varanasi <prashant@prashantv.com>
|
||||||
Preetam Jinka <pj@preet.am>
|
Preetam Jinka <pj@preet.am>
|
||||||
Quan Yong Zhai <qyzhai@gmail.com>
|
Quan Yong Zhai <qyzhai@gmail.com>
|
||||||
Quentin Perez <qperez@ocs.online.net>
|
Quentin Perez <qperez@ocs.online.net>
|
||||||
|
|
@ -538,9 +609,11 @@ Ralph Corderoy <ralph@inputplus.co.uk>
|
||||||
Red Hat, Inc.
|
Red Hat, Inc.
|
||||||
Reinaldo de Souza Jr <juniorz@gmail.com>
|
Reinaldo de Souza Jr <juniorz@gmail.com>
|
||||||
Rémy Oudompheng <oudomphe@phare.normalesup.org>
|
Rémy Oudompheng <oudomphe@phare.normalesup.org>
|
||||||
|
Ricardo Padilha <ricardospadilha@gmail.com>
|
||||||
Richard Barnes <rlb@ipv.sx>
|
Richard Barnes <rlb@ipv.sx>
|
||||||
Richard Crowley <r@rcrowley.org>
|
Richard Crowley <r@rcrowley.org>
|
||||||
Richard Eric Gavaletz <gavaletz@gmail.com>
|
Richard Eric Gavaletz <gavaletz@gmail.com>
|
||||||
|
Richard Miller <miller.research@gmail.com>
|
||||||
Richard Musiol <mail@richard-musiol.de>
|
Richard Musiol <mail@richard-musiol.de>
|
||||||
Rick Arnold <rickarnoldjr@gmail.com>
|
Rick Arnold <rickarnoldjr@gmail.com>
|
||||||
Risto Jaakko Saarelma <rsaarelm@gmail.com>
|
Risto Jaakko Saarelma <rsaarelm@gmail.com>
|
||||||
|
|
@ -556,6 +629,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>
|
||||||
|
Roland Shoemaker <rolandshoemaker@gmail.com>
|
||||||
Ron Hashimoto <mail@h2so5.net>
|
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>
|
||||||
|
|
@ -567,8 +641,11 @@ Ryan Seys <ryan@ryanseys.com>
|
||||||
Ryan Slade <ryanslade@gmail.com>
|
Ryan Slade <ryanslade@gmail.com>
|
||||||
S.Çağlar Onur <caglar@10ur.org>
|
S.Çağlar Onur <caglar@10ur.org>
|
||||||
Salmān Aljammāz <s@0x65.net>
|
Salmān Aljammāz <s@0x65.net>
|
||||||
|
Sam Hug <samuel.b.hug@gmail.com>
|
||||||
|
Sam Whited <sam@samwhited.com>
|
||||||
Sanjay Menakuru <balasanjay@gmail.com>
|
Sanjay Menakuru <balasanjay@gmail.com>
|
||||||
Scott Barron <scott.barron@github.com>
|
Scott Barron <scott.barron@github.com>
|
||||||
|
Scott Bell <scott@sctsm.com>
|
||||||
Scott Ferguson <scottwferg@gmail.com>
|
Scott Ferguson <scottwferg@gmail.com>
|
||||||
Scott Lawrence <bytbox@gmail.com>
|
Scott Lawrence <bytbox@gmail.com>
|
||||||
Sebastien Binet <seb.binet@gmail.com>
|
Sebastien Binet <seb.binet@gmail.com>
|
||||||
|
|
@ -577,17 +654,21 @@ Sergei Skorobogatov <skorobo@rambler.ru>
|
||||||
Sergey 'SnakE' Gromov <snake.scaly@gmail.com>
|
Sergey 'SnakE' Gromov <snake.scaly@gmail.com>
|
||||||
Sergio Luis O. B. Correia <sergio@correia.cc>
|
Sergio Luis O. B. Correia <sergio@correia.cc>
|
||||||
Seth Hoenig <seth.a.hoenig@gmail.com>
|
Seth Hoenig <seth.a.hoenig@gmail.com>
|
||||||
|
Shahar Kohanim <skohanim@gmail.com>
|
||||||
Shane Hansen <shanemhansen@gmail.com>
|
Shane Hansen <shanemhansen@gmail.com>
|
||||||
Shaozhen Ding <dsz0111@gmail.com>
|
Shaozhen Ding <dsz0111@gmail.com>
|
||||||
Shawn Smith <shawn.p.smith@gmail.com>
|
Shawn Smith <shawn.p.smith@gmail.com>
|
||||||
Shenghou Ma <minux.ma@gmail.com>
|
Shenghou Ma <minux.ma@gmail.com>
|
||||||
|
Shinji Tanaka <shinji.tanaka@gmail.com>
|
||||||
Shivakumar GN <shivakumar.gn@gmail.com>
|
Shivakumar GN <shivakumar.gn@gmail.com>
|
||||||
Silvan Jegen <s.jegen@gmail.com>
|
Silvan Jegen <s.jegen@gmail.com>
|
||||||
|
Simon Jefford <simon.jefford@gmail.com>
|
||||||
Simon Whitehead <chemnova@gmail.com>
|
Simon Whitehead <chemnova@gmail.com>
|
||||||
Sokolov Yura <funny.falcon@gmail.com>
|
Sokolov Yura <funny.falcon@gmail.com>
|
||||||
Spencer Nelson <s@spenczar.com>
|
Spencer Nelson <s@spenczar.com>
|
||||||
Spring Mc <heresy.mc@gmail.com>
|
Spring Mc <heresy.mc@gmail.com>
|
||||||
Square, Inc.
|
Square, Inc.
|
||||||
|
Sridhar Venkatakrishnan <sridhar@laddoo.net>
|
||||||
StalkR <stalkr@stalkr.net>
|
StalkR <stalkr@stalkr.net>
|
||||||
Stan Schwertly <stan@schwertly.com>
|
Stan Schwertly <stan@schwertly.com>
|
||||||
Stefan Nilsson <snilsson@nada.kth.se> <trolleriprofessorn@gmail.com>
|
Stefan Nilsson <snilsson@nada.kth.se> <trolleriprofessorn@gmail.com>
|
||||||
|
|
@ -605,6 +686,7 @@ Szabolcs Nagy <nsz@port70.net>
|
||||||
Tad Glines <tad.glines@gmail.com>
|
Tad Glines <tad.glines@gmail.com>
|
||||||
Taj Khattra <taj.khattra@gmail.com>
|
Taj Khattra <taj.khattra@gmail.com>
|
||||||
Takeshi YAMANASHI <9.nashi@gmail.com>
|
Takeshi YAMANASHI <9.nashi@gmail.com>
|
||||||
|
Tal Shprecher <tshprecher@gmail.com>
|
||||||
Tamir Duberstein <tamird@gmail.com>
|
Tamir Duberstein <tamird@gmail.com>
|
||||||
Tarmigan Casebolt <tarmigan@gmail.com>
|
Tarmigan Casebolt <tarmigan@gmail.com>
|
||||||
Taru Karttunen <taruti@taruti.net>
|
Taru Karttunen <taruti@taruti.net>
|
||||||
|
|
@ -615,9 +697,12 @@ Thomas Alan Copeland <talan.copeland@gmail.com>
|
||||||
Thomas Desrosiers <thomasdesr@gmail.com>
|
Thomas Desrosiers <thomasdesr@gmail.com>
|
||||||
Thomas Kappler <tkappler@gmail.com>
|
Thomas Kappler <tkappler@gmail.com>
|
||||||
Thorben Krueger <thorben.krueger@gmail.com>
|
Thorben Krueger <thorben.krueger@gmail.com>
|
||||||
|
Tilman Dilo <tilman.dilo@gmail.com>
|
||||||
Tim Cooijmans <timcooijmans@gmail.com>
|
Tim Cooijmans <timcooijmans@gmail.com>
|
||||||
|
Tim Ebringer <tim.ebringer@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>
|
||||||
|
Timothy Studd <tim@timstudd.com>
|
||||||
Tobias Columbus <tobias.columbus@gmail.com>
|
Tobias Columbus <tobias.columbus@gmail.com>
|
||||||
Todd Neal <todd@tneal.org>
|
Todd Neal <todd@tneal.org>
|
||||||
Tom Heng <zhm20070928@gmail.com>
|
Tom Heng <zhm20070928@gmail.com>
|
||||||
|
|
@ -634,12 +719,15 @@ Tyler Treat <ttreat31@gmail.com>
|
||||||
Ugorji Nwoke <ugorji@gmail.com>
|
Ugorji Nwoke <ugorji@gmail.com>
|
||||||
Ulf Holm Nielsen <doktor@dyregod.dk>
|
Ulf Holm Nielsen <doktor@dyregod.dk>
|
||||||
Ulrich Kunitz <uli.kunitz@gmail.com>
|
Ulrich Kunitz <uli.kunitz@gmail.com>
|
||||||
|
Upthere, Inc.
|
||||||
Uriel Mangado <uriel@berlinblue.org>
|
Uriel Mangado <uriel@berlinblue.org>
|
||||||
|
Vadim Grek <vadimprog@gmail.com>
|
||||||
Vadim Vygonets <unixdj@gmail.com>
|
Vadim Vygonets <unixdj@gmail.com>
|
||||||
Vincent Ambo <tazjin@googlemail.com>
|
Vincent Ambo <tazjin@googlemail.com>
|
||||||
Vincent Batts <vbatts@hashbangbash.com> <vbatts@gmail.com>
|
Vincent Batts <vbatts@hashbangbash.com> <vbatts@gmail.com>
|
||||||
Vincent Vanackere <vincent.vanackere@gmail.com>
|
Vincent Vanackere <vincent.vanackere@gmail.com>
|
||||||
Vinu Rajashekhar <vinutheraj@gmail.com>
|
Vinu Rajashekhar <vinutheraj@gmail.com>
|
||||||
|
Vishvananda Ishaya <vishvananda@gmail.com>
|
||||||
Vladimir Nikishenko <vova616@gmail.com>
|
Vladimir Nikishenko <vova616@gmail.com>
|
||||||
Volker Dobler <dr.volker.dobler@gmail.com>
|
Volker Dobler <dr.volker.dobler@gmail.com>
|
||||||
Wei Guangjing <vcc.163@gmail.com>
|
Wei Guangjing <vcc.163@gmail.com>
|
||||||
|
|
@ -648,6 +736,7 @@ William Josephson <wjosephson@gmail.com>
|
||||||
William Orr <will@worrbase.com> <ay1244@gmail.com>
|
William Orr <will@worrbase.com> <ay1244@gmail.com>
|
||||||
Xia Bin <snyh@snyh.org>
|
Xia Bin <snyh@snyh.org>
|
||||||
Xing Xing <mikespook@gmail.com>
|
Xing Xing <mikespook@gmail.com>
|
||||||
|
Xudong Zhang <felixmelon@gmail.com>
|
||||||
Yahoo Inc.
|
Yahoo Inc.
|
||||||
Yann Kerhervé <yann.kerherve@gmail.com>
|
Yann Kerhervé <yann.kerherve@gmail.com>
|
||||||
Yao Zhang <lunaria21@gmail.com>
|
Yao Zhang <lunaria21@gmail.com>
|
||||||
|
|
@ -661,6 +750,7 @@ Yoshiyuki Kanno <nekotaroh@gmail.com> <yoshiyuki.kanno@stoic.co.jp>
|
||||||
Yusuke Kagiwada <block.rxckin.beats@gmail.com>
|
Yusuke Kagiwada <block.rxckin.beats@gmail.com>
|
||||||
Yuusei Kuwana <kuwana@kumama.org>
|
Yuusei Kuwana <kuwana@kumama.org>
|
||||||
Yuval Pavel Zholkover <paulzhol@gmail.com>
|
Yuval Pavel Zholkover <paulzhol@gmail.com>
|
||||||
|
Zemanta d.o.o.
|
||||||
Ziad Hatahet <hatahet@gmail.com>
|
Ziad Hatahet <hatahet@gmail.com>
|
||||||
Zorion Arrizabalaga <zorionk@gmail.com>
|
Zorion Arrizabalaga <zorionk@gmail.com>
|
||||||
申习之 <bronze1man@gmail.com>
|
申习之 <bronze1man@gmail.com>
|
||||||
|
|
|
||||||
126
CONTRIBUTORS
126
CONTRIBUTORS
|
|
@ -37,6 +37,7 @@ Aaron France <aaron.l.france@gmail.com>
|
||||||
Aaron Jacobs <jacobsa@google.com>
|
Aaron Jacobs <jacobsa@google.com>
|
||||||
Aaron Kemp <kemp.aaron@gmail.com>
|
Aaron Kemp <kemp.aaron@gmail.com>
|
||||||
Aaron Torres <tcboox@gmail.com>
|
Aaron Torres <tcboox@gmail.com>
|
||||||
|
Abe Haskins <abeisgreat@abeisgreat.com>
|
||||||
Abhinav Gupta <abhinav.g90@gmail.com>
|
Abhinav Gupta <abhinav.g90@gmail.com>
|
||||||
Adam Langley <agl@golang.org>
|
Adam Langley <agl@golang.org>
|
||||||
Adrian Nos <nos.adrian@gmail.com>
|
Adrian Nos <nos.adrian@gmail.com>
|
||||||
|
|
@ -44,7 +45,10 @@ Adrian O'Grady <elpollouk@gmail.com>
|
||||||
Adrien Bustany <adrien-xx-google@bustany.org>
|
Adrien Bustany <adrien-xx-google@bustany.org>
|
||||||
Aécio Júnior <aeciodantasjunior@gmail.com>
|
Aécio Júnior <aeciodantasjunior@gmail.com>
|
||||||
Ahmed Waheed Moanes <oneofone@gmail.com>
|
Ahmed Waheed Moanes <oneofone@gmail.com>
|
||||||
|
Ahmy Yulrizka <yulrizka@gmail.com>
|
||||||
|
Aiden Scandella <ai@uber.com>
|
||||||
Ainar Garipov <gugl.zadolbal@gmail.com>
|
Ainar Garipov <gugl.zadolbal@gmail.com>
|
||||||
|
Akihiro Suda <suda.kyoto@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>
|
||||||
|
|
@ -53,6 +57,7 @@ Alberto Bertogli <albertito@blitiri.com.ar>
|
||||||
Alberto Donizetti <alb.donizetti@gmail.com>
|
Alberto Donizetti <alb.donizetti@gmail.com>
|
||||||
Alberto García Hierro <alberto@garciahierro.com> <alberto.garcia.hierro@gmail.com>
|
Alberto García Hierro <alberto@garciahierro.com> <alberto.garcia.hierro@gmail.com>
|
||||||
Aleksandar Dezelin <dezelin@gmail.com>
|
Aleksandar Dezelin <dezelin@gmail.com>
|
||||||
|
Alessandro Arzilli <alessandro.arzilli@gmail.com>
|
||||||
Alex A Skinner <alex@lx.lc>
|
Alex A Skinner <alex@lx.lc>
|
||||||
Alex Brainman <alex.brainman@gmail.com>
|
Alex Brainman <alex.brainman@gmail.com>
|
||||||
Alex Bramley <abramley@google.com>
|
Alex Bramley <abramley@google.com>
|
||||||
|
|
@ -60,6 +65,7 @@ Alex Jin <toalexjin@gmail.com>
|
||||||
Alex Plugaru <alex@plugaru.org> <alexandru.plugaru@gmail.com>
|
Alex Plugaru <alex@plugaru.org> <alexandru.plugaru@gmail.com>
|
||||||
Alex Schroeder <alex@gnu.org>
|
Alex Schroeder <alex@gnu.org>
|
||||||
Alex Sergeyev <abc@alexsergeyev.com>
|
Alex Sergeyev <abc@alexsergeyev.com>
|
||||||
|
Alex Vaghin <crhyme@google.com>
|
||||||
Alexander Demakin <alexander.demakin@gmail.com>
|
Alexander Demakin <alexander.demakin@gmail.com>
|
||||||
Alexander Larsson <alexander.larsson@gmail.com>
|
Alexander Larsson <alexander.larsson@gmail.com>
|
||||||
Alexander Morozov <lk4d4math@gmail.com>
|
Alexander Morozov <lk4d4math@gmail.com>
|
||||||
|
|
@ -80,6 +86,7 @@ Aliaksandr Valialkin <valyala@gmail.com>
|
||||||
Alif Rachmawadi <subosito@gmail.com>
|
Alif Rachmawadi <subosito@gmail.com>
|
||||||
Amir Mohammad Saied <amir@gluegadget.com>
|
Amir Mohammad Saied <amir@gluegadget.com>
|
||||||
Amrut Joshi <amrut.joshi@gmail.com>
|
Amrut Joshi <amrut.joshi@gmail.com>
|
||||||
|
Andre Nathan <andrenth@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 Korzhevskii <a.korzhevskiy@gmail.com>
|
Andrei Korzhevskii <a.korzhevskiy@gmail.com>
|
||||||
|
|
@ -98,6 +105,7 @@ Andrew Pritchard <awpritchard@gmail.com>
|
||||||
Andrew Radev <andrey.radev@gmail.com>
|
Andrew Radev <andrey.radev@gmail.com>
|
||||||
Andrew Skiba <skibaa@gmail.com>
|
Andrew Skiba <skibaa@gmail.com>
|
||||||
Andrew Szeto <andrew@jabagawee.com>
|
Andrew Szeto <andrew@jabagawee.com>
|
||||||
|
Andrew Werner <andrew@upthere.com> <awerner32@gmail.com>
|
||||||
Andrew Wilkins <axwalk@gmail.com>
|
Andrew Wilkins <axwalk@gmail.com>
|
||||||
Andrew Williams <williams.andrew@gmail.com>
|
Andrew Williams <williams.andrew@gmail.com>
|
||||||
Andrey Mirtchovski <mirtchovski@gmail.com>
|
Andrey Mirtchovski <mirtchovski@gmail.com>
|
||||||
|
|
@ -119,6 +127,7 @@ Apisak Darakananda <pongad@gmail.com>
|
||||||
Aram Hăvărneanu <aram@mgk.ro>
|
Aram Hăvărneanu <aram@mgk.ro>
|
||||||
Areski Belaid <areski@gmail.com>
|
Areski Belaid <areski@gmail.com>
|
||||||
Arkadi Pyuro <arkadi@google.com>
|
Arkadi Pyuro <arkadi@google.com>
|
||||||
|
Arlo Breault <arlolra@gmail.com>
|
||||||
Arnaud Ysmal <arnaud.ysmal@gmail.com>
|
Arnaud Ysmal <arnaud.ysmal@gmail.com>
|
||||||
Arne Hormann <arnehormann@gmail.com>
|
Arne Hormann <arnehormann@gmail.com>
|
||||||
Arnout Engelen <arnout@bzzt.net>
|
Arnout Engelen <arnout@bzzt.net>
|
||||||
|
|
@ -127,6 +136,8 @@ Artyom Pervukhin <artyom.pervukhin@gmail.com>
|
||||||
Arvindh Rajesh Tamilmani <art@a-30.net>
|
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>
|
||||||
|
Audrey Lim <audreylh@gmail.com>
|
||||||
|
Augusto Roman <aroman@gmail.com>
|
||||||
Aulus Egnatius Varialus <varialus@gmail.com>
|
Aulus Egnatius Varialus <varialus@gmail.com>
|
||||||
Austin Clements <austin@google.com> <aclements@csail.mit.edu>
|
Austin Clements <austin@google.com> <aclements@csail.mit.edu>
|
||||||
awaw fumin <awawfumin@gmail.com>
|
awaw fumin <awawfumin@gmail.com>
|
||||||
|
|
@ -139,6 +150,7 @@ Ben Lynn <benlynn@gmail.com>
|
||||||
Ben Olive <sionide21@gmail.com>
|
Ben Olive <sionide21@gmail.com>
|
||||||
Benjamin Black <b@b3k.us>
|
Benjamin Black <b@b3k.us>
|
||||||
Benjamin Prosnitz <bprosnitz@google.com>
|
Benjamin Prosnitz <bprosnitz@google.com>
|
||||||
|
Benjamin Wester <bwester@squareup.com>
|
||||||
Benny Siegert <bsiegert@gmail.com>
|
Benny Siegert <bsiegert@gmail.com>
|
||||||
Benoit Sigoure <tsunanet@gmail.com>
|
Benoit Sigoure <tsunanet@gmail.com>
|
||||||
Berengar Lehr <Berengar.Lehr@gmx.de>
|
Berengar Lehr <Berengar.Lehr@gmx.de>
|
||||||
|
|
@ -152,6 +164,8 @@ Blake Mizerany <blake.mizerany@gmail.com>
|
||||||
Bobby Powers <bobbypowers@gmail.com>
|
Bobby Powers <bobbypowers@gmail.com>
|
||||||
Brad Fitzpatrick <bradfitz@golang.org> <bradfitz@gmail.com>
|
Brad Fitzpatrick <bradfitz@golang.org> <bradfitz@gmail.com>
|
||||||
Brad Garcia <bgarcia@golang.org>
|
Brad Garcia <bgarcia@golang.org>
|
||||||
|
Brady Catherman <brady@gmail.com>
|
||||||
|
Brady Sullivan <brady@bsull.com>
|
||||||
Brandon Gilmore <varz@google.com>
|
Brandon Gilmore <varz@google.com>
|
||||||
Brendan Daniel Tracey <tracey.brendan@gmail.com>
|
Brendan Daniel Tracey <tracey.brendan@gmail.com>
|
||||||
Brendan O'Dea <bod@golang.org>
|
Brendan O'Dea <bod@golang.org>
|
||||||
|
|
@ -163,8 +177,10 @@ Brian Ketelsen <bketelsen@gmail.com>
|
||||||
Brian Slesinsky <skybrian@google.com>
|
Brian Slesinsky <skybrian@google.com>
|
||||||
Brian Smith <ohohvi@gmail.com>
|
Brian Smith <ohohvi@gmail.com>
|
||||||
Bryan C. Mills <bcmills@google.com>
|
Bryan C. Mills <bcmills@google.com>
|
||||||
|
Bryan Chan <bryan.chan@ca.ibm.com>
|
||||||
Bryan Ford <brynosaurus@gmail.com>
|
Bryan Ford <brynosaurus@gmail.com>
|
||||||
Caine Tighe <arctanofyourface@gmail.com>
|
Caine Tighe <arctanofyourface@gmail.com>
|
||||||
|
Caio Marcelo de Oliveira Filho <caio.oliveira@intel.com>
|
||||||
Caleb Spare <cespare@gmail.com>
|
Caleb Spare <cespare@gmail.com>
|
||||||
Carl Chatfield <carlchatfield@gmail.com>
|
Carl Chatfield <carlchatfield@gmail.com>
|
||||||
Carl Jackson <carl@stripe.com>
|
Carl Jackson <carl@stripe.com>
|
||||||
|
|
@ -175,6 +191,7 @@ Carlos Cirello <uldericofilho@gmail.com>
|
||||||
Cary Hull <chull@google.com>
|
Cary Hull <chull@google.com>
|
||||||
Case Nelson <case.nelson@gmail.com>
|
Case Nelson <case.nelson@gmail.com>
|
||||||
Casey Marshall <casey.marshall@gmail.com>
|
Casey Marshall <casey.marshall@gmail.com>
|
||||||
|
Catalin Nicutar <cnicutar@google.com>
|
||||||
Catalin Patulea <catalinp@google.com>
|
Catalin Patulea <catalinp@google.com>
|
||||||
Cedric Staub <cs@squareup.com>
|
Cedric Staub <cs@squareup.com>
|
||||||
Cezar Sá Espinola <cezarsa@gmail.com>
|
Cezar Sá Espinola <cezarsa@gmail.com>
|
||||||
|
|
@ -182,6 +199,7 @@ ChaiShushan <chaishushan@gmail.com>
|
||||||
Charles L. Dorian <cldorian@gmail.com>
|
Charles L. Dorian <cldorian@gmail.com>
|
||||||
Charles Lee <zombie.fml@gmail.com>
|
Charles Lee <zombie.fml@gmail.com>
|
||||||
Charles Weill <weill@google.com>
|
Charles Weill <weill@google.com>
|
||||||
|
Cherry Zhang <cherryyz@google.com>
|
||||||
Chris Broadfoot <cbro@golang.org>
|
Chris Broadfoot <cbro@golang.org>
|
||||||
Chris Dollin <ehog.hedge@gmail.com>
|
Chris Dollin <ehog.hedge@gmail.com>
|
||||||
Chris Farmiloe <chrisfarms@gmail.com>
|
Chris Farmiloe <chrisfarms@gmail.com>
|
||||||
|
|
@ -193,25 +211,31 @@ Chris Kastorff <encryptio@gmail.com>
|
||||||
Chris Lennert <calennert@gmail.com>
|
Chris Lennert <calennert@gmail.com>
|
||||||
Chris Manghane <cmang@golang.org>
|
Chris Manghane <cmang@golang.org>
|
||||||
Chris McGee <sirnewton_01@yahoo.ca> <newton688@gmail.com>
|
Chris McGee <sirnewton_01@yahoo.ca> <newton688@gmail.com>
|
||||||
|
Chris Zou <chriszou@ca.ibm.com>
|
||||||
Christian Himpel <chressie@googlemail.com> <chressie@gmail.com>
|
Christian Himpel <chressie@googlemail.com> <chressie@gmail.com>
|
||||||
Christine Hansmann <chhansmann@gmail.com>
|
Christine Hansmann <chhansmann@gmail.com>
|
||||||
Christoffer Buchholz <christoffer.buchholz@gmail.com>
|
Christoffer Buchholz <christoffer.buchholz@gmail.com>
|
||||||
Christoph Hack <christoph@tux21b.org>
|
Christoph Hack <christoph@tux21b.org>
|
||||||
Christopher Cahoon <chris.cahoon@gmail.com>
|
Christopher Cahoon <chris.cahoon@gmail.com>
|
||||||
Christopher Guiney <chris@guiney.net>
|
Christopher Guiney <chris@guiney.net>
|
||||||
|
Christopher Nelson <nadiasvertex@gmail.com>
|
||||||
Christopher Nielsen <m4dh4tt3r@gmail.com>
|
Christopher Nielsen <m4dh4tt3r@gmail.com>
|
||||||
Christopher Redden <christopher.redden@gmail.com>
|
Christopher Redden <christopher.redden@gmail.com>
|
||||||
Christopher Swenson <cswenson@google.com>
|
Christopher Swenson <cswenson@google.com>
|
||||||
Christopher Wedgwood <cw@f00f.org>
|
Christopher Wedgwood <cw@f00f.org>
|
||||||
|
Christy Perez <christy@linux.vnet.ibm.com>
|
||||||
CL Sung <clsung@gmail.com> <cl_sung@htc.com>
|
CL Sung <clsung@gmail.com> <cl_sung@htc.com>
|
||||||
Clement Skau <clementskau@gmail.com>
|
Clement Skau <clementskau@gmail.com>
|
||||||
Colby Ranger <cranger@google.com>
|
Colby Ranger <cranger@google.com>
|
||||||
Colin Cross <ccross@android.com>
|
Colin Cross <ccross@android.com>
|
||||||
|
Colin Edwards <colin@recursivepenguin.com>
|
||||||
Colin Kennedy <moshen.colin@gmail.com>
|
Colin Kennedy <moshen.colin@gmail.com>
|
||||||
|
Conrad Irwin <conrad.irwin@gmail.com>
|
||||||
Conrad Meyer <cemeyer@cs.washington.edu>
|
Conrad Meyer <cemeyer@cs.washington.edu>
|
||||||
Corey Thomasson <cthom.lists@gmail.com>
|
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>
|
||||||
|
Cuihtlauac ALVARADO <cuihtlauac.alvarado@orange.com>
|
||||||
Damian Gryski <dgryski@gmail.com>
|
Damian Gryski <dgryski@gmail.com>
|
||||||
Damien Neil <dneil@google.com>
|
Damien Neil <dneil@google.com>
|
||||||
Dan Caddigan <goldcaddy77@gmail.com>
|
Dan Caddigan <goldcaddy77@gmail.com>
|
||||||
|
|
@ -229,8 +253,10 @@ Daniel Morsing <daniel.morsing@gmail.com>
|
||||||
Daniel Nadasi <dnadasi@google.com>
|
Daniel Nadasi <dnadasi@google.com>
|
||||||
Daniel Ortiz Pereira da Silva <daniel.particular@gmail.com>
|
Daniel Ortiz Pereira da Silva <daniel.particular@gmail.com>
|
||||||
Daniel Skinner <daniel@dasa.cc>
|
Daniel Skinner <daniel@dasa.cc>
|
||||||
|
Daniel Speichert <daniel@speichert.pl>
|
||||||
Daniel Theophanes <kardianos@gmail.com>
|
Daniel Theophanes <kardianos@gmail.com>
|
||||||
Darren Elwood <darren@textnode.com>
|
Darren Elwood <darren@textnode.com>
|
||||||
|
Datong Sun <dndx@idndx.com>
|
||||||
Dave Borowitz <dborowitz@google.com>
|
Dave Borowitz <dborowitz@google.com>
|
||||||
Dave Bort <dbort@golang.org>
|
Dave Bort <dbort@golang.org>
|
||||||
Dave Cheney <dave@cheney.net>
|
Dave Cheney <dave@cheney.net>
|
||||||
|
|
@ -239,6 +265,7 @@ Dave Grijalva <dgrijalva@ngmoco.com>
|
||||||
David Anderson <danderson@google.com>
|
David Anderson <danderson@google.com>
|
||||||
David Barnett <dbarnett@google.com>
|
David Barnett <dbarnett@google.com>
|
||||||
David Benjamin <davidben@google.com>
|
David Benjamin <davidben@google.com>
|
||||||
|
David Brophy <dave@brophy.uk>
|
||||||
David Bürgin <676c7473@gmail.com>
|
David Bürgin <676c7473@gmail.com>
|
||||||
David Calavera <david.calavera@gmail.com>
|
David Calavera <david.calavera@gmail.com>
|
||||||
David Chase <drchase@google.com>
|
David Chase <drchase@google.com>
|
||||||
|
|
@ -254,6 +281,7 @@ David Leon Gil <coruus@gmail.com>
|
||||||
David McLeish <davemc@google.com>
|
David McLeish <davemc@google.com>
|
||||||
David Presotto <presotto@gmail.com>
|
David Presotto <presotto@gmail.com>
|
||||||
David R. Jenni <david.r.jenni@gmail.com>
|
David R. Jenni <david.r.jenni@gmail.com>
|
||||||
|
David Sansome <me@davidsansome.com>
|
||||||
David Symonds <dsymonds@golang.org>
|
David Symonds <dsymonds@golang.org>
|
||||||
David Thomas <davidthomas426@gmail.com>
|
David Thomas <davidthomas426@gmail.com>
|
||||||
David Titarenco <david.titarenco@gmail.com>
|
David Titarenco <david.titarenco@gmail.com>
|
||||||
|
|
@ -261,15 +289,19 @@ Davies Liu <davies.liu@gmail.com>
|
||||||
Dean Prichard <dean.prichard@gmail.com>
|
Dean Prichard <dean.prichard@gmail.com>
|
||||||
Denis Bernard <db047h@gmail.com>
|
Denis Bernard <db047h@gmail.com>
|
||||||
Denis Brandolini <denis.brandolini@gmail.com>
|
Denis Brandolini <denis.brandolini@gmail.com>
|
||||||
|
Denys Honsiorovskyi <honsiorovskyi@gmail.com>
|
||||||
Derek Buitenhuis <derek.buitenhuis@gmail.com>
|
Derek Buitenhuis <derek.buitenhuis@gmail.com>
|
||||||
Derek Che <drc@yahoo-inc.com>
|
Derek Che <drc@yahoo-inc.com>
|
||||||
Derek Parker <parkerderek86@gmail.com>
|
Derek Parker <parkerderek86@gmail.com>
|
||||||
|
Derek Shockey <derek.shockey@gmail.com>
|
||||||
Devon H. O'Dell <devon.odell@gmail.com>
|
Devon H. O'Dell <devon.odell@gmail.com>
|
||||||
Dhiru Kholia <dhiru.kholia@gmail.com>
|
Dhiru Kholia <dhiru.kholia@gmail.com>
|
||||||
Didier Spezia <didier.06@gmail.com>
|
Didier Spezia <didier.06@gmail.com>
|
||||||
Dimitri Tcaciuc <dtcaciuc@gmail.com>
|
Dimitri Tcaciuc <dtcaciuc@gmail.com>
|
||||||
Dirk Gadsden <dirk@esherido.com>
|
Dirk Gadsden <dirk@esherido.com>
|
||||||
|
Diwaker Gupta <diwakergupta@gmail.com>
|
||||||
Dmitri Shuralyov <shurcooL@gmail.com>
|
Dmitri Shuralyov <shurcooL@gmail.com>
|
||||||
|
Dmitriy Dudkin <dudkin.dmitriy@gmail.com>
|
||||||
Dmitriy Shelenin <deemok@googlemail.com> <deemok@gmail.com>
|
Dmitriy Shelenin <deemok@googlemail.com> <deemok@gmail.com>
|
||||||
Dmitriy Vyukov <dvyukov@google.com>
|
Dmitriy Vyukov <dvyukov@google.com>
|
||||||
Dmitry Chestnykh <dchest@gmail.com>
|
Dmitry Chestnykh <dchest@gmail.com>
|
||||||
|
|
@ -279,8 +311,11 @@ Dominik Honnef <dominik.honnef@gmail.com>
|
||||||
Dominik Vogt <vogt@linux.vnet.ibm.com>
|
Dominik Vogt <vogt@linux.vnet.ibm.com>
|
||||||
Donald Huang <don.hcd@gmail.com>
|
Donald Huang <don.hcd@gmail.com>
|
||||||
Donovan Hide <donovanhide@gmail.com>
|
Donovan Hide <donovanhide@gmail.com>
|
||||||
|
Doug Anderson <douga@google.com>
|
||||||
Drew Hintz <adhintz@google.com>
|
Drew Hintz <adhintz@google.com>
|
||||||
Duncan Holm <mail@frou.org>
|
Duncan Holm <mail@frou.org>
|
||||||
|
Dustin Carlino <dcarlino@google.com>
|
||||||
|
Dustin Herbison <djherbis@gmail.com>
|
||||||
Dustin Long <dustmop@gmail.com>
|
Dustin Long <dustmop@gmail.com>
|
||||||
Dustin Sallings <dsallings@gmail.com>
|
Dustin Sallings <dsallings@gmail.com>
|
||||||
Dustin Shields-Cloues <dcloues@gmail.com>
|
Dustin Shields-Cloues <dcloues@gmail.com>
|
||||||
|
|
@ -304,7 +339,9 @@ Erik Aigner <aigner.erik@gmail.com>
|
||||||
Erik Dubbelboer <erik@dubbelboer.com>
|
Erik Dubbelboer <erik@dubbelboer.com>
|
||||||
Erik St. Martin <alakriti@gmail.com>
|
Erik St. Martin <alakriti@gmail.com>
|
||||||
Erik Westrup <erik.westrup@gmail.com>
|
Erik Westrup <erik.westrup@gmail.com>
|
||||||
|
Ernest Chiang <ernest_chiang@htc.com>
|
||||||
Esko Luontola <esko.luontola@gmail.com>
|
Esko Luontola <esko.luontola@gmail.com>
|
||||||
|
Ethan Burns <eaburns@google.com>
|
||||||
Evan Broder <evan@stripe.com>
|
Evan Broder <evan@stripe.com>
|
||||||
Evan Brown <evanbrown@google.com>
|
Evan Brown <evanbrown@google.com>
|
||||||
Evan Kroske <evankroske@google.com>
|
Evan Kroske <evankroske@google.com>
|
||||||
|
|
@ -331,11 +368,13 @@ Francisco Souza <franciscossouza@gmail.com>
|
||||||
Frederick Kelly Mayle III <frederickmayle@gmail.com>
|
Frederick Kelly Mayle III <frederickmayle@gmail.com>
|
||||||
Fredrik Enestad <fredrik.enestad@soundtrackyourbrand.com>
|
Fredrik Enestad <fredrik.enestad@soundtrackyourbrand.com>
|
||||||
Frithjof Schulze <schulze@math.uni-hannover.de> <sfrithjof@gmail.com>
|
Frithjof Schulze <schulze@math.uni-hannover.de> <sfrithjof@gmail.com>
|
||||||
|
Frits van Bommel <fvbommel@gmail.com>
|
||||||
Fumitoshi Ukai <ukai@google.com>
|
Fumitoshi Ukai <ukai@google.com>
|
||||||
Gaal Yahas <gaal@google.com>
|
Gaal Yahas <gaal@google.com>
|
||||||
Gabriel Aszalos <gabriel.aszalos@gmail.com>
|
Gabriel Aszalos <gabriel.aszalos@gmail.com>
|
||||||
Garrick Evans <garrick@google.com>
|
Garrick Evans <garrick@google.com>
|
||||||
Gary Burd <gary@beagledreams.com> <gary.burd@gmail.com>
|
Gary Burd <gary@beagledreams.com> <gary.burd@gmail.com>
|
||||||
|
Gary Elliott <garyelliott@google.com>
|
||||||
Gaurish Sharma <contact@gaurishsharma.com>
|
Gaurish Sharma <contact@gaurishsharma.com>
|
||||||
Gautham Thambidorai <gautham.dorai@gmail.com>
|
Gautham Thambidorai <gautham.dorai@gmail.com>
|
||||||
Geert-Johan Riemer <gjr19912@gmail.com>
|
Geert-Johan Riemer <gjr19912@gmail.com>
|
||||||
|
|
@ -359,17 +398,22 @@ 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>
|
||||||
Hajime Hoshi <hajimehoshi@gmail.com>
|
Hajime Hoshi <hajimehoshi@gmail.com>
|
||||||
|
Hallgrimur Gunnarsson <halg@google.com>
|
||||||
Han-Wen Nienhuys <hanwen@google.com>
|
Han-Wen Nienhuys <hanwen@google.com>
|
||||||
Hari haran <hariharan.uno@gmail.com>
|
Hari haran <hariharan.uno@gmail.com>
|
||||||
Hariharan Srinath <srinathh@gmail.com>
|
Hariharan Srinath <srinathh@gmail.com>
|
||||||
Harley Laue <losinggeneration@gmail.com>
|
Harley Laue <losinggeneration@gmail.com>
|
||||||
|
Harshavardhana <hrshvardhana@gmail.com>
|
||||||
Håvard Haugen <havard.haugen@gmail.com>
|
Håvard Haugen <havard.haugen@gmail.com>
|
||||||
Hector Chu <hectorchu@gmail.com>
|
Hector Chu <hectorchu@gmail.com>
|
||||||
Hector Martin Cantero <hector@marcansoft.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>
|
||||||
|
Hironao OTSUBO <motemen@gmail.com>
|
||||||
Hiroshi Ioka <hirochachacha@gmail.com>
|
Hiroshi Ioka <hirochachacha@gmail.com>
|
||||||
|
Hitoshi Mitake <mitake.hitoshi@gmail.com>
|
||||||
|
Holden Huang <ttyh061@gmail.com>
|
||||||
Hong Ruiqi <hongruiqi@gmail.com>
|
Hong Ruiqi <hongruiqi@gmail.com>
|
||||||
Hossein Sheikh Attar <hattar@google.com>
|
Hossein Sheikh Attar <hattar@google.com>
|
||||||
Hsin-Ho Yeh <yhh92u@gmail.com>
|
Hsin-Ho Yeh <yhh92u@gmail.com>
|
||||||
|
|
@ -378,11 +422,13 @@ Hyang-Ah Hana Kim <hakim@google.com> <hyangah@gmail.com>
|
||||||
Ian Gudger <ian@loosescre.ws>
|
Ian Gudger <ian@loosescre.ws>
|
||||||
Ian Lance Taylor <iant@golang.org>
|
Ian Lance Taylor <iant@golang.org>
|
||||||
Icarus Sparry <golang@icarus.freeuk.com>
|
Icarus Sparry <golang@icarus.freeuk.com>
|
||||||
|
Idora Shinatose <idora.shinatose@gmail.com>
|
||||||
Igor Dolzhikov <bluesriverz@gmail.com>
|
Igor Dolzhikov <bluesriverz@gmail.com>
|
||||||
Ilya Tocar <ilya.tocar@intel.com>
|
Ilya Tocar <ilya.tocar@intel.com>
|
||||||
INADA Naoki <songofacandy@gmail.com>
|
INADA Naoki <songofacandy@gmail.com>
|
||||||
Ingo Krabbe <ikrabbe.ask@gmail.com>
|
Ingo Krabbe <ikrabbe.ask@gmail.com>
|
||||||
Ingo Oeser <nightlyone@googlemail.com> <nightlyone@gmail.com>
|
Ingo Oeser <nightlyone@googlemail.com> <nightlyone@gmail.com>
|
||||||
|
Irieda Noboru <irieda@gmail.com>
|
||||||
Isaac Wagner <ibw@isaacwagner.me>
|
Isaac Wagner <ibw@isaacwagner.me>
|
||||||
Ivan Krasin <krasin@golang.org>
|
Ivan Krasin <krasin@golang.org>
|
||||||
Ivan Ukhov <ivan.ukhov@gmail.com>
|
Ivan Ukhov <ivan.ukhov@gmail.com>
|
||||||
|
|
@ -394,6 +440,8 @@ Jakob Borg <jakob@nym.se>
|
||||||
Jakub Čajka <jcajka@redhat.com>
|
Jakub Čajka <jcajka@redhat.com>
|
||||||
Jakub Ryszard Czarnowicz <j.czarnowicz@gmail.com>
|
Jakub Ryszard Czarnowicz <j.czarnowicz@gmail.com>
|
||||||
James Aguilar <jaguilar@google.com>
|
James Aguilar <jaguilar@google.com>
|
||||||
|
James Bardin <j.bardin@gmail.com>
|
||||||
|
James Chacon <jchacon@google.com>
|
||||||
James David Chalfant <james.chalfant@gmail.com>
|
James David Chalfant <james.chalfant@gmail.com>
|
||||||
James Fysh <james.fysh@gmail.com>
|
James Fysh <james.fysh@gmail.com>
|
||||||
James Gray <james@james4k.com>
|
James Gray <james@james4k.com>
|
||||||
|
|
@ -408,6 +456,7 @@ James Whitehead <jnwhiteh@gmail.com>
|
||||||
Jamie Gennis <jgennis@google.com> <jgennis@gmail.com>
|
Jamie Gennis <jgennis@google.com> <jgennis@gmail.com>
|
||||||
Jamie Turner <jamwt@dropbox.com>
|
Jamie Turner <jamwt@dropbox.com>
|
||||||
Jamie Wilkinson <jaq@spacepants.org>
|
Jamie Wilkinson <jaq@spacepants.org>
|
||||||
|
Jamil Djadala <djadala@gmail.com>
|
||||||
Jan H. Hosang <jan.hosang@gmail.com>
|
Jan H. Hosang <jan.hosang@gmail.com>
|
||||||
Jan Kratochvil <jan.kratochvil@redhat.com>
|
Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||||
Jan Mercl <0xjnml@gmail.com>
|
Jan Mercl <0xjnml@gmail.com>
|
||||||
|
|
@ -422,6 +471,7 @@ Jason Travis <infomaniac7@gmail.com>
|
||||||
Jay Weisskopf <jay@jayschwa.net>
|
Jay Weisskopf <jay@jayschwa.net>
|
||||||
Jean-Marc Eurin <jmeurin@google.com>
|
Jean-Marc Eurin <jmeurin@google.com>
|
||||||
Jed Denlea <jed@fastly.com>
|
Jed Denlea <jed@fastly.com>
|
||||||
|
Jeff Craig <jeffcraig@google.com>
|
||||||
Jeff Hodges <jeff@somethingsimilar.com>
|
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>
|
||||||
|
|
@ -430,6 +480,7 @@ 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>
|
||||||
|
Jess Frazelle <me@jessfraz.com>
|
||||||
Jihyun Yu <yjh0502@gmail.com>
|
Jihyun Yu <yjh0502@gmail.com>
|
||||||
Jim Cote <jfcote87@gmail.com>
|
Jim Cote <jfcote87@gmail.com>
|
||||||
Jim McGrath <jimmc2@gmail.com>
|
Jim McGrath <jimmc2@gmail.com>
|
||||||
|
|
@ -439,12 +490,15 @@ Jingguo Yao <yaojingguo@gmail.com>
|
||||||
Jiong Du <londevil@gmail.com>
|
Jiong Du <londevil@gmail.com>
|
||||||
Joakim Sernbrant <serbaut@gmail.com>
|
Joakim Sernbrant <serbaut@gmail.com>
|
||||||
Joe Harrison <joehazzers@gmail.com>
|
Joe Harrison <joehazzers@gmail.com>
|
||||||
|
Joe Henke <joed.henke@gmail.com>
|
||||||
Joe Poirier <jdpoirier@gmail.com>
|
Joe Poirier <jdpoirier@gmail.com>
|
||||||
Joe Shaw <joe@joeshaw.org>
|
Joe Shaw <joe@joeshaw.org>
|
||||||
|
Joe Sylve <joe.sylve@gmail.com>
|
||||||
Joe Tsai <joetsai@digital-static.net>
|
Joe Tsai <joetsai@digital-static.net>
|
||||||
Joel Sing <jsing@google.com>
|
Joel Sing <jsing@google.com>
|
||||||
Joel Stemmer <stemmertech@gmail.com>
|
Joel Stemmer <stemmertech@gmail.com>
|
||||||
Johan Euphrosine <proppy@google.com>
|
Johan Euphrosine <proppy@google.com>
|
||||||
|
Johan Sageryd <j@1616.se>
|
||||||
John Asmuth <jasmuth@gmail.com>
|
John Asmuth <jasmuth@gmail.com>
|
||||||
John Beisley <huin@google.com>
|
John Beisley <huin@google.com>
|
||||||
John C Barstow <jbowtie@amathaine.com>
|
John C Barstow <jbowtie@amathaine.com>
|
||||||
|
|
@ -452,12 +506,15 @@ John DeNero <denero@google.com>
|
||||||
John Dethridge <jcd@golang.org>
|
John Dethridge <jcd@golang.org>
|
||||||
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 Jeffery <jjeffery@sp.com.au>
|
||||||
John Jenkins <twodopeshaggy@gmail.com>
|
John Jenkins <twodopeshaggy@gmail.com>
|
||||||
John Newlin <jnewlin@google.com>
|
John Newlin <jnewlin@google.com>
|
||||||
John Potocny <johnp@vividcortex.com>
|
John Potocny <johnp@vividcortex.com>
|
||||||
|
John Schnake <schnake.john@gmail.com>
|
||||||
John Shahid <jvshahid@gmail.com>
|
John Shahid <jvshahid@gmail.com>
|
||||||
John Tuley <john@tuley.org>
|
John Tuley <john@tuley.org>
|
||||||
Jonathan Allie <jonallie@google.com>
|
Jonathan Allie <jonallie@google.com>
|
||||||
|
Jonathan Amsterdam <jba@google.com>
|
||||||
Jonathan Boulle <jonathanboulle@gmail.com>
|
Jonathan Boulle <jonathanboulle@gmail.com>
|
||||||
Jonathan Feinberg <feinberg@google.com>
|
Jonathan Feinberg <feinberg@google.com>
|
||||||
Jonathan Gold <jgold.bg@gmail.com>
|
Jonathan Gold <jgold.bg@gmail.com>
|
||||||
|
|
@ -481,11 +538,14 @@ Jostein Stuhaug <js@solidsystem.no>
|
||||||
JP Sugarbroad <jpsugar@google.com>
|
JP Sugarbroad <jpsugar@google.com>
|
||||||
JT Olds <jtolds@xnet5.com>
|
JT Olds <jtolds@xnet5.com>
|
||||||
Jukka-Pekka Kekkonen <karatepekka@gmail.com>
|
Jukka-Pekka Kekkonen <karatepekka@gmail.com>
|
||||||
|
Julia Hansbrough <flowerhack@google.com>
|
||||||
Julian Phillips <julian@quantumfyre.co.uk>
|
Julian Phillips <julian@quantumfyre.co.uk>
|
||||||
Julien Schmidt <google@julienschmidt.com>
|
Julien Schmidt <google@julienschmidt.com>
|
||||||
Jungho Ahn <jhahn@google.com>
|
Jungho Ahn <jhahn@google.com>
|
||||||
|
Jure Ham <jure.ham@zemanta.com>
|
||||||
Justin Nuß <nuss.justin@gmail.com>
|
Justin Nuß <nuss.justin@gmail.com>
|
||||||
Kai Backman <kaib@golang.org>
|
Kai Backman <kaib@golang.org>
|
||||||
|
Kamal Aboul-Hosn <aboulhosn@google.com>
|
||||||
Kamil Kisiel <kamil@kamilkisiel.net> <kamil.kisiel@gmail.com>
|
Kamil Kisiel <kamil@kamilkisiel.net> <kamil.kisiel@gmail.com>
|
||||||
Kang Hu <hukangustc@gmail.com>
|
Kang Hu <hukangustc@gmail.com>
|
||||||
Kato Kazuyoshi <kato.kazuyoshi@gmail.com>
|
Kato Kazuyoshi <kato.kazuyoshi@gmail.com>
|
||||||
|
|
@ -502,10 +562,15 @@ Ken Friedenbach <kenliz@cruzio.com>
|
||||||
Ken Rockot <ken@oz.gs> <ken.rockot@gmail.com>
|
Ken Rockot <ken@oz.gs> <ken.rockot@gmail.com>
|
||||||
Ken Sedgwick <ken@bonsai.com>
|
Ken Sedgwick <ken@bonsai.com>
|
||||||
Ken Thompson <ken@golang.org>
|
Ken Thompson <ken@golang.org>
|
||||||
|
Kenji Kaneda <kenji.kaneda@gmail.com>
|
||||||
|
Kenneth Shaw <kenshaw@gmail.com>
|
||||||
Kenny Grant <kennygrant@gmail.com>
|
Kenny Grant <kennygrant@gmail.com>
|
||||||
Kevin Ballard <kevin@sb.org>
|
Kevin Ballard <kevin@sb.org>
|
||||||
|
Kevin Burke <kev@inburke.com>
|
||||||
|
Kevin Kirsche <kev.kirsche@gmail.com>
|
||||||
Kevin Klues <klueska@gmail.com> <klueska@google.com>
|
Kevin Klues <klueska@gmail.com> <klueska@google.com>
|
||||||
Kevin Malachowski <chowski@google.com>
|
Kevin Malachowski <chowski@google.com>
|
||||||
|
Kevin Vu <kevin.m.vu@gmail.com>
|
||||||
Kim Shrier <kshrier@racktopsystems.com>
|
Kim Shrier <kshrier@racktopsystems.com>
|
||||||
Kirklin McDonald <kirklin.mcdonald@gmail.com>
|
Kirklin McDonald <kirklin.mcdonald@gmail.com>
|
||||||
Klaus Post <klauspost@gmail.com>
|
Klaus Post <klauspost@gmail.com>
|
||||||
|
|
@ -519,11 +584,13 @@ L Campbell <unpantsu@gmail.com>
|
||||||
Lai Jiangshan <eag0628@gmail.com>
|
Lai Jiangshan <eag0628@gmail.com>
|
||||||
Larry Hosken <lahosken@golang.org>
|
Larry Hosken <lahosken@golang.org>
|
||||||
Larz Conwell <larzconwell@gmail.com>
|
Larz Conwell <larzconwell@gmail.com>
|
||||||
|
Lee Hinman <hinman@gmail.com>
|
||||||
Lee Packham <lpackham@gmail.com>
|
Lee Packham <lpackham@gmail.com>
|
||||||
Lewin Bormann <lewin.bormann@gmail.com>
|
Lewin Bormann <lewin.bormann@gmail.com>
|
||||||
Lloyd Dewolf <foolswisdom@gmail.com>
|
Lloyd Dewolf <foolswisdom@gmail.com>
|
||||||
Lorenzo Stoakes <lstoakes@gmail.com>
|
Lorenzo Stoakes <lstoakes@gmail.com>
|
||||||
Louis Kruger <louisk@google.com>
|
Louis Kruger <louisk@google.com>
|
||||||
|
Luan Santos <cfcluan@gmail.com>
|
||||||
Luca Greco <luca.greco@alcacoop.it>
|
Luca Greco <luca.greco@alcacoop.it>
|
||||||
Lucien Stuker <lucien.stuker@gmail.com>
|
Lucien Stuker <lucien.stuker@gmail.com>
|
||||||
Lucio De Re <lucio.dere@gmail.com>
|
Lucio De Re <lucio.dere@gmail.com>
|
||||||
|
|
@ -539,11 +606,13 @@ Manu Garg <manugarg@google.com>
|
||||||
Manu S Ajith <neo@codingarena.in>
|
Manu S Ajith <neo@codingarena.in>
|
||||||
Manuel Mendez <mmendez534@gmail.com>
|
Manuel Mendez <mmendez534@gmail.com>
|
||||||
Marc Weistroff <marc@weistroff.net>
|
Marc Weistroff <marc@weistroff.net>
|
||||||
|
Marc-Antoine Ruel <maruel@chromium.org>
|
||||||
Marcel van Lohuizen <mpvl@golang.org>
|
Marcel van Lohuizen <mpvl@golang.org>
|
||||||
Marco Hennings <marco.hennings@freiheit.com>
|
Marco Hennings <marco.hennings@freiheit.com>
|
||||||
Marga Manterola <marga@google.com>
|
Marga Manterola <marga@google.com>
|
||||||
Marius Nuennerich <mnu@google.com>
|
Marius Nuennerich <mnu@google.com>
|
||||||
Mark Bucciarelli <mkbucc@gmail.com>
|
Mark Bucciarelli <mkbucc@gmail.com>
|
||||||
|
Mark Severson <miquella@gmail.com>
|
||||||
Mark Theunissen <mark.theunissen@gmail.com>
|
Mark Theunissen <mark.theunissen@gmail.com>
|
||||||
Mark Zavislak <zavislak@google.com>
|
Mark Zavislak <zavislak@google.com>
|
||||||
Marko Juhani Silokunnas <marko.silokunnas@gmail.com>
|
Marko Juhani Silokunnas <marko.silokunnas@gmail.com>
|
||||||
|
|
@ -552,12 +621,14 @@ Marko Tiikkaja <marko@joh.to>
|
||||||
Markus Duft <markus.duft@salomon.at>
|
Markus Duft <markus.duft@salomon.at>
|
||||||
Markus Sonderegger <marraison@gmail.com>
|
Markus Sonderegger <marraison@gmail.com>
|
||||||
Markus Zimmermann <zimmski@gmail.com>
|
Markus Zimmermann <zimmski@gmail.com>
|
||||||
|
Martin Garton <garton@gmail.com>
|
||||||
Martin Möhrmann <martisch@uos.de>
|
Martin Möhrmann <martisch@uos.de>
|
||||||
Martin Neubauer <m.ne@gmx.net>
|
Martin Neubauer <m.ne@gmx.net>
|
||||||
Martin Olsson <martin@minimum.se>
|
Martin Olsson <martin@minimum.se>
|
||||||
Marvin Stenger <marvin.stenger94@gmail.com>
|
Marvin Stenger <marvin.stenger94@gmail.com>
|
||||||
Mateusz Czapliński <czapkofan@gmail.com>
|
Mateusz Czapliński <czapkofan@gmail.com>
|
||||||
Mathias Beke <git@denbeke.be>
|
Mathias Beke <git@denbeke.be>
|
||||||
|
Mathias Leppich <mleppich@muhqu.de>
|
||||||
Mathieu Lonjaret <mathieu.lonjaret@gmail.com>
|
Mathieu Lonjaret <mathieu.lonjaret@gmail.com>
|
||||||
Mats Lidell <mats.lidell@cag.se> <mats.lidell@gmail.com>
|
Mats Lidell <mats.lidell@cag.se> <mats.lidell@gmail.com>
|
||||||
Matt Aimonetti <mattaimonetti@gmail.com>
|
Matt Aimonetti <mattaimonetti@gmail.com>
|
||||||
|
|
@ -569,6 +640,7 @@ Matt Joiner <anacrolix@gmail.com>
|
||||||
Matt Jones <mrjones@google.com>
|
Matt Jones <mrjones@google.com>
|
||||||
Matt Layher <mdlayher@gmail.com>
|
Matt Layher <mdlayher@gmail.com>
|
||||||
Matt Reiferson <mreiferson@gmail.com>
|
Matt Reiferson <mreiferson@gmail.com>
|
||||||
|
Matt Robenolt <matt@ydekproductions.com>
|
||||||
Matt T. Proud <matt.proud@gmail.com>
|
Matt T. Proud <matt.proud@gmail.com>
|
||||||
Matt Williams <gh@mattyw.net> <mattyjwilliams@gmail.com>
|
Matt Williams <gh@mattyw.net> <mattyjwilliams@gmail.com>
|
||||||
Matthew Brennan <matty.brennan@gmail.com>
|
Matthew Brennan <matty.brennan@gmail.com>
|
||||||
|
|
@ -579,6 +651,7 @@ Matthew Horsnell <matthew.horsnell@gmail.com>
|
||||||
Maxim Khitrov <max@mxcrypt.com>
|
Maxim Khitrov <max@mxcrypt.com>
|
||||||
Maxim Pimenov <mpimenov@google.com>
|
Maxim Pimenov <mpimenov@google.com>
|
||||||
Maxim Ushakov <ushakov@google.com>
|
Maxim Ushakov <ushakov@google.com>
|
||||||
|
Maxwell Krohn <themax@gmail.com>
|
||||||
Meir Fischer <meirfischer@gmail.com>
|
Meir Fischer <meirfischer@gmail.com>
|
||||||
Meng Zhuo <mengzhuo1203@gmail.com>
|
Meng Zhuo <mengzhuo1203@gmail.com>
|
||||||
Mhd Sulhan <m.shulhan@gmail.com>
|
Mhd Sulhan <m.shulhan@gmail.com>
|
||||||
|
|
@ -595,9 +668,12 @@ Michael Lewis <mikelikespie@gmail.com>
|
||||||
Michael MacInnis <Michael.P.MacInnis@gmail.com>
|
Michael MacInnis <Michael.P.MacInnis@gmail.com>
|
||||||
Michael Marineau <michael.marineau@coreos.com>
|
Michael Marineau <michael.marineau@coreos.com>
|
||||||
Michael Matloob <matloob@google.com>
|
Michael Matloob <matloob@google.com>
|
||||||
|
Michael McConville <momcconville@gmail.com>
|
||||||
Michael McGreevy <mcgreevy@golang.org>
|
Michael McGreevy <mcgreevy@golang.org>
|
||||||
|
Michael Munday <munday@ca.ibm.com>
|
||||||
Michael Pearson <mipearson@gmail.com>
|
Michael Pearson <mipearson@gmail.com>
|
||||||
Michael Piatek <piatek@google.com>
|
Michael Piatek <piatek@google.com>
|
||||||
|
Michael Pratt <mpratt@google.com>
|
||||||
Michael Schaller <michael@5challer.de>
|
Michael Schaller <michael@5challer.de>
|
||||||
Michael Shields <mshields@google.com>
|
Michael Shields <mshields@google.com>
|
||||||
Michael Stapelberg <michael@stapelberg.de> <mstplbrg@googlemail.com>
|
Michael Stapelberg <michael@stapelberg.de> <mstplbrg@googlemail.com>
|
||||||
|
|
@ -608,22 +684,28 @@ Michal Bohuslávek <mbohuslavek@gmail.com>
|
||||||
Michal Cierniak <cierniak@google.com>
|
Michal Cierniak <cierniak@google.com>
|
||||||
Michał Derkacz <ziutek@lnet.pl>
|
Michał Derkacz <ziutek@lnet.pl>
|
||||||
Michalis Kargakis <michaliskargakis@gmail.com>
|
Michalis Kargakis <michaliskargakis@gmail.com>
|
||||||
|
Michel Lespinasse <walken@google.com>
|
||||||
Miek Gieben <miek@miek.nl> <remigius.gieben@gmail.com>
|
Miek Gieben <miek@miek.nl> <remigius.gieben@gmail.com>
|
||||||
Mihai Borobocea <MihaiBorobocea@gmail.com>
|
Mihai Borobocea <MihaiBorobocea@gmail.com>
|
||||||
Mikael Tillenius <mikti42@gmail.com>
|
Mikael Tillenius <mikti42@gmail.com>
|
||||||
Mike Andrews <mra@xoba.com>
|
Mike Andrews <mra@xoba.com>
|
||||||
|
Mike Danese <mikedanese@google.com>
|
||||||
Mike Rosset <mike.rosset@gmail.com>
|
Mike Rosset <mike.rosset@gmail.com>
|
||||||
Mike Samuel <mikesamuel@gmail.com>
|
Mike Samuel <mikesamuel@gmail.com>
|
||||||
Mike Solomon <msolo@gmail.com>
|
Mike Solomon <msolo@gmail.com>
|
||||||
|
Mikhail Gusarov <dottedmag@dottedmag.net>
|
||||||
Mikhail Panchenko <m@mihasya.com>
|
Mikhail Panchenko <m@mihasya.com>
|
||||||
Miki Tebeka <miki.tebeka@gmail.com>
|
Miki Tebeka <miki.tebeka@gmail.com>
|
||||||
Mikio Hara <mikioh.mikioh@gmail.com>
|
Mikio Hara <mikioh.mikioh@gmail.com>
|
||||||
Mikkel Krautz <mikkel@krautz.dk> <krautz@gmail.com>
|
Mikkel Krautz <mikkel@krautz.dk> <krautz@gmail.com>
|
||||||
Miquel Sabaté Solà <mikisabate@gmail.com>
|
Miquel Sabaté Solà <mikisabate@gmail.com>
|
||||||
Mohit Agarwal <mohit@sdf.org>
|
Mohit Agarwal <mohit@sdf.org>
|
||||||
|
Monty Taylor <mordred@inaugust.com>
|
||||||
Moriyoshi Koizumi <mozo@mozo.jp>
|
Moriyoshi Koizumi <mozo@mozo.jp>
|
||||||
|
Morten Siebuhr <sbhr@sbhr.dk>
|
||||||
Môshe van der Sterre <moshevds@gmail.com>
|
Môshe van der Sterre <moshevds@gmail.com>
|
||||||
Mrunal Patel <mrunalp@gmail.com>
|
Mrunal Patel <mrunalp@gmail.com>
|
||||||
|
Muhammed Uluyol <uluyol0@gmail.com>
|
||||||
Nan Deng <monnand@gmail.com>
|
Nan Deng <monnand@gmail.com>
|
||||||
Nathan John Youngman <nj@nathany.com>
|
Nathan John Youngman <nj@nathany.com>
|
||||||
Nathan Otterness <otternes@cs.unc.edu>
|
Nathan Otterness <otternes@cs.unc.edu>
|
||||||
|
|
@ -633,17 +715,22 @@ Nathan Youngman <git@nathany.com>
|
||||||
Nathan(yinian) Hu <nathanhu@google.com>
|
Nathan(yinian) Hu <nathanhu@google.com>
|
||||||
Neelesh Chandola <neelesh.c98@gmail.com>
|
Neelesh Chandola <neelesh.c98@gmail.com>
|
||||||
Nevins Bartolomeo <nevins.bartolomeo@gmail.com>
|
Nevins Bartolomeo <nevins.bartolomeo@gmail.com>
|
||||||
|
Niall Sheridan <nsheridan@gmail.com>
|
||||||
Nicholas Katsaros <nick@nickkatsaros.com>
|
Nicholas Katsaros <nick@nickkatsaros.com>
|
||||||
Nicholas Presta <nick@nickpresta.ca> <nick1presta@gmail.com>
|
Nicholas Presta <nick@nickpresta.ca> <nick1presta@gmail.com>
|
||||||
Nicholas Sullivan <nicholas.sullivan@gmail.com>
|
Nicholas Sullivan <nicholas.sullivan@gmail.com>
|
||||||
Nicholas Waples <nwaples@gmail.com>
|
Nicholas Waples <nwaples@gmail.com>
|
||||||
Nick Cooper <nmvc@google.com>
|
Nick Cooper <nmvc@google.com>
|
||||||
Nick Craig-Wood <nick@craig-wood.com> <nickcw@gmail.com>
|
Nick Craig-Wood <nick@craig-wood.com> <nickcw@gmail.com>
|
||||||
|
Nick Patavalis <nick.patavalis@gmail.com>
|
||||||
|
Nick Petroni <npetroni@cs.umd.edu>
|
||||||
Nicolas Kaiser <nikai@nikai.net>
|
Nicolas Kaiser <nikai@nikai.net>
|
||||||
Nicolas Owens <mischief@offblast.org>
|
Nicolas Owens <mischief@offblast.org>
|
||||||
Nicolas S. Dade <nic.dade@gmail.com>
|
Nicolas S. Dade <nic.dade@gmail.com>
|
||||||
|
Niels Widger <niels.widger@gmail.com>
|
||||||
Nigel Kerr <nigel.kerr@gmail.com>
|
Nigel Kerr <nigel.kerr@gmail.com>
|
||||||
Nigel Tao <nigeltao@golang.org>
|
Nigel Tao <nigeltao@golang.org>
|
||||||
|
Niko Dziemba <niko@dziemba.com>
|
||||||
Nikolay Turpitko <nikolay@turpitko.com>
|
Nikolay Turpitko <nikolay@turpitko.com>
|
||||||
Noah Campbell <noahcampbell@gmail.com>
|
Noah Campbell <noahcampbell@gmail.com>
|
||||||
Nodir Turakulov <nodir@google.com>
|
Nodir Turakulov <nodir@google.com>
|
||||||
|
|
@ -653,7 +740,10 @@ Oling Cat <olingcat@gmail.com>
|
||||||
Oliver Hookins <ohookins@gmail.com>
|
Oliver Hookins <ohookins@gmail.com>
|
||||||
Olivier Antoine <olivier.antoine@gmail.com>
|
Olivier Antoine <olivier.antoine@gmail.com>
|
||||||
Olivier Duperray <duperray.olivier@gmail.com>
|
Olivier Duperray <duperray.olivier@gmail.com>
|
||||||
|
Olivier Poitrey <rs@dailymotion.com>
|
||||||
Olivier Saingre <osaingre@gmail.com>
|
Olivier Saingre <osaingre@gmail.com>
|
||||||
|
Omar Jarjur <ojarjur@google.com>
|
||||||
|
Özgür Kesim <oec-go@kesim.org>
|
||||||
Padraig Kitterick <padraigkitterick@gmail.com>
|
Padraig Kitterick <padraigkitterick@gmail.com>
|
||||||
Paolo Giarrusso <p.giarrusso@gmail.com>
|
Paolo Giarrusso <p.giarrusso@gmail.com>
|
||||||
Paolo Martini <mrtnpaolo@gmail.com>
|
Paolo Martini <mrtnpaolo@gmail.com>
|
||||||
|
|
@ -678,6 +768,7 @@ Paul Rosania <paul.rosania@gmail.com>
|
||||||
Paul Sbarra <Sbarra.Paul@gmail.com>
|
Paul Sbarra <Sbarra.Paul@gmail.com>
|
||||||
Paul Smith <paulsmith@pobox.com> <paulsmith@gmail.com>
|
Paul Smith <paulsmith@pobox.com> <paulsmith@gmail.com>
|
||||||
Paul van Brouwershaven <paul@vanbrouwershaven.com>
|
Paul van Brouwershaven <paul@vanbrouwershaven.com>
|
||||||
|
Paul Wankadia <junyer@google.com>
|
||||||
Pavel Paulau <pavel.paulau@gmail.com>
|
Pavel Paulau <pavel.paulau@gmail.com>
|
||||||
Pavel Zinovkin <pavel.zinovkin@gmail.com>
|
Pavel Zinovkin <pavel.zinovkin@gmail.com>
|
||||||
Pawel Knap <pawelknap88@gmail.com>
|
Pawel Knap <pawelknap88@gmail.com>
|
||||||
|
|
@ -688,6 +779,7 @@ Petar Maymounkov <petarm@gmail.com>
|
||||||
Peter Armitage <peter.armitage@gmail.com>
|
Peter Armitage <peter.armitage@gmail.com>
|
||||||
Peter Collingbourne <pcc@google.com>
|
Peter Collingbourne <pcc@google.com>
|
||||||
Peter Froehlich <peter.hans.froehlich@gmail.com>
|
Peter Froehlich <peter.hans.froehlich@gmail.com>
|
||||||
|
Peter Gonda <pgonda@google.com>
|
||||||
Peter Kleiweg <pkleiweg@xs4all.nl>
|
Peter Kleiweg <pkleiweg@xs4all.nl>
|
||||||
Peter McKenzie <petermck@google.com>
|
Peter McKenzie <petermck@google.com>
|
||||||
Peter Moody <pmoody@uber.com>
|
Peter Moody <pmoody@uber.com>
|
||||||
|
|
@ -701,13 +793,17 @@ Peter Waller <peter.waller@gmail.com>
|
||||||
Peter Weinberger <pjw@golang.org>
|
Peter Weinberger <pjw@golang.org>
|
||||||
Peter Williams <pwil3058@gmail.com>
|
Peter Williams <pwil3058@gmail.com>
|
||||||
Phil Pennock <pdp@golang.org>
|
Phil Pennock <pdp@golang.org>
|
||||||
|
Philip Hofer <phofer@umich.edu>
|
||||||
Philip K. Warren <pkwarren@gmail.com>
|
Philip K. Warren <pkwarren@gmail.com>
|
||||||
|
Pierre Durand <pierredurand@gmail.com>
|
||||||
Pierre Roullon <pierre.roullon@gmail.com>
|
Pierre Roullon <pierre.roullon@gmail.com>
|
||||||
Pieter Droogendijk <pieter@binky.org.uk>
|
Pieter Droogendijk <pieter@binky.org.uk>
|
||||||
Pietro Gagliardi <pietro10@mac.com>
|
Pietro Gagliardi <pietro10@mac.com>
|
||||||
|
Prashant Varanasi <prashant@prashantv.com>
|
||||||
Preetam Jinka <pj@preet.am>
|
Preetam Jinka <pj@preet.am>
|
||||||
Quan Yong Zhai <qyzhai@gmail.com>
|
Quan Yong Zhai <qyzhai@gmail.com>
|
||||||
Quentin Perez <qperez@ocs.online.net>
|
Quentin Perez <qperez@ocs.online.net>
|
||||||
|
Quentin Smith <quentin@golang.org>
|
||||||
Quoc-Viet Nguyen <afelion@gmail.com>
|
Quoc-Viet Nguyen <afelion@gmail.com>
|
||||||
Rahul Chaudhry <rahulchaudhry@chromium.org>
|
Rahul Chaudhry <rahulchaudhry@chromium.org>
|
||||||
Raif S. Naffah <go@naffah-raif.name>
|
Raif S. Naffah <go@naffah-raif.name>
|
||||||
|
|
@ -717,12 +813,16 @@ Raph Levien <raph@google.com>
|
||||||
Raul Silvera <rsilvera@google.com>
|
Raul Silvera <rsilvera@google.com>
|
||||||
Reinaldo de Souza Jr <juniorz@gmail.com>
|
Reinaldo de Souza Jr <juniorz@gmail.com>
|
||||||
Rémy Oudompheng <oudomphe@phare.normalesup.org> <remyoudompheng@gmail.com>
|
Rémy Oudompheng <oudomphe@phare.normalesup.org> <remyoudompheng@gmail.com>
|
||||||
|
Rhys Hiltner <rhys@justin.tv>
|
||||||
|
Ricardo Padilha <ricardospadilha@gmail.com>
|
||||||
Richard Barnes <rlb@ipv.sx>
|
Richard Barnes <rlb@ipv.sx>
|
||||||
Richard Crowley <r@rcrowley.org>
|
Richard Crowley <r@rcrowley.org>
|
||||||
Richard Eric Gavaletz <gavaletz@gmail.com>
|
Richard Eric Gavaletz <gavaletz@gmail.com>
|
||||||
|
Richard Miller <miller.research@gmail.com>
|
||||||
Richard Musiol <mail@richard-musiol.de> <neelance@gmail.com>
|
Richard Musiol <mail@richard-musiol.de> <neelance@gmail.com>
|
||||||
Rick Arnold <rickarnoldjr@gmail.com>
|
Rick Arnold <rickarnoldjr@gmail.com>
|
||||||
Rick Hudson <rlh@golang.org>
|
Rick Hudson <rlh@golang.org>
|
||||||
|
Riku Voipio <riku.voipio@linaro.org>
|
||||||
Risto Jaakko Saarelma <rsaarelm@gmail.com>
|
Risto Jaakko Saarelma <rsaarelm@gmail.com>
|
||||||
Rob Earhart <earhart@google.com>
|
Rob Earhart <earhart@google.com>
|
||||||
Rob Norman <rob.norman@infinitycloud.com>
|
Rob Norman <rob.norman@infinitycloud.com>
|
||||||
|
|
@ -742,6 +842,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>
|
||||||
|
Roland Shoemaker <rolandshoemaker@gmail.com>
|
||||||
Ron Hashimoto <mail@h2so5.net>
|
Ron Hashimoto <mail@h2so5.net>
|
||||||
Ron Minnich <rminnich@gmail.com>
|
Ron Minnich <rminnich@gmail.com>
|
||||||
Ross Light <light@google.com> <rlight2@gmail.com>
|
Ross Light <light@google.com> <rlight2@gmail.com>
|
||||||
|
|
@ -757,17 +858,23 @@ Ryan Seys <ryan@ryanseys.com>
|
||||||
Ryan Slade <ryanslade@gmail.com>
|
Ryan Slade <ryanslade@gmail.com>
|
||||||
S.Çağlar Onur <caglar@10ur.org>
|
S.Çağlar Onur <caglar@10ur.org>
|
||||||
Salmān Aljammāz <s@0x65.net>
|
Salmān Aljammāz <s@0x65.net>
|
||||||
|
Sam Hug <samuel.b.hug@gmail.com>
|
||||||
Sam Thorogood <thorogood@google.com> <sam.thorogood@gmail.com>
|
Sam Thorogood <thorogood@google.com> <sam.thorogood@gmail.com>
|
||||||
|
Sam Whited <sam@samwhited.com>
|
||||||
Sameer Ajmani <sameer@golang.org> <ajmani@gmail.com>
|
Sameer Ajmani <sameer@golang.org> <ajmani@gmail.com>
|
||||||
|
Sami Commerot <samic@google.com>
|
||||||
Sanjay Menakuru <balasanjay@gmail.com>
|
Sanjay Menakuru <balasanjay@gmail.com>
|
||||||
Sasha Lionheart <lionhearts@google.com>
|
Sasha Lionheart <lionhearts@google.com>
|
||||||
Scott Barron <scott.barron@github.com>
|
Scott Barron <scott.barron@github.com>
|
||||||
|
Scott Bell <scott@sctsm.com>
|
||||||
Scott Ferguson <scottwferg@gmail.com>
|
Scott Ferguson <scottwferg@gmail.com>
|
||||||
Scott Lawrence <bytbox@gmail.com>
|
Scott Lawrence <bytbox@gmail.com>
|
||||||
|
Scott Mansfield <smansfield@netflix.com>
|
||||||
Scott Schwartz <scotts@golang.org>
|
Scott Schwartz <scotts@golang.org>
|
||||||
Scott Van Woudenberg <scottvw@google.com>
|
Scott Van Woudenberg <scottvw@google.com>
|
||||||
Sean Burford <sburford@google.com>
|
Sean Burford <sburford@google.com>
|
||||||
Sean Dolphin <Sean.Dolphin@kpcompass.com>
|
Sean Dolphin <Sean.Dolphin@kpcompass.com>
|
||||||
|
Sean Harger <sharger@google.com>
|
||||||
Sebastien Binet <seb.binet@gmail.com>
|
Sebastien Binet <seb.binet@gmail.com>
|
||||||
Sébastien Paolacci <sebastien.paolacci@gmail.com>
|
Sébastien Paolacci <sebastien.paolacci@gmail.com>
|
||||||
Sergei Skorobogatov <skorobo@rambler.ru>
|
Sergei Skorobogatov <skorobo@rambler.ru>
|
||||||
|
|
@ -775,20 +882,24 @@ Sergey 'SnakE' Gromov <snake.scaly@gmail.com>
|
||||||
Sergey Arseev <sergey.arseev@intel.com>
|
Sergey Arseev <sergey.arseev@intel.com>
|
||||||
Sergio Luis O. B. Correia <sergio@correia.cc>
|
Sergio Luis O. B. Correia <sergio@correia.cc>
|
||||||
Seth Hoenig <seth.a.hoenig@gmail.com>
|
Seth Hoenig <seth.a.hoenig@gmail.com>
|
||||||
|
Shahar Kohanim <skohanim@gmail.com>
|
||||||
Shane Hansen <shanemhansen@gmail.com>
|
Shane Hansen <shanemhansen@gmail.com>
|
||||||
Shaozhen Ding <dsz0111@gmail.com>
|
Shaozhen Ding <dsz0111@gmail.com>
|
||||||
Shawn Ledbetter <sledbetter@google.com>
|
Shawn Ledbetter <sledbetter@google.com>
|
||||||
Shawn Smith <shawn.p.smith@gmail.com>
|
Shawn Smith <shawn.p.smith@gmail.com>
|
||||||
Shawn Walker-Salas <shawn.walker@oracle.com>
|
Shawn Walker-Salas <shawn.walker@oracle.com>
|
||||||
Shenghou Ma <minux@golang.org> <minux.ma@gmail.com>
|
Shenghou Ma <minux@golang.org> <minux.ma@gmail.com>
|
||||||
|
Shinji Tanaka <shinji.tanaka@gmail.com>
|
||||||
Shivakumar GN <shivakumar.gn@gmail.com>
|
Shivakumar GN <shivakumar.gn@gmail.com>
|
||||||
Shun Fan <sfan@google.com>
|
Shun Fan <sfan@google.com>
|
||||||
Silvan Jegen <s.jegen@gmail.com>
|
Silvan Jegen <s.jegen@gmail.com>
|
||||||
|
Simon Jefford <simon.jefford@gmail.com>
|
||||||
Simon Whitehead <chemnova@gmail.com>
|
Simon Whitehead <chemnova@gmail.com>
|
||||||
Sokolov Yura <funny.falcon@gmail.com>
|
Sokolov Yura <funny.falcon@gmail.com>
|
||||||
Spencer Nelson <s@spenczar.com>
|
Spencer Nelson <s@spenczar.com>
|
||||||
Spring Mc <heresy.mc@gmail.com>
|
Spring Mc <heresy.mc@gmail.com>
|
||||||
Srdjan Petrovic <spetrovic@google.com>
|
Srdjan Petrovic <spetrovic@google.com>
|
||||||
|
Sridhar Venkatakrishnan <sridhar@laddoo.net>
|
||||||
StalkR <stalkr@stalkr.net>
|
StalkR <stalkr@stalkr.net>
|
||||||
Stan Schwertly <stan@schwertly.com>
|
Stan Schwertly <stan@schwertly.com>
|
||||||
Stefan Nilsson <snilsson@nada.kth.se> <trolleriprofessorn@gmail.com>
|
Stefan Nilsson <snilsson@nada.kth.se> <trolleriprofessorn@gmail.com>
|
||||||
|
|
@ -803,12 +914,14 @@ Steve Streeting <steve@stevestreeting.com>
|
||||||
Steven Elliot Harris <seharris@gmail.com>
|
Steven Elliot Harris <seharris@gmail.com>
|
||||||
Steven Hartland <steven.hartland@multiplay.co.uk>
|
Steven Hartland <steven.hartland@multiplay.co.uk>
|
||||||
Sugu Sougoumarane <ssougou@gmail.com>
|
Sugu Sougoumarane <ssougou@gmail.com>
|
||||||
|
Suharsh Sivakumar <suharshs@google.com>
|
||||||
Sven Almgren <sven@tras.se>
|
Sven Almgren <sven@tras.se>
|
||||||
Szabolcs Nagy <nsz@port70.net>
|
Szabolcs Nagy <nsz@port70.net>
|
||||||
Tad Glines <tad.glines@gmail.com>
|
Tad Glines <tad.glines@gmail.com>
|
||||||
Taj Khattra <taj.khattra@gmail.com>
|
Taj Khattra <taj.khattra@gmail.com>
|
||||||
Takashi Matsuo <tmatsuo@google.com>
|
Takashi Matsuo <tmatsuo@google.com>
|
||||||
Takeshi YAMANASHI <9.nashi@gmail.com>
|
Takeshi YAMANASHI <9.nashi@gmail.com>
|
||||||
|
Tal Shprecher <tshprecher@gmail.com>
|
||||||
Tamir Duberstein <tamird@gmail.com>
|
Tamir Duberstein <tamird@gmail.com>
|
||||||
Tarmigan Casebolt <tarmigan@gmail.com>
|
Tarmigan Casebolt <tarmigan@gmail.com>
|
||||||
Taru Karttunen <taruti@taruti.net>
|
Taru Karttunen <taruti@taruti.net>
|
||||||
|
|
@ -820,13 +933,20 @@ Thomas Desrosiers <thomasdesr@gmail.com>
|
||||||
Thomas Habets <habets@google.com>
|
Thomas Habets <habets@google.com>
|
||||||
Thomas Kappler <tkappler@gmail.com>
|
Thomas Kappler <tkappler@gmail.com>
|
||||||
Thorben Krueger <thorben.krueger@gmail.com>
|
Thorben Krueger <thorben.krueger@gmail.com>
|
||||||
|
Tilman Dilo <tilman.dilo@gmail.com>
|
||||||
Tim Cooijmans <timcooijmans@gmail.com>
|
Tim Cooijmans <timcooijmans@gmail.com>
|
||||||
|
Tim Ebringer <tim.ebringer@gmail.com>
|
||||||
Tim Hockin <thockin@google.com>
|
Tim Hockin <thockin@google.com>
|
||||||
|
Tim Swast <swast@google.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>
|
||||||
|
Timothy Studd <tim@timstudd.com>
|
||||||
|
Tipp Moseley <tipp@google.com>
|
||||||
Tobias Columbus <tobias.columbus@gmail.com> <tobias.columbus@googlemail.com>
|
Tobias Columbus <tobias.columbus@gmail.com> <tobias.columbus@googlemail.com>
|
||||||
|
Toby Burress <kurin@google.com>
|
||||||
Todd Neal <todd@tneal.org>
|
Todd Neal <todd@tneal.org>
|
||||||
Todd Wang <toddwang@gmail.com>
|
Todd Wang <toddwang@gmail.com>
|
||||||
|
Tom Bergan <tombergan@google.com>
|
||||||
Tom Heng <zhm20070928@gmail.com>
|
Tom Heng <zhm20070928@gmail.com>
|
||||||
Tom Linford <tomlinford@gmail.com>
|
Tom Linford <tomlinford@gmail.com>
|
||||||
Tom Szymanski <tgs@google.com>
|
Tom Szymanski <tgs@google.com>
|
||||||
|
|
@ -840,11 +960,13 @@ Trey Tacon <ttacon@gmail.com>
|
||||||
Tudor Golubenco <tudor.g@gmail.com>
|
Tudor Golubenco <tudor.g@gmail.com>
|
||||||
Tyler Bunnell <tylerbunnell@gmail.com>
|
Tyler Bunnell <tylerbunnell@gmail.com>
|
||||||
Tyler Treat <ttreat31@gmail.com>
|
Tyler Treat <ttreat31@gmail.com>
|
||||||
|
Tzu-Jung Lee <roylee17@currant.com>
|
||||||
Ugorji Nwoke <ugorji@gmail.com>
|
Ugorji Nwoke <ugorji@gmail.com>
|
||||||
Ulf Holm Nielsen <doktor@dyregod.dk>
|
Ulf Holm Nielsen <doktor@dyregod.dk>
|
||||||
Ulrich Kunitz <uli.kunitz@gmail.com>
|
Ulrich Kunitz <uli.kunitz@gmail.com>
|
||||||
Uriel Mangado <uriel@berlinblue.org>
|
Uriel Mangado <uriel@berlinblue.org>
|
||||||
Uttam C Pawar <uttam.c.pawar@intel.com>
|
Uttam C Pawar <uttam.c.pawar@intel.com>
|
||||||
|
Vadim Grek <vadimprog@gmail.com>
|
||||||
Vadim Vygonets <unixdj@gmail.com>
|
Vadim Vygonets <unixdj@gmail.com>
|
||||||
Vega Garcia Luis Alfonso <vegacom@gmail.com>
|
Vega Garcia Luis Alfonso <vegacom@gmail.com>
|
||||||
Vincent Ambo <tazjin@googlemail.com>
|
Vincent Ambo <tazjin@googlemail.com>
|
||||||
|
|
@ -852,9 +974,11 @@ Vincent Batts <vbatts@hashbangbash.com> <vbatts@gmail.com>
|
||||||
Vincent Vanackere <vincent.vanackere@gmail.com>
|
Vincent Vanackere <vincent.vanackere@gmail.com>
|
||||||
Vinu Rajashekhar <vinutheraj@gmail.com>
|
Vinu Rajashekhar <vinutheraj@gmail.com>
|
||||||
Vish Subramanian <vish@google.com>
|
Vish Subramanian <vish@google.com>
|
||||||
|
Vishvananda Ishaya <vishvananda@gmail.com>
|
||||||
Vlad Krasnov <vlad@cloudflare.com>
|
Vlad Krasnov <vlad@cloudflare.com>
|
||||||
Vladimir Nikishenko <vova616@gmail.com>
|
Vladimir Nikishenko <vova616@gmail.com>
|
||||||
Volker Dobler <dr.volker.dobler@gmail.com>
|
Volker Dobler <dr.volker.dobler@gmail.com>
|
||||||
|
Wedson Almeida Filho <wedsonaf@google.com>
|
||||||
Wei Guangjing <vcc.163@gmail.com>
|
Wei Guangjing <vcc.163@gmail.com>
|
||||||
Will Chan <willchan@google.com>
|
Will Chan <willchan@google.com>
|
||||||
Will Norris <willnorris@google.com>
|
Will Norris <willnorris@google.com>
|
||||||
|
|
@ -864,6 +988,7 @@ William Josephson <wjosephson@gmail.com>
|
||||||
William Orr <will@worrbase.com> <ay1244@gmail.com>
|
William Orr <will@worrbase.com> <ay1244@gmail.com>
|
||||||
Xia Bin <snyh@snyh.org>
|
Xia Bin <snyh@snyh.org>
|
||||||
Xing Xing <mikespook@gmail.com>
|
Xing Xing <mikespook@gmail.com>
|
||||||
|
Xudong Zhang <felixmelon@gmail.com>
|
||||||
Yan Zou <yzou@google.com>
|
Yan Zou <yzou@google.com>
|
||||||
Yann Kerhervé <yann.kerherve@gmail.com>
|
Yann Kerhervé <yann.kerherve@gmail.com>
|
||||||
Yao Zhang <lunaria21@gmail.com>
|
Yao Zhang <lunaria21@gmail.com>
|
||||||
|
|
@ -879,6 +1004,7 @@ Yusuke Kagiwada <block.rxckin.beats@gmail.com>
|
||||||
Yuusei Kuwana <kuwana@kumama.org>
|
Yuusei Kuwana <kuwana@kumama.org>
|
||||||
Yuval Pavel Zholkover <paulzhol@gmail.com>
|
Yuval Pavel Zholkover <paulzhol@gmail.com>
|
||||||
Yves Junqueira <yvesj@google.com> <yves.junqueira@gmail.com>
|
Yves Junqueira <yvesj@google.com> <yves.junqueira@gmail.com>
|
||||||
|
Zhongwei Yao <zhongwei.yao@arm.com>
|
||||||
Ziad Hatahet <hatahet@gmail.com>
|
Ziad Hatahet <hatahet@gmail.com>
|
||||||
Zorion Arrizabalaga <zorionk@gmail.com>
|
Zorion Arrizabalaga <zorionk@gmail.com>
|
||||||
申习之 <bronze1man@gmail.com>
|
申习之 <bronze1man@gmail.com>
|
||||||
|
|
|
||||||
62
api/next.txt
62
api/next.txt
|
|
@ -17,7 +17,15 @@ pkg context, type Context interface, Err() error
|
||||||
pkg context, type Context interface, Value(interface{}) interface{}
|
pkg context, type Context interface, Value(interface{}) interface{}
|
||||||
pkg context, var Canceled error
|
pkg context, var Canceled error
|
||||||
pkg context, var DeadlineExceeded error
|
pkg context, var DeadlineExceeded error
|
||||||
|
pkg crypto/tls, const RenegotiateFreelyAsClient = 2
|
||||||
|
pkg crypto/tls, const RenegotiateFreelyAsClient RenegotiationSupport
|
||||||
|
pkg crypto/tls, const RenegotiateNever = 0
|
||||||
|
pkg crypto/tls, const RenegotiateNever RenegotiationSupport
|
||||||
|
pkg crypto/tls, const RenegotiateOnceAsClient = 1
|
||||||
|
pkg crypto/tls, const RenegotiateOnceAsClient RenegotiationSupport
|
||||||
pkg crypto/tls, type Config struct, DynamicRecordSizingDisabled bool
|
pkg crypto/tls, type Config struct, DynamicRecordSizingDisabled bool
|
||||||
|
pkg crypto/tls, type Config struct, Renegotiation RenegotiationSupport
|
||||||
|
pkg crypto/tls, type RenegotiationSupport int
|
||||||
pkg crypto/x509, func SystemCertPool() (*CertPool, error)
|
pkg crypto/x509, func SystemCertPool() (*CertPool, error)
|
||||||
pkg crypto/x509, type SystemRootsError struct, Err error
|
pkg crypto/x509, type SystemRootsError struct, Err error
|
||||||
pkg debug/dwarf, method (*Data) Ranges(*Entry) ([][2]uint64, error)
|
pkg debug/dwarf, method (*Data) Ranges(*Entry) ([][2]uint64, error)
|
||||||
|
|
@ -147,8 +155,9 @@ pkg debug/elf, const R_390_TLS_TPOFF R_390
|
||||||
pkg debug/elf, method (R_390) GoString() string
|
pkg debug/elf, method (R_390) GoString() string
|
||||||
pkg debug/elf, method (R_390) String() string
|
pkg debug/elf, method (R_390) String() string
|
||||||
pkg debug/elf, type R_390 int
|
pkg debug/elf, type R_390 int
|
||||||
pkg encoding/json, method (*Encoder) DisableHTMLEscaping()
|
pkg encoding/json, method (*Encoder) SetEscapeHTML(bool)
|
||||||
pkg encoding/json, method (*Encoder) Indent(string, string)
|
pkg encoding/json, method (*Encoder) SetIndent(string, string)
|
||||||
|
pkg go/build, type Package struct, BinaryOnly bool
|
||||||
pkg go/build, type Package struct, CgoFFLAGS []string
|
pkg go/build, type Package struct, CgoFFLAGS []string
|
||||||
pkg go/build, type Package struct, FFiles []string
|
pkg go/build, type Package struct, FFiles []string
|
||||||
pkg go/doc, type Example struct, Unordered bool
|
pkg go/doc, type Example struct, Unordered bool
|
||||||
|
|
@ -158,22 +167,54 @@ pkg io, const SeekEnd = 2
|
||||||
pkg io, const SeekEnd ideal-int
|
pkg io, const SeekEnd ideal-int
|
||||||
pkg io, const SeekStart = 0
|
pkg io, const SeekStart = 0
|
||||||
pkg io, const SeekStart ideal-int
|
pkg io, const SeekStart ideal-int
|
||||||
pkg io, type SizedReaderAt interface { ReadAt, Size }
|
|
||||||
pkg io, type SizedReaderAt interface, ReadAt([]uint8, int64) (int, error)
|
|
||||||
pkg io, type SizedReaderAt interface, Size() int64
|
|
||||||
pkg math/big, method (*Float) GobDecode([]uint8) error
|
pkg math/big, method (*Float) GobDecode([]uint8) error
|
||||||
pkg math/big, method (*Float) GobEncode() ([]uint8, error)
|
pkg math/big, method (*Float) GobEncode() ([]uint8, error)
|
||||||
pkg net, method (*Dialer) DialContext(context.Context, string, string) (Conn, error)
|
pkg net, method (*Dialer) DialContext(context.Context, string, string) (Conn, error)
|
||||||
pkg net, type IPNet struct, Zone string
|
|
||||||
pkg net/http, method (*Request) Context() context.Context
|
pkg net/http, method (*Request) Context() context.Context
|
||||||
pkg net/http, method (*Request) WithContext(context.Context) *Request
|
pkg net/http, method (*Request) WithContext(context.Context) *Request
|
||||||
|
pkg net/http, type Request struct, Response *Response
|
||||||
|
pkg net/http, type Response struct, Uncompressed bool
|
||||||
pkg net/http, type Transport struct, Dialer *net.Dialer
|
pkg net/http, type Transport struct, Dialer *net.Dialer
|
||||||
|
pkg net/http, type Transport struct, IdleConnTimeout time.Duration
|
||||||
|
pkg net/http, type Transport struct, MaxIdleConns int
|
||||||
pkg net/http, type Transport struct, MaxResponseHeaderBytes int64
|
pkg net/http, type Transport struct, MaxResponseHeaderBytes int64
|
||||||
|
pkg net/http, var ErrUseLastResponse error
|
||||||
|
pkg net/http, var LocalAddrContextKey *contextKey
|
||||||
pkg net/http, var ServerContextKey *contextKey
|
pkg net/http, var ServerContextKey *contextKey
|
||||||
pkg net/http/cgi, type Handler struct, Stderr io.Writer
|
pkg net/http/cgi, type Handler struct, Stderr io.Writer
|
||||||
pkg net/http/httptest, func NewRequest(string, string, io.Reader) *http.Request
|
pkg net/http/httptest, func NewRequest(string, string, io.Reader) *http.Request
|
||||||
pkg net/http/httptest, method (*ResponseRecorder) Trailers() http.Header
|
pkg net/http/httptest, method (*ResponseRecorder) Result() *http.Response
|
||||||
|
pkg net/http/httptrace, func ContextClientTrace(context.Context) *ClientTrace
|
||||||
|
pkg net/http/httptrace, func WithClientTrace(context.Context, *ClientTrace) context.Context
|
||||||
|
pkg net/http/httptrace, type ClientTrace struct
|
||||||
|
pkg net/http/httptrace, type ClientTrace struct, ConnectDone func(string, string, error)
|
||||||
|
pkg net/http/httptrace, type ClientTrace struct, ConnectStart func(string, string)
|
||||||
|
pkg net/http/httptrace, type ClientTrace struct, DNSDone func(DNSDoneInfo)
|
||||||
|
pkg net/http/httptrace, type ClientTrace struct, DNSStart func(DNSStartInfo)
|
||||||
|
pkg net/http/httptrace, type ClientTrace struct, GetConn func(string)
|
||||||
|
pkg net/http/httptrace, type ClientTrace struct, Got100Continue func()
|
||||||
|
pkg net/http/httptrace, type ClientTrace struct, GotConn func(GotConnInfo)
|
||||||
|
pkg net/http/httptrace, type ClientTrace struct, GotFirstResponseByte func()
|
||||||
|
pkg net/http/httptrace, type ClientTrace struct, PutIdleConn func(error)
|
||||||
|
pkg net/http/httptrace, type ClientTrace struct, Wait100Continue func()
|
||||||
|
pkg net/http/httptrace, type ClientTrace struct, WroteHeaders func()
|
||||||
|
pkg net/http/httptrace, type ClientTrace struct, WroteRequest func(WroteRequestInfo)
|
||||||
|
pkg net/http/httptrace, type DNSDoneInfo struct
|
||||||
|
pkg net/http/httptrace, type DNSDoneInfo struct, Addrs []net.IPAddr
|
||||||
|
pkg net/http/httptrace, type DNSDoneInfo struct, Coalesced bool
|
||||||
|
pkg net/http/httptrace, type DNSDoneInfo struct, Err error
|
||||||
|
pkg net/http/httptrace, type DNSStartInfo struct
|
||||||
|
pkg net/http/httptrace, type DNSStartInfo struct, Host string
|
||||||
|
pkg net/http/httptrace, type GotConnInfo struct
|
||||||
|
pkg net/http/httptrace, type GotConnInfo struct, Conn net.Conn
|
||||||
|
pkg net/http/httptrace, type GotConnInfo struct, IdleTime time.Duration
|
||||||
|
pkg net/http/httptrace, type GotConnInfo struct, Reused bool
|
||||||
|
pkg net/http/httptrace, type GotConnInfo struct, WasIdle bool
|
||||||
|
pkg net/http/httptrace, type WroteRequestInfo struct
|
||||||
|
pkg net/http/httptrace, type WroteRequestInfo struct, Err error
|
||||||
pkg net/url, type URL struct, ForceQuery bool
|
pkg net/url, type URL struct, ForceQuery bool
|
||||||
|
pkg os, method (*File) Size() (int64, error)
|
||||||
|
pkg os/exec, func CommandContext(context.Context, string, ...string) *Cmd
|
||||||
pkg os/user, func LookupGroup(string) (*Group, error)
|
pkg os/user, func LookupGroup(string) (*Group, error)
|
||||||
pkg os/user, func LookupGroupId(string) (*Group, error)
|
pkg os/user, func LookupGroupId(string) (*Group, error)
|
||||||
pkg os/user, method (*User) GroupIds() ([]string, error)
|
pkg os/user, method (*User) GroupIds() ([]string, error)
|
||||||
|
|
@ -187,6 +228,7 @@ pkg os/user, type UnknownGroupIdError string
|
||||||
pkg reflect, func StructOf([]StructField) Type
|
pkg reflect, func StructOf([]StructField) Type
|
||||||
pkg reflect, method (StructTag) Lookup(string) (string, bool)
|
pkg reflect, method (StructTag) Lookup(string) (string, bool)
|
||||||
pkg runtime, func CallersFrames([]uintptr) *Frames
|
pkg runtime, func CallersFrames([]uintptr) *Frames
|
||||||
|
pkg runtime, func KeepAlive(interface{})
|
||||||
pkg runtime, func SetCgoTraceback(int, unsafe.Pointer, unsafe.Pointer, unsafe.Pointer)
|
pkg runtime, func SetCgoTraceback(int, unsafe.Pointer, unsafe.Pointer, unsafe.Pointer)
|
||||||
pkg runtime, method (*Frames) Next() (Frame, bool)
|
pkg runtime, method (*Frames) Next() (Frame, bool)
|
||||||
pkg runtime, type Frame struct
|
pkg runtime, type Frame struct
|
||||||
|
|
@ -198,6 +240,12 @@ pkg runtime, type Frame struct, Line int
|
||||||
pkg runtime, type Frame struct, PC uintptr
|
pkg runtime, type Frame struct, PC uintptr
|
||||||
pkg runtime, type Frames struct
|
pkg runtime, type Frames struct
|
||||||
pkg strings, method (*Reader) Reset(string)
|
pkg strings, method (*Reader) Reset(string)
|
||||||
|
pkg syscall (linux-386), type SysProcAttr struct, Unshare uintptr
|
||||||
|
pkg syscall (linux-386-cgo), type SysProcAttr struct, Unshare uintptr
|
||||||
|
pkg syscall (linux-amd64), type SysProcAttr struct, Unshare uintptr
|
||||||
|
pkg syscall (linux-amd64-cgo), type SysProcAttr struct, Unshare uintptr
|
||||||
|
pkg syscall (linux-arm), type SysProcAttr struct, Unshare uintptr
|
||||||
|
pkg syscall (linux-arm-cgo), type SysProcAttr struct, Unshare uintptr
|
||||||
pkg testing, method (*B) Run(string, func(*B)) bool
|
pkg testing, method (*B) Run(string, func(*B)) bool
|
||||||
pkg testing, method (*T) Run(string, func(*T)) bool
|
pkg testing, method (*T) Run(string, func(*T)) bool
|
||||||
pkg testing, type InternalExample struct, Unordered bool
|
pkg testing, type InternalExample struct, Unordered bool
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ gofmt</a> command with more general options.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><a href="//godoc.org/golang.org/x/tools/cmd/vet/">vet</a></td>
|
<td><a href="/cmd/vet/">vet</a></td>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
<td>Vet examines Go source code and reports suspicious constructs, such as Printf
|
<td>Vet examines Go source code and reports suspicious constructs, such as Printf
|
||||||
calls whose arguments do not align with the format string.</td>
|
calls whose arguments do not align with the format string.</td>
|
||||||
|
|
|
||||||
|
|
@ -353,10 +353,13 @@ with a thorough description of your change.
|
||||||
The first line of the change description is conventionally a one-line
|
The first line of the change description is conventionally a one-line
|
||||||
summary of the change, prefixed by the primary affected package,
|
summary of the change, prefixed by the primary affected package,
|
||||||
and is used as the subject for code review mail.
|
and is used as the subject for code review mail.
|
||||||
The rest of the
|
It should complete the sentence "This change modifies Go to _____."
|
||||||
description elaborates and should provide context for the
|
The rest of the description elaborates and should provide context for the
|
||||||
change and explain what it does.
|
change and explain what it does.
|
||||||
|
Write in complete sentences with correct punctuation, just like
|
||||||
|
for your comments in Go.
|
||||||
If there is a helpful reference, mention it here.
|
If there is a helpful reference, mention it here.
|
||||||
|
If you've fixed an issue, reference it by number with a # before it.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
@ -364,7 +367,7 @@ After editing, the template might now read:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
math: improved Sin, Cos and Tan precision for very large arguments
|
math: improve Sin, Cos and Tan precision for very large arguments
|
||||||
|
|
||||||
The existing implementation has poor numerical properties for
|
The existing implementation has poor numerical properties for
|
||||||
large arguments, so use the McGillicutty algorithm to improve
|
large arguments, so use the McGillicutty algorithm to improve
|
||||||
|
|
|
||||||
|
|
@ -2014,7 +2014,7 @@ then make the receiver for the method a value of that type.
|
||||||
type ByteSlice []byte
|
type ByteSlice []byte
|
||||||
|
|
||||||
func (slice ByteSlice) Append(data []byte) []byte {
|
func (slice ByteSlice) Append(data []byte) []byte {
|
||||||
// Body exactly the same as above
|
// Body exactly the same as the Append function defined above.
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
<p>
|
<p>
|
||||||
|
|
|
||||||
1132
doc/go1.7.html
Normal file
1132
doc/go1.7.html
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,32 +0,0 @@
|
||||||
Tools:
|
|
||||||
|
|
||||||
cmd/dist: add list subcommand to list all supported platforms (CL 19837)
|
|
||||||
cmd/go: GO15VENDOREXPERIMENT gone, assumed on (CL 19615)
|
|
||||||
cmd/link: "-X name value" form gone (CL 19614)
|
|
||||||
cmd/compile: smaller binaries (many CLs)
|
|
||||||
cmd/go, go/build: add support for Fortran (CL 19670, CL 4114)
|
|
||||||
cmd/doc: group constructors with types (CL 22354)
|
|
||||||
cmd/go, go/build: binary-only package support (CL 22433)
|
|
||||||
|
|
||||||
Ports:
|
|
||||||
|
|
||||||
We now require OpenBSD 5.6+ (CL 18219, crypto/rand using getentropy)
|
|
||||||
plan9/arm support? Start at least.
|
|
||||||
cgo and external linking support for linux/mips64 and linux/mips64le (CL 19809, ...)
|
|
||||||
|
|
||||||
New packages:
|
|
||||||
|
|
||||||
* context (and new support in net, net/http, os/exec, net/http/httptrace)
|
|
||||||
* net/http/httptrace
|
|
||||||
|
|
||||||
API additions and behavior changes:
|
|
||||||
|
|
||||||
crypto/tls: allow renegotiation to be handled by a client (CL 22475)
|
|
||||||
runtime: support symbolic backtrace of C code in a cgo crash (CL 17761)
|
|
||||||
runtime: add CallerFrames and Frames (CL 19869)
|
|
||||||
testing/quick: now generates nil values (CL 16470)
|
|
||||||
net/http/httptest: ResponseRecorder supports trailer (CL 20047) (compat impact: issue 14928)
|
|
||||||
net/url: support query string without values (CL 19931)
|
|
||||||
net/textproto: permit all valid token chars in CanonicalMIMEHeaderKey input (CL 18725)
|
|
||||||
go/doc: add Unordered boolean to Example struct (CL 19280)
|
|
||||||
time: print zero duration as 0s, not 0 (CL 22357)
|
|
||||||
|
|
@ -33,7 +33,7 @@ compiler using the GCC back end, see
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The Go compilers support five instruction sets.
|
The Go compilers support six instruction sets.
|
||||||
There are important differences in the quality of the compilers for the different
|
There are important differences in the quality of the compilers for the different
|
||||||
architectures.
|
architectures.
|
||||||
</p>
|
</p>
|
||||||
|
|
@ -63,19 +63,19 @@ architectures.
|
||||||
<code>arm64</code> (<code>AArch64</code>)
|
<code>arm64</code> (<code>AArch64</code>)
|
||||||
</dt>
|
</dt>
|
||||||
<dd>
|
<dd>
|
||||||
Supports Linux and Darwin binaries. New in 1.5 and not as well excercised as other ports.
|
Supports Linux and Darwin binaries. New in 1.5 and not as well exercised as other ports.
|
||||||
</dd>
|
</dd>
|
||||||
<dt>
|
<dt>
|
||||||
<code>ppc64, ppc64le</code> (64-bit PowerPC big- and little-endian)
|
<code>ppc64, ppc64le</code> (64-bit PowerPC big- and little-endian)
|
||||||
</dt>
|
</dt>
|
||||||
<dd>
|
<dd>
|
||||||
Supports Linux binaries. New in 1.5 and not as well excercised as other ports.
|
Supports Linux binaries. New in 1.5 and not as well exercised as other ports.
|
||||||
</dd>
|
</dd>
|
||||||
<dt>
|
<dt>
|
||||||
<code>mips64, mips64le</code> (64-bit MIPS big- and little-endian)
|
<code>mips64, mips64le</code> (64-bit MIPS big- and little-endian)
|
||||||
</dt>
|
</dt>
|
||||||
<dd>
|
<dd>
|
||||||
Supports Linux binaries. New in 1.6 and not as well excercised as other ports.
|
Supports Linux binaries. New in 1.6 and not as well exercised as other ports.
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -221,7 +221,7 @@ and building a simple program, as follows.
|
||||||
<p>
|
<p>
|
||||||
Create a directory to contain your <a href="code.html#Workspaces">workspace</a>,
|
Create a directory to contain your <a href="code.html#Workspaces">workspace</a>,
|
||||||
<code class="testUnix">$HOME/work</code>
|
<code class="testUnix">$HOME/work</code>
|
||||||
<code class="testWindows" style="display: none">%HOME%\work</code>
|
<code class="testWindows" style="display: none">C:\work</code>
|
||||||
for example, and set the <code>GOPATH</code> environment
|
for example, and set the <code>GOPATH</code> environment
|
||||||
variable to point to that location.
|
variable to point to that location.
|
||||||
</p>
|
</p>
|
||||||
|
|
@ -231,7 +231,7 @@ $ <b>export GOPATH=$HOME/work</b>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<pre class="testWindows" style="display: none">
|
<pre class="testWindows" style="display: none">
|
||||||
C:\> <b>set GOPATH=%HOME%\work</b>
|
C:\> <b>set GOPATH=C:\work</b>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
|
||||||
23
misc/cgo/errors/issue14669.go
Normal file
23
misc/cgo/errors/issue14669.go
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
// Copyright 2016 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 14669: test that fails when build with CGO_CFLAGS selecting
|
||||||
|
// optimization.
|
||||||
|
|
||||||
|
package p
|
||||||
|
|
||||||
|
/*
|
||||||
|
const int E = 1;
|
||||||
|
|
||||||
|
typedef struct s {
|
||||||
|
int c;
|
||||||
|
} s;
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
func F() {
|
||||||
|
_ = C.s{
|
||||||
|
c: C.E,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -290,6 +290,30 @@ var ptrTests = []ptrTest{
|
||||||
},
|
},
|
||||||
fail: true,
|
fail: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// Don't check non-pointer data.
|
||||||
|
// Uses unsafe code to get a pointer we shouldn't check.
|
||||||
|
// Although we use unsafe, the uintptr represents an integer
|
||||||
|
// that happens to have the same representation as a pointer;
|
||||||
|
// that is, we are testing something that is not unsafe.
|
||||||
|
name: "ptrdata1",
|
||||||
|
c: `#include <stdlib.h>
|
||||||
|
void f(void* p) {}`,
|
||||||
|
imports: []string{"unsafe"},
|
||||||
|
support: `type S struct { p *int; a [8*8]byte; u uintptr }`,
|
||||||
|
body: `i := 0; p := &S{u:uintptr(unsafe.Pointer(&i))}; q := (*S)(C.malloc(C.size_t(unsafe.Sizeof(*p)))); *q = *p; C.f(unsafe.Pointer(q))`,
|
||||||
|
fail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Like ptrdata1, but with a type that uses a GC program.
|
||||||
|
name: "ptrdata2",
|
||||||
|
c: `#include <stdlib.h>
|
||||||
|
void f(void* p) {}`,
|
||||||
|
imports: []string{"unsafe"},
|
||||||
|
support: `type S struct { p *int; a [32769*8]byte; q *int; u uintptr }`,
|
||||||
|
body: `i := 0; p := S{u:uintptr(unsafe.Pointer(&i))}; q := (*S)(C.malloc(C.size_t(unsafe.Sizeof(p)))); *q = p; C.f(unsafe.Pointer(q))`,
|
||||||
|
fail: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,13 @@ expect issue13129.go C.ushort
|
||||||
check issue13423.go
|
check issue13423.go
|
||||||
expect issue13635.go C.uchar C.schar C.ushort C.uint C.ulong C.longlong C.ulonglong C.complexfloat C.complexdouble
|
expect issue13635.go C.uchar C.schar C.ushort C.uint C.ulong C.longlong C.ulonglong C.complexfloat C.complexdouble
|
||||||
|
|
||||||
|
if ! go build issue14669.go; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if ! CGO_CFLAGS="-O" go build issue14669.go; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
if ! go run ptr.go; then
|
if ! go run ptr.go; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
|
|
@ -79,14 +79,12 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if GOOS == "darwin" {
|
if GOOS == "darwin" {
|
||||||
cc = append(cc, "-Wl,-no_pie")
|
|
||||||
|
|
||||||
// For Darwin/ARM.
|
// For Darwin/ARM.
|
||||||
// TODO(crawshaw): can we do better?
|
// TODO(crawshaw): can we do better?
|
||||||
cc = append(cc, []string{"-framework", "CoreFoundation", "-framework", "Foundation"}...)
|
cc = append(cc, []string{"-framework", "CoreFoundation", "-framework", "Foundation"}...)
|
||||||
}
|
}
|
||||||
libgodir = GOOS + "_" + GOARCH
|
libgodir = GOOS + "_" + GOARCH
|
||||||
if GOOS == "darwin" && GOARCH == "arm" {
|
if GOOS == "darwin" && (GOARCH == "arm" || GOARCH == "arm64") {
|
||||||
libgodir = GOOS + "_" + GOARCH + "_shared"
|
libgodir = GOOS + "_" + GOARCH + "_shared"
|
||||||
}
|
}
|
||||||
cc = append(cc, "-I", filepath.Join("pkg", libgodir))
|
cc = append(cc, "-I", filepath.Join("pkg", libgodir))
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,7 @@ static void init() {
|
||||||
|
|
||||||
// Test raising SIGIO on a C thread with an alternate signal stack
|
// Test raising SIGIO on a C thread with an alternate signal stack
|
||||||
// when there is a Go signal handler for SIGIO.
|
// when there is a Go signal handler for SIGIO.
|
||||||
static void* thread1(void* arg) {
|
static void* thread1(void* arg __attribute__ ((unused))) {
|
||||||
pthread_t* ptid = (pthread_t*)(arg);
|
|
||||||
stack_t ss;
|
stack_t ss;
|
||||||
int i;
|
int i;
|
||||||
stack_t nss;
|
stack_t nss;
|
||||||
|
|
@ -65,7 +64,7 @@ static void* thread1(void* arg) {
|
||||||
// Send ourselves a SIGIO. This will be caught by the Go
|
// Send ourselves a SIGIO. This will be caught by the Go
|
||||||
// signal handler which should forward to the C signal
|
// signal handler which should forward to the C signal
|
||||||
// handler.
|
// handler.
|
||||||
i = pthread_kill(*ptid, SIGIO);
|
i = pthread_kill(pthread_self(), SIGIO);
|
||||||
if (i != 0) {
|
if (i != 0) {
|
||||||
fprintf(stderr, "pthread_kill: %s\n", strerror(i));
|
fprintf(stderr, "pthread_kill: %s\n", strerror(i));
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
|
@ -101,11 +100,11 @@ static void* thread1(void* arg) {
|
||||||
|
|
||||||
// Test calling a Go function to raise SIGIO on a C thread with an
|
// Test calling a Go function to raise SIGIO on a C thread with an
|
||||||
// alternate signal stack when there is a Go signal handler for SIGIO.
|
// alternate signal stack when there is a Go signal handler for SIGIO.
|
||||||
static void* thread2(void* arg) {
|
static void* thread2(void* arg __attribute__ ((unused))) {
|
||||||
pthread_t* ptid = (pthread_t*)(arg);
|
|
||||||
stack_t ss;
|
stack_t ss;
|
||||||
int i;
|
int i;
|
||||||
int oldcount;
|
int oldcount;
|
||||||
|
pthread_t tid;
|
||||||
stack_t nss;
|
stack_t nss;
|
||||||
|
|
||||||
// Set up an alternate signal stack for this thread.
|
// Set up an alternate signal stack for this thread.
|
||||||
|
|
@ -124,7 +123,8 @@ static void* thread2(void* arg) {
|
||||||
|
|
||||||
// Call a Go function that will call a C function to send us a
|
// Call a Go function that will call a C function to send us a
|
||||||
// SIGIO.
|
// SIGIO.
|
||||||
GoRaiseSIGIO(ptid);
|
tid = pthread_self();
|
||||||
|
GoRaiseSIGIO(&tid);
|
||||||
|
|
||||||
// Wait until the signal has been delivered.
|
// Wait until the signal has been delivered.
|
||||||
i = 0;
|
i = 0;
|
||||||
|
|
@ -161,7 +161,7 @@ int main(int argc, char **argv) {
|
||||||
// Tell the Go library to start looking for SIGIO.
|
// Tell the Go library to start looking for SIGIO.
|
||||||
GoCatchSIGIO();
|
GoCatchSIGIO();
|
||||||
|
|
||||||
i = pthread_create(&tid, NULL, thread1, (void*)(&tid));
|
i = pthread_create(&tid, NULL, thread1, NULL);
|
||||||
if (i != 0) {
|
if (i != 0) {
|
||||||
fprintf(stderr, "pthread_create: %s\n", strerror(i));
|
fprintf(stderr, "pthread_create: %s\n", strerror(i));
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
|
@ -173,7 +173,7 @@ int main(int argc, char **argv) {
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
i = pthread_create(&tid, NULL, thread2, (void*)(&tid));
|
i = pthread_create(&tid, NULL, thread2, NULL);
|
||||||
if (i != 0) {
|
if (i != 0) {
|
||||||
fprintf(stderr, "pthread_create: %s\n", strerror(i));
|
fprintf(stderr, "pthread_create: %s\n", strerror(i));
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
|
|
||||||
|
|
@ -134,6 +134,26 @@ if test "$tsan" = "yes"; then
|
||||||
status=1
|
status=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if ! go run tsan3.go 2>$err; then
|
||||||
|
cat $err
|
||||||
|
echo "FAIL: tsan3"
|
||||||
|
status=1
|
||||||
|
elif grep -i warning $err >/dev/null 2>&1; then
|
||||||
|
cat $err
|
||||||
|
echo "FAIL: tsan3"
|
||||||
|
status=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! go run tsan4.go 2>$err; then
|
||||||
|
cat $err
|
||||||
|
echo "FAIL: tsan4"
|
||||||
|
status=1
|
||||||
|
elif grep -i warning $err >/dev/null 2>&1; then
|
||||||
|
cat $err
|
||||||
|
echo "FAIL: tsan4"
|
||||||
|
status=1
|
||||||
|
fi
|
||||||
|
|
||||||
rm -f $err
|
rm -f $err
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
||||||
40
misc/cgo/testsanitizers/tsan3.go
Normal file
40
misc/cgo/testsanitizers/tsan3.go
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
// The stubs for the C functions read and write the same slot on the
|
||||||
|
// g0 stack when copying arguments in and out.
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -fsanitize=thread
|
||||||
|
#cgo LDFLAGS: -fsanitize=thread
|
||||||
|
|
||||||
|
int Func1() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Func2(int x) {
|
||||||
|
(void)x;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
const N = 10000
|
||||||
|
done := make(chan bool, N)
|
||||||
|
for i := 0; i < N; i++ {
|
||||||
|
go func() {
|
||||||
|
C.Func1()
|
||||||
|
done <- true
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
C.Func2(0)
|
||||||
|
done <- true
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
for i := 0; i < 2*N; i++ {
|
||||||
|
<-done
|
||||||
|
}
|
||||||
|
}
|
||||||
34
misc/cgo/testsanitizers/tsan4.go
Normal file
34
misc/cgo/testsanitizers/tsan4.go
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
// Check that calls to C.malloc/C.free do not trigger TSAN false
|
||||||
|
// positive reports.
|
||||||
|
|
||||||
|
// #cgo CFLAGS: -fsanitize=thread
|
||||||
|
// #cgo LDFLAGS: -fsanitize=thread
|
||||||
|
// #include <stdlib.h>
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
p := C.malloc(C.size_t(i * 10))
|
||||||
|
runtime.Gosched()
|
||||||
|
C.free(p)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
@ -27,23 +27,23 @@ go src=..
|
||||||
internal
|
internal
|
||||||
objfile
|
objfile
|
||||||
objfile.go
|
objfile.go
|
||||||
unvendor
|
|
||||||
golang.org
|
|
||||||
x
|
|
||||||
arch
|
|
||||||
arm
|
|
||||||
armasm
|
|
||||||
testdata
|
|
||||||
+
|
|
||||||
x86
|
|
||||||
x86asm
|
|
||||||
testdata
|
|
||||||
+
|
|
||||||
gofmt
|
gofmt
|
||||||
gofmt.go
|
gofmt.go
|
||||||
gofmt_test.go
|
gofmt_test.go
|
||||||
testdata
|
testdata
|
||||||
+
|
+
|
||||||
|
vendor
|
||||||
|
golang.org
|
||||||
|
x
|
||||||
|
arch
|
||||||
|
arm
|
||||||
|
armasm
|
||||||
|
testdata
|
||||||
|
+
|
||||||
|
x86
|
||||||
|
x86asm
|
||||||
|
testdata
|
||||||
|
+
|
||||||
archive
|
archive
|
||||||
tar
|
tar
|
||||||
testdata
|
testdata
|
||||||
|
|
|
||||||
|
|
@ -21,10 +21,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Header type flags.
|
||||||
const (
|
const (
|
||||||
blockSize = 512
|
|
||||||
|
|
||||||
// Types
|
|
||||||
TypeReg = '0' // regular file
|
TypeReg = '0' // regular file
|
||||||
TypeRegA = '\x00' // regular file
|
TypeRegA = '\x00' // regular file
|
||||||
TypeLink = '1' // hard link
|
TypeLink = '1' // hard link
|
||||||
|
|
@ -61,12 +59,6 @@ type Header struct {
|
||||||
Xattrs map[string]string
|
Xattrs map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
// File name constants from the tar spec.
|
|
||||||
const (
|
|
||||||
fileNameSize = 100 // Maximum number of bytes in a standard tar name.
|
|
||||||
fileNamePrefixSize = 155 // Maximum number of ustar extension bytes.
|
|
||||||
)
|
|
||||||
|
|
||||||
// FileInfo returns an os.FileInfo for the Header.
|
// FileInfo returns an os.FileInfo for the Header.
|
||||||
func (h *Header) FileInfo() os.FileInfo {
|
func (h *Header) FileInfo() os.FileInfo {
|
||||||
return headerFileInfo{h}
|
return headerFileInfo{h}
|
||||||
|
|
@ -279,33 +271,6 @@ func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) {
|
||||||
return h, nil
|
return h, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var zeroBlock = make([]byte, blockSize)
|
|
||||||
|
|
||||||
// POSIX specifies a sum of the unsigned byte values, but the Sun tar uses signed byte values.
|
|
||||||
// We compute and return both.
|
|
||||||
func checksum(header []byte) (unsigned int64, signed int64) {
|
|
||||||
for i := 0; i < len(header); i++ {
|
|
||||||
if i == 148 {
|
|
||||||
// The chksum field (header[148:156]) is special: it should be treated as space bytes.
|
|
||||||
unsigned += ' ' * 8
|
|
||||||
signed += ' ' * 8
|
|
||||||
i += 7
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
unsigned += int64(header[i])
|
|
||||||
signed += int64(int8(header[i]))
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type slicer []byte
|
|
||||||
|
|
||||||
func (sp *slicer) next(n int) (b []byte) {
|
|
||||||
s := *sp
|
|
||||||
b, *sp = s[0:n], s[n:]
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func isASCII(s string) bool {
|
func isASCII(s string) bool {
|
||||||
for _, c := range s {
|
for _, c := range s {
|
||||||
if c >= 0x80 {
|
if c >= 0x80 {
|
||||||
|
|
|
||||||
197
src/archive/tar/format.go
Normal file
197
src/archive/tar/format.go
Normal file
|
|
@ -0,0 +1,197 @@
|
||||||
|
// Copyright 2016 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 tar
|
||||||
|
|
||||||
|
// Constants to identify various tar formats.
|
||||||
|
const (
|
||||||
|
// The format is unknown.
|
||||||
|
formatUnknown = (1 << iota) / 2 // Sequence of 0, 1, 2, 4, 8, etc...
|
||||||
|
|
||||||
|
// The format of the original Unix V7 tar tool prior to standardization.
|
||||||
|
formatV7
|
||||||
|
|
||||||
|
// The old and new GNU formats, which are incompatible with USTAR.
|
||||||
|
// This does cover the old GNU sparse extension.
|
||||||
|
// This does not cover the GNU sparse extensions using PAX headers,
|
||||||
|
// versions 0.0, 0.1, and 1.0; these fall under the PAX format.
|
||||||
|
formatGNU
|
||||||
|
|
||||||
|
// Schily's tar format, which is incompatible with USTAR.
|
||||||
|
// This does not cover STAR extensions to the PAX format; these fall under
|
||||||
|
// the PAX format.
|
||||||
|
formatSTAR
|
||||||
|
|
||||||
|
// USTAR is the former standardization of tar defined in POSIX.1-1988.
|
||||||
|
// This is incompatible with the GNU and STAR formats.
|
||||||
|
formatUSTAR
|
||||||
|
|
||||||
|
// PAX is the latest standardization of tar defined in POSIX.1-2001.
|
||||||
|
// This is an extension of USTAR and is "backwards compatible" with it.
|
||||||
|
//
|
||||||
|
// Some newer formats add their own extensions to PAX, such as GNU sparse
|
||||||
|
// files and SCHILY extended attributes. Since they are backwards compatible
|
||||||
|
// with PAX, they will be labelled as "PAX".
|
||||||
|
formatPAX
|
||||||
|
)
|
||||||
|
|
||||||
|
// Magics used to identify various formats.
|
||||||
|
const (
|
||||||
|
magicGNU, versionGNU = "ustar ", " \x00"
|
||||||
|
magicUSTAR, versionUSTAR = "ustar\x00", "00"
|
||||||
|
trailerSTAR = "tar\x00"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Size constants from various tar specifications.
|
||||||
|
const (
|
||||||
|
blockSize = 512 // Size of each block in a tar stream
|
||||||
|
nameSize = 100 // Max length of the name field in USTAR format
|
||||||
|
prefixSize = 155 // Max length of the prefix field in USTAR format
|
||||||
|
)
|
||||||
|
|
||||||
|
var zeroBlock block
|
||||||
|
|
||||||
|
type block [blockSize]byte
|
||||||
|
|
||||||
|
// Convert block to any number of formats.
|
||||||
|
func (b *block) V7() *headerV7 { return (*headerV7)(b) }
|
||||||
|
func (b *block) GNU() *headerGNU { return (*headerGNU)(b) }
|
||||||
|
func (b *block) STAR() *headerSTAR { return (*headerSTAR)(b) }
|
||||||
|
func (b *block) USTAR() *headerUSTAR { return (*headerUSTAR)(b) }
|
||||||
|
func (b *block) Sparse() sparseArray { return (sparseArray)(b[:]) }
|
||||||
|
|
||||||
|
// GetFormat checks that the block is a valid tar header based on the checksum.
|
||||||
|
// It then attempts to guess the specific format based on magic values.
|
||||||
|
// If the checksum fails, then formatUnknown is returned.
|
||||||
|
func (b *block) GetFormat() (format int) {
|
||||||
|
// Verify checksum.
|
||||||
|
var p parser
|
||||||
|
value := p.parseOctal(b.V7().Chksum())
|
||||||
|
chksum1, chksum2 := b.ComputeChecksum()
|
||||||
|
if p.err != nil || (value != chksum1 && value != chksum2) {
|
||||||
|
return formatUnknown
|
||||||
|
}
|
||||||
|
|
||||||
|
// Guess the magic values.
|
||||||
|
magic := string(b.USTAR().Magic())
|
||||||
|
version := string(b.USTAR().Version())
|
||||||
|
trailer := string(b.STAR().Trailer())
|
||||||
|
switch {
|
||||||
|
case magic == magicUSTAR && trailer == trailerSTAR:
|
||||||
|
return formatSTAR
|
||||||
|
case magic == magicUSTAR:
|
||||||
|
return formatUSTAR
|
||||||
|
case magic == magicGNU && version == versionGNU:
|
||||||
|
return formatGNU
|
||||||
|
default:
|
||||||
|
return formatV7
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFormat writes the magic values necessary for specified format
|
||||||
|
// and then updates the checksum accordingly.
|
||||||
|
func (b *block) SetFormat(format int) {
|
||||||
|
// Set the magic values.
|
||||||
|
switch format {
|
||||||
|
case formatV7:
|
||||||
|
// Do nothing.
|
||||||
|
case formatGNU:
|
||||||
|
copy(b.GNU().Magic(), magicGNU)
|
||||||
|
copy(b.GNU().Version(), versionGNU)
|
||||||
|
case formatSTAR:
|
||||||
|
copy(b.STAR().Magic(), magicUSTAR)
|
||||||
|
copy(b.STAR().Version(), versionUSTAR)
|
||||||
|
copy(b.STAR().Trailer(), trailerSTAR)
|
||||||
|
case formatUSTAR, formatPAX:
|
||||||
|
copy(b.USTAR().Magic(), magicUSTAR)
|
||||||
|
copy(b.USTAR().Version(), versionUSTAR)
|
||||||
|
default:
|
||||||
|
panic("invalid format")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update checksum.
|
||||||
|
// This field is special in that it is terminated by a NULL then space.
|
||||||
|
var f formatter
|
||||||
|
field := b.V7().Chksum()
|
||||||
|
chksum, _ := b.ComputeChecksum() // Possible values are 256..128776
|
||||||
|
f.formatOctal(field[:7], chksum) // Never fails since 128776 < 262143
|
||||||
|
field[7] = ' '
|
||||||
|
}
|
||||||
|
|
||||||
|
// ComputeChecksum computes the checksum for the header block.
|
||||||
|
// POSIX specifies a sum of the unsigned byte values, but the Sun tar used
|
||||||
|
// signed byte values.
|
||||||
|
// We compute and return both.
|
||||||
|
func (b *block) ComputeChecksum() (unsigned, signed int64) {
|
||||||
|
for i, c := range b {
|
||||||
|
if 148 <= i && i < 156 {
|
||||||
|
c = ' ' // Treat the checksum field itself as all spaces.
|
||||||
|
}
|
||||||
|
unsigned += int64(uint8(c))
|
||||||
|
signed += int64(int8(c))
|
||||||
|
}
|
||||||
|
return unsigned, signed
|
||||||
|
}
|
||||||
|
|
||||||
|
type headerV7 [blockSize]byte
|
||||||
|
|
||||||
|
func (h *headerV7) Name() []byte { return h[000:][:100] }
|
||||||
|
func (h *headerV7) Mode() []byte { return h[100:][:8] }
|
||||||
|
func (h *headerV7) UID() []byte { return h[108:][:8] }
|
||||||
|
func (h *headerV7) GID() []byte { return h[116:][:8] }
|
||||||
|
func (h *headerV7) Size() []byte { return h[124:][:12] }
|
||||||
|
func (h *headerV7) ModTime() []byte { return h[136:][:12] }
|
||||||
|
func (h *headerV7) Chksum() []byte { return h[148:][:8] }
|
||||||
|
func (h *headerV7) TypeFlag() []byte { return h[156:][:1] }
|
||||||
|
func (h *headerV7) LinkName() []byte { return h[157:][:100] }
|
||||||
|
|
||||||
|
type headerGNU [blockSize]byte
|
||||||
|
|
||||||
|
func (h *headerGNU) V7() *headerV7 { return (*headerV7)(h) }
|
||||||
|
func (h *headerGNU) Magic() []byte { return h[257:][:6] }
|
||||||
|
func (h *headerGNU) Version() []byte { return h[263:][:2] }
|
||||||
|
func (h *headerGNU) UserName() []byte { return h[265:][:32] }
|
||||||
|
func (h *headerGNU) GroupName() []byte { return h[297:][:32] }
|
||||||
|
func (h *headerGNU) DevMajor() []byte { return h[329:][:8] }
|
||||||
|
func (h *headerGNU) DevMinor() []byte { return h[337:][:8] }
|
||||||
|
func (h *headerGNU) AccessTime() []byte { return h[345:][:12] }
|
||||||
|
func (h *headerGNU) ChangeTime() []byte { return h[357:][:12] }
|
||||||
|
func (h *headerGNU) Sparse() sparseArray { return (sparseArray)(h[386:][:24*4+1]) }
|
||||||
|
func (h *headerGNU) RealSize() []byte { return h[483:][:12] }
|
||||||
|
|
||||||
|
type headerSTAR [blockSize]byte
|
||||||
|
|
||||||
|
func (h *headerSTAR) V7() *headerV7 { return (*headerV7)(h) }
|
||||||
|
func (h *headerSTAR) Magic() []byte { return h[257:][:6] }
|
||||||
|
func (h *headerSTAR) Version() []byte { return h[263:][:2] }
|
||||||
|
func (h *headerSTAR) UserName() []byte { return h[265:][:32] }
|
||||||
|
func (h *headerSTAR) GroupName() []byte { return h[297:][:32] }
|
||||||
|
func (h *headerSTAR) DevMajor() []byte { return h[329:][:8] }
|
||||||
|
func (h *headerSTAR) DevMinor() []byte { return h[337:][:8] }
|
||||||
|
func (h *headerSTAR) Prefix() []byte { return h[345:][:131] }
|
||||||
|
func (h *headerSTAR) AccessTime() []byte { return h[476:][:12] }
|
||||||
|
func (h *headerSTAR) ChangeTime() []byte { return h[488:][:12] }
|
||||||
|
func (h *headerSTAR) Trailer() []byte { return h[508:][:4] }
|
||||||
|
|
||||||
|
type headerUSTAR [blockSize]byte
|
||||||
|
|
||||||
|
func (h *headerUSTAR) V7() *headerV7 { return (*headerV7)(h) }
|
||||||
|
func (h *headerUSTAR) Magic() []byte { return h[257:][:6] }
|
||||||
|
func (h *headerUSTAR) Version() []byte { return h[263:][:2] }
|
||||||
|
func (h *headerUSTAR) UserName() []byte { return h[265:][:32] }
|
||||||
|
func (h *headerUSTAR) GroupName() []byte { return h[297:][:32] }
|
||||||
|
func (h *headerUSTAR) DevMajor() []byte { return h[329:][:8] }
|
||||||
|
func (h *headerUSTAR) DevMinor() []byte { return h[337:][:8] }
|
||||||
|
func (h *headerUSTAR) Prefix() []byte { return h[345:][:155] }
|
||||||
|
|
||||||
|
type sparseArray []byte
|
||||||
|
|
||||||
|
func (s sparseArray) Entry(i int) sparseNode { return (sparseNode)(s[i*24:]) }
|
||||||
|
func (s sparseArray) IsExtended() []byte { return s[24*s.MaxEntries():][:1] }
|
||||||
|
func (s sparseArray) MaxEntries() int { return len(s) / 24 }
|
||||||
|
|
||||||
|
type sparseNode []byte
|
||||||
|
|
||||||
|
func (s sparseNode) Offset() []byte { return s[00:][:12] }
|
||||||
|
func (s sparseNode) NumBytes() []byte { return s[12:][:12] }
|
||||||
|
|
@ -29,11 +29,11 @@ const maxNanoSecondIntSize = 9
|
||||||
// The Next method advances to the next file in the archive (including the first),
|
// The Next method advances to the next file in the archive (including the first),
|
||||||
// and then it can be treated as an io.Reader to access the file's data.
|
// and then it can be treated as an io.Reader to access the file's data.
|
||||||
type Reader struct {
|
type Reader struct {
|
||||||
r io.Reader
|
r io.Reader
|
||||||
err error
|
err error
|
||||||
pad int64 // amount of padding (ignored) after current file entry
|
pad int64 // amount of padding (ignored) after current file entry
|
||||||
curr numBytesReader // reader for current file entry
|
curr numBytesReader // reader for current file entry
|
||||||
hdrBuff [blockSize]byte // buffer to use in readHeader
|
blk block // buffer to use as temporary local storage
|
||||||
}
|
}
|
||||||
|
|
||||||
type parser struct {
|
type parser struct {
|
||||||
|
|
@ -98,17 +98,6 @@ const (
|
||||||
paxGNUSparseRealSize = "GNU.sparse.realsize"
|
paxGNUSparseRealSize = "GNU.sparse.realsize"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Keywords for old GNU sparse headers
|
|
||||||
const (
|
|
||||||
oldGNUSparseMainHeaderOffset = 386
|
|
||||||
oldGNUSparseMainHeaderIsExtendedOffset = 482
|
|
||||||
oldGNUSparseMainHeaderNumEntries = 4
|
|
||||||
oldGNUSparseExtendedHeaderIsExtendedOffset = 504
|
|
||||||
oldGNUSparseExtendedHeaderNumEntries = 21
|
|
||||||
oldGNUSparseOffsetSize = 12
|
|
||||||
oldGNUSparseNumBytesSize = 12
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewReader creates a new Reader reading from r.
|
// NewReader creates a new Reader reading from r.
|
||||||
func NewReader(r io.Reader) *Reader { return &Reader{r: r} }
|
func NewReader(r io.Reader) *Reader { return &Reader{r: r} }
|
||||||
|
|
||||||
|
|
@ -542,17 +531,6 @@ func (tr *Reader) skipUnread() error {
|
||||||
return tr.err
|
return tr.err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tr *Reader) verifyChecksum(header []byte) bool {
|
|
||||||
if tr.err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
var p parser
|
|
||||||
given := p.parseOctal(header[148:156])
|
|
||||||
unsigned, signed := checksum(header)
|
|
||||||
return p.err == nil && (given == unsigned || given == signed)
|
|
||||||
}
|
|
||||||
|
|
||||||
// readHeader reads the next block header and assumes that the underlying reader
|
// readHeader reads the next block header and assumes that the underlying reader
|
||||||
// is already aligned to a block boundary.
|
// is already aligned to a block boundary.
|
||||||
//
|
//
|
||||||
|
|
@ -561,19 +539,16 @@ func (tr *Reader) verifyChecksum(header []byte) bool {
|
||||||
// * Exactly 1 block of zeros is read and EOF is hit.
|
// * Exactly 1 block of zeros is read and EOF is hit.
|
||||||
// * At least 2 blocks of zeros are read.
|
// * At least 2 blocks of zeros are read.
|
||||||
func (tr *Reader) readHeader() *Header {
|
func (tr *Reader) readHeader() *Header {
|
||||||
header := tr.hdrBuff[:]
|
if _, tr.err = io.ReadFull(tr.r, tr.blk[:]); tr.err != nil {
|
||||||
copy(header, zeroBlock)
|
|
||||||
|
|
||||||
if _, tr.err = io.ReadFull(tr.r, header); tr.err != nil {
|
|
||||||
return nil // io.EOF is okay here
|
return nil // io.EOF is okay here
|
||||||
}
|
}
|
||||||
|
|
||||||
// Two blocks of zero bytes marks the end of the archive.
|
// Two blocks of zero bytes marks the end of the archive.
|
||||||
if bytes.Equal(header, zeroBlock[0:blockSize]) {
|
if bytes.Equal(tr.blk[:], zeroBlock[:]) {
|
||||||
if _, tr.err = io.ReadFull(tr.r, header); tr.err != nil {
|
if _, tr.err = io.ReadFull(tr.r, tr.blk[:]); tr.err != nil {
|
||||||
return nil // io.EOF is okay here
|
return nil // io.EOF is okay here
|
||||||
}
|
}
|
||||||
if bytes.Equal(header, zeroBlock[0:blockSize]) {
|
if bytes.Equal(tr.blk[:], zeroBlock[:]) {
|
||||||
tr.err = io.EOF
|
tr.err = io.EOF
|
||||||
} else {
|
} else {
|
||||||
tr.err = ErrHeader // zero block and then non-zero block
|
tr.err = ErrHeader // zero block and then non-zero block
|
||||||
|
|
@ -581,71 +556,55 @@ func (tr *Reader) readHeader() *Header {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if !tr.verifyChecksum(header) {
|
// Verify the header matches a known format.
|
||||||
|
format := tr.blk.GetFormat()
|
||||||
|
if format == formatUnknown {
|
||||||
tr.err = ErrHeader
|
tr.err = ErrHeader
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unpack
|
|
||||||
var p parser
|
var p parser
|
||||||
hdr := new(Header)
|
hdr := new(Header)
|
||||||
s := slicer(header)
|
|
||||||
|
|
||||||
hdr.Name = p.parseString(s.next(100))
|
// Unpack the V7 header.
|
||||||
hdr.Mode = p.parseNumeric(s.next(8))
|
v7 := tr.blk.V7()
|
||||||
hdr.Uid = int(p.parseNumeric(s.next(8)))
|
hdr.Name = p.parseString(v7.Name())
|
||||||
hdr.Gid = int(p.parseNumeric(s.next(8)))
|
hdr.Mode = p.parseNumeric(v7.Mode())
|
||||||
hdr.Size = p.parseNumeric(s.next(12))
|
hdr.Uid = int(p.parseNumeric(v7.UID()))
|
||||||
hdr.ModTime = time.Unix(p.parseNumeric(s.next(12)), 0)
|
hdr.Gid = int(p.parseNumeric(v7.GID()))
|
||||||
s.next(8) // chksum
|
hdr.Size = p.parseNumeric(v7.Size())
|
||||||
hdr.Typeflag = s.next(1)[0]
|
hdr.ModTime = time.Unix(p.parseNumeric(v7.ModTime()), 0)
|
||||||
hdr.Linkname = p.parseString(s.next(100))
|
hdr.Typeflag = v7.TypeFlag()[0]
|
||||||
|
hdr.Linkname = p.parseString(v7.LinkName())
|
||||||
|
|
||||||
// The remainder of the header depends on the value of magic.
|
// Unpack format specific fields.
|
||||||
// The original (v7) version of tar had no explicit magic field,
|
if format > formatV7 {
|
||||||
// so its magic bytes, like the rest of the block, are NULs.
|
ustar := tr.blk.USTAR()
|
||||||
magic := string(s.next(8)) // contains version field as well.
|
hdr.Uname = p.parseString(ustar.UserName())
|
||||||
var format string
|
hdr.Gname = p.parseString(ustar.GroupName())
|
||||||
switch {
|
|
||||||
case magic[:6] == "ustar\x00": // POSIX tar (1003.1-1988)
|
|
||||||
if string(header[508:512]) == "tar\x00" {
|
|
||||||
format = "star"
|
|
||||||
} else {
|
|
||||||
format = "posix"
|
|
||||||
}
|
|
||||||
case magic == "ustar \x00": // old GNU tar
|
|
||||||
format = "gnu"
|
|
||||||
}
|
|
||||||
|
|
||||||
switch format {
|
|
||||||
case "posix", "gnu", "star":
|
|
||||||
hdr.Uname = p.parseString(s.next(32))
|
|
||||||
hdr.Gname = p.parseString(s.next(32))
|
|
||||||
devmajor := s.next(8)
|
|
||||||
devminor := s.next(8)
|
|
||||||
if hdr.Typeflag == TypeChar || hdr.Typeflag == TypeBlock {
|
if hdr.Typeflag == TypeChar || hdr.Typeflag == TypeBlock {
|
||||||
hdr.Devmajor = p.parseNumeric(devmajor)
|
hdr.Devmajor = p.parseNumeric(ustar.DevMajor())
|
||||||
hdr.Devminor = p.parseNumeric(devminor)
|
hdr.Devminor = p.parseNumeric(ustar.DevMinor())
|
||||||
}
|
}
|
||||||
|
|
||||||
var prefix string
|
var prefix string
|
||||||
switch format {
|
switch format {
|
||||||
case "posix", "gnu":
|
case formatUSTAR, formatGNU:
|
||||||
prefix = p.parseString(s.next(155))
|
// TODO(dsnet): Do not use the prefix field for the GNU format!
|
||||||
case "star":
|
// See golang.org/issues/12594
|
||||||
prefix = p.parseString(s.next(131))
|
ustar := tr.blk.USTAR()
|
||||||
hdr.AccessTime = time.Unix(p.parseNumeric(s.next(12)), 0)
|
prefix = p.parseString(ustar.Prefix())
|
||||||
hdr.ChangeTime = time.Unix(p.parseNumeric(s.next(12)), 0)
|
case formatSTAR:
|
||||||
|
star := tr.blk.STAR()
|
||||||
|
prefix = p.parseString(star.Prefix())
|
||||||
|
hdr.AccessTime = time.Unix(p.parseNumeric(star.AccessTime()), 0)
|
||||||
|
hdr.ChangeTime = time.Unix(p.parseNumeric(star.ChangeTime()), 0)
|
||||||
}
|
}
|
||||||
if len(prefix) > 0 {
|
if len(prefix) > 0 {
|
||||||
hdr.Name = prefix + "/" + hdr.Name
|
hdr.Name = prefix + "/" + hdr.Name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.err != nil {
|
|
||||||
tr.err = p.err
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
nb := hdr.Size
|
nb := hdr.Size
|
||||||
if isHeaderOnlyType(hdr.Typeflag) {
|
if isHeaderOnlyType(hdr.Typeflag) {
|
||||||
nb = 0
|
nb = 0
|
||||||
|
|
@ -662,14 +621,14 @@ func (tr *Reader) readHeader() *Header {
|
||||||
// Check for old GNU sparse format entry.
|
// Check for old GNU sparse format entry.
|
||||||
if hdr.Typeflag == TypeGNUSparse {
|
if hdr.Typeflag == TypeGNUSparse {
|
||||||
// Get the real size of the file.
|
// Get the real size of the file.
|
||||||
hdr.Size = p.parseNumeric(header[483:495])
|
hdr.Size = p.parseNumeric(tr.blk.GNU().RealSize())
|
||||||
if p.err != nil {
|
if p.err != nil {
|
||||||
tr.err = p.err
|
tr.err = p.err
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the sparse map.
|
// Read the sparse map.
|
||||||
sp := tr.readOldGNUSparseMap(header)
|
sp := tr.readOldGNUSparseMap(&tr.blk)
|
||||||
if tr.err != nil {
|
if tr.err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -681,26 +640,24 @@ func (tr *Reader) readHeader() *Header {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if p.err != nil {
|
||||||
|
tr.err = p.err
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
return hdr
|
return hdr
|
||||||
}
|
}
|
||||||
|
|
||||||
// readOldGNUSparseMap reads the sparse map as stored in the old GNU sparse format.
|
// readOldGNUSparseMap reads the sparse map as stored in the old GNU sparse format.
|
||||||
// The sparse map is stored in the tar header if it's small enough. If it's larger than four entries,
|
// The sparse map is stored in the tar header if it's small enough. If it's larger than four entries,
|
||||||
// then one or more extension headers are used to store the rest of the sparse map.
|
// then one or more extension headers are used to store the rest of the sparse map.
|
||||||
func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry {
|
func (tr *Reader) readOldGNUSparseMap(blk *block) []sparseEntry {
|
||||||
var p parser
|
var p parser
|
||||||
isExtended := header[oldGNUSparseMainHeaderIsExtendedOffset] != 0
|
var s sparseArray = blk.GNU().Sparse()
|
||||||
spCap := oldGNUSparseMainHeaderNumEntries
|
var sp = make([]sparseEntry, 0, s.MaxEntries())
|
||||||
if isExtended {
|
for i := 0; i < s.MaxEntries(); i++ {
|
||||||
spCap += oldGNUSparseExtendedHeaderNumEntries
|
offset := p.parseOctal(s.Entry(i).Offset())
|
||||||
}
|
numBytes := p.parseOctal(s.Entry(i).NumBytes())
|
||||||
sp := make([]sparseEntry, 0, spCap)
|
|
||||||
s := slicer(header[oldGNUSparseMainHeaderOffset:])
|
|
||||||
|
|
||||||
// Read the four entries from the main tar header
|
|
||||||
for i := 0; i < oldGNUSparseMainHeaderNumEntries; i++ {
|
|
||||||
offset := p.parseNumeric(s.next(oldGNUSparseOffsetSize))
|
|
||||||
numBytes := p.parseNumeric(s.next(oldGNUSparseNumBytesSize))
|
|
||||||
if p.err != nil {
|
if p.err != nil {
|
||||||
tr.err = p.err
|
tr.err = p.err
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -711,17 +668,17 @@ func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry {
|
||||||
sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
|
sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
|
||||||
}
|
}
|
||||||
|
|
||||||
for isExtended {
|
for s.IsExtended()[0] > 0 {
|
||||||
// There are more entries. Read an extension header and parse its entries.
|
// There are more entries. Read an extension header and parse its entries.
|
||||||
sparseHeader := make([]byte, blockSize)
|
var blk block
|
||||||
if _, tr.err = io.ReadFull(tr.r, sparseHeader); tr.err != nil {
|
if _, tr.err = io.ReadFull(tr.r, blk[:]); tr.err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
isExtended = sparseHeader[oldGNUSparseExtendedHeaderIsExtendedOffset] != 0
|
s = blk.Sparse()
|
||||||
s = slicer(sparseHeader)
|
|
||||||
for i := 0; i < oldGNUSparseExtendedHeaderNumEntries; i++ {
|
for i := 0; i < s.MaxEntries(); i++ {
|
||||||
offset := p.parseNumeric(s.next(oldGNUSparseOffsetSize))
|
offset := p.parseOctal(s.Entry(i).Offset())
|
||||||
numBytes := p.parseNumeric(s.next(oldGNUSparseNumBytesSize))
|
numBytes := p.parseOctal(s.Entry(i).NumBytes())
|
||||||
if p.err != nil {
|
if p.err != nil {
|
||||||
tr.err = p.err
|
tr.err = p.err
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -36,10 +36,10 @@ type Writer struct {
|
||||||
nb int64 // number of unwritten bytes for current file entry
|
nb int64 // number of unwritten bytes for current file entry
|
||||||
pad int64 // amount of padding to write after current file entry
|
pad int64 // amount of padding to write after current file entry
|
||||||
closed bool
|
closed bool
|
||||||
usedBinary bool // whether the binary numeric field extension was used
|
usedBinary bool // whether the binary numeric field extension was used
|
||||||
preferPax bool // use pax header instead of binary numeric header
|
preferPax bool // use PAX header instead of binary numeric header
|
||||||
hdrBuff [blockSize]byte // buffer to use in writeHeader when writing a regular header
|
hdrBuff block // buffer to use in writeHeader when writing a regular header
|
||||||
paxHdrBuff [blockSize]byte // buffer to use in writeHeader when writing a pax header
|
paxHdrBuff block // buffer to use in writeHeader when writing a PAX header
|
||||||
}
|
}
|
||||||
|
|
||||||
type formatter struct {
|
type formatter struct {
|
||||||
|
|
@ -153,27 +153,24 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
|
||||||
// a map to hold pax header records, if any are needed
|
// a map to hold pax header records, if any are needed
|
||||||
paxHeaders := make(map[string]string)
|
paxHeaders := make(map[string]string)
|
||||||
|
|
||||||
// TODO(shanemhansen): we might want to use PAX headers for
|
// TODO(dsnet): we might want to use PAX headers for
|
||||||
// subsecond time resolution, but for now let's just capture
|
// subsecond time resolution, but for now let's just capture
|
||||||
// too long fields or non ascii characters
|
// too long fields or non ascii characters
|
||||||
|
|
||||||
var f formatter
|
|
||||||
var header []byte
|
|
||||||
|
|
||||||
// We need to select which scratch buffer to use carefully,
|
// We need to select which scratch buffer to use carefully,
|
||||||
// since this method is called recursively to write PAX headers.
|
// since this method is called recursively to write PAX headers.
|
||||||
// If allowPax is true, this is the non-recursive call, and we will use hdrBuff.
|
// If allowPax is true, this is the non-recursive call, and we will use hdrBuff.
|
||||||
// If allowPax is false, we are being called by writePAXHeader, and hdrBuff is
|
// If allowPax is false, we are being called by writePAXHeader, and hdrBuff is
|
||||||
// already being used by the non-recursive call, so we must use paxHdrBuff.
|
// already being used by the non-recursive call, so we must use paxHdrBuff.
|
||||||
header = tw.hdrBuff[:]
|
header := &tw.hdrBuff
|
||||||
if !allowPax {
|
if !allowPax {
|
||||||
header = tw.paxHdrBuff[:]
|
header = &tw.paxHdrBuff
|
||||||
}
|
}
|
||||||
copy(header, zeroBlock)
|
copy(header[:], zeroBlock[:])
|
||||||
s := slicer(header)
|
|
||||||
|
|
||||||
// Wrappers around formatter that automatically sets paxHeaders if the
|
// Wrappers around formatter that automatically sets paxHeaders if the
|
||||||
// argument extends beyond the capacity of the input byte slice.
|
// argument extends beyond the capacity of the input byte slice.
|
||||||
|
var f formatter
|
||||||
var formatString = func(b []byte, s string, paxKeyword string) {
|
var formatString = func(b []byte, s string, paxKeyword string) {
|
||||||
needsPaxHeader := paxKeyword != paxNone && len(s) > len(b) || !isASCII(s)
|
needsPaxHeader := paxKeyword != paxNone && len(s) > len(b) || !isASCII(s)
|
||||||
if needsPaxHeader {
|
if needsPaxHeader {
|
||||||
|
|
@ -202,44 +199,33 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
|
||||||
f.formatNumeric(b, x)
|
f.formatNumeric(b, x)
|
||||||
}
|
}
|
||||||
|
|
||||||
// keep a reference to the filename to allow to overwrite it later if we detect that we can use ustar longnames instead of pax
|
|
||||||
pathHeaderBytes := s.next(fileNameSize)
|
|
||||||
|
|
||||||
formatString(pathHeaderBytes, hdr.Name, paxPath)
|
|
||||||
|
|
||||||
// Handle out of range ModTime carefully.
|
// Handle out of range ModTime carefully.
|
||||||
var modTime int64
|
var modTime int64
|
||||||
if !hdr.ModTime.Before(minTime) && !hdr.ModTime.After(maxTime) {
|
if !hdr.ModTime.Before(minTime) && !hdr.ModTime.After(maxTime) {
|
||||||
modTime = hdr.ModTime.Unix()
|
modTime = hdr.ModTime.Unix()
|
||||||
}
|
}
|
||||||
|
|
||||||
f.formatOctal(s.next(8), hdr.Mode) // 100:108
|
v7 := header.V7()
|
||||||
formatNumeric(s.next(8), int64(hdr.Uid), paxUid) // 108:116
|
formatString(v7.Name(), hdr.Name, paxPath)
|
||||||
formatNumeric(s.next(8), int64(hdr.Gid), paxGid) // 116:124
|
// TODO(dsnet): The GNU format permits the mode field to be encoded in
|
||||||
formatNumeric(s.next(12), hdr.Size, paxSize) // 124:136
|
// base-256 format. Thus, we can use formatNumeric instead of formatOctal.
|
||||||
formatNumeric(s.next(12), modTime, paxNone) // 136:148 --- consider using pax for finer granularity
|
f.formatOctal(v7.Mode(), hdr.Mode)
|
||||||
s.next(8) // chksum (148:156)
|
formatNumeric(v7.UID(), int64(hdr.Uid), paxUid)
|
||||||
s.next(1)[0] = hdr.Typeflag // 156:157
|
formatNumeric(v7.GID(), int64(hdr.Gid), paxGid)
|
||||||
|
formatNumeric(v7.Size(), hdr.Size, paxSize)
|
||||||
|
// TODO(dsnet): Consider using PAX for finer time granularity.
|
||||||
|
formatNumeric(v7.ModTime(), modTime, paxNone)
|
||||||
|
v7.TypeFlag()[0] = hdr.Typeflag
|
||||||
|
formatString(v7.LinkName(), hdr.Linkname, paxLinkpath)
|
||||||
|
|
||||||
formatString(s.next(100), hdr.Linkname, paxLinkpath)
|
ustar := header.USTAR()
|
||||||
|
formatString(ustar.UserName(), hdr.Uname, paxUname)
|
||||||
|
formatString(ustar.GroupName(), hdr.Gname, paxGname)
|
||||||
|
formatNumeric(ustar.DevMajor(), hdr.Devmajor, paxNone)
|
||||||
|
formatNumeric(ustar.DevMinor(), hdr.Devminor, paxNone)
|
||||||
|
|
||||||
copy(s.next(8), []byte("ustar\x0000")) // 257:265
|
|
||||||
formatString(s.next(32), hdr.Uname, paxUname) // 265:297
|
|
||||||
formatString(s.next(32), hdr.Gname, paxGname) // 297:329
|
|
||||||
formatNumeric(s.next(8), hdr.Devmajor, paxNone) // 329:337
|
|
||||||
formatNumeric(s.next(8), hdr.Devminor, paxNone) // 337:345
|
|
||||||
|
|
||||||
// keep a reference to the prefix to allow to overwrite it later if we detect that we can use ustar longnames instead of pax
|
|
||||||
prefixHeaderBytes := s.next(155)
|
|
||||||
formatString(prefixHeaderBytes, "", paxNone) // 345:500 prefix
|
|
||||||
|
|
||||||
// Use the GNU magic instead of POSIX magic if we used any GNU extensions.
|
|
||||||
if tw.usedBinary {
|
|
||||||
copy(header[257:265], []byte("ustar \x00"))
|
|
||||||
}
|
|
||||||
|
|
||||||
_, paxPathUsed := paxHeaders[paxPath]
|
|
||||||
// try to use a ustar header when only the name is too long
|
// try to use a ustar header when only the name is too long
|
||||||
|
_, paxPathUsed := paxHeaders[paxPath]
|
||||||
if !tw.preferPax && len(paxHeaders) == 1 && paxPathUsed {
|
if !tw.preferPax && len(paxHeaders) == 1 && paxPathUsed {
|
||||||
prefix, suffix, ok := splitUSTARPath(hdr.Name)
|
prefix, suffix, ok := splitUSTARPath(hdr.Name)
|
||||||
if ok {
|
if ok {
|
||||||
|
|
@ -247,16 +233,16 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
|
||||||
delete(paxHeaders, paxPath)
|
delete(paxHeaders, paxPath)
|
||||||
|
|
||||||
// Update the path fields
|
// Update the path fields
|
||||||
formatString(pathHeaderBytes, suffix, paxNone)
|
formatString(v7.Name(), suffix, paxNone)
|
||||||
formatString(prefixHeaderBytes, prefix, paxNone)
|
formatString(ustar.Prefix(), prefix, paxNone)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The chksum field is terminated by a NUL and a space.
|
if tw.usedBinary {
|
||||||
// This is different from the other octal fields.
|
header.SetFormat(formatGNU)
|
||||||
chksum, _ := checksum(header)
|
} else {
|
||||||
f.formatOctal(header[148:155], chksum) // Never fails
|
header.SetFormat(formatUSTAR)
|
||||||
header[155] = ' '
|
}
|
||||||
|
|
||||||
// Check if there were any formatting errors.
|
// Check if there were any formatting errors.
|
||||||
if f.err != nil {
|
if f.err != nil {
|
||||||
|
|
@ -281,7 +267,7 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
|
||||||
tw.nb = hdr.Size
|
tw.nb = hdr.Size
|
||||||
tw.pad = (blockSize - (tw.nb % blockSize)) % blockSize
|
tw.pad = (blockSize - (tw.nb % blockSize)) % blockSize
|
||||||
|
|
||||||
_, tw.err = tw.w.Write(header)
|
_, tw.err = tw.w.Write(header[:])
|
||||||
return tw.err
|
return tw.err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -289,10 +275,10 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
|
||||||
// If the path is not splittable, then it will return ("", "", false).
|
// If the path is not splittable, then it will return ("", "", false).
|
||||||
func splitUSTARPath(name string) (prefix, suffix string, ok bool) {
|
func splitUSTARPath(name string) (prefix, suffix string, ok bool) {
|
||||||
length := len(name)
|
length := len(name)
|
||||||
if length <= fileNameSize || !isASCII(name) {
|
if length <= nameSize || !isASCII(name) {
|
||||||
return "", "", false
|
return "", "", false
|
||||||
} else if length > fileNamePrefixSize+1 {
|
} else if length > prefixSize+1 {
|
||||||
length = fileNamePrefixSize + 1
|
length = prefixSize + 1
|
||||||
} else if name[length-1] == '/' {
|
} else if name[length-1] == '/' {
|
||||||
length--
|
length--
|
||||||
}
|
}
|
||||||
|
|
@ -300,7 +286,7 @@ func splitUSTARPath(name string) (prefix, suffix string, ok bool) {
|
||||||
i := strings.LastIndex(name[:length], "/")
|
i := strings.LastIndex(name[:length], "/")
|
||||||
nlen := len(name) - i - 1 // nlen is length of suffix
|
nlen := len(name) - i - 1 // nlen is length of suffix
|
||||||
plen := i // plen is length of prefix
|
plen := i // plen is length of prefix
|
||||||
if i <= 0 || nlen > fileNameSize || nlen == 0 || plen > fileNamePrefixSize {
|
if i <= 0 || nlen > nameSize || nlen == 0 || plen > prefixSize {
|
||||||
return "", "", false
|
return "", "", false
|
||||||
}
|
}
|
||||||
return name[:i], name[i+1:], true
|
return name[:i], name[i+1:], true
|
||||||
|
|
@ -323,8 +309,8 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHeaders map[string]string) erro
|
||||||
fullName := path.Join(dir, "PaxHeaders.0", file)
|
fullName := path.Join(dir, "PaxHeaders.0", file)
|
||||||
|
|
||||||
ascii := toASCII(fullName)
|
ascii := toASCII(fullName)
|
||||||
if len(ascii) > 100 {
|
if len(ascii) > nameSize {
|
||||||
ascii = ascii[:100]
|
ascii = ascii[:nameSize]
|
||||||
}
|
}
|
||||||
ext.Name = ascii
|
ext.Name = ascii
|
||||||
// Construct the body
|
// Construct the body
|
||||||
|
|
@ -407,7 +393,7 @@ func (tw *Writer) Close() error {
|
||||||
|
|
||||||
// trailer: two zero blocks
|
// trailer: two zero blocks
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
_, tw.err = tw.w.Write(zeroBlock)
|
_, tw.err = tw.w.Write(zeroBlock[:])
|
||||||
if tw.err != nil {
|
if tw.err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -587,17 +587,17 @@ func TestSplitUSTARPath(t *testing.T) {
|
||||||
{"", "", "", false},
|
{"", "", "", false},
|
||||||
{"abc", "", "", false},
|
{"abc", "", "", false},
|
||||||
{"用戶名", "", "", false},
|
{"用戶名", "", "", false},
|
||||||
{sr("a", fileNameSize), "", "", false},
|
{sr("a", nameSize), "", "", false},
|
||||||
{sr("a", fileNameSize) + "/", "", "", false},
|
{sr("a", nameSize) + "/", "", "", false},
|
||||||
{sr("a", fileNameSize) + "/a", sr("a", fileNameSize), "a", true},
|
{sr("a", nameSize) + "/a", sr("a", nameSize), "a", true},
|
||||||
{sr("a", fileNamePrefixSize) + "/", "", "", false},
|
{sr("a", prefixSize) + "/", "", "", false},
|
||||||
{sr("a", fileNamePrefixSize) + "/a", sr("a", fileNamePrefixSize), "a", true},
|
{sr("a", prefixSize) + "/a", sr("a", prefixSize), "a", true},
|
||||||
{sr("a", fileNameSize+1), "", "", false},
|
{sr("a", nameSize+1), "", "", false},
|
||||||
{sr("/", fileNameSize+1), sr("/", fileNameSize-1), "/", true},
|
{sr("/", nameSize+1), sr("/", nameSize-1), "/", true},
|
||||||
{sr("a", fileNamePrefixSize) + "/" + sr("b", fileNameSize),
|
{sr("a", prefixSize) + "/" + sr("b", nameSize),
|
||||||
sr("a", fileNamePrefixSize), sr("b", fileNameSize), true},
|
sr("a", prefixSize), sr("b", nameSize), true},
|
||||||
{sr("a", fileNamePrefixSize) + "//" + sr("b", fileNameSize), "", "", false},
|
{sr("a", prefixSize) + "//" + sr("b", nameSize), "", "", false},
|
||||||
{sr("a/", fileNameSize), sr("a/", 77) + "a", sr("a/", 22), true},
|
{sr("a/", nameSize), sr("a/", 77) + "a", sr("a/", 22), true},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, v := range vectors {
|
for _, v := range vectors {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
/*
|
/*
|
||||||
Package zip provides support for reading and writing ZIP archives.
|
Package zip provides support for reading and writing ZIP archives.
|
||||||
|
|
||||||
See: http://www.pkware.com/documents/casestudies/APPNOTE.TXT
|
See: https://www.pkware.com/documents/casestudies/APPNOTE.TXT
|
||||||
|
|
||||||
This package does not support disk spanning.
|
This package does not support disk spanning.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1475,7 +1475,7 @@ func BenchmarkReaderWriteToOptimal(b *testing.B) {
|
||||||
b.Fatal("ioutil.Discard doesn't support ReaderFrom")
|
b.Fatal("ioutil.Discard doesn't support ReaderFrom")
|
||||||
}
|
}
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
r.Seek(0, 0)
|
r.Seek(0, io.SeekStart)
|
||||||
srcReader.Reset(onlyReader{r})
|
srcReader.Reset(onlyReader{r})
|
||||||
n, err := srcReader.WriteTo(ioutil.Discard)
|
n, err := srcReader.WriteTo(ioutil.Discard)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -108,11 +108,11 @@ func (r *Reader) Seek(offset int64, whence int) (int64, error) {
|
||||||
r.prevRune = -1
|
r.prevRune = -1
|
||||||
var abs int64
|
var abs int64
|
||||||
switch whence {
|
switch whence {
|
||||||
case 0:
|
case io.SeekStart:
|
||||||
abs = offset
|
abs = offset
|
||||||
case 1:
|
case io.SeekCurrent:
|
||||||
abs = r.i + offset
|
abs = r.i + offset
|
||||||
case 2:
|
case io.SeekEnd:
|
||||||
abs = int64(len(r.s)) + offset
|
abs = int64(len(r.s)) + offset
|
||||||
default:
|
default:
|
||||||
return 0, errors.New("bytes.Reader.Seek: invalid whence")
|
return 0, errors.New("bytes.Reader.Seek: invalid whence")
|
||||||
|
|
|
||||||
|
|
@ -188,7 +188,7 @@ var UnreadRuneErrorTests = []struct {
|
||||||
{"Read", func(r *Reader) { r.Read([]byte{0}) }},
|
{"Read", func(r *Reader) { r.Read([]byte{0}) }},
|
||||||
{"ReadByte", func(r *Reader) { r.ReadByte() }},
|
{"ReadByte", func(r *Reader) { r.ReadByte() }},
|
||||||
{"UnreadRune", func(r *Reader) { r.UnreadRune() }},
|
{"UnreadRune", func(r *Reader) { r.UnreadRune() }},
|
||||||
{"Seek", func(r *Reader) { r.Seek(0, 1) }},
|
{"Seek", func(r *Reader) { r.Seek(0, io.SeekCurrent) }},
|
||||||
{"WriteTo", func(r *Reader) { r.WriteTo(&Buffer{}) }},
|
{"WriteTo", func(r *Reader) { r.WriteTo(&Buffer{}) }},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
28
src/cmd/asm/internal/arch/amd64.go
Normal file
28
src/cmd/asm/internal/arch/amd64.go
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
// Copyright 2016 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 encapsulates some of the odd characteristics of the
|
||||||
|
// AMD64 instruction set, to minimize its interaction
|
||||||
|
// with the core of the assembler.
|
||||||
|
|
||||||
|
package arch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cmd/internal/obj"
|
||||||
|
"cmd/internal/obj/x86"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsAMD4OP reports whether the op (as defined by an ppc64.A* constant) is
|
||||||
|
// The FMADD-like instructions behave similarly.
|
||||||
|
func IsAMD4OP(op obj.As) bool {
|
||||||
|
switch op {
|
||||||
|
case x86.AVPERM2F128,
|
||||||
|
x86.AVPALIGNR,
|
||||||
|
x86.AVPERM2I128,
|
||||||
|
x86.AVINSERTI128,
|
||||||
|
x86.AVPBLENDD:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
@ -568,6 +568,15 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
|
||||||
prog.From = a[0]
|
prog.From = a[0]
|
||||||
prog.Reg = p.getRegister(prog, op, &a[1])
|
prog.Reg = p.getRegister(prog, op, &a[1])
|
||||||
prog.To = a[2]
|
prog.To = a[2]
|
||||||
|
case sys.AMD64:
|
||||||
|
// Catch missing operand here, because we store immediate as part of From3, and can't distinguish
|
||||||
|
// missing operand from legal value 0 in obj/x86/asm6.
|
||||||
|
if arch.IsAMD4OP(op) {
|
||||||
|
p.errorf("4 operands required, but only 3 are provided for %s instruction", obj.Aconv(op))
|
||||||
|
}
|
||||||
|
prog.From = a[0]
|
||||||
|
prog.From3 = newAddr(a[1])
|
||||||
|
prog.To = a[2]
|
||||||
case sys.ARM64:
|
case sys.ARM64:
|
||||||
// ARM64 instructions with one input and two outputs.
|
// ARM64 instructions with one input and two outputs.
|
||||||
if arch.IsARM64STLXR(op) {
|
if arch.IsARM64STLXR(op) {
|
||||||
|
|
@ -583,7 +592,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
|
||||||
prog.From = a[0]
|
prog.From = a[0]
|
||||||
prog.Reg = p.getRegister(prog, op, &a[1])
|
prog.Reg = p.getRegister(prog, op, &a[1])
|
||||||
prog.To = a[2]
|
prog.To = a[2]
|
||||||
case sys.AMD64, sys.I386:
|
case sys.I386:
|
||||||
prog.From = a[0]
|
prog.From = a[0]
|
||||||
prog.From3 = newAddr(a[1])
|
prog.From3 = newAddr(a[1])
|
||||||
prog.To = a[2]
|
prog.To = a[2]
|
||||||
|
|
@ -640,6 +649,23 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
|
||||||
prog.Reg = r1
|
prog.Reg = r1
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
if p.arch.Family == sys.AMD64 {
|
||||||
|
// 4 operand instruction have form ymm1, ymm2, ymm3/m256, imm8
|
||||||
|
// So From3 is always just a register, so we store imm8 in Offset field,
|
||||||
|
// to avoid increasing size of Prog.
|
||||||
|
prog.From = a[1]
|
||||||
|
prog.From3 = newAddr(a[2])
|
||||||
|
if a[0].Type != obj.TYPE_CONST {
|
||||||
|
p.errorf("first operand must be an immediate in %s instruction", obj.Aconv(op))
|
||||||
|
}
|
||||||
|
if prog.From3.Type != obj.TYPE_REG {
|
||||||
|
p.errorf("third operand must be a register in %s instruction", obj.Aconv(op))
|
||||||
|
}
|
||||||
|
prog.From3.Offset = int64(p.getImmediate(prog, op, &a[0]))
|
||||||
|
prog.To = a[3]
|
||||||
|
prog.RegTo2 = -1
|
||||||
|
break
|
||||||
|
}
|
||||||
if p.arch.Family == sys.ARM64 {
|
if p.arch.Family == sys.ARM64 {
|
||||||
prog.From = a[0]
|
prog.From = a[0]
|
||||||
prog.Reg = p.getRegister(prog, op, &a[1])
|
prog.Reg = p.getRegister(prog, op, &a[1])
|
||||||
|
|
|
||||||
368
src/cmd/asm/internal/asm/testdata/amd64enc.s
vendored
368
src/cmd/asm/internal/asm/testdata/amd64enc.s
vendored
|
|
@ -5008,22 +5008,22 @@ TEXT asmtest(SB),7,$0
|
||||||
RORB $7, (R11) // 41c00b07
|
RORB $7, (R11) // 41c00b07
|
||||||
RORB $7, DL // c0ca07
|
RORB $7, DL // c0ca07
|
||||||
RORB $7, R11 // 41c0cb07
|
RORB $7, R11 // 41c0cb07
|
||||||
//TODO: RORXL $7, (BX), DX // c4e37bf01307
|
RORXL $7, (BX), DX // c4e37bf01307
|
||||||
//TODO: RORXL $7, (R11), DX // c4c37bf01307
|
RORXL $7, (R11), DX // c4c37bf01307
|
||||||
//TODO: RORXL $7, DX, DX // c4e37bf0d207
|
RORXL $7, DX, DX // c4e37bf0d207
|
||||||
//TODO: RORXL $7, R11, DX // c4c37bf0d307
|
RORXL $7, R11, DX // c4c37bf0d307
|
||||||
//TODO: RORXL $7, (BX), R11 // c4637bf01b07
|
RORXL $7, (BX), R11 // c4637bf01b07
|
||||||
//TODO: RORXL $7, (R11), R11 // c4437bf01b07
|
RORXL $7, (R11), R11 // c4437bf01b07
|
||||||
//TODO: RORXL $7, DX, R11 // c4637bf0da07
|
RORXL $7, DX, R11 // c4637bf0da07
|
||||||
//TODO: RORXL $7, R11, R11 // c4437bf0db07
|
RORXL $7, R11, R11 // c4437bf0db07
|
||||||
//TODO: RORXQ $7, (BX), DX // c4e3fbf01307
|
RORXQ $7, (BX), DX // c4e3fbf01307
|
||||||
//TODO: RORXQ $7, (R11), DX // c4c3fbf01307
|
RORXQ $7, (R11), DX // c4c3fbf01307
|
||||||
//TODO: RORXQ $7, DX, DX // c4e3fbf0d207
|
RORXQ $7, DX, DX // c4e3fbf0d207
|
||||||
//TODO: RORXQ $7, R11, DX // c4c3fbf0d307
|
RORXQ $7, R11, DX // c4c3fbf0d307
|
||||||
//TODO: RORXQ $7, (BX), R11 // c463fbf01b07
|
RORXQ $7, (BX), R11 // c463fbf01b07
|
||||||
//TODO: RORXQ $7, (R11), R11 // c443fbf01b07
|
RORXQ $7, (R11), R11 // c443fbf01b07
|
||||||
//TODO: RORXQ $7, DX, R11 // c463fbf0da07
|
RORXQ $7, DX, R11 // c463fbf0da07
|
||||||
//TODO: RORXQ $7, R11, R11 // c443fbf0db07
|
RORXQ $7, R11, R11 // c443fbf0db07
|
||||||
ROUNDPD $7, (BX), X2 // 660f3a091307
|
ROUNDPD $7, (BX), X2 // 660f3a091307
|
||||||
ROUNDPD $7, (R11), X2 // 66410f3a091307
|
ROUNDPD $7, (R11), X2 // 66410f3a091307
|
||||||
ROUNDPD $7, X2, X2 // 660f3a09d207
|
ROUNDPD $7, X2, X2 // 660f3a09d207
|
||||||
|
|
@ -7420,14 +7420,14 @@ TEXT asmtest(SB),7,$0
|
||||||
//TODO: VINSERTF128 $7, (R11), Y15, Y11 // c44305181b07
|
//TODO: VINSERTF128 $7, (R11), Y15, Y11 // c44305181b07
|
||||||
//TODO: VINSERTF128 $7, X2, Y15, Y11 // c4630518da07
|
//TODO: VINSERTF128 $7, X2, Y15, Y11 // c4630518da07
|
||||||
//TODO: VINSERTF128 $7, X11, Y15, Y11 // c4430518db07
|
//TODO: VINSERTF128 $7, X11, Y15, Y11 // c4430518db07
|
||||||
//TODO: VINSERTI128 $7, (BX), Y15, Y2 // c4e305381307
|
VINSERTI128 $7, (BX), Y15, Y2 // c4e305381307
|
||||||
//TODO: VINSERTI128 $7, (R11), Y15, Y2 // c4c305381307
|
VINSERTI128 $7, (R11), Y15, Y2 // c4c305381307
|
||||||
//TODO: VINSERTI128 $7, X2, Y15, Y2 // c4e30538d207
|
VINSERTI128 $7, X2, Y15, Y2 // c4e30538d207
|
||||||
//TODO: VINSERTI128 $7, X11, Y15, Y2 // c4c30538d307
|
VINSERTI128 $7, X11, Y15, Y2 // c4c30538d307
|
||||||
//TODO: VINSERTI128 $7, (BX), Y15, Y11 // c46305381b07
|
VINSERTI128 $7, (BX), Y15, Y11 // c46305381b07
|
||||||
//TODO: VINSERTI128 $7, (R11), Y15, Y11 // c44305381b07
|
VINSERTI128 $7, (R11), Y15, Y11 // c44305381b07
|
||||||
//TODO: VINSERTI128 $7, X2, Y15, Y11 // c4630538da07
|
VINSERTI128 $7, X2, Y15, Y11 // c4630538da07
|
||||||
//TODO: VINSERTI128 $7, X11, Y15, Y11 // c4430538db07
|
VINSERTI128 $7, X11, Y15, Y11 // c4430538db07
|
||||||
//TODO: VINSERTPS $7, (BX), X9, X2 // c4e331211307
|
//TODO: VINSERTPS $7, (BX), X9, X2 // c4e331211307
|
||||||
//TODO: VINSERTPS $7, (R11), X9, X2 // c4c331211307
|
//TODO: VINSERTPS $7, (R11), X9, X2 // c4c331211307
|
||||||
//TODO: VINSERTPS $7, X2, X9, X2 // c4e33121d207
|
//TODO: VINSERTPS $7, X2, X9, X2 // c4e33121d207
|
||||||
|
|
@ -8142,38 +8142,38 @@ TEXT asmtest(SB),7,$0
|
||||||
//TODO: VPADDB (R11), Y15, Y11 // c44105fc1b
|
//TODO: VPADDB (R11), Y15, Y11 // c44105fc1b
|
||||||
//TODO: VPADDB Y2, Y15, Y11 // c46105fcda or c505fcda
|
//TODO: VPADDB Y2, Y15, Y11 // c46105fcda or c505fcda
|
||||||
//TODO: VPADDB Y11, Y15, Y11 // c44105fcdb
|
//TODO: VPADDB Y11, Y15, Y11 // c44105fcdb
|
||||||
//TODO: VPADDD (BX), X9, X2 // c4e131fe13 or c5b1fe13
|
VPADDD (BX), X9, X2 // c4e131fe13 or c5b1fe13
|
||||||
//TODO: VPADDD (R11), X9, X2 // c4c131fe13
|
VPADDD (R11), X9, X2 // c4c131fe13
|
||||||
//TODO: VPADDD X2, X9, X2 // c4e131fed2 or c5b1fed2
|
VPADDD X2, X9, X2 // c4e131fed2 or c5b1fed2
|
||||||
//TODO: VPADDD X11, X9, X2 // c4c131fed3
|
VPADDD X11, X9, X2 // c4c131fed3
|
||||||
//TODO: VPADDD (BX), X9, X11 // c46131fe1b or c531fe1b
|
VPADDD (BX), X9, X11 // c46131fe1b or c531fe1b
|
||||||
//TODO: VPADDD (R11), X9, X11 // c44131fe1b
|
VPADDD (R11), X9, X11 // c44131fe1b
|
||||||
//TODO: VPADDD X2, X9, X11 // c46131feda or c531feda
|
VPADDD X2, X9, X11 // c46131feda or c531feda
|
||||||
//TODO: VPADDD X11, X9, X11 // c44131fedb
|
VPADDD X11, X9, X11 // c44131fedb
|
||||||
//TODO: VPADDD (BX), Y15, Y2 // c4e105fe13 or c585fe13
|
VPADDD (BX), Y15, Y2 // c4e105fe13 or c585fe13
|
||||||
//TODO: VPADDD (R11), Y15, Y2 // c4c105fe13
|
VPADDD (R11), Y15, Y2 // c4c105fe13
|
||||||
//TODO: VPADDD Y2, Y15, Y2 // c4e105fed2 or c585fed2
|
VPADDD Y2, Y15, Y2 // c4e105fed2 or c585fed2
|
||||||
//TODO: VPADDD Y11, Y15, Y2 // c4c105fed3
|
VPADDD Y11, Y15, Y2 // c4c105fed3
|
||||||
//TODO: VPADDD (BX), Y15, Y11 // c46105fe1b or c505fe1b
|
VPADDD (BX), Y15, Y11 // c46105fe1b or c505fe1b
|
||||||
//TODO: VPADDD (R11), Y15, Y11 // c44105fe1b
|
VPADDD (R11), Y15, Y11 // c44105fe1b
|
||||||
//TODO: VPADDD Y2, Y15, Y11 // c46105feda or c505feda
|
VPADDD Y2, Y15, Y11 // c46105feda or c505feda
|
||||||
//TODO: VPADDD Y11, Y15, Y11 // c44105fedb
|
VPADDD Y11, Y15, Y11 // c44105fedb
|
||||||
//TODO: VPADDQ (BX), X9, X2 // c4e131d413 or c5b1d413
|
VPADDQ (BX), X9, X2 // c4e131d413 or c5b1d413
|
||||||
//TODO: VPADDQ (R11), X9, X2 // c4c131d413
|
VPADDQ (R11), X9, X2 // c4c131d413
|
||||||
//TODO: VPADDQ X2, X9, X2 // c4e131d4d2 or c5b1d4d2
|
VPADDQ X2, X9, X2 // c4e131d4d2 or c5b1d4d2
|
||||||
//TODO: VPADDQ X11, X9, X2 // c4c131d4d3
|
VPADDQ X11, X9, X2 // c4c131d4d3
|
||||||
//TODO: VPADDQ (BX), X9, X11 // c46131d41b or c531d41b
|
VPADDQ (BX), X9, X11 // c46131d41b or c531d41b
|
||||||
//TODO: VPADDQ (R11), X9, X11 // c44131d41b
|
VPADDQ (R11), X9, X11 // c44131d41b
|
||||||
//TODO: VPADDQ X2, X9, X11 // c46131d4da or c531d4da
|
VPADDQ X2, X9, X11 // c46131d4da or c531d4da
|
||||||
//TODO: VPADDQ X11, X9, X11 // c44131d4db
|
VPADDQ X11, X9, X11 // c44131d4db
|
||||||
//TODO: VPADDQ (BX), Y15, Y2 // c4e105d413 or c585d413
|
VPADDQ (BX), Y15, Y2 // c4e105d413 or c585d413
|
||||||
//TODO: VPADDQ (R11), Y15, Y2 // c4c105d413
|
VPADDQ (R11), Y15, Y2 // c4c105d413
|
||||||
//TODO: VPADDQ Y2, Y15, Y2 // c4e105d4d2 or c585d4d2
|
VPADDQ Y2, Y15, Y2 // c4e105d4d2 or c585d4d2
|
||||||
//TODO: VPADDQ Y11, Y15, Y2 // c4c105d4d3
|
VPADDQ Y11, Y15, Y2 // c4c105d4d3
|
||||||
//TODO: VPADDQ (BX), Y15, Y11 // c46105d41b or c505d41b
|
VPADDQ (BX), Y15, Y11 // c46105d41b or c505d41b
|
||||||
//TODO: VPADDQ (R11), Y15, Y11 // c44105d41b
|
VPADDQ (R11), Y15, Y11 // c44105d41b
|
||||||
//TODO: VPADDQ Y2, Y15, Y11 // c46105d4da or c505d4da
|
VPADDQ Y2, Y15, Y11 // c46105d4da or c505d4da
|
||||||
//TODO: VPADDQ Y11, Y15, Y11 // c44105d4db
|
VPADDQ Y11, Y15, Y11 // c44105d4db
|
||||||
//TODO: VPADDSB (BX), X9, X2 // c4e131ec13 or c5b1ec13
|
//TODO: VPADDSB (BX), X9, X2 // c4e131ec13 or c5b1ec13
|
||||||
//TODO: VPADDSB (R11), X9, X2 // c4c131ec13
|
//TODO: VPADDSB (R11), X9, X2 // c4c131ec13
|
||||||
//TODO: VPADDSB X2, X9, X2 // c4e131ecd2 or c5b1ecd2
|
//TODO: VPADDSB X2, X9, X2 // c4e131ecd2 or c5b1ecd2
|
||||||
|
|
@ -8262,14 +8262,14 @@ TEXT asmtest(SB),7,$0
|
||||||
//TODO: VPALIGNR $7, (R11), X9, X11 // c443310f1b07
|
//TODO: VPALIGNR $7, (R11), X9, X11 // c443310f1b07
|
||||||
//TODO: VPALIGNR $7, X2, X9, X11 // c463310fda07
|
//TODO: VPALIGNR $7, X2, X9, X11 // c463310fda07
|
||||||
//TODO: VPALIGNR $7, X11, X9, X11 // c443310fdb07
|
//TODO: VPALIGNR $7, X11, X9, X11 // c443310fdb07
|
||||||
//TODO: VPALIGNR $7, (BX), Y15, Y2 // c4e3050f1307
|
VPALIGNR $7, (BX), Y15, Y2 // c4e3050f1307
|
||||||
//TODO: VPALIGNR $7, (R11), Y15, Y2 // c4c3050f1307
|
VPALIGNR $7, (R11), Y15, Y2 // c4c3050f1307
|
||||||
//TODO: VPALIGNR $7, Y2, Y15, Y2 // c4e3050fd207
|
VPALIGNR $7, Y2, Y15, Y2 // c4e3050fd207
|
||||||
//TODO: VPALIGNR $7, Y11, Y15, Y2 // c4c3050fd307
|
VPALIGNR $7, Y11, Y15, Y2 // c4c3050fd307
|
||||||
//TODO: VPALIGNR $7, (BX), Y15, Y11 // c463050f1b07
|
VPALIGNR $7, (BX), Y15, Y11 // c463050f1b07
|
||||||
//TODO: VPALIGNR $7, (R11), Y15, Y11 // c443050f1b07
|
VPALIGNR $7, (R11), Y15, Y11 // c443050f1b07
|
||||||
//TODO: VPALIGNR $7, Y2, Y15, Y11 // c463050fda07
|
VPALIGNR $7, Y2, Y15, Y11 // c463050fda07
|
||||||
//TODO: VPALIGNR $7, Y11, Y15, Y11 // c443050fdb07
|
VPALIGNR $7, Y11, Y15, Y11 // c443050fdb07
|
||||||
VPAND (BX), X9, X2 // c4e131db13 or c5b1db13
|
VPAND (BX), X9, X2 // c4e131db13 or c5b1db13
|
||||||
VPAND (R11), X9, X2 // c4c131db13
|
VPAND (R11), X9, X2 // c4c131db13
|
||||||
VPAND X2, X9, X2 // c4e131dbd2 or c5b1dbd2
|
VPAND X2, X9, X2 // c4e131dbd2 or c5b1dbd2
|
||||||
|
|
@ -8342,14 +8342,14 @@ TEXT asmtest(SB),7,$0
|
||||||
//TODO: VPBLENDD $7, (R11), X9, X11 // c44331021b07
|
//TODO: VPBLENDD $7, (R11), X9, X11 // c44331021b07
|
||||||
//TODO: VPBLENDD $7, X2, X9, X11 // c4633102da07
|
//TODO: VPBLENDD $7, X2, X9, X11 // c4633102da07
|
||||||
//TODO: VPBLENDD $7, X11, X9, X11 // c4433102db07
|
//TODO: VPBLENDD $7, X11, X9, X11 // c4433102db07
|
||||||
//TODO: VPBLENDD $7, (BX), Y15, Y2 // c4e305021307
|
VPBLENDD $7, (BX), Y15, Y2 // c4e305021307
|
||||||
//TODO: VPBLENDD $7, (R11), Y15, Y2 // c4c305021307
|
VPBLENDD $7, (R11), Y15, Y2 // c4c305021307
|
||||||
//TODO: VPBLENDD $7, Y2, Y15, Y2 // c4e30502d207
|
VPBLENDD $7, Y2, Y15, Y2 // c4e30502d207
|
||||||
//TODO: VPBLENDD $7, Y11, Y15, Y2 // c4c30502d307
|
VPBLENDD $7, Y11, Y15, Y2 // c4c30502d307
|
||||||
//TODO: VPBLENDD $7, (BX), Y15, Y11 // c46305021b07
|
VPBLENDD $7, (BX), Y15, Y11 // c46305021b07
|
||||||
//TODO: VPBLENDD $7, (R11), Y15, Y11 // c44305021b07
|
VPBLENDD $7, (R11), Y15, Y11 // c44305021b07
|
||||||
//TODO: VPBLENDD $7, Y2, Y15, Y11 // c4630502da07
|
VPBLENDD $7, Y2, Y15, Y11 // c4630502da07
|
||||||
//TODO: VPBLENDD $7, Y11, Y15, Y11 // c4430502db07
|
VPBLENDD $7, Y11, Y15, Y11 // c4430502db07
|
||||||
//TODO: VPBLENDVB XMM12, (BX), X9, X2 // c4e3314c13c0
|
//TODO: VPBLENDVB XMM12, (BX), X9, X2 // c4e3314c13c0
|
||||||
//TODO: VPBLENDVB XMM12, (R11), X9, X2 // c4c3314c13c0
|
//TODO: VPBLENDVB XMM12, (R11), X9, X2 // c4c3314c13c0
|
||||||
//TODO: VPBLENDVB XMM12, X2, X9, X2 // c4e3314cd2c0
|
//TODO: VPBLENDVB XMM12, X2, X9, X2 // c4e3314cd2c0
|
||||||
|
|
@ -8614,22 +8614,22 @@ TEXT asmtest(SB),7,$0
|
||||||
//TODO: VPCMPISTRM $7, (R11), X11 // c44379621b07
|
//TODO: VPCMPISTRM $7, (R11), X11 // c44379621b07
|
||||||
//TODO: VPCMPISTRM $7, X2, X11 // c4637962da07
|
//TODO: VPCMPISTRM $7, X2, X11 // c4637962da07
|
||||||
//TODO: VPCMPISTRM $7, X11, X11 // c4437962db07
|
//TODO: VPCMPISTRM $7, X11, X11 // c4437962db07
|
||||||
//TODO: VPERM2F128 $7, (BX), Y15, Y2 // c4e305061307
|
VPERM2F128 $7, (BX), Y15, Y2 // c4e305061307
|
||||||
//TODO: VPERM2F128 $7, (R11), Y15, Y2 // c4c305061307
|
VPERM2F128 $7, (R11), Y15, Y2 // c4c305061307
|
||||||
//TODO: VPERM2F128 $7, Y2, Y15, Y2 // c4e30506d207
|
VPERM2F128 $7, Y2, Y15, Y2 // c4e30506d207
|
||||||
//TODO: VPERM2F128 $7, Y11, Y15, Y2 // c4c30506d307
|
VPERM2F128 $7, Y11, Y15, Y2 // c4c30506d307
|
||||||
//TODO: VPERM2F128 $7, (BX), Y15, Y11 // c46305061b07
|
VPERM2F128 $7, (BX), Y15, Y11 // c46305061b07
|
||||||
//TODO: VPERM2F128 $7, (R11), Y15, Y11 // c44305061b07
|
VPERM2F128 $7, (R11), Y15, Y11 // c44305061b07
|
||||||
//TODO: VPERM2F128 $7, Y2, Y15, Y11 // c4630506da07
|
VPERM2F128 $7, Y2, Y15, Y11 // c4630506da07
|
||||||
//TODO: VPERM2F128 $7, Y11, Y15, Y11 // c4430506db07
|
VPERM2F128 $7, Y11, Y15, Y11 // c4430506db07
|
||||||
//TODO: VPERM2I128 $7, (BX), Y15, Y2 // c4e305461307
|
VPERM2I128 $7, (BX), Y15, Y2 // c4e305461307
|
||||||
//TODO: VPERM2I128 $7, (R11), Y15, Y2 // c4c305461307
|
VPERM2I128 $7, (R11), Y15, Y2 // c4c305461307
|
||||||
//TODO: VPERM2I128 $7, Y2, Y15, Y2 // c4e30546d207
|
VPERM2I128 $7, Y2, Y15, Y2 // c4e30546d207
|
||||||
//TODO: VPERM2I128 $7, Y11, Y15, Y2 // c4c30546d307
|
VPERM2I128 $7, Y11, Y15, Y2 // c4c30546d307
|
||||||
//TODO: VPERM2I128 $7, (BX), Y15, Y11 // c46305461b07
|
VPERM2I128 $7, (BX), Y15, Y11 // c46305461b07
|
||||||
//TODO: VPERM2I128 $7, (R11), Y15, Y11 // c44305461b07
|
VPERM2I128 $7, (R11), Y15, Y11 // c44305461b07
|
||||||
//TODO: VPERM2I128 $7, Y2, Y15, Y11 // c4630546da07
|
VPERM2I128 $7, Y2, Y15, Y11 // c4630546da07
|
||||||
//TODO: VPERM2I128 $7, Y11, Y15, Y11 // c4430546db07
|
VPERM2I128 $7, Y11, Y15, Y11 // c4430546db07
|
||||||
//TODO: VPERMD (BX), Y15, Y2 // c4e2053613
|
//TODO: VPERMD (BX), Y15, Y2 // c4e2053613
|
||||||
//TODO: VPERMD (R11), Y15, Y2 // c4c2053613
|
//TODO: VPERMD (R11), Y15, Y2 // c4c2053613
|
||||||
//TODO: VPERMD Y2, Y15, Y2 // c4e20536d2
|
//TODO: VPERMD Y2, Y15, Y2 // c4e20536d2
|
||||||
|
|
@ -9462,22 +9462,22 @@ TEXT asmtest(SB),7,$0
|
||||||
//TODO: VPMULUDQ (R11), Y15, Y11 // c44105f41b
|
//TODO: VPMULUDQ (R11), Y15, Y11 // c44105f41b
|
||||||
//TODO: VPMULUDQ Y2, Y15, Y11 // c46105f4da or c505f4da
|
//TODO: VPMULUDQ Y2, Y15, Y11 // c46105f4da or c505f4da
|
||||||
//TODO: VPMULUDQ Y11, Y15, Y11 // c44105f4db
|
//TODO: VPMULUDQ Y11, Y15, Y11 // c44105f4db
|
||||||
//TODO: VPOR (BX), X9, X2 // c4e131eb13 or c5b1eb13
|
VPOR (BX), X9, X2 // c4e131eb13 or c5b1eb13
|
||||||
//TODO: VPOR (R11), X9, X2 // c4c131eb13
|
VPOR (R11), X9, X2 // c4c131eb13
|
||||||
//TODO: VPOR X2, X9, X2 // c4e131ebd2 or c5b1ebd2
|
VPOR X2, X9, X2 // c4e131ebd2 or c5b1ebd2
|
||||||
//TODO: VPOR X11, X9, X2 // c4c131ebd3
|
VPOR X11, X9, X2 // c4c131ebd3
|
||||||
//TODO: VPOR (BX), X9, X11 // c46131eb1b or c531eb1b
|
VPOR (BX), X9, X11 // c46131eb1b or c531eb1b
|
||||||
//TODO: VPOR (R11), X9, X11 // c44131eb1b
|
VPOR (R11), X9, X11 // c44131eb1b
|
||||||
//TODO: VPOR X2, X9, X11 // c46131ebda or c531ebda
|
VPOR X2, X9, X11 // c46131ebda or c531ebda
|
||||||
//TODO: VPOR X11, X9, X11 // c44131ebdb
|
VPOR X11, X9, X11 // c44131ebdb
|
||||||
//TODO: VPOR (BX), Y15, Y2 // c4e105eb13 or c585eb13
|
VPOR (BX), Y15, Y2 // c4e105eb13 or c585eb13
|
||||||
//TODO: VPOR (R11), Y15, Y2 // c4c105eb13
|
VPOR (R11), Y15, Y2 // c4c105eb13
|
||||||
//TODO: VPOR Y2, Y15, Y2 // c4e105ebd2 or c585ebd2
|
VPOR Y2, Y15, Y2 // c4e105ebd2 or c585ebd2
|
||||||
//TODO: VPOR Y11, Y15, Y2 // c4c105ebd3
|
VPOR Y11, Y15, Y2 // c4c105ebd3
|
||||||
//TODO: VPOR (BX), Y15, Y11 // c46105eb1b or c505eb1b
|
VPOR (BX), Y15, Y11 // c46105eb1b or c505eb1b
|
||||||
//TODO: VPOR (R11), Y15, Y11 // c44105eb1b
|
VPOR (R11), Y15, Y11 // c44105eb1b
|
||||||
//TODO: VPOR Y2, Y15, Y11 // c46105ebda or c505ebda
|
VPOR Y2, Y15, Y11 // c46105ebda or c505ebda
|
||||||
//TODO: VPOR Y11, Y15, Y11 // c44105ebdb
|
VPOR Y11, Y15, Y11 // c44105ebdb
|
||||||
//TODO: VPSADBW (BX), X9, X2 // c4e131f613 or c5b1f613
|
//TODO: VPSADBW (BX), X9, X2 // c4e131f613 or c5b1f613
|
||||||
//TODO: VPSADBW (R11), X9, X2 // c4c131f613
|
//TODO: VPSADBW (R11), X9, X2 // c4c131f613
|
||||||
//TODO: VPSADBW X2, X9, X2 // c4e131f6d2 or c5b1f6d2
|
//TODO: VPSADBW X2, X9, X2 // c4e131f6d2 or c5b1f6d2
|
||||||
|
|
@ -9494,38 +9494,38 @@ TEXT asmtest(SB),7,$0
|
||||||
//TODO: VPSADBW (R11), Y15, Y11 // c44105f61b
|
//TODO: VPSADBW (R11), Y15, Y11 // c44105f61b
|
||||||
//TODO: VPSADBW Y2, Y15, Y11 // c46105f6da or c505f6da
|
//TODO: VPSADBW Y2, Y15, Y11 // c46105f6da or c505f6da
|
||||||
//TODO: VPSADBW Y11, Y15, Y11 // c44105f6db
|
//TODO: VPSADBW Y11, Y15, Y11 // c44105f6db
|
||||||
//TODO: VPSHUFB (BX), X9, X2 // c4e2310013
|
VPSHUFB (BX), X9, X2 // c4e2310013
|
||||||
//TODO: VPSHUFB (R11), X9, X2 // c4c2310013
|
VPSHUFB (R11), X9, X2 // c4c2310013
|
||||||
//TODO: VPSHUFB X2, X9, X2 // c4e23100d2
|
VPSHUFB X2, X9, X2 // c4e23100d2
|
||||||
//TODO: VPSHUFB X11, X9, X2 // c4c23100d3
|
VPSHUFB X11, X9, X2 // c4c23100d3
|
||||||
//TODO: VPSHUFB (BX), X9, X11 // c46231001b
|
VPSHUFB (BX), X9, X11 // c46231001b
|
||||||
//TODO: VPSHUFB (R11), X9, X11 // c44231001b
|
VPSHUFB (R11), X9, X11 // c44231001b
|
||||||
//TODO: VPSHUFB X2, X9, X11 // c4623100da
|
VPSHUFB X2, X9, X11 // c4623100da
|
||||||
//TODO: VPSHUFB X11, X9, X11 // c4423100db
|
VPSHUFB X11, X9, X11 // c4423100db
|
||||||
//TODO: VPSHUFB (BX), Y15, Y2 // c4e2050013
|
VPSHUFB (BX), Y15, Y2 // c4e2050013
|
||||||
//TODO: VPSHUFB (R11), Y15, Y2 // c4c2050013
|
VPSHUFB (R11), Y15, Y2 // c4c2050013
|
||||||
//TODO: VPSHUFB Y2, Y15, Y2 // c4e20500d2
|
VPSHUFB Y2, Y15, Y2 // c4e20500d2
|
||||||
//TODO: VPSHUFB Y11, Y15, Y2 // c4c20500d3
|
VPSHUFB Y11, Y15, Y2 // c4c20500d3
|
||||||
//TODO: VPSHUFB (BX), Y15, Y11 // c46205001b
|
VPSHUFB (BX), Y15, Y11 // c46205001b
|
||||||
//TODO: VPSHUFB (R11), Y15, Y11 // c44205001b
|
VPSHUFB (R11), Y15, Y11 // c44205001b
|
||||||
//TODO: VPSHUFB Y2, Y15, Y11 // c4620500da
|
VPSHUFB Y2, Y15, Y11 // c4620500da
|
||||||
//TODO: VPSHUFB Y11, Y15, Y11 // c4420500db
|
VPSHUFB Y11, Y15, Y11 // c4420500db
|
||||||
//TODO: VPSHUFD $7, (BX), X2 // c4e179701307 or c5f9701307
|
VPSHUFD $7, (BX), X2 // c4e179701307 or c5f9701307
|
||||||
//TODO: VPSHUFD $7, (R11), X2 // c4c179701307
|
VPSHUFD $7, (R11), X2 // c4c179701307
|
||||||
//TODO: VPSHUFD $7, X2, X2 // c4e17970d207 or c5f970d207
|
VPSHUFD $7, X2, X2 // c4e17970d207 or c5f970d207
|
||||||
//TODO: VPSHUFD $7, X11, X2 // c4c17970d307
|
VPSHUFD $7, X11, X2 // c4c17970d307
|
||||||
//TODO: VPSHUFD $7, (BX), X11 // c46179701b07 or c579701b07
|
VPSHUFD $7, (BX), X11 // c46179701b07 or c579701b07
|
||||||
//TODO: VPSHUFD $7, (R11), X11 // c44179701b07
|
VPSHUFD $7, (R11), X11 // c44179701b07
|
||||||
//TODO: VPSHUFD $7, X2, X11 // c4617970da07 or c57970da07
|
VPSHUFD $7, X2, X11 // c4617970da07 or c57970da07
|
||||||
//TODO: VPSHUFD $7, X11, X11 // c4417970db07
|
VPSHUFD $7, X11, X11 // c4417970db07
|
||||||
//TODO: VPSHUFD $7, (BX), Y2 // c4e17d701307 or c5fd701307
|
VPSHUFD $7, (BX), Y2 // c4e17d701307 or c5fd701307
|
||||||
//TODO: VPSHUFD $7, (R11), Y2 // c4c17d701307
|
VPSHUFD $7, (R11), Y2 // c4c17d701307
|
||||||
//TODO: VPSHUFD $7, Y2, Y2 // c4e17d70d207 or c5fd70d207
|
VPSHUFD $7, Y2, Y2 // c4e17d70d207 or c5fd70d207
|
||||||
//TODO: VPSHUFD $7, Y11, Y2 // c4c17d70d307
|
VPSHUFD $7, Y11, Y2 // c4c17d70d307
|
||||||
//TODO: VPSHUFD $7, (BX), Y11 // c4617d701b07 or c57d701b07
|
VPSHUFD $7, (BX), Y11 // c4617d701b07 or c57d701b07
|
||||||
//TODO: VPSHUFD $7, (R11), Y11 // c4417d701b07
|
VPSHUFD $7, (R11), Y11 // c4417d701b07
|
||||||
//TODO: VPSHUFD $7, Y2, Y11 // c4617d70da07 or c57d70da07
|
VPSHUFD $7, Y2, Y11 // c4617d70da07 or c57d70da07
|
||||||
//TODO: VPSHUFD $7, Y11, Y11 // c4417d70db07
|
VPSHUFD $7, Y11, Y11 // c4417d70db07
|
||||||
//TODO: VPSHUFHW $7, (BX), X2 // c4e17a701307 or c5fa701307
|
//TODO: VPSHUFHW $7, (BX), X2 // c4e17a701307 or c5fa701307
|
||||||
//TODO: VPSHUFHW $7, (R11), X2 // c4c17a701307
|
//TODO: VPSHUFHW $7, (R11), X2 // c4c17a701307
|
||||||
//TODO: VPSHUFHW $7, X2, X2 // c4e17a70d207 or c5fa70d207
|
//TODO: VPSHUFHW $7, X2, X2 // c4e17a70d207 or c5fa70d207
|
||||||
|
|
@ -9606,30 +9606,30 @@ TEXT asmtest(SB),7,$0
|
||||||
//TODO: VPSIGNW (R11), Y15, Y11 // c44205091b
|
//TODO: VPSIGNW (R11), Y15, Y11 // c44205091b
|
||||||
//TODO: VPSIGNW Y2, Y15, Y11 // c4620509da
|
//TODO: VPSIGNW Y2, Y15, Y11 // c4620509da
|
||||||
//TODO: VPSIGNW Y11, Y15, Y11 // c4420509db
|
//TODO: VPSIGNW Y11, Y15, Y11 // c4420509db
|
||||||
//TODO: VPSLLD (BX), X9, X2 // c4e131f213 or c5b1f213
|
VPSLLD (BX), X9, X2 // c4e131f213 or c5b1f213
|
||||||
//TODO: VPSLLD (R11), X9, X2 // c4c131f213
|
VPSLLD (R11), X9, X2 // c4c131f213
|
||||||
//TODO: VPSLLD X2, X9, X2 // c4e131f2d2 or c5b1f2d2
|
VPSLLD X2, X9, X2 // c4e131f2d2 or c5b1f2d2
|
||||||
//TODO: VPSLLD X11, X9, X2 // c4c131f2d3
|
VPSLLD X11, X9, X2 // c4c131f2d3
|
||||||
//TODO: VPSLLD (BX), X9, X11 // c46131f21b or c531f21b
|
VPSLLD (BX), X9, X11 // c46131f21b or c531f21b
|
||||||
//TODO: VPSLLD (R11), X9, X11 // c44131f21b
|
VPSLLD (R11), X9, X11 // c44131f21b
|
||||||
//TODO: VPSLLD X2, X9, X11 // c46131f2da or c531f2da
|
VPSLLD X2, X9, X11 // c46131f2da or c531f2da
|
||||||
//TODO: VPSLLD X11, X9, X11 // c44131f2db
|
VPSLLD X11, X9, X11 // c44131f2db
|
||||||
//TODO: VPSLLD $7, X2, X9 // c4e13172f207 or c5b172f207
|
VPSLLD $7, X2, X9 // c4e13172f207 or c5b172f207
|
||||||
//TODO: VPSLLD $7, X11, X9 // c4c13172f307
|
VPSLLD $7, X11, X9 // c4c13172f307
|
||||||
//TODO: VPSLLDQ $7, X2, X9 // c4e13173fa07 or c5b173fa07
|
VPSLLDQ $7, X2, X9 // c4e13173fa07 or c5b173fa07
|
||||||
//TODO: VPSLLDQ $7, X11, X9 // c4c13173fb07
|
VPSLLDQ $7, X11, X9 // c4c13173fb07
|
||||||
//TODO: VPSLLDQ $7, Y2, Y15 // c4e10573fa07 or c58573fa07
|
VPSLLDQ $7, Y2, Y15 // c4e10573fa07 or c58573fa07
|
||||||
//TODO: VPSLLDQ $7, Y11, Y15 // c4c10573fb07
|
VPSLLDQ $7, Y11, Y15 // c4c10573fb07
|
||||||
//TODO: VPSLLQ (BX), X9, X2 // c4e131f313 or c5b1f313
|
VPSLLQ (BX), X9, X2 // c4e131f313 or c5b1f313
|
||||||
//TODO: VPSLLQ (R11), X9, X2 // c4c131f313
|
VPSLLQ (R11), X9, X2 // c4c131f313
|
||||||
//TODO: VPSLLQ X2, X9, X2 // c4e131f3d2 or c5b1f3d2
|
VPSLLQ X2, X9, X2 // c4e131f3d2 or c5b1f3d2
|
||||||
//TODO: VPSLLQ X11, X9, X2 // c4c131f3d3
|
VPSLLQ X11, X9, X2 // c4c131f3d3
|
||||||
//TODO: VPSLLQ (BX), X9, X11 // c46131f31b or c531f31b
|
VPSLLQ (BX), X9, X11 // c46131f31b or c531f31b
|
||||||
//TODO: VPSLLQ (R11), X9, X11 // c44131f31b
|
VPSLLQ (R11), X9, X11 // c44131f31b
|
||||||
//TODO: VPSLLQ X2, X9, X11 // c46131f3da or c531f3da
|
VPSLLQ X2, X9, X11 // c46131f3da or c531f3da
|
||||||
//TODO: VPSLLQ X11, X9, X11 // c44131f3db
|
VPSLLQ X11, X9, X11 // c44131f3db
|
||||||
//TODO: VPSLLQ $7, X2, X9 // c4e13173f207 or c5b173f207
|
VPSLLQ $7, X2, X9 // c4e13173f207 or c5b173f207
|
||||||
//TODO: VPSLLQ $7, X11, X9 // c4c13173f307
|
VPSLLQ $7, X11, X9 // c4c13173f307
|
||||||
//TODO: VPSLLVD (BX), X9, X2 // c4e2314713
|
//TODO: VPSLLVD (BX), X9, X2 // c4e2314713
|
||||||
//TODO: VPSLLVD (R11), X9, X2 // c4c2314713
|
//TODO: VPSLLVD (R11), X9, X2 // c4c2314713
|
||||||
//TODO: VPSLLVD X2, X9, X2 // c4e23147d2
|
//TODO: VPSLLVD X2, X9, X2 // c4e23147d2
|
||||||
|
|
@ -9738,30 +9738,30 @@ TEXT asmtest(SB),7,$0
|
||||||
//TODO: VPSRAW X11, Y15, Y11 // c44105e1db
|
//TODO: VPSRAW X11, Y15, Y11 // c44105e1db
|
||||||
//TODO: VPSRAW $7, Y2, Y15 // c4e10571e207 or c58571e207
|
//TODO: VPSRAW $7, Y2, Y15 // c4e10571e207 or c58571e207
|
||||||
//TODO: VPSRAW $7, Y11, Y15 // c4c10571e307
|
//TODO: VPSRAW $7, Y11, Y15 // c4c10571e307
|
||||||
//TODO: VPSRLD (BX), X9, X2 // c4e131d213 or c5b1d213
|
VPSRLD (BX), X9, X2 // c4e131d213 or c5b1d213
|
||||||
//TODO: VPSRLD (R11), X9, X2 // c4c131d213
|
VPSRLD (R11), X9, X2 // c4c131d213
|
||||||
//TODO: VPSRLD X2, X9, X2 // c4e131d2d2 or c5b1d2d2
|
VPSRLD X2, X9, X2 // c4e131d2d2 or c5b1d2d2
|
||||||
//TODO: VPSRLD X11, X9, X2 // c4c131d2d3
|
VPSRLD X11, X9, X2 // c4c131d2d3
|
||||||
//TODO: VPSRLD (BX), X9, X11 // c46131d21b or c531d21b
|
VPSRLD (BX), X9, X11 // c46131d21b or c531d21b
|
||||||
//TODO: VPSRLD (R11), X9, X11 // c44131d21b
|
VPSRLD (R11), X9, X11 // c44131d21b
|
||||||
//TODO: VPSRLD X2, X9, X11 // c46131d2da or c531d2da
|
VPSRLD X2, X9, X11 // c46131d2da or c531d2da
|
||||||
//TODO: VPSRLD X11, X9, X11 // c44131d2db
|
VPSRLD X11, X9, X11 // c44131d2db
|
||||||
//TODO: VPSRLD $7, X2, X9 // c4e13172d207 or c5b172d207
|
VPSRLD $7, X2, X9 // c4e13172d207 or c5b172d207
|
||||||
//TODO: VPSRLD $7, X11, X9 // c4c13172d307
|
VPSRLD $7, X11, X9 // c4c13172d307
|
||||||
//TODO: VPSRLDQ $7, X2, X9 // c4e13173da07 or c5b173da07
|
VPSRLDQ $7, X2, X9 // c4e13173da07 or c5b173da07
|
||||||
//TODO: VPSRLDQ $7, X11, X9 // c4c13173db07
|
VPSRLDQ $7, X11, X9 // c4c13173db07
|
||||||
//TODO: VPSRLDQ $7, Y2, Y15 // c4e10573da07 or c58573da07
|
VPSRLDQ $7, Y2, Y15 // c4e10573da07 or c58573da07
|
||||||
//TODO: VPSRLDQ $7, Y11, Y15 // c4c10573db07
|
VPSRLDQ $7, Y11, Y15 // c4c10573db07
|
||||||
//TODO: VPSRLQ (BX), X9, X2 // c4e131d313 or c5b1d313
|
VPSRLQ (BX), X9, X2 // c4e131d313 or c5b1d313
|
||||||
//TODO: VPSRLQ (R11), X9, X2 // c4c131d313
|
VPSRLQ (R11), X9, X2 // c4c131d313
|
||||||
//TODO: VPSRLQ X2, X9, X2 // c4e131d3d2 or c5b1d3d2
|
VPSRLQ X2, X9, X2 // c4e131d3d2 or c5b1d3d2
|
||||||
//TODO: VPSRLQ X11, X9, X2 // c4c131d3d3
|
VPSRLQ X11, X9, X2 // c4c131d3d3
|
||||||
//TODO: VPSRLQ (BX), X9, X11 // c46131d31b or c531d31b
|
VPSRLQ (BX), X9, X11 // c46131d31b or c531d31b
|
||||||
//TODO: VPSRLQ (R11), X9, X11 // c44131d31b
|
VPSRLQ (R11), X9, X11 // c44131d31b
|
||||||
//TODO: VPSRLQ X2, X9, X11 // c46131d3da or c531d3da
|
VPSRLQ X2, X9, X11 // c46131d3da or c531d3da
|
||||||
//TODO: VPSRLQ X11, X9, X11 // c44131d3db
|
VPSRLQ X11, X9, X11 // c44131d3db
|
||||||
//TODO: VPSRLQ $7, X2, X9 // c4e13173d207 or c5b173d207
|
VPSRLQ $7, X2, X9 // c4e13173d207 or c5b173d207
|
||||||
//TODO: VPSRLQ $7, X11, X9 // c4c13173d307
|
VPSRLQ $7, X11, X9 // c4c13173d307
|
||||||
//TODO: VPSRLVD (BX), X9, X2 // c4e2314513
|
//TODO: VPSRLVD (BX), X9, X2 // c4e2314513
|
||||||
//TODO: VPSRLVD (R11), X9, X2 // c4c2314513
|
//TODO: VPSRLVD (R11), X9, X2 // c4c2314513
|
||||||
//TODO: VPSRLVD X2, X9, X2 // c4e23145d2
|
//TODO: VPSRLVD X2, X9, X2 // c4e23145d2
|
||||||
|
|
|
||||||
|
|
@ -1089,6 +1089,8 @@ func (p *Package) gccMachine() []string {
|
||||||
return []string{"-m31"}
|
return []string{"-m31"}
|
||||||
case "s390x":
|
case "s390x":
|
||||||
return []string{"-m64"}
|
return []string{"-m64"}
|
||||||
|
case "mips64", "mips64le":
|
||||||
|
return []string{"-mabi=64"}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -1241,12 +1243,20 @@ func (p *Package) gccErrors(stdin []byte) string {
|
||||||
// TODO(rsc): require failure
|
// TODO(rsc): require failure
|
||||||
args := p.gccCmd()
|
args := p.gccCmd()
|
||||||
|
|
||||||
|
// Optimization options can confuse the error messages; remove them.
|
||||||
|
nargs := make([]string, 0, len(args))
|
||||||
|
for _, arg := range args {
|
||||||
|
if !strings.HasPrefix(arg, "-O") {
|
||||||
|
nargs = append(nargs, arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if *debugGcc {
|
if *debugGcc {
|
||||||
fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " "))
|
fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(nargs, " "))
|
||||||
os.Stderr.Write(stdin)
|
os.Stderr.Write(stdin)
|
||||||
fmt.Fprint(os.Stderr, "EOF\n")
|
fmt.Fprint(os.Stderr, "EOF\n")
|
||||||
}
|
}
|
||||||
stdout, stderr, _ := run(stdin, args)
|
stdout, stderr, _ := run(stdin, nargs)
|
||||||
if *debugGcc {
|
if *debugGcc {
|
||||||
os.Stderr.Write(stdout)
|
os.Stderr.Write(stdout)
|
||||||
os.Stderr.Write(stderr)
|
os.Stderr.Write(stderr)
|
||||||
|
|
|
||||||
|
|
@ -175,10 +175,11 @@ func (p *Package) writeDefs() {
|
||||||
}
|
}
|
||||||
fmt.Fprintf(fgo2, "\n")
|
fmt.Fprintf(fgo2, "\n")
|
||||||
|
|
||||||
|
callsMalloc := false
|
||||||
for _, key := range nameKeys(p.Name) {
|
for _, key := range nameKeys(p.Name) {
|
||||||
n := p.Name[key]
|
n := p.Name[key]
|
||||||
if n.FuncType != nil {
|
if n.FuncType != nil {
|
||||||
p.writeDefsFunc(fgo2, n)
|
p.writeDefsFunc(fgo2, n, &callsMalloc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -189,6 +190,12 @@ func (p *Package) writeDefs() {
|
||||||
} else {
|
} else {
|
||||||
p.writeExports(fgo2, fm, fgcc, fgcch)
|
p.writeExports(fgo2, fm, fgcc, fgcch)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if callsMalloc && !*gccgo {
|
||||||
|
fmt.Fprint(fgo2, strings.Replace(cMallocDefGo, "PREFIX", cPrefix, -1))
|
||||||
|
fmt.Fprint(fgcc, strings.Replace(strings.Replace(cMallocDefC, "PREFIX", cPrefix, -1), "PACKED", p.packedAttribute(), -1))
|
||||||
|
}
|
||||||
|
|
||||||
if err := fgcc.Close(); err != nil {
|
if err := fgcc.Close(); err != nil {
|
||||||
fatalf("%s", err)
|
fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
|
@ -352,7 +359,7 @@ func (p *Package) structType(n *Name) (string, int64) {
|
||||||
return buf.String(), off
|
return buf.String(), off
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name) {
|
func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name, callsMalloc *bool) {
|
||||||
name := n.Go
|
name := n.Go
|
||||||
gtype := n.FuncType.Go
|
gtype := n.FuncType.Go
|
||||||
void := gtype.Results == nil || len(gtype.Results.List) == 0
|
void := gtype.Results == nil || len(gtype.Results.List) == 0
|
||||||
|
|
@ -441,6 +448,9 @@ func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name) {
|
||||||
|
|
||||||
if inProlog {
|
if inProlog {
|
||||||
fmt.Fprint(fgo2, builtinDefs[name])
|
fmt.Fprint(fgo2, builtinDefs[name])
|
||||||
|
if strings.Contains(builtinDefs[name], "_cgo_cmalloc") {
|
||||||
|
*callsMalloc = true
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -560,6 +570,7 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
|
||||||
|
|
||||||
// Gcc wrapper unpacks the C argument struct
|
// Gcc wrapper unpacks the C argument struct
|
||||||
// and calls the actual C function.
|
// and calls the actual C function.
|
||||||
|
fmt.Fprintf(fgcc, "CGO_NO_SANITIZE_THREAD\n")
|
||||||
if n.AddError {
|
if n.AddError {
|
||||||
fmt.Fprintf(fgcc, "int\n")
|
fmt.Fprintf(fgcc, "int\n")
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -635,6 +646,7 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
|
||||||
// wrapper, we can't refer to the function, since the reference is in
|
// wrapper, we can't refer to the function, since the reference is in
|
||||||
// a different file.
|
// a different file.
|
||||||
func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) {
|
func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) {
|
||||||
|
fmt.Fprintf(fgcc, "CGO_NO_SANITIZE_THREAD\n")
|
||||||
if t := n.FuncType.Result; t != nil {
|
if t := n.FuncType.Result; t != nil {
|
||||||
fmt.Fprintf(fgcc, "%s\n", t.C.String())
|
fmt.Fprintf(fgcc, "%s\n", t.C.String())
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -710,11 +722,13 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||||
p.writeExportHeader(fgcch)
|
p.writeExportHeader(fgcch)
|
||||||
|
|
||||||
fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n")
|
fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n")
|
||||||
|
fmt.Fprintf(fgcc, "#include <stdlib.h>\n")
|
||||||
fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n\n")
|
fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n\n")
|
||||||
|
|
||||||
fmt.Fprintf(fgcc, "extern void crosscall2(void (*fn)(void *, int, __SIZE_TYPE__), void *, int, __SIZE_TYPE__);\n")
|
fmt.Fprintf(fgcc, "extern void crosscall2(void (*fn)(void *, int, __SIZE_TYPE__), void *, int, __SIZE_TYPE__);\n")
|
||||||
fmt.Fprintf(fgcc, "extern __SIZE_TYPE__ _cgo_wait_runtime_init_done();\n")
|
fmt.Fprintf(fgcc, "extern __SIZE_TYPE__ _cgo_wait_runtime_init_done();\n")
|
||||||
fmt.Fprintf(fgcc, "extern void _cgo_release_context(__SIZE_TYPE__);\n\n")
|
fmt.Fprintf(fgcc, "extern void _cgo_release_context(__SIZE_TYPE__);\n\n")
|
||||||
|
fmt.Fprintf(fgcc, "extern char* _cgo_topofstack(void);")
|
||||||
fmt.Fprintf(fgcc, "%s\n", tsanProlog)
|
fmt.Fprintf(fgcc, "%s\n", tsanProlog)
|
||||||
|
|
||||||
for _, exp := range p.ExpFunc {
|
for _, exp := range p.ExpFunc {
|
||||||
|
|
@ -817,6 +831,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||||
fmt.Fprintf(fgcch, "\nextern %s;\n", s)
|
fmt.Fprintf(fgcch, "\nextern %s;\n", s)
|
||||||
|
|
||||||
fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *, int, __SIZE_TYPE__);\n", cPrefix, exp.ExpName)
|
fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *, int, __SIZE_TYPE__);\n", cPrefix, exp.ExpName)
|
||||||
|
fmt.Fprintf(fgcc, "\nCGO_NO_SANITIZE_THREAD")
|
||||||
fmt.Fprintf(fgcc, "\n%s\n", s)
|
fmt.Fprintf(fgcc, "\n%s\n", s)
|
||||||
fmt.Fprintf(fgcc, "{\n")
|
fmt.Fprintf(fgcc, "{\n")
|
||||||
fmt.Fprintf(fgcc, "\t__SIZE_TYPE__ _cgo_ctxt = _cgo_wait_runtime_init_done();\n")
|
fmt.Fprintf(fgcc, "\t__SIZE_TYPE__ _cgo_ctxt = _cgo_wait_runtime_init_done();\n")
|
||||||
|
|
@ -1020,7 +1035,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||||
fmt.Fprintf(fgcc, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, goName)
|
fmt.Fprintf(fgcc, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, goName)
|
||||||
fmt.Fprint(fgcc, "\n")
|
fmt.Fprint(fgcc, "\n")
|
||||||
|
|
||||||
fmt.Fprint(fgcc, "\n")
|
fmt.Fprint(fgcc, "\nCGO_NO_SANITIZE_THREAD\n")
|
||||||
fmt.Fprintf(fgcc, "%s %s %s {\n", cRet, exp.ExpName, cParams)
|
fmt.Fprintf(fgcc, "%s %s %s {\n", cRet, exp.ExpName, cParams)
|
||||||
if resultCount > 0 {
|
if resultCount > 0 {
|
||||||
fmt.Fprintf(fgcc, "\t%s r;\n", cRet)
|
fmt.Fprintf(fgcc, "\t%s r;\n", cRet)
|
||||||
|
|
@ -1304,11 +1319,14 @@ extern char* _cgo_topofstack(void);
|
||||||
|
|
||||||
// Prologue defining TSAN functions in C.
|
// Prologue defining TSAN functions in C.
|
||||||
const noTsanProlog = `
|
const noTsanProlog = `
|
||||||
|
#define CGO_NO_SANITIZE_THREAD
|
||||||
#define _cgo_tsan_acquire()
|
#define _cgo_tsan_acquire()
|
||||||
#define _cgo_tsan_release()
|
#define _cgo_tsan_release()
|
||||||
`
|
`
|
||||||
|
|
||||||
const yesTsanProlog = `
|
const yesTsanProlog = `
|
||||||
|
#define CGO_NO_SANITIZE_THREAD __attribute__ ((no_sanitize_thread))
|
||||||
|
|
||||||
long long _cgo_sync __attribute__ ((common));
|
long long _cgo_sync __attribute__ ((common));
|
||||||
|
|
||||||
extern void __tsan_acquire(void*);
|
extern void __tsan_acquire(void*);
|
||||||
|
|
@ -1346,9 +1364,6 @@ const goProlog = `
|
||||||
//go:linkname _cgo_runtime_cgocall runtime.cgocall
|
//go:linkname _cgo_runtime_cgocall runtime.cgocall
|
||||||
func _cgo_runtime_cgocall(unsafe.Pointer, uintptr) int32
|
func _cgo_runtime_cgocall(unsafe.Pointer, uintptr) int32
|
||||||
|
|
||||||
//go:linkname _cgo_runtime_cmalloc runtime.cmalloc
|
|
||||||
func _cgo_runtime_cmalloc(uintptr) unsafe.Pointer
|
|
||||||
|
|
||||||
//go:linkname _cgo_runtime_cgocallback runtime.cgocallback
|
//go:linkname _cgo_runtime_cgocallback runtime.cgocallback
|
||||||
func _cgo_runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr, uintptr)
|
func _cgo_runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr, uintptr)
|
||||||
|
|
||||||
|
|
@ -1360,10 +1375,8 @@ func _cgoCheckResult(interface{})
|
||||||
`
|
`
|
||||||
|
|
||||||
const gccgoGoProlog = `
|
const gccgoGoProlog = `
|
||||||
//extern runtime.cgoCheckPointer
|
|
||||||
func _cgoCheckPointer(interface{}, ...interface{}) interface{}
|
func _cgoCheckPointer(interface{}, ...interface{}) interface{}
|
||||||
|
|
||||||
//extern runtime.cgoCheckResult
|
|
||||||
func _cgoCheckResult(interface{})
|
func _cgoCheckResult(interface{})
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
@ -1396,7 +1409,7 @@ func _Cfunc_GoBytes(p unsafe.Pointer, l _Ctype_int) []byte {
|
||||||
|
|
||||||
const cStringDef = `
|
const cStringDef = `
|
||||||
func _Cfunc_CString(s string) *_Ctype_char {
|
func _Cfunc_CString(s string) *_Ctype_char {
|
||||||
p := _cgo_runtime_cmalloc(uintptr(len(s)+1))
|
p := _cgo_cmalloc(uint64(len(s)+1))
|
||||||
pp := (*[1<<30]byte)(p)
|
pp := (*[1<<30]byte)(p)
|
||||||
copy(pp[:], s)
|
copy(pp[:], s)
|
||||||
pp[len(s)] = 0
|
pp[len(s)] = 0
|
||||||
|
|
@ -1406,7 +1419,7 @@ func _Cfunc_CString(s string) *_Ctype_char {
|
||||||
|
|
||||||
const cBytesDef = `
|
const cBytesDef = `
|
||||||
func _Cfunc_CBytes(b []byte) unsafe.Pointer {
|
func _Cfunc_CBytes(b []byte) unsafe.Pointer {
|
||||||
p := _cgo_runtime_cmalloc(uintptr(len(b)))
|
p := _cgo_cmalloc(uint64(len(b)))
|
||||||
pp := (*[1<<30]byte)(p)
|
pp := (*[1<<30]byte)(p)
|
||||||
copy(pp[:], b)
|
copy(pp[:], b)
|
||||||
return p
|
return p
|
||||||
|
|
@ -1415,7 +1428,7 @@ func _Cfunc_CBytes(b []byte) unsafe.Pointer {
|
||||||
|
|
||||||
const cMallocDef = `
|
const cMallocDef = `
|
||||||
func _Cfunc__CMalloc(n _Ctype_size_t) unsafe.Pointer {
|
func _Cfunc__CMalloc(n _Ctype_size_t) unsafe.Pointer {
|
||||||
return _cgo_runtime_cmalloc(uintptr(n))
|
return _cgo_cmalloc(uint64(n))
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
@ -1428,6 +1441,50 @@ var builtinDefs = map[string]string{
|
||||||
"_CMalloc": cMallocDef,
|
"_CMalloc": cMallocDef,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Definitions for C.malloc in Go and in C. We define it ourselves
|
||||||
|
// since we call it from functions we define, such as C.CString.
|
||||||
|
// Also, we have historically ensured that C.malloc does not return
|
||||||
|
// nil even for an allocation of 0.
|
||||||
|
|
||||||
|
const cMallocDefGo = `
|
||||||
|
//go:cgo_import_static _cgoPREFIX_Cfunc__Cmalloc
|
||||||
|
//go:linkname __cgofn__cgoPREFIX_Cfunc__Cmalloc _cgoPREFIX_Cfunc__Cmalloc
|
||||||
|
var __cgofn__cgoPREFIX_Cfunc__Cmalloc byte
|
||||||
|
var _cgoPREFIX_Cfunc__Cmalloc = unsafe.Pointer(&__cgofn__cgoPREFIX_Cfunc__Cmalloc)
|
||||||
|
|
||||||
|
//go:cgo_unsafe_args
|
||||||
|
func _cgo_cmalloc(p0 uint64) (r1 unsafe.Pointer) {
|
||||||
|
_cgo_runtime_cgocall(_cgoPREFIX_Cfunc__Cmalloc, uintptr(unsafe.Pointer(&p0)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
// cMallocDefC defines the C version of C.malloc for the gc compiler.
|
||||||
|
// It is defined here because C.CString and friends need a definition.
|
||||||
|
// We define it by hand, rather than simply inventing a reference to
|
||||||
|
// C.malloc, because <stdlib.h> may not have been included.
|
||||||
|
// This is approximately what writeOutputFunc would generate, but
|
||||||
|
// skips the cgo_topofstack code (which is only needed if the C code
|
||||||
|
// calls back into Go). This also avoids returning nil for an
|
||||||
|
// allocation of 0 bytes.
|
||||||
|
const cMallocDefC = `
|
||||||
|
CGO_NO_SANITIZE_THREAD
|
||||||
|
void _cgoPREFIX_Cfunc__Cmalloc(void *v) {
|
||||||
|
struct {
|
||||||
|
unsigned long long p0;
|
||||||
|
void *r1;
|
||||||
|
} PACKED *a = v;
|
||||||
|
void *ret;
|
||||||
|
_cgo_tsan_acquire();
|
||||||
|
ret = malloc(a->p0);
|
||||||
|
if (ret == 0 && a->p0 == 0) {
|
||||||
|
ret = malloc(1);
|
||||||
|
}
|
||||||
|
a->r1 = ret;
|
||||||
|
_cgo_tsan_release();
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
func (p *Package) cPrologGccgo() string {
|
func (p *Package) cPrologGccgo() string {
|
||||||
return strings.Replace(strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1),
|
return strings.Replace(strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1),
|
||||||
"GCCGOSYMBOLPREF", p.gccgoSymbolPrefix(), -1)
|
"GCCGOSYMBOLPREF", p.gccgoSymbolPrefix(), -1)
|
||||||
|
|
|
||||||
|
|
@ -60,8 +60,15 @@ Flags:
|
||||||
-installsuffix suffix
|
-installsuffix suffix
|
||||||
Look for packages in $GOROOT/pkg/$GOOS_$GOARCH_suffix
|
Look for packages in $GOROOT/pkg/$GOOS_$GOARCH_suffix
|
||||||
instead of $GOROOT/pkg/$GOOS_$GOARCH.
|
instead of $GOROOT/pkg/$GOOS_$GOARCH.
|
||||||
|
-l
|
||||||
|
Disable inlining.
|
||||||
-largemodel
|
-largemodel
|
||||||
Generated code that assumes a large memory model.
|
Generate code that assumes a large memory model.
|
||||||
|
-linkobj file
|
||||||
|
Write linker-specific object to file and compiler-specific
|
||||||
|
object to usual output file (as specified by -o).
|
||||||
|
Without this flag, the -o output is a combination of both
|
||||||
|
linker and compiler input.
|
||||||
-memprofile file
|
-memprofile file
|
||||||
Write memory profile for the compilation to file.
|
Write memory profile for the compilation to file.
|
||||||
-memprofilerate rate
|
-memprofilerate rate
|
||||||
|
|
|
||||||
|
|
@ -25,18 +25,16 @@ func betypeinit() {
|
||||||
cmpptr = x86.ACMPL
|
cmpptr = x86.ACMPL
|
||||||
}
|
}
|
||||||
|
|
||||||
if gc.Ctxt.Flag_dynlink {
|
if gc.Ctxt.Flag_dynlink || obj.Getgoos() == "nacl" {
|
||||||
gc.Thearch.ReservedRegs = append(gc.Thearch.ReservedRegs, x86.REG_R15)
|
resvd = append(resvd, x86.REG_R15)
|
||||||
}
|
}
|
||||||
|
if gc.Ctxt.Framepointer_enabled || obj.Getgoos() == "nacl" {
|
||||||
|
resvd = append(resvd, x86.REG_BP)
|
||||||
|
}
|
||||||
|
gc.Thearch.ReservedRegs = resvd
|
||||||
}
|
}
|
||||||
|
|
||||||
func Main() {
|
func Main() {
|
||||||
if obj.Getgoos() == "nacl" {
|
|
||||||
resvd = append(resvd, x86.REG_BP, x86.REG_R15)
|
|
||||||
} else if obj.Framepointer_enabled != 0 {
|
|
||||||
resvd = append(resvd, x86.REG_BP)
|
|
||||||
}
|
|
||||||
|
|
||||||
gc.Thearch.LinkArch = &x86.Linkamd64
|
gc.Thearch.LinkArch = &x86.Linkamd64
|
||||||
if obj.Getgoarch() == "amd64p32" {
|
if obj.Getgoarch() == "amd64p32" {
|
||||||
gc.Thearch.LinkArch = &x86.Linkamd64p32
|
gc.Thearch.LinkArch = &x86.Linkamd64p32
|
||||||
|
|
@ -51,7 +49,6 @@ func Main() {
|
||||||
gc.Thearch.FREGMIN = x86.REG_X0
|
gc.Thearch.FREGMIN = x86.REG_X0
|
||||||
gc.Thearch.FREGMAX = x86.REG_X15
|
gc.Thearch.FREGMAX = x86.REG_X15
|
||||||
gc.Thearch.MAXWIDTH = 1 << 50
|
gc.Thearch.MAXWIDTH = 1 << 50
|
||||||
gc.Thearch.ReservedRegs = resvd
|
|
||||||
|
|
||||||
gc.Thearch.AddIndex = addindex
|
gc.Thearch.AddIndex = addindex
|
||||||
gc.Thearch.Betypeinit = betypeinit
|
gc.Thearch.Betypeinit = betypeinit
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,7 @@ func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
|
||||||
base = n1.Left
|
base = n1.Left
|
||||||
}
|
}
|
||||||
|
|
||||||
if base.Op == gc.ONAME && base.Class&gc.PHEAP == 0 || n1.Op == gc.OINDREG {
|
if base.Op == gc.ONAME && base.Class != gc.PAUTOHEAP || n1.Op == gc.OINDREG {
|
||||||
r1 = *n1
|
r1 = *n1
|
||||||
} else {
|
} else {
|
||||||
gc.Regalloc(&r1, t, n1)
|
gc.Regalloc(&r1, t, n1)
|
||||||
|
|
@ -229,6 +229,8 @@ func gmove(f *gc.Node, t *gc.Node) {
|
||||||
|
|
||||||
switch uint32(ft)<<16 | uint32(tt) {
|
switch uint32(ft)<<16 | uint32(tt) {
|
||||||
default:
|
default:
|
||||||
|
gc.Dump("f", f)
|
||||||
|
gc.Dump("t", t)
|
||||||
gc.Fatalf("gmove %v -> %v", gc.Tconv(f.Type, gc.FmtLong), gc.Tconv(t.Type, gc.FmtLong))
|
gc.Fatalf("gmove %v -> %v", gc.Tconv(f.Type, gc.FmtLong), gc.Tconv(t.Type, gc.FmtLong))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@ package amd64
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"cmd/compile/internal/gc"
|
"cmd/compile/internal/gc"
|
||||||
"cmd/internal/obj"
|
|
||||||
"cmd/internal/obj/x86"
|
"cmd/internal/obj/x86"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -121,7 +120,7 @@ func BtoR(b uint64) int {
|
||||||
b &= 0xffff
|
b &= 0xffff
|
||||||
if gc.Nacl {
|
if gc.Nacl {
|
||||||
b &^= (1<<(x86.REG_BP-x86.REG_AX) | 1<<(x86.REG_R15-x86.REG_AX))
|
b &^= (1<<(x86.REG_BP-x86.REG_AX) | 1<<(x86.REG_R15-x86.REG_AX))
|
||||||
} else if obj.Framepointer_enabled != 0 {
|
} else if gc.Ctxt.Framepointer_enabled {
|
||||||
// BP is part of the calling convention if framepointer_enabled.
|
// BP is part of the calling convention if framepointer_enabled.
|
||||||
b &^= (1 << (x86.REG_BP - x86.REG_AX))
|
b &^= (1 << (x86.REG_BP - x86.REG_AX))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -878,6 +878,18 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||||
gc.Gvarkill(v.Aux.(*gc.Node))
|
gc.Gvarkill(v.Aux.(*gc.Node))
|
||||||
case ssa.OpVarLive:
|
case ssa.OpVarLive:
|
||||||
gc.Gvarlive(v.Aux.(*gc.Node))
|
gc.Gvarlive(v.Aux.(*gc.Node))
|
||||||
|
case ssa.OpKeepAlive:
|
||||||
|
if !v.Args[0].Type.IsPtrShaped() {
|
||||||
|
v.Fatalf("keeping non-pointer alive %v", v.Args[0])
|
||||||
|
}
|
||||||
|
n, off := gc.AutoVar(v.Args[0])
|
||||||
|
if n == nil {
|
||||||
|
v.Fatalf("KeepLive with non-spilled value %s %s", v, v.Args[0])
|
||||||
|
}
|
||||||
|
if off != 0 {
|
||||||
|
v.Fatalf("KeepLive with non-zero offset spill location %s:%d", n, off)
|
||||||
|
}
|
||||||
|
gc.Gvarlive(n)
|
||||||
case ssa.OpAMD64LoweredNilCheck:
|
case ssa.OpAMD64LoweredNilCheck:
|
||||||
// Optimization - if the subsequent block has a load or store
|
// Optimization - if the subsequent block has a load or store
|
||||||
// at the same address, we don't need to issue this instruction.
|
// at the same address, we don't need to issue this instruction.
|
||||||
|
|
|
||||||
|
|
@ -86,17 +86,8 @@ func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) {
|
||||||
|
|
||||||
n = &n1
|
n = &n1
|
||||||
|
|
||||||
case gc.ONAME:
|
case gc.ONAME, gc.OINDREG:
|
||||||
if n.Class == gc.PPARAMREF {
|
|
||||||
var n1 gc.Node
|
|
||||||
gc.Cgen(n.Name.Heapaddr, &n1)
|
|
||||||
sclean[nsclean-1] = n1
|
|
||||||
n = &n1
|
|
||||||
}
|
|
||||||
|
|
||||||
// nothing
|
// nothing
|
||||||
case gc.OINDREG:
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*lo = *n
|
*lo = *n
|
||||||
|
|
|
||||||
|
|
@ -55,12 +55,15 @@ func widstruct(errtype *Type, t *Type, o int64, flag int) int64 {
|
||||||
}
|
}
|
||||||
f.Offset = o
|
f.Offset = o
|
||||||
if f.Nname != nil {
|
if f.Nname != nil {
|
||||||
// this same stackparam logic is in addrescapes
|
// addrescapes has similar code to update these offsets.
|
||||||
// in typecheck.go. usually addrescapes runs after
|
// Usually addrescapes runs after widstruct,
|
||||||
// widstruct, in which case we could drop this,
|
// in which case we could drop this,
|
||||||
// but function closure functions are the exception.
|
// but function closure functions are the exception.
|
||||||
if f.Nname.Name.Param.Stackparam != nil {
|
// NOTE(rsc): This comment may be stale.
|
||||||
f.Nname.Name.Param.Stackparam.Xoffset = o
|
// It's possible the ordering has changed and this is
|
||||||
|
// now the common case. I'm not sure.
|
||||||
|
if f.Nname.Name.Param.Stackcopy != nil {
|
||||||
|
f.Nname.Name.Param.Stackcopy.Xoffset = o
|
||||||
f.Nname.Xoffset = 0
|
f.Nname.Xoffset = 0
|
||||||
} else {
|
} else {
|
||||||
f.Nname.Xoffset = o
|
f.Nname.Xoffset = o
|
||||||
|
|
|
||||||
105
src/cmd/compile/internal/gc/asm_test.go
Normal file
105
src/cmd/compile/internal/gc/asm_test.go
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
// Copyright 2016 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 gc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"internal/testenv"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestAssembly checks to make sure the assembly generated for
|
||||||
|
// functions contains certain expected instructions.
|
||||||
|
// Note: this test will fail if -ssa=0.
|
||||||
|
func TestAssembly(t *testing.T) {
|
||||||
|
testenv.MustHaveGoBuild(t)
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
// TODO: remove if we can get "go tool compile -S" to work on windows.
|
||||||
|
t.Skipf("skipping test: recursive windows compile not working")
|
||||||
|
}
|
||||||
|
dir, err := ioutil.TempDir("", "TestAssembly")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not create directory: %v", err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
|
for _, test := range asmTests {
|
||||||
|
asm := compileToAsm(dir, test.arch, fmt.Sprintf(template, test.function))
|
||||||
|
// Get rid of code for "".init. Also gets rid of type algorithms & other junk.
|
||||||
|
if i := strings.Index(asm, "\n\"\".init "); i >= 0 {
|
||||||
|
asm = asm[:i+1]
|
||||||
|
}
|
||||||
|
for _, r := range test.regexps {
|
||||||
|
if b, err := regexp.MatchString(r, asm); !b || err != nil {
|
||||||
|
t.Errorf("expected:%s\ngo:%s\nasm:%s\n", r, test.function, asm)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// compile compiles the package pkg for architecture arch and
|
||||||
|
// returns the generated assembly. dir is a scratch directory.
|
||||||
|
func compileToAsm(dir, arch, pkg string) string {
|
||||||
|
// Create source.
|
||||||
|
src := filepath.Join(dir, "test.go")
|
||||||
|
f, err := os.Create(src)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
f.Write([]byte(pkg))
|
||||||
|
f.Close()
|
||||||
|
|
||||||
|
var stdout, stderr bytes.Buffer
|
||||||
|
cmd := exec.Command("go", "tool", "compile", "-S", "-o", filepath.Join(dir, "out.o"), src)
|
||||||
|
cmd.Env = append(cmd.Env, "GOARCH="+arch)
|
||||||
|
cmd.Stdout = &stdout
|
||||||
|
cmd.Stderr = &stderr
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if s := stderr.String(); s != "" {
|
||||||
|
panic(fmt.Errorf("Stderr = %s\nWant empty", s))
|
||||||
|
}
|
||||||
|
return stdout.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// template to convert a function to a full file
|
||||||
|
const template = `
|
||||||
|
package main
|
||||||
|
%s
|
||||||
|
`
|
||||||
|
|
||||||
|
type asmTest struct {
|
||||||
|
// architecture to compile to
|
||||||
|
arch string
|
||||||
|
// function to compile
|
||||||
|
function string
|
||||||
|
// regexps that must match the generated assembly
|
||||||
|
regexps []string
|
||||||
|
}
|
||||||
|
|
||||||
|
var asmTests = [...]asmTest{
|
||||||
|
{"amd64", `
|
||||||
|
func f(x int) int {
|
||||||
|
return x * 64
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
[]string{"\tSHLQ\t\\$6,"},
|
||||||
|
},
|
||||||
|
{"amd64", `
|
||||||
|
func f(x int) int {
|
||||||
|
return x * 96
|
||||||
|
}`,
|
||||||
|
[]string{"\tSHLQ\t\\$5,", "\tLEAQ\t\\(.*\\)\\(.*\\*2\\),"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
// (see fmt.go, parser.go as "documentation" for how to use/setup data structures)
|
// (see fmt.go, parser.go as "documentation" for how to use/setup data structures)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Export data encoding:
|
1) Export data encoding principles:
|
||||||
|
|
||||||
The export data is a serialized description of the graph of exported
|
The export data is a serialized description of the graph of exported
|
||||||
"objects": constants, types, variables, and functions. In general,
|
"objects": constants, types, variables, and functions. In general,
|
||||||
|
|
@ -49,7 +49,7 @@ Before exporting or importing, the type tables are populated with the
|
||||||
predeclared types (int, string, error, unsafe.Pointer, etc.). This way
|
predeclared types (int, string, error, unsafe.Pointer, etc.). This way
|
||||||
they are automatically encoded with a known and fixed type index.
|
they are automatically encoded with a known and fixed type index.
|
||||||
|
|
||||||
Encoding format:
|
2) Encoding format:
|
||||||
|
|
||||||
The export data starts with a single byte indicating the encoding format
|
The export data starts with a single byte indicating the encoding format
|
||||||
(compact, or with debugging information), followed by a version string
|
(compact, or with debugging information), followed by a version string
|
||||||
|
|
@ -84,6 +84,43 @@ each encoding routine there is a matching and symmetric decoding routine.
|
||||||
This symmetry makes it very easy to change or extend the format: If a new
|
This symmetry makes it very easy to change or extend the format: If a new
|
||||||
field needs to be encoded, a symmetric change can be made to exporter and
|
field needs to be encoded, a symmetric change can be made to exporter and
|
||||||
importer.
|
importer.
|
||||||
|
|
||||||
|
3) Making changes to the encoding format:
|
||||||
|
|
||||||
|
Any change to the encoding format requires a respective change in the
|
||||||
|
exporter below and a corresponding symmetric change to the importer in
|
||||||
|
bimport.go.
|
||||||
|
|
||||||
|
Furthermore, it requires a corresponding change to go/internal/gcimporter
|
||||||
|
and golang.org/x/tools/go/gcimporter15. Changes to the latter must preserve
|
||||||
|
compatibility with both the last release of the compiler, and with the
|
||||||
|
corresponding compiler at tip. That change is necessarily more involved,
|
||||||
|
as it must switch based on the version number in the export data file.
|
||||||
|
|
||||||
|
It is recommended to turn on debugFormat when working on format changes
|
||||||
|
as it will help finding encoding/decoding inconsistencies quickly.
|
||||||
|
|
||||||
|
Special care must be taken to update builtin.go when the export format
|
||||||
|
changes: builtin.go contains the export data obtained by compiling the
|
||||||
|
builtin/runtime.go and builtin/unsafe.go files; those compilations in
|
||||||
|
turn depend on importing the data in builtin.go. Thus, when the export
|
||||||
|
data format changes, the compiler must be able to import the data in
|
||||||
|
builtin.go even if its format has not yet changed. Proceed in several
|
||||||
|
steps as follows:
|
||||||
|
|
||||||
|
- Change the exporter to use the new format, and use a different version
|
||||||
|
string as well.
|
||||||
|
- Update the importer accordingly, but accept both the old and the new
|
||||||
|
format depending on the version string.
|
||||||
|
- all.bash should pass at this point.
|
||||||
|
- Run mkbuiltin.go: this will create a new builtin.go using the new
|
||||||
|
export format.
|
||||||
|
- go test -run Builtin should pass at this point.
|
||||||
|
- Remove importer support for the old export format and (maybe) revert
|
||||||
|
the version string again (it's only needed to mark the transition).
|
||||||
|
- all.bash should still pass.
|
||||||
|
|
||||||
|
Don't forget to set debugFormat to false.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package gc
|
package gc
|
||||||
|
|
@ -125,6 +162,17 @@ const exportVersion = "v0"
|
||||||
// Leave for debugging.
|
// Leave for debugging.
|
||||||
const exportInlined = true // default: true
|
const exportInlined = true // default: true
|
||||||
|
|
||||||
|
// trackAllTypes enables cycle tracking for all types, not just named
|
||||||
|
// types. The existing compiler invariants assume that unnamed types
|
||||||
|
// that are not completely set up are not used, or else there are spurious
|
||||||
|
// errors.
|
||||||
|
// If disabled, only named types are tracked, possibly leading to slightly
|
||||||
|
// less efficient encoding in rare cases. It also prevents the export of
|
||||||
|
// some corner-case type declarations (but those are not handled correctly
|
||||||
|
// with with the textual export format either).
|
||||||
|
// TODO(gri) enable and remove once issues caused by it are fixed
|
||||||
|
const trackAllTypes = false
|
||||||
|
|
||||||
type exporter struct {
|
type exporter struct {
|
||||||
out *bufio.Writer
|
out *bufio.Writer
|
||||||
|
|
||||||
|
|
@ -159,6 +207,10 @@ func export(out *bufio.Writer, trace bool) int {
|
||||||
trace: trace,
|
trace: trace,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(gri) clean up the ad-hoc encoding of the file format below
|
||||||
|
// (we need this so we can read the builtin package export data
|
||||||
|
// easily w/o being affected by format changes)
|
||||||
|
|
||||||
// first byte indicates low-level encoding format
|
// first byte indicates low-level encoding format
|
||||||
var format byte = 'c' // compact
|
var format byte = 'c' // compact
|
||||||
if debugFormat {
|
if debugFormat {
|
||||||
|
|
@ -166,6 +218,12 @@ func export(out *bufio.Writer, trace bool) int {
|
||||||
}
|
}
|
||||||
p.rawByte(format)
|
p.rawByte(format)
|
||||||
|
|
||||||
|
format = 'n' // track named types only
|
||||||
|
if trackAllTypes {
|
||||||
|
format = 'a'
|
||||||
|
}
|
||||||
|
p.rawByte(format)
|
||||||
|
|
||||||
// posInfo exported or not?
|
// posInfo exported or not?
|
||||||
p.bool(p.posInfoFormat)
|
p.bool(p.posInfoFormat)
|
||||||
|
|
||||||
|
|
@ -585,14 +643,21 @@ func (p *exporter) typ(t *Type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// otherwise, remember the type, write the type tag (< 0) and type data
|
// otherwise, remember the type, write the type tag (< 0) and type data
|
||||||
if p.trace {
|
if trackAllTypes {
|
||||||
p.tracef("T%d = {>\n", len(p.typIndex))
|
if p.trace {
|
||||||
defer p.tracef("<\n} ")
|
p.tracef("T%d = {>\n", len(p.typIndex))
|
||||||
|
defer p.tracef("<\n} ")
|
||||||
|
}
|
||||||
|
p.typIndex[t] = len(p.typIndex)
|
||||||
}
|
}
|
||||||
p.typIndex[t] = len(p.typIndex)
|
|
||||||
|
|
||||||
// pick off named types
|
// pick off named types
|
||||||
if tsym := t.Sym; tsym != nil {
|
if tsym := t.Sym; tsym != nil {
|
||||||
|
if !trackAllTypes {
|
||||||
|
// if we don't track all types, track named types now
|
||||||
|
p.typIndex[t] = len(p.typIndex)
|
||||||
|
}
|
||||||
|
|
||||||
// Predeclared types should have been found in the type map.
|
// Predeclared types should have been found in the type map.
|
||||||
if t.Orig == t {
|
if t.Orig == t {
|
||||||
Fatalf("exporter: predeclared type missing from type map?")
|
Fatalf("exporter: predeclared type missing from type map?")
|
||||||
|
|
@ -909,7 +974,7 @@ func parName(f *Field, numbered bool) string {
|
||||||
// print symbol with Vargen number or not as desired
|
// print symbol with Vargen number or not as desired
|
||||||
name := s.Name
|
name := s.Name
|
||||||
if strings.Contains(name, ".") {
|
if strings.Contains(name, ".") {
|
||||||
panic("invalid symbol name: " + name)
|
Fatalf("invalid symbol name: %s", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Functions that can be inlined use numbered parameters so we can distingish them
|
// Functions that can be inlined use numbered parameters so we can distingish them
|
||||||
|
|
@ -1012,6 +1077,8 @@ func (p *exporter) float(x *Mpflt) {
|
||||||
// but instead of emitting the information textually, emit the node tree in
|
// but instead of emitting the information textually, emit the node tree in
|
||||||
// binary form.
|
// binary form.
|
||||||
|
|
||||||
|
// TODO(gri) Improve tracing output. The current format is difficult to read.
|
||||||
|
|
||||||
// stmtList may emit more (or fewer) than len(list) nodes.
|
// stmtList may emit more (or fewer) than len(list) nodes.
|
||||||
func (p *exporter) stmtList(list Nodes) {
|
func (p *exporter) stmtList(list Nodes) {
|
||||||
if p.trace {
|
if p.trace {
|
||||||
|
|
@ -1088,6 +1155,16 @@ func (p *exporter) expr(n *Node) {
|
||||||
defer p.tracef(") ")
|
defer p.tracef(") ")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// from nodefmt (fmt.go)
|
||||||
|
//
|
||||||
|
// nodefmt reverts nodes back to their original - we don't need to do
|
||||||
|
// it because we are not bound to produce valid Go syntax when exporting
|
||||||
|
//
|
||||||
|
// if (fmtmode != FExp || n.Op != OLITERAL) && n.Orig != nil {
|
||||||
|
// n = n.Orig
|
||||||
|
// }
|
||||||
|
|
||||||
|
// from exprfmt (fmt.go)
|
||||||
for n != nil && n.Implicit && (n.Op == OIND || n.Op == OADDR) {
|
for n != nil && n.Implicit && (n.Op == OIND || n.Op == OADDR) {
|
||||||
n = n.Left
|
n = n.Left
|
||||||
}
|
}
|
||||||
|
|
@ -1117,15 +1194,13 @@ func (p *exporter) expr(n *Node) {
|
||||||
// Special case: name used as local variable in export.
|
// Special case: name used as local variable in export.
|
||||||
// _ becomes ~b%d internally; print as _ for export
|
// _ becomes ~b%d internally; print as _ for export
|
||||||
if n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' {
|
if n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' {
|
||||||
// case 0: mapped to ONAME
|
|
||||||
p.op(ONAME)
|
p.op(ONAME)
|
||||||
p.bool(true) // indicate blank identifier
|
p.string("_") // inlined and customized version of p.sym(n)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if n.Sym != nil && !isblank(n) && n.Name.Vargen > 0 {
|
if n.Sym != nil && !isblank(n) && n.Name.Vargen > 0 {
|
||||||
// case 1: mapped to OPACK
|
p.op(ONAME)
|
||||||
p.op(OPACK)
|
|
||||||
p.sym(n)
|
p.sym(n)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -1134,24 +1209,18 @@ func (p *exporter) expr(n *Node) {
|
||||||
// but for export, this should be rendered as (*pkg.T).meth.
|
// but for export, this should be rendered as (*pkg.T).meth.
|
||||||
// These nodes have the special property that they are names with a left OTYPE and a right ONAME.
|
// These nodes have the special property that they are names with a left OTYPE and a right ONAME.
|
||||||
if n.Left != nil && n.Left.Op == OTYPE && n.Right != nil && n.Right.Op == ONAME {
|
if n.Left != nil && n.Left.Op == OTYPE && n.Right != nil && n.Right.Op == ONAME {
|
||||||
// case 2: mapped to ONAME
|
p.op(OXDOT)
|
||||||
p.op(ONAME)
|
p.expr(n.Left) // n.Left.Op == OTYPE
|
||||||
// TODO(gri) can we map this case directly to OXDOT
|
|
||||||
// and then get rid of the bool here?
|
|
||||||
p.bool(false) // indicate non-blank identifier
|
|
||||||
p.typ(n.Left.Type)
|
|
||||||
p.fieldSym(n.Right.Sym, true)
|
p.fieldSym(n.Right.Sym, true)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// case 3: mapped to OPACK
|
p.op(ONAME)
|
||||||
p.op(OPACK)
|
|
||||||
p.sym(n) // fallthrough inlined here
|
|
||||||
|
|
||||||
case OPACK, ONONAME:
|
|
||||||
p.op(op)
|
|
||||||
p.sym(n)
|
p.sym(n)
|
||||||
|
|
||||||
|
// case OPACK, ONONAME:
|
||||||
|
// should have been resolved by typechecking - handled by default case
|
||||||
|
|
||||||
case OTYPE:
|
case OTYPE:
|
||||||
p.op(OTYPE)
|
p.op(OTYPE)
|
||||||
if p.bool(n.Type == nil) {
|
if p.bool(n.Type == nil) {
|
||||||
|
|
@ -1160,14 +1229,14 @@ func (p *exporter) expr(n *Node) {
|
||||||
p.typ(n.Type)
|
p.typ(n.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC:
|
// case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC:
|
||||||
panic("unreachable") // should have been resolved by typechecking
|
// should have been resolved by typechecking - handled by default case
|
||||||
|
|
||||||
// case OCLOSURE:
|
// case OCLOSURE:
|
||||||
// unimplemented - handled by default case
|
// unimplemented - handled by default case
|
||||||
|
|
||||||
// case OCOMPLIT:
|
// case OCOMPLIT:
|
||||||
// unimplemented - handled by default case
|
// should have been resolved by typechecking - handled by default case
|
||||||
|
|
||||||
case OPTRLIT:
|
case OPTRLIT:
|
||||||
p.op(OPTRLIT)
|
p.op(OPTRLIT)
|
||||||
|
|
@ -1176,16 +1245,12 @@ func (p *exporter) expr(n *Node) {
|
||||||
|
|
||||||
case OSTRUCTLIT:
|
case OSTRUCTLIT:
|
||||||
p.op(OSTRUCTLIT)
|
p.op(OSTRUCTLIT)
|
||||||
if !p.bool(n.Implicit) {
|
p.typ(n.Type)
|
||||||
p.typ(n.Type)
|
|
||||||
}
|
|
||||||
p.elemList(n.List) // special handling of field names
|
p.elemList(n.List) // special handling of field names
|
||||||
|
|
||||||
case OARRAYLIT, OMAPLIT:
|
case OARRAYLIT, OMAPLIT:
|
||||||
p.op(op)
|
p.op(OCOMPLIT)
|
||||||
if !p.bool(n.Implicit) {
|
p.typ(n.Type)
|
||||||
p.typ(n.Type)
|
|
||||||
}
|
|
||||||
p.exprList(n.List)
|
p.exprList(n.List)
|
||||||
|
|
||||||
case OKEY:
|
case OKEY:
|
||||||
|
|
@ -1198,9 +1263,6 @@ func (p *exporter) expr(n *Node) {
|
||||||
case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
|
case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
|
||||||
p.op(OXDOT)
|
p.op(OXDOT)
|
||||||
p.expr(n.Left)
|
p.expr(n.Left)
|
||||||
if n.Sym == nil {
|
|
||||||
panic("unreachable") // can this happen during export?
|
|
||||||
}
|
|
||||||
p.fieldSym(n.Sym, true)
|
p.fieldSym(n.Sym, true)
|
||||||
|
|
||||||
case ODOTTYPE, ODOTTYPE2:
|
case ODOTTYPE, ODOTTYPE2:
|
||||||
|
|
@ -1231,26 +1293,35 @@ func (p *exporter) expr(n *Node) {
|
||||||
p.expr(max)
|
p.expr(max)
|
||||||
|
|
||||||
case OCOPY, OCOMPLEX:
|
case OCOPY, OCOMPLEX:
|
||||||
|
// treated like other builtin calls (see e.g., OREAL)
|
||||||
p.op(op)
|
p.op(op)
|
||||||
p.expr(n.Left)
|
p.expr(n.Left)
|
||||||
p.expr(n.Right)
|
p.expr(n.Right)
|
||||||
|
p.op(OEND)
|
||||||
|
|
||||||
case OCONV, OCONVIFACE, OCONVNOP, OARRAYBYTESTR, OARRAYRUNESTR, OSTRARRAYBYTE, OSTRARRAYRUNE, ORUNESTR:
|
case OCONV, OCONVIFACE, OCONVNOP, OARRAYBYTESTR, OARRAYRUNESTR, OSTRARRAYBYTE, OSTRARRAYRUNE, ORUNESTR:
|
||||||
p.op(OCONV)
|
p.op(OCONV)
|
||||||
p.typ(n.Type)
|
p.typ(n.Type)
|
||||||
if p.bool(n.Left != nil) {
|
if n.Left != nil {
|
||||||
p.expr(n.Left)
|
p.expr(n.Left)
|
||||||
|
p.op(OEND)
|
||||||
} else {
|
} else {
|
||||||
p.exprList(n.List)
|
p.exprList(n.List) // emits terminating OEND
|
||||||
}
|
}
|
||||||
|
|
||||||
case OREAL, OIMAG, OAPPEND, OCAP, OCLOSE, ODELETE, OLEN, OMAKE, ONEW, OPANIC, ORECOVER, OPRINT, OPRINTN:
|
case OREAL, OIMAG, OAPPEND, OCAP, OCLOSE, ODELETE, OLEN, OMAKE, ONEW, OPANIC, ORECOVER, OPRINT, OPRINTN:
|
||||||
p.op(op)
|
p.op(op)
|
||||||
if p.bool(n.Left != nil) {
|
if n.Left != nil {
|
||||||
p.expr(n.Left)
|
p.expr(n.Left)
|
||||||
|
p.op(OEND)
|
||||||
} else {
|
} else {
|
||||||
p.exprList(n.List)
|
p.exprList(n.List) // emits terminating OEND
|
||||||
|
}
|
||||||
|
// only append() calls may contain '...' arguments
|
||||||
|
if op == OAPPEND {
|
||||||
p.bool(n.Isddd)
|
p.bool(n.Isddd)
|
||||||
|
} else if n.Isddd {
|
||||||
|
Fatalf("exporter: unexpected '...' with %s call", opnames[op])
|
||||||
}
|
}
|
||||||
|
|
||||||
case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OGETG:
|
case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OGETG:
|
||||||
|
|
@ -1306,7 +1377,8 @@ func (p *exporter) expr(n *Node) {
|
||||||
p.op(ODCLCONST)
|
p.op(ODCLCONST)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Fatalf("exporter: CANNOT EXPORT: %s\nPlease notify gri@\n", n.Op)
|
Fatalf("cannot export %s (%d) node\n"+
|
||||||
|
"==> please file an issue and assign to gri@\n", n.Op, n.Op)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1336,8 +1408,8 @@ func (p *exporter) stmt(n *Node) {
|
||||||
switch op := n.Op; op {
|
switch op := n.Op; op {
|
||||||
case ODCL:
|
case ODCL:
|
||||||
p.op(ODCL)
|
p.op(ODCL)
|
||||||
switch n.Left.Class &^ PHEAP {
|
switch n.Left.Class {
|
||||||
case PPARAM, PPARAMOUT, PAUTO:
|
case PPARAM, PPARAMOUT, PAUTO, PAUTOHEAP:
|
||||||
// TODO(gri) when is this not PAUTO?
|
// TODO(gri) when is this not PAUTO?
|
||||||
// Also, originally this didn't look like
|
// Also, originally this didn't look like
|
||||||
// the default case. Investigate.
|
// the default case. Investigate.
|
||||||
|
|
@ -1370,10 +1442,7 @@ func (p *exporter) stmt(n *Node) {
|
||||||
p.expr(n.Right)
|
p.expr(n.Right)
|
||||||
}
|
}
|
||||||
|
|
||||||
case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
|
case OAS2, OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
|
||||||
fallthrough
|
|
||||||
|
|
||||||
case OAS2:
|
|
||||||
p.op(OAS2)
|
p.op(OAS2)
|
||||||
p.exprList(n.List)
|
p.exprList(n.List)
|
||||||
p.exprList(n.Rlist)
|
p.exprList(n.Rlist)
|
||||||
|
|
@ -1382,9 +1451,8 @@ func (p *exporter) stmt(n *Node) {
|
||||||
p.op(ORETURN)
|
p.op(ORETURN)
|
||||||
p.exprList(n.List)
|
p.exprList(n.List)
|
||||||
|
|
||||||
case ORETJMP:
|
// case ORETJMP:
|
||||||
// generated by compiler for trampolin routines - not exported
|
// unreachable - generated by compiler for trampolin routines
|
||||||
panic("unreachable")
|
|
||||||
|
|
||||||
case OPROC, ODEFER:
|
case OPROC, ODEFER:
|
||||||
p.op(op)
|
p.op(op)
|
||||||
|
|
@ -1420,19 +1488,18 @@ func (p *exporter) stmt(n *Node) {
|
||||||
p.stmtList(n.List)
|
p.stmtList(n.List)
|
||||||
p.stmtList(n.Nbody)
|
p.stmtList(n.Nbody)
|
||||||
|
|
||||||
case OFALL:
|
case OFALL, OXFALL:
|
||||||
op = OXFALL
|
p.op(OXFALL)
|
||||||
fallthrough
|
|
||||||
|
|
||||||
case OBREAK, OCONTINUE, OGOTO, OXFALL:
|
case OBREAK, OCONTINUE:
|
||||||
p.op(op)
|
p.op(op)
|
||||||
p.exprsOrNil(n.Left, nil)
|
p.exprsOrNil(n.Left, nil)
|
||||||
|
|
||||||
case OEMPTY:
|
case OEMPTY:
|
||||||
// nothing to emit
|
// nothing to emit
|
||||||
|
|
||||||
case OLABEL:
|
case OGOTO, OLABEL:
|
||||||
p.op(OLABEL)
|
p.op(op)
|
||||||
p.expr(n.Left)
|
p.expr(n.Left)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
@ -1475,6 +1542,8 @@ func (p *exporter) fieldSym(s *Sym, short bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sym must encode the _ (blank) identifier as a single string "_" since
|
||||||
|
// encoding for some nodes is based on this assumption (e.g. ONAME nodes).
|
||||||
func (p *exporter) sym(n *Node) {
|
func (p *exporter) sym(n *Node) {
|
||||||
s := n.Sym
|
s := n.Sym
|
||||||
if s.Pkg != nil {
|
if s.Pkg != nil {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,8 @@
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// Binary package import.
|
// Binary package import.
|
||||||
// Based loosely on x/tools/go/importer.
|
// See bexport.go for the export data format and how
|
||||||
|
// to make a format change.
|
||||||
|
|
||||||
package gc
|
package gc
|
||||||
|
|
||||||
|
|
@ -24,10 +25,11 @@ type importer struct {
|
||||||
buf []byte // reused for reading strings
|
buf []byte // reused for reading strings
|
||||||
|
|
||||||
// object lists, in order of deserialization
|
// object lists, in order of deserialization
|
||||||
strList []string
|
strList []string
|
||||||
pkgList []*Pkg
|
pkgList []*Pkg
|
||||||
typList []*Type
|
typList []*Type
|
||||||
funcList []*Node // nil entry means already declared
|
funcList []*Node // nil entry means already declared
|
||||||
|
trackAllTypes bool
|
||||||
|
|
||||||
// for delayed type verification
|
// for delayed type verification
|
||||||
cmpList []struct{ pt, t *Type }
|
cmpList []struct{ pt, t *Type }
|
||||||
|
|
@ -59,6 +61,8 @@ func Import(in *bufio.Reader) {
|
||||||
Fatalf("importer: invalid encoding format in export data: got %q; want 'c' or 'd'", format)
|
Fatalf("importer: invalid encoding format in export data: got %q; want 'c' or 'd'", format)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.trackAllTypes = p.rawByte() == 'a'
|
||||||
|
|
||||||
p.posInfoFormat = p.bool()
|
p.posInfoFormat = p.bool()
|
||||||
|
|
||||||
// --- generic export data ---
|
// --- generic export data ---
|
||||||
|
|
@ -100,7 +104,9 @@ func Import(in *bufio.Reader) {
|
||||||
// --- compiler-specific export data ---
|
// --- compiler-specific export data ---
|
||||||
|
|
||||||
// read compiler-specific flags
|
// read compiler-specific flags
|
||||||
importpkg.Safe = p.bool()
|
|
||||||
|
// read but ignore safemode bit (see issue #15772)
|
||||||
|
p.bool() // formerly: importpkg.Safe = p.bool()
|
||||||
|
|
||||||
// phase 2
|
// phase 2
|
||||||
objcount = 0
|
objcount = 0
|
||||||
|
|
@ -230,7 +236,7 @@ func (p *importer) pkg() *Pkg {
|
||||||
// an empty path denotes the package we are currently importing;
|
// an empty path denotes the package we are currently importing;
|
||||||
// it must be the first package we see
|
// it must be the first package we see
|
||||||
if (path == "") != (len(p.pkgList) == 0) {
|
if (path == "") != (len(p.pkgList) == 0) {
|
||||||
panic(fmt.Sprintf("package path %q for pkg index %d", path, len(p.pkgList)))
|
Fatalf("importer: package path %q for pkg index %d", path, len(p.pkgList))
|
||||||
}
|
}
|
||||||
|
|
||||||
pkg := importpkg
|
pkg := importpkg
|
||||||
|
|
@ -331,7 +337,9 @@ func (p *importer) pos() {
|
||||||
|
|
||||||
func (p *importer) newtyp(etype EType) *Type {
|
func (p *importer) newtyp(etype EType) *Type {
|
||||||
t := typ(etype)
|
t := typ(etype)
|
||||||
p.typList = append(p.typList, t)
|
if p.trackAllTypes {
|
||||||
|
p.typList = append(p.typList, t)
|
||||||
|
}
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -389,7 +397,13 @@ func (p *importer) typ() *Type {
|
||||||
// read underlying type
|
// read underlying type
|
||||||
// parser.go:hidden_type
|
// parser.go:hidden_type
|
||||||
t0 := p.typ()
|
t0 := p.typ()
|
||||||
p.importtype(t, t0) // parser.go:hidden_import
|
if p.trackAllTypes {
|
||||||
|
// If we track all types, we cannot check equality of previously
|
||||||
|
// imported types until later. Use customized version of importtype.
|
||||||
|
p.importtype(t, t0)
|
||||||
|
} else {
|
||||||
|
importtype(t, t0)
|
||||||
|
}
|
||||||
|
|
||||||
// interfaces don't have associated methods
|
// interfaces don't have associated methods
|
||||||
if t0.IsInterface() {
|
if t0.IsInterface() {
|
||||||
|
|
@ -788,16 +802,11 @@ func (p *importer) node() *Node {
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case ONAME:
|
case ONAME:
|
||||||
if p.bool() {
|
|
||||||
// "_"
|
|
||||||
// TODO(gri) avoid repeated "_" lookup
|
|
||||||
return mkname(Pkglookup("_", localpkg))
|
|
||||||
}
|
|
||||||
return NodSym(OXDOT, typenod(p.typ()), p.fieldSym())
|
|
||||||
|
|
||||||
case OPACK, ONONAME:
|
|
||||||
return mkname(p.sym())
|
return mkname(p.sym())
|
||||||
|
|
||||||
|
// case OPACK, ONONAME:
|
||||||
|
// unreachable - should have been resolved by typechecking
|
||||||
|
|
||||||
case OTYPE:
|
case OTYPE:
|
||||||
if p.bool() {
|
if p.bool() {
|
||||||
return mkname(p.sym())
|
return mkname(p.sym())
|
||||||
|
|
@ -810,12 +819,9 @@ func (p *importer) node() *Node {
|
||||||
// case OCLOSURE:
|
// case OCLOSURE:
|
||||||
// unimplemented
|
// unimplemented
|
||||||
|
|
||||||
// case OCOMPLIT:
|
|
||||||
// unimplemented
|
|
||||||
|
|
||||||
case OPTRLIT:
|
case OPTRLIT:
|
||||||
n := p.expr()
|
n := p.expr()
|
||||||
if !p.bool() /* !implicit, i.e. '&' operator*/ {
|
if !p.bool() /* !implicit, i.e. '&' operator */ {
|
||||||
if n.Op == OCOMPLIT {
|
if n.Op == OCOMPLIT {
|
||||||
// Special case for &T{...}: turn into (*T){...}.
|
// Special case for &T{...}: turn into (*T){...}.
|
||||||
n.Right = Nod(OIND, n.Right, nil)
|
n.Right = Nod(OIND, n.Right, nil)
|
||||||
|
|
@ -827,18 +833,15 @@ func (p *importer) node() *Node {
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case OSTRUCTLIT:
|
case OSTRUCTLIT:
|
||||||
n := Nod(OCOMPLIT, nil, nil)
|
n := Nod(OCOMPLIT, nil, typenod(p.typ()))
|
||||||
if !p.bool() {
|
n.List.Set(p.elemList()) // special handling of field names
|
||||||
n.Right = typenod(p.typ())
|
|
||||||
}
|
|
||||||
n.List.Set(p.elemList())
|
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case OARRAYLIT, OMAPLIT:
|
// case OARRAYLIT, OMAPLIT:
|
||||||
n := Nod(OCOMPLIT, nil, nil)
|
// unreachable - mapped to case OCOMPLIT below by exporter
|
||||||
if !p.bool() {
|
|
||||||
n.Right = typenod(p.typ())
|
case OCOMPLIT:
|
||||||
}
|
n := Nod(OCOMPLIT, nil, typenod(p.typ()))
|
||||||
n.List.Set(p.exprList())
|
n.List.Set(p.exprList())
|
||||||
return n
|
return n
|
||||||
|
|
||||||
|
|
@ -854,14 +857,7 @@ func (p *importer) node() *Node {
|
||||||
|
|
||||||
case OXDOT:
|
case OXDOT:
|
||||||
// see parser.new_dotname
|
// see parser.new_dotname
|
||||||
obj := p.expr()
|
return NodSym(OXDOT, p.expr(), p.fieldSym())
|
||||||
sel := p.fieldSym()
|
|
||||||
if obj.Op == OPACK {
|
|
||||||
s := restrictlookup(sel.Name, obj.Name.Pkg)
|
|
||||||
obj.Used = true
|
|
||||||
return oldname(s)
|
|
||||||
}
|
|
||||||
return NodSym(OXDOT, obj, sel)
|
|
||||||
|
|
||||||
// case ODOTTYPE, ODOTTYPE2:
|
// case ODOTTYPE, ODOTTYPE2:
|
||||||
// unreachable - mapped to case ODOTTYPE below by exporter
|
// unreachable - mapped to case ODOTTYPE below by exporter
|
||||||
|
|
@ -891,29 +887,18 @@ func (p *importer) node() *Node {
|
||||||
n.SetSliceBounds(low, high, max)
|
n.SetSliceBounds(low, high, max)
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case OCOPY, OCOMPLEX:
|
|
||||||
n := builtinCall(op)
|
|
||||||
n.List.Set([]*Node{p.expr(), p.expr()})
|
|
||||||
return n
|
|
||||||
|
|
||||||
// case OCONV, OCONVIFACE, OCONVNOP, OARRAYBYTESTR, OARRAYRUNESTR, OSTRARRAYBYTE, OSTRARRAYRUNE, ORUNESTR:
|
// case OCONV, OCONVIFACE, OCONVNOP, OARRAYBYTESTR, OARRAYRUNESTR, OSTRARRAYBYTE, OSTRARRAYRUNE, ORUNESTR:
|
||||||
// unreachable - mapped to OCONV case below by exporter
|
// unreachable - mapped to OCONV case below by exporter
|
||||||
|
|
||||||
case OCONV:
|
case OCONV:
|
||||||
n := Nod(OCALL, typenod(p.typ()), nil)
|
n := Nod(OCALL, typenod(p.typ()), nil)
|
||||||
if p.bool() {
|
n.List.Set(p.exprList())
|
||||||
n.List.Set1(p.expr())
|
|
||||||
} else {
|
|
||||||
n.List.Set(p.exprList())
|
|
||||||
}
|
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case OREAL, OIMAG, OAPPEND, OCAP, OCLOSE, ODELETE, OLEN, OMAKE, ONEW, OPANIC, ORECOVER, OPRINT, OPRINTN:
|
case OCOPY, OCOMPLEX, OREAL, OIMAG, OAPPEND, OCAP, OCLOSE, ODELETE, OLEN, OMAKE, ONEW, OPANIC, ORECOVER, OPRINT, OPRINTN:
|
||||||
n := builtinCall(op)
|
n := builtinCall(op)
|
||||||
if p.bool() {
|
n.List.Set(p.exprList())
|
||||||
n.List.Set1(p.expr())
|
if op == OAPPEND {
|
||||||
} else {
|
|
||||||
n.List.Set(p.exprList())
|
|
||||||
n.Isddd = p.bool()
|
n.Isddd = p.bool()
|
||||||
}
|
}
|
||||||
return n
|
return n
|
||||||
|
|
@ -1053,6 +1038,7 @@ func (p *importer) node() *Node {
|
||||||
case OXCASE:
|
case OXCASE:
|
||||||
markdcl()
|
markdcl()
|
||||||
n := Nod(OXCASE, nil, nil)
|
n := Nod(OXCASE, nil, nil)
|
||||||
|
n.Xoffset = int64(block)
|
||||||
n.List.Set(p.exprList())
|
n.List.Set(p.exprList())
|
||||||
// TODO(gri) eventually we must declare variables for type switch
|
// TODO(gri) eventually we must declare variables for type switch
|
||||||
// statements (type switch statements are not yet exported)
|
// statements (type switch statements are not yet exported)
|
||||||
|
|
@ -1063,23 +1049,32 @@ func (p *importer) node() *Node {
|
||||||
// case OFALL:
|
// case OFALL:
|
||||||
// unreachable - mapped to OXFALL case below by exporter
|
// unreachable - mapped to OXFALL case below by exporter
|
||||||
|
|
||||||
case OBREAK, OCONTINUE, OGOTO, OXFALL:
|
case OXFALL:
|
||||||
|
n := Nod(OXFALL, nil, nil)
|
||||||
|
n.Xoffset = int64(block)
|
||||||
|
return n
|
||||||
|
|
||||||
|
case OBREAK, OCONTINUE:
|
||||||
left, _ := p.exprsOrNil()
|
left, _ := p.exprsOrNil()
|
||||||
|
if left != nil {
|
||||||
|
left = newname(left.Sym)
|
||||||
|
}
|
||||||
return Nod(op, left, nil)
|
return Nod(op, left, nil)
|
||||||
|
|
||||||
// case OEMPTY:
|
// case OEMPTY:
|
||||||
// unreachable - not emitted by exporter
|
// unreachable - not emitted by exporter
|
||||||
|
|
||||||
case OLABEL:
|
case OGOTO, OLABEL:
|
||||||
n := Nod(OLABEL, p.expr(), nil)
|
n := Nod(op, newname(p.expr().Sym), nil)
|
||||||
n.Left.Sym = dclstack // context, for goto restrictions
|
n.Sym = dclstack // context, for goto restrictions
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case OEND:
|
case OEND:
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Fatalf("importer: %s (%d) node not yet supported", op, op)
|
Fatalf("cannot import %s (%d) node\n"+
|
||||||
|
"==> please file an issue and assign to gri@\n", op, op)
|
||||||
panic("unreachable") // satisfy compiler
|
panic("unreachable") // satisfy compiler
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,106 +3,108 @@
|
||||||
package gc
|
package gc
|
||||||
|
|
||||||
const runtimeimport = "" +
|
const runtimeimport = "" +
|
||||||
"c\x00\x03v0\x01\rruntime\x00\t\x11newobject\x00\x02\x17\"\vtyp·2\x00\x00\x01" +
|
"cn\x00\x03v0\x01\rruntime\x00\t\x11newobject\x00\x02\x17\"\vtyp·2\x00\x00" +
|
||||||
"\x17:\x00\t\x13panicindex\x00\x00\x00\t\x13panicslice\x00\x00\x00\t\x15panic" +
|
"\x01\x17:\x00\t\x13panicindex\x00\x00\x00\t\x13panicslice\x00\x00\x00\t\x15pani" +
|
||||||
"divide\x00\x00\x00\t\x15throwreturn\x00\x00\x00\t\x11throwinit\x00\x00\x00\t" +
|
"cdivide\x00\x00\x00\t\x15throwreturn\x00\x00\x00\t\x11throwinit\x00\x00\x00" +
|
||||||
"\x11panicwrap\x00\x05 \x00 \x00 \x00\x00\t\rgopanic\x00\x01\x1b\x00\x00\x00\x00\t\x11gor" +
|
"\t\x11panicwrap\x00\x05 \x00 \x00 \x00\x00\t\rgopanic\x00\x01\x1b\x00\x00\x00\x00\t\x11go" +
|
||||||
"ecover\x00\x01\x17\b\x00\x01\x1b\x00\x00\x00\t\x11printbool\x00\x01\x00\x00\x00\t\x13printf" +
|
"recover\x00\x01\x17\b\x00\x01\x1b\x00\x00\x00\t\x11printbool\x00\x01\x00\x00\x00\t\x13print" +
|
||||||
"loat\x00\x01\x1a\x00\x00\t\x0fprintint\x00\x01\n\x00\x00\t\x0fprinthex\x00\x01\x14\x00\x00\t" +
|
"float\x00\x01\x1a\x00\x00\t\x0fprintint\x00\x01\n\x00\x00\t\x0fprinthex\x00\x01\x14\x00\x00" +
|
||||||
"\x11printuint\x00\x01\x14\x00\x00\t\x17printcomplex\x00\x01\x1e\x00\x00\t\x15prin" +
|
"\t\x11printuint\x00\x01\x14\x00\x00\t\x17printcomplex\x00\x01\x1e\x00\x00\t\x15pri" +
|
||||||
"tstring\x00\x01 \x00\x00\t\x17printpointer\x00\x01:\x00\x00\t\x13printif" +
|
"ntstring\x00\x01 \x00\x00\t\x17printpointer\x00\x01:\x00\x00\t\x13printi" +
|
||||||
"ace\x00\x01:\x00\x00\t\x13printeface\x00\x01:\x00\x00\t\x13printslice\x00\x01:" +
|
"face\x00\x01:\x00\x00\t\x13printeface\x00\x01:\x00\x00\t\x13printslice\x00\x01" +
|
||||||
"\x00\x00\t\rprintnl\x00\x00\x00\t\rprintsp\x00\x00\x00\t\x11printlock\x00\x00\x00" +
|
":\x00\x00\t\rprintnl\x00\x00\x00\t\rprintsp\x00\x00\x00\t\x11printlock\x00\x00" +
|
||||||
"\t\x15printunlock\x00\x00\x00\t\x19concatstring2\x00\x05\x17\x0f@\"\x00 \x00" +
|
"\x00\t\x15printunlock\x00\x00\x00\t\x19concatstring2\x00\x05\x17\x0f@\"\x00 " +
|
||||||
" \x00\x01 \x00\t\x19concatstring3\x00\a\x17\x0f@\"\x00 \x00 \x00 \x00\x01 \x00\t\x19co" +
|
"\x00 \x00\x01 \x00\t\x19concatstring3\x00\a\x17\x0f@\"\x00 \x00 \x00 \x00\x01 \x00\t\x19c" +
|
||||||
"ncatstring4\x00\t\x17\x0f@\"\x00 \x00 \x00 \x00 \x00\x01 \x00\t\x19concatstr" +
|
"oncatstring4\x00\t\x17\x0f@\"\x00 \x00 \x00 \x00 \x00\x01 \x00\t\x19concatst" +
|
||||||
"ing5\x00\v\x17\x0f@\"\x00 \x00 \x00 \x00 \x00 \x00\x01 \x00\t\x19concatstrings\x00" +
|
"ring5\x00\v\x17\x0f@\"\x00 \x00 \x00 \x00 \x00 \x00\x01 \x00\t\x19concatstrings" +
|
||||||
"\x03\x17\x0f@\"\x00\x11 \x00\x01 \x00\t\x11cmpstring\x00\x03 \x00 \x00\x01\x02\x00\t\x0feqstri" +
|
"\x00\x03\x17\x0f@\"\x00\x11 \x00\x01 \x00\t\x11cmpstring\x00\x03 \x00 \x00\x01\x02\x00\t\x0feqstr" +
|
||||||
"ng\x00\x03 \x00 \x00\x01\x00\x00\t\x11intstring\x00\x03\x17\x0f\b\"\x00\n\x00\x01 \x00\t!slic" +
|
"ing\x00\x03 \x00 \x00\x01\x00\x00\t\x11intstring\x00\x03\x17\x0f\b\"\x00\n\x00\x01 \x00\t!sli" +
|
||||||
"ebytetostring\x00\x03\x17\x0f@\"\x00\x11\"\x00\x01 \x00\t'slicebytetos" +
|
"cebytetostring\x00\x03\x17\x0f@\"\x00\x11\"\x00\x01 \x00\t'slicebyteto" +
|
||||||
"tringtmp\x00\x01\x11\"\x00\x01 \x00\t!slicerunetostring\x00\x03\x17\x0f@" +
|
"stringtmp\x00\x01\x11\"\x00\x01 \x00\t!slicerunetostring\x00\x03\x17\x0f" +
|
||||||
"\"\x00\x11|S\x00\x01 \x00\t!stringtoslicebyte\x00\x03\x17\x0f@\"\x00 \x00\x01\x11\"" +
|
"@\"\x00\x11|S\x00\x01 \x00\t!stringtoslicebyte\x00\x03\x17\x0f@\"\x00 \x00\x01\x11" +
|
||||||
"\x00\t'stringtoslicebytetmp\x00\x01 \x00\x01\x11\"\x00\t!stringt" +
|
"\"\x00\t'stringtoslicebytetmp\x00\x01 \x00\x01\x11\"\x00\t!string" +
|
||||||
"oslicerune\x00\x03\x17\x0f@|S\x00 \x00\x01\x11|S\x00\t\x13stringiter\x00\x03 " +
|
"toslicerune\x00\x03\x17\x0f@|S\x00 \x00\x01\x11|S\x00\t\x13stringiter\x00\x03" +
|
||||||
"\x00\x02\x00\x01\x02\x00\t\x15stringiter2\x00\x03 \x00\x02\x00\x04\x02\rretk·1\x00\x00|S\r" +
|
" \x00\x02\x00\x01\x02\x00\t\x15stringiter2\x00\x03 \x00\x02\x00\x04\x02\rretk·1\x00\x00|S" +
|
||||||
"retv·2\x00\x00\t\x11slicecopy\x00\x06:\tto·2\x00\x00:\tfr·3\x00\x00" +
|
"\rretv·2\x00\x00\t\x11slicecopy\x00\x06:\tto·2\x00\x00:\tfr·3\x00" +
|
||||||
"\x16\vwid·4\x00\x1bunsafe-uintptr\x01\x02\x00\t\x1dslicestring" +
|
"\x00\x16\vwid·4\x00\x1bunsafe-uintptr\x01\x02\x00\t\x1dslicestrin" +
|
||||||
"copy\x00\x04:^\x00\x00:`\x00\x00\x01\x02\x00\t\rconvI2E\x00\x02:\relem·2\x00\x00\x02" +
|
"gcopy\x00\x04:^\x00\x00:`\x00\x00\x01\x02\x00\t\rconvI2E\x00\x02:\relem·2\x00\x00" +
|
||||||
":\vret·1\x00\x00\t\rconvI2I\x00\x04\x17\"\b\x00\x00:\relem·3\x00\x00\x02:l" +
|
"\x02:\vret·1\x00\x00\t\rconvI2I\x00\x04\x17\"\b\x00\x00:\relem·3\x00\x00\x02:" +
|
||||||
"\x00\x00\t\rconvT2E\x00\x06\x17\"\b\x00\x00>p\x00\x00>\vbuf·4\x00\x00\x02:l\x00\x00\t\rc" +
|
"l\x00\x00\t\rconvT2E\x00\x06\x17\"\b\x00\x00\x17:p\x00\x00\x17:\vbuf·4\x00\x00\x02:l\x00\x00" +
|
||||||
"onvT2I\x00\x06\x17\"\vtab·2\x00\x00>p\x00\x00>t\x00\x00\x02:l\x00\x00\t\x11assert" +
|
"\t\rconvT2I\x00\x06\x17\"\vtab·2\x00\x00\x17:p\x00\x00\x17:t\x00\x00\x02:l\x00\x00\t\x11a" +
|
||||||
"E2E\x00\x06\x17\"\vtyp·1\x00\x00:\x0fiface·2\x00\x00>\vret·3\x00\x00\x00\t" +
|
"ssertE2E\x00\x06\x17\"\vtyp·1\x00\x00:\x0fiface·2\x00\x00\x17:\vret\xc2" +
|
||||||
"\x13assertE2E2\x00\x06\x17\"\b\x00\x00:\x0fiface·3\x00\x00>\vret·4\x00\x00" +
|
"\xb73\x00\x00\x00\t\x13assertE2E2\x00\x06\x17\"\b\x00\x00:\x0fiface·3\x00\x00\x17:\vr" +
|
||||||
"\x01\x00\x00\t\x11assertE2I\x00\x06\x17\"||\x00\x00:~\x00\x00>\x80\x01\x00\x00\x00\t\x13assert" +
|
"et·4\x00\x00\x01\x00\x00\t\x11assertE2I\x00\x06\x17\"||\x00\x00:~\x00\x00\x17:\x80\x01\x00\x00\x00" +
|
||||||
"E2I2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00>\x86\x01\x00\x00\x01\x00\x00\t\x11assertE2T\x00\x06\x17\"|" +
|
"\t\x13assertE2I2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00\x17:\x86\x01\x00\x00\x01\x00\x00\t\x11asser" +
|
||||||
"|\x00\x00:~\x00\x00>\x80\x01\x00\x00\x00\t\x13assertE2T2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00>\x86\x01" +
|
"tE2T\x00\x06\x17\"||\x00\x00:~\x00\x00\x17:\x80\x01\x00\x00\x00\t\x13assertE2T2\x00\x06\x17\"\b" +
|
||||||
"\x00\x00\x01\x00\x00\t\x11assertI2E\x00\x06\x17\"||\x00\x00:~\x00\x00>\x80\x01\x00\x00\x00\t\x13asse" +
|
"\x00\x00:\x84\x01\x00\x00\x17:\x86\x01\x00\x00\x01\x00\x00\t\x11assertI2E\x00\x06\x17\"||\x00\x00:~\x00\x00\x17" +
|
||||||
"rtI2E2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00>\x86\x01\x00\x00\x01\x00\x00\t\x11assertI2I\x00\x06\x17" +
|
":\x80\x01\x00\x00\x00\t\x13assertI2E2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00\x17:\x86\x01\x00\x00\x01\x00\x00\t" +
|
||||||
"\"||\x00\x00:~\x00\x00>\x80\x01\x00\x00\x00\t\x13assertI2I2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00>" +
|
"\x11assertI2I\x00\x06\x17\"||\x00\x00:~\x00\x00\x17:\x80\x01\x00\x00\x00\t\x13assertI2I" +
|
||||||
"\x86\x01\x00\x00\x01\x00\x00\t\x11assertI2T\x00\x06\x17\"||\x00\x00:~\x00\x00>\x80\x01\x00\x00\x00\t\x13as" +
|
"2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00\x17:\x86\x01\x00\x00\x01\x00\x00\t\x11assertI2T\x00\x06\x17\"||\x00" +
|
||||||
"sertI2T2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00>\x86\x01\x00\x00\x01\x00\x00\t\x17panicdotty" +
|
"\x00:~\x00\x00\x17:\x80\x01\x00\x00\x00\t\x13assertI2T2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00\x17:\x86\x01" +
|
||||||
"pe\x00\x06\x17\"\rhave·1\x00\x00\x9a\x01\rwant·2\x00\x00\x9a\x01\x84\x01\x00\x00\x00\t\rifa" +
|
"\x00\x00\x01\x00\x00\t\x17panicdottype\x00\x06\x17\"\rhave·1\x00\x00\x17\"\rwant" +
|
||||||
"ceeq\x00\x04:\ti1·2\x00\x00:\ti2·3\x00\x00\x02\x00l\x00\x00\t\refaceeq\x00\x04" +
|
"·2\x00\x00\x17\"\x84\x01\x00\x00\x00\t\rifaceeq\x00\x04:\ti1·2\x00\x00:\ti2·3\x00" +
|
||||||
":\xa4\x01\x00\x00:\xa6\x01\x00\x00\x02\x00l\x00\x00\t\rmakemap\x00\b\x17\"\x13mapType·2\x00" +
|
"\x00\x02\x00l\x00\x00\t\refaceeq\x00\x04:\xa4\x01\x00\x00:\xa6\x01\x00\x00\x02\x00l\x00\x00\t\rmakema" +
|
||||||
"\x00\n\rhint·3\x00\x00>\x11mapbuf·4\x00\x00>\x17bucketbuf·5\x00" +
|
"p\x00\b\x17\"\x13mapType·2\x00\x00\n\rhint·3\x00\x00\x17:\x11mapbuf·" +
|
||||||
"\x00\x02\x1d::\rhmap·1\x00\x00\t\x13mapaccess1\x00\x06\x17\"\xac\x01\x00\x00\x1d::\rh" +
|
"4\x00\x00\x17:\x17bucketbuf·5\x00\x00\x02\x1d::\rhmap·1\x00\x00\t\x13mapa" +
|
||||||
"map·3\x00\x00>\vkey·4\x00\x00\x02>\vval·1\x00\x00\t!mapaccess" +
|
"ccess1\x00\x06\x17\"\xac\x01\x00\x00\x1d::\rhmap·3\x00\x00\x17:\vkey·4\x00\x00\x02\x17" +
|
||||||
"1_fast32\x00\x06\x17\"\xac\x01\x00\x00\x1d::\xb8\x01\x00\x00:\xba\x01\x00\x00\x02>\xbc\x01\x00\x00\t!mapa" +
|
":\vval·1\x00\x00\t!mapaccess1_fast32\x00\x06\x17\"\xac\x01\x00\x00\x1d::" +
|
||||||
"ccess1_fast64\x00\x06\x17\"\xac\x01\x00\x00\x1d::\xb8\x01\x00\x00:\xba\x01\x00\x00\x02>\xbc\x01\x00\x00\t" +
|
"\xb8\x01\x00\x00:\xba\x01\x00\x00\x02\x17:\xbc\x01\x00\x00\t!mapaccess1_fast64\x00\x06\x17\"\xac" +
|
||||||
"#mapaccess1_faststr\x00\x06\x17\"\xac\x01\x00\x00\x1d::\xb8\x01\x00\x00:\xba\x01\x00\x00\x02" +
|
"\x01\x00\x00\x1d::\xb8\x01\x00\x00:\xba\x01\x00\x00\x02\x17:\xbc\x01\x00\x00\t#mapaccess1_fasts" +
|
||||||
">\xbc\x01\x00\x00\t\x1bmapaccess1_fat\x00\b\x17\"\xac\x01\x00\x00\x1d::\xb8\x01\x00\x00>\xba\x01\x00" +
|
"tr\x00\x06\x17\"\xac\x01\x00\x00\x1d::\xb8\x01\x00\x00:\xba\x01\x00\x00\x02\x17:\xbc\x01\x00\x00\t\x1bmapaccess" +
|
||||||
"\x00\x17\"\rzero·5\x00\x00\x02>\xbc\x01\x00\x00\t\x13mapaccess2\x00\x06\x17\"\x13mapT" +
|
"1_fat\x00\b\x17\"\xac\x01\x00\x00\x1d::\xb8\x01\x00\x00\x17:\xba\x01\x00\x00\x17\"\rzero·5\x00\x00\x02\x17" +
|
||||||
"ype·3\x00\x00\x1d::\rhmap·4\x00\x00>\vkey·5\x00\x00\x04>\xbc\x01\x00\x00\x00\rp" +
|
":\xbc\x01\x00\x00\t\x13mapaccess2\x00\x06\x17\"\x13mapType·3\x00\x00\x1d::\rhm" +
|
||||||
"res·2\x00\x00\t!mapaccess2_fast32\x00\x06\x17\"\xca\x01\x00\x00\x1d::\xcc\x01" +
|
"ap·4\x00\x00\x17:\vkey·5\x00\x00\x04\x17:\xbc\x01\x00\x00\x00\rpres·2\x00\x00\t!ma" +
|
||||||
"\x00\x00:\xce\x01\x00\x00\x04>\xbc\x01\x00\x00\x00\xd0\x01\x00\x00\t!mapaccess2_fast64\x00\x06\x17" +
|
"paccess2_fast32\x00\x06\x17\"\xca\x01\x00\x00\x1d::\xcc\x01\x00\x00:\xce\x01\x00\x00\x04\x17:\xbc\x01" +
|
||||||
"\"\xca\x01\x00\x00\x1d::\xcc\x01\x00\x00:\xce\x01\x00\x00\x04>\xbc\x01\x00\x00\x00\xd0\x01\x00\x00\t#mapaccess2" +
|
"\x00\x00\x00\xd0\x01\x00\x00\t!mapaccess2_fast64\x00\x06\x17\"\xca\x01\x00\x00\x1d::\xcc\x01\x00" +
|
||||||
"_faststr\x00\x06\x17\"\xca\x01\x00\x00\x1d::\xcc\x01\x00\x00:\xce\x01\x00\x00\x04>\xbc\x01\x00\x00\x00\xd0\x01\x00\x00\t" +
|
"\x00:\xce\x01\x00\x00\x04\x17:\xbc\x01\x00\x00\x00\xd0\x01\x00\x00\t#mapaccess2_faststr\x00\x06" +
|
||||||
"\x1bmapaccess2_fat\x00\b\x17\"\xca\x01\x00\x00\x1d::\xcc\x01\x00\x00>\xce\x01\x00\x00\x17\"\rze" +
|
"\x17\"\xca\x01\x00\x00\x1d::\xcc\x01\x00\x00:\xce\x01\x00\x00\x04\x17:\xbc\x01\x00\x00\x00\xd0\x01\x00\x00\t\x1bmapacces" +
|
||||||
"ro·6\x00\x00\x04>\xbc\x01\x00\x00\x00\xd0\x01\x00\x00\t\x13mapassign1\x00\b\x17\"\x13mapTy" +
|
"s2_fat\x00\b\x17\"\xca\x01\x00\x00\x1d::\xcc\x01\x00\x00\x17:\xce\x01\x00\x00\x17\"\rzero·6\x00\x00\x04" +
|
||||||
"pe·1\x00\x00\x1d::\rhmap·2\x00\x00>\vkey·3\x00\x00>\vval·4\x00\x00" +
|
"\x17:\xbc\x01\x00\x00\x00\xd0\x01\x00\x00\t\x13mapassign1\x00\b\x17\"\x13mapType·1\x00\x00" +
|
||||||
"\x00\t\x15mapiterinit\x00\x06\x17\"\xde\x01\x00\x00\x1d::\xe0\x01\x00\x00>\x0fhiter·3\x00" +
|
"\x1d::\rhmap·2\x00\x00\x17:\vkey·3\x00\x00\x17:\vval·4\x00\x00\x00\t\x15ma" +
|
||||||
"\x00\x00\t\x11mapdelete\x00\x06\x17\"\xde\x01\x00\x00\x1d::\xe0\x01\x00\x00>\xe2\x01\x00\x00\x00\t\x15mapi" +
|
"piterinit\x00\x06\x17\"\xde\x01\x00\x00\x1d::\xe0\x01\x00\x00\x17:\x0fhiter·3\x00\x00\x00\t\x11" +
|
||||||
"ternext\x00\x02>\x0fhiter·1\x00\x00\x00\t\x0fmakechan\x00\x04\x17\"\x15cha" +
|
"mapdelete\x00\x06\x17\"\xde\x01\x00\x00\x1d::\xe0\x01\x00\x00\x17:\xe2\x01\x00\x00\x00\t\x15mapiter" +
|
||||||
"nType·2\x00\x00\n\xae\x01\x00\x00\x02\x1f\x06:\x0fhchan·1\x00\x00\t\x11chanrecv" +
|
"next\x00\x02\x17:\x0fhiter·1\x00\x00\x00\t\x0fmakechan\x00\x04\x17\"\x15chanT" +
|
||||||
"1\x00\x06\x17\"\x15chanType·1\x00\x00\x1f\x02:\x0fhchan·2\x00\x00>p\x00\x00\x00\t\x11" +
|
"ype·2\x00\x00\n\xae\x01\x00\x00\x02\x1f\x06:\x0fhchan·1\x00\x00\t\x11chanrecv1\x00" +
|
||||||
"chanrecv2\x00\x06\x17\"\xf2\x01\x00\x00\x1f\x02:\x0fhchan·3\x00\x00>\relem·4" +
|
"\x06\x17\"\x15chanType·1\x00\x00\x1f\x02:\x0fhchan·2\x00\x00\x17:p\x00\x00\x00\t\x11c" +
|
||||||
"\x00\x00\x01\x00\x00\t\x11chansend1\x00\x06\x17\"\xf8\x01\x00\x00\x1f\x04:\xfa\x01\x00\x00>p\x00\x00\x00\t\x11cl" +
|
"hanrecv2\x00\x06\x17\"\xf2\x01\x00\x00\x1f\x02:\x0fhchan·3\x00\x00\x17:\relem·4" +
|
||||||
"osechan\x00\x02:\xf4\x01\x00\x00\x00\a\x17writeBarrier\x00\x15\x06\renabled" +
|
"\x00\x00\x01\x00\x00\t\x11chansend1\x00\x06\x17\"\xf8\x01\x00\x00\x1f\x04:\xfa\x01\x00\x00\x17:p\x00\x00\x00\t\x11c" +
|
||||||
"\x00\x00\x00\vneeded\x00\x00\x00\x05cgo\x00\x00\x00\t\x1dwritebarrierptr\x00\x04>" +
|
"losechan\x00\x02:\xf4\x01\x00\x00\x00\a\x17writeBarrier\x00\x15\x06\renable" +
|
||||||
"\vdst·1\x00\x00:\vsrc·2\x00\x00\x00\t\x17typedmemmove\x00\x06\x17\"||" +
|
"d\x00\x00\x00\vneeded\x00\x00\x00\x05cgo\x00\x00\x00\t\x1dwritebarrierptr\x00\x04" +
|
||||||
"\x00\x00>\vdst·2\x00\x00>\vsrc·3\x00\x00\x00\t\x1btypedslicecopy\x00" +
|
"\x17:\vdst·1\x00\x00:\vsrc·2\x00\x00\x00\t\x17typedmemmove\x00\x06\x17\"" +
|
||||||
"\x06\x17\"\b\x00\x00:\vdst·3\x00\x00:\vsrc·4\x00\x00\x01\x02\x00\t\x17selectnbs" +
|
"||\x00\x00\x17:\vdst·2\x00\x00\x17:\vsrc·3\x00\x00\x00\t\x1btypedslicec" +
|
||||||
"end\x00\x06\x17\"\xf2\x01\x00\x00\x1f\x04:\xfe\x01\x00\x00>\x80\x02\x00\x00\x01\x00\x00\t\x17selectnbrecv" +
|
"opy\x00\x06\x17\"\b\x00\x00:\vdst·3\x00\x00:\vsrc·4\x00\x00\x01\x02\x00\t\x17selec" +
|
||||||
"\x00\x06\x17\"\xf2\x01\x00\x00>p\x00\x00\x1f\x02:\x0fhchan·4\x00\x00\x01\x00\x00\t\x19selectnbr" +
|
"tnbsend\x00\x06\x17\"\xf2\x01\x00\x00\x1f\x04:\xfe\x01\x00\x00\x17:\x80\x02\x00\x00\x01\x00\x00\t\x17selectn" +
|
||||||
"ecv2\x00\b\x17\"\xf2\x01\x00\x00>p\x00\x00\x17\x00\x15received·4\x00\x00\x1f\x02:\x0fhcha" +
|
"brecv\x00\x06\x17\"\xf2\x01\x00\x00\x17:p\x00\x00\x1f\x02:\x0fhchan·4\x00\x00\x01\x00\x00\t\x19sel" +
|
||||||
"n·5\x00\x00\x01\x00\x00\t\x11newselect\x00\x06\x17\"\vsel·1\x00\x00\n\x13selsi" +
|
"ectnbrecv2\x00\b\x17\"\xf2\x01\x00\x00\x17:p\x00\x00\x17\x00\x15received·4\x00\x00\x1f" +
|
||||||
"ze·2\x00\x00\b\rsize·3\x00\x00\x00\t\x13selectsend\x00\x06\x17\"\vsel\xc2" +
|
"\x02:\x0fhchan·5\x00\x00\x01\x00\x00\t\x11newselect\x00\x06\x17\"\vsel·1\x00\x00" +
|
||||||
"\xb72\x00\x00\x1f\x04:\xfe\x01\x00\x00>\x80\x02\x00\x00\x02\x00\x15selected·1\x00\x00\t\x13select" +
|
"\n\x13selsize·2\x00\x00\b\rsize·3\x00\x00\x00\t\x13selectsend\x00\x06" +
|
||||||
"recv\x00\x06\x17\"\xb6\x02\x00\x00\x1f\x02:\xfe\x01\x00\x00>\x80\x02\x00\x00\x02\x00\xb8\x02\x00\x00\t\x15selectre" +
|
"\x17\"\vsel·2\x00\x00\x1f\x04:\xfe\x01\x00\x00\x17:\x80\x02\x00\x00\x02\x00\x15selected·1\x00\x00" +
|
||||||
"cv2\x00\b\x17\"\xb6\x02\x00\x00\x1f\x02:\xfe\x01\x00\x00>\x80\x02\x00\x00\xf8\x01\x15received·5\x00\x00\x02" +
|
"\t\x13selectrecv\x00\x06\x17\"\xb6\x02\x00\x00\x1f\x02:\xfe\x01\x00\x00\x17:\x80\x02\x00\x00\x02\x00\xb8\x02\x00\x00\t" +
|
||||||
"\x00\xb8\x02\x00\x00\t\x19selectdefault\x00\x02\x17\"\xb6\x02\x00\x00\x02\x00\xb8\x02\x00\x00\t\x0fsele" +
|
"\x15selectrecv2\x00\b\x17\"\xb6\x02\x00\x00\x1f\x02:\xfe\x01\x00\x00\x17:\x80\x02\x00\x00\x17\x00\x15rece" +
|
||||||
"ctgo\x00\x02\x17\"\xae\x02\x00\x00\x00\t\tblock\x00\x00\x00\t\x11makeslice\x00\x06\x17\"\b\x00" +
|
"ived·5\x00\x00\x02\x00\xb8\x02\x00\x00\t\x19selectdefault\x00\x02\x17\"\xb6\x02\x00\x00\x02\x00" +
|
||||||
"\x00\n\vnel·3\x00\x00\n\vcap·4\x00\x00\x02\x11:\vary·1\x00\x00\t\x11grows" +
|
"\xb8\x02\x00\x00\t\x0fselectgo\x00\x02\x17\"\xae\x02\x00\x00\x00\t\tblock\x00\x00\x00\t\x11makes" +
|
||||||
"lice\x00\x06\x17\"\b\x00\x00\x11:\vold·3\x00\x00\x02\xca\x02\x00\x00\x02\x11:\xcc\x02\x00\x00\t\rmemm" +
|
"lice\x00\x06\x17\"\b\x00\x00\n\vnel·3\x00\x00\n\vcap·4\x00\x00\x02\x11:\vary·" +
|
||||||
"ove\x00\x06>\tto·1\x00\x00>\vfrm·2\x00\x00\x16\x11length·3\x00d\x00\t\v" +
|
"1\x00\x00\t\x11growslice\x00\x06\x17\"\b\x00\x00\x11:\vold·3\x00\x00\x02\xca\x02\x00\x00\x02\x11:" +
|
||||||
"memclr\x00\x04\x17\"\vptr·1\x00\x00\x16\x11length·2\x00d\x00\t\x0fmemeq" +
|
"\xcc\x02\x00\x00\t\rmemmove\x00\x06\x17:\tto·1\x00\x00\x17:\vfrm·2\x00\x00\x16\x11le" +
|
||||||
"ual\x00\x06>\ax·2\x00\x00>\ay·3\x00\x00\x16\rsize·4\x00d\x01\x00\x00\t\x11mem" +
|
"ngth·3\x00d\x00\t\vmemclr\x00\x04\x17\"\vptr·1\x00\x00\x16\x11length\xc2" +
|
||||||
"equal8\x00\x04>\xe2\x02\x00\x00>\xe4\x02\x00\x00\x01\x00\x00\t\x13memequal16\x00\x04>\xe2\x02\x00\x00" +
|
"\xb72\x00d\x00\t\x0fmemequal\x00\x06\x17:\ax·2\x00\x00\x17:\ay·3\x00\x00\x16\rsiz" +
|
||||||
">\xe4\x02\x00\x00\x01\x00\x00\t\x13memequal32\x00\x04>\xe2\x02\x00\x00>\xe4\x02\x00\x00\x01\x00\x00\t\x13mem" +
|
"e·4\x00d\x01\x00\x00\t\x11memequal8\x00\x04\x17:\xe2\x02\x00\x00\x17:\xe4\x02\x00\x00\x01\x00\x00\t\x13m" +
|
||||||
"equal64\x00\x04>\xe2\x02\x00\x00>\xe4\x02\x00\x00\x01\x00\x00\t\x15memequal128\x00\x04>\xe2\x02" +
|
"emequal16\x00\x04\x17:\xe2\x02\x00\x00\x17:\xe4\x02\x00\x00\x01\x00\x00\t\x13memequal32\x00\x04" +
|
||||||
"\x00\x00>\xe4\x02\x00\x00\x01\x00\x00\t\x0fint64div\x00\x03\n\x00\n\x00\x01\n\x00\t\x11uint64div" +
|
"\x17:\xe2\x02\x00\x00\x17:\xe4\x02\x00\x00\x01\x00\x00\t\x13memequal64\x00\x04\x17:\xe2\x02\x00\x00\x17:\xe4\x02\x00" +
|
||||||
"\x00\x03\x14\x00\x14\x00\x01\x14\x00\t\x0fint64mod\x00\x03\n\x00\n\x00\x01\n\x00\t\x11uint64mod\x00" +
|
"\x00\x01\x00\x00\t\x15memequal128\x00\x04\x17:\xe2\x02\x00\x00\x17:\xe4\x02\x00\x00\x01\x00\x00\t\x0fint6" +
|
||||||
"\x03\x14\x00\x14\x00\x01\x14\x00\t\x1bfloat64toint64\x00\x01\x1a\x00\x01\n\x00\t\x1dfloat64" +
|
"4div\x00\x03\n\x00\n\x00\x01\n\x00\t\x11uint64div\x00\x03\x14\x00\x14\x00\x01\x14\x00\t\x0fint64" +
|
||||||
"touint64\x00\x01\x1a\x00\x01\x14\x00\t\x1bint64tofloat64\x00\x01\n\x00\x01\x1a\x00\t\x1d" +
|
"mod\x00\x03\n\x00\n\x00\x01\n\x00\t\x11uint64mod\x00\x03\x14\x00\x14\x00\x01\x14\x00\t\x1bfloat6" +
|
||||||
"uint64tofloat64\x00\x01\x14\x00\x01\x1a\x00\t\x19complex128div\x00\x04\x1e" +
|
"4toint64\x00\x01\x1a\x00\x01\n\x00\t\x1dfloat64touint64\x00\x01\x1a\x00\x01\x14\x00\t" +
|
||||||
"\vnum·2\x00\x00\x1e\vden·3\x00\x00\x02\x1e\vquo·1\x00\x00\t\x19racefunc" +
|
"\x1bint64tofloat64\x00\x01\n\x00\x01\x1a\x00\t\x1duint64tofloat64\x00" +
|
||||||
"enter\x00\x01\x16d\x00\t\x17racefuncexit\x00\x00\x00\t\x0fraceread\x00\x01\x16" +
|
"\x01\x14\x00\x01\x1a\x00\t\x19complex128div\x00\x04\x1e\vnum·2\x00\x00\x1e\vden·" +
|
||||||
"d\x00\t\x11racewrite\x00\x01\x16d\x00\t\x19racereadrange\x00\x04\x16\radd" +
|
"3\x00\x00\x02\x1e\vquo·1\x00\x00\t\x19racefuncenter\x00\x01\x16d\x00\t\x17race" +
|
||||||
"r·1\x00d\x16\rsize·2\x00d\x00\t\x1bracewriterange\x00\x04\x16\x94\x03\x00" +
|
"funcexit\x00\x00\x00\t\x0fraceread\x00\x01\x16d\x00\t\x11racewrite\x00\x01\x16" +
|
||||||
"d\x16\x96\x03\x00d\x00\t\x0fmsanread\x00\x04\x16\x94\x03\x00d\x16\x96\x03\x00d\x00\t\x11msanwrit" +
|
"d\x00\t\x19racereadrange\x00\x04\x16\raddr·1\x00d\x16\rsize·2\x00" +
|
||||||
"e\x00\x04\x16\x94\x03\x00d\x16\x96\x03\x00d\x00\v\xf4\x01\x02\v\x00\x01\x00\n$$\n"
|
"d\x00\t\x1bracewriterange\x00\x04\x16\x94\x03\x00d\x16\x96\x03\x00d\x00\t\x0fmsanrea" +
|
||||||
|
"d\x00\x04\x16\x94\x03\x00d\x16\x96\x03\x00d\x00\t\x11msanwrite\x00\x04\x16\x94\x03\x00d\x16\x96\x03\x00d\x00\v\xf4" +
|
||||||
|
"\x01\x02\v\x00\x01\x00\n$$\n"
|
||||||
|
|
||||||
const unsafeimport = "" +
|
const unsafeimport = "" +
|
||||||
"c\x00\x03v0\x01\vunsafe\x00\x05\r\rPointer\x00\x16\x00\t\x0fOffsetof\x00\x01:" +
|
"cn\x00\x03v0\x01\vunsafe\x00\x05\r\rPointer\x00\x16\x00\t\x0fOffsetof\x00\x01" +
|
||||||
"\x00\x01\x16\x00\t\vSizeof\x00\x01:\x00\x01\x16\x00\t\rAlignof\x00\x01:\x00\x01\x16\x00\v\b\x00\v\x00" +
|
":\x00\x01\x16\x00\t\vSizeof\x00\x01:\x00\x01\x16\x00\t\rAlignof\x00\x01:\x00\x01\x16\x00\v\b\x00\v" +
|
||||||
"\x01\x00\n$$\n"
|
"\x00\x01\x00\n$$\n"
|
||||||
|
|
|
||||||
|
|
@ -518,8 +518,7 @@ func cgen_wb(n, res *Node, wb bool) {
|
||||||
case ODOT,
|
case ODOT,
|
||||||
ODOTPTR,
|
ODOTPTR,
|
||||||
OINDEX,
|
OINDEX,
|
||||||
OIND,
|
OIND:
|
||||||
ONAME: // PHEAP or PPARAMREF var
|
|
||||||
var n1 Node
|
var n1 Node
|
||||||
Igen(n, &n1, res)
|
Igen(n, &n1, res)
|
||||||
|
|
||||||
|
|
@ -1545,6 +1544,7 @@ func Agen(n *Node, res *Node) {
|
||||||
|
|
||||||
switch n.Op {
|
switch n.Op {
|
||||||
default:
|
default:
|
||||||
|
Dump("bad agen", n)
|
||||||
Fatalf("agen: unknown op %v", Nconv(n, FmtShort|FmtSign))
|
Fatalf("agen: unknown op %v", Nconv(n, FmtShort|FmtSign))
|
||||||
|
|
||||||
case OCALLMETH:
|
case OCALLMETH:
|
||||||
|
|
@ -1571,24 +1571,6 @@ func Agen(n *Node, res *Node) {
|
||||||
Thearch.Gmove(&n1, res)
|
Thearch.Gmove(&n1, res)
|
||||||
Regfree(&n1)
|
Regfree(&n1)
|
||||||
|
|
||||||
case ONAME:
|
|
||||||
// should only get here with names in this func.
|
|
||||||
if n.Name.Funcdepth > 0 && n.Name.Funcdepth != Funcdepth {
|
|
||||||
Dump("bad agen", n)
|
|
||||||
Fatalf("agen: bad ONAME funcdepth %d != %d", n.Name.Funcdepth, Funcdepth)
|
|
||||||
}
|
|
||||||
|
|
||||||
// should only get here for heap vars or paramref
|
|
||||||
if n.Class&PHEAP == 0 && n.Class != PPARAMREF {
|
|
||||||
Dump("bad agen", n)
|
|
||||||
Fatalf("agen: bad ONAME class %#x", n.Class)
|
|
||||||
}
|
|
||||||
|
|
||||||
Cgen(n.Name.Heapaddr, res)
|
|
||||||
if n.Xoffset != 0 {
|
|
||||||
addOffset(res, n.Xoffset)
|
|
||||||
}
|
|
||||||
|
|
||||||
case OIND:
|
case OIND:
|
||||||
Cgen(nl, res)
|
Cgen(nl, res)
|
||||||
if !nl.NonNil {
|
if !nl.NonNil {
|
||||||
|
|
@ -1646,8 +1628,9 @@ func Igen(n *Node, a *Node, res *Node) {
|
||||||
|
|
||||||
switch n.Op {
|
switch n.Op {
|
||||||
case ONAME:
|
case ONAME:
|
||||||
if (n.Class&PHEAP != 0) || n.Class == PPARAMREF {
|
if n.Class == PAUTOHEAP {
|
||||||
break
|
Dump("igen", n)
|
||||||
|
Fatalf("bad name")
|
||||||
}
|
}
|
||||||
*a = *n
|
*a = *n
|
||||||
return
|
return
|
||||||
|
|
@ -1702,11 +1685,11 @@ func Igen(n *Node, a *Node, res *Node) {
|
||||||
a.Type = n.Type
|
a.Type = n.Type
|
||||||
return
|
return
|
||||||
|
|
||||||
// Index of fixed-size array by constant can
|
|
||||||
// put the offset in the addressing.
|
|
||||||
// Could do the same for slice except that we need
|
|
||||||
// to use the real index for the bounds checking.
|
|
||||||
case OINDEX:
|
case OINDEX:
|
||||||
|
// Index of fixed-size array by constant can
|
||||||
|
// put the offset in the addressing.
|
||||||
|
// Could do the same for slice except that we need
|
||||||
|
// to use the real index for the bounds checking.
|
||||||
if n.Left.Type.IsArray() || (n.Left.Type.IsPtr() && n.Left.Left.Type.IsArray()) {
|
if n.Left.Type.IsArray() || (n.Left.Type.IsPtr() && n.Left.Left.Type.IsArray()) {
|
||||||
if Isconst(n.Right, CTINT) {
|
if Isconst(n.Right, CTINT) {
|
||||||
// Compute &a.
|
// Compute &a.
|
||||||
|
|
|
||||||
|
|
@ -66,8 +66,39 @@ func closurebody(body []*Node) *Node {
|
||||||
// unhook them.
|
// unhook them.
|
||||||
// make the list of pointers for the closure call.
|
// make the list of pointers for the closure call.
|
||||||
for _, v := range func_.Func.Cvars.Slice() {
|
for _, v := range func_.Func.Cvars.Slice() {
|
||||||
v.Name.Param.Closure.Name.Param.Closure = v.Name.Param.Outer
|
// Unlink from v1; see comment in syntax.go type Param for these fields.
|
||||||
v.Name.Param.Outerexpr = oldname(v.Sym)
|
v1 := v.Name.Defn
|
||||||
|
v1.Name.Param.Innermost = v.Name.Param.Outer
|
||||||
|
|
||||||
|
// If the closure usage of v is not dense,
|
||||||
|
// we need to make it dense; now that we're out
|
||||||
|
// of the function in which v appeared,
|
||||||
|
// look up v.Sym in the enclosing function
|
||||||
|
// and keep it around for use in the compiled code.
|
||||||
|
//
|
||||||
|
// That is, suppose we just finished parsing the innermost
|
||||||
|
// closure f4 in this code:
|
||||||
|
//
|
||||||
|
// func f() {
|
||||||
|
// v := 1
|
||||||
|
// func() { // f2
|
||||||
|
// use(v)
|
||||||
|
// func() { // f3
|
||||||
|
// func() { // f4
|
||||||
|
// use(v)
|
||||||
|
// }()
|
||||||
|
// }()
|
||||||
|
// }()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// At this point v.Outer is f2's v; there is no f3's v.
|
||||||
|
// To construct the closure f4 from within f3,
|
||||||
|
// we need to use f3's v and in this case we need to create f3's v.
|
||||||
|
// We are now in the context of f3, so calling oldname(v.Sym)
|
||||||
|
// obtains f3's v, creating it if necessary (as it is in the example).
|
||||||
|
//
|
||||||
|
// capturevars will decide whether to use v directly or &v.
|
||||||
|
v.Name.Param.Outer = oldname(v.Sym)
|
||||||
}
|
}
|
||||||
|
|
||||||
return func_
|
return func_
|
||||||
|
|
@ -75,7 +106,7 @@ func closurebody(body []*Node) *Node {
|
||||||
|
|
||||||
func typecheckclosure(func_ *Node, top int) {
|
func typecheckclosure(func_ *Node, top int) {
|
||||||
for _, ln := range func_.Func.Cvars.Slice() {
|
for _, ln := range func_.Func.Cvars.Slice() {
|
||||||
n := ln.Name.Param.Closure
|
n := ln.Name.Defn
|
||||||
if !n.Name.Captured {
|
if !n.Name.Captured {
|
||||||
n.Name.Captured = true
|
n.Name.Captured = true
|
||||||
if n.Name.Decldepth == 0 {
|
if n.Name.Decldepth == 0 {
|
||||||
|
|
@ -215,8 +246,6 @@ func makeclosure(func_ *Node) *Node {
|
||||||
// We use value capturing for values <= 128 bytes that are never reassigned
|
// We use value capturing for values <= 128 bytes that are never reassigned
|
||||||
// after capturing (effectively constant).
|
// after capturing (effectively constant).
|
||||||
func capturevars(xfunc *Node) {
|
func capturevars(xfunc *Node) {
|
||||||
var outer *Node
|
|
||||||
|
|
||||||
lno := lineno
|
lno := lineno
|
||||||
lineno = xfunc.Lineno
|
lineno = xfunc.Lineno
|
||||||
|
|
||||||
|
|
@ -239,14 +268,14 @@ func capturevars(xfunc *Node) {
|
||||||
// so that the outer frame also grabs them and knows they escape.
|
// so that the outer frame also grabs them and knows they escape.
|
||||||
dowidth(v.Type)
|
dowidth(v.Type)
|
||||||
|
|
||||||
outer = v.Name.Param.Outerexpr
|
outer := v.Name.Param.Outer
|
||||||
v.Name.Param.Outerexpr = nil
|
outermost := v.Name.Defn
|
||||||
|
|
||||||
// out parameters will be assigned to implicitly upon return.
|
// out parameters will be assigned to implicitly upon return.
|
||||||
if outer.Class != PPARAMOUT && !v.Name.Param.Closure.Addrtaken && !v.Name.Param.Closure.Assigned && v.Type.Width <= 128 {
|
if outer.Class != PPARAMOUT && !outermost.Addrtaken && !outermost.Assigned && v.Type.Width <= 128 {
|
||||||
v.Name.Byval = true
|
v.Name.Byval = true
|
||||||
} else {
|
} else {
|
||||||
v.Name.Param.Closure.Addrtaken = true
|
outermost.Addrtaken = true
|
||||||
outer = Nod(OADDR, outer, nil)
|
outer = Nod(OADDR, outer, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -259,7 +288,7 @@ func capturevars(xfunc *Node) {
|
||||||
if v.Name.Byval {
|
if v.Name.Byval {
|
||||||
how = "value"
|
how = "value"
|
||||||
}
|
}
|
||||||
Warnl(v.Lineno, "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym, v.Name.Param.Closure.Addrtaken, v.Name.Param.Closure.Assigned, int32(v.Type.Width))
|
Warnl(v.Lineno, "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym, outermost.Addrtaken, outermost.Assigned, int32(v.Type.Width))
|
||||||
}
|
}
|
||||||
|
|
||||||
outer = typecheck(outer, Erv)
|
outer = typecheck(outer, Erv)
|
||||||
|
|
@ -303,7 +332,7 @@ func transformclosure(xfunc *Node) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fld := newField()
|
fld := newField()
|
||||||
fld.Funarg = true
|
fld.Funarg = FunargParams
|
||||||
if v.Name.Byval {
|
if v.Name.Byval {
|
||||||
// If v is captured by value, we merely downgrade it to PPARAM.
|
// If v is captured by value, we merely downgrade it to PPARAM.
|
||||||
v.Class = PPARAM
|
v.Class = PPARAM
|
||||||
|
|
@ -313,7 +342,7 @@ func transformclosure(xfunc *Node) {
|
||||||
} else {
|
} else {
|
||||||
// If v of type T is captured by reference,
|
// If v of type T is captured by reference,
|
||||||
// we introduce function param &v *T
|
// we introduce function param &v *T
|
||||||
// and v remains PPARAMREF with &v heapaddr
|
// and v remains PAUTOHEAP with &v heapaddr
|
||||||
// (accesses will implicitly deref &v).
|
// (accesses will implicitly deref &v).
|
||||||
addr := newname(Lookupf("&%s", v.Sym.Name))
|
addr := newname(Lookupf("&%s", v.Sym.Name))
|
||||||
addr.Type = Ptrto(v.Type)
|
addr.Type = Ptrto(v.Type)
|
||||||
|
|
|
||||||
12416
src/cmd/compile/internal/gc/constFold_test.go
Normal file
12416
src/cmd/compile/internal/gc/constFold_test.go
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -405,7 +405,6 @@ func Complexgen(n *Node, res *Node) {
|
||||||
ODOTPTR,
|
ODOTPTR,
|
||||||
OINDEX,
|
OINDEX,
|
||||||
OIND,
|
OIND,
|
||||||
ONAME, // PHEAP or PPARAMREF var
|
|
||||||
OCALLFUNC,
|
OCALLFUNC,
|
||||||
OCALLMETH,
|
OCALLMETH,
|
||||||
OCALLINTER:
|
OCALLINTER:
|
||||||
|
|
|
||||||
|
|
@ -385,32 +385,36 @@ func oldname(s *Sym) *Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
if Curfn != nil && n.Op == ONAME && n.Name.Funcdepth > 0 && n.Name.Funcdepth != Funcdepth {
|
if Curfn != nil && n.Op == ONAME && n.Name.Funcdepth > 0 && n.Name.Funcdepth != Funcdepth {
|
||||||
// inner func is referring to var in outer func.
|
// Inner func is referring to var in outer func.
|
||||||
//
|
//
|
||||||
// TODO(rsc): If there is an outer variable x and we
|
// TODO(rsc): If there is an outer variable x and we
|
||||||
// are parsing x := 5 inside the closure, until we get to
|
// are parsing x := 5 inside the closure, until we get to
|
||||||
// the := it looks like a reference to the outer x so we'll
|
// the := it looks like a reference to the outer x so we'll
|
||||||
// make x a closure variable unnecessarily.
|
// make x a closure variable unnecessarily.
|
||||||
if n.Name.Param.Closure == nil || n.Name.Param.Closure.Name.Funcdepth != Funcdepth {
|
c := n.Name.Param.Innermost
|
||||||
// create new closure var.
|
if c == nil || c.Name.Funcdepth != Funcdepth {
|
||||||
c := Nod(ONAME, nil, nil)
|
// Do not have a closure var for the active closure yet; make one.
|
||||||
|
c = Nod(ONAME, nil, nil)
|
||||||
c.Sym = s
|
c.Sym = s
|
||||||
c.Class = PPARAMREF
|
c.Class = PAUTOHEAP
|
||||||
|
c.setIsClosureVar(true)
|
||||||
c.Isddd = n.Isddd
|
c.Isddd = n.Isddd
|
||||||
c.Name.Defn = n
|
c.Name.Defn = n
|
||||||
c.Addable = false
|
c.Addable = false
|
||||||
c.Ullman = 2
|
c.Ullman = 2
|
||||||
c.Name.Funcdepth = Funcdepth
|
c.Name.Funcdepth = Funcdepth
|
||||||
c.Name.Param.Outer = n.Name.Param.Closure
|
|
||||||
n.Name.Param.Closure = c
|
// Link into list of active closure variables.
|
||||||
c.Name.Param.Closure = n
|
// Popped from list in func closurebody.
|
||||||
|
c.Name.Param.Outer = n.Name.Param.Innermost
|
||||||
|
n.Name.Param.Innermost = c
|
||||||
|
|
||||||
c.Xoffset = 0
|
c.Xoffset = 0
|
||||||
Curfn.Func.Cvars.Append(c)
|
Curfn.Func.Cvars.Append(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// return ref to closure var, not original
|
// return ref to closure var, not original
|
||||||
return n.Name.Param.Closure
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
return n
|
return n
|
||||||
|
|
@ -504,10 +508,8 @@ func ifacedcl(n *Node) {
|
||||||
n.Func = new(Func)
|
n.Func = new(Func)
|
||||||
n.Func.FCurfn = Curfn
|
n.Func.FCurfn = Curfn
|
||||||
dclcontext = PPARAM
|
dclcontext = PPARAM
|
||||||
markdcl()
|
|
||||||
Funcdepth++
|
funcstart(n)
|
||||||
n.Func.Outer = Curfn
|
|
||||||
Curfn = n
|
|
||||||
funcargs(n.Right)
|
funcargs(n.Right)
|
||||||
|
|
||||||
// funcbody is normally called after the parser has
|
// funcbody is normally called after the parser has
|
||||||
|
|
@ -534,11 +536,7 @@ func funchdr(n *Node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
dclcontext = PAUTO
|
dclcontext = PAUTO
|
||||||
markdcl()
|
funcstart(n)
|
||||||
Funcdepth++
|
|
||||||
|
|
||||||
n.Func.Outer = Curfn
|
|
||||||
Curfn = n
|
|
||||||
|
|
||||||
if n.Func.Nname != nil {
|
if n.Func.Nname != nil {
|
||||||
funcargs(n.Func.Nname.Name.Param.Ntype)
|
funcargs(n.Func.Nname.Name.Param.Ntype)
|
||||||
|
|
@ -671,6 +669,18 @@ func funcargs2(t *Type) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var funcstack []*Node // stack of previous values of Curfn
|
||||||
|
var Funcdepth int32 // len(funcstack) during parsing, but then forced to be the same later during compilation
|
||||||
|
|
||||||
|
// start the function.
|
||||||
|
// called before funcargs; undone at end of funcbody.
|
||||||
|
func funcstart(n *Node) {
|
||||||
|
markdcl()
|
||||||
|
funcstack = append(funcstack, Curfn)
|
||||||
|
Funcdepth++
|
||||||
|
Curfn = n
|
||||||
|
}
|
||||||
|
|
||||||
// finish the body.
|
// finish the body.
|
||||||
// called in auto-declaration context.
|
// called in auto-declaration context.
|
||||||
// returns in extern-declaration context.
|
// returns in extern-declaration context.
|
||||||
|
|
@ -680,9 +690,8 @@ func funcbody(n *Node) {
|
||||||
Fatalf("funcbody: unexpected dclcontext %d", dclcontext)
|
Fatalf("funcbody: unexpected dclcontext %d", dclcontext)
|
||||||
}
|
}
|
||||||
popdcl()
|
popdcl()
|
||||||
|
funcstack, Curfn = funcstack[:len(funcstack)-1], funcstack[len(funcstack)-1]
|
||||||
Funcdepth--
|
Funcdepth--
|
||||||
Curfn = n.Func.Outer
|
|
||||||
n.Func.Outer = nil
|
|
||||||
if Funcdepth == 0 {
|
if Funcdepth == 0 {
|
||||||
dclcontext = PEXTERN
|
dclcontext = PEXTERN
|
||||||
}
|
}
|
||||||
|
|
@ -827,14 +836,14 @@ func tostruct0(t *Type, l []*Node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func tofunargs(l []*Node) *Type {
|
func tofunargs(l []*Node, funarg Funarg) *Type {
|
||||||
t := typ(TSTRUCT)
|
t := typ(TSTRUCT)
|
||||||
t.StructType().Funarg = true
|
t.StructType().Funarg = funarg
|
||||||
|
|
||||||
fields := make([]*Field, len(l))
|
fields := make([]*Field, len(l))
|
||||||
for i, n := range l {
|
for i, n := range l {
|
||||||
f := structfield(n)
|
f := structfield(n)
|
||||||
f.Funarg = true
|
f.Funarg = funarg
|
||||||
|
|
||||||
// esc.go needs to find f given a PPARAM to add the tag.
|
// esc.go needs to find f given a PPARAM to add the tag.
|
||||||
if n.Left != nil && n.Left.Class == PPARAM {
|
if n.Left != nil && n.Left.Class == PPARAM {
|
||||||
|
|
@ -1025,9 +1034,9 @@ func functype0(t *Type, this *Node, in, out []*Node) {
|
||||||
if this != nil {
|
if this != nil {
|
||||||
rcvr = []*Node{this}
|
rcvr = []*Node{this}
|
||||||
}
|
}
|
||||||
*t.RecvsP() = tofunargs(rcvr)
|
*t.RecvsP() = tofunargs(rcvr, FunargRcvr)
|
||||||
*t.ResultsP() = tofunargs(out)
|
*t.ResultsP() = tofunargs(out, FunargResults)
|
||||||
*t.ParamsP() = tofunargs(in)
|
*t.ParamsP() = tofunargs(in, FunargParams)
|
||||||
|
|
||||||
checkdupfields("argument", t.Recvs(), t.Results(), t.Params())
|
checkdupfields("argument", t.Recvs(), t.Results(), t.Params())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -640,7 +640,7 @@ func esc(e *EscState, n *Node, up *Node) {
|
||||||
// "Big" conditions that were scattered around in walk have been gathered here
|
// "Big" conditions that were scattered around in walk have been gathered here
|
||||||
if n.Esc != EscHeap && n.Type != nil &&
|
if n.Esc != EscHeap && n.Type != nil &&
|
||||||
(n.Type.Width > MaxStackVarSize ||
|
(n.Type.Width > MaxStackVarSize ||
|
||||||
n.Op == ONEW && n.Type.Elem().Width >= 1<<16 ||
|
(n.Op == ONEW || n.Op == OPTRLIT) && n.Type.Elem().Width >= 1<<16 ||
|
||||||
n.Op == OMAKESLICE && !isSmallMakeSlice(n)) {
|
n.Op == OMAKESLICE && !isSmallMakeSlice(n)) {
|
||||||
if Debug['m'] > 2 {
|
if Debug['m'] > 2 {
|
||||||
Warnl(n.Lineno, "%v is too large for stack", n)
|
Warnl(n.Lineno, "%v is too large for stack", n)
|
||||||
|
|
@ -900,13 +900,13 @@ func esc(e *EscState, n *Node, up *Node) {
|
||||||
escassignSinkNilWhy(e, n, n7.Right, "map literal value")
|
escassignSinkNilWhy(e, n, n7.Right, "map literal value")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Link addresses of captured variables to closure.
|
|
||||||
case OCLOSURE:
|
case OCLOSURE:
|
||||||
|
// Link addresses of captured variables to closure.
|
||||||
for _, v := range n.Func.Cvars.Slice() {
|
for _, v := range n.Func.Cvars.Slice() {
|
||||||
if v.Op == OXXX { // unnamed out argument; see dcl.go:/^funcargs
|
if v.Op == OXXX { // unnamed out argument; see dcl.go:/^funcargs
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
a := v.Name.Param.Closure
|
a := v.Name.Defn
|
||||||
if !v.Name.Byval {
|
if !v.Name.Byval {
|
||||||
a = Nod(OADDR, a, nil)
|
a = Nod(OADDR, a, nil)
|
||||||
a.Lineno = v.Lineno
|
a.Lineno = v.Lineno
|
||||||
|
|
@ -1068,7 +1068,6 @@ func escassign(e *EscState, dst, src *Node, step *EscStep) {
|
||||||
OIND, // dst = *x
|
OIND, // dst = *x
|
||||||
ODOTPTR, // dst = (*x).f
|
ODOTPTR, // dst = (*x).f
|
||||||
ONAME,
|
ONAME,
|
||||||
OPARAM,
|
|
||||||
ODDDARG,
|
ODDDARG,
|
||||||
OPTRLIT,
|
OPTRLIT,
|
||||||
OARRAYLIT,
|
OARRAYLIT,
|
||||||
|
|
@ -1818,14 +1817,14 @@ func escwalkBody(e *EscState, level Level, dst *Node, src *Node, step *EscStep,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Treat a PPARAMREF closure variable as equivalent to the
|
// Treat a captured closure variable as equivalent to the
|
||||||
// original variable.
|
// original variable.
|
||||||
if src.Class == PPARAMREF {
|
if src.isClosureVar() {
|
||||||
if leaks && Debug['m'] != 0 {
|
if leaks && Debug['m'] != 0 {
|
||||||
Warnl(src.Lineno, "leaking closure reference %v", Nconv(src, FmtShort))
|
Warnl(src.Lineno, "leaking closure reference %v", Nconv(src, FmtShort))
|
||||||
step.describe(src)
|
step.describe(src)
|
||||||
}
|
}
|
||||||
escwalk(e, level, dst, src.Name.Param.Closure, e.stepWalk(dst, src.Name.Param.Closure, "closure-var", step))
|
escwalk(e, level, dst, src.Name.Defn, e.stepWalk(dst, src.Name.Defn, "closure-var", step))
|
||||||
}
|
}
|
||||||
|
|
||||||
case OPTRLIT, OADDR:
|
case OPTRLIT, OADDR:
|
||||||
|
|
@ -1835,20 +1834,20 @@ func escwalkBody(e *EscState, level Level, dst *Node, src *Node, step *EscStep,
|
||||||
}
|
}
|
||||||
if leaks {
|
if leaks {
|
||||||
src.Esc = EscHeap
|
src.Esc = EscHeap
|
||||||
addrescapes(src.Left)
|
|
||||||
if Debug['m'] != 0 && osrcesc != src.Esc {
|
if Debug['m'] != 0 && osrcesc != src.Esc {
|
||||||
p := src
|
p := src
|
||||||
if p.Left.Op == OCLOSURE {
|
if p.Left.Op == OCLOSURE {
|
||||||
p = p.Left // merely to satisfy error messages in tests
|
p = p.Left // merely to satisfy error messages in tests
|
||||||
}
|
}
|
||||||
if Debug['m'] > 2 {
|
if Debug['m'] > 2 {
|
||||||
Warnl(src.Lineno, "%v escapes to heap, level=%v, dst.eld=%v, src.eld=%v",
|
Warnl(src.Lineno, "%v escapes to heap, level=%v, dst=%v dst.eld=%v, src.eld=%v",
|
||||||
Nconv(p, FmtShort), level, dstE.Escloopdepth, modSrcLoopdepth)
|
Nconv(p, FmtShort), level, dst, dstE.Escloopdepth, modSrcLoopdepth)
|
||||||
} else {
|
} else {
|
||||||
Warnl(src.Lineno, "%v escapes to heap", Nconv(p, FmtShort))
|
Warnl(src.Lineno, "%v escapes to heap", Nconv(p, FmtShort))
|
||||||
step.describe(src)
|
step.describe(src)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
addrescapes(src.Left)
|
||||||
escwalkBody(e, level.dec(), dst, src.Left, e.stepWalk(dst, src.Left, why, step), modSrcLoopdepth)
|
escwalkBody(e, level.dec(), dst, src.Left, e.stepWalk(dst, src.Left, why, step), modSrcLoopdepth)
|
||||||
extraloopdepth = modSrcLoopdepth // passes to recursive case, seems likely a no-op
|
extraloopdepth = modSrcLoopdepth // passes to recursive case, seems likely a no-op
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ func reexportdep(n *Node) {
|
||||||
//print("reexportdep %+hN\n", n);
|
//print("reexportdep %+hN\n", n);
|
||||||
switch n.Op {
|
switch n.Op {
|
||||||
case ONAME:
|
case ONAME:
|
||||||
switch n.Class &^ PHEAP {
|
switch n.Class {
|
||||||
// methods will be printed along with their type
|
// methods will be printed along with their type
|
||||||
// nodes for T.Method expressions
|
// nodes for T.Method expressions
|
||||||
case PFUNC:
|
case PFUNC:
|
||||||
|
|
|
||||||
|
|
@ -218,9 +218,9 @@ var classnames = []string{
|
||||||
"Pxxx",
|
"Pxxx",
|
||||||
"PEXTERN",
|
"PEXTERN",
|
||||||
"PAUTO",
|
"PAUTO",
|
||||||
|
"PAUTOHEAP",
|
||||||
"PPARAM",
|
"PPARAM",
|
||||||
"PPARAMOUT",
|
"PPARAMOUT",
|
||||||
"PPARAMREF",
|
|
||||||
"PFUNC",
|
"PFUNC",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -251,14 +251,10 @@ func jconv(n *Node, flag FmtFlag) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
if n.Class != 0 {
|
if n.Class != 0 {
|
||||||
s := ""
|
if int(n.Class) < len(classnames) {
|
||||||
if n.Class&PHEAP != 0 {
|
fmt.Fprintf(&buf, " class(%s)", classnames[n.Class])
|
||||||
s = ",heap"
|
|
||||||
}
|
|
||||||
if int(n.Class&^PHEAP) < len(classnames) {
|
|
||||||
fmt.Fprintf(&buf, " class(%s%s)", classnames[n.Class&^PHEAP], s)
|
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(&buf, " class(%d?%s)", n.Class&^PHEAP, s)
|
fmt.Fprintf(&buf, " class(%d?)", n.Class)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -798,8 +794,8 @@ func stmtfmt(n *Node) string {
|
||||||
switch n.Op {
|
switch n.Op {
|
||||||
case ODCL:
|
case ODCL:
|
||||||
if fmtmode == FExp {
|
if fmtmode == FExp {
|
||||||
switch n.Left.Class &^ PHEAP {
|
switch n.Left.Class {
|
||||||
case PPARAM, PPARAMOUT, PAUTO:
|
case PPARAM, PPARAMOUT, PAUTO, PAUTOHEAP:
|
||||||
f += fmt.Sprintf("var %v %v", n.Left, n.Left.Type)
|
f += fmt.Sprintf("var %v %v", n.Left, n.Left.Type)
|
||||||
goto ret
|
goto ret
|
||||||
}
|
}
|
||||||
|
|
@ -1197,7 +1193,7 @@ func exprfmt(n *Node, prec int) string {
|
||||||
if n.Nbody.Len() != 0 {
|
if n.Nbody.Len() != 0 {
|
||||||
return fmt.Sprintf("%v { %v }", n.Type, n.Nbody)
|
return fmt.Sprintf("%v { %v }", n.Type, n.Nbody)
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%v { %v }", n.Type, n.Name.Param.Closure.Nbody)
|
return fmt.Sprintf("%v { %v }", n.Type, n.Func.Closure.Nbody)
|
||||||
|
|
||||||
case OCOMPLIT:
|
case OCOMPLIT:
|
||||||
ptrlit := n.Right != nil && n.Right.Implicit && n.Right.Type != nil && n.Right.Type.IsPtr()
|
ptrlit := n.Right != nil && n.Right.Implicit && n.Right.Type != nil && n.Right.Type.IsPtr()
|
||||||
|
|
@ -1663,7 +1659,7 @@ func Fldconv(f *Field, flag FmtFlag) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
if s != nil && f.Embedded == 0 {
|
if s != nil && f.Embedded == 0 {
|
||||||
if f.Funarg {
|
if f.Funarg != FunargNone {
|
||||||
name = Nconv(f.Nname, 0)
|
name = Nconv(f.Nname, 0)
|
||||||
} else if flag&FmtLong != 0 {
|
} else if flag&FmtLong != 0 {
|
||||||
name = sconv(s, FmtShort|FmtByte) // qualify non-exported names (used on structs, not on funarg)
|
name = sconv(s, FmtShort|FmtByte) // qualify non-exported names (used on structs, not on funarg)
|
||||||
|
|
@ -1696,7 +1692,7 @@ func Fldconv(f *Field, flag FmtFlag) string {
|
||||||
// (The escape analysis tags do not apply to func vars.)
|
// (The escape analysis tags do not apply to func vars.)
|
||||||
// But it must not suppress struct field tags.
|
// But it must not suppress struct field tags.
|
||||||
// See golang.org/issue/13777 and golang.org/issue/14331.
|
// See golang.org/issue/13777 and golang.org/issue/14331.
|
||||||
if flag&FmtShort == 0 && (!fmtbody || !f.Funarg) && f.Note != "" {
|
if flag&FmtShort == 0 && (!fmtbody || f.Funarg == FunargNone) && f.Note != "" {
|
||||||
str += " " + strconv.Quote(f.Note)
|
str += " " + strconv.Quote(f.Note)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,53 +43,39 @@ func addrescapes(n *Node) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
switch n.Class {
|
// If a closure reference escapes, mark the outer variable as escaping.
|
||||||
case PPARAMREF:
|
if n.isClosureVar() {
|
||||||
addrescapes(n.Name.Defn)
|
addrescapes(n.Name.Defn)
|
||||||
|
break
|
||||||
// if func param, need separate temporary
|
|
||||||
// to hold heap pointer.
|
|
||||||
// the function type has already been checked
|
|
||||||
// (we're in the function body)
|
|
||||||
// so the param already has a valid xoffset.
|
|
||||||
|
|
||||||
// expression to refer to stack copy
|
|
||||||
case PPARAM, PPARAMOUT:
|
|
||||||
n.Name.Param.Stackparam = Nod(OPARAM, n, nil)
|
|
||||||
|
|
||||||
n.Name.Param.Stackparam.Type = n.Type
|
|
||||||
n.Name.Param.Stackparam.Addable = true
|
|
||||||
if n.Xoffset == BADWIDTH {
|
|
||||||
Fatalf("addrescapes before param assignment")
|
|
||||||
}
|
|
||||||
n.Name.Param.Stackparam.Xoffset = n.Xoffset
|
|
||||||
fallthrough
|
|
||||||
|
|
||||||
case PAUTO:
|
|
||||||
n.Class |= PHEAP
|
|
||||||
|
|
||||||
n.Addable = false
|
|
||||||
n.Ullman = 2
|
|
||||||
n.Xoffset = 0
|
|
||||||
|
|
||||||
// create stack variable to hold pointer to heap
|
|
||||||
oldfn := Curfn
|
|
||||||
|
|
||||||
Curfn = n.Name.Curfn
|
|
||||||
if Curfn.Func.Closure != nil && Curfn.Op == OCLOSURE {
|
|
||||||
Curfn = Curfn.Func.Closure
|
|
||||||
}
|
|
||||||
n.Name.Heapaddr = temp(Ptrto(n.Type))
|
|
||||||
buf := fmt.Sprintf("&%v", n.Sym)
|
|
||||||
n.Name.Heapaddr.Sym = Lookup(buf)
|
|
||||||
n.Name.Heapaddr.Orig.Sym = n.Name.Heapaddr.Sym
|
|
||||||
n.Esc = EscHeap
|
|
||||||
if Debug['m'] != 0 {
|
|
||||||
fmt.Printf("%v: moved to heap: %v\n", n.Line(), n)
|
|
||||||
}
|
|
||||||
Curfn = oldfn
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if n.Class != PPARAM && n.Class != PPARAMOUT && n.Class != PAUTO {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a plain parameter or local variable that needs to move to the heap,
|
||||||
|
// but possibly for the function outside the one we're compiling.
|
||||||
|
// That is, if we have:
|
||||||
|
//
|
||||||
|
// func f(x int) {
|
||||||
|
// func() {
|
||||||
|
// global = &x
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// then we're analyzing the inner closure but we need to move x to the
|
||||||
|
// heap in f, not in the inner closure. Flip over to f before calling moveToHeap.
|
||||||
|
oldfn := Curfn
|
||||||
|
Curfn = n.Name.Curfn
|
||||||
|
if Curfn.Func.Closure != nil && Curfn.Op == OCLOSURE {
|
||||||
|
Curfn = Curfn.Func.Closure
|
||||||
|
}
|
||||||
|
ln := lineno
|
||||||
|
lineno = Curfn.Lineno
|
||||||
|
moveToHeap(n)
|
||||||
|
Curfn = oldfn
|
||||||
|
lineno = ln
|
||||||
|
|
||||||
case OIND, ODOTPTR:
|
case OIND, ODOTPTR:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
@ -105,6 +91,110 @@ func addrescapes(n *Node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isParamStackCopy reports whether this is the on-stack copy of a
|
||||||
|
// function parameter that moved to the heap.
|
||||||
|
func (n *Node) isParamStackCopy() bool {
|
||||||
|
return n.Op == ONAME && (n.Class == PPARAM || n.Class == PPARAMOUT) && n.Name.Heapaddr != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// isParamHeapCopy reports whether this is the on-heap copy of
|
||||||
|
// a function parameter that moved to the heap.
|
||||||
|
func (n *Node) isParamHeapCopy() bool {
|
||||||
|
return n.Op == ONAME && n.Class == PAUTOHEAP && n.Name.Param.Stackcopy != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// paramClass reports the parameter class (PPARAM or PPARAMOUT)
|
||||||
|
// of the node, which may be an unmoved on-stack parameter
|
||||||
|
// or the on-heap or on-stack copy of a parameter that moved to the heap.
|
||||||
|
// If the node is not a parameter, paramClass returns Pxxx.
|
||||||
|
func (n *Node) paramClass() Class {
|
||||||
|
if n.Op != ONAME {
|
||||||
|
return Pxxx
|
||||||
|
}
|
||||||
|
if n.Class == PPARAM || n.Class == PPARAMOUT {
|
||||||
|
return n.Class
|
||||||
|
}
|
||||||
|
if n.isParamHeapCopy() {
|
||||||
|
return n.Name.Param.Stackcopy.Class
|
||||||
|
}
|
||||||
|
return Pxxx
|
||||||
|
}
|
||||||
|
|
||||||
|
// moveToHeap records the parameter or local variable n as moved to the heap.
|
||||||
|
func moveToHeap(n *Node) {
|
||||||
|
if Debug['r'] != 0 {
|
||||||
|
Dump("MOVE", n)
|
||||||
|
}
|
||||||
|
if compiling_runtime {
|
||||||
|
Yyerror("%v escapes to heap, not allowed in runtime.", n)
|
||||||
|
}
|
||||||
|
if n.Class == PAUTOHEAP {
|
||||||
|
Dump("n", n)
|
||||||
|
Fatalf("double move to heap")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate a local stack variable to hold the pointer to the heap copy.
|
||||||
|
// temp will add it to the function declaration list automatically.
|
||||||
|
heapaddr := temp(Ptrto(n.Type))
|
||||||
|
heapaddr.Sym = Lookup("&" + n.Sym.Name)
|
||||||
|
heapaddr.Orig.Sym = heapaddr.Sym
|
||||||
|
|
||||||
|
// Parameters have a local stack copy used at function start/end
|
||||||
|
// in addition to the copy in the heap that may live longer than
|
||||||
|
// the function.
|
||||||
|
if n.Class == PPARAM || n.Class == PPARAMOUT {
|
||||||
|
if n.Xoffset == BADWIDTH {
|
||||||
|
Fatalf("addrescapes before param assignment")
|
||||||
|
}
|
||||||
|
|
||||||
|
// We rewrite n below to be a heap variable (indirection of heapaddr).
|
||||||
|
// Preserve a copy so we can still write code referring to the original,
|
||||||
|
// and substitute that copy into the function declaration list
|
||||||
|
// so that analyses of the local (on-stack) variables use it.
|
||||||
|
stackcopy := Nod(ONAME, nil, nil)
|
||||||
|
stackcopy.Sym = n.Sym
|
||||||
|
stackcopy.Type = n.Type
|
||||||
|
stackcopy.Xoffset = n.Xoffset
|
||||||
|
stackcopy.Class = n.Class
|
||||||
|
stackcopy.Name.Heapaddr = heapaddr
|
||||||
|
if n.Class == PPARAM {
|
||||||
|
stackcopy.SetNotLiveAtEnd(true)
|
||||||
|
}
|
||||||
|
n.Name.Param.Stackcopy = stackcopy
|
||||||
|
|
||||||
|
// Substitute the stackcopy into the function variable list so that
|
||||||
|
// liveness and other analyses use the underlying stack slot
|
||||||
|
// and not the now-pseudo-variable n.
|
||||||
|
found := false
|
||||||
|
for i, d := range Curfn.Func.Dcl {
|
||||||
|
if d == n {
|
||||||
|
Curfn.Func.Dcl[i] = stackcopy
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// Parameters are before locals, so can stop early.
|
||||||
|
// This limits the search even in functions with many local variables.
|
||||||
|
if d.Class == PAUTO {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
Fatalf("cannot find %v in local variable list", n)
|
||||||
|
}
|
||||||
|
Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modify n in place so that uses of n now mean indirection of the heapaddr.
|
||||||
|
n.Class = PAUTOHEAP
|
||||||
|
n.Ullman = 2
|
||||||
|
n.Xoffset = 0
|
||||||
|
n.Name.Heapaddr = heapaddr
|
||||||
|
n.Esc = EscHeap
|
||||||
|
if Debug['m'] != 0 {
|
||||||
|
fmt.Printf("%v: moved to heap: %v\n", n.Line(), n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func clearlabels() {
|
func clearlabels() {
|
||||||
for _, l := range labellist {
|
for _, l := range labellist {
|
||||||
l.Sym.Label = nil
|
l.Sym.Label = nil
|
||||||
|
|
@ -243,16 +333,9 @@ func cgen_dcl(n *Node) {
|
||||||
Fatalf("cgen_dcl")
|
Fatalf("cgen_dcl")
|
||||||
}
|
}
|
||||||
|
|
||||||
if n.Class&PHEAP == 0 {
|
if n.Class == PAUTOHEAP {
|
||||||
return
|
Fatalf("cgen_dcl %v", n)
|
||||||
}
|
}
|
||||||
if compiling_runtime {
|
|
||||||
Yyerror("%v escapes to heap, not allowed in runtime.", n)
|
|
||||||
}
|
|
||||||
if prealloc[n] == nil {
|
|
||||||
prealloc[n] = callnew(n.Type)
|
|
||||||
}
|
|
||||||
Cgen_as(n.Name.Heapaddr, prealloc[n])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate discard of value
|
// generate discard of value
|
||||||
|
|
@ -263,7 +346,7 @@ func cgen_discard(nr *Node) {
|
||||||
|
|
||||||
switch nr.Op {
|
switch nr.Op {
|
||||||
case ONAME:
|
case ONAME:
|
||||||
if nr.Class&PHEAP == 0 && nr.Class != PEXTERN && nr.Class != PFUNC && nr.Class != PPARAMREF {
|
if nr.Class != PAUTOHEAP && nr.Class != PEXTERN && nr.Class != PFUNC {
|
||||||
gused(nr)
|
gused(nr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -908,11 +991,6 @@ func Cgen_as_wb(nl, nr *Node, wb bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if nr == nil || iszero(nr) {
|
if nr == nil || iszero(nr) {
|
||||||
// heaps should already be clear
|
|
||||||
if nr == nil && (nl.Class&PHEAP != 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
tl := nl.Type
|
tl := nl.Type
|
||||||
if tl == nil {
|
if tl == nil {
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -91,14 +91,12 @@ const (
|
||||||
Pxxx Class = iota
|
Pxxx Class = iota
|
||||||
PEXTERN // global variable
|
PEXTERN // global variable
|
||||||
PAUTO // local variables
|
PAUTO // local variables
|
||||||
|
PAUTOHEAP // local variable or parameter moved to heap
|
||||||
PPARAM // input arguments
|
PPARAM // input arguments
|
||||||
PPARAMOUT // output results
|
PPARAMOUT // output results
|
||||||
PPARAMREF // closure variable reference
|
|
||||||
PFUNC // global function
|
PFUNC // global function
|
||||||
|
|
||||||
PDISCARD // discard during parse of duplicate import
|
PDISCARD // discard during parse of duplicate import
|
||||||
|
|
||||||
PHEAP = 1 << 7 // an extra bit to identify an escaped variable
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// note this is the runtime representation
|
// note this is the runtime representation
|
||||||
|
|
@ -133,6 +131,7 @@ var pragcgobuf string
|
||||||
var infile string
|
var infile string
|
||||||
|
|
||||||
var outfile string
|
var outfile string
|
||||||
|
var linkobj string
|
||||||
|
|
||||||
var bout *bio.Writer
|
var bout *bio.Writer
|
||||||
|
|
||||||
|
|
@ -260,8 +259,6 @@ var Widthreg int
|
||||||
|
|
||||||
var nblank *Node
|
var nblank *Node
|
||||||
|
|
||||||
var Funcdepth int32
|
|
||||||
|
|
||||||
var typecheckok bool
|
var typecheckok bool
|
||||||
|
|
||||||
var compiling_runtime bool
|
var compiling_runtime bool
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,6 @@ func Ismem(n *Node) bool {
|
||||||
OCAP,
|
OCAP,
|
||||||
OINDREG,
|
OINDREG,
|
||||||
ONAME,
|
ONAME,
|
||||||
OPARAM,
|
|
||||||
OCLOSUREVAR:
|
OCLOSUREVAR:
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
|
@ -349,18 +348,6 @@ func Naddr(a *obj.Addr, n *Node) {
|
||||||
a.Width = 0
|
a.Width = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// n->left is PHEAP ONAME for stack parameter.
|
|
||||||
// compute address of actual parameter on stack.
|
|
||||||
case OPARAM:
|
|
||||||
a.Etype = uint8(Simtype[n.Left.Type.Etype])
|
|
||||||
|
|
||||||
a.Width = n.Left.Type.Width
|
|
||||||
a.Offset = n.Xoffset
|
|
||||||
a.Sym = Linksym(n.Left.Sym)
|
|
||||||
a.Type = obj.TYPE_MEM
|
|
||||||
a.Name = obj.NAME_PARAM
|
|
||||||
a.Node = n.Left.Orig
|
|
||||||
|
|
||||||
case OCLOSUREVAR:
|
case OCLOSUREVAR:
|
||||||
if !Curfn.Func.Needctxt {
|
if !Curfn.Func.Needctxt {
|
||||||
Fatalf("closurevar without needctxt")
|
Fatalf("closurevar without needctxt")
|
||||||
|
|
@ -528,25 +515,36 @@ func newplist() *obj.Plist {
|
||||||
return pl
|
return pl
|
||||||
}
|
}
|
||||||
|
|
||||||
// nodarg does something that depends on the value of
|
// nodarg returns a Node for the function argument denoted by t,
|
||||||
// fp (this was previously completely undocumented).
|
// which is either the entire function argument or result struct (t is a struct *Type)
|
||||||
|
// or a specific argument (t is a *Field within a struct *Type).
|
||||||
//
|
//
|
||||||
// fp=1 corresponds to input args
|
// If fp is 0, the node is for use by a caller invoking the given
|
||||||
// fp=0 corresponds to output args
|
// function, preparing the arguments before the call
|
||||||
// fp=-1 is a special case of output args for a
|
// or retrieving the results after the call.
|
||||||
// specific call from walk that previously (and
|
// In this case, the node will correspond to an outgoing argument
|
||||||
// incorrectly) passed a 1; the behavior is exactly
|
// slot like 8(SP).
|
||||||
// the same as it is for 1, except that PARAMOUT is
|
//
|
||||||
// generated instead of PARAM.
|
// If fp is 1, the node is for use by the function itself
|
||||||
|
// (the callee), to retrieve its arguments or write its results.
|
||||||
|
// In this case the node will be an ONAME with an appropriate
|
||||||
|
// type and offset.
|
||||||
func nodarg(t interface{}, fp int) *Node {
|
func nodarg(t interface{}, fp int) *Node {
|
||||||
var n *Node
|
var n *Node
|
||||||
|
|
||||||
|
var funarg Funarg
|
||||||
switch t := t.(type) {
|
switch t := t.(type) {
|
||||||
|
default:
|
||||||
|
Fatalf("bad nodarg %T(%v)", t, t)
|
||||||
|
|
||||||
case *Type:
|
case *Type:
|
||||||
// entire argument struct, not just one arg
|
// Entire argument struct, not just one arg
|
||||||
if !t.IsFuncArgStruct() {
|
if !t.IsFuncArgStruct() {
|
||||||
Fatalf("nodarg: bad type %v", t)
|
Fatalf("nodarg: bad type %v", t)
|
||||||
}
|
}
|
||||||
|
funarg = t.StructType().Funarg
|
||||||
|
|
||||||
|
// Build fake variable name for whole arg struct.
|
||||||
n = Nod(ONAME, nil, nil)
|
n = Nod(ONAME, nil, nil)
|
||||||
n.Sym = Lookup(".args")
|
n.Sym = Lookup(".args")
|
||||||
n.Type = t
|
n.Type = t
|
||||||
|
|
@ -559,15 +557,43 @@ func nodarg(t interface{}, fp int) *Node {
|
||||||
}
|
}
|
||||||
n.Xoffset = first.Offset
|
n.Xoffset = first.Offset
|
||||||
n.Addable = true
|
n.Addable = true
|
||||||
|
|
||||||
case *Field:
|
case *Field:
|
||||||
if fp == 1 || fp == -1 {
|
funarg = t.Funarg
|
||||||
|
if fp == 1 {
|
||||||
|
// NOTE(rsc): This should be using t.Nname directly,
|
||||||
|
// except in the case where t.Nname.Sym is the blank symbol and
|
||||||
|
// so the assignment would be discarded during code generation.
|
||||||
|
// In that case we need to make a new node, and there is no harm
|
||||||
|
// in optimization passes to doing so. But otherwise we should
|
||||||
|
// definitely be using the actual declaration and not a newly built node.
|
||||||
|
// The extra Fatalf checks here are verifying that this is the case,
|
||||||
|
// without changing the actual logic (at time of writing, it's getting
|
||||||
|
// toward time for the Go 1.7 beta).
|
||||||
|
// At some quieter time (assuming we've never seen these Fatalfs happen)
|
||||||
|
// we could change this code to use "expect" directly.
|
||||||
|
expect := t.Nname
|
||||||
|
if expect.isParamHeapCopy() {
|
||||||
|
expect = expect.Name.Param.Stackcopy
|
||||||
|
}
|
||||||
|
|
||||||
for _, n := range Curfn.Func.Dcl {
|
for _, n := range Curfn.Func.Dcl {
|
||||||
if (n.Class == PPARAM || n.Class == PPARAMOUT) && !isblanksym(t.Sym) && n.Sym == t.Sym {
|
if (n.Class == PPARAM || n.Class == PPARAMOUT) && !isblanksym(t.Sym) && n.Sym == t.Sym {
|
||||||
|
if n != expect {
|
||||||
|
Fatalf("nodarg: unexpected node: %v (%p %v) vs %v (%p %v)", n, n, n.Op, t.Nname, t.Nname, t.Nname.Op)
|
||||||
|
}
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !isblanksym(expect.Sym) {
|
||||||
|
Fatalf("nodarg: did not find node in dcl list: %v", expect)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build fake name for individual variable.
|
||||||
|
// This is safe because if there was a real declared name
|
||||||
|
// we'd have used it above.
|
||||||
n = Nod(ONAME, nil, nil)
|
n = Nod(ONAME, nil, nil)
|
||||||
n.Type = t.Type
|
n.Type = t.Type
|
||||||
n.Sym = t.Sym
|
n.Sym = t.Sym
|
||||||
|
|
@ -577,8 +603,6 @@ func nodarg(t interface{}, fp int) *Node {
|
||||||
n.Xoffset = t.Offset
|
n.Xoffset = t.Offset
|
||||||
n.Addable = true
|
n.Addable = true
|
||||||
n.Orig = t.Nname
|
n.Orig = t.Nname
|
||||||
default:
|
|
||||||
panic("unreachable")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rewrite argument named _ to __,
|
// Rewrite argument named _ to __,
|
||||||
|
|
@ -589,23 +613,23 @@ func nodarg(t interface{}, fp int) *Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch fp {
|
switch fp {
|
||||||
case 0: // output arg
|
default:
|
||||||
n.Op = OINDREG
|
Fatalf("bad fp")
|
||||||
|
|
||||||
|
case 0: // preparing arguments for call
|
||||||
|
n.Op = OINDREG
|
||||||
n.Reg = int16(Thearch.REGSP)
|
n.Reg = int16(Thearch.REGSP)
|
||||||
n.Xoffset += Ctxt.FixedFrameSize()
|
n.Xoffset += Ctxt.FixedFrameSize()
|
||||||
|
|
||||||
case 1: // input arg
|
case 1: // reading arguments inside call
|
||||||
n.Class = PPARAM
|
n.Class = PPARAM
|
||||||
|
if funarg == FunargResults {
|
||||||
case -1: // output arg from paramstoheap
|
n.Class = PPARAMOUT
|
||||||
n.Class = PPARAMOUT
|
}
|
||||||
|
|
||||||
case 2: // offset output arg
|
|
||||||
Fatalf("shouldn't be used")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
n.Typecheck = 1
|
n.Typecheck = 1
|
||||||
|
n.Addrtaken = true // keep optimizers at bay
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,21 +31,22 @@ func renameinit() *Sym {
|
||||||
}
|
}
|
||||||
|
|
||||||
// hand-craft the following initialization code
|
// hand-craft the following initialization code
|
||||||
// var initdone· uint8 (1)
|
// var initdone· uint8 (1)
|
||||||
// func init() (2)
|
// func init() { (2)
|
||||||
// if initdone· > 1 { (3)
|
// if initdone· > 1 { (3)
|
||||||
// return (3a)
|
// return (3a)
|
||||||
// if initdone· == 1 { (4)
|
// }
|
||||||
// throw(); (4a)
|
// if initdone· == 1 { (4)
|
||||||
// }
|
// throw() (4a)
|
||||||
// initdone· = 1; (6)
|
// }
|
||||||
// // over all matching imported symbols
|
// initdone· = 1 (5)
|
||||||
// <pkg>.init() (7)
|
// // over all matching imported symbols
|
||||||
// { <init stmts> } (8)
|
// <pkg>.init() (6)
|
||||||
// init.<n>() // if any (9)
|
// { <init stmts> } (7)
|
||||||
// initdone· = 2; (10)
|
// init.<n>() // if any (8)
|
||||||
// return (11)
|
// initdone· = 2 (9)
|
||||||
// }
|
// return (10)
|
||||||
|
// }
|
||||||
func anyinit(n []*Node) bool {
|
func anyinit(n []*Node) bool {
|
||||||
// are there any interesting init statements
|
// are there any interesting init statements
|
||||||
for _, ln := range n {
|
for _, ln := range n {
|
||||||
|
|
@ -132,12 +133,12 @@ func fninit(n []*Node) {
|
||||||
// (4a)
|
// (4a)
|
||||||
b.Nbody.Set1(Nod(OCALL, syslook("throwinit"), nil))
|
b.Nbody.Set1(Nod(OCALL, syslook("throwinit"), nil))
|
||||||
|
|
||||||
// (6)
|
// (5)
|
||||||
a = Nod(OAS, gatevar, Nodintconst(1))
|
a = Nod(OAS, gatevar, Nodintconst(1))
|
||||||
|
|
||||||
r = append(r, a)
|
r = append(r, a)
|
||||||
|
|
||||||
// (7)
|
// (6)
|
||||||
for _, s := range initSyms {
|
for _, s := range initSyms {
|
||||||
if s.Def != nil && s != initsym {
|
if s.Def != nil && s != initsym {
|
||||||
// could check that it is fn of no args/returns
|
// could check that it is fn of no args/returns
|
||||||
|
|
@ -146,10 +147,10 @@ func fninit(n []*Node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// (8)
|
// (7)
|
||||||
r = append(r, nf...)
|
r = append(r, nf...)
|
||||||
|
|
||||||
// (9)
|
// (8)
|
||||||
// could check that it is fn of no args/returns
|
// could check that it is fn of no args/returns
|
||||||
for i := 1; ; i++ {
|
for i := 1; ; i++ {
|
||||||
s := LookupN("init.", i)
|
s := LookupN("init.", i)
|
||||||
|
|
@ -160,12 +161,12 @@ func fninit(n []*Node) {
|
||||||
r = append(r, a)
|
r = append(r, a)
|
||||||
}
|
}
|
||||||
|
|
||||||
// (10)
|
// (9)
|
||||||
a = Nod(OAS, gatevar, Nodintconst(2))
|
a = Nod(OAS, gatevar, Nodintconst(2))
|
||||||
|
|
||||||
r = append(r, a)
|
r = append(r, a)
|
||||||
|
|
||||||
// (11)
|
// (10)
|
||||||
a = Nod(ORETURN, nil, nil)
|
a = Nod(ORETURN, nil, nil)
|
||||||
|
|
||||||
r = append(r, a)
|
r = append(r, a)
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,7 @@
|
||||||
|
|
||||||
package gc
|
package gc
|
||||||
|
|
||||||
import (
|
import "fmt"
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Get the function's package. For ordinary functions it's on the ->sym, but for imported methods
|
// Get the function's package. For ordinary functions it's on the ->sym, but for imported methods
|
||||||
// the ->sym can be re-used in the local package, so peel it off the receiver's type.
|
// the ->sym can be re-used in the local package, so peel it off the receiver's type.
|
||||||
|
|
@ -180,6 +178,7 @@ func ishairy(n *Node, budget *int32) bool {
|
||||||
*budget -= fn.InlCost
|
*budget -= fn.InlCost
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if n.Left.Op == ONAME && n.Left.Left != nil && n.Left.Left.Op == OTYPE && n.Left.Right != nil && n.Left.Right.Op == ONAME { // methods called as functions
|
if n.Left.Op == ONAME && n.Left.Left != nil && n.Left.Left.Op == OTYPE && n.Left.Right != nil && n.Left.Right.Op == ONAME { // methods called as functions
|
||||||
if d := n.Left.Sym.Def; d != nil && d.Func.Inl.Len() != 0 {
|
if d := n.Left.Sym.Def; d != nil && d.Func.Inl.Len() != 0 {
|
||||||
*budget -= d.Func.InlCost
|
*budget -= d.Func.InlCost
|
||||||
|
|
@ -568,14 +567,13 @@ func mkinlcall1(n *Node, fn *Node, isddd bool) *Node {
|
||||||
if ln.Class == PPARAMOUT { // return values handled below.
|
if ln.Class == PPARAMOUT { // return values handled below.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if ln.isParamStackCopy() { // ignore the on-stack copy of a parameter that moved to the heap
|
||||||
|
continue
|
||||||
|
}
|
||||||
if ln.Op == ONAME {
|
if ln.Op == ONAME {
|
||||||
ln.Name.Inlvar = inlvar(ln)
|
ln.Name.Inlvar = typecheck(inlvar(ln), Erv)
|
||||||
|
if ln.Class == PPARAM || ln.Name.Param.Stackcopy != nil && ln.Name.Param.Stackcopy.Class == PPARAM {
|
||||||
// Typecheck because inlvar is not necessarily a function parameter.
|
ninit.Append(Nod(ODCL, ln.Name.Inlvar, nil))
|
||||||
ln.Name.Inlvar = typecheck(ln.Name.Inlvar, Erv)
|
|
||||||
|
|
||||||
if ln.Class&^PHEAP != PAUTO {
|
|
||||||
ninit.Append(Nod(ODCL, ln.Name.Inlvar, nil)) // otherwise gen won't emit the allocations for heapallocs
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
289
src/cmd/compile/internal/gc/logic_test.go
Normal file
289
src/cmd/compile/internal/gc/logic_test.go
Normal file
|
|
@ -0,0 +1,289 @@
|
||||||
|
package gc
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
// Tests to make sure logic simplification rules are correct.
|
||||||
|
|
||||||
|
func TestLogic64(t *testing.T) {
|
||||||
|
// test values to determine function equality
|
||||||
|
values := [...]int64{-1 << 63, 1<<63 - 1, -4, -3, -2, -1, 0, 1, 2, 3, 4}
|
||||||
|
|
||||||
|
// golden functions we use repeatedly
|
||||||
|
zero := func(x int64) int64 { return 0 }
|
||||||
|
id := func(x int64) int64 { return x }
|
||||||
|
or := func(x, y int64) int64 { return x | y }
|
||||||
|
and := func(x, y int64) int64 { return x & y }
|
||||||
|
y := func(x, y int64) int64 { return y }
|
||||||
|
|
||||||
|
for _, test := range [...]struct {
|
||||||
|
name string
|
||||||
|
f func(int64) int64
|
||||||
|
golden func(int64) int64
|
||||||
|
}{
|
||||||
|
{"x|x", func(x int64) int64 { return x | x }, id},
|
||||||
|
{"x|0", func(x int64) int64 { return x | 0 }, id},
|
||||||
|
{"x|-1", func(x int64) int64 { return x | -1 }, func(x int64) int64 { return -1 }},
|
||||||
|
{"x&x", func(x int64) int64 { return x & x }, id},
|
||||||
|
{"x&0", func(x int64) int64 { return x & 0 }, zero},
|
||||||
|
{"x&-1", func(x int64) int64 { return x & -1 }, id},
|
||||||
|
{"x^x", func(x int64) int64 { return x ^ x }, zero},
|
||||||
|
{"x^0", func(x int64) int64 { return x ^ 0 }, id},
|
||||||
|
{"x^-1", func(x int64) int64 { return x ^ -1 }, func(x int64) int64 { return ^x }},
|
||||||
|
{"x+0", func(x int64) int64 { return x + 0 }, id},
|
||||||
|
{"x-x", func(x int64) int64 { return x - x }, zero},
|
||||||
|
{"x*0", func(x int64) int64 { return x * 0 }, zero},
|
||||||
|
{"^^x", func(x int64) int64 { return ^^x }, id},
|
||||||
|
} {
|
||||||
|
for _, v := range values {
|
||||||
|
got := test.f(v)
|
||||||
|
want := test.golden(v)
|
||||||
|
if want != got {
|
||||||
|
t.Errorf("[%s](%d)=%d, want %d", test.name, v, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, test := range [...]struct {
|
||||||
|
name string
|
||||||
|
f func(int64, int64) int64
|
||||||
|
golden func(int64, int64) int64
|
||||||
|
}{
|
||||||
|
{"x|(x|y)", func(x, y int64) int64 { return x | (x | y) }, or},
|
||||||
|
{"x|(y|x)", func(x, y int64) int64 { return x | (y | x) }, or},
|
||||||
|
{"(x|y)|x", func(x, y int64) int64 { return (x | y) | x }, or},
|
||||||
|
{"(y|x)|x", func(x, y int64) int64 { return (y | x) | x }, or},
|
||||||
|
{"x&(x&y)", func(x, y int64) int64 { return x & (x & y) }, and},
|
||||||
|
{"x&(y&x)", func(x, y int64) int64 { return x & (y & x) }, and},
|
||||||
|
{"(x&y)&x", func(x, y int64) int64 { return (x & y) & x }, and},
|
||||||
|
{"(y&x)&x", func(x, y int64) int64 { return (y & x) & x }, and},
|
||||||
|
{"x^(x^y)", func(x, y int64) int64 { return x ^ (x ^ y) }, y},
|
||||||
|
{"x^(y^x)", func(x, y int64) int64 { return x ^ (y ^ x) }, y},
|
||||||
|
{"(x^y)^x", func(x, y int64) int64 { return (x ^ y) ^ x }, y},
|
||||||
|
{"(y^x)^x", func(x, y int64) int64 { return (y ^ x) ^ x }, y},
|
||||||
|
{"-(y-x)", func(x, y int64) int64 { return -(y - x) }, func(x, y int64) int64 { return x - y }},
|
||||||
|
{"(x+y)-x", func(x, y int64) int64 { return (x + y) - x }, y},
|
||||||
|
{"(y+x)-x", func(x, y int64) int64 { return (y + x) - x }, y},
|
||||||
|
} {
|
||||||
|
for _, v := range values {
|
||||||
|
for _, w := range values {
|
||||||
|
got := test.f(v, w)
|
||||||
|
want := test.golden(v, w)
|
||||||
|
if want != got {
|
||||||
|
t.Errorf("[%s](%d,%d)=%d, want %d", test.name, v, w, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLogic32(t *testing.T) {
|
||||||
|
// test values to determine function equality
|
||||||
|
values := [...]int32{-1 << 31, 1<<31 - 1, -4, -3, -2, -1, 0, 1, 2, 3, 4}
|
||||||
|
|
||||||
|
// golden functions we use repeatedly
|
||||||
|
zero := func(x int32) int32 { return 0 }
|
||||||
|
id := func(x int32) int32 { return x }
|
||||||
|
or := func(x, y int32) int32 { return x | y }
|
||||||
|
and := func(x, y int32) int32 { return x & y }
|
||||||
|
y := func(x, y int32) int32 { return y }
|
||||||
|
|
||||||
|
for _, test := range [...]struct {
|
||||||
|
name string
|
||||||
|
f func(int32) int32
|
||||||
|
golden func(int32) int32
|
||||||
|
}{
|
||||||
|
{"x|x", func(x int32) int32 { return x | x }, id},
|
||||||
|
{"x|0", func(x int32) int32 { return x | 0 }, id},
|
||||||
|
{"x|-1", func(x int32) int32 { return x | -1 }, func(x int32) int32 { return -1 }},
|
||||||
|
{"x&x", func(x int32) int32 { return x & x }, id},
|
||||||
|
{"x&0", func(x int32) int32 { return x & 0 }, zero},
|
||||||
|
{"x&-1", func(x int32) int32 { return x & -1 }, id},
|
||||||
|
{"x^x", func(x int32) int32 { return x ^ x }, zero},
|
||||||
|
{"x^0", func(x int32) int32 { return x ^ 0 }, id},
|
||||||
|
{"x^-1", func(x int32) int32 { return x ^ -1 }, func(x int32) int32 { return ^x }},
|
||||||
|
{"x+0", func(x int32) int32 { return x + 0 }, id},
|
||||||
|
{"x-x", func(x int32) int32 { return x - x }, zero},
|
||||||
|
{"x*0", func(x int32) int32 { return x * 0 }, zero},
|
||||||
|
{"^^x", func(x int32) int32 { return ^^x }, id},
|
||||||
|
} {
|
||||||
|
for _, v := range values {
|
||||||
|
got := test.f(v)
|
||||||
|
want := test.golden(v)
|
||||||
|
if want != got {
|
||||||
|
t.Errorf("[%s](%d)=%d, want %d", test.name, v, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, test := range [...]struct {
|
||||||
|
name string
|
||||||
|
f func(int32, int32) int32
|
||||||
|
golden func(int32, int32) int32
|
||||||
|
}{
|
||||||
|
{"x|(x|y)", func(x, y int32) int32 { return x | (x | y) }, or},
|
||||||
|
{"x|(y|x)", func(x, y int32) int32 { return x | (y | x) }, or},
|
||||||
|
{"(x|y)|x", func(x, y int32) int32 { return (x | y) | x }, or},
|
||||||
|
{"(y|x)|x", func(x, y int32) int32 { return (y | x) | x }, or},
|
||||||
|
{"x&(x&y)", func(x, y int32) int32 { return x & (x & y) }, and},
|
||||||
|
{"x&(y&x)", func(x, y int32) int32 { return x & (y & x) }, and},
|
||||||
|
{"(x&y)&x", func(x, y int32) int32 { return (x & y) & x }, and},
|
||||||
|
{"(y&x)&x", func(x, y int32) int32 { return (y & x) & x }, and},
|
||||||
|
{"x^(x^y)", func(x, y int32) int32 { return x ^ (x ^ y) }, y},
|
||||||
|
{"x^(y^x)", func(x, y int32) int32 { return x ^ (y ^ x) }, y},
|
||||||
|
{"(x^y)^x", func(x, y int32) int32 { return (x ^ y) ^ x }, y},
|
||||||
|
{"(y^x)^x", func(x, y int32) int32 { return (y ^ x) ^ x }, y},
|
||||||
|
{"-(y-x)", func(x, y int32) int32 { return -(y - x) }, func(x, y int32) int32 { return x - y }},
|
||||||
|
{"(x+y)-x", func(x, y int32) int32 { return (x + y) - x }, y},
|
||||||
|
{"(y+x)-x", func(x, y int32) int32 { return (y + x) - x }, y},
|
||||||
|
} {
|
||||||
|
for _, v := range values {
|
||||||
|
for _, w := range values {
|
||||||
|
got := test.f(v, w)
|
||||||
|
want := test.golden(v, w)
|
||||||
|
if want != got {
|
||||||
|
t.Errorf("[%s](%d,%d)=%d, want %d", test.name, v, w, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLogic16(t *testing.T) {
|
||||||
|
// test values to determine function equality
|
||||||
|
values := [...]int16{-1 << 15, 1<<15 - 1, -4, -3, -2, -1, 0, 1, 2, 3, 4}
|
||||||
|
|
||||||
|
// golden functions we use repeatedly
|
||||||
|
zero := func(x int16) int16 { return 0 }
|
||||||
|
id := func(x int16) int16 { return x }
|
||||||
|
or := func(x, y int16) int16 { return x | y }
|
||||||
|
and := func(x, y int16) int16 { return x & y }
|
||||||
|
y := func(x, y int16) int16 { return y }
|
||||||
|
|
||||||
|
for _, test := range [...]struct {
|
||||||
|
name string
|
||||||
|
f func(int16) int16
|
||||||
|
golden func(int16) int16
|
||||||
|
}{
|
||||||
|
{"x|x", func(x int16) int16 { return x | x }, id},
|
||||||
|
{"x|0", func(x int16) int16 { return x | 0 }, id},
|
||||||
|
{"x|-1", func(x int16) int16 { return x | -1 }, func(x int16) int16 { return -1 }},
|
||||||
|
{"x&x", func(x int16) int16 { return x & x }, id},
|
||||||
|
{"x&0", func(x int16) int16 { return x & 0 }, zero},
|
||||||
|
{"x&-1", func(x int16) int16 { return x & -1 }, id},
|
||||||
|
{"x^x", func(x int16) int16 { return x ^ x }, zero},
|
||||||
|
{"x^0", func(x int16) int16 { return x ^ 0 }, id},
|
||||||
|
{"x^-1", func(x int16) int16 { return x ^ -1 }, func(x int16) int16 { return ^x }},
|
||||||
|
{"x+0", func(x int16) int16 { return x + 0 }, id},
|
||||||
|
{"x-x", func(x int16) int16 { return x - x }, zero},
|
||||||
|
{"x*0", func(x int16) int16 { return x * 0 }, zero},
|
||||||
|
{"^^x", func(x int16) int16 { return ^^x }, id},
|
||||||
|
} {
|
||||||
|
for _, v := range values {
|
||||||
|
got := test.f(v)
|
||||||
|
want := test.golden(v)
|
||||||
|
if want != got {
|
||||||
|
t.Errorf("[%s](%d)=%d, want %d", test.name, v, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, test := range [...]struct {
|
||||||
|
name string
|
||||||
|
f func(int16, int16) int16
|
||||||
|
golden func(int16, int16) int16
|
||||||
|
}{
|
||||||
|
{"x|(x|y)", func(x, y int16) int16 { return x | (x | y) }, or},
|
||||||
|
{"x|(y|x)", func(x, y int16) int16 { return x | (y | x) }, or},
|
||||||
|
{"(x|y)|x", func(x, y int16) int16 { return (x | y) | x }, or},
|
||||||
|
{"(y|x)|x", func(x, y int16) int16 { return (y | x) | x }, or},
|
||||||
|
{"x&(x&y)", func(x, y int16) int16 { return x & (x & y) }, and},
|
||||||
|
{"x&(y&x)", func(x, y int16) int16 { return x & (y & x) }, and},
|
||||||
|
{"(x&y)&x", func(x, y int16) int16 { return (x & y) & x }, and},
|
||||||
|
{"(y&x)&x", func(x, y int16) int16 { return (y & x) & x }, and},
|
||||||
|
{"x^(x^y)", func(x, y int16) int16 { return x ^ (x ^ y) }, y},
|
||||||
|
{"x^(y^x)", func(x, y int16) int16 { return x ^ (y ^ x) }, y},
|
||||||
|
{"(x^y)^x", func(x, y int16) int16 { return (x ^ y) ^ x }, y},
|
||||||
|
{"(y^x)^x", func(x, y int16) int16 { return (y ^ x) ^ x }, y},
|
||||||
|
{"-(y-x)", func(x, y int16) int16 { return -(y - x) }, func(x, y int16) int16 { return x - y }},
|
||||||
|
{"(x+y)-x", func(x, y int16) int16 { return (x + y) - x }, y},
|
||||||
|
{"(y+x)-x", func(x, y int16) int16 { return (y + x) - x }, y},
|
||||||
|
} {
|
||||||
|
for _, v := range values {
|
||||||
|
for _, w := range values {
|
||||||
|
got := test.f(v, w)
|
||||||
|
want := test.golden(v, w)
|
||||||
|
if want != got {
|
||||||
|
t.Errorf("[%s](%d,%d)=%d, want %d", test.name, v, w, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLogic8(t *testing.T) {
|
||||||
|
// test values to determine function equality
|
||||||
|
values := [...]int8{-1 << 7, 1<<7 - 1, -4, -3, -2, -1, 0, 1, 2, 3, 4}
|
||||||
|
|
||||||
|
// golden functions we use repeatedly
|
||||||
|
zero := func(x int8) int8 { return 0 }
|
||||||
|
id := func(x int8) int8 { return x }
|
||||||
|
or := func(x, y int8) int8 { return x | y }
|
||||||
|
and := func(x, y int8) int8 { return x & y }
|
||||||
|
y := func(x, y int8) int8 { return y }
|
||||||
|
|
||||||
|
for _, test := range [...]struct {
|
||||||
|
name string
|
||||||
|
f func(int8) int8
|
||||||
|
golden func(int8) int8
|
||||||
|
}{
|
||||||
|
{"x|x", func(x int8) int8 { return x | x }, id},
|
||||||
|
{"x|0", func(x int8) int8 { return x | 0 }, id},
|
||||||
|
{"x|-1", func(x int8) int8 { return x | -1 }, func(x int8) int8 { return -1 }},
|
||||||
|
{"x&x", func(x int8) int8 { return x & x }, id},
|
||||||
|
{"x&0", func(x int8) int8 { return x & 0 }, zero},
|
||||||
|
{"x&-1", func(x int8) int8 { return x & -1 }, id},
|
||||||
|
{"x^x", func(x int8) int8 { return x ^ x }, zero},
|
||||||
|
{"x^0", func(x int8) int8 { return x ^ 0 }, id},
|
||||||
|
{"x^-1", func(x int8) int8 { return x ^ -1 }, func(x int8) int8 { return ^x }},
|
||||||
|
{"x+0", func(x int8) int8 { return x + 0 }, id},
|
||||||
|
{"x-x", func(x int8) int8 { return x - x }, zero},
|
||||||
|
{"x*0", func(x int8) int8 { return x * 0 }, zero},
|
||||||
|
{"^^x", func(x int8) int8 { return ^^x }, id},
|
||||||
|
} {
|
||||||
|
for _, v := range values {
|
||||||
|
got := test.f(v)
|
||||||
|
want := test.golden(v)
|
||||||
|
if want != got {
|
||||||
|
t.Errorf("[%s](%d)=%d, want %d", test.name, v, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, test := range [...]struct {
|
||||||
|
name string
|
||||||
|
f func(int8, int8) int8
|
||||||
|
golden func(int8, int8) int8
|
||||||
|
}{
|
||||||
|
{"x|(x|y)", func(x, y int8) int8 { return x | (x | y) }, or},
|
||||||
|
{"x|(y|x)", func(x, y int8) int8 { return x | (y | x) }, or},
|
||||||
|
{"(x|y)|x", func(x, y int8) int8 { return (x | y) | x }, or},
|
||||||
|
{"(y|x)|x", func(x, y int8) int8 { return (y | x) | x }, or},
|
||||||
|
{"x&(x&y)", func(x, y int8) int8 { return x & (x & y) }, and},
|
||||||
|
{"x&(y&x)", func(x, y int8) int8 { return x & (y & x) }, and},
|
||||||
|
{"(x&y)&x", func(x, y int8) int8 { return (x & y) & x }, and},
|
||||||
|
{"(y&x)&x", func(x, y int8) int8 { return (y & x) & x }, and},
|
||||||
|
{"x^(x^y)", func(x, y int8) int8 { return x ^ (x ^ y) }, y},
|
||||||
|
{"x^(y^x)", func(x, y int8) int8 { return x ^ (y ^ x) }, y},
|
||||||
|
{"(x^y)^x", func(x, y int8) int8 { return (x ^ y) ^ x }, y},
|
||||||
|
{"(y^x)^x", func(x, y int8) int8 { return (y ^ x) ^ x }, y},
|
||||||
|
{"-(y-x)", func(x, y int8) int8 { return -(y - x) }, func(x, y int8) int8 { return x - y }},
|
||||||
|
{"(x+y)-x", func(x, y int8) int8 { return (x + y) - x }, y},
|
||||||
|
{"(y+x)-x", func(x, y int8) int8 { return (y + x) - x }, y},
|
||||||
|
} {
|
||||||
|
for _, v := range values {
|
||||||
|
for _, w := range values {
|
||||||
|
got := test.f(v, w)
|
||||||
|
want := test.golden(v, w)
|
||||||
|
if want != got {
|
||||||
|
t.Errorf("[%s](%d,%d)=%d, want %d", test.name, v, w, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -178,6 +178,7 @@ func Main() {
|
||||||
flag.StringVar(&flag_installsuffix, "installsuffix", "", "set pkg directory `suffix`")
|
flag.StringVar(&flag_installsuffix, "installsuffix", "", "set pkg directory `suffix`")
|
||||||
obj.Flagcount("j", "debug runtime-initialized variables", &Debug['j'])
|
obj.Flagcount("j", "debug runtime-initialized variables", &Debug['j'])
|
||||||
obj.Flagcount("l", "disable inlining", &Debug['l'])
|
obj.Flagcount("l", "disable inlining", &Debug['l'])
|
||||||
|
flag.StringVar(&linkobj, "linkobj", "", "write linker-specific object to `file`")
|
||||||
obj.Flagcount("live", "debug liveness analysis", &debuglive)
|
obj.Flagcount("live", "debug liveness analysis", &debuglive)
|
||||||
obj.Flagcount("m", "print optimization decisions", &Debug['m'])
|
obj.Flagcount("m", "print optimization decisions", &Debug['m'])
|
||||||
flag.BoolVar(&flag_msan, "msan", false, "build code compatible with C/C++ memory sanitizer")
|
flag.BoolVar(&flag_msan, "msan", false, "build code compatible with C/C++ memory sanitizer")
|
||||||
|
|
@ -772,7 +773,7 @@ func importfile(f *Val, indent []byte) {
|
||||||
|
|
||||||
if p != "empty archive" {
|
if p != "empty archive" {
|
||||||
if !strings.HasPrefix(p, "go object ") {
|
if !strings.HasPrefix(p, "go object ") {
|
||||||
Yyerror("import %s: not a go object file", file)
|
Yyerror("import %s: not a go object file: %s", file, p)
|
||||||
errorexit()
|
errorexit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -783,6 +784,21 @@ func importfile(f *Val, indent []byte) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// process header lines
|
||||||
|
for {
|
||||||
|
p, err = imp.ReadString('\n')
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("reading input: %v", err)
|
||||||
|
}
|
||||||
|
if p == "\n" {
|
||||||
|
break // header ends with blank line
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(p, "safe") {
|
||||||
|
importpkg.Safe = true
|
||||||
|
break // ok to ignore rest
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// assume files move (get installed)
|
// assume files move (get installed)
|
||||||
// so don't record the full path.
|
// so don't record the full path.
|
||||||
linehistpragma(file[len(file)-len(path_)-2:]) // acts as #pragma lib
|
linehistpragma(file[len(file)-len(path_)-2:]) // acts as #pragma lib
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
// Run this after changing builtin/runtime.go and builtin/unsafe.go
|
// Run this after changing builtin/runtime.go and builtin/unsafe.go
|
||||||
// or after changing the export metadata format in the compiler.
|
// or after changing the export metadata format in the compiler.
|
||||||
// Either way, you need to have a working compiler binary first.
|
// Either way, you need to have a working compiler binary first.
|
||||||
|
// See bexport.go for how to make an export metadata format change.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,34 @@ func formathdr(arhdr []byte, name string, size int64) {
|
||||||
copy(arhdr[:], fmt.Sprintf("%-16s%-12d%-6d%-6d%-8o%-10d`\n", name, 0, 0, 0, 0644, size))
|
copy(arhdr[:], fmt.Sprintf("%-16s%-12d%-6d%-6d%-8o%-10d`\n", name, 0, 0, 0, 0644, size))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// These modes say which kind of object file to generate.
|
||||||
|
// The default use of the toolchain is to set both bits,
|
||||||
|
// generating a combined compiler+linker object, one that
|
||||||
|
// serves to describe the package to both the compiler and the linker.
|
||||||
|
// In fact the compiler and linker read nearly disjoint sections of
|
||||||
|
// that file, though, so in a distributed build setting it can be more
|
||||||
|
// efficient to split the output into two files, supplying the compiler
|
||||||
|
// object only to future compilations and the linker object only to
|
||||||
|
// future links.
|
||||||
|
//
|
||||||
|
// By default a combined object is written, but if -linkobj is specified
|
||||||
|
// on the command line then the default -o output is a compiler object
|
||||||
|
// and the -linkobj output is a linker object.
|
||||||
|
const (
|
||||||
|
modeCompilerObj = 1 << iota
|
||||||
|
modeLinkerObj
|
||||||
|
)
|
||||||
|
|
||||||
func dumpobj() {
|
func dumpobj() {
|
||||||
|
if linkobj == "" {
|
||||||
|
dumpobj1(outfile, modeCompilerObj|modeLinkerObj)
|
||||||
|
} else {
|
||||||
|
dumpobj1(outfile, modeCompilerObj)
|
||||||
|
dumpobj1(linkobj, modeLinkerObj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dumpobj1(outfile string, mode int) {
|
||||||
var err error
|
var err error
|
||||||
bout, err = bio.Create(outfile)
|
bout, err = bio.Create(outfile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -40,8 +67,27 @@ func dumpobj() {
|
||||||
startobj = bout.Offset()
|
startobj = bout.Offset()
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring())
|
printheader := func() {
|
||||||
dumpexport()
|
fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring())
|
||||||
|
if buildid != "" {
|
||||||
|
fmt.Fprintf(bout, "build id %q\n", buildid)
|
||||||
|
}
|
||||||
|
if localpkg.Name == "main" {
|
||||||
|
fmt.Fprintf(bout, "main\n")
|
||||||
|
}
|
||||||
|
if safemode {
|
||||||
|
fmt.Fprintf(bout, "safe\n")
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(bout, "----\n") // room for some other tool to write "safe"
|
||||||
|
}
|
||||||
|
fmt.Fprintf(bout, "\n") // header ends with blank line
|
||||||
|
}
|
||||||
|
|
||||||
|
printheader()
|
||||||
|
|
||||||
|
if mode&modeCompilerObj != 0 {
|
||||||
|
dumpexport()
|
||||||
|
}
|
||||||
|
|
||||||
if writearchive {
|
if writearchive {
|
||||||
bout.Flush()
|
bout.Flush()
|
||||||
|
|
@ -53,12 +99,20 @@ func dumpobj() {
|
||||||
formathdr(arhdr[:], "__.PKGDEF", size)
|
formathdr(arhdr[:], "__.PKGDEF", size)
|
||||||
bout.Write(arhdr[:])
|
bout.Write(arhdr[:])
|
||||||
bout.Flush()
|
bout.Flush()
|
||||||
|
|
||||||
bout.Seek(startobj+size+(size&1), 0)
|
bout.Seek(startobj+size+(size&1), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mode&modeLinkerObj == 0 {
|
||||||
|
bout.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if writearchive {
|
||||||
|
// start object file
|
||||||
arhdr = [ArhdrSize]byte{}
|
arhdr = [ArhdrSize]byte{}
|
||||||
bout.Write(arhdr[:])
|
bout.Write(arhdr[:])
|
||||||
startobj = bout.Offset()
|
startobj = bout.Offset()
|
||||||
fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring())
|
printheader()
|
||||||
}
|
}
|
||||||
|
|
||||||
if pragcgobuf != "" {
|
if pragcgobuf != "" {
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,6 @@ var opnames = []string{
|
||||||
OINDEX: "INDEX",
|
OINDEX: "INDEX",
|
||||||
OINDEXMAP: "INDEXMAP",
|
OINDEXMAP: "INDEXMAP",
|
||||||
OKEY: "KEY",
|
OKEY: "KEY",
|
||||||
OPARAM: "PARAM",
|
|
||||||
OLEN: "LEN",
|
OLEN: "LEN",
|
||||||
OMAKE: "MAKE",
|
OMAKE: "MAKE",
|
||||||
OMAKECHAN: "MAKECHAN",
|
OMAKECHAN: "MAKECHAN",
|
||||||
|
|
|
||||||
|
|
@ -1082,6 +1082,20 @@ func orderexpr(n *Node, order *Order, lhs *Node) *Node {
|
||||||
n.Left = orderaddrtemp(n.Left, order)
|
n.Left = orderaddrtemp(n.Left, order)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case OCONVNOP:
|
||||||
|
if n.Type.IsKind(TUNSAFEPTR) && n.Left.Type.IsKind(TUINTPTR) && (n.Left.Op == OCALLFUNC || n.Left.Op == OCALLINTER || n.Left.Op == OCALLMETH) {
|
||||||
|
// When reordering unsafe.Pointer(f()) into a separate
|
||||||
|
// statement, the conversion and function call must stay
|
||||||
|
// together. See golang.org/issue/15329.
|
||||||
|
orderinit(n.Left, order)
|
||||||
|
ordercall(n.Left, order)
|
||||||
|
if lhs == nil || lhs.Op != ONAME || instrumenting {
|
||||||
|
n = ordercopyexpr(n, n.Type, order, 0)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
n.Left = orderexpr(n.Left, order, nil)
|
||||||
|
}
|
||||||
|
|
||||||
case OANDAND, OOROR:
|
case OANDAND, OOROR:
|
||||||
mark := marktemp(order)
|
mark := marktemp(order)
|
||||||
n.Left = orderexpr(n.Left, order, nil)
|
n.Left = orderexpr(n.Left, order, nil)
|
||||||
|
|
|
||||||
|
|
@ -398,11 +398,8 @@ func (p *parser) import_package() {
|
||||||
p.import_error()
|
p.import_error()
|
||||||
}
|
}
|
||||||
|
|
||||||
importsafe := false
|
// read but skip "safe" bit (see issue #15772)
|
||||||
if p.tok == LNAME {
|
if p.tok == LNAME {
|
||||||
if p.sym_.Name == "safe" {
|
|
||||||
importsafe = true
|
|
||||||
}
|
|
||||||
p.next()
|
p.next()
|
||||||
}
|
}
|
||||||
p.want(';')
|
p.want(';')
|
||||||
|
|
@ -413,7 +410,6 @@ func (p *parser) import_package() {
|
||||||
} else if importpkg.Name != name {
|
} else if importpkg.Name != name {
|
||||||
Yyerror("conflicting names %s and %s for package %q", importpkg.Name, name, importpkg.Path)
|
Yyerror("conflicting names %s and %s for package %q", importpkg.Name, name, importpkg.Path)
|
||||||
}
|
}
|
||||||
importpkg.Safe = importsafe
|
|
||||||
|
|
||||||
typecheckok = true
|
typecheckok = true
|
||||||
defercheckwidth()
|
defercheckwidth()
|
||||||
|
|
|
||||||
|
|
@ -197,54 +197,41 @@ func blockany(bb *BasicBlock, f func(*obj.Prog) bool) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collects and returns a slice of *Nodes for functions arguments and local
|
// livenessShouldTrack reports whether the liveness analysis
|
||||||
// variables.
|
// should track the variable n.
|
||||||
|
// We don't care about variables that have no pointers,
|
||||||
|
// nor do we care about non-local variables,
|
||||||
|
// nor do we care about empty structs (handled by the pointer check),
|
||||||
|
// nor do we care about the fake PAUTOHEAP variables.
|
||||||
|
func livenessShouldTrack(n *Node) bool {
|
||||||
|
return n.Op == ONAME && (n.Class == PAUTO || n.Class == PPARAM || n.Class == PPARAMOUT) && haspointers(n.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getvariables returns the list of on-stack variables that we need to track.
|
||||||
func getvariables(fn *Node) []*Node {
|
func getvariables(fn *Node) []*Node {
|
||||||
var result []*Node
|
var vars []*Node
|
||||||
for _, ln := range fn.Func.Dcl {
|
for _, n := range fn.Func.Dcl {
|
||||||
if ln.Op == ONAME {
|
if n.Op == ONAME {
|
||||||
// In order for GODEBUG=gcdead=1 to work, each bitmap needs
|
|
||||||
// to contain information about all variables covered by the bitmap.
|
|
||||||
// For local variables, the bitmap only covers the stkptrsize
|
|
||||||
// bytes in the frame where variables containing pointers live.
|
|
||||||
// For arguments and results, the bitmap covers all variables,
|
|
||||||
// so we must include all the variables, even the ones without
|
|
||||||
// pointers.
|
|
||||||
//
|
|
||||||
// The Node.opt field is available for use by optimization passes.
|
// The Node.opt field is available for use by optimization passes.
|
||||||
// We use it to hold the index of the node in the variables array, plus 1
|
// We use it to hold the index of the node in the variables array
|
||||||
// (so that 0 means the Node is not in the variables array).
|
// (nil means the Node is not in the variables array).
|
||||||
// Each pass should clear opt when done, but you never know,
|
|
||||||
// so clear them all ourselves too.
|
|
||||||
// The Node.curfn field is supposed to be set to the current function
|
// The Node.curfn field is supposed to be set to the current function
|
||||||
// already, but for some compiler-introduced names it seems not to be,
|
// already, but for some compiler-introduced names it seems not to be,
|
||||||
// so fix that here.
|
// so fix that here.
|
||||||
// Later, when we want to find the index of a node in the variables list,
|
// Later, when we want to find the index of a node in the variables list,
|
||||||
// we will check that n.curfn == curfn and n.opt > 0. Then n.opt - 1
|
// we will check that n.Curfn == Curfn and n.Opt() != nil. Then n.Opt().(int32)
|
||||||
// is the index in the variables list.
|
// is the index in the variables list.
|
||||||
ln.SetOpt(nil)
|
n.SetOpt(nil)
|
||||||
|
n.Name.Curfn = Curfn
|
||||||
|
}
|
||||||
|
|
||||||
// The compiler doesn't emit initializations for zero-width parameters or results.
|
if livenessShouldTrack(n) {
|
||||||
if ln.Type.Width == 0 {
|
n.SetOpt(int32(len(vars)))
|
||||||
continue
|
vars = append(vars, n)
|
||||||
}
|
|
||||||
|
|
||||||
ln.Name.Curfn = Curfn
|
|
||||||
switch ln.Class {
|
|
||||||
case PAUTO:
|
|
||||||
if haspointers(ln.Type) {
|
|
||||||
ln.SetOpt(int32(len(result)))
|
|
||||||
result = append(result, ln)
|
|
||||||
}
|
|
||||||
|
|
||||||
case PPARAM, PPARAMOUT:
|
|
||||||
ln.SetOpt(int32(len(result)))
|
|
||||||
result = append(result, ln)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return vars
|
||||||
}
|
}
|
||||||
|
|
||||||
// A pretty printer for control flow graphs. Takes a slice of *BasicBlocks.
|
// A pretty printer for control flow graphs. Takes a slice of *BasicBlocks.
|
||||||
|
|
@ -567,9 +554,11 @@ func progeffects(prog *obj.Prog, vars []*Node, uevar bvec, varkill bvec, avarini
|
||||||
// read the out arguments - they won't be set until the new
|
// read the out arguments - they won't be set until the new
|
||||||
// function runs.
|
// function runs.
|
||||||
for i, node := range vars {
|
for i, node := range vars {
|
||||||
switch node.Class &^ PHEAP {
|
switch node.Class {
|
||||||
case PPARAM:
|
case PPARAM:
|
||||||
bvset(uevar, int32(i))
|
if !node.NotLiveAtEnd() {
|
||||||
|
bvset(uevar, int32(i))
|
||||||
|
}
|
||||||
|
|
||||||
// If the result had its address taken, it is being tracked
|
// If the result had its address taken, it is being tracked
|
||||||
// by the avarinit code, which does not use uevar.
|
// by the avarinit code, which does not use uevar.
|
||||||
|
|
@ -593,7 +582,7 @@ func progeffects(prog *obj.Prog, vars []*Node, uevar bvec, varkill bvec, avarini
|
||||||
// A text instruction marks the entry point to a function and
|
// A text instruction marks the entry point to a function and
|
||||||
// the definition point of all in arguments.
|
// the definition point of all in arguments.
|
||||||
for i, node := range vars {
|
for i, node := range vars {
|
||||||
switch node.Class &^ PHEAP {
|
switch node.Class {
|
||||||
case PPARAM:
|
case PPARAM:
|
||||||
if node.Addrtaken {
|
if node.Addrtaken {
|
||||||
bvset(avarinit, int32(i))
|
bvset(avarinit, int32(i))
|
||||||
|
|
@ -607,24 +596,17 @@ func progeffects(prog *obj.Prog, vars []*Node, uevar bvec, varkill bvec, avarini
|
||||||
|
|
||||||
if prog.Info.Flags&(LeftRead|LeftWrite|LeftAddr) != 0 {
|
if prog.Info.Flags&(LeftRead|LeftWrite|LeftAddr) != 0 {
|
||||||
from := &prog.From
|
from := &prog.From
|
||||||
if from.Node != nil && from.Sym != nil && ((from.Node).(*Node)).Name.Curfn == Curfn {
|
if from.Node != nil && from.Sym != nil {
|
||||||
switch ((from.Node).(*Node)).Class &^ PHEAP {
|
n := from.Node.(*Node)
|
||||||
case PAUTO, PPARAM, PPARAMOUT:
|
if pos := liveIndex(n, vars); pos >= 0 {
|
||||||
pos, ok := from.Node.(*Node).Opt().(int32) // index in vars
|
if n.Addrtaken {
|
||||||
if !ok {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if pos >= int32(len(vars)) || vars[pos] != from.Node {
|
|
||||||
Fatalf("bad bookkeeping in liveness %v %d", Nconv(from.Node.(*Node), 0), pos)
|
|
||||||
}
|
|
||||||
if ((from.Node).(*Node)).Addrtaken {
|
|
||||||
bvset(avarinit, pos)
|
bvset(avarinit, pos)
|
||||||
} else {
|
} else {
|
||||||
if prog.Info.Flags&(LeftRead|LeftAddr) != 0 {
|
if prog.Info.Flags&(LeftRead|LeftAddr) != 0 {
|
||||||
bvset(uevar, pos)
|
bvset(uevar, pos)
|
||||||
}
|
}
|
||||||
if prog.Info.Flags&LeftWrite != 0 {
|
if prog.Info.Flags&LeftWrite != 0 {
|
||||||
if from.Node != nil && !Isfat(((from.Node).(*Node)).Type) {
|
if !Isfat(n.Type) {
|
||||||
bvset(varkill, pos)
|
bvset(varkill, pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -635,17 +617,10 @@ func progeffects(prog *obj.Prog, vars []*Node, uevar bvec, varkill bvec, avarini
|
||||||
|
|
||||||
if prog.Info.Flags&(RightRead|RightWrite|RightAddr) != 0 {
|
if prog.Info.Flags&(RightRead|RightWrite|RightAddr) != 0 {
|
||||||
to := &prog.To
|
to := &prog.To
|
||||||
if to.Node != nil && to.Sym != nil && ((to.Node).(*Node)).Name.Curfn == Curfn {
|
if to.Node != nil && to.Sym != nil {
|
||||||
switch ((to.Node).(*Node)).Class &^ PHEAP {
|
n := to.Node.(*Node)
|
||||||
case PAUTO, PPARAM, PPARAMOUT:
|
if pos := liveIndex(n, vars); pos >= 0 {
|
||||||
pos, ok := to.Node.(*Node).Opt().(int32) // index in vars
|
if n.Addrtaken {
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if pos >= int32(len(vars)) || vars[pos] != to.Node {
|
|
||||||
Fatalf("bad bookkeeping in liveness %v %d", Nconv(to.Node.(*Node), 0), pos)
|
|
||||||
}
|
|
||||||
if ((to.Node).(*Node)).Addrtaken {
|
|
||||||
if prog.As != obj.AVARKILL {
|
if prog.As != obj.AVARKILL {
|
||||||
bvset(avarinit, pos)
|
bvset(avarinit, pos)
|
||||||
}
|
}
|
||||||
|
|
@ -665,7 +640,7 @@ func progeffects(prog *obj.Prog, vars []*Node, uevar bvec, varkill bvec, avarini
|
||||||
bvset(uevar, pos)
|
bvset(uevar, pos)
|
||||||
}
|
}
|
||||||
if prog.Info.Flags&RightWrite != 0 {
|
if prog.Info.Flags&RightWrite != 0 {
|
||||||
if to.Node != nil && (!Isfat(((to.Node).(*Node)).Type) || prog.As == obj.AVARDEF) {
|
if !Isfat(n.Type) || prog.As == obj.AVARDEF {
|
||||||
bvset(varkill, pos)
|
bvset(varkill, pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -675,6 +650,24 @@ func progeffects(prog *obj.Prog, vars []*Node, uevar bvec, varkill bvec, avarini
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// liveIndex returns the index of n in the set of tracked vars.
|
||||||
|
// If n is not a tracked var, liveIndex returns -1.
|
||||||
|
// If n is not a tracked var but should be tracked, liveIndex crashes.
|
||||||
|
func liveIndex(n *Node, vars []*Node) int32 {
|
||||||
|
if n.Name.Curfn != Curfn || !livenessShouldTrack(n) {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
pos, ok := n.Opt().(int32) // index in vars
|
||||||
|
if !ok {
|
||||||
|
Fatalf("lost track of variable in liveness: %v (%p, %p)", n, n, n.Orig)
|
||||||
|
}
|
||||||
|
if pos >= int32(len(vars)) || vars[pos] != n {
|
||||||
|
Fatalf("bad bookkeeping in liveness: %v (%p, %p)", n, n, n.Orig)
|
||||||
|
}
|
||||||
|
return pos
|
||||||
|
}
|
||||||
|
|
||||||
// Constructs a new liveness structure used to hold the global state of the
|
// Constructs a new liveness structure used to hold the global state of the
|
||||||
// liveness computation. The cfg argument is a slice of *BasicBlocks and the
|
// liveness computation. The cfg argument is a slice of *BasicBlocks and the
|
||||||
// vars argument is a slice of *Nodes.
|
// vars argument is a slice of *Nodes.
|
||||||
|
|
@ -812,8 +805,7 @@ func checkparam(fn *Node, p *obj.Prog, n *Node) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, a := range fn.Func.Dcl {
|
for _, a := range fn.Func.Dcl {
|
||||||
class := a.Class &^ PHEAP
|
if a.Op == ONAME && (a.Class == PPARAM || a.Class == PPARAMOUT) && a == n {
|
||||||
if a.Op == ONAME && (class == PPARAM || class == PPARAMOUT) && a == n {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -980,23 +972,6 @@ func onebitlivepointermap(lv *Liveness, liveout bvec, vars []*Node, args bvec, l
|
||||||
onebitwalktype1(node.Type, &xoffset, args)
|
onebitwalktype1(node.Type, &xoffset, args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The node list only contains declared names.
|
|
||||||
// If the receiver or arguments are unnamed, they will be omitted
|
|
||||||
// from the list above. Preserve those values - even though they are unused -
|
|
||||||
// in order to keep their addresses live for use in stack traces.
|
|
||||||
thisargtype := lv.fn.Type.Recvs()
|
|
||||||
|
|
||||||
if thisargtype != nil {
|
|
||||||
xoffset = 0
|
|
||||||
onebitwalktype1(thisargtype, &xoffset, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
inargtype := lv.fn.Type.Params()
|
|
||||||
if inargtype != nil {
|
|
||||||
xoffset = 0
|
|
||||||
onebitwalktype1(inargtype, &xoffset, args)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct a disembodied instruction.
|
// Construct a disembodied instruction.
|
||||||
|
|
|
||||||
|
|
@ -419,7 +419,6 @@ func instrumentnode(np **Node, init *Nodes, wr int, skip int) {
|
||||||
case OPRINT, // don't bother instrumenting it
|
case OPRINT, // don't bother instrumenting it
|
||||||
OPRINTN, // don't bother instrumenting it
|
OPRINTN, // don't bother instrumenting it
|
||||||
OCHECKNIL, // always followed by a read.
|
OCHECKNIL, // always followed by a read.
|
||||||
OPARAM, // it appears only in fn->exit to copy heap params back
|
|
||||||
OCLOSUREVAR, // immutable pointer to captured variable
|
OCLOSUREVAR, // immutable pointer to captured variable
|
||||||
ODOTMETH, // either part of CALLMETH or CALLPART (lowered to PTRLIT)
|
ODOTMETH, // either part of CALLMETH or CALLPART (lowered to PTRLIT)
|
||||||
OINDREG, // at this stage, only n(SP) nodes from nodarg
|
OINDREG, // at this stage, only n(SP) nodes from nodarg
|
||||||
|
|
@ -496,7 +495,7 @@ func callinstr(np **Node, init *Nodes, wr int, skip int) bool {
|
||||||
// e.g. if we've got a local variable/method receiver
|
// e.g. if we've got a local variable/method receiver
|
||||||
// that has got a pointer inside. Whether it points to
|
// that has got a pointer inside. Whether it points to
|
||||||
// the heap or not is impossible to know at compile time
|
// the heap or not is impossible to know at compile time
|
||||||
if (class&PHEAP != 0) || class == PPARAMREF || class == PEXTERN || b.Op == OINDEX || b.Op == ODOTPTR || b.Op == OIND {
|
if class == PAUTOHEAP || class == PEXTERN || b.Op == OINDEX || b.Op == ODOTPTR || b.Op == OIND {
|
||||||
hascalls := 0
|
hascalls := 0
|
||||||
foreach(n, hascallspred, &hascalls)
|
foreach(n, hascallspred, &hascalls)
|
||||||
if hascalls != 0 {
|
if hascalls != 0 {
|
||||||
|
|
|
||||||
|
|
@ -516,7 +516,7 @@ func isliteral(n *Node) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) isSimpleName() bool {
|
func (n *Node) isSimpleName() bool {
|
||||||
return n.Op == ONAME && n.Addable && n.Class&PHEAP == 0 && n.Class != PPARAMREF
|
return n.Op == ONAME && n.Addable && n.Class != PAUTOHEAP
|
||||||
}
|
}
|
||||||
|
|
||||||
func litas(l *Node, r *Node, init *Nodes) {
|
func litas(l *Node, r *Node, init *Nodes) {
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ func TestSizeof(t *testing.T) {
|
||||||
_64bit uintptr // size on 64bit platforms
|
_64bit uintptr // size on 64bit platforms
|
||||||
}{
|
}{
|
||||||
{Flow{}, 52, 88},
|
{Flow{}, 52, 88},
|
||||||
{Func{}, 96, 168},
|
{Func{}, 92, 160},
|
||||||
{Name{}, 52, 80},
|
{Name{}, 52, 80},
|
||||||
{Node{}, 92, 144},
|
{Node{}, 92, 144},
|
||||||
{Sym{}, 60, 112},
|
{Sym{}, 60, 112},
|
||||||
|
|
|
||||||
199
src/cmd/compile/internal/gc/sparselocatephifunctions.go
Normal file
199
src/cmd/compile/internal/gc/sparselocatephifunctions.go
Normal file
|
|
@ -0,0 +1,199 @@
|
||||||
|
// Copyright 2016 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 gc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cmd/compile/internal/ssa"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
|
// sparseDefState contains a Go map from ONAMEs (*Node) to sparse definition trees, and
|
||||||
|
// a search helper for the CFG's dominator tree in which those definitions are embedded.
|
||||||
|
// Once initialized, given a use of an ONAME within a block, the ssa definition for
|
||||||
|
// that ONAME can be discovered in time roughly proportional to the log of the number
|
||||||
|
// of SSA definitions of that ONAME (thus avoiding pathological quadratic behavior for
|
||||||
|
// very large programs). The helper contains state (a dominator tree numbering) common
|
||||||
|
// to all the sparse definition trees, as well as some necessary data obtained from
|
||||||
|
// the ssa package.
|
||||||
|
//
|
||||||
|
// This algorithm has improved asymptotic complexity, but the constant factor is
|
||||||
|
// rather large and thus it is only preferred for very large inputs containing
|
||||||
|
// 1000s of blocks and variables.
|
||||||
|
type sparseDefState struct {
|
||||||
|
helper *ssa.SparseTreeHelper // contains one copy of information needed to do sparse mapping
|
||||||
|
defmapForOname map[*Node]*onameDefs // for each ONAME, its definition set (normal and phi)
|
||||||
|
}
|
||||||
|
|
||||||
|
// onameDefs contains a record of definitions (ordinary and implied phi function) for a single OName.
|
||||||
|
// stm is the set of definitions for the OName.
|
||||||
|
// firstdef and lastuse are postorder block numberings that
|
||||||
|
// conservatively bracket the entire lifetime of the OName.
|
||||||
|
type onameDefs struct {
|
||||||
|
stm *ssa.SparseTreeMap
|
||||||
|
// firstdef and lastuse define an interval in the postorder numbering
|
||||||
|
// that is guaranteed to include the entire lifetime of an ONAME.
|
||||||
|
// In the postorder numbering, math.MaxInt32 is before anything,
|
||||||
|
// and 0 is after-or-equal all exit nodes and infinite loops.
|
||||||
|
firstdef int32 // the first definition of this ONAME *in the postorder numbering*
|
||||||
|
lastuse int32 // the last use of this ONAME *in the postorder numbering*
|
||||||
|
}
|
||||||
|
|
||||||
|
// defsFor finds or creates-and-inserts-in-map the definition information
|
||||||
|
// (sparse tree and live range) for a given OName.
|
||||||
|
func (m *sparseDefState) defsFor(n *Node) *onameDefs {
|
||||||
|
d := m.defmapForOname[n]
|
||||||
|
if d != nil {
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
// Reminder: firstdef/lastuse are postorder indices, not block indices,
|
||||||
|
// so these default values define an empty interval, not the entire one.
|
||||||
|
d = &onameDefs{stm: m.helper.NewTree(), firstdef: 0, lastuse: math.MaxInt32}
|
||||||
|
m.defmapForOname[n] = d
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert adds a definition at b (with specified before/within/after adjustment)
|
||||||
|
// to sparse tree onameDefs. The lifetime is extended as necessary.
|
||||||
|
func (m *sparseDefState) Insert(tree *onameDefs, b *ssa.Block, adjust int32) {
|
||||||
|
bponum := m.helper.Ponums[b.ID]
|
||||||
|
if bponum > tree.firstdef {
|
||||||
|
tree.firstdef = bponum
|
||||||
|
}
|
||||||
|
tree.stm.Insert(b, adjust, b, m.helper)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use updates tree to record a use within b, extending the lifetime as necessary.
|
||||||
|
func (m *sparseDefState) Use(tree *onameDefs, b *ssa.Block) {
|
||||||
|
bponum := m.helper.Ponums[b.ID]
|
||||||
|
if bponum < tree.lastuse {
|
||||||
|
tree.lastuse = bponum
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// locatePotentialPhiFunctions finds all the places where phi functions
|
||||||
|
// will be inserted into a program and records those and ordinary definitions
|
||||||
|
// in a "map" (not a Go map) that given an OName and use site, returns the
|
||||||
|
// SSA definition for that OName that will reach the use site (that is,
|
||||||
|
// the use site's nearest def/phi site in the dominator tree.)
|
||||||
|
func (s *state) locatePotentialPhiFunctions(fn *Node) *sparseDefState {
|
||||||
|
// s.config.SparsePhiCutoff() is compared with product of numblocks and numvalues,
|
||||||
|
// if product is smaller than cutoff, use old non-sparse method.
|
||||||
|
// cutoff == 0 implies all sparse
|
||||||
|
// cutoff == uint(-1) implies all non-sparse
|
||||||
|
if uint64(s.f.NumValues())*uint64(s.f.NumBlocks()) < s.config.SparsePhiCutoff() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
helper := ssa.NewSparseTreeHelper(s.f)
|
||||||
|
po := helper.Po // index by block.ID to obtain postorder # of block.
|
||||||
|
trees := make(map[*Node]*onameDefs)
|
||||||
|
dm := &sparseDefState{defmapForOname: trees, helper: helper}
|
||||||
|
|
||||||
|
// Process params, taking note of their special lifetimes
|
||||||
|
b := s.f.Entry
|
||||||
|
for _, n := range fn.Func.Dcl {
|
||||||
|
switch n.Class {
|
||||||
|
case PPARAM, PPARAMOUT:
|
||||||
|
t := dm.defsFor(n)
|
||||||
|
dm.Insert(t, b, ssa.AdjustBefore) // define param at entry block
|
||||||
|
if n.Class == PPARAMOUT {
|
||||||
|
dm.Use(t, po[0]) // Explicitly use PPARAMOUT at very last block
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process memory variable.
|
||||||
|
t := dm.defsFor(&memVar)
|
||||||
|
dm.Insert(t, b, ssa.AdjustBefore) // define memory at entry block
|
||||||
|
dm.Use(t, po[0]) // Explicitly use memory at last block
|
||||||
|
|
||||||
|
// Next load the map w/ basic definitions for ONames recorded per-block
|
||||||
|
// Iterate over po to avoid unreachable blocks.
|
||||||
|
for i := len(po) - 1; i >= 0; i-- {
|
||||||
|
b := po[i]
|
||||||
|
m := s.defvars[b.ID]
|
||||||
|
for n := range m { // no specified order, but per-node trees are independent.
|
||||||
|
t := dm.defsFor(n)
|
||||||
|
dm.Insert(t, b, ssa.AdjustWithin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find last use of each variable
|
||||||
|
for _, v := range s.fwdRefs {
|
||||||
|
b := v.Block
|
||||||
|
name := v.Aux.(*Node)
|
||||||
|
t := dm.defsFor(name)
|
||||||
|
dm.Use(t, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, t := range trees {
|
||||||
|
// iterating over names in the outer loop
|
||||||
|
for change := true; change; {
|
||||||
|
change = false
|
||||||
|
for i := t.firstdef; i >= t.lastuse; i-- {
|
||||||
|
// Iterating in reverse of post-order reduces number of 'change' iterations;
|
||||||
|
// all possible forward flow goes through each time.
|
||||||
|
b := po[i]
|
||||||
|
// Within tree t, would a use at b require a phi function to ensure a single definition?
|
||||||
|
// TODO: perhaps more efficient to record specific use sites instead of range?
|
||||||
|
if len(b.Preds) < 2 {
|
||||||
|
continue // no phi possible
|
||||||
|
}
|
||||||
|
phi := t.stm.Find(b, ssa.AdjustWithin, helper) // Look for defs in earlier block or AdjustBefore in this one.
|
||||||
|
if phi != nil && phi.(*ssa.Block) == b {
|
||||||
|
continue // has a phi already in this block.
|
||||||
|
}
|
||||||
|
var defseen interface{}
|
||||||
|
// Do preds see different definitions? if so, need a phi function.
|
||||||
|
for _, e := range b.Preds {
|
||||||
|
p := e.Block()
|
||||||
|
dm.Use(t, p) // always count phi pred as "use"; no-op except for loop edges, which matter.
|
||||||
|
x := t.stm.Find(p, ssa.AdjustAfter, helper) // Look for defs reaching or within predecessors.
|
||||||
|
if defseen == nil {
|
||||||
|
defseen = x
|
||||||
|
}
|
||||||
|
if defseen != x || x == nil { // TODO: too conservative at loops, does better if x == nil -> continue
|
||||||
|
// Need to insert a phi function here because predecessors's definitions differ.
|
||||||
|
change = true
|
||||||
|
// Phi insertion is at AdjustBefore, visible with find in same block at AdjustWithin or AdjustAfter.
|
||||||
|
dm.Insert(t, b, ssa.AdjustBefore)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dm
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindBetterDefiningBlock tries to find a better block for a definition of OName name
|
||||||
|
// reaching (or within) p than p itself. If it cannot, it returns p instead.
|
||||||
|
// This aids in more efficient location of phi functions, since it can skip over
|
||||||
|
// branch code that might contain a definition of name if it actually does not.
|
||||||
|
func (m *sparseDefState) FindBetterDefiningBlock(name *Node, p *ssa.Block) *ssa.Block {
|
||||||
|
if m == nil {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
t := m.defmapForOname[name]
|
||||||
|
// For now this is fail-soft, since the old algorithm still works using the unimproved block.
|
||||||
|
if t == nil {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
x := t.stm.Find(p, ssa.AdjustAfter, m.helper)
|
||||||
|
if x == nil {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
b := x.(*ssa.Block)
|
||||||
|
if b == nil {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *onameDefs) String() string {
|
||||||
|
return fmt.Sprintf("onameDefs:first=%d,last=%d,tree=%s", d.firstdef, d.lastuse, d.stm.String())
|
||||||
|
}
|
||||||
|
|
@ -161,23 +161,19 @@ func buildssa(fn *Node) *ssa.Func {
|
||||||
// the function.
|
// the function.
|
||||||
s.returns = append(s.returns, n)
|
s.returns = append(s.returns, n)
|
||||||
}
|
}
|
||||||
case PAUTO | PHEAP:
|
if n.Class == PPARAM && s.canSSA(n) && n.Type.IsPtrShaped() {
|
||||||
// TODO this looks wrong for PAUTO|PHEAP, no vardef, but also no definition
|
s.ptrargs = append(s.ptrargs, n)
|
||||||
aux := s.lookupSymbol(n, &ssa.AutoSymbol{Typ: n.Type, Node: n})
|
n.SetNotLiveAtEnd(true) // SSA takes care of this explicitly
|
||||||
s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
|
}
|
||||||
case PPARAM | PHEAP, PPARAMOUT | PHEAP:
|
|
||||||
// This ends up wrong, have to do it at the PARAM node instead.
|
|
||||||
case PAUTO:
|
case PAUTO:
|
||||||
// processed at each use, to prevent Addr coming
|
// processed at each use, to prevent Addr coming
|
||||||
// before the decl.
|
// before the decl.
|
||||||
|
case PAUTOHEAP:
|
||||||
|
// moved to heap - already handled by frontend
|
||||||
case PFUNC:
|
case PFUNC:
|
||||||
// local function - already handled by frontend
|
// local function - already handled by frontend
|
||||||
default:
|
default:
|
||||||
str := ""
|
s.Unimplementedf("local variable with class %s unimplemented", classnames[n.Class])
|
||||||
if n.Class&PHEAP != 0 {
|
|
||||||
str = ",heap"
|
|
||||||
}
|
|
||||||
s.Unimplementedf("local variable with class %s%s unimplemented", classnames[n.Class&^PHEAP], str)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -218,8 +214,16 @@ func buildssa(fn *Node) *ssa.Func {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prelinkNumvars := s.f.NumValues()
|
||||||
|
sparseDefState := s.locatePotentialPhiFunctions(fn)
|
||||||
|
|
||||||
// Link up variable uses to variable definitions
|
// Link up variable uses to variable definitions
|
||||||
s.linkForwardReferences()
|
s.linkForwardReferences(sparseDefState)
|
||||||
|
|
||||||
|
if ssa.BuildStats > 0 {
|
||||||
|
s.f.LogStat("build", s.f.NumBlocks(), "blocks", prelinkNumvars, "vars_before",
|
||||||
|
s.f.NumValues(), "vars_after", prelinkNumvars*s.f.NumBlocks(), "ssa_phi_loc_cutoff_score")
|
||||||
|
}
|
||||||
|
|
||||||
// Don't carry reference this around longer than necessary
|
// Don't carry reference this around longer than necessary
|
||||||
s.exitCode = Nodes{}
|
s.exitCode = Nodes{}
|
||||||
|
|
@ -282,9 +286,13 @@ type state struct {
|
||||||
// list of FwdRef values.
|
// list of FwdRef values.
|
||||||
fwdRefs []*ssa.Value
|
fwdRefs []*ssa.Value
|
||||||
|
|
||||||
// list of PPARAMOUT (return) variables. Does not include PPARAM|PHEAP vars.
|
// list of PPARAMOUT (return) variables.
|
||||||
returns []*Node
|
returns []*Node
|
||||||
|
|
||||||
|
// list of PPARAM SSA-able pointer-shaped args. We ensure these are live
|
||||||
|
// throughout the function to help users avoid premature finalizers.
|
||||||
|
ptrargs []*Node
|
||||||
|
|
||||||
cgoUnsafeArgs bool
|
cgoUnsafeArgs bool
|
||||||
noWB bool
|
noWB bool
|
||||||
WBLineno int32 // line number of first write barrier. 0=no write barriers
|
WBLineno int32 // line number of first write barrier. 0=no write barriers
|
||||||
|
|
@ -577,24 +585,9 @@ func (s *state) stmt(n *Node) {
|
||||||
return
|
return
|
||||||
|
|
||||||
case ODCL:
|
case ODCL:
|
||||||
if n.Left.Class&PHEAP == 0 {
|
if n.Left.Class == PAUTOHEAP {
|
||||||
return
|
Fatalf("DCL %v", n)
|
||||||
}
|
}
|
||||||
if compiling_runtime {
|
|
||||||
Fatalf("%v escapes to heap, not allowed in runtime.", n)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: the old pass hides the details of PHEAP
|
|
||||||
// variables behind ONAME nodes. Figure out if it's better
|
|
||||||
// to rewrite the tree and make the heapaddr construct explicit
|
|
||||||
// or to keep this detail hidden behind the scenes.
|
|
||||||
palloc := prealloc[n.Left]
|
|
||||||
if palloc == nil {
|
|
||||||
palloc = callnew(n.Left.Type)
|
|
||||||
prealloc[n.Left] = palloc
|
|
||||||
}
|
|
||||||
r := s.expr(palloc)
|
|
||||||
s.assign(n.Left.Name.Heapaddr, r, false, false, n.Lineno, 0)
|
|
||||||
|
|
||||||
case OLABEL:
|
case OLABEL:
|
||||||
sym := n.Left.Sym
|
sym := n.Left.Sym
|
||||||
|
|
@ -980,8 +973,7 @@ func (s *state) exit() *ssa.Block {
|
||||||
|
|
||||||
// Store SSAable PPARAMOUT variables back to stack locations.
|
// Store SSAable PPARAMOUT variables back to stack locations.
|
||||||
for _, n := range s.returns {
|
for _, n := range s.returns {
|
||||||
aux := &ssa.ArgSymbol{Typ: n.Type, Node: n}
|
addr := s.decladdrs[n]
|
||||||
addr := s.newValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
|
|
||||||
val := s.variable(n, n.Type)
|
val := s.variable(n, n.Type)
|
||||||
s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, n, s.mem())
|
s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, n, s.mem())
|
||||||
s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, n.Type.Size(), addr, val, s.mem())
|
s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, n.Type.Size(), addr, val, s.mem())
|
||||||
|
|
@ -990,6 +982,16 @@ func (s *state) exit() *ssa.Block {
|
||||||
// currently.
|
// currently.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep input pointer args live until the return. This is a bandaid
|
||||||
|
// fix for 1.7 for what will become in 1.8 explicit runtime.KeepAlive calls.
|
||||||
|
// For <= 1.7 we guarantee that pointer input arguments live to the end of
|
||||||
|
// the function to prevent premature (from the user's point of view)
|
||||||
|
// execution of finalizers. See issue 15277.
|
||||||
|
// TODO: remove for 1.8?
|
||||||
|
for _, n := range s.ptrargs {
|
||||||
|
s.vars[&memVar] = s.newValue2(ssa.OpKeepAlive, ssa.TypeMem, s.variable(n, n.Type), s.mem())
|
||||||
|
}
|
||||||
|
|
||||||
// Do actual return.
|
// Do actual return.
|
||||||
m := s.mem()
|
m := s.mem()
|
||||||
b := s.endBlock()
|
b := s.endBlock()
|
||||||
|
|
@ -1428,9 +1430,6 @@ func (s *state) expr(n *Node) *ssa.Value {
|
||||||
case OCFUNC:
|
case OCFUNC:
|
||||||
aux := s.lookupSymbol(n, &ssa.ExternSymbol{Typ: n.Type, Sym: n.Left.Sym})
|
aux := s.lookupSymbol(n, &ssa.ExternSymbol{Typ: n.Type, Sym: n.Left.Sym})
|
||||||
return s.entryNewValue1A(ssa.OpAddr, n.Type, aux, s.sb)
|
return s.entryNewValue1A(ssa.OpAddr, n.Type, aux, s.sb)
|
||||||
case OPARAM:
|
|
||||||
addr := s.addr(n, false)
|
|
||||||
return s.newValue2(ssa.OpLoad, n.Left.Type, addr, s.mem())
|
|
||||||
case ONAME:
|
case ONAME:
|
||||||
if n.Class == PFUNC {
|
if n.Class == PFUNC {
|
||||||
// "value" of a function is the address of the function's closure
|
// "value" of a function is the address of the function's closure
|
||||||
|
|
@ -2644,6 +2643,10 @@ func (s *state) call(n *Node, k callKind) *ssa.Value {
|
||||||
|
|
||||||
// Start exit block, find address of result.
|
// Start exit block, find address of result.
|
||||||
s.startBlock(bNext)
|
s.startBlock(bNext)
|
||||||
|
// Keep input pointer args live across calls. This is a bandaid until 1.8.
|
||||||
|
for _, n := range s.ptrargs {
|
||||||
|
s.vars[&memVar] = s.newValue2(ssa.OpKeepAlive, ssa.TypeMem, s.variable(n, n.Type), s.mem())
|
||||||
|
}
|
||||||
res := n.Left.Type.Results()
|
res := n.Left.Type.Results()
|
||||||
if res.NumFields() == 0 || k != callNormal {
|
if res.NumFields() == 0 || k != callNormal {
|
||||||
// call has no return value. Continue with the next statement.
|
// call has no return value. Continue with the next statement.
|
||||||
|
|
@ -2724,10 +2727,8 @@ func (s *state) addr(n *Node, bounded bool) *ssa.Value {
|
||||||
// that cse works on their addresses
|
// that cse works on their addresses
|
||||||
aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
|
aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
|
||||||
return s.newValue1A(ssa.OpAddr, t, aux, s.sp)
|
return s.newValue1A(ssa.OpAddr, t, aux, s.sp)
|
||||||
case PAUTO | PHEAP, PPARAM | PHEAP, PPARAMOUT | PHEAP, PPARAMREF:
|
|
||||||
return s.expr(n.Name.Heapaddr)
|
|
||||||
default:
|
default:
|
||||||
s.Unimplementedf("variable address class %v not implemented", n.Class)
|
s.Unimplementedf("variable address class %v not implemented", classnames[n.Class])
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
case OINDREG:
|
case OINDREG:
|
||||||
|
|
@ -2770,17 +2771,6 @@ func (s *state) addr(n *Node, bounded bool) *ssa.Value {
|
||||||
case OCLOSUREVAR:
|
case OCLOSUREVAR:
|
||||||
return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset,
|
return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset,
|
||||||
s.entryNewValue0(ssa.OpGetClosurePtr, Ptrto(Types[TUINT8])))
|
s.entryNewValue0(ssa.OpGetClosurePtr, Ptrto(Types[TUINT8])))
|
||||||
case OPARAM:
|
|
||||||
p := n.Left
|
|
||||||
if p.Op != ONAME || !(p.Class == PPARAM|PHEAP || p.Class == PPARAMOUT|PHEAP) {
|
|
||||||
s.Fatalf("OPARAM not of ONAME,{PPARAM,PPARAMOUT}|PHEAP, instead %s", nodedump(p, 0))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recover original offset to address passed-in param value.
|
|
||||||
original_p := *p
|
|
||||||
original_p.Xoffset = n.Xoffset
|
|
||||||
aux := &ssa.ArgSymbol{Typ: n.Type, Node: &original_p}
|
|
||||||
return s.entryNewValue1A(ssa.OpAddr, t, aux, s.sp)
|
|
||||||
case OCONVNOP:
|
case OCONVNOP:
|
||||||
addr := s.addr(n.Left, bounded)
|
addr := s.addr(n.Left, bounded)
|
||||||
return s.newValue1(ssa.OpCopy, t, addr) // ensure that addr has the right type
|
return s.newValue1(ssa.OpCopy, t, addr) // ensure that addr has the right type
|
||||||
|
|
@ -2808,12 +2798,14 @@ func (s *state) canSSA(n *Node) bool {
|
||||||
if n.Addrtaken {
|
if n.Addrtaken {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if n.Class&PHEAP != 0 {
|
if n.isParamHeapCopy() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if n.Class == PAUTOHEAP {
|
||||||
|
Fatalf("canSSA of PAUTOHEAP %v", n)
|
||||||
|
}
|
||||||
switch n.Class {
|
switch n.Class {
|
||||||
case PEXTERN, PPARAMREF:
|
case PEXTERN:
|
||||||
// TODO: maybe treat PPARAMREF with an Arg-like op to read from closure?
|
|
||||||
return false
|
return false
|
||||||
case PPARAMOUT:
|
case PPARAMOUT:
|
||||||
if hasdefer {
|
if hasdefer {
|
||||||
|
|
@ -2993,6 +2985,11 @@ func (s *state) rtcall(fn *Node, returns bool, results []*Type, args ...*ssa.Val
|
||||||
b.AddEdgeTo(bNext)
|
b.AddEdgeTo(bNext)
|
||||||
s.startBlock(bNext)
|
s.startBlock(bNext)
|
||||||
|
|
||||||
|
// Keep input pointer args live across calls. This is a bandaid until 1.8.
|
||||||
|
for _, n := range s.ptrargs {
|
||||||
|
s.vars[&memVar] = s.newValue2(ssa.OpKeepAlive, ssa.TypeMem, s.variable(n, n.Type), s.mem())
|
||||||
|
}
|
||||||
|
|
||||||
// Load results
|
// Load results
|
||||||
res := make([]*ssa.Value, len(results))
|
res := make([]*ssa.Value, len(results))
|
||||||
for i, t := range results {
|
for i, t := range results {
|
||||||
|
|
@ -3743,7 +3740,8 @@ func (s *state) mem() *ssa.Value {
|
||||||
return s.variable(&memVar, ssa.TypeMem)
|
return s.variable(&memVar, ssa.TypeMem)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *state) linkForwardReferences() {
|
func (s *state) linkForwardReferences(dm *sparseDefState) {
|
||||||
|
|
||||||
// Build SSA graph. Each variable on its first use in a basic block
|
// Build SSA graph. Each variable on its first use in a basic block
|
||||||
// leaves a FwdRef in that block representing the incoming value
|
// leaves a FwdRef in that block representing the incoming value
|
||||||
// of that variable. This function links that ref up with possible definitions,
|
// of that variable. This function links that ref up with possible definitions,
|
||||||
|
|
@ -3758,13 +3756,13 @@ func (s *state) linkForwardReferences() {
|
||||||
for len(s.fwdRefs) > 0 {
|
for len(s.fwdRefs) > 0 {
|
||||||
v := s.fwdRefs[len(s.fwdRefs)-1]
|
v := s.fwdRefs[len(s.fwdRefs)-1]
|
||||||
s.fwdRefs = s.fwdRefs[:len(s.fwdRefs)-1]
|
s.fwdRefs = s.fwdRefs[:len(s.fwdRefs)-1]
|
||||||
s.resolveFwdRef(v)
|
s.resolveFwdRef(v, dm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolveFwdRef modifies v to be the variable's value at the start of its block.
|
// resolveFwdRef modifies v to be the variable's value at the start of its block.
|
||||||
// v must be a FwdRef op.
|
// v must be a FwdRef op.
|
||||||
func (s *state) resolveFwdRef(v *ssa.Value) {
|
func (s *state) resolveFwdRef(v *ssa.Value, dm *sparseDefState) {
|
||||||
b := v.Block
|
b := v.Block
|
||||||
name := v.Aux.(*Node)
|
name := v.Aux.(*Node)
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
|
|
@ -3803,6 +3801,7 @@ func (s *state) resolveFwdRef(v *ssa.Value) {
|
||||||
args := argstore[:0]
|
args := argstore[:0]
|
||||||
for _, e := range b.Preds {
|
for _, e := range b.Preds {
|
||||||
p := e.Block()
|
p := e.Block()
|
||||||
|
p = dm.FindBetterDefiningBlock(name, p) // try sparse improvement on p
|
||||||
args = append(args, s.lookupVarOutgoing(p, v.Type, name, v.Line))
|
args = append(args, s.lookupVarOutgoing(p, v.Type, name, v.Line))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,12 +57,7 @@ func TestArithmetic(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestFP tests that both backends have the same result for floating point expressions.
|
// TestFP tests that both backends have the same result for floating point expressions.
|
||||||
func TestFP(t *testing.T) {
|
func TestFP(t *testing.T) { runTest(t, "fp_ssa.go") }
|
||||||
if runtime.GOARCH == "mips64" || runtime.GOARCH == "mips64le" {
|
|
||||||
t.Skip("legacy mips64 compiler doesn't handle uint->float conversion correctly (issue 15552)")
|
|
||||||
}
|
|
||||||
runTest(t, "fp_ssa.go")
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestArithmeticBoundary tests boundary results for arithmetic operations.
|
// TestArithmeticBoundary tests boundary results for arithmetic operations.
|
||||||
func TestArithmeticBoundary(t *testing.T) { runTest(t, "arithBoundary_ssa.go") }
|
func TestArithmeticBoundary(t *testing.T) { runTest(t, "arithBoundary_ssa.go") }
|
||||||
|
|
|
||||||
|
|
@ -87,8 +87,39 @@ func linestr(line int32) string {
|
||||||
return Ctxt.Line(int(line))
|
return Ctxt.Line(int(line))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// lasterror keeps track of the most recently issued error.
|
||||||
|
// It is used to avoid multiple error messages on the same
|
||||||
|
// line.
|
||||||
|
var lasterror struct {
|
||||||
|
syntax int32 // line of last syntax error
|
||||||
|
other int32 // line of last non-syntax error
|
||||||
|
msg string // error message of last non-syntax error
|
||||||
|
}
|
||||||
|
|
||||||
func yyerrorl(line int32, format string, args ...interface{}) {
|
func yyerrorl(line int32, format string, args ...interface{}) {
|
||||||
adderr(line, format, args...)
|
msg := fmt.Sprintf(format, args...)
|
||||||
|
|
||||||
|
if strings.HasPrefix(msg, "syntax error") {
|
||||||
|
nsyntaxerrors++
|
||||||
|
// only one syntax error per line, no matter what error
|
||||||
|
if lasterror.syntax == line {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
lasterror.syntax = line
|
||||||
|
} else {
|
||||||
|
// only one of multiple equal non-syntax errors per line
|
||||||
|
// (Flusherrors shows only one of them, so we filter them
|
||||||
|
// here as best as we can (they may not appear in order)
|
||||||
|
// so that we don't count them here and exit early, and
|
||||||
|
// then have nothing to show for.)
|
||||||
|
if lasterror.other == line && lasterror.msg == msg {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
lasterror.other = line
|
||||||
|
lasterror.msg = msg
|
||||||
|
}
|
||||||
|
|
||||||
|
adderr(line, "%s", msg)
|
||||||
|
|
||||||
hcrash()
|
hcrash()
|
||||||
nerrors++
|
nerrors++
|
||||||
|
|
@ -99,32 +130,8 @@ func yyerrorl(line int32, format string, args ...interface{}) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var yyerror_lastsyntax int32
|
|
||||||
|
|
||||||
func Yyerror(format string, args ...interface{}) {
|
func Yyerror(format string, args ...interface{}) {
|
||||||
msg := fmt.Sprintf(format, args...)
|
yyerrorl(lineno, format, args...)
|
||||||
if strings.HasPrefix(msg, "syntax error") {
|
|
||||||
nsyntaxerrors++
|
|
||||||
|
|
||||||
// only one syntax error per line
|
|
||||||
if yyerror_lastsyntax == lineno {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
yyerror_lastsyntax = lineno
|
|
||||||
|
|
||||||
yyerrorl(lineno, "%s", msg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
adderr(lineno, "%s", msg)
|
|
||||||
|
|
||||||
hcrash()
|
|
||||||
nerrors++
|
|
||||||
if nsavederrors+nerrors >= 10 && Debug['e'] == 0 {
|
|
||||||
Flusherrors()
|
|
||||||
fmt.Printf("%v: too many errors\n", linestr(lineno))
|
|
||||||
errorexit()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Warn(fmt_ string, args ...interface{}) {
|
func Warn(fmt_ string, args ...interface{}) {
|
||||||
|
|
@ -1224,7 +1231,7 @@ func ullmancalc(n *Node) {
|
||||||
switch n.Op {
|
switch n.Op {
|
||||||
case OREGISTER, OLITERAL, ONAME:
|
case OREGISTER, OLITERAL, ONAME:
|
||||||
ul = 1
|
ul = 1
|
||||||
if n.Class == PPARAMREF || (n.Class&PHEAP != 0) {
|
if n.Class == PAUTOHEAP {
|
||||||
ul++
|
ul++
|
||||||
}
|
}
|
||||||
goto out
|
goto out
|
||||||
|
|
@ -2250,6 +2257,7 @@ func isbadimport(path string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func checknil(x *Node, init *Nodes) {
|
func checknil(x *Node, init *Nodes) {
|
||||||
|
x = walkexpr(x, nil) // caller has not done this yet
|
||||||
if x.Type.IsInterface() {
|
if x.Type.IsInterface() {
|
||||||
x = Nod(OITAB, x, nil)
|
x = Nod(OITAB, x, nil)
|
||||||
x = typecheck(x, Erv)
|
x = typecheck(x, Erv)
|
||||||
|
|
|
||||||
|
|
@ -68,11 +68,48 @@ type Node struct {
|
||||||
Used bool
|
Used bool
|
||||||
Isddd bool // is the argument variadic
|
Isddd bool // is the argument variadic
|
||||||
Implicit bool
|
Implicit bool
|
||||||
Addrtaken bool // address taken, even if not moved to heap
|
Addrtaken bool // address taken, even if not moved to heap
|
||||||
Assigned bool // is the variable ever assigned to
|
Assigned bool // is the variable ever assigned to
|
||||||
Likely int8 // likeliness of if statement
|
Likely int8 // likeliness of if statement
|
||||||
Hasbreak bool // has break statement
|
hasVal int8 // +1 for Val, -1 for Opt, 0 for not yet set
|
||||||
hasVal int8 // +1 for Val, -1 for Opt, 0 for not yet set
|
flags uint8 // TODO: store more bool fields in this flag field
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
hasBreak = 1 << iota
|
||||||
|
notLiveAtEnd
|
||||||
|
isClosureVar
|
||||||
|
)
|
||||||
|
|
||||||
|
func (n *Node) HasBreak() bool {
|
||||||
|
return n.flags&hasBreak != 0
|
||||||
|
}
|
||||||
|
func (n *Node) SetHasBreak(b bool) {
|
||||||
|
if b {
|
||||||
|
n.flags |= hasBreak
|
||||||
|
} else {
|
||||||
|
n.flags &^= hasBreak
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (n *Node) NotLiveAtEnd() bool {
|
||||||
|
return n.flags¬LiveAtEnd != 0
|
||||||
|
}
|
||||||
|
func (n *Node) SetNotLiveAtEnd(b bool) {
|
||||||
|
if b {
|
||||||
|
n.flags |= notLiveAtEnd
|
||||||
|
} else {
|
||||||
|
n.flags &^= notLiveAtEnd
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (n *Node) isClosureVar() bool {
|
||||||
|
return n.flags&isClosureVar != 0
|
||||||
|
}
|
||||||
|
func (n *Node) setIsClosureVar(b bool) {
|
||||||
|
if b {
|
||||||
|
n.flags |= isClosureVar
|
||||||
|
} else {
|
||||||
|
n.flags &^= isClosureVar
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Val returns the Val for the node.
|
// Val returns the Val for the node.
|
||||||
|
|
@ -117,18 +154,18 @@ func (n *Node) SetOpt(x interface{}) {
|
||||||
n.E = x
|
n.E = x
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name holds Node fields used only by named nodes (ONAME, OPACK, some OLITERAL).
|
// Name holds Node fields used only by named nodes (ONAME, OPACK, OLABEL, ODCLFIELD, some OLITERAL).
|
||||||
type Name struct {
|
type Name struct {
|
||||||
Pack *Node // real package for import . names
|
Pack *Node // real package for import . names
|
||||||
Pkg *Pkg // pkg for OPACK nodes
|
Pkg *Pkg // pkg for OPACK nodes
|
||||||
Heapaddr *Node // temp holding heap address of param
|
Heapaddr *Node // temp holding heap address of param (could move to Param?)
|
||||||
Inlvar *Node // ONAME substitute while inlining
|
Inlvar *Node // ONAME substitute while inlining (could move to Param?)
|
||||||
Defn *Node // initializing assignment
|
Defn *Node // initializing assignment
|
||||||
Curfn *Node // function for local variables
|
Curfn *Node // function for local variables
|
||||||
Param *Param
|
Param *Param // additional fields for ONAME, ODCLFIELD
|
||||||
Decldepth int32 // declaration loop depth, increased for every loop or label
|
Decldepth int32 // declaration loop depth, increased for every loop or label
|
||||||
Vargen int32 // unique name for ONAME within a function. Function outputs are numbered starting at one.
|
Vargen int32 // unique name for ONAME within a function. Function outputs are numbered starting at one.
|
||||||
Iota int32 // value if this name is iota
|
Iota int32 // value if this name is iota
|
||||||
Funcdepth int32
|
Funcdepth int32
|
||||||
Method bool // OCALLMETH name
|
Method bool // OCALLMETH name
|
||||||
Readonly bool
|
Readonly bool
|
||||||
|
|
@ -141,16 +178,83 @@ type Name struct {
|
||||||
type Param struct {
|
type Param struct {
|
||||||
Ntype *Node
|
Ntype *Node
|
||||||
|
|
||||||
// ONAME func param with PHEAP
|
// ONAME PAUTOHEAP
|
||||||
Outerexpr *Node // expression copied into closure for variable
|
Stackcopy *Node // the PPARAM/PPARAMOUT on-stack slot (moved func params only)
|
||||||
Stackparam *Node // OPARAM node referring to stack copy of param
|
|
||||||
|
|
||||||
// ONAME PPARAM
|
// ONAME PPARAM
|
||||||
Field *Field // TFIELD in arg struct
|
Field *Field // TFIELD in arg struct
|
||||||
|
|
||||||
// ONAME closure param with PPARAMREF
|
// ONAME closure linkage
|
||||||
Outer *Node // outer PPARAMREF in nested closure
|
// Consider:
|
||||||
Closure *Node // ONAME/PHEAP <-> ONAME/PPARAMREF
|
//
|
||||||
|
// func f() {
|
||||||
|
// x := 1 // x1
|
||||||
|
// func() {
|
||||||
|
// use(x) // x2
|
||||||
|
// func() {
|
||||||
|
// use(x) // x3
|
||||||
|
// --- parser is here ---
|
||||||
|
// }()
|
||||||
|
// }()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// There is an original declaration of x and then a chain of mentions of x
|
||||||
|
// leading into the current function. Each time x is mentioned in a new closure,
|
||||||
|
// we create a variable representing x for use in that specific closure,
|
||||||
|
// since the way you get to x is different in each closure.
|
||||||
|
//
|
||||||
|
// Let's number the specific variables as shown in the code:
|
||||||
|
// x1 is the original x, x2 is when mentioned in the closure,
|
||||||
|
// and x3 is when mentioned in the closure in the closure.
|
||||||
|
//
|
||||||
|
// We keep these linked (assume N > 1):
|
||||||
|
//
|
||||||
|
// - x1.Defn = original declaration statement for x (like most variables)
|
||||||
|
// - x1.Innermost = current innermost closure x (in this case x3), or nil for none
|
||||||
|
// - x1.isClosureVar() = false
|
||||||
|
//
|
||||||
|
// - xN.Defn = x1, N > 1
|
||||||
|
// - xN.isClosureVar() = true, N > 1
|
||||||
|
// - x2.Outer = nil
|
||||||
|
// - xN.Outer = x(N-1), N > 2
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// When we look up x in the symbol table, we always get x1.
|
||||||
|
// Then we can use x1.Innermost (if not nil) to get the x
|
||||||
|
// for the innermost known closure function,
|
||||||
|
// but the first reference in a closure will find either no x1.Innermost
|
||||||
|
// or an x1.Innermost with .Funcdepth < Funcdepth.
|
||||||
|
// In that case, a new xN must be created, linked in with:
|
||||||
|
//
|
||||||
|
// xN.Defn = x1
|
||||||
|
// xN.Outer = x1.Innermost
|
||||||
|
// x1.Innermost = xN
|
||||||
|
//
|
||||||
|
// When we finish the function, we'll process its closure variables
|
||||||
|
// and find xN and pop it off the list using:
|
||||||
|
//
|
||||||
|
// x1 := xN.Defn
|
||||||
|
// x1.Innermost = xN.Outer
|
||||||
|
//
|
||||||
|
// We leave xN.Innermost set so that we can still get to the original
|
||||||
|
// variable quickly. Not shown here, but once we're
|
||||||
|
// done parsing a function and no longer need xN.Outer for the
|
||||||
|
// lexical x reference links as described above, closurebody
|
||||||
|
// recomputes xN.Outer as the semantic x reference link tree,
|
||||||
|
// even filling in x in intermediate closures that might not
|
||||||
|
// have mentioned it along the way to inner closures that did.
|
||||||
|
// See closurebody for details.
|
||||||
|
//
|
||||||
|
// During the eventual compilation, then, for closure variables we have:
|
||||||
|
//
|
||||||
|
// xN.Defn = original variable
|
||||||
|
// xN.Outer = variable captured in next outward scope
|
||||||
|
// to make closure where xN appears
|
||||||
|
//
|
||||||
|
// Because of the sharding of pieces of the node, x.Defn means x.Name.Defn
|
||||||
|
// and x.Innermost/Outer means x.Name.Param.Innermost/Outer.
|
||||||
|
Innermost *Node
|
||||||
|
Outer *Node
|
||||||
}
|
}
|
||||||
|
|
||||||
// Func holds Node fields used only with function-like nodes.
|
// Func holds Node fields used only with function-like nodes.
|
||||||
|
|
@ -162,9 +266,8 @@ type Func struct {
|
||||||
Dcl []*Node // autodcl for this func/closure
|
Dcl []*Node // autodcl for this func/closure
|
||||||
Inldcl Nodes // copy of dcl for use in inlining
|
Inldcl Nodes // copy of dcl for use in inlining
|
||||||
Closgen int
|
Closgen int
|
||||||
Outerfunc *Node
|
Outerfunc *Node // outer function (for closure)
|
||||||
FieldTrack map[*Sym]struct{}
|
FieldTrack map[*Sym]struct{}
|
||||||
Outer *Node // outer func for closure
|
|
||||||
Ntype *Node // signature
|
Ntype *Node // signature
|
||||||
Top int // top context (Ecall, Eproc, etc)
|
Top int // top context (Ecall, Eproc, etc)
|
||||||
Closure *Node // OCLOSURE <-> ODCLFUNC
|
Closure *Node // OCLOSURE <-> ODCLFUNC
|
||||||
|
|
@ -266,7 +369,7 @@ const (
|
||||||
OINDEX // Left[Right] (index of array or slice)
|
OINDEX // Left[Right] (index of array or slice)
|
||||||
OINDEXMAP // Left[Right] (index of map)
|
OINDEXMAP // Left[Right] (index of map)
|
||||||
OKEY // Left:Right (key:value in struct/array/map literal, or slice index pair)
|
OKEY // Left:Right (key:value in struct/array/map literal, or slice index pair)
|
||||||
OPARAM // variant of ONAME for on-stack copy of a parameter or return value that escapes.
|
_ // was OPARAM, but cannot remove without breaking binary blob in builtin.go
|
||||||
OLEN // len(Left)
|
OLEN // len(Left)
|
||||||
OMAKE // make(List) (before type checking converts to one of the following)
|
OMAKE // make(List) (before type checking converts to one of the following)
|
||||||
OMAKECHAN // make(Type, Left) (type is chan)
|
OMAKECHAN // make(Type, Left) (type is chan)
|
||||||
|
|
|
||||||
224
src/cmd/compile/internal/gc/testdata/gen/constFoldGen.go
vendored
Normal file
224
src/cmd/compile/internal/gc/testdata/gen/constFoldGen.go
vendored
Normal file
|
|
@ -0,0 +1,224 @@
|
||||||
|
// Copyright 2016 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 program generates a test to verify that the standard arithmetic
|
||||||
|
// operators properly handle constant folding. The test file should be
|
||||||
|
// generated with a known working version of go.
|
||||||
|
// launch with `go run constFoldGen.go` a file called constFold_test.go
|
||||||
|
// will be written into the grandparent directory containing the tests.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"go/format"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type op struct {
|
||||||
|
name, symbol string
|
||||||
|
}
|
||||||
|
type szD struct {
|
||||||
|
name string
|
||||||
|
sn string
|
||||||
|
u []uint64
|
||||||
|
i []int64
|
||||||
|
}
|
||||||
|
|
||||||
|
var szs []szD = []szD{
|
||||||
|
szD{name: "uint64", sn: "64", u: []uint64{0, 1, 4294967296, 0xffffFFFFffffFFFF}},
|
||||||
|
szD{name: "int64", sn: "64", i: []int64{-0x8000000000000000, -0x7FFFFFFFFFFFFFFF,
|
||||||
|
-4294967296, -1, 0, 1, 4294967296, 0x7FFFFFFFFFFFFFFE, 0x7FFFFFFFFFFFFFFF}},
|
||||||
|
|
||||||
|
szD{name: "uint32", sn: "32", u: []uint64{0, 1, 4294967295}},
|
||||||
|
szD{name: "int32", sn: "32", i: []int64{-0x80000000, -0x7FFFFFFF, -1, 0,
|
||||||
|
1, 0x7FFFFFFF}},
|
||||||
|
|
||||||
|
szD{name: "uint16", sn: "16", u: []uint64{0, 1, 65535}},
|
||||||
|
szD{name: "int16", sn: "16", i: []int64{-32768, -32767, -1, 0, 1, 32766, 32767}},
|
||||||
|
|
||||||
|
szD{name: "uint8", sn: "8", u: []uint64{0, 1, 255}},
|
||||||
|
szD{name: "int8", sn: "8", i: []int64{-128, -127, -1, 0, 1, 126, 127}},
|
||||||
|
}
|
||||||
|
|
||||||
|
var ops = []op{
|
||||||
|
op{"add", "+"}, op{"sub", "-"}, op{"div", "/"}, op{"mul", "*"},
|
||||||
|
op{"lsh", "<<"}, op{"rsh", ">>"}, op{"mod", "%"},
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute the result of i op j, cast as type t.
|
||||||
|
func ansU(i, j uint64, t, op string) string {
|
||||||
|
var ans uint64
|
||||||
|
switch op {
|
||||||
|
case "+":
|
||||||
|
ans = i + j
|
||||||
|
case "-":
|
||||||
|
ans = i - j
|
||||||
|
case "*":
|
||||||
|
ans = i * j
|
||||||
|
case "/":
|
||||||
|
if j != 0 {
|
||||||
|
ans = i / j
|
||||||
|
}
|
||||||
|
case "%":
|
||||||
|
if j != 0 {
|
||||||
|
ans = i % j
|
||||||
|
}
|
||||||
|
case "<<":
|
||||||
|
ans = i << j
|
||||||
|
case ">>":
|
||||||
|
ans = i >> j
|
||||||
|
}
|
||||||
|
switch t {
|
||||||
|
case "uint32":
|
||||||
|
ans = uint64(uint32(ans))
|
||||||
|
case "uint16":
|
||||||
|
ans = uint64(uint16(ans))
|
||||||
|
case "uint8":
|
||||||
|
ans = uint64(uint8(ans))
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%d", ans)
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute the result of i op j, cast as type t.
|
||||||
|
func ansS(i, j int64, t, op string) string {
|
||||||
|
var ans int64
|
||||||
|
switch op {
|
||||||
|
case "+":
|
||||||
|
ans = i + j
|
||||||
|
case "-":
|
||||||
|
ans = i - j
|
||||||
|
case "*":
|
||||||
|
ans = i * j
|
||||||
|
case "/":
|
||||||
|
if j != 0 {
|
||||||
|
ans = i / j
|
||||||
|
}
|
||||||
|
case "%":
|
||||||
|
if j != 0 {
|
||||||
|
ans = i % j
|
||||||
|
}
|
||||||
|
case "<<":
|
||||||
|
ans = i << uint64(j)
|
||||||
|
case ">>":
|
||||||
|
ans = i >> uint64(j)
|
||||||
|
}
|
||||||
|
switch t {
|
||||||
|
case "int32":
|
||||||
|
ans = int64(int32(ans))
|
||||||
|
case "int16":
|
||||||
|
ans = int64(int16(ans))
|
||||||
|
case "int8":
|
||||||
|
ans = int64(int8(ans))
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%d", ans)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
w := new(bytes.Buffer)
|
||||||
|
|
||||||
|
fmt.Fprintf(w, "package gc\n")
|
||||||
|
fmt.Fprintf(w, "import \"testing\"\n")
|
||||||
|
|
||||||
|
for _, s := range szs {
|
||||||
|
for _, o := range ops {
|
||||||
|
if o.symbol == "<<" || o.symbol == ">>" {
|
||||||
|
// shifts handled separately below, as they can have
|
||||||
|
// different types on the LHS and RHS.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "func TestConstFold%s%s(t *testing.T) {\n", s.name, o.name)
|
||||||
|
fmt.Fprintf(w, "\tvar x, y, r %s\n", s.name)
|
||||||
|
// unsigned test cases
|
||||||
|
for _, c := range s.u {
|
||||||
|
fmt.Fprintf(w, "\tx = %d\n", c)
|
||||||
|
for _, d := range s.u {
|
||||||
|
if d == 0 && (o.symbol == "/" || o.symbol == "%") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "\ty = %d\n", d)
|
||||||
|
fmt.Fprintf(w, "\tr = x %s y\n", o.symbol)
|
||||||
|
want := ansU(c, d, s.name, o.symbol)
|
||||||
|
fmt.Fprintf(w, "\tif r != %s {\n", want)
|
||||||
|
fmt.Fprintf(w, "\t\tt.Errorf(\"%d %s %d = %%d, want %s\", r)\n", c, o.symbol, d, want)
|
||||||
|
fmt.Fprintf(w, "\t}\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// signed test cases
|
||||||
|
for _, c := range s.i {
|
||||||
|
fmt.Fprintf(w, "\tx = %d\n", c)
|
||||||
|
for _, d := range s.i {
|
||||||
|
if d == 0 && (o.symbol == "/" || o.symbol == "%") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "\ty = %d\n", d)
|
||||||
|
fmt.Fprintf(w, "\tr = x %s y\n", o.symbol)
|
||||||
|
want := ansS(c, d, s.name, o.symbol)
|
||||||
|
fmt.Fprintf(w, "\tif r != %s {\n", want)
|
||||||
|
fmt.Fprintf(w, "\t\tt.Errorf(\"%d %s %d = %%d, want %s\", r)\n", c, o.symbol, d, want)
|
||||||
|
fmt.Fprintf(w, "\t}\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "}\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special signed/unsigned cases for shifts
|
||||||
|
for _, ls := range szs {
|
||||||
|
for _, rs := range szs {
|
||||||
|
if rs.name[0] != 'u' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, o := range ops {
|
||||||
|
if o.symbol != "<<" && o.symbol != ">>" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "func TestConstFold%s%s%s(t *testing.T) {\n", ls.name, rs.name, o.name)
|
||||||
|
fmt.Fprintf(w, "\tvar x, r %s\n", ls.name)
|
||||||
|
fmt.Fprintf(w, "\tvar y %s\n", rs.name)
|
||||||
|
// unsigned LHS
|
||||||
|
for _, c := range ls.u {
|
||||||
|
fmt.Fprintf(w, "\tx = %d\n", c)
|
||||||
|
for _, d := range rs.u {
|
||||||
|
fmt.Fprintf(w, "\ty = %d\n", d)
|
||||||
|
fmt.Fprintf(w, "\tr = x %s y\n", o.symbol)
|
||||||
|
want := ansU(c, d, ls.name, o.symbol)
|
||||||
|
fmt.Fprintf(w, "\tif r != %s {\n", want)
|
||||||
|
fmt.Fprintf(w, "\t\tt.Errorf(\"%d %s %d = %%d, want %s\", r)\n", c, o.symbol, d, want)
|
||||||
|
fmt.Fprintf(w, "\t}\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// signed LHS
|
||||||
|
for _, c := range ls.i {
|
||||||
|
fmt.Fprintf(w, "\tx = %d\n", c)
|
||||||
|
for _, d := range rs.u {
|
||||||
|
fmt.Fprintf(w, "\ty = %d\n", d)
|
||||||
|
fmt.Fprintf(w, "\tr = x %s y\n", o.symbol)
|
||||||
|
want := ansS(c, int64(d), ls.name, o.symbol)
|
||||||
|
fmt.Fprintf(w, "\tif r != %s {\n", want)
|
||||||
|
fmt.Fprintf(w, "\t\tt.Errorf(\"%d %s %d = %%d, want %s\", r)\n", c, o.symbol, d, want)
|
||||||
|
fmt.Fprintf(w, "\t}\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "}\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// gofmt result
|
||||||
|
b := w.Bytes()
|
||||||
|
src, err := format.Source(b)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("%s\n", b)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// write to file
|
||||||
|
err = ioutil.WriteFile("../../constFold_test.go", src, 0666)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("can't write output: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -223,10 +223,20 @@ type StructType struct {
|
||||||
// Map links such structs back to their map type.
|
// Map links such structs back to their map type.
|
||||||
Map *Type
|
Map *Type
|
||||||
|
|
||||||
Funarg bool // whether this struct represents function parameters
|
Funarg Funarg // type of function arguments for arg struct
|
||||||
Haspointers uint8 // 0 unknown, 1 no, 2 yes
|
Haspointers uint8 // 0 unknown, 1 no, 2 yes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fnstruct records the kind of function argument
|
||||||
|
type Funarg uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
FunargNone Funarg = iota
|
||||||
|
FunargRcvr // receiver
|
||||||
|
FunargParams // input parameters
|
||||||
|
FunargResults // output results
|
||||||
|
)
|
||||||
|
|
||||||
// StructType returns t's extra struct-specific fields.
|
// StructType returns t's extra struct-specific fields.
|
||||||
func (t *Type) StructType() *StructType {
|
func (t *Type) StructType() *StructType {
|
||||||
t.wantEtype(TSTRUCT)
|
t.wantEtype(TSTRUCT)
|
||||||
|
|
@ -287,7 +297,7 @@ type SliceType struct {
|
||||||
type Field struct {
|
type Field struct {
|
||||||
Nointerface bool
|
Nointerface bool
|
||||||
Embedded uint8 // embedded field
|
Embedded uint8 // embedded field
|
||||||
Funarg bool
|
Funarg Funarg
|
||||||
Broke bool // broken field definition
|
Broke bool // broken field definition
|
||||||
Isddd bool // field is ... argument
|
Isddd bool // field is ... argument
|
||||||
|
|
||||||
|
|
@ -786,7 +796,7 @@ func (t *Type) SetNname(n *Node) {
|
||||||
|
|
||||||
// IsFuncArgStruct reports whether t is a struct representing function parameters.
|
// IsFuncArgStruct reports whether t is a struct representing function parameters.
|
||||||
func (t *Type) IsFuncArgStruct() bool {
|
func (t *Type) IsFuncArgStruct() bool {
|
||||||
return t.Etype == TSTRUCT && t.Extra.(*StructType).Funarg
|
return t.Etype == TSTRUCT && t.Extra.(*StructType).Funarg != FunargNone
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Type) Methods() *Fields {
|
func (t *Type) Methods() *Fields {
|
||||||
|
|
|
||||||
|
|
@ -796,8 +796,8 @@ OpSwitch:
|
||||||
var l *Node
|
var l *Node
|
||||||
for l = n.Left; l != r; l = l.Left {
|
for l = n.Left; l != r; l = l.Left {
|
||||||
l.Addrtaken = true
|
l.Addrtaken = true
|
||||||
if l.Name != nil && l.Name.Param != nil && l.Name.Param.Closure != nil {
|
if l.isClosureVar() {
|
||||||
l.Name.Param.Closure.Addrtaken = true
|
l.Name.Defn.Addrtaken = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -805,8 +805,8 @@ OpSwitch:
|
||||||
Fatalf("found non-orig name node %v", l)
|
Fatalf("found non-orig name node %v", l)
|
||||||
}
|
}
|
||||||
l.Addrtaken = true
|
l.Addrtaken = true
|
||||||
if l.Name != nil && l.Name.Param != nil && l.Name.Param.Closure != nil {
|
if l.isClosureVar() {
|
||||||
l.Name.Param.Closure.Addrtaken = true
|
l.Name.Defn.Addrtaken = true
|
||||||
}
|
}
|
||||||
n.Left = defaultlit(n.Left, nil)
|
n.Left = defaultlit(n.Left, nil)
|
||||||
l = n.Left
|
l = n.Left
|
||||||
|
|
@ -3099,7 +3099,7 @@ func islvalue(n *Node) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
fallthrough
|
fallthrough
|
||||||
case OIND, ODOTPTR, OCLOSUREVAR, OPARAM:
|
case OIND, ODOTPTR, OCLOSUREVAR:
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case ODOT:
|
case ODOT:
|
||||||
|
|
@ -3128,14 +3128,14 @@ func checkassign(stmt *Node, n *Node) {
|
||||||
var l *Node
|
var l *Node
|
||||||
for l = n; l != r; l = l.Left {
|
for l = n; l != r; l = l.Left {
|
||||||
l.Assigned = true
|
l.Assigned = true
|
||||||
if l.Name != nil && l.Name.Param != nil && l.Name.Param.Closure != nil {
|
if l.isClosureVar() {
|
||||||
l.Name.Param.Closure.Assigned = true
|
l.Name.Defn.Assigned = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
l.Assigned = true
|
l.Assigned = true
|
||||||
if l.Name != nil && l.Name.Param != nil && l.Name.Param.Closure != nil {
|
if l.isClosureVar() {
|
||||||
l.Name.Param.Closure.Assigned = true
|
l.Name.Defn.Assigned = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3153,7 +3153,7 @@ func checkassign(stmt *Node, n *Node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if n.Op == ODOT && n.Left.Op == OINDEXMAP {
|
if n.Op == ODOT && n.Left.Op == OINDEXMAP {
|
||||||
Yyerror("cannot directly assign to struct field %v in map", n)
|
Yyerror("cannot assign to struct field %v in map", n)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3786,12 +3786,12 @@ func markbreak(n *Node, implicit *Node) {
|
||||||
case OBREAK:
|
case OBREAK:
|
||||||
if n.Left == nil {
|
if n.Left == nil {
|
||||||
if implicit != nil {
|
if implicit != nil {
|
||||||
implicit.Hasbreak = true
|
implicit.SetHasBreak(true)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
lab := n.Left.Sym.Label
|
lab := n.Left.Sym.Label
|
||||||
if lab != nil {
|
if lab != nil {
|
||||||
lab.Def.Hasbreak = true
|
lab.Def.SetHasBreak(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3867,7 +3867,7 @@ func (n *Node) isterminating() bool {
|
||||||
if n.Left != nil {
|
if n.Left != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if n.Hasbreak {
|
if n.HasBreak() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|
@ -3876,7 +3876,7 @@ func (n *Node) isterminating() bool {
|
||||||
return n.Nbody.isterminating() && n.Rlist.isterminating()
|
return n.Nbody.isterminating() && n.Rlist.isterminating()
|
||||||
|
|
||||||
case OSWITCH, OTYPESW, OSELECT:
|
case OSWITCH, OTYPESW, OSELECT:
|
||||||
if n.Hasbreak {
|
if n.HasBreak() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
def := 0
|
def := 0
|
||||||
|
|
|
||||||
|
|
@ -362,16 +362,16 @@ func lexinit1() {
|
||||||
// t = interface { Error() string }
|
// t = interface { Error() string }
|
||||||
|
|
||||||
rcvr := typ(TSTRUCT)
|
rcvr := typ(TSTRUCT)
|
||||||
rcvr.StructType().Funarg = true
|
rcvr.StructType().Funarg = FunargRcvr
|
||||||
field := newField()
|
field := newField()
|
||||||
field.Type = Ptrto(typ(TSTRUCT))
|
field.Type = Ptrto(typ(TSTRUCT))
|
||||||
rcvr.SetFields([]*Field{field})
|
rcvr.SetFields([]*Field{field})
|
||||||
|
|
||||||
in := typ(TSTRUCT)
|
in := typ(TSTRUCT)
|
||||||
in.StructType().Funarg = true
|
in.StructType().Funarg = FunargParams
|
||||||
|
|
||||||
out := typ(TSTRUCT)
|
out := typ(TSTRUCT)
|
||||||
out.StructType().Funarg = true
|
out.StructType().Funarg = FunargResults
|
||||||
field = newField()
|
field = newField()
|
||||||
field.Type = Types[TSTRING]
|
field.Type = Types[TSTRING]
|
||||||
out.SetFields([]*Field{field})
|
out.SetFields([]*Field{field})
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,8 @@ func walk(fn *Node) {
|
||||||
lno := lineno
|
lno := lineno
|
||||||
|
|
||||||
// Final typecheck for any unused variables.
|
// Final typecheck for any unused variables.
|
||||||
// It's hard to be on the heap when not-used, but best to be consistent about &~PHEAP here and below.
|
|
||||||
for i, ln := range fn.Func.Dcl {
|
for i, ln := range fn.Func.Dcl {
|
||||||
if ln.Op == ONAME && ln.Class&^PHEAP == PAUTO {
|
if ln.Op == ONAME && (ln.Class == PAUTO || ln.Class == PAUTOHEAP) {
|
||||||
ln = typecheck(ln, Erv|Easgn)
|
ln = typecheck(ln, Erv|Easgn)
|
||||||
fn.Func.Dcl[i] = ln
|
fn.Func.Dcl[i] = ln
|
||||||
}
|
}
|
||||||
|
|
@ -37,13 +36,13 @@ func walk(fn *Node) {
|
||||||
|
|
||||||
// Propagate the used flag for typeswitch variables up to the NONAME in it's definition.
|
// Propagate the used flag for typeswitch variables up to the NONAME in it's definition.
|
||||||
for _, ln := range fn.Func.Dcl {
|
for _, ln := range fn.Func.Dcl {
|
||||||
if ln.Op == ONAME && ln.Class&^PHEAP == PAUTO && ln.Name.Defn != nil && ln.Name.Defn.Op == OTYPESW && ln.Used {
|
if ln.Op == ONAME && (ln.Class == PAUTO || ln.Class == PAUTOHEAP) && ln.Name.Defn != nil && ln.Name.Defn.Op == OTYPESW && ln.Used {
|
||||||
ln.Name.Defn.Left.Used = true
|
ln.Name.Defn.Left.Used = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, ln := range fn.Func.Dcl {
|
for _, ln := range fn.Func.Dcl {
|
||||||
if ln.Op != ONAME || ln.Class&^PHEAP != PAUTO || ln.Sym.Name[0] == '&' || ln.Used {
|
if ln.Op != ONAME || (ln.Class != PAUTO && ln.Class != PAUTOHEAP) || ln.Sym.Name[0] == '&' || ln.Used {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if defn := ln.Name.Defn; defn != nil && defn.Op == OTYPESW {
|
if defn := ln.Name.Defn; defn != nil && defn.Op == OTYPESW {
|
||||||
|
|
@ -97,13 +96,13 @@ func samelist(a, b []*Node) bool {
|
||||||
func paramoutheap(fn *Node) bool {
|
func paramoutheap(fn *Node) bool {
|
||||||
for _, ln := range fn.Func.Dcl {
|
for _, ln := range fn.Func.Dcl {
|
||||||
switch ln.Class {
|
switch ln.Class {
|
||||||
case PPARAMOUT,
|
case PPARAMOUT:
|
||||||
PPARAMOUT | PHEAP:
|
if ln.isParamStackCopy() || ln.Addrtaken {
|
||||||
return ln.Addrtaken
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
case PAUTO:
|
||||||
// stop early - parameters are over
|
// stop early - parameters are over
|
||||||
case PAUTO,
|
|
||||||
PAUTO | PHEAP:
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -212,7 +211,6 @@ func walkstmt(n *Node) *Node {
|
||||||
n = addinit(n, init.Slice())
|
n = addinit(n, init.Slice())
|
||||||
|
|
||||||
case OBREAK,
|
case OBREAK,
|
||||||
ODCL,
|
|
||||||
OCONTINUE,
|
OCONTINUE,
|
||||||
OFALL,
|
OFALL,
|
||||||
OGOTO,
|
OGOTO,
|
||||||
|
|
@ -224,6 +222,21 @@ func walkstmt(n *Node) *Node {
|
||||||
OVARLIVE:
|
OVARLIVE:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
case ODCL:
|
||||||
|
v := n.Left
|
||||||
|
if v.Class == PAUTOHEAP {
|
||||||
|
if compiling_runtime {
|
||||||
|
Yyerror("%v escapes to heap, not allowed in runtime.", v)
|
||||||
|
}
|
||||||
|
if prealloc[v] == nil {
|
||||||
|
prealloc[v] = callnew(v.Type)
|
||||||
|
}
|
||||||
|
nn := Nod(OAS, v.Name.Heapaddr, prealloc[v])
|
||||||
|
nn.Colas = true
|
||||||
|
nn = typecheck(nn, Etop)
|
||||||
|
return walkstmt(nn)
|
||||||
|
}
|
||||||
|
|
||||||
case OBLOCK:
|
case OBLOCK:
|
||||||
walkstmtlist(n.List.Slice())
|
walkstmtlist(n.List.Slice())
|
||||||
|
|
||||||
|
|
@ -295,11 +308,14 @@ func walkstmt(n *Node) *Node {
|
||||||
|
|
||||||
var cl Class
|
var cl Class
|
||||||
for _, ln := range Curfn.Func.Dcl {
|
for _, ln := range Curfn.Func.Dcl {
|
||||||
cl = ln.Class &^ PHEAP
|
cl = ln.Class
|
||||||
if cl == PAUTO {
|
if cl == PAUTO || cl == PAUTOHEAP {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if cl == PPARAMOUT {
|
if cl == PPARAMOUT {
|
||||||
|
if ln.isParamStackCopy() {
|
||||||
|
ln = walkexpr(typecheck(Nod(OIND, ln.Name.Heapaddr, nil), Erv), nil)
|
||||||
|
}
|
||||||
rl = append(rl, ln)
|
rl = append(rl, ln)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -487,6 +503,12 @@ func walkexpr(n *Node, init *Nodes) *Node {
|
||||||
Fatalf("missed typecheck: %v\n", Nconv(n, FmtSign))
|
Fatalf("missed typecheck: %v\n", Nconv(n, FmtSign))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if n.Op == ONAME && n.Class == PAUTOHEAP {
|
||||||
|
nn := Nod(OIND, n.Name.Heapaddr, nil)
|
||||||
|
nn = typecheck(nn, Erv)
|
||||||
|
return walkexpr(nn, init)
|
||||||
|
}
|
||||||
|
|
||||||
opswitch:
|
opswitch:
|
||||||
switch n.Op {
|
switch n.Op {
|
||||||
default:
|
default:
|
||||||
|
|
@ -497,7 +519,6 @@ opswitch:
|
||||||
ONONAME,
|
ONONAME,
|
||||||
OINDREG,
|
OINDREG,
|
||||||
OEMPTY,
|
OEMPTY,
|
||||||
OPARAM,
|
|
||||||
OGETG:
|
OGETG:
|
||||||
|
|
||||||
case ONOT,
|
case ONOT,
|
||||||
|
|
@ -626,9 +647,7 @@ opswitch:
|
||||||
n.Addable = true
|
n.Addable = true
|
||||||
|
|
||||||
case ONAME:
|
case ONAME:
|
||||||
if n.Class&PHEAP == 0 && n.Class != PPARAMREF {
|
n.Addable = true
|
||||||
n.Addable = true
|
|
||||||
}
|
|
||||||
|
|
||||||
case OCALLINTER:
|
case OCALLINTER:
|
||||||
usemethod(n)
|
usemethod(n)
|
||||||
|
|
@ -1640,7 +1659,7 @@ func ascompatee(op Op, nl, nr []*Node, init *Nodes) []*Node {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// Do not generate 'x = x' during return. See issue 4014.
|
// Do not generate 'x = x' during return. See issue 4014.
|
||||||
if op == ORETURN && nl[i] == nr[i] {
|
if op == ORETURN && samesafeexpr(nl[i], nr[i]) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
nn = append(nn, ascompatee1(op, nl[i], nr[i], init))
|
nn = append(nn, ascompatee1(op, nl[i], nr[i], init))
|
||||||
|
|
@ -2515,7 +2534,7 @@ func vmatch1(l *Node, r *Node) bool {
|
||||||
switch l.Op {
|
switch l.Op {
|
||||||
case ONAME:
|
case ONAME:
|
||||||
switch l.Class {
|
switch l.Class {
|
||||||
case PPARAM, PPARAMREF, PAUTO:
|
case PPARAM, PAUTO:
|
||||||
break
|
break
|
||||||
|
|
||||||
// assignment to non-stack variable
|
// assignment to non-stack variable
|
||||||
|
|
@ -2550,41 +2569,31 @@ func vmatch1(l *Node, r *Node) bool {
|
||||||
// and to copy non-result prameters' values from the stack.
|
// and to copy non-result prameters' values from the stack.
|
||||||
// If out is true, then code is also produced to zero-initialize their
|
// If out is true, then code is also produced to zero-initialize their
|
||||||
// stack memory addresses.
|
// stack memory addresses.
|
||||||
func paramstoheap(params *Type, out bool) []*Node {
|
func paramstoheap(params *Type) []*Node {
|
||||||
var nn []*Node
|
var nn []*Node
|
||||||
for _, t := range params.Fields().Slice() {
|
for _, t := range params.Fields().Slice() {
|
||||||
|
// For precise stacks, the garbage collector assumes results
|
||||||
|
// are always live, so zero them always.
|
||||||
|
if params.StructType().Funarg == FunargResults {
|
||||||
|
// Defer might stop a panic and show the
|
||||||
|
// return values as they exist at the time of panic.
|
||||||
|
// Make sure to zero them on entry to the function.
|
||||||
|
nn = append(nn, Nod(OAS, nodarg(t, 1), nil))
|
||||||
|
}
|
||||||
|
|
||||||
v := t.Nname
|
v := t.Nname
|
||||||
if v != nil && v.Sym != nil && strings.HasPrefix(v.Sym.Name, "~r") { // unnamed result
|
if v != nil && v.Sym != nil && strings.HasPrefix(v.Sym.Name, "~r") { // unnamed result
|
||||||
v = nil
|
v = nil
|
||||||
}
|
}
|
||||||
|
if v == nil {
|
||||||
// For precise stacks, the garbage collector assumes results
|
|
||||||
// are always live, so zero them always.
|
|
||||||
if out {
|
|
||||||
// Defer might stop a panic and show the
|
|
||||||
// return values as they exist at the time of panic.
|
|
||||||
// Make sure to zero them on entry to the function.
|
|
||||||
nn = append(nn, Nod(OAS, nodarg(t, -1), nil))
|
|
||||||
}
|
|
||||||
|
|
||||||
if v == nil || v.Class&PHEAP == 0 {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate allocation & copying code
|
if stackcopy := v.Name.Param.Stackcopy; stackcopy != nil {
|
||||||
if compiling_runtime {
|
nn = append(nn, walkstmt(Nod(ODCL, v, nil)))
|
||||||
Yyerror("%v escapes to heap, not allowed in runtime.", v)
|
if stackcopy.Class == PPARAM {
|
||||||
}
|
nn = append(nn, walkstmt(typecheck(Nod(OAS, v, stackcopy), Etop)))
|
||||||
if prealloc[v] == nil {
|
}
|
||||||
prealloc[v] = callnew(v.Type)
|
|
||||||
}
|
|
||||||
nn = append(nn, Nod(OAS, v.Name.Heapaddr, prealloc[v]))
|
|
||||||
if v.Class&^PHEAP != PPARAMOUT {
|
|
||||||
as := Nod(OAS, v, v.Name.Param.Stackparam)
|
|
||||||
v.Name.Param.Stackparam.Typecheck = 1
|
|
||||||
as = typecheck(as, Etop)
|
|
||||||
as = applywritebarrier(as)
|
|
||||||
nn = append(nn, as)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2597,10 +2606,12 @@ func returnsfromheap(params *Type) []*Node {
|
||||||
var nn []*Node
|
var nn []*Node
|
||||||
for _, t := range params.Fields().Slice() {
|
for _, t := range params.Fields().Slice() {
|
||||||
v := t.Nname
|
v := t.Nname
|
||||||
if v == nil || v.Class != PHEAP|PPARAMOUT {
|
if v == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
nn = append(nn, Nod(OAS, v.Name.Param.Stackparam, v))
|
if stackcopy := v.Name.Param.Stackcopy; stackcopy != nil && stackcopy.Class == PPARAMOUT {
|
||||||
|
nn = append(nn, walkstmt(typecheck(Nod(OAS, stackcopy, v), Etop)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nn
|
return nn
|
||||||
|
|
@ -2612,9 +2623,9 @@ func returnsfromheap(params *Type) []*Node {
|
||||||
func heapmoves() {
|
func heapmoves() {
|
||||||
lno := lineno
|
lno := lineno
|
||||||
lineno = Curfn.Lineno
|
lineno = Curfn.Lineno
|
||||||
nn := paramstoheap(Curfn.Type.Recvs(), false)
|
nn := paramstoheap(Curfn.Type.Recvs())
|
||||||
nn = append(nn, paramstoheap(Curfn.Type.Params(), false)...)
|
nn = append(nn, paramstoheap(Curfn.Type.Params())...)
|
||||||
nn = append(nn, paramstoheap(Curfn.Type.Results(), true)...)
|
nn = append(nn, paramstoheap(Curfn.Type.Results())...)
|
||||||
Curfn.Func.Enter.Append(nn...)
|
Curfn.Func.Enter.Append(nn...)
|
||||||
lineno = Curfn.Func.Endlineno
|
lineno = Curfn.Func.Endlineno
|
||||||
Curfn.Func.Exit.Append(returnsfromheap(Curfn.Type.Results())...)
|
Curfn.Func.Exit.Append(returnsfromheap(Curfn.Type.Results())...)
|
||||||
|
|
|
||||||
|
|
@ -466,7 +466,7 @@ func gmove(f *gc.Node, t *gc.Node) {
|
||||||
//return;
|
//return;
|
||||||
// algorithm is:
|
// algorithm is:
|
||||||
// if small enough, use native int64 -> float64 conversion.
|
// if small enough, use native int64 -> float64 conversion.
|
||||||
// otherwise, halve (rounding to odd?), convert, and double.
|
// otherwise, halve (x -> (x>>1)|(x&1)), convert, and double.
|
||||||
/*
|
/*
|
||||||
* integer to float
|
* integer to float
|
||||||
*/
|
*/
|
||||||
|
|
@ -496,9 +496,16 @@ func gmove(f *gc.Node, t *gc.Node) {
|
||||||
gmove(&bigi, &rtmp)
|
gmove(&bigi, &rtmp)
|
||||||
gins(mips.AAND, &r1, &rtmp)
|
gins(mips.AAND, &r1, &rtmp)
|
||||||
p1 := ginsbranch(mips.ABEQ, nil, &rtmp, nil, 0)
|
p1 := ginsbranch(mips.ABEQ, nil, &rtmp, nil, 0)
|
||||||
p2 := gins(mips.ASRLV, nil, &r1)
|
var r3 gc.Node
|
||||||
|
gc.Regalloc(&r3, gc.Types[gc.TUINT64], nil)
|
||||||
|
p2 := gins3(mips.AAND, nil, &r1, &r3)
|
||||||
p2.From.Type = obj.TYPE_CONST
|
p2.From.Type = obj.TYPE_CONST
|
||||||
p2.From.Offset = 1
|
p2.From.Offset = 1
|
||||||
|
p3 := gins(mips.ASRLV, nil, &r1)
|
||||||
|
p3.From.Type = obj.TYPE_CONST
|
||||||
|
p3.From.Offset = 1
|
||||||
|
gins(mips.AOR, &r3, &r1)
|
||||||
|
gc.Regfree(&r3)
|
||||||
gc.Patch(p1, gc.Pc)
|
gc.Patch(p1, gc.Pc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -316,7 +316,7 @@ func checkFunc(f *Func) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// domCheck reports whether x dominates y (including x==y).
|
// domCheck reports whether x dominates y (including x==y).
|
||||||
func domCheck(f *Func, sdom sparseTree, x, y *Block) bool {
|
func domCheck(f *Func, sdom SparseTree, x, y *Block) bool {
|
||||||
if !sdom.isAncestorEq(f.Entry, y) {
|
if !sdom.isAncestorEq(f.Entry, y) {
|
||||||
// unreachable - ignore
|
// unreachable - ignore
|
||||||
return true
|
return true
|
||||||
|
|
|
||||||
|
|
@ -86,14 +86,14 @@ func Compile(f *Func) {
|
||||||
// Surround timing information w/ enough context to allow comparisons.
|
// Surround timing information w/ enough context to allow comparisons.
|
||||||
time := tEnd.Sub(tStart).Nanoseconds()
|
time := tEnd.Sub(tStart).Nanoseconds()
|
||||||
if p.time {
|
if p.time {
|
||||||
f.logStat("TIME(ns)", time)
|
f.LogStat("TIME(ns)", time)
|
||||||
}
|
}
|
||||||
if p.mem {
|
if p.mem {
|
||||||
var mEnd runtime.MemStats
|
var mEnd runtime.MemStats
|
||||||
runtime.ReadMemStats(&mEnd)
|
runtime.ReadMemStats(&mEnd)
|
||||||
nBytes := mEnd.TotalAlloc - mStart.TotalAlloc
|
nBytes := mEnd.TotalAlloc - mStart.TotalAlloc
|
||||||
nAllocs := mEnd.Mallocs - mStart.Mallocs
|
nAllocs := mEnd.Mallocs - mStart.Mallocs
|
||||||
f.logStat("TIME(ns):BYTES:ALLOCS", time, nBytes, nAllocs)
|
f.LogStat("TIME(ns):BYTES:ALLOCS", time, nBytes, nAllocs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if checkEnabled {
|
if checkEnabled {
|
||||||
|
|
@ -124,6 +124,10 @@ var checkEnabled = false
|
||||||
var IntrinsicsDebug int
|
var IntrinsicsDebug int
|
||||||
var IntrinsicsDisable bool
|
var IntrinsicsDisable bool
|
||||||
|
|
||||||
|
var BuildDebug int
|
||||||
|
var BuildTest int
|
||||||
|
var BuildStats int
|
||||||
|
|
||||||
// PhaseOption sets the specified flag in the specified ssa phase,
|
// PhaseOption sets the specified flag in the specified ssa phase,
|
||||||
// returning empty string if this was successful or a string explaining
|
// returning empty string if this was successful or a string explaining
|
||||||
// the error if it was not.
|
// the error if it was not.
|
||||||
|
|
@ -174,6 +178,19 @@ func PhaseOption(phase, flag string, val int) string {
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
if phase == "build" {
|
||||||
|
switch flag {
|
||||||
|
case "debug":
|
||||||
|
BuildDebug = val
|
||||||
|
case "test":
|
||||||
|
BuildTest = val
|
||||||
|
case "stats":
|
||||||
|
BuildStats = val
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("Did not find a flag matching %s in -d=ssa/%s debug option", flag, phase)
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
underphase := strings.Replace(phase, "_", " ", -1)
|
underphase := strings.Replace(phase, "_", " ", -1)
|
||||||
var re *regexp.Regexp
|
var re *regexp.Regexp
|
||||||
|
|
|
||||||
|
|
@ -9,23 +9,25 @@ import (
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
arch string // "amd64", etc.
|
arch string // "amd64", etc.
|
||||||
IntSize int64 // 4 or 8
|
IntSize int64 // 4 or 8
|
||||||
PtrSize int64 // 4 or 8
|
PtrSize int64 // 4 or 8
|
||||||
lowerBlock func(*Block) bool // lowering function
|
lowerBlock func(*Block) bool // lowering function
|
||||||
lowerValue func(*Value, *Config) bool // lowering function
|
lowerValue func(*Value, *Config) bool // lowering function
|
||||||
registers []Register // machine registers
|
registers []Register // machine registers
|
||||||
flagRegMask regMask // flag register mask
|
flagRegMask regMask // flag register mask
|
||||||
fe Frontend // callbacks into compiler frontend
|
fe Frontend // callbacks into compiler frontend
|
||||||
HTML *HTMLWriter // html writer, for debugging
|
HTML *HTMLWriter // html writer, for debugging
|
||||||
ctxt *obj.Link // Generic arch information
|
ctxt *obj.Link // Generic arch information
|
||||||
optimize bool // Do optimization
|
optimize bool // Do optimization
|
||||||
noDuffDevice bool // Don't use Duff's device
|
noDuffDevice bool // Don't use Duff's device
|
||||||
curFunc *Func
|
sparsePhiCutoff uint64 // Sparse phi location algorithm used above this #blocks*#variables score
|
||||||
|
curFunc *Func
|
||||||
|
|
||||||
// TODO: more stuff. Compiler flags of interest, ...
|
// TODO: more stuff. Compiler flags of interest, ...
|
||||||
|
|
||||||
|
|
@ -162,10 +164,27 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config
|
||||||
|
|
||||||
c.logfiles = make(map[string]*os.File)
|
c.logfiles = make(map[string]*os.File)
|
||||||
|
|
||||||
|
// cutoff is compared with product of numblocks and numvalues,
|
||||||
|
// if product is smaller than cutoff, use old non-sparse method.
|
||||||
|
// cutoff == 0 implies all sparse.
|
||||||
|
// cutoff == -1 implies none sparse.
|
||||||
|
// Good cutoff values seem to be O(million) depending on constant factor cost of sparse.
|
||||||
|
// TODO: get this from a flag, not an environment variable
|
||||||
|
c.sparsePhiCutoff = 2500000 // 0 for testing. // 2500000 determined with crude experiments w/ make.bash
|
||||||
|
ev := os.Getenv("GO_SSA_PHI_LOC_CUTOFF")
|
||||||
|
if ev != "" {
|
||||||
|
v, err := strconv.ParseInt(ev, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
fe.Fatalf(0, "Environment variable GO_SSA_PHI_LOC_CUTOFF (value '%s') did not parse as a number", ev)
|
||||||
|
}
|
||||||
|
c.sparsePhiCutoff = uint64(v) // convert -1 to maxint, for never use sparse
|
||||||
|
}
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) Frontend() Frontend { return c.fe }
|
func (c *Config) Frontend() Frontend { return c.fe }
|
||||||
|
func (c *Config) SparsePhiCutoff() uint64 { return c.sparsePhiCutoff }
|
||||||
|
|
||||||
// NewFunc returns a new, empty function object.
|
// NewFunc returns a new, empty function object.
|
||||||
// Caller must call f.Free() before calling NewFunc again.
|
// Caller must call f.Free() before calling NewFunc again.
|
||||||
|
|
@ -262,3 +281,7 @@ func (c *Config) DebugHashMatch(evname, name string) bool {
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Config) DebugNameMatch(evname, name string) bool {
|
||||||
|
return os.Getenv(evname) == name
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -137,10 +137,9 @@ func cse(f *Func) {
|
||||||
// if v and w are in the same equivalence class and v dominates w.
|
// if v and w are in the same equivalence class and v dominates w.
|
||||||
rewrite := make([]*Value, f.NumValues())
|
rewrite := make([]*Value, f.NumValues())
|
||||||
for _, e := range partition {
|
for _, e := range partition {
|
||||||
sort.Sort(sortbyentry{e, f.sdom})
|
sort.Sort(partitionByDom{e, f.sdom})
|
||||||
for i := 0; i < len(e)-1; i++ {
|
for i := 0; i < len(e)-1; i++ {
|
||||||
// e is sorted by entry value so maximal dominant element should be
|
// e is sorted by domorder, so a maximal dominant element is first in the slice
|
||||||
// found first in the slice
|
|
||||||
v := e[i]
|
v := e[i]
|
||||||
if v == nil {
|
if v == nil {
|
||||||
continue
|
continue
|
||||||
|
|
@ -157,9 +156,7 @@ func cse(f *Func) {
|
||||||
rewrite[w.ID] = v
|
rewrite[w.ID] = v
|
||||||
e[j] = nil
|
e[j] = nil
|
||||||
} else {
|
} else {
|
||||||
// since the blocks are assorted in ascending order by entry number
|
// e is sorted by domorder, so v.Block doesn't dominate any subsequent blocks in e
|
||||||
// once we know that we don't dominate a block we can't dominate any
|
|
||||||
// 'later' block
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -190,7 +187,7 @@ func cse(f *Func) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if f.pass.stats > 0 {
|
if f.pass.stats > 0 {
|
||||||
f.logStat("CSE REWRITES", rewrites)
|
f.LogStat("CSE REWRITES", rewrites)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -311,15 +308,15 @@ func (sv sortvalues) Less(i, j int) bool {
|
||||||
return v.ID < w.ID
|
return v.ID < w.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
type sortbyentry struct {
|
type partitionByDom struct {
|
||||||
a []*Value // array of values
|
a []*Value // array of values
|
||||||
sdom sparseTree
|
sdom SparseTree
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sv sortbyentry) Len() int { return len(sv.a) }
|
func (sv partitionByDom) Len() int { return len(sv.a) }
|
||||||
func (sv sortbyentry) Swap(i, j int) { sv.a[i], sv.a[j] = sv.a[j], sv.a[i] }
|
func (sv partitionByDom) Swap(i, j int) { sv.a[i], sv.a[j] = sv.a[j], sv.a[i] }
|
||||||
func (sv sortbyentry) Less(i, j int) bool {
|
func (sv partitionByDom) Less(i, j int) bool {
|
||||||
v := sv.a[i]
|
v := sv.a[i]
|
||||||
w := sv.a[j]
|
w := sv.a[j]
|
||||||
return sv.sdom.maxdomorder(v.Block) < sv.sdom.maxdomorder(w.Block)
|
return sv.sdom.domorder(v.Block) < sv.sdom.domorder(w.Block)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,9 @@ const (
|
||||||
// postorder computes a postorder traversal ordering for the
|
// postorder computes a postorder traversal ordering for the
|
||||||
// basic blocks in f. Unreachable blocks will not appear.
|
// basic blocks in f. Unreachable blocks will not appear.
|
||||||
func postorder(f *Func) []*Block {
|
func postorder(f *Func) []*Block {
|
||||||
return postorderWithNumbering(f, []int{})
|
return postorderWithNumbering(f, []int32{})
|
||||||
}
|
}
|
||||||
func postorderWithNumbering(f *Func, ponums []int) []*Block {
|
func postorderWithNumbering(f *Func, ponums []int32) []*Block {
|
||||||
mark := make([]markKind, f.NumBlocks())
|
mark := make([]markKind, f.NumBlocks())
|
||||||
|
|
||||||
// result ordering
|
// result ordering
|
||||||
|
|
@ -40,7 +40,7 @@ func postorderWithNumbering(f *Func, ponums []int) []*Block {
|
||||||
s = s[:len(s)-1]
|
s = s[:len(s)-1]
|
||||||
mark[b.ID] = done
|
mark[b.ID] = done
|
||||||
if len(ponums) > 0 {
|
if len(ponums) > 0 {
|
||||||
ponums[b.ID] = len(order)
|
ponums[b.ID] = int32(len(order))
|
||||||
}
|
}
|
||||||
order = append(order, b)
|
order = append(order, b)
|
||||||
case notExplored:
|
case notExplored:
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ type Func struct {
|
||||||
freeBlocks *Block // free Blocks linked by succstorage[0].b. All other fields except ID are 0/nil.
|
freeBlocks *Block // free Blocks linked by succstorage[0].b. All other fields except ID are 0/nil.
|
||||||
|
|
||||||
idom []*Block // precomputed immediate dominators
|
idom []*Block // precomputed immediate dominators
|
||||||
sdom sparseTree // precomputed dominator tree
|
sdom SparseTree // precomputed dominator tree
|
||||||
|
|
||||||
constants map[int64][]*Value // constants cache, keyed by constant value; users must check value's Op and Type
|
constants map[int64][]*Value // constants cache, keyed by constant value; users must check value's Op and Type
|
||||||
}
|
}
|
||||||
|
|
@ -104,12 +104,16 @@ func (f *Func) newValue(op Op, t Type, b *Block, line int32) *Value {
|
||||||
// context to allow item-by-item comparisons across runs.
|
// context to allow item-by-item comparisons across runs.
|
||||||
// For example:
|
// For example:
|
||||||
// awk 'BEGIN {FS="\t"} $3~/TIME/{sum+=$4} END{print "t(ns)=",sum}' t.log
|
// awk 'BEGIN {FS="\t"} $3~/TIME/{sum+=$4} END{print "t(ns)=",sum}' t.log
|
||||||
func (f *Func) logStat(key string, args ...interface{}) {
|
func (f *Func) LogStat(key string, args ...interface{}) {
|
||||||
value := ""
|
value := ""
|
||||||
for _, a := range args {
|
for _, a := range args {
|
||||||
value += fmt.Sprintf("\t%v", a)
|
value += fmt.Sprintf("\t%v", a)
|
||||||
}
|
}
|
||||||
f.Config.Warnl(f.Entry.Line, "\t%s\t%s%s\t%s", f.pass.name, key, value, f.Name)
|
n := "missing_pass"
|
||||||
|
if f.pass != nil {
|
||||||
|
n = f.pass.name
|
||||||
|
}
|
||||||
|
f.Config.Warnl(f.Entry.Line, "\t%s\t%s%s\t%s", n, key, value, f.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// freeValue frees a value. It must no longer be referenced.
|
// freeValue frees a value. It must no longer be referenced.
|
||||||
|
|
|
||||||
|
|
@ -382,9 +382,9 @@ var genericOps = []opData{
|
||||||
{name: "ComplexImag", argLength: 1}, // imag(arg0)
|
{name: "ComplexImag", argLength: 1}, // imag(arg0)
|
||||||
|
|
||||||
// Strings
|
// Strings
|
||||||
{name: "StringMake", argLength: 2}, // arg0=ptr, arg1=len
|
{name: "StringMake", argLength: 2}, // arg0=ptr, arg1=len
|
||||||
{name: "StringPtr", argLength: 1}, // ptr(arg0)
|
{name: "StringPtr", argLength: 1, typ: "BytePtr"}, // ptr(arg0)
|
||||||
{name: "StringLen", argLength: 1}, // len(arg0)
|
{name: "StringLen", argLength: 1, typ: "Int"}, // len(arg0)
|
||||||
|
|
||||||
// Interfaces
|
// Interfaces
|
||||||
{name: "IMake", argLength: 2}, // arg0=itab, arg1=data
|
{name: "IMake", argLength: 2}, // arg0=itab, arg1=data
|
||||||
|
|
@ -407,7 +407,7 @@ var genericOps = []opData{
|
||||||
{name: "LoadReg", argLength: 1},
|
{name: "LoadReg", argLength: 1},
|
||||||
|
|
||||||
// Used during ssa construction. Like Copy, but the arg has not been specified yet.
|
// Used during ssa construction. Like Copy, but the arg has not been specified yet.
|
||||||
{name: "FwdRef"},
|
{name: "FwdRef", aux: "Sym"},
|
||||||
|
|
||||||
// Unknown value. Used for Values whose values don't matter because they are dead code.
|
// Unknown value. Used for Values whose values don't matter because they are dead code.
|
||||||
{name: "Unknown"},
|
{name: "Unknown"},
|
||||||
|
|
@ -415,6 +415,7 @@ var genericOps = []opData{
|
||||||
{name: "VarDef", argLength: 1, aux: "Sym", typ: "Mem"}, // aux is a *gc.Node of a variable that is about to be initialized. arg0=mem, returns mem
|
{name: "VarDef", argLength: 1, aux: "Sym", typ: "Mem"}, // aux is a *gc.Node of a variable that is about to be initialized. arg0=mem, returns mem
|
||||||
{name: "VarKill", argLength: 1, aux: "Sym"}, // aux is a *gc.Node of a variable that is known to be dead. arg0=mem, returns mem
|
{name: "VarKill", argLength: 1, aux: "Sym"}, // aux is a *gc.Node of a variable that is known to be dead. arg0=mem, returns mem
|
||||||
{name: "VarLive", argLength: 1, aux: "Sym"}, // aux is a *gc.Node of a variable that must be kept live. arg0=mem, returns mem
|
{name: "VarLive", argLength: 1, aux: "Sym"}, // aux is a *gc.Node of a variable that must be kept live. arg0=mem, returns mem
|
||||||
|
{name: "KeepAlive", argLength: 2, typ: "Mem"}, // arg[0] is a value that must be kept alive until this mark. arg[1]=mem, returns mem
|
||||||
}
|
}
|
||||||
|
|
||||||
// kind control successors implicit exit
|
// kind control successors implicit exit
|
||||||
|
|
|
||||||
|
|
@ -150,9 +150,6 @@ func genRules(arch arch) {
|
||||||
fmt.Fprintln(w, "// generated with: cd gen; go run *.go")
|
fmt.Fprintln(w, "// generated with: cd gen; go run *.go")
|
||||||
fmt.Fprintln(w)
|
fmt.Fprintln(w)
|
||||||
fmt.Fprintln(w, "package ssa")
|
fmt.Fprintln(w, "package ssa")
|
||||||
if *genLog {
|
|
||||||
fmt.Fprintln(w, "import \"fmt\"")
|
|
||||||
}
|
|
||||||
fmt.Fprintln(w, "import \"math\"")
|
fmt.Fprintln(w, "import \"math\"")
|
||||||
fmt.Fprintln(w, "var _ = math.MinInt8 // in case not otherwise used")
|
fmt.Fprintln(w, "var _ = math.MinInt8 // in case not otherwise used")
|
||||||
|
|
||||||
|
|
@ -196,7 +193,7 @@ func genRules(arch arch) {
|
||||||
|
|
||||||
genResult(w, arch, result, rule.loc)
|
genResult(w, arch, result, rule.loc)
|
||||||
if *genLog {
|
if *genLog {
|
||||||
fmt.Fprintf(w, "fmt.Println(\"rewrite %s\")\n", rule.loc)
|
fmt.Fprintf(w, "logRule(\"%s\")\n", rule.loc)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(w, "return true\n")
|
fmt.Fprintf(w, "return true\n")
|
||||||
|
|
||||||
|
|
@ -300,7 +297,7 @@ func genRules(arch arch) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if *genLog {
|
if *genLog {
|
||||||
fmt.Fprintf(w, "fmt.Println(\"rewrite %s\")\n", rule.loc)
|
fmt.Fprintf(w, "logRule(\"%s\")\n", rule.loc)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(w, "return true\n")
|
fmt.Fprintf(w, "return true\n")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ type loop struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// outerinner records that outer contains inner
|
// outerinner records that outer contains inner
|
||||||
func (sdom sparseTree) outerinner(outer, inner *loop) {
|
func (sdom SparseTree) outerinner(outer, inner *loop) {
|
||||||
oldouter := inner.outer
|
oldouter := inner.outer
|
||||||
if oldouter == nil || sdom.isAncestorEq(oldouter.header, outer.header) {
|
if oldouter == nil || sdom.isAncestorEq(oldouter.header, outer.header) {
|
||||||
inner.outer = outer
|
inner.outer = outer
|
||||||
|
|
@ -59,7 +59,7 @@ type loopnest struct {
|
||||||
f *Func
|
f *Func
|
||||||
b2l []*loop
|
b2l []*loop
|
||||||
po []*Block
|
po []*Block
|
||||||
sdom sparseTree
|
sdom SparseTree
|
||||||
loops []*loop
|
loops []*loop
|
||||||
|
|
||||||
// Record which of the lazily initialized fields have actually been initialized.
|
// Record which of the lazily initialized fields have actually been initialized.
|
||||||
|
|
@ -238,7 +238,7 @@ func (l *loop) LongString() string {
|
||||||
// containing block b; the header must dominate b. loop itself
|
// containing block b; the header must dominate b. loop itself
|
||||||
// is assumed to not be that loop. For acceptable performance,
|
// is assumed to not be that loop. For acceptable performance,
|
||||||
// we're relying on loop nests to not be terribly deep.
|
// we're relying on loop nests to not be terribly deep.
|
||||||
func (l *loop) nearestOuterLoop(sdom sparseTree, b *Block) *loop {
|
func (l *loop) nearestOuterLoop(sdom SparseTree, b *Block) *loop {
|
||||||
var o *loop
|
var o *loop
|
||||||
for o = l.outer; o != nil && !sdom.isAncestorEq(o.header, b); o = o.outer {
|
for o = l.outer; o != nil && !sdom.isAncestorEq(o.header, b); o = o.outer {
|
||||||
}
|
}
|
||||||
|
|
@ -335,7 +335,7 @@ func loopnestfor(f *Func) *loopnest {
|
||||||
inner++
|
inner++
|
||||||
}
|
}
|
||||||
|
|
||||||
f.logStat("loopstats:",
|
f.LogStat("loopstats:",
|
||||||
l.depth, "depth", x, "exits",
|
l.depth, "depth", x, "exits",
|
||||||
inner, "is_inner", cf, "is_callfree", l.nBlocks, "n_blocks")
|
inner, "is_inner", cf, "is_callfree", l.nBlocks, "n_blocks")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ func checkLower(f *Func) {
|
||||||
continue // lowered
|
continue // lowered
|
||||||
}
|
}
|
||||||
switch v.Op {
|
switch v.Op {
|
||||||
case OpSP, OpSB, OpInitMem, OpArg, OpPhi, OpVarDef, OpVarKill, OpVarLive:
|
case OpSP, OpSB, OpInitMem, OpArg, OpPhi, OpVarDef, OpVarKill, OpVarLive, OpKeepAlive:
|
||||||
continue // ok not to lower
|
continue // ok not to lower
|
||||||
}
|
}
|
||||||
s := "not lowered: " + v.Op.String() + " " + v.Type.SimpleString()
|
s := "not lowered: " + v.Op.String() + " " + v.Type.SimpleString()
|
||||||
|
|
|
||||||
|
|
@ -674,6 +674,7 @@ const (
|
||||||
OpVarDef
|
OpVarDef
|
||||||
OpVarKill
|
OpVarKill
|
||||||
OpVarLive
|
OpVarLive
|
||||||
|
OpKeepAlive
|
||||||
)
|
)
|
||||||
|
|
||||||
var opcodeTable = [...]opInfo{
|
var opcodeTable = [...]opInfo{
|
||||||
|
|
@ -6167,6 +6168,7 @@ var opcodeTable = [...]opInfo{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "FwdRef",
|
name: "FwdRef",
|
||||||
|
auxType: auxSym,
|
||||||
argLen: 0,
|
argLen: 0,
|
||||||
generic: true,
|
generic: true,
|
||||||
},
|
},
|
||||||
|
|
@ -6193,6 +6195,11 @@ var opcodeTable = [...]opInfo{
|
||||||
argLen: 1,
|
argLen: 1,
|
||||||
generic: true,
|
generic: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "KeepAlive",
|
||||||
|
argLen: 2,
|
||||||
|
generic: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o Op) Asm() obj.As { return opcodeTable[o].asm }
|
func (o Op) Asm() obj.As { return opcodeTable[o].asm }
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ func benchFnPass(b *testing.B, fn passFunc, size int, bg blockGen) {
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
c := NewConfig("amd64", DummyFrontend{b}, nil, true)
|
c := NewConfig("amd64", DummyFrontend{b}, nil, true)
|
||||||
fun := Fun(c, "entry", bg(size)...)
|
fun := Fun(c, "entry", bg(size)...)
|
||||||
|
domTree(fun.f)
|
||||||
CheckFunc(fun.f)
|
CheckFunc(fun.f)
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
|
|
@ -51,7 +51,7 @@ func benchFnBlock(b *testing.B, fn passFunc, bg blockGen) {
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
c := NewConfig("amd64", DummyFrontend{b}, nil, true)
|
c := NewConfig("amd64", DummyFrontend{b}, nil, true)
|
||||||
fun := Fun(c, "entry", bg(b.N)...)
|
fun := Fun(c, "entry", bg(b.N)...)
|
||||||
|
domTree(fun.f)
|
||||||
CheckFunc(fun.f)
|
CheckFunc(fun.f)
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < passCount; i++ {
|
for i := 0; i < passCount; i++ {
|
||||||
|
|
|
||||||
|
|
@ -515,7 +515,7 @@ func prove(f *Func) {
|
||||||
|
|
||||||
// getBranch returns the range restrictions added by p
|
// getBranch returns the range restrictions added by p
|
||||||
// when reaching b. p is the immediate dominator of b.
|
// when reaching b. p is the immediate dominator of b.
|
||||||
func getBranch(sdom sparseTree, p *Block, b *Block) branch {
|
func getBranch(sdom SparseTree, p *Block, b *Block) branch {
|
||||||
if p == nil || p.Kind != BlockIf {
|
if p == nil || p.Kind != BlockIf {
|
||||||
return unknown
|
return unknown
|
||||||
}
|
}
|
||||||
|
|
|
||||||
429
src/cmd/compile/internal/ssa/redblack32.go
Normal file
429
src/cmd/compile/internal/ssa/redblack32.go
Normal file
|
|
@ -0,0 +1,429 @@
|
||||||
|
// Copyright 2016 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 ssa
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
const (
|
||||||
|
rankLeaf rbrank = 1
|
||||||
|
rankZero rbrank = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
type rbrank int8
|
||||||
|
|
||||||
|
// RBTint32 is a red-black tree with data stored at internal nodes,
|
||||||
|
// following Tarjan, Data Structures and Network Algorithms,
|
||||||
|
// pp 48-52, using explicit rank instead of red and black.
|
||||||
|
// Deletion is not yet implemented because it is not yet needed.
|
||||||
|
// Extra operations glb, lub, glbEq, lubEq are provided for
|
||||||
|
// use in sparse lookup algorithms.
|
||||||
|
type RBTint32 struct {
|
||||||
|
root *node32
|
||||||
|
// An extra-clever implementation will have special cases
|
||||||
|
// for small sets, but we are not extra-clever today.
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RBTint32) String() string {
|
||||||
|
if t.root == nil {
|
||||||
|
return "[]"
|
||||||
|
}
|
||||||
|
return "[" + t.root.String() + "]"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *node32) String() string {
|
||||||
|
s := ""
|
||||||
|
if t.left != nil {
|
||||||
|
s = t.left.String() + " "
|
||||||
|
}
|
||||||
|
s = s + fmt.Sprintf("k=%d,d=%v", t.key, t.data)
|
||||||
|
if t.right != nil {
|
||||||
|
s = s + " " + t.right.String()
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
type node32 struct {
|
||||||
|
// Standard conventions hold for left = smaller, right = larger
|
||||||
|
left, right, parent *node32
|
||||||
|
data interface{}
|
||||||
|
key int32
|
||||||
|
rank rbrank // From Tarjan pp 48-49:
|
||||||
|
// If x is a node with a parent, then x.rank <= x.parent.rank <= x.rank+1.
|
||||||
|
// If x is a node with a grandparent, then x.rank < x.parent.parent.rank.
|
||||||
|
// If x is an "external [null] node", then x.rank = 0 && x.parent.rank = 1.
|
||||||
|
// Any node with one or more null children should have rank = 1.
|
||||||
|
}
|
||||||
|
|
||||||
|
// makeNode returns a new leaf node with the given key and nil data.
|
||||||
|
func (t *RBTint32) makeNode(key int32) *node32 {
|
||||||
|
return &node32{key: key, rank: rankLeaf}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty reports whether t is empty.
|
||||||
|
func (t *RBTint32) IsEmpty() bool {
|
||||||
|
return t.root == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSingle reports whether t is a singleton (leaf).
|
||||||
|
func (t *RBTint32) IsSingle() bool {
|
||||||
|
return t.root != nil && t.root.isLeaf()
|
||||||
|
}
|
||||||
|
|
||||||
|
// VisitInOrder applies f to the key and data pairs in t,
|
||||||
|
// with keys ordered from smallest to largest.
|
||||||
|
func (t *RBTint32) VisitInOrder(f func(int32, interface{})) {
|
||||||
|
if t.root == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.root.visitInOrder(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *node32) Data() interface{} {
|
||||||
|
if n == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return n.data
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *node32) keyAndData() (k int32, d interface{}) {
|
||||||
|
if n == nil {
|
||||||
|
k = 0
|
||||||
|
d = nil
|
||||||
|
} else {
|
||||||
|
k = n.key
|
||||||
|
d = n.data
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *node32) Rank() rbrank {
|
||||||
|
if n == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return n.rank
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find returns the data associated with key in the tree, or
|
||||||
|
// nil if key is not in the tree.
|
||||||
|
func (t *RBTint32) Find(key int32) interface{} {
|
||||||
|
return t.root.find(key).Data()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert adds key to the tree and associates key with data.
|
||||||
|
// If key was already in the tree, it updates the associated data.
|
||||||
|
// Insert returns the previous data associated with key,
|
||||||
|
// or nil if key was not present.
|
||||||
|
// Insert panics if data is nil.
|
||||||
|
func (t *RBTint32) Insert(key int32, data interface{}) interface{} {
|
||||||
|
if data == nil {
|
||||||
|
panic("Cannot insert nil data into tree")
|
||||||
|
}
|
||||||
|
n := t.root
|
||||||
|
var newroot *node32
|
||||||
|
if n == nil {
|
||||||
|
n = t.makeNode(key)
|
||||||
|
newroot = n
|
||||||
|
} else {
|
||||||
|
newroot, n = n.insert(key, t)
|
||||||
|
}
|
||||||
|
r := n.data
|
||||||
|
n.data = data
|
||||||
|
t.root = newroot
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// Min returns the minimum element of t and its associated data.
|
||||||
|
// If t is empty, then (0, nil) is returned.
|
||||||
|
func (t *RBTint32) Min() (k int32, d interface{}) {
|
||||||
|
return t.root.min().keyAndData()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Max returns the maximum element of t and its associated data.
|
||||||
|
// If t is empty, then (0, nil) is returned.
|
||||||
|
func (t *RBTint32) Max() (k int32, d interface{}) {
|
||||||
|
return t.root.max().keyAndData()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Glb returns the greatest-lower-bound-exclusive of x and its associated
|
||||||
|
// data. If x has no glb in the tree, then (0, nil) is returned.
|
||||||
|
func (t *RBTint32) Glb(x int32) (k int32, d interface{}) {
|
||||||
|
return t.root.glb(x, false).keyAndData()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GlbEq returns the greatest-lower-bound-inclusive of x and its associated
|
||||||
|
// data. If x has no glbEQ in the tree, then (0, nil) is returned.
|
||||||
|
func (t *RBTint32) GlbEq(x int32) (k int32, d interface{}) {
|
||||||
|
return t.root.glb(x, true).keyAndData()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lub returns the least-upper-bound-exclusive of x and its associated
|
||||||
|
// data. If x has no lub in the tree, then (0, nil) is returned.
|
||||||
|
func (t *RBTint32) Lub(x int32) (k int32, d interface{}) {
|
||||||
|
return t.root.lub(x, false).keyAndData()
|
||||||
|
}
|
||||||
|
|
||||||
|
// LubEq returns the least-upper-bound-inclusive of x and its associated
|
||||||
|
// data. If x has no lubEq in the tree, then (0, nil) is returned.
|
||||||
|
func (t *RBTint32) LubEq(x int32) (k int32, d interface{}) {
|
||||||
|
return t.root.lub(x, true).keyAndData()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *node32) isLeaf() bool {
|
||||||
|
return t.left == nil && t.right == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *node32) visitInOrder(f func(int32, interface{})) {
|
||||||
|
if t.left != nil {
|
||||||
|
t.left.visitInOrder(f)
|
||||||
|
}
|
||||||
|
f(t.key, t.data)
|
||||||
|
if t.right != nil {
|
||||||
|
t.right.visitInOrder(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *node32) maxChildRank() rbrank {
|
||||||
|
if t.left == nil {
|
||||||
|
if t.right == nil {
|
||||||
|
return rankZero
|
||||||
|
}
|
||||||
|
return t.right.rank
|
||||||
|
}
|
||||||
|
if t.right == nil {
|
||||||
|
return t.left.rank
|
||||||
|
}
|
||||||
|
if t.right.rank > t.left.rank {
|
||||||
|
return t.right.rank
|
||||||
|
}
|
||||||
|
return t.left.rank
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *node32) minChildRank() rbrank {
|
||||||
|
if t.left == nil || t.right == nil {
|
||||||
|
return rankZero
|
||||||
|
}
|
||||||
|
if t.right.rank < t.left.rank {
|
||||||
|
return t.right.rank
|
||||||
|
}
|
||||||
|
return t.left.rank
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *node32) find(key int32) *node32 {
|
||||||
|
for t != nil {
|
||||||
|
if key < t.key {
|
||||||
|
t = t.left
|
||||||
|
} else if key > t.key {
|
||||||
|
t = t.right
|
||||||
|
} else {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *node32) min() *node32 {
|
||||||
|
if t == nil {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
for t.left != nil {
|
||||||
|
t = t.left
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *node32) max() *node32 {
|
||||||
|
if t == nil {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
for t.right != nil {
|
||||||
|
t = t.right
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *node32) glb(key int32, allow_eq bool) *node32 {
|
||||||
|
var best *node32 = nil
|
||||||
|
for t != nil {
|
||||||
|
if key <= t.key {
|
||||||
|
if key == t.key && allow_eq {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
// t is too big, glb is to left.
|
||||||
|
t = t.left
|
||||||
|
} else {
|
||||||
|
// t is a lower bound, record it and seek a better one.
|
||||||
|
best = t
|
||||||
|
t = t.right
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return best
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *node32) lub(key int32, allow_eq bool) *node32 {
|
||||||
|
var best *node32 = nil
|
||||||
|
for t != nil {
|
||||||
|
if key >= t.key {
|
||||||
|
if key == t.key && allow_eq {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
// t is too small, lub is to right.
|
||||||
|
t = t.right
|
||||||
|
} else {
|
||||||
|
// t is a upper bound, record it and seek a better one.
|
||||||
|
best = t
|
||||||
|
t = t.left
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return best
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *node32) insert(x int32, w *RBTint32) (newroot, newnode *node32) {
|
||||||
|
// defaults
|
||||||
|
newroot = t
|
||||||
|
newnode = t
|
||||||
|
if x == t.key {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if x < t.key {
|
||||||
|
if t.left == nil {
|
||||||
|
n := w.makeNode(x)
|
||||||
|
n.parent = t
|
||||||
|
t.left = n
|
||||||
|
newnode = n
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var new_l *node32
|
||||||
|
new_l, newnode = t.left.insert(x, w)
|
||||||
|
t.left = new_l
|
||||||
|
new_l.parent = t
|
||||||
|
newrank := 1 + new_l.maxChildRank()
|
||||||
|
if newrank > t.rank {
|
||||||
|
if newrank > 1+t.right.Rank() { // rotations required
|
||||||
|
if new_l.left.Rank() < new_l.right.Rank() {
|
||||||
|
// double rotation
|
||||||
|
t.left = new_l.rightToRoot()
|
||||||
|
}
|
||||||
|
newroot = t.leftToRoot()
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
t.rank = newrank
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // x > t.key
|
||||||
|
if t.right == nil {
|
||||||
|
n := w.makeNode(x)
|
||||||
|
n.parent = t
|
||||||
|
t.right = n
|
||||||
|
newnode = n
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var new_r *node32
|
||||||
|
new_r, newnode = t.right.insert(x, w)
|
||||||
|
t.right = new_r
|
||||||
|
new_r.parent = t
|
||||||
|
newrank := 1 + new_r.maxChildRank()
|
||||||
|
if newrank > t.rank {
|
||||||
|
if newrank > 1+t.left.Rank() { // rotations required
|
||||||
|
if new_r.right.Rank() < new_r.left.Rank() {
|
||||||
|
// double rotation
|
||||||
|
t.right = new_r.leftToRoot()
|
||||||
|
}
|
||||||
|
newroot = t.rightToRoot()
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
t.rank = newrank
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *node32) rightToRoot() *node32 {
|
||||||
|
// this
|
||||||
|
// left right
|
||||||
|
// rl rr
|
||||||
|
//
|
||||||
|
// becomes
|
||||||
|
//
|
||||||
|
// right
|
||||||
|
// this rr
|
||||||
|
// left rl
|
||||||
|
//
|
||||||
|
right := t.right
|
||||||
|
rl := right.left
|
||||||
|
right.parent = t.parent
|
||||||
|
right.left = t
|
||||||
|
t.parent = right
|
||||||
|
// parent's child ptr fixed in caller
|
||||||
|
t.right = rl
|
||||||
|
if rl != nil {
|
||||||
|
rl.parent = t
|
||||||
|
}
|
||||||
|
return right
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *node32) leftToRoot() *node32 {
|
||||||
|
// this
|
||||||
|
// left right
|
||||||
|
// ll lr
|
||||||
|
//
|
||||||
|
// becomes
|
||||||
|
//
|
||||||
|
// left
|
||||||
|
// ll this
|
||||||
|
// lr right
|
||||||
|
//
|
||||||
|
left := t.left
|
||||||
|
lr := left.right
|
||||||
|
left.parent = t.parent
|
||||||
|
left.right = t
|
||||||
|
t.parent = left
|
||||||
|
// parent's child ptr fixed in caller
|
||||||
|
t.left = lr
|
||||||
|
if lr != nil {
|
||||||
|
lr.parent = t
|
||||||
|
}
|
||||||
|
return left
|
||||||
|
}
|
||||||
|
|
||||||
|
// next returns the successor of t in a left-to-right
|
||||||
|
// walk of the tree in which t is embedded.
|
||||||
|
func (t *node32) next() *node32 {
|
||||||
|
// If there is a right child, it is to the right
|
||||||
|
r := t.right
|
||||||
|
if r != nil {
|
||||||
|
return r.min()
|
||||||
|
}
|
||||||
|
// if t is p.left, then p, else repeat.
|
||||||
|
p := t.parent
|
||||||
|
for p != nil {
|
||||||
|
if p.left == t {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
t = p
|
||||||
|
p = t.parent
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// prev returns the predecessor of t in a left-to-right
|
||||||
|
// walk of the tree in which t is embedded.
|
||||||
|
func (t *node32) prev() *node32 {
|
||||||
|
// If there is a left child, it is to the left
|
||||||
|
l := t.left
|
||||||
|
if l != nil {
|
||||||
|
return l.max()
|
||||||
|
}
|
||||||
|
// if t is p.right, then p, else repeat.
|
||||||
|
p := t.parent
|
||||||
|
for p != nil {
|
||||||
|
if p.right == t {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
t = p
|
||||||
|
p = t.parent
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
276
src/cmd/compile/internal/ssa/redblack32_test.go
Normal file
276
src/cmd/compile/internal/ssa/redblack32_test.go
Normal file
|
|
@ -0,0 +1,276 @@
|
||||||
|
// Copyright 2016 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 ssa
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type sstring string
|
||||||
|
|
||||||
|
func (s sstring) String() string {
|
||||||
|
return string(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// wellFormed ensures that a red-black tree meets
|
||||||
|
// all of its invariants and returns a string identifying
|
||||||
|
// the first problem encountered. If there is no problem
|
||||||
|
// then the returned string is empty. The size is also
|
||||||
|
// returned to allow comparison of calculated tree size
|
||||||
|
// with expected.
|
||||||
|
func (t *RBTint32) wellFormed() (s string, i int) {
|
||||||
|
if t.root == nil {
|
||||||
|
s = ""
|
||||||
|
i = 0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return t.root.wellFormedSubtree(nil, -0x80000000, 0x7fffffff)
|
||||||
|
}
|
||||||
|
|
||||||
|
// wellFormedSubtree ensures that a red-black subtree meets
|
||||||
|
// all of its invariants and returns a string identifying
|
||||||
|
// the first problem encountered. If there is no problem
|
||||||
|
// then the returned string is empty. The size is also
|
||||||
|
// returned to allow comparison of calculated tree size
|
||||||
|
// with expected.
|
||||||
|
func (t *node32) wellFormedSubtree(parent *node32, min, max int32) (s string, i int) {
|
||||||
|
i = -1 // initialize to a failing value
|
||||||
|
s = "" // s is the reason for failure; empty means okay.
|
||||||
|
|
||||||
|
if t.parent != parent {
|
||||||
|
s = "t.parent != parent"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if min >= t.key {
|
||||||
|
s = "min >= t.key"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if max <= t.key {
|
||||||
|
s = "max <= t.key"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
l := t.left
|
||||||
|
r := t.right
|
||||||
|
if l == nil && r == nil {
|
||||||
|
if t.rank != rankLeaf {
|
||||||
|
s = "leaf rank wrong"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if l != nil {
|
||||||
|
if t.rank < l.rank {
|
||||||
|
s = "t.rank < l.rank"
|
||||||
|
} else if t.rank > 1+l.rank {
|
||||||
|
s = "t.rank > 1+l.rank"
|
||||||
|
} else if t.rank <= l.maxChildRank() {
|
||||||
|
s = "t.rank <= l.maxChildRank()"
|
||||||
|
} else if t.key <= l.key {
|
||||||
|
s = "t.key <= l.key"
|
||||||
|
}
|
||||||
|
if s != "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if t.rank != 1 {
|
||||||
|
s = "t w/ left nil has rank != 1"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if r != nil {
|
||||||
|
if t.rank < r.rank {
|
||||||
|
s = "t.rank < r.rank"
|
||||||
|
} else if t.rank > 1+r.rank {
|
||||||
|
s = "t.rank > 1+r.rank"
|
||||||
|
} else if t.rank <= r.maxChildRank() {
|
||||||
|
s = "t.rank <= r.maxChildRank()"
|
||||||
|
} else if t.key >= r.key {
|
||||||
|
s = "t.key >= r.key"
|
||||||
|
}
|
||||||
|
if s != "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if t.rank != 1 {
|
||||||
|
s = "t w/ right nil has rank != 1"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ii := 1
|
||||||
|
if l != nil {
|
||||||
|
res, il := l.wellFormedSubtree(t, min, t.key)
|
||||||
|
if res != "" {
|
||||||
|
s = "L." + res
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ii += il
|
||||||
|
}
|
||||||
|
if r != nil {
|
||||||
|
res, ir := r.wellFormedSubtree(t, t.key, max)
|
||||||
|
if res != "" {
|
||||||
|
s = "R." + res
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ii += ir
|
||||||
|
}
|
||||||
|
i = ii
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RBTint32) DebugString() string {
|
||||||
|
if t.root == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return t.root.DebugString()
|
||||||
|
}
|
||||||
|
|
||||||
|
// DebugString prints the tree with nested information
|
||||||
|
// to allow an eyeball check on the tree balance.
|
||||||
|
func (t *node32) DebugString() string {
|
||||||
|
s := ""
|
||||||
|
if t.left != nil {
|
||||||
|
s = s + "["
|
||||||
|
s = s + t.left.DebugString()
|
||||||
|
s = s + "]"
|
||||||
|
}
|
||||||
|
s = s + fmt.Sprintf("%v=%v:%d", t.key, t.data, t.rank)
|
||||||
|
if t.right != nil {
|
||||||
|
s = s + "["
|
||||||
|
s = s + t.right.DebugString()
|
||||||
|
s = s + "]"
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func allRBT32Ops(te *testing.T, x []int32) {
|
||||||
|
t := &RBTint32{}
|
||||||
|
for i, d := range x {
|
||||||
|
x[i] = d + d // Double everything for glb/lub testing
|
||||||
|
}
|
||||||
|
|
||||||
|
// fmt.Printf("Inserting double of %v", x)
|
||||||
|
k := 0
|
||||||
|
min := int32(0x7fffffff)
|
||||||
|
max := int32(-0x80000000)
|
||||||
|
for _, d := range x {
|
||||||
|
if d < min {
|
||||||
|
min = d
|
||||||
|
}
|
||||||
|
|
||||||
|
if d > max {
|
||||||
|
max = d
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Insert(d, sstring(fmt.Sprintf("%v", d)))
|
||||||
|
k++
|
||||||
|
s, i := t.wellFormed()
|
||||||
|
if i != k {
|
||||||
|
te.Errorf("Wrong tree size %v, expected %v for %v", i, k, t.DebugString())
|
||||||
|
}
|
||||||
|
if s != "" {
|
||||||
|
te.Errorf("Tree consistency problem at %v", s)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
// fmt.Printf("%s", t.DebugString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
oops := false
|
||||||
|
|
||||||
|
for _, d := range x {
|
||||||
|
s := fmt.Sprintf("%v", d)
|
||||||
|
f := t.Find(d)
|
||||||
|
|
||||||
|
// data
|
||||||
|
if s != fmt.Sprintf("%v", f) {
|
||||||
|
te.Errorf("s(%v) != f(%v)", s, f)
|
||||||
|
oops = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !oops {
|
||||||
|
for _, d := range x {
|
||||||
|
s := fmt.Sprintf("%v", d)
|
||||||
|
|
||||||
|
kg, g := t.Glb(d + 1)
|
||||||
|
kge, ge := t.GlbEq(d)
|
||||||
|
kl, l := t.Lub(d - 1)
|
||||||
|
kle, le := t.LubEq(d)
|
||||||
|
|
||||||
|
// keys
|
||||||
|
if d != kg {
|
||||||
|
te.Errorf("d(%v) != kg(%v)", d, kg)
|
||||||
|
}
|
||||||
|
if d != kl {
|
||||||
|
te.Errorf("d(%v) != kl(%v)", d, kl)
|
||||||
|
}
|
||||||
|
if d != kge {
|
||||||
|
te.Errorf("d(%v) != kge(%v)", d, kge)
|
||||||
|
}
|
||||||
|
if d != kle {
|
||||||
|
te.Errorf("d(%v) != kle(%v)", d, kle)
|
||||||
|
}
|
||||||
|
// data
|
||||||
|
if s != fmt.Sprintf("%v", g) {
|
||||||
|
te.Errorf("s(%v) != g(%v)", s, g)
|
||||||
|
}
|
||||||
|
if s != fmt.Sprintf("%v", l) {
|
||||||
|
te.Errorf("s(%v) != l(%v)", s, l)
|
||||||
|
}
|
||||||
|
if s != fmt.Sprintf("%v", ge) {
|
||||||
|
te.Errorf("s(%v) != ge(%v)", s, ge)
|
||||||
|
}
|
||||||
|
if s != fmt.Sprintf("%v", le) {
|
||||||
|
te.Errorf("s(%v) != le(%v)", s, le)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, d := range x {
|
||||||
|
s := fmt.Sprintf("%v", d)
|
||||||
|
kge, ge := t.GlbEq(d + 1)
|
||||||
|
kle, le := t.LubEq(d - 1)
|
||||||
|
if d != kge {
|
||||||
|
te.Errorf("d(%v) != kge(%v)", d, kge)
|
||||||
|
}
|
||||||
|
if d != kle {
|
||||||
|
te.Errorf("d(%v) != kle(%v)", d, kle)
|
||||||
|
}
|
||||||
|
if s != fmt.Sprintf("%v", ge) {
|
||||||
|
te.Errorf("s(%v) != ge(%v)", s, ge)
|
||||||
|
}
|
||||||
|
if s != fmt.Sprintf("%v", le) {
|
||||||
|
te.Errorf("s(%v) != le(%v)", s, le)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kg, g := t.Glb(min)
|
||||||
|
kge, ge := t.GlbEq(min - 1)
|
||||||
|
kl, l := t.Lub(max)
|
||||||
|
kle, le := t.LubEq(max + 1)
|
||||||
|
fmin := t.Find(min - 1)
|
||||||
|
fmax := t.Find(min + 11)
|
||||||
|
|
||||||
|
if kg != 0 || kge != 0 || kl != 0 || kle != 0 {
|
||||||
|
te.Errorf("Got non-zero-key for missing query")
|
||||||
|
}
|
||||||
|
|
||||||
|
if g != nil || ge != nil || l != nil || le != nil || fmin != nil || fmax != nil {
|
||||||
|
te.Errorf("Got non-error-data for missing query")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAllRBTreeOps(t *testing.T) {
|
||||||
|
allRBT32Ops(t, []int32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25})
|
||||||
|
allRBT32Ops(t, []int32{22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 3, 2, 1, 25, 24, 23, 12, 11, 10, 9, 8, 7, 6, 5, 4})
|
||||||
|
allRBT32Ops(t, []int32{25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1})
|
||||||
|
allRBT32Ops(t, []int32{1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24})
|
||||||
|
allRBT32Ops(t, []int32{1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2})
|
||||||
|
allRBT32Ops(t, []int32{24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25})
|
||||||
|
}
|
||||||
|
|
@ -106,7 +106,6 @@
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"cmd/internal/obj"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
@ -456,7 +455,7 @@ func (s *regAllocState) init(f *Func) {
|
||||||
s.allocatable = regMask(1)<<s.numRegs - 1
|
s.allocatable = regMask(1)<<s.numRegs - 1
|
||||||
s.allocatable &^= 1 << s.SPReg
|
s.allocatable &^= 1 << s.SPReg
|
||||||
s.allocatable &^= 1 << s.SBReg
|
s.allocatable &^= 1 << s.SBReg
|
||||||
if obj.Framepointer_enabled != 0 {
|
if s.f.Config.ctxt.Framepointer_enabled {
|
||||||
s.allocatable &^= 1 << 5 // BP
|
s.allocatable &^= 1 << 5 // BP
|
||||||
}
|
}
|
||||||
if s.f.Config.ctxt.Flag_dynlink {
|
if s.f.Config.ctxt.Flag_dynlink {
|
||||||
|
|
@ -941,11 +940,29 @@ func (s *regAllocState) regalloc(f *Func) {
|
||||||
s.advanceUses(v)
|
s.advanceUses(v)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if v.Op == OpKeepAlive {
|
||||||
|
// Make sure the argument to v is still live here.
|
||||||
|
s.advanceUses(v)
|
||||||
|
vi := &s.values[v.Args[0].ID]
|
||||||
|
if vi.spillUsed {
|
||||||
|
// Use the spill location.
|
||||||
|
v.SetArg(0, vi.spill)
|
||||||
|
} else {
|
||||||
|
// No need to keep unspilled values live.
|
||||||
|
// These are typically rematerializeable constants like nil,
|
||||||
|
// or values of a variable that were modified since the last call.
|
||||||
|
v.Op = OpCopy
|
||||||
|
v.SetArgs1(v.Args[1])
|
||||||
|
}
|
||||||
|
b.Values = append(b.Values, v)
|
||||||
|
continue
|
||||||
|
}
|
||||||
regspec := opcodeTable[v.Op].reg
|
regspec := opcodeTable[v.Op].reg
|
||||||
if len(regspec.inputs) == 0 && len(regspec.outputs) == 0 {
|
if len(regspec.inputs) == 0 && len(regspec.outputs) == 0 {
|
||||||
// No register allocation required (or none specified yet)
|
// No register allocation required (or none specified yet)
|
||||||
s.freeRegs(regspec.clobbers)
|
s.freeRegs(regspec.clobbers)
|
||||||
b.Values = append(b.Values, v)
|
b.Values = append(b.Values, v)
|
||||||
|
s.advanceUses(v)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1311,20 +1328,25 @@ func (s *regAllocState) regalloc(f *Func) {
|
||||||
// Start with live at end.
|
// Start with live at end.
|
||||||
for _, li := range s.live[ss.ID] {
|
for _, li := range s.live[ss.ID] {
|
||||||
if s.isLoopSpillCandidate(loop, s.orig[li.ID]) {
|
if s.isLoopSpillCandidate(loop, s.orig[li.ID]) {
|
||||||
|
// s.live contains original IDs, use s.orig above to map back to *Value
|
||||||
entryCandidates.setBit(li.ID, uint(whichExit))
|
entryCandidates.setBit(li.ID, uint(whichExit))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Control can also be live.
|
// Control can also be live.
|
||||||
if ss.Control != nil && s.isLoopSpillCandidate(loop, ss.Control) {
|
if ss.Control != nil && s.orig[ss.Control.ID] != nil && s.isLoopSpillCandidate(loop, s.orig[ss.Control.ID]) {
|
||||||
entryCandidates.setBit(ss.Control.ID, uint(whichExit))
|
entryCandidates.setBit(s.orig[ss.Control.ID].ID, uint(whichExit))
|
||||||
}
|
}
|
||||||
// Walk backwards, filling in locally live values, removing those defined.
|
// Walk backwards, filling in locally live values, removing those defined.
|
||||||
for i := len(ss.Values) - 1; i >= 0; i-- {
|
for i := len(ss.Values) - 1; i >= 0; i-- {
|
||||||
v := ss.Values[i]
|
v := ss.Values[i]
|
||||||
entryCandidates.remove(v.ID) // Cannot be an issue, only keeps the sets smaller.
|
vorig := s.orig[v.ID]
|
||||||
|
if vorig != nil {
|
||||||
|
entryCandidates.remove(vorig.ID) // Cannot be an issue, only keeps the sets smaller.
|
||||||
|
}
|
||||||
for _, a := range v.Args {
|
for _, a := range v.Args {
|
||||||
if s.isLoopSpillCandidate(loop, a) {
|
aorig := s.orig[a.ID]
|
||||||
entryCandidates.setBit(a.ID, uint(whichExit))
|
if aorig != nil && s.isLoopSpillCandidate(loop, aorig) {
|
||||||
|
entryCandidates.setBit(aorig.ID, uint(whichExit))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1524,7 +1546,7 @@ sinking:
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.pass.stats > 0 {
|
if f.pass.stats > 0 {
|
||||||
f.logStat("spills_info",
|
f.LogStat("spills_info",
|
||||||
nSpills, "spills", nSpillsInner, "inner_spills_remaining", nSpillsSunk, "inner_spills_sunk", nSpillsSunkUnused, "inner_spills_unused", nSpillsNotSunkLateUse, "inner_spills_shuffled", nSpillsChanged, "inner_spills_changed")
|
nSpills, "spills", nSpillsInner, "inner_spills_remaining", nSpillsSunk, "inner_spills_sunk", nSpillsSunkUnused, "inner_spills_unused", nSpillsNotSunkLateUse, "inner_spills_shuffled", nSpillsChanged, "inner_spills_changed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ package ssa
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
func applyRewrite(f *Func, rb func(*Block) bool, rv func(*Value, *Config) bool) {
|
func applyRewrite(f *Func, rb func(*Block) bool, rv func(*Value, *Config) bool) {
|
||||||
|
|
@ -357,3 +359,28 @@ func clobber(v *Value) bool {
|
||||||
// Note: leave v.Block intact. The Block field is used after clobber.
|
// Note: leave v.Block intact. The Block field is used after clobber.
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// logRule logs the use of the rule s. This will only be enabled if
|
||||||
|
// rewrite rules were generated with the -log option, see gen/rulegen.go.
|
||||||
|
func logRule(s string) {
|
||||||
|
if ruleFile == nil {
|
||||||
|
// Open a log file to write log to. We open in append
|
||||||
|
// mode because all.bash runs the compiler lots of times,
|
||||||
|
// and we want the concatenation of all of those logs.
|
||||||
|
// This means, of course, that users need to rm the old log
|
||||||
|
// to get fresh data.
|
||||||
|
// TODO: all.bash runs compilers in parallel. Need to synchronize logging somehow?
|
||||||
|
w, err := os.OpenFile(filepath.Join(os.Getenv("GOROOT"), "src", "rulelog"),
|
||||||
|
os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
ruleFile = w
|
||||||
|
}
|
||||||
|
_, err := fmt.Fprintf(ruleFile, "rewrite %s\n", s)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ruleFile *os.File
|
||||||
|
|
|
||||||
|
|
@ -14,13 +14,13 @@ type sparseEntry struct {
|
||||||
|
|
||||||
type sparseMap struct {
|
type sparseMap struct {
|
||||||
dense []sparseEntry
|
dense []sparseEntry
|
||||||
sparse []int
|
sparse []int32
|
||||||
}
|
}
|
||||||
|
|
||||||
// newSparseMap returns a sparseMap that can map
|
// newSparseMap returns a sparseMap that can map
|
||||||
// integers between 0 and n-1 to int32s.
|
// integers between 0 and n-1 to int32s.
|
||||||
func newSparseMap(n int) *sparseMap {
|
func newSparseMap(n int) *sparseMap {
|
||||||
return &sparseMap{nil, make([]int, n)}
|
return &sparseMap{dense: nil, sparse: make([]int32, n)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *sparseMap) size() int {
|
func (s *sparseMap) size() int {
|
||||||
|
|
@ -29,14 +29,14 @@ func (s *sparseMap) size() int {
|
||||||
|
|
||||||
func (s *sparseMap) contains(k ID) bool {
|
func (s *sparseMap) contains(k ID) bool {
|
||||||
i := s.sparse[k]
|
i := s.sparse[k]
|
||||||
return i < len(s.dense) && s.dense[i].key == k
|
return i < int32(len(s.dense)) && s.dense[i].key == k
|
||||||
}
|
}
|
||||||
|
|
||||||
// get returns the value for key k, or -1 if k does
|
// get returns the value for key k, or -1 if k does
|
||||||
// not appear in the map.
|
// not appear in the map.
|
||||||
func (s *sparseMap) get(k ID) int32 {
|
func (s *sparseMap) get(k ID) int32 {
|
||||||
i := s.sparse[k]
|
i := s.sparse[k]
|
||||||
if i < len(s.dense) && s.dense[i].key == k {
|
if i < int32(len(s.dense)) && s.dense[i].key == k {
|
||||||
return s.dense[i].val
|
return s.dense[i].val
|
||||||
}
|
}
|
||||||
return -1
|
return -1
|
||||||
|
|
@ -44,12 +44,12 @@ func (s *sparseMap) get(k ID) int32 {
|
||||||
|
|
||||||
func (s *sparseMap) set(k ID, v int32) {
|
func (s *sparseMap) set(k ID, v int32) {
|
||||||
i := s.sparse[k]
|
i := s.sparse[k]
|
||||||
if i < len(s.dense) && s.dense[i].key == k {
|
if i < int32(len(s.dense)) && s.dense[i].key == k {
|
||||||
s.dense[i].val = v
|
s.dense[i].val = v
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.dense = append(s.dense, sparseEntry{k, v})
|
s.dense = append(s.dense, sparseEntry{k, v})
|
||||||
s.sparse[k] = len(s.dense) - 1
|
s.sparse[k] = int32(len(s.dense)) - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// setBit sets the v'th bit of k's value, where 0 <= v < 32
|
// setBit sets the v'th bit of k's value, where 0 <= v < 32
|
||||||
|
|
@ -58,17 +58,17 @@ func (s *sparseMap) setBit(k ID, v uint) {
|
||||||
panic("bit index too large.")
|
panic("bit index too large.")
|
||||||
}
|
}
|
||||||
i := s.sparse[k]
|
i := s.sparse[k]
|
||||||
if i < len(s.dense) && s.dense[i].key == k {
|
if i < int32(len(s.dense)) && s.dense[i].key == k {
|
||||||
s.dense[i].val |= 1 << v
|
s.dense[i].val |= 1 << v
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.dense = append(s.dense, sparseEntry{k, 1 << v})
|
s.dense = append(s.dense, sparseEntry{k, 1 << v})
|
||||||
s.sparse[k] = len(s.dense) - 1
|
s.sparse[k] = int32(len(s.dense)) - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *sparseMap) remove(k ID) {
|
func (s *sparseMap) remove(k ID) {
|
||||||
i := s.sparse[k]
|
i := s.sparse[k]
|
||||||
if i < len(s.dense) && s.dense[i].key == k {
|
if i < int32(len(s.dense)) && s.dense[i].key == k {
|
||||||
y := s.dense[len(s.dense)-1]
|
y := s.dense[len(s.dense)-1]
|
||||||
s.dense[i] = y
|
s.dense[i] = y
|
||||||
s.sparse[y.key] = i
|
s.sparse[y.key] = i
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,13 @@ package ssa
|
||||||
|
|
||||||
type sparseSet struct {
|
type sparseSet struct {
|
||||||
dense []ID
|
dense []ID
|
||||||
sparse []int
|
sparse []int32
|
||||||
}
|
}
|
||||||
|
|
||||||
// newSparseSet returns a sparseSet that can represent
|
// newSparseSet returns a sparseSet that can represent
|
||||||
// integers between 0 and n-1
|
// integers between 0 and n-1
|
||||||
func newSparseSet(n int) *sparseSet {
|
func newSparseSet(n int) *sparseSet {
|
||||||
return &sparseSet{nil, make([]int, n)}
|
return &sparseSet{dense: nil, sparse: make([]int32, n)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *sparseSet) cap() int {
|
func (s *sparseSet) cap() int {
|
||||||
|
|
@ -28,16 +28,16 @@ func (s *sparseSet) size() int {
|
||||||
|
|
||||||
func (s *sparseSet) contains(x ID) bool {
|
func (s *sparseSet) contains(x ID) bool {
|
||||||
i := s.sparse[x]
|
i := s.sparse[x]
|
||||||
return i < len(s.dense) && s.dense[i] == x
|
return i < int32(len(s.dense)) && s.dense[i] == x
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *sparseSet) add(x ID) {
|
func (s *sparseSet) add(x ID) {
|
||||||
i := s.sparse[x]
|
i := s.sparse[x]
|
||||||
if i < len(s.dense) && s.dense[i] == x {
|
if i < int32(len(s.dense)) && s.dense[i] == x {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.dense = append(s.dense, x)
|
s.dense = append(s.dense, x)
|
||||||
s.sparse[x] = len(s.dense) - 1
|
s.sparse[x] = int32(len(s.dense)) - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *sparseSet) addAll(a []ID) {
|
func (s *sparseSet) addAll(a []ID) {
|
||||||
|
|
@ -54,7 +54,7 @@ func (s *sparseSet) addAllValues(a []*Value) {
|
||||||
|
|
||||||
func (s *sparseSet) remove(x ID) {
|
func (s *sparseSet) remove(x ID) {
|
||||||
i := s.sparse[x]
|
i := s.sparse[x]
|
||||||
if i < len(s.dense) && s.dense[i] == x {
|
if i < int32(len(s.dense)) && s.dense[i] == x {
|
||||||
y := s.dense[len(s.dense)-1]
|
y := s.dense[len(s.dense)-1]
|
||||||
s.dense[i] = y
|
s.dense[i] = y
|
||||||
s.sparse[y] = i
|
s.sparse[y] = i
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,9 @@
|
||||||
|
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
type sparseTreeNode struct {
|
import "fmt"
|
||||||
|
|
||||||
|
type SparseTreeNode struct {
|
||||||
child *Block
|
child *Block
|
||||||
sibling *Block
|
sibling *Block
|
||||||
parent *Block
|
parent *Block
|
||||||
|
|
@ -20,26 +22,39 @@ type sparseTreeNode struct {
|
||||||
entry, exit int32
|
entry, exit int32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SparseTreeNode) String() string {
|
||||||
|
return fmt.Sprintf("[%d,%d]", s.entry, s.exit)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SparseTreeNode) Entry() int32 {
|
||||||
|
return s.entry
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SparseTreeNode) Exit() int32 {
|
||||||
|
return s.exit
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// When used to lookup up definitions in a sparse tree,
|
// When used to lookup up definitions in a sparse tree,
|
||||||
// these adjustments to a block's entry (+adjust) and
|
// these adjustments to a block's entry (+adjust) and
|
||||||
// exit (-adjust) numbers allow a distinction to be made
|
// exit (-adjust) numbers allow a distinction to be made
|
||||||
// between assignments (typically branch-dependent
|
// between assignments (typically branch-dependent
|
||||||
// conditionals) occurring "before" phi functions, the
|
// conditionals) occurring "before" the block (e.g., as inputs
|
||||||
// phi functions, and at the bottom of a block.
|
// to the block and its phi functions), "within" the block,
|
||||||
ADJUST_BEFORE = -1 // defined before phi
|
// and "after" the block.
|
||||||
ADJUST_TOP = 0 // defined by phi
|
AdjustBefore = -1 // defined before phi
|
||||||
ADJUST_BOTTOM = 1 // defined within block
|
AdjustWithin = 0 // defined by phi
|
||||||
|
AdjustAfter = 1 // defined within block
|
||||||
)
|
)
|
||||||
|
|
||||||
// A sparseTree is a tree of Blocks.
|
// A SparseTree is a tree of Blocks.
|
||||||
// It allows rapid ancestor queries,
|
// It allows rapid ancestor queries,
|
||||||
// such as whether one block dominates another.
|
// such as whether one block dominates another.
|
||||||
type sparseTree []sparseTreeNode
|
type SparseTree []SparseTreeNode
|
||||||
|
|
||||||
// newSparseTree creates a sparseTree from a block-to-parent map (array indexed by Block.ID)
|
// newSparseTree creates a SparseTree from a block-to-parent map (array indexed by Block.ID)
|
||||||
func newSparseTree(f *Func, parentOf []*Block) sparseTree {
|
func newSparseTree(f *Func, parentOf []*Block) SparseTree {
|
||||||
t := make(sparseTree, f.NumBlocks())
|
t := make(SparseTree, f.NumBlocks())
|
||||||
for _, b := range f.Blocks {
|
for _, b := range f.Blocks {
|
||||||
n := &t[b.ID]
|
n := &t[b.ID]
|
||||||
if p := parentOf[b.ID]; p != nil {
|
if p := parentOf[b.ID]; p != nil {
|
||||||
|
|
@ -80,7 +95,7 @@ func newSparseTree(f *Func, parentOf []*Block) sparseTree {
|
||||||
// root left left right right root
|
// root left left right right root
|
||||||
// 1 2e 3 | 4 5e 6 | 7 8x 9 | 10 11e 12 | 13 14x 15 | 16 17x 18
|
// 1 2e 3 | 4 5e 6 | 7 8x 9 | 10 11e 12 | 13 14x 15 | 16 17x 18
|
||||||
|
|
||||||
func (t sparseTree) numberBlock(b *Block, n int32) int32 {
|
func (t SparseTree) numberBlock(b *Block, n int32) int32 {
|
||||||
// reserve n for entry-1, assign n+1 to entry
|
// reserve n for entry-1, assign n+1 to entry
|
||||||
n++
|
n++
|
||||||
t[b.ID].entry = n
|
t[b.ID].entry = n
|
||||||
|
|
@ -103,19 +118,19 @@ func (t sparseTree) numberBlock(b *Block, n int32) int32 {
|
||||||
// to assign entry and exit numbers in the treewalk, those
|
// to assign entry and exit numbers in the treewalk, those
|
||||||
// numbers are also consistent with this order (i.e.,
|
// numbers are also consistent with this order (i.e.,
|
||||||
// Sibling(x) has entry number larger than x's exit number).
|
// Sibling(x) has entry number larger than x's exit number).
|
||||||
func (t sparseTree) Sibling(x *Block) *Block {
|
func (t SparseTree) Sibling(x *Block) *Block {
|
||||||
return t[x.ID].sibling
|
return t[x.ID].sibling
|
||||||
}
|
}
|
||||||
|
|
||||||
// Child returns a child of x in the dominator tree, or
|
// Child returns a child of x in the dominator tree, or
|
||||||
// nil if there are none. The choice of first child is
|
// nil if there are none. The choice of first child is
|
||||||
// arbitrary but repeatable.
|
// arbitrary but repeatable.
|
||||||
func (t sparseTree) Child(x *Block) *Block {
|
func (t SparseTree) Child(x *Block) *Block {
|
||||||
return t[x.ID].child
|
return t[x.ID].child
|
||||||
}
|
}
|
||||||
|
|
||||||
// isAncestorEq reports whether x is an ancestor of or equal to y.
|
// isAncestorEq reports whether x is an ancestor of or equal to y.
|
||||||
func (t sparseTree) isAncestorEq(x, y *Block) bool {
|
func (t SparseTree) isAncestorEq(x, y *Block) bool {
|
||||||
if x == y {
|
if x == y {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -125,7 +140,7 @@ func (t sparseTree) isAncestorEq(x, y *Block) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// isAncestor reports whether x is a strict ancestor of y.
|
// isAncestor reports whether x is a strict ancestor of y.
|
||||||
func (t sparseTree) isAncestor(x, y *Block) bool {
|
func (t SparseTree) isAncestor(x, y *Block) bool {
|
||||||
if x == y {
|
if x == y {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -134,8 +149,38 @@ func (t sparseTree) isAncestor(x, y *Block) bool {
|
||||||
return xx.entry < yy.entry && yy.exit < xx.exit
|
return xx.entry < yy.entry && yy.exit < xx.exit
|
||||||
}
|
}
|
||||||
|
|
||||||
// maxdomorder returns a value to allow a maximal dominator first sort. maxdomorder(x) < maxdomorder(y) is true
|
// domorder returns a value for dominator-oriented sorting.
|
||||||
// if x may dominate y, and false if x cannot dominate y.
|
// Block domination does not provide a total ordering,
|
||||||
func (t sparseTree) maxdomorder(x *Block) int32 {
|
// but domorder two has useful properties.
|
||||||
|
// (1) If domorder(x) > domorder(y) then x does not dominate y.
|
||||||
|
// (2) If domorder(x) < domorder(y) and domorder(y) < domorder(z) and x does not dominate y,
|
||||||
|
// then x does not dominate z.
|
||||||
|
// Property (1) means that blocks sorted by domorder always have a maximal dominant block first.
|
||||||
|
// Property (2) allows searches for dominated blocks to exit early.
|
||||||
|
func (t SparseTree) domorder(x *Block) int32 {
|
||||||
|
// Here is an argument that entry(x) provides the properties documented above.
|
||||||
|
//
|
||||||
|
// Entry and exit values are assigned in a depth-first dominator tree walk.
|
||||||
|
// For all blocks x and y, one of the following holds:
|
||||||
|
//
|
||||||
|
// (x-dom-y) x dominates y => entry(x) < entry(y) < exit(y) < exit(x)
|
||||||
|
// (y-dom-x) y dominates x => entry(y) < entry(x) < exit(x) < exit(y)
|
||||||
|
// (x-then-y) neither x nor y dominates the other and x walked before y => entry(x) < exit(x) < entry(y) < exit(y)
|
||||||
|
// (y-then-x) neither x nor y dominates the other and y walked before y => entry(y) < exit(y) < entry(x) < exit(x)
|
||||||
|
//
|
||||||
|
// entry(x) > entry(y) eliminates case x-dom-y. This provides property (1) above.
|
||||||
|
//
|
||||||
|
// For property (2), assume entry(x) < entry(y) and entry(y) < entry(z) and x does not dominate y.
|
||||||
|
// entry(x) < entry(y) allows cases x-dom-y and x-then-y.
|
||||||
|
// But by supposition, x does not dominate y. So we have x-then-y.
|
||||||
|
//
|
||||||
|
// For contractidion, assume x dominates z.
|
||||||
|
// Then entry(x) < entry(z) < exit(z) < exit(x).
|
||||||
|
// But we know x-then-y, so entry(x) < exit(x) < entry(y) < exit(y).
|
||||||
|
// Combining those, entry(x) < entry(z) < exit(z) < exit(x) < entry(y) < exit(y).
|
||||||
|
// By supposition, entry(y) < entry(z), which allows cases y-dom-z and y-then-z.
|
||||||
|
// y-dom-z requires entry(y) < entry(z), but we have entry(z) < entry(y).
|
||||||
|
// y-then-z requires exit(y) < entry(z), but we have entry(z) < exit(y).
|
||||||
|
// We have a contradiction, so x does not dominate z, as required.
|
||||||
return t[x.ID].entry
|
return t[x.ID].entry
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue