[dev.cc] all: merge master (d1210ac) into dev.cc

Change-Id: I068d617175776c2f5df00b17ff0d404a584ab570
This commit is contained in:
Russ Cox 2015-01-14 19:39:34 -05:00
commit 929f3210ac
196 changed files with 3951 additions and 2753 deletions

View file

@ -19,6 +19,8 @@ Go is the work of hundreds of contributors. We appreciate your help!
To contribute, please read the contribution guidelines:
https://golang.org/doc/contribute.html
##### Please note that we do not use pull requests.
Unless otherwise noted, the Go source files are distributed
under the BSD-style license found in the LICENSE file.

View file

@ -247,5 +247,3 @@ pkg runtime (openbsd-amd64-cgo), const EWOULDBLOCK = 35
pkg runtime (openbsd-amd64-cgo), const EWOULDBLOCK ideal-int
pkg runtime (openbsd-amd64-cgo), const HW_NCPU = 3
pkg runtime (openbsd-amd64-cgo), const HW_NCPU ideal-int
pkg runtime, func GCcheckmarkdisable()
pkg runtime, func GCcheckmarkenable()

View file

@ -154,7 +154,7 @@ Git, note that you still need the commit hooks that the git-codereview command
configures; those hooks add a Gerrit <code>Change-Id</code> line to the commit
message and check that all Go source files have been formatted with gofmt. Even
if you intend to use plain Git for daily work, install the hooks in a new Git
checkout by running <code>git-codereview</code> <code>hooks</code>).
checkout by running <code>git-codereview</code> <code>hooks</code>.
</p>
<h3>Set up git aliases</h3>
@ -461,7 +461,7 @@ $ git sync
</pre>
<p>
(In git terms, git sync runs
(In git terms, <code>git</code> <code>sync</code> runs
<code>git</code> <code>pull</code> <code>-r</code>.)
</p>

View file

@ -4,10 +4,16 @@ bufio: add Reader.Discard (https://golang.org/cl/2260)
crypto/cipher: clarify what will happen if len(src) != len(dst) for the Stream interface. (https://golang.org/cl/1754)
crypto/tls: change default minimum version to TLS 1.0. (https://golang.org/cl/1791)
encoding/base64: add unpadded encodings (https://golang.org/cl/1511)
log: add global Output function (https://golang.org/cl/2686)
net/http: support for setting trailers from a server Handler (https://golang.org/cl/2157)
net/smtp: add TLSConnectionState accessor (https://golang.org/cl/2151)
Tools:
cmd/vet: better validation of struct tags (https://golang.org/cl/2685)
Performance:
strconv: optimize decimal to string conversion (https://golang.org/cl/2105)
math/big: faster assembly kernels for amd64 and 386 (https://golang.org/cl/2503, https://golang.org/cl/2560)
math/big: faster "pure Go" kernels for platforms w/o assembly kernels (https://golang.org/cl/2480)

View file

@ -77,6 +77,7 @@ struct Reloc
uchar siz;
uchar done;
int32 type;
int32 variant; // RV_*: variant on computed value
int64 add;
int64 xadd;
LSym* sym;
@ -141,6 +142,7 @@ struct LSym
uchar hide;
uchar leaf; // arm only
uchar fnptr; // arm only
uchar localentry; // ppc64: instrs between global & local entry
uchar seenglobl;
uchar onlist; // on the textp or datap lists
int16 symid; // for writing .5/.6/.8 files
@ -210,6 +212,7 @@ enum
SMACHO, /* Mach-O __nl_symbol_ptr */
SMACHOGOT,
SWINDOWS,
SELFGOT, /* also .toc in ppc64 ABI */
SNOPTRDATA,
SINITARR,
SDATA,
@ -254,6 +257,20 @@ enum
R_PLT1,
R_PLT2,
R_USEFIELD,
R_POWER_TOC, // ELF R_PPC64_TOC16*
};
// Reloc.variant
enum
{
RV_NONE, // identity variant
RV_POWER_LO, // x & 0xFFFF
RV_POWER_HI, // x >> 16
RV_POWER_HA, // (x + 0x8000) >> 16
RV_POWER_DS, // x & 0xFFFC, check x&0x3 == 0
RV_CHECK_OVERFLOW = 1<<8, // check overflow flag
RV_TYPE_MASK = (RV_CHECK_OVERFLOW - 1),
};
// Auto.type

View file

@ -63,5 +63,6 @@ func Test8811(t *testing.T) { test8811(t) }
func TestReturnAfterGrow(t *testing.T) { testReturnAfterGrow(t) }
func TestReturnAfterGrowFromGo(t *testing.T) { testReturnAfterGrowFromGo(t) }
func Test9026(t *testing.T) { test9026(t) }
func Test9557(t *testing.T) { test9557(t) }
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }

View file

@ -14,7 +14,7 @@ import "testing"
var v7234 = [...]string{"runtime/cgo"}
func TestIssue7234(t *testing.T) {
func Test7234(t *testing.T) {
if v7234[0] != "runtime/cgo" {
t.Errorf("bad string constant %q", v7234[0])
}

View file

@ -0,0 +1,36 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// cgo rewrote C.var to *_Cvar_var, but left
// C.var.field as _Cvar.var.field. It now rewrites
// the latter as (*_Cvar_var).field.
// See https://golang.org/issue/9557.
package cgotest
// struct issue9557_t {
// int a;
// } test9557bar = { 42 };
//
// struct issue9557_t *issue9557foo = &test9557bar;
import "C"
import "testing"
func test9557(t *testing.T) {
// implicitly dereference a Go variable
foo := C.issue9557foo
if v := foo.a; v != 42 {
t.Fatalf("foo.a expected 42, but got %d", v)
}
// explicitly dereference a C variable
if v := (*C.issue9557foo).a; v != 42 {
t.Fatalf("(*C.issue9557foo).a expected 42, but is %d", v)
}
// implicitly dereference a C variable
if v := C.issue9557foo.a; v != 42 {
t.Fatalf("C.issue9557foo.a expected 42, but is %d", v)
}
}

View file

@ -1,9 +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.
#include "runtime.h"
#include "cdefstest.h"
struct CdefsTest test;
struct PackedTest packed;

View file

@ -1,60 +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.
//
// +build ignore
package cgotest
/*
// This file tests a bug found in the cgo -cdefs tool that incorrectly
// translated Go pointer arrays generated by the cgo godefs tool back into C
// pointer arrays.
//
// The comments below show how the type is translated from gcc-style C into Go
// and back into C for both the buggy version and the correct version
struct cdefsTest {
// This was already being handled correctly
// Correct: -> Array [20]int8 -> int8 array[20]
char array1[20];
// Buggy: -> Array [20][20]int8 -> [20]int8 array[20]
// Correct: -> Array [20][20]int8 -> int8 array[20][20]
char array2[20][20];
// Buggy: -> Array [20]*int8 -> *int8 array[20]
// Correct: -> Array [20]*int8 -> int8 *array[20]
char *array3[20];
// Buggy: -> Array [20][20]*int8 -> [20]*int8 array[20]
// Correct: -> Array [20]**int8 -> int8 *array[20][20]
char *array4[20][20];
// Buggy: -> Array [20][20]**int8 -> [20]**int8 array[20]
// Correct: -> Array [20][20]**int8 -> int8 **array[20][20]
char **array5[20][20];
};
// Test that packed structures can be translated to C correctly too.
// See issue 8477.
struct packedTest {
char first;
int second;
long long third;
} __attribute__((packed));
// Test that conflicting type definitions don't cause problems with cgo.
// See issue 8477.
typedef struct timespec {
double bogus;
} pid_t;
*/
import "C"
type CdefsTest C.struct_cdefsTest
//type PackedTest C.struct_packedTest

View file

@ -1,76 +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.
#include "runtime.h"
#include "cdefstest.h"
void runtime·printf(int8*, ...);
// From cdefstest.go.
typedef struct CdefsOrig CdefsOrig;
struct CdefsOrig {
int8 array1[20];
int8 array2[20][20];
int8 *array3[20];
int8 *array4[20][20];
int8 **array5[20][20];
};
// Packed structs are no longer supported for -cdefs.
/*
typedef struct PackedOrig PackedOrig;
#pragma pack on
struct PackedOrig {
int8 first;
int32 second;
int64 third;
};
#pragma pack off
*/
void
main·test(int32 ret)
{
CdefsOrig o;
CdefsTest t;
// PackedOrig po;
// PackedTest pt;
ret = 0;
if(sizeof(t.array1) != sizeof(o.array1) || offsetof(CdefsTest, array1[0]) != offsetof(CdefsOrig, array1[0])) {
runtime·printf("array1: size, offset = %d, %d, want %d, %d\n", sizeof(t.array1), offsetof(CdefsTest, array1[0]), sizeof(o.array1), offsetof(CdefsOrig, array1[0]));
ret = 1;
}
if(sizeof(t.array2) != sizeof(o.array2) || offsetof(CdefsTest, array2[0][0]) != offsetof(CdefsOrig, array2[0][0])) {
runtime·printf("array2: size, offset = %d, %d, want %d, %d\n", sizeof(t.array2), offsetof(CdefsTest, array2[0][0]), sizeof(o.array2), offsetof(CdefsOrig, array2[0][0]));
ret = 1;
}
if(sizeof(t.array3) != sizeof(o.array3) || offsetof(CdefsTest, array3[0]) != offsetof(CdefsOrig, array3[0])) {
runtime·printf("array3: size, offset = %d, %d, want %d, %d\n", sizeof(t.array3), offsetof(CdefsTest, array3[0]), sizeof(o.array3), offsetof(CdefsOrig, array3[0]));
ret = 1;
}
if(sizeof(t.array4) != sizeof(o.array4) || offsetof(CdefsTest, array4[0][0]) != offsetof(CdefsOrig, array4[0][0])) {
runtime·printf("array4: size, offset = %d, %d, want %d, %d\n", sizeof(t.array4), offsetof(CdefsTest, array4[0][0]), sizeof(o.array4), offsetof(CdefsOrig, array4[0][0]));
ret = 1;
}
if(sizeof(t.array5) != sizeof(o.array5) || offsetof(CdefsTest, array5[0][0]) != offsetof(CdefsOrig, array5[0][0])) {
runtime·printf("array5: size, offset = %d, %d, want %d, %d\n", sizeof(t.array5), offsetof(CdefsTest, array5[0][0]), sizeof(o.array5), offsetof(CdefsOrig, array5[0][0]));
ret = 1;
}
/*
if(sizeof(pt.first) != sizeof(po.first) || offsetof(PackedTest, first) != offsetof(PackedOrig, first)) {
runtime·printf("first: size, offset = %d, %d, want %d, %d\n", sizeof(pt.first), offsetof(PackedTest, first), sizeof(po.first), offsetof(PackedOrig, first));
ret = 1;
}
if(sizeof(pt.second) != sizeof(po.second) || offsetof(PackedTest, second) != offsetof(PackedOrig, second)) {
runtime·printf("second: size, offset = %d, %d, want %d, %d\n", sizeof(pt.second), offsetof(PackedTest, second), sizeof(po.second), offsetof(PackedOrig, second));
ret = 1;
}
if(sizeof(pt.third) != sizeof(po.third) || offsetof(PackedTest, third) != offsetof(PackedOrig, third)) {
runtime·printf("third: size, offset = %d, %d, want %d, %d\n", sizeof(pt.third), offsetof(PackedTest, third), sizeof(po.third), offsetof(PackedOrig, third));
ret = 1;
}
*/
FLUSH(&ret); // flush return value
}

View file

@ -1,13 +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.
package main
import "os"
func test() int32 // in main.c
func main() {
os.Exit(int(test()))
}

View file

@ -1,16 +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.
# Just add issue file prefixes to this list if more issues come up
FILE_PREFIXES="cdefstest"
for FP in $FILE_PREFIXES
do
go tool cgo -cdefs ${FP}.go > ${FP}.h
done
go build . && ./testcdefs
EXIT=$?
rm -rf _obj testcdefs *.h
exit $EXIT

View file

@ -30,15 +30,16 @@ import (
"runtime"
"strings"
"code.google.com/p/goauth2/oauth"
storage "code.google.com/p/google-api-go-client/storage/v1"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
)
var (
tag = flag.String("tag", "release", "mercurial tag to check out")
toolTag = flag.String("tool", defaultToolTag, "go.tools tag to check out")
tag = flag.String("tag", "", "git revision to check out")
toolTag = flag.String("tool", defaultToolTag, "go.tools revision to check out")
tourTag = flag.String("tour", defaultTourTag, "go-tour tag to check out")
repo = flag.String("repo", "https://code.google.com/p/go", "repo URL")
repo = flag.String("repo", "https://go.googlesource.com/go", "repo URL")
verbose = flag.Bool("v", false, "verbose output")
upload = flag.Bool("upload", false, "upload resulting files to Google Code")
addLabel = flag.String("label", "", "additional label to apply to file when uploading")
@ -80,9 +81,9 @@ var preBuildCleanFiles = []string{
}
var cleanFiles = []string{
".hg",
".hgtags",
".hgignore",
".git",
".gitignore",
".gitattributes",
"VERSION.cache",
}
@ -140,6 +141,10 @@ func main() {
os.Exit(2)
}
flag.Parse()
if *tag == "" {
fmt.Fprintln(os.Stderr, "you must specify a -tag")
os.Exit(2)
}
if flag.NArg() == 0 {
flag.Usage()
}
@ -236,11 +241,11 @@ func (b *Build) Do() error {
b.gopath = work
// Clone Go distribution and update to tag.
_, err = b.hgCmd(work, "clone", *repo, b.root)
_, err = b.run(work, "git", "clone", *repo, b.root)
if err != nil {
return err
}
_, err = b.hgCmd(b.root, "update", *tag)
_, err = b.run(b.root, "git", "checkout", *tag)
if err != nil {
return err
}
@ -620,10 +625,6 @@ func ext() string {
return ""
}
func (b *Build) hgCmd(dir string, args ...string) ([]byte, error) {
return b.run(dir, "hg", append([]string{"--config", "extensions.codereview=!"}, args...)...)
}
func (b *Build) run(dir, name string, args ...string) ([]byte, error) {
buf := new(bytes.Buffer)
absName, err := lookPath(name)
@ -749,18 +750,13 @@ type File struct {
}
func setupOAuthClient() error {
config := &oauth.Config{
ClientId: "999119582588-h7kpj5pcm6d9solh5lgrbusmvvk4m9dn.apps.googleusercontent.com",
config := &oauth2.Config{
ClientID: "999119582588-h7kpj5pcm6d9solh5lgrbusmvvk4m9dn.apps.googleusercontent.com",
ClientSecret: "8YLFgOhXIELWbO-NtF3iqIQz",
Scope: storage.DevstorageRead_writeScope,
AuthURL: "https://accounts.google.com/o/oauth2/auth",
TokenURL: "https://accounts.google.com/o/oauth2/token",
TokenCache: oauth.CacheFile(*tokenCache),
RedirectURL: "oob",
Endpoint: google.Endpoint,
Scopes: []string{storage.DevstorageRead_writeScope},
}
transport := &oauth.Transport{Config: config}
if token, err := config.TokenCache.Token(); err != nil {
url := transport.Config.AuthCodeURL("")
url := config.AuthCodeURL("junk")
fmt.Println("Visit the following URL, obtain an authentication" +
"code, and enter it below.")
fmt.Println(url)
@ -769,13 +765,11 @@ func setupOAuthClient() error {
if _, err := fmt.Scan(&code); err != nil {
return err
}
if _, err := transport.Exchange(code); err != nil {
tok, err := config.Exchange(oauth2.NoContext, code)
if err != nil {
return err
}
} else {
transport.Token = token
}
oauthClient = transport.Client()
oauthClient = config.Client(oauth2.NoContext, tok)
return nil
}
@ -1011,6 +1005,11 @@ var hgTool = tool{
},
}
var gitTool = tool{
"http://git-scm.com/download/win",
[]string{`C:\Program Files\Git`, `C:\Program Files (x86)\Git`},
}
var gccTool = tool{
"Mingw gcc; http://sourceforge.net/projects/mingw/files/Installer/mingw-get-inst/",
[]string{`C:\Mingw\bin`},
@ -1022,6 +1021,7 @@ var windowsDeps = map[string]tool{
"candle": wixTool,
"light": wixTool,
"cmd": {"Windows cmd.exe", nil},
"git": gitTool,
"hg": hgTool,
}

View file

@ -10,7 +10,7 @@ import "testing"
// as expected.
func TestRead(t *testing.T) {
f := Fopen("file_test.go", "r")
if f == nil {
if f.Swigcptr() == 0 {
t.Fatal("fopen failed")
}
if Fgetc(f) != '/' || Fgetc(f) != '/' || Fgetc(f) != ' ' || Fgetc(f) != 'C' {

View file

@ -122,6 +122,8 @@ main(int argc, char *argv[])
if(assemble(argv[0]))
errorexit();
Bflush(&bstdout);
if(nerrors > 0)
errorexit();
exits(0);
}

View file

@ -371,6 +371,15 @@ archreloc(Reloc *r, LSym *s, vlong *val)
return -1;
}
vlong
archrelocvariant(Reloc *r, LSym *s, vlong t)
{
USED(r);
USED(s);
sysfatal("unexpected relocation variant");
return t;
}
static Reloc *
addpltreloc(Link *ctxt, LSym *plt, LSym *got, LSym *sym, int typ)
{

View file

@ -83,6 +83,7 @@ void adddynrel(LSym *s, Reloc *r);
void adddynrela(LSym *rel, LSym *s, Reloc *r);
void adddynsym(Link *ctxt, LSym *s);
int archreloc(Reloc *r, LSym *s, vlong *val);
vlong archrelocvariant(Reloc *r, LSym *s, vlong t);
void asmb(void);
int elfreloc1(Reloc *r, vlong sectoff);
void elfsetupplt(void);

View file

@ -132,6 +132,8 @@ main(int argc, char *argv[])
if(assemble(argv[0]))
errorexit();
Bflush(&bstdout);
if(nerrors > 0)
errorexit();
exits(0);
}

View file

@ -624,7 +624,6 @@ bignodes(void)
* t = f
* hard part is conversions.
*/
// TODO: lost special constants for floating point. XORPD for 0.0?
void
gmove(Node *f, Node *t)
{

View file

@ -121,7 +121,7 @@ peep(Prog *firstp)
case AMOVSS:
case AMOVSD:
if(regtyp(&p->to))
if(p->from.type == D_CONST)
if(p->from.type == D_CONST || p->from.type == D_FCONST)
conprop(r);
break;
}
@ -384,7 +384,7 @@ regtyp(Adr *a)
t = a->type;
if(t >= D_AX && t <= D_R15)
return 1;
if(t >= D_X0 && t <= D_X0+15)
if(t >= D_X0 && t <= D_X15)
return 1;
return 0;
}

View file

@ -396,6 +396,15 @@ archreloc(Reloc *r, LSym *s, vlong *val)
return -1;
}
vlong
archrelocvariant(Reloc *r, LSym *s, vlong t)
{
USED(r);
USED(s);
sysfatal("unexpected relocation variant");
return t;
}
void
elfsetupplt(void)
{

View file

@ -90,6 +90,7 @@ void adddynrel(LSym *s, Reloc *r);
void adddynrela(LSym *rela, LSym *s, Reloc *r);
void adddynsym(Link *ctxt, LSym *s);
int archreloc(Reloc *r, LSym *s, vlong *val);
vlong archrelocvariant(Reloc *r, LSym *s, vlong t);
void asmb(void);
int elfreloc1(Reloc *r, vlong sectoff);
void elfsetupplt(void);

View file

@ -127,6 +127,8 @@ main(int argc, char *argv[])
if(assemble(argv[0]))
errorexit();
Bflush(&bstdout);
if(nerrors > 0)
errorexit();
exits(0);
}

View file

@ -120,7 +120,7 @@ peep(Prog *firstp)
case AMOVSS:
case AMOVSD:
if(regtyp(&p->to))
if(p->from.type == D_CONST)
if(p->from.type == D_CONST || p->from.type == D_FCONST)
conprop(r);
break;
}

View file

@ -364,6 +364,15 @@ archreloc(Reloc *r, LSym *s, vlong *val)
return -1;
}
vlong
archrelocvariant(Reloc *r, LSym *s, vlong t)
{
USED(r);
USED(s);
sysfatal("unexpected relocation variant");
return t;
}
void
elfsetupplt(void)
{

View file

@ -74,6 +74,7 @@ void adddynrel(LSym *s, Reloc *r);
void adddynrela(LSym *rela, LSym *s, Reloc *r);
void adddynsym(Link *ctxt, LSym *s);
int archreloc(Reloc *r, LSym *s, vlong *val);
vlong archrelocvariant(Reloc *r, LSym *s, vlong t);
void asmb(void);
int elfreloc1(Reloc *r, vlong sectoff);
void elfsetupplt(void);

View file

@ -131,6 +131,8 @@ main(int argc, char *argv[])
if(assemble(argv[0]))
errorexit();
Bflush(&bstdout);
if(nerrors > 0)
errorexit();
exits(0);
}

View file

@ -262,8 +262,15 @@ afunclit(Addr *a, Node *n)
static int resvd[] =
{
REGZERO,
REGSP, // reserved for SP, XXX: not reserved in 9c.
30, // for g
REGSP, // reserved for SP
// We need to preserve the C ABI TLS pointer because sigtramp
// may happen during C code and needs to access the g. C
// clobbers REGG, so if Go were to clobber REGTLS, sigtramp
// won't know which convention to use. By preserving REGTLS,
// we can just retrieve g from TLS when we aren't sure.
REGTLS,
// TODO(austin): Consolidate REGTLS and REGG?
REGG,
REGTMP, // REGTMP
FREGCVI+NREG,
FREGZERO+NREG,

View file

@ -185,7 +185,7 @@ regopt(Prog *firstp)
}
// Exclude registers with fixed functions
regbits = (1<<D_R0)|RtoB(REGSP)|RtoB(REGG);
regbits = (1<<D_R0)|RtoB(REGSP)|RtoB(REGG)|RtoB(REGTLS);
// Also exclude floating point registers with fixed constants
regbits |= FtoB(D_F0+27)|FtoB(D_F0+28)|FtoB(D_F0+29)|FtoB(D_F0+30)|FtoB(D_F0+31);
externs = zbits;

View file

@ -30,10 +30,13 @@
/*
* powerpc 64
*/
#define NSNAME 8
#define NSYM 50
#define NREG 32 /* number of general registers */
#define NFREG 32 /* number of floating point registers */
enum
{
NSNAME = 8,
NSYM = 50,
NREG = 32, /* number of general registers */
NFREG = 32, /* number of floating point registers */
};
#include "../ld/textflag.h"
@ -48,6 +51,7 @@ enum
REGRT2 = 4, /* reserved for runtime, duffcopy */
REGMIN = 7, /* register variables allocated from here to REGMAX */
REGENV = 11, /* environment for closures */
REGTLS = 13, /* C ABI TLS base pointer */
REGMAX = 27,
REGEXT = 30, /* external registers allocated from here down */
REGG = 30, /* G */

View file

@ -36,6 +36,7 @@
#include "../ld/dwarf.h"
// TODO(austin): ABI v1 uses /usr/lib/ld.so.1
char linuxdynld[] = "/lib64/ld64.so.1";
char freebsddynld[] = "XXX";
char openbsddynld[] = "XXX";
@ -65,27 +66,264 @@ needlib(char *name)
int nelfsym = 1;
static void gencallstub(int abicase, LSym *stub, LSym *targ);
static void addpltsym(Link*, LSym*);
static LSym* ensureglinkresolver(void);
void
gentext(void)
{
LSym *s, *stub, **pprevtextp;
Reloc *r;
char *n;
uint32 o1;
uchar *cast;
int i;
// The ppc64 ABI PLT has similar concepts to other
// architectures, but is laid out quite differently. When we
// see an R_PPC64_REL24 relocation to a dynamic symbol
// (indicating that the call needs to go through the PLT), we
// generate up to three stubs and reserve a PLT slot.
//
// 1) The call site will be bl x; nop (where the relocation
// applies to the bl). We rewrite this to bl x_stub; ld
// r2,24(r1). The ld is necessary because x_stub will save
// r2 (the TOC pointer) at 24(r1) (the "TOC save slot").
//
// 2) We reserve space for a pointer in the .plt section (once
// per referenced dynamic function). .plt is a data
// section filled solely by the dynamic linker (more like
// .plt.got on other architectures). Initially, the
// dynamic linker will fill each slot with a pointer to the
// corresponding x@plt entry point.
//
// 3) We generate the "call stub" x_stub (once per dynamic
// function/object file pair). This saves the TOC in the
// TOC save slot, reads the function pointer from x's .plt
// slot and calls it like any other global entry point
// (including setting r12 to the function address).
//
// 4) We generate the "symbol resolver stub" x@plt (once per
// dynamic function). This is solely a branch to the glink
// resolver stub.
//
// 5) We generate the glink resolver stub (only once). This
// computes which symbol resolver stub we came through and
// invokes the dynamic resolver via a pointer provided by
// the dynamic linker. This will patch up the .plt slot to
// point directly at the function so future calls go
// straight from the call stub to the real function, and
// then call the function.
// NOTE: It's possible we could make ppc64 closer to other
// architectures: ppc64's .plt is like .plt.got on other
// platforms and ppc64's .glink is like .plt on other
// platforms.
// Find all R_PPC64_REL24 relocations that reference dynamic
// imports. Reserve PLT entries for these symbols and
// generate call stubs. The call stubs need to live in .text,
// which is why we need to do this pass this early.
//
// This assumes "case 1" from the ABI, where the caller needs
// us to save and restore the TOC pointer.
pprevtextp = &ctxt->textp;
for(s=*pprevtextp; s!=S; pprevtextp=&s->next, s=*pprevtextp) {
for(r=s->r; r<s->r+s->nr; r++) {
if(!(r->type == 256 + R_PPC64_REL24 &&
r->sym->type == SDYNIMPORT))
continue;
// Reserve PLT entry and generate symbol
// resolver
addpltsym(ctxt, r->sym);
// Generate call stub
n = smprint("%s.%s", s->name, r->sym->name);
stub = linklookup(ctxt, n, 0);
free(n);
stub->reachable |= s->reachable;
if(stub->size == 0) {
// Need outer to resolve .TOC.
stub->outer = s;
// Link in to textp before s (we could
// do it after, but would have to skip
// the subsymbols)
*pprevtextp = stub;
stub->next = s;
pprevtextp = &stub->next;
gencallstub(1, stub, r->sym);
}
// Update the relocation to use the call stub
r->sym = stub;
// Restore TOC after bl. The compiler put a
// nop here for us to overwrite.
o1 = 0xe8410018; // ld r2,24(r1)
cast = (uchar*)&o1;
for(i=0; i<4; i++)
s->p[r->off+4+i] = cast[inuxi4[i]];
}
}
}
// Construct a call stub in stub that calls symbol targ via its PLT
// entry.
static void
gencallstub(int abicase, LSym *stub, LSym *targ)
{
LSym *plt;
Reloc *r;
if(abicase != 1)
// If we see R_PPC64_TOCSAVE or R_PPC64_REL24_NOTOC
// relocations, we'll need to implement cases 2 and 3.
sysfatal("gencallstub only implements case 1 calls");
plt = linklookup(ctxt, ".plt", 0);
stub->type = STEXT;
// Save TOC pointer in TOC save slot
adduint32(ctxt, stub, 0xf8410018); // std r2,24(r1)
// Load the function pointer from the PLT.
r = addrel(stub);
r->off = stub->size;
r->sym = plt;
r->add = targ->plt;
r->siz = 2;
if(ctxt->arch->endian == BigEndian)
r->off += r->siz;
r->type = R_POWER_TOC;
r->variant = RV_POWER_HA;
adduint32(ctxt, stub, 0x3d820000); // addis r12,r2,targ@plt@toc@ha
r = addrel(stub);
r->off = stub->size;
r->sym = plt;
r->add = targ->plt;
r->siz = 2;
if(ctxt->arch->endian == BigEndian)
r->off += r->siz;
r->type = R_POWER_TOC;
r->variant = RV_POWER_LO;
adduint32(ctxt, stub, 0xe98c0000); // ld r12,targ@plt@toc@l(r12)
// Jump to the loaded pointer
adduint32(ctxt, stub, 0x7d8903a6); // mtctr r12
adduint32(ctxt, stub, 0x4e800420); // bctr
}
void
adddynrela(LSym *rel, LSym *s, Reloc *r)
{
// TODO(minux)
USED(rel); USED(s); USED(r);
sysfatal("adddynrela not implemented");
}
void
adddynrel(LSym *s, Reloc *r)
{
LSym *targ;
// TODO(minux)
LSym *targ, *rela;
targ = r->sym;
ctxt->cursym = s;
switch(r->type) {
default:
if(r->type >= 256) {
diag("unexpected relocation type %d", r->type);
return;
}
break;
// Handle relocations found in ELF object files.
case 256 + R_PPC64_REL24:
r->type = R_CALLPOWER;
// This is a local call, so the caller isn't setting
// up r12 and r2 is the same for the caller and
// callee. Hence, we need to go to the local entry
// point. (If we don't do this, the callee will try
// to use r12 to compute r2.)
r->add += r->sym->localentry * 4;
if(targ->type == SDYNIMPORT)
// Should have been handled in elfsetupplt
diag("unexpected R_PPC64_REL24 for dyn import");
return;
case 256 + R_PPC64_ADDR64:
r->type = R_ADDR;
if(targ->type == SDYNIMPORT) {
// These happen in .toc sections
adddynsym(ctxt, targ);
rela = linklookup(ctxt, ".rela", 0);
addaddrplus(ctxt, rela, s, r->off);
adduint64(ctxt, rela, ELF64_R_INFO(targ->dynid, R_PPC64_ADDR64));
adduint64(ctxt, rela, r->add);
r->type = 256; // ignore during relocsym
}
return;
case 256 + R_PPC64_TOC16:
r->type = R_POWER_TOC;
r->variant = RV_POWER_LO | RV_CHECK_OVERFLOW;
return;
case 256 + R_PPC64_TOC16_LO:
r->type = R_POWER_TOC;
r->variant = RV_POWER_LO;
return;
case 256 + R_PPC64_TOC16_HA:
r->type = R_POWER_TOC;
r->variant = RV_POWER_HA | RV_CHECK_OVERFLOW;
return;
case 256 + R_PPC64_TOC16_HI:
r->type = R_POWER_TOC;
r->variant = RV_POWER_HI | RV_CHECK_OVERFLOW;
return;
case 256 + R_PPC64_TOC16_DS:
r->type = R_POWER_TOC;
r->variant = RV_POWER_DS | RV_CHECK_OVERFLOW;
return;
case 256 + R_PPC64_TOC16_LO_DS:
r->type = R_POWER_TOC;
r->variant = RV_POWER_DS;
return;
case 256 + R_PPC64_REL16_LO:
r->type = R_PCREL;
r->variant = RV_POWER_LO;
r->add += 2; // Compensate for relocation size of 2
return;
case 256 + R_PPC64_REL16_HI:
r->type = R_PCREL;
r->variant = RV_POWER_HI | RV_CHECK_OVERFLOW;
r->add += 2;
return;
case 256 + R_PPC64_REL16_HA:
r->type = R_PCREL;
r->variant = RV_POWER_HA | RV_CHECK_OVERFLOW;
r->add += 2;
return;
}
// Handle references to ELF symbols from our own object files.
if(targ->type != SDYNIMPORT)
return;
// TODO(austin): Translate our relocations to ELF
diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
}
@ -100,8 +338,16 @@ elfreloc1(Reloc *r, vlong sectoff)
void
elfsetupplt(void)
{
// TODO(minux)
return;
LSym *plt;
plt = linklookup(ctxt, ".plt", 0);
if(plt->size == 0) {
// The dynamic linker stores the address of the
// dynamic resolver and the DSO identifier in the two
// doublewords at the beginning of the .plt section
// before the PLT array. Reserve space for these.
plt->size = 16;
}
}
int
@ -113,12 +359,29 @@ machoreloc1(Reloc *r, vlong sectoff)
return -1;
}
// Return the value of .TOC. for symbol s
static vlong
symtoc(LSym *s)
{
LSym *toc;
if(s->outer != nil)
toc = linkrlookup(ctxt, ".TOC.", s->outer->version);
else
toc = linkrlookup(ctxt, ".TOC.", s->version);
if(toc == nil) {
diag("TOC-relative relocation in object without .TOC.");
return 0;
}
return toc->value;
}
int
archreloc(Reloc *r, LSym *s, vlong *val)
{
uint32 o1, o2;
int32 t;
vlong t;
if(linkmode == LinkExternal) {
// TODO(minux): translate R_ADDRPOWER and R_CALLPOWER into standard ELF relocations.
@ -166,23 +429,252 @@ archreloc(Reloc *r, LSym *s, vlong *val)
t = symaddr(r->sym) + r->add - (s->value + r->off);
if(t & 3)
ctxt->diag("relocation for %s+%d is not aligned: %lld", r->sym->name, r->off, t);
if(t << 6 >> 6 != t)
if((int32)(t << 6) >> 6 != t)
// TODO(austin) This can happen if text > 32M.
// Add a call trampoline to .text in that case.
ctxt->diag("relocation for %s+%d is too big: %lld", r->sym->name, r->off, t);
*val = (o1 & 0xfc000003U) | (t & ~0xfc000003U);
return 0;
case R_POWER_TOC: // S + A - .TOC.
*val = symaddr(r->sym) + r->add - symtoc(s);
return 0;
}
return -1;
}
vlong
archrelocvariant(Reloc *r, LSym *s, vlong t)
{
uint32 o1;
switch(r->variant & RV_TYPE_MASK) {
default:
diag("unexpected relocation variant %d", r->variant);
case RV_NONE:
return t;
case RV_POWER_LO:
if(r->variant & RV_CHECK_OVERFLOW) {
// Whether to check for signed or unsigned
// overflow depends on the instruction
if(ctxt->arch->endian == BigEndian)
o1 = be32(s->p + r->off - 2);
else
o1 = le32(s->p + r->off);
switch(o1 >> 26) {
case 24: // ori
case 26: // xori
case 28: // andi
if((t >> 16) != 0)
goto overflow;
break;
default:
if((int16)t != t)
goto overflow;
break;
}
}
return (int16)t;
case RV_POWER_HA:
t += 0x8000;
// Fallthrough
case RV_POWER_HI:
t >>= 16;
if(r->variant & RV_CHECK_OVERFLOW) {
// Whether to check for signed or unsigned
// overflow depends on the instruction
if(ctxt->arch->endian == BigEndian)
o1 = be32(s->p + r->off - 2);
else
o1 = le32(s->p + r->off);
switch(o1 >> 26) {
case 25: // oris
case 27: // xoris
case 29: // andis
if((t >> 16) != 0)
goto overflow;
break;
default:
if((int16)t != t)
goto overflow;
break;
}
}
return (int16)t;
case RV_POWER_DS:
if(ctxt->arch->endian == BigEndian)
o1 = be16(s->p + r->off);
else
o1 = le16(s->p + r->off);
if(t & 3)
diag("relocation for %s+%d is not aligned: %lld", r->sym->name, r->off, t);
if((r->variant & RV_CHECK_OVERFLOW) && (int16)t != t)
goto overflow;
return (o1 & 0x3) | (vlong)(int16)t;
}
overflow:
diag("relocation for %s+%d is too big: %lld", r->sym->name, r->off, t);
return t;
}
static void
addpltsym(Link *ctxt, LSym *s)
{
if(s->plt >= 0)
return;
adddynsym(ctxt, s);
if(iself) {
LSym *plt, *rela, *glink;
Reloc *r;
plt = linklookup(ctxt, ".plt", 0);
rela = linklookup(ctxt, ".rela.plt", 0);
if(plt->size == 0)
elfsetupplt();
// Create the glink resolver if necessary
glink = ensureglinkresolver();
// Write symbol resolver stub (just a branch to the
// glink resolver stub)
r = addrel(glink);
r->sym = glink;
r->off = glink->size;
r->siz = 4;
r->type = R_CALLPOWER;
adduint32(ctxt, glink, 0x48000000); // b .glink
// In the ppc64 ABI, the dynamic linker is responsible
// for writing the entire PLT. We just need to
// reserve 8 bytes for each PLT entry and generate a
// JMP_SLOT dynamic relocation for it.
//
// TODO(austin): ABI v1 is different
s->plt = plt->size;
plt->size += 8;
addaddrplus(ctxt, rela, plt, s->plt);
adduint64(ctxt, rela, ELF64_R_INFO(s->dynid, R_PPC64_JMP_SLOT));
adduint64(ctxt, rela, 0);
} else {
diag("addpltsym: unsupported binary format");
}
}
// Generate the glink resolver stub if necessary and return the .glink section
static LSym*
ensureglinkresolver(void)
{
LSym *glink, *s;
Reloc *r;
glink = linklookup(ctxt, ".glink", 0);
if(glink->size != 0)
return glink;
// This is essentially the resolver from the ppc64 ELF ABI.
// At entry, r12 holds the address of the symbol resolver stub
// for the target routine and the argument registers hold the
// arguments for the target routine.
//
// This stub is PIC, so first get the PC of label 1 into r11.
// Other things will be relative to this.
adduint32(ctxt, glink, 0x7c0802a6); // mflr r0
adduint32(ctxt, glink, 0x429f0005); // bcl 20,31,1f
adduint32(ctxt, glink, 0x7d6802a6); // 1: mflr r11
adduint32(ctxt, glink, 0x7c0803a6); // mtlf r0
// Compute the .plt array index from the entry point address.
// Because this is PIC, everything is relative to label 1b (in
// r11):
// r0 = ((r12 - r11) - (res_0 - r11)) / 4 = (r12 - res_0) / 4
adduint32(ctxt, glink, 0x3800ffd0); // li r0,-(res_0-1b)=-48
adduint32(ctxt, glink, 0x7c006214); // add r0,r0,r12
adduint32(ctxt, glink, 0x7c0b0050); // sub r0,r0,r11
adduint32(ctxt, glink, 0x7800f082); // srdi r0,r0,2
// r11 = address of the first byte of the PLT
r = addrel(glink);
r->off = glink->size;
r->sym = linklookup(ctxt, ".plt", 0);
r->siz = 8;
r->type = R_ADDRPOWER;
// addis r11,0,.plt@ha; addi r11,r11,.plt@l
r->add = (0x3d600000ull << 32) | 0x396b0000;
glink->size += 8;
// Load r12 = dynamic resolver address and r11 = DSO
// identifier from the first two doublewords of the PLT.
adduint32(ctxt, glink, 0xe98b0000); // ld r12,0(r11)
adduint32(ctxt, glink, 0xe96b0008); // ld r11,8(r11)
// Jump to the dynamic resolver
adduint32(ctxt, glink, 0x7d8903a6); // mtctr r12
adduint32(ctxt, glink, 0x4e800420); // bctr
// The symbol resolvers must immediately follow.
// res_0:
// Add DT_PPC64_GLINK .dynamic entry, which points to 32 bytes
// before the first symbol resolver stub.
s = linklookup(ctxt, ".dynamic", 0);
elfwritedynentsymplus(s, DT_PPC64_GLINK, glink, glink->size - 32);
return glink;
}
void
adddynsym(Link *ctxt, LSym *s)
{
USED(ctxt); USED(s);
// TODO(minux)
LSym *d;
int t;
char *name;
if(s->dynid >= 0)
return;
if(iself) {
s->dynid = nelfsym++;
d = linklookup(ctxt, ".dynsym", 0);
name = s->extname;
adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name));
/* type */
t = STB_GLOBAL << 4;
if(s->cgoexport && (s->type&SMASK) == STEXT)
t |= STT_FUNC;
else
t |= STT_OBJECT;
adduint8(ctxt, d, t);
/* reserved */
adduint8(ctxt, d, 0);
/* section where symbol is defined */
if(s->type == SDYNIMPORT)
adduint16(ctxt, d, SHN_UNDEF);
else
adduint16(ctxt, d, 1);
/* value */
if(s->type == SDYNIMPORT)
adduint64(ctxt, d, 0);
else
addaddr(ctxt, d, s);
/* size of object */
adduint64(ctxt, d, s->size);
} else {
diag("adddynsym: unsupported binary format");
}
}
void

View file

@ -86,6 +86,7 @@ void adddynlib(char *lib);
void adddynrel(LSym *s, Reloc *r);
void adddynsym(Link *ctxt, LSym *s);
int archreloc(Reloc *r, LSym *s, vlong *val);
vlong archrelocvariant(Reloc *r, LSym *s, vlong t);
void listinit(void);
vlong rnd(vlong, int32);

View file

@ -80,7 +80,8 @@ archinit(void)
INITRND = 4096;
break;
case Hlinux: /* ppc64 elf */
debug['d'] = 1; // TODO(minux): dynamic linking is not supported yet.
if(strcmp(thestring, "ppc64") == 0)
debug['d'] = 1; // TODO(austin): ELF ABI v1 not supported yet
elfinit();
HEADR = ELFRESERVE;
if(INITTEXT == -1)

View file

@ -237,10 +237,6 @@ The following options are available when running cgo directly:
Write out input file in Go syntax replacing C package
names with real values. Used to generate files in the
syscall package when bootstrapping a new target.
-cdefs
Like -godefs, but write file in C syntax.
Used to generate files in the runtime package when
bootstrapping a new target.
-objdir directory
Put all generated files in directory.
-gccgo

View file

@ -154,20 +154,6 @@ func splitQuoted(s string) (r []string, err error) {
return args, err
}
var safeBytes = []byte(`+-.,/0123456789:=ABCDEFGHIJKLMNOPQRSTUVWXYZ\_abcdefghijklmnopqrstuvwxyz`)
func safeName(s string) bool {
if s == "" {
return false
}
for i := 0; i < len(s); i++ {
if c := s[i]; c < 0x80 && bytes.IndexByte(safeBytes, c) < 0 {
return false
}
}
return true
}
// Translate rewrites f.AST, the original Go input, to remove
// references to the imported package C, replacing them with
// references to the equivalent Go types, functions, and variables.
@ -582,7 +568,7 @@ func (p *Package) mangleName(n *Name) {
// rewriteRef rewrites all the C.xxx references in f.AST to refer to the
// Go equivalents, now that we have figured out the meaning of all
// the xxx. In *godefs or *cdefs mode, rewriteRef replaces the names
// the xxx. In *godefs mode, rewriteRef replaces the names
// with full definitions instead of mangled names.
func (p *Package) rewriteRef(f *File) {
// Keep a list of all the functions, to remove the ones
@ -673,6 +659,13 @@ func (p *Package) rewriteRef(f *File) {
expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
}
case "selector":
if r.Name.Kind == "var" {
expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
} else {
error_(r.Pos(), "only C variables allowed in selector expression", fixGo(r.Name.Go))
}
case "type":
if r.Name.Kind != "type" {
error_(r.Pos(), "expression C.%s used as type", fixGo(r.Name.Go))
@ -688,7 +681,7 @@ func (p *Package) rewriteRef(f *File) {
error_(r.Pos(), "must call C.%s", fixGo(r.Name.Go))
}
}
if *godefs || *cdefs {
if *godefs {
// Substitute definition for mangled type name.
if id, ok := expr.(*ast.Ident); ok {
if t := typedef[id.Name]; t != nil {
@ -992,8 +985,8 @@ func (c *typeConv) Init(ptrSize, intSize int64) {
c.goVoid = c.Ident("_Ctype_void")
// Normally cgo translates void* to unsafe.Pointer,
// but for historical reasons -cdefs and -godefs use *byte instead.
if *cdefs || *godefs {
// but for historical reasons -godefs uses *byte instead.
if *godefs {
c.goVoidPtr = &ast.StarExpr{X: c.byte}
} else {
c.goVoidPtr = c.Ident("unsafe.Pointer")
@ -1334,8 +1327,8 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
// If sub.Go.Name is "_Ctype_struct_foo" or "_Ctype_union_foo" or "_Ctype_class_foo",
// use that as the Go form for this typedef too, so that the typedef will be interchangeable
// with the base type.
// In -godefs and -cdefs mode, do this for all typedefs.
if isStructUnionClass(sub.Go) || *godefs || *cdefs {
// In -godefs mode, do this for all typedefs.
if isStructUnionClass(sub.Go) || *godefs {
t.Go = sub.Go
if isStructUnionClass(sub.Go) {
@ -1397,7 +1390,7 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
name := c.Ident("_Ctype_" + s)
tt := *t
typedef[name.Name] = &tt
if !*godefs && !*cdefs {
if !*godefs {
t.Go = name
}
}
@ -1573,7 +1566,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
used[f.Name] = true
}
if !*godefs && !*cdefs {
if !*godefs {
for cid, goid := range ident {
if token.Lookup(goid).IsKeyword() {
// Avoid keyword
@ -1600,12 +1593,12 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
name := f.Name
ft := f.Type
// In godefs or cdefs mode, if this field is a C11
// In godefs mode, if this field is a C11
// anonymous union then treat the first field in the
// union as the field in the struct. This handles
// cases like the glibc <sys/resource.h> file; see
// issue 6677.
if *godefs || *cdefs {
if *godefs {
if st, ok := f.Type.(*dwarf.StructType); ok && name == "" && st.Kind == "union" && len(st.Field) > 0 && !used[st.Field[0].Name] {
name = st.Field[0].Name
ident[name] = name
@ -1635,14 +1628,12 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
talign = size
}
if talign > 0 && f.ByteOffset%talign != 0 && !*cdefs {
if talign > 0 && f.ByteOffset%talign != 0 {
// Drop misaligned fields, the same way we drop integer bit fields.
// The goal is to make available what can be made available.
// Otherwise one bad and unneeded field in an otherwise okay struct
// makes the whole program not compile. Much of the time these
// structs are in system headers that cannot be corrected.
// Exception: In -cdefs mode, we use #pragma pack, so misaligned
// fields should still work.
continue
}
n := len(fld)
@ -1672,7 +1663,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
buf.WriteString("}")
csyntax = buf.String()
if *godefs || *cdefs {
if *godefs {
godefsFields(fld)
}
expr = &ast.StructType{Fields: &ast.FieldList{List: fld}}
@ -1707,11 +1698,9 @@ func godefsFields(fld []*ast.Field) {
n.Name = "Pad_cgo_" + strconv.Itoa(npad)
npad++
}
if !*cdefs {
n.Name = upper(n.Name)
}
}
}
}
// fieldPrefix returns the prefix that should be removed from all the
@ -1721,9 +1710,6 @@ func godefsFields(fld []*ast.Field) {
// package syscall's data structures, we drop a common prefix
// (so sec, usec, which will get turned into Sec, Usec for exporting).
func fieldPrefix(fld []*ast.Field) string {
if *cdefs {
return ""
}
prefix := ""
for _, f := range fld {
for _, n := range f.Names {

View file

@ -114,173 +114,6 @@ func (p *Package) godefs(f *File, srcfile string) string {
return buf.String()
}
// cdefs returns the output for -cdefs mode.
// The easiest way to do this is to translate the godefs Go to C.
func (p *Package) cdefs(f *File, srcfile string) string {
godefsOutput := p.godefs(f, srcfile)
lines := strings.Split(godefsOutput, "\n")
lines[0] = "// Created by cgo -cdefs - DO NOT EDIT"
for i, line := range lines {
lines[i] = strings.TrimSpace(line)
}
var out bytes.Buffer
printf := func(format string, args ...interface{}) { fmt.Fprintf(&out, format, args...) }
didTypedef := false
for i := 0; i < len(lines); i++ {
line := lines[i]
// Delete
// package x
if strings.HasPrefix(line, "package ") {
continue
}
// Convert
// const (
// A = 1
// B = 2
// )
//
// to
//
// enum {
// A = 1,
// B = 2,
// };
if line == "const (" {
printf("enum {\n")
for i++; i < len(lines) && lines[i] != ")"; i++ {
line = lines[i]
if line != "" {
printf("\t%s,", line)
}
printf("\n")
}
printf("};\n")
continue
}
// Convert
// const A = 1
// to
// enum { A = 1 };
if strings.HasPrefix(line, "const ") {
printf("enum { %s };\n", line[len("const "):])
continue
}
// On first type definition, typedef all the structs
// in case there are dependencies between them.
if !didTypedef && strings.HasPrefix(line, "type ") {
didTypedef = true
for _, line := range lines {
line = strings.TrimSpace(line)
if strings.HasPrefix(line, "type ") && strings.HasSuffix(line, " struct {") {
s := strings.TrimSuffix(strings.TrimPrefix(line, "type "), " struct {")
printf("typedef struct %s %s;\n", s, s)
}
}
printf("\n")
printf("#pragma pack on\n")
printf("\n")
}
// Convert
// type T struct {
// X int64
// Y *int32
// Z [4]byte
// }
//
// to
//
// struct T {
// int64 X;
// int32 *Y;
// byte Z[4];
// }
if strings.HasPrefix(line, "type ") && strings.HasSuffix(line, " struct {") {
if len(lines) > i+1 && lines[i+1] == "}" {
// do not output empty struct
i++
continue
}
s := line[len("type ") : len(line)-len(" struct {")]
printf("struct %s {\n", s)
for i++; i < len(lines) && lines[i] != "}"; i++ {
line := lines[i]
if line != "" {
f := strings.Fields(line)
if len(f) != 2 {
fmt.Fprintf(os.Stderr, "cgo: cannot parse struct field: %s\n", line)
nerrors++
continue
}
printf("\t%s;", cdecl(f[0], f[1]))
}
printf("\n")
}
printf("};\n")
continue
}
// Convert
// type T int
// to
// typedef int T;
if strings.HasPrefix(line, "type ") {
f := strings.Fields(line[len("type "):])
if len(f) != 2 {
fmt.Fprintf(os.Stderr, "cgo: cannot parse type definition: %s\n", line)
nerrors++
continue
}
printf("typedef\t%s;\n", cdecl(f[0], f[1]))
continue
}
printf("%s\n", line)
}
if didTypedef {
printf("\n")
printf("#pragma pack off\n")
}
return out.String()
}
// cdecl returns the C declaration for the given Go name and type.
// It only handles the specific cases necessary for converting godefs output.
func cdecl(name, typ string) string {
// X *[0]byte -> X *void
if strings.HasPrefix(typ, "*[0]") {
typ = "*void"
}
// X [4]byte -> X[4] byte
for strings.HasPrefix(typ, "[") {
i := strings.Index(typ, "]") + 1
name = name + typ[:i]
typ = typ[i:]
}
// X *byte -> *X byte
for strings.HasPrefix(typ, "*") {
name = "*" + name
typ = typ[1:]
}
// X T -> T X
// Handle the special case: 'unsafe.Pointer' is 'void *'
if typ == "unsafe.Pointer" {
typ = "void"
name = "*" + name
}
return typ + "\t" + name
}
var gofmtBuf bytes.Buffer
// gofmt returns the gofmt-formatted string for an AST node.

View file

@ -155,10 +155,9 @@ var dynpackage = flag.String("dynpackage", "main", "set Go package for -dynimpor
var dynlinker = flag.Bool("dynlinker", false, "record dynamic linker information in -dynimport mode")
// These flags are for bootstrapping a new Go implementation,
// to generate Go and C headers that match the data layout and
// to generate Go types that match the data layout and
// constant values used in the host's C libraries and system calls.
var godefs = flag.Bool("godefs", false, "for bootstrap: write Go definitions for C file to standard output")
var cdefs = flag.Bool("cdefs", false, "for bootstrap: write C definitions for C file to standard output")
var objDir = flag.String("objdir", "", "object directory")
var gccgo = flag.Bool("gccgo", false, "generate files for use with gccgo")
@ -185,12 +184,7 @@ func main() {
return
}
if *godefs && *cdefs {
fmt.Fprintf(os.Stderr, "cgo: cannot use -cdefs and -godefs together\n")
os.Exit(2)
}
if *godefs || *cdefs {
if *godefs {
// Generating definitions pulled from header files,
// to be checked into Go repositories.
// Line numbers are just noise.
@ -282,14 +276,12 @@ func main() {
p.Record(f)
if *godefs {
os.Stdout.WriteString(p.godefs(f, input))
} else if *cdefs {
os.Stdout.WriteString(p.cdefs(f, input))
} else {
p.writeOutput(f, input)
}
}
if !*godefs && !*cdefs {
if !*godefs {
p.writeDefs()
}
if nerrors > 0 {

View file

@ -60,6 +60,7 @@ func (p *Package) writeDefs() {
}
fmt.Fprintf(fm, "void _cgo_allocate(void *a, int c) { }\n")
fmt.Fprintf(fm, "void _cgo_panic(void *a, int c) { }\n")
fmt.Fprintf(fm, "void _cgo_reginit(void) { }\n")
// Write second Go output: definitions of _C_xxx.
// In a separate file so that the import of "unsafe" does not

View file

@ -48,10 +48,13 @@ widstruct(Type *errtype, Type *t, vlong o, int flag)
Type *f;
int64 w;
int32 maxalign;
vlong starto, lastzero;
starto = o;
maxalign = flag;
if(maxalign < 1)
maxalign = 1;
lastzero = 0;
for(f=t->type; f!=T; f=f->down) {
if(f->etype != TFIELD)
fatal("widstruct: not TFIELD: %lT", f);
@ -80,22 +83,28 @@ widstruct(Type *errtype, Type *t, vlong o, int flag)
} else
f->nname->xoffset = o;
}
if(w == 0)
lastzero = o;
o += w;
if(o >= MAXWIDTH) {
yyerror("type %lT too large", errtype);
o = 8; // small but nonzero
}
}
// For nonzero-sized structs which end in a zero-sized thing, we add
// an extra byte of padding to the type. This padding ensures that
// taking the address of the zero-sized thing can't manufacture a
// pointer to the next object in the heap. See issue 9401.
if(flag == 1 && o > starto && o == lastzero)
o++;
// final width is rounded
if(flag)
o = rnd(o, maxalign);
t->align = maxalign;
// type width only includes back to first field's offset
if(t->type == T)
t->width = 0;
else
t->width = o - t->type->width;
t->width = o - starto;
return o;
}
@ -128,6 +137,11 @@ dowidth(Type *t)
return;
}
// break infinite recursion if the broken recursive type
// is referenced again
if(t->broke && t->width == 0)
return;
// defer checkwidth calls until after we're done
defercalc++;

View file

@ -126,12 +126,13 @@ char *runtimeimport =
"func @\"\".makeslice (@\"\".typ·2 *byte, @\"\".nel·3 int64, @\"\".cap·4 int64) (@\"\".ary·1 []any)\n"
"func @\"\".growslice (@\"\".typ·2 *byte, @\"\".old·3 []any, @\"\".n·4 int64) (@\"\".ary·1 []any)\n"
"func @\"\".memmove (@\"\".to·1 *any, @\"\".frm·2 *any, @\"\".length·3 uintptr)\n"
"func @\"\".memclr (@\"\".ptr·1 *byte, @\"\".length·2 uintptr)\n"
"func @\"\".memequal (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
"func @\"\".memequal8 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
"func @\"\".memequal16 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
"func @\"\".memequal32 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
"func @\"\".memequal64 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
"func @\"\".memequal128 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
"func @\"\".memequal8 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n"
"func @\"\".memequal16 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n"
"func @\"\".memequal32 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n"
"func @\"\".memequal64 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n"
"func @\"\".memequal128 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n"
"func @\"\".int64div (? int64, ? int64) (? int64)\n"
"func @\"\".uint64div (? uint64, ? uint64) (? uint64)\n"
"func @\"\".int64mod (? int64, ? int64) (? int64)\n"

View file

@ -551,6 +551,7 @@ dumpasmhdr(void)
t = n->type;
if(t->etype != TSTRUCT || t->map != T || t->funarg)
break;
Bprint(b, "#define %s__size %d\n", t->sym->name, (int)t->width);
for(t=t->type; t != T; t=t->down)
if(!isblanksym(t->sym))
Bprint(b, "#define %s_%s %d\n", n->sym->name, t->sym->name, (int)t->width);

View file

@ -384,6 +384,7 @@ enum
SymUniq = 1<<3,
SymSiggen = 1<<4,
SymAsm = 1<<5,
SymAlgGen = 1<<6,
};
struct Sym
@ -1450,6 +1451,7 @@ void walkswitch(Node *sw);
* typecheck.c
*/
int islvalue(Node *n);
int samesafeexpr(Node *l, Node *r);
Node* typecheck(Node **np, int top);
void typechecklist(NodeList *l, int top);
Node* typecheckdef(Node *n);

View file

@ -210,11 +210,12 @@ racewalknode(Node **np, NodeList **init, int wr, int skip)
case OCALLFUNC:
// Instrument dst argument of runtime.writebarrier* calls
// as we do not instrument runtime code.
if(n->left->sym != S && n->left->sym->pkg == runtimepkg && strncmp(n->left->sym->name, "writebarrier", 12) == 0) {
if(n->left->sym != S && n->left->sym->pkg == runtimepkg &&
(strncmp(n->left->sym->name, "writebarrier", 12) == 0 || strcmp(n->left->sym->name, "typedmemmove") == 0)) {
// Find the dst argument.
// The list can be reordered, so it's not necessary just the first or the second element.
for(l = n->list; l; l = l->next) {
if(strcmp(n->left->sym->name, "writebarrierfat") == 0) {
if(strcmp(n->left->sym->name, "typedmemmove") == 0) {
if(l->n->left->xoffset == widthptr)
break;
} else {

View file

@ -144,6 +144,73 @@ walkrange(Node *n)
fatal("walkrange");
case TARRAY:
// Lower n into runtime·memclr if possible, for
// fast zeroing of slices and arrays (issue 5373).
// Look for instances of
//
// for i := range a {
// a[i] = zero
// }
//
// in which the evaluation of a is side-effect-free.
if(!debug['N'])
if(!flag_race)
if(v1 != N)
if(v2 == N)
if(n->nbody != nil)
if(n->nbody->n != N) // at least one statement in body
if(n->nbody->next == nil) { // at most one statement in body
tmp = n->nbody->n; // first statement of body
if(tmp->op == OAS)
if(tmp->left->op == OINDEX)
if(samesafeexpr(tmp->left->left, a))
if(samesafeexpr(tmp->left->right, v1))
if(t->type->width > 0)
if(iszero(tmp->right)) {
// Convert to
// if len(a) != 0 {
// hp = &a[0]
// hn = len(a)*sizeof(elem(a))
// memclr(hp, hn)
// i = len(a) - 1
// }
n->op = OIF;
n->nbody = nil;
n->ntest = nod(ONE, nod(OLEN, a, N), nodintconst(0));
n->nincr = nil;
// hp = &a[0]
hp = temp(ptrto(types[TUINT8]));
tmp = nod(OINDEX, a, nodintconst(0));
tmp->bounded = 1;
tmp = nod(OADDR, tmp, N);
tmp = nod(OCONVNOP, tmp, N);
tmp->type = ptrto(types[TUINT8]);
n->nbody = list(n->nbody, nod(OAS, hp, tmp));
// hn = len(a) * sizeof(elem(a))
hn = temp(types[TUINTPTR]);
tmp = nod(OLEN, a, N);
tmp = nod(OMUL, tmp, nodintconst(t->type->width));
tmp = conv(tmp, types[TUINTPTR]);
n->nbody = list(n->nbody, nod(OAS, hn, tmp));
// memclr(hp, hn)
fn = mkcall("memclr", T, nil, hp, hn);
n->nbody = list(n->nbody, fn);
// i = len(a) - 1
v1 = nod(OAS, v1, nod(OSUB, nod(OLEN, a, N), nodintconst(1)));
n->nbody = list(n->nbody, v1);
typecheck(&n->ntest, Erv);
typechecklist(n->nbody, Etop);
walkstmt(&n);
lineno = lno;
return;
}
}
// orderstmt arranged for a copy of the array/slice variable if needed.
ha = a;
hv1 = temp(types[TINT]);

View file

@ -731,7 +731,7 @@ dcommontype(Sym *s, int ot, Type *t)
dowidth(t);
alg = algtype(t);
algsym = S;
if(alg < 0)
if(alg < 0 || alg == AMEM)
algsym = dalgsym(t);
if(t->sym != nil && !isptr[t->etype])
@ -791,7 +791,7 @@ dcommontype(Sym *s, int ot, Type *t)
if(gcprog)
i |= KindGCProg;
ot = duint8(s, ot, i); // kind
if(alg >= 0)
if(algsym == S)
ot = dsymptr(s, ot, algarray, alg*sizeofAlg);
else
ot = dsymptr(s, ot, algsym, 0);
@ -1311,29 +1311,58 @@ dalgsym(Type *t)
{
int ot;
Sym *s, *hash, *hashfunc, *eq, *eqfunc;
char *p;
// dalgsym is only called for a type that needs an algorithm table,
// which implies that the type is comparable (or else it would use ANOEQ).
if(algtype(t) == AMEM) {
// we use one algorithm table for all AMEM types of a given size
p = smprint(".alg%lld", t->width);
s = pkglookup(p, typepkg);
free(p);
if(s->flags & SymAlgGen)
return s;
s->flags |= SymAlgGen;
// make hash closure
p = smprint(".hashfunc%lld", t->width);
hashfunc = pkglookup(p, typepkg);
free(p);
ot = 0;
ot = dsymptr(hashfunc, ot, pkglookup("memhash_varlen", runtimepkg), 0);
ot = duintxx(hashfunc, ot, t->width, widthptr); // size encoded in closure
ggloblsym(hashfunc, ot, DUPOK|RODATA);
// make equality closure
p = smprint(".eqfunc%lld", t->width);
eqfunc = pkglookup(p, typepkg);
free(p);
ot = 0;
ot = dsymptr(eqfunc, ot, pkglookup("memequal_varlen", runtimepkg), 0);
ot = duintxx(eqfunc, ot, t->width, widthptr);
ggloblsym(eqfunc, ot, DUPOK|RODATA);
} else {
// generate an alg table specific to this type
s = typesymprefix(".alg", t);
hash = typesymprefix(".hash", t);
genhash(hash, t);
eq = typesymprefix(".eq", t);
hashfunc = typesymprefix(".hashfunc", t);
eqfunc = typesymprefix(".eqfunc", t);
genhash(hash, t);
geneq(eq, t);
// make Go funcs (closures) for calling hash and equal from Go
hashfunc = typesymprefix(".hashfunc", t);
dsymptr(hashfunc, 0, hash, 0);
ggloblsym(hashfunc, widthptr, DUPOK|RODATA);
eqfunc = typesymprefix(".eqfunc", t);
dsymptr(eqfunc, 0, eq, 0);
ggloblsym(eqfunc, widthptr, DUPOK|RODATA);
}
// ../../runtime/alg.go:/typeAlg
ot = 0;
ot = dsymptr(s, ot, hashfunc, 0);
ot = dsymptr(s, ot, eqfunc, 0);
ggloblsym(s, ot, DUPOK|RODATA);
return s;
}

View file

@ -160,13 +160,14 @@ func block()
func makeslice(typ *byte, nel int64, cap int64) (ary []any)
func growslice(typ *byte, old []any, n int64) (ary []any)
func memmove(to *any, frm *any, length uintptr)
func memclr(ptr *byte, length uintptr)
func memequal(x, y *any, size uintptr) bool
func memequal8(x, y *any, size uintptr) bool
func memequal16(x, y *any, size uintptr) bool
func memequal32(x, y *any, size uintptr) bool
func memequal64(x, y *any, size uintptr) bool
func memequal128(x, y *any, size uintptr) bool
func memequal8(x, y *any) bool
func memequal16(x, y *any) bool
func memequal32(x, y *any) bool
func memequal64(x, y *any) bool
func memequal128(x, y *any) bool
// only used on 32-bit
func int64div(int64, int64) int64

View file

@ -2652,7 +2652,7 @@ hashfor(Type *t)
a = algtype1(t, nil);
switch(a) {
case AMEM:
return hashmem(t);
fatal("hashfor with AMEM type");
case AINTER:
sym = pkglookup("interhash", runtimepkg);
break;
@ -2684,7 +2684,6 @@ hashfor(Type *t)
tfn = nod(OTFUNC, N, N);
tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
tfn->rlist = list(tfn->rlist, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
typecheck(&tfn, Etype);
n->type = tfn->type;
@ -2710,7 +2709,7 @@ genhash(Sym *sym, Type *t)
dclcontext = PEXTERN;
markdcl();
// func sym(p *T, s uintptr, h uintptr) uintptr
// func sym(p *T, h uintptr) uintptr
fn = nod(ODCLFUNC, N, N);
fn->nname = newname(sym);
fn->nname->class = PFUNC;
@ -2720,8 +2719,6 @@ genhash(Sym *sym, Type *t)
n = nod(ODCLFIELD, newname(lookup("p")), typenod(ptrto(t)));
tfn->list = list(tfn->list, n);
np = n->left;
n = nod(ODCLFIELD, newname(lookup("s")), typenod(types[TUINTPTR]));
tfn->list = list(tfn->list, n);
n = nod(ODCLFIELD, newname(lookup("h")), typenod(types[TUINTPTR]));
tfn->list = list(tfn->list, n);
nh = n->left;
@ -2773,14 +2770,13 @@ genhash(Sym *sym, Type *t)
nh,
nod(OMUL, nh, nodintconst(mul))));
// h = hashel(&p[i], sizeof(p[i]), h)
// h = hashel(&p[i], h)
call = nod(OCALL, hashel, N);
nx = nod(OINDEX, np, ni);
nx->bounded = 1;
na = nod(OADDR, nx, N);
na->etype = 1; // no escape to heap
call->list = list(call->list, na);
call->list = list(call->list, nodintconst(t->type->width));
call->list = list(call->list, nh);
n->nbody = list(n->nbody, nod(OAS, nh, call));
@ -2813,8 +2809,8 @@ genhash(Sym *sym, Type *t)
na = nod(OADDR, nx, N);
na->etype = 1; // no escape to heap
call->list = list(call->list, na);
call->list = list(call->list, nodintconst(size));
call->list = list(call->list, nh);
call->list = list(call->list, nodintconst(size));
fn->nbody = list(fn->nbody, nod(OAS, nh, call));
first = T;
@ -2825,17 +2821,29 @@ genhash(Sym *sym, Type *t)
continue;
// Run hash for this field.
hashel = hashfor(t1->type);
// h = hashel(&p.t1, size, h)
if(algtype1(t1->type, nil) == AMEM) {
hashel = hashmem(t1->type);
// h = memhash(&p.t1, h, size)
call = nod(OCALL, hashel, N);
nx = nod(OXDOT, np, newname(t1->sym)); // TODO: fields from other packages?
na = nod(OADDR, nx, N);
na->etype = 1; // no escape to heap
call->list = list(call->list, na);
call->list = list(call->list, nh);
call->list = list(call->list, nodintconst(t1->type->width));
fn->nbody = list(fn->nbody, nod(OAS, nh, call));
} else {
hashel = hashfor(t1->type);
// h = hashel(&p.t1, h)
call = nod(OCALL, hashel, N);
nx = nod(OXDOT, np, newname(t1->sym)); // TODO: fields from other packages?
na = nod(OADDR, nx, N);
na->etype = 1; // no escape to heap
call->list = list(call->list, na);
call->list = list(call->list, nh);
fn->nbody = list(fn->nbody, nod(OAS, nh, call));
}
}
break;
}
r = nod(ORETURN, N, N);
@ -2881,7 +2889,7 @@ eqfield(Node *p, Node *q, Node *field)
}
static Node*
eqmemfunc(vlong size, Type *type)
eqmemfunc(vlong size, Type *type, int *needsize)
{
char buf[30];
Node *fn;
@ -2889,6 +2897,7 @@ eqmemfunc(vlong size, Type *type)
switch(size) {
default:
fn = syslook("memequal", 1);
*needsize = 1;
break;
case 1:
case 2:
@ -2897,6 +2906,7 @@ eqmemfunc(vlong size, Type *type)
case 16:
snprint(buf, sizeof buf, "memequal%d", (int)size*8);
fn = syslook(buf, 1);
*needsize = 0;
break;
}
argtype(fn, type);
@ -2905,11 +2915,12 @@ eqmemfunc(vlong size, Type *type)
}
// Return node for
// if !memequal(&p.field, &q.field, size) { return false }
// if !memequal(&p.field, &q.field [, size]) { return false }
static Node*
eqmem(Node *p, Node *q, Node *field, vlong size)
{
Node *nif, *nx, *ny, *call, *r;
int needsize;
nx = nod(OADDR, nod(OXDOT, p, field), N);
nx->etype = 1; // does not escape
@ -2918,9 +2929,10 @@ eqmem(Node *p, Node *q, Node *field, vlong size)
typecheck(&nx, Erv);
typecheck(&ny, Erv);
call = nod(OCALL, eqmemfunc(size, nx->type->type), N);
call = nod(OCALL, eqmemfunc(size, nx->type->type, &needsize), N);
call->list = list(call->list, nx);
call->list = list(call->list, ny);
if(needsize)
call->list = list(call->list, nodintconst(size));
nif = nod(OIF, N, N);
@ -2951,7 +2963,7 @@ geneq(Sym *sym, Type *t)
dclcontext = PEXTERN;
markdcl();
// func sym(p, q *T, s uintptr) bool
// func sym(p, q *T) bool
fn = nod(ODCLFUNC, N, N);
fn->nname = newname(sym);
fn->nname->class = PFUNC;
@ -2964,8 +2976,6 @@ geneq(Sym *sym, Type *t)
n = nod(ODCLFIELD, newname(lookup("q")), typenod(ptrto(t)));
tfn->list = list(tfn->list, n);
nq = n->left;
n = nod(ODCLFIELD, newname(lookup("s")), typenod(types[TUINTPTR]));
tfn->list = list(tfn->list, n);
n = nod(ODCLFIELD, N, typenod(types[TBOOL]));
tfn->rlist = list(tfn->rlist, n);

View file

@ -2831,7 +2831,7 @@ checkassignlist(NodeList *l)
// Check whether l and r are the same side effect-free expression,
// so that it is safe to reuse one instead of computing both.
static int
int
samesafeexpr(Node *l, Node *r)
{
if(l->op != r->op || !eqtype(l->type, r->type))

View file

@ -794,8 +794,6 @@ walkexpr(Node **np, NodeList **init)
// var,b = mapaccess2*(t, m, i)
// a = *var
a = n->list->n;
var = temp(ptrto(t->type));
var->typecheck = 1;
fn = mapfn(p, t);
r = mkcall1(fn, getoutargx(fn->type), init, typename(t), r->left, key);
@ -806,10 +804,17 @@ walkexpr(Node **np, NodeList **init)
r->type->type->down->type = n->list->next->n->type;
n->rlist = list1(r);
n->op = OAS2FUNC;
// don't generate a = *var if a is _
if(!isblank(a)) {
var = temp(ptrto(t->type));
var->typecheck = 1;
n->list->n = var;
walkexpr(&n, init);
*init = list(*init, n);
n = nod(OAS, a, nod(OIND, var, N));
}
typecheck(&n, Etop);
walkexpr(&n, init);
// mapaccess needs a zero value to be at least this big.
@ -3194,7 +3199,7 @@ sliceany(Node* n, NodeList **init)
}
static Node*
eqfor(Type *t)
eqfor(Type *t, int *needsize)
{
int a;
Node *n;
@ -3213,6 +3218,7 @@ eqfor(Type *t)
n = syslook("memequal", 1);
argtype(n, t);
argtype(n, t);
*needsize = 1;
return n;
}
@ -3222,10 +3228,10 @@ eqfor(Type *t)
ntype = nod(OTFUNC, N, N);
ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
ntype->rlist = list(ntype->rlist, nod(ODCLFIELD, N, typenod(types[TBOOL])));
typecheck(&ntype, Etype);
n->type = ntype->type;
*needsize = 0;
return n;
}
@ -3245,7 +3251,7 @@ static void
walkcompare(Node **np, NodeList **init)
{
Node *n, *l, *r, *call, *a, *li, *ri, *expr, *cmpl, *cmpr;
int andor, i;
int andor, i, needsize;
Type *t, *t1;
n = *np;
@ -3333,9 +3339,10 @@ walkcompare(Node **np, NodeList **init)
}
// Chose not to inline. Call equality function directly.
call = nod(OCALL, eqfor(t), N);
call = nod(OCALL, eqfor(t, &needsize), N);
call->list = list(call->list, l);
call->list = list(call->list, r);
if(needsize)
call->list = list(call->list, nodintconst(t->width));
r = call;
if(n->op != OEQ)

View file

@ -875,7 +875,26 @@ listed in the GOPATH environment variable (see 'go help gopath').
The go command attempts to download the version of the
package appropriate for the Go release being used.
Run 'go help install' for more.
Run 'go help get' for more.
Import path checking
When the custom import path feature described above redirects to a
known code hosting site, each of the resulting packages has two possible
import paths, using the custom domain or the known hosting site.
A package statement is said to have an "import comment" if it is immediately
followed (before the next newline) by a comment of one of these two forms:
package math // import "path"
package math /* import "path" * /
The go command will refuse to install a package with an import comment
unless it is being referred to by that import path. In this way, import comments
let package authors make sure the custom import path is used and not a
direct path to the underlying code hosting site.
See https://golang.org/s/go14customimport for details.
Description of package lists

View file

@ -290,7 +290,7 @@ func downloadPackage(p *Package) error {
}
}
if remote != repo {
return fmt.Errorf("%s is from %s, should be from %s", dir, remote, repo)
return fmt.Errorf("%s is a custom import path for %s, but %s is checked out from %s", rr.root, repo, dir, remote)
}
}
}

View file

@ -235,7 +235,26 @@ listed in the GOPATH environment variable (see 'go help gopath').
The go command attempts to download the version of the
package appropriate for the Go release being used.
Run 'go help install' for more.
Run 'go help get' for more.
Import path checking
When the custom import path feature described above redirects to a
known code hosting site, each of the resulting packages has two possible
import paths, using the custom domain or the known hosting site.
A package statement is said to have an "import comment" if it is immediately
followed (before the next newline) by a comment of one of these two forms:
package math // import "path"
package math /* import "path" */
The go command will refuse to install a package with an import comment
unless it is being referred to by that import path. In this way, import comments
let package authors make sure the custom import path is used and not a
direct path to the underlying code hosting site.
See https://golang.org/s/go14customimport for details.
`,
}

View file

@ -4,6 +4,6 @@
# license that can be found in the LICENSE file.
go install # So the next line will produce updated documentation.
go help documentation > doc.go
go help documentation | sed 's; \*/; * /;' >doc.go
gofmt -w doc.go

View file

@ -49,7 +49,11 @@ datcmp(LSym *s1, LSym *s2)
{
if(s1->type != s2->type)
return (int)s1->type - (int)s2->type;
if(s1->size != s2->size) {
// For ppc64, we want to interleave the .got and .toc sections
// from input files. Both are type SELFGOT, so in that case
// fall through to the name comparison (conveniently, .got
// sorts before .toc).
if(s1->type != SELFGOT && s1->size != s2->size) {
if(s1->size < s2->size)
return -1;
return +1;
@ -132,6 +136,7 @@ relocsym(LSym *s)
{
Reloc *r;
LSym *rs;
int16 i16;
int32 i, off, siz, fl;
vlong o;
uchar *cast;
@ -308,6 +313,8 @@ relocsym(LSym *s)
o = r->sym->size + r->add;
break;
}
if(r->variant != RV_NONE)
o = archrelocvariant(r, s, o);
//print("relocate %s %#llux (%#llux+%#llux, size %d) => %s %#llux +%#llx [%llx]\n", s->name, (uvlong)(s->value+off), (uvlong)s->value, (uvlong)r->off, r->siz, r->sym ? r->sym->name : "<nil>", (uvlong)symaddr(r->sym), (vlong)r->add, (vlong)o);
switch(siz) {
default:
@ -317,6 +324,14 @@ relocsym(LSym *s)
// TODO(rsc): Remove.
s->p[off] = (int8)o;
break;
case 2:
if(o != (int16)o)
diag("relocation address is too big: %#llx", o);
i16 = o;
cast = (uchar*)&i16;
for(i=0; i<2; i++)
s->p[off+i] = cast[inuxi2[i]];
break;
case 4:
if(r->type == R_PCREL || r->type == R_CALL) {
if(o != (int32)o)
@ -909,7 +924,7 @@ dodata(void)
vlong datsize;
Section *sect;
Segment *segro;
LSym *s, *last, **l;
LSym *s, *last, **l, *toc;
LSym *gcdata, *gcbss;
ProgGen gen;
@ -983,7 +998,7 @@ dodata(void)
/* writable ELF sections */
datsize = 0;
for(; s != nil && s->type < SNOPTRDATA; s = s->next) {
for(; s != nil && s->type < SELFGOT; s = s->next) {
sect = addsection(&segdata, s->name, 06);
sect->align = symalign(s);
datsize = rnd(datsize, sect->align);
@ -995,6 +1010,33 @@ dodata(void)
sect->len = datsize - sect->vaddr;
}
/* .got (and .toc on ppc64) */
if(s->type == SELFGOT) {
sect = addsection(&segdata, ".got", 06);
sect->align = maxalign(s, SELFGOT);
datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
for(; s != nil && s->type == SELFGOT; s = s->next) {
datsize = aligndatsize(datsize, s);
s->sect = sect;
s->type = SDATA;
s->value = datsize - sect->vaddr;
// Resolve .TOC. symbol for this object file (ppc64)
toc = linkrlookup(ctxt, ".TOC.", s->version);
if(toc != nil) {
toc->sect = sect;
toc->outer = s;
toc->sub = s->sub;
s->sub = toc;
toc->value = 0x8000;
}
growdatsize(&datsize, s);
}
sect->len = datsize - sect->vaddr;
}
/* pointer-free data */
sect = addsection(&segdata, ".noptrdata", 06);
sect->align = maxalign(s, SINITARR-1);
@ -1273,6 +1315,9 @@ textaddress(void)
sub->value += va;
if(sym->size == 0 && sym->sub != S)
ctxt->cursym = sym;
if(sym->size < MINFUNC)
va += MINFUNC; // spacing required for findfunctab
else
va += sym->size;
}
sect->len = va - sect->vaddr;

View file

@ -306,12 +306,18 @@ elfwritedynent(LSym *s, int tag, uint64 val)
void
elfwritedynentsym(LSym *s, int tag, LSym *t)
{
elfwritedynentsymplus(s, tag, t, 0);
}
void
elfwritedynentsymplus(LSym *s, int tag, LSym *t, vlong add)
{
if(elf64)
adduint64(ctxt, s, tag);
else
adduint32(ctxt, s, tag);
addaddr(ctxt, s, t);
addaddrplus(ctxt, s, t, add);
}
void
@ -977,6 +983,8 @@ doelf(void)
addstring(shstrtab, ".interp");
addstring(shstrtab, ".hash");
addstring(shstrtab, ".got");
if(thechar == '9')
addstring(shstrtab, ".glink");
addstring(shstrtab, ".got.plt");
addstring(shstrtab, ".dynamic");
addstring(shstrtab, ".dynsym");
@ -1020,7 +1028,14 @@ doelf(void)
/* global offset table */
s = linklookup(ctxt, ".got", 0);
s->reachable = 1;
s->type = SELFSECT; // writable
s->type = SELFGOT; // writable
/* ppc64 glink resolver */
if(thechar == '9') {
s = linklookup(ctxt, ".glink", 0);
s->reachable = 1;
s->type = SELFRXSECT;
}
/* hash */
s = linklookup(ctxt, ".hash", 0);
@ -1033,6 +1048,11 @@ doelf(void)
s = linklookup(ctxt, ".plt", 0);
s->reachable = 1;
if(thechar == '9')
// In the ppc64 ABI, .plt is a data section
// written by the dynamic linker.
s->type = SELFSECT;
else
s->type = SELFRXSECT;
elfsetupplt();
@ -1080,8 +1100,14 @@ doelf(void)
if(rpath)
elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath));
if(thechar == '9')
elfwritedynentsym(s, DT_PLTGOT, linklookup(ctxt, ".plt", 0));
else
elfwritedynentsym(s, DT_PLTGOT, linklookup(ctxt, ".got.plt", 0));
if(thechar == '9')
elfwritedynent(s, DT_PPC64_OPT, 0);
// Solaris dynamic linker can't handle an empty .rela.plt if
// DT_JMPREL is emitted so we have to defer generation of DT_PLTREL,
// DT_PLTRELSZ, and DT_JMPREL dynamic entries until after we know the
@ -1309,6 +1335,7 @@ asmbelf(vlong symo)
switch(eh->machine) {
case EM_X86_64:
case EM_PPC64:
sh = elfshname(".rela.plt");
sh->type = SHT_RELA;
sh->flags = SHF_ALLOC;
@ -1345,16 +1372,33 @@ asmbelf(vlong symo)
break;
}
if(eh->machine == EM_PPC64) {
sh = elfshname(".glink");
sh->type = SHT_PROGBITS;
sh->flags = SHF_ALLOC+SHF_EXECINSTR;
sh->addralign = 4;
shsym(sh, linklookup(ctxt, ".glink", 0));
}
sh = elfshname(".plt");
sh->type = SHT_PROGBITS;
sh->flags = SHF_ALLOC+SHF_EXECINSTR;
if(eh->machine == EM_X86_64)
sh->entsize = 16;
else
else if(eh->machine == EM_PPC64) {
// On ppc64, this is just a table of addresses
// filled by the dynamic linker
sh->type = SHT_NOBITS;
sh->flags = SHF_ALLOC+SHF_WRITE;
sh->entsize = 8;
} else
sh->entsize = 4;
sh->addralign = 4;
sh->addralign = sh->entsize;
shsym(sh, linklookup(ctxt, ".plt", 0));
// On ppc64, .got comes from the input files, so don't
// create it here, and .got.plt is not used.
if(eh->machine != EM_PPC64) {
sh = elfshname(".got");
sh->type = SHT_PROGBITS;
sh->flags = SHF_ALLOC+SHF_WRITE;
@ -1368,6 +1412,7 @@ asmbelf(vlong symo)
sh->entsize = RegSize;
sh->addralign = RegSize;
shsym(sh, linklookup(ctxt, ".got.plt", 0));
}
sh = elfshname(".hash");
sh->type = SHT_HASH;

View file

@ -317,6 +317,9 @@ typedef struct {
#define DT_VERNEEDNUM 0x6fffffff
#define DT_VERSYM 0x6ffffff0
#define DT_PPC64_GLINK (DT_LOPROC + 0)
#define DT_PPC64_OPT (DT_LOPROC + 3)
/* Values for DT_FLAGS */
/* Indicates that the object being loaded may make reference to
the $ORIGIN substitution string */
@ -700,6 +703,18 @@ typedef struct {
/* Count of defined relocation types. */
#define R_PPC_EMB_COUNT (R_PPC_EMB_RELSDA - R_PPC_EMB_NADDR32 + 1)
#define R_PPC64_REL24 R_PPC_REL24
#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT
#define R_PPC64_ADDR64 38
#define R_PPC64_TOC16 47
#define R_PPC64_TOC16_LO 48
#define R_PPC64_TOC16_HI 49
#define R_PPC64_TOC16_HA 50
#define R_PPC64_TOC16_DS 63
#define R_PPC64_TOC16_LO_DS 64
#define R_PPC64_REL16_LO 250
#define R_PPC64_REL16_HI 251
#define R_PPC64_REL16_HA 252
#define R_SPARC_NONE 0
#define R_SPARC_8 1
@ -970,6 +985,7 @@ uint32 elfwritephdrs(void);
uint32 elfwriteshdrs(void);
void elfwritedynent(LSym*, int, uint64);
void elfwritedynentsym(LSym*, int, LSym*);
void elfwritedynentsymplus(LSym*, int, LSym*, vlong);
void elfwritedynentsymsize(LSym*, int, LSym*);
uint32 elfhash(uchar*);
uint64 startelf(void);

View file

@ -327,7 +327,7 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
int32 base;
uint64 add, info;
char *name;
int i, j, rela, is64, n;
int i, j, rela, is64, n, flag;
uchar hdrbuf[64];
uchar *p;
ElfHdrBytes *hdr;
@ -554,6 +554,9 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
s->type = STEXT;
break;
}
if(strcmp(sect->name, ".got") == 0 ||
strcmp(sect->name, ".toc") == 0)
s->type = SELFGOT;
if(sect->type == ElfSectProgbits) {
s->p = sect->base;
s->np = sect->size;
@ -616,6 +619,13 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
diag("%s: duplicate definition of %s", pn, s->name);
s->external = 1;
}
if(obj->machine == ElfMachPower64) {
flag = sym.other >> 5;
if(2 <= flag && flag <= 6)
s->localentry = 1 << (flag - 2);
else if(flag == 7)
diag("%s: invalid sym.other 0x%x for %s", pn, sym.other, s->name);
}
}
// Sort outer lists by address, adding to textp.
@ -714,6 +724,8 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
else
diag("invalid rela size %d", rp->siz);
}
if(rp->siz == 2)
rp->add = (int16)rp->add;
if(rp->siz == 4)
rp->add = (int32)rp->add;
//print("rel %s %d %d %s %#llx\n", sect->sym->name, rp->type, rp->siz, rp->sym->name, rp->add);
@ -803,6 +815,10 @@ readsym(ElfObj *obj, int i, ElfSym *sym, int needSym)
s = nil;
if(strcmp(sym->name, "_GLOBAL_OFFSET_TABLE_") == 0)
sym->name = ".got";
if(strcmp(sym->name, ".TOC.") == 0)
// Magic symbol on ppc64. Will be set to this object
// file's .got+0x8000.
sym->bind = ElfSymBindLocal;
switch(sym->type) {
case ElfSymTypeSection:
s = obj->sect[sym->shndx].sym;
@ -833,6 +849,15 @@ readsym(ElfObj *obj, int i, ElfSym *sym, int needSym)
// symbols, ignore these
break;
}
if(strcmp(sym->name, ".TOC.") == 0) {
// We need to be able to look this up,
// so put it in the hash table.
if(needSym) {
s = linklookup(ctxt, sym->name, ctxt->version);
s->type |= SHIDDEN;
}
break;
}
if(needSym) {
// local names and hidden visiblity global names are unique
// and should only reference by its index, not name, so we
@ -883,6 +908,17 @@ reltype(char *pn, int elftype, uchar *siz)
switch(R(thechar, elftype)) {
default:
diag("%s: unknown relocation type %d; compiled without -fpic?", pn, elftype);
case R('9', R_PPC64_TOC16):
case R('9', R_PPC64_TOC16_LO):
case R('9', R_PPC64_TOC16_HI):
case R('9', R_PPC64_TOC16_HA):
case R('9', R_PPC64_TOC16_DS):
case R('9', R_PPC64_TOC16_LO_DS):
case R('9', R_PPC64_REL16_LO):
case R('9', R_PPC64_REL16_HI):
case R('9', R_PPC64_REL16_HA):
*siz = 2;
break;
case R('5', R_ARM_ABS32):
case R('5', R_ARM_GOT32):
case R('5', R_ARM_PLT32):
@ -904,9 +940,11 @@ reltype(char *pn, int elftype, uchar *siz)
case R('8', R_386_PLT32):
case R('8', R_386_GOTOFF):
case R('8', R_386_GOTPC):
case R('9', R_PPC64_REL24):
*siz = 4;
break;
case R('6', R_X86_64_64):
case R('9', R_PPC64_ADDR64):
*siz = 8;
break;
}

View file

@ -35,6 +35,7 @@
enum {
MAXIO = 8192,
MINFUNC = 16, // minimum size for a function
};
typedef struct Segment Segment;
@ -260,6 +261,7 @@ void patch(void);
int pathchar(void);
void pcln(void);
void pclntab(void);
void findfunctab(void);
void putelfsectionsym(LSym* s, int shndx);
void putelfsymshndx(vlong sympos, int shndx);
void putsymb(LSym *s, char *name, int t, vlong v, vlong size, int ver, LSym *typ);

View file

@ -242,3 +242,58 @@ pclntab(void)
if(debug['v'])
Bprint(&bso, "%5.2f pclntab=%lld bytes, funcdata total %lld bytes\n", cputime(), (vlong)ftab->size, (vlong)funcdata_bytes);
}
enum {
BUCKETSIZE = 256*MINFUNC,
SUBBUCKETS = 16,
};
// findfunctab generates a lookup table to quickly find the containing
// function for a pc. See src/runtime/symtab.go:findfunc for details.
void
findfunctab(void)
{
LSym *t, *s;
int32 idx, bidx, i, j, nbuckets;
vlong min, max;
t = linklookup(ctxt, "runtime.findfunctab", 0);
t->type = SRODATA;
t->reachable = 1;
// find min and max address
min = ctxt->textp->value;
max = 0;
for(s = ctxt->textp; s != nil; s = s->next)
max = s->value + s->size;
// allocate table
nbuckets = (max-min+BUCKETSIZE-1)/BUCKETSIZE;
symgrow(ctxt, t, nbuckets * (4+SUBBUCKETS));
// fill in table
s = ctxt->textp;
idx = 0;
for(i = 0; i < nbuckets; i++) {
// Find first function which overlaps this bucket.
// Only do leaf symbols; skip symbols which are just containers (sub != nil but outer == nil).
while(s != nil && (s->value+s->size <= min + i * BUCKETSIZE || s->sub != nil && s->outer == nil)) {
s = s->next;
idx++;
}
// record this function in bucket header
setuint32(ctxt, t, i*(4+SUBBUCKETS), idx);
bidx = idx;
// compute SUBBUCKETS deltas
for(j = 0; j < SUBBUCKETS; j++) {
while(s != nil && (s->value+s->size <= min + i * BUCKETSIZE + j * (BUCKETSIZE/SUBBUCKETS) || s->sub != nil && s->outer == nil)) {
s = s->next;
idx++;
}
if(idx - bidx >= 256)
diag("too many functions in a findfunc bucket! %d %s", idx-bidx, s->name);
setuint8(ctxt, t, i*(4+SUBBUCKETS)+4+j, idx-bidx);
}
}
}

View file

@ -187,6 +187,7 @@ main(int argc, char *argv[])
gentext(); // trampolines, call stubs, etc.
textaddress();
pclntab();
findfunctab();
symtab();
dodata();
address();

View file

@ -45,6 +45,7 @@ type CurveParams struct {
B *big.Int // the constant of the curve equation
Gx, Gy *big.Int // (x,y) of the base point
BitSize int // the size of the underlying field
Name string // the canonical name of the curve
}
func (curve *CurveParams) Params() *CurveParams {
@ -334,7 +335,7 @@ func initAll() {
func initP384() {
// See FIPS 186-3, section D.2.4
p384 = new(CurveParams)
p384 = &CurveParams{Name: "P-384"}
p384.P, _ = new(big.Int).SetString("39402006196394479212279040100143613805079739270465446667948293404245721771496870329047266088258938001861606973112319", 10)
p384.N, _ = new(big.Int).SetString("39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942643", 10)
p384.B, _ = new(big.Int).SetString("b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef", 16)
@ -345,7 +346,7 @@ func initP384() {
func initP521() {
// See FIPS 186-3, section D.2.5
p521 = new(CurveParams)
p521 = &CurveParams{Name: "P-521"}
p521.P, _ = new(big.Int).SetString("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", 10)
p521.N, _ = new(big.Int).SetString("6864797660130609714981900799081393217269435300143305409394463459185543183397655394245057746333217197532963996371363321113864768612440380340372808892707005449", 10)
p521.B, _ = new(big.Int).SetString("051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00", 16)

View file

@ -22,7 +22,7 @@ type p224Curve struct {
func initP224() {
// See FIPS 186-3, section D.2.2
p224.CurveParams = new(CurveParams)
p224.CurveParams = &CurveParams{Name: "P-224"}
p224.P, _ = new(big.Int).SetString("26959946667150639794667015087019630673557916260026308143510066298881", 10)
p224.N, _ = new(big.Int).SetString("26959946667150639794667015087019625940457807714424391721682722368061", 10)
p224.B, _ = new(big.Int).SetString("b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4", 16)

View file

@ -23,7 +23,7 @@ var (
func initP256() {
// See FIPS 186-3, section D.2.3
p256.CurveParams = new(CurveParams)
p256.CurveParams = &CurveParams{Name: "P-256"}
p256.P, _ = new(big.Int).SetString("115792089210356248762697446949407573530086143415290314195533631308867097853951", 10)
p256.N, _ = new(big.Int).SetString("115792089210356248762697446949407573529996955224135760342422259061068512044369", 10)
p256.B, _ = new(big.Int).SetString("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16)

View file

@ -167,22 +167,24 @@ func Dial(network, addr string, config *Config) (*Conn, error) {
// LoadX509KeyPair reads and parses a public/private key pair from a pair of
// files. The files must contain PEM encoded data.
func LoadX509KeyPair(certFile, keyFile string) (cert Certificate, err error) {
func LoadX509KeyPair(certFile, keyFile string) (Certificate, error) {
certPEMBlock, err := ioutil.ReadFile(certFile)
if err != nil {
return
return Certificate{}, err
}
keyPEMBlock, err := ioutil.ReadFile(keyFile)
if err != nil {
return
return Certificate{}, err
}
return X509KeyPair(certPEMBlock, keyPEMBlock)
}
// X509KeyPair parses a public/private key pair from a pair of
// PEM encoded data.
func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err error) {
func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) {
var cert Certificate
var certDERBlock *pem.Block
fail := func(err error) (Certificate, error) { return Certificate{}, err }
for {
certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
if certDERBlock == nil {
@ -194,62 +196,56 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err error)
}
if len(cert.Certificate) == 0 {
err = errors.New("crypto/tls: failed to parse certificate PEM data")
return
return fail(errors.New("crypto/tls: failed to parse certificate PEM data"))
}
var keyDERBlock *pem.Block
for {
keyDERBlock, keyPEMBlock = pem.Decode(keyPEMBlock)
if keyDERBlock == nil {
err = errors.New("crypto/tls: failed to parse key PEM data")
return
return fail(errors.New("crypto/tls: failed to parse key PEM data"))
}
if keyDERBlock.Type == "PRIVATE KEY" || strings.HasSuffix(keyDERBlock.Type, " PRIVATE KEY") {
break
}
}
var err error
cert.PrivateKey, err = parsePrivateKey(keyDERBlock.Bytes)
if err != nil {
return
return fail(err)
}
// We don't need to parse the public key for TLS, but we so do anyway
// to check that it looks sane and matches the private key.
x509Cert, err := x509.ParseCertificate(cert.Certificate[0])
if err != nil {
return
return fail(err)
}
switch pub := x509Cert.PublicKey.(type) {
case *rsa.PublicKey:
priv, ok := cert.PrivateKey.(*rsa.PrivateKey)
if !ok {
err = errors.New("crypto/tls: private key type does not match public key type")
return
return fail(errors.New("crypto/tls: private key type does not match public key type"))
}
if pub.N.Cmp(priv.N) != 0 {
err = errors.New("crypto/tls: private key does not match public key")
return
return fail(errors.New("crypto/tls: private key does not match public key"))
}
case *ecdsa.PublicKey:
priv, ok := cert.PrivateKey.(*ecdsa.PrivateKey)
if !ok {
err = errors.New("crypto/tls: private key type does not match public key type")
return
return fail(errors.New("crypto/tls: private key type does not match public key type"))
}
if pub.X.Cmp(priv.X) != 0 || pub.Y.Cmp(priv.Y) != 0 {
err = errors.New("crypto/tls: private key does not match public key")
return
return fail(errors.New("crypto/tls: private key does not match public key"))
}
default:
err = errors.New("crypto/tls: unknown public key algorithm")
return
return fail(errors.New("crypto/tls: unknown public key algorithm"))
}
return
return cert, nil
}
// Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates

View file

@ -160,7 +160,7 @@ func (certList *CertificateList) HasExpired(now time.Time) bool {
// 5280, section 5.1.
type TBSCertificateList struct {
Raw asn1.RawContent
Version int `asn1:"optional,default:2"`
Version int `asn1:"optional,default:1"`
Signature AlgorithmIdentifier
Issuer RDNSequence
ThisUpdate time.Time

View file

@ -7,4 +7,5 @@ package x509
// Possible certificate files; stop after finding one.
var certFiles = []string{
"/etc/certs/ca-certificates.crt", // Solaris 11.2+
"/etc/ssl/certs/ca-certificates.crt", // Joyent SmartOS
}

View file

@ -1377,8 +1377,11 @@ func signingParamsForPrivateKey(priv interface{}, requestedSigAlgo SignatureAlgo
switch priv := priv.(type) {
case *rsa.PrivateKey:
pubType = RSA
sigAlgo.Algorithm = oidSignatureSHA256WithRSA
hashFunc = crypto.SHA256
sigAlgo.Algorithm = oidSignatureSHA256WithRSA
sigAlgo.Parameters = asn1.RawValue{
Tag: 5,
}
case *ecdsa.PrivateKey:
pubType = ECDSA
@ -1572,7 +1575,7 @@ func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts [
return nil, errors.New("x509: non-RSA private keys not supported")
}
tbsCertList := pkix.TBSCertificateList{
Version: 2,
Version: 1,
Signature: pkix.AlgorithmIdentifier{
Algorithm: oidSignatureSHA1WithRSA,
},

View file

@ -267,6 +267,7 @@ var cgoEnabled = map[string]bool{
"linux/386": true,
"linux/amd64": true,
"linux/arm": true,
"linux/ppc64le": true,
"android/386": true,
"android/amd64": true,
"android/arm": true,
@ -1072,9 +1073,6 @@ func (ctxt *Context) shouldBuild(content []byte, allTags map[string]bool) bool {
// saveCgo saves the information from the #cgo lines in the import "C" comment.
// These lines set CFLAGS, CPPFLAGS, CXXFLAGS and LDFLAGS and pkg-config directives
// that affect the way cgo's C code is built.
//
// TODO(rsc): This duplicates code in cgo.
// Once the dust settles, remove this code from cgo.
func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup) error {
text := cg.Text()
for _, line := range strings.Split(text, "\n") {

View file

@ -139,7 +139,19 @@ var clipTests = []clipTest{
image.Pt(20, 0),
image.Pt(20, 0),
},
// TODO(nigeltao): write more tests.
{
"clip sr and mr",
image.Rect(0, 0, 100, 100),
image.Rect(0, 0, 100, 100),
image.Rect(23, 23, 55, 86),
image.Rect(44, 44, 87, 58),
image.Pt(10, 10),
image.Pt(11, 11),
false,
image.Rect(33, 33, 45, 47),
image.Pt(43, 43),
image.Pt(44, 44),
},
}
func TestClip(t *testing.T) {
@ -149,12 +161,12 @@ func TestClip(t *testing.T) {
for _, c := range clipTests {
dst := dst0.SubImage(c.dr).(*image.RGBA)
src := src0.SubImage(c.sr).(*image.RGBA)
var mask image.Image
if !c.nilMask {
mask = mask0.SubImage(c.mr)
}
r, sp, mp := c.r, c.sp, c.mp
clip(dst, &r, src, &sp, mask, &mp)
if c.nilMask {
clip(dst, &r, src, &sp, nil, nil)
} else {
clip(dst, &r, src, &sp, mask0.SubImage(c.mr), &mp)
}
// Check that the actual results equal the expected results.
if !c.r0.Eq(r) {
@ -191,13 +203,3 @@ func TestClip(t *testing.T) {
}
}
}
func TestClipWithNilMP(t *testing.T) {
src := image.NewRGBA(image.Rect(0, 0, 100, 100))
// dst must be smaller than src for clipping to occur
dst := image.NewRGBA(image.Rect(50, 50, 100, 100))
r := image.Rect(0, 0, 100, 100)
sp := image.ZP
// issue 9177: floydSteinberg.Draw passes nil for mp, which used to cause clip to panic
clip(dst, &r, src, &sp, nil, nil)
}

View file

@ -81,11 +81,11 @@ func clip(dst Image, r *image.Rectangle, src image.Image, sp *image.Point, mask
if dx == 0 && dy == 0 {
return
}
(*sp).X += dx
(*sp).Y += dy
sp.X += dx
sp.Y += dy
if mp != nil {
(*mp).X += dx
(*mp).Y += dy
mp.X += dx
mp.Y += dy
}
}

View file

@ -329,25 +329,25 @@ static struct {
static int checkpool(Link*, Prog*, int);
static int flushpool(Link*, Prog*, int, int);
static void addpool(Link*, Prog*, Addr*);
static void asmout(Link*, Prog*, Optab*, int32*);
static int asmoutnacl(Link*, int32, Prog*, Optab*, int32 *);
static void asmout(Link*, Prog*, Optab*, uint32*);
static int asmoutnacl(Link*, int32, Prog*, Optab*, uint32*);
static Optab* oplook(Link*, Prog*);
static int32 oprrr(Link*, int, int);
static int32 olr(Link*, int32, int, int, int);
static int32 olhr(Link*, int32, int, int, int);
static int32 olrr(Link*, int, int, int, int);
static int32 olhrr(Link*, int, int, int, int);
static int32 osr(Link*, int, int, int32, int, int);
static int32 oshr(Link*, int, int32, int, int);
static int32 ofsr(Link*, int, int, int32, int, int, Prog*);
static int32 osrr(Link*, int, int, int, int);
static int32 oshrr(Link*, int, int, int, int);
static int32 omvl(Link*, Prog*, Addr*, int);
static uint32 oprrr(Link*, int, int);
static uint32 olr(Link*, int32, int, int, int);
static uint32 olhr(Link*, int32, int, int, int);
static uint32 olrr(Link*, int, int, int, int);
static uint32 olhrr(Link*, int, int, int, int);
static uint32 osr(Link*, int, int, int32, int, int);
static uint32 oshr(Link*, int, int32, int, int);
static uint32 ofsr(Link*, int, int, int32, int, int, Prog*);
static uint32 osrr(Link*, int, int, int, int);
static uint32 oshrr(Link*, int, int, int, int);
static uint32 omvl(Link*, Prog*, Addr*, int);
static int32 immaddr(int32);
static int aclass(Link*, Addr*);
static int32 immrot(uint32);
static int32 immaddr(int32);
static int32 opbra(Link*, int, int);
static uint32 opbra(Link*, int, int);
static Oprang oprange[ALAST];
static uchar xcmp[C_GOK+1][C_GOK+1];
@ -405,7 +405,7 @@ static void buildop(Link*);
// In rare cases, asmoutnacl might split p into two instructions.
// origPC is the PC for this Prog (no padding is taken into account).
static int
asmoutnacl(Link *ctxt, int32 origPC, Prog *p, Optab *o, int32 *out)
asmoutnacl(Link *ctxt, int32 origPC, Prog *p, Optab *o, uint32 *out)
{
int size, reg;
Prog *q;
@ -642,7 +642,8 @@ span5(Link *ctxt, LSym *cursym)
Prog *p, *op;
Optab *o;
int m, bflag, i, v, times;
int32 c, opc, out[6+3];
int32 c, opc;
uint32 out[6+3];
uchar *bp;
p = cursym->text;
@ -682,7 +683,10 @@ span5(Link *ctxt, LSym *cursym)
}
// must check literal pool here in case p generates many instructions
if(ctxt->blitrl){
if(checkpool(ctxt, op, p->as == ACASE ? casesz(ctxt, p) : m)) {
i = m;
if(p->as == ACASE)
i = casesz(ctxt, p);
if(checkpool(ctxt, op, i)) {
p = op;
continue;
}
@ -1070,8 +1074,11 @@ aclass(Link *ctxt, Addr *a)
ctxt->instoffset = ctxt->autosize + a->offset;
t = immaddr(ctxt->instoffset);
if(t){
if(immhalf(ctxt->instoffset))
return immfloat(t) ? C_HFAUTO : C_HAUTO;
if(immhalf(ctxt->instoffset)) {
if(immfloat(t))
return C_HFAUTO;
return C_HAUTO;
}
if(immfloat(t))
return C_FAUTO;
return C_SAUTO;
@ -1082,8 +1089,11 @@ aclass(Link *ctxt, Addr *a)
ctxt->instoffset = ctxt->autosize + a->offset + 4L;
t = immaddr(ctxt->instoffset);
if(t){
if(immhalf(ctxt->instoffset))
return immfloat(t) ? C_HFAUTO : C_HAUTO;
if(immhalf(ctxt->instoffset)) {
if(immfloat(t))
return C_HFAUTO;
return C_HAUTO;
}
if(immfloat(t))
return C_FAUTO;
return C_SAUTO;
@ -1093,8 +1103,11 @@ aclass(Link *ctxt, Addr *a)
ctxt->instoffset = a->offset;
t = immaddr(ctxt->instoffset);
if(t) {
if(immhalf(ctxt->instoffset)) /* n.b. that it will also satisfy immrot */
return immfloat(t) ? C_HFOREG : C_HOREG;
if(immhalf(ctxt->instoffset)) { /* n.b. that it will also satisfy immrot */
if(immfloat(t))
return C_HFOREG;
return C_HOREG;
}
if(immfloat(t))
return C_FOREG; /* n.b. that it will also satisfy immrot */
t = immrot(ctxt->instoffset);
@ -1488,12 +1501,13 @@ buildop(Link *ctxt)
}
}
static int32 mov(Link*, Prog*);
static uint32 mov(Link*, Prog*);
static void
asmout(Link *ctxt, Prog *p, Optab *o, int32 *out)
asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
{
int32 o1, o2, o3, o4, o5, o6, v;
uint32 o1, o2, o3, o4, o5, o6;
int32 v;
int r, rf, rt, rt2;
Reloc *rel;
@ -2315,10 +2329,10 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
return;
}
static int32
static uint32
mov(Link *ctxt, Prog *p)
{
int32 o1;
uint32 o1;
int rt, r;
aclass(ctxt, &p->from);
@ -2336,10 +2350,10 @@ mov(Link *ctxt, Prog *p)
return o1;
}
static int32
static uint32
oprrr(Link *ctxt, int a, int sc)
{
int32 o;
uint32 o;
o = (sc & C_SCOND) << 28;
if(sc & C_SBIT)
@ -2450,7 +2464,7 @@ oprrr(Link *ctxt, int a, int sc)
return 0;
}
static int32
static uint32
opbra(Link *ctxt, int a, int sc)
{
@ -2485,10 +2499,10 @@ opbra(Link *ctxt, int a, int sc)
return 0;
}
static int32
static uint32
olr(Link *ctxt, int32 v, int b, int r, int sc)
{
int32 o;
uint32 o;
if(sc & C_SBIT)
ctxt->diag(".nil on LDR/STR instruction");
@ -2514,10 +2528,10 @@ olr(Link *ctxt, int32 v, int b, int r, int sc)
return o;
}
static int32
static uint32
olhr(Link *ctxt, int32 v, int b, int r, int sc)
{
int32 o;
uint32 o;
if(sc & C_SBIT)
ctxt->diag(".nil on LDRH/STRH instruction");
@ -2539,10 +2553,10 @@ olhr(Link *ctxt, int32 v, int b, int r, int sc)
return o;
}
static int32
static uint32
osr(Link *ctxt, int a, int r, int32 v, int b, int sc)
{
int32 o;
uint32 o;
o = olr(ctxt, v, b, r, sc) ^ (1<<20);
if(a != AMOVW)
@ -2550,46 +2564,46 @@ osr(Link *ctxt, int a, int r, int32 v, int b, int sc)
return o;
}
static int32
static uint32
oshr(Link *ctxt, int r, int32 v, int b, int sc)
{
int32 o;
uint32 o;
o = olhr(ctxt, v, b, r, sc) ^ (1<<20);
return o;
}
static int32
static uint32
osrr(Link *ctxt, int r, int i, int b, int sc)
{
return olr(ctxt, i, b, r, sc) ^ ((1<<25) | (1<<20));
}
static int32
static uint32
oshrr(Link *ctxt, int r, int i, int b, int sc)
{
return olhr(ctxt, i, b, r, sc) ^ ((1<<22) | (1<<20));
}
static int32
static uint32
olrr(Link *ctxt, int i, int b, int r, int sc)
{
return olr(ctxt, i, b, r, sc) ^ (1<<25);
}
static int32
static uint32
olhrr(Link *ctxt, int i, int b, int r, int sc)
{
return olhr(ctxt, i, b, r, sc) ^ (1<<22);
}
static int32
static uint32
ofsr(Link *ctxt, int a, int r, int32 v, int b, int sc, Prog *p)
{
int32 o;
uint32 o;
if(sc & C_SBIT)
ctxt->diag(".nil on FLDR/FSTR instruction");
@ -2623,10 +2637,11 @@ ofsr(Link *ctxt, int a, int r, int32 v, int b, int sc, Prog *p)
return o;
}
static int32
static uint32
omvl(Link *ctxt, Prog *p, Addr *a, int dr)
{
int32 v, o1;
int32 v;
uint32 o1;
if(!p->pcond) {
aclass(ctxt, a);
v = immrot(~ctxt->instoffset);
@ -2659,7 +2674,7 @@ chipfloat5(Link *ctxt, float64 e)
{
int n;
ulong h1;
int32 l, h;
uint32 l, h;
uint64 ei;
// We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
@ -2667,8 +2682,8 @@ chipfloat5(Link *ctxt, float64 e)
goto no;
memmove(&ei, &e, 8);
l = (int32)ei;
h = (int32)(ei>>32);
l = (uint32)ei;
h = (uint32)(ei>>32);
if(l != 0 || (h&0xffff) != 0)
goto no;

View file

@ -454,7 +454,7 @@ static int isint32(vlong);
static int isuint32(uvlong);
static int aclass(Link*, Addr*);
static Optab* oplook(Link*, Prog*);
static void asmout(Link*, Prog*, Optab*, int32*);
static void asmout(Link*, Prog*, Optab*, uint32*);
static vlong vregoff(Link*, Addr*);
static int32 regoff(Link*, Addr*);
static int32 oprrr(Link*, int);
@ -468,13 +468,16 @@ static void maskgen(Link*, Prog*, uchar*, uint32);
static int getmask64(uchar*, uvlong);
static void maskgen64(Link*, Prog*, uchar*, uvlong);
static uint32 loadu32(int, vlong);
static void addaddrreloc(Link*, LSym*, int*, int*);
static void addaddrreloc(Link*, LSym*, uint32*, uint32*);
static struct
typedef struct Oprang Oprang;
struct Oprang
{
Optab* start;
Optab* stop;
} oprange[ALAST];
};
static Oprang oprange[ALAST];
static uchar xcmp[C_NCLASS][C_NCLASS];
@ -486,7 +489,8 @@ span9(Link *ctxt, LSym *cursym)
Optab *o;
int m, bflag;
vlong c, otxt;
int32 out[6], i, j;
uint32 out[6];
int32 i, j;
uchar *bp, *cast;
p = cursym->text;
@ -687,27 +691,7 @@ aclass(Link *ctxt, Addr *a)
return C_LACON;
return C_DACON;
}
consize:
if(ctxt->instoffset >= 0) {
if(ctxt->instoffset == 0)
return C_ZCON;
if(ctxt->instoffset <= 0x7fff)
return C_SCON;
if(ctxt->instoffset <= 0xffff)
return C_ANDCON;
if((ctxt->instoffset & 0xffff) == 0 && isuint32(ctxt->instoffset)) /* && (instoffset & (1<<31)) == 0) */
return C_UCON;
if(isint32(ctxt->instoffset) || isuint32(ctxt->instoffset))
return C_LCON;
return C_DCON;
}
if(ctxt->instoffset >= -0x8000)
return C_ADDCON;
if((ctxt->instoffset & 0xffff) == 0 && isint32(ctxt->instoffset))
return C_UCON;
if(isint32(ctxt->instoffset))
return C_LCON;
return C_DCON;
goto consize;
case D_EXTERN:
case D_STATIC:
@ -736,6 +720,28 @@ aclass(Link *ctxt, Addr *a)
}
return C_GOK;
consize:
if(ctxt->instoffset >= 0) {
if(ctxt->instoffset == 0)
return C_ZCON;
if(ctxt->instoffset <= 0x7fff)
return C_SCON;
if(ctxt->instoffset <= 0xffff)
return C_ANDCON;
if((ctxt->instoffset & 0xffff) == 0 && isuint32(ctxt->instoffset)) /* && (instoffset & (1<<31)) == 0) */
return C_UCON;
if(isint32(ctxt->instoffset) || isuint32(ctxt->instoffset))
return C_LCON;
return C_DCON;
}
if(ctxt->instoffset >= -0x8000)
return C_ADDCON;
if((ctxt->instoffset & 0xffff) == 0 && isint32(ctxt->instoffset))
return C_UCON;
if(isint32(ctxt->instoffset))
return C_LCON;
return C_DCON;
case D_BRANCH:
return C_SBRA;
}
@ -1271,61 +1277,120 @@ buildop(Link *ctxt)
}
}
#define OPVCC(o,xo,oe,rc) (((o)<<26)|((xo)<<1)|((oe)<<10)|((rc)&1))
#define OPCC(o,xo,rc) OPVCC((o),(xo),0,(rc))
#define OP(o,xo) OPVCC((o),(xo),0,0)
uint32
OPVCC(uint32 o, uint32 xo, uint32 oe, uint32 rc)
{
return o<<26 | xo<<1 | oe<<10 | rc&1;
}
uint32
OPCC(uint32 o, uint32 xo, uint32 rc)
{
return OPVCC(o, xo, 0, rc);
}
uint32
OP(uint32 o, uint32 xo)
{
return OPVCC(o, xo, 0, 0);
}
/* the order is dest, a/s, b/imm for both arithmetic and logical operations */
#define AOP_RRR(op,d,a,b) ((op)|(((d)&31L)<<21)|(((a)&31L)<<16)|(((b)&31L)<<11))
#define AOP_IRR(op,d,a,simm) ((op)|(((d)&31L)<<21)|(((a)&31L)<<16)|((simm)&0xFFFF))
#define LOP_RRR(op,a,s,b) ((op)|(((s)&31L)<<21)|(((a)&31L)<<16)|(((b)&31L)<<11))
#define LOP_IRR(op,a,s,uimm) ((op)|(((s)&31L)<<21)|(((a)&31L)<<16)|((uimm)&0xFFFF))
#define OP_BR(op,li,aa) ((op)|((li)&0x03FFFFFC)|((aa)<<1))
#define OP_BC(op,bo,bi,bd,aa) ((op)|(((bo)&0x1F)<<21)|(((bi)&0x1F)<<16)|((bd)&0xFFFC)|((aa)<<1))
#define OP_BCR(op,bo,bi) ((op)|(((bo)&0x1F)<<21)|(((bi)&0x1F)<<16))
#define OP_RLW(op,a,s,sh,mb,me) ((op)|(((s)&31L)<<21)|(((a)&31L)<<16)|(((sh)&31L)<<11)|\
(((mb)&31L)<<6)|(((me)&31L)<<1))
uint32
AOP_RRR(uint32 op, uint32 d, uint32 a, uint32 b)
{
return op | (d&31)<<21 | (a&31)<<16 | (b&31)<<11;
}
#define OP_ADD OPVCC(31,266,0,0)
#define OP_ADDI OPVCC(14,0,0,0)
#define OP_ADDIS OPVCC(15,0,0,0)
#define OP_ANDI OPVCC(28,0,0,0)
#define OP_EXTSB OPVCC(31,954,0,0)
#define OP_EXTSH OPVCC(31,922,0,0)
#define OP_EXTSW OPVCC(31,986,0,0)
#define OP_MCRF OPVCC(19,0,0,0)
#define OP_MCRFS OPVCC(63,64,0,0)
#define OP_MCRXR OPVCC(31,512,0,0)
#define OP_MFCR OPVCC(31,19,0,0)
#define OP_MFFS OPVCC(63,583,0,0)
#define OP_MFMSR OPVCC(31,83,0,0)
#define OP_MFSPR OPVCC(31,339,0,0)
#define OP_MFSR OPVCC(31,595,0,0)
#define OP_MFSRIN OPVCC(31,659,0,0)
#define OP_MTCRF OPVCC(31,144,0,0)
#define OP_MTFSF OPVCC(63,711,0,0)
#define OP_MTFSFI OPVCC(63,134,0,0)
#define OP_MTMSR OPVCC(31,146,0,0)
#define OP_MTMSRD OPVCC(31,178,0,0)
#define OP_MTSPR OPVCC(31,467,0,0)
#define OP_MTSR OPVCC(31,210,0,0)
#define OP_MTSRIN OPVCC(31,242,0,0)
#define OP_MULLW OPVCC(31,235,0,0)
#define OP_MULLD OPVCC(31,233,0,0)
#define OP_OR OPVCC(31,444,0,0)
#define OP_ORI OPVCC(24,0,0,0)
#define OP_ORIS OPVCC(25,0,0,0)
#define OP_RLWINM OPVCC(21,0,0,0)
#define OP_SUBF OPVCC(31,40,0,0)
#define OP_RLDIC OPVCC(30,4,0,0)
#define OP_RLDICR OPVCC(30,2,0,0)
#define OP_RLDICL OPVCC(30,0,0,0)
uint32
AOP_IRR(uint32 op, uint32 d, uint32 a, uint32 simm)
{
return op | (d&31)<<21 | (a&31)<<16 | (simm&0xFFFF);
}
#define oclass(v) ((v).class-1)
uint32
LOP_RRR(uint32 op, uint32 a, uint32 s, uint32 b)
{
return op | (s&31)<<21 | (a&31)<<16 | (b&31)<<11;
}
uint32
LOP_IRR(uint32 op, uint32 a, uint32 s, uint32 uimm)
{
return op | (s&31)<<21 | (a&31)<<16 | (uimm&0xFFFF);
}
uint32
OP_BR(uint32 op, uint32 li, uint32 aa)
{
return op | li&0x03FFFFFC | aa<<1;
}
uint32
OP_BC(uint32 op, uint32 bo, uint32 bi, uint32 bd, uint32 aa)
{
return op | (bo&0x1F)<<21 | (bi&0x1F)<<16 | bd&0xFFFC | aa<<1;
}
uint32
OP_BCR(uint32 op, uint32 bo, uint32 bi)
{
return op | (bo&0x1F)<<21 | (bi&0x1F)<<16;
}
uint32
OP_RLW(uint32 op, uint32 a, uint32 s, uint32 sh, uint32 mb, uint32 me)
{
return op | (s&31)<<21 | (a&31)<<16 | (sh&31)<<11 | (mb&31)<<6 | (me&31)<<1;
}
enum {
/* each rhs is OPVCC(_, _, _, _) */
OP_ADD = 31<<26 | 266<<1 | 0<<10 | 0,
OP_ADDI = 14<<26 | 0<<1 | 0<<10 | 0,
OP_ADDIS = 15<<26 | 0<<1 | 0<<10 | 0,
OP_ANDI = 28<<26 | 0<<1 | 0<<10 | 0,
OP_EXTSB = 31<<26 | 954<<1 | 0<<10 | 0,
OP_EXTSH = 31<<26 | 922<<1 | 0<<10 | 0,
OP_EXTSW = 31<<26 | 986<<1 | 0<<10 | 0,
OP_MCRF = 19<<26 | 0<<1 | 0<<10 | 0,
OP_MCRFS = 63<<26 | 64<<1 | 0<<10 | 0,
OP_MCRXR = 31<<26 | 512<<1 | 0<<10 | 0,
OP_MFCR = 31<<26 | 19<<1 | 0<<10 | 0,
OP_MFFS = 63<<26 | 583<<1 | 0<<10 | 0,
OP_MFMSR = 31<<26 | 83<<1 | 0<<10 | 0,
OP_MFSPR = 31<<26 | 339<<1 | 0<<10 | 0,
OP_MFSR = 31<<26 | 595<<1 | 0<<10 | 0,
OP_MFSRIN = 31<<26 | 659<<1 | 0<<10 | 0,
OP_MTCRF = 31<<26 | 144<<1 | 0<<10 | 0,
OP_MTFSF = 63<<26 | 711<<1 | 0<<10 | 0,
OP_MTFSFI = 63<<26 | 134<<1 | 0<<10 | 0,
OP_MTMSR = 31<<26 | 146<<1 | 0<<10 | 0,
OP_MTMSRD = 31<<26 | 178<<1 | 0<<10 | 0,
OP_MTSPR = 31<<26 | 467<<1 | 0<<10 | 0,
OP_MTSR = 31<<26 | 210<<1 | 0<<10 | 0,
OP_MTSRIN = 31<<26 | 242<<1 | 0<<10 | 0,
OP_MULLW = 31<<26 | 235<<1 | 0<<10 | 0,
OP_MULLD = 31<<26 | 233<<1 | 0<<10 | 0,
OP_OR = 31<<26 | 444<<1 | 0<<10 | 0,
OP_ORI = 24<<26 | 0<<1 | 0<<10 | 0,
OP_ORIS = 25<<26 | 0<<1 | 0<<10 | 0,
OP_RLWINM = 21<<26 | 0<<1 | 0<<10 | 0,
OP_SUBF = 31<<26 | 40<<1 | 0<<10 | 0,
OP_RLDIC = 30<<26 | 4<<1 | 0<<10 | 0,
OP_RLDICR = 30<<26 | 2<<1 | 0<<10 | 0,
OP_RLDICL = 30<<26 | 0<<1 | 0<<10 | 0,
};
int
oclass(Addr *a)
{
return a->class - 1;
}
// add R_ADDRPOWER relocation to symbol s for the two instructions o1 and o2.
static void
addaddrreloc(Link *ctxt, LSym *s, int *o1, int *o2)
addaddrreloc(Link *ctxt, LSym *s, uint32 *o1, uint32 *o2)
{
Reloc *rel;
@ -1346,7 +1411,7 @@ getmask(uchar *m, uint32 v)
int i;
m[0] = m[1] = 0;
if(v != ~0U && v & (1<<31) && v & 1){ /* MB > ME */
if(v != ~(uint32)0 && v & (1<<31) && v & 1){ /* MB > ME */
if(getmask(m, ~v)){
i = m[0]; m[0] = m[1]+1; m[1] = i-1;
return 1;
@ -1424,9 +1489,10 @@ high16adjusted(int32 d)
}
static void
asmout(Link *ctxt, Prog *p, Optab *o, int32 *out)
asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
{
int32 o1, o2, o3, o4, o5, v, t;
uint32 o1, o2, o3, o4, o5;
int32 v, t;
vlong d;
int r, a;
uchar mask[2];
@ -1694,7 +1760,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, int32 *out)
r = p->reg;
if(r == NREG)
r = 0;
switch(oclass(p->to)) {
switch(oclass(&p->to)) {
case C_CTR:
o1 = OPVCC(19, 528, 0, 0);
break;
@ -1902,7 +1968,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, int32 *out)
case 33: /* fabs [frb,]frd; fmr. frb,frd */
r = p->from.reg;
if(oclass(p->from) == C_NONE)
if(oclass(&p->from) == C_NONE)
r = p->to.reg;
o1 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, 0, r);
break;
@ -2034,7 +2100,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, int32 *out)
break;
case 54: /* mov msr,r1; mov r1, msr*/
if(oclass(p->from) == C_REG){
if(oclass(&p->from) == C_REG){
if(p->as == AMOVD)
o1 = AOP_RRR(OP_MTMSRD, p->from.reg, 0, 0);
else

View file

@ -83,18 +83,6 @@ 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",
@ -139,29 +127,6 @@ 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->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);

View file

@ -84,28 +84,14 @@ static Prog* bigP;
static int
Pconv(Fmt *fp)
{
char str[STRINGSZ], *s;
char str[STRINGSZ];
Prog *p;
int a;
int a, ch;
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) {
@ -119,26 +105,29 @@ Pconv(Fmt *fp)
else
sprint(str, "%.5lld (%L) %A %D,%D", p->pc, p->lineno, a, &p->from, &p->to);
} else {
s = str;
if(p->mark & NOSCHED)
s += sprint(s, "*");
sprint(strchr(str, 0), "*");
if(p->reg == NREG && p->from3.type == D_NONE)
sprint(s, "%.5lld (%L) %A %D,%D", p->pc, p->lineno, a, &p->from, &p->to);
sprint(strchr(str, 0), "%.5lld (%L) %A %D,%D", p->pc, p->lineno, a, &p->from, &p->to);
else
if(a != ATEXT && p->from.type == D_OREG) {
sprint(s, "%.5lld (%L) %A %lld(R%d+R%d),%D", p->pc, p->lineno, a,
sprint(strchr(str, 0), "%.5lld (%L) %A %lld(R%d+R%d),%D", p->pc, p->lineno, a,
p->from.offset, p->from.reg, p->reg, &p->to);
} else
if(p->to.type == D_OREG) {
sprint(s, "%.5lld (%L) %A %D,%lld(R%d+R%d)", p->pc, p->lineno, a,
sprint(strchr(str, 0), "%.5lld (%L) %A %D,%lld(R%d+R%d)", p->pc, p->lineno, a,
&p->from, p->to.offset, p->to.reg, p->reg);
} else {
s += sprint(s, "%.5lld (%L) %A %D", p->pc, p->lineno, a, &p->from);
if(p->reg != NREG)
s += sprint(s, ",%c%d", p->from.type==D_FREG?'F':'R', p->reg);
sprint(strchr(str, 0), "%.5lld (%L) %A %D", p->pc, p->lineno, a, &p->from);
if(p->reg != NREG) {
ch = 'R';
if(p->from.type == D_FREG)
ch = 'F';
sprint(strchr(str, 0), ",%c%d", ch, p->reg);
}
if(p->from3.type != D_NONE)
s += sprint(s, ",%D", &p->from3);
sprint(s, ",%D", &p->to);
sprint(strchr(str, 0), ",%D", &p->from3);
sprint(strchr(str, 0), ",%D", &p->to);
}
if(p->spadj != 0)
return fmtprint(fp, "%s # spadj=%d", str, p->spadj);
@ -168,32 +157,6 @@ 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));

View file

@ -35,7 +35,7 @@
#include "../cmd/5l/5.out.h"
#include "../runtime/stack.h"
static Prog zprg = {
static Prog zprg5 = {
.as = AGOK,
.scond = C_SCOND_NONE,
.reg = NREG,
@ -156,11 +156,11 @@ progedit(Link *ctxt, Prog *p)
case AMOVF:
if(p->from.type == D_FCONST && chipfloat5(ctxt, p->from.u.dval) < 0 &&
(chipzero5(ctxt, p->from.u.dval) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
int32 i32;
uint32 i32;
float32 f32;
f32 = p->from.u.dval;
memmove(&i32, &f32, 4);
sprint(literal, "$f32.%08ux", (uint32)i32);
sprint(literal, "$f32.%08ux", i32);
s = linklookup(ctxt, literal, 0);
if(s->type == 0) {
s->type = SRODATA;
@ -177,9 +177,9 @@ progedit(Link *ctxt, Prog *p)
case AMOVD:
if(p->from.type == D_FCONST && chipfloat5(ctxt, p->from.u.dval) < 0 &&
(chipzero5(ctxt, p->from.u.dval) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
int64 i64;
uint64 i64;
memmove(&i64, &p->from.u.dval, 8);
sprint(literal, "$f64.%016llux", (uvlong)i64);
sprint(literal, "$f64.%016llux", i64);
s = linklookup(ctxt, literal, 0);
if(s->type == 0) {
s->type = SRODATA;
@ -216,7 +216,7 @@ prg(void)
Prog *p;
p = emallocz(sizeof(*p));
*p = zprg;
*p = zprg5;
return p;
}
@ -247,7 +247,7 @@ linkcase(Prog *casep)
}
static void
nocache(Prog *p)
nocache5(Prog *p)
{
p->optab = 0;
p->from.class = 0;
@ -540,11 +540,11 @@ addstacksplit(Link *ctxt, LSym *cursym)
break;
case ARET:
nocache(p);
nocache5(p);
if(cursym->text->mark & LEAF) {
if(!autosize) {
p->as = AB;
p->from = zprg.from;
p->from = zprg5.from;
if(p->to.sym) { // retjmp
p->to.type = D_BRANCH;
} else {
@ -758,7 +758,7 @@ softfloat(Link *ctxt, LSym *cursym)
*next = *p;
// BL _sfloat(SB)
*p = zprg;
*p = zprg5;
p->link = next;
p->as = ABL;
p->to.type = D_BRANCH;

View file

@ -241,6 +241,19 @@ progedit(Link *ctxt, Prog *p)
// Rewrite float constants to values stored in memory.
switch(p->as) {
case AMOVSS:
// Convert AMOVSS $(0), Xx to AXORPS Xx, Xx
if(p->from.type == D_FCONST)
if(p->from.u.dval == 0)
if(p->to.type >= D_X0)
if(p->to.type <= D_X15) {
p->as = AXORPS;
p->from.type = p->to.type;
p->from.index = p->to.index;
break;
}
// fallthrough
case AFMOVF:
case AFADDF:
case AFSUBF:
@ -250,7 +263,6 @@ progedit(Link *ctxt, Prog *p)
case AFDIVRF:
case AFCOMF:
case AFCOMFP:
case AMOVSS:
case AADDSS:
case ASUBSS:
case AMULSS:
@ -258,11 +270,11 @@ progedit(Link *ctxt, Prog *p)
case ACOMISS:
case AUCOMISS:
if(p->from.type == D_FCONST) {
int32 i32;
uint32 i32;
float32 f32;
f32 = p->from.u.dval;
memmove(&i32, &f32, 4);
sprint(literal, "$f32.%08ux", (uint32)i32);
sprint(literal, "$f32.%08ux", i32);
s = linklookup(ctxt, literal, 0);
if(s->type == 0) {
s->type = SRODATA;
@ -275,6 +287,19 @@ progedit(Link *ctxt, Prog *p)
}
break;
case AMOVSD:
// Convert AMOVSD $(0), Xx to AXORPS Xx, Xx
if(p->from.type == D_FCONST)
if(p->from.u.dval == 0)
if(p->to.type >= D_X0)
if(p->to.type <= D_X15) {
p->as = AXORPS;
p->from.type = p->to.type;
p->from.index = p->to.index;
break;
}
// fallthrough
case AFMOVD:
case AFADDD:
case AFSUBD:
@ -284,7 +309,6 @@ progedit(Link *ctxt, Prog *p)
case AFDIVRD:
case AFCOMD:
case AFCOMDP:
case AMOVSD:
case AADDSD:
case ASUBSD:
case AMULSD:
@ -292,9 +316,9 @@ progedit(Link *ctxt, Prog *p)
case ACOMISD:
case AUCOMISD:
if(p->from.type == D_FCONST) {
int64 i64;
uint64 i64;
memmove(&i64, &p->from.u.dval, 8);
sprint(literal, "$f64.%016llux", (uvlong)i64);
sprint(literal, "$f64.%016llux", i64);
s = linklookup(ctxt, literal, 0);
if(s->type == 0) {
s->type = SRODATA;

View file

@ -177,6 +177,19 @@ progedit(Link *ctxt, Prog *p)
// Rewrite float constants to values stored in memory.
switch(p->as) {
case AMOVSS:
// Convert AMOVSS $(0), Xx to AXORPS Xx, Xx
if(p->from.type == D_FCONST)
if(p->from.u.dval == 0)
if(p->to.type >= D_X0)
if(p->to.type <= D_X7) {
p->as = AXORPS;
p->from.type = p->to.type;
p->from.index = p->to.index;
break;
}
// fallthrough
case AFMOVF:
case AFADDF:
case AFSUBF:
@ -186,7 +199,6 @@ progedit(Link *ctxt, Prog *p)
case AFDIVRF:
case AFCOMF:
case AFCOMFP:
case AMOVSS:
case AADDSS:
case ASUBSS:
case AMULSS:
@ -194,11 +206,11 @@ progedit(Link *ctxt, Prog *p)
case ACOMISS:
case AUCOMISS:
if(p->from.type == D_FCONST) {
int32 i32;
uint32 i32;
float32 f32;
f32 = p->from.u.dval;
memmove(&i32, &f32, 4);
sprint(literal, "$f32.%08ux", (uint32)i32);
sprint(literal, "$f32.%08ux", i32);
s = linklookup(ctxt, literal, 0);
if(s->type == 0) {
s->type = SRODATA;
@ -211,6 +223,19 @@ progedit(Link *ctxt, Prog *p)
}
break;
case AMOVSD:
// Convert AMOVSD $(0), Xx to AXORPS Xx, Xx
if(p->from.type == D_FCONST)
if(p->from.u.dval == 0)
if(p->to.type >= D_X0)
if(p->to.type <= D_X7) {
p->as = AXORPS;
p->from.type = p->to.type;
p->from.index = p->to.index;
break;
}
// fallthrough
case AFMOVD:
case AFADDD:
case AFSUBD:
@ -220,7 +245,6 @@ progedit(Link *ctxt, Prog *p)
case AFDIVRD:
case AFCOMD:
case AFCOMDP:
case AMOVSD:
case AADDSD:
case ASUBSD:
case AMULSD:
@ -228,9 +252,9 @@ progedit(Link *ctxt, Prog *p)
case ACOMISD:
case AUCOMISD:
if(p->from.type == D_FCONST) {
int64 i64;
uint64 i64;
memmove(&i64, &p->from.u.dval, 8);
sprint(literal, "$f64.%016llux", (uvlong)i64);
sprint(literal, "$f64.%016llux", i64);
s = linklookup(ctxt, literal, 0);
if(s->type == 0) {
s->type = SRODATA;

View file

@ -118,11 +118,11 @@ progedit(Link *ctxt, Prog *p)
switch(p->as) {
case AFMOVS:
if(p->from.type == D_FCONST) {
int32 i32;
uint32 i32;
float32 f32;
f32 = p->from.u.dval;
memmove(&i32, &f32, 4);
sprint(literal, "$f32.%08ux", (uint32)i32);
sprint(literal, "$f32.%08ux", i32);
s = linklookup(ctxt, literal, 0);
s->size = 4;
p->from.type = D_OREG;
@ -133,9 +133,9 @@ progedit(Link *ctxt, Prog *p)
break;
case AFMOVD:
if(p->from.type == D_FCONST) {
int64 i64;
uint64 i64;
memmove(&i64, &p->from.u.dval, 8);
sprint(literal, "$f64.%016llux", (uvlong)i64);
sprint(literal, "$f64.%016llux", i64);
s = linklookup(ctxt, literal, 0);
s->size = 8;
p->from.type = D_OREG;
@ -414,7 +414,7 @@ addstacksplit(Link *ctxt, LSym *cursym)
else
if(autosize & 4)
autosize += 4;
p->to.offset = (p->to.offset & (0xffffffffull<<32)) | (uint32)(autosize-8);
p->to.offset = ((uint64)p->to.offset & (0xffffffffull<<32)) | (uint32)(autosize-8);
if(!(p->reg & NOSPLIT))
p = stacksplit(ctxt, p, autosize, !(cursym->text->reg&NEEDCTXT)); // emit split check
@ -668,14 +668,15 @@ addstacksplit(Link *ctxt, LSym *cursym)
}
}
#if 0 // instruction scheduling
/*
// instruction scheduling
if(debug['Q'] == 0)
return;
curtext = nil;
q = nil; /* p - 1 */
q1 = firstp; /* top of block */
o = 0; /* count of instructions */
q = nil; // p - 1
q1 = firstp; // top of block
o = 0; // count of instructions
for(p = firstp; p != nil; p = p1) {
p1 = p->link;
o++;
@ -711,7 +712,7 @@ addstacksplit(Link *ctxt, LSym *cursym)
}
q = p;
}
#endif
*/
}
static Prog*

View file

@ -69,6 +69,7 @@ void
linkpatch(Link *ctxt, LSym *sym)
{
int32 c;
char *name;
Prog *p, *q;
ctxt->cursym = sym;
@ -95,8 +96,10 @@ linkpatch(Link *ctxt, LSym *sym)
q = q->link;
}
if(q == nil) {
ctxt->diag("branch out of range (%#ux)\n%P [%s]",
c, p, p->to.sym ? p->to.sym->name : "<nil>");
name = "<nil>";
if(p->to.sym)
name = p->to.sym->name;
ctxt->diag("branch out of range (%#ux)\n%P [%s]", c, p, name);
p->to.type = ctxt->arch->D_NONE;
}
p->to.u.branch = q;

View file

@ -1,835 +0,0 @@
// cmd/9l/sched.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.
// +build ignore
#include "l.h"
enum
{
E_ICC = 1<<0,
E_FCC = 1<<1,
E_MEM = 1<<2,
E_MEMSP = 1<<3, /* uses offset and size */
E_MEMSB = 1<<4, /* uses offset and size */
E_LR = 1<<5,
E_CR = 1<<6,
E_CTR = 1<<7,
E_XER = 1<<8,
E_CR0 = 0xF<<0,
E_CR1 = 0xF<<4,
ANYMEM = E_MEM|E_MEMSP|E_MEMSB,
ALL = ~0,
};
typedef struct Sch Sch;
typedef struct Dep Dep;
struct Dep
{
ulong ireg;
ulong freg;
ulong cc;
ulong cr;
};
struct Sch
{
Prog p;
Dep set;
Dep used;
long soffset;
char size;
char comp;
};
void regused(Sch*, Prog*);
int depend(Sch*, Sch*);
int conflict(Sch*, Sch*);
int offoverlap(Sch*, Sch*);
void dumpbits(Sch*, Dep*);
void
sched(Prog *p0, Prog *pe)
{
Prog *p, *q;
Sch sch[NSCHED], *s, *t, *u, *se, stmp;
if(!debug['Q'])
return;
/*
* build side structure
*/
s = sch;
for(p=p0;; p=p->link) {
memset(s, 0, sizeof(*s));
s->p = *p;
regused(s, p);
if(debug['X']) {
Bprint(&bso, "%P\tset", &s->p);
dumpbits(s, &s->set);
Bprint(&bso, "; used");
dumpbits(s, &s->used);
if(s->comp)
Bprint(&bso, "; compound");
if(s->p.mark & LOAD)
Bprint(&bso, "; load");
if(s->p.mark & BRANCH)
Bprint(&bso, "; branch");
if(s->p.mark & FCMP)
Bprint(&bso, "; fcmp");
Bprint(&bso, "\n");
}
s++;
if(p == pe)
break;
}
se = s;
for(s=se-1; s>=sch; s--) {
/*
* load delay. interlocked.
*/
if(s->p.mark & LOAD) {
if(s >= se-1)
continue;
if(!conflict(s, (s+1)))
continue;
/*
* s is load, s+1 is immediate use of result
* t is the trial instruction to insert between s and s+1
*/
for(t=s-1; t>=sch; t--) {
if(t->p.mark & BRANCH)
goto no2;
if(t->p.mark & FCMP)
if((s+1)->p.mark & BRANCH)
goto no2;
if(t->p.mark & LOAD)
if(conflict(t, (s+1)))
goto no2;
for(u=t+1; u<=s; u++)
if(depend(u, t))
goto no2;
goto out2;
no2:;
}
if(debug['X'])
Bprint(&bso, "?l%P\n", &s->p);
continue;
out2:
if(debug['X']) {
Bprint(&bso, "!l%P\n", &t->p);
Bprint(&bso, "%P\n", &s->p);
}
stmp = *t;
memmove(t, t+1, (uchar*)s - (uchar*)t);
*s = stmp;
s--;
continue;
}
/*
* fop2 delay.
*/
if(s->p.mark & FCMP) {
if(s >= se-1)
continue;
if(!((s+1)->p.mark & BRANCH))
continue;
/* t is the trial instruction to use */
for(t=s-1; t>=sch; t--) {
for(u=t+1; u<=s; u++)
if(depend(u, t))
goto no3;
goto out3;
no3:;
}
if(debug['X'])
Bprint(&bso, "?f%P\n", &s->p);
continue;
out3:
if(debug['X']) {
Bprint(&bso, "!f%P\n", &t->p);
Bprint(&bso, "%P\n", &s->p);
}
stmp = *t;
memmove(t, t+1, (uchar*)s - (uchar*)t);
*s = stmp;
s--;
continue;
}
}
/*
* put it all back
*/
for(s=sch, p=p0; s<se; s++, p=q) {
q = p->link;
if(q != s->p.link) {
*p = s->p;
p->link = q;
}
}
if(debug['X'])
Bprint(&bso, "\n");
}
void
regused(Sch *s, Prog *realp)
{
int c, ar, ad, ld, sz, nr, upd;
ulong m;
Prog *p;
p = &s->p;
s->comp = compound(p);
if(s->comp) {
s->set.ireg |= 1<<REGTMP;
s->used.ireg |= 1<<REGTMP;
}
ar = 0; /* dest is really reference */
ad = 0; /* source/dest is really address */
ld = 0; /* opcode is load instruction */
sz = 32*4; /* size of load/store for overlap computation */
nr = 0; /* source/dest is not really reg */
upd = 0; /* move with update; changes reg */
/*
* flags based on opcode
*/
switch(p->as) {
case ATEXT:
curtext = realp;
autosize = p->to.offset + 8;
ad = 1;
break;
case ABL:
s->set.cc |= E_LR;
ar = 1;
ad = 1;
break;
case ABR:
ar = 1;
ad = 1;
break;
case ACMP:
case ACMPU:
case ACMPW:
case ACMPWU:
s->set.cc |= E_ICC;
if(p->reg == 0)
s->set.cr |= E_CR0;
else
s->set.cr |= (0xF<<((p->reg&7)*4));
ar = 1;
break;
case AFCMPO:
case AFCMPU:
s->set.cc |= E_FCC;
if(p->reg == 0)
s->set.cr |= E_CR0;
else
s->set.cr |= (0xF<<((p->reg&7)*4));
ar = 1;
break;
case ACRAND:
case ACRANDN:
case ACREQV:
case ACRNAND:
case ACRNOR:
case ACROR:
case ACRORN:
case ACRXOR:
s->used.cr |= 1<<p->from.reg;
s->set.cr |= 1<<p->to.reg;
nr = 1;
break;
case ABCL: /* tricky */
s->used.cc |= E_FCC|E_ICC;
s->used.cr = ALL;
s->set.cc |= E_LR;
ar = 1;
break;
case ABC: /* tricky */
s->used.cc |= E_FCC|E_ICC;
s->used.cr = ALL;
ar = 1;
break;
case ABEQ:
case ABGE:
case ABGT:
case ABLE:
case ABLT:
case ABNE:
case ABVC:
case ABVS:
s->used.cc |= E_ICC;
s->used.cr |= E_CR0;
ar = 1;
break;
case ALSW:
case AMOVMW:
/* could do better */
sz = 32*4;
ld = 1;
break;
case AMOVBU:
case AMOVBZU:
upd = 1;
sz = 1;
ld = 1;
break;
case AMOVB:
case AMOVBZ:
sz = 1;
ld = 1;
break;
case AMOVHU:
case AMOVHZU:
upd = 1;
sz = 2;
ld = 1;
break;
case AMOVH:
case AMOVHBR:
case AMOVHZ:
sz = 2;
ld = 1;
break;
case AFMOVSU:
case AMOVWU:
case AMOVWZU:
upd = 1;
sz = 4;
ld = 1;
break;
case AFMOVS:
case AMOVW:
case AMOVWZ:
case AMOVWBR:
case ALWAR:
sz = 4;
ld = 1;
break;
case AFMOVDU:
upd = 1;
sz = 8;
ld = 1;
break;
case AFMOVD:
sz = 8;
ld = 1;
break;
case AFMOVDCC:
sz = 8;
ld = 1;
s->set.cc |= E_FCC;
s->set.cr |= E_CR1;
break;
case AMOVFL:
case AMOVCRFS:
case AMTFSB0:
case AMTFSB0CC:
case AMTFSB1:
case AMTFSB1CC:
s->set.ireg = ALL;
s->set.freg = ALL;
s->set.cc = ALL;
s->set.cr = ALL;
break;
case AADDCC:
case AADDVCC:
case AADDCCC:
case AADDCVCC:
case AADDMECC:
case AADDMEVCC:
case AADDECC:
case AADDEVCC:
case AADDZECC:
case AADDZEVCC:
case AANDCC:
case AANDNCC:
case ACNTLZWCC:
case ADIVWCC:
case ADIVWVCC:
case ADIVWUCC:
case ADIVWUVCC:
case AEQVCC:
case AEXTSBCC:
case AEXTSHCC:
case AMULHWCC:
case AMULHWUCC:
case AMULLWCC:
case AMULLWVCC:
case ANANDCC:
case ANEGCC:
case ANEGVCC:
case ANORCC:
case AORCC:
case AORNCC:
case AREMCC:
case AREMVCC:
case AREMUCC:
case AREMUVCC:
case ARLWMICC:
case ARLWNMCC:
case ASLWCC:
case ASRAWCC:
case ASRWCC:
case ASTWCCC:
case ASUBCC:
case ASUBVCC:
case ASUBCCC:
case ASUBCVCC:
case ASUBMECC:
case ASUBMEVCC:
case ASUBECC:
case ASUBEVCC:
case ASUBZECC:
case ASUBZEVCC:
case AXORCC:
s->set.cc |= E_ICC;
s->set.cr |= E_CR0;
break;
case AFABSCC:
case AFADDCC:
case AFADDSCC:
case AFCTIWCC:
case AFCTIWZCC:
case AFDIVCC:
case AFDIVSCC:
case AFMADDCC:
case AFMADDSCC:
case AFMSUBCC:
case AFMSUBSCC:
case AFMULCC:
case AFMULSCC:
case AFNABSCC:
case AFNEGCC:
case AFNMADDCC:
case AFNMADDSCC:
case AFNMSUBCC:
case AFNMSUBSCC:
case AFRSPCC:
case AFSUBCC:
case AFSUBSCC:
s->set.cc |= E_FCC;
s->set.cr |= E_CR1;
break;
}
/*
* flags based on 'to' field
*/
c = p->to.class;
if(c == 0) {
c = aclass(&p->to) + 1;
p->to.class = c;
}
c--;
switch(c) {
default:
print("unknown class %d %D\n", c, &p->to);
case C_NONE:
case C_ZCON:
case C_SCON:
case C_UCON:
case C_LCON:
case C_ADDCON:
case C_ANDCON:
case C_SBRA:
case C_LBRA:
break;
case C_CREG:
c = p->to.reg;
if(c == NREG)
s->set.cr = ALL;
else
s->set.cr |= (0xF << ((p->from.reg&7)*4));
s->set.cc = ALL;
break;
case C_SPR:
case C_FPSCR:
case C_MSR:
case C_XER:
s->set.ireg = ALL;
s->set.freg = ALL;
s->set.cc = ALL;
s->set.cr = ALL;
break;
case C_LR:
s->set.cc |= E_LR;
break;
case C_CTR:
s->set.cc |= E_CTR;
break;
case C_ZOREG:
case C_SOREG:
case C_LOREG:
c = p->to.reg;
s->used.ireg |= 1<<c;
if(upd)
s->set.ireg |= 1<<c;
if(ad)
break;
s->size = sz;
s->soffset = regoff(&p->to);
m = ANYMEM;
if(c == REGSB)
m = E_MEMSB;
if(c == REGSP)
m = E_MEMSP;
if(ar)
s->used.cc |= m;
else
s->set.cc |= m;
break;
case C_SACON:
case C_LACON:
s->used.ireg |= 1<<REGSP;
if(upd)
s->set.ireg |= 1<<c;
break;
case C_SECON:
case C_LECON:
s->used.ireg |= 1<<REGSB;
if(upd)
s->set.ireg |= 1<<c;
break;
case C_REG:
if(nr)
break;
if(ar)
s->used.ireg |= 1<<p->to.reg;
else
s->set.ireg |= 1<<p->to.reg;
break;
case C_FREG:
if(ar)
s->used.freg |= 1<<p->to.reg;
else
s->set.freg |= 1<<p->to.reg;
break;
case C_SAUTO:
case C_LAUTO:
s->used.ireg |= 1<<REGSP;
if(upd)
s->set.ireg |= 1<<c;
if(ad)
break;
s->size = sz;
s->soffset = regoff(&p->to);
if(ar)
s->used.cc |= E_MEMSP;
else
s->set.cc |= E_MEMSP;
break;
case C_SEXT:
case C_LEXT:
s->used.ireg |= 1<<REGSB;
if(upd)
s->set.ireg |= 1<<c;
if(ad)
break;
s->size = sz;
s->soffset = regoff(&p->to);
if(ar)
s->used.cc |= E_MEMSB;
else
s->set.cc |= E_MEMSB;
break;
}
/*
* flags based on 'from' field
*/
c = p->from.class;
if(c == 0) {
c = aclass(&p->from) + 1;
p->from.class = c;
}
c--;
switch(c) {
default:
print("unknown class %d %D\n", c, &p->from);
case C_NONE:
case C_ZCON:
case C_SCON:
case C_UCON:
case C_LCON:
case C_ADDCON:
case C_ANDCON:
case C_SBRA:
case C_LBRA:
c = p->from.reg;
if(c != NREG)
s->used.ireg |= 1<<c;
break;
case C_CREG:
c = p->from.reg;
if(c == NREG)
s->used.cr = ALL;
else
s->used.cr |= (0xF << ((p->from.reg&7)*4));
s->used.cc = ALL;
break;
case C_SPR:
case C_FPSCR:
case C_MSR:
case C_XER:
s->set.ireg = ALL;
s->set.freg = ALL;
s->set.cc = ALL;
s->set.cr = ALL;
break;
case C_LR:
s->used.cc |= E_LR;
break;
case C_CTR:
s->used.cc |= E_CTR;
break;
case C_ZOREG:
case C_SOREG:
case C_LOREG:
c = p->from.reg;
s->used.ireg |= 1<<c;
if(ld)
p->mark |= LOAD;
if(ad)
break;
s->size = sz;
s->soffset = regoff(&p->from);
m = ANYMEM;
if(c == REGSB)
m = E_MEMSB;
if(c == REGSP)
m = E_MEMSP;
s->used.cc |= m;
break;
case C_SACON:
case C_LACON:
s->used.ireg |= 1<<REGSP;
break;
case C_SECON:
case C_LECON:
s->used.ireg |= 1<<REGSB;
break;
case C_REG:
if(nr)
break;
s->used.ireg |= 1<<p->from.reg;
break;
case C_FREG:
s->used.freg |= 1<<p->from.reg;
break;
case C_SAUTO:
case C_LAUTO:
s->used.ireg |= 1<<REGSP;
if(ld)
p->mark |= LOAD;
if(ad)
break;
s->size = sz;
s->soffset = regoff(&p->from);
s->used.cc |= E_MEMSP;
break;
case C_SEXT:
case C_LEXT:
s->used.ireg |= 1<<REGSB;
if(ld)
p->mark |= LOAD;
if(ad)
break;
s->size = sz;
s->soffset = regoff(&p->from);
s->used.cc |= E_MEMSB;
break;
}
c = p->reg;
if(c != NREG) {
if(p->from.type == D_FREG || p->to.type == D_FREG)
s->used.freg |= 1<<c;
else
s->used.ireg |= 1<<c;
}
}
/*
* test to see if 2 instrictions can be
* interchanged without changing semantics
*/
int
depend(Sch *sa, Sch *sb)
{
ulong x;
if(sa->set.ireg & (sb->set.ireg|sb->used.ireg))
return 1;
if(sb->set.ireg & sa->used.ireg)
return 1;
if(sa->set.freg & (sb->set.freg|sb->used.freg))
return 1;
if(sb->set.freg & sa->used.freg)
return 1;
if(sa->set.cr & (sb->set.cr|sb->used.cr))
return 1;
if(sb->set.cr & sa->used.cr)
return 1;
x = (sa->set.cc & (sb->set.cc|sb->used.cc)) |
(sb->set.cc & sa->used.cc);
if(x) {
/*
* allow SB and SP to pass each other.
* allow SB to pass SB iff doffsets are ok
* anything else conflicts
*/
if(x != E_MEMSP && x != E_MEMSB)
return 1;
x = sa->set.cc | sb->set.cc |
sa->used.cc | sb->used.cc;
if(x & E_MEM)
return 1;
if(offoverlap(sa, sb))
return 1;
}
return 0;
}
int
offoverlap(Sch *sa, Sch *sb)
{
if(sa->soffset < sb->soffset) {
if(sa->soffset+sa->size > sb->soffset)
return 1;
return 0;
}
if(sb->soffset+sb->size > sa->soffset)
return 1;
return 0;
}
/*
* test 2 adjacent instructions
* and find out if inserted instructions
* are desired to prevent stalls.
* first instruction is a load instruction.
*/
int
conflict(Sch *sa, Sch *sb)
{
if(sa->set.ireg & sb->used.ireg)
return 1;
if(sa->set.freg & sb->used.freg)
return 1;
if(sa->set.cr & sb->used.cr)
return 1;
return 0;
}
int
compound(Prog *p)
{
Optab *o;
o = oplook(p);
if(o->size != 4)
return 1;
if(p->to.type == D_REG && p->to.reg == REGSB)
return 1;
return 0;
}
void
dumpbits(Sch *s, Dep *d)
{
int i;
for(i=0; i<32; i++)
if(d->ireg & (1<<i))
Bprint(&bso, " R%d", i);
for(i=0; i<32; i++)
if(d->freg & (1<<i))
Bprint(&bso, " F%d", i);
for(i=0; i<32; i++)
if(d->cr & (1<<i))
Bprint(&bso, " C%d", i);
for(i=0; i<32; i++)
switch(d->cc & (1<<i)) {
default:
break;
case E_ICC:
Bprint(&bso, " ICC");
break;
case E_FCC:
Bprint(&bso, " FCC");
break;
case E_LR:
Bprint(&bso, " LR");
break;
case E_CR:
Bprint(&bso, " CR");
break;
case E_CTR:
Bprint(&bso, " CTR");
break;
case E_XER:
Bprint(&bso, " XER");
break;
case E_MEM:
Bprint(&bso, " MEM%d", s->size);
break;
case E_MEMSB:
Bprint(&bso, " SB%d", s->size);
break;
case E_MEMSP:
Bprint(&bso, " SP%d", s->size);
break;
}
}

View file

@ -57,7 +57,6 @@ static struct {
{"solaris", Hsolaris},
{"windows", Hwindows},
{"windowsgui", Hwindows},
{0, 0},
};
int
@ -65,7 +64,7 @@ headtype(char *name)
{
int i;
for(i=0; headers[i].name; i++)
for(i=0; i < nelem(headers); i++)
if(strcmp(name, headers[i].name) == 0)
return headers[i].val;
return -1;
@ -77,7 +76,7 @@ headstr(int v)
static char buf[20];
int i;
for(i=0; headers[i].name; i++)
for(i=0; i < nelem(headers); i++)
if(v == headers[i].val)
return headers[i].name;
snprint(buf, sizeof buf, "%d", v);

View file

@ -63,22 +63,19 @@ func New(out io.Writer, prefix string, flag int) *Logger {
var std = New(os.Stderr, "", LstdFlags)
// Cheap integer to fixed-width decimal ASCII. Give a negative width to avoid zero-padding.
// Knows the buffer has capacity.
func itoa(buf *[]byte, i int, wid int) {
var u uint = uint(i)
if u == 0 && wid <= 1 {
*buf = append(*buf, '0')
return
}
// Assemble decimal in reverse order.
var b [32]byte
bp := len(b)
for ; u > 0 || wid > 0; u /= 10 {
bp--
var b [20]byte
bp := len(b) - 1
for i >= 10 || wid > 1 {
wid--
b[bp] = byte(u%10) + '0'
q := i / 10
b[bp] = byte('0' + i - q*10)
bp--
i = q
}
// i < 10
b[bp] = byte('0' + i)
*buf = append(*buf, b[bp:]...)
}
@ -325,3 +322,14 @@ func Panicln(v ...interface{}) {
std.Output(2, s)
panic(s)
}
// Output writes the output for a logging event. The string s contains
// the text to print after the prefix specified by the flags of the
// Logger. A newline is appended if the last character of s is not
// already a newline. Calldepth is the count of the number of
// frames to skip when computing the file name and line number
// if Llongfile or Lshortfile is set; a value of 1 will print the details
// for the caller of Output.
func Output(calldepth int, s string) error {
return std.Output(calldepth+1, s) // +1 for this frame.
}

View file

@ -117,3 +117,27 @@ func TestFlagAndPrefixSetting(t *testing.T) {
t.Error("message did not match pattern")
}
}
func BenchmarkItoa(b *testing.B) {
dst := make([]byte, 0, 64)
for i := 0; i < b.N; i++ {
dst = dst[0:0]
itoa(&dst, 2015, 4) // year
itoa(&dst, 1, 2) // month
itoa(&dst, 30, 2) // day
itoa(&dst, 12, 2) // hour
itoa(&dst, 56, 2) // minute
itoa(&dst, 0, 2) // second
itoa(&dst, 987654, 6) // microsecond
}
}
func BenchmarkPrintln(b *testing.B) {
const testString = "test"
var buf bytes.Buffer
l := New(&buf, "", LstdFlags)
for i := 0; i < b.N; i++ {
buf.Reset()
l.Println(testString)
}
}

View file

@ -70,7 +70,7 @@ func mulWW_g(x, y Word) (z1, z0 Word) {
// z1<<_W + z0 = x*y + c
func mulAddWWW_g(x, y, c Word) (z1, z0 Word) {
z1, zz0 := mulWW(x, y)
z1, zz0 := mulWW_g(x, y)
if z0 = zz0 + c; z0 < zz0 {
z1++
}
@ -154,34 +154,84 @@ func divWW_g(u1, u0, v Word) (q, r Word) {
return q1*_B2 + q0, (un21*_B2 + un0 - q0*v) >> s
}
// Keep for performance debugging.
// Using addWW_g is likely slower.
const use_addWW_g = false
// The resulting carry c is either 0 or 1.
func addVV_g(z, x, y []Word) (c Word) {
if use_addWW_g {
for i := range z {
c, z[i] = addWW_g(x[i], y[i], c)
}
return
}
}
func subVV_g(z, x, y []Word) (c Word) {
for i := range z {
c, z[i] = subWW_g(x[i], y[i], c)
for i, xi := range x[:len(z)] {
yi := y[i]
zi := xi + yi + c
z[i] = zi
// see "Hacker's Delight", section 2-12 (overflow detection)
c = (xi&yi | (xi|yi)&^zi) >> (_W - 1)
}
return
}
// The resulting carry c is either 0 or 1.
func subVV_g(z, x, y []Word) (c Word) {
if use_addWW_g {
for i := range z {
c, z[i] = subWW_g(x[i], y[i], c)
}
return
}
for i, xi := range x[:len(z)] {
yi := y[i]
zi := xi - yi - c
z[i] = zi
// see "Hacker's Delight", section 2-12 (overflow detection)
c = (yi&^xi | (yi|^xi)&zi) >> (_W - 1)
}
return
}
// Argument y must be either 0 or 1.
// The resulting carry c is either 0 or 1.
func addVW_g(z, x []Word, y Word) (c Word) {
if use_addWW_g {
c = y
for i := range z {
c, z[i] = addWW_g(x[i], c, 0)
}
return
}
c = y
for i, xi := range x[:len(z)] {
zi := xi + c
z[i] = zi
c = xi &^ zi >> (_W - 1)
}
return
}
func subVW_g(z, x []Word, y Word) (c Word) {
if use_addWW_g {
c = y
for i := range z {
c, z[i] = subWW_g(x[i], c, 0)
}
return
}
c = y
for i, xi := range x[:len(z)] {
zi := xi - c
z[i] = zi
c = (zi &^ xi) >> (_W - 1)
}
return
}
func shlVU_g(z, x []Word, s uint) (c Word) {
@ -222,6 +272,7 @@ func mulAddVWW_g(z, x []Word, y, r Word) (c Word) {
return
}
// TODO(gri) Remove use of addWW_g here and then we can remove addWW_g and subWW_g.
func addMulVVW_g(z, x []Word, y Word) (c Word) {
for i := range z {
z1, z0 := mulAddWWW_g(x[i], y, z[i])

View file

@ -37,15 +37,16 @@ TEXT ·addVV(SB),NOSPLIT,$0
JMP E1
L1: MOVL (SI)(BX*4), AX
RCRL $1, DX
ADDL DX, DX // restore CF
ADCL (CX)(BX*4), AX
RCLL $1, DX
SBBL DX, DX // save CF
MOVL AX, (DI)(BX*4)
ADDL $1, BX // i++
E1: CMPL BX, BP // i < n
JL L1
NEGL DX
MOVL DX, c+36(FP)
RET
@ -62,15 +63,16 @@ TEXT ·subVV(SB),NOSPLIT,$0
JMP E2
L2: MOVL (SI)(BX*4), AX
RCRL $1, DX
ADDL DX, DX // restore CF
SBBL (CX)(BX*4), AX
RCLL $1, DX
SBBL DX, DX // save CF
MOVL AX, (DI)(BX*4)
ADDL $1, BX // i++
E2: CMPL BX, BP // i < n
JL L2
NEGL DX
MOVL DX, c+36(FP)
RET
@ -86,8 +88,8 @@ TEXT ·addVW(SB),NOSPLIT,$0
L3: ADDL (SI)(BX*4), AX
MOVL AX, (DI)(BX*4)
RCLL $1, AX
ANDL $1, AX
SBBL AX, AX // save CF
NEGL AX
ADDL $1, BX // i++
E3: CMPL BX, BP // i < n
@ -106,11 +108,11 @@ TEXT ·subVW(SB),NOSPLIT,$0
MOVL $0, BX // i = 0
JMP E4
L4: MOVL (SI)(BX*4), DX // TODO(gri) is there a reverse SUBL?
L4: MOVL (SI)(BX*4), DX
SUBL AX, DX
MOVL DX, (DI)(BX*4)
RCLL $1, AX
ANDL $1, AX
SBBL AX, AX // save CF
NEGL AX
ADDL $1, BX // i++
E4: CMPL BX, BP // i < n

View file

@ -7,16 +7,6 @@
// This file provides fast assembly versions for the elementary
// arithmetic operations on vectors implemented in arith.go.
// Literal instruction for MOVQ $0, CX.
// (MOVQ $0, reg is translated to XORQ reg, reg and clears CF.)
#define ZERO_CX BYTE $0x48; \
BYTE $0xc7; \
BYTE $0xc1; \
BYTE $0x00; \
BYTE $0x00; \
BYTE $0x00; \
BYTE $0x00
// func mulWW(x, y Word) (z1, z0 Word)
TEXT ·mulWW(SB),NOSPLIT,$0
MOVQ x+0(FP), AX
@ -35,6 +25,11 @@ TEXT ·divWW(SB),NOSPLIT,$0
MOVQ DX, r+32(FP)
RET
// The carry bit is saved with SBBQ Rx, Rx: if the carry was set, Rx is -1, otherwise it is 0.
// It is restored with ADDQ Rx, Rx: if Rx was -1 the carry is set, otherwise it is cleared.
// This is faster than using rotate instructions.
//
// CAUTION: Note that MOVQ $0, Rx is translated to XORQ Rx, Rx which clears the carry bit!
// func addVV(z, x, y []Word) (c Word)
TEXT ·addVV(SB),NOSPLIT,$0
@ -52,7 +47,7 @@ TEXT ·addVV(SB),NOSPLIT,$0
U1: // n >= 0
// regular loop body unrolled 4x
RCRQ $1, CX // CF = c
ADDQ CX, CX // restore CF
MOVQ 0(R8)(SI*8), R11
MOVQ 8(R8)(SI*8), R12
MOVQ 16(R8)(SI*8), R13
@ -65,7 +60,7 @@ U1: // n >= 0
MOVQ R12, 8(R10)(SI*8)
MOVQ R13, 16(R10)(SI*8)
MOVQ R14, 24(R10)(SI*8)
RCLQ $1, CX // c = CF
SBBQ CX, CX // save CF
ADDQ $4, SI // i += 4
SUBQ $4, DI // n -= 4
@ -75,17 +70,18 @@ V1: ADDQ $4, DI // n += 4
JLE E1 // if n <= 0 goto E1
L1: // n > 0
RCRQ $1, CX // CF = c
ADDQ CX, CX // restore CF
MOVQ 0(R8)(SI*8), R11
ADCQ 0(R9)(SI*8), R11
MOVQ R11, 0(R10)(SI*8)
RCLQ $1, CX // c = CF
SBBQ CX, CX // save CF
ADDQ $1, SI // i++
SUBQ $1, DI // n--
JG L1 // if n > 0 goto L1
E1: MOVQ CX, c+72(FP) // return c
E1: NEGQ CX
MOVQ CX, c+72(FP) // return c
RET
@ -106,7 +102,7 @@ TEXT ·subVV(SB),NOSPLIT,$0
U2: // n >= 0
// regular loop body unrolled 4x
RCRQ $1, CX // CF = c
ADDQ CX, CX // restore CF
MOVQ 0(R8)(SI*8), R11
MOVQ 8(R8)(SI*8), R12
MOVQ 16(R8)(SI*8), R13
@ -119,7 +115,7 @@ U2: // n >= 0
MOVQ R12, 8(R10)(SI*8)
MOVQ R13, 16(R10)(SI*8)
MOVQ R14, 24(R10)(SI*8)
RCLQ $1, CX // c = CF
SBBQ CX, CX // save CF
ADDQ $4, SI // i += 4
SUBQ $4, DI // n -= 4
@ -129,17 +125,18 @@ V2: ADDQ $4, DI // n += 4
JLE E2 // if n <= 0 goto E2
L2: // n > 0
RCRQ $1, CX // CF = c
ADDQ CX, CX // restore CF
MOVQ 0(R8)(SI*8), R11
SBBQ 0(R9)(SI*8), R11
MOVQ R11, 0(R10)(SI*8)
RCLQ $1, CX // c = CF
SBBQ CX, CX // save CF
ADDQ $1, SI // i++
SUBQ $1, DI // n--
JG L2 // if n > 0 goto L2
E2: MOVQ CX, c+72(FP) // return c
E2: NEGQ CX
MOVQ CX, c+72(FP) // return c
RET
@ -163,11 +160,11 @@ U3: // n >= 0
MOVQ 16(R8)(SI*8), R13
MOVQ 24(R8)(SI*8), R14
ADDQ CX, R11
ZERO_CX
ADCQ $0, R12
ADCQ $0, R13
ADCQ $0, R14
SETCS CX // c = CF
SBBQ CX, CX // save CF
NEGQ CX
MOVQ R11, 0(R10)(SI*8)
MOVQ R12, 8(R10)(SI*8)
MOVQ R13, 16(R10)(SI*8)
@ -183,8 +180,8 @@ V3: ADDQ $4, DI // n += 4
L3: // n > 0
ADDQ 0(R8)(SI*8), CX
MOVQ CX, 0(R10)(SI*8)
ZERO_CX
RCLQ $1, CX // c = CF
SBBQ CX, CX // save CF
NEGQ CX
ADDQ $1, SI // i++
SUBQ $1, DI // n--
@ -215,11 +212,11 @@ U4: // n >= 0
MOVQ 16(R8)(SI*8), R13
MOVQ 24(R8)(SI*8), R14
SUBQ CX, R11
ZERO_CX
SBBQ $0, R12
SBBQ $0, R13
SBBQ $0, R14
SETCS CX // c = CF
SBBQ CX, CX // save CF
NEGQ CX
MOVQ R11, 0(R10)(SI*8)
MOVQ R12, 8(R10)(SI*8)
MOVQ R13, 16(R10)(SI*8)
@ -236,8 +233,8 @@ L4: // n > 0
MOVQ 0(R8)(SI*8), R11
SUBQ CX, R11
MOVQ R11, 0(R10)(SI*8)
ZERO_CX
RCLQ $1, CX // c = CF
SBBQ CX, CX // save CF
NEGQ CX
ADDQ $1, SI // i++
SUBQ $1, DI // n--

View file

@ -254,7 +254,7 @@ func benchmarkFunVW(b *testing.B, f funVW, n int) {
x := rndV(n)
y := rndW()
z := make([]Word, n)
b.SetBytes(int64(n * _W))
b.SetBytes(int64(n * _S))
b.ResetTimer()
for i := 0; i < b.N; i++ {
f(z, x, y)

View file

@ -769,3 +769,55 @@ func BenchmarkExp3Power0x10000(b *testing.B) { ExpHelper(b, 3, 0x10000) }
func BenchmarkExp3Power0x40000(b *testing.B) { ExpHelper(b, 3, 0x40000) }
func BenchmarkExp3Power0x100000(b *testing.B) { ExpHelper(b, 3, 0x100000) }
func BenchmarkExp3Power0x400000(b *testing.B) { ExpHelper(b, 3, 0x400000) }
func fibo(n int) nat {
switch n {
case 0:
return nil
case 1:
return nat{1}
}
f0 := fibo(0)
f1 := fibo(1)
var f2 nat
for i := 1; i < n; i++ {
f2 = f2.add(f0, f1)
f0, f1, f2 = f1, f2, f0
}
return f1
}
var fiboNums = []string{
"0",
"55",
"6765",
"832040",
"102334155",
"12586269025",
"1548008755920",
"190392490709135",
"23416728348467685",
"2880067194370816120",
"354224848179261915075",
}
func TestFibo(t *testing.T) {
for i, want := range fiboNums {
n := i * 10
got := fibo(n).decimalString()
if got != want {
t.Errorf("fibo(%d) failed: got %s want %s", n, got, want)
}
}
}
func BenchmarkFibo(b *testing.B) {
for i := 0; i < b.N; i++ {
fibo(1e0)
fibo(1e1)
fibo(1e2)
fibo(1e3)
fibo(1e4)
fibo(1e5)
}
}

View file

@ -100,6 +100,24 @@ var hopHeaders = []string{
"Upgrade",
}
type requestCanceler interface {
CancelRequest(*http.Request)
}
type runOnFirstRead struct {
io.Reader
fn func() // Run before first Read, then set to nil
}
func (c *runOnFirstRead) Read(bs []byte) (int, error) {
if c.fn != nil {
c.fn()
c.fn = nil
}
return c.Reader.Read(bs)
}
func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
transport := p.Transport
if transport == nil {
@ -109,6 +127,34 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
outreq := new(http.Request)
*outreq = *req // includes shallow copies of maps, but okay
if closeNotifier, ok := rw.(http.CloseNotifier); ok {
if requestCanceler, ok := transport.(requestCanceler); ok {
reqDone := make(chan struct{})
defer close(reqDone)
clientGone := closeNotifier.CloseNotify()
outreq.Body = struct {
io.Reader
io.Closer
}{
Reader: &runOnFirstRead{
Reader: outreq.Body,
fn: func() {
go func() {
select {
case <-clientGone:
requestCanceler.CancelRequest(outreq)
case <-reqDone:
}
}()
},
},
Closer: outreq.Body,
}
}
}
p.Director(outreq)
outreq.Proto = "HTTP/1.1"
outreq.ProtoMajor = 1

View file

@ -8,9 +8,11 @@ package httputil
import (
"io/ioutil"
"log"
"net/http"
"net/http/httptest"
"net/url"
"runtime"
"strings"
"testing"
"time"
@ -211,3 +213,61 @@ func TestReverseProxyFlushInterval(t *testing.T) {
t.Error("maxLatencyWriter flushLoop() never exited")
}
}
func TestReverseProxyCancellation(t *testing.T) {
if runtime.GOOS == "plan9" {
t.Skip("skipping test; see http://golang.org/issue/9554")
}
const backendResponse = "I am the backend"
reqInFlight := make(chan struct{})
backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
close(reqInFlight)
select {
case <-time.After(10 * time.Second):
// Note: this should only happen in broken implementations, and the
// closenotify case should be instantaneous.
t.Log("Failed to close backend connection")
t.Fail()
case <-w.(http.CloseNotifier).CloseNotify():
}
w.WriteHeader(http.StatusOK)
w.Write([]byte(backendResponse))
}))
defer backend.Close()
backend.Config.ErrorLog = log.New(ioutil.Discard, "", 0)
backendURL, err := url.Parse(backend.URL)
if err != nil {
t.Fatal(err)
}
proxyHandler := NewSingleHostReverseProxy(backendURL)
// Discards errors of the form:
// http: proxy error: read tcp 127.0.0.1:44643: use of closed network connection
proxyHandler.ErrorLog = log.New(ioutil.Discard, "", 0)
frontend := httptest.NewServer(proxyHandler)
defer frontend.Close()
getReq, _ := http.NewRequest("GET", frontend.URL, nil)
go func() {
<-reqInFlight
http.DefaultTransport.(*http.Transport).CancelRequest(getReq)
}()
res, err := http.DefaultClient.Do(getReq)
if res != nil {
t.Fatal("Non-nil response")
}
if err == nil {
// This should be an error like:
// Get http://127.0.0.1:58079: read tcp 127.0.0.1:58079:
// use of closed network connection
t.Fatal("DefaultClient.Do() returned nil error")
}
}

View file

@ -2384,18 +2384,24 @@ func TestRequestBodyCloseDoesntBlock(t *testing.T) {
}
}
func TestResponseWriterWriteStringAllocs(t *testing.T) {
// test that ResponseWriter implements io.stringWriter.
func TestResponseWriterWriteString(t *testing.T) {
okc := make(chan bool, 1)
ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) {
if r.URL.Path == "/s" {
io.WriteString(w, "Hello world")
} else {
w.Write([]byte("Hello world"))
type stringWriter interface {
WriteString(s string) (n int, err error)
}
_, ok := w.(stringWriter)
okc <- ok
}))
before := testing.AllocsPerRun(50, func() { ht.rawResponse("GET / HTTP/1.0") })
after := testing.AllocsPerRun(50, func() { ht.rawResponse("GET /s HTTP/1.0") })
if int(after) >= int(before) {
t.Errorf("WriteString allocs of %v >= Write allocs of %v", after, before)
ht.rawResponse("GET / HTTP/1.0")
select {
case ok := <-okc:
if !ok {
t.Error("ResponseWriter did not implement io.stringWriter")
}
default:
t.Error("handler was never called")
}
}

View file

@ -1530,6 +1530,7 @@ type gcProg struct {
gc []byte
size uintptr // size of type in bytes
hasPtr bool
lastZero uintptr // largest offset of a zero-byte field
}
func (gc *gcProg) append(v byte) {
@ -1542,6 +1543,9 @@ func (gc *gcProg) appendProg(t *rtype) {
gc.align(uintptr(t.align))
if !t.pointers() {
gc.size += t.size
if t.size == 0 {
gc.lastZero = gc.size
}
return
}
switch t.Kind() {
@ -1566,11 +1570,15 @@ func (gc *gcProg) appendProg(t *rtype) {
gc.appendWord(bitsPointer)
gc.appendWord(bitsPointer)
case Struct:
oldsize := gc.size
c := t.NumField()
for i := 0; i < c; i++ {
gc.appendProg(t.Field(i).Type.common())
}
gc.align(uintptr(t.align))
if gc.size > oldsize + t.size {
panic("reflect: struct components are larger than the struct itself")
}
gc.size = oldsize + t.size
}
}
@ -1595,6 +1603,9 @@ func (gc *gcProg) finalize() (unsafe.Pointer, bool) {
if gc.size == 0 {
return nil, false
}
if gc.lastZero == gc.size {
gc.size++
}
ptrsize := unsafe.Sizeof(uintptr(0))
gc.align(ptrsize)
nptr := gc.size / ptrsize

View file

@ -732,7 +732,7 @@ func (v Value) Field(i int) Value {
// Either flagIndir is set and v.ptr points at struct,
// or flagIndir is not set and v.ptr is the actual struct data.
// In the former case, we want v.ptr + offset.
// In the latter case, we must be have field.offset = 0,
// In the latter case, we must have field.offset = 0,
// so v.ptr + field.offset is still okay.
ptr := unsafe.Pointer(uintptr(v.ptr) + field.offset)
return Value{typ, ptr, fl}

View file

@ -118,6 +118,7 @@ export GOTRACEBACK=2
go test -ldflags '-linkmode=auto' || exit 1
# linkmode=internal fails on dragonfly since errno is a TLS relocation.
[ "$GOHOSTOS" == dragonfly ] || go test -ldflags '-linkmode=internal' || exit 1
# TODO(austin): Add linux-ppc64(le) once external linking works (issue #8912)
case "$GOHOSTOS-$GOARCH" in
openbsd-386 | openbsd-amd64)
# test linkmode=external, but __thread not supported, so skip testtls.
@ -180,17 +181,6 @@ linux-linux-amd64-1 | freebsd-freebsd-amd64-1 | darwin-darwin-amd64-1)
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.
# It doesn't work at all now that we disallow C code
# outside runtime. Once runtime has no C code it won't
# even be necessary.
# [ "$CGO_ENABLED" != 1 ] || [ "$GOOS" == darwin ] ||
# (xcd ../misc/cgo/testcdefs
# ./test.bash || exit 1
# ) || exit $?
[ "$CGO_ENABLED" != 1 ] || [ "$GOOS" == darwin ] ||
(xcd ../misc/cgo/testgodefs
./test.bash || exit 1

View file

@ -29,13 +29,25 @@ if not {
GOROOT_FINAL = ()
echo '# Testing packages.'
time go test std -short -timeout 120s
time go test std -short -timeout 240s
echo
# Temporary GCE builder hack until Plan 9 on GCE is fast enough.
# See https://golang.org/issue/9491
if(~ $GOTESTONLY std) {
echo
echo PARTIAL TESTS PASSED: std
exit
}
# We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code,
# creation of first goroutines and first garbage collections in the parallel setting.
# TODO(bradfitz,0intro): make this not be 15 minutes once Plan 9 runs quickly on GCE.
# Linux does 63 seconds on GCE, but Plan 9 was failing with 8 minutes.
# See issue 8393 and 9491.
# TODO(bradfitz,0intro): remove -v once we see some a successful build.
echo '# GOMAXPROCS=2 runtime -cpu=1,2,4'
GOMAXPROCS=2 go test runtime -short -timeout 240s -cpu 1,2,4
GOMAXPROCS=2 go test runtime -v -short -timeout 15m -cpu 1,2,4
echo
echo '# sync -cpu=10'

View file

@ -40,21 +40,45 @@ const (
type typeAlg struct {
// function for hashing objects of this type
// (ptr to object, size, seed) -> hash
hash func(unsafe.Pointer, uintptr, uintptr) uintptr
// (ptr to object, seed) -> hash
hash func(unsafe.Pointer, uintptr) uintptr
// function for comparing objects of this type
// (ptr to object A, ptr to object B, size) -> ==?
equal func(unsafe.Pointer, unsafe.Pointer, uintptr) bool
// (ptr to object A, ptr to object B) -> ==?
equal func(unsafe.Pointer, unsafe.Pointer) bool
}
func memhash0(p unsafe.Pointer, h uintptr) uintptr {
return h
}
func memhash8(p unsafe.Pointer, h uintptr) uintptr {
return memhash(p, h, 1)
}
func memhash16(p unsafe.Pointer, h uintptr) uintptr {
return memhash(p, h, 2)
}
func memhash32(p unsafe.Pointer, h uintptr) uintptr {
return memhash(p, h, 4)
}
func memhash64(p unsafe.Pointer, h uintptr) uintptr {
return memhash(p, h, 8)
}
func memhash128(p unsafe.Pointer, h uintptr) uintptr {
return memhash(p, h, 16)
}
// memhash_varlen is defined in assembly because it needs access
// to the closure. It appears here to provide an argument
// signature for the assembly routine.
func memhash_varlen(p unsafe.Pointer, h uintptr) uintptr
var algarray = [alg_max]typeAlg{
alg_MEM: {memhash, memequal},
alg_MEM0: {memhash, memequal0},
alg_MEM8: {memhash, memequal8},
alg_MEM16: {memhash, memequal16},
alg_MEM32: {memhash, memequal32},
alg_MEM64: {memhash, memequal64},
alg_MEM128: {memhash, memequal128},
alg_MEM: {nil, nil}, // not used
alg_MEM0: {memhash0, memequal0},
alg_MEM8: {memhash8, memequal8},
alg_MEM16: {memhash16, memequal16},
alg_MEM32: {memhash32, memequal32},
alg_MEM64: {memhash64, memequal64},
alg_MEM128: {memhash128, memequal128},
alg_NOEQ: {nil, nil},
alg_NOEQ0: {nil, nil},
alg_NOEQ8: {nil, nil},
@ -75,14 +99,14 @@ var algarray = [alg_max]typeAlg{
var useAeshash bool
// in asm_*.s
func aeshash(p unsafe.Pointer, s, h uintptr) uintptr
func aeshash32(p unsafe.Pointer, s, h uintptr) uintptr
func aeshash64(p unsafe.Pointer, s, h uintptr) uintptr
func aeshashstr(p unsafe.Pointer, s, h uintptr) uintptr
func aeshash(p unsafe.Pointer, h, s uintptr) uintptr
func aeshash32(p unsafe.Pointer, h uintptr) uintptr
func aeshash64(p unsafe.Pointer, h uintptr) uintptr
func aeshashstr(p unsafe.Pointer, h uintptr) uintptr
func strhash(a unsafe.Pointer, s, h uintptr) uintptr {
func strhash(a unsafe.Pointer, h uintptr) uintptr {
x := (*stringStruct)(a)
return memhash(x.str, uintptr(x.len), h)
return memhash(x.str, h, uintptr(x.len))
}
// NOTE: Because NaN != NaN, a map can contain any
@ -90,7 +114,7 @@ func strhash(a unsafe.Pointer, s, h uintptr) uintptr {
// To avoid long hash chains, we assign a random number
// as the hash value for a NaN.
func f32hash(p unsafe.Pointer, s, h uintptr) uintptr {
func f32hash(p unsafe.Pointer, h uintptr) uintptr {
f := *(*float32)(p)
switch {
case f == 0:
@ -98,11 +122,11 @@ func f32hash(p unsafe.Pointer, s, h uintptr) uintptr {
case f != f:
return c1 * (c0 ^ h ^ uintptr(fastrand1())) // any kind of NaN
default:
return memhash(p, 4, h)
return memhash(p, h, 4)
}
}
func f64hash(p unsafe.Pointer, s, h uintptr) uintptr {
func f64hash(p unsafe.Pointer, h uintptr) uintptr {
f := *(*float64)(p)
switch {
case f == 0:
@ -110,21 +134,21 @@ func f64hash(p unsafe.Pointer, s, h uintptr) uintptr {
case f != f:
return c1 * (c0 ^ h ^ uintptr(fastrand1())) // any kind of NaN
default:
return memhash(p, 8, h)
return memhash(p, h, 8)
}
}
func c64hash(p unsafe.Pointer, s, h uintptr) uintptr {
func c64hash(p unsafe.Pointer, h uintptr) uintptr {
x := (*[2]float32)(p)
return f32hash(unsafe.Pointer(&x[1]), 4, f32hash(unsafe.Pointer(&x[0]), 4, h))
return f32hash(unsafe.Pointer(&x[1]), f32hash(unsafe.Pointer(&x[0]), h))
}
func c128hash(p unsafe.Pointer, s, h uintptr) uintptr {
func c128hash(p unsafe.Pointer, h uintptr) uintptr {
x := (*[2]float64)(p)
return f64hash(unsafe.Pointer(&x[1]), 8, f64hash(unsafe.Pointer(&x[0]), 8, h))
return f64hash(unsafe.Pointer(&x[1]), f64hash(unsafe.Pointer(&x[0]), h))
}
func interhash(p unsafe.Pointer, s, h uintptr) uintptr {
func interhash(p unsafe.Pointer, h uintptr) uintptr {
a := (*iface)(p)
tab := a.tab
if tab == nil {
@ -136,13 +160,13 @@ func interhash(p unsafe.Pointer, s, h uintptr) uintptr {
panic(errorString("hash of unhashable type " + *t._string))
}
if isDirectIface(t) {
return c1 * fn(unsafe.Pointer(&a.data), uintptr(t.size), h^c0)
return c1 * fn(unsafe.Pointer(&a.data), h^c0)
} else {
return c1 * fn(a.data, uintptr(t.size), h^c0)
return c1 * fn(a.data, h^c0)
}
}
func nilinterhash(p unsafe.Pointer, s, h uintptr) uintptr {
func nilinterhash(p unsafe.Pointer, h uintptr) uintptr {
a := (*eface)(p)
t := a._type
if t == nil {
@ -153,9 +177,9 @@ func nilinterhash(p unsafe.Pointer, s, h uintptr) uintptr {
panic(errorString("hash of unhashable type " + *t._string))
}
if isDirectIface(t) {
return c1 * fn(unsafe.Pointer(&a.data), uintptr(t.size), h^c0)
return c1 * fn(unsafe.Pointer(&a.data), h^c0)
} else {
return c1 * fn(a.data, uintptr(t.size), h^c0)
return c1 * fn(a.data, h^c0)
}
}
@ -166,47 +190,47 @@ func memequal(p, q unsafe.Pointer, size uintptr) bool {
return memeq(p, q, size)
}
func memequal0(p, q unsafe.Pointer, size uintptr) bool {
func memequal0(p, q unsafe.Pointer) bool {
return true
}
func memequal8(p, q unsafe.Pointer, size uintptr) bool {
func memequal8(p, q unsafe.Pointer) bool {
return *(*int8)(p) == *(*int8)(q)
}
func memequal16(p, q unsafe.Pointer, size uintptr) bool {
func memequal16(p, q unsafe.Pointer) bool {
return *(*int16)(p) == *(*int16)(q)
}
func memequal32(p, q unsafe.Pointer, size uintptr) bool {
func memequal32(p, q unsafe.Pointer) bool {
return *(*int32)(p) == *(*int32)(q)
}
func memequal64(p, q unsafe.Pointer, size uintptr) bool {
func memequal64(p, q unsafe.Pointer) bool {
return *(*int64)(p) == *(*int64)(q)
}
func memequal128(p, q unsafe.Pointer, size uintptr) bool {
func memequal128(p, q unsafe.Pointer) bool {
return *(*[2]int64)(p) == *(*[2]int64)(q)
}
func f32equal(p, q unsafe.Pointer, size uintptr) bool {
func f32equal(p, q unsafe.Pointer) bool {
return *(*float32)(p) == *(*float32)(q)
}
func f64equal(p, q unsafe.Pointer, size uintptr) bool {
func f64equal(p, q unsafe.Pointer) bool {
return *(*float64)(p) == *(*float64)(q)
}
func c64equal(p, q unsafe.Pointer, size uintptr) bool {
func c64equal(p, q unsafe.Pointer) bool {
return *(*complex64)(p) == *(*complex64)(q)
}
func c128equal(p, q unsafe.Pointer, size uintptr) bool {
func c128equal(p, q unsafe.Pointer) bool {
return *(*complex128)(p) == *(*complex128)(q)
}
func strequal(p, q unsafe.Pointer, size uintptr) bool {
func strequal(p, q unsafe.Pointer) bool {
return *(*string)(p) == *(*string)(q)
}
func interequal(p, q unsafe.Pointer, size uintptr) bool {
func interequal(p, q unsafe.Pointer) bool {
return ifaceeq(*(*interface {
f()
})(p), *(*interface {
f()
})(q))
}
func nilinterequal(p, q unsafe.Pointer, size uintptr) bool {
func nilinterequal(p, q unsafe.Pointer) bool {
return efaceeq(*(*interface{})(p), *(*interface{})(q))
}
func efaceeq(p, q interface{}) bool {
@ -224,9 +248,9 @@ func efaceeq(p, q interface{}) bool {
panic(errorString("comparing uncomparable type " + *t._string))
}
if isDirectIface(t) {
return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)), uintptr(t.size))
return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)))
}
return eq(x.data, y.data, uintptr(t.size))
return eq(x.data, y.data)
}
func ifaceeq(p, q interface {
f()
@ -246,37 +270,37 @@ func ifaceeq(p, q interface {
panic(errorString("comparing uncomparable type " + *t._string))
}
if isDirectIface(t) {
return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)), uintptr(t.size))
return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)))
}
return eq(x.data, y.data, uintptr(t.size))
return eq(x.data, y.data)
}
// Testing adapters for hash quality tests (see hash_test.go)
func stringHash(s string, seed uintptr) uintptr {
return algarray[alg_STRING].hash(noescape(unsafe.Pointer(&s)), unsafe.Sizeof(s), seed)
return algarray[alg_STRING].hash(noescape(unsafe.Pointer(&s)), seed)
}
func bytesHash(b []byte, seed uintptr) uintptr {
s := (*sliceStruct)(unsafe.Pointer(&b))
return algarray[alg_MEM].hash(s.array, uintptr(s.len), seed)
return memhash(s.array, seed, uintptr(s.len))
}
func int32Hash(i uint32, seed uintptr) uintptr {
return algarray[alg_MEM32].hash(noescape(unsafe.Pointer(&i)), 4, seed)
return algarray[alg_MEM32].hash(noescape(unsafe.Pointer(&i)), seed)
}
func int64Hash(i uint64, seed uintptr) uintptr {
return algarray[alg_MEM64].hash(noescape(unsafe.Pointer(&i)), 8, seed)
return algarray[alg_MEM64].hash(noescape(unsafe.Pointer(&i)), seed)
}
func efaceHash(i interface{}, seed uintptr) uintptr {
return algarray[alg_NILINTER].hash(noescape(unsafe.Pointer(&i)), unsafe.Sizeof(i), seed)
return algarray[alg_NILINTER].hash(noescape(unsafe.Pointer(&i)), seed)
}
func ifaceHash(i interface {
F()
}, seed uintptr) uintptr {
return algarray[alg_INTER].hash(noescape(unsafe.Pointer(&i)), unsafe.Sizeof(i), seed)
return algarray[alg_INTER].hash(noescape(unsafe.Pointer(&i)), seed)
}
// Testing adapter for memclr
@ -301,12 +325,8 @@ func init() {
cpuid_ecx&(1<<9) != 0 && // sse3 (pshufb)
cpuid_ecx&(1<<19) != 0 { // sse4.1 (pinsr{d,q})
useAeshash = true
algarray[alg_MEM].hash = aeshash
algarray[alg_MEM8].hash = aeshash
algarray[alg_MEM16].hash = aeshash
algarray[alg_MEM32].hash = aeshash32
algarray[alg_MEM64].hash = aeshash64
algarray[alg_MEM128].hash = aeshash
algarray[alg_STRING].hash = aeshashstr
// Initialize with random data so hash collisions will be hard to engineer.
getRandomData(aeskeysched[:])

View file

@ -8,7 +8,7 @@ const (
thechar = '9'
_BigEndian = 1
_CacheLineSize = 64
_RuntimeGogoBytes = 64
_RuntimeGogoBytes = 72
_PhysPageSize = 65536
_PCQuantum = 4
_Int64Align = 8

View file

@ -8,7 +8,7 @@ const (
thechar = '9'
_BigEndian = 0
_CacheLineSize = 64
_RuntimeGogoBytes = 64
_RuntimeGogoBytes = 72
_PhysPageSize = 65536
_PCQuantum = 4
_Int64Align = 8

View file

@ -451,7 +451,7 @@ TEXT runtime·cas(SB), NOSPLIT, $0-13
MOVL new+8(FP), CX
LOCK
CMPXCHGL CX, 0(BX)
SETEQ , ret+12(FP)
SETEQ ret+12(FP)
RET
TEXT runtime·casuintptr(SB), NOSPLIT, $0-13
@ -482,7 +482,7 @@ TEXT runtime·cas64(SB), NOSPLIT, $0-21
MOVL new_hi+16(FP), CX
LOCK
CMPXCHG8B 0(BP)
SETEQ , ret+20(FP)
SETEQ ret+20(FP)
RET
// bool casp(void **p, void *old, void *new)
@ -498,7 +498,7 @@ TEXT runtime·casp1(SB), NOSPLIT, $0-13
MOVL new+8(FP), CX
LOCK
CMPXCHGL CX, 0(BX)
SETEQ , ret+12(FP)
SETEQ ret+12(FP)
RET
// uint32 xadd(uint32 volatile *val, int32 delta)
@ -887,23 +887,42 @@ TEXT runtime·emptyfunc(SB),0,$0-0
TEXT runtime·abort(SB),NOSPLIT,$0-0
INT $0x3
// memhash_varlen(p unsafe.Pointer, h seed) uintptr
// redirects to memhash(p, h, size) using the size
// stored in the closure.
TEXT runtime·memhash_varlen(SB),NOSPLIT,$16-12
GO_ARGS
NO_LOCAL_POINTERS
MOVL p+0(FP), AX
MOVL h+4(FP), BX
MOVL 4(DX), CX
MOVL AX, 0(SP)
MOVL BX, 4(SP)
MOVL CX, 8(SP)
CALL runtime·memhash(SB)
MOVL 12(SP), AX
MOVL AX, ret+8(FP)
RET
// hash function using AES hardware instructions
TEXT runtime·aeshash(SB),NOSPLIT,$0-16
MOVL p+0(FP), AX // ptr to data
MOVL s+4(FP), CX // size
MOVL s+8(FP), CX // size
LEAL ret+12(FP), DX
JMP runtime·aeshashbody(SB)
TEXT runtime·aeshashstr(SB),NOSPLIT,$0-16
TEXT runtime·aeshashstr(SB),NOSPLIT,$0-12
MOVL p+0(FP), AX // ptr to string object
// s+4(FP) is ignored, it is always sizeof(String)
MOVL 4(AX), CX // length of string
MOVL (AX), AX // string data
LEAL ret+8(FP), DX
JMP runtime·aeshashbody(SB)
// AX: data
// CX: length
TEXT runtime·aeshashbody(SB),NOSPLIT,$0-16
MOVL h+8(FP), X6 // seed to low 64 bits of xmm6
// DX: address to put return value
TEXT runtime·aeshashbody(SB),NOSPLIT,$0-0
MOVL h+4(FP), X6 // seed to low 64 bits of xmm6
PINSRD $2, CX, X6 // size to high 64 bits of xmm6
PSHUFHW $0, X6, X6 // replace size with its low 2 bytes repeated 4 times
MOVO runtime·aeskeysched(SB), X7
@ -934,7 +953,7 @@ aes0to15:
AESENC X6, X0
AESENC X7, X0
AESENC X7, X0
MOVL X0, ret+12(FP)
MOVL X0, (DX)
RET
endofpage:
@ -947,13 +966,13 @@ endofpage:
AESENC X6, X0
AESENC X7, X0
AESENC X7, X0
MOVL X0, ret+12(FP)
MOVL X0, (DX)
RET
aes0:
// return input seed
MOVL h+8(FP), AX
MOVL AX, ret+12(FP)
MOVL h+4(FP), AX
MOVL AX, (DX)
RET
aes16:
@ -961,7 +980,7 @@ aes16:
AESENC X6, X0
AESENC X7, X0
AESENC X7, X0
MOVL X0, ret+12(FP)
MOVL X0, (DX)
RET
@ -980,7 +999,7 @@ aes17to32:
// combine results
PXOR X1, X0
MOVL X0, ret+12(FP)
MOVL X0, (DX)
RET
aes33to64:
@ -1005,7 +1024,7 @@ aes33to64:
PXOR X2, X0
PXOR X3, X1
PXOR X1, X0
MOVL X0, ret+12(FP)
MOVL X0, (DX)
RET
aes65plus:
@ -1059,29 +1078,27 @@ aesloop:
PXOR X2, X0
PXOR X3, X1
PXOR X1, X0
MOVL X0, ret+12(FP)
MOVL X0, (DX)
RET
TEXT runtime·aeshash32(SB),NOSPLIT,$0-16
TEXT runtime·aeshash32(SB),NOSPLIT,$0-12
MOVL p+0(FP), AX // ptr to data
// s+4(FP) is ignored, it is always sizeof(int32)
MOVL h+8(FP), X0 // seed
MOVL h+4(FP), X0 // seed
PINSRD $1, (AX), X0 // data
AESENC runtime·aeskeysched+0(SB), X0
AESENC runtime·aeskeysched+16(SB), X0
AESENC runtime·aeskeysched+32(SB), X0
MOVL X0, ret+12(FP)
MOVL X0, ret+8(FP)
RET
TEXT runtime·aeshash64(SB),NOSPLIT,$0-16
TEXT runtime·aeshash64(SB),NOSPLIT,$0-12
MOVL p+0(FP), AX // ptr to data
// s+4(FP) is ignored, it is always sizeof(int64)
MOVQ (AX), X0 // data
PINSRD $2, h+8(FP), X0 // seed
PINSRD $2, h+4(FP), X0 // seed
AESENC runtime·aeskeysched+0(SB), X0
AESENC runtime·aeskeysched+16(SB), X0
AESENC runtime·aeskeysched+32(SB), X0
MOVL X0, ret+12(FP)
MOVL X0, ret+8(FP)
RET
// simple mask to get rid of data in the high part of the register.
@ -1260,6 +1277,20 @@ TEXT runtime·memeq(SB),NOSPLIT,$0-13
MOVB AX, ret+12(FP)
RET
// memequal_varlen(a, b unsafe.Pointer) bool
TEXT runtime·memequal_varlen(SB),NOSPLIT,$0-9
MOVL a+0(FP), SI
MOVL b+4(FP), DI
CMPL SI, DI
JEQ eq
MOVL 4(DX), BX // compiler stores size at offset 4 in the closure
CALL runtime·memeqbody(SB)
MOVB AX, ret+8(FP)
RET
eq:
MOVB $1, ret+8(FP)
RET
// eqstring tests whether two strings are equal.
// See runtime_test.go:eqstring_generic for
// equivalent Go code.

Some files were not shown because too many files have changed in this diff Show more