Commit 44483901 authored by Russ Cox's avatar Russ Cox

[dev.garbage] all: merge dev.cc (81884b89bd88) into dev.garbage

TBR=rlh
CC=golang-codereviews
https://golang.org/cl/181100044
parents b8540fc2 829b286f
...@@ -137,3 +137,4 @@ f44017549ff9c3cc5eef74ebe7276cd0dfc066b6 go1.3.3 ...@@ -137,3 +137,4 @@ f44017549ff9c3cc5eef74ebe7276cd0dfc066b6 go1.3.3
f44017549ff9c3cc5eef74ebe7276cd0dfc066b6 release f44017549ff9c3cc5eef74ebe7276cd0dfc066b6 release
1fdfd7dfaedb1b7702141617e621ab7328a236a1 go1.4beta1 1fdfd7dfaedb1b7702141617e621ab7328a236a1 go1.4beta1
bffdd0cae380ce1ccf3e98ed6b6cd53fece7ba72 go1.4rc1 bffdd0cae380ce1ccf3e98ed6b6cd53fece7ba72 go1.4rc1
6c4e66ae713704840fcea78c8055b44ba86ae5ea go1.4rc2
...@@ -30,21 +30,16 @@ We encourage all Go users to subscribe to ...@@ -30,21 +30,16 @@ We encourage all Go users to subscribe to
<h2 id="go1">Version history</h2> <h2 id="go1">Version history</h2>
<h3 id="release"><a href="/doc/devel/release.html">Release History</a></h3> <h3 id="release"><a href="/doc/devel/release.html">Release History</a></h3>
<p>A summary of the changes between Go releases.</p>
<h4 id="go1notes"><a href="/doc/go1">Go 1 Release Notes</a></h4> <p>A <a href="/doc/devel/release.html">summary</a> of the changes between Go releases. Notes for the major releases:</p>
<p>
A guide for updating your code to work with Go 1.
</p>
<h4 id="release notes"><a href="/doc/go1.1">Go 1.1 Release Notes</a></h4> <ul>
<p> <li><a href="/doc/go1.4">Go 1.4</a> <small>(December 2014)</small></li>
A list of significant changes in Go 1.1, with instructions for updating <li><a href="/doc/go1.3">Go 1.3</a> <small>(June 2014)</small></li>
your code where necessary. <li><a href="/doc/go1.2">Go 1.2</a> <small>(December 2013)</small></li>
Each point release includes a similar document appropriate for that <li><a href="/doc/go1.1">Go 1.1</a> <small>(May 2013)</small></li>
release: <a href="/doc/go1.2">Go 1.2</a>, <a href="/doc/go1.3">Go 1.3</a>, <li><a href="/doc/go1">Go 1</a> <small>(March 2012)</small></li>
and so on. </ul>
</p>
<h3 id="go1compat"><a href="/doc/go1compat">Go 1 and the Future of Go Programs</a></h3> <h3 id="go1compat"><a href="/doc/go1compat">Go 1 and the Future of Go Programs</a></h3>
<p> <p>
......
...@@ -5579,7 +5579,7 @@ s3 := append(s2, s0...) // append a slice s3 == []int{0, ...@@ -5579,7 +5579,7 @@ s3 := append(s2, s0...) // append a slice s3 == []int{0,
s4 := append(s3[3:6], s3[2:]...) // append overlapping slice s4 == []int{3, 5, 7, 2, 3, 5, 7, 0, 0} s4 := append(s3[3:6], s3[2:]...) // append overlapping slice s4 == []int{3, 5, 7, 2, 3, 5, 7, 0, 0}
var t []interface{} var t []interface{}
t = append(t, 42, 3.1415, "foo") t == []interface{}{42, 3.1415, "foo"} t = append(t, 42, 3.1415, "foo") // t == []interface{}{42, 3.1415, "foo"}
var b []byte var b []byte
b = append(b, "bar"...) // append string contents b == []byte{'b', 'a', 'r' } b = append(b, "bar"...) // append string contents b == []byte{'b', 'a', 'r' }
......
...@@ -7,8 +7,8 @@ ...@@ -7,8 +7,8 @@
# downloaded from the ICANN/IANA distribution. # downloaded from the ICANN/IANA distribution.
# Versions to use. # Versions to use.
CODE=2014d CODE=2014j
DATA=2014d DATA=2014j
set -e set -e
rm -rf work rm -rf work
......
No preview for this file type
...@@ -458,7 +458,7 @@ brk: ...@@ -458,7 +458,7 @@ brk:
print("\nregisterizing\n"); print("\nregisterizing\n");
for(i=0; i<nregion; i++) { for(i=0; i<nregion; i++) {
if(debug['R'] && debug['v']) 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); print("region %d: cost %d varno %d enter %lld\n", i, rgp->cost, rgp->varno, rgp->enter->f.prog->pc);
bit = blsh(rgp->varno); bit = blsh(rgp->varno);
vreg = paint2(rgp->enter, rgp->varno, 0); vreg = paint2(rgp->enter, rgp->varno, 0);
vreg = allreg(vreg, rgp); vreg = allreg(vreg, rgp);
......
...@@ -393,7 +393,7 @@ brk: ...@@ -393,7 +393,7 @@ brk:
print("\nregisterizing\n"); print("\nregisterizing\n");
for(i=0; i<nregion; i++) { for(i=0; i<nregion; i++) {
if(debug['R'] && debug['v']) 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); print("region %d: cost %d varno %d enter %lld\n", i, rgp->cost, rgp->varno, rgp->enter->f.prog->pc);
bit = blsh(rgp->varno); bit = blsh(rgp->varno);
vreg = paint2(rgp->enter, rgp->varno, 0); vreg = paint2(rgp->enter, rgp->varno, 0);
vreg = allreg(vreg, rgp); vreg = allreg(vreg, rgp);
......
...@@ -225,6 +225,16 @@ enum ...@@ -225,6 +225,16 @@ enum
void proginfo(ProgInfo*, Prog*); void proginfo(ProgInfo*, Prog*);
// Many Power ISA arithmetic and logical instructions come in four
// standard variants. These bits let us map between variants.
enum {
V_CC = 1<<0, // xCC (affect CR field 0 flags)
V_V = 1<<1, // xV (affect SO and OV flags)
};
int as2variant(int);
int variant2as(int, int);
// To allow use of AJMP, ACALL, ARET in ../gc/popt.c. // To allow use of AJMP, ACALL, ARET in ../gc/popt.c.
enum enum
{ {
......
This diff is collapsed.
...@@ -101,9 +101,36 @@ static ProgInfo progtable[ALAST] = { ...@@ -101,9 +101,36 @@ static ProgInfo progtable[ALAST] = {
[ADUFFCOPY]= {Call}, [ADUFFCOPY]= {Call},
}; };
static void
initproginfo(void)
{
static int initialized;
int addvariant[] = {V_CC, V_V, V_CC|V_V};
int as, as2, i, variant;
if(initialized)
return;
initialized = 1;
// Perform one-time expansion of instructions in progtable to
// their CC, V, and VCC variants
for(as=0; as<nelem(progtable); as++) {
if(progtable[as].flags == 0)
continue;
variant = as2variant(as);
for(i=0; i<nelem(addvariant); i++) {
as2 = variant2as(as, variant | addvariant[i]);
if(as2 != 0 && progtable[as2].flags == 0)
progtable[as2] = progtable[as];
}
}
}
void void
proginfo(ProgInfo *info, Prog *p) proginfo(ProgInfo *info, Prog *p)
{ {
initproginfo();
*info = progtable[p->as]; *info = progtable[p->as];
if(info->flags == 0) { if(info->flags == 0) {
*info = progtable[AADD]; *info = progtable[AADD];
...@@ -143,3 +170,138 @@ proginfo(ProgInfo *info, Prog *p) ...@@ -143,3 +170,138 @@ proginfo(ProgInfo *info, Prog *p)
info->regset |= RtoB(3) | RtoB(4); info->regset |= RtoB(3) | RtoB(4);
} }
} }
// Instruction variants table. Initially this contains entries only
// for the "base" form of each instruction. On the first call to
// as2variant or variant2as, we'll add the variants to the table.
static int varianttable[ALAST][4] = {
[AADD]= {AADD, AADDCC, AADDV, AADDVCC},
[AADDC]= {AADDC, AADDCCC, AADDCV, AADDCVCC},
[AADDE]= {AADDE, AADDECC, AADDEV, AADDEVCC},
[AADDME]= {AADDME, AADDMECC, AADDMEV, AADDMEVCC},
[AADDZE]= {AADDZE, AADDZECC, AADDZEV, AADDZEVCC},
[AAND]= {AAND, AANDCC, 0, 0},
[AANDN]= {AANDN, AANDNCC, 0, 0},
[ACNTLZD]= {ACNTLZD, ACNTLZDCC, 0, 0},
[ACNTLZW]= {ACNTLZW, ACNTLZWCC, 0, 0},
[ADIVD]= {ADIVD, ADIVDCC, ADIVDV, ADIVDVCC},
[ADIVDU]= {ADIVDU, ADIVDUCC, ADIVDUV, ADIVDUVCC},
[ADIVW]= {ADIVW, ADIVWCC, ADIVWV, ADIVWVCC},
[ADIVWU]= {ADIVWU, ADIVWUCC, ADIVWUV, ADIVWUVCC},
[AEQV]= {AEQV, AEQVCC, 0, 0},
[AEXTSB]= {AEXTSB, AEXTSBCC, 0, 0},
[AEXTSH]= {AEXTSH, AEXTSHCC, 0, 0},
[AEXTSW]= {AEXTSW, AEXTSWCC, 0, 0},
[AFABS]= {AFABS, AFABSCC, 0, 0},
[AFADD]= {AFADD, AFADDCC, 0, 0},
[AFADDS]= {AFADDS, AFADDSCC, 0, 0},
[AFCFID]= {AFCFID, AFCFIDCC, 0, 0},
[AFCTID]= {AFCTID, AFCTIDCC, 0, 0},
[AFCTIDZ]= {AFCTIDZ, AFCTIDZCC, 0, 0},
[AFCTIW]= {AFCTIW, AFCTIWCC, 0, 0},
[AFCTIWZ]= {AFCTIWZ, AFCTIWZCC, 0, 0},
[AFDIV]= {AFDIV, AFDIVCC, 0, 0},
[AFDIVS]= {AFDIVS, AFDIVSCC, 0, 0},
[AFMADD]= {AFMADD, AFMADDCC, 0, 0},
[AFMADDS]= {AFMADDS, AFMADDSCC, 0, 0},
[AFMOVD]= {AFMOVD, AFMOVDCC, 0, 0},
[AFMSUB]= {AFMSUB, AFMSUBCC, 0, 0},
[AFMSUBS]= {AFMSUBS, AFMSUBSCC, 0, 0},
[AFMUL]= {AFMUL, AFMULCC, 0, 0},
[AFMULS]= {AFMULS, AFMULSCC, 0, 0},
[AFNABS]= {AFNABS, AFNABSCC, 0, 0},
[AFNEG]= {AFNEG, AFNEGCC, 0, 0},
[AFNMADD]= {AFNMADD, AFNMADDCC, 0, 0},
[AFNMADDS]= {AFNMADDS, AFNMADDSCC, 0, 0},
[AFNMSUB]= {AFNMSUB, AFNMSUBCC, 0, 0},
[AFNMSUBS]= {AFNMSUBS, AFNMSUBSCC, 0, 0},
[AFRES]= {AFRES, AFRESCC, 0, 0},
[AFRSP]= {AFRSP, AFRSPCC, 0, 0},
[AFRSQRTE]= {AFRSQRTE, AFRSQRTECC, 0, 0},
[AFSEL]= {AFSEL, AFSELCC, 0, 0},
[AFSQRT]= {AFSQRT, AFSQRTCC, 0, 0},
[AFSQRTS]= {AFSQRTS, AFSQRTSCC, 0, 0},
[AFSUB]= {AFSUB, AFSUBCC, 0, 0},
[AFSUBS]= {AFSUBS, AFSUBSCC, 0, 0},
[AMTFSB0]= {AMTFSB0, AMTFSB0CC, 0, 0},
[AMTFSB1]= {AMTFSB1, AMTFSB1CC, 0, 0},
[AMULHD]= {AMULHD, AMULHDCC, 0, 0},
[AMULHDU]= {AMULHDU, AMULHDUCC, 0, 0},
[AMULHW]= {AMULHW, AMULHWCC, 0, 0},
[AMULHWU]= {AMULHWU, AMULHWUCC, 0, 0},
[AMULLD]= {AMULLD, AMULLDCC, AMULLDV, AMULLDVCC},
[AMULLW]= {AMULLW, AMULLWCC, AMULLWV, AMULLWVCC},
[ANAND]= {ANAND, ANANDCC, 0, 0},
[ANEG]= {ANEG, ANEGCC, ANEGV, ANEGVCC},
[ANOR]= {ANOR, ANORCC, 0, 0},
[AOR]= {AOR, AORCC, 0, 0},
[AORN]= {AORN, AORNCC, 0, 0},
[AREM]= {AREM, AREMCC, AREMV, AREMVCC},
[AREMD]= {AREMD, AREMDCC, AREMDV, AREMDVCC},
[AREMDU]= {AREMDU, AREMDUCC, AREMDUV, AREMDUVCC},
[AREMU]= {AREMU, AREMUCC, AREMUV, AREMUVCC},
[ARLDC]= {ARLDC, ARLDCCC, 0, 0},
[ARLDCL]= {ARLDCL, ARLDCLCC, 0, 0},
[ARLDCR]= {ARLDCR, ARLDCRCC, 0, 0},
[ARLDMI]= {ARLDMI, ARLDMICC, 0, 0},
[ARLWMI]= {ARLWMI, ARLWMICC, 0, 0},
[ARLWNM]= {ARLWNM, ARLWNMCC, 0, 0},
[ASLD]= {ASLD, ASLDCC, 0, 0},
[ASLW]= {ASLW, ASLWCC, 0, 0},
[ASRAD]= {ASRAD, ASRADCC, 0, 0},
[ASRAW]= {ASRAW, ASRAWCC, 0, 0},
[ASRD]= {ASRD, ASRDCC, 0, 0},
[ASRW]= {ASRW, ASRWCC, 0, 0},
[ASUB]= {ASUB, ASUBCC, ASUBV, ASUBVCC},
[ASUBC]= {ASUBC, ASUBCCC, ASUBCV, ASUBCVCC},
[ASUBE]= {ASUBE, ASUBECC, ASUBEV, ASUBEVCC},
[ASUBME]= {ASUBME, ASUBMECC, ASUBMEV, ASUBMEVCC},
[ASUBZE]= {ASUBZE, ASUBZECC, ASUBZEV, ASUBZEVCC},
[AXOR]= {AXOR, AXORCC, 0, 0},
};
static void
initvariants(void)
{
static int initialized;
int i, j;
if(initialized)
return;
initialized = 1;
for(i=0; i<nelem(varianttable); i++) {
if(varianttable[i][0] == 0) {
// Instruction has no variants
varianttable[i][0] = i;
continue;
}
// Copy base form to other variants
if(varianttable[i][0] == i) {
for(j=0; j<nelem(varianttable[i]); j++)
memmove(&varianttable[varianttable[i][j]], &varianttable[i], sizeof(varianttable[i]));
}
}
}
// as2variant returns the variant (V_*) flags of instruction as.
int
as2variant(int as)
{
int i;
initvariants();
for(i=0; i<nelem(varianttable[as]); i++)
if(varianttable[as][i] == as)
return i;
fatal("as2variant: instruction %A is not a variant of itself", as);
return 0;
}
// variant2as returns the instruction as with the given variant (V_*) flags.
// If no such variant exists, this returns 0.
int
variant2as(int as, int flags)
{
initvariants();
return varianttable[as][flags];
}
...@@ -437,7 +437,7 @@ brk: ...@@ -437,7 +437,7 @@ brk:
print("\nregisterizing\n"); print("\nregisterizing\n");
for(i=0; i<nregion; i++) { for(i=0; i<nregion; i++) {
if(debug['R'] && debug['v']) 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); print("region %d: cost %d varno %d enter %lld\n", i, rgp->cost, rgp->varno, rgp->enter->f.prog->pc);
bit = blsh(rgp->varno); bit = blsh(rgp->varno);
usedreg = paint2(rgp->enter, rgp->varno, 0); usedreg = paint2(rgp->enter, rgp->varno, 0);
vreg = allreg(usedreg, rgp); vreg = allreg(usedreg, rgp);
......
...@@ -65,14 +65,6 @@ needlib(char *name) ...@@ -65,14 +65,6 @@ needlib(char *name)
int nelfsym = 1; int nelfsym = 1;
// b is the addresses, a is the I-form branch instruction template, peform
// addition so that the instruction jumps to address (offset) b.
static int32
braddoff(int32 a, int32 b)
{
return (((uint32)a) & 0xfc000003U) | (0x03fffffcU & (uint32)((a & 0x3fffffcU) + b));
}
void void
adddynrela(LSym *rel, LSym *s, Reloc *r) adddynrela(LSym *rel, LSym *s, Reloc *r)
{ {
...@@ -160,7 +152,19 @@ archreloc(Reloc *r, LSym *s, vlong *val) ...@@ -160,7 +152,19 @@ archreloc(Reloc *r, LSym *s, vlong *val)
*val = ((vlong)o2 << 32) | o1; *val = ((vlong)o2 << 32) | o1;
return 0; return 0;
case R_CALLPOWER: case R_CALLPOWER:
*val = braddoff((uint32)r->add, (int32)(symaddr(r->sym) - (s->value + r->off))); // Bits 6 through 29 = (S + A - P) >> 2
if(ctxt->arch->endian == BigEndian)
o1 = be32(s->p + r->off);
else
o1 = le32(s->p + r->off);
t = symaddr(r->sym) + r->add - (s->value + r->off);
if(t & 3)
ctxt->diag("relocation for %s is not aligned: %lld", s->name, t);
if(t << 6 >> 6 != t)
ctxt->diag("relocation for %s is too big: %lld", s->name, t);
*val = (o1 & 0xfc000003U) | (t & ~0xfc000003U);
return 0; return 0;
} }
return -1; return -1;
......
...@@ -234,17 +234,24 @@ create or update Go source files, for instance by running yacc. ...@@ -234,17 +234,24 @@ create or update Go source files, for instance by running yacc.
Go generate is never run automatically by go build, go get, go test, Go generate is never run automatically by go build, go get, go test,
and so on. It must be run explicitly. and so on. It must be run explicitly.
Directives are written as a whole-line comment of the form Go generate scans the file for directives, which are lines of
the form,
//go:generate command argument... //go:generate command argument...
(note: no space in "//go") where command is the generator to be (note: no leading spaces and no space in "//go") where command
run, corresponding to an executable file that can be run locally. is the generator to be run, corresponding to an executable file
It must either be in the shell path (gofmt), a fully qualified path that can be run locally. It must either be in the shell path
(/usr/you/bin/mytool), or a command alias, described below. (gofmt), a fully qualified path (/usr/you/bin/mytool), or a
command alias, described below.
The arguments are space-separated tokens or double-quoted strings Note that go generate does not parse the file, so lines that look
passed to the generator as individual arguments when it is run. like directives in comments or multiline strings will be treated
as directives.
The arguments to the directive are space-separated tokens or
double-quoted strings passed to the generator as individual
arguments when it is run.
Quoted strings use Go syntax and are evaluated before execution; a Quoted strings use Go syntax and are evaluated before execution; a
quoted string appears as a single argument to the generator. quoted string appears as a single argument to the generator.
...@@ -317,7 +324,7 @@ Download and install packages and dependencies ...@@ -317,7 +324,7 @@ Download and install packages and dependencies
Usage: Usage:
go get [-d] [-fix] [-t] [-u] [build flags] [packages] go get [-d] [-f] [-fix] [-t] [-u] [build flags] [packages]
Get downloads and installs the packages named by the import paths, Get downloads and installs the packages named by the import paths,
along with their dependencies. along with their dependencies.
...@@ -325,6 +332,11 @@ along with their dependencies. ...@@ -325,6 +332,11 @@ along with their dependencies.
The -d flag instructs get to stop after downloading the packages; that is, The -d flag instructs get to stop after downloading the packages; that is,
it instructs get not to install the packages. it instructs get not to install the packages.
The -f flag, valid only when -u is set, forces get -u not to verify that
each package has been checked out from the source control repository
implied by its import path. This can be useful if the source is a local fork
of the original.
The -fix flag instructs get to run the fix tool on the downloaded packages The -fix flag instructs get to run the fix tool on the downloaded packages
before resolving dependencies or building the code. before resolving dependencies or building the code.
......
...@@ -32,20 +32,27 @@ create or update Go source files, for instance by running yacc. ...@@ -32,20 +32,27 @@ create or update Go source files, for instance by running yacc.
Go generate is never run automatically by go build, go get, go test, Go generate is never run automatically by go build, go get, go test,
and so on. It must be run explicitly. and so on. It must be run explicitly.
Directives are written as a whole-line comment of the form Go generate scans the file for directives, which are lines of
the form,
//go:generate command argument... //go:generate command argument...
(note: no space in "//go") where command is the generator to be (note: no leading spaces and no space in "//go") where command
run, corresponding to an executable file that can be run locally. is the generator to be run, corresponding to an executable file
It must either be in the shell path (gofmt), a fully qualified path that can be run locally. It must either be in the shell path
(/usr/you/bin/mytool), or a command alias, described below. (gofmt), a fully qualified path (/usr/you/bin/mytool), or a
command alias, described below.
The arguments are space-separated tokens or double-quoted strings Note that go generate does not parse the file, so lines that look
passed to the generator as individual arguments when it is run. like directives in comments or multiline strings will be treated
as directives.
The arguments to the directive are space-separated tokens or
double-quoted strings passed to the generator as individual
arguments when it is run.
Quoted strings use Go syntax and are evaluated before execution; a Quoted strings use Go syntax and are evaluated before execution; a
quoted string appears a single argument to the generator. quoted string appears as a single argument to the generator.
Go generate sets several variables when it runs the generator: Go generate sets several variables when it runs the generator:
...@@ -178,13 +185,43 @@ func (g *Generator) run() (ok bool) { ...@@ -178,13 +185,43 @@ func (g *Generator) run() (ok bool) {
fmt.Fprintf(os.Stderr, "%s\n", shortPath(g.path)) fmt.Fprintf(os.Stderr, "%s\n", shortPath(g.path))
} }
s := bufio.NewScanner(g.r) // Scan for lines that start "//go:generate".
for s.Scan() { // Can't use bufio.Scanner because it can't handle long lines,
g.lineNum++ // which are likely to appear when using generate.
if !bytes.HasPrefix(s.Bytes(), []byte("//go:generate ")) && !bytes.HasPrefix(s.Bytes(), []byte("//go:generate\t")) { input := bufio.NewReader(g.r)
var err error
// One line per loop.
for {
g.lineNum++ // 1-indexed.
var buf []byte
buf, err = input.ReadSlice('\n')
if err == bufio.ErrBufferFull {
// Line too long - consume and ignore.
if isGoGenerate(buf) {
g.errorf("directive too long")
}
for err == bufio.ErrBufferFull {
_, err = input.ReadSlice('\n')
}
if err != nil {
break
}
continue
}
if err != nil {
// Check for marker at EOF without final \n.
if err == io.EOF && isGoGenerate(buf) {
err = io.ErrUnexpectedEOF
}
break
}
if !isGoGenerate(buf) {
continue continue
} }
words := g.split(s.Text())
words := g.split(string(buf))
if len(words) == 0 { if len(words) == 0 {
g.errorf("no arguments to directive") g.errorf("no arguments to directive")
} }
...@@ -201,19 +238,23 @@ func (g *Generator) run() (ok bool) { ...@@ -201,19 +238,23 @@ func (g *Generator) run() (ok bool) {
} }
g.exec(words) g.exec(words)
} }
if s.Err() != nil { if err != nil && err != io.EOF {
g.errorf("error reading %s: %s", shortPath(g.path), s.Err()) g.errorf("error reading %s: %s", shortPath(g.path), err)
} }
return true return true
} }
func isGoGenerate(buf []byte) bool {
return bytes.HasPrefix(buf, []byte("//go:generate ")) || bytes.HasPrefix(buf, []byte("//go:generate\t"))
}
// split breaks the line into words, evaluating quoted // split breaks the line into words, evaluating quoted
// strings and evaluating environment variables. // strings and evaluating environment variables.
// The initial //go:generate element is dropped. // The initial //go:generate element is present in line.
func (g *Generator) split(line string) []string { func (g *Generator) split(line string) []string {
// Parse line, obeying quoted strings. // Parse line, obeying quoted strings.
var words []string var words []string
line = line[len("//go:generate "):] line = line[len("//go:generate ") : len(line)-1] // Drop preamble and final newline.
// One (possibly quoted) word per iteration. // One (possibly quoted) word per iteration.
Words: Words:
for { for {
......
...@@ -40,7 +40,7 @@ func TestGenerateCommandParse(t *testing.T) { ...@@ -40,7 +40,7 @@ func TestGenerateCommandParse(t *testing.T) {
} }
g.setShorthand([]string{"-command", "yacc", "go", "tool", "yacc"}) g.setShorthand([]string{"-command", "yacc", "go", "tool", "yacc"})
for _, test := range splitTests { for _, test := range splitTests {
got := g.split("//go:generate " + test.in) got := g.split("//go:generate " + test.in + "\n")
if !reflect.DeepEqual(got, test.out) { if !reflect.DeepEqual(got, test.out) {
t.Errorf("split(%q): got %q expected %q", test.in, got, test.out) t.Errorf("split(%q): got %q expected %q", test.in, got, test.out)
} }
......
...@@ -203,6 +203,17 @@ loadlib(void) ...@@ -203,6 +203,17 @@ loadlib(void)
objfile(ctxt->library[i].file, ctxt->library[i].pkg); objfile(ctxt->library[i].file, ctxt->library[i].pkg);
} }
if(linkmode == LinkAuto) {
if(iscgo && externalobj)
linkmode = LinkExternal;
else
linkmode = LinkInternal;
// Force external linking for android.
if(strcmp(goos, "android") == 0)
linkmode = LinkExternal;
}
if(linkmode == LinkExternal && !iscgo) { if(linkmode == LinkExternal && !iscgo) {
// This indicates a user requested -linkmode=external. // This indicates a user requested -linkmode=external.
// The startup code uses an import of runtime/cgo to decide // The startup code uses an import of runtime/cgo to decide
...@@ -229,17 +240,6 @@ loadlib(void) ...@@ -229,17 +240,6 @@ loadlib(void)
} }
} }
if(linkmode == LinkAuto) {
if(iscgo && externalobj)
linkmode = LinkExternal;
else
linkmode = LinkInternal;
// Force external linking for android.
if(strcmp(goos, "android") == 0)
linkmode = LinkExternal;
}
if(linkmode == LinkInternal) { if(linkmode == LinkInternal) {
// Drop all the cgo_import_static declarations. // Drop all the cgo_import_static declarations.
// Turns out we won't be needing them. // Turns out we won't be needing them.
......
...@@ -11,6 +11,7 @@ import ( ...@@ -11,6 +11,7 @@ import (
"io" "io"
"os" "os"
"os/exec" "os/exec"
"runtime"
"strings" "strings"
"cmd/pprof/internal/plugin" "cmd/pprof/internal/plugin"
...@@ -71,15 +72,27 @@ func PProf(c Completer, interactive **bool, svgpan **string) Commands { ...@@ -71,15 +72,27 @@ func PProf(c Completer, interactive **bool, svgpan **string) Commands {
"eog": {c, report.Dot, invokeVisualizer(interactive, invokeDot("svg"), "svg", []string{"eog"}), false, "Visualize graph through eog"}, "eog": {c, report.Dot, invokeVisualizer(interactive, invokeDot("svg"), "svg", []string{"eog"}), false, "Visualize graph through eog"},
"evince": {c, report.Dot, invokeVisualizer(interactive, invokeDot("pdf"), "pdf", []string{"evince"}), false, "Visualize graph through evince"}, "evince": {c, report.Dot, invokeVisualizer(interactive, invokeDot("pdf"), "pdf", []string{"evince"}), false, "Visualize graph through evince"},
"gv": {c, report.Dot, invokeVisualizer(interactive, invokeDot("ps"), "ps", []string{"gv --noantialias"}), false, "Visualize graph through gv"}, "gv": {c, report.Dot, invokeVisualizer(interactive, invokeDot("ps"), "ps", []string{"gv --noantialias"}), false, "Visualize graph through gv"},
"web": {c, report.Dot, invokeVisualizer(interactive, saveSVGToFile(svgpan), "svg", browsers), false, "Visualize graph through web browser"}, "web": {c, report.Dot, invokeVisualizer(interactive, saveSVGToFile(svgpan), "svg", browsers()), false, "Visualize graph through web browser"},
// Visualize HTML directly generated by report. // Visualize HTML directly generated by report.
"weblist": {c, report.WebList, invokeVisualizer(interactive, awayFromTTY("html"), "html", browsers), true, "Output annotated source in HTML for functions matching regexp or address"}, "weblist": {c, report.WebList, invokeVisualizer(interactive, awayFromTTY("html"), "html", browsers()), true, "Output annotated source in HTML for functions matching regexp or address"},
} }
} }
// List of web browsers to attempt for web visualization // browsers returns a list of commands to attempt for web visualization
var browsers = []string{"chrome", "google-chrome", "firefox", "/usr/bin/open"} // on the current platform
func browsers() []string {
cmds := []string{"chrome", "google-chrome", "firefox"}
switch runtime.GOOS {
case "darwin":
cmds = append(cmds, "/usr/bin/open")
case "windows":
cmds = append(cmds, "cmd /c start")
default:
cmds = append(cmds, "xdg-open")
}
return cmds
}
// NewCompleter creates an autocompletion function for a set of commands. // NewCompleter creates an autocompletion function for a set of commands.
func NewCompleter(cs Commands) Completer { func NewCompleter(cs Commands) Completer {
...@@ -142,6 +155,10 @@ func awayFromTTY(format string) PostProcessor { ...@@ -142,6 +155,10 @@ func awayFromTTY(format string) PostProcessor {
func invokeDot(format string) PostProcessor { func invokeDot(format string) PostProcessor {
divert := awayFromTTY(format) divert := awayFromTTY(format)
return func(input *bytes.Buffer, output io.Writer, ui plugin.UI) error { return func(input *bytes.Buffer, output io.Writer, ui plugin.UI) error {
if _, err := exec.LookPath("dot"); err != nil {
ui.PrintErr("Cannot find dot, have you installed Graphviz?")
return err
}
cmd := exec.Command("dot", "-T"+format) cmd := exec.Command("dot", "-T"+format)
var buf bytes.Buffer var buf bytes.Buffer
cmd.Stdin, cmd.Stdout, cmd.Stderr = input, &buf, os.Stderr cmd.Stdin, cmd.Stdout, cmd.Stderr = input, &buf, os.Stderr
...@@ -174,6 +191,7 @@ func invokeVisualizer(interactive **bool, format PostProcessor, suffix string, v ...@@ -174,6 +191,7 @@ func invokeVisualizer(interactive **bool, format PostProcessor, suffix string, v
if err = format(input, tempFile, ui); err != nil { if err = format(input, tempFile, ui); err != nil {
return err return err
} }
tempFile.Close() // on windows, if the file is Open, start cannot access it.
// Try visualizers until one is successful // Try visualizers until one is successful
for _, v := range visualizers { for _, v := range visualizers {
// Separate command and arguments for exec.Command. // Separate command and arguments for exec.Command.
......
...@@ -32,6 +32,10 @@ func Symbolize(mode string, prof *profile.Profile, obj plugin.ObjTool, ui plugin ...@@ -32,6 +32,10 @@ func Symbolize(mode string, prof *profile.Profile, obj plugin.ObjTool, ui plugin
} }
} }
if len(prof.Mapping) == 0 {
return fmt.Errorf("no known mappings")
}
mt, err := newMapping(prof, obj, ui, force) mt, err := newMapping(prof, obj, ui, force)
if err != nil { if err != nil {
return err return err
......
...@@ -1310,11 +1310,13 @@ func (ctxt *Context) goodOSArchFile(name string, allTags map[string]bool) bool { ...@@ -1310,11 +1310,13 @@ func (ctxt *Context) goodOSArchFile(name string, allTags map[string]bool) bool {
// auto-tagging to apply only to files with a non-empty prefix, so // auto-tagging to apply only to files with a non-empty prefix, so
// "foo_linux.go" is tagged but "linux.go" is not. This allows new operating // "foo_linux.go" is tagged but "linux.go" is not. This allows new operating
// sytems, such as android, to arrive without breaking existing code with // sytems, such as android, to arrive without breaking existing code with
// innocuous source code in "android.go". The easiest fix: files without // innocuous source code in "android.go". The easiest fix: cut everything
// underscores are always included. // in the name before the initial _.
if !strings.ContainsRune(name, '_') { i := strings.Index(name, "_")
if i < 0 {
return true return true
} }
name = name[i:] // ignore everything before first _
l := strings.Split(name, "_") l := strings.Split(name, "_")
if n := len(l); n > 0 && l[n-1] == "test" { if n := len(l); n > 0 && l[n-1] == "test" {
......
...@@ -189,6 +189,7 @@ var matchFileTests = []struct { ...@@ -189,6 +189,7 @@ var matchFileTests = []struct {
{ctxtAndroid, "foo_plan9.go", "", false}, {ctxtAndroid, "foo_plan9.go", "", false},
{ctxtAndroid, "android.go", "", true}, {ctxtAndroid, "android.go", "", true},
{ctxtAndroid, "plan9.go", "", true}, {ctxtAndroid, "plan9.go", "", true},
{ctxtAndroid, "plan9_test.go", "", true},
{ctxtAndroid, "arm.s", "", true}, {ctxtAndroid, "arm.s", "", true},
{ctxtAndroid, "amd64.s", "", true}, {ctxtAndroid, "amd64.s", "", true},
} }
......
...@@ -1589,7 +1589,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, int32 *out) ...@@ -1589,7 +1589,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, int32 *out)
ctxt->diag("odd branch target address\n%P", p); ctxt->diag("odd branch target address\n%P", p);
v &= ~03; v &= ~03;
} }
rel->add = o1 | (v & 0x03FFFFFC); rel->add = v;
rel->type = R_CALLPOWER; rel->type = R_CALLPOWER;
} }
break; break;
......
...@@ -41,7 +41,7 @@ brchain(Link *ctxt, Prog *p) ...@@ -41,7 +41,7 @@ brchain(Link *ctxt, Prog *p)
int i; int i;
for(i=0; i<20; i++) { for(i=0; i<20; i++) {
if(p == nil || p->as != ctxt->arch->AJMP) if(p == nil || p->as != ctxt->arch->AJMP || p->pcond == nil)
return p; return p;
p = p->pcond; p = p->pcond;
} }
...@@ -56,7 +56,7 @@ brloop(Link *ctxt, Prog *p) ...@@ -56,7 +56,7 @@ brloop(Link *ctxt, Prog *p)
c = 0; c = 0;
for(q = p; q != nil; q = q->pcond) { for(q = p; q != nil; q = q->pcond) {
if(q->as != ctxt->arch->AJMP) if(q->as != ctxt->arch->AJMP || q->pcond == nil)
break; break;
c++; c++;
if(c >= 5000) if(c >= 5000)
......
...@@ -4060,3 +4060,104 @@ func TestLargeGCProg(t *testing.T) { ...@@ -4060,3 +4060,104 @@ func TestLargeGCProg(t *testing.T) {
fv := ValueOf(func([256]*byte) {}) fv := ValueOf(func([256]*byte) {})
fv.Call([]Value{ValueOf([256]*byte{})}) fv.Call([]Value{ValueOf([256]*byte{})})
} }
// Issue 9179.
func TestCallGC(t *testing.T) {
f := func(a, b, c, d, e string) {
}
g := func(in []Value) []Value {
runtime.GC()
return nil
}
typ := ValueOf(f).Type()
f2 := MakeFunc(typ, g).Interface().(func(string, string, string, string, string))
f2("four", "five5", "six666", "seven77", "eight888")
}
type funcLayoutTest struct {
rcvr, t Type
argsize, retOffset uintptr
stack []byte
}
var funcLayoutTests []funcLayoutTest
func init() {
var argAlign = PtrSize
if runtime.GOARCH == "amd64p32" {
argAlign = 2 * PtrSize
}
roundup := func(x uintptr, a uintptr) uintptr {
return (x + a - 1) / a * a
}
funcLayoutTests = append(funcLayoutTests,
funcLayoutTest{
nil,
ValueOf(func(a, b string) string { return "" }).Type(),
4 * PtrSize,
4 * PtrSize,
[]byte{BitsPointer, BitsScalar, BitsPointer},
})
var r []byte
if PtrSize == 4 {
r = []byte{BitsScalar, BitsScalar, BitsScalar, BitsPointer}
} else {
r = []byte{BitsScalar, BitsScalar, BitsPointer}
}
funcLayoutTests = append(funcLayoutTests,
funcLayoutTest{
nil,
ValueOf(func(a, b, c uint32, p *byte, d uint16) {}).Type(),
roundup(3*4, PtrSize) + PtrSize + 2,
roundup(roundup(3*4, PtrSize)+PtrSize+2, argAlign),
r,
})
funcLayoutTests = append(funcLayoutTests,
funcLayoutTest{
nil,
ValueOf(func(a map[int]int, b uintptr, c interface{}) {}).Type(),
4 * PtrSize,
4 * PtrSize,
[]byte{BitsPointer, BitsScalar, BitsPointer, BitsPointer},
})
type S struct {
a, b uintptr
c, d *byte
}
funcLayoutTests = append(funcLayoutTests,
funcLayoutTest{
nil,
ValueOf(func(a S) {}).Type(),
4 * PtrSize,
4 * PtrSize,
[]byte{BitsScalar, BitsScalar, BitsPointer, BitsPointer},
})
funcLayoutTests = append(funcLayoutTests,
funcLayoutTest{
ValueOf((*byte)(nil)).Type(),
ValueOf(func(a uintptr, b *int) {}).Type(),
3 * PtrSize,
roundup(3*PtrSize, argAlign),
[]byte{BitsPointer, BitsScalar, BitsPointer},
})
}
func TestFuncLayout(t *testing.T) {
for _, lt := range funcLayoutTests {
_, argsize, retOffset, stack := FuncLayout(lt.t, lt.rcvr)
if argsize != lt.argsize {
t.Errorf("funcLayout(%v, %v).argsize=%d, want %d", lt.t, lt.rcvr, argsize, lt.argsize)
}
if retOffset != lt.retOffset {
t.Errorf("funcLayout(%v, %v).retOffset=%d, want %d", lt.t, lt.rcvr, retOffset, lt.retOffset)
}
if !bytes.Equal(stack, lt.stack) {
t.Errorf("funcLayout(%v, %v).stack=%v, want %v", lt.t, lt.rcvr, stack, lt.stack)
}
}
}
...@@ -17,3 +17,22 @@ func IsRO(v Value) bool { ...@@ -17,3 +17,22 @@ func IsRO(v Value) bool {
var ArrayOf = arrayOf var ArrayOf = arrayOf
var CallGC = &callGC var CallGC = &callGC
const PtrSize = ptrSize
const BitsPointer = bitsPointer
const BitsScalar = bitsScalar
func FuncLayout(t Type, rcvr Type) (frametype Type, argSize, retOffset uintptr, stack []byte) {
var ft *rtype
var s *bitVector
if rcvr != nil {
ft, argSize, retOffset, s = funcLayout(t.(*rtype), rcvr.(*rtype))
} else {
ft, argSize, retOffset, s = funcLayout(t.(*rtype), nil)
}
frametype = ft
for i := uint32(0); i < s.n; i += 2 {
stack = append(stack, s.data[i/8]>>(i%8)&3)
}
return
}
...@@ -1889,14 +1889,14 @@ func addTypeBits(bv *bitVector, offset *uintptr, t *rtype) { ...@@ -1889,14 +1889,14 @@ func addTypeBits(bv *bitVector, offset *uintptr, t *rtype) {
switch Kind(t.kind & kindMask) { switch Kind(t.kind & kindMask) {
case Chan, Func, Map, Ptr, Slice, String, UnsafePointer: case Chan, Func, Map, Ptr, Slice, String, UnsafePointer:
// 1 pointer at start of representation // 1 pointer at start of representation
for bv.n < uint32(*offset/uintptr(ptrSize)) { for bv.n < 2*uint32(*offset/uintptr(ptrSize)) {
bv.append2(bitsScalar) bv.append2(bitsScalar)
} }
bv.append2(bitsPointer) bv.append2(bitsPointer)
case Interface: case Interface:
// 2 pointers // 2 pointers
for bv.n < uint32(*offset/uintptr(ptrSize)) { for bv.n < 2*uint32(*offset/uintptr(ptrSize)) {
bv.append2(bitsScalar) bv.append2(bitsScalar)
} }
bv.append2(bitsPointer) bv.append2(bitsPointer)
......
...@@ -92,16 +92,16 @@ type rtprio struct { ...@@ -92,16 +92,16 @@ type rtprio struct {
} }
type lwpparams struct { type lwpparams struct {
_type unsafe.Pointer start_func uintptr
arg *byte arg unsafe.Pointer
stack *byte stack uintptr
tid1 *int32 tid1 unsafe.Pointer // *int32
tid2 *int32 tid2 unsafe.Pointer // *int32
} }
type sigaltstackt struct { type sigaltstackt struct {
ss_sp *int8 ss_sp uintptr
ss_size uint32 ss_size uintptr
ss_flags int32 ss_flags int32
} }
...@@ -110,8 +110,8 @@ type sigset struct { ...@@ -110,8 +110,8 @@ type sigset struct {
} }
type stackt struct { type stackt struct {
ss_sp *int8 ss_sp uintptr
ss_size uint32 ss_size uintptr
ss_flags int32 ss_flags int32
} }
...@@ -122,39 +122,39 @@ type siginfo struct { ...@@ -122,39 +122,39 @@ type siginfo struct {
si_pid int32 si_pid int32
si_uid uint32 si_uid uint32
si_status int32 si_status int32
si_addr *byte si_addr uintptr
si_value [4]byte si_value [4]byte
si_band int32 si_band int32
__spare__ [7]int32 __spare__ [7]int32
} }
type mcontext struct { type mcontext struct {
mc_onstack int32 mc_onstack uint32
mc_gs int32 mc_gs uint32
mc_fs int32 mc_fs uint32
mc_es int32 mc_es uint32
mc_ds int32 mc_ds uint32
mc_edi int32 mc_edi uint32
mc_esi int32 mc_esi uint32
mc_ebp int32 mc_ebp uint32
mc_isp int32 mc_isp uint32
mc_ebx int32 mc_ebx uint32
mc_edx int32 mc_edx uint32
mc_ecx int32 mc_ecx uint32
mc_eax int32 mc_eax uint32
mc_xflags int32 mc_xflags uint32
mc_trapno int32 mc_trapno uint32
mc_err int32 mc_err uint32
mc_eip int32 mc_eip uint32
mc_cs int32 mc_cs uint32
mc_eflags int32 mc_eflags uint32
mc_esp int32 mc_esp uint32
mc_ss int32 mc_ss uint32
mc_len int32 mc_len uint32
mc_fpformat int32 mc_fpformat uint32
mc_ownedfp int32 mc_ownedfp uint32
mc_fpregs [128]int32 mc_fpregs [128]uint32
__spare__ [16]int32 __spare__ [16]uint32
} }
type ucontext struct { type ucontext struct {
...@@ -170,11 +170,19 @@ type timespec struct { ...@@ -170,11 +170,19 @@ type timespec struct {
tv_nsec int32 tv_nsec int32
} }
func (ts *timespec) set_sec(x int64) {
ts.tv_sec = int32(x)
}
type timeval struct { type timeval struct {
tv_sec int32 tv_sec int32
tv_usec int32 tv_usec int32
} }
func (tv *timeval) set_usec(x int32) {
tv.tv_usec = x
}
type itimerval struct { type itimerval struct {
it_interval timeval it_interval timeval
it_value timeval it_value timeval
......
...@@ -375,6 +375,36 @@ func casgstatus(gp *g, oldval, newval uint32) { ...@@ -375,6 +375,36 @@ func casgstatus(gp *g, oldval, newval uint32) {
// loop if gp->atomicstatus is in a scan state giving // loop if gp->atomicstatus is in a scan state giving
// GC time to finish and change the state to oldval. // GC time to finish and change the state to oldval.
for !cas(&gp.atomicstatus, oldval, newval) { for !cas(&gp.atomicstatus, oldval, newval) {
if oldval == _Gwaiting && gp.atomicstatus == _Grunnable {
systemstack(func() {
gothrow("casgstatus: waiting for Gwaiting but is Grunnable")
})
}
// Help GC if needed.
// if gp.preemptscan && !gp.gcworkdone && (oldval == _Grunning || oldval == _Gsyscall) {
// gp.preemptscan = false
// systemstack(func() {
// gcphasework(gp)
// })
// }
}
}
// casgstatus(gp, oldstatus, Gcopystack), assuming oldstatus is Gwaiting or Grunnable.
// Returns old status. Cannot call casgstatus directly, because we are racing with an
// async wakeup that might come in from netpoll. If we see Gwaiting from the readgstatus,
// it might have become Grunnable by the time we get to the cas. If we called casgstatus,
// it would loop waiting for the status to go back to Gwaiting, which it never will.
//go:nosplit
func casgcopystack(gp *g) uint32 {
for {
oldstatus := readgstatus(gp) &^ _Gscan
if oldstatus != _Gwaiting && oldstatus != _Grunnable {
gothrow("copystack: bad status, not Gwaiting or Grunnable")
}
if cas(&gp.atomicstatus, oldstatus, _Gcopystack) {
return oldstatus
}
} }
} }
......
// 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() *mcontext { return &(*ucontext)(c.ctxt).uc_mcontext }
func (c *sigctxt) eax() uint32 { return c.regs().mc_eax }
func (c *sigctxt) ebx() uint32 { return c.regs().mc_ebx }
func (c *sigctxt) ecx() uint32 { return c.regs().mc_ecx }
func (c *sigctxt) edx() uint32 { return c.regs().mc_edx }
func (c *sigctxt) edi() uint32 { return c.regs().mc_edi }
func (c *sigctxt) esi() uint32 { return c.regs().mc_esi }
func (c *sigctxt) ebp() uint32 { return c.regs().mc_ebp }
func (c *sigctxt) esp() uint32 { return c.regs().mc_esp }
func (c *sigctxt) eip() uint32 { return c.regs().mc_eip }
func (c *sigctxt) eflags() uint32 { return c.regs().mc_eflags }
func (c *sigctxt) cs() uint32 { return uint32(c.regs().mc_cs) }
func (c *sigctxt) fs() uint32 { return uint32(c.regs().mc_fs) }
func (c *sigctxt) gs() uint32 { return uint32(c.regs().mc_gs) }
func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) }
func (c *sigctxt) sigaddr() uint32 { return uint32(c.info.si_addr) }
func (c *sigctxt) set_eip(x uint32) { c.regs().mc_eip = x }
func (c *sigctxt) set_esp(x uint32) { c.regs().mc_esp = x }
func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) }
func (c *sigctxt) set_sigaddr(x uint32) { c.info.si_addr = uintptr(x) }
// 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) (((Ucontext*)(ctxt))->uc_mcontext)
#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).mc_eax)
#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).mc_ebx)
#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).mc_ecx)
#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).mc_edx)
#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).mc_edi)
#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).mc_esi)
#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).mc_ebp)
#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).mc_esp)
#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).mc_eip)
#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).mc_eflags)
#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).mc_cs)
#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).mc_fs)
#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).mc_gs)
#define SIG_CODE0(info, ctxt) ((info)->si_code)
#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr)
...@@ -718,9 +718,7 @@ func newstack() { ...@@ -718,9 +718,7 @@ func newstack() {
gothrow("stack overflow") gothrow("stack overflow")
} }
oldstatus := readgstatus(gp) casgstatus(gp, _Gwaiting, _Gcopystack)
oldstatus &^= _Gscan
casgstatus(gp, oldstatus, _Gcopystack) // oldstatus is Gwaiting or Grunnable
// The concurrent GC will not scan the stack while we are doing the copy since // The concurrent GC will not scan the stack while we are doing the copy since
// the gp is in a Gcopystack status. // the gp is in a Gcopystack status.
...@@ -789,15 +787,7 @@ func shrinkstack(gp *g) { ...@@ -789,15 +787,7 @@ func shrinkstack(gp *g) {
print("shrinking stack ", oldsize, "->", newsize, "\n") print("shrinking stack ", oldsize, "->", newsize, "\n")
} }
// This is being done in a Gscan state and was initiated by the GC so no need to move to oldstatus := casgcopystack(gp)
// the Gcopystate.
// The world is stopped, so the goroutine must be Gwaiting or Grunnable,
// and what it is is not changing underfoot.
oldstatus := readgstatus(gp) &^ _Gscan
if oldstatus != _Gwaiting && oldstatus != _Grunnable {
gothrow("status is not Gwaiting or Grunnable")
}
casgstatus(gp, oldstatus, _Gcopystack)
copystack(gp, newsize) copystack(gp, newsize)
casgstatus(gp, _Gcopystack, oldstatus) casgstatus(gp, _Gcopystack, oldstatus)
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment