misc/cgo/testso/main
src/cmd/cgo/zdefaultcc.go
src/cmd/go/zdefaultcc.go
+src/cmd/go/zosarch.go
src/cmd/internal/obj/zbootstrap.go
src/go/build/zcgo.go
src/go/doc/headscan
Aamir Khan <syst3m.w0rm@gmail.com>
Aaron France <aaron.l.france@gmail.com>
Aaron Torres <tcboox@gmail.com>
+Abe Haskins <abeisgreat@abeisgreat.com>
Abhinav Gupta <abhinav.g90@gmail.com>
Adrian Nos <nos.adrian@gmail.com>
Adrian O'Grady <elpollouk@gmail.com>
Adrien Bustany <adrien-xx-google@bustany.org>
Aécio Júnior <aeciodantasjunior@gmail.com>
Ahmed Waheed Moanes <oneofone@gmail.com>
+Ahmy Yulrizka <yulrizka@gmail.com>
+Aiden Scandella <ai@uber.com>
Ainar Garipov <gugl.zadolbal@gmail.com>
+Akihiro Suda <suda.kyoto@gmail.com>
Akshat Kumar <seed@mail.nanosouffle.net>
Alan Shreve <alan@inconshreveable.com>
Albert Strasheim <fullung@gmail.com>
Alberto Donizetti <alb.donizetti@gmail.com>
Alberto García Hierro <alberto@garciahierro.com> <alberto.garcia.hierro@gmail.com>
Aleksandar Dezelin <dezelin@gmail.com>
+Alessandro Arzilli <alessandro.arzilli@gmail.com>
Alex A Skinner <alex@lx.lc>
Alex Brainman <alex.brainman@gmail.com>
Alex Jin <toalexjin@gmail.com>
Alexey Palazhchenko <alexey.palazhchenko@gmail.com>
Aliaksandr Valialkin <valyala@gmail.com>
Alif Rachmawadi <subosito@gmail.com>
+Amazon.com, Inc
Amir Mohammad Saied <amir@gluegadget.com>
Amrut Joshi <amrut.joshi@gmail.com>
+Andre Nathan <andrenth@gmail.com>
Andrei Korzhevskii <a.korzhevskiy@gmail.com>
Andrei Vieru <euvieru@gmail.com>
Andrew Balholm <andybalholm@gmail.com>
Apisak Darakananda <pongad@gmail.com>
Aram Hăvărneanu <aram@mgk.ro>
Areski Belaid <areski@gmail.com>
+Arlo Breault <arlolra@gmail.com>
+ARM Ltd.
Arnaud Ysmal <arnaud.ysmal@gmail.com>
Arne Hormann <arnehormann@gmail.com>
Arnout Engelen <arnout@bzzt.net>
Artyom Pervukhin <artyom.pervukhin@gmail.com>
Arvindh Rajesh Tamilmani <art@a-30.net>
Ato Araki <ato.araki@gmail.com>
+Audrey Lim <audreylh@gmail.com>
+Augusto Roman <aroman@gmail.com>
Aulus Egnatius Varialus <varialus@gmail.com>
awaw fumin <awawfumin@gmail.com>
Aymerick Jéhanne <aymerick@jehanne.org>
Blake Gentry <blakesgentry@gmail.com>
Blake Mizerany <blake.mizerany@gmail.com>
Bobby Powers <bobbypowers@gmail.com>
+Brady Catherman <brady@gmail.com>
+Brady Sullivan <brady@bsull.com>
Brendan Daniel Tracey <tracey.brendan@gmail.com>
Brett Cannon <bcannon@gmail.com>
Brian Dellisanti <briandellisanti@gmail.com>
Christoph Hack <christoph@tux21b.org>
Christopher Cahoon <chris.cahoon@gmail.com>
Christopher Guiney <chris@guiney.net>
+Christopher Nelson <nadiasvertex@gmail.com>
Christopher Nielsen <m4dh4tt3r@gmail.com>
Christopher Redden <christopher.redden@gmail.com>
Christopher Wedgwood <cw@f00f.org>
CL Sung <clsung@gmail.com> <cl_sung@htc.com>
Clement Skau <clementskau@gmail.com>
CloudFlare Inc.
+Colin Edwards <colin@recursivepenguin.com>
Colin Kennedy <moshen.colin@gmail.com>
+Conrad Irwin <conrad.irwin@gmail.com>
Conrad Meyer <cemeyer@cs.washington.edu>
CoreOS, Inc.
Corey Thomasson <cthom.lists@gmail.com>
Cristian Staretu <unclejacksons@gmail.com>
+Currant
Damian Gryski <dgryski@gmail.com>
Dan Caddigan <goldcaddy77@gmail.com>
Dan Callahan <dan.callahan@gmail.com>
Daniel Morsing <daniel.morsing@gmail.com>
Daniel Ortiz Pereira da Silva <daniel.particular@gmail.com>
Daniel Skinner <daniel@dasa.cc>
+Daniel Speichert <daniel@speichert.pl>
Daniel Theophanes <kardianos@gmail.com>
Darren Elwood <darren@textnode.com>
+Datong Sun <dndx@idndx.com>
Dave Cheney <dave@cheney.net>
+David Brophy <dave@brophy.uk>
David Bürgin <676c7473@gmail.com>
David Calavera <david.calavera@gmail.com>
David du Colombier <0intro@gmail.com>
David Jakob Fritz <david.jakob.fritz@gmail.com>
David Leon Gil <coruus@gmail.com>
David R. Jenni <david.r.jenni@gmail.com>
+David Sansome <me@davidsansome.com>
David Thomas <davidthomas426@gmail.com>
David Titarenco <david.titarenco@gmail.com>
Davies Liu <davies.liu@gmail.com>
Dean Prichard <dean.prichard@gmail.com>
Denis Bernard <db047h@gmail.com>
Denis Brandolini <denis.brandolini@gmail.com>
+Denys Honsiorovskyi <honsiorovskyi@gmail.com>
Derek Buitenhuis <derek.buitenhuis@gmail.com>
Derek Parker <parkerderek86@gmail.com>
+Derek Shockey <derek.shockey@gmail.com>
Develer SRL
Devon H. O'Dell <devon.odell@gmail.com>
Dhiru Kholia <dhiru.kholia@gmail.com>
Didier Spezia <didier.06@gmail.com>
Dimitri Tcaciuc <dtcaciuc@gmail.com>
Dirk Gadsden <dirk@esherido.com>
+Diwaker Gupta <diwakergupta@gmail.com>
Dmitri Shuralyov <shurcooL@gmail.com>
+Dmitriy Dudkin <dudkin.dmitriy@gmail.com>
Dmitriy Shelenin <deemok@googlemail.com> <deemok@gmail.com>
Dmitry Chestnykh <dchest@gmail.com>
Dmitry Savintsev <dsavints@gmail.com>
Donovan Hide <donovanhide@gmail.com>
Dropbox, Inc.
Duncan Holm <mail@frou.org>
+Dustin Herbison <djherbis@gmail.com>
Dustin Sallings <dsallings@gmail.com>
Dustin Shields-Cloues <dcloues@gmail.com>
Dvir Volk <dvir@everything.me> <dvirsky@gmail.com>
Erik Dubbelboer <erik@dubbelboer.com>
Erik St. Martin <alakriti@gmail.com>
Erik Westrup <erik.westrup@gmail.com>
+Ernest Chiang <ernest_chiang@htc.com>
Esko Luontola <esko.luontola@gmail.com>
Evan Phoenix <evan@phx.io>
Evan Shaw <chickencha@gmail.com>
Frederick Kelly Mayle III <frederickmayle@gmail.com>
Fredrik Enestad <fredrik.enestad@soundtrackyourbrand.com>
Frithjof Schulze <schulze@math.uni-hannover.de> <sfrithjof@gmail.com>
+Frits van Bommel <fvbommel@gmail.com>
Gabriel Aszalos <gabriel.aszalos@gmail.com>
Gary Burd <gary@beagledreams.com>
Gaurish Sharma <contact@gaurishsharma.com>
Hari haran <hariharan.uno@gmail.com>
Hariharan Srinath <srinathh@gmail.com>
Harley Laue <losinggeneration@gmail.com>
+Harshavardhana <hrshvardhana@gmail.com>
Håvard Haugen <havard.haugen@gmail.com>
Hector Chu <hectorchu@gmail.com>
Hector Martin Cantero <hector@marcansoft.com>
Henning Schmiedehausen <henning@schmiedehausen.org>
Henrik Edwards <henrik.edwards@gmail.com>
Herbert Georg Fischer <herbert.fischer@gmail.com>
+Hironao OTSUBO <motemen@gmail.com>
Hiroshi Ioka <hirochachacha@gmail.com>
+Hitoshi Mitake <mitake.hitoshi@gmail.com>
+Holden Huang <ttyh061@gmail.com>
Hong Ruiqi <hongruiqi@gmail.com>
Hsin-Ho Yeh <yhh92u@gmail.com>
Hu Keping <hukeping@huawei.com>
Ian Gudger <ian@loosescre.ws>
IBM
Icarus Sparry <golang@icarus.freeuk.com>
+Idora Shinatose <idora.shinatose@gmail.com>
Igneous Systems, Inc.
Igor Dolzhikov <bluesriverz@gmail.com>
INADA Naoki <songofacandy@gmail.com>
Ingo Krabbe <ikrabbe.ask@gmail.com>
Ingo Oeser <nightlyone@googlemail.com>
Intel Corporation
+Irieda Noboru <irieda@gmail.com>
Isaac Wagner <ibw@isaacwagner.me>
Ivan Ukhov <ivan.ukhov@gmail.com>
Jae Kwon <jae@tendermint.com>
Jakob Borg <jakob@nym.se>
Jakub Ryszard Czarnowicz <j.czarnowicz@gmail.com>
+James Bardin <j.bardin@gmail.com>
James David Chalfant <james.chalfant@gmail.com>
James Fysh <james.fysh@gmail.com>
James Gray <james@james4k.com>
James Sweet <james.sweet88@googlemail.com>
James Toy <nil@opensesame.st>
James Whitehead <jnwhiteh@gmail.com>
+Jamil Djadala <djadala@gmail.com>
Jan H. Hosang <jan.hosang@gmail.com>
Jan Mercl <0xjnml@gmail.com>
Jan Mercl <befelemepeseveze@gmail.com>
Jeff Wendling <jeff@spacemonkey.com>
Jens Frederich <jfrederich@gmail.com>
Jeremy Jackins <jeremyjackins@gmail.com>
+Jess Frazelle <me@jessfraz.com>
Jihyun Yu <yjh0502@gmail.com>
Jim McGrath <jimmc2@gmail.com>
Jimmy Zelinskie <jimmyzelinskie@gmail.com>
Jiong Du <londevil@gmail.com>
Joakim Sernbrant <serbaut@gmail.com>
Joe Harrison <joehazzers@gmail.com>
+Joe Henke <joed.henke@gmail.com>
Joe Poirier <jdpoirier@gmail.com>
Joe Shaw <joe@joeshaw.org>
+Joe Sylve <joe.sylve@gmail.com>
Joe Tsai <joetsai@digital-static.net>
Joel Stemmer <stemmertech@gmail.com>
+Johan Sageryd <j@1616.se>
John Asmuth <jasmuth@gmail.com>
John C Barstow <jbowtie@amathaine.com>
John Graham-Cumming <jgc@jgc.org> <jgrahamc@gmail.com>
John Howard Palevich <jack.palevich@gmail.com>
+John Jeffery <jjeffery@sp.com.au>
John Jenkins <twodopeshaggy@gmail.com>
John Potocny <johnp@vividcortex.com>
+John Schnake <schnake.john@gmail.com>
John Shahid <jvshahid@gmail.com>
John Tuley <john@tuley.org>
Jonathan Boulle <jonathanboulle@gmail.com>
Ken Friedenbach <kenliz@cruzio.com>
Ken Rockot <ken@oz.gs>
Ken Sedgwick <ken@bonsai.com>
+Kenji Kaneda <kenji.kaneda@gmail.com>
+Kenneth Shaw <kenshaw@gmail.com>
Kenny Grant <kennygrant@gmail.com>
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>
Konstantin Shaposhnikov <k.shaposhnikov@gmail.com>
KPCompass, Inc.
L Campbell <unpantsu@gmail.com>
Lai Jiangshan <eag0628@gmail.com>
Larz Conwell <larzconwell@gmail.com>
+Lee Hinman <hinman@gmail.com>
Lee Packham <lpackham@gmail.com>
Lewin Bormann <lewin.bormann@gmail.com>
Liberty Fund Inc
Linaro Limited
Lloyd Dewolf <foolswisdom@gmail.com>
Lorenzo Stoakes <lstoakes@gmail.com>
+Luan Santos <cfcluan@gmail.com>
Luca Greco <luca.greco@alcacoop.it>
Lucien Stuker <lucien.stuker@gmail.com>
Lucio De Re <lucio.dere@gmail.com>
Marc Weistroff <marc@weistroff.net>
Marco Hennings <marco.hennings@freiheit.com>
Mark Bucciarelli <mkbucc@gmail.com>
+Mark Severson <miquella@gmail.com>
Mark Theunissen <mark.theunissen@gmail.com>
Marko Juhani Silokunnas <marko.silokunnas@gmail.com>
Marko Tiikkaja <marko@joh.to>
Markus Duft <markus.duft@salomon.at>
Markus Sonderegger <marraison@gmail.com>
Markus Zimmermann <zimmski@gmail.com>
+Martin Garton <garton@gmail.com>
Martin Möhrmann <martisch@uos.de>
Martin Neubauer <m.ne@gmx.net>
Martin Olsson <martin@minimum.se>
Marvin Stenger <marvin.stenger94@gmail.com>
Mateusz Czapliński <czapkofan@gmail.com>
Mathias Beke <git@denbeke.be>
+Mathias Leppich <mleppich@muhqu.de>
Mathieu Lonjaret <mathieu.lonjaret@gmail.com>
Mats Lidell <mats.lidell@cag.se>
Matt Aimonetti <mattaimonetti@gmail.com>
Matt Joiner <anacrolix@gmail.com>
Matt Layher <mdlayher@gmail.com>
Matt Reiferson <mreiferson@gmail.com>
+Matt Robenolt <matt@ydekproductions.com>
Matt T. Proud <matt.proud@gmail.com>
Matt Williams <gh@mattyw.net>
Matthew Brennan <matty.brennan@gmail.com>
Matthew Holt <Matthew.Holt+git@gmail.com>
Matthew Horsnell <matthew.horsnell@gmail.com>
Maxim Khitrov <max@mxcrypt.com>
+Maxwell Krohn <themax@gmail.com>
Meir Fischer <meirfischer@gmail.com>
Meng Zhuo <mengzhuo1203@gmail.com>
Meteor Development Group
Michael Käufl <golang@c.michael-kaeufl.de>
Michael Lewis <mikelikespie@gmail.com>
Michael MacInnis <Michael.P.MacInnis@gmail.com>
+Michael McConville <momcconville@gmail.com>
Michael Pearson <mipearson@gmail.com>
Michael Schaller <michael@5challer.de>
Michael Stapelberg <michael@stapelberg.de>
Mikael Tillenius <mikti42@gmail.com>
Mike Andrews <mra@xoba.com>
Mike Rosset <mike.rosset@gmail.com>
+Mikhail Gusarov <dottedmag@dottedmag.net>
Mikhail Panchenko <m@mihasya.com>
Miki Tebeka <miki.tebeka@gmail.com>
Mikio Hara <mikioh.mikioh@gmail.com>
Mikkel Krautz <mikkel@krautz.dk>
Miquel Sabaté Solà <mikisabate@gmail.com>
Mohit Agarwal <mohit@sdf.org>
+Monty Taylor <mordred@inaugust.com>
Moov Corporation
Moriyoshi Koizumi <mozo@mozo.jp>
+Morten Siebuhr <sbhr@sbhr.dk>
Môshe van der Sterre <moshevds@gmail.com>
+Muhammed Uluyol <uluyol0@gmail.com>
Nan Deng <monnand@gmail.com>
Nathan John Youngman <nj@nathany.com>
Nathan Otterness <otternes@cs.unc.edu>
Nathan VanBenschoten <nvanbenschoten@gmail.com>
Nathan Youngman <git@nathany.com>
Neelesh Chandola <neelesh.c98@gmail.com>
+Netflix, Inc.
Nevins Bartolomeo <nevins.bartolomeo@gmail.com>
ngmoco, LLC
+Niall Sheridan <nsheridan@gmail.com>
Nicholas Katsaros <nick@nickkatsaros.com>
Nicholas Presta <nick@nickpresta.ca> <nick1presta@gmail.com>
Nicholas Sullivan <nicholas.sullivan@gmail.com>
Nicholas Waples <nwaples@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 Owens <mischief@offblast.org>
Nicolas S. Dade <nic.dade@gmail.com>
+Niels Widger <niels.widger@gmail.com>
Nigel Kerr <nigel.kerr@gmail.com>
+Niko Dziemba <niko@dziemba.com>
Nikolay Turpitko <nikolay@turpitko.com>
Noah Campbell <noahcampbell@gmail.com>
Norberto Lopes <nlopes.ml@gmail.com>
Oliver Hookins <ohookins@gmail.com>
Olivier Antoine <olivier.antoine@gmail.com>
Olivier Duperray <duperray.olivier@gmail.com>
+Olivier Poitrey <rs@dailymotion.com>
Olivier Saingre <osaingre@gmail.com>
Oracle
+Orange
+Özgür Kesim <oec-go@kesim.org>
Padraig Kitterick <padraigkitterick@gmail.com>
Palm Stone Games
Paolo Giarrusso <p.giarrusso@gmail.com>
Peter Waldschmidt <peter@waldschmidt.com>
Peter Waller <peter.waller@gmail.com>
Peter Williams <pwil3058@gmail.com>
+Philip Hofer <phofer@umich.edu>
Philip K. Warren <pkwarren@gmail.com>
+Pierre Durand <pierredurand@gmail.com>
Pierre Roullon <pierre.roullon@gmail.com>
Pieter Droogendijk <pieter@binky.org.uk>
Pietro Gagliardi <pietro10@mac.com>
+Prashant Varanasi <prashant@prashantv.com>
Preetam Jinka <pj@preet.am>
Quan Yong Zhai <qyzhai@gmail.com>
Quentin Perez <qperez@ocs.online.net>
Red Hat, Inc.
Reinaldo de Souza Jr <juniorz@gmail.com>
Rémy Oudompheng <oudomphe@phare.normalesup.org>
+Ricardo Padilha <ricardospadilha@gmail.com>
Richard Barnes <rlb@ipv.sx>
Richard Crowley <r@rcrowley.org>
Richard Eric Gavaletz <gavaletz@gmail.com>
+Richard Miller <miller.research@gmail.com>
Richard Musiol <mail@richard-musiol.de>
Rick Arnold <rickarnoldjr@gmail.com>
Risto Jaakko Saarelma <rsaarelm@gmail.com>
Rodrigo Rafael Monti Kochenburger <divoxx@gmail.com>
Roger Pau Monné <royger@gmail.com>
Roger Peppe <rogpeppe@gmail.com>
+Roland Shoemaker <rolandshoemaker@gmail.com>
Ron Hashimoto <mail@h2so5.net>
Ron Minnich <rminnich@gmail.com>
Ross Light <rlight2@gmail.com>
Ryan Slade <ryanslade@gmail.com>
S.Çağlar Onur <caglar@10ur.org>
Salmān Aljammāz <s@0x65.net>
+Sam Hug <samuel.b.hug@gmail.com>
+Sam Whited <sam@samwhited.com>
Sanjay Menakuru <balasanjay@gmail.com>
Scott Barron <scott.barron@github.com>
+Scott Bell <scott@sctsm.com>
Scott Ferguson <scottwferg@gmail.com>
Scott Lawrence <bytbox@gmail.com>
Sebastien Binet <seb.binet@gmail.com>
Sergey 'SnakE' Gromov <snake.scaly@gmail.com>
Sergio Luis O. B. Correia <sergio@correia.cc>
Seth Hoenig <seth.a.hoenig@gmail.com>
+Shahar Kohanim <skohanim@gmail.com>
Shane Hansen <shanemhansen@gmail.com>
Shaozhen Ding <dsz0111@gmail.com>
Shawn Smith <shawn.p.smith@gmail.com>
Shenghou Ma <minux.ma@gmail.com>
+Shinji Tanaka <shinji.tanaka@gmail.com>
Shivakumar GN <shivakumar.gn@gmail.com>
Silvan Jegen <s.jegen@gmail.com>
+Simon Jefford <simon.jefford@gmail.com>
Simon Whitehead <chemnova@gmail.com>
Sokolov Yura <funny.falcon@gmail.com>
Spencer Nelson <s@spenczar.com>
Spring Mc <heresy.mc@gmail.com>
Square, Inc.
+Sridhar Venkatakrishnan <sridhar@laddoo.net>
StalkR <stalkr@stalkr.net>
Stan Schwertly <stan@schwertly.com>
Stefan Nilsson <snilsson@nada.kth.se> <trolleriprofessorn@gmail.com>
Tad Glines <tad.glines@gmail.com>
Taj Khattra <taj.khattra@gmail.com>
Takeshi YAMANASHI <9.nashi@gmail.com>
+Tal Shprecher <tshprecher@gmail.com>
Tamir Duberstein <tamird@gmail.com>
Tarmigan Casebolt <tarmigan@gmail.com>
Taru Karttunen <taruti@taruti.net>
Thomas Desrosiers <thomasdesr@gmail.com>
Thomas Kappler <tkappler@gmail.com>
Thorben Krueger <thorben.krueger@gmail.com>
+Tilman Dilo <tilman.dilo@gmail.com>
Tim Cooijmans <timcooijmans@gmail.com>
+Tim Ebringer <tim.ebringer@gmail.com>
Timo Savola <timo.savola@gmail.com>
Timo Truyts <alkaloid.btx@gmail.com>
+Timothy Studd <tim@timstudd.com>
Tobias Columbus <tobias.columbus@gmail.com>
Todd Neal <todd@tneal.org>
Tom Heng <zhm20070928@gmail.com>
Ugorji Nwoke <ugorji@gmail.com>
Ulf Holm Nielsen <doktor@dyregod.dk>
Ulrich Kunitz <uli.kunitz@gmail.com>
+Upthere, Inc.
Uriel Mangado <uriel@berlinblue.org>
+Vadim Grek <vadimprog@gmail.com>
Vadim Vygonets <unixdj@gmail.com>
Vincent Ambo <tazjin@googlemail.com>
Vincent Batts <vbatts@hashbangbash.com> <vbatts@gmail.com>
Vincent Vanackere <vincent.vanackere@gmail.com>
Vinu Rajashekhar <vinutheraj@gmail.com>
+Vishvananda Ishaya <vishvananda@gmail.com>
Vladimir Nikishenko <vova616@gmail.com>
Volker Dobler <dr.volker.dobler@gmail.com>
Wei Guangjing <vcc.163@gmail.com>
William Orr <will@worrbase.com> <ay1244@gmail.com>
Xia Bin <snyh@snyh.org>
Xing Xing <mikespook@gmail.com>
+Xudong Zhang <felixmelon@gmail.com>
Yahoo Inc.
Yann Kerhervé <yann.kerherve@gmail.com>
Yao Zhang <lunaria21@gmail.com>
Yusuke Kagiwada <block.rxckin.beats@gmail.com>
Yuusei Kuwana <kuwana@kumama.org>
Yuval Pavel Zholkover <paulzhol@gmail.com>
+Zemanta d.o.o.
Ziad Hatahet <hatahet@gmail.com>
Zorion Arrizabalaga <zorionk@gmail.com>
申习之 <bronze1man@gmail.com>
Aaron Jacobs <jacobsa@google.com>
Aaron Kemp <kemp.aaron@gmail.com>
Aaron Torres <tcboox@gmail.com>
+Abe Haskins <abeisgreat@abeisgreat.com>
Abhinav Gupta <abhinav.g90@gmail.com>
Adam Langley <agl@golang.org>
Adrian Nos <nos.adrian@gmail.com>
Adrien Bustany <adrien-xx-google@bustany.org>
Aécio Júnior <aeciodantasjunior@gmail.com>
Ahmed Waheed Moanes <oneofone@gmail.com>
+Ahmy Yulrizka <yulrizka@gmail.com>
+Aiden Scandella <ai@uber.com>
Ainar Garipov <gugl.zadolbal@gmail.com>
+Akihiro Suda <suda.kyoto@gmail.com>
Akshat Kumar <seed@mail.nanosouffle.net>
Alan Donovan <adonovan@google.com>
Alan Shreve <alan@inconshreveable.com>
Alberto Donizetti <alb.donizetti@gmail.com>
Alberto García Hierro <alberto@garciahierro.com> <alberto.garcia.hierro@gmail.com>
Aleksandar Dezelin <dezelin@gmail.com>
+Alessandro Arzilli <alessandro.arzilli@gmail.com>
Alex A Skinner <alex@lx.lc>
Alex Brainman <alex.brainman@gmail.com>
Alex Bramley <abramley@google.com>
Alex Plugaru <alex@plugaru.org> <alexandru.plugaru@gmail.com>
Alex Schroeder <alex@gnu.org>
Alex Sergeyev <abc@alexsergeyev.com>
+Alex Vaghin <crhyme@google.com>
Alexander Demakin <alexander.demakin@gmail.com>
Alexander Larsson <alexander.larsson@gmail.com>
Alexander Morozov <lk4d4math@gmail.com>
Alif Rachmawadi <subosito@gmail.com>
Amir Mohammad Saied <amir@gluegadget.com>
Amrut Joshi <amrut.joshi@gmail.com>
+Andre Nathan <andrenth@gmail.com>
Andrea Spadaccini <spadaccio@google.com>
Andreas Jellinghaus <andreas@ionisiert.de> <anj@google.com>
Andrei Korzhevskii <a.korzhevskiy@gmail.com>
Andrew Radev <andrey.radev@gmail.com>
Andrew Skiba <skibaa@gmail.com>
Andrew Szeto <andrew@jabagawee.com>
+Andrew Werner <andrew@upthere.com> <awerner32@gmail.com>
Andrew Wilkins <axwalk@gmail.com>
Andrew Williams <williams.andrew@gmail.com>
Andrey Mirtchovski <mirtchovski@gmail.com>
Aram Hăvărneanu <aram@mgk.ro>
Areski Belaid <areski@gmail.com>
Arkadi Pyuro <arkadi@google.com>
+Arlo Breault <arlolra@gmail.com>
Arnaud Ysmal <arnaud.ysmal@gmail.com>
Arne Hormann <arnehormann@gmail.com>
Arnout Engelen <arnout@bzzt.net>
Arvindh Rajesh Tamilmani <art@a-30.net>
Asim Shankar <asimshankar@gmail.com>
Ato Araki <ato.araki@gmail.com>
+Audrey Lim <audreylh@gmail.com>
+Augusto Roman <aroman@gmail.com>
Aulus Egnatius Varialus <varialus@gmail.com>
Austin Clements <austin@google.com> <aclements@csail.mit.edu>
awaw fumin <awawfumin@gmail.com>
Ben Olive <sionide21@gmail.com>
Benjamin Black <b@b3k.us>
Benjamin Prosnitz <bprosnitz@google.com>
+Benjamin Wester <bwester@squareup.com>
Benny Siegert <bsiegert@gmail.com>
Benoit Sigoure <tsunanet@gmail.com>
Berengar Lehr <Berengar.Lehr@gmx.de>
Bobby Powers <bobbypowers@gmail.com>
Brad Fitzpatrick <bradfitz@golang.org> <bradfitz@gmail.com>
Brad Garcia <bgarcia@golang.org>
+Brady Catherman <brady@gmail.com>
+Brady Sullivan <brady@bsull.com>
Brandon Gilmore <varz@google.com>
Brendan Daniel Tracey <tracey.brendan@gmail.com>
Brendan O'Dea <bod@golang.org>
Brian Slesinsky <skybrian@google.com>
Brian Smith <ohohvi@gmail.com>
Bryan C. Mills <bcmills@google.com>
+Bryan Chan <bryan.chan@ca.ibm.com>
Bryan Ford <brynosaurus@gmail.com>
Caine Tighe <arctanofyourface@gmail.com>
+Caio Marcelo de Oliveira Filho <caio.oliveira@intel.com>
Caleb Spare <cespare@gmail.com>
Carl Chatfield <carlchatfield@gmail.com>
Carl Jackson <carl@stripe.com>
Cary Hull <chull@google.com>
Case Nelson <case.nelson@gmail.com>
Casey Marshall <casey.marshall@gmail.com>
+Catalin Nicutar <cnicutar@google.com>
Catalin Patulea <catalinp@google.com>
Cedric Staub <cs@squareup.com>
Cezar Sá Espinola <cezarsa@gmail.com>
Charles L. Dorian <cldorian@gmail.com>
Charles Lee <zombie.fml@gmail.com>
Charles Weill <weill@google.com>
+Cherry Zhang <cherryyz@google.com>
Chris Broadfoot <cbro@golang.org>
Chris Dollin <ehog.hedge@gmail.com>
Chris Farmiloe <chrisfarms@gmail.com>
Chris Lennert <calennert@gmail.com>
Chris Manghane <cmang@golang.org>
Chris McGee <sirnewton_01@yahoo.ca> <newton688@gmail.com>
+Chris Zou <chriszou@ca.ibm.com>
Christian Himpel <chressie@googlemail.com> <chressie@gmail.com>
Christine Hansmann <chhansmann@gmail.com>
Christoffer Buchholz <christoffer.buchholz@gmail.com>
Christoph Hack <christoph@tux21b.org>
Christopher Cahoon <chris.cahoon@gmail.com>
Christopher Guiney <chris@guiney.net>
+Christopher Nelson <nadiasvertex@gmail.com>
Christopher Nielsen <m4dh4tt3r@gmail.com>
Christopher Redden <christopher.redden@gmail.com>
Christopher Swenson <cswenson@google.com>
Christopher Wedgwood <cw@f00f.org>
+Christy Perez <christy@linux.vnet.ibm.com>
CL Sung <clsung@gmail.com> <cl_sung@htc.com>
Clement Skau <clementskau@gmail.com>
Colby Ranger <cranger@google.com>
Colin Cross <ccross@android.com>
+Colin Edwards <colin@recursivepenguin.com>
Colin Kennedy <moshen.colin@gmail.com>
+Conrad Irwin <conrad.irwin@gmail.com>
Conrad Meyer <cemeyer@cs.washington.edu>
Corey Thomasson <cthom.lists@gmail.com>
Cosmos Nicolaou <cnicolaou@google.com>
Cristian Staretu <unclejacksons@gmail.com>
+Cuihtlauac ALVARADO <cuihtlauac.alvarado@orange.com>
Damian Gryski <dgryski@gmail.com>
Damien Neil <dneil@google.com>
Dan Caddigan <goldcaddy77@gmail.com>
Daniel Nadasi <dnadasi@google.com>
Daniel Ortiz Pereira da Silva <daniel.particular@gmail.com>
Daniel Skinner <daniel@dasa.cc>
+Daniel Speichert <daniel@speichert.pl>
Daniel Theophanes <kardianos@gmail.com>
Darren Elwood <darren@textnode.com>
+Datong Sun <dndx@idndx.com>
Dave Borowitz <dborowitz@google.com>
Dave Bort <dbort@golang.org>
Dave Cheney <dave@cheney.net>
David Anderson <danderson@google.com>
David Barnett <dbarnett@google.com>
David Benjamin <davidben@google.com>
+David Brophy <dave@brophy.uk>
David Bürgin <676c7473@gmail.com>
David Calavera <david.calavera@gmail.com>
David Chase <drchase@google.com>
David McLeish <davemc@google.com>
David Presotto <presotto@gmail.com>
David R. Jenni <david.r.jenni@gmail.com>
+David Sansome <me@davidsansome.com>
David Symonds <dsymonds@golang.org>
David Thomas <davidthomas426@gmail.com>
David Titarenco <david.titarenco@gmail.com>
Dean Prichard <dean.prichard@gmail.com>
Denis Bernard <db047h@gmail.com>
Denis Brandolini <denis.brandolini@gmail.com>
+Denys Honsiorovskyi <honsiorovskyi@gmail.com>
Derek Buitenhuis <derek.buitenhuis@gmail.com>
Derek Che <drc@yahoo-inc.com>
Derek Parker <parkerderek86@gmail.com>
+Derek Shockey <derek.shockey@gmail.com>
Devon H. O'Dell <devon.odell@gmail.com>
Dhiru Kholia <dhiru.kholia@gmail.com>
Didier Spezia <didier.06@gmail.com>
Dimitri Tcaciuc <dtcaciuc@gmail.com>
Dirk Gadsden <dirk@esherido.com>
+Diwaker Gupta <diwakergupta@gmail.com>
Dmitri Shuralyov <shurcooL@gmail.com>
+Dmitriy Dudkin <dudkin.dmitriy@gmail.com>
Dmitriy Shelenin <deemok@googlemail.com> <deemok@gmail.com>
Dmitriy Vyukov <dvyukov@google.com>
Dmitry Chestnykh <dchest@gmail.com>
Dominik Vogt <vogt@linux.vnet.ibm.com>
Donald Huang <don.hcd@gmail.com>
Donovan Hide <donovanhide@gmail.com>
+Doug Anderson <douga@google.com>
Drew Hintz <adhintz@google.com>
Duncan Holm <mail@frou.org>
+Dustin Carlino <dcarlino@google.com>
+Dustin Herbison <djherbis@gmail.com>
Dustin Long <dustmop@gmail.com>
Dustin Sallings <dsallings@gmail.com>
Dustin Shields-Cloues <dcloues@gmail.com>
Erik Dubbelboer <erik@dubbelboer.com>
Erik St. Martin <alakriti@gmail.com>
Erik Westrup <erik.westrup@gmail.com>
+Ernest Chiang <ernest_chiang@htc.com>
Esko Luontola <esko.luontola@gmail.com>
+Ethan Burns <eaburns@google.com>
Evan Broder <evan@stripe.com>
Evan Brown <evanbrown@google.com>
Evan Kroske <evankroske@google.com>
Frederick Kelly Mayle III <frederickmayle@gmail.com>
Fredrik Enestad <fredrik.enestad@soundtrackyourbrand.com>
Frithjof Schulze <schulze@math.uni-hannover.de> <sfrithjof@gmail.com>
+Frits van Bommel <fvbommel@gmail.com>
Fumitoshi Ukai <ukai@google.com>
Gaal Yahas <gaal@google.com>
Gabriel Aszalos <gabriel.aszalos@gmail.com>
Garrick Evans <garrick@google.com>
Gary Burd <gary@beagledreams.com> <gary.burd@gmail.com>
+Gary Elliott <garyelliott@google.com>
Gaurish Sharma <contact@gaurishsharma.com>
Gautham Thambidorai <gautham.dorai@gmail.com>
Geert-Johan Riemer <gjr19912@gmail.com>
Gustavo Niemeyer <gustavo@niemeyer.net> <n13m3y3r@gmail.com>
Gwenael Treguier <gwenn.kahz@gmail.com>
Hajime Hoshi <hajimehoshi@gmail.com>
+Hallgrimur Gunnarsson <halg@google.com>
Han-Wen Nienhuys <hanwen@google.com>
Hari haran <hariharan.uno@gmail.com>
Hariharan Srinath <srinathh@gmail.com>
Harley Laue <losinggeneration@gmail.com>
+Harshavardhana <hrshvardhana@gmail.com>
Håvard Haugen <havard.haugen@gmail.com>
Hector Chu <hectorchu@gmail.com>
Hector Martin Cantero <hector@marcansoft.com>
Henning Schmiedehausen <henning@schmiedehausen.org>
Henrik Edwards <henrik.edwards@gmail.com>
Herbert Georg Fischer <herbert.fischer@gmail.com>
+Hironao OTSUBO <motemen@gmail.com>
Hiroshi Ioka <hirochachacha@gmail.com>
+Hitoshi Mitake <mitake.hitoshi@gmail.com>
+Holden Huang <ttyh061@gmail.com>
Hong Ruiqi <hongruiqi@gmail.com>
Hossein Sheikh Attar <hattar@google.com>
Hsin-Ho Yeh <yhh92u@gmail.com>
Ian Gudger <ian@loosescre.ws>
Ian Lance Taylor <iant@golang.org>
Icarus Sparry <golang@icarus.freeuk.com>
+Idora Shinatose <idora.shinatose@gmail.com>
Igor Dolzhikov <bluesriverz@gmail.com>
Ilya Tocar <ilya.tocar@intel.com>
INADA Naoki <songofacandy@gmail.com>
Ingo Krabbe <ikrabbe.ask@gmail.com>
Ingo Oeser <nightlyone@googlemail.com> <nightlyone@gmail.com>
+Irieda Noboru <irieda@gmail.com>
Isaac Wagner <ibw@isaacwagner.me>
Ivan Krasin <krasin@golang.org>
Ivan Ukhov <ivan.ukhov@gmail.com>
Jakub Čajka <jcajka@redhat.com>
Jakub Ryszard Czarnowicz <j.czarnowicz@gmail.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 Fysh <james.fysh@gmail.com>
James Gray <james@james4k.com>
Jamie Gennis <jgennis@google.com> <jgennis@gmail.com>
Jamie Turner <jamwt@dropbox.com>
Jamie Wilkinson <jaq@spacepants.org>
+Jamil Djadala <djadala@gmail.com>
Jan H. Hosang <jan.hosang@gmail.com>
Jan Kratochvil <jan.kratochvil@redhat.com>
Jan Mercl <0xjnml@gmail.com>
Jay Weisskopf <jay@jayschwa.net>
Jean-Marc Eurin <jmeurin@google.com>
Jed Denlea <jed@fastly.com>
+Jeff Craig <jeffcraig@google.com>
Jeff Hodges <jeff@somethingsimilar.com>
Jeff R. Allen <jra@nella.org> <jeff.allen@gmail.com>
Jeff Sickel <jas@corpus-callosum.com>
Jeremiah Harmsen <jeremiah@google.com>
Jeremy Jackins <jeremyjackins@gmail.com>
Jeremy Schlatter <jeremy.schlatter@gmail.com>
+Jess Frazelle <me@jessfraz.com>
Jihyun Yu <yjh0502@gmail.com>
Jim Cote <jfcote87@gmail.com>
Jim McGrath <jimmc2@gmail.com>
Jiong Du <londevil@gmail.com>
Joakim Sernbrant <serbaut@gmail.com>
Joe Harrison <joehazzers@gmail.com>
+Joe Henke <joed.henke@gmail.com>
Joe Poirier <jdpoirier@gmail.com>
Joe Shaw <joe@joeshaw.org>
+Joe Sylve <joe.sylve@gmail.com>
Joe Tsai <joetsai@digital-static.net>
Joel Sing <jsing@google.com>
Joel Stemmer <stemmertech@gmail.com>
Johan Euphrosine <proppy@google.com>
+Johan Sageryd <j@1616.se>
John Asmuth <jasmuth@gmail.com>
John Beisley <huin@google.com>
John C Barstow <jbowtie@amathaine.com>
John Dethridge <jcd@golang.org>
John Graham-Cumming <jgc@jgc.org> <jgrahamc@gmail.com>
John Howard Palevich <jack.palevich@gmail.com>
+John Jeffery <jjeffery@sp.com.au>
John Jenkins <twodopeshaggy@gmail.com>
John Newlin <jnewlin@google.com>
John Potocny <johnp@vividcortex.com>
+John Schnake <schnake.john@gmail.com>
John Shahid <jvshahid@gmail.com>
John Tuley <john@tuley.org>
Jonathan Allie <jonallie@google.com>
+Jonathan Amsterdam <jba@google.com>
Jonathan Boulle <jonathanboulle@gmail.com>
Jonathan Feinberg <feinberg@google.com>
Jonathan Gold <jgold.bg@gmail.com>
JP Sugarbroad <jpsugar@google.com>
JT Olds <jtolds@xnet5.com>
Jukka-Pekka Kekkonen <karatepekka@gmail.com>
+Julia Hansbrough <flowerhack@google.com>
Julian Phillips <julian@quantumfyre.co.uk>
Julien Schmidt <google@julienschmidt.com>
Jungho Ahn <jhahn@google.com>
+Jure Ham <jure.ham@zemanta.com>
Justin Nuß <nuss.justin@gmail.com>
Kai Backman <kaib@golang.org>
+Kamal Aboul-Hosn <aboulhosn@google.com>
Kamil Kisiel <kamil@kamilkisiel.net> <kamil.kisiel@gmail.com>
Kang Hu <hukangustc@gmail.com>
Kato Kazuyoshi <kato.kazuyoshi@gmail.com>
Ken Rockot <ken@oz.gs> <ken.rockot@gmail.com>
Ken Sedgwick <ken@bonsai.com>
Ken Thompson <ken@golang.org>
+Kenji Kaneda <kenji.kaneda@gmail.com>
+Kenneth Shaw <kenshaw@gmail.com>
Kenny Grant <kennygrant@gmail.com>
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 Malachowski <chowski@google.com>
+Kevin Vu <kevin.m.vu@gmail.com>
Kim Shrier <kshrier@racktopsystems.com>
Kirklin McDonald <kirklin.mcdonald@gmail.com>
Klaus Post <klauspost@gmail.com>
Lai Jiangshan <eag0628@gmail.com>
Larry Hosken <lahosken@golang.org>
Larz Conwell <larzconwell@gmail.com>
+Lee Hinman <hinman@gmail.com>
Lee Packham <lpackham@gmail.com>
Lewin Bormann <lewin.bormann@gmail.com>
Lloyd Dewolf <foolswisdom@gmail.com>
Lorenzo Stoakes <lstoakes@gmail.com>
Louis Kruger <louisk@google.com>
+Luan Santos <cfcluan@gmail.com>
Luca Greco <luca.greco@alcacoop.it>
Lucien Stuker <lucien.stuker@gmail.com>
Lucio De Re <lucio.dere@gmail.com>
Manu S Ajith <neo@codingarena.in>
Manuel Mendez <mmendez534@gmail.com>
Marc Weistroff <marc@weistroff.net>
+Marc-Antoine Ruel <maruel@chromium.org>
Marcel van Lohuizen <mpvl@golang.org>
Marco Hennings <marco.hennings@freiheit.com>
Marga Manterola <marga@google.com>
Marius Nuennerich <mnu@google.com>
Mark Bucciarelli <mkbucc@gmail.com>
+Mark Severson <miquella@gmail.com>
Mark Theunissen <mark.theunissen@gmail.com>
Mark Zavislak <zavislak@google.com>
Marko Juhani Silokunnas <marko.silokunnas@gmail.com>
Markus Duft <markus.duft@salomon.at>
Markus Sonderegger <marraison@gmail.com>
Markus Zimmermann <zimmski@gmail.com>
+Martin Garton <garton@gmail.com>
Martin Möhrmann <martisch@uos.de>
Martin Neubauer <m.ne@gmx.net>
Martin Olsson <martin@minimum.se>
Marvin Stenger <marvin.stenger94@gmail.com>
Mateusz Czapliński <czapkofan@gmail.com>
Mathias Beke <git@denbeke.be>
+Mathias Leppich <mleppich@muhqu.de>
Mathieu Lonjaret <mathieu.lonjaret@gmail.com>
Mats Lidell <mats.lidell@cag.se> <mats.lidell@gmail.com>
Matt Aimonetti <mattaimonetti@gmail.com>
Matt Jones <mrjones@google.com>
Matt Layher <mdlayher@gmail.com>
Matt Reiferson <mreiferson@gmail.com>
+Matt Robenolt <matt@ydekproductions.com>
Matt T. Proud <matt.proud@gmail.com>
Matt Williams <gh@mattyw.net> <mattyjwilliams@gmail.com>
Matthew Brennan <matty.brennan@gmail.com>
Maxim Khitrov <max@mxcrypt.com>
Maxim Pimenov <mpimenov@google.com>
Maxim Ushakov <ushakov@google.com>
+Maxwell Krohn <themax@gmail.com>
Meir Fischer <meirfischer@gmail.com>
Meng Zhuo <mengzhuo1203@gmail.com>
Mhd Sulhan <m.shulhan@gmail.com>
Michael MacInnis <Michael.P.MacInnis@gmail.com>
Michael Marineau <michael.marineau@coreos.com>
Michael Matloob <matloob@google.com>
+Michael McConville <momcconville@gmail.com>
Michael McGreevy <mcgreevy@golang.org>
+Michael Munday <munday@ca.ibm.com>
Michael Pearson <mipearson@gmail.com>
Michael Piatek <piatek@google.com>
+Michael Pratt <mpratt@google.com>
Michael Schaller <michael@5challer.de>
Michael Shields <mshields@google.com>
Michael Stapelberg <michael@stapelberg.de> <mstplbrg@googlemail.com>
Michal Cierniak <cierniak@google.com>
Michał Derkacz <ziutek@lnet.pl>
Michalis Kargakis <michaliskargakis@gmail.com>
+Michel Lespinasse <walken@google.com>
Miek Gieben <miek@miek.nl> <remigius.gieben@gmail.com>
Mihai Borobocea <MihaiBorobocea@gmail.com>
Mikael Tillenius <mikti42@gmail.com>
Mike Andrews <mra@xoba.com>
+Mike Danese <mikedanese@google.com>
Mike Rosset <mike.rosset@gmail.com>
Mike Samuel <mikesamuel@gmail.com>
Mike Solomon <msolo@gmail.com>
+Mikhail Gusarov <dottedmag@dottedmag.net>
Mikhail Panchenko <m@mihasya.com>
Miki Tebeka <miki.tebeka@gmail.com>
Mikio Hara <mikioh.mikioh@gmail.com>
Mikkel Krautz <mikkel@krautz.dk> <krautz@gmail.com>
Miquel Sabaté Solà <mikisabate@gmail.com>
Mohit Agarwal <mohit@sdf.org>
+Monty Taylor <mordred@inaugust.com>
Moriyoshi Koizumi <mozo@mozo.jp>
+Morten Siebuhr <sbhr@sbhr.dk>
Môshe van der Sterre <moshevds@gmail.com>
Mrunal Patel <mrunalp@gmail.com>
+Muhammed Uluyol <uluyol0@gmail.com>
Nan Deng <monnand@gmail.com>
Nathan John Youngman <nj@nathany.com>
Nathan Otterness <otternes@cs.unc.edu>
Nathan(yinian) Hu <nathanhu@google.com>
Neelesh Chandola <neelesh.c98@gmail.com>
Nevins Bartolomeo <nevins.bartolomeo@gmail.com>
+Niall Sheridan <nsheridan@gmail.com>
Nicholas Katsaros <nick@nickkatsaros.com>
Nicholas Presta <nick@nickpresta.ca> <nick1presta@gmail.com>
Nicholas Sullivan <nicholas.sullivan@gmail.com>
Nicholas Waples <nwaples@gmail.com>
Nick Cooper <nmvc@google.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 Owens <mischief@offblast.org>
Nicolas S. Dade <nic.dade@gmail.com>
+Niels Widger <niels.widger@gmail.com>
Nigel Kerr <nigel.kerr@gmail.com>
Nigel Tao <nigeltao@golang.org>
+Niko Dziemba <niko@dziemba.com>
Nikolay Turpitko <nikolay@turpitko.com>
Noah Campbell <noahcampbell@gmail.com>
Nodir Turakulov <nodir@google.com>
Oliver Hookins <ohookins@gmail.com>
Olivier Antoine <olivier.antoine@gmail.com>
Olivier Duperray <duperray.olivier@gmail.com>
+Olivier Poitrey <rs@dailymotion.com>
Olivier Saingre <osaingre@gmail.com>
+Omar Jarjur <ojarjur@google.com>
+Özgür Kesim <oec-go@kesim.org>
Padraig Kitterick <padraigkitterick@gmail.com>
Paolo Giarrusso <p.giarrusso@gmail.com>
Paolo Martini <mrtnpaolo@gmail.com>
Paul Sbarra <Sbarra.Paul@gmail.com>
Paul Smith <paulsmith@pobox.com> <paulsmith@gmail.com>
Paul van Brouwershaven <paul@vanbrouwershaven.com>
+Paul Wankadia <junyer@google.com>
Pavel Paulau <pavel.paulau@gmail.com>
Pavel Zinovkin <pavel.zinovkin@gmail.com>
Pawel Knap <pawelknap88@gmail.com>
Peter Armitage <peter.armitage@gmail.com>
Peter Collingbourne <pcc@google.com>
Peter Froehlich <peter.hans.froehlich@gmail.com>
+Peter Gonda <pgonda@google.com>
Peter Kleiweg <pkleiweg@xs4all.nl>
Peter McKenzie <petermck@google.com>
Peter Moody <pmoody@uber.com>
Peter Weinberger <pjw@golang.org>
Peter Williams <pwil3058@gmail.com>
Phil Pennock <pdp@golang.org>
+Philip Hofer <phofer@umich.edu>
Philip K. Warren <pkwarren@gmail.com>
+Pierre Durand <pierredurand@gmail.com>
Pierre Roullon <pierre.roullon@gmail.com>
Pieter Droogendijk <pieter@binky.org.uk>
Pietro Gagliardi <pietro10@mac.com>
+Prashant Varanasi <prashant@prashantv.com>
Preetam Jinka <pj@preet.am>
Quan Yong Zhai <qyzhai@gmail.com>
Quentin Perez <qperez@ocs.online.net>
+Quentin Smith <quentin@golang.org>
Quoc-Viet Nguyen <afelion@gmail.com>
Rahul Chaudhry <rahulchaudhry@chromium.org>
Raif S. Naffah <go@naffah-raif.name>
Raul Silvera <rsilvera@google.com>
Reinaldo de Souza Jr <juniorz@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 Crowley <r@rcrowley.org>
Richard Eric Gavaletz <gavaletz@gmail.com>
+Richard Miller <miller.research@gmail.com>
Richard Musiol <mail@richard-musiol.de> <neelance@gmail.com>
Rick Arnold <rickarnoldjr@gmail.com>
Rick Hudson <rlh@golang.org>
+Riku Voipio <riku.voipio@linaro.org>
Risto Jaakko Saarelma <rsaarelm@gmail.com>
Rob Earhart <earhart@google.com>
Rob Norman <rob.norman@infinitycloud.com>
Rodrigo Rafael Monti Kochenburger <divoxx@gmail.com>
Roger Pau Monné <royger@gmail.com>
Roger Peppe <rogpeppe@gmail.com>
+Roland Shoemaker <rolandshoemaker@gmail.com>
Ron Hashimoto <mail@h2so5.net>
Ron Minnich <rminnich@gmail.com>
Ross Light <light@google.com> <rlight2@gmail.com>
Ryan Slade <ryanslade@gmail.com>
S.Çağlar Onur <caglar@10ur.org>
Salmān Aljammāz <s@0x65.net>
+Sam Hug <samuel.b.hug@gmail.com>
Sam Thorogood <thorogood@google.com> <sam.thorogood@gmail.com>
+Sam Whited <sam@samwhited.com>
Sameer Ajmani <sameer@golang.org> <ajmani@gmail.com>
+Sami Commerot <samic@google.com>
Sanjay Menakuru <balasanjay@gmail.com>
Sasha Lionheart <lionhearts@google.com>
Scott Barron <scott.barron@github.com>
+Scott Bell <scott@sctsm.com>
Scott Ferguson <scottwferg@gmail.com>
Scott Lawrence <bytbox@gmail.com>
+Scott Mansfield <smansfield@netflix.com>
Scott Schwartz <scotts@golang.org>
Scott Van Woudenberg <scottvw@google.com>
Sean Burford <sburford@google.com>
Sean Dolphin <Sean.Dolphin@kpcompass.com>
+Sean Harger <sharger@google.com>
Sebastien Binet <seb.binet@gmail.com>
Sébastien Paolacci <sebastien.paolacci@gmail.com>
Sergei Skorobogatov <skorobo@rambler.ru>
Sergey Arseev <sergey.arseev@intel.com>
Sergio Luis O. B. Correia <sergio@correia.cc>
Seth Hoenig <seth.a.hoenig@gmail.com>
+Shahar Kohanim <skohanim@gmail.com>
Shane Hansen <shanemhansen@gmail.com>
Shaozhen Ding <dsz0111@gmail.com>
Shawn Ledbetter <sledbetter@google.com>
Shawn Smith <shawn.p.smith@gmail.com>
Shawn Walker-Salas <shawn.walker@oracle.com>
Shenghou Ma <minux@golang.org> <minux.ma@gmail.com>
+Shinji Tanaka <shinji.tanaka@gmail.com>
Shivakumar GN <shivakumar.gn@gmail.com>
Shun Fan <sfan@google.com>
Silvan Jegen <s.jegen@gmail.com>
+Simon Jefford <simon.jefford@gmail.com>
Simon Whitehead <chemnova@gmail.com>
Sokolov Yura <funny.falcon@gmail.com>
Spencer Nelson <s@spenczar.com>
Spring Mc <heresy.mc@gmail.com>
Srdjan Petrovic <spetrovic@google.com>
+Sridhar Venkatakrishnan <sridhar@laddoo.net>
StalkR <stalkr@stalkr.net>
Stan Schwertly <stan@schwertly.com>
Stefan Nilsson <snilsson@nada.kth.se> <trolleriprofessorn@gmail.com>
Steven Elliot Harris <seharris@gmail.com>
Steven Hartland <steven.hartland@multiplay.co.uk>
Sugu Sougoumarane <ssougou@gmail.com>
+Suharsh Sivakumar <suharshs@google.com>
Sven Almgren <sven@tras.se>
Szabolcs Nagy <nsz@port70.net>
Tad Glines <tad.glines@gmail.com>
Taj Khattra <taj.khattra@gmail.com>
Takashi Matsuo <tmatsuo@google.com>
Takeshi YAMANASHI <9.nashi@gmail.com>
+Tal Shprecher <tshprecher@gmail.com>
Tamir Duberstein <tamird@gmail.com>
Tarmigan Casebolt <tarmigan@gmail.com>
Taru Karttunen <taruti@taruti.net>
Thomas Habets <habets@google.com>
Thomas Kappler <tkappler@gmail.com>
Thorben Krueger <thorben.krueger@gmail.com>
+Tilman Dilo <tilman.dilo@gmail.com>
Tim Cooijmans <timcooijmans@gmail.com>
+Tim Ebringer <tim.ebringer@gmail.com>
Tim Hockin <thockin@google.com>
+Tim Swast <swast@google.com>
Timo Savola <timo.savola@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>
+Toby Burress <kurin@google.com>
Todd Neal <todd@tneal.org>
Todd Wang <toddwang@gmail.com>
+Tom Bergan <tombergan@google.com>
Tom Heng <zhm20070928@gmail.com>
Tom Linford <tomlinford@gmail.com>
Tom Szymanski <tgs@google.com>
Tudor Golubenco <tudor.g@gmail.com>
Tyler Bunnell <tylerbunnell@gmail.com>
Tyler Treat <ttreat31@gmail.com>
+Tzu-Jung Lee <roylee17@currant.com>
Ugorji Nwoke <ugorji@gmail.com>
Ulf Holm Nielsen <doktor@dyregod.dk>
Ulrich Kunitz <uli.kunitz@gmail.com>
Uriel Mangado <uriel@berlinblue.org>
Uttam C Pawar <uttam.c.pawar@intel.com>
+Vadim Grek <vadimprog@gmail.com>
Vadim Vygonets <unixdj@gmail.com>
Vega Garcia Luis Alfonso <vegacom@gmail.com>
Vincent Ambo <tazjin@googlemail.com>
Vincent Vanackere <vincent.vanackere@gmail.com>
Vinu Rajashekhar <vinutheraj@gmail.com>
Vish Subramanian <vish@google.com>
+Vishvananda Ishaya <vishvananda@gmail.com>
Vlad Krasnov <vlad@cloudflare.com>
Vladimir Nikishenko <vova616@gmail.com>
Volker Dobler <dr.volker.dobler@gmail.com>
+Wedson Almeida Filho <wedsonaf@google.com>
Wei Guangjing <vcc.163@gmail.com>
Will Chan <willchan@google.com>
Will Norris <willnorris@google.com>
William Orr <will@worrbase.com> <ay1244@gmail.com>
Xia Bin <snyh@snyh.org>
Xing Xing <mikespook@gmail.com>
+Xudong Zhang <felixmelon@gmail.com>
Yan Zou <yzou@google.com>
Yann Kerhervé <yann.kerherve@gmail.com>
Yao Zhang <lunaria21@gmail.com>
Yuusei Kuwana <kuwana@kumama.org>
Yuval Pavel Zholkover <paulzhol@gmail.com>
Yves Junqueira <yvesj@google.com> <yves.junqueira@gmail.com>
+Zhongwei Yao <zhongwei.yao@arm.com>
Ziad Hatahet <hatahet@gmail.com>
Zorion Arrizabalaga <zorionk@gmail.com>
申习之 <bronze1man@gmail.com>
pkg context, type Context interface, Value(interface{}) interface{}
pkg context, var Canceled 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, Renegotiation RenegotiationSupport
+pkg crypto/tls, type RenegotiationSupport int
pkg crypto/x509, func SystemCertPool() (*CertPool, error)
pkg crypto/x509, type SystemRootsError struct, Err error
pkg debug/dwarf, method (*Data) Ranges(*Entry) ([][2]uint64, error)
pkg debug/elf, method (R_390) GoString() string
pkg debug/elf, method (R_390) String() string
pkg debug/elf, type R_390 int
-pkg encoding/json, method (*Encoder) DisableHTMLEscaping()
-pkg encoding/json, method (*Encoder) Indent(string, string)
+pkg encoding/json, method (*Encoder) SetEscapeHTML(bool)
+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, FFiles []string
pkg go/doc, type Example struct, Unordered bool
pkg io, const SeekEnd ideal-int
pkg io, const SeekStart = 0
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) GobEncode() ([]uint8, 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) 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, IdleConnTimeout time.Duration
+pkg net/http, type Transport struct, MaxIdleConns int
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/cgi, type Handler struct, Stderr io.Writer
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 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 LookupGroupId(string) (*Group, error)
pkg os/user, method (*User) GroupIds() ([]string, error)
pkg reflect, func StructOf([]StructField) Type
pkg reflect, method (StructTag) Lookup(string) (string, bool)
pkg runtime, func CallersFrames([]uintptr) *Frames
+pkg runtime, func KeepAlive(interface{})
pkg runtime, func SetCgoTraceback(int, unsafe.Pointer, unsafe.Pointer, unsafe.Pointer)
pkg runtime, method (*Frames) Next() (Frame, bool)
pkg runtime, type Frame struct
pkg runtime, type Frame struct, PC uintptr
pkg runtime, type Frames struct
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 (*T) Run(string, func(*T)) bool
pkg testing, type InternalExample struct, Unordered bool
</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>Vet examines Go source code and reports suspicious constructs, such as Printf
calls whose arguments do not align with the format string.</td>
The first line of the change description is conventionally a one-line
summary of the change, prefixed by the primary affected package,
and is used as the subject for code review mail.
-The rest of the
-description elaborates and should provide context for the
+It should complete the sentence "This change modifies Go to _____."
+The rest of the description elaborates and should provide context for the
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 you've fixed an issue, reference it by number with a # before it.
</p>
<p>
</p>
<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
large arguments, so use the McGillicutty algorithm to improve
type ByteSlice []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>
<p>
--- /dev/null
+<!--{
+ "Title": "Go 1.7 Release Notes DRAFT",
+ "Path": "/doc/go1.7",
+ "Template": true
+}-->
+
+<!--
+for acme:
+Edit .,s;^PKG:([a-z][A-Za-z0-9_/]+);<a href="/pkg/\1/"><code>\1</code></a>;g
+Edit .,s;^([a-z][A-Za-z0-9_/]+)\.([A-Z][A-Za-z0-9_]+\.)?([A-Z][A-Za-z0-9_]+)([ .',)]|$);<a href="/pkg/\1/#\2\3"><code>\3</code></a>\4;g
+Edit .,s;^FULL:([a-z][A-Za-z0-9_/]+)\.([A-Z][A-Za-z0-9_]+\.)?([A-Z][A-Za-z0-9_]+)([ .',)]|$);<a href="/pkg/\1/#\2\3"><code>\1.\2\3</code></a>\4;g
+Edit .,s;^DPKG:([a-z][A-Za-z0-9_/]+);<dl id="\1"><a href="/pkg/\1/">\1</a></dl>;g
+
+rsc last updated through 6729576
+-->
+
+<!--
+NOTE: In this document and others in this directory, the convention is to
+set fixed-width phrases with non-fixed-width spaces, as in
+<code>hello</code> <code>world</code>.
+Do not send CLs removing the interior tags from such phrases.
+-->
+
+<style>
+ul li { margin: 0.5em 0; }
+</style>
+
+<p>
+<!-- TODO: REMOVE THIS COMMENT -->
+<!-- TODO: Also remove "DRAFT" in the "Title" at the top of this file. -->
+<i>NOTE: This is a DRAFT of the Go 1.7 release notes, prepared for the Go 1.7 beta.
+Go 1.7 has NOT yet been released.
+By our regular schedule, it is expected some time in August 2016.
+</i>
+</p>
+
+<h2 id="introduction">Introduction to Go 1.7</h2>
+
+<p>
+The latest Go release, version 1.7, arrives six months after 1.6.
+Most of its changes are in the implementation of the toolchain, runtime, and libraries.
+There is one minor change to the language specification.
+As always, the release maintains the Go 1 <a href="/doc/go1compat.html">promise of compatibility</a>.
+We expect almost all Go programs to continue to compile and run as before.
+</p>
+
+<p>
+The release <a href="#ports">adds a port to IBM LinuxOne</a>;
+<a href="#compiler">updates the x86-64 compiler back end</a> to generate more efficient code;
+includes the <a href="#context">context package</a>, promoted from the
+<a href="https://golang.org/x/net/context">x/net subrepository</a>
+and now used in the standard library;
+and <a href="#testing">adds support in the testing package</a> for
+creating hierarchies of tests and benchmarks.
+The release also <a href="#cmd/go">finalizes the vendoring support</a>
+started in Go 1.5, making it a standard feature.
+</p>
+
+<h2 id="language">Changes to the language</h2>
+
+<p>
+There is one tiny language change in this release.
+The section on <a href="/ref/spec#Terminating_statements">terminating statements</a>
+clarifies that to determine whether a statement list ends in a terminating statement,
+the “final non-empty statement” is considered the end,
+matching the existing behavior of the gc and gccgo compiler toolchains.
+In earlier releases the definition referred only to the “final statement,”
+leaving the effect of trailing empty statements at the least unclear.
+The <a href="/pkg/go/types/"><code>go/types</code></a>
+package has been updated to match the gc and gccgo compiler toolchains
+in this respect.
+This change has no effect on the correctness of existing programs.
+</p>
+
+<h2 id="ports">Ports</h2>
+
+<p>
+Go 1.7 adds an experimental port to <a href="https://en.wikipedia.org/wiki/Linux_on_z_Systems">Linux on z Systems</a> (<code>linux/s390x</code>)
+and the beginning of a port to Plan 9 on ARM (<code>plan9/arm</code>).
+</p>
+
+<p>
+The experimental ports to Linux on 64-bit MIPS (<code>linux/mips64</code> and <code>linux/mips64le</code>)
+added in Go 1.6 now have full support for cgo and external linking.
+</p>
+
+<p>
+The experimental port to Linux on big-endian 64-bit PowerPC (<code>linux/ppc64</code>)
+now requires the POWER8 architecture or later.
+</p>
+
+<p>
+The OpenBSD port now requires OpenBSD 5.6 or later, for access to the <a href="http://man.openbsd.org/getentropy.2"><i>getentropy</i>(2)</a> system call.
+</p>
+
+<h2 id="tools">Tools</h2>
+
+<h3 id="cmd/asm">Assembler</h3>
+
+<p>
+For 64-bit ARM systems, the vector register names have been
+corrected to <code>V0</code> through <code>V31</code>;
+previous releases incorrectly referred to them as <code>V32</code> through <code>V63</code>.
+</p>
+
+<p>
+For 64-bit x86 systems, the following instructions have been added:
+<code>PCMPESTRI</code>,
+<code>RORXL</code>,
+<code>RORXQ</code>,
+<code>VINSERTI128</code>,
+<code>VPADDD</code>,
+<code>VPADDQ</code>,
+<code>VPALIGNR</code>,
+<code>VPBLENDD</code>,
+<code>VPERM2F128</code>,
+<code>VPERM2I128</code>,
+<code>VPOR</code>,
+<code>VPSHUFB</code>,
+<code>VPSHUFD</code>,
+<code>VPSLLD</code>,
+<code>VPSLLDQ</code>,
+<code>VPSLLQ</code>,
+<code>VPSRLD</code>,
+<code>VPSRLDQ</code>,
+and
+<code>VPSRLQ</code>.
+</p>
+
+<h3 id="compiler">Compiler Toolchain</h3>
+
+<p>
+This release includes a new code generation back end for 64-bit x86 systems,
+following a <a href="https://golang.org/s/go17ssa">proposal from 2015</a>
+that has been under development since then.
+The new back end, based on
+<a href="https://en.wikipedia.org/wiki/Static_single_assignment_form">SSA</a>,
+generates more compact, more efficient code
+and provides a better platform for optimizations
+such as bounds check elimination.
+The new back end reduces the CPU time required by
+<a href="https://golang.org/test/bench/go1/">our benchmark programs</a> by 5-35%.
+</p>
+
+<p>
+For this release, the new back end can be disabled by passing
+<code>-ssa=0</code> to the compiler.
+If you find that your program compiles or runs successfully
+only with the new back end disabled, please
+<a href="https://golang.org/issue/new">file a bug report</a>.
+</p>
+
+<p>
+The format of exported metadata written by the compiler in package archives has changed:
+the old textual format has been replaced by a more compact binary format.
+This results in somewhat smaller package archives and fixes a few
+long-standing corner case bugs.
+</p>
+
+<p>
+For this release, the new export format can be disabled by passing
+<code>-newexport=0</code> to the compiler.
+If you find that your program compiles or runs successfully
+only with the new export format disabled, please
+<a href="https://golang.org/issue/new">file a bug report</a>.
+</p>
+
+<p>
+The linker's <code>-X</code> option no longer supports the unusual two-argument form
+<code>-X</code> <code>name</code> <code>value</code>,
+as <a href="/doc/go1.6#compiler">announced</a> in the Go 1.6 release
+and in warnings printed by the linker.
+Use <code>-X</code> <code>name=value</code> instead.
+</p>
+
+<p>
+The compiler and linker have been optimized and run significantly faster in this release than in Go 1.6,
+although they are still slower than we would like and will continue to be optimized in future releases.
+</p>
+
+<p>
+Due to changes across the compiler toolchain and standard library,
+binaries built with this release should typically be smaller than binaries
+built with Go 1.6,
+sometimes by as much as 20-30%.
+</p>
+
+<h3 id="cmd/cgo">Cgo</h3>
+
+<p>
+Packages using <a href="/cmd/cgo/">cgo</a> may now include
+Fortran source files (in addition to C, C++, Objective C, and SWIG),
+although the Go bindings must still use C language APIs.
+</p>
+
+<p>
+Go bindings may now use a new helper function <code>C.CBytes</code>.
+In contrast to <code>C.CString</code>, which takes a Go <code>string</code>
+and returns a <code>*C.byte</code> (a C <code>char*</code>),
+<code>C.CBytes</code> takes a Go <code>[]byte</code>
+and returns an <code>unsafe.Pointer</code> (a C <code>void*</code>).
+</p>
+
+<p>
+Packages and binaries built using <code>cgo</code> have in past releases
+produced different output on each build,
+due to the embedding of temporary directory names.
+When using this release with
+new enough versions of GCC or Clang
+(those that support the <code>-fdebug-prefix-map</code> option),
+those builds should finally be deterministic.
+</p>
+
+<h3 id="gccgo">Gccgo</h3>
+
+<p>
+Due to the alignment of Go's semiannual release schedule with GCC's annual release schedule,
+GCC release 6 contains the Go 1.6.1 version of gccgo.
+The next release, GCC 7, will likely have the Go 1.8 version of gccgo.
+</p>
+
+<h3 id="cmd/go">Go command</h3>
+
+<p>
+The <a href="/cmd/go/"><code>go</code></a> command's basic operation
+is unchanged, but there are a number of changes worth noting.
+</p>
+
+<p>
+This release removes support for the <code>GO15VENDOREXPERIMENT</code> environment variable,
+as <a href="/doc/go1.6#go_command">announced</a> in the Go 1.6 release.
+<a href="https://golang.org/s/go15vendor">Vendoring support</a>
+is now a standard feature of the <code>go</code> command and toolchain.
+</p>
+
+<p>
+The <code>Package</code> data structure made available to
+“<code>go</code> <code>list</code>” now includes a
+<code>StaleReason</code> field explaining why a particular package
+is or is not considered stale (in need of rebuilding).
+This field is available to the <code>-f</code> or <code>-json</code>
+options and is useful for understanding why a target is being rebuilt.
+</p>
+
+<p>
+The “<code>go</code> <code>get</code>” command now supports
+import paths referring to <code>git.openstack.org</code>.
+</p>
+
+<p>
+This release adds experimental, minimal support for building programs using
+<a href="/pkg/go/build#hdr-Binary_Only_Packages">binary-only packages</a>,
+packages distributed in binary form
+without the corresponding source code.
+This feature is needed in some commercial settings
+but is not intended to be fully integrated into the rest of the toolchain.
+For example, tools that assume access to complete source code
+will not work with such packages, and there are no plans to support
+such packages in the “<code>go</code> <code>get</code>” command.
+</p>
+
+<h3 id="cmd/doc">Go doc</h3>
+
+<p>
+The “<code>go</code> <code>doc</code>” command
+now groups constructors with the type they construct,
+following <a href="/cmd/godoc/"><code>godoc</code></a>.
+</p>
+
+<h3 id="cmd/vet">Go vet</h3>
+
+<p>
+The “<code>go</code> <code>vet</code>” command
+has more accurate analysis in its <code>-copylock</code> and <code>-printf</code> checks,
+and a new <code>-tests</code> check that checks the name and signature of likely test functions.
+To avoid confusion with the new <code>-tests</code> check, the old, unadvertised
+<code>-test</code> option has been removed; it was equivalent to <code>-all</code> <code>-shadow</code>.
+</p>
+
+<h3 id="cmd/dist">Go tool dist</h3>
+
+<p>
+The new subcommand “<code>go</code> <code>tool</code> <code>dist</code> <code>list</code>”
+prints all supported operating system/architecture pairs.
+</p>
+
+<h3 id="cmd/trace">Go tool trace</h3>
+
+<p>
+The “<code>go</code> <code>tool</code> <code>trace</code>” command,
+<a href="/doc/go1.5#trace_command">introduced in Go 1.5</a>,
+has been refined in various ways.
+</p>
+
+<p>
+First, collecting traces is significantly more efficient than in past releases.
+In this release, the typical execution-time overhead of collecting a trace is about 25%;
+in past releases it was at least 400%.
+Second, trace files now include file and line number information,
+making them more self-contained and making the
+original executable optional when running the trace tool.
+Third, the trace tool now breaks up large traces to avoid limits
+in the browser-based viewer.
+</p>
+
+<p>
+Although the trace file format has changed in this release,
+the Go 1.7 tools can still read traces from earlier releases.
+</p>
+
+<h2 id="performance">Performance</h2>
+
+<p>
+As always, the changes are so general and varied that precise statements
+about performance are difficult to make.
+Most programs should run a bit faster,
+due to speedups in the garbage collector and
+optimizations in the core library.
+On x86-64 systems, many programs will run significantly faster,
+due to improvements in generated code brought by the
+new compiler back end.
+As noted above, in our own benchmarks,
+the code generation changes alone typically reduce program CPU time by 5-35%.
+</p>
+
+<p>
+<!-- git log --grep '-[0-9][0-9]\.[0-9][0-9]%' go1.6.. -->
+There have been significant optimizations bringing more than 10% improvements
+to implementations in the
+<a href="/pkg/crypto/sha1/"><code>crypto/sha1</code></a>,
+<a href="/pkg/crypto/sha256/"><code>crypto/sha256</code></a>,
+<a href="/pkg/encoding/binary/"><code>encoding/binary</code></a>,
+<a href="/pkg/fmt/"><code>fmt</code></a>,
+<a href="/pkg/hash/adler32/"><code>hash/adler32</code></a>,
+<a href="/pkg/hash/crc32/"><code>hash/crc32</code></a>,
+<a href="/pkg/hash/crc64/"><code>hash/crc64</code></a>,
+<a href="/pkg/image/color/"><code>image/color</code></a>,
+<a href="/pkg/math/big/"><code>math/big</code></a>,
+<a href="/pkg/strconv/"><code>strconv</code></a>,
+<a href="/pkg/strings/"><code>strings</code></a>,
+<a href="/pkg/unicode/"><code>unicode</code></a>,
+and
+<a href="/pkg/unicode/utf16/"><code>unicode/utf16</code></a>
+packages.
+</p>
+
+<h2 id="library">Core library</h2>
+
+<h3 id="context">Context</h3>
+
+<p>
+Go 1.7 moves the <code>golang.org/x/net/context</code> package
+into the standard library as <a href="/pkg/context/"><code>context</code></a>.
+This allows the use of contexts for cancellation, timeouts, and passing
+request-scoped data in other standard library packages,
+including
+<a href="#net">net</a>,
+<a href="#net/http">net/http</a>,
+and
+<a href="#os/exec">os/exec</a>,
+as noted below.
+</p>
+
+<p>
+For more information about contexts, see the
+<a href="/pkg/context/">package documentation</a>
+and the Go blog post
+“<a href="https://blog.golang.org/context">Go Concurrent Patterns: Context</a>.”
+</p>
+
+<h3 id="testing">Testing</h3>
+
+<p>
+The <code>testing</code> package now supports the definition
+of tests with subtests and benchmarks with sub-benchmarks.
+This support makes it easy to write table-driven benchmarks
+and to create hierarchical tests.
+It also provides a way to share common setup and tear-down code.
+See the <a href="/pkg/testing/#hdr-Subtests_and_Sub_benchmarks">package documentation</a> for details.
+</p>
+
+<h3 id="runtime">Runtime</h3>
+
+<p>
+All panics started by the runtime now use panic values
+that implement both the builtin <a href="/ref/spec#Errors">error</code>,
+and
+<a href="/pkg/runtime/#Error"><code>runtime.Error</code></a>,
+as
+<a href="/ref/spec#Run_time_panics">required by the language specification</a>.
+</p>
+
+<p>
+During panics, if a signal's name is known, it will be printed in the stack trace.
+Otherwise, the signal's number will be used, as it was before Go1.7.
+</p>
+
+<p>
+The new function
+<a href="/pkg/runtime/#KeepAlive"><code>KeepAlive</code></a>
+provides an explicit mechanism for declaring
+that an allocated object must be considered reachable
+at a particular point in a program,
+typically to delay the execution of an associated finalizer.
+</p>
+
+<p>
+The new function
+<a href="/pkg/runtime/#CallersFrames"><code>CallersFrames</code></a>
+translates a PC slice obtained from
+<a href="/pkg/runtime/#Callers"><code>Callers</code></a>
+into a sequence of frames corresponding to the call stack.
+This new API should be preferred instead of direct use of
+<a href="/pkg/runtime/#FuncForPC"><code>FuncForPC</code></a>,
+because the frame sequence can more accurately describe
+call stacks with inlined function calls.
+</p>
+
+<p>
+The new function
+<a href="/pkg/runtime/#SetCgoTraceback"><code>SetCgoTraceback</code></a>
+facilitates tighter integration between Go and C code executing
+in the same process called using cgo.
+</p>
+
+<p>
+On 32-bit systems, the runtime can now use memory allocated
+by the operating system anywhere in the address space,
+eliminating the
+“memory allocated by OS not in usable range” failure
+common in some environments.
+</p>
+
+<p>
+On Windows, Go programs in Go 1.5 and earlier forced
+the global Windows timer resolution to 1ms at startup
+by calling <code>timeBeginPeriod(1)</code>.
+Changing the global timer resolution caused problems on some systems,
+and testing suggested that the call was not needed for good scheduler performance,
+so Go 1.6 removed the call.
+Go 1.7 brings the call back: under some workloads the call
+is still needed for good scheduler performance.
+</p>
+
+
+<h3 id="minor_library_changes">Minor changes to the library</h3>
+
+<p>
+As always, there are various minor changes and updates to the library,
+made with the Go 1 <a href="/doc/go1compat">promise of compatibility</a>
+in mind.
+</p>
+
+<dl id="bufio"><a href="/pkg/bufio/">bufio</a></dl>
+
+<dd>
+<p>
+In previous releases of Go, if
+<a href="/pkg/bufio/#Reader"><code>Reader</code></a>'s
+<a href="/pkg/bufio/#Reader.Peek"><code>Peek</code></a> method
+were asked for more bytes than fit in the underlying buffer,
+it would return an empty slice and the error <code>ErrBufferFull</code>.
+Now it returns the entire underlying buffer, still accompanied by the error <code>ErrBufferFull</code>.
+</p>
+</dd>
+
+<dl id="bytes"><a href="/pkg/bytes/">bytes</a></dl>
+
+<dd>
+<p>
+The new functions
+<a href="/pkg/bytes/#ContainsAny"><code>ContainsAny</code></a> and
+<a href="/pkg/bytes/#ContainsRune"><code>ContainsRune</code></a>
+have been added for symmetry with
+the <a href="/pkg/strings/"><code>strings</code></a> package.
+</p>
+
+<p>
+In previous releases of Go, if
+<a href="/pkg/bytes/#Reader"><code>Reader</code></a>'s
+<a href="/pkg/bytes/#Reader.Read"><code>Read</code></a> method
+were asked for zero bytes with no data remaining, it would
+return a count of 0 and no error.
+Now it returns a count of 0 and the error
+<a href="/pkg/io/#EOF"><code>io.EOF</code></a> .
+</p>
+
+<p>
+The
+<a href="/pkg/bytes/#Reader"><code>Reader</code></a> type has a new method
+<a href="/pkg/bytes/#Reader.Reset"><code>Reset</code></a> to allow reuse of a <code>Reader</code>.
+</p>
+</dd>
+
+<dl id="compress/flate"><a href="/pkg/compress/flate/">compress/flate</a></dl>
+
+<dd>
+<p>
+As noted above,
+there are significant performance optimizations throughout the package.
+Decompression speed is improved by about 10%,
+while compression speed for <code>DefaultCompression</code> is roughly doubled.
+</p>
+
+<p>
+In addition to those general improvements,
+the
+<code>BestSpeed</code>
+compressor has been replaced entirely and uses an
+algorithm similar to <a href="https://github.com/google/snappy">Snappy</a>,
+resulting in about a 2.5X speed increase,
+although the output can be 5-10% larger than with the previous algorithm.
+</p>
+
+<p>
+There is also a new compression level
+<code>HuffmanOnly</code>
+that applies Huffman but not Lempel-Ziv encoding.
+<a href="https://blog.klauspost.com/constant-time-gzipzip-compression/">Forgoing Lempel-Ziv encoding</a> means that
+<code>HuffmanOnly</code> runs about 3X faster than the new <code>BestSpeed</code>
+but at the cost of producing compressed outputs that are 20-40% larger than those
+generated by the new <code>BestSpeed</code>.
+</p>
+</dd>
+
+<dl id="crypto/tls"><a href="/pkg/crypto/tls/">crypto/tls</a></dl>
+
+<dd>
+<p>
+The TLS implementation sends the first few data packets on each connection
+using small record sizes, gradually increasing to the TLS maximum record size.
+This heuristic reduces the amount of data that must be received before
+the first packet can be decrypted, improving communication latency over
+low-bandwidth networks.
+Setting
+<a href="/pkg/crypto/tls/#Config"><code>Config</code></a>'s
+<code>DynamicRecordSizingDisabled</code> field to true
+forces the behavior of Go 1.6 and earlier, where packets are
+as large as possible from the start of the connection.
+</p>
+
+<p>
+The TLS client now has optional, limited support for server-initiated renegotiation,
+enabled by setting the
+<a href="/pkg/crypto/tls/#Config"><code>Config</code></a>'s
+<code>Renegotiation</code> field.
+This is needed for connecting to many Microsoft Azure servers.
+</p>
+
+<p>
+The errors returned by the package now consistently begin with a
+<code>tls:</code> prefix.
+In past releases, some errors used a <code>crypto/tls:</code> prefix,
+some used a <code>tls:</code> prefix, and some had no prefix at all.
+</p>
+
+<p>
+When generating self-signed certificates, the package no longer sets the
+“Authority Key Identifier” field by default.
+</p>
+</dd>
+
+<dl id="crypto/x509"><a href="/pkg/crypto/x509/">crypto/x509</a></dl>
+
+<dd>
+<p>
+The new function
+<a href="/pkg/crypto/x509/#SystemCertPool"><code>SystemCertPool</code></a>
+provides access to the entire system certificate pool if available.
+There is also a new associated error type
+<a href="/pkg/crypto/x509/#SystemRootsError"><code>SystemRootsError</code></a>.
+</p>
+</dd>
+
+<dl id="debug/dwarf"><a href="/pkg/debug/dwarf/">debug/dwarf</a></dl>
+
+<dd>
+<p>
+The
+<a href="/pkg/debug/dwarf/#Reader"><code>Reader</code></a> type's new
+<a href="/pkg/debug/dwarf/#Reader.SeekPC"><code>SeekPC</code></a> method and the
+<a href="/pkg/debug/dwarf/#Data"><code>Data</code></a> type's new
+<a href="/pkg/debug/dwarf/#Ranges"><code>Ranges</code></a> method
+help to find the compilation unit to pass to a
+<a href="/pkg/debug/dwarf/#LineReader"><code>LineReader</code></a>
+and to identify the specific function for a given program counter.
+</p>
+</dd>
+
+<dl id="debug/elf"><a href="/pkg/debug/elf/">debug/elf</a></dl>
+
+<dd>
+<p>
+The new
+<a href="/pkg/debug/elf/#R_390"><code>R_390</code></a> relocation type
+and its many predefined constants
+support the S390 port.
+</p>
+</dd>
+
+<dl id="encoding/asn1"><a href="/pkg/encoding/asn1/">encoding/asn1</a></dl>
+
+<dd>
+<p>
+The ASN.1 decoder now rejects non-minimal integer encodings.
+This may cause the package to reject some invalid but formerly accepted ASN.1 data.
+</p>
+</dd>
+
+<dl id="encoding/json"><a href="/pkg/encoding/json/">encoding/json</a></dl>
+
+<dd>
+<p>
+The
+<a href="/pkg/encoding/json/#Encoder"><code>Encoder</code></a>'s new
+<a href="/pkg/encoding/json/#Encoder.SetIndent"><code>SetIndent</code></a> method
+sets the indentation parameters for JSON encoding,
+like in the top-level
+<a href="/pkg/encoding/json/#Indent"><code>Indent</code></a> function.
+</p>
+
+<p>
+The
+<a href="/pkg/encoding/json/#Encoder"><code>Encoder</code></a>'s new
+<a href="/pkg/encoding/json/#Encoder.SetEscapeHTML"><code>SetEscapeHTML</code></a> method
+controls whether the
+<code>&</code>, <code><</code>, and <code>></code>
+characters in quoted strings should be escaped as
+<code>\u0026</code>, <code>\u003c</code>, and <code>\u003e</code>,
+respectively.
+As in previous releases, the encoder defaults to applying this escaping,
+to avoid certain problems that can arise when embedding JSON in HTML.
+</p>
+
+<p>
+In earlier versions of Go, this package only supported encoding and decoding
+maps using keys with string types.
+Go 1.7 adds support for maps using keys with integer types:
+the encoding uses a quoted decimal representation as the JSON key.
+Go 1.7 also adds support for encoding maps using non-string keys that implement
+<code>MarshalJSON</code>
+(see
+<a href="/pkg/encoding/json/#Marshaler"><code>Marshaler</code></a>)
+or
+<code>MarshalText</code>
+(see
+<a href="/pkg/encoding/#TextMarshaler"><code>encoding.TextMarshaler</code></a>)
+methods,
+as well as support for decoding maps using non-string keys that implement
+<code>UnmarshalJSON</code>
+(see
+<a href="/pkg/encoding/json/#Unmarshaler"><code>Unmarshaler</code></a>)
+or
+<code>UnmarshalText</code>
+(see
+<a href="/pkg/encoding/#TextUnmarshaler"><code>encoding.TextUnmarshaler</code></a>)
+methods.
+These methods are ignored for keys with string types in order to preserve
+the encoding and decoding used in earlier versions of Go.
+</p>
+
+<p>
+When encoding a slice of typed bytes,
+<a href="/pkg/encoding/json/#Marshal"><code>Marshal</code></a>
+now generates an array of elements encoded using
+that byte type's
+<code>MarshalJSON</code>
+or
+<code>MarshalText</code>
+method if present,
+only falling back to the default base64-encoded string data if neither method is available.
+Earlier versions of Go accept both the original base64-encoded string encoding
+and the array encoding (assuming the byte type also implements
+<code>UnmarshalJSON</code>
+or
+<code>UnmarshalText</code>
+as appropriate),
+so this change should be semantically backwards compatible with earlier versions of Go,
+even though it does change the chosen encoding.
+</p>
+</dd>
+
+<dl id="go/build"><a href="/pkg/go/build/">go/build</a></dl>
+
+<dd>
+<p>
+To implement the go command's new support for binary-only packages
+and for Fortran code in cgo-based packages,
+the
+<a href="/pkg/go/build/#Package"><code>Package</code></a> type
+adds new fields <code>BinaryOnly</code>, <code>CgoFFLAGS</code>, and <code>FFiles</code>.
+</p>
+</dd>
+
+<dl id="go/doc"><a href="/pkg/go/doc/">go/doc</a></dl>
+
+<dd>
+<p>
+To support the corresponding change in <code>go</code> <code>test</code> described above,
+<a href="/pkg/go/doc/#Example"><code>Example</code></a> struct adds a Unordered field
+indicating whether the example may generate its output lines in any order.
+</p>
+</dd>
+
+<dl id="io"><a href="/pkg/io/">io</a></dl>
+
+<dd>
+<p>
+The package adds new constants
+<code>SeekStart</code>, <code>SeekCurrent</code>, and <code>SeekEnd</code>,
+for use with
+<a href="/pkg/io/#Seeker"><code>Seeker</code></a>
+implementations.
+These constants are preferred over <code>os.SEEK_SET</code>, <code>os.SEEK_CUR</code>, and <code>os.SEEK_END</code>,
+but the latter will be preserved for compatibility.
+</p>
+</dd>
+
+<dl id="math/big"><a href="/pkg/math/big/">math/big</a></dl>
+
+<dd>
+<p>
+The
+<a href="/pkg/math/big/#Float"><code>Float</code></a> type adds
+<a href="/pkg/math/big/#Float.GobEncode"><code>GobEncode</code></a> and
+<a href="/pkg/math/big/#Float.GobDecode"><code>GobDecode</code></a> methods,
+so that values of type <code>Float</code> can now be encoded and decoded using the
+<a href="/pkg/encoding/gob/"><code>encoding/gob</code></a>
+package.
+</p>
+</dd>
+
+<dl id="mime/multipart"><a href="/pkg/mime/multipart/">mime/multipart</a></dl>
+
+<dd>
+<p>
+The
+<a href="/pkg/mime/multipart/#Writer"><code>Writer</code></a>
+implementation now emits each multipart section's header sorted by key.
+Previously, iteration over a map caused the section header to use a
+non-deterministic order.
+</p>
+</dd>
+
+<dl id="net"><a href="/pkg/net/">net</a></dl>
+
+<dd>
+<p>
+As part of the introduction of <a href="#context">context</a>, the
+<a href="/pkg/net/#Dialer"><code>Dialer</code></a> type has a new method
+<a href="/pkg/net/#Dialer.DialContext"><code>DialContext</code></a>, like
+<a href="/pkg/net/#Dialer.Dial"><code>Dial</code></a> but adding the
+<a href="/pkg/context/#Context"><code>context.Context</code></a>
+for the dial operation.
+The context is intended to obsolete the <code>Dialer</code>'s
+<code>Cancel</code> and <code>Deadline</code> fields,
+but the implementation continues to respect them,
+for backwards compatibility.
+</p>
+
+<p>
+The
+<a href="/pkg/net/#IP"><code>IP</code></a> type's
+<a href="/pkg/net/#IP.String"><code>String</code></a> method has changed its result for invalid <code>IP</code> addresses.
+In past releases, if an <code>IP</code> byte slice had length other than 0, 4, or 16, <code>String</code>
+returned <code>"?"</code>.
+Go 1.7 adds the hexadecimal encoding of the bytes, as in <code>"?12ab"</code>.
+</p>
+
+<p>
+The pure Go <a href="/pkg/net/#hdr-Name_Resolution">name resolution</a>
+implementation now respects <code>nsswtch.conf</code>'s
+stated preference for the priority of DNS lookups compared to
+local file (that is, <code>/etc/hosts</code>) lookups.
+</p>
+</dd>
+
+<dl id="net/http"><a href="/pkg/net/http/">net/http</a></dl>
+
+<dd>
+<p>
+<a href="/pkg/net/http/#ResponseWriter"><code>ResponseWriter</code></a>'s
+documentation now makes clear that beginning to write the response
+may prevent future reads on the request body.
+For maximal compatibility, implementations are encouraged to
+read the request body completely before writing any part of the response.
+</p>
+
+<p>
+As part of the introduction of <a href="#context">context</a>, the
+<a href="/pkg/net/http/#Request"><code>Request</code></a> has a new methods
+<a href="/pkg/net/http/#Request.Context"><code>Context</code></a>, to retrieve the associated context, and
+<a href="/pkg/net/http/#Request.WithContext"><code>WithContext</code></a>, to construct a copy of <code>Request</code>
+with a modified context.
+</p>
+
+<p>
+In the
+<a href="/pkg/net/http/#Server"><code>Server</code></a> implementation,
+<a href="/pkg/net/http/#Server.Serve"><code>Serve</code></a> records in the request context
+both the underlying <code>*Server</code> using the key <code>ServerContextKey</code>
+and the local address on which the request was received (a
+<a href="/pkg/net/#Addr"><code>Addr</code></a>) using the key <code>LocalAddrContextKey</code>.
+For example, the address on which a request received is
+<code>req.Context().Value(http.LocalAddrContextKey).(net.Addr)</code>.
+</p>
+
+<p>
+The server implementation now
+pads response codes less than 100 to three digits
+as required by the protocol,
+so that <code>w.WriteHeader(5)</code> uses the HTTP response
+status <code>005</code>, not just <code>5</code>.
+</p>
+
+<p>
+In the client, the
+<a href="/pkg/net/http/#Transport"><code>Transport</code></a> implementation passes the request context
+to any dial operation connecting to the remote server.
+If a custom dialer is needed, the new <code>Transport</code> field
+<code>DialContext</code> is preferred over the existing <code>Dial</code> field,
+to allow the transport to supply a context.
+</p>
+
+<p>
+The
+<a href="/pkg/net/http/#Transport"><code>Transport</code></a> also adds fields
+<code>IdleConnTimeout</code>,
+<code>MaxIdleConns</code>,
+and
+<code>MaxResponseHeaderBytes</code>
+to help control client resources consumed
+by idle or chatty servers.
+</p>
+
+<p>
+A
+<a href="/pkg/net/http/#Client"><code>Client</code></a>'s configured <code>CheckRedirect</code> function can now
+return <code>ErrUseLastResponse</code> to indicate that the
+most recent redirect response should be returned as the
+result of the HTTP request.
+That response is now available to the <code>CheckRedirect</code> function
+as <code>req.Response</code>.
+</p>
+
+<p>
+Since Go 1, the default behavior of the HTTP client is
+to request server-side compression
+using the <code>Accept-Encoding</code> request header
+and then to uncompress the response body transparently,
+and this behavior is adjustable using the
+<a href="/pkg/net/http/#Transport"><code>Transport</code></a>'s <code>DisableCompression</code> field.
+In Go 1.7, to aid the implementation of HTTP proxies, the
+<a href="/pkg/net/http/#Response"><code>Response</code></a>'s new
+<code>Uncompressed</code> field reports whether
+this transparent uncompression took place.
+</p>
+
+<p>
+<a href="/pkg/net/http/#DetectContentType"><code>DetectContentType</code></a>
+adds support for a few new audio and video content types.
+</p>
+</dd>
+
+<dl id="net/http/cgi"><a href="/pkg/net/http/cgi/">net/http/cgi</a></dl>
+
+<dd>
+<p>
+The
+<a href="/pkg/net/http/cgi/#Handler"><code>Handler</code></a>
+adds a new field
+<code>Stderr</code>
+that allows redirection of the child process's
+standard error away from the host process's
+standard error.
+</p>
+</dd>
+
+<dl id="net/http/httptest"><a href="/pkg/net/http/httptest/">net/http/httptest</a></dl>
+
+<dd>
+<p>
+The new function
+<a href="/pkg/net/http/httptest/#NewRequest"><code>NewRequest</code></a>
+prepares a new
+<a href="/pkg/net/http/#Request"><code>http.Request</code></a>
+suitable for passing to an
+<a href="/pkg/net/http/#Handler"><code>http.Handler</code></a> during a test.
+</p>
+
+<p>
+The
+<a href="/pkg/net/http/httptest/#ResponseRecorder"><code>ResponseRecorder</code></a>'s new
+<a href="/pkg/net/http/httptest/#ResponseRecorder.Result"><code>Result</code></a> method
+returns the recorded
+<a href="/pkg/net/http/#Response"><code>http.Response</code></a>.
+Tests that need to check the response's headers or trailers
+should call <code>Result</code> and inspect the response fields
+instead of accessing
+<code>ResponseRecorder</code>'s <code>HeaderMap</code> directly.
+</p>
+</dd>
+
+<dl id="net/http/httputil"><a href="/pkg/net/http/httputil/">net/http/httputil</a></dl>
+
+<dd>
+<p>
+The
+<a href="/pkg/net/http/httputil/#ReverseProxy"><code>ReverseProxy</code></a> implementation now responds with “502 Bad Gateway”
+when it cannot reach a back end; in earlier releases it responded with “500 Internal Server Error.”
+</p>
+
+<p>
+Both
+<a href="/pkg/net/http/httputil/#ClientConn"><code>ClientConn</code></a> and
+<a href="/pkg/net/http/httputil/#ServerConn"><code>ServerConn</code></a> have been documented as deprecated.
+They are low-level, old, and unused by Go's current HTTP stack
+and will no longer be updated.
+Programs should use
+<a href="/pkg/net/http/#Client"><code>http.Client</code></a>,
+<a href="/pkg/net/http/#Transport"><code>http.Transport</code></a>,
+and
+<a href="/pkg/net/http/#Server"><code>http.Server</code></a>
+instead.
+</p>
+</dd>
+
+<dl id="net/http/pprof"><a href="/pkg/net/http/pprof/">net/http/pprof</a></dl>
+
+<dd>
+<p>
+The runtime trace HTTP handler, installed to handle the path <code>/debug/pprof/trace</code>,
+now accepts a fractional number in its <code>seconds</code> query parameter,
+allowing collection of traces for intervals smaller than one second.
+This is especially useful on busy servers.
+</p>
+</dd>
+
+<dl><a href="/pkg/net/mail/">net/mail</a></dl>
+
+<dd>
+<p>
+The address parser now allows unescaped UTF-8 text in addresses
+following <a href="https://tools.ietf.org/html/rfc6532">RFC 6532</a>,
+but it does not apply any normalization to the result.
+For compatibility with older mail parsers,
+the address encoder, namely
+<a href="/pkg/net/mail/#Address"><code>Address</code></a>'s
+<a href="/pkg/net/mail/#Address.String"><code>String</code></a> method,
+continues to escape all UTF-8 text following <a href="https://tools.ietf.org/html/rfc5322">RFC 5322</a>,
+</p>
+</dd>
+
+<dl id="net/url"><a href="/pkg/net/url/">net/url</a></dl>
+
+<dd>
+<p>
+The
+<a href="/pkg/net/url/#URL"><code>URL</code></a>'s
+new <code>ForceQuery</code> field
+records whether the URL must have a query string,
+in order to distinguish URLs without query strings (like <code>/search</code>)
+from URLs with empty query strings (like <code>/search?</code>).
+</p>
+</dd>
+
+<dl id="os"><a href="/pkg/os/">os</a></dl>
+
+<dd>
+<p>
+The
+<a href="/pkg/os/#File"><code>File</code></a>
+type adds a new
+<a href="/pkg/os/#File.Size"><code>Size</code></a>
+method, so that <code>File</code> implements the new
+<a href="/pkg/io/#SizedReaderAt"><code>SizedReaderAt</code></a> method.
+</p>
+
+<p>
+<a href="/pkg/os/#IsExists"><code>IsExists</code></a> now returns true for <code>syscall.ENOTEMPTY</code>,
+on systems where that error exists.
+</p>
+
+<p>
+On Windows,
+<a href="/pkg/os/#Remove"><code>Remove</code></a> now removes read-only files when possible,
+making the implementation behave as on
+non-Windows systems.
+</p>
+</dd>
+
+<dl id="os/exec"><a href="/pkg/os/exec/">os/exec</a></dl>
+
+<dd>
+<p>
+As part of the introduction of <a href="#context">context</a>,
+the new constructor
+<a href="/pkg/os/exec/#CommandContext"><code>CommandContext</code></a>
+is like
+<a href="/pkg/os/exec/#Command"><code>Command</code></a> but includes a context that can be used to cancel the command execution.
+</p>
+</dd>
+
+<dl id="os/user"><a href="/pkg/os/user/">os/user</a></dl>
+
+<dd>
+<p>
+The
+<a href="/pkg/os/user/#Current"><code>Current</code></a>
+function is now implemented even when cgo is not available.
+</p>
+
+<p>
+The new
+<a href="/pkg/os/user/#Group"><code>Group</code></a> type,
+along with the lookup functions
+<a href="/pkg/os/user/#LookupGroup"><code>LookupGroup</code></a> and
+<a href="/pkg/os/user/#LookupGroupId"><code>LookupGroupId</code></a>
+and the new field <code>GroupIds</code> in the <code>User</code> struct,
+provides access to system-specific user group information.
+</p>
+</dd>
+
+<dl id="reflect"><a href="/pkg/reflect/">reflect</a></dl>
+
+<dd>
+<p>
+Although
+<a href="/pkg/reflect/#Value"><code>Value</code></a>'s
+<a href="/pkg/reflect/#Value.Field"><code>Field</code></a> method has always been documented to panic
+if the given field number <code>i</code> is out of range, it has instead
+silently returned a zero
+<a href="/pkg/reflect/#Value"><code>Value</code></a>.
+Go 1.7 changes the method to behave as documented.
+</p>
+
+<p>
+The new
+<a href="/pkg/reflect/#StructOf"><code>StructOf</code></a>
+function constructs a struct type at run time.
+It completes the set of type constructors, joining
+<a href="/pkg/reflect/#ArrayOf"><code>ArrayOf</code></a>,
+<a href="/pkg/reflect/#ChanOf"><code>ChanOf</code></a>,
+<a href="/pkg/reflect/#FuncOf"><code>FuncOf</code></a>,
+<a href="/pkg/reflect/#MapOf"><code>MapOf</code></a>,
+<a href="/pkg/reflect/#PtrTo"><code>PtrTo</code></a>,
+and
+<a href="/pkg/reflect/#SliceOf"><code>SliceOf</code></a>.
+</p>
+
+<p>
+<a href="/pkg/reflect/#StructTag"><code>StructTag</code></a>'s
+new method
+<a href="/pkg/reflect/#StructTag.Lookup"><code>Lookup</code></a>
+is like
+<a href="/pkg/reflect/#StructTag.Get"><code>Get</code></a>
+but distinguishes the tag not containing the given key
+from the tag associating an empty string with the given key.
+</p>
+
+<p>
+The
+<a href="/pkg/reflect/#Type.Method"><code>Method</code></a> and
+<a href="/pkg/reflect/#Type.NumMethod"><code>NumMethod</code></a>
+methods of
+<a href="/pkg/reflect/#Type"><code>Type</code></a> and
+<a href="/pkg/reflect/#Value"><code>Value</code></a>
+no longer return or count unexported methods.
+</p>
+</dd>
+
+<dl id="strings"><a href="/pkg/strings/">strings</a></dl>
+
+<dd>
+<p>
+In previous releases of Go, if
+<a href="/pkg/strings/#Reader"><code>Reader</code></a>'s
+<a href="/pkg/strings/#Reader.Read"><code>Read</code></a> method
+were asked for zero bytes with no data remaining, it would
+return a count of 0 and no error.
+Now it returns a count of 0 and the error
+<a href="/pkg/io/#EOF"><code>io.EOF</code></a> .
+</p>
+
+<p>
+The
+<a href="/pkg/strings/#Reader"><code>Reader</code></a> type has a new method
+<a href="/pkg/strings/#Reader.Reset"><code>Reset</code></a> to allow reuse of a <code>Reader</code>.
+</p>
+</dd>
+
+<dl id="time"><a href="/pkg/time/">time</a></dl>
+
+<dd>
+<p>
+<a href="/pkg/time/#Duration"><code>Duration</code></a>'s
+time.Duration.String method now reports the zero duration as <code>"0s"</code>, not <code>"0"</code>.
+<a href="/pkg/time/#ParseDuration"><code>ParseDuration</code></a> continues to accept both forms.
+</p>
+
+<p>
+The method call <code>time.Local.String()</code> now returns <code>"Local"</code> on all systems;
+in earlier releases, it returned an empty string on Windows.
+</p>
+
+<p>
+The time zone database in
+<code>$GOROOT/lib/time</code> has been updated
+to IANA release 2016d.
+This fallback database is only used when the system time zone database
+cannot be found, for example on Windows.
+The Windows time zone abbreviation list has also been updated.
+</p>
+</dd>
+
+<dl id="syscall"><a href="/pkg/syscall/">syscall</a></dl>
+
+<dd>
+<p>
+On Linux, the
+<a href="/pkg/syscall/#SysProcAttr"><code>SysProcAttr</code></a> struct
+(as used in
+<a href="/pkg/os/exec/#Cmd"><code>os/exec.Cmd</code></a>'s <code>SysProcAttr</code> field)
+has a new <code>Unshare</code> field.
+If the field is nonzero, the child process created by
+<a href="/pkg/syscall/#ForkExec"><code>ForkExec</code></a>
+(as used in <code>exec.Cmd</code>'s <code>Run</code> method)
+will call the
+<a href="http://man7.org/linux/man-pages/man2/unshare.2.html"><i>unshare</i>(2)</a>
+system call before executing the new program.
+</p>
+</dd>
+++ /dev/null
-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)
</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
architectures.
</p>
<code>arm64</code> (<code>AArch64</code>)
</dt>
<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>
<dt>
<code>ppc64, ppc64le</code> (64-bit PowerPC big- and little-endian)
</dt>
<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>
<dt>
<code>mips64, mips64le</code> (64-bit MIPS big- and little-endian)
</dt>
<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>
</dl>
<p>
Create a directory to contain your <a href="code.html#Workspaces">workspace</a>,
<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
variable to point to that location.
</p>
</pre>
<pre class="testWindows" style="display: none">
-C:\> <b>set GOPATH=%HOME%\work</b>
+C:\> <b>set GOPATH=C:\work</b>
</pre>
<p>
--- /dev/null
+// 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,
+ }
+}
},
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() {
check issue13423.go
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
exit 1
fi
}
if GOOS == "darwin" {
- cc = append(cc, "-Wl,-no_pie")
-
// For Darwin/ARM.
// TODO(crawshaw): can we do better?
cc = append(cc, []string{"-framework", "CoreFoundation", "-framework", "Foundation"}...)
}
libgodir = GOOS + "_" + GOARCH
- if GOOS == "darwin" && GOARCH == "arm" {
+ if GOOS == "darwin" && (GOARCH == "arm" || GOARCH == "arm64") {
libgodir = GOOS + "_" + GOARCH + "_shared"
}
cc = append(cc, "-I", filepath.Join("pkg", libgodir))
// Test raising SIGIO on a C thread with an alternate signal stack
// when there is a Go signal handler for SIGIO.
-static void* thread1(void* arg) {
- pthread_t* ptid = (pthread_t*)(arg);
+static void* thread1(void* arg __attribute__ ((unused))) {
stack_t ss;
int i;
stack_t nss;
// Send ourselves a SIGIO. This will be caught by the Go
// signal handler which should forward to the C signal
// handler.
- i = pthread_kill(*ptid, SIGIO);
+ i = pthread_kill(pthread_self(), SIGIO);
if (i != 0) {
fprintf(stderr, "pthread_kill: %s\n", strerror(i));
exit(EXIT_FAILURE);
// 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.
-static void* thread2(void* arg) {
- pthread_t* ptid = (pthread_t*)(arg);
+static void* thread2(void* arg __attribute__ ((unused))) {
stack_t ss;
int i;
int oldcount;
+ pthread_t tid;
stack_t nss;
// Set up an alternate signal stack for this thread.
// Call a Go function that will call a C function to send us a
// SIGIO.
- GoRaiseSIGIO(ptid);
+ tid = pthread_self();
+ GoRaiseSIGIO(&tid);
// Wait until the signal has been delivered.
i = 0;
// Tell the Go library to start looking for SIGIO.
GoCatchSIGIO();
- i = pthread_create(&tid, NULL, thread1, (void*)(&tid));
+ i = pthread_create(&tid, NULL, thread1, NULL);
if (i != 0) {
fprintf(stderr, "pthread_create: %s\n", strerror(i));
exit(EXIT_FAILURE);
exit(EXIT_FAILURE);
}
- i = pthread_create(&tid, NULL, thread2, (void*)(&tid));
+ i = pthread_create(&tid, NULL, thread2, NULL);
if (i != 0) {
fprintf(stderr, "pthread_create: %s\n", strerror(i));
exit(EXIT_FAILURE);
status=1
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
fi
--- /dev/null
+// 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
+ }
+}
--- /dev/null
+// 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()
+}
internal
objfile
objfile.go
- unvendor
- golang.org
- x
- arch
- arm
- armasm
- testdata
- +
- x86
- x86asm
- testdata
- +
gofmt
gofmt.go
gofmt_test.go
testdata
+
+ vendor
+ golang.org
+ x
+ arch
+ arm
+ armasm
+ testdata
+ +
+ x86
+ x86asm
+ testdata
+ +
archive
tar
testdata
"time"
)
+// Header type flags.
const (
- blockSize = 512
-
- // Types
TypeReg = '0' // regular file
TypeRegA = '\x00' // regular file
TypeLink = '1' // hard link
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.
func (h *Header) FileInfo() os.FileInfo {
return headerFileInfo{h}
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 {
for _, c := range s {
if c >= 0x80 {
--- /dev/null
+// 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] }
// 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.
type Reader struct {
- r io.Reader
- err error
- pad int64 // amount of padding (ignored) after current file entry
- curr numBytesReader // reader for current file entry
- hdrBuff [blockSize]byte // buffer to use in readHeader
+ r io.Reader
+ err error
+ pad int64 // amount of padding (ignored) after current file entry
+ curr numBytesReader // reader for current file entry
+ blk block // buffer to use as temporary local storage
}
type parser struct {
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.
func NewReader(r io.Reader) *Reader { return &Reader{r: r} }
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
// is already aligned to a block boundary.
//
// * Exactly 1 block of zeros is read and EOF is hit.
// * At least 2 blocks of zeros are read.
func (tr *Reader) readHeader() *Header {
- header := tr.hdrBuff[:]
- copy(header, 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
}
// Two blocks of zero bytes marks the end of the archive.
- if bytes.Equal(header, zeroBlock[0:blockSize]) {
- if _, tr.err = io.ReadFull(tr.r, header); tr.err != nil {
+ if bytes.Equal(tr.blk[:], zeroBlock[:]) {
+ if _, tr.err = io.ReadFull(tr.r, tr.blk[:]); tr.err != nil {
return nil // io.EOF is okay here
}
- if bytes.Equal(header, zeroBlock[0:blockSize]) {
+ if bytes.Equal(tr.blk[:], zeroBlock[:]) {
tr.err = io.EOF
} else {
tr.err = ErrHeader // zero block and then non-zero block
return nil
}
- if !tr.verifyChecksum(header) {
+ // Verify the header matches a known format.
+ format := tr.blk.GetFormat()
+ if format == formatUnknown {
tr.err = ErrHeader
return nil
}
- // Unpack
var p parser
hdr := new(Header)
- s := slicer(header)
-
- hdr.Name = p.parseString(s.next(100))
- hdr.Mode = p.parseNumeric(s.next(8))
- hdr.Uid = int(p.parseNumeric(s.next(8)))
- hdr.Gid = int(p.parseNumeric(s.next(8)))
- hdr.Size = p.parseNumeric(s.next(12))
- hdr.ModTime = time.Unix(p.parseNumeric(s.next(12)), 0)
- s.next(8) // chksum
- hdr.Typeflag = s.next(1)[0]
- hdr.Linkname = p.parseString(s.next(100))
-
- // The remainder of the header depends on the value of magic.
- // The original (v7) version of tar had no explicit magic field,
- // so its magic bytes, like the rest of the block, are NULs.
- magic := string(s.next(8)) // contains version field as well.
- var format string
- 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)
+ // Unpack the V7 header.
+ v7 := tr.blk.V7()
+ hdr.Name = p.parseString(v7.Name())
+ hdr.Mode = p.parseNumeric(v7.Mode())
+ hdr.Uid = int(p.parseNumeric(v7.UID()))
+ hdr.Gid = int(p.parseNumeric(v7.GID()))
+ hdr.Size = p.parseNumeric(v7.Size())
+ hdr.ModTime = time.Unix(p.parseNumeric(v7.ModTime()), 0)
+ hdr.Typeflag = v7.TypeFlag()[0]
+ hdr.Linkname = p.parseString(v7.LinkName())
+
+ // Unpack format specific fields.
+ if format > formatV7 {
+ ustar := tr.blk.USTAR()
+ hdr.Uname = p.parseString(ustar.UserName())
+ hdr.Gname = p.parseString(ustar.GroupName())
if hdr.Typeflag == TypeChar || hdr.Typeflag == TypeBlock {
- hdr.Devmajor = p.parseNumeric(devmajor)
- hdr.Devminor = p.parseNumeric(devminor)
+ hdr.Devmajor = p.parseNumeric(ustar.DevMajor())
+ hdr.Devminor = p.parseNumeric(ustar.DevMinor())
}
+
var prefix string
switch format {
- case "posix", "gnu":
- prefix = p.parseString(s.next(155))
- case "star":
- prefix = p.parseString(s.next(131))
- hdr.AccessTime = time.Unix(p.parseNumeric(s.next(12)), 0)
- hdr.ChangeTime = time.Unix(p.parseNumeric(s.next(12)), 0)
+ case formatUSTAR, formatGNU:
+ // TODO(dsnet): Do not use the prefix field for the GNU format!
+ // See golang.org/issues/12594
+ ustar := tr.blk.USTAR()
+ prefix = p.parseString(ustar.Prefix())
+ 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 {
hdr.Name = prefix + "/" + hdr.Name
}
}
- if p.err != nil {
- tr.err = p.err
- return nil
- }
-
nb := hdr.Size
if isHeaderOnlyType(hdr.Typeflag) {
nb = 0
// Check for old GNU sparse format entry.
if hdr.Typeflag == TypeGNUSparse {
// 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 {
tr.err = p.err
return nil
}
// Read the sparse map.
- sp := tr.readOldGNUSparseMap(header)
+ sp := tr.readOldGNUSparseMap(&tr.blk)
if tr.err != nil {
return nil
}
}
}
+ if p.err != nil {
+ tr.err = p.err
+ return nil
+ }
+
return hdr
}
// 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,
// 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
- isExtended := header[oldGNUSparseMainHeaderIsExtendedOffset] != 0
- spCap := oldGNUSparseMainHeaderNumEntries
- if isExtended {
- spCap += oldGNUSparseExtendedHeaderNumEntries
- }
- 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))
+ var s sparseArray = blk.GNU().Sparse()
+ var sp = make([]sparseEntry, 0, s.MaxEntries())
+ for i := 0; i < s.MaxEntries(); i++ {
+ offset := p.parseOctal(s.Entry(i).Offset())
+ numBytes := p.parseOctal(s.Entry(i).NumBytes())
if p.err != nil {
tr.err = p.err
return nil
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.
- sparseHeader := make([]byte, blockSize)
- if _, tr.err = io.ReadFull(tr.r, sparseHeader); tr.err != nil {
+ var blk block
+ if _, tr.err = io.ReadFull(tr.r, blk[:]); tr.err != nil {
return nil
}
- isExtended = sparseHeader[oldGNUSparseExtendedHeaderIsExtendedOffset] != 0
- s = slicer(sparseHeader)
- for i := 0; i < oldGNUSparseExtendedHeaderNumEntries; i++ {
- offset := p.parseNumeric(s.next(oldGNUSparseOffsetSize))
- numBytes := p.parseNumeric(s.next(oldGNUSparseNumBytesSize))
+ s = blk.Sparse()
+
+ for i := 0; i < s.MaxEntries(); i++ {
+ offset := p.parseOctal(s.Entry(i).Offset())
+ numBytes := p.parseOctal(s.Entry(i).NumBytes())
if p.err != nil {
tr.err = p.err
return nil
nb int64 // number of unwritten bytes for current file entry
pad int64 // amount of padding to write after current file entry
closed bool
- usedBinary bool // whether the binary numeric field extension was used
- preferPax bool // use pax header instead of binary numeric header
- hdrBuff [blockSize]byte // buffer to use in writeHeader when writing a regular header
- paxHdrBuff [blockSize]byte // buffer to use in writeHeader when writing a pax header
+ usedBinary bool // whether the binary numeric field extension was used
+ preferPax bool // use PAX header instead of binary numeric header
+ hdrBuff block // buffer to use in writeHeader when writing a regular header
+ paxHdrBuff block // buffer to use in writeHeader when writing a PAX header
}
type formatter struct {
// a map to hold pax header records, if any are needed
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
// too long fields or non ascii characters
- var f formatter
- var header []byte
-
// We need to select which scratch buffer to use carefully,
// 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 false, we are being called by writePAXHeader, and hdrBuff is
// already being used by the non-recursive call, so we must use paxHdrBuff.
- header = tw.hdrBuff[:]
+ header := &tw.hdrBuff
if !allowPax {
- header = tw.paxHdrBuff[:]
+ header = &tw.paxHdrBuff
}
- copy(header, zeroBlock)
- s := slicer(header)
+ copy(header[:], zeroBlock[:])
// Wrappers around formatter that automatically sets paxHeaders if the
// argument extends beyond the capacity of the input byte slice.
+ var f formatter
var formatString = func(b []byte, s string, paxKeyword string) {
needsPaxHeader := paxKeyword != paxNone && len(s) > len(b) || !isASCII(s)
if needsPaxHeader {
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.
var modTime int64
if !hdr.ModTime.Before(minTime) && !hdr.ModTime.After(maxTime) {
modTime = hdr.ModTime.Unix()
}
- f.formatOctal(s.next(8), hdr.Mode) // 100:108
- formatNumeric(s.next(8), int64(hdr.Uid), paxUid) // 108:116
- formatNumeric(s.next(8), int64(hdr.Gid), paxGid) // 116:124
- formatNumeric(s.next(12), hdr.Size, paxSize) // 124:136
- formatNumeric(s.next(12), modTime, paxNone) // 136:148 --- consider using pax for finer granularity
- s.next(8) // chksum (148:156)
- s.next(1)[0] = hdr.Typeflag // 156:157
-
- formatString(s.next(100), hdr.Linkname, paxLinkpath)
-
- 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
+ v7 := header.V7()
+ formatString(v7.Name(), hdr.Name, paxPath)
+ // TODO(dsnet): The GNU format permits the mode field to be encoded in
+ // base-256 format. Thus, we can use formatNumeric instead of formatOctal.
+ f.formatOctal(v7.Mode(), hdr.Mode)
+ formatNumeric(v7.UID(), int64(hdr.Uid), paxUid)
+ 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)
+
+ 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)
- // 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
+ _, paxPathUsed := paxHeaders[paxPath]
if !tw.preferPax && len(paxHeaders) == 1 && paxPathUsed {
prefix, suffix, ok := splitUSTARPath(hdr.Name)
if ok {
delete(paxHeaders, paxPath)
// Update the path fields
- formatString(pathHeaderBytes, suffix, paxNone)
- formatString(prefixHeaderBytes, prefix, paxNone)
+ formatString(v7.Name(), suffix, paxNone)
+ formatString(ustar.Prefix(), prefix, paxNone)
}
}
- // The chksum field is terminated by a NUL and a space.
- // This is different from the other octal fields.
- chksum, _ := checksum(header)
- f.formatOctal(header[148:155], chksum) // Never fails
- header[155] = ' '
+ if tw.usedBinary {
+ header.SetFormat(formatGNU)
+ } else {
+ header.SetFormat(formatUSTAR)
+ }
// Check if there were any formatting errors.
if f.err != nil {
tw.nb = hdr.Size
tw.pad = (blockSize - (tw.nb % blockSize)) % blockSize
- _, tw.err = tw.w.Write(header)
+ _, tw.err = tw.w.Write(header[:])
return tw.err
}
// If the path is not splittable, then it will return ("", "", false).
func splitUSTARPath(name string) (prefix, suffix string, ok bool) {
length := len(name)
- if length <= fileNameSize || !isASCII(name) {
+ if length <= nameSize || !isASCII(name) {
return "", "", false
- } else if length > fileNamePrefixSize+1 {
- length = fileNamePrefixSize + 1
+ } else if length > prefixSize+1 {
+ length = prefixSize + 1
} else if name[length-1] == '/' {
length--
}
i := strings.LastIndex(name[:length], "/")
nlen := len(name) - i - 1 // nlen is length of suffix
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 name[:i], name[i+1:], true
fullName := path.Join(dir, "PaxHeaders.0", file)
ascii := toASCII(fullName)
- if len(ascii) > 100 {
- ascii = ascii[:100]
+ if len(ascii) > nameSize {
+ ascii = ascii[:nameSize]
}
ext.Name = ascii
// Construct the body
// trailer: two zero blocks
for i := 0; i < 2; i++ {
- _, tw.err = tw.w.Write(zeroBlock)
+ _, tw.err = tw.w.Write(zeroBlock[:])
if tw.err != nil {
break
}
{"", "", "", false},
{"abc", "", "", false},
{"用戶名", "", "", false},
- {sr("a", fileNameSize), "", "", false},
- {sr("a", fileNameSize) + "/", "", "", false},
- {sr("a", fileNameSize) + "/a", sr("a", fileNameSize), "a", true},
- {sr("a", fileNamePrefixSize) + "/", "", "", false},
- {sr("a", fileNamePrefixSize) + "/a", sr("a", fileNamePrefixSize), "a", true},
- {sr("a", fileNameSize+1), "", "", false},
- {sr("/", fileNameSize+1), sr("/", fileNameSize-1), "/", true},
- {sr("a", fileNamePrefixSize) + "/" + sr("b", fileNameSize),
- sr("a", fileNamePrefixSize), sr("b", fileNameSize), true},
- {sr("a", fileNamePrefixSize) + "//" + sr("b", fileNameSize), "", "", false},
- {sr("a/", fileNameSize), sr("a/", 77) + "a", sr("a/", 22), true},
+ {sr("a", nameSize), "", "", false},
+ {sr("a", nameSize) + "/", "", "", false},
+ {sr("a", nameSize) + "/a", sr("a", nameSize), "a", true},
+ {sr("a", prefixSize) + "/", "", "", false},
+ {sr("a", prefixSize) + "/a", sr("a", prefixSize), "a", true},
+ {sr("a", nameSize+1), "", "", false},
+ {sr("/", nameSize+1), sr("/", nameSize-1), "/", true},
+ {sr("a", prefixSize) + "/" + sr("b", nameSize),
+ sr("a", prefixSize), sr("b", nameSize), true},
+ {sr("a", prefixSize) + "//" + sr("b", nameSize), "", "", false},
+ {sr("a/", nameSize), sr("a/", 77) + "a", sr("a/", 22), true},
}
for _, v := range vectors {
/*
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.
b.Fatal("ioutil.Discard doesn't support ReaderFrom")
}
for i := 0; i < b.N; i++ {
- r.Seek(0, 0)
+ r.Seek(0, io.SeekStart)
srcReader.Reset(onlyReader{r})
n, err := srcReader.WriteTo(ioutil.Discard)
if err != nil {
r.prevRune = -1
var abs int64
switch whence {
- case 0:
+ case io.SeekStart:
abs = offset
- case 1:
+ case io.SeekCurrent:
abs = r.i + offset
- case 2:
+ case io.SeekEnd:
abs = int64(len(r.s)) + offset
default:
return 0, errors.New("bytes.Reader.Seek: invalid whence")
{"Read", func(r *Reader) { r.Read([]byte{0}) }},
{"ReadByte", func(r *Reader) { r.ReadByte() }},
{"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{}) }},
}
--- /dev/null
+// 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
+}
prog.From = a[0]
prog.Reg = p.getRegister(prog, op, &a[1])
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:
// ARM64 instructions with one input and two outputs.
if arch.IsARM64STLXR(op) {
prog.From = a[0]
prog.Reg = p.getRegister(prog, op, &a[1])
prog.To = a[2]
- case sys.AMD64, sys.I386:
+ case sys.I386:
prog.From = a[0]
prog.From3 = newAddr(a[1])
prog.To = a[2]
prog.Reg = r1
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 {
prog.From = a[0]
prog.Reg = p.getRegister(prog, op, &a[1])
RORB $7, (R11) // 41c00b07
RORB $7, DL // c0ca07
RORB $7, R11 // 41c0cb07
- //TODO: RORXL $7, (BX), DX // c4e37bf01307
- //TODO: RORXL $7, (R11), DX // c4c37bf01307
- //TODO: RORXL $7, DX, DX // c4e37bf0d207
- //TODO: RORXL $7, R11, DX // c4c37bf0d307
- //TODO: RORXL $7, (BX), R11 // c4637bf01b07
- //TODO: RORXL $7, (R11), R11 // c4437bf01b07
- //TODO: RORXL $7, DX, R11 // c4637bf0da07
- //TODO: RORXL $7, R11, R11 // c4437bf0db07
- //TODO: RORXQ $7, (BX), DX // c4e3fbf01307
- //TODO: RORXQ $7, (R11), DX // c4c3fbf01307
- //TODO: RORXQ $7, DX, DX // c4e3fbf0d207
- //TODO: RORXQ $7, R11, DX // c4c3fbf0d307
- //TODO: RORXQ $7, (BX), R11 // c463fbf01b07
- //TODO: RORXQ $7, (R11), R11 // c443fbf01b07
- //TODO: RORXQ $7, DX, R11 // c463fbf0da07
- //TODO: RORXQ $7, R11, R11 // c443fbf0db07
+ RORXL $7, (BX), DX // c4e37bf01307
+ RORXL $7, (R11), DX // c4c37bf01307
+ RORXL $7, DX, DX // c4e37bf0d207
+ RORXL $7, R11, DX // c4c37bf0d307
+ RORXL $7, (BX), R11 // c4637bf01b07
+ RORXL $7, (R11), R11 // c4437bf01b07
+ RORXL $7, DX, R11 // c4637bf0da07
+ RORXL $7, R11, R11 // c4437bf0db07
+ RORXQ $7, (BX), DX // c4e3fbf01307
+ RORXQ $7, (R11), DX // c4c3fbf01307
+ RORXQ $7, DX, DX // c4e3fbf0d207
+ RORXQ $7, R11, DX // c4c3fbf0d307
+ RORXQ $7, (BX), R11 // c463fbf01b07
+ RORXQ $7, (R11), R11 // c443fbf01b07
+ RORXQ $7, DX, R11 // c463fbf0da07
+ RORXQ $7, R11, R11 // c443fbf0db07
ROUNDPD $7, (BX), X2 // 660f3a091307
ROUNDPD $7, (R11), X2 // 66410f3a091307
ROUNDPD $7, X2, X2 // 660f3a09d207
//TODO: VINSERTF128 $7, (R11), Y15, Y11 // c44305181b07
//TODO: VINSERTF128 $7, X2, Y15, Y11 // c4630518da07
//TODO: VINSERTF128 $7, X11, Y15, Y11 // c4430518db07
- //TODO: VINSERTI128 $7, (BX), Y15, Y2 // c4e305381307
- //TODO: VINSERTI128 $7, (R11), Y15, Y2 // c4c305381307
- //TODO: VINSERTI128 $7, X2, Y15, Y2 // c4e30538d207
- //TODO: VINSERTI128 $7, X11, Y15, Y2 // c4c30538d307
- //TODO: VINSERTI128 $7, (BX), Y15, Y11 // c46305381b07
- //TODO: VINSERTI128 $7, (R11), Y15, Y11 // c44305381b07
- //TODO: VINSERTI128 $7, X2, Y15, Y11 // c4630538da07
- //TODO: VINSERTI128 $7, X11, Y15, Y11 // c4430538db07
+ VINSERTI128 $7, (BX), Y15, Y2 // c4e305381307
+ VINSERTI128 $7, (R11), Y15, Y2 // c4c305381307
+ VINSERTI128 $7, X2, Y15, Y2 // c4e30538d207
+ VINSERTI128 $7, X11, Y15, Y2 // c4c30538d307
+ VINSERTI128 $7, (BX), Y15, Y11 // c46305381b07
+ VINSERTI128 $7, (R11), Y15, Y11 // c44305381b07
+ VINSERTI128 $7, X2, Y15, Y11 // c4630538da07
+ VINSERTI128 $7, X11, Y15, Y11 // c4430538db07
//TODO: VINSERTPS $7, (BX), X9, X2 // c4e331211307
//TODO: VINSERTPS $7, (R11), X9, X2 // c4c331211307
//TODO: VINSERTPS $7, X2, X9, X2 // c4e33121d207
//TODO: VPADDB (R11), Y15, Y11 // c44105fc1b
//TODO: VPADDB Y2, Y15, Y11 // c46105fcda or c505fcda
//TODO: VPADDB Y11, Y15, Y11 // c44105fcdb
- //TODO: VPADDD (BX), X9, X2 // c4e131fe13 or c5b1fe13
- //TODO: VPADDD (R11), X9, X2 // c4c131fe13
- //TODO: VPADDD X2, X9, X2 // c4e131fed2 or c5b1fed2
- //TODO: VPADDD X11, X9, X2 // c4c131fed3
- //TODO: VPADDD (BX), X9, X11 // c46131fe1b or c531fe1b
- //TODO: VPADDD (R11), X9, X11 // c44131fe1b
- //TODO: VPADDD X2, X9, X11 // c46131feda or c531feda
- //TODO: VPADDD X11, X9, X11 // c44131fedb
- //TODO: VPADDD (BX), Y15, Y2 // c4e105fe13 or c585fe13
- //TODO: VPADDD (R11), Y15, Y2 // c4c105fe13
- //TODO: VPADDD Y2, Y15, Y2 // c4e105fed2 or c585fed2
- //TODO: VPADDD Y11, Y15, Y2 // c4c105fed3
- //TODO: VPADDD (BX), Y15, Y11 // c46105fe1b or c505fe1b
- //TODO: VPADDD (R11), Y15, Y11 // c44105fe1b
- //TODO: VPADDD Y2, Y15, Y11 // c46105feda or c505feda
- //TODO: VPADDD Y11, Y15, Y11 // c44105fedb
- //TODO: VPADDQ (BX), X9, X2 // c4e131d413 or c5b1d413
- //TODO: VPADDQ (R11), X9, X2 // c4c131d413
- //TODO: VPADDQ X2, X9, X2 // c4e131d4d2 or c5b1d4d2
- //TODO: VPADDQ X11, X9, X2 // c4c131d4d3
- //TODO: VPADDQ (BX), X9, X11 // c46131d41b or c531d41b
- //TODO: VPADDQ (R11), X9, X11 // c44131d41b
- //TODO: VPADDQ X2, X9, X11 // c46131d4da or c531d4da
- //TODO: VPADDQ X11, X9, X11 // c44131d4db
- //TODO: VPADDQ (BX), Y15, Y2 // c4e105d413 or c585d413
- //TODO: VPADDQ (R11), Y15, Y2 // c4c105d413
- //TODO: VPADDQ Y2, Y15, Y2 // c4e105d4d2 or c585d4d2
- //TODO: VPADDQ Y11, Y15, Y2 // c4c105d4d3
- //TODO: VPADDQ (BX), Y15, Y11 // c46105d41b or c505d41b
- //TODO: VPADDQ (R11), Y15, Y11 // c44105d41b
- //TODO: VPADDQ Y2, Y15, Y11 // c46105d4da or c505d4da
- //TODO: VPADDQ Y11, Y15, Y11 // c44105d4db
+ VPADDD (BX), X9, X2 // c4e131fe13 or c5b1fe13
+ VPADDD (R11), X9, X2 // c4c131fe13
+ VPADDD X2, X9, X2 // c4e131fed2 or c5b1fed2
+ VPADDD X11, X9, X2 // c4c131fed3
+ VPADDD (BX), X9, X11 // c46131fe1b or c531fe1b
+ VPADDD (R11), X9, X11 // c44131fe1b
+ VPADDD X2, X9, X11 // c46131feda or c531feda
+ VPADDD X11, X9, X11 // c44131fedb
+ VPADDD (BX), Y15, Y2 // c4e105fe13 or c585fe13
+ VPADDD (R11), Y15, Y2 // c4c105fe13
+ VPADDD Y2, Y15, Y2 // c4e105fed2 or c585fed2
+ VPADDD Y11, Y15, Y2 // c4c105fed3
+ VPADDD (BX), Y15, Y11 // c46105fe1b or c505fe1b
+ VPADDD (R11), Y15, Y11 // c44105fe1b
+ VPADDD Y2, Y15, Y11 // c46105feda or c505feda
+ VPADDD Y11, Y15, Y11 // c44105fedb
+ VPADDQ (BX), X9, X2 // c4e131d413 or c5b1d413
+ VPADDQ (R11), X9, X2 // c4c131d413
+ VPADDQ X2, X9, X2 // c4e131d4d2 or c5b1d4d2
+ VPADDQ X11, X9, X2 // c4c131d4d3
+ VPADDQ (BX), X9, X11 // c46131d41b or c531d41b
+ VPADDQ (R11), X9, X11 // c44131d41b
+ VPADDQ X2, X9, X11 // c46131d4da or c531d4da
+ VPADDQ X11, X9, X11 // c44131d4db
+ VPADDQ (BX), Y15, Y2 // c4e105d413 or c585d413
+ VPADDQ (R11), Y15, Y2 // c4c105d413
+ VPADDQ Y2, Y15, Y2 // c4e105d4d2 or c585d4d2
+ VPADDQ Y11, Y15, Y2 // c4c105d4d3
+ VPADDQ (BX), Y15, Y11 // c46105d41b or c505d41b
+ VPADDQ (R11), Y15, Y11 // c44105d41b
+ VPADDQ Y2, Y15, Y11 // c46105d4da or c505d4da
+ VPADDQ Y11, Y15, Y11 // c44105d4db
//TODO: VPADDSB (BX), X9, X2 // c4e131ec13 or c5b1ec13
//TODO: VPADDSB (R11), X9, X2 // c4c131ec13
//TODO: VPADDSB X2, X9, X2 // c4e131ecd2 or c5b1ecd2
//TODO: VPALIGNR $7, (R11), X9, X11 // c443310f1b07
//TODO: VPALIGNR $7, X2, X9, X11 // c463310fda07
//TODO: VPALIGNR $7, X11, X9, X11 // c443310fdb07
- //TODO: VPALIGNR $7, (BX), Y15, Y2 // c4e3050f1307
- //TODO: VPALIGNR $7, (R11), Y15, Y2 // c4c3050f1307
- //TODO: VPALIGNR $7, Y2, Y15, Y2 // c4e3050fd207
- //TODO: VPALIGNR $7, Y11, Y15, Y2 // c4c3050fd307
- //TODO: VPALIGNR $7, (BX), Y15, Y11 // c463050f1b07
- //TODO: VPALIGNR $7, (R11), Y15, Y11 // c443050f1b07
- //TODO: VPALIGNR $7, Y2, Y15, Y11 // c463050fda07
- //TODO: VPALIGNR $7, Y11, Y15, Y11 // c443050fdb07
+ VPALIGNR $7, (BX), Y15, Y2 // c4e3050f1307
+ VPALIGNR $7, (R11), Y15, Y2 // c4c3050f1307
+ VPALIGNR $7, Y2, Y15, Y2 // c4e3050fd207
+ VPALIGNR $7, Y11, Y15, Y2 // c4c3050fd307
+ VPALIGNR $7, (BX), Y15, Y11 // c463050f1b07
+ VPALIGNR $7, (R11), Y15, Y11 // c443050f1b07
+ VPALIGNR $7, Y2, Y15, Y11 // c463050fda07
+ VPALIGNR $7, Y11, Y15, Y11 // c443050fdb07
VPAND (BX), X9, X2 // c4e131db13 or c5b1db13
VPAND (R11), X9, X2 // c4c131db13
VPAND X2, X9, X2 // c4e131dbd2 or c5b1dbd2
//TODO: VPBLENDD $7, (R11), X9, X11 // c44331021b07
//TODO: VPBLENDD $7, X2, X9, X11 // c4633102da07
//TODO: VPBLENDD $7, X11, X9, X11 // c4433102db07
- //TODO: VPBLENDD $7, (BX), Y15, Y2 // c4e305021307
- //TODO: VPBLENDD $7, (R11), Y15, Y2 // c4c305021307
- //TODO: VPBLENDD $7, Y2, Y15, Y2 // c4e30502d207
- //TODO: VPBLENDD $7, Y11, Y15, Y2 // c4c30502d307
- //TODO: VPBLENDD $7, (BX), Y15, Y11 // c46305021b07
- //TODO: VPBLENDD $7, (R11), Y15, Y11 // c44305021b07
- //TODO: VPBLENDD $7, Y2, Y15, Y11 // c4630502da07
- //TODO: VPBLENDD $7, Y11, Y15, Y11 // c4430502db07
+ VPBLENDD $7, (BX), Y15, Y2 // c4e305021307
+ VPBLENDD $7, (R11), Y15, Y2 // c4c305021307
+ VPBLENDD $7, Y2, Y15, Y2 // c4e30502d207
+ VPBLENDD $7, Y11, Y15, Y2 // c4c30502d307
+ VPBLENDD $7, (BX), Y15, Y11 // c46305021b07
+ VPBLENDD $7, (R11), Y15, Y11 // c44305021b07
+ VPBLENDD $7, Y2, Y15, Y11 // c4630502da07
+ VPBLENDD $7, Y11, Y15, Y11 // c4430502db07
//TODO: VPBLENDVB XMM12, (BX), X9, X2 // c4e3314c13c0
//TODO: VPBLENDVB XMM12, (R11), X9, X2 // c4c3314c13c0
//TODO: VPBLENDVB XMM12, X2, X9, X2 // c4e3314cd2c0
//TODO: VPCMPISTRM $7, (R11), X11 // c44379621b07
//TODO: VPCMPISTRM $7, X2, X11 // c4637962da07
//TODO: VPCMPISTRM $7, X11, X11 // c4437962db07
- //TODO: VPERM2F128 $7, (BX), Y15, Y2 // c4e305061307
- //TODO: VPERM2F128 $7, (R11), Y15, Y2 // c4c305061307
- //TODO: VPERM2F128 $7, Y2, Y15, Y2 // c4e30506d207
- //TODO: VPERM2F128 $7, Y11, Y15, Y2 // c4c30506d307
- //TODO: VPERM2F128 $7, (BX), Y15, Y11 // c46305061b07
- //TODO: VPERM2F128 $7, (R11), Y15, Y11 // c44305061b07
- //TODO: VPERM2F128 $7, Y2, Y15, Y11 // c4630506da07
- //TODO: VPERM2F128 $7, Y11, Y15, Y11 // c4430506db07
- //TODO: VPERM2I128 $7, (BX), Y15, Y2 // c4e305461307
- //TODO: VPERM2I128 $7, (R11), Y15, Y2 // c4c305461307
- //TODO: VPERM2I128 $7, Y2, Y15, Y2 // c4e30546d207
- //TODO: VPERM2I128 $7, Y11, Y15, Y2 // c4c30546d307
- //TODO: VPERM2I128 $7, (BX), Y15, Y11 // c46305461b07
- //TODO: VPERM2I128 $7, (R11), Y15, Y11 // c44305461b07
- //TODO: VPERM2I128 $7, Y2, Y15, Y11 // c4630546da07
- //TODO: VPERM2I128 $7, Y11, Y15, Y11 // c4430546db07
+ VPERM2F128 $7, (BX), Y15, Y2 // c4e305061307
+ VPERM2F128 $7, (R11), Y15, Y2 // c4c305061307
+ VPERM2F128 $7, Y2, Y15, Y2 // c4e30506d207
+ VPERM2F128 $7, Y11, Y15, Y2 // c4c30506d307
+ VPERM2F128 $7, (BX), Y15, Y11 // c46305061b07
+ VPERM2F128 $7, (R11), Y15, Y11 // c44305061b07
+ VPERM2F128 $7, Y2, Y15, Y11 // c4630506da07
+ VPERM2F128 $7, Y11, Y15, Y11 // c4430506db07
+ VPERM2I128 $7, (BX), Y15, Y2 // c4e305461307
+ VPERM2I128 $7, (R11), Y15, Y2 // c4c305461307
+ VPERM2I128 $7, Y2, Y15, Y2 // c4e30546d207
+ VPERM2I128 $7, Y11, Y15, Y2 // c4c30546d307
+ VPERM2I128 $7, (BX), Y15, Y11 // c46305461b07
+ VPERM2I128 $7, (R11), Y15, Y11 // c44305461b07
+ VPERM2I128 $7, Y2, Y15, Y11 // c4630546da07
+ VPERM2I128 $7, Y11, Y15, Y11 // c4430546db07
//TODO: VPERMD (BX), Y15, Y2 // c4e2053613
//TODO: VPERMD (R11), Y15, Y2 // c4c2053613
//TODO: VPERMD Y2, Y15, Y2 // c4e20536d2
//TODO: VPMULUDQ (R11), Y15, Y11 // c44105f41b
//TODO: VPMULUDQ Y2, Y15, Y11 // c46105f4da or c505f4da
//TODO: VPMULUDQ Y11, Y15, Y11 // c44105f4db
- //TODO: VPOR (BX), X9, X2 // c4e131eb13 or c5b1eb13
- //TODO: VPOR (R11), X9, X2 // c4c131eb13
- //TODO: VPOR X2, X9, X2 // c4e131ebd2 or c5b1ebd2
- //TODO: VPOR X11, X9, X2 // c4c131ebd3
- //TODO: VPOR (BX), X9, X11 // c46131eb1b or c531eb1b
- //TODO: VPOR (R11), X9, X11 // c44131eb1b
- //TODO: VPOR X2, X9, X11 // c46131ebda or c531ebda
- //TODO: VPOR X11, X9, X11 // c44131ebdb
- //TODO: VPOR (BX), Y15, Y2 // c4e105eb13 or c585eb13
- //TODO: VPOR (R11), Y15, Y2 // c4c105eb13
- //TODO: VPOR Y2, Y15, Y2 // c4e105ebd2 or c585ebd2
- //TODO: VPOR Y11, Y15, Y2 // c4c105ebd3
- //TODO: VPOR (BX), Y15, Y11 // c46105eb1b or c505eb1b
- //TODO: VPOR (R11), Y15, Y11 // c44105eb1b
- //TODO: VPOR Y2, Y15, Y11 // c46105ebda or c505ebda
- //TODO: VPOR Y11, Y15, Y11 // c44105ebdb
+ VPOR (BX), X9, X2 // c4e131eb13 or c5b1eb13
+ VPOR (R11), X9, X2 // c4c131eb13
+ VPOR X2, X9, X2 // c4e131ebd2 or c5b1ebd2
+ VPOR X11, X9, X2 // c4c131ebd3
+ VPOR (BX), X9, X11 // c46131eb1b or c531eb1b
+ VPOR (R11), X9, X11 // c44131eb1b
+ VPOR X2, X9, X11 // c46131ebda or c531ebda
+ VPOR X11, X9, X11 // c44131ebdb
+ VPOR (BX), Y15, Y2 // c4e105eb13 or c585eb13
+ VPOR (R11), Y15, Y2 // c4c105eb13
+ VPOR Y2, Y15, Y2 // c4e105ebd2 or c585ebd2
+ VPOR Y11, Y15, Y2 // c4c105ebd3
+ VPOR (BX), Y15, Y11 // c46105eb1b or c505eb1b
+ VPOR (R11), Y15, Y11 // c44105eb1b
+ VPOR Y2, Y15, Y11 // c46105ebda or c505ebda
+ VPOR Y11, Y15, Y11 // c44105ebdb
//TODO: VPSADBW (BX), X9, X2 // c4e131f613 or c5b1f613
//TODO: VPSADBW (R11), X9, X2 // c4c131f613
//TODO: VPSADBW X2, X9, X2 // c4e131f6d2 or c5b1f6d2
//TODO: VPSADBW (R11), Y15, Y11 // c44105f61b
//TODO: VPSADBW Y2, Y15, Y11 // c46105f6da or c505f6da
//TODO: VPSADBW Y11, Y15, Y11 // c44105f6db
- //TODO: VPSHUFB (BX), X9, X2 // c4e2310013
- //TODO: VPSHUFB (R11), X9, X2 // c4c2310013
- //TODO: VPSHUFB X2, X9, X2 // c4e23100d2
- //TODO: VPSHUFB X11, X9, X2 // c4c23100d3
- //TODO: VPSHUFB (BX), X9, X11 // c46231001b
- //TODO: VPSHUFB (R11), X9, X11 // c44231001b
- //TODO: VPSHUFB X2, X9, X11 // c4623100da
- //TODO: VPSHUFB X11, X9, X11 // c4423100db
- //TODO: VPSHUFB (BX), Y15, Y2 // c4e2050013
- //TODO: VPSHUFB (R11), Y15, Y2 // c4c2050013
- //TODO: VPSHUFB Y2, Y15, Y2 // c4e20500d2
- //TODO: VPSHUFB Y11, Y15, Y2 // c4c20500d3
- //TODO: VPSHUFB (BX), Y15, Y11 // c46205001b
- //TODO: VPSHUFB (R11), Y15, Y11 // c44205001b
- //TODO: VPSHUFB Y2, Y15, Y11 // c4620500da
- //TODO: VPSHUFB Y11, Y15, Y11 // c4420500db
- //TODO: VPSHUFD $7, (BX), X2 // c4e179701307 or c5f9701307
- //TODO: VPSHUFD $7, (R11), X2 // c4c179701307
- //TODO: VPSHUFD $7, X2, X2 // c4e17970d207 or c5f970d207
- //TODO: VPSHUFD $7, X11, X2 // c4c17970d307
- //TODO: VPSHUFD $7, (BX), X11 // c46179701b07 or c579701b07
- //TODO: VPSHUFD $7, (R11), X11 // c44179701b07
- //TODO: VPSHUFD $7, X2, X11 // c4617970da07 or c57970da07
- //TODO: VPSHUFD $7, X11, X11 // c4417970db07
- //TODO: VPSHUFD $7, (BX), Y2 // c4e17d701307 or c5fd701307
- //TODO: VPSHUFD $7, (R11), Y2 // c4c17d701307
- //TODO: VPSHUFD $7, Y2, Y2 // c4e17d70d207 or c5fd70d207
- //TODO: VPSHUFD $7, Y11, Y2 // c4c17d70d307
- //TODO: VPSHUFD $7, (BX), Y11 // c4617d701b07 or c57d701b07
- //TODO: VPSHUFD $7, (R11), Y11 // c4417d701b07
- //TODO: VPSHUFD $7, Y2, Y11 // c4617d70da07 or c57d70da07
- //TODO: VPSHUFD $7, Y11, Y11 // c4417d70db07
+ VPSHUFB (BX), X9, X2 // c4e2310013
+ VPSHUFB (R11), X9, X2 // c4c2310013
+ VPSHUFB X2, X9, X2 // c4e23100d2
+ VPSHUFB X11, X9, X2 // c4c23100d3
+ VPSHUFB (BX), X9, X11 // c46231001b
+ VPSHUFB (R11), X9, X11 // c44231001b
+ VPSHUFB X2, X9, X11 // c4623100da
+ VPSHUFB X11, X9, X11 // c4423100db
+ VPSHUFB (BX), Y15, Y2 // c4e2050013
+ VPSHUFB (R11), Y15, Y2 // c4c2050013
+ VPSHUFB Y2, Y15, Y2 // c4e20500d2
+ VPSHUFB Y11, Y15, Y2 // c4c20500d3
+ VPSHUFB (BX), Y15, Y11 // c46205001b
+ VPSHUFB (R11), Y15, Y11 // c44205001b
+ VPSHUFB Y2, Y15, Y11 // c4620500da
+ VPSHUFB Y11, Y15, Y11 // c4420500db
+ VPSHUFD $7, (BX), X2 // c4e179701307 or c5f9701307
+ VPSHUFD $7, (R11), X2 // c4c179701307
+ VPSHUFD $7, X2, X2 // c4e17970d207 or c5f970d207
+ VPSHUFD $7, X11, X2 // c4c17970d307
+ VPSHUFD $7, (BX), X11 // c46179701b07 or c579701b07
+ VPSHUFD $7, (R11), X11 // c44179701b07
+ VPSHUFD $7, X2, X11 // c4617970da07 or c57970da07
+ VPSHUFD $7, X11, X11 // c4417970db07
+ VPSHUFD $7, (BX), Y2 // c4e17d701307 or c5fd701307
+ VPSHUFD $7, (R11), Y2 // c4c17d701307
+ VPSHUFD $7, Y2, Y2 // c4e17d70d207 or c5fd70d207
+ VPSHUFD $7, Y11, Y2 // c4c17d70d307
+ VPSHUFD $7, (BX), Y11 // c4617d701b07 or c57d701b07
+ VPSHUFD $7, (R11), Y11 // c4417d701b07
+ VPSHUFD $7, Y2, Y11 // c4617d70da07 or c57d70da07
+ VPSHUFD $7, Y11, Y11 // c4417d70db07
//TODO: VPSHUFHW $7, (BX), X2 // c4e17a701307 or c5fa701307
//TODO: VPSHUFHW $7, (R11), X2 // c4c17a701307
//TODO: VPSHUFHW $7, X2, X2 // c4e17a70d207 or c5fa70d207
//TODO: VPSIGNW (R11), Y15, Y11 // c44205091b
//TODO: VPSIGNW Y2, Y15, Y11 // c4620509da
//TODO: VPSIGNW Y11, Y15, Y11 // c4420509db
- //TODO: VPSLLD (BX), X9, X2 // c4e131f213 or c5b1f213
- //TODO: VPSLLD (R11), X9, X2 // c4c131f213
- //TODO: VPSLLD X2, X9, X2 // c4e131f2d2 or c5b1f2d2
- //TODO: VPSLLD X11, X9, X2 // c4c131f2d3
- //TODO: VPSLLD (BX), X9, X11 // c46131f21b or c531f21b
- //TODO: VPSLLD (R11), X9, X11 // c44131f21b
- //TODO: VPSLLD X2, X9, X11 // c46131f2da or c531f2da
- //TODO: VPSLLD X11, X9, X11 // c44131f2db
- //TODO: VPSLLD $7, X2, X9 // c4e13172f207 or c5b172f207
- //TODO: VPSLLD $7, X11, X9 // c4c13172f307
- //TODO: VPSLLDQ $7, X2, X9 // c4e13173fa07 or c5b173fa07
- //TODO: VPSLLDQ $7, X11, X9 // c4c13173fb07
- //TODO: VPSLLDQ $7, Y2, Y15 // c4e10573fa07 or c58573fa07
- //TODO: VPSLLDQ $7, Y11, Y15 // c4c10573fb07
- //TODO: VPSLLQ (BX), X9, X2 // c4e131f313 or c5b1f313
- //TODO: VPSLLQ (R11), X9, X2 // c4c131f313
- //TODO: VPSLLQ X2, X9, X2 // c4e131f3d2 or c5b1f3d2
- //TODO: VPSLLQ X11, X9, X2 // c4c131f3d3
- //TODO: VPSLLQ (BX), X9, X11 // c46131f31b or c531f31b
- //TODO: VPSLLQ (R11), X9, X11 // c44131f31b
- //TODO: VPSLLQ X2, X9, X11 // c46131f3da or c531f3da
- //TODO: VPSLLQ X11, X9, X11 // c44131f3db
- //TODO: VPSLLQ $7, X2, X9 // c4e13173f207 or c5b173f207
- //TODO: VPSLLQ $7, X11, X9 // c4c13173f307
+ VPSLLD (BX), X9, X2 // c4e131f213 or c5b1f213
+ VPSLLD (R11), X9, X2 // c4c131f213
+ VPSLLD X2, X9, X2 // c4e131f2d2 or c5b1f2d2
+ VPSLLD X11, X9, X2 // c4c131f2d3
+ VPSLLD (BX), X9, X11 // c46131f21b or c531f21b
+ VPSLLD (R11), X9, X11 // c44131f21b
+ VPSLLD X2, X9, X11 // c46131f2da or c531f2da
+ VPSLLD X11, X9, X11 // c44131f2db
+ VPSLLD $7, X2, X9 // c4e13172f207 or c5b172f207
+ VPSLLD $7, X11, X9 // c4c13172f307
+ VPSLLDQ $7, X2, X9 // c4e13173fa07 or c5b173fa07
+ VPSLLDQ $7, X11, X9 // c4c13173fb07
+ VPSLLDQ $7, Y2, Y15 // c4e10573fa07 or c58573fa07
+ VPSLLDQ $7, Y11, Y15 // c4c10573fb07
+ VPSLLQ (BX), X9, X2 // c4e131f313 or c5b1f313
+ VPSLLQ (R11), X9, X2 // c4c131f313
+ VPSLLQ X2, X9, X2 // c4e131f3d2 or c5b1f3d2
+ VPSLLQ X11, X9, X2 // c4c131f3d3
+ VPSLLQ (BX), X9, X11 // c46131f31b or c531f31b
+ VPSLLQ (R11), X9, X11 // c44131f31b
+ VPSLLQ X2, X9, X11 // c46131f3da or c531f3da
+ VPSLLQ X11, X9, X11 // c44131f3db
+ VPSLLQ $7, X2, X9 // c4e13173f207 or c5b173f207
+ VPSLLQ $7, X11, X9 // c4c13173f307
//TODO: VPSLLVD (BX), X9, X2 // c4e2314713
//TODO: VPSLLVD (R11), X9, X2 // c4c2314713
//TODO: VPSLLVD X2, X9, X2 // c4e23147d2
//TODO: VPSRAW X11, Y15, Y11 // c44105e1db
//TODO: VPSRAW $7, Y2, Y15 // c4e10571e207 or c58571e207
//TODO: VPSRAW $7, Y11, Y15 // c4c10571e307
- //TODO: VPSRLD (BX), X9, X2 // c4e131d213 or c5b1d213
- //TODO: VPSRLD (R11), X9, X2 // c4c131d213
- //TODO: VPSRLD X2, X9, X2 // c4e131d2d2 or c5b1d2d2
- //TODO: VPSRLD X11, X9, X2 // c4c131d2d3
- //TODO: VPSRLD (BX), X9, X11 // c46131d21b or c531d21b
- //TODO: VPSRLD (R11), X9, X11 // c44131d21b
- //TODO: VPSRLD X2, X9, X11 // c46131d2da or c531d2da
- //TODO: VPSRLD X11, X9, X11 // c44131d2db
- //TODO: VPSRLD $7, X2, X9 // c4e13172d207 or c5b172d207
- //TODO: VPSRLD $7, X11, X9 // c4c13172d307
- //TODO: VPSRLDQ $7, X2, X9 // c4e13173da07 or c5b173da07
- //TODO: VPSRLDQ $7, X11, X9 // c4c13173db07
- //TODO: VPSRLDQ $7, Y2, Y15 // c4e10573da07 or c58573da07
- //TODO: VPSRLDQ $7, Y11, Y15 // c4c10573db07
- //TODO: VPSRLQ (BX), X9, X2 // c4e131d313 or c5b1d313
- //TODO: VPSRLQ (R11), X9, X2 // c4c131d313
- //TODO: VPSRLQ X2, X9, X2 // c4e131d3d2 or c5b1d3d2
- //TODO: VPSRLQ X11, X9, X2 // c4c131d3d3
- //TODO: VPSRLQ (BX), X9, X11 // c46131d31b or c531d31b
- //TODO: VPSRLQ (R11), X9, X11 // c44131d31b
- //TODO: VPSRLQ X2, X9, X11 // c46131d3da or c531d3da
- //TODO: VPSRLQ X11, X9, X11 // c44131d3db
- //TODO: VPSRLQ $7, X2, X9 // c4e13173d207 or c5b173d207
- //TODO: VPSRLQ $7, X11, X9 // c4c13173d307
+ VPSRLD (BX), X9, X2 // c4e131d213 or c5b1d213
+ VPSRLD (R11), X9, X2 // c4c131d213
+ VPSRLD X2, X9, X2 // c4e131d2d2 or c5b1d2d2
+ VPSRLD X11, X9, X2 // c4c131d2d3
+ VPSRLD (BX), X9, X11 // c46131d21b or c531d21b
+ VPSRLD (R11), X9, X11 // c44131d21b
+ VPSRLD X2, X9, X11 // c46131d2da or c531d2da
+ VPSRLD X11, X9, X11 // c44131d2db
+ VPSRLD $7, X2, X9 // c4e13172d207 or c5b172d207
+ VPSRLD $7, X11, X9 // c4c13172d307
+ VPSRLDQ $7, X2, X9 // c4e13173da07 or c5b173da07
+ VPSRLDQ $7, X11, X9 // c4c13173db07
+ VPSRLDQ $7, Y2, Y15 // c4e10573da07 or c58573da07
+ VPSRLDQ $7, Y11, Y15 // c4c10573db07
+ VPSRLQ (BX), X9, X2 // c4e131d313 or c5b1d313
+ VPSRLQ (R11), X9, X2 // c4c131d313
+ VPSRLQ X2, X9, X2 // c4e131d3d2 or c5b1d3d2
+ VPSRLQ X11, X9, X2 // c4c131d3d3
+ VPSRLQ (BX), X9, X11 // c46131d31b or c531d31b
+ VPSRLQ (R11), X9, X11 // c44131d31b
+ VPSRLQ X2, X9, X11 // c46131d3da or c531d3da
+ VPSRLQ X11, X9, X11 // c44131d3db
+ VPSRLQ $7, X2, X9 // c4e13173d207 or c5b173d207
+ VPSRLQ $7, X11, X9 // c4c13173d307
//TODO: VPSRLVD (BX), X9, X2 // c4e2314513
//TODO: VPSRLVD (R11), X9, X2 // c4c2314513
//TODO: VPSRLVD X2, X9, X2 // c4e23145d2
return []string{"-m31"}
case "s390x":
return []string{"-m64"}
+ case "mips64", "mips64le":
+ return []string{"-mabi=64"}
}
return nil
}
// TODO(rsc): require failure
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 {
- fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " "))
+ fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(nargs, " "))
os.Stderr.Write(stdin)
fmt.Fprint(os.Stderr, "EOF\n")
}
- stdout, stderr, _ := run(stdin, args)
+ stdout, stderr, _ := run(stdin, nargs)
if *debugGcc {
os.Stderr.Write(stdout)
os.Stderr.Write(stderr)
}
fmt.Fprintf(fgo2, "\n")
+ callsMalloc := false
for _, key := range nameKeys(p.Name) {
n := p.Name[key]
if n.FuncType != nil {
- p.writeDefsFunc(fgo2, n)
+ p.writeDefsFunc(fgo2, n, &callsMalloc)
}
}
} else {
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 {
fatalf("%s", err)
}
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
gtype := n.FuncType.Go
void := gtype.Results == nil || len(gtype.Results.List) == 0
if inProlog {
fmt.Fprint(fgo2, builtinDefs[name])
+ if strings.Contains(builtinDefs[name], "_cgo_cmalloc") {
+ *callsMalloc = true
+ }
return
}
// Gcc wrapper unpacks the C argument struct
// and calls the actual C function.
+ fmt.Fprintf(fgcc, "CGO_NO_SANITIZE_THREAD\n")
if n.AddError {
fmt.Fprintf(fgcc, "int\n")
} else {
// wrapper, we can't refer to the function, since the reference is in
// a different file.
func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) {
+ fmt.Fprintf(fgcc, "CGO_NO_SANITIZE_THREAD\n")
if t := n.FuncType.Result; t != nil {
fmt.Fprintf(fgcc, "%s\n", t.C.String())
} else {
p.writeExportHeader(fgcch)
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, "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 void _cgo_release_context(__SIZE_TYPE__);\n\n")
+ fmt.Fprintf(fgcc, "extern char* _cgo_topofstack(void);")
fmt.Fprintf(fgcc, "%s\n", tsanProlog)
for _, exp := range p.ExpFunc {
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, "\nCGO_NO_SANITIZE_THREAD")
fmt.Fprintf(fgcc, "\n%s\n", s)
fmt.Fprintf(fgcc, "{\n")
fmt.Fprintf(fgcc, "\t__SIZE_TYPE__ _cgo_ctxt = _cgo_wait_runtime_init_done();\n")
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, "\nCGO_NO_SANITIZE_THREAD\n")
fmt.Fprintf(fgcc, "%s %s %s {\n", cRet, exp.ExpName, cParams)
if resultCount > 0 {
fmt.Fprintf(fgcc, "\t%s r;\n", cRet)
// Prologue defining TSAN functions in C.
const noTsanProlog = `
+#define CGO_NO_SANITIZE_THREAD
#define _cgo_tsan_acquire()
#define _cgo_tsan_release()
`
const yesTsanProlog = `
+#define CGO_NO_SANITIZE_THREAD __attribute__ ((no_sanitize_thread))
+
long long _cgo_sync __attribute__ ((common));
extern void __tsan_acquire(void*);
//go:linkname _cgo_runtime_cgocall runtime.cgocall
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
func _cgo_runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr, uintptr)
`
const gccgoGoProlog = `
-//extern runtime.cgoCheckPointer
func _cgoCheckPointer(interface{}, ...interface{}) interface{}
-//extern runtime.cgoCheckResult
func _cgoCheckResult(interface{})
`
const cStringDef = `
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)
copy(pp[:], s)
pp[len(s)] = 0
const cBytesDef = `
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)
copy(pp[:], b)
return p
const cMallocDef = `
func _Cfunc__CMalloc(n _Ctype_size_t) unsafe.Pointer {
- return _cgo_runtime_cmalloc(uintptr(n))
+ return _cgo_cmalloc(uint64(n))
}
`
"_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 {
return strings.Replace(strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1),
"GCCGOSYMBOLPREF", p.gccgoSymbolPrefix(), -1)
-installsuffix suffix
Look for packages in $GOROOT/pkg/$GOOS_$GOARCH_suffix
instead of $GOROOT/pkg/$GOOS_$GOARCH.
+ -l
+ Disable inlining.
-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
Write memory profile for the compilation to file.
-memprofilerate rate
cmpptr = x86.ACMPL
}
- if gc.Ctxt.Flag_dynlink {
- gc.Thearch.ReservedRegs = append(gc.Thearch.ReservedRegs, x86.REG_R15)
+ if gc.Ctxt.Flag_dynlink || obj.Getgoos() == "nacl" {
+ resvd = append(resvd, x86.REG_R15)
}
-}
-
-func Main() {
- if obj.Getgoos() == "nacl" {
- resvd = append(resvd, x86.REG_BP, x86.REG_R15)
- } else if obj.Framepointer_enabled != 0 {
+ if gc.Ctxt.Framepointer_enabled || obj.Getgoos() == "nacl" {
resvd = append(resvd, x86.REG_BP)
}
+ gc.Thearch.ReservedRegs = resvd
+}
+func Main() {
gc.Thearch.LinkArch = &x86.Linkamd64
if obj.Getgoarch() == "amd64p32" {
gc.Thearch.LinkArch = &x86.Linkamd64p32
gc.Thearch.FREGMIN = x86.REG_X0
gc.Thearch.FREGMAX = x86.REG_X15
gc.Thearch.MAXWIDTH = 1 << 50
- gc.Thearch.ReservedRegs = resvd
gc.Thearch.AddIndex = addindex
gc.Thearch.Betypeinit = betypeinit
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
} else {
gc.Regalloc(&r1, t, n1)
switch uint32(ft)<<16 | uint32(tt) {
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))
/*
import (
"cmd/compile/internal/gc"
- "cmd/internal/obj"
"cmd/internal/obj/x86"
)
b &= 0xffff
if gc.Nacl {
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.
b &^= (1 << (x86.REG_BP - x86.REG_AX))
}
gc.Gvarkill(v.Aux.(*gc.Node))
case ssa.OpVarLive:
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:
// Optimization - if the subsequent block has a load or store
// at the same address, we don't need to issue this instruction.
n = &n1
- case gc.ONAME:
- if n.Class == gc.PPARAMREF {
- var n1 gc.Node
- gc.Cgen(n.Name.Heapaddr, &n1)
- sclean[nsclean-1] = n1
- n = &n1
- }
-
+ case gc.ONAME, gc.OINDREG:
// nothing
- case gc.OINDREG:
- break
}
*lo = *n
}
f.Offset = o
if f.Nname != nil {
- // this same stackparam logic is in addrescapes
- // in typecheck.go. usually addrescapes runs after
- // widstruct, in which case we could drop this,
+ // addrescapes has similar code to update these offsets.
+ // Usually addrescapes runs after widstruct,
+ // in which case we could drop this,
// but function closure functions are the exception.
- if f.Nname.Name.Param.Stackparam != nil {
- f.Nname.Name.Param.Stackparam.Xoffset = o
+ // NOTE(rsc): This comment may be stale.
+ // 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
} else {
f.Nname.Xoffset = o
--- /dev/null
+// 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\\),"},
+ },
+}
// (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
"objects": constants, types, variables, and functions. In general,
predeclared types (int, string, error, unsafe.Pointer, etc.). This way
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
(compact, or with debugging information), followed by a version string
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
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
// Leave for debugging.
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 {
out *bufio.Writer
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
var format byte = 'c' // compact
if debugFormat {
}
p.rawByte(format)
+ format = 'n' // track named types only
+ if trackAllTypes {
+ format = 'a'
+ }
+ p.rawByte(format)
+
// posInfo exported or not?
p.bool(p.posInfoFormat)
}
// otherwise, remember the type, write the type tag (< 0) and type data
- if p.trace {
- p.tracef("T%d = {>\n", len(p.typIndex))
- defer p.tracef("<\n} ")
+ if trackAllTypes {
+ if p.trace {
+ 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
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.
if t.Orig == t {
Fatalf("exporter: predeclared type missing from type map?")
// print symbol with Vargen number or not as desired
name := s.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
// but instead of emitting the information textually, emit the node tree in
// binary form.
+// TODO(gri) Improve tracing output. The current format is difficult to read.
+
// stmtList may emit more (or fewer) than len(list) nodes.
func (p *exporter) stmtList(list Nodes) {
if p.trace {
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) {
n = n.Left
}
// Special case: name used as local variable in export.
// _ becomes ~b%d internally; print as _ for export
if n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' {
- // case 0: mapped to ONAME
p.op(ONAME)
- p.bool(true) // indicate blank identifier
+ p.string("_") // inlined and customized version of p.sym(n)
break
}
if n.Sym != nil && !isblank(n) && n.Name.Vargen > 0 {
- // case 1: mapped to OPACK
- p.op(OPACK)
+ p.op(ONAME)
p.sym(n)
break
}
// 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.
if n.Left != nil && n.Left.Op == OTYPE && n.Right != nil && n.Right.Op == ONAME {
- // case 2: mapped to ONAME
- p.op(ONAME)
- // 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.op(OXDOT)
+ p.expr(n.Left) // n.Left.Op == OTYPE
p.fieldSym(n.Right.Sym, true)
break
}
- // case 3: mapped to OPACK
- p.op(OPACK)
- p.sym(n) // fallthrough inlined here
-
- case OPACK, ONONAME:
- p.op(op)
+ p.op(ONAME)
p.sym(n)
+ // case OPACK, ONONAME:
+ // should have been resolved by typechecking - handled by default case
+
case OTYPE:
p.op(OTYPE)
if p.bool(n.Type == nil) {
p.typ(n.Type)
}
- case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC:
- panic("unreachable") // should have been resolved by typechecking
+ // case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC:
+ // should have been resolved by typechecking - handled by default case
// case OCLOSURE:
// unimplemented - handled by default case
// case OCOMPLIT:
- // unimplemented - handled by default case
+ // should have been resolved by typechecking - handled by default case
case OPTRLIT:
p.op(OPTRLIT)
case 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
case OARRAYLIT, OMAPLIT:
- p.op(op)
- if !p.bool(n.Implicit) {
- p.typ(n.Type)
- }
+ p.op(OCOMPLIT)
+ p.typ(n.Type)
p.exprList(n.List)
case OKEY:
case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
p.op(OXDOT)
p.expr(n.Left)
- if n.Sym == nil {
- panic("unreachable") // can this happen during export?
- }
p.fieldSym(n.Sym, true)
case ODOTTYPE, ODOTTYPE2:
p.expr(max)
case OCOPY, OCOMPLEX:
+ // treated like other builtin calls (see e.g., OREAL)
p.op(op)
p.expr(n.Left)
p.expr(n.Right)
+ p.op(OEND)
case OCONV, OCONVIFACE, OCONVNOP, OARRAYBYTESTR, OARRAYRUNESTR, OSTRARRAYBYTE, OSTRARRAYRUNE, ORUNESTR:
p.op(OCONV)
p.typ(n.Type)
- if p.bool(n.Left != nil) {
+ if n.Left != nil {
p.expr(n.Left)
+ p.op(OEND)
} 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:
p.op(op)
- if p.bool(n.Left != nil) {
+ if n.Left != nil {
p.expr(n.Left)
+ p.op(OEND)
} 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)
+ } else if n.Isddd {
+ Fatalf("exporter: unexpected '...' with %s call", opnames[op])
}
case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OGETG:
p.op(ODCLCONST)
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)
}
}
switch op := n.Op; op {
case ODCL:
p.op(ODCL)
- switch n.Left.Class &^ PHEAP {
- case PPARAM, PPARAMOUT, PAUTO:
+ switch n.Left.Class {
+ case PPARAM, PPARAMOUT, PAUTO, PAUTOHEAP:
// TODO(gri) when is this not PAUTO?
// Also, originally this didn't look like
// the default case. Investigate.
p.expr(n.Right)
}
- case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
- fallthrough
-
- case OAS2:
+ case OAS2, OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
p.op(OAS2)
p.exprList(n.List)
p.exprList(n.Rlist)
p.op(ORETURN)
p.exprList(n.List)
- case ORETJMP:
- // generated by compiler for trampolin routines - not exported
- panic("unreachable")
+ // case ORETJMP:
+ // unreachable - generated by compiler for trampolin routines
case OPROC, ODEFER:
p.op(op)
p.stmtList(n.List)
p.stmtList(n.Nbody)
- case OFALL:
- op = OXFALL
- fallthrough
+ case OFALL, OXFALL:
+ p.op(OXFALL)
- case OBREAK, OCONTINUE, OGOTO, OXFALL:
+ case OBREAK, OCONTINUE:
p.op(op)
p.exprsOrNil(n.Left, nil)
case OEMPTY:
- // nothing to emit
+ // nothing to emit
- case OLABEL:
- p.op(OLABEL)
+ case OGOTO, OLABEL:
+ p.op(op)
p.expr(n.Left)
default:
}
}
+// 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) {
s := n.Sym
if s.Pkg != nil {
// license that can be found in the LICENSE file.
// 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
buf []byte // reused for reading strings
// object lists, in order of deserialization
- strList []string
- pkgList []*Pkg
- typList []*Type
- funcList []*Node // nil entry means already declared
+ strList []string
+ pkgList []*Pkg
+ typList []*Type
+ funcList []*Node // nil entry means already declared
+ trackAllTypes bool
// for delayed type verification
cmpList []struct{ pt, t *Type }
Fatalf("importer: invalid encoding format in export data: got %q; want 'c' or 'd'", format)
}
+ p.trackAllTypes = p.rawByte() == 'a'
+
p.posInfoFormat = p.bool()
// --- generic export data ---
// --- compiler-specific export data ---
// 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
objcount = 0
// an empty path denotes the package we are currently importing;
// it must be the first package we see
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
func (p *importer) newtyp(etype EType) *Type {
t := typ(etype)
- p.typList = append(p.typList, t)
+ if p.trackAllTypes {
+ p.typList = append(p.typList, t)
+ }
return t
}
// read underlying type
// parser.go:hidden_type
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
if t0.IsInterface() {
return n
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())
+ // case OPACK, ONONAME:
+ // unreachable - should have been resolved by typechecking
+
case OTYPE:
if p.bool() {
return mkname(p.sym())
// case OCLOSURE:
// unimplemented
- // case OCOMPLIT:
- // unimplemented
-
case OPTRLIT:
n := p.expr()
- if !p.bool() /* !implicit, i.e. '&' operator*/ {
+ if !p.bool() /* !implicit, i.e. '&' operator */ {
if n.Op == OCOMPLIT {
// Special case for &T{...}: turn into (*T){...}.
n.Right = Nod(OIND, n.Right, nil)
return n
case OSTRUCTLIT:
- n := Nod(OCOMPLIT, nil, nil)
- if !p.bool() {
- n.Right = typenod(p.typ())
- }
- n.List.Set(p.elemList())
+ n := Nod(OCOMPLIT, nil, typenod(p.typ()))
+ n.List.Set(p.elemList()) // special handling of field names
return n
- case OARRAYLIT, OMAPLIT:
- n := Nod(OCOMPLIT, nil, nil)
- if !p.bool() {
- n.Right = typenod(p.typ())
- }
+ // case OARRAYLIT, OMAPLIT:
+ // unreachable - mapped to case OCOMPLIT below by exporter
+
+ case OCOMPLIT:
+ n := Nod(OCOMPLIT, nil, typenod(p.typ()))
n.List.Set(p.exprList())
return n
case OXDOT:
// see parser.new_dotname
- obj := p.expr()
- 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)
+ return NodSym(OXDOT, p.expr(), p.fieldSym())
// case ODOTTYPE, ODOTTYPE2:
// unreachable - mapped to case ODOTTYPE below by exporter
n.SetSliceBounds(low, high, max)
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:
// unreachable - mapped to OCONV case below by exporter
case OCONV:
n := Nod(OCALL, typenod(p.typ()), nil)
- if p.bool() {
- n.List.Set1(p.expr())
- } else {
- n.List.Set(p.exprList())
- }
+ n.List.Set(p.exprList())
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)
- if p.bool() {
- n.List.Set1(p.expr())
- } else {
- n.List.Set(p.exprList())
+ n.List.Set(p.exprList())
+ if op == OAPPEND {
n.Isddd = p.bool()
}
return n
case OXCASE:
markdcl()
n := Nod(OXCASE, nil, nil)
+ n.Xoffset = int64(block)
n.List.Set(p.exprList())
// TODO(gri) eventually we must declare variables for type switch
// statements (type switch statements are not yet exported)
// case OFALL:
// 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()
+ if left != nil {
+ left = newname(left.Sym)
+ }
return Nod(op, left, nil)
// case OEMPTY:
// unreachable - not emitted by exporter
- case OLABEL:
- n := Nod(OLABEL, p.expr(), nil)
- n.Left.Sym = dclstack // context, for goto restrictions
+ case OGOTO, OLABEL:
+ n := Nod(op, newname(p.expr().Sym), nil)
+ n.Sym = dclstack // context, for goto restrictions
return n
case OEND:
return nil
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
}
}
package gc
const runtimeimport = "" +
- "c\x00\x03v0\x01\rruntime\x00\t\x11newobject\x00\x02\x17\"\vtyp·2\x00\x00\x01" +
- "\x17:\x00\t\x13panicindex\x00\x00\x00\t\x13panicslice\x00\x00\x00\t\x15panic" +
- "divide\x00\x00\x00\t\x15throwreturn\x00\x00\x00\t\x11throwinit\x00\x00\x00\t" +
- "\x11panicwrap\x00\x05 \x00 \x00 \x00\x00\t\rgopanic\x00\x01\x1b\x00\x00\x00\x00\t\x11gor" +
- "ecover\x00\x01\x17\b\x00\x01\x1b\x00\x00\x00\t\x11printbool\x00\x01\x00\x00\x00\t\x13printf" +
- "loat\x00\x01\x1a\x00\x00\t\x0fprintint\x00\x01\n\x00\x00\t\x0fprinthex\x00\x01\x14\x00\x00\t" +
- "\x11printuint\x00\x01\x14\x00\x00\t\x17printcomplex\x00\x01\x1e\x00\x00\t\x15prin" +
- "tstring\x00\x01 \x00\x00\t\x17printpointer\x00\x01:\x00\x00\t\x13printif" +
- "ace\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" +
- "\t\x15printunlock\x00\x00\x00\t\x19concatstring2\x00\x05\x17\x0f@\"\x00 \x00" +
- " \x00\x01 \x00\t\x19concatstring3\x00\a\x17\x0f@\"\x00 \x00 \x00 \x00\x01 \x00\t\x19co" +
- "ncatstring4\x00\t\x17\x0f@\"\x00 \x00 \x00 \x00 \x00\x01 \x00\t\x19concatstr" +
- "ing5\x00\v\x17\x0f@\"\x00 \x00 \x00 \x00 \x00 \x00\x01 \x00\t\x19concatstrings\x00" +
- "\x03\x17\x0f@\"\x00\x11 \x00\x01 \x00\t\x11cmpstring\x00\x03 \x00 \x00\x01\x02\x00\t\x0feqstri" +
- "ng\x00\x03 \x00 \x00\x01\x00\x00\t\x11intstring\x00\x03\x17\x0f\b\"\x00\n\x00\x01 \x00\t!slic" +
- "ebytetostring\x00\x03\x17\x0f@\"\x00\x11\"\x00\x01 \x00\t'slicebytetos" +
- "tringtmp\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\t'stringtoslicebytetmp\x00\x01 \x00\x01\x11\"\x00\t!stringt" +
- "oslicerune\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" +
- "retv·2\x00\x00\t\x11slicecopy\x00\x06:\tto·2\x00\x00:\tfr·3\x00\x00" +
- "\x16\vwid·4\x00\x1bunsafe-uintptr\x01\x02\x00\t\x1dslicestring" +
- "copy\x00\x04:^\x00\x00:`\x00\x00\x01\x02\x00\t\rconvI2E\x00\x02:\relem·2\x00\x00\x02" +
- ":\vret·1\x00\x00\t\rconvI2I\x00\x04\x17\"\b\x00\x00:\relem·3\x00\x00\x02:l" +
- "\x00\x00\t\rconvT2E\x00\x06\x17\"\b\x00\x00>p\x00\x00>\vbuf·4\x00\x00\x02:l\x00\x00\t\rc" +
- "onvT2I\x00\x06\x17\"\vtab·2\x00\x00>p\x00\x00>t\x00\x00\x02:l\x00\x00\t\x11assert" +
- "E2E\x00\x06\x17\"\vtyp·1\x00\x00:\x0fiface·2\x00\x00>\vret·3\x00\x00\x00\t" +
- "\x13assertE2E2\x00\x06\x17\"\b\x00\x00:\x0fiface·3\x00\x00>\vret·4\x00\x00" +
- "\x01\x00\x00\t\x11assertE2I\x00\x06\x17\"||\x00\x00:~\x00\x00>\x80\x01\x00\x00\x00\t\x13assert" +
- "E2I2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00>\x86\x01\x00\x00\x01\x00\x00\t\x11assertE2T\x00\x06\x17\"|" +
- "|\x00\x00:~\x00\x00>\x80\x01\x00\x00\x00\t\x13assertE2T2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00>\x86\x01" +
- "\x00\x00\x01\x00\x00\t\x11assertI2E\x00\x06\x17\"||\x00\x00:~\x00\x00>\x80\x01\x00\x00\x00\t\x13asse" +
- "rtI2E2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00>\x86\x01\x00\x00\x01\x00\x00\t\x11assertI2I\x00\x06\x17" +
- "\"||\x00\x00:~\x00\x00>\x80\x01\x00\x00\x00\t\x13assertI2I2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00>" +
- "\x86\x01\x00\x00\x01\x00\x00\t\x11assertI2T\x00\x06\x17\"||\x00\x00:~\x00\x00>\x80\x01\x00\x00\x00\t\x13as" +
- "sertI2T2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00>\x86\x01\x00\x00\x01\x00\x00\t\x17panicdotty" +
- "pe\x00\x06\x17\"\rhave·1\x00\x00\x9a\x01\rwant·2\x00\x00\x9a\x01\x84\x01\x00\x00\x00\t\rifa" +
- "ceeq\x00\x04:\ti1·2\x00\x00:\ti2·3\x00\x00\x02\x00l\x00\x00\t\refaceeq\x00\x04" +
- ":\xa4\x01\x00\x00:\xa6\x01\x00\x00\x02\x00l\x00\x00\t\rmakemap\x00\b\x17\"\x13mapType·2\x00" +
- "\x00\n\rhint·3\x00\x00>\x11mapbuf·4\x00\x00>\x17bucketbuf·5\x00" +
- "\x00\x02\x1d::\rhmap·1\x00\x00\t\x13mapaccess1\x00\x06\x17\"\xac\x01\x00\x00\x1d::\rh" +
- "map·3\x00\x00>\vkey·4\x00\x00\x02>\vval·1\x00\x00\t!mapaccess" +
- "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" +
- "ccess1_fast64\x00\x06\x17\"\xac\x01\x00\x00\x1d::\xb8\x01\x00\x00:\xba\x01\x00\x00\x02>\xbc\x01\x00\x00\t" +
- "#mapaccess1_faststr\x00\x06\x17\"\xac\x01\x00\x00\x1d::\xb8\x01\x00\x00:\xba\x01\x00\x00\x02" +
- ">\xbc\x01\x00\x00\t\x1bmapaccess1_fat\x00\b\x17\"\xac\x01\x00\x00\x1d::\xb8\x01\x00\x00>\xba\x01\x00" +
- "\x00\x17\"\rzero·5\x00\x00\x02>\xbc\x01\x00\x00\t\x13mapaccess2\x00\x06\x17\"\x13mapT" +
- "ype·3\x00\x00\x1d::\rhmap·4\x00\x00>\vkey·5\x00\x00\x04>\xbc\x01\x00\x00\x00\rp" +
- "res·2\x00\x00\t!mapaccess2_fast32\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!mapaccess2_fast64\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#mapaccess2" +
- "_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" +
- "\x1bmapaccess2_fat\x00\b\x17\"\xca\x01\x00\x00\x1d::\xcc\x01\x00\x00>\xce\x01\x00\x00\x17\"\rze" +
- "ro·6\x00\x00\x04>\xbc\x01\x00\x00\x00\xd0\x01\x00\x00\t\x13mapassign1\x00\b\x17\"\x13mapTy" +
- "pe·1\x00\x00\x1d::\rhmap·2\x00\x00>\vkey·3\x00\x00>\vval·4\x00\x00" +
- "\x00\t\x15mapiterinit\x00\x06\x17\"\xde\x01\x00\x00\x1d::\xe0\x01\x00\x00>\x0fhiter·3\x00" +
- "\x00\x00\t\x11mapdelete\x00\x06\x17\"\xde\x01\x00\x00\x1d::\xe0\x01\x00\x00>\xe2\x01\x00\x00\x00\t\x15mapi" +
- "ternext\x00\x02>\x0fhiter·1\x00\x00\x00\t\x0fmakechan\x00\x04\x17\"\x15cha" +
- "nType·2\x00\x00\n\xae\x01\x00\x00\x02\x1f\x06:\x0fhchan·1\x00\x00\t\x11chanrecv" +
- "1\x00\x06\x17\"\x15chanType·1\x00\x00\x1f\x02:\x0fhchan·2\x00\x00>p\x00\x00\x00\t\x11" +
- "chanrecv2\x00\x06\x17\"\xf2\x01\x00\x00\x1f\x02:\x0fhchan·3\x00\x00>\relem·4" +
- "\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" +
- "osechan\x00\x02:\xf4\x01\x00\x00\x00\a\x17writeBarrier\x00\x15\x06\renabled" +
- "\x00\x00\x00\vneeded\x00\x00\x00\x05cgo\x00\x00\x00\t\x1dwritebarrierptr\x00\x04>" +
- "\vdst·1\x00\x00:\vsrc·2\x00\x00\x00\t\x17typedmemmove\x00\x06\x17\"||" +
- "\x00\x00>\vdst·2\x00\x00>\vsrc·3\x00\x00\x00\t\x1btypedslicecopy\x00" +
- "\x06\x17\"\b\x00\x00:\vdst·3\x00\x00:\vsrc·4\x00\x00\x01\x02\x00\t\x17selectnbs" +
- "end\x00\x06\x17\"\xf2\x01\x00\x00\x1f\x04:\xfe\x01\x00\x00>\x80\x02\x00\x00\x01\x00\x00\t\x17selectnbrecv" +
- "\x00\x06\x17\"\xf2\x01\x00\x00>p\x00\x00\x1f\x02:\x0fhchan·4\x00\x00\x01\x00\x00\t\x19selectnbr" +
- "ecv2\x00\b\x17\"\xf2\x01\x00\x00>p\x00\x00\x17\x00\x15received·4\x00\x00\x1f\x02:\x0fhcha" +
- "n·5\x00\x00\x01\x00\x00\t\x11newselect\x00\x06\x17\"\vsel·1\x00\x00\n\x13selsi" +
- "ze·2\x00\x00\b\rsize·3\x00\x00\x00\t\x13selectsend\x00\x06\x17\"\vsel\xc2" +
- "\xb72\x00\x00\x1f\x04:\xfe\x01\x00\x00>\x80\x02\x00\x00\x02\x00\x15selected·1\x00\x00\t\x13select" +
- "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" +
- "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" +
- "\x00\xb8\x02\x00\x00\t\x19selectdefault\x00\x02\x17\"\xb6\x02\x00\x00\x02\x00\xb8\x02\x00\x00\t\x0fsele" +
- "ctgo\x00\x02\x17\"\xae\x02\x00\x00\x00\t\tblock\x00\x00\x00\t\x11makeslice\x00\x06\x17\"\b\x00" +
- "\x00\n\vnel·3\x00\x00\n\vcap·4\x00\x00\x02\x11:\vary·1\x00\x00\t\x11grows" +
- "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" +
- "ove\x00\x06>\tto·1\x00\x00>\vfrm·2\x00\x00\x16\x11length·3\x00d\x00\t\v" +
- "memclr\x00\x04\x17\"\vptr·1\x00\x00\x16\x11length·2\x00d\x00\t\x0fmemeq" +
- "ual\x00\x06>\ax·2\x00\x00>\ay·3\x00\x00\x16\rsize·4\x00d\x01\x00\x00\t\x11mem" +
- "equal8\x00\x04>\xe2\x02\x00\x00>\xe4\x02\x00\x00\x01\x00\x00\t\x13memequal16\x00\x04>\xe2\x02\x00\x00" +
- ">\xe4\x02\x00\x00\x01\x00\x00\t\x13memequal32\x00\x04>\xe2\x02\x00\x00>\xe4\x02\x00\x00\x01\x00\x00\t\x13mem" +
- "equal64\x00\x04>\xe2\x02\x00\x00>\xe4\x02\x00\x00\x01\x00\x00\t\x15memequal128\x00\x04>\xe2\x02" +
- "\x00\x00>\xe4\x02\x00\x00\x01\x00\x00\t\x0fint64div\x00\x03\n\x00\n\x00\x01\n\x00\t\x11uint64div" +
- "\x00\x03\x14\x00\x14\x00\x01\x14\x00\t\x0fint64mod\x00\x03\n\x00\n\x00\x01\n\x00\t\x11uint64mod\x00" +
- "\x03\x14\x00\x14\x00\x01\x14\x00\t\x1bfloat64toint64\x00\x01\x1a\x00\x01\n\x00\t\x1dfloat64" +
- "touint64\x00\x01\x1a\x00\x01\x14\x00\t\x1bint64tofloat64\x00\x01\n\x00\x01\x1a\x00\t\x1d" +
- "uint64tofloat64\x00\x01\x14\x00\x01\x1a\x00\t\x19complex128div\x00\x04\x1e" +
- "\vnum·2\x00\x00\x1e\vden·3\x00\x00\x02\x1e\vquo·1\x00\x00\t\x19racefunc" +
- "enter\x00\x01\x16d\x00\t\x17racefuncexit\x00\x00\x00\t\x0fraceread\x00\x01\x16" +
- "d\x00\t\x11racewrite\x00\x01\x16d\x00\t\x19racereadrange\x00\x04\x16\radd" +
- "r·1\x00d\x16\rsize·2\x00d\x00\t\x1bracewriterange\x00\x04\x16\x94\x03\x00" +
- "d\x16\x96\x03\x00d\x00\t\x0fmsanread\x00\x04\x16\x94\x03\x00d\x16\x96\x03\x00d\x00\t\x11msanwrit" +
- "e\x00\x04\x16\x94\x03\x00d\x16\x96\x03\x00d\x00\v\xf4\x01\x02\v\x00\x01\x00\n$$\n"
+ "cn\x00\x03v0\x01\rruntime\x00\t\x11newobject\x00\x02\x17\"\vtyp·2\x00\x00" +
+ "\x01\x17:\x00\t\x13panicindex\x00\x00\x00\t\x13panicslice\x00\x00\x00\t\x15pani" +
+ "cdivide\x00\x00\x00\t\x15throwreturn\x00\x00\x00\t\x11throwinit\x00\x00\x00" +
+ "\t\x11panicwrap\x00\x05 \x00 \x00 \x00\x00\t\rgopanic\x00\x01\x1b\x00\x00\x00\x00\t\x11go" +
+ "recover\x00\x01\x17\b\x00\x01\x1b\x00\x00\x00\t\x11printbool\x00\x01\x00\x00\x00\t\x13print" +
+ "float\x00\x01\x1a\x00\x00\t\x0fprintint\x00\x01\n\x00\x00\t\x0fprinthex\x00\x01\x14\x00\x00" +
+ "\t\x11printuint\x00\x01\x14\x00\x00\t\x17printcomplex\x00\x01\x1e\x00\x00\t\x15pri" +
+ "ntstring\x00\x01 \x00\x00\t\x17printpointer\x00\x01:\x00\x00\t\x13printi" +
+ "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\t\x15printunlock\x00\x00\x00\t\x19concatstring2\x00\x05\x17\x0f@\"\x00 " +
+ "\x00 \x00\x01 \x00\t\x19concatstring3\x00\a\x17\x0f@\"\x00 \x00 \x00 \x00\x01 \x00\t\x19c" +
+ "oncatstring4\x00\t\x17\x0f@\"\x00 \x00 \x00 \x00 \x00\x01 \x00\t\x19concatst" +
+ "ring5\x00\v\x17\x0f@\"\x00 \x00 \x00 \x00 \x00 \x00\x01 \x00\t\x19concatstrings" +
+ "\x00\x03\x17\x0f@\"\x00\x11 \x00\x01 \x00\t\x11cmpstring\x00\x03 \x00 \x00\x01\x02\x00\t\x0feqstr" +
+ "ing\x00\x03 \x00 \x00\x01\x00\x00\t\x11intstring\x00\x03\x17\x0f\b\"\x00\n\x00\x01 \x00\t!sli" +
+ "cebytetostring\x00\x03\x17\x0f@\"\x00\x11\"\x00\x01 \x00\t'slicebyteto" +
+ "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\t'stringtoslicebytetmp\x00\x01 \x00\x01\x11\"\x00\t!string" +
+ "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" +
+ "\rretv·2\x00\x00\t\x11slicecopy\x00\x06:\tto·2\x00\x00:\tfr·3\x00" +
+ "\x00\x16\vwid·4\x00\x1bunsafe-uintptr\x01\x02\x00\t\x1dslicestrin" +
+ "gcopy\x00\x04:^\x00\x00:`\x00\x00\x01\x02\x00\t\rconvI2E\x00\x02:\relem·2\x00\x00" +
+ "\x02:\vret·1\x00\x00\t\rconvI2I\x00\x04\x17\"\b\x00\x00:\relem·3\x00\x00\x02:" +
+ "l\x00\x00\t\rconvT2E\x00\x06\x17\"\b\x00\x00\x17:p\x00\x00\x17:\vbuf·4\x00\x00\x02:l\x00\x00" +
+ "\t\rconvT2I\x00\x06\x17\"\vtab·2\x00\x00\x17:p\x00\x00\x17:t\x00\x00\x02:l\x00\x00\t\x11a" +
+ "ssertE2E\x00\x06\x17\"\vtyp·1\x00\x00:\x0fiface·2\x00\x00\x17:\vret\xc2" +
+ "\xb73\x00\x00\x00\t\x13assertE2E2\x00\x06\x17\"\b\x00\x00:\x0fiface·3\x00\x00\x17:\vr" +
+ "et·4\x00\x00\x01\x00\x00\t\x11assertE2I\x00\x06\x17\"||\x00\x00:~\x00\x00\x17:\x80\x01\x00\x00\x00" +
+ "\t\x13assertE2I2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00\x17:\x86\x01\x00\x00\x01\x00\x00\t\x11asser" +
+ "tE2T\x00\x06\x17\"||\x00\x00:~\x00\x00\x17:\x80\x01\x00\x00\x00\t\x13assertE2T2\x00\x06\x17\"\b" +
+ "\x00\x00:\x84\x01\x00\x00\x17:\x86\x01\x00\x00\x01\x00\x00\t\x11assertI2E\x00\x06\x17\"||\x00\x00:~\x00\x00\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" +
+ "\x11assertI2I\x00\x06\x17\"||\x00\x00:~\x00\x00\x17:\x80\x01\x00\x00\x00\t\x13assertI2I" +
+ "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" +
+ "\x00:~\x00\x00\x17:\x80\x01\x00\x00\x00\t\x13assertI2T2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00\x17:\x86\x01" +
+ "\x00\x00\x01\x00\x00\t\x17panicdottype\x00\x06\x17\"\rhave·1\x00\x00\x17\"\rwant" +
+ "·2\x00\x00\x17\"\x84\x01\x00\x00\x00\t\rifaceeq\x00\x04:\ti1·2\x00\x00:\ti2·3\x00" +
+ "\x00\x02\x00l\x00\x00\t\refaceeq\x00\x04:\xa4\x01\x00\x00:\xa6\x01\x00\x00\x02\x00l\x00\x00\t\rmakema" +
+ "p\x00\b\x17\"\x13mapType·2\x00\x00\n\rhint·3\x00\x00\x17:\x11mapbuf·" +
+ "4\x00\x00\x17:\x17bucketbuf·5\x00\x00\x02\x1d::\rhmap·1\x00\x00\t\x13mapa" +
+ "ccess1\x00\x06\x17\"\xac\x01\x00\x00\x1d::\rhmap·3\x00\x00\x17:\vkey·4\x00\x00\x02\x17" +
+ ":\vval·1\x00\x00\t!mapaccess1_fast32\x00\x06\x17\"\xac\x01\x00\x00\x1d::" +
+ "\xb8\x01\x00\x00:\xba\x01\x00\x00\x02\x17:\xbc\x01\x00\x00\t!mapaccess1_fast64\x00\x06\x17\"\xac" +
+ "\x01\x00\x00\x1d::\xb8\x01\x00\x00:\xba\x01\x00\x00\x02\x17:\xbc\x01\x00\x00\t#mapaccess1_fasts" +
+ "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" +
+ "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" +
+ ":\xbc\x01\x00\x00\t\x13mapaccess2\x00\x06\x17\"\x13mapType·3\x00\x00\x1d::\rhm" +
+ "ap·4\x00\x00\x17:\vkey·5\x00\x00\x04\x17:\xbc\x01\x00\x00\x00\rpres·2\x00\x00\t!ma" +
+ "paccess2_fast32\x00\x06\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!mapaccess2_fast64\x00\x06\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#mapaccess2_faststr\x00\x06" +
+ "\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" +
+ "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" +
+ "\x17:\xbc\x01\x00\x00\x00\xd0\x01\x00\x00\t\x13mapassign1\x00\b\x17\"\x13mapType·1\x00\x00" +
+ "\x1d::\rhmap·2\x00\x00\x17:\vkey·3\x00\x00\x17:\vval·4\x00\x00\x00\t\x15ma" +
+ "piterinit\x00\x06\x17\"\xde\x01\x00\x00\x1d::\xe0\x01\x00\x00\x17:\x0fhiter·3\x00\x00\x00\t\x11" +
+ "mapdelete\x00\x06\x17\"\xde\x01\x00\x00\x1d::\xe0\x01\x00\x00\x17:\xe2\x01\x00\x00\x00\t\x15mapiter" +
+ "next\x00\x02\x17:\x0fhiter·1\x00\x00\x00\t\x0fmakechan\x00\x04\x17\"\x15chanT" +
+ "ype·2\x00\x00\n\xae\x01\x00\x00\x02\x1f\x06:\x0fhchan·1\x00\x00\t\x11chanrecv1\x00" +
+ "\x06\x17\"\x15chanType·1\x00\x00\x1f\x02:\x0fhchan·2\x00\x00\x17:p\x00\x00\x00\t\x11c" +
+ "hanrecv2\x00\x06\x17\"\xf2\x01\x00\x00\x1f\x02:\x0fhchan·3\x00\x00\x17:\relem·4" +
+ "\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" +
+ "losechan\x00\x02:\xf4\x01\x00\x00\x00\a\x17writeBarrier\x00\x15\x06\renable" +
+ "d\x00\x00\x00\vneeded\x00\x00\x00\x05cgo\x00\x00\x00\t\x1dwritebarrierptr\x00\x04" +
+ "\x17:\vdst·1\x00\x00:\vsrc·2\x00\x00\x00\t\x17typedmemmove\x00\x06\x17\"" +
+ "||\x00\x00\x17:\vdst·2\x00\x00\x17:\vsrc·3\x00\x00\x00\t\x1btypedslicec" +
+ "opy\x00\x06\x17\"\b\x00\x00:\vdst·3\x00\x00:\vsrc·4\x00\x00\x01\x02\x00\t\x17selec" +
+ "tnbsend\x00\x06\x17\"\xf2\x01\x00\x00\x1f\x04:\xfe\x01\x00\x00\x17:\x80\x02\x00\x00\x01\x00\x00\t\x17selectn" +
+ "brecv\x00\x06\x17\"\xf2\x01\x00\x00\x17:p\x00\x00\x1f\x02:\x0fhchan·4\x00\x00\x01\x00\x00\t\x19sel" +
+ "ectnbrecv2\x00\b\x17\"\xf2\x01\x00\x00\x17:p\x00\x00\x17\x00\x15received·4\x00\x00\x1f" +
+ "\x02:\x0fhchan·5\x00\x00\x01\x00\x00\t\x11newselect\x00\x06\x17\"\vsel·1\x00\x00" +
+ "\n\x13selsize·2\x00\x00\b\rsize·3\x00\x00\x00\t\x13selectsend\x00\x06" +
+ "\x17\"\vsel·2\x00\x00\x1f\x04:\xfe\x01\x00\x00\x17:\x80\x02\x00\x00\x02\x00\x15selected·1\x00\x00" +
+ "\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" +
+ "\x15selectrecv2\x00\b\x17\"\xb6\x02\x00\x00\x1f\x02:\xfe\x01\x00\x00\x17:\x80\x02\x00\x00\x17\x00\x15rece" +
+ "ived·5\x00\x00\x02\x00\xb8\x02\x00\x00\t\x19selectdefault\x00\x02\x17\"\xb6\x02\x00\x00\x02\x00" +
+ "\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\n\vnel·3\x00\x00\n\vcap·4\x00\x00\x02\x11:\vary·" +
+ "1\x00\x00\t\x11growslice\x00\x06\x17\"\b\x00\x00\x11:\vold·3\x00\x00\x02\xca\x02\x00\x00\x02\x11:" +
+ "\xcc\x02\x00\x00\t\rmemmove\x00\x06\x17:\tto·1\x00\x00\x17:\vfrm·2\x00\x00\x16\x11le" +
+ "ngth·3\x00d\x00\t\vmemclr\x00\x04\x17\"\vptr·1\x00\x00\x16\x11length\xc2" +
+ "\xb72\x00d\x00\t\x0fmemequal\x00\x06\x17:\ax·2\x00\x00\x17:\ay·3\x00\x00\x16\rsiz" +
+ "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" +
+ "emequal16\x00\x04\x17:\xe2\x02\x00\x00\x17:\xe4\x02\x00\x00\x01\x00\x00\t\x13memequal32\x00\x04" +
+ "\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\x01\x00\x00\t\x15memequal128\x00\x04\x17:\xe2\x02\x00\x00\x17:\xe4\x02\x00\x00\x01\x00\x00\t\x0fint6" +
+ "4div\x00\x03\n\x00\n\x00\x01\n\x00\t\x11uint64div\x00\x03\x14\x00\x14\x00\x01\x14\x00\t\x0fint64" +
+ "mod\x00\x03\n\x00\n\x00\x01\n\x00\t\x11uint64mod\x00\x03\x14\x00\x14\x00\x01\x14\x00\t\x1bfloat6" +
+ "4toint64\x00\x01\x1a\x00\x01\n\x00\t\x1dfloat64touint64\x00\x01\x1a\x00\x01\x14\x00\t" +
+ "\x1bint64tofloat64\x00\x01\n\x00\x01\x1a\x00\t\x1duint64tofloat64\x00" +
+ "\x01\x14\x00\x01\x1a\x00\t\x19complex128div\x00\x04\x1e\vnum·2\x00\x00\x1e\vden·" +
+ "3\x00\x00\x02\x1e\vquo·1\x00\x00\t\x19racefuncenter\x00\x01\x16d\x00\t\x17race" +
+ "funcexit\x00\x00\x00\t\x0fraceread\x00\x01\x16d\x00\t\x11racewrite\x00\x01\x16" +
+ "d\x00\t\x19racereadrange\x00\x04\x16\raddr·1\x00d\x16\rsize·2\x00" +
+ "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 = "" +
- "c\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" +
- "\x01\x00\n$$\n"
+ "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\x01\x00\n$$\n"
case ODOT,
ODOTPTR,
OINDEX,
- OIND,
- ONAME: // PHEAP or PPARAMREF var
+ OIND:
var n1 Node
Igen(n, &n1, res)
switch n.Op {
default:
+ Dump("bad agen", n)
Fatalf("agen: unknown op %v", Nconv(n, FmtShort|FmtSign))
case OCALLMETH:
Thearch.Gmove(&n1, res)
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:
Cgen(nl, res)
if !nl.NonNil {
switch n.Op {
case ONAME:
- if (n.Class&PHEAP != 0) || n.Class == PPARAMREF {
- break
+ if n.Class == PAUTOHEAP {
+ Dump("igen", n)
+ Fatalf("bad name")
}
*a = *n
return
a.Type = n.Type
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:
+ // 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 Isconst(n.Right, CTINT) {
// Compute &a.
// unhook them.
// make the list of pointers for the closure call.
for _, v := range func_.Func.Cvars.Slice() {
- v.Name.Param.Closure.Name.Param.Closure = v.Name.Param.Outer
- v.Name.Param.Outerexpr = oldname(v.Sym)
+ // Unlink from v1; see comment in syntax.go type Param for these fields.
+ 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_
func typecheckclosure(func_ *Node, top int) {
for _, ln := range func_.Func.Cvars.Slice() {
- n := ln.Name.Param.Closure
+ n := ln.Name.Defn
if !n.Name.Captured {
n.Name.Captured = true
if n.Name.Decldepth == 0 {
// We use value capturing for values <= 128 bytes that are never reassigned
// after capturing (effectively constant).
func capturevars(xfunc *Node) {
- var outer *Node
-
lno := lineno
lineno = xfunc.Lineno
// so that the outer frame also grabs them and knows they escape.
dowidth(v.Type)
- outer = v.Name.Param.Outerexpr
- v.Name.Param.Outerexpr = nil
+ outer := v.Name.Param.Outer
+ outermost := v.Name.Defn
// 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
} else {
- v.Name.Param.Closure.Addrtaken = true
+ outermost.Addrtaken = true
outer = Nod(OADDR, outer, nil)
}
if v.Name.Byval {
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)
continue
}
fld := newField()
- fld.Funarg = true
+ fld.Funarg = FunargParams
if v.Name.Byval {
// If v is captured by value, we merely downgrade it to PPARAM.
v.Class = PPARAM
} else {
// If v of type T is captured by reference,
// 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).
addr := newname(Lookupf("&%s", v.Sym.Name))
addr.Type = Ptrto(v.Type)
--- /dev/null
+package gc
+
+import "testing"
+
+func TestConstFolduint64add(t *testing.T) {
+ var x, y, r uint64
+ x = 0
+ y = 0
+ r = x + y
+ if r != 0 {
+ t.Errorf("0 + 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x + y
+ if r != 1 {
+ t.Errorf("0 + 1 = %d, want 1", r)
+ }
+ y = 4294967296
+ r = x + y
+ if r != 4294967296 {
+ t.Errorf("0 + 4294967296 = %d, want 4294967296", r)
+ }
+ y = 18446744073709551615
+ r = x + y
+ if r != 18446744073709551615 {
+ t.Errorf("0 + 18446744073709551615 = %d, want 18446744073709551615", r)
+ }
+ x = 1
+ y = 0
+ r = x + y
+ if r != 1 {
+ t.Errorf("1 + 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x + y
+ if r != 2 {
+ t.Errorf("1 + 1 = %d, want 2", r)
+ }
+ y = 4294967296
+ r = x + y
+ if r != 4294967297 {
+ t.Errorf("1 + 4294967296 = %d, want 4294967297", r)
+ }
+ y = 18446744073709551615
+ r = x + y
+ if r != 0 {
+ t.Errorf("1 + 18446744073709551615 = %d, want 0", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x + y
+ if r != 4294967296 {
+ t.Errorf("4294967296 + 0 = %d, want 4294967296", r)
+ }
+ y = 1
+ r = x + y
+ if r != 4294967297 {
+ t.Errorf("4294967296 + 1 = %d, want 4294967297", r)
+ }
+ y = 4294967296
+ r = x + y
+ if r != 8589934592 {
+ t.Errorf("4294967296 + 4294967296 = %d, want 8589934592", r)
+ }
+ y = 18446744073709551615
+ r = x + y
+ if r != 4294967295 {
+ t.Errorf("4294967296 + 18446744073709551615 = %d, want 4294967295", r)
+ }
+ x = 18446744073709551615
+ y = 0
+ r = x + y
+ if r != 18446744073709551615 {
+ t.Errorf("18446744073709551615 + 0 = %d, want 18446744073709551615", r)
+ }
+ y = 1
+ r = x + y
+ if r != 0 {
+ t.Errorf("18446744073709551615 + 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x + y
+ if r != 4294967295 {
+ t.Errorf("18446744073709551615 + 4294967296 = %d, want 4294967295", r)
+ }
+ y = 18446744073709551615
+ r = x + y
+ if r != 18446744073709551614 {
+ t.Errorf("18446744073709551615 + 18446744073709551615 = %d, want 18446744073709551614", r)
+ }
+}
+func TestConstFolduint64sub(t *testing.T) {
+ var x, y, r uint64
+ x = 0
+ y = 0
+ r = x - y
+ if r != 0 {
+ t.Errorf("0 - 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x - y
+ if r != 18446744073709551615 {
+ t.Errorf("0 - 1 = %d, want 18446744073709551615", r)
+ }
+ y = 4294967296
+ r = x - y
+ if r != 18446744069414584320 {
+ t.Errorf("0 - 4294967296 = %d, want 18446744069414584320", r)
+ }
+ y = 18446744073709551615
+ r = x - y
+ if r != 1 {
+ t.Errorf("0 - 18446744073709551615 = %d, want 1", r)
+ }
+ x = 1
+ y = 0
+ r = x - y
+ if r != 1 {
+ t.Errorf("1 - 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x - y
+ if r != 0 {
+ t.Errorf("1 - 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x - y
+ if r != 18446744069414584321 {
+ t.Errorf("1 - 4294967296 = %d, want 18446744069414584321", r)
+ }
+ y = 18446744073709551615
+ r = x - y
+ if r != 2 {
+ t.Errorf("1 - 18446744073709551615 = %d, want 2", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x - y
+ if r != 4294967296 {
+ t.Errorf("4294967296 - 0 = %d, want 4294967296", r)
+ }
+ y = 1
+ r = x - y
+ if r != 4294967295 {
+ t.Errorf("4294967296 - 1 = %d, want 4294967295", r)
+ }
+ y = 4294967296
+ r = x - y
+ if r != 0 {
+ t.Errorf("4294967296 - 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x - y
+ if r != 4294967297 {
+ t.Errorf("4294967296 - 18446744073709551615 = %d, want 4294967297", r)
+ }
+ x = 18446744073709551615
+ y = 0
+ r = x - y
+ if r != 18446744073709551615 {
+ t.Errorf("18446744073709551615 - 0 = %d, want 18446744073709551615", r)
+ }
+ y = 1
+ r = x - y
+ if r != 18446744073709551614 {
+ t.Errorf("18446744073709551615 - 1 = %d, want 18446744073709551614", r)
+ }
+ y = 4294967296
+ r = x - y
+ if r != 18446744069414584319 {
+ t.Errorf("18446744073709551615 - 4294967296 = %d, want 18446744069414584319", r)
+ }
+ y = 18446744073709551615
+ r = x - y
+ if r != 0 {
+ t.Errorf("18446744073709551615 - 18446744073709551615 = %d, want 0", r)
+ }
+}
+func TestConstFolduint64div(t *testing.T) {
+ var x, y, r uint64
+ x = 0
+ y = 1
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / 18446744073709551615 = %d, want 0", r)
+ }
+ x = 1
+ y = 1
+ r = x / y
+ if r != 1 {
+ t.Errorf("1 / 1 = %d, want 1", r)
+ }
+ y = 4294967296
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 / 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 / 18446744073709551615 = %d, want 0", r)
+ }
+ x = 4294967296
+ y = 1
+ r = x / y
+ if r != 4294967296 {
+ t.Errorf("4294967296 / 1 = %d, want 4294967296", r)
+ }
+ y = 4294967296
+ r = x / y
+ if r != 1 {
+ t.Errorf("4294967296 / 4294967296 = %d, want 1", r)
+ }
+ y = 18446744073709551615
+ r = x / y
+ if r != 0 {
+ t.Errorf("4294967296 / 18446744073709551615 = %d, want 0", r)
+ }
+ x = 18446744073709551615
+ y = 1
+ r = x / y
+ if r != 18446744073709551615 {
+ t.Errorf("18446744073709551615 / 1 = %d, want 18446744073709551615", r)
+ }
+ y = 4294967296
+ r = x / y
+ if r != 4294967295 {
+ t.Errorf("18446744073709551615 / 4294967296 = %d, want 4294967295", r)
+ }
+ y = 18446744073709551615
+ r = x / y
+ if r != 1 {
+ t.Errorf("18446744073709551615 / 18446744073709551615 = %d, want 1", r)
+ }
+}
+func TestConstFolduint64mul(t *testing.T) {
+ var x, y, r uint64
+ x = 0
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * 18446744073709551615 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("1 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != 1 {
+ t.Errorf("1 * 1 = %d, want 1", r)
+ }
+ y = 4294967296
+ r = x * y
+ if r != 4294967296 {
+ t.Errorf("1 * 4294967296 = %d, want 4294967296", r)
+ }
+ y = 18446744073709551615
+ r = x * y
+ if r != 18446744073709551615 {
+ t.Errorf("1 * 18446744073709551615 = %d, want 18446744073709551615", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("4294967296 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != 4294967296 {
+ t.Errorf("4294967296 * 1 = %d, want 4294967296", r)
+ }
+ y = 4294967296
+ r = x * y
+ if r != 0 {
+ t.Errorf("4294967296 * 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x * y
+ if r != 18446744069414584320 {
+ t.Errorf("4294967296 * 18446744073709551615 = %d, want 18446744069414584320", r)
+ }
+ x = 18446744073709551615
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("18446744073709551615 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != 18446744073709551615 {
+ t.Errorf("18446744073709551615 * 1 = %d, want 18446744073709551615", r)
+ }
+ y = 4294967296
+ r = x * y
+ if r != 18446744069414584320 {
+ t.Errorf("18446744073709551615 * 4294967296 = %d, want 18446744069414584320", r)
+ }
+ y = 18446744073709551615
+ r = x * y
+ if r != 1 {
+ t.Errorf("18446744073709551615 * 18446744073709551615 = %d, want 1", r)
+ }
+}
+func TestConstFolduint64mod(t *testing.T) {
+ var x, y, r uint64
+ x = 0
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % 18446744073709551615 = %d, want 0", r)
+ }
+ x = 1
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("1 % 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 % 4294967296 = %d, want 1", r)
+ }
+ y = 18446744073709551615
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 % 18446744073709551615 = %d, want 1", r)
+ }
+ x = 4294967296
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("4294967296 % 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x % y
+ if r != 0 {
+ t.Errorf("4294967296 % 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x % y
+ if r != 4294967296 {
+ t.Errorf("4294967296 % 18446744073709551615 = %d, want 4294967296", r)
+ }
+ x = 18446744073709551615
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("18446744073709551615 % 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x % y
+ if r != 4294967295 {
+ t.Errorf("18446744073709551615 % 4294967296 = %d, want 4294967295", r)
+ }
+ y = 18446744073709551615
+ r = x % y
+ if r != 0 {
+ t.Errorf("18446744073709551615 % 18446744073709551615 = %d, want 0", r)
+ }
+}
+func TestConstFoldint64add(t *testing.T) {
+ var x, y, r int64
+ x = -9223372036854775808
+ y = -9223372036854775808
+ r = x + y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 + -9223372036854775808 = %d, want 0", r)
+ }
+ y = -9223372036854775807
+ r = x + y
+ if r != 1 {
+ t.Errorf("-9223372036854775808 + -9223372036854775807 = %d, want 1", r)
+ }
+ y = -4294967296
+ r = x + y
+ if r != 9223372032559808512 {
+ t.Errorf("-9223372036854775808 + -4294967296 = %d, want 9223372032559808512", r)
+ }
+ y = -1
+ r = x + y
+ if r != 9223372036854775807 {
+ t.Errorf("-9223372036854775808 + -1 = %d, want 9223372036854775807", r)
+ }
+ y = 0
+ r = x + y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 + 0 = %d, want -9223372036854775808", r)
+ }
+ y = 1
+ r = x + y
+ if r != -9223372036854775807 {
+ t.Errorf("-9223372036854775808 + 1 = %d, want -9223372036854775807", r)
+ }
+ y = 4294967296
+ r = x + y
+ if r != -9223372032559808512 {
+ t.Errorf("-9223372036854775808 + 4294967296 = %d, want -9223372032559808512", r)
+ }
+ y = 9223372036854775806
+ r = x + y
+ if r != -2 {
+ t.Errorf("-9223372036854775808 + 9223372036854775806 = %d, want -2", r)
+ }
+ y = 9223372036854775807
+ r = x + y
+ if r != -1 {
+ t.Errorf("-9223372036854775808 + 9223372036854775807 = %d, want -1", r)
+ }
+ x = -9223372036854775807
+ y = -9223372036854775808
+ r = x + y
+ if r != 1 {
+ t.Errorf("-9223372036854775807 + -9223372036854775808 = %d, want 1", r)
+ }
+ y = -9223372036854775807
+ r = x + y
+ if r != 2 {
+ t.Errorf("-9223372036854775807 + -9223372036854775807 = %d, want 2", r)
+ }
+ y = -4294967296
+ r = x + y
+ if r != 9223372032559808513 {
+ t.Errorf("-9223372036854775807 + -4294967296 = %d, want 9223372032559808513", r)
+ }
+ y = -1
+ r = x + y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775807 + -1 = %d, want -9223372036854775808", r)
+ }
+ y = 0
+ r = x + y
+ if r != -9223372036854775807 {
+ t.Errorf("-9223372036854775807 + 0 = %d, want -9223372036854775807", r)
+ }
+ y = 1
+ r = x + y
+ if r != -9223372036854775806 {
+ t.Errorf("-9223372036854775807 + 1 = %d, want -9223372036854775806", r)
+ }
+ y = 4294967296
+ r = x + y
+ if r != -9223372032559808511 {
+ t.Errorf("-9223372036854775807 + 4294967296 = %d, want -9223372032559808511", r)
+ }
+ y = 9223372036854775806
+ r = x + y
+ if r != -1 {
+ t.Errorf("-9223372036854775807 + 9223372036854775806 = %d, want -1", r)
+ }
+ y = 9223372036854775807
+ r = x + y
+ if r != 0 {
+ t.Errorf("-9223372036854775807 + 9223372036854775807 = %d, want 0", r)
+ }
+ x = -4294967296
+ y = -9223372036854775808
+ r = x + y
+ if r != 9223372032559808512 {
+ t.Errorf("-4294967296 + -9223372036854775808 = %d, want 9223372032559808512", r)
+ }
+ y = -9223372036854775807
+ r = x + y
+ if r != 9223372032559808513 {
+ t.Errorf("-4294967296 + -9223372036854775807 = %d, want 9223372032559808513", r)
+ }
+ y = -4294967296
+ r = x + y
+ if r != -8589934592 {
+ t.Errorf("-4294967296 + -4294967296 = %d, want -8589934592", r)
+ }
+ y = -1
+ r = x + y
+ if r != -4294967297 {
+ t.Errorf("-4294967296 + -1 = %d, want -4294967297", r)
+ }
+ y = 0
+ r = x + y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 + 0 = %d, want -4294967296", r)
+ }
+ y = 1
+ r = x + y
+ if r != -4294967295 {
+ t.Errorf("-4294967296 + 1 = %d, want -4294967295", r)
+ }
+ y = 4294967296
+ r = x + y
+ if r != 0 {
+ t.Errorf("-4294967296 + 4294967296 = %d, want 0", r)
+ }
+ y = 9223372036854775806
+ r = x + y
+ if r != 9223372032559808510 {
+ t.Errorf("-4294967296 + 9223372036854775806 = %d, want 9223372032559808510", r)
+ }
+ y = 9223372036854775807
+ r = x + y
+ if r != 9223372032559808511 {
+ t.Errorf("-4294967296 + 9223372036854775807 = %d, want 9223372032559808511", r)
+ }
+ x = -1
+ y = -9223372036854775808
+ r = x + y
+ if r != 9223372036854775807 {
+ t.Errorf("-1 + -9223372036854775808 = %d, want 9223372036854775807", r)
+ }
+ y = -9223372036854775807
+ r = x + y
+ if r != -9223372036854775808 {
+ t.Errorf("-1 + -9223372036854775807 = %d, want -9223372036854775808", r)
+ }
+ y = -4294967296
+ r = x + y
+ if r != -4294967297 {
+ t.Errorf("-1 + -4294967296 = %d, want -4294967297", r)
+ }
+ y = -1
+ r = x + y
+ if r != -2 {
+ t.Errorf("-1 + -1 = %d, want -2", r)
+ }
+ y = 0
+ r = x + y
+ if r != -1 {
+ t.Errorf("-1 + 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x + y
+ if r != 0 {
+ t.Errorf("-1 + 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x + y
+ if r != 4294967295 {
+ t.Errorf("-1 + 4294967296 = %d, want 4294967295", r)
+ }
+ y = 9223372036854775806
+ r = x + y
+ if r != 9223372036854775805 {
+ t.Errorf("-1 + 9223372036854775806 = %d, want 9223372036854775805", r)
+ }
+ y = 9223372036854775807
+ r = x + y
+ if r != 9223372036854775806 {
+ t.Errorf("-1 + 9223372036854775807 = %d, want 9223372036854775806", r)
+ }
+ x = 0
+ y = -9223372036854775808
+ r = x + y
+ if r != -9223372036854775808 {
+ t.Errorf("0 + -9223372036854775808 = %d, want -9223372036854775808", r)
+ }
+ y = -9223372036854775807
+ r = x + y
+ if r != -9223372036854775807 {
+ t.Errorf("0 + -9223372036854775807 = %d, want -9223372036854775807", r)
+ }
+ y = -4294967296
+ r = x + y
+ if r != -4294967296 {
+ t.Errorf("0 + -4294967296 = %d, want -4294967296", r)
+ }
+ y = -1
+ r = x + y
+ if r != -1 {
+ t.Errorf("0 + -1 = %d, want -1", r)
+ }
+ y = 0
+ r = x + y
+ if r != 0 {
+ t.Errorf("0 + 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x + y
+ if r != 1 {
+ t.Errorf("0 + 1 = %d, want 1", r)
+ }
+ y = 4294967296
+ r = x + y
+ if r != 4294967296 {
+ t.Errorf("0 + 4294967296 = %d, want 4294967296", r)
+ }
+ y = 9223372036854775806
+ r = x + y
+ if r != 9223372036854775806 {
+ t.Errorf("0 + 9223372036854775806 = %d, want 9223372036854775806", r)
+ }
+ y = 9223372036854775807
+ r = x + y
+ if r != 9223372036854775807 {
+ t.Errorf("0 + 9223372036854775807 = %d, want 9223372036854775807", r)
+ }
+ x = 1
+ y = -9223372036854775808
+ r = x + y
+ if r != -9223372036854775807 {
+ t.Errorf("1 + -9223372036854775808 = %d, want -9223372036854775807", r)
+ }
+ y = -9223372036854775807
+ r = x + y
+ if r != -9223372036854775806 {
+ t.Errorf("1 + -9223372036854775807 = %d, want -9223372036854775806", r)
+ }
+ y = -4294967296
+ r = x + y
+ if r != -4294967295 {
+ t.Errorf("1 + -4294967296 = %d, want -4294967295", r)
+ }
+ y = -1
+ r = x + y
+ if r != 0 {
+ t.Errorf("1 + -1 = %d, want 0", r)
+ }
+ y = 0
+ r = x + y
+ if r != 1 {
+ t.Errorf("1 + 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x + y
+ if r != 2 {
+ t.Errorf("1 + 1 = %d, want 2", r)
+ }
+ y = 4294967296
+ r = x + y
+ if r != 4294967297 {
+ t.Errorf("1 + 4294967296 = %d, want 4294967297", r)
+ }
+ y = 9223372036854775806
+ r = x + y
+ if r != 9223372036854775807 {
+ t.Errorf("1 + 9223372036854775806 = %d, want 9223372036854775807", r)
+ }
+ y = 9223372036854775807
+ r = x + y
+ if r != -9223372036854775808 {
+ t.Errorf("1 + 9223372036854775807 = %d, want -9223372036854775808", r)
+ }
+ x = 4294967296
+ y = -9223372036854775808
+ r = x + y
+ if r != -9223372032559808512 {
+ t.Errorf("4294967296 + -9223372036854775808 = %d, want -9223372032559808512", r)
+ }
+ y = -9223372036854775807
+ r = x + y
+ if r != -9223372032559808511 {
+ t.Errorf("4294967296 + -9223372036854775807 = %d, want -9223372032559808511", r)
+ }
+ y = -4294967296
+ r = x + y
+ if r != 0 {
+ t.Errorf("4294967296 + -4294967296 = %d, want 0", r)
+ }
+ y = -1
+ r = x + y
+ if r != 4294967295 {
+ t.Errorf("4294967296 + -1 = %d, want 4294967295", r)
+ }
+ y = 0
+ r = x + y
+ if r != 4294967296 {
+ t.Errorf("4294967296 + 0 = %d, want 4294967296", r)
+ }
+ y = 1
+ r = x + y
+ if r != 4294967297 {
+ t.Errorf("4294967296 + 1 = %d, want 4294967297", r)
+ }
+ y = 4294967296
+ r = x + y
+ if r != 8589934592 {
+ t.Errorf("4294967296 + 4294967296 = %d, want 8589934592", r)
+ }
+ y = 9223372036854775806
+ r = x + y
+ if r != -9223372032559808514 {
+ t.Errorf("4294967296 + 9223372036854775806 = %d, want -9223372032559808514", r)
+ }
+ y = 9223372036854775807
+ r = x + y
+ if r != -9223372032559808513 {
+ t.Errorf("4294967296 + 9223372036854775807 = %d, want -9223372032559808513", r)
+ }
+ x = 9223372036854775806
+ y = -9223372036854775808
+ r = x + y
+ if r != -2 {
+ t.Errorf("9223372036854775806 + -9223372036854775808 = %d, want -2", r)
+ }
+ y = -9223372036854775807
+ r = x + y
+ if r != -1 {
+ t.Errorf("9223372036854775806 + -9223372036854775807 = %d, want -1", r)
+ }
+ y = -4294967296
+ r = x + y
+ if r != 9223372032559808510 {
+ t.Errorf("9223372036854775806 + -4294967296 = %d, want 9223372032559808510", r)
+ }
+ y = -1
+ r = x + y
+ if r != 9223372036854775805 {
+ t.Errorf("9223372036854775806 + -1 = %d, want 9223372036854775805", r)
+ }
+ y = 0
+ r = x + y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 + 0 = %d, want 9223372036854775806", r)
+ }
+ y = 1
+ r = x + y
+ if r != 9223372036854775807 {
+ t.Errorf("9223372036854775806 + 1 = %d, want 9223372036854775807", r)
+ }
+ y = 4294967296
+ r = x + y
+ if r != -9223372032559808514 {
+ t.Errorf("9223372036854775806 + 4294967296 = %d, want -9223372032559808514", r)
+ }
+ y = 9223372036854775806
+ r = x + y
+ if r != -4 {
+ t.Errorf("9223372036854775806 + 9223372036854775806 = %d, want -4", r)
+ }
+ y = 9223372036854775807
+ r = x + y
+ if r != -3 {
+ t.Errorf("9223372036854775806 + 9223372036854775807 = %d, want -3", r)
+ }
+ x = 9223372036854775807
+ y = -9223372036854775808
+ r = x + y
+ if r != -1 {
+ t.Errorf("9223372036854775807 + -9223372036854775808 = %d, want -1", r)
+ }
+ y = -9223372036854775807
+ r = x + y
+ if r != 0 {
+ t.Errorf("9223372036854775807 + -9223372036854775807 = %d, want 0", r)
+ }
+ y = -4294967296
+ r = x + y
+ if r != 9223372032559808511 {
+ t.Errorf("9223372036854775807 + -4294967296 = %d, want 9223372032559808511", r)
+ }
+ y = -1
+ r = x + y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775807 + -1 = %d, want 9223372036854775806", r)
+ }
+ y = 0
+ r = x + y
+ if r != 9223372036854775807 {
+ t.Errorf("9223372036854775807 + 0 = %d, want 9223372036854775807", r)
+ }
+ y = 1
+ r = x + y
+ if r != -9223372036854775808 {
+ t.Errorf("9223372036854775807 + 1 = %d, want -9223372036854775808", r)
+ }
+ y = 4294967296
+ r = x + y
+ if r != -9223372032559808513 {
+ t.Errorf("9223372036854775807 + 4294967296 = %d, want -9223372032559808513", r)
+ }
+ y = 9223372036854775806
+ r = x + y
+ if r != -3 {
+ t.Errorf("9223372036854775807 + 9223372036854775806 = %d, want -3", r)
+ }
+ y = 9223372036854775807
+ r = x + y
+ if r != -2 {
+ t.Errorf("9223372036854775807 + 9223372036854775807 = %d, want -2", r)
+ }
+}
+func TestConstFoldint64sub(t *testing.T) {
+ var x, y, r int64
+ x = -9223372036854775808
+ y = -9223372036854775808
+ r = x - y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 - -9223372036854775808 = %d, want 0", r)
+ }
+ y = -9223372036854775807
+ r = x - y
+ if r != -1 {
+ t.Errorf("-9223372036854775808 - -9223372036854775807 = %d, want -1", r)
+ }
+ y = -4294967296
+ r = x - y
+ if r != -9223372032559808512 {
+ t.Errorf("-9223372036854775808 - -4294967296 = %d, want -9223372032559808512", r)
+ }
+ y = -1
+ r = x - y
+ if r != -9223372036854775807 {
+ t.Errorf("-9223372036854775808 - -1 = %d, want -9223372036854775807", r)
+ }
+ y = 0
+ r = x - y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 - 0 = %d, want -9223372036854775808", r)
+ }
+ y = 1
+ r = x - y
+ if r != 9223372036854775807 {
+ t.Errorf("-9223372036854775808 - 1 = %d, want 9223372036854775807", r)
+ }
+ y = 4294967296
+ r = x - y
+ if r != 9223372032559808512 {
+ t.Errorf("-9223372036854775808 - 4294967296 = %d, want 9223372032559808512", r)
+ }
+ y = 9223372036854775806
+ r = x - y
+ if r != 2 {
+ t.Errorf("-9223372036854775808 - 9223372036854775806 = %d, want 2", r)
+ }
+ y = 9223372036854775807
+ r = x - y
+ if r != 1 {
+ t.Errorf("-9223372036854775808 - 9223372036854775807 = %d, want 1", r)
+ }
+ x = -9223372036854775807
+ y = -9223372036854775808
+ r = x - y
+ if r != 1 {
+ t.Errorf("-9223372036854775807 - -9223372036854775808 = %d, want 1", r)
+ }
+ y = -9223372036854775807
+ r = x - y
+ if r != 0 {
+ t.Errorf("-9223372036854775807 - -9223372036854775807 = %d, want 0", r)
+ }
+ y = -4294967296
+ r = x - y
+ if r != -9223372032559808511 {
+ t.Errorf("-9223372036854775807 - -4294967296 = %d, want -9223372032559808511", r)
+ }
+ y = -1
+ r = x - y
+ if r != -9223372036854775806 {
+ t.Errorf("-9223372036854775807 - -1 = %d, want -9223372036854775806", r)
+ }
+ y = 0
+ r = x - y
+ if r != -9223372036854775807 {
+ t.Errorf("-9223372036854775807 - 0 = %d, want -9223372036854775807", r)
+ }
+ y = 1
+ r = x - y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775807 - 1 = %d, want -9223372036854775808", r)
+ }
+ y = 4294967296
+ r = x - y
+ if r != 9223372032559808513 {
+ t.Errorf("-9223372036854775807 - 4294967296 = %d, want 9223372032559808513", r)
+ }
+ y = 9223372036854775806
+ r = x - y
+ if r != 3 {
+ t.Errorf("-9223372036854775807 - 9223372036854775806 = %d, want 3", r)
+ }
+ y = 9223372036854775807
+ r = x - y
+ if r != 2 {
+ t.Errorf("-9223372036854775807 - 9223372036854775807 = %d, want 2", r)
+ }
+ x = -4294967296
+ y = -9223372036854775808
+ r = x - y
+ if r != 9223372032559808512 {
+ t.Errorf("-4294967296 - -9223372036854775808 = %d, want 9223372032559808512", r)
+ }
+ y = -9223372036854775807
+ r = x - y
+ if r != 9223372032559808511 {
+ t.Errorf("-4294967296 - -9223372036854775807 = %d, want 9223372032559808511", r)
+ }
+ y = -4294967296
+ r = x - y
+ if r != 0 {
+ t.Errorf("-4294967296 - -4294967296 = %d, want 0", r)
+ }
+ y = -1
+ r = x - y
+ if r != -4294967295 {
+ t.Errorf("-4294967296 - -1 = %d, want -4294967295", r)
+ }
+ y = 0
+ r = x - y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 - 0 = %d, want -4294967296", r)
+ }
+ y = 1
+ r = x - y
+ if r != -4294967297 {
+ t.Errorf("-4294967296 - 1 = %d, want -4294967297", r)
+ }
+ y = 4294967296
+ r = x - y
+ if r != -8589934592 {
+ t.Errorf("-4294967296 - 4294967296 = %d, want -8589934592", r)
+ }
+ y = 9223372036854775806
+ r = x - y
+ if r != 9223372032559808514 {
+ t.Errorf("-4294967296 - 9223372036854775806 = %d, want 9223372032559808514", r)
+ }
+ y = 9223372036854775807
+ r = x - y
+ if r != 9223372032559808513 {
+ t.Errorf("-4294967296 - 9223372036854775807 = %d, want 9223372032559808513", r)
+ }
+ x = -1
+ y = -9223372036854775808
+ r = x - y
+ if r != 9223372036854775807 {
+ t.Errorf("-1 - -9223372036854775808 = %d, want 9223372036854775807", r)
+ }
+ y = -9223372036854775807
+ r = x - y
+ if r != 9223372036854775806 {
+ t.Errorf("-1 - -9223372036854775807 = %d, want 9223372036854775806", r)
+ }
+ y = -4294967296
+ r = x - y
+ if r != 4294967295 {
+ t.Errorf("-1 - -4294967296 = %d, want 4294967295", r)
+ }
+ y = -1
+ r = x - y
+ if r != 0 {
+ t.Errorf("-1 - -1 = %d, want 0", r)
+ }
+ y = 0
+ r = x - y
+ if r != -1 {
+ t.Errorf("-1 - 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x - y
+ if r != -2 {
+ t.Errorf("-1 - 1 = %d, want -2", r)
+ }
+ y = 4294967296
+ r = x - y
+ if r != -4294967297 {
+ t.Errorf("-1 - 4294967296 = %d, want -4294967297", r)
+ }
+ y = 9223372036854775806
+ r = x - y
+ if r != -9223372036854775807 {
+ t.Errorf("-1 - 9223372036854775806 = %d, want -9223372036854775807", r)
+ }
+ y = 9223372036854775807
+ r = x - y
+ if r != -9223372036854775808 {
+ t.Errorf("-1 - 9223372036854775807 = %d, want -9223372036854775808", r)
+ }
+ x = 0
+ y = -9223372036854775808
+ r = x - y
+ if r != -9223372036854775808 {
+ t.Errorf("0 - -9223372036854775808 = %d, want -9223372036854775808", r)
+ }
+ y = -9223372036854775807
+ r = x - y
+ if r != 9223372036854775807 {
+ t.Errorf("0 - -9223372036854775807 = %d, want 9223372036854775807", r)
+ }
+ y = -4294967296
+ r = x - y
+ if r != 4294967296 {
+ t.Errorf("0 - -4294967296 = %d, want 4294967296", r)
+ }
+ y = -1
+ r = x - y
+ if r != 1 {
+ t.Errorf("0 - -1 = %d, want 1", r)
+ }
+ y = 0
+ r = x - y
+ if r != 0 {
+ t.Errorf("0 - 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x - y
+ if r != -1 {
+ t.Errorf("0 - 1 = %d, want -1", r)
+ }
+ y = 4294967296
+ r = x - y
+ if r != -4294967296 {
+ t.Errorf("0 - 4294967296 = %d, want -4294967296", r)
+ }
+ y = 9223372036854775806
+ r = x - y
+ if r != -9223372036854775806 {
+ t.Errorf("0 - 9223372036854775806 = %d, want -9223372036854775806", r)
+ }
+ y = 9223372036854775807
+ r = x - y
+ if r != -9223372036854775807 {
+ t.Errorf("0 - 9223372036854775807 = %d, want -9223372036854775807", r)
+ }
+ x = 1
+ y = -9223372036854775808
+ r = x - y
+ if r != -9223372036854775807 {
+ t.Errorf("1 - -9223372036854775808 = %d, want -9223372036854775807", r)
+ }
+ y = -9223372036854775807
+ r = x - y
+ if r != -9223372036854775808 {
+ t.Errorf("1 - -9223372036854775807 = %d, want -9223372036854775808", r)
+ }
+ y = -4294967296
+ r = x - y
+ if r != 4294967297 {
+ t.Errorf("1 - -4294967296 = %d, want 4294967297", r)
+ }
+ y = -1
+ r = x - y
+ if r != 2 {
+ t.Errorf("1 - -1 = %d, want 2", r)
+ }
+ y = 0
+ r = x - y
+ if r != 1 {
+ t.Errorf("1 - 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x - y
+ if r != 0 {
+ t.Errorf("1 - 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x - y
+ if r != -4294967295 {
+ t.Errorf("1 - 4294967296 = %d, want -4294967295", r)
+ }
+ y = 9223372036854775806
+ r = x - y
+ if r != -9223372036854775805 {
+ t.Errorf("1 - 9223372036854775806 = %d, want -9223372036854775805", r)
+ }
+ y = 9223372036854775807
+ r = x - y
+ if r != -9223372036854775806 {
+ t.Errorf("1 - 9223372036854775807 = %d, want -9223372036854775806", r)
+ }
+ x = 4294967296
+ y = -9223372036854775808
+ r = x - y
+ if r != -9223372032559808512 {
+ t.Errorf("4294967296 - -9223372036854775808 = %d, want -9223372032559808512", r)
+ }
+ y = -9223372036854775807
+ r = x - y
+ if r != -9223372032559808513 {
+ t.Errorf("4294967296 - -9223372036854775807 = %d, want -9223372032559808513", r)
+ }
+ y = -4294967296
+ r = x - y
+ if r != 8589934592 {
+ t.Errorf("4294967296 - -4294967296 = %d, want 8589934592", r)
+ }
+ y = -1
+ r = x - y
+ if r != 4294967297 {
+ t.Errorf("4294967296 - -1 = %d, want 4294967297", r)
+ }
+ y = 0
+ r = x - y
+ if r != 4294967296 {
+ t.Errorf("4294967296 - 0 = %d, want 4294967296", r)
+ }
+ y = 1
+ r = x - y
+ if r != 4294967295 {
+ t.Errorf("4294967296 - 1 = %d, want 4294967295", r)
+ }
+ y = 4294967296
+ r = x - y
+ if r != 0 {
+ t.Errorf("4294967296 - 4294967296 = %d, want 0", r)
+ }
+ y = 9223372036854775806
+ r = x - y
+ if r != -9223372032559808510 {
+ t.Errorf("4294967296 - 9223372036854775806 = %d, want -9223372032559808510", r)
+ }
+ y = 9223372036854775807
+ r = x - y
+ if r != -9223372032559808511 {
+ t.Errorf("4294967296 - 9223372036854775807 = %d, want -9223372032559808511", r)
+ }
+ x = 9223372036854775806
+ y = -9223372036854775808
+ r = x - y
+ if r != -2 {
+ t.Errorf("9223372036854775806 - -9223372036854775808 = %d, want -2", r)
+ }
+ y = -9223372036854775807
+ r = x - y
+ if r != -3 {
+ t.Errorf("9223372036854775806 - -9223372036854775807 = %d, want -3", r)
+ }
+ y = -4294967296
+ r = x - y
+ if r != -9223372032559808514 {
+ t.Errorf("9223372036854775806 - -4294967296 = %d, want -9223372032559808514", r)
+ }
+ y = -1
+ r = x - y
+ if r != 9223372036854775807 {
+ t.Errorf("9223372036854775806 - -1 = %d, want 9223372036854775807", r)
+ }
+ y = 0
+ r = x - y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 - 0 = %d, want 9223372036854775806", r)
+ }
+ y = 1
+ r = x - y
+ if r != 9223372036854775805 {
+ t.Errorf("9223372036854775806 - 1 = %d, want 9223372036854775805", r)
+ }
+ y = 4294967296
+ r = x - y
+ if r != 9223372032559808510 {
+ t.Errorf("9223372036854775806 - 4294967296 = %d, want 9223372032559808510", r)
+ }
+ y = 9223372036854775806
+ r = x - y
+ if r != 0 {
+ t.Errorf("9223372036854775806 - 9223372036854775806 = %d, want 0", r)
+ }
+ y = 9223372036854775807
+ r = x - y
+ if r != -1 {
+ t.Errorf("9223372036854775806 - 9223372036854775807 = %d, want -1", r)
+ }
+ x = 9223372036854775807
+ y = -9223372036854775808
+ r = x - y
+ if r != -1 {
+ t.Errorf("9223372036854775807 - -9223372036854775808 = %d, want -1", r)
+ }
+ y = -9223372036854775807
+ r = x - y
+ if r != -2 {
+ t.Errorf("9223372036854775807 - -9223372036854775807 = %d, want -2", r)
+ }
+ y = -4294967296
+ r = x - y
+ if r != -9223372032559808513 {
+ t.Errorf("9223372036854775807 - -4294967296 = %d, want -9223372032559808513", r)
+ }
+ y = -1
+ r = x - y
+ if r != -9223372036854775808 {
+ t.Errorf("9223372036854775807 - -1 = %d, want -9223372036854775808", r)
+ }
+ y = 0
+ r = x - y
+ if r != 9223372036854775807 {
+ t.Errorf("9223372036854775807 - 0 = %d, want 9223372036854775807", r)
+ }
+ y = 1
+ r = x - y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775807 - 1 = %d, want 9223372036854775806", r)
+ }
+ y = 4294967296
+ r = x - y
+ if r != 9223372032559808511 {
+ t.Errorf("9223372036854775807 - 4294967296 = %d, want 9223372032559808511", r)
+ }
+ y = 9223372036854775806
+ r = x - y
+ if r != 1 {
+ t.Errorf("9223372036854775807 - 9223372036854775806 = %d, want 1", r)
+ }
+ y = 9223372036854775807
+ r = x - y
+ if r != 0 {
+ t.Errorf("9223372036854775807 - 9223372036854775807 = %d, want 0", r)
+ }
+}
+func TestConstFoldint64div(t *testing.T) {
+ var x, y, r int64
+ x = -9223372036854775808
+ y = -9223372036854775808
+ r = x / y
+ if r != 1 {
+ t.Errorf("-9223372036854775808 / -9223372036854775808 = %d, want 1", r)
+ }
+ y = -9223372036854775807
+ r = x / y
+ if r != 1 {
+ t.Errorf("-9223372036854775808 / -9223372036854775807 = %d, want 1", r)
+ }
+ y = -4294967296
+ r = x / y
+ if r != 2147483648 {
+ t.Errorf("-9223372036854775808 / -4294967296 = %d, want 2147483648", r)
+ }
+ y = -1
+ r = x / y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 / -1 = %d, want -9223372036854775808", r)
+ }
+ y = 1
+ r = x / y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 / 1 = %d, want -9223372036854775808", r)
+ }
+ y = 4294967296
+ r = x / y
+ if r != -2147483648 {
+ t.Errorf("-9223372036854775808 / 4294967296 = %d, want -2147483648", r)
+ }
+ y = 9223372036854775806
+ r = x / y
+ if r != -1 {
+ t.Errorf("-9223372036854775808 / 9223372036854775806 = %d, want -1", r)
+ }
+ y = 9223372036854775807
+ r = x / y
+ if r != -1 {
+ t.Errorf("-9223372036854775808 / 9223372036854775807 = %d, want -1", r)
+ }
+ x = -9223372036854775807
+ y = -9223372036854775808
+ r = x / y
+ if r != 0 {
+ t.Errorf("-9223372036854775807 / -9223372036854775808 = %d, want 0", r)
+ }
+ y = -9223372036854775807
+ r = x / y
+ if r != 1 {
+ t.Errorf("-9223372036854775807 / -9223372036854775807 = %d, want 1", r)
+ }
+ y = -4294967296
+ r = x / y
+ if r != 2147483647 {
+ t.Errorf("-9223372036854775807 / -4294967296 = %d, want 2147483647", r)
+ }
+ y = -1
+ r = x / y
+ if r != 9223372036854775807 {
+ t.Errorf("-9223372036854775807 / -1 = %d, want 9223372036854775807", r)
+ }
+ y = 1
+ r = x / y
+ if r != -9223372036854775807 {
+ t.Errorf("-9223372036854775807 / 1 = %d, want -9223372036854775807", r)
+ }
+ y = 4294967296
+ r = x / y
+ if r != -2147483647 {
+ t.Errorf("-9223372036854775807 / 4294967296 = %d, want -2147483647", r)
+ }
+ y = 9223372036854775806
+ r = x / y
+ if r != -1 {
+ t.Errorf("-9223372036854775807 / 9223372036854775806 = %d, want -1", r)
+ }
+ y = 9223372036854775807
+ r = x / y
+ if r != -1 {
+ t.Errorf("-9223372036854775807 / 9223372036854775807 = %d, want -1", r)
+ }
+ x = -4294967296
+ y = -9223372036854775808
+ r = x / y
+ if r != 0 {
+ t.Errorf("-4294967296 / -9223372036854775808 = %d, want 0", r)
+ }
+ y = -9223372036854775807
+ r = x / y
+ if r != 0 {
+ t.Errorf("-4294967296 / -9223372036854775807 = %d, want 0", r)
+ }
+ y = -4294967296
+ r = x / y
+ if r != 1 {
+ t.Errorf("-4294967296 / -4294967296 = %d, want 1", r)
+ }
+ y = -1
+ r = x / y
+ if r != 4294967296 {
+ t.Errorf("-4294967296 / -1 = %d, want 4294967296", r)
+ }
+ y = 1
+ r = x / y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 / 1 = %d, want -4294967296", r)
+ }
+ y = 4294967296
+ r = x / y
+ if r != -1 {
+ t.Errorf("-4294967296 / 4294967296 = %d, want -1", r)
+ }
+ y = 9223372036854775806
+ r = x / y
+ if r != 0 {
+ t.Errorf("-4294967296 / 9223372036854775806 = %d, want 0", r)
+ }
+ y = 9223372036854775807
+ r = x / y
+ if r != 0 {
+ t.Errorf("-4294967296 / 9223372036854775807 = %d, want 0", r)
+ }
+ x = -1
+ y = -9223372036854775808
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 / -9223372036854775808 = %d, want 0", r)
+ }
+ y = -9223372036854775807
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 / -9223372036854775807 = %d, want 0", r)
+ }
+ y = -4294967296
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 / -4294967296 = %d, want 0", r)
+ }
+ y = -1
+ r = x / y
+ if r != 1 {
+ t.Errorf("-1 / -1 = %d, want 1", r)
+ }
+ y = 1
+ r = x / y
+ if r != -1 {
+ t.Errorf("-1 / 1 = %d, want -1", r)
+ }
+ y = 4294967296
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 / 4294967296 = %d, want 0", r)
+ }
+ y = 9223372036854775806
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 / 9223372036854775806 = %d, want 0", r)
+ }
+ y = 9223372036854775807
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 / 9223372036854775807 = %d, want 0", r)
+ }
+ x = 0
+ y = -9223372036854775808
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / -9223372036854775808 = %d, want 0", r)
+ }
+ y = -9223372036854775807
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / -9223372036854775807 = %d, want 0", r)
+ }
+ y = -4294967296
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / -4294967296 = %d, want 0", r)
+ }
+ y = -1
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / 4294967296 = %d, want 0", r)
+ }
+ y = 9223372036854775806
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / 9223372036854775806 = %d, want 0", r)
+ }
+ y = 9223372036854775807
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / 9223372036854775807 = %d, want 0", r)
+ }
+ x = 1
+ y = -9223372036854775808
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 / -9223372036854775808 = %d, want 0", r)
+ }
+ y = -9223372036854775807
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 / -9223372036854775807 = %d, want 0", r)
+ }
+ y = -4294967296
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 / -4294967296 = %d, want 0", r)
+ }
+ y = -1
+ r = x / y
+ if r != -1 {
+ t.Errorf("1 / -1 = %d, want -1", r)
+ }
+ y = 1
+ r = x / y
+ if r != 1 {
+ t.Errorf("1 / 1 = %d, want 1", r)
+ }
+ y = 4294967296
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 / 4294967296 = %d, want 0", r)
+ }
+ y = 9223372036854775806
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 / 9223372036854775806 = %d, want 0", r)
+ }
+ y = 9223372036854775807
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 / 9223372036854775807 = %d, want 0", r)
+ }
+ x = 4294967296
+ y = -9223372036854775808
+ r = x / y
+ if r != 0 {
+ t.Errorf("4294967296 / -9223372036854775808 = %d, want 0", r)
+ }
+ y = -9223372036854775807
+ r = x / y
+ if r != 0 {
+ t.Errorf("4294967296 / -9223372036854775807 = %d, want 0", r)
+ }
+ y = -4294967296
+ r = x / y
+ if r != -1 {
+ t.Errorf("4294967296 / -4294967296 = %d, want -1", r)
+ }
+ y = -1
+ r = x / y
+ if r != -4294967296 {
+ t.Errorf("4294967296 / -1 = %d, want -4294967296", r)
+ }
+ y = 1
+ r = x / y
+ if r != 4294967296 {
+ t.Errorf("4294967296 / 1 = %d, want 4294967296", r)
+ }
+ y = 4294967296
+ r = x / y
+ if r != 1 {
+ t.Errorf("4294967296 / 4294967296 = %d, want 1", r)
+ }
+ y = 9223372036854775806
+ r = x / y
+ if r != 0 {
+ t.Errorf("4294967296 / 9223372036854775806 = %d, want 0", r)
+ }
+ y = 9223372036854775807
+ r = x / y
+ if r != 0 {
+ t.Errorf("4294967296 / 9223372036854775807 = %d, want 0", r)
+ }
+ x = 9223372036854775806
+ y = -9223372036854775808
+ r = x / y
+ if r != 0 {
+ t.Errorf("9223372036854775806 / -9223372036854775808 = %d, want 0", r)
+ }
+ y = -9223372036854775807
+ r = x / y
+ if r != 0 {
+ t.Errorf("9223372036854775806 / -9223372036854775807 = %d, want 0", r)
+ }
+ y = -4294967296
+ r = x / y
+ if r != -2147483647 {
+ t.Errorf("9223372036854775806 / -4294967296 = %d, want -2147483647", r)
+ }
+ y = -1
+ r = x / y
+ if r != -9223372036854775806 {
+ t.Errorf("9223372036854775806 / -1 = %d, want -9223372036854775806", r)
+ }
+ y = 1
+ r = x / y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 / 1 = %d, want 9223372036854775806", r)
+ }
+ y = 4294967296
+ r = x / y
+ if r != 2147483647 {
+ t.Errorf("9223372036854775806 / 4294967296 = %d, want 2147483647", r)
+ }
+ y = 9223372036854775806
+ r = x / y
+ if r != 1 {
+ t.Errorf("9223372036854775806 / 9223372036854775806 = %d, want 1", r)
+ }
+ y = 9223372036854775807
+ r = x / y
+ if r != 0 {
+ t.Errorf("9223372036854775806 / 9223372036854775807 = %d, want 0", r)
+ }
+ x = 9223372036854775807
+ y = -9223372036854775808
+ r = x / y
+ if r != 0 {
+ t.Errorf("9223372036854775807 / -9223372036854775808 = %d, want 0", r)
+ }
+ y = -9223372036854775807
+ r = x / y
+ if r != -1 {
+ t.Errorf("9223372036854775807 / -9223372036854775807 = %d, want -1", r)
+ }
+ y = -4294967296
+ r = x / y
+ if r != -2147483647 {
+ t.Errorf("9223372036854775807 / -4294967296 = %d, want -2147483647", r)
+ }
+ y = -1
+ r = x / y
+ if r != -9223372036854775807 {
+ t.Errorf("9223372036854775807 / -1 = %d, want -9223372036854775807", r)
+ }
+ y = 1
+ r = x / y
+ if r != 9223372036854775807 {
+ t.Errorf("9223372036854775807 / 1 = %d, want 9223372036854775807", r)
+ }
+ y = 4294967296
+ r = x / y
+ if r != 2147483647 {
+ t.Errorf("9223372036854775807 / 4294967296 = %d, want 2147483647", r)
+ }
+ y = 9223372036854775806
+ r = x / y
+ if r != 1 {
+ t.Errorf("9223372036854775807 / 9223372036854775806 = %d, want 1", r)
+ }
+ y = 9223372036854775807
+ r = x / y
+ if r != 1 {
+ t.Errorf("9223372036854775807 / 9223372036854775807 = %d, want 1", r)
+ }
+}
+func TestConstFoldint64mul(t *testing.T) {
+ var x, y, r int64
+ x = -9223372036854775808
+ y = -9223372036854775808
+ r = x * y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 * -9223372036854775808 = %d, want 0", r)
+ }
+ y = -9223372036854775807
+ r = x * y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 * -9223372036854775807 = %d, want -9223372036854775808", r)
+ }
+ y = -4294967296
+ r = x * y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 * -4294967296 = %d, want 0", r)
+ }
+ y = -1
+ r = x * y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 * -1 = %d, want -9223372036854775808", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 * 1 = %d, want -9223372036854775808", r)
+ }
+ y = 4294967296
+ r = x * y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 * 4294967296 = %d, want 0", r)
+ }
+ y = 9223372036854775806
+ r = x * y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 * 9223372036854775806 = %d, want 0", r)
+ }
+ y = 9223372036854775807
+ r = x * y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 * 9223372036854775807 = %d, want -9223372036854775808", r)
+ }
+ x = -9223372036854775807
+ y = -9223372036854775808
+ r = x * y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775807 * -9223372036854775808 = %d, want -9223372036854775808", r)
+ }
+ y = -9223372036854775807
+ r = x * y
+ if r != 1 {
+ t.Errorf("-9223372036854775807 * -9223372036854775807 = %d, want 1", r)
+ }
+ y = -4294967296
+ r = x * y
+ if r != -4294967296 {
+ t.Errorf("-9223372036854775807 * -4294967296 = %d, want -4294967296", r)
+ }
+ y = -1
+ r = x * y
+ if r != 9223372036854775807 {
+ t.Errorf("-9223372036854775807 * -1 = %d, want 9223372036854775807", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("-9223372036854775807 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != -9223372036854775807 {
+ t.Errorf("-9223372036854775807 * 1 = %d, want -9223372036854775807", r)
+ }
+ y = 4294967296
+ r = x * y
+ if r != 4294967296 {
+ t.Errorf("-9223372036854775807 * 4294967296 = %d, want 4294967296", r)
+ }
+ y = 9223372036854775806
+ r = x * y
+ if r != 9223372036854775806 {
+ t.Errorf("-9223372036854775807 * 9223372036854775806 = %d, want 9223372036854775806", r)
+ }
+ y = 9223372036854775807
+ r = x * y
+ if r != -1 {
+ t.Errorf("-9223372036854775807 * 9223372036854775807 = %d, want -1", r)
+ }
+ x = -4294967296
+ y = -9223372036854775808
+ r = x * y
+ if r != 0 {
+ t.Errorf("-4294967296 * -9223372036854775808 = %d, want 0", r)
+ }
+ y = -9223372036854775807
+ r = x * y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 * -9223372036854775807 = %d, want -4294967296", r)
+ }
+ y = -4294967296
+ r = x * y
+ if r != 0 {
+ t.Errorf("-4294967296 * -4294967296 = %d, want 0", r)
+ }
+ y = -1
+ r = x * y
+ if r != 4294967296 {
+ t.Errorf("-4294967296 * -1 = %d, want 4294967296", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("-4294967296 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 * 1 = %d, want -4294967296", r)
+ }
+ y = 4294967296
+ r = x * y
+ if r != 0 {
+ t.Errorf("-4294967296 * 4294967296 = %d, want 0", r)
+ }
+ y = 9223372036854775806
+ r = x * y
+ if r != 8589934592 {
+ t.Errorf("-4294967296 * 9223372036854775806 = %d, want 8589934592", r)
+ }
+ y = 9223372036854775807
+ r = x * y
+ if r != 4294967296 {
+ t.Errorf("-4294967296 * 9223372036854775807 = %d, want 4294967296", r)
+ }
+ x = -1
+ y = -9223372036854775808
+ r = x * y
+ if r != -9223372036854775808 {
+ t.Errorf("-1 * -9223372036854775808 = %d, want -9223372036854775808", r)
+ }
+ y = -9223372036854775807
+ r = x * y
+ if r != 9223372036854775807 {
+ t.Errorf("-1 * -9223372036854775807 = %d, want 9223372036854775807", r)
+ }
+ y = -4294967296
+ r = x * y
+ if r != 4294967296 {
+ t.Errorf("-1 * -4294967296 = %d, want 4294967296", r)
+ }
+ y = -1
+ r = x * y
+ if r != 1 {
+ t.Errorf("-1 * -1 = %d, want 1", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("-1 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != -1 {
+ t.Errorf("-1 * 1 = %d, want -1", r)
+ }
+ y = 4294967296
+ r = x * y
+ if r != -4294967296 {
+ t.Errorf("-1 * 4294967296 = %d, want -4294967296", r)
+ }
+ y = 9223372036854775806
+ r = x * y
+ if r != -9223372036854775806 {
+ t.Errorf("-1 * 9223372036854775806 = %d, want -9223372036854775806", r)
+ }
+ y = 9223372036854775807
+ r = x * y
+ if r != -9223372036854775807 {
+ t.Errorf("-1 * 9223372036854775807 = %d, want -9223372036854775807", r)
+ }
+ x = 0
+ y = -9223372036854775808
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * -9223372036854775808 = %d, want 0", r)
+ }
+ y = -9223372036854775807
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * -9223372036854775807 = %d, want 0", r)
+ }
+ y = -4294967296
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * -4294967296 = %d, want 0", r)
+ }
+ y = -1
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * -1 = %d, want 0", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * 4294967296 = %d, want 0", r)
+ }
+ y = 9223372036854775806
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * 9223372036854775806 = %d, want 0", r)
+ }
+ y = 9223372036854775807
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * 9223372036854775807 = %d, want 0", r)
+ }
+ x = 1
+ y = -9223372036854775808
+ r = x * y
+ if r != -9223372036854775808 {
+ t.Errorf("1 * -9223372036854775808 = %d, want -9223372036854775808", r)
+ }
+ y = -9223372036854775807
+ r = x * y
+ if r != -9223372036854775807 {
+ t.Errorf("1 * -9223372036854775807 = %d, want -9223372036854775807", r)
+ }
+ y = -4294967296
+ r = x * y
+ if r != -4294967296 {
+ t.Errorf("1 * -4294967296 = %d, want -4294967296", r)
+ }
+ y = -1
+ r = x * y
+ if r != -1 {
+ t.Errorf("1 * -1 = %d, want -1", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("1 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != 1 {
+ t.Errorf("1 * 1 = %d, want 1", r)
+ }
+ y = 4294967296
+ r = x * y
+ if r != 4294967296 {
+ t.Errorf("1 * 4294967296 = %d, want 4294967296", r)
+ }
+ y = 9223372036854775806
+ r = x * y
+ if r != 9223372036854775806 {
+ t.Errorf("1 * 9223372036854775806 = %d, want 9223372036854775806", r)
+ }
+ y = 9223372036854775807
+ r = x * y
+ if r != 9223372036854775807 {
+ t.Errorf("1 * 9223372036854775807 = %d, want 9223372036854775807", r)
+ }
+ x = 4294967296
+ y = -9223372036854775808
+ r = x * y
+ if r != 0 {
+ t.Errorf("4294967296 * -9223372036854775808 = %d, want 0", r)
+ }
+ y = -9223372036854775807
+ r = x * y
+ if r != 4294967296 {
+ t.Errorf("4294967296 * -9223372036854775807 = %d, want 4294967296", r)
+ }
+ y = -4294967296
+ r = x * y
+ if r != 0 {
+ t.Errorf("4294967296 * -4294967296 = %d, want 0", r)
+ }
+ y = -1
+ r = x * y
+ if r != -4294967296 {
+ t.Errorf("4294967296 * -1 = %d, want -4294967296", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("4294967296 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != 4294967296 {
+ t.Errorf("4294967296 * 1 = %d, want 4294967296", r)
+ }
+ y = 4294967296
+ r = x * y
+ if r != 0 {
+ t.Errorf("4294967296 * 4294967296 = %d, want 0", r)
+ }
+ y = 9223372036854775806
+ r = x * y
+ if r != -8589934592 {
+ t.Errorf("4294967296 * 9223372036854775806 = %d, want -8589934592", r)
+ }
+ y = 9223372036854775807
+ r = x * y
+ if r != -4294967296 {
+ t.Errorf("4294967296 * 9223372036854775807 = %d, want -4294967296", r)
+ }
+ x = 9223372036854775806
+ y = -9223372036854775808
+ r = x * y
+ if r != 0 {
+ t.Errorf("9223372036854775806 * -9223372036854775808 = %d, want 0", r)
+ }
+ y = -9223372036854775807
+ r = x * y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 * -9223372036854775807 = %d, want 9223372036854775806", r)
+ }
+ y = -4294967296
+ r = x * y
+ if r != 8589934592 {
+ t.Errorf("9223372036854775806 * -4294967296 = %d, want 8589934592", r)
+ }
+ y = -1
+ r = x * y
+ if r != -9223372036854775806 {
+ t.Errorf("9223372036854775806 * -1 = %d, want -9223372036854775806", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("9223372036854775806 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 * 1 = %d, want 9223372036854775806", r)
+ }
+ y = 4294967296
+ r = x * y
+ if r != -8589934592 {
+ t.Errorf("9223372036854775806 * 4294967296 = %d, want -8589934592", r)
+ }
+ y = 9223372036854775806
+ r = x * y
+ if r != 4 {
+ t.Errorf("9223372036854775806 * 9223372036854775806 = %d, want 4", r)
+ }
+ y = 9223372036854775807
+ r = x * y
+ if r != -9223372036854775806 {
+ t.Errorf("9223372036854775806 * 9223372036854775807 = %d, want -9223372036854775806", r)
+ }
+ x = 9223372036854775807
+ y = -9223372036854775808
+ r = x * y
+ if r != -9223372036854775808 {
+ t.Errorf("9223372036854775807 * -9223372036854775808 = %d, want -9223372036854775808", r)
+ }
+ y = -9223372036854775807
+ r = x * y
+ if r != -1 {
+ t.Errorf("9223372036854775807 * -9223372036854775807 = %d, want -1", r)
+ }
+ y = -4294967296
+ r = x * y
+ if r != 4294967296 {
+ t.Errorf("9223372036854775807 * -4294967296 = %d, want 4294967296", r)
+ }
+ y = -1
+ r = x * y
+ if r != -9223372036854775807 {
+ t.Errorf("9223372036854775807 * -1 = %d, want -9223372036854775807", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("9223372036854775807 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != 9223372036854775807 {
+ t.Errorf("9223372036854775807 * 1 = %d, want 9223372036854775807", r)
+ }
+ y = 4294967296
+ r = x * y
+ if r != -4294967296 {
+ t.Errorf("9223372036854775807 * 4294967296 = %d, want -4294967296", r)
+ }
+ y = 9223372036854775806
+ r = x * y
+ if r != -9223372036854775806 {
+ t.Errorf("9223372036854775807 * 9223372036854775806 = %d, want -9223372036854775806", r)
+ }
+ y = 9223372036854775807
+ r = x * y
+ if r != 1 {
+ t.Errorf("9223372036854775807 * 9223372036854775807 = %d, want 1", r)
+ }
+}
+func TestConstFoldint64mod(t *testing.T) {
+ var x, y, r int64
+ x = -9223372036854775808
+ y = -9223372036854775808
+ r = x % y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 % -9223372036854775808 = %d, want 0", r)
+ }
+ y = -9223372036854775807
+ r = x % y
+ if r != -1 {
+ t.Errorf("-9223372036854775808 % -9223372036854775807 = %d, want -1", r)
+ }
+ y = -4294967296
+ r = x % y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 % -4294967296 = %d, want 0", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 % -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 % 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x % y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 % 4294967296 = %d, want 0", r)
+ }
+ y = 9223372036854775806
+ r = x % y
+ if r != -2 {
+ t.Errorf("-9223372036854775808 % 9223372036854775806 = %d, want -2", r)
+ }
+ y = 9223372036854775807
+ r = x % y
+ if r != -1 {
+ t.Errorf("-9223372036854775808 % 9223372036854775807 = %d, want -1", r)
+ }
+ x = -9223372036854775807
+ y = -9223372036854775808
+ r = x % y
+ if r != -9223372036854775807 {
+ t.Errorf("-9223372036854775807 % -9223372036854775808 = %d, want -9223372036854775807", r)
+ }
+ y = -9223372036854775807
+ r = x % y
+ if r != 0 {
+ t.Errorf("-9223372036854775807 % -9223372036854775807 = %d, want 0", r)
+ }
+ y = -4294967296
+ r = x % y
+ if r != -4294967295 {
+ t.Errorf("-9223372036854775807 % -4294967296 = %d, want -4294967295", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-9223372036854775807 % -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-9223372036854775807 % 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x % y
+ if r != -4294967295 {
+ t.Errorf("-9223372036854775807 % 4294967296 = %d, want -4294967295", r)
+ }
+ y = 9223372036854775806
+ r = x % y
+ if r != -1 {
+ t.Errorf("-9223372036854775807 % 9223372036854775806 = %d, want -1", r)
+ }
+ y = 9223372036854775807
+ r = x % y
+ if r != 0 {
+ t.Errorf("-9223372036854775807 % 9223372036854775807 = %d, want 0", r)
+ }
+ x = -4294967296
+ y = -9223372036854775808
+ r = x % y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 % -9223372036854775808 = %d, want -4294967296", r)
+ }
+ y = -9223372036854775807
+ r = x % y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 % -9223372036854775807 = %d, want -4294967296", r)
+ }
+ y = -4294967296
+ r = x % y
+ if r != 0 {
+ t.Errorf("-4294967296 % -4294967296 = %d, want 0", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-4294967296 % -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-4294967296 % 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x % y
+ if r != 0 {
+ t.Errorf("-4294967296 % 4294967296 = %d, want 0", r)
+ }
+ y = 9223372036854775806
+ r = x % y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 % 9223372036854775806 = %d, want -4294967296", r)
+ }
+ y = 9223372036854775807
+ r = x % y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 % 9223372036854775807 = %d, want -4294967296", r)
+ }
+ x = -1
+ y = -9223372036854775808
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 % -9223372036854775808 = %d, want -1", r)
+ }
+ y = -9223372036854775807
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 % -9223372036854775807 = %d, want -1", r)
+ }
+ y = -4294967296
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 % -4294967296 = %d, want -1", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-1 % -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-1 % 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 % 4294967296 = %d, want -1", r)
+ }
+ y = 9223372036854775806
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 % 9223372036854775806 = %d, want -1", r)
+ }
+ y = 9223372036854775807
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 % 9223372036854775807 = %d, want -1", r)
+ }
+ x = 0
+ y = -9223372036854775808
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % -9223372036854775808 = %d, want 0", r)
+ }
+ y = -9223372036854775807
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % -9223372036854775807 = %d, want 0", r)
+ }
+ y = -4294967296
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % -4294967296 = %d, want 0", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % 4294967296 = %d, want 0", r)
+ }
+ y = 9223372036854775806
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % 9223372036854775806 = %d, want 0", r)
+ }
+ y = 9223372036854775807
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % 9223372036854775807 = %d, want 0", r)
+ }
+ x = 1
+ y = -9223372036854775808
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 % -9223372036854775808 = %d, want 1", r)
+ }
+ y = -9223372036854775807
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 % -9223372036854775807 = %d, want 1", r)
+ }
+ y = -4294967296
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 % -4294967296 = %d, want 1", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("1 % -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("1 % 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 % 4294967296 = %d, want 1", r)
+ }
+ y = 9223372036854775806
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 % 9223372036854775806 = %d, want 1", r)
+ }
+ y = 9223372036854775807
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 % 9223372036854775807 = %d, want 1", r)
+ }
+ x = 4294967296
+ y = -9223372036854775808
+ r = x % y
+ if r != 4294967296 {
+ t.Errorf("4294967296 % -9223372036854775808 = %d, want 4294967296", r)
+ }
+ y = -9223372036854775807
+ r = x % y
+ if r != 4294967296 {
+ t.Errorf("4294967296 % -9223372036854775807 = %d, want 4294967296", r)
+ }
+ y = -4294967296
+ r = x % y
+ if r != 0 {
+ t.Errorf("4294967296 % -4294967296 = %d, want 0", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("4294967296 % -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("4294967296 % 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x % y
+ if r != 0 {
+ t.Errorf("4294967296 % 4294967296 = %d, want 0", r)
+ }
+ y = 9223372036854775806
+ r = x % y
+ if r != 4294967296 {
+ t.Errorf("4294967296 % 9223372036854775806 = %d, want 4294967296", r)
+ }
+ y = 9223372036854775807
+ r = x % y
+ if r != 4294967296 {
+ t.Errorf("4294967296 % 9223372036854775807 = %d, want 4294967296", r)
+ }
+ x = 9223372036854775806
+ y = -9223372036854775808
+ r = x % y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 % -9223372036854775808 = %d, want 9223372036854775806", r)
+ }
+ y = -9223372036854775807
+ r = x % y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 % -9223372036854775807 = %d, want 9223372036854775806", r)
+ }
+ y = -4294967296
+ r = x % y
+ if r != 4294967294 {
+ t.Errorf("9223372036854775806 % -4294967296 = %d, want 4294967294", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("9223372036854775806 % -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("9223372036854775806 % 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x % y
+ if r != 4294967294 {
+ t.Errorf("9223372036854775806 % 4294967296 = %d, want 4294967294", r)
+ }
+ y = 9223372036854775806
+ r = x % y
+ if r != 0 {
+ t.Errorf("9223372036854775806 % 9223372036854775806 = %d, want 0", r)
+ }
+ y = 9223372036854775807
+ r = x % y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 % 9223372036854775807 = %d, want 9223372036854775806", r)
+ }
+ x = 9223372036854775807
+ y = -9223372036854775808
+ r = x % y
+ if r != 9223372036854775807 {
+ t.Errorf("9223372036854775807 % -9223372036854775808 = %d, want 9223372036854775807", r)
+ }
+ y = -9223372036854775807
+ r = x % y
+ if r != 0 {
+ t.Errorf("9223372036854775807 % -9223372036854775807 = %d, want 0", r)
+ }
+ y = -4294967296
+ r = x % y
+ if r != 4294967295 {
+ t.Errorf("9223372036854775807 % -4294967296 = %d, want 4294967295", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("9223372036854775807 % -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("9223372036854775807 % 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x % y
+ if r != 4294967295 {
+ t.Errorf("9223372036854775807 % 4294967296 = %d, want 4294967295", r)
+ }
+ y = 9223372036854775806
+ r = x % y
+ if r != 1 {
+ t.Errorf("9223372036854775807 % 9223372036854775806 = %d, want 1", r)
+ }
+ y = 9223372036854775807
+ r = x % y
+ if r != 0 {
+ t.Errorf("9223372036854775807 % 9223372036854775807 = %d, want 0", r)
+ }
+}
+func TestConstFolduint32add(t *testing.T) {
+ var x, y, r uint32
+ x = 0
+ y = 0
+ r = x + y
+ if r != 0 {
+ t.Errorf("0 + 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x + y
+ if r != 1 {
+ t.Errorf("0 + 1 = %d, want 1", r)
+ }
+ y = 4294967295
+ r = x + y
+ if r != 4294967295 {
+ t.Errorf("0 + 4294967295 = %d, want 4294967295", r)
+ }
+ x = 1
+ y = 0
+ r = x + y
+ if r != 1 {
+ t.Errorf("1 + 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x + y
+ if r != 2 {
+ t.Errorf("1 + 1 = %d, want 2", r)
+ }
+ y = 4294967295
+ r = x + y
+ if r != 0 {
+ t.Errorf("1 + 4294967295 = %d, want 0", r)
+ }
+ x = 4294967295
+ y = 0
+ r = x + y
+ if r != 4294967295 {
+ t.Errorf("4294967295 + 0 = %d, want 4294967295", r)
+ }
+ y = 1
+ r = x + y
+ if r != 0 {
+ t.Errorf("4294967295 + 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x + y
+ if r != 4294967294 {
+ t.Errorf("4294967295 + 4294967295 = %d, want 4294967294", r)
+ }
+}
+func TestConstFolduint32sub(t *testing.T) {
+ var x, y, r uint32
+ x = 0
+ y = 0
+ r = x - y
+ if r != 0 {
+ t.Errorf("0 - 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x - y
+ if r != 4294967295 {
+ t.Errorf("0 - 1 = %d, want 4294967295", r)
+ }
+ y = 4294967295
+ r = x - y
+ if r != 1 {
+ t.Errorf("0 - 4294967295 = %d, want 1", r)
+ }
+ x = 1
+ y = 0
+ r = x - y
+ if r != 1 {
+ t.Errorf("1 - 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x - y
+ if r != 0 {
+ t.Errorf("1 - 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x - y
+ if r != 2 {
+ t.Errorf("1 - 4294967295 = %d, want 2", r)
+ }
+ x = 4294967295
+ y = 0
+ r = x - y
+ if r != 4294967295 {
+ t.Errorf("4294967295 - 0 = %d, want 4294967295", r)
+ }
+ y = 1
+ r = x - y
+ if r != 4294967294 {
+ t.Errorf("4294967295 - 1 = %d, want 4294967294", r)
+ }
+ y = 4294967295
+ r = x - y
+ if r != 0 {
+ t.Errorf("4294967295 - 4294967295 = %d, want 0", r)
+ }
+}
+func TestConstFolduint32div(t *testing.T) {
+ var x, y, r uint32
+ x = 0
+ y = 1
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / 4294967295 = %d, want 0", r)
+ }
+ x = 1
+ y = 1
+ r = x / y
+ if r != 1 {
+ t.Errorf("1 / 1 = %d, want 1", r)
+ }
+ y = 4294967295
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 / 4294967295 = %d, want 0", r)
+ }
+ x = 4294967295
+ y = 1
+ r = x / y
+ if r != 4294967295 {
+ t.Errorf("4294967295 / 1 = %d, want 4294967295", r)
+ }
+ y = 4294967295
+ r = x / y
+ if r != 1 {
+ t.Errorf("4294967295 / 4294967295 = %d, want 1", r)
+ }
+}
+func TestConstFolduint32mul(t *testing.T) {
+ var x, y, r uint32
+ x = 0
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * 4294967295 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("1 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != 1 {
+ t.Errorf("1 * 1 = %d, want 1", r)
+ }
+ y = 4294967295
+ r = x * y
+ if r != 4294967295 {
+ t.Errorf("1 * 4294967295 = %d, want 4294967295", r)
+ }
+ x = 4294967295
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("4294967295 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != 4294967295 {
+ t.Errorf("4294967295 * 1 = %d, want 4294967295", r)
+ }
+ y = 4294967295
+ r = x * y
+ if r != 1 {
+ t.Errorf("4294967295 * 4294967295 = %d, want 1", r)
+ }
+}
+func TestConstFolduint32mod(t *testing.T) {
+ var x, y, r uint32
+ x = 0
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % 4294967295 = %d, want 0", r)
+ }
+ x = 1
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("1 % 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 % 4294967295 = %d, want 1", r)
+ }
+ x = 4294967295
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("4294967295 % 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x % y
+ if r != 0 {
+ t.Errorf("4294967295 % 4294967295 = %d, want 0", r)
+ }
+}
+func TestConstFoldint32add(t *testing.T) {
+ var x, y, r int32
+ x = -2147483648
+ y = -2147483648
+ r = x + y
+ if r != 0 {
+ t.Errorf("-2147483648 + -2147483648 = %d, want 0", r)
+ }
+ y = -2147483647
+ r = x + y
+ if r != 1 {
+ t.Errorf("-2147483648 + -2147483647 = %d, want 1", r)
+ }
+ y = -1
+ r = x + y
+ if r != 2147483647 {
+ t.Errorf("-2147483648 + -1 = %d, want 2147483647", r)
+ }
+ y = 0
+ r = x + y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 + 0 = %d, want -2147483648", r)
+ }
+ y = 1
+ r = x + y
+ if r != -2147483647 {
+ t.Errorf("-2147483648 + 1 = %d, want -2147483647", r)
+ }
+ y = 2147483647
+ r = x + y
+ if r != -1 {
+ t.Errorf("-2147483648 + 2147483647 = %d, want -1", r)
+ }
+ x = -2147483647
+ y = -2147483648
+ r = x + y
+ if r != 1 {
+ t.Errorf("-2147483647 + -2147483648 = %d, want 1", r)
+ }
+ y = -2147483647
+ r = x + y
+ if r != 2 {
+ t.Errorf("-2147483647 + -2147483647 = %d, want 2", r)
+ }
+ y = -1
+ r = x + y
+ if r != -2147483648 {
+ t.Errorf("-2147483647 + -1 = %d, want -2147483648", r)
+ }
+ y = 0
+ r = x + y
+ if r != -2147483647 {
+ t.Errorf("-2147483647 + 0 = %d, want -2147483647", r)
+ }
+ y = 1
+ r = x + y
+ if r != -2147483646 {
+ t.Errorf("-2147483647 + 1 = %d, want -2147483646", r)
+ }
+ y = 2147483647
+ r = x + y
+ if r != 0 {
+ t.Errorf("-2147483647 + 2147483647 = %d, want 0", r)
+ }
+ x = -1
+ y = -2147483648
+ r = x + y
+ if r != 2147483647 {
+ t.Errorf("-1 + -2147483648 = %d, want 2147483647", r)
+ }
+ y = -2147483647
+ r = x + y
+ if r != -2147483648 {
+ t.Errorf("-1 + -2147483647 = %d, want -2147483648", r)
+ }
+ y = -1
+ r = x + y
+ if r != -2 {
+ t.Errorf("-1 + -1 = %d, want -2", r)
+ }
+ y = 0
+ r = x + y
+ if r != -1 {
+ t.Errorf("-1 + 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x + y
+ if r != 0 {
+ t.Errorf("-1 + 1 = %d, want 0", r)
+ }
+ y = 2147483647
+ r = x + y
+ if r != 2147483646 {
+ t.Errorf("-1 + 2147483647 = %d, want 2147483646", r)
+ }
+ x = 0
+ y = -2147483648
+ r = x + y
+ if r != -2147483648 {
+ t.Errorf("0 + -2147483648 = %d, want -2147483648", r)
+ }
+ y = -2147483647
+ r = x + y
+ if r != -2147483647 {
+ t.Errorf("0 + -2147483647 = %d, want -2147483647", r)
+ }
+ y = -1
+ r = x + y
+ if r != -1 {
+ t.Errorf("0 + -1 = %d, want -1", r)
+ }
+ y = 0
+ r = x + y
+ if r != 0 {
+ t.Errorf("0 + 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x + y
+ if r != 1 {
+ t.Errorf("0 + 1 = %d, want 1", r)
+ }
+ y = 2147483647
+ r = x + y
+ if r != 2147483647 {
+ t.Errorf("0 + 2147483647 = %d, want 2147483647", r)
+ }
+ x = 1
+ y = -2147483648
+ r = x + y
+ if r != -2147483647 {
+ t.Errorf("1 + -2147483648 = %d, want -2147483647", r)
+ }
+ y = -2147483647
+ r = x + y
+ if r != -2147483646 {
+ t.Errorf("1 + -2147483647 = %d, want -2147483646", r)
+ }
+ y = -1
+ r = x + y
+ if r != 0 {
+ t.Errorf("1 + -1 = %d, want 0", r)
+ }
+ y = 0
+ r = x + y
+ if r != 1 {
+ t.Errorf("1 + 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x + y
+ if r != 2 {
+ t.Errorf("1 + 1 = %d, want 2", r)
+ }
+ y = 2147483647
+ r = x + y
+ if r != -2147483648 {
+ t.Errorf("1 + 2147483647 = %d, want -2147483648", r)
+ }
+ x = 2147483647
+ y = -2147483648
+ r = x + y
+ if r != -1 {
+ t.Errorf("2147483647 + -2147483648 = %d, want -1", r)
+ }
+ y = -2147483647
+ r = x + y
+ if r != 0 {
+ t.Errorf("2147483647 + -2147483647 = %d, want 0", r)
+ }
+ y = -1
+ r = x + y
+ if r != 2147483646 {
+ t.Errorf("2147483647 + -1 = %d, want 2147483646", r)
+ }
+ y = 0
+ r = x + y
+ if r != 2147483647 {
+ t.Errorf("2147483647 + 0 = %d, want 2147483647", r)
+ }
+ y = 1
+ r = x + y
+ if r != -2147483648 {
+ t.Errorf("2147483647 + 1 = %d, want -2147483648", r)
+ }
+ y = 2147483647
+ r = x + y
+ if r != -2 {
+ t.Errorf("2147483647 + 2147483647 = %d, want -2", r)
+ }
+}
+func TestConstFoldint32sub(t *testing.T) {
+ var x, y, r int32
+ x = -2147483648
+ y = -2147483648
+ r = x - y
+ if r != 0 {
+ t.Errorf("-2147483648 - -2147483648 = %d, want 0", r)
+ }
+ y = -2147483647
+ r = x - y
+ if r != -1 {
+ t.Errorf("-2147483648 - -2147483647 = %d, want -1", r)
+ }
+ y = -1
+ r = x - y
+ if r != -2147483647 {
+ t.Errorf("-2147483648 - -1 = %d, want -2147483647", r)
+ }
+ y = 0
+ r = x - y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 - 0 = %d, want -2147483648", r)
+ }
+ y = 1
+ r = x - y
+ if r != 2147483647 {
+ t.Errorf("-2147483648 - 1 = %d, want 2147483647", r)
+ }
+ y = 2147483647
+ r = x - y
+ if r != 1 {
+ t.Errorf("-2147483648 - 2147483647 = %d, want 1", r)
+ }
+ x = -2147483647
+ y = -2147483648
+ r = x - y
+ if r != 1 {
+ t.Errorf("-2147483647 - -2147483648 = %d, want 1", r)
+ }
+ y = -2147483647
+ r = x - y
+ if r != 0 {
+ t.Errorf("-2147483647 - -2147483647 = %d, want 0", r)
+ }
+ y = -1
+ r = x - y
+ if r != -2147483646 {
+ t.Errorf("-2147483647 - -1 = %d, want -2147483646", r)
+ }
+ y = 0
+ r = x - y
+ if r != -2147483647 {
+ t.Errorf("-2147483647 - 0 = %d, want -2147483647", r)
+ }
+ y = 1
+ r = x - y
+ if r != -2147483648 {
+ t.Errorf("-2147483647 - 1 = %d, want -2147483648", r)
+ }
+ y = 2147483647
+ r = x - y
+ if r != 2 {
+ t.Errorf("-2147483647 - 2147483647 = %d, want 2", r)
+ }
+ x = -1
+ y = -2147483648
+ r = x - y
+ if r != 2147483647 {
+ t.Errorf("-1 - -2147483648 = %d, want 2147483647", r)
+ }
+ y = -2147483647
+ r = x - y
+ if r != 2147483646 {
+ t.Errorf("-1 - -2147483647 = %d, want 2147483646", r)
+ }
+ y = -1
+ r = x - y
+ if r != 0 {
+ t.Errorf("-1 - -1 = %d, want 0", r)
+ }
+ y = 0
+ r = x - y
+ if r != -1 {
+ t.Errorf("-1 - 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x - y
+ if r != -2 {
+ t.Errorf("-1 - 1 = %d, want -2", r)
+ }
+ y = 2147483647
+ r = x - y
+ if r != -2147483648 {
+ t.Errorf("-1 - 2147483647 = %d, want -2147483648", r)
+ }
+ x = 0
+ y = -2147483648
+ r = x - y
+ if r != -2147483648 {
+ t.Errorf("0 - -2147483648 = %d, want -2147483648", r)
+ }
+ y = -2147483647
+ r = x - y
+ if r != 2147483647 {
+ t.Errorf("0 - -2147483647 = %d, want 2147483647", r)
+ }
+ y = -1
+ r = x - y
+ if r != 1 {
+ t.Errorf("0 - -1 = %d, want 1", r)
+ }
+ y = 0
+ r = x - y
+ if r != 0 {
+ t.Errorf("0 - 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x - y
+ if r != -1 {
+ t.Errorf("0 - 1 = %d, want -1", r)
+ }
+ y = 2147483647
+ r = x - y
+ if r != -2147483647 {
+ t.Errorf("0 - 2147483647 = %d, want -2147483647", r)
+ }
+ x = 1
+ y = -2147483648
+ r = x - y
+ if r != -2147483647 {
+ t.Errorf("1 - -2147483648 = %d, want -2147483647", r)
+ }
+ y = -2147483647
+ r = x - y
+ if r != -2147483648 {
+ t.Errorf("1 - -2147483647 = %d, want -2147483648", r)
+ }
+ y = -1
+ r = x - y
+ if r != 2 {
+ t.Errorf("1 - -1 = %d, want 2", r)
+ }
+ y = 0
+ r = x - y
+ if r != 1 {
+ t.Errorf("1 - 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x - y
+ if r != 0 {
+ t.Errorf("1 - 1 = %d, want 0", r)
+ }
+ y = 2147483647
+ r = x - y
+ if r != -2147483646 {
+ t.Errorf("1 - 2147483647 = %d, want -2147483646", r)
+ }
+ x = 2147483647
+ y = -2147483648
+ r = x - y
+ if r != -1 {
+ t.Errorf("2147483647 - -2147483648 = %d, want -1", r)
+ }
+ y = -2147483647
+ r = x - y
+ if r != -2 {
+ t.Errorf("2147483647 - -2147483647 = %d, want -2", r)
+ }
+ y = -1
+ r = x - y
+ if r != -2147483648 {
+ t.Errorf("2147483647 - -1 = %d, want -2147483648", r)
+ }
+ y = 0
+ r = x - y
+ if r != 2147483647 {
+ t.Errorf("2147483647 - 0 = %d, want 2147483647", r)
+ }
+ y = 1
+ r = x - y
+ if r != 2147483646 {
+ t.Errorf("2147483647 - 1 = %d, want 2147483646", r)
+ }
+ y = 2147483647
+ r = x - y
+ if r != 0 {
+ t.Errorf("2147483647 - 2147483647 = %d, want 0", r)
+ }
+}
+func TestConstFoldint32div(t *testing.T) {
+ var x, y, r int32
+ x = -2147483648
+ y = -2147483648
+ r = x / y
+ if r != 1 {
+ t.Errorf("-2147483648 / -2147483648 = %d, want 1", r)
+ }
+ y = -2147483647
+ r = x / y
+ if r != 1 {
+ t.Errorf("-2147483648 / -2147483647 = %d, want 1", r)
+ }
+ y = -1
+ r = x / y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 / -1 = %d, want -2147483648", r)
+ }
+ y = 1
+ r = x / y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 / 1 = %d, want -2147483648", r)
+ }
+ y = 2147483647
+ r = x / y
+ if r != -1 {
+ t.Errorf("-2147483648 / 2147483647 = %d, want -1", r)
+ }
+ x = -2147483647
+ y = -2147483648
+ r = x / y
+ if r != 0 {
+ t.Errorf("-2147483647 / -2147483648 = %d, want 0", r)
+ }
+ y = -2147483647
+ r = x / y
+ if r != 1 {
+ t.Errorf("-2147483647 / -2147483647 = %d, want 1", r)
+ }
+ y = -1
+ r = x / y
+ if r != 2147483647 {
+ t.Errorf("-2147483647 / -1 = %d, want 2147483647", r)
+ }
+ y = 1
+ r = x / y
+ if r != -2147483647 {
+ t.Errorf("-2147483647 / 1 = %d, want -2147483647", r)
+ }
+ y = 2147483647
+ r = x / y
+ if r != -1 {
+ t.Errorf("-2147483647 / 2147483647 = %d, want -1", r)
+ }
+ x = -1
+ y = -2147483648
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 / -2147483648 = %d, want 0", r)
+ }
+ y = -2147483647
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 / -2147483647 = %d, want 0", r)
+ }
+ y = -1
+ r = x / y
+ if r != 1 {
+ t.Errorf("-1 / -1 = %d, want 1", r)
+ }
+ y = 1
+ r = x / y
+ if r != -1 {
+ t.Errorf("-1 / 1 = %d, want -1", r)
+ }
+ y = 2147483647
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 / 2147483647 = %d, want 0", r)
+ }
+ x = 0
+ y = -2147483648
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / -2147483648 = %d, want 0", r)
+ }
+ y = -2147483647
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / -2147483647 = %d, want 0", r)
+ }
+ y = -1
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / 1 = %d, want 0", r)
+ }
+ y = 2147483647
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / 2147483647 = %d, want 0", r)
+ }
+ x = 1
+ y = -2147483648
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 / -2147483648 = %d, want 0", r)
+ }
+ y = -2147483647
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 / -2147483647 = %d, want 0", r)
+ }
+ y = -1
+ r = x / y
+ if r != -1 {
+ t.Errorf("1 / -1 = %d, want -1", r)
+ }
+ y = 1
+ r = x / y
+ if r != 1 {
+ t.Errorf("1 / 1 = %d, want 1", r)
+ }
+ y = 2147483647
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 / 2147483647 = %d, want 0", r)
+ }
+ x = 2147483647
+ y = -2147483648
+ r = x / y
+ if r != 0 {
+ t.Errorf("2147483647 / -2147483648 = %d, want 0", r)
+ }
+ y = -2147483647
+ r = x / y
+ if r != -1 {
+ t.Errorf("2147483647 / -2147483647 = %d, want -1", r)
+ }
+ y = -1
+ r = x / y
+ if r != -2147483647 {
+ t.Errorf("2147483647 / -1 = %d, want -2147483647", r)
+ }
+ y = 1
+ r = x / y
+ if r != 2147483647 {
+ t.Errorf("2147483647 / 1 = %d, want 2147483647", r)
+ }
+ y = 2147483647
+ r = x / y
+ if r != 1 {
+ t.Errorf("2147483647 / 2147483647 = %d, want 1", r)
+ }
+}
+func TestConstFoldint32mul(t *testing.T) {
+ var x, y, r int32
+ x = -2147483648
+ y = -2147483648
+ r = x * y
+ if r != 0 {
+ t.Errorf("-2147483648 * -2147483648 = %d, want 0", r)
+ }
+ y = -2147483647
+ r = x * y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 * -2147483647 = %d, want -2147483648", r)
+ }
+ y = -1
+ r = x * y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 * -1 = %d, want -2147483648", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("-2147483648 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 * 1 = %d, want -2147483648", r)
+ }
+ y = 2147483647
+ r = x * y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 * 2147483647 = %d, want -2147483648", r)
+ }
+ x = -2147483647
+ y = -2147483648
+ r = x * y
+ if r != -2147483648 {
+ t.Errorf("-2147483647 * -2147483648 = %d, want -2147483648", r)
+ }
+ y = -2147483647
+ r = x * y
+ if r != 1 {
+ t.Errorf("-2147483647 * -2147483647 = %d, want 1", r)
+ }
+ y = -1
+ r = x * y
+ if r != 2147483647 {
+ t.Errorf("-2147483647 * -1 = %d, want 2147483647", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("-2147483647 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != -2147483647 {
+ t.Errorf("-2147483647 * 1 = %d, want -2147483647", r)
+ }
+ y = 2147483647
+ r = x * y
+ if r != -1 {
+ t.Errorf("-2147483647 * 2147483647 = %d, want -1", r)
+ }
+ x = -1
+ y = -2147483648
+ r = x * y
+ if r != -2147483648 {
+ t.Errorf("-1 * -2147483648 = %d, want -2147483648", r)
+ }
+ y = -2147483647
+ r = x * y
+ if r != 2147483647 {
+ t.Errorf("-1 * -2147483647 = %d, want 2147483647", r)
+ }
+ y = -1
+ r = x * y
+ if r != 1 {
+ t.Errorf("-1 * -1 = %d, want 1", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("-1 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != -1 {
+ t.Errorf("-1 * 1 = %d, want -1", r)
+ }
+ y = 2147483647
+ r = x * y
+ if r != -2147483647 {
+ t.Errorf("-1 * 2147483647 = %d, want -2147483647", r)
+ }
+ x = 0
+ y = -2147483648
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * -2147483648 = %d, want 0", r)
+ }
+ y = -2147483647
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * -2147483647 = %d, want 0", r)
+ }
+ y = -1
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * -1 = %d, want 0", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * 1 = %d, want 0", r)
+ }
+ y = 2147483647
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * 2147483647 = %d, want 0", r)
+ }
+ x = 1
+ y = -2147483648
+ r = x * y
+ if r != -2147483648 {
+ t.Errorf("1 * -2147483648 = %d, want -2147483648", r)
+ }
+ y = -2147483647
+ r = x * y
+ if r != -2147483647 {
+ t.Errorf("1 * -2147483647 = %d, want -2147483647", r)
+ }
+ y = -1
+ r = x * y
+ if r != -1 {
+ t.Errorf("1 * -1 = %d, want -1", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("1 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != 1 {
+ t.Errorf("1 * 1 = %d, want 1", r)
+ }
+ y = 2147483647
+ r = x * y
+ if r != 2147483647 {
+ t.Errorf("1 * 2147483647 = %d, want 2147483647", r)
+ }
+ x = 2147483647
+ y = -2147483648
+ r = x * y
+ if r != -2147483648 {
+ t.Errorf("2147483647 * -2147483648 = %d, want -2147483648", r)
+ }
+ y = -2147483647
+ r = x * y
+ if r != -1 {
+ t.Errorf("2147483647 * -2147483647 = %d, want -1", r)
+ }
+ y = -1
+ r = x * y
+ if r != -2147483647 {
+ t.Errorf("2147483647 * -1 = %d, want -2147483647", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("2147483647 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != 2147483647 {
+ t.Errorf("2147483647 * 1 = %d, want 2147483647", r)
+ }
+ y = 2147483647
+ r = x * y
+ if r != 1 {
+ t.Errorf("2147483647 * 2147483647 = %d, want 1", r)
+ }
+}
+func TestConstFoldint32mod(t *testing.T) {
+ var x, y, r int32
+ x = -2147483648
+ y = -2147483648
+ r = x % y
+ if r != 0 {
+ t.Errorf("-2147483648 % -2147483648 = %d, want 0", r)
+ }
+ y = -2147483647
+ r = x % y
+ if r != -1 {
+ t.Errorf("-2147483648 % -2147483647 = %d, want -1", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-2147483648 % -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-2147483648 % 1 = %d, want 0", r)
+ }
+ y = 2147483647
+ r = x % y
+ if r != -1 {
+ t.Errorf("-2147483648 % 2147483647 = %d, want -1", r)
+ }
+ x = -2147483647
+ y = -2147483648
+ r = x % y
+ if r != -2147483647 {
+ t.Errorf("-2147483647 % -2147483648 = %d, want -2147483647", r)
+ }
+ y = -2147483647
+ r = x % y
+ if r != 0 {
+ t.Errorf("-2147483647 % -2147483647 = %d, want 0", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-2147483647 % -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-2147483647 % 1 = %d, want 0", r)
+ }
+ y = 2147483647
+ r = x % y
+ if r != 0 {
+ t.Errorf("-2147483647 % 2147483647 = %d, want 0", r)
+ }
+ x = -1
+ y = -2147483648
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 % -2147483648 = %d, want -1", r)
+ }
+ y = -2147483647
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 % -2147483647 = %d, want -1", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-1 % -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-1 % 1 = %d, want 0", r)
+ }
+ y = 2147483647
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 % 2147483647 = %d, want -1", r)
+ }
+ x = 0
+ y = -2147483648
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % -2147483648 = %d, want 0", r)
+ }
+ y = -2147483647
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % -2147483647 = %d, want 0", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % 1 = %d, want 0", r)
+ }
+ y = 2147483647
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % 2147483647 = %d, want 0", r)
+ }
+ x = 1
+ y = -2147483648
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 % -2147483648 = %d, want 1", r)
+ }
+ y = -2147483647
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 % -2147483647 = %d, want 1", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("1 % -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("1 % 1 = %d, want 0", r)
+ }
+ y = 2147483647
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 % 2147483647 = %d, want 1", r)
+ }
+ x = 2147483647
+ y = -2147483648
+ r = x % y
+ if r != 2147483647 {
+ t.Errorf("2147483647 % -2147483648 = %d, want 2147483647", r)
+ }
+ y = -2147483647
+ r = x % y
+ if r != 0 {
+ t.Errorf("2147483647 % -2147483647 = %d, want 0", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("2147483647 % -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("2147483647 % 1 = %d, want 0", r)
+ }
+ y = 2147483647
+ r = x % y
+ if r != 0 {
+ t.Errorf("2147483647 % 2147483647 = %d, want 0", r)
+ }
+}
+func TestConstFolduint16add(t *testing.T) {
+ var x, y, r uint16
+ x = 0
+ y = 0
+ r = x + y
+ if r != 0 {
+ t.Errorf("0 + 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x + y
+ if r != 1 {
+ t.Errorf("0 + 1 = %d, want 1", r)
+ }
+ y = 65535
+ r = x + y
+ if r != 65535 {
+ t.Errorf("0 + 65535 = %d, want 65535", r)
+ }
+ x = 1
+ y = 0
+ r = x + y
+ if r != 1 {
+ t.Errorf("1 + 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x + y
+ if r != 2 {
+ t.Errorf("1 + 1 = %d, want 2", r)
+ }
+ y = 65535
+ r = x + y
+ if r != 0 {
+ t.Errorf("1 + 65535 = %d, want 0", r)
+ }
+ x = 65535
+ y = 0
+ r = x + y
+ if r != 65535 {
+ t.Errorf("65535 + 0 = %d, want 65535", r)
+ }
+ y = 1
+ r = x + y
+ if r != 0 {
+ t.Errorf("65535 + 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x + y
+ if r != 65534 {
+ t.Errorf("65535 + 65535 = %d, want 65534", r)
+ }
+}
+func TestConstFolduint16sub(t *testing.T) {
+ var x, y, r uint16
+ x = 0
+ y = 0
+ r = x - y
+ if r != 0 {
+ t.Errorf("0 - 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x - y
+ if r != 65535 {
+ t.Errorf("0 - 1 = %d, want 65535", r)
+ }
+ y = 65535
+ r = x - y
+ if r != 1 {
+ t.Errorf("0 - 65535 = %d, want 1", r)
+ }
+ x = 1
+ y = 0
+ r = x - y
+ if r != 1 {
+ t.Errorf("1 - 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x - y
+ if r != 0 {
+ t.Errorf("1 - 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x - y
+ if r != 2 {
+ t.Errorf("1 - 65535 = %d, want 2", r)
+ }
+ x = 65535
+ y = 0
+ r = x - y
+ if r != 65535 {
+ t.Errorf("65535 - 0 = %d, want 65535", r)
+ }
+ y = 1
+ r = x - y
+ if r != 65534 {
+ t.Errorf("65535 - 1 = %d, want 65534", r)
+ }
+ y = 65535
+ r = x - y
+ if r != 0 {
+ t.Errorf("65535 - 65535 = %d, want 0", r)
+ }
+}
+func TestConstFolduint16div(t *testing.T) {
+ var x, y, r uint16
+ x = 0
+ y = 1
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / 65535 = %d, want 0", r)
+ }
+ x = 1
+ y = 1
+ r = x / y
+ if r != 1 {
+ t.Errorf("1 / 1 = %d, want 1", r)
+ }
+ y = 65535
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 / 65535 = %d, want 0", r)
+ }
+ x = 65535
+ y = 1
+ r = x / y
+ if r != 65535 {
+ t.Errorf("65535 / 1 = %d, want 65535", r)
+ }
+ y = 65535
+ r = x / y
+ if r != 1 {
+ t.Errorf("65535 / 65535 = %d, want 1", r)
+ }
+}
+func TestConstFolduint16mul(t *testing.T) {
+ var x, y, r uint16
+ x = 0
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * 65535 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("1 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != 1 {
+ t.Errorf("1 * 1 = %d, want 1", r)
+ }
+ y = 65535
+ r = x * y
+ if r != 65535 {
+ t.Errorf("1 * 65535 = %d, want 65535", r)
+ }
+ x = 65535
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("65535 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != 65535 {
+ t.Errorf("65535 * 1 = %d, want 65535", r)
+ }
+ y = 65535
+ r = x * y
+ if r != 1 {
+ t.Errorf("65535 * 65535 = %d, want 1", r)
+ }
+}
+func TestConstFolduint16mod(t *testing.T) {
+ var x, y, r uint16
+ x = 0
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % 65535 = %d, want 0", r)
+ }
+ x = 1
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("1 % 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 % 65535 = %d, want 1", r)
+ }
+ x = 65535
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("65535 % 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x % y
+ if r != 0 {
+ t.Errorf("65535 % 65535 = %d, want 0", r)
+ }
+}
+func TestConstFoldint16add(t *testing.T) {
+ var x, y, r int16
+ x = -32768
+ y = -32768
+ r = x + y
+ if r != 0 {
+ t.Errorf("-32768 + -32768 = %d, want 0", r)
+ }
+ y = -32767
+ r = x + y
+ if r != 1 {
+ t.Errorf("-32768 + -32767 = %d, want 1", r)
+ }
+ y = -1
+ r = x + y
+ if r != 32767 {
+ t.Errorf("-32768 + -1 = %d, want 32767", r)
+ }
+ y = 0
+ r = x + y
+ if r != -32768 {
+ t.Errorf("-32768 + 0 = %d, want -32768", r)
+ }
+ y = 1
+ r = x + y
+ if r != -32767 {
+ t.Errorf("-32768 + 1 = %d, want -32767", r)
+ }
+ y = 32766
+ r = x + y
+ if r != -2 {
+ t.Errorf("-32768 + 32766 = %d, want -2", r)
+ }
+ y = 32767
+ r = x + y
+ if r != -1 {
+ t.Errorf("-32768 + 32767 = %d, want -1", r)
+ }
+ x = -32767
+ y = -32768
+ r = x + y
+ if r != 1 {
+ t.Errorf("-32767 + -32768 = %d, want 1", r)
+ }
+ y = -32767
+ r = x + y
+ if r != 2 {
+ t.Errorf("-32767 + -32767 = %d, want 2", r)
+ }
+ y = -1
+ r = x + y
+ if r != -32768 {
+ t.Errorf("-32767 + -1 = %d, want -32768", r)
+ }
+ y = 0
+ r = x + y
+ if r != -32767 {
+ t.Errorf("-32767 + 0 = %d, want -32767", r)
+ }
+ y = 1
+ r = x + y
+ if r != -32766 {
+ t.Errorf("-32767 + 1 = %d, want -32766", r)
+ }
+ y = 32766
+ r = x + y
+ if r != -1 {
+ t.Errorf("-32767 + 32766 = %d, want -1", r)
+ }
+ y = 32767
+ r = x + y
+ if r != 0 {
+ t.Errorf("-32767 + 32767 = %d, want 0", r)
+ }
+ x = -1
+ y = -32768
+ r = x + y
+ if r != 32767 {
+ t.Errorf("-1 + -32768 = %d, want 32767", r)
+ }
+ y = -32767
+ r = x + y
+ if r != -32768 {
+ t.Errorf("-1 + -32767 = %d, want -32768", r)
+ }
+ y = -1
+ r = x + y
+ if r != -2 {
+ t.Errorf("-1 + -1 = %d, want -2", r)
+ }
+ y = 0
+ r = x + y
+ if r != -1 {
+ t.Errorf("-1 + 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x + y
+ if r != 0 {
+ t.Errorf("-1 + 1 = %d, want 0", r)
+ }
+ y = 32766
+ r = x + y
+ if r != 32765 {
+ t.Errorf("-1 + 32766 = %d, want 32765", r)
+ }
+ y = 32767
+ r = x + y
+ if r != 32766 {
+ t.Errorf("-1 + 32767 = %d, want 32766", r)
+ }
+ x = 0
+ y = -32768
+ r = x + y
+ if r != -32768 {
+ t.Errorf("0 + -32768 = %d, want -32768", r)
+ }
+ y = -32767
+ r = x + y
+ if r != -32767 {
+ t.Errorf("0 + -32767 = %d, want -32767", r)
+ }
+ y = -1
+ r = x + y
+ if r != -1 {
+ t.Errorf("0 + -1 = %d, want -1", r)
+ }
+ y = 0
+ r = x + y
+ if r != 0 {
+ t.Errorf("0 + 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x + y
+ if r != 1 {
+ t.Errorf("0 + 1 = %d, want 1", r)
+ }
+ y = 32766
+ r = x + y
+ if r != 32766 {
+ t.Errorf("0 + 32766 = %d, want 32766", r)
+ }
+ y = 32767
+ r = x + y
+ if r != 32767 {
+ t.Errorf("0 + 32767 = %d, want 32767", r)
+ }
+ x = 1
+ y = -32768
+ r = x + y
+ if r != -32767 {
+ t.Errorf("1 + -32768 = %d, want -32767", r)
+ }
+ y = -32767
+ r = x + y
+ if r != -32766 {
+ t.Errorf("1 + -32767 = %d, want -32766", r)
+ }
+ y = -1
+ r = x + y
+ if r != 0 {
+ t.Errorf("1 + -1 = %d, want 0", r)
+ }
+ y = 0
+ r = x + y
+ if r != 1 {
+ t.Errorf("1 + 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x + y
+ if r != 2 {
+ t.Errorf("1 + 1 = %d, want 2", r)
+ }
+ y = 32766
+ r = x + y
+ if r != 32767 {
+ t.Errorf("1 + 32766 = %d, want 32767", r)
+ }
+ y = 32767
+ r = x + y
+ if r != -32768 {
+ t.Errorf("1 + 32767 = %d, want -32768", r)
+ }
+ x = 32766
+ y = -32768
+ r = x + y
+ if r != -2 {
+ t.Errorf("32766 + -32768 = %d, want -2", r)
+ }
+ y = -32767
+ r = x + y
+ if r != -1 {
+ t.Errorf("32766 + -32767 = %d, want -1", r)
+ }
+ y = -1
+ r = x + y
+ if r != 32765 {
+ t.Errorf("32766 + -1 = %d, want 32765", r)
+ }
+ y = 0
+ r = x + y
+ if r != 32766 {
+ t.Errorf("32766 + 0 = %d, want 32766", r)
+ }
+ y = 1
+ r = x + y
+ if r != 32767 {
+ t.Errorf("32766 + 1 = %d, want 32767", r)
+ }
+ y = 32766
+ r = x + y
+ if r != -4 {
+ t.Errorf("32766 + 32766 = %d, want -4", r)
+ }
+ y = 32767
+ r = x + y
+ if r != -3 {
+ t.Errorf("32766 + 32767 = %d, want -3", r)
+ }
+ x = 32767
+ y = -32768
+ r = x + y
+ if r != -1 {
+ t.Errorf("32767 + -32768 = %d, want -1", r)
+ }
+ y = -32767
+ r = x + y
+ if r != 0 {
+ t.Errorf("32767 + -32767 = %d, want 0", r)
+ }
+ y = -1
+ r = x + y
+ if r != 32766 {
+ t.Errorf("32767 + -1 = %d, want 32766", r)
+ }
+ y = 0
+ r = x + y
+ if r != 32767 {
+ t.Errorf("32767 + 0 = %d, want 32767", r)
+ }
+ y = 1
+ r = x + y
+ if r != -32768 {
+ t.Errorf("32767 + 1 = %d, want -32768", r)
+ }
+ y = 32766
+ r = x + y
+ if r != -3 {
+ t.Errorf("32767 + 32766 = %d, want -3", r)
+ }
+ y = 32767
+ r = x + y
+ if r != -2 {
+ t.Errorf("32767 + 32767 = %d, want -2", r)
+ }
+}
+func TestConstFoldint16sub(t *testing.T) {
+ var x, y, r int16
+ x = -32768
+ y = -32768
+ r = x - y
+ if r != 0 {
+ t.Errorf("-32768 - -32768 = %d, want 0", r)
+ }
+ y = -32767
+ r = x - y
+ if r != -1 {
+ t.Errorf("-32768 - -32767 = %d, want -1", r)
+ }
+ y = -1
+ r = x - y
+ if r != -32767 {
+ t.Errorf("-32768 - -1 = %d, want -32767", r)
+ }
+ y = 0
+ r = x - y
+ if r != -32768 {
+ t.Errorf("-32768 - 0 = %d, want -32768", r)
+ }
+ y = 1
+ r = x - y
+ if r != 32767 {
+ t.Errorf("-32768 - 1 = %d, want 32767", r)
+ }
+ y = 32766
+ r = x - y
+ if r != 2 {
+ t.Errorf("-32768 - 32766 = %d, want 2", r)
+ }
+ y = 32767
+ r = x - y
+ if r != 1 {
+ t.Errorf("-32768 - 32767 = %d, want 1", r)
+ }
+ x = -32767
+ y = -32768
+ r = x - y
+ if r != 1 {
+ t.Errorf("-32767 - -32768 = %d, want 1", r)
+ }
+ y = -32767
+ r = x - y
+ if r != 0 {
+ t.Errorf("-32767 - -32767 = %d, want 0", r)
+ }
+ y = -1
+ r = x - y
+ if r != -32766 {
+ t.Errorf("-32767 - -1 = %d, want -32766", r)
+ }
+ y = 0
+ r = x - y
+ if r != -32767 {
+ t.Errorf("-32767 - 0 = %d, want -32767", r)
+ }
+ y = 1
+ r = x - y
+ if r != -32768 {
+ t.Errorf("-32767 - 1 = %d, want -32768", r)
+ }
+ y = 32766
+ r = x - y
+ if r != 3 {
+ t.Errorf("-32767 - 32766 = %d, want 3", r)
+ }
+ y = 32767
+ r = x - y
+ if r != 2 {
+ t.Errorf("-32767 - 32767 = %d, want 2", r)
+ }
+ x = -1
+ y = -32768
+ r = x - y
+ if r != 32767 {
+ t.Errorf("-1 - -32768 = %d, want 32767", r)
+ }
+ y = -32767
+ r = x - y
+ if r != 32766 {
+ t.Errorf("-1 - -32767 = %d, want 32766", r)
+ }
+ y = -1
+ r = x - y
+ if r != 0 {
+ t.Errorf("-1 - -1 = %d, want 0", r)
+ }
+ y = 0
+ r = x - y
+ if r != -1 {
+ t.Errorf("-1 - 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x - y
+ if r != -2 {
+ t.Errorf("-1 - 1 = %d, want -2", r)
+ }
+ y = 32766
+ r = x - y
+ if r != -32767 {
+ t.Errorf("-1 - 32766 = %d, want -32767", r)
+ }
+ y = 32767
+ r = x - y
+ if r != -32768 {
+ t.Errorf("-1 - 32767 = %d, want -32768", r)
+ }
+ x = 0
+ y = -32768
+ r = x - y
+ if r != -32768 {
+ t.Errorf("0 - -32768 = %d, want -32768", r)
+ }
+ y = -32767
+ r = x - y
+ if r != 32767 {
+ t.Errorf("0 - -32767 = %d, want 32767", r)
+ }
+ y = -1
+ r = x - y
+ if r != 1 {
+ t.Errorf("0 - -1 = %d, want 1", r)
+ }
+ y = 0
+ r = x - y
+ if r != 0 {
+ t.Errorf("0 - 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x - y
+ if r != -1 {
+ t.Errorf("0 - 1 = %d, want -1", r)
+ }
+ y = 32766
+ r = x - y
+ if r != -32766 {
+ t.Errorf("0 - 32766 = %d, want -32766", r)
+ }
+ y = 32767
+ r = x - y
+ if r != -32767 {
+ t.Errorf("0 - 32767 = %d, want -32767", r)
+ }
+ x = 1
+ y = -32768
+ r = x - y
+ if r != -32767 {
+ t.Errorf("1 - -32768 = %d, want -32767", r)
+ }
+ y = -32767
+ r = x - y
+ if r != -32768 {
+ t.Errorf("1 - -32767 = %d, want -32768", r)
+ }
+ y = -1
+ r = x - y
+ if r != 2 {
+ t.Errorf("1 - -1 = %d, want 2", r)
+ }
+ y = 0
+ r = x - y
+ if r != 1 {
+ t.Errorf("1 - 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x - y
+ if r != 0 {
+ t.Errorf("1 - 1 = %d, want 0", r)
+ }
+ y = 32766
+ r = x - y
+ if r != -32765 {
+ t.Errorf("1 - 32766 = %d, want -32765", r)
+ }
+ y = 32767
+ r = x - y
+ if r != -32766 {
+ t.Errorf("1 - 32767 = %d, want -32766", r)
+ }
+ x = 32766
+ y = -32768
+ r = x - y
+ if r != -2 {
+ t.Errorf("32766 - -32768 = %d, want -2", r)
+ }
+ y = -32767
+ r = x - y
+ if r != -3 {
+ t.Errorf("32766 - -32767 = %d, want -3", r)
+ }
+ y = -1
+ r = x - y
+ if r != 32767 {
+ t.Errorf("32766 - -1 = %d, want 32767", r)
+ }
+ y = 0
+ r = x - y
+ if r != 32766 {
+ t.Errorf("32766 - 0 = %d, want 32766", r)
+ }
+ y = 1
+ r = x - y
+ if r != 32765 {
+ t.Errorf("32766 - 1 = %d, want 32765", r)
+ }
+ y = 32766
+ r = x - y
+ if r != 0 {
+ t.Errorf("32766 - 32766 = %d, want 0", r)
+ }
+ y = 32767
+ r = x - y
+ if r != -1 {
+ t.Errorf("32766 - 32767 = %d, want -1", r)
+ }
+ x = 32767
+ y = -32768
+ r = x - y
+ if r != -1 {
+ t.Errorf("32767 - -32768 = %d, want -1", r)
+ }
+ y = -32767
+ r = x - y
+ if r != -2 {
+ t.Errorf("32767 - -32767 = %d, want -2", r)
+ }
+ y = -1
+ r = x - y
+ if r != -32768 {
+ t.Errorf("32767 - -1 = %d, want -32768", r)
+ }
+ y = 0
+ r = x - y
+ if r != 32767 {
+ t.Errorf("32767 - 0 = %d, want 32767", r)
+ }
+ y = 1
+ r = x - y
+ if r != 32766 {
+ t.Errorf("32767 - 1 = %d, want 32766", r)
+ }
+ y = 32766
+ r = x - y
+ if r != 1 {
+ t.Errorf("32767 - 32766 = %d, want 1", r)
+ }
+ y = 32767
+ r = x - y
+ if r != 0 {
+ t.Errorf("32767 - 32767 = %d, want 0", r)
+ }
+}
+func TestConstFoldint16div(t *testing.T) {
+ var x, y, r int16
+ x = -32768
+ y = -32768
+ r = x / y
+ if r != 1 {
+ t.Errorf("-32768 / -32768 = %d, want 1", r)
+ }
+ y = -32767
+ r = x / y
+ if r != 1 {
+ t.Errorf("-32768 / -32767 = %d, want 1", r)
+ }
+ y = -1
+ r = x / y
+ if r != -32768 {
+ t.Errorf("-32768 / -1 = %d, want -32768", r)
+ }
+ y = 1
+ r = x / y
+ if r != -32768 {
+ t.Errorf("-32768 / 1 = %d, want -32768", r)
+ }
+ y = 32766
+ r = x / y
+ if r != -1 {
+ t.Errorf("-32768 / 32766 = %d, want -1", r)
+ }
+ y = 32767
+ r = x / y
+ if r != -1 {
+ t.Errorf("-32768 / 32767 = %d, want -1", r)
+ }
+ x = -32767
+ y = -32768
+ r = x / y
+ if r != 0 {
+ t.Errorf("-32767 / -32768 = %d, want 0", r)
+ }
+ y = -32767
+ r = x / y
+ if r != 1 {
+ t.Errorf("-32767 / -32767 = %d, want 1", r)
+ }
+ y = -1
+ r = x / y
+ if r != 32767 {
+ t.Errorf("-32767 / -1 = %d, want 32767", r)
+ }
+ y = 1
+ r = x / y
+ if r != -32767 {
+ t.Errorf("-32767 / 1 = %d, want -32767", r)
+ }
+ y = 32766
+ r = x / y
+ if r != -1 {
+ t.Errorf("-32767 / 32766 = %d, want -1", r)
+ }
+ y = 32767
+ r = x / y
+ if r != -1 {
+ t.Errorf("-32767 / 32767 = %d, want -1", r)
+ }
+ x = -1
+ y = -32768
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 / -32768 = %d, want 0", r)
+ }
+ y = -32767
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 / -32767 = %d, want 0", r)
+ }
+ y = -1
+ r = x / y
+ if r != 1 {
+ t.Errorf("-1 / -1 = %d, want 1", r)
+ }
+ y = 1
+ r = x / y
+ if r != -1 {
+ t.Errorf("-1 / 1 = %d, want -1", r)
+ }
+ y = 32766
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 / 32766 = %d, want 0", r)
+ }
+ y = 32767
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 / 32767 = %d, want 0", r)
+ }
+ x = 0
+ y = -32768
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / -32768 = %d, want 0", r)
+ }
+ y = -32767
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / -32767 = %d, want 0", r)
+ }
+ y = -1
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / 1 = %d, want 0", r)
+ }
+ y = 32766
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / 32766 = %d, want 0", r)
+ }
+ y = 32767
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / 32767 = %d, want 0", r)
+ }
+ x = 1
+ y = -32768
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 / -32768 = %d, want 0", r)
+ }
+ y = -32767
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 / -32767 = %d, want 0", r)
+ }
+ y = -1
+ r = x / y
+ if r != -1 {
+ t.Errorf("1 / -1 = %d, want -1", r)
+ }
+ y = 1
+ r = x / y
+ if r != 1 {
+ t.Errorf("1 / 1 = %d, want 1", r)
+ }
+ y = 32766
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 / 32766 = %d, want 0", r)
+ }
+ y = 32767
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 / 32767 = %d, want 0", r)
+ }
+ x = 32766
+ y = -32768
+ r = x / y
+ if r != 0 {
+ t.Errorf("32766 / -32768 = %d, want 0", r)
+ }
+ y = -32767
+ r = x / y
+ if r != 0 {
+ t.Errorf("32766 / -32767 = %d, want 0", r)
+ }
+ y = -1
+ r = x / y
+ if r != -32766 {
+ t.Errorf("32766 / -1 = %d, want -32766", r)
+ }
+ y = 1
+ r = x / y
+ if r != 32766 {
+ t.Errorf("32766 / 1 = %d, want 32766", r)
+ }
+ y = 32766
+ r = x / y
+ if r != 1 {
+ t.Errorf("32766 / 32766 = %d, want 1", r)
+ }
+ y = 32767
+ r = x / y
+ if r != 0 {
+ t.Errorf("32766 / 32767 = %d, want 0", r)
+ }
+ x = 32767
+ y = -32768
+ r = x / y
+ if r != 0 {
+ t.Errorf("32767 / -32768 = %d, want 0", r)
+ }
+ y = -32767
+ r = x / y
+ if r != -1 {
+ t.Errorf("32767 / -32767 = %d, want -1", r)
+ }
+ y = -1
+ r = x / y
+ if r != -32767 {
+ t.Errorf("32767 / -1 = %d, want -32767", r)
+ }
+ y = 1
+ r = x / y
+ if r != 32767 {
+ t.Errorf("32767 / 1 = %d, want 32767", r)
+ }
+ y = 32766
+ r = x / y
+ if r != 1 {
+ t.Errorf("32767 / 32766 = %d, want 1", r)
+ }
+ y = 32767
+ r = x / y
+ if r != 1 {
+ t.Errorf("32767 / 32767 = %d, want 1", r)
+ }
+}
+func TestConstFoldint16mul(t *testing.T) {
+ var x, y, r int16
+ x = -32768
+ y = -32768
+ r = x * y
+ if r != 0 {
+ t.Errorf("-32768 * -32768 = %d, want 0", r)
+ }
+ y = -32767
+ r = x * y
+ if r != -32768 {
+ t.Errorf("-32768 * -32767 = %d, want -32768", r)
+ }
+ y = -1
+ r = x * y
+ if r != -32768 {
+ t.Errorf("-32768 * -1 = %d, want -32768", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("-32768 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != -32768 {
+ t.Errorf("-32768 * 1 = %d, want -32768", r)
+ }
+ y = 32766
+ r = x * y
+ if r != 0 {
+ t.Errorf("-32768 * 32766 = %d, want 0", r)
+ }
+ y = 32767
+ r = x * y
+ if r != -32768 {
+ t.Errorf("-32768 * 32767 = %d, want -32768", r)
+ }
+ x = -32767
+ y = -32768
+ r = x * y
+ if r != -32768 {
+ t.Errorf("-32767 * -32768 = %d, want -32768", r)
+ }
+ y = -32767
+ r = x * y
+ if r != 1 {
+ t.Errorf("-32767 * -32767 = %d, want 1", r)
+ }
+ y = -1
+ r = x * y
+ if r != 32767 {
+ t.Errorf("-32767 * -1 = %d, want 32767", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("-32767 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != -32767 {
+ t.Errorf("-32767 * 1 = %d, want -32767", r)
+ }
+ y = 32766
+ r = x * y
+ if r != 32766 {
+ t.Errorf("-32767 * 32766 = %d, want 32766", r)
+ }
+ y = 32767
+ r = x * y
+ if r != -1 {
+ t.Errorf("-32767 * 32767 = %d, want -1", r)
+ }
+ x = -1
+ y = -32768
+ r = x * y
+ if r != -32768 {
+ t.Errorf("-1 * -32768 = %d, want -32768", r)
+ }
+ y = -32767
+ r = x * y
+ if r != 32767 {
+ t.Errorf("-1 * -32767 = %d, want 32767", r)
+ }
+ y = -1
+ r = x * y
+ if r != 1 {
+ t.Errorf("-1 * -1 = %d, want 1", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("-1 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != -1 {
+ t.Errorf("-1 * 1 = %d, want -1", r)
+ }
+ y = 32766
+ r = x * y
+ if r != -32766 {
+ t.Errorf("-1 * 32766 = %d, want -32766", r)
+ }
+ y = 32767
+ r = x * y
+ if r != -32767 {
+ t.Errorf("-1 * 32767 = %d, want -32767", r)
+ }
+ x = 0
+ y = -32768
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * -32768 = %d, want 0", r)
+ }
+ y = -32767
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * -32767 = %d, want 0", r)
+ }
+ y = -1
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * -1 = %d, want 0", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * 1 = %d, want 0", r)
+ }
+ y = 32766
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * 32766 = %d, want 0", r)
+ }
+ y = 32767
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * 32767 = %d, want 0", r)
+ }
+ x = 1
+ y = -32768
+ r = x * y
+ if r != -32768 {
+ t.Errorf("1 * -32768 = %d, want -32768", r)
+ }
+ y = -32767
+ r = x * y
+ if r != -32767 {
+ t.Errorf("1 * -32767 = %d, want -32767", r)
+ }
+ y = -1
+ r = x * y
+ if r != -1 {
+ t.Errorf("1 * -1 = %d, want -1", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("1 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != 1 {
+ t.Errorf("1 * 1 = %d, want 1", r)
+ }
+ y = 32766
+ r = x * y
+ if r != 32766 {
+ t.Errorf("1 * 32766 = %d, want 32766", r)
+ }
+ y = 32767
+ r = x * y
+ if r != 32767 {
+ t.Errorf("1 * 32767 = %d, want 32767", r)
+ }
+ x = 32766
+ y = -32768
+ r = x * y
+ if r != 0 {
+ t.Errorf("32766 * -32768 = %d, want 0", r)
+ }
+ y = -32767
+ r = x * y
+ if r != 32766 {
+ t.Errorf("32766 * -32767 = %d, want 32766", r)
+ }
+ y = -1
+ r = x * y
+ if r != -32766 {
+ t.Errorf("32766 * -1 = %d, want -32766", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("32766 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != 32766 {
+ t.Errorf("32766 * 1 = %d, want 32766", r)
+ }
+ y = 32766
+ r = x * y
+ if r != 4 {
+ t.Errorf("32766 * 32766 = %d, want 4", r)
+ }
+ y = 32767
+ r = x * y
+ if r != -32766 {
+ t.Errorf("32766 * 32767 = %d, want -32766", r)
+ }
+ x = 32767
+ y = -32768
+ r = x * y
+ if r != -32768 {
+ t.Errorf("32767 * -32768 = %d, want -32768", r)
+ }
+ y = -32767
+ r = x * y
+ if r != -1 {
+ t.Errorf("32767 * -32767 = %d, want -1", r)
+ }
+ y = -1
+ r = x * y
+ if r != -32767 {
+ t.Errorf("32767 * -1 = %d, want -32767", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("32767 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != 32767 {
+ t.Errorf("32767 * 1 = %d, want 32767", r)
+ }
+ y = 32766
+ r = x * y
+ if r != -32766 {
+ t.Errorf("32767 * 32766 = %d, want -32766", r)
+ }
+ y = 32767
+ r = x * y
+ if r != 1 {
+ t.Errorf("32767 * 32767 = %d, want 1", r)
+ }
+}
+func TestConstFoldint16mod(t *testing.T) {
+ var x, y, r int16
+ x = -32768
+ y = -32768
+ r = x % y
+ if r != 0 {
+ t.Errorf("-32768 % -32768 = %d, want 0", r)
+ }
+ y = -32767
+ r = x % y
+ if r != -1 {
+ t.Errorf("-32768 % -32767 = %d, want -1", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-32768 % -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-32768 % 1 = %d, want 0", r)
+ }
+ y = 32766
+ r = x % y
+ if r != -2 {
+ t.Errorf("-32768 % 32766 = %d, want -2", r)
+ }
+ y = 32767
+ r = x % y
+ if r != -1 {
+ t.Errorf("-32768 % 32767 = %d, want -1", r)
+ }
+ x = -32767
+ y = -32768
+ r = x % y
+ if r != -32767 {
+ t.Errorf("-32767 % -32768 = %d, want -32767", r)
+ }
+ y = -32767
+ r = x % y
+ if r != 0 {
+ t.Errorf("-32767 % -32767 = %d, want 0", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-32767 % -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-32767 % 1 = %d, want 0", r)
+ }
+ y = 32766
+ r = x % y
+ if r != -1 {
+ t.Errorf("-32767 % 32766 = %d, want -1", r)
+ }
+ y = 32767
+ r = x % y
+ if r != 0 {
+ t.Errorf("-32767 % 32767 = %d, want 0", r)
+ }
+ x = -1
+ y = -32768
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 % -32768 = %d, want -1", r)
+ }
+ y = -32767
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 % -32767 = %d, want -1", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-1 % -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-1 % 1 = %d, want 0", r)
+ }
+ y = 32766
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 % 32766 = %d, want -1", r)
+ }
+ y = 32767
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 % 32767 = %d, want -1", r)
+ }
+ x = 0
+ y = -32768
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % -32768 = %d, want 0", r)
+ }
+ y = -32767
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % -32767 = %d, want 0", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % 1 = %d, want 0", r)
+ }
+ y = 32766
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % 32766 = %d, want 0", r)
+ }
+ y = 32767
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % 32767 = %d, want 0", r)
+ }
+ x = 1
+ y = -32768
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 % -32768 = %d, want 1", r)
+ }
+ y = -32767
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 % -32767 = %d, want 1", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("1 % -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("1 % 1 = %d, want 0", r)
+ }
+ y = 32766
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 % 32766 = %d, want 1", r)
+ }
+ y = 32767
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 % 32767 = %d, want 1", r)
+ }
+ x = 32766
+ y = -32768
+ r = x % y
+ if r != 32766 {
+ t.Errorf("32766 % -32768 = %d, want 32766", r)
+ }
+ y = -32767
+ r = x % y
+ if r != 32766 {
+ t.Errorf("32766 % -32767 = %d, want 32766", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("32766 % -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("32766 % 1 = %d, want 0", r)
+ }
+ y = 32766
+ r = x % y
+ if r != 0 {
+ t.Errorf("32766 % 32766 = %d, want 0", r)
+ }
+ y = 32767
+ r = x % y
+ if r != 32766 {
+ t.Errorf("32766 % 32767 = %d, want 32766", r)
+ }
+ x = 32767
+ y = -32768
+ r = x % y
+ if r != 32767 {
+ t.Errorf("32767 % -32768 = %d, want 32767", r)
+ }
+ y = -32767
+ r = x % y
+ if r != 0 {
+ t.Errorf("32767 % -32767 = %d, want 0", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("32767 % -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("32767 % 1 = %d, want 0", r)
+ }
+ y = 32766
+ r = x % y
+ if r != 1 {
+ t.Errorf("32767 % 32766 = %d, want 1", r)
+ }
+ y = 32767
+ r = x % y
+ if r != 0 {
+ t.Errorf("32767 % 32767 = %d, want 0", r)
+ }
+}
+func TestConstFolduint8add(t *testing.T) {
+ var x, y, r uint8
+ x = 0
+ y = 0
+ r = x + y
+ if r != 0 {
+ t.Errorf("0 + 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x + y
+ if r != 1 {
+ t.Errorf("0 + 1 = %d, want 1", r)
+ }
+ y = 255
+ r = x + y
+ if r != 255 {
+ t.Errorf("0 + 255 = %d, want 255", r)
+ }
+ x = 1
+ y = 0
+ r = x + y
+ if r != 1 {
+ t.Errorf("1 + 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x + y
+ if r != 2 {
+ t.Errorf("1 + 1 = %d, want 2", r)
+ }
+ y = 255
+ r = x + y
+ if r != 0 {
+ t.Errorf("1 + 255 = %d, want 0", r)
+ }
+ x = 255
+ y = 0
+ r = x + y
+ if r != 255 {
+ t.Errorf("255 + 0 = %d, want 255", r)
+ }
+ y = 1
+ r = x + y
+ if r != 0 {
+ t.Errorf("255 + 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x + y
+ if r != 254 {
+ t.Errorf("255 + 255 = %d, want 254", r)
+ }
+}
+func TestConstFolduint8sub(t *testing.T) {
+ var x, y, r uint8
+ x = 0
+ y = 0
+ r = x - y
+ if r != 0 {
+ t.Errorf("0 - 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x - y
+ if r != 255 {
+ t.Errorf("0 - 1 = %d, want 255", r)
+ }
+ y = 255
+ r = x - y
+ if r != 1 {
+ t.Errorf("0 - 255 = %d, want 1", r)
+ }
+ x = 1
+ y = 0
+ r = x - y
+ if r != 1 {
+ t.Errorf("1 - 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x - y
+ if r != 0 {
+ t.Errorf("1 - 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x - y
+ if r != 2 {
+ t.Errorf("1 - 255 = %d, want 2", r)
+ }
+ x = 255
+ y = 0
+ r = x - y
+ if r != 255 {
+ t.Errorf("255 - 0 = %d, want 255", r)
+ }
+ y = 1
+ r = x - y
+ if r != 254 {
+ t.Errorf("255 - 1 = %d, want 254", r)
+ }
+ y = 255
+ r = x - y
+ if r != 0 {
+ t.Errorf("255 - 255 = %d, want 0", r)
+ }
+}
+func TestConstFolduint8div(t *testing.T) {
+ var x, y, r uint8
+ x = 0
+ y = 1
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / 255 = %d, want 0", r)
+ }
+ x = 1
+ y = 1
+ r = x / y
+ if r != 1 {
+ t.Errorf("1 / 1 = %d, want 1", r)
+ }
+ y = 255
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 / 255 = %d, want 0", r)
+ }
+ x = 255
+ y = 1
+ r = x / y
+ if r != 255 {
+ t.Errorf("255 / 1 = %d, want 255", r)
+ }
+ y = 255
+ r = x / y
+ if r != 1 {
+ t.Errorf("255 / 255 = %d, want 1", r)
+ }
+}
+func TestConstFolduint8mul(t *testing.T) {
+ var x, y, r uint8
+ x = 0
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * 255 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("1 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != 1 {
+ t.Errorf("1 * 1 = %d, want 1", r)
+ }
+ y = 255
+ r = x * y
+ if r != 255 {
+ t.Errorf("1 * 255 = %d, want 255", r)
+ }
+ x = 255
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("255 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != 255 {
+ t.Errorf("255 * 1 = %d, want 255", r)
+ }
+ y = 255
+ r = x * y
+ if r != 1 {
+ t.Errorf("255 * 255 = %d, want 1", r)
+ }
+}
+func TestConstFolduint8mod(t *testing.T) {
+ var x, y, r uint8
+ x = 0
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % 255 = %d, want 0", r)
+ }
+ x = 1
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("1 % 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 % 255 = %d, want 1", r)
+ }
+ x = 255
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("255 % 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x % y
+ if r != 0 {
+ t.Errorf("255 % 255 = %d, want 0", r)
+ }
+}
+func TestConstFoldint8add(t *testing.T) {
+ var x, y, r int8
+ x = -128
+ y = -128
+ r = x + y
+ if r != 0 {
+ t.Errorf("-128 + -128 = %d, want 0", r)
+ }
+ y = -127
+ r = x + y
+ if r != 1 {
+ t.Errorf("-128 + -127 = %d, want 1", r)
+ }
+ y = -1
+ r = x + y
+ if r != 127 {
+ t.Errorf("-128 + -1 = %d, want 127", r)
+ }
+ y = 0
+ r = x + y
+ if r != -128 {
+ t.Errorf("-128 + 0 = %d, want -128", r)
+ }
+ y = 1
+ r = x + y
+ if r != -127 {
+ t.Errorf("-128 + 1 = %d, want -127", r)
+ }
+ y = 126
+ r = x + y
+ if r != -2 {
+ t.Errorf("-128 + 126 = %d, want -2", r)
+ }
+ y = 127
+ r = x + y
+ if r != -1 {
+ t.Errorf("-128 + 127 = %d, want -1", r)
+ }
+ x = -127
+ y = -128
+ r = x + y
+ if r != 1 {
+ t.Errorf("-127 + -128 = %d, want 1", r)
+ }
+ y = -127
+ r = x + y
+ if r != 2 {
+ t.Errorf("-127 + -127 = %d, want 2", r)
+ }
+ y = -1
+ r = x + y
+ if r != -128 {
+ t.Errorf("-127 + -1 = %d, want -128", r)
+ }
+ y = 0
+ r = x + y
+ if r != -127 {
+ t.Errorf("-127 + 0 = %d, want -127", r)
+ }
+ y = 1
+ r = x + y
+ if r != -126 {
+ t.Errorf("-127 + 1 = %d, want -126", r)
+ }
+ y = 126
+ r = x + y
+ if r != -1 {
+ t.Errorf("-127 + 126 = %d, want -1", r)
+ }
+ y = 127
+ r = x + y
+ if r != 0 {
+ t.Errorf("-127 + 127 = %d, want 0", r)
+ }
+ x = -1
+ y = -128
+ r = x + y
+ if r != 127 {
+ t.Errorf("-1 + -128 = %d, want 127", r)
+ }
+ y = -127
+ r = x + y
+ if r != -128 {
+ t.Errorf("-1 + -127 = %d, want -128", r)
+ }
+ y = -1
+ r = x + y
+ if r != -2 {
+ t.Errorf("-1 + -1 = %d, want -2", r)
+ }
+ y = 0
+ r = x + y
+ if r != -1 {
+ t.Errorf("-1 + 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x + y
+ if r != 0 {
+ t.Errorf("-1 + 1 = %d, want 0", r)
+ }
+ y = 126
+ r = x + y
+ if r != 125 {
+ t.Errorf("-1 + 126 = %d, want 125", r)
+ }
+ y = 127
+ r = x + y
+ if r != 126 {
+ t.Errorf("-1 + 127 = %d, want 126", r)
+ }
+ x = 0
+ y = -128
+ r = x + y
+ if r != -128 {
+ t.Errorf("0 + -128 = %d, want -128", r)
+ }
+ y = -127
+ r = x + y
+ if r != -127 {
+ t.Errorf("0 + -127 = %d, want -127", r)
+ }
+ y = -1
+ r = x + y
+ if r != -1 {
+ t.Errorf("0 + -1 = %d, want -1", r)
+ }
+ y = 0
+ r = x + y
+ if r != 0 {
+ t.Errorf("0 + 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x + y
+ if r != 1 {
+ t.Errorf("0 + 1 = %d, want 1", r)
+ }
+ y = 126
+ r = x + y
+ if r != 126 {
+ t.Errorf("0 + 126 = %d, want 126", r)
+ }
+ y = 127
+ r = x + y
+ if r != 127 {
+ t.Errorf("0 + 127 = %d, want 127", r)
+ }
+ x = 1
+ y = -128
+ r = x + y
+ if r != -127 {
+ t.Errorf("1 + -128 = %d, want -127", r)
+ }
+ y = -127
+ r = x + y
+ if r != -126 {
+ t.Errorf("1 + -127 = %d, want -126", r)
+ }
+ y = -1
+ r = x + y
+ if r != 0 {
+ t.Errorf("1 + -1 = %d, want 0", r)
+ }
+ y = 0
+ r = x + y
+ if r != 1 {
+ t.Errorf("1 + 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x + y
+ if r != 2 {
+ t.Errorf("1 + 1 = %d, want 2", r)
+ }
+ y = 126
+ r = x + y
+ if r != 127 {
+ t.Errorf("1 + 126 = %d, want 127", r)
+ }
+ y = 127
+ r = x + y
+ if r != -128 {
+ t.Errorf("1 + 127 = %d, want -128", r)
+ }
+ x = 126
+ y = -128
+ r = x + y
+ if r != -2 {
+ t.Errorf("126 + -128 = %d, want -2", r)
+ }
+ y = -127
+ r = x + y
+ if r != -1 {
+ t.Errorf("126 + -127 = %d, want -1", r)
+ }
+ y = -1
+ r = x + y
+ if r != 125 {
+ t.Errorf("126 + -1 = %d, want 125", r)
+ }
+ y = 0
+ r = x + y
+ if r != 126 {
+ t.Errorf("126 + 0 = %d, want 126", r)
+ }
+ y = 1
+ r = x + y
+ if r != 127 {
+ t.Errorf("126 + 1 = %d, want 127", r)
+ }
+ y = 126
+ r = x + y
+ if r != -4 {
+ t.Errorf("126 + 126 = %d, want -4", r)
+ }
+ y = 127
+ r = x + y
+ if r != -3 {
+ t.Errorf("126 + 127 = %d, want -3", r)
+ }
+ x = 127
+ y = -128
+ r = x + y
+ if r != -1 {
+ t.Errorf("127 + -128 = %d, want -1", r)
+ }
+ y = -127
+ r = x + y
+ if r != 0 {
+ t.Errorf("127 + -127 = %d, want 0", r)
+ }
+ y = -1
+ r = x + y
+ if r != 126 {
+ t.Errorf("127 + -1 = %d, want 126", r)
+ }
+ y = 0
+ r = x + y
+ if r != 127 {
+ t.Errorf("127 + 0 = %d, want 127", r)
+ }
+ y = 1
+ r = x + y
+ if r != -128 {
+ t.Errorf("127 + 1 = %d, want -128", r)
+ }
+ y = 126
+ r = x + y
+ if r != -3 {
+ t.Errorf("127 + 126 = %d, want -3", r)
+ }
+ y = 127
+ r = x + y
+ if r != -2 {
+ t.Errorf("127 + 127 = %d, want -2", r)
+ }
+}
+func TestConstFoldint8sub(t *testing.T) {
+ var x, y, r int8
+ x = -128
+ y = -128
+ r = x - y
+ if r != 0 {
+ t.Errorf("-128 - -128 = %d, want 0", r)
+ }
+ y = -127
+ r = x - y
+ if r != -1 {
+ t.Errorf("-128 - -127 = %d, want -1", r)
+ }
+ y = -1
+ r = x - y
+ if r != -127 {
+ t.Errorf("-128 - -1 = %d, want -127", r)
+ }
+ y = 0
+ r = x - y
+ if r != -128 {
+ t.Errorf("-128 - 0 = %d, want -128", r)
+ }
+ y = 1
+ r = x - y
+ if r != 127 {
+ t.Errorf("-128 - 1 = %d, want 127", r)
+ }
+ y = 126
+ r = x - y
+ if r != 2 {
+ t.Errorf("-128 - 126 = %d, want 2", r)
+ }
+ y = 127
+ r = x - y
+ if r != 1 {
+ t.Errorf("-128 - 127 = %d, want 1", r)
+ }
+ x = -127
+ y = -128
+ r = x - y
+ if r != 1 {
+ t.Errorf("-127 - -128 = %d, want 1", r)
+ }
+ y = -127
+ r = x - y
+ if r != 0 {
+ t.Errorf("-127 - -127 = %d, want 0", r)
+ }
+ y = -1
+ r = x - y
+ if r != -126 {
+ t.Errorf("-127 - -1 = %d, want -126", r)
+ }
+ y = 0
+ r = x - y
+ if r != -127 {
+ t.Errorf("-127 - 0 = %d, want -127", r)
+ }
+ y = 1
+ r = x - y
+ if r != -128 {
+ t.Errorf("-127 - 1 = %d, want -128", r)
+ }
+ y = 126
+ r = x - y
+ if r != 3 {
+ t.Errorf("-127 - 126 = %d, want 3", r)
+ }
+ y = 127
+ r = x - y
+ if r != 2 {
+ t.Errorf("-127 - 127 = %d, want 2", r)
+ }
+ x = -1
+ y = -128
+ r = x - y
+ if r != 127 {
+ t.Errorf("-1 - -128 = %d, want 127", r)
+ }
+ y = -127
+ r = x - y
+ if r != 126 {
+ t.Errorf("-1 - -127 = %d, want 126", r)
+ }
+ y = -1
+ r = x - y
+ if r != 0 {
+ t.Errorf("-1 - -1 = %d, want 0", r)
+ }
+ y = 0
+ r = x - y
+ if r != -1 {
+ t.Errorf("-1 - 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x - y
+ if r != -2 {
+ t.Errorf("-1 - 1 = %d, want -2", r)
+ }
+ y = 126
+ r = x - y
+ if r != -127 {
+ t.Errorf("-1 - 126 = %d, want -127", r)
+ }
+ y = 127
+ r = x - y
+ if r != -128 {
+ t.Errorf("-1 - 127 = %d, want -128", r)
+ }
+ x = 0
+ y = -128
+ r = x - y
+ if r != -128 {
+ t.Errorf("0 - -128 = %d, want -128", r)
+ }
+ y = -127
+ r = x - y
+ if r != 127 {
+ t.Errorf("0 - -127 = %d, want 127", r)
+ }
+ y = -1
+ r = x - y
+ if r != 1 {
+ t.Errorf("0 - -1 = %d, want 1", r)
+ }
+ y = 0
+ r = x - y
+ if r != 0 {
+ t.Errorf("0 - 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x - y
+ if r != -1 {
+ t.Errorf("0 - 1 = %d, want -1", r)
+ }
+ y = 126
+ r = x - y
+ if r != -126 {
+ t.Errorf("0 - 126 = %d, want -126", r)
+ }
+ y = 127
+ r = x - y
+ if r != -127 {
+ t.Errorf("0 - 127 = %d, want -127", r)
+ }
+ x = 1
+ y = -128
+ r = x - y
+ if r != -127 {
+ t.Errorf("1 - -128 = %d, want -127", r)
+ }
+ y = -127
+ r = x - y
+ if r != -128 {
+ t.Errorf("1 - -127 = %d, want -128", r)
+ }
+ y = -1
+ r = x - y
+ if r != 2 {
+ t.Errorf("1 - -1 = %d, want 2", r)
+ }
+ y = 0
+ r = x - y
+ if r != 1 {
+ t.Errorf("1 - 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x - y
+ if r != 0 {
+ t.Errorf("1 - 1 = %d, want 0", r)
+ }
+ y = 126
+ r = x - y
+ if r != -125 {
+ t.Errorf("1 - 126 = %d, want -125", r)
+ }
+ y = 127
+ r = x - y
+ if r != -126 {
+ t.Errorf("1 - 127 = %d, want -126", r)
+ }
+ x = 126
+ y = -128
+ r = x - y
+ if r != -2 {
+ t.Errorf("126 - -128 = %d, want -2", r)
+ }
+ y = -127
+ r = x - y
+ if r != -3 {
+ t.Errorf("126 - -127 = %d, want -3", r)
+ }
+ y = -1
+ r = x - y
+ if r != 127 {
+ t.Errorf("126 - -1 = %d, want 127", r)
+ }
+ y = 0
+ r = x - y
+ if r != 126 {
+ t.Errorf("126 - 0 = %d, want 126", r)
+ }
+ y = 1
+ r = x - y
+ if r != 125 {
+ t.Errorf("126 - 1 = %d, want 125", r)
+ }
+ y = 126
+ r = x - y
+ if r != 0 {
+ t.Errorf("126 - 126 = %d, want 0", r)
+ }
+ y = 127
+ r = x - y
+ if r != -1 {
+ t.Errorf("126 - 127 = %d, want -1", r)
+ }
+ x = 127
+ y = -128
+ r = x - y
+ if r != -1 {
+ t.Errorf("127 - -128 = %d, want -1", r)
+ }
+ y = -127
+ r = x - y
+ if r != -2 {
+ t.Errorf("127 - -127 = %d, want -2", r)
+ }
+ y = -1
+ r = x - y
+ if r != -128 {
+ t.Errorf("127 - -1 = %d, want -128", r)
+ }
+ y = 0
+ r = x - y
+ if r != 127 {
+ t.Errorf("127 - 0 = %d, want 127", r)
+ }
+ y = 1
+ r = x - y
+ if r != 126 {
+ t.Errorf("127 - 1 = %d, want 126", r)
+ }
+ y = 126
+ r = x - y
+ if r != 1 {
+ t.Errorf("127 - 126 = %d, want 1", r)
+ }
+ y = 127
+ r = x - y
+ if r != 0 {
+ t.Errorf("127 - 127 = %d, want 0", r)
+ }
+}
+func TestConstFoldint8div(t *testing.T) {
+ var x, y, r int8
+ x = -128
+ y = -128
+ r = x / y
+ if r != 1 {
+ t.Errorf("-128 / -128 = %d, want 1", r)
+ }
+ y = -127
+ r = x / y
+ if r != 1 {
+ t.Errorf("-128 / -127 = %d, want 1", r)
+ }
+ y = -1
+ r = x / y
+ if r != -128 {
+ t.Errorf("-128 / -1 = %d, want -128", r)
+ }
+ y = 1
+ r = x / y
+ if r != -128 {
+ t.Errorf("-128 / 1 = %d, want -128", r)
+ }
+ y = 126
+ r = x / y
+ if r != -1 {
+ t.Errorf("-128 / 126 = %d, want -1", r)
+ }
+ y = 127
+ r = x / y
+ if r != -1 {
+ t.Errorf("-128 / 127 = %d, want -1", r)
+ }
+ x = -127
+ y = -128
+ r = x / y
+ if r != 0 {
+ t.Errorf("-127 / -128 = %d, want 0", r)
+ }
+ y = -127
+ r = x / y
+ if r != 1 {
+ t.Errorf("-127 / -127 = %d, want 1", r)
+ }
+ y = -1
+ r = x / y
+ if r != 127 {
+ t.Errorf("-127 / -1 = %d, want 127", r)
+ }
+ y = 1
+ r = x / y
+ if r != -127 {
+ t.Errorf("-127 / 1 = %d, want -127", r)
+ }
+ y = 126
+ r = x / y
+ if r != -1 {
+ t.Errorf("-127 / 126 = %d, want -1", r)
+ }
+ y = 127
+ r = x / y
+ if r != -1 {
+ t.Errorf("-127 / 127 = %d, want -1", r)
+ }
+ x = -1
+ y = -128
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 / -128 = %d, want 0", r)
+ }
+ y = -127
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 / -127 = %d, want 0", r)
+ }
+ y = -1
+ r = x / y
+ if r != 1 {
+ t.Errorf("-1 / -1 = %d, want 1", r)
+ }
+ y = 1
+ r = x / y
+ if r != -1 {
+ t.Errorf("-1 / 1 = %d, want -1", r)
+ }
+ y = 126
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 / 126 = %d, want 0", r)
+ }
+ y = 127
+ r = x / y
+ if r != 0 {
+ t.Errorf("-1 / 127 = %d, want 0", r)
+ }
+ x = 0
+ y = -128
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / -128 = %d, want 0", r)
+ }
+ y = -127
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / -127 = %d, want 0", r)
+ }
+ y = -1
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / 1 = %d, want 0", r)
+ }
+ y = 126
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / 126 = %d, want 0", r)
+ }
+ y = 127
+ r = x / y
+ if r != 0 {
+ t.Errorf("0 / 127 = %d, want 0", r)
+ }
+ x = 1
+ y = -128
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 / -128 = %d, want 0", r)
+ }
+ y = -127
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 / -127 = %d, want 0", r)
+ }
+ y = -1
+ r = x / y
+ if r != -1 {
+ t.Errorf("1 / -1 = %d, want -1", r)
+ }
+ y = 1
+ r = x / y
+ if r != 1 {
+ t.Errorf("1 / 1 = %d, want 1", r)
+ }
+ y = 126
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 / 126 = %d, want 0", r)
+ }
+ y = 127
+ r = x / y
+ if r != 0 {
+ t.Errorf("1 / 127 = %d, want 0", r)
+ }
+ x = 126
+ y = -128
+ r = x / y
+ if r != 0 {
+ t.Errorf("126 / -128 = %d, want 0", r)
+ }
+ y = -127
+ r = x / y
+ if r != 0 {
+ t.Errorf("126 / -127 = %d, want 0", r)
+ }
+ y = -1
+ r = x / y
+ if r != -126 {
+ t.Errorf("126 / -1 = %d, want -126", r)
+ }
+ y = 1
+ r = x / y
+ if r != 126 {
+ t.Errorf("126 / 1 = %d, want 126", r)
+ }
+ y = 126
+ r = x / y
+ if r != 1 {
+ t.Errorf("126 / 126 = %d, want 1", r)
+ }
+ y = 127
+ r = x / y
+ if r != 0 {
+ t.Errorf("126 / 127 = %d, want 0", r)
+ }
+ x = 127
+ y = -128
+ r = x / y
+ if r != 0 {
+ t.Errorf("127 / -128 = %d, want 0", r)
+ }
+ y = -127
+ r = x / y
+ if r != -1 {
+ t.Errorf("127 / -127 = %d, want -1", r)
+ }
+ y = -1
+ r = x / y
+ if r != -127 {
+ t.Errorf("127 / -1 = %d, want -127", r)
+ }
+ y = 1
+ r = x / y
+ if r != 127 {
+ t.Errorf("127 / 1 = %d, want 127", r)
+ }
+ y = 126
+ r = x / y
+ if r != 1 {
+ t.Errorf("127 / 126 = %d, want 1", r)
+ }
+ y = 127
+ r = x / y
+ if r != 1 {
+ t.Errorf("127 / 127 = %d, want 1", r)
+ }
+}
+func TestConstFoldint8mul(t *testing.T) {
+ var x, y, r int8
+ x = -128
+ y = -128
+ r = x * y
+ if r != 0 {
+ t.Errorf("-128 * -128 = %d, want 0", r)
+ }
+ y = -127
+ r = x * y
+ if r != -128 {
+ t.Errorf("-128 * -127 = %d, want -128", r)
+ }
+ y = -1
+ r = x * y
+ if r != -128 {
+ t.Errorf("-128 * -1 = %d, want -128", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("-128 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != -128 {
+ t.Errorf("-128 * 1 = %d, want -128", r)
+ }
+ y = 126
+ r = x * y
+ if r != 0 {
+ t.Errorf("-128 * 126 = %d, want 0", r)
+ }
+ y = 127
+ r = x * y
+ if r != -128 {
+ t.Errorf("-128 * 127 = %d, want -128", r)
+ }
+ x = -127
+ y = -128
+ r = x * y
+ if r != -128 {
+ t.Errorf("-127 * -128 = %d, want -128", r)
+ }
+ y = -127
+ r = x * y
+ if r != 1 {
+ t.Errorf("-127 * -127 = %d, want 1", r)
+ }
+ y = -1
+ r = x * y
+ if r != 127 {
+ t.Errorf("-127 * -1 = %d, want 127", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("-127 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != -127 {
+ t.Errorf("-127 * 1 = %d, want -127", r)
+ }
+ y = 126
+ r = x * y
+ if r != 126 {
+ t.Errorf("-127 * 126 = %d, want 126", r)
+ }
+ y = 127
+ r = x * y
+ if r != -1 {
+ t.Errorf("-127 * 127 = %d, want -1", r)
+ }
+ x = -1
+ y = -128
+ r = x * y
+ if r != -128 {
+ t.Errorf("-1 * -128 = %d, want -128", r)
+ }
+ y = -127
+ r = x * y
+ if r != 127 {
+ t.Errorf("-1 * -127 = %d, want 127", r)
+ }
+ y = -1
+ r = x * y
+ if r != 1 {
+ t.Errorf("-1 * -1 = %d, want 1", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("-1 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != -1 {
+ t.Errorf("-1 * 1 = %d, want -1", r)
+ }
+ y = 126
+ r = x * y
+ if r != -126 {
+ t.Errorf("-1 * 126 = %d, want -126", r)
+ }
+ y = 127
+ r = x * y
+ if r != -127 {
+ t.Errorf("-1 * 127 = %d, want -127", r)
+ }
+ x = 0
+ y = -128
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * -128 = %d, want 0", r)
+ }
+ y = -127
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * -127 = %d, want 0", r)
+ }
+ y = -1
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * -1 = %d, want 0", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * 1 = %d, want 0", r)
+ }
+ y = 126
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * 126 = %d, want 0", r)
+ }
+ y = 127
+ r = x * y
+ if r != 0 {
+ t.Errorf("0 * 127 = %d, want 0", r)
+ }
+ x = 1
+ y = -128
+ r = x * y
+ if r != -128 {
+ t.Errorf("1 * -128 = %d, want -128", r)
+ }
+ y = -127
+ r = x * y
+ if r != -127 {
+ t.Errorf("1 * -127 = %d, want -127", r)
+ }
+ y = -1
+ r = x * y
+ if r != -1 {
+ t.Errorf("1 * -1 = %d, want -1", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("1 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != 1 {
+ t.Errorf("1 * 1 = %d, want 1", r)
+ }
+ y = 126
+ r = x * y
+ if r != 126 {
+ t.Errorf("1 * 126 = %d, want 126", r)
+ }
+ y = 127
+ r = x * y
+ if r != 127 {
+ t.Errorf("1 * 127 = %d, want 127", r)
+ }
+ x = 126
+ y = -128
+ r = x * y
+ if r != 0 {
+ t.Errorf("126 * -128 = %d, want 0", r)
+ }
+ y = -127
+ r = x * y
+ if r != 126 {
+ t.Errorf("126 * -127 = %d, want 126", r)
+ }
+ y = -1
+ r = x * y
+ if r != -126 {
+ t.Errorf("126 * -1 = %d, want -126", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("126 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != 126 {
+ t.Errorf("126 * 1 = %d, want 126", r)
+ }
+ y = 126
+ r = x * y
+ if r != 4 {
+ t.Errorf("126 * 126 = %d, want 4", r)
+ }
+ y = 127
+ r = x * y
+ if r != -126 {
+ t.Errorf("126 * 127 = %d, want -126", r)
+ }
+ x = 127
+ y = -128
+ r = x * y
+ if r != -128 {
+ t.Errorf("127 * -128 = %d, want -128", r)
+ }
+ y = -127
+ r = x * y
+ if r != -1 {
+ t.Errorf("127 * -127 = %d, want -1", r)
+ }
+ y = -1
+ r = x * y
+ if r != -127 {
+ t.Errorf("127 * -1 = %d, want -127", r)
+ }
+ y = 0
+ r = x * y
+ if r != 0 {
+ t.Errorf("127 * 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x * y
+ if r != 127 {
+ t.Errorf("127 * 1 = %d, want 127", r)
+ }
+ y = 126
+ r = x * y
+ if r != -126 {
+ t.Errorf("127 * 126 = %d, want -126", r)
+ }
+ y = 127
+ r = x * y
+ if r != 1 {
+ t.Errorf("127 * 127 = %d, want 1", r)
+ }
+}
+func TestConstFoldint8mod(t *testing.T) {
+ var x, y, r int8
+ x = -128
+ y = -128
+ r = x % y
+ if r != 0 {
+ t.Errorf("-128 % -128 = %d, want 0", r)
+ }
+ y = -127
+ r = x % y
+ if r != -1 {
+ t.Errorf("-128 % -127 = %d, want -1", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-128 % -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-128 % 1 = %d, want 0", r)
+ }
+ y = 126
+ r = x % y
+ if r != -2 {
+ t.Errorf("-128 % 126 = %d, want -2", r)
+ }
+ y = 127
+ r = x % y
+ if r != -1 {
+ t.Errorf("-128 % 127 = %d, want -1", r)
+ }
+ x = -127
+ y = -128
+ r = x % y
+ if r != -127 {
+ t.Errorf("-127 % -128 = %d, want -127", r)
+ }
+ y = -127
+ r = x % y
+ if r != 0 {
+ t.Errorf("-127 % -127 = %d, want 0", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-127 % -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-127 % 1 = %d, want 0", r)
+ }
+ y = 126
+ r = x % y
+ if r != -1 {
+ t.Errorf("-127 % 126 = %d, want -1", r)
+ }
+ y = 127
+ r = x % y
+ if r != 0 {
+ t.Errorf("-127 % 127 = %d, want 0", r)
+ }
+ x = -1
+ y = -128
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 % -128 = %d, want -1", r)
+ }
+ y = -127
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 % -127 = %d, want -1", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-1 % -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("-1 % 1 = %d, want 0", r)
+ }
+ y = 126
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 % 126 = %d, want -1", r)
+ }
+ y = 127
+ r = x % y
+ if r != -1 {
+ t.Errorf("-1 % 127 = %d, want -1", r)
+ }
+ x = 0
+ y = -128
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % -128 = %d, want 0", r)
+ }
+ y = -127
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % -127 = %d, want 0", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % 1 = %d, want 0", r)
+ }
+ y = 126
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % 126 = %d, want 0", r)
+ }
+ y = 127
+ r = x % y
+ if r != 0 {
+ t.Errorf("0 % 127 = %d, want 0", r)
+ }
+ x = 1
+ y = -128
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 % -128 = %d, want 1", r)
+ }
+ y = -127
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 % -127 = %d, want 1", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("1 % -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("1 % 1 = %d, want 0", r)
+ }
+ y = 126
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 % 126 = %d, want 1", r)
+ }
+ y = 127
+ r = x % y
+ if r != 1 {
+ t.Errorf("1 % 127 = %d, want 1", r)
+ }
+ x = 126
+ y = -128
+ r = x % y
+ if r != 126 {
+ t.Errorf("126 % -128 = %d, want 126", r)
+ }
+ y = -127
+ r = x % y
+ if r != 126 {
+ t.Errorf("126 % -127 = %d, want 126", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("126 % -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("126 % 1 = %d, want 0", r)
+ }
+ y = 126
+ r = x % y
+ if r != 0 {
+ t.Errorf("126 % 126 = %d, want 0", r)
+ }
+ y = 127
+ r = x % y
+ if r != 126 {
+ t.Errorf("126 % 127 = %d, want 126", r)
+ }
+ x = 127
+ y = -128
+ r = x % y
+ if r != 127 {
+ t.Errorf("127 % -128 = %d, want 127", r)
+ }
+ y = -127
+ r = x % y
+ if r != 0 {
+ t.Errorf("127 % -127 = %d, want 0", r)
+ }
+ y = -1
+ r = x % y
+ if r != 0 {
+ t.Errorf("127 % -1 = %d, want 0", r)
+ }
+ y = 1
+ r = x % y
+ if r != 0 {
+ t.Errorf("127 % 1 = %d, want 0", r)
+ }
+ y = 126
+ r = x % y
+ if r != 1 {
+ t.Errorf("127 % 126 = %d, want 1", r)
+ }
+ y = 127
+ r = x % y
+ if r != 0 {
+ t.Errorf("127 % 127 = %d, want 0", r)
+ }
+}
+func TestConstFolduint64uint64lsh(t *testing.T) {
+ var x, r uint64
+ var y uint64
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x << y
+ if r != 4294967296 {
+ t.Errorf("4294967296 << 0 = %d, want 4294967296", r)
+ }
+ y = 1
+ r = x << y
+ if r != 8589934592 {
+ t.Errorf("4294967296 << 1 = %d, want 8589934592", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("4294967296 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("4294967296 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = 18446744073709551615
+ y = 0
+ r = x << y
+ if r != 18446744073709551615 {
+ t.Errorf("18446744073709551615 << 0 = %d, want 18446744073709551615", r)
+ }
+ y = 1
+ r = x << y
+ if r != 18446744073709551614 {
+ t.Errorf("18446744073709551615 << 1 = %d, want 18446744073709551614", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("18446744073709551615 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("18446744073709551615 << 18446744073709551615 = %d, want 0", r)
+ }
+}
+func TestConstFolduint64uint64rsh(t *testing.T) {
+ var x, r uint64
+ var y uint64
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 18446744073709551615 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 18446744073709551615 = %d, want 0", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x >> y
+ if r != 4294967296 {
+ t.Errorf("4294967296 >> 0 = %d, want 4294967296", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 2147483648 {
+ t.Errorf("4294967296 >> 1 = %d, want 2147483648", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("4294967296 >> 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("4294967296 >> 18446744073709551615 = %d, want 0", r)
+ }
+ x = 18446744073709551615
+ y = 0
+ r = x >> y
+ if r != 18446744073709551615 {
+ t.Errorf("18446744073709551615 >> 0 = %d, want 18446744073709551615", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 9223372036854775807 {
+ t.Errorf("18446744073709551615 >> 1 = %d, want 9223372036854775807", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("18446744073709551615 >> 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("18446744073709551615 >> 18446744073709551615 = %d, want 0", r)
+ }
+}
+func TestConstFolduint64uint32lsh(t *testing.T) {
+ var x, r uint64
+ var y uint32
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 4294967295 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 4294967295 = %d, want 0", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x << y
+ if r != 4294967296 {
+ t.Errorf("4294967296 << 0 = %d, want 4294967296", r)
+ }
+ y = 1
+ r = x << y
+ if r != 8589934592 {
+ t.Errorf("4294967296 << 1 = %d, want 8589934592", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("4294967296 << 4294967295 = %d, want 0", r)
+ }
+ x = 18446744073709551615
+ y = 0
+ r = x << y
+ if r != 18446744073709551615 {
+ t.Errorf("18446744073709551615 << 0 = %d, want 18446744073709551615", r)
+ }
+ y = 1
+ r = x << y
+ if r != 18446744073709551614 {
+ t.Errorf("18446744073709551615 << 1 = %d, want 18446744073709551614", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("18446744073709551615 << 4294967295 = %d, want 0", r)
+ }
+}
+func TestConstFolduint64uint32rsh(t *testing.T) {
+ var x, r uint64
+ var y uint32
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 4294967295 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 4294967295 = %d, want 0", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x >> y
+ if r != 4294967296 {
+ t.Errorf("4294967296 >> 0 = %d, want 4294967296", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 2147483648 {
+ t.Errorf("4294967296 >> 1 = %d, want 2147483648", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("4294967296 >> 4294967295 = %d, want 0", r)
+ }
+ x = 18446744073709551615
+ y = 0
+ r = x >> y
+ if r != 18446744073709551615 {
+ t.Errorf("18446744073709551615 >> 0 = %d, want 18446744073709551615", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 9223372036854775807 {
+ t.Errorf("18446744073709551615 >> 1 = %d, want 9223372036854775807", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("18446744073709551615 >> 4294967295 = %d, want 0", r)
+ }
+}
+func TestConstFolduint64uint16lsh(t *testing.T) {
+ var x, r uint64
+ var y uint16
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 65535 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 65535 = %d, want 0", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x << y
+ if r != 4294967296 {
+ t.Errorf("4294967296 << 0 = %d, want 4294967296", r)
+ }
+ y = 1
+ r = x << y
+ if r != 8589934592 {
+ t.Errorf("4294967296 << 1 = %d, want 8589934592", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("4294967296 << 65535 = %d, want 0", r)
+ }
+ x = 18446744073709551615
+ y = 0
+ r = x << y
+ if r != 18446744073709551615 {
+ t.Errorf("18446744073709551615 << 0 = %d, want 18446744073709551615", r)
+ }
+ y = 1
+ r = x << y
+ if r != 18446744073709551614 {
+ t.Errorf("18446744073709551615 << 1 = %d, want 18446744073709551614", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("18446744073709551615 << 65535 = %d, want 0", r)
+ }
+}
+func TestConstFolduint64uint16rsh(t *testing.T) {
+ var x, r uint64
+ var y uint16
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 65535 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 65535 = %d, want 0", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x >> y
+ if r != 4294967296 {
+ t.Errorf("4294967296 >> 0 = %d, want 4294967296", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 2147483648 {
+ t.Errorf("4294967296 >> 1 = %d, want 2147483648", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("4294967296 >> 65535 = %d, want 0", r)
+ }
+ x = 18446744073709551615
+ y = 0
+ r = x >> y
+ if r != 18446744073709551615 {
+ t.Errorf("18446744073709551615 >> 0 = %d, want 18446744073709551615", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 9223372036854775807 {
+ t.Errorf("18446744073709551615 >> 1 = %d, want 9223372036854775807", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("18446744073709551615 >> 65535 = %d, want 0", r)
+ }
+}
+func TestConstFolduint64uint8lsh(t *testing.T) {
+ var x, r uint64
+ var y uint8
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 255 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 255 = %d, want 0", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x << y
+ if r != 4294967296 {
+ t.Errorf("4294967296 << 0 = %d, want 4294967296", r)
+ }
+ y = 1
+ r = x << y
+ if r != 8589934592 {
+ t.Errorf("4294967296 << 1 = %d, want 8589934592", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("4294967296 << 255 = %d, want 0", r)
+ }
+ x = 18446744073709551615
+ y = 0
+ r = x << y
+ if r != 18446744073709551615 {
+ t.Errorf("18446744073709551615 << 0 = %d, want 18446744073709551615", r)
+ }
+ y = 1
+ r = x << y
+ if r != 18446744073709551614 {
+ t.Errorf("18446744073709551615 << 1 = %d, want 18446744073709551614", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("18446744073709551615 << 255 = %d, want 0", r)
+ }
+}
+func TestConstFolduint64uint8rsh(t *testing.T) {
+ var x, r uint64
+ var y uint8
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 255 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 255 = %d, want 0", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x >> y
+ if r != 4294967296 {
+ t.Errorf("4294967296 >> 0 = %d, want 4294967296", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 2147483648 {
+ t.Errorf("4294967296 >> 1 = %d, want 2147483648", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("4294967296 >> 255 = %d, want 0", r)
+ }
+ x = 18446744073709551615
+ y = 0
+ r = x >> y
+ if r != 18446744073709551615 {
+ t.Errorf("18446744073709551615 >> 0 = %d, want 18446744073709551615", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 9223372036854775807 {
+ t.Errorf("18446744073709551615 >> 1 = %d, want 9223372036854775807", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("18446744073709551615 >> 255 = %d, want 0", r)
+ }
+}
+func TestConstFoldint64uint64lsh(t *testing.T) {
+ var x, r int64
+ var y uint64
+ x = -9223372036854775808
+ y = 0
+ r = x << y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 << 0 = %d, want -9223372036854775808", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 << 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = -9223372036854775807
+ y = 0
+ r = x << y
+ if r != -9223372036854775807 {
+ t.Errorf("-9223372036854775807 << 0 = %d, want -9223372036854775807", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-9223372036854775807 << 1 = %d, want 2", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("-9223372036854775807 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("-9223372036854775807 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = -4294967296
+ y = 0
+ r = x << y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 << 0 = %d, want -4294967296", r)
+ }
+ y = 1
+ r = x << y
+ if r != -8589934592 {
+ t.Errorf("-4294967296 << 1 = %d, want -8589934592", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("-4294967296 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("-4294967296 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 << 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 << 1 = %d, want -2", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x << y
+ if r != 4294967296 {
+ t.Errorf("4294967296 << 0 = %d, want 4294967296", r)
+ }
+ y = 1
+ r = x << y
+ if r != 8589934592 {
+ t.Errorf("4294967296 << 1 = %d, want 8589934592", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("4294967296 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("4294967296 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = 9223372036854775806
+ y = 0
+ r = x << y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 << 0 = %d, want 9223372036854775806", r)
+ }
+ y = 1
+ r = x << y
+ if r != -4 {
+ t.Errorf("9223372036854775806 << 1 = %d, want -4", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("9223372036854775806 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("9223372036854775806 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = 9223372036854775807
+ y = 0
+ r = x << y
+ if r != 9223372036854775807 {
+ t.Errorf("9223372036854775807 << 0 = %d, want 9223372036854775807", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("9223372036854775807 << 1 = %d, want -2", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("9223372036854775807 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("9223372036854775807 << 18446744073709551615 = %d, want 0", r)
+ }
+}
+func TestConstFoldint64uint64rsh(t *testing.T) {
+ var x, r int64
+ var y uint64
+ x = -9223372036854775808
+ y = 0
+ r = x >> y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 >> 0 = %d, want -9223372036854775808", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -4611686018427387904 {
+ t.Errorf("-9223372036854775808 >> 1 = %d, want -4611686018427387904", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-9223372036854775808 >> 4294967296 = %d, want -1", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-9223372036854775808 >> 18446744073709551615 = %d, want -1", r)
+ }
+ x = -9223372036854775807
+ y = 0
+ r = x >> y
+ if r != -9223372036854775807 {
+ t.Errorf("-9223372036854775807 >> 0 = %d, want -9223372036854775807", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -4611686018427387904 {
+ t.Errorf("-9223372036854775807 >> 1 = %d, want -4611686018427387904", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-9223372036854775807 >> 4294967296 = %d, want -1", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-9223372036854775807 >> 18446744073709551615 = %d, want -1", r)
+ }
+ x = -4294967296
+ y = 0
+ r = x >> y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 >> 0 = %d, want -4294967296", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -2147483648 {
+ t.Errorf("-4294967296 >> 1 = %d, want -2147483648", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-4294967296 >> 4294967296 = %d, want -1", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-4294967296 >> 18446744073709551615 = %d, want -1", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 1 = %d, want -1", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 4294967296 = %d, want -1", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 18446744073709551615 = %d, want -1", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 18446744073709551615 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 18446744073709551615 = %d, want 0", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x >> y
+ if r != 4294967296 {
+ t.Errorf("4294967296 >> 0 = %d, want 4294967296", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 2147483648 {
+ t.Errorf("4294967296 >> 1 = %d, want 2147483648", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("4294967296 >> 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("4294967296 >> 18446744073709551615 = %d, want 0", r)
+ }
+ x = 9223372036854775806
+ y = 0
+ r = x >> y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 >> 0 = %d, want 9223372036854775806", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 4611686018427387903 {
+ t.Errorf("9223372036854775806 >> 1 = %d, want 4611686018427387903", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("9223372036854775806 >> 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("9223372036854775806 >> 18446744073709551615 = %d, want 0", r)
+ }
+ x = 9223372036854775807
+ y = 0
+ r = x >> y
+ if r != 9223372036854775807 {
+ t.Errorf("9223372036854775807 >> 0 = %d, want 9223372036854775807", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 4611686018427387903 {
+ t.Errorf("9223372036854775807 >> 1 = %d, want 4611686018427387903", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("9223372036854775807 >> 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("9223372036854775807 >> 18446744073709551615 = %d, want 0", r)
+ }
+}
+func TestConstFoldint64uint32lsh(t *testing.T) {
+ var x, r int64
+ var y uint32
+ x = -9223372036854775808
+ y = 0
+ r = x << y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 << 0 = %d, want -9223372036854775808", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 << 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 << 4294967295 = %d, want 0", r)
+ }
+ x = -9223372036854775807
+ y = 0
+ r = x << y
+ if r != -9223372036854775807 {
+ t.Errorf("-9223372036854775807 << 0 = %d, want -9223372036854775807", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-9223372036854775807 << 1 = %d, want 2", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("-9223372036854775807 << 4294967295 = %d, want 0", r)
+ }
+ x = -4294967296
+ y = 0
+ r = x << y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 << 0 = %d, want -4294967296", r)
+ }
+ y = 1
+ r = x << y
+ if r != -8589934592 {
+ t.Errorf("-4294967296 << 1 = %d, want -8589934592", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("-4294967296 << 4294967295 = %d, want 0", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 << 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 << 1 = %d, want -2", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 << 4294967295 = %d, want 0", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 4294967295 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 4294967295 = %d, want 0", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x << y
+ if r != 4294967296 {
+ t.Errorf("4294967296 << 0 = %d, want 4294967296", r)
+ }
+ y = 1
+ r = x << y
+ if r != 8589934592 {
+ t.Errorf("4294967296 << 1 = %d, want 8589934592", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("4294967296 << 4294967295 = %d, want 0", r)
+ }
+ x = 9223372036854775806
+ y = 0
+ r = x << y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 << 0 = %d, want 9223372036854775806", r)
+ }
+ y = 1
+ r = x << y
+ if r != -4 {
+ t.Errorf("9223372036854775806 << 1 = %d, want -4", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("9223372036854775806 << 4294967295 = %d, want 0", r)
+ }
+ x = 9223372036854775807
+ y = 0
+ r = x << y
+ if r != 9223372036854775807 {
+ t.Errorf("9223372036854775807 << 0 = %d, want 9223372036854775807", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("9223372036854775807 << 1 = %d, want -2", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("9223372036854775807 << 4294967295 = %d, want 0", r)
+ }
+}
+func TestConstFoldint64uint32rsh(t *testing.T) {
+ var x, r int64
+ var y uint32
+ x = -9223372036854775808
+ y = 0
+ r = x >> y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 >> 0 = %d, want -9223372036854775808", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -4611686018427387904 {
+ t.Errorf("-9223372036854775808 >> 1 = %d, want -4611686018427387904", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-9223372036854775808 >> 4294967295 = %d, want -1", r)
+ }
+ x = -9223372036854775807
+ y = 0
+ r = x >> y
+ if r != -9223372036854775807 {
+ t.Errorf("-9223372036854775807 >> 0 = %d, want -9223372036854775807", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -4611686018427387904 {
+ t.Errorf("-9223372036854775807 >> 1 = %d, want -4611686018427387904", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-9223372036854775807 >> 4294967295 = %d, want -1", r)
+ }
+ x = -4294967296
+ y = 0
+ r = x >> y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 >> 0 = %d, want -4294967296", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -2147483648 {
+ t.Errorf("-4294967296 >> 1 = %d, want -2147483648", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-4294967296 >> 4294967295 = %d, want -1", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 1 = %d, want -1", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 4294967295 = %d, want -1", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 4294967295 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 4294967295 = %d, want 0", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x >> y
+ if r != 4294967296 {
+ t.Errorf("4294967296 >> 0 = %d, want 4294967296", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 2147483648 {
+ t.Errorf("4294967296 >> 1 = %d, want 2147483648", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("4294967296 >> 4294967295 = %d, want 0", r)
+ }
+ x = 9223372036854775806
+ y = 0
+ r = x >> y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 >> 0 = %d, want 9223372036854775806", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 4611686018427387903 {
+ t.Errorf("9223372036854775806 >> 1 = %d, want 4611686018427387903", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("9223372036854775806 >> 4294967295 = %d, want 0", r)
+ }
+ x = 9223372036854775807
+ y = 0
+ r = x >> y
+ if r != 9223372036854775807 {
+ t.Errorf("9223372036854775807 >> 0 = %d, want 9223372036854775807", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 4611686018427387903 {
+ t.Errorf("9223372036854775807 >> 1 = %d, want 4611686018427387903", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("9223372036854775807 >> 4294967295 = %d, want 0", r)
+ }
+}
+func TestConstFoldint64uint16lsh(t *testing.T) {
+ var x, r int64
+ var y uint16
+ x = -9223372036854775808
+ y = 0
+ r = x << y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 << 0 = %d, want -9223372036854775808", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 << 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 << 65535 = %d, want 0", r)
+ }
+ x = -9223372036854775807
+ y = 0
+ r = x << y
+ if r != -9223372036854775807 {
+ t.Errorf("-9223372036854775807 << 0 = %d, want -9223372036854775807", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-9223372036854775807 << 1 = %d, want 2", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("-9223372036854775807 << 65535 = %d, want 0", r)
+ }
+ x = -4294967296
+ y = 0
+ r = x << y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 << 0 = %d, want -4294967296", r)
+ }
+ y = 1
+ r = x << y
+ if r != -8589934592 {
+ t.Errorf("-4294967296 << 1 = %d, want -8589934592", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("-4294967296 << 65535 = %d, want 0", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 << 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 << 1 = %d, want -2", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 << 65535 = %d, want 0", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 65535 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 65535 = %d, want 0", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x << y
+ if r != 4294967296 {
+ t.Errorf("4294967296 << 0 = %d, want 4294967296", r)
+ }
+ y = 1
+ r = x << y
+ if r != 8589934592 {
+ t.Errorf("4294967296 << 1 = %d, want 8589934592", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("4294967296 << 65535 = %d, want 0", r)
+ }
+ x = 9223372036854775806
+ y = 0
+ r = x << y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 << 0 = %d, want 9223372036854775806", r)
+ }
+ y = 1
+ r = x << y
+ if r != -4 {
+ t.Errorf("9223372036854775806 << 1 = %d, want -4", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("9223372036854775806 << 65535 = %d, want 0", r)
+ }
+ x = 9223372036854775807
+ y = 0
+ r = x << y
+ if r != 9223372036854775807 {
+ t.Errorf("9223372036854775807 << 0 = %d, want 9223372036854775807", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("9223372036854775807 << 1 = %d, want -2", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("9223372036854775807 << 65535 = %d, want 0", r)
+ }
+}
+func TestConstFoldint64uint16rsh(t *testing.T) {
+ var x, r int64
+ var y uint16
+ x = -9223372036854775808
+ y = 0
+ r = x >> y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 >> 0 = %d, want -9223372036854775808", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -4611686018427387904 {
+ t.Errorf("-9223372036854775808 >> 1 = %d, want -4611686018427387904", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-9223372036854775808 >> 65535 = %d, want -1", r)
+ }
+ x = -9223372036854775807
+ y = 0
+ r = x >> y
+ if r != -9223372036854775807 {
+ t.Errorf("-9223372036854775807 >> 0 = %d, want -9223372036854775807", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -4611686018427387904 {
+ t.Errorf("-9223372036854775807 >> 1 = %d, want -4611686018427387904", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-9223372036854775807 >> 65535 = %d, want -1", r)
+ }
+ x = -4294967296
+ y = 0
+ r = x >> y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 >> 0 = %d, want -4294967296", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -2147483648 {
+ t.Errorf("-4294967296 >> 1 = %d, want -2147483648", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-4294967296 >> 65535 = %d, want -1", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 1 = %d, want -1", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 65535 = %d, want -1", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 65535 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 65535 = %d, want 0", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x >> y
+ if r != 4294967296 {
+ t.Errorf("4294967296 >> 0 = %d, want 4294967296", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 2147483648 {
+ t.Errorf("4294967296 >> 1 = %d, want 2147483648", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("4294967296 >> 65535 = %d, want 0", r)
+ }
+ x = 9223372036854775806
+ y = 0
+ r = x >> y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 >> 0 = %d, want 9223372036854775806", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 4611686018427387903 {
+ t.Errorf("9223372036854775806 >> 1 = %d, want 4611686018427387903", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("9223372036854775806 >> 65535 = %d, want 0", r)
+ }
+ x = 9223372036854775807
+ y = 0
+ r = x >> y
+ if r != 9223372036854775807 {
+ t.Errorf("9223372036854775807 >> 0 = %d, want 9223372036854775807", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 4611686018427387903 {
+ t.Errorf("9223372036854775807 >> 1 = %d, want 4611686018427387903", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("9223372036854775807 >> 65535 = %d, want 0", r)
+ }
+}
+func TestConstFoldint64uint8lsh(t *testing.T) {
+ var x, r int64
+ var y uint8
+ x = -9223372036854775808
+ y = 0
+ r = x << y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 << 0 = %d, want -9223372036854775808", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 << 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("-9223372036854775808 << 255 = %d, want 0", r)
+ }
+ x = -9223372036854775807
+ y = 0
+ r = x << y
+ if r != -9223372036854775807 {
+ t.Errorf("-9223372036854775807 << 0 = %d, want -9223372036854775807", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-9223372036854775807 << 1 = %d, want 2", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("-9223372036854775807 << 255 = %d, want 0", r)
+ }
+ x = -4294967296
+ y = 0
+ r = x << y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 << 0 = %d, want -4294967296", r)
+ }
+ y = 1
+ r = x << y
+ if r != -8589934592 {
+ t.Errorf("-4294967296 << 1 = %d, want -8589934592", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("-4294967296 << 255 = %d, want 0", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 << 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 << 1 = %d, want -2", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 << 255 = %d, want 0", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 255 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 255 = %d, want 0", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x << y
+ if r != 4294967296 {
+ t.Errorf("4294967296 << 0 = %d, want 4294967296", r)
+ }
+ y = 1
+ r = x << y
+ if r != 8589934592 {
+ t.Errorf("4294967296 << 1 = %d, want 8589934592", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("4294967296 << 255 = %d, want 0", r)
+ }
+ x = 9223372036854775806
+ y = 0
+ r = x << y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 << 0 = %d, want 9223372036854775806", r)
+ }
+ y = 1
+ r = x << y
+ if r != -4 {
+ t.Errorf("9223372036854775806 << 1 = %d, want -4", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("9223372036854775806 << 255 = %d, want 0", r)
+ }
+ x = 9223372036854775807
+ y = 0
+ r = x << y
+ if r != 9223372036854775807 {
+ t.Errorf("9223372036854775807 << 0 = %d, want 9223372036854775807", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("9223372036854775807 << 1 = %d, want -2", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("9223372036854775807 << 255 = %d, want 0", r)
+ }
+}
+func TestConstFoldint64uint8rsh(t *testing.T) {
+ var x, r int64
+ var y uint8
+ x = -9223372036854775808
+ y = 0
+ r = x >> y
+ if r != -9223372036854775808 {
+ t.Errorf("-9223372036854775808 >> 0 = %d, want -9223372036854775808", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -4611686018427387904 {
+ t.Errorf("-9223372036854775808 >> 1 = %d, want -4611686018427387904", r)
+ }
+ y = 255
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-9223372036854775808 >> 255 = %d, want -1", r)
+ }
+ x = -9223372036854775807
+ y = 0
+ r = x >> y
+ if r != -9223372036854775807 {
+ t.Errorf("-9223372036854775807 >> 0 = %d, want -9223372036854775807", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -4611686018427387904 {
+ t.Errorf("-9223372036854775807 >> 1 = %d, want -4611686018427387904", r)
+ }
+ y = 255
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-9223372036854775807 >> 255 = %d, want -1", r)
+ }
+ x = -4294967296
+ y = 0
+ r = x >> y
+ if r != -4294967296 {
+ t.Errorf("-4294967296 >> 0 = %d, want -4294967296", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -2147483648 {
+ t.Errorf("-4294967296 >> 1 = %d, want -2147483648", r)
+ }
+ y = 255
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-4294967296 >> 255 = %d, want -1", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 1 = %d, want -1", r)
+ }
+ y = 255
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 255 = %d, want -1", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 255 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 255 = %d, want 0", r)
+ }
+ x = 4294967296
+ y = 0
+ r = x >> y
+ if r != 4294967296 {
+ t.Errorf("4294967296 >> 0 = %d, want 4294967296", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 2147483648 {
+ t.Errorf("4294967296 >> 1 = %d, want 2147483648", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("4294967296 >> 255 = %d, want 0", r)
+ }
+ x = 9223372036854775806
+ y = 0
+ r = x >> y
+ if r != 9223372036854775806 {
+ t.Errorf("9223372036854775806 >> 0 = %d, want 9223372036854775806", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 4611686018427387903 {
+ t.Errorf("9223372036854775806 >> 1 = %d, want 4611686018427387903", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("9223372036854775806 >> 255 = %d, want 0", r)
+ }
+ x = 9223372036854775807
+ y = 0
+ r = x >> y
+ if r != 9223372036854775807 {
+ t.Errorf("9223372036854775807 >> 0 = %d, want 9223372036854775807", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 4611686018427387903 {
+ t.Errorf("9223372036854775807 >> 1 = %d, want 4611686018427387903", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("9223372036854775807 >> 255 = %d, want 0", r)
+ }
+}
+func TestConstFolduint32uint64lsh(t *testing.T) {
+ var x, r uint32
+ var y uint64
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = 4294967295
+ y = 0
+ r = x << y
+ if r != 4294967295 {
+ t.Errorf("4294967295 << 0 = %d, want 4294967295", r)
+ }
+ y = 1
+ r = x << y
+ if r != 4294967294 {
+ t.Errorf("4294967295 << 1 = %d, want 4294967294", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("4294967295 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("4294967295 << 18446744073709551615 = %d, want 0", r)
+ }
+}
+func TestConstFolduint32uint64rsh(t *testing.T) {
+ var x, r uint32
+ var y uint64
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 18446744073709551615 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 18446744073709551615 = %d, want 0", r)
+ }
+ x = 4294967295
+ y = 0
+ r = x >> y
+ if r != 4294967295 {
+ t.Errorf("4294967295 >> 0 = %d, want 4294967295", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 2147483647 {
+ t.Errorf("4294967295 >> 1 = %d, want 2147483647", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("4294967295 >> 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("4294967295 >> 18446744073709551615 = %d, want 0", r)
+ }
+}
+func TestConstFolduint32uint32lsh(t *testing.T) {
+ var x, r uint32
+ var y uint32
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 4294967295 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 4294967295 = %d, want 0", r)
+ }
+ x = 4294967295
+ y = 0
+ r = x << y
+ if r != 4294967295 {
+ t.Errorf("4294967295 << 0 = %d, want 4294967295", r)
+ }
+ y = 1
+ r = x << y
+ if r != 4294967294 {
+ t.Errorf("4294967295 << 1 = %d, want 4294967294", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("4294967295 << 4294967295 = %d, want 0", r)
+ }
+}
+func TestConstFolduint32uint32rsh(t *testing.T) {
+ var x, r uint32
+ var y uint32
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 4294967295 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 4294967295 = %d, want 0", r)
+ }
+ x = 4294967295
+ y = 0
+ r = x >> y
+ if r != 4294967295 {
+ t.Errorf("4294967295 >> 0 = %d, want 4294967295", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 2147483647 {
+ t.Errorf("4294967295 >> 1 = %d, want 2147483647", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("4294967295 >> 4294967295 = %d, want 0", r)
+ }
+}
+func TestConstFolduint32uint16lsh(t *testing.T) {
+ var x, r uint32
+ var y uint16
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 65535 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 65535 = %d, want 0", r)
+ }
+ x = 4294967295
+ y = 0
+ r = x << y
+ if r != 4294967295 {
+ t.Errorf("4294967295 << 0 = %d, want 4294967295", r)
+ }
+ y = 1
+ r = x << y
+ if r != 4294967294 {
+ t.Errorf("4294967295 << 1 = %d, want 4294967294", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("4294967295 << 65535 = %d, want 0", r)
+ }
+}
+func TestConstFolduint32uint16rsh(t *testing.T) {
+ var x, r uint32
+ var y uint16
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 65535 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 65535 = %d, want 0", r)
+ }
+ x = 4294967295
+ y = 0
+ r = x >> y
+ if r != 4294967295 {
+ t.Errorf("4294967295 >> 0 = %d, want 4294967295", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 2147483647 {
+ t.Errorf("4294967295 >> 1 = %d, want 2147483647", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("4294967295 >> 65535 = %d, want 0", r)
+ }
+}
+func TestConstFolduint32uint8lsh(t *testing.T) {
+ var x, r uint32
+ var y uint8
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 255 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 255 = %d, want 0", r)
+ }
+ x = 4294967295
+ y = 0
+ r = x << y
+ if r != 4294967295 {
+ t.Errorf("4294967295 << 0 = %d, want 4294967295", r)
+ }
+ y = 1
+ r = x << y
+ if r != 4294967294 {
+ t.Errorf("4294967295 << 1 = %d, want 4294967294", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("4294967295 << 255 = %d, want 0", r)
+ }
+}
+func TestConstFolduint32uint8rsh(t *testing.T) {
+ var x, r uint32
+ var y uint8
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 255 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 255 = %d, want 0", r)
+ }
+ x = 4294967295
+ y = 0
+ r = x >> y
+ if r != 4294967295 {
+ t.Errorf("4294967295 >> 0 = %d, want 4294967295", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 2147483647 {
+ t.Errorf("4294967295 >> 1 = %d, want 2147483647", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("4294967295 >> 255 = %d, want 0", r)
+ }
+}
+func TestConstFoldint32uint64lsh(t *testing.T) {
+ var x, r int32
+ var y uint64
+ x = -2147483648
+ y = 0
+ r = x << y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 << 0 = %d, want -2147483648", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-2147483648 << 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("-2147483648 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("-2147483648 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = -2147483647
+ y = 0
+ r = x << y
+ if r != -2147483647 {
+ t.Errorf("-2147483647 << 0 = %d, want -2147483647", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-2147483647 << 1 = %d, want 2", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("-2147483647 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("-2147483647 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 << 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 << 1 = %d, want -2", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = 2147483647
+ y = 0
+ r = x << y
+ if r != 2147483647 {
+ t.Errorf("2147483647 << 0 = %d, want 2147483647", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("2147483647 << 1 = %d, want -2", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("2147483647 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("2147483647 << 18446744073709551615 = %d, want 0", r)
+ }
+}
+func TestConstFoldint32uint64rsh(t *testing.T) {
+ var x, r int32
+ var y uint64
+ x = -2147483648
+ y = 0
+ r = x >> y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 >> 0 = %d, want -2147483648", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1073741824 {
+ t.Errorf("-2147483648 >> 1 = %d, want -1073741824", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-2147483648 >> 4294967296 = %d, want -1", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-2147483648 >> 18446744073709551615 = %d, want -1", r)
+ }
+ x = -2147483647
+ y = 0
+ r = x >> y
+ if r != -2147483647 {
+ t.Errorf("-2147483647 >> 0 = %d, want -2147483647", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1073741824 {
+ t.Errorf("-2147483647 >> 1 = %d, want -1073741824", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-2147483647 >> 4294967296 = %d, want -1", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-2147483647 >> 18446744073709551615 = %d, want -1", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 1 = %d, want -1", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 4294967296 = %d, want -1", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 18446744073709551615 = %d, want -1", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 18446744073709551615 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 18446744073709551615 = %d, want 0", r)
+ }
+ x = 2147483647
+ y = 0
+ r = x >> y
+ if r != 2147483647 {
+ t.Errorf("2147483647 >> 0 = %d, want 2147483647", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 1073741823 {
+ t.Errorf("2147483647 >> 1 = %d, want 1073741823", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("2147483647 >> 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("2147483647 >> 18446744073709551615 = %d, want 0", r)
+ }
+}
+func TestConstFoldint32uint32lsh(t *testing.T) {
+ var x, r int32
+ var y uint32
+ x = -2147483648
+ y = 0
+ r = x << y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 << 0 = %d, want -2147483648", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-2147483648 << 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("-2147483648 << 4294967295 = %d, want 0", r)
+ }
+ x = -2147483647
+ y = 0
+ r = x << y
+ if r != -2147483647 {
+ t.Errorf("-2147483647 << 0 = %d, want -2147483647", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-2147483647 << 1 = %d, want 2", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("-2147483647 << 4294967295 = %d, want 0", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 << 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 << 1 = %d, want -2", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 << 4294967295 = %d, want 0", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 4294967295 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 4294967295 = %d, want 0", r)
+ }
+ x = 2147483647
+ y = 0
+ r = x << y
+ if r != 2147483647 {
+ t.Errorf("2147483647 << 0 = %d, want 2147483647", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("2147483647 << 1 = %d, want -2", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("2147483647 << 4294967295 = %d, want 0", r)
+ }
+}
+func TestConstFoldint32uint32rsh(t *testing.T) {
+ var x, r int32
+ var y uint32
+ x = -2147483648
+ y = 0
+ r = x >> y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 >> 0 = %d, want -2147483648", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1073741824 {
+ t.Errorf("-2147483648 >> 1 = %d, want -1073741824", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-2147483648 >> 4294967295 = %d, want -1", r)
+ }
+ x = -2147483647
+ y = 0
+ r = x >> y
+ if r != -2147483647 {
+ t.Errorf("-2147483647 >> 0 = %d, want -2147483647", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1073741824 {
+ t.Errorf("-2147483647 >> 1 = %d, want -1073741824", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-2147483647 >> 4294967295 = %d, want -1", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 1 = %d, want -1", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 4294967295 = %d, want -1", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 4294967295 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 4294967295 = %d, want 0", r)
+ }
+ x = 2147483647
+ y = 0
+ r = x >> y
+ if r != 2147483647 {
+ t.Errorf("2147483647 >> 0 = %d, want 2147483647", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 1073741823 {
+ t.Errorf("2147483647 >> 1 = %d, want 1073741823", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("2147483647 >> 4294967295 = %d, want 0", r)
+ }
+}
+func TestConstFoldint32uint16lsh(t *testing.T) {
+ var x, r int32
+ var y uint16
+ x = -2147483648
+ y = 0
+ r = x << y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 << 0 = %d, want -2147483648", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-2147483648 << 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("-2147483648 << 65535 = %d, want 0", r)
+ }
+ x = -2147483647
+ y = 0
+ r = x << y
+ if r != -2147483647 {
+ t.Errorf("-2147483647 << 0 = %d, want -2147483647", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-2147483647 << 1 = %d, want 2", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("-2147483647 << 65535 = %d, want 0", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 << 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 << 1 = %d, want -2", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 << 65535 = %d, want 0", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 65535 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 65535 = %d, want 0", r)
+ }
+ x = 2147483647
+ y = 0
+ r = x << y
+ if r != 2147483647 {
+ t.Errorf("2147483647 << 0 = %d, want 2147483647", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("2147483647 << 1 = %d, want -2", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("2147483647 << 65535 = %d, want 0", r)
+ }
+}
+func TestConstFoldint32uint16rsh(t *testing.T) {
+ var x, r int32
+ var y uint16
+ x = -2147483648
+ y = 0
+ r = x >> y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 >> 0 = %d, want -2147483648", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1073741824 {
+ t.Errorf("-2147483648 >> 1 = %d, want -1073741824", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-2147483648 >> 65535 = %d, want -1", r)
+ }
+ x = -2147483647
+ y = 0
+ r = x >> y
+ if r != -2147483647 {
+ t.Errorf("-2147483647 >> 0 = %d, want -2147483647", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1073741824 {
+ t.Errorf("-2147483647 >> 1 = %d, want -1073741824", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-2147483647 >> 65535 = %d, want -1", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 1 = %d, want -1", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 65535 = %d, want -1", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 65535 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 65535 = %d, want 0", r)
+ }
+ x = 2147483647
+ y = 0
+ r = x >> y
+ if r != 2147483647 {
+ t.Errorf("2147483647 >> 0 = %d, want 2147483647", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 1073741823 {
+ t.Errorf("2147483647 >> 1 = %d, want 1073741823", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("2147483647 >> 65535 = %d, want 0", r)
+ }
+}
+func TestConstFoldint32uint8lsh(t *testing.T) {
+ var x, r int32
+ var y uint8
+ x = -2147483648
+ y = 0
+ r = x << y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 << 0 = %d, want -2147483648", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-2147483648 << 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("-2147483648 << 255 = %d, want 0", r)
+ }
+ x = -2147483647
+ y = 0
+ r = x << y
+ if r != -2147483647 {
+ t.Errorf("-2147483647 << 0 = %d, want -2147483647", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-2147483647 << 1 = %d, want 2", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("-2147483647 << 255 = %d, want 0", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 << 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 << 1 = %d, want -2", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 << 255 = %d, want 0", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 255 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 255 = %d, want 0", r)
+ }
+ x = 2147483647
+ y = 0
+ r = x << y
+ if r != 2147483647 {
+ t.Errorf("2147483647 << 0 = %d, want 2147483647", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("2147483647 << 1 = %d, want -2", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("2147483647 << 255 = %d, want 0", r)
+ }
+}
+func TestConstFoldint32uint8rsh(t *testing.T) {
+ var x, r int32
+ var y uint8
+ x = -2147483648
+ y = 0
+ r = x >> y
+ if r != -2147483648 {
+ t.Errorf("-2147483648 >> 0 = %d, want -2147483648", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1073741824 {
+ t.Errorf("-2147483648 >> 1 = %d, want -1073741824", r)
+ }
+ y = 255
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-2147483648 >> 255 = %d, want -1", r)
+ }
+ x = -2147483647
+ y = 0
+ r = x >> y
+ if r != -2147483647 {
+ t.Errorf("-2147483647 >> 0 = %d, want -2147483647", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1073741824 {
+ t.Errorf("-2147483647 >> 1 = %d, want -1073741824", r)
+ }
+ y = 255
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-2147483647 >> 255 = %d, want -1", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 1 = %d, want -1", r)
+ }
+ y = 255
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 255 = %d, want -1", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 255 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 255 = %d, want 0", r)
+ }
+ x = 2147483647
+ y = 0
+ r = x >> y
+ if r != 2147483647 {
+ t.Errorf("2147483647 >> 0 = %d, want 2147483647", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 1073741823 {
+ t.Errorf("2147483647 >> 1 = %d, want 1073741823", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("2147483647 >> 255 = %d, want 0", r)
+ }
+}
+func TestConstFolduint16uint64lsh(t *testing.T) {
+ var x, r uint16
+ var y uint64
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = 65535
+ y = 0
+ r = x << y
+ if r != 65535 {
+ t.Errorf("65535 << 0 = %d, want 65535", r)
+ }
+ y = 1
+ r = x << y
+ if r != 65534 {
+ t.Errorf("65535 << 1 = %d, want 65534", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("65535 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("65535 << 18446744073709551615 = %d, want 0", r)
+ }
+}
+func TestConstFolduint16uint64rsh(t *testing.T) {
+ var x, r uint16
+ var y uint64
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 18446744073709551615 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 18446744073709551615 = %d, want 0", r)
+ }
+ x = 65535
+ y = 0
+ r = x >> y
+ if r != 65535 {
+ t.Errorf("65535 >> 0 = %d, want 65535", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 32767 {
+ t.Errorf("65535 >> 1 = %d, want 32767", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("65535 >> 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("65535 >> 18446744073709551615 = %d, want 0", r)
+ }
+}
+func TestConstFolduint16uint32lsh(t *testing.T) {
+ var x, r uint16
+ var y uint32
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 4294967295 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 4294967295 = %d, want 0", r)
+ }
+ x = 65535
+ y = 0
+ r = x << y
+ if r != 65535 {
+ t.Errorf("65535 << 0 = %d, want 65535", r)
+ }
+ y = 1
+ r = x << y
+ if r != 65534 {
+ t.Errorf("65535 << 1 = %d, want 65534", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("65535 << 4294967295 = %d, want 0", r)
+ }
+}
+func TestConstFolduint16uint32rsh(t *testing.T) {
+ var x, r uint16
+ var y uint32
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 4294967295 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 4294967295 = %d, want 0", r)
+ }
+ x = 65535
+ y = 0
+ r = x >> y
+ if r != 65535 {
+ t.Errorf("65535 >> 0 = %d, want 65535", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 32767 {
+ t.Errorf("65535 >> 1 = %d, want 32767", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("65535 >> 4294967295 = %d, want 0", r)
+ }
+}
+func TestConstFolduint16uint16lsh(t *testing.T) {
+ var x, r uint16
+ var y uint16
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 65535 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 65535 = %d, want 0", r)
+ }
+ x = 65535
+ y = 0
+ r = x << y
+ if r != 65535 {
+ t.Errorf("65535 << 0 = %d, want 65535", r)
+ }
+ y = 1
+ r = x << y
+ if r != 65534 {
+ t.Errorf("65535 << 1 = %d, want 65534", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("65535 << 65535 = %d, want 0", r)
+ }
+}
+func TestConstFolduint16uint16rsh(t *testing.T) {
+ var x, r uint16
+ var y uint16
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 65535 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 65535 = %d, want 0", r)
+ }
+ x = 65535
+ y = 0
+ r = x >> y
+ if r != 65535 {
+ t.Errorf("65535 >> 0 = %d, want 65535", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 32767 {
+ t.Errorf("65535 >> 1 = %d, want 32767", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("65535 >> 65535 = %d, want 0", r)
+ }
+}
+func TestConstFolduint16uint8lsh(t *testing.T) {
+ var x, r uint16
+ var y uint8
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 255 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 255 = %d, want 0", r)
+ }
+ x = 65535
+ y = 0
+ r = x << y
+ if r != 65535 {
+ t.Errorf("65535 << 0 = %d, want 65535", r)
+ }
+ y = 1
+ r = x << y
+ if r != 65534 {
+ t.Errorf("65535 << 1 = %d, want 65534", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("65535 << 255 = %d, want 0", r)
+ }
+}
+func TestConstFolduint16uint8rsh(t *testing.T) {
+ var x, r uint16
+ var y uint8
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 255 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 255 = %d, want 0", r)
+ }
+ x = 65535
+ y = 0
+ r = x >> y
+ if r != 65535 {
+ t.Errorf("65535 >> 0 = %d, want 65535", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 32767 {
+ t.Errorf("65535 >> 1 = %d, want 32767", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("65535 >> 255 = %d, want 0", r)
+ }
+}
+func TestConstFoldint16uint64lsh(t *testing.T) {
+ var x, r int16
+ var y uint64
+ x = -32768
+ y = 0
+ r = x << y
+ if r != -32768 {
+ t.Errorf("-32768 << 0 = %d, want -32768", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-32768 << 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("-32768 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("-32768 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = -32767
+ y = 0
+ r = x << y
+ if r != -32767 {
+ t.Errorf("-32767 << 0 = %d, want -32767", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-32767 << 1 = %d, want 2", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("-32767 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("-32767 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 << 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 << 1 = %d, want -2", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = 32766
+ y = 0
+ r = x << y
+ if r != 32766 {
+ t.Errorf("32766 << 0 = %d, want 32766", r)
+ }
+ y = 1
+ r = x << y
+ if r != -4 {
+ t.Errorf("32766 << 1 = %d, want -4", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("32766 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("32766 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = 32767
+ y = 0
+ r = x << y
+ if r != 32767 {
+ t.Errorf("32767 << 0 = %d, want 32767", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("32767 << 1 = %d, want -2", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("32767 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("32767 << 18446744073709551615 = %d, want 0", r)
+ }
+}
+func TestConstFoldint16uint64rsh(t *testing.T) {
+ var x, r int16
+ var y uint64
+ x = -32768
+ y = 0
+ r = x >> y
+ if r != -32768 {
+ t.Errorf("-32768 >> 0 = %d, want -32768", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -16384 {
+ t.Errorf("-32768 >> 1 = %d, want -16384", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-32768 >> 4294967296 = %d, want -1", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-32768 >> 18446744073709551615 = %d, want -1", r)
+ }
+ x = -32767
+ y = 0
+ r = x >> y
+ if r != -32767 {
+ t.Errorf("-32767 >> 0 = %d, want -32767", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -16384 {
+ t.Errorf("-32767 >> 1 = %d, want -16384", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-32767 >> 4294967296 = %d, want -1", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-32767 >> 18446744073709551615 = %d, want -1", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 1 = %d, want -1", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 4294967296 = %d, want -1", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 18446744073709551615 = %d, want -1", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 18446744073709551615 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 18446744073709551615 = %d, want 0", r)
+ }
+ x = 32766
+ y = 0
+ r = x >> y
+ if r != 32766 {
+ t.Errorf("32766 >> 0 = %d, want 32766", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 16383 {
+ t.Errorf("32766 >> 1 = %d, want 16383", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("32766 >> 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("32766 >> 18446744073709551615 = %d, want 0", r)
+ }
+ x = 32767
+ y = 0
+ r = x >> y
+ if r != 32767 {
+ t.Errorf("32767 >> 0 = %d, want 32767", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 16383 {
+ t.Errorf("32767 >> 1 = %d, want 16383", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("32767 >> 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("32767 >> 18446744073709551615 = %d, want 0", r)
+ }
+}
+func TestConstFoldint16uint32lsh(t *testing.T) {
+ var x, r int16
+ var y uint32
+ x = -32768
+ y = 0
+ r = x << y
+ if r != -32768 {
+ t.Errorf("-32768 << 0 = %d, want -32768", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-32768 << 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("-32768 << 4294967295 = %d, want 0", r)
+ }
+ x = -32767
+ y = 0
+ r = x << y
+ if r != -32767 {
+ t.Errorf("-32767 << 0 = %d, want -32767", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-32767 << 1 = %d, want 2", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("-32767 << 4294967295 = %d, want 0", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 << 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 << 1 = %d, want -2", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 << 4294967295 = %d, want 0", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 4294967295 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 4294967295 = %d, want 0", r)
+ }
+ x = 32766
+ y = 0
+ r = x << y
+ if r != 32766 {
+ t.Errorf("32766 << 0 = %d, want 32766", r)
+ }
+ y = 1
+ r = x << y
+ if r != -4 {
+ t.Errorf("32766 << 1 = %d, want -4", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("32766 << 4294967295 = %d, want 0", r)
+ }
+ x = 32767
+ y = 0
+ r = x << y
+ if r != 32767 {
+ t.Errorf("32767 << 0 = %d, want 32767", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("32767 << 1 = %d, want -2", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("32767 << 4294967295 = %d, want 0", r)
+ }
+}
+func TestConstFoldint16uint32rsh(t *testing.T) {
+ var x, r int16
+ var y uint32
+ x = -32768
+ y = 0
+ r = x >> y
+ if r != -32768 {
+ t.Errorf("-32768 >> 0 = %d, want -32768", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -16384 {
+ t.Errorf("-32768 >> 1 = %d, want -16384", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-32768 >> 4294967295 = %d, want -1", r)
+ }
+ x = -32767
+ y = 0
+ r = x >> y
+ if r != -32767 {
+ t.Errorf("-32767 >> 0 = %d, want -32767", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -16384 {
+ t.Errorf("-32767 >> 1 = %d, want -16384", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-32767 >> 4294967295 = %d, want -1", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 1 = %d, want -1", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 4294967295 = %d, want -1", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 4294967295 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 4294967295 = %d, want 0", r)
+ }
+ x = 32766
+ y = 0
+ r = x >> y
+ if r != 32766 {
+ t.Errorf("32766 >> 0 = %d, want 32766", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 16383 {
+ t.Errorf("32766 >> 1 = %d, want 16383", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("32766 >> 4294967295 = %d, want 0", r)
+ }
+ x = 32767
+ y = 0
+ r = x >> y
+ if r != 32767 {
+ t.Errorf("32767 >> 0 = %d, want 32767", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 16383 {
+ t.Errorf("32767 >> 1 = %d, want 16383", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("32767 >> 4294967295 = %d, want 0", r)
+ }
+}
+func TestConstFoldint16uint16lsh(t *testing.T) {
+ var x, r int16
+ var y uint16
+ x = -32768
+ y = 0
+ r = x << y
+ if r != -32768 {
+ t.Errorf("-32768 << 0 = %d, want -32768", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-32768 << 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("-32768 << 65535 = %d, want 0", r)
+ }
+ x = -32767
+ y = 0
+ r = x << y
+ if r != -32767 {
+ t.Errorf("-32767 << 0 = %d, want -32767", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-32767 << 1 = %d, want 2", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("-32767 << 65535 = %d, want 0", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 << 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 << 1 = %d, want -2", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 << 65535 = %d, want 0", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 65535 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 65535 = %d, want 0", r)
+ }
+ x = 32766
+ y = 0
+ r = x << y
+ if r != 32766 {
+ t.Errorf("32766 << 0 = %d, want 32766", r)
+ }
+ y = 1
+ r = x << y
+ if r != -4 {
+ t.Errorf("32766 << 1 = %d, want -4", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("32766 << 65535 = %d, want 0", r)
+ }
+ x = 32767
+ y = 0
+ r = x << y
+ if r != 32767 {
+ t.Errorf("32767 << 0 = %d, want 32767", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("32767 << 1 = %d, want -2", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("32767 << 65535 = %d, want 0", r)
+ }
+}
+func TestConstFoldint16uint16rsh(t *testing.T) {
+ var x, r int16
+ var y uint16
+ x = -32768
+ y = 0
+ r = x >> y
+ if r != -32768 {
+ t.Errorf("-32768 >> 0 = %d, want -32768", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -16384 {
+ t.Errorf("-32768 >> 1 = %d, want -16384", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-32768 >> 65535 = %d, want -1", r)
+ }
+ x = -32767
+ y = 0
+ r = x >> y
+ if r != -32767 {
+ t.Errorf("-32767 >> 0 = %d, want -32767", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -16384 {
+ t.Errorf("-32767 >> 1 = %d, want -16384", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-32767 >> 65535 = %d, want -1", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 1 = %d, want -1", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 65535 = %d, want -1", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 65535 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 65535 = %d, want 0", r)
+ }
+ x = 32766
+ y = 0
+ r = x >> y
+ if r != 32766 {
+ t.Errorf("32766 >> 0 = %d, want 32766", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 16383 {
+ t.Errorf("32766 >> 1 = %d, want 16383", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("32766 >> 65535 = %d, want 0", r)
+ }
+ x = 32767
+ y = 0
+ r = x >> y
+ if r != 32767 {
+ t.Errorf("32767 >> 0 = %d, want 32767", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 16383 {
+ t.Errorf("32767 >> 1 = %d, want 16383", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("32767 >> 65535 = %d, want 0", r)
+ }
+}
+func TestConstFoldint16uint8lsh(t *testing.T) {
+ var x, r int16
+ var y uint8
+ x = -32768
+ y = 0
+ r = x << y
+ if r != -32768 {
+ t.Errorf("-32768 << 0 = %d, want -32768", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-32768 << 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("-32768 << 255 = %d, want 0", r)
+ }
+ x = -32767
+ y = 0
+ r = x << y
+ if r != -32767 {
+ t.Errorf("-32767 << 0 = %d, want -32767", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-32767 << 1 = %d, want 2", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("-32767 << 255 = %d, want 0", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 << 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 << 1 = %d, want -2", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 << 255 = %d, want 0", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 255 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 255 = %d, want 0", r)
+ }
+ x = 32766
+ y = 0
+ r = x << y
+ if r != 32766 {
+ t.Errorf("32766 << 0 = %d, want 32766", r)
+ }
+ y = 1
+ r = x << y
+ if r != -4 {
+ t.Errorf("32766 << 1 = %d, want -4", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("32766 << 255 = %d, want 0", r)
+ }
+ x = 32767
+ y = 0
+ r = x << y
+ if r != 32767 {
+ t.Errorf("32767 << 0 = %d, want 32767", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("32767 << 1 = %d, want -2", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("32767 << 255 = %d, want 0", r)
+ }
+}
+func TestConstFoldint16uint8rsh(t *testing.T) {
+ var x, r int16
+ var y uint8
+ x = -32768
+ y = 0
+ r = x >> y
+ if r != -32768 {
+ t.Errorf("-32768 >> 0 = %d, want -32768", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -16384 {
+ t.Errorf("-32768 >> 1 = %d, want -16384", r)
+ }
+ y = 255
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-32768 >> 255 = %d, want -1", r)
+ }
+ x = -32767
+ y = 0
+ r = x >> y
+ if r != -32767 {
+ t.Errorf("-32767 >> 0 = %d, want -32767", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -16384 {
+ t.Errorf("-32767 >> 1 = %d, want -16384", r)
+ }
+ y = 255
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-32767 >> 255 = %d, want -1", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 1 = %d, want -1", r)
+ }
+ y = 255
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 255 = %d, want -1", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 255 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 255 = %d, want 0", r)
+ }
+ x = 32766
+ y = 0
+ r = x >> y
+ if r != 32766 {
+ t.Errorf("32766 >> 0 = %d, want 32766", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 16383 {
+ t.Errorf("32766 >> 1 = %d, want 16383", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("32766 >> 255 = %d, want 0", r)
+ }
+ x = 32767
+ y = 0
+ r = x >> y
+ if r != 32767 {
+ t.Errorf("32767 >> 0 = %d, want 32767", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 16383 {
+ t.Errorf("32767 >> 1 = %d, want 16383", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("32767 >> 255 = %d, want 0", r)
+ }
+}
+func TestConstFolduint8uint64lsh(t *testing.T) {
+ var x, r uint8
+ var y uint64
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = 255
+ y = 0
+ r = x << y
+ if r != 255 {
+ t.Errorf("255 << 0 = %d, want 255", r)
+ }
+ y = 1
+ r = x << y
+ if r != 254 {
+ t.Errorf("255 << 1 = %d, want 254", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("255 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("255 << 18446744073709551615 = %d, want 0", r)
+ }
+}
+func TestConstFolduint8uint64rsh(t *testing.T) {
+ var x, r uint8
+ var y uint64
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 18446744073709551615 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 18446744073709551615 = %d, want 0", r)
+ }
+ x = 255
+ y = 0
+ r = x >> y
+ if r != 255 {
+ t.Errorf("255 >> 0 = %d, want 255", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 127 {
+ t.Errorf("255 >> 1 = %d, want 127", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("255 >> 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("255 >> 18446744073709551615 = %d, want 0", r)
+ }
+}
+func TestConstFolduint8uint32lsh(t *testing.T) {
+ var x, r uint8
+ var y uint32
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 4294967295 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 4294967295 = %d, want 0", r)
+ }
+ x = 255
+ y = 0
+ r = x << y
+ if r != 255 {
+ t.Errorf("255 << 0 = %d, want 255", r)
+ }
+ y = 1
+ r = x << y
+ if r != 254 {
+ t.Errorf("255 << 1 = %d, want 254", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("255 << 4294967295 = %d, want 0", r)
+ }
+}
+func TestConstFolduint8uint32rsh(t *testing.T) {
+ var x, r uint8
+ var y uint32
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 4294967295 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 4294967295 = %d, want 0", r)
+ }
+ x = 255
+ y = 0
+ r = x >> y
+ if r != 255 {
+ t.Errorf("255 >> 0 = %d, want 255", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 127 {
+ t.Errorf("255 >> 1 = %d, want 127", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("255 >> 4294967295 = %d, want 0", r)
+ }
+}
+func TestConstFolduint8uint16lsh(t *testing.T) {
+ var x, r uint8
+ var y uint16
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 65535 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 65535 = %d, want 0", r)
+ }
+ x = 255
+ y = 0
+ r = x << y
+ if r != 255 {
+ t.Errorf("255 << 0 = %d, want 255", r)
+ }
+ y = 1
+ r = x << y
+ if r != 254 {
+ t.Errorf("255 << 1 = %d, want 254", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("255 << 65535 = %d, want 0", r)
+ }
+}
+func TestConstFolduint8uint16rsh(t *testing.T) {
+ var x, r uint8
+ var y uint16
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 65535 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 65535 = %d, want 0", r)
+ }
+ x = 255
+ y = 0
+ r = x >> y
+ if r != 255 {
+ t.Errorf("255 >> 0 = %d, want 255", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 127 {
+ t.Errorf("255 >> 1 = %d, want 127", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("255 >> 65535 = %d, want 0", r)
+ }
+}
+func TestConstFolduint8uint8lsh(t *testing.T) {
+ var x, r uint8
+ var y uint8
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 255 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 255 = %d, want 0", r)
+ }
+ x = 255
+ y = 0
+ r = x << y
+ if r != 255 {
+ t.Errorf("255 << 0 = %d, want 255", r)
+ }
+ y = 1
+ r = x << y
+ if r != 254 {
+ t.Errorf("255 << 1 = %d, want 254", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("255 << 255 = %d, want 0", r)
+ }
+}
+func TestConstFolduint8uint8rsh(t *testing.T) {
+ var x, r uint8
+ var y uint8
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 255 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 255 = %d, want 0", r)
+ }
+ x = 255
+ y = 0
+ r = x >> y
+ if r != 255 {
+ t.Errorf("255 >> 0 = %d, want 255", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 127 {
+ t.Errorf("255 >> 1 = %d, want 127", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("255 >> 255 = %d, want 0", r)
+ }
+}
+func TestConstFoldint8uint64lsh(t *testing.T) {
+ var x, r int8
+ var y uint64
+ x = -128
+ y = 0
+ r = x << y
+ if r != -128 {
+ t.Errorf("-128 << 0 = %d, want -128", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-128 << 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("-128 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("-128 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = -127
+ y = 0
+ r = x << y
+ if r != -127 {
+ t.Errorf("-127 << 0 = %d, want -127", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-127 << 1 = %d, want 2", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("-127 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("-127 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 << 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 << 1 = %d, want -2", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = 126
+ y = 0
+ r = x << y
+ if r != 126 {
+ t.Errorf("126 << 0 = %d, want 126", r)
+ }
+ y = 1
+ r = x << y
+ if r != -4 {
+ t.Errorf("126 << 1 = %d, want -4", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("126 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("126 << 18446744073709551615 = %d, want 0", r)
+ }
+ x = 127
+ y = 0
+ r = x << y
+ if r != 127 {
+ t.Errorf("127 << 0 = %d, want 127", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("127 << 1 = %d, want -2", r)
+ }
+ y = 4294967296
+ r = x << y
+ if r != 0 {
+ t.Errorf("127 << 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x << y
+ if r != 0 {
+ t.Errorf("127 << 18446744073709551615 = %d, want 0", r)
+ }
+}
+func TestConstFoldint8uint64rsh(t *testing.T) {
+ var x, r int8
+ var y uint64
+ x = -128
+ y = 0
+ r = x >> y
+ if r != -128 {
+ t.Errorf("-128 >> 0 = %d, want -128", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -64 {
+ t.Errorf("-128 >> 1 = %d, want -64", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-128 >> 4294967296 = %d, want -1", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-128 >> 18446744073709551615 = %d, want -1", r)
+ }
+ x = -127
+ y = 0
+ r = x >> y
+ if r != -127 {
+ t.Errorf("-127 >> 0 = %d, want -127", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -64 {
+ t.Errorf("-127 >> 1 = %d, want -64", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-127 >> 4294967296 = %d, want -1", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-127 >> 18446744073709551615 = %d, want -1", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 1 = %d, want -1", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 4294967296 = %d, want -1", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 18446744073709551615 = %d, want -1", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 18446744073709551615 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 18446744073709551615 = %d, want 0", r)
+ }
+ x = 126
+ y = 0
+ r = x >> y
+ if r != 126 {
+ t.Errorf("126 >> 0 = %d, want 126", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 63 {
+ t.Errorf("126 >> 1 = %d, want 63", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("126 >> 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("126 >> 18446744073709551615 = %d, want 0", r)
+ }
+ x = 127
+ y = 0
+ r = x >> y
+ if r != 127 {
+ t.Errorf("127 >> 0 = %d, want 127", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 63 {
+ t.Errorf("127 >> 1 = %d, want 63", r)
+ }
+ y = 4294967296
+ r = x >> y
+ if r != 0 {
+ t.Errorf("127 >> 4294967296 = %d, want 0", r)
+ }
+ y = 18446744073709551615
+ r = x >> y
+ if r != 0 {
+ t.Errorf("127 >> 18446744073709551615 = %d, want 0", r)
+ }
+}
+func TestConstFoldint8uint32lsh(t *testing.T) {
+ var x, r int8
+ var y uint32
+ x = -128
+ y = 0
+ r = x << y
+ if r != -128 {
+ t.Errorf("-128 << 0 = %d, want -128", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-128 << 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("-128 << 4294967295 = %d, want 0", r)
+ }
+ x = -127
+ y = 0
+ r = x << y
+ if r != -127 {
+ t.Errorf("-127 << 0 = %d, want -127", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-127 << 1 = %d, want 2", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("-127 << 4294967295 = %d, want 0", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 << 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 << 1 = %d, want -2", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 << 4294967295 = %d, want 0", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 4294967295 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 4294967295 = %d, want 0", r)
+ }
+ x = 126
+ y = 0
+ r = x << y
+ if r != 126 {
+ t.Errorf("126 << 0 = %d, want 126", r)
+ }
+ y = 1
+ r = x << y
+ if r != -4 {
+ t.Errorf("126 << 1 = %d, want -4", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("126 << 4294967295 = %d, want 0", r)
+ }
+ x = 127
+ y = 0
+ r = x << y
+ if r != 127 {
+ t.Errorf("127 << 0 = %d, want 127", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("127 << 1 = %d, want -2", r)
+ }
+ y = 4294967295
+ r = x << y
+ if r != 0 {
+ t.Errorf("127 << 4294967295 = %d, want 0", r)
+ }
+}
+func TestConstFoldint8uint32rsh(t *testing.T) {
+ var x, r int8
+ var y uint32
+ x = -128
+ y = 0
+ r = x >> y
+ if r != -128 {
+ t.Errorf("-128 >> 0 = %d, want -128", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -64 {
+ t.Errorf("-128 >> 1 = %d, want -64", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-128 >> 4294967295 = %d, want -1", r)
+ }
+ x = -127
+ y = 0
+ r = x >> y
+ if r != -127 {
+ t.Errorf("-127 >> 0 = %d, want -127", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -64 {
+ t.Errorf("-127 >> 1 = %d, want -64", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-127 >> 4294967295 = %d, want -1", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 1 = %d, want -1", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 4294967295 = %d, want -1", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 4294967295 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 4294967295 = %d, want 0", r)
+ }
+ x = 126
+ y = 0
+ r = x >> y
+ if r != 126 {
+ t.Errorf("126 >> 0 = %d, want 126", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 63 {
+ t.Errorf("126 >> 1 = %d, want 63", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("126 >> 4294967295 = %d, want 0", r)
+ }
+ x = 127
+ y = 0
+ r = x >> y
+ if r != 127 {
+ t.Errorf("127 >> 0 = %d, want 127", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 63 {
+ t.Errorf("127 >> 1 = %d, want 63", r)
+ }
+ y = 4294967295
+ r = x >> y
+ if r != 0 {
+ t.Errorf("127 >> 4294967295 = %d, want 0", r)
+ }
+}
+func TestConstFoldint8uint16lsh(t *testing.T) {
+ var x, r int8
+ var y uint16
+ x = -128
+ y = 0
+ r = x << y
+ if r != -128 {
+ t.Errorf("-128 << 0 = %d, want -128", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-128 << 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("-128 << 65535 = %d, want 0", r)
+ }
+ x = -127
+ y = 0
+ r = x << y
+ if r != -127 {
+ t.Errorf("-127 << 0 = %d, want -127", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-127 << 1 = %d, want 2", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("-127 << 65535 = %d, want 0", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 << 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 << 1 = %d, want -2", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 << 65535 = %d, want 0", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 65535 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 65535 = %d, want 0", r)
+ }
+ x = 126
+ y = 0
+ r = x << y
+ if r != 126 {
+ t.Errorf("126 << 0 = %d, want 126", r)
+ }
+ y = 1
+ r = x << y
+ if r != -4 {
+ t.Errorf("126 << 1 = %d, want -4", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("126 << 65535 = %d, want 0", r)
+ }
+ x = 127
+ y = 0
+ r = x << y
+ if r != 127 {
+ t.Errorf("127 << 0 = %d, want 127", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("127 << 1 = %d, want -2", r)
+ }
+ y = 65535
+ r = x << y
+ if r != 0 {
+ t.Errorf("127 << 65535 = %d, want 0", r)
+ }
+}
+func TestConstFoldint8uint16rsh(t *testing.T) {
+ var x, r int8
+ var y uint16
+ x = -128
+ y = 0
+ r = x >> y
+ if r != -128 {
+ t.Errorf("-128 >> 0 = %d, want -128", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -64 {
+ t.Errorf("-128 >> 1 = %d, want -64", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-128 >> 65535 = %d, want -1", r)
+ }
+ x = -127
+ y = 0
+ r = x >> y
+ if r != -127 {
+ t.Errorf("-127 >> 0 = %d, want -127", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -64 {
+ t.Errorf("-127 >> 1 = %d, want -64", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-127 >> 65535 = %d, want -1", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 1 = %d, want -1", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 65535 = %d, want -1", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 65535 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 65535 = %d, want 0", r)
+ }
+ x = 126
+ y = 0
+ r = x >> y
+ if r != 126 {
+ t.Errorf("126 >> 0 = %d, want 126", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 63 {
+ t.Errorf("126 >> 1 = %d, want 63", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("126 >> 65535 = %d, want 0", r)
+ }
+ x = 127
+ y = 0
+ r = x >> y
+ if r != 127 {
+ t.Errorf("127 >> 0 = %d, want 127", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 63 {
+ t.Errorf("127 >> 1 = %d, want 63", r)
+ }
+ y = 65535
+ r = x >> y
+ if r != 0 {
+ t.Errorf("127 >> 65535 = %d, want 0", r)
+ }
+}
+func TestConstFoldint8uint8lsh(t *testing.T) {
+ var x, r int8
+ var y uint8
+ x = -128
+ y = 0
+ r = x << y
+ if r != -128 {
+ t.Errorf("-128 << 0 = %d, want -128", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("-128 << 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("-128 << 255 = %d, want 0", r)
+ }
+ x = -127
+ y = 0
+ r = x << y
+ if r != -127 {
+ t.Errorf("-127 << 0 = %d, want -127", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("-127 << 1 = %d, want 2", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("-127 << 255 = %d, want 0", r)
+ }
+ x = -1
+ y = 0
+ r = x << y
+ if r != -1 {
+ t.Errorf("-1 << 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("-1 << 1 = %d, want -2", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("-1 << 255 = %d, want 0", r)
+ }
+ x = 0
+ y = 0
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("0 << 255 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x << y
+ if r != 1 {
+ t.Errorf("1 << 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x << y
+ if r != 2 {
+ t.Errorf("1 << 1 = %d, want 2", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("1 << 255 = %d, want 0", r)
+ }
+ x = 126
+ y = 0
+ r = x << y
+ if r != 126 {
+ t.Errorf("126 << 0 = %d, want 126", r)
+ }
+ y = 1
+ r = x << y
+ if r != -4 {
+ t.Errorf("126 << 1 = %d, want -4", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("126 << 255 = %d, want 0", r)
+ }
+ x = 127
+ y = 0
+ r = x << y
+ if r != 127 {
+ t.Errorf("127 << 0 = %d, want 127", r)
+ }
+ y = 1
+ r = x << y
+ if r != -2 {
+ t.Errorf("127 << 1 = %d, want -2", r)
+ }
+ y = 255
+ r = x << y
+ if r != 0 {
+ t.Errorf("127 << 255 = %d, want 0", r)
+ }
+}
+func TestConstFoldint8uint8rsh(t *testing.T) {
+ var x, r int8
+ var y uint8
+ x = -128
+ y = 0
+ r = x >> y
+ if r != -128 {
+ t.Errorf("-128 >> 0 = %d, want -128", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -64 {
+ t.Errorf("-128 >> 1 = %d, want -64", r)
+ }
+ y = 255
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-128 >> 255 = %d, want -1", r)
+ }
+ x = -127
+ y = 0
+ r = x >> y
+ if r != -127 {
+ t.Errorf("-127 >> 0 = %d, want -127", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -64 {
+ t.Errorf("-127 >> 1 = %d, want -64", r)
+ }
+ y = 255
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-127 >> 255 = %d, want -1", r)
+ }
+ x = -1
+ y = 0
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 0 = %d, want -1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 1 = %d, want -1", r)
+ }
+ y = 255
+ r = x >> y
+ if r != -1 {
+ t.Errorf("-1 >> 255 = %d, want -1", r)
+ }
+ x = 0
+ y = 0
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 0 = %d, want 0", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("0 >> 255 = %d, want 0", r)
+ }
+ x = 1
+ y = 0
+ r = x >> y
+ if r != 1 {
+ t.Errorf("1 >> 0 = %d, want 1", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 1 = %d, want 0", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("1 >> 255 = %d, want 0", r)
+ }
+ x = 126
+ y = 0
+ r = x >> y
+ if r != 126 {
+ t.Errorf("126 >> 0 = %d, want 126", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 63 {
+ t.Errorf("126 >> 1 = %d, want 63", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("126 >> 255 = %d, want 0", r)
+ }
+ x = 127
+ y = 0
+ r = x >> y
+ if r != 127 {
+ t.Errorf("127 >> 0 = %d, want 127", r)
+ }
+ y = 1
+ r = x >> y
+ if r != 63 {
+ t.Errorf("127 >> 1 = %d, want 63", r)
+ }
+ y = 255
+ r = x >> y
+ if r != 0 {
+ t.Errorf("127 >> 255 = %d, want 0", r)
+ }
+}
ODOTPTR,
OINDEX,
OIND,
- ONAME, // PHEAP or PPARAMREF var
OCALLFUNC,
OCALLMETH,
OCALLINTER:
}
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
// are parsing x := 5 inside the closure, until we get to
// the := it looks like a reference to the outer x so we'll
// make x a closure variable unnecessarily.
- if n.Name.Param.Closure == nil || n.Name.Param.Closure.Name.Funcdepth != Funcdepth {
- // create new closure var.
- c := Nod(ONAME, nil, nil)
-
+ c := n.Name.Param.Innermost
+ if c == nil || c.Name.Funcdepth != Funcdepth {
+ // Do not have a closure var for the active closure yet; make one.
+ c = Nod(ONAME, nil, nil)
c.Sym = s
- c.Class = PPARAMREF
+ c.Class = PAUTOHEAP
+ c.setIsClosureVar(true)
c.Isddd = n.Isddd
c.Name.Defn = n
c.Addable = false
c.Ullman = 2
c.Name.Funcdepth = Funcdepth
- c.Name.Param.Outer = n.Name.Param.Closure
- n.Name.Param.Closure = c
- c.Name.Param.Closure = n
+
+ // Link into list of active closure variables.
+ // Popped from list in func closurebody.
+ c.Name.Param.Outer = n.Name.Param.Innermost
+ n.Name.Param.Innermost = c
+
c.Xoffset = 0
Curfn.Func.Cvars.Append(c)
}
// return ref to closure var, not original
- return n.Name.Param.Closure
+ return c
}
return n
n.Func = new(Func)
n.Func.FCurfn = Curfn
dclcontext = PPARAM
- markdcl()
- Funcdepth++
- n.Func.Outer = Curfn
- Curfn = n
+
+ funcstart(n)
funcargs(n.Right)
// funcbody is normally called after the parser has
}
dclcontext = PAUTO
- markdcl()
- Funcdepth++
-
- n.Func.Outer = Curfn
- Curfn = n
+ funcstart(n)
if n.Func.Nname != nil {
funcargs(n.Func.Nname.Name.Param.Ntype)
}
}
+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.
// called in auto-declaration context.
// returns in extern-declaration context.
Fatalf("funcbody: unexpected dclcontext %d", dclcontext)
}
popdcl()
+ funcstack, Curfn = funcstack[:len(funcstack)-1], funcstack[len(funcstack)-1]
Funcdepth--
- Curfn = n.Func.Outer
- n.Func.Outer = nil
if Funcdepth == 0 {
dclcontext = PEXTERN
}
}
}
-func tofunargs(l []*Node) *Type {
+func tofunargs(l []*Node, funarg Funarg) *Type {
t := typ(TSTRUCT)
- t.StructType().Funarg = true
+ t.StructType().Funarg = funarg
fields := make([]*Field, len(l))
for i, n := range l {
f := structfield(n)
- f.Funarg = true
+ f.Funarg = funarg
// esc.go needs to find f given a PPARAM to add the tag.
if n.Left != nil && n.Left.Class == PPARAM {
if this != nil {
rcvr = []*Node{this}
}
- *t.RecvsP() = tofunargs(rcvr)
- *t.ResultsP() = tofunargs(out)
- *t.ParamsP() = tofunargs(in)
+ *t.RecvsP() = tofunargs(rcvr, FunargRcvr)
+ *t.ResultsP() = tofunargs(out, FunargResults)
+ *t.ParamsP() = tofunargs(in, FunargParams)
checkdupfields("argument", t.Recvs(), t.Results(), t.Params())
// "Big" conditions that were scattered around in walk have been gathered here
if n.Esc != EscHeap && n.Type != nil &&
(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)) {
if Debug['m'] > 2 {
Warnl(n.Lineno, "%v is too large for stack", n)
escassignSinkNilWhy(e, n, n7.Right, "map literal value")
}
- // Link addresses of captured variables to closure.
case OCLOSURE:
+ // Link addresses of captured variables to closure.
for _, v := range n.Func.Cvars.Slice() {
if v.Op == OXXX { // unnamed out argument; see dcl.go:/^funcargs
continue
}
- a := v.Name.Param.Closure
+ a := v.Name.Defn
if !v.Name.Byval {
a = Nod(OADDR, a, nil)
a.Lineno = v.Lineno
OIND, // dst = *x
ODOTPTR, // dst = (*x).f
ONAME,
- OPARAM,
ODDDARG,
OPTRLIT,
OARRAYLIT,
}
}
- // Treat a PPARAMREF closure variable as equivalent to the
+ // Treat a captured closure variable as equivalent to the
// original variable.
- if src.Class == PPARAMREF {
+ if src.isClosureVar() {
if leaks && Debug['m'] != 0 {
Warnl(src.Lineno, "leaking closure reference %v", Nconv(src, FmtShort))
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:
}
if leaks {
src.Esc = EscHeap
- addrescapes(src.Left)
if Debug['m'] != 0 && osrcesc != src.Esc {
p := src
if p.Left.Op == OCLOSURE {
p = p.Left // merely to satisfy error messages in tests
}
if Debug['m'] > 2 {
- Warnl(src.Lineno, "%v escapes to heap, level=%v, dst.eld=%v, src.eld=%v",
- Nconv(p, FmtShort), level, dstE.Escloopdepth, modSrcLoopdepth)
+ Warnl(src.Lineno, "%v escapes to heap, level=%v, dst=%v dst.eld=%v, src.eld=%v",
+ Nconv(p, FmtShort), level, dst, dstE.Escloopdepth, modSrcLoopdepth)
} else {
Warnl(src.Lineno, "%v escapes to heap", Nconv(p, FmtShort))
step.describe(src)
}
}
+ addrescapes(src.Left)
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
} else {
//print("reexportdep %+hN\n", n);
switch n.Op {
case ONAME:
- switch n.Class &^ PHEAP {
+ switch n.Class {
// methods will be printed along with their type
// nodes for T.Method expressions
case PFUNC:
"Pxxx",
"PEXTERN",
"PAUTO",
+ "PAUTOHEAP",
"PPARAM",
"PPARAMOUT",
- "PPARAMREF",
"PFUNC",
}
}
if n.Class != 0 {
- s := ""
- if n.Class&PHEAP != 0 {
- s = ",heap"
- }
- if int(n.Class&^PHEAP) < len(classnames) {
- fmt.Fprintf(&buf, " class(%s%s)", classnames[n.Class&^PHEAP], s)
+ if int(n.Class) < len(classnames) {
+ fmt.Fprintf(&buf, " class(%s)", classnames[n.Class])
} else {
- fmt.Fprintf(&buf, " class(%d?%s)", n.Class&^PHEAP, s)
+ fmt.Fprintf(&buf, " class(%d?)", n.Class)
}
}
switch n.Op {
case ODCL:
if fmtmode == FExp {
- switch n.Left.Class &^ PHEAP {
- case PPARAM, PPARAMOUT, PAUTO:
+ switch n.Left.Class {
+ case PPARAM, PPARAMOUT, PAUTO, PAUTOHEAP:
f += fmt.Sprintf("var %v %v", n.Left, n.Left.Type)
goto ret
}
if n.Nbody.Len() != 0 {
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:
ptrlit := n.Right != nil && n.Right.Implicit && n.Right.Type != nil && n.Right.Type.IsPtr()
}
if s != nil && f.Embedded == 0 {
- if f.Funarg {
+ if f.Funarg != FunargNone {
name = Nconv(f.Nname, 0)
} else if flag&FmtLong != 0 {
name = sconv(s, FmtShort|FmtByte) // qualify non-exported names (used on structs, not on funarg)
// (The escape analysis tags do not apply to func vars.)
// But it must not suppress struct field tags.
// 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)
}
break
}
- switch n.Class {
- case PPARAMREF:
+ // If a closure reference escapes, mark the outer variable as escaping.
+ if n.isClosureVar() {
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
+ if n.Class != PPARAM && n.Class != PPARAMOUT && n.Class != PAUTO {
+ break
+ }
- 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
+ // 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:
break
}
}
+// 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() {
for _, l := range labellist {
l.Sym.Label = nil
Fatalf("cgen_dcl")
}
- if n.Class&PHEAP == 0 {
- return
+ if n.Class == PAUTOHEAP {
+ 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
switch nr.Op {
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)
}
}
if nr == nil || iszero(nr) {
- // heaps should already be clear
- if nr == nil && (nl.Class&PHEAP != 0) {
- return
- }
-
tl := nl.Type
if tl == nil {
return
Pxxx Class = iota
PEXTERN // global variable
PAUTO // local variables
+ PAUTOHEAP // local variable or parameter moved to heap
PPARAM // input arguments
PPARAMOUT // output results
- PPARAMREF // closure variable reference
PFUNC // global function
PDISCARD // discard during parse of duplicate import
-
- PHEAP = 1 << 7 // an extra bit to identify an escaped variable
)
// note this is the runtime representation
var infile string
var outfile string
+var linkobj string
var bout *bio.Writer
var nblank *Node
-var Funcdepth int32
-
var typecheckok bool
var compiling_runtime bool
OCAP,
OINDREG,
ONAME,
- OPARAM,
OCLOSUREVAR:
return true
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:
if !Curfn.Func.Needctxt {
Fatalf("closurevar without needctxt")
return pl
}
-// nodarg does something that depends on the value of
-// fp (this was previously completely undocumented).
+// nodarg returns a Node for the function argument denoted by t,
+// 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).
+//
+// If fp is 0, the node is for use by a caller invoking the given
+// function, preparing the arguments before the call
+// or retrieving the results after the call.
+// In this case, the node will correspond to an outgoing argument
+// slot like 8(SP).
//
-// fp=1 corresponds to input args
-// fp=0 corresponds to output args
-// fp=-1 is a special case of output args for a
-// specific call from walk that previously (and
-// incorrectly) passed a 1; the behavior is exactly
-// 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 {
var n *Node
+ var funarg Funarg
switch t := t.(type) {
+ default:
+ Fatalf("bad nodarg %T(%v)", t, t)
+
case *Type:
- // entire argument struct, not just one arg
+ // Entire argument struct, not just one arg
if !t.IsFuncArgStruct() {
Fatalf("nodarg: bad type %v", t)
}
+ funarg = t.StructType().Funarg
+
+ // Build fake variable name for whole arg struct.
n = Nod(ONAME, nil, nil)
n.Sym = Lookup(".args")
n.Type = t
}
n.Xoffset = first.Offset
n.Addable = true
+
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 {
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
}
}
+
+ 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.Type = t.Type
n.Sym = t.Sym
n.Xoffset = t.Offset
n.Addable = true
n.Orig = t.Nname
- default:
- panic("unreachable")
}
// Rewrite argument named _ to __,
}
switch fp {
- case 0: // output arg
- n.Op = OINDREG
+ default:
+ Fatalf("bad fp")
+ case 0: // preparing arguments for call
+ n.Op = OINDREG
n.Reg = int16(Thearch.REGSP)
n.Xoffset += Ctxt.FixedFrameSize()
- case 1: // input arg
+ case 1: // reading arguments inside call
n.Class = PPARAM
-
- case -1: // output arg from paramstoheap
- n.Class = PPARAMOUT
-
- case 2: // offset output arg
- Fatalf("shouldn't be used")
+ if funarg == FunargResults {
+ n.Class = PPARAMOUT
+ }
}
n.Typecheck = 1
+ n.Addrtaken = true // keep optimizers at bay
return n
}
}
// hand-craft the following initialization code
-// var initdone· uint8 (1)
-// func init() (2)
+// var initdone· uint8 (1)
+// func init() { (2)
// if initdone· > 1 { (3)
// return (3a)
-// if initdone· == 1 { (4)
-// throw(); (4a)
-// }
-// initdone· = 1; (6)
-// // over all matching imported symbols
-// <pkg>.init() (7)
-// { <init stmts> } (8)
-// init.<n>() // if any (9)
-// initdone· = 2; (10)
-// return (11)
-// }
+// }
+// if initdone· == 1 { (4)
+// throw() (4a)
+// }
+// initdone· = 1 (5)
+// // over all matching imported symbols
+// <pkg>.init() (6)
+// { <init stmts> } (7)
+// init.<n>() // if any (8)
+// initdone· = 2 (9)
+// return (10)
+// }
func anyinit(n []*Node) bool {
// are there any interesting init statements
for _, ln := range n {
// (4a)
b.Nbody.Set1(Nod(OCALL, syslook("throwinit"), nil))
- // (6)
+ // (5)
a = Nod(OAS, gatevar, Nodintconst(1))
r = append(r, a)
- // (7)
+ // (6)
for _, s := range initSyms {
if s.Def != nil && s != initsym {
// could check that it is fn of no args/returns
}
}
- // (8)
+ // (7)
r = append(r, nf...)
- // (9)
+ // (8)
// could check that it is fn of no args/returns
for i := 1; ; i++ {
s := LookupN("init.", i)
r = append(r, a)
}
- // (10)
+ // (9)
a = Nod(OAS, gatevar, Nodintconst(2))
r = append(r, a)
- // (11)
+ // (10)
a = Nod(ORETURN, nil, nil)
r = append(r, a)
package gc
-import (
- "fmt"
-)
+import "fmt"
// 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.
*budget -= fn.InlCost
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 d := n.Left.Sym.Def; d != nil && d.Func.Inl.Len() != 0 {
*budget -= d.Func.InlCost
if ln.Class == PPARAMOUT { // return values handled below.
continue
}
+ if ln.isParamStackCopy() { // ignore the on-stack copy of a parameter that moved to the heap
+ continue
+ }
if ln.Op == ONAME {
- ln.Name.Inlvar = inlvar(ln)
-
- // Typecheck because inlvar is not necessarily a function parameter.
- 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
+ ln.Name.Inlvar = typecheck(inlvar(ln), Erv)
+ if ln.Class == PPARAM || ln.Name.Param.Stackcopy != nil && ln.Name.Param.Stackcopy.Class == PPARAM {
+ ninit.Append(Nod(ODCL, ln.Name.Inlvar, nil))
}
}
}
--- /dev/null
+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)
+ }
+ }
+ }
+ }
+}
flag.StringVar(&flag_installsuffix, "installsuffix", "", "set pkg directory `suffix`")
obj.Flagcount("j", "debug runtime-initialized variables", &Debug['j'])
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("m", "print optimization decisions", &Debug['m'])
flag.BoolVar(&flag_msan, "msan", false, "build code compatible with C/C++ memory sanitizer")
if p != "empty archive" {
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()
}
}
}
+ // 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)
// so don't record the full path.
linehistpragma(file[len(file)-len(path_)-2:]) // acts as #pragma lib
// Run this after changing builtin/runtime.go and builtin/unsafe.go
// or after changing the export metadata format in the compiler.
// 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
import (
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() {
+ if linkobj == "" {
+ dumpobj1(outfile, modeCompilerObj|modeLinkerObj)
+ } else {
+ dumpobj1(outfile, modeCompilerObj)
+ dumpobj1(linkobj, modeLinkerObj)
+ }
+}
+
+func dumpobj1(outfile string, mode int) {
var err error
bout, err = bio.Create(outfile)
if err != nil {
startobj = bout.Offset()
}
- fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring())
- dumpexport()
+ printheader := func() {
+ 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 {
bout.Flush()
formathdr(arhdr[:], "__.PKGDEF", size)
bout.Write(arhdr[:])
bout.Flush()
-
bout.Seek(startobj+size+(size&1), 0)
+ }
+
+ if mode&modeLinkerObj == 0 {
+ bout.Close()
+ return
+ }
+
+ if writearchive {
+ // start object file
arhdr = [ArhdrSize]byte{}
bout.Write(arhdr[:])
startobj = bout.Offset()
- fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring())
+ printheader()
}
if pragcgobuf != "" {
OINDEX: "INDEX",
OINDEXMAP: "INDEXMAP",
OKEY: "KEY",
- OPARAM: "PARAM",
OLEN: "LEN",
OMAKE: "MAKE",
OMAKECHAN: "MAKECHAN",
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:
mark := marktemp(order)
n.Left = orderexpr(n.Left, order, nil)
p.import_error()
}
- importsafe := false
+ // read but skip "safe" bit (see issue #15772)
if p.tok == LNAME {
- if p.sym_.Name == "safe" {
- importsafe = true
- }
p.next()
}
p.want(';')
} else if importpkg.Name != name {
Yyerror("conflicting names %s and %s for package %q", importpkg.Name, name, importpkg.Path)
}
- importpkg.Safe = importsafe
typecheckok = true
defercheckwidth()
return false
}
-// Collects and returns a slice of *Nodes for functions arguments and local
-// variables.
+// livenessShouldTrack reports whether the liveness analysis
+// 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 {
- var result []*Node
- for _, ln := range fn.Func.Dcl {
- if ln.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.
- //
+ var vars []*Node
+ for _, n := range fn.Func.Dcl {
+ if n.Op == ONAME {
// 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
- // (so that 0 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.
+ // We use it to hold the index of the node in the variables array
+ // (nil means the Node is not in the variables array).
// 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,
// so fix that here.
// 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.
- ln.SetOpt(nil)
-
- // The compiler doesn't emit initializations for zero-width parameters or results.
- if ln.Type.Width == 0 {
- continue
- }
-
- ln.Name.Curfn = Curfn
- switch ln.Class {
- case PAUTO:
- if haspointers(ln.Type) {
- ln.SetOpt(int32(len(result)))
- result = append(result, ln)
- }
+ n.SetOpt(nil)
+ n.Name.Curfn = Curfn
+ }
- case PPARAM, PPARAMOUT:
- ln.SetOpt(int32(len(result)))
- result = append(result, ln)
- }
+ if livenessShouldTrack(n) {
+ n.SetOpt(int32(len(vars)))
+ vars = append(vars, n)
}
}
- return result
+ return vars
}
// A pretty printer for control flow graphs. Takes a slice of *BasicBlocks.
// read the out arguments - they won't be set until the new
// function runs.
for i, node := range vars {
- switch node.Class &^ PHEAP {
+ switch node.Class {
case PPARAM:
- bvset(uevar, int32(i))
+ if !node.NotLiveAtEnd() {
+ bvset(uevar, int32(i))
+ }
// If the result had its address taken, it is being tracked
// by the avarinit code, which does not use uevar.
// A text instruction marks the entry point to a function and
// the definition point of all in arguments.
for i, node := range vars {
- switch node.Class &^ PHEAP {
+ switch node.Class {
case PPARAM:
if node.Addrtaken {
bvset(avarinit, int32(i))
if prog.Info.Flags&(LeftRead|LeftWrite|LeftAddr) != 0 {
from := &prog.From
- if from.Node != nil && from.Sym != nil && ((from.Node).(*Node)).Name.Curfn == Curfn {
- switch ((from.Node).(*Node)).Class &^ PHEAP {
- case PAUTO, PPARAM, PPARAMOUT:
- pos, ok := from.Node.(*Node).Opt().(int32) // index in vars
- 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 {
+ if from.Node != nil && from.Sym != nil {
+ n := from.Node.(*Node)
+ if pos := liveIndex(n, vars); pos >= 0 {
+ if n.Addrtaken {
bvset(avarinit, pos)
} else {
if prog.Info.Flags&(LeftRead|LeftAddr) != 0 {
bvset(uevar, pos)
}
if prog.Info.Flags&LeftWrite != 0 {
- if from.Node != nil && !Isfat(((from.Node).(*Node)).Type) {
+ if !Isfat(n.Type) {
bvset(varkill, pos)
}
}
if prog.Info.Flags&(RightRead|RightWrite|RightAddr) != 0 {
to := &prog.To
- if to.Node != nil && to.Sym != nil && ((to.Node).(*Node)).Name.Curfn == Curfn {
- switch ((to.Node).(*Node)).Class &^ PHEAP {
- case PAUTO, PPARAM, PPARAMOUT:
- pos, ok := to.Node.(*Node).Opt().(int32) // index in vars
- 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 to.Node != nil && to.Sym != nil {
+ n := to.Node.(*Node)
+ if pos := liveIndex(n, vars); pos >= 0 {
+ if n.Addrtaken {
if prog.As != obj.AVARKILL {
bvset(avarinit, pos)
}
bvset(uevar, pos)
}
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)
}
}
}
}
+// 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
// liveness computation. The cfg argument is a slice of *BasicBlocks and the
// vars argument is a slice of *Nodes.
return
}
for _, a := range fn.Func.Dcl {
- class := a.Class &^ PHEAP
- if a.Op == ONAME && (class == PPARAM || class == PPARAMOUT) && a == n {
+ if a.Op == ONAME && (a.Class == PPARAM || a.Class == PPARAMOUT) && a == n {
return
}
}
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.
case OPRINT, // don't bother instrumenting it
OPRINTN, // don't bother instrumenting it
OCHECKNIL, // always followed by a read.
- OPARAM, // it appears only in fn->exit to copy heap params back
OCLOSUREVAR, // immutable pointer to captured variable
ODOTMETH, // either part of CALLMETH or CALLPART (lowered to PTRLIT)
OINDREG, // at this stage, only n(SP) nodes from nodarg
// e.g. if we've got a local variable/method receiver
// that has got a pointer inside. Whether it points to
// 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
foreach(n, hascallspred, &hascalls)
if hascalls != 0 {
}
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) {
_64bit uintptr // size on 64bit platforms
}{
{Flow{}, 52, 88},
- {Func{}, 96, 168},
+ {Func{}, 92, 160},
{Name{}, 52, 80},
{Node{}, 92, 144},
{Sym{}, 60, 112},
--- /dev/null
+// 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())
+}
// the function.
s.returns = append(s.returns, n)
}
- case PAUTO | PHEAP:
- // TODO this looks wrong for PAUTO|PHEAP, no vardef, but also no definition
- aux := s.lookupSymbol(n, &ssa.AutoSymbol{Typ: n.Type, Node: n})
- 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.
+ if n.Class == PPARAM && s.canSSA(n) && n.Type.IsPtrShaped() {
+ s.ptrargs = append(s.ptrargs, n)
+ n.SetNotLiveAtEnd(true) // SSA takes care of this explicitly
+ }
case PAUTO:
// processed at each use, to prevent Addr coming
// before the decl.
+ case PAUTOHEAP:
+ // moved to heap - already handled by frontend
case PFUNC:
// local function - already handled by frontend
default:
- str := ""
- if n.Class&PHEAP != 0 {
- str = ",heap"
- }
- s.Unimplementedf("local variable with class %s%s unimplemented", classnames[n.Class&^PHEAP], str)
+ s.Unimplementedf("local variable with class %s unimplemented", classnames[n.Class])
}
}
return nil
}
+ prelinkNumvars := s.f.NumValues()
+ sparseDefState := s.locatePotentialPhiFunctions(fn)
+
// 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
s.exitCode = Nodes{}
// list of FwdRef values.
fwdRefs []*ssa.Value
- // list of PPARAMOUT (return) variables. Does not include PPARAM|PHEAP vars.
+ // list of PPARAMOUT (return) variables.
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
noWB bool
WBLineno int32 // line number of first write barrier. 0=no write barriers
return
case ODCL:
- if n.Left.Class&PHEAP == 0 {
- return
- }
- 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
+ if n.Left.Class == PAUTOHEAP {
+ Fatalf("DCL %v", n)
}
- r := s.expr(palloc)
- s.assign(n.Left.Name.Heapaddr, r, false, false, n.Lineno, 0)
case OLABEL:
sym := n.Left.Sym
// Store SSAable PPARAMOUT variables back to stack locations.
for _, n := range s.returns {
- aux := &ssa.ArgSymbol{Typ: n.Type, Node: n}
- addr := s.newValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
+ addr := s.decladdrs[n]
val := s.variable(n, n.Type)
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())
// 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.
m := s.mem()
b := s.endBlock()
case OCFUNC:
aux := s.lookupSymbol(n, &ssa.ExternSymbol{Typ: n.Type, Sym: n.Left.Sym})
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:
if n.Class == PFUNC {
// "value" of a function is the address of the function's closure
// Start exit block, find address of result.
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()
if res.NumFields() == 0 || k != callNormal {
// call has no return value. Continue with the next statement.
// that cse works on their addresses
aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
return s.newValue1A(ssa.OpAddr, t, aux, s.sp)
- case PAUTO | PHEAP, PPARAM | PHEAP, PPARAMOUT | PHEAP, PPARAMREF:
- return s.expr(n.Name.Heapaddr)
default:
- s.Unimplementedf("variable address class %v not implemented", n.Class)
+ s.Unimplementedf("variable address class %v not implemented", classnames[n.Class])
return nil
}
case OINDREG:
case OCLOSUREVAR:
return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset,
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:
addr := s.addr(n.Left, bounded)
return s.newValue1(ssa.OpCopy, t, addr) // ensure that addr has the right type
if n.Addrtaken {
return false
}
- if n.Class&PHEAP != 0 {
+ if n.isParamHeapCopy() {
return false
}
+ if n.Class == PAUTOHEAP {
+ Fatalf("canSSA of PAUTOHEAP %v", n)
+ }
switch n.Class {
- case PEXTERN, PPARAMREF:
- // TODO: maybe treat PPARAMREF with an Arg-like op to read from closure?
+ case PEXTERN:
return false
case PPARAMOUT:
if hasdefer {
b.AddEdgeTo(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
res := make([]*ssa.Value, len(results))
for i, t := range results {
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
// leaves a FwdRef in that block representing the incoming value
// of that variable. This function links that ref up with possible definitions,
for len(s.fwdRefs) > 0 {
v := 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.
// 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
name := v.Aux.(*Node)
v.Aux = nil
args := argstore[:0]
for _, e := range b.Preds {
p := e.Block()
+ p = dm.FindBetterDefiningBlock(name, p) // try sparse improvement on p
args = append(args, s.lookupVarOutgoing(p, v.Type, name, v.Line))
}
}
// TestFP tests that both backends have the same result for floating point expressions.
-func TestFP(t *testing.T) {
- 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")
-}
+func TestFP(t *testing.T) { runTest(t, "fp_ssa.go") }
// TestArithmeticBoundary tests boundary results for arithmetic operations.
func TestArithmeticBoundary(t *testing.T) { runTest(t, "arithBoundary_ssa.go") }
return Ctxt.Line(int(line))
}
-func yyerrorl(line int32, format string, args ...interface{}) {
- adderr(line, format, args...)
-
- hcrash()
- nerrors++
- if nsavederrors+nerrors >= 10 && Debug['e'] == 0 {
- Flusherrors()
- fmt.Printf("%v: too many errors\n", linestr(line))
- errorexit()
- }
+// 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
}
-var yyerror_lastsyntax int32
-
-func Yyerror(format string, args ...interface{}) {
+func yyerrorl(line int32, format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
+
if strings.HasPrefix(msg, "syntax error") {
nsyntaxerrors++
-
- // only one syntax error per line
- if yyerror_lastsyntax == lineno {
+ // only one syntax error per line, no matter what error
+ if lasterror.syntax == line {
return
}
- yyerror_lastsyntax = lineno
-
- yyerrorl(lineno, "%s", msg)
- 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(lineno, "%s", msg)
+ adderr(line, "%s", msg)
hcrash()
nerrors++
if nsavederrors+nerrors >= 10 && Debug['e'] == 0 {
Flusherrors()
- fmt.Printf("%v: too many errors\n", linestr(lineno))
+ fmt.Printf("%v: too many errors\n", linestr(line))
errorexit()
}
}
+func Yyerror(format string, args ...interface{}) {
+ yyerrorl(lineno, format, args...)
+}
+
func Warn(fmt_ string, args ...interface{}) {
adderr(lineno, fmt_, args...)
switch n.Op {
case OREGISTER, OLITERAL, ONAME:
ul = 1
- if n.Class == PPARAMREF || (n.Class&PHEAP != 0) {
+ if n.Class == PAUTOHEAP {
ul++
}
goto out
}
func checknil(x *Node, init *Nodes) {
+ x = walkexpr(x, nil) // caller has not done this yet
if x.Type.IsInterface() {
x = Nod(OITAB, x, nil)
x = typecheck(x, Erv)
Used bool
Isddd bool // is the argument variadic
Implicit bool
- Addrtaken bool // address taken, even if not moved to heap
- Assigned bool // is the variable ever assigned to
- Likely int8 // likeliness of if statement
- Hasbreak bool // has break statement
- hasVal int8 // +1 for Val, -1 for Opt, 0 for not yet set
+ Addrtaken bool // address taken, even if not moved to heap
+ Assigned bool // is the variable ever assigned to
+ Likely int8 // likeliness of if statement
+ 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.
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 {
- Pack *Node // real package for import . names
- Pkg *Pkg // pkg for OPACK nodes
- Heapaddr *Node // temp holding heap address of param
- Inlvar *Node // ONAME substitute while inlining
- Defn *Node // initializing assignment
- Curfn *Node // function for local variables
- Param *Param
- 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.
- Iota int32 // value if this name is iota
+ Pack *Node // real package for import . names
+ Pkg *Pkg // pkg for OPACK nodes
+ Heapaddr *Node // temp holding heap address of param (could move to Param?)
+ Inlvar *Node // ONAME substitute while inlining (could move to Param?)
+ Defn *Node // initializing assignment
+ Curfn *Node // function for local variables
+ Param *Param // additional fields for ONAME, ODCLFIELD
+ 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.
+ Iota int32 // value if this name is iota
Funcdepth int32
Method bool // OCALLMETH name
Readonly bool
type Param struct {
Ntype *Node
- // ONAME func param with PHEAP
- Outerexpr *Node // expression copied into closure for variable
- Stackparam *Node // OPARAM node referring to stack copy of param
+ // ONAME PAUTOHEAP
+ Stackcopy *Node // the PPARAM/PPARAMOUT on-stack slot (moved func params only)
// ONAME PPARAM
Field *Field // TFIELD in arg struct
- // ONAME closure param with PPARAMREF
- Outer *Node // outer PPARAMREF in nested closure
- Closure *Node // ONAME/PHEAP <-> ONAME/PPARAMREF
+ // ONAME closure linkage
+ // Consider:
+ //
+ // 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.
Dcl []*Node // autodcl for this func/closure
Inldcl Nodes // copy of dcl for use in inlining
Closgen int
- Outerfunc *Node
+ Outerfunc *Node // outer function (for closure)
FieldTrack map[*Sym]struct{}
- Outer *Node // outer func for closure
Ntype *Node // signature
Top int // top context (Ecall, Eproc, etc)
Closure *Node // OCLOSURE <-> ODCLFUNC
OINDEX // Left[Right] (index of array or slice)
OINDEXMAP // Left[Right] (index of map)
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)
OMAKE // make(List) (before type checking converts to one of the following)
OMAKECHAN // make(Type, Left) (type is chan)
--- /dev/null
+// 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)
+ }
+}
// Map links such structs back to their map type.
Map *Type
- Funarg bool // whether this struct represents function parameters
- Haspointers uint8 // 0 unknown, 1 no, 2 yes
+ Funarg Funarg // type of function arguments for arg struct
+ 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.
func (t *Type) StructType() *StructType {
t.wantEtype(TSTRUCT)
type Field struct {
Nointerface bool
Embedded uint8 // embedded field
- Funarg bool
+ Funarg Funarg
Broke bool // broken field definition
Isddd bool // field is ... argument
// IsFuncArgStruct reports whether t is a struct representing function parameters.
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 {
var l *Node
for l = n.Left; l != r; l = l.Left {
l.Addrtaken = true
- if l.Name != nil && l.Name.Param != nil && l.Name.Param.Closure != nil {
- l.Name.Param.Closure.Addrtaken = true
+ if l.isClosureVar() {
+ l.Name.Defn.Addrtaken = true
}
}
Fatalf("found non-orig name node %v", l)
}
l.Addrtaken = true
- if l.Name != nil && l.Name.Param != nil && l.Name.Param.Closure != nil {
- l.Name.Param.Closure.Addrtaken = true
+ if l.isClosureVar() {
+ l.Name.Defn.Addrtaken = true
}
n.Left = defaultlit(n.Left, nil)
l = n.Left
return false
}
fallthrough
- case OIND, ODOTPTR, OCLOSUREVAR, OPARAM:
+ case OIND, ODOTPTR, OCLOSUREVAR:
return true
case ODOT:
var l *Node
for l = n; l != r; l = l.Left {
l.Assigned = true
- if l.Name != nil && l.Name.Param != nil && l.Name.Param.Closure != nil {
- l.Name.Param.Closure.Assigned = true
+ if l.isClosureVar() {
+ l.Name.Defn.Assigned = true
}
}
l.Assigned = true
- if l.Name != nil && l.Name.Param != nil && l.Name.Param.Closure != nil {
- l.Name.Param.Closure.Assigned = true
+ if l.isClosureVar() {
+ l.Name.Defn.Assigned = true
}
}
}
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
}
case OBREAK:
if n.Left == nil {
if implicit != nil {
- implicit.Hasbreak = true
+ implicit.SetHasBreak(true)
}
} else {
lab := n.Left.Sym.Label
if lab != nil {
- lab.Def.Hasbreak = true
+ lab.Def.SetHasBreak(true)
}
}
if n.Left != nil {
return false
}
- if n.Hasbreak {
+ if n.HasBreak() {
return false
}
return true
return n.Nbody.isterminating() && n.Rlist.isterminating()
case OSWITCH, OTYPESW, OSELECT:
- if n.Hasbreak {
+ if n.HasBreak() {
return false
}
def := 0
// t = interface { Error() string }
rcvr := typ(TSTRUCT)
- rcvr.StructType().Funarg = true
+ rcvr.StructType().Funarg = FunargRcvr
field := newField()
field.Type = Ptrto(typ(TSTRUCT))
rcvr.SetFields([]*Field{field})
in := typ(TSTRUCT)
- in.StructType().Funarg = true
+ in.StructType().Funarg = FunargParams
out := typ(TSTRUCT)
- out.StructType().Funarg = true
+ out.StructType().Funarg = FunargResults
field = newField()
field.Type = Types[TSTRING]
out.SetFields([]*Field{field})
lno := lineno
// 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 {
- if ln.Op == ONAME && ln.Class&^PHEAP == PAUTO {
+ if ln.Op == ONAME && (ln.Class == PAUTO || ln.Class == PAUTOHEAP) {
ln = typecheck(ln, Erv|Easgn)
fn.Func.Dcl[i] = ln
}
// Propagate the used flag for typeswitch variables up to the NONAME in it's definition.
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
}
}
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
}
if defn := ln.Name.Defn; defn != nil && defn.Op == OTYPESW {
func paramoutheap(fn *Node) bool {
for _, ln := range fn.Func.Dcl {
switch ln.Class {
- case PPARAMOUT,
- PPARAMOUT | PHEAP:
- return ln.Addrtaken
+ case PPARAMOUT:
+ if ln.isParamStackCopy() || ln.Addrtaken {
+ return true
+ }
+ case PAUTO:
// stop early - parameters are over
- case PAUTO,
- PAUTO | PHEAP:
return false
}
}
n = addinit(n, init.Slice())
case OBREAK,
- ODCL,
OCONTINUE,
OFALL,
OGOTO,
OVARLIVE:
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:
walkstmtlist(n.List.Slice())
var cl Class
for _, ln := range Curfn.Func.Dcl {
- cl = ln.Class &^ PHEAP
- if cl == PAUTO {
+ cl = ln.Class
+ if cl == PAUTO || cl == PAUTOHEAP {
break
}
if cl == PPARAMOUT {
+ if ln.isParamStackCopy() {
+ ln = walkexpr(typecheck(Nod(OIND, ln.Name.Heapaddr, nil), Erv), nil)
+ }
rl = append(rl, ln)
}
}
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:
switch n.Op {
default:
ONONAME,
OINDREG,
OEMPTY,
- OPARAM,
OGETG:
case ONOT,
n.Addable = true
case ONAME:
- if n.Class&PHEAP == 0 && n.Class != PPARAMREF {
- n.Addable = true
- }
+ n.Addable = true
case OCALLINTER:
usemethod(n)
break
}
// 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
}
nn = append(nn, ascompatee1(op, nl[i], nr[i], init))
switch l.Op {
case ONAME:
switch l.Class {
- case PPARAM, PPARAMREF, PAUTO:
+ case PPARAM, PAUTO:
break
// assignment to non-stack variable
// and to copy non-result prameters' values from the stack.
// If out is true, then code is also produced to zero-initialize their
// stack memory addresses.
-func paramstoheap(params *Type, out bool) []*Node {
+func paramstoheap(params *Type) []*Node {
var nn []*Node
for _, t := range params.Fields().Slice() {
- v := t.Nname
- if v != nil && v.Sym != nil && strings.HasPrefix(v.Sym.Name, "~r") { // unnamed result
- v = nil
- }
-
// For precise stacks, the garbage collector assumes results
// are always live, so zero them always.
- if out {
+ 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))
+ nn = append(nn, Nod(OAS, nodarg(t, 1), nil))
}
- if v == nil || v.Class&PHEAP == 0 {
+ v := t.Nname
+ if v != nil && v.Sym != nil && strings.HasPrefix(v.Sym.Name, "~r") { // unnamed result
+ v = nil
+ }
+ if v == nil {
continue
}
- // generate allocation & copying code
- if compiling_runtime {
- Yyerror("%v escapes to heap, not allowed in runtime.", v)
- }
- 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)
+ if stackcopy := v.Name.Param.Stackcopy; stackcopy != nil {
+ nn = append(nn, walkstmt(Nod(ODCL, v, nil)))
+ if stackcopy.Class == PPARAM {
+ nn = append(nn, walkstmt(typecheck(Nod(OAS, v, stackcopy), Etop)))
+ }
}
}
var nn []*Node
for _, t := range params.Fields().Slice() {
v := t.Nname
- if v == nil || v.Class != PHEAP|PPARAMOUT {
+ if v == nil {
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
func heapmoves() {
lno := lineno
lineno = Curfn.Lineno
- nn := paramstoheap(Curfn.Type.Recvs(), false)
- nn = append(nn, paramstoheap(Curfn.Type.Params(), false)...)
- nn = append(nn, paramstoheap(Curfn.Type.Results(), true)...)
+ nn := paramstoheap(Curfn.Type.Recvs())
+ nn = append(nn, paramstoheap(Curfn.Type.Params())...)
+ nn = append(nn, paramstoheap(Curfn.Type.Results())...)
Curfn.Func.Enter.Append(nn...)
lineno = Curfn.Func.Endlineno
Curfn.Func.Exit.Append(returnsfromheap(Curfn.Type.Results())...)
//return;
// algorithm is:
// 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
*/
gmove(&bigi, &rtmp)
gins(mips.AAND, &r1, &rtmp)
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.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)
}
}
// 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) {
// unreachable - ignore
return true
// Surround timing information w/ enough context to allow comparisons.
time := tEnd.Sub(tStart).Nanoseconds()
if p.time {
- f.logStat("TIME(ns)", time)
+ f.LogStat("TIME(ns)", time)
}
if p.mem {
var mEnd runtime.MemStats
runtime.ReadMemStats(&mEnd)
nBytes := mEnd.TotalAlloc - mStart.TotalAlloc
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 {
var IntrinsicsDebug int
var IntrinsicsDisable bool
+var BuildDebug int
+var BuildTest int
+var BuildStats int
+
// PhaseOption sets the specified flag in the specified ssa phase,
// returning empty string if this was successful or a string explaining
// the error if it was not.
}
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)
var re *regexp.Regexp
"crypto/sha1"
"fmt"
"os"
+ "strconv"
"strings"
)
type Config struct {
- arch string // "amd64", etc.
- IntSize int64 // 4 or 8
- PtrSize int64 // 4 or 8
- lowerBlock func(*Block) bool // lowering function
- lowerValue func(*Value, *Config) bool // lowering function
- registers []Register // machine registers
- flagRegMask regMask // flag register mask
- fe Frontend // callbacks into compiler frontend
- HTML *HTMLWriter // html writer, for debugging
- ctxt *obj.Link // Generic arch information
- optimize bool // Do optimization
- noDuffDevice bool // Don't use Duff's device
- curFunc *Func
+ arch string // "amd64", etc.
+ IntSize int64 // 4 or 8
+ PtrSize int64 // 4 or 8
+ lowerBlock func(*Block) bool // lowering function
+ lowerValue func(*Value, *Config) bool // lowering function
+ registers []Register // machine registers
+ flagRegMask regMask // flag register mask
+ fe Frontend // callbacks into compiler frontend
+ HTML *HTMLWriter // html writer, for debugging
+ ctxt *obj.Link // Generic arch information
+ optimize bool // Do optimization
+ noDuffDevice bool // Don't use Duff's device
+ sparsePhiCutoff uint64 // Sparse phi location algorithm used above this #blocks*#variables score
+ curFunc *Func
// TODO: more stuff. Compiler flags of interest, ...
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
}
-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.
// Caller must call f.Free() before calling NewFunc again.
}
return false
}
+
+func (c *Config) DebugNameMatch(evname, name string) bool {
+ return os.Getenv(evname) == name
+}
// if v and w are in the same equivalence class and v dominates w.
rewrite := make([]*Value, f.NumValues())
for _, e := range partition {
- sort.Sort(sortbyentry{e, f.sdom})
+ sort.Sort(partitionByDom{e, f.sdom})
for i := 0; i < len(e)-1; i++ {
- // e is sorted by entry value so maximal dominant element should be
- // found first in the slice
+ // e is sorted by domorder, so a maximal dominant element is first in the slice
v := e[i]
if v == nil {
continue
rewrite[w.ID] = v
e[j] = nil
} else {
- // since the blocks are assorted in ascending order by entry number
- // once we know that we don't dominate a block we can't dominate any
- // 'later' block
+ // e is sorted by domorder, so v.Block doesn't dominate any subsequent blocks in e
break
}
}
}
}
if f.pass.stats > 0 {
- f.logStat("CSE REWRITES", rewrites)
+ f.LogStat("CSE REWRITES", rewrites)
}
}
return v.ID < w.ID
}
-type sortbyentry struct {
+type partitionByDom struct {
a []*Value // array of values
- sdom sparseTree
+ sdom SparseTree
}
-func (sv sortbyentry) 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 sortbyentry) Less(i, j int) bool {
+func (sv partitionByDom) Len() int { return len(sv.a) }
+func (sv partitionByDom) Swap(i, j int) { sv.a[i], sv.a[j] = sv.a[j], sv.a[i] }
+func (sv partitionByDom) Less(i, j int) bool {
v := sv.a[i]
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)
}
// postorder computes a postorder traversal ordering for the
// basic blocks in f. Unreachable blocks will not appear.
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())
// result ordering
s = s[:len(s)-1]
mark[b.ID] = done
if len(ponums) > 0 {
- ponums[b.ID] = len(order)
+ ponums[b.ID] = int32(len(order))
}
order = append(order, b)
case notExplored:
freeBlocks *Block // free Blocks linked by succstorage[0].b. All other fields except ID are 0/nil.
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
}
// context to allow item-by-item comparisons across runs.
// For example:
// 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 := ""
for _, a := range args {
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.
{name: "ComplexImag", argLength: 1}, // imag(arg0)
// Strings
- {name: "StringMake", argLength: 2}, // arg0=ptr, arg1=len
- {name: "StringPtr", argLength: 1}, // ptr(arg0)
- {name: "StringLen", argLength: 1}, // len(arg0)
+ {name: "StringMake", argLength: 2}, // arg0=ptr, arg1=len
+ {name: "StringPtr", argLength: 1, typ: "BytePtr"}, // ptr(arg0)
+ {name: "StringLen", argLength: 1, typ: "Int"}, // len(arg0)
// Interfaces
{name: "IMake", argLength: 2}, // arg0=itab, arg1=data
{name: "LoadReg", argLength: 1},
// 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.
{name: "Unknown"},
{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: "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
fmt.Fprintln(w, "// generated with: cd gen; go run *.go")
fmt.Fprintln(w)
fmt.Fprintln(w, "package ssa")
- if *genLog {
- fmt.Fprintln(w, "import \"fmt\"")
- }
fmt.Fprintln(w, "import \"math\"")
fmt.Fprintln(w, "var _ = math.MinInt8 // in case not otherwise used")
genResult(w, arch, result, rule.loc)
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")
}
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")
}
// outerinner records that outer contains inner
-func (sdom sparseTree) outerinner(outer, inner *loop) {
+func (sdom SparseTree) outerinner(outer, inner *loop) {
oldouter := inner.outer
if oldouter == nil || sdom.isAncestorEq(oldouter.header, outer.header) {
inner.outer = outer
f *Func
b2l []*loop
po []*Block
- sdom sparseTree
+ sdom SparseTree
loops []*loop
// Record which of the lazily initialized fields have actually been initialized.
// containing block b; the header must dominate b. loop itself
// is assumed to not be that loop. For acceptable performance,
// 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
for o = l.outer; o != nil && !sdom.isAncestorEq(o.header, b); o = o.outer {
}
inner++
}
- f.logStat("loopstats:",
+ f.LogStat("loopstats:",
l.depth, "depth", x, "exits",
inner, "is_inner", cf, "is_callfree", l.nBlocks, "n_blocks")
}
continue // lowered
}
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
}
s := "not lowered: " + v.Op.String() + " " + v.Type.SimpleString()
OpVarDef
OpVarKill
OpVarLive
+ OpKeepAlive
)
var opcodeTable = [...]opInfo{
},
{
name: "FwdRef",
+ auxType: auxSym,
argLen: 0,
generic: true,
},
argLen: 1,
generic: true,
},
+ {
+ name: "KeepAlive",
+ argLen: 2,
+ generic: true,
+ },
}
func (o Op) Asm() obj.As { return opcodeTable[o].asm }
b.ReportAllocs()
c := NewConfig("amd64", DummyFrontend{b}, nil, true)
fun := Fun(c, "entry", bg(size)...)
-
+ domTree(fun.f)
CheckFunc(fun.f)
b.ResetTimer()
for i := 0; i < b.N; i++ {
b.ReportAllocs()
c := NewConfig("amd64", DummyFrontend{b}, nil, true)
fun := Fun(c, "entry", bg(b.N)...)
-
+ domTree(fun.f)
CheckFunc(fun.f)
b.ResetTimer()
for i := 0; i < passCount; i++ {
// getBranch returns the range restrictions added by p
// 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 {
return unknown
}
--- /dev/null
+// 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
+}
--- /dev/null
+// 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})
+}
package ssa
import (
- "cmd/internal/obj"
"fmt"
"unsafe"
)
s.allocatable = regMask(1)<<s.numRegs - 1
s.allocatable &^= 1 << s.SPReg
s.allocatable &^= 1 << s.SBReg
- if obj.Framepointer_enabled != 0 {
+ if s.f.Config.ctxt.Framepointer_enabled {
s.allocatable &^= 1 << 5 // BP
}
if s.f.Config.ctxt.Flag_dynlink {
s.advanceUses(v)
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
if len(regspec.inputs) == 0 && len(regspec.outputs) == 0 {
// No register allocation required (or none specified yet)
s.freeRegs(regspec.clobbers)
b.Values = append(b.Values, v)
+ s.advanceUses(v)
continue
}
// Start with live at end.
for _, li := range s.live[ss.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))
}
}
// Control can also be live.
- if ss.Control != nil && s.isLoopSpillCandidate(loop, ss.Control) {
- entryCandidates.setBit(ss.Control.ID, uint(whichExit))
+ if ss.Control != nil && s.orig[ss.Control.ID] != nil && s.isLoopSpillCandidate(loop, s.orig[ss.Control.ID]) {
+ entryCandidates.setBit(s.orig[ss.Control.ID].ID, uint(whichExit))
}
// Walk backwards, filling in locally live values, removing those defined.
for i := len(ss.Values) - 1; i >= 0; 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 {
- if s.isLoopSpillCandidate(loop, a) {
- entryCandidates.setBit(a.ID, uint(whichExit))
+ aorig := s.orig[a.ID]
+ if aorig != nil && s.isLoopSpillCandidate(loop, aorig) {
+ entryCandidates.setBit(aorig.ID, uint(whichExit))
}
}
}
}
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")
}
}
import (
"fmt"
"math"
+ "os"
+ "path/filepath"
)
func applyRewrite(f *Func, rb func(*Block) bool, rv func(*Value, *Config) bool) {
// Note: leave v.Block intact. The Block field is used after clobber.
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
type sparseMap struct {
dense []sparseEntry
- sparse []int
+ sparse []int32
}
// newSparseMap returns a sparseMap that can map
// integers between 0 and n-1 to int32s.
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) contains(k ID) bool {
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
// not appear in the map.
func (s *sparseMap) get(k ID) int32 {
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 -1
func (s *sparseMap) set(k ID, v int32) {
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
return
}
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
panic("bit index too large.")
}
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
return
}
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) {
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]
s.dense[i] = y
s.sparse[y.key] = i
type sparseSet struct {
dense []ID
- sparse []int
+ sparse []int32
}
// newSparseSet returns a sparseSet that can represent
// integers between 0 and n-1
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) contains(x ID) bool {
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) {
i := s.sparse[x]
- if i < len(s.dense) && s.dense[i] == x {
+ if i < int32(len(s.dense)) && s.dense[i] == x {
return
}
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) remove(x ID) {
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]
s.dense[i] = y
s.sparse[y] = i
package ssa
-type sparseTreeNode struct {
+import "fmt"
+
+type SparseTreeNode struct {
child *Block
sibling *Block
parent *Block
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 (
// When used to lookup up definitions in a sparse tree,
// these adjustments to a block's entry (+adjust) and
// exit (-adjust) numbers allow a distinction to be made
// between assignments (typically branch-dependent
- // conditionals) occurring "before" phi functions, the
- // phi functions, and at the bottom of a block.
- ADJUST_BEFORE = -1 // defined before phi
- ADJUST_TOP = 0 // defined by phi
- ADJUST_BOTTOM = 1 // defined within block
+ // conditionals) occurring "before" the block (e.g., as inputs
+ // to the block and its phi functions), "within" the block,
+ // and "after" the block.
+ AdjustBefore = -1 // defined before phi
+ 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,
// 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)
-func newSparseTree(f *Func, parentOf []*Block) sparseTree {
- t := make(sparseTree, f.NumBlocks())
+// newSparseTree creates a SparseTree from a block-to-parent map (array indexed by Block.ID)
+func newSparseTree(f *Func, parentOf []*Block) SparseTree {
+ t := make(SparseTree, f.NumBlocks())
for _, b := range f.Blocks {
n := &t[b.ID]
if p := parentOf[b.ID]; p != nil {
// root left left right right root
// 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
n++
t[b.ID].entry = n
// to assign entry and exit numbers in the treewalk, those
// numbers are also consistent with this order (i.e.,
// 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
}
// Child returns a child of x in the dominator tree, or
// nil if there are none. The choice of first child is
// arbitrary but repeatable.
-func (t sparseTree) Child(x *Block) *Block {
+func (t SparseTree) Child(x *Block) *Block {
return t[x.ID].child
}
// 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 {
return true
}
}
// 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 {
return false
}
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
-// if x may dominate y, and false if x cannot dominate y.
-func (t sparseTree) maxdomorder(x *Block) int32 {
+// domorder returns a value for dominator-oriented sorting.
+// Block domination does not provide a total ordering,
+// 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
}
--- /dev/null
+// 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"
+
+// A SparseTreeMap encodes a subset of nodes within a tree
+// used for sparse-ancestor queries.
+//
+// Combined with a SparseTreeHelper, this supports an Insert
+// to add a tree node to the set and a Find operation to locate
+// the nearest tree ancestor of a given node such that the
+// ancestor is also in the set.
+//
+// Given a set of blocks {B1, B2, B3} within the dominator tree, established by
+// stm.Insert()ing B1, B2, B3, etc, a query at block B
+// (performed with stm.Find(stm, B, adjust, helper))
+// will return the member of the set that is the nearest strict
+// ancestor of B within the dominator tree, or nil if none exists.
+// The expected complexity of this operation is the log of the size
+// the set, given certain assumptions about sparsity (the log complexity
+// could be guaranteed with additional data structures whose constant-
+// factor overhead has not yet been justified.)
+//
+// The adjust parameter allows positioning of the insertion
+// and lookup points within a block -- one of
+// AdjustBefore, AdjustWithin, AdjustAfter,
+// where lookups at AdjustWithin can find insertions at
+// AdjustBefore in the same block, and lookups at AdjustAfter
+// can find insertions at either AdjustBefore or AdjustWithin
+// in the same block. (Note that this assumes a gappy numbering
+// such that exit number or exit number is separated from its
+// nearest neighbor by at least 3).
+//
+// The Sparse Tree lookup algorithm is described by
+// Paul F. Dietz. Maintaining order in a linked list. In
+// Proceedings of the Fourteenth Annual ACM Symposium on
+// Theory of Computing, pages 122–127, May 1982.
+// and by
+// Ben Wegbreit. Faster retrieval from context trees.
+// Communications of the ACM, 19(9):526–529, September 1976.
+type SparseTreeMap RBTint32
+
+// A SparseTreeHelper contains indexing and allocation data
+// structures common to a collection of SparseTreeMaps, as well
+// as exposing some useful control-flow-related data to other
+// packages, such as gc.
+type SparseTreeHelper struct {
+ Sdom []SparseTreeNode // indexed by block.ID
+ Po []*Block // exported data
+ Dom []*Block // exported data
+ Ponums []int32 // exported data
+}
+
+// NewSparseTreeHelper returns a SparseTreeHelper for use
+// in the gc package, for example in phi-function placement.
+func NewSparseTreeHelper(f *Func) *SparseTreeHelper {
+ dom := dominators(f)
+ ponums := make([]int32, f.NumBlocks())
+ po := postorderWithNumbering(f, ponums)
+ return makeSparseTreeHelper(newSparseTree(f, dom), dom, po, ponums)
+}
+
+func (h *SparseTreeHelper) NewTree() *SparseTreeMap {
+ return &SparseTreeMap{}
+}
+
+func makeSparseTreeHelper(sdom SparseTree, dom, po []*Block, ponums []int32) *SparseTreeHelper {
+ helper := &SparseTreeHelper{Sdom: []SparseTreeNode(sdom),
+ Dom: dom,
+ Po: po,
+ Ponums: ponums,
+ }
+ return helper
+}
+
+// A sparseTreeMapEntry contains the data stored in a binary search
+// data structure indexed by (dominator tree walk) entry and exit numbers.
+// Each entry is added twice, once keyed by entry-1/entry/entry+1 and
+// once keyed by exit+1/exit/exit-1. (there are three choices of paired indices, not 9, and they properly nest)
+type sparseTreeMapEntry struct {
+ index *SparseTreeNode
+ block *Block // TODO: store this in a separate index.
+ data interface{}
+}
+
+// Insert creates a definition within b with data x.
+// adjust indicates where in the block should be inserted:
+// AdjustBefore means defined at a phi function (visible Within or After in the same block)
+// AdjustWithin means defined within the block (visible After in the same block)
+// AdjustAfter means after the block (visible within child blocks)
+func (m *SparseTreeMap) Insert(b *Block, adjust int32, x interface{}, helper *SparseTreeHelper) {
+ rbtree := (*RBTint32)(m)
+ blockIndex := &helper.Sdom[b.ID]
+ if blockIndex.entry == 0 {
+ // assert unreachable
+ return
+ }
+ entry := &sparseTreeMapEntry{index: blockIndex, data: x}
+ right := blockIndex.exit - adjust
+ _ = rbtree.Insert(right, entry)
+
+ left := blockIndex.entry + adjust
+ _ = rbtree.Insert(left, entry)
+}
+
+// Find returns the definition visible from block b, or nil if none can be found.
+// Adjust indicates where the block should be searched.
+// AdjustBefore searches before the phi functions of b.
+// AdjustWithin searches starting at the phi functions of b.
+// AdjustAfter searches starting at the exit from the block, including normal within-block definitions.
+//
+// Note that Finds are properly nested with Inserts:
+// m.Insert(b, a) followed by m.Find(b, a) will not return the result of the insert,
+// but m.Insert(b, AdjustBefore) followed by m.Find(b, AdjustWithin) will.
+//
+// Another way to think of this is that Find searches for inputs, Insert defines outputs.
+func (m *SparseTreeMap) Find(b *Block, adjust int32, helper *SparseTreeHelper) interface{} {
+ rbtree := (*RBTint32)(m)
+ if rbtree == nil {
+ return nil
+ }
+ blockIndex := &helper.Sdom[b.ID]
+ _, v := rbtree.Glb(blockIndex.entry + adjust)
+ for v != nil {
+ otherEntry := v.(*sparseTreeMapEntry)
+ otherIndex := otherEntry.index
+ // Two cases -- either otherIndex brackets blockIndex,
+ // or it doesn't.
+ //
+ // Note that if otherIndex and blockIndex are
+ // the same block, then the glb test only passed
+ // because the definition is "before",
+ // i.e., k == blockIndex.entry-1
+ // allowing equality is okay on the blocks check.
+ if otherIndex.exit >= blockIndex.exit {
+ // bracketed.
+ return otherEntry.data
+ }
+ // In the not-bracketed case, we could memoize the results of
+ // walking up the tree, but for now we won't.
+ // Memoize plan is to take the gap (inclusive)
+ // from otherIndex.exit+1 to blockIndex.entry-1
+ // and insert it into this or a second tree.
+ // Said tree would then need adjusting whenever
+ // an insertion occurred.
+
+ // Expectation is that per-variable tree is sparse,
+ // therefore probe siblings instead of climbing up.
+ // Note that each sibling encountered in this walk
+ // to find a defining ancestor shares that ancestor
+ // because the walk skips over the interior -- each
+ // Glb will be an exit, and the iteration is to the
+ // Glb of the entry.
+ _, v = rbtree.Glb(otherIndex.entry - 1)
+ }
+ return nil // nothing found
+}
+
+func (m *SparseTreeMap) String() string {
+ tree := (*RBTint32)(m)
+ return tree.String()
+}
+
+func (e *sparseTreeMapEntry) String() string {
+ return fmt.Sprintf("index=%v, data=%v", e.index, e.data)
+}
s.stackalloc()
if f.pass.stats > 0 {
- f.logStat("stack_alloc_stats",
+ f.LogStat("stack_alloc_stats",
s.nArgSlot, "arg_slots", s.nNotNeed, "slot_not_needed",
s.nNamedSlot, "named_slots", s.nAuto, "auto_slots",
s.nReuse, "reused_slots", s.nSelfInterfere, "self_interfering")
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
} else {
gc.Regalloc(&r1, t, n1)
n = &n1
- case gc.ONAME:
- if n.Class == gc.PPARAMREF {
- var n1 gc.Node
- gc.Cgen(n.Name.Heapaddr, &n1)
- sclean[nsclean-1] = n1
- n = &n1
- }
-
+ case gc.ONAME, gc.OINDREG:
// nothing
- case gc.OINDREG:
- break
}
*lo = *n
}
}
if list != nil {
- comments = append(comments, &ast.CommentGroup{list})
+ comments = append(comments, &ast.CommentGroup{List: list})
}
}
return comments
}{
{"cmd/go", []string{
"zdefaultcc.go",
+ "zosarch.go",
}},
{"runtime/internal/sys", []string{
"zversion.go",
gen func(string, string)
}{
{"zdefaultcc.go", mkzdefaultcc},
+ {"zosarch.go", mkzosarch},
{"zversion.go", mkzversion},
{"zcgo.go", mkzcgo},
// It is invoked to write cmd/go/zdefaultcc.go
// but we also write cmd/cgo/zdefaultcc.go
func mkzdefaultcc(dir, file string) {
- var out string
-
- out = fmt.Sprintf(
+ out := fmt.Sprintf(
"// auto generated by go tool dist\n"+
"\n"+
"package main\n"+
writefile(out, file, writeSkipSame)
}
-// mkzcgo writes zcgo.go for go/build package:
+// mkzcgo writes zosarch.go for cmd/go.
+func mkzosarch(dir, file string) {
+ var buf bytes.Buffer
+ buf.WriteString("// auto generated by go tool dist\n\n")
+ buf.WriteString("package main\n\n")
+ fmt.Fprintf(&buf, "var osArchSupportsCgo = %#v", cgoEnabled)
+ writefile(buf.String(), file, writeSkipSame)
+}
+
+// mkzcgo writes zcgo.go for the go/build package:
//
// package build
// var cgoEnabled = map[string]bool{}
}
return false
default:
- log.Fatal("internal error: unknown buildmode %s", mode)
+ log.Fatalf("internal error: unknown buildmode %s", mode)
return false
}
}
Stale bool // would 'go install' do anything for this package?
StaleReason string // explanation for Stale==true
Root string // Go root or Go path dir containing this package
+ ConflictDir string // this directory shadows Dir in $GOPATH
+ BinaryOnly bool // binary-only package: cannot be recompiled from sources
// Source files
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
Test files that declare a package with the suffix "_test" will be compiled as a
separate package, and then linked and run with the main test binary.
+The go tool will ignore a directory named "testdata", making it available
+to hold ancillary data needed by the tests.
+
By default, go test needs no arguments. It compiles and tests the package
with source in the current directory, including tests, and runs the tests.
Files of each of these types except .syso may contain build
constraints, but the go command stops scanning for build constraints
at the first item in the file that is not a blank line or //-style
-line comment.
+line comment. See the go/build package documentation for
+more details.
+
+Non-test Go source files can also include a //go:binary-only-package
+comment, indicating that the package sources are included
+for documentation only and must not be used to build the
+package binary. This enables distribution of Go packages in
+their compiled form alone. See the go/build package documentation
+for more details.
GOPATH environment variable
-trace trace.out
Write an execution trace to the specified file before exiting.
- Writes test binary as -c would.
-v
Verbose output: log all tests as they are run. Also print all
return p
}
switch platform {
- case "darwin/arm":
+ case "darwin/arm", "darwin/arm64":
codegenArg = "-shared"
default:
}
case "android/arm", "android/arm64", "android/amd64", "android/386":
codegenArg = "-shared"
ldBuildmode = "pie"
+ case "darwin/arm", "darwin/arm64":
+ codegenArg = "-shared"
+ fallthrough
default:
ldBuildmode = "exe"
}
func init() {
goarch = buildContext.GOARCH
goos = buildContext.GOOS
+
+ if _, ok := osArchSupportsCgo[goos+"/"+goarch]; !ok {
+ fmt.Fprintf(os.Stderr, "cmd/go: unsupported GOOS/GOARCH pair %s/%s\n", goos, goarch)
+ os.Exit(2)
+ }
+
if goos == "windows" {
exeSuffix = ".exe"
}
return []string{"-marm"} // not thumb
case "s390x":
return []string{"-m64", "-march=z196"}
+ case "mips64", "mips64le":
+ return []string{"-mabi=64"}
}
return nil
}
}
}
-// resetReadOnlyFlagAll resets windows read-only flag
-// set on path and any children it contains.
-// The flag is set by git and has to be removed.
-// os.Remove refuses to remove files with read-only flag set.
-func (tg *testgoData) resetReadOnlyFlagAll(path string) {
- fi, err := os.Stat(path)
- if err != nil {
- tg.t.Fatalf("resetReadOnlyFlagAll(%q) failed: %v", path, err)
- }
- if !fi.IsDir() {
- err := os.Chmod(path, 0666)
- if err != nil {
- tg.t.Fatalf("resetReadOnlyFlagAll(%q) failed: %v", path, err)
- }
- }
- fd, err := os.Open(path)
- if err != nil {
- tg.t.Fatalf("resetReadOnlyFlagAll(%q) failed: %v", path, err)
- }
- defer fd.Close()
- names, _ := fd.Readdirnames(-1)
- for _, name := range names {
- tg.resetReadOnlyFlagAll(path + string(filepath.Separator) + name)
- }
-}
-
// failSSH puts an ssh executable in the PATH that always fails.
// This is to stub out uses of ssh by go get.
func (tg *testgoData) failSSH() {
tg.grepStderr("found import comments", "go build did not mention comment conflict")
}
-// cmd/go: custom import path checking should not apply to github.com/xxx/yyy.
+// cmd/go: custom import path checking should not apply to Go packages without import comment.
func TestIssue10952(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
if _, err := exec.LookPath("git"); err != nil {
const importPath = "github.com/zombiezen/go-get-issue-10952"
tg.run("get", "-d", "-u", importPath)
repoDir := tg.path("src/" + importPath)
- defer tg.resetReadOnlyFlagAll(repoDir)
tg.runGit(repoDir, "remote", "set-url", "origin", "https://"+importPath+".git")
tg.run("get", "-d", "-u", importPath)
}
+// Test git clone URL that uses SCP-like syntax and custom import path checking.
+func TestIssue11457(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+ if _, err := exec.LookPath("git"); err != nil {
+ t.Skip("skipping because git binary not found")
+ }
+
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.tempDir("src")
+ tg.setenv("GOPATH", tg.path("."))
+ const importPath = "github.com/rsc/go-get-issue-11457"
+ tg.run("get", "-d", "-u", importPath)
+ repoDir := tg.path("src/" + importPath)
+ tg.runGit(repoDir, "remote", "set-url", "origin", "git@github.com:rsc/go-get-issue-11457")
+
+ // At this time, custom import path checking compares remotes verbatim (rather than
+ // just the host and path, skipping scheme and user), so we expect go get -u to fail.
+ // However, the goal of this test is to verify that gitRemoteRepo correctly parsed
+ // the SCP-like syntax, and we expect it to appear in the error message.
+ tg.runFail("get", "-d", "-u", importPath)
+ want := " is checked out from ssh://git@github.com/rsc/go-get-issue-11457"
+ if !strings.HasSuffix(strings.TrimSpace(tg.getStderr()), want) {
+ t.Error("expected clone URL to appear in stderr")
+ }
+}
+
func TestGetGitDefaultBranch(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
if _, err := exec.LookPath("git"); err != nil {
tg.run("get", "-d", importPath)
repoDir := tg.path("src/" + importPath)
- defer tg.resetReadOnlyFlagAll(repoDir)
tg.runGit(repoDir, "branch", "--contains", "HEAD")
tg.grepStdout(`\* another-branch`, "not on correct default branch")
os.Remove(tg.path("src/p1/p1.go"))
tg.mustNotExist(tg.path("src/p1/p1.go"))
- tg.tempFile("src/p2/p2.go", `
+ tg.tempFile("src/p2/p2.go", `//go:binary-only-packages-are-not-great
+
package p2
import "p1"
func F() { p1.F(true) }
tg.grepStderr("no buildable Go source files", "did not complain about missing sources")
tg.tempFile("src/p1/missing.go", `//go:binary-only-package
-
+
package p1
func G()
`)
// or even the first few megabytes of the file
// due to differences in note segment placement;
// in that case, extract the note data manually.
- _, err = f.Seek(int64(p.Off), 0)
+ _, err = f.Seek(int64(p.Off), io.SeekStart)
if err != nil {
return "", err
}
Test files that declare a package with the suffix "_test" will be compiled as a
separate package, and then linked and run with the main test binary.
+The go tool will ignore a directory named "testdata", making it available
+to hold ancillary data needed by the tests.
+
By default, go test needs no arguments. It compiles and tests the package
with source in the current directory, including tests, and runs the tests.
// Eg, "git@github.com:user/repo" becomes
// "ssh://git@github.com/user/repo".
repoURL = &url.URL{
- Scheme: "ssh",
- User: url.User(m[1]),
- Host: m[2],
- RawPath: m[3],
+ Scheme: "ssh",
+ User: url.User(m[1]),
+ Host: m[2],
+ Path: m[3],
}
} else {
repoURL, err = url.Parse(out)
repo: "https://{root}",
},
+ // Git at OpenStack
+ {
+ prefix: "git.openstack.org",
+ re: `^(?P<root>git\.openstack\.org/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(\.git)?(/[A-Za-z0-9_.\-]+)*$`,
+ vcs: "git",
+ repo: "https://{root}",
+ check: noVCSSuffix,
+ },
+
// General syntax for any server.
// Must be last.
{
"hub.jazz.net/git/USER/pkgname",
nil,
},
+ // OpenStack tests
+ {
+ "git.openstack.org/openstack/swift",
+ &repoRoot{
+ vcs: vcsGit,
+ repo: "https://git.openstack.org/openstack/swift",
+ },
+ },
+ // Trailing .git is less preferred but included for
+ // compatibility purposes while the same source needs to
+ // be compilable on both old and new go
+ {
+ "git.openstack.org/openstack/swift.git",
+ &repoRoot{
+ vcs: vcsGit,
+ repo: "https://git.openstack.org/openstack/swift",
+ },
+ },
+ {
+ "git.openstack.org/openstack/swift/go/hummingbird",
+ &repoRoot{
+ vcs: vcsGit,
+ repo: "https://git.openstack.org/openstack/swift",
+ },
+ },
+ {
+ "git.openstack.org",
+ nil,
+ },
+ {
+ "git.openstack.org/openstack",
+ nil,
+ },
// Spaces are not valid in package name
{
"git.apache.org/package name/path/to/lib",
func (r *objReader) init(f io.ReadSeeker, p *Package) {
r.f = f
r.p = p
- r.offset, _ = f.Seek(0, 1)
- r.limit, _ = f.Seek(0, 2)
- f.Seek(r.offset, 0)
+ r.offset, _ = f.Seek(0, io.SeekCurrent)
+ r.limit, _ = f.Seek(0, io.SeekEnd)
+ f.Seek(r.offset, io.SeekStart)
r.b = bufio.NewReader(f)
r.pkgprefix = importPathToPrefix(p.ImportPath) + "."
}
r.readFull(r.tmp[:n])
} else {
// Seek, giving up buffered data.
- _, err := r.f.Seek(r.offset+n, 0)
+ _, err := r.f.Seek(r.offset+n, io.SeekStart)
if err != nil {
r.error(err)
}
// go-specific code shared across loaders (5l, 6l, 8l).
var (
- Framepointer_enabled int
+ framepointer_enabled int
Fieldtrack_enabled int
)
val *int
}{
{"fieldtrack", &Fieldtrack_enabled},
- {"framepointer", &Framepointer_enabled},
+ {"framepointer", &framepointer_enabled},
}
func addexp(s string) {
+ // Could do general integer parsing here, but the runtime copy doesn't yet.
+ v := 1
+ name := s
+ if len(name) > 2 && name[:2] == "no" {
+ v = 0
+ name = name[2:]
+ }
for i := 0; i < len(exper); i++ {
- if exper[i].name == s {
+ if exper[i].name == name {
if exper[i].val != nil {
- *exper[i].val = 1
+ *exper[i].val = v
}
return
}
}
func init() {
+ framepointer_enabled = 1 // default
for _, f := range strings.Split(goexperiment, ",") {
if f != "" {
addexp(f)
}
}
+func Framepointer_enabled(goos, goarch string) bool {
+ return framepointer_enabled != 0 && goarch == "amd64" && goos != "nacl"
+}
+
func Nopout(p *Prog) {
p.As = ANOP
p.Scond = 0
Etextp *LSym
Errors int
+ Framepointer_enabled bool
+
// state for writing objects
Text []*LSym
Data []*LSym
}
ctxt.Flag_optimize = true
+ ctxt.Framepointer_enabled = Framepointer_enabled(Getgoos(), arch.Name)
return ctxt
}
fmt.Fprintf(&buf, "%.5d (%v)\t%v%s", p.Pc, p.Line(), Aconv(p.As), sc)
sep := "\t"
+ quadOpAmd64 := p.RegTo2 == -1
+ if quadOpAmd64 {
+ fmt.Fprintf(&buf, "%s$%d", sep, p.From3.Offset)
+ sep = ", "
+ }
if p.From.Type != TYPE_NONE {
fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.From))
sep = ", "
if p.From3.Type == TYPE_CONST && (p.As == ATEXT || p.As == AGLOBL) {
// Special case - omit $.
fmt.Fprintf(&buf, "%s%d", sep, p.From3.Offset)
+ } else if quadOpAmd64 {
+ fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.From3.Reg)))
} else {
fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, p.From3))
}
if p.To.Type != TYPE_NONE {
fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.To))
}
- if p.RegTo2 != REG_NONE {
+ if p.RegTo2 != REG_NONE && !quadOpAmd64 {
fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.RegTo2)))
}
return buf.String()
AVPAND
AVPTEST
AVPBROADCASTB
+ AVPSHUFB
+ AVPSHUFD
+ AVPERM2F128
+ AVPALIGNR
+ AVPADDQ
+ AVPADDD
+ AVPSRLDQ
+ AVPSLLDQ
+ AVPSRLQ
+ AVPSLLQ
+ AVPSRLD
+ AVPSLLD
+ AVPOR
+ AVPBLENDD
+ AVINSERTI128
+ AVPERM2I128
+ ARORXL
+ ARORXQ
// from 386
AJCXZW
"VPAND",
"VPTEST",
"VPBROADCASTB",
+ "VPSHUFB",
+ "VPSHUFD",
+ "VPERM2F128",
+ "VPALIGNR",
+ "VPADDQ",
+ "VPADDD",
+ "VPSRLDQ",
+ "VPSLLDQ",
+ "VPSRLQ",
+ "VPSLLQ",
+ "VPSRLD",
+ "VPSLLD",
+ "VPOR",
+ "VPBLENDD",
+ "VINSERTI128",
+ "VPERM2I128",
+ "RORXL",
+ "RORXQ",
"JCXZW",
"FCMOVCC",
"FCMOVCS",
Zvex_rm_v_r
Zvex_r_v_rm
Zvex_v_rm_r
+ Zvex_i_rm_r
+ Zvex_i_r_v
+ Zvex_i_rm_v_r
Zmax
)
{Yym, Yyr, Yyr, Zvex_rm_v_r, 2},
}
+var yvex_ri3 = []ytab{
+ {Yi8, Ymb, Yrl, Zvex_i_rm_r, 2},
+}
+
+var yvex_xyi3 = []ytab{
+ {Yi8, Yxm, Yxr, Zvex_i_rm_r, 2},
+ {Yi8, Yym, Yyr, Zvex_i_rm_r, 2},
+}
+
+var yvex_yyi4 = []ytab{ //TODO don't hide 4 op, some version have xmm version
+ {Yym, Yyr, Yyr, Zvex_i_rm_v_r, 2},
+}
+
+var yvex_xyi4 = []ytab{
+ {Yxm, Yyr, Yyr, Zvex_i_rm_v_r, 2},
+}
+
+var yvex_shift = []ytab{
+ {Yi8, Yxr, Yxr, Zvex_i_r_v, 3},
+ {Yi8, Yyr, Yyr, Zvex_i_r_v, 3},
+ {Yxm, Yxr, Yxr, Zvex_rm_v_r, 2},
+ {Yxm, Yyr, Yyr, Zvex_rm_v_r, 2},
+}
+
+var yvex_shift_dq = []ytab{
+ {Yi8, Yxr, Yxr, Zvex_i_r_v, 3},
+ {Yi8, Yyr, Yyr, Zvex_i_r_v, 3},
+}
+
var yvex_r3 = []ytab{
{Yml, Yrl, Yrl, Zvex_rm_v_r, 2},
{Yml, Yrl, Yrl, Zvex_rm_v_r, 2},
{AVPAND, yvex_xy3, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0xDB, VEX_256_66_0F_WIG, 0xDB}},
{AVPBROADCASTB, yvex_vpbroadcast, Pvex, [23]uint8{VEX_128_66_0F38_W0, 0x78, VEX_256_66_0F38_W0, 0x78}},
{AVPTEST, yvex_xy2, Pvex, [23]uint8{VEX_128_66_0F38_WIG, 0x17, VEX_256_66_0F38_WIG, 0x17}},
+ {AVPSHUFB, yvex_xy3, Pvex, [23]uint8{VEX_128_66_0F38_WIG, 0x00, VEX_256_66_0F38_WIG, 0x00}},
+ {AVPSHUFD, yvex_xyi3, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0x70, VEX_256_66_0F_WIG, 0x70}},
+ {AVPOR, yvex_xy3, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0xeb, VEX_256_66_0F_WIG, 0xeb}},
+ {AVPADDQ, yvex_xy3, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0xd4, VEX_256_66_0F_WIG, 0xd4}},
+ {AVPADDD, yvex_xy3, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0xfe, VEX_256_66_0F_WIG, 0xfe}},
+ {AVPSLLD, yvex_shift, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0x72, 0xf0, VEX_256_66_0F_WIG, 0x72, 0xf0, VEX_128_66_0F_WIG, 0xf2, VEX_256_66_0F_WIG, 0xf2}},
+ {AVPSLLQ, yvex_shift, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0x73, 0xf0, VEX_256_66_0F_WIG, 0x73, 0xf0, VEX_128_66_0F_WIG, 0xf3, VEX_256_66_0F_WIG, 0xf3}},
+ {AVPSRLD, yvex_shift, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0x72, 0xd0, VEX_256_66_0F_WIG, 0x72, 0xd0, VEX_128_66_0F_WIG, 0xd2, VEX_256_66_0F_WIG, 0xd2}},
+ {AVPSRLQ, yvex_shift, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0x73, 0xd0, VEX_256_66_0F_WIG, 0x73, 0xd0, VEX_128_66_0F_WIG, 0xd3, VEX_256_66_0F_WIG, 0xd3}},
+ {AVPSRLDQ, yvex_shift_dq, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0x73, 0xd8, VEX_256_66_0F_WIG, 0x73, 0xd8}},
+ {AVPSLLDQ, yvex_shift_dq, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0x73, 0xf8, VEX_256_66_0F_WIG, 0x73, 0xf8}},
+ {AVPERM2F128, yvex_yyi4, Pvex, [23]uint8{VEX_256_66_0F3A_W0, 0x06}},
+ {AVPALIGNR, yvex_yyi4, Pvex, [23]uint8{VEX_256_66_0F3A_WIG, 0x0f}},
+ {AVPBLENDD, yvex_yyi4, Pvex, [23]uint8{VEX_256_66_0F3A_WIG, 0x02}},
+ {AVINSERTI128, yvex_xyi4, Pvex, [23]uint8{VEX_256_66_0F3A_WIG, 0x38}},
+ {AVPERM2I128, yvex_yyi4, Pvex, [23]uint8{VEX_256_66_0F3A_WIG, 0x46}},
+ {ARORXL, yvex_ri3, Pvex, [23]uint8{VEX_LZ_F2_0F3A_W0, 0xf0}},
+ {ARORXQ, yvex_ri3, Pvex, [23]uint8{VEX_LZ_F2_0F3A_W1, 0xf0}},
{AXACQUIRE, ynone, Px, [23]uint8{0xf2}},
{AXRELEASE, ynone, Px, [23]uint8{0xf3}},
// https://en.wikipedia.org/wiki/VEX_prefix#Technical_description
func asmvex(ctxt *obj.Link, rm, v, r *obj.Addr, vex, opcode uint8) {
ctxt.Vexflag = 1
- rexR := regrex[r.Reg] & Rxr
- rexB := regrex[rm.Reg] & Rxb
- rexX := regrex[rm.Index] & Rxx
+ rexR := 0
+ if r != nil {
+ rexR = regrex[r.Reg] & Rxr
+ }
+ rexB := 0
+ rexX := 0
+ if rm != nil {
+ rexB = regrex[rm.Reg] & Rxb
+ rexX = regrex[rm.Index] & Rxx
+ }
vexM := (vex >> 3) & 0xF
vexWLP := vex & 0x87
vexV := byte(0)
asmvex(ctxt, &p.From, p.From3, &p.To, o.op[z], o.op[z+1])
asmand(ctxt, p, &p.From, &p.To)
+ case Zvex_i_r_v:
+ asmvex(ctxt, p.From3, &p.To, nil, o.op[z], o.op[z+1])
+ regnum := byte(0x7)
+ if p.From3.Reg >= REG_X0 && p.From3.Reg <= REG_X15 {
+ regnum &= byte(p.From3.Reg - REG_X0)
+ } else {
+ regnum &= byte(p.From3.Reg - REG_Y0)
+ }
+ ctxt.AsmBuf.Put1(byte(o.op[z+2]) | regnum)
+ ctxt.AsmBuf.Put1(byte(p.From.Offset))
+
+ case Zvex_i_rm_v_r:
+ asmvex(ctxt, &p.From, p.From3, &p.To, o.op[z], o.op[z+1])
+ asmand(ctxt, p, &p.From, &p.To)
+ ctxt.AsmBuf.Put1(byte(p.From3.Offset))
+
+ case Zvex_i_rm_r:
+ asmvex(ctxt, p.From3, nil, &p.To, o.op[z], o.op[z+1])
+ asmand(ctxt, p, p.From3, &p.To)
+ ctxt.AsmBuf.Put1(byte(p.From.Offset))
+
case Zvex_v_rm_r:
asmvex(ctxt, p.From3, &p.From, &p.To, o.op[z], o.op[z+1])
asmand(ctxt, p, p.From3, &p.To)
ctxt.Diag("directly calling duff when dynamically linking Go")
}
- if obj.Framepointer_enabled != 0 && yt.zcase == Zcallduff && p.Mode == 64 {
+ if ctxt.Framepointer_enabled && yt.zcase == Zcallduff && p.Mode == 64 {
// Maintain BP around call, since duffcopy/duffzero can't do it
// (the call jumps into the middle of the function).
// This makes it possible to see call sites for duffcopy/duffzero in
r.Siz = 4
ctxt.AsmBuf.PutInt32(0)
- if obj.Framepointer_enabled != 0 && yt.zcase == Zcallduff && p.Mode == 64 {
+ if ctxt.Framepointer_enabled && yt.zcase == Zcallduff && p.Mode == 64 {
// Pop BP pushed above.
// MOVQ 0(BP), BP
ctxt.AsmBuf.Put(bpduff2)
}
var bpsize int
- if p.Mode == 64 && obj.Framepointer_enabled != 0 && autoffset > 0 {
+ if p.Mode == 64 && ctxt.Framepointer_enabled && autoffset > 0 && p.From3.Offset&obj.NOFRAME == 0 {
// Make room for to save a base pointer. If autoffset == 0,
// this might do something special like a tail jump to
// another function, so in that case we omit this.
bpsize = ctxt.Arch.PtrSize
-
autoffset += int32(bpsize)
p.To.Offset += int64(bpsize)
} else {
"strings"
"text/tabwriter"
- "cmd/internal/unvendor/golang.org/x/arch/arm/armasm"
- "cmd/internal/unvendor/golang.org/x/arch/x86/x86asm"
+ "golang.org/x/arch/arm/armasm"
+ "golang.org/x/arch/x86/x86asm"
)
// Disasm is a disassembler for a given File.
if err != nil {
return err
}
+ tempfile.DeferDelete(name)
vizTmpDir = name
return nil
}
// offset to adjust the sample addresses.
func annotateAssembly(insns []plugin.Inst, samples nodes, base uint64) nodes {
// Add end marker to simplify printing loop.
- insns = append(insns, plugin.Inst{^uint64(0), "", "", 0})
+ insns = append(insns, plugin.Inst{
+ Addr: ^uint64(0),
+ })
// Ensure samples are sorted by address.
samples.sort(addressOrder)
var tempFiles []string
var tempFilesMu = sync.Mutex{}
-// DeferDelete marks a file to be deleted by next call to Cleanup()
+// DeferDelete marks a file or directory to be deleted by next call to Cleanup.
func DeferDelete(path string) {
tempFilesMu.Lock()
tempFiles = append(tempFiles, path)
tempFilesMu.Unlock()
}
-// Cleanup removes any temporary files selected for deferred cleaning.
+// Cleanup removes any temporary files or directories selected for deferred cleaning.
+// Similar to defer semantics, the nodes are deleted in LIFO order.
func Cleanup() {
tempFilesMu.Lock()
- for _, f := range tempFiles {
- os.Remove(f)
+ for i := len(tempFiles) - 1; i >= 0; i-- {
+ os.Remove(tempFiles[i])
}
tempFiles = nil
tempFilesMu.Unlock()
if !haslinkregister() {
offs -= int64(SysArch.PtrSize)
}
+ if obj.Framepointer_enabled(obj.Getgoos(), obj.Getgoarch()) {
+ // The frame pointer is saved
+ // between the CFA and the
+ // autos.
+ offs -= int64(SysArch.PtrSize)
+ }
case obj.A_PARAM:
dt = DW_ABRV_PARAM
Addaddr(ctxt, d, s)
}
- /* size */
- Adduint32(ctxt, d, 0)
+ /* size of object */
+ Adduint32(ctxt, d, uint32(s.Size))
/* type */
t := STB_GLOBAL << 4
}
data := string(bdata)
- // first \n$$ marks beginning of exports - skip rest of line
- p0 = strings.Index(data, "\n$$")
- if p0 < 0 {
- if Debug['u'] != 0 && whence != ArchiveObj {
- Exitf("cannot find export data in %s", filename)
- }
- return
- }
-
- // \n$$B marks the beginning of binary export data - don't skip over the B
- p0 += 3
- for p0 < len(data) && data[p0] != '\n' && data[p0] != 'B' {
- p0++
- }
-
- // second marks end of exports / beginning of local data
- p1 = strings.Index(data[p0:], "\n$$\n")
- if p1 < 0 && whence == Pkgdef {
- p1 = len(data) - p0
- }
- if p1 < 0 {
- fmt.Fprintf(os.Stderr, "%s: cannot find end of exports in %s\n", os.Args[0], filename)
- if Debug['u'] != 0 {
- errorexit()
- }
- return
- }
- p1 += p0
-
- for p0 < p1 && data[p0] != 'B' && (data[p0] == ' ' || data[p0] == '\t' || data[p0] == '\n') {
- p0++
- }
- // don't check this section if we have binary (B) export data
- // TODO fix this eventually
- if p0 < p1 && data[p0] != 'B' {
- if !strings.HasPrefix(data[p0:], "package ") {
- fmt.Fprintf(os.Stderr, "%s: bad package section in %s - %.20s\n", os.Args[0], filename, data[p0:])
- if Debug['u'] != 0 {
- errorexit()
- }
- return
+ // process header lines
+ isSafe := false
+ isMain := false
+ for data != "" {
+ var line string
+ if i := strings.Index(data, "\n"); i >= 0 {
+ line, data = data[:i], data[i+1:]
+ } else {
+ line, data = data, ""
}
-
- p0 += 8
- for p0 < p1 && (data[p0] == ' ' || data[p0] == '\t' || data[p0] == '\n') {
- p0++
+ if line == "safe" {
+ isSafe = true
}
- pname := p0
- for p0 < p1 && data[p0] != ' ' && data[p0] != '\t' && data[p0] != '\n' {
- p0++
+ if line == "main" {
+ isMain = true
}
- if Debug['u'] != 0 && whence != ArchiveObj && (p0+6 > p1 || !strings.HasPrefix(data[p0:], " safe\n")) {
- Exitf("load of unsafe package %s", filename)
+ if line == "" {
+ break
}
+ }
- name := data[pname:p0]
- for p0 < p1 && data[p0] != '\n' {
- p0++
+ if whence == Pkgdef || whence == FileObj {
+ if pkg == "main" && !isMain {
+ Exitf("%s: not package main", filename)
}
- if p0 < p1 {
- p0++
- }
-
- if pkg == "main" && name != "main" {
- Exitf("%s: not package main (package %s)", filename, name)
+ if Debug['u'] != 0 && whence != ArchiveObj && !isSafe {
+ Exitf("load of unsafe package %s", filename)
}
}
}
// look for cgo section
- p0 = strings.Index(data[p1:], "\n$$ // cgo")
+ p0 = strings.Index(data, "\n$$ // cgo")
if p0 >= 0 {
p0 += p1
i := strings.IndexByte(data[p0+1:], '\n')
// recording the value of GOARM.
if SysArch.Family == sys.ARM {
s := Linklookup(Ctxt, "runtime.goarm", 0)
-
s.Type = obj.SRODATA
s.Size = 0
Adduint8(Ctxt, s, uint8(Ctxt.Goarm))
}
+
+ if obj.Framepointer_enabled(obj.Getgoos(), obj.Getgoarch()) {
+ s := Linklookup(Ctxt, "runtime.framepointer_enabled", 0)
+ s.Type = obj.SRODATA
+ s.Size = 0
+ Adduint8(Ctxt, s, 1)
+ }
} else {
// If OTOH the module does not contain the runtime package,
// create a local symbol for the moduledata.
//
// In both cases, switch to gold.
argv = append(argv, "-fuse-ld=gold")
+
+ // If gold is not installed, gcc will silently switch
+ // back to ld.bfd. So we parse the version information
+ // and provide a useful error if gold is missing.
+ cmd := exec.Command(extld, "-fuse-ld=gold", "-Wl,--version")
+ if out, err := cmd.CombinedOutput(); err == nil {
+ if !bytes.Contains(out, []byte("GNU gold")) {
+ log.Fatalf("ARM external linker must be gold (issue #15696), but is not: %s", out)
+ }
+ }
}
}
origName = make([]byte, n)
r.readFull(origName)
} else if err != nil {
- log.Fatalf("%s: error reading symbol: %v", err)
+ log.Fatalf("%s: error reading symbol: %v", r.pn, err)
}
adjName := r.rdBuf[:0]
for {
log.Fatal("short file")
}
if entry.size&1 == 1 {
- _, err := ar.fd.Seek(1, 1)
+ _, err := ar.fd.Seek(1, io.SeekCurrent)
if err != nil {
log.Fatal(err)
}
if size&1 == 1 {
size++
}
- _, err := ar.fd.Seek(size, 1)
+ _, err := ar.fd.Seek(size, io.SeekCurrent)
if err != nil {
log.Fatal(err)
}
"bufio"
"flag"
"fmt"
+ "html/template"
"internal/trace"
+ "log"
"net"
"net/http"
"os"
if err != nil {
dief("failed to create server socket: %v\n", err)
}
- // Open browser.
+
+ log.Printf("Parsing trace...")
+ events, err := parseEvents()
+ if err != nil {
+ dief("%v\n", err)
+ }
+
+ log.Printf("Serializing trace...")
+ params := &traceParams{
+ events: events,
+ endTime: int64(1<<63 - 1),
+ }
+ data := generateTrace(params)
+
+ log.Printf("Splitting trace...")
+ ranges = splitTrace(data)
+
+ log.Printf("Opening browser")
if !startBrowser("http://" + ln.Addr().String()) {
fmt.Fprintf(os.Stderr, "Trace viewer is listening on http://%s\n", ln.Addr().String())
}
- // Parse and symbolize trace asynchronously while browser opens.
- go parseEvents()
-
// Start http server.
http.HandleFunc("/", httpMain)
err = http.Serve(ln, nil)
dief("failed to start http server: %v\n", err)
}
+var ranges []Range
+
var loader struct {
once sync.Once
events []*trace.Event
// httpMain serves the starting page.
func httpMain(w http.ResponseWriter, r *http.Request) {
- w.Write(templMain)
+ if err := templMain.Execute(w, ranges); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
}
-var templMain = []byte(`
+var templMain = template.Must(template.New("").Parse(`
<html>
<body>
-<a href="/trace">View trace</a><br>
+{{if $}}
+ {{range $e := $}}
+ <a href="/trace?start={{$e.Start}}&end={{$e.End}}">View trace ({{$e.Name}})</a><br>
+ {{end}}
+ <br>
+{{else}}
+ <a href="/trace">View trace</a><br>
+{{end}}
<a href="/goroutines">Goroutine analysis</a><br>
<a href="/io">Network blocking profile</a><br>
<a href="/block">Synchronization blocking profile</a><br>
<a href="/sched">Scheduler latency profile</a><br>
</body>
</html>
-`)
+`))
// startBrowser tries to open the URL in a browser
// and reports whether it succeeds.
"runtime"
"strconv"
"strings"
+ "time"
)
func init() {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
-
- params := ""
- if goids := r.FormValue("goid"); goids != "" {
- goid, err := strconv.ParseUint(goids, 10, 64)
- if err != nil {
- http.Error(w, fmt.Sprintf("failed to parse goid parameter '%v': %v", goids, err), http.StatusInternalServerError)
- return
- }
- params = fmt.Sprintf("?goid=%v", goid)
+ if err := r.ParseForm(); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
}
- html := strings.Replace(templTrace, "{{PARAMS}}", params, -1)
+ html := strings.Replace(templTrace, "{{PARAMS}}", r.Form.Encode(), -1)
w.Write([]byte(html))
}
viewer.globalMode = true;
document.body.appendChild(viewer);
- url = '/jsontrace{{PARAMS}}';
+ url = '/jsontrace?{{PARAMS}}';
load();
});
}());
}
if goids := r.FormValue("goid"); goids != "" {
+ // If goid argument is present, we are rendering a trace for this particular goroutine.
goid, err := strconv.ParseUint(goids, 10, 64)
if err != nil {
log.Printf("failed to parse goid parameter '%v': %v", goids, err)
params.gs = trace.RelatedGoroutines(events, goid)
}
- err = json.NewEncoder(w).Encode(generateTrace(params))
+ data := generateTrace(params)
+
+ if startStr, endStr := r.FormValue("start"), r.FormValue("end"); startStr != "" && endStr != "" {
+ // If start/end arguments are present, we are rendering a range of the trace.
+ start, err := strconv.ParseUint(startStr, 10, 64)
+ if err != nil {
+ log.Printf("failed to parse start parameter '%v': %v", startStr, err)
+ return
+ }
+ end, err := strconv.ParseUint(endStr, 10, 64)
+ if err != nil {
+ log.Printf("failed to parse end parameter '%v': %v", endStr, err)
+ return
+ }
+ if start >= uint64(len(data.Events)) || end <= start || end > uint64(len(data.Events)) {
+ log.Printf("bogus start/end parameters: %v/%v, trace size %v", start, end, len(data.Events))
+ return
+ }
+ data.Events = append(data.Events[start:end], data.Events[data.footer:]...)
+ }
+ err = json.NewEncoder(w).Encode(data)
if err != nil {
log.Printf("failed to serialize trace: %v", err)
return
}
}
+type Range struct {
+ Name string
+ Start int
+ End int
+}
+
+// splitTrace splits the trace into a number of ranges,
+// each resulting in approx 100MB of json output (trace viewer can hardly handle more).
+func splitTrace(data ViewerData) []Range {
+ const rangeSize = 100 << 20
+ var ranges []Range
+ cw := new(countingWriter)
+ enc := json.NewEncoder(cw)
+ // First calculate size of the mandatory part of the trace.
+ // This includes stack traces and thread names.
+ data1 := data
+ data1.Events = data.Events[data.footer:]
+ enc.Encode(data1)
+ auxSize := cw.size
+ cw.size = 0
+ // Then calculate size of each individual event and group them into ranges.
+ for i, start := 0, 0; i < data.footer; i++ {
+ enc.Encode(data.Events[i])
+ if cw.size+auxSize > rangeSize || i == data.footer-1 {
+ ranges = append(ranges, Range{
+ Name: fmt.Sprintf("%v-%v", time.Duration(data.Events[start].Time*1000), time.Duration(data.Events[i].Time*1000)),
+ Start: start,
+ End: i + 1,
+ })
+ start = i + 1
+ cw.size = 0
+ }
+ }
+ if len(ranges) == 1 {
+ ranges = nil
+ }
+ return ranges
+}
+
+type countingWriter struct {
+ size int
+}
+
+func (cw *countingWriter) Write(data []byte) (int, error) {
+ cw.size += len(data)
+ return len(data), nil
+}
+
type traceParams struct {
events []*trace.Event
gtrace bool
Events []*ViewerEvent `json:"traceEvents"`
Frames map[string]ViewerFrame `json:"stackFrames"`
TimeUnit string `json:"displayTimeUnit"`
+
+ // This is where mandatory part of the trace starts (e.g. thread names)
+ footer int
}
type ViewerEvent struct {
}
}
+ ctx.data.footer = len(ctx.data.Events)
ctx.emit(&ViewerEvent{Name: "process_name", Phase: "M", Pid: 0, Arg: &NameArg{"PROCS"}})
ctx.emit(&ViewerEvent{Name: "process_sort_index", Phase: "M", Pid: 0, Arg: &SortIndexArg{1}})
func (f *File) checkPrint(call *ast.CallExpr, name string) {
firstArg := 0
typ := f.pkg.types[call.Fun].Type
- if typ != nil {
- if sig, ok := typ.(*types.Signature); ok {
- if !sig.Variadic() {
- // Skip checking non-variadic functions.
- return
- }
- params := sig.Params()
- firstArg = params.Len() - 1
-
- typ := params.At(firstArg).Type()
- typ = typ.(*types.Slice).Elem()
- it, ok := typ.(*types.Interface)
- if !ok || !it.Empty() {
- // Skip variadic functions accepting non-interface{} args.
- return
- }
+ if typ == nil {
+ // Skip checking functions with unknown type.
+ return
+ }
+ if sig, ok := typ.(*types.Signature); ok {
+ if !sig.Variadic() {
+ // Skip checking non-variadic functions.
+ return
+ }
+ params := sig.Params()
+ firstArg = params.Len() - 1
+
+ typ := params.At(firstArg).Type()
+ typ = typ.(*types.Slice).Elem()
+ it, ok := typ.(*types.Interface)
+ if !ok || !it.Empty() {
+ // Skip variadic functions accepting non-interface{} args.
+ return
}
}
args := call.Args
package testdata
-import "sync"
+import (
+ "sync"
+ "sync/atomic"
+)
func OkFunc() {
var x *sync.Mutex
new := func(interface{}) {}
new(t) // ERROR "function call copies lock value: testdata.Tlock contains sync.Once contains sync.Mutex"
}
+
+// SyncTypesCheck checks copying of sync.* types except sync.Mutex
+func SyncTypesCheck() {
+ // sync.RWMutex copying
+ var rwmuX sync.RWMutex
+ var rwmuXX = sync.RWMutex{}
+ rwmuX1 := new(sync.RWMutex)
+ rwmuY := rwmuX // ERROR "assignment copies lock value to rwmuY: sync.RWMutex"
+ rwmuY = rwmuX // ERROR "assignment copies lock value to rwmuY: sync.RWMutex"
+ var rwmuYY = rwmuX // ERROR "variable declaration copies lock value to rwmuYY: sync.RWMutex"
+ rwmuP := &rwmuX
+ rwmuZ := &sync.RWMutex{}
+
+ // sync.Cond copying
+ var condX sync.Cond
+ var condXX = sync.Cond{}
+ condX1 := new(sync.Cond)
+ condY := condX // ERROR "assignment copies lock value to condY: sync.Cond contains sync.noCopy"
+ condY = condX // ERROR "assignment copies lock value to condY: sync.Cond contains sync.noCopy"
+ var condYY = condX // ERROR "variable declaration copies lock value to condYY: sync.Cond contains sync.noCopy"
+ condP := &condX
+ condZ := &sync.Cond{
+ L: &sync.Mutex{},
+ }
+ condZ = sync.NewCond(&sync.Mutex{})
+
+ // sync.WaitGroup copying
+ var wgX sync.WaitGroup
+ var wgXX = sync.WaitGroup{}
+ wgX1 := new(sync.WaitGroup)
+ wgY := wgX // ERROR "assignment copies lock value to wgY: sync.WaitGroup contains sync.noCopy"
+ wgY = wgX // ERROR "assignment copies lock value to wgY: sync.WaitGroup contains sync.noCopy"
+ var wgYY = wgX // ERROR "variable declaration copies lock value to wgYY: sync.WaitGroup contains sync.noCopy"
+ wgP := &wgX
+ wgZ := &sync.WaitGroup{}
+
+ // sync.Pool copying
+ var poolX sync.Pool
+ var poolXX = sync.Pool{}
+ poolX1 := new(sync.Pool)
+ poolY := poolX // ERROR "assignment copies lock value to poolY: sync.Pool contains sync.noCopy"
+ poolY = poolX // ERROR "assignment copies lock value to poolY: sync.Pool contains sync.noCopy"
+ var poolYY = poolX // ERROR "variable declaration copies lock value to poolYY: sync.Pool contains sync.noCopy"
+ poolP := &poolX
+ poolZ := &sync.Pool{}
+
+ // sync.Once copying
+ var onceX sync.Once
+ var onceXX = sync.Once{}
+ onceX1 := new(sync.Once)
+ onceY := onceX // ERROR "assignment copies lock value to onceY: sync.Once contains sync.Mutex"
+ onceY = onceX // ERROR "assignment copies lock value to onceY: sync.Once contains sync.Mutex"
+ var onceYY = onceX // ERROR "variable declaration copies lock value to onceYY: sync.Once contains sync.Mutex"
+ onceP := &onceX
+ onceZ := &sync.Once{}
+}
+
+// AtomicTypesCheck checks copying of sync/atomic types
+func AtomicTypesCheck() {
+ // atomic.Value copying
+ var vX atomic.Value
+ var vXX = atomic.Value{}
+ vX1 := new(atomic.Value)
+ vY := vX // ERROR "assignment copies lock value to vY: sync/atomic.Value contains sync/atomic.noCopy"
+ vY = vX // ERROR "assignment copies lock value to vY: sync/atomic.Value contains sync/atomic.noCopy"
+ var vYY = vX // ERROR "variable declaration copies lock value to vYY: sync/atomic.Value contains sync/atomic.noCopy"
+ vP := &vX
+ vZ := &atomic.Value{}
+}
import (
"fmt"
+ "io"
"math"
"os"
"unsafe" // just for test case printing unsafe.Pointer
panic("don't call - testing only")
}
+// Println is used by the test so we must declare it.
+func Println(args ...interface{}) {
+ panic("don't call - testing only")
+}
+
// Logf is used by the test so we must declare it.
func Logf(format string, args ...interface{}) {
panic("don't call - testing only")
}
+// Log is used by the test so we must declare it.
+func Log(args ...interface{}) {
+ panic("don't call - testing only")
+}
+
// printf is used by the test so we must declare it.
func printf(format string, args ...interface{}) {
panic("don't call - testing only")
func (int) String() {
return ""
}
+
+func (s *unknownStruct) Fprintln(w io.Writer, s string) {}
+
+func UnknownStructFprintln() {
+ s := unknownStruct{}
+ s.Fprintln(os.Stdout, "hello, world!") // OK
+}
"\x75\xc4\xf8\x0f\x12\x11\xb9\xb4\x4b\x09\xa0\xbe\x8b\x91\x4c")))
}
-const (
- digits = iota
- twain
-)
-
-var testfiles = []string{
+var suites = []struct{ name, file string }{
// Digits is the digits of the irrational number e. Its decimal representation
// does not repeat, but there are only 10 possible digits, so it should be
// reasonably compressible.
- digits: "../testdata/e.txt",
+ {"Digits", "../testdata/e.txt"},
// Twain is Mark Twain's classic English novel.
- twain: "../testdata/Mark.Twain-Tom.Sawyer.txt",
+ {"Twain", "../testdata/Mark.Twain-Tom.Sawyer.txt"},
}
-func benchmarkDecode(b *testing.B, testfile, level, n int) {
- b.ReportAllocs()
- b.StopTimer()
- b.SetBytes(int64(n))
- buf0, err := ioutil.ReadFile(testfiles[testfile])
- if err != nil {
- b.Fatal(err)
- }
- if len(buf0) == 0 {
- b.Fatalf("test file %q has no data", testfiles[testfile])
- }
- compressed := new(bytes.Buffer)
- w, err := NewWriter(compressed, level)
- if err != nil {
- b.Fatal(err)
- }
- for i := 0; i < n; i += len(buf0) {
- if len(buf0) > n-i {
- buf0 = buf0[:n-i]
+func BenchmarkDecode(b *testing.B) {
+ doBench(b, func(b *testing.B, buf0 []byte, level, n int) {
+ b.ReportAllocs()
+ b.StopTimer()
+ b.SetBytes(int64(n))
+
+ compressed := new(bytes.Buffer)
+ w, err := NewWriter(compressed, level)
+ if err != nil {
+ b.Fatal(err)
}
- io.Copy(w, bytes.NewReader(buf0))
- }
- w.Close()
- buf1 := compressed.Bytes()
- buf0, compressed, w = nil, nil, nil
- runtime.GC()
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- io.Copy(ioutil.Discard, NewReader(bytes.NewReader(buf1)))
- }
+ for i := 0; i < n; i += len(buf0) {
+ if len(buf0) > n-i {
+ buf0 = buf0[:n-i]
+ }
+ io.Copy(w, bytes.NewReader(buf0))
+ }
+ w.Close()
+ buf1 := compressed.Bytes()
+ buf0, compressed, w = nil, nil, nil
+ runtime.GC()
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ io.Copy(ioutil.Discard, NewReader(bytes.NewReader(buf1)))
+ }
+ })
}
-// These short names are so that gofmt doesn't break the BenchmarkXxx function
-// bodies below over multiple lines.
-const (
- speed = BestSpeed
- default_ = DefaultCompression
- compress = BestCompression
- huffman = HuffmanOnly
-)
+var levelTests = []struct {
+ name string
+ level int
+}{
+ {"Huffman", HuffmanOnly},
+ {"Speed", BestSpeed},
+ {"Default", DefaultCompression},
+ {"Compression", BestCompression},
+}
-func BenchmarkDecodeDigitsHuffman1e4(b *testing.B) { benchmarkDecode(b, digits, huffman, 1e4) }
-func BenchmarkDecodeDigitsHuffman1e5(b *testing.B) { benchmarkDecode(b, digits, huffman, 1e5) }
-func BenchmarkDecodeDigitsHuffman1e6(b *testing.B) { benchmarkDecode(b, digits, huffman, 1e6) }
-func BenchmarkDecodeDigitsSpeed1e4(b *testing.B) { benchmarkDecode(b, digits, speed, 1e4) }
-func BenchmarkDecodeDigitsSpeed1e5(b *testing.B) { benchmarkDecode(b, digits, speed, 1e5) }
-func BenchmarkDecodeDigitsSpeed1e6(b *testing.B) { benchmarkDecode(b, digits, speed, 1e6) }
-func BenchmarkDecodeDigitsDefault1e4(b *testing.B) { benchmarkDecode(b, digits, default_, 1e4) }
-func BenchmarkDecodeDigitsDefault1e5(b *testing.B) { benchmarkDecode(b, digits, default_, 1e5) }
-func BenchmarkDecodeDigitsDefault1e6(b *testing.B) { benchmarkDecode(b, digits, default_, 1e6) }
-func BenchmarkDecodeDigitsCompress1e4(b *testing.B) { benchmarkDecode(b, digits, compress, 1e4) }
-func BenchmarkDecodeDigitsCompress1e5(b *testing.B) { benchmarkDecode(b, digits, compress, 1e5) }
-func BenchmarkDecodeDigitsCompress1e6(b *testing.B) { benchmarkDecode(b, digits, compress, 1e6) }
-func BenchmarkDecodeTwainHuffman1e4(b *testing.B) { benchmarkDecode(b, twain, huffman, 1e4) }
-func BenchmarkDecodeTwainHuffman1e5(b *testing.B) { benchmarkDecode(b, twain, huffman, 1e5) }
-func BenchmarkDecodeTwainHuffman1e6(b *testing.B) { benchmarkDecode(b, twain, huffman, 1e6) }
-func BenchmarkDecodeTwainSpeed1e4(b *testing.B) { benchmarkDecode(b, twain, speed, 1e4) }
-func BenchmarkDecodeTwainSpeed1e5(b *testing.B) { benchmarkDecode(b, twain, speed, 1e5) }
-func BenchmarkDecodeTwainSpeed1e6(b *testing.B) { benchmarkDecode(b, twain, speed, 1e6) }
-func BenchmarkDecodeTwainDefault1e4(b *testing.B) { benchmarkDecode(b, twain, default_, 1e4) }
-func BenchmarkDecodeTwainDefault1e5(b *testing.B) { benchmarkDecode(b, twain, default_, 1e5) }
-func BenchmarkDecodeTwainDefault1e6(b *testing.B) { benchmarkDecode(b, twain, default_, 1e6) }
-func BenchmarkDecodeTwainCompress1e4(b *testing.B) { benchmarkDecode(b, twain, compress, 1e4) }
-func BenchmarkDecodeTwainCompress1e5(b *testing.B) { benchmarkDecode(b, twain, compress, 1e5) }
-func BenchmarkDecodeTwainCompress1e6(b *testing.B) { benchmarkDecode(b, twain, compress, 1e6) }
+var sizes = []struct {
+ name string
+ n int
+}{
+ {"1e4", 1e4},
+ {"1e5", 1e5},
+ {"1e6", 1e6},
+}
+
+func doBench(b *testing.B, f func(b *testing.B, buf []byte, level, n int)) {
+ for _, suite := range suites {
+ buf, err := ioutil.ReadFile(suite.file)
+ if err != nil {
+ b.Fatal(err)
+ }
+ if len(buf) == 0 {
+ b.Fatalf("test file %q has no data", suite.file)
+ }
+ for _, l := range levelTests {
+ for _, s := range sizes {
+ b.Run(suite.name+"/"+l.name+"/"+s.name, func(b *testing.B) {
+ f(b, buf, l.level, s.n)
+ })
+ }
+ }
+ }
+}
"testing"
)
-func benchmarkEncoder(b *testing.B, testfile, level, n int) {
- b.StopTimer()
- b.SetBytes(int64(n))
- buf0, err := ioutil.ReadFile(testfiles[testfile])
- if err != nil {
- b.Fatal(err)
- }
- if len(buf0) == 0 {
- b.Fatalf("test file %q has no data", testfiles[testfile])
- }
- buf1 := make([]byte, n)
- for i := 0; i < n; i += len(buf0) {
- if len(buf0) > n-i {
- buf0 = buf0[:n-i]
+func BenchmarkEncode(b *testing.B) {
+ doBench(b, func(b *testing.B, buf0 []byte, level, n int) {
+ b.StopTimer()
+ b.SetBytes(int64(n))
+
+ buf1 := make([]byte, n)
+ for i := 0; i < n; i += len(buf0) {
+ if len(buf0) > n-i {
+ buf0 = buf0[:n-i]
+ }
+ copy(buf1[i:], buf0)
}
- copy(buf1[i:], buf0)
- }
- buf0 = nil
- w, err := NewWriter(ioutil.Discard, level)
- if err != nil {
- b.Fatal(err)
- }
- runtime.GC()
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- w.Reset(ioutil.Discard)
- w.Write(buf1)
- w.Close()
- }
+ buf0 = nil
+ w, err := NewWriter(ioutil.Discard, level)
+ if err != nil {
+ b.Fatal(err)
+ }
+ runtime.GC()
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ w.Reset(ioutil.Discard)
+ w.Write(buf1)
+ w.Close()
+ }
+ })
}
-func BenchmarkEncodeDigitsHuffman1e4(b *testing.B) { benchmarkEncoder(b, digits, huffman, 1e4) }
-func BenchmarkEncodeDigitsHuffman1e5(b *testing.B) { benchmarkEncoder(b, digits, huffman, 1e5) }
-func BenchmarkEncodeDigitsHuffman1e6(b *testing.B) { benchmarkEncoder(b, digits, huffman, 1e6) }
-func BenchmarkEncodeDigitsSpeed1e4(b *testing.B) { benchmarkEncoder(b, digits, speed, 1e4) }
-func BenchmarkEncodeDigitsSpeed1e5(b *testing.B) { benchmarkEncoder(b, digits, speed, 1e5) }
-func BenchmarkEncodeDigitsSpeed1e6(b *testing.B) { benchmarkEncoder(b, digits, speed, 1e6) }
-func BenchmarkEncodeDigitsDefault1e4(b *testing.B) { benchmarkEncoder(b, digits, default_, 1e4) }
-func BenchmarkEncodeDigitsDefault1e5(b *testing.B) { benchmarkEncoder(b, digits, default_, 1e5) }
-func BenchmarkEncodeDigitsDefault1e6(b *testing.B) { benchmarkEncoder(b, digits, default_, 1e6) }
-func BenchmarkEncodeDigitsCompress1e4(b *testing.B) { benchmarkEncoder(b, digits, compress, 1e4) }
-func BenchmarkEncodeDigitsCompress1e5(b *testing.B) { benchmarkEncoder(b, digits, compress, 1e5) }
-func BenchmarkEncodeDigitsCompress1e6(b *testing.B) { benchmarkEncoder(b, digits, compress, 1e6) }
-func BenchmarkEncodeTwainHuffman1e4(b *testing.B) { benchmarkEncoder(b, twain, huffman, 1e4) }
-func BenchmarkEncodeTwainHuffman1e5(b *testing.B) { benchmarkEncoder(b, twain, huffman, 1e5) }
-func BenchmarkEncodeTwainHuffman1e6(b *testing.B) { benchmarkEncoder(b, twain, huffman, 1e6) }
-func BenchmarkEncodeTwainSpeed1e4(b *testing.B) { benchmarkEncoder(b, twain, speed, 1e4) }
-func BenchmarkEncodeTwainSpeed1e5(b *testing.B) { benchmarkEncoder(b, twain, speed, 1e5) }
-func BenchmarkEncodeTwainSpeed1e6(b *testing.B) { benchmarkEncoder(b, twain, speed, 1e6) }
-func BenchmarkEncodeTwainDefault1e4(b *testing.B) { benchmarkEncoder(b, twain, default_, 1e4) }
-func BenchmarkEncodeTwainDefault1e5(b *testing.B) { benchmarkEncoder(b, twain, default_, 1e5) }
-func BenchmarkEncodeTwainDefault1e6(b *testing.B) { benchmarkEncoder(b, twain, default_, 1e6) }
-func BenchmarkEncodeTwainCompress1e4(b *testing.B) { benchmarkEncoder(b, twain, compress, 1e4) }
-func BenchmarkEncodeTwainCompress1e5(b *testing.B) { benchmarkEncoder(b, twain, compress, 1e5) }
-func BenchmarkEncodeTwainCompress1e6(b *testing.B) { benchmarkEncoder(b, twain, compress, 1e6) }
-
// errorWriter is a writer that fails after N writes.
type errorWriter struct {
N int
// Test if two runs produce identical results
// even when writing different sizes to the Writer.
-func TestDeterministicL0(t *testing.T) { testDeterministic(0, t) }
-func TestDeterministicL1(t *testing.T) { testDeterministic(1, t) }
-func TestDeterministicL2(t *testing.T) { testDeterministic(2, t) }
-func TestDeterministicL3(t *testing.T) { testDeterministic(3, t) }
-func TestDeterministicL4(t *testing.T) { testDeterministic(4, t) }
-func TestDeterministicL5(t *testing.T) { testDeterministic(5, t) }
-func TestDeterministicL6(t *testing.T) { testDeterministic(6, t) }
-func TestDeterministicL7(t *testing.T) { testDeterministic(7, t) }
-func TestDeterministicL8(t *testing.T) { testDeterministic(8, t) }
-func TestDeterministicL9(t *testing.T) { testDeterministic(9, t) }
-func TestDeterministicLM2(t *testing.T) { testDeterministic(-2, t) }
+func TestDeterministic(t *testing.T) {
+ for i := 0; i <= 9; i++ {
+ t.Run(fmt.Sprint("L", i), func(t *testing.T) { testDeterministic(i, t) })
+ }
+ t.Run("LM2", func(t *testing.T) { testDeterministic(-2, t) })
+}
func testDeterministic(i int, t *testing.T) {
// Test so much we cross a good number of block boundaries.
}
// Close closes the Reader. It does not close the underlying io.Reader.
+// In order for the GZIP checksum to be verified, the reader must be
+// fully consumed until the io.EOF.
func (z *Reader) Close() error { return z.decompressor.Close() }
import (
"bytes"
+ "fmt"
"io"
"io/ioutil"
+ "math"
"runtime"
"strconv"
"strings"
}
}
-func benchmarkDecoder(b *testing.B, n int) {
- b.StopTimer()
- b.SetBytes(int64(n))
- buf0, err := ioutil.ReadFile("../testdata/e.txt")
+func BenchmarkDecoder(b *testing.B) {
+ buf, err := ioutil.ReadFile("../testdata/e.txt")
if err != nil {
b.Fatal(err)
}
- if len(buf0) == 0 {
+ if len(buf) == 0 {
b.Fatalf("test file has no data")
}
- compressed := new(bytes.Buffer)
- w := NewWriter(compressed, LSB, 8)
- for i := 0; i < n; i += len(buf0) {
- if len(buf0) > n-i {
- buf0 = buf0[:n-i]
- }
- w.Write(buf0)
- }
- w.Close()
- buf1 := compressed.Bytes()
- buf0, compressed, w = nil, nil, nil
- runtime.GC()
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- io.Copy(ioutil.Discard, NewReader(bytes.NewReader(buf1), LSB, 8))
- }
-}
-
-func BenchmarkDecoder1e4(b *testing.B) {
- benchmarkDecoder(b, 1e4)
-}
-func BenchmarkDecoder1e5(b *testing.B) {
- benchmarkDecoder(b, 1e5)
-}
-
-func BenchmarkDecoder1e6(b *testing.B) {
- benchmarkDecoder(b, 1e6)
+ for e := 4; e <= 6; e++ {
+ n := int(math.Pow10(e))
+ b.Run(fmt.Sprint("1e", e), func(b *testing.B) {
+ b.StopTimer()
+ b.SetBytes(int64(n))
+ buf0 := buf
+ compressed := new(bytes.Buffer)
+ w := NewWriter(compressed, LSB, 8)
+ for i := 0; i < n; i += len(buf0) {
+ if len(buf0) > n-i {
+ buf0 = buf0[:n-i]
+ }
+ w.Write(buf0)
+ }
+ w.Close()
+ buf1 := compressed.Bytes()
+ buf0, compressed, w = nil, nil, nil
+ runtime.GC()
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ io.Copy(ioutil.Discard, NewReader(bytes.NewReader(buf1), LSB, 8))
+ }
+ })
+ }
}
package lzw
import (
+ "fmt"
"internal/testenv"
"io"
"io/ioutil"
+ "math"
"os"
"runtime"
"testing"
}
}
-func benchmarkEncoder(b *testing.B, n int) {
- b.StopTimer()
- b.SetBytes(int64(n))
- buf0, err := ioutil.ReadFile("../testdata/e.txt")
+func BenchmarkEncoder(b *testing.B) {
+ buf, err := ioutil.ReadFile("../testdata/e.txt")
if err != nil {
b.Fatal(err)
}
- if len(buf0) == 0 {
+ if len(buf) == 0 {
b.Fatalf("test file has no data")
}
- buf1 := make([]byte, n)
- for i := 0; i < n; i += len(buf0) {
- if len(buf0) > n-i {
- buf0 = buf0[:n-i]
+
+ for e := 4; e <= 6; e++ {
+ n := int(math.Pow10(e))
+ buf0 := buf
+ buf1 := make([]byte, n)
+ for i := 0; i < n; i += len(buf0) {
+ if len(buf0) > n-i {
+ buf0 = buf0[:n-i]
+ }
+ copy(buf1[i:], buf0)
}
- copy(buf1[i:], buf0)
- }
- buf0 = nil
- runtime.GC()
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- w := NewWriter(ioutil.Discard, LSB, 8)
- w.Write(buf1)
- w.Close()
+ buf0 = nil
+ runtime.GC()
+ b.Run(fmt.Sprint("1e", e), func(b *testing.B) {
+ b.SetBytes(int64(n))
+ for i := 0; i < b.N; i++ {
+ w := NewWriter(ioutil.Discard, LSB, 8)
+ w.Write(buf1)
+ w.Close()
+ }
+ })
}
}
-
-func BenchmarkEncoder1e4(b *testing.B) {
- benchmarkEncoder(b, 1e4)
-}
-
-func BenchmarkEncoder1e5(b *testing.B) {
- benchmarkEncoder(b, 1e5)
-}
-
-func BenchmarkEncoder1e6(b *testing.B) {
- benchmarkEncoder(b, 1e6)
-}
// NewReader creates a new ReadCloser.
// Reads from the returned ReadCloser read and decompress data from r.
-// The implementation buffers input and may read more data than necessary from r.
+// If r does not implement io.ByteReader, the decompressor may read more
+// data than necessary from r.
// It is the caller's responsibility to call Close on the ReadCloser when done.
//
// The ReadCloser returned by NewReader also implements Resetter.
}
// Calling Close does not close the wrapped io.Reader originally passed to NewReader.
+// In order for the ZLIB checksum to be verified, the reader must be
+// fully consumed until the io.EOF.
func (z *reader) Close() error {
if z.err != nil && z.err != io.EOF {
return z.err
}
// Test that a list l is not modified when calling MoveAfter or MoveBefore with a mark that is not an element of l.
-func TestMoveUnkownMark(t *testing.T) {
+func TestMoveUnknownMark(t *testing.T) {
var l1 List
e1 := l1.PushBack(1)
// DeadlineExceeded is the error returned by Context.Err when the context's
// deadline passes.
-var DeadlineExceeded = errors.New("context deadline exceeded")
+var DeadlineExceeded error = deadlineExceededError{}
+
+type deadlineExceededError struct{}
+
+func (deadlineExceededError) Error() string { return "context deadline exceeded" }
+
+func (deadlineExceededError) Timeout() bool { return true }
// An emptyCtx is never canceled, has no values, and has no deadline. It is not
// struct{}, since vars of this type must have distinct addresses.
fn()
return
}
+
+func TestDeadlineExceededSupportsTimeout(t *testing.T) {
+ i, ok := DeadlineExceeded.(interface {
+ Timeout() bool
+ })
+ if !ok {
+ t.Fatal("DeadlineExceeded does not support Timeout interface")
+ }
+ if !i.Timeout() {
+ t.Fatal("wrong value for timeout")
+ }
+}
// The key argument should be the AES key, either 16 or 32 bytes
// to select AES-128 or AES-256.
key := []byte("AES256Key-32Characters1234567890")
- ciphertext, _ := hex.DecodeString("f90fbef747e7212ad7410d0eee2d965de7e890471695cddd2a5bc0ef5da1d04ad8147b62141ad6e4914aee8c512f64fba9037603d41de0d50b718bd665f019cdcd")
+ ciphertext, _ := hex.DecodeString("1019aa66cd7c024f9efd0038899dae1973ee69427f5a6579eba292ffe1b5a260")
- nonce, _ := hex.DecodeString("bb8ef84243d2ee95a41c6c57")
+ nonce, _ := hex.DecodeString("37b8e8a308c354048d245f6d")
block, err := aes.NewCipher(key)
if err != nil {
panic(err.Error())
}
- fmt.Printf("%s\n", string(plaintext))
+ fmt.Printf("%s\n", plaintext)
+ // Output: exampleplaintext
}
func ExampleNewCBCDecrypter() {
c := pub.Curve
N := c.Params().N
- if r.Sign() == 0 || s.Sign() == 0 {
+ if r.Sign() <= 0 || s.Sign() <= 0 {
return false
}
if r.Cmp(N) >= 0 || s.Cmp(N) >= 0 {
}
}
}
+
+func testNegativeInputs(t *testing.T, curve elliptic.Curve, tag string) {
+ key, err := GenerateKey(curve, rand.Reader)
+ if err != nil {
+ t.Errorf("failed to generate key for %q", tag)
+ }
+
+ var hash [32]byte
+ r := new(big.Int).SetInt64(1)
+ r.Lsh(r, 550 /* larger than any supported curve */)
+ r.Neg(r)
+
+ if Verify(&key.PublicKey, hash[:], r, r) {
+ t.Errorf("bogus signature accepted for %q", tag)
+ }
+}
+
+func TestNegativeInputs(t *testing.T) {
+ testNegativeInputs(t, elliptic.P224(), "p224")
+ testNegativeInputs(t, elliptic.P256(), "p256")
+ testNegativeInputs(t, elliptic.P384(), "p384")
+ testNegativeInputs(t, elliptic.P521(), "p521")
+}
func p256PointDoubleAsm(res, in []uint64)
func (curve p256Curve) Inverse(k *big.Int) *big.Int {
+ if k.Sign() < 0 {
+ // This should never happen.
+ k = new(big.Int).Neg(k)
+ }
+
if k.Cmp(p256.N) >= 0 {
// This should never happen.
- reducedK := new(big.Int).Mod(k, p256.N)
- k = reducedK
+ k = new(big.Int).Mod(k, p256.N)
}
// table will store precomputed powers of x. The four words at index
--- /dev/null
+// +build amd64
+// +build linux darwin
+
+// 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 sha1_test
+
+import (
+ "crypto/sha1"
+ "syscall"
+ "testing"
+)
+
+func TestOutOfBoundsRead(t *testing.T) {
+ const pageSize = 4 << 10
+ data, err := syscall.Mmap(0, 0, 2*pageSize, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_ANON|syscall.MAP_PRIVATE)
+ if err != nil {
+ panic(err)
+ }
+ if err := syscall.Mprotect(data[pageSize:], syscall.PROT_NONE); err != nil {
+ panic(err)
+ }
+ for i := 0; i < pageSize; i++ {
+ sha1.Sum(data[pageSize-i : pageSize])
+ }
+}
}
var golden = []sha1Test{
+ {"76245dbf96f661bd221046197ab8b9f063f11bad", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"},
{"da39a3ee5e6b4b0d3255bfef95601890afd80709", ""},
{"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", "a"},
{"da23614e02469a0d7c7bd1bdab5c9c474b1904dc", "ab"},
// Tests that blockGeneric (pure Go) and block (in assembly for some architectures) match.
func TestBlockGeneric(t *testing.T) {
- gen, asm := New().(*digest), New().(*digest)
- buf := make([]byte, BlockSize*20) // arbitrary factor
- rand.Read(buf)
- blockGeneric(gen, buf)
- block(asm, buf)
- if *gen != *asm {
- t.Error("block and blockGeneric resulted in different states")
+ for i := 1; i < 30; i++ { // arbitrary factor
+ gen, asm := New().(*digest), New().(*digest)
+ buf := make([]byte, BlockSize*i)
+ rand.Read(buf)
+ blockGeneric(gen, buf)
+ block(asm, buf)
+ if *gen != *asm {
+ t.Errorf("For %#v block and blockGeneric resulted in different states", buf)
+ }
}
}
benchmarkSize(b, 8)
}
+func BenchmarkHash320Bytes(b *testing.B) {
+ benchmarkSize(b, 320)
+}
+
func BenchmarkHash1K(b *testing.B) {
benchmarkSize(b, 1024)
}
--- /dev/null
+// 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 sha1
+
+//go:noescape
+
+func blockAVX2(dig *digest, p []byte)
+
+//go:noescape
+func blockAMD64(dig *digest, p []byte)
+func checkAVX2() bool
+
+var hasAVX2 = checkAVX2()
+
+func block(dig *digest, p []byte) {
+ if hasAVX2 && len(p) >= 256 {
+ // blockAVX2 calculates sha1 for 2 block per iteration
+ // it also interleaves precalculation for next block.
+ // So it may read up-to 192 bytes past end of p
+ // We may add checks inside blockAVX2, but this will
+ // just turn it into a copy of blockAMD64,
+ // so call it directly, instead.
+ safeLen := len(p) - 128
+ if safeLen%128 != 0 {
+ safeLen -= 64
+ }
+ blockAVX2(dig, p[:safeLen])
+ blockAMD64(dig, p[safeLen:])
+ } else {
+ blockAMD64(dig, p)
+ }
+}
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// AVX2 version by Intel, same algorithm as code in Linux kernel:
+// https://github.com/torvalds/linux/blob/master/arch/x86/crypto/sha1_avx2_x86_64_asm.S
+// Authors:
+// Ilya Albrekht <ilya.albrekht@intel.com>
+// Maxim Locktyukhin <maxim.locktyukhin@intel.com>
+// Ronen Zohar <ronen.zohar@intel.com>
+// Chandramouli Narayanan <mouli@linux.intel.com>
+
+
#include "textflag.h"
// SHA1 block routine. See sha1block.go for Go equivalent.
FUNC4(a, b, c, d, e); \
MIX(a, b, c, d, e, 0xCA62C1D6)
-TEXT ·block(SB),NOSPLIT,$64-32
+TEXT ·blockAMD64(SB),NOSPLIT,$64-32
MOVQ dig+0(FP), BP
MOVQ p_base+8(FP), SI
MOVQ p_len+16(FP), DX
MOVL DX, (3*4)(DI)
MOVL BP, (4*4)(DI)
RET
+
+
+// This is the implementation using AVX2. It is based on:
+// "SHA-1 implementation with Intel(R) AVX2 instruction set extensions"
+// From http://software.intel.com/en-us/articles
+// (look for improving-the-performance-of-the-secure-hash-algorithm-1)
+// This implementation is 2x unrolled, and interleaves vector instructions,
+// used to precompute W, with scalar computation of current round
+// for optimal scheduling.
+
+// Trivial helper macros.
+#define UPDATE_HASH(A,TB,C,D,E) \
+ ADDL (R9), A \
+ MOVL A, (R9) \
+ ADDL 4(R9), TB \
+ MOVL TB, 4(R9) \
+ ADDL 8(R9), C \
+ MOVL C, 8(R9) \
+ ADDL 12(R9), D \
+ MOVL D, 12(R9) \
+ ADDL 16(R9), E \
+ MOVL E, 16(R9)
+
+
+
+// Helper macros for PRECALC, which does precomputations
+#define PRECALC_0(OFFSET) \
+ VMOVDQU OFFSET(R10),X0
+
+#define PRECALC_1(OFFSET) \
+ VINSERTI128 $1, OFFSET(R13), Y0, Y0
+
+#define PRECALC_2(YREG) \
+ VPSHUFB Y10, Y0, YREG
+
+#define PRECALC_4(YREG,K_OFFSET) \
+ VPADDD K_OFFSET(R8), YREG, Y0
+
+#define PRECALC_7(OFFSET) \
+ VMOVDQU Y0, (OFFSET*2)(R14)
+
+
+// Message scheduling pre-compute for rounds 0-15
+// R13 is a pointer to even 64-byte block
+// R10 is a pointer to odd 64-byte block
+// R14 is a pointer to temp buffer
+// X0 is used as temp register
+// YREG is clobbered as part of computation
+// OFFSET chooses 16 byte chunk within a block
+// R8 is a pointer to constants block
+// K_OFFSET chooses K constants relevant to this round
+// X10 holds swap mask
+#define PRECALC_00_15(OFFSET,YREG) \
+ PRECALC_0(OFFSET) \
+ PRECALC_1(OFFSET) \
+ PRECALC_2(YREG) \
+ PRECALC_4(YREG,0x0) \
+ PRECALC_7(OFFSET)
+
+
+// Helper macros for PRECALC_16_31
+#define PRECALC_16(REG_SUB_16,REG_SUB_12,REG_SUB_4,REG) \
+ VPALIGNR $8, REG_SUB_16, REG_SUB_12, REG \ // w[i-14]
+ VPSRLDQ $4, REG_SUB_4, Y0 // w[i-3]
+
+#define PRECALC_17(REG_SUB_16,REG_SUB_8,REG) \
+ VPXOR REG_SUB_8, REG, REG \
+ VPXOR REG_SUB_16, Y0, Y0
+
+#define PRECALC_18(REG) \
+ VPXOR Y0, REG, REG \
+ VPSLLDQ $12, REG, Y9
+
+#define PRECALC_19(REG) \
+ VPSLLD $1, REG, Y0 \
+ VPSRLD $31, REG, REG
+
+#define PRECALC_20(REG) \
+ VPOR REG, Y0, Y0 \
+ VPSLLD $2, Y9, REG
+
+#define PRECALC_21(REG) \
+ VPSRLD $30, Y9, Y9 \
+ VPXOR REG, Y0, Y0
+
+#define PRECALC_23(REG,K_OFFSET,OFFSET) \
+ VPXOR Y9, Y0, REG \
+ VPADDD K_OFFSET(R8), REG, Y0 \
+ VMOVDQU Y0, (OFFSET)(R14)
+
+// Message scheduling pre-compute for rounds 16-31
+// calculating last 32 w[i] values in 8 XMM registers
+// pre-calculate K+w[i] values and store to mem
+// for later load by ALU add instruction.
+// "brute force" vectorization for rounds 16-31 only
+// due to w[i]->w[i-3] dependency.
+// clobbers 5 input ymm registers REG_SUB*
+// uses X0 and X9 as temp registers
+// As always, R8 is a pointer to constants block
+// and R14 is a pointer to temp buffer
+#define PRECALC_16_31(REG,REG_SUB_4,REG_SUB_8,REG_SUB_12,REG_SUB_16,K_OFFSET,OFFSET) \
+ PRECALC_16(REG_SUB_16,REG_SUB_12,REG_SUB_4,REG) \
+ PRECALC_17(REG_SUB_16,REG_SUB_8,REG) \
+ PRECALC_18(REG) \
+ PRECALC_19(REG) \
+ PRECALC_20(REG) \
+ PRECALC_21(REG) \
+ PRECALC_23(REG,K_OFFSET,OFFSET)
+
+
+// Helper macros for PRECALC_32_79
+#define PRECALC_32(REG_SUB_8,REG_SUB_4) \
+ VPALIGNR $8, REG_SUB_8, REG_SUB_4, Y0
+
+#define PRECALC_33(REG_SUB_28,REG) \
+ VPXOR REG_SUB_28, REG, REG
+
+#define PRECALC_34(REG_SUB_16) \
+ VPXOR REG_SUB_16, Y0, Y0
+
+#define PRECALC_35(REG) \
+ VPXOR Y0, REG, REG
+
+#define PRECALC_36(REG) \
+ VPSLLD $2, REG, Y0
+
+#define PRECALC_37(REG) \
+ VPSRLD $30, REG, REG \
+ VPOR REG, Y0, REG
+
+#define PRECALC_39(REG,K_OFFSET,OFFSET) \
+ VPADDD K_OFFSET(R8), REG, Y0 \
+ VMOVDQU Y0, (OFFSET)(R14)
+
+// Message scheduling pre-compute for rounds 32-79
+// In SHA-1 specification we have:
+// w[i] = (w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]) rol 1
+// Which is the same as:
+// w[i] = (w[i-6] ^ w[i-16] ^ w[i-28] ^ w[i-32]) rol 2
+// This allows for more efficient vectorization,
+// since w[i]->w[i-3] dependency is broken
+#define PRECALC_32_79(REG,REG_SUB_4,REG_SUB_8,REG_SUB_16,REG_SUB_28,K_OFFSET,OFFSET) \
+ PRECALC_32(REG_SUB_8,REG_SUB_4) \
+ PRECALC_33(REG_SUB_28,REG) \
+ PRECALC_34(REG_SUB_16) \
+ PRECALC_35(REG) \
+ PRECALC_36(REG) \
+ PRECALC_37(REG) \
+ PRECALC_39(REG,K_OFFSET,OFFSET)
+
+#define PRECALC \
+ PRECALC_00_15(0,Y15) \
+ PRECALC_00_15(0x10,Y14) \
+ PRECALC_00_15(0x20,Y13) \
+ PRECALC_00_15(0x30,Y12) \
+ PRECALC_16_31(Y8,Y12,Y13,Y14,Y15,0,0x80) \
+ PRECALC_16_31(Y7,Y8,Y12,Y13,Y14,0x20,0xa0) \
+ PRECALC_16_31(Y5,Y7,Y8,Y12,Y13,0x20,0xc0) \
+ PRECALC_16_31(Y3,Y5,Y7,Y8,Y12,0x20,0xe0) \
+ PRECALC_32_79(Y15,Y3,Y5,Y8,Y14,0x20,0x100) \
+ PRECALC_32_79(Y14,Y15,Y3,Y7,Y13,0x20,0x120) \
+ PRECALC_32_79(Y13,Y14,Y15,Y5,Y12,0x40,0x140) \
+ PRECALC_32_79(Y12,Y13,Y14,Y3,Y8,0x40,0x160) \
+ PRECALC_32_79(Y8,Y12,Y13,Y15,Y7,0x40,0x180) \
+ PRECALC_32_79(Y7,Y8,Y12,Y14,Y5,0x40,0x1a0) \
+ PRECALC_32_79(Y5,Y7,Y8,Y13,Y3,0x40,0x1c0) \
+ PRECALC_32_79(Y3,Y5,Y7,Y12,Y15,0x60,0x1e0) \
+ PRECALC_32_79(Y15,Y3,Y5,Y8,Y14,0x60,0x200) \
+ PRECALC_32_79(Y14,Y15,Y3,Y7,Y13,0x60,0x220) \
+ PRECALC_32_79(Y13,Y14,Y15,Y5,Y12,0x60,0x240) \
+ PRECALC_32_79(Y12,Y13,Y14,Y3,Y8,0x60,0x260)
+
+// Macros calculating individual rounds have general forn
+// CALC_ROUND_PRE + PRECALC_ROUND + CALC_ROUND_POST
+// CALC_ROUND_{PRE,POST} macros follow
+
+#define CALC_F1_PRE(OFFSET,REG_A,REG_B,REG_C,REG_E) \
+ ADDL OFFSET(R15),REG_E \
+ ANDNL REG_C,REG_A,BP \
+ LEAL (REG_E)(REG_B*1), REG_E \ // Add F from the previous round
+ RORXL $0x1b, REG_A, R12 \
+ RORXL $2, REG_A, REG_B // for next round
+
+// Calculate F for the next round
+#define CALC_F1_POST(REG_A,REG_B,REG_E) \
+ ANDL REG_B,REG_A \ // b&c
+ XORL BP, REG_A \ // F1 = (b&c) ^ (~b&d)
+ LEAL (REG_E)(R12*1), REG_E // E += A >>> 5
+
+
+// Registers are cycleickly rotated DX -> AX -> DI -> SI -> BX -> CX
+#define CALC_0 \
+ MOVL SI, BX \ // Precalculating first round
+ RORXL $2, SI, SI \
+ ANDNL AX, BX, BP \
+ ANDL DI, BX \
+ XORL BP, BX \
+ CALC_F1_PRE(0x0,CX,BX,DI,DX) \
+ PRECALC_0(0x80) \
+ CALC_F1_POST(CX,SI,DX)
+
+#define CALC_1 \
+ CALC_F1_PRE(0x4,DX,CX,SI,AX) \
+ PRECALC_1(0x80) \
+ CALC_F1_POST(DX,BX,AX)
+
+#define CALC_2 \
+ CALC_F1_PRE(0x8,AX,DX,BX,DI) \
+ PRECALC_2(Y15) \
+ CALC_F1_POST(AX,CX,DI)
+
+#define CALC_3 \
+ CALC_F1_PRE(0xc,DI,AX,CX,SI) \
+ CALC_F1_POST(DI,DX,SI)
+
+#define CALC_4 \
+ CALC_F1_PRE(0x20,SI,DI,DX,BX) \
+ PRECALC_4(Y15,0x0) \
+ CALC_F1_POST(SI,AX,BX)
+
+#define CALC_5 \
+ CALC_F1_PRE(0x24,BX,SI,AX,CX) \
+ CALC_F1_POST(BX,DI,CX)
+
+#define CALC_6 \
+ CALC_F1_PRE(0x28,CX,BX,DI,DX) \
+ CALC_F1_POST(CX,SI,DX)
+
+#define CALC_7 \
+ CALC_F1_PRE(0x2c,DX,CX,SI,AX) \
+ PRECALC_7(0x0) \
+ CALC_F1_POST(DX,BX,AX)
+
+#define CALC_8 \
+ CALC_F1_PRE(0x40,AX,DX,BX,DI) \
+ PRECALC_0(0x90) \
+ CALC_F1_POST(AX,CX,DI)
+
+#define CALC_9 \
+ CALC_F1_PRE(0x44,DI,AX,CX,SI) \
+ PRECALC_1(0x90) \
+ CALC_F1_POST(DI,DX,SI)
+
+#define CALC_10 \
+ CALC_F1_PRE(0x48,SI,DI,DX,BX) \
+ PRECALC_2(Y14) \
+ CALC_F1_POST(SI,AX,BX)
+
+#define CALC_11 \
+ CALC_F1_PRE(0x4c,BX,SI,AX,CX) \
+ CALC_F1_POST(BX,DI,CX)
+
+#define CALC_12 \
+ CALC_F1_PRE(0x60,CX,BX,DI,DX) \
+ PRECALC_4(Y14,0x0) \
+ CALC_F1_POST(CX,SI,DX)
+
+#define CALC_13 \
+ CALC_F1_PRE(0x64,DX,CX,SI,AX) \
+ CALC_F1_POST(DX,BX,AX)
+
+#define CALC_14 \
+ CALC_F1_PRE(0x68,AX,DX,BX,DI) \
+ CALC_F1_POST(AX,CX,DI)
+
+#define CALC_15 \
+ CALC_F1_PRE(0x6c,DI,AX,CX,SI) \
+ PRECALC_7(0x10) \
+ CALC_F1_POST(DI,DX,SI)
+
+#define CALC_16 \
+ CALC_F1_PRE(0x80,SI,DI,DX,BX) \
+ PRECALC_0(0xa0) \
+ CALC_F1_POST(SI,AX,BX)
+
+#define CALC_17 \
+ CALC_F1_PRE(0x84,BX,SI,AX,CX) \
+ PRECALC_1(0xa0) \
+ CALC_F1_POST(BX,DI,CX)
+
+#define CALC_18 \
+ CALC_F1_PRE(0x88,CX,BX,DI,DX) \
+ PRECALC_2(Y13) \
+ CALC_F1_POST(CX,SI,DX)
+
+
+#define CALC_F2_PRE(OFFSET,REG_A,REG_B,REG_E) \
+ ADDL OFFSET(R15),REG_E \
+ LEAL (REG_E)(REG_B*1), REG_E \ // Add F from the previous round
+ RORXL $0x1b, REG_A, R12 \
+ RORXL $2, REG_A, REG_B // for next round
+
+#define CALC_F2_POST(REG_A,REG_B,REG_C,REG_E) \
+ XORL REG_B, REG_A \
+ ADDL R12, REG_E \
+ XORL REG_C, REG_A
+
+#define CALC_19 \
+ CALC_F2_PRE(0x8c,DX,CX,AX) \
+ CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_20 \
+ CALC_F2_PRE(0xa0,AX,DX,DI) \
+ PRECALC_4(Y13,0x0) \
+ CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_21 \
+ CALC_F2_PRE(0xa4,DI,AX,SI) \
+ CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_22 \
+ CALC_F2_PRE(0xa8,SI,DI,BX) \
+ CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_23 \
+ CALC_F2_PRE(0xac,BX,SI,CX) \
+ PRECALC_7(0x20) \
+ CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_24 \
+ CALC_F2_PRE(0xc0,CX,BX,DX) \
+ PRECALC_0(0xb0) \
+ CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_25 \
+ CALC_F2_PRE(0xc4,DX,CX,AX) \
+ PRECALC_1(0xb0) \
+ CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_26 \
+ CALC_F2_PRE(0xc8,AX,DX,DI) \
+ PRECALC_2(Y12) \
+ CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_27 \
+ CALC_F2_PRE(0xcc,DI,AX,SI) \
+ CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_28 \
+ CALC_F2_PRE(0xe0,SI,DI,BX) \
+ PRECALC_4(Y12,0x0) \
+ CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_29 \
+ CALC_F2_PRE(0xe4,BX,SI,CX) \
+ CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_30 \
+ CALC_F2_PRE(0xe8,CX,BX,DX) \
+ CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_31 \
+ CALC_F2_PRE(0xec,DX,CX,AX) \
+ PRECALC_7(0x30) \
+ CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_32 \
+ CALC_F2_PRE(0x100,AX,DX,DI) \
+ PRECALC_16(Y15,Y14,Y12,Y8) \
+ CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_33 \
+ CALC_F2_PRE(0x104,DI,AX,SI) \
+ PRECALC_17(Y15,Y13,Y8) \
+ CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_34 \
+ CALC_F2_PRE(0x108,SI,DI,BX) \
+ PRECALC_18(Y8) \
+ CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_35 \
+ CALC_F2_PRE(0x10c,BX,SI,CX) \
+ PRECALC_19(Y8) \
+ CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_36 \
+ CALC_F2_PRE(0x120,CX,BX,DX) \
+ PRECALC_20(Y8) \
+ CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_37 \
+ CALC_F2_PRE(0x124,DX,CX,AX) \
+ PRECALC_21(Y8) \
+ CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_38 \
+ CALC_F2_PRE(0x128,AX,DX,DI) \
+ CALC_F2_POST(AX,CX,BX,DI)
+
+
+#define CALC_F3_PRE(OFFSET,REG_E) \
+ ADDL OFFSET(R15),REG_E
+
+#define CALC_F3_POST(REG_A,REG_B,REG_C,REG_E,REG_TB) \
+ LEAL (REG_E)(REG_TB*1), REG_E \ // Add F from the previous round
+ MOVL REG_B, BP \
+ ORL REG_A, BP \
+ RORXL $0x1b, REG_A, R12 \
+ RORXL $2, REG_A, REG_TB \
+ ANDL REG_C, BP \ // Calculate F for the next round
+ ANDL REG_B, REG_A \
+ ORL BP, REG_A \
+ ADDL R12, REG_E
+
+#define CALC_39 \
+ CALC_F3_PRE(0x12c,SI) \
+ PRECALC_23(Y8,0x0,0x80) \
+ CALC_F3_POST(DI,DX,CX,SI,AX)
+
+#define CALC_40 \
+ CALC_F3_PRE(0x140,BX) \
+ PRECALC_16(Y14,Y13,Y8,Y7) \
+ CALC_F3_POST(SI,AX,DX,BX,DI)
+
+#define CALC_41 \
+ CALC_F3_PRE(0x144,CX) \
+ PRECALC_17(Y14,Y12,Y7) \
+ CALC_F3_POST(BX,DI,AX,CX,SI)
+
+#define CALC_42 \
+ CALC_F3_PRE(0x148,DX) \
+ PRECALC_18(Y7) \
+ CALC_F3_POST(CX,SI,DI,DX,BX)
+
+#define CALC_43 \
+ CALC_F3_PRE(0x14c,AX) \
+ PRECALC_19(Y7) \
+ CALC_F3_POST(DX,BX,SI,AX,CX)
+
+#define CALC_44 \
+ CALC_F3_PRE(0x160,DI) \
+ PRECALC_20(Y7) \
+ CALC_F3_POST(AX,CX,BX,DI,DX)
+
+#define CALC_45 \
+ CALC_F3_PRE(0x164,SI) \
+ PRECALC_21(Y7) \
+ CALC_F3_POST(DI,DX,CX,SI,AX)
+
+#define CALC_46 \
+ CALC_F3_PRE(0x168,BX) \
+ CALC_F3_POST(SI,AX,DX,BX,DI)
+
+#define CALC_47 \
+ CALC_F3_PRE(0x16c,CX) \
+ VPXOR Y9, Y0, Y7 \
+ VPADDD 0x20(R8), Y7, Y0 \
+ VMOVDQU Y0, 0xa0(R14) \
+ CALC_F3_POST(BX,DI,AX,CX,SI)
+
+#define CALC_48 \
+ CALC_F3_PRE(0x180,DX) \
+ PRECALC_16(Y13,Y12,Y7,Y5) \
+ CALC_F3_POST(CX,SI,DI,DX,BX)
+
+#define CALC_49 \
+ CALC_F3_PRE(0x184,AX) \
+ PRECALC_17(Y13,Y8,Y5) \
+ CALC_F3_POST(DX,BX,SI,AX,CX)
+
+#define CALC_50 \
+ CALC_F3_PRE(0x188,DI) \
+ PRECALC_18(Y5) \
+ CALC_F3_POST(AX,CX,BX,DI,DX)
+
+#define CALC_51 \
+ CALC_F3_PRE(0x18c,SI) \
+ PRECALC_19(Y5) \
+ CALC_F3_POST(DI,DX,CX,SI,AX)
+
+#define CALC_52 \
+ CALC_F3_PRE(0x1a0,BX) \
+ PRECALC_20(Y5) \
+ CALC_F3_POST(SI,AX,DX,BX,DI)
+
+#define CALC_53 \
+ CALC_F3_PRE(0x1a4,CX) \
+ PRECALC_21(Y5) \
+ CALC_F3_POST(BX,DI,AX,CX,SI)
+
+#define CALC_54 \
+ CALC_F3_PRE(0x1a8,DX) \
+ CALC_F3_POST(CX,SI,DI,DX,BX)
+
+#define CALC_55 \
+ CALC_F3_PRE(0x1ac,AX) \
+ PRECALC_23(Y5,0x20,0xc0) \
+ CALC_F3_POST(DX,BX,SI,AX,CX)
+
+#define CALC_56 \
+ CALC_F3_PRE(0x1c0,DI) \
+ PRECALC_16(Y12,Y8,Y5,Y3) \
+ CALC_F3_POST(AX,CX,BX,DI,DX)
+
+#define CALC_57 \
+ CALC_F3_PRE(0x1c4,SI) \
+ PRECALC_17(Y12,Y7,Y3) \
+ CALC_F3_POST(DI,DX,CX,SI,AX)
+
+#define CALC_58 \
+ CALC_F3_PRE(0x1c8,BX) \
+ PRECALC_18(Y3) \
+ CALC_F3_POST(SI,AX,DX,BX,DI)
+
+#define CALC_59 \
+ CALC_F2_PRE(0x1cc,BX,SI,CX) \
+ PRECALC_19(Y3) \
+ CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_60 \
+ CALC_F2_PRE(0x1e0,CX,BX,DX) \
+ PRECALC_20(Y3) \
+ CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_61 \
+ CALC_F2_PRE(0x1e4,DX,CX,AX) \
+ PRECALC_21(Y3) \
+ CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_62 \
+ CALC_F2_PRE(0x1e8,AX,DX,DI) \
+ CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_63 \
+ CALC_F2_PRE(0x1ec,DI,AX,SI) \
+ PRECALC_23(Y3,0x20,0xe0) \
+ CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_64 \
+ CALC_F2_PRE(0x200,SI,DI,BX) \
+ PRECALC_32(Y5,Y3) \
+ CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_65 \
+ CALC_F2_PRE(0x204,BX,SI,CX) \
+ PRECALC_33(Y14,Y15) \
+ CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_66 \
+ CALC_F2_PRE(0x208,CX,BX,DX) \
+ PRECALC_34(Y8) \
+ CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_67 \
+ CALC_F2_PRE(0x20c,DX,CX,AX) \
+ PRECALC_35(Y15) \
+ CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_68 \
+ CALC_F2_PRE(0x220,AX,DX,DI) \
+ PRECALC_36(Y15) \
+ CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_69 \
+ CALC_F2_PRE(0x224,DI,AX,SI) \
+ PRECALC_37(Y15) \
+ CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_70 \
+ CALC_F2_PRE(0x228,SI,DI,BX) \
+ CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_71 \
+ CALC_F2_PRE(0x22c,BX,SI,CX) \
+ PRECALC_39(Y15,0x20,0x100) \
+ CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_72 \
+ CALC_F2_PRE(0x240,CX,BX,DX) \
+ PRECALC_32(Y3,Y15) \
+ CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_73 \
+ CALC_F2_PRE(0x244,DX,CX,AX) \
+ PRECALC_33(Y13,Y14) \
+ CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_74 \
+ CALC_F2_PRE(0x248,AX,DX,DI) \
+ PRECALC_34(Y7) \
+ CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_75 \
+ CALC_F2_PRE(0x24c,DI,AX,SI) \
+ PRECALC_35(Y14) \
+ CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_76 \
+ CALC_F2_PRE(0x260,SI,DI,BX) \
+ PRECALC_36(Y14) \
+ CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_77 \
+ CALC_F2_PRE(0x264,BX,SI,CX) \
+ PRECALC_37(Y14) \
+ CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_78 \
+ CALC_F2_PRE(0x268,CX,BX,DX) \
+ CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_79 \
+ ADDL 0x26c(R15), AX \
+ LEAL (AX)(CX*1), AX \
+ RORXL $0x1b, DX, R12 \
+ PRECALC_39(Y14,0x20,0x120) \
+ ADDL R12, AX
+
+// Similar to CALC_0
+#define CALC_80 \
+ MOVL CX, DX \
+ RORXL $2, CX, CX \
+ ANDNL SI, DX, BP \
+ ANDL BX, DX \
+ XORL BP, DX \
+ CALC_F1_PRE(0x10,AX,DX,BX,DI) \
+ PRECALC_32(Y15,Y14) \
+ CALC_F1_POST(AX,CX,DI)
+
+#define CALC_81 \
+ CALC_F1_PRE(0x14,DI,AX,CX,SI) \
+ PRECALC_33(Y12,Y13) \
+ CALC_F1_POST(DI,DX,SI)
+
+#define CALC_82 \
+ CALC_F1_PRE(0x18,SI,DI,DX,BX) \
+ PRECALC_34(Y5) \
+ CALC_F1_POST(SI,AX,BX)
+
+#define CALC_83 \
+ CALC_F1_PRE(0x1c,BX,SI,AX,CX) \
+ PRECALC_35(Y13) \
+ CALC_F1_POST(BX,DI,CX)
+
+#define CALC_84 \
+ CALC_F1_PRE(0x30,CX,BX,DI,DX) \
+ PRECALC_36(Y13) \
+ CALC_F1_POST(CX,SI,DX)
+
+#define CALC_85 \
+ CALC_F1_PRE(0x34,DX,CX,SI,AX) \
+ PRECALC_37(Y13) \
+ CALC_F1_POST(DX,BX,AX)
+
+#define CALC_86 \
+ CALC_F1_PRE(0x38,AX,DX,BX,DI) \
+ CALC_F1_POST(AX,CX,DI)
+
+#define CALC_87 \
+ CALC_F1_PRE(0x3c,DI,AX,CX,SI) \
+ PRECALC_39(Y13,0x40,0x140) \
+ CALC_F1_POST(DI,DX,SI)
+
+#define CALC_88 \
+ CALC_F1_PRE(0x50,SI,DI,DX,BX) \
+ PRECALC_32(Y14,Y13) \
+ CALC_F1_POST(SI,AX,BX)
+
+#define CALC_89 \
+ CALC_F1_PRE(0x54,BX,SI,AX,CX) \
+ PRECALC_33(Y8,Y12) \
+ CALC_F1_POST(BX,DI,CX)
+
+#define CALC_90 \
+ CALC_F1_PRE(0x58,CX,BX,DI,DX) \
+ PRECALC_34(Y3) \
+ CALC_F1_POST(CX,SI,DX)
+
+#define CALC_91 \
+ CALC_F1_PRE(0x5c,DX,CX,SI,AX) \
+ PRECALC_35(Y12) \
+ CALC_F1_POST(DX,BX,AX)
+
+#define CALC_92 \
+ CALC_F1_PRE(0x70,AX,DX,BX,DI) \
+ PRECALC_36(Y12) \
+ CALC_F1_POST(AX,CX,DI)
+
+#define CALC_93 \
+ CALC_F1_PRE(0x74,DI,AX,CX,SI) \
+ PRECALC_37(Y12) \
+ CALC_F1_POST(DI,DX,SI)
+
+#define CALC_94 \
+ CALC_F1_PRE(0x78,SI,DI,DX,BX) \
+ CALC_F1_POST(SI,AX,BX)
+
+#define CALC_95 \
+ CALC_F1_PRE(0x7c,BX,SI,AX,CX) \
+ PRECALC_39(Y12,0x40,0x160) \
+ CALC_F1_POST(BX,DI,CX)
+
+#define CALC_96 \
+ CALC_F1_PRE(0x90,CX,BX,DI,DX) \
+ PRECALC_32(Y13,Y12) \
+ CALC_F1_POST(CX,SI,DX)
+
+#define CALC_97 \
+ CALC_F1_PRE(0x94,DX,CX,SI,AX) \
+ PRECALC_33(Y7,Y8) \
+ CALC_F1_POST(DX,BX,AX)
+
+#define CALC_98 \
+ CALC_F1_PRE(0x98,AX,DX,BX,DI) \
+ PRECALC_34(Y15) \
+ CALC_F1_POST(AX,CX,DI)
+
+#define CALC_99 \
+ CALC_F2_PRE(0x9c,DI,AX,SI) \
+ PRECALC_35(Y8) \
+ CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_100 \
+ CALC_F2_PRE(0xb0,SI,DI,BX) \
+ PRECALC_36(Y8) \
+ CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_101 \
+ CALC_F2_PRE(0xb4,BX,SI,CX) \
+ PRECALC_37(Y8) \
+ CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_102 \
+ CALC_F2_PRE(0xb8,CX,BX,DX) \
+ CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_103 \
+ CALC_F2_PRE(0xbc,DX,CX,AX) \
+ PRECALC_39(Y8,0x40,0x180) \
+ CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_104 \
+ CALC_F2_PRE(0xd0,AX,DX,DI) \
+ PRECALC_32(Y12,Y8) \
+ CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_105 \
+ CALC_F2_PRE(0xd4,DI,AX,SI) \
+ PRECALC_33(Y5,Y7) \
+ CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_106 \
+ CALC_F2_PRE(0xd8,SI,DI,BX) \
+ PRECALC_34(Y14) \
+ CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_107 \
+ CALC_F2_PRE(0xdc,BX,SI,CX) \
+ PRECALC_35(Y7) \
+ CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_108 \
+ CALC_F2_PRE(0xf0,CX,BX,DX) \
+ PRECALC_36(Y7) \
+ CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_109 \
+ CALC_F2_PRE(0xf4,DX,CX,AX) \
+ PRECALC_37(Y7) \
+ CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_110 \
+ CALC_F2_PRE(0xf8,AX,DX,DI) \
+ CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_111 \
+ CALC_F2_PRE(0xfc,DI,AX,SI) \
+ PRECALC_39(Y7,0x40,0x1a0) \
+ CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_112 \
+ CALC_F2_PRE(0x110,SI,DI,BX) \
+ PRECALC_32(Y8,Y7) \
+ CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_113 \
+ CALC_F2_PRE(0x114,BX,SI,CX) \
+ PRECALC_33(Y3,Y5) \
+ CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_114 \
+ CALC_F2_PRE(0x118,CX,BX,DX) \
+ PRECALC_34(Y13) \
+ CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_115 \
+ CALC_F2_PRE(0x11c,DX,CX,AX) \
+ PRECALC_35(Y5) \
+ CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_116 \
+ CALC_F2_PRE(0x130,AX,DX,DI) \
+ PRECALC_36(Y5) \
+ CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_117 \
+ CALC_F2_PRE(0x134,DI,AX,SI) \
+ PRECALC_37(Y5) \
+ CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_118 \
+ CALC_F2_PRE(0x138,SI,DI,BX) \
+ CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_119 \
+ CALC_F3_PRE(0x13c,CX) \
+ PRECALC_39(Y5,0x40,0x1c0) \
+ CALC_F3_POST(BX,DI,AX,CX,SI)
+
+#define CALC_120 \
+ CALC_F3_PRE(0x150,DX) \
+ PRECALC_32(Y7,Y5) \
+ CALC_F3_POST(CX,SI,DI,DX,BX)
+
+#define CALC_121 \
+ CALC_F3_PRE(0x154,AX) \
+ PRECALC_33(Y15,Y3) \
+ CALC_F3_POST(DX,BX,SI,AX,CX)
+
+#define CALC_122 \
+ CALC_F3_PRE(0x158,DI) \
+ PRECALC_34(Y12) \
+ CALC_F3_POST(AX,CX,BX,DI,DX)
+
+#define CALC_123 \
+ CALC_F3_PRE(0x15c,SI) \
+ PRECALC_35(Y3) \
+ CALC_F3_POST(DI,DX,CX,SI,AX)
+
+#define CALC_124 \
+ CALC_F3_PRE(0x170,BX) \
+ PRECALC_36(Y3) \
+ CALC_F3_POST(SI,AX,DX,BX,DI)
+
+#define CALC_125 \
+ CALC_F3_PRE(0x174,CX) \
+ PRECALC_37(Y3) \
+ CALC_F3_POST(BX,DI,AX,CX,SI)
+
+#define CALC_126 \
+ CALC_F3_PRE(0x178,DX) \
+ CALC_F3_POST(CX,SI,DI,DX,BX)
+
+#define CALC_127 \
+ CALC_F3_PRE(0x17c,AX) \
+ PRECALC_39(Y3,0x60,0x1e0) \
+ CALC_F3_POST(DX,BX,SI,AX,CX)
+
+#define CALC_128 \
+ CALC_F3_PRE(0x190,DI) \
+ PRECALC_32(Y5,Y3) \
+ CALC_F3_POST(AX,CX,BX,DI,DX)
+
+#define CALC_129 \
+ CALC_F3_PRE(0x194,SI) \
+ PRECALC_33(Y14,Y15) \
+ CALC_F3_POST(DI,DX,CX,SI,AX)
+
+#define CALC_130 \
+ CALC_F3_PRE(0x198,BX) \
+ PRECALC_34(Y8) \
+ CALC_F3_POST(SI,AX,DX,BX,DI)
+
+#define CALC_131 \
+ CALC_F3_PRE(0x19c,CX) \
+ PRECALC_35(Y15) \
+ CALC_F3_POST(BX,DI,AX,CX,SI)
+
+#define CALC_132 \
+ CALC_F3_PRE(0x1b0,DX) \
+ PRECALC_36(Y15) \
+ CALC_F3_POST(CX,SI,DI,DX,BX)
+
+#define CALC_133 \
+ CALC_F3_PRE(0x1b4,AX) \
+ PRECALC_37(Y15) \
+ CALC_F3_POST(DX,BX,SI,AX,CX)
+
+#define CALC_134 \
+ CALC_F3_PRE(0x1b8,DI) \
+ CALC_F3_POST(AX,CX,BX,DI,DX)
+
+#define CALC_135 \
+ CALC_F3_PRE(0x1bc,SI) \
+ PRECALC_39(Y15,0x60,0x200) \
+ CALC_F3_POST(DI,DX,CX,SI,AX)
+
+#define CALC_136 \
+ CALC_F3_PRE(0x1d0,BX) \
+ PRECALC_32(Y3,Y15) \
+ CALC_F3_POST(SI,AX,DX,BX,DI)
+
+#define CALC_137 \
+ CALC_F3_PRE(0x1d4,CX) \
+ PRECALC_33(Y13,Y14) \
+ CALC_F3_POST(BX,DI,AX,CX,SI)
+
+#define CALC_138 \
+ CALC_F3_PRE(0x1d8,DX) \
+ PRECALC_34(Y7) \
+ CALC_F3_POST(CX,SI,DI,DX,BX)
+
+#define CALC_139 \
+ CALC_F2_PRE(0x1dc,DX,CX,AX) \
+ PRECALC_35(Y14) \
+ CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_140 \
+ CALC_F2_PRE(0x1f0,AX,DX,DI) \
+ PRECALC_36(Y14) \
+ CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_141 \
+ CALC_F2_PRE(0x1f4,DI,AX,SI) \
+ PRECALC_37(Y14) \
+ CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_142 \
+ CALC_F2_PRE(0x1f8,SI,DI,BX) \
+ CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_143 \
+ CALC_F2_PRE(0x1fc,BX,SI,CX) \
+ PRECALC_39(Y14,0x60,0x220) \
+ CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_144 \
+ CALC_F2_PRE(0x210,CX,BX,DX) \
+ PRECALC_32(Y15,Y14) \
+ CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_145 \
+ CALC_F2_PRE(0x214,DX,CX,AX) \
+ PRECALC_33(Y12,Y13) \
+ CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_146 \
+ CALC_F2_PRE(0x218,AX,DX,DI) \
+ PRECALC_34(Y5) \
+ CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_147 \
+ CALC_F2_PRE(0x21c,DI,AX,SI) \
+ PRECALC_35(Y13) \
+ CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_148 \
+ CALC_F2_PRE(0x230,SI,DI,BX) \
+ PRECALC_36(Y13) \
+ CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_149 \
+ CALC_F2_PRE(0x234,BX,SI,CX) \
+ PRECALC_37(Y13) \
+ CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_150 \
+ CALC_F2_PRE(0x238,CX,BX,DX) \
+ CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_151 \
+ CALC_F2_PRE(0x23c,DX,CX,AX) \
+ PRECALC_39(Y13,0x60,0x240) \
+ CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_152 \
+ CALC_F2_PRE(0x250,AX,DX,DI) \
+ PRECALC_32(Y14,Y13) \
+ CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_153 \
+ CALC_F2_PRE(0x254,DI,AX,SI) \
+ PRECALC_33(Y8,Y12) \
+ CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_154 \
+ CALC_F2_PRE(0x258,SI,DI,BX) \
+ PRECALC_34(Y3) \
+ CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_155 \
+ CALC_F2_PRE(0x25c,BX,SI,CX) \
+ PRECALC_35(Y12) \
+ CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_156 \
+ CALC_F2_PRE(0x270,CX,BX,DX) \
+ PRECALC_36(Y12) \
+ CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_157 \
+ CALC_F2_PRE(0x274,DX,CX,AX) \
+ PRECALC_37(Y12) \
+ CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_158 \
+ CALC_F2_PRE(0x278,AX,DX,DI) \
+ CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_159 \
+ ADDL 0x27c(R15),SI \
+ LEAL (SI)(AX*1), SI \
+ RORXL $0x1b, DI, R12 \
+ PRECALC_39(Y12,0x60,0x260) \
+ ADDL R12, SI
+
+
+
+#define CALC \
+ MOVL (R9), CX \
+ MOVL 4(R9), SI \
+ MOVL 8(R9), DI \
+ MOVL 12(R9), AX \
+ MOVL 16(R9), DX \
+ MOVQ SP, R14 \
+ LEAQ (2*4*80+32)(SP), R15 \
+ PRECALC \ // Precalc WK for first 2 blocks
+ XCHGQ R15, R14 \
+loop: \ // this loops is unrolled
+ CMPQ R10, R8 \ // we use R8 value (set below) as a signal of a last block
+ JNE begin \
+ VZEROUPPER \
+ RET \
+begin: \
+ CALC_0 \
+ CALC_1 \
+ CALC_2 \
+ CALC_3 \
+ CALC_4 \
+ CALC_5 \
+ CALC_6 \
+ CALC_7 \
+ CALC_8 \
+ CALC_9 \
+ CALC_10 \
+ CALC_11 \
+ CALC_12 \
+ CALC_13 \
+ CALC_14 \
+ CALC_15 \
+ CALC_16 \
+ CALC_17 \
+ CALC_18 \
+ CALC_19 \
+ CALC_20 \
+ CALC_21 \
+ CALC_22 \
+ CALC_23 \
+ CALC_24 \
+ CALC_25 \
+ CALC_26 \
+ CALC_27 \
+ CALC_28 \
+ CALC_29 \
+ CALC_30 \
+ CALC_31 \
+ CALC_32 \
+ CALC_33 \
+ CALC_34 \
+ CALC_35 \
+ CALC_36 \
+ CALC_37 \
+ CALC_38 \
+ CALC_39 \
+ CALC_40 \
+ CALC_41 \
+ CALC_42 \
+ CALC_43 \
+ CALC_44 \
+ CALC_45 \
+ CALC_46 \
+ CALC_47 \
+ CALC_48 \
+ CALC_49 \
+ CALC_50 \
+ CALC_51 \
+ CALC_52 \
+ CALC_53 \
+ CALC_54 \
+ CALC_55 \
+ CALC_56 \
+ CALC_57 \
+ CALC_58 \
+ CALC_59 \
+ ADDQ $128, R10 \ // move to next even-64-byte block
+ CMPQ R10, R11 \ // is current block the last one?
+ CMOVQCC R8, R10 \ // signal the last iteration smartly
+ CALC_60 \
+ CALC_61 \
+ CALC_62 \
+ CALC_63 \
+ CALC_64 \
+ CALC_65 \
+ CALC_66 \
+ CALC_67 \
+ CALC_68 \
+ CALC_69 \
+ CALC_70 \
+ CALC_71 \
+ CALC_72 \
+ CALC_73 \
+ CALC_74 \
+ CALC_75 \
+ CALC_76 \
+ CALC_77 \
+ CALC_78 \
+ CALC_79 \
+ UPDATE_HASH(AX,DX,BX,SI,DI) \
+ CMPQ R10, R8 \ // is current block the last one?
+ JE loop\
+ MOVL DX, CX \
+ CALC_80 \
+ CALC_81 \
+ CALC_82 \
+ CALC_83 \
+ CALC_84 \
+ CALC_85 \
+ CALC_86 \
+ CALC_87 \
+ CALC_88 \
+ CALC_89 \
+ CALC_90 \
+ CALC_91 \
+ CALC_92 \
+ CALC_93 \
+ CALC_94 \
+ CALC_95 \
+ CALC_96 \
+ CALC_97 \
+ CALC_98 \
+ CALC_99 \
+ CALC_100 \
+ CALC_101 \
+ CALC_102 \
+ CALC_103 \
+ CALC_104 \
+ CALC_105 \
+ CALC_106 \
+ CALC_107 \
+ CALC_108 \
+ CALC_109 \
+ CALC_110 \
+ CALC_111 \
+ CALC_112 \
+ CALC_113 \
+ CALC_114 \
+ CALC_115 \
+ CALC_116 \
+ CALC_117 \
+ CALC_118 \
+ CALC_119 \
+ CALC_120 \
+ CALC_121 \
+ CALC_122 \
+ CALC_123 \
+ CALC_124 \
+ CALC_125 \
+ CALC_126 \
+ CALC_127 \
+ CALC_128 \
+ CALC_129 \
+ CALC_130 \
+ CALC_131 \
+ CALC_132 \
+ CALC_133 \
+ CALC_134 \
+ CALC_135 \
+ CALC_136 \
+ CALC_137 \
+ CALC_138 \
+ CALC_139 \
+ ADDQ $128, R13 \ //move to next even-64-byte block
+ CMPQ R13, R11 \ //is current block the last one?
+ CMOVQCC R8, R10 \
+ CALC_140 \
+ CALC_141 \
+ CALC_142 \
+ CALC_143 \
+ CALC_144 \
+ CALC_145 \
+ CALC_146 \
+ CALC_147 \
+ CALC_148 \
+ CALC_149 \
+ CALC_150 \
+ CALC_151 \
+ CALC_152 \
+ CALC_153 \
+ CALC_154 \
+ CALC_155 \
+ CALC_156 \
+ CALC_157 \
+ CALC_158 \
+ CALC_159 \
+ UPDATE_HASH(SI,DI,DX,CX,BX) \
+ MOVL SI, R12 \ //Reset state for AVX2 reg permutation
+ MOVL DI, SI \
+ MOVL DX, DI \
+ MOVL BX, DX \
+ MOVL CX, AX \
+ MOVL R12, CX \
+ XCHGQ R15, R14 \
+ JMP loop
+
+
+
+TEXT ·blockAVX2(SB),$1408-32
+
+ MOVQ dig+0(FP), DI
+ MOVQ p_base+8(FP), SI
+ MOVQ p_len+16(FP), DX
+ SHRQ $6, DX
+ SHLQ $6, DX
+
+ MOVQ $K_XMM_AR<>(SB), R8
+
+ MOVQ DI, R9
+ MOVQ SI, R10
+ LEAQ 64(SI), R13
+
+ ADDQ SI, DX
+ ADDQ $64, DX
+ MOVQ DX, R11
+
+ CMPQ R13, R11
+ CMOVQCC R8, R13
+
+ MOVQ $BSWAP_SHUFB_CTL<>(SB), R8
+ VMOVDQU (R8), Y10
+ MOVQ $K_XMM_AR<>(SB), R8 //restore R8
+
+ CALC // RET is inside macros
+
+
+// func checkAVX2() bool
+// returns whether AVX2 is supported
+TEXT ·checkAVX2(SB),NOSPLIT,$0
+ CMPB runtime·support_avx2(SB), $1
+ JE has
+ MOVB $0, ret+0(FP)
+ RET
+has:
+ MOVB $1, ret+0(FP)
+ RET
+
+
+DATA K_XMM_AR<>+0x00(SB)/4,$0x5a827999
+DATA K_XMM_AR<>+0x04(SB)/4,$0x5a827999
+DATA K_XMM_AR<>+0x08(SB)/4,$0x5a827999
+DATA K_XMM_AR<>+0x0c(SB)/4,$0x5a827999
+DATA K_XMM_AR<>+0x10(SB)/4,$0x5a827999
+DATA K_XMM_AR<>+0x14(SB)/4,$0x5a827999
+DATA K_XMM_AR<>+0x18(SB)/4,$0x5a827999
+DATA K_XMM_AR<>+0x1c(SB)/4,$0x5a827999
+DATA K_XMM_AR<>+0x20(SB)/4,$0x6ed9eba1
+DATA K_XMM_AR<>+0x24(SB)/4,$0x6ed9eba1
+DATA K_XMM_AR<>+0x28(SB)/4,$0x6ed9eba1
+DATA K_XMM_AR<>+0x2c(SB)/4,$0x6ed9eba1
+DATA K_XMM_AR<>+0x30(SB)/4,$0x6ed9eba1
+DATA K_XMM_AR<>+0x34(SB)/4,$0x6ed9eba1
+DATA K_XMM_AR<>+0x38(SB)/4,$0x6ed9eba1
+DATA K_XMM_AR<>+0x3c(SB)/4,$0x6ed9eba1
+DATA K_XMM_AR<>+0x40(SB)/4,$0x8f1bbcdc
+DATA K_XMM_AR<>+0x44(SB)/4,$0x8f1bbcdc
+DATA K_XMM_AR<>+0x48(SB)/4,$0x8f1bbcdc
+DATA K_XMM_AR<>+0x4c(SB)/4,$0x8f1bbcdc
+DATA K_XMM_AR<>+0x50(SB)/4,$0x8f1bbcdc
+DATA K_XMM_AR<>+0x54(SB)/4,$0x8f1bbcdc
+DATA K_XMM_AR<>+0x58(SB)/4,$0x8f1bbcdc
+DATA K_XMM_AR<>+0x5c(SB)/4,$0x8f1bbcdc
+DATA K_XMM_AR<>+0x60(SB)/4,$0xca62c1d6
+DATA K_XMM_AR<>+0x64(SB)/4,$0xca62c1d6
+DATA K_XMM_AR<>+0x68(SB)/4,$0xca62c1d6
+DATA K_XMM_AR<>+0x6c(SB)/4,$0xca62c1d6
+DATA K_XMM_AR<>+0x70(SB)/4,$0xca62c1d6
+DATA K_XMM_AR<>+0x74(SB)/4,$0xca62c1d6
+DATA K_XMM_AR<>+0x78(SB)/4,$0xca62c1d6
+DATA K_XMM_AR<>+0x7c(SB)/4,$0xca62c1d6
+GLOBL K_XMM_AR<>(SB),RODATA,$128
+
+DATA BSWAP_SHUFB_CTL<>+0x00(SB)/4,$0x00010203
+DATA BSWAP_SHUFB_CTL<>+0x04(SB)/4,$0x04050607
+DATA BSWAP_SHUFB_CTL<>+0x08(SB)/4,$0x08090a0b
+DATA BSWAP_SHUFB_CTL<>+0x0c(SB)/4,$0x0c0d0e0f
+DATA BSWAP_SHUFB_CTL<>+0x10(SB)/4,$0x00010203
+DATA BSWAP_SHUFB_CTL<>+0x14(SB)/4,$0x04050607
+DATA BSWAP_SHUFB_CTL<>+0x18(SB)/4,$0x08090a0b
+DATA BSWAP_SHUFB_CTL<>+0x1c(SB)/4,$0x0c0d0e0f
+GLOBL BSWAP_SHUFB_CTL<>(SB),RODATA,$32
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build amd64 amd64p32 arm 386 s390x
+// +build amd64p32 arm 386 s390x
package sha1
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// The algorithm is detailed in FIPS 180-4:
//
// http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
-//
+
+// The avx2-version is described in an Intel White-Paper:
+// "Fast SHA-256 Implementations on Intel Architecture Processors"
+// To find it, surf to http://www.intel.com/p/en_US/embedded
+// and search for that title.
+// AVX2 version by Intel, same algorithm as code in Linux kernel:
+// https://github.com/torvalds/linux/blob/master/arch/x86/crypto/sha256-avx2-asm.S
+// by
+// James Guilford <james.guilford@intel.com>
+// Kirk Yap <kirk.s.yap@intel.com>
+// Tim Chen <tim.c.chen@linux.intel.com>
+
// Wt = Mt; for 0 <= t <= 15
// Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63
//
MSGSCHEDULE1(index); \
SHA256ROUND(index, const, a, b, c, d, e, f, g, h)
-TEXT ·block(SB),0,$264-32
- MOVQ p_base+8(FP), SI
- MOVQ p_len+16(FP), DX
- SHRQ $6, DX
- SHLQ $6, DX
-
- LEAQ (SI)(DX*1), DI
- MOVQ DI, 256(SP)
- CMPQ SI, DI
- JEQ end
-
- MOVQ dig+0(FP), BP
- MOVL (0*4)(BP), R8 // a = H0
- MOVL (1*4)(BP), R9 // b = H1
- MOVL (2*4)(BP), R10 // c = H2
- MOVL (3*4)(BP), R11 // d = H3
- MOVL (4*4)(BP), R12 // e = H4
- MOVL (5*4)(BP), R13 // f = H5
- MOVL (6*4)(BP), R14 // g = H6
- MOVL (7*4)(BP), R15 // h = H7
+
+// Definitions for AVX2 version
+
+// addm (mem), reg
+// Add reg to mem using reg-mem add and store
+#define addm(P1, P2) \
+ ADDL P2, P1; \
+ MOVL P1, P2
+
+#define XDWORD0 Y4
+#define XDWORD1 Y5
+#define XDWORD2 Y6
+#define XDWORD3 Y7
+
+#define XWORD0 X4
+#define XWORD1 X5
+#define XWORD2 X6
+#define XWORD3 X7
+
+#define XTMP0 Y0
+#define XTMP1 Y1
+#define XTMP2 Y2
+#define XTMP3 Y3
+#define XTMP4 Y8
+#define XTMP5 Y11
+
+#define XFER Y9
+
+#define BYTE_FLIP_MASK Y13 // mask to convert LE -> BE
+#define X_BYTE_FLIP_MASK X13
+
+#define NUM_BYTES DX
+#define INP DI
+
+#define CTX SI // Beginning of digest in memory (a, b, c, ... , h)
+
+#define a AX
+#define b BX
+#define c CX
+#define d R8
+#define e DX
+#define f R9
+#define g R10
+#define h R11
+
+#define old_h R11
+
+#define TBL BP
+
+#define SRND SI // SRND is same register as CTX
+
+#define T1 R12
+
+#define y0 R13
+#define y1 R14
+#define y2 R15
+#define y3 DI
+
+// Offsets
+#define XFER_SIZE 2*64*4
+#define INP_END_SIZE 8
+#define INP_SIZE 8
+#define TMP_SIZE 4
+
+#define _XFER 0
+#define _INP_END _XFER + XFER_SIZE
+#define _INP _INP_END + INP_END_SIZE
+#define _TMP _INP + INP_SIZE
+#define STACK_SIZE _TMP + TMP_SIZE
+
+#define ROUND_AND_SCHED_N_0(disp, a, b, c, d, e, f, g, h, XDWORD0, XDWORD1, XDWORD2, XDWORD3) \
+ ; \ // ############################# RND N + 0 ############################//
+ MOVL a, y3; \ // y3 = a // MAJA
+ RORXL $25, e, y0; \ // y0 = e >> 25 // S1A
+ RORXL $11, e, y1; \ // y1 = e >> 11 // S1B
+ ; \
+ ADDL (disp + 0*4)(SP)(SRND*1), h; \ // h = k + w + h // disp = k + w
+ ORL c, y3; \ // y3 = a|c // MAJA
+ VPALIGNR $4, XDWORD2, XDWORD3, XTMP0; \ // XTMP0 = W[-7]
+ MOVL f, y2; \ // y2 = f // CH
+ RORXL $13, a, T1; \ // T1 = a >> 13 // S0B
+ ; \
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1
+ XORL g, y2; \ // y2 = f^g // CH
+ VPADDD XDWORD0, XTMP0, XTMP0; \ // XTMP0 = W[-7] + W[-16] // y1 = (e >> 6) // S1
+ RORXL $6, e, y1; \ // y1 = (e >> 6) // S1
+ ; \
+ ANDL e, y2; \ // y2 = (f^g)&e // CH
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1
+ RORXL $22, a, y1; \ // y1 = a >> 22 // S0A
+ ADDL h, d; \ // d = k + w + h + d // --
+ ; \
+ ANDL b, y3; \ // y3 = (a|c)&b // MAJA
+ VPALIGNR $4, XDWORD0, XDWORD1, XTMP1; \ // XTMP1 = W[-15]
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0
+ RORXL $2, a, T1; \ // T1 = (a >> 2) // S0
+ ; \
+ XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH
+ VPSRLD $7, XTMP1, XTMP2; \
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0
+ MOVL a, T1; \ // T1 = a // MAJB
+ ANDL c, T1; \ // T1 = a&c // MAJB
+ ; \
+ ADDL y0, y2; \ // y2 = S1 + CH // --
+ VPSLLD $(32-7), XTMP1, XTMP3; \
+ ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ
+ ADDL y1, h; \ // h = k + w + h + S0 // --
+ ; \
+ ADDL y2, d; \ // d = k + w + h + d + S1 + CH = d + t1 // --
+ VPOR XTMP2, XTMP3, XTMP3; \ // XTMP3 = W[-15] ror 7
+ ; \
+ VPSRLD $18, XTMP1, XTMP2; \
+ ADDL y2, h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0// --
+ ADDL y3, h // h = t1 + S0 + MAJ // --
+
+#define ROUND_AND_SCHED_N_1(disp, a, b, c, d, e, f, g, h, XDWORD0, XDWORD1, XDWORD2, XDWORD3) \
+ ; \ // ################################### RND N + 1 ############################
+ ; \
+ MOVL a, y3; \ // y3 = a // MAJA
+ RORXL $25, e, y0; \ // y0 = e >> 25 // S1A
+ RORXL $11, e, y1; \ // y1 = e >> 11 // S1B
+ ADDL (disp + 1*4)(SP)(SRND*1), h; \ // h = k + w + h // --
+ ORL c, y3; \ // y3 = a|c // MAJA
+ ; \
+ VPSRLD $3, XTMP1, XTMP4; \ // XTMP4 = W[-15] >> 3
+ MOVL f, y2; \ // y2 = f // CH
+ RORXL $13, a, T1; \ // T1 = a >> 13 // S0B
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1
+ XORL g, y2; \ // y2 = f^g // CH
+ ; \
+ RORXL $6, e, y1; \ // y1 = (e >> 6) // S1
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1
+ RORXL $22, a, y1; \ // y1 = a >> 22 // S0A
+ ANDL e, y2; \ // y2 = (f^g)&e // CH
+ ADDL h, d; \ // d = k + w + h + d // --
+ ; \
+ VPSLLD $(32-18), XTMP1, XTMP1; \
+ ANDL b, y3; \ // y3 = (a|c)&b // MAJA
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0
+ ; \
+ VPXOR XTMP1, XTMP3, XTMP3; \
+ RORXL $2, a, T1; \ // T1 = (a >> 2) // S0
+ XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH
+ ; \
+ VPXOR XTMP2, XTMP3, XTMP3; \ // XTMP3 = W[-15] ror 7 ^ W[-15] ror 18
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0
+ MOVL a, T1; \ // T1 = a // MAJB
+ ANDL c, T1; \ // T1 = a&c // MAJB
+ ADDL y0, y2; \ // y2 = S1 + CH // --
+ ; \
+ VPXOR XTMP4, XTMP3, XTMP1; \ // XTMP1 = s0
+ VPSHUFD $-6, XDWORD3, XTMP2; \ // XTMP2 = W[-2] {BBAA}
+ ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ
+ ADDL y1, h; \ // h = k + w + h + S0 // --
+ ; \
+ VPADDD XTMP1, XTMP0, XTMP0; \ // XTMP0 = W[-16] + W[-7] + s0
+ ADDL y2, d; \ // d = k + w + h + d + S1 + CH = d + t1 // --
+ ADDL y2, h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0// --
+ ADDL y3, h; \ // h = t1 + S0 + MAJ // --
+ ; \
+ VPSRLD $10, XTMP2, XTMP4 // XTMP4 = W[-2] >> 10 {BBAA}
+
+#define ROUND_AND_SCHED_N_2(disp, a, b, c, d, e, f, g, h, XDWORD0, XDWORD1, XDWORD2, XDWORD3) \
+ ; \ // ################################### RND N + 2 ############################
+ ; \
+ MOVL a, y3; \ // y3 = a // MAJA
+ RORXL $25, e, y0; \ // y0 = e >> 25 // S1A
+ ADDL (disp + 2*4)(SP)(SRND*1), h; \ // h = k + w + h // --
+ ; \
+ VPSRLQ $19, XTMP2, XTMP3; \ // XTMP3 = W[-2] ror 19 {xBxA}
+ RORXL $11, e, y1; \ // y1 = e >> 11 // S1B
+ ORL c, y3; \ // y3 = a|c // MAJA
+ MOVL f, y2; \ // y2 = f // CH
+ XORL g, y2; \ // y2 = f^g // CH
+ ; \
+ RORXL $13, a, T1; \ // T1 = a >> 13 // S0B
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1
+ VPSRLQ $17, XTMP2, XTMP2; \ // XTMP2 = W[-2] ror 17 {xBxA}
+ ANDL e, y2; \ // y2 = (f^g)&e // CH
+ ; \
+ RORXL $6, e, y1; \ // y1 = (e >> 6) // S1
+ VPXOR XTMP3, XTMP2, XTMP2; \
+ ADDL h, d; \ // d = k + w + h + d // --
+ ANDL b, y3; \ // y3 = (a|c)&b // MAJA
+ ; \
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1
+ RORXL $22, a, y1; \ // y1 = a >> 22 // S0A
+ VPXOR XTMP2, XTMP4, XTMP4; \ // XTMP4 = s1 {xBxA}
+ XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH
+ ; \
+ MOVL f, _TMP(SP); \
+ MOVQ $shuff_00BA<>(SB), f; \ // f is used to keep SHUF_00BA
+ VPSHUFB (f), XTMP4, XTMP4; \ // XTMP4 = s1 {00BA}
+ MOVL _TMP(SP), f; \ // f is restored
+ ; \
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0
+ RORXL $2, a, T1; \ // T1 = (a >> 2) // S0
+ VPADDD XTMP4, XTMP0, XTMP0; \ // XTMP0 = {..., ..., W[1], W[0]}
+ ; \
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0
+ MOVL a, T1; \ // T1 = a // MAJB
+ ANDL c, T1; \ // T1 = a&c // MAJB
+ ADDL y0, y2; \ // y2 = S1 + CH // --
+ VPSHUFD $80, XTMP0, XTMP2; \ // XTMP2 = W[-2] {DDCC}
+ ; \
+ ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ
+ ADDL y1, h; \ // h = k + w + h + S0 // --
+ ADDL y2, d; \ // d = k + w + h + d + S1 + CH = d + t1 // --
+ ADDL y2, h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0// --
+ ; \
+ ADDL y3, h // h = t1 + S0 + MAJ // --
+
+#define ROUND_AND_SCHED_N_3(disp, a, b, c, d, e, f, g, h, XDWORD0, XDWORD1, XDWORD2, XDWORD3) \
+ ; \ // ################################### RND N + 3 ############################
+ ; \
+ MOVL a, y3; \ // y3 = a // MAJA
+ RORXL $25, e, y0; \ // y0 = e >> 25 // S1A
+ RORXL $11, e, y1; \ // y1 = e >> 11 // S1B
+ ADDL (disp + 3*4)(SP)(SRND*1), h; \ // h = k + w + h // --
+ ORL c, y3; \ // y3 = a|c // MAJA
+ ; \
+ VPSRLD $10, XTMP2, XTMP5; \ // XTMP5 = W[-2] >> 10 {DDCC}
+ MOVL f, y2; \ // y2 = f // CH
+ RORXL $13, a, T1; \ // T1 = a >> 13 // S0B
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1
+ XORL g, y2; \ // y2 = f^g // CH
+ ; \
+ VPSRLQ $19, XTMP2, XTMP3; \ // XTMP3 = W[-2] ror 19 {xDxC}
+ RORXL $6, e, y1; \ // y1 = (e >> 6) // S1
+ ANDL e, y2; \ // y2 = (f^g)&e // CH
+ ADDL h, d; \ // d = k + w + h + d // --
+ ANDL b, y3; \ // y3 = (a|c)&b // MAJA
+ ; \
+ VPSRLQ $17, XTMP2, XTMP2; \ // XTMP2 = W[-2] ror 17 {xDxC}
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1
+ XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH
+ ; \
+ VPXOR XTMP3, XTMP2, XTMP2; \
+ RORXL $22, a, y1; \ // y1 = a >> 22 // S0A
+ ADDL y0, y2; \ // y2 = S1 + CH // --
+ ; \
+ VPXOR XTMP2, XTMP5, XTMP5; \ // XTMP5 = s1 {xDxC}
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0
+ ADDL y2, d; \ // d = k + w + h + d + S1 + CH = d + t1 // --
+ ; \
+ RORXL $2, a, T1; \ // T1 = (a >> 2) // S0
+ ; \
+ MOVL f, _TMP(SP); \ // Save f
+ MOVQ $shuff_DC00<>(SB), f; \ // SHUF_00DC
+ VPSHUFB (f), XTMP5, XTMP5; \ // XTMP5 = s1 {DC00}
+ MOVL _TMP(SP), f; \ // Restore f
+ ; \
+ VPADDD XTMP0, XTMP5, XDWORD0; \ // XDWORD0 = {W[3], W[2], W[1], W[0]}
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0
+ MOVL a, T1; \ // T1 = a // MAJB
+ ANDL c, T1; \ // T1 = a&c // MAJB
+ ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ
+ ; \
+ ADDL y1, h; \ // h = k + w + h + S0 // --
+ ADDL y2, h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0// --
+ ADDL y3, h // h = t1 + S0 + MAJ // --
+
+#define DO_ROUND_N_0(disp, a, b, c, d, e, f, g, h, old_h) \
+ ; \ // ################################### RND N + 0 ###########################
+ MOVL f, y2; \ // y2 = f // CH
+ RORXL $25, e, y0; \ // y0 = e >> 25 // S1A
+ RORXL $11, e, y1; \ // y1 = e >> 11 // S1B
+ XORL g, y2; \ // y2 = f^g // CH
+ ; \
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1
+ RORXL $6, e, y1; \ // y1 = (e >> 6) // S1
+ ANDL e, y2; \ // y2 = (f^g)&e // CH
+ ; \
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1
+ RORXL $13, a, T1; \ // T1 = a >> 13 // S0B
+ XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH
+ RORXL $22, a, y1; \ // y1 = a >> 22 // S0A
+ MOVL a, y3; \ // y3 = a // MAJA
+ ; \
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0
+ RORXL $2, a, T1; \ // T1 = (a >> 2) // S0
+ ADDL (disp + 0*4)(SP)(SRND*1), h; \ // h = k + w + h // --
+ ORL c, y3; \ // y3 = a|c // MAJA
+ ; \
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0
+ MOVL a, T1; \ // T1 = a // MAJB
+ ANDL b, y3; \ // y3 = (a|c)&b // MAJA
+ ANDL c, T1; \ // T1 = a&c // MAJB
+ ADDL y0, y2; \ // y2 = S1 + CH // --
+ ; \
+ ADDL h, d; \ // d = k + w + h + d // --
+ ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ
+ ADDL y1, h; \ // h = k + w + h + S0 // --
+ ADDL y2, d // d = k + w + h + d + S1 + CH = d + t1 // --
+
+#define DO_ROUND_N_1(disp, a, b, c, d, e, f, g, h, old_h) \
+ ; \ // ################################### RND N + 1 ###########################
+ ADDL y2, old_h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0 // --
+ MOVL f, y2; \ // y2 = f // CH
+ RORXL $25, e, y0; \ // y0 = e >> 25 // S1A
+ RORXL $11, e, y1; \ // y1 = e >> 11 // S1B
+ XORL g, y2; \ // y2 = f^g // CH
+ ; \
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1
+ RORXL $6, e, y1; \ // y1 = (e >> 6) // S1
+ ANDL e, y2; \ // y2 = (f^g)&e // CH
+ ADDL y3, old_h; \ // h = t1 + S0 + MAJ // --
+ ; \
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1
+ RORXL $13, a, T1; \ // T1 = a >> 13 // S0B
+ XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH
+ RORXL $22, a, y1; \ // y1 = a >> 22 // S0A
+ MOVL a, y3; \ // y3 = a // MAJA
+ ; \
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0
+ RORXL $2, a, T1; \ // T1 = (a >> 2) // S0
+ ADDL (disp + 1*4)(SP)(SRND*1), h; \ // h = k + w + h // --
+ ORL c, y3; \ // y3 = a|c // MAJA
+ ; \
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0
+ MOVL a, T1; \ // T1 = a // MAJB
+ ANDL b, y3; \ // y3 = (a|c)&b // MAJA
+ ANDL c, T1; \ // T1 = a&c // MAJB
+ ADDL y0, y2; \ // y2 = S1 + CH // --
+ ; \
+ ADDL h, d; \ // d = k + w + h + d // --
+ ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ
+ ADDL y1, h; \ // h = k + w + h + S0 // --
+ ; \
+ ADDL y2, d // d = k + w + h + d + S1 + CH = d + t1 // --
+
+#define DO_ROUND_N_2(disp, a, b, c, d, e, f, g, h, old_h) \
+ ; \ // ################################### RND N + 2 ##############################
+ ADDL y2, old_h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0// --
+ MOVL f, y2; \ // y2 = f // CH
+ RORXL $25, e, y0; \ // y0 = e >> 25 // S1A
+ RORXL $11, e, y1; \ // y1 = e >> 11 // S1B
+ XORL g, y2; \ // y2 = f^g // CH
+ ; \
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1
+ RORXL $6, e, y1; \ // y1 = (e >> 6) // S1
+ ANDL e, y2; \ // y2 = (f^g)&e // CH
+ ADDL y3, old_h; \ // h = t1 + S0 + MAJ // --
+ ; \
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1
+ RORXL $13, a, T1; \ // T1 = a >> 13 // S0B
+ XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH
+ RORXL $22, a, y1; \ // y1 = a >> 22 // S0A
+ MOVL a, y3; \ // y3 = a // MAJA
+ ; \
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0
+ RORXL $2, a, T1; \ // T1 = (a >> 2) // S0
+ ADDL (disp + 2*4)(SP)(SRND*1), h; \ // h = k + w + h // --
+ ORL c, y3; \ // y3 = a|c // MAJA
+ ; \
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0
+ MOVL a, T1; \ // T1 = a // MAJB
+ ANDL b, y3; \ // y3 = (a|c)&b // MAJA
+ ANDL c, T1; \ // T1 = a&c // MAJB
+ ADDL y0, y2; \ // y2 = S1 + CH // --
+ ; \
+ ADDL h, d; \ // d = k + w + h + d // --
+ ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ
+ ADDL y1, h; \ // h = k + w + h + S0 // --
+ ; \
+ ADDL y2, d // d = k + w + h + d + S1 + CH = d + t1 // --
+
+#define DO_ROUND_N_3(disp, a, b, c, d, e, f, g, h, old_h) \
+ ; \ // ################################### RND N + 3 ###########################
+ ADDL y2, old_h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0// --
+ MOVL f, y2; \ // y2 = f // CH
+ RORXL $25, e, y0; \ // y0 = e >> 25 // S1A
+ RORXL $11, e, y1; \ // y1 = e >> 11 // S1B
+ XORL g, y2; \ // y2 = f^g // CH
+ ; \
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1
+ RORXL $6, e, y1; \ // y1 = (e >> 6) // S1
+ ANDL e, y2; \ // y2 = (f^g)&e // CH
+ ADDL y3, old_h; \ // h = t1 + S0 + MAJ // --
+ ; \
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1
+ RORXL $13, a, T1; \ // T1 = a >> 13 // S0B
+ XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH
+ RORXL $22, a, y1; \ // y1 = a >> 22 // S0A
+ MOVL a, y3; \ // y3 = a // MAJA
+ ; \
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0
+ RORXL $2, a, T1; \ // T1 = (a >> 2) // S0
+ ADDL (disp + 3*4)(SP)(SRND*1), h; \ // h = k + w + h // --
+ ORL c, y3; \ // y3 = a|c // MAJA
+ ; \
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0
+ MOVL a, T1; \ // T1 = a // MAJB
+ ANDL b, y3; \ // y3 = (a|c)&b // MAJA
+ ANDL c, T1; \ // T1 = a&c // MAJB
+ ADDL y0, y2; \ // y2 = S1 + CH // --
+ ; \
+ ADDL h, d; \ // d = k + w + h + d // --
+ ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ
+ ADDL y1, h; \ // h = k + w + h + S0 // --
+ ; \
+ ADDL y2, d; \ // d = k + w + h + d + S1 + CH = d + t1 // --
+ ; \
+ ADDL y2, h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0// --
+ ; \
+ ADDL y3, h // h = t1 + S0 + MAJ // --
+
+TEXT ·block(SB), 0, $536-32
+ CMPB runtime·support_avx2(SB), $1
+ JE avx2
+
+ MOVQ p_base+8(FP), SI
+ MOVQ p_len+16(FP), DX
+ SHRQ $6, DX
+ SHLQ $6, DX
+
+ LEAQ (SI)(DX*1), DI
+ MOVQ DI, 256(SP)
+ CMPQ SI, DI
+ JEQ end
+
+ MOVQ dig+0(FP), BP
+ MOVL (0*4)(BP), R8 // a = H0
+ MOVL (1*4)(BP), R9 // b = H1
+ MOVL (2*4)(BP), R10 // c = H2
+ MOVL (3*4)(BP), R11 // d = H3
+ MOVL (4*4)(BP), R12 // e = H4
+ MOVL (5*4)(BP), R13 // f = H5
+ MOVL (6*4)(BP), R14 // g = H6
+ MOVL (7*4)(BP), R15 // h = H7
loop:
- MOVQ SP, BP // message schedule
+ MOVQ SP, BP
SHA256ROUND0(0, 0x428a2f98, R8, R9, R10, R11, R12, R13, R14, R15)
SHA256ROUND0(1, 0x71374491, R15, R8, R9, R10, R11, R12, R13, R14)
SHA256ROUND1(62, 0xbef9a3f7, R10, R11, R12, R13, R14, R15, R8, R9)
SHA256ROUND1(63, 0xc67178f2, R9, R10, R11, R12, R13, R14, R15, R8)
- MOVQ dig+0(FP), BP
- ADDL (0*4)(BP), R8 // H0 = a + H0
- MOVL R8, (0*4)(BP)
- ADDL (1*4)(BP), R9 // H1 = b + H1
- MOVL R9, (1*4)(BP)
- ADDL (2*4)(BP), R10 // H2 = c + H2
- MOVL R10, (2*4)(BP)
- ADDL (3*4)(BP), R11 // H3 = d + H3
- MOVL R11, (3*4)(BP)
- ADDL (4*4)(BP), R12 // H4 = e + H4
- MOVL R12, (4*4)(BP)
- ADDL (5*4)(BP), R13 // H5 = f + H5
- MOVL R13, (5*4)(BP)
- ADDL (6*4)(BP), R14 // H6 = g + H6
- MOVL R14, (6*4)(BP)
- ADDL (7*4)(BP), R15 // H7 = h + H7
- MOVL R15, (7*4)(BP)
-
- ADDQ $64, SI
- CMPQ SI, 256(SP)
- JB loop
+ MOVQ dig+0(FP), BP
+ ADDL (0*4)(BP), R8 // H0 = a + H0
+ MOVL R8, (0*4)(BP)
+ ADDL (1*4)(BP), R9 // H1 = b + H1
+ MOVL R9, (1*4)(BP)
+ ADDL (2*4)(BP), R10 // H2 = c + H2
+ MOVL R10, (2*4)(BP)
+ ADDL (3*4)(BP), R11 // H3 = d + H3
+ MOVL R11, (3*4)(BP)
+ ADDL (4*4)(BP), R12 // H4 = e + H4
+ MOVL R12, (4*4)(BP)
+ ADDL (5*4)(BP), R13 // H5 = f + H5
+ MOVL R13, (5*4)(BP)
+ ADDL (6*4)(BP), R14 // H6 = g + H6
+ MOVL R14, (6*4)(BP)
+ ADDL (7*4)(BP), R15 // H7 = h + H7
+ MOVL R15, (7*4)(BP)
+
+ ADDQ $64, SI
+ CMPQ SI, 256(SP)
+ JB loop
end:
RET
+
+avx2:
+ MOVQ dig+0(FP), CTX // d.h[8]
+ MOVQ p_base+8(FP), INP
+ MOVQ p_len+16(FP), NUM_BYTES
+
+ LEAQ -64(INP)(NUM_BYTES*1), NUM_BYTES // Pointer to the last block
+ MOVQ NUM_BYTES, _INP_END(SP)
+
+ CMPQ NUM_BYTES, INP
+ JE avx2_only_one_block
+
+ // Load initial digest
+ MOVL 0(CTX), a // a = H0
+ MOVL 4(CTX), b // b = H1
+ MOVL 8(CTX), c // c = H2
+ MOVL 12(CTX), d // d = H3
+ MOVL 16(CTX), e // e = H4
+ MOVL 20(CTX), f // f = H5
+ MOVL 24(CTX), g // g = H6
+ MOVL 28(CTX), h // h = H7
+
+avx2_loop0: // at each iteration works with one block (512 bit)
+
+ VMOVDQU (0*32)(INP), XTMP0
+ VMOVDQU (1*32)(INP), XTMP1
+ VMOVDQU (2*32)(INP), XTMP2
+ VMOVDQU (3*32)(INP), XTMP3
+
+ MOVQ $flip_mask<>(SB), BP // BYTE_FLIP_MASK
+ VMOVDQU (BP), BYTE_FLIP_MASK
+
+ // Apply Byte Flip Mask: LE -> BE
+ VPSHUFB BYTE_FLIP_MASK, XTMP0, XTMP0
+ VPSHUFB BYTE_FLIP_MASK, XTMP1, XTMP1
+ VPSHUFB BYTE_FLIP_MASK, XTMP2, XTMP2
+ VPSHUFB BYTE_FLIP_MASK, XTMP3, XTMP3
+
+ // Transpose data into high/low parts
+ VPERM2I128 $0x20, XTMP2, XTMP0, XDWORD0 // w3, w2, w1, w0
+ VPERM2I128 $0x31, XTMP2, XTMP0, XDWORD1 // w7, w6, w5, w4
+ VPERM2I128 $0x20, XTMP3, XTMP1, XDWORD2 // w11, w10, w9, w8
+ VPERM2I128 $0x31, XTMP3, XTMP1, XDWORD3 // w15, w14, w13, w12
+
+ MOVQ $K256<>(SB), TBL // Loading address of table with round-specific constants
+
+avx2_last_block_enter:
+ ADDQ $64, INP
+ MOVQ INP, _INP(SP)
+ XORQ SRND, SRND
+
+avx2_loop1: // for w0 - w47
+ // Do 4 rounds and scheduling
+ VPADDD 0*32(TBL)(SRND*1), XDWORD0, XFER
+ VMOVDQU XFER, (_XFER + 0*32)(SP)(SRND*1)
+ ROUND_AND_SCHED_N_0(_XFER + 0*32, a, b, c, d, e, f, g, h, XDWORD0, XDWORD1, XDWORD2, XDWORD3)
+ ROUND_AND_SCHED_N_1(_XFER + 0*32, h, a, b, c, d, e, f, g, XDWORD0, XDWORD1, XDWORD2, XDWORD3)
+ ROUND_AND_SCHED_N_2(_XFER + 0*32, g, h, a, b, c, d, e, f, XDWORD0, XDWORD1, XDWORD2, XDWORD3)
+ ROUND_AND_SCHED_N_3(_XFER + 0*32, f, g, h, a, b, c, d, e, XDWORD0, XDWORD1, XDWORD2, XDWORD3)
+
+ // Do 4 rounds and scheduling
+ VPADDD 1*32(TBL)(SRND*1), XDWORD1, XFER
+ VMOVDQU XFER, (_XFER + 1*32)(SP)(SRND*1)
+ ROUND_AND_SCHED_N_0(_XFER + 1*32, e, f, g, h, a, b, c, d, XDWORD1, XDWORD2, XDWORD3, XDWORD0)
+ ROUND_AND_SCHED_N_1(_XFER + 1*32, d, e, f, g, h, a, b, c, XDWORD1, XDWORD2, XDWORD3, XDWORD0)
+ ROUND_AND_SCHED_N_2(_XFER + 1*32, c, d, e, f, g, h, a, b, XDWORD1, XDWORD2, XDWORD3, XDWORD0)
+ ROUND_AND_SCHED_N_3(_XFER + 1*32, b, c, d, e, f, g, h, a, XDWORD1, XDWORD2, XDWORD3, XDWORD0)
+
+ // Do 4 rounds and scheduling
+ VPADDD 2*32(TBL)(SRND*1), XDWORD2, XFER
+ VMOVDQU XFER, (_XFER + 2*32)(SP)(SRND*1)
+ ROUND_AND_SCHED_N_0(_XFER + 2*32, a, b, c, d, e, f, g, h, XDWORD2, XDWORD3, XDWORD0, XDWORD1)
+ ROUND_AND_SCHED_N_1(_XFER + 2*32, h, a, b, c, d, e, f, g, XDWORD2, XDWORD3, XDWORD0, XDWORD1)
+ ROUND_AND_SCHED_N_2(_XFER + 2*32, g, h, a, b, c, d, e, f, XDWORD2, XDWORD3, XDWORD0, XDWORD1)
+ ROUND_AND_SCHED_N_3(_XFER + 2*32, f, g, h, a, b, c, d, e, XDWORD2, XDWORD3, XDWORD0, XDWORD1)
+
+ // Do 4 rounds and scheduling
+ VPADDD 3*32(TBL)(SRND*1), XDWORD3, XFER
+ VMOVDQU XFER, (_XFER + 3*32)(SP)(SRND*1)
+ ROUND_AND_SCHED_N_0(_XFER + 3*32, e, f, g, h, a, b, c, d, XDWORD3, XDWORD0, XDWORD1, XDWORD2)
+ ROUND_AND_SCHED_N_1(_XFER + 3*32, d, e, f, g, h, a, b, c, XDWORD3, XDWORD0, XDWORD1, XDWORD2)
+ ROUND_AND_SCHED_N_2(_XFER + 3*32, c, d, e, f, g, h, a, b, XDWORD3, XDWORD0, XDWORD1, XDWORD2)
+ ROUND_AND_SCHED_N_3(_XFER + 3*32, b, c, d, e, f, g, h, a, XDWORD3, XDWORD0, XDWORD1, XDWORD2)
+
+ ADDQ $4*32, SRND
+ CMPQ SRND, $3*4*32
+ JB avx2_loop1
+
+avx2_loop2:
+ // w48 - w63 processed with no scheduliung (last 16 rounds)
+ VPADDD 0*32(TBL)(SRND*1), XDWORD0, XFER
+ VMOVDQU XFER, (_XFER + 0*32)(SP)(SRND*1)
+ DO_ROUND_N_0(_XFER + 0*32, a, b, c, d, e, f, g, h, h)
+ DO_ROUND_N_1(_XFER + 0*32, h, a, b, c, d, e, f, g, h)
+ DO_ROUND_N_2(_XFER + 0*32, g, h, a, b, c, d, e, f, g)
+ DO_ROUND_N_3(_XFER + 0*32, f, g, h, a, b, c, d, e, f)
+
+ VPADDD 1*32(TBL)(SRND*1), XDWORD1, XFER
+ VMOVDQU XFER, (_XFER + 1*32)(SP)(SRND*1)
+ DO_ROUND_N_0(_XFER + 1*32, e, f, g, h, a, b, c, d, e)
+ DO_ROUND_N_1(_XFER + 1*32, d, e, f, g, h, a, b, c, d)
+ DO_ROUND_N_2(_XFER + 1*32, c, d, e, f, g, h, a, b, c)
+ DO_ROUND_N_3(_XFER + 1*32, b, c, d, e, f, g, h, a, b)
+
+ ADDQ $2*32, SRND
+
+ VMOVDQU XDWORD2, XDWORD0
+ VMOVDQU XDWORD3, XDWORD1
+
+ CMPQ SRND, $4*4*32
+ JB avx2_loop2
+
+ MOVQ dig+0(FP), CTX // d.h[8]
+ MOVQ _INP(SP), INP
+
+ addm( 0(CTX), a)
+ addm( 4(CTX), b)
+ addm( 8(CTX), c)
+ addm( 12(CTX), d)
+ addm( 16(CTX), e)
+ addm( 20(CTX), f)
+ addm( 24(CTX), g)
+ addm( 28(CTX), h)
+
+ CMPQ _INP_END(SP), INP
+ JB done_hash
+
+ XORQ SRND, SRND
+
+avx2_loop3: // Do second block using previously scheduled results
+ DO_ROUND_N_0(_XFER + 0*32 + 16, a, b, c, d, e, f, g, h, a)
+ DO_ROUND_N_1(_XFER + 0*32 + 16, h, a, b, c, d, e, f, g, h)
+ DO_ROUND_N_2(_XFER + 0*32 + 16, g, h, a, b, c, d, e, f, g)
+ DO_ROUND_N_3(_XFER + 0*32 + 16, f, g, h, a, b, c, d, e, f)
+
+ DO_ROUND_N_0(_XFER + 1*32 + 16, e, f, g, h, a, b, c, d, e)
+ DO_ROUND_N_1(_XFER + 1*32 + 16, d, e, f, g, h, a, b, c, d)
+ DO_ROUND_N_2(_XFER + 1*32 + 16, c, d, e, f, g, h, a, b, c)
+ DO_ROUND_N_3(_XFER + 1*32 + 16, b, c, d, e, f, g, h, a, b)
+
+ ADDQ $2*32, SRND
+ CMPQ SRND, $4*4*32
+ JB avx2_loop3
+
+ MOVQ dig+0(FP), CTX // d.h[8]
+ MOVQ _INP(SP), INP
+ ADDQ $64, INP
+
+ addm( 0(CTX), a)
+ addm( 4(CTX), b)
+ addm( 8(CTX), c)
+ addm( 12(CTX), d)
+ addm( 16(CTX), e)
+ addm( 20(CTX), f)
+ addm( 24(CTX), g)
+ addm( 28(CTX), h)
+
+ CMPQ _INP_END(SP), INP
+ JA avx2_loop0
+ JB done_hash
+
+avx2_do_last_block:
+
+ VMOVDQU 0(INP), XWORD0
+ VMOVDQU 16(INP), XWORD1
+ VMOVDQU 32(INP), XWORD2
+ VMOVDQU 48(INP), XWORD3
+
+ MOVQ $flip_mask<>(SB), BP
+ VMOVDQU (BP), X_BYTE_FLIP_MASK
+
+ VPSHUFB X_BYTE_FLIP_MASK, XWORD0, XWORD0
+ VPSHUFB X_BYTE_FLIP_MASK, XWORD1, XWORD1
+ VPSHUFB X_BYTE_FLIP_MASK, XWORD2, XWORD2
+ VPSHUFB X_BYTE_FLIP_MASK, XWORD3, XWORD3
+
+ MOVQ $K256<>(SB), TBL
+
+ JMP avx2_last_block_enter
+
+avx2_only_one_block:
+ // Load initial digest
+ MOVL 0(CTX), a // a = H0
+ MOVL 4(CTX), b // b = H1
+ MOVL 8(CTX), c // c = H2
+ MOVL 12(CTX), d // d = H3
+ MOVL 16(CTX), e // e = H4
+ MOVL 20(CTX), f // f = H5
+ MOVL 24(CTX), g // g = H6
+ MOVL 28(CTX), h // h = H7
+
+ JMP avx2_do_last_block
+
+done_hash:
+ VZEROUPPER
+ RET
+
+// shuffle byte order from LE to BE
+DATA flip_mask<>+0x00(SB)/8, $0x0405060700010203
+DATA flip_mask<>+0x08(SB)/8, $0x0c0d0e0f08090a0b
+DATA flip_mask<>+0x10(SB)/8, $0x0405060700010203
+DATA flip_mask<>+0x18(SB)/8, $0x0c0d0e0f08090a0b
+GLOBL flip_mask<>(SB), 8, $32
+
+// shuffle xBxA -> 00BA
+DATA shuff_00BA<>+0x00(SB)/8, $0x0b0a090803020100
+DATA shuff_00BA<>+0x08(SB)/8, $0xFFFFFFFFFFFFFFFF
+DATA shuff_00BA<>+0x10(SB)/8, $0x0b0a090803020100
+DATA shuff_00BA<>+0x18(SB)/8, $0xFFFFFFFFFFFFFFFF
+GLOBL shuff_00BA<>(SB), 8, $32
+
+// shuffle xDxC -> DC00
+DATA shuff_DC00<>+0x00(SB)/8, $0xFFFFFFFFFFFFFFFF
+DATA shuff_DC00<>+0x08(SB)/8, $0x0b0a090803020100
+DATA shuff_DC00<>+0x10(SB)/8, $0xFFFFFFFFFFFFFFFF
+DATA shuff_DC00<>+0x18(SB)/8, $0x0b0a090803020100
+GLOBL shuff_DC00<>(SB), 8, $32
+
+// Round specific constants
+DATA K256<>+0x00(SB)/4, $0x428a2f98 // k1
+DATA K256<>+0x04(SB)/4, $0x71374491 // k2
+DATA K256<>+0x08(SB)/4, $0xb5c0fbcf // k3
+DATA K256<>+0x0c(SB)/4, $0xe9b5dba5 // k4
+DATA K256<>+0x10(SB)/4, $0x428a2f98 // k1
+DATA K256<>+0x14(SB)/4, $0x71374491 // k2
+DATA K256<>+0x18(SB)/4, $0xb5c0fbcf // k3
+DATA K256<>+0x1c(SB)/4, $0xe9b5dba5 // k4
+
+DATA K256<>+0x20(SB)/4, $0x3956c25b // k5 - k8
+DATA K256<>+0x24(SB)/4, $0x59f111f1
+DATA K256<>+0x28(SB)/4, $0x923f82a4
+DATA K256<>+0x2c(SB)/4, $0xab1c5ed5
+DATA K256<>+0x30(SB)/4, $0x3956c25b
+DATA K256<>+0x34(SB)/4, $0x59f111f1
+DATA K256<>+0x38(SB)/4, $0x923f82a4
+DATA K256<>+0x3c(SB)/4, $0xab1c5ed5
+
+DATA K256<>+0x40(SB)/4, $0xd807aa98 // k9 - k12
+DATA K256<>+0x44(SB)/4, $0x12835b01
+DATA K256<>+0x48(SB)/4, $0x243185be
+DATA K256<>+0x4c(SB)/4, $0x550c7dc3
+DATA K256<>+0x50(SB)/4, $0xd807aa98
+DATA K256<>+0x54(SB)/4, $0x12835b01
+DATA K256<>+0x58(SB)/4, $0x243185be
+DATA K256<>+0x5c(SB)/4, $0x550c7dc3
+
+DATA K256<>+0x60(SB)/4, $0x72be5d74 // k13 - k16
+DATA K256<>+0x64(SB)/4, $0x80deb1fe
+DATA K256<>+0x68(SB)/4, $0x9bdc06a7
+DATA K256<>+0x6c(SB)/4, $0xc19bf174
+DATA K256<>+0x70(SB)/4, $0x72be5d74
+DATA K256<>+0x74(SB)/4, $0x80deb1fe
+DATA K256<>+0x78(SB)/4, $0x9bdc06a7
+DATA K256<>+0x7c(SB)/4, $0xc19bf174
+
+DATA K256<>+0x80(SB)/4, $0xe49b69c1 // k17 - k20
+DATA K256<>+0x84(SB)/4, $0xefbe4786
+DATA K256<>+0x88(SB)/4, $0x0fc19dc6
+DATA K256<>+0x8c(SB)/4, $0x240ca1cc
+DATA K256<>+0x90(SB)/4, $0xe49b69c1
+DATA K256<>+0x94(SB)/4, $0xefbe4786
+DATA K256<>+0x98(SB)/4, $0x0fc19dc6
+DATA K256<>+0x9c(SB)/4, $0x240ca1cc
+
+DATA K256<>+0xa0(SB)/4, $0x2de92c6f // k21 - k24
+DATA K256<>+0xa4(SB)/4, $0x4a7484aa
+DATA K256<>+0xa8(SB)/4, $0x5cb0a9dc
+DATA K256<>+0xac(SB)/4, $0x76f988da
+DATA K256<>+0xb0(SB)/4, $0x2de92c6f
+DATA K256<>+0xb4(SB)/4, $0x4a7484aa
+DATA K256<>+0xb8(SB)/4, $0x5cb0a9dc
+DATA K256<>+0xbc(SB)/4, $0x76f988da
+
+DATA K256<>+0xc0(SB)/4, $0x983e5152 // k25 - k28
+DATA K256<>+0xc4(SB)/4, $0xa831c66d
+DATA K256<>+0xc8(SB)/4, $0xb00327c8
+DATA K256<>+0xcc(SB)/4, $0xbf597fc7
+DATA K256<>+0xd0(SB)/4, $0x983e5152
+DATA K256<>+0xd4(SB)/4, $0xa831c66d
+DATA K256<>+0xd8(SB)/4, $0xb00327c8
+DATA K256<>+0xdc(SB)/4, $0xbf597fc7
+
+DATA K256<>+0xe0(SB)/4, $0xc6e00bf3 // k29 - k32
+DATA K256<>+0xe4(SB)/4, $0xd5a79147
+DATA K256<>+0xe8(SB)/4, $0x06ca6351
+DATA K256<>+0xec(SB)/4, $0x14292967
+DATA K256<>+0xf0(SB)/4, $0xc6e00bf3
+DATA K256<>+0xf4(SB)/4, $0xd5a79147
+DATA K256<>+0xf8(SB)/4, $0x06ca6351
+DATA K256<>+0xfc(SB)/4, $0x14292967
+
+DATA K256<>+0x100(SB)/4, $0x27b70a85
+DATA K256<>+0x104(SB)/4, $0x2e1b2138
+DATA K256<>+0x108(SB)/4, $0x4d2c6dfc
+DATA K256<>+0x10c(SB)/4, $0x53380d13
+DATA K256<>+0x110(SB)/4, $0x27b70a85
+DATA K256<>+0x114(SB)/4, $0x2e1b2138
+DATA K256<>+0x118(SB)/4, $0x4d2c6dfc
+DATA K256<>+0x11c(SB)/4, $0x53380d13
+
+DATA K256<>+0x120(SB)/4, $0x650a7354
+DATA K256<>+0x124(SB)/4, $0x766a0abb
+DATA K256<>+0x128(SB)/4, $0x81c2c92e
+DATA K256<>+0x12c(SB)/4, $0x92722c85
+DATA K256<>+0x130(SB)/4, $0x650a7354
+DATA K256<>+0x134(SB)/4, $0x766a0abb
+DATA K256<>+0x138(SB)/4, $0x81c2c92e
+DATA K256<>+0x13c(SB)/4, $0x92722c85
+
+DATA K256<>+0x140(SB)/4, $0xa2bfe8a1
+DATA K256<>+0x144(SB)/4, $0xa81a664b
+DATA K256<>+0x148(SB)/4, $0xc24b8b70
+DATA K256<>+0x14c(SB)/4, $0xc76c51a3
+DATA K256<>+0x150(SB)/4, $0xa2bfe8a1
+DATA K256<>+0x154(SB)/4, $0xa81a664b
+DATA K256<>+0x158(SB)/4, $0xc24b8b70
+DATA K256<>+0x15c(SB)/4, $0xc76c51a3
+
+DATA K256<>+0x160(SB)/4, $0xd192e819
+DATA K256<>+0x164(SB)/4, $0xd6990624
+DATA K256<>+0x168(SB)/4, $0xf40e3585
+DATA K256<>+0x16c(SB)/4, $0x106aa070
+DATA K256<>+0x170(SB)/4, $0xd192e819
+DATA K256<>+0x174(SB)/4, $0xd6990624
+DATA K256<>+0x178(SB)/4, $0xf40e3585
+DATA K256<>+0x17c(SB)/4, $0x106aa070
+
+DATA K256<>+0x180(SB)/4, $0x19a4c116
+DATA K256<>+0x184(SB)/4, $0x1e376c08
+DATA K256<>+0x188(SB)/4, $0x2748774c
+DATA K256<>+0x18c(SB)/4, $0x34b0bcb5
+DATA K256<>+0x190(SB)/4, $0x19a4c116
+DATA K256<>+0x194(SB)/4, $0x1e376c08
+DATA K256<>+0x198(SB)/4, $0x2748774c
+DATA K256<>+0x19c(SB)/4, $0x34b0bcb5
+
+DATA K256<>+0x1a0(SB)/4, $0x391c0cb3
+DATA K256<>+0x1a4(SB)/4, $0x4ed8aa4a
+DATA K256<>+0x1a8(SB)/4, $0x5b9cca4f
+DATA K256<>+0x1ac(SB)/4, $0x682e6ff3
+DATA K256<>+0x1b0(SB)/4, $0x391c0cb3
+DATA K256<>+0x1b4(SB)/4, $0x4ed8aa4a
+DATA K256<>+0x1b8(SB)/4, $0x5b9cca4f
+DATA K256<>+0x1bc(SB)/4, $0x682e6ff3
+
+DATA K256<>+0x1c0(SB)/4, $0x748f82ee
+DATA K256<>+0x1c4(SB)/4, $0x78a5636f
+DATA K256<>+0x1c8(SB)/4, $0x84c87814
+DATA K256<>+0x1cc(SB)/4, $0x8cc70208
+DATA K256<>+0x1d0(SB)/4, $0x748f82ee
+DATA K256<>+0x1d4(SB)/4, $0x78a5636f
+DATA K256<>+0x1d8(SB)/4, $0x84c87814
+DATA K256<>+0x1dc(SB)/4, $0x8cc70208
+
+DATA K256<>+0x1e0(SB)/4, $0x90befffa
+DATA K256<>+0x1e4(SB)/4, $0xa4506ceb
+DATA K256<>+0x1e8(SB)/4, $0xbef9a3f7
+DATA K256<>+0x1ec(SB)/4, $0xc67178f2
+DATA K256<>+0x1f0(SB)/4, $0x90befffa
+DATA K256<>+0x1f4(SB)/4, $0xa4506ceb
+DATA K256<>+0x1f8(SB)/4, $0xbef9a3f7
+DATA K256<>+0x1fc(SB)/4, $0xc67178f2
+
+GLOBL K256<>(SB), (NOPTR + RODATA), $512
input *block // application data waiting to be read
hand bytes.Buffer // handshake data waiting to be read
- // bytesSent counts the number of bytes of application data that have
- // been sent.
- bytesSent int64
+ // bytesSent counts the bytes of application data sent.
+ // packetsSent counts packets.
+ bytesSent int64
+ packetsSent int64
// activeCall is an atomic int32; the low bit is whether Close has
// been called. the rest of the bits are the number of goroutines
// recordSizeBoostThreshold is the number of bytes of application data
// sent after which the TLS record size will be increased to the
// maximum.
- recordSizeBoostThreshold = 1 * 1024 * 1024
+ recordSizeBoostThreshold = 128 * 1024
)
// maxPayloadSizeForWrite returns the maximum TLS payload size to use for the
}
}
- return payloadBytes
+ // Allow packet growth in arithmetic progression up to max.
+ pkt := c.packetsSent
+ c.packetsSent++
+ if pkt > 1000 {
+ return maxPlaintext // avoid overflow in multiply below
+ }
+
+ n := payloadBytes * int(pkt+1)
+ if n > maxPlaintext {
+ n = maxPlaintext
+ }
+ return n
}
// writeRecordLocked writes a TLS record with the given type and payload to the
seenLargeRecord := false
for i, size := range recordSizes {
if !seenLargeRecord {
- if size > tcpMSSEstimate {
- if i < 100 {
- t.Fatalf("Record #%d has size %d, which is too large too soon", i, size)
- }
- if size <= maxPlaintext {
- t.Fatalf("Record #%d has odd size %d", i, size)
- }
+ if size > (i+1)*tcpMSSEstimate {
+ t.Fatalf("Record #%d has size %d, which is too large too soon", i, size)
+ }
+ if size >= maxPlaintext {
seenLargeRecord = true
}
} else if size <= maxPlaintext {
return false
}
- if hs.sessionState.vers > hs.clientHello.vers {
- return false
- }
- if vers, ok := c.config.mutualVersion(hs.sessionState.vers); !ok || vers != hs.sessionState.vers {
+ // Never resume a session for a different TLS version.
+ if c.vers != hs.sessionState.vers {
return false
}
}
}
+func TestCrossVersionResume(t *testing.T) {
+ serverConfig := &Config{
+ CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
+ Certificates: testConfig.Certificates,
+ }
+ clientConfig := &Config{
+ CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
+ InsecureSkipVerify: true,
+ ClientSessionCache: NewLRUClientSessionCache(1),
+ ServerName: "servername",
+ }
+
+ // Establish a session at TLS 1.1.
+ clientConfig.MaxVersion = VersionTLS11
+ _, _, err := testHandshake(clientConfig, serverConfig)
+ if err != nil {
+ t.Fatalf("handshake failed: %s", err)
+ }
+
+ // The client session cache now contains a TLS 1.1 session.
+ state, _, err := testHandshake(clientConfig, serverConfig)
+ if err != nil {
+ t.Fatalf("handshake failed: %s", err)
+ }
+ if !state.DidResume {
+ t.Fatalf("handshake did not resume at the same version")
+ }
+
+ // Test that the server will decline to resume at a lower version.
+ clientConfig.MaxVersion = VersionTLS10
+ state, _, err = testHandshake(clientConfig, serverConfig)
+ if err != nil {
+ t.Fatalf("handshake failed: %s", err)
+ }
+ if state.DidResume {
+ t.Fatalf("handshake resumed at a lower version")
+ }
+
+ // The client session cache now contains a TLS 1.0 session.
+ state, _, err = testHandshake(clientConfig, serverConfig)
+ if err != nil {
+ t.Fatalf("handshake failed: %s", err)
+ }
+ if !state.DidResume {
+ t.Fatalf("handshake did not resume at the same version")
+ }
+
+ // Test that the server will decline to resume at a higher version.
+ clientConfig.MaxVersion = VersionTLS11
+ state, _, err = testHandshake(clientConfig, serverConfig)
+ if err != nil {
+ t.Fatalf("handshake failed: %s", err)
+ }
+ if state.DidResume {
+ t.Fatalf("handshake resumed at a higher version")
+ }
+}
+
// Note: see comment in handshake_test.go for details of how the reference
// tests work.
return DialWithDialer(new(net.Dialer), network, addr, config)
}
-// LoadX509KeyPair reads and parses a public/private key pair from a pair of
-// files. The files must contain PEM encoded data. On successful return,
-// Certificate.Leaf will be nil because the parsed form of the certificate is
-// not retained.
+// LoadX509KeyPair reads and parses a public/private key pair from a pair
+// of files. The files must contain PEM encoded data. The certificate file
+// may contain intermediate certificates following the leaf certificate to
+// form a certificate chain. On successful return, Certificate.Leaf will
+// be nil because the parsed form of the certificate is not retained.
func LoadX509KeyPair(certFile, keyFile string) (Certificate, error) {
certPEMBlock, err := ioutil.ReadFile(certFile)
if err != nil {
"fmt"
"internal/testenv"
"io"
+ "math"
"net"
"strings"
"testing"
}
}
-func newLocalListener(t *testing.T) net.Listener {
+func newLocalListener(t testing.TB) net.Listener {
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
ln, err = net.Listen("tcp6", "[::1]:0")
}
return w.Conn.Close()
}
+
+func throughput(b *testing.B, totalBytes int64, dynamicRecordSizingDisabled bool) {
+ ln := newLocalListener(b)
+ defer ln.Close()
+
+ N := b.N
+
+ var serr error
+ go func() {
+ for i := 0; i < N; i++ {
+ sconn, err := ln.Accept()
+ if err != nil {
+ serr = err
+ return
+ }
+ serverConfig := *testConfig
+ serverConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled
+ srv := Server(sconn, &serverConfig)
+ if err := srv.Handshake(); err != nil {
+ serr = fmt.Errorf("handshake: %v", err)
+ return
+ }
+ io.Copy(srv, srv)
+ }
+ }()
+
+ b.SetBytes(totalBytes)
+ clientConfig := *testConfig
+ clientConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled
+
+ buf := make([]byte, 1<<16)
+ chunks := int(math.Ceil(float64(totalBytes) / float64(len(buf))))
+ for i := 0; i < N; i++ {
+ conn, err := Dial("tcp", ln.Addr().String(), &clientConfig)
+ if err != nil {
+ b.Fatal(err)
+ }
+ for j := 0; j < chunks; j++ {
+ _, err := conn.Write(buf)
+ if err != nil {
+ b.Fatal(err)
+ }
+ _, err = io.ReadFull(conn, buf)
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+ conn.Close()
+ }
+}
+
+func BenchmarkThroughput(b *testing.B) {
+ for _, mode := range []string{"Max", "Dynamic"} {
+ for size := 1; size <= 64; size <<= 1 {
+ name := fmt.Sprintf("%sPacket/%dMB", mode, size)
+ b.Run(name, func(b *testing.B) {
+ throughput(b, int64(size<<20), mode == "Max")
+ })
+ }
+ }
+}
+
+type slowConn struct {
+ net.Conn
+ bps int
+}
+
+func (c *slowConn) Write(p []byte) (int, error) {
+ if c.bps == 0 {
+ panic("too slow")
+ }
+ t0 := time.Now()
+ wrote := 0
+ for wrote < len(p) {
+ time.Sleep(100 * time.Microsecond)
+ allowed := int(time.Since(t0).Seconds()*float64(c.bps)) / 8
+ if allowed > len(p) {
+ allowed = len(p)
+ }
+ if wrote < allowed {
+ n, err := c.Conn.Write(p[wrote:allowed])
+ wrote += n
+ if err != nil {
+ return wrote, err
+ }
+ }
+ }
+ return len(p), nil
+}
+
+func latency(b *testing.B, bps int, dynamicRecordSizingDisabled bool) {
+ ln := newLocalListener(b)
+ defer ln.Close()
+
+ N := b.N
+
+ var serr error
+ go func() {
+ for i := 0; i < N; i++ {
+ sconn, err := ln.Accept()
+ if err != nil {
+ serr = err
+ return
+ }
+ serverConfig := *testConfig
+ serverConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled
+ srv := Server(&slowConn{sconn, bps}, &serverConfig)
+ if err := srv.Handshake(); err != nil {
+ serr = fmt.Errorf("handshake: %v", err)
+ return
+ }
+ io.Copy(srv, srv)
+ }
+ }()
+
+ clientConfig := *testConfig
+ clientConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled
+
+ buf := make([]byte, 16384)
+ peek := make([]byte, 1)
+
+ for i := 0; i < N; i++ {
+ conn, err := Dial("tcp", ln.Addr().String(), &clientConfig)
+ if err != nil {
+ b.Fatal(err)
+ }
+ // make sure we're connected and previous connection has stopped
+ if _, err := conn.Write(buf[:1]); err != nil {
+ b.Fatal(err)
+ }
+ if _, err := io.ReadFull(conn, peek); err != nil {
+ b.Fatal(err)
+ }
+ if _, err := conn.Write(buf); err != nil {
+ b.Fatal(err)
+ }
+ if _, err = io.ReadFull(conn, peek); err != nil {
+ b.Fatal(err)
+ }
+ conn.Close()
+ }
+}
+
+func BenchmarkLatency(b *testing.B) {
+ for _, mode := range []string{"Max", "Dynamic"} {
+ for _, kbps := range []int{200, 500, 1000, 2000, 5000} {
+ name := fmt.Sprintf("%sPacket/%dkbps", mode, kbps)
+ b.Run(name, func(b *testing.B) {
+ latency(b, kbps*1000, mode == "Max")
+ })
+ }
+ }
+}
// Note: The CFDataRef returned in pemRoots must be released (using CFRelease) after
// we've consumed its content.
int FetchPEMRoots(CFDataRef *pemRoots) {
- if (pemRoots == NULL) {
- return -1;
- }
+ // Get certificates from all domains, not just System, this lets
+ // the user add CAs to their "login" keychain, and Admins to add
+ // to the "System" keychain
+ SecTrustSettingsDomain domains[] = { kSecTrustSettingsDomainSystem,
+ kSecTrustSettingsDomainAdmin,
+ kSecTrustSettingsDomainUser };
- CFArrayRef certs = NULL;
- OSStatus err = SecTrustCopyAnchorCertificates(&certs);
- if (err != noErr) {
+ int numDomains = sizeof(domains)/sizeof(SecTrustSettingsDomain);
+ if (pemRoots == NULL) {
return -1;
}
CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
- int i, ncerts = CFArrayGetCount(certs);
- for (i = 0; i < ncerts; i++) {
- CFDataRef data = NULL;
- SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, i);
- if (cert == NULL) {
- continue;
- }
-
- // Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport.
- // Once we support weak imports via cgo we should prefer that, and fall back to this
- // for older systems.
- err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
+ for (int i = 0; i < numDomains; i++) {
+ CFArrayRef certs = NULL;
+ // Only get certificates from domain that are trusted
+ OSStatus err = SecTrustSettingsCopyCertificates(domains[i], &certs);
if (err != noErr) {
continue;
}
- if (data != NULL) {
- CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data));
- CFRelease(data);
- }
- }
+ int numCerts = CFArrayGetCount(certs);
+ for (int j = 0; j < numCerts; j++) {
+ CFDataRef data = NULL;
+ CFErrorRef errRef = NULL;
+ SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, j);
+ if (cert == NULL) {
+ continue;
+ }
+ // We only want to add Root CAs, so make sure Subject and Issuer Name match
+ CFDataRef subjectName = SecCertificateCopyNormalizedSubjectContent(cert, &errRef);
+ if (errRef != NULL) {
+ CFRelease(errRef);
+ continue;
+ }
+ CFDataRef issuerName = SecCertificateCopyNormalizedIssuerContent(cert, &errRef);
+ if (errRef != NULL) {
+ CFRelease(subjectName);
+ CFRelease(errRef);
+ continue;
+ }
+ Boolean equal = CFEqual(subjectName, issuerName);
+ CFRelease(subjectName);
+ CFRelease(issuerName);
+ if (!equal) {
+ continue;
+ }
- CFRelease(certs);
+ // Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport.
+ // Once we support weak imports via cgo we should prefer that, and fall back to this
+ // for older systems.
+ err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
+ if (err != noErr) {
+ continue;
+ }
+ if (data != NULL) {
+ CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data));
+ CFRelease(data);
+ }
+ }
+ CFRelease(certs);
+ }
*pemRoots = combinedData;
return 0;
}
return ret, nil
}
-// CreateCertificateRequest creates a new certificate based on a template. The
-// following members of template are used: Subject, Attributes,
+// CreateCertificateRequest creates a new certificate request based on a template.
+// The following members of template are used: Subject, Attributes,
// SignatureAlgorithm, Extensions, DNSNames, EmailAddresses, and IPAddresses.
// The private key is the private key of the signer.
//
// Test Open method and seeking.
buf, have, count := make([]byte, len(b)), make([]bool, len(b)), 0
sf := sec.Open()
- if got, err := sf.Seek(0, 2); got != int64(len(b)) || err != nil {
+ if got, err := sf.Seek(0, io.SeekEnd); got != int64(len(b)) || err != nil {
t.Fatalf("want seek end %d, got %d error %v", len(b), got, err)
}
if n, err := sf.Read(buf); n != 0 || err != io.EOF {
target := rand.Int63n(int64(len(buf)))
var offset int64
switch whence {
- case 0:
+ case io.SeekStart:
offset = target
- case 1:
+ case io.SeekCurrent:
offset = target - pos
- case 2:
+ case io.SeekEnd:
offset = target - int64(len(buf))
}
pos, err = sf.Seek(offset, whence)
func (r *readSeekerFromReader) Seek(offset int64, whence int) (int64, error) {
var newOffset int64
switch whence {
- case 0:
+ case io.SeekStart:
newOffset = offset
- case 1:
+ case io.SeekCurrent:
newOffset = r.offset + offset
- case 2:
+ case io.SeekEnd:
newOffset = r.size + offset
default:
return 0, os.ErrInvalid
package gosym
import (
+ "bytes"
"debug/elf"
"internal/testenv"
"io/ioutil"
if err := cmd.Run(); err != nil {
t.Fatal(err)
}
+
+ // stamp .o file as being 'package main' so that go tool link will accept it
+ data, err := ioutil.ReadFile(pclinetestBinary + ".o")
+ if err != nil {
+ t.Fatal(err)
+ }
+ i := bytes.IndexByte(data, '\n')
+ if i < 0 {
+ t.Fatal("bad binary")
+ }
+ data = append(append(data[:i:i], "\nmain"...), data[i:]...)
+ if err := ioutil.WriteFile(pclinetestBinary+".o", data, 0666); err != nil {
+ t.Fatal(err)
+ }
+
cmd = exec.Command("go", "tool", "link", "-H", "linux",
"-o", pclinetestBinary, pclinetestBinary+".o")
cmd.Stdout = os.Stdout
// PackageName returns the package part of the symbol name,
// or the empty string if there is none.
func (s *Sym) PackageName() string {
- if i := strings.Index(s.Name, "."); i != -1 {
- return s.Name[0:i]
+ pathend := strings.LastIndex(s.Name, "/")
+ if pathend < 0 {
+ pathend = 0
+ }
+
+ if i := strings.Index(s.Name[pathend:], "."); i != -1 {
+ return s.Name[:pathend+i]
}
return ""
}
// ReceiverName returns the receiver type name of this symbol,
// or the empty string if there is none.
func (s *Sym) ReceiverName() string {
- l := strings.Index(s.Name, ".")
- r := strings.LastIndex(s.Name, ".")
+ pathend := strings.LastIndex(s.Name, "/")
+ if pathend < 0 {
+ pathend = 0
+ }
+ l := strings.Index(s.Name[pathend:], ".")
+ r := strings.LastIndex(s.Name[pathend:], ".")
if l == -1 || r == -1 || l == r {
return ""
}
- return s.Name[l+1 : r]
+ return s.Name[pathend+l+1 : pathend+r]
}
// BaseName returns the symbol name without the package or receiver name.
--- /dev/null
+// 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 gosym
+
+import (
+ "fmt"
+ "testing"
+)
+
+func assertString(t *testing.T, dsc, out, tgt string) {
+ if out != tgt {
+ t.Fatalf("Expected: %q Actual: %q for %s", tgt, out, dsc)
+ }
+}
+
+func TestStandardLibPackage(t *testing.T) {
+ s1 := Sym{Name: "io.(*LimitedReader).Read"}
+ s2 := Sym{Name: "io.NewSectionReader"}
+ assertString(t, fmt.Sprintf("package of %q", s1.Name), s1.PackageName(), "io")
+ assertString(t, fmt.Sprintf("package of %q", s2.Name), s2.PackageName(), "io")
+ assertString(t, fmt.Sprintf("receiver of %q", s1.Name), s1.ReceiverName(), "(*LimitedReader)")
+ assertString(t, fmt.Sprintf("receiver of %q", s2.Name), s2.ReceiverName(), "")
+}
+
+func TestStandardLibPathPackage(t *testing.T) {
+ s1 := Sym{Name: "debug/gosym.(*LineTable).PCToLine"}
+ s2 := Sym{Name: "debug/gosym.NewTable"}
+ assertString(t, fmt.Sprintf("package of %q", s1.Name), s1.PackageName(), "debug/gosym")
+ assertString(t, fmt.Sprintf("package of %q", s2.Name), s2.PackageName(), "debug/gosym")
+ assertString(t, fmt.Sprintf("receiver of %q", s1.Name), s1.ReceiverName(), "(*LineTable)")
+ assertString(t, fmt.Sprintf("receiver of %q", s2.Name), s2.ReceiverName(), "")
+}
+
+func TestRemotePackage(t *testing.T) {
+ s1 := Sym{Name: "github.com/docker/doc.ker/pkg/mflag.(*FlagSet).PrintDefaults"}
+ s2 := Sym{Name: "github.com/docker/doc.ker/pkg/mflag.PrintDefaults"}
+ assertString(t, fmt.Sprintf("package of %q", s1.Name), s1.PackageName(), "github.com/docker/doc.ker/pkg/mflag")
+ assertString(t, fmt.Sprintf("package of %q", s2.Name), s2.PackageName(), "github.com/docker/doc.ker/pkg/mflag")
+ assertString(t, fmt.Sprintf("receiver of %q", s1.Name), s1.ReceiverName(), "(*FlagSet)")
+ assertString(t, fmt.Sprintf("receiver of %q", s2.Name), s2.ReceiverName(), "")
+}
// license that can be found in the LICENSE file.
// Package csv reads and writes comma-separated values (CSV) files.
+// There are many kinds of CSV files; this package supports the format
+// described in RFC 4180.
//
// A csv file contains zero or more records of one or more fields per record.
// Each record is separated by the newline character. The final record may
for {
haveField, delim, err := r.parseField()
if haveField {
- // If FieldsPerRecord is greater then 0 we can assume the final
+ // If FieldsPerRecord is greater than 0 we can assume the final
// length of fields to be equal to FieldsPerRecord.
if r.FieldsPerRecord > 0 && fields == nil {
fields = make([]string, 0, r.FieldsPerRecord)
if item2.I != item1.I {
t.Error("normal int did not decode correctly")
}
- if item2.F != item2.F {
+ if item2.F != item1.F {
t.Error("normal float did not decode correctly")
}
}
if err != nil {
t.Fatal("decode error:", err)
}
- if u0.A != u0.A || u0.B != u1.B || u0.D != u1.D {
+ if u0.A != u1.A || u0.B != u1.B || u0.D != u1.D {
t.Errorf("u1->u0: expected %v; got %v", u0, u1)
}
if u1.c != 1234. {
// the additional Go array elements are set to zero values.
//
// To unmarshal a JSON object into a map, Unmarshal first establishes a map to
-// use, If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal
+// use. If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal
// reuses the existing map, keeping existing entries. Unmarshal then stores key-
-// value pairs from the JSON object into the map. The map's key type must
-// either be a string or implement encoding.TextUnmarshaler.
+// value pairs from the JSON object into the map. The map's key type must
+// either be a string, an integer, or implement encoding.TextUnmarshaler.
//
// If a JSON value is not appropriate for a given target type,
// or if a JSON number overflows the target type, Unmarshal
// Check type of target:
// struct or
- // map[string]T or map[encoding.TextUnmarshaler]T
+ // map[T1]T2 where T1 is string, an integer type,
+ // or an encoding.TextUnmarshaler
switch v.Kind() {
case reflect.Map:
- // Map key must either have string kind or be an encoding.TextUnmarshaler.
+ // Map key must either have string kind, have an integer kind,
+ // or be an encoding.TextUnmarshaler.
t := v.Type()
- if t.Key().Kind() != reflect.String &&
- !reflect.PtrTo(t.Key()).Implements(textUnmarshalerType) {
- d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)})
- d.off--
- d.next() // skip over { } in input
- return
+ switch t.Key().Kind() {
+ case reflect.String,
+ reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+ reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ default:
+ if !reflect.PtrTo(t.Key()).Implements(textUnmarshalerType) {
+ d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)})
+ d.off--
+ d.next() // skip over { } in input
+ return
+ }
}
if v.IsNil() {
v.Set(reflect.MakeMap(t))
var kv reflect.Value
switch {
case kt.Kind() == reflect.String:
- kv = reflect.ValueOf(key).Convert(v.Type().Key())
+ kv = reflect.ValueOf(key).Convert(kt)
case reflect.PtrTo(kt).Implements(textUnmarshalerType):
kv = reflect.New(v.Type().Key())
d.literalStore(item, kv, true)
kv = kv.Elem()
default:
- panic("json: Unexpected key type") // should never occur
+ switch kt.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ s := string(key)
+ n, err := strconv.ParseInt(s, 10, 64)
+ if err != nil || reflect.Zero(kt).OverflowInt(n) {
+ d.saveError(&UnmarshalTypeError{"number " + s, kt, int64(start + 1)})
+ return
+ }
+ kv = reflect.ValueOf(n).Convert(kt)
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ s := string(key)
+ n, err := strconv.ParseUint(s, 10, 64)
+ if err != nil || reflect.Zero(kt).OverflowUint(n) {
+ d.saveError(&UnmarshalTypeError{"number " + s, kt, int64(start + 1)})
+ return
+ }
+ kv = reflect.ValueOf(n).Convert(kt)
+ default:
+ panic("json: Unexpected key type") // should never occur
+ }
}
v.SetMapIndex(kv, subv)
}
"errors"
"fmt"
"image"
+ "math"
"net"
"reflect"
+ "strconv"
"strings"
"testing"
"time"
x int
}
+type u8 uint8
+
// A type that can unmarshal itself.
type unmarshaler struct {
M unmarshalerText
}
+// u8marshal is an integer type that can marshal/unmarshal itself.
+type u8marshal uint8
+
+func (u8 u8marshal) MarshalText() ([]byte, error) {
+ return []byte(fmt.Sprintf("u%d", u8)), nil
+}
+
+var errMissingU8Prefix = errors.New("missing 'u' prefix")
+
+func (u8 *u8marshal) UnmarshalText(b []byte) error {
+ if !bytes.HasPrefix(b, []byte{'u'}) {
+ return errMissingU8Prefix
+ }
+ n, err := strconv.Atoi(string(b[1:]))
+ if err != nil {
+ return err
+ }
+ *u8 = u8marshal(n)
+ return nil
+}
+
+var _ encoding.TextUnmarshaler = (*u8marshal)(nil)
+
var (
um0, um1 unmarshaler // target2 of unmarshaling
ump = &um1
S8
}
-type unmarshalTest struct {
- in string
- ptr interface{}
- out interface{}
- err error
- useNumber bool
-}
-
type Ambig struct {
// Given "hello", the first match should win.
First int `json:"HELLO"`
func sliceAddr(x []int) *[]int { return &x }
func mapAddr(x map[string]int) *map[string]int { return &x }
+type byteWithMarshalJSON byte
+
+func (b byteWithMarshalJSON) MarshalJSON() ([]byte, error) {
+ return []byte(fmt.Sprintf(`"Z%.2x"`, byte(b))), nil
+}
+
+func (b *byteWithMarshalJSON) UnmarshalJSON(data []byte) error {
+ if len(data) != 5 || data[0] != '"' || data[1] != 'Z' || data[4] != '"' {
+ return fmt.Errorf("bad quoted string")
+ }
+ i, err := strconv.ParseInt(string(data[2:4]), 16, 8)
+ if err != nil {
+ return fmt.Errorf("bad hex")
+ }
+ *b = byteWithMarshalJSON(i)
+ return nil
+}
+
+type byteWithPtrMarshalJSON byte
+
+func (b *byteWithPtrMarshalJSON) MarshalJSON() ([]byte, error) {
+ return byteWithMarshalJSON(*b).MarshalJSON()
+}
+
+func (b *byteWithPtrMarshalJSON) UnmarshalJSON(data []byte) error {
+ return (*byteWithMarshalJSON)(b).UnmarshalJSON(data)
+}
+
+type byteWithMarshalText byte
+
+func (b byteWithMarshalText) MarshalText() ([]byte, error) {
+ return []byte(fmt.Sprintf(`Z%.2x`, byte(b))), nil
+}
+
+func (b *byteWithMarshalText) UnmarshalText(data []byte) error {
+ if len(data) != 3 || data[0] != 'Z' {
+ return fmt.Errorf("bad quoted string")
+ }
+ i, err := strconv.ParseInt(string(data[1:3]), 16, 8)
+ if err != nil {
+ return fmt.Errorf("bad hex")
+ }
+ *b = byteWithMarshalText(i)
+ return nil
+}
+
+type byteWithPtrMarshalText byte
+
+func (b *byteWithPtrMarshalText) MarshalText() ([]byte, error) {
+ return byteWithMarshalText(*b).MarshalText()
+}
+
+func (b *byteWithPtrMarshalText) UnmarshalText(data []byte) error {
+ return (*byteWithMarshalText)(b).UnmarshalText(data)
+}
+
+type intWithMarshalJSON int
+
+func (b intWithMarshalJSON) MarshalJSON() ([]byte, error) {
+ return []byte(fmt.Sprintf(`"Z%.2x"`, int(b))), nil
+}
+
+func (b *intWithMarshalJSON) UnmarshalJSON(data []byte) error {
+ if len(data) != 5 || data[0] != '"' || data[1] != 'Z' || data[4] != '"' {
+ return fmt.Errorf("bad quoted string")
+ }
+ i, err := strconv.ParseInt(string(data[2:4]), 16, 8)
+ if err != nil {
+ return fmt.Errorf("bad hex")
+ }
+ *b = intWithMarshalJSON(i)
+ return nil
+}
+
+type intWithPtrMarshalJSON int
+
+func (b *intWithPtrMarshalJSON) MarshalJSON() ([]byte, error) {
+ return intWithMarshalJSON(*b).MarshalJSON()
+}
+
+func (b *intWithPtrMarshalJSON) UnmarshalJSON(data []byte) error {
+ return (*intWithMarshalJSON)(b).UnmarshalJSON(data)
+}
+
+type intWithMarshalText int
+
+func (b intWithMarshalText) MarshalText() ([]byte, error) {
+ return []byte(fmt.Sprintf(`Z%.2x`, int(b))), nil
+}
+
+func (b *intWithMarshalText) UnmarshalText(data []byte) error {
+ if len(data) != 3 || data[0] != 'Z' {
+ return fmt.Errorf("bad quoted string")
+ }
+ i, err := strconv.ParseInt(string(data[1:3]), 16, 8)
+ if err != nil {
+ return fmt.Errorf("bad hex")
+ }
+ *b = intWithMarshalText(i)
+ return nil
+}
+
+type intWithPtrMarshalText int
+
+func (b *intWithPtrMarshalText) MarshalText() ([]byte, error) {
+ return intWithMarshalText(*b).MarshalText()
+}
+
+func (b *intWithPtrMarshalText) UnmarshalText(data []byte) error {
+ return (*intWithMarshalText)(b).UnmarshalText(data)
+}
+
+type unmarshalTest struct {
+ in string
+ ptr interface{}
+ out interface{}
+ err error
+ useNumber bool
+ golden bool
+}
+
var unmarshalTests = []unmarshalTest{
// basic types
{in: `true`, ptr: new(bool), out: true},
{in: `["x:y"]`, ptr: &umslicepType, out: &umsliceXY},
{in: `{"M":"x:y"}`, ptr: umstructType, out: umstructXY},
- // Map keys can be encoding.TextUnmarshalers
+ // integer-keyed map test
+ {
+ in: `{"-1":"a","0":"b","1":"c"}`,
+ ptr: new(map[int]string),
+ out: map[int]string{-1: "a", 0: "b", 1: "c"},
+ },
+ {
+ in: `{"0":"a","10":"c","9":"b"}`,
+ ptr: new(map[u8]string),
+ out: map[u8]string{0: "a", 9: "b", 10: "c"},
+ },
+ {
+ in: `{"-9223372036854775808":"min","9223372036854775807":"max"}`,
+ ptr: new(map[int64]string),
+ out: map[int64]string{math.MinInt64: "min", math.MaxInt64: "max"},
+ },
+ {
+ in: `{"18446744073709551615":"max"}`,
+ ptr: new(map[uint64]string),
+ out: map[uint64]string{math.MaxUint64: "max"},
+ },
+ {
+ in: `{"0":false,"10":true}`,
+ ptr: new(map[uintptr]bool),
+ out: map[uintptr]bool{0: false, 10: true},
+ },
+
+ // Check that MarshalText and UnmarshalText take precedence
+ // over default integer handling in map keys.
+ {
+ in: `{"u2":4}`,
+ ptr: new(map[u8marshal]int),
+ out: map[u8marshal]int{2: 4},
+ },
+ {
+ in: `{"2":4}`,
+ ptr: new(map[u8marshal]int),
+ err: errMissingU8Prefix,
+ },
+
+ // integer-keyed map errors
+ {
+ in: `{"abc":"abc"}`,
+ ptr: new(map[int]string),
+ err: &UnmarshalTypeError{"number abc", reflect.TypeOf(0), 2},
+ },
+ {
+ in: `{"256":"abc"}`,
+ ptr: new(map[uint8]string),
+ err: &UnmarshalTypeError{"number 256", reflect.TypeOf(uint8(0)), 2},
+ },
+ {
+ in: `{"128":"abc"}`,
+ ptr: new(map[int8]string),
+ err: &UnmarshalTypeError{"number 128", reflect.TypeOf(int8(0)), 2},
+ },
+ {
+ in: `{"-1":"abc"}`,
+ ptr: new(map[uint8]string),
+ err: &UnmarshalTypeError{"number -1", reflect.TypeOf(uint8(0)), 2},
+ },
+
+ // Map keys can be encoding.TextUnmarshalers.
{in: `{"x:y":true}`, ptr: &ummapType, out: ummapXY},
// If multiple values for the same key exists, only the most recent value is used.
{in: `{"x:y":false,"x:y":true}`, ptr: &ummapType, out: ummapXY},
ptr: &map[unmarshaler]string{},
err: &UnmarshalTypeError{"object", reflect.TypeOf(map[unmarshaler]string{}), 1},
},
+
+ // related to issue 13783.
+ // Go 1.7 changed marshaling a slice of typed byte to use the methods on the byte type,
+ // similar to marshaling a slice of typed int.
+ // These tests check that, assuming the byte type also has valid decoding methods,
+ // either the old base64 string encoding or the new per-element encoding can be
+ // successfully unmarshaled. The custom unmarshalers were accessible in earlier
+ // versions of Go, even though the custom marshaler was not.
+ {
+ in: `"AQID"`,
+ ptr: new([]byteWithMarshalJSON),
+ out: []byteWithMarshalJSON{1, 2, 3},
+ },
+ {
+ in: `["Z01","Z02","Z03"]`,
+ ptr: new([]byteWithMarshalJSON),
+ out: []byteWithMarshalJSON{1, 2, 3},
+ golden: true,
+ },
+ {
+ in: `"AQID"`,
+ ptr: new([]byteWithMarshalText),
+ out: []byteWithMarshalText{1, 2, 3},
+ },
+ {
+ in: `["Z01","Z02","Z03"]`,
+ ptr: new([]byteWithMarshalText),
+ out: []byteWithMarshalText{1, 2, 3},
+ golden: true,
+ },
+ {
+ in: `"AQID"`,
+ ptr: new([]byteWithPtrMarshalJSON),
+ out: []byteWithPtrMarshalJSON{1, 2, 3},
+ },
+ {
+ in: `["Z01","Z02","Z03"]`,
+ ptr: new([]byteWithPtrMarshalJSON),
+ out: []byteWithPtrMarshalJSON{1, 2, 3},
+ golden: true,
+ },
+ {
+ in: `"AQID"`,
+ ptr: new([]byteWithPtrMarshalText),
+ out: []byteWithPtrMarshalText{1, 2, 3},
+ },
+ {
+ in: `["Z01","Z02","Z03"]`,
+ ptr: new([]byteWithPtrMarshalText),
+ out: []byteWithPtrMarshalText{1, 2, 3},
+ golden: true,
+ },
+
+ // ints work with the marshaler but not the base64 []byte case
+ {
+ in: `["Z01","Z02","Z03"]`,
+ ptr: new([]intWithMarshalJSON),
+ out: []intWithMarshalJSON{1, 2, 3},
+ golden: true,
+ },
+ {
+ in: `["Z01","Z02","Z03"]`,
+ ptr: new([]intWithMarshalText),
+ out: []intWithMarshalText{1, 2, 3},
+ golden: true,
+ },
+ {
+ in: `["Z01","Z02","Z03"]`,
+ ptr: new([]intWithPtrMarshalJSON),
+ out: []intWithPtrMarshalJSON{1, 2, 3},
+ golden: true,
+ },
+ {
+ in: `["Z01","Z02","Z03"]`,
+ ptr: new([]intWithPtrMarshalText),
+ out: []intWithPtrMarshalText{1, 2, 3},
+ golden: true,
+ },
}
func TestMarshal(t *testing.T) {
continue
}
- // Check round trip.
+ // Check round trip also decodes correctly.
if tt.err == nil {
enc, err := Marshal(v.Interface())
if err != nil {
t.Errorf("#%d: error re-marshaling: %v", i, err)
continue
}
+ if tt.golden && !bytes.Equal(enc, in) {
+ t.Errorf("#%d: remarshal mismatch:\nhave: %s\nwant: %s", i, enc, in)
+ }
vv := reflect.New(reflect.TypeOf(tt.ptr).Elem())
dec = NewDecoder(bytes.NewReader(enc))
if tt.useNumber {
// an anonymous struct field in both current and earlier versions, give the field
// a JSON tag of "-".
//
-// Map values encode as JSON objects. The map's key type must either be a string
-// or implement encoding.TextMarshaler. The map keys are used as JSON object
-// keys, subject to the UTF-8 coercion described for string values above.
+// Map values encode as JSON objects. The map's key type must either be a
+// string, an integer type, or implement encoding.TextMarshaler. The map keys
+// are sorted and used as JSON object keys by applying the following rules,
+// subject to the UTF-8 coercion described for string values above:
+// - string keys are used directly
+// - encoding.TextMarshalers are marshaled
+// - integer keys are converted to strings
//
// Pointer values encode as the value pointed to.
// A nil pointer encodes as the null JSON value.
}
func newMapEncoder(t reflect.Type) encoderFunc {
- if t.Key().Kind() != reflect.String && !t.Key().Implements(textMarshalerType) {
- return unsupportedTypeEncoder
+ switch t.Key().Kind() {
+ case reflect.String,
+ reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+ reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ default:
+ if !t.Key().Implements(textMarshalerType) {
+ return unsupportedTypeEncoder
+ }
}
me := &mapEncoder{typeEncoder(t.Elem())}
return me.encode
func newSliceEncoder(t reflect.Type) encoderFunc {
// Byte slices get special treatment; arrays don't.
- if t.Elem().Kind() == reflect.Uint8 &&
- !t.Elem().Implements(marshalerType) &&
- !t.Elem().Implements(textMarshalerType) {
- return encodeByteSlice
+ if t.Elem().Kind() == reflect.Uint8 {
+ p := reflect.PtrTo(t.Elem())
+ if !p.Implements(marshalerType) && !p.Implements(textMarshalerType) {
+ return encodeByteSlice
+ }
}
enc := &sliceEncoder{newArrayEncoder(t)}
return enc.encode
w.s = w.v.String()
return nil
}
- buf, err := w.v.Interface().(encoding.TextMarshaler).MarshalText()
- w.s = string(buf)
- return err
+ if tm, ok := w.v.Interface().(encoding.TextMarshaler); ok {
+ buf, err := tm.MarshalText()
+ w.s = string(buf)
+ return err
+ }
+ switch w.v.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ w.s = strconv.FormatInt(w.v.Int(), 10)
+ return nil
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ w.s = strconv.FormatUint(w.v.Uint(), 10)
+ return nil
+ }
+ panic("unexpected map key type")
}
// byString is a slice of reflectWithString where the reflect.Value is either
}
fmt.Printf("%T: %v\n", t, t)
- var m Message
// while the array contains values
for dec.More() {
-
+ var m Message
// decode an array value (Message)
err := dec.Decode(&m)
if err != nil {
e.WriteByte('\n')
b := e.Bytes()
- if enc.indentBuf != nil {
+ if enc.indentPrefix != "" || enc.indentValue != "" {
+ if enc.indentBuf == nil {
+ enc.indentBuf = new(bytes.Buffer)
+ }
enc.indentBuf.Reset()
err = Indent(enc.indentBuf, b, enc.indentPrefix, enc.indentValue)
if err != nil {
return err
}
-// Indent sets the encoder to format each encoded value with Indent.
-func (enc *Encoder) Indent(prefix, indent string) {
- enc.indentBuf = new(bytes.Buffer)
+// SetIndent instructs the encoder to format each subsequent encoded
+// value as if indented by the package-level function Indent(dst, src, prefix, indent).
+// Calling SetIndent("", "") disables indentation.
+func (enc *Encoder) SetIndent(prefix, indent string) {
enc.indentPrefix = prefix
enc.indentValue = indent
}
-// DisableHTMLEscaping causes the encoder not to escape angle brackets
-// ("<" and ">") or ampersands ("&") in JSON strings.
-func (enc *Encoder) DisableHTMLEscaping() {
- enc.escapeHTML = false
+// SetEscapeHTML specifies whether problematic HTML characters
+// should be escaped inside JSON quoted strings.
+// The default behavior is to escape &, <, and > to \u0026, \u003c, and \u003e
+// to avoid certain safety problems that can arise when embedding JSON in HTML.
+//
+// In non-HTML settings where the escaping interferes with the readability
+// of the output, SetEscapeHTML(false) disables this behavior.
+func (enc *Encoder) SetEscapeHTML(on bool) {
+ enc.escapeHTML = on
}
// RawMessage is a raw encoded JSON value.
for i := 0; i <= len(streamTest); i++ {
var buf bytes.Buffer
enc := NewEncoder(&buf)
+ // Check that enc.SetIndent("", "") turns off indentation.
+ enc.SetIndent(">", ".")
+ enc.SetIndent("", "")
for j, v := range streamTest[0:i] {
if err := enc.Encode(v); err != nil {
t.Fatalf("encode #%d: %v", j, err)
func TestEncoderIndent(t *testing.T) {
var buf bytes.Buffer
enc := NewEncoder(&buf)
- enc.Indent(">", ".")
+ enc.SetIndent(">", ".")
for _, v := range streamTest {
enc.Encode(v)
}
}
}
-func TestEncoderDisableHTMLEscaping(t *testing.T) {
+func TestEncoderSetEscapeHTML(t *testing.T) {
var c C
var ct CText
for _, tt := range []struct {
t.Errorf("Encode(%s) = %#q, want %#q", tt.name, got, tt.wantEscape)
}
buf.Reset()
- enc.DisableHTMLEscaping()
+ enc.SetEscapeHTML(false)
if err := enc.Encode(tt.v); err != nil {
- t.Fatalf("DisableHTMLEscaping Encode(%s): %s", tt.name, err)
+ t.Fatalf("SetEscapeHTML(false) Encode(%s): %s", tt.name, err)
}
if got := strings.TrimSpace(buf.String()); got != tt.want {
- t.Errorf("DisableHTMLEscaping Encode(%s) = %#q, want %#q",
+ t.Errorf("SetEscapeHTML(false) Encode(%s) = %#q, want %#q",
tt.name, got, tt.want)
}
}
// Var is an abstract type for all exported variables.
type Var interface {
// String returns a valid JSON value for the variable.
+ // Types with String methods that do not return valid JSON
+ // (such as time.Time) must not be used as a Var.
String() string
}
Too many arguments: %!(EXTRA type=value)
Printf("hi", "guys"): hi%!(EXTRA string=guys)
Too few arguments: %!verb(MISSING)
- Printf("hi%d"): hi %!d(MISSING)
+ Printf("hi%d"): hi%!d(MISSING)
Non-int for width or precision: %!(BADWIDTH) or %!(BADPREC)
Printf("%*s", 4.5, "hi"): %!(BADWIDTH)hi
Printf("%.*s", 4.5, "hi"): %!(BADPREC)hi
}
line = bytes.TrimSpace(line)
if bytes.HasPrefix(line, slashslash) {
- if bytes.HasPrefix(line, binaryOnlyComment) {
+ if bytes.Equal(line, binaryOnlyComment) {
sawBinaryOnly = true
}
line = bytes.TrimSpace(line[len(slashslash):])
"internal/syscall/unix": {"L0", "syscall"},
"internal/syscall/windows": {"L0", "syscall", "internal/syscall/windows/sysdll"},
"internal/syscall/windows/registry": {"L0", "syscall", "internal/syscall/windows/sysdll", "unicode/utf16"},
- "time": {"L0", "syscall", "internal/syscall/windows/registry"},
+ "time": {
+ // "L0" without the "io" package:
+ "errors",
+ "runtime",
+ "runtime/internal/atomic",
+ "sync",
+ "sync/atomic",
+ "unsafe",
+ // Other time dependencies:
+ "internal/syscall/windows/registry",
+ "syscall",
+ },
+
"os": {"L1", "os", "syscall", "time", "internal/syscall/windows"},
"path/filepath": {"L2", "os", "syscall"},
"io/ioutil": {"L2", "os", "path/filepath", "time"},
// Basic networking.
// Because net must be used by any package that wants to
// do networking portably, it must have a small dependency set: just L0+basic os.
- "net": {"L0", "CGO",
+ "net": {
+ "L0", "CGO",
"context", "math/rand", "os", "sort", "syscall", "time",
"internal/nettrace",
- "internal/syscall/windows", "internal/singleflight", "internal/race"},
+ "internal/syscall/windows", "internal/singleflight", "internal/race",
+ "golang.org/x/net/route",
+ },
// NET enables use of basic network-related packages.
"NET": {
"mime/multipart", "runtime/debug",
"net/http/internal",
"golang.org/x/net/http2/hpack",
+ "golang.org/x/net/lex/httplex",
"internal/nettrace",
"net/http/httptrace",
},
if err != nil {
return
}
- // reset to offset 0 - needed on Plan 9 (see issue #11265)
- // TODO: remove once issue #11265 has been resolved.
- _, err = f.Seek(0, 0)
- if err != nil {
- return
- }
var elfreader io.ReaderAt
switch string(magic[:]) {
if err != nil {
return
}
- _, err = reader.Seek(0, 0)
+ _, err = reader.Seek(0, io.SeekStart)
if err != nil {
return
}
buf []byte // for reading strings
// object lists
- strList []string // in order of appearance
- pkgList []*types.Package // in order of appearance
- typList []types.Type // in order of appearance
+ strList []string // in order of appearance
+ pkgList []*types.Package // in order of appearance
+ typList []types.Type // in order of appearance
+ trackAllTypes bool
// position encoding
posInfoFormat bool
return p.read, nil, fmt.Errorf("invalid encoding format in export data: got %q; want 'c' or 'd'", format)
}
+ p.trackAllTypes = p.rawByte() == 'a'
+
p.posInfoFormat = p.int() != 0
// --- generic export data ---
// complete interfaces
for _, typ := range p.typList {
- if it, ok := typ.(*types.Interface); ok {
+ // If we only record named types (!p.trackAllTypes),
+ // we must check the underlying types here. If we
+ // track all types, the Underlying() method call is
+ // not needed.
+ // TODO(gri) Remove if p.trackAllTypes is gone.
+ if it, ok := typ.Underlying().(*types.Interface); ok {
it.Complete()
}
}
// imported.
// (See also the comment in cmd/compile/internal/gc/bimport.go importer.obj,
// switch case importing functions).
- panic(fmt.Sprintf("%s already declared", alt.Name()))
+ panic(fmt.Sprintf("inconsistent import:\n\t%v\npreviously imported as:\n\t%v\n", alt, obj))
}
}
case arrayTag:
t := new(types.Array)
- p.record(t)
+ if p.trackAllTypes {
+ p.record(t)
+ }
n := p.int64()
*t = *types.NewArray(p.typ(parent), n)
case sliceTag:
t := new(types.Slice)
- p.record(t)
+ if p.trackAllTypes {
+ p.record(t)
+ }
*t = *types.NewSlice(p.typ(parent))
return t
case dddTag:
t := new(dddSlice)
- p.record(t)
+ if p.trackAllTypes {
+ p.record(t)
+ }
t.elem = p.typ(parent)
return t
case structTag:
t := new(types.Struct)
- p.record(t)
+ if p.trackAllTypes {
+ p.record(t)
+ }
*t = *types.NewStruct(p.fieldList(parent))
return t
case pointerTag:
t := new(types.Pointer)
- p.record(t)
+ if p.trackAllTypes {
+ p.record(t)
+ }
*t = *types.NewPointer(p.typ(parent))
return t
case signatureTag:
t := new(types.Signature)
- p.record(t)
+ if p.trackAllTypes {
+ p.record(t)
+ }
params, isddd := p.paramList()
result, _ := p.paramList()
// such cycle must contain a named type which would have been
// first defined earlier.
n := len(p.typList)
- p.record(nil)
+ if p.trackAllTypes {
+ p.record(nil)
+ }
// no embedded interfaces with gc compiler
if p.int() != 0 {
}
t := types.NewInterface(p.methodList(parent), nil)
- p.typList[n] = t
+ if p.trackAllTypes {
+ p.typList[n] = t
+ }
return t
case mapTag:
t := new(types.Map)
- p.record(t)
+ if p.trackAllTypes {
+ p.record(t)
+ }
key := p.typ(parent)
val := p.typ(parent)
case chanTag:
t := new(types.Chan)
- p.record(t)
+ if p.trackAllTypes {
+ p.record(t)
+ }
var dir types.ChanDir
// tag values must match the constants in cmd/compile/internal/gc/go.go
var data []byte
data, err = ioutil.ReadAll(buf)
if err == nil {
- _, pkg, err = BImportData(packages, data, path)
+ _, pkg, err = BImportData(packages, data, id)
return
}
default:
}
// lookup go/types.Object.Pkg method
- m, _, _ := types.LookupFieldOrMethod(typ, false, nil, "Pkg")
+ m, index, indirect := types.LookupFieldOrMethod(typ, false, nil, "Pkg")
if m == nil {
- t.Fatal("go/types.Object.Pkg not found")
+ t.Fatalf("go/types.Object.Pkg not found (index = %v, indirect = %v)", index, indirect)
}
// the method must belong to go/types
t.Fatalf("found %v; want go/types", m.Pkg())
}
}
+
+func TestIssue15517(t *testing.T) {
+ skipSpecialPlatforms(t)
+
+ // This package only handles gc export data.
+ if runtime.Compiler != "gc" {
+ t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+ return
+ }
+
+ // On windows, we have to set the -D option for the compiler to avoid having a drive
+ // letter and an illegal ':' in the import path - just skip it (see also issue #3483).
+ if runtime.GOOS == "windows" {
+ t.Skip("avoid dealing with relative paths/drive letters on windows")
+ }
+
+ if f := compile(t, "testdata", "p.go"); f != "" {
+ defer os.Remove(f)
+ }
+
+ // Multiple imports of p must succeed without redeclaration errors.
+ // We use an import path that's not cleaned up so that the eventual
+ // file path for the package is different from the package path; this
+ // will expose the error if it is present.
+ //
+ // (Issue: Both the textual and the binary importer used the file path
+ // of the package to be imported as key into the shared packages map.
+ // However, the binary importer then used the package path to identify
+ // the imported package to mark it as complete; effectively marking the
+ // wrong package as complete. By using an "unclean" package path, the
+ // file and package path are different, exposing the problem if present.
+ // The same issue occurs with vendoring.)
+ imports := make(map[string]*types.Package)
+ for i := 0; i < 3; i++ {
+ if _, err := Import(imports, "./././testdata/p", "."); err != nil {
+ t.Fatal(err)
+ }
+ }
+}
--- /dev/null
+// 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.
+
+// Input for TestIssue15517
+
+package p
+
+const C = 0
+
+var V int
+
+func F() {}
// Each line offset must be larger than the offset for the previous line
// and smaller than the file size; otherwise SetLines fails and returns
// false.
+// Callers must not mutate the provided slice after SetLines returns.
//
func (f *File) SetLines(lines []int) bool {
// verify validity of lines table
var op operand
check.expr(&op, sel.X)
if op.mode == mapindex {
- check.errorf(z.pos(), "cannot directly assign to struct field %s in map", ExprString(z.expr))
+ check.errorf(z.pos(), "cannot assign to struct field %s in map", ExprString(z.expr))
return nil
}
}
// determine type, if any
if typ != nil {
obj.typ = check.typ(typ)
+ // We cannot spread the type to all lhs variables if there
+ // are more than one since that would mark them as checked
+ // (see Checker.objDecl) and the assignment of init exprs,
+ // if any, would not be checked.
+ //
+ // TODO(gri) If we have no init expr, we should distribute
+ // a given type otherwise we need to re-evalate the type
+ // expr for each lhs variable, leading to duplicate work.
}
// check initialization
panic("inconsistent lhs")
}
}
+
+ // We have multiple variables on the lhs and one init expr.
+ // Make sure all variables have been given the same type if
+ // one was specified, otherwise they assume the type of the
+ // init expression values (was issue #15755).
+ if typ != nil {
+ for _, lhs := range lhs {
+ lhs.typ = obj.typ
+ }
+ }
+
check.initVars(lhs, []ast.Expr{init}, token.NoPos)
}
// TODO(gri) avoid declared but not used error here
} else {
// init exprs "inherited"
- check.errorf(s.Pos(), "extra init expr at %s", init.Pos())
+ check.errorf(s.Pos(), "extra init expr at %s", check.fset.Position(init.Pos()))
// TODO(gri) avoid declared but not used error here
}
case l > r && (init != nil || r != 1):
}
if d != nil {
if first != nil {
- check.errorf(d.Pos(), "multiple defaults (first at %s)", first.Pos())
+ check.errorf(d.Pos(), "multiple defaults (first at %s)", check.fset.Position(first.Pos()))
} else {
first = d
}
_ = b % a
)
}
+
+// Check that in a n:1 variable declaration with type and initialization
+// expression the type is distributed to all variables of the lhs before
+// the initialization expression assignment is checked.
+func issue15755() {
+ // from issue
+ var i interface{}
+ type b bool
+ var x, y b = i.(b)
+ _ = x == y
+
+ // related: we should see an error since the result of f1 is ([]int, int)
+ var u, v []int = f1 /* ERROR cannot use f1 */ ()
+ _ = u
+ _ = v
+}
type M map[string]S
var m M
- m /* ERROR "cannot directly assign to struct field" */ ["foo"].x = 0
+ m /* ERROR "cannot assign to struct field" */ ["foo"].x = 0
_ = &( /* ERROR "cannot take address" */ m["foo"].x)
_ = &m /* ERROR "cannot take address" */ ["foo"].x
}
// Table is a 256-word table representing the polynomial for efficient processing.
type Table [256]uint64
+var (
+ slicing8TableISO = makeSlicingBy8Table(makeTable(ISO))
+ slicing8TableECMA = makeSlicingBy8Table(makeTable(ECMA))
+)
+
// MakeTable returns a Table constructed from the specified polynomial.
// The contents of this Table must not be modified.
func MakeTable(poly uint64) *Table {
+ switch poly {
+ case ISO:
+ return &slicing8TableISO[0]
+ case ECMA:
+ return &slicing8TableECMA[0]
+ default:
+ return makeTable(poly)
+ }
+}
+
+func makeTable(poly uint64) *Table {
t := new(Table)
for i := 0; i < 256; i++ {
crc := uint64(i)
return t
}
+func makeSlicingBy8Table(t *Table) *[8]Table {
+ var helperTable [8]Table
+ helperTable[0] = *t
+ for i := 0; i < 256; i++ {
+ crc := t[i]
+ for j := 1; j < 8; j++ {
+ crc = t[crc&0xff] ^ (crc >> 8)
+ helperTable[j][i] = crc
+ }
+ }
+ return &helperTable
+}
+
// digest represents the partial evaluation of a checksum.
type digest struct {
crc uint64
func update(crc uint64, tab *Table, p []byte) uint64 {
crc = ^crc
+ // Table comparison is somewhat expensive, so avoid it for small sizes
+ for len(p) >= 64 {
+ var helperTable *[8]Table
+ if *tab == slicing8TableECMA[0] {
+ helperTable = slicing8TableECMA
+ } else if *tab == slicing8TableISO[0] {
+ helperTable = slicing8TableISO
+ // For smaller sizes creating extended table takes too much time
+ } else if len(p) > 16384 {
+ helperTable = makeSlicingBy8Table(tab)
+ } else {
+ break
+ }
+ // Update using slicing-by-8
+ for len(p) > 8 {
+ crc ^= uint64(p[0]) | uint64(p[1])<<8 | uint64(p[2])<<16 | uint64(p[3])<<24 |
+ uint64(p[4])<<32 | uint64(p[5])<<40 | uint64(p[6])<<48 | uint64(p[7])<<56
+ crc = helperTable[7][crc&0xff] ^
+ helperTable[6][(crc>>8)&0xff] ^
+ helperTable[5][(crc>>16)&0xff] ^
+ helperTable[4][(crc>>24)&0xff] ^
+ helperTable[3][(crc>>32)&0xff] ^
+ helperTable[2][(crc>>40)&0xff] ^
+ helperTable[1][(crc>>48)&0xff] ^
+ helperTable[0][crc>>56]
+ p = p[8:]
+ }
+ }
+ // For reminders or small sizes
for _, v := range p {
crc = tab[byte(crc)^v] ^ (crc >> 8)
}
}
}
-func BenchmarkISOCrc64KB(b *testing.B) {
- b.SetBytes(1024)
- data := make([]byte, 1024)
+func bench(b *testing.B, poly uint64, size int64) {
+ b.SetBytes(size)
+ data := make([]byte, size)
for i := range data {
data[i] = byte(i)
}
- h := New(MakeTable(ISO))
+ h := New(MakeTable(poly))
in := make([]byte, 0, h.Size())
b.ResetTimer()
h.Sum(in)
}
}
+
+func BenchmarkCrc64(b *testing.B) {
+ b.Run("ISO64KB", func(b *testing.B) {
+ bench(b, ISO, 64<<10)
+ })
+ b.Run("ISO4KB", func(b *testing.B) {
+ bench(b, ISO, 4<<10)
+ })
+ b.Run("ISO1KB", func(b *testing.B) {
+ bench(b, ISO, 1<<10)
+ })
+ b.Run("ECMA64KB", func(b *testing.B) {
+ bench(b, ECMA, 64<<10)
+ })
+ b.Run("Random64KB", func(b *testing.B) {
+ bench(b, 0x777, 64<<10)
+ })
+ b.Run("Random16KB", func(b *testing.B) {
+ bench(b, 0x777, 16<<10)
+ })
+}
// 4. The CSS3 value production, such as `rgba(0, 0, 255, 127)`.
// See http://www.w3.org/TR/css3-syntax/#parsing and
// https://web.archive.org/web/20090211114933/http://w3.org/TR/css3-syntax#style
+ //
+ // Use of this type presents a security risk:
+ // the encapsulated content should come from a trusted source,
+ // as it will be included verbatim in the template output.
CSS string
// HTML encapsulates a known safe HTML document fragment.
// It should not be used for HTML from a third-party, or HTML with
// unclosed tags or comments. The outputs of a sound HTML sanitizer
// and a template escaped by this package are fine for use with HTML.
+ //
+ // Use of this type presents a security risk:
+ // the encapsulated content should come from a trusted source,
+ // as it will be included verbatim in the template output.
HTML string
// HTMLAttr encapsulates an HTML attribute from a trusted source,
// for example, ` dir="ltr"`.
+ //
+ // Use of this type presents a security risk:
+ // the encapsulated content should come from a trusted source,
+ // as it will be included verbatim in the template output.
HTMLAttr string
// JS encapsulates a known safe EcmaScript5 Expression, for example,
// statement/expression ambiguity as when passing an expression like
// "{ foo: bar() }\n['foo']()", which is both a valid Expression and a
// valid Program with a very different meaning.
+ //
+ // Use of this type presents a security risk:
+ // the encapsulated content should come from a trusted source,
+ // as it will be included verbatim in the template output.
+ //
+ // Using JS to include valid but untrusted JSON is not safe.
+ // A safe alternative is to parse the JSON with json.Unmarshal and then
+ // pass the resultant object into the template, where it will be
+ // converted to sanitized JSON when presented in a JavaScript context.
JS string
// JSStr encapsulates a sequence of characters meant to be embedded
// | EscapeSequence
// Note that LineContinuations are not allowed.
// JSStr("foo\\nbar") is fine, but JSStr("foo\\\nbar") is not.
+ //
+ // Use of this type presents a security risk:
+ // the encapsulated content should come from a trusted source,
+ // as it will be included verbatim in the template output.
JSStr string
// URL encapsulates a known safe URL or URL substring (see RFC 3986).
// from a trusted source should go in the page, but by default dynamic
// `javascript:` URLs are filtered out since they are a frequently
// exploited injection vector.
+ //
+ // Use of this type presents a security risk:
+ // the encapsulated content should come from a trusted source,
+ // as it will be included verbatim in the template output.
URL string
)
// actually be for circular dependency reasons.
DNSDone func(netIPs []interface{}, coalesced bool, err error)
- // ConnectStart is called before a Dial. In the case of
- // DualStack (Happy Eyeballs) dialing, this may be called
- // multiple times, from multiple goroutines.
+ // ConnectStart is called before a Dial, excluding Dials made
+ // during DNS lookups. In the case of DualStack (Happy Eyeballs)
+ // dialing, this may be called multiple times, from multiple
+ // goroutines.
ConnectStart func(network, addr string)
- // ConnectStart is called after a Dial with the results. It
- // may also be called multiple times, like ConnectStart.
+ // ConnectStart is called after a Dial with the results, excluding
+ // Dials made during DNS lookups. It may also be called multiple
+ // times, like ConnectStart.
ConnectDone func(network, addr string, err error)
}
import "syscall"
-//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go -systemdll syscall.go
+//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall.go
const (
_REG_OPTION_NON_VOLATILE = 0
package registry
-import "unsafe"
-import "syscall"
-import "internal/syscall/windows/sysdll"
+import (
+ "internal/syscall/windows/sysdll"
+ "syscall"
+ "unsafe"
+)
var _ unsafe.Pointer
import "syscall"
-//go:generate go run ../../../syscall/mksyscall_windows.go -output zsyscall_windows.go -systemdll syscall_windows.go
+//go:generate go run ../../../syscall/mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go
const GAA_FLAG_INCLUDE_PREFIX = 0x00000010
package windows
-import "unsafe"
-import "syscall"
-import "internal/syscall/windows/sysdll"
+import (
+ "internal/syscall/windows/sysdll"
+ "syscall"
+ "unsafe"
+)
var _ unsafe.Pointer
"os/exec"
"path/filepath"
"runtime"
+ "strconv"
"strings"
"testing"
)
t.Skipf("skipping known flaky test without the -flaky flag; see golang.org/issue/%d", issue)
}
}
+
+func SkipFlakyNet(t *testing.T) {
+ if v, _ := strconv.ParseBool(os.Getenv("GO_BUILDER_FLAKY_NET")); v {
+ t.Skip("skipping test on builder known to have frequent network failures")
+ }
+}
r := strings.NewReader("some io.Reader stream to be read\n")
s := io.NewSectionReader(r, 5, 16)
- if _, err := s.Seek(10, 0); err != nil {
+ if _, err := s.Seek(10, io.SeekStart); err != nil {
log.Fatal(err)
}
UnreadRune() error
}
-// SizedReaderAt is the interface that groups the basic ReadAt method
-// with a Size method that reports the total size of the underlying
-// object. It represents a fixed-size data source that supports random
-// access by multiple concurrent goroutines.
-type SizedReaderAt interface {
- ReaderAt
- // Size reports the length of the data source in bytes.
- Size() int64
-}
-
// stringWriter is the interface that wraps the WriteString method.
type stringWriter interface {
WriteString(s string) (n int, err error)
switch whence {
default:
return 0, errWhence
- case 0:
+ case SeekStart:
offset += s.base
- case 1:
+ case SeekCurrent:
offset += s.off
- case 2:
+ case SeekEnd:
offset += s.limit
}
if offset < s.base {
br := bytes.NewReader([]byte("foo"))
sr := NewSectionReader(br, 0, int64(len("foo")))
- for whence := 0; whence <= 2; whence++ {
+ for _, whence := range []int{SeekStart, SeekCurrent, SeekEnd} {
for offset := int64(-3); offset <= 4; offset++ {
brOff, brErr := br.Seek(offset, whence)
srOff, srErr := sr.Seek(offset, whence)
}
// And verify we can just seek past the end and get an EOF
- got, err := sr.Seek(100, 0)
+ got, err := sr.Seek(100, SeekStart)
if err != nil || got != 100 {
t.Errorf("Seek = %v, %v; want 100, nil", got, err)
}
func (mr *multiReader) Read(p []byte) (n int, err error) {
for len(mr.readers) > 0 {
+ // Optimization to flatten nested multiReaders (Issue 13558)
+ if len(mr.readers) == 1 {
+ if r, ok := mr.readers[0].(*multiReader); ok {
+ mr.readers = r.readers
+ continue
+ }
+ }
n, err = mr.readers[0].Read(p)
if n > 0 || err != EOF {
if err == EOF {
import (
"bytes"
"crypto/sha1"
+ "errors"
"fmt"
. "io"
"io/ioutil"
+ "runtime"
"strings"
"testing"
)
t.Errorf("buf.String() = %q, want %q", buf.String(), "hello world")
}
}
+
+// readerFunc is an io.Reader implemented by the underlying func.
+type readerFunc func(p []byte) (int, error)
+
+func (f readerFunc) Read(p []byte) (int, error) {
+ return f(p)
+}
+
+// Test that MultiReader properly flattens chained multiReaders when Read is called
+func TestMultiReaderFlatten(t *testing.T) {
+ pc := make([]uintptr, 1000) // 1000 should fit the full stack
+ var myDepth = runtime.Callers(0, pc)
+ var readDepth int // will contain the depth from which fakeReader.Read was called
+ var r Reader = MultiReader(readerFunc(func(p []byte) (int, error) {
+ readDepth = runtime.Callers(1, pc)
+ return 0, errors.New("irrelevant")
+ }))
+
+ // chain a bunch of multiReaders
+ for i := 0; i < 100; i++ {
+ r = MultiReader(r)
+ }
+
+ r.Read(nil) // don't care about errors, just want to check the call-depth for Read
+
+ if readDepth != myDepth+2 { // 2 should be multiReader.Read and fakeReader.Read
+ t.Errorf("multiReader did not flatten chained multiReaders: expected readDepth %d, got %d",
+ myDepth+2, readDepth)
+ }
+}
# GO_DISTFLAGS: extra flags to provide to "dist bootstrap".
set -e
+
+unset GOBIN # Issue 14340
+
if [ ! -f run.bash ]; then
echo 'make.bash must be run from $GOROOT/src' 1>&2
exit 1
set GOROOT=%GOROOT_BOOTSTRAP%
set GOOS=
set GOARCH=
+set GOBIN=
"%GOROOT_BOOTSTRAP%\bin\go" build -o cmd\dist\dist.exe .\cmd\dist
endlocal
if errorlevel 1 goto fail
if(! ~ $GOHOSTARCH $GOARCH || ! ~ $GOHOSTOS $GOOS){
echo '##### Building packages and commands for host,' $GOHOSTOS/$GOHOSTARCH^.
- GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH \
+ GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH GOBIN= \
$GOTOOLDIR/go_bootstrap install -gcflags $"GO_GCFLAGS -ldflags $"GO_LDFLAGS -v $pflag std cmd
echo
}
package big
import (
+ "fmt"
"math/rand"
"testing"
)
return v
}
-func benchmarkFunVV(b *testing.B, f funVV, n int) {
- x := rndV(n)
- y := rndV(n)
- z := make([]Word, n)
- b.SetBytes(int64(n * _W))
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- f(z, x, y)
+var benchSizes = []int{1, 2, 3, 4, 5, 1e1, 1e2, 1e3, 1e4, 1e5}
+
+func BenchmarkAddVV(b *testing.B) {
+ for _, n := range benchSizes {
+ x := rndV(n)
+ y := rndV(n)
+ z := make([]Word, n)
+ b.Run(fmt.Sprint(n), func(b *testing.B) {
+ b.SetBytes(int64(n * _W))
+ for i := 0; i < b.N; i++ {
+ addVV(z, x, y)
+ }
+ })
}
}
-func BenchmarkAddVV_1(b *testing.B) { benchmarkFunVV(b, addVV, 1) }
-func BenchmarkAddVV_2(b *testing.B) { benchmarkFunVV(b, addVV, 2) }
-func BenchmarkAddVV_3(b *testing.B) { benchmarkFunVV(b, addVV, 3) }
-func BenchmarkAddVV_4(b *testing.B) { benchmarkFunVV(b, addVV, 4) }
-func BenchmarkAddVV_5(b *testing.B) { benchmarkFunVV(b, addVV, 5) }
-func BenchmarkAddVV_1e1(b *testing.B) { benchmarkFunVV(b, addVV, 1e1) }
-func BenchmarkAddVV_1e2(b *testing.B) { benchmarkFunVV(b, addVV, 1e2) }
-func BenchmarkAddVV_1e3(b *testing.B) { benchmarkFunVV(b, addVV, 1e3) }
-func BenchmarkAddVV_1e4(b *testing.B) { benchmarkFunVV(b, addVV, 1e4) }
-func BenchmarkAddVV_1e5(b *testing.B) { benchmarkFunVV(b, addVV, 1e5) }
-
type funVW func(z, x []Word, y Word) (c Word)
type argVW struct {
z, x nat
}
}
-func benchmarkFunVW(b *testing.B, f funVW, n int) {
- x := rndV(n)
- y := rndW()
- z := make([]Word, n)
- b.SetBytes(int64(n * _S))
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- f(z, x, y)
+func BenchmarkAddVW(b *testing.B) {
+ for _, n := range benchSizes {
+ x := rndV(n)
+ y := rndW()
+ z := make([]Word, n)
+ b.Run(fmt.Sprint(n), func(b *testing.B) {
+ b.SetBytes(int64(n * _S))
+ for i := 0; i < b.N; i++ {
+ addVW(z, x, y)
+ }
+ })
}
}
-func BenchmarkAddVW_1(b *testing.B) { benchmarkFunVW(b, addVW, 1) }
-func BenchmarkAddVW_2(b *testing.B) { benchmarkFunVW(b, addVW, 2) }
-func BenchmarkAddVW_3(b *testing.B) { benchmarkFunVW(b, addVW, 3) }
-func BenchmarkAddVW_4(b *testing.B) { benchmarkFunVW(b, addVW, 4) }
-func BenchmarkAddVW_5(b *testing.B) { benchmarkFunVW(b, addVW, 5) }
-func BenchmarkAddVW_1e1(b *testing.B) { benchmarkFunVW(b, addVW, 1e1) }
-func BenchmarkAddVW_1e2(b *testing.B) { benchmarkFunVW(b, addVW, 1e2) }
-func BenchmarkAddVW_1e3(b *testing.B) { benchmarkFunVW(b, addVW, 1e3) }
-func BenchmarkAddVW_1e4(b *testing.B) { benchmarkFunVW(b, addVW, 1e4) }
-func BenchmarkAddVW_1e5(b *testing.B) { benchmarkFunVW(b, addVW, 1e5) }
-
type funVWW func(z, x []Word, y, r Word) (c Word)
type argVWW struct {
z, x nat
}
}
-func benchmarkAddMulVVW(b *testing.B, n int) {
- x := rndV(n)
- y := rndW()
- z := make([]Word, n)
- b.SetBytes(int64(n * _W))
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- addMulVVW(z, x, y)
+func BenchmarkAddMulVVW(b *testing.B) {
+ for _, n := range benchSizes {
+ x := rndV(n)
+ y := rndW()
+ z := make([]Word, n)
+ b.Run(fmt.Sprint(n), func(b *testing.B) {
+ b.SetBytes(int64(n * _W))
+ for i := 0; i < b.N; i++ {
+ addMulVVW(z, x, y)
+ }
+ })
}
}
-func BenchmarkAddMulVVW_1(b *testing.B) { benchmarkAddMulVVW(b, 1) }
-func BenchmarkAddMulVVW_2(b *testing.B) { benchmarkAddMulVVW(b, 2) }
-func BenchmarkAddMulVVW_3(b *testing.B) { benchmarkAddMulVVW(b, 3) }
-func BenchmarkAddMulVVW_4(b *testing.B) { benchmarkAddMulVVW(b, 4) }
-func BenchmarkAddMulVVW_5(b *testing.B) { benchmarkAddMulVVW(b, 5) }
-func BenchmarkAddMulVVW_1e1(b *testing.B) { benchmarkAddMulVVW(b, 1e1) }
-func BenchmarkAddMulVVW_1e2(b *testing.B) { benchmarkAddMulVVW(b, 1e2) }
-func BenchmarkAddMulVVW_1e3(b *testing.B) { benchmarkAddMulVVW(b, 1e3) }
-func BenchmarkAddMulVVW_1e4(b *testing.B) { benchmarkAddMulVVW(b, 1e4) }
-func BenchmarkAddMulVVW_1e5(b *testing.B) { benchmarkAddMulVVW(b, 1e5) }
-
func testWordBitLen(t *testing.T, fname string, f func(Word) int) {
for i := 0; i <= _W; i++ {
x := Word(1) << uint(i-1) // i == 0 => x == 0
}
// runs b.N iterations of bitLen called on a Word containing (1 << nbits)-1.
-func benchmarkBitLenN(b *testing.B, nbits uint) {
- testword := Word((uint64(1) << nbits) - 1)
- for i := 0; i < b.N; i++ {
- bitLen(testword)
+func BenchmarkBitLen(b *testing.B) {
+ // Individual bitLen tests. Numbers chosen to examine both sides
+ // of powers-of-two boundaries.
+ for _, nbits := range []uint{0, 1, 2, 3, 4, 5, 8, 9, 16, 17, 31} {
+ testword := Word((uint64(1) << nbits) - 1)
+ b.Run(fmt.Sprint(nbits), func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ bitLen(testword)
+ }
+ })
}
}
-
-// Individual bitLen tests. Numbers chosen to examine both sides
-// of powers-of-two boundaries.
-func BenchmarkBitLen0(b *testing.B) { benchmarkBitLenN(b, 0) }
-func BenchmarkBitLen1(b *testing.B) { benchmarkBitLenN(b, 1) }
-func BenchmarkBitLen2(b *testing.B) { benchmarkBitLenN(b, 2) }
-func BenchmarkBitLen3(b *testing.B) { benchmarkBitLenN(b, 3) }
-func BenchmarkBitLen4(b *testing.B) { benchmarkBitLenN(b, 4) }
-func BenchmarkBitLen5(b *testing.B) { benchmarkBitLenN(b, 5) }
-func BenchmarkBitLen8(b *testing.B) { benchmarkBitLenN(b, 8) }
-func BenchmarkBitLen9(b *testing.B) { benchmarkBitLenN(b, 9) }
-func BenchmarkBitLen16(b *testing.B) { benchmarkBitLenN(b, 16) }
-func BenchmarkBitLen17(b *testing.B) { benchmarkBitLenN(b, 17) }
-func BenchmarkBitLen31(b *testing.B) { benchmarkBitLenN(b, 31) }
package big
import (
+ "fmt"
"runtime"
"strings"
"testing"
}
}
-func ExpHelper(b *testing.B, x, y Word) {
- var z nat
- for i := 0; i < b.N; i++ {
- z.expWW(x, y)
+func BenchmarkExp3Power(b *testing.B) {
+ const x = 3
+ for _, y := range []Word{
+ 0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x10000, 0x40000, 0x100000, 0x400000,
+ } {
+ b.Run(fmt.Sprintf("%#x", y), func(b *testing.B) {
+ var z nat
+ for i := 0; i < b.N; i++ {
+ z.expWW(x, y)
+ }
+ })
}
}
-func BenchmarkExp3Power0x10(b *testing.B) { ExpHelper(b, 3, 0x10) }
-func BenchmarkExp3Power0x40(b *testing.B) { ExpHelper(b, 3, 0x40) }
-func BenchmarkExp3Power0x100(b *testing.B) { ExpHelper(b, 3, 0x100) }
-func BenchmarkExp3Power0x400(b *testing.B) { ExpHelper(b, 3, 0x400) }
-func BenchmarkExp3Power0x1000(b *testing.B) { ExpHelper(b, 3, 0x1000) }
-func BenchmarkExp3Power0x4000(b *testing.B) { ExpHelper(b, 3, 0x4000) }
-func BenchmarkExp3Power0x10000(b *testing.B) { ExpHelper(b, 3, 0x10000) }
-func BenchmarkExp3Power0x40000(b *testing.B) { ExpHelper(b, 3, 0x40000) }
-func BenchmarkExp3Power0x100000(b *testing.B) { ExpHelper(b, 3, 0x100000) }
-func BenchmarkExp3Power0x400000(b *testing.B) { ExpHelper(b, 3, 0x400000) }
-
func fibo(n int) nat {
switch n {
case 0:
// this appears to be faster for BenchmarkString10000Base10
// and smaller strings (but a bit slower for larger ones)
t := r / 10
- s[i] = '0' + byte(r-t<<3-t-t) // TODO(gri) replace w/ t*10 once compiler produces better code
+ s[i] = '0' + byte(r-t*10)
r = t
}
}
import (
"bytes"
+ "fmt"
"io"
"strings"
"testing"
})
}
-func BenchmarkScan10Base2(b *testing.B) { ScanHelper(b, 2, 10, 10) }
-func BenchmarkScan100Base2(b *testing.B) { ScanHelper(b, 2, 10, 100) }
-func BenchmarkScan1000Base2(b *testing.B) { ScanHelper(b, 2, 10, 1000) }
-func BenchmarkScan10000Base2(b *testing.B) { ScanHelper(b, 2, 10, 10000) }
-func BenchmarkScan100000Base2(b *testing.B) { ScanHelper(b, 2, 10, 100000) }
-
-func BenchmarkScan10Base8(b *testing.B) { ScanHelper(b, 8, 10, 10) }
-func BenchmarkScan100Base8(b *testing.B) { ScanHelper(b, 8, 10, 100) }
-func BenchmarkScan1000Base8(b *testing.B) { ScanHelper(b, 8, 10, 1000) }
-func BenchmarkScan10000Base8(b *testing.B) { ScanHelper(b, 8, 10, 10000) }
-func BenchmarkScan100000Base8(b *testing.B) { ScanHelper(b, 8, 10, 100000) }
-
-func BenchmarkScan10Base10(b *testing.B) { ScanHelper(b, 10, 10, 10) }
-func BenchmarkScan100Base10(b *testing.B) { ScanHelper(b, 10, 10, 100) }
-func BenchmarkScan1000Base10(b *testing.B) { ScanHelper(b, 10, 10, 1000) }
-func BenchmarkScan10000Base10(b *testing.B) { ScanHelper(b, 10, 10, 10000) }
-func BenchmarkScan100000Base10(b *testing.B) { ScanHelper(b, 10, 10, 100000) }
-
-func BenchmarkScan10Base16(b *testing.B) { ScanHelper(b, 16, 10, 10) }
-func BenchmarkScan100Base16(b *testing.B) { ScanHelper(b, 16, 10, 100) }
-func BenchmarkScan1000Base16(b *testing.B) { ScanHelper(b, 16, 10, 1000) }
-func BenchmarkScan10000Base16(b *testing.B) { ScanHelper(b, 16, 10, 10000) }
-func BenchmarkScan100000Base16(b *testing.B) { ScanHelper(b, 16, 10, 100000) }
-
-func ScanHelper(b *testing.B, base int, x, y Word) {
- b.StopTimer()
- var z nat
- z = z.expWW(x, y)
-
- s := z.utoa(base)
- if t := itoa(z, base); !bytes.Equal(s, t) {
- b.Fatalf("scanning: got %s; want %s", s, t)
+func BenchmarkScan(b *testing.B) {
+ const x = 10
+ for _, base := range []int{2, 8, 10, 16} {
+ for _, y := range []Word{10, 100, 1000, 10000, 100000} {
+ b.Run(fmt.Sprintf("%d/Base%d", y, base), func(b *testing.B) {
+ b.StopTimer()
+ var z nat
+ z = z.expWW(x, y)
+
+ s := z.utoa(base)
+ if t := itoa(z, base); !bytes.Equal(s, t) {
+ b.Fatalf("scanning: got %s; want %s", s, t)
+ }
+ b.StartTimer()
+
+ for i := 0; i < b.N; i++ {
+ z.scan(bytes.NewReader(s), base, false)
+ }
+ })
+ }
}
- b.StartTimer()
+}
- for i := 0; i < b.N; i++ {
- z.scan(bytes.NewReader(s), base, false)
+func BenchmarkString(b *testing.B) {
+ const x = 10
+ for _, base := range []int{2, 8, 10, 16} {
+ for _, y := range []Word{10, 100, 1000, 10000, 100000} {
+ b.Run(fmt.Sprintf("%d/Base%d", y, base), func(b *testing.B) {
+ b.StopTimer()
+ var z nat
+ z = z.expWW(x, y)
+ z.utoa(base) // warm divisor cache
+ b.StartTimer()
+
+ for i := 0; i < b.N; i++ {
+ _ = z.utoa(base)
+ }
+ })
+ }
}
}
-func BenchmarkString10Base2(b *testing.B) { StringHelper(b, 2, 10, 10) }
-func BenchmarkString100Base2(b *testing.B) { StringHelper(b, 2, 10, 100) }
-func BenchmarkString1000Base2(b *testing.B) { StringHelper(b, 2, 10, 1000) }
-func BenchmarkString10000Base2(b *testing.B) { StringHelper(b, 2, 10, 10000) }
-func BenchmarkString100000Base2(b *testing.B) { StringHelper(b, 2, 10, 100000) }
-
-func BenchmarkString10Base8(b *testing.B) { StringHelper(b, 8, 10, 10) }
-func BenchmarkString100Base8(b *testing.B) { StringHelper(b, 8, 10, 100) }
-func BenchmarkString1000Base8(b *testing.B) { StringHelper(b, 8, 10, 1000) }
-func BenchmarkString10000Base8(b *testing.B) { StringHelper(b, 8, 10, 10000) }
-func BenchmarkString100000Base8(b *testing.B) { StringHelper(b, 8, 10, 100000) }
-
-func BenchmarkString10Base10(b *testing.B) { StringHelper(b, 10, 10, 10) }
-func BenchmarkString100Base10(b *testing.B) { StringHelper(b, 10, 10, 100) }
-func BenchmarkString1000Base10(b *testing.B) { StringHelper(b, 10, 10, 1000) }
-func BenchmarkString10000Base10(b *testing.B) { StringHelper(b, 10, 10, 10000) }
-func BenchmarkString100000Base10(b *testing.B) { StringHelper(b, 10, 10, 100000) }
-
-func BenchmarkString10Base16(b *testing.B) { StringHelper(b, 16, 10, 10) }
-func BenchmarkString100Base16(b *testing.B) { StringHelper(b, 16, 10, 100) }
-func BenchmarkString1000Base16(b *testing.B) { StringHelper(b, 16, 10, 1000) }
-func BenchmarkString10000Base16(b *testing.B) { StringHelper(b, 16, 10, 10000) }
-func BenchmarkString100000Base16(b *testing.B) { StringHelper(b, 16, 10, 100000) }
-
-func StringHelper(b *testing.B, base int, x, y Word) {
- b.StopTimer()
- var z nat
- z = z.expWW(x, y)
- z.utoa(base) // warm divisor cache
- b.StartTimer()
-
- for i := 0; i < b.N; i++ {
- _ = z.utoa(base)
+func BenchmarkLeafSize(b *testing.B) {
+ for n := 0; n <= 16; n++ {
+ b.Run(fmt.Sprint(n), func(b *testing.B) { LeafSizeHelper(b, 10, n) })
+ }
+ // Try some large lengths
+ for _, n := range []int{32, 64} {
+ b.Run(fmt.Sprint(n), func(b *testing.B) { LeafSizeHelper(b, 10, n) })
}
}
-func BenchmarkLeafSize0(b *testing.B) { LeafSizeHelper(b, 10, 0) } // test without splitting
-func BenchmarkLeafSize1(b *testing.B) { LeafSizeHelper(b, 10, 1) }
-func BenchmarkLeafSize2(b *testing.B) { LeafSizeHelper(b, 10, 2) }
-func BenchmarkLeafSize3(b *testing.B) { LeafSizeHelper(b, 10, 3) }
-func BenchmarkLeafSize4(b *testing.B) { LeafSizeHelper(b, 10, 4) }
-func BenchmarkLeafSize5(b *testing.B) { LeafSizeHelper(b, 10, 5) }
-func BenchmarkLeafSize6(b *testing.B) { LeafSizeHelper(b, 10, 6) }
-func BenchmarkLeafSize7(b *testing.B) { LeafSizeHelper(b, 10, 7) }
-func BenchmarkLeafSize8(b *testing.B) { LeafSizeHelper(b, 10, 8) }
-func BenchmarkLeafSize9(b *testing.B) { LeafSizeHelper(b, 10, 9) }
-func BenchmarkLeafSize10(b *testing.B) { LeafSizeHelper(b, 10, 10) }
-func BenchmarkLeafSize11(b *testing.B) { LeafSizeHelper(b, 10, 11) }
-func BenchmarkLeafSize12(b *testing.B) { LeafSizeHelper(b, 10, 12) }
-func BenchmarkLeafSize13(b *testing.B) { LeafSizeHelper(b, 10, 13) }
-func BenchmarkLeafSize14(b *testing.B) { LeafSizeHelper(b, 10, 14) }
-func BenchmarkLeafSize15(b *testing.B) { LeafSizeHelper(b, 10, 15) }
-func BenchmarkLeafSize16(b *testing.B) { LeafSizeHelper(b, 10, 16) }
-func BenchmarkLeafSize32(b *testing.B) { LeafSizeHelper(b, 10, 32) } // try some large lengths
-func BenchmarkLeafSize64(b *testing.B) { LeafSizeHelper(b, 10, 64) }
-
func LeafSizeHelper(b *testing.B, base, size int) {
b.StopTimer()
originalLeafSize := leafSize
// Seed uses the provided seed value to initialize the default Source to a
// deterministic state. If Seed is not called, the generator behaves as
-// if seeded by Seed(1).
+// if seeded by Seed(1). Only uses the bottom 31 bits of seed; the top 33
+// bits are ignored.
func Seed(seed int64) { globalRand.Seed(seed) }
// Int63 returns a non-negative pseudo-random 63-bit integer as an int64
"fmt"
"io"
"net/textproto"
+ "sort"
"strings"
)
} else {
fmt.Fprintf(&b, "--%s\r\n", w.boundary)
}
- // TODO(bradfitz): move this to textproto.MimeHeader.Write(w), have it sort
- // and clean, like http.Header.Write(w) does.
- for k, vv := range header {
- for _, v := range vv {
+
+ keys := make([]string, 0, len(header))
+ for k := range header {
+ keys = append(keys, k)
+ }
+ sort.Strings(keys)
+ for _, k := range keys {
+ for _, v := range header[k] {
fmt.Fprintf(&b, "%s: %s\r\n", k, v)
}
}
import (
"bytes"
"io/ioutil"
+ "net/textproto"
"strings"
"testing"
)
w.Boundary()
<-done
}
+
+func TestSortedHeader(t *testing.T) {
+ var buf bytes.Buffer
+ w := NewWriter(&buf)
+ if err := w.SetBoundary("MIMEBOUNDARY"); err != nil {
+ t.Fatalf("Error setting mime boundary: %v", err)
+ }
+
+ header := textproto.MIMEHeader{
+ "A": {"2"},
+ "B": {"5", "7", "6"},
+ "C": {"4"},
+ "M": {"3"},
+ "Z": {"1"},
+ }
+
+ part, err := w.CreatePart(header)
+ if err != nil {
+ t.Fatalf("Unable to create part: %v", err)
+ }
+ part.Write([]byte("foo"))
+
+ w.Close()
+
+ want := "--MIMEBOUNDARY\r\nA: 2\r\nB: 5\r\nB: 7\r\nB: 6\r\nC: 4\r\nM: 3\r\nZ: 1\r\n\r\nfoo\r\n--MIMEBOUNDARY--\r\n"
+ if want != buf.String() {
+ t.Fatalf("\n got: %q\nwant: %q\n", buf.String(), want)
+ }
+}
}
var typeFiles = []string{
- "/sys/lib/mimetypes",
+ "/sys/lib/mimetype",
}
func initMimeForTests() map[string]string {
package net
+import "context"
+
func init() { netGo = true }
type addrinfoErrno int
func (eai addrinfoErrno) Temporary() bool { return false }
func (eai addrinfoErrno) Timeout() bool { return false }
-func cgoLookupHost(name string) (addrs []string, err error, completed bool) {
+func cgoLookupHost(ctx context.Context, name string) (addrs []string, err error, completed bool) {
return nil, nil, false
}
-func cgoLookupPort(network, service string) (port int, err error, completed bool) {
+func cgoLookupPort(ctx context.Context, network, service string) (port int, err error, completed bool) {
return 0, nil, false
}
-func cgoLookupIP(name string) (addrs []IPAddr, err error, completed bool) {
+func cgoLookupIP(ctx context.Context, name string) (addrs []IPAddr, err error, completed bool) {
return nil, nil, false
}
-func cgoLookupCNAME(name string) (cname string, err error, completed bool) {
+func cgoLookupCNAME(ctx context.Context, name string) (cname string, err error, completed bool) {
return "", nil, false
}
-func cgoLookupPTR(addr string) (ptrs []string, err error, completed bool) {
+func cgoLookupPTR(ctx context.Context, addr string) (ptrs []string, err error, completed bool) {
return nil, nil, false
}
import "C"
import (
+ "context"
"syscall"
"unsafe"
)
func (eai addrinfoErrno) Temporary() bool { return eai == C.EAI_AGAIN }
func (eai addrinfoErrno) Timeout() bool { return false }
-func cgoLookupHost(name string) (hosts []string, err error, completed bool) {
- addrs, err, completed := cgoLookupIP(name)
+type portLookupResult struct {
+ port int
+ err error
+}
+
+type ipLookupResult struct {
+ addrs []IPAddr
+ cname string
+ err error
+}
+
+type reverseLookupResult struct {
+ names []string
+ err error
+}
+
+func cgoLookupHost(ctx context.Context, name string) (hosts []string, err error, completed bool) {
+ addrs, err, completed := cgoLookupIP(ctx, name)
for _, addr := range addrs {
hosts = append(hosts, addr.String())
}
return
}
-func cgoLookupPort(network, service string) (port int, err error, completed bool) {
- acquireThread()
- defer releaseThread()
-
+func cgoLookupPort(ctx context.Context, network, service string) (port int, err error, completed bool) {
var hints C.struct_addrinfo
switch network {
case "": // no hints
hints.ai_family = C.AF_INET6
}
}
+ if ctx.Done() == nil {
+ port, err := cgoLookupServicePort(&hints, network, service)
+ return port, err, true
+ }
+ result := make(chan portLookupResult, 1)
+ go cgoPortLookup(result, &hints, network, service)
+ select {
+ case r := <-result:
+ return r.port, r.err, true
+ case <-ctx.Done():
+ // Since there isn't a portable way to cancel the lookup,
+ // we just let it finish and write to the buffered channel.
+ return 0, mapErr(ctx.Err()), false
+ }
+}
+func cgoLookupServicePort(hints *C.struct_addrinfo, network, service string) (port int, err error) {
s := C.CString(service)
var res *C.struct_addrinfo
defer C.free(unsafe.Pointer(s))
- gerrno, err := C.getaddrinfo(nil, s, &hints, &res)
+ gerrno, err := C.getaddrinfo(nil, s, hints, &res)
if gerrno != 0 {
switch gerrno {
case C.EAI_SYSTEM:
default:
err = addrinfoErrno(gerrno)
}
- return 0, &DNSError{Err: err.Error(), Name: network + "/" + service}, true
+ return 0, &DNSError{Err: err.Error(), Name: network + "/" + service}
}
defer C.freeaddrinfo(res)
case C.AF_INET:
sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.ai_addr))
p := (*[2]byte)(unsafe.Pointer(&sa.Port))
- return int(p[0])<<8 | int(p[1]), nil, true
+ return int(p[0])<<8 | int(p[1]), nil
case C.AF_INET6:
sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(r.ai_addr))
p := (*[2]byte)(unsafe.Pointer(&sa.Port))
- return int(p[0])<<8 | int(p[1]), nil, true
+ return int(p[0])<<8 | int(p[1]), nil
}
}
- return 0, &DNSError{Err: "unknown port", Name: network + "/" + service}, true
+ return 0, &DNSError{Err: "unknown port", Name: network + "/" + service}
}
-func cgoLookupIPCNAME(name string) (addrs []IPAddr, cname string, err error, completed bool) {
+func cgoPortLookup(result chan<- portLookupResult, hints *C.struct_addrinfo, network, service string) {
+ port, err := cgoLookupServicePort(hints, network, service)
+ result <- portLookupResult{port, err}
+}
+
+func cgoLookupIPCNAME(name string) (addrs []IPAddr, cname string, err error) {
acquireThread()
defer releaseThread()
default:
err = addrinfoErrno(gerrno)
}
- return nil, "", &DNSError{Err: err.Error(), Name: name}, true
+ return nil, "", &DNSError{Err: err.Error(), Name: name}
}
defer C.freeaddrinfo(res)
addrs = append(addrs, addr)
}
}
- return addrs, cname, nil, true
+ return addrs, cname, nil
}
-func cgoLookupIP(name string) (addrs []IPAddr, err error, completed bool) {
- addrs, _, err, completed = cgoLookupIPCNAME(name)
- return
+func cgoIPLookup(result chan<- ipLookupResult, name string) {
+ addrs, cname, err := cgoLookupIPCNAME(name)
+ result <- ipLookupResult{addrs, cname, err}
}
-func cgoLookupCNAME(name string) (cname string, err error, completed bool) {
- _, cname, err, completed = cgoLookupIPCNAME(name)
- return
+func cgoLookupIP(ctx context.Context, name string) (addrs []IPAddr, err error, completed bool) {
+ if ctx.Done() == nil {
+ addrs, _, err = cgoLookupIPCNAME(name)
+ return addrs, err, true
+ }
+ result := make(chan ipLookupResult, 1)
+ go cgoIPLookup(result, name)
+ select {
+ case r := <-result:
+ return r.addrs, r.err, true
+ case <-ctx.Done():
+ return nil, mapErr(ctx.Err()), false
+ }
+}
+
+func cgoLookupCNAME(ctx context.Context, name string) (cname string, err error, completed bool) {
+ if ctx.Done() == nil {
+ _, cname, err = cgoLookupIPCNAME(name)
+ return cname, err, true
+ }
+ result := make(chan ipLookupResult, 1)
+ go cgoIPLookup(result, name)
+ select {
+ case r := <-result:
+ return r.cname, r.err, true
+ case <-ctx.Done():
+ return "", mapErr(ctx.Err()), false
+ }
}
// These are roughly enough for the following:
maxNameinfoLen = 4096
)
-func cgoLookupPTR(addr string) ([]string, error, bool) {
- acquireThread()
- defer releaseThread()
-
+func cgoLookupPTR(ctx context.Context, addr string) (names []string, err error, completed bool) {
var zone string
ip := parseIPv4(addr)
if ip == nil {
if sa == nil {
return nil, &DNSError{Err: "invalid address " + ip.String(), Name: addr}, true
}
- var err error
- var b []byte
+ if ctx.Done() == nil {
+ names, err := cgoLookupAddrPTR(addr, sa, salen)
+ return names, err, true
+ }
+ result := make(chan reverseLookupResult, 1)
+ go cgoReverseLookup(result, addr, sa, salen)
+ select {
+ case r := <-result:
+ return r.names, r.err, true
+ case <-ctx.Done():
+ return nil, mapErr(ctx.Err()), false
+ }
+}
+
+func cgoLookupAddrPTR(addr string, sa *C.struct_sockaddr, salen C.socklen_t) (names []string, err error) {
+ acquireThread()
+ defer releaseThread()
+
var gerrno int
+ var b []byte
for l := nameinfoLen; l <= maxNameinfoLen; l *= 2 {
b = make([]byte, l)
gerrno, err = cgoNameinfoPTR(b, sa, salen)
default:
err = addrinfoErrno(gerrno)
}
- return nil, &DNSError{Err: err.Error(), Name: addr}, true
+ return nil, &DNSError{Err: err.Error(), Name: addr}
}
-
for i := 0; i < len(b); i++ {
if b[i] == 0 {
b = b[:i]
break
}
}
- return []string{absDomainName(b)}, nil, true
+ return []string{absDomainName(b)}, nil
+}
+
+func cgoReverseLookup(result chan<- reverseLookupResult, addr string, sa *C.struct_sockaddr, salen C.socklen_t) {
+ names, err := cgoLookupAddrPTR(addr, sa, salen)
+ result <- reverseLookupResult{names, err}
}
func cgoSockaddr(ip IP, zone string) (*C.struct_sockaddr, C.socklen_t) {
)
func TestCgoLookupIP(t *testing.T) {
- host := "localhost"
- _, err, ok := cgoLookupIP(host)
+ ctx := context.Background()
+ _, err, ok := cgoLookupIP(ctx, "localhost")
if !ok {
t.Errorf("cgoLookupIP must not be a placeholder")
}
if err != nil {
t.Error(err)
}
- if _, err := goLookupIP(context.Background(), host); err != nil {
+}
+
+func TestCgoLookupIPWithCancel(t *testing.T) {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ _, err, ok := cgoLookupIP(ctx, "localhost")
+ if !ok {
+ t.Errorf("cgoLookupIP must not be a placeholder")
+ }
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func TestCgoLookupPort(t *testing.T) {
+ ctx := context.Background()
+ _, err, ok := cgoLookupPort(ctx, "tcp", "smtp")
+ if !ok {
+ t.Errorf("cgoLookupPort must not be a placeholder")
+ }
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func TestCgoLookupPortWithCancel(t *testing.T) {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ _, err, ok := cgoLookupPort(ctx, "tcp", "smtp")
+ if !ok {
+ t.Errorf("cgoLookupPort must not be a placeholder")
+ }
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func TestCgoLookupPTR(t *testing.T) {
+ ctx := context.Background()
+ _, err, ok := cgoLookupPTR(ctx, "127.0.0.1")
+ if !ok {
+ t.Errorf("cgoLookupPTR must not be a placeholder")
+ }
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func TestCgoLookupPTRWithCancel(t *testing.T) {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ _, err, ok := cgoLookupPTR(ctx, "127.0.0.1")
+ if !ok {
+ t.Errorf("cgoLookupPTR must not be a placeholder")
+ }
+ if err != nil {
t.Error(err)
}
}
t.Fatal(err)
}
defer c.Close()
- if c.LocalAddr().Network() != network || c.LocalAddr().Network() != network {
+ if c.LocalAddr().Network() != network || c.RemoteAddr().Network() != network {
t.Fatalf("got %s->%s; want %s->%s", c.LocalAddr().Network(), c.RemoteAddr().Network(), network, network)
}
c.SetDeadline(time.Now().Add(someTimeout))
// If the host is empty, as in ":80", the local system is assumed.
//
// Examples:
-// Dial("tcp", "12.34.56.78:80")
-// Dial("tcp", "google.com:http")
+// Dial("tcp", "192.0.2.1:80")
+// Dial("tcp", "golang.org:http")
// Dial("tcp", "[2001:db8::1]:http")
// Dial("tcp", "[fe80::1%lo0]:80")
// Dial("tcp", ":80")
// literal IP address.
//
// Examples:
-// Dial("ip4:1", "127.0.0.1")
-// Dial("ip6:ospf", "::1")
+// Dial("ip4:1", "192.0.2.1")
+// Dial("ip6:ipv6-icmp", "2001:db8::1")
//
// For Unix networks, the address must be a file system path.
func Dial(network, address string) (Conn, error) {
ctx = subCtx
}
- addrs, err := resolveAddrList(ctx, "dial", network, address, d.LocalAddr)
+ // Shadow the nettrace (if any) during resolve so Connect events don't fire for DNS lookups.
+ resolveCtx := ctx
+ if trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace); trace != nil {
+ shadow := *trace
+ shadow.ConnectStart = nil
+ shadow.ConnectDone = nil
+ resolveCtx = context.WithValue(resolveCtx, nettrace.TraceKey{}, &shadow)
+ }
+
+ addrs, err := resolveAddrList(resolveCtx, "dial", network, address, d.LocalAddr)
if err != nil {
return nil, &OpError{Op: "dial", Net: network, Source: nil, Addr: nil, Err: err}
}
t.Skipf("%s does not have full support of socktest", runtime.GOOS)
case "windows":
t.Skipf("not implemented a way to cancel dial racers in TCP SYN-SENT state on %s", runtime.GOOS)
- case "openbsd":
- testenv.SkipFlaky(t, 15157)
}
if !supportsIPv4 || !supportsIPv6 {
t.Skip("both IPv4 and IPv6 are required")
}
+ closedPortDelay, expectClosedPortDelay := dialClosedPort()
+ if closedPortDelay > expectClosedPortDelay {
+ t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay)
+ }
+
before := sw.Sockets()
origTestHookLookupIP := testHookLookupIP
defer func() { testHookLookupIP = origTestHookLookupIP }()
c.Close()
}
}
- dss, err := newDualStackServer([]streamListener{
- {network: "tcp4", address: "127.0.0.1"},
- {network: "tcp6", address: "::1"},
- })
+ dss, err := newDualStackServer()
if err != nil {
t.Fatal(err)
}
const N = 10
var wg sync.WaitGroup
wg.Add(N)
- d := &Dialer{DualStack: true, Timeout: 100 * time.Millisecond}
+ d := &Dialer{DualStack: true, Timeout: 100*time.Millisecond + closedPortDelay}
for i := 0; i < N; i++ {
go func() {
defer wg.Done()
}
for i, tt := range testCases {
- dss, err := newDualStackServer([]streamListener{
- {network: "tcp4", address: "127.0.0.1"},
- {network: "tcp6", address: "::1"},
- })
+ dss, err := newDualStackServer()
if err != nil {
t.Fatal(err)
}
c.Close()
}
}
- dss, err := newDualStackServer([]streamListener{
- {network: "tcp", address: "127.0.0.1"},
- })
+ dss, err := newDualStackServer()
if err != nil {
t.Fatal(err)
}
c.Close()
wg.Done()
}
- dss, err := newDualStackServer([]streamListener{
- {network: "tcp4", address: "127.0.0.1"},
- {network: "tcp6", address: "::1"},
- })
+ dss, err := newDualStackServer()
if err != nil {
t.Fatal(err)
}
}
}
-type dialerLocalAddrTest struct {
- network, raddr string
- laddr Addr
- error
-}
-
-var dialerLocalAddrTests = []dialerLocalAddrTest{
- {"tcp4", "127.0.0.1", nil, nil},
- {"tcp4", "127.0.0.1", &TCPAddr{}, nil},
- {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil},
- {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil},
- {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, &AddrError{Err: "some error"}},
- {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, nil},
- {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, nil},
- {"tcp4", "127.0.0.1", &TCPAddr{IP: IPv6loopback}, errNoSuitableAddress},
- {"tcp4", "127.0.0.1", &UDPAddr{}, &AddrError{Err: "some error"}},
- {"tcp4", "127.0.0.1", &UnixAddr{}, &AddrError{Err: "some error"}},
-
- {"tcp6", "::1", nil, nil},
- {"tcp6", "::1", &TCPAddr{}, nil},
- {"tcp6", "::1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil},
- {"tcp6", "::1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil},
- {"tcp6", "::1", &TCPAddr{IP: ParseIP("::")}, nil},
- {"tcp6", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, errNoSuitableAddress},
- {"tcp6", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, errNoSuitableAddress},
- {"tcp6", "::1", &TCPAddr{IP: IPv6loopback}, nil},
- {"tcp6", "::1", &UDPAddr{}, &AddrError{Err: "some error"}},
- {"tcp6", "::1", &UnixAddr{}, &AddrError{Err: "some error"}},
-
- {"tcp", "127.0.0.1", nil, nil},
- {"tcp", "127.0.0.1", &TCPAddr{}, nil},
- {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil},
- {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil},
- {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, nil},
- {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, nil},
- {"tcp", "127.0.0.1", &TCPAddr{IP: IPv6loopback}, errNoSuitableAddress},
- {"tcp", "127.0.0.1", &UDPAddr{}, &AddrError{Err: "some error"}},
- {"tcp", "127.0.0.1", &UnixAddr{}, &AddrError{Err: "some error"}},
-
- {"tcp", "::1", nil, nil},
- {"tcp", "::1", &TCPAddr{}, nil},
- {"tcp", "::1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil},
- {"tcp", "::1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil},
- {"tcp", "::1", &TCPAddr{IP: ParseIP("::")}, nil},
- {"tcp", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, errNoSuitableAddress},
- {"tcp", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, errNoSuitableAddress},
- {"tcp", "::1", &TCPAddr{IP: IPv6loopback}, nil},
- {"tcp", "::1", &UDPAddr{}, &AddrError{Err: "some error"}},
- {"tcp", "::1", &UnixAddr{}, &AddrError{Err: "some error"}},
-}
-
func TestDialerLocalAddr(t *testing.T) {
if !supportsIPv4 || !supportsIPv6 {
t.Skip("both IPv4 and IPv6 are required")
}
+ type test struct {
+ network, raddr string
+ laddr Addr
+ error
+ }
+ var tests = []test{
+ {"tcp4", "127.0.0.1", nil, nil},
+ {"tcp4", "127.0.0.1", &TCPAddr{}, nil},
+ {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil},
+ {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil},
+ {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, &AddrError{Err: "some error"}},
+ {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, nil},
+ {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, nil},
+ {"tcp4", "127.0.0.1", &TCPAddr{IP: IPv6loopback}, errNoSuitableAddress},
+ {"tcp4", "127.0.0.1", &UDPAddr{}, &AddrError{Err: "some error"}},
+ {"tcp4", "127.0.0.1", &UnixAddr{}, &AddrError{Err: "some error"}},
+
+ {"tcp6", "::1", nil, nil},
+ {"tcp6", "::1", &TCPAddr{}, nil},
+ {"tcp6", "::1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil},
+ {"tcp6", "::1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil},
+ {"tcp6", "::1", &TCPAddr{IP: ParseIP("::")}, nil},
+ {"tcp6", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, errNoSuitableAddress},
+ {"tcp6", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, errNoSuitableAddress},
+ {"tcp6", "::1", &TCPAddr{IP: IPv6loopback}, nil},
+ {"tcp6", "::1", &UDPAddr{}, &AddrError{Err: "some error"}},
+ {"tcp6", "::1", &UnixAddr{}, &AddrError{Err: "some error"}},
+
+ {"tcp", "127.0.0.1", nil, nil},
+ {"tcp", "127.0.0.1", &TCPAddr{}, nil},
+ {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil},
+ {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil},
+ {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, nil},
+ {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, nil},
+ {"tcp", "127.0.0.1", &TCPAddr{IP: IPv6loopback}, errNoSuitableAddress},
+ {"tcp", "127.0.0.1", &UDPAddr{}, &AddrError{Err: "some error"}},
+ {"tcp", "127.0.0.1", &UnixAddr{}, &AddrError{Err: "some error"}},
+
+ {"tcp", "::1", nil, nil},
+ {"tcp", "::1", &TCPAddr{}, nil},
+ {"tcp", "::1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil},
+ {"tcp", "::1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil},
+ {"tcp", "::1", &TCPAddr{IP: ParseIP("::")}, nil},
+ {"tcp", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, errNoSuitableAddress},
+ {"tcp", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, errNoSuitableAddress},
+ {"tcp", "::1", &TCPAddr{IP: IPv6loopback}, nil},
+ {"tcp", "::1", &UDPAddr{}, &AddrError{Err: "some error"}},
+ {"tcp", "::1", &UnixAddr{}, &AddrError{Err: "some error"}},
+ }
+
if supportsIPv4map {
- dialerLocalAddrTests = append(dialerLocalAddrTests, dialerLocalAddrTest{
+ tests = append(tests, test{
"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, nil,
})
} else {
- dialerLocalAddrTests = append(dialerLocalAddrTests, dialerLocalAddrTest{
+ tests = append(tests, test{
"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, &AddrError{Err: "some error"},
})
}
}
}
- for _, tt := range dialerLocalAddrTests {
+ for _, tt := range tests {
d := &Dialer{LocalAddr: tt.laddr}
var addr string
ip := ParseIP(tt.raddr)
var timeout = 150*time.Millisecond + closedPortDelay
for _, dualstack := range []bool{false, true} {
- dss, err := newDualStackServer([]streamListener{
- {network: "tcp4", address: "127.0.0.1"},
- {network: "tcp6", address: "::1"},
- })
+ dss, err := newDualStackServer()
if err != nil {
t.Fatal(err)
}
}
if got := len(addrs); got != 1 {
- t.Fatal("got %d addresses, want 1", got)
+ t.Fatalf("got %d addresses, want 1", got)
}
if got, want := addrs[0].String(), "192.0.2.1"; got != want {
- t.Fatal("got address %v, want %v", got, want)
+ t.Fatalf("got address %v, want %v", got, want)
}
}
}
if got := resp.answer[0].(*dnsRR_A).A; got != TestAddr {
- t.Error("got address %v, want %v", got, TestAddr)
+ t.Errorf("got address %v, want %v", got, TestAddr)
}
}
ln.Close()
}
}
+
+func parseLookupPortError(nestedErr error) error {
+ if nestedErr == nil {
+ return nil
+ }
+
+ switch nestedErr.(type) {
+ case *AddrError, *DNSError:
+ return nil
+ case *os.PathError: // for Plan 9
+ return nil
+ }
+ return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
+}
return 0, err
}
defer fd.readUnlock()
+ if len(b) == 0 {
+ return 0, nil
+ }
n, err = fd.data.Read(b)
if isHangup(err) {
err = io.EOF
}
func (fd *netFD) file(f *os.File, s string) (*os.File, error) {
- syscall.ForkLock.RLock()
dfd, err := syscall.Dup(int(f.Fd()), -1)
- syscall.ForkLock.RUnlock()
if err != nil {
return nil, os.NewSyscallError("dup", err)
}
return 0, err
}
defer fd.readUnlock()
+ if len(p) == 0 {
+ // If the caller wanted a zero byte read, return immediately
+ // without trying. (But after acquiring the readLock.) Otherwise
+ // syscall.Read returns 0, nil and eofError turns that into
+ // io.EOF.
+ // TODO(bradfitz): make it wait for readability? (Issue 15735)
+ return 0, nil
+ }
if err := fd.pd.prepareRead(); err != nil {
return 0, err
}
if race.Enabled {
race.Acquire(unsafe.Pointer(&ioSync))
}
- err = fd.eofError(n, err)
+ if len(buf) != 0 {
+ err = fd.eofError(n, err)
+ }
if _, ok := err.(syscall.Errno); ok {
err = os.NewSyscallError("wsarecv", err)
}
name := comp[2]
switch file := comp[n-1]; file {
case "ctl", "clone":
- syscall.ForkLock.RLock()
fd, err := syscall.Dup(int(f.Fd()), -1)
- syscall.ForkLock.RUnlock()
if err != nil {
return nil, os.NewSyscallError("dup", err)
}
dir := netdir + "/" + comp[n-2]
ctl = os.NewFile(uintptr(fd), dir+"/"+file)
- ctl.Seek(0, 0)
+ ctl.Seek(0, io.SeekStart)
var buf [16]byte
n, err := ctl.Read(buf[:])
if err != nil {
// method returns both the previous Response (with its Body
// closed) and CheckRedirect's error (wrapped in a url.Error)
// instead of issuing the Request req.
+ // As a special case, if CheckRedirect returns ErrUseLastResponse,
+ // then the most recent response is returned with its body
+ // unclosed, along with a nil error.
//
// If CheckRedirect is nil, the Client uses its default policy,
// which is to stop after 10 consecutive requests.
func alwaysFalse() bool { return false }
+// ErrUseLastResponse can be returned by Client.CheckRedirect hooks to
+// control how redirects are processed. If returned, the next request
+// is not sent and the most recent response is returned with its body
+// unclosed.
+var ErrUseLastResponse = errors.New("net/http: use last response")
+
// checkRedirect calls either the user's configured CheckRedirect
// function, or the default.
func (c *Client) checkRedirect(req *Request, via []*Request) error {
req.closeBody()
method := valueOrDefault(reqs[0].Method, "GET")
var urlStr string
- if resp != nil {
+ if resp != nil && resp.Request != nil {
urlStr = resp.Request.URL.String()
} else {
urlStr = req.URL.String()
}
ireq := reqs[0]
req = &Request{
- Method: ireq.Method,
- URL: u,
- Header: make(Header),
- Cancel: ireq.Cancel,
- ctx: ireq.ctx,
+ Method: ireq.Method,
+ Response: resp,
+ URL: u,
+ Header: make(Header),
+ Cancel: ireq.Cancel,
+ ctx: ireq.ctx,
}
if ireq.Method == "POST" || ireq.Method == "PUT" {
req.Method = "GET"
if ref := refererForURL(reqs[len(reqs)-1].URL, req.URL); ref != "" {
req.Header.Set("Referer", ref)
}
- if err := c.checkRedirect(req, reqs); err != nil {
+ err = c.checkRedirect(req, reqs)
+
+ // Sentinel error to let users select the
+ // previous response, without closing its
+ // body. See Issue 10069.
+ if err == ErrUseLastResponse {
+ return resp, nil
+ }
+
+ // Close the previous response's body. But
+ // read at least some of the body so if it's
+ // small the underlying TCP connection will be
+ // re-used. No need to check for errors: if it
+ // fails, the Transport won't reuse it anyway.
+ const maxBodySlurpSize = 2 << 10
+ if resp.ContentLength == -1 || resp.ContentLength <= maxBodySlurpSize {
+ io.CopyN(ioutil.Discard, resp.Body, maxBodySlurpSize)
+ }
+ resp.Body.Close()
+
+ if err != nil {
// Special case for Go 1 compatibility: return both the response
// and an error if the CheckRedirect function failed.
// See https://golang.org/issue/3795
if !shouldRedirect(resp.StatusCode) {
return resp, nil
}
-
- // Read the body if small so underlying TCP connection will be re-used.
- // No need to check for errors: if it fails, Transport won't reuse it anyway.
- const maxBodySlurpSize = 2 << 10
- if resp.ContentLength == -1 || resp.ContentLength <= maxBodySlurpSize {
- io.CopyN(ioutil.Discard, resp.Body, maxBodySlurpSize)
- }
- resp.Body.Close()
}
}
}
}
+func TestClientRedirectUseResponse(t *testing.T) {
+ defer afterTest(t)
+ const body = "Hello, world."
+ var ts *httptest.Server
+ ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ if strings.Contains(r.URL.Path, "/other") {
+ io.WriteString(w, "wrong body")
+ } else {
+ w.Header().Set("Location", ts.URL+"/other")
+ w.WriteHeader(StatusFound)
+ io.WriteString(w, body)
+ }
+ }))
+ defer ts.Close()
+
+ c := &Client{CheckRedirect: func(req *Request, via []*Request) error {
+ if req.Response == nil {
+ t.Error("expected non-nil Request.Response")
+ }
+ return ErrUseLastResponse
+ }}
+ res, err := c.Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if res.StatusCode != StatusFound {
+ t.Errorf("status = %d; want %d", res.StatusCode, StatusFound)
+ }
+ defer res.Body.Close()
+ slurp, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if string(slurp) != body {
+ t.Errorf("body = %q; want %q", slurp, body)
+ }
+}
+
var expectedCookies = []*Cookie{
{Name: "ChocolateChip", Value: "tasty"},
{Name: "First", Value: "Hit"},
}
}
}
+
+// issue15577Tripper returns a Response with a redirect response
+// header and doesn't populate its Response.Request field.
+type issue15577Tripper struct{}
+
+func (issue15577Tripper) RoundTrip(*Request) (*Response, error) {
+ resp := &Response{
+ StatusCode: 303,
+ Header: map[string][]string{"Location": {"http://www.example.com/"}},
+ Body: ioutil.NopCloser(strings.NewReader("")),
+ }
+ return resp, nil
+}
+
+// Issue 15577: don't assume the roundtripper's response populates its Request field.
+func TestClientRedirectResponseWithoutRequest(t *testing.T) {
+ c := &Client{
+ CheckRedirect: func(*Request, []*Request) error { return fmt.Errorf("no redirects!") },
+ Transport: issue15577Tripper{},
+ }
+ // Check that this doesn't crash:
+ c.Get("http://dummy.tld")
+}
t.ts.Close()
}
+func (t *clientServerTest) scheme() string {
+ if t.h2 {
+ return "https"
+ }
+ return "http"
+}
+
const (
h1Mode = false
h2Mode = true
}
slurp, err := ioutil.ReadAll(res.Body)
- // TODO(bradfitz): short-term hack. Fix the
- // http2 side of golang.org/issue/15366 once
- // the http1 part is submitted.
- res.Uncompressed = false
-
res.Body.Close()
res.Body = slurpResult{
ReadCloser: ioutil.NopCloser(bytes.NewReader(slurp)),
io.WriteString(w, "\x1f\x8b\b\x00\x00\x00\x00\x00\x00\x00s\xf3\xf7\a\x00\xab'\xd4\x1a\x03\x00\x00\x00")
},
EarlyCheckResponse: func(proto string, res *Response) {
- if proto == "HTTP/2.0" {
- // TODO(bradfitz): Fix the http2 side
- // of golang.org/issue/15366 once the
- // http1 part is submitted.
- return
- }
if !res.Uncompressed {
t.Errorf("%s: expected Uncompressed to be set", proto)
}
}.run(t)
}
+// Issue 14607
+func TestCloseIdleConnections_h1(t *testing.T) { testCloseIdleConnections(t, h1Mode) }
+func TestCloseIdleConnections_h2(t *testing.T) { testCloseIdleConnections(t, h2Mode) }
+func testCloseIdleConnections(t *testing.T, h2 bool) {
+ defer afterTest(t)
+ cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header().Set("X-Addr", r.RemoteAddr)
+ }))
+ defer cst.close()
+ get := func() string {
+ res, err := cst.c.Get(cst.ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ res.Body.Close()
+ v := res.Header.Get("X-Addr")
+ if v == "" {
+ t.Fatal("didn't get X-Addr")
+ }
+ return v
+ }
+ a1 := get()
+ cst.tr.CloseIdleConnections()
+ a2 := get()
+ if a1 == a2 {
+ t.Errorf("didn't close connection")
+ }
+}
+
type noteCloseConn struct {
net.Conn
closeFunc func()
)
var (
- DefaultUserAgent = defaultUserAgent
- NewLoggingConn = newLoggingConn
- ExportAppendTime = appendTime
- ExportRefererForURL = refererForURL
- ExportServerNewConn = (*Server).newConn
- ExportCloseWriteAndWait = (*conn).closeWriteAndWait
- ExportErrRequestCanceled = errRequestCanceled
- ExportErrRequestCanceledConn = errRequestCanceledConn
- ExportServeFile = serveFile
- ExportHttp2ConfigureTransport = http2ConfigureTransport
- ExportHttp2ConfigureServer = http2ConfigureServer
+ DefaultUserAgent = defaultUserAgent
+ NewLoggingConn = newLoggingConn
+ ExportAppendTime = appendTime
+ ExportRefererForURL = refererForURL
+ ExportServerNewConn = (*Server).newConn
+ ExportCloseWriteAndWait = (*conn).closeWriteAndWait
+ ExportErrRequestCanceled = errRequestCanceled
+ ExportErrRequestCanceledConn = errRequestCanceledConn
+ ExportServeFile = serveFile
+ ExportHttp2ConfigureServer = http2ConfigureServer
)
func init() {
*dst = fn
}
}
+
+func ExportHttp2ConfigureTransport(t *Transport) error {
+ t2, err := http2configureTransport(t)
+ if err != nil {
+ return err
+ }
+ t.h2transport = t2
+ return nil
+}
"bufio"
"bytes"
"compress/gzip"
+ "context"
"crypto/tls"
"encoding/binary"
"errors"
"fmt"
"golang.org/x/net/http2/hpack"
+ "golang.org/x/net/lex/httplex"
"io"
"io/ioutil"
"log"
"net"
+ "net/http/httptrace"
"net/textproto"
"net/url"
"os"
MarkDead(*http2ClientConn)
}
+// clientConnPoolIdleCloser is the interface implemented by ClientConnPool
+// implementations which can close their idle connections.
+type http2clientConnPoolIdleCloser interface {
+ http2ClientConnPool
+ closeIdleConnections()
+}
+
+var (
+ _ http2clientConnPoolIdleCloser = (*http2clientConnPool)(nil)
+ _ http2clientConnPoolIdleCloser = http2noDialClientConnPool{}
+)
+
// TODO: use singleflight for dialing and addConnCalls?
type http2clientConnPool struct {
t *http2Transport
return out
}
+// noDialClientConnPool is an implementation of http2.ClientConnPool
+// which never dials. We let the HTTP/1.1 client dial and use its TLS
+// connection instead.
+type http2noDialClientConnPool struct{ *http2clientConnPool }
+
+func (p http2noDialClientConnPool) GetClientConn(req *Request, addr string) (*http2ClientConn, error) {
+ return p.getClientConn(req, addr, http2noDialOnMiss)
+}
+
func http2configureTransport(t1 *Transport) (*http2Transport, error) {
connPool := new(http2clientConnPool)
t2 := &http2Transport{
return nil
}
-// noDialClientConnPool is an implementation of http2.ClientConnPool
-// which never dials. We let the HTTP/1.1 client dial and use its TLS
-// connection instead.
-type http2noDialClientConnPool struct{ *http2clientConnPool }
-
-func (p http2noDialClientConnPool) GetClientConn(req *Request, addr string) (*http2ClientConn, error) {
- return p.getClientConn(req, addr, http2noDialOnMiss)
-}
-
// noDialH2RoundTripper is a RoundTripper which only tries to complete the request
// if there's already has a cached connection to the host.
type http2noDialH2RoundTripper struct{ t *http2Transport }
return f, nil
}
-var http2errStreamID = errors.New("invalid streamid")
+var (
+ http2errStreamID = errors.New("invalid stream ID")
+ http2errDepStreamID = errors.New("invalid dependent stream ID")
+)
+
+func http2validStreamIDOrZero(streamID uint32) bool {
+ return streamID&(1<<31) == 0
+}
func http2validStreamID(streamID uint32) bool {
return streamID != 0 && streamID&(1<<31) == 0
}
if !p.Priority.IsZero() {
v := p.Priority.StreamDep
- if !http2validStreamID(v) && !f.AllowIllegalWrites {
- return errors.New("invalid dependent stream id")
+ if !http2validStreamIDOrZero(v) && !f.AllowIllegalWrites {
+ return http2errDepStreamID
}
if p.Priority.Exclusive {
v |= 1 << 31
if !http2validStreamID(streamID) && !f.AllowIllegalWrites {
return http2errStreamID
}
+ if !http2validStreamIDOrZero(p.StreamDep) {
+ return http2errDepStreamID
+ }
f.startWrite(http2FramePriority, 0, streamID)
v := p.StreamDep
if p.Exclusive {
hdec.SetEmitEnabled(true)
hdec.SetMaxStringLength(fr.maxHeaderStringLen())
hdec.SetEmitFunc(func(hf hpack.HeaderField) {
- if !http2validHeaderFieldValue(hf.Value) {
+ if !httplex.ValidHeaderFieldValue(hf.Value) {
invalid = http2headerFieldValueError(hf.Value)
}
isPseudo := strings.HasPrefix(hf.Name, ":")
}
} else {
sawRegular = true
- if !http2validHeaderFieldName(hf.Name) {
+ if !http2validWireHeaderFieldName(hf.Name) {
invalid = http2headerFieldNameError(hf.Name)
}
}
return buf.String()
}
-func http2requestCancel(req *Request) <-chan struct{} { return req.Cancel }
+func http2transportExpectContinueTimeout(t1 *Transport) time.Duration {
+ return t1.ExpectContinueTimeout
+}
+
+type http2contextContext interface {
+ context.Context
+}
+
+func http2serverConnBaseContext(c net.Conn, opts *http2ServeConnOpts) (ctx http2contextContext, cancel func()) {
+ ctx, cancel = context.WithCancel(context.Background())
+ ctx = context.WithValue(ctx, LocalAddrContextKey, c.LocalAddr())
+ if hs := opts.baseConfig(); hs != nil {
+ ctx = context.WithValue(ctx, ServerContextKey, hs)
+ }
+ return
+}
+
+func http2contextWithCancel(ctx http2contextContext) (_ http2contextContext, cancel func()) {
+ return context.WithCancel(ctx)
+}
+
+func http2requestWithContext(req *Request, ctx http2contextContext) *Request {
+ return req.WithContext(ctx)
+}
+
+type http2clientTrace httptrace.ClientTrace
+
+func http2reqContext(r *Request) context.Context { return r.Context() }
+
+func http2setResponseUncompressed(res *Response) { res.Uncompressed = true }
+
+func http2traceGotConn(req *Request, cc *http2ClientConn) {
+ trace := httptrace.ContextClientTrace(req.Context())
+ if trace == nil || trace.GotConn == nil {
+ return
+ }
+ ci := httptrace.GotConnInfo{Conn: cc.tconn}
+ cc.mu.Lock()
+ ci.Reused = cc.nextStreamID > 1
+ ci.WasIdle = len(cc.streams) == 0 && ci.Reused
+ if ci.WasIdle && !cc.lastActive.IsZero() {
+ ci.IdleTime = time.Now().Sub(cc.lastActive)
+ }
+ cc.mu.Unlock()
+
+ trace.GotConn(ci)
+}
+
+func http2traceWroteHeaders(trace *http2clientTrace) {
+ if trace != nil && trace.WroteHeaders != nil {
+ trace.WroteHeaders()
+ }
+}
+
+func http2traceGot100Continue(trace *http2clientTrace) {
+ if trace != nil && trace.Got100Continue != nil {
+ trace.Got100Continue()
+ }
+}
+
+func http2traceWait100Continue(trace *http2clientTrace) {
+ if trace != nil && trace.Wait100Continue != nil {
+ trace.Wait100Continue()
+ }
+}
+
+func http2traceWroteRequest(trace *http2clientTrace, err error) {
+ if trace != nil && trace.WroteRequest != nil {
+ trace.WroteRequest(httptrace.WroteRequestInfo{Err: err})
+ }
+}
+
+func http2traceFirstResponseByte(trace *http2clientTrace) {
+ if trace != nil && trace.GotFirstResponseByte != nil {
+ trace.GotFirstResponseByte()
+ }
+}
+
+func http2requestTrace(req *Request) *http2clientTrace {
+ trace := httptrace.ContextClientTrace(req.Context())
+ return (*http2clientTrace)(trace)
+}
var http2DebugGoroutines = os.Getenv("DEBUG_HTTP2_GOROUTINES") == "1"
http2errInvalidHeaderFieldValue = errors.New("http2: invalid header field value")
)
-// validHeaderFieldName reports whether v is a valid header field name (key).
-// RFC 7230 says:
-// header-field = field-name ":" OWS field-value OWS
-// field-name = token
-// token = 1*tchar
-// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
-// "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
+// validWireHeaderFieldName reports whether v is a valid header field
+// name (key). See httplex.ValidHeaderName for the base rules.
+//
// Further, http2 says:
// "Just as in HTTP/1.x, header field names are strings of ASCII
// characters that are compared in a case-insensitive
// fashion. However, header field names MUST be converted to
// lowercase prior to their encoding in HTTP/2. "
-func http2validHeaderFieldName(v string) bool {
+func http2validWireHeaderFieldName(v string) bool {
if len(v) == 0 {
return false
}
for _, r := range v {
- if int(r) >= len(http2isTokenTable) || ('A' <= r && r <= 'Z') {
- return false
- }
- if !http2isTokenTable[byte(r)] {
+ if !httplex.IsTokenRune(r) {
return false
}
- }
- return true
-}
-
-// validHeaderFieldValue reports whether v is a valid header field value.
-//
-// RFC 7230 says:
-// field-value = *( field-content / obs-fold )
-// obj-fold = N/A to http2, and deprecated
-// field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
-// field-vchar = VCHAR / obs-text
-// obs-text = %x80-FF
-// VCHAR = "any visible [USASCII] character"
-//
-// http2 further says: "Similarly, HTTP/2 allows header field values
-// that are not valid. While most of the values that can be encoded
-// will not alter header field parsing, carriage return (CR, ASCII
-// 0xd), line feed (LF, ASCII 0xa), and the zero character (NUL, ASCII
-// 0x0) might be exploited by an attacker if they are translated
-// verbatim. Any request or response that contains a character not
-// permitted in a header field value MUST be treated as malformed
-// (Section 8.1.2.6). Valid characters are defined by the
-// field-content ABNF rule in Section 3.2 of [RFC7230]."
-//
-// This function does not (yet?) properly handle the rejection of
-// strings that begin or end with SP or HTAB.
-func http2validHeaderFieldValue(v string) bool {
- for i := 0; i < len(v); i++ {
- if b := v[i]; b < ' ' && b != '\t' || b == 0x7f {
+ if 'A' <= r && r <= 'Z' {
return false
}
}
}
// bodyAllowedForStatus reports whether a given response status code
-// permits a body. See RFC2616, section 4.4.
+// permits a body. See RFC 2616, section 4.4.
func http2bodyAllowedForStatus(status int) bool {
switch {
case status >= 100 && status <= 199:
var http2errTimeout error = &http2httpError{msg: "http2: timeout awaiting response headers", timeout: true}
-var http2isTokenTable = [127]bool{
- '!': true,
- '#': true,
- '$': true,
- '%': true,
- '&': true,
- '\'': true,
- '*': true,
- '+': true,
- '-': true,
- '.': true,
- '0': true,
- '1': true,
- '2': true,
- '3': true,
- '4': true,
- '5': true,
- '6': true,
- '7': true,
- '8': true,
- '9': true,
- 'A': true,
- 'B': true,
- 'C': true,
- 'D': true,
- 'E': true,
- 'F': true,
- 'G': true,
- 'H': true,
- 'I': true,
- 'J': true,
- 'K': true,
- 'L': true,
- 'M': true,
- 'N': true,
- 'O': true,
- 'P': true,
- 'Q': true,
- 'R': true,
- 'S': true,
- 'T': true,
- 'U': true,
- 'W': true,
- 'V': true,
- 'X': true,
- 'Y': true,
- 'Z': true,
- '^': true,
- '_': true,
- '`': true,
- 'a': true,
- 'b': true,
- 'c': true,
- 'd': true,
- 'e': true,
- 'f': true,
- 'g': true,
- 'h': true,
- 'i': true,
- 'j': true,
- 'k': true,
- 'l': true,
- 'm': true,
- 'n': true,
- 'o': true,
- 'p': true,
- 'q': true,
- 'r': true,
- 's': true,
- 't': true,
- 'u': true,
- 'v': true,
- 'w': true,
- 'x': true,
- 'y': true,
- 'z': true,
- '|': true,
- '~': true,
-}
-
type http2connectionStater interface {
ConnectionState() tls.ConnectionState
}
//
// The opts parameter is optional. If nil, default values are used.
func (s *http2Server) ServeConn(c net.Conn, opts *http2ServeConnOpts) {
+ baseCtx, cancel := http2serverConnBaseContext(c, opts)
+ defer cancel()
+
sc := &http2serverConn{
srv: s,
hs: opts.baseConfig(),
conn: c,
+ baseCtx: baseCtx,
remoteAddrStr: c.RemoteAddr().String(),
bw: http2newBufferedWriter(c),
handler: opts.handler(),
serveG: http2newGoroutineLock(),
pushEnabled: true,
}
+
sc.flow.add(http2initialWindowSize)
sc.inflow.add(http2initialWindowSize)
sc.hpackEncoder = hpack.NewEncoder(&sc.headerWriteBuf)
conn net.Conn
bw *http2bufferedWriter // writing to conn
handler Handler
+ baseCtx http2contextContext
framer *http2Framer
doneServing chan struct{} // closed when serverConn.serve ends
readFrameCh chan http2readFrameResult // written by serverConn.readFrames
// responseWriter's state field.
type http2stream struct {
// immutable:
- sc *http2serverConn
- id uint32
- body *http2pipe // non-nil if expecting DATA frames
- cw http2closeWaiter // closed wait stream transitions to closed state
+ sc *http2serverConn
+ id uint32
+ body *http2pipe // non-nil if expecting DATA frames
+ cw http2closeWaiter // closed wait stream transitions to closed state
+ ctx http2contextContext
+ cancelCtx func()
// owned by serverConn's serve loop:
bodyBytes int64 // body bytes seen so far
sentReset bool // only true once detached from streams map
gotReset bool // only true once detacted from streams map
gotTrailerHeader bool // HEADER frame for trailers was seen
+ wroteHeaders bool // whether we wrote headers (not status 100)
reqBuf []byte
trailer Header // accumulated trailers
// If you're not on the serve goroutine, use writeFrameFromHandler instead.
func (sc *http2serverConn) writeFrame(wm http2frameWriteMsg) {
sc.serveG.check()
- sc.writeSched.add(wm)
+
+ var ignoreWrite bool
+
+ switch wm.write.(type) {
+ case *http2writeResHeaders:
+ wm.stream.wroteHeaders = true
+ case http2write100ContinueHeadersFrame:
+ if wm.stream.wroteHeaders {
+ ignoreWrite = true
+ }
+ }
+
+ if !ignoreWrite {
+ sc.writeSched.add(wm)
+ }
sc.scheduleFrameWrite()
}
}
if st != nil {
st.gotReset = true
+ st.cancelCtx()
sc.closeStream(st, http2StreamError{f.StreamID, f.ErrCode})
}
return nil
}
sc.maxStreamID = id
+ ctx, cancelCtx := http2contextWithCancel(sc.baseCtx)
st = &http2stream{
- sc: sc,
- id: id,
- state: http2stateOpen,
+ sc: sc,
+ id: id,
+ state: http2stateOpen,
+ ctx: ctx,
+ cancelCtx: cancelCtx,
}
if f.StreamEnded() {
st.state = http2stateHalfClosedRemote
if f.Truncated {
handler = http2handleHeaderListTooLong
+ } else if err := http2checkValidHTTP2Request(req); err != nil {
+ handler = http2new400Handler(err)
}
go sc.runHandler(rw, req, handler)
if st.trailer != nil {
for _, hf := range f.RegularFields() {
key := sc.canonicalHeader(hf.Name)
+ if !http2ValidTrailerHeader(key) {
+
+ return http2StreamError{st.id, http2ErrCodeProtocol}
+ }
st.trailer[key] = append(st.trailer[key], hf.Value)
}
}
Body: body,
Trailer: trailer,
}
+ req = http2requestWithContext(req, st.ctx)
if bodyOpen {
buf := make([]byte, http2initialWindowSize)
func (sc *http2serverConn) runHandler(rw *http2responseWriter, req *Request, handler func(ResponseWriter, *Request)) {
didPanic := true
defer func() {
+ rw.rws.stream.cancelCtx()
if didPanic {
e := recover()
// Same as net/http:
func (b *http2requestBody) Close() error {
if b.pipe != nil {
- b.pipe.CloseWithError(http2errClosedBody)
+ b.pipe.BreakWithError(http2errClosedBody)
}
b.closed = true
return nil
// written in the trailers at the end of the response.
func (rws *http2responseWriterState) declareTrailer(k string) {
k = CanonicalHeaderKey(k)
- switch k {
- case "Transfer-Encoding", "Content-Length", "Trailer":
+ if !http2ValidTrailerHeader(k) {
+ rws.conn.logf("ignoring invalid trailer %q", k)
return
}
if !http2strSliceContains(rws.trailers, k) {
}
}
+// From http://httpwg.org/specs/rfc7540.html#rfc.section.8.1.2.2
+var http2connHeaders = []string{
+ "Connection",
+ "Keep-Alive",
+ "Proxy-Connection",
+ "Transfer-Encoding",
+ "Upgrade",
+}
+
+// checkValidHTTP2Request checks whether req is a valid HTTP/2 request,
+// per RFC 7540 Section 8.1.2.2.
+// The returned error is reported to users.
+func http2checkValidHTTP2Request(req *Request) error {
+ for _, h := range http2connHeaders {
+ if _, ok := req.Header[h]; ok {
+ return fmt.Errorf("request header %q is not valid in HTTP/2", h)
+ }
+ }
+ te := req.Header["Te"]
+ if len(te) > 0 && (len(te) > 1 || (te[0] != "trailers" && te[0] != "")) {
+ return errors.New(`request header "TE" may only be "trailers" in HTTP/2`)
+ }
+ return nil
+}
+
+func http2new400Handler(err error) HandlerFunc {
+ return func(w ResponseWriter, r *Request) {
+ Error(w, err.Error(), StatusBadRequest)
+ }
+}
+
+// ValidTrailerHeader reports whether name is a valid header field name to appear
+// in trailers.
+// See: http://tools.ietf.org/html/rfc7230#section-4.1.2
+func http2ValidTrailerHeader(name string) bool {
+ name = CanonicalHeaderKey(name)
+ if strings.HasPrefix(name, "If-") || http2badTrailer[name] {
+ return false
+ }
+ return true
+}
+
+var http2badTrailer = map[string]bool{
+ "Authorization": true,
+ "Cache-Control": true,
+ "Connection": true,
+ "Content-Encoding": true,
+ "Content-Length": true,
+ "Content-Range": true,
+ "Content-Type": true,
+ "Expect": true,
+ "Host": true,
+ "Keep-Alive": true,
+ "Max-Forwards": true,
+ "Pragma": true,
+ "Proxy-Authenticate": true,
+ "Proxy-Authorization": true,
+ "Proxy-Connection": true,
+ "Range": true,
+ "Realm": true,
+ "Te": true,
+ "Trailer": true,
+ "Transfer-Encoding": true,
+ "Www-Authenticate": true,
+}
+
const (
// transportDefaultConnFlow is how many connection-level flow control
// tokens we give the server at start-up, past the default 64k.
bw *bufio.Writer
br *bufio.Reader
fr *http2Framer
+ lastActive time.Time
+
// Settings from peer:
maxFrameSize uint32
maxConcurrentStreams uint32
type http2clientStream struct {
cc *http2ClientConn
req *Request
+ trace *http2clientTrace // or nil
ID uint32
resc chan http2resAndError
bufPipe http2pipe // buffered pipe with the flow-controlled response payload
requestedGzip bool
+ on100 func() // optional code to run if get a 100 continue response
flow http2flow // guarded by cc.mu
inflow http2flow // guarded by cc.mu
}
// awaitRequestCancel runs in its own goroutine and waits for the user
-// to either cancel a RoundTrip request (using the provided
-// Request.Cancel channel), or for the request to be done (any way it
-// might be removed from the cc.streams map: peer reset, successful
-// completion, TCP connection breakage, etc)
-func (cs *http2clientStream) awaitRequestCancel(cancel <-chan struct{}) {
- if cancel == nil {
+// to cancel a RoundTrip request, its context to expire, or for the
+// request to be done (any way it might be removed from the cc.streams
+// map: peer reset, successful completion, TCP connection breakage,
+// etc)
+func (cs *http2clientStream) awaitRequestCancel(req *Request) {
+ ctx := http2reqContext(req)
+ if req.Cancel == nil && ctx.Done() == nil {
return
}
select {
- case <-cancel:
+ case <-req.Cancel:
cs.bufPipe.CloseWithError(http2errRequestCanceled)
cs.cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil)
+ case <-ctx.Done():
+ cs.bufPipe.CloseWithError(ctx.Err())
+ cs.cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil)
case <-cs.done:
}
}
-// checkReset reports any error sent in a RST_STREAM frame by the
-// server.
-func (cs *http2clientStream) checkReset() error {
+// checkResetOrDone reports any error sent in a RST_STREAM frame by the
+// server, or errStreamClosed if the stream is complete.
+func (cs *http2clientStream) checkResetOrDone() error {
select {
case <-cs.peerReset:
return cs.resetErr
+ case <-cs.done:
+ return http2errStreamClosed
default:
return nil
}
t.vlogf("http2: Transport failed to get client conn for %s: %v", addr, err)
return nil, err
}
+ http2traceGotConn(req, cc)
res, err := cc.RoundTrip(req)
if http2shouldRetryRequest(req, err) {
continue
// connected from previous requests but are now sitting idle.
// It does not interrupt any connections currently in use.
func (t *http2Transport) CloseIdleConnections() {
- if cp, ok := t.connPool().(*http2clientConnPool); ok {
+ if cp, ok := t.connPool().(http2clientConnPoolIdleCloser); ok {
cp.closeIdleConnections()
}
}
return t.t1 != nil && t.t1.DisableKeepAlives
}
+func (t *http2Transport) expectContinueTimeout() time.Duration {
+ if t.t1 == nil {
+ return 0
+ }
+ return http2transportExpectContinueTimeout(t.t1)
+}
+
func (t *http2Transport) NewClientConn(c net.Conn) (*http2ClientConn, error) {
if http2VerboseLogs {
t.vlogf("http2: Transport creating client conn to %v", c.RemoteAddr())
return nil
}
+func http2bodyAndLength(req *Request) (body io.Reader, contentLen int64) {
+ body = req.Body
+ if body == nil {
+ return nil, 0
+ }
+ if req.ContentLength != 0 {
+ return req.Body, req.ContentLength
+ }
+
+ // We have a body but a zero content length. Test to see if
+ // it's actually zero or just unset.
+ var buf [1]byte
+ n, rerr := io.ReadFull(body, buf[:])
+ if rerr != nil && rerr != io.EOF {
+ return http2errorReader{rerr}, -1
+ }
+ if n == 1 {
+
+ return io.MultiReader(bytes.NewReader(buf[:]), body), -1
+ }
+
+ return nil, 0
+}
+
func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) {
if err := http2checkConnHeaders(req); err != nil {
return nil, err
}
hasTrailers := trailers != ""
- var body io.Reader = req.Body
- contentLen := req.ContentLength
- if req.Body != nil && contentLen == 0 {
- // Test to see if it's actually zero or just unset.
- var buf [1]byte
- n, rerr := io.ReadFull(body, buf[:])
- if rerr != nil && rerr != io.EOF {
- contentLen = -1
- body = http2errorReader{rerr}
- } else if n == 1 {
-
- contentLen = -1
- body = io.MultiReader(bytes.NewReader(buf[:]), body)
- } else {
-
- body = nil
- }
- }
+ body, contentLen := http2bodyAndLength(req)
+ hasBody := body != nil
cc.mu.Lock()
+ cc.lastActive = time.Now()
if cc.closed || !cc.canTakeNewRequestLocked() {
cc.mu.Unlock()
return nil, http2errClientConnUnusable
}
- cs := cc.newStream()
- cs.req = req
- hasBody := body != nil
-
+ // TODO(bradfitz): this is a copy of the logic in net/http. Unify somewhere?
+ var requestedGzip bool
if !cc.t.disableCompression() &&
req.Header.Get("Accept-Encoding") == "" &&
req.Header.Get("Range") == "" &&
req.Method != "HEAD" {
- cs.requestedGzip = true
+ requestedGzip = true
}
- hdrs := cc.encodeHeaders(req, cs.requestedGzip, trailers, contentLen)
+ hdrs, err := cc.encodeHeaders(req, requestedGzip, trailers, contentLen)
+ if err != nil {
+ cc.mu.Unlock()
+ return nil, err
+ }
+
+ cs := cc.newStream()
+ cs.req = req
+ cs.trace = http2requestTrace(req)
+ cs.requestedGzip = requestedGzip
+ bodyWriter := cc.t.getBodyWriterState(cs, body)
+ cs.on100 = bodyWriter.on100
+
cc.wmu.Lock()
endStream := !hasBody && !hasTrailers
werr := cc.writeHeaders(cs.ID, endStream, hdrs)
cc.wmu.Unlock()
+ http2traceWroteHeaders(cs.trace)
cc.mu.Unlock()
if werr != nil {
if hasBody {
req.Body.Close()
+ bodyWriter.cancel()
}
cc.forgetStreamID(cs.ID)
+ http2traceWroteRequest(cs.trace, werr)
return nil, werr
}
var respHeaderTimer <-chan time.Time
- var bodyCopyErrc chan error // result of body copy
if hasBody {
- bodyCopyErrc = make(chan error, 1)
- go func() {
- bodyCopyErrc <- cs.writeRequestBody(body, req.Body)
- }()
+ bodyWriter.scheduleBodyWrite()
} else {
+ http2traceWroteRequest(cs.trace, nil)
if d := cc.responseHeaderTimeout(); d != 0 {
timer := time.NewTimer(d)
defer timer.Stop()
}
readLoopResCh := cs.resc
- requestCanceledCh := http2requestCancel(req)
bodyWritten := false
+ ctx := http2reqContext(req)
for {
select {
res := re.res
if re.err != nil || res.StatusCode > 299 {
+ bodyWriter.cancel()
cs.abortRequestBodyWrite(http2errStopReqBodyWrite)
}
if re.err != nil {
if !hasBody || bodyWritten {
cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil)
} else {
+ bodyWriter.cancel()
cs.abortRequestBodyWrite(http2errStopReqBodyWriteAndCancel)
}
return nil, http2errTimeout
- case <-requestCanceledCh:
+ case <-ctx.Done():
+ cc.forgetStreamID(cs.ID)
+ if !hasBody || bodyWritten {
+ cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil)
+ } else {
+ bodyWriter.cancel()
+ cs.abortRequestBodyWrite(http2errStopReqBodyWriteAndCancel)
+ }
+ return nil, ctx.Err()
+ case <-req.Cancel:
cc.forgetStreamID(cs.ID)
if !hasBody || bodyWritten {
cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil)
} else {
+ bodyWriter.cancel()
cs.abortRequestBodyWrite(http2errStopReqBodyWriteAndCancel)
}
return nil, http2errRequestCanceled
case <-cs.peerReset:
return nil, cs.resetErr
- case err := <-bodyCopyErrc:
+ case err := <-bodyWriter.resc:
if err != nil {
return nil, err
}
defer cc.putFrameScratchBuffer(buf)
defer func() {
+ http2traceWroteRequest(cs.trace, err)
cerr := bodyCloser.Close()
if err == nil {
if cs.stopReqBody != nil {
return 0, cs.stopReqBody
}
- if err := cs.checkReset(); err != nil {
+ if err := cs.checkResetOrDone(); err != nil {
return 0, err
}
if a := cs.flow.available(); a > 0 {
func (e *http2badStringError) Error() string { return fmt.Sprintf("%s %q", e.what, e.str) }
// requires cc.mu be held.
-func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trailers string, contentLength int64) []byte {
+func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trailers string, contentLength int64) ([]byte, error) {
cc.hbuf.Reset()
host := req.Host
host = req.URL.Host
}
+ for k, vv := range req.Header {
+ if !httplex.ValidHeaderFieldName(k) {
+ return nil, fmt.Errorf("invalid HTTP header name %q", k)
+ }
+ for _, v := range vv {
+ if !httplex.ValidHeaderFieldValue(v) {
+ return nil, fmt.Errorf("invalid HTTP header value %q for header %q", v, k)
+ }
+ }
+ }
+
cc.writeHeader(":authority", host)
cc.writeHeader(":method", req.Method)
if req.Method != "CONNECT" {
case "host", "content-length":
continue
- case "connection", "proxy-connection", "transfer-encoding", "upgrade":
+ case "connection", "proxy-connection", "transfer-encoding", "upgrade", "keep-alive":
continue
case "user-agent":
if !didUA {
cc.writeHeader("user-agent", http2defaultUserAgent)
}
- return cc.hbuf.Bytes()
+ return cc.hbuf.Bytes(), nil
}
// shouldSendReqContentLength reports whether the http2.Transport should send
defer cc.mu.Unlock()
cs := cc.streams[id]
if andRemove && cs != nil && !cc.closed {
+ cc.lastActive = time.Now()
delete(cc.streams, id)
close(cs.done)
+ cc.cond.Broadcast()
}
return cs
}
} else {
return rl.processTrailers(cs, f)
}
+ if cs.trace != nil {
+
+ http2traceFirstResponseByte(cs.trace)
+ }
res, err := rl.handleResponse(cs, f)
if err != nil {
}
if statusCode == 100 {
-
+ http2traceGot100Continue(cs.trace)
+ if cs.on100 != nil {
+ cs.on100()
+ }
cs.pastHeaders = false
return nil, nil
}
cs.bufPipe = http2pipe{b: buf}
cs.bytesRemain = res.ContentLength
res.Body = http2transportResponseBody{cs}
- go cs.awaitRequestCancel(http2requestCancel(cs.req))
+ go cs.awaitRequestCancel(cs.req)
if cs.requestedGzip && res.Header.Get("Content-Encoding") == "gzip" {
res.Header.Del("Content-Encoding")
res.Header.Del("Content-Length")
res.ContentLength = -1
res.Body = &http2gzipReader{body: res.Body}
+ http2setResponseUncompressed(res)
}
return res, nil
}
func (r http2errorReader) Read(p []byte) (int, error) { return 0, r.err }
+// bodyWriterState encapsulates various state around the Transport's writing
+// of the request body, particularly regarding doing delayed writes of the body
+// when the request contains "Expect: 100-continue".
+type http2bodyWriterState struct {
+ cs *http2clientStream
+ timer *time.Timer // if non-nil, we're doing a delayed write
+ fnonce *sync.Once // to call fn with
+ fn func() // the code to run in the goroutine, writing the body
+ resc chan error // result of fn's execution
+ delay time.Duration // how long we should delay a delayed write for
+}
+
+func (t *http2Transport) getBodyWriterState(cs *http2clientStream, body io.Reader) (s http2bodyWriterState) {
+ s.cs = cs
+ if body == nil {
+ return
+ }
+ resc := make(chan error, 1)
+ s.resc = resc
+ s.fn = func() {
+ resc <- cs.writeRequestBody(body, cs.req.Body)
+ }
+ s.delay = t.expectContinueTimeout()
+ if s.delay == 0 ||
+ !httplex.HeaderValuesContainsToken(
+ cs.req.Header["Expect"],
+ "100-continue") {
+ return
+ }
+ s.fnonce = new(sync.Once)
+
+ // Arm the timer with a very large duration, which we'll
+ // intentionally lower later. It has to be large now because
+ // we need a handle to it before writing the headers, but the
+ // s.delay value is defined to not start until after the
+ // request headers were written.
+ const hugeDuration = 365 * 24 * time.Hour
+ s.timer = time.AfterFunc(hugeDuration, func() {
+ s.fnonce.Do(s.fn)
+ })
+ return
+}
+
+func (s http2bodyWriterState) cancel() {
+ if s.timer != nil {
+ s.timer.Stop()
+ }
+}
+
+func (s http2bodyWriterState) on100() {
+ if s.timer == nil {
+
+ return
+ }
+ s.timer.Stop()
+ go func() { s.fnonce.Do(s.fn) }()
+}
+
+// scheduleBodyWrite starts writing the body, either immediately (in
+// the common case) or after the delay timeout. It should not be
+// called until after the headers have been written.
+func (s http2bodyWriterState) scheduleBodyWrite() {
+ if s.timer == nil {
+
+ go s.fn()
+ return
+ }
+ http2traceWait100Continue(s.cs.trace)
+ if s.timer.Stop() {
+ s.timer.Reset(s.delay)
+ }
+}
+
// writeFramer is implemented by any type that is used to write frames.
type http2writeFramer interface {
writeFrame(http2writeContext) error
for _, k := range keys {
vv := h[k]
k = http2lowerHeader(k)
- if !http2validHeaderFieldName(k) {
+ if !http2validWireHeaderFieldName(k) {
continue
}
isTE := k == "transfer-encoding"
for _, v := range vv {
- if !http2validHeaderFieldValue(v) {
+ if !httplex.ValidHeaderFieldValue(v) {
continue
}
import (
"strings"
+
+ "golang.org/x/net/lex/httplex"
)
// maxInt64 is the effective "infinite" value for the Server and
}
return host
}
+
+func isNotToken(r rune) bool {
+ return !httplex.IsTokenRune(r)
+}
import (
"bytes"
+ "io/ioutil"
"net/http"
)
Body *bytes.Buffer // if non-nil, the bytes.Buffer to append written data to
Flushed bool
- stagingMap http.Header // map that handlers manipulate to set headers
- trailerMap http.Header // lazily filled when Trailers() is called
-
+ result *http.Response // cache of Result's return value
+ snapHeader http.Header // snapshot of HeaderMap at first Write
wroteHeader bool
}
// Header returns the response headers.
func (rw *ResponseRecorder) Header() http.Header {
- m := rw.stagingMap
+ m := rw.HeaderMap
if m == nil {
m = make(http.Header)
- rw.stagingMap = m
+ rw.HeaderMap = m
}
return m
}
if rw.HeaderMap == nil {
rw.HeaderMap = make(http.Header)
}
- for k, vv := range rw.stagingMap {
+ rw.snapHeader = cloneHeader(rw.HeaderMap)
+}
+
+func cloneHeader(h http.Header) http.Header {
+ h2 := make(http.Header, len(h))
+ for k, vv := range h {
vv2 := make([]string, len(vv))
copy(vv2, vv)
- rw.HeaderMap[k] = vv2
+ h2[k] = vv2
}
+ return h2
}
// Flush sets rw.Flushed to true.
rw.Flushed = true
}
-// Trailers returns any trailers set by the handler. It must be called
-// after the handler finished running.
-func (rw *ResponseRecorder) Trailers() http.Header {
- if rw.trailerMap != nil {
- return rw.trailerMap
- }
- trailers, ok := rw.HeaderMap["Trailer"]
- if !ok {
- rw.trailerMap = make(http.Header)
- return rw.trailerMap
- }
- rw.trailerMap = make(http.Header, len(trailers))
- for _, k := range trailers {
- switch k {
- case "Transfer-Encoding", "Content-Length", "Trailer":
- // Ignore since forbidden by RFC 2616 14.40.
- continue
- }
- k = http.CanonicalHeaderKey(k)
- vv, ok := rw.stagingMap[k]
- if !ok {
- continue
+// Result returns the response generated by the handler.
+//
+// The returned Response will have at least its StatusCode,
+// Header, Body, and optionally Trailer populated.
+// More fields may be populated in the future, so callers should
+// not DeepEqual the result in tests.
+//
+// The Response.Header is a snapshot of the headers at the time of the
+// first write call, or at the time of this call, if the handler never
+// did a write.
+//
+// Result must only be called after the handler has finished running.
+func (rw *ResponseRecorder) Result() *http.Response {
+ if rw.result != nil {
+ return rw.result
+ }
+ if rw.snapHeader == nil {
+ rw.snapHeader = cloneHeader(rw.HeaderMap)
+ }
+ res := &http.Response{
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ StatusCode: rw.Code,
+ Header: rw.snapHeader,
+ }
+ rw.result = res
+ if res.StatusCode == 0 {
+ res.StatusCode = 200
+ }
+ res.Status = http.StatusText(res.StatusCode)
+ if rw.Body != nil {
+ res.Body = ioutil.NopCloser(bytes.NewReader(rw.Body.Bytes()))
+ }
+
+ if trailers, ok := rw.snapHeader["Trailer"]; ok {
+ res.Trailer = make(http.Header, len(trailers))
+ for _, k := range trailers {
+ // TODO: use http2.ValidTrailerHeader, but we can't
+ // get at it easily because it's bundled into net/http
+ // unexported. This is good enough for now:
+ switch k {
+ case "Transfer-Encoding", "Content-Length", "Trailer":
+ // Ignore since forbidden by RFC 2616 14.40.
+ continue
+ }
+ k = http.CanonicalHeaderKey(k)
+ vv, ok := rw.HeaderMap[k]
+ if !ok {
+ continue
+ }
+ vv2 := make([]string, len(vv))
+ copy(vv2, vv)
+ res.Trailer[k] = vv2
}
- vv2 := make([]string, len(vv))
- copy(vv2, vv)
- rw.trailerMap[k] = vv2
}
- return rw.trailerMap
+ return res
}
return nil
}
}
+ hasResultStatus := func(wantCode int) checkFunc {
+ return func(rec *ResponseRecorder) error {
+ if rec.Result().StatusCode != wantCode {
+ return fmt.Errorf("Result().StatusCode = %d; want %d", rec.Result().StatusCode, wantCode)
+ }
+ return nil
+ }
+ }
hasContents := func(want string) checkFunc {
return func(rec *ResponseRecorder) error {
if rec.Body.String() != want {
return nil
}
}
- hasHeader := func(key, want string) checkFunc {
+ hasOldHeader := func(key, want string) checkFunc {
return func(rec *ResponseRecorder) error {
if got := rec.HeaderMap.Get(key); got != want {
- return fmt.Errorf("header %s = %q; want %q", key, got, want)
+ return fmt.Errorf("HeaderMap header %s = %q; want %q", key, got, want)
+ }
+ return nil
+ }
+ }
+ hasHeader := func(key, want string) checkFunc {
+ return func(rec *ResponseRecorder) error {
+ if got := rec.Result().Header.Get(key); got != want {
+ return fmt.Errorf("final header %s = %q; want %q", key, got, want)
}
return nil
}
hasNotHeaders := func(keys ...string) checkFunc {
return func(rec *ResponseRecorder) error {
for _, k := range keys {
- _, ok := rec.HeaderMap[http.CanonicalHeaderKey(k)]
+ v, ok := rec.Result().Header[http.CanonicalHeaderKey(k)]
if ok {
- return fmt.Errorf("unexpected header %s", k)
+ return fmt.Errorf("unexpected header %s with value %q", k, v)
}
}
return nil
}
hasTrailer := func(key, want string) checkFunc {
return func(rec *ResponseRecorder) error {
- if got := rec.Trailers().Get(key); got != want {
+ if got := rec.Result().Trailer.Get(key); got != want {
return fmt.Errorf("trailer %s = %q; want %q", key, got, want)
}
return nil
}
hasNotTrailers := func(keys ...string) checkFunc {
return func(rec *ResponseRecorder) error {
- trailers := rec.Trailers()
+ trailers := rec.Result().Trailer
for _, k := range keys {
_, ok := trailers[http.CanonicalHeaderKey(k)]
if ok {
hasNotTrailers("Non-Trailer", "Trailer-B", "Trailer-NotDeclared"),
),
},
+ {
+ "Header set without any write", // Issue 15560
+ func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("X-Foo", "1")
+
+ // Simulate somebody using
+ // new(ResponseRecorder) instead of
+ // using the constructor which sets
+ // this to 200
+ w.(*ResponseRecorder).Code = 0
+ },
+ check(
+ hasOldHeader("X-Foo", "1"),
+ hasStatus(0),
+ hasHeader("X-Foo", "1"),
+ hasResultStatus(200),
+ ),
+ },
+ {
+ "HeaderMap vs FinalHeaders", // more for Issue 15560
+ func(w http.ResponseWriter, r *http.Request) {
+ h := w.Header()
+ h.Set("X-Foo", "1")
+ w.Write([]byte("hi"))
+ h.Set("X-Foo", "2")
+ h.Set("X-Bar", "2")
+ },
+ check(
+ hasOldHeader("X-Foo", "2"),
+ hasOldHeader("X-Bar", "2"),
+ hasHeader("X-Foo", "1"),
+ hasNotHeaders("X-Bar"),
+ ),
+ },
}
r, _ := http.NewRequest("GET", "http://foo.com/", nil)
for _, tt := range tests {
// connection reuse is disabled via Transport.DisableKeepAlives.
// PutIdleConn is called before the caller's Response.Body.Close
// call returns.
+ // For HTTP/2, this hook is not currently used.
PutIdleConn func(err error)
// GotFirstResponseByte is called when the first byte of the response
connectStart := func(b byte) func(network, addr string) {
return func(network, addr string) {
if addr != "addr" {
- t.Errorf(`%d. args for %Q case = %q, %q; want addr of "addr"`, testNum, b, network, addr)
+ t.Errorf(`%d. args for %q case = %q, %q; want addr of "addr"`, testNum, b, network, addr)
}
buf.WriteByte(b)
}
} else {
req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery
}
+ if _, ok := req.Header["User-Agent"]; !ok {
+ // explicitly disable User-Agent so it's not set to default value
+ req.Header.Set("User-Agent", "")
+ }
}
return &ReverseProxy{Director: director}
}
}
}
+// Issue 15524
+func TestUserAgentHeader(t *testing.T) {
+ const explicitUA = "explicit UA"
+ backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.URL.Path == "/noua" {
+ if c := r.Header.Get("User-Agent"); c != "" {
+ t.Errorf("handler got non-empty User-Agent header %q", c)
+ }
+ return
+ }
+ if c := r.Header.Get("User-Agent"); c != explicitUA {
+ t.Errorf("handler got unexpected User-Agent header %q", c)
+ }
+ }))
+ defer backend.Close()
+ backendURL, err := url.Parse(backend.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ proxyHandler := NewSingleHostReverseProxy(backendURL)
+ proxyHandler.ErrorLog = log.New(ioutil.Discard, "", 0) // quiet for tests
+ frontend := httptest.NewServer(proxyHandler)
+ defer frontend.Close()
+
+ getReq, _ := http.NewRequest("GET", frontend.URL, nil)
+ getReq.Header.Set("User-Agent", explicitUA)
+ getReq.Close = true
+ res, err := http.DefaultClient.Do(getReq)
+ if err != nil {
+ t.Fatalf("Get: %v", err)
+ }
+ res.Body.Close()
+
+ getReq, _ = http.NewRequest("GET", frontend.URL+"/noua", nil)
+ getReq.Header.Set("User-Agent", "")
+ getReq.Close = true
+ res, err = http.DefaultClient.Do(getReq)
+ if err != nil {
+ t.Fatalf("Get: %v", err)
+ }
+ res.Body.Close()
+}
+
type bufferPool struct {
get func() []byte
put func([]byte)
byter := bytes.NewReader(buf.Bytes())
bufr := bufio.NewReader(byter)
mallocs := testing.AllocsPerRun(100, func() {
- byter.Seek(0, 0)
+ byter.Seek(0, io.SeekStart)
bufr.Reset(byter)
r := NewChunkedReader(bufr)
n, err := io.ReadFull(r, readBuf)
// set, it is undefined whether Cancel is respected.
Cancel <-chan struct{}
+ // Response is the redirect response which caused this request
+ // to be created. This field is only populated during client
+ // redirects.
+ Response *Response
+
// ctx is either the client or server context. It should only
// be modified via copying the whole Request using WithContext.
// It is unexported to prevent people from using Context wrong
}
type maxBytesReader struct {
- w ResponseWriter
- r io.ReadCloser // underlying reader
- n int64 // max bytes remaining
- stopped bool
- sawEOF bool
+ w ResponseWriter
+ r io.ReadCloser // underlying reader
+ n int64 // max bytes remaining
+ err error // sticky error
}
func (l *maxBytesReader) tooLarge() (n int, err error) {
- if !l.stopped {
- l.stopped = true
-
- // The server code and client code both use
- // maxBytesReader. This "requestTooLarge" check is
- // only used by the server code. To prevent binaries
- // which only using the HTTP Client code (such as
- // cmd/go) from also linking in the HTTP server, don't
- // use a static type assertion to the server
- // "*response" type. Check this interface instead:
- type requestTooLarger interface {
- requestTooLarge()
- }
- if res, ok := l.w.(requestTooLarger); ok {
- res.requestTooLarge()
- }
- }
- return 0, errors.New("http: request body too large")
+ l.err = errors.New("http: request body too large")
+ return 0, l.err
}
func (l *maxBytesReader) Read(p []byte) (n int, err error) {
- toRead := l.n
- if l.n == 0 {
- if l.sawEOF {
- return l.tooLarge()
- }
- // The underlying io.Reader may not return (0, io.EOF)
- // at EOF if the requested size is 0, so read 1 byte
- // instead. The io.Reader docs are a bit ambiguous
- // about the return value of Read when 0 bytes are
- // requested, and {bytes,strings}.Reader gets it wrong
- // too (it returns (0, nil) even at EOF).
- toRead = 1
+ if l.err != nil {
+ return 0, l.err
+ }
+ if len(p) == 0 {
+ return 0, nil
}
- if int64(len(p)) > toRead {
- p = p[:toRead]
+ // If they asked for a 32KB byte read but only 5 bytes are
+ // remaining, no need to read 32KB. 6 bytes will answer the
+ // question of the whether we hit the limit or go past it.
+ if int64(len(p)) > l.n+1 {
+ p = p[:l.n+1]
}
n, err = l.r.Read(p)
- if err == io.EOF {
- l.sawEOF = true
- }
- if l.n == 0 {
- // If we had zero bytes to read remaining (but hadn't seen EOF)
- // and we get a byte here, that means we went over our limit.
- if n > 0 {
- return l.tooLarge()
- }
- return 0, err
+
+ if int64(n) <= l.n {
+ l.n -= int64(n)
+ l.err = err
+ return n, err
+ }
+
+ n = int(l.n)
+ l.n = 0
+
+ // The server code and client code both use
+ // maxBytesReader. This "requestTooLarge" check is
+ // only used by the server code. To prevent binaries
+ // which only using the HTTP Client code (such as
+ // cmd/go) from also linking in the HTTP server, don't
+ // use a static type assertion to the server
+ // "*response" type. Check this interface instead:
+ type requestTooLarger interface {
+ requestTooLarge()
}
- l.n -= int64(n)
- if l.n < 0 {
- l.n = 0
+ if res, ok := l.w.(requestTooLarger); ok {
+ res.requestTooLarge()
}
- return
+ l.err = errors.New("http: request body too large")
+ return n, l.err
}
func (l *maxBytesReader) Close() error {
}
}
+// Issue 14981: MaxBytesReader's return error wasn't sticky. It
+// doesn't technically need to be, but people expected it to be.
+func TestMaxBytesReaderStickyError(t *testing.T) {
+ isSticky := func(r io.Reader) error {
+ var log bytes.Buffer
+ buf := make([]byte, 1000)
+ var firstErr error
+ for {
+ n, err := r.Read(buf)
+ fmt.Fprintf(&log, "Read(%d) = %d, %v\n", len(buf), n, err)
+ if err == nil {
+ continue
+ }
+ if firstErr == nil {
+ firstErr = err
+ continue
+ }
+ if !reflect.DeepEqual(err, firstErr) {
+ return fmt.Errorf("non-sticky error. got log:\n%s", log.Bytes())
+ }
+ t.Logf("Got log: %s", log.Bytes())
+ return nil
+ }
+ }
+ tests := [...]struct {
+ readable int
+ limit int64
+ }{
+ 0: {99, 100},
+ 1: {100, 100},
+ 2: {101, 100},
+ }
+ for i, tt := range tests {
+ rc := MaxBytesReader(nil, ioutil.NopCloser(bytes.NewReader(make([]byte, tt.readable))), tt.limit)
+ if err := isSticky(rc); err != nil {
+ t.Errorf("%d. error: %v", i, err)
+ }
+ }
+}
+
func testMissingFile(t *testing.T, req *Request) {
f, fh, err := req.FormFile("missing")
if f != nil {
// any trailer values sent by the server.
Trailer Header
- // The Request that was sent to obtain this Response.
+ // Request is the request that was sent to obtain this Response.
// Request's Body is nil (having already been consumed).
// This is only populated for Client requests.
Request *Request
"bytes"
"context"
"crypto/tls"
+ "encoding/json"
"errors"
"fmt"
"internal/testenv"
}
}
+func testTCPConnectionStaysOpen(t *testing.T, req string, handler Handler) {
+ defer afterTest(t)
+ ts := httptest.NewServer(handler)
+ defer ts.Close()
+ conn, err := net.Dial("tcp", ts.Listener.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer conn.Close()
+ br := bufio.NewReader(conn)
+ for i := 0; i < 2; i++ {
+ if _, err := io.WriteString(conn, req); err != nil {
+ t.Fatal(err)
+ }
+ res, err := ReadResponse(br, nil)
+ if err != nil {
+ t.Fatalf("res %d: %v", i+1, err)
+ }
+ if _, err := io.Copy(ioutil.Discard, res.Body); err != nil {
+ t.Fatalf("res %d body copy: %v", i+1, err)
+ }
+ res.Body.Close()
+ }
+}
+
// TestServeHTTP10Close verifies that HTTP/1.0 requests won't be kept alive.
func TestServeHTTP10Close(t *testing.T) {
testTCPConnectionCloses(t, "GET / HTTP/1.0\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
}))
}
+func send204(w ResponseWriter, r *Request) { w.WriteHeader(204) }
+func send304(w ResponseWriter, r *Request) { w.WriteHeader(304) }
+
+// Issue 15647: 204 responses can't have bodies, so HTTP/1.0 keep-alive conns should stay open.
+func TestHTTP10KeepAlive204Response(t *testing.T) {
+ testTCPConnectionStaysOpen(t, "GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n", HandlerFunc(send204))
+}
+
+func TestHTTP11KeepAlive204Response(t *testing.T) {
+ testTCPConnectionStaysOpen(t, "GET / HTTP/1.1\r\nHost: foo\r\n\r\n", HandlerFunc(send204))
+}
+
+func TestHTTP10KeepAlive304Response(t *testing.T) {
+ testTCPConnectionStaysOpen(t,
+ "GET / HTTP/1.0\r\nConnection: keep-alive\r\nIf-Modified-Since: Mon, 02 Jan 2006 15:04:05 GMT\r\n\r\n",
+ HandlerFunc(send304))
+}
+
+// Issue 15703
+func TestKeepAliveFinalChunkWithEOF(t *testing.T) {
+ defer afterTest(t)
+ cst := newClientServerTest(t, false /* h1 */, HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.(Flusher).Flush() // force chunked encoding
+ w.Write([]byte("{\"Addr\": \"" + r.RemoteAddr + "\"}"))
+ }))
+ defer cst.close()
+ type data struct {
+ Addr string
+ }
+ var addrs [2]data
+ for i := range addrs {
+ res, err := cst.c.Get(cst.ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := json.NewDecoder(res.Body).Decode(&addrs[i]); err != nil {
+ t.Fatal(err)
+ }
+ if addrs[i].Addr == "" {
+ t.Fatal("no address")
+ }
+ res.Body.Close()
+ }
+ if addrs[0] != addrs[1] {
+ t.Fatalf("connection not reused")
+ }
+}
+
func TestSetsRemoteAddr_h1(t *testing.T) { testSetsRemoteAddr(t, h1Mode) }
func TestSetsRemoteAddr_h2(t *testing.T) { testSetsRemoteAddr(t, h2Mode) }
}
}
-func TestServerRequestContextCancel_ServeHTTPDone(t *testing.T) {
+func TestServerRequestContextCancel_ServeHTTPDone_h1(t *testing.T) {
+ testServerRequestContextCancel_ServeHTTPDone(t, h1Mode)
+}
+func TestServerRequestContextCancel_ServeHTTPDone_h2(t *testing.T) {
+ testServerRequestContextCancel_ServeHTTPDone(t, h2Mode)
+}
+func testServerRequestContextCancel_ServeHTTPDone(t *testing.T, h2 bool) {
defer afterTest(t)
ctxc := make(chan context.Context, 1)
- ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
ctx := r.Context()
select {
case <-ctx.Done():
}
ctxc <- ctx
}))
- defer ts.Close()
- res, err := Get(ts.URL)
+ defer cst.close()
+ res, err := cst.c.Get(cst.ts.URL)
if err != nil {
t.Fatal(err)
}
}
}
-func TestServerContext_ServerContextKey(t *testing.T) {
+func TestServerContext_ServerContextKey_h1(t *testing.T) {
+ testServerContext_ServerContextKey(t, h1Mode)
+}
+func TestServerContext_ServerContextKey_h2(t *testing.T) {
+ testServerContext_ServerContextKey(t, h2Mode)
+}
+func testServerContext_ServerContextKey(t *testing.T, h2 bool) {
defer afterTest(t)
- ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
ctx := r.Context()
got := ctx.Value(ServerContextKey)
if _, ok := got.(*Server); !ok {
}
got = ctx.Value(LocalAddrContextKey)
- if _, ok := got.(net.Addr); !ok {
+ if addr, ok := got.(net.Addr); !ok {
t.Errorf("local addr value = %T; want net.Addr", got)
+ } else if fmt.Sprint(addr) != r.Host {
+ t.Errorf("local addr = %v; want %v", addr, r.Host)
}
}))
- defer ts.Close()
- res, err := Get(ts.URL)
+ defer cst.close()
+ res, err := cst.c.Get(cst.ts.URL)
if err != nil {
t.Fatal(err)
}
// Wait for the server process to respond.
url := "http://localhost:" + port + "/"
for i := 0; i < 100; i++ {
- time.Sleep(50 * time.Millisecond)
+ time.Sleep(100 * time.Millisecond)
if _, err := getNoBody(url); err == nil {
break
}
"sync"
"sync/atomic"
"time"
+
+ "golang.org/x/net/lex/httplex"
)
// Errors used by the HTTP server.
Header() Header
// Write writes the data to the connection as part of an HTTP reply.
- // If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK)
- // before writing the data. If the Header does not contain a
- // Content-Type line, Write adds a Content-Type set to the result of passing
- // the initial 512 bytes of written data to DetectContentType.
+ //
+ // If WriteHeader has not yet been called, Write calls
+ // WriteHeader(http.StatusOK) before writing the data. If the Header
+ // does not contain a Content-Type line, Write adds a Content-Type set
+ // to the result of passing the initial 512 bytes of written data to
+ // DetectContentType.
+ //
+ // Depending on the HTTP protocol version and the client, calling
+ // Write or WriteHeader may prevent future reads on the
+ // Request.Body. For HTTP/1.x requests, handlers should read any
+ // needed request body data before writing the response. Once the
+ // headers have been flushed (due to either an explicit Flusher.Flush
+ // call or writing enough data to trigger a flush), the request body
+ // may be unavailable. For HTTP/2 requests, the Go HTTP server permits
+ // handlers to continue to read the request body while concurrently
+ // writing the response. However, such behavior may not be supported
+ // by all HTTP/2 clients. Handlers should read before writing if
+ // possible to maximize compatibility.
Write([]byte) (int, error)
// WriteHeader sends an HTTP response header with status code.
if len(hosts) > 1 {
return nil, badRequestError("too many Host headers")
}
- if len(hosts) == 1 && !validHostHeader(hosts[0]) {
+ if len(hosts) == 1 && !httplex.ValidHostHeader(hosts[0]) {
return nil, badRequestError("malformed Host header")
}
for k, vv := range req.Header {
- if !validHeaderName(k) {
+ if !httplex.ValidHeaderFieldName(k) {
return nil, badRequestError("invalid header name")
}
for _, v := range vv {
- if !validHeaderValue(v) {
+ if !httplex.ValidHeaderFieldValue(v) {
return nil, badRequestError("invalid header value")
}
}
// Check for a explicit (and valid) Content-Length header.
hasCL := w.contentLength != -1
- if w.wants10KeepAlive && (isHEAD || hasCL) {
+ if w.wants10KeepAlive && (isHEAD || hasCL || !bodyAllowedForStatus(w.status)) {
_, connectionHeaderSet := header["Connection"]
if !connectionHeaderSet {
setHeader.connection = "keep-alive"
// replying, if the handler hasn't already done so. But we
// don't want to do an unbounded amount of reading here for
// DoS reasons, so we only try up to a threshold.
+ // TODO(bradfitz): where does RFC 2616 say that? See Issue 15527
+ // about HTTP/1.x Handlers concurrently reading and writing, like
+ // HTTP/2 handlers can do. Maybe this code should be relaxed?
if w.req.ContentLength != 0 && !w.closeAfterReply {
var discard, tooBig bool
MaxHeaderBytes int
// TLSNextProto optionally specifies a function to take over
- // ownership of the provided TLS connection when an NPN
+ // ownership of the provided TLS connection when an NPN/ALPN
// protocol upgrade has occurred. The map key is the protocol
// name negotiated. The Handler argument should be used to
// handle HTTP requests and will initialize the Request's TLS
package http
-// HTTP status codes, defined in RFC 2616.
+// HTTP status codes as registered with IANA.
+// See: http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
const (
- StatusContinue = 100
- StatusSwitchingProtocols = 101
+ StatusContinue = 100 // RFC 7231, 6.2.1
+ StatusSwitchingProtocols = 101 // RFC 7231, 6.2.2
+ StatusProcessing = 102 // RFC 2518, 10.1
- StatusOK = 200
- StatusCreated = 201
- StatusAccepted = 202
- StatusNonAuthoritativeInfo = 203
- StatusNoContent = 204
- StatusResetContent = 205
- StatusPartialContent = 206
+ StatusOK = 200 // RFC 7231, 6.3.1
+ StatusCreated = 201 // RFC 7231, 6.3.2
+ StatusAccepted = 202 // RFC 7231, 6.3.3
+ StatusNonAuthoritativeInfo = 203 // RFC 7231, 6.3.4
+ StatusNoContent = 204 // RFC 7231, 6.3.5
+ StatusResetContent = 205 // RFC 7231, 6.3.6
+ StatusPartialContent = 206 // RFC 7233, 4.1
+ StatusMultiStatus = 207 // RFC 4918, 11.1
+ StatusAlreadyReported = 208 // RFC 5842, 7.1
+ StatusIMUsed = 226 // RFC 3229, 10.4.1
- StatusMultipleChoices = 300
- StatusMovedPermanently = 301
- StatusFound = 302
- StatusSeeOther = 303
- StatusNotModified = 304
- StatusUseProxy = 305
- StatusTemporaryRedirect = 307
+ StatusMultipleChoices = 300 // RFC 7231, 6.4.1
+ StatusMovedPermanently = 301 // RFC 7231, 6.4.2
+ StatusFound = 302 // RFC 7231, 6.4.3
+ StatusSeeOther = 303 // RFC 7231, 6.4.4
+ StatusNotModified = 304 // RFC 7232, 4.1
+ StatusUseProxy = 305 // RFC 7231, 6.4.5
+ _ = 306 // RFC 7231, 6.4.6 (Unused)
+ StatusTemporaryRedirect = 307 // RFC 7231, 6.4.7
+ StatusPermanentRedirect = 308 // RFC 7538, 3
- StatusBadRequest = 400
- StatusUnauthorized = 401
- StatusPaymentRequired = 402
- StatusForbidden = 403
- StatusNotFound = 404
- StatusMethodNotAllowed = 405
- StatusNotAcceptable = 406
- StatusProxyAuthRequired = 407
- StatusRequestTimeout = 408
- StatusConflict = 409
- StatusGone = 410
- StatusLengthRequired = 411
- StatusPreconditionFailed = 412
- StatusRequestEntityTooLarge = 413
- StatusRequestURITooLong = 414
- StatusUnsupportedMediaType = 415
- StatusRequestedRangeNotSatisfiable = 416
- StatusExpectationFailed = 417
- StatusTeapot = 418
- StatusPreconditionRequired = 428
- StatusTooManyRequests = 429
- StatusRequestHeaderFieldsTooLarge = 431
- StatusUnavailableForLegalReasons = 451
+ StatusBadRequest = 400 // RFC 7231, 6.5.1
+ StatusUnauthorized = 401 // RFC 7235, 3.1
+ StatusPaymentRequired = 402 // RFC 7231, 6.5.2
+ StatusForbidden = 403 // RFC 7231, 6.5.3
+ StatusNotFound = 404 // RFC 7231, 6.5.4
+ StatusMethodNotAllowed = 405 // RFC 7231, 6.5.5
+ StatusNotAcceptable = 406 // RFC 7231, 6.5.6
+ StatusProxyAuthRequired = 407 // RFC 7235, 3.2
+ StatusRequestTimeout = 408 // RFC 7231, 6.5.7
+ StatusConflict = 409 // RFC 7231, 6.5.8
+ StatusGone = 410 // RFC 7231, 6.5.9
+ StatusLengthRequired = 411 // RFC 7231, 6.5.10
+ StatusPreconditionFailed = 412 // RFC 7232, 4.2
+ StatusRequestEntityTooLarge = 413 // RFC 7231, 6.5.11
+ StatusRequestURITooLong = 414 // RFC 7231, 6.5.12
+ StatusUnsupportedMediaType = 415 // RFC 7231, 6.5.13
+ StatusRequestedRangeNotSatisfiable = 416 // RFC 7233, 4.4
+ StatusExpectationFailed = 417 // RFC 7231, 6.5.14
+ StatusTeapot = 418 // RFC 7168, 2.3.3
+ StatusUnprocessableEntity = 422 // RFC 4918, 11.2
+ StatusLocked = 423 // RFC 4918, 11.3
+ StatusFailedDependency = 424 // RFC 4918, 11.4
+ StatusUpgradeRequired = 426 // RFC 7231, 6.5.15
+ StatusPreconditionRequired = 428 // RFC 6585, 3
+ StatusTooManyRequests = 429 // RFC 6585, 4
+ StatusRequestHeaderFieldsTooLarge = 431 // RFC 6585, 5
+ StatusUnavailableForLegalReasons = 451 // RFC 7725, 3
- StatusInternalServerError = 500
- StatusNotImplemented = 501
- StatusBadGateway = 502
- StatusServiceUnavailable = 503
- StatusGatewayTimeout = 504
- StatusHTTPVersionNotSupported = 505
- StatusNetworkAuthenticationRequired = 511
+ StatusInternalServerError = 500 // RFC 7231, 6.6.1
+ StatusNotImplemented = 501 // RFC 7231, 6.6.2
+ StatusBadGateway = 502 // RFC 7231, 6.6.3
+ StatusServiceUnavailable = 503 // RFC 7231, 6.6.4
+ StatusGatewayTimeout = 504 // RFC 7231, 6.6.5
+ StatusHTTPVersionNotSupported = 505 // RFC 7231, 6.6.6
+ StatusVariantAlsoNegotiates = 506 // RFC 2295, 8.1
+ StatusInsufficientStorage = 507 // RFC 4918, 11.5
+ StatusLoopDetected = 508 // RFC 5842, 7.2
+ StatusNotExtended = 510 // RFC 2774, 7
+ StatusNetworkAuthenticationRequired = 511 // RFC 6585, 6
)
var statusText = map[int]string{
StatusContinue: "Continue",
StatusSwitchingProtocols: "Switching Protocols",
+ StatusProcessing: "Processing",
StatusOK: "OK",
StatusCreated: "Created",
StatusNoContent: "No Content",
StatusResetContent: "Reset Content",
StatusPartialContent: "Partial Content",
+ StatusMultiStatus: "Multi-Status",
+ StatusAlreadyReported: "Already Reported",
+ StatusIMUsed: "IM Used",
StatusMultipleChoices: "Multiple Choices",
StatusMovedPermanently: "Moved Permanently",
StatusNotModified: "Not Modified",
StatusUseProxy: "Use Proxy",
StatusTemporaryRedirect: "Temporary Redirect",
+ StatusPermanentRedirect: "Permanent Redirect",
StatusBadRequest: "Bad Request",
StatusUnauthorized: "Unauthorized",
StatusRequestedRangeNotSatisfiable: "Requested Range Not Satisfiable",
StatusExpectationFailed: "Expectation Failed",
StatusTeapot: "I'm a teapot",
+ StatusUnprocessableEntity: "Unprocessable Entity",
+ StatusLocked: "Locked",
+ StatusFailedDependency: "Failed Dependency",
+ StatusUpgradeRequired: "Upgrade Required",
StatusPreconditionRequired: "Precondition Required",
StatusTooManyRequests: "Too Many Requests",
StatusRequestHeaderFieldsTooLarge: "Request Header Fields Too Large",
StatusServiceUnavailable: "Service Unavailable",
StatusGatewayTimeout: "Gateway Timeout",
StatusHTTPVersionNotSupported: "HTTP Version Not Supported",
+ StatusVariantAlsoNegotiates: "Variant Also Negotiates",
+ StatusInsufficientStorage: "Insufficient Storage",
+ StatusLoopDetected: "Loop Detected",
+ StatusNotExtended: "Not Extended",
StatusNetworkAuthenticationRequired: "Network Authentication Required",
}
"strconv"
"strings"
"sync"
+
+ "golang.org/x/net/lex/httplex"
)
// ErrLineTooLong is returned when reading request or response bodies
}
conv := header["Connection"]
- hasClose := headerValuesContainsToken(conv, "close")
+ hasClose := httplex.HeaderValuesContainsToken(conv, "close")
if major == 1 && minor == 0 {
- return hasClose || !headerValuesContainsToken(conv, "keep-alive")
+ return hasClose || !httplex.HeaderValuesContainsToken(conv, "keep-alive")
}
if hasClose && removeCloseHeader {
"strings"
"sync"
"time"
+
+ "golang.org/x/net/lex/httplex"
)
// DefaultTransport is the default implementation of Transport and is
// $no_proxy) environment variables.
var DefaultTransport RoundTripper = &Transport{
Proxy: ProxyFromEnvironment,
- Dialer: &net.Dialer{
+ DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
- },
+ }).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
// If Proxy is nil or returns a nil *URL, no proxy is used.
Proxy func(*Request) (*url.URL, error)
- // Dial specifies the dial function for creating unencrypted
- // TCP connections. If Dial and Dialer are both nil, net.Dial
- // is used.
+ // DialContext specifies the dial function for creating unencrypted TCP connections.
+ // If DialContext is nil (and the deprecated Dial below is also nil),
+ // then the transport dials using package net.
+ DialContext func(ctx context.Context, network, addr string) (net.Conn, error)
+
+ // Dial specifies the dial function for creating unencrypted TCP connections.
//
- // Deprecated: Use Dialer instead. If both are specified, Dialer
- // takes precedence.
+ // Deprecated: Use DialContext instead, which allows the transport
+ // to cancel dials as soon as they are no longer needed.
+ // If both are set, DialContext takes priority.
Dial func(network, addr string) (net.Conn, error)
- // Dialer optionally specifies a dialer configuration to use
- // for new connections.
- Dialer *net.Dialer
-
// DialTLS specifies an optional dial function for creating
// TLS connections for non-proxied HTTPS requests.
//
// Transport.
return
}
- if t.TLSClientConfig != nil {
- // Be conservative for now (for Go 1.6) at least and
- // don't automatically enable http2 if they've
- // specified a custom TLS config. Let them opt-in
- // themselves via http2.ConfigureTransport so we don't
- // surprise them by modifying their tls.Config.
- // Issue 14275.
- return
- }
- if t.ExpectContinueTimeout != 0 && t != DefaultTransport {
- // ExpectContinueTimeout is unsupported in http2, so
- // if they explicitly asked for it (as opposed to just
- // using the DefaultTransport, which sets it), then
- // disable http2 for now.
- //
- // Issue 13851. (and changed in Issue 14391)
+ if t.TLSClientConfig != nil || t.Dial != nil || t.DialTLS != nil {
+ // Be conservative and don't automatically enable
+ // http2 if they've specified a custom TLS config or
+ // custom dialers. Let them opt-in themselves via
+ // http2.ConfigureTransport so we don't surprise them
+ // by modifying their tls.Config. Issue 14275.
return
}
t2, err := http2configureTransport(t)
isHTTP := scheme == "http" || scheme == "https"
if isHTTP {
for k, vv := range req.Header {
- if !validHeaderName(k) {
+ if !httplex.ValidHeaderFieldName(k) {
return nil, fmt.Errorf("net/http: invalid header field name %q", k)
}
for _, v := range vv {
- if !validHeaderValue(v) {
+ if !httplex.ValidHeaderFieldValue(v) {
return nil, fmt.Errorf("net/http: invalid header field value %q for key %v", v, k)
}
}
if err == nil {
return resp, nil
}
- if err := checkTransportResend(err, req, pconn); err != nil {
+ if !pconn.shouldRetryRequest(req, err) {
return nil, err
}
testHookRoundTripRetried()
}
}
-// checkTransportResend checks whether a failed HTTP request can be
-// resent on a new connection. The non-nil input error is the error from
-// roundTrip, which might be wrapped in a beforeRespHeaderError error.
-//
-// The return value is either nil to retry the request, the provided
-// err unmodified, or the unwrapped error inside a
-// beforeRespHeaderError.
-func checkTransportResend(err error, req *Request, pconn *persistConn) error {
- brhErr, ok := err.(beforeRespHeaderError)
- if !ok {
- return err
+// shouldRetryRequest reports whether we should retry sending a failed
+// HTTP request on a new connection. The non-nil input error is the
+// error from roundTrip.
+func (pc *persistConn) shouldRetryRequest(req *Request, err error) bool {
+ if err == errMissingHost {
+ // User error.
+ return false
}
- err = brhErr.error // unwrap the custom error in case we return it
- if err != errMissingHost && pconn.isReused() && req.isReplayable() {
- // If we try to reuse a connection that the server is in the process of
- // closing, we may end up successfully writing out our request (or a
- // portion of our request) only to find a connection error when we try to
- // read from (or finish writing to) the socket.
-
- // There can be a race between the socket pool checking whether a socket
- // is still connected, receiving the FIN, and sending/reading data on a
- // reused socket. If we receive the FIN between the connectedness check
- // and writing/reading from the socket, we may first learn the socket is
- // disconnected when we get a ERR_SOCKET_NOT_CONNECTED. This will most
- // likely happen when trying to retrieve its IP address. See
- // http://crbug.com/105824 for more details.
-
- // We resend a request only if we reused a keep-alive connection and did
- // not yet receive any header data. This automatically prevents an
- // infinite resend loop because we'll run out of the cached keep-alive
- // connections eventually.
- return nil
+ if !pc.isReused() {
+ // This was a fresh connection. There's no reason the server
+ // should've hung up on us.
+ //
+ // Also, if we retried now, we could loop forever
+ // creating new connections and retrying if the server
+ // is just hanging up on us because it doesn't like
+ // our request (as opposed to sending an error).
+ return false
}
- return err
+ if !req.isReplayable() {
+ // Don't retry non-idempotent requests.
+
+ // TODO: swap the nothingWrittenError and isReplayable checks,
+ // putting the "if nothingWrittenError => return true" case
+ // first, per golang.org/issue/15723
+ return false
+ }
+ if _, ok := err.(nothingWrittenError); ok {
+ // We never wrote anything, so it's safe to retry.
+ return true
+ }
+ if err == errServerClosedIdle || err == errServerClosedConn {
+ return true
+ }
+ return false // conservatively
}
// ErrSkipAltProtocol is a sentinel error value defined by Transport.RegisterProtocol.
errTooManyIdleHost = errors.New("http: putIdleConn: too many idle connections for host")
errCloseIdleConns = errors.New("http: CloseIdleConnections called")
errReadLoopExiting = errors.New("http: persistConn.readLoop exiting")
- errServerClosedIdle = errors.New("http: server closed idle conn")
+ errServerClosedIdle = errors.New("http: server closed idle connection")
+ errServerClosedConn = errors.New("http: server closed connection")
errIdleConnTimeout = errors.New("http: idle connection timeout")
)
var zeroDialer net.Dialer
func (t *Transport) dial(ctx context.Context, network, addr string) (net.Conn, error) {
- if t.Dialer != nil {
- return t.Dialer.DialContext(ctx, network, addr)
+ if t.DialContext != nil {
+ return t.DialContext(ctx, network, addr)
}
if t.Dial != nil {
c, err := t.Dial(network, addr)
select {
case v := <-dialc:
// Our dial finished.
- if trace != nil && trace.GotConn != nil && v.pc != nil {
+ if trace != nil && trace.GotConn != nil && v.pc != nil && v.pc.alt == nil {
trace.GotConn(httptrace.GotConnInfo{Conn: v.pc.conn})
}
return v.pc, v.err
func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (*persistConn, error) {
pconn := &persistConn{
- t: t,
- cacheKey: cm.key(),
- reqch: make(chan requestAndChan, 1),
- writech: make(chan writeRequest, 1),
- closech: make(chan struct{}),
- writeErrCh: make(chan error, 1),
+ t: t,
+ cacheKey: cm.key(),
+ reqch: make(chan requestAndChan, 1),
+ writech: make(chan writeRequest, 1),
+ closech: make(chan struct{}),
+ writeErrCh: make(chan error, 1),
+ writeLoopDone: make(chan struct{}),
}
tlsDial := t.DialTLS != nil && cm.targetScheme == "https" && cm.proxyURL == nil
if tlsDial {
}
pconn.br = bufio.NewReader(pconn)
- pconn.bw = bufio.NewWriter(pconn.conn)
+ pconn.bw = bufio.NewWriter(persistConnWriter{pconn})
go pconn.readLoop()
go pconn.writeLoop()
return pconn, nil
}
+// persistConnWriter is the io.Writer written to by pc.bw.
+// It accumulates the number of bytes written to the underlying conn,
+// so the retry logic can determine whether any bytes made it across
+// the wire.
+// This is exactly 1 pointer field wide so it can go into an interface
+// without allocation.
+type persistConnWriter struct {
+ pc *persistConn
+}
+
+func (w persistConnWriter) Write(p []byte) (n int, err error) {
+ n, err = w.pc.conn.Write(p)
+ w.pc.nwrite += int64(n)
+ return
+}
+
// useProxy reports whether requests to addr should use a proxy,
// according to the NO_PROXY or no_proxy environment variable.
// addr is always a canonicalAddr with a host and port.
tlsState *tls.ConnectionState
br *bufio.Reader // from conn
bw *bufio.Writer // to conn
+ nwrite int64 // bytes written
reqch chan requestAndChan // written by roundTrip; read by readLoop
writech chan writeRequest // written by roundTrip; read by writeLoop
closech chan struct{} // closed when conn closed
// whether or not a connection can be reused. Issue 7569.
writeErrCh chan error
+ writeLoopDone chan struct{} // closed when write loop ends
+
// Both guarded by Transport.idleMu:
idleAt time.Time // time it last become idle
idleTimer *time.Timer // holding an AfterFunc to close it
// isBroken reports whether this connection is in a known broken state.
func (pc *persistConn) isBroken() bool {
pc.mu.Lock()
- b := pc.broken
+ b := pc.closed != nil
pc.mu.Unlock()
return b
}
t.Reused = pc.reused
t.Conn = pc.conn
t.WasIdle = true
- t.IdleTime = time.Since(idleAt)
+ if !idleAt.IsZero() {
+ t.IdleTime = time.Since(idleAt)
+ }
return
}
pc.close(errIdleConnTimeout)
}
+// mapRoundTripErrorFromReadLoop maps the provided readLoop error into
+// the error value that should be returned from persistConn.roundTrip.
+//
+// The startBytesWritten value should be the value of pc.nwrite before the roundTrip
+// started writing the request.
+func (pc *persistConn) mapRoundTripErrorFromReadLoop(startBytesWritten int64, err error) (out error) {
+ if err == nil {
+ return nil
+ }
+ if pc.isCanceled() {
+ return errRequestCanceled
+ }
+ if err == errServerClosedIdle || err == errServerClosedConn {
+ return err
+ }
+ if pc.isBroken() {
+ <-pc.writeLoopDone
+ if pc.nwrite == startBytesWritten {
+ return nothingWrittenError{err}
+ }
+ }
+ return err
+}
+
+// mapRoundTripErrorAfterClosed returns the error value to be propagated
+// up to Transport.RoundTrip method when persistConn.roundTrip sees
+// its pc.closech channel close, indicating the persistConn is dead.
+// (after closech is closed, pc.closed is valid).
+func (pc *persistConn) mapRoundTripErrorAfterClosed(startBytesWritten int64) error {
+ if pc.isCanceled() {
+ return errRequestCanceled
+ }
+ err := pc.closed
+ if err == errServerClosedIdle || err == errServerClosedConn {
+ // Don't decorate
+ return err
+ }
+
+ // Wait for the writeLoop goroutine to terminated, and then
+ // see if we actually managed to write anything. If not, we
+ // can retry the request.
+ <-pc.writeLoopDone
+ if pc.nwrite == startBytesWritten {
+ return nothingWrittenError{err}
+ }
+
+ return fmt.Errorf("net/http: HTTP/1.x transport connection broken: %v", err)
+
+}
+
func (pc *persistConn) readLoop() {
closeErr := errReadLoopExiting // default value, if not changed below
defer func() {
for alive {
pc.readLimit = pc.maxHeaderResponseSize()
_, err := pc.br.Peek(1)
- if err != nil {
- err = beforeRespHeaderError{err}
- }
pc.mu.Lock()
if pc.numExpectedResponses == 0 {
var resp *Response
if err == nil {
resp, err = pc.readResponse(rc, trace)
+ } else {
+ err = errServerClosedConn
+ closeErr = err
}
if err != nil {
if pc.readLimit <= 0 {
err = fmt.Errorf("net/http: server response headers exceeded %d bytes; aborted", pc.maxHeaderResponseSize())
}
+
// If we won't be able to retry this request later (from the
// roundTrip goroutine), mark it as done now.
// BEFORE the send on rc.ch, as the client might re-use the
// t.setReqCanceler from this persistConn while the Transport
// potentially spins up a different persistConn for the
// caller's subsequent request.
- if checkTransportResend(err, rc.req, pc) != nil {
+ if !pc.shouldRetryRequest(rc.req, err) {
pc.t.setReqCanceler(rc.req, nil)
}
select {
}
}
+// nothingWrittenError wraps a write errors which ended up writing zero bytes.
+type nothingWrittenError struct {
+ error
+}
+
func (pc *persistConn) writeLoop() {
+ defer close(pc.writeLoopDone)
for {
select {
case wr := <-pc.writech:
- if pc.isBroken() {
- wr.ch <- errors.New("http: can't write HTTP request on broken connection")
- continue
- }
+ startBytesWritten := pc.nwrite
err := wr.req.Request.write(pc.bw, pc.isProxy, wr.req.extra, pc.waitForContinue(wr.continueCh))
if err == nil {
err = pc.bw.Flush()
}
if err != nil {
- pc.markBroken()
wr.req.Request.closeBody()
+ if pc.nwrite == startBytesWritten {
+ err = nothingWrittenError{err}
+ }
}
pc.writeErrCh <- err // to the body reader, which might recycle us
wr.ch <- err // to the roundTrip function
+ if err != nil {
+ pc.close(err)
+ return
+ }
case <-pc.closech:
return
}
testHookReadLoopBeforeNextRead = nop
)
-// beforeRespHeaderError is used to indicate when an IO error has occurred before
-// any header data was received.
-type beforeRespHeaderError struct {
- error
-}
-
func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err error) {
testHookEnterRoundTrip()
if !pc.t.replaceReqCanceler(req.Request, pc.cancelRequest) {
// Write the request concurrently with waiting for a response,
// in case the server decides to reply before reading our full
// request body.
+ startBytesWritten := pc.nwrite
writeErrCh := make(chan error, 1)
pc.writech <- writeRequest{req, writeErrCh, continueCh}
if pc.isCanceled() {
err = errRequestCanceled
}
- re = responseAndError{err: beforeRespHeaderError{err}}
+ re = responseAndError{err: err}
pc.close(fmt.Errorf("write error: %v", err))
break WaitResponse
}
respHeaderTimer = timer.C
}
case <-pc.closech:
- var err error
- if pc.isCanceled() {
- err = errRequestCanceled
- } else {
- err = beforeRespHeaderError{fmt.Errorf("net/http: HTTP/1 transport connection broken: %v", pc.closed)}
- }
- re = responseAndError{err: err}
+ re = responseAndError{err: pc.mapRoundTripErrorAfterClosed(startBytesWritten)}
break WaitResponse
case <-respHeaderTimer:
pc.close(errTimeout)
re = responseAndError{err: errTimeout}
break WaitResponse
case re = <-resc:
- if re.err != nil && pc.isCanceled() {
- re.err = errRequestCanceled
- }
+ re.err = pc.mapRoundTripErrorFromReadLoop(startBytesWritten, re.err)
break WaitResponse
case <-cancelChan:
pc.t.CancelRequest(req.Request)
return re.res, re.err
}
-// markBroken marks a connection as broken (so it's not reused).
-// It differs from close in that it doesn't close the underlying
-// connection for use when it's still being read.
-func (pc *persistConn) markBroken() {
- pc.mu.Lock()
- defer pc.mu.Unlock()
- pc.broken = true
-}
-
// markReused marks this connection as having been successfully used for a
// request and response.
func (pc *persistConn) markReused() {
return &tls.Config{}
}
return &tls.Config{
- Rand: cfg.Rand,
- Time: cfg.Time,
- Certificates: cfg.Certificates,
- NameToCertificate: cfg.NameToCertificate,
- GetCertificate: cfg.GetCertificate,
- RootCAs: cfg.RootCAs,
- NextProtos: cfg.NextProtos,
- ServerName: cfg.ServerName,
- ClientAuth: cfg.ClientAuth,
- ClientCAs: cfg.ClientCAs,
- InsecureSkipVerify: cfg.InsecureSkipVerify,
- CipherSuites: cfg.CipherSuites,
- PreferServerCipherSuites: cfg.PreferServerCipherSuites,
- SessionTicketsDisabled: cfg.SessionTicketsDisabled,
- SessionTicketKey: cfg.SessionTicketKey,
- ClientSessionCache: cfg.ClientSessionCache,
- MinVersion: cfg.MinVersion,
- MaxVersion: cfg.MaxVersion,
- CurvePreferences: cfg.CurvePreferences,
+ Rand: cfg.Rand,
+ Time: cfg.Time,
+ Certificates: cfg.Certificates,
+ NameToCertificate: cfg.NameToCertificate,
+ GetCertificate: cfg.GetCertificate,
+ RootCAs: cfg.RootCAs,
+ NextProtos: cfg.NextProtos,
+ ServerName: cfg.ServerName,
+ ClientAuth: cfg.ClientAuth,
+ ClientCAs: cfg.ClientCAs,
+ InsecureSkipVerify: cfg.InsecureSkipVerify,
+ CipherSuites: cfg.CipherSuites,
+ PreferServerCipherSuites: cfg.PreferServerCipherSuites,
+ SessionTicketsDisabled: cfg.SessionTicketsDisabled,
+ SessionTicketKey: cfg.SessionTicketKey,
+ ClientSessionCache: cfg.ClientSessionCache,
+ MinVersion: cfg.MinVersion,
+ MaxVersion: cfg.MaxVersion,
+ CurvePreferences: cfg.CurvePreferences,
+ DynamicRecordSizingDisabled: cfg.DynamicRecordSizingDisabled,
+ Renegotiation: cfg.Renegotiation,
}
}
return &tls.Config{}
}
return &tls.Config{
- Rand: cfg.Rand,
- Time: cfg.Time,
- Certificates: cfg.Certificates,
- NameToCertificate: cfg.NameToCertificate,
- GetCertificate: cfg.GetCertificate,
- RootCAs: cfg.RootCAs,
- NextProtos: cfg.NextProtos,
- ServerName: cfg.ServerName,
- ClientAuth: cfg.ClientAuth,
- ClientCAs: cfg.ClientCAs,
- InsecureSkipVerify: cfg.InsecureSkipVerify,
- CipherSuites: cfg.CipherSuites,
- PreferServerCipherSuites: cfg.PreferServerCipherSuites,
- ClientSessionCache: cfg.ClientSessionCache,
- MinVersion: cfg.MinVersion,
- MaxVersion: cfg.MaxVersion,
- CurvePreferences: cfg.CurvePreferences,
- Renegotiation: cfg.Renegotiation,
+ Rand: cfg.Rand,
+ Time: cfg.Time,
+ Certificates: cfg.Certificates,
+ NameToCertificate: cfg.NameToCertificate,
+ GetCertificate: cfg.GetCertificate,
+ RootCAs: cfg.RootCAs,
+ NextProtos: cfg.NextProtos,
+ ServerName: cfg.ServerName,
+ ClientAuth: cfg.ClientAuth,
+ ClientCAs: cfg.ClientCAs,
+ InsecureSkipVerify: cfg.InsecureSkipVerify,
+ CipherSuites: cfg.CipherSuites,
+ PreferServerCipherSuites: cfg.PreferServerCipherSuites,
+ ClientSessionCache: cfg.ClientSessionCache,
+ MinVersion: cfg.MinVersion,
+ MaxVersion: cfg.MaxVersion,
+ CurvePreferences: cfg.CurvePreferences,
+ DynamicRecordSizingDisabled: cfg.DynamicRecordSizingDisabled,
+ Renegotiation: cfg.Renegotiation,
}
}
--- /dev/null
+// 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.
+
+// White-box tests for transport.go (in package http instead of http_test).
+
+package http
+
+import (
+ "errors"
+ "net"
+ "testing"
+)
+
+// Issue 15446: incorrect wrapping of errors when server closes an idle connection.
+func TestTransportPersistConnReadLoopEOF(t *testing.T) {
+ ln := newLocalListener(t)
+ defer ln.Close()
+
+ connc := make(chan net.Conn, 1)
+ go func() {
+ defer close(connc)
+ c, err := ln.Accept()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ connc <- c
+ }()
+
+ tr := new(Transport)
+ req, _ := NewRequest("GET", "http://"+ln.Addr().String(), nil)
+ treq := &transportRequest{Request: req}
+ cm := connectMethod{targetScheme: "http", targetAddr: ln.Addr().String()}
+ pc, err := tr.getConn(treq, cm)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer pc.close(errors.New("test over"))
+
+ conn := <-connc
+ if conn == nil {
+ // Already called t.Error in the accept goroutine.
+ return
+ }
+ conn.Close() // simulate the server hanging up on the client
+
+ _, err = pc.roundTrip(treq)
+ if err != errServerClosedConn && err != errServerClosedIdle {
+ t.Fatalf("roundTrip = %#v, %v; want errServerClosedConn or errServerClosedIdle", err, err)
+ }
+
+ <-pc.closech
+ err = pc.closed
+ if err != errServerClosedConn && err != errServerClosedIdle {
+ t.Fatalf("pc.closed = %#v, %v; want errServerClosedConn or errServerClosedIdle", err, err)
+ }
+}
+
+func newLocalListener(t *testing.T) net.Listener {
+ ln, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ ln, err = net.Listen("tcp6", "[::1]:0")
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+ return ln
+}
func TestTransportAutomaticHTTP2_ExpectContinueTimeout(t *testing.T) {
testTransportAutoHTTP(t, &Transport{
ExpectContinueTimeout: 1 * time.Second,
+ }, true)
+}
+
+func TestTransportAutomaticHTTP2_Dial(t *testing.T) {
+ var d net.Dialer
+ testTransportAutoHTTP(t, &Transport{
+ Dial: d.Dial,
+ }, false)
+}
+
+func TestTransportAutomaticHTTP2_DialTLS(t *testing.T) {
+ testTransportAutoHTTP(t, &Transport{
+ DialTLS: func(network, addr string) (net.Conn, error) {
+ panic("unused")
+ },
}, false)
}
}
}
-func TestTransportEventTrace(t *testing.T) { testTransportEventTrace(t, false) }
+func TestTransportEventTrace(t *testing.T) { testTransportEventTrace(t, h1Mode, false) }
+func TestTransportEventTrace_h2(t *testing.T) { testTransportEventTrace(t, h2Mode, false) }
// test a non-nil httptrace.ClientTrace but with all hooks set to zero.
-func TestTransportEventTrace_NoHooks(t *testing.T) { testTransportEventTrace(t, true) }
+func TestTransportEventTrace_NoHooks(t *testing.T) { testTransportEventTrace(t, h1Mode, true) }
+func TestTransportEventTrace_NoHooks_h2(t *testing.T) { testTransportEventTrace(t, h2Mode, true) }
-func testTransportEventTrace(t *testing.T, noHooks bool) {
+func testTransportEventTrace(t *testing.T, h2 bool, noHooks bool) {
defer afterTest(t)
const resBody = "some body"
- ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ gotWroteReqEvent := make(chan struct{})
+ cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
if _, err := ioutil.ReadAll(r.Body); err != nil {
t.Error(err)
}
+ if !noHooks {
+ select {
+ case <-gotWroteReqEvent:
+ case <-time.After(5 * time.Second):
+ t.Error("timeout waiting for WroteRequest event")
+ }
+ }
io.WriteString(w, resBody)
}))
- defer ts.Close()
- tr := &Transport{
- ExpectContinueTimeout: 1 * time.Second,
- }
- defer tr.CloseIdleConnections()
- c := &Client{Transport: tr}
+ defer cst.close()
+
+ cst.tr.ExpectContinueTimeout = 1 * time.Second
var mu sync.Mutex
var buf bytes.Buffer
buf.WriteByte('\n')
}
- ip, port, err := net.SplitHostPort(ts.Listener.Addr().String())
+ addrStr := cst.ts.Listener.Addr().String()
+ ip, port, err := net.SplitHostPort(addrStr)
if err != nil {
t.Fatal(err)
}
return []net.IPAddr{{IP: net.ParseIP(ip)}}, nil
})
- req, _ := NewRequest("POST", "http://dns-is-faked.golang:"+port, strings.NewReader("some body"))
+ req, _ := NewRequest("POST", cst.scheme()+"://dns-is-faked.golang:"+port, strings.NewReader("some body"))
trace := &httptrace.ClientTrace{
GetConn: func(hostPort string) { logf("Getting conn for %v ...", hostPort) },
GotConn: func(ci httptrace.GotConnInfo) { logf("got conn: %+v", ci) },
},
Wait100Continue: func() { logf("Wait100Continue") },
Got100Continue: func() { logf("Got100Continue") },
- WroteRequest: func(e httptrace.WroteRequestInfo) { logf("WroteRequest: %+v", e) },
+ WroteRequest: func(e httptrace.WroteRequestInfo) {
+ close(gotWroteReqEvent)
+ logf("WroteRequest: %+v", e)
+ },
}
if noHooks {
// zero out all func pointers, trying to get some path to crash
req = req.WithContext(httptrace.WithClientTrace(ctx, trace))
req.Header.Set("Expect", "100-continue")
- res, err := c.Do(req)
+ res, err := cst.c.Do(req)
if err != nil {
t.Fatal(err)
}
+ logf("got roundtrip.response")
slurp, err := ioutil.ReadAll(res.Body)
if err != nil {
t.Fatal(err)
}
+ logf("consumed body")
if string(slurp) != resBody || res.StatusCode != 200 {
t.Fatalf("Got %q, %v; want %q, 200 OK", slurp, res.Status, resBody)
}
t.Errorf("expected substring %q in output.", sub)
}
}
+ if strings.Count(got, "got conn: {") != 1 {
+ t.Errorf("expected exactly 1 \"got conn\" event.")
+ }
wantSub("Getting conn for dns-is-faked.golang:" + port)
wantSub("DNS start: {Host:dns-is-faked.golang}")
wantSub("DNS done: {Addrs:[{IP:" + ip + " Zone:}] Err:<nil> Coalesced:false}")
- wantSub("connected to tcp " + ts.Listener.Addr().String() + " = <nil>")
+ wantSub("Connecting to tcp " + addrStr)
+ wantSub("connected to tcp " + addrStr + " = <nil>")
wantSub("Reused:false WasIdle:false IdleTime:0s")
wantSub("first response byte")
- wantSub("PutIdleConn = <nil>")
- wantSub("WroteRequest: {Err:<nil>}")
+ if !h2 {
+ wantSub("PutIdleConn = <nil>")
+ }
wantSub("Wait100Continue")
wantSub("Got100Continue")
+ wantSub("WroteRequest: {Err:<nil>}")
+ if strings.Contains(got, " to udp ") {
+ t.Errorf("should not see UDP (DNS) connections")
+ }
+ if t.Failed() {
+ t.Errorf("Output:\n%s", got)
+ }
+}
+
+func TestTransportEventTraceRealDNS(t *testing.T) {
+ defer afterTest(t)
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+ c := &Client{Transport: tr}
+
+ var mu sync.Mutex
+ var buf bytes.Buffer
+ logf := func(format string, args ...interface{}) {
+ mu.Lock()
+ defer mu.Unlock()
+ fmt.Fprintf(&buf, format, args...)
+ buf.WriteByte('\n')
+ }
+
+ req, _ := NewRequest("GET", "http://dns-should-not-resolve.golang:80", nil)
+ trace := &httptrace.ClientTrace{
+ DNSStart: func(e httptrace.DNSStartInfo) { logf("DNSStart: %+v", e) },
+ DNSDone: func(e httptrace.DNSDoneInfo) { logf("DNSDone: %+v", e) },
+ ConnectStart: func(network, addr string) { logf("ConnectStart: %s %s", network, addr) },
+ ConnectDone: func(network, addr string, err error) { logf("ConnectDone: %s %s %v", network, addr, err) },
+ }
+ req = req.WithContext(httptrace.WithClientTrace(context.Background(), trace))
+
+ resp, err := c.Do(req)
+ if err == nil {
+ resp.Body.Close()
+ t.Fatal("expected error during DNS lookup")
+ }
+
+ got := buf.String()
+ wantSub := func(sub string) {
+ if !strings.Contains(got, sub) {
+ t.Errorf("expected substring %q in output.", sub)
+ }
+ }
+ wantSub("DNSStart: {Host:dns-should-not-resolve.golang}")
+ wantSub("DNSDone: {Addrs:[] Err:")
+ if strings.Contains(got, "ConnectStart") || strings.Contains(got, "ConnectDone") {
+ t.Errorf("should not see Connect events")
+ }
if t.Failed() {
t.Errorf("Output:\n%s", got)
}
package net
import (
- "os"
"syscall"
- "unsafe"
+
+ "golang.org/x/net/route"
)
// If the ifindex is zero, interfaceTable returns mappings of all
// network interfaces. Otherwise it returns a mapping of a specific
// interface.
func interfaceTable(ifindex int) ([]Interface, error) {
- tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
+ msgs, err := interfaceMessages(ifindex)
if err != nil {
- return nil, os.NewSyscallError("routerib", err)
+ return nil, err
}
- msgs, err := syscall.ParseRoutingMessage(tab)
- if err != nil {
- return nil, os.NewSyscallError("parseroutingmessage", err)
+ n := len(msgs)
+ if ifindex != 0 {
+ n = 1
}
- return parseInterfaceTable(ifindex, msgs)
-}
-
-func parseInterfaceTable(ifindex int, msgs []syscall.RoutingMessage) ([]Interface, error) {
- var ift []Interface
-loop:
+ ift := make([]Interface, n)
+ n = 0
for _, m := range msgs {
switch m := m.(type) {
- case *syscall.InterfaceMessage:
- if ifindex == 0 || ifindex == int(m.Header.Index) {
- ifi, err := newLink(m)
- if err != nil {
- return nil, err
- }
- ift = append(ift, *ifi)
- if ifindex == int(m.Header.Index) {
- break loop
+ case *route.InterfaceMessage:
+ if ifindex != 0 && ifindex != m.Index {
+ continue
+ }
+ ift[n].Index = m.Index
+ ift[n].Name = m.Name
+ ift[n].Flags = linkFlags(m.Flags)
+ if sa, ok := m.Addrs[syscall.RTAX_IFP].(*route.LinkAddr); ok && len(sa.Addr) > 0 {
+ ift[n].HardwareAddr = make([]byte, len(sa.Addr))
+ copy(ift[n].HardwareAddr, sa.Addr)
+ }
+ for _, sys := range m.Sys() {
+ if imx, ok := sys.(*route.InterfaceMetrics); ok {
+ ift[n].MTU = imx.MTU
+ break
}
}
+ n++
+ if ifindex == m.Index {
+ return ift[:n], nil
+ }
}
}
- return ift, nil
-}
-
-func newLink(m *syscall.InterfaceMessage) (*Interface, error) {
- sas, err := syscall.ParseRoutingSockaddr(m)
- if err != nil {
- return nil, os.NewSyscallError("parseroutingsockaddr", err)
- }
- ifi := &Interface{Index: int(m.Header.Index), Flags: linkFlags(m.Header.Flags)}
- sa, _ := sas[syscall.RTAX_IFP].(*syscall.SockaddrDatalink)
- if sa != nil {
- // NOTE: SockaddrDatalink.Data is minimum work area,
- // can be larger.
- m.Data = m.Data[unsafe.Offsetof(sa.Data):]
- var name [syscall.IFNAMSIZ]byte
- for i := 0; i < int(sa.Nlen); i++ {
- name[i] = m.Data[i]
- }
- ifi.Name = string(name[:sa.Nlen])
- ifi.MTU = int(m.Header.Data.Mtu)
- addr := make([]byte, sa.Alen)
- for i := 0; i < int(sa.Alen); i++ {
- addr[i] = m.Data[int(sa.Nlen)+i]
- }
- ifi.HardwareAddr = addr[:sa.Alen]
- }
- return ifi, nil
+ return ift[:n], nil
}
-func linkFlags(rawFlags int32) Flags {
+func linkFlags(rawFlags int) Flags {
var f Flags
if rawFlags&syscall.IFF_UP != 0 {
f |= FlagUp
if ifi != nil {
index = ifi.Index
}
- tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, index)
- if err != nil {
- return nil, os.NewSyscallError("routerib", err)
- }
- msgs, err := syscall.ParseRoutingMessage(tab)
+ msgs, err := interfaceMessages(index)
if err != nil {
- return nil, os.NewSyscallError("parseroutingmessage", err)
+ return nil, err
}
- var ift []Interface
- if index == 0 {
- ift, err = parseInterfaceTable(index, msgs)
- if err != nil {
- return nil, err
- }
- }
- var ifat []Addr
+ ifat := make([]Addr, 0, len(msgs))
for _, m := range msgs {
switch m := m.(type) {
- case *syscall.InterfaceAddrMessage:
- if index == 0 || index == int(m.Header.Index) {
- if index == 0 {
- var err error
- ifi, err = interfaceByIndex(ift, int(m.Header.Index))
- if err != nil {
- return nil, err
- }
- }
- ifa, err := newAddr(ifi, m)
- if err != nil {
- return nil, err
- }
- if ifa != nil {
- ifat = append(ifat, ifa)
- }
+ case *route.InterfaceAddrMessage:
+ if index != 0 && index != m.Index {
+ continue
+ }
+ var mask IPMask
+ switch sa := m.Addrs[syscall.RTAX_NETMASK].(type) {
+ case *route.Inet4Addr:
+ mask = IPv4Mask(sa.IP[0], sa.IP[1], sa.IP[2], sa.IP[3])
+ case *route.Inet6Addr:
+ mask = make(IPMask, IPv6len)
+ copy(mask, sa.IP[:])
+ }
+ var ip IP
+ switch sa := m.Addrs[syscall.RTAX_IFA].(type) {
+ case *route.Inet4Addr:
+ ip = IPv4(sa.IP[0], sa.IP[1], sa.IP[2], sa.IP[3])
+ case *route.Inet6Addr:
+ ip = make(IP, IPv6len)
+ copy(ip, sa.IP[:])
+ }
+ if ip != nil && mask != nil { // NetBSD may contain route.LinkAddr
+ ifat = append(ifat, &IPNet{IP: ip, Mask: mask})
}
}
}
return ifat, nil
}
-
-func newAddr(ifi *Interface, m *syscall.InterfaceAddrMessage) (*IPNet, error) {
- sas, err := syscall.ParseRoutingSockaddr(m)
- if err != nil {
- return nil, os.NewSyscallError("parseroutingsockaddr", err)
- }
- ifa := &IPNet{}
- switch sa := sas[syscall.RTAX_NETMASK].(type) {
- case *syscall.SockaddrInet4:
- ifa.Mask = IPv4Mask(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])
- case *syscall.SockaddrInet6:
- ifa.Mask = make(IPMask, IPv6len)
- copy(ifa.Mask, sa.Addr[:])
- }
- switch sa := sas[syscall.RTAX_IFA].(type) {
- case *syscall.SockaddrInet4:
- ifa.IP = IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])
- case *syscall.SockaddrInet6:
- ifa.IP = make(IP, IPv6len)
- copy(ifa.IP, sa.Addr[:])
- // NOTE: KAME based IPv6 protocol stack usually embeds
- // the interface index in the interface-local or
- // link-local address as the kernel-internal form.
- if ifa.IP.IsLinkLocalUnicast() {
- ifa.IP[2], ifa.IP[3] = 0, 0
- ifa.Zone = ifi.Name
- }
- }
- if ifa.IP == nil || ifa.Mask == nil {
- return nil, nil // Sockaddrs contain syscall.SockaddrDatalink on NetBSD
- }
- return ifa, nil
-}
import (
"fmt"
"os/exec"
+ "runtime"
)
-func (ti *testInterface) setBroadcast(suffix int) error {
- ti.name = fmt.Sprintf("vlan%d", suffix)
+func (ti *testInterface) setBroadcast(vid int) error {
+ if runtime.GOOS == "openbsd" {
+ ti.name = fmt.Sprintf("vether%d", vid)
+ } else {
+ ti.name = fmt.Sprintf("vlan%d", vid)
+ }
xname, err := exec.LookPath("ifconfig")
if err != nil {
return err
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build dragonfly netbsd openbsd
+
package net
+import (
+ "syscall"
+
+ "golang.org/x/net/route"
+)
+
+func interfaceMessages(ifindex int) ([]route.Message, error) {
+ rib, err := route.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_IFLIST, ifindex)
+ if err != nil {
+ return nil, err
+ }
+ return route.ParseRIB(syscall.NET_RT_IFLIST, rib)
+}
+
// interfaceMulticastAddrTable returns addresses for a specific
// interface.
func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
package net
import (
- "os"
"syscall"
+
+ "golang.org/x/net/route"
)
+func interfaceMessages(ifindex int) ([]route.Message, error) {
+ rib, err := route.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_IFLIST, ifindex)
+ if err != nil {
+ return nil, err
+ }
+ return route.ParseRIB(syscall.NET_RT_IFLIST, rib)
+}
+
// interfaceMulticastAddrTable returns addresses for a specific
// interface.
func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
- tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST2, ifi.Index)
+ rib, err := route.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_IFLIST2, ifi.Index)
if err != nil {
- return nil, os.NewSyscallError("routerib", err)
+ return nil, err
}
- msgs, err := syscall.ParseRoutingMessage(tab)
+ msgs, err := route.ParseRIB(syscall.NET_RT_IFLIST2, rib)
if err != nil {
- return nil, os.NewSyscallError("parseroutingmessage", err)
+ return nil, err
}
- var ifmat []Addr
+ ifmat := make([]Addr, 0, len(msgs))
for _, m := range msgs {
switch m := m.(type) {
- case *syscall.InterfaceMulticastAddrMessage:
- if ifi.Index == int(m.Header.Index) {
- ifma, err := newMulticastAddr(ifi, m)
- if err != nil {
- return nil, err
- }
- if ifma != nil {
- ifmat = append(ifmat, ifma)
- }
+ case *route.InterfaceMulticastAddrMessage:
+ if ifi.Index != m.Index {
+ continue
+ }
+ var ip IP
+ switch sa := m.Addrs[syscall.RTAX_IFA].(type) {
+ case *route.Inet4Addr:
+ ip = IPv4(sa.IP[0], sa.IP[1], sa.IP[2], sa.IP[3])
+ case *route.Inet6Addr:
+ ip = make(IP, IPv6len)
+ copy(ip, sa.IP[:])
+ }
+ if ip != nil {
+ ifmat = append(ifmat, &IPAddr{IP: ip})
}
}
}
return ifmat, nil
}
-
-func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) (*IPAddr, error) {
- sas, err := syscall.ParseRoutingSockaddr(m)
- if err != nil {
- return nil, os.NewSyscallError("parseroutingsockaddr", err)
- }
- switch sa := sas[syscall.RTAX_IFA].(type) {
- case *syscall.SockaddrInet4:
- return &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])}, nil
- case *syscall.SockaddrInet6:
- ifma := IPAddr{IP: make(IP, IPv6len)}
- copy(ifma.IP, sa.Addr[:])
- // NOTE: KAME based IPv6 protocol stack usually embeds
- // the interface index in the interface-local or
- // link-local address as the kernel-internal form.
- if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() {
- ifma.IP[2], ifma.IP[3] = 0, 0
- }
- return &ifma, nil
- default:
- return nil, nil
- }
-}
+++ /dev/null
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package net
-
-// interfaceMulticastAddrTable returns addresses for a specific
-// interface.
-func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
- // TODO(mikio): Implement this like other platforms.
- return nil, nil
-}
package net
import (
- "os"
"syscall"
+
+ "golang.org/x/net/route"
)
+func interfaceMessages(ifindex int) ([]route.Message, error) {
+ typ := route.RIBType(syscall.NET_RT_IFLISTL)
+ rib, err := route.FetchRIB(syscall.AF_UNSPEC, typ, ifindex)
+ if err != nil {
+ typ = route.RIBType(syscall.NET_RT_IFLIST)
+ rib, err = route.FetchRIB(syscall.AF_UNSPEC, typ, ifindex)
+ }
+ if err != nil {
+ return nil, err
+ }
+ return route.ParseRIB(typ, rib)
+}
+
// interfaceMulticastAddrTable returns addresses for a specific
// interface.
func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
- tab, err := syscall.RouteRIB(syscall.NET_RT_IFMALIST, ifi.Index)
+ rib, err := route.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_IFMALIST, ifi.Index)
if err != nil {
- return nil, os.NewSyscallError("routerib", err)
+ return nil, err
}
- msgs, err := syscall.ParseRoutingMessage(tab)
+ msgs, err := route.ParseRIB(syscall.NET_RT_IFMALIST, rib)
if err != nil {
- return nil, os.NewSyscallError("parseroutingmessage", err)
+ return nil, err
}
- var ifmat []Addr
+ ifmat := make([]Addr, 0, len(msgs))
for _, m := range msgs {
switch m := m.(type) {
- case *syscall.InterfaceMulticastAddrMessage:
- if ifi.Index == int(m.Header.Index) {
- ifma, err := newMulticastAddr(ifi, m)
- if err != nil {
- return nil, err
- }
- if ifma != nil {
- ifmat = append(ifmat, ifma)
- }
+ case *route.InterfaceMulticastAddrMessage:
+ if ifi.Index != m.Index {
+ continue
+ }
+ var ip IP
+ switch sa := m.Addrs[syscall.RTAX_IFA].(type) {
+ case *route.Inet4Addr:
+ ip = IPv4(sa.IP[0], sa.IP[1], sa.IP[2], sa.IP[3])
+ case *route.Inet6Addr:
+ ip = make(IP, IPv6len)
+ copy(ip, sa.IP[:])
+ }
+ if ip != nil {
+ ifmat = append(ifmat, &IPAddr{IP: ip})
}
}
}
return ifmat, nil
}
-
-func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) (*IPAddr, error) {
- sas, err := syscall.ParseRoutingSockaddr(m)
- if err != nil {
- return nil, os.NewSyscallError("parseroutingsockaddr", err)
- }
- switch sa := sas[syscall.RTAX_IFA].(type) {
- case *syscall.SockaddrInet4:
- return &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])}, nil
- case *syscall.SockaddrInet6:
- ifma := IPAddr{IP: make(IP, IPv6len)}
- copy(ifma.IP, sa.Addr[:])
- // NOTE: KAME based IPv6 protocol stack usually embeds
- // the interface index in the interface-local or
- // link-local address as the kernel-internal form.
- if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() {
- ifma.IP[2], ifma.IP[3] = 0, 0
- }
- return &ifma, nil
- default:
- return nil, nil
- }
-}
case syscall.AF_INET6:
ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv6len)}
copy(ifa.IP, a.Value[:])
- if ifa.IP.IsLinkLocalUnicast() {
- ifa.Zone = ifi.Name
- }
return ifa
}
}
+++ /dev/null
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package net
-
-// interfaceMulticastAddrTable returns addresses for a specific
-// interface.
-func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
- // TODO(mikio): Implement this like other platforms.
- return nil, nil
-}
package net
import (
- "internal/testenv"
+ "fmt"
"reflect"
"runtime"
"testing"
return ""
}
-type routeStats struct {
- loop int // # of active loopback interfaces
- other int // # of active other interfaces
-
- uni4, uni6 int // # of active connected unicast, anycast routes
- multi4, multi6 int // # of active connected multicast route clones
-}
-
func TestInterfaces(t *testing.T) {
- if runtime.GOOS == "freebsd" && runtime.GOARCH == "arm" {
- // 100% flaky, actually, at least on some FreeBSD versions
- testenv.SkipFlaky(t, 15262)
- }
ift, err := Interfaces()
if err != nil {
t.Fatal(err)
}
- var stats routeStats
for _, ifi := range ift {
ifxi, err := InterfaceByIndex(ifi.Index)
if err != nil {
if !reflect.DeepEqual(ifxn, &ifi) {
t.Errorf("got %v; want %v", ifxn, ifi)
}
- t.Logf("%q: flags %q, ifindex %v, mtu %v", ifi.Name, ifi.Flags.String(), ifi.Index, ifi.MTU)
- t.Logf("hardware address %q", ifi.HardwareAddr.String())
- if ifi.Flags&FlagUp != 0 {
- if ifi.Flags&FlagLoopback != 0 {
- stats.loop++
- } else {
- stats.other++
- }
- }
- n4, n6 := testInterfaceAddrs(t, &ifi)
- stats.uni4 += n4
- stats.uni6 += n6
- n4, n6 = testInterfaceMulticastAddrs(t, &ifi)
- stats.multi4 += n4
- stats.multi6 += n6
- }
- switch runtime.GOOS {
- case "nacl", "plan9", "solaris":
- default:
- // Test the existence of connected unicast routes for
- // IPv4.
- if supportsIPv4 && stats.loop+stats.other > 0 && stats.uni4 == 0 {
- t.Errorf("num IPv4 unicast routes = 0; want >0; summary: %+v", stats)
- }
- // Test the existence of connected unicast routes for
- // IPv6. We can assume the existence of ::1/128 when
- // at least one loopback interface is installed.
- if supportsIPv6 && stats.loop > 0 && stats.uni6 == 0 {
- t.Errorf("num IPv6 unicast routes = 0; want >0; summary: %+v", stats)
- }
- }
- switch runtime.GOOS {
- case "dragonfly", "nacl", "netbsd", "openbsd", "plan9", "solaris":
- default:
- // Test the existence of connected multicast route
- // clones for IPv4. Unlike IPv6, IPv4 multicast
- // capability is not a mandatory feature, and so this
- // test is disabled.
- //if supportsIPv4 && stats.loop > 0 && stats.uni4 > 1 && stats.multi4 == 0 {
- // t.Errorf("num IPv4 multicast route clones = 0; want >0; summary: %+v", stats)
- //}
- // Test the existence of connected multicast route
- // clones for IPv6. Some platform never uses loopback
- // interface as the nexthop for multicast routing.
- // We can assume the existence of connected multicast
- // route clones when at least two connected unicast
- // routes, ::1/128 and other, are installed.
- if supportsIPv6 && stats.loop > 0 && stats.uni6 > 1 && stats.multi6 == 0 {
- t.Errorf("num IPv6 multicast route clones = 0; want >0; summary: %+v", stats)
- }
+ t.Logf("%s: flags=%v index=%d mtu=%d hwaddr=%v", ifi.Name, ifi.Flags, ifi.Index, ifi.MTU, ifi.HardwareAddr)
}
}
if err != nil {
t.Fatal(err)
}
- var stats routeStats
- for _, ifi := range ift {
- if ifi.Flags&FlagUp != 0 {
- if ifi.Flags&FlagLoopback != 0 {
- stats.loop++
- } else {
- stats.other++
- }
- }
- }
+ ifStats := interfaceStats(ift)
ifat, err := InterfaceAddrs()
if err != nil {
t.Fatal(err)
}
- stats.uni4, stats.uni6 = testAddrs(t, ifat)
- // Test the existence of connected unicast routes for IPv4.
- if supportsIPv4 && stats.loop+stats.other > 0 && stats.uni4 == 0 {
- t.Errorf("num IPv4 unicast routes = 0; want >0; summary: %+v", stats)
+ uniStats, err := validateInterfaceUnicastAddrs(ifat)
+ if err != nil {
+ t.Fatal(err)
}
- // Test the existence of connected unicast routes for IPv6.
- // We can assume the existence of ::1/128 when at least one
- // loopback interface is installed.
- if supportsIPv6 && stats.loop > 0 && stats.uni6 == 0 {
- t.Errorf("num IPv6 unicast routes = 0; want >0; summary: %+v", stats)
+ if err := checkUnicastStats(ifStats, uniStats); err != nil {
+ t.Fatal(err)
}
}
-func testInterfaceAddrs(t *testing.T, ifi *Interface) (naf4, naf6 int) {
- ifat, err := ifi.Addrs()
+func TestInterfaceUnicastAddrs(t *testing.T) {
+ ift, err := Interfaces()
+ if err != nil {
+ t.Fatal(err)
+ }
+ ifStats := interfaceStats(ift)
if err != nil {
t.Fatal(err)
}
- return testAddrs(t, ifat)
+ var uniStats routeStats
+ for _, ifi := range ift {
+ ifat, err := ifi.Addrs()
+ if err != nil {
+ t.Fatal(ifi, err)
+ }
+ stats, err := validateInterfaceUnicastAddrs(ifat)
+ if err != nil {
+ t.Fatal(ifi, err)
+ }
+ uniStats.ipv4 += stats.ipv4
+ uniStats.ipv6 += stats.ipv6
+ }
+ if err := checkUnicastStats(ifStats, &uniStats); err != nil {
+ t.Fatal(err)
+ }
}
-func testInterfaceMulticastAddrs(t *testing.T, ifi *Interface) (nmaf4, nmaf6 int) {
- ifmat, err := ifi.MulticastAddrs()
+func TestInterfaceMulticastAddrs(t *testing.T) {
+ ift, err := Interfaces()
+ if err != nil {
+ t.Fatal(err)
+ }
+ ifStats := interfaceStats(ift)
+ ifat, err := InterfaceAddrs()
+ if err != nil {
+ t.Fatal(err)
+ }
+ uniStats, err := validateInterfaceUnicastAddrs(ifat)
if err != nil {
t.Fatal(err)
}
- return testMulticastAddrs(t, ifmat)
+ var multiStats routeStats
+ for _, ifi := range ift {
+ ifmat, err := ifi.MulticastAddrs()
+ if err != nil {
+ t.Fatal(ifi, err)
+ }
+ stats, err := validateInterfaceMulticastAddrs(ifmat)
+ if err != nil {
+ t.Fatal(ifi, err)
+ }
+ multiStats.ipv4 += stats.ipv4
+ multiStats.ipv6 += stats.ipv6
+ }
+ if err := checkMulticastStats(ifStats, uniStats, &multiStats); err != nil {
+ t.Fatal(err)
+ }
+}
+
+type ifStats struct {
+ loop int // # of active loopback interfaces
+ other int // # of active other interfaces
+}
+
+func interfaceStats(ift []Interface) *ifStats {
+ var stats ifStats
+ for _, ifi := range ift {
+ if ifi.Flags&FlagUp != 0 {
+ if ifi.Flags&FlagLoopback != 0 {
+ stats.loop++
+ } else {
+ stats.other++
+ }
+ }
+ }
+ return &stats
+}
+
+type routeStats struct {
+ ipv4, ipv6 int // # of active connected unicast, anycast or multicast routes
}
-func testAddrs(t *testing.T, ifat []Addr) (naf4, naf6 int) {
+func validateInterfaceUnicastAddrs(ifat []Addr) (*routeStats, error) {
// Note: BSD variants allow assigning any IPv4/IPv6 address
// prefix to IP interface. For example,
// - 0.0.0.0/0 through 255.255.255.255/32
// - ::/0 through ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128
// In other words, there is no tightly-coupled combination of
// interface address prefixes and connected routes.
+ stats := new(routeStats)
for _, ifa := range ifat {
switch ifa := ifa.(type) {
case *IPNet:
if ifa == nil || ifa.IP == nil || ifa.IP.IsMulticast() || ifa.Mask == nil {
- t.Errorf("unexpected value: %#v", ifa)
- continue
+ return nil, fmt.Errorf("unexpected value: %#v", ifa)
}
if len(ifa.IP) != IPv6len {
- t.Errorf("should be internal representation either IPv6 or IPv6 IPv4-mapped address: %#v", ifa)
- continue
+ return nil, fmt.Errorf("should be internal representation either IPv6 or IPv4-mapped IPv6 address: %#v", ifa)
}
prefixLen, maxPrefixLen := ifa.Mask.Size()
if ifa.IP.To4() != nil {
if 0 >= prefixLen || prefixLen > 8*IPv4len || maxPrefixLen != 8*IPv4len {
- t.Errorf("unexpected prefix length: %d/%d", prefixLen, maxPrefixLen)
- continue
+ return nil, fmt.Errorf("unexpected prefix length: %d/%d for %#v", prefixLen, maxPrefixLen, ifa)
}
if ifa.IP.IsLoopback() && (prefixLen != 8 && prefixLen != 8*IPv4len) { // see RFC 1122
- t.Errorf("unexpected prefix length for IPv4 loopback: %d/%d", prefixLen, maxPrefixLen)
- continue
+ return nil, fmt.Errorf("unexpected prefix length: %d/%d for %#v", prefixLen, maxPrefixLen, ifa)
}
- naf4++
+ stats.ipv4++
}
if ifa.IP.To16() != nil && ifa.IP.To4() == nil {
if 0 >= prefixLen || prefixLen > 8*IPv6len || maxPrefixLen != 8*IPv6len {
- t.Errorf("unexpected prefix length: %d/%d", prefixLen, maxPrefixLen)
- continue
+ return nil, fmt.Errorf("unexpected prefix length: %d/%d for %#v", prefixLen, maxPrefixLen, ifa)
}
if ifa.IP.IsLoopback() && prefixLen != 8*IPv6len { // see RFC 4291
- t.Errorf("unexpected prefix length for IPv6 loopback: %d/%d", prefixLen, maxPrefixLen)
- continue
+ return nil, fmt.Errorf("unexpected prefix length: %d/%d for %#v", prefixLen, maxPrefixLen, ifa)
}
- if ifa.IP.IsLinkLocalUnicast() && ifa.Zone == "" {
- t.Errorf("no IPv6 zone identifier found: %#v", ifa)
- continue
- }
- naf6++
+ stats.ipv6++
}
- t.Logf("interface address %q", ifa.String())
case *IPAddr:
if ifa == nil || ifa.IP == nil || ifa.IP.IsMulticast() {
- t.Errorf("unexpected value: %#v", ifa)
- continue
+ return nil, fmt.Errorf("unexpected value: %#v", ifa)
}
if len(ifa.IP) != IPv6len {
- t.Errorf("should be internal representation either IPv6 or IPv6 IPv4-mapped address: %#v", ifa)
- continue
+ return nil, fmt.Errorf("should be internal representation either IPv6 or IPv4-mapped IPv6 address: %#v", ifa)
}
if ifa.IP.To4() != nil {
- naf4++
+ stats.ipv4++
}
if ifa.IP.To16() != nil && ifa.IP.To4() == nil {
- naf6++
+ stats.ipv6++
}
- t.Logf("interface address %q", ifa.String())
default:
- t.Errorf("unexpected type: %T", ifa)
+ return nil, fmt.Errorf("unexpected type: %T", ifa)
}
}
- return
+ return stats, nil
}
-func testMulticastAddrs(t *testing.T, ifmat []Addr) (nmaf4, nmaf6 int) {
- for _, ifma := range ifmat {
- switch ifma := ifma.(type) {
+func validateInterfaceMulticastAddrs(ifat []Addr) (*routeStats, error) {
+ stats := new(routeStats)
+ for _, ifa := range ifat {
+ switch ifa := ifa.(type) {
case *IPAddr:
- if ifma == nil || ifma.IP == nil || ifma.IP.IsUnspecified() || !ifma.IP.IsMulticast() {
- t.Errorf("unexpected value: %+v", ifma)
- continue
+ if ifa == nil || ifa.IP == nil || ifa.IP.IsUnspecified() || !ifa.IP.IsMulticast() {
+ return nil, fmt.Errorf("unexpected value: %#v", ifa)
}
- if len(ifma.IP) != IPv6len {
- t.Errorf("should be internal representation either IPv6 or IPv6 IPv4-mapped address: %#v", ifma)
- continue
+ if len(ifa.IP) != IPv6len {
+ return nil, fmt.Errorf("should be internal representation either IPv6 or IPv4-mapped IPv6 address: %#v", ifa)
}
- if ifma.IP.To4() != nil {
- nmaf4++
+ if ifa.IP.To4() != nil {
+ stats.ipv4++
}
- if ifma.IP.To16() != nil && ifma.IP.To4() == nil {
- nmaf6++
+ if ifa.IP.To16() != nil && ifa.IP.To4() == nil {
+ stats.ipv6++
}
- t.Logf("joined group address %q", ifma.String())
default:
- t.Errorf("unexpected type: %T", ifma)
+ return nil, fmt.Errorf("unexpected type: %T", ifa)
}
}
- return
+ return stats, nil
+}
+
+func checkUnicastStats(ifStats *ifStats, uniStats *routeStats) error {
+ // Test the existence of connected unicast routes for IPv4.
+ if supportsIPv4 && ifStats.loop+ifStats.other > 0 && uniStats.ipv4 == 0 {
+ return fmt.Errorf("num IPv4 unicast routes = 0; want >0; summary: %+v, %+v", ifStats, uniStats)
+ }
+ // Test the existence of connected unicast routes for IPv6.
+ // We can assume the existence of ::1/128 when at least one
+ // loopback interface is installed.
+ if supportsIPv6 && ifStats.loop > 0 && uniStats.ipv6 == 0 {
+ return fmt.Errorf("num IPv6 unicast routes = 0; want >0; summary: %+v, %+v", ifStats, uniStats)
+ }
+ return nil
+}
+
+func checkMulticastStats(ifStats *ifStats, uniStats, multiStats *routeStats) error {
+ switch runtime.GOOS {
+ case "dragonfly", "nacl", "netbsd", "openbsd", "plan9", "solaris":
+ default:
+ // Test the existence of connected multicast route
+ // clones for IPv4. Unlike IPv6, IPv4 multicast
+ // capability is not a mandatory feature, and so IPv4
+ // multicast validation is ignored and we only check
+ // IPv6 below.
+ //
+ // Test the existence of connected multicast route
+ // clones for IPv6. Some platform never uses loopback
+ // interface as the nexthop for multicast routing.
+ // We can assume the existence of connected multicast
+ // route clones when at least two connected unicast
+ // routes, ::1/128 and other, are installed.
+ if supportsIPv6 && ifStats.loop > 0 && uniStats.ipv6 > 1 && multiStats.ipv6 == 0 {
+ return fmt.Errorf("num IPv6 multicast route clones = 0; want >0; summary: %+v, %+v, %+v", ifStats, uniStats, multiStats)
+ }
+ }
+ return nil
}
func BenchmarkInterfaces(b *testing.B) {
package net
import (
+ "fmt"
"os"
"os/exec"
"runtime"
func (ti *testInterface) setup() error {
for _, cmd := range ti.setupCmds {
- if err := cmd.Run(); err != nil {
- return err
+ if out, err := cmd.CombinedOutput(); err != nil {
+ return fmt.Errorf("args=%v out=%q err=%v", cmd.Args, string(out), err)
}
}
return nil
func (ti *testInterface) teardown() error {
for _, cmd := range ti.teardownCmds {
- if err := cmd.Run(); err != nil {
- return err
+ if out, err := cmd.CombinedOutput(); err != nil {
+ return fmt.Errorf("args=%v out=%q err=%v ", cmd.Args, string(out), err)
}
}
return nil
t.Skip("must be root")
}
+ // We suppose that using IPv4 link-local addresses doesn't
+ // harm anyone.
local, remote := "169.254.0.1", "169.254.0.254"
ip := ParseIP(remote)
for i := 0; i < 3; i++ {
t.Skip("must be root")
}
+ // We suppose that using IPv4 link-local addresses and the
+ // dot1Q ID for Token Ring and FDDI doesn't harm anyone.
local, remote := "169.254.0.1", "169.254.0.254"
ip := ParseIP(remote)
- for i := 0; i < 3; i++ {
+ for _, vid := range []int{1002, 1003, 1004, 1005} {
ift1, err := Interfaces()
if err != nil {
t.Fatal(err)
}
ti := &testInterface{local: local, remote: remote}
- if err := ti.setBroadcast(5682 + i); err != nil {
+ if err := ti.setBroadcast(vid); err != nil {
t.Skipf("test requires external command: %v", err)
}
if err := ti.setup(); err != nil {
}
ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(l, 8*IPv6len)}
copy(ifa.IP, sa.Addr[:])
- if ifa.IP.IsLinkLocalUnicast() {
- ifa.Zone = syscall.UTF16ToString((*(*[10000]uint16)(unsafe.Pointer(aa.FriendlyName)))[:])
- }
ifat = append(ifat, ifa)
}
}
type IPNet struct {
IP IP // network number
Mask IPMask // network mask
- Zone string // IPv6 scoped addressing zone
}
// IPv4 returns the IP address (in 16-byte form) of the
// It returns one of 4 forms:
// - "<nil>", if ip has length 0
// - dotted decimal ("192.0.2.1"), if ip is an IPv4 or IP4-mapped IPv6 address
-// - IPv6 ("2001:db9::1"), if ip is a valid IPv6 address
+// - IPv6 ("2001:db8::1"), if ip is a valid IPv6 address
// - the hexadecimal form of ip, without punctuation, if no other cases apply
func (ip IP) String() string {
p := ip
uitoa(uint(p4[3]))
}
if len(p) != IPv6len {
- return hexString(ip)
+ return "?" + hexString(ip)
}
// Find longest run of zeros.
return []byte(""), nil
}
if len(ip) != IPv4len && len(ip) != IPv6len {
- return nil, &AddrError{Err: "invalid IP address", Addr: ip.String()}
+ return nil, &AddrError{Err: "invalid IP address", Addr: hexString(ip)}
}
return []byte(ip.String()), nil
}
// Network returns the address's network name, "ip+net".
func (n *IPNet) Network() string { return "ip+net" }
-// String returns the CIDR notation of n like "192.168.100.1/24"
-// or "2001:DB8::/48" as defined in RFC 4632 and RFC 4291.
+// String returns the CIDR notation of n like "192.0.2.1/24"
+// or "2001:db8::/48" as defined in RFC 4632 and RFC 4291.
// If the mask is not in the canonical form, it returns the
// string which consists of an IP address, followed by a slash
// character and a mask expressed as hexadecimal form with no
-// punctuation like "192.168.100.1/c000ff00".
+// punctuation like "198.51.100.1/c000ff00".
func (n *IPNet) String() string {
nn, m := networkNumberAndMask(n)
if nn == nil || m == nil {
return "<nil>"
}
- ip := nn.String()
- if n.Zone != "" {
- ip = ip + "%" + n.Zone
- }
l := simpleMaskLength(m)
if l == -1 {
- return ip + "/" + m.String()
+ return nn.String() + "/" + m.String()
}
- return ip + "/" + uitoa(uint(l))
+ return nn.String() + "/" + uitoa(uint(l))
}
// Parse IPv4 address (d.d.d.d).
}
// ParseIP parses s as an IP address, returning the result.
-// The string s can be in dotted decimal ("74.125.19.99")
-// or IPv6 ("2001:4860:0:2001::68") form.
+// The string s can be in dotted decimal ("192.0.2.1")
+// or IPv6 ("2001:db8::68") form.
// If s is not a valid textual representation of an IP address,
// ParseIP returns nil.
func ParseIP(s string) IP {
}
// ParseCIDR parses s as a CIDR notation IP address and mask,
-// like "192.168.100.1/24" or "2001:DB8::/48", as defined in
+// like "192.0.2.0/24" or "2001:db8::/32", as defined in
// RFC 4632 and RFC 4291.
//
// It returns the IP address and the network implied by the IP
-// and mask. For example, ParseCIDR("192.168.100.1/16") returns
-// the IP address 192.168.100.1 and the network 192.168.0.0/16.
+// and mask. For example, ParseCIDR("198.51.100.1/24") returns
+// the IP address 198.51.100.1 and the network 198.51.100.0/24.
func ParseCIDR(s string) (IP, *IPNet, error) {
i := byteIndex(s, '/')
if i < 0 {
return nil, nil, &ParseError{Type: "CIDR address", Text: s}
}
- var zone string
addr, mask := s[:i], s[i+1:]
iplen := IPv4len
ip := parseIPv4(addr)
if ip == nil {
iplen = IPv6len
- ip, zone = parseIPv6(addr, true)
+ ip, _ = parseIPv6(addr, false)
}
n, i, ok := dtoi(mask, 0)
if ip == nil || !ok || i != len(mask) || n < 0 || n > 8*iplen {
return nil, nil, &ParseError{Type: "CIDR address", Text: s}
}
m := CIDRMask(n, 8*iplen)
- return ip, &IPNet{IP: ip.Mask(m), Mask: m, Zone: zone}, nil
+ return ip, &IPNet{IP: ip.Mask(m), Mask: m}, nil
}
// Opaque byte sequence
{
IP{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
- "0123456789abcdef",
+ "?0123456789abcdef",
nil,
&AddrError{Err: "invalid IP address", Addr: "0123456789abcdef"},
},
{"abcd:2345::/24", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2300::"), Mask: IPMask(ParseIP("ffff:ff00::"))}, nil},
{"2001:DB8::/48", ParseIP("2001:DB8::"), &IPNet{IP: ParseIP("2001:DB8::"), Mask: IPMask(ParseIP("ffff:ffff:ffff::"))}, nil},
{"2001:DB8::1/48", ParseIP("2001:DB8::1"), &IPNet{IP: ParseIP("2001:DB8::"), Mask: IPMask(ParseIP("ffff:ffff:ffff::"))}, nil},
- {"fe80::%en0/64", ParseIP("fe80::"), &IPNet{IP: ParseIP("fe80::"), Mask: CIDRMask(64, 128), Zone: "en0"}, nil},
- {"fe80::1%en0/64", ParseIP("fe80::1"), &IPNet{IP: ParseIP("fe80::"), Mask: CIDRMask(64, 128), Zone: "en0"}, nil},
-
{"192.168.1.1/255.255.255.0", nil, nil, &ParseError{Type: "CIDR address", Text: "192.168.1.1/255.255.255.0"}},
{"192.168.1.1/35", nil, nil, &ParseError{Type: "CIDR address", Text: "192.168.1.1/35"}},
{"2001:db8::1/-1", nil, nil, &ParseError{Type: "CIDR address", Text: "2001:db8::1/-1"}},
out string
}{
{&IPNet{IP: IPv4(192, 168, 1, 0), Mask: CIDRMask(26, 32)}, "192.168.1.0/26"},
- {&IPNet{IP: IPv4(192, 168, 1, 1), Mask: CIDRMask(26, 32)}, "192.168.1.1/26"},
{&IPNet{IP: IPv4(192, 168, 1, 0), Mask: IPv4Mask(255, 0, 255, 0)}, "192.168.1.0/ff00ff00"},
- {&IPNet{IP: ParseIP("fe80::"), Mask: CIDRMask(64, 128), Zone: "en0"}, "fe80::%en0/64"},
- {&IPNet{IP: ParseIP("fe80::1"), Mask: CIDRMask(64, 128), Zone: "en0"}, "fe80::1%en0/64"},
- {&IPNet{IP: ParseIP("fe80::"), Mask: IPMask(ParseIP("8000:f123:0:cafe::")), Zone: "en0"}, "fe80::%en0/8000f1230000cafe0000000000000000"},
{&IPNet{IP: ParseIP("2001:db8::"), Mask: CIDRMask(55, 128)}, "2001:db8::/55"},
- {&IPNet{IP: ParseIP("2001:db8::1"), Mask: CIDRMask(55, 128)}, "2001:db8::1/55"},
{&IPNet{IP: ParseIP("2001:db8::"), Mask: IPMask(ParseIP("8000:f123:0:cafe::"))}, "2001:db8::/8000f1230000cafe0000000000000000"},
}
import (
"context"
"errors"
+ "io"
"os"
)
}
defer file.Close()
- _, err = file.Seek(0, 0)
+ _, err = file.Seek(0, io.SeekStart)
if err != nil {
return
}
if err != nil {
return
}
- _, err = file.Seek(0, 0)
+ _, err = file.Seek(0, io.SeekStart)
if err != nil {
return
}
for _, tt := range lookupGoogleSRVTests {
cname, srvs, err := LookupSRV(tt.service, tt.proto, tt.name)
if err != nil {
+ testenv.SkipFlakyNet(t)
t.Fatal(err)
}
if len(srvs) == 0 {
for _, tt := range lookupGmailNSTests {
nss, err := LookupNS(tt.name)
if err != nil {
+ testenv.SkipFlakyNet(t)
t.Fatal(err)
}
if len(nss) == 0 {
}
}
-func TestLookupIPDeadline(t *testing.T) {
+func TestDNSFlood(t *testing.T) {
if !*testDNSFlood {
t.Skip("test disabled; use -dnsflood to enable")
}
- const N = 5000
+ var N = 5000
+ if runtime.GOOS == "darwin" {
+ // On Darwin this test consumes kernel threads much
+ // than other platforms for some reason.
+ // When we monitor the number of allocated Ms by
+ // observing on runtime.newm calls, we can see that it
+ // easily reaches the per process ceiling
+ // kern.num_threads when CGO_ENABLED=1 and
+ // GODEBUG=netdns=go.
+ N = 500
+ }
+
const timeout = 3 * time.Second
ctxHalfTimeout, cancel := context.WithTimeout(context.Background(), timeout/2)
defer cancel()
func testDots(t *testing.T, mode string) {
names, err := LookupAddr("8.8.8.8") // Google dns server
if err != nil {
+ testenv.SkipFlakyNet(t)
t.Errorf("LookupAddr(8.8.8.8): %v (mode=%v)", err, mode)
} else {
for _, name := range names {
}
cname, err := LookupCNAME("www.mit.edu")
- if err != nil || !strings.HasSuffix(cname, ".") {
- t.Errorf("LookupCNAME(www.mit.edu) = %v, %v, want cname ending in . with trailing dot (mode=%v)", cname, err, mode)
+ if err != nil {
+ testenv.SkipFlakyNet(t)
+ t.Errorf("LookupCNAME(www.mit.edu, mode=%v): %v", mode, err)
+ } else if !strings.HasSuffix(cname, ".") {
+ t.Errorf("LookupCNAME(www.mit.edu) = %v, want cname ending in . with trailing dot (mode=%v)", cname, mode)
}
mxs, err := LookupMX("google.com")
if err != nil {
+ testenv.SkipFlakyNet(t)
t.Errorf("LookupMX(google.com): %v (mode=%v)", err, mode)
} else {
for _, mx := range mxs {
nss, err := LookupNS("google.com")
if err != nil {
+ testenv.SkipFlakyNet(t)
t.Errorf("LookupNS(google.com): %v (mode=%v)", err, mode)
} else {
for _, ns := range nss {
cname, srvs, err := LookupSRV("xmpp-server", "tcp", "google.com")
if err != nil {
+ testenv.SkipFlakyNet(t)
t.Errorf("LookupSRV(xmpp-server, tcp, google.com): %v (mode=%v)", err, mode)
} else {
if !strings.HasSuffix(cname, ".google.com.") {
return buf.String()
}
-var lookupPortTests = []struct {
- network string
- name string
- port int
- ok bool
-}{
- {"tcp", "0", 0, true},
- {"tcp", "echo", 7, true},
- {"tcp", "discard", 9, true},
- {"tcp", "systat", 11, true},
- {"tcp", "daytime", 13, true},
- {"tcp", "chargen", 19, true},
- {"tcp", "ftp-data", 20, true},
- {"tcp", "ftp", 21, true},
- {"tcp", "telnet", 23, true},
- {"tcp", "smtp", 25, true},
- {"tcp", "time", 37, true},
- {"tcp", "domain", 53, true},
- {"tcp", "finger", 79, true},
- {"tcp", "42", 42, true},
-
- {"udp", "0", 0, true},
- {"udp", "echo", 7, true},
- {"udp", "tftp", 69, true},
- {"udp", "bootpc", 68, true},
- {"udp", "bootps", 67, true},
- {"udp", "domain", 53, true},
- {"udp", "ntp", 123, true},
- {"udp", "snmp", 161, true},
- {"udp", "syslog", 514, true},
- {"udp", "42", 42, true},
-
- {"--badnet--", "zzz", 0, false},
- {"tcp", "--badport--", 0, false},
- {"tcp", "-1", 0, false},
- {"tcp", "65536", 0, false},
- {"udp", "-1", 0, false},
- {"udp", "65536", 0, false},
- {"tcp", "123456789", 0, false},
-
- // Issue 13610: LookupPort("tcp", "")
- {"tcp", "", 0, true},
- {"tcp6", "", 0, true},
- {"tcp4", "", 0, true},
- {"udp", "", 0, true},
-}
-
func TestLookupPort(t *testing.T) {
+ // See http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml
+ //
+ // Please be careful about adding new mappings for testings.
+ // There are platforms having incomplete mappings for
+ // restricted resource access and security reasons.
+ type test struct {
+ network string
+ name string
+ port int
+ ok bool
+ }
+ var tests = []test{
+ {"tcp", "0", 0, true},
+ {"udp", "0", 0, true},
+ {"udp", "domain", 53, true},
+
+ {"--badnet--", "zzz", 0, false},
+ {"tcp", "--badport--", 0, false},
+ {"tcp", "-1", 0, false},
+ {"tcp", "65536", 0, false},
+ {"udp", "-1", 0, false},
+ {"udp", "65536", 0, false},
+ {"tcp", "123456789", 0, false},
+
+ // Issue 13610: LookupPort("tcp", "")
+ {"tcp", "", 0, true},
+ {"tcp4", "", 0, true},
+ {"tcp6", "", 0, true},
+ {"udp", "", 0, true},
+ {"udp4", "", 0, true},
+ {"udp6", "", 0, true},
+ }
+
switch runtime.GOOS {
case "nacl":
t.Skipf("not supported on %s", runtime.GOOS)
if netGo {
t.Skipf("not supported on %s without cgo; see golang.org/issues/14576", runtime.GOOS)
}
+ default:
+ tests = append(tests, test{"tcp", "http", 80, true})
}
- for _, tt := range lookupPortTests {
- if port, err := LookupPort(tt.network, tt.name); port != tt.port || (err == nil) != tt.ok {
+ for _, tt := range tests {
+ port, err := LookupPort(tt.network, tt.name)
+ if port != tt.port || (err == nil) != tt.ok {
t.Errorf("LookupPort(%q, %q) = %d, %v; want %d, error=%t", tt.network, tt.name, port, err, tt.port, !tt.ok)
}
+ if err != nil {
+ if perr := parseLookupPortError(err); perr != nil {
+ t.Error(perr)
+ }
+ }
}
}
func lookupHost(ctx context.Context, host string) (addrs []string, err error) {
order := systemConf().hostLookupOrder(host)
if order == hostLookupCgo {
- if addrs, err, ok := cgoLookupHost(host); ok {
+ if addrs, err, ok := cgoLookupHost(ctx, host); ok {
return addrs, err
}
// cgo not available (or netgo); fall back to Go's DNS resolver
func lookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) {
order := systemConf().hostLookupOrder(host)
if order == hostLookupCgo {
- // TODO(bradfitz): push down ctx, or at least its deadline to start
- if addrs, err, ok := cgoLookupIP(host); ok {
+ if addrs, err, ok := cgoLookupIP(ctx, host); ok {
return addrs, err
}
// cgo not available (or netgo); fall back to Go's DNS resolver
// files might be on a remote filesystem, though. This should
// probably race goroutines if ctx != context.Background().
if systemConf().canUseCgo() {
- if port, err, ok := cgoLookupPort(network, service); ok {
+ if port, err, ok := cgoLookupPort(ctx, network, service); ok {
return port, err
}
}
func lookupCNAME(ctx context.Context, name string) (string, error) {
if systemConf().canUseCgo() {
- // TODO: use ctx. issue 15321. Or race goroutines.
- if cname, err, ok := cgoLookupCNAME(name); ok {
+ if cname, err, ok := cgoLookupCNAME(ctx, name); ok {
return cname, err
}
}
func lookupAddr(ctx context.Context, addr string) ([]string, error) {
if systemConf().canUseCgo() {
- if ptrs, err, ok := cgoLookupPTR(addr); ok {
+ if ptrs, err, ok := cgoLookupPTR(ctx, addr); ok {
return ptrs, err
}
}
return nil
}
-func newDualStackServer(lns []streamListener) (*dualStackServer, error) {
- dss := &dualStackServer{lns: lns, port: "0"}
- for i := range dss.lns {
- ln, err := Listen(dss.lns[i].network, JoinHostPort(dss.lns[i].address, dss.port))
- if err != nil {
- for _, ln := range dss.lns[:i] {
- ln.Listener.Close()
- }
- return nil, err
- }
- dss.lns[i].Listener = ln
- dss.lns[i].done = make(chan bool)
- if dss.port == "0" {
- if _, dss.port, err = SplitHostPort(ln.Addr().String()); err != nil {
- for _, ln := range dss.lns {
- ln.Listener.Close()
- }
- return nil, err
- }
- }
+func newDualStackServer() (*dualStackServer, error) {
+ lns, err := newDualStackListener()
+ if err != nil {
+ return nil, err
+ }
+ _, port, err := SplitHostPort(lns[0].Addr().String())
+ if err != nil {
+ lns[0].Close()
+ lns[1].Close()
+ return nil, err
}
- return dss, nil
+ return &dualStackServer{
+ lns: []streamListener{
+ {network: "tcp4", address: lns[0].Addr().String(), Listener: lns[0], done: make(chan bool)},
+ {network: "tcp6", address: lns[1].Addr().String(), Listener: lns[1], done: make(chan bool)},
+ },
+ port: port,
+ }, nil
}
func transponder(ln Listener, ch chan<- error) {
defer c.Close()
network := ln.Addr().Network()
- if c.LocalAddr().Network() != network || c.LocalAddr().Network() != network {
+ if c.LocalAddr().Network() != network || c.RemoteAddr().Network() != network {
ch <- fmt.Errorf("got %v->%v; expected %v->%v", c.LocalAddr().Network(), c.RemoteAddr().Network(), network, network)
return
}
The Dial function connects to a server:
- conn, err := net.Dial("tcp", "google.com:80")
+ conn, err := net.Dial("tcp", "golang.org:80")
if err != nil {
// handle error
}
t.Error(err)
}
}
+
+func TestZeroByteRead(t *testing.T) {
+ for _, network := range []string{"tcp", "unix", "unixpacket"} {
+ if !testableNetwork(network) {
+ t.Logf("skipping %s test", network)
+ continue
+ }
+
+ ln, err := newLocalListener(network)
+ if err != nil {
+ t.Fatal(err)
+ }
+ connc := make(chan Conn, 1)
+ go func() {
+ defer ln.Close()
+ c, err := ln.Accept()
+ if err != nil {
+ t.Error(err)
+ }
+ connc <- c // might be nil
+ }()
+ c, err := Dial(network, ln.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer c.Close()
+ sc := <-connc
+ if sc == nil {
+ continue
+ }
+ defer sc.Close()
+
+ if runtime.GOOS == "windows" {
+ // A zero byte read on Windows caused a wait for readability first.
+ // Rather than change that behavior, satisfy it in this test.
+ // See Issue 15735.
+ go io.WriteString(sc, "a")
+ }
+
+ n, err := c.Read(nil)
+ if n != 0 || err != nil {
+ t.Errorf("%s: zero byte client read = %v, %v; want 0, nil", network, n, err)
+ }
+
+ if runtime.GOOS == "windows" {
+ // Same as comment above.
+ go io.WriteString(c, "a")
+ }
+ n, err = sc.Read(nil)
+ if n != 0 || err != nil {
+ t.Errorf("%s: zero byte server read = %v, %v; want 0, nil", network, n, err)
+ }
+ }
+}
func TestGoLookupIP(t *testing.T) {
host := "localhost"
- _, err, ok := cgoLookupIP(host)
+ ctx := context.Background()
+ _, err, ok := cgoLookupIP(ctx, host)
if ok {
t.Errorf("cgoLookupIP must be a placeholder")
}
if err != nil {
t.Error(err)
}
- if _, err := goLookupIP(context.Background(), host); err != nil {
+ if _, err := goLookupIP(ctx, host); err != nil {
t.Error(err)
}
}
for i, tt := range dialTimeoutMaxDurationTests {
ch := make(chan error)
- max := time.NewTimer(100 * time.Millisecond)
+ max := time.NewTimer(250 * time.Millisecond)
defer max.Stop()
go func() {
d := Dialer{Timeout: tt.timeout}
// license that can be found in the LICENSE file.
// Package url parses URLs and implements query escaping.
-// See RFC 3986.
package url
+// See RFC 3986. This package generally follows RFC 3986, except where
+// it deviates for compatibility reasons. When sending changes, first
+// search old issues for history on decisions. Unit tests should also
+// contain references to issue numbers with details.
+
import (
"bytes"
"errors"
}
return host1 + host2 + host3, nil
}
- } else if i := strings.LastIndex(host, ":"); i > 0 {
- colonPort := host[i:]
- if !validOptionalPort(colonPort) {
- return "", fmt.Errorf("invalid port %q after host", colonPort)
- }
}
+
var err error
if host, err = unescape(host, encodeHost); err != nil {
return "", err
},
// worst case host, still round trips
{
- "scheme://!$&'()*+,;=hello!:8080/path",
+ "scheme://!$&'()*+,;=hello!:port/path",
&URL{
Scheme: "scheme",
- Host: "!$&'()*+,;=hello!:8080",
+ Host: "!$&'()*+,;=hello!:port",
Path: "/path",
},
"",
{"*", true},
{"http://192.168.0.1/", true},
{"http://192.168.0.1:8080/", true},
- {"http://192.168.0.1:foo/", false},
{"http://[fe80::1]/", true},
{"http://[fe80::1]:8080/", true},
- {"http://[fe80::1]:foo/", false},
// Tests exercising RFC 6874 compliance:
{"http://[fe80::1%25en0]/", true}, // with alphanum zone identifier
// available after a call to Wait or Run.
ProcessState *os.ProcessState
- lookPathErr error // LookPath error, if any.
- finished bool // when Wait was called
+ ctx context.Context // nil means none
+ lookPathErr error // LookPath error, if any.
+ finished bool // when Wait was called
childFiles []*os.File
closeAfterStart []io.Closer
closeAfterWait []io.Closer
return cmd
}
+// CommandContext is like Command but includes a context.
+//
+// The provided context is used to kill the process (by calling
+// os.Process.Kill) if the context becomes done before the command
+// completes on its own.
+func CommandContext(ctx context.Context, name string, arg ...string) *Cmd {
+ if ctx == nil {
+ panic("nil Context")
+ }
+ cmd := Command(name, arg...)
+ cmd.ctx = ctx
+ return cmd
+}
+
// interfaceEqual protects against panics from doing equality tests on
// two interfaces with non-comparable underlying types.
func interfaceEqual(a, b interface{}) bool {
return c.Wait()
}
-// RunContext is like Run, but kills the process (by calling os.Process.Kill)
-// if ctx is done before the process ends on its own.
-func (c *Cmd) RunContext(ctx context.Context) error {
- if err := c.Start(); err != nil {
- return err
- }
- return c.WaitContext(ctx)
-}
-
// lookExtensions finds windows executable by its dir and path.
// It uses LookPath to try appropriate extensions.
// lookExtensions does not search PATH, instead it converts `prog` into `.\prog`.
//
// Wait releases any resources associated with the Cmd.
func (c *Cmd) Wait() error {
- return c.WaitContext(nil)
-}
-
-// WaitContext is like Wait, but kills the process (by calling os.Process.Kill)
-// if ctx is done before the process ends on its own.
-func (c *Cmd) WaitContext(ctx context.Context) error {
if c.Process == nil {
return errors.New("exec: not started")
}
c.finished = true
var waitDone chan struct{}
- if ctx != nil {
+ if c.ctx != nil {
waitDone = make(chan struct{})
go func() {
select {
- case <-ctx.Done():
+ case <-c.ctx.Done():
c.Process.Kill()
case <-waitDone:
}
"time"
)
-func helperCommand(t *testing.T, s ...string) *exec.Cmd {
+func helperCommandContext(t *testing.T, ctx context.Context, s ...string) (cmd *exec.Cmd) {
testenv.MustHaveExec(t)
cs := []string{"-test.run=TestHelperProcess", "--"}
cs = append(cs, s...)
- cmd := exec.Command(os.Args[0], cs...)
+ if ctx != nil {
+ cmd = exec.CommandContext(ctx, os.Args[0], cs...)
+ } else {
+ cmd = exec.Command(os.Args[0], cs...)
+ }
cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
return cmd
}
+func helperCommand(t *testing.T, s ...string) *exec.Cmd {
+ return helperCommandContext(t, nil, s...)
+}
+
func TestEcho(t *testing.T) {
bs, err := helperCommand(t, "echo", "foo bar", "baz").Output()
if err != nil {
// the cloned file descriptors that result from opening
// /dev/urandom.
// https://golang.org/issue/3955
- case "plan9":
- // TODO(0intro): Determine why Plan 9 is leaking
- // file descriptors.
- // https://golang.org/issue/7118
case "solaris":
// TODO(aram): This fails on Solaris because libc opens
// its own files, as it sees fit. Darwin does the same,
}
func TestContext(t *testing.T) {
- c := helperCommand(t, "pipetest")
+ ctx, cancel := context.WithCancel(context.Background())
+ c := helperCommandContext(t, ctx, "pipetest")
stdin, err := c.StdinPipe()
if err != nil {
t.Fatal(err)
if err != nil {
t.Fatal(err)
}
- ctx, cancel := context.WithCancel(context.Background())
if err := c.Start(); err != nil {
t.Fatal(err)
}
}
waitErr := make(chan error, 1)
go func() {
- waitErr <- c.WaitContext(ctx)
+ waitErr <- c.Wait()
}()
cancel()
select {
import (
"errors"
"os"
+ "path/filepath"
"strings"
)
}
path := os.Getenv("path")
- for _, dir := range strings.Split(path, "\000") {
- if err := findExecutable(dir + "/" + file); err == nil {
- return dir + "/" + file, nil
+ for _, dir := range filepath.SplitList(path) {
+ path := filepath.Join(dir, file)
+ if err := findExecutable(path); err == nil {
+ return path, nil
}
}
return "", &Error{file, ErrNotFound}
import (
"errors"
"os"
+ "path/filepath"
"strings"
)
}
return "", &Error{file, err}
}
- pathenv := os.Getenv("PATH")
- if pathenv == "" {
- return "", &Error{file, ErrNotFound}
- }
- for _, dir := range strings.Split(pathenv, ":") {
+ path := os.Getenv("PATH")
+ for _, dir := range filepath.SplitList(path) {
if dir == "" {
// Unix shell semantics: path element "" means "."
dir = "."
}
- path := dir + "/" + file
+ path := filepath.Join(dir, file)
if err := findExecutable(path); err == nil {
return path, nil
}
import (
"errors"
"os"
+ "path/filepath"
"strings"
)
// a suitable candidate.
// The result may be an absolute path or a path relative to the current directory.
func LookPath(file string) (string, error) {
+ var exts []string
x := os.Getenv(`PATHEXT`)
- if x == "" {
- x = `.COM;.EXE;.BAT;.CMD`
- }
- exts := []string{}
- for _, e := range strings.Split(strings.ToLower(x), `;`) {
- if e == "" {
- continue
- }
- if e[0] != '.' {
- e = "." + e
+ if x != "" {
+ for _, e := range strings.Split(strings.ToLower(x), `;`) {
+ if e == "" {
+ continue
+ }
+ if e[0] != '.' {
+ e = "." + e
+ }
+ exts = append(exts, e)
}
- exts = append(exts, e)
+ } else {
+ exts = []string{".com", ".exe", ".bat", ".cmd"}
}
+
if strings.ContainsAny(file, `:\/`) {
if f, err := findExecutable(file, exts); err == nil {
return f, nil
return "", &Error{file, err}
}
}
- if f, err := findExecutable(`.\`+file, exts); err == nil {
+ if f, err := findExecutable(filepath.Join(".", file), exts); err == nil {
return f, nil
}
- if pathenv := os.Getenv(`PATH`); pathenv != "" {
- for _, dir := range splitList(pathenv) {
- if f, err := findExecutable(dir+`\`+file, exts); err == nil {
- return f, nil
- }
+ path := os.Getenv("path")
+ for _, dir := range filepath.SplitList(path) {
+ if f, err := findExecutable(filepath.Join(dir, file), exts); err == nil {
+ return f, nil
}
}
return "", &Error{file, ErrNotFound}
}
-
-func splitList(path string) []string {
- // The same implementation is used in SplitList in path/filepath;
- // consider changing path/filepath when changing this.
-
- if path == "" {
- return []string{}
- }
-
- // Split path, respecting but preserving quotes.
- list := []string{}
- start := 0
- quo := false
- for i := 0; i < len(path); i++ {
- switch c := path[i]; {
- case c == '"':
- quo = !quo
- case c == os.PathListSeparator && !quo:
- list = append(list, path[start:i])
- start = i + 1
- }
- }
- list = append(list, path[start:])
-
- // Remove quotes.
- for i, s := range list {
- if strings.Contains(s, `"`) {
- list[i] = strings.Replace(s, `"`, "", -1)
- }
- }
-
- return list
-}
env := os.Environ()
env = updateEnv(env, "PATHEXT", PATHEXT)
// Add dir in front of every directory in the PATH.
- dirs := splitList(PATH)
+ dirs := filepath.SplitList(PATH)
for i := range dirs {
dirs[i] = filepath.Join(dir, dirs[i])
}
package os
import (
+ "io"
"runtime"
"syscall"
"time"
}
if append {
- if _, e = syscall.Seek(fd, 0, SEEK_END); e != nil {
+ if _, e = syscall.Seek(fd, 0, io.SeekEnd); e != nil {
return nil, &PathError{"seek", name, e}
}
}
return ErrInvalid
}
var err error
- syscall.ForkLock.RLock()
if e := syscall.Close(file.fd); e != nil {
err = &PathError{"close", file.name, e}
}
- syscall.ForkLock.RUnlock()
file.fd = -1 // so it can't be closed again
// no need for a finalizer anymore
func Pipe() (r *File, w *File, err error) {
var p [2]int
- syscall.ForkLock.RLock()
if e := syscall.Pipe(p[0:]); e != nil {
- syscall.ForkLock.RUnlock()
return nil, nil, NewSyscallError("pipe", e)
}
- syscall.ForkLock.RUnlock()
return NewFile(uintptr(p[0]), "|0"), NewFile(uintptr(p[1]), "|1"), nil
}
func (f *File) pread(b []byte, off int64) (n int, err error) {
f.l.Lock()
defer f.l.Unlock()
- curoffset, e := syscall.Seek(f.fd, 0, 1)
+ curoffset, e := syscall.Seek(f.fd, 0, io.SeekCurrent)
if e != nil {
return 0, e
}
- defer syscall.Seek(f.fd, curoffset, 0)
+ defer syscall.Seek(f.fd, curoffset, io.SeekStart)
o := syscall.Overlapped{
OffsetHigh: uint32(off >> 32),
Offset: uint32(off),
func (f *File) pwrite(b []byte, off int64) (n int, err error) {
f.l.Lock()
defer f.l.Unlock()
- curoffset, e := syscall.Seek(f.fd, 0, 1)
+ curoffset, e := syscall.Seek(f.fd, 0, io.SeekCurrent)
if e != nil {
return 0, e
}
- defer syscall.Seek(f.fd, curoffset, 0)
+ defer syscall.Seek(f.fd, curoffset, io.SeekStart)
o := syscall.Overlapped{
OffsetHigh: uint32(off >> 32),
Offset: uint32(off),
} else {
if a&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
e = e1
+ } else if a&syscall.FILE_ATTRIBUTE_READONLY != 0 {
+ if e1 = syscall.SetFileAttributes(p, a&^syscall.FILE_ATTRIBUTE_READONLY); e1 == nil {
+ if e = syscall.DeleteFile(p); e == nil {
+ return nil
+ }
+ }
}
}
}
out int64
}
var tests = []test{
- {0, 1, int64(len(data))},
- {0, 0, 0},
- {5, 0, 5},
- {0, 2, int64(len(data))},
- {0, 0, 0},
- {-1, 2, int64(len(data)) - 1},
- {1 << 33, 0, 1 << 33},
- {1 << 33, 2, 1<<33 + int64(len(data))},
+ {0, io.SeekCurrent, int64(len(data))},
+ {0, io.SeekStart, 0},
+ {5, io.SeekStart, 5},
+ {0, io.SeekEnd, int64(len(data))},
+ {0, io.SeekStart, 0},
+ {-1, io.SeekEnd, int64(len(data)) - 1},
+ {1 << 33, io.SeekStart, 1 << 33},
+ {1 << 33, io.SeekEnd, 1<<33 + int64(len(data))},
}
for i, tt := range tests {
off, err := f.Seek(tt.in, tt.whence)
}
}
+// Verify that ReadAt doesn't affect seek offset.
+// In the Plan 9 kernel, there used to be a bug in the implementation of
+// the pread syscall, where the channel offset was erroneously updated after
+// calling pread on a file.
+func TestReadAtOffset(t *testing.T) {
+ f := newFile("TestReadAtOffset", t)
+ defer Remove(f.Name())
+ defer f.Close()
+
+ const data = "hello, world\n"
+ io.WriteString(f, data)
+
+ f.Seek(0, 0)
+ b := make([]byte, 5)
+
+ n, err := f.ReadAt(b, 7)
+ if err != nil || n != len(b) {
+ t.Fatalf("ReadAt 7: %d, %v", n, err)
+ }
+ if string(b) != "world" {
+ t.Fatalf("ReadAt 7: have %q want %q", string(b), "world")
+ }
+
+ n, err = f.Read(b)
+ if err != nil || n != len(b) {
+ t.Fatalf("Read: %d, %v", n, err)
+ }
+ if string(b) != "hello" {
+ t.Fatalf("Read: have %q want %q", string(b), "hello")
+ }
+}
+
func TestWriteAt(t *testing.T) {
f := newFile("TestWriteAt", t)
defer Remove(f.Name())
{"ReadAt", func(f *File) error { _, err := f.ReadAt(make([]byte, 0), 0); return err }},
{"Readdir", func(f *File) error { _, err := f.Readdir(1); return err }},
{"Readdirnames", func(f *File) error { _, err := f.Readdirnames(1); return err }},
- {"Seek", func(f *File) error { _, err := f.Seek(0, 0); return err }},
+ {"Seek", func(f *File) error { _, err := f.Seek(0, io.SeekStart); return err }},
{"Stat", func(f *File) error { _, err := f.Stat(); return err }},
{"Sync", func(f *File) error { return f.Sync() }},
{"Truncate", func(f *File) error { return f.Truncate(0) }},
linkname := f.Name() + "2"
if err := Symlink(f.Name(), linkname); err != nil {
+ if runtime.GOOS == "android" && IsPermission(err) {
+ t.Skip("skipping test on Android; permission error creating symlink")
+ }
t.Fatalf("link %s -> %s: %v", f.Name(), linkname, err)
}
defer Remove(linkname)
t.Fatalf("unexpected file list %q, want %q", have, want)
}
}
+
+func TestDeleteReadOnly(t *testing.T) {
+ tmpdir, err := ioutil.TempDir("", "TestDeleteReadOnly")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpdir)
+ p := filepath.Join(tmpdir, "a")
+ // This sets FILE_ATTRIBUTE_READONLY.
+ f, err := os.OpenFile(p, os.O_CREATE, 0400)
+ if err != nil {
+ t.Fatal(err)
+ }
+ f.Close()
+
+ if err = os.Chmod(p, 0400); err != nil {
+ t.Fatal(err)
+ }
+ if err = os.Remove(p); err != nil {
+ t.Fatal(err)
+ }
+}
Windows
On Windows a ^C (Control-C) or ^BREAK (Control-Break) normally cause
-the program to exit. If Notify is called for os.SIGINT, ^C or ^BREAK
-will cause os.SIGINT to be sent on the channel, and the program will
+the program to exit. If Notify is called for os.Interrupt, ^C or ^BREAK
+will cause os.Interrupt to be sent on the channel, and the program will
not exit. If Reset is called, or Stop is called on all channels passed
to Notify, then the default behavior will be restored.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build cgo
+package user
+/*
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
-int mygetgrouplist(const char* user, gid_t group, gid_t* groups, int* ngroups) {
+static int mygetgrouplist(const char* user, gid_t group, gid_t* groups, int* ngroups) {
int* buf = malloc(*ngroups * sizeof(int));
int rv = getgrouplist(user, (int) group, buf, ngroups);
int i;
free(buf);
return rv;
}
+*/
+import "C"
+
+func getGroupList(name *C.char, userGID C.gid_t, gids *C.gid_t, n *C.int) C.int {
+ return C.mygetgrouplist(name, userGID, gids, n)
+}
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build cgo
// +build dragonfly freebsd !android,linux netbsd openbsd
+package user
+
+/*
#include <unistd.h>
#include <sys/types.h>
#include <grp.h>
-int mygetgrouplist(const char* user, gid_t group, gid_t* groups, int* ngroups) {
+static int mygetgrouplist(const char* user, gid_t group, gid_t* groups, int* ngroups) {
return getgrouplist(user, group, groups, ngroups);
}
+*/
+import "C"
+
+func getGroupList(name *C.char, userGID C.gid_t, gids *C.gid_t, n *C.int) C.int {
+ return C.mygetgrouplist(name, userGID, gids, n)
+}
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
-
-extern int mygetgrouplist(const char* user, gid_t group, gid_t* groups, int* ngroups);
*/
import "C"
n := C.int(256)
gidsC := make([]C.gid_t, n)
- rv := C.mygetgrouplist(nameC, userGID, &gidsC[0], &n)
+ rv := getGroupList(nameC, userGID, &gidsC[0], &n)
if rv == -1 {
// More than initial buffer, but now n contains the correct size.
const maxGroups = 2048
return nil, fmt.Errorf("user: list groups for %s: member of more than %d groups", u.Username, maxGroups)
}
gidsC = make([]C.gid_t, n)
- rv := C.mygetgrouplist(nameC, userGID, &gidsC[0], &n)
+ rv := getGroupList(nameC, userGID, &gidsC[0], &n)
if rv == -1 {
return nil, fmt.Errorf("user: list groups for %s failed (changed groups?)", u.Username)
}
}
dir, file := Split(pattern)
- switch dir {
- case "":
- dir = "."
- case string(Separator):
- // nothing
- default:
- dir = dir[0 : len(dir)-1] // chop off trailing separator
+ if runtime.GOOS == "windows" {
+ dir = cleanGlobPathWindows(dir)
+ } else {
+ dir = cleanGlobPath(dir)
}
if !hasMeta(dir) {
return
}
+// cleanGlobPath prepares path for glob matching.
+func cleanGlobPath(path string) string {
+ switch path {
+ case "":
+ return "."
+ case string(Separator):
+ // do nothing to the path
+ return path
+ default:
+ return path[0 : len(path)-1] // chop off trailing separator
+ }
+}
+
+// cleanGlobPathWindows is windows version of cleanGlobPath.
+func cleanGlobPathWindows(path string) string {
+ vollen := volumeNameLen(path)
+ switch {
+ case path == "":
+ return "."
+ case vollen+1 == len(path) && os.IsPathSeparator(path[len(path)-1]): // /, \, C:\ and C:/
+ // do nothing to the path
+ return path
+ case vollen == len(path) && len(path) == 2: // C:
+ return path + "." // convert C: into C:.
+ default:
+ return path[0 : len(path)-1] // chop off trailing separator
+ }
+}
+
// glob searches for files matching pattern in the directory dir
// and appends them to matches. If the directory cannot be
// opened, it returns the existing matches. New matches are
package filepath_test
import (
+ "fmt"
"io/ioutil"
"os"
. "path/filepath"
"runtime"
+ "sort"
"strings"
"testing"
)
}
}
}
+
+type globTest struct {
+ pattern string
+ matches []string
+}
+
+func (test *globTest) buildWant(root string) []string {
+ want := make([]string, 0)
+ for _, m := range test.matches {
+ want = append(want, root+FromSlash(m))
+ }
+ sort.Strings(want)
+ return want
+}
+
+func (test *globTest) globAbs(root, rootPattern string) error {
+ p := FromSlash(rootPattern + `\` + test.pattern)
+ have, err := Glob(p)
+ if err != nil {
+ return err
+ }
+ sort.Strings(have)
+ want := test.buildWant(root + `\`)
+ if strings.Join(want, "_") == strings.Join(have, "_") {
+ return nil
+ }
+ return fmt.Errorf("Glob(%q) returns %q, but %q expected", p, have, want)
+}
+
+func (test *globTest) globRel(root string) error {
+ p := root + FromSlash(test.pattern)
+ have, err := Glob(p)
+ if err != nil {
+ return err
+ }
+ sort.Strings(have)
+ want := test.buildWant(root)
+ if strings.Join(want, "_") == strings.Join(have, "_") {
+ return nil
+ }
+ // try also matching version without root prefix
+ wantWithNoRoot := test.buildWant("")
+ if strings.Join(wantWithNoRoot, "_") == strings.Join(have, "_") {
+ return nil
+ }
+ return fmt.Errorf("Glob(%q) returns %q, but %q expected", p, have, want)
+}
+
+func TestWindowsGlob(t *testing.T) {
+ if runtime.GOOS != "windows" {
+ t.Skipf("skipping windows specific test")
+ }
+
+ tmpDir, err := ioutil.TempDir("", "TestWindowsGlob")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpDir)
+
+ // /tmp may itself be a symlink
+ tmpDir, err = EvalSymlinks(tmpDir)
+ if err != nil {
+ t.Fatal("eval symlink for tmp dir:", err)
+ }
+
+ if len(tmpDir) < 3 {
+ t.Fatalf("tmpDir path %q is too short", tmpDir)
+ }
+ if tmpDir[1] != ':' {
+ t.Fatalf("tmpDir path %q must have drive letter in it", tmpDir)
+ }
+
+ dirs := []string{
+ "a",
+ "b",
+ "dir/d/bin",
+ }
+ files := []string{
+ "dir/d/bin/git.exe",
+ }
+ for _, dir := range dirs {
+ err := os.MkdirAll(Join(tmpDir, dir), 0777)
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+ for _, file := range files {
+ err := ioutil.WriteFile(Join(tmpDir, file), nil, 0666)
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+
+ tests := []globTest{
+ {"a", []string{"a"}},
+ {"b", []string{"b"}},
+ {"c", []string{}},
+ {"*", []string{"a", "b", "dir"}},
+ {"d*", []string{"dir"}},
+ {"*i*", []string{"dir"}},
+ {"*r", []string{"dir"}},
+ {"?ir", []string{"dir"}},
+ {"?r", []string{}},
+ {"d*/*/bin/git.exe", []string{"dir/d/bin/git.exe"}},
+ }
+
+ // test absolute paths
+ for _, test := range tests {
+ var p string
+ err = test.globAbs(tmpDir, tmpDir)
+ if err != nil {
+ t.Error(err)
+ }
+ // test C:\*Documents and Settings\...
+ p = tmpDir
+ p = strings.Replace(p, `:\`, `:\*`, 1)
+ err = test.globAbs(tmpDir, p)
+ if err != nil {
+ t.Error(err)
+ }
+ // test C:\Documents and Settings*\...
+ p = tmpDir
+ p = strings.Replace(p, `:\`, `:`, 1)
+ p = strings.Replace(p, `\`, `*\`, 1)
+ p = strings.Replace(p, `:`, `:\`, 1)
+ err = test.globAbs(tmpDir, p)
+ if err != nil {
+ t.Error(err)
+ }
+ }
+
+ // test relative paths
+ wd, err := os.Getwd()
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = os.Chdir(tmpDir)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer func() {
+ err := os.Chdir(wd)
+ if err != nil {
+ t.Fatal(err)
+ }
+ }()
+ for _, test := range tests {
+ err := test.globRel("")
+ if err != nil {
+ t.Error(err)
+ }
+ err = test.globRel(`.\`)
+ if err != nil {
+ t.Error(err)
+ }
+ err = test.globRel(tmpDir[:2]) // C:
+ if err != nil {
+ t.Error(err)
+ }
+ }
+}
func (p *Tbigp) M(x int, b byte) (byte, int) { return b, x + int(p[0]) + int(p[1]) }
-// Again, with an unexported method.
-
-type tsmallv byte
-
-func (v tsmallv) m(x int, b byte) (byte, int) { return b, x + int(v) }
-
-type tsmallp byte
-
-func (p *tsmallp) m(x int, b byte) (byte, int) { return b, x + int(*p) }
-
-type twordv uintptr
-
-func (v twordv) m(x int, b byte) (byte, int) { return b, x + int(v) }
-
-type twordp uintptr
-
-func (p *twordp) m(x int, b byte) (byte, int) { return b, x + int(*p) }
-
-type tbigv [2]uintptr
-
-func (v tbigv) m(x int, b byte) (byte, int) { return b, x + int(v[0]) + int(v[1]) }
-
-type tbigp [2]uintptr
-
-func (p *tbigp) m(x int, b byte) (byte, int) { return b, x + int(p[0]) + int(p[1]) }
-
type tinter interface {
m(int, byte) (byte, int)
}
}
var TinterType = TypeOf(new(Tinter)).Elem()
- var tinterType = TypeOf(new(tinter)).Elem()
CheckI := func(name string, i interface{}, inc int) {
v := ValueOf(i)
CheckI("t1", t1, 40)
CheckI("&t1", &t1, 40)
- methodShouldPanic := func(name string, i interface{}) {
- v := ValueOf(i)
- m := v.Method(0)
- shouldPanic(func() { m.Call([]Value{ValueOf(1000), ValueOf(byte(99))}) })
- shouldPanic(func() { m.Interface() })
-
- v = v.Convert(tinterType)
- m = v.Method(0)
- shouldPanic(func() { m.Call([]Value{ValueOf(1000), ValueOf(byte(99))}) })
- shouldPanic(func() { m.Interface() })
- }
-
- _sv := tsmallv(1)
- methodShouldPanic("_sv", _sv)
- methodShouldPanic("&_sv", &_sv)
-
- _sp := tsmallp(2)
- methodShouldPanic("&_sp", &_sp)
-
- _wv := twordv(3)
- methodShouldPanic("_wv", _wv)
- methodShouldPanic("&_wv", &_wv)
-
- _wp := twordp(4)
- methodShouldPanic("&_wp", &_wp)
-
- _bv := tbigv([2]uintptr{5, 6})
- methodShouldPanic("_bv", _bv)
- methodShouldPanic("&_bv", &_bv)
-
- _bp := tbigp([2]uintptr{7, 8})
- methodShouldPanic("&_bp", &_bp)
-
var tnil Tinter
vnil := ValueOf(&tnil).Elem()
shouldPanic(func() { vnil.Method(0) })
inner
}
-func (*inner) m() {}
-func (*outer) m() {}
+func (*inner) M() {}
+func (*outer) M() {}
func TestNestedMethods(t *testing.T) {
typ := TypeOf((*outer)(nil))
- if typ.NumMethod() != 1 || typ.Method(0).Func.Pointer() != ValueOf((*outer).m).Pointer() {
- t.Errorf("Wrong method table for outer: (m=%p)", (*outer).m)
+ if typ.NumMethod() != 1 || typ.Method(0).Func.Pointer() != ValueOf((*outer).M).Pointer() {
+ t.Errorf("Wrong method table for outer: (M=%p)", (*outer).M)
for i := 0; i < typ.NumMethod(); i++ {
m := typ.Method(i)
t.Errorf("\t%d: %s %#x\n", i, m.Name, m.Func.Pointer())
func TestUnexportedMethods(t *testing.T) {
typ := TypeOf(unexpi)
- if typ.Method(0).Type == nil {
- t.Error("missing type for satisfied method 'f'")
- }
- if !typ.Method(0).Func.IsValid() {
- t.Error("missing func for satisfied method 'f'")
- }
- if typ.Method(1).Type != nil {
- t.Error("found type for unsatisfied method 'g'")
- }
- if typ.Method(1).Func.IsValid() {
- t.Error("found func for unsatisfied method 'g'")
+ if got := typ.NumMethod(); got != 0 {
+ t.Errorf("NumMethod=%d, want 0 satisfied methods", got)
}
}
isValid(v.Elem().Field(1))
isValid(v.Elem().FieldByName("x"))
isValid(v.Elem().FieldByName("y"))
- isValid(v.Type().Method(0).Func)
shouldPanic(func() { v.Elem().Field(0).Interface() })
shouldPanic(func() { v.Elem().Field(1).Interface() })
shouldPanic(func() { v.Elem().FieldByName("x").Interface() })
shouldPanic(func() { v.Elem().FieldByName("y").Interface() })
- shouldPanic(func() { v.Type().Method(0).Func.Interface() })
+ shouldPanic(func() { v.Type().Method(0) })
}
func TestSetPanic(t *testing.T) {
}
exported := isExported(n)
if exported != test.exported {
- t.Errorf("test-%d: got exported=%v want exported=%v", exported, test.exported)
+ t.Errorf("test-%d: got exported=%v want exported=%v", i, exported, test.exported)
}
})
}
if table.impl {
t.Errorf("test-%d: type=%v fails to implement Iface.\n", i, table.typ)
} else {
- t.Errorf("test-%d: type=%v should NOT implement Iface\n", table.typ)
+ t.Errorf("test-%d: type=%v should NOT implement Iface\n", i, table.typ)
}
continue
}
if len(args) != 1 {
t.Errorf("args == %v, want exactly one arg", args)
} else if args[0].Type() != TypeOf(K("")) {
- t.Errorf("args[0] is type %v, want %v", args[0].Type, TypeOf(K("")))
+ t.Errorf("args[0] is type %v, want %v", args[0].Type(), TypeOf(K("")))
} else if args[0].String() != "gopher" {
t.Errorf("args[0] = %q, want %q", args[0].String(), "gopher")
}
if len(outs) != 1 {
t.Fatalf("v.Call returned %v, want exactly one result", outs)
} else if outs[0].Type() != TypeOf(V(0)) {
- t.Fatalf("c.Call[0] is type %v, want %v", outs[0].Type, TypeOf(V(0)))
+ t.Fatalf("c.Call[0] is type %v, want %v", outs[0].Type(), TypeOf(V(0)))
}
f := outs[0].Float()
if f != 3.14 {
type Impl struct{}
-func (Impl) f() {}
+func (Impl) F() {}
func TestValueString(t *testing.T) {
rv := ValueOf(Impl{})
fv.Call([]Value{ValueOf([256]*byte{})})
}
+func fieldIndexRecover(t Type, i int) (recovered interface{}) {
+ defer func() {
+ recovered = recover()
+ }()
+
+ t.Field(i)
+ return
+}
+
+// Issue 15046.
+func TestTypeFieldOutOfRangePanic(t *testing.T) {
+ typ := TypeOf(struct{ X int }{10})
+ testIndices := [...]struct {
+ i int
+ mustPanic bool
+ }{
+ 0: {-2, true},
+ 1: {0, false},
+ 2: {1, true},
+ 3: {1 << 10, true},
+ }
+ for i, tt := range testIndices {
+ recoveredErr := fieldIndexRecover(typ, tt.i)
+ if tt.mustPanic {
+ if recoveredErr == nil {
+ t.Errorf("#%d: fieldIndex %d expected to panic", i, tt.i)
+ }
+ } else {
+ if recoveredErr != nil {
+ t.Errorf("#%d: got err=%v, expected no panic", i, recoveredErr)
+ }
+ }
+ }
+}
+
// Issue 9179.
func TestCallGC(t *testing.T) {
f := func(a, b, c, d, e string) {
}
}
-func TestMethodPkgPathReadable(t *testing.T) {
- // Reading the Method type for an unexported method triggers an
- // offset resolution via p.name.pkgPath(). Make sure it uses a
- // valid base pointer for the offset.
- v := ValueOf(embed{})
- m := v.Type().Method(0)
- if m.PkgPath != "reflect" {
- t.Errorf(`PkgPath=%q, want "reflect"`, m.PkgPath)
+func TestTypeStrings(t *testing.T) {
+ type stringTest struct {
+ typ Type
+ want string
+ }
+ stringTests := []stringTest{
+ {TypeOf(func(int) {}), "func(int)"},
+ {FuncOf([]Type{TypeOf(int(0))}, nil, false), "func(int)"},
+ {TypeOf(XM{}), "reflect_test.XM"},
+ {TypeOf(new(XM)), "*reflect_test.XM"},
+ {TypeOf(new(XM).String), "func() string"},
+ {TypeOf(new(XM)).Method(0).Type, "func(*reflect_test.XM) string"},
+ }
+
+ for i, test := range stringTests {
+ if got, want := test.typ.String(), test.want; got != want {
+ t.Errorf("type %d String()=%q, want %q", i, got, want)
+ }
+ }
+}
+
+func TestOffsetLock(t *testing.T) {
+ var wg sync.WaitGroup
+ for i := 0; i < 4; i++ {
+ i := i
+ wg.Add(1)
+ go func() {
+ for j := 0; j < 50; j++ {
+ ResolveReflectName(fmt.Sprintf("OffsetLockName:%d:%d", i, j))
+ }
+ wg.Done()
+ }()
}
+ wg.Wait()
}
n := typ.nameOff(typ.str)
return n.isExported()
}
+
+func ResolveReflectName(s string) {
+ resolveReflectName(newName(s, "", "", false))
+}
func (t *rtype) common() *rtype { return t }
+var methodCache struct {
+ sync.RWMutex
+ m map[*rtype][]method
+}
+
+func (t *rtype) exportedMethods() []method {
+ methodCache.RLock()
+ methods, found := methodCache.m[t]
+ methodCache.RUnlock()
+
+ if found {
+ return methods
+ }
+
+ ut := t.uncommon()
+ if ut == nil {
+ return nil
+ }
+ allm := ut.methods()
+ allExported := true
+ for _, m := range allm {
+ name := t.nameOff(m.name)
+ if !name.isExported() {
+ allExported = false
+ break
+ }
+ }
+ if allExported {
+ methods = allm
+ } else {
+ methods = make([]method, 0, len(allm))
+ for _, m := range allm {
+ name := t.nameOff(m.name)
+ if name.isExported() {
+ methods = append(methods, m)
+ }
+ }
+ methods = methods[:len(methods):len(methods)]
+ }
+
+ methodCache.Lock()
+ if methodCache.m == nil {
+ methodCache.m = make(map[*rtype][]method)
+ }
+ methodCache.m[t] = methods
+ methodCache.Unlock()
+
+ return methods
+}
+
func (t *rtype) NumMethod() int {
if t.Kind() == Interface {
tt := (*interfaceType)(unsafe.Pointer(t))
return tt.NumMethod()
}
- ut := t.uncommon()
- if ut == nil {
- return 0
- }
- return int(ut.mcount)
+ return len(t.exportedMethods())
}
func (t *rtype) Method(i int) (m Method) {
tt := (*interfaceType)(unsafe.Pointer(t))
return tt.Method(i)
}
- ut := t.uncommon()
-
- if ut == nil || i < 0 || i >= int(ut.mcount) {
+ methods := t.exportedMethods()
+ if i < 0 || i >= len(methods) {
panic("reflect: Method index out of range")
}
- p := ut.methods()[i]
+ p := methods[i]
pname := t.nameOff(p.name)
m.Name = pname.name()
fl := flag(Func)
- if !pname.isExported() {
- m.PkgPath = pname.pkgPath()
- if m.PkgPath == "" {
- m.PkgPath = t.nameOff(ut.pkgPath).name()
- }
- fl |= flagStickyRO
- }
- if p.mtyp != 0 {
- mtyp := t.typeOff(p.mtyp)
- ft := (*funcType)(unsafe.Pointer(mtyp))
- in := make([]Type, 0, 1+len(ft.in()))
- in = append(in, t)
- for _, arg := range ft.in() {
- in = append(in, arg)
- }
- out := make([]Type, 0, len(ft.out()))
- for _, ret := range ft.out() {
- out = append(out, ret)
- }
- mt := FuncOf(in, out, ft.IsVariadic())
- m.Type = mt
- tfn := t.textOff(p.tfn)
- fn := unsafe.Pointer(&tfn)
- m.Func = Value{mt.(*rtype), fn, fl}
- }
+ mtyp := t.typeOff(p.mtyp)
+ ft := (*funcType)(unsafe.Pointer(mtyp))
+ in := make([]Type, 0, 1+len(ft.in()))
+ in = append(in, t)
+ for _, arg := range ft.in() {
+ in = append(in, arg)
+ }
+ out := make([]Type, 0, len(ft.out()))
+ for _, ret := range ft.out() {
+ out = append(out, ret)
+ }
+ mt := FuncOf(in, out, ft.IsVariadic())
+ m.Type = mt
+ tfn := t.textOff(p.tfn)
+ fn := unsafe.Pointer(&tfn)
+ m.Func = Value{mt.(*rtype), fn, fl}
+
m.Index = i
return m
}
for i := 0; i < int(ut.mcount); i++ {
p := utmethods[i]
pname := t.nameOff(p.name)
- if pname.name() == name {
+ if pname.isExported() && pname.name() == name {
return t.Method(i), true
}
}
// Field returns the i'th struct field.
func (t *structType) Field(i int) (f StructField) {
if i < 0 || i >= len(t.fields) {
- return
+ panic("reflect: Field index out of bounds")
}
p := &t.fields[i]
f.Type = toType(p.typ)
if len(args) > 50 {
panic("reflect.FuncOf does not support more than 50 arguments")
}
+ ft.tflag = 0
ft.hash = hash
ft.inCount = uint16(len(in))
ft.outCount = uint16(len(out))
// StructOf returns the struct type containing fields.
// The Offset and Index fields are ignored and computed as they would be
// by the compiler.
-//
-// StructOf does not support creating structs with UTF-8 field names or
-// UTF-8 (embedded) type names.
-// This limitation may be lifted eventually.
func StructOf(fields []StructField) Type {
var (
hash = fnv1(0, []byte("struct {")...)
default:
panic("reflect.typeptrdata: unexpected type, " + t.String())
}
- return 0
}
// See cmd/compile/internal/gc/reflect.go for derivation of constant.
Empty strings:
^ at beginning of text or line (flag m=true)
- $ at end of text (like \z not \Z) or line (flag m=true)
+ $ at end of text (like \z not Perl's \Z) or line (flag m=true)
\A at beginning of text
\b at ASCII word boundary (\w on one side and \W, \A, or \z on the other)
\B not at ASCII word boundary
unset CDPATH # in case user has it set
unset GOPATH # we disallow local import for non-local packages, if $GOROOT happens
# to be under $GOPATH, then some tests below will fail
+unset GOBIN # Issue 14340
export GOHOSTOS
export CC
:: we disallow local import for non-local packages, if %GOROOT% happens
:: to be under %GOPATH%, then some tests below will fail
set GOPATH=
+:: Issue 14340: ignore GOBIN during all.bat.
+set GOBIN=
rem TODO avoid rebuild if possible
GOPATH = () # we disallow local import for non-local packages, if $GOROOT happens
# to be under $GOPATH, then some tests below will fail
+GOBIN = () # Issue 14340
exec go tool dist test -rebuild $*
// license that can be found in the LICENSE file.
package runtime_test
-import "testing"
+import (
+ "fmt"
+ "testing"
+)
const N = 20
}
}
-func benchmarkAppendBytes(b *testing.B, length int) {
- b.StopTimer()
- x := make([]byte, 0, N)
- y := make([]byte, length)
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- x = x[0:0]
- x = append(x, y...)
+func BenchmarkAppendSlice(b *testing.B) {
+ for _, length := range []int{1, 4, 7, 8, 15, 16, 32} {
+ b.Run(fmt.Sprint(length, "Bytes"), func(b *testing.B) {
+ x := make([]byte, 0, N)
+ y := make([]byte, length)
+ for i := 0; i < b.N; i++ {
+ x = x[0:0]
+ x = append(x, y...)
+ }
+ })
}
}
-func BenchmarkAppend1Byte(b *testing.B) {
- benchmarkAppendBytes(b, 1)
-}
-
-func BenchmarkAppend4Bytes(b *testing.B) {
- benchmarkAppendBytes(b, 4)
-}
-
-func BenchmarkAppend7Bytes(b *testing.B) {
- benchmarkAppendBytes(b, 7)
-}
-
-func BenchmarkAppend8Bytes(b *testing.B) {
- benchmarkAppendBytes(b, 8)
-}
-
-func BenchmarkAppend15Bytes(b *testing.B) {
- benchmarkAppendBytes(b, 15)
-}
-
-func BenchmarkAppend16Bytes(b *testing.B) {
- benchmarkAppendBytes(b, 16)
-}
-
-func BenchmarkAppend32Bytes(b *testing.B) {
- benchmarkAppendBytes(b, 32)
-}
-
-func benchmarkAppendStr(b *testing.B, str string) {
- b.StopTimer()
- x := make([]byte, 0, N)
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- x = x[0:0]
- x = append(x, str...)
+func BenchmarkAppendStr(b *testing.B) {
+ for _, str := range []string{
+ "1",
+ "1234",
+ "12345678",
+ "1234567890123456",
+ "12345678901234567890123456789012",
+ } {
+ b.Run(fmt.Sprint(len(str), "Bytes"), func(b *testing.B) {
+ x := make([]byte, 0, N)
+ for i := 0; i < b.N; i++ {
+ x = x[0:0]
+ x = append(x, str...)
+ }
+ })
}
}
-func BenchmarkAppendStr1Byte(b *testing.B) {
- benchmarkAppendStr(b, "1")
-}
-
-func BenchmarkAppendStr4Bytes(b *testing.B) {
- benchmarkAppendStr(b, "1234")
-}
-
-func BenchmarkAppendStr8Bytes(b *testing.B) {
- benchmarkAppendStr(b, "12345678")
-}
-
-func BenchmarkAppendStr16Bytes(b *testing.B) {
- benchmarkAppendStr(b, "1234567890123456")
-}
-
-func BenchmarkAppendStr32Bytes(b *testing.B) {
- benchmarkAppendStr(b, "12345678901234567890123456789012")
-}
-
func BenchmarkAppendSpecialCase(b *testing.B) {
b.StopTimer()
x := make([]int, 0, N)
}
}
-func benchmarkCopySlice(b *testing.B, l int) {
- s := make([]byte, l)
- buf := make([]byte, 4096)
- var n int
- for i := 0; i < b.N; i++ {
- n = copy(buf, s)
- }
- b.SetBytes(int64(n))
-}
-
-func benchmarkCopyStr(b *testing.B, l int) {
- s := string(make([]byte, l))
- buf := make([]byte, 4096)
- var n int
- for i := 0; i < b.N; i++ {
- n = copy(buf, s)
+func BenchmarkCopy(b *testing.B) {
+ for _, l := range []int{1, 2, 4, 8, 12, 16, 32, 128, 1024} {
+ buf := make([]byte, 4096)
+ b.Run(fmt.Sprint(l, "Byte"), func(b *testing.B) {
+ s := make([]byte, l)
+ var n int
+ for i := 0; i < b.N; i++ {
+ n = copy(buf, s)
+ }
+ b.SetBytes(int64(n))
+ })
+ b.Run(fmt.Sprint(l, "String"), func(b *testing.B) {
+ s := string(make([]byte, l))
+ var n int
+ for i := 0; i < b.N; i++ {
+ n = copy(buf, s)
+ }
+ b.SetBytes(int64(n))
+ })
}
- b.SetBytes(int64(n))
}
-func BenchmarkCopy1Byte(b *testing.B) { benchmarkCopySlice(b, 1) }
-func BenchmarkCopy2Byte(b *testing.B) { benchmarkCopySlice(b, 2) }
-func BenchmarkCopy4Byte(b *testing.B) { benchmarkCopySlice(b, 4) }
-func BenchmarkCopy8Byte(b *testing.B) { benchmarkCopySlice(b, 8) }
-func BenchmarkCopy12Byte(b *testing.B) { benchmarkCopySlice(b, 12) }
-func BenchmarkCopy16Byte(b *testing.B) { benchmarkCopySlice(b, 16) }
-func BenchmarkCopy32Byte(b *testing.B) { benchmarkCopySlice(b, 32) }
-func BenchmarkCopy128Byte(b *testing.B) { benchmarkCopySlice(b, 128) }
-func BenchmarkCopy1024Byte(b *testing.B) { benchmarkCopySlice(b, 1024) }
-
-func BenchmarkCopy1String(b *testing.B) { benchmarkCopyStr(b, 1) }
-func BenchmarkCopy2String(b *testing.B) { benchmarkCopyStr(b, 2) }
-func BenchmarkCopy4String(b *testing.B) { benchmarkCopyStr(b, 4) }
-func BenchmarkCopy8String(b *testing.B) { benchmarkCopyStr(b, 8) }
-func BenchmarkCopy12String(b *testing.B) { benchmarkCopyStr(b, 12) }
-func BenchmarkCopy16String(b *testing.B) { benchmarkCopyStr(b, 16) }
-func BenchmarkCopy32String(b *testing.B) { benchmarkCopyStr(b, 32) }
-func BenchmarkCopy128String(b *testing.B) { benchmarkCopyStr(b, 128) }
-func BenchmarkCopy1024String(b *testing.B) { benchmarkCopyStr(b, 1024) }
-
var (
sByte []byte
s1Ptr []uintptr
MOVQ fv+0(FP), DX // fn
MOVQ argp+8(FP), BX // caller sp
LEAQ -8(BX), SP // caller sp after CALL
+ MOVQ -8(SP), BP // restore BP as if deferreturn returned (harmless if framepointers not in use)
SUBQ $5, (SP) // return to CALL again
MOVQ 0(DX), BX
JMP BX // but first run the deferred function
CMPQ DI,DX
JB loop16
JMP fail
+//TODO: the code below is wrong. Fix it. See #15679.
_17_to_31:
LEAQ 1(DI)(DX*1), DX
SUBQ AX, DX
// Filled in by runtime/cgo when linked into binary.
//go:linkname _cgo_init _cgo_init
-//go:linkname _cgo_malloc _cgo_malloc
-//go:linkname _cgo_free _cgo_free
//go:linkname _cgo_thread_start _cgo_thread_start
//go:linkname _cgo_sys_thread_create _cgo_sys_thread_create
//go:linkname _cgo_notify_runtime_init_done _cgo_notify_runtime_init_done
var (
_cgo_init unsafe.Pointer
- _cgo_malloc unsafe.Pointer
- _cgo_free unsafe.Pointer
_cgo_thread_start unsafe.Pointer
_cgo_sys_thread_create unsafe.Pointer
_cgo_notify_runtime_init_done unsafe.Pointer
* Additionally, runtime·load_g will clobber R0, so we need to save R0
* nevertheless.
*/
+ SUB $(8*9), R13 // Reserve space for the floating point registers.
MOVM.WP [R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, g, R11, R12, R14], (R13)
+
+ // Skip floating point registers on GOARM < 6.
+ MOVB runtime·goarm(SB), R11
+ CMP $6, R11
+ BLT skipfpsave
+ MOVD F8, (14*4+8*1)(R13)
+ MOVD F9, (14*4+8*2)(R13)
+ MOVD F10, (14*4+8*3)(R13)
+ MOVD F11, (14*4+8*4)(R13)
+ MOVD F12, (14*4+8*5)(R13)
+ MOVD F13, (14*4+8*6)(R13)
+ MOVD F14, (14*4+8*7)(R13)
+ MOVD F15, (14*4+8*8)(R13)
+
+skipfpsave:
BL runtime·load_g(SB)
MOVW R15, R14 // R15 is PC.
MOVW 0(R13), R15
- MOVM.IAW (R13), [R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, g, R11, R12, R15]
+
+ MOVB runtime·goarm(SB), R11
+ CMP $6, R11
+ BLT skipfprest
+ MOVD (14*4+8*1)(R13), F8
+ MOVD (14*4+8*2)(R13), F9
+ MOVD (14*4+8*3)(R13), F10
+ MOVD (14*4+8*4)(R13), F11
+ MOVD (14*4+8*5)(R13), F12
+ MOVD (14*4+8*6)(R13), F13
+ MOVD (14*4+8*7)(R13), F14
+ MOVD (14*4+8*8)(R13), F15
+
+skipfprest:
+ MOVM.IAW (R13), [R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, g, R11, R12, R14]
+ ADD $(8*9), R13
+ MOVW R14, R15
var x_cgo_init byte
var _cgo_init = &x_cgo_init
-//go:cgo_import_static x_cgo_malloc
-//go:linkname x_cgo_malloc x_cgo_malloc
-//go:linkname _cgo_malloc _cgo_malloc
-var x_cgo_malloc byte
-var _cgo_malloc = &x_cgo_malloc
-
-//go:cgo_import_static x_cgo_free
-//go:linkname x_cgo_free x_cgo_free
-//go:linkname _cgo_free _cgo_free
-var x_cgo_free byte
-var _cgo_free = &x_cgo_free
-
//go:cgo_import_static x_cgo_thread_start
//go:linkname x_cgo_thread_start x_cgo_thread_start
//go:linkname _cgo_thread_start _cgo_thread_start
static void* threadentry(void*);
static void (*setg_gcc)(void*);
-// TCB_SIZE is sizeof(struct thread_control_block),
-// as defined in /usr/src/lib/librthread/tcb.h
+// TCB_SIZE is sizeof(struct thread_control_block), as defined in
+// /usr/src/lib/librthread/tcb.h on OpenBSD 5.9 and earlier.
#define TCB_SIZE (4 * sizeof(void *))
+
+// TIB_SIZE is sizeof(struct tib), as defined in
+// /usr/include/tib.h on OpenBSD 6.0 and later.
+#define TIB_SIZE (4 * sizeof(void *) + 6 * sizeof(int))
+
+// TLS_SIZE is the size of TLS needed for Go.
#define TLS_SIZE (2 * sizeof(void *))
void *__get_tcb(void);
void *arg;
};
+static int has_tib = 0;
+
static void
tcb_fixup(int mainthread)
{
- void *newtcb, *oldtcb;
+ void *tls, *newtcb, *oldtcb;
+ size_t tls_size, tcb_size;
+
+ // TODO(jsing): Remove once OpenBSD 6.1 is released and OpenBSD 5.9 is
+ // no longer supported.
// The OpenBSD ld.so(1) does not currently support PT_TLS. As a result,
// we need to allocate our own TLS space while preserving the existing
- // TCB that has been setup via librthread.
+ // TCB or TIB that has been setup via librthread.
- newtcb = malloc(TCB_SIZE + TLS_SIZE);
- if(newtcb == NULL)
+ tcb_size = has_tib ? TIB_SIZE : TCB_SIZE;
+ tls_size = TLS_SIZE + tcb_size;
+ tls = malloc(tls_size);
+ if(tls == NULL)
abort();
// The signal trampoline expects the TLS slots to be zeroed.
- bzero(newtcb, TLS_SIZE);
+ bzero(tls, TLS_SIZE);
oldtcb = __get_tcb();
- bcopy(oldtcb, newtcb + TLS_SIZE, TCB_SIZE);
- __set_tcb(newtcb + TLS_SIZE);
+ newtcb = tls + TLS_SIZE;
+ bcopy(oldtcb, newtcb, tcb_size);
+ if(has_tib) {
+ // Fix up self pointer.
+ *(uintptr_t *)(newtcb) = (uintptr_t)newtcb;
+ }
+ __set_tcb(newtcb);
// NOTE(jsing, minux): we can't free oldtcb without causing double-free
// problem. so newtcb will be memory leaks. Get rid of this when OpenBSD
fprintf(stderr, "runtime/cgo: dlsym failed to find pthread_create: %s\n", dlerror());
abort();
}
+ // _rthread_init is hidden in OpenBSD librthread that has TIB.
+ if(dlsym(handle, "_rthread_init") == NULL) {
+ has_tib = 1;
+ }
dlclose(handle);
}
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
+
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
ts->g->stackhi = size;
err = sys_pthread_create(&p, &attr, threadentry, ts);
static void* threadentry(void*);
static void (*setg_gcc)(void*);
-// TCB_SIZE is sizeof(struct thread_control_block),
-// as defined in /usr/src/lib/librthread/tcb.h
+// TCB_SIZE is sizeof(struct thread_control_block), as defined in
+// /usr/src/lib/librthread/tcb.h on OpenBSD 5.9 and earlier.
#define TCB_SIZE (4 * sizeof(void *))
+
+// TIB_SIZE is sizeof(struct tib), as defined in
+// /usr/include/tib.h on OpenBSD 6.0 and later.
+#define TIB_SIZE (4 * sizeof(void *) + 6 * sizeof(int))
+
+// TLS_SIZE is the size of TLS needed for Go.
#define TLS_SIZE (2 * sizeof(void *))
void *__get_tcb(void);
void *arg;
};
+static int has_tib = 0;
+
static void
tcb_fixup(int mainthread)
{
- void *newtcb, *oldtcb;
+ void *tls, *newtcb, *oldtcb;
+ size_t tls_size, tcb_size;
+
+ // TODO(jsing): Remove once OpenBSD 6.1 is released and OpenBSD 5.9 is
+ // no longer supported.
// The OpenBSD ld.so(1) does not currently support PT_TLS. As a result,
// we need to allocate our own TLS space while preserving the existing
- // TCB that has been setup via librthread.
+ // TCB or TIB that has been setup via librthread.
- newtcb = malloc(TCB_SIZE + TLS_SIZE);
- if(newtcb == NULL)
+ tcb_size = has_tib ? TIB_SIZE : TCB_SIZE;
+ tls_size = TLS_SIZE + tcb_size;
+ tls = malloc(tls_size);
+ if(tls == NULL)
abort();
// The signal trampoline expects the TLS slots to be zeroed.
- bzero(newtcb, TLS_SIZE);
+ bzero(tls, TLS_SIZE);
oldtcb = __get_tcb();
- bcopy(oldtcb, newtcb + TLS_SIZE, TCB_SIZE);
- __set_tcb(newtcb + TLS_SIZE);
+ newtcb = tls + TLS_SIZE;
+ bcopy(oldtcb, newtcb, tcb_size);
+ if(has_tib) {
+ // Fix up self pointer.
+ *(uintptr_t *)(newtcb) = (uintptr_t)newtcb;
+ }
+ __set_tcb(newtcb);
// NOTE(jsing, minux): we can't free oldtcb without causing double-free
// problem. so newtcb will be memory leaks. Get rid of this when OpenBSD
fprintf(stderr, "runtime/cgo: dlsym failed to find pthread_create: %s\n", dlerror());
abort();
}
+ // _rthread_init is hidden in OpenBSD librthread that has TIB.
+ if(dlsym(handle, "_rthread_init") == NULL) {
+ has_tib = 1;
+ }
dlclose(handle);
}
#include "libcgo.h"
-/* Stub for calling malloc from Go */
-void
-x_cgo_malloc(void *p)
-{
- struct a {
- long long n;
- void *ret;
- } *a = p;
-
- a->ret = malloc(a->n);
- if(a->ret == NULL && a->n == 0)
- a->ret = malloc(1);
-}
-
-/* Stub for calling free from Go */
-void
-x_cgo_free(void *p)
-{
- struct a {
- void *arg;
- } *a = p;
-
- free(a->arg);
-}
-
/* Stub for creating a new thread */
void
x_cgo_thread_start(ThreadStart *arg)
unlockOSThread() // invalidates mp
}
-// Helper functions for cgo code.
-
-func cmalloc(n uintptr) unsafe.Pointer {
- var args struct {
- n uint64
- ret unsafe.Pointer
- }
- args.n = uint64(n)
- cgocall(_cgo_malloc, unsafe.Pointer(&args))
- if args.ret == nil {
- throw("C malloc failed")
- }
- return args.ret
-}
-
-func cfree(p unsafe.Pointer) {
- cgocall(_cgo_free, p)
-}
-
// Call from C back to Go.
//go:nosplit
func cgocallbackg(ctxt uintptr) {
return false
}
- if cgoInRange(p, mheap_.arena_start, mheap_.arena_used) {
+ if inHeapOrStack(uintptr(p)) {
return true
}
//go:nosplit
//go:nowritebarrier
func cgoCheckTypedBlock(typ *_type, src unsafe.Pointer, off, size uintptr) {
+ // Anything past typ.ptrdata is not a pointer.
+ if typ.ptrdata <= off {
+ return
+ }
+ if ptrdataSize := typ.ptrdata - off; size > ptrdataSize {
+ size = ptrdataSize
+ }
+
if typ.kind&kindGCProg == 0 {
cgoCheckBits(src, typ.gcdata, off, size)
return
// cgoCheckUsingType is like cgoCheckTypedBlock, but is a last ditch
// fall back to look for pointers in src using the type information.
-// We only this when looking at a value on the stack when the type
+// We only use this when looking at a value on the stack when the type
// uses a GC program, because otherwise it's more efficient to use the
// GC bits. This is called on the system stack.
//go:nowritebarrier
if typ.kind&kindNoPointers != 0 {
return
}
+
+ // Anything past typ.ptrdata is not a pointer.
+ if typ.ptrdata <= off {
+ return
+ }
+ if ptrdataSize := typ.ptrdata - off; size > ptrdataSize {
+ size = ptrdataSize
+ }
+
if typ.kind&kindGCProg == 0 {
cgoCheckBits(src, typ.gcdata, off, size)
return
func TestSignalExitStatus(t *testing.T) {
testenv.MustHaveGoBuild(t)
- switch runtime.GOOS {
- case "netbsd", "solaris":
- t.Skipf("skipping on %s; see https://golang.org/issue/14063", runtime.GOOS)
- }
exe, err := buildTestProg(t, "testprog")
if err != nil {
t.Fatal(err)
_MaxGcproc = 32
)
-const _MaxArena32 = 2 << 30
+const _MaxArena32 = 1<<32 - 1
// OS-defined helpers:
//
// Set up the allocation arena, a contiguous area of memory where
// allocated data will be found. The arena begins with a bitmap large
- // enough to hold 4 bits per allocated word.
+ // enough to hold 2 bits per allocated word.
if sys.PtrSize == 8 && (limit == 0 || limit > 1<<30) {
// On a 64-bit machine, allocate from a single contiguous reservation.
// 512 GB (MaxMem) should be big enough for now.
// translation buffers, the user address space is limited to 39 bits
// On darwin/arm64, the address space is even smaller.
arenaSize := round(_MaxMem, _PageSize)
- bitmapSize = arenaSize / (sys.PtrSize * 8 / 4)
+ bitmapSize = arenaSize / (sys.PtrSize * 8 / 2)
spansSize = arenaSize / _PageSize * sys.PtrSize
spansSize = round(spansSize, _PageSize)
for i := 0; i <= 0x7f; i++ {
// with a giant virtual address space reservation.
// Instead we map the memory information bitmap
// immediately after the data segment, large enough
- // to handle another 2GB of mappings (256 MB),
+ // to handle the entire 4GB address space (256 MB),
// along with a reservation for an initial arena.
// When that gets used up, we'll start asking the kernel
- // for any memory anywhere and hope it's in the 2GB
- // following the bitmap (presumably the executable begins
- // near the bottom of memory, so we'll have to use up
- // most of memory before the kernel resorts to giving out
- // memory before the beginning of the text segment).
- //
- // Alternatively we could reserve 512 MB bitmap, enough
- // for 4GB of mappings, and then accept any memory the
- // kernel threw at us, but normally that's a waste of 512 MB
- // of address space, which is probably too much in a 32-bit world.
+ // for any memory anywhere.
// If we fail to allocate, try again with a smaller arena.
// This is necessary on Android L where we share a process
// with ART, which reserves virtual memory aggressively.
+ // In the worst case, fall back to a 0-sized initial arena,
+ // in the hope that subsequent reservations will succeed.
arenaSizes := []uintptr{
512 << 20,
256 << 20,
128 << 20,
+ 0,
}
for _, arenaSize := range arenaSizes {
- bitmapSize = _MaxArena32 / (sys.PtrSize * 8 / 4)
- spansSize = _MaxArena32 / _PageSize * sys.PtrSize
+ bitmapSize = (_MaxArena32 + 1) / (sys.PtrSize * 8 / 2)
+ spansSize = (_MaxArena32 + 1) / _PageSize * sys.PtrSize
if limit > 0 && arenaSize+bitmapSize+spansSize > limit {
bitmapSize = (limit / 9) &^ ((1 << _PageShift) - 1)
arenaSize = bitmapSize * 8
p1 := round(p, _PageSize)
mheap_.spans = (**mspan)(unsafe.Pointer(p1))
- mheap_.bitmap = p1 + spansSize
- mheap_.arena_start = p1 + (spansSize + bitmapSize)
- mheap_.arena_used = mheap_.arena_start
+ mheap_.bitmap = p1 + spansSize + bitmapSize
+ if sys.PtrSize == 4 {
+ // Set arena_start such that we can accept memory
+ // reservations located anywhere in the 4GB virtual space.
+ mheap_.arena_start = 0
+ } else {
+ mheap_.arena_start = p1 + (spansSize + bitmapSize)
+ }
mheap_.arena_end = p + pSize
+ mheap_.arena_used = p1 + (spansSize + bitmapSize)
mheap_.arena_reserved = reserved
if mheap_.arena_start&(_PageSize-1) != 0 {
_g_.m.mcache = allocmcache()
}
-// sysReserveHigh reserves space somewhere high in the address space.
-// sysReserve doesn't actually reserve the full amount requested on
-// 64-bit systems, because of problems with ulimit. Instead it checks
-// that it can get the first 64 kB and assumes it can grab the rest as
-// needed. This doesn't work well with the "let the kernel pick an address"
-// mode, so don't do that. Pick a high address instead.
-func sysReserveHigh(n uintptr, reserved *bool) unsafe.Pointer {
- if sys.PtrSize == 4 {
- return sysReserve(nil, n, reserved)
- }
-
- for i := 0; i <= 0x7f; i++ {
- p := uintptr(i)<<40 | uintptrMask&(0x00c0<<32)
- *reserved = false
- p = uintptr(sysReserve(unsafe.Pointer(p), n, reserved))
- if p != 0 {
- return unsafe.Pointer(p)
- }
- }
-
- return sysReserve(nil, n, reserved)
-}
-
// sysAlloc allocates the next n bytes from the heap arena. The
// returned pointer is always _PageSize aligned and between
// h.arena_start and h.arena_end. sysAlloc returns nil on failure.
// Reserve some more space.
p_size := round(n+_PageSize, 256<<20)
new_end := h.arena_end + p_size // Careful: can overflow
- if h.arena_end <= new_end && new_end <= h.arena_start+_MaxArena32 {
+ if h.arena_end <= new_end && new_end-h.arena_start-1 <= _MaxArena32 {
// TODO: It would be bad if part of the arena
// is reserved and part is not.
var reserved bool
if p == h.arena_end {
h.arena_end = new_end
h.arena_reserved = reserved
- } else if h.arena_start <= p && p+p_size <= h.arena_start+_MaxArena32 {
+ } else if h.arena_start <= p && p+p_size-h.arena_start-1 <= _MaxArena32 {
// Keep everything page-aligned.
// Our pages are bigger than hardware pages.
h.arena_end = p + p_size
}
// If using 64-bit, our reservation is all we have.
- if h.arena_end-h.arena_start >= _MaxArena32 {
+ if h.arena_end-h.arena_start > _MaxArena32 {
return nil
}
// On 32-bit, once the reservation is gone we can
- // try to get memory at a location chosen by the OS
- // and hope that it is in the range we allocated bitmap for.
+ // try to get memory at a location chosen by the OS.
p_size := round(n, _PageSize) + _PageSize
p := uintptr(sysAlloc(p_size, &memstats.heap_sys))
if p == 0 {
return nil
}
- if p < h.arena_start || p+p_size-h.arena_start >= _MaxArena32 {
+ if p < h.arena_start || p+p_size-h.arena_start > _MaxArena32 {
top := ^uintptr(0)
- if top-h.arena_start > _MaxArena32 {
- top = h.arena_start + _MaxArena32
+ if top-h.arena_start-1 > _MaxArena32 {
+ top = h.arena_start + _MaxArena32 + 1
}
print("runtime: memory allocated by OS (", hex(p), ") not in usable range [", hex(h.arena_start), ",", hex(top), ")\n")
sysFree(unsafe.Pointer(p), p_size, &memstats.heap_sys)
scanSize = typ.ptrdata
}
c.local_scan += scanSize
-
- // Ensure that the stores above that initialize x to
- // type-safe memory and set the heap bits occur before
- // the caller can make x observable to the garbage
- // collector. Otherwise, on weakly ordered machines,
- // the garbage collector could follow a pointer to x,
- // but see uninitialized memory or stale heap bits.
- publicationBarrier()
}
+ // Ensure that the stores above that initialize x to
+ // type-safe memory and set the heap bits occur before
+ // the caller can make x observable to the garbage
+ // collector. Otherwise, on weakly ordered machines,
+ // the garbage collector could follow a pointer to x,
+ // but see uninitialized memory or stale heap bits.
+ publicationBarrier()
+
// Allocate black during GC.
// All slots hold nil so no scanning is needed.
// This may be racing with GC so do it atomically if there can be
return
}
- sysMap(unsafe.Pointer(h.arena_start-n), n-h.bitmap_mapped, h.arena_reserved, &memstats.gc_sys)
+ sysMap(unsafe.Pointer(h.bitmap-n), n-h.bitmap_mapped, h.arena_reserved, &memstats.gc_sys)
h.bitmap_mapped = n
}
func heapBitsForAddr(addr uintptr) heapBits {
// 2 bits per work, 4 pairs per byte, and a mask is hard coded.
off := (addr - mheap_.arena_start) / sys.PtrSize
- return heapBits{(*uint8)(unsafe.Pointer(mheap_.arena_start - off/4 - 1)), uint32(off & 3)}
+ return heapBits{(*uint8)(unsafe.Pointer(mheap_.bitmap - off/4 - 1)), uint32(off & 3)}
}
// heapBitsForSpan returns the heapBits for the span base address base.
}
// isPointer reports whether the heap bits describe a pointer word.
-// h must describe the initial word of the object.
//
// nosplit because it is used during write barriers and must not be preempted.
//go:nosplit
}
// hasPointers reports whether the given object has any pointers.
-// It must be told how large the object at h is, so that it does not read too
-// far into the bitmap.
+// It must be told how large the object at h is for efficiency.
// h must describe the initial word of the object.
func (h heapBits) hasPointers(size uintptr) bool {
if size == sys.PtrSize { // 1-word objects are always pointers
// malloc does not call heapBitsSetType when there are no pointers,
// because all free objects are marked as noscan during
// heapBitsSweepSpan.
+//
// There can only be one allocation from a given span active at a time,
-// so this code is not racing with other instances of itself, and
-// the bitmap for a span always falls on byte boundaries.
-// Hence, it can access the bitmap with racing.
+// and the bitmap for a span always falls on byte boundaries,
+// so there are no write-write races for access to the heap bitmap.
+// Hence, heapBitsSetType can access the bitmap without atomics.
+//
+// There can be read-write races between heapBitsSetType and things
+// that read the heap bitmap like scanobject. However, since
+// heapBitsSetType is only used for objects that have not yet been
+// made reachable, readers will ignore bits being modified by this
+// function. This does mean this function cannot transiently modify
+// bits that belong to neighboring objects. Also, on weakly-ordered
+// machines, callers must execute a store/store (publication) barrier
+// between calling this function and making the object reachable.
//
// TODO: This still has atomic accesses left over from when it could
// race with GC accessing mark bits in the bitmap. Remove these.
package runtime_test
import (
+ "fmt"
. "runtime"
"testing"
)
}
}
-func bmMemmove(b *testing.B, n int) {
- x := make([]byte, n)
- y := make([]byte, n)
- b.SetBytes(int64(n))
- for i := 0; i < b.N; i++ {
- copy(x, y)
+func benchmarkSizes(b *testing.B, sizes []int, fn func(b *testing.B, n int)) {
+ for _, n := range sizes {
+ b.Run(fmt.Sprint(n), func(b *testing.B) {
+ b.SetBytes(int64(n))
+ fn(b, n)
+ })
}
}
-func BenchmarkMemmove0(b *testing.B) { bmMemmove(b, 0) }
-func BenchmarkMemmove1(b *testing.B) { bmMemmove(b, 1) }
-func BenchmarkMemmove2(b *testing.B) { bmMemmove(b, 2) }
-func BenchmarkMemmove3(b *testing.B) { bmMemmove(b, 3) }
-func BenchmarkMemmove4(b *testing.B) { bmMemmove(b, 4) }
-func BenchmarkMemmove5(b *testing.B) { bmMemmove(b, 5) }
-func BenchmarkMemmove6(b *testing.B) { bmMemmove(b, 6) }
-func BenchmarkMemmove7(b *testing.B) { bmMemmove(b, 7) }
-func BenchmarkMemmove8(b *testing.B) { bmMemmove(b, 8) }
-func BenchmarkMemmove9(b *testing.B) { bmMemmove(b, 9) }
-func BenchmarkMemmove10(b *testing.B) { bmMemmove(b, 10) }
-func BenchmarkMemmove11(b *testing.B) { bmMemmove(b, 11) }
-func BenchmarkMemmove12(b *testing.B) { bmMemmove(b, 12) }
-func BenchmarkMemmove13(b *testing.B) { bmMemmove(b, 13) }
-func BenchmarkMemmove14(b *testing.B) { bmMemmove(b, 14) }
-func BenchmarkMemmove15(b *testing.B) { bmMemmove(b, 15) }
-func BenchmarkMemmove16(b *testing.B) { bmMemmove(b, 16) }
-func BenchmarkMemmove32(b *testing.B) { bmMemmove(b, 32) }
-func BenchmarkMemmove64(b *testing.B) { bmMemmove(b, 64) }
-func BenchmarkMemmove128(b *testing.B) { bmMemmove(b, 128) }
-func BenchmarkMemmove256(b *testing.B) { bmMemmove(b, 256) }
-func BenchmarkMemmove512(b *testing.B) { bmMemmove(b, 512) }
-func BenchmarkMemmove1024(b *testing.B) { bmMemmove(b, 1024) }
-func BenchmarkMemmove2048(b *testing.B) { bmMemmove(b, 2048) }
-func BenchmarkMemmove4096(b *testing.B) { bmMemmove(b, 4096) }
-
-func bmMemmoveUnalignedDst(b *testing.B, n int) {
- x := make([]byte, n+1)
- y := make([]byte, n)
- b.SetBytes(int64(n))
- for i := 0; i < b.N; i++ {
- copy(x[1:], y)
- }
+var bufSizes = []int{
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 32, 64, 128, 256, 512, 1024, 2048, 4096,
}
-func BenchmarkMemmoveUnalignedDst0(b *testing.B) { bmMemmoveUnalignedDst(b, 0) }
-func BenchmarkMemmoveUnalignedDst1(b *testing.B) { bmMemmoveUnalignedDst(b, 1) }
-func BenchmarkMemmoveUnalignedDst2(b *testing.B) { bmMemmoveUnalignedDst(b, 2) }
-func BenchmarkMemmoveUnalignedDst3(b *testing.B) { bmMemmoveUnalignedDst(b, 3) }
-func BenchmarkMemmoveUnalignedDst4(b *testing.B) { bmMemmoveUnalignedDst(b, 4) }
-func BenchmarkMemmoveUnalignedDst5(b *testing.B) { bmMemmoveUnalignedDst(b, 5) }
-func BenchmarkMemmoveUnalignedDst6(b *testing.B) { bmMemmoveUnalignedDst(b, 6) }
-func BenchmarkMemmoveUnalignedDst7(b *testing.B) { bmMemmoveUnalignedDst(b, 7) }
-func BenchmarkMemmoveUnalignedDst8(b *testing.B) { bmMemmoveUnalignedDst(b, 8) }
-func BenchmarkMemmoveUnalignedDst9(b *testing.B) { bmMemmoveUnalignedDst(b, 9) }
-func BenchmarkMemmoveUnalignedDst10(b *testing.B) { bmMemmoveUnalignedDst(b, 10) }
-func BenchmarkMemmoveUnalignedDst11(b *testing.B) { bmMemmoveUnalignedDst(b, 11) }
-func BenchmarkMemmoveUnalignedDst12(b *testing.B) { bmMemmoveUnalignedDst(b, 12) }
-func BenchmarkMemmoveUnalignedDst13(b *testing.B) { bmMemmoveUnalignedDst(b, 13) }
-func BenchmarkMemmoveUnalignedDst14(b *testing.B) { bmMemmoveUnalignedDst(b, 14) }
-func BenchmarkMemmoveUnalignedDst15(b *testing.B) { bmMemmoveUnalignedDst(b, 15) }
-func BenchmarkMemmoveUnalignedDst16(b *testing.B) { bmMemmoveUnalignedDst(b, 16) }
-func BenchmarkMemmoveUnalignedDst32(b *testing.B) { bmMemmoveUnalignedDst(b, 32) }
-func BenchmarkMemmoveUnalignedDst64(b *testing.B) { bmMemmoveUnalignedDst(b, 64) }
-func BenchmarkMemmoveUnalignedDst128(b *testing.B) { bmMemmoveUnalignedDst(b, 128) }
-func BenchmarkMemmoveUnalignedDst256(b *testing.B) { bmMemmoveUnalignedDst(b, 256) }
-func BenchmarkMemmoveUnalignedDst512(b *testing.B) { bmMemmoveUnalignedDst(b, 512) }
-func BenchmarkMemmoveUnalignedDst1024(b *testing.B) { bmMemmoveUnalignedDst(b, 1024) }
-func BenchmarkMemmoveUnalignedDst2048(b *testing.B) { bmMemmoveUnalignedDst(b, 2048) }
-func BenchmarkMemmoveUnalignedDst4096(b *testing.B) { bmMemmoveUnalignedDst(b, 4096) }
+func BenchmarkMemmove(b *testing.B) {
+ benchmarkSizes(b, bufSizes, func(b *testing.B, n int) {
+ x := make([]byte, n)
+ y := make([]byte, n)
+ for i := 0; i < b.N; i++ {
+ copy(x, y)
+ }
+ })
+}
-func bmMemmoveUnalignedSrc(b *testing.B, n int) {
- x := make([]byte, n)
- y := make([]byte, n+1)
- b.SetBytes(int64(n))
- for i := 0; i < b.N; i++ {
- copy(x, y[1:])
- }
+func BenchmarkMemmoveUnalignedDst(b *testing.B) {
+ benchmarkSizes(b, bufSizes, func(b *testing.B, n int) {
+ x := make([]byte, n+1)
+ y := make([]byte, n)
+ for i := 0; i < b.N; i++ {
+ copy(x[1:], y)
+ }
+ })
}
-func BenchmarkMemmoveUnalignedSrc0(b *testing.B) { bmMemmoveUnalignedSrc(b, 0) }
-func BenchmarkMemmoveUnalignedSrc1(b *testing.B) { bmMemmoveUnalignedSrc(b, 1) }
-func BenchmarkMemmoveUnalignedSrc2(b *testing.B) { bmMemmoveUnalignedSrc(b, 2) }
-func BenchmarkMemmoveUnalignedSrc3(b *testing.B) { bmMemmoveUnalignedSrc(b, 3) }
-func BenchmarkMemmoveUnalignedSrc4(b *testing.B) { bmMemmoveUnalignedSrc(b, 4) }
-func BenchmarkMemmoveUnalignedSrc5(b *testing.B) { bmMemmoveUnalignedSrc(b, 5) }
-func BenchmarkMemmoveUnalignedSrc6(b *testing.B) { bmMemmoveUnalignedSrc(b, 6) }
-func BenchmarkMemmoveUnalignedSrc7(b *testing.B) { bmMemmoveUnalignedSrc(b, 7) }
-func BenchmarkMemmoveUnalignedSrc8(b *testing.B) { bmMemmoveUnalignedSrc(b, 8) }
-func BenchmarkMemmoveUnalignedSrc9(b *testing.B) { bmMemmoveUnalignedSrc(b, 9) }
-func BenchmarkMemmoveUnalignedSrc10(b *testing.B) { bmMemmoveUnalignedSrc(b, 10) }
-func BenchmarkMemmoveUnalignedSrc11(b *testing.B) { bmMemmoveUnalignedSrc(b, 11) }
-func BenchmarkMemmoveUnalignedSrc12(b *testing.B) { bmMemmoveUnalignedSrc(b, 12) }
-func BenchmarkMemmoveUnalignedSrc13(b *testing.B) { bmMemmoveUnalignedSrc(b, 13) }
-func BenchmarkMemmoveUnalignedSrc14(b *testing.B) { bmMemmoveUnalignedSrc(b, 14) }
-func BenchmarkMemmoveUnalignedSrc15(b *testing.B) { bmMemmoveUnalignedSrc(b, 15) }
-func BenchmarkMemmoveUnalignedSrc16(b *testing.B) { bmMemmoveUnalignedSrc(b, 16) }
-func BenchmarkMemmoveUnalignedSrc32(b *testing.B) { bmMemmoveUnalignedSrc(b, 32) }
-func BenchmarkMemmoveUnalignedSrc64(b *testing.B) { bmMemmoveUnalignedSrc(b, 64) }
-func BenchmarkMemmoveUnalignedSrc128(b *testing.B) { bmMemmoveUnalignedSrc(b, 128) }
-func BenchmarkMemmoveUnalignedSrc256(b *testing.B) { bmMemmoveUnalignedSrc(b, 256) }
-func BenchmarkMemmoveUnalignedSrc512(b *testing.B) { bmMemmoveUnalignedSrc(b, 512) }
-func BenchmarkMemmoveUnalignedSrc1024(b *testing.B) { bmMemmoveUnalignedSrc(b, 1024) }
-func BenchmarkMemmoveUnalignedSrc2048(b *testing.B) { bmMemmoveUnalignedSrc(b, 2048) }
-func BenchmarkMemmoveUnalignedSrc4096(b *testing.B) { bmMemmoveUnalignedSrc(b, 4096) }
+func BenchmarkMemmoveUnalignedSrc(b *testing.B) {
+ benchmarkSizes(b, bufSizes, func(b *testing.B, n int) {
+ x := make([]byte, n)
+ y := make([]byte, n+1)
+ for i := 0; i < b.N; i++ {
+ copy(x, y[1:])
+ }
+ })
+}
func TestMemclr(t *testing.T) {
size := 512
}
}
-func bmMemclr(b *testing.B, n int) {
- x := make([]byte, n)
- b.SetBytes(int64(n))
- for i := 0; i < b.N; i++ {
- MemclrBytes(x)
- }
-}
-func BenchmarkMemclr5(b *testing.B) { bmMemclr(b, 5) }
-func BenchmarkMemclr16(b *testing.B) { bmMemclr(b, 16) }
-func BenchmarkMemclr64(b *testing.B) { bmMemclr(b, 64) }
-func BenchmarkMemclr256(b *testing.B) { bmMemclr(b, 256) }
-func BenchmarkMemclr4096(b *testing.B) { bmMemclr(b, 4096) }
-func BenchmarkMemclr65536(b *testing.B) { bmMemclr(b, 65536) }
-func BenchmarkMemclr1M(b *testing.B) { bmMemclr(b, 1<<20) }
-func BenchmarkMemclr4M(b *testing.B) { bmMemclr(b, 4<<20) }
-func BenchmarkMemclr8M(b *testing.B) { bmMemclr(b, 8<<20) }
-func BenchmarkMemclr16M(b *testing.B) { bmMemclr(b, 16<<20) }
-func BenchmarkMemclr64M(b *testing.B) { bmMemclr(b, 64<<20) }
+func BenchmarkMemclr(b *testing.B) {
+ for _, n := range []int{5, 16, 64, 256, 4096, 65536} {
+ x := make([]byte, n)
+ b.Run(fmt.Sprint(n), func(b *testing.B) {
+ b.SetBytes(int64(n))
+ for i := 0; i < b.N; i++ {
+ MemclrBytes(x)
+ }
+ })
+ }
+ for _, m := range []int{1, 4, 8, 16, 64} {
+ x := make([]byte, m<<20)
+ b.Run(fmt.Sprint(m, "M"), func(b *testing.B) {
+ b.SetBytes(int64(m << 20))
+ for i := 0; i < b.N; i++ {
+ MemclrBytes(x)
+ }
+ })
+ }
+}
-func bmGoMemclr(b *testing.B, n int) {
- x := make([]byte, n)
- b.SetBytes(int64(n))
- for i := 0; i < b.N; i++ {
- for j := range x {
- x[j] = 0
+func BenchmarkGoMemclr(b *testing.B) {
+ benchmarkSizes(b, []int{5, 16, 64, 256}, func(b *testing.B, n int) {
+ x := make([]byte, n)
+ for i := 0; i < b.N; i++ {
+ for j := range x {
+ x[j] = 0
+ }
}
- }
+ })
}
-func BenchmarkGoMemclr5(b *testing.B) { bmGoMemclr(b, 5) }
-func BenchmarkGoMemclr16(b *testing.B) { bmGoMemclr(b, 16) }
-func BenchmarkGoMemclr64(b *testing.B) { bmGoMemclr(b, 64) }
-func BenchmarkGoMemclr256(b *testing.B) { bmGoMemclr(b, 256) }
func BenchmarkClearFat8(b *testing.B) {
for i := 0; i < b.N; i++ {
// in initializers for package-level variables. Such objects may be
// linker-allocated, not heap-allocated.
//
+// A finalizer may run as soon as an object becomes unreachable.
+// In order to use finalizers correctly, the program must ensure that
+// the object is reachable until it is no longer required.
+// Objects stored in global variables, or that can be found by tracing
+// pointers from a global variable, are reachable. For other objects,
+// pass the object to a call of the KeepAlive function to mark the
+// last point in the function where the object must be reachable.
+//
+// For example, if p points to a struct that contains a file descriptor d,
+// and p has a finalizer that closes that file descriptor, and if the last
+// use of p in a function is a call to syscall.Write(p.d, buf, size), then
+// p may be unreachable as soon as the program enters syscall.Write. The
+// finalizer may run at that moment, closing p.d, causing syscall.Write
+// to fail because it is writing to a closed file descriptor (or, worse,
+// to an entirely different file descriptor opened by a different goroutine).
+// To avoid this problem, call runtime.KeepAlive(p) after the call to
+// syscall.Write.
+//
// A single goroutine runs all finalizers for a program, sequentially.
// If a finalizer must run for a long time, it should do so by starting
// a new goroutine.
}
return
}
+
+// Mark KeepAlive as noinline so that the current compiler will ensure
+// that the argument is alive at the point of the function call.
+// If it were inlined, it would disappear, and there would be nothing
+// keeping the argument alive. Perhaps a future compiler will recognize
+// runtime.KeepAlive specially and do something more efficient.
+//go:noinline
+
+// KeepAlive marks its argument as currently reachable.
+// This ensures that the object is not freed, and its finalizer is not run,
+// before the point in the program where KeepAlive is called.
+//
+// A very simplified example showing where KeepAlive is required:
+// type File struct { d int }
+// d, err := syscall.Open("/file/path", syscall.O_RDONLY, 0)
+// // ... do something if err != nil ...
+// p := &FILE{d}
+// runtime.SetFinalizer(p, func(p *File) { syscall.Close(p.d) })
+// var buf [10]byte
+// n, err := syscall.Read(p.d, buf[:])
+// // Ensure p is not finalized until Read returns.
+// runtime.KeepAlive(p)
+// // No more uses of p after this point.
+//
+// Without the KeepAlive call, the finalizer could run at the start of
+// syscall.Read, closing the file descriptor before syscall.Read makes
+// the actual system call.
+func KeepAlive(interface{}) {}
notewakeup(&work.bgMarkReady)
for {
- // Go to sleep until woken by gcContoller.findRunnable.
+ // Go to sleep until woken by gcController.findRunnable.
// We can't releasem yet since even the call to gopark
// may be preempted.
gopark(func(g *g, parkp unsafe.Pointer) bool {
lock(&sweep.lock)
if sweep.parked {
sweep.parked = false
- ready(sweep.g, 0)
+ ready(sweep.g, 0, true)
}
unlock(&sweep.lock)
mProf_GC()
// Only do this once per GC cycle; preferably
// concurrently.
if !work.markrootDone {
- markrootFreeGStacks()
+ // Switch to the system stack so we can call
+ // stackfree.
+ systemstack(markrootFreeGStacks)
}
case baseSpans <= i && i < baseStacks:
// we scan the stacks we can and ask running
// goroutines to scan themselves; and the
// second blocks.
- scang(gp)
+ scang(gp, gcw)
if selfScan {
casgstatus(userG, _Gwaiting, _Grunning)
gp.gcAssistBytes = 0
xgp := gp
gp = gp.schedlink.ptr()
- ready(xgp, 0)
+ // It's important that we *not* put xgp in
+ // runnext. Otherwise, it's possible for user
+ // code to exploit the GC worker's high
+ // scheduler priority to get itself always run
+ // before other goroutines and always in the
+ // fresh quantum started by GC.
+ ready(xgp, 0, false)
} else {
// Partially satisfy this assist.
gp.gcAssistBytes += scanBytes
unlock(&work.assistQueue.lock)
}
+// scanstack scans gp's stack, greying all pointers found on the stack.
+//
+// During mark phase, it also installs stack barriers while traversing
+// gp's stack. During mark termination, it stops scanning when it
+// reaches an unhit stack barrier.
+//
+// scanstack is marked go:systemstack because it must not be preempted
+// while using a workbuf.
+//
//go:nowritebarrier
-func scanstack(gp *g) {
+//go:systemstack
+func scanstack(gp *g, gcw *gcWork) {
if gp.gcscanvalid {
return
}
// Scan the stack.
var cache pcvalueCache
- gcw := &getg().m.p.ptr().gcw
n := 0
scanframe := func(frame *stkframe, unused unsafe.Pointer) bool {
scanframeworker(frame, &cache, gcw)
}
gentraceback(^uintptr(0), ^uintptr(0), 0, gp, 0, nil, 0x7fffffff, scanframe, nil, 0)
tracebackdefers(gp, scanframe, nil)
- if gcphase == _GCmarktermination {
- gcw.dispose()
- }
gcUnlockStackBarriers(gp)
if gcphase == _GCmark {
// gp may have added itself to the rescan list between
// scanobject scans the object starting at b, adding pointers to gcw.
// b must point to the beginning of a heap object; scanobject consults
// the GC bitmap for the pointer mask and the spans for the size of the
-// object (it ignores n).
+// object.
//go:nowritebarrier
func scanobject(b uintptr, gcw *gcWork) {
// Note that arena_used may change concurrently during
nsmallfree [_NumSizeClasses]uint64 // number of frees for small objects (<=maxsmallsize)
// range of addresses we might see in the heap
- bitmap uintptr
+ bitmap uintptr // Points to one byte past the end of the bitmap
bitmap_mapped uintptr
arena_start uintptr
arena_used uintptr // always mHeap_Map{Bits,Spans} before updating
return true
}
+// inHeapOrStack is a variant of inheap that returns true for pointers into stack spans.
+//go:nowritebarrier
+//go:nosplit
+func inHeapOrStack(b uintptr) bool {
+ if b == 0 || b < mheap_.arena_start || b >= mheap_.arena_used {
+ return false
+ }
+ // Not a beginning of a block, consult span table to find the block beginning.
+ s := h_spans[(b-mheap_.arena_start)>>_PageShift]
+ if s == nil || b < s.base() {
+ return false
+ }
+ switch s.state {
+ case mSpanInUse:
+ return b < s.limit
+ case _MSpanStack:
+ return b < s.base()+s.npages<<_PageShift
+ default:
+ return false
+ }
+}
+
// TODO: spanOf and spanOfUnchecked are open-coded in a lot of places.
// Use the functions instead.
}
}
-const gcBitsChunkBytes = uintptr(1 << 16)
+const gcBitsChunkBytes = uintptr(64 << 10)
const gcBitsHeaderBytes = unsafe.Sizeof(gcBitsHeader{})
type gcBitsHeader struct {
+++ /dev/null
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package runtime
-
-import (
- "runtime/internal/sys"
- "unsafe"
-)
-
-// From FreeBSD's <sys/sysctl.h>
-const (
- _CTL_HW = 6
- _HW_NCPU = 3
-)
-
-var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
-
-func getncpu() int32 {
- mib := [2]uint32{_CTL_HW, _HW_NCPU}
- out := uint32(0)
- nout := unsafe.Sizeof(out)
- ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
- if ret >= 0 {
- return int32(out)
- }
- return 1
-}
-
-// FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and
-// thus the code is largely similar. See Linux implementation
-// and lock_futex.go for comments.
-
-//go:nosplit
-func futexsleep(addr *uint32, val uint32, ns int64) {
- systemstack(func() {
- futexsleep1(addr, val, ns)
- })
-}
-
-func futexsleep1(addr *uint32, val uint32, ns int64) {
- var tsp *timespec
- if ns >= 0 {
- var ts timespec
- ts.tv_nsec = 0
- ts.set_sec(int64(timediv(ns, 1000000000, (*int32)(unsafe.Pointer(&ts.tv_nsec)))))
- tsp = &ts
- }
- ret := sys_umtx_op(addr, _UMTX_OP_WAIT_UINT_PRIVATE, val, nil, tsp)
- if ret >= 0 || ret == -_EINTR {
- return
- }
- print("umtx_wait addr=", addr, " val=", val, " ret=", ret, "\n")
- *(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005
-}
-
-//go:nosplit
-func futexwakeup(addr *uint32, cnt uint32) {
- ret := sys_umtx_op(addr, _UMTX_OP_WAKE_PRIVATE, cnt, nil, nil)
- if ret >= 0 {
- return
- }
-
- systemstack(func() {
- print("umtx_wake_addr=", addr, " ret=", ret, "\n")
- })
-}
-
-func thr_start()
-
-// May run with m.p==nil, so write barriers are not allowed.
-//go:nowritebarrier
-func newosproc(mp *m, stk unsafe.Pointer) {
- if false {
- print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " thr_start=", funcPC(thr_start), " id=", mp.id, " ostk=", &mp, "\n")
- }
-
- // NOTE(rsc): This code is confused. stackbase is the top of the stack
- // and is equal to stk. However, it's working, so I'm not changing it.
- param := thrparam{
- start_func: funcPC(thr_start),
- arg: unsafe.Pointer(mp),
- stack_base: mp.g0.stack.hi,
- stack_size: uintptr(stk) - mp.g0.stack.hi,
- child_tid: unsafe.Pointer(&mp.procid),
- parent_tid: nil,
- tls_base: unsafe.Pointer(&mp.tls[0]),
- tls_size: unsafe.Sizeof(mp.tls),
- }
-
- var oset sigset
- sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
- thr_new(¶m, int32(unsafe.Sizeof(param)))
- sigprocmask(_SIG_SETMASK, &oset, nil)
-}
-
-func osinit() {
- ncpu = getncpu()
-}
-
-var urandom_dev = []byte("/dev/urandom\x00")
-
-//go:nosplit
-func getRandomData(r []byte) {
- fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
- n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
- closefd(fd)
- extendRandom(r, int(n))
-}
-
-func goenvs() {
- goenvs_unix()
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
-func mpreinit(mp *m) {
- mp.gsignal = malg(32 * 1024)
- mp.gsignal.m = mp
-}
-
-//go:nosplit
-func msigsave(mp *m) {
- sigprocmask(_SIG_SETMASK, nil, &mp.sigmask)
-}
-
-//go:nosplit
-func msigrestore(sigmask sigset) {
- sigprocmask(_SIG_SETMASK, &sigmask, nil)
-}
-
-//go:nosplit
-func sigblock() {
- sigprocmask(_SIG_SETMASK, &sigset_all, nil)
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, cannot allocate memory.
-func minit() {
- _g_ := getg()
-
- // m.procid is a uint64, but thr_new writes a uint32 on 32-bit systems.
- // Fix it up. (Only matters on big-endian, but be clean anyway.)
- if sys.PtrSize == 4 {
- _g_.m.procid = uint64(*(*uint32)(unsafe.Pointer(&_g_.m.procid)))
- }
-
- // Initialize signal handling.
- var st stackt
- sigaltstack(nil, &st)
- if st.ss_flags&_SS_DISABLE != 0 {
- signalstack(&_g_.m.gsignal.stack)
- _g_.m.newSigstack = true
- } else {
- // Use existing signal stack.
- stsp := uintptr(unsafe.Pointer(st.ss_sp))
- _g_.m.gsignal.stack.lo = stsp
- _g_.m.gsignal.stack.hi = stsp + st.ss_size
- _g_.m.gsignal.stackguard0 = stsp + _StackGuard
- _g_.m.gsignal.stackguard1 = stsp + _StackGuard
- _g_.m.gsignal.stackAlloc = st.ss_size
- _g_.m.newSigstack = false
- }
-
- // restore signal mask from m.sigmask and unblock essential signals
- nmask := _g_.m.sigmask
- for i := range sigtable {
- if sigtable[i].flags&_SigUnblock != 0 {
- nmask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
- }
- }
- sigprocmask(_SIG_SETMASK, &nmask, nil)
-}
-
-// Called from dropm to undo the effect of an minit.
-//go:nosplit
-func unminit() {
- if getg().m.newSigstack {
- signalstack(nil)
- }
-}
-
-func memlimit() uintptr {
- /*
- TODO: Convert to Go when something actually uses the result.
- Rlimit rl;
- extern byte runtime·text[], runtime·end[];
- uintptr used;
-
- if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
- return 0;
- if(rl.rlim_cur >= 0x7fffffff)
- return 0;
-
- // Estimate our VM footprint excluding the heap.
- // Not an exact science: use size of binary plus
- // some room for thread stacks.
- used = runtime·end - runtime·text + (64<<20);
- if(used >= rl.rlim_cur)
- return 0;
-
- // If there's not at least 16 MB left, we're probably
- // not going to be able to do much. Treat as no limit.
- rl.rlim_cur -= used;
- if(rl.rlim_cur < (16<<20))
- return 0;
-
- return rl.rlim_cur - used;
- */
-
- return 0
-}
-
-func sigtramp()
-
-type sigactiont struct {
- sa_handler uintptr
- sa_flags int32
- sa_mask sigset
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-func setsig(i int32, fn uintptr, restart bool) {
- var sa sigactiont
- sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
- if restart {
- sa.sa_flags |= _SA_RESTART
- }
- sa.sa_mask = sigset_all
- if fn == funcPC(sighandler) {
- fn = funcPC(sigtramp)
- }
- sa.sa_handler = fn
- sigaction(i, &sa, nil)
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-func setsigstack(i int32) {
- throw("setsigstack")
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-func getsig(i int32) uintptr {
- var sa sigactiont
- sigaction(i, nil, &sa)
- if sa.sa_handler == funcPC(sigtramp) {
- return funcPC(sighandler)
- }
- return sa.sa_handler
-}
-
-//go:nosplit
-func signalstack(s *stack) {
- var st stackt
- if s == nil {
- st.ss_flags = _SS_DISABLE
- } else {
- st.ss_sp = s.lo
- st.ss_size = s.hi - s.lo
- st.ss_flags = 0
- }
- sigaltstack(&st, nil)
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-func updatesigmask(m [(_NSIG + 31) / 32]uint32) {
- var mask sigset
- copy(mask.__bits[:], m[:])
- sigprocmask(_SIG_SETMASK, &mask, nil)
-}
-
-func unblocksig(sig int32) {
- var mask sigset
- mask.__bits[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31)
- sigprocmask(_SIG_UNBLOCK, &mask, nil)
-}
+++ /dev/null
-// Copyright 2010 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 runtime
-
-import "unsafe"
-
-type sigset struct{}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
-func mpreinit(mp *m) {
- mp.gsignal = malg(32 * 1024)
- mp.gsignal.m = mp
-}
-
-func sigtramp()
-
-//go:nosplit
-func msigsave(mp *m) {
-}
-
-//go:nosplit
-func msigrestore(sigmask sigset) {
-}
-
-//go:nosplit
-func sigblock() {
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, cannot allocate memory.
-func minit() {
- _g_ := getg()
-
- // Initialize signal handling
- ret := nacl_exception_stack(_g_.m.gsignal.stack.lo, 32*1024)
- if ret < 0 {
- print("runtime: nacl_exception_stack: error ", -ret, "\n")
- }
-
- ret = nacl_exception_handler(funcPC(sigtramp), nil)
- if ret < 0 {
- print("runtime: nacl_exception_handler: error ", -ret, "\n")
- }
-}
-
-// Called from dropm to undo the effect of an minit.
-func unminit() {
-}
-
-func osinit() {
- ncpu = 1
- getg().m.procid = 2
- //nacl_exception_handler(funcPC(sigtramp), nil);
-}
-
-func signame(sig uint32) string {
- if sig >= uint32(len(sigtable)) {
- return ""
- }
- return sigtable[sig].name
-}
-
-func crash() {
- *(*int32)(nil) = 0
-}
-
-//go:noescape
-func getRandomData([]byte)
-
-func goenvs() {
- goenvs_unix()
-}
-
-func initsig(preinit bool) {
-}
-
-//go:nosplit
-func usleep(us uint32) {
- var ts timespec
-
- ts.tv_sec = int64(us / 1e6)
- ts.tv_nsec = int32(us%1e6) * 1e3
- nacl_nanosleep(&ts, nil)
-}
-
-func mstart_nacl()
-
-// May run with m.p==nil, so write barriers are not allowed.
-//go:nowritebarrier
-func newosproc(mp *m, stk unsafe.Pointer) {
- mp.tls[0] = uintptr(unsafe.Pointer(mp.g0))
- mp.tls[1] = uintptr(unsafe.Pointer(mp))
- ret := nacl_thread_create(funcPC(mstart_nacl), stk, unsafe.Pointer(&mp.tls[2]), nil)
- if ret < 0 {
- print("nacl_thread_create: error ", -ret, "\n")
- throw("newosproc")
- }
-}
-
-//go:nosplit
-func semacreate(mp *m) {
- if mp.waitsema != 0 {
- return
- }
- systemstack(func() {
- mu := nacl_mutex_create(0)
- if mu < 0 {
- print("nacl_mutex_create: error ", -mu, "\n")
- throw("semacreate")
- }
- c := nacl_cond_create(0)
- if c < 0 {
- print("nacl_cond_create: error ", -c, "\n")
- throw("semacreate")
- }
- mp.waitsema = c
- mp.waitsemalock = mu
- })
-}
-
-//go:nosplit
-func semasleep(ns int64) int32 {
- var ret int32
-
- systemstack(func() {
- _g_ := getg()
- if nacl_mutex_lock(_g_.m.waitsemalock) < 0 {
- throw("semasleep")
- }
-
- for _g_.m.waitsemacount == 0 {
- if ns < 0 {
- if nacl_cond_wait(_g_.m.waitsema, _g_.m.waitsemalock) < 0 {
- throw("semasleep")
- }
- } else {
- var ts timespec
- end := ns + nanotime()
- ts.tv_sec = end / 1e9
- ts.tv_nsec = int32(end % 1e9)
- r := nacl_cond_timed_wait_abs(_g_.m.waitsema, _g_.m.waitsemalock, &ts)
- if r == -_ETIMEDOUT {
- nacl_mutex_unlock(_g_.m.waitsemalock)
- ret = -1
- return
- }
- if r < 0 {
- throw("semasleep")
- }
- }
- }
-
- _g_.m.waitsemacount = 0
- nacl_mutex_unlock(_g_.m.waitsemalock)
- ret = 0
- })
- return ret
-}
-
-//go:nosplit
-func semawakeup(mp *m) {
- systemstack(func() {
- if nacl_mutex_lock(mp.waitsemalock) < 0 {
- throw("semawakeup")
- }
- if mp.waitsemacount != 0 {
- throw("semawakeup")
- }
- mp.waitsemacount = 1
- nacl_cond_signal(mp.waitsema)
- nacl_mutex_unlock(mp.waitsemalock)
- })
-}
-
-func memlimit() uintptr {
- return 0
-}
-
-// This runs on a foreign stack, without an m or a g. No stack split.
-//go:nosplit
-//go:norace
-//go:nowritebarrierrec
-func badsignal(sig uintptr) {
- cgocallback(unsafe.Pointer(funcPC(badsignalgo)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig))
-}
-
-func badsignalgo(sig uintptr) {
- if !sigsend(uint32(sig)) {
- // A foreign thread received the signal sig, and the
- // Go code does not want to handle it.
- raisebadsignal(int32(sig))
- }
-}
-
-// This runs on a foreign stack, without an m or a g. No stack split.
-//go:nosplit
-func badsignal2() {
- write(2, unsafe.Pointer(&badsignal1[0]), int32(len(badsignal1)))
- exit(2)
-}
-
-var badsignal1 = []byte("runtime: signal received on thread not created by Go.\n")
-
-func raisebadsignal(sig int32) {
- badsignal2()
-}
-
-func madvise(addr unsafe.Pointer, n uintptr, flags int32) {}
-func munmap(addr unsafe.Pointer, n uintptr) {}
-func resetcpuprofiler(hz int32) {}
-func sigdisable(uint32) {}
-func sigenable(uint32) {}
-func sigignore(uint32) {}
-func closeonexec(int32) {}
-
-var writelock uint32 // test-and-set spin lock for write
-
-/*
-An attempt at IRT. Doesn't work. See end of sys_nacl_amd64.s.
-
-void (*nacl_irt_query)(void);
-
-int8 nacl_irt_basic_v0_1_str[] = "nacl-irt-basic-0.1";
-void *nacl_irt_basic_v0_1[6]; // exit, gettod, clock, nanosleep, sched_yield, sysconf
-int32 nacl_irt_basic_v0_1_size = sizeof(nacl_irt_basic_v0_1);
-
-int8 nacl_irt_memory_v0_3_str[] = "nacl-irt-memory-0.3";
-void *nacl_irt_memory_v0_3[3]; // mmap, munmap, mprotect
-int32 nacl_irt_memory_v0_3_size = sizeof(nacl_irt_memory_v0_3);
-
-int8 nacl_irt_thread_v0_1_str[] = "nacl-irt-thread-0.1";
-void *nacl_irt_thread_v0_1[3]; // thread_create, thread_exit, thread_nice
-int32 nacl_irt_thread_v0_1_size = sizeof(nacl_irt_thread_v0_1);
-*/
+++ /dev/null
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package runtime
-
-import (
- "runtime/internal/atomic"
- "unsafe"
-)
-
-const (
- _ESRCH = 3
- _EAGAIN = 35
- _EWOULDBLOCK = _EAGAIN
- _ENOTSUP = 91
-
- // From OpenBSD's sys/time.h
- _CLOCK_REALTIME = 0
- _CLOCK_VIRTUAL = 1
- _CLOCK_PROF = 2
- _CLOCK_MONOTONIC = 3
-)
-
-type sigset uint32
-
-const (
- sigset_none = sigset(0)
- sigset_all = ^sigset(0)
-)
-
-// From OpenBSD's <sys/sysctl.h>
-const (
- _CTL_HW = 6
- _HW_NCPU = 3
-)
-
-func getncpu() int32 {
- mib := [2]uint32{_CTL_HW, _HW_NCPU}
- out := uint32(0)
- nout := unsafe.Sizeof(out)
-
- // Fetch hw.ncpu via sysctl.
- ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
- if ret >= 0 {
- return int32(out)
- }
- return 1
-}
-
-//go:nosplit
-func semacreate(mp *m) {
-}
-
-//go:nosplit
-func semasleep(ns int64) int32 {
- _g_ := getg()
-
- // Compute sleep deadline.
- var tsp *timespec
- if ns >= 0 {
- var ts timespec
- var nsec int32
- ns += nanotime()
- ts.set_sec(int64(timediv(ns, 1000000000, &nsec)))
- ts.set_nsec(nsec)
- tsp = &ts
- }
-
- for {
- v := atomic.Load(&_g_.m.waitsemacount)
- if v > 0 {
- if atomic.Cas(&_g_.m.waitsemacount, v, v-1) {
- return 0 // semaphore acquired
- }
- continue
- }
-
- // Sleep until woken by semawakeup or timeout; or abort if waitsemacount != 0.
- //
- // From OpenBSD's __thrsleep(2) manual:
- // "The abort argument, if not NULL, points to an int that will
- // be examined [...] immediately before blocking. If that int
- // is non-zero then __thrsleep() will immediately return EINTR
- // without blocking."
- ret := thrsleep(uintptr(unsafe.Pointer(&_g_.m.waitsemacount)), _CLOCK_MONOTONIC, tsp, 0, &_g_.m.waitsemacount)
- if ret == _EWOULDBLOCK {
- return -1
- }
- }
-}
-
-//go:nosplit
-func semawakeup(mp *m) {
- atomic.Xadd(&mp.waitsemacount, 1)
- ret := thrwakeup(uintptr(unsafe.Pointer(&mp.waitsemacount)), 1)
- if ret != 0 && ret != _ESRCH {
- // semawakeup can be called on signal stack.
- systemstack(func() {
- print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n")
- })
- }
-}
-
-// May run with m.p==nil, so write barriers are not allowed.
-//go:nowritebarrier
-func newosproc(mp *m, stk unsafe.Pointer) {
- if false {
- print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, " ostk=", &mp, "\n")
- }
-
- param := tforkt{
- tf_tcb: unsafe.Pointer(&mp.tls[0]),
- tf_tid: (*int32)(unsafe.Pointer(&mp.procid)),
- tf_stack: uintptr(stk),
- }
-
- oset := sigprocmask(_SIG_SETMASK, sigset_all)
- ret := tfork(¶m, unsafe.Sizeof(param), mp, mp.g0, funcPC(mstart))
- sigprocmask(_SIG_SETMASK, oset)
-
- if ret < 0 {
- print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n")
- throw("runtime.newosproc")
- }
-}
-
-func osinit() {
- ncpu = getncpu()
-}
-
-var urandom_dev = []byte("/dev/urandom\x00")
-
-//go:nosplit
-func getRandomData(r []byte) {
- fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
- n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
- closefd(fd)
- extendRandom(r, int(n))
-}
-
-func goenvs() {
- goenvs_unix()
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
-func mpreinit(mp *m) {
- mp.gsignal = malg(32 * 1024)
- mp.gsignal.m = mp
-}
-
-//go:nosplit
-func msigsave(mp *m) {
- mp.sigmask = sigprocmask(_SIG_BLOCK, 0)
-}
-
-//go:nosplit
-func msigrestore(sigmask sigset) {
- sigprocmask(_SIG_SETMASK, sigmask)
-}
-
-//go:nosplit
-func sigblock() {
- sigprocmask(_SIG_SETMASK, sigset_all)
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
-func minit() {
- _g_ := getg()
-
- // m.procid is a uint64, but tfork writes an int32. Fix it up.
- _g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid)))
-
- // Initialize signal handling
- var st stackt
- sigaltstack(nil, &st)
- if st.ss_flags&_SS_DISABLE != 0 {
- signalstack(&_g_.m.gsignal.stack)
- _g_.m.newSigstack = true
- } else {
- // Use existing signal stack.
- stsp := uintptr(unsafe.Pointer(st.ss_sp))
- _g_.m.gsignal.stack.lo = stsp
- _g_.m.gsignal.stack.hi = stsp + st.ss_size
- _g_.m.gsignal.stackguard0 = stsp + _StackGuard
- _g_.m.gsignal.stackguard1 = stsp + _StackGuard
- _g_.m.gsignal.stackAlloc = st.ss_size
- _g_.m.newSigstack = false
- }
-
- // restore signal mask from m.sigmask and unblock essential signals
- nmask := _g_.m.sigmask
- for i := range sigtable {
- if sigtable[i].flags&_SigUnblock != 0 {
- nmask &^= 1 << (uint32(i) - 1)
- }
- }
- sigprocmask(_SIG_SETMASK, nmask)
-}
-
-// Called from dropm to undo the effect of an minit.
-//go:nosplit
-func unminit() {
- if getg().m.newSigstack {
- signalstack(nil)
- }
-}
-
-func memlimit() uintptr {
- return 0
-}
-
-func sigtramp()
-
-type sigactiont struct {
- sa_sigaction uintptr
- sa_mask uint32
- sa_flags int32
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-func setsig(i int32, fn uintptr, restart bool) {
- var sa sigactiont
- sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
- if restart {
- sa.sa_flags |= _SA_RESTART
- }
- sa.sa_mask = uint32(sigset_all)
- if fn == funcPC(sighandler) {
- fn = funcPC(sigtramp)
- }
- sa.sa_sigaction = fn
- sigaction(i, &sa, nil)
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-func setsigstack(i int32) {
- throw("setsigstack")
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-func getsig(i int32) uintptr {
- var sa sigactiont
- sigaction(i, nil, &sa)
- if sa.sa_sigaction == funcPC(sigtramp) {
- return funcPC(sighandler)
- }
- return sa.sa_sigaction
-}
-
-//go:nosplit
-func signalstack(s *stack) {
- var st stackt
- if s == nil {
- st.ss_flags = _SS_DISABLE
- } else {
- st.ss_sp = s.lo
- st.ss_size = s.hi - s.lo
- st.ss_flags = 0
- }
- sigaltstack(&st, nil)
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-func updatesigmask(m sigmask) {
- sigprocmask(_SIG_SETMASK, sigset(m[0]))
-}
-
-func unblocksig(sig int32) {
- mask := sigset(1) << (uint32(sig) - 1)
- sigprocmask(_SIG_UNBLOCK, mask)
-}
+++ /dev/null
-// Copyright 2010 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 runtime
-
-import (
- "runtime/internal/atomic"
- "unsafe"
-)
-
-type sigset struct{}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
-func mpreinit(mp *m) {
- // Initialize stack and goroutine for note handling.
- mp.gsignal = malg(32 * 1024)
- mp.gsignal.m = mp
- mp.notesig = (*int8)(mallocgc(_ERRMAX, nil, true))
- // Initialize stack for handling strings from the
- // errstr system call, as used in package syscall.
- mp.errstr = (*byte)(mallocgc(_ERRMAX, nil, true))
-}
-
-func msigsave(mp *m) {
-}
-
-func msigrestore(sigmask sigset) {
-}
-
-func sigblock() {
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, cannot allocate memory.
-func minit() {
- if atomic.Load(&exiting) != 0 {
- exits(&emptystatus[0])
- }
- // Mask all SSE floating-point exceptions
- // when running on the 64-bit kernel.
- setfpmasks()
-}
-
-// Called from dropm to undo the effect of an minit.
-func unminit() {
-}
-
-var sysstat = []byte("/dev/sysstat\x00")
-
-func getproccount() int32 {
- var buf [2048]byte
- fd := open(&sysstat[0], _OREAD, 0)
- if fd < 0 {
- return 1
- }
- ncpu := int32(0)
- for {
- n := read(fd, unsafe.Pointer(&buf), int32(len(buf)))
- if n <= 0 {
- break
- }
- for i := int32(0); i < n; i++ {
- if buf[i] == '\n' {
- ncpu++
- }
- }
- }
- closefd(fd)
- if ncpu == 0 {
- ncpu = 1
- }
- return ncpu
-}
-
-var pid = []byte("#c/pid\x00")
-
-func getpid() uint64 {
- var b [20]byte
- fd := open(&pid[0], 0, 0)
- if fd >= 0 {
- read(fd, unsafe.Pointer(&b), int32(len(b)))
- closefd(fd)
- }
- c := b[:]
- for c[0] == ' ' || c[0] == '\t' {
- c = c[1:]
- }
- return uint64(_atoi(c))
-}
-
-func osinit() {
- initBloc()
- ncpu = getproccount()
- getg().m.procid = getpid()
- notify(unsafe.Pointer(funcPC(sigtramp)))
-}
-
-func crash() {
- notify(nil)
- *(*int)(nil) = 0
-}
-
-//go:nosplit
-func getRandomData(r []byte) {
- extendRandom(r, 0)
-}
-
-func goenvs() {
-}
-
-func initsig(preinit bool) {
-}
-
-//go:nosplit
-func osyield() {
- sleep(0)
-}
-
-//go:nosplit
-func usleep(µs uint32) {
- ms := int32(µs / 1000)
- if ms == 0 {
- ms = 1
- }
- sleep(ms)
-}
-
-//go:nosplit
-func nanotime() int64 {
- var scratch int64
- ns := nsec(&scratch)
- // TODO(aram): remove hack after I fix _nsec in the pc64 kernel.
- if ns == 0 {
- return scratch
- }
- return ns
-}
-
-//go:nosplit
-func itoa(buf []byte, val uint64) []byte {
- i := len(buf) - 1
- for val >= 10 {
- buf[i] = byte(val%10 + '0')
- i--
- val /= 10
- }
- buf[i] = byte(val + '0')
- return buf[i:]
-}
-
-var goexits = []byte("go: exit ")
-var emptystatus = []byte("\x00")
-var exiting uint32
-
-func goexitsall(status *byte) {
- var buf [_ERRMAX]byte
- if !atomic.Cas(&exiting, 0, 1) {
- return
- }
- getg().m.locks++
- n := copy(buf[:], goexits)
- n = copy(buf[n:], gostringnocopy(status))
- pid := getpid()
- for mp := (*m)(atomic.Loadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink {
- if mp.procid != 0 && mp.procid != pid {
- postnote(mp.procid, buf[:])
- }
- }
- getg().m.locks--
-}
-
-var procdir = []byte("/proc/")
-var notefile = []byte("/note\x00")
-
-func postnote(pid uint64, msg []byte) int {
- var buf [128]byte
- var tmp [32]byte
- n := copy(buf[:], procdir)
- n += copy(buf[n:], itoa(tmp[:], pid))
- copy(buf[n:], notefile)
- fd := open(&buf[0], _OWRITE, 0)
- if fd < 0 {
- return -1
- }
- len := findnull(&msg[0])
- if write(uintptr(fd), unsafe.Pointer(&msg[0]), int32(len)) != int64(len) {
- closefd(fd)
- return -1
- }
- closefd(fd)
- return 0
-}
-
-//go:nosplit
-func exit(e int) {
- var status []byte
- if e == 0 {
- status = emptystatus
- } else {
- // build error string
- var tmp [32]byte
- status = append(itoa(tmp[:len(tmp)-1], uint64(e)), 0)
- }
- goexitsall(&status[0])
- exits(&status[0])
-}
-
-// May run with m.p==nil, so write barriers are not allowed.
-//go:nowritebarrier
-func newosproc(mp *m, stk unsafe.Pointer) {
- if false {
- print("newosproc mp=", mp, " ostk=", &mp, "\n")
- }
- pid := rfork(_RFPROC | _RFMEM | _RFNOWAIT)
- if pid < 0 {
- throw("newosproc: rfork failed")
- }
- if pid == 0 {
- tstart_plan9(mp)
- }
-}
-
-//go:nosplit
-func semacreate(mp *m) {
-}
-
-//go:nosplit
-func semasleep(ns int64) int {
- _g_ := getg()
- if ns >= 0 {
- ms := timediv(ns, 1000000, nil)
- if ms == 0 {
- ms = 1
- }
- ret := plan9_tsemacquire(&_g_.m.waitsemacount, ms)
- if ret == 1 {
- return 0 // success
- }
- return -1 // timeout or interrupted
- }
- for plan9_semacquire(&_g_.m.waitsemacount, 1) < 0 {
- // interrupted; try again (c.f. lock_sema.go)
- }
- return 0 // success
-}
-
-//go:nosplit
-func semawakeup(mp *m) {
- plan9_semrelease(&mp.waitsemacount, 1)
-}
-
-//go:nosplit
-func read(fd int32, buf unsafe.Pointer, n int32) int32 {
- return pread(fd, buf, n, -1)
-}
-
-//go:nosplit
-func write(fd uintptr, buf unsafe.Pointer, n int32) int64 {
- return int64(pwrite(int32(fd), buf, n, -1))
-}
-
-func memlimit() uint64 {
- return 0
-}
-
-var _badsignal = []byte("runtime: signal received on thread not created by Go.\n")
-
-// This runs on a foreign stack, without an m or a g. No stack split.
-//go:nosplit
-func badsignal2() {
- pwrite(2, unsafe.Pointer(&_badsignal[0]), int32(len(_badsignal)), -1)
- exits(&_badsignal[0])
-}
-
-func raisebadsignal(sig int32) {
- badsignal2()
-}
-
-func _atoi(b []byte) int {
- n := 0
- for len(b) > 0 && '0' <= b[0] && b[0] <= '9' {
- n = n*10 + int(b[0]) - '0'
- b = b[1:]
- }
- return n
-}
-
-func signame(sig uint32) string {
- if sig >= uint32(len(sigtable)) {
- return ""
- }
- return sigtable[sig].name
-}
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package runtime
-import "unsafe"
+import (
+ "runtime/internal/sys"
+ "unsafe"
+)
type mOS struct{}
func sys_umtx_op(addr *uint32, mode int32, val uint32, ptr2, ts *timespec) int32
func osyield()
+
+// From FreeBSD's <sys/sysctl.h>
+const (
+ _CTL_HW = 6
+ _HW_NCPU = 3
+)
+
+var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
+
+func getncpu() int32 {
+ mib := [2]uint32{_CTL_HW, _HW_NCPU}
+ out := uint32(0)
+ nout := unsafe.Sizeof(out)
+ ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
+ if ret >= 0 {
+ return int32(out)
+ }
+ return 1
+}
+
+// FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and
+// thus the code is largely similar. See Linux implementation
+// and lock_futex.go for comments.
+
+//go:nosplit
+func futexsleep(addr *uint32, val uint32, ns int64) {
+ systemstack(func() {
+ futexsleep1(addr, val, ns)
+ })
+}
+
+func futexsleep1(addr *uint32, val uint32, ns int64) {
+ var tsp *timespec
+ if ns >= 0 {
+ var ts timespec
+ ts.tv_nsec = 0
+ ts.set_sec(int64(timediv(ns, 1000000000, (*int32)(unsafe.Pointer(&ts.tv_nsec)))))
+ tsp = &ts
+ }
+ ret := sys_umtx_op(addr, _UMTX_OP_WAIT_UINT_PRIVATE, val, nil, tsp)
+ if ret >= 0 || ret == -_EINTR {
+ return
+ }
+ print("umtx_wait addr=", addr, " val=", val, " ret=", ret, "\n")
+ *(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005
+}
+
+//go:nosplit
+func futexwakeup(addr *uint32, cnt uint32) {
+ ret := sys_umtx_op(addr, _UMTX_OP_WAKE_PRIVATE, cnt, nil, nil)
+ if ret >= 0 {
+ return
+ }
+
+ systemstack(func() {
+ print("umtx_wake_addr=", addr, " ret=", ret, "\n")
+ })
+}
+
+func thr_start()
+
+// May run with m.p==nil, so write barriers are not allowed.
+//go:nowritebarrier
+func newosproc(mp *m, stk unsafe.Pointer) {
+ if false {
+ print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " thr_start=", funcPC(thr_start), " id=", mp.id, " ostk=", &mp, "\n")
+ }
+
+ // NOTE(rsc): This code is confused. stackbase is the top of the stack
+ // and is equal to stk. However, it's working, so I'm not changing it.
+ param := thrparam{
+ start_func: funcPC(thr_start),
+ arg: unsafe.Pointer(mp),
+ stack_base: mp.g0.stack.hi,
+ stack_size: uintptr(stk) - mp.g0.stack.hi,
+ child_tid: unsafe.Pointer(&mp.procid),
+ parent_tid: nil,
+ tls_base: unsafe.Pointer(&mp.tls[0]),
+ tls_size: unsafe.Sizeof(mp.tls),
+ }
+
+ var oset sigset
+ sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
+ thr_new(¶m, int32(unsafe.Sizeof(param)))
+ sigprocmask(_SIG_SETMASK, &oset, nil)
+}
+
+func osinit() {
+ ncpu = getncpu()
+}
+
+var urandom_dev = []byte("/dev/urandom\x00")
+
+//go:nosplit
+func getRandomData(r []byte) {
+ fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
+ n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
+ closefd(fd)
+ extendRandom(r, int(n))
+}
+
+func goenvs() {
+ goenvs_unix()
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+func mpreinit(mp *m) {
+ mp.gsignal = malg(32 * 1024)
+ mp.gsignal.m = mp
+}
+
+//go:nosplit
+func msigsave(mp *m) {
+ sigprocmask(_SIG_SETMASK, nil, &mp.sigmask)
+}
+
+//go:nosplit
+func msigrestore(sigmask sigset) {
+ sigprocmask(_SIG_SETMASK, &sigmask, nil)
+}
+
+//go:nosplit
+func sigblock() {
+ sigprocmask(_SIG_SETMASK, &sigset_all, nil)
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, cannot allocate memory.
+func minit() {
+ _g_ := getg()
+
+ // m.procid is a uint64, but thr_new writes a uint32 on 32-bit systems.
+ // Fix it up. (Only matters on big-endian, but be clean anyway.)
+ if sys.PtrSize == 4 {
+ _g_.m.procid = uint64(*(*uint32)(unsafe.Pointer(&_g_.m.procid)))
+ }
+
+ // Initialize signal handling.
+ var st stackt
+ sigaltstack(nil, &st)
+ if st.ss_flags&_SS_DISABLE != 0 {
+ signalstack(&_g_.m.gsignal.stack)
+ _g_.m.newSigstack = true
+ } else {
+ // Use existing signal stack.
+ stsp := uintptr(unsafe.Pointer(st.ss_sp))
+ _g_.m.gsignal.stack.lo = stsp
+ _g_.m.gsignal.stack.hi = stsp + st.ss_size
+ _g_.m.gsignal.stackguard0 = stsp + _StackGuard
+ _g_.m.gsignal.stackguard1 = stsp + _StackGuard
+ _g_.m.gsignal.stackAlloc = st.ss_size
+ _g_.m.newSigstack = false
+ }
+
+ // restore signal mask from m.sigmask and unblock essential signals
+ nmask := _g_.m.sigmask
+ for i := range sigtable {
+ if sigtable[i].flags&_SigUnblock != 0 {
+ nmask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
+ }
+ }
+ sigprocmask(_SIG_SETMASK, &nmask, nil)
+}
+
+// Called from dropm to undo the effect of an minit.
+//go:nosplit
+func unminit() {
+ if getg().m.newSigstack {
+ signalstack(nil)
+ }
+}
+
+func memlimit() uintptr {
+ /*
+ TODO: Convert to Go when something actually uses the result.
+ Rlimit rl;
+ extern byte runtime·text[], runtime·end[];
+ uintptr used;
+
+ if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
+ return 0;
+ if(rl.rlim_cur >= 0x7fffffff)
+ return 0;
+
+ // Estimate our VM footprint excluding the heap.
+ // Not an exact science: use size of binary plus
+ // some room for thread stacks.
+ used = runtime·end - runtime·text + (64<<20);
+ if(used >= rl.rlim_cur)
+ return 0;
+
+ // If there's not at least 16 MB left, we're probably
+ // not going to be able to do much. Treat as no limit.
+ rl.rlim_cur -= used;
+ if(rl.rlim_cur < (16<<20))
+ return 0;
+
+ return rl.rlim_cur - used;
+ */
+
+ return 0
+}
+
+func sigtramp()
+
+type sigactiont struct {
+ sa_handler uintptr
+ sa_flags int32
+ sa_mask sigset
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func setsig(i int32, fn uintptr, restart bool) {
+ var sa sigactiont
+ sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
+ if restart {
+ sa.sa_flags |= _SA_RESTART
+ }
+ sa.sa_mask = sigset_all
+ if fn == funcPC(sighandler) {
+ fn = funcPC(sigtramp)
+ }
+ sa.sa_handler = fn
+ sigaction(i, &sa, nil)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func setsigstack(i int32) {
+ throw("setsigstack")
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func getsig(i int32) uintptr {
+ var sa sigactiont
+ sigaction(i, nil, &sa)
+ if sa.sa_handler == funcPC(sigtramp) {
+ return funcPC(sighandler)
+ }
+ return sa.sa_handler
+}
+
+//go:nosplit
+func signalstack(s *stack) {
+ var st stackt
+ if s == nil {
+ st.ss_flags = _SS_DISABLE
+ } else {
+ st.ss_sp = s.lo
+ st.ss_size = s.hi - s.lo
+ st.ss_flags = 0
+ }
+ sigaltstack(&st, nil)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func updatesigmask(m [(_NSIG + 31) / 32]uint32) {
+ var mask sigset
+ copy(mask.__bits[:], m[:])
+ sigprocmask(_SIG_SETMASK, &mask, nil)
+}
+
+func unblocksig(sig int32) {
+ var mask sigset
+ mask.__bits[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31)
+ sigprocmask(_SIG_UNBLOCK, &mask, nil)
+}
var randomNumber uint32
+func archauxv(tag, val uintptr) {
+ switch tag {
+ case _AT_RANDOM:
+ // sysargs filled in startupRandomData, but that
+ // pointer may not be word aligned, so we must treat
+ // it as a byte array.
+ randomNumber = uint32(startupRandomData[4]) | uint32(startupRandomData[5])<<8 |
+ uint32(startupRandomData[6])<<16 | uint32(startupRandomData[7])<<24
+ }
+}
+
//go:nosplit
func cputicks() int64 {
// Currently cputicks() is used in blocking profiler and to seed fastrand1().
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !amd64,!arm,!arm64
+// +build !amd64,!arm,!arm64,!mips64,!mips64le
package runtime
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2010 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.
func open(name *byte, mode, perm int32) int32
func closefd(fd int32) int32
func read(fd int32, p unsafe.Pointer, n int32) int32
+
+type sigset struct{}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+func mpreinit(mp *m) {
+ mp.gsignal = malg(32 * 1024)
+ mp.gsignal.m = mp
+}
+
+func sigtramp()
+
+//go:nosplit
+func msigsave(mp *m) {
+}
+
+//go:nosplit
+func msigrestore(sigmask sigset) {
+}
+
+//go:nosplit
+func sigblock() {
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, cannot allocate memory.
+func minit() {
+ _g_ := getg()
+
+ // Initialize signal handling
+ ret := nacl_exception_stack(_g_.m.gsignal.stack.lo, 32*1024)
+ if ret < 0 {
+ print("runtime: nacl_exception_stack: error ", -ret, "\n")
+ }
+
+ ret = nacl_exception_handler(funcPC(sigtramp), nil)
+ if ret < 0 {
+ print("runtime: nacl_exception_handler: error ", -ret, "\n")
+ }
+}
+
+// Called from dropm to undo the effect of an minit.
+func unminit() {
+}
+
+func osinit() {
+ ncpu = 1
+ getg().m.procid = 2
+ //nacl_exception_handler(funcPC(sigtramp), nil);
+}
+
+func signame(sig uint32) string {
+ if sig >= uint32(len(sigtable)) {
+ return ""
+ }
+ return sigtable[sig].name
+}
+
+func crash() {
+ *(*int32)(nil) = 0
+}
+
+//go:noescape
+func getRandomData([]byte)
+
+func goenvs() {
+ goenvs_unix()
+}
+
+func initsig(preinit bool) {
+}
+
+//go:nosplit
+func usleep(us uint32) {
+ var ts timespec
+
+ ts.tv_sec = int64(us / 1e6)
+ ts.tv_nsec = int32(us%1e6) * 1e3
+ nacl_nanosleep(&ts, nil)
+}
+
+func mstart_nacl()
+
+// May run with m.p==nil, so write barriers are not allowed.
+//go:nowritebarrier
+func newosproc(mp *m, stk unsafe.Pointer) {
+ mp.tls[0] = uintptr(unsafe.Pointer(mp.g0))
+ mp.tls[1] = uintptr(unsafe.Pointer(mp))
+ ret := nacl_thread_create(funcPC(mstart_nacl), stk, unsafe.Pointer(&mp.tls[2]), nil)
+ if ret < 0 {
+ print("nacl_thread_create: error ", -ret, "\n")
+ throw("newosproc")
+ }
+}
+
+//go:nosplit
+func semacreate(mp *m) {
+ if mp.waitsema != 0 {
+ return
+ }
+ systemstack(func() {
+ mu := nacl_mutex_create(0)
+ if mu < 0 {
+ print("nacl_mutex_create: error ", -mu, "\n")
+ throw("semacreate")
+ }
+ c := nacl_cond_create(0)
+ if c < 0 {
+ print("nacl_cond_create: error ", -c, "\n")
+ throw("semacreate")
+ }
+ mp.waitsema = c
+ mp.waitsemalock = mu
+ })
+}
+
+//go:nosplit
+func semasleep(ns int64) int32 {
+ var ret int32
+
+ systemstack(func() {
+ _g_ := getg()
+ if nacl_mutex_lock(_g_.m.waitsemalock) < 0 {
+ throw("semasleep")
+ }
+
+ for _g_.m.waitsemacount == 0 {
+ if ns < 0 {
+ if nacl_cond_wait(_g_.m.waitsema, _g_.m.waitsemalock) < 0 {
+ throw("semasleep")
+ }
+ } else {
+ var ts timespec
+ end := ns + nanotime()
+ ts.tv_sec = end / 1e9
+ ts.tv_nsec = int32(end % 1e9)
+ r := nacl_cond_timed_wait_abs(_g_.m.waitsema, _g_.m.waitsemalock, &ts)
+ if r == -_ETIMEDOUT {
+ nacl_mutex_unlock(_g_.m.waitsemalock)
+ ret = -1
+ return
+ }
+ if r < 0 {
+ throw("semasleep")
+ }
+ }
+ }
+
+ _g_.m.waitsemacount = 0
+ nacl_mutex_unlock(_g_.m.waitsemalock)
+ ret = 0
+ })
+ return ret
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+ systemstack(func() {
+ if nacl_mutex_lock(mp.waitsemalock) < 0 {
+ throw("semawakeup")
+ }
+ if mp.waitsemacount != 0 {
+ throw("semawakeup")
+ }
+ mp.waitsemacount = 1
+ nacl_cond_signal(mp.waitsema)
+ nacl_mutex_unlock(mp.waitsemalock)
+ })
+}
+
+func memlimit() uintptr {
+ return 0
+}
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+//go:nosplit
+//go:norace
+//go:nowritebarrierrec
+func badsignal(sig uintptr) {
+ cgocallback(unsafe.Pointer(funcPC(badsignalgo)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig))
+}
+
+func badsignalgo(sig uintptr) {
+ if !sigsend(uint32(sig)) {
+ // A foreign thread received the signal sig, and the
+ // Go code does not want to handle it.
+ raisebadsignal(int32(sig))
+ }
+}
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+//go:nosplit
+func badsignal2() {
+ write(2, unsafe.Pointer(&badsignal1[0]), int32(len(badsignal1)))
+ exit(2)
+}
+
+var badsignal1 = []byte("runtime: signal received on thread not created by Go.\n")
+
+func raisebadsignal(sig int32) {
+ badsignal2()
+}
+
+func madvise(addr unsafe.Pointer, n uintptr, flags int32) {}
+func munmap(addr unsafe.Pointer, n uintptr) {}
+func resetcpuprofiler(hz int32) {}
+func sigdisable(uint32) {}
+func sigenable(uint32) {}
+func sigignore(uint32) {}
+func closeonexec(int32) {}
+
+var writelock uint32 // test-and-set spin lock for write
+
+/*
+An attempt at IRT. Doesn't work. See end of sys_nacl_amd64.s.
+
+void (*nacl_irt_query)(void);
+
+int8 nacl_irt_basic_v0_1_str[] = "nacl-irt-basic-0.1";
+void *nacl_irt_basic_v0_1[6]; // exit, gettod, clock, nanosleep, sched_yield, sysconf
+int32 nacl_irt_basic_v0_1_size = sizeof(nacl_irt_basic_v0_1);
+
+int8 nacl_irt_memory_v0_3_str[] = "nacl-irt-memory-0.3";
+void *nacl_irt_memory_v0_3[3]; // mmap, munmap, mprotect
+int32 nacl_irt_memory_v0_3_size = sizeof(nacl_irt_memory_v0_3);
+
+int8 nacl_irt_thread_v0_1_str[] = "nacl-irt-thread-0.1";
+void *nacl_irt_thread_v0_1[3]; // thread_create, thread_exit, thread_nice
+int32 nacl_irt_thread_v0_1_size = sizeof(nacl_irt_thread_v0_1);
+*/
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package runtime
+import (
+ "runtime/internal/atomic"
+ "unsafe"
+)
+
type mOS struct {
waitsemacount uint32
}
func thrwakeup(ident uintptr, n int32) int32
func osyield()
+
+const (
+ _ESRCH = 3
+ _EAGAIN = 35
+ _EWOULDBLOCK = _EAGAIN
+ _ENOTSUP = 91
+
+ // From OpenBSD's sys/time.h
+ _CLOCK_REALTIME = 0
+ _CLOCK_VIRTUAL = 1
+ _CLOCK_PROF = 2
+ _CLOCK_MONOTONIC = 3
+)
+
+type sigset uint32
+
+const (
+ sigset_none = sigset(0)
+ sigset_all = ^sigset(0)
+)
+
+// From OpenBSD's <sys/sysctl.h>
+const (
+ _CTL_HW = 6
+ _HW_NCPU = 3
+)
+
+func getncpu() int32 {
+ mib := [2]uint32{_CTL_HW, _HW_NCPU}
+ out := uint32(0)
+ nout := unsafe.Sizeof(out)
+
+ // Fetch hw.ncpu via sysctl.
+ ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
+ if ret >= 0 {
+ return int32(out)
+ }
+ return 1
+}
+
+//go:nosplit
+func semacreate(mp *m) {
+}
+
+//go:nosplit
+func semasleep(ns int64) int32 {
+ _g_ := getg()
+
+ // Compute sleep deadline.
+ var tsp *timespec
+ if ns >= 0 {
+ var ts timespec
+ var nsec int32
+ ns += nanotime()
+ ts.set_sec(int64(timediv(ns, 1000000000, &nsec)))
+ ts.set_nsec(nsec)
+ tsp = &ts
+ }
+
+ for {
+ v := atomic.Load(&_g_.m.waitsemacount)
+ if v > 0 {
+ if atomic.Cas(&_g_.m.waitsemacount, v, v-1) {
+ return 0 // semaphore acquired
+ }
+ continue
+ }
+
+ // Sleep until woken by semawakeup or timeout; or abort if waitsemacount != 0.
+ //
+ // From OpenBSD's __thrsleep(2) manual:
+ // "The abort argument, if not NULL, points to an int that will
+ // be examined [...] immediately before blocking. If that int
+ // is non-zero then __thrsleep() will immediately return EINTR
+ // without blocking."
+ ret := thrsleep(uintptr(unsafe.Pointer(&_g_.m.waitsemacount)), _CLOCK_MONOTONIC, tsp, 0, &_g_.m.waitsemacount)
+ if ret == _EWOULDBLOCK {
+ return -1
+ }
+ }
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+ atomic.Xadd(&mp.waitsemacount, 1)
+ ret := thrwakeup(uintptr(unsafe.Pointer(&mp.waitsemacount)), 1)
+ if ret != 0 && ret != _ESRCH {
+ // semawakeup can be called on signal stack.
+ systemstack(func() {
+ print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n")
+ })
+ }
+}
+
+// May run with m.p==nil, so write barriers are not allowed.
+//go:nowritebarrier
+func newosproc(mp *m, stk unsafe.Pointer) {
+ if false {
+ print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, " ostk=", &mp, "\n")
+ }
+
+ param := tforkt{
+ tf_tcb: unsafe.Pointer(&mp.tls[0]),
+ tf_tid: (*int32)(unsafe.Pointer(&mp.procid)),
+ tf_stack: uintptr(stk),
+ }
+
+ oset := sigprocmask(_SIG_SETMASK, sigset_all)
+ ret := tfork(¶m, unsafe.Sizeof(param), mp, mp.g0, funcPC(mstart))
+ sigprocmask(_SIG_SETMASK, oset)
+
+ if ret < 0 {
+ print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n")
+ throw("runtime.newosproc")
+ }
+}
+
+func osinit() {
+ ncpu = getncpu()
+}
+
+var urandom_dev = []byte("/dev/urandom\x00")
+
+//go:nosplit
+func getRandomData(r []byte) {
+ fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
+ n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
+ closefd(fd)
+ extendRandom(r, int(n))
+}
+
+func goenvs() {
+ goenvs_unix()
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+func mpreinit(mp *m) {
+ mp.gsignal = malg(32 * 1024)
+ mp.gsignal.m = mp
+}
+
+//go:nosplit
+func msigsave(mp *m) {
+ mp.sigmask = sigprocmask(_SIG_BLOCK, 0)
+}
+
+//go:nosplit
+func msigrestore(sigmask sigset) {
+ sigprocmask(_SIG_SETMASK, sigmask)
+}
+
+//go:nosplit
+func sigblock() {
+ sigprocmask(_SIG_SETMASK, sigset_all)
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+func minit() {
+ _g_ := getg()
+
+ // m.procid is a uint64, but tfork writes an int32. Fix it up.
+ _g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid)))
+
+ // Initialize signal handling
+ var st stackt
+ sigaltstack(nil, &st)
+ if st.ss_flags&_SS_DISABLE != 0 {
+ signalstack(&_g_.m.gsignal.stack)
+ _g_.m.newSigstack = true
+ } else {
+ // Use existing signal stack.
+ stsp := uintptr(unsafe.Pointer(st.ss_sp))
+ _g_.m.gsignal.stack.lo = stsp
+ _g_.m.gsignal.stack.hi = stsp + st.ss_size
+ _g_.m.gsignal.stackguard0 = stsp + _StackGuard
+ _g_.m.gsignal.stackguard1 = stsp + _StackGuard
+ _g_.m.gsignal.stackAlloc = st.ss_size
+ _g_.m.newSigstack = false
+ }
+
+ // restore signal mask from m.sigmask and unblock essential signals
+ nmask := _g_.m.sigmask
+ for i := range sigtable {
+ if sigtable[i].flags&_SigUnblock != 0 {
+ nmask &^= 1 << (uint32(i) - 1)
+ }
+ }
+ sigprocmask(_SIG_SETMASK, nmask)
+}
+
+// Called from dropm to undo the effect of an minit.
+//go:nosplit
+func unminit() {
+ if getg().m.newSigstack {
+ signalstack(nil)
+ }
+}
+
+func memlimit() uintptr {
+ return 0
+}
+
+func sigtramp()
+
+type sigactiont struct {
+ sa_sigaction uintptr
+ sa_mask uint32
+ sa_flags int32
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func setsig(i int32, fn uintptr, restart bool) {
+ var sa sigactiont
+ sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
+ if restart {
+ sa.sa_flags |= _SA_RESTART
+ }
+ sa.sa_mask = uint32(sigset_all)
+ if fn == funcPC(sighandler) {
+ fn = funcPC(sigtramp)
+ }
+ sa.sa_sigaction = fn
+ sigaction(i, &sa, nil)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func setsigstack(i int32) {
+ throw("setsigstack")
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func getsig(i int32) uintptr {
+ var sa sigactiont
+ sigaction(i, nil, &sa)
+ if sa.sa_sigaction == funcPC(sigtramp) {
+ return funcPC(sighandler)
+ }
+ return sa.sa_sigaction
+}
+
+//go:nosplit
+func signalstack(s *stack) {
+ var st stackt
+ if s == nil {
+ st.ss_flags = _SS_DISABLE
+ } else {
+ st.ss_sp = s.lo
+ st.ss_size = s.hi - s.lo
+ st.ss_flags = 0
+ }
+ sigaltstack(&st, nil)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func updatesigmask(m sigmask) {
+ sigprocmask(_SIG_SETMASK, sigset(m[0]))
+}
+
+func unblocksig(sig int32) {
+ mask := sigset(1) << (uint32(sig) - 1)
+ sigprocmask(_SIG_UNBLOCK, mask)
+}
-// Copyright 2014 The Go Authors. All rights reserved.
+// Copyright 2010 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 runtime
-import "unsafe"
+import (
+ "runtime/internal/atomic"
+ "unsafe"
+)
type mOS struct {
waitsemacount uint32
}
return n
}
+
+type sigset struct{}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+func mpreinit(mp *m) {
+ // Initialize stack and goroutine for note handling.
+ mp.gsignal = malg(32 * 1024)
+ mp.gsignal.m = mp
+ mp.notesig = (*int8)(mallocgc(_ERRMAX, nil, true))
+ // Initialize stack for handling strings from the
+ // errstr system call, as used in package syscall.
+ mp.errstr = (*byte)(mallocgc(_ERRMAX, nil, true))
+}
+
+func msigsave(mp *m) {
+}
+
+func msigrestore(sigmask sigset) {
+}
+
+func sigblock() {
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, cannot allocate memory.
+func minit() {
+ if atomic.Load(&exiting) != 0 {
+ exits(&emptystatus[0])
+ }
+ // Mask all SSE floating-point exceptions
+ // when running on the 64-bit kernel.
+ setfpmasks()
+}
+
+// Called from dropm to undo the effect of an minit.
+func unminit() {
+}
+
+var sysstat = []byte("/dev/sysstat\x00")
+
+func getproccount() int32 {
+ var buf [2048]byte
+ fd := open(&sysstat[0], _OREAD, 0)
+ if fd < 0 {
+ return 1
+ }
+ ncpu := int32(0)
+ for {
+ n := read(fd, unsafe.Pointer(&buf), int32(len(buf)))
+ if n <= 0 {
+ break
+ }
+ for i := int32(0); i < n; i++ {
+ if buf[i] == '\n' {
+ ncpu++
+ }
+ }
+ }
+ closefd(fd)
+ if ncpu == 0 {
+ ncpu = 1
+ }
+ return ncpu
+}
+
+var pid = []byte("#c/pid\x00")
+
+func getpid() uint64 {
+ var b [20]byte
+ fd := open(&pid[0], 0, 0)
+ if fd >= 0 {
+ read(fd, unsafe.Pointer(&b), int32(len(b)))
+ closefd(fd)
+ }
+ c := b[:]
+ for c[0] == ' ' || c[0] == '\t' {
+ c = c[1:]
+ }
+ return uint64(_atoi(c))
+}
+
+func osinit() {
+ initBloc()
+ ncpu = getproccount()
+ getg().m.procid = getpid()
+ notify(unsafe.Pointer(funcPC(sigtramp)))
+}
+
+func crash() {
+ notify(nil)
+ *(*int)(nil) = 0
+}
+
+//go:nosplit
+func getRandomData(r []byte) {
+ extendRandom(r, 0)
+}
+
+func goenvs() {
+}
+
+func initsig(preinit bool) {
+}
+
+//go:nosplit
+func osyield() {
+ sleep(0)
+}
+
+//go:nosplit
+func usleep(µs uint32) {
+ ms := int32(µs / 1000)
+ if ms == 0 {
+ ms = 1
+ }
+ sleep(ms)
+}
+
+//go:nosplit
+func nanotime() int64 {
+ var scratch int64
+ ns := nsec(&scratch)
+ // TODO(aram): remove hack after I fix _nsec in the pc64 kernel.
+ if ns == 0 {
+ return scratch
+ }
+ return ns
+}
+
+//go:nosplit
+func itoa(buf []byte, val uint64) []byte {
+ i := len(buf) - 1
+ for val >= 10 {
+ buf[i] = byte(val%10 + '0')
+ i--
+ val /= 10
+ }
+ buf[i] = byte(val + '0')
+ return buf[i:]
+}
+
+var goexits = []byte("go: exit ")
+var emptystatus = []byte("\x00")
+var exiting uint32
+
+func goexitsall(status *byte) {
+ var buf [_ERRMAX]byte
+ if !atomic.Cas(&exiting, 0, 1) {
+ return
+ }
+ getg().m.locks++
+ n := copy(buf[:], goexits)
+ n = copy(buf[n:], gostringnocopy(status))
+ pid := getpid()
+ for mp := (*m)(atomic.Loadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink {
+ if mp.procid != 0 && mp.procid != pid {
+ postnote(mp.procid, buf[:])
+ }
+ }
+ getg().m.locks--
+}
+
+var procdir = []byte("/proc/")
+var notefile = []byte("/note\x00")
+
+func postnote(pid uint64, msg []byte) int {
+ var buf [128]byte
+ var tmp [32]byte
+ n := copy(buf[:], procdir)
+ n += copy(buf[n:], itoa(tmp[:], pid))
+ copy(buf[n:], notefile)
+ fd := open(&buf[0], _OWRITE, 0)
+ if fd < 0 {
+ return -1
+ }
+ len := findnull(&msg[0])
+ if write(uintptr(fd), unsafe.Pointer(&msg[0]), int32(len)) != int64(len) {
+ closefd(fd)
+ return -1
+ }
+ closefd(fd)
+ return 0
+}
+
+//go:nosplit
+func exit(e int) {
+ var status []byte
+ if e == 0 {
+ status = emptystatus
+ } else {
+ // build error string
+ var tmp [32]byte
+ status = append(itoa(tmp[:len(tmp)-1], uint64(e)), 0)
+ }
+ goexitsall(&status[0])
+ exits(&status[0])
+}
+
+// May run with m.p==nil, so write barriers are not allowed.
+//go:nowritebarrier
+func newosproc(mp *m, stk unsafe.Pointer) {
+ if false {
+ print("newosproc mp=", mp, " ostk=", &mp, "\n")
+ }
+ pid := rfork(_RFPROC | _RFMEM | _RFNOWAIT)
+ if pid < 0 {
+ throw("newosproc: rfork failed")
+ }
+ if pid == 0 {
+ tstart_plan9(mp)
+ }
+}
+
+//go:nosplit
+func semacreate(mp *m) {
+}
+
+//go:nosplit
+func semasleep(ns int64) int {
+ _g_ := getg()
+ if ns >= 0 {
+ ms := timediv(ns, 1000000, nil)
+ if ms == 0 {
+ ms = 1
+ }
+ ret := plan9_tsemacquire(&_g_.m.waitsemacount, ms)
+ if ret == 1 {
+ return 0 // success
+ }
+ return -1 // timeout or interrupted
+ }
+ for plan9_semacquire(&_g_.m.waitsemacount, 1) < 0 {
+ // interrupted; try again (c.f. lock_sema.go)
+ }
+ return 0 // success
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+ plan9_semrelease(&mp.waitsemacount, 1)
+}
+
+//go:nosplit
+func read(fd int32, buf unsafe.Pointer, n int32) int32 {
+ return pread(fd, buf, n, -1)
+}
+
+//go:nosplit
+func write(fd uintptr, buf unsafe.Pointer, n int32) int64 {
+ return int64(pwrite(int32(fd), buf, n, -1))
+}
+
+func memlimit() uint64 {
+ return 0
+}
+
+var _badsignal = []byte("runtime: signal received on thread not created by Go.\n")
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+//go:nosplit
+func badsignal2() {
+ pwrite(2, unsafe.Pointer(&_badsignal[0]), int32(len(_badsignal)), -1)
+ exits(&_badsignal[0])
+}
+
+func raisebadsignal(sig int32) {
+ badsignal2()
+}
+
+func _atoi(b []byte) int {
+ n := 0
+ for len(b) > 0 && '0' <= b[0] && b[0] <= '9' {
+ n = n*10 + int(b[0]) - '0'
+ b = b[1:]
+ }
+ return n
+}
+
+func signame(sig uint32) string {
+ if sig >= uint32(len(sigtable)) {
+ return ""
+ }
+ return sigtable[sig].name
+}
args = append(args, "-test.short")
}
cmd := exec.Command(os.Args[0], args...)
- cmd.Env = append([]string{"GODEBUG=gcstackbarrierall=1", "GOGC=1"}, os.Environ()...)
+ cmd.Env = append([]string{"GODEBUG=gcstackbarrierall=1", "GOGC=1", "GOTRACEBACK=system"}, os.Environ()...)
if out, err := cmd.CombinedOutput(); err != nil {
t.Fatalf("subprocess failed with %v:\n%s", err, out)
}
if _cgo_thread_start == nil {
throw("_cgo_thread_start missing")
}
- if _cgo_malloc == nil {
- throw("_cgo_malloc missing")
- }
- if _cgo_free == nil {
- throw("_cgo_free missing")
- }
if GOOS != "windows" {
if _cgo_setenv == nil {
throw("_cgo_setenv missing")
func goready(gp *g, traceskip int) {
systemstack(func() {
- ready(gp, traceskip)
+ ready(gp, traceskip, true)
})
}
sched.maxmcount = 10000
- // Cache the framepointer experiment. This affects stack unwinding.
- framepointer_enabled = haveexperiment("framepointer")
-
tracebackinit()
moduledataverify()
stackinit()
}
// Mark gp ready to run.
-func ready(gp *g, traceskip int) {
+func ready(gp *g, traceskip int, next bool) {
if trace.enabled {
traceGoUnpark(gp, traceskip)
}
// status is Gwaiting or Gscanwaiting, make Grunnable and put on runq
casgstatus(gp, _Gwaiting, _Grunnable)
- runqput(_g_.m.p.ptr(), gp, true)
+ runqput(_g_.m.p.ptr(), gp, next)
if atomic.Load(&sched.npidle) != 0 && atomic.Load(&sched.nmspinning) == 0 { // TODO: fast atomic
wakep()
}
// scang blocks until gp's stack has been scanned.
// It might be scanned by scang or it might be scanned by the goroutine itself.
// Either way, the stack scan has completed when scang returns.
-func scang(gp *g) {
+func scang(gp *g, gcw *gcWork) {
// Invariant; we (the caller, markroot for a specific goroutine) own gp.gcscandone.
// Nothing is racing with us now, but gcscandone might be set to true left over
// from an earlier round of stack scanning (we scan twice per GC).
// the goroutine until we're done.
if castogscanstatus(gp, s, s|_Gscan) {
if !gp.gcscandone {
- scanstack(gp)
+ scanstack(gp, gcw)
gp.gcscandone = true
}
restartg(gp)
}
if fingwait && fingwake {
if gp := wakefing(); gp != nil {
- ready(gp, 0)
+ ready(gp, 0, true)
}
}
_g_.m.locks++ // see comment in entersyscall
if getcallersp(unsafe.Pointer(&dummy)) > _g_.syscallsp {
- throw("exitsyscall: syscall frame is no longer valid")
+ // throw calls print which may try to grow the stack,
+ // but throwsplit == true so the stack can not be grown;
+ // use systemstack to avoid that possible problem.
+ systemstack(func() {
+ throw("exitsyscall: syscall frame is no longer valid")
+ })
}
_g_.waitsince = 0
}
func haveexperiment(name string) bool {
+ if name == "framepointer" {
+ return framepointer_enabled // set by linker
+ }
x := sys.Goexperiment
for x != "" {
xname := ""
if xname == name {
return true
}
+ if len(xname) > 2 && xname[:2] == "no" && xname[2:] == name {
+ return false
+ }
}
return false
}
}
}
+func TestGCFairness2(t *testing.T) {
+ output := runTestProg(t, "testprog", "GCFairness2")
+ want := "OK\n"
+ if output != want {
+ t.Fatalf("want %s, got %s\n", want, output)
+ }
+}
+
func TestNumGoroutine(t *testing.T) {
output := runTestProg(t, "testprog", "NumGoroutine")
want := "1\n"
return
}
+var raceFiniLock mutex
+
//go:nosplit
func racefini() {
+ // racefini() can only be called once to avoid races.
+ // This eventually (via __tsan_fini) calls C.exit which has
+ // undefined behavior if called more than once. If the lock is
+ // already held it's assumed that the first caller exits the program
+ // so other calls can hang forever without an issue.
+ lock(&raceFiniLock)
racecall(&__tsan_fini, 0, 0, 0, 0)
}
v1 := 0
v2 := 0
c := make(chan int, 1)
+ done := make(chan bool)
go func() {
defer func() {
recover()
}()
v1 = 1
c <- 1
+ done <- true
}()
go func() {
time.Sleep(1e7)
v2 = 2
close(c)
+ done <- true
}()
time.Sleep(2e7)
if _, who := <-c; who {
} else {
v1 = 2
}
+ <-done
+ <-done
}
func TestRaceChanSendClose(t *testing.T) {
// When linking with -shared, this symbol is called when the shared library
// is loaded.
-TEXT _rt0_amd64_darwin_lib(SB),NOSPLIT,$0x48
+TEXT _rt0_amd64_darwin_lib(SB),NOSPLIT,$0x58
+ // Align stack. We don't know whether Go is adding a frame pointer here or not.
+ MOVQ SP, R8
+ SUBQ $16, R8
+ ANDQ $~15, R8
+ XCHGQ SP, R8
+
+ MOVQ R8, 0x48(SP)
MOVQ BX, 0x18(SP)
MOVQ BP, 0x20(SP)
MOVQ R12, 0x28(SP)
MOVQ 0x30(SP), R13
MOVQ 0x38(SP), R14
MOVQ 0x40(SP), R15
+
+ MOVQ 0x48(SP), R8
+ MOVQ R8, SP
RET
TEXT _rt0_amd64_darwin_lib_go(SB),NOSPLIT,$0
//
// Note that all currently shipping darwin/arm platforms require
// cgo and do not support c-shared.
-TEXT _rt0_arm_darwin_lib(SB),NOSPLIT,$32
+TEXT _rt0_arm_darwin_lib(SB),NOSPLIT,$104
// Preserve callee-save registers.
MOVW R4, 12(R13)
MOVW R5, 16(R13)
MOVW R8, 28(R13)
MOVW R11, 32(R13)
+ MOVD F8, (32+8*1)(R13)
+ MOVD F9, (32+8*2)(R13)
+ MOVD F10, (32+8*3)(R13)
+ MOVD F11, (32+8*4)(R13)
+ MOVD F12, (32+8*5)(R13)
+ MOVD F13, (32+8*6)(R13)
+ MOVD F14, (32+8*7)(R13)
+ MOVD F15, (32+8*8)(R13)
+
MOVW R0, _rt0_arm_darwin_lib_argc<>(SB)
MOVW R1, _rt0_arm_darwin_lib_argv<>(SB)
MOVW 24(R13), R7
MOVW 28(R13), R8
MOVW 32(R13), R11
+ MOVD (32+8*1)(R13), F8
+ MOVD (32+8*2)(R13), F9
+ MOVD (32+8*3)(R13), F10
+ MOVD (32+8*4)(R13), F11
+ MOVD (32+8*5)(R13), F12
+ MOVD (32+8*6)(R13), F13
+ MOVD (32+8*7)(R13), F14
+ MOVD (32+8*8)(R13), F15
RET
// When building with -buildmode=c-shared, this symbol is called when the shared
// library is loaded.
-TEXT _rt0_arm_linux_lib(SB),NOSPLIT,$32
+TEXT _rt0_arm_linux_lib(SB),NOSPLIT,$104
// Preserve callee-save registers. Raspberry Pi's dlopen(), for example,
// actually cares that R11 is preserved.
MOVW R4, 12(R13)
MOVW R8, 28(R13)
MOVW R11, 32(R13)
+ // Skip floating point registers on GOARM < 6.
+ MOVB runtime·goarm(SB), R11
+ CMP $6, R11
+ BLT skipfpsave
+ MOVD F8, (32+8*1)(R13)
+ MOVD F9, (32+8*2)(R13)
+ MOVD F10, (32+8*3)(R13)
+ MOVD F11, (32+8*4)(R13)
+ MOVD F12, (32+8*5)(R13)
+ MOVD F13, (32+8*6)(R13)
+ MOVD F14, (32+8*7)(R13)
+ MOVD F15, (32+8*8)(R13)
+skipfpsave:
// Save argc/argv.
MOVW R0, _rt0_arm_linux_lib_argc<>(SB)
MOVW R1, _rt0_arm_linux_lib_argv<>(SB)
BL runtime·newosproc0(SB)
rr:
// Restore callee-save registers and return.
+ MOVB runtime·goarm(SB), R11
+ CMP $6, R11
+ BLT skipfprest
+ MOVD (32+8*1)(R13), F8
+ MOVD (32+8*2)(R13), F9
+ MOVD (32+8*3)(R13), F10
+ MOVD (32+8*4)(R13), F11
+ MOVD (32+8*5)(R13), F12
+ MOVD (32+8*6)(R13), F13
+ MOVD (32+8*7)(R13), F14
+ MOVD (32+8*8)(R13), F15
+skipfprest:
MOVW 12(R13), R4
MOVW 16(R13), R5
MOVW 20(R13), R6
TEXT _rt0_ppc64le_linux(SB),NOSPLIT,$0
BR _main<>(SB)
+TEXT _rt0_ppc64le_linux_lib(SB),NOSPLIT,$-8
+ // Start with standard C stack frame layout and linkage.
+ MOVD LR, R0
+ MOVD R0, 16(R1) // Save LR in caller's frame.
+ MOVD R2, 24(R1) // Save TOC in caller's frame.
+ MOVDU R1, -320(R1) // Allocate frame.
+
+ // Preserve callee-save registers.
+ MOVD R14, 24(R1)
+ MOVD R15, 32(R1)
+ MOVD R16, 40(R1)
+ MOVD R17, 48(R1)
+ MOVD R18, 56(R1)
+ MOVD R19, 64(R1)
+ MOVD R20, 72(R1)
+ MOVD R21, 80(R1)
+ MOVD R22, 88(R1)
+ MOVD R23, 96(R1)
+ MOVD R24, 104(R1)
+ MOVD R25, 112(R1)
+ MOVD R26, 120(R1)
+ MOVD R27, 128(R1)
+ MOVD R28, 136(R1)
+ MOVD R29, 144(R1)
+ MOVD g, 152(R1) // R30
+ MOVD R31, 160(R1)
+ FMOVD F14, 168(R1)
+ FMOVD F15, 176(R1)
+ FMOVD F16, 184(R1)
+ FMOVD F17, 192(R1)
+ FMOVD F18, 200(R1)
+ FMOVD F19, 208(R1)
+ FMOVD F20, 216(R1)
+ FMOVD F21, 224(R1)
+ FMOVD F22, 232(R1)
+ FMOVD F23, 240(R1)
+ FMOVD F24, 248(R1)
+ FMOVD F25, 256(R1)
+ FMOVD F26, 264(R1)
+ FMOVD F27, 272(R1)
+ FMOVD F28, 280(R1)
+ FMOVD F29, 288(R1)
+ FMOVD F30, 296(R1)
+ FMOVD F31, 304(R1)
+
+ MOVD R3, _rt0_ppc64le_linux_lib_argc<>(SB)
+ MOVD R4, _rt0_ppc64le_linux_lib_argv<>(SB)
+
+ // Synchronous initialization.
+ MOVD $runtime·libpreinit(SB), R12
+ MOVD R12, CTR
+ BL (CTR)
+
+ // Create a new thread to do the runtime initialization and return.
+ MOVD _cgo_sys_thread_create(SB), R12
+ CMP $0, R12
+ BEQ nocgo
+ MOVD $_rt0_ppc64le_linux_lib_go(SB), R3
+ MOVD $0, R4
+ MOVD R12, CTR
+ BL (CTR)
+ BR done
+
+nocgo:
+ MOVD $0x800000, R12 // stacksize = 8192KB
+ MOVD R12, 8(R1)
+ MOVD $_rt0_ppc64le_linux_lib_go(SB), R12
+ MOVD R12, 16(R1)
+ MOVD $runtime·newosproc0(SB),R12
+ MOVD R12, CTR
+ BL (CTR)
+
+done:
+ // Restore saved registers.
+ MOVD 24(R1), R14
+ MOVD 32(R1), R15
+ MOVD 40(R1), R16
+ MOVD 48(R1), R17
+ MOVD 56(R1), R18
+ MOVD 64(R1), R19
+ MOVD 72(R1), R20
+ MOVD 80(R1), R21
+ MOVD 88(R1), R22
+ MOVD 96(R1), R23
+ MOVD 104(R1), R24
+ MOVD 112(R1), R25
+ MOVD 120(R1), R26
+ MOVD 128(R1), R27
+ MOVD 136(R1), R28
+ MOVD 144(R1), R29
+ MOVD 152(R1), g // R30
+ MOVD 160(R1), R31
+ FMOVD 168(R1), F14
+ FMOVD 176(R1), F15
+ FMOVD 184(R1), F16
+ FMOVD 192(R1), F17
+ FMOVD 200(R1), F18
+ FMOVD 208(R1), F19
+ FMOVD 216(R1), F20
+ FMOVD 224(R1), F21
+ FMOVD 232(R1), F22
+ FMOVD 240(R1), F23
+ FMOVD 248(R1), F24
+ FMOVD 256(R1), F25
+ FMOVD 264(R1), F26
+ FMOVD 272(R1), F27
+ FMOVD 280(R1), F28
+ FMOVD 288(R1), F29
+ FMOVD 296(R1), F30
+ FMOVD 304(R1), F31
+
+ ADD $320, R1
+ MOVD 24(R1), R2
+ MOVD 16(R1), R0
+ MOVD R0, LR
+ RET
+
+TEXT _rt0_ppc64le_linux_lib_go(SB),NOSPLIT,$0
+ MOVD _rt0_ppc64le_linux_lib_argc<>(SB), R3
+ MOVD _rt0_ppc64le_linux_lib_argv<>(SB), R4
+ MOVD $runtime·rt0_go(SB), R12
+ MOVD R12, CTR
+ BR (CTR)
+
+DATA _rt0_ppc64le_linux_lib_argc<>(SB)/8, $0
+GLOBL _rt0_ppc64le_linux_lib_argc<>(SB),NOPTR, $8
+DATA _rt0_ppc64le_linux_lib_argv<>(SB)/8, $0
+GLOBL _rt0_ppc64le_linux_lib_argv<>(SB),NOPTR, $8
+
TEXT _main<>(SB),NOSPLIT,$-8
// In a statically linked binary, the stack contains argc,
// argv as argc string pointers followed by a NULL, envv as a
+// Copyright 2015 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 runtime_test
import (
args := []string{"-nx", "-q", "--batch", "-iex",
fmt.Sprintf("add-auto-load-safe-path %s/src/runtime", runtime.GOROOT()),
+ "-ex", "set startup-with-shell off",
"-ex", "info auto-load python-scripts",
+ "-ex", "set python print-stack full",
"-ex", "br main.go:10",
"-ex", "run",
"-ex", "echo BEGIN info goroutines\n",
checkGdbEnvironment(t)
checkGdbVersion(t)
+ if runtime.GOOS == "netbsd" {
+ testenv.SkipFlaky(t, 15603)
+ }
+
dir, err := ioutil.TempDir("", "go-build")
if err != nil {
t.Fatalf("failed to create temp directory: %v", err)
// Execute gdb commands.
args := []string{"-nx", "-batch",
+ "-ex", "set startup-with-shell off",
"-ex", "break main.eee",
"-ex", "run",
"-ex", "backtrace",
SegmentSize uint8
}
for {
- offset, err := data.Seek(0, 1)
+ offset, err := data.Seek(0, io.SeekCurrent)
if err != nil {
t.Fatalf("Seek error: %v", err)
}
if lastTupleOffset%tupleSize != 0 {
t.Fatalf("Invalid arange length %d, (addr %d, seg %d)", header.UnitLength, header.AddressSize, header.SegmentSize)
}
- if _, err = data.Seek(lastTupleOffset, 0); err != nil {
+ if _, err = data.Seek(lastTupleOffset, io.SeekStart); err != nil {
t.Fatalf("Seek error: %v", err)
}
buf := make([]byte, tupleSize)
// reflect_addReflectOff adds a pointer to the reflection offset lookup map.
//go:linkname reflect_addReflectOff reflect.addReflectOff
func reflect_addReflectOff(ptr unsafe.Pointer) int32 {
- lock(&reflectOffs.lock)
+ reflectOffsLock()
if reflectOffs.m == nil {
reflectOffs.m = make(map[int32]unsafe.Pointer)
reflectOffs.minv = make(map[unsafe.Pointer]int32)
reflectOffs.m[id] = ptr
reflectOffs.minv[ptr] = id
}
- unlock(&reflectOffs.lock)
+ reflectOffsUnlock()
return id
}
support_avx bool
support_avx2 bool
- goarm uint8 // set by cmd/link on arm systems
+ goarm uint8 // set by cmd/link on arm systems
+ framepointer_enabled bool // set by cmd/link
)
// Set by the linker so the runtime can determine the buildmode.
setsig(sig, _SIG_DFL, false)
updatesigmask(sigmask{})
raise(sig)
- // That should have killed us; call exit just in case.
+
+ // That should have killed us. On some systems, though, raise
+ // sends the signal to the whole process rather than to just
+ // the current thread, which means that the signal may not yet
+ // have been delivered. Give other threads a chance to run and
+ // pick up the signal.
+ osyield()
+ osyield()
+ osyield()
+
+ // If we are still somehow running, just exit with the wrong status.
exit(2)
}
case 0xeeb80ac0: // D[regd] = S[regm] (MOVWF)
cmp := int32(m.freglo[regm])
if cmp < 0 {
- fputf(regd, f64to32(fintto64(int64(-cmp))))
+ fputf(regd, f64to32(fintto64(-int64(cmp))))
m.freglo[regd] ^= 0x80000000
} else {
fputf(regd, f64to32(fintto64(int64(cmp))))
case 0xeeb80bc0: // D[regd] = S[regm] (MOVWD)
cmp := int32(m.freglo[regm])
if cmp < 0 {
- fputd(regd, fintto64(int64(-cmp)))
+ fputd(regd, fintto64(-int64(cmp)))
m.freghi[regd] ^= 0x80000000
} else {
fputd(regd, fintto64(int64(cmp)))
free [_MHeapMap_Bits]mSpanList // free lists by log_2(s.npages)
}
-// Cached value of haveexperiment("framepointer")
-var framepointer_enabled bool
-
func stackinit() {
if _StackCacheSize&_PageMask != 0 {
throw("cache size must be a multiple of page size")
// stackcacherefill/stackcacherelease implement a global pool of stack segments.
// The pool is required to prevent unlimited growth of per-thread caches.
+//
+//go:systemstack
func stackcacherefill(c *mcache, order uint8) {
if stackDebug >= 1 {
print("stackcacherefill order=", order, "\n")
c.stackcache[order].size = size
}
+//go:systemstack
func stackcacherelease(c *mcache, order uint8) {
if stackDebug >= 1 {
print("stackcacherelease order=", order, "\n")
c.stackcache[order].size = size
}
+//go:systemstack
func stackcache_clear(c *mcache) {
if stackDebug >= 1 {
print("stackcache clear\n")
unlock(&stackpoolmu)
}
+// stackalloc allocates an n byte stack.
+//
+// stackalloc must run on the system stack because it uses per-P
+// resources and must not split the stack.
+//
+//go:systemstack
func stackalloc(n uint32) (stack, []stkbar) {
// Stackalloc must be called on scheduler stack, so that we
// never try to grow the stack during the code that stackalloc runs.
return stack{uintptr(v), uintptr(v) + top}, *(*[]stkbar)(unsafe.Pointer(&stkbarSlice))
}
+// stackfree frees an n byte stack allocation at stk.
+//
+// stackfree must run on the system stack because it uses per-P
+// resources and must not split the stack.
+//
+//go:systemstack
func stackfree(stk stack, n uintptr) {
gp := getg()
v := unsafe.Pointer(stk.lo)
// return.
}
if !gp.gcscandone {
- scanstack(gp)
+ // gcw is safe because we're on the
+ // system stack.
+ gcw := &gp.m.p.ptr().gcw
+ scanstack(gp, gcw)
+ if gcBlackenPromptly {
+ gcw.dispose()
+ }
gp.gcscandone = true
}
gp.preemptscan = false
MOVL context+8(FP), BX
MOVL BX, 8(SP)
CALL runtime·sigtrampgo(SB)
-
- // call sigreturn
- MOVL context+8(FP), AX
- MOVL $0, 0(SP) // syscall gap
- MOVL AX, 4(SP) // arg 1 - sigcontext
- MOVL $103, AX // sys_sigreturn
- INT $0x80
- MOVL $0xf1, 0xf1 // crash
RET
// int32 tfork(void *param, uintptr psize, M *mp, G *gp, void (*fn)(void));
#define maxargs 16
// void runtime·asmstdcall(void *c);
-TEXT runtime·asmstdcall(SB),NOSPLIT,$0
+TEXT runtime·asmstdcall(SB),NOSPLIT|NOFRAME,$0
// asmcgocall will put first argument into CX.
PUSHQ CX // save for later
MOVQ libcall_fn(CX), AX
RET
-TEXT runtime·badsignal2(SB),NOSPLIT,$48
+TEXT runtime·badsignal2(SB),NOSPLIT|NOFRAME,$48
// stderr
MOVQ $-12, CX // stderr
MOVQ CX, 0(SP)
// exception record and context pointers.
// Handler function is stored in AX.
// Return 0 for 'not handled', -1 for handled.
-TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
+TEXT runtime·sigtramp(SB),NOSPLIT|NOFRAME,$0-0
// CX: PEXCEPTION_POINTERS ExceptionInfo
// DI SI BP BX R12 R13 R14 R15 registers and DF flag are preserved
RET
-TEXT runtime·exceptiontramp(SB),NOSPLIT,$0
+TEXT runtime·exceptiontramp(SB),NOSPLIT|NOFRAME,$0
MOVQ $runtime·exceptionhandler(SB), AX
JMP runtime·sigtramp(SB)
-TEXT runtime·firstcontinuetramp(SB),NOSPLIT,$0-0
+TEXT runtime·firstcontinuetramp(SB),NOSPLIT|NOFRAME,$0-0
MOVQ $runtime·firstcontinuehandler(SB), AX
JMP runtime·sigtramp(SB)
-TEXT runtime·lastcontinuetramp(SB),NOSPLIT,$0-0
+TEXT runtime·lastcontinuetramp(SB),NOSPLIT|NOFRAME,$0-0
MOVQ $runtime·lastcontinuehandler(SB), AX
JMP runtime·sigtramp(SB)
-TEXT runtime·ctrlhandler(SB),NOSPLIT,$8
+TEXT runtime·ctrlhandler(SB),NOSPLIT|NOFRAME,$8
MOVQ CX, 16(SP) // spill
MOVQ $runtime·ctrlhandler1(SB), CX
MOVQ CX, 0(SP)
CALL runtime·externalthreadhandler(SB)
RET
-TEXT runtime·profileloop(SB),NOSPLIT,$8
+TEXT runtime·profileloop(SB),NOSPLIT|NOFRAME,$8
MOVQ $runtime·profileloop1(SB), CX
MOVQ CX, 0(SP)
CALL runtime·externalthreadhandler(SB)
RET
-TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0
+TEXT runtime·externalthreadhandler(SB),NOSPLIT|NOFRAME,$0
PUSHQ BP
MOVQ SP, BP
PUSHQ BX
SUBQ $m__size, SP // space for M
MOVQ SP, 0(SP)
MOVQ $m__size, 8(SP)
- CALL runtime·memclr(SB) // smashes AX,BX,CX
+ CALL runtime·memclr(SB) // smashes AX,BX,CX, maybe BP
LEAQ m_tls(SP), CX
MOVQ CX, 0x28(GS)
MOVQ SP, 0(SP)
MOVQ $g__size, 8(SP)
- CALL runtime·memclr(SB) // smashes AX,BX,CX
+ CALL runtime·memclr(SB) // smashes AX,BX,CX, maybe BP
LEAQ g__size(SP), BX
MOVQ BX, g_m(SP)
// Runs on OS stack. duration (in 100ns units) is in BX.
// The function leaves room for 4 syscall parameters
// (as per windows amd64 calling convention).
-TEXT runtime·usleep2(SB),NOSPLIT,$48
+TEXT runtime·usleep2(SB),NOSPLIT|NOFRAME,$48
MOVQ SP, AX
ANDQ $~15, SP // alignment as per Windows requirement
MOVQ AX, 40(SP)
RET
// Runs on OS stack.
-TEXT runtime·switchtothread(SB),NOSPLIT,$0
+TEXT runtime·switchtothread(SB),NOSPLIT|NOFRAME,$0
MOVQ SP, AX
ANDQ $~15, SP // alignment as per Windows requirement
SUBQ $(48), SP // room for SP and 4 args as per Windows requirement
"fmt"
"os"
"runtime"
+ "runtime/debug"
+ "sync/atomic"
"time"
)
func init() {
register("GCFairness", GCFairness)
+ register("GCFairness2", GCFairness2)
register("GCSys", GCSys)
}
time.Sleep(10 * time.Millisecond)
fmt.Println("OK")
}
+
+func GCFairness2() {
+ // Make sure user code can't exploit the GC's high priority
+ // scheduling to make scheduling of user code unfair. See
+ // issue #15706.
+ runtime.GOMAXPROCS(1)
+ debug.SetGCPercent(1)
+ var count [3]int64
+ var sink [3]interface{}
+ for i := range count {
+ go func(i int) {
+ for {
+ sink[i] = make([]byte, 1024)
+ atomic.AddInt64(&count[i], 1)
+ }
+ }(i)
+ }
+ // Note: If the unfairness is really bad, it may not even get
+ // past the sleep.
+ //
+ // If the scheduling rules change, this may not be enough time
+ // to let all goroutines run, but for now we cycle through
+ // them rapidly.
+ time.Sleep(30 * time.Millisecond)
+ for i := range count {
+ if atomic.LoadInt64(&count[i]) == 0 {
+ fmt.Printf("goroutine %d did not run\n", i)
+ return
+ }
+ }
+ fmt.Println("OK")
+}
package main
-import "syscall"
+import (
+ "syscall"
+ "time"
+)
func init() {
register("SignalExitStatus", SignalExitStatus)
func SignalExitStatus() {
syscall.Kill(syscall.Getpid(), syscall.SIGTERM)
+
+ // Should die immediately, but we've seen flakiness on various
+ // systems (see issue 14063). It's possible that the signal is
+ // being delivered to a different thread and we are returning
+ // and exiting before that thread runs again. Give the program
+ // a little while to die to make sure we pick up the signal
+ // before we return and exit the program. The time here
+ // shouldn't matter--we'll never really sleep this long.
+ time.Sleep(time.Second)
}
void gopanic(void);
-static unsigned int
+static unsigned int __attribute__((__stdcall__))
die(void* x)
{
gopanic();
// stk is the stack containing sp.
// The caller's program counter is lr, unless lr is zero, in which case it is *(uintptr*)sp.
f = frame.fn
+ if f.pcsp == 0 {
+ // No frame information, must be external function, like race support.
+ // See golang.org/issue/13568.
+ break
+ }
// Found an actual function.
// Derive frame pointer and link register.
sp := frame.sp
if flags&_TraceJumpStack != 0 && f.entry == systemstackPC && gp == g.m.g0 && gp.m.curg != nil {
sp = gp.m.curg.sched.sp
+ frame.sp = sp
stkbarG = gp.m.curg
stkbar = stkbarG.stkbar[stkbarG.stkbarPos:]
cgoCtxt = gp.m.curg.cgoCtxt
if arg.file != nil {
print(gostringnocopy(arg.file), ":", arg.lineno, " ")
}
- print("pc=", hex(c), "\n")
+ print("pc=", hex(pc), "\n")
c++
if arg.more == 0 {
break
minv map[unsafe.Pointer]int32
}
+func reflectOffsLock() {
+ lock(&reflectOffs.lock)
+ if raceenabled {
+ raceacquire(unsafe.Pointer(&reflectOffs.lock))
+ }
+}
+
+func reflectOffsUnlock() {
+ if raceenabled {
+ racerelease(unsafe.Pointer(&reflectOffs.lock))
+ }
+ unlock(&reflectOffs.lock)
+}
+
func resolveNameOff(ptrInModule unsafe.Pointer, off nameOff) name {
if off == 0 {
return name{}
}
}
if md == nil {
- lock(&reflectOffs.lock)
+ reflectOffsLock()
res, found := reflectOffs.m[int32(off)]
- unlock(&reflectOffs.lock)
+ reflectOffsUnlock()
if !found {
println("runtime: nameOff", hex(off), "base", hex(base), "not in ranges:")
for next := &firstmoduledata; next != nil; next = next.next {
}
}
if md == nil {
- lock(&reflectOffs.lock)
+ reflectOffsLock()
res := reflectOffs.m[int32(off)]
- unlock(&reflectOffs.lock)
+ reflectOffsUnlock()
if res == nil {
println("runtime: typeOff", hex(off), "base", hex(base), "not in ranges:")
for next := &firstmoduledata; next != nil; next = next.next {
}
}
if md == nil {
- lock(&reflectOffs.lock)
+ reflectOffsLock()
res := reflectOffs.m[int32(off)]
- unlock(&reflectOffs.lock)
+ reflectOffsUnlock()
if res == nil {
println("runtime: textOff", hex(off), "base", hex(base), "not in ranges:")
for next := &firstmoduledata; next != nil; next = next.next {
r.prevRune = -1
var abs int64
switch whence {
- case 0:
+ case io.SeekStart:
abs = offset
- case 1:
+ case io.SeekCurrent:
abs = r.i + offset
- case 2:
+ case io.SeekEnd:
abs = int64(len(r.s)) + offset
default:
return 0, errors.New("strings.Reader.Seek: invalid whence")
// indexShortStr returns the index of the first instance of c in s, or -1 if c is not present in s.
// indexShortStr requires 2 <= len(c) <= shortStringLen
func indexShortStr(s, c string) int // ../runtime/asm_$GOARCH.s
-const shortStringLen = 31
+const shortStringLen = 16 // TODO: restore to 31 when #15679 is fixed
// Index returns the index of the first instance of sep in s, or -1 if sep is not present in s.
func Index(s, sep string) int {
{"Read", func(r *Reader) { r.Read([]byte{0}) }},
{"ReadByte", func(r *Reader) { r.ReadByte() }},
{"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(&bytes.Buffer{}) }},
}
{"abc", "bcd", false},
{"abc", "", true},
{"", "a", false},
+
+ // cases to cover code in runtime/asm_amd64.s:indexShortStr
+ // 2-byte needle
+ {"xxxxxx", "01", false},
+ {"01xxxx", "01", true},
+ {"xx01xx", "01", true},
+ {"xxxx01", "01", true},
+ {"01xxxxx"[1:], "01", false},
+ {"xxxxx01"[:6], "01", false},
+ // 3-byte needle
+ {"xxxxxxx", "012", false},
+ {"012xxxx", "012", true},
+ {"xx012xx", "012", true},
+ {"xxxx012", "012", true},
+ {"012xxxxx"[1:], "012", false},
+ {"xxxxx012"[:7], "012", false},
+ // 4-byte needle
+ {"xxxxxxxx", "0123", false},
+ {"0123xxxx", "0123", true},
+ {"xx0123xx", "0123", true},
+ {"xxxx0123", "0123", true},
+ {"0123xxxxx"[1:], "0123", false},
+ {"xxxxx0123"[:8], "0123", false},
+ // 5-7-byte needle
+ {"xxxxxxxxx", "01234", false},
+ {"01234xxxx", "01234", true},
+ {"xx01234xx", "01234", true},
+ {"xxxx01234", "01234", true},
+ {"01234xxxxx"[1:], "01234", false},
+ {"xxxxx01234"[:9], "01234", false},
+ // 8-byte needle
+ {"xxxxxxxxxxxx", "01234567", false},
+ {"01234567xxxx", "01234567", true},
+ {"xx01234567xx", "01234567", true},
+ {"xxxx01234567", "01234567", true},
+ {"01234567xxxxx"[1:], "01234567", false},
+ {"xxxxx01234567"[:12], "01234567", false},
+ // 9-15-byte needle
+ {"xxxxxxxxxxxxx", "012345678", false},
+ {"012345678xxxx", "012345678", true},
+ {"xx012345678xx", "012345678", true},
+ {"xxxx012345678", "012345678", true},
+ {"012345678xxxxx"[1:], "012345678", false},
+ {"xxxxx012345678"[:13], "012345678", false},
+ // 16-byte needle
+ {"xxxxxxxxxxxxxxxxxxxx", "0123456789ABCDEF", false},
+ {"0123456789ABCDEFxxxx", "0123456789ABCDEF", true},
+ {"xx0123456789ABCDEFxx", "0123456789ABCDEF", true},
+ {"xxxx0123456789ABCDEF", "0123456789ABCDEF", true},
+ {"0123456789ABCDEFxxxxx"[1:], "0123456789ABCDEF", false},
+ {"xxxxx0123456789ABCDEF"[:20], "0123456789ABCDEF", false},
+ // 17-31-byte needle
+ {"xxxxxxxxxxxxxxxxxxxxx", "0123456789ABCDEFG", false},
+ {"0123456789ABCDEFGxxxx", "0123456789ABCDEFG", true},
+ {"xx0123456789ABCDEFGxx", "0123456789ABCDEFG", true},
+ {"xxxx0123456789ABCDEFG", "0123456789ABCDEFG", true},
+ {"0123456789ABCDEFGxxxxx"[1:], "0123456789ABCDEFG", false},
+ {"xxxxx0123456789ABCDEFG"[:21], "0123456789ABCDEFG", false},
+
+ // partial match cases
+ {"xx01x", "012", false}, // 3
+ {"xx0123x", "01234", false}, // 5-7
+ {"xx01234567x", "012345678", false}, // 9-15
+ {"xx0123456789ABCDEFx", "0123456789ABCDEFG", false}, // 17-31, issue 15679
}
func TestContains(t *testing.T) {
// Values can be created as part of other data structures.
// The zero value for a Value returns nil from Load.
// Once Store has been called, a Value must not be copied.
+//
+// A Value must not be copied after first use.
type Value struct {
+ noCopy noCopy
+
v interface{}
}
// Disable/enable preemption, implemented in runtime.
func runtime_procPin()
func runtime_procUnpin()
+
+// noCopy may be embedded into structs which must not be copied
+// after the first use.
+//
+// See https://github.com/golang/go/issues/8005#issuecomment-190753527
+// for details.
+type noCopy struct{}
+
+// Lock is a no-op used by -copylocks checker from `go vet`.
+func (*noCopy) Lock() {}
// A Cond can be created as part of other structures.
// A Cond must not be copied after first use.
type Cond struct {
+ noCopy noCopy
+
// L is held while observing or changing the condition
L Locker
panic("sync.Cond is copied")
}
}
+
+// noCopy may be embedded into structs which must not be copied
+// after the first use.
+//
+// See https://github.com/golang/go/issues/8005#issuecomment-190753527
+// for details.
+type noCopy struct{}
+
+// Lock is a no-op used by -copylocks checker from `go vet`.
+func (*noCopy) Lock() {}
// A Mutex is a mutual exclusion lock.
// Mutexes can be created as part of other structures;
// the zero value for a Mutex is an unlocked mutex.
+//
+// A Mutex must not be copied after first use.
type Mutex struct {
state int32
sema uint32
// that scenario. It is more efficient to have such objects implement their own
// free list.
//
+// A Pool must not be copied after first use.
type Pool struct {
+ noCopy noCopy
+
local unsafe.Pointer // local fixed-size per-P pool, actual type is [P]poolLocal
localSize uintptr // size of the local array
// RWMutexes can be created as part of other
// structures; the zero value for a RWMutex is
// an unlocked mutex.
+//
+// An RWMutex must not be copied after first use.
type RWMutex struct {
w Mutex // held if there are pending writers
writerSem uint32 // semaphore for writers to wait for completing readers
// goroutines to wait for. Then each of the goroutines
// runs and calls Done when finished. At the same time,
// Wait can be used to block until all goroutines have finished.
+//
+// A WaitGroup must not be copied after first use.
type WaitGroup struct {
+ noCopy noCopy
+
// 64-bit value: high 32 bits are counter, low 32 bits are waiter count.
// 64-bit atomic operations require 64-bit alignment, but 32-bit
// compilers do not ensure it. So we allocate 12 bytes and then use
"unsafe"
)
+// Deprecated: Use golang.org/x/net/bpf instead.
func BpfStmt(code, k int) *BpfInsn {
return &BpfInsn{Code: uint16(code), K: uint32(k)}
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func BpfJump(code, k, jt, jf int) *BpfInsn {
return &BpfInsn{Code: uint16(code), Jt: uint8(jt), Jf: uint8(jf), K: uint32(k)}
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func BpfBuflen(fd int) (int, error) {
var l int
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGBLEN, uintptr(unsafe.Pointer(&l)))
return l, nil
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func SetBpfBuflen(fd, l int) (int, error) {
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSBLEN, uintptr(unsafe.Pointer(&l)))
if err != 0 {
return l, nil
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func BpfDatalink(fd int) (int, error) {
var t int
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGDLT, uintptr(unsafe.Pointer(&t)))
return t, nil
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func SetBpfDatalink(fd, t int) (int, error) {
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSDLT, uintptr(unsafe.Pointer(&t)))
if err != 0 {
return t, nil
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func SetBpfPromisc(fd, m int) error {
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCPROMISC, uintptr(unsafe.Pointer(&m)))
if err != 0 {
return nil
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func FlushBpf(fd int) error {
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCFLUSH, 0)
if err != 0 {
value int16
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func BpfInterface(fd int, name string) (string, error) {
var iv ivalue
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGETIF, uintptr(unsafe.Pointer(&iv)))
return name, nil
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func SetBpfInterface(fd int, name string) error {
var iv ivalue
copy(iv.name[:], []byte(name))
return nil
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func BpfTimeout(fd int) (*Timeval, error) {
var tv Timeval
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGRTIMEOUT, uintptr(unsafe.Pointer(&tv)))
return &tv, nil
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func SetBpfTimeout(fd int, tv *Timeval) error {
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSRTIMEOUT, uintptr(unsafe.Pointer(tv)))
if err != 0 {
return nil
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func BpfStats(fd int) (*BpfStat, error) {
var s BpfStat
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGSTATS, uintptr(unsafe.Pointer(&s)))
return &s, nil
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func SetBpfImmediate(fd, m int) error {
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCIMMEDIATE, uintptr(unsafe.Pointer(&m)))
if err != 0 {
return nil
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func SetBpf(fd int, i []BpfInsn) error {
var p BpfProgram
p.Len = uint32(len(i))
return nil
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func CheckBpfVersion(fd int) error {
var v BpfVersion
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCVERSION, uintptr(unsafe.Pointer(&v)))
return nil
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func BpfHeadercmpl(fd int) (int, error) {
var f int
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGHDRCMPLT, uintptr(unsafe.Pointer(&f)))
return f, nil
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func SetBpfHeadercmpl(fd, f int) error {
_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSHDRCMPLT, uintptr(unsafe.Pointer(&f)))
if err != 0 {
Pgid int // Child's process group ID if Setpgid.
Pdeathsig Signal // Signal that the process will get when its parent dies (Linux only)
Cloneflags uintptr // Flags for clone calls (Linux only)
+ Unshare uintptr // Flags for unshare calls (Linux only)
UidMappings []SysProcIDMap // User ID mappings for user namespaces.
GidMappings []SysProcIDMap // Group ID mappings for user namespaces.
// GidMappingsEnableSetgroups enabling setgroups syscall.
}
}
+ // Unshare
+ if sys.Unshare != 0 {
+ _, _, err1 = RawSyscall(SYS_UNSHARE, sys.Unshare, 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
// User and groups
if cred := sys.Credential; cred != nil {
ngroups := uintptr(len(cred.Groups))
t.Fatal(err)
}
}
+
+func TestUnshare(t *testing.T) {
+ // Make sure we are running as root so we have permissions to use unshare
+ // and create a network namespace.
+ if os.Getuid() != 0 {
+ t.Skip("kernel prohibits unshare in unprivileged process, unless using user namespace")
+ }
+
+ // When running under the Go continuous build, skip tests for
+ // now when under Kubernetes. (where things are root but not quite)
+ // Both of these are our own environment variables.
+ // See Issue 12815.
+ if os.Getenv("GO_BUILDER_NAME") != "" && os.Getenv("IN_KUBERNETES") == "1" {
+ t.Skip("skipping test on Kubernetes-based builders; see Issue 12815")
+ }
+
+ cmd := exec.Command("cat", "/proc/net/dev")
+ cmd.SysProcAttr = &syscall.SysProcAttr{
+ Unshare: syscall.CLONE_NEWNET,
+ }
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("Cmd failed with err %v, output: %s", err, out)
+ }
+
+ // Check there is only the local network interface
+ sout := strings.TrimSpace(string(out))
+ if !strings.Contains(sout, "lo:") {
+ t.Fatalf("Expected lo network interface to exist, got %s", sout)
+ }
+
+ lines := strings.Split(sout, "\n")
+ if len(lines) != 3 {
+ t.Fatalf("Expected 3 lines of output, got %d", len(lines))
+ }
+}
"unsafe"
)
-// Lock synchronizing creation of new file descriptors with fork.
-//
-// We want the child in a fork/exec sequence to inherit only the
-// file descriptors we intend. To do that, we mark all file
-// descriptors close-on-exec and then, in the child, explicitly
-// unmark the ones we want the exec'ed program to keep.
-// Unix doesn't make this easy: there is, in general, no way to
-// allocate a new file descriptor close-on-exec. Instead you
-// have to allocate the descriptor and then mark it close-on-exec.
-// If a fork happens between those two events, the child's exec
-// will inherit an unwanted file descriptor.
-//
-// This lock solves that race: the create new fd/mark close-on-exec
-// operation is done holding ForkLock for reading, and the fork itself
-// is done holding ForkLock for writing. At least, that's the idea.
-// There are some complications.
-//
-// Some system calls that create new file descriptors can block
-// for arbitrarily long times: open on a hung NFS server or named
-// pipe, accept on a socket, and so on. We can't reasonably grab
-// the lock across those operations.
-//
-// It is worse to inherit some file descriptors than others.
-// If a non-malicious child accidentally inherits an open ordinary file,
-// that's not a big deal. On the other hand, if a long-lived child
-// accidentally inherits the write end of a pipe, then the reader
-// of that pipe will not see EOF until that child exits, potentially
-// causing the parent program to hang. This is a common problem
-// in threaded C programs that use popen.
-//
-// Luckily, the file descriptors that are most important not to
-// inherit are not the ones that can take an arbitrarily long time
-// to create: pipe returns instantly, and the net package uses
-// non-blocking I/O to accept on a listening socket.
-// The rules for which file descriptor-creating operations use the
-// ForkLock are as follows:
-//
-// 1) Pipe. Does not block. Use the ForkLock.
-// 2) Socket. Does not block. Use the ForkLock.
-// 3) Accept. If using non-blocking mode, use the ForkLock.
-// Otherwise, live with the race.
-// 4) Open. Can block. Use O_CLOEXEC if available (Linux).
-// Otherwise, live with the race.
-// 5) Dup. Does not block. Use the ForkLock.
-// On Linux, could use fcntl F_DUPFD_CLOEXEC
-// instead of the ForkLock, but only for dup(fd, -1).
-
+// ForkLock is not used on plan9.
var ForkLock sync.RWMutex
+// gstringb reads a non-empty string from b, prefixed with a 16-bit length in little-endian order.
+// It returns the string as a byte slice, or nil if b is too short to contain the length or
+// the full string.
+//go:nosplit
+func gstringb(b []byte) []byte {
+ if len(b) < 2 {
+ return nil
+ }
+ n, b := gbit16(b)
+ if int(n) > len(b) {
+ return nil
+ }
+ return b[:n]
+}
+
+// Offset of the name field in a 9P directory entry - see UnmarshalDir() in dir_plan9.go
+const nameOffset = 39
+
+// gdirname returns the first filename from a buffer of directory entries,
+// and a slice containing the remaining directory entries.
+// If the buffer doesn't start with a valid directory entry, the returned name is nil.
+//go:nosplit
+func gdirname(buf []byte) (name []byte, rest []byte) {
+ if len(buf) < 2 {
+ return
+ }
+ size, buf := gbit16(buf)
+ if size < STATFIXLEN || int(size) > len(buf) {
+ return
+ }
+ name = gstringb(buf[nameOffset:size])
+ rest = buf[size:]
+ return
+}
+
// StringSlicePtr converts a slice of strings to a slice of pointers
// to NUL-terminated byte arrays. If any string contains a NUL byte
// this function panics instead of returning an error.
if n == 0 {
break
}
- for i := 0; i < n; {
- m, _ := gbit16(buf[i:])
- m += 2
-
- if m < STATFIXLEN {
- return nil, ErrBadStat
- }
-
- s, _, ok := gstring(buf[i+41:])
- if !ok {
+ for b := buf[:n]; len(b) > 0; {
+ var s []byte
+ s, b = gdirname(b)
+ if s == nil {
return nil, ErrBadStat
}
- names = append(names, s)
- i += int(m)
+ names = append(names, string(s))
}
}
return
}
-// readdupdevice returns a list of currently opened fds (excluding stdin, stdout, stderr) from the dup device #d.
-// ForkLock should be write locked before calling, so that no new fds would be created while the fd list is being read.
-func readdupdevice() (fds []int, err error) {
- dupdevfd, err := Open("#d", O_RDONLY)
- if err != nil {
- return
- }
- defer Close(dupdevfd)
-
- names, err := readdirnames(dupdevfd)
- if err != nil {
- return
- }
-
- fds = make([]int, 0, len(names)/2)
- for _, name := range names {
- if n := len(name); n > 3 && name[n-3:n] == "ctl" {
- continue
- }
- fd := int(atoi([]byte(name)))
- switch fd {
- case 0, 1, 2, dupdevfd:
- continue
- }
- fds = append(fds, fd)
- }
- return
-}
-
-var startupFds []int
-
-// Plan 9 does not allow clearing the OCEXEC flag
-// from the underlying channel backing an open file descriptor,
-// therefore we store a list of already opened file descriptors
-// inside startupFds and skip them when manually closing descriptors
-// not meant to be passed to a child exec.
-func init() {
- startupFds, _ = readdupdevice()
-}
+// name of the directory containing names and control files for all open file descriptors
+var dupdev, _ = BytePtrFromString("#d")
// forkAndExecInChild forks the process, calling dup onto 0..len(fd)
// and finally invoking exec(argv0, argvv, envv) in the child.
// The calls to RawSyscall are okay because they are assembly
// functions that do not grow the stack.
//go:norace
-func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, attr *ProcAttr, fdsToClose []int, pipe int, rflag int) (pid int, err error) {
+func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, attr *ProcAttr, pipe int, rflag int) (pid int, err error) {
// Declare all variables at top in case any
// declarations require heap allocation (e.g., errbuf).
var (
clearenv int
envfd int
errbuf [ERRMAX]byte
+ statbuf [STATMAX]byte
+ dupdevfd int
)
// Guard against side effects of shuffling fds below.
// Fork succeeded, now in child.
// Close fds we don't need.
- for i = 0; i < len(fdsToClose); i++ {
- if fdsToClose[i] != pipe {
- RawSyscall(SYS_CLOSE, uintptr(fdsToClose[i]), 0, 0)
+ r1, _, _ = RawSyscall(SYS_OPEN, uintptr(unsafe.Pointer(dupdev)), uintptr(O_RDONLY), 0)
+ dupdevfd = int(r1)
+ if dupdevfd == -1 {
+ goto childerror
+ }
+dirloop:
+ for {
+ r1, _, _ = RawSyscall6(SYS_PREAD, uintptr(dupdevfd), uintptr(unsafe.Pointer(&statbuf[0])), uintptr(len(statbuf)), ^uintptr(0), ^uintptr(0), 0)
+ n := int(r1)
+ switch n {
+ case -1:
+ goto childerror
+ case 0:
+ break dirloop
+ }
+ for b := statbuf[:n]; len(b) > 0; {
+ var s []byte
+ s, b = gdirname(b)
+ if s == nil {
+ copy(errbuf[:], ErrBadStat.Error())
+ goto childerror1
+ }
+ if s[len(s)-1] == 'l' {
+ // control file for descriptor <N> is named <N>ctl
+ continue
+ }
+ closeFdExcept(int(atoi(s)), pipe, dupdevfd, fd)
}
}
+ RawSyscall(SYS_CLOSE, uintptr(dupdevfd), 0, 0)
+ // Write new environment variables.
if envv != nil {
- // Write new environment variables.
for i = 0; i < len(envv); i++ {
r1, _, _ = RawSyscall(SYS_CREATE, uintptr(unsafe.Pointer(envv[i].name)), uintptr(O_WRONLY), uintptr(0666))
childerror:
// send error string on pipe
RawSyscall(SYS_ERRSTR, uintptr(unsafe.Pointer(&errbuf[0])), uintptr(len(errbuf)), 0)
+childerror1:
errbuf[len(errbuf)-1] = 0
i = 0
for i < len(errbuf) && errbuf[i] != 0 {
panic("unreached")
}
+// close the numbered file descriptor, unless it is fd1, fd2, or a member of fds.
+//go:nosplit
+func closeFdExcept(n int, fd1 int, fd2 int, fds []int) {
+ if n == fd1 || n == fd2 {
+ return
+ }
+ for _, fd := range fds {
+ if n == fd {
+ return
+ }
+ }
+ RawSyscall(SYS_CLOSE, uintptr(n), 0, 0)
+}
+
func cexecPipe(p []int) error {
e := Pipe(p)
if e != nil {
}
}
- // Acquire the fork lock to prevent other threads from creating new fds before we fork.
- ForkLock.Lock()
-
- // get a list of open fds, excluding stdin,stdout and stderr that need to be closed in the child.
- // no new fds can be created while we hold the ForkLock for writing.
- openFds, e := readdupdevice()
- if e != nil {
- ForkLock.Unlock()
- return 0, e
- }
-
- fdsToClose := make([]int, 0, len(openFds))
- for _, fd := range openFds {
- doClose := true
-
- // exclude files opened at startup.
- for _, sfd := range startupFds {
- if fd == sfd {
- doClose = false
- break
- }
- }
-
- // exclude files explicitly requested by the caller.
- for _, rfd := range attr.Files {
- if fd == int(rfd) {
- doClose = false
- break
- }
- }
-
- if doClose {
- fdsToClose = append(fdsToClose, fd)
- }
- }
-
// Allocate child status pipe close on exec.
- e = cexecPipe(p[:])
+ e := cexecPipe(p[:])
if e != nil {
return 0, e
}
- fdsToClose = append(fdsToClose, p[0])
// Kick off child.
- pid, err = forkAndExecInChild(argv0p, argvp, envvParsed, dir, attr, fdsToClose, p[1], sys.Rfork)
+ pid, err = forkAndExecInChild(argv0p, argvp, envvParsed, dir, attr, p[1], sys.Rfork)
if err != nil {
if p[0] >= 0 {
Close(p[0])
Close(p[1])
}
- ForkLock.Unlock()
return 0, err
}
- ForkLock.Unlock()
// Read child error status from pipe.
Close(p[1])
Close(p[0])
if err != nil || n != 0 {
- if n != 0 {
+ if n > 0 {
err = NewError(string(errbuf[:n]))
+ } else if err == nil {
+ err = NewError("failed to read exec status")
}
// Child failed; wait for it to exit, to make sure
package syscall
import (
+ "io"
"sync"
)
func (f *naclFile) prw(b []byte, offset int64, rw func([]byte) (int, error)) (int, error) {
// NaCl has no pread; simulate with seek and hope for no races.
- old, err := f.seek(0, 1)
+ old, err := f.seek(0, io.SeekCurrent)
if err != nil {
return 0, err
}
- if _, err := f.seek(offset, 0); err != nil {
+ if _, err := f.seek(offset, io.SeekStart); err != nil {
return 0, err
}
n, err := rw(b)
- f.seek(old, 0)
+ f.seek(old, io.SeekStart)
return n, err
}
package syscall
import (
+ "io"
"sync"
"unsafe"
)
f.fsys.mu.Lock()
defer f.fsys.mu.Unlock()
switch whence {
- case 1:
+ case io.SeekCurrent:
offset += f.offset
- case 2:
+ case io.SeekEnd:
offset += f.inode.Size
}
if offset < 0 {
"unsafe"
)
+// Deprecated: Use golang.org/x/net/bpf instead.
func LsfStmt(code, k int) *SockFilter {
return &SockFilter{Code: uint16(code), K: uint32(k)}
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func LsfJump(code, k, jt, jf int) *SockFilter {
return &SockFilter{Code: uint16(code), Jt: uint8(jt), Jf: uint8(jf), K: uint32(k)}
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func LsfSocket(ifindex, proto int) (int, error) {
var lsall SockaddrLinklayer
s, e := Socket(AF_PACKET, SOCK_RAW, proto)
flags uint16
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func SetLsfPromisc(name string, m bool) error {
s, e := Socket(AF_INET, SOCK_DGRAM, 0)
if e != nil {
return nil
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func AttachLsf(fd int, i []SockFilter) error {
var p SockFprog
p.Len = uint16(len(i))
return setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, unsafe.Pointer(&p), unsafe.Sizeof(p))
}
+// Deprecated: Use golang.org/x/net/bpf instead.
func DetachLsf(fd int) error {
var dummy int
return setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, unsafe.Pointer(&dummy), unsafe.Sizeof(dummy))
"io/ioutil"
"log"
"os"
+ "path/filepath"
+ "runtime"
"sort"
"strconv"
"strings"
var (
filename = flag.String("output", "", "output file name (standard output if omitted)")
printTraceFlag = flag.Bool("trace", false, "generate print statement after every syscall")
- systemDLL = flag.Bool("systemdll", false, "whether all DLLs should be loaded from the Windows system directory")
- sysRepo = flag.Bool("xsys", false, "whether this code is for the x/sys subrepo")
+ systemDLL = flag.Bool("systemdll", true, "whether all DLLs should be loaded from the Windows system directory")
)
func trim(s string) string {
// Source files and functions.
type Source struct {
- Funcs []*Fn
- Files []string
- Imports []string
+ Funcs []*Fn
+ Files []string
+ StdLibImports []string
+ ExternalImports []string
}
func (src *Source) Import(pkg string) {
- src.Imports = append(src.Imports, pkg)
- sort.Strings(src.Imports)
+ src.StdLibImports = append(src.StdLibImports, pkg)
+ sort.Strings(src.StdLibImports)
+}
+
+func (src *Source) ExternalImport(pkg string) {
+ src.ExternalImports = append(src.ExternalImports, pkg)
+ sort.Strings(src.ExternalImports)
}
// ParseFiles parses files listed in fs and extracts all syscall
src := &Source{
Funcs: make([]*Fn, 0),
Files: make([]string, 0),
- Imports: []string{
+ StdLibImports: []string{
"unsafe",
},
- }
- if *systemDLL {
- src.Import("internal/syscall/windows/sysdll")
+ ExternalImports: make([]string, 0),
}
for _, file := range fs {
if err := src.ParseFile(file); err != nil {
return nil
}
+// IsStdRepo returns true if src is part of standard library.
+func (src *Source) IsStdRepo() (bool, error) {
+ if len(src.Files) == 0 {
+ return false, errors.New("no input files provided")
+ }
+ abspath, err := filepath.Abs(src.Files[0])
+ if err != nil {
+ return false, err
+ }
+ goroot := runtime.GOROOT()
+ if runtime.GOOS == "windows" {
+ abspath = strings.ToLower(abspath)
+ goroot = strings.ToLower(goroot)
+ }
+ return strings.HasPrefix(abspath, goroot), nil
+}
+
// Generate output source file from a source set src.
func (src *Source) Generate(w io.Writer) error {
- if *sysRepo && packageName != "windows" {
- src.Import("golang.org/x/sys/windows")
+ const (
+ pkgStd = iota // any package in std library
+ pkgXSysWindows // x/sys/windows package
+ pkgOther
+ )
+ isStdRepo, err := src.IsStdRepo()
+ if err != nil {
+ return err
+ }
+ var pkgtype int
+ switch {
+ case isStdRepo:
+ pkgtype = pkgStd
+ case packageName == "windows":
+ // TODO: this needs better logic than just using package name
+ pkgtype = pkgXSysWindows
+ default:
+ pkgtype = pkgOther
+ }
+ if *systemDLL {
+ switch pkgtype {
+ case pkgStd:
+ src.Import("internal/syscall/windows/sysdll")
+ case pkgXSysWindows:
+ default:
+ src.ExternalImport("golang.org/x/sys/windows")
+ }
}
if packageName != "syscall" {
src.Import("syscall")
"syscalldot": syscalldot,
"newlazydll": func(dll string) string {
arg := "\"" + dll + ".dll\""
- if *systemDLL {
- arg = "sysdll.Add(" + arg + ")"
- }
- if *sysRepo {
- if packageName == "windows" {
- return "NewLazySystemDLL(" + arg + ")"
- } else {
- return "windows.NewLazySystemDLL(" + arg + ")"
- }
- } else {
+ if !*systemDLL {
return syscalldot() + "NewLazyDLL(" + arg + ")"
}
+ switch pkgtype {
+ case pkgStd:
+ return syscalldot() + "NewLazyDLL(sysdll.Add(" + arg + "))"
+ case pkgXSysWindows:
+ return "NewLazySystemDLL(" + arg + ")"
+ default:
+ return "windows.NewLazySystemDLL(" + arg + ")"
+ }
},
}
t := template.Must(template.New("main").Funcs(funcMap).Parse(srcTemplate))
- err := t.Execute(w, src)
+ err = t.Execute(w, src)
if err != nil {
return errors.New("Failed to execute template: " + err.Error())
}
package {{packagename}}
import (
-{{range .Imports}}"{{.}}"
+{{range .StdLibImports}}"{{.}}"
+{{end}}
+
+{{range .ExternalImports}}"{{.}}"
{{end}}
)
// RouteRIB returns routing information base, as known as RIB,
// which consists of network facility information, states and
// parameters.
+//
+// Deprecated: Use golang.org/x/net/route instead.
func RouteRIB(facility, param int) ([]byte, error) {
mib := []_C_int{CTL_NET, AF_ROUTE, 0, 0, _C_int(facility), _C_int(param)}
// Find size.
}
// RoutingMessage represents a routing message.
+//
+// Deprecated: Use golang.org/x/net/route instead.
type RoutingMessage interface {
sockaddr() ([]Sockaddr, error)
}
// RouteMessage represents a routing message containing routing
// entries.
+//
+// Deprecated: Use golang.org/x/net/route instead.
type RouteMessage struct {
Header RtMsghdr
Data []byte
// InterfaceMessage represents a routing message containing
// network interface entries.
+//
+// Deprecated: Use golang.org/x/net/route instead.
type InterfaceMessage struct {
Header IfMsghdr
Data []byte
// InterfaceAddrMessage represents a routing message containing
// network interface address entries.
+//
+// Deprecated: Use golang.org/x/net/route instead.
type InterfaceAddrMessage struct {
Header IfaMsghdr
Data []byte
// ParseRoutingMessage parses b as routing messages and returns the
// slice containing the RoutingMessage interfaces.
+//
+// Deprecated: Use golang.org/x/net/route instead.
func ParseRoutingMessage(b []byte) (msgs []RoutingMessage, err error) {
nmsgs, nskips := 0, 0
for len(b) >= anyMessageLen {
// ParseRoutingSockaddr parses msg's payload as raw sockaddrs and
// returns the slice containing the Sockaddr interfaces.
+//
+// Deprecated: Use golang.org/x/net/route instead.
func ParseRoutingSockaddr(msg RoutingMessage) ([]Sockaddr, error) {
sas, err := msg.sockaddr()
if err != nil {
+++ /dev/null
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build darwin dragonfly freebsd netbsd openbsd
-
-package syscall_test
-
-import (
- "fmt"
- "net"
- "os"
- "syscall"
- "testing"
- "time"
-)
-
-func TestRouteRIB(t *testing.T) {
- for _, facility := range []int{syscall.NET_RT_DUMP, syscall.NET_RT_IFLIST} {
- for _, param := range []int{syscall.AF_UNSPEC, syscall.AF_INET, syscall.AF_INET6} {
- var err error
- var b []byte
- // The VM allocator wrapper functions can
- // return ENOMEM easily.
- for i := 0; i < 3; i++ {
- b, err = syscall.RouteRIB(facility, param)
- if err != nil {
- time.Sleep(5 * time.Millisecond)
- continue
- }
- break
- }
- if err != nil {
- t.Error(facility, param, err)
- continue
- }
- msgs, err := syscall.ParseRoutingMessage(b)
- if err != nil {
- t.Error(facility, param, err)
- continue
- }
- var ipv4loopback, ipv6loopback bool
- for _, m := range msgs {
- flags, err := parseRoutingMessageHeader(m)
- if err != nil {
- t.Error(err)
- continue
- }
- sas, err := parseRoutingSockaddrs(m)
- if err != nil {
- t.Error(err)
- continue
- }
- if flags&(syscall.RTA_DST|syscall.RTA_IFA) != 0 {
- sa := sas[syscall.RTAX_DST]
- if sa == nil {
- sa = sas[syscall.RTAX_IFA]
- }
- switch sa := sa.(type) {
- case *syscall.SockaddrInet4:
- if net.IP(sa.Addr[:]).IsLoopback() {
- ipv4loopback = true
- }
- case *syscall.SockaddrInet6:
- if net.IP(sa.Addr[:]).IsLoopback() {
- ipv6loopback = true
- }
- }
- }
- t.Log(facility, param, flags, sockaddrs(sas))
- }
- if param == syscall.AF_UNSPEC && len(msgs) > 0 && !ipv4loopback && !ipv6loopback {
- t.Errorf("no loopback facility found: ipv4/ipv6=%v/%v, %v", ipv4loopback, ipv6loopback, len(msgs))
- continue
- }
- }
- }
-}
-
-func TestRouteMonitor(t *testing.T) {
- if testing.Short() || os.Getuid() != 0 {
- t.Skip("must be root")
- }
-
- s, err := syscall.Socket(syscall.AF_ROUTE, syscall.SOCK_RAW, syscall.AF_UNSPEC)
- if err != nil {
- t.Fatal(err)
- }
- defer syscall.Close(s)
-
- tmo := time.After(30 * time.Second)
- go func() {
- b := make([]byte, os.Getpagesize())
- for {
- n, err := syscall.Read(s, b)
- if err != nil {
- return
- }
- msgs, err := syscall.ParseRoutingMessage(b[:n])
- if err != nil {
- t.Error(err)
- return
- }
- for _, m := range msgs {
- flags, err := parseRoutingMessageHeader(m)
- if err != nil {
- t.Error(err)
- continue
- }
- sas, err := parseRoutingSockaddrs(m)
- if err != nil {
- t.Error(err)
- continue
- }
- t.Log(flags, sockaddrs(sas))
- }
- }
- }()
- <-tmo
-}
-
-var parseInterfaceMessageTests = []*syscall.InterfaceMessage{
- // with link-layer address
- {
- Header: syscall.IfMsghdr{Version: syscall.RTM_VERSION, Addrs: syscall.RTA_IFP},
- Data: []uint8{
- 0x11, 0x12, 0x2, 0x0, 0x6, 0x3, 0x6, 0x0,
- 0x77, 0x6d, 0x31, 0x01, 0x23, 0x45, 0xab, 0xcd,
- 0xef, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- },
- },
- // without link-layer address
- {
- Header: syscall.IfMsghdr{Version: syscall.RTM_VERSION, Addrs: syscall.RTA_IFP},
- Data: []uint8{
- 0xe, 0x12, 0x4, 0x0, 0xf5, 0x6, 0x0, 0x0,
- 0x70, 0x66, 0x6c, 0x6f, 0x67, 0x30, 0x0, 0x0,
- },
- },
- // no data
- {
- Header: syscall.IfMsghdr{Version: syscall.RTM_VERSION, Addrs: syscall.RTA_IFP},
- Data: []uint8{
- 0x8, 0xa, 0xb, 0xc, 0xd, 0x0, 0x0, 0x0,
- },
- },
-}
-
-func TestParseInterfaceMessage(t *testing.T) {
- for i, tt := range parseInterfaceMessageTests {
- if _, err := syscall.ParseRoutingSockaddr(tt); err != nil {
- t.Errorf("#%d: %v", i, err)
- }
- }
-}
-
-type addrFamily byte
-
-func (f addrFamily) String() string {
- switch f {
- case syscall.AF_UNSPEC:
- return "unspec"
- case syscall.AF_LINK:
- return "link"
- case syscall.AF_INET:
- return "inet4"
- case syscall.AF_INET6:
- return "inet6"
- default:
- return fmt.Sprintf("unknown %d", f)
- }
-}
-
-type addrFlags uint32
-
-var addrFlagNames = [...]string{
- "dst",
- "gateway",
- "netmask",
- "genmask",
- "ifp",
- "ifa",
- "author",
- "brd",
- "mpls1,tag,src", // sockaddr_mpls=dragonfly,netbsd, sockaddr_in/in6=openbsd
- "mpls2,srcmask", // sockaddr_mpls=dragonfly, sockaddr_in/in6=openbsd
- "mpls3,label", // sockaddr_mpls=dragonfly, sockaddr_rtlabel=openbsd
-}
-
-func (f addrFlags) String() string {
- var s string
- for i, name := range addrFlagNames {
- if f&(1<<uint(i)) != 0 {
- if s != "" {
- s += "|"
- }
- s += name
- }
- }
- if s == "" {
- return "<nil>"
- }
- return s
-}
-
-type sockaddrs []syscall.Sockaddr
-
-func (sas sockaddrs) String() string {
- var s string
- for _, sa := range sas {
- if sa == nil {
- continue
- }
- if len(s) > 0 {
- s += " "
- }
- switch sa := sa.(type) {
- case *syscall.SockaddrDatalink:
- s += fmt.Sprintf("[%v/%v/%v t/n/a/s=%v/%v/%v/%v]", sa.Len, addrFamily(sa.Family), sa.Index, sa.Type, sa.Nlen, sa.Alen, sa.Slen)
- case *syscall.SockaddrInet4:
- s += fmt.Sprintf("%v", net.IP(sa.Addr[:]).To4())
- case *syscall.SockaddrInet6:
- s += fmt.Sprintf("%v", net.IP(sa.Addr[:]).To16())
- }
- }
- if s == "" {
- return "<nil>"
- }
- return s
-}
-
-func (sas sockaddrs) match(flags addrFlags) error {
- var f addrFlags
- family := syscall.AF_UNSPEC
- for i := range sas {
- if sas[i] != nil {
- f |= 1 << uint(i)
- }
- switch sas[i].(type) {
- case *syscall.SockaddrInet4:
- if family == syscall.AF_UNSPEC {
- family = syscall.AF_INET
- }
- if family != syscall.AF_INET {
- return fmt.Errorf("got %v; want %v", sockaddrs(sas), family)
- }
- case *syscall.SockaddrInet6:
- if family == syscall.AF_UNSPEC {
- family = syscall.AF_INET6
- }
- if family != syscall.AF_INET6 {
- return fmt.Errorf("got %v; want %v", sockaddrs(sas), family)
- }
- }
- }
- if f != flags {
- return fmt.Errorf("got %v; want %v", f, flags)
- }
- return nil
-}
// InterfaceMulticastAddrMessage represents a routing message
// containing network interface address entries.
+//
+// Deprecated: Use golang.org/x/net/route instead.
type InterfaceMulticastAddrMessage struct {
Header IfmaMsghdr2
Data []byte
// InterfaceAnnounceMessage represents a routing message containing
// network interface arrival and departure information.
+//
+// Deprecated: Use golang.org/x/net/route instead.
type InterfaceAnnounceMessage struct {
Header IfAnnounceMsghdr
}
// InterfaceMulticastAddrMessage represents a routing message
// containing network interface address entries.
+//
+// Deprecated: Use golang.org/x/net/route instead.
type InterfaceMulticastAddrMessage struct {
Header IfmaMsghdr
Data []byte
// InterfaceAnnounceMessage represents a routing message containing
// network interface arrival and departure information.
+//
+// Deprecated: Use golang.org/x/net/route instead.
type InterfaceAnnounceMessage struct {
Header IfAnnounceMsghdr
}
// InterfaceMulticastAddrMessage represents a routing message
// containing network interface address entries.
+//
+// Deprecated: Use golang.org/x/net/route instead.
type InterfaceMulticastAddrMessage struct {
Header IfmaMsghdr
Data []byte
+++ /dev/null
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build darwin dragonfly freebsd
-
-package syscall_test
-
-import (
- "fmt"
- "syscall"
-)
-
-func parseRoutingMessageHeader(m syscall.RoutingMessage) (addrFlags, error) {
- switch m := m.(type) {
- case *syscall.RouteMessage:
- errno := syscall.Errno(uintptr(m.Header.Errno))
- if errno != 0 {
- return 0, fmt.Errorf("%T: %v, %#v", m, errno, m.Header)
- }
- return addrFlags(m.Header.Addrs), nil
- case *syscall.InterfaceMessage:
- return addrFlags(m.Header.Addrs), nil
- case *syscall.InterfaceAddrMessage:
- return addrFlags(m.Header.Addrs), nil
- case *syscall.InterfaceMulticastAddrMessage:
- return addrFlags(m.Header.Addrs), nil
- default:
- panic(fmt.Sprintf("unknown routing message type: %T", m))
- }
-}
-
-func parseRoutingSockaddrs(m syscall.RoutingMessage) ([]syscall.Sockaddr, error) {
- switch m := m.(type) {
- case *syscall.RouteMessage:
- sas, err := syscall.ParseRoutingSockaddr(m)
- if err != nil {
- return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data)
- }
- if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil {
- return nil, err
- }
- return sas, nil
- case *syscall.InterfaceMessage:
- sas, err := syscall.ParseRoutingSockaddr(m)
- if err != nil {
- return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data)
- }
- if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil {
- return nil, err
- }
- return sas, nil
- case *syscall.InterfaceAddrMessage:
- sas, err := syscall.ParseRoutingSockaddr(m)
- if err != nil {
- return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data)
- }
- if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil {
- return nil, err
- }
- return sas, nil
- case *syscall.InterfaceMulticastAddrMessage:
- sas, err := syscall.ParseRoutingSockaddr(m)
- if err != nil {
- return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data)
- }
- if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil {
- return nil, err
- }
- return sas, nil
- default:
- panic(fmt.Sprintf("unknown routing message type: %T", m))
- }
-}
// InterfaceAnnounceMessage represents a routing message containing
// network interface arrival and departure information.
+//
+// Deprecated: Use golang.org/x/net/route instead.
type InterfaceAnnounceMessage struct {
Header IfAnnounceMsghdr
}
+++ /dev/null
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build netbsd openbsd
-
-package syscall_test
-
-import (
- "fmt"
- "syscall"
-)
-
-func parseRoutingMessageHeader(m syscall.RoutingMessage) (addrFlags, error) {
- switch m := m.(type) {
- case *syscall.RouteMessage:
- errno := syscall.Errno(uintptr(m.Header.Errno))
- if errno != 0 {
- return 0, fmt.Errorf("%T: %v, %#v", m, errno, m.Header)
- }
- return addrFlags(m.Header.Addrs), nil
- case *syscall.InterfaceMessage:
- return addrFlags(m.Header.Addrs), nil
- case *syscall.InterfaceAddrMessage:
- return addrFlags(m.Header.Addrs), nil
- default:
- panic(fmt.Sprintf("unknown routing message type: %T", m))
- }
-}
-
-func parseRoutingSockaddrs(m syscall.RoutingMessage) ([]syscall.Sockaddr, error) {
- switch m := m.(type) {
- case *syscall.RouteMessage:
- sas, err := syscall.ParseRoutingSockaddr(m)
- if err != nil {
- return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data)
- }
- if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil {
- return nil, err
- }
- return sas, nil
- case *syscall.InterfaceMessage:
- sas, err := syscall.ParseRoutingSockaddr(m)
- if err != nil {
- return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data)
- }
- if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil {
- return nil, err
- }
- return sas, nil
- case *syscall.InterfaceAddrMessage:
- sas, err := syscall.ParseRoutingSockaddr(m)
- if err != nil {
- return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data)
- }
- if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil {
- return nil, err
- }
- return sas, nil
- default:
- panic(fmt.Sprintf("unknown routing message type: %T", m))
- }
-}
// InterfaceAnnounceMessage represents a routing message containing
// network interface arrival and departure information.
+//
+// Deprecated: Use golang.org/x/net/route instead.
type InterfaceAnnounceMessage struct {
Header IfAnnounceMsghdr
}
func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
+//go:nosplit
func atoi(b []byte) (n uint) {
n = 0
for i := 0; i < len(b); i++ {
"flag"
"fmt"
"internal/testenv"
+ "io"
"io/ioutil"
"net"
"os"
}
f.Write([]byte("Hello from child process!\n"))
- f.Seek(0, 0)
+ f.Seek(0, io.SeekStart)
rights := syscall.UnixRights(int(f.Fd()))
dummyByte := []byte("x")
}
func TestSeekFailure(t *testing.T) {
- _, err := syscall.Seek(-1, 0, 0)
+ _, err := syscall.Seek(-1, 0, io.SeekStart)
if err == nil {
t.Fatalf("Seek(-1, 0, 0) did not fail")
}
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+ use(_p0)
if e1 != 0 {
err = errnoErr(e1)
}
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+ use(_p0)
if e1 != 0 {
err = errnoErr(e1)
}
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+ use(_p0)
if e1 != 0 {
err = errnoErr(e1)
}
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+ use(_p0)
if e1 != 0 {
err = errnoErr(e1)
}
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+ use(_p0)
if e1 != 0 {
err = errnoErr(e1)
}
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+ use(_p0)
if e1 != 0 {
err = errnoErr(e1)
}
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+ use(_p0)
if e1 != 0 {
err = errnoErr(e1)
}
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+ use(_p0)
if e1 != 0 {
err = errnoErr(e1)
}
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+ use(_p0)
if e1 != 0 {
err = errnoErr(e1)
}
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+ use(_p0)
if e1 != 0 {
err = errnoErr(e1)
}
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+ use(_p0)
if e1 != 0 {
err = errnoErr(e1)
}
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+ use(_p0)
if e1 != 0 {
err = errnoErr(e1)
}
parent.level = 1
}
if n, ok := m.fullName(parent, tc.sub); ok != tc.ok {
- t.Errorf("pattern: %q, parent: %q, sub %q: got %v; want %v",
- tc.pattern, tc.parent, tc.sub, ok, tc.ok, n)
+ t.Errorf("for pattern %q, fullName(parent=%q, sub=%q) = %q, ok %v; want ok %v",
+ tc.pattern, tc.parent, tc.sub, n, ok, tc.ok)
}
}
}
"strings"
)
-var defaultMaxCount = flag.Int("quickchecks", 100, "The default number of iterations for each check")
+var defaultMaxCount *int = flag.Int("quickchecks", 100, "The default number of iterations for each check")
// A Generator can generate random values of its own type.
type Generator interface {
case reflect.Uintptr:
v.SetUint(uint64(randInt64(rand)))
case reflect.Map:
- if generateNilValue(rand) {
- v.Set(reflect.Zero(concrete)) // Generate nil map.
- } else {
- numElems := rand.Intn(size)
- v.Set(reflect.MakeMap(concrete))
- for i := 0; i < numElems; i++ {
- key, ok1 := sizedValue(concrete.Key(), rand, size)
- value, ok2 := sizedValue(concrete.Elem(), rand, size)
- if !ok1 || !ok2 {
- return reflect.Value{}, false
- }
- v.SetMapIndex(key, value)
+ numElems := rand.Intn(size)
+ v.Set(reflect.MakeMap(concrete))
+ for i := 0; i < numElems; i++ {
+ key, ok1 := sizedValue(concrete.Key(), rand, size)
+ value, ok2 := sizedValue(concrete.Elem(), rand, size)
+ if !ok1 || !ok2 {
+ return reflect.Value{}, false
}
+ v.SetMapIndex(key, value)
}
case reflect.Ptr:
- if generateNilValue(rand) {
+ if rand.Intn(size) == 0 {
v.Set(reflect.Zero(concrete)) // Generate nil pointer.
} else {
elem, ok := sizedValue(concrete.Elem(), rand, size)
v.Elem().Set(elem)
}
case reflect.Slice:
- if generateNilValue(rand) {
- v.Set(reflect.Zero(concrete)) // Generate nil slice.
- } else {
- slCap := rand.Intn(size)
- slLen := rand.Intn(slCap + 1)
- sizeLeft := size - slCap
- v.Set(reflect.MakeSlice(concrete, slLen, slCap))
- for i := 0; i < slLen; i++ {
- elem, ok := sizedValue(concrete.Elem(), rand, sizeLeft)
- if !ok {
- return reflect.Value{}, false
- }
- v.Index(i).Set(elem)
+ numElems := rand.Intn(size)
+ sizeLeft := size - numElems
+ v.Set(reflect.MakeSlice(concrete, numElems, numElems))
+ for i := 0; i < numElems; i++ {
+ elem, ok := sizedValue(concrete.Elem(), rand, sizeLeft)
+ if !ok {
+ return reflect.Value{}, false
}
+ v.Index(i).Set(elem)
}
case reflect.Array:
for i := 0; i < v.Len(); i++ {
}
return strings.Join(s, ", ")
}
-
-func generateNilValue(r *rand.Rand) bool { return r.Intn(20) == 0 }
f := func(a A) bool { return true }
Check(f, nil)
}
+
+// Some serialization formats (e.g. encoding/pem) cannot distinguish
+// between a nil and an empty map or slice, so avoid generating the
+// zero value for these.
+func TestNonZeroSliceAndMap(t *testing.T) {
+ type Q struct {
+ M map[int]int
+ S []int
+ }
+ f := func(q Q) bool {
+ return q.M != nil && q.S != nil
+ }
+ err := Check(f, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+}
f: func(t *T) {
t.Skip()
},
+ }, {
+ desc: "panic on goroutine fail after test exit",
+ ok: false,
+ maxPar: 4,
+ f: func(t *T) {
+ ch := make(chan bool)
+ t.Run("", func(t *T) {
+ go func() {
+ <-ch
+ defer func() {
+ if r := recover(); r == nil {
+ realTest.Errorf("expected panic")
+ }
+ ch <- true
+ }()
+ t.Errorf("failed after success")
+ }()
+ })
+ ch <- true
+ <-ch
+ },
}}
for _, tc := range testCases {
ctx := newTestContext(tc.maxPar, newMatcher(regexp.MatchString, "", ""))
// example function, at least one other function, type, variable, or constant
// declaration, and no test or benchmark functions.
//
+// Subtests and Sub-benchmarks
+//
+// The Run methods of T and B allow defining subtests and sub-benchmarks,
+// without having to define separate functions for each. This enables uses
+// like table-driven benchmarks and creating hierarchical tests.
+// It also provides a way to share common setup and tear-down code:
+//
+// func TestFoo(t *testing.T) {
+// // <setup code>
+// t.Run("A=1", func(t *testing.T) { ... })
+// t.Run("A=2", func(t *testing.T) { ... })
+// t.Run("B=1", func(t *testing.T) { ... })
+// // <tear-down code>
+// }
+//
+// Each subtest and sub-benchmark has a unique name: the combination of the name
+// of the top-level test and the sequence of names passed to Run, separated by
+// slashes, with an optional trailing sequence number for disambiguation.
+//
+// The argument to the -run and -bench command-line flags is a slash-separated
+// list of regular expressions that match each name element in turn.
+// For example:
+//
+// go test -run Foo # Run top-level tests matching "Foo".
+// go test -run Foo/A= # Run subtests of Foo matching "A=".
+// go test -run /A=1 # Run all subtests of a top-level test matching "A=1".
+//
+// Subtests can also be used to control parallelism. A parent test will only
+// complete once all of its subtests complete. In this example, all tests are
+// run in parallel with each other, and only with each other, regardless of
+// other top-level tests that may be defined:
+//
+// func TestGroupedParallel(t *testing.T) {
+// for _, tc := range tests {
+// tc := tc // capture range variable
+// t.Run(tc.Name, func(t *testing.T) {
+// t.Parallel()
+// ...
+// })
+// }
+// }
+//
+// Run does not return until parallel subtests have completed, providing a way
+// to clean up after a group of parallel tests:
+//
+// func TestTeardownParallel(t *testing.T) {
+// // This Run will not return until the parallel tests finish.
+// t.Run("group", func(t *testing.T) {
+// t.Run("Test1", parallelTest1)
+// t.Run("Test2", parallelTest2)
+// t.Run("Test3", parallelTest3)
+// })
+// // <tear-down code>
+// }
+//
// Main
//
// It is sometimes necessary for a test program to do extra setup or teardown
// common holds the elements common between T and B and
// captures common methods such as Errorf.
type common struct {
- mu sync.RWMutex // guards output and failed
+ mu sync.RWMutex // guards output, failed, and done.
output []byte // Output generated by test or benchmark.
w io.Writer // For flushToParent.
chatty bool // A copy of the chatty flag.
failed bool // Test or benchmark has failed.
skipped bool // Test of benchmark has been skipped.
- finished bool
+ finished bool // Test function has completed.
+ done bool // Test is finished and all subtests have completed.
parent *common
level int // Nesting depth of test or benchmark.
}
c.mu.Lock()
defer c.mu.Unlock()
+ // c.done needs to be locked to synchronize checks to c.done in parent tests.
+ if c.done {
+ panic("Fail in goroutine after " + c.name + " has completed")
+ }
c.failed = true
}
}
t.report() // Report after all subtests have finished.
+ // Do not lock t.done to allow race detector to detect race in case
+ // the user does not appropriately synchronizes a goroutine.
+ t.done = true
t.signal <- true
}()
someParsable = text
}`
var s scanner.Scanner
+ s.Filename = "example"
s.Init(strings.NewReader(src))
var tok rune
for tok != scanner.EOF {
}
// Output:
- // At position 3:4 : if
- // At position 3:6 : a
- // At position 3:8 : >
- // At position 3:11 : 10
- // At position 3:13 : {
- // At position 4:15 : someParsable
- // At position 4:17 : =
- // At position 4:22 : text
- // At position 5:3 : }
- // At position 5:3 :
+ // At position example:3:4 : if
+ // At position example:3:6 : a
+ // At position example:3:8 : >
+ // At position example:3:11 : 10
+ // At position example:3:13 : {
+ // At position example:4:15 : someParsable
+ // At position example:4:17 : =
+ // At position example:4:22 : text
+ // At position example:5:3 : }
+ // At position example:5:3 :
}
func (pos Position) String() string {
s := pos.Filename
- if pos.IsValid() {
- if s != "" {
- s += ":"
- }
- s += fmt.Sprintf("%d:%d", pos.Line, pos.Column)
- }
if s == "" {
- s = "???"
+ s = "<input>"
+ }
+ if pos.IsValid() {
+ s += fmt.Sprintf(":%d:%d", pos.Line, pos.Column)
}
return s
}
if !pos.IsValid() {
pos = s.Pos()
}
- fmt.Fprintf(os.Stderr, "text/scanner: %s: %s\n", pos, msg)
+ fmt.Fprintf(os.Stderr, "%s: %s\n", pos, msg)
}
func (s *Scanner) isIdentRune(ch rune, i int) bool {
}
func TestError(t *testing.T) {
- testError(t, "\x00", "1:1", "illegal character NUL", 0)
- testError(t, "\x80", "1:1", "illegal UTF-8 encoding", utf8.RuneError)
- testError(t, "\xff", "1:1", "illegal UTF-8 encoding", utf8.RuneError)
-
- testError(t, "a\x00", "1:2", "illegal character NUL", Ident)
- testError(t, "ab\x80", "1:3", "illegal UTF-8 encoding", Ident)
- testError(t, "abc\xff", "1:4", "illegal UTF-8 encoding", Ident)
-
- testError(t, `"a`+"\x00", "1:3", "illegal character NUL", String)
- testError(t, `"ab`+"\x80", "1:4", "illegal UTF-8 encoding", String)
- testError(t, `"abc`+"\xff", "1:5", "illegal UTF-8 encoding", String)
-
- testError(t, "`a"+"\x00", "1:3", "illegal character NUL", String)
- testError(t, "`ab"+"\x80", "1:4", "illegal UTF-8 encoding", String)
- testError(t, "`abc"+"\xff", "1:5", "illegal UTF-8 encoding", String)
-
- testError(t, `'\"'`, "1:3", "illegal char escape", Char)
- testError(t, `"\'"`, "1:3", "illegal char escape", String)
-
- testError(t, `01238`, "1:6", "illegal octal number", Int)
- testError(t, `01238123`, "1:9", "illegal octal number", Int)
- testError(t, `0x`, "1:3", "illegal hexadecimal number", Int)
- testError(t, `0xg`, "1:3", "illegal hexadecimal number", Int)
- testError(t, `'aa'`, "1:4", "illegal char literal", Char)
-
- testError(t, `'`, "1:2", "literal not terminated", Char)
- testError(t, `'`+"\n", "1:2", "literal not terminated", Char)
- testError(t, `"abc`, "1:5", "literal not terminated", String)
- testError(t, `"abc`+"\n", "1:5", "literal not terminated", String)
- testError(t, "`abc\n", "2:1", "literal not terminated", String)
- testError(t, `/*/`, "1:4", "comment not terminated", EOF)
+ testError(t, "\x00", "<input>:1:1", "illegal character NUL", 0)
+ testError(t, "\x80", "<input>:1:1", "illegal UTF-8 encoding", utf8.RuneError)
+ testError(t, "\xff", "<input>:1:1", "illegal UTF-8 encoding", utf8.RuneError)
+
+ testError(t, "a\x00", "<input>:1:2", "illegal character NUL", Ident)
+ testError(t, "ab\x80", "<input>:1:3", "illegal UTF-8 encoding", Ident)
+ testError(t, "abc\xff", "<input>:1:4", "illegal UTF-8 encoding", Ident)
+
+ testError(t, `"a`+"\x00", "<input>:1:3", "illegal character NUL", String)
+ testError(t, `"ab`+"\x80", "<input>:1:4", "illegal UTF-8 encoding", String)
+ testError(t, `"abc`+"\xff", "<input>:1:5", "illegal UTF-8 encoding", String)
+
+ testError(t, "`a"+"\x00", "<input>:1:3", "illegal character NUL", String)
+ testError(t, "`ab"+"\x80", "<input>:1:4", "illegal UTF-8 encoding", String)
+ testError(t, "`abc"+"\xff", "<input>:1:5", "illegal UTF-8 encoding", String)
+
+ testError(t, `'\"'`, "<input>:1:3", "illegal char escape", Char)
+ testError(t, `"\'"`, "<input>:1:3", "illegal char escape", String)
+
+ testError(t, `01238`, "<input>:1:6", "illegal octal number", Int)
+ testError(t, `01238123`, "<input>:1:9", "illegal octal number", Int)
+ testError(t, `0x`, "<input>:1:3", "illegal hexadecimal number", Int)
+ testError(t, `0xg`, "<input>:1:3", "illegal hexadecimal number", Int)
+ testError(t, `'aa'`, "<input>:1:4", "illegal char literal", Char)
+
+ testError(t, `'`, "<input>:1:2", "literal not terminated", Char)
+ testError(t, `'`+"\n", "<input>:1:2", "literal not terminated", Char)
+ testError(t, `"abc`, "<input>:1:5", "literal not terminated", String)
+ testError(t, `"abc`+"\n", "<input>:1:5", "literal not terminated", String)
+ testError(t, "`abc\n", "<input>:2:1", "literal not terminated", String)
+ testError(t, `/*/`, "<input>:1:4", "comment not terminated", EOF)
}
// An errReader returns (0, err) where err is not io.EOF.
Functions and function names are described below.
A pipeline may be "chained" by separating a sequence of commands with pipeline
-characters '|'. In a chained pipeline, the result of the each command is
+characters '|'. In a chained pipeline, the result of each command is
passed as the last argument of the following command. The output of the final
command in the pipeline is the value of the pipeline.
"text/template/parse"
)
+// maxExecDepth specifies the maximum stack depth of templates within
+// templates. This limit is only practically reached by accidentally
+// recursive template invocations. This limit allows us to return
+// an error instead of triggering a stack overflow.
+const maxExecDepth = 100000
+
// state represents the state of an execution. It's not part of the
// template so that multiple executions of the same template
// can execute in parallel.
type state struct {
- tmpl *Template
- wr io.Writer
- node parse.Node // current node, for errors
- vars []variable // push-down stack of variable values.
+ tmpl *Template
+ wr io.Writer
+ node parse.Node // current node, for errors
+ vars []variable // push-down stack of variable values.
+ depth int // the height of the stack of executing templates.
}
// variable holds the dynamic value of a variable such as $, $x etc.
if tmpl == nil {
s.errorf("template %q not defined", t.Name)
}
+ if s.depth == maxExecDepth {
+ s.errorf("exceeded maximum template depth (%v)", maxExecDepth)
+ }
// Variables declared by the pipeline persist.
dot = s.evalPipeline(dot, t.Pipe)
newState := *s
+ newState.depth++
newState.tmpl = tmpl
// No dynamic scoping: template invocations inherit no variables.
newState.vars = []variable{{"$", dot}}
t.Errorf("got error %q, want %q", got, want)
}
}
+
+func TestMaxExecDepth(t *testing.T) {
+ tmpl := Must(New("tmpl").Parse(`{{template "tmpl" .}}`))
+ err := tmpl.Execute(ioutil.Discard, nil)
+ got := "<nil>"
+ if err != nil {
+ got = err.Error()
+ }
+ const want = "exceeded maximum template depth"
+ if !strings.Contains(got, want) {
+ t.Errorf("got error %q; want %q", got, want)
+ }
+}
// After waits for the duration to elapse and then sends the current time
// on the returned channel.
// It is equivalent to NewTimer(d).C.
+// The underlying Timer is not recovered by the garbage collector
+// until the timer fires. If efficiency is a concern, use NewTimer
+// instead and call Timer.Stop if the timer is no longer needed.
func After(d Duration) <-chan Time {
return NewTimer(d).C
}
}
func preadn(fd uintptr, buf []byte, off int) error {
- whence := 0
+ whence := seekStart
if off < 0 {
- whence = 2
+ whence = seekEnd
}
if _, err := syscall.Seek(int(fd), int64(off), whence); err != nil {
return err
}
func preadn(fd uintptr, buf []byte, off int) error {
- whence := 0
+ whence := seekStart
if off < 0 {
- whence = 2
+ whence = seekEnd
}
if _, err := syscall.Seek(int(fd), int64(off), whence); err != nil {
return err
}
func preadn(fd uintptr, buf []byte, off int) error {
- whence := 0
+ whence := seekStart
if off < 0 {
- whence = 2
+ whence = seekEnd
}
if _, err := syscall.Seek(syscall.Handle(fd), int64(off), whence); err != nil {
return err
"Namibia Standard Time": {"WAT", "WAST"}, // Africa/Windhoek
"Alaskan Standard Time": {"AKST", "AKDT"}, // America/Anchorage
"Paraguay Standard Time": {"PYT", "PYST"}, // America/Asuncion
- "Bahia Standard Time": {"BRT", "BRST"}, // America/Bahia
+ "Bahia Standard Time": {"BRT", "BRT"}, // America/Bahia
"SA Pacific Standard Time": {"COT", "COT"}, // America/Bogota
"Argentina Standard Time": {"ART", "ART"}, // America/Buenos_Aires
+ "Eastern Standard Time (Mexico)": {"EST", "EST"}, // America/Cancun
"Venezuela Standard Time": {"VET", "VET"}, // America/Caracas
"SA Eastern Standard Time": {"GFT", "GFT"}, // America/Cayenne
"Central Standard Time": {"CST", "CDT"}, // America/Chicago
"SA Western Standard Time": {"BOT", "BOT"}, // America/La_Paz
"Pacific Standard Time": {"PST", "PDT"}, // America/Los_Angeles
"Central Standard Time (Mexico)": {"CST", "CDT"}, // America/Mexico_City
- "Montevideo Standard Time": {"UYT", "UYST"}, // America/Montevideo
+ "Montevideo Standard Time": {"UYT", "UYT"}, // America/Montevideo
"Eastern Standard Time": {"EST", "EDT"}, // America/New_York
"US Mountain Standard Time": {"MST", "MST"}, // America/Phoenix
"Canada Central Standard Time": {"CST", "CST"}, // America/Regina
- "Pacific Standard Time (Mexico)": {"PST", "PDT"}, // America/Santa_Isabel
"Pacific SA Standard Time": {"CLT", "CLST"}, // America/Santiago
"E. South America Standard Time": {"BRT", "BRST"}, // America/Sao_Paulo
"Newfoundland Standard Time": {"NST", "NDT"}, // America/St_Johns
- "Central Asia Standard Time": {"ALMT", "ALMT"}, // Asia/Almaty
+ "Central Asia Standard Time": {"+06", "+06"}, // Asia/Almaty
"Jordan Standard Time": {"EET", "EEST"}, // Asia/Amman
"Arabic Standard Time": {"AST", "AST"}, // Asia/Baghdad
- "Azerbaijan Standard Time": {"AZT", "AZST"}, // Asia/Baku
+ "Azerbaijan Standard Time": {"AZT", "AZT"}, // Asia/Baku
"SE Asia Standard Time": {"ICT", "ICT"}, // Asia/Bangkok
+ "Altai Standard Time": {"+06", "+07"}, // Asia/Barnaul
"Middle East Standard Time": {"EET", "EEST"}, // Asia/Beirut
"India Standard Time": {"IST", "IST"}, // Asia/Calcutta
+ "Transbaikal Standard Time": {"IRKT", "YAKT"}, // Asia/Chita
"Sri Lanka Standard Time": {"IST", "IST"}, // Asia/Colombo
"Syria Standard Time": {"EET", "EEST"}, // Asia/Damascus
"Bangladesh Standard Time": {"BDT", "BDT"}, // Asia/Dhaka
"North Asia East Standard Time": {"IRKT", "IRKT"}, // Asia/Irkutsk
"Israel Standard Time": {"IST", "IDT"}, // Asia/Jerusalem
"Afghanistan Standard Time": {"AFT", "AFT"}, // Asia/Kabul
+ "Russia Time Zone 11": {"PETT", "PETT"}, // Asia/Kamchatka
"Pakistan Standard Time": {"PKT", "PKT"}, // Asia/Karachi
"Nepal Standard Time": {"NPT", "NPT"}, // Asia/Katmandu
"North Asia Standard Time": {"KRAT", "KRAT"}, // Asia/Krasnoyarsk
"Magadan Standard Time": {"MAGT", "MAGT"}, // Asia/Magadan
"N. Central Asia Standard Time": {"NOVT", "NOVT"}, // Asia/Novosibirsk
+ "North Korea Standard Time": {"KST", "KST"}, // Asia/Pyongyang
"Myanmar Standard Time": {"MMT", "MMT"}, // Asia/Rangoon
"Arab Standard Time": {"AST", "AST"}, // Asia/Riyadh
+ "Sakhalin Standard Time": {"SAKT", "SAKT"}, // Asia/Sakhalin
"Korea Standard Time": {"KST", "KST"}, // Asia/Seoul
"China Standard Time": {"CST", "CST"}, // Asia/Shanghai
"Singapore Standard Time": {"SGT", "SGT"}, // Asia/Singapore
+ "Russia Time Zone 10": {"SRET", "SRET"}, // Asia/Srednekolymsk
"Taipei Standard Time": {"CST", "CST"}, // Asia/Taipei
"West Asia Standard Time": {"UZT", "UZT"}, // Asia/Tashkent
"Georgian Standard Time": {"GET", "GET"}, // Asia/Tbilisi
"Iran Standard Time": {"IRST", "IRDT"}, // Asia/Tehran
"Tokyo Standard Time": {"JST", "JST"}, // Asia/Tokyo
- "Ulaanbaatar Standard Time": {"ULAT", "ULAT"}, // Asia/Ulaanbaatar
+ "Ulaanbaatar Standard Time": {"ULAT", "ULAST"}, // Asia/Ulaanbaatar
"Vladivostok Standard Time": {"VLAT", "VLAT"}, // Asia/Vladivostok
"Yakutsk Standard Time": {"YAKT", "YAKT"}, // Asia/Yakutsk
"Ekaterinburg Standard Time": {"YEKT", "YEKT"}, // Asia/Yekaterinburg
"Azores Standard Time": {"AZOT", "AZOST"}, // Atlantic/Azores
"Cape Verde Standard Time": {"CVT", "CVT"}, // Atlantic/Cape_Verde
"Greenwich Standard Time": {"GMT", "GMT"}, // Atlantic/Reykjavik
- "Cen. Australia Standard Time": {"CST", "CST"}, // Australia/Adelaide
- "E. Australia Standard Time": {"EST", "EST"}, // Australia/Brisbane
- "AUS Central Standard Time": {"CST", "CST"}, // Australia/Darwin
- "Tasmania Standard Time": {"EST", "EST"}, // Australia/Hobart
- "W. Australia Standard Time": {"WST", "WST"}, // Australia/Perth
- "AUS Eastern Standard Time": {"EST", "EST"}, // Australia/Sydney
+ "Cen. Australia Standard Time": {"ACST", "ACDT"}, // Australia/Adelaide
+ "E. Australia Standard Time": {"AEST", "AEST"}, // Australia/Brisbane
+ "AUS Central Standard Time": {"ACST", "ACST"}, // Australia/Darwin
+ "Tasmania Standard Time": {"AEST", "AEDT"}, // Australia/Hobart
+ "W. Australia Standard Time": {"AWST", "AWST"}, // Australia/Perth
+ "AUS Eastern Standard Time": {"AEST", "AEDT"}, // Australia/Sydney
"UTC": {"GMT", "GMT"}, // Etc/GMT
"UTC-11": {"GMT+11", "GMT+11"}, // Etc/GMT+11
"Dateline Standard Time": {"GMT+12", "GMT+12"}, // Etc/GMT+12
"UTC-02": {"GMT+2", "GMT+2"}, // Etc/GMT+2
"UTC+12": {"GMT-12", "GMT-12"}, // Etc/GMT-12
+ "Astrakhan Standard Time": {"+03", "+04"}, // Europe/Astrakhan
"W. Europe Standard Time": {"CET", "CEST"}, // Europe/Berlin
"GTB Standard Time": {"EET", "EEST"}, // Europe/Bucharest
"Central Europe Standard Time": {"CET", "CEST"}, // Europe/Budapest
+ "E. Europe Standard Time": {"EET", "EEST"}, // Europe/Chisinau
"Turkey Standard Time": {"EET", "EEST"}, // Europe/Istanbul
- "Kaliningrad Standard Time": {"FET", "FET"}, // Europe/Kaliningrad
+ "Kaliningrad Standard Time": {"EET", "EET"}, // Europe/Kaliningrad
"FLE Standard Time": {"EET", "EEST"}, // Europe/Kiev
"GMT Standard Time": {"GMT", "BST"}, // Europe/London
+ "Belarus Standard Time": {"MSK", "MSK"}, // Europe/Minsk
"Russian Standard Time": {"MSK", "MSK"}, // Europe/Moscow
"Romance Standard Time": {"CET", "CEST"}, // Europe/Paris
+ "Russia Time Zone 3": {"SAMT", "SAMT"}, // Europe/Samara
"Central European Standard Time": {"CET", "CEST"}, // Europe/Warsaw
"Mauritius Standard Time": {"MUT", "MUT"}, // Indian/Mauritius
- "Samoa Standard Time": {"WST", "WST"}, // Pacific/Apia
+ "Samoa Standard Time": {"WSST", "WSDT"}, // Pacific/Apia
"New Zealand Standard Time": {"NZST", "NZDT"}, // Pacific/Auckland
- "Fiji Standard Time": {"FJT", "FJT"}, // Pacific/Fiji
+ "Fiji Standard Time": {"FJT", "FJST"}, // Pacific/Fiji
"Central Pacific Standard Time": {"SBT", "SBT"}, // Pacific/Guadalcanal
"Hawaiian Standard Time": {"HST", "HST"}, // Pacific/Honolulu
"Line Islands Standard Time": {"LINT", "LINT"}, // Pacific/Kiritimati
import "errors"
+// Copies of io.Seek* constants to avoid importing "io":
+const (
+ seekStart = 0
+ seekCurrent = 1
+ seekEnd = 2
+)
+
// Simple I/O interface to binary blob of data.
type data struct {
p []byte
}
}
}
+
+func TestLocationNames(t *testing.T) {
+ if time.Local.String() != "Local" {
+ t.Errorf(`invalid Local location name: got %q want "Local"`, time.Local)
+ }
+ if time.UTC.String() != "UTC" {
+ t.Errorf(`invalid UTC location name: got %q want "UTC"`, time.UTC)
+ }
+}
func initLocalFromTZI(i *syscall.Timezoneinformation) {
l := &localLoc
+ l.name = "Local"
+
nzone := 1
if i.StandardDate.Month > 0 {
nzone++
}
}
+func TestHuffmanDecodeExcessPadding(t *testing.T) {
+ tests := [][]byte{
+ {0xff}, // Padding Exceeds 7 bits
+ {0x1f, 0xff}, // {"a", 1 byte excess padding}
+ {0x1f, 0xff, 0xff}, // {"a", 2 byte excess padding}
+ {0x1f, 0xff, 0xff, 0xff}, // {"a", 3 byte excess padding}
+ {0xff, 0x9f, 0xff, 0xff, 0xff}, // {"a", 29 bit excess padding}
+ {'R', 0xbc, '0', 0xff, 0xff, 0xff, 0xff}, // Padding ends on partial symbol.
+ }
+ for i, in := range tests {
+ var buf bytes.Buffer
+ if _, err := HuffmanDecode(&buf, in); err != ErrInvalidHuffman {
+ t.Errorf("test-%d: decode(%q) = %v; want ErrInvalidHuffman", i, in, err)
+ }
+ }
+}
+
+func TestHuffmanDecodeEOS(t *testing.T) {
+ in := []byte{0xff, 0xff, 0xff, 0xff, 0xfc} // {EOS, "?"}
+ var buf bytes.Buffer
+ if _, err := HuffmanDecode(&buf, in); err != ErrInvalidHuffman {
+ t.Errorf("error = %v; want ErrInvalidHuffman", err)
+ }
+}
+
+func TestHuffmanDecodeMaxLengthOnTrailingByte(t *testing.T) {
+ in := []byte{0x00, 0x01} // {"0", "0", "0"}
+ var buf bytes.Buffer
+ if err := huffmanDecode(&buf, 2, in); err != ErrStringLength {
+ t.Errorf("error = %v; want ErrStringLength", err)
+ }
+}
+
+func TestHuffmanDecodeCorruptPadding(t *testing.T) {
+ in := []byte{0x00}
+ var buf bytes.Buffer
+ if _, err := HuffmanDecode(&buf, in); err != ErrInvalidHuffman {
+ t.Errorf("error = %v; want ErrInvalidHuffman", err)
+ }
+}
+
func TestHuffmanDecode(t *testing.T) {
tests := []struct {
inHex, want string
// maxLen bytes will return ErrStringLength.
func huffmanDecode(buf *bytes.Buffer, maxLen int, v []byte) error {
n := rootHuffmanNode
- cur, nbits := uint(0), uint8(0)
+ // cur is the bit buffer that has not been fed into n.
+ // cbits is the number of low order bits in cur that are valid.
+ // sbits is the number of bits of the symbol prefix being decoded.
+ cur, cbits, sbits := uint(0), uint8(0), uint8(0)
for _, b := range v {
cur = cur<<8 | uint(b)
- nbits += 8
- for nbits >= 8 {
- idx := byte(cur >> (nbits - 8))
+ cbits += 8
+ sbits += 8
+ for cbits >= 8 {
+ idx := byte(cur >> (cbits - 8))
n = n.children[idx]
if n == nil {
return ErrInvalidHuffman
return ErrStringLength
}
buf.WriteByte(n.sym)
- nbits -= n.codeLen
+ cbits -= n.codeLen
n = rootHuffmanNode
+ sbits = cbits
} else {
- nbits -= 8
+ cbits -= 8
}
}
}
- for nbits > 0 {
- n = n.children[byte(cur<<(8-nbits))]
- if n.children != nil || n.codeLen > nbits {
+ for cbits > 0 {
+ n = n.children[byte(cur<<(8-cbits))]
+ if n == nil {
+ return ErrInvalidHuffman
+ }
+ if n.children != nil || n.codeLen > cbits {
break
}
+ if maxLen != 0 && buf.Len() == maxLen {
+ return ErrStringLength
+ }
buf.WriteByte(n.sym)
- nbits -= n.codeLen
+ cbits -= n.codeLen
n = rootHuffmanNode
+ sbits = cbits
+ }
+ if sbits > 7 {
+ // Either there was an incomplete symbol, or overlong padding.
+ // Both are decoding errors per RFC 7541 section 5.2.
+ return ErrInvalidHuffman
}
+ if mask := uint(1<<cbits - 1); cur&mask != mask {
+ // Trailing bits must be a prefix of EOS per RFC 7541 section 5.2.
+ return ErrInvalidHuffman
+ }
+
return nil
}
-// Copyright 2009 The Go Authors. All rights reserved.
+// 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 http
+// Package httplex contains rules around lexical matters of various
+// HTTP-related specifications.
+//
+// This package is shared by the standard library (which vendors it)
+// and x/net/http2. It comes with no API stability promise.
+package httplex
import (
"strings"
"unicode/utf8"
)
-// This file deals with lexical matters of HTTP
-
var isTokenTable = [127]bool{
'!': true,
'#': true,
'~': true,
}
-func isToken(r rune) bool {
+func IsTokenRune(r rune) bool {
i := int(r)
return i < len(isTokenTable) && isTokenTable[i]
}
func isNotToken(r rune) bool {
- return !isToken(r)
+ return !IsTokenRune(r)
}
-// headerValuesContainsToken reports whether any string in values
+// HeaderValuesContainsToken reports whether any string in values
// contains the provided token, ASCII case-insensitively.
-func headerValuesContainsToken(values []string, token string) bool {
+func HeaderValuesContainsToken(values []string, token string) bool {
for _, v := range values {
if headerValueContainsToken(v, token) {
return true
return b < ' ' || b == del
}
-func validHeaderName(v string) bool {
+// ValidHeaderFieldName reports whether v is a valid HTTP/1.x header name.
+// HTTP/2 imposes the additional restriction that uppercase ASCII
+// letters are not allowed.
+//
+// RFC 7230 says:
+// header-field = field-name ":" OWS field-value OWS
+// field-name = token
+// token = 1*tchar
+// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
+// "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
+func ValidHeaderFieldName(v string) bool {
if len(v) == 0 {
return false
}
for _, r := range v {
- if !isToken(r) {
+ if !IsTokenRune(r) {
return false
}
}
return true
}
-func validHostHeader(h string) bool {
- // The latests spec is actually this:
+// ValidHostHeader reports whether h is a valid host header.
+func ValidHostHeader(h string) bool {
+ // The latest spec is actually this:
//
// http://tools.ietf.org/html/rfc7230#section-5.4
// Host = uri-host [ ":" port ]
'~': true, // unreserved
}
-// validHeaderValue reports whether v is a valid "field-value" according to
+// ValidHeaderFieldValue reports whether v is a valid "field-value" according to
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 :
//
// message-header = field-name ":" [ field-value ]
// LWS = [CRLF] 1*( SP | HT )
// CTL = <any US-ASCII control character
// (octets 0 - 31) and DEL (127)>
-func validHeaderValue(v string) bool {
+//
+// RFC 7230 says:
+// field-value = *( field-content / obs-fold )
+// obj-fold = N/A to http2, and deprecated
+// field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
+// field-vchar = VCHAR / obs-text
+// obs-text = %x80-FF
+// VCHAR = "any visible [USASCII] character"
+//
+// http2 further says: "Similarly, HTTP/2 allows header field values
+// that are not valid. While most of the values that can be encoded
+// will not alter header field parsing, carriage return (CR, ASCII
+// 0xd), line feed (LF, ASCII 0xa), and the zero character (NUL, ASCII
+// 0x0) might be exploited by an attacker if they are translated
+// verbatim. Any request or response that contains a character not
+// permitted in a header field value MUST be treated as malformed
+// (Section 8.1.2.6). Valid characters are defined by the
+// field-content ABNF rule in Section 3.2 of [RFC7230]."
+//
+// This function does not (yet?) properly handle the rejection of
+// strings that begin or end with SP or HTAB.
+func ValidHeaderFieldValue(v string) bool {
for i := 0; i < len(v); i++ {
b := v[i]
if isCTL(b) && !isLWS(b) {
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package http
+package httplex
import (
"testing"
for i := 0; i <= 130; i++ {
r := rune(i)
expected := isChar(r) && !isCtl(r) && !isSeparator(r)
- if isToken(r) != expected {
+ if IsTokenRune(r) != expected {
t.Errorf("isToken(0x%x) = %v", r, !expected)
}
}
},
}
for _, tt := range tests {
- got := headerValuesContainsToken(tt.vals, tt.token)
+ got := HeaderValuesContainsToken(tt.vals, tt.token)
if got != tt.want {
t.Errorf("headerValuesContainsToken(%q, %q) = %v; want %v", tt.vals, tt.token, got, tt.want)
}
--- /dev/null
+// 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.
+
+// +build darwin dragonfly freebsd netbsd openbsd
+
+package route
+
+import "runtime"
+
+// An Addr represents an address associated with packet routing.
+type Addr interface {
+ // Family returns an address family.
+ Family() int
+}
+
+// A LinkAddr represents a link-layer address.
+type LinkAddr struct {
+ Index int // interface index when attached
+ Name string // interface name when attached
+ Addr []byte // link-layer address when attached
+}
+
+// Family implements the Family method of Addr interface.
+func (a *LinkAddr) Family() int { return sysAF_LINK }
+
+func parseLinkAddr(b []byte) (Addr, error) {
+ if len(b) < 8 {
+ return nil, errInvalidAddr
+ }
+ _, a, err := parseKernelLinkAddr(sysAF_LINK, b[4:])
+ if err != nil {
+ return nil, err
+ }
+ a.(*LinkAddr).Index = int(nativeEndian.Uint16(b[2:4]))
+ return a, nil
+}
+
+// parseKernelLinkAddr parses b as a link-layer address in
+// conventional BSD kernel form.
+func parseKernelLinkAddr(_ int, b []byte) (int, Addr, error) {
+ // The encoding looks like the following:
+ // +----------------------------+
+ // | Type (1 octet) |
+ // +----------------------------+
+ // | Name length (1 octet) |
+ // +----------------------------+
+ // | Address length (1 octet) |
+ // +----------------------------+
+ // | Selector length (1 octet) |
+ // +----------------------------+
+ // | Data (variable) |
+ // +----------------------------+
+ //
+ // On some platforms, all-bit-one of length field means "don't
+ // care".
+ nlen, alen, slen := int(b[1]), int(b[2]), int(b[3])
+ if nlen == 0xff {
+ nlen = 0
+ }
+ if alen == 0xff {
+ alen = 0
+ }
+ if slen == 0xff {
+ slen = 0
+ }
+ l := 4 + nlen + alen + slen
+ if len(b) < l {
+ return 0, nil, errInvalidAddr
+ }
+ data := b[4:]
+ var name string
+ var addr []byte
+ if nlen > 0 {
+ name = string(data[:nlen])
+ data = data[nlen:]
+ }
+ if alen > 0 {
+ addr = data[:alen]
+ data = data[alen:]
+ }
+ return l, &LinkAddr{Name: name, Addr: addr}, nil
+}
+
+// An Inet4Addr represents an internet address for IPv4.
+type Inet4Addr struct {
+ IP [4]byte // IP address
+}
+
+// Family implements the Family method of Addr interface.
+func (a *Inet4Addr) Family() int { return sysAF_INET }
+
+// An Inet6Addr represents an internet address for IPv6.
+type Inet6Addr struct {
+ IP [16]byte // IP address
+ ZoneID int // zone identifier
+}
+
+// Family implements the Family method of Addr interface.
+func (a *Inet6Addr) Family() int { return sysAF_INET6 }
+
+// parseInetAddr parses b as an internet address for IPv4 or IPv6.
+func parseInetAddr(af int, b []byte) (Addr, error) {
+ switch af {
+ case sysAF_INET:
+ if len(b) < 16 {
+ return nil, errInvalidAddr
+ }
+ a := &Inet4Addr{}
+ copy(a.IP[:], b[4:8])
+ return a, nil
+ case sysAF_INET6:
+ if len(b) < 28 {
+ return nil, errInvalidAddr
+ }
+ a := &Inet6Addr{ZoneID: int(nativeEndian.Uint32(b[24:28]))}
+ copy(a.IP[:], b[8:24])
+ if a.IP[0] == 0xfe && a.IP[1]&0xc0 == 0x80 || a.IP[0] == 0xff && (a.IP[1]&0x0f == 0x01 || a.IP[1]&0x0f == 0x02) {
+ // KAME based IPv6 protocol stack usually
+ // embeds the interface index in the
+ // interface-local or link-local address as
+ // the kernel-internal form.
+ id := int(bigEndian.Uint16(a.IP[2:4]))
+ if id != 0 {
+ a.ZoneID = id
+ a.IP[2], a.IP[3] = 0, 0
+ }
+ }
+ return a, nil
+ default:
+ return nil, errInvalidAddr
+ }
+}
+
+// parseKernelInetAddr parses b as an internet address in conventional
+// BSD kernel form.
+func parseKernelInetAddr(af int, b []byte) (int, Addr, error) {
+ // The encoding looks similar to the NLRI encoding.
+ // +----------------------------+
+ // | Length (1 octet) |
+ // +----------------------------+
+ // | Address prefix (variable) |
+ // +----------------------------+
+ //
+ // The differences between the kernel form and the NLRI
+ // encoding are:
+ //
+ // - The length field of the kernel form indicates the prefix
+ // length in bytes, not in bits
+ //
+ // - In the kernel form, zero value of the length field
+ // doesn't mean 0.0.0.0/0 or ::/0
+ //
+ // - The kernel form appends leading bytes to the prefix field
+ // to make the <length, prefix> tuple to be conformed with
+ // the routing message boundary
+ l := int(b[0])
+ if runtime.GOOS == "darwin" {
+ // On Darwn, an address in the kernel form is also
+ // used as a message filler.
+ if l == 0 || len(b) > roundup(l) {
+ l = roundup(l)
+ }
+ } else {
+ l = roundup(l)
+ }
+ if len(b) < l {
+ return 0, nil, errInvalidAddr
+ }
+ // Don't reorder case expressions.
+ // The case expressions for IPv6 must come first.
+ const (
+ off4 = 4 // offset of in_addr
+ off6 = 8 // offset of in6_addr
+ )
+ switch {
+ case b[0] == 28: // size of sockaddr_in6
+ a := &Inet6Addr{}
+ copy(a.IP[:], b[off6:off6+16])
+ return int(b[0]), a, nil
+ case af == sysAF_INET6:
+ a := &Inet6Addr{}
+ if l-1 < off6 {
+ copy(a.IP[:], b[1:l])
+ } else {
+ copy(a.IP[:], b[l-off6:l])
+ }
+ return int(b[0]), a, nil
+ case b[0] == 16: // size of sockaddr_in
+ a := &Inet4Addr{}
+ copy(a.IP[:], b[off4:off4+4])
+ return int(b[0]), a, nil
+ default: // an old fashion, AF_UNSPEC or unknown means AF_INET
+ a := &Inet4Addr{}
+ if l-1 < off4 {
+ copy(a.IP[:], b[1:l])
+ } else {
+ copy(a.IP[:], b[l-off4:l])
+ }
+ return int(b[0]), a, nil
+ }
+}
+
+// A DefaultAddr represents an address of various operating
+// system-specific features.
+type DefaultAddr struct {
+ af int
+ Raw []byte // raw format of address
+}
+
+// Family implements the Family method of Addr interface.
+func (a *DefaultAddr) Family() int { return a.af }
+
+func parseDefaultAddr(b []byte) (Addr, error) {
+ if len(b) < 2 || len(b) < int(b[0]) {
+ return nil, errInvalidAddr
+ }
+ a := &DefaultAddr{af: int(b[1]), Raw: b[:b[0]]}
+ return a, nil
+}
+
+func parseAddrs(attrs uint, fn func(int, []byte) (int, Addr, error), b []byte) ([]Addr, error) {
+ var as [sysRTAX_MAX]Addr
+ af := int(sysAF_UNSPEC)
+ for i := uint(0); i < sysRTAX_MAX && len(b) >= roundup(0); i++ {
+ if attrs&(1<<i) == 0 {
+ continue
+ }
+ if i <= sysRTAX_BRD {
+ switch b[1] {
+ case sysAF_LINK:
+ a, err := parseLinkAddr(b)
+ if err != nil {
+ return nil, err
+ }
+ as[i] = a
+ b = b[roundup(int(b[0])):]
+ case sysAF_INET, sysAF_INET6:
+ af = int(b[1])
+ a, err := parseInetAddr(af, b)
+ if err != nil {
+ return nil, err
+ }
+ as[i] = a
+ b = b[roundup(int(b[0])):]
+ default:
+ l, a, err := fn(af, b)
+ if err != nil {
+ return nil, err
+ }
+ as[i] = a
+ ll := roundup(l)
+ if len(b) < ll {
+ b = b[l:]
+ } else {
+ b = b[ll:]
+ }
+ }
+ } else {
+ a, err := parseDefaultAddr(b)
+ if err != nil {
+ return nil, err
+ }
+ as[i] = a
+ b = b[roundup(int(b[0])):]
+ }
+ }
+ return as[:], nil
+}
--- /dev/null
+// 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 route
+
+import (
+ "reflect"
+ "testing"
+)
+
+type parseAddrsOnDarwinTest struct {
+ attrs uint
+ fn func(int, []byte) (int, Addr, error)
+ b []byte
+ as []Addr
+}
+
+var parseAddrsOnDarwinLittleEndianTests = []parseAddrsOnDarwinTest{
+ {
+ sysRTA_DST | sysRTA_GATEWAY | sysRTA_NETMASK,
+ parseKernelInetAddr,
+ []byte{
+ 0x10, 0x2, 0x0, 0x0, 0xc0, 0xa8, 0x56, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+ 0x14, 0x12, 0x4, 0x0, 0x6, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0,
+
+ 0x7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ []Addr{
+ &Inet4Addr{IP: [4]byte{192, 168, 86, 0}},
+ &LinkAddr{Index: 4},
+ &Inet4Addr{IP: [4]byte{255, 255, 255, 255}},
+ nil,
+ nil,
+ nil,
+ nil,
+ nil,
+ },
+ },
+}
+
+func TestParseAddrsOnDarwin(t *testing.T) {
+ tests := parseAddrsOnDarwinLittleEndianTests
+ if nativeEndian != littleEndian {
+ t.Skip("no test for non-little endian machine yet")
+ }
+
+ for i, tt := range tests {
+ as, err := parseAddrs(tt.attrs, tt.fn, tt.b)
+ if err != nil {
+ t.Error(i, err)
+ continue
+ }
+ if !reflect.DeepEqual(as, tt.as) {
+ t.Errorf("#%d: got %+v; want %+v", i, as, tt.as)
+ continue
+ }
+ }
+}
--- /dev/null
+// 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.
+
+// +build darwin dragonfly freebsd netbsd openbsd
+
+package route
+
+import (
+ "reflect"
+ "testing"
+)
+
+type parseAddrsTest struct {
+ attrs uint
+ fn func(int, []byte) (int, Addr, error)
+ b []byte
+ as []Addr
+}
+
+var parseAddrsLittleEndianTests = []parseAddrsTest{
+ {
+ sysRTA_DST | sysRTA_GATEWAY | sysRTA_NETMASK | sysRTA_BRD,
+ parseKernelInetAddr,
+ []byte{
+ 0x38, 0x12, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+ 0x38, 0x12, 0x2, 0x0, 0x6, 0x3, 0x6, 0x0,
+ 0x65, 0x6d, 0x31, 0x0, 0xc, 0x29, 0x66, 0x2c,
+ 0xdc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+ 0x10, 0x2, 0x0, 0x0, 0xac, 0x10, 0xdc, 0xb4,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+ 0x10, 0x2, 0x0, 0x0, 0xac, 0x10, 0xdc, 0xff,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ },
+ []Addr{
+ &LinkAddr{Index: 0},
+ &LinkAddr{Index: 2, Name: "em1", Addr: []byte{0x00, 0x0c, 0x29, 0x66, 0x2c, 0xdc}},
+ &Inet4Addr{IP: [4]byte{172, 16, 220, 180}},
+ nil,
+ nil,
+ nil,
+ nil,
+ &Inet4Addr{IP: [4]byte{172, 16, 220, 255}},
+ },
+ },
+ {
+ sysRTA_NETMASK | sysRTA_IFP | sysRTA_IFA,
+ parseKernelInetAddr,
+ []byte{
+ 0x7, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0,
+
+ 0x18, 0x12, 0xa, 0x0, 0x87, 0x8, 0x0, 0x0,
+ 0x76, 0x6c, 0x61, 0x6e, 0x35, 0x36, 0x38, 0x32,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+ 0x10, 0x2, 0x0, 0x0, 0xa9, 0xfe, 0x0, 0x1,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ },
+ []Addr{
+ nil,
+ nil,
+ &Inet4Addr{IP: [4]byte{255, 255, 255, 0}},
+ nil,
+ &LinkAddr{Index: 10, Name: "vlan5682"},
+ &Inet4Addr{IP: [4]byte{169, 254, 0, 1}},
+ nil,
+ nil,
+ },
+ },
+}
+
+func TestParseAddrs(t *testing.T) {
+ tests := parseAddrsLittleEndianTests
+ if nativeEndian != littleEndian {
+ t.Skip("no test for non-little endian machine yet")
+ }
+
+ for i, tt := range tests {
+ as, err := parseAddrs(tt.attrs, tt.fn, tt.b)
+ if err != nil {
+ t.Error(i, err)
+ continue
+ }
+ as = as[:8] // the list varies between operating systems
+ if !reflect.DeepEqual(as, tt.as) {
+ t.Errorf("#%d: got %+v; want %+v", i, as, tt.as)
+ continue
+ }
+ }
+}
--- /dev/null
+// 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.
+
+// +build darwin dragonfly freebsd netbsd openbsd
+
+package route
+
+// This file contains duplicates of encoding/binary package.
+//
+// This package is supposed to be used by the net package of standard
+// library. Therefore a package set used in the package must be the
+// same as net package.
+
+var (
+ littleEndian binaryLittleEndian
+ bigEndian binaryBigEndian
+)
+
+type binaryByteOrder interface {
+ Uint16([]byte) uint16
+ Uint32([]byte) uint32
+ PutUint16([]byte, uint16)
+ PutUint32([]byte, uint32)
+ Uint64([]byte) uint64
+}
+
+type binaryLittleEndian struct{}
+
+func (binaryLittleEndian) Uint16(b []byte) uint16 {
+ _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint16(b[0]) | uint16(b[1])<<8
+}
+
+func (binaryLittleEndian) PutUint16(b []byte, v uint16) {
+ _ = b[1] // early bounds check to guarantee safety of writes below
+ b[0] = byte(v)
+ b[1] = byte(v >> 8)
+}
+
+func (binaryLittleEndian) Uint32(b []byte) uint32 {
+ _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+}
+
+func (binaryLittleEndian) PutUint32(b []byte, v uint32) {
+ _ = b[3] // early bounds check to guarantee safety of writes below
+ b[0] = byte(v)
+ b[1] = byte(v >> 8)
+ b[2] = byte(v >> 16)
+ b[3] = byte(v >> 24)
+}
+
+func (binaryLittleEndian) Uint64(b []byte) uint64 {
+ _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
+ uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
+}
+
+type binaryBigEndian struct{}
+
+func (binaryBigEndian) Uint16(b []byte) uint16 {
+ _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint16(b[1]) | uint16(b[0])<<8
+}
+
+func (binaryBigEndian) PutUint16(b []byte, v uint16) {
+ _ = b[1] // early bounds check to guarantee safety of writes below
+ b[0] = byte(v >> 8)
+ b[1] = byte(v)
+}
+
+func (binaryBigEndian) Uint32(b []byte) uint32 {
+ _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
+}
+
+func (binaryBigEndian) PutUint32(b []byte, v uint32) {
+ _ = b[3] // early bounds check to guarantee safety of writes below
+ b[0] = byte(v >> 24)
+ b[1] = byte(v >> 16)
+ b[2] = byte(v >> 8)
+ b[3] = byte(v)
+}
+
+func (binaryBigEndian) Uint64(b []byte) uint64 {
+ _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
+ uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
+}
--- /dev/null
+// 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.
+
+// +build ignore
+
+package route
+
+/*
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+*/
+import "C"
+
+const (
+ sysAF_UNSPEC = C.AF_UNSPEC
+ sysAF_INET = C.AF_INET
+ sysAF_ROUTE = C.AF_ROUTE
+ sysAF_LINK = C.AF_LINK
+ sysAF_INET6 = C.AF_INET6
+
+ sysNET_RT_DUMP = C.NET_RT_DUMP
+ sysNET_RT_FLAGS = C.NET_RT_FLAGS
+ sysNET_RT_IFLIST = C.NET_RT_IFLIST
+ sysNET_RT_STAT = C.NET_RT_STAT
+ sysNET_RT_TRASH = C.NET_RT_TRASH
+ sysNET_RT_IFLIST2 = C.NET_RT_IFLIST2
+ sysNET_RT_DUMP2 = C.NET_RT_DUMP2
+ sysNET_RT_MAXID = C.NET_RT_MAXID
+)
+
+const (
+ sysCTL_MAXNAME = C.CTL_MAXNAME
+
+ sysCTL_UNSPEC = C.CTL_UNSPEC
+ sysCTL_KERN = C.CTL_KERN
+ sysCTL_VM = C.CTL_VM
+ sysCTL_VFS = C.CTL_VFS
+ sysCTL_NET = C.CTL_NET
+ sysCTL_DEBUG = C.CTL_DEBUG
+ sysCTL_HW = C.CTL_HW
+ sysCTL_MACHDEP = C.CTL_MACHDEP
+ sysCTL_USER = C.CTL_USER
+ sysCTL_MAXID = C.CTL_MAXID
+)
+
+const (
+ sysRTM_VERSION = C.RTM_VERSION
+
+ sysRTM_ADD = C.RTM_ADD
+ sysRTM_DELETE = C.RTM_DELETE
+ sysRTM_CHANGE = C.RTM_CHANGE
+ sysRTM_GET = C.RTM_GET
+ sysRTM_LOSING = C.RTM_LOSING
+ sysRTM_REDIRECT = C.RTM_REDIRECT
+ sysRTM_MISS = C.RTM_MISS
+ sysRTM_LOCK = C.RTM_LOCK
+ sysRTM_OLDADD = C.RTM_OLDADD
+ sysRTM_OLDDEL = C.RTM_OLDDEL
+ sysRTM_RESOLVE = C.RTM_RESOLVE
+ sysRTM_NEWADDR = C.RTM_NEWADDR
+ sysRTM_DELADDR = C.RTM_DELADDR
+ sysRTM_IFINFO = C.RTM_IFINFO
+ sysRTM_NEWMADDR = C.RTM_NEWMADDR
+ sysRTM_DELMADDR = C.RTM_DELMADDR
+ sysRTM_IFINFO2 = C.RTM_IFINFO2
+ sysRTM_NEWMADDR2 = C.RTM_NEWMADDR2
+ sysRTM_GET2 = C.RTM_GET2
+
+ sysRTA_DST = C.RTA_DST
+ sysRTA_GATEWAY = C.RTA_GATEWAY
+ sysRTA_NETMASK = C.RTA_NETMASK
+ sysRTA_GENMASK = C.RTA_GENMASK
+ sysRTA_IFP = C.RTA_IFP
+ sysRTA_IFA = C.RTA_IFA
+ sysRTA_AUTHOR = C.RTA_AUTHOR
+ sysRTA_BRD = C.RTA_BRD
+
+ sysRTAX_DST = C.RTAX_DST
+ sysRTAX_GATEWAY = C.RTAX_GATEWAY
+ sysRTAX_NETMASK = C.RTAX_NETMASK
+ sysRTAX_GENMASK = C.RTAX_GENMASK
+ sysRTAX_IFP = C.RTAX_IFP
+ sysRTAX_IFA = C.RTAX_IFA
+ sysRTAX_AUTHOR = C.RTAX_AUTHOR
+ sysRTAX_BRD = C.RTAX_BRD
+ sysRTAX_MAX = C.RTAX_MAX
+)
+
+const (
+ sizeofIfMsghdrDarwin15 = C.sizeof_struct_if_msghdr
+ sizeofIfaMsghdrDarwin15 = C.sizeof_struct_ifa_msghdr
+ sizeofIfmaMsghdrDarwin15 = C.sizeof_struct_ifma_msghdr
+ sizeofIfMsghdr2Darwin15 = C.sizeof_struct_if_msghdr2
+ sizeofIfmaMsghdr2Darwin15 = C.sizeof_struct_ifma_msghdr2
+ sizeofIfDataDarwin15 = C.sizeof_struct_if_data
+ sizeofIfData64Darwin15 = C.sizeof_struct_if_data64
+
+ sizeofRtMsghdrDarwin15 = C.sizeof_struct_rt_msghdr
+ sizeofRtMsghdr2Darwin15 = C.sizeof_struct_rt_msghdr2
+ sizeofRtMetricsDarwin15 = C.sizeof_struct_rt_metrics
+)
--- /dev/null
+// 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.
+
+// +build ignore
+
+package route
+
+/*
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+*/
+import "C"
+
+const (
+ sysAF_UNSPEC = C.AF_UNSPEC
+ sysAF_INET = C.AF_INET
+ sysAF_ROUTE = C.AF_ROUTE
+ sysAF_LINK = C.AF_LINK
+ sysAF_INET6 = C.AF_INET6
+
+ sysNET_RT_DUMP = C.NET_RT_DUMP
+ sysNET_RT_FLAGS = C.NET_RT_FLAGS
+ sysNET_RT_IFLIST = C.NET_RT_IFLIST
+ sysNET_RT_MAXID = C.NET_RT_MAXID
+)
+
+const (
+ sysCTL_MAXNAME = C.CTL_MAXNAME
+
+ sysCTL_UNSPEC = C.CTL_UNSPEC
+ sysCTL_KERN = C.CTL_KERN
+ sysCTL_VM = C.CTL_VM
+ sysCTL_VFS = C.CTL_VFS
+ sysCTL_NET = C.CTL_NET
+ sysCTL_DEBUG = C.CTL_DEBUG
+ sysCTL_HW = C.CTL_HW
+ sysCTL_MACHDEP = C.CTL_MACHDEP
+ sysCTL_USER = C.CTL_USER
+ sysCTL_P1003_1B = C.CTL_P1003_1B
+ sysCTL_LWKT = C.CTL_LWKT
+ sysCTL_MAXID = C.CTL_MAXID
+)
+
+const (
+ sysRTM_VERSION = C.RTM_VERSION
+
+ sysRTM_ADD = C.RTM_ADD
+ sysRTM_DELETE = C.RTM_DELETE
+ sysRTM_CHANGE = C.RTM_CHANGE
+ sysRTM_GET = C.RTM_GET
+ sysRTM_LOSING = C.RTM_LOSING
+ sysRTM_REDIRECT = C.RTM_REDIRECT
+ sysRTM_MISS = C.RTM_MISS
+ sysRTM_LOCK = C.RTM_LOCK
+ sysRTM_OLDADD = C.RTM_OLDADD
+ sysRTM_OLDDEL = C.RTM_OLDDEL
+ sysRTM_RESOLVE = C.RTM_RESOLVE
+ sysRTM_NEWADDR = C.RTM_NEWADDR
+ sysRTM_DELADDR = C.RTM_DELADDR
+ sysRTM_IFINFO = C.RTM_IFINFO
+ sysRTM_NEWMADDR = C.RTM_NEWMADDR
+ sysRTM_DELMADDR = C.RTM_DELMADDR
+ sysRTM_IFANNOUNCE = C.RTM_IFANNOUNCE
+ sysRTM_IEEE80211 = C.RTM_IEEE80211
+
+ sysRTA_DST = C.RTA_DST
+ sysRTA_GATEWAY = C.RTA_GATEWAY
+ sysRTA_NETMASK = C.RTA_NETMASK
+ sysRTA_GENMASK = C.RTA_GENMASK
+ sysRTA_IFP = C.RTA_IFP
+ sysRTA_IFA = C.RTA_IFA
+ sysRTA_AUTHOR = C.RTA_AUTHOR
+ sysRTA_BRD = C.RTA_BRD
+ sysRTA_MPLS1 = C.RTA_MPLS1
+ sysRTA_MPLS2 = C.RTA_MPLS2
+ sysRTA_MPLS3 = C.RTA_MPLS3
+
+ sysRTAX_DST = C.RTAX_DST
+ sysRTAX_GATEWAY = C.RTAX_GATEWAY
+ sysRTAX_NETMASK = C.RTAX_NETMASK
+ sysRTAX_GENMASK = C.RTAX_GENMASK
+ sysRTAX_IFP = C.RTAX_IFP
+ sysRTAX_IFA = C.RTAX_IFA
+ sysRTAX_AUTHOR = C.RTAX_AUTHOR
+ sysRTAX_BRD = C.RTAX_BRD
+ sysRTAX_MPLS1 = C.RTAX_MPLS1
+ sysRTAX_MPLS2 = C.RTAX_MPLS2
+ sysRTAX_MPLS3 = C.RTAX_MPLS3
+ sysRTAX_MAX = C.RTAX_MAX
+)
+
+const (
+ sizeofIfMsghdrDragonFlyBSD4 = C.sizeof_struct_if_msghdr
+ sizeofIfaMsghdrDragonFlyBSD4 = C.sizeof_struct_ifa_msghdr
+ sizeofIfmaMsghdrDragonFlyBSD4 = C.sizeof_struct_ifma_msghdr
+ sizeofIfAnnouncemsghdrDragonFlyBSD4 = C.sizeof_struct_if_announcemsghdr
+
+ sizeofRtMsghdrDragonFlyBSD4 = C.sizeof_struct_rt_msghdr
+ sizeofRtMetricsDragonFlyBSD4 = C.sizeof_struct_rt_metrics
+)
--- /dev/null
+// 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.
+
+// +build ignore
+
+package route
+
+/*
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+
+struct if_data_freebsd7 {
+ u_char ifi_type;
+ u_char ifi_physical;
+ u_char ifi_addrlen;
+ u_char ifi_hdrlen;
+ u_char ifi_link_state;
+ u_char ifi_spare_char1;
+ u_char ifi_spare_char2;
+ u_char ifi_datalen;
+ u_long ifi_mtu;
+ u_long ifi_metric;
+ u_long ifi_baudrate;
+ u_long ifi_ipackets;
+ u_long ifi_ierrors;
+ u_long ifi_opackets;
+ u_long ifi_oerrors;
+ u_long ifi_collisions;
+ u_long ifi_ibytes;
+ u_long ifi_obytes;
+ u_long ifi_imcasts;
+ u_long ifi_omcasts;
+ u_long ifi_iqdrops;
+ u_long ifi_noproto;
+ u_long ifi_hwassist;
+ time_t __ifi_epoch;
+ struct timeval __ifi_lastchange;
+};
+
+struct if_data_freebsd8 {
+ u_char ifi_type;
+ u_char ifi_physical;
+ u_char ifi_addrlen;
+ u_char ifi_hdrlen;
+ u_char ifi_link_state;
+ u_char ifi_spare_char1;
+ u_char ifi_spare_char2;
+ u_char ifi_datalen;
+ u_long ifi_mtu;
+ u_long ifi_metric;
+ u_long ifi_baudrate;
+ u_long ifi_ipackets;
+ u_long ifi_ierrors;
+ u_long ifi_opackets;
+ u_long ifi_oerrors;
+ u_long ifi_collisions;
+ u_long ifi_ibytes;
+ u_long ifi_obytes;
+ u_long ifi_imcasts;
+ u_long ifi_omcasts;
+ u_long ifi_iqdrops;
+ u_long ifi_noproto;
+ u_long ifi_hwassist;
+ time_t __ifi_epoch;
+ struct timeval __ifi_lastchange;
+};
+
+struct if_data_freebsd9 {
+ u_char ifi_type;
+ u_char ifi_physical;
+ u_char ifi_addrlen;
+ u_char ifi_hdrlen;
+ u_char ifi_link_state;
+ u_char ifi_spare_char1;
+ u_char ifi_spare_char2;
+ u_char ifi_datalen;
+ u_long ifi_mtu;
+ u_long ifi_metric;
+ u_long ifi_baudrate;
+ u_long ifi_ipackets;
+ u_long ifi_ierrors;
+ u_long ifi_opackets;
+ u_long ifi_oerrors;
+ u_long ifi_collisions;
+ u_long ifi_ibytes;
+ u_long ifi_obytes;
+ u_long ifi_imcasts;
+ u_long ifi_omcasts;
+ u_long ifi_iqdrops;
+ u_long ifi_noproto;
+ u_long ifi_hwassist;
+ time_t __ifi_epoch;
+ struct timeval __ifi_lastchange;
+};
+
+struct if_data_freebsd10 {
+ u_char ifi_type;
+ u_char ifi_physical;
+ u_char ifi_addrlen;
+ u_char ifi_hdrlen;
+ u_char ifi_link_state;
+ u_char ifi_vhid;
+ u_char ifi_baudrate_pf;
+ u_char ifi_datalen;
+ u_long ifi_mtu;
+ u_long ifi_metric;
+ u_long ifi_baudrate;
+ u_long ifi_ipackets;
+ u_long ifi_ierrors;
+ u_long ifi_opackets;
+ u_long ifi_oerrors;
+ u_long ifi_collisions;
+ u_long ifi_ibytes;
+ u_long ifi_obytes;
+ u_long ifi_imcasts;
+ u_long ifi_omcasts;
+ u_long ifi_iqdrops;
+ u_long ifi_noproto;
+ uint64_t ifi_hwassist;
+ time_t __ifi_epoch;
+ struct timeval __ifi_lastchange;
+};
+
+struct if_data_freebsd11 {
+ uint8_t ifi_type;
+ uint8_t ifi_physical;
+ uint8_t ifi_addrlen;
+ uint8_t ifi_hdrlen;
+ uint8_t ifi_link_state;
+ uint8_t ifi_vhid;
+ uint16_t ifi_datalen;
+ uint32_t ifi_mtu;
+ uint32_t ifi_metric;
+ uint64_t ifi_baudrate;
+ uint64_t ifi_ipackets;
+ uint64_t ifi_ierrors;
+ uint64_t ifi_opackets;
+ uint64_t ifi_oerrors;
+ uint64_t ifi_collisions;
+ uint64_t ifi_ibytes;
+ uint64_t ifi_obytes;
+ uint64_t ifi_imcasts;
+ uint64_t ifi_omcasts;
+ uint64_t ifi_iqdrops;
+ uint64_t ifi_oqdrops;
+ uint64_t ifi_noproto;
+ uint64_t ifi_hwassist;
+ union {
+ time_t tt;
+ uint64_t ph;
+ } __ifi_epoch;
+ union {
+ struct timeval tv;
+ struct {
+ uint64_t ph1;
+ uint64_t ph2;
+ } ph;
+ } __ifi_lastchange;
+};
+
+struct if_msghdr_freebsd7 {
+ u_short ifm_msglen;
+ u_char ifm_version;
+ u_char ifm_type;
+ int ifm_addrs;
+ int ifm_flags;
+ u_short ifm_index;
+ struct if_data_freebsd7 ifm_data;
+};
+
+struct if_msghdr_freebsd8 {
+ u_short ifm_msglen;
+ u_char ifm_version;
+ u_char ifm_type;
+ int ifm_addrs;
+ int ifm_flags;
+ u_short ifm_index;
+ struct if_data_freebsd8 ifm_data;
+};
+
+struct if_msghdr_freebsd9 {
+ u_short ifm_msglen;
+ u_char ifm_version;
+ u_char ifm_type;
+ int ifm_addrs;
+ int ifm_flags;
+ u_short ifm_index;
+ struct if_data_freebsd9 ifm_data;
+};
+
+struct if_msghdr_freebsd10 {
+ u_short ifm_msglen;
+ u_char ifm_version;
+ u_char ifm_type;
+ int ifm_addrs;
+ int ifm_flags;
+ u_short ifm_index;
+ struct if_data_freebsd10 ifm_data;
+};
+
+struct if_msghdr_freebsd11 {
+ u_short ifm_msglen;
+ u_char ifm_version;
+ u_char ifm_type;
+ int ifm_addrs;
+ int ifm_flags;
+ u_short ifm_index;
+ struct if_data_freebsd11 ifm_data;
+};
+*/
+import "C"
+
+const (
+ sysAF_UNSPEC = C.AF_UNSPEC
+ sysAF_INET = C.AF_INET
+ sysAF_ROUTE = C.AF_ROUTE
+ sysAF_LINK = C.AF_LINK
+ sysAF_INET6 = C.AF_INET6
+
+ sysNET_RT_DUMP = C.NET_RT_DUMP
+ sysNET_RT_FLAGS = C.NET_RT_FLAGS
+ sysNET_RT_IFLIST = C.NET_RT_IFLIST
+ sysNET_RT_IFMALIST = C.NET_RT_IFMALIST
+ sysNET_RT_IFLISTL = C.NET_RT_IFLISTL
+)
+
+const (
+ sysCTL_MAXNAME = C.CTL_MAXNAME
+
+ sysCTL_UNSPEC = C.CTL_UNSPEC
+ sysCTL_KERN = C.CTL_KERN
+ sysCTL_VM = C.CTL_VM
+ sysCTL_VFS = C.CTL_VFS
+ sysCTL_NET = C.CTL_NET
+ sysCTL_DEBUG = C.CTL_DEBUG
+ sysCTL_HW = C.CTL_HW
+ sysCTL_MACHDEP = C.CTL_MACHDEP
+ sysCTL_USER = C.CTL_USER
+ sysCTL_P1003_1B = C.CTL_P1003_1B
+)
+
+const (
+ sysRTM_VERSION = C.RTM_VERSION
+
+ sysRTM_ADD = C.RTM_ADD
+ sysRTM_DELETE = C.RTM_DELETE
+ sysRTM_CHANGE = C.RTM_CHANGE
+ sysRTM_GET = C.RTM_GET
+ sysRTM_LOSING = C.RTM_LOSING
+ sysRTM_REDIRECT = C.RTM_REDIRECT
+ sysRTM_MISS = C.RTM_MISS
+ sysRTM_LOCK = C.RTM_LOCK
+ sysRTM_RESOLVE = C.RTM_RESOLVE
+ sysRTM_NEWADDR = C.RTM_NEWADDR
+ sysRTM_DELADDR = C.RTM_DELADDR
+ sysRTM_IFINFO = C.RTM_IFINFO
+ sysRTM_NEWMADDR = C.RTM_NEWMADDR
+ sysRTM_DELMADDR = C.RTM_DELMADDR
+ sysRTM_IFANNOUNCE = C.RTM_IFANNOUNCE
+ sysRTM_IEEE80211 = C.RTM_IEEE80211
+
+ sysRTA_DST = C.RTA_DST
+ sysRTA_GATEWAY = C.RTA_GATEWAY
+ sysRTA_NETMASK = C.RTA_NETMASK
+ sysRTA_GENMASK = C.RTA_GENMASK
+ sysRTA_IFP = C.RTA_IFP
+ sysRTA_IFA = C.RTA_IFA
+ sysRTA_AUTHOR = C.RTA_AUTHOR
+ sysRTA_BRD = C.RTA_BRD
+
+ sysRTAX_DST = C.RTAX_DST
+ sysRTAX_GATEWAY = C.RTAX_GATEWAY
+ sysRTAX_NETMASK = C.RTAX_NETMASK
+ sysRTAX_GENMASK = C.RTAX_GENMASK
+ sysRTAX_IFP = C.RTAX_IFP
+ sysRTAX_IFA = C.RTAX_IFA
+ sysRTAX_AUTHOR = C.RTAX_AUTHOR
+ sysRTAX_BRD = C.RTAX_BRD
+ sysRTAX_MAX = C.RTAX_MAX
+)
+
+const (
+ sizeofIfMsghdrlFreeBSD10 = C.sizeof_struct_if_msghdrl
+ sizeofIfaMsghdrFreeBSD10 = C.sizeof_struct_ifa_msghdr
+ sizeofIfaMsghdrlFreeBSD10 = C.sizeof_struct_ifa_msghdrl
+ sizeofIfmaMsghdrFreeBSD10 = C.sizeof_struct_ifma_msghdr
+ sizeofIfAnnouncemsghdrFreeBSD10 = C.sizeof_struct_if_announcemsghdr
+
+ sizeofRtMsghdrFreeBSD10 = C.sizeof_struct_rt_msghdr
+ sizeofRtMetricsFreeBSD10 = C.sizeof_struct_rt_metrics
+
+ sizeofIfMsghdrFreeBSD7 = C.sizeof_struct_if_msghdr_freebsd7
+ sizeofIfMsghdrFreeBSD8 = C.sizeof_struct_if_msghdr_freebsd8
+ sizeofIfMsghdrFreeBSD9 = C.sizeof_struct_if_msghdr_freebsd9
+ sizeofIfMsghdrFreeBSD10 = C.sizeof_struct_if_msghdr_freebsd10
+ sizeofIfMsghdrFreeBSD11 = C.sizeof_struct_if_msghdr_freebsd11
+
+ sizeofIfDataFreeBSD7 = C.sizeof_struct_if_data_freebsd7
+ sizeofIfDataFreeBSD8 = C.sizeof_struct_if_data_freebsd8
+ sizeofIfDataFreeBSD9 = C.sizeof_struct_if_data_freebsd9
+ sizeofIfDataFreeBSD10 = C.sizeof_struct_if_data_freebsd10
+ sizeofIfDataFreeBSD11 = C.sizeof_struct_if_data_freebsd11
+
+ sizeofIfMsghdrlFreeBSD10Emu = C.sizeof_struct_if_msghdrl
+ sizeofIfaMsghdrFreeBSD10Emu = C.sizeof_struct_ifa_msghdr
+ sizeofIfaMsghdrlFreeBSD10Emu = C.sizeof_struct_ifa_msghdrl
+ sizeofIfmaMsghdrFreeBSD10Emu = C.sizeof_struct_ifma_msghdr
+ sizeofIfAnnouncemsghdrFreeBSD10Emu = C.sizeof_struct_if_announcemsghdr
+
+ sizeofRtMsghdrFreeBSD10Emu = C.sizeof_struct_rt_msghdr
+ sizeofRtMetricsFreeBSD10Emu = C.sizeof_struct_rt_metrics
+
+ sizeofIfMsghdrFreeBSD7Emu = C.sizeof_struct_if_msghdr_freebsd7
+ sizeofIfMsghdrFreeBSD8Emu = C.sizeof_struct_if_msghdr_freebsd8
+ sizeofIfMsghdrFreeBSD9Emu = C.sizeof_struct_if_msghdr_freebsd9
+ sizeofIfMsghdrFreeBSD10Emu = C.sizeof_struct_if_msghdr_freebsd10
+ sizeofIfMsghdrFreeBSD11Emu = C.sizeof_struct_if_msghdr_freebsd11
+
+ sizeofIfDataFreeBSD7Emu = C.sizeof_struct_if_data_freebsd7
+ sizeofIfDataFreeBSD8Emu = C.sizeof_struct_if_data_freebsd8
+ sizeofIfDataFreeBSD9Emu = C.sizeof_struct_if_data_freebsd9
+ sizeofIfDataFreeBSD10Emu = C.sizeof_struct_if_data_freebsd10
+ sizeofIfDataFreeBSD11Emu = C.sizeof_struct_if_data_freebsd11
+)
--- /dev/null
+// 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.
+
+// +build ignore
+
+package route
+
+/*
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+*/
+import "C"
+
+const (
+ sysAF_UNSPEC = C.AF_UNSPEC
+ sysAF_INET = C.AF_INET
+ sysAF_ROUTE = C.AF_ROUTE
+ sysAF_LINK = C.AF_LINK
+ sysAF_INET6 = C.AF_INET6
+
+ sysNET_RT_DUMP = C.NET_RT_DUMP
+ sysNET_RT_FLAGS = C.NET_RT_FLAGS
+ sysNET_RT_IFLIST = C.NET_RT_IFLIST
+ sysNET_RT_MAXID = C.NET_RT_MAXID
+)
+
+const (
+ sysCTL_MAXNAME = C.CTL_MAXNAME
+
+ sysCTL_UNSPEC = C.CTL_UNSPEC
+ sysCTL_KERN = C.CTL_KERN
+ sysCTL_VM = C.CTL_VM
+ sysCTL_VFS = C.CTL_VFS
+ sysCTL_NET = C.CTL_NET
+ sysCTL_DEBUG = C.CTL_DEBUG
+ sysCTL_HW = C.CTL_HW
+ sysCTL_MACHDEP = C.CTL_MACHDEP
+ sysCTL_USER = C.CTL_USER
+ sysCTL_DDB = C.CTL_DDB
+ sysCTL_PROC = C.CTL_PROC
+ sysCTL_VENDOR = C.CTL_VENDOR
+ sysCTL_EMUL = C.CTL_EMUL
+ sysCTL_SECURITY = C.CTL_SECURITY
+ sysCTL_MAXID = C.CTL_MAXID
+)
+
+const (
+ sysRTM_VERSION = C.RTM_VERSION
+
+ sysRTM_ADD = C.RTM_ADD
+ sysRTM_DELETE = C.RTM_DELETE
+ sysRTM_CHANGE = C.RTM_CHANGE
+ sysRTM_GET = C.RTM_GET
+ sysRTM_LOSING = C.RTM_LOSING
+ sysRTM_REDIRECT = C.RTM_REDIRECT
+ sysRTM_MISS = C.RTM_MISS
+ sysRTM_LOCK = C.RTM_LOCK
+ sysRTM_OLDADD = C.RTM_OLDADD
+ sysRTM_OLDDEL = C.RTM_OLDDEL
+ sysRTM_RESOLVE = C.RTM_RESOLVE
+ sysRTM_NEWADDR = C.RTM_NEWADDR
+ sysRTM_DELADDR = C.RTM_DELADDR
+ sysRTM_IFANNOUNCE = C.RTM_IFANNOUNCE
+ sysRTM_IEEE80211 = C.RTM_IEEE80211
+ sysRTM_SETGATE = C.RTM_SETGATE
+ sysRTM_LLINFO_UPD = C.RTM_LLINFO_UPD
+ sysRTM_IFINFO = C.RTM_IFINFO
+ sysRTM_CHGADDR = C.RTM_CHGADDR
+
+ sysRTA_DST = C.RTA_DST
+ sysRTA_GATEWAY = C.RTA_GATEWAY
+ sysRTA_NETMASK = C.RTA_NETMASK
+ sysRTA_GENMASK = C.RTA_GENMASK
+ sysRTA_IFP = C.RTA_IFP
+ sysRTA_IFA = C.RTA_IFA
+ sysRTA_AUTHOR = C.RTA_AUTHOR
+ sysRTA_BRD = C.RTA_BRD
+ sysRTA_TAG = C.RTA_TAG
+
+ sysRTAX_DST = C.RTAX_DST
+ sysRTAX_GATEWAY = C.RTAX_GATEWAY
+ sysRTAX_NETMASK = C.RTAX_NETMASK
+ sysRTAX_GENMASK = C.RTAX_GENMASK
+ sysRTAX_IFP = C.RTAX_IFP
+ sysRTAX_IFA = C.RTAX_IFA
+ sysRTAX_AUTHOR = C.RTAX_AUTHOR
+ sysRTAX_BRD = C.RTAX_BRD
+ sysRTAX_TAG = C.RTAX_TAG
+ sysRTAX_MAX = C.RTAX_MAX
+)
+
+const (
+ sizeofIfMsghdrNetBSD7 = C.sizeof_struct_if_msghdr
+ sizeofIfaMsghdrNetBSD7 = C.sizeof_struct_ifa_msghdr
+ sizeofIfAnnouncemsghdrNetBSD7 = C.sizeof_struct_if_announcemsghdr
+
+ sizeofRtMsghdrNetBSD7 = C.sizeof_struct_rt_msghdr
+ sizeofRtMetricsNetBSD7 = C.sizeof_struct_rt_metrics
+)
--- /dev/null
+// 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.
+
+// +build ignore
+
+package route
+
+/*
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+*/
+import "C"
+
+const (
+ sysAF_UNSPEC = C.AF_UNSPEC
+ sysAF_INET = C.AF_INET
+ sysAF_ROUTE = C.AF_ROUTE
+ sysAF_LINK = C.AF_LINK
+ sysAF_INET6 = C.AF_INET6
+
+ sysNET_RT_DUMP = C.NET_RT_DUMP
+ sysNET_RT_FLAGS = C.NET_RT_FLAGS
+ sysNET_RT_IFLIST = C.NET_RT_IFLIST
+ sysNET_RT_STATS = C.NET_RT_STATS
+ sysNET_RT_TABLE = C.NET_RT_TABLE
+ sysNET_RT_IFNAMES = C.NET_RT_IFNAMES
+ sysNET_RT_MAXID = C.NET_RT_MAXID
+)
+
+const (
+ sysCTL_MAXNAME = C.CTL_MAXNAME
+
+ sysCTL_UNSPEC = C.CTL_UNSPEC
+ sysCTL_KERN = C.CTL_KERN
+ sysCTL_VM = C.CTL_VM
+ sysCTL_FS = C.CTL_FS
+ sysCTL_NET = C.CTL_NET
+ sysCTL_DEBUG = C.CTL_DEBUG
+ sysCTL_HW = C.CTL_HW
+ sysCTL_MACHDEP = C.CTL_MACHDEP
+ sysCTL_DDB = C.CTL_DDB
+ sysCTL_VFS = C.CTL_VFS
+ sysCTL_MAXID = C.CTL_MAXID
+)
+
+const (
+ sysRTM_VERSION = C.RTM_VERSION
+
+ sysRTM_ADD = C.RTM_ADD
+ sysRTM_DELETE = C.RTM_DELETE
+ sysRTM_CHANGE = C.RTM_CHANGE
+ sysRTM_GET = C.RTM_GET
+ sysRTM_LOSING = C.RTM_LOSING
+ sysRTM_REDIRECT = C.RTM_REDIRECT
+ sysRTM_MISS = C.RTM_MISS
+ sysRTM_LOCK = C.RTM_LOCK
+ sysRTM_RESOLVE = C.RTM_RESOLVE
+ sysRTM_NEWADDR = C.RTM_NEWADDR
+ sysRTM_DELADDR = C.RTM_DELADDR
+ sysRTM_IFINFO = C.RTM_IFINFO
+ sysRTM_IFANNOUNCE = C.RTM_IFANNOUNCE
+ sysRTM_DESYNC = C.RTM_DESYNC
+
+ sysRTA_DST = C.RTA_DST
+ sysRTA_GATEWAY = C.RTA_GATEWAY
+ sysRTA_NETMASK = C.RTA_NETMASK
+ sysRTA_GENMASK = C.RTA_GENMASK
+ sysRTA_IFP = C.RTA_IFP
+ sysRTA_IFA = C.RTA_IFA
+ sysRTA_AUTHOR = C.RTA_AUTHOR
+ sysRTA_BRD = C.RTA_BRD
+ sysRTA_SRC = C.RTA_SRC
+ sysRTA_SRCMASK = C.RTA_SRCMASK
+ sysRTA_LABEL = C.RTA_LABEL
+
+ sysRTAX_DST = C.RTAX_DST
+ sysRTAX_GATEWAY = C.RTAX_GATEWAY
+ sysRTAX_NETMASK = C.RTAX_NETMASK
+ sysRTAX_GENMASK = C.RTAX_GENMASK
+ sysRTAX_IFP = C.RTAX_IFP
+ sysRTAX_IFA = C.RTAX_IFA
+ sysRTAX_AUTHOR = C.RTAX_AUTHOR
+ sysRTAX_BRD = C.RTAX_BRD
+ sysRTAX_SRC = C.RTAX_SRC
+ sysRTAX_SRCMASK = C.RTAX_SRCMASK
+ sysRTAX_LABEL = C.RTAX_LABEL
+ sysRTAX_MAX = C.RTAX_MAX
+)
--- /dev/null
+// 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.
+
+// +build darwin dragonfly freebsd netbsd openbsd
+
+package route
+
+// An InterfaceMessage represents an interface message.
+type InterfaceMessage struct {
+ Version int // message version
+ Type int // message type
+ Flags int // interface flags
+ Index int // interface index
+ Name string // interface name
+ Addrs []Addr // addresses
+
+ extOff int // offset of header extension
+ raw []byte // raw message
+}
+
+// An InterfaceAddrMessage represents an interface address message.
+type InterfaceAddrMessage struct {
+ Version int // message version
+ Type int // message type
+ Flags int // interface flags
+ Index int // interface index
+ Addrs []Addr // addresses
+
+ raw []byte // raw message
+}
+
+// Sys implements the Sys method of Message interface.
+func (m *InterfaceAddrMessage) Sys() []Sys { return nil }
+
+// An InterfaceMulticastAddrMessage represents an interface multicast
+// address message.
+type InterfaceMulticastAddrMessage struct {
+ Version int // message version
+ Type int // messsage type
+ Flags int // interface flags
+ Index int // interface index
+ Addrs []Addr // addresses
+
+ raw []byte // raw message
+}
+
+// Sys implements the Sys method of Message interface.
+func (m *InterfaceMulticastAddrMessage) Sys() []Sys { return nil }
+
+// An InterfaceAnnounceMessage represents an interface announcement
+// message.
+type InterfaceAnnounceMessage struct {
+ Version int // message version
+ Type int // message type
+ Index int // interface index
+ Name string // interface name
+ What int // what type of announcement
+
+ raw []byte // raw message
+}
+
+// Sys implements the Sys method of Message interface.
+func (m *InterfaceAnnounceMessage) Sys() []Sys { return nil }
--- /dev/null
+// 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.
+
+// +build dragonfly freebsd netbsd
+
+package route
+
+func (w *wireFormat) parseInterfaceAnnounceMessage(_ RIBType, b []byte) (Message, error) {
+ if len(b) < w.bodyOff {
+ return nil, errMessageTooShort
+ }
+ l := int(nativeEndian.Uint16(b[:2]))
+ if len(b) < l {
+ return nil, errInvalidMessage
+ }
+ m := &InterfaceAnnounceMessage{
+ Version: int(b[2]),
+ Type: int(b[3]),
+ Index: int(nativeEndian.Uint16(b[4:6])),
+ What: int(nativeEndian.Uint16(b[22:24])),
+ raw: b[:l],
+ }
+ for i := 0; i < 16; i++ {
+ if b[6+i] != 0 {
+ continue
+ }
+ m.Name = string(b[6 : 6+i])
+ break
+ }
+ return m, nil
+}
--- /dev/null
+// 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.
+
+// +build darwin dragonfly netbsd
+
+package route
+
+import "runtime"
+
+func (w *wireFormat) parseInterfaceMessage(_ RIBType, b []byte) (Message, error) {
+ if len(b) < w.bodyOff {
+ return nil, errMessageTooShort
+ }
+ l := int(nativeEndian.Uint16(b[:2]))
+ if len(b) < l {
+ return nil, errInvalidMessage
+ }
+ attrs := uint(nativeEndian.Uint32(b[4:8]))
+ if attrs&sysRTA_IFP == 0 {
+ return nil, nil
+ }
+ m := &InterfaceMessage{
+ Version: int(b[2]),
+ Type: int(b[3]),
+ Addrs: make([]Addr, sysRTAX_MAX),
+ Flags: int(nativeEndian.Uint32(b[8:12])),
+ Index: int(nativeEndian.Uint16(b[12:14])),
+ extOff: w.extOff,
+ raw: b[:l],
+ }
+ a, err := parseLinkAddr(b[w.bodyOff:])
+ if err != nil {
+ return nil, err
+ }
+ m.Addrs[sysRTAX_IFP] = a
+ m.Name = a.(*LinkAddr).Name
+ return m, nil
+}
+
+func (w *wireFormat) parseInterfaceAddrMessage(_ RIBType, b []byte) (Message, error) {
+ if len(b) < w.bodyOff {
+ return nil, errMessageTooShort
+ }
+ l := int(nativeEndian.Uint16(b[:2]))
+ if len(b) < l {
+ return nil, errInvalidMessage
+ }
+ m := &InterfaceAddrMessage{
+ Version: int(b[2]),
+ Type: int(b[3]),
+ Flags: int(nativeEndian.Uint32(b[8:12])),
+ raw: b[:l],
+ }
+ if runtime.GOOS == "netbsd" {
+ m.Index = int(nativeEndian.Uint16(b[16:18]))
+ } else {
+ m.Index = int(nativeEndian.Uint16(b[12:14]))
+ }
+ var err error
+ m.Addrs, err = parseAddrs(uint(nativeEndian.Uint32(b[4:8])), parseKernelInetAddr, b[w.bodyOff:])
+ if err != nil {
+ return nil, err
+ }
+ return m, nil
+}
--- /dev/null
+// 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 route
+
+func (w *wireFormat) parseInterfaceMessage(typ RIBType, b []byte) (Message, error) {
+ var extOff, bodyOff int
+ if typ == sysNET_RT_IFLISTL {
+ if len(b) < 20 {
+ return nil, errMessageTooShort
+ }
+ extOff = int(nativeEndian.Uint16(b[18:20]))
+ bodyOff = int(nativeEndian.Uint16(b[16:18]))
+ } else {
+ if len(b) < w.bodyOff {
+ return nil, errMessageTooShort
+ }
+ extOff = w.extOff
+ bodyOff = w.bodyOff
+ }
+ l := int(nativeEndian.Uint16(b[:2]))
+ if len(b) < l {
+ return nil, errInvalidMessage
+ }
+ attrs := uint(nativeEndian.Uint32(b[4:8]))
+ if attrs&sysRTA_IFP == 0 {
+ return nil, nil
+ }
+ m := &InterfaceMessage{
+ Version: int(b[2]),
+ Type: int(b[3]),
+ Flags: int(nativeEndian.Uint32(b[8:12])),
+ Index: int(nativeEndian.Uint16(b[12:14])),
+ Addrs: make([]Addr, sysRTAX_MAX),
+ extOff: extOff,
+ raw: b[:l],
+ }
+ a, err := parseLinkAddr(b[bodyOff:])
+ if err != nil {
+ return nil, err
+ }
+ m.Addrs[sysRTAX_IFP] = a
+ m.Name = a.(*LinkAddr).Name
+ return m, nil
+}
+
+func (w *wireFormat) parseInterfaceAddrMessage(typ RIBType, b []byte) (Message, error) {
+ var bodyOff int
+ if typ == sysNET_RT_IFLISTL {
+ if len(b) < 24 {
+ return nil, errMessageTooShort
+ }
+ bodyOff = int(nativeEndian.Uint16(b[16:18]))
+ } else {
+ if len(b) < w.bodyOff {
+ return nil, errMessageTooShort
+ }
+ bodyOff = w.bodyOff
+ }
+ l := int(nativeEndian.Uint16(b[:2]))
+ if len(b) < l {
+ return nil, errInvalidMessage
+ }
+ m := &InterfaceAddrMessage{
+ Version: int(b[2]),
+ Type: int(b[3]),
+ Flags: int(nativeEndian.Uint32(b[8:12])),
+ Index: int(nativeEndian.Uint16(b[12:14])),
+ raw: b[:l],
+ }
+ var err error
+ m.Addrs, err = parseAddrs(uint(nativeEndian.Uint32(b[4:8])), parseKernelInetAddr, b[bodyOff:])
+ if err != nil {
+ return nil, err
+ }
+ return m, nil
+}
--- /dev/null
+// 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.
+
+// +build darwin dragonfly freebsd
+
+package route
+
+func (w *wireFormat) parseInterfaceMulticastAddrMessage(_ RIBType, b []byte) (Message, error) {
+ if len(b) < w.bodyOff {
+ return nil, errMessageTooShort
+ }
+ l := int(nativeEndian.Uint16(b[:2]))
+ if len(b) < l {
+ return nil, errInvalidMessage
+ }
+ m := &InterfaceMulticastAddrMessage{
+ Version: int(b[2]),
+ Type: int(b[3]),
+ Flags: int(nativeEndian.Uint32(b[8:12])),
+ Index: int(nativeEndian.Uint16(b[12:14])),
+ raw: b[:l],
+ }
+ var err error
+ m.Addrs, err = parseAddrs(uint(nativeEndian.Uint32(b[4:8])), parseKernelInetAddr, b[w.bodyOff:])
+ if err != nil {
+ return nil, err
+ }
+ return m, nil
+}
--- /dev/null
+// 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 route
+
+func (*wireFormat) parseInterfaceMessage(_ RIBType, b []byte) (Message, error) {
+ if len(b) < 32 {
+ return nil, errMessageTooShort
+ }
+ l := int(nativeEndian.Uint16(b[:2]))
+ if len(b) < l {
+ return nil, errInvalidMessage
+ }
+ attrs := uint(nativeEndian.Uint32(b[12:16]))
+ if attrs&sysRTA_IFP == 0 {
+ return nil, nil
+ }
+ m := &InterfaceMessage{
+ Version: int(b[2]),
+ Type: int(b[3]),
+ Flags: int(nativeEndian.Uint32(b[16:20])),
+ Index: int(nativeEndian.Uint16(b[6:8])),
+ Addrs: make([]Addr, sysRTAX_MAX),
+ raw: b[:l],
+ }
+ a, err := parseLinkAddr(b[int(nativeEndian.Uint16(b[4:6])):])
+ if err != nil {
+ return nil, err
+ }
+ m.Addrs[sysRTAX_IFP] = a
+ m.Name = a.(*LinkAddr).Name
+ return m, nil
+}
+
+func (*wireFormat) parseInterfaceAddrMessage(_ RIBType, b []byte) (Message, error) {
+ if len(b) < 24 {
+ return nil, errMessageTooShort
+ }
+ l := int(nativeEndian.Uint16(b[:2]))
+ if len(b) < l {
+ return nil, errInvalidMessage
+ }
+ bodyOff := int(nativeEndian.Uint16(b[4:6]))
+ m := &InterfaceAddrMessage{
+ Version: int(b[2]),
+ Type: int(b[3]),
+ Flags: int(nativeEndian.Uint32(b[12:16])),
+ Index: int(nativeEndian.Uint16(b[6:8])),
+ raw: b[:l],
+ }
+ var err error
+ m.Addrs, err = parseAddrs(uint(nativeEndian.Uint32(b[12:16])), parseKernelInetAddr, b[bodyOff:])
+ if err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
+func (*wireFormat) parseInterfaceAnnounceMessage(_ RIBType, b []byte) (Message, error) {
+ if len(b) < 26 {
+ return nil, errMessageTooShort
+ }
+ l := int(nativeEndian.Uint16(b[:2]))
+ if len(b) < l {
+ return nil, errInvalidMessage
+ }
+ m := &InterfaceAnnounceMessage{
+ Version: int(b[2]),
+ Type: int(b[3]),
+ Index: int(nativeEndian.Uint16(b[6:8])),
+ What: int(nativeEndian.Uint16(b[8:10])),
+ raw: b[:l],
+ }
+ for i := 0; i < 16; i++ {
+ if b[10+i] != 0 {
+ continue
+ }
+ m.Name = string(b[10 : 10+i])
+ break
+ }
+ return m, nil
+}
--- /dev/null
+// 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.
+
+// +build darwin dragonfly freebsd netbsd openbsd
+
+package route
+
+// A Message represents a routing message.
+//
+// Note: This interface will be changed to support Marshal method in
+// future version.
+type Message interface {
+ // Sys returns operating system-specific information.
+ Sys() []Sys
+}
+
+// A Sys reprensents operating system-specific information.
+type Sys interface {
+ // SysType returns a type of operating system-specific
+ // information.
+ SysType() SysType
+}
+
+// A SysType represents a type of operating system-specific
+// information.
+type SysType int
+
+const (
+ SysMetrics SysType = iota
+ SysStats
+)
+
+// ParseRIB parses b as a routing information base and returns a list
+// of routing messages.
+func ParseRIB(typ RIBType, b []byte) ([]Message, error) {
+ if !typ.parseable() {
+ return nil, errUnsupportedMessage
+ }
+ var msgs []Message
+ nmsgs, nskips := 0, 0
+ for len(b) > 4 {
+ nmsgs++
+ l := int(nativeEndian.Uint16(b[:2]))
+ if b[2] != sysRTM_VERSION {
+ b = b[l:]
+ continue
+ }
+ mtyp := int(b[3])
+ if fn, ok := parseFns[mtyp]; !ok {
+ nskips++
+ } else {
+ m, err := fn(typ, b)
+ if err != nil {
+ return nil, err
+ }
+ if m == nil {
+ nskips++
+ } else {
+ msgs = append(msgs, m)
+ }
+ }
+ b = b[l:]
+ }
+ // We failed to parse any of the messages - version mismatch?
+ if nmsgs != len(msgs)+nskips {
+ return nil, errMessageMismatch
+ }
+ return msgs, nil
+}
--- /dev/null
+// 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 route
+
+import "testing"
+
+func TestFetchAndParseRIBOnDarwin(t *testing.T) {
+ for _, af := range []int{sysAF_UNSPEC, sysAF_INET, sysAF_INET6} {
+ for _, typ := range []RIBType{sysNET_RT_FLAGS, sysNET_RT_DUMP2, sysNET_RT_IFLIST2} {
+ ms, err := fetchAndParseRIB(af, typ)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ ss, err := msgs(ms).validate()
+ if err != nil {
+ t.Errorf("%v %d %v", addrFamily(af), typ, err)
+ continue
+ }
+ for _, s := range ss {
+ t.Log(s)
+ }
+ }
+ }
+}
--- /dev/null
+// 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 route
+
+import (
+ "testing"
+ "time"
+ "unsafe"
+)
+
+func TestFetchAndParseRIBOnFreeBSD(t *testing.T) {
+ for _, af := range []int{sysAF_UNSPEC, sysAF_INET, sysAF_INET6} {
+ for _, typ := range []RIBType{sysNET_RT_IFMALIST} {
+ ms, err := fetchAndParseRIB(af, typ)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ ss, err := msgs(ms).validate()
+ if err != nil {
+ t.Errorf("%v %d %v", addrFamily(af), typ, err)
+ continue
+ }
+ for _, s := range ss {
+ t.Log(s)
+ }
+ }
+ }
+}
+
+func TestFetchAndParseRIBOnFreeBSD10AndAbove(t *testing.T) {
+ if _, err := FetchRIB(sysAF_UNSPEC, sysNET_RT_IFLISTL, 0); err != nil {
+ t.Skip("NET_RT_LISTL not supported")
+ }
+ var p uintptr
+ if kernelAlign != int(unsafe.Sizeof(p)) {
+ t.Skip("NET_RT_LIST vs. NET_RT_LISTL doesn't work for 386 emulation on amd64")
+ }
+
+ var tests = [2]struct {
+ typ RIBType
+ b []byte
+ msgs []Message
+ ss []string
+ }{
+ {typ: sysNET_RT_IFLIST},
+ {typ: sysNET_RT_IFLISTL},
+ }
+ for _, af := range []int{sysAF_UNSPEC, sysAF_INET, sysAF_INET6} {
+ var lastErr error
+ for i := 0; i < 3; i++ {
+ for j := range tests {
+ var err error
+ if tests[j].b, err = FetchRIB(af, tests[j].typ, 0); err != nil {
+ lastErr = err
+ time.Sleep(10 * time.Millisecond)
+ }
+ }
+ if lastErr == nil {
+ break
+ }
+ }
+ if lastErr != nil {
+ t.Error(af, lastErr)
+ continue
+ }
+ for i := range tests {
+ var err error
+ if tests[i].msgs, err = ParseRIB(tests[i].typ, tests[i].b); err != nil {
+ lastErr = err
+ t.Error(af, err)
+ }
+ }
+ if lastErr != nil {
+ continue
+ }
+ for i := range tests {
+ var err error
+ tests[i].ss, err = msgs(tests[i].msgs).validate()
+ if err != nil {
+ lastErr = err
+ t.Error(af, err)
+ }
+ for _, s := range tests[i].ss {
+ t.Log(s)
+ }
+ }
+ if lastErr != nil {
+ continue
+ }
+ for i := len(tests) - 1; i > 0; i-- {
+ if len(tests[i].ss) != len(tests[i-1].ss) {
+ t.Errorf("got %v; want %v", tests[i].ss, tests[i-1].ss)
+ continue
+ }
+ for j, s1 := range tests[i].ss {
+ s0 := tests[i-1].ss[j]
+ if s1 != s0 {
+ t.Errorf("got %s; want %s", s1, s0)
+ }
+ }
+ }
+ }
+}
--- /dev/null
+// 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.
+
+// +build darwin dragonfly freebsd netbsd openbsd
+
+package route
+
+import (
+ "os"
+ "syscall"
+ "testing"
+ "time"
+)
+
+func TestFetchAndParseRIB(t *testing.T) {
+ for _, af := range []int{sysAF_UNSPEC, sysAF_INET, sysAF_INET6} {
+ for _, typ := range []RIBType{sysNET_RT_DUMP, sysNET_RT_IFLIST} {
+ ms, err := fetchAndParseRIB(af, typ)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ ss, err := msgs(ms).validate()
+ if err != nil {
+ t.Errorf("%v %d %v", addrFamily(af), typ, err)
+ continue
+ }
+ for _, s := range ss {
+ t.Log(s)
+ }
+ }
+ }
+}
+
+func TestMonitorAndParseRIB(t *testing.T) {
+ if testing.Short() || os.Getuid() != 0 {
+ t.Skip("must be root")
+ }
+
+ // We suppose that using an IPv4 link-local address and the
+ // dot1Q ID for Token Ring and FDDI doesn't harm anyone.
+ pv := &propVirtual{addr: "169.254.0.1", mask: "255.255.255.0"}
+ if err := pv.configure(1002); err != nil {
+ t.Skip(err)
+ }
+ if err := pv.setup(); err != nil {
+ t.Skip(err)
+ }
+ pv.teardown()
+
+ s, err := syscall.Socket(syscall.AF_ROUTE, syscall.SOCK_RAW, syscall.AF_UNSPEC)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer syscall.Close(s)
+
+ go func() {
+ b := make([]byte, os.Getpagesize())
+ for {
+ n, err := syscall.Read(s, b)
+ if err != nil {
+ return
+ }
+ ms, err := ParseRIB(0, b[:n])
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ ss, err := msgs(ms).validate()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ for _, s := range ss {
+ t.Log(s)
+ }
+ }
+ }()
+
+ for _, vid := range []int{1002, 1003, 1004, 1005} {
+ pv := &propVirtual{addr: "169.254.0.1", mask: "255.255.255.0"}
+ if err := pv.configure(vid); err != nil {
+ t.Fatal(err)
+ }
+ if err := pv.setup(); err != nil {
+ t.Fatal(err)
+ }
+ time.Sleep(200 * time.Millisecond)
+ if err := pv.teardown(); err != nil {
+ t.Fatal(err)
+ }
+ time.Sleep(200 * time.Millisecond)
+ }
+}
--- /dev/null
+// 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.
+
+// +build darwin dragonfly freebsd netbsd openbsd
+
+// Package route provides basic functions for the manipulation of
+// packet routing facilities on BSD variants.
+//
+// The package supports any version of Darwin, any version of
+// DragonFly BSD, FreeBSD 7 through 11, NetBSD 6 and above, and
+// OpenBSD 5.6 and above.
+package route
+
+import (
+ "errors"
+ "os"
+ "syscall"
+)
+
+var (
+ errUnsupportedMessage = errors.New("unsupported message")
+ errMessageMismatch = errors.New("message mismatch")
+ errMessageTooShort = errors.New("message too short")
+ errInvalidMessage = errors.New("invalid message")
+ errInvalidAddr = errors.New("invalid address")
+)
+
+// A RouteMessage represents a message conveying an address prefix, a
+// nexthop address and an output interface.
+type RouteMessage struct {
+ Version int // message version
+ Type int // message type
+ Flags int // route flags
+ Index int // interface index when atatched
+ Addrs []Addr // addresses
+
+ extOff int // offset of header extension
+ raw []byte // raw message
+}
+
+// A RIBType reprensents a type of routing information base.
+type RIBType int
+
+const (
+ RIBTypeRoute RIBType = syscall.NET_RT_DUMP
+ RIBTypeInterface RIBType = syscall.NET_RT_IFLIST
+)
+
+// FetchRIB fetches a routing information base from the operating
+// system.
+//
+// The provided af must be an address family.
+//
+// The provided arg must be a RIBType-specific argument.
+// When RIBType is related to routes, arg might be a set of route
+// flags. When RIBType is related to network interfaces, arg might be
+// an interface index or a set of interface flags. In most cases, zero
+// means a wildcard.
+func FetchRIB(af int, typ RIBType, arg int) ([]byte, error) {
+ mib := [6]int32{sysCTL_NET, sysAF_ROUTE, 0, int32(af), int32(typ), int32(arg)}
+ n := uintptr(0)
+ if err := sysctl(mib[:], nil, &n, nil, 0); err != nil {
+ return nil, os.NewSyscallError("sysctl", err)
+ }
+ if n == 0 {
+ return nil, nil
+ }
+ b := make([]byte, n)
+ if err := sysctl(mib[:], &b[0], &n, nil, 0); err != nil {
+ return nil, os.NewSyscallError("sysctl", err)
+ }
+ return b[:n], nil
+}
--- /dev/null
+// 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.
+
+// +build darwin dragonfly freebsd netbsd
+
+package route
+
+func (w *wireFormat) parseRouteMessage(typ RIBType, b []byte) (Message, error) {
+ if len(b) < w.bodyOff {
+ return nil, errMessageTooShort
+ }
+ l := int(nativeEndian.Uint16(b[:2]))
+ if len(b) < l {
+ return nil, errInvalidMessage
+ }
+ m := &RouteMessage{
+ Version: int(b[2]),
+ Type: int(b[3]),
+ Flags: int(nativeEndian.Uint32(b[8:12])),
+ Index: int(nativeEndian.Uint16(b[4:6])),
+ extOff: w.extOff,
+ raw: b[:l],
+ }
+ var err error
+ m.Addrs, err = parseAddrs(uint(nativeEndian.Uint32(b[12:16])), parseKernelInetAddr, b[w.bodyOff:])
+ if err != nil {
+ return nil, err
+ }
+ return m, nil
+}
--- /dev/null
+// 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 route
+
+func (*wireFormat) parseRouteMessage(_ RIBType, b []byte) (Message, error) {
+ if len(b) < 40 {
+ return nil, errMessageTooShort
+ }
+ l := int(nativeEndian.Uint16(b[:2]))
+ if len(b) < l {
+ return nil, errInvalidMessage
+ }
+ m := &RouteMessage{
+ Version: int(b[2]),
+ Type: int(b[3]),
+ Flags: int(nativeEndian.Uint32(b[16:20])),
+ Index: int(nativeEndian.Uint16(b[6:8])),
+ raw: b[:l],
+ }
+ as, err := parseAddrs(uint(nativeEndian.Uint32(b[12:16])), parseKernelInetAddr, b[int(nativeEndian.Uint16(b[4:6])):])
+ if err != nil {
+ return nil, err
+ }
+ m.Addrs = as
+ return m, nil
+}
--- /dev/null
+// 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.
+
+// +build darwin dragonfly freebsd netbsd openbsd
+
+package route
+
+import (
+ "fmt"
+ "os/exec"
+ "runtime"
+ "time"
+)
+
+func (m *RouteMessage) String() string {
+ return fmt.Sprintf("%s", addrAttrs(nativeEndian.Uint32(m.raw[12:16])))
+}
+
+func (m *InterfaceMessage) String() string {
+ var attrs addrAttrs
+ if runtime.GOOS == "openbsd" {
+ attrs = addrAttrs(nativeEndian.Uint32(m.raw[12:16]))
+ } else {
+ attrs = addrAttrs(nativeEndian.Uint32(m.raw[4:8]))
+ }
+ return fmt.Sprintf("%s", attrs)
+}
+
+func (m *InterfaceAddrMessage) String() string {
+ var attrs addrAttrs
+ if runtime.GOOS == "openbsd" {
+ attrs = addrAttrs(nativeEndian.Uint32(m.raw[12:16]))
+ } else {
+ attrs = addrAttrs(nativeEndian.Uint32(m.raw[4:8]))
+ }
+ return fmt.Sprintf("%s", attrs)
+}
+
+func (m *InterfaceMulticastAddrMessage) String() string {
+ return fmt.Sprintf("%s", addrAttrs(nativeEndian.Uint32(m.raw[4:8])))
+}
+
+func (m *InterfaceAnnounceMessage) String() string {
+ what := "<nil>"
+ switch m.What {
+ case 0:
+ what = "arrival"
+ case 1:
+ what = "departure"
+ }
+ return fmt.Sprintf("(%d %s %s)", m.Index, m.Name, what)
+}
+
+func (m *InterfaceMetrics) String() string {
+ return fmt.Sprintf("(type=%d mtu=%d)", m.Type, m.MTU)
+}
+
+func (m *RouteMetrics) String() string {
+ return fmt.Sprintf("(pmtu=%d)", m.PathMTU)
+}
+
+type addrAttrs uint
+
+var addrAttrNames = [...]string{
+ "dst",
+ "gateway",
+ "netmask",
+ "genmask",
+ "ifp",
+ "ifa",
+ "author",
+ "brd",
+ "df:mpls1-n:tag-o:src", // mpls1 for dragonfly, tag for netbsd, src for openbsd
+ "df:mpls2-o:srcmask", // mpls2 for dragonfly, srcmask for openbsd
+ "df:mpls3-o:label", // mpls3 for dragonfly, label for openbsd
+}
+
+func (attrs addrAttrs) String() string {
+ var s string
+ for i, name := range addrAttrNames {
+ if attrs&(1<<uint(i)) != 0 {
+ if s != "" {
+ s += "|"
+ }
+ s += name
+ }
+ }
+ if s == "" {
+ return "<nil>"
+ }
+ return s
+}
+
+type msgs []Message
+
+func (ms msgs) validate() ([]string, error) {
+ var ss []string
+ for _, m := range ms {
+ switch m := m.(type) {
+ case *RouteMessage:
+ if err := addrs(m.Addrs).match(addrAttrs(nativeEndian.Uint32(m.raw[12:16]))); err != nil {
+ return nil, err
+ }
+ sys := m.Sys()
+ if sys == nil {
+ return nil, fmt.Errorf("no sys for %s", m.String())
+ }
+ ss = append(ss, m.String()+" "+syss(sys).String()+" "+addrs(m.Addrs).String())
+ case *InterfaceMessage:
+ var attrs addrAttrs
+ if runtime.GOOS == "openbsd" {
+ attrs = addrAttrs(nativeEndian.Uint32(m.raw[12:16]))
+ } else {
+ attrs = addrAttrs(nativeEndian.Uint32(m.raw[4:8]))
+ }
+ if err := addrs(m.Addrs).match(attrs); err != nil {
+ return nil, err
+ }
+ sys := m.Sys()
+ if sys == nil {
+ return nil, fmt.Errorf("no sys for %s", m.String())
+ }
+ ss = append(ss, m.String()+" "+syss(sys).String()+" "+addrs(m.Addrs).String())
+ case *InterfaceAddrMessage:
+ var attrs addrAttrs
+ if runtime.GOOS == "openbsd" {
+ attrs = addrAttrs(nativeEndian.Uint32(m.raw[12:16]))
+ } else {
+ attrs = addrAttrs(nativeEndian.Uint32(m.raw[4:8]))
+ }
+ if err := addrs(m.Addrs).match(attrs); err != nil {
+ return nil, err
+ }
+ ss = append(ss, m.String()+" "+addrs(m.Addrs).String())
+ case *InterfaceMulticastAddrMessage:
+ if err := addrs(m.Addrs).match(addrAttrs(nativeEndian.Uint32(m.raw[4:8]))); err != nil {
+ return nil, err
+ }
+ ss = append(ss, m.String()+" "+addrs(m.Addrs).String())
+ case *InterfaceAnnounceMessage:
+ ss = append(ss, m.String())
+ default:
+ ss = append(ss, fmt.Sprintf("%+v", m))
+ }
+ }
+ return ss, nil
+}
+
+type syss []Sys
+
+func (sys syss) String() string {
+ var s string
+ for _, sy := range sys {
+ switch sy := sy.(type) {
+ case *InterfaceMetrics:
+ if len(s) > 0 {
+ s += " "
+ }
+ s += sy.String()
+ case *RouteMetrics:
+ if len(s) > 0 {
+ s += " "
+ }
+ s += sy.String()
+ }
+ }
+ return s
+}
+
+type addrFamily int
+
+func (af addrFamily) String() string {
+ switch af {
+ case sysAF_UNSPEC:
+ return "unspec"
+ case sysAF_LINK:
+ return "link"
+ case sysAF_INET:
+ return "inet4"
+ case sysAF_INET6:
+ return "inet6"
+ default:
+ return fmt.Sprintf("%d", af)
+ }
+}
+
+const hexDigit = "0123456789abcdef"
+
+type llAddr []byte
+
+func (a llAddr) String() string {
+ if len(a) == 0 {
+ return ""
+ }
+ buf := make([]byte, 0, len(a)*3-1)
+ for i, b := range a {
+ if i > 0 {
+ buf = append(buf, ':')
+ }
+ buf = append(buf, hexDigit[b>>4])
+ buf = append(buf, hexDigit[b&0xF])
+ }
+ return string(buf)
+}
+
+type ipAddr []byte
+
+func (a ipAddr) String() string {
+ if len(a) == 0 {
+ return "<nil>"
+ }
+ if len(a) == 4 {
+ return fmt.Sprintf("%d.%d.%d.%d", a[0], a[1], a[2], a[3])
+ }
+ if len(a) == 16 {
+ return fmt.Sprintf("%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15])
+ }
+ s := make([]byte, len(a)*2)
+ for i, tn := range a {
+ s[i*2], s[i*2+1] = hexDigit[tn>>4], hexDigit[tn&0xf]
+ }
+ return string(s)
+}
+
+func (a *LinkAddr) String() string {
+ name := a.Name
+ if name == "" {
+ name = "<nil>"
+ }
+ lla := llAddr(a.Addr).String()
+ if lla == "" {
+ lla = "<nil>"
+ }
+ return fmt.Sprintf("(%v %d %s %s)", addrFamily(a.Family()), a.Index, name, lla)
+}
+
+func (a Inet4Addr) String() string {
+ return fmt.Sprintf("(%v %v)", addrFamily(a.Family()), ipAddr(a.IP[:]))
+}
+
+func (a *Inet6Addr) String() string {
+ return fmt.Sprintf("(%v %v %d)", addrFamily(a.Family()), ipAddr(a.IP[:]), a.ZoneID)
+}
+
+func (a *DefaultAddr) String() string {
+ return fmt.Sprintf("(%v %s)", addrFamily(a.Family()), ipAddr(a.Raw[2:]).String())
+}
+
+type addrs []Addr
+
+func (as addrs) String() string {
+ var s string
+ for _, a := range as {
+ if a == nil {
+ continue
+ }
+ if len(s) > 0 {
+ s += " "
+ }
+ switch a := a.(type) {
+ case *LinkAddr:
+ s += a.String()
+ case *Inet4Addr:
+ s += a.String()
+ case *Inet6Addr:
+ s += a.String()
+ case *DefaultAddr:
+ s += a.String()
+ }
+ }
+ if s == "" {
+ return "<nil>"
+ }
+ return s
+}
+
+func (as addrs) match(attrs addrAttrs) error {
+ var ts addrAttrs
+ af := sysAF_UNSPEC
+ for i := range as {
+ if as[i] != nil {
+ ts |= 1 << uint(i)
+ }
+ switch as[i].(type) {
+ case *Inet4Addr:
+ if af == sysAF_UNSPEC {
+ af = sysAF_INET
+ }
+ if af != sysAF_INET {
+ return fmt.Errorf("got %v; want %v", addrs(as), addrFamily(af))
+ }
+ case *Inet6Addr:
+ if af == sysAF_UNSPEC {
+ af = sysAF_INET6
+ }
+ if af != sysAF_INET6 {
+ return fmt.Errorf("got %v; want %v", addrs(as), addrFamily(af))
+ }
+ }
+ }
+ if ts != attrs && ts > attrs {
+ return fmt.Errorf("%v not included in %v", ts, attrs)
+ }
+ return nil
+}
+
+func fetchAndParseRIB(af int, typ RIBType) ([]Message, error) {
+ var err error
+ var b []byte
+ for i := 0; i < 3; i++ {
+ if b, err = FetchRIB(af, typ, 0); err != nil {
+ time.Sleep(10 * time.Millisecond)
+ continue
+ }
+ break
+ }
+ if err != nil {
+ return nil, fmt.Errorf("%v %d %v", addrFamily(af), typ, err)
+ }
+ ms, err := ParseRIB(typ, b)
+ if err != nil {
+ return nil, fmt.Errorf("%v %d %v", addrFamily(af), typ, err)
+ }
+ return ms, nil
+}
+
+type propVirtual struct {
+ name string
+ addr, mask string
+ setupCmds []*exec.Cmd
+ teardownCmds []*exec.Cmd
+}
+
+func (ti *propVirtual) setup() error {
+ for _, cmd := range ti.setupCmds {
+ if err := cmd.Run(); err != nil {
+ ti.teardown()
+ return err
+ }
+ }
+ return nil
+}
+
+func (ti *propVirtual) teardown() error {
+ for _, cmd := range ti.teardownCmds {
+ if err := cmd.Run(); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (ti *propVirtual) configure(suffix int) error {
+ if runtime.GOOS == "openbsd" {
+ ti.name = fmt.Sprintf("vether%d", suffix)
+ } else {
+ ti.name = fmt.Sprintf("vlan%d", suffix)
+ }
+ xname, err := exec.LookPath("ifconfig")
+ if err != nil {
+ return err
+ }
+ ti.setupCmds = append(ti.setupCmds, &exec.Cmd{
+ Path: xname,
+ Args: []string{"ifconfig", ti.name, "create"},
+ })
+ if runtime.GOOS == "netbsd" {
+ // NetBSD requires an underlying dot1Q-capable network
+ // interface.
+ ti.setupCmds = append(ti.setupCmds, &exec.Cmd{
+ Path: xname,
+ Args: []string{"ifconfig", ti.name, "vlan", fmt.Sprintf("%d", suffix&0xfff), "vlanif", "wm0"},
+ })
+ }
+ ti.setupCmds = append(ti.setupCmds, &exec.Cmd{
+ Path: xname,
+ Args: []string{"ifconfig", ti.name, "inet", ti.addr, "netmask", ti.mask},
+ })
+ ti.teardownCmds = append(ti.teardownCmds, &exec.Cmd{
+ Path: xname,
+ Args: []string{"ifconfig", ti.name, "destroy"},
+ })
+ return nil
+}
--- /dev/null
+// 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.
+
+// +build darwin dragonfly freebsd netbsd openbsd
+
+package route
+
+import "unsafe"
+
+var (
+ nativeEndian binaryByteOrder
+ kernelAlign int
+ parseFns map[int]parseFn
+)
+
+func init() {
+ i := uint32(1)
+ b := (*[4]byte)(unsafe.Pointer(&i))
+ if b[0] == 1 {
+ nativeEndian = littleEndian
+ } else {
+ nativeEndian = bigEndian
+ }
+ kernelAlign, parseFns = probeRoutingStack()
+}
+
+func roundup(l int) int {
+ if l == 0 {
+ return kernelAlign
+ }
+ return (l + kernelAlign - 1) & ^(kernelAlign - 1)
+}
+
+type parseFn func(RIBType, []byte) (Message, error)
+
+type wireFormat struct {
+ extOff int // offset of header extension
+ bodyOff int // offset of message body
+}
--- /dev/null
+// 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 route
+
+func (typ RIBType) parseable() bool {
+ switch typ {
+ case sysNET_RT_STAT, sysNET_RT_TRASH:
+ return false
+ default:
+ return true
+ }
+}
+
+// A RouteMetrics represents route metrics.
+type RouteMetrics struct {
+ PathMTU int // path maximum transmission unit
+}
+
+// SysType implements the SysType method of Sys interface.
+func (rmx *RouteMetrics) SysType() SysType { return SysMetrics }
+
+// Sys implements the Sys method of Message interface.
+func (m *RouteMessage) Sys() []Sys {
+ return []Sys{
+ &RouteMetrics{
+ PathMTU: int(nativeEndian.Uint32(m.raw[m.extOff+4 : m.extOff+8])),
+ },
+ }
+}
+
+// A InterfaceMetrics represents interface metrics.
+type InterfaceMetrics struct {
+ Type int // interface type
+ MTU int // maximum transmission unit
+}
+
+// SysType implements the SysType method of Sys interface.
+func (imx *InterfaceMetrics) SysType() SysType { return SysMetrics }
+
+// Sys implements the Sys method of Message interface.
+func (m *InterfaceMessage) Sys() []Sys {
+ return []Sys{
+ &InterfaceMetrics{
+ Type: int(m.raw[m.extOff]),
+ MTU: int(nativeEndian.Uint32(m.raw[m.extOff+8 : m.extOff+12])),
+ },
+ }
+}
+
+func probeRoutingStack() (int, map[int]parseFn) {
+ rtm := &wireFormat{extOff: 36, bodyOff: sizeofRtMsghdrDarwin15}
+ rtm2 := &wireFormat{extOff: 36, bodyOff: sizeofRtMsghdr2Darwin15}
+ ifm := &wireFormat{extOff: 16, bodyOff: sizeofIfMsghdrDarwin15}
+ ifm2 := &wireFormat{extOff: 32, bodyOff: sizeofIfMsghdr2Darwin15}
+ ifam := &wireFormat{extOff: sizeofIfaMsghdrDarwin15, bodyOff: sizeofIfaMsghdrDarwin15}
+ ifmam := &wireFormat{extOff: sizeofIfmaMsghdrDarwin15, bodyOff: sizeofIfmaMsghdrDarwin15}
+ ifmam2 := &wireFormat{extOff: sizeofIfmaMsghdr2Darwin15, bodyOff: sizeofIfmaMsghdr2Darwin15}
+ // Darwin kernels require 32-bit aligned access to routing facilities.
+ return 4, map[int]parseFn{
+ sysRTM_ADD: rtm.parseRouteMessage,
+ sysRTM_DELETE: rtm.parseRouteMessage,
+ sysRTM_CHANGE: rtm.parseRouteMessage,
+ sysRTM_GET: rtm.parseRouteMessage,
+ sysRTM_LOSING: rtm.parseRouteMessage,
+ sysRTM_REDIRECT: rtm.parseRouteMessage,
+ sysRTM_MISS: rtm.parseRouteMessage,
+ sysRTM_LOCK: rtm.parseRouteMessage,
+ sysRTM_RESOLVE: rtm.parseRouteMessage,
+ sysRTM_NEWADDR: ifam.parseInterfaceAddrMessage,
+ sysRTM_DELADDR: ifam.parseInterfaceAddrMessage,
+ sysRTM_IFINFO: ifm.parseInterfaceMessage,
+ sysRTM_NEWMADDR: ifmam.parseInterfaceMulticastAddrMessage,
+ sysRTM_DELMADDR: ifmam.parseInterfaceMulticastAddrMessage,
+ sysRTM_IFINFO2: ifm2.parseInterfaceMessage,
+ sysRTM_NEWMADDR2: ifmam2.parseInterfaceMulticastAddrMessage,
+ sysRTM_GET2: rtm2.parseRouteMessage,
+ }
+}
--- /dev/null
+// 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 route
+
+import "unsafe"
+
+func (typ RIBType) parseable() bool { return true }
+
+// A RouteMetrics represents route metrics.
+type RouteMetrics struct {
+ PathMTU int // path maximum transmission unit
+}
+
+// SysType implements the SysType method of Sys interface.
+func (rmx *RouteMetrics) SysType() SysType { return SysMetrics }
+
+// Sys implements the Sys method of Message interface.
+func (m *RouteMessage) Sys() []Sys {
+ return []Sys{
+ &RouteMetrics{
+ PathMTU: int(nativeEndian.Uint64(m.raw[m.extOff+8 : m.extOff+16])),
+ },
+ }
+}
+
+// A InterfaceMetrics represents interface metrics.
+type InterfaceMetrics struct {
+ Type int // interface type
+ MTU int // maximum transmission unit
+}
+
+// SysType implements the SysType method of Sys interface.
+func (imx *InterfaceMetrics) SysType() SysType { return SysMetrics }
+
+// Sys implements the Sys method of Message interface.
+func (m *InterfaceMessage) Sys() []Sys {
+ return []Sys{
+ &InterfaceMetrics{
+ Type: int(m.raw[m.extOff]),
+ MTU: int(nativeEndian.Uint32(m.raw[m.extOff+8 : m.extOff+12])),
+ },
+ }
+}
+
+func probeRoutingStack() (int, map[int]parseFn) {
+ var p uintptr
+ rtm := &wireFormat{extOff: 40, bodyOff: sizeofRtMsghdrDragonFlyBSD4}
+ ifm := &wireFormat{extOff: 16, bodyOff: sizeofIfMsghdrDragonFlyBSD4}
+ ifam := &wireFormat{extOff: sizeofIfaMsghdrDragonFlyBSD4, bodyOff: sizeofIfaMsghdrDragonFlyBSD4}
+ ifmam := &wireFormat{extOff: sizeofIfmaMsghdrDragonFlyBSD4, bodyOff: sizeofIfmaMsghdrDragonFlyBSD4}
+ ifanm := &wireFormat{extOff: sizeofIfAnnouncemsghdrDragonFlyBSD4, bodyOff: sizeofIfAnnouncemsghdrDragonFlyBSD4}
+ return int(unsafe.Sizeof(p)), map[int]parseFn{
+ sysRTM_ADD: rtm.parseRouteMessage,
+ sysRTM_DELETE: rtm.parseRouteMessage,
+ sysRTM_CHANGE: rtm.parseRouteMessage,
+ sysRTM_GET: rtm.parseRouteMessage,
+ sysRTM_LOSING: rtm.parseRouteMessage,
+ sysRTM_REDIRECT: rtm.parseRouteMessage,
+ sysRTM_MISS: rtm.parseRouteMessage,
+ sysRTM_LOCK: rtm.parseRouteMessage,
+ sysRTM_RESOLVE: rtm.parseRouteMessage,
+ sysRTM_NEWADDR: ifam.parseInterfaceAddrMessage,
+ sysRTM_DELADDR: ifam.parseInterfaceAddrMessage,
+ sysRTM_IFINFO: ifm.parseInterfaceMessage,
+ sysRTM_NEWMADDR: ifmam.parseInterfaceMulticastAddrMessage,
+ sysRTM_DELMADDR: ifmam.parseInterfaceMulticastAddrMessage,
+ sysRTM_IFANNOUNCE: ifanm.parseInterfaceAnnounceMessage,
+ }
+}
--- /dev/null
+// 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 route
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+func (typ RIBType) parseable() bool { return true }
+
+// A RouteMetrics represents route metrics.
+type RouteMetrics struct {
+ PathMTU int // path maximum transmission unit
+}
+
+// SysType implements the SysType method of Sys interface.
+func (rmx *RouteMetrics) SysType() SysType { return SysMetrics }
+
+// Sys implements the Sys method of Message interface.
+func (m *RouteMessage) Sys() []Sys {
+ if kernelAlign == 8 {
+ return []Sys{
+ &RouteMetrics{
+ PathMTU: int(nativeEndian.Uint64(m.raw[m.extOff+8 : m.extOff+16])),
+ },
+ }
+ }
+ return []Sys{
+ &RouteMetrics{
+ PathMTU: int(nativeEndian.Uint32(m.raw[m.extOff+4 : m.extOff+8])),
+ },
+ }
+}
+
+// A InterfaceMetrics represents interface metrics.
+type InterfaceMetrics struct {
+ Type int // interface type
+ MTU int // maximum transmission unit
+}
+
+// SysType implements the SysType method of Sys interface.
+func (imx *InterfaceMetrics) SysType() SysType { return SysMetrics }
+
+// Sys implements the Sys method of Message interface.
+func (m *InterfaceMessage) Sys() []Sys {
+ return []Sys{
+ &InterfaceMetrics{
+ Type: int(m.raw[m.extOff]),
+ MTU: int(nativeEndian.Uint32(m.raw[m.extOff+8 : m.extOff+12])),
+ },
+ }
+}
+
+func probeRoutingStack() (int, map[int]parseFn) {
+ var p uintptr
+ wordSize := int(unsafe.Sizeof(p))
+ align := int(unsafe.Sizeof(p))
+ // In the case of kern.supported_archs="amd64 i386", we need
+ // to know the underlying kernel's architecture because the
+ // alignment for routing facilities are set at the build time
+ // of the kernel.
+ conf, _ := syscall.Sysctl("kern.conftxt")
+ for i, j := 0, 0; j < len(conf); j++ {
+ if conf[j] != '\n' {
+ continue
+ }
+ s := conf[i:j]
+ i = j + 1
+ if len(s) > len("machine") && s[:len("machine")] == "machine" {
+ s = s[len("machine"):]
+ for k := 0; k < len(s); k++ {
+ if s[k] == ' ' || s[k] == '\t' {
+ s = s[1:]
+ }
+ break
+ }
+ if s == "amd64" {
+ align = 8
+ }
+ break
+ }
+ }
+ var rtm, ifm, ifam, ifmam, ifanm *wireFormat
+ if align != wordSize { // 386 emulation on amd64
+ rtm = &wireFormat{extOff: sizeofRtMsghdrFreeBSD10Emu - sizeofRtMetricsFreeBSD10Emu, bodyOff: sizeofRtMsghdrFreeBSD10Emu}
+ ifm = &wireFormat{extOff: 16}
+ ifam = &wireFormat{extOff: sizeofIfaMsghdrFreeBSD10Emu, bodyOff: sizeofIfaMsghdrFreeBSD10Emu}
+ ifmam = &wireFormat{extOff: sizeofIfmaMsghdrFreeBSD10Emu, bodyOff: sizeofIfmaMsghdrFreeBSD10Emu}
+ ifanm = &wireFormat{extOff: sizeofIfAnnouncemsghdrFreeBSD10Emu, bodyOff: sizeofIfAnnouncemsghdrFreeBSD10Emu}
+ } else {
+ rtm = &wireFormat{extOff: sizeofRtMsghdrFreeBSD10 - sizeofRtMetricsFreeBSD10, bodyOff: sizeofRtMsghdrFreeBSD10}
+ ifm = &wireFormat{extOff: 16}
+ ifam = &wireFormat{extOff: sizeofIfaMsghdrFreeBSD10, bodyOff: sizeofIfaMsghdrFreeBSD10}
+ ifmam = &wireFormat{extOff: sizeofIfmaMsghdrFreeBSD10, bodyOff: sizeofIfmaMsghdrFreeBSD10}
+ ifanm = &wireFormat{extOff: sizeofIfAnnouncemsghdrFreeBSD10, bodyOff: sizeofIfAnnouncemsghdrFreeBSD10}
+ }
+ rel, _ := syscall.SysctlUint32("kern.osreldate")
+ switch {
+ case rel < 800000:
+ if align != wordSize { // 386 emulation on amd64
+ ifm.bodyOff = sizeofIfMsghdrFreeBSD7Emu
+ } else {
+ ifm.bodyOff = sizeofIfMsghdrFreeBSD7
+ }
+ case 800000 <= rel && rel < 900000:
+ if align != wordSize { // 386 emulation on amd64
+ ifm.bodyOff = sizeofIfMsghdrFreeBSD8Emu
+ } else {
+ ifm.bodyOff = sizeofIfMsghdrFreeBSD8
+ }
+ case 900000 <= rel && rel < 1000000:
+ if align != wordSize { // 386 emulation on amd64
+ ifm.bodyOff = sizeofIfMsghdrFreeBSD9Emu
+ } else {
+ ifm.bodyOff = sizeofIfMsghdrFreeBSD9
+ }
+ case 1000000 <= rel && rel < 1100000:
+ if align != wordSize { // 386 emulation on amd64
+ ifm.bodyOff = sizeofIfMsghdrFreeBSD10Emu
+ } else {
+ ifm.bodyOff = sizeofIfMsghdrFreeBSD10
+ }
+ default:
+ if align != wordSize { // 386 emulation on amd64
+ ifm.bodyOff = sizeofIfMsghdrFreeBSD11Emu
+ } else {
+ ifm.bodyOff = sizeofIfMsghdrFreeBSD11
+ }
+ }
+ return align, map[int]parseFn{
+ sysRTM_ADD: rtm.parseRouteMessage,
+ sysRTM_DELETE: rtm.parseRouteMessage,
+ sysRTM_CHANGE: rtm.parseRouteMessage,
+ sysRTM_GET: rtm.parseRouteMessage,
+ sysRTM_LOSING: rtm.parseRouteMessage,
+ sysRTM_REDIRECT: rtm.parseRouteMessage,
+ sysRTM_MISS: rtm.parseRouteMessage,
+ sysRTM_LOCK: rtm.parseRouteMessage,
+ sysRTM_RESOLVE: rtm.parseRouteMessage,
+ sysRTM_NEWADDR: ifam.parseInterfaceAddrMessage,
+ sysRTM_DELADDR: ifam.parseInterfaceAddrMessage,
+ sysRTM_IFINFO: ifm.parseInterfaceMessage,
+ sysRTM_NEWMADDR: ifmam.parseInterfaceMulticastAddrMessage,
+ sysRTM_DELMADDR: ifmam.parseInterfaceMulticastAddrMessage,
+ sysRTM_IFANNOUNCE: ifanm.parseInterfaceAnnounceMessage,
+ }
+}
--- /dev/null
+// 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 route
+
+func (typ RIBType) parseable() bool { return true }
+
+// A RouteMetrics represents route metrics.
+type RouteMetrics struct {
+ PathMTU int // path maximum transmission unit
+}
+
+// SysType implements the SysType method of Sys interface.
+func (rmx *RouteMetrics) SysType() SysType { return SysMetrics }
+
+// Sys implements the Sys method of Message interface.
+func (m *RouteMessage) Sys() []Sys {
+ return []Sys{
+ &RouteMetrics{
+ PathMTU: int(nativeEndian.Uint64(m.raw[m.extOff+8 : m.extOff+16])),
+ },
+ }
+}
+
+// A InterfaceMetrics represents interface metrics.
+type InterfaceMetrics struct {
+ Type int // interface type
+ MTU int // maximum transmission unit
+}
+
+// SysType implements the SysType method of Sys interface.
+func (imx *InterfaceMetrics) SysType() SysType { return SysMetrics }
+
+// Sys implements the Sys method of Message interface.
+func (m *InterfaceMessage) Sys() []Sys {
+ return []Sys{
+ &InterfaceMetrics{
+ Type: int(m.raw[m.extOff]),
+ MTU: int(nativeEndian.Uint32(m.raw[m.extOff+8 : m.extOff+12])),
+ },
+ }
+}
+
+func probeRoutingStack() (int, map[int]parseFn) {
+ rtm := &wireFormat{extOff: 40, bodyOff: sizeofRtMsghdrNetBSD7}
+ ifm := &wireFormat{extOff: 16, bodyOff: sizeofIfMsghdrNetBSD7}
+ ifam := &wireFormat{extOff: sizeofIfaMsghdrNetBSD7, bodyOff: sizeofIfaMsghdrNetBSD7}
+ ifanm := &wireFormat{extOff: sizeofIfAnnouncemsghdrNetBSD7, bodyOff: sizeofIfAnnouncemsghdrNetBSD7}
+ // NetBSD 6 and above kernels require 64-bit aligned access to
+ // routing facilities.
+ return 8, map[int]parseFn{
+ sysRTM_ADD: rtm.parseRouteMessage,
+ sysRTM_DELETE: rtm.parseRouteMessage,
+ sysRTM_CHANGE: rtm.parseRouteMessage,
+ sysRTM_GET: rtm.parseRouteMessage,
+ sysRTM_LOSING: rtm.parseRouteMessage,
+ sysRTM_REDIRECT: rtm.parseRouteMessage,
+ sysRTM_MISS: rtm.parseRouteMessage,
+ sysRTM_LOCK: rtm.parseRouteMessage,
+ sysRTM_RESOLVE: rtm.parseRouteMessage,
+ sysRTM_NEWADDR: ifam.parseInterfaceAddrMessage,
+ sysRTM_DELADDR: ifam.parseInterfaceAddrMessage,
+ sysRTM_IFANNOUNCE: ifanm.parseInterfaceAnnounceMessage,
+ sysRTM_IFINFO: ifm.parseInterfaceMessage,
+ }
+}
--- /dev/null
+// 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 route
+
+import "unsafe"
+
+func (typ RIBType) parseable() bool {
+ switch typ {
+ case sysNET_RT_STATS, sysNET_RT_TABLE:
+ return false
+ default:
+ return true
+ }
+}
+
+// A RouteMetrics represents route metrics.
+type RouteMetrics struct {
+ PathMTU int // path maximum transmission unit
+}
+
+// SysType implements the SysType method of Sys interface.
+func (rmx *RouteMetrics) SysType() SysType { return SysMetrics }
+
+// Sys implements the Sys method of Message interface.
+func (m *RouteMessage) Sys() []Sys {
+ return []Sys{
+ &RouteMetrics{
+ PathMTU: int(nativeEndian.Uint32(m.raw[60:64])),
+ },
+ }
+}
+
+// A InterfaceMetrics represents interface metrics.
+type InterfaceMetrics struct {
+ Type int // interface type
+ MTU int // maximum transmission unit
+}
+
+// SysType implements the SysType method of Sys interface.
+func (imx *InterfaceMetrics) SysType() SysType { return SysMetrics }
+
+// Sys implements the Sys method of Message interface.
+func (m *InterfaceMessage) Sys() []Sys {
+ return []Sys{
+ &InterfaceMetrics{
+ Type: int(m.raw[24]),
+ MTU: int(nativeEndian.Uint32(m.raw[28:32])),
+ },
+ }
+}
+
+func probeRoutingStack() (int, map[int]parseFn) {
+ var p uintptr
+ nooff := &wireFormat{extOff: -1, bodyOff: -1}
+ return int(unsafe.Sizeof(p)), map[int]parseFn{
+ sysRTM_ADD: nooff.parseRouteMessage,
+ sysRTM_DELETE: nooff.parseRouteMessage,
+ sysRTM_CHANGE: nooff.parseRouteMessage,
+ sysRTM_GET: nooff.parseRouteMessage,
+ sysRTM_LOSING: nooff.parseRouteMessage,
+ sysRTM_REDIRECT: nooff.parseRouteMessage,
+ sysRTM_MISS: nooff.parseRouteMessage,
+ sysRTM_LOCK: nooff.parseRouteMessage,
+ sysRTM_RESOLVE: nooff.parseRouteMessage,
+ sysRTM_NEWADDR: nooff.parseInterfaceAddrMessage,
+ sysRTM_DELADDR: nooff.parseInterfaceAddrMessage,
+ sysRTM_IFINFO: nooff.parseInterfaceMessage,
+ sysRTM_IFANNOUNCE: nooff.parseInterfaceAnnounceMessage,
+ }
+}
--- /dev/null
+// 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.
+
+// +build darwin dragonfly freebsd netbsd openbsd
+
+package route
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+// TODO: replace with runtime.KeepAlive when available
+//go:noescape
+func keepAlive(p unsafe.Pointer)
+
+var zero uintptr
+
+func sysctl(mib []int32, old *byte, oldlen *uintptr, new *byte, newlen uintptr) error {
+ var p unsafe.Pointer
+ if len(mib) > 0 {
+ p = unsafe.Pointer(&mib[0])
+ } else {
+ p = unsafe.Pointer(&zero)
+ }
+ _, _, errno := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(p), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+ keepAlive(p)
+ if errno != 0 {
+ return error(errno)
+ }
+ return nil
+}
--- /dev/null
+// 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.
+
+#include "textflag.h"
+
+TEXT ·keepAlive(SB),NOSPLIT,$0
+ RET
--- /dev/null
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs defs_darwin.go
+
+package route
+
+const (
+ sysAF_UNSPEC = 0x0
+ sysAF_INET = 0x2
+ sysAF_ROUTE = 0x11
+ sysAF_LINK = 0x12
+ sysAF_INET6 = 0x1e
+
+ sysNET_RT_DUMP = 0x1
+ sysNET_RT_FLAGS = 0x2
+ sysNET_RT_IFLIST = 0x3
+ sysNET_RT_STAT = 0x4
+ sysNET_RT_TRASH = 0x5
+ sysNET_RT_IFLIST2 = 0x6
+ sysNET_RT_DUMP2 = 0x7
+ sysNET_RT_MAXID = 0xa
+)
+
+const (
+ sysCTL_MAXNAME = 0xc
+
+ sysCTL_UNSPEC = 0x0
+ sysCTL_KERN = 0x1
+ sysCTL_VM = 0x2
+ sysCTL_VFS = 0x3
+ sysCTL_NET = 0x4
+ sysCTL_DEBUG = 0x5
+ sysCTL_HW = 0x6
+ sysCTL_MACHDEP = 0x7
+ sysCTL_USER = 0x8
+ sysCTL_MAXID = 0x9
+)
+
+const (
+ sysRTM_VERSION = 0x5
+
+ sysRTM_ADD = 0x1
+ sysRTM_DELETE = 0x2
+ sysRTM_CHANGE = 0x3
+ sysRTM_GET = 0x4
+ sysRTM_LOSING = 0x5
+ sysRTM_REDIRECT = 0x6
+ sysRTM_MISS = 0x7
+ sysRTM_LOCK = 0x8
+ sysRTM_OLDADD = 0x9
+ sysRTM_OLDDEL = 0xa
+ sysRTM_RESOLVE = 0xb
+ sysRTM_NEWADDR = 0xc
+ sysRTM_DELADDR = 0xd
+ sysRTM_IFINFO = 0xe
+ sysRTM_NEWMADDR = 0xf
+ sysRTM_DELMADDR = 0x10
+ sysRTM_IFINFO2 = 0x12
+ sysRTM_NEWMADDR2 = 0x13
+ sysRTM_GET2 = 0x14
+
+ sysRTA_DST = 0x1
+ sysRTA_GATEWAY = 0x2
+ sysRTA_NETMASK = 0x4
+ sysRTA_GENMASK = 0x8
+ sysRTA_IFP = 0x10
+ sysRTA_IFA = 0x20
+ sysRTA_AUTHOR = 0x40
+ sysRTA_BRD = 0x80
+
+ sysRTAX_DST = 0x0
+ sysRTAX_GATEWAY = 0x1
+ sysRTAX_NETMASK = 0x2
+ sysRTAX_GENMASK = 0x3
+ sysRTAX_IFP = 0x4
+ sysRTAX_IFA = 0x5
+ sysRTAX_AUTHOR = 0x6
+ sysRTAX_BRD = 0x7
+ sysRTAX_MAX = 0x8
+)
+
+const (
+ sizeofIfMsghdrDarwin15 = 0x70
+ sizeofIfaMsghdrDarwin15 = 0x14
+ sizeofIfmaMsghdrDarwin15 = 0x10
+ sizeofIfMsghdr2Darwin15 = 0xa0
+ sizeofIfmaMsghdr2Darwin15 = 0x14
+ sizeofIfDataDarwin15 = 0x60
+ sizeofIfData64Darwin15 = 0x80
+
+ sizeofRtMsghdrDarwin15 = 0x5c
+ sizeofRtMsghdr2Darwin15 = 0x5c
+ sizeofRtMetricsDarwin15 = 0x38
+)
--- /dev/null
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs defs_dragonfly.go
+
+package route
+
+const (
+ sysAF_UNSPEC = 0x0
+ sysAF_INET = 0x2
+ sysAF_ROUTE = 0x11
+ sysAF_LINK = 0x12
+ sysAF_INET6 = 0x1c
+
+ sysNET_RT_DUMP = 0x1
+ sysNET_RT_FLAGS = 0x2
+ sysNET_RT_IFLIST = 0x3
+ sysNET_RT_MAXID = 0x4
+)
+
+const (
+ sysCTL_MAXNAME = 0xc
+
+ sysCTL_UNSPEC = 0x0
+ sysCTL_KERN = 0x1
+ sysCTL_VM = 0x2
+ sysCTL_VFS = 0x3
+ sysCTL_NET = 0x4
+ sysCTL_DEBUG = 0x5
+ sysCTL_HW = 0x6
+ sysCTL_MACHDEP = 0x7
+ sysCTL_USER = 0x8
+ sysCTL_P1003_1B = 0x9
+ sysCTL_LWKT = 0xa
+ sysCTL_MAXID = 0xb
+)
+
+const (
+ sysRTM_VERSION = 0x6
+
+ sysRTM_ADD = 0x1
+ sysRTM_DELETE = 0x2
+ sysRTM_CHANGE = 0x3
+ sysRTM_GET = 0x4
+ sysRTM_LOSING = 0x5
+ sysRTM_REDIRECT = 0x6
+ sysRTM_MISS = 0x7
+ sysRTM_LOCK = 0x8
+ sysRTM_OLDADD = 0x9
+ sysRTM_OLDDEL = 0xa
+ sysRTM_RESOLVE = 0xb
+ sysRTM_NEWADDR = 0xc
+ sysRTM_DELADDR = 0xd
+ sysRTM_IFINFO = 0xe
+ sysRTM_NEWMADDR = 0xf
+ sysRTM_DELMADDR = 0x10
+ sysRTM_IFANNOUNCE = 0x11
+ sysRTM_IEEE80211 = 0x12
+
+ sysRTA_DST = 0x1
+ sysRTA_GATEWAY = 0x2
+ sysRTA_NETMASK = 0x4
+ sysRTA_GENMASK = 0x8
+ sysRTA_IFP = 0x10
+ sysRTA_IFA = 0x20
+ sysRTA_AUTHOR = 0x40
+ sysRTA_BRD = 0x80
+ sysRTA_MPLS1 = 0x100
+ sysRTA_MPLS2 = 0x200
+ sysRTA_MPLS3 = 0x400
+
+ sysRTAX_DST = 0x0
+ sysRTAX_GATEWAY = 0x1
+ sysRTAX_NETMASK = 0x2
+ sysRTAX_GENMASK = 0x3
+ sysRTAX_IFP = 0x4
+ sysRTAX_IFA = 0x5
+ sysRTAX_AUTHOR = 0x6
+ sysRTAX_BRD = 0x7
+ sysRTAX_MPLS1 = 0x8
+ sysRTAX_MPLS2 = 0x9
+ sysRTAX_MPLS3 = 0xa
+ sysRTAX_MAX = 0xb
+)
+
+const (
+ sizeofIfMsghdrDragonFlyBSD4 = 0xb0
+ sizeofIfaMsghdrDragonFlyBSD4 = 0x14
+ sizeofIfmaMsghdrDragonFlyBSD4 = 0x10
+ sizeofIfAnnouncemsghdrDragonFlyBSD4 = 0x18
+
+ sizeofRtMsghdrDragonFlyBSD4 = 0x98
+ sizeofRtMetricsDragonFlyBSD4 = 0x70
+)
--- /dev/null
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs defs_freebsd.go
+
+package route
+
+const (
+ sysAF_UNSPEC = 0x0
+ sysAF_INET = 0x2
+ sysAF_ROUTE = 0x11
+ sysAF_LINK = 0x12
+ sysAF_INET6 = 0x1c
+
+ sysNET_RT_DUMP = 0x1
+ sysNET_RT_FLAGS = 0x2
+ sysNET_RT_IFLIST = 0x3
+ sysNET_RT_IFMALIST = 0x4
+ sysNET_RT_IFLISTL = 0x5
+)
+
+const (
+ sysCTL_MAXNAME = 0x18
+
+ sysCTL_UNSPEC = 0x0
+ sysCTL_KERN = 0x1
+ sysCTL_VM = 0x2
+ sysCTL_VFS = 0x3
+ sysCTL_NET = 0x4
+ sysCTL_DEBUG = 0x5
+ sysCTL_HW = 0x6
+ sysCTL_MACHDEP = 0x7
+ sysCTL_USER = 0x8
+ sysCTL_P1003_1B = 0x9
+)
+
+const (
+ sysRTM_VERSION = 0x5
+
+ sysRTM_ADD = 0x1
+ sysRTM_DELETE = 0x2
+ sysRTM_CHANGE = 0x3
+ sysRTM_GET = 0x4
+ sysRTM_LOSING = 0x5
+ sysRTM_REDIRECT = 0x6
+ sysRTM_MISS = 0x7
+ sysRTM_LOCK = 0x8
+ sysRTM_RESOLVE = 0xb
+ sysRTM_NEWADDR = 0xc
+ sysRTM_DELADDR = 0xd
+ sysRTM_IFINFO = 0xe
+ sysRTM_NEWMADDR = 0xf
+ sysRTM_DELMADDR = 0x10
+ sysRTM_IFANNOUNCE = 0x11
+ sysRTM_IEEE80211 = 0x12
+
+ sysRTA_DST = 0x1
+ sysRTA_GATEWAY = 0x2
+ sysRTA_NETMASK = 0x4
+ sysRTA_GENMASK = 0x8
+ sysRTA_IFP = 0x10
+ sysRTA_IFA = 0x20
+ sysRTA_AUTHOR = 0x40
+ sysRTA_BRD = 0x80
+
+ sysRTAX_DST = 0x0
+ sysRTAX_GATEWAY = 0x1
+ sysRTAX_NETMASK = 0x2
+ sysRTAX_GENMASK = 0x3
+ sysRTAX_IFP = 0x4
+ sysRTAX_IFA = 0x5
+ sysRTAX_AUTHOR = 0x6
+ sysRTAX_BRD = 0x7
+ sysRTAX_MAX = 0x8
+)
+
+const (
+ sizeofIfMsghdrlFreeBSD10 = 0x68
+ sizeofIfaMsghdrFreeBSD10 = 0x14
+ sizeofIfaMsghdrlFreeBSD10 = 0x6c
+ sizeofIfmaMsghdrFreeBSD10 = 0x10
+ sizeofIfAnnouncemsghdrFreeBSD10 = 0x18
+
+ sizeofRtMsghdrFreeBSD10 = 0x5c
+ sizeofRtMetricsFreeBSD10 = 0x38
+
+ sizeofIfMsghdrFreeBSD7 = 0x60
+ sizeofIfMsghdrFreeBSD8 = 0x60
+ sizeofIfMsghdrFreeBSD9 = 0x60
+ sizeofIfMsghdrFreeBSD10 = 0x64
+ sizeofIfMsghdrFreeBSD11 = 0xa8
+
+ sizeofIfDataFreeBSD7 = 0x50
+ sizeofIfDataFreeBSD8 = 0x50
+ sizeofIfDataFreeBSD9 = 0x50
+ sizeofIfDataFreeBSD10 = 0x54
+ sizeofIfDataFreeBSD11 = 0x98
+
+ // MODIFIED BY HAND FOR 386 EMULATION ON AMD64
+ // 386 EMULATION USES THE UNDERLYING RAW DATA LAYOUT
+
+ sizeofIfMsghdrlFreeBSD10Emu = 0xb0
+ sizeofIfaMsghdrFreeBSD10Emu = 0x14
+ sizeofIfaMsghdrlFreeBSD10Emu = 0xb0
+ sizeofIfmaMsghdrFreeBSD10Emu = 0x10
+ sizeofIfAnnouncemsghdrFreeBSD10Emu = 0x18
+
+ sizeofRtMsghdrFreeBSD10Emu = 0x98
+ sizeofRtMetricsFreeBSD10Emu = 0x70
+
+ sizeofIfMsghdrFreeBSD7Emu = 0xa8
+ sizeofIfMsghdrFreeBSD8Emu = 0xa8
+ sizeofIfMsghdrFreeBSD9Emu = 0xa8
+ sizeofIfMsghdrFreeBSD10Emu = 0xa8
+ sizeofIfMsghdrFreeBSD11Emu = 0xa8
+
+ sizeofIfDataFreeBSD7Emu = 0x98
+ sizeofIfDataFreeBSD8Emu = 0x98
+ sizeofIfDataFreeBSD9Emu = 0x98
+ sizeofIfDataFreeBSD10Emu = 0x98
+ sizeofIfDataFreeBSD11Emu = 0x98
+)
--- /dev/null
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs defs_freebsd.go
+
+package route
+
+const (
+ sysAF_UNSPEC = 0x0
+ sysAF_INET = 0x2
+ sysAF_ROUTE = 0x11
+ sysAF_LINK = 0x12
+ sysAF_INET6 = 0x1c
+
+ sysNET_RT_DUMP = 0x1
+ sysNET_RT_FLAGS = 0x2
+ sysNET_RT_IFLIST = 0x3
+ sysNET_RT_IFMALIST = 0x4
+ sysNET_RT_IFLISTL = 0x5
+)
+
+const (
+ sysCTL_MAXNAME = 0x18
+
+ sysCTL_UNSPEC = 0x0
+ sysCTL_KERN = 0x1
+ sysCTL_VM = 0x2
+ sysCTL_VFS = 0x3
+ sysCTL_NET = 0x4
+ sysCTL_DEBUG = 0x5
+ sysCTL_HW = 0x6
+ sysCTL_MACHDEP = 0x7
+ sysCTL_USER = 0x8
+ sysCTL_P1003_1B = 0x9
+)
+
+const (
+ sysRTM_VERSION = 0x5
+
+ sysRTM_ADD = 0x1
+ sysRTM_DELETE = 0x2
+ sysRTM_CHANGE = 0x3
+ sysRTM_GET = 0x4
+ sysRTM_LOSING = 0x5
+ sysRTM_REDIRECT = 0x6
+ sysRTM_MISS = 0x7
+ sysRTM_LOCK = 0x8
+ sysRTM_RESOLVE = 0xb
+ sysRTM_NEWADDR = 0xc
+ sysRTM_DELADDR = 0xd
+ sysRTM_IFINFO = 0xe
+ sysRTM_NEWMADDR = 0xf
+ sysRTM_DELMADDR = 0x10
+ sysRTM_IFANNOUNCE = 0x11
+ sysRTM_IEEE80211 = 0x12
+
+ sysRTA_DST = 0x1
+ sysRTA_GATEWAY = 0x2
+ sysRTA_NETMASK = 0x4
+ sysRTA_GENMASK = 0x8
+ sysRTA_IFP = 0x10
+ sysRTA_IFA = 0x20
+ sysRTA_AUTHOR = 0x40
+ sysRTA_BRD = 0x80
+
+ sysRTAX_DST = 0x0
+ sysRTAX_GATEWAY = 0x1
+ sysRTAX_NETMASK = 0x2
+ sysRTAX_GENMASK = 0x3
+ sysRTAX_IFP = 0x4
+ sysRTAX_IFA = 0x5
+ sysRTAX_AUTHOR = 0x6
+ sysRTAX_BRD = 0x7
+ sysRTAX_MAX = 0x8
+)
+
+const (
+ sizeofIfMsghdrlFreeBSD10 = 0xb0
+ sizeofIfaMsghdrFreeBSD10 = 0x14
+ sizeofIfaMsghdrlFreeBSD10 = 0xb0
+ sizeofIfmaMsghdrFreeBSD10 = 0x10
+ sizeofIfAnnouncemsghdrFreeBSD10 = 0x18
+
+ sizeofRtMsghdrFreeBSD10 = 0x98
+ sizeofRtMetricsFreeBSD10 = 0x70
+
+ sizeofIfMsghdrFreeBSD7 = 0xa8
+ sizeofIfMsghdrFreeBSD8 = 0xa8
+ sizeofIfMsghdrFreeBSD9 = 0xa8
+ sizeofIfMsghdrFreeBSD10 = 0xa8
+ sizeofIfMsghdrFreeBSD11 = 0xa8
+
+ sizeofIfDataFreeBSD7 = 0x98
+ sizeofIfDataFreeBSD8 = 0x98
+ sizeofIfDataFreeBSD9 = 0x98
+ sizeofIfDataFreeBSD10 = 0x98
+ sizeofIfDataFreeBSD11 = 0x98
+
+ sizeofIfMsghdrlFreeBSD10Emu = 0xb0
+ sizeofIfaMsghdrFreeBSD10Emu = 0x14
+ sizeofIfaMsghdrlFreeBSD10Emu = 0xb0
+ sizeofIfmaMsghdrFreeBSD10Emu = 0x10
+ sizeofIfAnnouncemsghdrFreeBSD10Emu = 0x18
+
+ sizeofRtMsghdrFreeBSD10Emu = 0x98
+ sizeofRtMetricsFreeBSD10Emu = 0x70
+
+ sizeofIfMsghdrFreeBSD7Emu = 0xa8
+ sizeofIfMsghdrFreeBSD8Emu = 0xa8
+ sizeofIfMsghdrFreeBSD9Emu = 0xa8
+ sizeofIfMsghdrFreeBSD10Emu = 0xa8
+ sizeofIfMsghdrFreeBSD11Emu = 0xa8
+
+ sizeofIfDataFreeBSD7Emu = 0x98
+ sizeofIfDataFreeBSD8Emu = 0x98
+ sizeofIfDataFreeBSD9Emu = 0x98
+ sizeofIfDataFreeBSD10Emu = 0x98
+ sizeofIfDataFreeBSD11Emu = 0x98
+)
--- /dev/null
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs defs_freebsd.go
+
+package route
+
+const (
+ sysAF_UNSPEC = 0x0
+ sysAF_INET = 0x2
+ sysAF_ROUTE = 0x11
+ sysAF_LINK = 0x12
+ sysAF_INET6 = 0x1c
+
+ sysNET_RT_DUMP = 0x1
+ sysNET_RT_FLAGS = 0x2
+ sysNET_RT_IFLIST = 0x3
+ sysNET_RT_IFMALIST = 0x4
+ sysNET_RT_IFLISTL = 0x5
+)
+
+const (
+ sysCTL_MAXNAME = 0x18
+
+ sysCTL_UNSPEC = 0x0
+ sysCTL_KERN = 0x1
+ sysCTL_VM = 0x2
+ sysCTL_VFS = 0x3
+ sysCTL_NET = 0x4
+ sysCTL_DEBUG = 0x5
+ sysCTL_HW = 0x6
+ sysCTL_MACHDEP = 0x7
+ sysCTL_USER = 0x8
+ sysCTL_P1003_1B = 0x9
+)
+
+const (
+ sysRTM_VERSION = 0x5
+
+ sysRTM_ADD = 0x1
+ sysRTM_DELETE = 0x2
+ sysRTM_CHANGE = 0x3
+ sysRTM_GET = 0x4
+ sysRTM_LOSING = 0x5
+ sysRTM_REDIRECT = 0x6
+ sysRTM_MISS = 0x7
+ sysRTM_LOCK = 0x8
+ sysRTM_RESOLVE = 0xb
+ sysRTM_NEWADDR = 0xc
+ sysRTM_DELADDR = 0xd
+ sysRTM_IFINFO = 0xe
+ sysRTM_NEWMADDR = 0xf
+ sysRTM_DELMADDR = 0x10
+ sysRTM_IFANNOUNCE = 0x11
+ sysRTM_IEEE80211 = 0x12
+
+ sysRTA_DST = 0x1
+ sysRTA_GATEWAY = 0x2
+ sysRTA_NETMASK = 0x4
+ sysRTA_GENMASK = 0x8
+ sysRTA_IFP = 0x10
+ sysRTA_IFA = 0x20
+ sysRTA_AUTHOR = 0x40
+ sysRTA_BRD = 0x80
+
+ sysRTAX_DST = 0x0
+ sysRTAX_GATEWAY = 0x1
+ sysRTAX_NETMASK = 0x2
+ sysRTAX_GENMASK = 0x3
+ sysRTAX_IFP = 0x4
+ sysRTAX_IFA = 0x5
+ sysRTAX_AUTHOR = 0x6
+ sysRTAX_BRD = 0x7
+ sysRTAX_MAX = 0x8
+)
+
+const (
+ sizeofIfMsghdrlFreeBSD10 = 0x68
+ sizeofIfaMsghdrFreeBSD10 = 0x14
+ sizeofIfaMsghdrlFreeBSD10 = 0x6c
+ sizeofIfmaMsghdrFreeBSD10 = 0x10
+ sizeofIfAnnouncemsghdrFreeBSD10 = 0x18
+
+ sizeofRtMsghdrFreeBSD10 = 0x5c
+ sizeofRtMetricsFreeBSD10 = 0x38
+
+ sizeofIfMsghdrFreeBSD7 = 0x70
+ sizeofIfMsghdrFreeBSD8 = 0x70
+ sizeofIfMsghdrFreeBSD9 = 0x70
+ sizeofIfMsghdrFreeBSD10 = 0x70
+ sizeofIfMsghdrFreeBSD11 = 0xa8
+
+ sizeofIfDataFreeBSD7 = 0x60
+ sizeofIfDataFreeBSD8 = 0x60
+ sizeofIfDataFreeBSD9 = 0x60
+ sizeofIfDataFreeBSD10 = 0x60
+ sizeofIfDataFreeBSD11 = 0x98
+
+ sizeofIfMsghdrlFreeBSD10Emu = 0x68
+ sizeofIfaMsghdrFreeBSD10Emu = 0x14
+ sizeofIfaMsghdrlFreeBSD10Emu = 0x6c
+ sizeofIfmaMsghdrFreeBSD10Emu = 0x10
+ sizeofIfAnnouncemsghdrFreeBSD10Emu = 0x18
+
+ sizeofRtMsghdrFreeBSD10Emu = 0x5c
+ sizeofRtMetricsFreeBSD10Emu = 0x38
+
+ sizeofIfMsghdrFreeBSD7Emu = 0x70
+ sizeofIfMsghdrFreeBSD8Emu = 0x70
+ sizeofIfMsghdrFreeBSD9Emu = 0x70
+ sizeofIfMsghdrFreeBSD10Emu = 0x70
+ sizeofIfMsghdrFreeBSD11Emu = 0xa8
+
+ sizeofIfDataFreeBSD7Emu = 0x60
+ sizeofIfDataFreeBSD8Emu = 0x60
+ sizeofIfDataFreeBSD9Emu = 0x60
+ sizeofIfDataFreeBSD10Emu = 0x60
+ sizeofIfDataFreeBSD11Emu = 0x98
+)
--- /dev/null
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs defs_netbsd.go
+
+package route
+
+const (
+ sysAF_UNSPEC = 0x0
+ sysAF_INET = 0x2
+ sysAF_ROUTE = 0x22
+ sysAF_LINK = 0x12
+ sysAF_INET6 = 0x18
+
+ sysNET_RT_DUMP = 0x1
+ sysNET_RT_FLAGS = 0x2
+ sysNET_RT_IFLIST = 0x5
+ sysNET_RT_MAXID = 0x6
+)
+
+const (
+ sysCTL_MAXNAME = 0xc
+
+ sysCTL_UNSPEC = 0x0
+ sysCTL_KERN = 0x1
+ sysCTL_VM = 0x2
+ sysCTL_VFS = 0x3
+ sysCTL_NET = 0x4
+ sysCTL_DEBUG = 0x5
+ sysCTL_HW = 0x6
+ sysCTL_MACHDEP = 0x7
+ sysCTL_USER = 0x8
+ sysCTL_DDB = 0x9
+ sysCTL_PROC = 0xa
+ sysCTL_VENDOR = 0xb
+ sysCTL_EMUL = 0xc
+ sysCTL_SECURITY = 0xd
+ sysCTL_MAXID = 0xe
+)
+
+const (
+ sysRTM_VERSION = 0x4
+
+ sysRTM_ADD = 0x1
+ sysRTM_DELETE = 0x2
+ sysRTM_CHANGE = 0x3
+ sysRTM_GET = 0x4
+ sysRTM_LOSING = 0x5
+ sysRTM_REDIRECT = 0x6
+ sysRTM_MISS = 0x7
+ sysRTM_LOCK = 0x8
+ sysRTM_OLDADD = 0x9
+ sysRTM_OLDDEL = 0xa
+ sysRTM_RESOLVE = 0xb
+ sysRTM_NEWADDR = 0xc
+ sysRTM_DELADDR = 0xd
+ sysRTM_IFANNOUNCE = 0x10
+ sysRTM_IEEE80211 = 0x11
+ sysRTM_SETGATE = 0x12
+ sysRTM_LLINFO_UPD = 0x13
+ sysRTM_IFINFO = 0x14
+ sysRTM_CHGADDR = 0x15
+
+ sysRTA_DST = 0x1
+ sysRTA_GATEWAY = 0x2
+ sysRTA_NETMASK = 0x4
+ sysRTA_GENMASK = 0x8
+ sysRTA_IFP = 0x10
+ sysRTA_IFA = 0x20
+ sysRTA_AUTHOR = 0x40
+ sysRTA_BRD = 0x80
+ sysRTA_TAG = 0x100
+
+ sysRTAX_DST = 0x0
+ sysRTAX_GATEWAY = 0x1
+ sysRTAX_NETMASK = 0x2
+ sysRTAX_GENMASK = 0x3
+ sysRTAX_IFP = 0x4
+ sysRTAX_IFA = 0x5
+ sysRTAX_AUTHOR = 0x6
+ sysRTAX_BRD = 0x7
+ sysRTAX_TAG = 0x8
+ sysRTAX_MAX = 0x9
+)
+
+const (
+ sizeofIfMsghdrNetBSD7 = 0x98
+ sizeofIfaMsghdrNetBSD7 = 0x18
+ sizeofIfAnnouncemsghdrNetBSD7 = 0x18
+
+ sizeofRtMsghdrNetBSD7 = 0x78
+ sizeofRtMetricsNetBSD7 = 0x50
+)
--- /dev/null
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs defs_openbsd.go
+
+package route
+
+const (
+ sysAF_UNSPEC = 0x0
+ sysAF_INET = 0x2
+ sysAF_ROUTE = 0x11
+ sysAF_LINK = 0x12
+ sysAF_INET6 = 0x18
+
+ sysNET_RT_DUMP = 0x1
+ sysNET_RT_FLAGS = 0x2
+ sysNET_RT_IFLIST = 0x3
+ sysNET_RT_STATS = 0x4
+ sysNET_RT_TABLE = 0x5
+ sysNET_RT_IFNAMES = 0x6
+ sysNET_RT_MAXID = 0x7
+)
+
+const (
+ sysCTL_MAXNAME = 0xc
+
+ sysCTL_UNSPEC = 0x0
+ sysCTL_KERN = 0x1
+ sysCTL_VM = 0x2
+ sysCTL_FS = 0x3
+ sysCTL_NET = 0x4
+ sysCTL_DEBUG = 0x5
+ sysCTL_HW = 0x6
+ sysCTL_MACHDEP = 0x7
+ sysCTL_DDB = 0x9
+ sysCTL_VFS = 0xa
+ sysCTL_MAXID = 0xb
+)
+
+const (
+ sysRTM_VERSION = 0x5
+
+ sysRTM_ADD = 0x1
+ sysRTM_DELETE = 0x2
+ sysRTM_CHANGE = 0x3
+ sysRTM_GET = 0x4
+ sysRTM_LOSING = 0x5
+ sysRTM_REDIRECT = 0x6
+ sysRTM_MISS = 0x7
+ sysRTM_LOCK = 0x8
+ sysRTM_RESOLVE = 0xb
+ sysRTM_NEWADDR = 0xc
+ sysRTM_DELADDR = 0xd
+ sysRTM_IFINFO = 0xe
+ sysRTM_IFANNOUNCE = 0xf
+ sysRTM_DESYNC = 0x10
+
+ sysRTA_DST = 0x1
+ sysRTA_GATEWAY = 0x2
+ sysRTA_NETMASK = 0x4
+ sysRTA_GENMASK = 0x8
+ sysRTA_IFP = 0x10
+ sysRTA_IFA = 0x20
+ sysRTA_AUTHOR = 0x40
+ sysRTA_BRD = 0x80
+ sysRTA_SRC = 0x100
+ sysRTA_SRCMASK = 0x200
+ sysRTA_LABEL = 0x400
+
+ sysRTAX_DST = 0x0
+ sysRTAX_GATEWAY = 0x1
+ sysRTAX_NETMASK = 0x2
+ sysRTAX_GENMASK = 0x3
+ sysRTAX_IFP = 0x4
+ sysRTAX_IFA = 0x5
+ sysRTAX_AUTHOR = 0x6
+ sysRTAX_BRD = 0x7
+ sysRTAX_SRC = 0x8
+ sysRTAX_SRCMASK = 0x9
+ sysRTAX_LABEL = 0xa
+ sysRTAX_MAX = 0xb
+)
package p
-type I1 interface {
- F() interface{I1}
+type i1 interface {
+ F() interface{i1}
}
-type I2 interface {
- F() interface{I2}
+type i2 interface {
+ F() interface{i2}
}
-var v1 I1
-var v2 I2
+var v1 i1
+var v2 i2
func f() bool {
return v1 == v2
}
+
+// TODO(gri) Change test to use exported interfaces.
+// See issue #15596 for details.
\ No newline at end of file
func main() {
type person struct{ age, weight, height int }
students := map[string]person{"sally": person{12, 50, 32}}
- students["sally"].age = 3 // ERROR "cannot directly assign to struct field .* in map"
+ students["sally"].age = 3 // ERROR "cannot assign to struct field .* in map"
}
--- /dev/null
+// errorcheck
+
+// 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.
+
+// Test that > 10 non-syntax errors on the same line
+// don't lead to early exit. Specifically, here test
+// that we see the initialization error for variable
+// s.
+
+package main
+
+type T struct{}
+
+func main() {
+ t := T{X: 1, X: 1, X: 1, X: 1, X: 1, X: 1, X: 1, X: 1, X: 1, X: 1} // ERROR "unknown T field"
+ var s string = 1 // ERROR "cannot use 1"
+}
--- /dev/null
+// run
+
+// 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.
+// +build amd64
+
+package main
+
+import "runtime"
+
+type big [10 << 20]byte
+
+func f(x *big, start int64) {
+ if delta := inuse() - start; delta < 9<<20 {
+ println("after alloc: expected delta at least 9MB, got: ", delta)
+ }
+ x = nil
+ if delta := inuse() - start; delta > 1<<20 {
+ println("after drop: expected delta below 1MB, got: ", delta)
+ }
+ x = new(big)
+ if delta := inuse() - start; delta < 9<<20 {
+ println("second alloc: expected delta at least 9MB, got: ", delta)
+ }
+}
+
+func main() {
+ x := inuse()
+ f(new(big), x)
+}
+
+func inuse() int64 {
+ runtime.GC()
+ var st runtime.MemStats
+ runtime.ReadMemStats(&st)
+ return int64(st.Alloc)
+}
--- /dev/null
+// run
+
+// 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.
+
+// Previously, cmd/compile would rewrite
+//
+// check(unsafe.Pointer(testMeth(1).Pointer()), unsafe.Pointer(testMeth(2).Pointer()))
+//
+// to
+//
+// var autotmp_1 uintptr = testMeth(1).Pointer()
+// var autotmp_2 uintptr = testMeth(2).Pointer()
+// check(unsafe.Pointer(autotmp_1), unsafe.Pointer(autotmp_2))
+//
+// However, that means autotmp_1 is the only reference to the int
+// variable containing the value "1", but it's not a pointer type,
+// so it was at risk of being garbage collected by the evaluation of
+// testMeth(2).Pointer(), even though package unsafe's documentation
+// says the original code was allowed.
+//
+// Now cmd/compile rewrites it to
+//
+// var autotmp_1 unsafe.Pointer = unsafe.Pointer(testMeth(1).Pointer())
+// var autotmp_2 unsafe.Pointer = unsafe.Pointer(testMeth(2).Pointer())
+// check(autotmp_1, autotmp_2)
+//
+// to ensure the pointed-to variables are visible to the GC.
+
+package main
+
+import (
+ "fmt"
+ "reflect"
+ "runtime"
+ "unsafe"
+)
+
+func main() {
+ // Test all the different ways we can invoke reflect.Value.Pointer.
+
+ // Direct method invocation.
+ check(unsafe.Pointer(testMeth(1).Pointer()), unsafe.Pointer(testMeth(2).Pointer()))
+
+ // Invocation via method expression.
+ check(unsafe.Pointer(reflect.Value.Pointer(testMeth(1))), unsafe.Pointer(reflect.Value.Pointer(testMeth(2))))
+
+ // Invocation via interface.
+ check(unsafe.Pointer(testInter(1).Pointer()), unsafe.Pointer(testInter(2).Pointer()))
+
+ // Invocation via method value.
+ check(unsafe.Pointer(testFunc(1)()), unsafe.Pointer(testFunc(2)()))
+}
+
+func check(p, q unsafe.Pointer) {
+ a, b := *(*int)(p), *(*int)(q)
+ if a != 1 || b != 2 {
+ fmt.Printf("got %v, %v; expected 1, 2\n", a, b)
+ }
+}
+
+func testMeth(x int) reflect.Value {
+ // Force GC to run.
+ runtime.GC()
+ return reflect.ValueOf(&x)
+}
+
+type Pointerer interface {
+ Pointer() uintptr
+}
+
+func testInter(x int) Pointerer {
+ return testMeth(x)
+}
+
+func testFunc(x int) func() uintptr {
+ return testMeth(x).Pointer
+}
package c
import (
- _ "./a"
_ "./b"
+ _ "./a"
)
--- /dev/null
+// 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 a
+
+type T struct {
+}
+
+func F() []T {
+ return []T{T{}}
+}
+
+func Fi() []T {
+ return []T{{}} // element with implicit composite literal type
+}
+
+func Fp() []*T {
+ return []*T{&T{}}
+}
+
+func Fip() []*T {
+ return []*T{{}} // element with implicit composite literal type
+}
+
+func Gp() map[int]*T {
+ return map[int]*T{0: &T{}}
+}
+
+func Gip() map[int]*T {
+ return map[int]*T{0: {}} // element with implicit composite literal type
+}
+
+func Hp() map[*T]int {
+ return map[*T]int{&T{}: 0}
+}
+
+func Hip() map[*T]int {
+ return map[*T]int{{}: 0} // key with implicit composite literal type
+}
--- /dev/null
+// 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 b
+
+import "./a"
+
+func F() {
+ a.F()
+ a.Fi()
+}
+
+func Fp() {
+ a.Fp()
+ a.Fip()
+}
+
+func Gp() {
+ a.Gp()
+ a.Gip()
+}
+
+func Hp() {
+ a.Hp()
+ a.Hip()
+}
--- /dev/null
+// compiledir
+
+// 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.
+
+// Test that exporting composite literals with implicit
+// types doesn't crash the typechecker when running over
+// inlined function bodies containing such literals.
+
+package ignored
--- /dev/null
+// compile
+
+// 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 bug
+
+func example(n int) (rc int) {
+ var cc, ll, pp, rr [27]int
+ for q0 := 0; q0 < n-2; q0++ {
+ for q1 := q0 + 2; q1 < n; q1++ {
+ var c, d, l, p, r int
+ b0 := 1 << uint(q0)
+ b1 := 1 << uint(q1)
+ l = ((b0 << 1) | b1) << 1
+ c = b0 | b1 | (-1 << uint(n))
+ r = ((b0 >> 1) | b1) >> 1
+ E:
+ if c != -1 {
+ p = ^(l | c | r)
+ } else {
+ rc++
+ goto R
+ }
+ L:
+ if p != 0 {
+ lsb := p & -p
+ p &^= lsb
+ ll[d], cc[d], rr[d], pp[d] = l, c, r, p
+ l, c, r = (l|lsb)<<1, c|lsb, (r|lsb)>>1
+ d++
+ goto E
+ }
+ R:
+ d--
+ if d >= 0 {
+ l, c, r, p = ll[d], cc[d], rr[d], pp[d]
+ goto L
+ }
+ }
+ }
+ rc <<= 1
+ return
+}
--- /dev/null
+// compile
+
+// 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 p
+
+func f(i interface{}) {
+ i, _ = i.(error)
+}
--- /dev/null
+// compile
+
+// 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 bug
+
+import "os"
+
+func f(err error) {
+ var ok bool
+ if err, ok = err.(*os.PathError); ok {
+ if err == os.ErrNotExist {
+ }
+ }
+}
--- /dev/null
+// 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 a
+
+type T struct{}
+
+func (T) m() string {
+ return "m"
+}
+
+func (*T) mp() string {
+ return "mp"
+}
+
+func F() func(T) string {
+ return T.m // method expression
+}
+
+func Fp() func(*T) string {
+ return (*T).mp // method expression
+}
--- /dev/null
+// 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
+
+import "./a" // import must succeed
+
+func main() {
+ if a.F()(a.T{}) != "m" {
+ panic(0)
+ }
+ if a.Fp()(nil) != "mp" {
+ panic(1)
+ }
+}
--- /dev/null
+// rundir
+
+// 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.
+
+// Test that method expressions are correctly encoded
+// in binary export data and can be imported again.
+package ignore
\ No newline at end of file
--- /dev/null
+// compile
+
+// 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
+
+type S struct {
+ a [1 << 16]byte
+}
+
+func f1() {
+ p := &S{}
+ _ = p
+}
+
+type T [1 << 16]byte
+
+func f2() {
+ p := &T{}
+ _ = p
+}
--- /dev/null
+// errorcheck -0 -live
+
+// 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 15747: liveness analysis was marking heap-escaped params live too much,
+// and worse was using the wrong bitmap bits to do so.
+
+package p
+
+var global *[]byte
+
+type Q struct{}
+
+type T struct{ M string }
+
+var b bool
+
+func f1(q *Q, xx []byte) interface{} { // ERROR "live at entry to f1: q xx" "live at call to newobject: q xx" "live at call to writebarrierptr: q &xx"
+ // xx was copied from the stack to the heap on the previous line:
+ // xx was live for the first two prints but then it switched to &xx
+ // being live. We should not see plain xx again.
+ if b {
+ global = &xx // ERROR "live at call to writebarrierptr: q &xx$"
+ }
+ xx, _, err := f2(xx, 5) // ERROR "live at call to newobject: q( d)? &xx( odata.ptr)?" "live at call to writebarrierptr: q (e|err.data err.type)$"
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func f2(d []byte, n int) (odata, res []byte, e interface{}) { // ERROR "live at entry to f2: d"
+ if n > len(d) {
+ return d, nil, &T{M: "hello"} // ERROR "live at call to newobject: d"
+ }
+ res = d[:n]
+ odata = d[n:]
+ return
+}
--- /dev/null
+// compile
+
+// 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 15747: If a ODCL is dropped, for example when inlining,
+// then it's easy to end up not initializing the '&x' pseudo-variable
+// to point to an actual allocation. The liveness analysis will detect
+// this and abort the computation, so this test just checks that the
+// compilation succeeds.
+
+package p
+
+type R [100]byte
+
+func (x R) New() *R {
+ return &x
+}
--- /dev/null
+// 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 a
+
+func F1() {
+L:
+ goto L
+}
+
+func F2() {
+L:
+ for {
+ break L
+ }
+}
+
+func F3() {
+L:
+ for {
+ continue L
+ }
+}
+
+func F4() {
+ switch {
+ case true:
+ fallthrough
+ default:
+ }
+}
+
+type T struct{}
+
+func (T) M1() {
+L:
+ goto L
+}
+
+func (T) M2() {
+L:
+ for {
+ break L
+ }
+}
+
+func (T) M3() {
+L:
+ for {
+ continue L
+ }
+}
+
+func (T) M4() {
+ switch {
+ case true:
+ fallthrough
+ default:
+ }
+}
--- /dev/null
+// 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 b
+
+import "./a"
+
+type T struct{ a.T }
--- /dev/null
+// compiledir
+
+// 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.
+
+// Test cases for issue #15838, and related failures.
+// Make sure the importer correctly sets up nodes for
+// label decls, goto, continue, break, and fallthrough
+// statements.
+
+package ignored
--- /dev/null
+// +build !nacl
+// run
+
+// 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.
+
+// Test the compiler -linkobj flag.
+
+package main
+
+import (
+ "fmt"
+ "io/ioutil"
+ "log"
+ "os"
+ "os/exec"
+ "strings"
+)
+
+var pwd, tmpdir string
+
+func main() {
+ dir, err := ioutil.TempDir("", "go-test-linkobj-")
+ if err != nil {
+ log.Fatal(err)
+ }
+ pwd, err = os.Getwd()
+ if err != nil {
+ log.Fatal(err)
+ }
+ if err := os.Chdir(dir); err != nil {
+ os.RemoveAll(dir)
+ log.Fatal(err)
+ }
+ tmpdir = dir
+
+ writeFile("p1.go", `
+ package p1
+
+ func F() {
+ println("hello from p1")
+ }
+ `)
+ writeFile("p2.go", `
+ package p2
+
+ import "./p1"
+
+ func F() {
+ p1.F()
+ println("hello from p2")
+ }
+
+ func main() {}
+ `)
+ writeFile("p3.go", `
+ package main
+
+ import "./p2"
+
+ func main() {
+ p2.F()
+ println("hello from main")
+ }
+ `)
+
+ // two rounds: once using normal objects, again using .a files (compile -pack).
+ for round := 0; round < 2; round++ {
+ pkg := "-pack=" + fmt.Sprint(round)
+
+ // The compiler expects the files being read to have the right suffix.
+ o := "o"
+ if round == 1 {
+ o = "a"
+ }
+
+ // inlining is disabled to make sure that the link objects contain needed code.
+ run("go", "tool", "compile", pkg, "-D", ".", "-I", ".", "-l", "-o", "p1."+o, "-linkobj", "p1.lo", "p1.go")
+ run("go", "tool", "compile", pkg, "-D", ".", "-I", ".", "-l", "-o", "p2."+o, "-linkobj", "p2.lo", "p2.go")
+ run("go", "tool", "compile", pkg, "-D", ".", "-I", ".", "-l", "-o", "p3."+o, "-linkobj", "p3.lo", "p3.go")
+
+ cp("p1."+o, "p1.oo")
+ cp("p2."+o, "p2.oo")
+ cp("p3."+o, "p3.oo")
+ cp("p1.lo", "p1."+o)
+ cp("p2.lo", "p2."+o)
+ cp("p3.lo", "p3."+o)
+ out := runFail("go", "tool", "link", "p2."+o)
+ if !strings.Contains(out, "not package main") {
+ fatalf("link p2.o failed but not for package main:\n%s", out)
+ }
+
+ run("go", "tool", "link", "-L", ".", "-o", "a.out.exe", "p3."+o)
+ out = run("./a.out.exe")
+ if !strings.Contains(out, "hello from p1\nhello from p2\nhello from main\n") {
+ fatalf("running main, incorrect output:\n%s", out)
+ }
+
+ // ensure that mistaken future round can't use these
+ os.Remove("p1.o")
+ os.Remove("a.out.exe")
+ }
+
+ cleanup()
+}
+
+func run(args ...string) string {
+ out, err := exec.Command(args[0], args[1:]...).CombinedOutput()
+ if err != nil {
+ fatalf("run %v: %s\n%s", args, err, out)
+ }
+ return string(out)
+}
+
+func runFail(args ...string) string {
+ out, err := exec.Command(args[0], args[1:]...).CombinedOutput()
+ if err == nil {
+ fatalf("runFail %v: unexpected success!\n%s", args, err, out)
+ }
+ return string(out)
+}
+
+func cp(src, dst string) {
+ data, err := ioutil.ReadFile(src)
+ if err != nil {
+ fatalf("%v", err)
+ }
+ err = ioutil.WriteFile(dst, data, 0666)
+ if err != nil {
+ fatalf("%v", err)
+ }
+}
+
+func writeFile(name, data string) {
+ err := ioutil.WriteFile(name, []byte(data), 0666)
+ if err != nil {
+ fatalf("%v", err)
+ }
+}
+
+func cleanup() {
+ const debug = false
+ if debug {
+ println("TMPDIR:", tmpdir)
+ return
+ }
+ os.Chdir(pwd) // get out of tmpdir before removing it
+ os.RemoveAll(tmpdir)
+}
+
+func fatalf(format string, args ...interface{}) {
+ cleanup()
+ log.Fatalf(format, args...)
+}