diff options
author | Russ Cox <rsc@golang.org> | 2014-11-24 12:07:11 -0500 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2014-11-24 12:07:11 -0500 |
commit | e5fc9ffb729e31c4eb0a6518e819e9fc70f14818 (patch) | |
tree | 5f67f9fb6c209085505b8fa6a01a245942ea45c3 | |
parent | df7d4576f312e1b646af4f5f1a32412a4221b785 (diff) | |
parent | db6a11ff558add790779fdef118b5ad899f77137 (diff) | |
download | go-e5fc9ffb729e31c4eb0a6518e819e9fc70f14818.tar.gz |
[dev.garbage] all: merge dev.cc (493ad916c3b1) into dev.garbage
TBR=austin
CC=golang-codereviews
https://codereview.appspot.com/179290043
206 files changed, 4733 insertions, 11182 deletions
@@ -145,7 +145,7 @@ Egon Elbre <egonelbre@gmail.com> Ehren Kret <ehren.kret@gmail.com> Eivind Uggedal <eivind@uggedal.com> Elias Naur <elias.naur@gmail.com> -Emil Hessman <c.emil.hessman@gmail.com> +Emil Hessman <c.emil.hessman@gmail.com> <emil@hessman.se> Eoghan Sherry <ejsherry@gmail.com> Eric Clark <zerohp@gmail.com> Eric Milliken <emilliken@gmail.com> diff --git a/CONTRIBUTORS b/CONTRIBUTORS index ec69858b6..b5e709ed6 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -214,7 +214,7 @@ Egon Elbre <egonelbre@gmail.com> Ehren Kret <ehren.kret@gmail.com> Eivind Uggedal <eivind@uggedal.com> Elias Naur <elias.naur@gmail.com> -Emil Hessman <c.emil.hessman@gmail.com> +Emil Hessman <c.emil.hessman@gmail.com> <emil@hessman.se> Eoghan Sherry <ejsherry@gmail.com> Eric Clark <zerohp@gmail.com> Eric Milliken <emilliken@gmail.com> @@ -452,6 +452,7 @@ Nicholas Katsaros <nick@nickkatsaros.com> Nicholas Presta <nick@nickpresta.ca> <nick1presta@gmail.com> Nicholas Sullivan <nicholas.sullivan@gmail.com> Nicholas Waples <nwaples@gmail.com> +Nick Cooper <nmvc@google.com> Nick Craig-Wood <nick@craig-wood.com> <nickcw@gmail.com> Nicolas Kaiser <nikai@nikai.net> Nicolas Owens <mischief@offblast.org> diff --git a/doc/go1.4.html b/doc/go1.4.html index ac63ade60..883352e34 100644 --- a/doc/go1.4.html +++ b/doc/go1.4.html @@ -7,10 +7,10 @@ <h2 id="introduction">Introduction to Go 1.4</h2> <p> -The latest Go release, version 1.4, arrives as scheduled six months after 1.3 -and contains only one tiny language change, -a possibly breaking change to the compiler, -a backwards-compatible simple form of <code>for</code>-<code>range</code> loop. +The latest Go release, version 1.4, arrives as scheduled six months after 1.3. +It contains only one tiny language change, +in the form of a backwards-compatible simple variant of <code>for</code>-<code>range</code> loop, +and a possibly breaking change to the compiler involving methods on pointers-to-pointers. The release focuses primarily on implementation work, improving the garbage collector and preparing the ground for a fully concurrent collector to be rolled out in the next few releases. @@ -20,7 +20,7 @@ this release therefore eliminates the notorious "hot stack split" problem. There are some new tools available including support in the <code>go</code> command for build-time source code generation. The release also adds support for ARM processors on Android and Native Client (NaCl) -and AMD64 on Plan 9. +and for AMD64 on Plan 9. As always, Go 1.4 keeps the <a href="/doc/go1compat.html">promise of compatibility</a>, and almost everything @@ -638,11 +638,28 @@ See the relevant package documentation for more information about each change. <ul> <li> +The <a href="/pkg/archive/zip/"><code>archive/zip</code></a> package's +<a href="/pkg/archive/zip/#Writer"><code>Writer</code></a> now supports a +<a href="/pkg/archive/zip/#Writer.Flush"><code>Flush</code></a> method. +</li> + +<li> The <a href="/pkg/compress/flate/"><code>compress/flate</code></a>, <a href="/pkg/compress/gzip/"><code>compress/gzip</code></a>, and <a href="/pkg/compress/zlib/"><code>compress/zlib</code></a> packages now support a <code>Reset</code> method for the decompressors, allowing them to reuse buffers and improve performance. +The <a href="/pkg/compress/gzip/"><code>compress/gzip</code></a> package also has a +<a href="/pkg/compress/gzip/#Reader.Multistream"><code>Multistream</code></a> method to control support +for multistream files. +</li> + +<li> +The <a href="/pkg/crypto/"><code>crypto</code></a> package now has a +<a href="/pkg/crypto/#Signer"><code>Signer</code></a> interface, implemented by the +<code>PrivateKey</code> types in +<a href="/pkg/crypto/ecdsa"><code>crypto/ecdsa</code></a> and +<a href="/pkg/crypto/rsa"><code>crypto/rsa</code></a>. </li> <li> @@ -666,6 +683,16 @@ those attacks.) </li> <li> +The <a href="/pkg/database/sql/"><code>database/sql</code></a> package can now list all registered +<a href="/pkg/database/sql/#Drivers"><code>Drivers</code></a>. +</li> + +<li> +The <a href="/pkg/debug/dwarf/"><code>debug/dwarf</code></a> package now supports +<a href="/pkg/debug/dwarf/#UnspecifiedType"><code>UnspecifiedType</code></a>s. +</li> + +<li> In the <a href="/pkg/encoding/asn1/"><code>encoding/asn1</code></a> package, optional elements with a default value will now only be omitted if they have that value. </li> @@ -686,6 +713,11 @@ There is no functional change. </li> <li> +The <a href="/pkg/encoding/xml/"><code>encoding/xml</code></a> package's +<a href="/pkg/encoding/xml/#Decoder"><code>Decoder</code></a> can now report its input offset. +</li> + +<li> In the <a href="/pkg/fmt/"><code>fmt</code></a> package, formatting of pointers to maps has changed to be consistent with that of pointers to structs, arrays, and so on. @@ -694,6 +726,28 @@ For instance, <code>&map[string]int{"one":</code> <code>1}</code> now prints </li> <li> +The <a href="/pkg/image/"><code>image</code></a> package's +<a href="/pkg/image/#Image"><code>Image</code></a> +implementations like +<a href="/pkg/image/#RGBA"><code>RGBA</code></a> and +<a href="/pkg/image/#Gray"><code>Gray</code></a> have specialized +<a href="/pkg/image/#RGBA.RGBAAt"><code>RGBAAt</code></a> and +<a href="/pkg/image/#Gray.GrayAt"><code>GrayAt</code></a> methods alongside the general +<a href="/pkg/image/#Image.At"><code>At</code></a> method. +</li> + +<li> +The <a href="/pkg/image/png/"><code>image/png</code></a> package now has an +<a href="/pkg/image/png/#Encoder"><code>Encoder</code></a> +type to control the compression level used for encoding. +</li> + +<li> +The <a href="/pkg/math/"><code>math</code></a> package now has a +<a href="/pkg/math/#Nextafter32"><code>Nextafter32</code><a/> function. +</li> + +<li> The <a href="/pkg/net/http/"><code>net/http</code></a> package's <a href="/pkg/net/http/#Request"><code>Request</code></a> type has a new <a href="/pkg/net/http/#Request.BasicAuth"><code>BasicAuth</code></a> method @@ -721,6 +775,7 @@ The <a href="/pkg/os/"><code>os</code></a> package now implements symbolic links on the Windows operating system through the <a href="/pkg/os/#Symlink"><code>Symlink</code></a> function. Other operating systems already have this functionality. +There is also a new <a href="/pkg/os/#Unsetenv"><code>Unsetenv</code></a> function. </li> <li> diff --git a/doc/go_spec.html b/doc/go_spec.html index 050c06465..ca0deb56a 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,6 +1,6 @@ <!--{ "Title": "The Go Programming Language Specification", - "Subtitle": "Version of October 27, 2014", + "Subtitle": "Version of November 11, 2014", "Path": "/ref/spec" }--> @@ -2521,30 +2521,40 @@ The following rules apply to selectors: <ol> <li> For a value <code>x</code> of type <code>T</code> or <code>*T</code> -where <code>T</code> is not an interface type, +where <code>T</code> is not a pointer or interface type, <code>x.f</code> denotes the field or method at the shallowest depth in <code>T</code> where there is such an <code>f</code>. If there is not exactly <a href="#Uniqueness_of_identifiers">one <code>f</code></a> with shallowest depth, the selector expression is illegal. </li> + <li> -For a variable <code>x</code> of type <code>I</code> where <code>I</code> +For a value <code>x</code> of type <code>I</code> where <code>I</code> is an interface type, <code>x.f</code> denotes the actual method with name -<code>f</code> of the value assigned to <code>x</code>. +<code>f</code> of the dynamic value of <code>x</code>. If there is no method with name <code>f</code> in the <a href="#Method_sets">method set</a> of <code>I</code>, the selector expression is illegal. </li> + +<li> +As an exception, if the type of <code>x</code> is a named pointer type +and <code>(*x).f</code> is a valid selector expression denoting a field +(but not a method), <code>x.f</code> is shorthand for <code>(*x).f</code>. +</li> + <li> In all other cases, <code>x.f</code> is illegal. </li> + <li> If <code>x</code> is of pointer type and has the value <code>nil</code> and <code>x.f</code> denotes a struct field, assigning to or evaluating <code>x.f</code> causes a <a href="#Run_time_panics">run-time panic</a>. </li> + <li> If <code>x</code> is of interface type and has the value <code>nil</code>, <a href="#Calls">calling</a> or @@ -2554,18 +2564,6 @@ causes a <a href="#Run_time_panics">run-time panic</a>. </ol> <p> -Selectors automatically <a href="#Address_operators">dereference</a> -pointers to structs. -If <code>x</code> is a pointer to a struct, <code>x.y</code> -is shorthand for <code>(*x).y</code>; if the field <code>y</code> -is also a pointer to a struct, <code>x.y.z</code> is shorthand -for <code>(*(*x).y).z</code>, and so on. -If <code>x</code> contains an anonymous field of type <code>*A</code>, -where <code>A</code> is also a struct type, -<code>x.f</code> is shorthand for <code>(*x.A).f</code>. -</p> - -<p> For example, given the declarations: </p> @@ -2574,13 +2572,13 @@ type T0 struct { x int } -func (recv *T0) M0() +func (*T0) M0() type T1 struct { y int } -func (recv T1) M1() +func (T1) M1() type T2 struct { z int @@ -2588,9 +2586,13 @@ type T2 struct { *T0 } -func (recv *T2) M2() +func (*T2) M2() -var p *T2 // with p != nil and p.T0 != nil +type Q *T2 + +var t T2 // with t.T0 != nil +var p *T2 // with p != nil and (*p).T0 != nil +var q Q = p </pre> <p> @@ -2598,13 +2600,27 @@ one may write: </p> <pre> -p.z // (*p).z -p.y // ((*p).T1).y -p.x // (*(*p).T0).x +t.z // t.z +t.y // t.T1.y +t.x // (*t.TO).x + +p.z // (*p).z +p.y // (*p).T1.y +p.x // (*(*p).T0).x + +q.x // (*(*q).T0).x (*q).x is a valid field selector + +p.M2() // p.M2() M2 expects *T2 receiver +p.M1() // ((*p).T1).M1() M1 expects T1 receiver +p.M0() // ((&(*p).T0)).M0() M0 expects *T0 receiver, see section on Calls +</pre> -p.M2() // (*p).M2() -p.M1() // ((*p).T1).M1() -p.M0() // ((*p).T0).M0() +<p> +but the following is invalid: +</p> + +<pre> +q.M0() // (*q).M0 is valid but not a field selector </pre> diff --git a/doc/gopher/fiveyears.jpg b/doc/gopher/fiveyears.jpg Binary files differnew file mode 100644 index 000000000..df1064868 --- /dev/null +++ b/doc/gopher/fiveyears.jpg diff --git a/doc/install.html b/doc/install.html index d6984c244..9561fdde2 100644 --- a/doc/install.html +++ b/doc/install.html @@ -47,7 +47,7 @@ proceeding. If your OS or architecture is not on the list, it's possible that <tr><td>FreeBSD 8 or later</td> <td>amd64, 386, arm</td> <td>Debian GNU/kFreeBSD not supported; FreeBSD/ARM needs FreeBSD 10 or later</td></tr> <tr><td>Linux 2.6.23 or later with glibc</td> <td>amd64, 386, arm</td> <td>CentOS/RHEL 5.x not supported; no binary distribution for ARM yet</td></tr> <tr><td>Mac OS X 10.6 or later</td> <td>amd64, 386</td> <td>use the gcc<sup>†</sup> that comes with Xcode<sup>‡</sup></td></tr> -<tr><td>Windows XP or later</td> <td>amd64, 386</td> <td>use MinGW gcc<sup>†</sup>. No need for cgywin or msys.</td></tr> +<tr><td>Windows XP or later</td> <td>amd64, 386</td> <td>use MinGW gcc<sup>†</sup>. No need for cygwin or msys.</td></tr> </table> <p> diff --git a/include/link.h b/include/link.h index 06f3ebb48..2b1d02102 100644 --- a/include/link.h +++ b/include/link.h @@ -62,7 +62,7 @@ struct Addr short type; uint8 index; int8 scale; - int8 reg; // for 5l, 9l + int8 reg; // for 5l, 9l; GPRs and FPRs both start at 0 int8 name; // for 5l, 9l int8 class; // for 5l, 9l uint8 etype; // for 5g, 6g, 8g @@ -94,6 +94,7 @@ struct Prog // operands Addr from; uchar reg; // arm, power64 only (e.g., ADD from, reg, to); + // starts at 0 for both GPRs and FPRs; // also used for ADATA width on arm, power64 Addr from3; // power64 only (e.g., RLWM/FMADD from, reg, from3, to) Addr to; @@ -626,6 +627,11 @@ extern char* anames9[]; extern char* cnames5[]; extern char* cnames9[]; +extern char* dnames5[]; +extern char* dnames6[]; +extern char* dnames8[]; +extern char* dnames9[]; + extern LinkArch link386; extern LinkArch linkamd64; extern LinkArch linkamd64p32; @@ -634,6 +640,7 @@ extern LinkArch linkpower64; extern LinkArch linkpower64le; #pragma varargck type "A" int +#pragma varargck type "E" uint #pragma varargck type "D" Addr* #pragma varargck type "lD" Addr* #pragma varargck type "P" Prog* diff --git a/misc/makerelease/makerelease.go b/misc/makerelease/makerelease.go index e94efdbce..8cf6be2a4 100644 --- a/misc/makerelease/makerelease.go +++ b/misc/makerelease/makerelease.go @@ -56,8 +56,8 @@ const ( blogPath = "golang.org/x/blog" toolPath = "golang.org/x/tools" tourPath = "code.google.com/p/go-tour" - defaultToolTag = "release-branch.go1.3" - defaultTourTag = "release-branch.go1.3" + defaultToolTag = "release-branch.go1.4" + defaultTourTag = "release-branch.go1.4" ) // Import paths for tool commands. diff --git a/src/cmd/5g/opt.h b/src/cmd/5g/opt.h index 5016d1cc8..a606f1d31 100644 --- a/src/cmd/5g/opt.h +++ b/src/cmd/5g/opt.h @@ -75,12 +75,18 @@ struct Reg { Flow f; - Bits set; // variables written by this instruction. - Bits use1; // variables read by prog->from. - Bits use2; // variables read by prog->to. + Bits set; // regopt variables written by this instruction. + Bits use1; // regopt variables read by prog->from. + Bits use2; // regopt variables read by prog->to. + // refahead/refbehind are the regopt variables whose current + // value may be used in the following/preceding instructions + // up to a CALL (or the value is clobbered). Bits refbehind; Bits refahead; + // calahead/calbehind are similar, but for variables in + // instructions that are reachable after hitting at least one + // CALL. Bits calbehind; Bits calahead; Bits regdiff; @@ -93,6 +99,16 @@ struct Reg #define NRGN 600 /*c2go enum { NRGN = 600 }; */ + +// A Rgn represents a single regopt variable over a region of code +// where a register could potentially be dedicated to that variable. +// The code encompassed by a Rgn is defined by the flow graph, +// starting at enter, flood-filling forward while varno is refahead +// and backward while varno is refbehind, and following branches. A +// single variable may be represented by multiple disjoint Rgns and +// each Rgn may choose a different register for that variable. +// Registers are allocated to regions greedily in order of descending +// cost. struct Rgn { Reg* enter; @@ -144,7 +160,7 @@ void prop(Reg*, Bits, Bits); void synch(Reg*, Bits); uint32 allreg(uint32, Rgn*); void paint1(Reg*, int); -uint32 paint2(Reg*, int); +uint32 paint2(Reg*, int, int); void paint3(Reg*, int, uint32, int); void addreg(Adr*, int); void dumpit(char *str, Flow *r0, int); @@ -187,16 +203,16 @@ enum SizeF = 1<<7, // float aka float32 SizeD = 1<<8, // double aka float64 - // Left side: address taken, read, write. + // Left side (Prog.from): address taken, read, write. LeftAddr = 1<<9, LeftRead = 1<<10, LeftWrite = 1<<11, - // Register in middle; never written. + // Register in middle (Prog.reg); only ever read. RegRead = 1<<12, CanRegRead = 1<<13, - // Right side: address taken, read, write. + // Right side (Prog.to): address taken, read, write. RightAddr = 1<<14, RightRead = 1<<15, RightWrite = 1<<16, diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c index 441792873..611310f12 100644 --- a/src/cmd/5g/reg.c +++ b/src/cmd/5g/reg.c @@ -230,7 +230,7 @@ regopt(Prog *firstp) /* the mod/div runtime routines smash R12 */ if(p->as == ADIV || p->as == ADIVU || p->as == AMOD || p->as == AMODU) - r->set.b[z] |= RtoB(12); + r->set.b[0] |= RtoB(12); } if(firstr == R) return; @@ -454,9 +454,13 @@ brk: * replace code (paint3) */ rgp = region; + if(debug['R'] && debug['v']) + print("\nregisterizing\n"); for(i=0; i<nregion; i++) { + if(debug['R'] && debug['v']) + print("region %d: cost %d varno %d enter %d\n", i, rgp->cost, rgp->varno, rgp->enter->f.prog->pc); bit = blsh(rgp->varno); - vreg = paint2(rgp->enter, rgp->varno); + vreg = paint2(rgp->enter, rgp->varno, 0); vreg = allreg(vreg, rgp); if(debug['R']) { if(rgp->regno >= NREG) @@ -477,9 +481,6 @@ brk: rgp++; } - if(debug['R'] && debug['v']) - dumpit("pass6", &firstr->f, 1); - /* * free aux structures. peep allocates new ones. */ @@ -488,6 +489,15 @@ brk: flowend(g); firstr = R; + if(debug['R'] && debug['v']) { + // Rebuild flow graph, since we inserted instructions + g = flowstart(firstp, sizeof(Reg)); + firstr = (Reg*)g->start; + dumpit("pass6", &firstr->f, 1); + flowend(g); + firstr = R; + } + /* * pass 7 * peep-hole on basic block @@ -1189,7 +1199,7 @@ paint1(Reg *r, int bn) } uint32 -paint2(Reg *r, int bn) +paint2(Reg *r, int bn, int depth) { Reg *r1; int z; @@ -1213,6 +1223,9 @@ paint2(Reg *r, int bn) r = r1; } for(;;) { + if(debug['R'] && debug['v']) + print(" paint2 %d %P\n", depth, r->f.prog); + r->act.b[z] &= ~bb; vreg |= r->regu; @@ -1220,14 +1233,14 @@ paint2(Reg *r, int bn) if(r->refbehind.b[z] & bb) for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link) if(r1->refahead.b[z] & bb) - vreg |= paint2(r1, bn); + vreg |= paint2(r1, bn, depth+1); if(!(r->refahead.b[z] & bb)) break; r1 = (Reg*)r->f.s2; if(r1 != R) if(r1->refbehind.b[z] & bb) - vreg |= paint2(r1, bn); + vreg |= paint2(r1, bn, depth+1); r = (Reg*)r->f.s1; if(r == R) break; @@ -1344,6 +1357,8 @@ RtoB(int r) int BtoR(uint32 b) { + // TODO Allow R0 and R1, but be careful with a 0 return + // TODO Allow R9. Only R10 is reserved now (just g, not m). b &= 0x11fcL; // excluded R9 and R10 for m and g, but not R12 if(b == 0) return 0; @@ -1442,12 +1457,14 @@ dumpit(char *str, Flow *r0, int isreg) print(" (only)"); print("\n"); } -// r1 = r->s1; -// if(r1 != nil) { -// print(" succ:"); -// for(; r1 != R; r1 = r1->s1) -// print(" %.4ud", (int)r1->prog->pc); -// print("\n"); -// } + // Print successors if it's not just the next one + if(r->s1 != r->link || r->s2 != nil) { + print(" succ:"); + if(r->s1 != nil) + print(" %.4ud", (int)r->s1->prog->pc); + if(r->s2 != nil) + print(" %.4ud", (int)r->s2->prog->pc); + print("\n"); + } } } diff --git a/src/cmd/5l/5.out.h b/src/cmd/5l/5.out.h index 7b16ac446..38a33db64 100644 --- a/src/cmd/5l/5.out.h +++ b/src/cmd/5l/5.out.h @@ -338,6 +338,8 @@ enum D_STATIC = (D_NONE+4), D_AUTO = (D_NONE+5), D_PARAM = (D_NONE+6), + + D_LAST = (D_NONE+26), }; /* diff --git a/src/cmd/6g/opt.h b/src/cmd/6g/opt.h index 4c9bb89fc..493171ef8 100644 --- a/src/cmd/6g/opt.h +++ b/src/cmd/6g/opt.h @@ -75,12 +75,18 @@ struct Reg { Flow f; - Bits set; // variables written by this instruction. - Bits use1; // variables read by prog->from. - Bits use2; // variables read by prog->to. + Bits set; // regopt variables written by this instruction. + Bits use1; // regopt variables read by prog->from. + Bits use2; // regopt variables read by prog->to. + // refahead/refbehind are the regopt variables whose current + // value may be used in the following/preceding instructions + // up to a CALL (or the value is clobbered). Bits refbehind; Bits refahead; + // calahead/calbehind are similar, but for variables in + // instructions that are reachable after hitting at least one + // CALL. Bits calbehind; Bits calahead; Bits regdiff; @@ -93,6 +99,16 @@ struct Reg #define NRGN 600 /*c2go enum { NRGN = 600 }; */ + +// A Rgn represents a single regopt variable over a region of code +// where a register could potentially be dedicated to that variable. +// The code encompassed by a Rgn is defined by the flow graph, +// starting at enter, flood-filling forward while varno is refahead +// and backward while varno is refbehind, and following branches. A +// single variable may be represented by multiple disjoint Rgns and +// each Rgn may choose a different register for that variable. +// Registers are allocated to regions greedily in order of descending +// cost. struct Rgn { Reg* enter; @@ -140,7 +156,7 @@ void prop(Reg*, Bits, Bits); void synch(Reg*, Bits); uint32 allreg(uint32, Rgn*); void paint1(Reg*, int); -uint32 paint2(Reg*, int); +uint32 paint2(Reg*, int, int); void paint3(Reg*, int, uint32, int); void addreg(Adr*, int); void dumpone(Flow*, int); @@ -165,8 +181,8 @@ typedef struct ProgInfo ProgInfo; struct ProgInfo { uint32 flags; // the bits below - uint32 reguse; // required registers used by this instruction - uint32 regset; // required registers set by this instruction + uint32 reguse; // registers implicitly used by this instruction + uint32 regset; // registers implicitly set by this instruction uint32 regindex; // registers used by addressing mode }; @@ -187,12 +203,12 @@ enum SizeF = 1<<7, // float aka float32 SizeD = 1<<8, // double aka float64 - // Left side: address taken, read, write. + // Left side (Prog.from): address taken, read, write. LeftAddr = 1<<9, LeftRead = 1<<10, LeftWrite = 1<<11, - // Right side: address taken, read, write. + // Right side (Prog.to): address taken, read, write. RightAddr = 1<<12, RightRead = 1<<13, RightWrite = 1<<14, diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c index 4ce2f4db0..75f9573b2 100644 --- a/src/cmd/6g/reg.c +++ b/src/cmd/6g/reg.c @@ -389,9 +389,13 @@ brk: * replace code (paint3) */ rgp = region; + if(debug['R'] && debug['v']) + print("\nregisterizing\n"); for(i=0; i<nregion; i++) { + if(debug['R'] && debug['v']) + print("region %d: cost %d varno %d enter %d\n", i, rgp->cost, rgp->varno, rgp->enter->f.prog->pc); bit = blsh(rgp->varno); - vreg = paint2(rgp->enter, rgp->varno); + vreg = paint2(rgp->enter, rgp->varno, 0); vreg = allreg(vreg, rgp); if(rgp->regno != 0) { if(debug['R'] && debug['v']) { @@ -406,9 +410,6 @@ brk: rgp++; } - if(debug['R'] && debug['v']) - dumpit("pass6", &firstr->f, 1); - /* * free aux structures. peep allocates new ones. */ @@ -417,6 +418,15 @@ brk: flowend(g); firstr = R; + if(debug['R'] && debug['v']) { + // Rebuild flow graph, since we inserted instructions + g = flowstart(firstp, sizeof(Reg)); + firstr = (Reg*)g->start; + dumpit("pass6", &firstr->f, 1); + flowend(g); + firstr = R; + } + /* * pass 7 * peep-hole on basic block @@ -1020,7 +1030,7 @@ paint1(Reg *r, int bn) } uint32 -paint2(Reg *r, int bn) +paint2(Reg *r, int bn, int depth) { Reg *r1; int z; @@ -1044,6 +1054,9 @@ paint2(Reg *r, int bn) r = r1; } for(;;) { + if(debug['R'] && debug['v']) + print(" paint2 %d %P\n", depth, r->f.prog); + r->act.b[z] &= ~bb; vreg |= r->regu; @@ -1051,14 +1064,14 @@ paint2(Reg *r, int bn) if(r->refbehind.b[z] & bb) for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link) if(r1->refahead.b[z] & bb) - vreg |= paint2(r1, bn); + vreg |= paint2(r1, bn, depth+1); if(!(r->refahead.b[z] & bb)) break; r1 = (Reg*)r->f.s2; if(r1 != R) if(r1->refbehind.b[z] & bb) - vreg |= paint2(r1, bn); + vreg |= paint2(r1, bn, depth+1); r = (Reg*)r->f.s1; if(r == R) break; @@ -1259,12 +1272,14 @@ dumpit(char *str, Flow *r0, int isreg) print(" %.4ud", (int)r1->prog->pc); print("\n"); } -// r1 = r->s1; -// if(r1 != R) { -// print(" succ:"); -// for(; r1 != R; r1 = r1->s1) -// print(" %.4ud", (int)r1->prog->pc); -// print("\n"); -// } + // Print successors if it's not just the next one + if(r->s1 != r->link || r->s2 != nil) { + print(" succ:"); + if(r->s1 != nil) + print(" %.4ud", (int)r->s1->prog->pc); + if(r->s2 != nil) + print(" %.4ud", (int)r->s2->prog->pc); + print("\n"); + } } } diff --git a/src/cmd/6l/6.out.h b/src/cmd/6l/6.out.h index af72784e8..c09ac2824 100644 --- a/src/cmd/6l/6.out.h +++ b/src/cmd/6l/6.out.h @@ -865,6 +865,8 @@ enum D_INDIR, /* additive */ + D_LAST, + T_TYPE = 1<<0, T_INDEX = 1<<1, T_OFFSET = 1<<2, diff --git a/src/cmd/8g/opt.h b/src/cmd/8g/opt.h index 0e2d165b1..5445f9127 100644 --- a/src/cmd/8g/opt.h +++ b/src/cmd/8g/opt.h @@ -75,12 +75,18 @@ struct Reg { Flow f; - Bits set; // variables written by this instruction. - Bits use1; // variables read by prog->from. - Bits use2; // variables read by prog->to. + Bits set; // regopt variables written by this instruction. + Bits use1; // regopt variables read by prog->from. + Bits use2; // regopt variables read by prog->to. + // refahead/refbehind are the regopt variables whose current + // value may be used in the following/preceding instructions + // up to a CALL (or the value is clobbered). Bits refbehind; Bits refahead; + // calahead/calbehind are similar, but for variables in + // instructions that are reachable after hitting at least one + // CALL. Bits calbehind; Bits calahead; Bits regdiff; @@ -106,6 +112,16 @@ struct Reg #define NRGN 600 /*c2go enum { NRGN = 600 }; */ + +// A Rgn represents a single regopt variable over a region of code +// where a register could potentially be dedicated to that variable. +// The code encompassed by a Rgn is defined by the flow graph, +// starting at enter, flood-filling forward while varno is refahead +// and backward while varno is refbehind, and following branches. A +// single variable may be represented by multiple disjoint Rgns and +// each Rgn may choose a different register for that variable. +// Registers are allocated to regions greedily in order of descending +// cost. struct Rgn { Reg* enter; @@ -158,7 +174,7 @@ void loopit(Reg*, int32); void synch(Reg*, Bits); uint32 allreg(uint32, Rgn*); void paint1(Reg*, int); -uint32 paint2(Reg*, int); +uint32 paint2(Reg*, int, int); void paint3(Reg*, int, uint32, int); void addreg(Adr*, int); void dumpone(Flow*, int); @@ -183,8 +199,8 @@ typedef struct ProgInfo ProgInfo; struct ProgInfo { uint32 flags; // the bits below - uint32 reguse; // required registers used by this instruction - uint32 regset; // required registers set by this instruction + uint32 reguse; // registers implicitly used by this instruction + uint32 regset; // registers implicitly set by this instruction uint32 regindex; // registers used by addressing mode }; @@ -205,12 +221,12 @@ enum SizeF = 1<<7, // float aka float32 SizeD = 1<<8, // double aka float64 - // Left side: address taken, read, write. + // Left side (Prog.from): address taken, read, write. LeftAddr = 1<<9, LeftRead = 1<<10, LeftWrite = 1<<11, - // Right side: address taken, read, write. + // Right side (Prog.to): address taken, read, write. RightAddr = 1<<12, RightRead = 1<<13, RightWrite = 1<<14, diff --git a/src/cmd/8g/reg.c b/src/cmd/8g/reg.c index 79d60bed5..d7394a16d 100644 --- a/src/cmd/8g/reg.c +++ b/src/cmd/8g/reg.c @@ -358,18 +358,19 @@ brk: * replace code (paint3) */ rgp = region; + if(debug['R'] && debug['v']) + print("\nregisterizing\n"); for(i=0; i<nregion; i++) { + if(debug['R'] && debug['v']) + print("region %d: cost %d varno %d enter %lld\n", i, rgp->cost, rgp->varno, rgp->enter->f.prog->pc); bit = blsh(rgp->varno); - vreg = paint2(rgp->enter, rgp->varno); + vreg = paint2(rgp->enter, rgp->varno, 0); vreg = allreg(vreg, rgp); if(rgp->regno != 0) paint3(rgp->enter, rgp->varno, vreg, rgp->regno); rgp++; } - if(debug['R'] && debug['v']) - dumpit("pass6", &firstr->f, 1); - /* * free aux structures. peep allocates new ones. */ @@ -378,6 +379,15 @@ brk: flowend(g); firstr = R; + if(debug['R'] && debug['v']) { + // Rebuild flow graph, since we inserted instructions + g = flowstart(firstp, sizeof(Reg)); + firstr = (Reg*)g->start; + dumpit("pass6", &firstr->f, 1); + flowend(g); + firstr = R; + } + /* * pass 7 * peep-hole on basic block @@ -926,7 +936,7 @@ paint1(Reg *r, int bn) Reg *r1; Prog *p; int z; - uint64 bb; + uint64 bb, rbz; z = bn/64; bb = 1LL<<(bn%64); @@ -945,7 +955,8 @@ paint1(Reg *r, int bn) r = r1; } - if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) { + rbz = ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])); + if(LOAD(r) & rbz & bb) { change -= CLOAD * r->f.loop; } for(;;) { @@ -996,7 +1007,7 @@ paint1(Reg *r, int bn) } uint32 -paint2(Reg *r, int bn) +paint2(Reg *r, int bn, int depth) { Reg *r1; int z; @@ -1020,6 +1031,9 @@ paint2(Reg *r, int bn) r = r1; } for(;;) { + if(debug['R'] && debug['v']) + print(" paint2 %d %P\n", depth, r->f.prog); + r->act.b[z] &= ~bb; vreg |= r->regu; @@ -1027,14 +1041,14 @@ paint2(Reg *r, int bn) if(r->refbehind.b[z] & bb) for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link) if(r1->refahead.b[z] & bb) - vreg |= paint2(r1, bn); + vreg |= paint2(r1, bn, depth+1); if(!(r->refahead.b[z] & bb)) break; r1 = (Reg*)r->f.s2; if(r1 != R) if(r1->refbehind.b[z] & bb) - vreg |= paint2(r1, bn); + vreg |= paint2(r1, bn, depth+1); r = (Reg*)r->f.s1; if(r == R) break; @@ -1053,7 +1067,7 @@ paint3(Reg *r, int bn, uint32 rb, int rn) Reg *r1; Prog *p; int z; - uint64 bb; + uint64 bb, rbz; z = bn/64; bb = 1LL << (bn%64); @@ -1072,7 +1086,8 @@ paint3(Reg *r, int bn, uint32 rb, int rn) r = r1; } - if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb) + rbz = ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])); + if(LOAD(r) & rbz & bb) addmove(r, bn, rn, 0); for(;;) { r->act.b[z] |= bb; @@ -1227,12 +1242,14 @@ dumpit(char *str, Flow *r0, int isreg) print(" %.4ud", (int)r1->prog->pc); print("\n"); } -// r1 = r->s1; -// if(r1 != nil) { -// print(" succ:"); -// for(; r1 != R; r1 = r1->s1) -// print(" %.4ud", (int)r1->prog->pc); -// print("\n"); -// } + // Print successors if it's not just the next one + if(r->s1 != r->link || r->s2 != nil) { + print(" succ:"); + if(r->s1 != nil) + print(" %.4ud", (int)r->s1->prog->pc); + if(r->s2 != nil) + print(" %.4ud", (int)r->s2->prog->pc); + print("\n"); + } } } diff --git a/src/cmd/8l/8.out.h b/src/cmd/8l/8.out.h index ed54f6744..596c5f61a 100644 --- a/src/cmd/8l/8.out.h +++ b/src/cmd/8l/8.out.h @@ -654,6 +654,8 @@ enum D_CONST2 = D_INDIR+D_INDIR, + D_LAST, + T_TYPE = 1<<0, T_INDEX = 1<<1, T_OFFSET = 1<<2, diff --git a/src/cmd/9a/lex.c b/src/cmd/9a/lex.c index 26f21f743..e2945ef89 100644 --- a/src/cmd/9a/lex.c +++ b/src/cmd/9a/lex.c @@ -250,7 +250,7 @@ struct "R27", LREG, 27, "R28", LREG, 28, "R29", LREG, 29, - "R30", LREG, 30, + "g", LREG, 30, // avoid unintentionally clobbering g using R30 "R31", LREG, 31, "F", LF, 0, @@ -488,6 +488,7 @@ struct "SYSCALL", LNOP, ASYSCALL, "UNDEF", LNOP, AUNDEF, + "RET", LRETRN, ARETURN, "RETURN", LRETRN, ARETURN, "RFI", LRETRN, ARFI, "RFCI", LRETRN, ARFCI, diff --git a/src/cmd/9c/Makefile b/src/cmd/9c/Makefile deleted file mode 100644 index 3f528d751..000000000 --- a/src/cmd/9c/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright 2012 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 ../../Make.dist diff --git a/src/cmd/9c/Notes b/src/cmd/9c/Notes deleted file mode 100644 index 92dd9deb3..000000000 --- a/src/cmd/9c/Notes +++ /dev/null @@ -1,14 +0,0 @@ -- effect of register expansion on 32-bit shifts and masks etc -9c -- multab -- floating-point conversions -- conversions of constants -- nodtype for loads -- sign-extension instruction (32-64) when in register? -- double indexing -- SLW (eg, in cat) -- scheduling - -9l -- D_QCONST, DWORD -- maskgen diff --git a/src/cmd/9c/cgen.c b/src/cmd/9c/cgen.c deleted file mode 100644 index bd1f7b28f..000000000 --- a/src/cmd/9c/cgen.c +++ /dev/null @@ -1,1147 +0,0 @@ -// cmd/9c/cgen.c from Vita Nuova. -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "gc.h" -#include "../../runtime/funcdata.h" - -void -cgen(Node *n, Node *nn) -{ - Node *l, *r; - Prog *p1; - Node nod, nod1, nod2, nod3, nod4; - int o; - int32 v, curs; - - if(debug['g']) { - prtree(nn, "cgen lhs"); - prtree(n, "cgen"); - } - if(n == Z || n->type == T) - return; - if(typesu[n->type->etype] && (n->op != OFUNC || nn != Z)) { - sugen(n, nn, n->type->width); - return; - } - l = n->left; - r = n->right; - o = n->op; - if(n->addable >= INDEXED) { - if(nn == Z) { - switch(o) { - default: - nullwarn(Z, Z); - break; - case OINDEX: - nullwarn(l, r); - break; - } - return; - } - gmove(n, nn); - return; - } - curs = cursafe; - - if(n->complex >= FNX) - if(l->complex >= FNX) - if(r != Z && r->complex >= FNX) - switch(o) { - default: - regret(&nod, r, 0, 0); - cgen(r, &nod); - - regsalloc(&nod1, r); - gopcode(OAS, &nod, Z, &nod1); - - regfree(&nod); - nod = *n; - nod.right = &nod1; - cgen(&nod, nn); - return; - - case OFUNC: - case OCOMMA: - case OANDAND: - case OOROR: - case OCOND: - case ODOT: - break; - } - - switch(o) { - default: - diag(n, "unknown op in cgen: %O", o); - break; - - case OAS: - if(l->op == OBIT) - goto bitas; - if(l->addable >= INDEXED) { - if(nn != Z || r->addable < INDEXED) { - regalloc(&nod, r, nn); - cgen(r, &nod); - gmove(&nod, l); - regfree(&nod); - } else - gmove(r, l); - break; - } - if(l->complex >= r->complex) { - reglcgen(&nod1, l, Z); - if(r->addable >= INDEXED) { - gmove(r, &nod1); - if(nn != Z) - gmove(r, nn); - regfree(&nod1); - break; - } - regalloc(&nod, r, nn); - cgen(r, &nod); - } else { - regalloc(&nod, r, nn); - cgen(r, &nod); - reglcgen(&nod1, l, Z); - } - gmove(&nod, &nod1); - regfree(&nod); - regfree(&nod1); - break; - - bitas: - n = l->left; - regalloc(&nod, r, nn); - if(l->complex >= r->complex) { - reglcgen(&nod1, n, Z); - cgen(r, &nod); - } else { - cgen(r, &nod); - reglcgen(&nod1, n, Z); - } - regalloc(&nod2, n, Z); - gopcode(OAS, &nod1, Z, &nod2); - bitstore(l, &nod, &nod1, &nod2, nn); - break; - - case OBIT: - if(nn == Z) { - nullwarn(l, Z); - break; - } - bitload(n, &nod, Z, Z, nn); - gopcode(OAS, &nod, Z, nn); - regfree(&nod); - break; - - case OXOR: - if(nn != Z) - if(r->op == OCONST && r->vconst == -1){ - cgen(l, nn); - gopcode(OCOM, nn, Z, nn); - break; - } - - case OADD: - case OSUB: - case OAND: - case OOR: - case OLSHR: - case OASHL: - case OASHR: - /* - * immediate operands - */ - if(nn != Z && - r->op == OCONST && - !typefd[n->type->etype] && - immconst(r)) { - cgen(l, nn); - if(r->vconst == 0) - if(o != OAND) - break; - if(nn != Z) - gopcode(o, r, Z, nn); - break; - } - - case OMUL: - case OLMUL: - case OLDIV: - case OLMOD: - case ODIV: - case OMOD: - if(nn == Z) { - nullwarn(l, r); - break; - } - if(o == OMUL || o == OLMUL) { - if(mulcon(n, nn)) - break; - if(debug['M']) - print("%L multiply\n", n->lineno); - } - if(l->complex >= r->complex) { - regalloc(&nod, l, nn); - cgen(l, &nod); - regalloc(&nod1, l, Z); /* note: l used for type, so shifts work! */ - cgen(r, &nod1); - gopcode(o, &nod1, Z, &nod); - } else { - regalloc(&nod, l, nn); /* note: l used for type, so shifts work! */ - cgen(r, &nod); - regalloc(&nod1, l, Z); - cgen(l, &nod1); - gopcode(o, &nod, &nod1, &nod); - } - gopcode(OAS, &nod, Z, nn); - regfree(&nod); - regfree(&nod1); - break; - - case OASLSHR: - case OASASHL: - case OASASHR: - case OASAND: - case OASADD: - case OASSUB: - case OASXOR: - case OASOR: - if(l->op == OBIT) - goto asbitop; - if(r->op == OCONST && - !typefd[n->type->etype] && - immconst(r)) { - if(l->addable < INDEXED) - reglcgen(&nod2, l, Z); - else - nod2 = *l; - regalloc(&nod, l, nn); /* note: l used for type, so shifts work! */ - gopcode(OAS, &nod2, Z, &nod); - gopcode(o, r, Z, &nod); - gopcode(OAS, &nod, Z, &nod2); - - regfree(&nod); - if(l->addable < INDEXED) - regfree(&nod2); - break; - } - - case OASLMUL: - case OASLDIV: - case OASLMOD: - case OASMUL: - case OASDIV: - case OASMOD: - if(l->op == OBIT) - goto asbitop; - if(l->complex >= r->complex) { - if(l->addable < INDEXED) - reglcgen(&nod2, l, Z); - else - nod2 = *l; - regalloc(&nod, n, nn); - cgen(r, &nod); - } else { - regalloc(&nod, n, nn); - cgen(r, &nod); - if(l->addable < INDEXED) - reglcgen(&nod2, l, Z); - else - nod2 = *l; - } - regalloc(&nod1, n, Z); - gopcode(OAS, &nod2, Z, &nod1); - if(nod1.type->etype != nod.type->etype){ - regalloc(&nod3, &nod, Z); - gmove(&nod1, &nod3); - regfree(&nod1); - nod1 = nod3; - } - gopcode(o, &nod, &nod1, &nod); - gmove(&nod, &nod2); - if(nn != Z) - gmove(&nod, nn); - regfree(&nod); - regfree(&nod1); - if(l->addable < INDEXED) - regfree(&nod2); - break; - - asbitop: - regalloc(&nod4, n, nn); - regalloc(&nod3, r, Z); - if(l->complex >= r->complex) { - bitload(l, &nod, &nod1, &nod2, &nod4); - cgen(r, &nod3); - } else { - cgen(r, &nod3); - bitload(l, &nod, &nod1, &nod2, &nod4); - } - gmove(&nod, &nod4); - gopcode(n->op, &nod3, Z, &nod4); - regfree(&nod3); - gmove(&nod4, &nod); - regfree(&nod4); - bitstore(l, &nod, &nod1, &nod2, nn); - break; - - case OADDR: - if(nn == Z) { - nullwarn(l, Z); - break; - } - lcgen(l, nn); - break; - - case OFUNC: - if(l->complex >= FNX) { - if(l->op != OIND) - diag(n, "bad function call"); - - regret(&nod, l->left, 0, 0); - cgen(l->left, &nod); - regsalloc(&nod1, l->left); - gopcode(OAS, &nod, Z, &nod1); - regfree(&nod); - - nod = *n; - nod.left = &nod2; - nod2 = *l; - nod2.left = &nod1; - nod2.complex = 1; - cgen(&nod, nn); - - return; - } - if(REGARG >= 0) - o = reg[REGARG]; - gargs(r, &nod, &nod1); - if(l->addable < INDEXED) { - reglcgen(&nod, l, Z); - gopcode(OFUNC, Z, Z, &nod); - regfree(&nod); - } else - gopcode(OFUNC, Z, Z, l); - if(REGARG>=0) - if(o != reg[REGARG]) - reg[REGARG]--; - regret(&nod, n, l->type, 1); // update maxarg if nothing else - if(nn != Z) - gopcode(OAS, &nod, Z, nn); - if(nod.op == OREGISTER) - regfree(&nod); - break; - - case OIND: - if(nn == Z) { - cgen(l, nn); - break; - } - regialloc(&nod, n, nn); - r = l; - while(r->op == OADD) - r = r->right; - if(sconst(r)) { - v = r->vconst; - r->vconst = 0; - cgen(l, &nod); - nod.xoffset += v; - r->vconst = v; - } else - cgen(l, &nod); - regind(&nod, n); - gopcode(OAS, &nod, Z, nn); - regfree(&nod); - break; - - case OEQ: - case ONE: - case OLE: - case OLT: - case OGE: - case OGT: - case OLO: - case OLS: - case OHI: - case OHS: - if(nn == Z) { - nullwarn(l, r); - break; - } - boolgen(n, 1, nn); - break; - - case OANDAND: - case OOROR: - boolgen(n, 1, nn); - if(nn == Z) - patch(p, pc); - break; - - case ONOT: - if(nn == Z) { - nullwarn(l, Z); - break; - } - boolgen(n, 1, nn); - break; - - case OCOMMA: - cgen(l, Z); - cgen(r, nn); - break; - - case OCAST: - if(nn == Z) { - nullwarn(l, Z); - break; - } - /* - * convert from types l->n->nn - */ - if(nocast(l->type, n->type) && nocast(n->type, nn->type)) { - /* both null, gen l->nn */ - cgen(l, nn); - break; - } - regalloc(&nod, l, nn); - cgen(l, &nod); - regalloc(&nod1, n, &nod); - gopcode(OAS, &nod, Z, &nod1); - gopcode(OAS, &nod1, Z, nn); - regfree(&nod1); - regfree(&nod); - break; - - case ODOT: - sugen(l, nodrat, l->type->width); - if(nn != Z) { - warn(n, "non-interruptable temporary"); - nod = *nodrat; - if(!r || r->op != OCONST) { - diag(n, "DOT and no offset"); - break; - } - nod.xoffset += (int32)r->vconst; - nod.type = n->type; - cgen(&nod, nn); - } - break; - - case OCOND: - bcgen(l, 1); - p1 = p; - cgen(r->left, nn); - gbranch(OGOTO); - patch(p1, pc); - p1 = p; - cgen(r->right, nn); - patch(p1, pc); - break; - - case OPOSTINC: - case OPOSTDEC: - v = 1; - if(l->type->etype == TIND) - v = l->type->link->width; - if(o == OPOSTDEC) - v = -v; - if(l->op == OBIT) - goto bitinc; - if(nn == Z) - goto pre; - - if(l->addable < INDEXED) - reglcgen(&nod2, l, Z); - else - nod2 = *l; - - regalloc(&nod, l, nn); - gopcode(OAS, &nod2, Z, &nod); - regalloc(&nod1, l, Z); - if(typefd[l->type->etype]) { - regalloc(&nod3, l, Z); - if(v < 0) { - gopcode(OAS, nodfconst(-v), Z, &nod3); - gopcode(OSUB, &nod3, &nod, &nod1); - } else { - gopcode(OAS, nodfconst(v), Z, &nod3); - gopcode(OADD, &nod3, &nod, &nod1); - } - regfree(&nod3); - } else - gopcode(OADD, nodconst(v), &nod, &nod1); - gopcode(OAS, &nod1, Z, &nod2); - - regfree(&nod); - regfree(&nod1); - if(l->addable < INDEXED) - regfree(&nod2); - break; - - case OPREINC: - case OPREDEC: - v = 1; - if(l->type->etype == TIND) - v = l->type->link->width; - if(o == OPREDEC) - v = -v; - if(l->op == OBIT) - goto bitinc; - - pre: - if(l->addable < INDEXED) - reglcgen(&nod2, l, Z); - else - nod2 = *l; - - regalloc(&nod, l, nn); - gopcode(OAS, &nod2, Z, &nod); - if(typefd[l->type->etype]) { - regalloc(&nod3, l, Z); - if(v < 0) { - gopcode(OAS, nodfconst(-v), Z, &nod3); - gopcode(OSUB, &nod3, Z, &nod); - } else { - gopcode(OAS, nodfconst(v), Z, &nod3); - gopcode(OADD, &nod3, Z, &nod); - } - regfree(&nod3); - } else - gopcode(OADD, nodconst(v), Z, &nod); - gopcode(OAS, &nod, Z, &nod2); - if(nn && l->op == ONAME) /* in x=++i, emit USED(i) */ - gins(ANOP, l, Z); - - regfree(&nod); - if(l->addable < INDEXED) - regfree(&nod2); - break; - - bitinc: - if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) { - bitload(l, &nod, &nod1, &nod2, Z); - gopcode(OAS, &nod, Z, nn); - gopcode(OADD, nodconst(v), Z, &nod); - bitstore(l, &nod, &nod1, &nod2, Z); - break; - } - bitload(l, &nod, &nod1, &nod2, nn); - gopcode(OADD, nodconst(v), Z, &nod); - bitstore(l, &nod, &nod1, &nod2, nn); - break; - } - cursafe = curs; -} - -void -reglcgen(Node *t, Node *n, Node *nn) -{ - Node *r; - int32 v; - - regialloc(t, n, nn); - if(n->op == OIND) { - r = n->left; - while(r->op == OADD) - r = r->right; - if(sconst(r)) { - v = r->vconst; - r->vconst = 0; - lcgen(n, t); - t->xoffset += v; - r->vconst = v; - regind(t, n); - return; - } - } - lcgen(n, t); - regind(t, n); -} - -void -lcgen(Node *n, Node *nn) -{ - Prog *p1; - Node nod; - - if(debug['g']) { - prtree(nn, "lcgen lhs"); - prtree(n, "lcgen"); - } - if(n == Z || n->type == T) - return; - if(nn == Z) { - nn = &nod; - regalloc(&nod, n, Z); - } - switch(n->op) { - default: - if(n->addable < INDEXED) { - diag(n, "unknown op in lcgen: %O", n->op); - break; - } - nod = *n; - nod.op = OADDR; - nod.left = n; - nod.right = Z; - nod.type = types[TIND]; - gopcode(OAS, &nod, Z, nn); - break; - - case OCOMMA: - cgen(n->left, n->left); - lcgen(n->right, nn); - break; - - case OIND: - cgen(n->left, nn); - break; - - case OCOND: - bcgen(n->left, 1); - p1 = p; - lcgen(n->right->left, nn); - gbranch(OGOTO); - patch(p1, pc); - p1 = p; - lcgen(n->right->right, nn); - patch(p1, pc); - break; - } -} - -void -bcgen(Node *n, int true) -{ - - if(n->type == T) - gbranch(OGOTO); - else - boolgen(n, true, Z); -} - -void -boolgen(Node *n, int true, Node *nn) -{ - int o; - Prog *p1, *p2; - Node *l, *r, nod, nod1; - int32 curs; - - if(debug['g']) { - prtree(nn, "boolgen lhs"); - prtree(n, "boolgen"); - } - curs = cursafe; - l = n->left; - r = n->right; - switch(n->op) { - - default: - if(n->op == OCONST) { - o = vconst(n); - if(!true) - o = !o; - gbranch(OGOTO); - if(o) { - p1 = p; - gbranch(OGOTO); - patch(p1, pc); - } - goto com; - } - regalloc(&nod, n, nn); - cgen(n, &nod); - o = ONE; - if(true) - o = comrel[relindex(o)]; - if(typefd[n->type->etype]) { - nodreg(&nod1, n, NREG+FREGZERO); - gopcode(o, &nod, Z, &nod1); - } else - gopcode(o, &nod, Z, nodconst(0)); - regfree(&nod); - goto com; - - case OCOMMA: - cgen(l, Z); - boolgen(r, true, nn); - break; - - case ONOT: - boolgen(l, !true, nn); - break; - - case OCOND: - bcgen(l, 1); - p1 = p; - bcgen(r->left, true); - p2 = p; - gbranch(OGOTO); - patch(p1, pc); - p1 = p; - bcgen(r->right, !true); - patch(p2, pc); - p2 = p; - gbranch(OGOTO); - patch(p1, pc); - patch(p2, pc); - goto com; - - case OANDAND: - if(!true) - goto caseor; - - caseand: - bcgen(l, true); - p1 = p; - bcgen(r, !true); - p2 = p; - patch(p1, pc); - gbranch(OGOTO); - patch(p2, pc); - goto com; - - case OOROR: - if(!true) - goto caseand; - - caseor: - bcgen(l, !true); - p1 = p; - bcgen(r, !true); - p2 = p; - gbranch(OGOTO); - patch(p1, pc); - patch(p2, pc); - goto com; - - case OEQ: - case ONE: - case OLE: - case OLT: - case OGE: - case OGT: - case OHI: - case OHS: - case OLO: - case OLS: - o = n->op; - if(true) - o = comrel[relindex(o)]; - if(l->complex >= FNX && r->complex >= FNX) { - regret(&nod, r, 0, 0); - cgen(r, &nod); - regsalloc(&nod1, r); - gopcode(OAS, &nod, Z, &nod1); - regfree(&nod); - nod = *n; - nod.right = &nod1; - boolgen(&nod, true, nn); - break; - } - if(sconst(r)) { - regalloc(&nod, l, nn); - cgen(l, &nod); - gopcode(o, &nod, Z, r); - regfree(&nod); - goto com; - } - if(l->complex >= r->complex) { - regalloc(&nod1, l, nn); - cgen(l, &nod1); - regalloc(&nod, r, Z); - cgen(r, &nod); - } else { - regalloc(&nod, r, nn); - cgen(r, &nod); - regalloc(&nod1, l, Z); - cgen(l, &nod1); - } - gopcode(o, &nod1, Z, &nod); - regfree(&nod); - regfree(&nod1); - - com: - if(nn != Z) { - p1 = p; - gopcode(OAS, nodconst(1L), Z, nn); - gbranch(OGOTO); - p2 = p; - patch(p1, pc); - gopcode(OAS, nodconst(0L), Z, nn); - patch(p2, pc); - } - break; - } - cursafe = curs; -} - -void -sugen(Node *n, Node *nn, int32 w) -{ - Prog *p1; - Node nod0, nod1, nod2, nod3, nod4, *l, *r; - Type *t; - int32 pc1; - int i, m, c; - - if(n == Z || n->type == T) - return; - if(debug['g']) { - prtree(nn, "sugen lhs"); - prtree(n, "sugen"); - } - if(nn == nodrat) - if(w > nrathole) - nrathole = w; - switch(n->op) { - case OIND: - if(nn == Z) { - nullwarn(n->left, Z); - break; - } - - default: - goto copy; - - case OCONST: - if(n->type && typev[n->type->etype]) { - if(nn == Z) { - nullwarn(n->left, Z); - break; - } - - t = nn->type; - nn->type = types[TLONG]; - reglcgen(&nod1, nn, Z); - nn->type = t; - - if(align(0, types[TCHAR], Aarg1, nil)) /* isbigendian */ - gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1); - else - gopcode(OAS, nod32const(n->vconst), Z, &nod1); - nod1.xoffset += SZ_LONG; - if(align(0, types[TCHAR], Aarg1, nil)) /* isbigendian */ - gopcode(OAS, nod32const(n->vconst), Z, &nod1); - else - gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1); - - regfree(&nod1); - break; - } - goto copy; - - case ODOT: - l = n->left; - sugen(l, nodrat, l->type->width); - if(nn != Z) { - warn(n, "non-interruptable temporary"); - nod1 = *nodrat; - r = n->right; - if(!r || r->op != OCONST) { - diag(n, "DOT and no offset"); - break; - } - nod1.xoffset += (int32)r->vconst; - nod1.type = n->type; - sugen(&nod1, nn, w); - } - break; - - case OSTRUCT: - /* - * rewrite so lhs has no side effects - */ - if(nn != Z && side(nn)) { - nod1 = *n; - nod1.type = typ(TIND, n->type); - regalloc(&nod2, &nod1, Z); - lcgen(nn, &nod2); - regsalloc(&nod0, &nod1); - gopcode(OAS, &nod2, Z, &nod0); - regfree(&nod2); - - nod1 = *n; - nod1.op = OIND; - nod1.left = &nod0; - nod1.right = Z; - nod1.complex = 1; - - sugen(n, &nod1, w); - return; - } - - r = n->left; - for(t = n->type->link; t != T; t = t->down) { - l = r; - if(r->op == OLIST) { - l = r->left; - r = r->right; - } - if(nn == Z) { - cgen(l, nn); - continue; - } - /* - * hand craft *(&nn + o) = l - */ - nod0 = znode; - nod0.op = OAS; - nod0.type = t; - nod0.left = &nod1; - nod0.right = l; - - nod1 = znode; - nod1.op = OIND; - nod1.type = t; - nod1.left = &nod2; - - nod2 = znode; - nod2.op = OADD; - nod2.type = typ(TIND, t); - nod2.left = &nod3; - nod2.right = &nod4; - - nod3 = znode; - nod3.op = OADDR; - nod3.type = nod2.type; - nod3.left = nn; - - nod4 = znode; - nod4.op = OCONST; - nod4.type = nod2.type; - nod4.vconst = t->offset; - - ccom(&nod0); - acom(&nod0); - xcom(&nod0); - nod0.addable = 0; - - /* prtree(&nod0, "hand craft"); /* */ - cgen(&nod0, Z); - } - break; - - case OAS: - if(nn == Z) { - if(n->addable < INDEXED) - sugen(n->right, n->left, w); - break; - } - /* BOTCH -- functions can clobber rathole */ - sugen(n->right, nodrat, w); - warn(n, "non-interruptable temporary"); - sugen(nodrat, n->left, w); - sugen(nodrat, nn, 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; - } - if(nn->op != OIND) { - nn = new1(OADDR, nn, Z); - nn->type = types[TIND]; - nn->addable = 0; - } else - nn = nn->left; - n = new(OFUNC, n->left, new(OLIST, nn, n->right)); - n->type = types[TVOID]; - n->left->type = types[TVOID]; - cgen(n, Z); - break; - - case OCOND: - bcgen(n->left, 1); - p1 = p; - sugen(n->right->left, nn, w); - gbranch(OGOTO); - patch(p1, pc); - p1 = p; - sugen(n->right->right, nn, w); - patch(p1, pc); - break; - - case OCOMMA: - cgen(n->left, Z); - sugen(n->right, nn, w); - break; - } - return; - -copy: - if(nn == Z) - return; - if(n->complex >= FNX && nn->complex >= FNX) { - t = nn->type; - nn->type = types[TLONG]; - regialloc(&nod1, nn, Z); - lcgen(nn, &nod1); - regsalloc(&nod2, nn); - nn->type = t; - - gopcode(OAS, &nod1, Z, &nod2); - regfree(&nod1); - - nod2.type = typ(TIND, t); - - nod1 = nod2; - nod1.op = OIND; - nod1.left = &nod2; - nod1.right = Z; - nod1.complex = 1; - nod1.type = t; - - sugen(n, &nod1, w); - return; - } - - if(n->complex > nn->complex) { - t = n->type; - n->type = types[TLONG]; - reglcgen(&nod1, n, Z); - n->type = t; - - t = nn->type; - nn->type = types[TLONG]; - reglcgen(&nod2, nn, Z); - nn->type = t; - } else { - t = nn->type; - nn->type = types[TLONG]; - reglcgen(&nod2, nn, Z); - nn->type = t; - - t = n->type; - n->type = types[TLONG]; - reglcgen(&nod1, n, Z); - n->type = t; - } - - w /= SZ_LONG; - if(w <= 5) { - layout(&nod1, &nod2, w, 0, Z); - goto out; - } - - /* - * minimize space for unrolling loop - * 3,4,5 times. (6 or more is never minimum) - * if small structure, try 2 also. - */ - c = 0; /* set */ - m = 100; - i = 3; - if(w <= 15) - i = 2; - for(; i<=5; i++) - if(i + w%i <= m) { - c = i; - m = c + w%c; - } - - regalloc(&nod3, ®node, Z); - layout(&nod1, &nod2, w%c, w/c, &nod3); - - pc1 = pc; - layout(&nod1, &nod2, c, 0, Z); - - gopcode(OSUB, nodconst(1L), Z, &nod3); - nod1.op = OREGISTER; - gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod1); - nod2.op = OREGISTER; - gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod2); - - gopcode(OGT, &nod3, Z, nodconst(0)); - patch(p, pc1); - - regfree(&nod3); -out: - regfree(&nod1); - regfree(&nod2); -} - -void -layout(Node *f, Node *t, int c, int cv, Node *cn) -{ - Node t1, t2; - - while(c > 3) { - layout(f, t, 2, 0, Z); - c -= 2; - } - - regalloc(&t1, ®node, Z); - regalloc(&t2, ®node, Z); - if(c > 0) { - gopcode(OAS, f, Z, &t1); - f->xoffset += SZ_LONG; - } - if(cn != Z) - gopcode(OAS, nodconst(cv), Z, cn); - if(c > 1) { - gopcode(OAS, f, Z, &t2); - f->xoffset += SZ_LONG; - } - if(c > 0) { - gopcode(OAS, &t1, Z, t); - t->xoffset += SZ_LONG; - } - if(c > 2) { - gopcode(OAS, f, Z, &t1); - f->xoffset += SZ_LONG; - } - if(c > 1) { - gopcode(OAS, &t2, Z, t); - t->xoffset += SZ_LONG; - } - if(c > 2) { - gopcode(OAS, &t1, Z, t); - t->xoffset += SZ_LONG; - } - regfree(&t1); - regfree(&t2); -} diff --git a/src/cmd/9c/doc.go b/src/cmd/9c/doc.go deleted file mode 100644 index 6c9b4762d..000000000 --- a/src/cmd/9c/doc.go +++ /dev/null @@ -1,17 +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. - -// +build ignore - -/* - -9c is a version of the Plan 9 C compiler. The original is documented at - - http://plan9.bell-labs.com/magic/man2html/1/8c - -Its target architecture is the Power64, referred to by these tools as -power64 (big endian) or power64le (little endian). - -*/ -package main diff --git a/src/cmd/9c/gc.h b/src/cmd/9c/gc.h deleted file mode 100644 index fbe5099fe..000000000 --- a/src/cmd/9c/gc.h +++ /dev/null @@ -1,350 +0,0 @@ -// cmd/9c/gc.h from Vita Nuova. -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include <u.h> -#include "../cc/cc.h" -#include "../9l/9.out.h" - -/* - * 9c/powerpc64 - */ -#define SZ_CHAR 1 -#define SZ_SHORT 2 -#define SZ_INT 4 -#define SZ_LONG 4 -#define SZ_IND 8 -#define SZ_FLOAT 4 -#define SZ_VLONG 8 -#define SZ_DOUBLE 8 -#define FNX 100 - -typedef struct Case Case; -typedef struct C1 C1; -typedef struct Multab Multab; -typedef struct Hintab Hintab; -typedef struct Reg Reg; -typedef struct Rgn Rgn; - -#define A ((Adr*)0) - -#define INDEXED 9 -#define P ((Prog*)0) - -struct Case -{ - Case* link; - vlong val; - int32 label; - char def; - char isv; -}; -#define C ((Case*)0) - -struct C1 -{ - vlong val; - int32 label; -}; - -struct Multab -{ - int32 val; - char code[20]; -}; - -struct Hintab -{ - ushort val; - char hint[10]; -}; - -struct Reg -{ - int32 pc; - int32 rpo; /* reverse post ordering */ - - Bits set; - Bits use1; - Bits use2; - - Bits refbehind; - Bits refahead; - Bits calbehind; - Bits calahead; - Bits regdiff; - Bits act; - - int32 regu; - int32 loop; /* could be shorter */ - - union - { - Reg* log5; - int32 active; - }; - Reg* p1; - Reg* p2; - Reg* p2link; - Reg* s1; - Reg* s2; - Reg* link; - Prog* prog; -}; -#define R ((Reg*)0) - -#define NRGN 600 -struct Rgn -{ - Reg* enter; - short cost; - short varno; - short regno; -}; - -EXTERN int32 breakpc; -EXTERN int32 nbreak; -EXTERN Case* cases; -EXTERN Node constnode; -EXTERN Node fconstnode; -EXTERN Node vconstnode; -EXTERN int32 continpc; -EXTERN int32 curarg; -EXTERN int32 cursafe; -EXTERN Prog* lastp; -extern int hintabsize; -EXTERN int32 maxargsafe; -EXTERN Multab multab[20]; -EXTERN int mnstring; -EXTERN Node* nodrat; -EXTERN Node* nodret; -EXTERN Node* nodsafe; -EXTERN int32 nrathole; -EXTERN int32 nstring; -EXTERN Prog* p; -EXTERN int32 pc; -EXTERN Node regnode; -EXTERN Node qregnode; -EXTERN char string[NSNAME]; -EXTERN Sym* symrathole; -EXTERN Node znode; -EXTERN Prog zprog; -EXTERN int reg[NREG+NREG]; -EXTERN int32 exregoffset; -EXTERN int32 exfregoffset; -EXTERN uchar typechlpv[NTYPE]; - -#define BLOAD(r) band(bnot(r->refbehind), r->refahead) -#define BSTORE(r) band(bnot(r->calbehind), r->calahead) -#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z]) -#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z]) - -#define bset(a,n) ((a).b[(n)/32]&(1L<<(n)%32)) - -#define CLOAD 5 -#define CREF 5 -#define CINF 1000 -#define LOOP 3 - -EXTERN Rgn region[NRGN]; -EXTERN Rgn* rgp; -EXTERN int nregion; -EXTERN int nvar; - -EXTERN Bits externs; -EXTERN Bits params; -EXTERN Bits consts; -EXTERN Bits addrs; - -EXTERN int32 regbits; -EXTERN int32 exregbits; - -EXTERN int change; -EXTERN int suppress; - -EXTERN Reg* firstr; -EXTERN Reg* lastr; -EXTERN Reg zreg; -EXTERN Reg* freer; -EXTERN Var var[NVAR]; -EXTERN int32* idom; -EXTERN Reg** rpo2r; -EXTERN int32 maxnr; - -#define R0ISZERO (debug['0']==0) - -extern char* anames[]; -extern Hintab hintab[]; - -/* - * sgen.c - */ -void codgen(Node*, Node*); -void gen(Node*); -void usedset(Node*, int); -void noretval(int); -void xcom(Node*); -int bcomplex(Node*, Node*); -Prog* gtext(Sym*, int32); -vlong argsize(int); - -/* - * cgen.c - */ -void cgen(Node*, Node*); -void reglcgen(Node*, Node*, Node*); -void lcgen(Node*, Node*); -void bcgen(Node*, int); -void boolgen(Node*, int, Node*); -void sugen(Node*, Node*, int32); -void layout(Node*, Node*, int, int, Node*); - -/* - * txt.c - */ -void ginit(void); -void gclean(void); -void nextpc(void); -void gargs(Node*, Node*, Node*); -void garg1(Node*, Node*, Node*, int, Node**); -Node* nodconst(int32); -Node* nod32const(vlong); -Node* nodfconst(double); -Node* nodgconst(vlong v, Type *t); -void nodreg(Node*, Node*, int); -void regret(Node*, Node*, Type*, int); -void regalloc(Node*, Node*, Node*); -void regfree(Node*); -void regialloc(Node*, Node*, Node*); -void regsalloc(Node*, Node*); -void regaalloc1(Node*, Node*); -void regaalloc(Node*, Node*); -void regind(Node*, Node*); -void gprep(Node*, Node*); -void raddr(Node*, Prog*); -void naddr(Node*, Addr*); -void gmove(Node*, Node*); -void gins(int a, Node*, Node*); -void gopcode(int, Node*, Node*, Node*); -int samaddr(Node*, Node*); -void gbranch(int); -int immconst(Node*); -void patch(Prog*, int32); -int sconst(Node*); -int sval(int32); -int uconst(Node*); -void gpseudo(int, Sym*, Node*); -void gprefetch(Node*); -void gpcdata(int, int); - -/* - * swt.c - */ -int swcmp(const void*, const void*); -void doswit(Node*); -void swit1(C1*, int, int32, Node*); -void swit2(C1*, int, int32, Node*, Node*); -void newcase(void); -void bitload(Node*, Node*, Node*, Node*, Node*); -void bitstore(Node*, Node*, Node*, Node*, Node*); -int32 outstring(char*, int32); -int mulcon(Node*, Node*); -Multab* mulcon0(Node*, int32); -int mulcon1(Node*, int32, Node*); -void nullwarn(Node*, Node*); -void sextern(Sym*, Node*, int32, int32); -void gextern(Sym*, Node*, int32, int32); -void outcode(void); - -/* - * list - */ -void listinit(void); -int Pconv(Fmt*); -int Aconv(Fmt*); -int Dconv(Fmt*); -int Sconv(Fmt*); -int Nconv(Fmt*); -int Bconv(Fmt*); - -/* - * reg.c - */ -Reg* rega(void); -int rcmp(const void*, const void*); -void regopt(Prog*); -void addmove(Reg*, int, int, int); -Bits mkvar(Addr*, int); -void prop(Reg*, Bits, Bits); -void loopit(Reg*, int32); -void synch(Reg*, Bits); -uint32 allreg(uint32, Rgn*); -void paint1(Reg*, int); -uint32 paint2(Reg*, int); -void paint3(Reg*, int, int32, int); -void addreg(Addr*, int); - -/* - * peep.c - */ -void peep(void); -void excise(Reg*); -Reg* uniqp(Reg*); -Reg* uniqs(Reg*); -int regtyp(Addr*); -int regzer(Addr*); -int anyvar(Addr*); -int subprop(Reg*); -int copyprop(Reg*); -int copy1(Addr*, Addr*, Reg*, int); -int copyu(Prog*, Addr*, Addr*); - -int copyas(Addr*, Addr*); -int copyau(Addr*, Addr*); -int copyau1(Prog*, Addr*); -int copysub(Addr*, Addr*, Addr*, int); -int copysub1(Prog*, Addr*, Addr*, int); - -int32 RtoB(int); -int32 FtoB(int); -int BtoR(int32); -int BtoF(int32); - -/* - * com64.c - */ -int com64(Node*); -void com64init(void); -void bool64(Node*); - -#pragma varargck type "A" int -#pragma varargck type "B" Bits -#pragma varargck type "D" Addr* -#pragma varargck type "N" Addr* -#pragma varargck type "P" Prog* -#pragma varargck type "S" char* diff --git a/src/cmd/9c/list.c b/src/cmd/9c/list.c deleted file mode 100644 index 5cfc442cb..000000000 --- a/src/cmd/9c/list.c +++ /dev/null @@ -1,37 +0,0 @@ -// cmd/9c/list.c from Vita Nuova. -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#define EXTERN -#include "gc.h" - -void -listinit(void) -{ - listinit9(); -} diff --git a/src/cmd/9c/machcap.c b/src/cmd/9c/machcap.c deleted file mode 100644 index af44bc820..000000000 --- a/src/cmd/9c/machcap.c +++ /dev/null @@ -1,105 +0,0 @@ -// cmd/9c/machcap.c from Vita Nuova. -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "gc.h" - -int -machcap(Node *n) -{ - - if(n == Z) - return 1; /* test */ - - switch(n->op) { - case OMUL: - case OLMUL: - case OASMUL: - case OASLMUL: - if(typechlv[n->type->etype]) - return 1; - break; - - case OADD: - case OAND: - case OOR: - case OSUB: - case OXOR: - case OASHL: - case OLSHR: - case OASHR: - if(typechlv[n->left->type->etype]) - return 1; - break; - - case OCAST: - return 1; - - case OCOND: - case OCOMMA: - case OLIST: - case OANDAND: - case OOROR: - case ONOT: - return 1; - - case OASADD: - case OASSUB: - case OASAND: - case OASOR: - case OASXOR: - return 1; - - case OASASHL: - case OASASHR: - case OASLSHR: - return 1; - - case OPOSTINC: - case OPOSTDEC: - case OPREINC: - case OPREDEC: - return 1; - - case OEQ: - case ONE: - case OLE: - case OGT: - case OLT: - case OGE: - case OHI: - case OHS: - case OLO: - case OLS: - return 1; - case ONEG: - case OCOM: - break; - } - return 0; -} diff --git a/src/cmd/9c/mul.c b/src/cmd/9c/mul.c deleted file mode 100644 index 353376f15..000000000 --- a/src/cmd/9c/mul.c +++ /dev/null @@ -1,638 +0,0 @@ -// cmd/9c/mul.c from Vita Nuova. -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "gc.h" - -/* - * code sequences for multiply by constant. - * [a-l][0-3] - * lsl $(A-'a'),r0,r1 - * [+][0-7] - * add r0,r1,r2 - * [-][0-7] - * sub r0,r1,r2 - */ - -static int multabp; -static int32 mulval; -static char* mulcp; -static int32 valmax; -static int shmax; - -static int docode(char *hp, char *cp, int r0, int r1); -static int gen1(int len); -static int gen2(int len, int32 r1); -static int gen3(int len, int32 r0, int32 r1, int flag); -enum -{ - SR1 = 1<<0, /* r1 has been shifted */ - SR0 = 1<<1, /* r0 has been shifted */ - UR1 = 1<<2, /* r1 has not been used */ - UR0 = 1<<3, /* r0 has not been used */ -}; - -Multab* -mulcon0(Node *n, int32 v) -{ - int a1, a2, g; - Multab *m, *m1; - char hint[10]; - - if(v < 0) - v = -v; - - /* - * look in cache - */ - m = multab; - for(g=0; g<nelem(multab); g++) { - if(m->val == v) { - if(m->code[0] == 0) - return 0; - return m; - } - m++; - } - - /* - * select a spot in cache to overwrite - */ - multabp++; - if(multabp < 0 || multabp >= nelem(multab)) - multabp = 0; - m = multab+multabp; - m->val = v; - mulval = v; - - /* - * look in execption hint table - */ - a1 = 0; - a2 = hintabsize; - for(;;) { - if(a1 >= a2) - goto no; - g = (a2 + a1)/2; - if(v < hintab[g].val) { - a2 = g; - continue; - } - if(v > hintab[g].val) { - a1 = g+1; - continue; - } - break; - } - - if(docode(hintab[g].hint, m->code, 1, 0)) - return m; - print("%L: multiply table failure %ld\n", n->lineno, v); - m->code[0] = 0; - return 0; - -no: - /* - * try to search - */ - hint[0] = 0; - for(g=1; g<=6; g++) { - if(g >= 6 && v >= 65535) - break; - mulcp = hint+g; - *mulcp = 0; - if(gen1(g)) { - if(docode(hint, m->code, 1, 0)) - return m; - print("%L: multiply table failure (g=%d h=%s) %ld\n", - n->lineno, g, hint, v); - break; - } - } - - /* - * try a recur followed by a shift - */ - g = 0; - while(!(v & 1)) { - g++; - v >>= 1; - } - if(g) { - m1 = mulcon0(n, v); - if(m1) { - strcpy(m->code, m1->code); - sprint(strchr(m->code, 0), "%c0", g+'a'); - return m; - } - } - m->code[0] = 0; - return 0; -} - -static int -docode(char *hp, char *cp, int r0, int r1) -{ - int c, i; - - c = *hp++; - *cp = c; - cp += 2; - switch(c) { - default: - c -= 'a'; - if(c < 1 || c >= 30) - break; - for(i=0; i<4; i++) { - switch(i) { - case 0: - if(docode(hp, cp, r0<<c, r1)) - goto out; - break; - case 1: - if(docode(hp, cp, r1<<c, r1)) - goto out; - break; - case 2: - if(docode(hp, cp, r0, r0<<c)) - goto out; - break; - case 3: - if(docode(hp, cp, r0, r1<<c)) - goto out; - break; - } - } - break; - - case '+': - for(i=0; i<8; i++) { - cp[-1] = i+'0'; - switch(i) { - case 1: - if(docode(hp, cp, r0+r1, r1)) - goto out; - break; - case 5: - if(docode(hp, cp, r0, r0+r1)) - goto out; - break; - } - } - break; - - case '-': - for(i=0; i<8; i++) { - cp[-1] = i+'0'; - switch(i) { - case 1: - if(docode(hp, cp, r0-r1, r1)) - goto out; - break; - case 2: - if(docode(hp, cp, r1-r0, r1)) - goto out; - break; - case 5: - if(docode(hp, cp, r0, r0-r1)) - goto out; - break; - case 6: - if(docode(hp, cp, r0, r1-r0)) - goto out; - break; - } - } - break; - - case 0: - if(r0 == mulval) - return 1; - } - return 0; - -out: - cp[-1] = i+'0'; - return 1; -} - -static int -gen1(int len) -{ - int i; - - for(shmax=1; shmax<30; shmax++) { - valmax = 1<<shmax; - if(valmax >= mulval) - break; - } - if(mulval == 1) - return 1; - - len--; - for(i=1; i<=shmax; i++) - if(gen2(len, 1<<i)) { - *--mulcp = 'a'+i; - return 1; - } - return 0; -} - -static int -gen2(int len, int32 r1) -{ - int i; - - if(len <= 0) { - if(r1 == mulval) - return 1; - return 0; - } - - len--; - if(len == 0) - goto calcr0; - - if(gen3(len, r1, r1+1, UR1)) { - i = '+'; - goto out; - } - if(gen3(len, r1-1, r1, UR0)) { - i = '-'; - goto out; - } - if(gen3(len, 1, r1+1, UR1)) { - i = '+'; - goto out; - } - if(gen3(len, 1, r1-1, UR1)) { - i = '-'; - goto out; - } - - return 0; - -calcr0: - if(mulval == r1+1) { - i = '+'; - goto out; - } - if(mulval == r1-1) { - i = '-'; - goto out; - } - return 0; - -out: - *--mulcp = i; - return 1; -} - -static int -gen3(int len, int32 r0, int32 r1, int flag) -{ - int i, f1, f2; - int32 x; - - if(r0 <= 0 || - r0 >= r1 || - r1 > valmax) - return 0; - - len--; - if(len == 0) - goto calcr0; - - if(!(flag & UR1)) { - f1 = UR1|SR1; - for(i=1; i<=shmax; i++) { - x = r0<<i; - if(x > valmax) - break; - if(gen3(len, r0, x, f1)) { - i += 'a'; - goto out; - } - } - } - - if(!(flag & UR0)) { - f1 = UR1|SR1; - for(i=1; i<=shmax; i++) { - x = r1<<i; - if(x > valmax) - break; - if(gen3(len, r1, x, f1)) { - i += 'a'; - goto out; - } - } - } - - if(!(flag & SR1)) { - f1 = UR1|SR1|(flag&UR0); - for(i=1; i<=shmax; i++) { - x = r1<<i; - if(x > valmax) - break; - if(gen3(len, r0, x, f1)) { - i += 'a'; - goto out; - } - } - } - - if(!(flag & SR0)) { - f1 = UR0|SR0|(flag&(SR1|UR1)); - - f2 = UR1|SR1; - if(flag & UR1) - f2 |= UR0; - if(flag & SR1) - f2 |= SR0; - - for(i=1; i<=shmax; i++) { - x = r0<<i; - if(x > valmax) - break; - if(x > r1) { - if(gen3(len, r1, x, f2)) { - i += 'a'; - goto out; - } - } else - if(gen3(len, x, r1, f1)) { - i += 'a'; - goto out; - } - } - } - - x = r1+r0; - if(gen3(len, r0, x, UR1)) { - i = '+'; - goto out; - } - - if(gen3(len, r1, x, UR1)) { - i = '+'; - goto out; - } - - x = r1-r0; - if(gen3(len, x, r1, UR0)) { - i = '-'; - goto out; - } - - if(x > r0) { - if(gen3(len, r0, x, UR1)) { - i = '-'; - goto out; - } - } else - if(gen3(len, x, r0, UR0)) { - i = '-'; - goto out; - } - - return 0; - -calcr0: - f1 = flag & (UR0|UR1); - if(f1 == UR1) { - for(i=1; i<=shmax; i++) { - x = r1<<i; - if(x >= mulval) { - if(x == mulval) { - i += 'a'; - goto out; - } - break; - } - } - } - - if(mulval == r1+r0) { - i = '+'; - goto out; - } - if(mulval == r1-r0) { - i = '-'; - goto out; - } - - return 0; - -out: - *--mulcp = i; - return 1; -} - -/* - * hint table has numbers that - * the search algorithm fails on. - * <1000: - * all numbers - * <5000: - * ÷ by 5 - * <10000: - * ÷ by 50 - * <65536: - * ÷ by 250 - */ -Hintab hintab[] = -{ - 683, "b++d+e+", - 687, "b+e++e-", - 691, "b++d+e+", - 731, "b++d+e+", - 811, "b++d+i+", - 821, "b++e+e+", - 843, "b+d++e+", - 851, "b+f-+e-", - 853, "b++e+e+", - 877, "c++++g-", - 933, "b+c++g-", - 981, "c-+e-d+", - 1375, "b+c+b+h-", - 1675, "d+b++h+", - 2425, "c++f-e+", - 2675, "c+d++f-", - 2750, "b+d-b+h-", - 2775, "c-+g-e-", - 3125, "b++e+g+", - 3275, "b+c+g+e+", - 3350, "c++++i+", - 3475, "c-+e-f-", - 3525, "c-+d+g-", - 3625, "c-+e-j+", - 3675, "b+d+d+e+", - 3725, "b+d-+h+", - 3925, "b+d+f-d-", - 4275, "b+g++e+", - 4325, "b+h-+d+", - 4425, "b+b+g-j-", - 4525, "b+d-d+f+", - 4675, "c++d-g+", - 4775, "b+d+b+g-", - 4825, "c+c-+i-", - 4850, "c++++i-", - 4925, "b++e-g-", - 4975, "c+f++e-", - 5500, "b+g-c+d+", - 6700, "d+b++i+", - 9700, "d++++j-", - 11000, "b+f-c-h-", - 11750, "b+d+g+j-", - 12500, "b+c+e-k+", - 13250, "b+d+e-f+", - 13750, "b+h-c-d+", - 14250, "b+g-c+e-", - 14500, "c+f+j-d-", - 14750, "d-g--f+", - 16750, "b+e-d-n+", - 17750, "c+h-b+e+", - 18250, "d+b+h-d+", - 18750, "b+g-++f+", - 19250, "b+e+b+h+", - 19750, "b++h--f-", - 20250, "b+e-l-c+", - 20750, "c++bi+e-", - 21250, "b+i+l+c+", - 22000, "b+e+d-g-", - 22250, "b+d-h+k-", - 22750, "b+d-e-g+", - 23250, "b+c+h+e-", - 23500, "b+g-c-g-", - 23750, "b+g-b+h-", - 24250, "c++g+m-", - 24750, "b+e+e+j-", - 25000, "b++dh+g+", - 25250, "b+e+d-g-", - 25750, "b+e+b+j+", - 26250, "b+h+c+e+", - 26500, "b+h+c+g+", - 26750, "b+d+e+g-", - 27250, "b+e+e+f+", - 27500, "c-i-c-d+", - 27750, "b+bd++j+", - 28250, "d-d-++i-", - 28500, "c+c-h-e-", - 29000, "b+g-d-f+", - 29500, "c+h+++e-", - 29750, "b+g+f-c+", - 30250, "b+f-g-c+", - 33500, "c-f-d-n+", - 33750, "b+d-b+j-", - 34250, "c+e+++i+", - 35250, "e+b+d+k+", - 35500, "c+e+d-g-", - 35750, "c+i-++e+", - 36250, "b+bh-d+e+", - 36500, "c+c-h-e-", - 36750, "d+e--i+", - 37250, "b+g+g+b+", - 37500, "b+h-b+f+", - 37750, "c+be++j-", - 38500, "b+e+b+i+", - 38750, "d+i-b+d+", - 39250, "b+g-l-+d+", - 39500, "b+g-c+g-", - 39750, "b+bh-c+f-", - 40250, "b+bf+d+g-", - 40500, "b+g-c+g+", - 40750, "c+b+i-e+", - 41250, "d++bf+h+", - 41500, "b+j+c+d-", - 41750, "c+f+b+h-", - 42500, "c+h++g+", - 42750, "b+g+d-f-", - 43250, "b+l-e+d-", - 43750, "c+bd+h+f-", - 44000, "b+f+g-d-", - 44250, "b+d-g--f+", - 44500, "c+e+c+h+", - 44750, "b+e+d-h-", - 45250, "b++g+j-g+", - 45500, "c+d+e-g+", - 45750, "b+d-h-e-", - 46250, "c+bd++j+", - 46500, "b+d-c-j-", - 46750, "e-e-b+g-", - 47000, "b+c+d-j-", - 47250, "b+e+e-g-", - 47500, "b+g-c-h-", - 47750, "b+f-c+h-", - 48250, "d--h+n-", - 48500, "b+c-g+m-", - 48750, "b+e+e-g+", - 49500, "c-f+e+j-", - 49750, "c+c+g++f-", - 50000, "b+e+e+k+", - 50250, "b++i++g+", - 50500, "c+g+f-i+", - 50750, "b+e+d+k-", - 51500, "b+i+c-f+", - 51750, "b+bd+g-e-", - 52250, "b+d+g-j+", - 52500, "c+c+f+g+", - 52750, "b+c+e+i+", - 53000, "b+i+c+g+", - 53500, "c+g+g-n+", - 53750, "b+j+d-c+", - 54250, "b+d-g-j-", - 54500, "c-f+e+f+", - 54750, "b+f-+c+g+", - 55000, "b+g-d-g-", - 55250, "b+e+e+g+", - 55500, "b+cd++j+", - 55750, "b+bh-d-f-", - 56250, "c+d-b+j-", - 56500, "c+d+c+i+", - 56750, "b+e+d++h-", - 57000, "b+d+g-f+", - 57250, "b+f-m+d-", - 57750, "b+i+c+e-", - 58000, "b+e+d+h+", - 58250, "c+b+g+g+", - 58750, "d-e-j--e+", - 59000, "d-i-+e+", - 59250, "e--h-m+", - 59500, "c+c-h+f-", - 59750, "b+bh-e+i-", - 60250, "b+bh-e-e-", - 60500, "c+c-g-g-", - 60750, "b+e-l-e-", - 61250, "b+g-g-c+", - 61750, "b+g-c+g+", - 62250, "f--+c-i-", - 62750, "e+f--+g+", - 64750, "b+f+d+p-", -}; -int hintabsize = nelem(hintab); diff --git a/src/cmd/9c/peep.c b/src/cmd/9c/peep.c deleted file mode 100644 index 2e8e2adcc..000000000 --- a/src/cmd/9c/peep.c +++ /dev/null @@ -1,1076 +0,0 @@ -// cmd/9c/peep.c from Vita Nuova. -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "gc.h" - -/* -static Reg* -rnops(Reg *r) -{ - Prog *p; - Reg *r1; - - if(r != R) - for(;;){ - p = r->prog; - if(p->as != ANOP || p->from.type != D_NONE || p->to.type != D_NONE) - break; - r1 = uniqs(r); - if(r1 == R) - break; - r = r1; - } - return r; -} -*/ - -void -peep(void) -{ - Reg *r, *r1, *r2; - Prog *p, *p1; - int t; -/* - * complete R structure - */ - t = 0; - for(r=firstr; r!=R; r=r1) { - r1 = r->link; - if(r1 == R) - break; - p = r->prog->link; - while(p != r1->prog) - switch(p->as) { - default: - r2 = rega(); - r->link = r2; - r2->link = r1; - - r2->prog = p; - r2->p1 = r; - r->s1 = r2; - r2->s1 = r1; - r1->p1 = r2; - - r = r2; - t++; - - case ADATA: - case AGLOBL: - case ANAME: - case ASIGNAME: - p = p->link; - } - } - -loop1: - t = 0; - for(r=firstr; r!=R; r=r->link) { - p = r->prog; - if(p->as == AMOVW || p->as == AMOVD || p->as == AFMOVS || p->as == AFMOVD) - if(regtyp(&p->to)) { - if(regtyp(&p->from)) - if(p->from.type == p->to.type) { - if(copyprop(r)) { - excise(r); - t++; - } else - if(subprop(r) && copyprop(r)) { - excise(r); - t++; - } - } - if(regzer(&p->from)) - if(p->to.type == D_REG) { - p->from.type = D_REG; - p->from.reg = REGZERO; - if(copyprop(r)) { - excise(r); - t++; - } else - if(subprop(r) && copyprop(r)) { - excise(r); - t++; - } - } - } - } - if(t) - goto loop1; - /* - * look for MOVB x,R; MOVB R,R - */ - for(r=firstr; r!=R; r=r->link) { - p = r->prog; - switch(p->as) { - default: - continue; - case AMOVH: - case AMOVHZ: - case AMOVB: - case AMOVBZ: - case AMOVW: - case AMOVWZ: - if(p->to.type != D_REG) - continue; - break; - } - r1 = r->link; - if(r1 == R) - continue; - p1 = r1->prog; - if(p1->as != p->as) - continue; - if(p1->from.type != D_REG || p1->from.reg != p->to.reg) - continue; - if(p1->to.type != D_REG || p1->to.reg != p->to.reg) - continue; - excise(r1); - } - - if(debug['D'] > 1) - return; /* allow following code improvement to be suppressed */ - - /* - * look for OP x,y,R; CMP R, $0 -> OPCC x,y,R - * when OP can set condition codes correctly - */ - for(r=firstr; r!=R; r=r->link) { - p = r->prog; - switch(p->as) { - case ACMP: - case ACMPW: /* always safe? */ - if(!regzer(&p->to)) - continue; - r1 = r->s1; - if(r1 == R) - continue; - switch(r1->prog->as) { - default: - continue; - case ABCL: - case ABC: - /* the conditions can be complex and these are currently little used */ - continue; - case ABEQ: - case ABGE: - case ABGT: - case ABLE: - case ABLT: - case ABNE: - case ABVC: - case ABVS: - break; - } - r1 = r; - do - r1 = uniqp(r1); - while (r1 != R && r1->prog->as == ANOP); - if(r1 == R) - continue; - p1 = r1->prog; - if(p1->to.type != D_REG || p1->to.reg != p->from.reg) - continue; - switch(p1->as) { - case ASUB: - case AADD: - case AXOR: - case AOR: - /* irregular instructions */ - if(p1->from.type == D_CONST) - continue; - break; - } - switch(p1->as) { - default: - continue; - case AMOVW: - case AMOVD: - if(p1->from.type != D_REG) - continue; - continue; - case AANDCC: - case AANDNCC: - case AORCC: - case AORNCC: - case AXORCC: - case ASUBCC: - case ASUBECC: - case ASUBMECC: - case ASUBZECC: - case AADDCC: - case AADDCCC: - case AADDECC: - case AADDMECC: - case AADDZECC: - case ARLWMICC: - case ARLWNMCC: - t = p1->as; - break; - /* don't deal with floating point instructions for now */ -/* - case AFABS: t = AFABSCC; break; - case AFADD: t = AFADDCC; break; - case AFADDS: t = AFADDSCC; break; - case AFCTIW: t = AFCTIWCC; break; - case AFCTIWZ: t = AFCTIWZCC; break; - case AFDIV: t = AFDIVCC; break; - case AFDIVS: t = AFDIVSCC; break; - case AFMADD: t = AFMADDCC; break; - case AFMADDS: t = AFMADDSCC; break; - case AFMOVD: t = AFMOVDCC; break; - case AFMSUB: t = AFMSUBCC; break; - case AFMSUBS: t = AFMSUBSCC; break; - case AFMUL: t = AFMULCC; break; - case AFMULS: t = AFMULSCC; break; - case AFNABS: t = AFNABSCC; break; - case AFNEG: t = AFNEGCC; break; - case AFNMADD: t = AFNMADDCC; break; - case AFNMADDS: t = AFNMADDSCC; break; - case AFNMSUB: t = AFNMSUBCC; break; - case AFNMSUBS: t = AFNMSUBSCC; break; - case AFRSP: t = AFRSPCC; break; - case AFSUB: t = AFSUBCC; break; - case AFSUBS: t = AFSUBSCC; break; - case ACNTLZW: t = ACNTLZWCC; break; - case AMTFSB0: t = AMTFSB0CC; break; - case AMTFSB1: t = AMTFSB1CC; break; -*/ - case AADD: t = AADDCC; break; - case AADDV: t = AADDVCC; break; - case AADDC: t = AADDCCC; break; - case AADDCV: t = AADDCVCC; break; - case AADDME: t = AADDMECC; break; - case AADDMEV: t = AADDMEVCC; break; - case AADDE: t = AADDECC; break; - case AADDEV: t = AADDEVCC; break; - case AADDZE: t = AADDZECC; break; - case AADDZEV: t = AADDZEVCC; break; - case AAND: t = AANDCC; break; - case AANDN: t = AANDNCC; break; - case ADIVW: t = ADIVWCC; break; - case ADIVWV: t = ADIVWVCC; break; - case ADIVWU: t = ADIVWUCC; break; - case ADIVWUV: t = ADIVWUVCC; break; - case ADIVD: t = ADIVDCC; break; - case ADIVDV: t = ADIVDVCC; break; - case ADIVDU: t = ADIVDUCC; break; - case ADIVDUV: t = ADIVDUVCC; break; - case AEQV: t = AEQVCC; break; - case AEXTSB: t = AEXTSBCC; break; - case AEXTSH: t = AEXTSHCC; break; - case AEXTSW: t = AEXTSWCC; break; - case AMULHW: t = AMULHWCC; break; - case AMULHWU: t = AMULHWUCC; break; - case AMULLW: t = AMULLWCC; break; - case AMULLWV: t = AMULLWVCC; break; - case AMULHD: t = AMULHDCC; break; - case AMULHDU: t = AMULHDUCC; break; - case AMULLD: t = AMULLDCC; break; - case AMULLDV: t = AMULLDVCC; break; - case ANAND: t = ANANDCC; break; - case ANEG: t = ANEGCC; break; - case ANEGV: t = ANEGVCC; break; - case ANOR: t = ANORCC; break; - case AOR: t = AORCC; break; - case AORN: t = AORNCC; break; - case AREM: t = AREMCC; break; - case AREMV: t = AREMVCC; break; - case AREMU: t = AREMUCC; break; - case AREMUV: t = AREMUVCC; break; - case AREMD: t = AREMDCC; break; - case AREMDV: t = AREMDVCC; break; - case AREMDU: t = AREMDUCC; break; - case AREMDUV: t = AREMDUVCC; break; - case ARLWMI: t = ARLWMICC; break; - case ARLWNM: t = ARLWNMCC; break; - case ASLW: t = ASLWCC; break; - case ASRAW: t = ASRAWCC; break; - case ASRW: t = ASRWCC; break; - case ASLD: t = ASLDCC; break; - case ASRAD: t = ASRADCC; break; - case ASRD: t = ASRDCC; break; - case ASUB: t = ASUBCC; break; - case ASUBV: t = ASUBVCC; break; - case ASUBC: t = ASUBCCC; break; - case ASUBCV: t = ASUBCVCC; break; - case ASUBME: t = ASUBMECC; break; - case ASUBMEV: t = ASUBMEVCC; break; - case ASUBE: t = ASUBECC; break; - case ASUBEV: t = ASUBEVCC; break; - case ASUBZE: t = ASUBZECC; break; - case ASUBZEV: t = ASUBZEVCC; break; - case AXOR: t = AXORCC; break; - break; - } - if(debug['D']) - print("cmp %P; %P -> ", p1, p); - p1->as = t; - if(debug['D']) - print("%P\n", p1); - excise(r); - continue; - } - } -} - -void -excise(Reg *r) -{ - Prog *p; - - p = r->prog; - p->as = ANOP; - p->from = zprog.from; - p->from3 = zprog.from3; - p->to = zprog.to; - p->reg = zprog.reg; /**/ -} - -Reg* -uniqp(Reg *r) -{ - Reg *r1; - - r1 = r->p1; - if(r1 == R) { - r1 = r->p2; - if(r1 == R || r1->p2link != R) - return R; - } else - if(r->p2 != R) - return R; - return r1; -} - -Reg* -uniqs(Reg *r) -{ - Reg *r1; - - r1 = r->s1; - if(r1 == R) { - r1 = r->s2; - if(r1 == R) - return R; - } else - if(r->s2 != R) - return R; - return r1; -} - -/* - * if the system forces R0 to be zero, - * convert references to $0 to references to R0. - */ -int -regzer(Addr *a) -{ - if(R0ISZERO) { - if(a->type == D_CONST) - if(a->sym == nil) - if(a->offset == 0) - return 1; - if(a->type == D_REG) - if(a->reg == REGZERO) - return 1; - } - return 0; -} - -int -regtyp(Addr *a) -{ - - if(a->type == D_REG) { - if(!R0ISZERO || a->reg != REGZERO) - return 1; - return 0; - } - if(a->type == D_FREG) - return 1; - return 0; -} - -/* - * the idea is to substitute - * one register for another - * from one MOV to another - * MOV a, R0 - * ADD b, R0 / no use of R1 - * MOV R0, R1 - * would be converted to - * MOV a, R1 - * ADD b, R1 - * MOV R1, R0 - * hopefully, then the former or latter MOV - * will be eliminated by copy propagation. - */ -int -subprop(Reg *r0) -{ - Prog *p; - Addr *v1, *v2; - Reg *r; - int t; - - p = r0->prog; - v1 = &p->from; - if(!regtyp(v1)) - return 0; - v2 = &p->to; - if(!regtyp(v2)) - return 0; - for(r=uniqp(r0); r!=R; r=uniqp(r)) { - if(uniqs(r) == R) - break; - p = r->prog; - switch(p->as) { - case ABL: - return 0; - - case AADD: - case AADDC: - case AADDCC: - case AADDE: - case AADDECC: - case ASUB: - case ASUBCC: - case ASUBC: - case ASUBCCC: - case ASUBE: - case ASUBECC: - case ASLW: - case ASRW: - case ASRWCC: - case ASRAW: - case ASRAWCC: - case ASLD: - case ASRD: - case ASRAD: - case AOR: - case AORCC: - case AORN: - case AORNCC: - case AAND: - case AANDCC: - case AANDN: - case AANDNCC: - case ANAND: - case ANANDCC: - case ANOR: - case ANORCC: - case AXOR: - case AXORCC: - case AMULHW: - case AMULHWU: - case AMULLW: - case AMULLD: - case ADIVW: - case ADIVWU: - case ADIVD: - case ADIVDU: - case AREM: - case AREMU: - case AREMD: - case AREMDU: - case ARLWNM: - case ARLWNMCC: - - case AFADD: - case AFADDS: - case AFSUB: - case AFSUBS: - case AFMUL: - case AFMULS: - case AFDIV: - case AFDIVS: - if(p->to.type == v1->type) - if(p->to.reg == v1->reg) { - if(p->reg == NREG) - p->reg = p->to.reg; - goto gotit; - } - break; - - case AADDME: - case AADDMECC: - case AADDZE: - case AADDZECC: - case ASUBME: - case ASUBMECC: - case ASUBZE: - case ASUBZECC: - case ANEG: - case ANEGCC: - case AFNEG: - case AFNEGCC: - case AFMOVS: - case AFMOVD: - case AMOVW: - case AMOVD: - if(p->to.type == v1->type) - if(p->to.reg == v1->reg) - goto gotit; - break; - } - if(copyau(&p->from, v2) || - copyau1(p, v2) || - copyau(&p->to, v2)) - break; - if(copysub(&p->from, v1, v2, 0) || - copysub1(p, v1, v2, 0) || - copysub(&p->to, v1, v2, 0)) - break; - } - return 0; - -gotit: - copysub(&p->to, v1, v2, 1); - if(debug['P']) { - print("gotit: %D->%D\n%P", v1, v2, r->prog); - if(p->from.type == v2->type) - print(" excise"); - print("\n"); - } - for(r=uniqs(r); r!=r0; r=uniqs(r)) { - p = r->prog; - copysub(&p->from, v1, v2, 1); - copysub1(p, v1, v2, 1); - copysub(&p->to, v1, v2, 1); - if(debug['P']) - print("%P\n", r->prog); - } - t = v1->reg; - v1->reg = v2->reg; - v2->reg = t; - if(debug['P']) - print("%P last\n", r->prog); - return 1; -} - -/* - * The idea is to remove redundant copies. - * v1->v2 F=0 - * (use v2 s/v2/v1/)* - * set v1 F=1 - * use v2 return fail - * ----------------- - * v1->v2 F=0 - * (use v2 s/v2/v1/)* - * set v1 F=1 - * set v2 return success - */ -int -copyprop(Reg *r0) -{ - Prog *p; - Addr *v1, *v2; - Reg *r; - - p = r0->prog; - v1 = &p->from; - v2 = &p->to; - if(copyas(v1, v2)) - return 1; - for(r=firstr; r!=R; r=r->link) - r->active = 0; - return copy1(v1, v2, r0->s1, 0); -} - -int -copy1(Addr *v1, Addr *v2, Reg *r, int f) -{ - int t; - Prog *p; - - if(r->active) { - if(debug['P']) - print("act set; return 1\n"); - return 1; - } - r->active = 1; - if(debug['P']) - print("copy %D->%D f=%d\n", v1, v2, f); - for(; r != R; r = r->s1) { - p = r->prog; - if(debug['P']) - print("%P", p); - if(!f && uniqp(r) == R) { - f = 1; - if(debug['P']) - print("; merge; f=%d", f); - } - t = copyu(p, v2, nil); - switch(t) { - case 2: /* rar, cant split */ - if(debug['P']) - print("; %Drar; return 0\n", v2); - return 0; - - case 3: /* set */ - if(debug['P']) - print("; %Dset; return 1\n", v2); - return 1; - - case 1: /* used, substitute */ - case 4: /* use and set */ - if(f) { - if(!debug['P']) - return 0; - if(t == 4) - print("; %Dused+set and f=%d; return 0\n", v2, f); - else - print("; %Dused and f=%d; return 0\n", v2, f); - return 0; - } - if(copyu(p, v2, v1)) { - if(debug['P']) - print("; sub fail; return 0\n"); - return 0; - } - if(debug['P']) - print("; sub%D/%D", v2, v1); - if(t == 4) { - if(debug['P']) - print("; %Dused+set; return 1\n", v2); - return 1; - } - break; - } - if(!f) { - t = copyu(p, v1, nil); - if(!f && (t == 2 || t == 3 || t == 4)) { - f = 1; - if(debug['P']) - print("; %Dset and !f; f=%d", v1, f); - } - } - if(debug['P']) - print("\n"); - if(r->s2) - if(!copy1(v1, v2, r->s2, f)) - return 0; - } - return 1; -} - -/* - * return - * 1 if v only used (and substitute), - * 2 if read-alter-rewrite - * 3 if set - * 4 if set and used - * 0 otherwise (not touched) - */ -int -copyu(Prog *p, Addr *v, Addr *s) -{ - - switch(p->as) { - - default: - if(debug['P']) - print(" (\?\?\?)"); - return 2; - - - case ANOP: /* read, write */ - case AMOVH: - case AMOVHZ: - case AMOVB: - case AMOVBZ: - case AMOVW: - case AMOVWZ: - case AMOVD: - - case ANEG: - case ANEGCC: - case AADDME: - case AADDMECC: - case AADDZE: - case AADDZECC: - case ASUBME: - case ASUBMECC: - case ASUBZE: - case ASUBZECC: - - case AFCTIW: - case AFCTIWZ: - case AFMOVS: - case AFMOVD: - case AFRSP: - case AFNEG: - case AFNEGCC: - if(s != nil) { - if(copysub(&p->from, v, s, 1)) - return 1; - if(!copyas(&p->to, v)) - if(copysub(&p->to, v, s, 1)) - return 1; - return 0; - } - if(copyas(&p->to, v)) { - if(copyau(&p->from, v)) - return 4; - return 3; - } - if(copyau(&p->from, v)) - return 1; - if(copyau(&p->to, v)) - return 1; - return 0; - - case ARLWMI: /* read read rar */ - case ARLWMICC: - if(copyas(&p->to, v)) - return 2; - /* fall through */ - - case AADD: /* read read write */ - case AADDC: - case AADDE: - case ASUB: - case ASLW: - case ASRW: - case ASRAW: - case ASLD: - case ASRD: - case ASRAD: - case AOR: - case AORCC: - case AORN: - case AORNCC: - case AAND: - case AANDCC: - case AANDN: - case AANDNCC: - case ANAND: - case ANANDCC: - case ANOR: - case ANORCC: - case AXOR: - case AMULHW: - case AMULHWU: - case AMULLW: - case AMULLD: - case ADIVW: - case ADIVD: - case ADIVWU: - case ADIVDU: - case AREM: - case AREMU: - case AREMD: - case AREMDU: - case ARLWNM: - case ARLWNMCC: - - case AFADDS: - case AFADD: - case AFSUBS: - case AFSUB: - case AFMULS: - case AFMUL: - case AFDIVS: - case AFDIV: - if(s != nil) { - if(copysub(&p->from, v, s, 1)) - return 1; - if(copysub1(p, v, s, 1)) - return 1; - if(!copyas(&p->to, v)) - if(copysub(&p->to, v, s, 1)) - return 1; - return 0; - } - if(copyas(&p->to, v)) { - if(p->reg == NREG) - p->reg = p->to.reg; - if(copyau(&p->from, v)) - return 4; - if(copyau1(p, v)) - return 4; - return 3; - } - if(copyau(&p->from, v)) - return 1; - if(copyau1(p, v)) - return 1; - if(copyau(&p->to, v)) - return 1; - return 0; - - case ABEQ: - case ABGT: - case ABGE: - case ABLT: - case ABLE: - case ABNE: - case ABVC: - case ABVS: - break; - - case ACMP: /* read read */ - case ACMPU: - case ACMPW: - case ACMPWU: - case AFCMPO: - case AFCMPU: - if(s != nil) { - if(copysub(&p->from, v, s, 1)) - return 1; - return copysub(&p->to, v, s, 1); - } - if(copyau(&p->from, v)) - return 1; - if(copyau(&p->to, v)) - return 1; - break; - - case ABR: /* funny */ - if(s != nil) { - if(copysub(&p->to, v, s, 1)) - return 1; - return 0; - } - if(copyau(&p->to, v)) - return 1; - return 0; - - case ARETURN: /* funny */ - if(v->type == D_REG) - if(v->reg == REGRET) - return 2; - if(v->type == D_FREG) - if(v->reg == FREGRET) - return 2; - - case ABL: /* funny */ - if(v->type == D_REG) { - if(v->reg <= REGEXT && v->reg > exregoffset) - return 2; - if(v->reg == REGARG) - return 2; - } - if(v->type == D_FREG) { - if(v->reg <= FREGEXT && v->reg > exfregoffset) - return 2; - } - - if(s != nil) { - if(copysub(&p->to, v, s, 1)) - return 1; - return 0; - } - if(copyau(&p->to, v)) - return 4; - return 3; - - case ATEXT: /* funny */ - if(v->type == D_REG) - if(v->reg == REGARG) - return 3; - return 0; - } - return 0; -} - -int -a2type(Prog *p) -{ - - switch(p->as) { - case AADD: - case AADDC: - case AADDCC: - case AADDCCC: - case AADDE: - case AADDECC: - case AADDME: - case AADDMECC: - case AADDZE: - case AADDZECC: - case ASUB: - case ASUBC: - case ASUBCC: - case ASUBCCC: - case ASUBE: - case ASUBECC: - case ASUBME: - case ASUBMECC: - case ASUBZE: - case ASUBZECC: - case ASLW: - case ASLWCC: - case ASRW: - case ASRWCC: - case ASRAW: - case ASRAWCC: - case ASLD: - case ASLDCC: - case ASRD: - case ASRDCC: - case ASRAD: - case ASRADCC: - case AOR: - case AORCC: - case AORN: - case AORNCC: - case AAND: - case AANDCC: - case AANDN: - case AANDNCC: - case AXOR: - case AXORCC: - case ANEG: - case ANEGCC: - case AMULHW: - case AMULHWU: - case AMULLW: - case AMULLWCC: - case ADIVW: - case ADIVWCC: - case ADIVWU: - case ADIVWUCC: - case AREM: - case AREMCC: - case AREMU: - case AREMUCC: - case AMULLD: - case AMULLDCC: - case ADIVD: - case ADIVDCC: - case ADIVDU: - case ADIVDUCC: - case AREMD: - case AREMDCC: - case AREMDU: - case AREMDUCC: - case ANAND: - case ANANDCC: - case ANOR: - case ANORCC: - case ARLWMI: - case ARLWMICC: - case ARLWNM: - case ARLWNMCC: - return D_REG; - - case AFADDS: - case AFADDSCC: - case AFADD: - case AFADDCC: - case AFSUBS: - case AFSUBSCC: - case AFSUB: - case AFSUBCC: - case AFMULS: - case AFMULSCC: - case AFMUL: - case AFMULCC: - case AFDIVS: - case AFDIVSCC: - case AFDIV: - case AFDIVCC: - case AFNEG: - case AFNEGCC: - return D_FREG; - } - return D_NONE; -} - -/* - * direct reference, - * could be set/use depending on - * semantics - */ -int -copyas(Addr *a, Addr *v) -{ - - if(regtyp(v)) - if(a->type == v->type) - if(a->reg == v->reg) - return 1; - return 0; -} - -/* - * either direct or indirect - */ -int -copyau(Addr *a, Addr *v) -{ - - if(copyas(a, v)) - return 1; - if(v->type == D_REG) - if(a->type == D_OREG) - if(v->reg == a->reg) - return 1; - return 0; -} - -int -copyau1(Prog *p, Addr *v) -{ - - if(regtyp(v)) - if(p->from.type == v->type || p->to.type == v->type) - if(p->reg == v->reg) { - if(a2type(p) != v->type) - print("botch a2type %P\n", p); - return 1; - } - return 0; -} - -/* - * substitute s for v in a - * return failure to substitute - */ -int -copysub(Addr *a, Addr *v, Addr *s, int f) -{ - - if(f) - if(copyau(a, v)) - a->reg = s->reg; - return 0; -} - -int -copysub1(Prog *p1, Addr *v, Addr *s, int f) -{ - - if(f) - if(copyau1(p1, v)) - p1->reg = s->reg; - return 0; -} diff --git a/src/cmd/9c/reg.c b/src/cmd/9c/reg.c deleted file mode 100644 index 81a7c7fe4..000000000 --- a/src/cmd/9c/reg.c +++ /dev/null @@ -1,1163 +0,0 @@ -// cmd/9c/reg.c from Vita Nuova. -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "gc.h" - -Reg* -rega(void) -{ - Reg *r; - - r = freer; - if(r == R) { - r = alloc(sizeof(*r)); - } else - freer = r->link; - - *r = zreg; - return r; -} - -int -rcmp(const void *a1, const void *a2) -{ - const Rgn *p1, *p2; - int c1, c2; - - p1 = a1; - p2 = a2; - c1 = p2->cost; - c2 = p1->cost; - if(c1 -= c2) - return c1; - return p2->varno - p1->varno; -} - -void -regopt(Prog *p) -{ - Reg *r, *r1, *r2; - Prog *p1; - int i, z; - int32 initpc, val, npc; - uint32 vreg; - Bits bit; - struct - { - int32 m; - int32 c; - Reg* p; - } log5[6], *lp; - - firstr = R; - lastr = R; - nvar = 0; - regbits = 0; - for(z=0; z<BITS; z++) { - externs.b[z] = 0; - params.b[z] = 0; - consts.b[z] = 0; - addrs.b[z] = 0; - } - - /* - * pass 1 - * build aux data structure - * allocate pcs - * find use and set of variables - */ - val = 5L * 5L * 5L * 5L * 5L; - lp = log5; - for(i=0; i<5; i++) { - lp->m = val; - lp->c = 0; - lp->p = R; - val /= 5L; - lp++; - } - val = 0; - for(; p != P; p = p->link) { - switch(p->as) { - case ADATA: - case AGLOBL: - case ANAME: - case ASIGNAME: - case AFUNCDATA: - continue; - } - r = rega(); - if(firstr == R) { - firstr = r; - lastr = r; - } else { - lastr->link = r; - r->p1 = lastr; - lastr->s1 = r; - lastr = r; - } - r->prog = p; - r->pc = val; - val++; - - lp = log5; - for(i=0; i<5; i++) { - lp->c--; - if(lp->c <= 0) { - lp->c = lp->m; - if(lp->p != R) - lp->p->log5 = r; - lp->p = r; - (lp+1)->c = 0; - break; - } - lp++; - } - - r1 = r->p1; - if(r1 != R) - switch(r1->prog->as) { - case ARETURN: - case ABR: - case ARFI: - case ARFCI: - case ARFID: - r->p1 = R; - r1->s1 = R; - } - - /* - * left side always read - */ - bit = mkvar(&p->from, p->as==AMOVW || p->as == AMOVWZ || p->as == AMOVD); - for(z=0; z<BITS; z++) - r->use1.b[z] |= bit.b[z]; - - /* - * right side depends on opcode - */ - bit = mkvar(&p->to, 0); - if(bany(&bit)) - switch(p->as) { - default: - diag(Z, "reg: unknown asop: %A", p->as); - break; - - /* - * right side write - */ - case ANOP: - case AMOVB: - case AMOVBU: - case AMOVBZ: - case AMOVBZU: - case AMOVH: - case AMOVHBR: - case AMOVWBR: - case AMOVHU: - case AMOVHZ: - case AMOVHZU: - case AMOVW: - case AMOVWU: - case AMOVWZ: - case AMOVWZU: - case AMOVD: - case AMOVDU: - case AFMOVD: - case AFMOVDCC: - case AFMOVDU: - case AFMOVS: - case AFMOVSU: - case AFRSP: - for(z=0; z<BITS; z++) - r->set.b[z] |= bit.b[z]; - break; - - /* - * funny - */ - case ABL: - for(z=0; z<BITS; z++) - addrs.b[z] |= bit.b[z]; - break; - } - } - if(firstr == R) - return; - initpc = pc - val; - npc = val; - - /* - * pass 2 - * turn branch references to pointers - * build back pointers - */ - for(r = firstr; r != R; r = r->link) { - p = r->prog; - if(p->to.type == D_BRANCH) { - val = p->to.offset - initpc; - r1 = firstr; - while(r1 != R) { - r2 = r1->log5; - if(r2 != R && val >= r2->pc) { - r1 = r2; - continue; - } - if(r1->pc == val) - break; - r1 = r1->link; - } - if(r1 == R) { - nearln = p->lineno; - diag(Z, "ref not found\n%P", p); - continue; - } - if(r1 == r) { - nearln = p->lineno; - diag(Z, "ref to self\n%P", p); - continue; - } - r->s2 = r1; - r->p2link = r1->p2; - r1->p2 = r; - } - } - if(debug['R']) { - p = firstr->prog; - print("\n%L %D\n", p->lineno, &p->from); - } - - /* - * pass 2.5 - * find looping structure - */ - for(r = firstr; r != R; r = r->link) - r->active = 0; - change = 0; - loopit(firstr, npc); - if(debug['R'] && debug['v']) { - print("\nlooping structure:\n"); - for(r = firstr; r != R; r = r->link) { - print("%ld:%P", r->loop, r->prog); - for(z=0; z<BITS; z++) - bit.b[z] = r->use1.b[z] | - r->use2.b[z] | r->set.b[z]; - if(bany(&bit)) { - print("\t"); - if(bany(&r->use1)) - print(" u1=%B", r->use1); - if(bany(&r->use2)) - print(" u2=%B", r->use2); - if(bany(&r->set)) - print(" st=%B", r->set); - } - print("\n"); - } - } - - /* - * pass 3 - * iterate propagating usage - * back until flow graph is complete - */ -loop1: - change = 0; - for(r = firstr; r != R; r = r->link) - r->active = 0; - for(r = firstr; r != R; r = r->link) - if(r->prog->as == ARETURN) - prop(r, zbits, zbits); -loop11: - /* pick up unreachable code */ - i = 0; - for(r = firstr; r != R; r = r1) { - r1 = r->link; - if(r1 && r1->active && !r->active) { - prop(r, zbits, zbits); - i = 1; - } - } - if(i) - goto loop11; - if(change) - goto loop1; - - - /* - * pass 4 - * iterate propagating register/variable synchrony - * forward until graph is complete - */ -loop2: - change = 0; - for(r = firstr; r != R; r = r->link) - r->active = 0; - synch(firstr, zbits); - if(change) - goto loop2; - - - /* - * pass 5 - * isolate regions - * calculate costs (paint1) - */ - r = firstr; - if(r) { - for(z=0; z<BITS; z++) - bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) & - ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]); - if(bany(&bit)) { - nearln = r->prog->lineno; - warn(Z, "used and not set: %B", bit); - if(debug['R'] && !debug['w']) - print("used and not set: %B\n", bit); - } - } - if(debug['R'] && debug['v']) - print("\nprop structure:\n"); - for(r = firstr; r != R; r = r->link) - r->act = zbits; - rgp = region; - nregion = 0; - for(r = firstr; r != R; r = r->link) { - if(debug['R'] && debug['v']) - print("%P\n set = %B; rah = %B; cal = %B\n", - r->prog, r->set, r->refahead, r->calahead); - for(z=0; z<BITS; z++) - bit.b[z] = r->set.b[z] & - ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]); - if(bany(&bit)) { - nearln = r->prog->lineno; - warn(Z, "set and not used: %B", bit); - if(debug['R']) - print("set an not used: %B\n", bit); - excise(r); - } - for(z=0; z<BITS; z++) - bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]); - while(bany(&bit)) { - i = bnum(bit); - rgp->enter = r; - rgp->varno = i; - change = 0; - if(debug['R'] && debug['v']) - print("\n"); - paint1(r, i); - bit.b[i/32] &= ~(1L<<(i%32)); - if(change <= 0) { - if(debug['R']) - print("%L$%d: %B\n", - r->prog->lineno, change, blsh(i)); - continue; - } - rgp->cost = change; - nregion++; - if(nregion >= NRGN) - fatal(Z, "too many regions"); - rgp++; - } - } - qsort(region, nregion, sizeof(region[0]), rcmp); - - /* - * pass 6 - * determine used registers (paint2) - * replace code (paint3) - */ - rgp = region; - for(i=0; i<nregion; i++) { - bit = blsh(rgp->varno); - vreg = paint2(rgp->enter, rgp->varno); - vreg = allreg(vreg, rgp); - if(debug['R']) { - if(rgp->regno >= NREG) - print("%L$%d F%d: %B\n", - rgp->enter->prog->lineno, - rgp->cost, - rgp->regno-NREG, - bit); - else - print("%L$%d R%d: %B\n", - rgp->enter->prog->lineno, - rgp->cost, - rgp->regno, - bit); - } - if(rgp->regno != 0) - paint3(rgp->enter, rgp->varno, vreg, rgp->regno); - rgp++; - } - /* - * pass 7 - * peep-hole on basic block - */ - if(!debug['R'] || debug['P']) - peep(); - - /* - * pass 8 - * recalculate pc - */ - val = initpc; - for(r = firstr; r != R; r = r1) { - r->pc = val; - p = r->prog; - p1 = P; - r1 = r->link; - if(r1 != R) - p1 = r1->prog; - for(; p != p1; p = p->link) { - switch(p->as) { - default: - val++; - break; - - case ANOP: - case ADATA: - case AGLOBL: - case ANAME: - case ASIGNAME: - case AFUNCDATA: - break; - } - } - } - pc = val; - - /* - * fix up branches - */ - if(debug['R']) - if(bany(&addrs)) - print("addrs: %B\n", addrs); - - r1 = 0; /* set */ - for(r = firstr; r != R; r = r->link) { - p = r->prog; - if(p->to.type == D_BRANCH) { - p->to.offset = r->s2->pc; - p->to.u.branch = r->s2->prog; - } - r1 = r; - } - - /* - * last pass - * eliminate nops - * free aux structures - */ - for(p = firstr->prog; p != P; p = p->link){ - while(p->link && p->link->as == ANOP) - p->link = p->link->link; - } - if(r1 != R) { - r1->link = freer; - freer = firstr; - } -} - -/* - * add mov b,rn - * just after r - */ -void -addmove(Reg *r, int bn, int rn, int f) -{ - Prog *p, *p1; - Addr *a; - Var *v; - - p1 = alloc(sizeof(*p1)); - *p1 = zprog; - p = r->prog; - - p1->link = p->link; - p->link = p1; - p1->lineno = p->lineno; - - v = var + bn; - - a = &p1->to; - a->sym = v->sym; - a->name = v->name; - a->offset = v->offset; - a->etype = v->etype; - a->type = D_OREG; - if(a->etype == TARRAY || a->sym == nil) - a->type = D_CONST; - - p1->as = AMOVW; - if(v->etype == TCHAR || v->etype == TUCHAR) - p1->as = AMOVB; - if(v->etype == TSHORT || v->etype == TUSHORT) - p1->as = AMOVH; - if(v->etype == TVLONG || v->etype == TUVLONG || v->etype == TIND) - p1->as = AMOVD; - if(v->etype == TFLOAT) - p1->as = AFMOVS; - if(v->etype == TDOUBLE) - p1->as = AFMOVD; - - p1->from.type = D_REG; - p1->from.reg = rn; - if(rn >= NREG) { - p1->from.type = D_FREG; - p1->from.reg = rn-NREG; - } - if(!f) { - p1->from = *a; - *a = zprog.from; - a->type = D_REG; - a->reg = rn; - if(rn >= NREG) { - a->type = D_FREG; - a->reg = rn-NREG; - } - if(v->etype == TUCHAR) - p1->as = AMOVBZ; - if(v->etype == TUSHORT) - p1->as = AMOVHZ; - if(v->etype == TUINT || v->etype == TULONG) - p1->as = AMOVWZ; - } - if(debug['R']) - print("%P\t.a%P\n", p, p1); -} - -Bits -mkvar(Addr *a, int docon) -{ - Var *v; - int i, t, n, et, z; - int64 o; - Bits bit; - LSym *s; - - t = a->type; - if(t == D_REG && a->reg != NREG) - regbits |= RtoB(a->reg); - if(t == D_FREG && a->reg != NREG) - regbits |= FtoB(a->reg); - s = a->sym; - o = a->offset; - et = a->etype; - if(s == nil) { - if(t != D_CONST || !docon || a->reg != NREG) - goto none; - et = TLONG; - } - if(t == D_CONST) { - if(s == nil && sval(o)) - goto none; - } - n = a->name; - v = var; - for(i=0; i<nvar; i++) { - if(s == v->sym) - if(n == v->name) - if(o == v->offset) - goto out; - v++; - } - if(s) - if(s->name[0] == '.') - goto none; - if(nvar >= NVAR) - fatal(Z, "variable not optimized: %s", s->name); - i = nvar; - nvar++; - v = &var[i]; - v->sym = s; - v->offset = o; - v->etype = et; - v->name = n; - if(debug['R']) - print("bit=%2d et=%2d %D\n", i, et, a); -out: - bit = blsh(i); - if(n == D_EXTERN || n == D_STATIC) - for(z=0; z<BITS; z++) - externs.b[z] |= bit.b[z]; - if(n == D_PARAM) - for(z=0; z<BITS; z++) - params.b[z] |= bit.b[z]; - if(v->etype != et || !(typechlpfd[et] || typev[et])) /* funny punning */ - for(z=0; z<BITS; z++) - addrs.b[z] |= bit.b[z]; - if(t == D_CONST) { - if((int32)o != o) - v->etype = TVLONG; - if(s == nil) { - for(z=0; z<BITS; z++) - consts.b[z] |= bit.b[z]; - return bit; - } - if(et != TARRAY) - for(z=0; z<BITS; z++) - addrs.b[z] |= bit.b[z]; - for(z=0; z<BITS; z++) - params.b[z] |= bit.b[z]; - return bit; - } - if(t == D_OREG) - return bit; - -none: - return zbits; -} - -void -prop(Reg *r, Bits ref, Bits cal) -{ - Reg *r1, *r2; - int z; - - for(r1 = r; r1 != R; r1 = r1->p1) { - for(z=0; z<BITS; z++) { - ref.b[z] |= r1->refahead.b[z]; - if(ref.b[z] != r1->refahead.b[z]) { - r1->refahead.b[z] = ref.b[z]; - change++; - } - cal.b[z] |= r1->calahead.b[z]; - if(cal.b[z] != r1->calahead.b[z]) { - r1->calahead.b[z] = cal.b[z]; - change++; - } - } - switch(r1->prog->as) { - case ABL: - for(z=0; z<BITS; z++) { - cal.b[z] |= ref.b[z] | externs.b[z]; - ref.b[z] = 0; - } - break; - - case ATEXT: - for(z=0; z<BITS; z++) { - cal.b[z] = 0; - ref.b[z] = 0; - } - break; - - case ARETURN: - for(z=0; z<BITS; z++) { - cal.b[z] = externs.b[z]; - ref.b[z] = 0; - } - } - for(z=0; z<BITS; z++) { - ref.b[z] = (ref.b[z] & ~r1->set.b[z]) | - r1->use1.b[z] | r1->use2.b[z]; - cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]); - r1->refbehind.b[z] = ref.b[z]; - r1->calbehind.b[z] = cal.b[z]; - } - if(r1->active) - break; - r1->active = 1; - } - for(; r != r1; r = r->p1) - for(r2 = r->p2; r2 != R; r2 = r2->p2link) - prop(r2, r->refbehind, r->calbehind); -} - -/* - * find looping structure - * - * 1) find reverse postordering - * 2) find approximate dominators, - * the actual dominators if the flow graph is reducible - * otherwise, dominators plus some other non-dominators. - * See Matthew S. Hecht and Jeffrey D. Ullman, - * "Analysis of a Simple Algorithm for Global Data Flow Problems", - * Conf. Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts, - * Oct. 1-3, 1973, pp. 207-217. - * 3) find all nodes with a predecessor dominated by the current node. - * such a node is a loop head. - * recursively, all preds with a greater rpo number are in the loop - */ -int32 -postorder(Reg *r, Reg **rpo2r, int32 n) -{ - Reg *r1; - - r->rpo = 1; - r1 = r->s1; - if(r1 && !r1->rpo) - n = postorder(r1, rpo2r, n); - r1 = r->s2; - if(r1 && !r1->rpo) - n = postorder(r1, rpo2r, n); - rpo2r[n] = r; - n++; - return n; -} - -int32 -rpolca(int32 *idom, int32 rpo1, int32 rpo2) -{ - int32 t; - - if(rpo1 == -1) - return rpo2; - while(rpo1 != rpo2){ - if(rpo1 > rpo2){ - t = rpo2; - rpo2 = rpo1; - rpo1 = t; - } - while(rpo1 < rpo2){ - t = idom[rpo2]; - if(t >= rpo2) - fatal(Z, "bad idom"); - rpo2 = t; - } - } - return rpo1; -} - -int -doms(int32 *idom, int32 r, int32 s) -{ - while(s > r) - s = idom[s]; - return s == r; -} - -int -loophead(int32 *idom, Reg *r) -{ - int32 src; - - src = r->rpo; - if(r->p1 != R && doms(idom, src, r->p1->rpo)) - return 1; - for(r = r->p2; r != R; r = r->p2link) - if(doms(idom, src, r->rpo)) - return 1; - return 0; -} - -void -loopmark(Reg **rpo2r, int32 head, Reg *r) -{ - if(r->rpo < head || r->active == head) - return; - r->active = head; - r->loop += LOOP; - if(r->p1 != R) - loopmark(rpo2r, head, r->p1); - for(r = r->p2; r != R; r = r->p2link) - loopmark(rpo2r, head, r); -} - -void -loopit(Reg *r, int32 nr) -{ - Reg *r1; - int32 i, d, me; - - if(nr > maxnr) { - rpo2r = alloc(nr * sizeof(Reg*)); - idom = alloc(nr * sizeof(int32)); - maxnr = nr; - } - - d = postorder(r, rpo2r, 0); - if(d > nr) - fatal(Z, "too many reg nodes"); - nr = d; - for(i = 0; i < nr / 2; i++){ - r1 = rpo2r[i]; - rpo2r[i] = rpo2r[nr - 1 - i]; - rpo2r[nr - 1 - i] = r1; - } - for(i = 0; i < nr; i++) - rpo2r[i]->rpo = i; - - idom[0] = 0; - for(i = 0; i < nr; i++){ - r1 = rpo2r[i]; - me = r1->rpo; - d = -1; - if(r1->p1 != R && r1->p1->rpo < me) - d = r1->p1->rpo; - for(r1 = r1->p2; r1 != nil; r1 = r1->p2link) - if(r1->rpo < me) - d = rpolca(idom, d, r1->rpo); - idom[i] = d; - } - - for(i = 0; i < nr; i++){ - r1 = rpo2r[i]; - r1->loop++; - if(r1->p2 != R && loophead(idom, r1)) - loopmark(rpo2r, i, r1); - } -} - -void -synch(Reg *r, Bits dif) -{ - Reg *r1; - int z; - - for(r1 = r; r1 != R; r1 = r1->s1) { - for(z=0; z<BITS; z++) { - dif.b[z] = (dif.b[z] & - ~(~r1->refbehind.b[z] & r1->refahead.b[z])) | - r1->set.b[z] | r1->regdiff.b[z]; - if(dif.b[z] != r1->regdiff.b[z]) { - r1->regdiff.b[z] = dif.b[z]; - change++; - } - } - if(r1->active) - break; - r1->active = 1; - for(z=0; z<BITS; z++) - dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]); - if(r1->s2 != R) - synch(r1->s2, dif); - } -} - -uint32 -allreg(uint32 b, Rgn *r) -{ - Var *v; - int i; - - v = var + r->varno; - r->regno = 0; - switch(v->etype) { - - default: - diag(Z, "unknown etype %d/%d", bitno(b), v->etype); - break; - - case TCHAR: - case TUCHAR: - case TSHORT: - case TUSHORT: - case TINT: - case TUINT: - case TLONG: - case TULONG: - case TIND: - case TVLONG: - case TUVLONG: - case TARRAY: - i = BtoR(~b); - if(i && r->cost > 0) { - r->regno = i; - return RtoB(i); - } - break; - - case TDOUBLE: - case TFLOAT: - i = BtoF(~b); - if(i && r->cost > 0) { - r->regno = i+NREG; - return FtoB(i); - } - break; - } - return 0; -} - -void -paint1(Reg *r, int bn) -{ - Reg *r1; - Prog *p; - int z; - uint32 bb; - - z = bn/32; - bb = 1L<<(bn%32); - if(r->act.b[z] & bb) - return; - for(;;) { - if(!(r->refbehind.b[z] & bb)) - break; - r1 = r->p1; - if(r1 == R) - break; - if(!(r1->refahead.b[z] & bb)) - break; - if(r1->act.b[z] & bb) - break; - r = r1; - } - - if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) { - change -= CLOAD * r->loop; - if(debug['R'] && debug['v']) - print("%ld%P\tld %B $%d\n", r->loop, - r->prog, blsh(bn), change); - } - for(;;) { - r->act.b[z] |= bb; - p = r->prog; - - if(r->use1.b[z] & bb) { - change += CREF * r->loop; - if(p->to.type == D_FREG && (p->as == AMOVW || p->as == AMOVD)) - change = -CINF; /* cant go Rreg to Freg */ - if(debug['R'] && debug['v']) - print("%ld%P\tu1 %B $%d\n", r->loop, - p, blsh(bn), change); - } - - if((r->use2.b[z]|r->set.b[z]) & bb) { - change += CREF * r->loop; - if(p->from.type == D_FREG && (p->as == AMOVW || p->as == AMOVD)) - change = -CINF; /* cant go Rreg to Freg */ - if(debug['R'] && debug['v']) - print("%ld%P\tu2 %B $%d\n", r->loop, - p, blsh(bn), change); - } - - if(STORE(r) & r->regdiff.b[z] & bb) { - change -= CLOAD * r->loop; - if(debug['R'] && debug['v']) - print("%ld%P\tst %B $%d\n", r->loop, - p, blsh(bn), change); - } - - if(r->refbehind.b[z] & bb) - for(r1 = r->p2; r1 != R; r1 = r1->p2link) - if(r1->refahead.b[z] & bb) - paint1(r1, bn); - - if(!(r->refahead.b[z] & bb)) - break; - r1 = r->s2; - if(r1 != R) - if(r1->refbehind.b[z] & bb) - paint1(r1, bn); - r = r->s1; - if(r == R) - break; - if(r->act.b[z] & bb) - break; - if(!(r->refbehind.b[z] & bb)) - break; - } -} - -uint32 -paint2(Reg *r, int bn) -{ - Reg *r1; - int z; - uint32 bb, vreg; - - z = bn/32; - bb = 1L << (bn%32); - vreg = regbits; - if(!(r->act.b[z] & bb)) - return vreg; - for(;;) { - if(!(r->refbehind.b[z] & bb)) - break; - r1 = r->p1; - if(r1 == R) - break; - if(!(r1->refahead.b[z] & bb)) - break; - if(!(r1->act.b[z] & bb)) - break; - r = r1; - } - for(;;) { - r->act.b[z] &= ~bb; - - vreg |= r->regu; - - if(r->refbehind.b[z] & bb) - for(r1 = r->p2; r1 != R; r1 = r1->p2link) - if(r1->refahead.b[z] & bb) - vreg |= paint2(r1, bn); - - if(!(r->refahead.b[z] & bb)) - break; - r1 = r->s2; - if(r1 != R) - if(r1->refbehind.b[z] & bb) - vreg |= paint2(r1, bn); - r = r->s1; - if(r == R) - break; - if(!(r->act.b[z] & bb)) - break; - if(!(r->refbehind.b[z] & bb)) - break; - } - return vreg; -} - -void -paint3(Reg *r, int bn, int32 rb, int rn) -{ - Reg *r1; - Prog *p; - int z; - uint32 bb; - - z = bn/32; - bb = 1L << (bn%32); - if(r->act.b[z] & bb) - return; - for(;;) { - if(!(r->refbehind.b[z] & bb)) - break; - r1 = r->p1; - if(r1 == R) - break; - if(!(r1->refahead.b[z] & bb)) - break; - if(r1->act.b[z] & bb) - break; - r = r1; - } - - if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb) - addmove(r, bn, rn, 0); - for(;;) { - r->act.b[z] |= bb; - p = r->prog; - - if(r->use1.b[z] & bb) { - if(debug['R']) - print("%P", p); - addreg(&p->from, rn); - if(debug['R']) - print("\t.c%P\n", p); - } - if((r->use2.b[z]|r->set.b[z]) & bb) { - if(debug['R']) - print("%P", p); - addreg(&p->to, rn); - if(debug['R']) - print("\t.c%P\n", p); - } - - if(STORE(r) & r->regdiff.b[z] & bb) - addmove(r, bn, rn, 1); - r->regu |= rb; - - if(r->refbehind.b[z] & bb) - for(r1 = r->p2; r1 != R; r1 = r1->p2link) - if(r1->refahead.b[z] & bb) - paint3(r1, bn, rb, rn); - - if(!(r->refahead.b[z] & bb)) - break; - r1 = r->s2; - if(r1 != R) - if(r1->refbehind.b[z] & bb) - paint3(r1, bn, rb, rn); - r = r->s1; - if(r == R) - break; - if(r->act.b[z] & bb) - break; - if(!(r->refbehind.b[z] & bb)) - break; - } -} - -void -addreg(Addr *a, int rn) -{ - - a->sym = 0; - a->name = D_NONE; - a->type = D_REG; - a->reg = rn; - if(rn >= NREG) { - a->type = D_FREG; - a->reg = rn-NREG; - } -} - -/* - * track register variables including external registers: - * bit reg - * 0 R7 - * 1 R8 - * ... ... - * 21 R28 - */ -int32 -RtoB(int r) -{ - - if(r >= REGMIN && r <= REGMAX) - return 1L << (r-REGMIN); - return 0; -} - -int -BtoR(int32 b) -{ - b &= 0x001fffffL; - if(b == 0) - return 0; - return bitno(b) + REGMIN; -} - -/* - * bit reg - * 22 F17 - * 23 F18 - * ... ... - * 31 F26 - */ -int32 -FtoB(int f) -{ - if(f < FREGMIN || f > FREGEXT) - return 0; - return 1L << (f - FREGMIN + 22); -} - -int -BtoF(int32 b) -{ - - b &= 0xffc00000L; - if(b == 0) - return 0; - return bitno(b) - 22 + FREGMIN; -} diff --git a/src/cmd/9c/sgen.c b/src/cmd/9c/sgen.c deleted file mode 100644 index b03c17267..000000000 --- a/src/cmd/9c/sgen.c +++ /dev/null @@ -1,291 +0,0 @@ -// cmd/9c/sgen.c from Vita Nuova. -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "gc.h" - -Prog* -gtext(Sym *s, int32 stkoff) -{ - vlong v; - - v = ((uvlong)argsize(1) << 32) | (stkoff & 0xffffffff); - if((textflag & NOSPLIT) && stkoff >= 128) - yyerror("stack frame too large for NOSPLIT function"); - - gpseudo(ATEXT, s, nodgconst(v, types[TVLONG])); - return p; -} - - -void -noretval(int n) -{ - - if(n & 1) { - gins(ANOP, Z, Z); - p->to.type = D_REG; - p->to.reg = REGRET; - } - if(n & 2) { - gins(ANOP, Z, Z); - p->to.type = D_FREG; - p->to.reg = FREGRET; - } -} - -/* - * calculate addressability as follows - * CONST ==> 20 $value - * NAME ==> 10 name - * REGISTER ==> 11 register - * INDREG ==> 12 *[(reg)+offset] - * &10 ==> 2 $name - * ADD(2, 20) ==> 2 $name+offset - * ADD(3, 20) ==> 3 $(reg)+offset - * &12 ==> 3 $(reg)+offset - * *11 ==> 11 ?? - * *2 ==> 10 name - * *3 ==> 12 *(reg)+offset - * calculate complexity (number of registers) - */ -void -xcom(Node *n) -{ - Node *l, *r; - int v; - - if(n == Z) - return; - l = n->left; - r = n->right; - n->addable = 0; - n->complex = 0; - switch(n->op) { - case OCONST: - n->addable = 20; - return; - - case OREGISTER: - n->addable = 11; - return; - - case OINDREG: - n->addable = 12; - return; - - case ONAME: - n->addable = 10; - return; - - case OADDR: - xcom(l); - if(l->addable == 10) - n->addable = 2; - if(l->addable == 12) - n->addable = 3; - break; - - case OIND: - xcom(l); - if(l->addable == 11) - n->addable = 12; - if(l->addable == 3) - n->addable = 12; - if(l->addable == 2) - n->addable = 10; - break; - - case OADD: - xcom(l); - xcom(r); - if(l->addable == 20) { - if(r->addable == 2) - n->addable = 2; - if(r->addable == 3) - n->addable = 3; - } - if(r->addable == 20) { - if(l->addable == 2) - n->addable = 2; - if(l->addable == 3) - n->addable = 3; - } - break; - - case OASMUL: - case OASLMUL: - xcom(l); - xcom(r); - v = vlog(r); - if(v >= 0) { - n->op = OASASHL; - r->vconst = v; - r->type = types[TINT]; - } - break; - - case OMUL: - case OLMUL: - xcom(l); - xcom(r); - v = vlog(r); - if(v >= 0) { - n->op = OASHL; - r->vconst = v; - r->type = types[TINT]; - } - v = vlog(l); - if(v >= 0) { - n->op = OASHL; - n->left = r; - n->right = l; - r = l; - l = n->left; - r->vconst = v; - r->type = types[TINT]; - simplifyshift(n); - } - break; - - case OASLDIV: - xcom(l); - xcom(r); - v = vlog(r); - if(v >= 0) { - n->op = OASLSHR; - r->vconst = v; - r->type = types[TINT]; - } - break; - - case OLDIV: - xcom(l); - xcom(r); - v = vlog(r); - if(v >= 0) { - n->op = OLSHR; - r->vconst = v; - r->type = types[TINT]; - simplifyshift(n); - } - break; - - case OASLMOD: - xcom(l); - xcom(r); - v = vlog(r); - if(v >= 0) { - n->op = OASAND; - r->vconst--; - } - break; - - case OLMOD: - xcom(l); - xcom(r); - v = vlog(r); - if(v >= 0) { - n->op = OAND; - r->vconst--; - } - break; - - case OLSHR: - case OASHL: - case OASHR: - xcom(l); - xcom(r); - simplifyshift(n); - break; - - default: - if(l != Z) - xcom(l); - if(r != Z) - xcom(r); - break; - } - if(n->addable >= 10) - return; - if(l != Z) - n->complex = l->complex; - if(r != Z) { - if(r->complex == n->complex) - n->complex = r->complex+1; - else - if(r->complex > n->complex) - n->complex = r->complex; - } - if(n->complex == 0) - n->complex++; - -// if(com64(n)) -// return; - - switch(n->op) { - - case OFUNC: - n->complex = FNX; - break; - - case OEQ: - case ONE: - case OLE: - case OLT: - case OGE: - case OGT: - case OHI: - case OHS: - case OLO: - case OLS: - /* - * immediate operators, make const on right - */ - if(l->op == OCONST) { - n->left = r; - n->right = l; - n->op = invrel[relindex(n->op)]; - } - break; - - case OADD: - case OXOR: - case OAND: - case OOR: - /* - * immediate operators, make const on right - */ - if(l->op == OCONST) { - n->left = r; - n->right = l; - } - break; - } -} - diff --git a/src/cmd/9c/swt.c b/src/cmd/9c/swt.c deleted file mode 100644 index a63db60b2..000000000 --- a/src/cmd/9c/swt.c +++ /dev/null @@ -1,407 +0,0 @@ -// cmd/9c/swt.c from Vita Nuova. -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "gc.h" - -void -swit1(C1 *q, int nc, int32 def, Node *n) -{ - Node tn, nod; - - regalloc(&nod, n, Z); - /* always signed */ - if(typev[n->type->etype]) - nod.type = types[TVLONG]; - else - nod.type = types[TLONG]; - cgen(n, &nod); - regalloc(&tn, ®node, Z); - swit2(q, nc, def, &nod, &tn); - regfree(&tn); - regfree(&nod); -} - -void -swit2(C1 *q, int nc, int32 def, Node *n, Node *tn) -{ - C1 *r; - int i; - Prog *sp; - - if(nc < 5) { - for(i=0; i<nc; i++) { - if(sval(q->val)) { - gopcode(OEQ, n, Z, nodconst(q->val)); - } else { - gopcode(OSUB, nodconst(q->val), n, tn); - gopcode(OEQ, tn, Z, nodconst(0)); - } - patch(p, q->label); - q++; - } - gbranch(OGOTO); - patch(p, def); - return; - } - i = nc / 2; - r = q+i; - if(sval(r->val)) { - gopcode(OGT, n, Z, nodconst(r->val)); - sp = p; - } else { - gopcode(OSUB, nodconst(r->val), n, tn); - gopcode(OGT, tn, Z, nodconst(0)); - sp = p; - } - gbranch(OGOTO); - p->as = ABEQ; - patch(p, r->label); - swit2(q, i, def, n, tn); - - patch(sp, pc); - swit2(r+1, nc-i-1, def, n, tn); -} - -void -bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn) -{ - int sh; - int32 v; - Node *l; - - /* - * n1 gets adjusted/masked value - * n2 gets address of cell - * n3 gets contents of cell - */ - l = b->left; - if(n2 != Z) { - regalloc(n1, l, nn); - reglcgen(n2, l, Z); - regalloc(n3, l, Z); - gopcode(OAS, n2, Z, n3); - gopcode(OAS, n3, Z, n1); - } else { - regalloc(n1, l, nn); - cgen(l, n1); - } - if(b->type->shift == 0 && typeu[b->type->etype]) { - v = ~0 + (1L << b->type->nbits); - gopcode(OAND, nodconst(v), Z, n1); - } else { - sh = 32 - b->type->shift - b->type->nbits; - if(sh > 0) - gopcode(OASHL, nodconst(sh), Z, n1); - sh += b->type->shift; - if(sh > 0) - if(typeu[b->type->etype]) - gopcode(OLSHR, nodconst(sh), Z, n1); - else - gopcode(OASHR, nodconst(sh), Z, n1); - } -} - -void -bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn) -{ - int32 v; - Node nod, *l; - int sh; - - /* - * n1 has adjusted/masked value - * n2 has address of cell - * n3 has contents of cell - */ - l = b->left; - regalloc(&nod, l, Z); - v = ~0 + (1L << b->type->nbits); - gopcode(OAND, nodconst(v), Z, n1); - gopcode(OAS, n1, Z, &nod); - if(nn != Z) - gopcode(OAS, n1, Z, nn); - sh = b->type->shift; - if(sh > 0) - gopcode(OASHL, nodconst(sh), Z, &nod); - v <<= sh; - gopcode(OAND, nodconst(~v), Z, n3); - gopcode(OOR, n3, Z, &nod); - gopcode(OAS, &nod, Z, n2); - - regfree(&nod); - regfree(n1); - regfree(n2); - regfree(n3); -} - -int32 -outstring(char *s, int32 n) -{ - int32 r; - - if(suppress) - return nstring; - r = nstring; - while(n) { - string[mnstring] = *s++; - mnstring++; - nstring++; - if(mnstring >= NSNAME) { - gpseudo(ADATA, symstring, nodconst(0L)); - p->from.offset += nstring - NSNAME; - p->reg = NSNAME; - p->to.type = D_SCONST; - memmove(p->to.u.sval, string, NSNAME); - mnstring = 0; - } - n--; - } - return r; -} - -int -mulcon(Node *n, Node *nn) -{ - Node *l, *r, nod1, nod2; - Multab *m; - int32 v; - int o; - char code[sizeof(m->code)+2], *p; - - if(typefd[n->type->etype]) - return 0; - l = n->left; - r = n->right; - if(l->op == OCONST) { - l = r; - r = n->left; - } - if(r->op != OCONST) - return 0; - v = convvtox(r->vconst, n->type->etype); - if(v != r->vconst) { - if(debug['M']) - print("%L multiply conv: %lld\n", n->lineno, r->vconst); - return 0; - } - m = mulcon0(n, v); - if(!m) { - if(debug['M']) - print("%L multiply table: %lld\n", n->lineno, r->vconst); - return 0; - } - - memmove(code, m->code, sizeof(m->code)); - code[sizeof(m->code)] = 0; - - p = code; - if(p[1] == 'i') - p += 2; - regalloc(&nod1, n, nn); - cgen(l, &nod1); - if(v < 0) - gopcode(ONEG, &nod1, Z, &nod1); - regalloc(&nod2, n, Z); - -loop: - switch(*p) { - case 0: - regfree(&nod2); - gopcode(OAS, &nod1, Z, nn); - regfree(&nod1); - return 1; - case '+': - o = OADD; - goto addsub; - case '-': - o = OSUB; - addsub: /* number is r,n,l */ - v = p[1] - '0'; - r = &nod1; - if(v&4) - r = &nod2; - n = &nod1; - if(v&2) - n = &nod2; - l = &nod1; - if(v&1) - l = &nod2; - gopcode(o, l, n, r); - break; - default: /* op is shiftcount, number is r,l */ - v = p[1] - '0'; - r = &nod1; - if(v&2) - r = &nod2; - l = &nod1; - if(v&1) - l = &nod2; - v = *p - 'a'; - if(v < 0 || v >= 32) { - diag(n, "mulcon unknown op: %c%c", p[0], p[1]); - break; - } - gopcode(OASHL, nodconst(v), l, r); - break; - } - p += 2; - goto loop; -} - -void -sextern(Sym *s, Node *a, int32 o, int32 w) -{ - int32 e, lw; - - for(e=0; e<w; e+=NSNAME) { - lw = NSNAME; - if(w-e < lw) - lw = w-e; - gpseudo(ADATA, s, nodconst(0)); - p->from.offset += o+e; - p->reg = lw; - p->to.type = D_SCONST; - memmove(p->to.u.sval, a->cstring+e, lw); - } -} - -void -gextern(Sym *s, Node *a, int32 o, int32 w) -{ - gpseudo(ADATA, s, a); - p->from.offset += o; - p->reg = w; - if(p->to.type == D_OREG) - p->to.type = D_CONST; -} - -void -outcode(void) -{ - Bprint(&outbuf, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion()); - if(pragcgobuf.to > pragcgobuf.start) { - Bprint(&outbuf, "\n"); - Bprint(&outbuf, "$$ // exports\n\n"); - Bprint(&outbuf, "$$ // local types\n\n"); - Bprint(&outbuf, "$$ // cgo\n"); - Bprint(&outbuf, "%s", fmtstrflush(&pragcgobuf)); - Bprint(&outbuf, "\n$$\n\n"); - } - Bprint(&outbuf, "!\n"); - - writeobj(ctxt, &outbuf); - lastp = nil; -} - -int32 -align(int32 i, Type *t, int op, int32 *maxalign) -{ - int32 o; - Type *v; - int w, packw; - - o = i; - w = 1; - packw = 0; - switch(op) { - default: - diag(Z, "unknown align opcode %d", op); - break; - - case Asu2: /* padding at end of a struct */ - w = *maxalign; - if(w < 1) - w = 1; - if(packflg) - packw = packflg; - break; - - case Ael1: /* initial allign of struct element */ - for(v=t; v->etype==TARRAY; v=v->link) - ; - if(v->etype == TSTRUCT || v->etype == TUNION) - w = v->align; - else - w = ewidth[v->etype]; - if(w < 1 || w > SZ_VLONG) - fatal(Z, "align"); - if(packflg) - packw = packflg; - break; - - case Ael2: /* width of a struct element */ - o += t->width; - break; - - case Aarg0: /* initial passbyptr argument in arg list */ - if(typesu[t->etype]) { - o = align(o, types[TIND], Aarg1, nil); - o = align(o, types[TIND], Aarg2, nil); - } - break; - - case Aarg1: /* initial align of parameter */ - w = ewidth[t->etype]; - if(w <= 0 || w >= SZ_VLONG) { - w = SZ_VLONG; - break; - } - w = 1; - break; - - case Aarg2: /* width of a parameter */ - o += t->width; - w = t->width; - if(w > SZ_VLONG) - w = SZ_VLONG; - break; - - case Aaut3: /* total align of automatic */ - o = align(o, t, Ael1, nil); - 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; - if(debug['A']) - print("align %s %ld %T = %ld\n", bnames[op], i, t, o); - return o; -} - -int32 -maxround(int32 max, int32 v) -{ - v = xround(v, SZ_VLONG); - if(v > max) - return v; - return max; -} diff --git a/src/cmd/9c/txt.c b/src/cmd/9c/txt.c deleted file mode 100644 index e46aba84e..000000000 --- a/src/cmd/9c/txt.c +++ /dev/null @@ -1,1537 +0,0 @@ -// cmd/9c/txt.c from Vita Nuova. -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "gc.h" - -static int resvreg[nelem(reg)]; - -#define isv(et) ((et) == TVLONG || (et) == TUVLONG || (et) == TIND) - -int thechar = '9'; -char *thestring = "power64"; - -LinkArch *thelinkarch; - -void -linkarchinit(void) -{ - thestring = getgoarch(); - if(strcmp(thestring, "power64le") == 0) - thelinkarch = &linkpower64le; - else - thelinkarch = &linkpower64; -} - - -void -ginit(void) -{ - Type *t; - - dodefine("_64BITREG"); - dodefine("_64BIT"); - exregoffset = REGEXT; - exfregoffset = FREGEXT; - listinit(); - nstring = 0; - mnstring = 0; - nrathole = 0; - pc = 0; - breakpc = -1; - continpc = -1; - cases = C; - lastp = P; - tfield = types[TLONG]; - - typeword = typechlvp; - typecmplx = typesu; - /* TO DO */ - memmove(typechlpv, typechlp, sizeof(typechlpv)); - typechlpv[TVLONG] = 1; - typechlpv[TUVLONG] = 1; - - zprog.link = P; - zprog.as = AGOK; - zprog.reg = NREG; - zprog.from.type = D_NONE; - zprog.from.name = D_NONE; - zprog.from.reg = NREG; - zprog.from3 = zprog.from; - zprog.to = zprog.from; - - regnode.op = OREGISTER; - regnode.class = CEXREG; - regnode.reg = 0; - regnode.complex = 0; - regnode.addable = 11; - regnode.type = types[TLONG]; - - qregnode = regnode; - qregnode.type = types[TVLONG]; - - constnode.op = OCONST; - constnode.class = CXXX; - constnode.complex = 0; - constnode.addable = 20; - constnode.type = types[TLONG]; - - vconstnode = constnode; - vconstnode.type = types[TVLONG]; - - fconstnode.op = OCONST; - fconstnode.class = CXXX; - fconstnode.complex = 0; - fconstnode.addable = 20; - fconstnode.type = types[TDOUBLE]; - - nodsafe = new(ONAME, Z, Z); - nodsafe->sym = slookup(".safe"); - nodsafe->type = types[TINT]; - nodsafe->etype = types[TINT]->etype; - nodsafe->class = CAUTO; - complex(nodsafe); - - t = typ(TARRAY, types[TCHAR]); - symrathole = slookup(".rathole"); - symrathole->class = CGLOBL; - symrathole->type = t; - - nodrat = new(ONAME, Z, Z); - nodrat->sym = symrathole; - nodrat->type = types[TIND]; - nodrat->etype = TVOID; - nodrat->class = CGLOBL; - complex(nodrat); - nodrat->type = t; - - nodret = new(ONAME, Z, Z); - nodret->sym = slookup(".ret"); - nodret->type = types[TIND]; - nodret->etype = TIND; - nodret->class = CPARAM; - nodret = new(OIND, nodret, Z); - complex(nodret); - - com64init(); - - memset(reg, 0, sizeof(reg)); - reg[REGZERO] = 1; /* don't use */ - reg[REGTMP] = 1; - reg[FREGCVI+NREG] = 1; - reg[FREGZERO+NREG] = 1; - reg[FREGHALF+NREG] = 1; - reg[FREGONE+NREG] = 1; - reg[FREGTWO+NREG] = 1; - memmove(resvreg, reg, sizeof(reg)); -} - -void -gclean(void) -{ - int i; - Sym *s; - - for(i=0; i<NREG; i++) - if(reg[i] && !resvreg[i]) - diag(Z, "reg %d left allocated", i); - for(i=NREG; i<NREG+NREG; i++) - if(reg[i] && !resvreg[i]) - diag(Z, "freg %d left allocated", i-NREG); - while(mnstring) - outstring("", 1L); - symstring->type->width = nstring; - symrathole->type->width = nrathole; - for(i=0; i<NHASH; i++) - for(s = hash[i]; s != S; s = s->link) { - if(s->type == T) - continue; - if(s->type->width == 0) - continue; - if(s->class != CGLOBL && s->class != CSTATIC) - continue; - if(s->type == types[TENUM]) - continue; - gpseudo(AGLOBL, s, nodconst(s->type->width)); - } - nextpc(); - p->as = AEND; - outcode(); -} - -void -nextpc(void) -{ - Plist *pl; - - p = alloc(sizeof(*p)); - *p = zprog; - p->lineno = nearln; - p->pc = pc; - pc++; - if(lastp == P) { - pl = linknewplist(ctxt); - pl->firstpc = p; - } else - lastp->link = p; - lastp = p; -} - -void -gargs(Node *n, Node *tn1, Node *tn2) -{ - int32 regs; - Node fnxargs[20], *fnxp; - - regs = cursafe; - - fnxp = fnxargs; - garg1(n, tn1, tn2, 0, &fnxp); /* compile fns to temps */ - - curarg = 0; - fnxp = fnxargs; - garg1(n, tn1, tn2, 1, &fnxp); /* compile normal args and temps */ - - cursafe = regs; -} - -void -garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp) -{ - Node nod; - - if(n == Z) - return; - if(n->op == OLIST) { - garg1(n->left, tn1, tn2, f, fnxp); - garg1(n->right, tn1, tn2, f, fnxp); - return; - } - if(f == 0) { - if(n->complex >= FNX) { - regsalloc(*fnxp, n); - nod = znode; - nod.op = OAS; - nod.left = *fnxp; - nod.right = n; - nod.type = n->type; - cgen(&nod, Z); - (*fnxp)++; - } - return; - } - if(typesu[n->type->etype]) { - regaalloc(tn2, n); - if(n->complex >= FNX) { - sugen(*fnxp, tn2, n->type->width); - (*fnxp)++; - } else - sugen(n, tn2, n->type->width); - return; - } - if(REGARG>=0 && curarg == 0 && typechlpv[n->type->etype]) { - regaalloc1(tn1, n); - if(n->complex >= FNX) { - cgen(*fnxp, tn1); - (*fnxp)++; - } else - cgen(n, tn1); - return; - } - if(vconst(n) == 0) { - regaalloc(tn2, n); - gopcode(OAS, n, Z, tn2); - return; - } - regalloc(tn1, n, Z); - if(n->complex >= FNX) { - cgen(*fnxp, tn1); - (*fnxp)++; - } else - cgen(n, tn1); - regaalloc(tn2, n); - gopcode(OAS, tn1, Z, tn2); - regfree(tn1); -} - -Node* -nod32const(vlong v) -{ - constnode.vconst = v & MASK(32); - return &constnode; -} - -Node* -nodgconst(vlong v, Type *t) -{ - if(!typev[t->etype]) - return nodconst((int32)v); - vconstnode.vconst = v; - return &vconstnode; -} - -Node* -nodconst(int32 v) -{ - constnode.vconst = v; - return &constnode; -} - -Node* -nodfconst(double d) -{ - fconstnode.fconst = d; - return &fconstnode; -} - -void -nodreg(Node *n, Node *nn, int reg) -{ - *n = qregnode; - n->reg = reg; - n->type = nn->type; - n->lineno = nn->lineno; -} - -void -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; - } - - 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 -regalloc(Node *n, Node *tn, Node *o) -{ - int i, j; - static int lasti; - - switch(tn->type->etype) { - case TCHAR: - case TUCHAR: - case TSHORT: - case TUSHORT: - case TINT: - case TUINT: - case TLONG: - case TULONG: - case TVLONG: - case TUVLONG: - case TIND: - if(o != Z && o->op == OREGISTER) { - i = o->reg; - if(i > 0 && i < NREG) - goto out; - } - j = lasti + REGRET+1; - for(i=REGRET+1; i<NREG; i++) { - if(j >= NREG) - j = REGRET+1; - if(reg[j] == 0) { - i = j; - goto out; - } - j++; - } - diag(tn, "out of fixed registers"); - goto err; - - case TFLOAT: - case TDOUBLE: - if(o != Z && o->op == OREGISTER) { - i = o->reg; - if(i >= NREG && i < NREG+NREG) - goto out; - } - j = lasti + NREG; - for(i=NREG; i<NREG+NREG; i++) { - if(j >= NREG+NREG) - j = NREG; - if(reg[j] == 0) { - i = j; - goto out; - } - j++; - } - diag(tn, "out of float registers"); - goto err; - } - diag(tn, "unknown type in regalloc: %T", tn->type); -err: - i = 0; -out: - if(i) - reg[i]++; - lasti++; - if(lasti >= 5) - lasti = 0; - nodreg(n, tn, i); -} - -void -regialloc(Node *n, Node *tn, Node *o) -{ - Node nod; - - nod = *tn; - nod.type = types[TIND]; - regalloc(n, &nod, o); -} - -void -regfree(Node *n) -{ - int i; - - i = 0; - if(n->op != OREGISTER && n->op != OINDREG) - goto err; - i = n->reg; - if(i < 0 || i >= sizeof(reg)) - goto err; - if(reg[i] <= 0) - goto err; - reg[i]--; - return; -err: - diag(n, "error in regfree: %d", i); -} - -void -regsalloc(Node *n, Node *nn) -{ - cursafe = align(cursafe, nn->type, Aaut3, nil); - maxargsafe = maxround(maxargsafe, cursafe+curarg); - *n = *nodsafe; - n->xoffset = -(stkoff + cursafe); - n->type = nn->type; - n->etype = nn->type->etype; - n->lineno = nn->lineno; -} - -void -regaalloc1(Node *n, Node *nn) -{ - if(REGARG < 0) - return; - nodreg(n, nn, REGARG); - reg[REGARG]++; - curarg = align(curarg, nn->type, Aarg1, nil); - curarg = align(curarg, nn->type, Aarg2, nil); - maxargsafe = maxround(maxargsafe, cursafe+curarg); -} - -void -regaalloc(Node *n, Node *nn) -{ - curarg = align(curarg, nn->type, Aarg1, nil); - *n = *nn; - n->op = OINDREG; - n->reg = REGSP; - n->xoffset = curarg + SZ_VLONG; - n->complex = 0; - n->addable = 20; - curarg = align(curarg, nn->type, Aarg2, nil); - maxargsafe = maxround(maxargsafe, cursafe+curarg); -} - -void -regind(Node *n, Node *nn) -{ - - if(n->op != OREGISTER) { - diag(n, "regind not OREGISTER"); - return; - } - n->op = OINDREG; - n->type = nn->type; -} - -void -raddr(Node *n, Prog *p) -{ - Addr a; - - naddr(n, &a); - if(R0ISZERO && a.type == D_CONST && a.offset == 0) { - a.type = D_REG; - a.reg = REGZERO; - } - if(a.type != D_REG && a.type != D_FREG) { - if(n) - diag(n, "bad in raddr: %O", n->op); - else - diag(n, "bad in raddr: <null>"); - p->reg = NREG; - } else - p->reg = a.reg; -} - -void -naddr(Node *n, Addr *a) -{ - int32 v; - - a->type = D_NONE; - if(n == Z) - return; - switch(n->op) { - default: - bad: - prtree(n, "naddr"); - diag(n, "%L: !bad in naddr: %O", n->lineno, n->op); - break; - - case OREGISTER: - a->type = D_REG; - a->sym = nil; - a->reg = n->reg; - if(a->reg >= NREG) { - a->type = D_FREG; - a->reg -= NREG; - } - break; - - case OIND: - naddr(n->left, a); - if(a->type == D_REG) { - a->type = D_OREG; - break; - } - if(a->type == D_CONST) { - a->type = D_OREG; - break; - } - goto bad; - - case OINDREG: - a->type = D_OREG; - a->sym = nil; - a->offset = n->xoffset; - a->reg = n->reg; - break; - - case ONAME: - a->etype = n->etype; - a->type = D_OREG; - a->name = D_STATIC; - a->sym = linksym(n->sym); - a->offset = n->xoffset; - if(n->class == CSTATIC) - break; - if(n->class == CEXTERN || n->class == CGLOBL) { - a->name = D_EXTERN; - break; - } - if(n->class == CAUTO) { - a->name = D_AUTO; - break; - } - if(n->class == CPARAM) { - a->name = D_PARAM; - break; - } - goto bad; - - case OCONST: - a->sym = nil; - a->reg = NREG; - if(typefd[n->type->etype]) { - a->type = D_FCONST; - a->u.dval = n->fconst; - } else { - a->type = D_CONST; - a->offset = n->vconst; - } - break; - - case OADDR: - naddr(n->left, a); - if(a->type == D_OREG) { - a->type = D_CONST; - break; - } - goto bad; - - case OADD: - if(n->left->op == OCONST) { - naddr(n->left, a); - v = a->offset; - naddr(n->right, a); - } else { - naddr(n->right, a); - v = a->offset; - naddr(n->left, a); - } - a->offset += v; - break; - - } -} - -void -fop(int as, int f1, int f2, Node *t) -{ - Node nod1, nod2, nod3; - - nodreg(&nod1, t, NREG+f1); - nodreg(&nod2, t, NREG+f2); - regalloc(&nod3, t, t); - gopcode(as, &nod1, &nod2, &nod3); - gmove(&nod3, t); - regfree(&nod3); -} - -void -gmove(Node *f, Node *t) -{ - int ft, tt, a; - Node nod, fxc0, fxc1, fxc2, fxrat; - Prog *p1; - double d; - - ft = f->type->etype; - tt = t->type->etype; - - if(ft == TDOUBLE && f->op == OCONST) { - d = f->fconst; - if(d == 0.0) { - a = FREGZERO; - goto ffreg; - } - if(d == 0.5) { - a = FREGHALF; - goto ffreg; - } - if(d == 1.0) { - a = FREGONE; - goto ffreg; - } - if(d == 2.0) { - a = FREGTWO; - goto ffreg; - } - if(d == -.5) { - fop(OSUB, FREGHALF, FREGZERO, t); - return; - } - if(d == -1.0) { - fop(OSUB, FREGONE, FREGZERO, t); - return; - } - if(d == -2.0) { - fop(OSUB, FREGTWO, FREGZERO, t); - return; - } - if(d == 1.5) { - fop(OADD, FREGONE, FREGHALF, t); - return; - } - if(d == 2.5) { - fop(OADD, FREGTWO, FREGHALF, t); - return; - } - if(d == 3.0) { - fop(OADD, FREGTWO, FREGONE, t); - return; - } - } - if(ft == TFLOAT && f->op == OCONST) { - d = f->fconst; - if(d == 0) { - a = FREGZERO; - ffreg: - nodreg(&nod, f, NREG+a); - gmove(&nod, t); - return; - } - } - /* - * a load -- - * put it into a register then - * worry what to do with it. - */ - if(f->op == ONAME || f->op == OINDREG || f->op == OIND) { - switch(ft) { - default: - if(ewidth[ft] == 4){ - if(typeu[ft]) - a = AMOVWZ; - else - a = AMOVW; - }else - a = AMOVD; - break; - case TINT: - a = AMOVW; - break; - case TUINT: - a = AMOVWZ; - break; - case TFLOAT: - a = AFMOVS; - break; - case TDOUBLE: - a = AFMOVD; - break; - case TCHAR: - a = AMOVB; - break; - case TUCHAR: - a = AMOVBZ; - break; - case TSHORT: - a = AMOVH; - break; - case TUSHORT: - a = AMOVHZ; - break; - } - regalloc(&nod, f, t); - gins(a, f, &nod); - gmove(&nod, t); - regfree(&nod); - return; - } - - /* - * a store -- - * put it into a register then - * store it. - */ - if(t->op == ONAME || t->op == OINDREG || t->op == OIND) { - switch(tt) { - default: - if(ewidth[tt] == 4) - a = AMOVW; - else - a = AMOVD; - break; - case TINT: - a = AMOVW; - break; - case TUINT: - a = AMOVWZ; - break; - case TUCHAR: - a = AMOVBZ; - break; - case TCHAR: - a = AMOVB; - break; - case TUSHORT: - a = AMOVHZ; - break; - case TSHORT: - a = AMOVH; - break; - case TFLOAT: - a = AFMOVS; - break; - case TDOUBLE: - a = AFMOVD; - break; - } - if(!typefd[ft] && vconst(f) == 0) { - gins(a, f, t); - return; - } - if(ft == tt) - regalloc(&nod, t, f); - else - regalloc(&nod, t, Z); - gmove(f, &nod); - gins(a, &nod, t); - regfree(&nod); - return; - } - - /* - * type x type cross table - */ - a = AGOK; - switch(ft) { - case TDOUBLE: - case TFLOAT: - switch(tt) { - case TDOUBLE: - a = AFMOVD; - if(ft == TFLOAT) - a = AFMOVS; /* AFMOVSD */ - break; - case TFLOAT: - a = AFRSP; - if(ft == TFLOAT) - a = AFMOVS; - break; - case TINT: - case TUINT: - case TLONG: - case TULONG: - case TIND: - case TSHORT: - case TUSHORT: - case TCHAR: - case TUCHAR: - /* BUG: not right for unsigned int32 */ - regalloc(&nod, f, Z); /* should be type float */ - regsalloc(&fxrat, f); - gins(AFCTIWZ, f, &nod); - gins(AFMOVD, &nod, &fxrat); - regfree(&nod); - fxrat.type = nodrat->type; - fxrat.etype = nodrat->etype; - fxrat.xoffset += 4; - gins(AMOVW, &fxrat, t); /* TO DO */ - gmove(t, t); - return; - case TVLONG: - case TUVLONG: - /* BUG: not right for unsigned int32 */ - regalloc(&nod, f, Z); /* should be type float */ - regsalloc(&fxrat, f); - gins(AFCTIDZ, f, &nod); - gins(AFMOVD, &nod, &fxrat); - regfree(&nod); - fxrat.type = nodrat->type; - fxrat.etype = nodrat->etype; - gins(AMOVD, &fxrat, t); - gmove(t, t); - return; - } - break; - case TINT: - case TUINT: - case TLONG: - case TULONG: - switch(tt) { - case TDOUBLE: - case TFLOAT: - goto fxtofl; - case TINT: - case TUINT: - case TLONG: - case TULONG: - case TSHORT: - case TUSHORT: - case TCHAR: - case TUCHAR: - if(typeu[tt]) - a = AMOVWZ; - else - a = AMOVW; - break; - case TVLONG: - case TUVLONG: - case TIND: - a = AMOVD; - break; - } - break; - case TVLONG: - case TUVLONG: - case TIND: - switch(tt) { - case TDOUBLE: - case TFLOAT: - goto fxtofl; - case TINT: - case TUINT: - case TLONG: - case TULONG: - case TVLONG: - case TUVLONG: - case TIND: - case TSHORT: - case TUSHORT: - case TCHAR: - case TUCHAR: - a = AMOVD; /* TO DO: conversion done? */ - break; - } - break; - case TSHORT: - switch(tt) { - case TDOUBLE: - case TFLOAT: - goto fxtofl; - case TINT: - case TUINT: - case TLONG: - case TULONG: - case TVLONG: - case TUVLONG: - case TIND: - a = AMOVH; - break; - case TSHORT: - case TUSHORT: - case TCHAR: - case TUCHAR: - a = AMOVD; - break; - } - break; - case TUSHORT: - switch(tt) { - case TDOUBLE: - case TFLOAT: - goto fxtofl; - case TINT: - case TUINT: - case TLONG: - case TULONG: - case TVLONG: - case TUVLONG: - case TIND: - a = AMOVHZ; - break; - case TSHORT: - case TUSHORT: - case TCHAR: - case TUCHAR: - a = AMOVD; - break; - } - break; - case TCHAR: - switch(tt) { - case TDOUBLE: - case TFLOAT: - goto fxtofl; - case TINT: - case TUINT: - case TLONG: - case TULONG: - case TVLONG: - case TUVLONG: - case TIND: - case TSHORT: - case TUSHORT: - a = AMOVB; - break; - case TCHAR: - case TUCHAR: - a = AMOVD; - break; - } - break; - case TUCHAR: - switch(tt) { - case TDOUBLE: - case TFLOAT: - fxtofl: - /* - * rat[0] = 0x43300000; rat[1] = f^0x80000000; - * t = *(double*)rat - FREGCVI; - * is-unsigned(t) => if(t<0) t += 2^32; - * could be streamlined for int-to-float - */ - regalloc(&fxc0, f, Z); - regalloc(&fxc2, f, Z); - regsalloc(&fxrat, t); /* should be type float */ - gins(AMOVW, nodconst(0x43300000L), &fxc0); - gins(AMOVW, f, &fxc2); - gins(AXOR, nodconst(0x80000000L), &fxc2); - if(ctxt->arch->endian == BigEndian) { - gins(AMOVW, &fxc0, &fxrat); - fxc1 = fxrat; - fxc1.type = nodrat->type; - fxc1.etype = nodrat->etype; - fxc1.xoffset += SZ_LONG; - gins(AMOVW, &fxc2, &fxc1); - } else { - gins(AMOVW, &fxc2, &fxrat); - fxc1 = fxrat; - fxc1.type = nodrat->type; - fxc1.etype = nodrat->etype; - fxc1.xoffset += SZ_LONG; - gins(AMOVW, &fxc0, &fxc1); - } - regfree(&fxc2); - regfree(&fxc0); - regalloc(&nod, t, t); /* should be type float */ - gins(AFMOVD, &fxrat, &nod); - nodreg(&fxc1, t, NREG+FREGCVI); - gins(AFSUB, &fxc1, &nod); - a = AFMOVD; - if(tt == TFLOAT) - a = AFRSP; - gins(a, &nod, t); - regfree(&nod); - if(ft == TULONG) { - regalloc(&nod, t, Z); - if(tt == TFLOAT) { - gins(AFCMPU, t, Z); - p->to.type = D_FREG; - p->to.reg = FREGZERO; - gins(ABGE, Z, Z); - p1 = p; - gins(AFMOVS, nodfconst(4294967296.), &nod); - gins(AFADDS, &nod, t); - } else { - gins(AFCMPU, t, Z); - p->to.type = D_FREG; - p->to.reg = FREGZERO; - gins(ABGE, Z, Z); - p1 = p; - gins(AFMOVD, nodfconst(4294967296.), &nod); - gins(AFADD, &nod, t); - } - patch(p1, pc); - regfree(&nod); - } - return; - case TINT: - case TUINT: - case TLONG: - case TULONG: - case TVLONG: - case TUVLONG: - case TIND: - case TSHORT: - case TUSHORT: - a = AMOVBZ; - break; - case TCHAR: - case TUCHAR: - a = AMOVD; - break; - } - break; - } - if(a == AGOK) - diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type); - if(a == AMOVD || (a == AMOVW || a == AMOVWZ) && ewidth[ft] == ewidth[tt] || a == AFMOVS || a == AFMOVD) - if(samaddr(f, t)) - return; - gins(a, f, t); -} - -void -gins(int a, Node *f, Node *t) -{ - - nextpc(); - p->as = a; - if(f != Z) - naddr(f, &p->from); - if(t != Z) - naddr(t, &p->to); - if(debug['g']) - print("%P\n", p); -} - -void -gopcode(int o, Node *f1, Node *f2, Node *t) -{ - int a, et; - Addr ta; - int uns; - - uns = 0; - et = TLONG; - if(f1 != Z && f1->type != T) { - if(f1->op == OCONST && t != Z && t->type != T) - et = t->type->etype; - else - et = f1->type->etype; - } - a = AGOK; - switch(o) { - case OAS: - gmove(f1, t); - return; - - case OASADD: - case OADD: - a = AADD; - if(et == TFLOAT) - a = AFADDS; - else - if(et == TDOUBLE) - a = AFADD; - break; - - case OASSUB: - case OSUB: - a = ASUB; - if(et == TFLOAT) - a = AFSUBS; - else - if(et == TDOUBLE) - a = AFSUB; - break; - - case OASOR: - case OOR: - a = AOR; - break; - - case OASAND: - case OAND: - a = AAND; - if(f1->op == OCONST) - a = AANDCC; - break; - - case OASXOR: - case OXOR: - a = AXOR; - break; - - case OASLSHR: - case OLSHR: - a = ASRW; - if(isv(et)) - a = ASRD; - break; - - case OASASHR: - case OASHR: - a = ASRAW; - if(isv(et)) - a = ASRAD; - break; - - case OASASHL: - case OASHL: - a = ASLW; - if(isv(et)) - a = ASLD; - break; - - case OFUNC: - a = ABL; - break; - - case OASLMUL: - case OLMUL: - case OASMUL: - case OMUL: - if(et == TFLOAT) { - a = AFMULS; - break; - } else - if(et == TDOUBLE) { - a = AFMUL; - break; - } - a = AMULLW; - if(isv(et)) - a = AMULLD; - break; - - case OASDIV: - case ODIV: - if(et == TFLOAT) { - a = AFDIVS; - break; - } else - if(et == TDOUBLE) { - a = AFDIV; - break; - } else - a = ADIVW; - if(isv(et)) - a = ADIVD; - break; - - case OASMOD: - case OMOD: - a = AREM; - if(isv(et)) - a = AREMD; - break; - - case OASLMOD: - case OLMOD: - a = AREMU; - if(isv(et)) - a = AREMDU; - break; - - case OASLDIV: - case OLDIV: - a = ADIVWU; - if(isv(et)) - a = ADIVDU; - break; - - case OCOM: - a = ANOR; - break; - - case ONEG: - a = ANEG; - if(et == TFLOAT || et == TDOUBLE) - a = AFNEG; - break; - - case OEQ: - a = ABEQ; - goto cmp; - - case ONE: - a = ABNE; - goto cmp; - - case OLT: - a = ABLT; - goto cmp; - - case OLE: - a = ABLE; - goto cmp; - - case OGE: - a = ABGE; - goto cmp; - - case OGT: - a = ABGT; - goto cmp; - - case OLO: - a = ABLT; - goto cmpu; - - case OLS: - a = ABLE; - goto cmpu; - - case OHS: - a = ABGE; - goto cmpu; - - case OHI: - a = ABGT; - goto cmpu; - - cmpu: - uns = 1; - cmp: - nextpc(); - switch(et){ - case TINT: - case TLONG: - p->as = ACMPW; - break; - case TUINT: - case TULONG: - p->as = ACMPWU; - break; - case TFLOAT: - case TDOUBLE: - p->as = AFCMPU; - break; - default: - p->as = uns? ACMPU: ACMP; - break; - } - if(f1 != Z) - naddr(f1, &p->from); - if(t != Z) - naddr(t, &p->to); - if(f1 == Z || t == Z || f2 != Z) - diag(Z, "bad cmp in gopcode %O", o); - if(debug['g']) - print("%P\n", p); - f1 = Z; - f2 = Z; - t = Z; - break; - } - if(a == AGOK) - diag(Z, "bad in gopcode %O", o); - nextpc(); - p->as = a; - if(f1 != Z) - naddr(f1, &p->from); - if(f2 != Z) { - naddr(f2, &ta); - p->reg = ta.reg; - if(ta.type == D_CONST && ta.offset == 0) { - if(R0ISZERO) - p->reg = REGZERO; - else - diag(Z, "REGZERO in gopcode %O", o); - } - } - if(t != Z) - naddr(t, &p->to); - if(debug['g']) - print("%P\n", p); -} - -int -samaddr(Node *f, Node *t) -{ - return f->op == OREGISTER && t->op == OREGISTER && f->reg == t->reg; -} - -void -gbranch(int o) -{ - int a; - - a = AGOK; - switch(o) { - case ORETURN: - a = ARETURN; - break; - case OGOTO: - a = ABR; - break; - } - nextpc(); - if(a == AGOK) { - diag(Z, "bad in gbranch %O", o); - nextpc(); - } - p->as = a; -} - -void -patch(Prog *op, int32 pc) -{ - - op->to.offset = pc; - op->to.type = D_BRANCH; -} - -void -gpseudo(int a, Sym *s, Node *n) -{ - - nextpc(); - p->as = a; - p->from.type = D_OREG; - p->from.sym = linksym(s); - - switch(a) { - case ATEXT: - p->reg = textflag; - textflag = 0; - break; - case AGLOBL: - p->reg = s->dataflag; - break; - } - - p->from.name = D_EXTERN; - if(s->class == CSTATIC) - p->from.name = D_STATIC; - naddr(n, &p->to); - if(a == ADATA || a == AGLOBL) - pc--; -} - -int -sval(int32 v) -{ - - if(v >= -(1<<15) && v < (1<<15)) - return 1; - return 0; -} - -void -gpcdata(int index, int value) -{ - Node n1; - - n1 = *nodconst(index); - gins(APCDATA, &n1, nodconst(value)); -} - -void -gprefetch(Node *n) -{ - // TODO(minux) - USED(n); - /* - Node n1; - - regalloc(&n1, n, Z); - gmove(n, &n1); - n1.op = OINDREG; - gins(ADCBT, &n1, Z); - regfree(&n1); - */ -} - - -int -sconst(Node *n) -{ - vlong vv; - - if(n->op == OCONST) { - if(!typefd[n->type->etype]) { - vv = n->vconst; - if(vv >= -(((vlong)1)<<15) && vv < (((vlong)1)<<15)) - return 1; - } - } - return 0; -} - -int -uconst(Node *n) -{ - vlong vv; - - if(n->op == OCONST) { - if(!typefd[n->type->etype]) { - vv = n->vconst; - if(vv >= 0 && vv < (((vlong)1)<<16)) - return 1; - } - } - return 0; -} - -int -immconst(Node *n) -{ - vlong v; - - if(n->op != OCONST || typefd[n->type->etype]) - return 0; - v = n->vconst; - if((v & 0xFFFF) == 0) - v >>= 16; - if(v >= 0 && v < ((vlong)1<<16)) - return 1; - if(v >= -((vlong)1<<15) && v <= ((vlong)1<<15)) - return 1; - return 0; -} - -int32 -exreg(Type *t) -{ - int32 o; - - if(typechlpv[t->etype]) { - if(exregoffset <= 3) - return 0; - o = exregoffset; - exregoffset--; - return o; - } - if(typefd[t->etype]) { - if(exfregoffset <= 16) - return 0; - o = exfregoffset + NREG; - exfregoffset--; - return o; - } - return 0; -} - -schar ewidth[NTYPE] = -{ - -1, /* [TXXX] */ - SZ_CHAR, /* [TCHAR] */ - SZ_CHAR, /* [TUCHAR] */ - SZ_SHORT, /* [TSHORT] */ - SZ_SHORT, /* [TUSHORT] */ - SZ_INT, /* [TINT] */ - SZ_INT, /* [TUINT] */ - SZ_LONG, /* [TLONG] */ - SZ_LONG, /* [TULONG] */ - SZ_VLONG, /* [TVLONG] */ - SZ_VLONG, /* [TUVLONG] */ - SZ_FLOAT, /* [TFLOAT] */ - SZ_DOUBLE, /* [TDOUBLE] */ - SZ_IND, /* [TIND] */ - 0, /* [TFUNC] */ - -1, /* [TARRAY] */ - 0, /* [TVOID] */ - -1, /* [TSTRUCT] */ - -1, /* [TUNION] */ - SZ_INT, /* [TENUM] */ -}; -int32 ncast[NTYPE] = -{ - 0, /* [TXXX] */ - BCHAR|BUCHAR, /* [TCHAR] */ - BCHAR|BUCHAR, /* [TUCHAR] */ - BSHORT|BUSHORT, /* [TSHORT] */ - BSHORT|BUSHORT, /* [TUSHORT] */ - BINT|BUINT|BLONG|BULONG, /* [TINT] */ - BINT|BUINT|BLONG|BULONG, /* [TUINT] */ - BINT|BUINT|BLONG|BULONG, /* [TLONG] */ - BINT|BUINT|BLONG|BULONG, /* [TULONG] */ - BVLONG|BUVLONG|BIND, /* [TVLONG] */ - BVLONG|BUVLONG|BIND, /* [TUVLONG] */ - BFLOAT, /* [TFLOAT] */ - BDOUBLE, /* [TDOUBLE] */ - BVLONG|BUVLONG|BIND, /* [TIND] */ - 0, /* [TFUNC] */ - 0, /* [TARRAY] */ - 0, /* [TVOID] */ - BSTRUCT, /* [TSTRUCT] */ - BUNION, /* [TUNION] */ - 0, /* [TENUM] */ -}; diff --git a/src/cmd/9g/prog.c b/src/cmd/9g/prog.c index e3e50f28a..51c132d18 100644 --- a/src/cmd/9g/prog.c +++ b/src/cmd/9g/prog.c @@ -134,11 +134,12 @@ proginfo(ProgInfo *info, Prog *p) } if(p->as == ADUFFZERO) { - info->reguse |= RtoB(0) | RtoB(2); - info->regset |= RtoB(2); + info->reguse |= (1<<D_R0) | RtoB(3); + info->regset |= RtoB(3); } if(p->as == ADUFFCOPY) { - info->reguse |= RtoB(0) | RtoB(2) | RtoB(3); - info->regset |= RtoB(2) | RtoB(3); + // TODO(austin) Revisit when duffcopy is implemented + info->reguse |= RtoB(3) | RtoB(4) | RtoB(5); + info->regset |= RtoB(3) | RtoB(4); } } diff --git a/src/cmd/9g/reg.c b/src/cmd/9g/reg.c index b911a2399..2e546a95b 100644 --- a/src/cmd/9g/reg.c +++ b/src/cmd/9g/reg.c @@ -1322,7 +1322,6 @@ void dumpit(char *str, Flow *r0, int isreg) { Flow *r, *r1; - int s1v, s2v; print("\n%s\n", str); for(r = r0; r != nil; r = r->link) { @@ -1334,10 +1333,8 @@ dumpit(char *str, Flow *r0, int isreg) print(" %.4ud", (int)r1->prog->pc); print("\n"); } - // If at least one successor is "interesting", print both - s1v = (r->s1 != nil) && (r->s1->prog != r->prog->link); - s2v = (r->s2 != nil) && (r->s2->prog != r->prog->link); - if(s1v || s2v) { + // Print successors if it's not just the next one + if(r->s1 != r->link || r->s2 != nil) { print(" succ:"); if(r->s1 != nil) print(" %.4ud", (int)r->s1->prog->pc); diff --git a/src/cmd/9l/9.out.h b/src/cmd/9l/9.out.h index 08a339318..87917f88a 100644 --- a/src/cmd/9l/9.out.h +++ b/src/cmd/9l/9.out.h @@ -497,6 +497,8 @@ enum D_DCONST, D_ADDR, // not used, use D_CONST with non-empty sym. + D_LAST, + /* reg names for 9g OREGISTER */ D_R0 = 0, // type is D_REG D_F0 = D_R0+NREG, // type is D_FREG diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go index 69c7ce893..6179c7afd 100644 --- a/src/cmd/cgo/doc.go +++ b/src/cmd/cgo/doc.go @@ -152,7 +152,7 @@ In C, a function argument written as a fixed size array actually requires a pointer to the first element of the array. C compilers are aware of this calling convention and adjust the call accordingly, but Go cannot. In Go, you must pass -the pointer to the first element explicitly: C.f(&x[0]). +the pointer to the first element explicitly: C.f(&C.x[0]). A few special functions convert between Go and C types by making copies of the data. In pseudo-Go definitions: diff --git a/src/cmd/dist/build.c b/src/cmd/dist/build.c index e4f307bee..bfb3d15b8 100644 --- a/src/cmd/dist/build.c +++ b/src/cmd/dist/build.c @@ -615,8 +615,6 @@ static struct { {"anames9.c", mkanames}, {"zdefaultcc.go", mkzdefaultcc}, {"zsys_", mkzsys}, - {"zgoarch_", mkzgoarch}, - {"zgoos_", mkzgoos}, {"zversion.go", mkzversion}, {"zaexperiment.h", mkzexperiment}, @@ -1419,12 +1417,13 @@ clean(void) xremove(bpathf(&b, "%s/%s", bstr(&path), cleantab[i]+4)); } - // remove src/runtime/z* unconditionally + // remove src/runtime/z* unconditionally, + // except leave zgoos and zgoarch, now maintained with go generate. vreset(&dir); bpathf(&path, "%s/src/runtime", goroot); xreaddir(&dir, bstr(&path)); for(j=0; j<dir.len; j++) { - if(hasprefix(dir.p[j], "z")) + if(hasprefix(dir.p[j], "z") && !hasprefix(dir.p[j], "zg")) xremove(bpathf(&b, "%s/%s", bstr(&path), dir.p[j])); } diff --git a/src/cmd/dist/buildgc.c b/src/cmd/dist/buildgc.c index 1c3329758..64434d51e 100644 --- a/src/cmd/dist/buildgc.c +++ b/src/cmd/dist/buildgc.c @@ -63,22 +63,36 @@ gcopnames(char *dir, char *file) vfree(&fields); } +static int +xatoi(char *s, char **end) +{ + int val = 0; + for(; *s && *s >= '0' && *s <= '9'; ++s) + val = val * 10 + (*s - '0'); + *end = s; + return val; +} + // mkanames reads [5689].out.h and writes anames[5689].c // The format is much the same as the Go opcodes above. -// it also writes out cnames array for C_* constants. +// It also writes out cnames array for C_* constants and the dnames +// array for D_* constants. void mkanames(char *dir, char *file) { - int i, j, ch; + int i, j, ch, n, unknown; Buf in, b, out, out2; Vec lines; - char *p; + char *p, *p2; + Vec dnames[128]; binit(&b); binit(&in); binit(&out); binit(&out2); vinit(&lines); + for(i=0; i<nelem(dnames); i++) + vinit(&dnames[i]); ch = file[xstrlen(file)-3]; bprintf(&b, "%s/../cmd/%cl/%c.out.h", dir, ch, ch); @@ -87,10 +101,12 @@ mkanames(char *dir, char *file) // Include link.h so that the extern declaration there is // checked against the non-extern declaration we are generating. + bwritestr(&out, bprintf(&b, "// auto generated by go tool dist\n")); bwritestr(&out, bprintf(&b, "#include <u.h>\n")); bwritestr(&out, bprintf(&b, "#include <libc.h>\n")); bwritestr(&out, bprintf(&b, "#include <bio.h>\n")); bwritestr(&out, bprintf(&b, "#include <link.h>\n")); + bwritestr(&out, bprintf(&b, "#include \"../cmd/%cl/%c.out.h\"\n", ch, ch)); bwritestr(&out, bprintf(&b, "\n")); bwritestr(&out, bprintf(&b, "char* anames%c[] = {\n", ch)); @@ -127,6 +143,69 @@ mkanames(char *dir, char *file) if(j>0) bwriteb(&out, &out2); + j=unknown=0; + n=-1; + for(i=0; i<lines.len; i++) { + if(hasprefix(lines.p[i], "\tD_")) { + p = xstrstr(lines.p[i], ","); + if(p) + *p = '\0'; + p = xstrstr(lines.p[i], "\n"); + if(p) + *p = '\0'; + + // Parse explicit value, if any + p = xstrstr(lines.p[i], "="); + if(p) { + // Skip space after '=' + p2 = p + 1; + while(*p2 == ' ' || *p2 == '\t') + p2++; + n = xatoi(p2, &p2); + // We can't do anything about + // non-numeric values or anything that + // follows + while(*p2 == ' ' || *p2 == '\t') + p2++; + if(*p2 != 0) { + unknown = 1; + continue; + } + // Truncate space before '=' + while(*(p-1) == ' ' || *(p-1) == '\t') + p--; + *p = '\0'; + unknown = 0; + } else { + n++; + } + + if(unknown || n >= nelem(dnames)) + continue; + + p = lines.p[i] + 3; + if(xstrcmp(p, "LAST") == 0) + continue; + vadd(&dnames[n], p); + j++; + } + } + if(j>0){ + bwritestr(&out, bprintf(&b, "char* dnames%c[D_LAST] = {\n", ch)); + for(i=0; i<nelem(dnames); i++) { + if(dnames[i].len == 0) + continue; + bwritestr(&out, bprintf(&b, "\t[D_%s] = \"", dnames[i].p[0])); + for(j=0; j<dnames[i].len; j++) { + if(j != 0) + bwritestr(&out, "/"); + bwritestr(&out, dnames[i].p[j]); + } + bwritestr(&out, "\",\n"); + } + bwritestr(&out, "};\n"); + } + writefile(&out, file, 0); bfree(&b); @@ -134,4 +213,6 @@ mkanames(char *dir, char *file) bfree(&out); bfree(&out2); vfree(&lines); + for(i=0; i<nelem(dnames); i++) + vfree(&dnames[i]); } diff --git a/src/cmd/dist/buildruntime.c b/src/cmd/dist/buildruntime.c index e561937fb..38e99e116 100644 --- a/src/cmd/dist/buildruntime.c +++ b/src/cmd/dist/buildruntime.c @@ -67,66 +67,6 @@ mkzexperiment(char *dir, char *file) bfree(&exp); } -// mkzgoarch writes zgoarch_$GOARCH.go: -// -// package runtime -// const theGoarch = <goarch> -// -void -mkzgoarch(char *dir, char *file) -{ - Buf b, out; - - USED(dir); - - binit(&b); - binit(&out); - - bwritestr(&out, bprintf(&b, - "// auto generated by go tool dist\n" - "\n" - "package runtime\n" - "\n" - "const theGoarch = `%s`\n", goarch)); - - writefile(&out, file, 0); - - bfree(&b); - bfree(&out); -} - -// mkzgoos writes zgoos_$GOOS.go: -// -// package runtime -// const theGoos = <goos> -// -void -mkzgoos(char *dir, char *file) -{ - Buf b, out; - - USED(dir); - - binit(&b); - binit(&out); - - bwritestr(&out, "// auto generated by go tool dist\n\n"); - - if(streq(goos, "linux")) { - bwritestr(&out, "// +build !android\n\n"); - } - - bwritestr(&out, bprintf(&b, - "package runtime\n" - "\n" - "const theGoos = `%s`\n", goos)); - - writefile(&out, file, 0); - - bfree(&b); - bfree(&out); -} - #define MAXWINCB 2000 /* maximum number of windows callbacks allowed */ // mkzsys writes zsys_$GOOS_$GOARCH.s, diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index 37bd62dea..061089349 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -1776,7 +1776,6 @@ walkprint(Node *nn, NodeList **init) int notfirst, et, op; NodeList *calls; - on = nil; op = nn->op; all = nn->list; calls = nil; diff --git a/src/cmd/go/tool.go b/src/cmd/go/tool.go index c96161e0f..3f11c3e3d 100644 --- a/src/cmd/go/tool.go +++ b/src/cmd/go/tool.go @@ -47,7 +47,7 @@ const toolWindowsExtension = ".exe" func tool(toolName string) string { toolPath := filepath.Join(toolDir, toolName) - if toolIsWindows && toolName != "pprof" { + if toolIsWindows { toolPath += toolWindowsExtension } // Give a nice message if there is no tool with that name. @@ -91,16 +91,6 @@ func runTool(cmd *Command, args []string) { if toolPath == "" { return } - if toolIsWindows && toolName == "pprof" { - args = append([]string{"perl", toolPath}, args[1:]...) - var err error - toolPath, err = exec.LookPath("perl") - if err != nil { - fmt.Fprintf(os.Stderr, "go tool: perl not found\n") - setExitStatus(3) - return - } - } if toolN { fmt.Printf("%s %s\n", toolPath, strings.Join(args[1:], " ")) return diff --git a/src/debug/goobj/read.go b/src/cmd/internal/goobj/read.go index 79a83e59a..79a83e59a 100644 --- a/src/debug/goobj/read.go +++ b/src/cmd/internal/goobj/read.go diff --git a/src/debug/goobj/read_test.go b/src/cmd/internal/goobj/read_test.go index cc991e5d9..cc991e5d9 100644 --- a/src/debug/goobj/read_test.go +++ b/src/cmd/internal/goobj/read_test.go diff --git a/src/cmd/internal/objfile/goobj.go b/src/cmd/internal/objfile/goobj.go index a1d773023..6b1607a17 100644 --- a/src/cmd/internal/objfile/goobj.go +++ b/src/cmd/internal/objfile/goobj.go @@ -7,7 +7,7 @@ package objfile import ( - "debug/goobj" + "cmd/internal/goobj" "fmt" "os" ) diff --git a/src/cmd/link/auto.go b/src/cmd/link/auto.go index f9228e8ca..21f6d6082 100644 --- a/src/cmd/link/auto.go +++ b/src/cmd/link/auto.go @@ -10,7 +10,7 @@ package main import ( - "debug/goobj" + "cmd/internal/goobj" "strconv" "strings" ) diff --git a/src/cmd/link/auto_test.go b/src/cmd/link/auto_test.go index 27f8e2b96..f99e097a9 100644 --- a/src/cmd/link/auto_test.go +++ b/src/cmd/link/auto_test.go @@ -13,7 +13,7 @@ package main import ( "bytes" - "debug/goobj" + "cmd/internal/goobj" "testing" ) diff --git a/src/cmd/link/dead.go b/src/cmd/link/dead.go index e1e775eb3..ee23a61f8 100644 --- a/src/cmd/link/dead.go +++ b/src/cmd/link/dead.go @@ -6,7 +6,7 @@ package main -import "debug/goobj" +import "cmd/internal/goobj" // dead removes unreachable code and data from the program. // It is basically a mark-sweep garbage collection: traverse all the diff --git a/src/cmd/link/dead_test.go b/src/cmd/link/dead_test.go index 2e179b453..eb34d0580 100644 --- a/src/cmd/link/dead_test.go +++ b/src/cmd/link/dead_test.go @@ -5,7 +5,7 @@ package main import ( - "debug/goobj" + "cmd/internal/goobj" "reflect" "strings" "testing" diff --git a/src/cmd/link/layout.go b/src/cmd/link/layout.go index 149ebced0..d5c291e25 100644 --- a/src/cmd/link/layout.go +++ b/src/cmd/link/layout.go @@ -7,7 +7,7 @@ package main import ( - "debug/goobj" + "cmd/internal/goobj" ) // A layoutSection describes a single section to add to the diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go index 984796784..b5ae15fc7 100644 --- a/src/cmd/link/link_test.go +++ b/src/cmd/link/link_test.go @@ -6,7 +6,7 @@ package main import ( "bytes" - "debug/goobj" + "cmd/internal/goobj" "io/ioutil" "testing" ) diff --git a/src/cmd/link/pclntab.go b/src/cmd/link/pclntab.go index 232d586bf..2d131781f 100644 --- a/src/cmd/link/pclntab.go +++ b/src/cmd/link/pclntab.go @@ -7,7 +7,7 @@ package main import ( - "debug/goobj" + "cmd/internal/goobj" "encoding/binary" "os" "sort" diff --git a/src/cmd/link/pclntab_test.go b/src/cmd/link/pclntab_test.go index 19953f579..ea8080674 100644 --- a/src/cmd/link/pclntab_test.go +++ b/src/cmd/link/pclntab_test.go @@ -6,7 +6,7 @@ package main import ( "bytes" - "debug/goobj" + "cmd/internal/goobj" "fmt" "math/rand" "sort" diff --git a/src/cmd/link/prog.go b/src/cmd/link/prog.go index a52b5ff9b..77fb1ece5 100644 --- a/src/cmd/link/prog.go +++ b/src/cmd/link/prog.go @@ -5,7 +5,7 @@ package main import ( - "debug/goobj" + "cmd/internal/goobj" "encoding/binary" "fmt" "go/build" diff --git a/src/cmd/link/runtime.go b/src/cmd/link/runtime.go index b0c1ac98a..acda2d24d 100644 --- a/src/cmd/link/runtime.go +++ b/src/cmd/link/runtime.go @@ -7,7 +7,7 @@ package main -import "debug/goobj" +import "cmd/internal/goobj" func (p *Prog) runtime() { p.pclntab() diff --git a/src/cmd/link/scan.go b/src/cmd/link/scan.go index 0720e039b..7feb0d890 100644 --- a/src/cmd/link/scan.go +++ b/src/cmd/link/scan.go @@ -11,7 +11,7 @@ package main import ( - "debug/goobj" + "cmd/internal/goobj" "os" "sort" "strings" @@ -69,7 +69,7 @@ func (p *Prog) scanFile(pkgpath string, file string) { return } - // TODO(rsc): Change debug/goobj to record package name as gp.Name. + // TODO(rsc): Change cmd/internal/goobj to record package name as gp.Name. // TODO(rsc): If pkgpath == "main", check that gp.Name == "main". pkg.Package = gp diff --git a/src/cmd/pprof/internal/report/source.go b/src/cmd/pprof/internal/report/source.go index 57300dd91..73ae1b4ea 100644 --- a/src/cmd/pprof/internal/report/source.go +++ b/src/cmd/pprof/internal/report/source.go @@ -358,9 +358,13 @@ func getFunctionSource(fun, file string, fns nodes, start, end int) (nodes, stri for { line, err := buf.ReadString('\n') if err != nil { - if line == "" || err != io.EOF { + if err != io.EOF { return nil, file, err } + if line == "" { + // end was at or past EOF; that's okay + break + } } if lineno >= start { flat, cum := sumNodes(lineNodes[lineno]) diff --git a/src/crypto/x509/root_unix.go b/src/crypto/x509/root_unix.go index c65f626ac..f77d6c0c5 100644 --- a/src/crypto/x509/root_unix.go +++ b/src/crypto/x509/root_unix.go @@ -16,6 +16,7 @@ var certFiles = []string{ "/etc/ssl/cert.pem", // OpenBSD "/usr/local/share/certs/ca-root-nss.crt", // FreeBSD/DragonFly "/etc/pki/tls/cacert.pem", // OpenELEC + "/etc/certs/ca-certificates.crt", // Solaris 11.2+ } // Possible directories with certificate files; stop after successfully diff --git a/src/go/parser/error_test.go b/src/go/parser/error_test.go index 48fb53e5b..1a08d5a6b 100644 --- a/src/go/parser/error_test.go +++ b/src/go/parser/error_test.go @@ -34,11 +34,9 @@ import ( const testdata = "testdata" -var fsetErrs = token.NewFileSet() - // getFile assumes that each filename occurs at most once -func getFile(filename string) (file *token.File) { - fsetErrs.Iterate(func(f *token.File) bool { +func getFile(fset *token.FileSet, filename string) (file *token.File) { + fset.Iterate(func(f *token.File) bool { if f.Name() == filename { if file != nil { panic(filename + " used multiple times") @@ -50,8 +48,8 @@ func getFile(filename string) (file *token.File) { return file } -func getPos(filename string, offset int) token.Pos { - if f := getFile(filename); f != nil { +func getPos(fset *token.FileSet, filename string, offset int) token.Pos { + if f := getFile(fset, filename); f != nil { return f.Pos(offset) } return token.NoPos @@ -68,14 +66,14 @@ var errRx = regexp.MustCompile(`^/\* *ERROR *(HERE)? *"([^"]*)" *\*/$`) // expectedErrors collects the regular expressions of ERROR comments found // in files and returns them as a map of error positions to error messages. // -func expectedErrors(t *testing.T, filename string, src []byte) map[token.Pos]string { +func expectedErrors(t *testing.T, fset *token.FileSet, filename string, src []byte) map[token.Pos]string { errors := make(map[token.Pos]string) var s scanner.Scanner // file was parsed already - do not add it again to the file // set otherwise the position information returned here will // not match the position information collected by the parser - s.Init(getFile(filename), src, nil, scanner.ScanComments) + s.Init(getFile(fset, filename), src, nil, scanner.ScanComments) var prev token.Pos // position of last non-comment, non-semicolon token var here token.Pos // position immediately after the token at position prev @@ -109,11 +107,11 @@ func expectedErrors(t *testing.T, filename string, src []byte) map[token.Pos]str // compareErrors compares the map of expected error messages with the list // of found errors and reports discrepancies. // -func compareErrors(t *testing.T, expected map[token.Pos]string, found scanner.ErrorList) { +func compareErrors(t *testing.T, fset *token.FileSet, expected map[token.Pos]string, found scanner.ErrorList) { for _, error := range found { // error.Pos is a token.Position, but we want // a token.Pos so we can do a map lookup - pos := getPos(error.Pos.Filename, error.Pos.Offset) + pos := getPos(fset, error.Pos.Filename, error.Pos.Offset) if msg, found := expected[pos]; found { // we expect a message at pos; check if it matches rx, err := regexp.Compile(msg) @@ -140,7 +138,7 @@ func compareErrors(t *testing.T, expected map[token.Pos]string, found scanner.Er if len(expected) > 0 { t.Errorf("%d errors not reported:", len(expected)) for pos, msg := range expected { - t.Errorf("%s: %s\n", fsetErrs.Position(pos), msg) + t.Errorf("%s: %s\n", fset.Position(pos), msg) } } } @@ -152,7 +150,8 @@ func checkErrors(t *testing.T, filename string, input interface{}) { return } - _, err = ParseFile(fsetErrs, filename, src, DeclarationErrors|AllErrors) + fset := token.NewFileSet() + _, err = ParseFile(fset, filename, src, DeclarationErrors|AllErrors) found, ok := err.(scanner.ErrorList) if err != nil && !ok { t.Error(err) @@ -162,10 +161,10 @@ func checkErrors(t *testing.T, filename string, input interface{}) { // we are expecting the following errors // (collect these after parsing a file so that it is found in the file set) - expected := expectedErrors(t, filename, src) + expected := expectedErrors(t, fset, filename, src) // verify errors returned by the parser - compareErrors(t, expected, found) + compareErrors(t, fset, expected, found) } func TestErrors(t *testing.T) { diff --git a/src/go/parser/parser_test.go b/src/go/parser/parser_test.go index 85065fd18..51ce1a933 100644 --- a/src/go/parser/parser_test.go +++ b/src/go/parser/parser_test.go @@ -14,8 +14,6 @@ import ( "testing" ) -var fset = token.NewFileSet() - var validFiles = []string{ "parser.go", "parser_test.go", @@ -25,7 +23,7 @@ var validFiles = []string{ func TestParse(t *testing.T) { for _, filename := range validFiles { - _, err := ParseFile(fset, filename, nil, DeclarationErrors) + _, err := ParseFile(token.NewFileSet(), filename, nil, DeclarationErrors) if err != nil { t.Fatalf("ParseFile(%s): %v", filename, err) } @@ -46,7 +44,7 @@ func dirFilter(f os.FileInfo) bool { return nameFilter(f.Name()) } func TestParseDir(t *testing.T) { path := "." - pkgs, err := ParseDir(fset, path, dirFilter, 0) + pkgs, err := ParseDir(token.NewFileSet(), path, dirFilter, 0) if err != nil { t.Fatalf("ParseDir(%s): %v", path, err) } @@ -131,7 +129,7 @@ func TestParseExpr(t *testing.T) { } func TestColonEqualsScope(t *testing.T) { - f, err := ParseFile(fset, "", `package p; func f() { x, y, z := x, y, z }`, 0) + f, err := ParseFile(token.NewFileSet(), "", `package p; func f() { x, y, z := x, y, z }`, 0) if err != nil { t.Fatal(err) } @@ -153,7 +151,7 @@ func TestColonEqualsScope(t *testing.T) { } func TestVarScope(t *testing.T) { - f, err := ParseFile(fset, "", `package p; func f() { var x, y, z = x, y, z }`, 0) + f, err := ParseFile(token.NewFileSet(), "", `package p; func f() { var x, y, z = x, y, z }`, 0) if err != nil { t.Fatal(err) } @@ -183,7 +181,7 @@ var x int func f() { L: } ` - f, err := ParseFile(fset, "", src, 0) + f, err := ParseFile(token.NewFileSet(), "", src, 0) if err != nil { t.Fatal(err) } @@ -221,7 +219,7 @@ func f() { L: } } func TestUnresolved(t *testing.T) { - f, err := ParseFile(fset, "", ` + f, err := ParseFile(token.NewFileSet(), "", ` package p // func f1a(int) @@ -316,7 +314,7 @@ var imports = map[string]bool{ func TestImports(t *testing.T) { for path, isValid := range imports { src := fmt.Sprintf("package p; import %s", path) - _, err := ParseFile(fset, "", src, 0) + _, err := ParseFile(token.NewFileSet(), "", src, 0) switch { case err != nil && isValid: t.Errorf("ParseFile(%s): got %v; expected no error", src, err) @@ -327,7 +325,7 @@ func TestImports(t *testing.T) { } func TestCommentGroups(t *testing.T) { - f, err := ParseFile(fset, "", ` + f, err := ParseFile(token.NewFileSet(), "", ` package p /* 1a */ /* 1b */ /* 1c */ // 1d /* 2a */ @@ -421,7 +419,7 @@ func checkFieldComments(t *testing.T, file *ast.File, fieldname, lead, line stri } func TestLeadAndLineComments(t *testing.T) { - f, err := ParseFile(fset, "", ` + f, err := ParseFile(token.NewFileSet(), "", ` package p type T struct { /* F1 lead comment */ diff --git a/src/hash/crc32/crc32.go b/src/hash/crc32/crc32.go index a2a21a06f..6a6b9473b 100644 --- a/src/hash/crc32/crc32.go +++ b/src/hash/crc32/crc32.go @@ -17,8 +17,8 @@ const Size = 4 // Predefined polynomials. const ( - // Far and away the most common CRC-32 polynomial. - // Used by ethernet (IEEE 802.3), v.42, fddi, gzip, zip, png, mpeg-2, ... + // IEEE is by far and away the most common CRC-32 polynomial. + // Used by ethernet (IEEE 802.3), v.42, fddi, gzip, zip, png, ... IEEE = 0xedb88320 // Castagnoli's polynomial, used in iSCSI. diff --git a/src/image/jpeg/reader.go b/src/image/jpeg/reader.go index c8fae3cea..6d8b1d1d0 100644 --- a/src/image/jpeg/reader.go +++ b/src/image/jpeg/reader.go @@ -143,6 +143,9 @@ func (d *decoder) fill() error { // Fill in the rest of the buffer. n, err := d.r.Read(d.bytes.buf[d.bytes.j:]) d.bytes.j += n + if n > 0 { + err = nil + } return err } diff --git a/src/image/jpeg/reader_test.go b/src/image/jpeg/reader_test.go index 93f4adab9..4de2e8ee7 100644 --- a/src/image/jpeg/reader_test.go +++ b/src/image/jpeg/reader_test.go @@ -9,6 +9,7 @@ import ( "fmt" "image" "image/color" + "io" "io/ioutil" "math/rand" "os" @@ -88,6 +89,51 @@ func decodeFile(filename string) (image.Image, error) { return Decode(f) } +type eofReader struct { + data []byte // deliver from Read without EOF + dataEOF []byte // then deliver from Read with EOF on last chunk + lenAtEOF int +} + +func (r *eofReader) Read(b []byte) (n int, err error) { + if len(r.data) > 0 { + n = copy(b, r.data) + r.data = r.data[n:] + } else { + n = copy(b, r.dataEOF) + r.dataEOF = r.dataEOF[n:] + if len(r.dataEOF) == 0 { + err = io.EOF + if r.lenAtEOF == -1 { + r.lenAtEOF = n + } + } + } + return +} + +func TestDecodeEOF(t *testing.T) { + // Check that if reader returns final data and EOF at same time, jpeg handles it. + data, err := ioutil.ReadFile("../testdata/video-001.jpeg") + if err != nil { + t.Fatal(err) + } + + n := len(data) + for i := 0; i < n; { + r := &eofReader{data[:n-i], data[n-i:], -1} + _, err := Decode(r) + if err != nil { + t.Errorf("Decode with Read() = %d, EOF: %v", r.lenAtEOF, err) + } + if i == 0 { + i = 1 + } else { + i *= 2 + } + } +} + // check checks that the two pix data are equal, within the given bounds. func check(bounds image.Rectangle, pix0, pix1 []byte, stride0, stride1 int) error { if stride0 <= 0 || stride0%8 != 0 { diff --git a/src/liblink/list6.c b/src/liblink/list6.c index 0635fdf1f..ff22273c4 100644 --- a/src/liblink/list6.c +++ b/src/liblink/list6.c @@ -82,6 +82,19 @@ Pconv(Fmt *fp) p = va_arg(fp->args, Prog*); bigP = p; + + if(fp->flags & FmtSharp) { + char *s = str; + s += sprint(s, "%.5lld (%L) %A", p->pc, p->lineno, p->as); + if(p->from.type != D_NONE) + s += sprint(s, " from={%#D}", &p->from); + if(p->reg) + s += sprint(s, " reg=%d", p->reg); + if(p->to.type != D_NONE) + sprint(s, " to={%#D}", &p->to); + return fmtstrcpy(fp, str); + } + switch(p->as) { case ADATA: sprint(str, "%.5lld (%L) %A %D/%d,%D", @@ -126,6 +139,31 @@ Dconv(Fmt *fp) a = va_arg(fp->args, Addr*); i = a->type; + if(fp->flags & FmtSharp) { + char *s = str; + s += sprint(s, "type="); + if(i == D_NONE) { + sprint(s, "NONE"); + goto brk; + } + if(i >= D_INDIR) { + i -= D_INDIR; + s += sprint(s, "INDIR+"); + } + if(i >= 0 && i < D_LAST && dnames6[i] != nil) + s += sprint(s, "%s ", dnames6[i]); + else + s += sprint(s, "%d ", i); + s += sprint(s, "offset=%lld etype=%E width=%lld", a->offset, a->etype, a->width); + if(a->class != 0) + s += sprint(s, " class=%s", cnames9[(int)a->class]); + if(a->sym != nil) + s += sprint(s, " sym=%s", a->sym->name); + if(a->type == D_BRANCH && a->u.branch != nil) + sprint(s, " branch=%.5lld", a->u.branch->pc); + goto brk; + } + if(fp->flags & FmtLong) { if(i == D_CONST) sprint(str, "$%lld-%lld", a->offset&0xffffffffLL, a->offset>>32); diff --git a/src/liblink/list9.c b/src/liblink/list9.c index 512ed5a11..32fcf8f87 100644 --- a/src/liblink/list9.c +++ b/src/liblink/list9.c @@ -91,6 +91,21 @@ Pconv(Fmt *fp) p = va_arg(fp->args, Prog*); bigP = p; a = p->as; + + if(fp->flags & FmtSharp) { + s = str; + s += sprint(s, "%.5lld (%L) %A", p->pc, p->lineno, a); + if(p->from.type != D_NONE) + s += sprint(s, " from={%#D}", &p->from); + if(p->reg) + s += sprint(s, " reg=%d", p->reg); + if(p->from3.type != D_NONE) + s += sprint(s, " from3={%#D}", &p->from3); + if(p->to.type != D_NONE) + sprint(s, " to={%#D}", &p->to); + return fmtstrcpy(fp, str); + } + if(a == ADATA || a == AINIT || a == ADYNT) sprint(str, "%.5lld (%L) %A %D/%d,%D", p->pc, p->lineno, a, &p->from, p->reg, &p->to); else if(a == ATEXT) { @@ -153,6 +168,32 @@ Dconv(Fmt *fp) a = va_arg(fp->args, Addr*); + if(fp->flags & FmtSharp) { + char *s = str; + if(a->type == D_NONE) { + sprint(s, "type=NONE"); + goto ret; + } + if(a->type >= 0 && a->type < D_LAST && dnames9[a->type] != nil) + s += sprint(s, "type=%s ", dnames9[a->type]); + else + s += sprint(s, "type=%d ", a->type); + if(a->name >= 0 && a->name < D_LAST && dnames9[(int)a->name] != nil) + s += sprint(s, "name=%s ", dnames9[(int)a->name]); + else + s += sprint(s, "name=%d ", a->name); + s += sprint(s, "offset=%lld etype=%E width=%lld", a->offset, a->etype, a->width); + if(a->class != 0) + s += sprint(s, " class=%s", cnames9[(int)a->class]); + if(a->reg != NREG) + s += sprint(s, " reg=%d", a->reg); + if(a->sym != nil) + s += sprint(s, " sym=%s", a->sym->name); + if(a->type == D_BRANCH && a->u.branch != nil) + sprint(s, " branch=%.5lld", a->u.branch->pc); + goto ret; + } + if(fp->flags & FmtLong) { if(a->type == D_CONST) sprint(str, "$%d-%d", (int32)a->offset, (int32)(a->offset>>32)); diff --git a/src/net/http/fs.go b/src/net/http/fs.go index 7bd777b71..e322f710a 100644 --- a/src/net/http/fs.go +++ b/src/net/http/fs.go @@ -22,8 +22,12 @@ import ( "time" ) -// A Dir implements http.FileSystem using the native file -// system restricted to a specific directory tree. +// A Dir implements FileSystem using the native file system restricted to a +// specific directory tree. +// +// While the FileSystem.Open method takes '/'-separated paths, a Dir's string +// value is a filename on the native file system, not a URL, so it is separated +// by filepath.Separator, which isn't necessarily '/'. // // An empty Dir is treated as ".". type Dir string diff --git a/src/net/url/example_test.go b/src/net/url/example_test.go index 56c5dc696..e55c1aa16 100644 --- a/src/net/url/example_test.go +++ b/src/net/url/example_test.go @@ -7,7 +7,10 @@ package url_test import ( "fmt" "log" + "net/http" + "net/http/httputil" "net/url" + "strings" ) func ExampleValues() { @@ -39,3 +42,30 @@ func ExampleURL() { fmt.Println(u) // Output: https://google.com/search?q=golang } + +func ExampleURL_opaque() { + // Sending a literal '%' in an HTTP request's Path + req := &http.Request{ + Method: "GET", + Host: "example.com", // takes precendence over URL.Host + URL: &url.URL{ + Host: "ignored", + Scheme: "https", + Opaque: "/%2f/", + }, + Header: http.Header{ + "User-Agent": {"godoc-example/0.1"}, + }, + } + out, err := httputil.DumpRequestOut(req, true) + if err != nil { + log.Fatal(err) + } + fmt.Println(strings.Replace(string(out), "\r", "", -1)) + // Output: + // GET /%2f/ HTTP/1.1 + // Host: example.com + // User-Agent: godoc-example/0.1 + // Accept-Encoding: gzip + // +} diff --git a/src/regexp/syntax/regexp.go b/src/regexp/syntax/regexp.go index 329a90e01..cea7d9e04 100644 --- a/src/regexp/syntax/regexp.go +++ b/src/regexp/syntax/regexp.go @@ -39,7 +39,7 @@ const ( OpEmptyMatch // matches empty string OpLiteral // matches Runes sequence OpCharClass // matches Runes interpreted as range pair list - OpAnyCharNotNL // matches any character + OpAnyCharNotNL // matches any character except newline OpAnyChar // matches any character OpBeginLine // matches empty string at beginning of line OpEndLine // matches empty string at end of line diff --git a/src/run.bash b/src/run.bash index 54b209591..b8ce417a0 100755 --- a/src/run.bash +++ b/src/run.bash @@ -64,18 +64,6 @@ echo echo '# sync -cpu=10' go test sync -short -timeout=$(expr 120 \* $timeout_scale)s -cpu=10 -# Race detector only supported on Linux, FreeBSD and OS X, -# and only on amd64, and only when cgo is enabled. -# DISABLED until we get garbage collection working. -case "$GOHOSTOS-$GOOS-$GOARCH-$CGO_ENABLED-XXX-DISABLED" in -linux-linux-amd64-1 | freebsd-freebsd-amd64-1 | darwin-darwin-amd64-1) - echo - echo '# Testing race detector.' - go test -race -i runtime/race flag - go test -race -run=Output runtime/race - go test -race -short flag -esac - xcd() { echo echo '#' $1 @@ -121,6 +109,7 @@ go run $GOROOT/test/run.go - . || exit 1 [ "$CGO_ENABLED" != 1 ] || (xcd ../misc/cgo/test # cgo tests inspect the traceback for runtime functions +extlink=0 export GOTRACEBACK=2 go test -ldflags '-linkmode=auto' || exit 1 # linkmode=internal fails on dragonfly since errno is a TLS relocation. @@ -129,19 +118,24 @@ case "$GOHOSTOS-$GOARCH" in openbsd-386 | openbsd-amd64) # test linkmode=external, but __thread not supported, so skip testtls. go test -ldflags '-linkmode=external' || exit 1 + extlink=1 ;; darwin-386 | darwin-amd64) # linkmode=external fails on OS X 10.6 and earlier == Darwin # 10.8 and earlier. case $(uname -r) in [0-9].* | 10.*) ;; - *) go test -ldflags '-linkmode=external' || exit 1;; + *) + go test -ldflags '-linkmode=external' || exit 1 + extlink=1 + ;; esac ;; android-arm | dragonfly-386 | dragonfly-amd64 | freebsd-386 | freebsd-amd64 | freebsd-arm | linux-386 | linux-amd64 | linux-arm | netbsd-386 | netbsd-amd64) go test -ldflags '-linkmode=external' || exit 1 go test -ldflags '-linkmode=auto' ../testtls || exit 1 go test -ldflags '-linkmode=external' ../testtls || exit 1 + extlink=1 case "$GOHOSTOS-$GOARCH" in netbsd-386 | netbsd-amd64) ;; # no static linking @@ -165,6 +159,24 @@ android-arm | dragonfly-386 | dragonfly-amd64 | freebsd-386 | freebsd-amd64 | fr esac ) || exit $? +# Race detector only supported on Linux, FreeBSD and OS X, +# and only on amd64, and only when cgo is enabled. +# Delayed until here so we know whether to try external linking. +# DISABLED until we get garbage collection working. +case "$GOHOSTOS-$GOOS-$GOARCH-$CGO_ENABLED-XXX-DISABLED" in +linux-linux-amd64-1 | freebsd-freebsd-amd64-1 | darwin-darwin-amd64-1) + echo + echo '# Testing race detector.' + go test -race -i runtime/race flag os/exec + go test -race -run=Output runtime/race + go test -race -short flag os/exec + + # Test with external linking; see issue 9133. + if [ "$extlink" = 1 ]; then + go test -race -short -ldflags=-linkmode=external flag os/exec + fi +esac + # This tests cgo -cdefs. That mode is not supported, # so it's okay if it doesn't work on some systems. # In particular, it works badly with clang on OS X. diff --git a/src/run.bat b/src/run.bat index 14c1b45fd..efa97662f 100644 --- a/src/run.bat +++ b/src/run.bat @@ -134,9 +134,11 @@ if %FAIL%==1 goto fail set GOMAXPROCS=%OLDGOMAXPROCS% set OLDGOMAXPROCS= -echo # Checking API compatibility. -go run "%GOROOT%\src\cmd\api\run.go" -if errorlevel 1 goto fail +:: echo # Checking API compatibility. +:: go run "%GOROOT%\src\cmd\api\run.go" +:: if errorlevel 1 goto fail +:: echo. +echo # SKIPPING API COMPATIBILITY UNTIL ALL SYSTEMS BUILD. echo. echo ALL TESTS PASSED diff --git a/src/runtime/arch1_386.go b/src/runtime/arch1_386.go index 7746dfbf0..a73e207ed 100644 --- a/src/runtime/arch1_386.go +++ b/src/runtime/arch1_386.go @@ -9,7 +9,7 @@ const ( _BigEndian = 0 _CacheLineSize = 64 _RuntimeGogoBytes = 64 - _PhysPageSize = _NaCl*65536 + (1-_NaCl)*4096 // 4k normally; 64k on NaCl + _PhysPageSize = goos_nacl*65536 + (1-goos_nacl)*4096 // 4k normally; 64k on NaCl _PCQuantum = 1 _Int64Align = 4 ) diff --git a/src/runtime/arch1_amd64.go b/src/runtime/arch1_amd64.go index 83c9c2dc9..794b7f65c 100644 --- a/src/runtime/arch1_amd64.go +++ b/src/runtime/arch1_amd64.go @@ -8,7 +8,7 @@ const ( thechar = '6' _BigEndian = 0 _CacheLineSize = 64 - _RuntimeGogoBytes = 64 + (_Plan9|_Solaris|_Windows)*16 + _RuntimeGogoBytes = 64 + (goos_plan9|goos_solaris|goos_windows)*16 _PhysPageSize = 4096 _PCQuantum = 1 _Int64Align = 8 diff --git a/src/runtime/arch1_amd64p32.go b/src/runtime/arch1_amd64p32.go new file mode 100644 index 000000000..2cee21f0c --- /dev/null +++ b/src/runtime/arch1_amd64p32.go @@ -0,0 +1,15 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +const ( + thechar = '6' + _BigEndian = 0 + _CacheLineSize = 64 + _RuntimeGogoBytes = 64 + _PhysPageSize = 65536*goos_nacl + 4096*(1-goos_nacl) + _PCQuantum = 1 + _Int64Align = 8 +) diff --git a/src/runtime/arch1_arm.go b/src/runtime/arch1_arm.go index 5cb79fd68..6662eaeac 100644 --- a/src/runtime/arch1_arm.go +++ b/src/runtime/arch1_arm.go @@ -9,7 +9,7 @@ const ( _BigEndian = 0 _CacheLineSize = 32 _RuntimeGogoBytes = 60 - _PhysPageSize = 65536*_NaCl + 4096*(1-_NaCl) + _PhysPageSize = 65536*goos_nacl + 4096*(1-goos_nacl) _PCQuantum = 4 _Int64Align = 4 ) diff --git a/src/runtime/arch1_power64.go b/src/runtime/arch1_power64.go new file mode 100644 index 000000000..01e2b70f9 --- /dev/null +++ b/src/runtime/arch1_power64.go @@ -0,0 +1,15 @@ +// 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 runtime + +const ( + thechar = '9' + _BigEndian = 1 + _CacheLineSize = 64 + _RuntimeGogoBytes = 64 + _PhysPageSize = 65536 + _PCQuantum = 4 + _Int64Align = 8 +) diff --git a/src/runtime/arch1_power64le.go b/src/runtime/arch1_power64le.go new file mode 100644 index 000000000..6580732a3 --- /dev/null +++ b/src/runtime/arch1_power64le.go @@ -0,0 +1,15 @@ +// 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 runtime + +const ( + thechar = '9' + _BigEndian = 0 + _CacheLineSize = 64 + _RuntimeGogoBytes = 64 + _PhysPageSize = 65536 + _PCQuantum = 4 + _Int64Align = 8 +) diff --git a/src/runtime/arch_amd64p32.h b/src/runtime/arch_amd64p32.h deleted file mode 100644 index d3e864987..000000000 --- a/src/runtime/arch_amd64p32.h +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -enum { - thechar = '6', - BigEndian = 0, - CacheLineSize = 64, - RuntimeGogoBytes = 64, -#ifdef GOOS_nacl - PhysPageSize = 65536, -#else - PhysPageSize = 4096, -#endif - PCQuantum = 1, - Int64Align = 8 -}; diff --git a/src/runtime/arch_power64.h b/src/runtime/arch_power64.h deleted file mode 100644 index 7cfb9da2f..000000000 --- a/src/runtime/arch_power64.h +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -enum { - thechar = '9', - BigEndian = 1, - CacheLineSize = 64, - RuntimeGogoBytes = 64, - PhysPageSize = 65536, - PCQuantum = 4, - Int64Align = 8 -}; - diff --git a/src/runtime/asm_amd64p32.s b/src/runtime/asm_amd64p32.s index 60c438c1d..c87d848fe 100644 --- a/src/runtime/asm_amd64p32.s +++ b/src/runtime/asm_amd64p32.s @@ -169,7 +169,7 @@ TEXT runtime·mcall(SB), NOSPLIT, $0-4 // of the G stack. We need to distinguish the routine that // lives at the bottom of the G stack from the one that lives // at the top of the system stack because the one at the top of -// the M stack terminates the stack walk (see topofstack()). +// the system stack terminates the stack walk (see topofstack()). TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0 RET diff --git a/src/runtime/asm_power64x.s b/src/runtime/asm_power64x.s index 6169202ea..548c88e47 100644 --- a/src/runtime/asm_power64x.s +++ b/src/runtime/asm_power64x.s @@ -4,7 +4,8 @@ // +build power64 power64le -#include "zasm_GOOS_GOARCH.h" +#include "go_asm.h" +#include "go_tls.h" #include "funcdata.h" #include "textflag.h" @@ -144,58 +145,44 @@ TEXT runtime·mcall(SB), NOSPLIT, $-8-8 BL (CTR) BR runtime·badmcall2(SB) -// switchtoM is a dummy routine that onM leaves at the bottom +// systemstack_switch is a dummy routine that systemstack leaves at the bottom // of the G stack. We need to distinguish the routine that // lives at the bottom of the G stack from the one that lives -// at the top of the M stack because the one at the top of -// the M stack terminates the stack walk (see topofstack()). -TEXT runtime·switchtoM(SB), NOSPLIT, $0-0 +// at the top of the system stack because the one at the top of +// the system stack terminates the stack walk (see topofstack()). +TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0 UNDEF BL (LR) // make sure this function is not leaf RETURN -// func onM_signalok(fn func()) -TEXT runtime·onM_signalok(SB), NOSPLIT, $8-8 - MOVD g, R3 // R3 = g - MOVD g_m(R3), R4 // R4 = g->m - MOVD m_gsignal(R4), R4 // R4 = g->m->gsignal - MOVD fn+0(FP), R11 // context for call below - CMP R3, R4 - BEQ onsignal - MOVD R11, 8(R1) - BL runtime·onM(SB) - RETURN - -onsignal: - MOVD 0(R11), R3 // code pointer - MOVD R3, CTR - BL (CTR) - RETURN - -// void onM(fn func()) -TEXT runtime·onM(SB), NOSPLIT, $0-8 +// func systemstack(fn func()) +TEXT runtime·systemstack(SB), NOSPLIT, $0-8 MOVD fn+0(FP), R3 // R3 = fn MOVD R3, R11 // context MOVD g_m(g), R4 // R4 = m + MOVD m_gsignal(R4), R5 // R5 = gsignal + CMP g, R5 + BEQ noswitch + MOVD m_g0(R4), R5 // R5 = g0 CMP g, R5 - BEQ onm + BEQ noswitch MOVD m_curg(R4), R6 CMP g, R6 - BEQ oncurg + BEQ switch - // Not g0, not curg. Must be gsignal, but that's not allowed. + // Bad: g is not gsignal, not g0, not curg. What is it? // Hide call from linker nosplit analysis. - MOVD $runtime·badonm(SB), R3 + MOVD $runtime·badsystemstack(SB), R3 MOVD R3, CTR BL (CTR) -oncurg: +switch: // save our state in g->sched. Pretend to - // be switchtoM if the G stack is scanned. - MOVD $runtime·switchtoM(SB), R6 + // be systemstack_switch if the G stack is scanned. + MOVD $runtime·systemstack_switch(SB), R6 ADD $8, R6 // get past prologue MOVD R6, (g_sched+gobuf_pc)(g) MOVD R1, (g_sched+gobuf_sp)(g) @@ -205,7 +192,7 @@ oncurg: // switch to g0 MOVD R5, g MOVD (g_sched+gobuf_sp)(g), R3 - // make it look like mstart called onM on g0, to stop traceback + // make it look like mstart called systemstack on g0, to stop traceback SUB $8, R3 MOVD $runtime·mstart(SB), R4 MOVD R4, 0(R3) @@ -223,7 +210,7 @@ oncurg: MOVD R0, (g_sched+gobuf_sp)(g) RETURN -onm: +noswitch: // already on m stack, just call directly MOVD 0(R11), R3 // code pointer MOVD R3, CTR @@ -987,6 +974,10 @@ TEXT runtime·goexit(SB),NOSPLIT,$-8-0 MOVD R0, R0 // NOP BL runtime·goexit1(SB) // does not return +TEXT runtime·getg(SB),NOSPLIT,$-8-8 + MOVD g, ret+0(FP) + RETURN + TEXT runtime·prefetcht0(SB),NOSPLIT,$0-8 RETURN diff --git a/src/runtime/atomic_power64x.go b/src/runtime/atomic_power64x.go new file mode 100644 index 000000000..a0dcf514b --- /dev/null +++ b/src/runtime/atomic_power64x.go @@ -0,0 +1,69 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build power64 power64le + +package runtime + +import "unsafe" + +//go:noescape +func xadd(ptr *uint32, delta int32) uint32 + +//go:noescape +func xadd64(ptr *uint64, delta int64) uint64 + +//go:noescape +func xchg(ptr *uint32, new uint32) uint32 + +//go:noescape +func xchg64(ptr *uint64, new uint64) uint64 + +// xchgp cannot have a go:noescape annotation, because +// while ptr does not escape, new does. If new is marked as +// not escaping, the compiler will make incorrect escape analysis +// decisions about the value being xchg'ed. +// Instead, make xchgp a wrapper around the actual atomic. +// When calling the wrapper we mark ptr as noescape explicitly. + +//go:nosplit +func xchgp(ptr unsafe.Pointer, new unsafe.Pointer) unsafe.Pointer { + return xchgp1(noescape(ptr), new) +} + +func xchgp1(ptr unsafe.Pointer, new unsafe.Pointer) unsafe.Pointer + +//go:noescape +func xchguintptr(ptr *uintptr, new uintptr) uintptr + +//go:noescape +func atomicload(ptr *uint32) uint32 + +//go:noescape +func atomicload64(ptr *uint64) uint64 + +//go:noescape +func atomicloadp(ptr unsafe.Pointer) unsafe.Pointer + +//go:noescape +func atomicor8(ptr *uint8, val uint8) + +//go:noescape +func cas64(ptr *uint64, old, new uint64) bool + +//go:noescape +func atomicstore(ptr *uint32, val uint32) + +//go:noescape +func atomicstore64(ptr *uint64, val uint64) + +// atomicstorep cannot have a go:noescape annotation. +// See comment above for xchgp. + +//go:nosplit +func atomicstorep(ptr unsafe.Pointer, new unsafe.Pointer) { + atomicstorep1(noescape(ptr), new) +} + +func atomicstorep1(ptr unsafe.Pointer, val unsafe.Pointer) diff --git a/src/runtime/chan.go b/src/runtime/chan.go index bb0110f94..330422ad0 100644 --- a/src/runtime/chan.go +++ b/src/runtime/chan.go @@ -630,6 +630,7 @@ func (q *waitq) dequeue() *sudog { return nil } q.first = sgp.next + sgp.next = nil if q.last == sgp { q.last = nil } diff --git a/src/runtime/defs1_netbsd_386.go b/src/runtime/defs1_netbsd_386.go index e39fd04c7..f222bed99 100644 --- a/src/runtime/defs1_netbsd_386.go +++ b/src/runtime/defs1_netbsd_386.go @@ -84,8 +84,8 @@ const ( ) type sigaltstackt struct { - ss_sp *byte - ss_size uint32 + ss_sp uintptr + ss_size uintptr ss_flags int32 } @@ -101,8 +101,8 @@ type siginfo struct { } type stackt struct { - ss_sp *byte - ss_size uint32 + ss_sp uintptr + ss_size uintptr ss_flags int32 } @@ -111,18 +111,30 @@ type timespec struct { tv_nsec int32 } +func (ts *timespec) set_sec(x int32) { + ts.tv_sec = int64(x) +} + +func (ts *timespec) set_nsec(x int32) { + ts.tv_nsec = x +} + type timeval struct { tv_sec int64 tv_usec int32 } +func (tv *timeval) set_usec(x int32) { + tv.tv_usec = x +} + type itimerval struct { it_interval timeval it_value timeval } type mcontextt struct { - __gregs [19]int32 + __gregs [19]uint32 __fpregs [644]byte _mc_tlsbase int32 } diff --git a/src/runtime/defs1_netbsd_amd64.go b/src/runtime/defs1_netbsd_amd64.go index cca701e5b..c2bde4dab 100644 --- a/src/runtime/defs1_netbsd_amd64.go +++ b/src/runtime/defs1_netbsd_amd64.go @@ -84,8 +84,8 @@ const ( ) type sigaltstackt struct { - ss_sp *byte - ss_size uint64 + ss_sp uintptr + ss_size uintptr ss_flags int32 pad_cgo_0 [4]byte } @@ -103,8 +103,8 @@ type siginfo struct { } type stackt struct { - ss_sp *byte - ss_size uint64 + ss_sp uintptr + ss_size uintptr ss_flags int32 pad_cgo_0 [4]byte } @@ -114,12 +114,24 @@ type timespec struct { tv_nsec int64 } +func (ts *timespec) set_sec(x int32) { + ts.tv_sec = int64(x) +} + +func (ts *timespec) set_nsec(x int32) { + ts.tv_nsec = int64(x) +} + type timeval struct { tv_sec int64 tv_usec int32 pad_cgo_0 [4]byte } +func (tv *timeval) set_usec(x int32) { + tv.tv_usec = x +} + type itimerval struct { it_interval timeval it_value timeval diff --git a/src/runtime/defs_linux_386.go b/src/runtime/defs_linux_386.go index ddf592c91..f55924b61 100644 --- a/src/runtime/defs_linux_386.go +++ b/src/runtime/defs_linux_386.go @@ -155,10 +155,11 @@ type sigactiont struct { } type siginfo struct { - si_signo int32 - si_errno int32 - si_code int32 - _sifields [116]byte + si_signo int32 + si_errno int32 + si_code int32 + // below here is a union; si_addr is the only field we use + si_addr uint32 } type sigaltstackt struct { diff --git a/src/runtime/defs_linux_amd64.go b/src/runtime/defs_linux_amd64.go index 7f8f5816c..a73f47514 100644 --- a/src/runtime/defs_linux_amd64.go +++ b/src/runtime/defs_linux_amd64.go @@ -117,11 +117,11 @@ type sigactiont struct { } type siginfo struct { - si_signo int32 - si_errno int32 - si_code int32 - pad_cgo_0 [4]byte - _sifields [112]byte + si_signo int32 + si_errno int32 + si_code int32 + // below here is a union; si_addr is the only field we use + si_addr uint64 } type itimerval struct { diff --git a/src/runtime/defs_linux_arm.go b/src/runtime/defs_linux_arm.go index a874b1594..c3a6e2f01 100644 --- a/src/runtime/defs_linux_arm.go +++ b/src/runtime/defs_linux_arm.go @@ -147,10 +147,11 @@ type itimerval struct { } type siginfo struct { - si_signo int32 - si_errno int32 - si_code int32 - _sifields [4]uint8 + si_signo int32 + si_errno int32 + si_code int32 + // below here is a union; si_addr is the only field we use + si_addr uint32 } type sigactiont struct { diff --git a/src/runtime/defs_linux_power64.go b/src/runtime/defs_linux_power64.go new file mode 100644 index 000000000..f90b84874 --- /dev/null +++ b/src/runtime/defs_linux_power64.go @@ -0,0 +1,198 @@ +// created by cgo -cdefs and then converted to Go +// cgo -cdefs defs_linux.go defs3_linux.go + +package runtime + +const ( + _EINTR = 0x4 + _EAGAIN = 0xb + _ENOMEM = 0xc + + _PROT_NONE = 0x0 + _PROT_READ = 0x1 + _PROT_WRITE = 0x2 + _PROT_EXEC = 0x4 + + _MAP_ANON = 0x20 + _MAP_PRIVATE = 0x2 + _MAP_FIXED = 0x10 + + _MADV_DONTNEED = 0x4 + + _SA_RESTART = 0x10000000 + _SA_ONSTACK = 0x8000000 + _SA_SIGINFO = 0x4 + + _SIGHUP = 0x1 + _SIGINT = 0x2 + _SIGQUIT = 0x3 + _SIGILL = 0x4 + _SIGTRAP = 0x5 + _SIGABRT = 0x6 + _SIGBUS = 0x7 + _SIGFPE = 0x8 + _SIGKILL = 0x9 + _SIGUSR1 = 0xa + _SIGSEGV = 0xb + _SIGUSR2 = 0xc + _SIGPIPE = 0xd + _SIGALRM = 0xe + _SIGSTKFLT = 0x10 + _SIGCHLD = 0x11 + _SIGCONT = 0x12 + _SIGSTOP = 0x13 + _SIGTSTP = 0x14 + _SIGTTIN = 0x15 + _SIGTTOU = 0x16 + _SIGURG = 0x17 + _SIGXCPU = 0x18 + _SIGXFSZ = 0x19 + _SIGVTALRM = 0x1a + _SIGPROF = 0x1b + _SIGWINCH = 0x1c + _SIGIO = 0x1d + _SIGPWR = 0x1e + _SIGSYS = 0x1f + + _FPE_INTDIV = 0x1 + _FPE_INTOVF = 0x2 + _FPE_FLTDIV = 0x3 + _FPE_FLTOVF = 0x4 + _FPE_FLTUND = 0x5 + _FPE_FLTRES = 0x6 + _FPE_FLTINV = 0x7 + _FPE_FLTSUB = 0x8 + + _BUS_ADRALN = 0x1 + _BUS_ADRERR = 0x2 + _BUS_OBJERR = 0x3 + + _SEGV_MAPERR = 0x1 + _SEGV_ACCERR = 0x2 + + _ITIMER_REAL = 0x0 + _ITIMER_VIRTUAL = 0x1 + _ITIMER_PROF = 0x2 + + _EPOLLIN = 0x1 + _EPOLLOUT = 0x4 + _EPOLLERR = 0x8 + _EPOLLHUP = 0x10 + _EPOLLRDHUP = 0x2000 + _EPOLLET = 0x80000000 + _EPOLL_CLOEXEC = 0x80000 + _EPOLL_CTL_ADD = 0x1 + _EPOLL_CTL_DEL = 0x2 + _EPOLL_CTL_MOD = 0x3 +) + +//struct Sigset { +// uint64 sig[1]; +//}; +//typedef uint64 Sigset; + +type timespec struct { + tv_sec int64 + tv_nsec int64 +} + +func (ts *timespec) set_sec(x int64) { + ts.tv_sec = x +} + +func (ts *timespec) set_nsec(x int32) { + ts.tv_nsec = int64(x) +} + +type timeval struct { + tv_sec int64 + tv_usec int64 +} + +func (tv *timeval) set_usec(x int32) { + tv.tv_usec = int64(x) +} + +type sigactiont struct { + sa_handler uintptr + sa_flags uint64 + sa_restorer uintptr + sa_mask uint64 +} + +type siginfo struct { + si_signo int32 + si_errno int32 + si_code int32 + // below here is a union; si_addr is the only field we use + si_addr uint64 +} + +type itimerval struct { + it_interval timeval + it_value timeval +} + +type epollevent struct { + events uint32 + pad_cgo_0 [4]byte + data [8]byte // unaligned uintptr +} + +// created by cgo -cdefs and then converted to Go +// cgo -cdefs defs_linux.go defs3_linux.go + +const ( + _O_RDONLY = 0x0 + _O_CLOEXEC = 0x80000 + _SA_RESTORER = 0 +) + +type ptregs struct { + gpr [32]uint64 + nip uint64 + msr uint64 + orig_gpr3 uint64 + ctr uint64 + link uint64 + xer uint64 + ccr uint64 + softe uint64 + trap uint64 + dar uint64 + dsisr uint64 + result uint64 +} + +type vreg struct { + u [4]uint32 +} + +type sigaltstackt struct { + ss_sp *byte + ss_flags int32 + pad_cgo_0 [4]byte + ss_size uintptr +} + +type sigcontext struct { + _unused [4]uint64 + signal int32 + _pad0 int32 + handler uint64 + oldmask uint64 + regs *ptregs + gp_regs [48]uint64 + fp_regs [33]float64 + v_regs *vreg + vmx_reserve [101]int64 +} + +type ucontext struct { + uc_flags uint64 + uc_link *ucontext + uc_stack sigaltstackt + uc_sigmask uint64 + __unused [15]uint64 + uc_mcontext sigcontext +} diff --git a/src/runtime/defs_linux_power64.h b/src/runtime/defs_linux_power64.h deleted file mode 100644 index 93742fa34..000000000 --- a/src/runtime/defs_linux_power64.h +++ /dev/null @@ -1,204 +0,0 @@ -// Created by cgo -cdefs - DO NOT EDIT -// cgo -cdefs defs_linux.go defs3_linux.go - - -enum { - EINTR = 0x4, - EAGAIN = 0xb, - ENOMEM = 0xc, - - PROT_NONE = 0x0, - PROT_READ = 0x1, - PROT_WRITE = 0x2, - PROT_EXEC = 0x4, - - MAP_ANON = 0x20, - MAP_PRIVATE = 0x2, - MAP_FIXED = 0x10, - - MADV_DONTNEED = 0x4, - - SA_RESTART = 0x10000000, - SA_ONSTACK = 0x8000000, - SA_SIGINFO = 0x4, - - SIGHUP = 0x1, - SIGINT = 0x2, - SIGQUIT = 0x3, - SIGILL = 0x4, - SIGTRAP = 0x5, - SIGABRT = 0x6, - SIGBUS = 0x7, - SIGFPE = 0x8, - SIGKILL = 0x9, - SIGUSR1 = 0xa, - SIGSEGV = 0xb, - SIGUSR2 = 0xc, - SIGPIPE = 0xd, - SIGALRM = 0xe, - SIGSTKFLT = 0x10, - SIGCHLD = 0x11, - SIGCONT = 0x12, - SIGSTOP = 0x13, - SIGTSTP = 0x14, - SIGTTIN = 0x15, - SIGTTOU = 0x16, - SIGURG = 0x17, - SIGXCPU = 0x18, - SIGXFSZ = 0x19, - SIGVTALRM = 0x1a, - SIGPROF = 0x1b, - SIGWINCH = 0x1c, - SIGIO = 0x1d, - SIGPWR = 0x1e, - SIGSYS = 0x1f, - - FPE_INTDIV = 0x1, - FPE_INTOVF = 0x2, - FPE_FLTDIV = 0x3, - FPE_FLTOVF = 0x4, - FPE_FLTUND = 0x5, - FPE_FLTRES = 0x6, - FPE_FLTINV = 0x7, - FPE_FLTSUB = 0x8, - - BUS_ADRALN = 0x1, - BUS_ADRERR = 0x2, - BUS_OBJERR = 0x3, - - SEGV_MAPERR = 0x1, - SEGV_ACCERR = 0x2, - - ITIMER_REAL = 0x0, - ITIMER_VIRTUAL = 0x1, - ITIMER_PROF = 0x2, - - EPOLLIN = 0x1, - EPOLLOUT = 0x4, - EPOLLERR = 0x8, - EPOLLHUP = 0x10, - EPOLLRDHUP = 0x2000, - EPOLLET = -0x80000000, - EPOLL_CLOEXEC = 0x80000, - EPOLL_CTL_ADD = 0x1, - EPOLL_CTL_DEL = 0x2, - EPOLL_CTL_MOD = 0x3, -}; - -typedef struct Sigset Sigset; -typedef struct Timespec Timespec; -typedef struct Timeval Timeval; -typedef struct SigactionT SigactionT; -typedef struct Siginfo Siginfo; -typedef struct Itimerval Itimerval; -typedef struct EpollEvent EpollEvent; - -#pragma pack on - -//struct Sigset { -// uint64 sig[1]; -//}; -//typedef uint64 Sigset; - -struct Timespec { - int64 tv_sec; - int64 tv_nsec; -}; -struct Timeval { - int64 tv_sec; - int64 tv_usec; -}; -struct SigactionT { - void *sa_handler; - uint64 sa_flags; - void *sa_restorer; - uint64 sa_mask; -}; -struct Siginfo { - int32 si_signo; - int32 si_errno; - int32 si_code; - byte Pad_cgo_0[4]; - byte _sifields[112]; -}; -struct Itimerval { - Timeval it_interval; - Timeval it_value; -}; -struct EpollEvent { - uint32 events; - byte Pad_cgo_0[4]; - byte data[8]; // unaligned uintptr -}; - - -#pragma pack off -// Created by cgo -cdefs - DO NOT EDIT -// cgo -cdefs defs_linux.go defs3_linux.go - - -enum { - O_RDONLY = 0x0, - O_CLOEXEC = 0x80000, - SA_RESTORER = 0, -}; - -typedef struct Ptregs Ptregs; -typedef struct Vreg Vreg; -typedef struct SigaltstackT SigaltstackT; -typedef struct Sigcontext Sigcontext; -typedef struct Ucontext Ucontext; - -#pragma pack on - -struct Ptregs { - uint64 gpr[32]; - uint64 nip; - uint64 msr; - uint64 orig_gpr3; - uint64 ctr; - uint64 link; - uint64 xer; - uint64 ccr; - uint64 softe; - uint64 trap; - uint64 dar; - uint64 dsisr; - uint64 result; -}; -typedef uint64 Gregset[48]; -typedef float64 FPregset[33]; -struct Vreg { - uint32 u[4]; -}; - -struct SigaltstackT { - byte *ss_sp; - int32 ss_flags; - byte Pad_cgo_0[4]; - uint64 ss_size; -}; - -struct Sigcontext { - uint64 _unused[4]; - int32 signal; - int32 _pad0; - uint64 handler; - uint64 oldmask; - Ptregs *regs; - uint64 gp_regs[48]; - float64 fp_regs[33]; - Vreg *v_regs; - int64 vmx_reserve[101]; -}; -struct Ucontext { - uint64 uc_flags; - Ucontext *uc_link; - SigaltstackT uc_stack; - uint64 uc_sigmask; - uint64 __unused[15]; - Sigcontext uc_mcontext; -}; - - -#pragma pack off diff --git a/src/runtime/defs_linux_power64le.go b/src/runtime/defs_linux_power64le.go new file mode 100644 index 000000000..f90b84874 --- /dev/null +++ b/src/runtime/defs_linux_power64le.go @@ -0,0 +1,198 @@ +// created by cgo -cdefs and then converted to Go +// cgo -cdefs defs_linux.go defs3_linux.go + +package runtime + +const ( + _EINTR = 0x4 + _EAGAIN = 0xb + _ENOMEM = 0xc + + _PROT_NONE = 0x0 + _PROT_READ = 0x1 + _PROT_WRITE = 0x2 + _PROT_EXEC = 0x4 + + _MAP_ANON = 0x20 + _MAP_PRIVATE = 0x2 + _MAP_FIXED = 0x10 + + _MADV_DONTNEED = 0x4 + + _SA_RESTART = 0x10000000 + _SA_ONSTACK = 0x8000000 + _SA_SIGINFO = 0x4 + + _SIGHUP = 0x1 + _SIGINT = 0x2 + _SIGQUIT = 0x3 + _SIGILL = 0x4 + _SIGTRAP = 0x5 + _SIGABRT = 0x6 + _SIGBUS = 0x7 + _SIGFPE = 0x8 + _SIGKILL = 0x9 + _SIGUSR1 = 0xa + _SIGSEGV = 0xb + _SIGUSR2 = 0xc + _SIGPIPE = 0xd + _SIGALRM = 0xe + _SIGSTKFLT = 0x10 + _SIGCHLD = 0x11 + _SIGCONT = 0x12 + _SIGSTOP = 0x13 + _SIGTSTP = 0x14 + _SIGTTIN = 0x15 + _SIGTTOU = 0x16 + _SIGURG = 0x17 + _SIGXCPU = 0x18 + _SIGXFSZ = 0x19 + _SIGVTALRM = 0x1a + _SIGPROF = 0x1b + _SIGWINCH = 0x1c + _SIGIO = 0x1d + _SIGPWR = 0x1e + _SIGSYS = 0x1f + + _FPE_INTDIV = 0x1 + _FPE_INTOVF = 0x2 + _FPE_FLTDIV = 0x3 + _FPE_FLTOVF = 0x4 + _FPE_FLTUND = 0x5 + _FPE_FLTRES = 0x6 + _FPE_FLTINV = 0x7 + _FPE_FLTSUB = 0x8 + + _BUS_ADRALN = 0x1 + _BUS_ADRERR = 0x2 + _BUS_OBJERR = 0x3 + + _SEGV_MAPERR = 0x1 + _SEGV_ACCERR = 0x2 + + _ITIMER_REAL = 0x0 + _ITIMER_VIRTUAL = 0x1 + _ITIMER_PROF = 0x2 + + _EPOLLIN = 0x1 + _EPOLLOUT = 0x4 + _EPOLLERR = 0x8 + _EPOLLHUP = 0x10 + _EPOLLRDHUP = 0x2000 + _EPOLLET = 0x80000000 + _EPOLL_CLOEXEC = 0x80000 + _EPOLL_CTL_ADD = 0x1 + _EPOLL_CTL_DEL = 0x2 + _EPOLL_CTL_MOD = 0x3 +) + +//struct Sigset { +// uint64 sig[1]; +//}; +//typedef uint64 Sigset; + +type timespec struct { + tv_sec int64 + tv_nsec int64 +} + +func (ts *timespec) set_sec(x int64) { + ts.tv_sec = x +} + +func (ts *timespec) set_nsec(x int32) { + ts.tv_nsec = int64(x) +} + +type timeval struct { + tv_sec int64 + tv_usec int64 +} + +func (tv *timeval) set_usec(x int32) { + tv.tv_usec = int64(x) +} + +type sigactiont struct { + sa_handler uintptr + sa_flags uint64 + sa_restorer uintptr + sa_mask uint64 +} + +type siginfo struct { + si_signo int32 + si_errno int32 + si_code int32 + // below here is a union; si_addr is the only field we use + si_addr uint64 +} + +type itimerval struct { + it_interval timeval + it_value timeval +} + +type epollevent struct { + events uint32 + pad_cgo_0 [4]byte + data [8]byte // unaligned uintptr +} + +// created by cgo -cdefs and then converted to Go +// cgo -cdefs defs_linux.go defs3_linux.go + +const ( + _O_RDONLY = 0x0 + _O_CLOEXEC = 0x80000 + _SA_RESTORER = 0 +) + +type ptregs struct { + gpr [32]uint64 + nip uint64 + msr uint64 + orig_gpr3 uint64 + ctr uint64 + link uint64 + xer uint64 + ccr uint64 + softe uint64 + trap uint64 + dar uint64 + dsisr uint64 + result uint64 +} + +type vreg struct { + u [4]uint32 +} + +type sigaltstackt struct { + ss_sp *byte + ss_flags int32 + pad_cgo_0 [4]byte + ss_size uintptr +} + +type sigcontext struct { + _unused [4]uint64 + signal int32 + _pad0 int32 + handler uint64 + oldmask uint64 + regs *ptregs + gp_regs [48]uint64 + fp_regs [33]float64 + v_regs *vreg + vmx_reserve [101]int64 +} + +type ucontext struct { + uc_flags uint64 + uc_link *ucontext + uc_stack sigaltstackt + uc_sigmask uint64 + __unused [15]uint64 + uc_mcontext sigcontext +} diff --git a/src/runtime/defs_linux_power64le.h b/src/runtime/defs_linux_power64le.h deleted file mode 100644 index 93742fa34..000000000 --- a/src/runtime/defs_linux_power64le.h +++ /dev/null @@ -1,204 +0,0 @@ -// Created by cgo -cdefs - DO NOT EDIT -// cgo -cdefs defs_linux.go defs3_linux.go - - -enum { - EINTR = 0x4, - EAGAIN = 0xb, - ENOMEM = 0xc, - - PROT_NONE = 0x0, - PROT_READ = 0x1, - PROT_WRITE = 0x2, - PROT_EXEC = 0x4, - - MAP_ANON = 0x20, - MAP_PRIVATE = 0x2, - MAP_FIXED = 0x10, - - MADV_DONTNEED = 0x4, - - SA_RESTART = 0x10000000, - SA_ONSTACK = 0x8000000, - SA_SIGINFO = 0x4, - - SIGHUP = 0x1, - SIGINT = 0x2, - SIGQUIT = 0x3, - SIGILL = 0x4, - SIGTRAP = 0x5, - SIGABRT = 0x6, - SIGBUS = 0x7, - SIGFPE = 0x8, - SIGKILL = 0x9, - SIGUSR1 = 0xa, - SIGSEGV = 0xb, - SIGUSR2 = 0xc, - SIGPIPE = 0xd, - SIGALRM = 0xe, - SIGSTKFLT = 0x10, - SIGCHLD = 0x11, - SIGCONT = 0x12, - SIGSTOP = 0x13, - SIGTSTP = 0x14, - SIGTTIN = 0x15, - SIGTTOU = 0x16, - SIGURG = 0x17, - SIGXCPU = 0x18, - SIGXFSZ = 0x19, - SIGVTALRM = 0x1a, - SIGPROF = 0x1b, - SIGWINCH = 0x1c, - SIGIO = 0x1d, - SIGPWR = 0x1e, - SIGSYS = 0x1f, - - FPE_INTDIV = 0x1, - FPE_INTOVF = 0x2, - FPE_FLTDIV = 0x3, - FPE_FLTOVF = 0x4, - FPE_FLTUND = 0x5, - FPE_FLTRES = 0x6, - FPE_FLTINV = 0x7, - FPE_FLTSUB = 0x8, - - BUS_ADRALN = 0x1, - BUS_ADRERR = 0x2, - BUS_OBJERR = 0x3, - - SEGV_MAPERR = 0x1, - SEGV_ACCERR = 0x2, - - ITIMER_REAL = 0x0, - ITIMER_VIRTUAL = 0x1, - ITIMER_PROF = 0x2, - - EPOLLIN = 0x1, - EPOLLOUT = 0x4, - EPOLLERR = 0x8, - EPOLLHUP = 0x10, - EPOLLRDHUP = 0x2000, - EPOLLET = -0x80000000, - EPOLL_CLOEXEC = 0x80000, - EPOLL_CTL_ADD = 0x1, - EPOLL_CTL_DEL = 0x2, - EPOLL_CTL_MOD = 0x3, -}; - -typedef struct Sigset Sigset; -typedef struct Timespec Timespec; -typedef struct Timeval Timeval; -typedef struct SigactionT SigactionT; -typedef struct Siginfo Siginfo; -typedef struct Itimerval Itimerval; -typedef struct EpollEvent EpollEvent; - -#pragma pack on - -//struct Sigset { -// uint64 sig[1]; -//}; -//typedef uint64 Sigset; - -struct Timespec { - int64 tv_sec; - int64 tv_nsec; -}; -struct Timeval { - int64 tv_sec; - int64 tv_usec; -}; -struct SigactionT { - void *sa_handler; - uint64 sa_flags; - void *sa_restorer; - uint64 sa_mask; -}; -struct Siginfo { - int32 si_signo; - int32 si_errno; - int32 si_code; - byte Pad_cgo_0[4]; - byte _sifields[112]; -}; -struct Itimerval { - Timeval it_interval; - Timeval it_value; -}; -struct EpollEvent { - uint32 events; - byte Pad_cgo_0[4]; - byte data[8]; // unaligned uintptr -}; - - -#pragma pack off -// Created by cgo -cdefs - DO NOT EDIT -// cgo -cdefs defs_linux.go defs3_linux.go - - -enum { - O_RDONLY = 0x0, - O_CLOEXEC = 0x80000, - SA_RESTORER = 0, -}; - -typedef struct Ptregs Ptregs; -typedef struct Vreg Vreg; -typedef struct SigaltstackT SigaltstackT; -typedef struct Sigcontext Sigcontext; -typedef struct Ucontext Ucontext; - -#pragma pack on - -struct Ptregs { - uint64 gpr[32]; - uint64 nip; - uint64 msr; - uint64 orig_gpr3; - uint64 ctr; - uint64 link; - uint64 xer; - uint64 ccr; - uint64 softe; - uint64 trap; - uint64 dar; - uint64 dsisr; - uint64 result; -}; -typedef uint64 Gregset[48]; -typedef float64 FPregset[33]; -struct Vreg { - uint32 u[4]; -}; - -struct SigaltstackT { - byte *ss_sp; - int32 ss_flags; - byte Pad_cgo_0[4]; - uint64 ss_size; -}; - -struct Sigcontext { - uint64 _unused[4]; - int32 signal; - int32 _pad0; - uint64 handler; - uint64 oldmask; - Ptregs *regs; - uint64 gp_regs[48]; - float64 fp_regs[33]; - Vreg *v_regs; - int64 vmx_reserve[101]; -}; -struct Ucontext { - uint64 uc_flags; - Ucontext *uc_link; - SigaltstackT uc_stack; - uint64 uc_sigmask; - uint64 __unused[15]; - Sigcontext uc_mcontext; -}; - - -#pragma pack off diff --git a/src/runtime/defs_plan9_386.go b/src/runtime/defs_plan9_386.go index 170506b23..212ecdf14 100644 --- a/src/runtime/defs_plan9_386.go +++ b/src/runtime/defs_plan9_386.go @@ -1,5 +1,7 @@ package runtime +const _PAGESIZE = 0x1000 + type ureg struct { di uint32 /* general registers */ si uint32 /* ... */ diff --git a/src/runtime/defs_plan9_amd64.go b/src/runtime/defs_plan9_amd64.go index 17becfb66..510da0e99 100644 --- a/src/runtime/defs_plan9_amd64.go +++ b/src/runtime/defs_plan9_amd64.go @@ -1,5 +1,7 @@ package runtime +const _PAGESIZE = 0x1000 + type ureg struct { ax uint64 bx uint64 diff --git a/src/runtime/env_plan9.go b/src/runtime/env_plan9.go index e442c3483..ec50cac48 100644 --- a/src/runtime/env_plan9.go +++ b/src/runtime/env_plan9.go @@ -54,3 +54,6 @@ func gogetenv(key string) string { sp.len = int(r) return s } + +var _cgo_setenv unsafe.Pointer // pointer to C function +var _cgo_unsetenv unsafe.Pointer // pointer to C function diff --git a/src/runtime/gengoos.go b/src/runtime/gengoos.go new file mode 100644 index 000000000..06621c8db --- /dev/null +++ b/src/runtime/gengoos.go @@ -0,0 +1,84 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + "log" + "strconv" + "strings" +) + +var gooses, goarches []string + +func main() { + data, err := ioutil.ReadFile("../go/build/syslist.go") + if err != nil { + log.Fatal(err) + } + const ( + goosPrefix = `const goosList = ` + goarchPrefix = `const goarchList = ` + ) + for _, line := range strings.Split(string(data), "\n") { + if strings.HasPrefix(line, goosPrefix) { + text, err := strconv.Unquote(strings.TrimPrefix(line, goosPrefix)) + if err != nil { + log.Fatalf("parsing goosList %#q: %v", strings.TrimPrefix(line, goosPrefix), err) + } + gooses = strings.Fields(text) + } + if strings.HasPrefix(line, goarchPrefix) { + text, err := strconv.Unquote(strings.TrimPrefix(line, goarchPrefix)) + if err != nil { + log.Fatal("parsing goarchList: %v", err) + } + goarches = strings.Fields(text) + } + } + + for _, target := range gooses { + var buf bytes.Buffer + fmt.Fprintf(&buf, "// generated by gengoos.go using 'go generate'\n\n") + if target == "linux" { + fmt.Fprintf(&buf, "// +build !android\n\n") // must explicitly exclude android for linux + } + fmt.Fprintf(&buf, "package runtime\n\n") + fmt.Fprintf(&buf, "const theGoos = `%s`\n\n", target) + for _, goos := range gooses { + value := 0 + if goos == target { + value = 1 + } + fmt.Fprintf(&buf, "const goos_%s = %d\n", goos, value) + } + err := ioutil.WriteFile("zgoos_"+target+".go", buf.Bytes(), 0666) + if err != nil { + log.Fatal(err) + } + } + + for _, target := range goarches { + var buf bytes.Buffer + fmt.Fprintf(&buf, "// generated by gengoos.go using 'go generate'\n\n") + fmt.Fprintf(&buf, "package runtime\n\n") + fmt.Fprintf(&buf, "const theGoarch = `%s`\n\n", target) + for _, goarch := range goarches { + value := 0 + if goarch == target { + value = 1 + } + fmt.Fprintf(&buf, "const goarch_%s = %d\n", goarch, value) + } + err := ioutil.WriteFile("zgoarch_"+target+".go", buf.Bytes(), 0666) + if err != nil { + log.Fatal(err) + } + } +} diff --git a/src/runtime/heapdump.go b/src/runtime/heapdump.go index c6f97025f..e1693d40f 100644 --- a/src/runtime/heapdump.go +++ b/src/runtime/heapdump.go @@ -7,7 +7,7 @@ // finalizers, etc.) to a file. // The format of the dumped file is described at -// http://code.google.com/p/go-wiki/wiki/heapdump14 +// http://golang.org/s/go14heapdump. package runtime diff --git a/src/runtime/lfstack.go b/src/runtime/lfstack.go index a4ad8a10c..fd3325972 100644 --- a/src/runtime/lfstack.go +++ b/src/runtime/lfstack.go @@ -12,6 +12,10 @@ import "unsafe" func lfstackpush(head *uint64, node *lfnode) { node.pushcnt++ new := lfstackPack(node, node.pushcnt) + if node1, _ := lfstackUnpack(new); node1 != node { + println("runtime: lfstackpush invalid packing: node=", node, " cnt=", hex(node.pushcnt), " packed=", hex(new), " -> node=", node1, "\n") + gothrow("lfstackpush") + } for { old := atomicload64(head) node.next = old diff --git a/src/runtime/lfstack_32bit.go b/src/runtime/lfstack_32bit.go index 61d8678d9..4b8bcbac6 100644 --- a/src/runtime/lfstack_32bit.go +++ b/src/runtime/lfstack_32bit.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build 386 arm +// +build 386 arm nacl package runtime diff --git a/src/runtime/lfstack_linux_power64x.go b/src/runtime/lfstack_linux_power64x.go index 7a122bf92..89e389fc7 100644 --- a/src/runtime/lfstack_linux_power64x.go +++ b/src/runtime/lfstack_linux_power64x.go @@ -9,18 +9,24 @@ package runtime import "unsafe" -// On Power64, Linux limits the user address space to 43 bits. -// (https://www.kernel.org/doc/ols/2001/ppc64.pdf) -// In addition to the 21 bits taken from the top, we can take 3 from the -// bottom, because node must be pointer-aligned, giving a total of 24 bits +// On Power64, Linux limits the user address space to 46 bits (see +// TASK_SIZE_USER64 in the Linux kernel). This has grown over time, +// so here we allow 48 bit addresses. +// +// In addition to the 16 bits taken from the top, we can take 3 from the +// bottom, because node must be pointer-aligned, giving a total of 19 bits // of count. +const ( + addrBits = 48 + cntBits = 64 - addrBits + 3 +) func lfstackPack(node *lfnode, cnt uintptr) uint64 { - return uint64(uintptr(unsafe.Pointer(node)))<<21 | uint64(cnt&(1<<24-1)) + return uint64(uintptr(unsafe.Pointer(node)))<<(64-addrBits) | uint64(cnt&(1<<cntBits-1)) } func lfstackUnpack(val uint64) (node *lfnode, cnt uintptr) { - node = (*lfnode)(unsafe.Pointer(uintptr(val >> 24 << 3))) - cnt = uintptr(val & (1<<24 - 1)) + node = (*lfnode)(unsafe.Pointer(uintptr(val >> cntBits << 3))) + cnt = uintptr(val & (1<<cntBits - 1)) return } diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index 86e20b249..e9fec7bb1 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -546,6 +546,8 @@ func GC() { // linker-provided var noptrdata struct{} +var enoptrdata struct{} +var noptrbss struct{} var enoptrbss struct{} // SetFinalizer sets the finalizer associated with x to f. @@ -622,8 +624,13 @@ func SetFinalizer(obj interface{}, finalizer interface{}) { // func main() { // runtime.SetFinalizer(Foo, nil) // } - // The segments are, in order: text, rodata, noptrdata, data, bss, noptrbss. - if uintptr(unsafe.Pointer(&noptrdata)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&enoptrbss)) { + // The relevant segments are: noptrdata, data, bss, noptrbss. + // We cannot assume they are in any order or even contiguous, + // due to external linking. + if uintptr(unsafe.Pointer(&noptrdata)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&enoptrdata)) || + uintptr(unsafe.Pointer(&data)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&edata)) || + uintptr(unsafe.Pointer(&bss)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&ebss)) || + uintptr(unsafe.Pointer(&noptrbss)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&enoptrbss)) { return } gothrow("runtime.SetFinalizer: pointer not in allocated block") diff --git a/src/runtime/malloc2.go b/src/runtime/malloc2.go index 511638d3d..a9d40de30 100644 --- a/src/runtime/malloc2.go +++ b/src/runtime/malloc2.go @@ -126,7 +126,7 @@ const ( // See http://golang.org/issue/5402 and http://golang.org/issue/5236. // On other 64-bit platforms, we limit the arena to 128GB, or 37 bits. // On 32-bit, we don't bother limiting anything, so we use the full 32-bit address. - _MHeapMap_TotalBits = (_64bit*_Windows)*35 + (_64bit*(1-_Windows))*37 + (1-_64bit)*32 + _MHeapMap_TotalBits = (_64bit*goos_windows)*35 + (_64bit*(1-goos_windows))*37 + (1-_64bit)*32 _MHeapMap_Bits = _MHeapMap_TotalBits - _PageShift _MaxMem = uintptr(1<<_MHeapMap_TotalBits - 1) diff --git a/src/runtime/mem_bsd.go b/src/runtime/mem_bsd.go index 4bd40a39f..e9be5ec8c 100644 --- a/src/runtime/mem_bsd.go +++ b/src/runtime/mem_bsd.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build dragonfly freebsd netbsd openbsd solaris +// +build dragonfly freebsd nacl netbsd openbsd solaris package runtime @@ -38,7 +38,7 @@ func sysReserve(v unsafe.Pointer, n uintptr, reserved *bool) unsafe.Pointer { // On 64-bit, people with ulimit -v set complain if we reserve too // much address space. Instead, assume that the reservation is okay // and check the assumption in SysMap. - if ptrSize == 8 && uint64(n) > 1<<32 { + if ptrSize == 8 && uint64(n) > 1<<32 || goos_nacl != 0 { *reserved = false return v } diff --git a/src/runtime/mem_nacl.c b/src/runtime/mem_nacl.c deleted file mode 100644 index 6c836f18a..000000000 --- a/src/runtime/mem_nacl.c +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "runtime.h" -#include "arch_GOARCH.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "malloc.h" -#include "textflag.h" - -enum -{ - Debug = 0, -}; - -#pragma textflag NOSPLIT -void* -runtime·sysAlloc(uintptr n, uint64 *stat) -{ - void *v; - - v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); - if(v < (void*)4096) { - if(Debug) - runtime·printf("sysAlloc(%p): %p\n", n, v); - return nil; - } - runtime·xadd64(stat, n); - if(Debug) - runtime·printf("sysAlloc(%p) = %p\n", n, v); - return v; -} - -void -runtime·SysUnused(void *v, uintptr n) -{ - if(Debug) - runtime·printf("SysUnused(%p, %p)\n", v, n); -} - -void -runtime·SysUsed(void *v, uintptr n) -{ - USED(v); - USED(n); -} - -void -runtime·SysFree(void *v, uintptr n, uint64 *stat) -{ - if(Debug) - runtime·printf("SysFree(%p, %p)\n", v, n); - runtime·xadd64(stat, -(uint64)n); - runtime·munmap(v, n); -} - -void -runtime·SysFault(void *v, uintptr n) -{ - runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0); -} - -void* -runtime·SysReserve(void *v, uintptr n, bool *reserved) -{ - void *p; - - // On 64-bit, people with ulimit -v set complain if we reserve too - // much address space. Instead, assume that the reservation is okay - // and check the assumption in SysMap. - if(NaCl || sizeof(void*) == 8) { - *reserved = false; - return v; - } - - p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0); - if(p < (void*)4096) - return nil; - *reserved = true; - return p; -} - -void -runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat) -{ - void *p; - - runtime·xadd64(stat, n); - - // On 64-bit, we don't actually have v reserved, so tread carefully. - if(!reserved) { - p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); - if(p == (void*)ENOMEM) { - runtime·printf("SysMap(%p, %p): %p\n", v, n, p); - runtime·throw("runtime: out of memory"); - } - if(p != v) { - runtime·printf("SysMap(%p, %p): %p\n", v, n, p); - runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p); - runtime·throw("runtime: address space conflict"); - } - if(Debug) - runtime·printf("SysMap(%p, %p) = %p\n", v, n, p); - return; - } - - p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0); - if(p == (void*)ENOMEM) { - runtime·printf("SysMap(%p, %p): %p\n", v, n, p); - runtime·throw("runtime: out of memory"); - } - if(p != v) { - runtime·printf("SysMap(%p, %p): %p\n", v, n, p); - runtime·printf("mmap MAP_FIXED %p returned %p\n", v, p); - runtime·throw("runtime: cannot map pages in arena address space"); - } - if(Debug) - runtime·printf("SysMap(%p, %p) = %p\n", v, n, p); -} diff --git a/src/runtime/mem_plan9.c b/src/runtime/mem_plan9.c deleted file mode 100644 index d673d6f83..000000000 --- a/src/runtime/mem_plan9.c +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "arch_GOARCH.h" -#include "malloc.h" -#include "os_GOOS.h" -#include "textflag.h" - -extern byte runtime·end[]; -#pragma dataflag NOPTR -static byte *bloc = { runtime·end }; -static Mutex memlock; - -enum -{ - Round = PAGESIZE-1 -}; - -static void* -brk(uintptr nbytes) -{ - uintptr bl; - - runtime·lock(&memlock); - // Plan 9 sbrk from /sys/src/libc/9sys/sbrk.c - bl = ((uintptr)bloc + Round) & ~Round; - if(runtime·brk_((void*)(bl + nbytes)) < 0) { - runtime·unlock(&memlock); - return nil; - } - bloc = (byte*)bl + nbytes; - runtime·unlock(&memlock); - return (void*)bl; -} - -static void -sysalloc(void) -{ - uintptr nbytes; - uint64 *stat; - void *p; - - nbytes = g->m->scalararg[0]; - stat = g->m->ptrarg[0]; - g->m->scalararg[0] = 0; - g->m->ptrarg[0] = nil; - - p = brk(nbytes); - if(p != nil) - runtime·xadd64(stat, nbytes); - - g->m->ptrarg[0] = p; -} - -#pragma textflag NOSPLIT -void* -runtime·sysAlloc(uintptr nbytes, uint64 *stat) -{ - void (*fn)(void); - void *p; - - g->m->scalararg[0] = nbytes; - g->m->ptrarg[0] = stat; - fn = sysalloc; - runtime·onM(&fn); - p = g->m->ptrarg[0]; - g->m->ptrarg[0] = nil; - return p; -} - -void -runtime·SysFree(void *v, uintptr nbytes, uint64 *stat) -{ - runtime·xadd64(stat, -(uint64)nbytes); - runtime·lock(&memlock); - // from tiny/mem.c - // Push pointer back if this is a free - // of the most recent sysAlloc. - nbytes += (nbytes + Round) & ~Round; - if(bloc == (byte*)v+nbytes) - bloc -= nbytes; - runtime·unlock(&memlock); -} - -void -runtime·SysUnused(void *v, uintptr nbytes) -{ - USED(v, nbytes); -} - -void -runtime·SysUsed(void *v, uintptr nbytes) -{ - USED(v, nbytes); -} - -void -runtime·SysMap(void *v, uintptr nbytes, bool reserved, uint64 *stat) -{ - // SysReserve has already allocated all heap memory, - // but has not adjusted stats. - USED(v, reserved); - runtime·xadd64(stat, nbytes); -} - -void -runtime·SysFault(void *v, uintptr nbytes) -{ - USED(v, nbytes); -} - -void* -runtime·SysReserve(void *v, uintptr nbytes, bool *reserved) -{ - USED(v); - *reserved = true; - return brk(nbytes); -} diff --git a/src/runtime/mem_plan9.go b/src/runtime/mem_plan9.go new file mode 100644 index 000000000..a5d7c1a4c --- /dev/null +++ b/src/runtime/mem_plan9.go @@ -0,0 +1,70 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import "unsafe" + +var bloc uintptr +var memlock mutex + +const memRound = _PAGESIZE - 1 + +func initBloc() { + bloc = uintptr(unsafe.Pointer(&end)) +} + +func sbrk(n uintptr) unsafe.Pointer { + lock(&memlock) + // Plan 9 sbrk from /sys/src/libc/9sys/sbrk.c + bl := (bloc + memRound) &^ memRound + if brk_(unsafe.Pointer(bl+n)) < 0 { + unlock(&memlock) + return nil + } + bloc = bl + n + unlock(&memlock) + return unsafe.Pointer(bl) +} + +func sysAlloc(n uintptr, stat *uint64) unsafe.Pointer { + p := sbrk(n) + if p != nil { + xadd64(stat, int64(n)) + } + return p +} + +func sysFree(v unsafe.Pointer, n uintptr, stat *uint64) { + xadd64(stat, -int64(n)) + lock(&memlock) + // from tiny/mem.c + // Push pointer back if this is a free + // of the most recent sysAlloc. + n += (n + memRound) &^ memRound + if bloc == uintptr(v)+n { + bloc -= n + } + unlock(&memlock) +} + +func sysUnused(v unsafe.Pointer, n uintptr) { +} + +func sysUsed(v unsafe.Pointer, n uintptr) { +} + +func sysMap(v unsafe.Pointer, n uintptr, reserved bool, stat *uint64) { + // sysReserve has already allocated all heap memory, + // but has not adjusted stats. + xadd64(stat, int64(n)) +} + +func sysFault(v unsafe.Pointer, n uintptr) { +} + +func sysReserve(v unsafe.Pointer, n uintptr, reserved *bool) unsafe.Pointer { + *reserved = true + return sbrk(n) +} diff --git a/src/runtime/mgc0.go b/src/runtime/mgc0.go index 00e64c0ff..7797894fc 100644 --- a/src/runtime/mgc0.go +++ b/src/runtime/mgc0.go @@ -51,10 +51,26 @@ func clearpools() { if c := p.mcache; c != nil { c.tiny = nil c.tinysize = 0 + + // disconnect cached list before dropping it on the floor, + // so that a dangling ref to one entry does not pin all of them. + var sg, sgnext *sudog + for sg = c.sudogcache; sg != nil; sg = sgnext { + sgnext = sg.next + sg.next = nil + } c.sudogcache = nil } + // clear defer pools for i := range p.deferpool { + // disconnect cached list before dropping it on the floor, + // so that a dangling ref to one entry does not pin all of them. + var d, dlink *_defer + for d = p.deferpool[i]; d != nil; d = dlink { + dlink = d.link + d.link = nil + } p.deferpool[i] = nil } } diff --git a/src/runtime/netpoll_stub.c b/src/runtime/netpoll_stub.go index b7a8f2944..6c7e79ea3 100644 --- a/src/runtime/netpoll_stub.c +++ b/src/runtime/netpoll_stub.go @@ -4,15 +4,12 @@ // +build plan9 -#include "runtime.h" +package runtime // Polls for ready network connections. // Returns list of goroutines that become runnable. -G* -runtime·netpoll(bool block) -{ +func netpoll(block bool) (gp *g) { // Implementation for platforms that do not support // integrated network poller. - USED(block); - return nil; + return } diff --git a/src/runtime/netpoll_windows.go b/src/runtime/netpoll_windows.go index 88e878137..23d5dc00f 100644 --- a/src/runtime/netpoll_windows.go +++ b/src/runtime/netpoll_windows.go @@ -108,7 +108,7 @@ retry: op = entries[i].op errno = 0 qty = 0 - if stdcall5(_WSAGetOverlappedResult, netpollfd(op.pd), uintptr(unsafe.Pointer(op)), uintptr(unsafe.Pointer(&qty)), 0, uintptr(unsafe.Pointer(&flags))) == 0 { + if stdcall5(_WSAGetOverlappedResult, op.pd.fd, uintptr(unsafe.Pointer(op)), uintptr(unsafe.Pointer(&qty)), 0, uintptr(unsafe.Pointer(&flags))) == 0 { errno = int32(getlasterror()) } handlecompletion(&gp, op, errno, qty) @@ -152,5 +152,5 @@ func handlecompletion(gpp **g, op *net_op, errno int32, qty uint32) { } op.errno = errno op.qty = qty - netpollready(gpp, op.pd, mode) + netpollready((**g)(noescape(unsafe.Pointer(gpp))), op.pd, mode) } diff --git a/src/runtime/os1_nacl.go b/src/runtime/os1_nacl.go new file mode 100644 index 000000000..7b4c99a3d --- /dev/null +++ b/src/runtime/os1_nacl.go @@ -0,0 +1,197 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import "unsafe" + +// Called to initialize a new m (including the bootstrap m). +// Called on the parent thread (main thread in case of bootstrap), can allocate memory. +func mpreinit(mp *m) { + mp.gsignal = malg(32 * 1024) + mp.gsignal.m = mp +} + +func sigtramp() + +// Called to initialize a new m (including the bootstrap m). +// Called on the new thread, can not allocate memory. +func minit() { + _g_ := getg() + + // Initialize signal handling + ret := nacl_exception_stack(_g_.m.gsignal.stack.lo, 32*1024) + if ret < 0 { + print("runtime: nacl_exception_stack: error ", -ret, "\n") + } + + ret = nacl_exception_handler(funcPC(sigtramp), nil) + if ret < 0 { + print("runtime: nacl_exception_handler: error ", -ret, "\n") + } +} + +// Called from dropm to undo the effect of an minit. +func unminit() { +} + +func osinit() { + ncpu = 1 + getg().m.procid = 2 + //nacl_exception_handler(funcPC(sigtramp), nil); +} + +func crash() { + *(*int32)(nil) = 0 +} + +//go:nosplit +func get_random_data(rnd *unsafe.Pointer, rnd_len *int32) { + *rnd = nil + *rnd_len = 0 +} + +func goenvs() { + goenvs_unix() +} + +func initsig() { +} + +//go:nosplit +func usleep(us uint32) { + var ts timespec + + ts.tv_sec = int64(us / 1e6) + ts.tv_nsec = int32(us%1e6) * 1e3 + nacl_nanosleep(&ts, nil) +} + +func mstart_nacl() + +func newosproc(mp *m, stk unsafe.Pointer) { + tls := (*[3]unsafe.Pointer)(unsafe.Pointer(&mp.tls)) + tls[0] = unsafe.Pointer(mp.g0) + tls[1] = unsafe.Pointer(mp) + ret := nacl_thread_create(funcPC(mstart_nacl), stk, unsafe.Pointer(&tls[2]), nil) + if ret < 0 { + print("nacl_thread_create: error ", -ret, "\n") + gothrow("newosproc") + } +} + +//go:nosplit +func semacreate() uintptr { + var cond uintptr + systemstack(func() { + mu := nacl_mutex_create(0) + if mu < 0 { + print("nacl_mutex_create: error ", -mu, "\n") + gothrow("semacreate") + } + c := nacl_cond_create(0) + if c < 0 { + print("nacl_cond_create: error ", -cond, "\n") + gothrow("semacreate") + } + cond = uintptr(c) + _g_ := getg() + _g_.m.waitsemalock = uint32(mu) + }) + return cond +} + +//go:nosplit +func semasleep(ns int64) int32 { + var ret int32 + + systemstack(func() { + _g_ := getg() + if nacl_mutex_lock(int32(_g_.m.waitsemalock)) < 0 { + gothrow("semasleep") + } + + for _g_.m.waitsemacount == 0 { + if ns < 0 { + if nacl_cond_wait(int32(_g_.m.waitsema), int32(_g_.m.waitsemalock)) < 0 { + gothrow("semasleep") + } + } else { + var ts timespec + end := ns + nanotime() + ts.tv_sec = end / 1e9 + ts.tv_nsec = int32(end % 1e9) + r := nacl_cond_timed_wait_abs(int32(_g_.m.waitsema), int32(_g_.m.waitsemalock), &ts) + if r == -_ETIMEDOUT { + nacl_mutex_unlock(int32(_g_.m.waitsemalock)) + ret = -1 + return + } + if r < 0 { + gothrow("semasleep") + } + } + } + + _g_.m.waitsemacount = 0 + nacl_mutex_unlock(int32(_g_.m.waitsemalock)) + ret = 0 + }) + return ret +} + +//go:nosplit +func semawakeup(mp *m) { + systemstack(func() { + if nacl_mutex_lock(int32(mp.waitsemalock)) < 0 { + gothrow("semawakeup") + } + if mp.waitsemacount != 0 { + gothrow("semawakeup") + } + mp.waitsemacount = 1 + nacl_cond_signal(int32(mp.waitsema)) + nacl_mutex_unlock(int32(mp.waitsemalock)) + }) +} + +func memlimit() uintptr { + return 0 +} + +// This runs on a foreign stack, without an m or a g. No stack split. +//go:nosplit +func badsignal2() { + write(2, unsafe.Pointer(&badsignal1[0]), int32(len(badsignal1))) + exit(2) +} + +var badsignal1 = []byte("runtime: signal received on thread not created by Go.\n") + +func madvise(addr unsafe.Pointer, n uintptr, flags int32) {} +func munmap(addr unsafe.Pointer, n uintptr) {} +func resetcpuprofiler(hz int32) {} +func sigdisable(uint32) {} +func sigenable(uint32) {} +func closeonexec(int32) {} + +var writelock uint32 // test-and-set spin lock for write + +/* +An attempt at IRT. Doesn't work. See end of sys_nacl_amd64.s. + +void (*nacl_irt_query)(void); + +int8 nacl_irt_basic_v0_1_str[] = "nacl-irt-basic-0.1"; +void *nacl_irt_basic_v0_1[6]; // exit, gettod, clock, nanosleep, sched_yield, sysconf +int32 nacl_irt_basic_v0_1_size = sizeof(nacl_irt_basic_v0_1); + +int8 nacl_irt_memory_v0_3_str[] = "nacl-irt-memory-0.3"; +void *nacl_irt_memory_v0_3[3]; // mmap, munmap, mprotect +int32 nacl_irt_memory_v0_3_size = sizeof(nacl_irt_memory_v0_3); + +int8 nacl_irt_thread_v0_1_str[] = "nacl-irt-thread-0.1"; +void *nacl_irt_thread_v0_1[3]; // thread_create, thread_exit, thread_nice +int32 nacl_irt_thread_v0_1_size = sizeof(nacl_irt_thread_v0_1); +*/ diff --git a/src/runtime/os1_netbsd.go b/src/runtime/os1_netbsd.go new file mode 100644 index 000000000..493be30fa --- /dev/null +++ b/src/runtime/os1_netbsd.go @@ -0,0 +1,265 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import "unsafe" + +const ( + _ESRCH = 3 + _ENOTSUP = 91 + + // From NetBSD's <sys/time.h> + _CLOCK_REALTIME = 0 + _CLOCK_VIRTUAL = 1 + _CLOCK_PROF = 2 + _CLOCK_MONOTONIC = 3 +) + +var sigset_none = sigset{} +var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}} + +// From NetBSD's <sys/sysctl.h> +const ( + _CTL_HW = 6 + _HW_NCPU = 3 +) + +func getncpu() int32 { + mib := [2]uint32{_CTL_HW, _HW_NCPU} + out := uint32(0) + nout := unsafe.Sizeof(out) + ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0) + if ret >= 0 { + return int32(out) + } + return 1 +} + +//go:nosplit +func semacreate() uintptr { + return 1 +} + +//go:nosplit +func semasleep(ns int64) int32 { + _g_ := getg() + + // spin-mutex lock + for { + if xchg(&_g_.m.waitsemalock, 1) == 0 { + break + } + osyield() + } + + for { + // lock held + if _g_.m.waitsemacount == 0 { + // sleep until semaphore != 0 or timeout. + // thrsleep unlocks m.waitsemalock. + if ns < 0 { + // TODO(jsing) - potential deadlock! + // + // There is a potential deadlock here since we + // have to release the waitsemalock mutex + // before we call lwp_park() to suspend the + // thread. This allows another thread to + // release the lock and call lwp_unpark() + // before the thread is actually suspended. + // If this occurs the current thread will end + // up sleeping indefinitely. Unfortunately + // the NetBSD kernel does not appear to provide + // a mechanism for unlocking the userspace + // mutex once the thread is actually parked. + atomicstore(&_g_.m.waitsemalock, 0) + lwp_park(nil, 0, unsafe.Pointer(&_g_.m.waitsemacount), nil) + } else { + var ts timespec + var nsec int32 + ns += nanotime() + ts.set_sec(timediv(ns, 1000000000, &nsec)) + ts.set_nsec(nsec) + // TODO(jsing) - potential deadlock! + // See above for details. + atomicstore(&_g_.m.waitsemalock, 0) + lwp_park(&ts, 0, unsafe.Pointer(&_g_.m.waitsemacount), nil) + } + // reacquire lock + for { + if xchg(&_g_.m.waitsemalock, 1) == 0 { + break + } + osyield() + } + } + + // lock held (again) + if _g_.m.waitsemacount != 0 { + // semaphore is available. + _g_.m.waitsemacount-- + // spin-mutex unlock + atomicstore(&_g_.m.waitsemalock, 0) + return 0 + } + + // semaphore not available. + // if there is a timeout, stop now. + // otherwise keep trying. + if ns >= 0 { + break + } + } + + // lock held but giving up + // spin-mutex unlock + atomicstore(&_g_.m.waitsemalock, 0) + return -1 +} + +//go:nosplit +func semawakeup(mp *m) { + // spin-mutex lock + for { + if xchg(&mp.waitsemalock, 1) == 0 { + break + } + osyield() + } + + mp.waitsemacount++ + // TODO(jsing) - potential deadlock, see semasleep() for details. + // Confirm that LWP is parked before unparking... + ret := lwp_unpark(int32(mp.procid), unsafe.Pointer(&mp.waitsemacount)) + if ret != 0 && ret != _ESRCH { + // semawakeup can be called on signal stack. + systemstack(func() { + print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n") + }) + } + + // spin-mutex unlock + atomicstore(&mp.waitsemalock, 0) +} + +func newosproc(mp *m, stk unsafe.Pointer) { + if false { + print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, "/", int32(mp.tls[0]), " ostk=", &mp, "\n") + } + + mp.tls[0] = uintptr(mp.id) // so 386 asm can find it + + var uc ucontextt + getcontext(unsafe.Pointer(&uc)) + + uc.uc_flags = _UC_SIGMASK | _UC_CPU + uc.uc_link = nil + uc.uc_sigmask = sigset_all + + lwp_mcontext_init(&uc.uc_mcontext, stk, mp, mp.g0, funcPC(mstart)) + + ret := lwp_create(unsafe.Pointer(&uc), 0, unsafe.Pointer(&mp.procid)) + if ret < 0 { + print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n") + gothrow("runtime.newosproc") + } +} + +func osinit() { + ncpu = getncpu() +} + +var urandom_data [_HashRandomBytes]byte +var urandom_dev = []byte("/dev/urandom\x00") + +//go:nosplit +func get_random_data(rnd *unsafe.Pointer, rnd_len *int32) { + fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0) + if read(fd, unsafe.Pointer(&urandom_data), _HashRandomBytes) == _HashRandomBytes { + *rnd = unsafe.Pointer(&urandom_data[0]) + *rnd_len = _HashRandomBytes + } else { + *rnd = nil + *rnd_len = 0 + } + close(fd) +} + +func goenvs() { + goenvs_unix() +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the parent thread (main thread in case of bootstrap), can allocate memory. +func mpreinit(mp *m) { + mp.gsignal = malg(32 * 1024) + mp.gsignal.m = mp +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the new thread, can not allocate memory. +func minit() { + _g_ := getg() + _g_.m.procid = uint64(lwp_self()) + + // Initialize signal handling + signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024) + sigprocmask(_SIG_SETMASK, &sigset_none, nil) +} + +// Called from dropm to undo the effect of an minit. +func unminit() { + signalstack(nil, 0) +} + +func memlimit() uintptr { + return 0 +} + +func sigtramp() + +type sigactiont struct { + sa_sigaction uintptr + sa_mask sigset + sa_flags int32 +} + +func setsig(i int32, fn uintptr, restart bool) { + var sa sigactiont + sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK + if restart { + sa.sa_flags |= _SA_RESTART + } + sa.sa_mask = sigset_all + if fn == funcPC(sighandler) { + fn = funcPC(sigtramp) + } + sa.sa_sigaction = fn + sigaction(i, &sa, nil) +} + +func getsig(i int32) uintptr { + var sa sigactiont + sigaction(i, nil, &sa) + if sa.sa_sigaction == funcPC(sigtramp) { + return funcPC(sighandler) + } + return sa.sa_sigaction +} + +func signalstack(p *byte, n int32) { + var st sigaltstackt + + st.ss_sp = uintptr(unsafe.Pointer(p)) + st.ss_size = uintptr(n) + st.ss_flags = 0 + if p == nil { + st.ss_flags = _SS_DISABLE + } + sigaltstack(&st, nil) +} + +func unblocksignals() { + sigprocmask(_SIG_SETMASK, &sigset_none, nil) +} diff --git a/src/runtime/os1_netbsd_386.go b/src/runtime/os1_netbsd_386.go new file mode 100644 index 000000000..037f7e36d --- /dev/null +++ b/src/runtime/os1_netbsd_386.go @@ -0,0 +1,16 @@ +// 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. + +package runtime + +import "unsafe" + +func lwp_mcontext_init(mc *mcontextt, stk unsafe.Pointer, mp *m, gp *g, fn uintptr) { + // Machine dependent mcontext initialisation for LWP. + mc.__gregs[_REG_EIP] = uint32(funcPC(lwp_tramp)) + mc.__gregs[_REG_UESP] = uint32(uintptr(stk)) + mc.__gregs[_REG_EBX] = uint32(uintptr(unsafe.Pointer(mp))) + mc.__gregs[_REG_EDX] = uint32(uintptr(unsafe.Pointer(gp))) + mc.__gregs[_REG_ESI] = uint32(fn) +} diff --git a/src/runtime/os1_netbsd_amd64.go b/src/runtime/os1_netbsd_amd64.go new file mode 100644 index 000000000..5118b0c4f --- /dev/null +++ b/src/runtime/os1_netbsd_amd64.go @@ -0,0 +1,16 @@ +// 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. + +package runtime + +import "unsafe" + +func lwp_mcontext_init(mc *mcontextt, stk unsafe.Pointer, mp *m, gp *g, fn uintptr) { + // Machine dependent mcontext initialisation for LWP. + mc.__gregs[_REG_RIP] = uint64(funcPC(lwp_tramp)) + mc.__gregs[_REG_RSP] = uint64(uintptr(stk)) + mc.__gregs[_REG_R8] = uint64(uintptr(unsafe.Pointer(mp))) + mc.__gregs[_REG_R9] = uint64(uintptr(unsafe.Pointer(gp))) + mc.__gregs[_REG_R12] = uint64(fn) +} diff --git a/src/runtime/os1_plan9.go b/src/runtime/os1_plan9.go new file mode 100644 index 000000000..0f8da03f2 --- /dev/null +++ b/src/runtime/os1_plan9.go @@ -0,0 +1,270 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import "unsafe" + +// Called to initialize a new m (including the bootstrap m). +// Called on the parent thread (main thread in case of bootstrap), can allocate memory. +func mpreinit(mp *m) { + // Initialize stack and goroutine for note handling. + mp.gsignal = malg(32 * 1024) + mp.gsignal.m = mp + mp.notesig = (*int8)(mallocgc(_ERRMAX, nil, _FlagNoScan)) + // Initialize stack for handling strings from the + // errstr system call, as used in package syscall. + mp.errstr = (*byte)(mallocgc(_ERRMAX, nil, _FlagNoScan)) +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the new thread, can not allocate memory. +func minit() { + // Mask all SSE floating-point exceptions + // when running on the 64-bit kernel. + setfpmasks() +} + +// Called from dropm to undo the effect of an minit. +func unminit() { +} + +var sysstat = []byte("/dev/sysstat\x00") + +func getproccount() int32 { + var buf [2048]byte + fd := open(&sysstat[0], _OREAD, 0) + if fd < 0 { + return 1 + } + ncpu := int32(0) + for { + n := read(fd, unsafe.Pointer(&buf), int32(len(buf))) + if n <= 0 { + break + } + for i := int32(0); i < n; i++ { + if buf[i] == '\n' { + ncpu++ + } + } + } + close(fd) + if ncpu == 0 { + ncpu = 1 + } + return ncpu +} + +var pid = []byte("#c/pid\x00") + +func getpid() uint64 { + var b [20]byte + fd := open(&pid[0], 0, 0) + if fd >= 0 { + read(fd, unsafe.Pointer(&b), int32(len(b))) + close(fd) + } + c := b[:] + for c[0] == ' ' || c[0] == '\t' { + c = c[1:] + } + return uint64(atoi(c)) +} + +func osinit() { + initBloc() + ncpu = getproccount() + getg().m.procid = getpid() + notify(unsafe.Pointer(funcPC(sigtramp))) +} + +func crash() { + notify(nil) + *(*int)(nil) = 0 +} + +var random_data [_HashRandomBytes]byte +var random_dev = []byte("/dev/random\x00") + +//go:nosplit +func get_random_data(rnd *unsafe.Pointer, rnd_len *int32) { + fd := open(&random_dev[0], 0 /* O_RDONLY */, 0) + if read(fd, unsafe.Pointer(&random_data), _HashRandomBytes) == _HashRandomBytes { + *rnd = unsafe.Pointer(&random_data[0]) + *rnd_len = _HashRandomBytes + } else { + *rnd = nil + *rnd_len = 0 + } + close(fd) +} + +func goenvs() { +} + +func initsig() { +} + +//go:nosplit +func osyield() { + sleep(0) +} + +//go:nosplit +func usleep(µs uint32) { + ms := int32(µs / 1000) + if ms == 0 { + ms = 1 + } + sleep(ms) +} + +//go:nosplit +func nanotime() int64 { + var scratch int64 + ns := nsec(&scratch) + // TODO(aram): remove hack after I fix _nsec in the pc64 kernel. + if ns == 0 { + return scratch + } + return ns +} + +//go:nosplit +func itoa(buf []byte, val uint64) []byte { + i := len(buf) - 1 + for val >= 10 { + buf[i] = byte(val%10 + '0') + i-- + val /= 10 + } + buf[i] = byte(val + '0') + return buf[i:] +} + +var goexits = []byte("go: exit ") + +func goexitsall(status *byte) { + var buf [_ERRMAX]byte + n := copy(buf[:], goexits) + n = copy(buf[n:], gostringnocopy(status)) + pid := getpid() + for mp := (*m)(atomicloadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink { + if mp.procid != pid { + postnote(mp.procid, buf[:]) + } + } +} + +var procdir = []byte("/proc/") +var notefile = []byte("/note\x00") + +func postnote(pid uint64, msg []byte) int { + var buf [128]byte + var tmp [32]byte + n := copy(buf[:], procdir) + n += copy(buf[n:], itoa(tmp[:], pid)) + copy(buf[n:], notefile) + fd := open(&buf[0], _OWRITE, 0) + if fd < 0 { + return -1 + } + len := findnull(&msg[0]) + if write(uintptr(fd), (unsafe.Pointer)(&msg[0]), int32(len)) != int64(len) { + close(fd) + return -1 + } + close(fd) + return 0 +} + +//go:nosplit +func exit(e int) { + var status []byte + if e == 0 { + status = []byte("\x00") + } else { + // build error string + var tmp [32]byte + status = []byte(gostringnocopy(&itoa(tmp[:], uint64(e))[0]) + "\x00") + } + goexitsall(&status[0]) + exits(&status[0]) +} + +func newosproc(mp *m, stk unsafe.Pointer) { + if false { + print("newosproc mp=", mp, " ostk=", &mp, "\n") + } + pid := rfork(_RFPROC | _RFMEM | _RFNOWAIT) + if pid < 0 { + gothrow("newosproc: rfork failed") + } + if pid == 0 { + tstart_plan9(mp) + } +} + +//go:nosplit +func semacreate() uintptr { + return 1 +} + +//go:nosplit +func semasleep(ns int64) int { + _g_ := getg() + if ns >= 0 { + ms := timediv(ns, 1000000, nil) + if ms == 0 { + ms = 1 + } + ret := plan9_tsemacquire(&_g_.m.waitsemacount, ms) + if ret == 1 { + return 0 // success + } + return -1 // timeout or interrupted + } + for plan9_semacquire(&_g_.m.waitsemacount, 1) < 0 { + // interrupted; try again (c.f. lock_sema.go) + } + return 0 // success +} + +//go:nosplit +func semawakeup(mp *m) { + plan9_semrelease(&mp.waitsemacount, 1) +} + +//go:nosplit +func read(fd int32, buf unsafe.Pointer, n int32) int32 { + return pread(fd, buf, n, -1) +} + +//go:nosplit +func write(fd uintptr, buf unsafe.Pointer, n int32) int64 { + return int64(pwrite(int32(fd), buf, n, -1)) +} + +func memlimit() uint64 { + return 0 +} + +var _badsignal = []byte("runtime: signal received on thread not created by Go.\n") + +// This runs on a foreign stack, without an m or a g. No stack split. +//go:nosplit +func badsignal2() { + pwrite(2, unsafe.Pointer(&_badsignal[0]), int32(len(_badsignal)), -1) + exits(&_badsignal[0]) +} + +func atoi(b []byte) int { + n := 0 + for len(b) > 0 && '0' <= b[0] && b[0] <= '9' { + n = n*10 + int(b[0]) - '0' + b = b[1:] + } + return n +} diff --git a/src/runtime/os1_windows.go b/src/runtime/os1_windows.go new file mode 100644 index 000000000..57ea050f2 --- /dev/null +++ b/src/runtime/os1_windows.go @@ -0,0 +1,564 @@ +// 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. + +package runtime + +import ( + "unsafe" +) + +//go:cgo_import_dynamic runtime._AddVectoredExceptionHandler AddVectoredExceptionHandler "kernel32.dll" +//go:cgo_import_dynamic runtime._CloseHandle CloseHandle "kernel32.dll" +//go:cgo_import_dynamic runtime._CreateEventA CreateEventA "kernel32.dll" +//go:cgo_import_dynamic runtime._CreateThread CreateThread "kernel32.dll" +//go:cgo_import_dynamic runtime._CreateWaitableTimerA CreateWaitableTimerA "kernel32.dll" +//go:cgo_import_dynamic runtime._CryptAcquireContextW CryptAcquireContextW "advapi32.dll" +//go:cgo_import_dynamic runtime._CryptGenRandom CryptGenRandom "advapi32.dll" +//go:cgo_import_dynamic runtime._CryptReleaseContext CryptReleaseContext "advapi32.dll" +//go:cgo_import_dynamic runtime._DuplicateHandle DuplicateHandle "kernel32.dll" +//go:cgo_import_dynamic runtime._ExitProcess ExitProcess "kernel32.dll" +//go:cgo_import_dynamic runtime._FreeEnvironmentStringsW FreeEnvironmentStringsW "kernel32.dll" +//go:cgo_import_dynamic runtime._GetEnvironmentStringsW GetEnvironmentStringsW "kernel32.dll" +//go:cgo_import_dynamic runtime._GetProcAddress GetProcAddress "kernel32.dll" +//go:cgo_import_dynamic runtime._GetStdHandle GetStdHandle "kernel32.dll" +//go:cgo_import_dynamic runtime._GetSystemInfo GetSystemInfo "kernel32.dll" +//go:cgo_import_dynamic runtime._GetThreadContext GetThreadContext "kernel32.dll" +//go:cgo_import_dynamic runtime._LoadLibraryW LoadLibraryW "kernel32.dll" +//go:cgo_import_dynamic runtime._LoadLibraryA LoadLibraryA "kernel32.dll" +//go:cgo_import_dynamic runtime._NtWaitForSingleObject NtWaitForSingleObject "ntdll.dll" +//go:cgo_import_dynamic runtime._ResumeThread ResumeThread "kernel32.dll" +//go:cgo_import_dynamic runtime._SetConsoleCtrlHandler SetConsoleCtrlHandler "kernel32.dll" +//go:cgo_import_dynamic runtime._SetEvent SetEvent "kernel32.dll" +//go:cgo_import_dynamic runtime._SetProcessPriorityBoost SetProcessPriorityBoost "kernel32.dll" +//go:cgo_import_dynamic runtime._SetThreadPriority SetThreadPriority "kernel32.dll" +//go:cgo_import_dynamic runtime._SetUnhandledExceptionFilter SetUnhandledExceptionFilter "kernel32.dll" +//go:cgo_import_dynamic runtime._SetWaitableTimer SetWaitableTimer "kernel32.dll" +//go:cgo_import_dynamic runtime._Sleep Sleep "kernel32.dll" +//go:cgo_import_dynamic runtime._SuspendThread SuspendThread "kernel32.dll" +//go:cgo_import_dynamic runtime._WaitForSingleObject WaitForSingleObject "kernel32.dll" +//go:cgo_import_dynamic runtime._WriteFile WriteFile "kernel32.dll" +//go:cgo_import_dynamic runtime._timeBeginPeriod timeBeginPeriod "winmm.dll" + +var ( + _AddVectoredExceptionHandler, + _CloseHandle, + _CreateEventA, + _CreateThread, + _CreateWaitableTimerA, + _CryptAcquireContextW, + _CryptGenRandom, + _CryptReleaseContext, + _DuplicateHandle, + _ExitProcess, + _FreeEnvironmentStringsW, + _GetEnvironmentStringsW, + _GetProcAddress, + _GetStdHandle, + _GetSystemInfo, + _GetThreadContext, + _LoadLibraryW, + _LoadLibraryA, + _NtWaitForSingleObject, + _ResumeThread, + _SetConsoleCtrlHandler, + _SetEvent, + _SetProcessPriorityBoost, + _SetThreadPriority, + _SetUnhandledExceptionFilter, + _SetWaitableTimer, + _Sleep, + _SuspendThread, + _WaitForSingleObject, + _WriteFile, + _timeBeginPeriod stdFunction +) + +var _GetQueuedCompletionStatusEx stdFunction + +// in sys_windows_386.s and sys_windows_amd64.s +func externalthreadhandler() +func exceptiontramp() +func firstcontinuetramp() +func lastcontinuetramp() + +//go:nosplit +func getLoadLibrary() uintptr { + return uintptr(unsafe.Pointer(_LoadLibraryW)) +} + +//go:nosplit +func getGetProcAddress() uintptr { + return uintptr(unsafe.Pointer(_GetProcAddress)) +} + +func getproccount() int32 { + var info systeminfo + stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info))) + return int32(info.dwnumberofprocessors) +} + +const ( + currentProcess = ^uintptr(0) // -1 = current process + currentThread = ^uintptr(1) // -2 = current thread +) + +var ( + kernel32Name = []byte("kernel32.dll\x00") + addVectoredContinueHandlerName = []byte("AddVectoredContinueHandler\x00") + getQueuedCompletionStatusExName = []byte("GetQueuedCompletionStatusEx\x00") +) + +func osinit() { + setBadSignalMsg() + + kernel32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&kernel32Name[0]))) + + externalthreadhandlerp = funcPC(externalthreadhandler) + + stdcall2(_AddVectoredExceptionHandler, 1, funcPC(exceptiontramp)) + addVectoredContinueHandler := uintptr(0) + if kernel32 != 0 { + addVectoredContinueHandler = stdcall2(_GetProcAddress, kernel32, uintptr(unsafe.Pointer(&addVectoredContinueHandlerName[0]))) + } + if addVectoredContinueHandler == 0 || unsafe.Sizeof(&kernel32) == 4 { + // use SetUnhandledExceptionFilter for windows-386 or + // if VectoredContinueHandler is unavailable. + // note: SetUnhandledExceptionFilter handler won't be called, if debugging. + stdcall1(_SetUnhandledExceptionFilter, funcPC(lastcontinuetramp)) + } else { + stdcall2(stdFunction(unsafe.Pointer(addVectoredContinueHandler)), 1, funcPC(firstcontinuetramp)) + stdcall2(stdFunction(unsafe.Pointer(addVectoredContinueHandler)), 0, funcPC(lastcontinuetramp)) + } + + stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1) + + stdcall1(_timeBeginPeriod, 1) + + ncpu = getproccount() + + // Windows dynamic priority boosting assumes that a process has different types + // of dedicated threads -- GUI, IO, computational, etc. Go processes use + // equivalent threads that all do a mix of GUI, IO, computations, etc. + // In such context dynamic priority boosting does nothing but harm, so we turn it off. + stdcall2(_SetProcessPriorityBoost, currentProcess, 1) + + if kernel32 != 0 { + _GetQueuedCompletionStatusEx = stdFunction(unsafe.Pointer(stdcall2(_GetProcAddress, kernel32, uintptr(unsafe.Pointer(&getQueuedCompletionStatusExName[0]))))) + } +} + +var random_data [_HashRandomBytes]byte + +//go:nosplit +func get_random_data(rnd *unsafe.Pointer, rnd_len *int32) { + const ( + prov_rsa_full = 1 + crypt_verifycontext = 0xF0000000 + ) + var handle uintptr + *rnd = nil + *rnd_len = 0 + if stdcall5(_CryptAcquireContextW, uintptr(unsafe.Pointer(&handle)), 0, 0, prov_rsa_full, crypt_verifycontext) != 0 { + if stdcall3(_CryptGenRandom, handle, _HashRandomBytes, uintptr(unsafe.Pointer(&random_data[0]))) != 0 { + *rnd = unsafe.Pointer(&random_data[0]) + *rnd_len = _HashRandomBytes + } + stdcall2(_CryptReleaseContext, handle, 0) + } +} + +func goenvs() { + var p *uint16 + + env := (*uint16)(unsafe.Pointer(stdcall0(_GetEnvironmentStringsW))) + + n := 0 + for p = env; *p != 0; n++ { + p = (*uint16)(add(unsafe.Pointer(p), uintptr(findnullw(p)+1)*unsafe.Sizeof(*p))) + } + + envs = makeStringSlice(int(n)) + + p = env + for i := 0; i < n; i++ { + envs[i] = gostringw(p) + p = (*uint16)(add(unsafe.Pointer(p), uintptr(findnullw(p)+1)*unsafe.Sizeof(*p))) + } + + stdcall1(_FreeEnvironmentStringsW, uintptr(unsafe.Pointer(env))) +} + +//go:nosplit +func exit(code int32) { + stdcall1(_ExitProcess, uintptr(code)) +} + +//go:nosplit +func write(fd uintptr, buf unsafe.Pointer, n int32) int32 { + const ( + _STD_OUTPUT_HANDLE = ^uintptr(10) // -11 + _STD_ERROR_HANDLE = ^uintptr(11) // -12 + ) + var handle uintptr + switch fd { + case 1: + handle = stdcall1(_GetStdHandle, _STD_OUTPUT_HANDLE) + case 2: + handle = stdcall1(_GetStdHandle, _STD_ERROR_HANDLE) + default: + // assume fd is real windows handle. + handle = fd + } + var written uint32 + stdcall5(_WriteFile, handle, uintptr(buf), uintptr(n), uintptr(unsafe.Pointer(&written)), 0) + return int32(written) +} + +//go:nosplit +func semasleep(ns int64) int32 { + // store ms in ns to save stack space + if ns < 0 { + ns = _INFINITE + } else { + ns = int64(timediv(ns, 1000000, nil)) + if ns == 0 { + ns = 1 + } + } + if stdcall2(_WaitForSingleObject, getg().m.waitsema, uintptr(ns)) != 0 { + return -1 // timeout + } + return 0 +} + +//go:nosplit +func semawakeup(mp *m) { + stdcall1(_SetEvent, mp.waitsema) +} + +//go:nosplit +func semacreate() uintptr { + return stdcall4(_CreateEventA, 0, 0, 0, 0) +} + +func newosproc(mp *m, stk unsafe.Pointer) { + const _STACK_SIZE_PARAM_IS_A_RESERVATION = 0x00010000 + thandle := stdcall6(_CreateThread, 0, 0x20000, + funcPC(tstart_stdcall), uintptr(unsafe.Pointer(mp)), + _STACK_SIZE_PARAM_IS_A_RESERVATION, 0) + if thandle == 0 { + println("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", getlasterror(), ")") + gothrow("runtime.newosproc") + } +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the parent thread (main thread in case of bootstrap), can allocate memory. +func mpreinit(mp *m) { +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the new thread, can not allocate memory. +func minit() { + var thandle uintptr + stdcall7(_DuplicateHandle, currentProcess, currentThread, currentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, _DUPLICATE_SAME_ACCESS) + atomicstoreuintptr(&getg().m.thread, thandle) +} + +// Called from dropm to undo the effect of an minit. +func unminit() { + tp := &getg().m.thread + stdcall1(_CloseHandle, *tp) + *tp = 0 +} + +// Described in http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/ +type _KSYSTEM_TIME struct { + LowPart uint32 + High1Time int32 + High2Time int32 +} + +const ( + _INTERRUPT_TIME = 0x7ffe0008 + _SYSTEM_TIME = 0x7ffe0014 +) + +//go:nosplit +func systime(addr uintptr) int64 { + timeaddr := (*_KSYSTEM_TIME)(unsafe.Pointer(addr)) + + var t _KSYSTEM_TIME + for i := 1; i < 10000; i++ { + // these fields must be read in that order (see URL above) + t.High1Time = timeaddr.High1Time + t.LowPart = timeaddr.LowPart + t.High2Time = timeaddr.High2Time + if t.High1Time == t.High2Time { + return int64(t.High1Time)<<32 | int64(t.LowPart) + } + if (i % 100) == 0 { + osyield() + } + } + systemstack(func() { + gothrow("interrupt/system time is changing too fast") + }) + return 0 +} + +//go:nosplit +func unixnano() int64 { + return (systime(_SYSTEM_TIME) - 116444736000000000) * 100 +} + +//go:nosplit +func nanotime() int64 { + return systime(_INTERRUPT_TIME) * 100 +} + +// Calling stdcall on os stack. +//go:nosplit +func stdcall(fn stdFunction) uintptr { + gp := getg() + mp := gp.m + mp.libcall.fn = uintptr(unsafe.Pointer(fn)) + + if mp.profilehz != 0 { + // leave pc/sp for cpu profiler + mp.libcallg = gp + mp.libcallpc = getcallerpc(unsafe.Pointer(&fn)) + // sp must be the last, because once async cpu profiler finds + // all three values to be non-zero, it will use them + mp.libcallsp = getcallersp(unsafe.Pointer(&fn)) + } + asmcgocall(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&mp.libcall)) + mp.libcallsp = 0 + return mp.libcall.r1 +} + +//go:nosplit +func stdcall0(fn stdFunction) uintptr { + mp := getg().m + mp.libcall.n = 0 + mp.libcall.args = uintptr(noescape(unsafe.Pointer(&fn))) // it's unused but must be non-nil, otherwise crashes + return stdcall(fn) +} + +//go:nosplit +func stdcall1(fn stdFunction, a0 uintptr) uintptr { + mp := getg().m + mp.libcall.n = 1 + mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) + return stdcall(fn) +} + +//go:nosplit +func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr { + mp := getg().m + mp.libcall.n = 2 + mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) + return stdcall(fn) +} + +//go:nosplit +func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr { + mp := getg().m + mp.libcall.n = 3 + mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) + return stdcall(fn) +} + +//go:nosplit +func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr { + mp := getg().m + mp.libcall.n = 4 + mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) + return stdcall(fn) +} + +//go:nosplit +func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr { + mp := getg().m + mp.libcall.n = 5 + mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) + return stdcall(fn) +} + +//go:nosplit +func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr { + mp := getg().m + mp.libcall.n = 6 + mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) + return stdcall(fn) +} + +//go:nosplit +func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr { + mp := getg().m + mp.libcall.n = 7 + mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0))) + return stdcall(fn) +} + +// in sys_windows_386.s and sys_windows_amd64.s +func usleep1(usec uint32) + +//go:nosplit +func osyield() { + usleep1(1) +} + +//go:nosplit +func usleep(us uint32) { + // Have 1us units; want 100ns units. + usleep1(10 * us) +} + +func issigpanic(code uint32) uint32 { + switch code { + default: + return 0 + case _EXCEPTION_ACCESS_VIOLATION: + case _EXCEPTION_INT_DIVIDE_BY_ZERO: + case _EXCEPTION_INT_OVERFLOW: + case _EXCEPTION_FLT_DENORMAL_OPERAND: + case _EXCEPTION_FLT_DIVIDE_BY_ZERO: + case _EXCEPTION_FLT_INEXACT_RESULT: + case _EXCEPTION_FLT_OVERFLOW: + case _EXCEPTION_FLT_UNDERFLOW: + case _EXCEPTION_BREAKPOINT: + } + return 1 +} + +func initsig() { + /* + // TODO(brainman): I don't think we need that bit of code + // following line keeps these functions alive at link stage + // if there's a better way please write it here + void *e = runtime·exceptiontramp; + void *f = runtime·firstcontinuetramp; + void *l = runtime·lastcontinuetramp; + USED(e); + USED(f); + USED(l); + */ +} + +func ctrlhandler1(_type uint32) uint32 { + var s uint32 + + switch _type { + case _CTRL_C_EVENT, _CTRL_BREAK_EVENT: + s = _SIGINT + default: + return 0 + } + + if sigsend(s) { + return 1 + } + exit(2) // SIGINT, SIGTERM, etc + return 0 +} + +// in sys_windows_386.s and sys_windows_amd64.s +func profileloop() + +var profiletimer uintptr + +func profilem(mp *m) { + var r *context + rbuf := make([]byte, unsafe.Sizeof(*r)+15) + + tls := &mp.tls[0] + if mp == &m0 { + tls = &tls0[0] + } + gp := *((**g)(unsafe.Pointer(tls))) + + // align Context to 16 bytes + r = (*context)(unsafe.Pointer((uintptr(unsafe.Pointer(&rbuf[15]))) &^ 15)) + r.contextflags = _CONTEXT_CONTROL + stdcall2(_GetThreadContext, mp.thread, uintptr(unsafe.Pointer(r))) + dosigprof(r, gp, mp) +} + +func profileloop1() { + stdcall2(_SetThreadPriority, currentThread, _THREAD_PRIORITY_HIGHEST) + + for { + stdcall2(_WaitForSingleObject, profiletimer, _INFINITE) + first := (*m)(atomicloadp(unsafe.Pointer(&allm))) + for mp := first; mp != nil; mp = mp.alllink { + thread := atomicloaduintptr(&mp.thread) + // Do not profile threads blocked on Notes, + // this includes idle worker threads, + // idle timer thread, idle heap scavenger, etc. + if thread == 0 || mp.profilehz == 0 || mp.blocked { + continue + } + stdcall1(_SuspendThread, thread) + if mp.profilehz != 0 && !mp.blocked { + profilem(mp) + } + stdcall1(_ResumeThread, thread) + } + } +} + +var cpuprofilerlock mutex + +func resetcpuprofiler(hz int32) { + lock(&cpuprofilerlock) + if profiletimer == 0 { + timer := stdcall3(_CreateWaitableTimerA, 0, 0, 0) + atomicstoreuintptr(&profiletimer, timer) + thread := stdcall6(_CreateThread, 0, 0, funcPC(profileloop), 0, 0, 0) + stdcall2(_SetThreadPriority, thread, _THREAD_PRIORITY_HIGHEST) + stdcall1(_CloseHandle, thread) + } + unlock(&cpuprofilerlock) + + ms := int32(0) + due := ^int64(^uint64(1 << 63)) + if hz > 0 { + ms = 1000 / hz + if ms == 0 { + ms = 1 + } + due = int64(ms) * -10000 + } + stdcall6(_SetWaitableTimer, profiletimer, uintptr(unsafe.Pointer(&due)), uintptr(ms), 0, 0, 0) + atomicstore((*uint32)(unsafe.Pointer(&getg().m.profilehz)), uint32(hz)) +} + +func memlimit() uintptr { + return 0 +} + +var ( + badsignalmsg [100]byte + badsignallen int32 +) + +func setBadSignalMsg() { + const msg = "runtime: signal received on thread not created by Go.\n" + for i, c := range msg { + badsignalmsg[i] = byte(c) + badsignallen++ + } +} + +func crash() { + // TODO: This routine should do whatever is needed + // to make the Windows program abort/crash as it + // would if Go was not intercepting signals. + // On Unix the routine would remove the custom signal + // handler and then raise a signal (like SIGABRT). + // Something like that should happen here. + // It's okay to leave this empty for now: if crash returns + // the ordinary exit-after-panic happens. +} diff --git a/src/runtime/os1_windows_386.go b/src/runtime/os1_windows_386.go new file mode 100644 index 000000000..0afef9156 --- /dev/null +++ b/src/runtime/os1_windows_386.go @@ -0,0 +1,118 @@ +// 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. + +package runtime + +import ( + "unsafe" +) + +var text struct{} + +func dumpregs(r *context) { + print("eax ", hex(r.eax), "\n") + print("ebx ", hex(r.ebx), "\n") + print("ecx ", hex(r.ecx), "\n") + print("edx ", hex(r.edx), "\n") + print("edi ", hex(r.edi), "\n") + print("esi ", hex(r.esi), "\n") + print("ebp ", hex(r.ebp), "\n") + print("esp ", hex(r.esp), "\n") + print("eip ", hex(r.eip), "\n") + print("eflags ", hex(r.eflags), "\n") + print("cs ", hex(r.segcs), "\n") + print("fs ", hex(r.segfs), "\n") + print("gs ", hex(r.seggs), "\n") +} + +func isgoexception(info *exceptionrecord, r *context) bool { + // Only handle exception if executing instructions in Go binary + // (not Windows library code). + if r.eip < uint32(uintptr(unsafe.Pointer(&text))) || uint32(uintptr(unsafe.Pointer(&etext))) < r.eip { + return false + } + + if issigpanic(info.exceptioncode) == 0 { + return false + } + + return true +} + +// Called by sigtramp from Windows VEH handler. +// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION) +// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH). +func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 { + if !isgoexception(info, r) { + return _EXCEPTION_CONTINUE_SEARCH + } + + // Make it look like a call to the signal func. + // Have to pass arguments out of band since + // augmenting the stack frame would break + // the unwinding code. + gp.sig = info.exceptioncode + gp.sigcode0 = uintptr(info.exceptioninformation[0]) + gp.sigcode1 = uintptr(info.exceptioninformation[1]) + gp.sigpc = uintptr(r.eip) + + // Only push runtime·sigpanic if r->eip != 0. + // If r->eip == 0, probably panicked because of a + // call to a nil func. Not pushing that onto sp will + // make the trace look like a call to runtime·sigpanic instead. + // (Otherwise the trace will end at runtime·sigpanic and we + // won't get to see who faulted.) + if r.eip != 0 { + sp := unsafe.Pointer(uintptr(r.esp)) + sp = add(sp, ^uintptr(unsafe.Sizeof(uintptr(0))-1)) // sp-- + *((*uintptr)(sp)) = uintptr(r.eip) + r.esp = uint32(uintptr(sp)) + } + r.eip = uint32(funcPC(sigpanic)) + return _EXCEPTION_CONTINUE_EXECUTION +} + +// lastcontinuehandler is reached, because runtime cannot handle +// current exception. lastcontinuehandler will print crash info and exit. +func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) uint32 { + _g_ := getg() + + if panicking != 0 { // traceback already printed + exit(2) + } + panicking = 1 + + print("Exception ", hex(info.exceptioncode), " ", hex(info.exceptioninformation[0]), " ", hex(info.exceptioninformation[1]), " ", hex(r.eip), "\n") + + print("PC=", hex(r.eip), "\n") + if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 { + print("signal arrived during cgo execution\n") + gp = _g_.m.lockedg + } + print("\n") + + var docrash bool + if gotraceback(&docrash) > 0 { + tracebacktrap(uintptr(r.eip), uintptr(r.esp), 0, gp) + tracebackothers(gp) + dumpregs(r) + } + + if docrash { + crash() + } + + exit(2) + return 0 // not reached +} + +func sigenable(sig uint32) { +} + +func sigdisable(sig uint32) { +} + +func dosigprof(r *context, gp *g, mp *m) { + sigprof((*byte)(unsafe.Pointer(uintptr(r.eip))), (*byte)(unsafe.Pointer(uintptr(r.esp))), nil, gp, mp) +} diff --git a/src/runtime/os1_windows_amd64.go b/src/runtime/os1_windows_amd64.go new file mode 100644 index 000000000..0d21b3881 --- /dev/null +++ b/src/runtime/os1_windows_amd64.go @@ -0,0 +1,137 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import ( + "unsafe" +) + +var text struct{} + +func dumpregs(r *context) { + print("rax ", hex(r.rax), "\n") + print("rbx ", hex(r.rbx), "\n") + print("rcx ", hex(r.rcx), "\n") + print("rdi ", hex(r.rdi), "\n") + print("rsi ", hex(r.rsi), "\n") + print("rbp ", hex(r.rbp), "\n") + print("rsp ", hex(r.rsp), "\n") + print("r8 ", hex(r.r8), "\n") + print("r9 ", hex(r.r9), "\n") + print("r10 ", hex(r.r10), "\n") + print("r11 ", hex(r.r11), "\n") + print("r12 ", hex(r.r12), "\n") + print("r13 ", hex(r.r13), "\n") + print("r14 ", hex(r.r14), "\n") + print("r15 ", hex(r.r15), "\n") + print("rip ", hex(r.rip), "\n") + print("rflags ", hex(r.eflags), "\n") + print("cs ", hex(r.segcs), "\n") + print("fs ", hex(r.segfs), "\n") + print("gs ", hex(r.seggs), "\n") +} + +func isgoexception(info *exceptionrecord, r *context) bool { + // Only handle exception if executing instructions in Go binary + // (not Windows library code). + if r.rip < uint64(uintptr(unsafe.Pointer(&text))) || uint64(uintptr(unsafe.Pointer(&etext))) < r.rip { + return false + } + + if issigpanic(info.exceptioncode) == 0 { + return false + } + + return true +} + +// Called by sigtramp from Windows VEH handler. +// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION) +// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH). + +func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 { + if !isgoexception(info, r) { + return _EXCEPTION_CONTINUE_SEARCH + } + + // Make it look like a call to the signal func. + // Have to pass arguments out of band since + // augmenting the stack frame would break + // the unwinding code. + gp.sig = info.exceptioncode + gp.sigcode0 = uintptr(info.exceptioninformation[0]) + gp.sigcode1 = uintptr(info.exceptioninformation[1]) + gp.sigpc = uintptr(r.rip) + + // Only push runtime·sigpanic if r->rip != 0. + // If r->rip == 0, probably panicked because of a + // call to a nil func. Not pushing that onto sp will + // make the trace look like a call to runtime·sigpanic instead. + // (Otherwise the trace will end at runtime·sigpanic and we + // won't get to see who faulted.) + if r.rip != 0 { + sp := unsafe.Pointer(uintptr(r.rsp)) + sp = add(sp, ^uintptr(unsafe.Sizeof(uintptr(0))-1)) // sp-- + *((*uintptr)(sp)) = uintptr(r.rip) + r.rsp = uint64(uintptr(sp)) + } + r.rip = uint64(funcPC(sigpanic)) + return _EXCEPTION_CONTINUE_EXECUTION +} + +// It seems Windows searches ContinueHandler's list even +// if ExceptionHandler returns EXCEPTION_CONTINUE_EXECUTION. +// firstcontinuehandler will stop that search, +// if exceptionhandler did the same earlier. +func firstcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 { + if !isgoexception(info, r) { + return _EXCEPTION_CONTINUE_SEARCH + } + return _EXCEPTION_CONTINUE_EXECUTION +} + +// lastcontinuehandler is reached, because runtime cannot handle +// current exception. lastcontinuehandler will print crash info and exit. +func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) uint32 { + _g_ := getg() + + if panicking != 0 { // traceback already printed + exit(2) + } + panicking = 1 + + print("Exception ", hex(info.exceptioncode), " ", hex(info.exceptioninformation[0]), " ", hex(info.exceptioninformation[1]), " ", hex(r.rip), "\n") + + print("PC=", hex(r.rip), "\n") + if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 { + print("signal arrived during cgo execution\n") + gp = _g_.m.lockedg + } + print("\n") + + var docrash bool + if gotraceback(&docrash) > 0 { + tracebacktrap(uintptr(r.rip), uintptr(r.rsp), 0, gp) + tracebackothers(gp) + dumpregs(r) + } + + if docrash { + crash() + } + + exit(2) + return 0 // not reached +} + +func sigenable(sig uint32) { +} + +func sigdisable(sig uint32) { +} + +func dosigprof(r *context, gp *g, mp *m) { + sigprof((*byte)(unsafe.Pointer(uintptr(r.rip))), (*byte)(unsafe.Pointer(uintptr(r.rsp))), nil, gp, mp) +} diff --git a/src/runtime/os2_nacl.go b/src/runtime/os2_nacl.go new file mode 100644 index 000000000..0c91e0f73 --- /dev/null +++ b/src/runtime/os2_nacl.go @@ -0,0 +1,154 @@ +// 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 runtime + +const ( + _NSIG = 32 + _SI_USER = 1 + + // native_client/src/trusted/service_runtime/include/sys/errno.h + // The errors are mainly copied from Linux. + _EPERM = 1 /* Operation not permitted */ + _ENOENT = 2 /* No such file or directory */ + _ESRCH = 3 /* No such process */ + _EINTR = 4 /* Interrupted system call */ + _EIO = 5 /* I/O error */ + _ENXIO = 6 /* No such device or address */ + _E2BIG = 7 /* Argument list too long */ + _ENOEXEC = 8 /* Exec format error */ + _EBADF = 9 /* Bad file number */ + _ECHILD = 10 /* No child processes */ + _EAGAIN = 11 /* Try again */ + _ENOMEM = 12 /* Out of memory */ + _EACCES = 13 /* Permission denied */ + _EFAULT = 14 /* Bad address */ + _EBUSY = 16 /* Device or resource busy */ + _EEXIST = 17 /* File exists */ + _EXDEV = 18 /* Cross-device link */ + _ENODEV = 19 /* No such device */ + _ENOTDIR = 20 /* Not a directory */ + _EISDIR = 21 /* Is a directory */ + _EINVAL = 22 /* Invalid argument */ + _ENFILE = 23 /* File table overflow */ + _EMFILE = 24 /* Too many open files */ + _ENOTTY = 25 /* Not a typewriter */ + _EFBIG = 27 /* File too large */ + _ENOSPC = 28 /* No space left on device */ + _ESPIPE = 29 /* Illegal seek */ + _EROFS = 30 /* Read-only file system */ + _EMLINK = 31 /* Too many links */ + _EPIPE = 32 /* Broken pipe */ + _ENAMETOOLONG = 36 /* File name too long */ + _ENOSYS = 38 /* Function not implemented */ + _EDQUOT = 122 /* Quota exceeded */ + _EDOM = 33 /* Math arg out of domain of func */ + _ERANGE = 34 /* Math result not representable */ + _EDEADLK = 35 /* Deadlock condition */ + _ENOLCK = 37 /* No record locks available */ + _ENOTEMPTY = 39 /* Directory not empty */ + _ELOOP = 40 /* Too many symbolic links */ + _ENOMSG = 42 /* No message of desired type */ + _EIDRM = 43 /* Identifier removed */ + _ECHRNG = 44 /* Channel number out of range */ + _EL2NSYNC = 45 /* Level 2 not synchronized */ + _EL3HLT = 46 /* Level 3 halted */ + _EL3RST = 47 /* Level 3 reset */ + _ELNRNG = 48 /* Link number out of range */ + _EUNATCH = 49 /* Protocol driver not attached */ + _ENOCSI = 50 /* No CSI structure available */ + _EL2HLT = 51 /* Level 2 halted */ + _EBADE = 52 /* Invalid exchange */ + _EBADR = 53 /* Invalid request descriptor */ + _EXFULL = 54 /* Exchange full */ + _ENOANO = 55 /* No anode */ + _EBADRQC = 56 /* Invalid request code */ + _EBADSLT = 57 /* Invalid slot */ + _EDEADLOCK = _EDEADLK /* File locking deadlock error */ + _EBFONT = 59 /* Bad font file fmt */ + _ENOSTR = 60 /* Device not a stream */ + _ENODATA = 61 /* No data (for no delay io) */ + _ETIME = 62 /* Timer expired */ + _ENOSR = 63 /* Out of streams resources */ + _ENONET = 64 /* Machine is not on the network */ + _ENOPKG = 65 /* Package not installed */ + _EREMOTE = 66 /* The object is remote */ + _ENOLINK = 67 /* The link has been severed */ + _EADV = 68 /* Advertise error */ + _ESRMNT = 69 /* Srmount error */ + _ECOMM = 70 /* Communication error on send */ + _EPROTO = 71 /* Protocol error */ + _EMULTIHOP = 72 /* Multihop attempted */ + _EDOTDOT = 73 /* Cross mount point (not really error) */ + _EBADMSG = 74 /* Trying to read unreadable message */ + _EOVERFLOW = 75 /* Value too large for defined data type */ + _ENOTUNIQ = 76 /* Given log. name not unique */ + _EBADFD = 77 /* f.d. invalid for this operation */ + _EREMCHG = 78 /* Remote address changed */ + _ELIBACC = 79 /* Can't access a needed shared lib */ + _ELIBBAD = 80 /* Accessing a corrupted shared lib */ + _ELIBSCN = 81 /* .lib section in a.out corrupted */ + _ELIBMAX = 82 /* Attempting to link in too many libs */ + _ELIBEXEC = 83 /* Attempting to exec a shared library */ + _EILSEQ = 84 + _EUSERS = 87 + _ENOTSOCK = 88 /* Socket operation on non-socket */ + _EDESTADDRREQ = 89 /* Destination address required */ + _EMSGSIZE = 90 /* Message too long */ + _EPROTOTYPE = 91 /* Protocol wrong type for socket */ + _ENOPROTOOPT = 92 /* Protocol not available */ + _EPROTONOSUPPORT = 93 /* Unknown protocol */ + _ESOCKTNOSUPPORT = 94 /* Socket type not supported */ + _EOPNOTSUPP = 95 /* Operation not supported on transport endpoint */ + _EPFNOSUPPORT = 96 /* Protocol family not supported */ + _EAFNOSUPPORT = 97 /* Address family not supported by protocol family */ + _EADDRINUSE = 98 /* Address already in use */ + _EADDRNOTAVAIL = 99 /* Address not available */ + _ENETDOWN = 100 /* Network interface is not configured */ + _ENETUNREACH = 101 /* Network is unreachable */ + _ENETRESET = 102 + _ECONNABORTED = 103 /* Connection aborted */ + _ECONNRESET = 104 /* Connection reset by peer */ + _ENOBUFS = 105 /* No buffer space available */ + _EISCONN = 106 /* Socket is already connected */ + _ENOTCONN = 107 /* Socket is not connected */ + _ESHUTDOWN = 108 /* Can't send after socket shutdown */ + _ETOOMANYREFS = 109 + _ETIMEDOUT = 110 /* Connection timed out */ + _ECONNREFUSED = 111 /* Connection refused */ + _EHOSTDOWN = 112 /* Host is down */ + _EHOSTUNREACH = 113 /* Host is unreachable */ + _EALREADY = 114 /* Socket already connected */ + _EINPROGRESS = 115 /* Connection already in progress */ + _ESTALE = 116 + _ENOTSUP = _EOPNOTSUPP /* Not supported */ + _ENOMEDIUM = 123 /* No medium (in tape drive) */ + _ECANCELED = 125 /* Operation canceled. */ + _ELBIN = 2048 /* Inode is remote (not really error) */ + _EFTYPE = 2049 /* Inappropriate file type or format */ + _ENMFILE = 2050 /* No more files */ + _EPROCLIM = 2051 + _ENOSHARE = 2052 /* No such host or network path */ + _ECASECLASH = 2053 /* Filename exists with different case */ + _EWOULDBLOCK = _EAGAIN /* Operation would block */ + + // native_client/src/trusted/service_runtime/include/bits/mman.h. + // NOTE: DO NOT USE native_client/src/shared/imc/nacl_imc_c.h. + // Those MAP_*values are different from these. + _PROT_NONE = 0x0 + _PROT_READ = 0x1 + _PROT_WRITE = 0x2 + _PROT_EXEC = 0x4 + + _MAP_SHARED = 0x1 + _MAP_PRIVATE = 0x2 + _MAP_FIXED = 0x10 + _MAP_ANON = 0x20 + + _MADV_FREE = 0 + _SIGFPE = 8 + _FPE_INTDIV = 0 +) + +type siginfo struct{} diff --git a/src/runtime/os2_netbsd.go b/src/runtime/os2_netbsd.go new file mode 100644 index 000000000..46576b9bc --- /dev/null +++ b/src/runtime/os2_netbsd.go @@ -0,0 +1,18 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +const ( + _SS_DISABLE = 4 + _SIG_BLOCK = 1 + _SIG_UNBLOCK = 2 + _SIG_SETMASK = 3 + _NSIG = 33 + _SI_USER = 0 + + // From NetBSD's <sys/ucontext.h> + _UC_SIGMASK = 0x01 + _UC_CPU = 0x04 +) diff --git a/src/runtime/os2_plan9.go b/src/runtime/os2_plan9.go new file mode 100644 index 000000000..f64f4c8da --- /dev/null +++ b/src/runtime/os2_plan9.go @@ -0,0 +1,72 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Plan 9-specific system calls + +package runtime + +// open +const ( + _OREAD = 0 + _OWRITE = 1 + _ORDWR = 2 + _OEXEC = 3 + _OTRUNC = 16 + _OCEXEC = 32 + _ORCLOSE = 64 + _OEXCL = 0x1000 +) + +// rfork +const ( + _RFNAMEG = 1 << 0 + _RFENVG = 1 << 1 + _RFFDG = 1 << 2 + _RFNOTEG = 1 << 3 + _RFPROC = 1 << 4 + _RFMEM = 1 << 5 + _RFNOWAIT = 1 << 6 + _RFCNAMEG = 1 << 10 + _RFCENVG = 1 << 11 + _RFCFDG = 1 << 12 + _RFREND = 1 << 13 + _RFNOMNT = 1 << 14 +) + +// notify +const ( + _NCONT = 0 + _NDFLT = 1 +) + +type uinptr _Plink + +type tos struct { + prof struct { // Per process profiling + pp *_Plink // known to be 0(ptr) + next *_Plink // known to be 4(ptr) + last *_Plink + first *_Plink + pid uint32 + what uint32 + } + cyclefreq uint64 // cycle clock frequency if there is one, 0 otherwise + kcycles int64 // cycles spent in kernel + pcycles int64 // cycles spent in process (kernel + user) + pid uint32 // might as well put the pid here + clock uint32 + // top of stack is here +} + +const ( + _NSIG = 14 // number of signals in sigtable array + _ERRMAX = 128 // max length of note string + + // Notes in runtime·sigtab that are handled by runtime·sigpanic. + _SIGRFAULT = 2 + _SIGWFAULT = 3 + _SIGINTDIV = 4 + _SIGFLOAT = 5 + _SIGTRAP = 6 +) diff --git a/src/runtime/os2_windows.go b/src/runtime/os2_windows.go new file mode 100644 index 000000000..d5b1f471f --- /dev/null +++ b/src/runtime/os2_windows.go @@ -0,0 +1,25 @@ +// 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. + +package runtime + +import "unsafe" + +// Call a Windows function with stdcall conventions, +// and switch to os stack during the call. +func asmstdcall(fn unsafe.Pointer) + +func getlasterror() uint32 +func setlasterror(err uint32) + +// Function to be called by windows CreateThread +// to start new os thread. +func tstart_stdcall(newm *m) uint32 + +func ctrlhandler(_type uint32) uint32 + +// TODO(brainman): should not need those +const ( + _NSIG = 65 +) diff --git a/src/runtime/os_android.h b/src/runtime/os_android.h deleted file mode 100644 index c7c1098e8..000000000 --- a/src/runtime/os_android.h +++ /dev/null @@ -1 +0,0 @@ -#include "os_linux.h" diff --git a/src/runtime/os_android.c b/src/runtime/os_android_arm.go index 5805f6871..132832236 100644 --- a/src/runtime/os_android.c +++ b/src/runtime/os_android_arm.go @@ -2,15 +2,14 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" +package runtime + +import _ "unsafe" // Export the runtime entry point symbol. // // Used by the app package to start the Go runtime after loading // a shared library via JNI. See golang.org/x/mobile/app. -void _rt0_arm_linux1(); -#pragma cgo_export_static _rt0_arm_linux1 -#pragma cgo_export_dynamic _rt0_arm_linux1 +//go:cgo_export_static _rt0_arm_linux1 +//go:cgo_export_dynamic _rt0_arm_linux1 diff --git a/src/runtime/os_nacl.c b/src/runtime/os_nacl.c deleted file mode 100644 index ad72cc7c6..000000000 --- a/src/runtime/os_nacl.c +++ /dev/null @@ -1,315 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "arch_GOARCH.h" -#include "textflag.h" -#include "stack.h" - -int8 *goos = "nacl"; -extern SigTab runtime·sigtab[]; - -void runtime·sigtramp(void); - -// Called to initialize a new m (including the bootstrap m). -// Called on the parent thread (main thread in case of bootstrap), can allocate memory. -void -runtime·mpreinit(M *mp) -{ - mp->gsignal = runtime·malg(32*1024); // OS X wants >=8K, Linux >=2K - runtime·writebarrierptr_nostore(&mp->gsignal, mp->gsignal); - - mp->gsignal->m = mp; - runtime·writebarrierptr_nostore(&mp->gsignal->m, mp->gsignal->m); -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the new thread, can not allocate memory. -void -runtime·minit(void) -{ - int32 ret; - - // Initialize signal handling - ret = runtime·nacl_exception_stack((byte*)g->m->gsignal->stack.lo, 32*1024); - if(ret < 0) - runtime·printf("runtime: nacl_exception_stack: error %d\n", -ret); - - ret = runtime·nacl_exception_handler(runtime·sigtramp, nil); - if(ret < 0) - runtime·printf("runtime: nacl_exception_handler: error %d\n", -ret); -} - -// Called from dropm to undo the effect of an minit. -void -runtime·unminit(void) -{ -} - -int8 runtime·sigtrampf[] = "runtime: signal at PC=%X AX=%X CX=%X DX=%X BX=%X DI=%X R15=%X *SP=%X\n"; -int8 runtime·sigtrampp[] = "runtime: sigtramp"; - -extern byte runtime·tls0[]; - -void -runtime·osinit(void) -{ - runtime·ncpu = 1; - g->m->procid = 2; -//runtime·nacl_exception_handler(runtime·sigtramp, nil); -} - -void -runtime·crash(void) -{ - *(int32*)0 = 0; -} - -#pragma textflag NOSPLIT -void -runtime·get_random_data(byte **rnd, int32 *rnd_len) -{ - *rnd = nil; - *rnd_len = 0; -} - -void -runtime·goenvs(void) -{ - runtime·goenvs_unix(); -} - -void -runtime·initsig(void) -{ -} - -#pragma textflag NOSPLIT -void -runtime·usleep(uint32 us) -{ - Timespec ts; - - ts.tv_sec = us/1000000; - ts.tv_nsec = (us%1000000)*1000; - runtime·nacl_nanosleep(&ts, nil); -} - -void runtime·mstart_nacl(void); - -void -runtime·newosproc(M *mp, void *stk) -{ - int32 ret; - void **tls; - - tls = (void**)mp->tls; - tls[0] = mp->g0; - tls[1] = mp; - ret = runtime·nacl_thread_create(runtime·mstart_nacl, stk, tls+2, 0); - if(ret < 0) { - runtime·printf("nacl_thread_create: error %d\n", -ret); - runtime·throw("newosproc"); - } -} - -static void -semacreate(void) -{ - int32 mu, cond; - - mu = runtime·nacl_mutex_create(0); - if(mu < 0) { - runtime·printf("nacl_mutex_create: error %d\n", -mu); - runtime·throw("semacreate"); - } - cond = runtime·nacl_cond_create(0); - if(cond < 0) { - runtime·printf("nacl_cond_create: error %d\n", -cond); - runtime·throw("semacreate"); - } - g->m->waitsemalock = mu; - g->m->scalararg[0] = cond; // assigned to m->waitsema -} - -#pragma textflag NOSPLIT -uint32 -runtime·semacreate(void) -{ - void (*fn)(void); - uint32 x; - - fn = semacreate; - runtime·onM(&fn); - x = g->m->scalararg[0]; - g->m->scalararg[0] = 0; - return x; -} - -static void -semasleep(void) -{ - int32 ret; - int64 ns; - - ns = (int64)(uint32)g->m->scalararg[0] | (int64)(uint32)g->m->scalararg[1]<<32; - g->m->scalararg[0] = 0; - g->m->scalararg[1] = 0; - - ret = runtime·nacl_mutex_lock(g->m->waitsemalock); - if(ret < 0) { - //runtime·printf("nacl_mutex_lock: error %d\n", -ret); - runtime·throw("semasleep"); - } - if(g->m->waitsemacount > 0) { - g->m->waitsemacount = 0; - runtime·nacl_mutex_unlock(g->m->waitsemalock); - g->m->scalararg[0] = 0; - return; - } - - while(g->m->waitsemacount == 0) { - if(ns < 0) { - ret = runtime·nacl_cond_wait(g->m->waitsema, g->m->waitsemalock); - if(ret < 0) { - //runtime·printf("nacl_cond_wait: error %d\n", -ret); - runtime·throw("semasleep"); - } - } else { - Timespec ts; - - ns += runtime·nanotime(); - ts.tv_sec = runtime·timediv(ns, 1000000000, (int32*)&ts.tv_nsec); - ret = runtime·nacl_cond_timed_wait_abs(g->m->waitsema, g->m->waitsemalock, &ts); - if(ret == -ETIMEDOUT) { - runtime·nacl_mutex_unlock(g->m->waitsemalock); - g->m->scalararg[0] = -1; - return; - } - if(ret < 0) { - //runtime·printf("nacl_cond_timed_wait_abs: error %d\n", -ret); - runtime·throw("semasleep"); - } - } - } - - g->m->waitsemacount = 0; - runtime·nacl_mutex_unlock(g->m->waitsemalock); - g->m->scalararg[0] = 0; -} - -#pragma textflag NOSPLIT -int32 -runtime·semasleep(int64 ns) -{ - int32 r; - void (*fn)(void); - - g->m->scalararg[0] = (uint32)ns; - g->m->scalararg[1] = (uint32)(ns>>32); - fn = semasleep; - runtime·onM(&fn); - r = g->m->scalararg[0]; - g->m->scalararg[0] = 0; - return r; -} - -static void -semawakeup(void) -{ - int32 ret; - M *mp; - - mp = g->m->ptrarg[0]; - g->m->ptrarg[0] = nil; - - ret = runtime·nacl_mutex_lock(mp->waitsemalock); - if(ret < 0) { - //runtime·printf("nacl_mutex_lock: error %d\n", -ret); - runtime·throw("semawakeup"); - } - if(mp->waitsemacount != 0) { - //runtime·printf("semawakeup: double wakeup\n"); - runtime·throw("semawakeup"); - } - mp->waitsemacount = 1; - runtime·nacl_cond_signal(mp->waitsema); - runtime·nacl_mutex_unlock(mp->waitsemalock); -} - -#pragma textflag NOSPLIT -void -runtime·semawakeup(M *mp) -{ - void (*fn)(void); - - g->m->ptrarg[0] = mp; - fn = semawakeup; - runtime·onM(&fn); -} - -uintptr -runtime·memlimit(void) -{ - runtime·printf("memlimit\n"); - return 0; -} - -#pragma dataflag NOPTR -static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n"; - -// This runs on a foreign stack, without an m or a g. No stack split. -#pragma textflag NOSPLIT -void -runtime·badsignal2(void) -{ - runtime·write(2, badsignal, sizeof badsignal - 1); - runtime·exit(2); -} - -void runtime·madvise(byte*, uintptr, int32) { } -void runtime·munmap(byte*, uintptr) {} - -void -runtime·resetcpuprofiler(int32 hz) -{ - USED(hz); -} - -void -runtime·sigdisable(uint32) -{ -} - -void -runtime·sigenable(uint32) -{ -} - -void -runtime·closeonexec(int32) -{ -} - -uint32 runtime·writelock; // test-and-set spin lock for runtime.write - -/* -An attempt at IRT. Doesn't work. See end of sys_nacl_amd64.s. - -void (*runtime·nacl_irt_query)(void); - -int8 runtime·nacl_irt_basic_v0_1_str[] = "nacl-irt-basic-0.1"; -void *runtime·nacl_irt_basic_v0_1[6]; // exit, gettod, clock, nanosleep, sched_yield, sysconf -int32 runtime·nacl_irt_basic_v0_1_size = sizeof(runtime·nacl_irt_basic_v0_1); - -int8 runtime·nacl_irt_memory_v0_3_str[] = "nacl-irt-memory-0.3"; -void *runtime·nacl_irt_memory_v0_3[3]; // mmap, munmap, mprotect -int32 runtime·nacl_irt_memory_v0_3_size = sizeof(runtime·nacl_irt_memory_v0_3); - -int8 runtime·nacl_irt_thread_v0_1_str[] = "nacl-irt-thread-0.1"; -void *runtime·nacl_irt_thread_v0_1[3]; // thread_create, thread_exit, thread_nice -int32 runtime·nacl_irt_thread_v0_1_size = sizeof(runtime·nacl_irt_thread_v0_1); -*/ diff --git a/src/runtime/os_nacl.go b/src/runtime/os_nacl.go index 8dd43ff06..eff9ec30e 100644 --- a/src/runtime/os_nacl.go +++ b/src/runtime/os_nacl.go @@ -6,8 +6,8 @@ package runtime import "unsafe" -func nacl_exception_stack(p unsafe.Pointer, size int32) int32 -func nacl_exception_handler(fn, arg unsafe.Pointer) int32 +func nacl_exception_stack(p uintptr, size int32) int32 +func nacl_exception_handler(fn uintptr, arg unsafe.Pointer) int32 func nacl_sem_create(flag int32) int32 func nacl_sem_wait(sem int32) int32 func nacl_sem_post(sem int32) int32 @@ -19,9 +19,20 @@ func nacl_cond_create(flag int32) int32 func nacl_cond_wait(cond, n int32) int32 func nacl_cond_signal(cond int32) int32 func nacl_cond_broadcast(cond int32) int32 -func nacl_cond_timed_wait_abs(cond, lock int32, ts unsafe.Pointer) int32 -func nacl_thread_create(fn, stk, tls, xx unsafe.Pointer) int32 -func nacl_nanosleep(ts, extra unsafe.Pointer) int32 + +//go:noescape +func nacl_cond_timed_wait_abs(cond, lock int32, ts *timespec) int32 +func nacl_thread_create(fn uintptr, stk, tls, xx unsafe.Pointer) int32 + +//go:noescape +func nacl_nanosleep(ts, extra *timespec) int32 +func nanotime() int64 +func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer +func exit(code int32) +func osyield() + +//go:noescape +func write(fd uintptr, p unsafe.Pointer, n int32) int32 func os_sigpipe() { gothrow("too many writes on closed pipe") diff --git a/src/runtime/os_nacl.h b/src/runtime/os_nacl.h deleted file mode 100644 index 7c9d9c242..000000000 --- a/src/runtime/os_nacl.h +++ /dev/null @@ -1,162 +0,0 @@ -enum { - NSIG = 32, - SI_USER = 1, - - // native_client/src/trusted/service_runtime/include/sys/errno.h - // The errors are mainly copied from Linux. - EPERM = 1, /* Operation not permitted */ - ENOENT = 2, /* No such file or directory */ - ESRCH = 3, /* No such process */ - EINTR = 4, /* Interrupted system call */ - EIO = 5, /* I/O error */ - ENXIO = 6, /* No such device or address */ - E2BIG = 7, /* Argument list too long */ - ENOEXEC = 8, /* Exec format error */ - EBADF = 9, /* Bad file number */ - ECHILD = 10, /* No child processes */ - EAGAIN = 11, /* Try again */ - ENOMEM = 12, /* Out of memory */ - EACCES = 13, /* Permission denied */ - EFAULT = 14, /* Bad address */ - EBUSY = 16, /* Device or resource busy */ - EEXIST = 17, /* File exists */ - EXDEV = 18, /* Cross-device link */ - ENODEV = 19, /* No such device */ - ENOTDIR = 20, /* Not a directory */ - EISDIR = 21, /* Is a directory */ - EINVAL = 22, /* Invalid argument */ - ENFILE = 23, /* File table overflow */ - EMFILE = 24, /* Too many open files */ - ENOTTY = 25, /* Not a typewriter */ - EFBIG = 27, /* File too large */ - ENOSPC = 28, /* No space left on device */ - ESPIPE = 29, /* Illegal seek */ - EROFS = 30, /* Read-only file system */ - EMLINK = 31, /* Too many links */ - EPIPE = 32, /* Broken pipe */ - ENAMETOOLONG = 36, /* File name too long */ - ENOSYS = 38, /* Function not implemented */ - EDQUOT = 122, /* Quota exceeded */ - EDOM = 33, /* Math arg out of domain of func */ - ERANGE = 34, /* Math result not representable */ - EDEADLK = 35, /* Deadlock condition */ - ENOLCK = 37, /* No record locks available */ - ENOTEMPTY = 39, /* Directory not empty */ - ELOOP = 40, /* Too many symbolic links */ - ENOMSG = 42, /* No message of desired type */ - EIDRM = 43, /* Identifier removed */ - ECHRNG = 44, /* Channel number out of range */ - EL2NSYNC = 45, /* Level 2 not synchronized */ - EL3HLT = 46, /* Level 3 halted */ - EL3RST = 47, /* Level 3 reset */ - ELNRNG = 48, /* Link number out of range */ - EUNATCH = 49, /* Protocol driver not attached */ - ENOCSI = 50, /* No CSI structure available */ - EL2HLT = 51, /* Level 2 halted */ - EBADE = 52, /* Invalid exchange */ - EBADR = 53, /* Invalid request descriptor */ - EXFULL = 54, /* Exchange full */ - ENOANO = 55, /* No anode */ - EBADRQC = 56, /* Invalid request code */ - EBADSLT = 57, /* Invalid slot */ - EDEADLOCK = EDEADLK, /* File locking deadlock error */ - EBFONT = 59, /* Bad font file fmt */ - ENOSTR = 60, /* Device not a stream */ - ENODATA = 61, /* No data (for no delay io) */ - ETIME = 62, /* Timer expired */ - ENOSR = 63, /* Out of streams resources */ - ENONET = 64, /* Machine is not on the network */ - ENOPKG = 65, /* Package not installed */ - EREMOTE = 66, /* The object is remote */ - ENOLINK = 67, /* The link has been severed */ - EADV = 68, /* Advertise error */ - ESRMNT = 69, /* Srmount error */ - ECOMM = 70, /* Communication error on send */ - EPROTO = 71, /* Protocol error */ - EMULTIHOP = 72, /* Multihop attempted */ - EDOTDOT = 73, /* Cross mount point (not really error) */ - EBADMSG = 74, /* Trying to read unreadable message */ - EOVERFLOW = 75, /* Value too large for defined data type */ - ENOTUNIQ = 76, /* Given log. name not unique */ - EBADFD = 77, /* f.d. invalid for this operation */ - EREMCHG = 78, /* Remote address changed */ - ELIBACC = 79, /* Can't access a needed shared lib */ - ELIBBAD = 80, /* Accessing a corrupted shared lib */ - ELIBSCN = 81, /* .lib section in a.out corrupted */ - ELIBMAX = 82, /* Attempting to link in too many libs */ - ELIBEXEC = 83, /* Attempting to exec a shared library */ - EILSEQ = 84, - EUSERS = 87, - ENOTSOCK = 88, /* Socket operation on non-socket */ - EDESTADDRREQ = 89, /* Destination address required */ - EMSGSIZE = 90, /* Message too long */ - EPROTOTYPE = 91, /* Protocol wrong type for socket */ - ENOPROTOOPT = 92, /* Protocol not available */ - EPROTONOSUPPORT = 93, /* Unknown protocol */ - ESOCKTNOSUPPORT = 94, /* Socket type not supported */ - EOPNOTSUPP = 95, /* Operation not supported on transport endpoint */ - EPFNOSUPPORT = 96, /* Protocol family not supported */ - EAFNOSUPPORT = 97, /* Address family not supported by protocol family */ - EADDRINUSE = 98, /* Address already in use */ - EADDRNOTAVAIL = 99, /* Address not available */ - ENETDOWN = 100, /* Network interface is not configured */ - ENETUNREACH = 101, /* Network is unreachable */ - ENETRESET = 102, - ECONNABORTED = 103, /* Connection aborted */ - ECONNRESET = 104, /* Connection reset by peer */ - ENOBUFS = 105, /* No buffer space available */ - EISCONN = 106, /* Socket is already connected */ - ENOTCONN = 107, /* Socket is not connected */ - ESHUTDOWN = 108, /* Can't send after socket shutdown */ - ETOOMANYREFS = 109, - ETIMEDOUT = 110, /* Connection timed out */ - ECONNREFUSED = 111, /* Connection refused */ - EHOSTDOWN = 112, /* Host is down */ - EHOSTUNREACH = 113, /* Host is unreachable */ - EALREADY = 114, /* Socket already connected */ - EINPROGRESS = 115, /* Connection already in progress */ - ESTALE = 116, - ENOTSUP = EOPNOTSUPP, /* Not supported */ - ENOMEDIUM = 123, /* No medium (in tape drive) */ - ECANCELED = 125, /* Operation canceled. */ - ELBIN = 2048, /* Inode is remote (not really error) */ - EFTYPE = 2049, /* Inappropriate file type or format */ - ENMFILE = 2050, /* No more files */ - EPROCLIM = 2051, - ENOSHARE = 2052, /* No such host or network path */ - ECASECLASH = 2053, /* Filename exists with different case */ - EWOULDBLOCK = EAGAIN, /* Operation would block */ - - // native_client/src/trusted/service_runtime/include/bits/mman.h. - // NOTE: DO NOT USE native_client/src/shared/imc/nacl_imc_c.h. - // Those MAP_*values are different from these. - PROT_NONE = 0x0, - PROT_READ = 0x1, - PROT_WRITE = 0x2, - PROT_EXEC = 0x4, - - MAP_SHARED = 0x1, - MAP_PRIVATE = 0x2, - MAP_FIXED = 0x10, - MAP_ANON = 0x20, -}; -typedef byte* kevent_udata; - -int32 runtime·nacl_exception_stack(byte*, int32); -int32 runtime·nacl_exception_handler(void*, void*); -int32 runtime·nacl_sem_create(int32); -int32 runtime·nacl_sem_wait(int32); -int32 runtime·nacl_sem_post(int32); -int32 runtime·nacl_mutex_create(int32); -int32 runtime·nacl_mutex_lock(int32); -int32 runtime·nacl_mutex_trylock(int32); -int32 runtime·nacl_mutex_unlock(int32); -int32 runtime·nacl_cond_create(int32); -int32 runtime·nacl_cond_wait(int32, int32); -int32 runtime·nacl_cond_signal(int32); -int32 runtime·nacl_cond_broadcast(int32); -int32 runtime·nacl_cond_timed_wait_abs(int32, int32, Timespec*); -int32 runtime·nacl_thread_create(void*, void*, void*, void*); -int32 runtime·nacl_nanosleep(Timespec*, Timespec*); - -void runtime·sigpanic(void); diff --git a/src/runtime/os_nacl_arm.c b/src/runtime/os_nacl_arm.go index 1248ea644..a43e7c47b 100644 --- a/src/runtime/os_nacl_arm.c +++ b/src/runtime/os_nacl_arm.go @@ -2,23 +2,16 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "textflag.h" +package runtime -void -runtime·checkgoarm(void) -{ - return; // NaCl/ARM only supports ARMv7 +func checkgoarm() { + return // NaCl/ARM only supports ARMv7 } -#pragma textflag NOSPLIT -int64 -runtime·cputicks(void) -{ +//go:nosplit +func cputicks() int64 { // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1(). // runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler. // TODO: need more entropy to better seed fastrand1. - return runtime·nanotime(); + return nanotime() } diff --git a/src/runtime/os_netbsd.c b/src/runtime/os_netbsd.c deleted file mode 100644 index 28929ea57..000000000 --- a/src/runtime/os_netbsd.c +++ /dev/null @@ -1,371 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "signal_unix.h" -#include "stack.h" -#include "textflag.h" - -enum -{ - ESRCH = 3, - ENOTSUP = 91, - - // From NetBSD's <sys/time.h> - CLOCK_REALTIME = 0, - CLOCK_VIRTUAL = 1, - CLOCK_PROF = 2, - CLOCK_MONOTONIC = 3 -}; - -extern SigTab runtime·sigtab[]; - -static Sigset sigset_none; -static Sigset sigset_all = { ~(uint32)0, ~(uint32)0, ~(uint32)0, ~(uint32)0, }; - -extern void runtime·getcontext(UcontextT *context); -extern int32 runtime·lwp_create(UcontextT *context, uintptr flags, void *lwpid); -extern void runtime·lwp_mcontext_init(void *mc, void *stack, M *mp, G *gp, void (*fn)(void)); -extern int32 runtime·lwp_park(Timespec *abstime, int32 unpark, void *hint, void *unparkhint); -extern int32 runtime·lwp_unpark(int32 lwp, void *hint); -extern int32 runtime·lwp_self(void); - -// From NetBSD's <sys/sysctl.h> -#define CTL_HW 6 -#define HW_NCPU 3 - -static int32 -getncpu(void) -{ - uint32 mib[2]; - uint32 out; - int32 ret; - uintptr nout; - - // Fetch hw.ncpu via sysctl. - mib[0] = CTL_HW; - mib[1] = HW_NCPU; - nout = sizeof out; - out = 0; - ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0); - if(ret >= 0) - return out; - else - return 1; -} - -#pragma textflag NOSPLIT -uintptr -runtime·semacreate(void) -{ - return 1; -} - -static void -semasleep(void) -{ - int64 ns; - Timespec ts; - - ns = (int64)(uint32)g->m->scalararg[0] | (int64)(uint32)g->m->scalararg[1]<<32; - g->m->scalararg[0] = 0; - g->m->scalararg[1] = 0; - - // spin-mutex lock - while(runtime·xchg(&g->m->waitsemalock, 1)) - runtime·osyield(); - - for(;;) { - // lock held - if(g->m->waitsemacount == 0) { - // sleep until semaphore != 0 or timeout. - // thrsleep unlocks m->waitsemalock. - if(ns < 0) { - // TODO(jsing) - potential deadlock! - // - // There is a potential deadlock here since we - // have to release the waitsemalock mutex - // before we call lwp_park() to suspend the - // thread. This allows another thread to - // release the lock and call lwp_unpark() - // before the thread is actually suspended. - // If this occurs the current thread will end - // up sleeping indefinitely. Unfortunately - // the NetBSD kernel does not appear to provide - // a mechanism for unlocking the userspace - // mutex once the thread is actually parked. - runtime·atomicstore(&g->m->waitsemalock, 0); - runtime·lwp_park(nil, 0, &g->m->waitsemacount, nil); - } else { - ns = ns + runtime·nanotime(); - // NOTE: tv_nsec is int64 on amd64, so this assumes a little-endian system. - ts.tv_nsec = 0; - ts.tv_sec = runtime·timediv(ns, 1000000000, (int32*)&ts.tv_nsec); - // TODO(jsing) - potential deadlock! - // See above for details. - runtime·atomicstore(&g->m->waitsemalock, 0); - runtime·lwp_park(&ts, 0, &g->m->waitsemacount, nil); - } - // reacquire lock - while(runtime·xchg(&g->m->waitsemalock, 1)) - runtime·osyield(); - } - - // lock held (again) - if(g->m->waitsemacount != 0) { - // semaphore is available. - g->m->waitsemacount--; - // spin-mutex unlock - runtime·atomicstore(&g->m->waitsemalock, 0); - g->m->scalararg[0] = 0; // semaphore acquired - return; - } - - // semaphore not available. - // if there is a timeout, stop now. - // otherwise keep trying. - if(ns >= 0) - break; - } - - // lock held but giving up - // spin-mutex unlock - runtime·atomicstore(&g->m->waitsemalock, 0); - g->m->scalararg[0] = -1; - return; -} - -#pragma textflag NOSPLIT -int32 -runtime·semasleep(int64 ns) -{ - int32 r; - void (*fn)(void); - - g->m->scalararg[0] = (uint32)ns; - g->m->scalararg[1] = (uint32)(ns>>32); - fn = semasleep; - runtime·onM(&fn); - r = g->m->scalararg[0]; - g->m->scalararg[0] = 0; - return r; -} - -static void badsemawakeup(void); - -#pragma textflag NOSPLIT -void -runtime·semawakeup(M *mp) -{ - uint32 ret; - void (*fn)(void); - void *oldptr; - uintptr oldscalar; - - // spin-mutex lock - while(runtime·xchg(&mp->waitsemalock, 1)) - runtime·osyield(); - mp->waitsemacount++; - // TODO(jsing) - potential deadlock, see semasleep() for details. - // Confirm that LWP is parked before unparking... - ret = runtime·lwp_unpark(mp->procid, &mp->waitsemacount); - if(ret != 0 && ret != ESRCH) { - // semawakeup can be called on signal stack. - // Save old ptrarg/scalararg so we can restore them. - oldptr = g->m->ptrarg[0]; - oldscalar = g->m->scalararg[0]; - g->m->ptrarg[0] = mp; - g->m->scalararg[0] = ret; - fn = badsemawakeup; - if(g == g->m->gsignal) - fn(); - else - runtime·onM(&fn); - g->m->ptrarg[0] = oldptr; - g->m->scalararg[0] = oldscalar; - } - // spin-mutex unlock - runtime·atomicstore(&mp->waitsemalock, 0); -} - -static void -badsemawakeup(void) -{ - M *mp; - int32 ret; - - mp = g->m->ptrarg[0]; - g->m->ptrarg[0] = nil; - ret = g->m->scalararg[0]; - g->m->scalararg[0] = 0; - - runtime·printf("thrwakeup addr=%p sem=%d ret=%d\n", &mp->waitsemacount, mp->waitsemacount, ret); -} - -void -runtime·newosproc(M *mp, void *stk) -{ - UcontextT uc; - int32 ret; - - if(0) { - runtime·printf( - "newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n", - stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp); - } - - mp->tls[0] = mp->id; // so 386 asm can find it - - runtime·getcontext(&uc); - - uc.uc_flags = _UC_SIGMASK | _UC_CPU; - uc.uc_link = nil; - uc.uc_sigmask = sigset_all; - - runtime·lwp_mcontext_init(&uc.uc_mcontext, stk, mp, mp->g0, runtime·mstart); - - ret = runtime·lwp_create(&uc, 0, &mp->procid); - - if(ret < 0) { - runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount() - 1, -ret); - runtime·throw("runtime.newosproc"); - } -} - -void -runtime·osinit(void) -{ - runtime·ncpu = getncpu(); -} - -#pragma textflag NOSPLIT -void -runtime·get_random_data(byte **rnd, int32 *rnd_len) -{ - #pragma dataflag NOPTR - static byte urandom_data[HashRandomBytes]; - int32 fd; - fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0); - if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) { - *rnd = urandom_data; - *rnd_len = HashRandomBytes; - } else { - *rnd = nil; - *rnd_len = 0; - } - runtime·close(fd); -} - -void -runtime·goenvs(void) -{ - runtime·goenvs_unix(); -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the parent thread (main thread in case of bootstrap), can allocate memory. -void -runtime·mpreinit(M *mp) -{ - mp->gsignal = runtime·malg(32*1024); - runtime·writebarrierptr_nostore(&mp->gsignal, mp->gsignal); - - mp->gsignal->m = mp; - runtime·writebarrierptr_nostore(&mp->gsignal->m, mp->gsignal->m); -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the new thread, can not allocate memory. -void -runtime·minit(void) -{ - g->m->procid = runtime·lwp_self(); - - // Initialize signal handling - runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024); - runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil); -} - -// Called from dropm to undo the effect of an minit. -void -runtime·unminit(void) -{ - runtime·signalstack(nil, 0); -} - -uintptr -runtime·memlimit(void) -{ - return 0; -} - -extern void runtime·sigtramp(void); - -typedef struct sigaction { - union { - void (*_sa_handler)(int32); - void (*_sa_sigaction)(int32, Siginfo*, void *); - } _sa_u; /* signal handler */ - uint32 sa_mask[4]; /* signal mask to apply */ - int32 sa_flags; /* see signal options below */ -} SigactionT; - -void -runtime·setsig(int32 i, GoSighandler *fn, bool restart) -{ - SigactionT sa; - - runtime·memclr((byte*)&sa, sizeof sa); - sa.sa_flags = SA_SIGINFO|SA_ONSTACK; - if(restart) - sa.sa_flags |= SA_RESTART; - sa.sa_mask[0] = ~0U; - sa.sa_mask[1] = ~0U; - sa.sa_mask[2] = ~0U; - sa.sa_mask[3] = ~0U; - if (fn == runtime·sighandler) - fn = (void*)runtime·sigtramp; - sa._sa_u._sa_sigaction = (void*)fn; - runtime·sigaction(i, &sa, nil); -} - -GoSighandler* -runtime·getsig(int32 i) -{ - SigactionT sa; - - runtime·memclr((byte*)&sa, sizeof sa); - runtime·sigaction(i, nil, &sa); - if((void*)sa._sa_u._sa_sigaction == runtime·sigtramp) - return runtime·sighandler; - return (void*)sa._sa_u._sa_sigaction; -} - -void -runtime·signalstack(byte *p, int32 n) -{ - StackT st; - - st.ss_sp = (void*)p; - st.ss_size = n; - st.ss_flags = 0; - if(p == nil) - st.ss_flags = SS_DISABLE; - runtime·sigaltstack(&st, nil); -} - -void -runtime·unblocksignals(void) -{ - runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil); -} - -#pragma textflag NOSPLIT -int8* -runtime·signame(int32 sig) -{ - return runtime·sigtab[sig].name; -} diff --git a/src/runtime/os_netbsd.go b/src/runtime/os_netbsd.go index f000c5e9f..a153bf2eb 100644 --- a/src/runtime/os_netbsd.go +++ b/src/runtime/os_netbsd.go @@ -6,15 +6,37 @@ package runtime import "unsafe" -func setitimer(mode int32, new, old unsafe.Pointer) -func sigaction(sig int32, new, old unsafe.Pointer) -func sigaltstack(new, old unsafe.Pointer) -func sigprocmask(mode int32, new, old unsafe.Pointer) +//go:noescape +func setitimer(mode int32, new, old *itimerval) + +//go:noescape +func sigaction(sig int32, new, old *sigactiont) + +//go:noescape +func sigaltstack(new, old *sigaltstackt) + +//go:noescape +func sigprocmask(mode int32, new, old *sigset) + +//go:noescape func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32 + func lwp_tramp() + func raise(sig int32) + +//go:noescape func getcontext(ctxt unsafe.Pointer) + +//go:noescape func lwp_create(ctxt unsafe.Pointer, flags uintptr, lwpid unsafe.Pointer) int32 -func lwp_park(abstime unsafe.Pointer, unpark int32, hint, unparkhint unsafe.Pointer) int32 + +//go:noescape +func lwp_park(abstime *timespec, unpark int32, hint, unparkhint unsafe.Pointer) int32 + +//go:noescape func lwp_unpark(lwp int32, hint unsafe.Pointer) int32 + func lwp_self() int32 + +func osyield() diff --git a/src/runtime/os_netbsd.h b/src/runtime/os_netbsd.h deleted file mode 100644 index f95db325f..000000000 --- a/src/runtime/os_netbsd.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - - -typedef uintptr kevent_udata; - -struct sigaction; - -void runtime·sigpanic(void); - -void runtime·setitimer(int32, Itimerval*, Itimerval*); -void runtime·sigaction(int32, struct sigaction*, struct sigaction*); -void runtime·sigaltstack(SigaltstackT*, SigaltstackT*); -void runtime·sigprocmask(int32, Sigset*, Sigset*); -void runtime·unblocksignals(void); -int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr); -extern void runtime·lwp_tramp(void); - -enum { - SS_DISABLE = 4, - SIG_BLOCK = 1, - SIG_UNBLOCK = 2, - SIG_SETMASK = 3, - NSIG = 33, - SI_USER = 0, - - // From NetBSD's <sys/ucontext.h> - _UC_SIGMASK = 0x01, - _UC_CPU = 0x04, -}; diff --git a/src/runtime/os_netbsd_386.c b/src/runtime/os_netbsd_386.c deleted file mode 100644 index 23e9db3c1..000000000 --- a/src/runtime/os_netbsd_386.c +++ /dev/null @@ -1,17 +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 "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" - -void -runtime·lwp_mcontext_init(McontextT *mc, void *stack, M *mp, G *gp, void (*fn)(void)) -{ - mc->__gregs[REG_EIP] = (uint32)runtime·lwp_tramp; - mc->__gregs[REG_UESP] = (uint32)stack; - mc->__gregs[REG_EBX] = (uint32)mp; - mc->__gregs[REG_EDX] = (uint32)gp; - mc->__gregs[REG_ESI] = (uint32)fn; -} diff --git a/src/runtime/os_netbsd_amd64.c b/src/runtime/os_netbsd_amd64.c deleted file mode 100644 index 226846cbb..000000000 --- a/src/runtime/os_netbsd_amd64.c +++ /dev/null @@ -1,18 +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 "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" - -void -runtime·lwp_mcontext_init(McontextT *mc, void *stack, M *mp, G *gp, void (*fn)(void)) -{ - // Machine dependent mcontext initialisation for LWP. - mc->__gregs[REG_RIP] = (uint64)runtime·lwp_tramp; - mc->__gregs[REG_RSP] = (uint64)stack; - mc->__gregs[REG_R8] = (uint64)mp; - mc->__gregs[REG_R9] = (uint64)gp; - mc->__gregs[REG_R12] = (uint64)fn; -} diff --git a/src/runtime/os_plan9.c b/src/runtime/os_plan9.c deleted file mode 100644 index 18460fc12..000000000 --- a/src/runtime/os_plan9.c +++ /dev/null @@ -1,368 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "runtime.h" -#include "os_GOOS.h" -#include "arch_GOARCH.h" -#include "textflag.h" -#include "malloc.h" - -int8 *goos = "plan9"; -extern SigTab runtime·sigtab[]; - -int32 runtime·postnote(int32, int8*); - -// Called to initialize a new m (including the bootstrap m). -// Called on the parent thread (main thread in case of bootstrap), can allocate memory. -void -runtime·mpreinit(M *mp) -{ - // Initialize stack and goroutine for note handling. - mp->gsignal = runtime·malg(32*1024); - runtime·writebarrierptr_nostore(&mp->gsignal, mp->gsignal); - - mp->gsignal->m = mp; - runtime·writebarrierptr_nostore(&mp->gsignal->m, mp->gsignal->m); - - mp->notesig = (int8*)runtime·mallocgc(ERRMAX*sizeof(int8), nil, FlagNoScan); - runtime·writebarrierptr_nostore(&mp->notesig, mp->notesig); - - // Initialize stack for handling strings from the - // errstr system call, as used in package syscall. - mp->errstr = (byte*)runtime·mallocgc(ERRMAX*sizeof(byte), nil, FlagNoScan); - runtime·writebarrierptr_nostore(&mp->errstr, mp->errstr); -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the new thread, can not allocate memory. -void -runtime·minit(void) -{ - // Mask all SSE floating-point exceptions - // when running on the 64-bit kernel. - runtime·setfpmasks(); -} - -// Called from dropm to undo the effect of an minit. -void -runtime·unminit(void) -{ -} - - -static int32 -getproccount(void) -{ - int32 fd, i, n, ncpu; - byte buf[2048]; - - fd = runtime·open("/dev/sysstat", OREAD, 0); - if(fd < 0) - return 1; - ncpu = 0; - for(;;) { - n = runtime·read(fd, buf, sizeof buf); - if(n <= 0) - break; - for(i = 0; i < n; i++) { - if(buf[i] == '\n') - ncpu++; - } - } - runtime·close(fd); - return ncpu > 0 ? ncpu : 1; -} - -static int32 -getpid(void) -{ - byte b[20], *c; - int32 fd; - - runtime·memclr(b, sizeof(b)); - fd = runtime·open("#c/pid", 0, 0); - if(fd >= 0) { - runtime·read(fd, b, sizeof(b)); - runtime·close(fd); - } - c = b; - while(*c == ' ' || *c == '\t') - c++; - return runtime·atoi(c); -} - -void -runtime·osinit(void) -{ - runtime·ncpu = getproccount(); - g->m->procid = getpid(); - runtime·notify(runtime·sigtramp); -} - -void -runtime·crash(void) -{ - runtime·notify(nil); - *(int32*)0 = 0; -} - -#pragma textflag NOSPLIT -void -runtime·get_random_data(byte **rnd, int32 *rnd_len) -{ - static byte random_data[HashRandomBytes]; - int32 fd; - - fd = runtime·open("/dev/random", 0 /* O_RDONLY */, 0); - if(runtime·read(fd, random_data, HashRandomBytes) == HashRandomBytes) { - *rnd = random_data; - *rnd_len = HashRandomBytes; - } else { - *rnd = nil; - *rnd_len = 0; - } - runtime·close(fd); -} - -void -runtime·goenvs(void) -{ -} - -void -runtime·initsig(void) -{ -} - -#pragma textflag NOSPLIT -void -runtime·osyield(void) -{ - runtime·sleep(0); -} - -#pragma textflag NOSPLIT -void -runtime·usleep(uint32 µs) -{ - uint32 ms; - - ms = µs/1000; - if(ms == 0) - ms = 1; - runtime·sleep(ms); -} - -#pragma textflag NOSPLIT -int64 -runtime·nanotime(void) -{ - int64 ns, scratch; - - ns = runtime·nsec(&scratch); - // TODO(aram): remove hack after I fix _nsec in the pc64 kernel. - if(ns == 0) - return scratch; - return ns; -} - -#pragma textflag NOSPLIT -void -runtime·itoa(int32 n, byte *p, uint32 len) -{ - byte *q, c; - uint32 i; - - if(len <= 1) - return; - - runtime·memclr(p, len); - q = p; - - if(n==0) { - *q++ = '0'; - USED(q); - return; - } - if(n < 0) { - *q++ = '-'; - p++; - n = -n; - } - for(i=0; n > 0 && i < len; i++) { - *q++ = '0' + (n%10); - n = n/10; - } - for(q--; q >= p; ) { - c = *p; - *p++ = *q; - *q-- = c; - } -} - -void -runtime·goexitsall(int8 *status) -{ - int8 buf[ERRMAX]; - M *mp; - int32 pid; - - runtime·snprintf((byte*)buf, sizeof buf, "go: exit %s", status); - pid = getpid(); - for(mp=runtime·atomicloadp(&runtime·allm); mp; mp=mp->alllink) - if(mp->procid != pid) - runtime·postnote(mp->procid, buf); -} - -int32 -runtime·postnote(int32 pid, int8* msg) -{ - int32 fd; - intgo len; - uint8 buf[128]; - uint8 tmp[16]; - uint8 *p, *q; - - runtime·memclr(buf, sizeof buf); - - /* build path string /proc/pid/note */ - q = tmp; - p = buf; - runtime·itoa(pid, tmp, sizeof tmp); - runtime·memmove((void*)p, (void*)"/proc/", 6); - for(p += 6; *p++ = *q++; ); - p--; - runtime·memmove((void*)p, (void*)"/note", 5); - - fd = runtime·open((int8*)buf, OWRITE, 0); - if(fd < 0) - return -1; - - len = runtime·findnull((byte*)msg); - if(runtime·write(fd, msg, len) != len) { - runtime·close(fd); - return -1; - } - runtime·close(fd); - return 0; -} - -static void exit(void); - -#pragma textflag NOSPLIT -void -runtime·exit(int32 e) -{ - void (*fn)(void); - - g->m->scalararg[0] = e; - fn = exit; - runtime·onM(&fn); -} - -static void -exit(void) -{ - int32 e; - byte tmp[16]; - int8 *status; - - e = g->m->scalararg[0]; - g->m->scalararg[0] = 0; - - if(e == 0) - status = ""; - else { - /* build error string */ - runtime·itoa(e, tmp, sizeof tmp); - status = (int8*)tmp; - } - - runtime·goexitsall(status); - runtime·exits(status); -} - -void -runtime·newosproc(M *mp, void *stk) -{ - int32 pid; - - if(0) - runtime·printf("newosproc mp=%p ostk=%p\n", mp, &mp); - - USED(stk); - if((pid = runtime·rfork(RFPROC|RFMEM|RFNOWAIT)) < 0) - runtime·throw("newosproc: rfork failed\n"); - if(pid == 0) - runtime·tstart_plan9(mp); -} - -#pragma textflag NOSPLIT -uintptr -runtime·semacreate(void) -{ - return 1; -} - -#pragma textflag NOSPLIT -int32 -runtime·semasleep(int64 ns) -{ - int32 ret; - int32 ms; - - if(ns >= 0) { - ms = runtime·timediv(ns, 1000000, nil); - if(ms == 0) - ms = 1; - ret = runtime·plan9_tsemacquire(&g->m->waitsemacount, ms); - if(ret == 1) - return 0; // success - return -1; // timeout or interrupted - } - - while(runtime·plan9_semacquire(&g->m->waitsemacount, 1) < 0) { - /* interrupted; try again (c.f. lock_sema.c) */ - } - return 0; // success -} - -#pragma textflag NOSPLIT -void -runtime·semawakeup(M *mp) -{ - runtime·plan9_semrelease(&mp->waitsemacount, 1); -} - -#pragma textflag NOSPLIT -int32 -runtime·read(int32 fd, void *buf, int32 nbytes) -{ - return runtime·pread(fd, buf, nbytes, -1LL); -} - -#pragma textflag NOSPLIT -int32 -runtime·write(uintptr fd, void *buf, int32 nbytes) -{ - return runtime·pwrite((int32)fd, buf, nbytes, -1LL); -} - -uintptr -runtime·memlimit(void) -{ - return 0; -} - -#pragma dataflag NOPTR -static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n"; - -// This runs on a foreign stack, without an m or a g. No stack split. -#pragma textflag NOSPLIT -void -runtime·badsignal2(void) -{ - runtime·pwrite(2, badsignal, sizeof badsignal - 1, -1LL); - runtime·exits(badsignal); -} diff --git a/src/runtime/os_plan9.go b/src/runtime/os_plan9.go index 20e47bf42..2dcdfc009 100644 --- a/src/runtime/os_plan9.go +++ b/src/runtime/os_plan9.go @@ -6,22 +6,49 @@ package runtime import "unsafe" +//go:noescape func pread(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32 + +//go:noescape func pwrite(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32 + func seek(fd int32, offset int64, whence int32) int64 + +//go:noescape func exits(msg *byte) + +//go:noescape func brk_(addr unsafe.Pointer) uintptr + func sleep(ms int32) int32 + func rfork(flags int32) int32 + +//go:noescape func plan9_semacquire(addr *uint32, block int32) int32 + +//go:noescape func plan9_tsemacquire(addr *uint32, ms int32) int32 + +//go:noescape func plan9_semrelease(addr *uint32, count int32) int32 + +//go:noescape func notify(fn unsafe.Pointer) int32 + func noted(mode int32) int32 + +//go:noescape func nsec(*int64) int64 + +//go:noescape func sigtramp(ureg, msg unsafe.Pointer) + func setfpmasks() + +//go:noescape func tstart_plan9(newm *m) + func errstr() string type _Plink uintptr diff --git a/src/runtime/os_plan9.h b/src/runtime/os_plan9.h deleted file mode 100644 index 6d1802483..000000000 --- a/src/runtime/os_plan9.h +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Plan 9-specific system calls -int32 runtime·pread(int32 fd, void *buf, int32 nbytes, int64 offset); -int32 runtime·pwrite(int32 fd, void *buf, int32 nbytes, int64 offset); -int64 runtime·seek(int32 fd, int64 offset, int32 whence); -void runtime·exits(int8* msg); -intptr runtime·brk_(void*); -int32 runtime·sleep(int32 ms); -int32 runtime·rfork(int32 flags); -int32 runtime·plan9_semacquire(uint32 *addr, int32 block); -int32 runtime·plan9_tsemacquire(uint32 *addr, int32 ms); -int32 runtime·plan9_semrelease(uint32 *addr, int32 count); -int32 runtime·notify(void (*fn)(void*, int8*)); -int32 runtime·noted(int32); -int64 runtime·nsec(int64*); -void runtime·sigtramp(void*, int8*); -void runtime·sigpanic(void); -void runtime·goexitsall(int8*); -void runtime·setfpmasks(void); -void runtime·tstart_plan9(M *newm); - -/* open */ -enum -{ - OREAD = 0, - OWRITE = 1, - ORDWR = 2, - OEXEC = 3, - OTRUNC = 16, - OCEXEC = 32, - ORCLOSE = 64, - OEXCL = 0x1000 -}; - -/* rfork */ -enum -{ - RFNAMEG = (1<<0), - RFENVG = (1<<1), - RFFDG = (1<<2), - RFNOTEG = (1<<3), - RFPROC = (1<<4), - RFMEM = (1<<5), - RFNOWAIT = (1<<6), - RFCNAMEG = (1<<10), - RFCENVG = (1<<11), - RFCFDG = (1<<12), - RFREND = (1<<13), - RFNOMNT = (1<<14) -}; - -/* notify */ -enum -{ - NCONT = 0, - NDFLT = 1 -}; - -typedef struct Tos Tos; -typedef intptr _Plink; - -struct Tos { - struct TosProf /* Per process profiling */ - { - _Plink *pp; /* known to be 0(ptr) */ - _Plink *next; /* known to be 4(ptr) */ - _Plink *last; - _Plink *first; - uint32 pid; - uint32 what; - } prof; - uint64 cyclefreq; /* cycle clock frequency if there is one, 0 otherwise */ - int64 kcycles; /* cycles spent in kernel */ - int64 pcycles; /* cycles spent in process (kernel + user) */ - uint32 pid; /* might as well put the pid here */ - uint32 clock; - /* top of stack is here */ -}; - -enum { - NSIG = 14, /* number of signals in runtime·SigTab array */ - ERRMAX = 128, /* max length of note string */ - - /* Notes in runtime·sigtab that are handled by runtime·sigpanic. */ - SIGRFAULT = 2, - SIGWFAULT = 3, - SIGINTDIV = 4, - SIGFLOAT = 5, - SIGTRAP = 6, -}; diff --git a/src/runtime/os_plan9_386.c b/src/runtime/os_plan9_386.c deleted file mode 100644 index 42c6d161c..000000000 --- a/src/runtime/os_plan9_386.c +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "signals_GOOS.h" - -void -runtime·dumpregs(Ureg *u) -{ - runtime·printf("ax %x\n", u->ax); - runtime·printf("bx %x\n", u->bx); - runtime·printf("cx %x\n", u->cx); - runtime·printf("dx %x\n", u->dx); - runtime·printf("di %x\n", u->di); - runtime·printf("si %x\n", u->si); - runtime·printf("bp %x\n", u->bp); - runtime·printf("sp %x\n", u->sp); - runtime·printf("pc %x\n", u->pc); - runtime·printf("flags %x\n", u->flags); - runtime·printf("cs %x\n", u->cs); - runtime·printf("fs %x\n", u->fs); - runtime·printf("gs %x\n", u->gs); -} - -int32 -runtime·sighandler(void *v, int8 *note, G *gp) -{ - uintptr *sp; - SigTab *t; - bool crash; - Ureg *ureg; - intgo len, n; - int32 sig, flags; - - ureg = (Ureg*)v; - - // The kernel will never pass us a nil note or ureg so we probably - // made a mistake somewhere in runtime·sigtramp. - if(ureg == nil || note == nil) { - runtime·printf("sighandler: ureg %p note %p\n", ureg, note); - goto Throw; - } - - // Check that the note is no more than ERRMAX bytes (including - // the trailing NUL). We should never receive a longer note. - len = runtime·findnull((byte*)note); - if(len > ERRMAX-1) { - runtime·printf("sighandler: note is longer than ERRMAX\n"); - goto Throw; - } - - // See if the note matches one of the patterns in runtime·sigtab. - // Notes that do not match any pattern can be handled at a higher - // level by the program but will otherwise be ignored. - flags = SigNotify; - for(sig = 0; sig < nelem(runtime·sigtab); sig++) { - t = &runtime·sigtab[sig]; - n = runtime·findnull((byte*)t->name); - if(len < n) - continue; - if(runtime·strncmp((byte*)note, (byte*)t->name, n) == 0) { - flags = t->flags; - break; - } - } - - if(flags & SigGoExit) - runtime·exits(note+9); // Strip "go: exit " prefix. - - if(flags & SigPanic) { - // Copy the error string from sigtramp's stack into m->notesig so - // we can reliably access it from the panic routines. - runtime·memmove(g->m->notesig, note, len+1); - - gp->sig = sig; - gp->sigpc = ureg->pc; - - // Only push runtime·sigpanic if PC != 0. - // - // If PC == 0, probably panicked because of a call to a nil func. - // Not pushing that onto SP will make the trace look like a call - // to runtime·sigpanic instead. (Otherwise the trace will end at - // runtime·sigpanic and we won't get to see who faulted). - if(ureg->pc != 0) { - sp = (uintptr*)ureg->sp; - *--sp = ureg->pc; - ureg->sp = (uint32)sp; - } - ureg->pc = (uintptr)runtime·sigpanic; - return NCONT; - } - - if(flags & SigNotify) { - // TODO(ality): See if os/signal wants it. - //if(runtime·sigsend(...)) - // return NCONT; - } - if(flags & SigKill) - goto Exit; - if(!(flags & SigThrow)) - return NCONT; - -Throw: - g->m->throwing = 1; - g->m->caughtsig = gp; - runtime·startpanic(); - - runtime·printf("%s\n", note); - runtime·printf("PC=%x\n", ureg->pc); - runtime·printf("\n"); - - if(runtime·gotraceback(&crash)) { - runtime·goroutineheader(gp); - runtime·tracebacktrap(ureg->pc, ureg->sp, 0, gp); - runtime·tracebackothers(gp); - runtime·printf("\n"); - runtime·dumpregs(ureg); - } - - if(crash) - runtime·crash(); - -Exit: - runtime·goexitsall(note); - runtime·exits(note); - return NDFLT; // not reached -} - -void -runtime·sigenable(uint32 sig) -{ - USED(sig); -} - -void -runtime·sigdisable(uint32 sig) -{ - USED(sig); -} - -void -runtime·resetcpuprofiler(int32 hz) -{ - // TODO: Enable profiling interrupts. - - g->m->profilehz = hz; -} diff --git a/src/runtime/os_plan9_386.go b/src/runtime/os_plan9_386.go new file mode 100644 index 000000000..7dda13931 --- /dev/null +++ b/src/runtime/os_plan9_386.go @@ -0,0 +1,131 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import "unsafe" + +func dumpregs(u *ureg) { + print("ax ", hex(u.ax), "\n") + print("bx ", hex(u.bx), "\n") + print("cx ", hex(u.cx), "\n") + print("dx ", hex(u.dx), "\n") + print("di ", hex(u.di), "\n") + print("si ", hex(u.si), "\n") + print("bp ", hex(u.bp), "\n") + print("sp ", hex(u.sp), "\n") + print("pc ", hex(u.pc), "\n") + print("flags ", hex(u.flags), "\n") + print("cs ", hex(u.cs), "\n") + print("fs ", hex(u.fs), "\n") + print("gs ", hex(u.gs), "\n") +} + +func sighandler(_ureg *ureg, note *byte, gp *g) int { + _g_ := getg() + var t sigTabT + var docrash bool + var length int + var sig int + var flags int + + // The kernel will never pass us a nil note or ureg so we probably + // made a mistake somewhere in sigtramp. + if _ureg == nil || note == nil { + print("sighandler: ureg ", _ureg, " note ", note, "\n") + goto Throw + } + // Check that the note is no more than ERRMAX bytes (including + // the trailing NUL). We should never receive a longer note. + length = findnull(note) + if length > _ERRMAX-1 { + print("sighandler: note is longer than ERRMAX\n") + goto Throw + } + // See if the note matches one of the patterns in sigtab. + // Notes that do not match any pattern can be handled at a higher + // level by the program but will otherwise be ignored. + flags = _SigNotify + for sig, t = range sigtable { + n := len(t.name) + if length < n { + continue + } + if strncmp(note, &t.name[0], uintptr(n)) == 0 { + flags = t.flags + break + } + } + if flags&_SigGoExit != 0 { + exits((*byte)(add(unsafe.Pointer(note), 9))) // Strip "go: exit " prefix. + } + if flags&_SigPanic != 0 { + // Copy the error string from sigtramp's stack into m->notesig so + // we can reliably access it from the panic routines. + memmove(unsafe.Pointer(_g_.m.notesig), unsafe.Pointer(note), uintptr(length+1)) + gp.sig = uint32(sig) + gp.sigpc = uintptr(_ureg.pc) + // Only push sigpanic if PC != 0. + // + // If PC == 0, probably panicked because of a call to a nil func. + // Not pushing that onto SP will make the trace look like a call + // to sigpanic instead. (Otherwise the trace will end at + // sigpanic and we won't get to see who faulted). + if _ureg.pc != 0 { + sp := _ureg.sp + if regSize > ptrSize { + sp -= ptrSize + *(*uintptr)(unsafe.Pointer(uintptr(sp))) = 0 + } + sp -= ptrSize + *(*uintptr)(unsafe.Pointer(uintptr(sp))) = uintptr(_ureg.pc) + _ureg.sp = sp + } + _ureg.pc = uint32(funcPC(sigpanic)) + return _NCONT + } + if flags&_SigNotify != 0 { + // TODO(ality): See if os/signal wants it. + //if(sigsend(...)) + // return _NCONT; + } + if flags&_SigKill != 0 { + goto Exit + } + if flags&_SigThrow == 0 { + return _NCONT + } +Throw: + _g_.m.throwing = 1 + _g_.m.caughtsig = gp + startpanic() + print(gostringnocopy(note), "\n") + print("PC=", hex(_ureg.pc), "\n") + print("\n") + if gotraceback(&docrash) > 0 { + goroutineheader(gp) + tracebacktrap(uintptr(_ureg.pc), uintptr(_ureg.sp), 0, gp) + tracebackothers(gp) + print("\n") + dumpregs(_ureg) + } + if docrash { + crash() + } +Exit: + goexitsall(note) + exits(note) + return _NDFLT // not reached +} + +func sigenable(sig uint32) { +} + +func sigdisable(sig uint32) { +} + +func resetcpuprofiler(hz int32) { + // TODO: Enable profiling interrupts. + getg().m.profilehz = hz +} diff --git a/src/runtime/os_plan9_amd64.c b/src/runtime/os_plan9_amd64.c deleted file mode 100644 index a9dc0eb96..000000000 --- a/src/runtime/os_plan9_amd64.c +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "signals_GOOS.h" - -void -runtime·dumpregs(Ureg *u) -{ - runtime·printf("ax %X\n", u->ax); - runtime·printf("bx %X\n", u->bx); - runtime·printf("cx %X\n", u->cx); - runtime·printf("dx %X\n", u->dx); - runtime·printf("di %X\n", u->di); - runtime·printf("si %X\n", u->si); - runtime·printf("bp %X\n", u->bp); - runtime·printf("sp %X\n", u->sp); - runtime·printf("r8 %X\n", u->r8); - runtime·printf("r9 %X\n", u->r9); - runtime·printf("r10 %X\n", u->r10); - runtime·printf("r11 %X\n", u->r11); - runtime·printf("r12 %X\n", u->r12); - runtime·printf("r13 %X\n", u->r13); - runtime·printf("r14 %X\n", u->r14); - runtime·printf("r15 %X\n", u->r15); - runtime·printf("ip %X\n", u->ip); - runtime·printf("flags %X\n", u->flags); - runtime·printf("cs %X\n", (uint64)u->cs); - runtime·printf("fs %X\n", (uint64)u->fs); - runtime·printf("gs %X\n", (uint64)u->gs); -} - -int32 -runtime·sighandler(void *v, int8 *note, G *gp) -{ - uintptr *sp; - SigTab *t; - bool crash; - Ureg *ureg; - intgo len, n; - int32 sig, flags; - - ureg = (Ureg*)v; - - // The kernel will never pass us a nil note or ureg so we probably - // made a mistake somewhere in runtime·sigtramp. - if(ureg == nil || note == nil) { - runtime·printf("sighandler: ureg %p note %p\n", ureg, note); - goto Throw; - } - - // Check that the note is no more than ERRMAX bytes (including - // the trailing NUL). We should never receive a longer note. - len = runtime·findnull((byte*)note); - if(len > ERRMAX-1) { - runtime·printf("sighandler: note is longer than ERRMAX\n"); - goto Throw; - } - - // See if the note matches one of the patterns in runtime·sigtab. - // Notes that do not match any pattern can be handled at a higher - // level by the program but will otherwise be ignored. - flags = SigNotify; - for(sig = 0; sig < nelem(runtime·sigtab); sig++) { - t = &runtime·sigtab[sig]; - n = runtime·findnull((byte*)t->name); - if(len < n) - continue; - if(runtime·strncmp((byte*)note, (byte*)t->name, n) == 0) { - flags = t->flags; - break; - } - } - - if(flags & SigGoExit) - runtime·exits(note+9); // Strip "go: exit " prefix. - - if(flags & SigPanic) { - // Copy the error string from sigtramp's stack into m->notesig so - // we can reliably access it from the panic routines. - runtime·memmove(g->m->notesig, note, len+1); - - gp->sig = sig; - gp->sigpc = ureg->ip; - - // Only push runtime·sigpanic if PC != 0. - // - // If PC == 0, probably panicked because of a call to a nil func. - // Not pushing that onto SP will make the trace look like a call - // to runtime·sigpanic instead. (Otherwise the trace will end at - // runtime·sigpanic and we won't get to see who faulted). - if(ureg->ip != 0) { - sp = (uintptr*)ureg->sp; - *--sp = ureg->ip; - ureg->sp = (uint64)sp; - } - ureg->ip = (uintptr)runtime·sigpanic; - return NCONT; - } - - if(flags & SigNotify) { - // TODO(ality): See if os/signal wants it. - //if(runtime·sigsend(...)) - // return NCONT; - } - if(flags & SigKill) - goto Exit; - if(!(flags & SigThrow)) - return NCONT; - -Throw: - g->m->throwing = 1; - g->m->caughtsig = gp; - runtime·startpanic(); - - runtime·printf("%s\n", note); - runtime·printf("PC=%X\n", ureg->ip); - runtime·printf("\n"); - - if(runtime·gotraceback(&crash)) { - runtime·goroutineheader(gp); - runtime·tracebacktrap(ureg->ip, ureg->sp, 0, gp); - runtime·tracebackothers(gp); - runtime·printf("\n"); - runtime·dumpregs(ureg); - } - - if(crash) - runtime·crash(); - -Exit: - runtime·goexitsall(note); - runtime·exits(note); - return NDFLT; // not reached -} - -void -runtime·sigenable(uint32 sig) -{ - USED(sig); -} - -void -runtime·sigdisable(uint32 sig) -{ - USED(sig); -} - -void -runtime·resetcpuprofiler(int32 hz) -{ - // TODO: Enable profiling interrupts. - - g->m->profilehz = hz; -} diff --git a/src/runtime/os_plan9_amd64.go b/src/runtime/os_plan9_amd64.go new file mode 100644 index 000000000..8727dcc20 --- /dev/null +++ b/src/runtime/os_plan9_amd64.go @@ -0,0 +1,139 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import "unsafe" + +func dumpregs(u *ureg) { + print("ax ", hex(u.ax), "\n") + print("bx ", hex(u.bx), "\n") + print("cx ", hex(u.cx), "\n") + print("dx ", hex(u.dx), "\n") + print("di ", hex(u.di), "\n") + print("si ", hex(u.si), "\n") + print("bp ", hex(u.bp), "\n") + print("sp ", hex(u.sp), "\n") + print("r8 ", hex(u.r8), "\n") + print("r9 ", hex(u.r9), "\n") + print("r10 ", hex(u.r10), "\n") + print("r11 ", hex(u.r11), "\n") + print("r12 ", hex(u.r12), "\n") + print("r13 ", hex(u.r13), "\n") + print("r14 ", hex(u.r14), "\n") + print("r15 ", hex(u.r15), "\n") + print("ip ", hex(u.ip), "\n") + print("flags ", hex(u.flags), "\n") + print("cs ", hex(uint64(u.cs)), "\n") + print("fs ", hex(uint64(u.fs)), "\n") + print("gs ", hex(uint64(u.gs)), "\n") +} + +func sighandler(_ureg *ureg, note *byte, gp *g) int { + _g_ := getg() + var t sigTabT + var docrash bool + var length int + var sig int + var flags int + + // The kernel will never pass us a nil note or ureg so we probably + // made a mistake somewhere in sigtramp. + if _ureg == nil || note == nil { + print("sighandler: ureg ", _ureg, " note ", note, "\n") + goto Throw + } + // Check that the note is no more than ERRMAX bytes (including + // the trailing NUL). We should never receive a longer note. + length = findnull(note) + if length > _ERRMAX-1 { + print("sighandler: note is longer than ERRMAX\n") + goto Throw + } + // See if the note matches one of the patterns in sigtab. + // Notes that do not match any pattern can be handled at a higher + // level by the program but will otherwise be ignored. + flags = _SigNotify + for sig, t = range sigtable { + n := len(t.name) + if length < n { + continue + } + if strncmp(note, &t.name[0], uintptr(n)) == 0 { + flags = t.flags + break + } + } + if flags&_SigGoExit != 0 { + exits((*byte)(add(unsafe.Pointer(note), 9))) // Strip "go: exit " prefix. + } + if flags&_SigPanic != 0 { + // Copy the error string from sigtramp's stack into m->notesig so + // we can reliably access it from the panic routines. + memmove(unsafe.Pointer(_g_.m.notesig), unsafe.Pointer(note), uintptr(length+1)) + gp.sig = uint32(sig) + gp.sigpc = uintptr(_ureg.ip) + // Only push sigpanic if PC != 0. + // + // If PC == 0, probably panicked because of a call to a nil func. + // Not pushing that onto SP will make the trace look like a call + // to sigpanic instead. (Otherwise the trace will end at + // sigpanic and we won't get to see who faulted). + if _ureg.ip != 0 { + sp := _ureg.sp + if regSize > ptrSize { + sp -= ptrSize + *(*uintptr)(unsafe.Pointer(uintptr(sp))) = 0 + } + sp -= ptrSize + *(*uintptr)(unsafe.Pointer(uintptr(sp))) = uintptr(_ureg.ip) + _ureg.sp = sp + } + _ureg.ip = uint64(funcPC(sigpanic)) + return _NCONT + } + if flags&_SigNotify != 0 { + // TODO(ality): See if os/signal wants it. + //if(sigsend(...)) + // return _NCONT; + } + if flags&_SigKill != 0 { + goto Exit + } + if flags&_SigThrow == 0 { + return _NCONT + } +Throw: + _g_.m.throwing = 1 + _g_.m.caughtsig = gp + startpanic() + print(gostringnocopy(note), "\n") + print("PC=", hex(_ureg.ip), "\n") + print("\n") + if gotraceback(&docrash) > 0 { + goroutineheader(gp) + tracebacktrap(uintptr(_ureg.ip), uintptr(_ureg.sp), 0, gp) + tracebackothers(gp) + print("\n") + dumpregs(_ureg) + } + if docrash { + crash() + } +Exit: + goexitsall(note) + exits(note) + return _NDFLT // not reached +} + +func sigenable(sig uint32) { +} + +func sigdisable(sig uint32) { +} + +func resetcpuprofiler(hz int32) { + // TODO: Enable profiling interrupts. + getg().m.profilehz = hz +} diff --git a/src/runtime/os_windows.c b/src/runtime/os_windows.c deleted file mode 100644 index b8b8eda5f..000000000 --- a/src/runtime/os_windows.c +++ /dev/null @@ -1,636 +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 "runtime.h" -#include "type.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "textflag.h" -#include "arch_GOARCH.h" -#include "malloc.h" - -#pragma dynimport runtime·AddVectoredExceptionHandler AddVectoredExceptionHandler "kernel32.dll" -#pragma dynimport runtime·CloseHandle CloseHandle "kernel32.dll" -#pragma dynimport runtime·CreateEvent CreateEventA "kernel32.dll" -#pragma dynimport runtime·CreateThread CreateThread "kernel32.dll" -#pragma dynimport runtime·CreateWaitableTimer CreateWaitableTimerA "kernel32.dll" -#pragma dynimport runtime·CryptAcquireContextW CryptAcquireContextW "advapi32.dll" -#pragma dynimport runtime·CryptGenRandom CryptGenRandom "advapi32.dll" -#pragma dynimport runtime·CryptReleaseContext CryptReleaseContext "advapi32.dll" -#pragma dynimport runtime·DuplicateHandle DuplicateHandle "kernel32.dll" -#pragma dynimport runtime·ExitProcess ExitProcess "kernel32.dll" -#pragma dynimport runtime·FreeEnvironmentStringsW FreeEnvironmentStringsW "kernel32.dll" -#pragma dynimport runtime·GetEnvironmentStringsW GetEnvironmentStringsW "kernel32.dll" -#pragma dynimport runtime·GetProcAddress GetProcAddress "kernel32.dll" -#pragma dynimport runtime·GetStdHandle GetStdHandle "kernel32.dll" -#pragma dynimport runtime·GetSystemInfo GetSystemInfo "kernel32.dll" -#pragma dynimport runtime·GetThreadContext GetThreadContext "kernel32.dll" -#pragma dynimport runtime·LoadLibrary LoadLibraryW "kernel32.dll" -#pragma dynimport runtime·LoadLibraryA LoadLibraryA "kernel32.dll" -#pragma dynimport runtime·NtWaitForSingleObject NtWaitForSingleObject "ntdll.dll" -#pragma dynimport runtime·ResumeThread ResumeThread "kernel32.dll" -#pragma dynimport runtime·SetConsoleCtrlHandler SetConsoleCtrlHandler "kernel32.dll" -#pragma dynimport runtime·SetEvent SetEvent "kernel32.dll" -#pragma dynimport runtime·SetProcessPriorityBoost SetProcessPriorityBoost "kernel32.dll" -#pragma dynimport runtime·SetThreadPriority SetThreadPriority "kernel32.dll" -#pragma dynimport runtime·SetUnhandledExceptionFilter SetUnhandledExceptionFilter "kernel32.dll" -#pragma dynimport runtime·SetWaitableTimer SetWaitableTimer "kernel32.dll" -#pragma dynimport runtime·Sleep Sleep "kernel32.dll" -#pragma dynimport runtime·SuspendThread SuspendThread "kernel32.dll" -#pragma dynimport runtime·WaitForSingleObject WaitForSingleObject "kernel32.dll" -#pragma dynimport runtime·WriteFile WriteFile "kernel32.dll" -#pragma dynimport runtime·timeBeginPeriod timeBeginPeriod "winmm.dll" - -extern void *runtime·AddVectoredExceptionHandler; -extern void *runtime·CloseHandle; -extern void *runtime·CreateEvent; -extern void *runtime·CreateThread; -extern void *runtime·CreateWaitableTimer; -extern void *runtime·CryptAcquireContextW; -extern void *runtime·CryptGenRandom; -extern void *runtime·CryptReleaseContext; -extern void *runtime·DuplicateHandle; -extern void *runtime·ExitProcess; -extern void *runtime·FreeEnvironmentStringsW; -extern void *runtime·GetEnvironmentStringsW; -extern void *runtime·GetProcAddress; -extern void *runtime·GetStdHandle; -extern void *runtime·GetSystemInfo; -extern void *runtime·GetThreadContext; -extern void *runtime·LoadLibrary; -extern void *runtime·LoadLibraryA; -extern void *runtime·NtWaitForSingleObject; -extern void *runtime·ResumeThread; -extern void *runtime·SetConsoleCtrlHandler; -extern void *runtime·SetEvent; -extern void *runtime·SetProcessPriorityBoost; -extern void *runtime·SetThreadPriority; -extern void *runtime·SetUnhandledExceptionFilter; -extern void *runtime·SetWaitableTimer; -extern void *runtime·Sleep; -extern void *runtime·SuspendThread; -extern void *runtime·WaitForSingleObject; -extern void *runtime·WriteFile; -extern void *runtime·timeBeginPeriod; - -#pragma dataflag NOPTR -void *runtime·GetQueuedCompletionStatusEx; - -extern uintptr runtime·externalthreadhandlerp; -void runtime·externalthreadhandler(void); -void runtime·exceptiontramp(void); -void runtime·firstcontinuetramp(void); -void runtime·lastcontinuetramp(void); - -#pragma textflag NOSPLIT -uintptr -runtime·getLoadLibrary(void) -{ - return (uintptr)runtime·LoadLibrary; -} - -#pragma textflag NOSPLIT -uintptr -runtime·getGetProcAddress(void) -{ - return (uintptr)runtime·GetProcAddress; -} - -static int32 -getproccount(void) -{ - SystemInfo info; - - runtime·stdcall1(runtime·GetSystemInfo, (uintptr)&info); - return info.dwNumberOfProcessors; -} - -void -runtime·osinit(void) -{ - void *kernel32; - void *addVectoredContinueHandler; - - kernel32 = runtime·stdcall1(runtime·LoadLibraryA, (uintptr)"kernel32.dll"); - - runtime·externalthreadhandlerp = (uintptr)runtime·externalthreadhandler; - - runtime·stdcall2(runtime·AddVectoredExceptionHandler, 1, (uintptr)runtime·exceptiontramp); - addVectoredContinueHandler = nil; - if(kernel32 != nil) - addVectoredContinueHandler = runtime·stdcall2(runtime·GetProcAddress, (uintptr)kernel32, (uintptr)"AddVectoredContinueHandler"); - if(addVectoredContinueHandler == nil || sizeof(void*) == 4) { - // use SetUnhandledExceptionFilter for windows-386 or - // if VectoredContinueHandler is unavailable. - // note: SetUnhandledExceptionFilter handler won't be called, if debugging. - runtime·stdcall1(runtime·SetUnhandledExceptionFilter, (uintptr)runtime·lastcontinuetramp); - } else { - runtime·stdcall2(addVectoredContinueHandler, 1, (uintptr)runtime·firstcontinuetramp); - runtime·stdcall2(addVectoredContinueHandler, 0, (uintptr)runtime·lastcontinuetramp); - } - - runtime·stdcall2(runtime·SetConsoleCtrlHandler, (uintptr)runtime·ctrlhandler, 1); - - runtime·stdcall1(runtime·timeBeginPeriod, 1); - - runtime·ncpu = getproccount(); - - // Windows dynamic priority boosting assumes that a process has different types - // of dedicated threads -- GUI, IO, computational, etc. Go processes use - // equivalent threads that all do a mix of GUI, IO, computations, etc. - // In such context dynamic priority boosting does nothing but harm, so we turn it off. - runtime·stdcall2(runtime·SetProcessPriorityBoost, -1, 1); - - if(kernel32 != nil) { - runtime·GetQueuedCompletionStatusEx = runtime·stdcall2(runtime·GetProcAddress, (uintptr)kernel32, (uintptr)"GetQueuedCompletionStatusEx"); - } -} - -#pragma textflag NOSPLIT -void -runtime·get_random_data(byte **rnd, int32 *rnd_len) -{ - uintptr handle; - *rnd = nil; - *rnd_len = 0; - if(runtime·stdcall5(runtime·CryptAcquireContextW, (uintptr)&handle, (uintptr)nil, (uintptr)nil, - 1 /* PROV_RSA_FULL */, - 0xf0000000U /* CRYPT_VERIFYCONTEXT */) != 0) { - static byte random_data[HashRandomBytes]; - if(runtime·stdcall3(runtime·CryptGenRandom, handle, HashRandomBytes, (uintptr)&random_data[0])) { - *rnd = random_data; - *rnd_len = HashRandomBytes; - } - runtime·stdcall2(runtime·CryptReleaseContext, handle, 0); - } -} - -void -runtime·goenvs(void) -{ - extern Slice runtime·envs; - - uint16 *env; - String *s; - int32 i, n; - uint16 *p; - - env = runtime·stdcall0(runtime·GetEnvironmentStringsW); - - n = 0; - for(p=env; *p; n++) - p += runtime·findnullw(p)+1; - - runtime·envs = runtime·makeStringSlice(n); - s = (String*)runtime·envs.array; - - p = env; - for(i=0; i<n; i++) { - s[i] = runtime·gostringw(p); - p += runtime·findnullw(p)+1; - } - - runtime·stdcall1(runtime·FreeEnvironmentStringsW, (uintptr)env); -} - -#pragma textflag NOSPLIT -void -runtime·exit(int32 code) -{ - runtime·stdcall1(runtime·ExitProcess, code); -} - -#pragma textflag NOSPLIT -int32 -runtime·write(uintptr fd, void *buf, int32 n) -{ - void *handle; - uint32 written; - - written = 0; - switch(fd) { - case 1: - handle = runtime·stdcall1(runtime·GetStdHandle, -11); - break; - case 2: - handle = runtime·stdcall1(runtime·GetStdHandle, -12); - break; - default: - // assume fd is real windows handle. - handle = (void*)fd; - break; - } - runtime·stdcall5(runtime·WriteFile, (uintptr)handle, (uintptr)buf, n, (uintptr)&written, 0); - return written; -} - -#define INFINITE ((uintptr)0xFFFFFFFF) - -#pragma textflag NOSPLIT -int32 -runtime·semasleep(int64 ns) -{ - // store ms in ns to save stack space - if(ns < 0) - ns = INFINITE; - else { - ns = runtime·timediv(ns, 1000000, nil); - if(ns == 0) - ns = 1; - } - if(runtime·stdcall2(runtime·WaitForSingleObject, (uintptr)g->m->waitsema, ns) != 0) - return -1; // timeout - return 0; -} - -#pragma textflag NOSPLIT -void -runtime·semawakeup(M *mp) -{ - runtime·stdcall1(runtime·SetEvent, mp->waitsema); -} - -#pragma textflag NOSPLIT -uintptr -runtime·semacreate(void) -{ - return (uintptr)runtime·stdcall4(runtime·CreateEvent, 0, 0, 0, 0); -} - -#define STACK_SIZE_PARAM_IS_A_RESERVATION ((uintptr)0x00010000) - -void -runtime·newosproc(M *mp, void *stk) -{ - void *thandle; - - USED(stk); - - thandle = runtime·stdcall6(runtime·CreateThread, - (uintptr)nil, 0x20000, (uintptr)runtime·tstart_stdcall, (uintptr)mp, - STACK_SIZE_PARAM_IS_A_RESERVATION, (uintptr)nil); - if(thandle == nil) { - runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), runtime·getlasterror()); - runtime·throw("runtime.newosproc"); - } -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the parent thread (main thread in case of bootstrap), can allocate memory. -void -runtime·mpreinit(M *mp) -{ - USED(mp); -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the new thread, can not allocate memory. -void -runtime·minit(void) -{ - uintptr thandle; - - // -1 = current process, -2 = current thread - runtime·stdcall7(runtime·DuplicateHandle, -1, -2, -1, (uintptr)&thandle, 0, 0, DUPLICATE_SAME_ACCESS); - runtime·atomicstoreuintptr(&g->m->thread, thandle); -} - -// Called from dropm to undo the effect of an minit. -void -runtime·unminit(void) -{ - runtime·stdcall1(runtime·CloseHandle, g->m->thread); - g->m->thread = 0; -} - -// Described in http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/ -typedef struct KSYSTEM_TIME { - uint32 LowPart; - int32 High1Time; - int32 High2Time; -} KSYSTEM_TIME; - -#pragma dataflag NOPTR -const KSYSTEM_TIME* INTERRUPT_TIME = (KSYSTEM_TIME*)0x7ffe0008; -#pragma dataflag NOPTR -const KSYSTEM_TIME* SYSTEM_TIME = (KSYSTEM_TIME*)0x7ffe0014; - -static void badsystime(void); - -#pragma textflag NOSPLIT -int64 -runtime·systime(KSYSTEM_TIME *timeaddr) -{ - KSYSTEM_TIME t; - int32 i; - void (*fn)(void); - - for(i = 1; i < 10000; i++) { - // these fields must be read in that order (see URL above) - t.High1Time = timeaddr->High1Time; - t.LowPart = timeaddr->LowPart; - t.High2Time = timeaddr->High2Time; - if(t.High1Time == t.High2Time) - return (int64)t.High1Time<<32 | t.LowPart; - if((i%100) == 0) - runtime·osyield(); - } - fn = badsystime; - runtime·onM(&fn); - return 0; -} - -#pragma textflag NOSPLIT -int64 -runtime·unixnano(void) -{ - return (runtime·systime(SYSTEM_TIME) - 116444736000000000LL) * 100LL; -} - -static void -badsystime(void) -{ - runtime·throw("interrupt/system time is changing too fast"); -} - -#pragma textflag NOSPLIT -int64 -runtime·nanotime(void) -{ - return runtime·systime(INTERRUPT_TIME) * 100LL; -} - -// Calling stdcall on os stack. -#pragma textflag NOSPLIT -static void* -stdcall(void *fn) -{ - g->m->libcall.fn = (uintptr)fn; - if(g->m->profilehz != 0) { - // leave pc/sp for cpu profiler - g->m->libcallg = g; - g->m->libcallpc = (uintptr)runtime·getcallerpc(&fn); - // sp must be the last, because once async cpu profiler finds - // all three values to be non-zero, it will use them - g->m->libcallsp = (uintptr)runtime·getcallersp(&fn); - } - runtime·asmcgocall(runtime·asmstdcall, &g->m->libcall); - g->m->libcallsp = 0; - return (void*)g->m->libcall.r1; -} - -#pragma textflag NOSPLIT -void* -runtime·stdcall0(void *fn) -{ - g->m->libcall.n = 0; - g->m->libcall.args = (uintptr)&fn; // it's unused but must be non-nil, otherwise crashes - return stdcall(fn); -} - -#pragma textflag NOSPLIT -void* -runtime·stdcall1(void *fn, uintptr a0) -{ - USED(a0); - g->m->libcall.n = 1; - g->m->libcall.args = (uintptr)&a0; - return stdcall(fn); -} - -#pragma textflag NOSPLIT -void* -runtime·stdcall2(void *fn, uintptr a0, uintptr a1) -{ - USED(a0, a1); - g->m->libcall.n = 2; - g->m->libcall.args = (uintptr)&a0; - return stdcall(fn); -} - -#pragma textflag NOSPLIT -void* -runtime·stdcall3(void *fn, uintptr a0, uintptr a1, uintptr a2) -{ - USED(a0, a1, a2); - g->m->libcall.n = 3; - g->m->libcall.args = (uintptr)&a0; - return stdcall(fn); -} - -#pragma textflag NOSPLIT -void* -runtime·stdcall4(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3) -{ - USED(a0, a1, a2, a3); - g->m->libcall.n = 4; - g->m->libcall.args = (uintptr)&a0; - return stdcall(fn); -} - -#pragma textflag NOSPLIT -void* -runtime·stdcall5(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4) -{ - USED(a0, a1, a2, a3, a4); - g->m->libcall.n = 5; - g->m->libcall.args = (uintptr)&a0; - return stdcall(fn); -} - -#pragma textflag NOSPLIT -void* -runtime·stdcall6(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5) -{ - USED(a0, a1, a2, a3, a4, a5); - g->m->libcall.n = 6; - g->m->libcall.args = (uintptr)&a0; - return stdcall(fn); -} - -#pragma textflag NOSPLIT -void* -runtime·stdcall7(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5, uintptr a6) -{ - USED(a0, a1, a2, a3, a4, a5, a6); - g->m->libcall.n = 7; - g->m->libcall.args = (uintptr)&a0; - return stdcall(fn); -} - -extern void runtime·usleep1(uint32); - -#pragma textflag NOSPLIT -void -runtime·osyield(void) -{ - runtime·usleep1(1); -} - -#pragma textflag NOSPLIT -void -runtime·usleep(uint32 us) -{ - // Have 1us units; want 100ns units. - runtime·usleep1(10*us); -} - -uint32 -runtime·issigpanic(uint32 code) -{ - switch(code) { - case EXCEPTION_ACCESS_VIOLATION: - case EXCEPTION_INT_DIVIDE_BY_ZERO: - case EXCEPTION_INT_OVERFLOW: - case EXCEPTION_FLT_DENORMAL_OPERAND: - case EXCEPTION_FLT_DIVIDE_BY_ZERO: - case EXCEPTION_FLT_INEXACT_RESULT: - case EXCEPTION_FLT_OVERFLOW: - case EXCEPTION_FLT_UNDERFLOW: - case EXCEPTION_BREAKPOINT: - return 1; - } - return 0; -} - -void -runtime·initsig(void) -{ - // following line keeps these functions alive at link stage - // if there's a better way please write it here - void *e = runtime·exceptiontramp; - void *f = runtime·firstcontinuetramp; - void *l = runtime·lastcontinuetramp; - USED(e); - USED(f); - USED(l); -} - -uint32 -runtime·ctrlhandler1(uint32 type) -{ - int32 s; - - switch(type) { - case CTRL_C_EVENT: - case CTRL_BREAK_EVENT: - s = SIGINT; - break; - default: - return 0; - } - - if(runtime·sigsend(s)) - return 1; - runtime·exit(2); // SIGINT, SIGTERM, etc - return 0; -} - -extern void runtime·dosigprof(Context *r, G *gp, M *mp); -extern void runtime·profileloop(void); -#pragma dataflag NOPTR -static void *profiletimer; - -static void -profilem(M *mp) -{ - extern M runtime·m0; - extern uint32 runtime·tls0[]; - byte rbuf[sizeof(Context)+15]; - Context *r; - void *tls; - G *gp; - - tls = mp->tls; - if(mp == &runtime·m0) - tls = runtime·tls0; - gp = *(G**)tls; - - // align Context to 16 bytes - r = (Context*)((uintptr)(&rbuf[15]) & ~15); - r->ContextFlags = CONTEXT_CONTROL; - runtime·stdcall2(runtime·GetThreadContext, (uintptr)mp->thread, (uintptr)r); - runtime·dosigprof(r, gp, mp); -} - -void -runtime·profileloop1(void) -{ - M *mp, *allm; - uintptr thread; - - runtime·stdcall2(runtime·SetThreadPriority, -2, THREAD_PRIORITY_HIGHEST); - - for(;;) { - runtime·stdcall2(runtime·WaitForSingleObject, (uintptr)profiletimer, -1); - allm = runtime·atomicloadp(&runtime·allm); - for(mp = allm; mp != nil; mp = mp->alllink) { - thread = runtime·atomicloaduintptr(&mp->thread); - // Do not profile threads blocked on Notes, - // this includes idle worker threads, - // idle timer thread, idle heap scavenger, etc. - if(thread == 0 || mp->profilehz == 0 || mp->blocked) - continue; - runtime·stdcall1(runtime·SuspendThread, (uintptr)thread); - if(mp->profilehz != 0 && !mp->blocked) - profilem(mp); - runtime·stdcall1(runtime·ResumeThread, (uintptr)thread); - } - } -} - -void -runtime·resetcpuprofiler(int32 hz) -{ - static Mutex lock; - void *timer, *thread; - int32 ms; - int64 due; - - runtime·lock(&lock); - if(profiletimer == nil) { - timer = runtime·stdcall3(runtime·CreateWaitableTimer, (uintptr)nil, (uintptr)nil, (uintptr)nil); - runtime·atomicstorep(&profiletimer, timer); - thread = runtime·stdcall6(runtime·CreateThread, - (uintptr)nil, (uintptr)nil, (uintptr)runtime·profileloop, (uintptr)nil, (uintptr)nil, (uintptr)nil); - runtime·stdcall2(runtime·SetThreadPriority, (uintptr)thread, THREAD_PRIORITY_HIGHEST); - runtime·stdcall1(runtime·CloseHandle, (uintptr)thread); - } - runtime·unlock(&lock); - - ms = 0; - due = 1LL<<63; - if(hz > 0) { - ms = 1000 / hz; - if(ms == 0) - ms = 1; - due = ms * -10000; - } - runtime·stdcall6(runtime·SetWaitableTimer, - (uintptr)profiletimer, (uintptr)&due, ms, (uintptr)nil, (uintptr)nil, (uintptr)nil); - runtime·atomicstore((uint32*)&g->m->profilehz, hz); -} - -uintptr -runtime·memlimit(void) -{ - return 0; -} - -#pragma dataflag NOPTR -int8 runtime·badsignalmsg[] = "runtime: signal received on thread not created by Go.\n"; -int32 runtime·badsignallen = sizeof runtime·badsignalmsg - 1; - -void -runtime·crash(void) -{ - // TODO: This routine should do whatever is needed - // to make the Windows program abort/crash as it - // would if Go was not intercepting signals. - // On Unix the routine would remove the custom signal - // handler and then raise a signal (like SIGABRT). - // Something like that should happen here. - // It's okay to leave this empty for now: if crash returns - // the ordinary exit-after-panic happens. -} diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go index fcd8f44cc..097b5d629 100644 --- a/src/runtime/os_windows.go +++ b/src/runtime/os_windows.go @@ -4,24 +4,8 @@ package runtime -import "unsafe" - type stdFunction *byte -func stdcall0(fn stdFunction) uintptr -func stdcall1(fn stdFunction, a0 uintptr) uintptr -func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr -func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr -func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr -func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr -func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr -func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr - -func asmstdcall(fn unsafe.Pointer) -func getlasterror() uint32 -func setlasterror(err uint32) -func usleep1(usec uint32) - func os_sigpipe() { gothrow("too many writes on closed pipe") } diff --git a/src/runtime/os_windows.h b/src/runtime/os_windows.h deleted file mode 100644 index d5d168d77..000000000 --- a/src/runtime/os_windows.h +++ /dev/null @@ -1,42 +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. - -extern void *runtime·LoadLibrary; -extern void *runtime·GetProcAddress; -extern void *runtime·GetQueuedCompletionStatusEx; - -// Call a Windows function with stdcall conventions, -// and switch to os stack during the call. -void runtime·asmstdcall(void *c); -void *runtime·stdcall0(void *fn); -void *runtime·stdcall1(void *fn, uintptr a0); -void *runtime·stdcall2(void *fn, uintptr a0, uintptr a1); -void *runtime·stdcall3(void *fn, uintptr a0, uintptr a1, uintptr a2); -void *runtime·stdcall4(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3); -void *runtime·stdcall5(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4); -void *runtime·stdcall6(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5); -void *runtime·stdcall7(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5, uintptr a6); - -uint32 runtime·getlasterror(void); -void runtime·setlasterror(uint32 err); - -// Function to be called by windows CreateThread -// to start new os thread. -uint32 runtime·tstart_stdcall(M *newm); - -uint32 runtime·issigpanic(uint32); -void runtime·sigpanic(void); -uint32 runtime·ctrlhandler(uint32 type); - -// Windows dll function to go callback entry. -byte *runtime·compilecallback(Eface fn, bool cleanstack); -void *runtime·callbackasm(void); - -void runtime·install_exception_handler(void); -void runtime·remove_exception_handler(void); - -// TODO(brainman): should not need those -enum { - NSIG = 65, -}; diff --git a/src/runtime/os_windows_386.c b/src/runtime/os_windows_386.c deleted file mode 100644 index 9962f0dc2..000000000 --- a/src/runtime/os_windows_386.c +++ /dev/null @@ -1,128 +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 "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" - -void -runtime·dumpregs(Context *r) -{ - runtime·printf("eax %x\n", r->Eax); - runtime·printf("ebx %x\n", r->Ebx); - runtime·printf("ecx %x\n", r->Ecx); - runtime·printf("edx %x\n", r->Edx); - runtime·printf("edi %x\n", r->Edi); - runtime·printf("esi %x\n", r->Esi); - runtime·printf("ebp %x\n", r->Ebp); - runtime·printf("esp %x\n", r->Esp); - runtime·printf("eip %x\n", r->Eip); - runtime·printf("eflags %x\n", r->EFlags); - runtime·printf("cs %x\n", r->SegCs); - runtime·printf("fs %x\n", r->SegFs); - runtime·printf("gs %x\n", r->SegGs); -} - -bool -runtime·isgoexception(ExceptionRecord *info, Context *r) -{ - extern byte runtime·text[], runtime·etext[]; - - // Only handle exception if executing instructions in Go binary - // (not Windows library code). - if(r->Eip < (uint32)runtime·text || (uint32)runtime·etext < r->Eip) - return false; - - if(!runtime·issigpanic(info->ExceptionCode)) - return false; - - return true; -} - -// Called by sigtramp from Windows VEH handler. -// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION) -// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH). -uint32 -runtime·exceptionhandler(ExceptionRecord *info, Context *r, G *gp) -{ - uintptr *sp; - - if(!runtime·isgoexception(info, r)) - return EXCEPTION_CONTINUE_SEARCH; - - // Make it look like a call to the signal func. - // Have to pass arguments out of band since - // augmenting the stack frame would break - // the unwinding code. - gp->sig = info->ExceptionCode; - gp->sigcode0 = info->ExceptionInformation[0]; - gp->sigcode1 = info->ExceptionInformation[1]; - gp->sigpc = r->Eip; - - // Only push runtime·sigpanic if r->eip != 0. - // If r->eip == 0, probably panicked because of a - // call to a nil func. Not pushing that onto sp will - // make the trace look like a call to runtime·sigpanic instead. - // (Otherwise the trace will end at runtime·sigpanic and we - // won't get to see who faulted.) - if(r->Eip != 0) { - sp = (uintptr*)r->Esp; - *--sp = r->Eip; - r->Esp = (uintptr)sp; - } - r->Eip = (uintptr)runtime·sigpanic; - return EXCEPTION_CONTINUE_EXECUTION; -} - -// lastcontinuehandler is reached, because runtime cannot handle -// current exception. lastcontinuehandler will print crash info and exit. -uint32 -runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp) -{ - bool crash; - - if(runtime·panicking) // traceback already printed - runtime·exit(2); - runtime·panicking = 1; - - runtime·printf("Exception %x %p %p %p\n", info->ExceptionCode, - (uintptr)info->ExceptionInformation[0], (uintptr)info->ExceptionInformation[1], (uintptr)r->Eip); - - runtime·printf("PC=%x\n", r->Eip); - if(g->m->lockedg != nil && g->m->ncgo > 0 && gp == g->m->g0) { - runtime·printf("signal arrived during cgo execution\n"); - gp = g->m->lockedg; - } - runtime·printf("\n"); - - if(runtime·gotraceback(&crash)){ - runtime·tracebacktrap(r->Eip, r->Esp, 0, gp); - runtime·tracebackothers(gp); - runtime·dumpregs(r); - } - - if(crash) - runtime·crash(); - - runtime·exit(2); - return 0; // not reached -} - -void -runtime·sigenable(uint32 sig) -{ - USED(sig); -} - -void -runtime·sigdisable(uint32 sig) -{ - USED(sig); -} - -void -runtime·dosigprof(Context *r, G *gp, M *mp) -{ - runtime·sigprof((uint8*)r->Eip, (uint8*)r->Esp, nil, gp, mp); -} diff --git a/src/runtime/os_windows_amd64.c b/src/runtime/os_windows_amd64.c deleted file mode 100644 index e4617e4ce..000000000 --- a/src/runtime/os_windows_amd64.c +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" - -void -runtime·dumpregs(Context *r) -{ - runtime·printf("rax %X\n", r->Rax); - runtime·printf("rbx %X\n", r->Rbx); - runtime·printf("rcx %X\n", r->Rcx); - runtime·printf("rdx %X\n", r->Rdx); - runtime·printf("rdi %X\n", r->Rdi); - runtime·printf("rsi %X\n", r->Rsi); - runtime·printf("rbp %X\n", r->Rbp); - runtime·printf("rsp %X\n", r->Rsp); - runtime·printf("r8 %X\n", r->R8 ); - runtime·printf("r9 %X\n", r->R9 ); - runtime·printf("r10 %X\n", r->R10); - runtime·printf("r11 %X\n", r->R11); - runtime·printf("r12 %X\n", r->R12); - runtime·printf("r13 %X\n", r->R13); - runtime·printf("r14 %X\n", r->R14); - runtime·printf("r15 %X\n", r->R15); - runtime·printf("rip %X\n", r->Rip); - runtime·printf("rflags %X\n", r->EFlags); - runtime·printf("cs %X\n", (uint64)r->SegCs); - runtime·printf("fs %X\n", (uint64)r->SegFs); - runtime·printf("gs %X\n", (uint64)r->SegGs); -} - -bool -runtime·isgoexception(ExceptionRecord *info, Context *r) -{ - extern byte runtime·text[], runtime·etext[]; - - // Only handle exception if executing instructions in Go binary - // (not Windows library code). - if(r->Rip < (uint64)runtime·text || (uint64)runtime·etext < r->Rip) - return false; - - if(!runtime·issigpanic(info->ExceptionCode)) - return false; - - return true; -} - -// Called by sigtramp from Windows VEH handler. -// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION) -// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH). -uint32 -runtime·exceptionhandler(ExceptionRecord *info, Context *r, G *gp) -{ - uintptr *sp; - - if(!runtime·isgoexception(info, r)) - return EXCEPTION_CONTINUE_SEARCH; - - // Make it look like a call to the signal func. - // Have to pass arguments out of band since - // augmenting the stack frame would break - // the unwinding code. - gp->sig = info->ExceptionCode; - gp->sigcode0 = info->ExceptionInformation[0]; - gp->sigcode1 = info->ExceptionInformation[1]; - gp->sigpc = r->Rip; - - // Only push runtime·sigpanic if r->rip != 0. - // If r->rip == 0, probably panicked because of a - // call to a nil func. Not pushing that onto sp will - // make the trace look like a call to runtime·sigpanic instead. - // (Otherwise the trace will end at runtime·sigpanic and we - // won't get to see who faulted.) - if(r->Rip != 0) { - sp = (uintptr*)r->Rsp; - *--sp = r->Rip; - r->Rsp = (uintptr)sp; - } - r->Rip = (uintptr)runtime·sigpanic; - return EXCEPTION_CONTINUE_EXECUTION; -} - -// It seems Windows searches ContinueHandler's list even -// if ExceptionHandler returns EXCEPTION_CONTINUE_EXECUTION. -// firstcontinuehandler will stop that search, -// if exceptionhandler did the same earlier. -uint32 -runtime·firstcontinuehandler(ExceptionRecord *info, Context *r, G *gp) -{ - USED(gp); - if(!runtime·isgoexception(info, r)) - return EXCEPTION_CONTINUE_SEARCH; - return EXCEPTION_CONTINUE_EXECUTION; -} - -// lastcontinuehandler is reached, because runtime cannot handle -// current exception. lastcontinuehandler will print crash info and exit. -uint32 -runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp) -{ - bool crash; - - if(runtime·panicking) // traceback already printed - runtime·exit(2); - runtime·panicking = 1; - - runtime·printf("Exception %x %p %p %p\n", info->ExceptionCode, - info->ExceptionInformation[0], info->ExceptionInformation[1], r->Rip); - - - runtime·printf("PC=%X\n", r->Rip); - if(g->m->lockedg != nil && g->m->ncgo > 0 && gp == g->m->g0) { - runtime·printf("signal arrived during cgo execution\n"); - gp = g->m->lockedg; - } - runtime·printf("\n"); - - if(runtime·gotraceback(&crash)){ - runtime·tracebacktrap(r->Rip, r->Rsp, 0, gp); - runtime·tracebackothers(gp); - runtime·dumpregs(r); - } - - if(crash) - runtime·crash(); - - runtime·exit(2); - return 0; // not reached -} - -void -runtime·sigenable(uint32 sig) -{ - USED(sig); -} - -void -runtime·sigdisable(uint32 sig) -{ - USED(sig); -} - -void -runtime·dosigprof(Context *r, G *gp, M *mp) -{ - runtime·sigprof((uint8*)r->Rip, (uint8*)r->Rsp, nil, gp, mp); -} diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 892946702..95e780b1d 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -162,7 +162,7 @@ func init() { // Allocate a Defer, usually using per-P pool. // Each defer must be released with freedefer. -// Note: runs on M stack +// Note: runs on g0 stack func newdefer(siz int32) *_defer { var d *_defer sc := deferclass(uintptr(siz)) diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 12e2e71e9..64f6a3520 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -63,11 +63,13 @@ func main() { if _cgo_free == nil { gothrow("_cgo_free missing") } - if _cgo_setenv == nil { - gothrow("_cgo_setenv missing") - } - if _cgo_unsetenv == nil { - gothrow("_cgo_unsetenv missing") + if GOOS != "windows" { + if _cgo_setenv == nil { + gothrow("_cgo_setenv missing") + } + if _cgo_unsetenv == nil { + gothrow("_cgo_unsetenv missing") + } } } @@ -165,6 +167,7 @@ func acquireSudog() *sudog { gothrow("acquireSudog: found s.elem != nil in cache") } c.sudogcache = s.next + s.next = nil return s } @@ -193,6 +196,15 @@ func releaseSudog(s *sudog) { if s.selectdone != nil { gothrow("runtime: sudog with non-nil selectdone") } + if s.next != nil { + gothrow("runtime: sudog with non-nil next") + } + if s.prev != nil { + gothrow("runtime: sudog with non-nil prev") + } + if s.waitlink != nil { + gothrow("runtime: sudog with non-nil waitlink") + } gp := getg() if gp.param != nil { gothrow("runtime: releaseSudog with non-nil gp.param") diff --git a/src/runtime/race/race_unix_test.go b/src/runtime/race/race_unix_test.go new file mode 100644 index 000000000..84f0acece --- /dev/null +++ b/src/runtime/race/race_unix_test.go @@ -0,0 +1,30 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build race +// +build darwin freebsd linux + +package race_test + +import ( + "sync/atomic" + "syscall" + "testing" + "unsafe" +) + +// Test that race detector does not crash when accessing non-Go allocated memory (issue 9136). +func TestNonGoMemory(t *testing.T) { + data, err := syscall.Mmap(-1, 0, 4096, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_ANON|syscall.MAP_PRIVATE) + if err != nil { + t.Fatalf("failed to mmap memory: %v", err) + } + p := (*uint32)(unsafe.Pointer(&data[0])) + atomic.AddUint32(p, 1) + (*p)++ + if *p != 2 { + t.Fatalf("data[0] = %v, expect 2", *p) + } + syscall.Munmap(data) +} diff --git a/src/runtime/race1.go b/src/runtime/race1.go index 4c580429c..2ec2bee65 100644 --- a/src/runtime/race1.go +++ b/src/runtime/race1.go @@ -81,6 +81,10 @@ var __tsan_go_ignore_sync_end byte //go:cgo_import_static __tsan_go_atomic32_compare_exchange //go:cgo_import_static __tsan_go_atomic64_compare_exchange +// start/end of global data (data+bss). +var racedatastart uintptr +var racedataend uintptr + // start/end of heap for race_amd64.s var racearenastart uintptr var racearenaend uintptr @@ -99,7 +103,7 @@ func racecall(*byte, uintptr, uintptr, uintptr, uintptr) //go:nosplit func isvalidaddr(addr unsafe.Pointer) bool { return racearenastart <= uintptr(addr) && uintptr(addr) < racearenaend || - uintptr(unsafe.Pointer(&noptrdata)) <= uintptr(addr) && uintptr(addr) < uintptr(unsafe.Pointer(&enoptrbss)) + racedatastart <= uintptr(addr) && uintptr(addr) < racedataend } //go:nosplit @@ -113,9 +117,36 @@ func raceinit() uintptr { racecall(&__tsan_init, uintptr(unsafe.Pointer(&racectx)), funcPC(racesymbolizethunk), 0, 0) // Round data segment to page boundaries, because it's used in mmap(). - start := uintptr(unsafe.Pointer(&noptrdata)) &^ (_PageSize - 1) - size := round(uintptr(unsafe.Pointer(&enoptrbss))-start, _PageSize) + start := ^uintptr(0) + end := uintptr(0) + if start > uintptr(unsafe.Pointer(&noptrdata)) { + start = uintptr(unsafe.Pointer(&noptrdata)) + } + if start > uintptr(unsafe.Pointer(&data)) { + start = uintptr(unsafe.Pointer(&data)) + } + if start > uintptr(unsafe.Pointer(&noptrbss)) { + start = uintptr(unsafe.Pointer(&noptrbss)) + } + if start > uintptr(unsafe.Pointer(&bss)) { + start = uintptr(unsafe.Pointer(&bss)) + } + if end < uintptr(unsafe.Pointer(&enoptrdata)) { + end = uintptr(unsafe.Pointer(&enoptrdata)) + } + if end < uintptr(unsafe.Pointer(&edata)) { + end = uintptr(unsafe.Pointer(&edata)) + } + if end < uintptr(unsafe.Pointer(&enoptrbss)) { + end = uintptr(unsafe.Pointer(&enoptrbss)) + } + if end < uintptr(unsafe.Pointer(&ebss)) { + end = uintptr(unsafe.Pointer(&ebss)) + } + size := round(end-start, _PageSize) racecall(&__tsan_map_shadow, start, size, 0, 0) + racedatastart = start + racedataend = start + size return racectx } diff --git a/src/runtime/race_amd64.s b/src/runtime/race_amd64.s index a7f44870a..d54d9798f 100644 --- a/src/runtime/race_amd64.s +++ b/src/runtime/race_amd64.s @@ -139,17 +139,15 @@ TEXT racecalladdr<>(SB), NOSPLIT, $0-0 get_tls(R12) MOVQ g(R12), R14 MOVQ g_racectx(R14), RARG0 // goroutine context - // Check that addr is within [arenastart, arenaend) or within [noptrdata, enoptrbss). + // Check that addr is within [arenastart, arenaend) or within [racedatastart, racedataend). CMPQ RARG1, runtime·racearenastart(SB) JB data CMPQ RARG1, runtime·racearenaend(SB) JB call data: - MOVQ $runtime·noptrdata(SB), R13 - CMPQ RARG1, R13 + CMPQ RARG1, runtime·racedatastart(SB) JB ret - MOVQ $runtime·enoptrbss(SB), R13 - CMPQ RARG1, R13 + CMPQ RARG1, runtime·racedataend(SB) JAE ret call: MOVQ AX, AX // w/o this 6a miscompiles this function @@ -167,6 +165,7 @@ TEXT runtime·racefuncenter(SB), NOSPLIT, $0-8 MOVQ callpc+0(FP), RARG1 // void __tsan_func_enter(ThreadState *thr, void *pc); MOVQ $__tsan_func_enter(SB), AX + // racecall<> preserves R15 CALL racecall<>(SB) MOVQ R15, DX // restore function entry context RET @@ -307,13 +306,45 @@ TEXT sync∕atomic·CompareAndSwapPointer(SB), NOSPLIT, $0-0 TEXT racecallatomic<>(SB), NOSPLIT, $0-0 // Trigger SIGSEGV early. MOVQ 16(SP), R12 - MOVL (R12), R12 + MOVL (R12), R13 + // Check that addr is within [arenastart, arenaend) or within [racedatastart, racedataend). + CMPQ R12, runtime·racearenastart(SB) + JB racecallatomic_data + CMPQ R12, runtime·racearenaend(SB) + JB racecallatomic_ok +racecallatomic_data: + CMPQ R12, runtime·racedatastart(SB) + JB racecallatomic_ignore + CMPQ R12, runtime·racedataend(SB) + JAE racecallatomic_ignore +racecallatomic_ok: + // Addr is within the good range, call the atomic function. get_tls(R12) MOVQ g(R12), R14 MOVQ g_racectx(R14), RARG0 // goroutine context MOVQ 8(SP), RARG1 // caller pc MOVQ (SP), RARG2 // pc LEAQ 16(SP), RARG3 // arguments + JMP racecall<>(SB) // does not return +racecallatomic_ignore: + // Addr is outside the good range. + // Call __tsan_go_ignore_sync_begin to ignore synchronization during the atomic op. + // An attempt to synchronize on the address would cause crash. + MOVQ AX, R15 // remember the original function + MOVQ $__tsan_go_ignore_sync_begin(SB), AX + MOVQ g(R12), R14 + MOVQ g_racectx(R14), RARG0 // goroutine context + CALL racecall<>(SB) + MOVQ R15, AX // restore the original function + // Call the atomic function. + MOVQ g_racectx(R14), RARG0 // goroutine context + MOVQ 8(SP), RARG1 // caller pc + MOVQ (SP), RARG2 // pc + LEAQ 16(SP), RARG3 // arguments + CALL racecall<>(SB) + // Call __tsan_go_ignore_sync_end. + MOVQ $__tsan_go_ignore_sync_end(SB), AX + MOVQ g_racectx(R14), RARG0 // goroutine context JMP racecall<>(SB) // void runtime·racecall(void(*f)(...), ...) diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go index 7625a2dd8..d18178d09 100644 --- a/src/runtime/runtime2.go +++ b/src/runtime/runtime2.go @@ -45,7 +45,13 @@ const ( _Pdead ) -// XXX inserting below here +// The next line makes 'go generate' write the zgen_*.go files with +// per-OS and per-arch information, including constants +// named goos_$GOOS and goarch_$GOARCH for every +// known GOOS and GOARCH. The constant is 1 on the +// current system, 0 otherwise; multiplying by them is +// useful for defining GOOS- or GOARCH-specific constants. +//go:generate go run gengoos.go type mutex struct { // Futex-based impl treats it as uint32 key, @@ -397,14 +403,6 @@ type itab struct { fun [0]uintptr } -const ( - // TODO: Generate in cmd/dist. - _NaCl = 0 - _Windows = 0 - _Solaris = 0 - _Plan9 = 0 -) - // Lock-free stack node. // // Also known to export_test.go. type lfnode struct { diff --git a/src/runtime/select.go b/src/runtime/select.go index e918b734a..5e5047bc1 100644 --- a/src/runtime/select.go +++ b/src/runtime/select.go @@ -399,6 +399,7 @@ loop: } } sgnext = sglist.waitlink + sglist.waitlink = nil releaseSudog(sglist) sglist = sgnext } @@ -636,6 +637,7 @@ func (q *waitq) dequeueSudoG(s *sudog) { if q.last == sgp { q.last = prevsgp } + s.next = nil return } l = &sgp.next diff --git a/src/runtime/sema.go b/src/runtime/sema.go index d2a028c01..26dbd30ea 100644 --- a/src/runtime/sema.go +++ b/src/runtime/sema.go @@ -201,6 +201,7 @@ func syncsemacquire(s *syncSema) { } unlock(&s.lock) if wake != nil { + wake.next = nil goready(wake.g) } } else { @@ -242,6 +243,7 @@ func syncsemrelease(s *syncSema, n uint32) { if wake.releasetime != 0 { wake.releasetime = cputicks() } + wake.next = nil goready(wake.g) n-- } diff --git a/src/runtime/signal_android_386.h b/src/runtime/signal_android_386.h deleted file mode 100644 index 2a1bb4b3e..000000000 --- a/src/runtime/signal_android_386.h +++ /dev/null @@ -1 +0,0 @@ -#include "signal_linux_386.h" diff --git a/src/runtime/signal_android_arm.h b/src/runtime/signal_android_arm.h deleted file mode 100644 index 8a05e21e5..000000000 --- a/src/runtime/signal_android_arm.h +++ /dev/null @@ -1 +0,0 @@ -#include "signal_linux_arm.h" diff --git a/src/runtime/signal_linux_386.go b/src/runtime/signal_linux_386.go index 41eae80ea..085f66e89 100644 --- a/src/runtime/signal_linux_386.go +++ b/src/runtime/signal_linux_386.go @@ -26,7 +26,7 @@ func (c *sigctxt) cs() uint32 { return uint32(c.regs().cs) } func (c *sigctxt) fs() uint32 { return uint32(c.regs().fs) } func (c *sigctxt) gs() uint32 { return uint32(c.regs().gs) } func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) } -func (c *sigctxt) sigaddr() uint32 { return uint32(*(*uintptr)(add(unsafe.Pointer(c.info), 2*ptrSize))) } +func (c *sigctxt) sigaddr() uint32 { return c.info.si_addr } func (c *sigctxt) set_eip(x uint32) { c.regs().eip = x } func (c *sigctxt) set_esp(x uint32) { c.regs().esp = x } diff --git a/src/runtime/signal_linux_amd64.go b/src/runtime/signal_linux_amd64.go index d94b19102..5e339b8a4 100644 --- a/src/runtime/signal_linux_amd64.go +++ b/src/runtime/signal_linux_amd64.go @@ -36,7 +36,7 @@ func (c *sigctxt) cs() uint64 { return uint64(c.regs().cs) } func (c *sigctxt) fs() uint64 { return uint64(c.regs().fs) } func (c *sigctxt) gs() uint64 { return uint64(c.regs().gs) } func (c *sigctxt) sigcode() uint64 { return uint64(c.info.si_code) } -func (c *sigctxt) sigaddr() uint64 { return uint64(*(*uintptr)(add(unsafe.Pointer(c.info), 2*ptrSize))) } +func (c *sigctxt) sigaddr() uint64 { return c.info.si_addr } func (c *sigctxt) set_rip(x uint64) { c.regs().rip = x } func (c *sigctxt) set_rsp(x uint64) { c.regs().rsp = x } diff --git a/src/runtime/signal_linux_arm.go b/src/runtime/signal_linux_arm.go index 4a5670e74..bdb4314fa 100644 --- a/src/runtime/signal_linux_arm.go +++ b/src/runtime/signal_linux_arm.go @@ -35,7 +35,7 @@ func (c *sigctxt) error() uint32 { return c.regs().error_code } func (c *sigctxt) oldmask() uint32 { return c.regs().oldmask } func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) } -func (c *sigctxt) sigaddr() uint32 { return uint32(*(*uintptr)(add(unsafe.Pointer(c.info), 2*ptrSize))) } +func (c *sigctxt) sigaddr() uint32 { return c.info.si_addr } func (c *sigctxt) set_pc(x uint32) { c.regs().pc = x } func (c *sigctxt) set_sp(x uint32) { c.regs().sp = x } diff --git a/src/runtime/signal_linux_power64.h b/src/runtime/signal_linux_power64.h deleted file mode 100644 index 840648920..000000000 --- a/src/runtime/signal_linux_power64.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#define SIG_REGS(ctxt) (*((Sigcontext*)&((Ucontext*)(ctxt))->uc_mcontext)->regs) - -#define SIG_R0(info, ctxt) (SIG_REGS(ctxt).gpr[0]) -#define SIG_R1(info, ctxt) (SIG_REGS(ctxt).gpr[1]) -#define SIG_R2(info, ctxt) (SIG_REGS(ctxt).gpr[2]) -#define SIG_R3(info, ctxt) (SIG_REGS(ctxt).gpr[3]) -#define SIG_R4(info, ctxt) (SIG_REGS(ctxt).gpr[4]) -#define SIG_R5(info, ctxt) (SIG_REGS(ctxt).gpr[5]) -#define SIG_R6(info, ctxt) (SIG_REGS(ctxt).gpr[6]) -#define SIG_R7(info, ctxt) (SIG_REGS(ctxt).gpr[7]) -#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).gpr[8]) -#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).gpr[9]) -#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).gpr[10]) -#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).gpr[11]) -#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).gpr[12]) -#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).gpr[13]) -#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).gpr[14]) -#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).gpr[15]) -#define SIG_R16(info, ctxt) (SIG_REGS(ctxt).gpr[16]) -#define SIG_R17(info, ctxt) (SIG_REGS(ctxt).gpr[17]) -#define SIG_R18(info, ctxt) (SIG_REGS(ctxt).gpr[18]) -#define SIG_R19(info, ctxt) (SIG_REGS(ctxt).gpr[19]) -#define SIG_R20(info, ctxt) (SIG_REGS(ctxt).gpr[20]) -#define SIG_R21(info, ctxt) (SIG_REGS(ctxt).gpr[21]) -#define SIG_R22(info, ctxt) (SIG_REGS(ctxt).gpr[22]) -#define SIG_R23(info, ctxt) (SIG_REGS(ctxt).gpr[23]) -#define SIG_R24(info, ctxt) (SIG_REGS(ctxt).gpr[24]) -#define SIG_R25(info, ctxt) (SIG_REGS(ctxt).gpr[25]) -#define SIG_R26(info, ctxt) (SIG_REGS(ctxt).gpr[26]) -#define SIG_R27(info, ctxt) (SIG_REGS(ctxt).gpr[27]) -#define SIG_R28(info, ctxt) (SIG_REGS(ctxt).gpr[28]) -#define SIG_R29(info, ctxt) (SIG_REGS(ctxt).gpr[29]) -#define SIG_R30(info, ctxt) (SIG_REGS(ctxt).gpr[30]) -#define SIG_R31(info, ctxt) (SIG_REGS(ctxt).gpr[31]) - -#define SIG_SP(info, ctxt) (SIG_REGS(ctxt).gpr[1]) -#define SIG_PC(info, ctxt) (SIG_REGS(ctxt).nip) -#define SIG_TRAP(info, ctxt) (SIG_REGS(ctxt).trap) -#define SIG_CTR(info, ctxt) (SIG_REGS(ctxt).ctr) -#define SIG_LINK(info, ctxt) (SIG_REGS(ctxt).link) -#define SIG_XER(info, ctxt) (SIG_REGS(ctxt).xer) -#define SIG_CCR(info, ctxt) (SIG_REGS(ctxt).ccr) - -#define SIG_CODE0(info, ctxt) ((uintptr)(info)->si_code) -#define SIG_FAULT(info, ctxt) (SIG_REGS(ctxt).dar) diff --git a/src/runtime/signal_linux_power64le.h b/src/runtime/signal_linux_power64le.h deleted file mode 100644 index 840648920..000000000 --- a/src/runtime/signal_linux_power64le.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#define SIG_REGS(ctxt) (*((Sigcontext*)&((Ucontext*)(ctxt))->uc_mcontext)->regs) - -#define SIG_R0(info, ctxt) (SIG_REGS(ctxt).gpr[0]) -#define SIG_R1(info, ctxt) (SIG_REGS(ctxt).gpr[1]) -#define SIG_R2(info, ctxt) (SIG_REGS(ctxt).gpr[2]) -#define SIG_R3(info, ctxt) (SIG_REGS(ctxt).gpr[3]) -#define SIG_R4(info, ctxt) (SIG_REGS(ctxt).gpr[4]) -#define SIG_R5(info, ctxt) (SIG_REGS(ctxt).gpr[5]) -#define SIG_R6(info, ctxt) (SIG_REGS(ctxt).gpr[6]) -#define SIG_R7(info, ctxt) (SIG_REGS(ctxt).gpr[7]) -#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).gpr[8]) -#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).gpr[9]) -#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).gpr[10]) -#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).gpr[11]) -#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).gpr[12]) -#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).gpr[13]) -#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).gpr[14]) -#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).gpr[15]) -#define SIG_R16(info, ctxt) (SIG_REGS(ctxt).gpr[16]) -#define SIG_R17(info, ctxt) (SIG_REGS(ctxt).gpr[17]) -#define SIG_R18(info, ctxt) (SIG_REGS(ctxt).gpr[18]) -#define SIG_R19(info, ctxt) (SIG_REGS(ctxt).gpr[19]) -#define SIG_R20(info, ctxt) (SIG_REGS(ctxt).gpr[20]) -#define SIG_R21(info, ctxt) (SIG_REGS(ctxt).gpr[21]) -#define SIG_R22(info, ctxt) (SIG_REGS(ctxt).gpr[22]) -#define SIG_R23(info, ctxt) (SIG_REGS(ctxt).gpr[23]) -#define SIG_R24(info, ctxt) (SIG_REGS(ctxt).gpr[24]) -#define SIG_R25(info, ctxt) (SIG_REGS(ctxt).gpr[25]) -#define SIG_R26(info, ctxt) (SIG_REGS(ctxt).gpr[26]) -#define SIG_R27(info, ctxt) (SIG_REGS(ctxt).gpr[27]) -#define SIG_R28(info, ctxt) (SIG_REGS(ctxt).gpr[28]) -#define SIG_R29(info, ctxt) (SIG_REGS(ctxt).gpr[29]) -#define SIG_R30(info, ctxt) (SIG_REGS(ctxt).gpr[30]) -#define SIG_R31(info, ctxt) (SIG_REGS(ctxt).gpr[31]) - -#define SIG_SP(info, ctxt) (SIG_REGS(ctxt).gpr[1]) -#define SIG_PC(info, ctxt) (SIG_REGS(ctxt).nip) -#define SIG_TRAP(info, ctxt) (SIG_REGS(ctxt).trap) -#define SIG_CTR(info, ctxt) (SIG_REGS(ctxt).ctr) -#define SIG_LINK(info, ctxt) (SIG_REGS(ctxt).link) -#define SIG_XER(info, ctxt) (SIG_REGS(ctxt).xer) -#define SIG_CCR(info, ctxt) (SIG_REGS(ctxt).ccr) - -#define SIG_CODE0(info, ctxt) ((uintptr)(info)->si_code) -#define SIG_FAULT(info, ctxt) (SIG_REGS(ctxt).dar) diff --git a/src/runtime/signal_linux_power64x.go b/src/runtime/signal_linux_power64x.go new file mode 100644 index 000000000..0a406b31f --- /dev/null +++ b/src/runtime/signal_linux_power64x.go @@ -0,0 +1,71 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build linux +// +build power64 power64le + +package runtime + +import "unsafe" + +type sigctxt struct { + info *siginfo + ctxt unsafe.Pointer +} + +func (c *sigctxt) regs() *ptregs { return (*ucontext)(c.ctxt).uc_mcontext.regs } +func (c *sigctxt) r0() uint64 { return c.regs().gpr[0] } +func (c *sigctxt) r1() uint64 { return c.regs().gpr[1] } +func (c *sigctxt) r2() uint64 { return c.regs().gpr[2] } +func (c *sigctxt) r3() uint64 { return c.regs().gpr[3] } +func (c *sigctxt) r4() uint64 { return c.regs().gpr[4] } +func (c *sigctxt) r5() uint64 { return c.regs().gpr[5] } +func (c *sigctxt) r6() uint64 { return c.regs().gpr[6] } +func (c *sigctxt) r7() uint64 { return c.regs().gpr[7] } +func (c *sigctxt) r8() uint64 { return c.regs().gpr[8] } +func (c *sigctxt) r9() uint64 { return c.regs().gpr[9] } +func (c *sigctxt) r10() uint64 { return c.regs().gpr[10] } +func (c *sigctxt) r11() uint64 { return c.regs().gpr[11] } +func (c *sigctxt) r12() uint64 { return c.regs().gpr[12] } +func (c *sigctxt) r13() uint64 { return c.regs().gpr[13] } +func (c *sigctxt) r14() uint64 { return c.regs().gpr[14] } +func (c *sigctxt) r15() uint64 { return c.regs().gpr[15] } +func (c *sigctxt) r16() uint64 { return c.regs().gpr[16] } +func (c *sigctxt) r17() uint64 { return c.regs().gpr[17] } +func (c *sigctxt) r18() uint64 { return c.regs().gpr[18] } +func (c *sigctxt) r19() uint64 { return c.regs().gpr[19] } +func (c *sigctxt) r20() uint64 { return c.regs().gpr[20] } +func (c *sigctxt) r21() uint64 { return c.regs().gpr[21] } +func (c *sigctxt) r22() uint64 { return c.regs().gpr[22] } +func (c *sigctxt) r23() uint64 { return c.regs().gpr[23] } +func (c *sigctxt) r24() uint64 { return c.regs().gpr[24] } +func (c *sigctxt) r25() uint64 { return c.regs().gpr[25] } +func (c *sigctxt) r26() uint64 { return c.regs().gpr[26] } +func (c *sigctxt) r27() uint64 { return c.regs().gpr[27] } +func (c *sigctxt) r28() uint64 { return c.regs().gpr[28] } +func (c *sigctxt) r29() uint64 { return c.regs().gpr[29] } +func (c *sigctxt) r30() uint64 { return c.regs().gpr[30] } +func (c *sigctxt) r31() uint64 { return c.regs().gpr[31] } +func (c *sigctxt) sp() uint64 { return c.regs().gpr[1] } +func (c *sigctxt) pc() uint64 { return c.regs().nip } +func (c *sigctxt) trap() uint64 { return c.regs().trap } +func (c *sigctxt) ctr() uint64 { return c.regs().ctr } +func (c *sigctxt) link() uint64 { return c.regs().link } +func (c *sigctxt) xer() uint64 { return c.regs().xer } +func (c *sigctxt) ccr() uint64 { return c.regs().ccr } + +func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) } +func (c *sigctxt) sigaddr() uint64 { return c.info.si_addr } +func (c *sigctxt) fault() uint64 { return c.regs().dar } + +func (c *sigctxt) set_r0(x uint64) { c.regs().gpr[0] = x } +func (c *sigctxt) set_r30(x uint64) { c.regs().gpr[30] = x } +func (c *sigctxt) set_pc(x uint64) { c.regs().nip = x } +func (c *sigctxt) set_sp(x uint64) { c.regs().gpr[1] = x } +func (c *sigctxt) set_link(x uint64) { c.regs().link = x } + +func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) } +func (c *sigctxt) set_sigaddr(x uint64) { + *(*uintptr)(add(unsafe.Pointer(c.info), 2*ptrSize)) = uintptr(x) +} diff --git a/src/runtime/signal_nacl.go b/src/runtime/signal_nacl.go new file mode 100644 index 000000000..122648bc3 --- /dev/null +++ b/src/runtime/signal_nacl.go @@ -0,0 +1,45 @@ +// 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. + +package runtime + +type sigTabT struct { + flags int32 + name string +} + +var sigtable = [...]sigTabT{ + /* 0 */ {0, "SIGNONE: no trap"}, + /* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"}, + /* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"}, + /* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"}, + /* 4 */ {_SigThrow, "SIGILL: illegal instruction"}, + /* 5 */ {_SigThrow, "SIGTRAP: trace trap"}, + /* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"}, + /* 7 */ {_SigThrow, "SIGEMT: emulate instruction executed"}, + /* 8 */ {_SigPanic, "SIGFPE: floating-point exception"}, + /* 9 */ {0, "SIGKILL: kill"}, + /* 10 */ {_SigPanic, "SIGBUS: bus error"}, + /* 11 */ {_SigPanic, "SIGSEGV: segmentation violation"}, + /* 12 */ {_SigThrow, "SIGSYS: bad system call"}, + /* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"}, + /* 14 */ {_SigNotify, "SIGALRM: alarm clock"}, + /* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"}, + /* 16 */ {_SigNotify, "SIGURG: urgent condition on socket"}, + /* 17 */ {0, "SIGSTOP: stop"}, + /* 18 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"}, + /* 19 */ {0, "SIGCONT: continue after stop"}, + /* 20 */ {_SigNotify, "SIGCHLD: child status has changed"}, + /* 21 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"}, + /* 22 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"}, + /* 23 */ {_SigNotify, "SIGIO: i/o now possible"}, + /* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"}, + /* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"}, + /* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"}, + /* 27 */ {_SigNotify, "SIGPROF: profiling alarm clock"}, + /* 28 */ {_SigNotify, "SIGWINCH: window size change"}, + /* 29 */ {_SigNotify, "SIGINFO: status request from keyboard"}, + /* 30 */ {_SigNotify, "SIGUSR1: user-defined signal 1"}, + /* 31 */ {_SigNotify, "SIGUSR2: user-defined signal 2"}, +} diff --git a/src/runtime/signal_nacl_386.go b/src/runtime/signal_nacl_386.go new file mode 100644 index 000000000..0a1e7c6ea --- /dev/null +++ b/src/runtime/signal_nacl_386.go @@ -0,0 +1,34 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import "unsafe" + +type sigctxt struct { + info *siginfo + ctxt unsafe.Pointer +} + +func (c *sigctxt) regs() *excregs386 { return &(*exccontext)(c.ctxt).regs } +func (c *sigctxt) eax() uint32 { return c.regs().eax } +func (c *sigctxt) ebx() uint32 { return c.regs().ebx } +func (c *sigctxt) ecx() uint32 { return c.regs().ecx } +func (c *sigctxt) edx() uint32 { return c.regs().edx } +func (c *sigctxt) edi() uint32 { return c.regs().edi } +func (c *sigctxt) esi() uint32 { return c.regs().esi } +func (c *sigctxt) ebp() uint32 { return c.regs().ebp } +func (c *sigctxt) esp() uint32 { return c.regs().esp } +func (c *sigctxt) eip() uint32 { return c.regs().eip } +func (c *sigctxt) eflags() uint32 { return c.regs().eflags } +func (c *sigctxt) cs() uint32 { return ^uint32(0) } +func (c *sigctxt) fs() uint32 { return ^uint32(0) } +func (c *sigctxt) gs() uint32 { return ^uint32(0) } +func (c *sigctxt) sigcode() uint32 { return ^uint32(0) } +func (c *sigctxt) sigaddr() uint32 { return 0 } + +func (c *sigctxt) set_eip(x uint32) { c.regs().eip = x } +func (c *sigctxt) set_esp(x uint32) { c.regs().esp = x } +func (c *sigctxt) set_sigcode(x uint32) {} +func (c *sigctxt) set_sigaddr(x uint32) {} diff --git a/src/runtime/signal_nacl_386.h b/src/runtime/signal_nacl_386.h deleted file mode 100644 index c9481b5f4..000000000 --- a/src/runtime/signal_nacl_386.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#define SIG_REGS(ctxt) (((ExcContext*)(ctxt))->regs) - -#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).eax) -#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).ebx) -#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).ecx) -#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).edx) -#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).edi) -#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).esi) -#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).ebp) -#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).esp) -#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).eip) -#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).eflags) - -#define SIG_CS(info, ctxt) (~0) -#define SIG_FS(info, ctxt) (~0) -#define SIG_GS(info, ctxt) (~0) - -#define SIG_CODE0(info, ctxt) (~0) -#define SIG_CODE1(info, ctxt) (0) diff --git a/src/runtime/signal_nacl_amd64p32.go b/src/runtime/signal_nacl_amd64p32.go new file mode 100644 index 000000000..024cebadd --- /dev/null +++ b/src/runtime/signal_nacl_amd64p32.go @@ -0,0 +1,44 @@ +// 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 runtime + +import "unsafe" + +type sigctxt struct { + info *siginfo + ctxt unsafe.Pointer +} + +func (c *sigctxt) regs() *excregsamd64 { + return &(*exccontext)(c.ctxt).regs +} +func (c *sigctxt) rax() uint64 { return c.regs().rax } +func (c *sigctxt) rbx() uint64 { return c.regs().rbx } +func (c *sigctxt) rcx() uint64 { return c.regs().rcx } +func (c *sigctxt) rdx() uint64 { return c.regs().rdx } +func (c *sigctxt) rdi() uint64 { return c.regs().rdi } +func (c *sigctxt) rsi() uint64 { return c.regs().rsi } +func (c *sigctxt) rbp() uint64 { return c.regs().rbp } +func (c *sigctxt) rsp() uint64 { return c.regs().rsp } +func (c *sigctxt) r8() uint64 { return c.regs().r8 } +func (c *sigctxt) r9() uint64 { return c.regs().r9 } +func (c *sigctxt) r10() uint64 { return c.regs().r10 } +func (c *sigctxt) r11() uint64 { return c.regs().r11 } +func (c *sigctxt) r12() uint64 { return c.regs().r12 } +func (c *sigctxt) r13() uint64 { return c.regs().r13 } +func (c *sigctxt) r14() uint64 { return c.regs().r14 } +func (c *sigctxt) r15() uint64 { return c.regs().r15 } +func (c *sigctxt) rip() uint64 { return c.regs().rip } +func (c *sigctxt) rflags() uint64 { return uint64(c.regs().rflags) } +func (c *sigctxt) cs() uint64 { return ^uint64(0) } +func (c *sigctxt) fs() uint64 { return ^uint64(0) } +func (c *sigctxt) gs() uint64 { return ^uint64(0) } +func (c *sigctxt) sigcode() uint64 { return ^uint64(0) } +func (c *sigctxt) sigaddr() uint64 { return 0 } + +func (c *sigctxt) set_rip(x uint64) { c.regs().rip = x } +func (c *sigctxt) set_rsp(x uint64) { c.regs().rsp = x } +func (c *sigctxt) set_sigcode(x uint64) {} +func (c *sigctxt) set_sigaddr(x uint64) {} diff --git a/src/runtime/signal_nacl_amd64p32.h b/src/runtime/signal_nacl_amd64p32.h deleted file mode 100644 index f62305cb5..000000000 --- a/src/runtime/signal_nacl_amd64p32.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#define SIG_REGS(ctxt) (((ExcContext*)(ctxt))->regs.regs64) - -#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).rax) -#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).rbx) -#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).rcx) -#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).rdx) -#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).rdi) -#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).rsi) -#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).rbp) -#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).rsp) -#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).r8) -#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).r9) -#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).r10) -#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).r11) -#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).r12) -#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).r13) -#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).r14) -#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).r15) -#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).rip) -#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).rflags) - -#define SIG_CS(info, ctxt) (~0) -#define SIG_FS(info, ctxt) (~0) -#define SIG_GS(info, ctxt) (~0) - -#define SIG_CODE0(info, ctxt) (~0) -#define SIG_CODE1(info, ctxt) (0) diff --git a/src/runtime/signal_nacl_arm.go b/src/runtime/signal_nacl_arm.go new file mode 100644 index 000000000..1aeaa4e42 --- /dev/null +++ b/src/runtime/signal_nacl_arm.go @@ -0,0 +1,47 @@ +// 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 runtime + +import "unsafe" + +type sigctxt struct { + info *siginfo + ctxt unsafe.Pointer +} + +func (c *sigctxt) regs() *excregsarm { return &(*exccontext)(c.ctxt).regs } + +func (c *sigctxt) r0() uint32 { return c.regs().r0 } +func (c *sigctxt) r1() uint32 { return c.regs().r1 } +func (c *sigctxt) r2() uint32 { return c.regs().r2 } +func (c *sigctxt) r3() uint32 { return c.regs().r3 } +func (c *sigctxt) r4() uint32 { return c.regs().r4 } +func (c *sigctxt) r5() uint32 { return c.regs().r5 } +func (c *sigctxt) r6() uint32 { return c.regs().r6 } +func (c *sigctxt) r7() uint32 { return c.regs().r7 } +func (c *sigctxt) r8() uint32 { return c.regs().r8 } +func (c *sigctxt) r9() uint32 { return c.regs().r9 } +func (c *sigctxt) r10() uint32 { return c.regs().r10 } +func (c *sigctxt) fp() uint32 { return c.regs().r11 } +func (c *sigctxt) ip() uint32 { return c.regs().r12 } +func (c *sigctxt) sp() uint32 { return c.regs().sp } +func (c *sigctxt) lr() uint32 { return c.regs().lr } +func (c *sigctxt) pc() uint32 { return c.regs().pc } +func (c *sigctxt) cpsr() uint32 { return c.regs().cpsr } +func (c *sigctxt) fault() uint32 { return ^uint32(0) } +func (c *sigctxt) trap() uint32 { return ^uint32(0) } +func (c *sigctxt) error() uint32 { return ^uint32(0) } +func (c *sigctxt) oldmask() uint32 { return ^uint32(0) } + +func (c *sigctxt) sigcode() uint32 { return 0 } +func (c *sigctxt) sigaddr() uint32 { return 0 } + +func (c *sigctxt) set_pc(x uint32) { c.regs().pc = x } +func (c *sigctxt) set_sp(x uint32) { c.regs().sp = x } +func (c *sigctxt) set_lr(x uint32) { c.regs().lr = x } +func (c *sigctxt) set_r10(x uint32) { c.regs().r10 = x } + +func (c *sigctxt) set_sigcode(x uint32) {} +func (c *sigctxt) set_sigaddr(x uint32) {} diff --git a/src/runtime/signal_nacl_arm.h b/src/runtime/signal_nacl_arm.h deleted file mode 100644 index e5bbb211d..000000000 --- a/src/runtime/signal_nacl_arm.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#define SIG_REGS(ctxt) (((ExcContext*)(ctxt))->regs) - -#define SIG_R0(info, ctxt) (SIG_REGS(ctxt).r0) -#define SIG_R1(info, ctxt) (SIG_REGS(ctxt).r1) -#define SIG_R2(info, ctxt) (SIG_REGS(ctxt).r2) -#define SIG_R3(info, ctxt) (SIG_REGS(ctxt).r3) -#define SIG_R4(info, ctxt) (SIG_REGS(ctxt).r4) -#define SIG_R5(info, ctxt) (SIG_REGS(ctxt).r5) -#define SIG_R6(info, ctxt) (SIG_REGS(ctxt).r6) -#define SIG_R7(info, ctxt) (SIG_REGS(ctxt).r7) -#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).r8) -#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).r9) -#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).r10) -#define SIG_FP(info, ctxt) (SIG_REGS(ctxt).r11) -#define SIG_IP(info, ctxt) (SIG_REGS(ctxt).r12) -#define SIG_SP(info, ctxt) (SIG_REGS(ctxt).sp) -#define SIG_LR(info, ctxt) (SIG_REGS(ctxt).lr) -#define SIG_PC(info, ctxt) (SIG_REGS(ctxt).pc) -#define SIG_CPSR(info, ctxt) (SIG_REGS(ctxt).cpsr) -#define SIG_FAULT(info, ctxt) (~0) -#define SIG_TRAP(info, ctxt) (~0) -#define SIG_ERROR(info, ctxt) (~0) -#define SIG_OLDMASK(info, ctxt) (~0) -#define SIG_CODE0(info, ctxt) (~0) diff --git a/src/runtime/signal_netbsd.go b/src/runtime/signal_netbsd.go new file mode 100644 index 000000000..78afc59ef --- /dev/null +++ b/src/runtime/signal_netbsd.go @@ -0,0 +1,46 @@ +// 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. + +package runtime + +type sigTabT struct { + flags int32 + name string +} + +var sigtable = [...]sigTabT{ + /* 0 */ {0, "SIGNONE: no trap"}, + /* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"}, + /* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"}, + /* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"}, + /* 4 */ {_SigThrow, "SIGILL: illegal instruction"}, + /* 5 */ {_SigThrow, "SIGTRAP: trace trap"}, + /* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"}, + /* 7 */ {_SigThrow, "SIGEMT: emulate instruction executed"}, + /* 8 */ {_SigPanic, "SIGFPE: floating-point exception"}, + /* 9 */ {0, "SIGKILL: kill"}, + /* 10 */ {_SigPanic, "SIGBUS: bus error"}, + /* 11 */ {_SigPanic, "SIGSEGV: segmentation violation"}, + /* 12 */ {_SigThrow, "SIGSYS: bad system call"}, + /* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"}, + /* 14 */ {_SigNotify, "SIGALRM: alarm clock"}, + /* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"}, + /* 16 */ {_SigNotify, "SIGURG: urgent condition on socket"}, + /* 17 */ {0, "SIGSTOP: stop"}, + /* 18 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"}, + /* 19 */ {0, "SIGCONT: continue after stop"}, + /* 20 */ {_SigNotify, "SIGCHLD: child status has changed"}, + /* 21 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"}, + /* 22 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"}, + /* 23 */ {_SigNotify, "SIGIO: i/o now possible"}, + /* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"}, + /* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"}, + /* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"}, + /* 27 */ {_SigNotify, "SIGPROF: profiling alarm clock"}, + /* 28 */ {_SigNotify, "SIGWINCH: window size change"}, + /* 29 */ {_SigNotify, "SIGINFO: status request from keyboard"}, + /* 30 */ {_SigNotify, "SIGUSR1: user-defined signal 1"}, + /* 31 */ {_SigNotify, "SIGUSR2: user-defined signal 2"}, + /* 32 */ {_SigNotify, "SIGTHR: reserved"}, +} diff --git a/src/runtime/signal_netbsd_386.go b/src/runtime/signal_netbsd_386.go new file mode 100644 index 000000000..6702336ab --- /dev/null +++ b/src/runtime/signal_netbsd_386.go @@ -0,0 +1,38 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import "unsafe" + +type sigctxt struct { + info *siginfo + ctxt unsafe.Pointer +} + +func (c *sigctxt) regs() *mcontextt { return &(*ucontextt)(c.ctxt).uc_mcontext } +func (c *sigctxt) eax() uint32 { return c.regs().__gregs[_REG_EAX] } +func (c *sigctxt) ebx() uint32 { return c.regs().__gregs[_REG_EBX] } +func (c *sigctxt) ecx() uint32 { return c.regs().__gregs[_REG_ECX] } +func (c *sigctxt) edx() uint32 { return c.regs().__gregs[_REG_EDX] } +func (c *sigctxt) edi() uint32 { return c.regs().__gregs[_REG_EDI] } +func (c *sigctxt) esi() uint32 { return c.regs().__gregs[_REG_ESI] } +func (c *sigctxt) ebp() uint32 { return c.regs().__gregs[_REG_EBP] } +func (c *sigctxt) esp() uint32 { return c.regs().__gregs[_REG_UESP] } +func (c *sigctxt) eip() uint32 { return c.regs().__gregs[_REG_EIP] } +func (c *sigctxt) eflags() uint32 { return c.regs().__gregs[_REG_EFL] } +func (c *sigctxt) cs() uint32 { return uint32(c.regs().__gregs[_REG_CS]) } +func (c *sigctxt) fs() uint32 { return uint32(c.regs().__gregs[_REG_FS]) } +func (c *sigctxt) gs() uint32 { return uint32(c.regs().__gregs[_REG_GS]) } +func (c *sigctxt) sigcode() uint32 { return uint32(c.info._code) } +func (c *sigctxt) sigaddr() uint32 { + return uint32(*(*uint32)(unsafe.Pointer(&c.info._reason[0]))) +} + +func (c *sigctxt) set_eip(x uint32) { c.regs().__gregs[_REG_EIP] = x } +func (c *sigctxt) set_esp(x uint32) { c.regs().__gregs[_REG_UESP] = x } +func (c *sigctxt) set_sigcode(x uint32) { c.info._code = int32(x) } +func (c *sigctxt) set_sigaddr(x uint32) { + *(*uint32)(unsafe.Pointer(&c.info._reason[0])) = x +} diff --git a/src/runtime/signal_netbsd_386.h b/src/runtime/signal_netbsd_386.h deleted file mode 100644 index d5a8a0c4b..000000000 --- a/src/runtime/signal_netbsd_386.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#define SIG_REGS(ctxt) (((UcontextT*)(ctxt))->uc_mcontext) - -#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EAX]) -#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EBX]) -#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_ECX]) -#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EDX]) -#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EDI]) -#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_ESI]) -#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EBP]) -#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_UESP]) -#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EIP]) -#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EFL]) - -#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_CS]) -#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_FS]) -#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_GS]) - -#define SIG_CODE0(info, ctxt) ((info)->_code) -#define SIG_CODE1(info, ctxt) (*(uintptr*)&(info)->_reason[0]) diff --git a/src/runtime/signal_netbsd_amd64.go b/src/runtime/signal_netbsd_amd64.go new file mode 100644 index 000000000..e22f4a724 --- /dev/null +++ b/src/runtime/signal_netbsd_amd64.go @@ -0,0 +1,48 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import "unsafe" + +type sigctxt struct { + info *siginfo + ctxt unsafe.Pointer +} + +func (c *sigctxt) regs() *mcontextt { + return (*mcontextt)(unsafe.Pointer(&(*ucontextt)(c.ctxt).uc_mcontext)) +} +func (c *sigctxt) rax() uint64 { return c.regs().__gregs[_REG_RAX] } +func (c *sigctxt) rbx() uint64 { return c.regs().__gregs[_REG_RBX] } +func (c *sigctxt) rcx() uint64 { return c.regs().__gregs[_REG_RCX] } +func (c *sigctxt) rdx() uint64 { return c.regs().__gregs[_REG_RDX] } +func (c *sigctxt) rdi() uint64 { return c.regs().__gregs[_REG_RDI] } +func (c *sigctxt) rsi() uint64 { return c.regs().__gregs[_REG_RSI] } +func (c *sigctxt) rbp() uint64 { return c.regs().__gregs[_REG_RBP] } +func (c *sigctxt) rsp() uint64 { return c.regs().__gregs[_REG_RSP] } +func (c *sigctxt) r8() uint64 { return c.regs().__gregs[_REG_R8] } +func (c *sigctxt) r9() uint64 { return c.regs().__gregs[_REG_R8] } +func (c *sigctxt) r10() uint64 { return c.regs().__gregs[_REG_R10] } +func (c *sigctxt) r11() uint64 { return c.regs().__gregs[_REG_R11] } +func (c *sigctxt) r12() uint64 { return c.regs().__gregs[_REG_R12] } +func (c *sigctxt) r13() uint64 { return c.regs().__gregs[_REG_R13] } +func (c *sigctxt) r14() uint64 { return c.regs().__gregs[_REG_R14] } +func (c *sigctxt) r15() uint64 { return c.regs().__gregs[_REG_R15] } +func (c *sigctxt) rip() uint64 { return c.regs().__gregs[_REG_RIP] } +func (c *sigctxt) rflags() uint64 { return c.regs().__gregs[_REG_RFLAGS] } +func (c *sigctxt) cs() uint64 { return c.regs().__gregs[_REG_CS] } +func (c *sigctxt) fs() uint64 { return c.regs().__gregs[_REG_FS] } +func (c *sigctxt) gs() uint64 { return c.regs().__gregs[_REG_GS] } +func (c *sigctxt) sigcode() uint64 { return uint64(c.info._code) } +func (c *sigctxt) sigaddr() uint64 { + return uint64(*(*uint64)(unsafe.Pointer(&c.info._reason[0]))) +} + +func (c *sigctxt) set_rip(x uint64) { c.regs().__gregs[_REG_RIP] = x } +func (c *sigctxt) set_rsp(x uint64) { c.regs().__gregs[_REG_RSP] = x } +func (c *sigctxt) set_sigcode(x uint64) { c.info._code = int32(x) } +func (c *sigctxt) set_sigaddr(x uint64) { + *(*uint64)(unsafe.Pointer(&c.info._reason[0])) = x +} diff --git a/src/runtime/signal_netbsd_amd64.h b/src/runtime/signal_netbsd_amd64.h deleted file mode 100644 index 7ec4cd98c..000000000 --- a/src/runtime/signal_netbsd_amd64.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#define SIG_REGS(ctxt) (((UcontextT*)(ctxt))->uc_mcontext) - -#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RAX]) -#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RBX]) -#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RCX]) -#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RDX]) -#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RDI]) -#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RSI]) -#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RBP]) -#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RSP]) -#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R8]) -#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R9]) -#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R10]) -#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R11]) -#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R12]) -#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R13]) -#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R14]) -#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R15]) -#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RIP]) -#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RFLAGS]) - -#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_CS]) -#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_FS]) -#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_GS]) - -#define SIG_CODE0(info, ctxt) ((info)->_code) -#define SIG_CODE1(info, ctxt) (*(uintptr*)&(info)->_reason[0]) diff --git a/src/runtime/signals_plan9.h b/src/runtime/signal_plan9.go index 4ee8e542c..37d24359b 100644 --- a/src/runtime/signals_plan9.h +++ b/src/runtime/signal_plan9.go @@ -2,62 +2,53 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include "textflag.h" +package runtime -#define N SigNotify -#define K SigKill -#define T SigThrow -#define P SigPanic -#define E SigGoExit +type sigTabT struct { + flags int + name []byte +} // Incoming notes are compared against this table using strncmp, so the // order matters: longer patterns must appear before their prefixes. -// There are #defined SIG constants in os_plan9.h for the table index of -// some of these. +// There are _SIG constants in os2_plan9.go for the table index of some +// of these. // // If you add entries to this table, you must respect the prefix ordering -// and also update the constant values is os_plan9.h. - -#pragma dataflag NOPTR -SigTab runtime·sigtab[] = { +// and also update the constant values is os2_plan9.go. +var sigtable = [...]sigTabT{ // Traps that we cannot be recovered. - T, "sys: trap: debug exception", - T, "sys: trap: invalid opcode", + {_SigThrow, []byte("sys: trap: debug exception")}, + {_SigThrow, []byte("sys: trap: invalid opcode")}, // We can recover from some memory errors in runtime·sigpanic. - P, "sys: trap: fault read addr", // SIGRFAULT - P, "sys: trap: fault write addr", // SIGWFAULT + {_SigPanic, []byte("sys: trap: fault read addr")}, // SIGRFAULT + {_SigPanic, []byte("sys: trap: fault write addr")}, // SIGWFAULT // We can also recover from math errors. - P, "sys: trap: divide error", // SIGINTDIV - P, "sys: fp:", // SIGFLOAT + {_SigPanic, []byte("sys: trap: divide error")}, // SIGINTDIV + {_SigPanic, []byte("sys: fp:")}, // SIGFLOAT // All other traps are normally handled as if they were marked SigThrow. // We mark them SigPanic here so that debug.SetPanicOnFault will work. - P, "sys: trap:", // SIGTRAP + {_SigPanic, []byte("sys: trap:")}, // SIGTRAP // Writes to a closed pipe can be handled if desired, otherwise they're ignored. - N, "sys: write on closed pipe", + {_SigNotify, []byte("sys: write on closed pipe")}, // Other system notes are more serious and cannot be recovered. - T, "sys:", + {_SigThrow, []byte("sys:")}, // Issued to all other procs when calling runtime·exit. - E, "go: exit ", + {_SigGoExit, []byte("go: exit ")}, // Kill is sent by external programs to cause an exit. - K, "kill", + {_SigKill, []byte("kill")}, // Interrupts can be handled if desired, otherwise they cause an exit. - N+K, "interrupt", - N+K, "hangup", + {_SigNotify + _SigKill, []byte("interrupt")}, + {_SigNotify + _SigKill, []byte("hangup")}, // Alarms can be handled if desired, otherwise they're ignored. - N, "alarm", -}; - -#undef N -#undef K -#undef T -#undef P -#undef E + {_SigNotify, []byte("alarm")}, +} diff --git a/src/runtime/signal_power64x.c b/src/runtime/signal_power64x.c deleted file mode 100644 index c0bf1c4a5..000000000 --- a/src/runtime/signal_power64x.c +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build linux -// +build power64 power64le - -#include "runtime.h" -#include "defs_GOOS_GOARCH.h" -#include "os_GOOS.h" -#include "signal_GOOS_GOARCH.h" -#include "signals_GOOS.h" - -void -runtime·dumpregs(Siginfo *info, void *ctxt) -{ - USED(info); USED(ctxt); - runtime·printf("r0 %X\t", SIG_R0(info, ctxt)); - runtime·printf("r1 %X\n", SIG_R1(info, ctxt)); - runtime·printf("r2 %X\t", SIG_R2(info, ctxt)); - runtime·printf("r3 %X\n", SIG_R3(info, ctxt)); - runtime·printf("r4 %X\t", SIG_R4(info, ctxt)); - runtime·printf("r5 %X\n", SIG_R5(info, ctxt)); - runtime·printf("r6 %X\t", SIG_R6(info, ctxt)); - runtime·printf("r7 %X\n", SIG_R7(info, ctxt)); - runtime·printf("r8 %X\t", SIG_R8(info, ctxt)); - runtime·printf("r9 %X\n", SIG_R9(info, ctxt)); - runtime·printf("r10 %X\t", SIG_R10(info, ctxt)); - runtime·printf("r11 %X\n", SIG_R11(info, ctxt)); - runtime·printf("r12 %X\t", SIG_R12(info, ctxt)); - runtime·printf("r13 %X\n", SIG_R13(info, ctxt)); - runtime·printf("r14 %X\t", SIG_R14(info, ctxt)); - runtime·printf("r15 %X\n", SIG_R15(info, ctxt)); - runtime·printf("r16 %X\t", SIG_R16(info, ctxt)); - runtime·printf("r17 %X\n", SIG_R17(info, ctxt)); - runtime·printf("r18 %X\t", SIG_R18(info, ctxt)); - runtime·printf("r19 %X\n", SIG_R19(info, ctxt)); - runtime·printf("r20 %X\t", SIG_R20(info, ctxt)); - runtime·printf("r21 %X\n", SIG_R21(info, ctxt)); - runtime·printf("r22 %X\t", SIG_R22(info, ctxt)); - runtime·printf("r23 %X\n", SIG_R23(info, ctxt)); - runtime·printf("r24 %X\t", SIG_R24(info, ctxt)); - runtime·printf("r25 %X\n", SIG_R25(info, ctxt)); - runtime·printf("r26 %X\t", SIG_R26(info, ctxt)); - runtime·printf("r27 %X\n", SIG_R27(info, ctxt)); - runtime·printf("r28 %X\t", SIG_R28(info, ctxt)); - runtime·printf("r29 %X\n", SIG_R29(info, ctxt)); - runtime·printf("r30 %X\t", SIG_R30(info, ctxt)); - runtime·printf("r31 %X\n", SIG_R31(info, ctxt)); - runtime·printf("pc %X\t", SIG_PC(info, ctxt)); - runtime·printf("ctr %X\n", SIG_CTR(info, ctxt)); - runtime·printf("link %X\t", SIG_LINK(info, ctxt)); - runtime·printf("xer %X\n", SIG_XER(info, ctxt)); - runtime·printf("ccr %X\t", SIG_CCR(info, ctxt)); - runtime·printf("trap %X\n", SIG_TRAP(info, ctxt)); -} - -void -runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp) -{ - SigTab *t; - bool crash; - - if(sig == SIGPROF) { - runtime·sigprof((uint8*)SIG_PC(info, ctxt), (uint8*)SIG_SP(info, ctxt), (uint8*)SIG_LINK(info, ctxt), gp, g->m); - return; - } - t = &runtime·sigtab[sig]; - if(SIG_CODE0(info, ctxt) != SI_USER && (t->flags & SigPanic)) { - // Make it look like a call to the signal func. - // Have to pass arguments out of band since - // augmenting the stack frame would break - // the unwinding code. - gp->sig = sig; - gp->sigcode0 = SIG_CODE0(info, ctxt); - gp->sigcode1 = SIG_FAULT(info, ctxt); - gp->sigpc = SIG_PC(info, ctxt); - - // We arrange link, and pc to pretend the panicking - // function calls sigpanic directly. - // Always save LINK to stack so that panics in leaf - // functions are correctly handled. This smashes - // the stack frame but we're not going back there - // anyway. - SIG_SP(info, ctxt) -= sizeof(uintptr); - *(uintptr*)SIG_SP(info, ctxt) = SIG_LINK(info, ctxt); - // Don't bother saving PC if it's zero, which is - // probably a call to a nil func: the old link register - // is more useful in the stack trace. - if(gp->sigpc != 0) - SIG_LINK(info, ctxt) = gp->sigpc; - // In case we are panicking from external C code - SIG_R0(info, ctxt) = 0; - SIG_R30(info, ctxt) = (uintptr)gp; - SIG_PC(info, ctxt) = (uintptr)runtime·sigpanic; - return; - } - - if(SIG_CODE0(info, ctxt) == SI_USER || (t->flags & SigNotify)) - if(runtime·sigsend(sig)) - return; - if(t->flags & SigKill) - runtime·exit(2); - if(!(t->flags & SigThrow)) - return; - - g->m->throwing = 1; - g->m->caughtsig = gp; - if(runtime·panicking) // traceback already printed - runtime·exit(2); - runtime·panicking = 1; - - if(sig < 0 || sig >= NSIG) - runtime·printf("Signal %d\n", sig); - else - runtime·printf("%s\n", runtime·sigtab[sig].name); - - runtime·printf("PC=%x\n", SIG_PC(info, ctxt)); - if(g->m->lockedg != nil && g->m->ncgo > 0 && gp == g->m->g0) { - runtime·printf("signal arrived during cgo execution\n"); - gp = g->m->lockedg; - } - runtime·printf("\n"); - - if(runtime·gotraceback(&crash)){ - runtime·goroutineheader(gp); - runtime·tracebacktrap(SIG_PC(info, ctxt), SIG_SP(info, ctxt), SIG_LINK(info, ctxt), gp); - runtime·tracebackothers(gp); - runtime·printf("\n"); - runtime·dumpregs(info, ctxt); - } - - if(crash) - runtime·crash(); - - runtime·exit(2); -} diff --git a/src/runtime/signal_power64x.go b/src/runtime/signal_power64x.go new file mode 100644 index 000000000..fc83beb1b --- /dev/null +++ b/src/runtime/signal_power64x.go @@ -0,0 +1,144 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build linux +// +build power64 power64le + +package runtime + +import "unsafe" + +func dumpregs(c *sigctxt) { + print("r0 ", hex(c.r0()), "\t") + print("r1 ", hex(c.r1()), "\n") + print("r2 ", hex(c.r2()), "\t") + print("r3 ", hex(c.r3()), "\n") + print("r4 ", hex(c.r4()), "\t") + print("r5 ", hex(c.r5()), "\n") + print("r6 ", hex(c.r6()), "\t") + print("r7 ", hex(c.r7()), "\n") + print("r8 ", hex(c.r8()), "\t") + print("r9 ", hex(c.r9()), "\n") + print("r10 ", hex(c.r10()), "\t") + print("r11 ", hex(c.r11()), "\n") + print("r12 ", hex(c.r12()), "\t") + print("r13 ", hex(c.r13()), "\n") + print("r14 ", hex(c.r14()), "\t") + print("r15 ", hex(c.r15()), "\n") + print("r16 ", hex(c.r16()), "\t") + print("r17 ", hex(c.r17()), "\n") + print("r18 ", hex(c.r18()), "\t") + print("r19 ", hex(c.r19()), "\n") + print("r20 ", hex(c.r20()), "\t") + print("r21 ", hex(c.r21()), "\n") + print("r22 ", hex(c.r22()), "\t") + print("r23 ", hex(c.r23()), "\n") + print("r24 ", hex(c.r24()), "\t") + print("r25 ", hex(c.r25()), "\n") + print("r26 ", hex(c.r26()), "\t") + print("r27 ", hex(c.r27()), "\n") + print("r28 ", hex(c.r28()), "\t") + print("r29 ", hex(c.r29()), "\n") + print("r30 ", hex(c.r30()), "\t") + print("r31 ", hex(c.r31()), "\n") + print("pc ", hex(c.pc()), "\t") + print("ctr ", hex(c.ctr()), "\n") + print("link ", hex(c.link()), "\t") + print("xer ", hex(c.xer()), "\n") + print("ccr ", hex(c.ccr()), "\t") + print("trap ", hex(c.trap()), "\n") +} + +func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) { + _g_ := getg() + c := &sigctxt{info, ctxt} + + if sig == _SIGPROF { + sigprof((*byte)(unsafe.Pointer(uintptr(c.pc()))), (*byte)(unsafe.Pointer(uintptr(c.sp()))), (*byte)(unsafe.Pointer(uintptr(c.link()))), gp, _g_.m) + return + } + flags := int32(_SigThrow) + if sig < uint32(len(sigtable)) { + flags = sigtable[sig].flags + } + if c.sigcode() != _SI_USER && flags&_SigPanic != 0 { + // Make it look like a call to the signal func. + // Have to pass arguments out of band since + // augmenting the stack frame would break + // the unwinding code. + gp.sig = sig + gp.sigcode0 = uintptr(c.sigcode()) + gp.sigcode1 = uintptr(c.fault()) + gp.sigpc = uintptr(c.pc()) + + // We arrange link, and pc to pretend the panicking + // function calls sigpanic directly. + // Always save LINK to stack so that panics in leaf + // functions are correctly handled. This smashes + // the stack frame but we're not going back there + // anyway. + sp := c.sp() - ptrSize + c.set_sp(sp) + *(*uint64)(unsafe.Pointer(uintptr(sp))) = c.link() + + // Don't bother saving PC if it's zero, which is + // probably a call to a nil func: the old link register + // is more useful in the stack trace. + if gp.sigpc != 0 { + c.set_link(uint64(gp.sigpc)) + } + + // In case we are panicking from external C code + c.set_r0(0) + c.set_r30(uint64(uintptr(unsafe.Pointer(gp)))) + c.set_pc(uint64(funcPC(sigpanic))) + return + } + + if c.sigcode() == _SI_USER || flags&_SigNotify != 0 { + if sigsend(sig) { + return + } + } + + if flags&_SigKill != 0 { + exit(2) + } + + if flags&_SigThrow == 0 { + return + } + + _g_.m.throwing = 1 + _g_.m.caughtsig = gp + startpanic() + + if sig < uint32(len(sigtable)) { + print(sigtable[sig].name, "\n") + } else { + print("Signal ", sig, "\n") + } + + print("PC=", hex(c.pc()), "\n") + if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 { + print("signal arrived during cgo execution\n") + gp = _g_.m.lockedg + } + print("\n") + + var docrash bool + if gotraceback(&docrash) > 0 { + goroutineheader(gp) + tracebacktrap(uintptr(c.pc()), uintptr(c.sp()), uintptr(c.link()), gp) + tracebackothers(gp) + print("\n") + dumpregs(c) + } + + if docrash { + crash() + } + + exit(2) +} diff --git a/src/runtime/signals_android.h b/src/runtime/signals_android.h deleted file mode 100644 index 5140d8a18..000000000 --- a/src/runtime/signals_android.h +++ /dev/null @@ -1 +0,0 @@ -#include "signals_linux.h" diff --git a/src/runtime/signals_nacl.h b/src/runtime/signals_nacl.h deleted file mode 100644 index 8761e1bd9..000000000 --- a/src/runtime/signals_nacl.h +++ /dev/null @@ -1,53 +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 "textflag.h" - -#define N SigNotify -#define K SigKill -#define T SigThrow -#define P SigPanic -#define D SigDefault - -#pragma dataflag NOPTR -SigTab runtime·sigtab[] = { - /* 0 */ 0, "SIGNONE: no trap", - /* 1 */ N+K, "SIGHUP: terminal line hangup", - /* 2 */ N+K, "SIGINT: interrupt", - /* 3 */ N+T, "SIGQUIT: quit", - /* 4 */ T, "SIGILL: illegal instruction", - /* 5 */ T, "SIGTRAP: trace trap", - /* 6 */ N+T, "SIGABRT: abort", - /* 7 */ T, "SIGEMT: emulate instruction executed", - /* 8 */ P, "SIGFPE: floating-point exception", - /* 9 */ 0, "SIGKILL: kill", - /* 10 */ P, "SIGBUS: bus error", - /* 11 */ P, "SIGSEGV: segmentation violation", - /* 12 */ T, "SIGSYS: bad system call", - /* 13 */ N, "SIGPIPE: write to broken pipe", - /* 14 */ N, "SIGALRM: alarm clock", - /* 15 */ N+K, "SIGTERM: termination", - /* 16 */ N, "SIGURG: urgent condition on socket", - /* 17 */ 0, "SIGSTOP: stop", - /* 18 */ N+D, "SIGTSTP: keyboard stop", - /* 19 */ 0, "SIGCONT: continue after stop", - /* 20 */ N, "SIGCHLD: child status has changed", - /* 21 */ N+D, "SIGTTIN: background read from tty", - /* 22 */ N+D, "SIGTTOU: background write to tty", - /* 23 */ N, "SIGIO: i/o now possible", - /* 24 */ N, "SIGXCPU: cpu limit exceeded", - /* 25 */ N, "SIGXFSZ: file size limit exceeded", - /* 26 */ N, "SIGVTALRM: virtual alarm clock", - /* 27 */ N, "SIGPROF: profiling alarm clock", - /* 28 */ N, "SIGWINCH: window size change", - /* 29 */ N, "SIGINFO: status request from keyboard", - /* 30 */ N, "SIGUSR1: user-defined signal 1", - /* 31 */ N, "SIGUSR2: user-defined signal 2", -}; - -#undef N -#undef K -#undef T -#undef P -#undef D diff --git a/src/runtime/signals_netbsd.h b/src/runtime/signals_netbsd.h deleted file mode 100644 index 950a2fe62..000000000 --- a/src/runtime/signals_netbsd.h +++ /dev/null @@ -1,54 +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 "textflag.h" - -#define N SigNotify -#define K SigKill -#define T SigThrow -#define P SigPanic -#define D SigDefault - -#pragma dataflag NOPTR -SigTab runtime·sigtab[] = { - /* 0 */ 0, "SIGNONE: no trap", - /* 1 */ N+K, "SIGHUP: terminal line hangup", - /* 2 */ N+K, "SIGINT: interrupt", - /* 3 */ N+T, "SIGQUIT: quit", - /* 4 */ T, "SIGILL: illegal instruction", - /* 5 */ T, "SIGTRAP: trace trap", - /* 6 */ N+T, "SIGABRT: abort", - /* 7 */ T, "SIGEMT: emulate instruction executed", - /* 8 */ P, "SIGFPE: floating-point exception", - /* 9 */ 0, "SIGKILL: kill", - /* 10 */ P, "SIGBUS: bus error", - /* 11 */ P, "SIGSEGV: segmentation violation", - /* 12 */ T, "SIGSYS: bad system call", - /* 13 */ N, "SIGPIPE: write to broken pipe", - /* 14 */ N, "SIGALRM: alarm clock", - /* 15 */ N+K, "SIGTERM: termination", - /* 16 */ N, "SIGURG: urgent condition on socket", - /* 17 */ 0, "SIGSTOP: stop", - /* 18 */ N+D, "SIGTSTP: keyboard stop", - /* 19 */ 0, "SIGCONT: continue after stop", - /* 20 */ N, "SIGCHLD: child status has changed", - /* 21 */ N+D, "SIGTTIN: background read from tty", - /* 22 */ N+D, "SIGTTOU: background write to tty", - /* 23 */ N, "SIGIO: i/o now possible", - /* 24 */ N, "SIGXCPU: cpu limit exceeded", - /* 25 */ N, "SIGXFSZ: file size limit exceeded", - /* 26 */ N, "SIGVTALRM: virtual alarm clock", - /* 27 */ N, "SIGPROF: profiling alarm clock", - /* 28 */ N, "SIGWINCH: window size change", - /* 29 */ N, "SIGINFO: status request from keyboard", - /* 30 */ N, "SIGUSR1: user-defined signal 1", - /* 31 */ N, "SIGUSR2: user-defined signal 2", - /* 32 */ N, "SIGTHR: reserved", -}; - -#undef N -#undef K -#undef T -#undef P -#undef D diff --git a/src/runtime/stack1.go b/src/runtime/stack1.go index 57d0f8c65..c14347dbd 100644 --- a/src/runtime/stack1.go +++ b/src/runtime/stack1.go @@ -781,7 +781,7 @@ func shrinkstack(gp *g) { if gp.syscallsp != 0 { return } - if _Windows != 0 && gp.m != nil && gp.m.libcallsp != 0 { + if goos_windows != 0 && gp.m != nil && gp.m.libcallsp != 0 { return } diff --git a/src/runtime/stack2.go b/src/runtime/stack2.go index c3718c205..e50b32c78 100644 --- a/src/runtime/stack2.go +++ b/src/runtime/stack2.go @@ -59,7 +59,7 @@ const ( // to each stack below the usual guard area for OS-specific // purposes like signal handling. Used on Windows and on // Plan 9 because they do not use a separate stack. - _StackSystem = _Windows*512*ptrSize + _Plan9*512 + _StackSystem = goos_windows*512*ptrSize + goos_plan9*512 // The minimum size of stack used by Go code _StackMin = 2048 diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go index 4063e5434..4408e22bf 100644 --- a/src/runtime/stubs.go +++ b/src/runtime/stubs.go @@ -154,7 +154,7 @@ func setcallerpc(argp unsafe.Pointer, pc uintptr) // // func f(arg1, arg2, arg3 int) { // pc := getcallerpc(unsafe.Pointer(&arg1)) -// sp := getcallerpc(unsafe.Pointer(&arg2)) +// sp := getcallersp(unsafe.Pointer(&arg1)) // } // // These two lines find the PC and SP immediately following diff --git a/src/runtime/stubs2.go b/src/runtime/stubs2.go index 526b3c569..60751dd34 100644 --- a/src/runtime/stubs2.go +++ b/src/runtime/stubs2.go @@ -2,7 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build !plan9 // +build !solaris +// +build !windows +// +build !nacl package runtime diff --git a/src/runtime/arch_power64le.h b/src/runtime/stubs3.go index 684ac9953..ffaa28775 100644 --- a/src/runtime/arch_power64le.h +++ b/src/runtime/stubs3.go @@ -2,13 +2,11 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -enum { - thechar = '9', - BigEndian = 0, - CacheLineSize = 64, - RuntimeGogoBytes = 64, - PhysPageSize = 65536, - PCQuantum = 4, - Int64Align = 8 -}; +// +build plan9 +package runtime + +func close(fd int32) int32 + +//go:noescape +func open(name *byte, mode, perm int32) int32 diff --git a/src/runtime/sys_linux_power64x.s b/src/runtime/sys_linux_power64x.s index fb24d3e79..395f657bf 100644 --- a/src/runtime/sys_linux_power64x.s +++ b/src/runtime/sys_linux_power64x.s @@ -9,7 +9,8 @@ // System calls and other sys.stuff for Power64, Linux // -#include "zasm_GOOS_GOARCH.h" +#include "go_asm.h" +#include "go_tls.h" #include "textflag.h" #define SYS_exit 1 diff --git a/src/runtime/sys_power64x.c b/src/runtime/sys_power64x.c deleted file mode 100644 index 79d976255..000000000 --- a/src/runtime/sys_power64x.c +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build power64 power64le - -#include "runtime.h" - -// adjust Gobuf as if it executed a call to fn with context ctxt -// and then did an immediate Gosave. -void -runtime·gostartcall(Gobuf *gobuf, void (*fn)(void), void *ctxt) -{ - if(gobuf->lr != 0) - runtime·throw("invalid use of gostartcall"); - gobuf->lr = gobuf->pc; - gobuf->pc = (uintptr)fn; - gobuf->ctxt = ctxt; -} - -// Called to rewind context saved during morestack back to beginning of function. -// To help us, the linker emits a jmp back to the beginning right after the -// call to morestack. We just have to decode and apply that jump. -void -runtime·rewindmorestack(Gobuf *gobuf) -{ - uint32 inst; - - inst = *(uint32*)gobuf->pc; - if((gobuf->pc&3) == 0 && (inst>>24) == 0x4b && (inst&3) == 0) { - //runtime·printf("runtime: rewind pc=%p to pc=%p\n", gobuf->pc, gobuf->pc + ((int32)(inst<<8)>>8)); - gobuf->pc += (int32)(inst<<8)>>8; - return; - } - runtime·printf("runtime: pc=%p %x\n", gobuf->pc, inst); - runtime·throw("runtime: misuse of rewindmorestack"); -} - diff --git a/src/runtime/sys_power64x.go b/src/runtime/sys_power64x.go new file mode 100644 index 000000000..90ebde7b4 --- /dev/null +++ b/src/runtime/sys_power64x.go @@ -0,0 +1,37 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build power64 power64le + +package runtime + +import "unsafe" + +// adjust Gobuf as if it executed a call to fn with context ctxt +// and then did an immediate Gosave. +func gostartcall(buf *gobuf, fn, ctxt unsafe.Pointer) { + if buf.lr != 0 { + gothrow("invalid use of gostartcall") + } + buf.lr = buf.pc + buf.pc = uintptr(fn) + buf.ctxt = ctxt +} + +// Called to rewind context saved during morestack back to beginning of function. +// To help us, the linker emits a jmp back to the beginning right after the +// call to morestack. We just have to decode and apply that jump. +func rewindmorestack(buf *gobuf) { + var inst uint32 + if buf.pc&3 == 0 && buf.pc != 0 { + inst = *(*uint32)(unsafe.Pointer(buf.pc)) + if inst>>26 == 18 && inst&3 == 0 { + //print("runtime: rewind pc=", hex(buf.pc), " to pc=", hex(uintptr(buf.pc + int32(inst<<6)>>6)), "\n"); + buf.pc += uintptr(int32(inst<<6) >> 6) + return + } + } + print("runtime: pc=", hex(buf.pc), " ", hex(inst), "\n") + gothrow("runtime: misuse of rewindmorestack") +} diff --git a/src/runtime/sys_windows_386.s b/src/runtime/sys_windows_386.s index 2793e5221..c8a830cdf 100644 --- a/src/runtime/sys_windows_386.s +++ b/src/runtime/sys_windows_386.s @@ -44,7 +44,7 @@ TEXT runtime·badsignal2(SB),NOSPLIT,$24 // stderr MOVL $-12, 0(SP) MOVL SP, BP - CALL *runtime·GetStdHandle(SB) + CALL *runtime·_GetStdHandle(SB) MOVL BP, SP MOVL AX, 0(SP) // handle @@ -56,7 +56,7 @@ TEXT runtime·badsignal2(SB),NOSPLIT,$24 MOVL $0, 0(DX) MOVL DX, 12(SP) MOVL $0, 16(SP) // overlapped - CALL *runtime·WriteFile(SB) + CALL *runtime·_WriteFile(SB) MOVL BP, SI RET @@ -208,7 +208,7 @@ TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0 MOVL BX, g_m(SP) LEAL -8192(SP), CX MOVL CX, (g_stack+stack_lo)(SP) - ADDL $const_StackGuard, CX + ADDL $const__StackGuard, CX MOVL CX, g_stackguard0(SP) MOVL CX, g_stackguard1(SP) MOVL DX, (g_stack+stack_hi)(SP) @@ -255,8 +255,8 @@ TEXT runtime·callbackasm1+0(SB),NOSPLIT,$0 MOVL -4(BX)(AX*4), BX // extract callback context - MOVL cbctxt_gobody(BX), AX - MOVL cbctxt_argsize(BX), DX + MOVL wincallbackcontext_gobody(BX), AX + MOVL wincallbackcontext_argsize(BX), DX // preserve whatever's at the memory location that // the callback will use to store the return value @@ -266,7 +266,7 @@ TEXT runtime·callbackasm1+0(SB),NOSPLIT,$0 ADDL $4, DX // remember how to restore stack on return - MOVL cbctxt_restorestack(BX), BX + MOVL wincallbackcontext_restorestack(BX), BX PUSHL BX // call target Go function @@ -314,7 +314,7 @@ TEXT runtime·tstart(SB),NOSPLIT,$0 MOVL AX, (g_stack+stack_hi)(DX) SUBL $(64*1024), AX // stack size MOVL AX, (g_stack+stack_lo)(DX) - ADDL $const_StackGuard, AX + ADDL $const__StackGuard, AX MOVL AX, g_stackguard0(DX) MOVL AX, g_stackguard1(DX) @@ -415,7 +415,7 @@ TEXT runtime·usleep2(SB),NOSPLIT,$20 MOVL $0, alertable-16(SP) MOVL $-1, handle-20(SP) MOVL SP, BP - MOVL runtime·NtWaitForSingleObject(SB), AX + MOVL runtime·_NtWaitForSingleObject(SB), AX CALL AX MOVL BP, SP RET diff --git a/src/runtime/sys_windows_amd64.s b/src/runtime/sys_windows_amd64.s index 5e5c2e7f5..68f7cd392 100644 --- a/src/runtime/sys_windows_amd64.s +++ b/src/runtime/sys_windows_amd64.s @@ -66,7 +66,7 @@ TEXT runtime·badsignal2(SB),NOSPLIT,$48 // stderr MOVQ $-12, CX // stderr MOVQ CX, 0(SP) - MOVQ runtime·GetStdHandle(SB), AX + MOVQ runtime·_GetStdHandle(SB), AX CALL AX MOVQ AX, CX // handle @@ -79,7 +79,7 @@ TEXT runtime·badsignal2(SB),NOSPLIT,$48 MOVQ $0, 0(R9) MOVQ R9, 24(SP) MOVQ $0, 32(SP) // overlapped - MOVQ runtime·WriteFile(SB), AX + MOVQ runtime·_WriteFile(SB), AX CALL AX RET @@ -245,7 +245,7 @@ TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0 LEAQ -8192(SP), CX MOVQ CX, (g_stack+stack_lo)(SP) - ADDQ $const_StackGuard, CX + ADDQ $const__StackGuard, CX MOVQ CX, g_stackguard0(SP) MOVQ CX, g_stackguard1(SP) MOVQ DX, (g_stack+stack_hi)(SP) @@ -294,8 +294,8 @@ TEXT runtime·callbackasm1(SB),NOSPLIT,$0 MOVQ -8(CX)(AX*8), AX // extract callback context - MOVQ cbctxt_argsize(AX), DX - MOVQ cbctxt_gobody(AX), AX + MOVQ wincallbackcontext_argsize(AX), DX + MOVQ wincallbackcontext_gobody(AX), AX // preserve whatever's at the memory location that // the callback will use to store the return value @@ -355,7 +355,7 @@ TEXT runtime·tstart_stdcall(SB),NOSPLIT,$0 MOVQ AX, (g_stack+stack_hi)(DX) SUBQ $(64*1024), AX // stack size MOVQ AX, (g_stack+stack_lo)(DX) - ADDQ $const_StackGuard, AX + ADDQ $const__StackGuard, AX MOVQ AX, g_stackguard0(DX) MOVQ AX, g_stackguard1(DX) @@ -436,7 +436,7 @@ TEXT runtime·usleep2(SB),NOSPLIT,$16 MOVQ BX, (R8) MOVQ $-1, CX // handle MOVQ $0, DX // alertable - MOVQ runtime·NtWaitForSingleObject(SB), AX + MOVQ runtime·_NtWaitForSingleObject(SB), AX CALL AX MOVQ 8(SP), SP RET diff --git a/src/runtime/syscall_windows.go b/src/runtime/syscall_windows.go index efbcab510..661ee59d7 100644 --- a/src/runtime/syscall_windows.go +++ b/src/runtime/syscall_windows.go @@ -41,20 +41,20 @@ func callbackasmAddr(i int) uintptr { func compileCallback(fn eface, cleanstack bool) (code uintptr) { if fn._type == nil || (fn._type.kind&kindMask) != kindFunc { - panic("compilecallback: not a function") + panic("compileCallback: not a function") } ft := (*functype)(unsafe.Pointer(fn._type)) - if len(ft.out) != 1 { - panic("compilecallback: function must have one output parameter") + if ft.out.len != 1 { + panic("compileCallback: function must have one output parameter") } uintptrSize := unsafe.Sizeof(uintptr(0)) - if t := (**_type)(unsafe.Pointer(&ft.out[0])); (*t).size != uintptrSize { - panic("compilecallback: output parameter size is wrong") + if t := (**_type)(unsafe.Pointer(ft.out.array)); (*t).size != uintptrSize { + panic("compileCallback: output parameter size is wrong") } argsize := uintptr(0) - for _, t := range (*[1024](*_type))(unsafe.Pointer(&ft.in[0]))[:len(ft.in)] { + for _, t := range (*[1024](*_type))(unsafe.Pointer(ft.in.array))[:ft.in.len] { if (*t).size > uintptrSize { - panic("compilecallback: input parameter size is wrong") + panic("compileCallback: input parameter size is wrong") } argsize += uintptrSize } @@ -87,8 +87,6 @@ func compileCallback(fn eface, cleanstack bool) (code uintptr) { return callbackasmAddr(n) } -func getLoadLibrary() uintptr - //go:nosplit func syscall_loadlibrary(filename *uint16) (handle, err uintptr) { var c libcall @@ -103,8 +101,6 @@ func syscall_loadlibrary(filename *uint16) (handle, err uintptr) { return } -func getGetProcAddress() uintptr - //go:nosplit func syscall_getprocaddress(handle uintptr, procname *byte) (outhandle, err uintptr) { var c libcall diff --git a/src/runtime/zgoarch_386.go b/src/runtime/zgoarch_386.go new file mode 100644 index 000000000..057a746bb --- /dev/null +++ b/src/runtime/zgoarch_386.go @@ -0,0 +1,12 @@ +// generated by gengoos.go using 'go generate' + +package runtime + +const theGoarch = `386` + +const goarch_386 = 1 +const goarch_amd64 = 0 +const goarch_amd64p32 = 0 +const goarch_arm = 0 +const goarch_power64 = 0 +const goarch_power64le = 0 diff --git a/src/runtime/zgoarch_amd64.go b/src/runtime/zgoarch_amd64.go new file mode 100644 index 000000000..a71240726 --- /dev/null +++ b/src/runtime/zgoarch_amd64.go @@ -0,0 +1,12 @@ +// generated by gengoos.go using 'go generate' + +package runtime + +const theGoarch = `amd64` + +const goarch_386 = 0 +const goarch_amd64 = 1 +const goarch_amd64p32 = 0 +const goarch_arm = 0 +const goarch_power64 = 0 +const goarch_power64le = 0 diff --git a/src/runtime/zgoarch_amd64p32.go b/src/runtime/zgoarch_amd64p32.go new file mode 100644 index 000000000..2b6a142bb --- /dev/null +++ b/src/runtime/zgoarch_amd64p32.go @@ -0,0 +1,12 @@ +// generated by gengoos.go using 'go generate' + +package runtime + +const theGoarch = `amd64p32` + +const goarch_386 = 0 +const goarch_amd64 = 0 +const goarch_amd64p32 = 1 +const goarch_arm = 0 +const goarch_power64 = 0 +const goarch_power64le = 0 diff --git a/src/runtime/zgoarch_arm.go b/src/runtime/zgoarch_arm.go new file mode 100644 index 000000000..403021005 --- /dev/null +++ b/src/runtime/zgoarch_arm.go @@ -0,0 +1,12 @@ +// generated by gengoos.go using 'go generate' + +package runtime + +const theGoarch = `arm` + +const goarch_386 = 0 +const goarch_amd64 = 0 +const goarch_amd64p32 = 0 +const goarch_arm = 1 +const goarch_power64 = 0 +const goarch_power64le = 0 diff --git a/src/runtime/zgoarch_power64.go b/src/runtime/zgoarch_power64.go new file mode 100644 index 000000000..cc361f050 --- /dev/null +++ b/src/runtime/zgoarch_power64.go @@ -0,0 +1,12 @@ +// generated by gengoos.go using 'go generate' + +package runtime + +const theGoarch = `power64` + +const goarch_386 = 0 +const goarch_amd64 = 0 +const goarch_amd64p32 = 0 +const goarch_arm = 0 +const goarch_power64 = 1 +const goarch_power64le = 0 diff --git a/src/runtime/zgoarch_power64le.go b/src/runtime/zgoarch_power64le.go new file mode 100644 index 000000000..41294e61b --- /dev/null +++ b/src/runtime/zgoarch_power64le.go @@ -0,0 +1,12 @@ +// generated by gengoos.go using 'go generate' + +package runtime + +const theGoarch = `power64le` + +const goarch_386 = 0 +const goarch_amd64 = 0 +const goarch_amd64p32 = 0 +const goarch_arm = 0 +const goarch_power64 = 0 +const goarch_power64le = 1 diff --git a/src/runtime/zgoos_android.go b/src/runtime/zgoos_android.go new file mode 100644 index 000000000..0590bd9ab --- /dev/null +++ b/src/runtime/zgoos_android.go @@ -0,0 +1,17 @@ +// generated by gengoos.go using 'go generate' + +package runtime + +const theGoos = `android` + +const goos_android = 1 +const goos_darwin = 0 +const goos_dragonfly = 0 +const goos_freebsd = 0 +const goos_linux = 0 +const goos_nacl = 0 +const goos_netbsd = 0 +const goos_openbsd = 0 +const goos_plan9 = 0 +const goos_solaris = 0 +const goos_windows = 0 diff --git a/src/runtime/zgoos_darwin.go b/src/runtime/zgoos_darwin.go new file mode 100644 index 000000000..c0a7cd6e7 --- /dev/null +++ b/src/runtime/zgoos_darwin.go @@ -0,0 +1,17 @@ +// generated by gengoos.go using 'go generate' + +package runtime + +const theGoos = `darwin` + +const goos_android = 0 +const goos_darwin = 1 +const goos_dragonfly = 0 +const goos_freebsd = 0 +const goos_linux = 0 +const goos_nacl = 0 +const goos_netbsd = 0 +const goos_openbsd = 0 +const goos_plan9 = 0 +const goos_solaris = 0 +const goos_windows = 0 diff --git a/src/runtime/zgoos_dragonfly.go b/src/runtime/zgoos_dragonfly.go new file mode 100644 index 000000000..008d6de81 --- /dev/null +++ b/src/runtime/zgoos_dragonfly.go @@ -0,0 +1,17 @@ +// generated by gengoos.go using 'go generate' + +package runtime + +const theGoos = `dragonfly` + +const goos_android = 0 +const goos_darwin = 0 +const goos_dragonfly = 1 +const goos_freebsd = 0 +const goos_linux = 0 +const goos_nacl = 0 +const goos_netbsd = 0 +const goos_openbsd = 0 +const goos_plan9 = 0 +const goos_solaris = 0 +const goos_windows = 0 diff --git a/src/runtime/zgoos_freebsd.go b/src/runtime/zgoos_freebsd.go new file mode 100644 index 000000000..247894035 --- /dev/null +++ b/src/runtime/zgoos_freebsd.go @@ -0,0 +1,17 @@ +// generated by gengoos.go using 'go generate' + +package runtime + +const theGoos = `freebsd` + +const goos_android = 0 +const goos_darwin = 0 +const goos_dragonfly = 0 +const goos_freebsd = 1 +const goos_linux = 0 +const goos_nacl = 0 +const goos_netbsd = 0 +const goos_openbsd = 0 +const goos_plan9 = 0 +const goos_solaris = 0 +const goos_windows = 0 diff --git a/src/runtime/zgoos_linux.go b/src/runtime/zgoos_linux.go new file mode 100644 index 000000000..c775ab538 --- /dev/null +++ b/src/runtime/zgoos_linux.go @@ -0,0 +1,19 @@ +// generated by gengoos.go using 'go generate' + +// +build !android + +package runtime + +const theGoos = `linux` + +const goos_android = 0 +const goos_darwin = 0 +const goos_dragonfly = 0 +const goos_freebsd = 0 +const goos_linux = 1 +const goos_nacl = 0 +const goos_netbsd = 0 +const goos_openbsd = 0 +const goos_plan9 = 0 +const goos_solaris = 0 +const goos_windows = 0 diff --git a/src/runtime/zgoos_nacl.go b/src/runtime/zgoos_nacl.go new file mode 100644 index 000000000..d9d88f450 --- /dev/null +++ b/src/runtime/zgoos_nacl.go @@ -0,0 +1,17 @@ +// generated by gengoos.go using 'go generate' + +package runtime + +const theGoos = `nacl` + +const goos_android = 0 +const goos_darwin = 0 +const goos_dragonfly = 0 +const goos_freebsd = 0 +const goos_linux = 0 +const goos_nacl = 1 +const goos_netbsd = 0 +const goos_openbsd = 0 +const goos_plan9 = 0 +const goos_solaris = 0 +const goos_windows = 0 diff --git a/src/runtime/zgoos_netbsd.go b/src/runtime/zgoos_netbsd.go new file mode 100644 index 000000000..ff2c5cb8f --- /dev/null +++ b/src/runtime/zgoos_netbsd.go @@ -0,0 +1,17 @@ +// generated by gengoos.go using 'go generate' + +package runtime + +const theGoos = `netbsd` + +const goos_android = 0 +const goos_darwin = 0 +const goos_dragonfly = 0 +const goos_freebsd = 0 +const goos_linux = 0 +const goos_nacl = 0 +const goos_netbsd = 1 +const goos_openbsd = 0 +const goos_plan9 = 0 +const goos_solaris = 0 +const goos_windows = 0 diff --git a/src/runtime/zgoos_openbsd.go b/src/runtime/zgoos_openbsd.go new file mode 100644 index 000000000..b071dc63a --- /dev/null +++ b/src/runtime/zgoos_openbsd.go @@ -0,0 +1,17 @@ +// generated by gengoos.go using 'go generate' + +package runtime + +const theGoos = `openbsd` + +const goos_android = 0 +const goos_darwin = 0 +const goos_dragonfly = 0 +const goos_freebsd = 0 +const goos_linux = 0 +const goos_nacl = 0 +const goos_netbsd = 0 +const goos_openbsd = 1 +const goos_plan9 = 0 +const goos_solaris = 0 +const goos_windows = 0 diff --git a/src/runtime/zgoos_plan9.go b/src/runtime/zgoos_plan9.go new file mode 100644 index 000000000..4306b0f1e --- /dev/null +++ b/src/runtime/zgoos_plan9.go @@ -0,0 +1,17 @@ +// generated by gengoos.go using 'go generate' + +package runtime + +const theGoos = `plan9` + +const goos_android = 0 +const goos_darwin = 0 +const goos_dragonfly = 0 +const goos_freebsd = 0 +const goos_linux = 0 +const goos_nacl = 0 +const goos_netbsd = 0 +const goos_openbsd = 0 +const goos_plan9 = 1 +const goos_solaris = 0 +const goos_windows = 0 diff --git a/src/runtime/zgoos_solaris.go b/src/runtime/zgoos_solaris.go new file mode 100644 index 000000000..10f9537d0 --- /dev/null +++ b/src/runtime/zgoos_solaris.go @@ -0,0 +1,17 @@ +// generated by gengoos.go using 'go generate' + +package runtime + +const theGoos = `solaris` + +const goos_android = 0 +const goos_darwin = 0 +const goos_dragonfly = 0 +const goos_freebsd = 0 +const goos_linux = 0 +const goos_nacl = 0 +const goos_netbsd = 0 +const goos_openbsd = 0 +const goos_plan9 = 0 +const goos_solaris = 1 +const goos_windows = 0 diff --git a/src/runtime/zgoos_windows.go b/src/runtime/zgoos_windows.go new file mode 100644 index 000000000..56f5c58ce --- /dev/null +++ b/src/runtime/zgoos_windows.go @@ -0,0 +1,17 @@ +// generated by gengoos.go using 'go generate' + +package runtime + +const theGoos = `windows` + +const goos_android = 0 +const goos_darwin = 0 +const goos_dragonfly = 0 +const goos_freebsd = 0 +const goos_linux = 0 +const goos_nacl = 0 +const goos_netbsd = 0 +const goos_openbsd = 0 +const goos_plan9 = 0 +const goos_solaris = 0 +const goos_windows = 1 diff --git a/src/syscall/exec_bsd.go b/src/syscall/exec_bsd.go index 7c2c1f707..ff78f197f 100644 --- a/src/syscall/exec_bsd.go +++ b/src/syscall/exec_bsd.go @@ -19,8 +19,6 @@ type SysProcAttr struct { Setpgid bool // Set process group ID to new pid (SYSV setpgrp) Setctty bool // Set controlling terminal to fd 0 Noctty bool // Detach fd 0 from controlling terminal - Foreground bool // Set foreground process group to child's pid. (Implies Setpgid. Stdin should be a TTY) - Joinpgrp int // If != 0, child's process group ID. (Setpgid must not be set) } // Implemented in runtime package. @@ -81,22 +79,7 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr if r1 != 0 { // parent; return PID runtime_AfterFork() - pid = int(r1) - - if sys.Joinpgrp != 0 { - // Place the child in the specified process group. - RawSyscall(SYS_SETPGID, r1, uintptr(sys.Joinpgrp), 0) - } else if sys.Foreground || sys.Setpgid { - // Place the child in a new process group. - RawSyscall(SYS_SETPGID, 0, 0, 0) - - if sys.Foreground { - // Set new foreground process group. - RawSyscall(SYS_IOCTL, uintptr(Stdin), TIOCSPGRP, uintptr(unsafe.Pointer(&pid))) - } - } - - return pid, 0 + return int(r1), 0 } // Fork succeeded, now in child. @@ -118,30 +101,11 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr } // Set process group - if sys.Joinpgrp != 0 { - // Place the child in the specified process group. - _, _, err1 = RawSyscall(SYS_SETPGID, r1, uintptr(sys.Joinpgrp), 0) - if err1 != 0 { - goto childerror - } - } else if sys.Foreground || sys.Setpgid { - // Place the child in a new process group. + if sys.Setpgid { _, _, err1 = RawSyscall(SYS_SETPGID, 0, 0, 0) if err1 != 0 { goto childerror } - - if sys.Foreground { - r1, _, _ = RawSyscall(SYS_GETPID, 0, 0, 0) - - pid := int(r1) - - // Set new foreground process group. - _, _, err1 = RawSyscall(SYS_IOCTL, uintptr(Stdin), TIOCSPGRP, uintptr(unsafe.Pointer(&pid))) - if err1 != 0 { - goto childerror - } - } } // Chroot diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go index 72e2f0b69..042c20a46 100644 --- a/src/syscall/exec_linux.go +++ b/src/syscall/exec_linux.go @@ -29,8 +29,6 @@ type SysProcAttr struct { Ctty int // Controlling TTY fd (Linux only) Pdeathsig Signal // Signal that the process will get when its parent dies (Linux only) Cloneflags uintptr // Flags for clone calls (Linux only) - Foreground bool // Set foreground process group to child's pid. (Implies Setpgid. Stdin should be a TTY) - Joinpgrp int // If != 0, child's process group ID. (Setpgid must not be set) UidMappings []SysProcIDMap // User ID mappings for user namespaces. GidMappings []SysProcIDMap // Group ID mappings for user namespaces. } @@ -105,19 +103,6 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr Close(p[1]) } - if sys.Joinpgrp != 0 { - // Place the child in the specified process group. - RawSyscall(SYS_SETPGID, r1, uintptr(sys.Joinpgrp), 0) - } else if sys.Foreground || sys.Setpgid { - // Place the child in a new process group. - RawSyscall(SYS_SETPGID, 0, 0, 0) - - if sys.Foreground { - // Set new foreground process group. - RawSyscall(SYS_IOCTL, uintptr(Stdin), TIOCSPGRP, uintptr(unsafe.Pointer(&pid))) - } - } - return pid, 0 } @@ -179,30 +164,11 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr } // Set process group - if sys.Joinpgrp != 0 { - // Place the child in the specified process group. - _, _, err1 = RawSyscall(SYS_SETPGID, r1, uintptr(sys.Joinpgrp), 0) - if err1 != 0 { - goto childerror - } - } else if sys.Foreground || sys.Setpgid { - // Place the child in a new process group. + if sys.Setpgid { _, _, err1 = RawSyscall(SYS_SETPGID, 0, 0, 0) if err1 != 0 { goto childerror } - - if sys.Foreground { - r1, _, _ = RawSyscall(SYS_GETPID, 0, 0, 0) - - pid := int(r1) - - // Set new foreground process group. - _, _, err1 = RawSyscall(SYS_IOCTL, uintptr(Stdin), TIOCSPGRP, uintptr(unsafe.Pointer(&pid))) - if err1 != 0 { - goto childerror - } - } } // Chroot diff --git a/test/fixedbugs/issue9110.go b/test/fixedbugs/issue9110.go new file mode 100644 index 000000000..729463305 --- /dev/null +++ b/test/fixedbugs/issue9110.go @@ -0,0 +1,90 @@ +// run + +// 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. + +// Scenario that used to leak arbitrarily many SudoG structs. +// See golang.org/issue/9110. + +package main + +import ( + "runtime" + "runtime/debug" + "sync" + "time" +) + +func main() { + debug.SetGCPercent(1000000) // only GC when we ask for GC + + var stats, stats1, stats2 runtime.MemStats + + release := func() {} + for i := 0; i < 20; i++ { + if i == 10 { + // Should be warmed up by now. + runtime.ReadMemStats(&stats1) + } + + c := make(chan int) + for i := 0; i < 10; i++ { + go func() { + select { + case <-c: + case <-c: + case <-c: + } + }() + } + time.Sleep(1 * time.Millisecond) + release() + + close(c) // let select put its sudog's into the cache + time.Sleep(1 * time.Millisecond) + + // pick up top sudog + var cond1 sync.Cond + var mu1 sync.Mutex + cond1.L = &mu1 + go func() { + mu1.Lock() + cond1.Wait() + mu1.Unlock() + }() + time.Sleep(1 * time.Millisecond) + + // pick up next sudog + var cond2 sync.Cond + var mu2 sync.Mutex + cond2.L = &mu2 + go func() { + mu2.Lock() + cond2.Wait() + mu2.Unlock() + }() + time.Sleep(1 * time.Millisecond) + + // put top sudog back + cond1.Broadcast() + time.Sleep(1 * time.Millisecond) + + // drop cache on floor + runtime.GC() + + // release cond2 after select has gotten to run + release = func() { + cond2.Broadcast() + time.Sleep(1 * time.Millisecond) + } + } + + runtime.GC() + + runtime.ReadMemStats(&stats2) + + if int(stats2.HeapObjects)-int(stats1.HeapObjects) > 20 { // normally at most 1 or 2; was 300 with leak + print("BUG: object leak: ", stats.HeapObjects, " -> ", stats1.HeapObjects, " -> ", stats2.HeapObjects, "\n") + } +} |