mirror of https://github.com/golang/go.git
[dev.power64] build: merge default into dev.power64
LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/160200044
This commit is contained in:
commit
3208250185
3
.hgtags
3
.hgtags
|
|
@ -131,4 +131,5 @@ f8b50ad4cac4d4c4ecf48324b4f512f65e82cc1c go1.3beta1
|
|||
9d5451df4e53acc58a848005b7ec3a24c4b6050c go1.3rc1
|
||||
3f66a43d5180052e2e1e38d979d1aa5ad05b21f9 go1.3rc2
|
||||
9895f9e36435468d503eaa74ee217f28d5e28dd4 go1.3
|
||||
9895f9e36435468d503eaa74ee217f28d5e28dd4 release
|
||||
073fc578434bf3e1e22749b559d273c8da728ebb go1.3.1
|
||||
073fc578434bf3e1e22749b559d273c8da728ebb release
|
||||
|
|
|
|||
9
AUTHORS
9
AUTHORS
|
|
@ -16,6 +16,7 @@ Adrien Bustany <adrien-xx-google@bustany.org>
|
|||
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>
|
||||
Alex A Skinner <alex@lx.lc>
|
||||
|
|
@ -35,6 +36,7 @@ Amrut Joshi <amrut.joshi@gmail.com>
|
|||
Andrei Vieru <euvieru@gmail.com>
|
||||
Andrew Balholm <andybalholm@gmail.com>
|
||||
Andrew Bonventre <andybons@chromium.org>
|
||||
Andrew Bursavich <abursavich@gmail.com>
|
||||
Andrew Harding <andrew@spacemonkey.com>
|
||||
Andrew Lutomirski <andy@luto.us>
|
||||
Andrew Pritchard <awpritchard@gmail.com>
|
||||
|
|
@ -118,6 +120,7 @@ David du Colombier <0intro@gmail.com>
|
|||
David Forsythe <dforsythe@gmail.com>
|
||||
David G. Andersen <dave.andersen@gmail.com>
|
||||
David Jakob Fritz <david.jakob.fritz@gmail.com>
|
||||
David Leon Gil <coruus@gmail.com>
|
||||
David Thomas <davidthomas426@gmail.com>
|
||||
David Titarenco <david.titarenco@gmail.com>
|
||||
Dean Prichard <dean.prichard@gmail.com>
|
||||
|
|
@ -152,6 +155,7 @@ Evan Shaw <chickencha@gmail.com>
|
|||
Ewan Chou <coocood@gmail.com>
|
||||
Fabrizio Milo <mistobaan@gmail.com>
|
||||
Fan Hongjian <fan.howard@gmail.com>
|
||||
Fatih Arslan <fatih@arslan.io>
|
||||
Fazlul Shahriar <fshahriar@gmail.com>
|
||||
Felix Geisendörfer <haimuiba@gmail.com>
|
||||
Firmansyah Adiputra <frm.adiputra@gmail.com>
|
||||
|
|
@ -178,6 +182,7 @@ Gustavo Niemeyer <gustavo@niemeyer.net>
|
|||
Gwenael Treguier <gwenn.kahz@gmail.com>
|
||||
Harley Laue <losinggeneration@gmail.com>
|
||||
Hector Chu <hectorchu@gmail.com>
|
||||
Henning Schmiedehausen <henning@schmiedehausen.org>
|
||||
Henrik Edwards <henrik.edwards@gmail.com>
|
||||
Herbert Georg Fischer <herbert.fischer@gmail.com>
|
||||
Hong Ruiqi <hongruiqi@gmail.com>
|
||||
|
|
@ -213,6 +218,8 @@ Jimmy Zelinskie <jimmyzelinskie@gmail.com>
|
|||
Jingcheng Zhang <diogin@gmail.com>
|
||||
Joakim Sernbrant <serbaut@gmail.com>
|
||||
Joe Poirier <jdpoirier@gmail.com>
|
||||
Joe Shaw <joe@joeshaw.org>
|
||||
Joel Stemmer <stemmertech@gmail.com>
|
||||
John Asmuth <jasmuth@gmail.com>
|
||||
John C Barstow <jbowtie@amathaine.com>
|
||||
John Graham-Cumming <jgc@jgc.org> <jgrahamc@gmail.com>
|
||||
|
|
@ -257,6 +264,7 @@ Luke Curley <qpingu@gmail.com>
|
|||
Manuel Mendez <mmendez534@gmail.com>
|
||||
Marc Weistroff <marc@weistroff.net>
|
||||
Marco Hennings <marco.hennings@freiheit.com>
|
||||
Mark Theunissen <mark.theunissen@gmail.com>
|
||||
Marko Juhani Silokunnas <marko.silokunnas@gmail.com>
|
||||
Marko Tiikkaja <marko@joh.to>
|
||||
Markover Inc. DBA Poptip
|
||||
|
|
@ -399,6 +407,7 @@ Taj Khattra <taj.khattra@gmail.com>
|
|||
Tarmigan Casebolt <tarmigan@gmail.com>
|
||||
Taru Karttunen <taruti@taruti.net>
|
||||
Tetsuo Kiso <tetsuokiso9@gmail.com>
|
||||
Thiago Fransosi Farina <thiago.farina@gmail.com>
|
||||
Thomas Alan Copeland <talan.copeland@gmail.com>
|
||||
Thomas Kappler <tkappler@gmail.com>
|
||||
Timo Savola <timo.savola@gmail.com>
|
||||
|
|
|
|||
11
CONTRIBUTORS
11
CONTRIBUTORS
|
|
@ -42,6 +42,7 @@ Akshat Kumar <seed@mail.nanosouffle.net>
|
|||
Alan Donovan <adonovan@google.com>
|
||||
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>
|
||||
Alex A Skinner <alex@lx.lc>
|
||||
|
|
@ -66,6 +67,7 @@ Andreas Jellinghaus <andreas@ionisiert.de> <anj@google.com>
|
|||
Andrei Vieru <euvieru@gmail.com>
|
||||
Andrew Balholm <andybalholm@gmail.com>
|
||||
Andrew Bonventre <andybons@chromium.org>
|
||||
Andrew Bursavich <abursavich@gmail.com>
|
||||
Andrew Gerrand <adg@golang.org>
|
||||
Andrew Harding <andrew@spacemonkey.com>
|
||||
Andrew Lutomirski <andy@luto.us>
|
||||
|
|
@ -180,6 +182,7 @@ David du Colombier <0intro@gmail.com>
|
|||
David Forsythe <dforsythe@gmail.com>
|
||||
David G. Andersen <dave.andersen@gmail.com>
|
||||
David Jakob Fritz <david.jakob.fritz@gmail.com>
|
||||
David Leon Gil <coruus@gmail.com>
|
||||
David McLeish <davemc@google.com>
|
||||
David Presotto <presotto@gmail.com>
|
||||
David Symonds <dsymonds@golang.org>
|
||||
|
|
@ -221,6 +224,7 @@ Evan Shaw <chickencha@gmail.com>
|
|||
Ewan Chou <coocood@gmail.com>
|
||||
Fabrizio Milo <mistobaan@gmail.com>
|
||||
Fan Hongjian <fan.howard@gmail.com>
|
||||
Fatih Arslan <fatih@arslan.io>
|
||||
Fazlul Shahriar <fshahriar@gmail.com>
|
||||
Felix Geisendörfer <haimuiba@gmail.com>
|
||||
Firmansyah Adiputra <frm.adiputra@gmail.com>
|
||||
|
|
@ -253,6 +257,7 @@ Gwenael Treguier <gwenn.kahz@gmail.com>
|
|||
Han-Wen Nienhuys <hanwen@google.com>
|
||||
Harley Laue <losinggeneration@gmail.com>
|
||||
Hector Chu <hectorchu@gmail.com>
|
||||
Henning Schmiedehausen <henning@schmiedehausen.org>
|
||||
Henrik Edwards <henrik.edwards@gmail.com>
|
||||
Herbert Georg Fischer <herbert.fischer@gmail.com>
|
||||
Hong Ruiqi <hongruiqi@gmail.com>
|
||||
|
|
@ -300,7 +305,9 @@ Jimmy Zelinskie <jimmyzelinskie@gmail.com>
|
|||
Jingcheng Zhang <diogin@gmail.com>
|
||||
Joakim Sernbrant <serbaut@gmail.com>
|
||||
Joe Poirier <jdpoirier@gmail.com>
|
||||
Joe Shaw <joe@joeshaw.org>
|
||||
Joel Sing <jsing@google.com>
|
||||
Joel Stemmer <stemmertech@gmail.com>
|
||||
Johan Euphrosine <proppy@google.com>
|
||||
John Asmuth <jasmuth@gmail.com>
|
||||
John Beisley <huin@google.com>
|
||||
|
|
@ -368,6 +375,7 @@ Manuel Mendez <mmendez534@gmail.com>
|
|||
Marc Weistroff <marc@weistroff.net>
|
||||
Marcel van Lohuizen <mpvl@golang.org>
|
||||
Marco Hennings <marco.hennings@freiheit.com>
|
||||
Mark Theunissen <mark.theunissen@gmail.com>
|
||||
Mark Zavislak <zavislak@google.com>
|
||||
Marko Juhani Silokunnas <marko.silokunnas@gmail.com>
|
||||
Marko Mikulicic <mkm@google.com>
|
||||
|
|
@ -455,6 +463,7 @@ Paul Borman <borman@google.com>
|
|||
Paul Chang <paulchang@google.com>
|
||||
Paul Hammond <paul@paulhammond.org>
|
||||
Paul Lalonde <paul.a.lalonde@gmail.com>
|
||||
Paul Nasrat <pnasrat@google.com>
|
||||
Paul Sbarra <Sbarra.Paul@gmail.com>
|
||||
Paul van Brouwershaven <paul@vanbrouwershaven.com>
|
||||
Pavel Zinovkin <pavel.zinovkin@gmail.com>
|
||||
|
|
@ -486,6 +495,7 @@ Richard Crowley <r@rcrowley.org>
|
|||
Richard Eric Gavaletz <gavaletz@gmail.com>
|
||||
Richard Musiol <mail@richard-musiol.de> <neelance@gmail.com>
|
||||
Rick Arnold <rickarnoldjr@gmail.com>
|
||||
Rick Hudson <rlh@golang.org>
|
||||
Risto Jaakko Saarelma <rsaarelm@gmail.com>
|
||||
Rob Pike <r@golang.org>
|
||||
Robert Daniel Kortschak <dan.kortschak@adelaide.edu.au>
|
||||
|
|
@ -547,6 +557,7 @@ Taj Khattra <taj.khattra@gmail.com>
|
|||
Tarmigan Casebolt <tarmigan@gmail.com>
|
||||
Taru Karttunen <taruti@taruti.net>
|
||||
Tetsuo Kiso <tetsuokiso9@gmail.com>
|
||||
Thiago Fransosi Farina <thiago.farina@gmail.com> <tfarina@chromium.org>
|
||||
Thomas Alan Copeland <talan.copeland@gmail.com>
|
||||
Thomas Habets <habets@google.com>
|
||||
Thomas Kappler <tkappler@gmail.com>
|
||||
|
|
|
|||
|
|
@ -327,3 +327,4 @@ pkg syscall (netbsd-arm), const SizeofIfData = 132
|
|||
pkg syscall (netbsd-arm), type IfMsghdr struct, Pad_cgo_1 [4]uint8
|
||||
pkg syscall (netbsd-arm-cgo), const SizeofIfData = 132
|
||||
pkg syscall (netbsd-arm-cgo), type IfMsghdr struct, Pad_cgo_1 [4]uint8
|
||||
pkg unicode, const Version = "6.3.0"
|
||||
|
|
|
|||
24
api/next.txt
24
api/next.txt
|
|
@ -115,3 +115,27 @@ pkg debug/goobj, type Var struct, Kind int
|
|||
pkg debug/goobj, type Var struct, Name string
|
||||
pkg debug/goobj, type Var struct, Offset int
|
||||
pkg debug/goobj, type Var struct, Type SymID
|
||||
pkg unicode, const Version = "7.0.0"
|
||||
pkg unicode, var Bassa_Vah *RangeTable
|
||||
pkg unicode, var Caucasian_Albanian *RangeTable
|
||||
pkg unicode, var Duployan *RangeTable
|
||||
pkg unicode, var Elbasan *RangeTable
|
||||
pkg unicode, var Grantha *RangeTable
|
||||
pkg unicode, var Khojki *RangeTable
|
||||
pkg unicode, var Khudawadi *RangeTable
|
||||
pkg unicode, var Linear_A *RangeTable
|
||||
pkg unicode, var Mahajani *RangeTable
|
||||
pkg unicode, var Manichaean *RangeTable
|
||||
pkg unicode, var Mende_Kikakui *RangeTable
|
||||
pkg unicode, var Modi *RangeTable
|
||||
pkg unicode, var Mro *RangeTable
|
||||
pkg unicode, var Nabataean *RangeTable
|
||||
pkg unicode, var Old_North_Arabian *RangeTable
|
||||
pkg unicode, var Old_Permic *RangeTable
|
||||
pkg unicode, var Pahawh_Hmong *RangeTable
|
||||
pkg unicode, var Palmyrene *RangeTable
|
||||
pkg unicode, var Pau_Cin_Hau *RangeTable
|
||||
pkg unicode, var Psalter_Pahlavi *RangeTable
|
||||
pkg unicode, var Siddham *RangeTable
|
||||
pkg unicode, var Tirhuta *RangeTable
|
||||
pkg unicode, var Warang_Citi *RangeTable
|
||||
|
|
|
|||
|
|
@ -253,7 +253,7 @@ There may be one or two arguments to the directives.
|
|||
If there are two, the first is a bit mask of flags,
|
||||
which can be written as numeric expressions, added or or-ed together,
|
||||
or can be set symbolically for easier absorption by a human.
|
||||
Their values, defined in the file <code>src/cmd/ld/textflag.h</code>, are:
|
||||
Their values, defined in the standard <code>#include</code> file <code>textflag.h</code>, are:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ details.
|
|||
<td><a href="//godoc.org/code.google.com/p/go.tools/cmd/cover/">cover</a></td>
|
||||
<td> </td>
|
||||
<td>Cover is a program for creating and analyzing the coverage profiles
|
||||
generated by <code>"go test -coverprofile"</code>.
|
||||
generated by <code>"go test -coverprofile"</code>.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
|
|
|||
|
|
@ -20,6 +20,13 @@ Go 1.3 is a major release of Go.
|
|||
Read the <a href="/doc/go1.3">Go 1.3 Release Notes</a> for more information.
|
||||
</p>
|
||||
|
||||
<h3 id="go1.3.minor">Minor revisions</h3>
|
||||
|
||||
<p>
|
||||
go1.3.1 (released 2014/08/13) includes bug fixes to the compiler and the <code>runtime</code>, <code>net</code>, and <code>crypto/rsa</code> packages.
|
||||
See the <a href="//code.google.com/p/go/source/list?name=release-branch.go1.3&r=073fc578434bf3e1e22749b559d273c8da728ebb">change history</a> for details.
|
||||
</p>
|
||||
|
||||
<h2 id="go1.2">go1.2 (released 2013/12/01)</h2>
|
||||
|
||||
<p>
|
||||
|
|
|
|||
|
|
@ -521,6 +521,15 @@ field to specify an end-to-end timeout on requests made using the
|
|||
client.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
The <a href="/pkg/net/http/"><code>net/http</code></a> package's
|
||||
<a href="/pkg/net/http/#Request.ParseMultipartForm"><code>Request.ParseMultipartForm</code></a>
|
||||
method will now return an error if the body's <code>Content-Type</code>
|
||||
is not <code>mutipart/form-data</code>.
|
||||
Prior to Go 1.3 it would silently fail and return <code>nil</code>.
|
||||
Code that relies on the previous behavior should be updated.
|
||||
</li>
|
||||
|
||||
<li> In the <a href="/pkg/net/"><code>net</code></a> package,
|
||||
the <a href="/pkg/net/#Dialer"><code>Dialer</code></a> struct now
|
||||
has a <code>KeepAlive</code> option to specify a keep-alive period for the connection.
|
||||
|
|
|
|||
|
|
@ -7,12 +7,27 @@ Please keep the list sorted (as in sort.Strings of the lines).
|
|||
|
||||
spec: permit for range x (CL 104680043)
|
||||
|
||||
cmd/6l, liblink: use pc-relative addressing for all memory references, so that linking Go binaries at high addresses works (CL 125140043). This cuts the maximum size of a Go binary's text+data+bss from 4GB to 2GB.
|
||||
cmd/go: import comments (CL 124940043)
|
||||
cmd/go: implement "internal" (CL 120600043)
|
||||
cmd/go: implement "generate" (CL 125580044)
|
||||
|
||||
asm: make textflag.h available outside of cmd/ld (CL 128050043)
|
||||
crypto/tls: add support for ALPN (RFC 7301) (CL 108710046)
|
||||
crypto/tls: support programmatic selection of server certificates (CL 107400043)
|
||||
encoding/gob: remove unsafe (CL 102680045)
|
||||
misc: deleted editor support; refer to https://code.google.com/p/go-wiki/wiki/IDEsAndTextEditorPlugins instead (CL 105470043)
|
||||
net/http: add Request.BasicAuth method (CL 76540043)
|
||||
net/http: add Transport.DialTLS hook (CL 137940043)
|
||||
net/http/httputil: add ReverseProxy.ErrorLog (CL 132750043)
|
||||
os: implement symlink support for windows (CL 86160044)
|
||||
runtime: implement monotonic clocks on windows (CL 108700045)
|
||||
runtime/race: freebsd is supported (CL 107270043)
|
||||
syscall: Setuid, Setgid are disabled on linux platforms. On linux those syscalls operate on the calling thread, not the whole process. This does not match the semantics of other platforms, nor the expectations of the caller, so the operations have been disabled until issue 1435 is resolved (CL 106170043)
|
||||
syscal: now frozen (CL 129820043)
|
||||
testing: add Coverage (CL 98150043)
|
||||
text/scanner: add IsIdentRune field of Scanner. (CL 108030044)
|
||||
time: use the micro symbol (µ (U+00B5)) to print microsecond duration (CL 105030046)
|
||||
encoding/asn1: optional elements with a default value will now only be omitted if they have that value (CL 86960045).
|
||||
|
||||
go.sys subrepo created: http://golang.org/s/go1.4-syscall
|
||||
|
|
|
|||
|
|
@ -152,6 +152,21 @@ will be tagged as appropriate to identify versions that are compatible
|
|||
with the Go 1 point releases.
|
||||
</p>
|
||||
|
||||
<h2 id="operating_systems">Operating systems</h2>
|
||||
|
||||
<p>
|
||||
It is impossible to guarantee long-term compatibility with operating
|
||||
system interfaces, which are changed by outside parties.
|
||||
The <a href="/pkg/syscall/"><code>syscall</code></a> package
|
||||
is therefore outside the purview of the guarantees made here.
|
||||
As of Go version 1.4, the <code>syscall</code> package is frozen.
|
||||
Any evolution of the system call interface must be supported elsewhere,
|
||||
such as in the
|
||||
<a href="http://godoc.org/code.google.com/p/go.sys">go.sys</a> subrepository.
|
||||
For details and background, see
|
||||
<a href="https://golang.org/s/go1.4-syscall">this document</a>.
|
||||
</p>
|
||||
|
||||
<h2 id="tools">Tools</h2>
|
||||
|
||||
<p>
|
||||
|
|
|
|||
475
doc/go_spec.html
475
doc/go_spec.html
|
|
@ -1,6 +1,6 @@
|
|||
<!--{
|
||||
"Title": "The Go Programming Language Specification",
|
||||
"Subtitle": "Version of August 5, 2014",
|
||||
"Subtitle": "Version of August 28, 2014",
|
||||
"Path": "/ref/spec"
|
||||
}-->
|
||||
|
||||
|
|
@ -479,7 +479,7 @@ Interpreted string literals are character sequences between double
|
|||
quotes <code>""</code>. The text between the quotes,
|
||||
which may not contain newlines, forms the
|
||||
value of the literal, with backslash escapes interpreted as they
|
||||
are in rune literals (except that <code>\'</code> is illegal and
|
||||
are in <a href="#Rune_literals">rune literals</a> (except that <code>\'</code> is illegal and
|
||||
<code>\"</code> is legal), with the same restrictions.
|
||||
The three-digit octal (<code>\</code><i>nnn</i>)
|
||||
and two-digit hexadecimal (<code>\x</code><i>nn</i>) escapes represent individual
|
||||
|
|
@ -1034,7 +1034,7 @@ The value of an uninitialized pointer is <code>nil</code>.
|
|||
|
||||
<pre class="ebnf">
|
||||
PointerType = "*" BaseType .
|
||||
BaseType = Type .
|
||||
BaseType = Type .
|
||||
</pre>
|
||||
|
||||
<pre>
|
||||
|
|
@ -2118,9 +2118,9 @@ operand only on the left-hand side of an <a href="#Assignments">assignment</a>.
|
|||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
Operand = Literal | OperandName | MethodExpr | "(" Expression ")" .
|
||||
Literal = BasicLit | CompositeLit | FunctionLit .
|
||||
BasicLit = int_lit | float_lit | imaginary_lit | rune_lit | string_lit .
|
||||
Operand = Literal | OperandName | MethodExpr | "(" Expression ")" .
|
||||
Literal = BasicLit | CompositeLit | FunctionLit .
|
||||
BasicLit = int_lit | float_lit | imaginary_lit | rune_lit | string_lit .
|
||||
OperandName = identifier | QualifiedIdent.
|
||||
</pre>
|
||||
|
||||
|
|
@ -2537,6 +2537,233 @@ p.M0() // ((*p).T0).M0()
|
|||
</pre>
|
||||
|
||||
|
||||
<h3 id="Method_expressions">Method expressions</h3>
|
||||
|
||||
<p>
|
||||
If <code>M</code> is in the <a href="#Method_sets">method set</a> of type <code>T</code>,
|
||||
<code>T.M</code> is a function that is callable as a regular function
|
||||
with the same arguments as <code>M</code> prefixed by an additional
|
||||
argument that is the receiver of the method.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
MethodExpr = ReceiverType "." MethodName .
|
||||
ReceiverType = TypeName | "(" "*" TypeName ")" | "(" ReceiverType ")" .
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Consider a struct type <code>T</code> with two methods,
|
||||
<code>Mv</code>, whose receiver is of type <code>T</code>, and
|
||||
<code>Mp</code>, whose receiver is of type <code>*T</code>.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type T struct {
|
||||
a int
|
||||
}
|
||||
func (tv T) Mv(a int) int { return 0 } // value receiver
|
||||
func (tp *T) Mp(f float32) float32 { return 1 } // pointer receiver
|
||||
|
||||
var t T
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The expression
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
T.Mv
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
yields a function equivalent to <code>Mv</code> but
|
||||
with an explicit receiver as its first argument; it has signature
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func(tv T, a int) int
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
That function may be called normally with an explicit receiver, so
|
||||
these five invocations are equivalent:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
t.Mv(7)
|
||||
T.Mv(t, 7)
|
||||
(T).Mv(t, 7)
|
||||
f1 := T.Mv; f1(t, 7)
|
||||
f2 := (T).Mv; f2(t, 7)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Similarly, the expression
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
(*T).Mp
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
yields a function value representing <code>Mp</code> with signature
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func(tp *T, f float32) float32
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
For a method with a value receiver, one can derive a function
|
||||
with an explicit pointer receiver, so
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
(*T).Mv
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
yields a function value representing <code>Mv</code> with signature
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func(tv *T, a int) int
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Such a function indirects through the receiver to create a value
|
||||
to pass as the receiver to the underlying method;
|
||||
the method does not overwrite the value whose address is passed in
|
||||
the function call.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The final case, a value-receiver function for a pointer-receiver method,
|
||||
is illegal because pointer-receiver methods are not in the method set
|
||||
of the value type.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Function values derived from methods are called with function call syntax;
|
||||
the receiver is provided as the first argument to the call.
|
||||
That is, given <code>f := T.Mv</code>, <code>f</code> is invoked
|
||||
as <code>f(t, 7)</code> not <code>t.f(7)</code>.
|
||||
To construct a function that binds the receiver, use a
|
||||
<a href="#Function_literals">function literal</a> or
|
||||
<a href="#Method_values">method value</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
It is legal to derive a function value from a method of an interface type.
|
||||
The resulting function takes an explicit receiver of that interface type.
|
||||
</p>
|
||||
|
||||
<h3 id="Method_values">Method values</h3>
|
||||
|
||||
<p>
|
||||
If the expression <code>x</code> has static type <code>T</code> and
|
||||
<code>M</code> is in the <a href="#Method_sets">method set</a> of type <code>T</code>,
|
||||
<code>x.M</code> is called a <i>method value</i>.
|
||||
The method value <code>x.M</code> is a function value that is callable
|
||||
with the same arguments as a method call of <code>x.M</code>.
|
||||
The expression <code>x</code> is evaluated and saved during the evaluation of the
|
||||
method value; the saved copy is then used as the receiver in any calls,
|
||||
which may be executed later.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The type <code>T</code> may be an interface or non-interface type.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
As in the discussion of <a href="#Method_expressions">method expressions</a> above,
|
||||
consider a struct type <code>T</code> with two methods,
|
||||
<code>Mv</code>, whose receiver is of type <code>T</code>, and
|
||||
<code>Mp</code>, whose receiver is of type <code>*T</code>.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type T struct {
|
||||
a int
|
||||
}
|
||||
func (tv T) Mv(a int) int { return 0 } // value receiver
|
||||
func (tp *T) Mp(f float32) float32 { return 1 } // pointer receiver
|
||||
|
||||
var t T
|
||||
var pt *T
|
||||
func makeT() T
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The expression
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
t.Mv
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
yields a function value of type
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func(int) int
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
These two invocations are equivalent:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
t.Mv(7)
|
||||
f := t.Mv; f(7)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Similarly, the expression
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
pt.Mp
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
yields a function value of type
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func(float32) float32
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
As with <a href="#Selectors">selectors</a>, a reference to a non-interface method with a value receiver
|
||||
using a pointer will automatically dereference that pointer: <code>pt.Mv</code> is equivalent to <code>(*pt).Mv</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
As with <a href="#Calls">method calls</a>, a reference to a non-interface method with a pointer receiver
|
||||
using an addressable value will automatically take the address of that value: <code>t.Mp</code> is equivalent to <code>(&t).Mp</code>.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
f := t.Mv; f(7) // like t.Mv(7)
|
||||
f := pt.Mp; f(7) // like pt.Mp(7)
|
||||
f := pt.Mv; f(7) // like (*pt).Mv(7)
|
||||
f := t.Mp; f(7) // like (&t).Mp(7)
|
||||
f := makeT().Mp // invalid: result of makeT() is not addressable
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Although the examples above use non-interface types, it is also legal to create a method value
|
||||
from a value of interface type.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var i interface { M(int) } = myVal
|
||||
f := i.M; f(7) // like i.M(7)
|
||||
</pre>
|
||||
|
||||
|
||||
<h3 id="Index_expressions">Index expressions</h3>
|
||||
|
||||
<p>
|
||||
|
|
@ -3371,7 +3598,7 @@ or an array indexing operation of an addressable array.
|
|||
As an exception to the addressability requirement, <code>x</code> may also be a
|
||||
(possibly parenthesized)
|
||||
<a href="#Composite_literals">composite literal</a>.
|
||||
If the evaluation of <code>x</code> would cause a <a href="#Run_time_panics">run-time panic</a>,
|
||||
If the evaluation of <code>x</code> would cause a <a href="#Run_time_panics">run-time panic</a>,
|
||||
then the evaluation of <code>&x</code> does too.
|
||||
</p>
|
||||
|
||||
|
|
@ -3436,232 +3663,6 @@ channel is closed and empty.
|
|||
</p>
|
||||
|
||||
|
||||
<h3 id="Method_expressions">Method expressions</h3>
|
||||
|
||||
<p>
|
||||
If <code>M</code> is in the <a href="#Method_sets">method set</a> of type <code>T</code>,
|
||||
<code>T.M</code> is a function that is callable as a regular function
|
||||
with the same arguments as <code>M</code> prefixed by an additional
|
||||
argument that is the receiver of the method.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
MethodExpr = ReceiverType "." MethodName .
|
||||
ReceiverType = TypeName | "(" "*" TypeName ")" | "(" ReceiverType ")" .
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Consider a struct type <code>T</code> with two methods,
|
||||
<code>Mv</code>, whose receiver is of type <code>T</code>, and
|
||||
<code>Mp</code>, whose receiver is of type <code>*T</code>.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type T struct {
|
||||
a int
|
||||
}
|
||||
func (tv T) Mv(a int) int { return 0 } // value receiver
|
||||
func (tp *T) Mp(f float32) float32 { return 1 } // pointer receiver
|
||||
|
||||
var t T
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The expression
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
T.Mv
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
yields a function equivalent to <code>Mv</code> but
|
||||
with an explicit receiver as its first argument; it has signature
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func(tv T, a int) int
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
That function may be called normally with an explicit receiver, so
|
||||
these five invocations are equivalent:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
t.Mv(7)
|
||||
T.Mv(t, 7)
|
||||
(T).Mv(t, 7)
|
||||
f1 := T.Mv; f1(t, 7)
|
||||
f2 := (T).Mv; f2(t, 7)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Similarly, the expression
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
(*T).Mp
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
yields a function value representing <code>Mp</code> with signature
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func(tp *T, f float32) float32
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
For a method with a value receiver, one can derive a function
|
||||
with an explicit pointer receiver, so
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
(*T).Mv
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
yields a function value representing <code>Mv</code> with signature
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func(tv *T, a int) int
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Such a function indirects through the receiver to create a value
|
||||
to pass as the receiver to the underlying method;
|
||||
the method does not overwrite the value whose address is passed in
|
||||
the function call.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The final case, a value-receiver function for a pointer-receiver method,
|
||||
is illegal because pointer-receiver methods are not in the method set
|
||||
of the value type.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Function values derived from methods are called with function call syntax;
|
||||
the receiver is provided as the first argument to the call.
|
||||
That is, given <code>f := T.Mv</code>, <code>f</code> is invoked
|
||||
as <code>f(t, 7)</code> not <code>t.f(7)</code>.
|
||||
To construct a function that binds the receiver, use a
|
||||
<a href="#Function_literals">function literal</a> or
|
||||
<a href="#Method_values">method value</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
It is legal to derive a function value from a method of an interface type.
|
||||
The resulting function takes an explicit receiver of that interface type.
|
||||
</p>
|
||||
|
||||
<h3 id="Method_values">Method values</h3>
|
||||
|
||||
<p>
|
||||
If the expression <code>x</code> has static type <code>T</code> and
|
||||
<code>M</code> is in the <a href="#Method_sets">method set</a> of type <code>T</code>,
|
||||
<code>x.M</code> is called a <i>method value</i>.
|
||||
The method value <code>x.M</code> is a function value that is callable
|
||||
with the same arguments as a method call of <code>x.M</code>.
|
||||
The expression <code>x</code> is evaluated and saved during the evaluation of the
|
||||
method value; the saved copy is then used as the receiver in any calls,
|
||||
which may be executed later.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The type <code>T</code> may be an interface or non-interface type.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
As in the discussion of <a href="#Method_expressions">method expressions</a> above,
|
||||
consider a struct type <code>T</code> with two methods,
|
||||
<code>Mv</code>, whose receiver is of type <code>T</code>, and
|
||||
<code>Mp</code>, whose receiver is of type <code>*T</code>.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type T struct {
|
||||
a int
|
||||
}
|
||||
func (tv T) Mv(a int) int { return 0 } // value receiver
|
||||
func (tp *T) Mp(f float32) float32 { return 1 } // pointer receiver
|
||||
|
||||
var t T
|
||||
var pt *T
|
||||
func makeT() T
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The expression
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
t.Mv
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
yields a function value of type
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func(int) int
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
These two invocations are equivalent:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
t.Mv(7)
|
||||
f := t.Mv; f(7)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Similarly, the expression
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
pt.Mp
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
yields a function value of type
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func(float32) float32
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
As with <a href="#Selectors">selectors</a>, a reference to a non-interface method with a value receiver
|
||||
using a pointer will automatically dereference that pointer: <code>pt.Mv</code> is equivalent to <code>(*pt).Mv</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
As with <a href="#Calls">method calls</a>, a reference to a non-interface method with a pointer receiver
|
||||
using an addressable value will automatically take the address of that value: <code>t.Mp</code> is equivalent to <code>(&t).Mp</code>.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
f := t.Mv; f(7) // like t.Mv(7)
|
||||
f := pt.Mp; f(7) // like pt.Mp(7)
|
||||
f := pt.Mv; f(7) // like (*pt).Mv(7)
|
||||
f := t.Mp; f(7) // like (&t).Mp(7)
|
||||
f := makeT().Mp // invalid: result of makeT() is not addressable
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Although the examples above use non-interface types, it is also legal to create a method value
|
||||
from a value of interface type.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var i interface { M(int) } = myVal
|
||||
f := i.M; f(7) // like i.M(7)
|
||||
</pre>
|
||||
|
||||
<h3 id="Conversions">Conversions</h3>
|
||||
|
||||
<p>
|
||||
|
|
@ -4051,7 +4052,7 @@ n := map[int]int{a: f()} // n may be {2: 3} or {3: 3}: evaluation order bet
|
|||
<p>
|
||||
At package level, initialization dependencies override the left-to-right rule
|
||||
for individual initialization expressions, but not for operands within each
|
||||
expression:
|
||||
expression:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
|
|
@ -5941,7 +5942,7 @@ variable or function.
|
|||
<li>
|
||||
A reference to a method <code>m</code> is a
|
||||
<a href="#Method_values">method value</a> or
|
||||
<a href="#Method_expressions">method expression</a> of the form
|
||||
<a href="#Method_expressions">method expression</a> of the form
|
||||
<code>t.m</code>, where the (static) type of <code>t</code> is
|
||||
not an interface type, and the method <code>m</code> is in the
|
||||
<a href="#Method_sets">method set</a> of <code>t</code>.
|
||||
|
|
@ -5950,7 +5951,7 @@ It is immaterial whether the resulting function value
|
|||
</li>
|
||||
|
||||
<li>
|
||||
A variable, function, or method <code>x</code> depends on a variable
|
||||
A variable, function, or method <code>x</code> depends on a variable
|
||||
<code>y</code> if <code>x</code>'s initialization expression or body
|
||||
(for functions and methods) contains a reference to <code>y</code>
|
||||
or to a function or method that depends on <code>y</code>.
|
||||
|
|
@ -6002,7 +6003,7 @@ func init() { … }
|
|||
</pre>
|
||||
|
||||
<p>
|
||||
Multiple such functions may be defined, even within a single
|
||||
Multiple such functions may be defined, even within a single
|
||||
source file. The <code>init</code> identifier is not
|
||||
<a href="#Declarations_and_scope">declared</a> and thus
|
||||
<code>init</code> functions cannot be referred to from anywhere
|
||||
|
|
|
|||
|
|
@ -127,6 +127,7 @@ struct LSym
|
|||
short type;
|
||||
short version;
|
||||
uchar dupok;
|
||||
uchar cfunc;
|
||||
uchar external;
|
||||
uchar nosplit;
|
||||
uchar reachable;
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
defaultcc: golang-codereviews@googlegroups.com
|
||||
contributors: http://go.googlecode.com/hg/CONTRIBUTORS
|
||||
|
|
|
|||
|
|
@ -3603,11 +3603,17 @@ class MercurialVCS(VersionControlSystem):
|
|||
if use_hg_shell:
|
||||
base_content = RunShell(["hg", "cat", "-r", base_rev, oldrelpath], silent_ok=True)
|
||||
else:
|
||||
base_content = str(self.repo[base_rev][oldrelpath].data())
|
||||
try:
|
||||
base_content = str(self.repo[base_rev][oldrelpath].data())
|
||||
except Exception:
|
||||
pass
|
||||
is_binary = "\0" in base_content # Mercurial's heuristic
|
||||
if status != "R":
|
||||
new_content = open(relpath, "rb").read()
|
||||
is_binary = is_binary or "\0" in new_content
|
||||
try:
|
||||
new_content = open(relpath, "rb").read()
|
||||
is_binary = is_binary or "\0" in new_content
|
||||
except Exception:
|
||||
pass
|
||||
if is_binary and base_content and use_hg_shell:
|
||||
# Fetch again without converting newlines
|
||||
base_content = RunShell(["hg", "cat", "-r", base_rev, oldrelpath],
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
/*
|
||||
void foo() {}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func main() {
|
||||
C.foo = C.foo // ERROR HERE
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
// Issue 8442. Cgo output unhelpful error messages for
|
||||
// invalid C preambles.
|
||||
|
||||
/*
|
||||
void issue8442foo(UNDEF*); // ERROR HERE
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func main() {
|
||||
C.issue8442foo(nil)
|
||||
}
|
||||
|
|
@ -27,6 +27,8 @@ check() {
|
|||
check err1.go
|
||||
check err2.go
|
||||
check err3.go
|
||||
check issue7757.go
|
||||
check issue8442.go
|
||||
|
||||
rm -rf errs _obj
|
||||
exit 0
|
||||
|
|
|
|||
|
|
@ -10,20 +10,6 @@
|
|||
|
||||
typedef char bool;
|
||||
|
||||
bool runtime·lockedOSThread(void);
|
||||
|
||||
static void
|
||||
FLUSH(void*)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
·LockedOSThread(bool b)
|
||||
{
|
||||
b = runtime·lockedOSThread();
|
||||
FLUSH(&b);
|
||||
}
|
||||
|
||||
// This is what a cgo-compiled stub declaration looks like.
|
||||
void
|
||||
·Issue7695(struct{void *y[8*sizeof(void*)];}p)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Assembly to get into package runtime without using exported symbols.
|
||||
|
||||
// +build amd64 amd64p32 arm 386
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
#ifdef GOARCH_arm
|
||||
#define JMP B
|
||||
#endif
|
||||
|
||||
TEXT ·LockedOSThread(SB),NOSPLIT,$0-0
|
||||
JMP runtime·lockedOSThread(SB)
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cgotest
|
||||
|
||||
// Test that we have no more than one build ID. In the past we used
|
||||
// to generate a separate build ID for each package using cgo, and the
|
||||
// linker concatenated them all. We don't want that--we only want
|
||||
// one.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"debug/elf"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func testBuildID(t *testing.T) {
|
||||
f, err := elf.Open("/proc/self/exe")
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
t.Skip("no /proc/self/exe")
|
||||
}
|
||||
t.Fatalf("opening /proc/self/exe: ", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
c := 0
|
||||
for i, s := range f.Sections {
|
||||
if s.Type != elf.SHT_NOTE {
|
||||
continue
|
||||
}
|
||||
|
||||
d, err := s.Data()
|
||||
if err != nil {
|
||||
t.Logf("reading data of note section %d: %v", i, err)
|
||||
continue
|
||||
}
|
||||
|
||||
for len(d) > 0 {
|
||||
|
||||
// ELF standards differ as to the sizes in
|
||||
// note sections. Both the GNU linker and
|
||||
// gold always generate 32-bit sizes, so that
|
||||
// is what we assume here.
|
||||
|
||||
if len(d) < 12 {
|
||||
t.Logf("note section %d too short (%d < 12)", i, len(d))
|
||||
continue
|
||||
}
|
||||
|
||||
namesz := f.ByteOrder.Uint32(d)
|
||||
descsz := f.ByteOrder.Uint32(d[4:])
|
||||
typ := f.ByteOrder.Uint32(d[8:])
|
||||
|
||||
an := (namesz + 3) &^ 3
|
||||
ad := (descsz + 3) &^ 3
|
||||
|
||||
if int(12+an+ad) > len(d) {
|
||||
t.Logf("note section %d too short for header (%d < 12 + align(%d,4) + align(%d,4))", i, len(d), namesz, descsz)
|
||||
continue
|
||||
}
|
||||
|
||||
// 3 == NT_GNU_BUILD_ID
|
||||
if typ == 3 && namesz == 4 && bytes.Equal(d[12:16], []byte("GNU\000")) {
|
||||
c++
|
||||
}
|
||||
|
||||
d = d[12+an+ad:]
|
||||
}
|
||||
}
|
||||
|
||||
if c > 1 {
|
||||
t.Errorf("found %d build ID notes", c)
|
||||
}
|
||||
}
|
||||
|
|
@ -13,12 +13,13 @@ void callPanic(void);
|
|||
import "C"
|
||||
|
||||
import (
|
||||
"./backdoor"
|
||||
"path"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"unsafe"
|
||||
|
||||
"./backdoor"
|
||||
)
|
||||
|
||||
// nestedCall calls into C, back into Go, and finally to f.
|
||||
|
|
@ -152,11 +153,13 @@ func testCallbackCallers(t *testing.T) {
|
|||
n := 0
|
||||
name := []string{
|
||||
"test.goCallback",
|
||||
"runtime.call16",
|
||||
"runtime.cgocallbackg1",
|
||||
"runtime.cgocallbackg",
|
||||
"runtime.cgocallback_gofunc",
|
||||
"runtime.asmcgocall",
|
||||
"runtime.cgocall",
|
||||
"asmcgocall",
|
||||
"runtime.asmcgocall_errno",
|
||||
"runtime.cgocall_errno",
|
||||
"test._Cfunc_callback",
|
||||
"test.nestedCall",
|
||||
"test.testCallbackCallers",
|
||||
|
|
@ -181,8 +184,12 @@ func testCallbackCallers(t *testing.T) {
|
|||
if strings.HasPrefix(fname, "_") {
|
||||
fname = path.Base(f.Name()[1:])
|
||||
}
|
||||
if fname != name[i] {
|
||||
t.Errorf("expected function name %s, got %s", name[i], fname)
|
||||
namei := ""
|
||||
if i < len(name) {
|
||||
namei = name[i]
|
||||
}
|
||||
if fname != namei {
|
||||
t.Errorf("stk[%d] = %q, want %q", i, fname, namei)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,5 +6,6 @@ package cgotest
|
|||
|
||||
import "testing"
|
||||
|
||||
func TestSetgid(t *testing.T) { testSetgid(t) }
|
||||
func Test6997(t *testing.T) { test6997(t) }
|
||||
func TestSetgid(t *testing.T) { testSetgid(t) }
|
||||
func Test6997(t *testing.T) { test6997(t) }
|
||||
func TestBuildID(t *testing.T) { testBuildID(t) }
|
||||
|
|
|
|||
|
|
@ -53,5 +53,7 @@ func Test5986(t *testing.T) { test5986(t) }
|
|||
func Test7665(t *testing.T) { test7665(t) }
|
||||
func TestNaming(t *testing.T) { testNaming(t) }
|
||||
func Test7560(t *testing.T) { test7560(t) }
|
||||
func Test5242(t *testing.T) { test5242(t) }
|
||||
func Test8092(t *testing.T) { test8092(t) }
|
||||
|
||||
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Issue 5242. Cgo incorrectly computed the alignment of structs
|
||||
// with no Go accessible fields as 0, and then panicked on
|
||||
// modulo-by-zero computations.
|
||||
|
||||
package cgotest
|
||||
|
||||
/*
|
||||
typedef struct {
|
||||
} foo;
|
||||
|
||||
typedef struct {
|
||||
int x : 1;
|
||||
} bar;
|
||||
|
||||
int issue5242(foo f, bar b) {
|
||||
return 5242;
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import "testing"
|
||||
|
||||
func test5242(t *testing.T) {
|
||||
if got := C.issue5242(C.foo{}, C.bar{}); got != 5242 {
|
||||
t.Errorf("got %v", got)
|
||||
}
|
||||
}
|
||||
|
|
@ -14,13 +14,14 @@ import "C"
|
|||
//export issue5548FromC
|
||||
func issue5548FromC(s string, i int) int {
|
||||
if len(s) == 4 && s == "test" && i == 42 {
|
||||
return 1
|
||||
return 12345
|
||||
}
|
||||
return 0
|
||||
println("got", len(s), i)
|
||||
return 9876
|
||||
}
|
||||
|
||||
func test5548(t *testing.T) {
|
||||
if C.issue5548_in_c() == 0 {
|
||||
t.Fail()
|
||||
if x := C.issue5548_in_c(); x != 12345 {
|
||||
t.Errorf("issue5548_in_c = %d, want %d", x, 12345)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build ignore
|
||||
// This test depends on running C code on Go stacks. Not allowed anymore.
|
||||
|
||||
// Demo of deferred C function with untrue prototype
|
||||
// breaking stack copying. See golang.org/issue/7695.
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Issue 8092. Test that linker defined symbols (e.g., text, data) don't
|
||||
// conflict with C symbols.
|
||||
|
||||
package cgotest
|
||||
|
||||
/*
|
||||
char text[] = "text";
|
||||
char data[] = "data";
|
||||
char *ctext(void) { return text; }
|
||||
char *cdata(void) { return data; }
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import "testing"
|
||||
|
||||
func test8092(t *testing.T) {
|
||||
tests := []struct {
|
||||
s string
|
||||
a, b *C.char
|
||||
}{
|
||||
{"text", &C.text[0], C.ctext()},
|
||||
{"data", &C.data[0], C.cdata()},
|
||||
}
|
||||
for _, test := range tests {
|
||||
if test.a != test.b {
|
||||
t.Errorf("%s: pointer mismatch: %v != %v", test.s, test.a, test.b)
|
||||
}
|
||||
if got := C.GoString(test.a); got != test.s {
|
||||
t.Errorf("%s: points at %#v, want %#v", test.s, got, test.s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This test fails on older versions of OS X because they use older buggy
|
||||
// versions of Clang that emit ambiguous DWARF info. See issue 8611.
|
||||
// +build !darwin
|
||||
|
||||
package cgotest
|
||||
|
||||
// Issue 8428. Cgo inconsistently translated zero size arrays.
|
||||
|
||||
/*
|
||||
struct issue8428one {
|
||||
char b;
|
||||
char rest[];
|
||||
};
|
||||
|
||||
struct issue8428two {
|
||||
void *p;
|
||||
char b;
|
||||
char rest[0];
|
||||
};
|
||||
|
||||
struct issue8428three {
|
||||
char w[1][2][3][0];
|
||||
char x[2][3][0][1];
|
||||
char y[3][0][1][2];
|
||||
char z[0][1][2][3];
|
||||
};
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import "unsafe"
|
||||
|
||||
var _ = C.struct_issue8428one{
|
||||
b: C.char(0),
|
||||
rest: [0]C.char{},
|
||||
}
|
||||
|
||||
var _ = C.struct_issue8428two{
|
||||
p: unsafe.Pointer(nil),
|
||||
b: C.char(0),
|
||||
rest: [0]C.char{},
|
||||
}
|
||||
|
||||
var _ = C.struct_issue8428three{
|
||||
w: [1][2][3][0]C.char{},
|
||||
x: [2][3][0][1]C.char{},
|
||||
y: [3][0][1][2]C.char{},
|
||||
z: [0][1][2][3]C.char{},
|
||||
}
|
||||
|
|
@ -56,4 +56,5 @@ typedef struct timespec {
|
|||
import "C"
|
||||
|
||||
type CdefsTest C.struct_cdefsTest
|
||||
type PackedTest C.struct_packedTest
|
||||
|
||||
//type PackedTest C.struct_packedTest
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ struct CdefsOrig {
|
|||
int8 **array5[20][20];
|
||||
};
|
||||
|
||||
// Packed structs are no longer supported for -cdefs.
|
||||
/*
|
||||
typedef struct PackedOrig PackedOrig;
|
||||
#pragma pack on
|
||||
struct PackedOrig {
|
||||
|
|
@ -25,14 +27,15 @@ struct PackedOrig {
|
|||
int64 third;
|
||||
};
|
||||
#pragma pack off
|
||||
*/
|
||||
|
||||
void
|
||||
main·test(int32 ret)
|
||||
{
|
||||
CdefsOrig o;
|
||||
CdefsTest t;
|
||||
PackedOrig po;
|
||||
PackedTest pt;
|
||||
// PackedOrig po;
|
||||
// PackedTest pt;
|
||||
|
||||
ret = 0;
|
||||
if(sizeof(t.array1) != sizeof(o.array1) || offsetof(CdefsTest, array1[0]) != offsetof(CdefsOrig, array1[0])) {
|
||||
|
|
@ -55,6 +58,7 @@ main·test(int32 ret)
|
|||
runtime·printf("array5: size, offset = %d, %d, want %d, %d\n", sizeof(t.array5), offsetof(CdefsTest, array5[0][0]), sizeof(o.array5), offsetof(CdefsOrig, array5[0][0]));
|
||||
ret = 1;
|
||||
}
|
||||
/*
|
||||
if(sizeof(pt.first) != sizeof(po.first) || offsetof(PackedTest, first) != offsetof(PackedOrig, first)) {
|
||||
runtime·printf("first: size, offset = %d, %d, want %d, %d\n", sizeof(pt.first), offsetof(PackedTest, first), sizeof(po.first), offsetof(PackedOrig, first));
|
||||
ret = 1;
|
||||
|
|
@ -67,5 +71,6 @@ main·test(int32 ret)
|
|||
runtime·printf("third: size, offset = %d, %d, want %d, %d\n", sizeof(pt.third), offsetof(PackedTest, third), sizeof(po.third), offsetof(PackedOrig, third));
|
||||
ret = 1;
|
||||
}
|
||||
*/
|
||||
FLUSH(&ret); // flush return value
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"code.google.com/p/goauth2/oauth"
|
||||
"code.google.com/p/google-api-go-client/storage/v1beta2"
|
||||
storage "code.google.com/p/google-api-go-client/storage/v1beta2"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -154,6 +154,7 @@ func main() {
|
|||
log.Fatalln("setupOAuthClient:", err)
|
||||
}
|
||||
}
|
||||
ok := true
|
||||
for _, targ := range flag.Args() {
|
||||
var b Build
|
||||
if m := fileRe.FindStringSubmatch(targ); m != nil {
|
||||
|
|
@ -205,8 +206,12 @@ func main() {
|
|||
}
|
||||
if err := b.Do(); err != nil {
|
||||
log.Printf("%s: %v", targ, err)
|
||||
ok = false
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
type Build struct {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
Native Client
|
||||
=============
|
||||
|
||||
This document outlines the basics of building and developing the Go runtime and programs in the Native Client (NaCl) environment.
|
||||
This document outlines the basics of building and developing the Go runtime and
|
||||
programs in the Native Client (NaCl) environment.
|
||||
|
||||
Go 1.3 supports three architectures
|
||||
|
||||
* nacl/386 which is standard 386.
|
||||
* nacl/amd64p32 which is a 64 bit architecture, where the address space is limited to a 4gb window.
|
||||
* nacl/amd64p32 which is a 64 bit architecture, where the address space is
|
||||
limited to a 4gb window.
|
||||
* nacl/arm which is 32-bit ARMv7A architecture with 1GB address space.
|
||||
|
||||
For background it is recommended that you read http://golang.org/s/go13nacl.
|
||||
|
|
@ -14,34 +16,48 @@ For background it is recommended that you read http://golang.org/s/go13nacl.
|
|||
Prerequisites
|
||||
-------------
|
||||
|
||||
Native Client programs are executed inside a sandbox, the NaCl runtime. This runtime must be installed before you can use NaCl programs.
|
||||
Native Client programs are executed inside a sandbox, the NaCl runtime. This
|
||||
runtime must be installed before you can use NaCl programs.
|
||||
|
||||
The NaCl distribution comes with an installer which ensures you have access to the latest version of the runtime. The version tracks the Chrome numbering scheme.
|
||||
The NaCl distribution comes with an installer which ensures you have access to
|
||||
the latest version of the runtime. The version tracks the Chrome numbering
|
||||
scheme.
|
||||
|
||||
# Download NaCl
|
||||
|
||||
Download nacl_sdk.zip file from https://developers.google.com/native-client/dev/sdk/download, and unpack it. I chose /opt/nacl_sdk
|
||||
Download nacl_sdk.zip file from
|
||||
https://developers.google.com/native-client/dev/sdk/download
|
||||
and unpack it. I chose /opt/nacl_sdk.
|
||||
|
||||
# Update
|
||||
|
||||
The zip file contains a small skeleton that can be used to download the correct sdk. These are released every 6-8 weeks, in line with Chrome releases.
|
||||
The zip file contains a small skeleton that can be used to download the correct
|
||||
sdk. These are released every 6-8 weeks, in line with Chrome releases.
|
||||
|
||||
% cd /opt/nacl_sdk
|
||||
% ./naclsdk update
|
||||
|
||||
At this time pepper_33 is the stable version. If naclsdk downloads a later version, please adjust accordingly. As of June 2014, only the canary sdk provides support for nacl/arm.
|
||||
At this time pepper_34 is the stable version. If naclsdk downloads a later
|
||||
version, please adjust accordingly. As of June 2014, only the canary sdk
|
||||
provides support for nacl/arm.
|
||||
|
||||
The cmd/go helper scripts expect that the runtime loaders, sel_ldr_{x86_{32,64},arm} and nacl_helper_bootstrap_arm are in your path. I find it easiest to make a symlink from the NaCl distribution to my $GOPATH/bin directory.
|
||||
The cmd/go helper scripts expect that the loaders sel_ldr_{x86_{32,64},arm} and
|
||||
nacl_helper_bootstrap_arm are in your path. I find it easiest to make a symlink
|
||||
from the NaCl distribution to my $GOPATH/bin directory.
|
||||
|
||||
% ln -nfs /opt/nacl_sdk/pepper_33/tools/sel_ldr_x86_32 $GOPATH/bin/sel_ldr_x86_32
|
||||
% ln -nfs /opt/nacl_sdk/pepper_33/tools/sel_ldr_x86_64 $GOPATH/bin/sel_ldr_x86_64
|
||||
% ln -nfs /opt/nacl_sdk/pepper_34/tools/sel_ldr_x86_32 $GOPATH/bin/sel_ldr_x86_32
|
||||
% ln -nfs /opt/nacl_sdk/pepper_34/tools/sel_ldr_x86_64 $GOPATH/bin/sel_ldr_x86_64
|
||||
% ln -nfs /opt/nacl_sdk/pepper_canary/tools/sel_ldr_arm $GOPATH/bin/sel_ldr_arm
|
||||
% ln -nfs /opt/nacl_sdk/pepper_canary/tools/nacl_helper_bootstrap_arm $GOPATH/bin/nacl_helper_bootstrap_arm # only required for NaCl/ARM.
|
||||
|
||||
Additionally, for NaCl/ARM only:
|
||||
|
||||
% ln -nfs /opt/nacl_sdk/pepper_canary/tools/nacl_helper_bootstrap_arm $GOPATH/bin/nacl_helper_bootstrap_arm
|
||||
|
||||
Support scripts
|
||||
---------------
|
||||
|
||||
Symlink the two scripts in this directory into your $PATH, just as you did with NaCl sdk above.
|
||||
Symlink the two scripts in this directory into your $PATH, just as you did with
|
||||
NaCl sdk above.
|
||||
|
||||
% ln -nfs $GOROOT/go/misc/nacl/go_nacl_amd64p32_exec $GOPATH/bin/go_nacl_amd64p32_exec
|
||||
% ln -nfs $GOROOT/go/misc/nacl/go_nacl_386_exec $GOPATH/bin/go_nacl_386_exec
|
||||
|
|
@ -50,18 +66,57 @@ Symlink the two scripts in this directory into your $PATH, just as you did with
|
|||
Building and testing
|
||||
--------------------
|
||||
|
||||
Building for NaCl is similar to cross compiling for other platforms. However, as it is not possible to ever build in a `native` NaCl environment, the cmd/go tool has been enhanced to allow the full build, all.bash, to be executed, rather than just the compile stage, make.bash.
|
||||
Building for NaCl is similar to cross compiling for other platforms. However,
|
||||
as it is not possible to ever build in a `native` NaCl environment, the cmd/go
|
||||
tool has been enhanced to allow the full build, all.bash, to be executed,
|
||||
rather than just the compile stage, make.bash.
|
||||
|
||||
The cmd/go tool knows that if GOOS is set to `nacl` it should not try to execute any binaries itself. Instead it passes their execution to a support script which sets up a Native Client environment and invokes the NaCl sandbox.
|
||||
The cmd/go tool knows that if GOOS is set to `nacl` it should not try to
|
||||
execute any binaries itself. Instead it passes their execution to a support
|
||||
script which sets up a Native Client environment and invokes the NaCl sandbox.
|
||||
|
||||
The script's name has a special format, go_$GOOS_$GOARCH_exec, so cmd/go can find it.
|
||||
The script's name has a special format, go_$GOOS_$GOARCH_exec, so cmd/go can
|
||||
find it.
|
||||
|
||||
In short, if the support scripts are in place, the cmd/go tool can be used as per normal.
|
||||
In short, if the support scripts are in place, the cmd/go tool can be used as
|
||||
per normal.
|
||||
|
||||
# Build and test Go for NaCl
|
||||
|
||||
NaCl does not permit direct file system access. Instead, package syscall provides a simulated file system served by in-memory data. The script nacltest.bash is the NaCl equivalent of all.bash. It builds NaCl with an in-memory file system containing files needed for tests, and then it runs the tests.
|
||||
NaCl does not permit direct file system access. Instead, package syscall
|
||||
provides a simulated file system served by in-memory data. The script
|
||||
nacltest.bash is the NaCl equivalent of all.bash. It builds NaCl with an
|
||||
in-memory file system containing files needed for tests, and then it runs the
|
||||
tests.
|
||||
|
||||
% cd go/src
|
||||
% env GOARCH=amd64p32 ./nacltest.bash
|
||||
|
||||
Debugging
|
||||
---------
|
||||
|
||||
Assuming that you have built nacl/amd64p32 binary ./mybin and can run as:
|
||||
|
||||
% sel_ldr_x86_64 -l /dev/null -S -e ./mybin
|
||||
|
||||
Create the nacl manifest file mybin.manifest with the following contents:
|
||||
|
||||
{ "program": { "x86-64": { "url": "mybin" } } }
|
||||
|
||||
url is the path to the binary relative to the manifest file.
|
||||
Then, run the program as:
|
||||
|
||||
% sel_ldr_x86_64 -g -l /dev/null -S -e ./mybin
|
||||
|
||||
The -g flag instructs the loader to stop at startup. Then, in another console:
|
||||
|
||||
% /opt/nacl_sdk/pepper_34/toolchain/linux_x86_glibc/bin/x86_64-nacl-gdb
|
||||
% nacl-manifest mybin.manifest
|
||||
% target remote :4014
|
||||
|
||||
If you see that the program is stopped in _rt0_amd64p32_nacl, then symbols are
|
||||
loaded successfully and you can type 'c' to start the program.
|
||||
Next time you can automate it as:
|
||||
|
||||
% /opt/nacl_sdk/pepper_34/toolchain/linux_x86_glibc/bin/x86_64-nacl-gdb \
|
||||
-ex 'nacl-manifest mybin.manifest' -ex 'target remote :4014'
|
||||
|
|
|
|||
|
|
@ -10,7 +10,12 @@ usr src=../misc/nacl/testdata
|
|||
go src=..
|
||||
src
|
||||
cmd
|
||||
internal
|
||||
objfile
|
||||
objfile.go
|
||||
gofmt
|
||||
gofmt.go
|
||||
gofmt_test.go
|
||||
testdata
|
||||
+
|
||||
link
|
||||
|
|
|
|||
|
|
@ -47,7 +47,9 @@ ln -s $GOROOT/src/cmd $FAKE_GOROOT/src/cmd
|
|||
ln -s $GOROOT/src/pkg $FAKE_GOROOT/src/pkg
|
||||
ln -s $GOROOT/test $FAKE_GOROOT/test
|
||||
ln -s $GOROOT/lib $FAKE_GOROOT/lib
|
||||
adb sync data
|
||||
echo '# Syncing test files to android device'
|
||||
time adb sync data &> /dev/null
|
||||
echo ''
|
||||
rm -rf "$ANDROID_PRODUCT_OUT"
|
||||
|
||||
# Run standard build and tests.
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ _cgen(Node *n, Node *nn, int inrel)
|
|||
}
|
||||
if(n == Z || n->type == T)
|
||||
return;
|
||||
if(typesuv[n->type->etype]) {
|
||||
if(typesuv[n->type->etype] && (n->op != OFUNC || nn != Z)) {
|
||||
sugen(n, nn, n->type->width);
|
||||
return;
|
||||
}
|
||||
|
|
@ -75,7 +75,7 @@ _cgen(Node *n, Node *nn, int inrel)
|
|||
if(r != Z && r->complex >= FNX)
|
||||
switch(o) {
|
||||
default:
|
||||
regret(&nod, r);
|
||||
regret(&nod, r, 0, 0);
|
||||
cgen(r, &nod);
|
||||
|
||||
regsalloc(&nod1, r);
|
||||
|
|
@ -107,7 +107,7 @@ _cgen(Node *n, Node *nn, int inrel)
|
|||
if(l->addable >= INDEXED && l->complex < FNX) {
|
||||
if(nn != Z || r->addable < INDEXED) {
|
||||
if(r->complex >= FNX && nn == Z)
|
||||
regret(&nod, r);
|
||||
regret(&nod, r, 0, 0);
|
||||
else
|
||||
regalloc(&nod, r, nn);
|
||||
cgen(r, &nod);
|
||||
|
|
@ -348,7 +348,7 @@ _cgen(Node *n, Node *nn, int inrel)
|
|||
if(l->op != OIND)
|
||||
diag(n, "bad function call");
|
||||
|
||||
regret(&nod, l->left);
|
||||
regret(&nod, l->left, 0, 0);
|
||||
cgen(l->left, &nod);
|
||||
regsalloc(&nod1, l->left);
|
||||
gopcode(OAS, &nod, Z, &nod1);
|
||||
|
|
@ -377,11 +377,11 @@ _cgen(Node *n, Node *nn, int inrel)
|
|||
if(REGARG >= 0)
|
||||
if(o != reg[REGARG])
|
||||
reg[REGARG]--;
|
||||
if(nn != Z) {
|
||||
regret(&nod, n);
|
||||
gopcode(OAS, &nod, Z, nn);
|
||||
regret(&nod, n, l->type, 1);
|
||||
if(nn != Z)
|
||||
gmove(&nod, nn);
|
||||
if(nod.op == OREGISTER)
|
||||
regfree(&nod);
|
||||
}
|
||||
break;
|
||||
|
||||
case OIND:
|
||||
|
|
@ -823,7 +823,7 @@ boolgen(Node *n, int true, Node *nn)
|
|||
if(true)
|
||||
o = comrel[relindex(o)];
|
||||
if(l->complex >= FNX && r->complex >= FNX) {
|
||||
regret(&nod, r);
|
||||
regret(&nod, r, 0, 0);
|
||||
cgenrel(r, &nod);
|
||||
regsalloc(&nod1, r);
|
||||
gopcode(OAS, &nod, Z, &nod1);
|
||||
|
|
@ -957,7 +957,7 @@ sugen(Node *n, Node *nn, int32 w)
|
|||
if(nn != Z && side(nn)) {
|
||||
nod1 = *n;
|
||||
nod1.type = typ(TIND, n->type);
|
||||
regret(&nod2, &nod1);
|
||||
regret(&nod2, &nod1, 0, 0);
|
||||
lcgen(nn, &nod2);
|
||||
regsalloc(&nod0, &nod1);
|
||||
gopcode(OAS, &nod2, Z, &nod0);
|
||||
|
|
@ -1036,6 +1036,20 @@ sugen(Node *n, Node *nn, int32 w)
|
|||
break;
|
||||
|
||||
case OFUNC:
|
||||
if(!hasdotdotdot(n->left->type)) {
|
||||
cgen(n, Z);
|
||||
if(nn != Z) {
|
||||
curarg -= n->type->width;
|
||||
regret(&nod1, n, n->left->type, 1);
|
||||
if(nn->complex >= FNX) {
|
||||
regsalloc(&nod2, n);
|
||||
cgen(&nod1, &nod2);
|
||||
nod1 = nod2;
|
||||
}
|
||||
cgen(&nod1, nn);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(nn == Z) {
|
||||
sugen(n, nodrat, w);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ void usedset(Node*, int);
|
|||
void xcom(Node*);
|
||||
int bcomplex(Node*, Node*);
|
||||
Prog* gtext(Sym*, int32);
|
||||
vlong argsize(void);
|
||||
vlong argsize(int);
|
||||
|
||||
/*
|
||||
* cgen.c
|
||||
|
|
@ -236,7 +236,7 @@ Node* nodconst(int32);
|
|||
Node* nod32const(vlong);
|
||||
Node* nodfconst(double);
|
||||
void nodreg(Node*, Node*, int);
|
||||
void regret(Node*, Node*);
|
||||
void regret(Node*, Node*, Type*, int);
|
||||
int tmpreg(void);
|
||||
void regalloc(Node*, Node*, Node*);
|
||||
void regfree(Node*);
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ gtext(Sym *s, int32 stkoff)
|
|||
{
|
||||
int32 a;
|
||||
|
||||
a = argsize();
|
||||
a = argsize(1);
|
||||
if((textflag & NOSPLIT) != 0 && stkoff >= 128)
|
||||
yyerror("stack frame too large for NOSPLIT function");
|
||||
|
||||
|
|
|
|||
|
|
@ -374,10 +374,11 @@ align(int32 i, Type *t, int op, int32 *maxalign)
|
|||
{
|
||||
int32 o;
|
||||
Type *v;
|
||||
int w;
|
||||
int w, packw;
|
||||
|
||||
o = i;
|
||||
w = 1;
|
||||
packw = 0;
|
||||
switch(op) {
|
||||
default:
|
||||
diag(Z, "unknown align opcode %d", op);
|
||||
|
|
@ -388,7 +389,7 @@ align(int32 i, Type *t, int op, int32 *maxalign)
|
|||
if(w < 1)
|
||||
w = 1;
|
||||
if(packflg)
|
||||
w = packflg;
|
||||
packw = packflg;
|
||||
break;
|
||||
|
||||
case Ael1: /* initial align of struct element */
|
||||
|
|
@ -404,7 +405,7 @@ align(int32 i, Type *t, int op, int32 *maxalign)
|
|||
if(w < 1 || w > SZ_LONG)
|
||||
fatal(Z, "align");
|
||||
if(packflg)
|
||||
w = packflg;
|
||||
packw = packflg;
|
||||
break;
|
||||
|
||||
case Ael2: /* width of a struct element */
|
||||
|
|
@ -440,6 +441,8 @@ align(int32 i, Type *t, int op, int32 *maxalign)
|
|||
w = SZ_LONG; /* because of a pun in cc/dcl.c:contig() */
|
||||
break;
|
||||
}
|
||||
if(packw != 0 && xround(o, w) != xround(o, packw))
|
||||
diag(Z, "#pragma pack changes offset of %T", t);
|
||||
o = xround(o, w);
|
||||
if(maxalign != nil && *maxalign < w)
|
||||
*maxalign = w;
|
||||
|
|
|
|||
|
|
@ -274,15 +274,43 @@ nodreg(Node *n, Node *nn, int reg)
|
|||
}
|
||||
|
||||
void
|
||||
regret(Node *n, Node *nn)
|
||||
regret(Node *n, Node *nn, Type *t, int mode)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = REGRET;
|
||||
if(typefd[nn->type->etype])
|
||||
r = FREGRET+NREG;
|
||||
nodreg(n, nn, r);
|
||||
reg[r]++;
|
||||
if(mode == 0 || hasdotdotdot(t) || nn->type->width == 0) {
|
||||
r = REGRET;
|
||||
if(typefd[nn->type->etype])
|
||||
r = FREGRET+NREG;
|
||||
nodreg(n, nn, r);
|
||||
reg[r]++;
|
||||
return;
|
||||
}
|
||||
|
||||
if(mode == 1) {
|
||||
// fetch returned value after call.
|
||||
// already called gargs, so curarg is set.
|
||||
curarg = (curarg+3) & ~3;
|
||||
regaalloc(n, nn);
|
||||
return;
|
||||
}
|
||||
|
||||
if(mode == 2) {
|
||||
// store value to be returned.
|
||||
// must compute arg offset.
|
||||
if(t->etype != TFUNC)
|
||||
fatal(Z, "bad regret func %T", t);
|
||||
*n = *nn;
|
||||
n->op = ONAME;
|
||||
n->class = CPARAM;
|
||||
n->sym = slookup(".ret");
|
||||
n->complex = nodret->complex;
|
||||
n->xoffset = argsize(0);
|
||||
n->addable = 20;
|
||||
return;
|
||||
}
|
||||
|
||||
fatal(Z, "bad regret");
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
|||
|
|
@ -254,7 +254,6 @@ cgen(Node *n, Node *res)
|
|||
case OOR:
|
||||
case OXOR:
|
||||
case OADD:
|
||||
case OADDPTR:
|
||||
case OMUL:
|
||||
a = optoas(n->op, nl->type);
|
||||
goto sbop;
|
||||
|
|
@ -1635,7 +1634,10 @@ int
|
|||
componentgen(Node *nr, Node *nl)
|
||||
{
|
||||
Node nodl, nodr, tmp;
|
||||
Type *t;
|
||||
int freel, freer;
|
||||
vlong fldcount;
|
||||
vlong loffset, roffset;
|
||||
|
||||
freel = 0;
|
||||
freer = 0;
|
||||
|
|
@ -1645,8 +1647,33 @@ componentgen(Node *nr, Node *nl)
|
|||
goto no;
|
||||
|
||||
case TARRAY:
|
||||
if(!isslice(nl->type))
|
||||
t = nl->type;
|
||||
|
||||
// Slices are ok.
|
||||
if(isslice(t))
|
||||
break;
|
||||
// Small arrays are ok.
|
||||
if(t->bound > 0 && t->bound <= 3 && !isfat(t->type))
|
||||
break;
|
||||
|
||||
goto no;
|
||||
|
||||
case TSTRUCT:
|
||||
// Small structs with non-fat types are ok.
|
||||
// Zero-sized structs are treated separately elsewhere.
|
||||
fldcount = 0;
|
||||
for(t=nl->type->type; t; t=t->down) {
|
||||
if(isfat(t->type))
|
||||
goto no;
|
||||
if(t->etype != TFIELD)
|
||||
fatal("componentgen: not a TFIELD: %lT", t);
|
||||
fldcount++;
|
||||
}
|
||||
if(fldcount == 0 || fldcount > 4)
|
||||
goto no;
|
||||
|
||||
break;
|
||||
|
||||
case TSTRING:
|
||||
case TINTER:
|
||||
break;
|
||||
|
|
@ -1674,6 +1701,7 @@ componentgen(Node *nr, Node *nl)
|
|||
freer = 1;
|
||||
}
|
||||
|
||||
|
||||
// nl and nr are 'cadable' which basically means they are names (variables) now.
|
||||
// If they are the same variable, don't generate any code, because the
|
||||
// VARDEF we generate will mark the old value as dead incorrectly.
|
||||
|
|
@ -1683,8 +1711,25 @@ componentgen(Node *nr, Node *nl)
|
|||
|
||||
switch(nl->type->etype) {
|
||||
case TARRAY:
|
||||
// componentgen for arrays.
|
||||
if(nl->op == ONAME)
|
||||
gvardef(nl);
|
||||
t = nl->type;
|
||||
if(!isslice(t)) {
|
||||
nodl.type = t->type;
|
||||
nodr.type = nodl.type;
|
||||
for(fldcount=0; fldcount < t->bound; fldcount++) {
|
||||
if(nr == N)
|
||||
clearslim(&nodl);
|
||||
else
|
||||
gmove(&nodr, &nodl);
|
||||
nodl.xoffset += t->type->width;
|
||||
nodr.xoffset += t->type->width;
|
||||
}
|
||||
goto yes;
|
||||
}
|
||||
|
||||
// componentgen for slices.
|
||||
nodl.xoffset += Array_array;
|
||||
nodl.type = ptrto(nl->type->type);
|
||||
|
||||
|
|
@ -1759,6 +1804,31 @@ componentgen(Node *nr, Node *nl)
|
|||
gmove(&nodr, &nodl);
|
||||
|
||||
goto yes;
|
||||
|
||||
case TSTRUCT:
|
||||
if(nl->op == ONAME)
|
||||
gvardef(nl);
|
||||
loffset = nodl.xoffset;
|
||||
roffset = nodr.xoffset;
|
||||
// funarg structs may not begin at offset zero.
|
||||
if(nl->type->etype == TSTRUCT && nl->type->funarg && nl->type->type)
|
||||
loffset -= nl->type->type->width;
|
||||
if(nr != N && nr->type->etype == TSTRUCT && nr->type->funarg && nr->type->type)
|
||||
roffset -= nr->type->type->width;
|
||||
|
||||
for(t=nl->type->type; t; t=t->down) {
|
||||
nodl.xoffset = loffset + t->width;
|
||||
nodl.type = t->type;
|
||||
|
||||
if(nr == N)
|
||||
clearslim(&nodl);
|
||||
else {
|
||||
nodr.xoffset = roffset + t->width;
|
||||
nodr.type = nodl.type;
|
||||
gmove(&nodr, &nodl);
|
||||
}
|
||||
}
|
||||
goto yes;
|
||||
}
|
||||
|
||||
no:
|
||||
|
|
|
|||
|
|
@ -1599,7 +1599,6 @@ optoas(int op, Type *t)
|
|||
case CASE(OADD, TINT32):
|
||||
case CASE(OADD, TUINT32):
|
||||
case CASE(OADD, TPTR32):
|
||||
case CASE(OADDPTR, TPTR32):
|
||||
a = AADD;
|
||||
break;
|
||||
|
||||
|
|
|
|||
|
|
@ -1315,6 +1315,7 @@ void
|
|||
addreg(Adr *a, int rn)
|
||||
{
|
||||
a->sym = nil;
|
||||
a->node = nil;
|
||||
a->name = D_NONE;
|
||||
a->type = D_REG;
|
||||
a->reg = rn;
|
||||
|
|
|
|||
|
|
@ -599,10 +599,10 @@ asmb(void)
|
|||
if(iself)
|
||||
goto ElfSym;
|
||||
case Hplan9:
|
||||
symo = HEADR+segtext.len+segdata.filelen;
|
||||
symo = segdata.fileoff+segdata.filelen;
|
||||
break;
|
||||
ElfSym:
|
||||
symo = rnd(HEADR+segtext.filelen, INITRND)+rnd(HEADR+segrodata.filelen, INITRND)+segdata.filelen;
|
||||
symo = segdata.fileoff+segdata.filelen;
|
||||
symo = rnd(symo, INITRND);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -435,49 +435,49 @@ struct
|
|||
"IRETQ", LTYPE0, AIRETQ,
|
||||
"IRETW", LTYPE0, AIRETW,
|
||||
|
||||
"JOS", LTYPER, AJOS,
|
||||
"JOS", LTYPER, AJOS, /* overflow set (OF = 1) */
|
||||
"JO", LTYPER, AJOS, /* alternate */
|
||||
"JOC", LTYPER, AJOC,
|
||||
"JOC", LTYPER, AJOC, /* overflow clear (OF = 0) */
|
||||
"JNO", LTYPER, AJOC, /* alternate */
|
||||
"JCS", LTYPER, AJCS,
|
||||
"JCS", LTYPER, AJCS, /* carry set (CF = 1) */
|
||||
"JB", LTYPER, AJCS, /* alternate */
|
||||
"JC", LTYPER, AJCS, /* alternate */
|
||||
"JNAE", LTYPER, AJCS, /* alternate */
|
||||
"JLO", LTYPER, AJCS, /* alternate */
|
||||
"JCC", LTYPER, AJCC,
|
||||
"JCC", LTYPER, AJCC, /* carry clear (CF = 0) */
|
||||
"JAE", LTYPER, AJCC, /* alternate */
|
||||
"JNB", LTYPER, AJCC, /* alternate */
|
||||
"JNC", LTYPER, AJCC, /* alternate */
|
||||
"JHS", LTYPER, AJCC, /* alternate */
|
||||
"JEQ", LTYPER, AJEQ,
|
||||
"JEQ", LTYPER, AJEQ, /* equal (ZF = 1) */
|
||||
"JE", LTYPER, AJEQ, /* alternate */
|
||||
"JZ", LTYPER, AJEQ, /* alternate */
|
||||
"JNE", LTYPER, AJNE,
|
||||
"JNE", LTYPER, AJNE, /* not equal (ZF = 0) */
|
||||
"JNZ", LTYPER, AJNE, /* alternate */
|
||||
"JLS", LTYPER, AJLS,
|
||||
"JLS", LTYPER, AJLS, /* lower or same (unsigned) (CF = 1 || ZF = 1) */
|
||||
"JBE", LTYPER, AJLS, /* alternate */
|
||||
"JNA", LTYPER, AJLS, /* alternate */
|
||||
"JHI", LTYPER, AJHI,
|
||||
"JHI", LTYPER, AJHI, /* higher (unsigned) (CF = 0 && ZF = 0) */
|
||||
"JA", LTYPER, AJHI, /* alternate */
|
||||
"JNBE", LTYPER, AJHI, /* alternate */
|
||||
"JMI", LTYPER, AJMI,
|
||||
"JMI", LTYPER, AJMI, /* negative (minus) (SF = 1) */
|
||||
"JS", LTYPER, AJMI, /* alternate */
|
||||
"JPL", LTYPER, AJPL,
|
||||
"JPL", LTYPER, AJPL, /* non-negative (plus) (SF = 0) */
|
||||
"JNS", LTYPER, AJPL, /* alternate */
|
||||
"JPS", LTYPER, AJPS,
|
||||
"JPS", LTYPER, AJPS, /* parity set (PF = 1) */
|
||||
"JP", LTYPER, AJPS, /* alternate */
|
||||
"JPE", LTYPER, AJPS, /* alternate */
|
||||
"JPC", LTYPER, AJPC,
|
||||
"JPC", LTYPER, AJPC, /* parity clear (PF = 0) */
|
||||
"JNP", LTYPER, AJPC, /* alternate */
|
||||
"JPO", LTYPER, AJPC, /* alternate */
|
||||
"JLT", LTYPER, AJLT,
|
||||
"JLT", LTYPER, AJLT, /* less than (signed) (SF != OF) */
|
||||
"JL", LTYPER, AJLT, /* alternate */
|
||||
"JNGE", LTYPER, AJLT, /* alternate */
|
||||
"JGE", LTYPER, AJGE,
|
||||
"JGE", LTYPER, AJGE, /* greater than or equal (signed) (SF = OF) */
|
||||
"JNL", LTYPER, AJGE, /* alternate */
|
||||
"JLE", LTYPER, AJLE,
|
||||
"JLE", LTYPER, AJLE, /* less than or equal (signed) (ZF = 1 || SF != OF) */
|
||||
"JNG", LTYPER, AJLE, /* alternate */
|
||||
"JGT", LTYPER, AJGT,
|
||||
"JGT", LTYPER, AJGT, /* greater than (signed) (ZF = 0 && SF = OF) */
|
||||
"JG", LTYPER, AJGT, /* alternate */
|
||||
"JNLE", LTYPER, AJGT, /* alternate */
|
||||
"JCXZL", LTYPER, AJCXZL,
|
||||
|
|
@ -612,7 +612,7 @@ struct
|
|||
"SCASL", LTYPE0, ASCASL,
|
||||
"SCASQ", LTYPE0, ASCASQ,
|
||||
"SCASW", LTYPE0, ASCASW,
|
||||
"SETCC", LTYPE1, ASETCC,
|
||||
"SETCC", LTYPE1, ASETCC, /* see JCC etc above for condition codes */
|
||||
"SETCS", LTYPE1, ASETCS,
|
||||
"SETEQ", LTYPE1, ASETEQ,
|
||||
"SETGE", LTYPE1, ASETGE,
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ cgen(Node *n, Node *nn)
|
|||
}
|
||||
if(n == Z || n->type == T)
|
||||
return;
|
||||
if(typesu[n->type->etype]) {
|
||||
if(typesu[n->type->etype] && (n->op != OFUNC || nn != Z)) {
|
||||
sugen(n, nn, n->type->width);
|
||||
return;
|
||||
}
|
||||
|
|
@ -88,7 +88,7 @@ cgen(Node *n, Node *nn)
|
|||
if(cond(o) && typesu[l->type->etype])
|
||||
break;
|
||||
|
||||
regret(&nod, r);
|
||||
regret(&nod, r, 0, 0);
|
||||
cgen(r, &nod);
|
||||
|
||||
regsalloc(&nod1, r);
|
||||
|
|
@ -135,7 +135,7 @@ cgen(Node *n, Node *nn)
|
|||
if(!hardleft) {
|
||||
if(nn != Z || r->addable < INDEXED || hardconst(r)) {
|
||||
if(r->complex >= FNX && nn == Z)
|
||||
regret(&nod, r);
|
||||
regret(&nod, r, 0, 0);
|
||||
else
|
||||
regalloc(&nod, r, nn);
|
||||
cgen(r, &nod);
|
||||
|
|
@ -929,7 +929,7 @@ cgen(Node *n, Node *nn)
|
|||
if(l->op != OIND)
|
||||
diag(n, "bad function call");
|
||||
|
||||
regret(&nod, l->left);
|
||||
regret(&nod, l->left, 0, 0);
|
||||
cgen(l->left, &nod);
|
||||
regsalloc(&nod1, l->left);
|
||||
gmove(&nod, &nod1);
|
||||
|
|
@ -956,11 +956,13 @@ cgen(Node *n, Node *nn)
|
|||
gpcdata(PCDATA_ArgSize, -1);
|
||||
if(REGARG >= 0 && reg[REGARG])
|
||||
reg[REGARG]--;
|
||||
if(nn != Z) {
|
||||
regret(&nod, n);
|
||||
regret(&nod, n, l->type, 1); // update maxarg if nothing else
|
||||
gpcdata(PCDATA_ArgSize, curarg);
|
||||
gpcdata(PCDATA_ArgSize, -1);
|
||||
if(nn != Z)
|
||||
gmove(&nod, nn);
|
||||
if(nod.op == OREGISTER)
|
||||
regfree(&nod);
|
||||
}
|
||||
break;
|
||||
|
||||
case OIND:
|
||||
|
|
@ -1382,7 +1384,7 @@ boolgen(Node *n, int true, Node *nn)
|
|||
if(true)
|
||||
o = comrel[relindex(o)];
|
||||
if(l->complex >= FNX && r->complex >= FNX) {
|
||||
regret(&nod, r);
|
||||
regret(&nod, r, 0, 0);
|
||||
cgen(r, &nod);
|
||||
regsalloc(&nod1, r);
|
||||
gmove(&nod, &nod1);
|
||||
|
|
@ -1535,7 +1537,7 @@ sugen(Node *n, Node *nn, int32 w)
|
|||
if(nn != Z && side(nn)) {
|
||||
nod1 = *n;
|
||||
nod1.type = typ(TIND, n->type);
|
||||
regret(&nod2, &nod1);
|
||||
regret(&nod2, &nod1, 0, 0);
|
||||
lcgen(nn, &nod2);
|
||||
regsalloc(&nod0, &nod1);
|
||||
cgen(&nod2, &nod0);
|
||||
|
|
@ -1617,6 +1619,20 @@ sugen(Node *n, Node *nn, int32 w)
|
|||
break;
|
||||
|
||||
case OFUNC:
|
||||
if(!hasdotdotdot(n->left->type)) {
|
||||
cgen(n, Z);
|
||||
if(nn != Z) {
|
||||
curarg -= n->type->width;
|
||||
regret(&nod1, n, n->left->type, 1);
|
||||
if(nn->complex >= FNX) {
|
||||
regsalloc(&nod2, n);
|
||||
cgen(&nod1, &nod2);
|
||||
nod1 = nod2;
|
||||
}
|
||||
cgen(&nod1, nn);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(nn == Z) {
|
||||
sugen(n, nodrat, w);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ void xcom(Node*);
|
|||
void indx(Node*);
|
||||
int bcomplex(Node*, Node*);
|
||||
Prog* gtext(Sym*, int32);
|
||||
vlong argsize(void);
|
||||
vlong argsize(int);
|
||||
|
||||
/*
|
||||
* cgen.c
|
||||
|
|
@ -239,7 +239,7 @@ Node* nodfconst(double);
|
|||
Node* nodgconst(vlong, Type*);
|
||||
int nodreg(Node*, Node*, int);
|
||||
int isreg(Node*, int);
|
||||
void regret(Node*, Node*);
|
||||
void regret(Node*, Node*, Type*, int);
|
||||
void regalloc(Node*, Node*, Node*);
|
||||
void regfree(Node*);
|
||||
void regialloc(Node*, Node*, Node*);
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ gtext(Sym *s, int32 stkoff)
|
|||
{
|
||||
vlong v;
|
||||
|
||||
v = ((uvlong)argsize() << 32) | (stkoff & 0xffffffff);
|
||||
v = ((uvlong)argsize(1) << 32) | (stkoff & 0xffffffff);
|
||||
if((textflag & NOSPLIT) && stkoff >= 128)
|
||||
yyerror("stack frame too large for NOSPLIT function");
|
||||
|
||||
|
|
@ -124,10 +124,7 @@ xcom(Node *n)
|
|||
break;
|
||||
|
||||
case ONAME:
|
||||
if(flag_largemodel)
|
||||
n->addable = 9;
|
||||
else
|
||||
n->addable = 10;
|
||||
n->addable = 9;
|
||||
if(n->class == CPARAM || n->class == CAUTO)
|
||||
n->addable = 11;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -250,10 +250,11 @@ align(int32 i, Type *t, int op, int32 *maxalign)
|
|||
{
|
||||
int32 o;
|
||||
Type *v;
|
||||
int w;
|
||||
int w, packw;
|
||||
|
||||
o = i;
|
||||
w = 1;
|
||||
packw = 0;
|
||||
switch(op) {
|
||||
default:
|
||||
diag(Z, "unknown align opcode %d", op);
|
||||
|
|
@ -264,7 +265,7 @@ align(int32 i, Type *t, int op, int32 *maxalign)
|
|||
if(w < 1)
|
||||
w = 1;
|
||||
if(packflg)
|
||||
w = packflg;
|
||||
packw = packflg;
|
||||
break;
|
||||
|
||||
case Ael1: /* initial align of struct element */
|
||||
|
|
@ -277,7 +278,7 @@ align(int32 i, Type *t, int op, int32 *maxalign)
|
|||
if(w < 1 || w > SZ_VLONG)
|
||||
fatal(Z, "align");
|
||||
if(packflg)
|
||||
w = packflg;
|
||||
packw = packflg;
|
||||
break;
|
||||
|
||||
case Ael2: /* width of a struct element */
|
||||
|
|
@ -331,6 +332,8 @@ align(int32 i, Type *t, int op, int32 *maxalign)
|
|||
o = align(o, t, Ael2, nil);
|
||||
break;
|
||||
}
|
||||
if(packw != 0 && xround(o, w) != xround(o, packw))
|
||||
diag(Z, "#pragma pack changes offset of %T", t);
|
||||
o = xround(o, w);
|
||||
if(maxalign && *maxalign < w)
|
||||
*maxalign = w;
|
||||
|
|
|
|||
|
|
@ -351,15 +351,43 @@ nodreg(Node *n, Node *nn, int r)
|
|||
}
|
||||
|
||||
void
|
||||
regret(Node *n, Node *nn)
|
||||
regret(Node *n, Node *nn, Type *t, int mode)
|
||||
{
|
||||
int r;
|
||||
|
||||
if(mode == 0 || hasdotdotdot(t) || nn->type->width == 0) {
|
||||
r = REGRET;
|
||||
if(typefd[nn->type->etype])
|
||||
r = FREGRET;
|
||||
nodreg(n, nn, r);
|
||||
reg[r]++;
|
||||
return;
|
||||
}
|
||||
|
||||
if(mode == 1) {
|
||||
// fetch returned value after call.
|
||||
// already called gargs, so curarg is set.
|
||||
curarg = (curarg+7) & ~7;
|
||||
regaalloc(n, nn);
|
||||
return;
|
||||
}
|
||||
|
||||
r = REGRET;
|
||||
if(typefd[nn->type->etype])
|
||||
r = FREGRET;
|
||||
nodreg(n, nn, r);
|
||||
reg[r]++;
|
||||
if(mode == 2) {
|
||||
// store value to be returned.
|
||||
// must compute arg offset.
|
||||
if(t->etype != TFUNC)
|
||||
fatal(Z, "bad regret func %T", t);
|
||||
*n = *nn;
|
||||
n->op = ONAME;
|
||||
n->class = CPARAM;
|
||||
n->sym = slookup(".ret");
|
||||
n->complex = nodret->complex;
|
||||
n->addable = 20;
|
||||
n->xoffset = argsize(0);
|
||||
return;
|
||||
}
|
||||
|
||||
fatal(Z, "bad regret");
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -247,7 +247,6 @@ cgen(Node *n, Node *res)
|
|||
case OOR:
|
||||
case OXOR:
|
||||
case OADD:
|
||||
case OADDPTR:
|
||||
case OMUL:
|
||||
a = optoas(n->op, nl->type);
|
||||
if(a == AIMULB) {
|
||||
|
|
@ -752,12 +751,7 @@ agenr(Node *n, Node *a, Node *res)
|
|||
regalloc(&n3, types[tptr], res);
|
||||
p1 = gins(ALEAQ, N, &n3);
|
||||
datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
|
||||
if(flag_largemodel) {
|
||||
gins(AADDQ, &n2, &n3);
|
||||
} else {
|
||||
p1->from.scale = 1;
|
||||
p1->from.index = n2.val.u.reg;
|
||||
}
|
||||
gins(AADDQ, &n2, &n3);
|
||||
goto indexdone;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,6 @@ void allocparams(void);
|
|||
void checklabels(void);
|
||||
void ginscall(Node*, int);
|
||||
int gen_as_init(Node*);
|
||||
void clearslim(Node*);
|
||||
|
||||
/*
|
||||
* cgen.c
|
||||
|
|
|
|||
|
|
@ -943,7 +943,7 @@ cgen_hmul(Node *nl, Node *nr, Node *res)
|
|||
if(t->width == 1) {
|
||||
// byte multiply behaves differently.
|
||||
nodreg(&ax, t, D_AH);
|
||||
nodreg(&dx, t, D_DL);
|
||||
nodreg(&dx, t, D_DX);
|
||||
gmove(&ax, &dx);
|
||||
}
|
||||
nodreg(&dx, t, D_DX);
|
||||
|
|
|
|||
|
|
@ -598,11 +598,8 @@ ismem(Node *n)
|
|||
case ONAME:
|
||||
case OPARAM:
|
||||
case OCLOSUREVAR:
|
||||
return 1;
|
||||
case OADDR:
|
||||
if(flag_largemodel)
|
||||
return 1;
|
||||
break;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1540,14 +1537,12 @@ optoas(int op, Type *t)
|
|||
case CASE(OADD, TINT32):
|
||||
case CASE(OADD, TUINT32):
|
||||
case CASE(OADD, TPTR32):
|
||||
case CASE(OADDPTR, TPTR32):
|
||||
a = AADDL;
|
||||
break;
|
||||
|
||||
case CASE(OADD, TINT64):
|
||||
case CASE(OADD, TUINT64):
|
||||
case CASE(OADD, TPTR64):
|
||||
case CASE(OADDPTR, TPTR64):
|
||||
a = AADDQ;
|
||||
break;
|
||||
|
||||
|
|
|
|||
|
|
@ -838,6 +838,11 @@ copyu(Prog *p, Adr *v, Adr *s)
|
|||
static int
|
||||
copyas(Adr *a, Adr *v)
|
||||
{
|
||||
if(D_AL <= a->type && a->type <= D_R15B)
|
||||
fatal("use of byte register");
|
||||
if(D_AL <= v->type && v->type <= D_R15B)
|
||||
fatal("use of byte register");
|
||||
|
||||
if(a->type != v->type)
|
||||
return 0;
|
||||
if(regtyp(v))
|
||||
|
|
|
|||
|
|
@ -844,7 +844,7 @@ prop(Reg *r, Bits ref, Bits cal)
|
|||
if(v == v1 || ((cal.b[j/32]>>(j&31))&1) == 0) {
|
||||
for(; v1 != nil; v1 = v1->nextinnode) {
|
||||
j = v1 - var;
|
||||
cal.b[j/32] |= 1<<(j&31);
|
||||
cal.b[j/32] |= 1UL<<(j&31);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1191,6 +1191,7 @@ void
|
|||
addreg(Adr *a, int rn)
|
||||
{
|
||||
a->sym = nil;
|
||||
a->node = nil;
|
||||
a->offset = 0;
|
||||
a->type = rn;
|
||||
|
||||
|
|
|
|||
|
|
@ -290,7 +290,6 @@ elfreloc1(Reloc *r, vlong sectoff)
|
|||
break;
|
||||
|
||||
case R_CALL:
|
||||
case R_PCREL:
|
||||
if(r->siz == 4) {
|
||||
if(r->xsym->type == SDYNIMPORT)
|
||||
VPUT(R_X86_64_GOTPCREL | (uint64)elfsym<<32);
|
||||
|
|
@ -299,7 +298,14 @@ elfreloc1(Reloc *r, vlong sectoff)
|
|||
} else
|
||||
return -1;
|
||||
break;
|
||||
|
||||
|
||||
case R_PCREL:
|
||||
if(r->siz == 4) {
|
||||
VPUT(R_X86_64_PC32 | (uint64)elfsym<<32);
|
||||
} else
|
||||
return -1;
|
||||
break;
|
||||
|
||||
case R_TLS:
|
||||
if(r->siz == 4) {
|
||||
if(flag_shared)
|
||||
|
|
@ -323,7 +329,7 @@ machoreloc1(Reloc *r, vlong sectoff)
|
|||
|
||||
rs = r->xsym;
|
||||
|
||||
if(rs->type == SHOSTOBJ) {
|
||||
if(rs->type == SHOSTOBJ || r->type == R_PCREL) {
|
||||
if(rs->dynid < 0) {
|
||||
diag("reloc %d to non-macho symbol %s type=%d", r->type, rs->name, rs->type);
|
||||
return -1;
|
||||
|
|
@ -345,10 +351,13 @@ machoreloc1(Reloc *r, vlong sectoff)
|
|||
v |= MACHO_X86_64_RELOC_UNSIGNED<<28;
|
||||
break;
|
||||
case R_CALL:
|
||||
case R_PCREL:
|
||||
v |= 1<<24; // pc-relative bit
|
||||
v |= MACHO_X86_64_RELOC_BRANCH<<28;
|
||||
break;
|
||||
case R_PCREL:
|
||||
// NOTE: Only works with 'external' relocation. Forced above.
|
||||
v |= 1<<24; // pc-relative bit
|
||||
v |= MACHO_X86_64_RELOC_SIGNED<<28;
|
||||
}
|
||||
|
||||
switch(r->siz) {
|
||||
|
|
@ -689,10 +698,10 @@ asmb(void)
|
|||
case Hplan9:
|
||||
case Helf:
|
||||
debug['s'] = 1;
|
||||
symo = HEADR+segtext.len+segdata.filelen;
|
||||
symo = segdata.fileoff+segdata.filelen;
|
||||
break;
|
||||
case Hdarwin:
|
||||
symo = rnd(HEADR+segtext.len, INITRND)+rnd(segdata.filelen, INITRND)+machlink;
|
||||
symo = segdata.fileoff+rnd(segdata.filelen, INITRND)+machlink;
|
||||
break;
|
||||
case Hlinux:
|
||||
case Hfreebsd:
|
||||
|
|
@ -701,11 +710,11 @@ asmb(void)
|
|||
case Hdragonfly:
|
||||
case Hsolaris:
|
||||
case Hnacl:
|
||||
symo = rnd(HEADR+segtext.len, INITRND)+rnd(segrodata.len, INITRND)+segdata.filelen;
|
||||
symo = segdata.fileoff+segdata.filelen;
|
||||
symo = rnd(symo, INITRND);
|
||||
break;
|
||||
case Hwindows:
|
||||
symo = rnd(HEADR+segtext.filelen, PEFILEALIGN)+segdata.filelen;
|
||||
symo = segdata.fileoff+segdata.filelen;
|
||||
symo = rnd(symo, PEFILEALIGN);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -352,49 +352,49 @@ struct
|
|||
"IRETL", LTYPE0, AIRETL,
|
||||
"IRETW", LTYPE0, AIRETW,
|
||||
|
||||
"JOS", LTYPER, AJOS,
|
||||
"JOS", LTYPER, AJOS, /* overflow set (OF = 1) */
|
||||
"JO", LTYPER, AJOS, /* alternate */
|
||||
"JOC", LTYPER, AJOC,
|
||||
"JOC", LTYPER, AJOC, /* overflow clear (OF = 0) */
|
||||
"JNO", LTYPER, AJOC, /* alternate */
|
||||
"JCS", LTYPER, AJCS,
|
||||
"JCS", LTYPER, AJCS, /* carry set (CF = 1) */
|
||||
"JB", LTYPER, AJCS, /* alternate */
|
||||
"JC", LTYPER, AJCS, /* alternate */
|
||||
"JNAE", LTYPER, AJCS, /* alternate */
|
||||
"JLO", LTYPER, AJCS, /* alternate */
|
||||
"JCC", LTYPER, AJCC,
|
||||
"JCC", LTYPER, AJCC, /* carry clear (CF = 0) */
|
||||
"JAE", LTYPER, AJCC, /* alternate */
|
||||
"JNB", LTYPER, AJCC, /* alternate */
|
||||
"JNC", LTYPER, AJCC, /* alternate */
|
||||
"JHS", LTYPER, AJCC, /* alternate */
|
||||
"JEQ", LTYPER, AJEQ,
|
||||
"JEQ", LTYPER, AJEQ, /* equal (ZF = 1) */
|
||||
"JE", LTYPER, AJEQ, /* alternate */
|
||||
"JZ", LTYPER, AJEQ, /* alternate */
|
||||
"JNE", LTYPER, AJNE,
|
||||
"JNE", LTYPER, AJNE, /* not equal (ZF = 0) */
|
||||
"JNZ", LTYPER, AJNE, /* alternate */
|
||||
"JLS", LTYPER, AJLS,
|
||||
"JLS", LTYPER, AJLS, /* lower or same (unsigned) (CF = 1 || ZF = 1) */
|
||||
"JBE", LTYPER, AJLS, /* alternate */
|
||||
"JNA", LTYPER, AJLS, /* alternate */
|
||||
"JHI", LTYPER, AJHI,
|
||||
"JHI", LTYPER, AJHI, /* higher (unsigned) (CF = 0 && ZF = 0) */
|
||||
"JA", LTYPER, AJHI, /* alternate */
|
||||
"JNBE", LTYPER, AJHI, /* alternate */
|
||||
"JMI", LTYPER, AJMI,
|
||||
"JMI", LTYPER, AJMI, /* negative (minus) (SF = 1) */
|
||||
"JS", LTYPER, AJMI, /* alternate */
|
||||
"JPL", LTYPER, AJPL,
|
||||
"JPL", LTYPER, AJPL, /* non-negative (plus) (SF = 0) */
|
||||
"JNS", LTYPER, AJPL, /* alternate */
|
||||
"JPS", LTYPER, AJPS,
|
||||
"JPS", LTYPER, AJPS, /* parity set (PF = 1) */
|
||||
"JP", LTYPER, AJPS, /* alternate */
|
||||
"JPE", LTYPER, AJPS, /* alternate */
|
||||
"JPC", LTYPER, AJPC,
|
||||
"JPC", LTYPER, AJPC, /* parity clear (PF = 0) */
|
||||
"JNP", LTYPER, AJPC, /* alternate */
|
||||
"JPO", LTYPER, AJPC, /* alternate */
|
||||
"JLT", LTYPER, AJLT,
|
||||
"JLT", LTYPER, AJLT, /* less than (signed) (SF != OF) */
|
||||
"JL", LTYPER, AJLT, /* alternate */
|
||||
"JNGE", LTYPER, AJLT, /* alternate */
|
||||
"JGE", LTYPER, AJGE,
|
||||
"JGE", LTYPER, AJGE, /* greater than or equal (signed) (SF = OF) */
|
||||
"JNL", LTYPER, AJGE, /* alternate */
|
||||
"JLE", LTYPER, AJLE,
|
||||
"JLE", LTYPER, AJLE, /* less than or equal (signed) (ZF = 1 || SF != OF) */
|
||||
"JNG", LTYPER, AJLE, /* alternate */
|
||||
"JGT", LTYPER, AJGT,
|
||||
"JGT", LTYPER, AJGT, /* greater than (signed) (ZF = 0 && SF = OF) */
|
||||
"JG", LTYPER, AJGT, /* alternate */
|
||||
"JNLE", LTYPER, AJGT, /* alternate */
|
||||
|
||||
|
|
@ -493,7 +493,7 @@ struct
|
|||
"SCASB", LTYPE0, ASCASB,
|
||||
"SCASL", LTYPE0, ASCASL,
|
||||
"SCASW", LTYPE0, ASCASW,
|
||||
"SETCC", LTYPE1, ASETCC,
|
||||
"SETCC", LTYPE1, ASETCC, /* see JCC etc above for condition codes */
|
||||
"SETCS", LTYPE1, ASETCS,
|
||||
"SETEQ", LTYPE1, ASETEQ,
|
||||
"SETGE", LTYPE1, ASETGE,
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ cgen(Node *n, Node *nn)
|
|||
}
|
||||
if(n == Z || n->type == T)
|
||||
return;
|
||||
if(typesuv[n->type->etype]) {
|
||||
if(typesuv[n->type->etype] && (n->op != OFUNC || nn != Z)) {
|
||||
sugen(n, nn, n->type->width);
|
||||
return;
|
||||
}
|
||||
|
|
@ -86,7 +86,7 @@ cgen(Node *n, Node *nn)
|
|||
if(cond(o) && typesuv[l->type->etype])
|
||||
break;
|
||||
|
||||
regret(&nod, r);
|
||||
regret(&nod, r, 0, 0);
|
||||
cgen(r, &nod);
|
||||
|
||||
regsalloc(&nod1, r);
|
||||
|
|
@ -147,7 +147,7 @@ cgen(Node *n, Node *nn)
|
|||
if(!hardleft) {
|
||||
if(nn != Z || r->addable < INDEXED) {
|
||||
if(r->complex >= FNX && nn == Z)
|
||||
regret(&nod, r);
|
||||
regret(&nod, r, 0, 0);
|
||||
else
|
||||
regalloc(&nod, r, nn);
|
||||
cgen(r, &nod);
|
||||
|
|
@ -922,7 +922,7 @@ cgen(Node *n, Node *nn)
|
|||
if(l->op != OIND)
|
||||
diag(n, "bad function call");
|
||||
|
||||
regret(&nod, l->left);
|
||||
regret(&nod, l->left, 0, 0);
|
||||
cgen(l->left, &nod);
|
||||
regsalloc(&nod1, l->left);
|
||||
gmove(&nod, &nod1);
|
||||
|
|
@ -949,12 +949,12 @@ cgen(Node *n, Node *nn)
|
|||
gpcdata(PCDATA_ArgSize, -1);
|
||||
if(REGARG >= 0 && reg[REGARG])
|
||||
reg[REGARG]--;
|
||||
if(nn != Z) {
|
||||
regret(&nod, n);
|
||||
regret(&nod, n, l->type, 1); // update maxarg if nothing else
|
||||
if(nn != Z)
|
||||
gmove(&nod, nn);
|
||||
if(nod.op == OREGISTER)
|
||||
regfree(&nod);
|
||||
} else
|
||||
if(typefd[n->type->etype])
|
||||
if(nn == Z && hasdotdotdot(l->type) && typefd[n->type->etype])
|
||||
gins(AFMOVDP, &fregnode0, &fregnode0);
|
||||
break;
|
||||
|
||||
|
|
@ -1374,7 +1374,7 @@ boolgen(Node *n, int true, Node *nn)
|
|||
if(true)
|
||||
o = comrel[relindex(o)];
|
||||
if(l->complex >= FNX && r->complex >= FNX) {
|
||||
regret(&nod, r);
|
||||
regret(&nod, r, 0, 0);
|
||||
cgen(r, &nod);
|
||||
regsalloc(&nod1, r);
|
||||
gmove(&nod, &nod1);
|
||||
|
|
@ -1567,7 +1567,7 @@ sugen(Node *n, Node *nn, int32 w)
|
|||
if(nn != Z && side(nn)) {
|
||||
nod1 = *n;
|
||||
nod1.type = typ(TIND, n->type);
|
||||
regret(&nod2, &nod1);
|
||||
regret(&nod2, &nod1, 0, 0);
|
||||
lcgen(nn, &nod2);
|
||||
regsalloc(&nod0, &nod1);
|
||||
cgen(&nod2, &nod0);
|
||||
|
|
@ -1649,6 +1649,20 @@ sugen(Node *n, Node *nn, int32 w)
|
|||
break;
|
||||
|
||||
case OFUNC:
|
||||
if(!hasdotdotdot(n->left->type)) {
|
||||
cgen(n, Z);
|
||||
if(nn != Z) {
|
||||
curarg -= n->type->width;
|
||||
regret(&nod1, n, n->left->type, 1);
|
||||
if(nn->complex >= FNX) {
|
||||
regsalloc(&nod2, n);
|
||||
cgen(&nod1, &nod2);
|
||||
nod1 = nod2;
|
||||
}
|
||||
cgen(&nod1, nn);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(nn == Z) {
|
||||
sugen(n, nodrat, w);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ void xcom(Node*);
|
|||
void indx(Node*);
|
||||
int bcomplex(Node*, Node*);
|
||||
Prog* gtext(Sym*, int32);
|
||||
vlong argsize(void);
|
||||
vlong argsize(int);
|
||||
|
||||
/*
|
||||
* cgen.c
|
||||
|
|
@ -244,7 +244,7 @@ Node* nodconst(int32);
|
|||
Node* nodfconst(double);
|
||||
int nodreg(Node*, Node*, int);
|
||||
int isreg(Node*, int);
|
||||
void regret(Node*, Node*);
|
||||
void regret(Node*, Node*, Type*, int);
|
||||
void regalloc(Node*, Node*, Node*);
|
||||
void regfree(Node*);
|
||||
void regialloc(Node*, Node*, Node*);
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ gtext(Sym *s, int32 stkoff)
|
|||
{
|
||||
int32 a;
|
||||
|
||||
a = argsize();
|
||||
a = argsize(1);
|
||||
if((textflag & NOSPLIT) != 0 && stkoff >= 128)
|
||||
yyerror("stack frame too large for NOSPLIT function");
|
||||
|
||||
|
|
|
|||
|
|
@ -255,10 +255,11 @@ align(int32 i, Type *t, int op, int32 *maxalign)
|
|||
{
|
||||
int32 o;
|
||||
Type *v;
|
||||
int w;
|
||||
int w, packw;
|
||||
|
||||
o = i;
|
||||
w = 1;
|
||||
packw = 0;
|
||||
switch(op) {
|
||||
default:
|
||||
diag(Z, "unknown align opcode %d", op);
|
||||
|
|
@ -269,7 +270,7 @@ align(int32 i, Type *t, int op, int32 *maxalign)
|
|||
if(w < 1)
|
||||
w = 1;
|
||||
if(packflg)
|
||||
w = packflg;
|
||||
packw = packflg;
|
||||
break;
|
||||
|
||||
case Ael1: /* initial align of struct element */
|
||||
|
|
@ -285,7 +286,7 @@ align(int32 i, Type *t, int op, int32 *maxalign)
|
|||
if(w < 1 || w > SZ_LONG)
|
||||
fatal(Z, "align");
|
||||
if(packflg)
|
||||
w = packflg;
|
||||
packw = packflg;
|
||||
break;
|
||||
|
||||
case Ael2: /* width of a struct element */
|
||||
|
|
@ -320,6 +321,8 @@ align(int32 i, Type *t, int op, int32 *maxalign)
|
|||
o = align(o, t, Ael2, nil);
|
||||
break;
|
||||
}
|
||||
if(packw != 0 && xround(o, w) != xround(o, packw))
|
||||
diag(Z, "#pragma pack changes offset of %T", t);
|
||||
o = xround(o, w);
|
||||
if(maxalign && *maxalign < w)
|
||||
*maxalign = w;
|
||||
|
|
|
|||
|
|
@ -311,15 +311,43 @@ nodreg(Node *n, Node *nn, int r)
|
|||
}
|
||||
|
||||
void
|
||||
regret(Node *n, Node *nn)
|
||||
regret(Node *n, Node *nn, Type *t, int mode)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = REGRET;
|
||||
if(typefd[nn->type->etype])
|
||||
r = FREGRET;
|
||||
nodreg(n, nn, r);
|
||||
reg[r]++;
|
||||
if(mode == 0 || hasdotdotdot(t) || nn->type->width == 0) {
|
||||
r = REGRET;
|
||||
if(typefd[nn->type->etype])
|
||||
r = FREGRET;
|
||||
nodreg(n, nn, r);
|
||||
reg[r]++;
|
||||
return;
|
||||
}
|
||||
|
||||
if(mode == 1) {
|
||||
// fetch returned value after call.
|
||||
// already called gargs, so curarg is set.
|
||||
curarg = (curarg+3) & ~3;
|
||||
regaalloc(n, nn);
|
||||
return;
|
||||
}
|
||||
|
||||
if(mode == 2) {
|
||||
// store value to be returned.
|
||||
// must compute arg offset.
|
||||
if(t->etype != TFUNC)
|
||||
fatal(Z, "bad regret func %T", t);
|
||||
*n = *nn;
|
||||
n->op = ONAME;
|
||||
n->class = CPARAM;
|
||||
n->sym = slookup(".retx");
|
||||
n->complex = 0;
|
||||
n->addable = 20;
|
||||
n->xoffset = argsize(0);
|
||||
return;
|
||||
}
|
||||
|
||||
fatal(Z, "bad regret");
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -242,7 +242,6 @@ cgen(Node *n, Node *res)
|
|||
case OOR:
|
||||
case OXOR:
|
||||
case OADD:
|
||||
case OADDPTR:
|
||||
case OMUL:
|
||||
a = optoas(n->op, nl->type);
|
||||
if(a == AIMULB) {
|
||||
|
|
@ -1367,7 +1366,10 @@ int
|
|||
componentgen(Node *nr, Node *nl)
|
||||
{
|
||||
Node nodl, nodr;
|
||||
Type *t;
|
||||
int freel, freer;
|
||||
vlong fldcount;
|
||||
vlong loffset, roffset;
|
||||
|
||||
freel = 0;
|
||||
freer = 0;
|
||||
|
|
@ -1377,8 +1379,33 @@ componentgen(Node *nr, Node *nl)
|
|||
goto no;
|
||||
|
||||
case TARRAY:
|
||||
if(!isslice(nl->type))
|
||||
t = nl->type;
|
||||
|
||||
// Slices are ok.
|
||||
if(isslice(t))
|
||||
break;
|
||||
// Small arrays are ok.
|
||||
if(t->bound > 0 && t->bound <= 3 && !isfat(t->type))
|
||||
break;
|
||||
|
||||
goto no;
|
||||
|
||||
case TSTRUCT:
|
||||
// Small structs with non-fat types are ok.
|
||||
// Zero-sized structs are treated separately elsewhere.
|
||||
fldcount = 0;
|
||||
for(t=nl->type->type; t; t=t->down) {
|
||||
if(isfat(t->type))
|
||||
goto no;
|
||||
if(t->etype != TFIELD)
|
||||
fatal("componentgen: not a TFIELD: %lT", t);
|
||||
fldcount++;
|
||||
}
|
||||
if(fldcount == 0 || fldcount > 4)
|
||||
goto no;
|
||||
|
||||
break;
|
||||
|
||||
case TSTRING:
|
||||
case TINTER:
|
||||
break;
|
||||
|
|
@ -1399,7 +1426,7 @@ componentgen(Node *nr, Node *nl)
|
|||
freer = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// nl and nr are 'cadable' which basically means they are names (variables) now.
|
||||
// If they are the same variable, don't generate any code, because the
|
||||
// VARDEF we generate will mark the old value as dead incorrectly.
|
||||
|
|
@ -1409,8 +1436,25 @@ componentgen(Node *nr, Node *nl)
|
|||
|
||||
switch(nl->type->etype) {
|
||||
case TARRAY:
|
||||
// componentgen for arrays.
|
||||
if(nl->op == ONAME)
|
||||
gvardef(nl);
|
||||
t = nl->type;
|
||||
if(!isslice(t)) {
|
||||
nodl.type = t->type;
|
||||
nodr.type = nodl.type;
|
||||
for(fldcount=0; fldcount < t->bound; fldcount++) {
|
||||
if(nr == N)
|
||||
clearslim(&nodl);
|
||||
else
|
||||
gmove(&nodr, &nodl);
|
||||
nodl.xoffset += t->type->width;
|
||||
nodr.xoffset += t->type->width;
|
||||
}
|
||||
goto yes;
|
||||
}
|
||||
|
||||
// componentgen for slices.
|
||||
nodl.xoffset += Array_array;
|
||||
nodl.type = ptrto(nl->type->type);
|
||||
|
||||
|
|
@ -1422,7 +1466,7 @@ componentgen(Node *nr, Node *nl)
|
|||
gmove(&nodr, &nodl);
|
||||
|
||||
nodl.xoffset += Array_nel-Array_array;
|
||||
nodl.type = types[TUINT32];
|
||||
nodl.type = types[simtype[TUINT]];
|
||||
|
||||
if(nr != N) {
|
||||
nodr.xoffset += Array_nel-Array_array;
|
||||
|
|
@ -1432,7 +1476,7 @@ componentgen(Node *nr, Node *nl)
|
|||
gmove(&nodr, &nodl);
|
||||
|
||||
nodl.xoffset += Array_cap-Array_nel;
|
||||
nodl.type = types[TUINT32];
|
||||
nodl.type = types[simtype[TUINT]];
|
||||
|
||||
if(nr != N) {
|
||||
nodr.xoffset += Array_cap-Array_nel;
|
||||
|
|
@ -1457,7 +1501,7 @@ componentgen(Node *nr, Node *nl)
|
|||
gmove(&nodr, &nodl);
|
||||
|
||||
nodl.xoffset += Array_nel-Array_array;
|
||||
nodl.type = types[TUINT32];
|
||||
nodl.type = types[simtype[TUINT]];
|
||||
|
||||
if(nr != N) {
|
||||
nodr.xoffset += Array_nel-Array_array;
|
||||
|
|
@ -1492,6 +1536,31 @@ componentgen(Node *nr, Node *nl)
|
|||
gmove(&nodr, &nodl);
|
||||
|
||||
goto yes;
|
||||
|
||||
case TSTRUCT:
|
||||
if(nl->op == ONAME)
|
||||
gvardef(nl);
|
||||
loffset = nodl.xoffset;
|
||||
roffset = nodr.xoffset;
|
||||
// funarg structs may not begin at offset zero.
|
||||
if(nl->type->etype == TSTRUCT && nl->type->funarg && nl->type->type)
|
||||
loffset -= nl->type->type->width;
|
||||
if(nr != N && nr->type->etype == TSTRUCT && nr->type->funarg && nr->type->type)
|
||||
roffset -= nr->type->type->width;
|
||||
|
||||
for(t=nl->type->type; t; t=t->down) {
|
||||
nodl.xoffset = loffset + t->width;
|
||||
nodl.type = t->type;
|
||||
|
||||
if(nr == N)
|
||||
clearslim(&nodl);
|
||||
else {
|
||||
nodr.xoffset = roffset + t->width;
|
||||
nodr.type = nodl.type;
|
||||
gmove(&nodr, &nodl);
|
||||
}
|
||||
}
|
||||
goto yes;
|
||||
}
|
||||
|
||||
no:
|
||||
|
|
|
|||
|
|
@ -991,7 +991,7 @@ cgen_hmul(Node *nl, Node *nr, Node *res)
|
|||
if(t->width == 1) {
|
||||
// byte multiply behaves differently.
|
||||
nodreg(&ax, t, D_AH);
|
||||
nodreg(&dx, t, D_DL);
|
||||
nodreg(&dx, t, D_DX);
|
||||
gmove(&ax, &dx);
|
||||
}
|
||||
nodreg(&dx, t, D_DX);
|
||||
|
|
|
|||
|
|
@ -430,7 +430,6 @@ optoas(int op, Type *t)
|
|||
case CASE(OADD, TINT32):
|
||||
case CASE(OADD, TUINT32):
|
||||
case CASE(OADD, TPTR32):
|
||||
case CASE(OADDPTR, TPTR32):
|
||||
a = AADDL;
|
||||
break;
|
||||
|
||||
|
|
|
|||
|
|
@ -636,6 +636,11 @@ copyu(Prog *p, Adr *v, Adr *s)
|
|||
static int
|
||||
copyas(Adr *a, Adr *v)
|
||||
{
|
||||
if(D_AL <= a->type && a->type <= D_BL)
|
||||
fatal("use of byte register");
|
||||
if(D_AL <= v->type && v->type <= D_BL)
|
||||
fatal("use of byte register");
|
||||
|
||||
if(a->type != v->type)
|
||||
return 0;
|
||||
if(regtyp(v))
|
||||
|
|
|
|||
|
|
@ -1168,6 +1168,7 @@ void
|
|||
addreg(Adr *a, int rn)
|
||||
{
|
||||
a->sym = nil;
|
||||
a->node = nil;
|
||||
a->offset = 0;
|
||||
a->type = rn;
|
||||
|
||||
|
|
|
|||
|
|
@ -619,17 +619,17 @@ asmb(void)
|
|||
if(iself)
|
||||
goto Elfsym;
|
||||
case Hplan9:
|
||||
symo = HEADR+segtext.filelen+segdata.filelen;
|
||||
symo = segdata.fileoff+segdata.filelen;
|
||||
break;
|
||||
case Hdarwin:
|
||||
symo = rnd(HEADR+segtext.filelen, INITRND)+rnd(segdata.filelen, INITRND)+machlink;
|
||||
symo = segdata.fileoff+rnd(segdata.filelen, INITRND)+machlink;
|
||||
break;
|
||||
Elfsym:
|
||||
symo = rnd(HEADR+segtext.filelen, INITRND)+rnd(HEADR+segrodata.filelen, INITRND)+segdata.filelen;
|
||||
symo = segdata.fileoff+segdata.filelen;
|
||||
symo = rnd(symo, INITRND);
|
||||
break;
|
||||
case Hwindows:
|
||||
symo = rnd(HEADR+segtext.filelen, PEFILEALIGN)+segdata.filelen;
|
||||
symo = segdata.fileoff+segdata.filelen;
|
||||
symo = rnd(symo, PEFILEALIGN);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ cgen(Node *n, Node *nn)
|
|||
}
|
||||
if(n == Z || n->type == T)
|
||||
return;
|
||||
if(typesu[n->type->etype]) {
|
||||
if(typesu[n->type->etype] && (n->op != OFUNC || nn != Z)) {
|
||||
sugen(n, nn, n->type->width);
|
||||
return;
|
||||
}
|
||||
|
|
@ -74,7 +74,7 @@ cgen(Node *n, Node *nn)
|
|||
if(r != Z && r->complex >= FNX)
|
||||
switch(o) {
|
||||
default:
|
||||
regret(&nod, r);
|
||||
regret(&nod, r, 0, 0);
|
||||
cgen(r, &nod);
|
||||
|
||||
regsalloc(&nod1, r);
|
||||
|
|
@ -324,7 +324,7 @@ cgen(Node *n, Node *nn)
|
|||
if(l->op != OIND)
|
||||
diag(n, "bad function call");
|
||||
|
||||
regret(&nod, l->left);
|
||||
regret(&nod, l->left, 0, 0);
|
||||
cgen(l->left, &nod);
|
||||
regsalloc(&nod1, l->left);
|
||||
gopcode(OAS, &nod, Z, &nod1);
|
||||
|
|
@ -353,11 +353,13 @@ cgen(Node *n, Node *nn)
|
|||
if(REGARG>=0)
|
||||
if(o != reg[REGARG])
|
||||
reg[REGARG]--;
|
||||
if(nn != Z) {
|
||||
regret(&nod, n);
|
||||
regret(&nod, n, l->type, 1); // update maxarg if nothing else
|
||||
gpcdata(PCDATA_ArgSize, curarg);
|
||||
gpcdata(PCDATA_ArgSize, -1);
|
||||
if(nn != Z)
|
||||
gopcode(OAS, &nod, Z, nn);
|
||||
if(nod.op == OREGISTER)
|
||||
regfree(&nod);
|
||||
}
|
||||
break;
|
||||
|
||||
case OIND:
|
||||
|
|
@ -759,7 +761,7 @@ boolgen(Node *n, int true, Node *nn)
|
|||
if(true)
|
||||
o = comrel[relindex(o)];
|
||||
if(l->complex >= FNX && r->complex >= FNX) {
|
||||
regret(&nod, r);
|
||||
regret(&nod, r, 0, 0);
|
||||
cgen(r, &nod);
|
||||
regsalloc(&nod1, r);
|
||||
gopcode(OAS, &nod, Z, &nod1);
|
||||
|
|
@ -966,6 +968,20 @@ sugen(Node *n, Node *nn, int32 w)
|
|||
break;
|
||||
|
||||
case OFUNC:
|
||||
if(!hasdotdotdot(n->left->type)) {
|
||||
cgen(n, Z);
|
||||
if(nn != Z) {
|
||||
curarg -= n->type->width;
|
||||
regret(&nod1, n, n->left->type, 1);
|
||||
if(nn->complex >= FNX) {
|
||||
regsalloc(&nod2, n);
|
||||
cgen(&nod1, &nod2);
|
||||
nod1 = nod2;
|
||||
}
|
||||
cgen(&nod1, nn);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(nn == Z) {
|
||||
sugen(n, nodrat, w);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -141,7 +141,6 @@ extern int hintabsize;
|
|||
EXTERN int32 maxargsafe;
|
||||
EXTERN Multab multab[20];
|
||||
EXTERN int mnstring;
|
||||
EXTERN int retok;
|
||||
EXTERN Node* nodrat;
|
||||
EXTERN Node* nodret;
|
||||
EXTERN Node* nodsafe;
|
||||
|
|
@ -212,7 +211,7 @@ void noretval(int);
|
|||
void xcom(Node*);
|
||||
int bcomplex(Node*, Node*);
|
||||
Prog* gtext(Sym*, int32);
|
||||
vlong argsize(void);
|
||||
vlong argsize(int);
|
||||
|
||||
/*
|
||||
* cgen.c
|
||||
|
|
@ -238,7 +237,7 @@ Node* nod32const(vlong);
|
|||
Node* nodfconst(double);
|
||||
Node* nodgconst(vlong v, Type *t);
|
||||
void nodreg(Node*, Node*, int);
|
||||
void regret(Node*, Node*);
|
||||
void regret(Node*, Node*, Type*, int);
|
||||
void regalloc(Node*, Node*, Node*);
|
||||
void regfree(Node*);
|
||||
void regialloc(Node*, Node*, Node*);
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ gtext(Sym *s, int32 stkoff)
|
|||
{
|
||||
vlong v;
|
||||
|
||||
v = ((uvlong)argsize() << 32) | (stkoff & 0xffffffff);
|
||||
v = ((uvlong)argsize(1) << 32) | (stkoff & 0xffffffff);
|
||||
if((textflag & NOSPLIT) && stkoff >= 128)
|
||||
yyerror("stack frame too large for NOSPLIT function");
|
||||
|
||||
|
|
|
|||
|
|
@ -324,10 +324,11 @@ align(int32 i, Type *t, int op, int32 *maxalign)
|
|||
{
|
||||
int32 o;
|
||||
Type *v;
|
||||
int w;
|
||||
int w, packw;
|
||||
|
||||
o = i;
|
||||
w = 1;
|
||||
packw = 0;
|
||||
switch(op) {
|
||||
default:
|
||||
diag(Z, "unknown align opcode %d", op);
|
||||
|
|
@ -338,7 +339,7 @@ align(int32 i, Type *t, int op, int32 *maxalign)
|
|||
if(w < 1)
|
||||
w = 1;
|
||||
if(packflg)
|
||||
w = packflg;
|
||||
packw = packflg;
|
||||
break;
|
||||
|
||||
case Ael1: /* initial allign of struct element */
|
||||
|
|
@ -351,7 +352,7 @@ align(int32 i, Type *t, int op, int32 *maxalign)
|
|||
if(w < 1 || w > SZ_VLONG)
|
||||
fatal(Z, "align");
|
||||
if(packflg)
|
||||
w = packflg;
|
||||
packw = packflg;
|
||||
break;
|
||||
|
||||
case Ael2: /* width of a struct element */
|
||||
|
|
@ -386,6 +387,8 @@ align(int32 i, Type *t, int op, int32 *maxalign)
|
|||
o = align(o, t, Ael2, nil);
|
||||
break;
|
||||
}
|
||||
if(packw != 0 && xround(o, w) != xround(o, packw))
|
||||
diag(Z, "#pragma pack changes offset of %T", t);
|
||||
o = xround(o, w);
|
||||
if(maxalign && *maxalign < w)
|
||||
*maxalign = w;
|
||||
|
|
|
|||
|
|
@ -319,15 +319,43 @@ nodreg(Node *n, Node *nn, int reg)
|
|||
}
|
||||
|
||||
void
|
||||
regret(Node *n, Node *nn)
|
||||
regret(Node *n, Node *nn, Type *t, int mode)
|
||||
{
|
||||
int r;
|
||||
|
||||
if(mode == 0 || hasdotdotdot(t) || nn->type->width == 0) {
|
||||
r = REGRET;
|
||||
if(typefd[nn->type->etype])
|
||||
r = FREGRET+NREG;
|
||||
nodreg(n, nn, r);
|
||||
reg[r]++;
|
||||
return;
|
||||
}
|
||||
|
||||
if(mode == 1) {
|
||||
// fetch returned value after call.
|
||||
// already called gargs, so curarg is set.
|
||||
curarg = (curarg+7) & ~7;
|
||||
regaalloc(n, nn);
|
||||
return;
|
||||
}
|
||||
|
||||
r = REGRET;
|
||||
if(typefd[nn->type->etype])
|
||||
r = FREGRET+NREG;
|
||||
nodreg(n, nn, r);
|
||||
reg[r]++;
|
||||
if(mode == 2) {
|
||||
// store value to be returned.
|
||||
// must compute arg offset.
|
||||
if(t->etype != TFUNC)
|
||||
fatal(Z, "bad regret func %T", t);
|
||||
*n = *nn;
|
||||
n->op = ONAME;
|
||||
n->class = CPARAM;
|
||||
n->sym = slookup(".ret");
|
||||
n->complex = nodret->complex;
|
||||
n->addable = 20;
|
||||
n->xoffset = argsize(0);
|
||||
return;
|
||||
}
|
||||
|
||||
fatal(Z, "bad regret");
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -260,7 +260,6 @@ cgen(Node *n, Node *res)
|
|||
case OOR:
|
||||
case OXOR:
|
||||
case OADD:
|
||||
case OADDPTR:
|
||||
case OMUL:
|
||||
a = optoas(n->op, nl->type);
|
||||
goto sbop;
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@ void allocparams(void);
|
|||
void checklabels(void);
|
||||
void ginscall(Node*, int);
|
||||
int gen_as_init(Node*);
|
||||
void clearslim(Node*);
|
||||
|
||||
/*
|
||||
* cgen.c
|
||||
|
|
|
|||
|
|
@ -614,11 +614,8 @@ ismem(Node *n)
|
|||
case ONAME:
|
||||
case OPARAM:
|
||||
case OCLOSUREVAR:
|
||||
return 1;
|
||||
case OADDR:
|
||||
//if(flag_largemodel)
|
||||
return 1;
|
||||
break;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1474,11 +1471,9 @@ optoas(int op, Type *t)
|
|||
case CASE(OADD, TINT32):
|
||||
case CASE(OADD, TUINT32):
|
||||
case CASE(OADD, TPTR32):
|
||||
case CASE(OADDPTR, TPTR32):
|
||||
case CASE(OADD, TINT64):
|
||||
case CASE(OADD, TUINT64):
|
||||
case CASE(OADD, TPTR64):
|
||||
case CASE(OADDPTR, TPTR64):
|
||||
a = AADD;
|
||||
break;
|
||||
|
||||
|
|
|
|||
|
|
@ -245,10 +245,10 @@ asmb(void)
|
|||
if(iself)
|
||||
goto ElfSym;
|
||||
case Hplan9:
|
||||
symo = HEADR+segtext.len+segdata.filelen;
|
||||
symo = segdata.fileoff+segdata.filelen;
|
||||
break;
|
||||
ElfSym:
|
||||
symo = rnd(HEADR+segtext.filelen, INITRND)+rnd(HEADR+segrodata.filelen, INITRND)+segdata.filelen;
|
||||
symo = segdata.fileoff+segdata.filelen;
|
||||
symo = rnd(symo, INITRND);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,17 +19,14 @@ package main
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"debug/elf"
|
||||
"debug/gosym"
|
||||
"debug/macho"
|
||||
"debug/pe"
|
||||
"debug/plan9obj"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"cmd/internal/objfile"
|
||||
)
|
||||
|
||||
func printUsage(w *os.File) {
|
||||
|
|
@ -60,18 +57,12 @@ func main() {
|
|||
usage()
|
||||
}
|
||||
|
||||
f, err := os.Open(flag.Arg(0))
|
||||
f, err := objfile.Open(flag.Arg(0))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
textStart, symtab, pclntab, err := loadTables(f)
|
||||
if err != nil {
|
||||
log.Fatalf("reading %s: %v", flag.Arg(0), err)
|
||||
}
|
||||
|
||||
pcln := gosym.NewLineTable(pclntab, textStart)
|
||||
tab, err := gosym.NewTable(symtab, pcln)
|
||||
tab, err := f.PCLineTable()
|
||||
if err != nil {
|
||||
log.Fatalf("reading %s: %v", flag.Arg(0), err)
|
||||
}
|
||||
|
|
@ -102,145 +93,3 @@ func main() {
|
|||
}
|
||||
stdout.Flush()
|
||||
}
|
||||
|
||||
func loadTables(f *os.File) (textStart uint64, symtab, pclntab []byte, err error) {
|
||||
if obj, err := elf.NewFile(f); err == nil {
|
||||
if sect := obj.Section(".text"); sect != nil {
|
||||
textStart = sect.Addr
|
||||
}
|
||||
if sect := obj.Section(".gosymtab"); sect != nil {
|
||||
if symtab, err = sect.Data(); err != nil {
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
}
|
||||
if sect := obj.Section(".gopclntab"); sect != nil {
|
||||
if pclntab, err = sect.Data(); err != nil {
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
}
|
||||
return textStart, symtab, pclntab, nil
|
||||
}
|
||||
|
||||
if obj, err := macho.NewFile(f); err == nil {
|
||||
if sect := obj.Section("__text"); sect != nil {
|
||||
textStart = sect.Addr
|
||||
}
|
||||
if sect := obj.Section("__gosymtab"); sect != nil {
|
||||
if symtab, err = sect.Data(); err != nil {
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
}
|
||||
if sect := obj.Section("__gopclntab"); sect != nil {
|
||||
if pclntab, err = sect.Data(); err != nil {
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
}
|
||||
return textStart, symtab, pclntab, nil
|
||||
}
|
||||
|
||||
if obj, err := pe.NewFile(f); err == nil {
|
||||
var imageBase uint64
|
||||
switch oh := obj.OptionalHeader.(type) {
|
||||
case *pe.OptionalHeader32:
|
||||
imageBase = uint64(oh.ImageBase)
|
||||
case *pe.OptionalHeader64:
|
||||
imageBase = oh.ImageBase
|
||||
default:
|
||||
return 0, nil, nil, fmt.Errorf("pe file format not recognized")
|
||||
}
|
||||
if sect := obj.Section(".text"); sect != nil {
|
||||
textStart = imageBase + uint64(sect.VirtualAddress)
|
||||
}
|
||||
if pclntab, err = loadPETable(obj, "pclntab", "epclntab"); err != nil {
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
if symtab, err = loadPETable(obj, "symtab", "esymtab"); err != nil {
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
return textStart, symtab, pclntab, nil
|
||||
}
|
||||
|
||||
if obj, err := plan9obj.NewFile(f); err == nil {
|
||||
textStart = obj.LoadAddress + obj.HdrSize
|
||||
if pclntab, err = loadPlan9Table(obj, "pclntab", "epclntab"); err != nil {
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
if symtab, err = loadPlan9Table(obj, "symtab", "esymtab"); err != nil {
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
return textStart, symtab, pclntab, nil
|
||||
}
|
||||
|
||||
return 0, nil, nil, fmt.Errorf("unrecognized binary format")
|
||||
}
|
||||
|
||||
func findPESymbol(f *pe.File, name string) (*pe.Symbol, error) {
|
||||
for _, s := range f.Symbols {
|
||||
if s.Name != name {
|
||||
continue
|
||||
}
|
||||
if s.SectionNumber <= 0 {
|
||||
return nil, fmt.Errorf("symbol %s: invalid section number %d", name, s.SectionNumber)
|
||||
}
|
||||
if len(f.Sections) < int(s.SectionNumber) {
|
||||
return nil, fmt.Errorf("symbol %s: section number %d is larger than max %d", name, s.SectionNumber, len(f.Sections))
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
return nil, fmt.Errorf("no %s symbol found", name)
|
||||
}
|
||||
|
||||
func loadPETable(f *pe.File, sname, ename string) ([]byte, error) {
|
||||
ssym, err := findPESymbol(f, sname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
esym, err := findPESymbol(f, ename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ssym.SectionNumber != esym.SectionNumber {
|
||||
return nil, fmt.Errorf("%s and %s symbols must be in the same section", sname, ename)
|
||||
}
|
||||
sect := f.Sections[ssym.SectionNumber-1]
|
||||
data, err := sect.Data()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data[ssym.Value:esym.Value], nil
|
||||
}
|
||||
|
||||
func findPlan9Symbol(f *plan9obj.File, name string) (*plan9obj.Sym, error) {
|
||||
syms, err := f.Symbols()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, s := range syms {
|
||||
if s.Name != name {
|
||||
continue
|
||||
}
|
||||
return &s, nil
|
||||
}
|
||||
return nil, fmt.Errorf("no %s symbol found", name)
|
||||
}
|
||||
|
||||
func loadPlan9Table(f *plan9obj.File, sname, ename string) ([]byte, error) {
|
||||
ssym, err := findPlan9Symbol(f, sname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
esym, err := findPlan9Symbol(f, ename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sect := f.Section("text")
|
||||
if sect == nil {
|
||||
return nil, err
|
||||
}
|
||||
data, err := sect.Data()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
textStart := f.LoadAddress + f.HdrSize
|
||||
return data[ssym.Value-textStart : esym.Value-textStart], nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -378,7 +378,51 @@ func (w *Walker) parseFile(dir, file string) (*ast.File, error) {
|
|||
}
|
||||
if w.context != nil && file == fmt.Sprintf("zruntime_defs_%s_%s.go", w.context.GOOS, w.context.GOARCH) {
|
||||
// Just enough to keep the api checker happy.
|
||||
src := "package runtime; type maptype struct{}; type _type struct{}; type alg struct{}; type mspan struct{}; type m struct{}; type lock struct{}; type slicetype struct{};"
|
||||
src := "package runtime; type (" +
|
||||
" _defer struct{};" +
|
||||
" _func struct{};" +
|
||||
" _panic struct{};" +
|
||||
" _select struct{}; " +
|
||||
" _type struct{};" +
|
||||
" alg struct{};" +
|
||||
" chantype struct{};" +
|
||||
" context struct{};" + // windows
|
||||
" eface struct{};" +
|
||||
" funcval struct{};" +
|
||||
" g struct{};" +
|
||||
" gobuf struct{};" +
|
||||
" hchan struct{};" +
|
||||
" iface struct{};" +
|
||||
" interfacetype struct{};" +
|
||||
" itab struct{};" +
|
||||
" m struct{};" +
|
||||
" maptype struct{};" +
|
||||
" mcache struct{};" +
|
||||
" mspan struct{};" +
|
||||
" mutex struct{};" +
|
||||
" note struct{};" +
|
||||
" slicetype struct{};" +
|
||||
" stkframe struct{};" +
|
||||
" sudog struct{};" +
|
||||
" waitq struct{};" +
|
||||
" wincallbackcontext struct{};" +
|
||||
" keventt struct{};" +
|
||||
" timespec struct{};" +
|
||||
" epollevent struct{};" +
|
||||
"); " +
|
||||
"const (" +
|
||||
" cb_max = 2000;" +
|
||||
" _CacheLineSize = 64;" +
|
||||
" _Gidle = 1;" +
|
||||
" _Grunnable = 2;" +
|
||||
" _Grunning = 3;" +
|
||||
" _Gsyscall = 4;" +
|
||||
" _Gwaiting = 5;" +
|
||||
" _Gdead = 6;" +
|
||||
" _Genqueue = 7;" +
|
||||
" _Gcopystack = 8;" +
|
||||
" _NSIG = 32;" +
|
||||
")"
|
||||
f, err = parser.ParseFile(fset, filename, src, 0)
|
||||
if err != nil {
|
||||
log.Fatalf("incorrect generated file: %s", err)
|
||||
|
|
|
|||
|
|
@ -98,11 +98,9 @@ func prepGoPath() string {
|
|||
if err == nil {
|
||||
username = u.Username
|
||||
} else {
|
||||
// Only need to handle Unix here, as Windows's os/user uses
|
||||
// native syscall and should work fine without cgo.
|
||||
username = os.Getenv("USER")
|
||||
if username == "" {
|
||||
log.Fatalf("Error getting current user: %v", err)
|
||||
username = "nobody"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -794,7 +794,7 @@ void xcom(Node*);
|
|||
int32 exreg(Type*);
|
||||
int32 align(int32, Type*, int, int32*);
|
||||
int32 maxround(int32, int32);
|
||||
int hasdotdotdot(void);
|
||||
int hasdotdotdot(Type*);
|
||||
void linkarchinit(void);
|
||||
|
||||
extern schar ewidth[];
|
||||
|
|
|
|||
|
|
@ -1043,6 +1043,7 @@ complex:
|
|||
}
|
||||
| LSTRUCT sbody
|
||||
{
|
||||
diag(Z, "struct must have tag");
|
||||
taggen++;
|
||||
sprint(symb, "_%d_", taggen);
|
||||
$$ = dotag(lookup(), TSTRUCT, autobn);
|
||||
|
|
|
|||
|
|
@ -697,7 +697,8 @@ argmark(Node *n, int pass)
|
|||
{
|
||||
Type *t;
|
||||
|
||||
autoffset = align(0, thisfn->link, Aarg0, nil);
|
||||
if(hasdotdotdot(thisfn->link))
|
||||
autoffset = align(0, thisfn->link, Aarg0, nil);
|
||||
stkoff = 0;
|
||||
for(; n->left != Z; n = n->left) {
|
||||
if(n->op != OFUNC || n->left->op != ONAME)
|
||||
|
|
@ -1401,6 +1402,10 @@ xdecl(int c, Type *t, Sym *s)
|
|||
}
|
||||
tmerge(t, s);
|
||||
s->type = t;
|
||||
if(c == CTYPEDEF && (typechlv[t->etype] || typefd[t->etype])) {
|
||||
s->type = copytyp(t);
|
||||
s->type->tag = s;
|
||||
}
|
||||
s->class = c;
|
||||
s->block = 0;
|
||||
s->offset = o;
|
||||
|
|
@ -1481,12 +1486,9 @@ edecl(int c, Type *t, Sym *s)
|
|||
{
|
||||
Type *t1;
|
||||
|
||||
if(s == S) {
|
||||
if(!typesu[t->etype])
|
||||
diag(Z, "unnamed structure element must be struct/union");
|
||||
if(c != CXXX)
|
||||
diag(Z, "unnamed structure element cannot have class");
|
||||
} else
|
||||
if(s == S)
|
||||
diag(Z, "unnamed structure elements not supported");
|
||||
else
|
||||
if(c != CXXX)
|
||||
diag(Z, "structure element cannot have class: %s", s->name);
|
||||
t1 = t;
|
||||
|
|
|
|||
|
|
@ -154,7 +154,6 @@ static void
|
|||
printtypename(Type *t)
|
||||
{
|
||||
Sym *s;
|
||||
Type *t1;
|
||||
int w;
|
||||
char *n;
|
||||
|
||||
|
|
@ -188,60 +187,27 @@ printtypename(Type *t)
|
|||
|
||||
switch(t->etype) {
|
||||
case TINT:
|
||||
Bprint(&outbuf, "int32");
|
||||
break;
|
||||
case TUINT:
|
||||
Bprint(&outbuf, "uint32");
|
||||
break;
|
||||
case TCHAR:
|
||||
Bprint(&outbuf, "int8");
|
||||
break;
|
||||
case TUCHAR:
|
||||
Bprint(&outbuf, "uint8");
|
||||
break;
|
||||
case TSHORT:
|
||||
Bprint(&outbuf, "int16");
|
||||
break;
|
||||
case TUSHORT:
|
||||
Bprint(&outbuf, "uint16");
|
||||
break;
|
||||
case TLONG:
|
||||
// The 32/64-bit ambiguous types (int,uint,uintptr)
|
||||
// are assigned a TLONG/TULONG to distinguish them
|
||||
// from always 32-bit types which get a TINT/TUINT.
|
||||
// (See int_x/uint_x in pkg/runtime/runtime.h.)
|
||||
// For LONG and VLONG types, we generate the
|
||||
// unqualified Go type when appropriate.
|
||||
// This makes it easier to write Go code that
|
||||
// modifies objects with autogenerated-from-C types.
|
||||
if(ewidth[TIND] == 4)
|
||||
Bprint(&outbuf, "int");
|
||||
else
|
||||
Bprint(&outbuf, "int32");
|
||||
break;
|
||||
case TULONG:
|
||||
if(ewidth[TIND] == 4)
|
||||
Bprint(&outbuf, "uint");
|
||||
else
|
||||
Bprint(&outbuf, "uint32");
|
||||
break;
|
||||
case TVLONG:
|
||||
if(ewidth[TIND] == 8)
|
||||
Bprint(&outbuf, "int");
|
||||
else
|
||||
Bprint(&outbuf, "int64");
|
||||
break;
|
||||
case TUVLONG:
|
||||
if(ewidth[TIND] == 8)
|
||||
Bprint(&outbuf, "uint");
|
||||
else
|
||||
Bprint(&outbuf, "uint64");
|
||||
break;
|
||||
case TFLOAT:
|
||||
Bprint(&outbuf, "float32");
|
||||
break;
|
||||
case TDOUBLE:
|
||||
Bprint(&outbuf, "float64");
|
||||
// All names used in the runtime code should be typedefs.
|
||||
if(t->tag != nil) {
|
||||
if(strcmp(t->tag->name, "intgo") == 0)
|
||||
Bprint(&outbuf, "int");
|
||||
else if(strcmp(t->tag->name, "uintgo") == 0)
|
||||
Bprint(&outbuf, "uint");
|
||||
else
|
||||
Bprint(&outbuf, "%s", t->tag->name);
|
||||
} else
|
||||
Bprint(&outbuf, "C.%T", t);
|
||||
break;
|
||||
case TUNION:
|
||||
case TSTRUCT:
|
||||
|
|
@ -251,27 +217,18 @@ printtypename(Type *t)
|
|||
n = s->name;
|
||||
else if(t->tag)
|
||||
n = t->tag->name;
|
||||
if(strcmp(n, "String") == 0){
|
||||
if(strcmp(n, "String") == 0)
|
||||
Bprint(&outbuf, "string");
|
||||
} else if(strcmp(n, "Slice") == 0){
|
||||
else if(strcmp(n, "Slice") == 0)
|
||||
Bprint(&outbuf, "[]byte");
|
||||
} else
|
||||
else if(strcmp(n, "Eface") == 0)
|
||||
Bprint(&outbuf, "interface{}");
|
||||
else
|
||||
Bprint(&outbuf, "%U", n);
|
||||
break;
|
||||
case TFUNC:
|
||||
Bprint(&outbuf, "func(");
|
||||
for(t1 = t->down; t1 != T; t1 = t1->down) {
|
||||
if(t1->etype == TVOID)
|
||||
break;
|
||||
if(t1 != t->down)
|
||||
Bprint(&outbuf, ", ");
|
||||
printtypename(t1);
|
||||
}
|
||||
Bprint(&outbuf, ")");
|
||||
if(t->link && t->link->etype != TVOID) {
|
||||
Bprint(&outbuf, " ");
|
||||
printtypename(t->link);
|
||||
}
|
||||
// There's no equivalent to a C function in the Go world.
|
||||
Bprint(&outbuf, "unsafe.Pointer");
|
||||
break;
|
||||
case TDOT:
|
||||
Bprint(&outbuf, "...interface{}");
|
||||
|
|
@ -360,9 +317,9 @@ godefvar(Sym *s)
|
|||
switch(t->etype) {
|
||||
case TENUM:
|
||||
if(!typefd[t->etype])
|
||||
Bprint(&outbuf, "const %U = %lld\n", s->name, s->vconst);
|
||||
Bprint(&outbuf, "const %s = %lld\n", s->name, s->vconst);
|
||||
else
|
||||
Bprint(&outbuf, "const %U = %f\n;", s->name, s->fconst);
|
||||
Bprint(&outbuf, "const %s = %f\n;", s->name, s->fconst);
|
||||
break;
|
||||
|
||||
case TFUNC:
|
||||
|
|
|
|||
|
|
@ -56,24 +56,24 @@ makefuncdatasym(char *namefmt, int64 funcdatakind)
|
|||
}
|
||||
|
||||
int
|
||||
hasdotdotdot(void)
|
||||
hasdotdotdot(Type *t)
|
||||
{
|
||||
Type *t;
|
||||
|
||||
for(t=thisfn->down; t!=T; t=t->down)
|
||||
for(t=t->down; t!=T; t=t->down)
|
||||
if(t->etype == TDOT)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
vlong
|
||||
argsize(void)
|
||||
argsize(int doret)
|
||||
{
|
||||
Type *t;
|
||||
int32 s;
|
||||
|
||||
//print("t=%T\n", thisfn);
|
||||
s = align(0, thisfn->link, Aarg0, nil);
|
||||
s = 0;
|
||||
if(hasdotdotdot(thisfn))
|
||||
s = align(s, thisfn->link, Aarg0, nil);
|
||||
for(t=thisfn->down; t!=T; t=t->down) {
|
||||
switch(t->etype) {
|
||||
case TVOID:
|
||||
|
|
@ -93,6 +93,14 @@ argsize(void)
|
|||
s = (s+7) & ~7;
|
||||
else
|
||||
s = (s+3) & ~3;
|
||||
if(doret && thisfn->link->etype != TVOID) {
|
||||
s = align(s, thisfn->link, Aarg1, nil);
|
||||
s = align(s, thisfn->link, Aarg2, nil);
|
||||
if(thechar == '6')
|
||||
s = (s+7) & ~7;
|
||||
else
|
||||
s = (s+3) & ~3;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
|
@ -123,13 +131,14 @@ codgen(Node *n, Node *nn)
|
|||
nearln = nn->lineno;
|
||||
|
||||
p = gtext(n1->sym, stkoff);
|
||||
p->from.sym->cfunc = 1;
|
||||
sp = p;
|
||||
|
||||
/*
|
||||
* generate funcdata symbol for this function.
|
||||
* data is filled in at the end of codgen().
|
||||
*/
|
||||
isvarargs = hasdotdotdot();
|
||||
isvarargs = hasdotdotdot(thisfn);
|
||||
gcargs = nil;
|
||||
if(!isvarargs)
|
||||
gcargs = makefuncdatasym("gcargs·%d", FUNCDATA_ArgsPointerMaps);
|
||||
|
|
@ -212,7 +221,7 @@ supgen(Node *n)
|
|||
void
|
||||
gen(Node *n)
|
||||
{
|
||||
Node *l, nod;
|
||||
Node *l, nod, nod1;
|
||||
Prog *sp, *spc, *spb;
|
||||
Case *cn;
|
||||
long sbc, scc;
|
||||
|
|
@ -273,14 +282,26 @@ loop:
|
|||
gbranch(ORETURN);
|
||||
break;
|
||||
}
|
||||
if(typecmplx[n->type->etype] && !hasdotdotdot(thisfn)) {
|
||||
regret(&nod, n, thisfn, 2);
|
||||
sugen(l, &nod, n->type->width);
|
||||
noretval(3);
|
||||
gbranch(ORETURN);
|
||||
break;
|
||||
}
|
||||
if(typecmplx[n->type->etype]) {
|
||||
sugen(l, nodret, n->type->width);
|
||||
noretval(3);
|
||||
gbranch(ORETURN);
|
||||
break;
|
||||
}
|
||||
regret(&nod, n);
|
||||
regret(&nod1, n, thisfn, 2);
|
||||
nod = nod1;
|
||||
if(nod.op != OREGISTER)
|
||||
regalloc(&nod, n, Z);
|
||||
cgen(l, &nod);
|
||||
if(nod1.op != OREGISTER)
|
||||
gmove(&nod, &nod1);
|
||||
regfree(&nod);
|
||||
if(typefd[n->type->etype])
|
||||
noretval(1);
|
||||
|
|
@ -729,9 +750,11 @@ dumpgcargs(Type *fn, Sym *sym)
|
|||
symoffset = 0;
|
||||
gextern(sym, nodconst(1), symoffset, 4);
|
||||
symoffset += 4;
|
||||
argbytes = (argsize() + ewidth[TIND] - 1);
|
||||
argbytes = (argsize(1) + ewidth[TIND] - 1);
|
||||
bv = bvalloc((argbytes / ewidth[TIND]) * BitsPerPointer);
|
||||
argoffset = align(0, fn->link, Aarg0, nil);
|
||||
argoffset = 0;
|
||||
if(hasdotdotdot(thisfn))
|
||||
argoffset = align(0, fn->link, Aarg0, nil);
|
||||
if(argoffset > 0) {
|
||||
// The C calling convention returns structs by copying them to a
|
||||
// location pointed to by a hidden first argument. This first
|
||||
|
|
|
|||
|
|
@ -229,7 +229,8 @@ func (p *Package) guessKinds(f *File) []*Name {
|
|||
// Determine kinds for names we already know about,
|
||||
// like #defines or 'struct foo', before bothering with gcc.
|
||||
var names, needType []*Name
|
||||
for _, n := range f.Name {
|
||||
for _, key := range nameKeys(f.Name) {
|
||||
n := f.Name[key]
|
||||
// If we've already found this name as a #define
|
||||
// and we can translate it as a constant value, do so.
|
||||
if n.Define != "" {
|
||||
|
|
@ -331,6 +332,7 @@ func (p *Package) guessKinds(f *File) []*Name {
|
|||
const (
|
||||
notType = 1 << iota
|
||||
notConst
|
||||
notDeclared
|
||||
)
|
||||
for _, line := range strings.Split(stderr, "\n") {
|
||||
if !strings.Contains(line, ": error:") {
|
||||
|
|
@ -365,7 +367,7 @@ func (p *Package) guessKinds(f *File) []*Name {
|
|||
completed = true
|
||||
|
||||
case "not-declared":
|
||||
error_(token.NoPos, "%s", strings.TrimSpace(line[c2+1:]))
|
||||
sniff[i] |= notDeclared
|
||||
case "not-type":
|
||||
sniff[i] |= notType
|
||||
case "not-const":
|
||||
|
|
@ -374,12 +376,12 @@ func (p *Package) guessKinds(f *File) []*Name {
|
|||
}
|
||||
|
||||
if !completed {
|
||||
fatalf("%s did not produce error at completed:1\non input:\n%s", p.gccBaseCmd()[0], b.Bytes())
|
||||
fatalf("%s did not produce error at completed:1\non input:\n%s\nfull error output:\n%s", p.gccBaseCmd()[0], b.Bytes(), stderr)
|
||||
}
|
||||
|
||||
for i, n := range names {
|
||||
switch sniff[i] {
|
||||
case 0:
|
||||
default:
|
||||
error_(token.NoPos, "could not determine kind of name for C.%s", fixGo(n.Go))
|
||||
case notType:
|
||||
n.Kind = "const"
|
||||
|
|
@ -390,6 +392,14 @@ func (p *Package) guessKinds(f *File) []*Name {
|
|||
}
|
||||
}
|
||||
if nerrors > 0 {
|
||||
// Check if compiling the preamble by itself causes any errors,
|
||||
// because the messages we've printed out so far aren't helpful
|
||||
// to users debugging preamble mistakes. See issue 8442.
|
||||
preambleErrors := p.gccErrors([]byte(f.Preamble))
|
||||
if len(preambleErrors) > 0 {
|
||||
error_(token.NoPos, "\n%s errors for preamble:\n%s", p.gccBaseCmd()[0], preambleErrors)
|
||||
}
|
||||
|
||||
fatalf("unresolved names")
|
||||
}
|
||||
|
||||
|
|
@ -649,7 +659,13 @@ func (p *Package) rewriteRef(f *File) {
|
|||
f.Name[fpName] = name
|
||||
}
|
||||
r.Name = name
|
||||
expr = ast.NewIdent(name.Mangle)
|
||||
// Rewrite into call to _Cgo_ptr to prevent assignments. The _Cgo_ptr
|
||||
// function is defined in out.go and simply returns its argument. See
|
||||
// issue 7757.
|
||||
expr = &ast.CallExpr{
|
||||
Fun: &ast.Ident{NamePos: (*r.Expr).Pos(), Name: "_Cgo_ptr"},
|
||||
Args: []ast.Expr{ast.NewIdent(name.Mangle)},
|
||||
}
|
||||
} else if r.Name.Kind == "type" {
|
||||
// Okay - might be new(T)
|
||||
expr = r.Name.Type.Go
|
||||
|
|
@ -1068,12 +1084,6 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
|||
return t
|
||||
}
|
||||
|
||||
// clang won't generate DW_AT_byte_size for pointer types,
|
||||
// so we have to fix it here.
|
||||
if dt, ok := base(dtype).(*dwarf.PtrType); ok && dt.ByteSize == -1 {
|
||||
dt.ByteSize = c.ptrSize
|
||||
}
|
||||
|
||||
t := new(Type)
|
||||
t.Size = dtype.Size() // note: wrong for array of pointers, corrected below
|
||||
t.Align = -1
|
||||
|
|
@ -1097,12 +1107,20 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
|||
t.Go = c.Opaque(t.Size)
|
||||
break
|
||||
}
|
||||
count := dt.Count
|
||||
if count == -1 {
|
||||
// Indicates flexible array member, which Go doesn't support.
|
||||
// Translate to zero-length array instead.
|
||||
count = 0
|
||||
}
|
||||
sub := c.Type(dt.Type, pos)
|
||||
t.Align = sub.Align
|
||||
t.Go = &ast.ArrayType{
|
||||
Len: c.intExpr(dt.Count),
|
||||
Len: c.intExpr(count),
|
||||
Elt: sub.Go,
|
||||
}
|
||||
// Recalculate t.Size now that we know sub.Size.
|
||||
t.Size = count * sub.Size
|
||||
t.C.Set("__typeof__(%s[%d])", sub.C, dt.Count)
|
||||
|
||||
case *dwarf.BoolType:
|
||||
|
|
@ -1203,6 +1221,11 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
|||
}
|
||||
|
||||
case *dwarf.PtrType:
|
||||
// Clang doesn't emit DW_AT_byte_size for pointer types.
|
||||
if t.Size != c.ptrSize && t.Size != -1 {
|
||||
fatalf("%s: unexpected: %d-byte pointer type - %s", lineno(pos), t.Size, dtype)
|
||||
}
|
||||
t.Size = c.ptrSize
|
||||
t.Align = c.ptrSize
|
||||
|
||||
if _, ok := base(dt.Type).(*dwarf.VoidType); ok {
|
||||
|
|
@ -1374,34 +1397,24 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
|||
}
|
||||
}
|
||||
|
||||
if t.Size <= 0 {
|
||||
// Clang does not record the size of a pointer in its DWARF entry,
|
||||
// so if dtype is an array, the call to dtype.Size at the top of the function
|
||||
// computed the size as the array length * 0 = 0.
|
||||
// The type switch called Type (this function) recursively on the pointer
|
||||
// entry, and the code near the top of the function updated the size to
|
||||
// be correct, so calling dtype.Size again will produce the correct value.
|
||||
t.Size = dtype.Size()
|
||||
if t.Size < 0 {
|
||||
// Unsized types are [0]byte, unless they're typedefs of other types
|
||||
// or structs with tags.
|
||||
// if so, use the name we've already defined.
|
||||
t.Size = 0
|
||||
switch dt := dtype.(type) {
|
||||
case *dwarf.TypedefType:
|
||||
// ok
|
||||
case *dwarf.StructType:
|
||||
if dt.StructName != "" {
|
||||
break
|
||||
}
|
||||
t.Go = c.Opaque(0)
|
||||
default:
|
||||
t.Go = c.Opaque(0)
|
||||
if t.Size < 0 {
|
||||
// Unsized types are [0]byte, unless they're typedefs of other types
|
||||
// or structs with tags.
|
||||
// if so, use the name we've already defined.
|
||||
t.Size = 0
|
||||
switch dt := dtype.(type) {
|
||||
case *dwarf.TypedefType:
|
||||
// ok
|
||||
case *dwarf.StructType:
|
||||
if dt.StructName != "" {
|
||||
break
|
||||
}
|
||||
if t.C.Empty() {
|
||||
t.C.Set("void")
|
||||
}
|
||||
return t
|
||||
t.Go = c.Opaque(0)
|
||||
default:
|
||||
t.Go = c.Opaque(0)
|
||||
}
|
||||
if t.C.Empty() {
|
||||
t.C.Set("void")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1533,6 +1546,9 @@ func (c *typeConv) pad(fld []*ast.Field, size int64) []*ast.Field {
|
|||
|
||||
// Struct conversion: return Go and (6g) C syntax for type.
|
||||
func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.StructType, csyntax string, align int64) {
|
||||
// Minimum alignment for a struct is 1 byte.
|
||||
align = 1
|
||||
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString("struct {")
|
||||
fld := make([]*ast.Field, 0, 2*len(dt.Field)+1) // enough for padding around every field
|
||||
|
|
|
|||
|
|
@ -58,16 +58,14 @@ func (p *Package) writeDefs() {
|
|||
fmt.Fprintf(fgo2, "// Created by cgo - DO NOT EDIT\n\n")
|
||||
fmt.Fprintf(fgo2, "package %s\n\n", p.PackageName)
|
||||
fmt.Fprintf(fgo2, "import \"unsafe\"\n\n")
|
||||
if *importSyscall {
|
||||
fmt.Fprintf(fgo2, "import \"syscall\"\n\n")
|
||||
}
|
||||
if !*gccgo && *importRuntimeCgo {
|
||||
fmt.Fprintf(fgo2, "import _ \"runtime/cgo\"\n\n")
|
||||
}
|
||||
fmt.Fprintf(fgo2, "type _ unsafe.Pointer\n\n")
|
||||
if *importSyscall {
|
||||
fmt.Fprintf(fgo2, "func _Cerrno(dst *error, x int32) { *dst = syscall.Errno(x) }\n")
|
||||
fmt.Fprintf(fgo2, "import \"syscall\"\n\n")
|
||||
fmt.Fprintf(fgo2, "var _ syscall.Errno\n")
|
||||
}
|
||||
fmt.Fprintf(fgo2, "func _Cgo_ptr(ptr unsafe.Pointer) unsafe.Pointer { return ptr }\n\n")
|
||||
|
||||
typedefNames := make([]string, 0, len(typedef))
|
||||
for name := range typedef {
|
||||
|
|
@ -87,9 +85,10 @@ func (p *Package) writeDefs() {
|
|||
}
|
||||
|
||||
if *gccgo {
|
||||
fmt.Fprintf(fc, p.cPrologGccgo())
|
||||
fmt.Fprint(fc, p.cPrologGccgo())
|
||||
} else {
|
||||
fmt.Fprintf(fc, cProlog)
|
||||
fmt.Fprint(fc, cProlog)
|
||||
fmt.Fprint(fgo2, goProlog)
|
||||
}
|
||||
|
||||
gccgoSymbolPrefix := p.gccgoSymbolPrefix()
|
||||
|
|
@ -296,10 +295,6 @@ func (p *Package) structType(n *Name) (string, int64) {
|
|||
fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
|
||||
off += pad
|
||||
}
|
||||
if n.AddError {
|
||||
fmt.Fprint(&buf, "\t\tint e[2*sizeof(void *)/sizeof(int)]; /* error */\n")
|
||||
off += 2 * p.PtrSize
|
||||
}
|
||||
if off == 0 {
|
||||
fmt.Fprintf(&buf, "\t\tchar unused;\n") // avoid empty struct
|
||||
}
|
||||
|
|
@ -334,19 +329,18 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
|
|||
}
|
||||
|
||||
// Builtins defined in the C prolog.
|
||||
inProlog := name == "CString" || name == "GoString" || name == "GoStringN" || name == "GoBytes" || name == "_CMalloc"
|
||||
inProlog := builtinDefs[name] != ""
|
||||
cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle)
|
||||
paramnames := []string(nil)
|
||||
for i, param := range d.Type.Params.List {
|
||||
paramName := fmt.Sprintf("p%d", i)
|
||||
param.Names = []*ast.Ident{ast.NewIdent(paramName)}
|
||||
paramnames = append(paramnames, paramName)
|
||||
}
|
||||
|
||||
if *gccgo {
|
||||
// Gccgo style hooks.
|
||||
fmt.Fprint(fgo2, "\n")
|
||||
cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle)
|
||||
paramnames := []string(nil)
|
||||
for i, param := range d.Type.Params.List {
|
||||
paramName := fmt.Sprintf("p%d", i)
|
||||
param.Names = []*ast.Ident{ast.NewIdent(paramName)}
|
||||
paramnames = append(paramnames, paramName)
|
||||
}
|
||||
|
||||
conf.Fprint(fgo2, fset, d)
|
||||
fmt.Fprint(fgo2, " {\n")
|
||||
if !inProlog {
|
||||
|
|
@ -383,7 +377,7 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
|
|||
fmt.Fprint(fgo2, "}\n")
|
||||
|
||||
// declare the C function.
|
||||
fmt.Fprintf(fgo2, "//extern _cgo%s%s\n", cPrefix, n.Mangle)
|
||||
fmt.Fprintf(fgo2, "//extern %s\n", cname)
|
||||
d.Name = ast.NewIdent(cname)
|
||||
if n.AddError {
|
||||
l := d.Type.Results.List
|
||||
|
|
@ -394,61 +388,49 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
|
|||
|
||||
return
|
||||
}
|
||||
conf.Fprint(fgo2, fset, d)
|
||||
fmt.Fprint(fgo2, "\n")
|
||||
|
||||
if inProlog {
|
||||
fmt.Fprint(fgo2, builtinDefs[name])
|
||||
return
|
||||
}
|
||||
|
||||
var argSize int64
|
||||
_, argSize = p.structType(n)
|
||||
|
||||
// C wrapper calls into gcc, passing a pointer to the argument frame.
|
||||
fmt.Fprintf(fc, "#pragma cgo_import_static _cgo%s%s\n", cPrefix, n.Mangle)
|
||||
fmt.Fprintf(fc, "void _cgo%s%s(void*);\n", cPrefix, n.Mangle)
|
||||
fmt.Fprintf(fc, "\n")
|
||||
fmt.Fprintf(fc, "void\n")
|
||||
if argSize == 0 {
|
||||
argSize++
|
||||
fmt.Fprintf(fc, "#pragma cgo_import_static %s\n", cname)
|
||||
fmt.Fprintf(fc, "void %s(void*);\n", cname)
|
||||
fmt.Fprintf(fc, "void *·%s = %s;\n", cname, cname)
|
||||
|
||||
nret := 0
|
||||
if !void {
|
||||
d.Type.Results.List[0].Names = []*ast.Ident{ast.NewIdent("r1")}
|
||||
nret = 1
|
||||
}
|
||||
// TODO(rsc): The struct here should declare pointers only where
|
||||
// there are pointers in the actual argument frame.
|
||||
// This is a workaround for golang.org/issue/6397.
|
||||
fmt.Fprintf(fc, "·%s(struct{", n.Mangle)
|
||||
if n := argSize / p.PtrSize; n > 0 {
|
||||
fmt.Fprintf(fc, "void *y[%d];", n)
|
||||
}
|
||||
if n := argSize % p.PtrSize; n > 0 {
|
||||
fmt.Fprintf(fc, "uint8 x[%d];", n)
|
||||
}
|
||||
fmt.Fprintf(fc, "}p)\n")
|
||||
fmt.Fprintf(fc, "{\n")
|
||||
fmt.Fprintf(fc, "\truntime·cgocall(_cgo%s%s, &p);\n", cPrefix, n.Mangle)
|
||||
if n.AddError {
|
||||
// gcc leaves errno in first word of interface at end of p.
|
||||
// check whether it is zero; if so, turn interface into nil.
|
||||
// if not, turn interface into errno.
|
||||
// Go init function initializes ·_Cerrno with an os.Errno
|
||||
// for us to copy.
|
||||
fmt.Fprintln(fc, ` {
|
||||
int32 e;
|
||||
void **v;
|
||||
v = (void**)(&p+1) - 2; /* v = final two void* of p */
|
||||
e = *(int32*)v;
|
||||
v[0] = (void*)0xdeadbeef;
|
||||
v[1] = (void*)0xdeadbeef;
|
||||
if(e == 0) {
|
||||
/* nil interface */
|
||||
v[0] = 0;
|
||||
v[1] = 0;
|
||||
} else {
|
||||
·_Cerrno(v, e); /* fill in v as error for errno e */
|
||||
}
|
||||
}`)
|
||||
d.Type.Results.List[nret].Names = []*ast.Ident{ast.NewIdent("r2")}
|
||||
}
|
||||
fmt.Fprintf(fc, "}\n")
|
||||
fmt.Fprintf(fc, "\n")
|
||||
|
||||
fmt.Fprint(fgo2, "\n")
|
||||
fmt.Fprintf(fgo2, "var %s unsafe.Pointer\n", cname)
|
||||
conf.Fprint(fgo2, fset, d)
|
||||
fmt.Fprint(fgo2, " {\n")
|
||||
|
||||
// NOTE: Using uintptr to hide from escape analysis.
|
||||
arg := "0"
|
||||
if len(paramnames) > 0 {
|
||||
arg = "uintptr(unsafe.Pointer(&p0))"
|
||||
} else if !void {
|
||||
arg = "uintptr(unsafe.Pointer(&r1))"
|
||||
}
|
||||
|
||||
prefix := ""
|
||||
if n.AddError {
|
||||
prefix = "errno := "
|
||||
}
|
||||
fmt.Fprintf(fgo2, "\t%s_cgo_runtime_cgocall_errno(%s, %s)\n", prefix, cname, arg)
|
||||
if n.AddError {
|
||||
fmt.Fprintf(fgo2, "\tif errno != 0 { r2 = syscall.Errno(errno) }\n")
|
||||
}
|
||||
fmt.Fprintf(fgo2, "\treturn\n")
|
||||
fmt.Fprintf(fgo2, "}\n")
|
||||
}
|
||||
|
||||
// writeOutput creates stubs for a specific source file to be compiled by 6g
|
||||
|
|
@ -521,7 +503,11 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
|
|||
|
||||
// Gcc wrapper unpacks the C argument struct
|
||||
// and calls the actual C function.
|
||||
fmt.Fprintf(fgcc, "void\n")
|
||||
if n.AddError {
|
||||
fmt.Fprintf(fgcc, "int\n")
|
||||
} else {
|
||||
fmt.Fprintf(fgcc, "void\n")
|
||||
}
|
||||
fmt.Fprintf(fgcc, "_cgo%s%s(void *v)\n", cPrefix, n.Mangle)
|
||||
fmt.Fprintf(fgcc, "{\n")
|
||||
if n.AddError {
|
||||
|
|
@ -557,7 +543,7 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
|
|||
}
|
||||
fmt.Fprintf(fgcc, ");\n")
|
||||
if n.AddError {
|
||||
fmt.Fprintf(fgcc, "\t*(int*)(a->e) = errno;\n")
|
||||
fmt.Fprintf(fgcc, "\treturn errno;\n")
|
||||
}
|
||||
fmt.Fprintf(fgcc, "}\n")
|
||||
fmt.Fprintf(fgcc, "\n")
|
||||
|
|
@ -1166,46 +1152,74 @@ const cProlog = `
|
|||
#include "runtime.h"
|
||||
#include "cgocall.h"
|
||||
|
||||
static void *cgocall_errno = runtime·cgocall_errno;
|
||||
void *·_cgo_runtime_cgocall_errno = &cgocall_errno;
|
||||
|
||||
static void *runtime_gostring = runtime·gostring;
|
||||
void *·_cgo_runtime_gostring = &runtime_gostring;
|
||||
|
||||
static void *runtime_gostringn = runtime·gostringn;
|
||||
void *·_cgo_runtime_gostringn = &runtime_gostringn;
|
||||
|
||||
static void *runtime_gobytes = runtime·gobytes;
|
||||
void *·_cgo_runtime_gobytes = &runtime_gobytes;
|
||||
|
||||
static void *runtime_cmalloc = runtime·cmalloc;
|
||||
void *·_cgo_runtime_cmalloc = &runtime_cmalloc;
|
||||
|
||||
void ·_Cerrno(void*, int32);
|
||||
`
|
||||
|
||||
void
|
||||
·_Cfunc_GoString(int8 *p, String s)
|
||||
{
|
||||
s = runtime·gostring((byte*)p);
|
||||
FLUSH(&s);
|
||||
}
|
||||
const goProlog = `
|
||||
var _cgo_runtime_cgocall_errno func(unsafe.Pointer, uintptr) int32
|
||||
var _cgo_runtime_cmalloc func(uintptr) unsafe.Pointer
|
||||
`
|
||||
|
||||
void
|
||||
·_Cfunc_GoStringN(int8 *p, int32 l, String s)
|
||||
{
|
||||
s = runtime·gostringn((byte*)p, l);
|
||||
FLUSH(&s);
|
||||
}
|
||||
|
||||
void
|
||||
·_Cfunc_GoBytes(int8 *p, int32 l, Slice s)
|
||||
{
|
||||
s = runtime·gobytes((byte*)p, l);
|
||||
FLUSH(&s);
|
||||
}
|
||||
|
||||
void
|
||||
·_Cfunc_CString(String s, int8 *p)
|
||||
{
|
||||
p = runtime·cmalloc(s.len+1);
|
||||
runtime·memmove((byte*)p, s.str, s.len);
|
||||
p[s.len] = 0;
|
||||
FLUSH(&p);
|
||||
}
|
||||
|
||||
void
|
||||
·_Cfunc__CMalloc(uintptr n, int8 *p)
|
||||
{
|
||||
p = runtime·cmalloc(n);
|
||||
FLUSH(&p);
|
||||
const goStringDef = `
|
||||
var _cgo_runtime_gostring func(*_Ctype_char) string
|
||||
func _Cfunc_GoString(p *_Ctype_char) string {
|
||||
return _cgo_runtime_gostring(p)
|
||||
}
|
||||
`
|
||||
|
||||
const goStringNDef = `
|
||||
var _cgo_runtime_gostringn func(*_Ctype_char, int) string
|
||||
func _Cfunc_GoStringN(p *_Ctype_char, l _Ctype_int) string {
|
||||
return _cgo_runtime_gostringn(p, int(l))
|
||||
}
|
||||
`
|
||||
|
||||
const goBytesDef = `
|
||||
var _cgo_runtime_gobytes func(unsafe.Pointer, int) []byte
|
||||
func _Cfunc_GoBytes(p unsafe.Pointer, l _Ctype_int) []byte {
|
||||
return _cgo_runtime_gobytes(p, int(l))
|
||||
}
|
||||
`
|
||||
|
||||
const cStringDef = `
|
||||
func _Cfunc_CString(s string) *_Ctype_char {
|
||||
p := _cgo_runtime_cmalloc(uintptr(len(s)+1))
|
||||
pp := (*[1<<30]byte)(p)
|
||||
copy(pp[:], s)
|
||||
pp[len(s)] = 0
|
||||
return (*_Ctype_char)(p)
|
||||
}
|
||||
`
|
||||
|
||||
const cMallocDef = `
|
||||
func _Cfunc__CMalloc(n _Ctype_size_t) unsafe.Pointer {
|
||||
return _cgo_runtime_cmalloc(uintptr(n))
|
||||
}
|
||||
`
|
||||
|
||||
var builtinDefs = map[string]string{
|
||||
"GoString": goStringDef,
|
||||
"GoStringN": goStringNDef,
|
||||
"GoBytes": goBytesDef,
|
||||
"CString": cStringDef,
|
||||
"_CMalloc": cMallocDef,
|
||||
}
|
||||
|
||||
func (p *Package) cPrologGccgo() string {
|
||||
return strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,9 +108,6 @@ void mkzexperiment(char*, char*);
|
|||
// buildgo.c
|
||||
void mkzdefaultcc(char*, char*);
|
||||
|
||||
// goc2c.c
|
||||
void goc2c(char*, char*);
|
||||
|
||||
// main.c
|
||||
extern int vflag;
|
||||
extern int sflag;
|
||||
|
|
@ -129,6 +126,7 @@ bool isfile(char *p);
|
|||
char* lastelem(char*);
|
||||
Time mtime(char*);
|
||||
void readfile(Buf*, char*);
|
||||
void copyfile(char*, char*, int);
|
||||
void run(Buf *b, char *dir, int mode, char *cmd, ...);
|
||||
void runv(Buf *b, char *dir, int mode, Vec *argv);
|
||||
void bgrunv(char *dir, int mode, Vec *argv);
|
||||
|
|
|
|||
|
|
@ -202,7 +202,7 @@ vadd(Vec *v, char *p)
|
|||
}
|
||||
|
||||
// vaddn adds a string consisting of the n bytes at p to the vector.
|
||||
void
|
||||
static void
|
||||
vaddn(Vec *v, char *p, int n)
|
||||
{
|
||||
char *q;
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ bool rebuildall;
|
|||
bool defaultclang;
|
||||
|
||||
static bool shouldbuild(char*, char*);
|
||||
static void copy(char*, char*, int);
|
||||
static void dopack(char*, char*, char**, int);
|
||||
static char *findgoversion(void);
|
||||
|
||||
|
|
@ -628,7 +627,6 @@ char *depsuffix[] = {
|
|||
".h",
|
||||
".s",
|
||||
".go",
|
||||
".goc",
|
||||
};
|
||||
|
||||
// gentab records how to generate some trivial files.
|
||||
|
|
@ -661,7 +659,7 @@ install(char *dir)
|
|||
{
|
||||
char *name, *p, *elem, *prefix, *exe;
|
||||
bool islib, ispkg, isgo, stale, ispackcmd;
|
||||
Buf b, b1, path;
|
||||
Buf b, b1, path, final_path, final_name;
|
||||
Vec compile, files, link, go, missing, clean, lib, extra;
|
||||
Time ttarg, t;
|
||||
int i, j, k, n, doclean, targ;
|
||||
|
|
@ -676,6 +674,8 @@ install(char *dir)
|
|||
binit(&b);
|
||||
binit(&b1);
|
||||
binit(&path);
|
||||
binit(&final_path);
|
||||
binit(&final_name);
|
||||
vinit(&compile);
|
||||
vinit(&files);
|
||||
vinit(&link);
|
||||
|
|
@ -688,11 +688,12 @@ install(char *dir)
|
|||
|
||||
// path = full path to dir.
|
||||
bpathf(&path, "%s/src/%s", goroot, dir);
|
||||
bpathf(&final_path, "%s/src/%s", goroot_final, dir);
|
||||
name = lastelem(dir);
|
||||
|
||||
// For misc/prof, copy into the tool directory and we're done.
|
||||
if(hasprefix(dir, "misc/")) {
|
||||
copy(bpathf(&b, "%s/%s", tooldir, name),
|
||||
copyfile(bpathf(&b, "%s/%s", tooldir, name),
|
||||
bpathf(&b1, "%s/misc/%s", goroot, name), 1);
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -904,17 +905,19 @@ install(char *dir)
|
|||
|
||||
// For package runtime, copy some files into the work space.
|
||||
if(streq(dir, "pkg/runtime")) {
|
||||
copy(bpathf(&b, "%s/arch_GOARCH.h", workdir),
|
||||
copyfile(bpathf(&b, "%s/arch_GOARCH.h", workdir),
|
||||
bpathf(&b1, "%s/arch_%s.h", bstr(&path), goarch), 0);
|
||||
copy(bpathf(&b, "%s/defs_GOOS_GOARCH.h", workdir),
|
||||
copyfile(bpathf(&b, "%s/defs_GOOS_GOARCH.h", workdir),
|
||||
bpathf(&b1, "%s/defs_%s_%s.h", bstr(&path), goos, goarch), 0);
|
||||
p = bpathf(&b1, "%s/signal_%s_%s.h", bstr(&path), goos, goarch);
|
||||
if(isfile(p))
|
||||
copy(bpathf(&b, "%s/signal_GOOS_GOARCH.h", workdir), p, 0);
|
||||
copy(bpathf(&b, "%s/os_GOOS.h", workdir),
|
||||
copyfile(bpathf(&b, "%s/signal_GOOS_GOARCH.h", workdir), p, 0);
|
||||
copyfile(bpathf(&b, "%s/os_GOOS.h", workdir),
|
||||
bpathf(&b1, "%s/os_%s.h", bstr(&path), goos), 0);
|
||||
copy(bpathf(&b, "%s/signals_GOOS.h", workdir),
|
||||
copyfile(bpathf(&b, "%s/signals_GOOS.h", workdir),
|
||||
bpathf(&b1, "%s/signals_%s.h", bstr(&path), goos), 0);
|
||||
copyfile(bpathf(&b, "%s/pkg/%s_%s/textflag.h", goroot, goos, goarch),
|
||||
bpathf(&b1, "%s/src/cmd/ld/textflag.h", goroot), 0);
|
||||
}
|
||||
|
||||
// Generate any missing files; regenerate existing ones.
|
||||
|
|
@ -948,26 +951,10 @@ install(char *dir)
|
|||
// The last batch was required for the generators.
|
||||
// This one is generated.
|
||||
if(streq(dir, "pkg/runtime")) {
|
||||
copy(bpathf(&b, "%s/zasm_GOOS_GOARCH.h", workdir),
|
||||
copyfile(bpathf(&b, "%s/zasm_GOOS_GOARCH.h", workdir),
|
||||
bpathf(&b1, "%s/zasm_%s_%s.h", bstr(&path), goos, goarch), 0);
|
||||
}
|
||||
|
||||
// Generate .c files from .goc files.
|
||||
if(streq(dir, "pkg/runtime")) {
|
||||
for(i=0; i<files.len; i++) {
|
||||
p = files.p[i];
|
||||
if(!hassuffix(p, ".goc"))
|
||||
continue;
|
||||
// b = path/zp but with _goos_goarch.c instead of .goc
|
||||
bprintf(&b, "%s%sz%s", bstr(&path), slash, lastelem(p));
|
||||
b.len -= 4;
|
||||
bwritef(&b, "_%s_%s.c", goos, goarch);
|
||||
goc2c(p, bstr(&b));
|
||||
vadd(&files, bstr(&b));
|
||||
}
|
||||
vuniq(&files);
|
||||
}
|
||||
|
||||
if((!streq(goos, gohostos) || !streq(goarch, gohostarch)) && isgo) {
|
||||
// We've generated the right files; the go command can do the build.
|
||||
if(vflag > 1)
|
||||
|
|
@ -1138,9 +1125,9 @@ nobuild:
|
|||
// In package runtime, we install runtime.h and cgocall.h too,
|
||||
// for use by cgo compilation.
|
||||
if(streq(dir, "pkg/runtime")) {
|
||||
copy(bpathf(&b, "%s/pkg/%s_%s/cgocall.h", goroot, goos, goarch),
|
||||
copyfile(bpathf(&b, "%s/pkg/%s_%s/cgocall.h", goroot, goos, goarch),
|
||||
bpathf(&b1, "%s/src/pkg/runtime/cgocall.h", goroot), 0);
|
||||
copy(bpathf(&b, "%s/pkg/%s_%s/runtime.h", goroot, goos, goarch),
|
||||
copyfile(bpathf(&b, "%s/pkg/%s_%s/runtime.h", goroot, goos, goarch),
|
||||
bpathf(&b1, "%s/src/pkg/runtime/runtime.h", goroot), 0);
|
||||
}
|
||||
|
||||
|
|
@ -1277,8 +1264,8 @@ out:
|
|||
}
|
||||
|
||||
// copy copies the file src to dst, via memory (so only good for small files).
|
||||
static void
|
||||
copy(char *dst, char *src, int exec)
|
||||
void
|
||||
copyfile(char *dst, char *src, int exec)
|
||||
{
|
||||
Buf b;
|
||||
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ mkzgoos(char *dir, char *file)
|
|||
|
||||
bwritestr(&out, "// auto generated by go tool dist\n\n");
|
||||
|
||||
if (streq(goos, "linux")) {
|
||||
if(streq(goos, "linux")) {
|
||||
bwritestr(&out, "// +build !android\n\n");
|
||||
}
|
||||
|
||||
|
|
@ -169,11 +169,12 @@ mkzasm(char *dir, char *file)
|
|||
{
|
||||
int i, n;
|
||||
char *aggr, *p;
|
||||
Buf in, b, out, exp;
|
||||
Buf in, b, b1, out, exp;
|
||||
Vec argv, lines, fields;
|
||||
|
||||
binit(&in);
|
||||
binit(&b);
|
||||
binit(&b1);
|
||||
binit(&out);
|
||||
binit(&exp);
|
||||
vinit(&argv);
|
||||
|
|
@ -181,6 +182,10 @@ mkzasm(char *dir, char *file)
|
|||
vinit(&fields);
|
||||
|
||||
bwritestr(&out, "// auto generated by go tool dist\n\n");
|
||||
if(streq(goos, "linux")) {
|
||||
bwritestr(&out, "// +build !android\n\n");
|
||||
}
|
||||
|
||||
for(i=0; i<nelem(zasmhdr); i++) {
|
||||
if(hasprefix(goarch, zasmhdr[i].goarch) && hasprefix(goos, zasmhdr[i].goos)) {
|
||||
bwritestr(&out, zasmhdr[i].hdr);
|
||||
|
|
@ -190,6 +195,9 @@ mkzasm(char *dir, char *file)
|
|||
fatal("unknown $GOOS/$GOARCH in mkzasm");
|
||||
ok:
|
||||
|
||||
copyfile(bpathf(&b, "%s/pkg/%s_%s/textflag.h", goroot, goos, goarch),
|
||||
bpathf(&b1, "%s/src/cmd/ld/textflag.h", goroot), 0);
|
||||
|
||||
// Run 6c -D GOOS_goos -D GOARCH_goarch -I workdir -a -n -o workdir/proc.acid proc.c
|
||||
// to get acid [sic] output. Run once without the -a -o workdir/proc.acid in order to
|
||||
// report compilation failures (the -o redirects all messages, unfortunately).
|
||||
|
|
@ -201,6 +209,8 @@ ok:
|
|||
vadd(&argv, bprintf(&b, "GOARCH_%s", goarch));
|
||||
vadd(&argv, "-I");
|
||||
vadd(&argv, bprintf(&b, "%s", workdir));
|
||||
vadd(&argv, "-I");
|
||||
vadd(&argv, bprintf(&b, "%s/pkg/%s_%s", goroot, goos, goarch));
|
||||
vadd(&argv, "-n");
|
||||
vadd(&argv, "-a");
|
||||
vadd(&argv, "-o");
|
||||
|
|
@ -241,6 +251,8 @@ ok:
|
|||
aggr = "seh";
|
||||
else if(streq(fields.p[1], "Alg"))
|
||||
aggr = "alg";
|
||||
else if(streq(fields.p[1], "Panic"))
|
||||
aggr = "panic";
|
||||
}
|
||||
if(hasprefix(lines.p[i], "}"))
|
||||
aggr = nil;
|
||||
|
|
@ -273,6 +285,7 @@ ok:
|
|||
|
||||
bfree(&in);
|
||||
bfree(&b);
|
||||
bfree(&b1);
|
||||
bfree(&out);
|
||||
bfree(&exp);
|
||||
vfree(&argv);
|
||||
|
|
@ -294,6 +307,10 @@ mkzsys(char *dir, char *file)
|
|||
binit(&out);
|
||||
|
||||
bwritestr(&out, "// auto generated by go tool dist\n\n");
|
||||
if(streq(goos, "linux")) {
|
||||
bwritestr(&out, "// +build !android\n\n");
|
||||
}
|
||||
|
||||
if(streq(goos, "windows")) {
|
||||
bwritef(&out,
|
||||
"// runtime·callbackasm is called by external code to\n"
|
||||
|
|
@ -346,13 +363,24 @@ mkzruntimedefs(char *dir, char *file)
|
|||
vinit(&seen);
|
||||
|
||||
bwritestr(&out, "// auto generated by go tool dist\n"
|
||||
"\n"
|
||||
"\n");
|
||||
|
||||
if(streq(goos, "linux")) {
|
||||
bwritestr(&out, "// +build !android\n\n");
|
||||
}
|
||||
|
||||
bwritestr(&out,
|
||||
"package runtime\n"
|
||||
"import \"unsafe\"\n"
|
||||
"var _ unsafe.Pointer\n"
|
||||
"\n"
|
||||
);
|
||||
|
||||
// Do not emit definitions for these.
|
||||
vadd(&seen, "true");
|
||||
vadd(&seen, "false");
|
||||
vadd(&seen, "raceenabled");
|
||||
vadd(&seen, "allgs");
|
||||
|
||||
// Run 6c -D GOOS_goos -D GOARCH_goarch -I workdir -q -n -o workdir/runtimedefs
|
||||
// on each of the runtimedefs C files.
|
||||
|
|
@ -363,6 +391,8 @@ mkzruntimedefs(char *dir, char *file)
|
|||
vadd(&argv, bprintf(&b, "GOARCH_%s", goarch));
|
||||
vadd(&argv, "-I");
|
||||
vadd(&argv, bprintf(&b, "%s", workdir));
|
||||
vadd(&argv, "-I");
|
||||
vadd(&argv, bprintf(&b, "%s/pkg/%s_%s", goroot, goos, goarch));
|
||||
vadd(&argv, "-q");
|
||||
vadd(&argv, "-n");
|
||||
vadd(&argv, "-o");
|
||||
|
|
@ -382,15 +412,15 @@ mkzruntimedefs(char *dir, char *file)
|
|||
splitlines(&lines, bstr(&in));
|
||||
for(i=0; i<lines.len; i++) {
|
||||
p = lines.p[i];
|
||||
// Drop comment, func, and const lines.
|
||||
if(hasprefix(p, "//") || hasprefix(p, "const") || hasprefix(p, "func"))
|
||||
// Drop comment and func lines.
|
||||
if(hasprefix(p, "//") || hasprefix(p, "func"))
|
||||
continue;
|
||||
|
||||
// Note beginning of type or var decl, which can be multiline.
|
||||
// Remove duplicates. The linear check of seen here makes the
|
||||
// whole processing quadratic in aggregate, but there are only
|
||||
// about 100 declarations, so this is okay (and simple).
|
||||
if(hasprefix(p, "type ") || hasprefix(p, "var ")) {
|
||||
if(hasprefix(p, "type ") || hasprefix(p, "var ") || hasprefix(p, "const ")) {
|
||||
splitfields(&fields, p);
|
||||
if(fields.len < 2)
|
||||
continue;
|
||||
|
|
@ -401,6 +431,17 @@ mkzruntimedefs(char *dir, char *file)
|
|||
}
|
||||
vadd(&seen, fields.p[1]);
|
||||
}
|
||||
|
||||
// Const lines are printed in original case (usually upper). Add a leading _ as needed.
|
||||
if(hasprefix(p, "const ")) {
|
||||
if('A' <= p[6] && p[6] <= 'Z')
|
||||
bwritestr(&out, "const _");
|
||||
else
|
||||
bwritestr(&out, "const ");
|
||||
bwritestr(&out, p+6);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(skip) {
|
||||
if(hasprefix(p, "}"))
|
||||
skip = 0;
|
||||
|
|
@ -409,6 +450,11 @@ mkzruntimedefs(char *dir, char *file)
|
|||
|
||||
bwritestr(&out, p);
|
||||
}
|
||||
|
||||
// Some windows specific const.
|
||||
if(streq(goos, "windows")) {
|
||||
bwritestr(&out, bprintf(&b, "const cb_max = %d\n", MAXWINCB));
|
||||
}
|
||||
|
||||
writefile(&out, file, 0);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,833 +0,0 @@
|
|||
// Copyright 2009 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 "a.h"
|
||||
|
||||
/*
|
||||
* Translate a .goc file into a .c file. A .goc file is a combination
|
||||
* of a limited form of Go with C.
|
||||
*/
|
||||
|
||||
/*
|
||||
package PACKAGENAME
|
||||
{# line}
|
||||
func NAME([NAME TYPE { , NAME TYPE }]) [(NAME TYPE { , NAME TYPE })] \{
|
||||
C code with proper brace nesting
|
||||
\}
|
||||
*/
|
||||
|
||||
/*
|
||||
* We generate C code which implements the function such that it can
|
||||
* be called from Go and executes the C code.
|
||||
*/
|
||||
|
||||
static char *input;
|
||||
static Buf *output;
|
||||
#define EOF -1
|
||||
|
||||
enum
|
||||
{
|
||||
use64bitint = 1,
|
||||
};
|
||||
|
||||
static int
|
||||
xgetchar(void)
|
||||
{
|
||||
int c;
|
||||
|
||||
c = *input;
|
||||
if(c == 0)
|
||||
return EOF;
|
||||
input++;
|
||||
return c;
|
||||
}
|
||||
|
||||
static void
|
||||
xungetc(void)
|
||||
{
|
||||
input--;
|
||||
}
|
||||
|
||||
static void
|
||||
xputchar(char c)
|
||||
{
|
||||
bwrite(output, &c, 1);
|
||||
}
|
||||
|
||||
static int
|
||||
xisspace(int c)
|
||||
{
|
||||
return c == ' ' || c == '\t' || c == '\r' || c == '\n';
|
||||
}
|
||||
|
||||
/* Whether we're emitting for gcc */
|
||||
static int gcc;
|
||||
|
||||
/* File and line number */
|
||||
static const char *file;
|
||||
static unsigned int lineno;
|
||||
|
||||
/* List of names and types. */
|
||||
struct params {
|
||||
struct params *next;
|
||||
char *name;
|
||||
char *type;
|
||||
};
|
||||
|
||||
/* index into type_table */
|
||||
enum {
|
||||
Bool,
|
||||
Float,
|
||||
Int,
|
||||
Uint,
|
||||
Uintptr,
|
||||
String,
|
||||
Slice,
|
||||
Eface,
|
||||
Complex128,
|
||||
Float32,
|
||||
Float64,
|
||||
};
|
||||
|
||||
static struct {
|
||||
char *name;
|
||||
int size;
|
||||
int rnd; // alignment
|
||||
} type_table[] = {
|
||||
/*
|
||||
* variable sized first, for easy replacement.
|
||||
* order matches enum above.
|
||||
* default is 32-bit architecture sizes.
|
||||
* spelling as in package runtime, so intgo/uintgo not int/uint.
|
||||
*/
|
||||
{"bool", 1},
|
||||
{"float", 4},
|
||||
{"intgo", 4},
|
||||
{"uintgo", 4},
|
||||
{"uintptr", 4},
|
||||
{"String", 8},
|
||||
{"Slice", 12},
|
||||
{"Eface", 8},
|
||||
{"Complex128", 16},
|
||||
|
||||
/* fixed size */
|
||||
{"float32", 4},
|
||||
{"float64", 8},
|
||||
{"byte", 1},
|
||||
{"int8", 1},
|
||||
{"uint8", 1},
|
||||
{"int16", 2},
|
||||
{"uint16", 2},
|
||||
{"int32", 4},
|
||||
{"rune", 4},
|
||||
{"uint32", 4},
|
||||
{"int64", 8},
|
||||
{"uint64", 8},
|
||||
|
||||
{nil, 0},
|
||||
};
|
||||
|
||||
/* Fixed structure alignment (non-gcc only) */
|
||||
int structround = 4;
|
||||
|
||||
/* Unexpected EOF. */
|
||||
static void
|
||||
bad_eof(void)
|
||||
{
|
||||
fatal("%s:%d: unexpected EOF\n", file, lineno);
|
||||
}
|
||||
|
||||
/* Free a list of parameters. */
|
||||
static void
|
||||
free_params(struct params *p)
|
||||
{
|
||||
while (p != nil) {
|
||||
struct params *next;
|
||||
|
||||
next = p->next;
|
||||
xfree(p->name);
|
||||
xfree(p->type);
|
||||
xfree(p);
|
||||
p = next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read a character, tracking lineno. */
|
||||
static int
|
||||
getchar_update_lineno(void)
|
||||
{
|
||||
int c;
|
||||
|
||||
c = xgetchar();
|
||||
if (c == '\n')
|
||||
++lineno;
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Read a character, giving an error on EOF, tracking lineno. */
|
||||
static int
|
||||
getchar_no_eof(void)
|
||||
{
|
||||
int c;
|
||||
|
||||
c = getchar_update_lineno();
|
||||
if (c == EOF)
|
||||
bad_eof();
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Read a character, skipping comments. */
|
||||
static int
|
||||
getchar_skipping_comments(void)
|
||||
{
|
||||
int c;
|
||||
|
||||
while (1) {
|
||||
c = getchar_update_lineno();
|
||||
if (c != '/')
|
||||
return c;
|
||||
|
||||
c = xgetchar();
|
||||
if (c == '/') {
|
||||
do {
|
||||
c = getchar_update_lineno();
|
||||
} while (c != EOF && c != '\n');
|
||||
return c;
|
||||
} else if (c == '*') {
|
||||
while (1) {
|
||||
c = getchar_update_lineno();
|
||||
if (c == EOF)
|
||||
return EOF;
|
||||
if (c == '*') {
|
||||
do {
|
||||
c = getchar_update_lineno();
|
||||
} while (c == '*');
|
||||
if (c == '/')
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
xungetc();
|
||||
return '/';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read and return a token. Tokens are string or character literals
|
||||
* or else delimited by whitespace or by [(),{}].
|
||||
* The latter are all returned as single characters.
|
||||
*/
|
||||
static char *
|
||||
read_token(void)
|
||||
{
|
||||
int c, q;
|
||||
char *buf;
|
||||
unsigned int alc, off;
|
||||
char* delims = "(),{}";
|
||||
|
||||
while (1) {
|
||||
c = getchar_skipping_comments();
|
||||
if (c == EOF)
|
||||
return nil;
|
||||
if (!xisspace(c))
|
||||
break;
|
||||
}
|
||||
alc = 16;
|
||||
buf = xmalloc(alc + 1);
|
||||
off = 0;
|
||||
if(c == '"' || c == '\'') {
|
||||
q = c;
|
||||
buf[off] = c;
|
||||
++off;
|
||||
while (1) {
|
||||
if (off+2 >= alc) { // room for c and maybe next char
|
||||
alc *= 2;
|
||||
buf = xrealloc(buf, alc + 1);
|
||||
}
|
||||
c = getchar_no_eof();
|
||||
buf[off] = c;
|
||||
++off;
|
||||
if(c == q)
|
||||
break;
|
||||
if(c == '\\') {
|
||||
buf[off] = getchar_no_eof();
|
||||
++off;
|
||||
}
|
||||
}
|
||||
} else if (xstrrchr(delims, c) != nil) {
|
||||
buf[off] = c;
|
||||
++off;
|
||||
} else {
|
||||
while (1) {
|
||||
if (off >= alc) {
|
||||
alc *= 2;
|
||||
buf = xrealloc(buf, alc + 1);
|
||||
}
|
||||
buf[off] = c;
|
||||
++off;
|
||||
c = getchar_skipping_comments();
|
||||
if (c == EOF)
|
||||
break;
|
||||
if (xisspace(c) || xstrrchr(delims, c) != nil) {
|
||||
if (c == '\n')
|
||||
lineno--;
|
||||
xungetc();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
buf[off] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Read a token, giving an error on EOF. */
|
||||
static char *
|
||||
read_token_no_eof(void)
|
||||
{
|
||||
char *token = read_token();
|
||||
if (token == nil)
|
||||
bad_eof();
|
||||
return token;
|
||||
}
|
||||
|
||||
/* Read the package clause, and return the package name. */
|
||||
static char *
|
||||
read_package(void)
|
||||
{
|
||||
char *token;
|
||||
|
||||
token = read_token_no_eof();
|
||||
if (token == nil)
|
||||
fatal("%s:%d: no token\n", file, lineno);
|
||||
if (!streq(token, "package")) {
|
||||
fatal("%s:%d: expected \"package\", got \"%s\"\n",
|
||||
file, lineno, token);
|
||||
}
|
||||
return read_token_no_eof();
|
||||
}
|
||||
|
||||
/* Read and copy preprocessor lines. */
|
||||
static void
|
||||
read_preprocessor_lines(void)
|
||||
{
|
||||
int first;
|
||||
|
||||
first = 1;
|
||||
while (1) {
|
||||
int c;
|
||||
|
||||
do {
|
||||
c = getchar_skipping_comments();
|
||||
} while (xisspace(c));
|
||||
if (c != '#') {
|
||||
xungetc();
|
||||
break;
|
||||
}
|
||||
if(first) {
|
||||
first = 0;
|
||||
xputchar('\n');
|
||||
}
|
||||
xputchar(c);
|
||||
do {
|
||||
c = getchar_update_lineno();
|
||||
xputchar(c);
|
||||
} while (c != '\n');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a type in Go syntax and return a type in C syntax. We only
|
||||
* permit basic types and pointers.
|
||||
*/
|
||||
static char *
|
||||
read_type(void)
|
||||
{
|
||||
char *p, *op, *q;
|
||||
int pointer_count;
|
||||
unsigned int len;
|
||||
|
||||
p = read_token_no_eof();
|
||||
if (*p != '*' && !streq(p, "int") && !streq(p, "uint"))
|
||||
return p;
|
||||
op = p;
|
||||
pointer_count = 0;
|
||||
while (*p == '*') {
|
||||
++pointer_count;
|
||||
++p;
|
||||
}
|
||||
len = xstrlen(p);
|
||||
q = xmalloc(len + 2 + pointer_count + 1);
|
||||
xmemmove(q, p, len);
|
||||
|
||||
// Turn int/uint into intgo/uintgo.
|
||||
if((len == 3 && xmemcmp(q, "int", 3) == 0) || (len == 4 && xmemcmp(q, "uint", 4) == 0)) {
|
||||
q[len++] = 'g';
|
||||
q[len++] = 'o';
|
||||
}
|
||||
|
||||
while (pointer_count-- > 0)
|
||||
q[len++] = '*';
|
||||
|
||||
q[len] = '\0';
|
||||
xfree(op);
|
||||
return q;
|
||||
}
|
||||
|
||||
/* Return the size of the given type. */
|
||||
static int
|
||||
type_size(char *p, int *rnd)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(p[xstrlen(p)-1] == '*') {
|
||||
*rnd = type_table[Uintptr].rnd;
|
||||
return type_table[Uintptr].size;
|
||||
}
|
||||
|
||||
if(streq(p, "Iface"))
|
||||
p = "Eface";
|
||||
|
||||
for(i=0; type_table[i].name; i++)
|
||||
if(streq(type_table[i].name, p)) {
|
||||
*rnd = type_table[i].rnd;
|
||||
return type_table[i].size;
|
||||
}
|
||||
fatal("%s:%d: unknown type %s\n", file, lineno, p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a list of parameters. Each parameter is a name and a type.
|
||||
* The list ends with a ')'. We have already read the '('.
|
||||
*/
|
||||
static struct params *
|
||||
read_params(int *poffset)
|
||||
{
|
||||
char *token;
|
||||
struct params *ret, **pp, *p;
|
||||
int offset, size, rnd;
|
||||
|
||||
ret = nil;
|
||||
pp = &ret;
|
||||
token = read_token_no_eof();
|
||||
offset = 0;
|
||||
if (!streq(token, ")")) {
|
||||
while (1) {
|
||||
p = xmalloc(sizeof(struct params));
|
||||
p->name = token;
|
||||
p->next = nil;
|
||||
*pp = p;
|
||||
pp = &p->next;
|
||||
|
||||
if(streq(token, "...")) {
|
||||
p->type = xstrdup("");
|
||||
} else {
|
||||
p->type = read_type();
|
||||
rnd = 0;
|
||||
size = type_size(p->type, &rnd);
|
||||
if(rnd > structround)
|
||||
rnd = structround;
|
||||
if(offset%rnd)
|
||||
offset += rnd - offset%rnd;
|
||||
offset += size;
|
||||
}
|
||||
|
||||
token = read_token_no_eof();
|
||||
if (!streq(token, ","))
|
||||
break;
|
||||
token = read_token_no_eof();
|
||||
}
|
||||
}
|
||||
if (!streq(token, ")")) {
|
||||
fatal("%s:%d: expected '('\n",
|
||||
file, lineno);
|
||||
}
|
||||
if (poffset != nil)
|
||||
*poffset = offset;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a function header. This reads up to and including the initial
|
||||
* '{' character. Returns 1 if it read a header, 0 at EOF.
|
||||
*/
|
||||
static int
|
||||
read_func_header(char **name, struct params **params, int *paramwid, struct params **rets)
|
||||
{
|
||||
int lastline;
|
||||
char *token;
|
||||
|
||||
lastline = -1;
|
||||
while (1) {
|
||||
read_preprocessor_lines();
|
||||
token = read_token();
|
||||
if (token == nil)
|
||||
return 0;
|
||||
if (streq(token, "func")) {
|
||||
if(lastline != -1)
|
||||
bwritef(output, "\n");
|
||||
break;
|
||||
}
|
||||
if (lastline != lineno) {
|
||||
if (lastline == lineno-1)
|
||||
bwritef(output, "\n");
|
||||
else
|
||||
bwritef(output, "\n#line %d \"%s\"\n", lineno, file);
|
||||
lastline = lineno;
|
||||
}
|
||||
bwritef(output, "%s ", token);
|
||||
}
|
||||
|
||||
*name = read_token_no_eof();
|
||||
|
||||
token = read_token();
|
||||
if (token == nil || !streq(token, "(")) {
|
||||
fatal("%s:%d: expected \"(\"\n",
|
||||
file, lineno);
|
||||
}
|
||||
*params = read_params(paramwid);
|
||||
|
||||
token = read_token();
|
||||
if (token == nil || !streq(token, "("))
|
||||
*rets = nil;
|
||||
else {
|
||||
*rets = read_params(nil);
|
||||
token = read_token();
|
||||
}
|
||||
if (token == nil || !streq(token, "{")) {
|
||||
fatal("%s:%d: expected \"{\"\n",
|
||||
file, lineno);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Write out parameters. */
|
||||
static void
|
||||
write_params(struct params *params, int *first)
|
||||
{
|
||||
struct params *p;
|
||||
|
||||
for (p = params; p != nil; p = p->next) {
|
||||
if (*first)
|
||||
*first = 0;
|
||||
else
|
||||
bwritef(output, ", ");
|
||||
bwritef(output, "%s %s", p->type, p->name);
|
||||
}
|
||||
}
|
||||
|
||||
/* Write a 6g function header. */
|
||||
static void
|
||||
write_6g_func_header(char *package, char *name, struct params *params,
|
||||
int paramwid, struct params *rets)
|
||||
{
|
||||
int first, n;
|
||||
struct params *p;
|
||||
|
||||
bwritef(output, "void\n");
|
||||
if(!contains(name, "·"))
|
||||
bwritef(output, "%s·", package);
|
||||
bwritef(output, "%s(", name);
|
||||
|
||||
first = 1;
|
||||
write_params(params, &first);
|
||||
|
||||
/* insert padding to align output struct */
|
||||
if(rets != nil && paramwid%structround != 0) {
|
||||
n = structround - paramwid%structround;
|
||||
if(n & 1)
|
||||
bwritef(output, ", uint8");
|
||||
if(n & 2)
|
||||
bwritef(output, ", uint16");
|
||||
if(n & 4)
|
||||
bwritef(output, ", uint32");
|
||||
}
|
||||
|
||||
write_params(rets, &first);
|
||||
bwritef(output, ")\n{\n");
|
||||
|
||||
for (p = rets; p != nil; p = p->next) {
|
||||
if(streq(p->name, "..."))
|
||||
continue;
|
||||
if(streq(p->type, "Slice"))
|
||||
bwritef(output, "\t%s.array = 0;\n\t%s.len = 0;\n\t%s.cap = 0;\n", p->name, p->name, p->name);
|
||||
else if(streq(p->type, "String"))
|
||||
bwritef(output, "\t%s.str = 0;\n\t%s.len = 0;\n", p->name, p->name);
|
||||
else if(streq(p->type, "Eface"))
|
||||
bwritef(output, "\t%s.type = 0;\n\t%s.data = 0;\n", p->name, p->name);
|
||||
else if(streq(p->type, "Iface"))
|
||||
bwritef(output, "\t%s.tab = 0;\n\t%s.data = 0;\n", p->name, p->name);
|
||||
else if(streq(p->type, "Complex128"))
|
||||
bwritef(output, "\t%s.real = 0;\n\t%s.imag = 0;\n", p->name, p->name);
|
||||
else
|
||||
bwritef(output, "\t%s = 0;\n", p->name);
|
||||
bwritef(output, "\tFLUSH(&%s);\n", p->name);
|
||||
}
|
||||
}
|
||||
|
||||
/* Write a 6g function trailer. */
|
||||
static void
|
||||
write_6g_func_trailer(struct params *rets)
|
||||
{
|
||||
struct params *p;
|
||||
|
||||
for (p = rets; p != nil; p = p->next)
|
||||
if(!streq(p->name, "..."))
|
||||
bwritef(output, "\tFLUSH(&%s);\n", p->name);
|
||||
bwritef(output, "}\n");
|
||||
}
|
||||
|
||||
/* Define the gcc function return type if necessary. */
|
||||
static void
|
||||
define_gcc_return_type(char *package, char *name, struct params *rets)
|
||||
{
|
||||
struct params *p;
|
||||
|
||||
if (rets == nil || rets->next == nil)
|
||||
return;
|
||||
bwritef(output, "struct %s_%s_ret {\n", package, name);
|
||||
for (p = rets; p != nil; p = p->next)
|
||||
bwritef(output, " %s %s;\n", p->type, p->name);
|
||||
bwritef(output, "};\n");
|
||||
}
|
||||
|
||||
/* Write out the gcc function return type. */
|
||||
static void
|
||||
write_gcc_return_type(char *package, char *name, struct params *rets)
|
||||
{
|
||||
if (rets == nil)
|
||||
bwritef(output, "void");
|
||||
else if (rets->next == nil)
|
||||
bwritef(output, "%s", rets->type);
|
||||
else
|
||||
bwritef(output, "struct %s_%s_ret", package, name);
|
||||
}
|
||||
|
||||
/* Write out a gcc function header. */
|
||||
static void
|
||||
write_gcc_func_header(char *package, char *name, struct params *params,
|
||||
struct params *rets)
|
||||
{
|
||||
int first;
|
||||
struct params *p;
|
||||
|
||||
define_gcc_return_type(package, name, rets);
|
||||
write_gcc_return_type(package, name, rets);
|
||||
bwritef(output, " %s_%s(", package, name);
|
||||
first = 1;
|
||||
write_params(params, &first);
|
||||
bwritef(output, ") asm (\"%s.%s\");\n", package, name);
|
||||
write_gcc_return_type(package, name, rets);
|
||||
bwritef(output, " %s_%s(", package, name);
|
||||
first = 1;
|
||||
write_params(params, &first);
|
||||
bwritef(output, ")\n{\n");
|
||||
for (p = rets; p != nil; p = p->next)
|
||||
bwritef(output, " %s %s;\n", p->type, p->name);
|
||||
}
|
||||
|
||||
/* Write out a gcc function trailer. */
|
||||
static void
|
||||
write_gcc_func_trailer(char *package, char *name, struct params *rets)
|
||||
{
|
||||
if (rets == nil) {
|
||||
// nothing to do
|
||||
}
|
||||
else if (rets->next == nil)
|
||||
bwritef(output, "return %s;\n", rets->name);
|
||||
else {
|
||||
struct params *p;
|
||||
|
||||
bwritef(output, " {\n struct %s_%s_ret __ret;\n", package, name);
|
||||
for (p = rets; p != nil; p = p->next)
|
||||
bwritef(output, " __ret.%s = %s;\n", p->name, p->name);
|
||||
bwritef(output, " return __ret;\n }\n");
|
||||
}
|
||||
bwritef(output, "}\n");
|
||||
}
|
||||
|
||||
/* Write out a function header. */
|
||||
static void
|
||||
write_func_header(char *package, char *name,
|
||||
struct params *params, int paramwid,
|
||||
struct params *rets)
|
||||
{
|
||||
if (gcc)
|
||||
write_gcc_func_header(package, name, params, rets);
|
||||
else
|
||||
write_6g_func_header(package, name, params, paramwid, rets);
|
||||
bwritef(output, "#line %d \"%s\"\n", lineno, file);
|
||||
}
|
||||
|
||||
/* Write out a function trailer. */
|
||||
static void
|
||||
write_func_trailer(char *package, char *name,
|
||||
struct params *rets)
|
||||
{
|
||||
if (gcc)
|
||||
write_gcc_func_trailer(package, name, rets);
|
||||
else
|
||||
write_6g_func_trailer(rets);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read and write the body of the function, ending in an unnested }
|
||||
* (which is read but not written).
|
||||
*/
|
||||
static void
|
||||
copy_body(void)
|
||||
{
|
||||
int nesting = 0;
|
||||
while (1) {
|
||||
int c;
|
||||
|
||||
c = getchar_no_eof();
|
||||
if (c == '}' && nesting == 0)
|
||||
return;
|
||||
xputchar(c);
|
||||
switch (c) {
|
||||
default:
|
||||
break;
|
||||
case '{':
|
||||
++nesting;
|
||||
break;
|
||||
case '}':
|
||||
--nesting;
|
||||
break;
|
||||
case '/':
|
||||
c = getchar_update_lineno();
|
||||
xputchar(c);
|
||||
if (c == '/') {
|
||||
do {
|
||||
c = getchar_no_eof();
|
||||
xputchar(c);
|
||||
} while (c != '\n');
|
||||
} else if (c == '*') {
|
||||
while (1) {
|
||||
c = getchar_no_eof();
|
||||
xputchar(c);
|
||||
if (c == '*') {
|
||||
do {
|
||||
c = getchar_no_eof();
|
||||
xputchar(c);
|
||||
} while (c == '*');
|
||||
if (c == '/')
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '"':
|
||||
case '\'':
|
||||
{
|
||||
int delim = c;
|
||||
do {
|
||||
c = getchar_no_eof();
|
||||
xputchar(c);
|
||||
if (c == '\\') {
|
||||
c = getchar_no_eof();
|
||||
xputchar(c);
|
||||
c = '\0';
|
||||
}
|
||||
} while (c != delim);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Process the entire file. */
|
||||
static void
|
||||
process_file(void)
|
||||
{
|
||||
char *package, *name, *p, *n;
|
||||
struct params *params, *rets;
|
||||
int paramwid;
|
||||
|
||||
package = read_package();
|
||||
read_preprocessor_lines();
|
||||
while (read_func_header(&name, ¶ms, ¶mwid, &rets)) {
|
||||
// name may have a package override already
|
||||
n = xstrstr(name, "·");
|
||||
if(n != nil) {
|
||||
p = xmalloc(n - name + 1);
|
||||
xmemmove(p, name, n - name);
|
||||
p[n - name] = 0;
|
||||
n += xstrlen("·");
|
||||
} else {
|
||||
p = package;
|
||||
n = name;
|
||||
}
|
||||
write_func_header(p, n, params, paramwid, rets);
|
||||
copy_body();
|
||||
write_func_trailer(p, n, rets);
|
||||
xfree(name);
|
||||
if(p != package) xfree(p);
|
||||
free_params(params);
|
||||
free_params(rets);
|
||||
}
|
||||
xfree(package);
|
||||
}
|
||||
|
||||
void
|
||||
goc2c(char *goc, char *c)
|
||||
{
|
||||
int i;
|
||||
Buf in, out;
|
||||
|
||||
binit(&in);
|
||||
binit(&out);
|
||||
|
||||
file = goc;
|
||||
readfile(&in, goc);
|
||||
|
||||
// TODO: set gcc=1 when using gcc
|
||||
|
||||
if(!gcc) {
|
||||
if(contains(goarch, "64p32")) {
|
||||
type_table[Uintptr].size = 4;
|
||||
type_table[Int].size = 4;
|
||||
structround = 8;
|
||||
} else if(contains(goarch, "64")) {
|
||||
type_table[Uintptr].size = 8;
|
||||
if(use64bitint) {
|
||||
type_table[Int].size = 8;
|
||||
} else {
|
||||
type_table[Int].size = 4;
|
||||
}
|
||||
structround = 8;
|
||||
} else {
|
||||
// NOTE: These are set in the initializer,
|
||||
// but they might have been changed by a
|
||||
// previous invocation of goc2c, so we have
|
||||
// to restore them.
|
||||
type_table[Uintptr].size = 4;
|
||||
type_table[Int].size = 4;
|
||||
structround = 4;
|
||||
}
|
||||
|
||||
type_table[Uint].size = type_table[Int].size;
|
||||
type_table[Slice].size = type_table[Uintptr].size+2*type_table[Int].size;
|
||||
type_table[Eface].size = 2*type_table[Uintptr].size;
|
||||
type_table[String].size = 2*type_table[Uintptr].size;
|
||||
|
||||
for(i=0; i<nelem(type_table); i++)
|
||||
type_table[i].rnd = type_table[i].size;
|
||||
|
||||
type_table[String].rnd = type_table[Uintptr].rnd;
|
||||
type_table[Slice].rnd = type_table[Uintptr].rnd;
|
||||
type_table[Eface].rnd = type_table[Uintptr].rnd;
|
||||
type_table[Complex128].rnd = type_table[Float64].rnd;
|
||||
}
|
||||
|
||||
bprintf(&out, "// auto generated by go tool dist\n// goos=%s goarch=%s\n\n", goos, goarch);
|
||||
input = bstr(&in);
|
||||
output = &out;
|
||||
|
||||
lineno = 1;
|
||||
process_file();
|
||||
|
||||
writefile(&out, c, 0);
|
||||
}
|
||||
|
|
@ -23,7 +23,7 @@ bprintf(Buf *b, char *fmt, ...)
|
|||
{
|
||||
va_list arg;
|
||||
char buf[4096];
|
||||
|
||||
|
||||
breset(b);
|
||||
va_start(arg, fmt);
|
||||
vsnprintf(buf, sizeof buf, fmt, arg);
|
||||
|
|
@ -572,10 +572,10 @@ bool
|
|||
hassuffix(char *p, char *suffix)
|
||||
{
|
||||
int np, ns;
|
||||
|
||||
|
||||
np = strlen(p);
|
||||
ns = strlen(suffix);
|
||||
return np >= ns && strcmp(p+np-ns, suffix) == 0;
|
||||
return np >= ns && streq(p+np-ns, suffix);
|
||||
}
|
||||
|
||||
// hasprefix reports whether p begins with prefix.
|
||||
|
|
|
|||
|
|
@ -431,7 +431,7 @@ xremoveall(char *p)
|
|||
}
|
||||
|
||||
bfree(&b);
|
||||
vfree(&dir);
|
||||
vfree(&dir);
|
||||
}
|
||||
|
||||
// xreaddir replaces dst with a list of the names of the files in dir.
|
||||
|
|
@ -441,13 +441,13 @@ xreaddir(Vec *dst, char *dir)
|
|||
{
|
||||
DIR *d;
|
||||
struct dirent *dp;
|
||||
|
||||
|
||||
vreset(dst);
|
||||
d = opendir(dir);
|
||||
if(d == nil)
|
||||
fatal("opendir %s: %s", dir, strerror(errno));
|
||||
while((dp = readdir(d)) != nil) {
|
||||
if(strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
|
||||
if(streq(dp->d_name, ".") || streq(dp->d_name, ".."))
|
||||
continue;
|
||||
vadd(dst, dp->d_name);
|
||||
}
|
||||
|
|
@ -461,7 +461,7 @@ xworkdir(void)
|
|||
{
|
||||
Buf b;
|
||||
char *p;
|
||||
|
||||
|
||||
binit(&b);
|
||||
|
||||
xgetenv(&b, "TMPDIR");
|
||||
|
|
@ -546,10 +546,10 @@ bool
|
|||
hassuffix(char *p, char *suffix)
|
||||
{
|
||||
int np, ns;
|
||||
|
||||
|
||||
np = strlen(p);
|
||||
ns = strlen(suffix);
|
||||
return np >= ns && strcmp(p+np-ns, suffix) == 0;
|
||||
return np >= ns && streq(p+np-ns, suffix);
|
||||
}
|
||||
|
||||
// hasprefix reports whether p begins with prefix.
|
||||
|
|
@ -716,7 +716,7 @@ main(int argc, char **argv)
|
|||
fatal("unknown architecture: %s", u.machine);
|
||||
}
|
||||
|
||||
if(strcmp(gohostarch, "arm") == 0)
|
||||
if(streq(gohostarch, "arm"))
|
||||
maxnbg = 1;
|
||||
|
||||
// The OS X 10.6 linker does not support external linking mode.
|
||||
|
|
@ -728,7 +728,7 @@ main(int argc, char **argv)
|
|||
//
|
||||
// Roughly, OS X 10.N shows up as uname release (N+4),
|
||||
// so OS X 10.6 is uname version 10 and OS X 10.8 is uname version 12.
|
||||
if(strcmp(gohostos, "darwin") == 0) {
|
||||
if(streq(gohostos, "darwin")) {
|
||||
if(uname(&u) < 0)
|
||||
fatal("uname: %s", strerror(errno));
|
||||
osx = atoi(u.release) - 4;
|
||||
|
|
|
|||
|
|
@ -770,10 +770,10 @@ bool
|
|||
hassuffix(char *p, char *suffix)
|
||||
{
|
||||
int np, ns;
|
||||
|
||||
|
||||
np = strlen(p);
|
||||
ns = strlen(suffix);
|
||||
return np >= ns && strcmp(p+np-ns, suffix) == 0;
|
||||
return np >= ns && streq(p+np-ns, suffix);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ rewrites are idempotent, so that it is safe to apply fix to updated
|
|||
or partially updated code even without using the -r flag.
|
||||
|
||||
Fix prints the full list of fixes it can apply in its help output;
|
||||
to see them, run go tool fix -?.
|
||||
to see them, run go tool fix -help.
|
||||
|
||||
Fix does not make backup copies of the files that it edits.
|
||||
Instead, use a version control system's ``diff'' functionality to inspect
|
||||
|
|
|
|||
|
|
@ -9,11 +9,12 @@ char *runtimeimport =
|
|||
"func @\"\".throwreturn ()\n"
|
||||
"func @\"\".throwinit ()\n"
|
||||
"func @\"\".panicwrap (? string, ? string, ? string)\n"
|
||||
"func @\"\".panic (? interface {})\n"
|
||||
"func @\"\".recover (? *int32) (? interface {})\n"
|
||||
"func @\"\".gopanic (? interface {})\n"
|
||||
"func @\"\".gorecover (? *int32) (? interface {})\n"
|
||||
"func @\"\".printbool (? bool)\n"
|
||||
"func @\"\".printfloat (? float64)\n"
|
||||
"func @\"\".printint (? int64)\n"
|
||||
"func @\"\".printhex (? uint64)\n"
|
||||
"func @\"\".printuint (? uint64)\n"
|
||||
"func @\"\".printcomplex (? complex128)\n"
|
||||
"func @\"\".printstring (? string)\n"
|
||||
|
|
@ -64,7 +65,6 @@ char *runtimeimport =
|
|||
"func @\"\".efaceeq (@\"\".i1·2 any, @\"\".i2·3 any) (@\"\".ret·1 bool)\n"
|
||||
"func @\"\".ifacethash (@\"\".i1·2 any) (@\"\".ret·1 uint32)\n"
|
||||
"func @\"\".efacethash (@\"\".i1·2 any) (@\"\".ret·1 uint32)\n"
|
||||
"func @\"\".equal (@\"\".typ·2 *byte, @\"\".x1·3 any, @\"\".x2·4 any) (@\"\".ret·1 bool)\n"
|
||||
"func @\"\".makemap (@\"\".mapType·2 *byte, @\"\".hint·3 int64) (@\"\".hmap·1 map[any]any)\n"
|
||||
"func @\"\".mapaccess1 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 *any) (@\"\".val·1 *any)\n"
|
||||
"func @\"\".mapaccess1_fast32 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n"
|
||||
|
|
@ -96,12 +96,12 @@ char *runtimeimport =
|
|||
"func @\"\".makeslice (@\"\".typ·2 *byte, @\"\".nel·3 int64, @\"\".cap·4 int64) (@\"\".ary·1 []any)\n"
|
||||
"func @\"\".growslice (@\"\".typ·2 *byte, @\"\".old·3 []any, @\"\".n·4 int64) (@\"\".ary·1 []any)\n"
|
||||
"func @\"\".memmove (@\"\".to·1 *any, @\"\".frm·2 *any, @\"\".length·3 uintptr)\n"
|
||||
"func @\"\".memequal (@\"\".eq·1 *bool, @\"\".size·2 uintptr, @\"\".x·3 *any, @\"\".y·4 *any)\n"
|
||||
"func @\"\".memequal8 (@\"\".eq·1 *bool, @\"\".size·2 uintptr, @\"\".x·3 *any, @\"\".y·4 *any)\n"
|
||||
"func @\"\".memequal16 (@\"\".eq·1 *bool, @\"\".size·2 uintptr, @\"\".x·3 *any, @\"\".y·4 *any)\n"
|
||||
"func @\"\".memequal32 (@\"\".eq·1 *bool, @\"\".size·2 uintptr, @\"\".x·3 *any, @\"\".y·4 *any)\n"
|
||||
"func @\"\".memequal64 (@\"\".eq·1 *bool, @\"\".size·2 uintptr, @\"\".x·3 *any, @\"\".y·4 *any)\n"
|
||||
"func @\"\".memequal128 (@\"\".eq·1 *bool, @\"\".size·2 uintptr, @\"\".x·3 *any, @\"\".y·4 *any)\n"
|
||||
"func @\"\".memequal (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
|
||||
"func @\"\".memequal8 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
|
||||
"func @\"\".memequal16 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
|
||||
"func @\"\".memequal32 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
|
||||
"func @\"\".memequal64 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
|
||||
"func @\"\".memequal128 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
|
||||
"func @\"\".int64div (? int64, ? int64) (? int64)\n"
|
||||
"func @\"\".uint64div (? uint64, ? uint64) (? uint64)\n"
|
||||
"func @\"\".int64mod (? int64, ? int64) (? int64)\n"
|
||||
|
|
|
|||
|
|
@ -108,6 +108,9 @@ bvnext(Bvec *bv, int32 i)
|
|||
{
|
||||
uint32 w;
|
||||
|
||||
if(i >= bv->n)
|
||||
return -1;
|
||||
|
||||
// Jump i ahead to next word with bits.
|
||||
if((bv->b[i>>WORDSHIFT]>>(i&WORDMASK)) == 0) {
|
||||
i &= ~WORDMASK;
|
||||
|
|
@ -117,7 +120,7 @@ bvnext(Bvec *bv, int32 i)
|
|||
}
|
||||
if(i >= bv->n)
|
||||
return -1;
|
||||
|
||||
|
||||
// Find 1 bit.
|
||||
w = bv->b[i>>WORDSHIFT]>>(i&WORDMASK);
|
||||
while((w&1) == 0) {
|
||||
|
|
|
|||
|
|
@ -1566,7 +1566,6 @@ isgoconst(Node *n)
|
|||
case ORSH:
|
||||
case OSUB:
|
||||
case OXOR:
|
||||
case OCONV:
|
||||
case OIOTA:
|
||||
case OCOMPLEX:
|
||||
case OREAL:
|
||||
|
|
@ -1574,7 +1573,12 @@ isgoconst(Node *n)
|
|||
if(isgoconst(n->left) && (n->right == N || isgoconst(n->right)))
|
||||
return 1;
|
||||
break;
|
||||
|
||||
|
||||
case OCONV:
|
||||
if(okforconst[n->type->etype] && isgoconst(n->left))
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case OLEN:
|
||||
case OCAP:
|
||||
l = n->left;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue