From 97572d5552699fbc7cce215f83d7b02265e7f1de Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 8 Feb 2016 22:50:17 -0500 Subject: [PATCH 001/117] cmd/go: silence standard imports non-standard error for non-existent import target This error only affects the compilation of the standard library, but I discovered that if you import "notexist" from the standard library then you get both an error about notexist not existing and an error about notexist being a non-standard package (because the non-existant package is in fact not a standard package). Silence the second error. Change-Id: Ib4c1523e89844260fde90de3459ec1e752df8f25 Reviewed-on: https://go-review.googlesource.com/19383 Run-TryBot: Russ Cox Reviewed-by: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/cmd/go/pkg.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go index a804ccd277..0c0cf07e71 100644 --- a/src/cmd/go/pkg.go +++ b/src/cmd/go/pkg.go @@ -967,7 +967,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package } } } - if p.Standard && !p1.Standard && p.Error == nil { + if p.Standard && p.Error == nil && !p1.Standard && p1.Error == nil { p.Error = &PackageError{ ImportStack: stk.copy(), Err: fmt.Sprintf("non-standard import %q in standard package %q", path, p.ImportPath), From 558a213d55beb23846e45a4500f3388f91dadb75 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 8 Feb 2016 22:51:34 -0500 Subject: [PATCH 002/117] build: mv cmd/vendor cmd/internal/unvendor And update two imports in cmd/internal/objfile/disasm.go. This makes GO15VENDOREXPERIMENT=0 ./make.bash work. For Go 1.7 we will move it back. Fixes #14236. Change-Id: I429c9af4baff8496f83d113b1b03b90e309f4f48 Reviewed-on: https://go-review.googlesource.com/19384 Reviewed-by: Brad Fitzpatrick Run-TryBot: Russ Cox TryBot-Result: Gobot Gobot --- misc/nacl/testzip.proto | 24 +++++++++---------- src/cmd/internal/objfile/disasm.go | 4 ++-- .../golang.org/x/arch/arm/armasm/Makefile | 0 .../golang.org/x/arch/arm/armasm/decode.go | 0 .../x/arch/arm/armasm/decode_test.go | 0 .../golang.org/x/arch/arm/armasm/ext_test.go | 0 .../golang.org/x/arch/arm/armasm/gnu.go | 0 .../golang.org/x/arch/arm/armasm/inst.go | 0 .../x/arch/arm/armasm/objdump_test.go | 0 .../x/arch/arm/armasm/objdumpext_test.go | 0 .../golang.org/x/arch/arm/armasm/plan9x.go | 0 .../golang.org/x/arch/arm/armasm/tables.go | 0 .../x/arch/arm/armasm/testdata/Makefile | 0 .../x/arch/arm/armasm/testdata/decode.txt | 0 .../golang.org/x/arch/x86/x86asm/Makefile | 0 .../golang.org/x/arch/x86/x86asm/decode.go | 0 .../x/arch/x86/x86asm/decode_test.go | 0 .../golang.org/x/arch/x86/x86asm/ext_test.go | 0 .../golang.org/x/arch/x86/x86asm/gnu.go | 0 .../golang.org/x/arch/x86/x86asm/inst.go | 0 .../golang.org/x/arch/x86/x86asm/inst_test.go | 0 .../golang.org/x/arch/x86/x86asm/intel.go | 0 .../x/arch/x86/x86asm/objdump_test.go | 0 .../x/arch/x86/x86asm/objdumpext_test.go | 0 .../x/arch/x86/x86asm/plan9ext_test.go | 0 .../golang.org/x/arch/x86/x86asm/plan9x.go | 0 .../x/arch/x86/x86asm/plan9x_test.go | 0 .../golang.org/x/arch/x86/x86asm/tables.go | 0 .../x/arch/x86/x86asm/testdata/Makefile | 0 .../x/arch/x86/x86asm/testdata/decode.txt | 0 .../x/arch/x86/x86asm/testdata/libmach8db.c | 0 .../golang.org/x/arch/x86/x86asm/xed_test.go | 0 .../x/arch/x86/x86asm/xedext_test.go | 0 .../{vendor => internal/unvendor}/vendor.json | 0 34 files changed, 14 insertions(+), 14 deletions(-) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/arm/armasm/Makefile (100%) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/arm/armasm/decode.go (100%) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/arm/armasm/decode_test.go (100%) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/arm/armasm/ext_test.go (100%) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/arm/armasm/gnu.go (100%) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/arm/armasm/inst.go (100%) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/arm/armasm/objdump_test.go (100%) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/arm/armasm/objdumpext_test.go (100%) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/arm/armasm/plan9x.go (100%) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/arm/armasm/tables.go (100%) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/arm/armasm/testdata/Makefile (100%) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/arm/armasm/testdata/decode.txt (100%) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/x86/x86asm/Makefile (100%) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/x86/x86asm/decode.go (100%) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/x86/x86asm/decode_test.go (100%) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/x86/x86asm/ext_test.go (100%) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/x86/x86asm/gnu.go (100%) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/x86/x86asm/inst.go (100%) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/x86/x86asm/inst_test.go (100%) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/x86/x86asm/intel.go (100%) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/x86/x86asm/objdump_test.go (100%) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/x86/x86asm/objdumpext_test.go (100%) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/x86/x86asm/plan9ext_test.go (100%) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/x86/x86asm/plan9x.go (100%) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/x86/x86asm/plan9x_test.go (100%) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/x86/x86asm/tables.go (100%) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/x86/x86asm/testdata/Makefile (100%) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/x86/x86asm/testdata/decode.txt (100%) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/x86/x86asm/testdata/libmach8db.c (100%) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/x86/x86asm/xed_test.go (100%) rename src/cmd/{vendor => internal/unvendor}/golang.org/x/arch/x86/x86asm/xedext_test.go (100%) rename src/cmd/{vendor => internal/unvendor}/vendor.json (100%) diff --git a/misc/nacl/testzip.proto b/misc/nacl/testzip.proto index b51e8da5c7..dcb156350a 100644 --- a/misc/nacl/testzip.proto +++ b/misc/nacl/testzip.proto @@ -27,6 +27,18 @@ go src=.. internal objfile objfile.go + unvendor + golang.org + x + arch + arm + armasm + testdata + + + x86 + x86asm + testdata + + gofmt gofmt.go gofmt_test.go @@ -35,18 +47,6 @@ go src=.. newlink testdata + - vendor - golang.org - x - arch - arm - armasm - testdata - + - x86 - x86asm - testdata - + archive tar testdata diff --git a/src/cmd/internal/objfile/disasm.go b/src/cmd/internal/objfile/disasm.go index 6495dfb356..f038883dc0 100644 --- a/src/cmd/internal/objfile/disasm.go +++ b/src/cmd/internal/objfile/disasm.go @@ -15,8 +15,8 @@ import ( "strings" "text/tabwriter" - "golang.org/x/arch/arm/armasm" - "golang.org/x/arch/x86/x86asm" + "cmd/internal/unvendor/golang.org/x/arch/arm/armasm" + "cmd/internal/unvendor/golang.org/x/arch/x86/x86asm" ) // Disasm is a disassembler for a given File. diff --git a/src/cmd/vendor/golang.org/x/arch/arm/armasm/Makefile b/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/Makefile similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/arm/armasm/Makefile rename to src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/Makefile diff --git a/src/cmd/vendor/golang.org/x/arch/arm/armasm/decode.go b/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/decode.go similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/arm/armasm/decode.go rename to src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/decode.go diff --git a/src/cmd/vendor/golang.org/x/arch/arm/armasm/decode_test.go b/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/decode_test.go similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/arm/armasm/decode_test.go rename to src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/decode_test.go diff --git a/src/cmd/vendor/golang.org/x/arch/arm/armasm/ext_test.go b/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/ext_test.go similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/arm/armasm/ext_test.go rename to src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/ext_test.go diff --git a/src/cmd/vendor/golang.org/x/arch/arm/armasm/gnu.go b/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/gnu.go similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/arm/armasm/gnu.go rename to src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/gnu.go diff --git a/src/cmd/vendor/golang.org/x/arch/arm/armasm/inst.go b/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/inst.go similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/arm/armasm/inst.go rename to src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/inst.go diff --git a/src/cmd/vendor/golang.org/x/arch/arm/armasm/objdump_test.go b/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/objdump_test.go similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/arm/armasm/objdump_test.go rename to src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/objdump_test.go diff --git a/src/cmd/vendor/golang.org/x/arch/arm/armasm/objdumpext_test.go b/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/objdumpext_test.go similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/arm/armasm/objdumpext_test.go rename to src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/objdumpext_test.go diff --git a/src/cmd/vendor/golang.org/x/arch/arm/armasm/plan9x.go b/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/plan9x.go similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/arm/armasm/plan9x.go rename to src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/plan9x.go diff --git a/src/cmd/vendor/golang.org/x/arch/arm/armasm/tables.go b/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/tables.go similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/arm/armasm/tables.go rename to src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/tables.go diff --git a/src/cmd/vendor/golang.org/x/arch/arm/armasm/testdata/Makefile b/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/testdata/Makefile similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/arm/armasm/testdata/Makefile rename to src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/testdata/Makefile diff --git a/src/cmd/vendor/golang.org/x/arch/arm/armasm/testdata/decode.txt b/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/testdata/decode.txt similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/arm/armasm/testdata/decode.txt rename to src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/testdata/decode.txt diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/Makefile b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/Makefile similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/Makefile rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/Makefile diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/decode.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/decode.go similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/decode.go rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/decode.go diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/decode_test.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/decode_test.go similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/decode_test.go rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/decode_test.go diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/ext_test.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/ext_test.go similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/ext_test.go rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/ext_test.go diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/gnu.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/gnu.go similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/gnu.go rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/gnu.go diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/inst.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/inst.go similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/inst.go rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/inst.go diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/inst_test.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/inst_test.go similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/inst_test.go rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/inst_test.go diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/intel.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/intel.go similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/intel.go rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/intel.go diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/objdump_test.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/objdump_test.go similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/objdump_test.go rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/objdump_test.go diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/objdumpext_test.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/objdumpext_test.go similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/objdumpext_test.go rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/objdumpext_test.go diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9ext_test.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/plan9ext_test.go similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9ext_test.go rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/plan9ext_test.go diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9x.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/plan9x.go similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9x.go rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/plan9x.go diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9x_test.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/plan9x_test.go similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9x_test.go rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/plan9x_test.go diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/tables.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/tables.go similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/tables.go rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/tables.go diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/testdata/Makefile b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/testdata/Makefile similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/testdata/Makefile rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/testdata/Makefile diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/testdata/decode.txt b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/testdata/decode.txt similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/testdata/decode.txt rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/testdata/decode.txt diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/testdata/libmach8db.c b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/testdata/libmach8db.c similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/testdata/libmach8db.c rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/testdata/libmach8db.c diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/xed_test.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/xed_test.go similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/xed_test.go rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/xed_test.go diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/xedext_test.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/xedext_test.go similarity index 100% rename from src/cmd/vendor/golang.org/x/arch/x86/x86asm/xedext_test.go rename to src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/xedext_test.go diff --git a/src/cmd/vendor/vendor.json b/src/cmd/internal/unvendor/vendor.json similarity index 100% rename from src/cmd/vendor/vendor.json rename to src/cmd/internal/unvendor/vendor.json From ee451770a76e138e05d2cf499b0eb25e69122432 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 8 Feb 2016 23:46:27 -0500 Subject: [PATCH 003/117] cmd/go: use GOPATH order for compile -I and link -L options Given GOPATH=p1:p2 and source code of just the right form, the go command could previously end up invoking the compiler with -I p2 -I p1 or the linker with -L p2 -L p1, so that compiled packages in p2 incorrectly shadowed packages in p1. If foo were in both p1 and p2 and the compilation of bar were such that the -I and -L options were inverted in this way, then GOPATH=p2 go install foo GOPATH=p1:p2 go install bar would get the p2 copy of foo instead of the (expected) p1 copy of foo. This manifested in real usage in a few different ways, but in all the root cause was that the -I or -L option sequence did not match GOPATH. Make it match GOPATH. Fixes #14176 (second report). Fixes #14192. Related but less common issue #14271 not fixed. Change-Id: I9c0f69042bb2bf92c9fc370535da2c60a1187d30 Reviewed-on: https://go-review.googlesource.com/19385 Reviewed-by: Ian Lance Taylor Run-TryBot: Russ Cox --- src/cmd/go/build.go | 18 +++++++++++++++ src/cmd/go/go_test.go | 53 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go index a1f925ed0b..f2a2a6014f 100644 --- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -667,6 +667,7 @@ var ( goarch string goos string exeSuffix string + gopath []string ) func init() { @@ -675,6 +676,7 @@ func init() { if goos == "windows" { exeSuffix = ".exe" } + gopath = filepath.SplitList(buildContext.GOPATH) } // A builder holds global state about a build. @@ -1684,6 +1686,22 @@ func (b *builder) includeArgs(flag string, all []*action) []string { inc = append(inc, flag, b.work) // Finally, look in the installed package directories for each action. + // First add the package dirs corresponding to GOPATH entries + // in the original GOPATH order. + need := map[string]*build.Package{} + for _, a1 := range all { + if a1.p != nil && a1.pkgdir == a1.p.build.PkgRoot { + need[a1.p.build.Root] = a1.p.build + } + } + for _, root := range gopath { + if p := need[root]; p != nil && !incMap[p.PkgRoot] { + incMap[p.PkgRoot] = true + inc = append(inc, flag, p.PkgTargetRoot) + } + } + + // Then add anything that's left. for _, a1 := range all { if a1.p == nil { continue diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index 6d12f75073..c60971efed 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -2565,6 +2565,59 @@ func TestGoInstallShadowedGOPATH(t *testing.T) { tg.grepStderr("no install location for.*gopath2.src.test: hidden by .*gopath1.src.test", "missing error") } +func TestGoBuildGOPATHOrder(t *testing.T) { + // golang.org/issue/14176#issuecomment-179895769 + // golang.org/issue/14192 + // -I arguments to compiler could end up not in GOPATH order, + // leading to unexpected import resolution in the compiler. + // This is still not a complete fix (see golang.org/issue/14271 and next test) + // but it is clearly OK and enough to fix both of the two reported + // instances of the underlying problem. It will have to do for now. + + tg := testgo(t) + defer tg.cleanup() + tg.makeTempdir() + tg.setenv("GOPATH", tg.path("p1")+string(filepath.ListSeparator)+tg.path("p2")) + + tg.tempFile("p1/src/foo/foo.go", "package foo\n") + tg.tempFile("p2/src/baz/baz.go", "package baz\n") + tg.tempFile("p2/pkg/"+runtime.GOOS+"_"+runtime.GOARCH+"/foo.a", "bad\n") + tg.tempFile("p1/src/bar/bar.go", ` + package bar + import _ "baz" + import _ "foo" + `) + + tg.run("install", "-x", "bar") +} + +func TestGoBuildGOPATHOrderBroken(t *testing.T) { + // This test is known not to work. + // See golang.org/issue/14271. + t.Skip("golang.org/issue/14271") + + tg := testgo(t) + defer tg.cleanup() + tg.makeTempdir() + + tg.tempFile("p1/src/foo/foo.go", "package foo\n") + tg.tempFile("p2/src/baz/baz.go", "package baz\n") + tg.tempFile("p1/pkg/"+runtime.GOOS+"_"+runtime.GOARCH+"/baz.a", "bad\n") + tg.tempFile("p2/pkg/"+runtime.GOOS+"_"+runtime.GOARCH+"/foo.a", "bad\n") + tg.tempFile("p1/src/bar/bar.go", ` + package bar + import _ "baz" + import _ "foo" + `) + + colon := string(filepath.ListSeparator) + tg.setenv("GOPATH", tg.path("p1")+colon+tg.path("p2")) + tg.run("install", "-x", "bar") + + tg.setenv("GOPATH", tg.path("p2")+colon+tg.path("p1")) + tg.run("install", "-x", "bar") +} + func TestIssue11709(t *testing.T) { tg := testgo(t) defer tg.cleanup() From 79d9f48c73124eb21db99efa4b97cee044f52700 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Tue, 9 Feb 2016 20:05:10 +0000 Subject: [PATCH 004/117] net/http: be more conservative about enabling http2 on Transports For now, don't enable http2 when Transport.TLSConfig != nil. See background in #14275. Also don't enable http2 when ExpectContinueTimeout is specified for now, in case somebody depends on that functionality. (It is not yet implemented in http2, and was only just added to net/http too in Go 1.6, so nobody would be setting it yet). Updates #14275 Updates #13851 Change-Id: I192d555f5fb0a567bd89b6ad87175bbdd7891ae3 Reviewed-on: https://go-review.googlesource.com/19424 Reviewed-by: Russ Cox Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/net/http/transport.go | 16 +++++++++++++++ src/net/http/transport_test.go | 37 ++++++++++++++++++++++------------ 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/src/net/http/transport.go b/src/net/http/transport.go index 41df906cf2..baf71d5e85 100644 --- a/src/net/http/transport.go +++ b/src/net/http/transport.go @@ -163,6 +163,22 @@ func (t *Transport) onceSetNextProtoDefaults() { return } if t.TLSNextProto != nil { + // This is the documented way to disable http2 on a + // Transport. + return + } + if t.TLSClientConfig != nil { + // Be conservative for now (for Go 1.6) at least and + // don't automatically enable http2 if they've + // specified a custom TLS config. Let them opt-in + // themselves via http2.ConfigureTransport so we don't + // surprise them by modifying their tls.Config. + // Issue 14275. + return + } + if t.ExpectContinueTimeout != 0 { + // Unsupported in http2, so disable http2 for now. + // Issue 13851. return } t2, err := http2configureTransport(t) diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go index 8cb89a4220..0c901b30a4 100644 --- a/src/net/http/transport_test.go +++ b/src/net/http/transport_test.go @@ -2885,23 +2885,34 @@ func TestTransportPrefersResponseOverWriteError(t *testing.T) { } func TestTransportAutomaticHTTP2(t *testing.T) { - tr := &Transport{} + testTransportAutoHTTP(t, &Transport{}, true) +} + +func TestTransportAutomaticHTTP2_TLSNextProto(t *testing.T) { + testTransportAutoHTTP(t, &Transport{ + TLSNextProto: make(map[string]func(string, *tls.Conn) RoundTripper), + }, false) +} + +func TestTransportAutomaticHTTP2_TLSConfig(t *testing.T) { + testTransportAutoHTTP(t, &Transport{ + TLSClientConfig: new(tls.Config), + }, false) +} + +func TestTransportAutomaticHTTP2_ExpectContinueTimeout(t *testing.T) { + testTransportAutoHTTP(t, &Transport{ + ExpectContinueTimeout: 1 * time.Second, + }, false) +} + +func testTransportAutoHTTP(t *testing.T, tr *Transport, wantH2 bool) { _, err := tr.RoundTrip(new(Request)) if err == nil { t.Error("expected error from RoundTrip") } - if tr.TLSNextProto["h2"] == nil { - t.Errorf("HTTP/2 not registered.") - } - - // Now with TLSNextProto set: - tr = &Transport{TLSNextProto: make(map[string]func(string, *tls.Conn) RoundTripper)} - _, err = tr.RoundTrip(new(Request)) - if err == nil { - t.Error("expected error from RoundTrip") - } - if tr.TLSNextProto["h2"] != nil { - t.Errorf("HTTP/2 registered, despite non-nil TLSNextProto field") + if reg := tr.TLSNextProto["h2"] != nil; reg != wantH2 { + t.Errorf("HTTP/2 registered = %v; want %v", reg, wantH2) } } From 811b785193e04c630f26f1cff83d276a572e150d Mon Sep 17 00:00:00 2001 From: Volker Dobler Date: Tue, 9 Feb 2016 14:39:52 +0100 Subject: [PATCH 005/117] net: make getmac based tests on windows more robust The Windows 7 getmac command may report the physical address of an adapter as "Disabled" or "N/A". Handle these two cases to make the tests more robust when building on Windows with manually disabled adapters or turned off hardware. Addresses issue #14130. Change-Id: I0c2f8554b4b6810568e4e60ed53857599401f296 Reviewed-on: https://go-review.googlesource.com/19411 Reviewed-by: Alex Brainman Run-TryBot: Alex Brainman TryBot-Result: Gobot Gobot Reviewed-by: Russ Cox --- src/net/net_windows_test.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/net/net_windows_test.go b/src/net/net_windows_test.go index 095a339e02..c26c6a77c9 100644 --- a/src/net/net_windows_test.go +++ b/src/net/net_windows_test.go @@ -487,8 +487,13 @@ func TestInterfaceHardwareAddrWithGetmac(t *testing.T) { // //Connection Name: Bluetooth Network Connection //Network Adapter: Bluetooth Device (Personal Area Network) - //Physical Address: XX-XX-XX-XX-XX-XX - //Transport Name: Media disconnected + //Physical Address: N/A + //Transport Name: Hardware not present + // + //Connection Name: VMware Network Adapter VMnet8 + //Network Adapter: VMware Virtual Ethernet Adapter for VMnet8 + //Physical Address: Disabled + //Transport Name: Disconnected // want := make(map[string]string) var name string @@ -516,6 +521,9 @@ func TestInterfaceHardwareAddrWithGetmac(t *testing.T) { if addr == "" { t.Fatal("empty address on \"Physical Address\" line: %q", line) } + if addr == "disabled" || addr == "n/a" { + continue + } addr = strings.Replace(addr, "-", ":", -1) want[name] = addr name = "" From 7ebf653fcc8510f260a1afbc3fb9e3de157dfe04 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 9 Feb 2016 12:58:35 -0800 Subject: [PATCH 006/117] go/internal/gcimporter: interpret relative srcDir relative to cwd 1) go/types.dir: Correctly return "." if there is no path. 2) go/internal/gcimporter.FindPkg: work-around for build.Import (build.Import doesn't produce expected result if srcDir is relative). See also issue 14282. Fixes #14215. Change-Id: Ia3721f9ad8a1115d2595fe99b04baaf30d5765f2 Reviewed-on: https://go-review.googlesource.com/19393 Reviewed-by: Russ Cox --- src/go/internal/gcimporter/gcimporter.go | 6 +++++- src/go/types/resolver.go | 10 ++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/go/internal/gcimporter/gcimporter.go b/src/go/internal/gcimporter/gcimporter.go index 0ef8eb4fc6..d70ec083c3 100644 --- a/src/go/internal/gcimporter/gcimporter.go +++ b/src/go/internal/gcimporter/gcimporter.go @@ -31,7 +31,8 @@ var pkgExts = [...]string{".a", ".o"} // FindPkg returns the filename and unique package id for an import // path based on package information provided by build.Import (using -// the build.Default build.Context). +// the build.Default build.Context). A relative srcDir is interpreted +// relative to the current working directory. // If no file was found, an empty filename is returned. // func FindPkg(path, srcDir string) (filename, id string) { @@ -44,6 +45,9 @@ func FindPkg(path, srcDir string) (filename, id string) { default: // "x" -> "$GOPATH/pkg/$GOOS_$GOARCH/x.ext", "x" // Don't require the source files to be present. + if abs, err := filepath.Abs(srcDir); err == nil { // see issue 14282 + srcDir = abs + } bp, _ := build.Import(path, srcDir, build.FindOnly|build.AllowBinary) if bp.PkgObj == "" { return diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go index 14148a585b..1536df5bf1 100644 --- a/src/go/types/resolver.go +++ b/src/go/types/resolver.go @@ -483,11 +483,9 @@ func pkgName(path string) string { // (Per the go/build package dependency tests, we cannot import // path/filepath and simply use filepath.Dir.) func dir(path string) string { - if i := strings.LastIndexAny(path, "/\\"); i >= 0 { - path = path[:i] + if i := strings.LastIndexAny(path, `/\`); i > 0 { + return path[:i] } - if path == "" { - path = "." - } - return path + // i <= 0 + return "." } From 53b66616736480152969fe1749f62e3da07644f7 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 10 Feb 2016 19:58:44 +0000 Subject: [PATCH 007/117] net/http/httptest: make Server.CloseClientConnections wait for conns to close httptest.Server was rewritten during Go 1.6, but CloseClientConnections was accidentally made async in the rewrite and not caught due to lack of tests. Restore the Go 1.5 behavior and add tests. Fixes #14290 Updates #14291 Change-Id: I14f01849066785053ccca2373931bc82d78c0a13 Reviewed-on: https://go-review.googlesource.com/19432 Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot Reviewed-by: Russ Cox --- src/net/http/httptest/server.go | 49 +++++++++++++++++++++++++--- src/net/http/httptest/server_test.go | 14 ++++++++ 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/src/net/http/httptest/server.go b/src/net/http/httptest/server.go index fabfeca943..a2573df251 100644 --- a/src/net/http/httptest/server.go +++ b/src/net/http/httptest/server.go @@ -202,10 +202,31 @@ func (s *Server) logCloseHangDebugInfo() { // CloseClientConnections closes any open HTTP connections to the test Server. func (s *Server) CloseClientConnections() { + var conns int + ch := make(chan bool) + s.mu.Lock() - defer s.mu.Unlock() for c := range s.conns { - s.closeConn(c) + conns++ + s.closeConnChan(c, ch) + } + s.mu.Unlock() + + // Wait for outstanding closes to finish. + // + // Out of paranoia for making a late change in Go 1.6, we + // bound how long this can wait, since golang.org/issue/14291 + // isn't fully understood yet. At least this should only be used + // in tests. + timer := time.NewTimer(5 * time.Second) + defer timer.Stop() + for i := 0; i < conns; i++ { + select { + case <-ch: + case <-timer.C: + // Too slow. Give up. + return + } } } @@ -267,9 +288,13 @@ func (s *Server) wrap() { } } -// closeConn closes c. Except on plan9, which is special. See comment below. +// closeConn closes c. // s.mu must be held. -func (s *Server) closeConn(c net.Conn) { +func (s *Server) closeConn(c net.Conn) { s.closeConnChan(c, nil) } + +// closeConnChan is like closeConn, but takes an optional channel to receive a value +// when the goroutine closing c is done. +func (s *Server) closeConnChan(c net.Conn, done chan<- bool) { if runtime.GOOS == "plan9" { // Go's Plan 9 net package isn't great at unblocking reads when // their underlying TCP connections are closed. Don't trust @@ -278,7 +303,21 @@ func (s *Server) closeConn(c net.Conn) { // resources if the syscall doesn't end up returning. Oh well. s.forgetConn(c) } - go c.Close() + + // Somewhere in the chaos of https://golang.org/cl/15151 we found that + // some types of conns were blocking in Close too long (or deadlocking?) + // and we had to call Close in a goroutine. I (bradfitz) forget what + // that was at this point, but I suspect it was *tls.Conns, which + // were later fixed in https://golang.org/cl/18572, so this goroutine + // is _probably_ unnecessary now. But it's too late in Go 1.6 too remove + // it with confidence. + // TODO(bradfitz): try to remove it for Go 1.7. (golang.org/issue/14291) + go func() { + c.Close() + if done != nil { + done <- true + } + }() } // forgetConn removes c from the set of tracked conns and decrements it from the diff --git a/src/net/http/httptest/server_test.go b/src/net/http/httptest/server_test.go index 6ffc671e57..c9606f2419 100644 --- a/src/net/http/httptest/server_test.go +++ b/src/net/http/httptest/server_test.go @@ -84,3 +84,17 @@ func TestServerCloseBlocking(t *testing.T) { ts.Close() // test we don't hang here forever. } + +// Issue 14290 +func TestServerCloseClientConnections(t *testing.T) { + var s *Server + s = NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + s.CloseClientConnections() + })) + defer s.Close() + res, err := http.Get(s.URL) + if err == nil { + res.Body.Close() + t.Fatal("Unexpected response: %#v", res) + } +} From 70418eb819eb1d02c2c56a13159d95baab85d3a8 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Thu, 11 Feb 2016 16:36:38 +0000 Subject: [PATCH 008/117] runtime: add test for mincore's return value sign on Linux Updates #14297 Change-Id: I6b5f5020af5efaaa71280bdeb2ff99785ee9b959 Reviewed-on: https://go-review.googlesource.com/19457 Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/runtime/export_test.go | 2 ++ src/runtime/runtime_linux_test.go | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go index 5400c1d14e..b09022b53c 100644 --- a/src/runtime/export_test.go +++ b/src/runtime/export_test.go @@ -28,6 +28,8 @@ var Exitsyscall = exitsyscall var LockedOSThread = lockedOSThread var Xadduintptr = atomic.Xadduintptr +var Mincore = mincore + var FuncPC = funcPC var Fastlog2 = fastlog2 diff --git a/src/runtime/runtime_linux_test.go b/src/runtime/runtime_linux_test.go index 5344ed2051..58c797f1dd 100644 --- a/src/runtime/runtime_linux_test.go +++ b/src/runtime/runtime_linux_test.go @@ -8,6 +8,7 @@ import ( . "runtime" "syscall" "testing" + "unsafe" ) var pid, tid int @@ -27,3 +28,15 @@ func TestLockOSThread(t *testing.T) { t.Fatalf("pid=%d but tid=%d", pid, tid) } } + +// Test that error values are negative. Use address 1 (a misaligned +// pointer) to get -EINVAL. +func TestMincoreErrorSign(t *testing.T) { + var dst byte + v := Mincore(unsafe.Pointer(uintptr(1)), 1, &dst) + + const EINVAL = 0x16 + if v != -EINVAL { + t.Errorf("mincore = %v, want %v", v, -EINVAL) + } +} From cc0a04d351c69a99f65342ad5822f2bba8b247d0 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 10 Feb 2016 21:46:51 -0800 Subject: [PATCH 009/117] runtime: fix errno sign for some mmap and mincore cases The caller of mmap expects it to return a positive errno value, but the linux-arm64 and nacl-386 system calls returned a negative errno value. Correct them to negate the errno value. The caller of mincore expects it to return a negative errno value (yes, this is inconsistent), but the linux-mips64x and linux-ppc64x system call returned a positive errno value. Correct them to negate the errno value. Add a test that mmap returns errno with the correct sign. Brad added a test for mincore's errno value in https://golang.org/cl/19457. Fixes #14297. Change-Id: I2b93f32e679bd1eae1c9aef9ae7bcf0ba39521b5 Reviewed-on: https://go-review.googlesource.com/19455 Reviewed-by: Brad Fitzpatrick Reviewed-by: Minux Ma Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot --- src/runtime/export_linux_test.go | 1 + src/runtime/export_mmap_test.go | 15 +++++++++++++++ src/runtime/export_test.go | 2 -- src/runtime/mem_bsd.go | 4 ++-- src/runtime/os2_nacl.go | 25 +++++++++++++------------ src/runtime/runtime_mmap_test.go | 30 ++++++++++++++++++++++++++++++ src/runtime/sys_linux_arm64.s | 3 +++ src/runtime/sys_linux_mips64x.s | 1 + src/runtime/sys_linux_ppc64x.s | 1 + src/runtime/sys_nacl_386.s | 3 +++ 10 files changed, 69 insertions(+), 16 deletions(-) create mode 100644 src/runtime/export_mmap_test.go create mode 100644 src/runtime/runtime_mmap_test.go diff --git a/src/runtime/export_linux_test.go b/src/runtime/export_linux_test.go index c8b9746676..61d6ae4bf2 100644 --- a/src/runtime/export_linux_test.go +++ b/src/runtime/export_linux_test.go @@ -7,3 +7,4 @@ package runtime var NewOSProc0 = newosproc0 +var Mincore = mincore diff --git a/src/runtime/export_mmap_test.go b/src/runtime/export_mmap_test.go new file mode 100644 index 0000000000..11ea076f0b --- /dev/null +++ b/src/runtime/export_mmap_test.go @@ -0,0 +1,15 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris + +// Export guts for testing. + +package runtime + +var Mmap = mmap + +const ENOMEM = _ENOMEM +const MAP_ANON = _MAP_ANON +const MAP_PRIVATE = _MAP_PRIVATE diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go index b09022b53c..5400c1d14e 100644 --- a/src/runtime/export_test.go +++ b/src/runtime/export_test.go @@ -28,8 +28,6 @@ var Exitsyscall = exitsyscall var LockedOSThread = lockedOSThread var Xadduintptr = atomic.Xadduintptr -var Mincore = mincore - var FuncPC = funcPC var Fastlog2 = fastlog2 diff --git a/src/runtime/mem_bsd.go b/src/runtime/mem_bsd.go index 1e388ec728..c3fe6106d7 100644 --- a/src/runtime/mem_bsd.go +++ b/src/runtime/mem_bsd.go @@ -59,9 +59,9 @@ func sysReserve(v unsafe.Pointer, n uintptr, reserved *bool) unsafe.Pointer { return p } -func sysMap(v unsafe.Pointer, n uintptr, reserved bool, sysStat *uint64) { - const _ENOMEM = 12 +const _ENOMEM = 12 +func sysMap(v unsafe.Pointer, n uintptr, reserved bool, sysStat *uint64) { mSysStatInc(sysStat, n) // On 64-bit, we don't actually have v reserved, so tread carefully. diff --git a/src/runtime/os2_nacl.go b/src/runtime/os2_nacl.go index 0c91e0f737..d8c88db0ad 100644 --- a/src/runtime/os2_nacl.go +++ b/src/runtime/os2_nacl.go @@ -10,18 +10,19 @@ const ( // native_client/src/trusted/service_runtime/include/sys/errno.h // The errors are mainly copied from Linux. - _EPERM = 1 /* Operation not permitted */ - _ENOENT = 2 /* No such file or directory */ - _ESRCH = 3 /* No such process */ - _EINTR = 4 /* Interrupted system call */ - _EIO = 5 /* I/O error */ - _ENXIO = 6 /* No such device or address */ - _E2BIG = 7 /* Argument list too long */ - _ENOEXEC = 8 /* Exec format error */ - _EBADF = 9 /* Bad file number */ - _ECHILD = 10 /* No child processes */ - _EAGAIN = 11 /* Try again */ - _ENOMEM = 12 /* Out of memory */ + _EPERM = 1 /* Operation not permitted */ + _ENOENT = 2 /* No such file or directory */ + _ESRCH = 3 /* No such process */ + _EINTR = 4 /* Interrupted system call */ + _EIO = 5 /* I/O error */ + _ENXIO = 6 /* No such device or address */ + _E2BIG = 7 /* Argument list too long */ + _ENOEXEC = 8 /* Exec format error */ + _EBADF = 9 /* Bad file number */ + _ECHILD = 10 /* No child processes */ + _EAGAIN = 11 /* Try again */ + // _ENOMEM is defined in mem_bsd.go for nacl. + // _ENOMEM = 12 /* Out of memory */ _EACCES = 13 /* Permission denied */ _EFAULT = 14 /* Bad address */ _EBUSY = 16 /* Device or resource busy */ diff --git a/src/runtime/runtime_mmap_test.go b/src/runtime/runtime_mmap_test.go new file mode 100644 index 0000000000..ff5e733cb0 --- /dev/null +++ b/src/runtime/runtime_mmap_test.go @@ -0,0 +1,30 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris + +package runtime_test + +import ( + "runtime" + "runtime/internal/sys" + "testing" +) + +// Test that the error value returned by mmap is positive, as that is +// what the code in mem_bsd.go, mem_darwin.go, and mem_linux.go expects. +// See the uses of ENOMEM in sysMap in those files. +func TestMmapErrorSign(t *testing.T) { + p := runtime.Mmap(nil, ^uintptr(0)&^(sys.PhysPageSize-1), 0, runtime.MAP_ANON|runtime.MAP_PRIVATE, -1, 0) + + // The runtime.mmap function is nosplit, but t.Errorf is not. + // Reset the pointer so that we don't get an "invalid stack + // pointer" error from t.Errorf if we call it. + v := uintptr(p) + p = nil + + if v != runtime.ENOMEM { + t.Errorf("mmap = %v, want %v", v, runtime.ENOMEM) + } +} diff --git a/src/runtime/sys_linux_arm64.s b/src/runtime/sys_linux_arm64.s index ca0e07aaa4..94c101a3d4 100644 --- a/src/runtime/sys_linux_arm64.s +++ b/src/runtime/sys_linux_arm64.s @@ -269,6 +269,9 @@ TEXT runtime·mmap(SB),NOSPLIT,$-8 MOVD $SYS_mmap, R8 SVC + CMN $4095, R0 + BCC 2(PC) + NEG R0,R0 MOVD R0, ret+32(FP) RET diff --git a/src/runtime/sys_linux_mips64x.s b/src/runtime/sys_linux_mips64x.s index 6ccb38f90b..26437ddde4 100644 --- a/src/runtime/sys_linux_mips64x.s +++ b/src/runtime/sys_linux_mips64x.s @@ -168,6 +168,7 @@ TEXT runtime·mincore(SB),NOSPLIT,$-8-28 MOVV dst+16(FP), R6 MOVV $SYS_mincore, R2 SYSCALL + SUBVU R2, R0, R2 // caller expects negative errno MOVW R2, ret+24(FP) RET diff --git a/src/runtime/sys_linux_ppc64x.s b/src/runtime/sys_linux_ppc64x.s index ba410c51b6..d063e025a6 100644 --- a/src/runtime/sys_linux_ppc64x.s +++ b/src/runtime/sys_linux_ppc64x.s @@ -153,6 +153,7 @@ TEXT runtime·mincore(SB),NOSPLIT|NOFRAME,$0-28 MOVD n+8(FP), R4 MOVD dst+16(FP), R5 SYSCALL $SYS_mincore + NEG R3 // caller expects negative errno MOVW R3, ret+24(FP) RET diff --git a/src/runtime/sys_nacl_386.s b/src/runtime/sys_nacl_386.s index bf2d36ec85..e69a0b7bfe 100644 --- a/src/runtime/sys_nacl_386.s +++ b/src/runtime/sys_nacl_386.s @@ -227,6 +227,9 @@ TEXT runtime·mmap(SB),NOSPLIT,$32 LEAL 24(SP), AX MOVL AX, 20(SP) NACL_SYSCALL(SYS_mmap) + CMPL AX, $-4095 + JNA 2(PC) + NEGL AX MOVL AX, ret+24(FP) RET From 68aa7fb636d236c23be4fa05f87a898b5e7df362 Mon Sep 17 00:00:00 2001 From: Ryan Brown Date: Wed, 10 Feb 2016 16:51:23 -0800 Subject: [PATCH 010/117] cmd/link: fix padding for dwarf aranges on 32 bit platforms. Fixes #14278 Change-Id: I6a0c1370d595f0573ff0eb933450b1eea41f4bb3 Reviewed-on: https://go-review.googlesource.com/19452 Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot Reviewed-by: Russ Cox --- src/cmd/link/internal/ld/dwarf.go | 4 +- src/runtime/runtime-lldb_test.go | 262 ++++++++++++++++++++++++++++++ 2 files changed, 265 insertions(+), 1 deletion(-) create mode 100644 src/runtime/runtime-lldb_test.go diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index 563600d9a2..a96b37a4be 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -1946,7 +1946,9 @@ func writepub(ispub func(*DWDie) bool) int64 { */ func writearanges() int64 { sectionstart := Cpos() - headersize := int(Rnd(4+2+4+1+1, int64(Thearch.Ptrsize))) // don't count unit_length field itself + // The first tuple is aligned to a multiple of the size of a single tuple + // (twice the size of an address) + headersize := int(Rnd(4+2+4+1+1, int64(Thearch.Ptrsize*2))) // don't count unit_length field itself for compunit := dwroot.child; compunit != nil; compunit = compunit.link { b := getattr(compunit, DW_AT_low_pc) diff --git a/src/runtime/runtime-lldb_test.go b/src/runtime/runtime-lldb_test.go new file mode 100644 index 0000000000..2bd91c1ec0 --- /dev/null +++ b/src/runtime/runtime-lldb_test.go @@ -0,0 +1,262 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime_test + +import ( + "debug/elf" + "debug/macho" + "encoding/binary" + "internal/testenv" + "io" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + "testing" +) + +var lldbPath string + +func checkLldbPython(t *testing.T) { + cmd := exec.Command("lldb", "-P") + out, err := cmd.CombinedOutput() + if err != nil { + t.Skipf("skipping due to issue running lldb: %v\n%s", err, out) + } + lldbPath = strings.TrimSpace(string(out)) + + cmd = exec.Command("/usr/bin/python2.7", "-c", "import sys;sys.path.append(sys.argv[1]);import lldb; print('go lldb python support')", lldbPath) + out, err = cmd.CombinedOutput() + + if err != nil { + t.Skipf("skipping due to issue running python: %v\n%s", err, out) + } + if string(out) != "go lldb python support\n" { + t.Skipf("skipping due to lack of python lldb support: %s", out) + } + + if runtime.GOOS == "darwin" { + // Try to see if we have debugging permissions. + cmd = exec.Command("/usr/sbin/DevToolsSecurity", "-status") + out, err = cmd.CombinedOutput() + if err != nil { + t.Skipf("DevToolsSecurity failed: %v", err) + } else if !strings.Contains(string(out), "enabled") { + t.Skip(string(out)) + } + cmd = exec.Command("/usr/bin/groups") + out, err = cmd.CombinedOutput() + if err != nil { + t.Skipf("groups failed: %v", err) + } else if !strings.Contains(string(out), "_developer") { + t.Skip("Not in _developer group") + } + } +} + +const lldbHelloSource = ` +package main +import "fmt" +func main() { + mapvar := make(map[string]string,5) + mapvar["abc"] = "def" + mapvar["ghi"] = "jkl" + intvar := 42 + ptrvar := &intvar + fmt.Println("hi") // line 10 + _ = ptrvar +} +` + +const lldbScriptSource = ` +import sys +sys.path.append(sys.argv[1]) +import lldb +import os + +TIMEOUT_SECS = 5 + +debugger = lldb.SBDebugger.Create() +debugger.SetAsync(True) +target = debugger.CreateTargetWithFileAndArch("a.exe", None) +if target: + print "Created target" + main_bp = target.BreakpointCreateByLocation("main.go", 10) + if main_bp: + print "Created breakpoint" + process = target.LaunchSimple(None, None, os.getcwd()) + if process: + print "Process launched" + listener = debugger.GetListener() + process.broadcaster.AddListener(listener, lldb.SBProcess.eBroadcastBitStateChanged) + while True: + event = lldb.SBEvent() + if listener.WaitForEvent(TIMEOUT_SECS, event): + if lldb.SBProcess.GetRestartedFromEvent(event): + continue + state = process.GetState() + if state in [lldb.eStateUnloaded, lldb.eStateLaunching, lldb.eStateRunning]: + continue + else: + print "Timeout launching" + break + if state == lldb.eStateStopped: + for t in process.threads: + if t.GetStopReason() == lldb.eStopReasonBreakpoint: + print "Hit breakpoint" + frame = t.GetFrameAtIndex(0) + if frame: + if frame.line_entry: + print "Stopped at %s:%d" % (frame.line_entry.file.basename, frame.line_entry.line) + if frame.function: + print "Stopped in %s" % (frame.function.name,) + var = frame.FindVariable('intvar') + if var: + print "intvar = %s" % (var.GetValue(),) + else: + print "no intvar" + else: + print "Process state", state + process.Destroy() +else: + print "Failed to create target a.exe" + +lldb.SBDebugger.Destroy(debugger) +sys.exit() +` + +const expectedLldbOutput = `Created target +Created breakpoint +Process launched +Hit breakpoint +Stopped at main.go:10 +Stopped in main.main +intvar = 42 +` + +func TestLldbPython(t *testing.T) { + testenv.MustHaveGoBuild(t) + if final := os.Getenv("GOROOT_FINAL"); final != "" && runtime.GOROOT() != final { + t.Skip("gdb test can fail with GOROOT_FINAL pending") + } + + checkLldbPython(t) + + dir, err := ioutil.TempDir("", "go-build") + if err != nil { + t.Fatalf("failed to create temp directory: %v", err) + } + defer os.RemoveAll(dir) + + src := filepath.Join(dir, "main.go") + err = ioutil.WriteFile(src, []byte(lldbHelloSource), 0644) + if err != nil { + t.Fatalf("failed to create file: %v", err) + } + + cmd := exec.Command("go", "build", "-gcflags", "-N -l", "-o", "a.exe") + cmd.Dir = dir + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("building source %v\n%s", err, out) + } + + src = filepath.Join(dir, "script.py") + err = ioutil.WriteFile(src, []byte(lldbScriptSource), 0755) + if err != nil { + t.Fatalf("failed to create script: %v", err) + } + + cmd = exec.Command("/usr/bin/python2.7", "script.py", lldbPath) + cmd.Dir = dir + got, _ := cmd.CombinedOutput() + + if string(got) != expectedLldbOutput { + if strings.Contains(string(got), "Timeout launching") { + t.Skip("Timeout launching") + } + t.Fatalf("Unexpected lldb output:\n%s", got) + } +} + +// Check that aranges are valid even when lldb isn't installed. +func TestDwarfAranges(t *testing.T) { + testenv.MustHaveGoBuild(t) + dir, err := ioutil.TempDir("", "go-build") + if err != nil { + t.Fatalf("failed to create temp directory: %v", err) + } + defer os.RemoveAll(dir) + + src := filepath.Join(dir, "main.go") + err = ioutil.WriteFile(src, []byte(lldbHelloSource), 0644) + if err != nil { + t.Fatalf("failed to create file: %v", err) + } + + cmd := exec.Command("go", "build", "-o", "a.exe") + cmd.Dir = dir + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("building source %v\n%s", err, out) + } + + filename := filepath.Join(dir, "a.exe") + if f, err := elf.Open(filename); err == nil { + sect := f.Section(".debug_aranges") + if sect == nil { + t.Fatal("Missing aranges section") + } + verifyAranges(t, f.ByteOrder, sect.Open()) + } else if f, err := macho.Open(filename); err == nil { + sect := f.Section("__debug_aranges") + if sect == nil { + t.Fatal("Missing aranges section") + } + verifyAranges(t, f.ByteOrder, sect.Open()) + } else { + t.Skip("Not an elf or macho binary.") + } +} + +func verifyAranges(t *testing.T, byteorder binary.ByteOrder, data io.ReadSeeker) { + var header struct { + UnitLength uint32 // does not include the UnitLength field + Version uint16 + Offset uint32 + AddressSize uint8 + SegmentSize uint8 + } + for { + offset, err := data.Seek(0, 1) + if err != nil { + t.Fatalf("Seek error: %v", err) + } + if err = binary.Read(data, byteorder, &header); err == io.EOF { + return + } else if err != nil { + t.Fatalf("Error reading arange header: %v", err) + } + tupleSize := int64(header.SegmentSize) + 2*int64(header.AddressSize) + lastTupleOffset := offset + int64(header.UnitLength) + 4 - tupleSize + if lastTupleOffset%tupleSize != 0 { + t.Fatalf("Invalid arange length %d, (addr %d, seg %d)", header.UnitLength, header.AddressSize, header.SegmentSize) + } + if _, err = data.Seek(lastTupleOffset, 0); err != nil { + t.Fatalf("Seek error: %v", err) + } + buf := make([]byte, tupleSize) + if n, err := data.Read(buf); err != nil || int64(n) < tupleSize { + t.Fatalf("Read error: %v", err) + } + for _, val := range buf { + if val != 0 { + t.Fatalf("Invalid terminator") + } + } + } +} From c93193aec0f33e901d6802e61c966286785f57ee Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 11 Feb 2016 18:09:34 -0800 Subject: [PATCH 011/117] runtime: return errno value from Solaris mmap as expected The code in mem_bsd.go expects that when mmap fails it will return a positive errno value. This fixes the Solaris implementation of mmap to work as expected. Change-Id: Id1c34a9b916e8dc955ced90ea2f4af8321d92265 Reviewed-on: https://go-review.googlesource.com/19477 Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot Reviewed-by: Russ Cox --- src/runtime/os3_solaris.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/runtime/os3_solaris.go b/src/runtime/os3_solaris.go index 7bda07bd4a..7ebb35c8e9 100644 --- a/src/runtime/os3_solaris.go +++ b/src/runtime/os3_solaris.go @@ -442,7 +442,21 @@ func madvise(addr unsafe.Pointer, n uintptr, flags int32) { //go:nosplit func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer { - return unsafe.Pointer(sysvicall6(&libc_mmap, uintptr(addr), uintptr(n), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(off))) + p, err := doMmap(uintptr(addr), n, uintptr(prot), uintptr(flags), uintptr(fd), uintptr(off)) + if p == ^uintptr(0) { + return unsafe.Pointer(err) + } + return unsafe.Pointer(p) +} + +//go:nosplit +func doMmap(addr, n, prot, flags, fd, off uintptr) (uintptr, uintptr) { + var libcall libcall + libcall.fn = uintptr(unsafe.Pointer(&libc_mmap)) + libcall.n = 6 + libcall.args = uintptr(noescape(unsafe.Pointer(&addr))) + asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&libcall)) + return libcall.r1, libcall.err } //go:nosplit From e3033fc535eb29ab7533ecc4a86c607c2046b9c7 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Fri, 12 Feb 2016 10:07:36 -0800 Subject: [PATCH 012/117] cmd/compile: add write barrier to type switch Type switches need write barriers if the written-to variable is heap allocated. For the added needwritebarrier call, the right arg doesn't really matter, I just pass something that will never disqualify the write barrier. The left arg is the one that matters. Fixes #14306 Change-Id: Ic2754167cce062064ea2eeac2944ea4f77cc9c3b Reviewed-on: https://go-review.googlesource.com/19481 Reviewed-by: Russ Cox Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/gc/gen.go | 2 +- test/writebarrier.go | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/gc/gen.go b/src/cmd/compile/internal/gc/gen.go index 836834f8bd..b756055668 100644 --- a/src/cmd/compile/internal/gc/gen.go +++ b/src/cmd/compile/internal/gc/gen.go @@ -836,7 +836,7 @@ func gen(n *Node) { Cgen_as_wb(n.Left, n.Right, true) case OAS2DOTTYPE: - cgen_dottype(n.Rlist.N, n.List.N, n.List.Next.N, false) + cgen_dottype(n.Rlist.N, n.List.N, n.List.Next.N, needwritebarrier(n.List.N, n.Rlist.N)) case OCALLMETH: cgen_callmeth(n, 0) diff --git a/test/writebarrier.go b/test/writebarrier.go index 9b741a60df..dcd20a0225 100644 --- a/test/writebarrier.go +++ b/test/writebarrier.go @@ -144,3 +144,17 @@ type T8 struct { func f16(x []T8, y T8) []T8 { return append(x, y) // ERROR "write barrier" } + +func t1(i interface{}) **int { + // From issue 14306, make sure we have write barriers in a type switch + // where the assigned variable escapes. + switch x := i.(type) { // ERROR "write barrier" + case *int: + return &x + } + switch y := i.(type) { // no write barrier here + case **int: + return y + } + return nil +} From 76cb265f2829be104c5fe395b81cd4721c9f0fa9 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Sat, 13 Feb 2016 06:20:17 +0000 Subject: [PATCH 013/117] net/http: update bundled http2 to fix gzip crash on Read after NewReader error Updates x/net/http2 to git rev 62685c2 for https://golang.org/cl/19483 Change-Id: Id01331cdba03934a6e55e55ad9c2ae27461ba149 Reviewed-on: https://go-review.googlesource.com/19484 Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/net/http/h2_bundle.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go index c4faccc7a8..d8be49c0de 100644 --- a/src/net/http/h2_bundle.go +++ b/src/net/http/h2_bundle.go @@ -6141,13 +6141,18 @@ func (rt http2erringRoundTripper) RoundTrip(*Request) (*Response, error) { retur // call gzip.NewReader on the first call to Read type http2gzipReader struct { body io.ReadCloser // underlying Response.Body - zr io.Reader // lazily-initialized gzip reader + zr *gzip.Reader // lazily-initialized gzip reader + zerr error // sticky error } func (gz *http2gzipReader) Read(p []byte) (n int, err error) { + if gz.zerr != nil { + return 0, gz.zerr + } if gz.zr == nil { gz.zr, err = gzip.NewReader(gz.body) if err != nil { + gz.zerr = err return 0, err } } From 387d5b8cfb085ed8d2a074586a0ee0e6e6cb9820 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sat, 13 Feb 2016 08:48:55 -0800 Subject: [PATCH 014/117] runtime: remove debugging print in cgoCheckTypedBlock Change-Id: I83639fcde88e7d9747b54728a9481ee2e1b23a64 Reviewed-on: https://go-review.googlesource.com/19486 Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/runtime/cgocheck.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/runtime/cgocheck.go b/src/runtime/cgocheck.go index 0077e22332..aebce1506d 100644 --- a/src/runtime/cgocheck.go +++ b/src/runtime/cgocheck.go @@ -135,9 +135,6 @@ func cgoCheckTypedBlock(typ *_type, src unsafe.Pointer, off, size uintptr) { hbits := heapBitsForAddr(uintptr(src)) for i := uintptr(0); i < off+size; i += sys.PtrSize { bits := hbits.bits() - if bits != 0 { - println(i, bits) - } if i >= off && bits&bitPointer != 0 { v := *(*unsafe.Pointer)(add(src, i)) if cgoIsGoPointer(v) { From 18aefe9c194dc1a649386def050c1e6a245f9115 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Sun, 14 Feb 2016 23:53:19 -0500 Subject: [PATCH 015/117] doc: fix non-possessive "'s" Currently we use "Section's" as the plural of the debug/elf Section struct. Change this to "Sections" because it's not possessive and doesn't seem to fall in to any special cases were the apostrophe is acceptable. Change-Id: Id5d3abbd748502a67ead3f483182ee7729db94a2 Reviewed-on: https://go-review.googlesource.com/19505 Reviewed-by: Russ Cox --- doc/go1.6.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/go1.6.html b/doc/go1.6.html index 6e3710cbad..4a1e4c1f9a 100644 --- a/doc/go1.6.html +++ b/doc/go1.6.html @@ -569,7 +569,7 @@ The debug/elf package adds support for general compressed ELF sections. User code needs no updating: the sections are decompressed automatically when read. However, compressed -Section's do not support random access: +Sections do not support random access: they have a nil ReaderAt field. From 62fad436bbea35e46ab9a4615a5fe077f205e269 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Sun, 14 Feb 2016 15:09:21 -0500 Subject: [PATCH 016/117] doc: tweak Go 1.6 GC release notes Go 1.6 significantly improves pause times for large heaps, but it improves them in many other situations as well, such as when goroutine churn is high, allocation rate is high, or when there are many finalizers. Hence, make the statement about pause times a bit more general. Change-Id: Ic034b1c904c39dd1d966ee7fa96ca8bbb3614e53 Reviewed-on: https://go-review.googlesource.com/19504 Reviewed-by: Brad Fitzpatrick --- doc/go1.6.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/go1.6.html b/doc/go1.6.html index 4a1e4c1f9a..0b9dc8a9f3 100644 --- a/doc/go1.6.html +++ b/doc/go1.6.html @@ -248,7 +248,7 @@ Some programs may run faster, some slower. On average the programs in the Go 1 benchmark suite run a few percent faster in Go 1.6 than they did in Go 1.5. The garbage collector's pauses are even lower than in Go 1.5, -although the effect is likely only noticeable for programs using +especially for programs using a large amount of memory.

From 095c0e5c000a18f63c47009fd0684669cc602584 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 11 Feb 2016 13:33:33 -0500 Subject: [PATCH 017/117] doc: fix remaining TODOs in Go 1.6 release notes Fixes #14300. Change-Id: Idb6a300fe0e06fb8966cf06b55f9b252752a69a6 Reviewed-on: https://go-review.googlesource.com/19459 Reviewed-by: Brad Fitzpatrick Reviewed-by: Michael Hudson-Doyle Run-TryBot: Russ Cox TryBot-Result: Gobot Gobot --- doc/asm.html | 9 +++++++++ doc/go1.6.html | 14 +++++++------- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/doc/asm.html b/doc/asm.html index cce2fe2b8d..392af174c2 100644 --- a/doc/asm.html +++ b/doc/asm.html @@ -621,6 +621,15 @@ These modes accept only 1, 2, 4, and 8 as scale factors. +

+When using the compiler and assembler's +-dynlink or -shared modes, +any load or store of a fixed memory location such as a global variable +must be assumed to overwrite CX. +Therefore, to be safe for use with these modes, +assembly sources should typically avoid CX except between memory references. +

+

64-bit Intel 386 (a.k.a. amd64)

diff --git a/doc/go1.6.html b/doc/go1.6.html index 0b9dc8a9f3..4937fc9a59 100644 --- a/doc/go1.6.html +++ b/doc/go1.6.html @@ -17,6 +17,7 @@ ul li { margin: 0.5em 0; } NOTE: This is a DRAFT of the Go 1.6 release notes, prepared for the Go 1.6 beta. Go 1.6 has NOT yet been released. By our regular schedule, it is expected some time in February 2016. +

@@ -70,9 +71,12 @@ On NaCl, Go 1.5 required SDK version pepper-41. Go 1.6 adds support for later SDK versions.

-
-TODO: CX no longer available on 386 assembly? (https://golang.org/cl/16386)
-
+

+On 32-bit x86 systems using the -dynlink or -shared compilation modes, +the register CX is now overwritten by certain memory references and should +be avoided in hand-written assembly. +See the assembly documentation for details. +

Tools

@@ -632,7 +636,6 @@ In previous releases, the argument to * was required to have type < Also in the fmt package, Scanf can now scan hexadecimal strings using %X, as an alias for %x. Both formats accept any mix of upper- and lower-case hexadecimal. -TODO: Keep?
  • @@ -717,9 +720,6 @@ Second, DNS lookup functions such as LookupAddr now return rooted domain names (with a trailing dot) on Plan 9 and Windows, to match the behavior of Go on Unix systems. -TODO: Third, lookups satisfied from /etc/hosts now add a trailing dot as well, -so that looking up 127.0.0.1 typically now returns “localhost.” not “localhost”. -This is arguably a mistake but is not yet fixed. See https://golang.org/issue/13564.
  • From 0c02bc009a65763a5015e7efb95baec84bb79e8d Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 12 Feb 2016 10:33:51 -0500 Subject: [PATCH 018/117] runtime: show panics in traceback We used to include panic calls in tracebacks; however, when runtime.panic was renamed to runtime.gopanic in the conversion of the runtime to Go, we missed the special case in showframe that includes panic calls even though they're in package runtime. Fix the function name check in showframe (and, while we're here, fix the other check for "runtime.panic" in runtime/pprof). Since the "runtime.gopanic" name doesn't match what users call panic and hence isn't very user-friendly, make traceback rewrite it to just "panic". Updates #5832, #13857. Fixes #14315. Change-Id: I8059621b41ec043e63d5cfb4cbee479f47f64973 Reviewed-on: https://go-review.googlesource.com/19492 Run-TryBot: Austin Clements TryBot-Result: Gobot Gobot Reviewed-by: Russ Cox --- src/runtime/crash_test.go | 19 +++++++++++++++++++ src/runtime/pprof/pprof.go | 2 +- src/runtime/testdata/testprog/deadlock.go | 20 +++++++++++++++++++- src/runtime/traceback.go | 10 +++++++--- 4 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/runtime/crash_test.go b/src/runtime/crash_test.go index b622eb4526..5f0e77b0dc 100644 --- a/src/runtime/crash_test.go +++ b/src/runtime/crash_test.go @@ -317,3 +317,22 @@ func TestNetpollDeadlock(t *testing.T) { t.Fatalf("output does not start with %q:\n%s", want, output) } } + +func TestPanicTraceback(t *testing.T) { + output := runTestProg(t, "testprog", "PanicTraceback") + want := "panic: hello" + if !strings.HasPrefix(output, want) { + t.Fatalf("output does not start with %q:\n%s", want, output) + } + + // Check functions in the traceback. + fns := []string{"panic", "main.pt1.func1", "panic", "main.pt2.func1", "panic", "main.pt2", "main.pt1"} + for _, fn := range fns { + re := regexp.MustCompile(`(?m)^` + regexp.QuoteMeta(fn) + `\(.*\n`) + idx := re.FindStringIndex(output) + if idx == nil { + t.Fatalf("expected %q function in traceback:\n%s", fn, output) + } + output = output[idx[1]:] + } +} diff --git a/src/runtime/pprof/pprof.go b/src/runtime/pprof/pprof.go index 7d677cb64e..e09a33d5d9 100644 --- a/src/runtime/pprof/pprof.go +++ b/src/runtime/pprof/pprof.go @@ -346,7 +346,7 @@ func printStackRecord(w io.Writer, stk []uintptr, allFrames bool) { name := f.Name() // Hide runtime.goexit and any runtime functions at the beginning. // This is useful mainly for allocation traces. - wasPanic = name == "runtime.panic" + wasPanic = name == "runtime.gopanic" if name == "runtime.goexit" || !show && strings.HasPrefix(name, "runtime.") { continue } diff --git a/src/runtime/testdata/testprog/deadlock.go b/src/runtime/testdata/testprog/deadlock.go index 7f0a0cd1e0..73fbf6224d 100644 --- a/src/runtime/testdata/testprog/deadlock.go +++ b/src/runtime/testdata/testprog/deadlock.go @@ -29,7 +29,7 @@ func init() { register("GoexitInPanic", GoexitInPanic) register("PanicAfterGoexit", PanicAfterGoexit) register("RecoveredPanicAfterGoexit", RecoveredPanicAfterGoexit) - + register("PanicTraceback", PanicTraceback) } func SimpleDeadlock() { @@ -171,3 +171,21 @@ func RecoveredPanicAfterGoexit() { }() runtime.Goexit() } + +func PanicTraceback() { + pt1() +} + +func pt1() { + defer func() { + panic("panic pt1") + }() + pt2() +} + +func pt2() { + defer func() { + panic("panic pt2") + }() + panic("hello") +} diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index 6559cd7ba3..b4bfe71627 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -380,7 +380,11 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in if (n > 0 || flags&_TraceTrap == 0) && frame.pc > f.entry && !waspanic { tracepc-- } - print(funcname(f), "(") + name := funcname(f) + if name == "runtime.gopanic" { + name = "panic" + } + print(name, "(") argp := (*[100]uintptr)(unsafe.Pointer(frame.argp)) for i := uintptr(0); i < frame.arglen/sys.PtrSize; i++ { if i >= 10 { @@ -617,10 +621,10 @@ func showframe(f *_func, gp *g) bool { level, _, _ := gotraceback() name := funcname(f) - // Special case: always show runtime.panic frame, so that we can + // Special case: always show runtime.gopanic frame, so that we can // see where a panic started in the middle of a stack trace. // See golang.org/issue/5832. - if name == "runtime.panic" { + if name == "runtime.gopanic" { return true } From e136cac48c14aa85795625169379eeeddce35e4f Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Thu, 11 Feb 2016 10:15:58 +1100 Subject: [PATCH 019/117] net: make TestInterfaceAddrsWithNetsh more robust TestInterfaceAddrsWithNetsh invokes Windows netsh command passing it a particular interface name. This approach somehow does not work on some computers (see issue for details). Change that to call netsh without specifying any interface name. This provides output for all interfaces available. So we can achieve same goal parsing this output. Also makes test faster because we only need to invoke netsh once. Fixes #14130. Change-Id: I7911692ca64e372af1e1f9d6acb718c67071de67 Reviewed-on: https://go-review.googlesource.com/19441 Reviewed-by: Volker Dobler Run-TryBot: Russ Cox TryBot-Result: Gobot Gobot Reviewed-by: Russ Cox --- src/net/net_windows_test.go | 105 ++++++++++++++++++++++++++++-------- 1 file changed, 82 insertions(+), 23 deletions(-) diff --git a/src/net/net_windows_test.go b/src/net/net_windows_test.go index c26c6a77c9..df39032721 100644 --- a/src/net/net_windows_test.go +++ b/src/net/net_windows_test.go @@ -314,20 +314,43 @@ func TestInterfacesWithNetsh(t *testing.T) { } } -func netshInterfaceIPv4ShowAddress(name string) ([]string, error) { - out, err := runCmd("netsh", "interface", "ipv4", "show", "address", "name=\""+name+"\"") - if err != nil { - return nil, err - } +func netshInterfaceIPv4ShowAddress(name string, netshOutput []byte) []string { // adress information is listed like: + // + //Configuration for interface "Local Area Connection" + // DHCP enabled: Yes // IP Address: 10.0.0.2 // Subnet Prefix: 10.0.0.0/24 (mask 255.255.255.0) // IP Address: 10.0.0.3 // Subnet Prefix: 10.0.0.0/24 (mask 255.255.255.0) + // Default Gateway: 10.0.0.254 + // Gateway Metric: 0 + // InterfaceMetric: 10 + // + //Configuration for interface "Loopback Pseudo-Interface 1" + // DHCP enabled: No + // IP Address: 127.0.0.1 + // Subnet Prefix: 127.0.0.0/8 (mask 255.0.0.0) + // InterfaceMetric: 50 + // addrs := make([]string, 0) var addr, subnetprefix string - lines := bytes.Split(out, []byte{'\r', '\n'}) + var processingOurInterface bool + lines := bytes.Split(netshOutput, []byte{'\r', '\n'}) for _, line := range lines { + if !processingOurInterface { + if !bytes.HasPrefix(line, []byte("Configuration for interface")) { + continue + } + if !bytes.Contains(line, []byte(`"`+name+`"`)) { + continue + } + processingOurInterface = true + continue + } + if len(line) == 0 { + break + } if bytes.Contains(line, []byte("Subnet Prefix:")) { f := bytes.Split(line, []byte{':'}) if len(f) == 2 { @@ -351,18 +374,50 @@ func netshInterfaceIPv4ShowAddress(name string) ([]string, error) { } } } - return addrs, nil + return addrs } -func netshInterfaceIPv6ShowAddress(name string) ([]string, error) { +func netshInterfaceIPv6ShowAddress(name string, netshOutput []byte) []string { + // adress information is listed like: + // + //Address ::1 Parameters + //--------------------------------------------------------- + //Interface Luid : Loopback Pseudo-Interface 1 + //Scope Id : 0.0 + //Valid Lifetime : infinite + //Preferred Lifetime : infinite + //DAD State : Preferred + //Address Type : Other + //Skip as Source : false + // + //Address XXXX::XXXX:XXXX:XXXX:XXXX%11 Parameters + //--------------------------------------------------------- + //Interface Luid : Local Area Connection + //Scope Id : 0.11 + //Valid Lifetime : infinite + //Preferred Lifetime : infinite + //DAD State : Preferred + //Address Type : Other + //Skip as Source : false + // + // TODO: need to test ipv6 netmask too, but netsh does not outputs it - out, err := runCmd("netsh", "interface", "ipv6", "show", "address", "interface=\""+name+"\"") - if err != nil { - return nil, err - } + var addr string addrs := make([]string, 0) - lines := bytes.Split(out, []byte{'\r', '\n'}) + lines := bytes.Split(netshOutput, []byte{'\r', '\n'}) for _, line := range lines { + if addr != "" { + if len(line) == 0 { + addr = "" + continue + } + if string(line) != "Interface Luid : "+name { + continue + } + addrs = append(addrs, addr) + addr = "" + continue + } if !bytes.HasPrefix(line, []byte("Address")) { continue } @@ -383,9 +438,9 @@ func netshInterfaceIPv6ShowAddress(name string) ([]string, error) { f[0] = []byte(ParseIP(string(f[0])).String()) } - addrs = append(addrs, string(bytes.ToLower(bytes.TrimSpace(f[0])))) + addr = string(bytes.ToLower(bytes.TrimSpace(f[0]))) } - return addrs, nil + return addrs } func TestInterfaceAddrsWithNetsh(t *testing.T) { @@ -395,6 +450,16 @@ func TestInterfaceAddrsWithNetsh(t *testing.T) { if !isEnglishOS(t) { t.Skip("English version of OS required for this test") } + + outIPV4, err := runCmd("netsh", "interface", "ipv4", "show", "address") + if err != nil { + t.Fatal(err) + } + outIPV6, err := runCmd("netsh", "interface", "ipv6", "show", "address", "level=verbose") + if err != nil { + t.Fatal(err) + } + ift, err := Interfaces() if err != nil { t.Fatal(err) @@ -431,14 +496,8 @@ func TestInterfaceAddrsWithNetsh(t *testing.T) { } sort.Strings(have) - want, err := netshInterfaceIPv4ShowAddress(ifi.Name) - if err != nil { - t.Fatal(err) - } - wantIPv6, err := netshInterfaceIPv6ShowAddress(ifi.Name) - if err != nil { - t.Fatal(err) - } + want := netshInterfaceIPv4ShowAddress(ifi.Name, outIPV4) + wantIPv6 := netshInterfaceIPv6ShowAddress(ifi.Name, outIPV6) want = append(want, wantIPv6...) sort.Strings(want) From feb2a5d6103dad76b6374c5f346e33d55612cb2a Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 16 Feb 2016 12:09:05 -0500 Subject: [PATCH 020/117] cmd/compile: print struct tags in var decl in inlined func body This bug was introduced in golang.org/cl/18217, while trying to fix #13777. Originally I wanted to just disable inlining for the case being handled incorrectly, but it's fairly difficult to detect and much easier just to fix. Since the case being handled incorrectly was inlined correctly in Go 1.5, not inlining it would also be somewhat of a regression. So just fix it. Test case copied from Ian's CL 19520. The mistake to worry about in this CL would be relaxing the condition too much (we now print the note more often than we did yesterday). To confirm that we'd catch this mistake, I checked that changing (!fmtbody || !t.Funarg) to (true) does cause fixedbugs/issue13777.go to fail. And putting it back to what is written in this CL makes that test pass again as well as the new fixedbugs/issue14331.go. So I believe that the new condition is correct for both constraints. Fixes #14331. Change-Id: I91f75a4d5d07c53af5caea1855c780d9874b8df6 Reviewed-on: https://go-review.googlesource.com/19514 Run-TryBot: Russ Cox TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/cmd/compile/internal/gc/fmt.go | 8 +++++++- test/fixedbugs/issue14331.dir/a.go | 14 ++++++++++++++ test/fixedbugs/issue14331.dir/b.go | 11 +++++++++++ test/fixedbugs/issue14331.go | 9 +++++++++ 4 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 test/fixedbugs/issue14331.dir/a.go create mode 100644 test/fixedbugs/issue14331.dir/b.go create mode 100644 test/fixedbugs/issue14331.go diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go index 64b6e36758..d00e5a6c46 100644 --- a/src/cmd/compile/internal/gc/fmt.go +++ b/src/cmd/compile/internal/gc/fmt.go @@ -748,7 +748,13 @@ func typefmt(t *Type, flag int) string { if name != "" { str = name + " " + typ } - if flag&obj.FmtShort == 0 && !fmtbody && t.Note != nil { + + // The fmtbody flag is intended to suppress escape analysis annotations + // when printing a function type used in a function body. + // (The escape analysis tags do not apply to func vars.) + // But it must not suppress struct field tags. + // See golang.org/issue/13777 and golang.org/issue/14331. + if flag&obj.FmtShort == 0 && (!fmtbody || !t.Funarg) && t.Note != nil { str += " " + strconv.Quote(*t.Note) } return str diff --git a/test/fixedbugs/issue14331.dir/a.go b/test/fixedbugs/issue14331.dir/a.go new file mode 100644 index 0000000000..1b7f853bc9 --- /dev/null +++ b/test/fixedbugs/issue14331.dir/a.go @@ -0,0 +1,14 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +var S struct { + Str string `tag` +} + +func F() string { + v := S + return v.Str +} diff --git a/test/fixedbugs/issue14331.dir/b.go b/test/fixedbugs/issue14331.dir/b.go new file mode 100644 index 0000000000..7a0abb2506 --- /dev/null +++ b/test/fixedbugs/issue14331.dir/b.go @@ -0,0 +1,11 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package b + +import "./a" + +func G() string { + return a.F() +} diff --git a/test/fixedbugs/issue14331.go b/test/fixedbugs/issue14331.go new file mode 100644 index 0000000000..32f3e5156c --- /dev/null +++ b/test/fixedbugs/issue14331.go @@ -0,0 +1,9 @@ +// compiledir + +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Inline function misses struct tags. + +package ignored From 7c22af830a72adf30b18ee3d1744aab8e3c009a8 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Tue, 16 Feb 2016 14:42:24 -0500 Subject: [PATCH 021/117] runtime: fix deadlock in TestCrashDumpsAllThreads TestCrashDumpsAllThreads carefully sets the number of Ps to one greater than the number of non-preemptible loops it starts so that the main goroutine can continue to run (necessary because of #10958). However, if GC starts, it can take over that one spare P and lock up the system while waiting for the non-preemptible loops, causing the test to eventually time out. This deadlock is easily reproducible if you run the runtime test with GOGC=1. Fix this by forcing GOGC=off when running this test. Change-Id: Ifb22da5ce33f9a61700a326ea92fcf4b049721d1 Reviewed-on: https://go-review.googlesource.com/19516 Run-TryBot: Austin Clements TryBot-Result: Gobot Gobot Reviewed-by: Russ Cox --- src/runtime/crash_unix_test.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/runtime/crash_unix_test.go b/src/runtime/crash_unix_test.go index 1a012eb6ef..771b303f6e 100644 --- a/src/runtime/crash_unix_test.go +++ b/src/runtime/crash_unix_test.go @@ -14,6 +14,7 @@ import ( "os/exec" "path/filepath" "runtime" + "strings" "syscall" "testing" ) @@ -52,6 +53,18 @@ func TestCrashDumpsAllThreads(t *testing.T) { cmd = exec.Command(filepath.Join(dir, "a.exe")) cmd = testEnv(cmd) cmd.Env = append(cmd.Env, "GOTRACEBACK=crash") + + // Set GOGC=off. Because of golang.org/issue/10958, the tight + // loops in the test program are not preemptible. If GC kicks + // in, it may lock up and prevent main from saying it's ready. + newEnv := []string{} + for _, s := range cmd.Env { + if !strings.HasPrefix(s, "GOGC=") { + newEnv = append(newEnv, s) + } + } + cmd.Env = append(newEnv, "GOGC=off") + var outbuf bytes.Buffer cmd.Stdout = &outbuf cmd.Stderr = &outbuf From aa22c42d704f9c6d9d8e65f972ac819678629ff2 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 16 Feb 2016 07:13:10 -0800 Subject: [PATCH 022/117] cmd/go: avoid race on test environment Fixes #14337. Change-Id: I58aef7e08d936b0712da577dd1ce5c9ed5d8bfd2 Reviewed-on: https://go-review.googlesource.com/19513 Reviewed-by: Russ Cox --- src/cmd/dist/test.go | 5 +++++ src/cmd/go/go_test.go | 26 +++++++++++++++++++++++++- src/cmd/go/main.go | 2 ++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index 156b868109..36c829d1b9 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -947,6 +947,11 @@ func (t *tester) raceTest(dt *distTest) error { t.addCmd(dt, "src", "go", "test", "-race", "-i", "runtime/race", "flag", "os/exec") t.addCmd(dt, "src", "go", "test", "-race", "-run=Output", "runtime/race") t.addCmd(dt, "src", "go", "test", "-race", "-short", "-run=TestParse|TestEcho", "flag", "os/exec") + // We don't want the following line, because it + // slows down all.bash (by 10 seconds on my laptop). + // The race builder should catch any error here, but doesn't. + // TODO(iant): Figure out how to catch this. + // t.addCmd(dt, "src", "go", "test", "-race", "-run=TestParallelTest", "cmd/go") if t.cgoEnabled { env := mergeEnvLists([]string{"GOTRACEBACK=2"}, os.Environ()) cmd := t.addCmd(dt, "misc/cgo/test", "go", "test", "-race", "-short") diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index c60971efed..39e0f3e56d 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -10,6 +10,7 @@ import ( "fmt" "go/build" "go/format" + "internal/race" "internal/testenv" "io" "io/ioutil" @@ -69,7 +70,11 @@ func TestMain(m *testing.M) { flag.Parse() if canRun { - out, err := exec.Command("go", "build", "-tags", "testgo", "-o", "testgo"+exeSuffix).CombinedOutput() + args := []string{"build", "-tags", "testgo", "-o", "testgo" + exeSuffix} + if race.Enabled { + args = append(args, "-race") + } + out, err := exec.Command("go", args...).CombinedOutput() if err != nil { fmt.Fprintf(os.Stderr, "building testgo failed: %v\n%s", err, out) os.Exit(2) @@ -2735,3 +2740,22 @@ func TestIssue13655(t *testing.T) { tg.grepStdout("runtime/internal/sys", "did not find required dependency of "+pkg+" on runtime/internal/sys") } } + +// For issue 14337. +func TestParallelTest(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.makeTempdir() + const testSrc = `package package_test + import ( + "testing" + ) + func TestTest(t *testing.T) { + }` + tg.tempFile("src/p1/p1_test.go", strings.Replace(testSrc, "package_test", "p1_test", 1)) + tg.tempFile("src/p2/p2_test.go", strings.Replace(testSrc, "package_test", "p2_test", 1)) + tg.tempFile("src/p3/p3_test.go", strings.Replace(testSrc, "package_test", "p3_test", 1)) + tg.tempFile("src/p4/p4_test.go", strings.Replace(testSrc, "package_test", "p4_test", 1)) + tg.setenv("GOPATH", tg.path(".")) + tg.run("test", "-p=4", "p1", "p2", "p3", "p4") +} diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go index d384594722..f9b979da7f 100644 --- a/src/cmd/go/main.go +++ b/src/cmd/go/main.go @@ -454,7 +454,9 @@ func envForDir(dir string, base []string) []string { // mergeEnvLists merges the two environment lists such that // variables with the same name in "in" replace those in "out". +// This always returns a newly allocated slice. func mergeEnvLists(in, out []string) []string { + out = append([]string(nil), out...) NextVar: for _, inkv := range in { k := strings.SplitAfterN(inkv, "=", 2)[0] From f997475129cb12924e34156a0529d88612695d22 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 17 Feb 2016 10:46:30 -0500 Subject: [PATCH 023/117] doc: mention multi-change branches in contribute.html Fixes #13651. Change-Id: I1d21b49e2b5bc6c507eb084d6d2553e5a9c607cf Reviewed-on: https://go-review.googlesource.com/19552 Reviewed-by: Ian Lance Taylor Reviewed-by: Chris Broadfoot --- doc/contribute.html | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/doc/contribute.html b/doc/contribute.html index a321a8646f..4619c81124 100644 --- a/doc/contribute.html +++ b/doc/contribute.html @@ -198,9 +198,13 @@ prints help text, not an error.

    -Note to Git aficionados: The git-codereview command is not required to +Note to Git aficionados: +The git-codereview command is not required to upload and manage Gerrit code reviews. For those who prefer plain Git, the text -below gives the Git equivalent of each git-codereview command. If you do use plain +below gives the Git equivalent of each git-codereview command. +

    + +

    If you do use plain Git, note that you still need the commit hooks that the git-codereview command configures; those hooks add a Gerrit Change-Id line to the commit message and check that all Go source files have been formatted with gofmt. Even @@ -208,6 +212,12 @@ if you intend to use plain Git for daily work, install the hooks in a new Git checkout by running git-codereview hooks.

    +

    +The workflow described below assumes a single change per branch. +It is also possible to prepare a sequence of (usually related) changes in a single branch. +See the git-codereview documentation for details. +

    +

    Set up git aliases

    From c4f902bef4c7edb9b051cec6c3da6690dc045203 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 17 Feb 2016 10:41:03 -0500 Subject: [PATCH 024/117] net/http: update bundle command This is the bundle command's new usage and new output header, after CL 19428. Actually running this command would work but would bring in a newer x/net/http2 that we don't want yet. Change-Id: Ic6082ca00102a2df1f7632eebf9aca41fdcdb444 Reviewed-on: https://go-review.googlesource.com/19551 Reviewed-by: Ian Lance Taylor Reviewed-by: Chris Broadfoot --- src/net/http/h2_bundle.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go index d8be49c0de..4e19b3e71f 100644 --- a/src/net/http/h2_bundle.go +++ b/src/net/http/h2_bundle.go @@ -1,5 +1,5 @@ -// Code generated by golang.org/x/tools/cmd/bundle command: -// $ bundle golang.org/x/net/http2 net/http http2 +// Code generated by golang.org/x/tools/cmd/bundle. +//go:generate bundle -o h2_bundle.go -prefix http2 -import golang.org/x/net/http2/hpack=internal/golang.org/x/net/http2/hpack golang.org/x/net/http2 // Package http2 implements the HTTP/2 protocol. // From 939a9424de5c3d0a0d2e1769778b5b0aa9c61954 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 17 Feb 2016 10:39:13 -0500 Subject: [PATCH 025/117] doc: remove DRAFT tags from go1.6.html Go 1.6 is soon (but not yet). Fixes #14301. Change-Id: I85e329b643adcb5d4fa680c5333fbc1f928d4d9d Reviewed-on: https://go-review.googlesource.com/19550 Reviewed-by: Ian Lance Taylor Reviewed-by: Chris Broadfoot --- doc/go1.6.html | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/doc/go1.6.html b/doc/go1.6.html index 4937fc9a59..17c3536aeb 100644 --- a/doc/go1.6.html +++ b/doc/go1.6.html @@ -1,5 +1,5 @@ @@ -13,14 +13,6 @@ Edit .,s;^([a-z][A-Za-z0-9_/]+)\.([A-Z][A-Za-z0-9_]+\.)?([A-Z][A-Za-z0-9_]+)([ . ul li { margin: 0.5em 0; } -

    -NOTE: This is a DRAFT of the Go 1.6 release notes, prepared for the Go 1.6 beta. -Go 1.6 has NOT yet been released. -By our regular schedule, it is expected some time in February 2016. - - -

    -

    Introduction to Go 1.6

    From 6030c7531539619003e651e8836f451ea6b832b0 Mon Sep 17 00:00:00 2001 From: Chris Broadfoot Date: Wed, 17 Feb 2016 14:02:26 -0800 Subject: [PATCH 026/117] doc: document Go 1.6 Change-Id: I4910105d48ed650289ecb1490d556929db05bc38 Reviewed-on: https://go-review.googlesource.com/19526 Reviewed-by: Andrew Gerrand Reviewed-on: https://go-review.googlesource.com/19527 --- doc/devel/release.html | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/devel/release.html b/doc/devel/release.html index ad060a8ce6..6cdbe1d608 100644 --- a/doc/devel/release.html +++ b/doc/devel/release.html @@ -30,6 +30,13 @@ to fix critical security problems in both Go 1.4 and Go 1.5 as they arise. See the security policy for more details.

    +

    go1.6 (released 2015/02/17)

    + +

    +Go 1.6 is a major release of Go. +Read the Go 1.6 Release Notes for more information. +

    +

    go1.5 (released 2015/08/19)

    From 6b9a0fa356de3c733c14951e42ca31cfafe7ff79 Mon Sep 17 00:00:00 2001 From: Rahul Chaudhry Date: Wed, 17 Feb 2016 14:55:16 -0800 Subject: [PATCH 027/117] doc: fix typo in go1.6 release date. Change-Id: If15fdcd3cd49394a0c1dffd39fbbeede11081ccb Reviewed-on: https://go-review.googlesource.com/19528 Reviewed-by: Chris Broadfoot --- doc/devel/release.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/devel/release.html b/doc/devel/release.html index 6cdbe1d608..e0c2ac0219 100644 --- a/doc/devel/release.html +++ b/doc/devel/release.html @@ -30,7 +30,7 @@ to fix critical security problems in both Go 1.4 and Go 1.5 as they arise. See the security policy for more details.

    -

    go1.6 (released 2015/02/17)

    +

    go1.6 (released 2016/02/17)

    Go 1.6 is a major release of Go. From c51f9173ad2711f5b1a5af9d95dae9e711e13ebb Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 18 Feb 2016 09:42:28 -0800 Subject: [PATCH 028/117] go/constant: fix doc strings Fixes #14357. Change-Id: I91acff0b0cc7be2bcbad68925a19a437dbd4c83d Reviewed-on: https://go-review.googlesource.com/19620 Reviewed-by: Alan Donovan --- src/go/constant/value.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/go/constant/value.go b/src/go/constant/value.go index 310814df71..1b0938dda4 100644 --- a/src/go/constant/value.go +++ b/src/go/constant/value.go @@ -276,10 +276,10 @@ func smallRat(x *big.Float) bool { // MakeUnknown returns the Unknown value. func MakeUnknown() Value { return unknownVal{} } -// MakeBool returns the Bool value for x. +// MakeBool returns the Bool value for b. func MakeBool(b bool) Value { return boolVal(b) } -// MakeString returns the String value for x. +// MakeString returns the String value for s. func MakeString(s string) Value { return stringVal(s) } // MakeInt64 returns the Int value for x. From 3e91e8aa356328c5a7c2ab0f6291f99c69145cdc Mon Sep 17 00:00:00 2001 From: Alberto Donizetti Date: Sat, 30 Jan 2016 21:50:07 +0100 Subject: [PATCH 029/117] go/internal/gcimporter: add missing argument to error message Change-Id: I3071f0e876506c6dc283e97bc15f157bf2ff011e Reviewed-on: https://go-review.googlesource.com/19641 Reviewed-by: Robert Griesemer --- src/go/internal/gcimporter/gcimporter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/go/internal/gcimporter/gcimporter.go b/src/go/internal/gcimporter/gcimporter.go index d70ec083c3..052277f4fe 100644 --- a/src/go/internal/gcimporter/gcimporter.go +++ b/src/go/internal/gcimporter/gcimporter.go @@ -385,7 +385,7 @@ func (p *parser) getPkg(id, name string) *types.Package { if pname := pkg.Name(); pname == "" { pkg.SetName(name) } else if pname != name { - p.errorf("%s package name mismatch: %s (given) vs %s (expected)", pname, name) + p.errorf("%s package name mismatch: %s (given) vs %s (expected)", id, pname, name) } } return pkg From 8fd1634f443cebcb176c7a95104b61240733e420 Mon Sep 17 00:00:00 2001 From: Matt Bostock Date: Tue, 16 Feb 2016 18:53:46 +0000 Subject: [PATCH 030/117] sort: Fix typo in stable sort comment Fix `reverences`, which I believe should read as `references`. Change-Id: I450efcbeee0f8861a84b209f2e6636764034232a Reviewed-on: https://go-review.googlesource.com/19469 Reviewed-by: Russ Cox --- src/sort/sort.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sort/sort.go b/src/sort/sort.go index ac8f4a661f..5eb45c6d4a 100644 --- a/src/sort/sort.go +++ b/src/sort/sort.go @@ -335,7 +335,7 @@ func StringsAreSorted(a []string) bool { return IsSorted(StringSlice(a)) } // unstable or rely on enough different elements in each step to encode the // performed block rearrangements. See also "In-Place Merging Algorithms", // Denham Coates-Evely, Department of Computer Science, Kings College, -// January 2004 and the reverences in there. +// January 2004 and the references in there. // - Often "optimal" algorithms are optimal in the number of assignments // but Interface has only Swap as operation. From a576e9883cd1a79ddcf1c258b4e72ef164e9a1c8 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 18 Feb 2016 11:43:52 -0800 Subject: [PATCH 031/117] text/scanner: mention package when reporting errors to stderr Fixes #14166. Change-Id: I325b283a1d53e73a6d862611c446820ab94a161c Reviewed-on: https://go-review.googlesource.com/19622 Reviewed-by: Damien Neil --- src/text/scanner/scanner.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/text/scanner/scanner.go b/src/text/scanner/scanner.go index 0155800f34..dd87850fcd 100644 --- a/src/text/scanner/scanner.go +++ b/src/text/scanner/scanner.go @@ -333,7 +333,7 @@ func (s *Scanner) error(msg string) { if !pos.IsValid() { pos = s.Pos() } - fmt.Fprintf(os.Stderr, "%s: %s\n", pos, msg) + fmt.Fprintf(os.Stderr, "text/scanner: %s: %s\n", pos, msg) } func (s *Scanner) isIdentRune(ch rune, i int) bool { From 1a94431a78c4de5182dd43b438701cca80455746 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 13 Jan 2016 15:51:16 -0800 Subject: [PATCH 032/117] cmd/cgo: support multiple-value special form in VarDecl Fixes #13930. Change-Id: I124b7d31d1f2be05b7f23dafd1e52d9f3f02f3f0 Reviewed-on: https://go-review.googlesource.com/18623 Run-TryBot: Matthew Dempsky Reviewed-by: Ian Lance Taylor --- misc/cgo/test/issue13930.go | 13 +++++++++++++ src/cmd/cgo/ast.go | 6 +++++- src/cmd/cgo/doc.go | 3 ++- 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 misc/cgo/test/issue13930.go diff --git a/misc/cgo/test/issue13930.go b/misc/cgo/test/issue13930.go new file mode 100644 index 0000000000..3a22459e68 --- /dev/null +++ b/misc/cgo/test/issue13930.go @@ -0,0 +1,13 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Issue 13930. Test that cgo's multiple-value special form for +// C function calls works in variable declaration statements. + +package cgotest + +// #include +import "C" + +var _, _ = C.abs(0) diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go index c3a24c2b76..4c5dc9a23d 100644 --- a/src/cmd/cgo/ast.go +++ b/src/cmd/cgo/ast.go @@ -447,7 +447,11 @@ func (f *File) walk(x interface{}, context string, visit func(*File, interface{} case *ast.ImportSpec: case *ast.ValueSpec: f.walk(&n.Type, "type", visit) - f.walk(n.Values, "expr", visit) + if len(n.Names) == 2 && len(n.Values) == 1 { + f.walk(&n.Values[0], "as2", visit) + } else { + f.walk(n.Values, "expr", visit) + } case *ast.TypeSpec: f.walk(&n.Type, "type", visit) diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go index bd38a5c153..8b4e2bfd58 100644 --- a/src/cmd/cgo/doc.go +++ b/src/cmd/cgo/doc.go @@ -148,8 +148,9 @@ assignment context to retrieve both the return value (if any) and the C errno variable as an error (use _ to skip the result value if the function returns void). For example: - n, err := C.sqrt(-1) + n, err = C.sqrt(-1) _, err := C.voidFunc() + var n, err = C.sqrt(1) Calling C function pointers is currently not supported, however you can declare Go variables which hold C function pointers and pass them From 5bbb98df0960f57dca73cb7640456608d4cc0917 Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Mon, 8 Feb 2016 17:20:59 -0800 Subject: [PATCH 033/117] cmd/go, cmd/link: make builds deterministic Add the following flags when supported by the compiler: -gno-record-gcc-switches -fdebug-prefix-map=$WORK=/tmp/go-build Add an empty NAME symbol to the ELF .symtab. GNU ld will add a NAME symbol when one is not present; including one of our own prevents it from adding a reference to the link tempdir. Fixes #13247 for compilers that support -fdebug-prefix-map. (gcc, clang in the near future.) Change-Id: I221c71fc59cd23ee8c99bcc038793ff4623c9ffc Reviewed-on: https://go-review.googlesource.com/19363 Reviewed-by: Ian Lance Taylor Run-TryBot: Damien Neil --- src/cmd/go/build.go | 40 +++++++++++++++++++++--------- src/cmd/go/go_test.go | 27 ++++++++++++++++++++ src/cmd/link/internal/ld/symtab.go | 5 ++++ 3 files changed, 60 insertions(+), 12 deletions(-) diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go index f2a2a6014f..1932f324ea 100644 --- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -686,6 +686,7 @@ type builder struct { work string // the temporary work directory (ends in filepath.Separator) actionCache map[cacheKey]*action // a cache of already-constructed actions mkdirCache map[string]bool // a cache of created directories + flagCache map[string]bool // a cache of supported compiler flags print func(args ...interface{}) (int, error) output sync.Mutex @@ -2927,6 +2928,14 @@ func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string { // disable word wrapping in error messages a = append(a, "-fmessage-length=0") + // Tell gcc not to include the work directory in object files. + if b.gccSupportsFlag("-fdebug-prefix-map=a=b") { + // -gno-record-gcc-switches is supported by all gcc/clang + // versions that support -fdebug-prefix-map. + a = append(a, "-gno-record-gcc-switches") + a = append(a, "-fdebug-prefix-map="+b.work+"=/tmp/go-build") + } + // On OS X, some of the compilers behave as if -fno-common // is always set, and the Mach-O linker in 6l/8l assumes this. // See https://golang.org/issue/3253. @@ -2941,19 +2950,24 @@ func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string { // -no-pie must be passed when doing a partial link with -Wl,-r. But -no-pie is // not supported by all compilers. func (b *builder) gccSupportsNoPie() bool { - if goos != "linux" { - // On some BSD platforms, error messages from the - // compiler make it to the console despite cmd.Std* - // all being nil. As -no-pie is only required on linux - // systems so far, we only test there. - return false + return b.gccSupportsFlag("-no-pie") +} + +// gccSupportsFlag checks to see if the compiler supports a flag. +func (b *builder) gccSupportsFlag(flag string) bool { + b.exec.Lock() + defer b.exec.Unlock() + if b, ok := b.flagCache[flag]; ok { + return b } - src := filepath.Join(b.work, "trivial.c") - if err := ioutil.WriteFile(src, []byte{}, 0666); err != nil { - return false + if b.flagCache == nil { + src := filepath.Join(b.work, "trivial.c") + if err := ioutil.WriteFile(src, []byte{}, 0666); err != nil { + return false + } + b.flagCache = make(map[string]bool) } - cmdArgs := b.gccCmd(b.work) - cmdArgs = append(cmdArgs, "-no-pie", "-c", "trivial.c") + cmdArgs := append(envList("CC", defaultCC), flag, "-c", "trivial.c") if buildN || buildX { b.showcmd(b.work, "%s", joinUnambiguously(cmdArgs)) if buildN { @@ -2964,7 +2978,9 @@ func (b *builder) gccSupportsNoPie() bool { cmd.Dir = b.work cmd.Env = envForDir(cmd.Dir, os.Environ()) out, err := cmd.CombinedOutput() - return err == nil && !bytes.Contains(out, []byte("unrecognized")) + supported := err == nil && !bytes.Contains(out, []byte("unrecognized")) + b.flagCache[flag] = supported + return supported } // gccArchArgs returns arguments to pass to gcc based on the architecture. diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index 39e0f3e56d..e55fc360de 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -2759,3 +2759,30 @@ func TestParallelTest(t *testing.T) { tg.setenv("GOPATH", tg.path(".")) tg.run("test", "-p=4", "p1", "p2", "p3", "p4") } + +func TestCgoConsistentResults(t *testing.T) { + if !canCgo { + t.Skip("skipping because cgo not enabled") + } + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.makeTempdir() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + exe1 := tg.path("cgotest1" + exeSuffix) + exe2 := tg.path("cgotest2" + exeSuffix) + tg.run("build", "-o", exe1, "cgotest") + tg.run("build", "-x", "-o", exe2, "cgotest") + b1, err := ioutil.ReadFile(exe1) + tg.must(err) + b2, err := ioutil.ReadFile(exe2) + tg.must(err) + + if !tg.doGrepMatch(`-fdebug-prefix-map=\$WORK`, &tg.stderr) { + t.Skip("skipping because C compiler does not support -fdebug-prefix-map") + } + if !bytes.Equal(b1, b2) { + t.Error("building cgotest twice did not produce the same output") + } +} diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go index 3e6169e453..b87ca81007 100644 --- a/src/cmd/link/internal/ld/symtab.go +++ b/src/cmd/link/internal/ld/symtab.go @@ -215,6 +215,11 @@ func Asmelfsym() { dwarfaddelfsectionsyms() + // Some linkers will add a FILE sym if one is not present. + // Avoid having the working directory inserted into the symbol table. + putelfsyment(0, 0, 0, STB_LOCAL<<4|STT_FILE, SHN_ABS, 0) + numelfsym++ + elfbind = STB_LOCAL genasmsym(putelfsym) From 7d80291c4c8bce8754b6e1aeb962aed1ceef64dc Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 1 Dec 2015 11:58:41 -0800 Subject: [PATCH 034/117] cmd/compile: eliminate Io.importsafe It was only really necessary for ensuring that package runtime should be treated as safe even without a "safe" marker, but mkbuiltin.go now compiles it with -u. Change-Id: Ifbcc62436ce40ab732ece667141afd82c1d3b64b Reviewed-on: https://go-review.googlesource.com/19625 Reviewed-by: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/gc/go.go | 17 ++++++++--------- src/cmd/compile/internal/gc/lex.go | 1 - src/cmd/compile/internal/gc/parser.go | 8 ++++---- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go index 3146caed2f..8053aaffe9 100644 --- a/src/cmd/compile/internal/gc/go.go +++ b/src/cmd/compile/internal/gc/go.go @@ -386,15 +386,14 @@ type Sig struct { } type Io struct { - infile string - bin *obj.Biobuf - cp string // used for content when bin==nil - last int - peekc int - peekc1 int // second peekc for ... - nlsemi bool - eofnl bool - importsafe bool + infile string + bin *obj.Biobuf + cp string // used for content when bin==nil + last int + peekc int + peekc1 int // second peekc for ... + nlsemi bool + eofnl bool } type Dlist struct { diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go index b9c27357bb..f1112e5af8 100644 --- a/src/cmd/compile/internal/gc/lex.go +++ b/src/cmd/compile/internal/gc/lex.go @@ -884,7 +884,6 @@ func cannedimports(file string, cp string) { curio.infile = file curio.cp = cp curio.nlsemi = false - curio.importsafe = false typecheckok = true incannedimport = 1 diff --git a/src/cmd/compile/internal/gc/parser.go b/src/cmd/compile/internal/gc/parser.go index 054cf73656..2e4be63a34 100644 --- a/src/cmd/compile/internal/gc/parser.go +++ b/src/cmd/compile/internal/gc/parser.go @@ -71,7 +71,6 @@ func (p *parser) loadsys() { } else { cannedimports("runtime.Builtin", runtimeimport) } - curio.importsafe = true p.import_package() p.import_there() @@ -467,9 +466,10 @@ func (p *parser) import_package() { p.import_error() } + importsafe := false if p.tok == LNAME { if p.sym_.Name == "safe" { - curio.importsafe = true + importsafe = true } p.next() } @@ -484,9 +484,9 @@ func (p *parser) import_package() { if incannedimport == 0 { importpkg.Direct = true } - importpkg.Safe = curio.importsafe + importpkg.Safe = importsafe - if safemode != 0 && !curio.importsafe { + if safemode != 0 && !importsafe { Yyerror("cannot import unsafe package %q", importpkg.Path) } } From 7555f7f2bf1636443b6013c90e45698894af75e1 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 1 Dec 2015 11:52:32 -0800 Subject: [PATCH 035/117] cmd/compile: cleanup mkbuiltin.go Changes largely in preparation for eventually switching the builtin export data to use the new binary format. Replace fancy incremental line-by-line scanning with simply reading the entire object file into memory, finding the export data section, and processing it that way. Just use "package runtime" and "package unsafe" in the builtin Go source files so we don't need to rewrite references to "PACKAGE". Stop looking for init_PACKAGE_function; it doesn't exist anyway. Compile package runtime with -u so that its export data marks it as a "safe" package. Eliminate requirement to pass "runtime" and "unsafe" as command-line arguments so that just "go run mkbuiltin.go" works. Only rewrite builtin.go when successful. Change-Id: I4addfde9e0cfb30607c7a83de686bde0ad1f035a Reviewed-on: https://go-review.googlesource.com/19624 Reviewed-by: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/gc/builtin.go | 2 +- .../compile/internal/gc/builtin/runtime.go | 2 +- src/cmd/compile/internal/gc/builtin/unsafe.go | 2 +- src/cmd/compile/internal/gc/lex.go | 2 +- src/cmd/compile/internal/gc/mkbuiltin.go | 88 ++++++++----------- src/cmd/compile/internal/gc/parser.go | 2 +- 6 files changed, 41 insertions(+), 57 deletions(-) diff --git a/src/cmd/compile/internal/gc/builtin.go b/src/cmd/compile/internal/gc/builtin.go index 4199fb35cc..1e1f85a4a1 100644 --- a/src/cmd/compile/internal/gc/builtin.go +++ b/src/cmd/compile/internal/gc/builtin.go @@ -3,7 +3,7 @@ package gc const runtimeimport = "" + - "package runtime\n" + + "package runtime safe\n" + "func @\"\".newobject (@\"\".typ·2 *byte) (? *any)\n" + "func @\"\".panicindex ()\n" + "func @\"\".panicslice ()\n" + diff --git a/src/cmd/compile/internal/gc/builtin/runtime.go b/src/cmd/compile/internal/gc/builtin/runtime.go index a50fc2e293..08f925f41c 100644 --- a/src/cmd/compile/internal/gc/builtin/runtime.go +++ b/src/cmd/compile/internal/gc/builtin/runtime.go @@ -8,7 +8,7 @@ // +build ignore -package PACKAGE +package runtime // emitted by compiler, not referred to by go programs diff --git a/src/cmd/compile/internal/gc/builtin/unsafe.go b/src/cmd/compile/internal/gc/builtin/unsafe.go index ce508692eb..a7fc8aa53e 100644 --- a/src/cmd/compile/internal/gc/builtin/unsafe.go +++ b/src/cmd/compile/internal/gc/builtin/unsafe.go @@ -8,7 +8,7 @@ // +build ignore -package PACKAGE +package unsafe type Pointer uintptr // not really; filled in by compiler diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go index f1112e5af8..a2a8be1610 100644 --- a/src/cmd/compile/internal/gc/lex.go +++ b/src/cmd/compile/internal/gc/lex.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:generate go run mkbuiltin.go runtime unsafe +//go:generate go run mkbuiltin.go package gc diff --git a/src/cmd/compile/internal/gc/mkbuiltin.go b/src/cmd/compile/internal/gc/mkbuiltin.go index b1e4458692..1b6cc4ae38 100644 --- a/src/cmd/compile/internal/gc/mkbuiltin.go +++ b/src/cmd/compile/internal/gc/mkbuiltin.go @@ -4,95 +4,79 @@ // +build ignore -// Generate builtin.go from builtin/runtime.go and builtin/unsafe.go -// (passed as arguments on the command line by a go:generate comment). +// Generate builtin.go from builtin/runtime.go and builtin/unsafe.go. // Run this after changing builtin/runtime.go and builtin/unsafe.go // or after changing the export metadata format in the compiler. // Either way, you need to have a working compiler binary first. package main import ( - "bufio" + "bytes" "fmt" "io" + "io/ioutil" "log" "os" "os/exec" - "strings" ) func main() { - f, err := os.Create("builtin.go") - if err != nil { - log.Fatal(err) - } - defer f.Close() - w := bufio.NewWriter(f) + var b bytes.Buffer + fmt.Fprintln(&b, "// AUTO-GENERATED by mkbuiltin.go; DO NOT EDIT") + fmt.Fprintln(&b, "") + fmt.Fprintln(&b, "package gc") - fmt.Fprintln(w, "// AUTO-GENERATED by mkbuiltin.go; DO NOT EDIT") - fmt.Fprintln(w, "") - fmt.Fprintln(w, "package gc") + mkbuiltin(&b, "runtime") + mkbuiltin(&b, "unsafe") - for _, name := range os.Args[1:] { - mkbuiltin(w, name) - } - - if err := w.Flush(); err != nil { + if err := ioutil.WriteFile("builtin.go", b.Bytes(), 0666); err != nil { log.Fatal(err) } } -// Compile .go file, import data from .6 file, and write Go string version. +// Compile .go file, import data from .o file, and write Go string version. func mkbuiltin(w io.Writer, name string) { - if err := exec.Command("go", "tool", "compile", "-A", "builtin/"+name+".go").Run(); err != nil { + args := []string{"tool", "compile", "-A"} + if name == "runtime" { + args = append(args, "-u") + } + args = append(args, "builtin/"+name+".go") + + if err := exec.Command("go", args...).Run(); err != nil { log.Fatal(err) } obj := name + ".o" defer os.Remove(obj) - r, err := os.Open(obj) + b, err := ioutil.ReadFile(obj) if err != nil { log.Fatal(err) } - defer r.Close() - scanner := bufio.NewScanner(r) // Look for $$ that introduces imports. - for scanner.Scan() { - if strings.Contains(scanner.Text(), "$$") { - goto Begin - } + i := bytes.Index(b, []byte("\n$$\n")) + if i < 0 { + log.Fatal("did not find beginning of imports") } - log.Fatal("did not find beginning of imports") + i += 4 -Begin: - initfunc := fmt.Sprintf("init_%s_function", name) - - fmt.Fprintf(w, "\nconst %simport = \"\" +\n", name) - - // sys.go claims to be in package PACKAGE to avoid - // conflicts during "go tool compile sys.go". Rename PACKAGE to $2. - replacer := strings.NewReplacer("PACKAGE", name) - - // Process imports, stopping at $$ that closes them. - for scanner.Scan() { - p := scanner.Text() - if strings.Contains(p, "$$") { - goto End - } + // Look for $$ that closes imports. + j := bytes.Index(b[i:], []byte("\n$$\n")) + if j < 0 { + log.Fatal("did not find end of imports") + } + j += i + 4 + // Process and reformat imports. + fmt.Fprintf(w, "\nconst %simport = \"\"", name) + for _, p := range bytes.SplitAfter(b[i:j], []byte("\n")) { // Chop leading white space. - p = strings.TrimLeft(p, " \t") - - // Cut out decl of init_$1_function - it doesn't exist. - if strings.Contains(p, initfunc) { + p = bytes.TrimLeft(p, " \t") + if len(p) == 0 { continue } - fmt.Fprintf(w, "\t%q +\n", replacer.Replace(p)+"\n") + fmt.Fprintf(w, " +\n\t%q", p) } - log.Fatal("did not find end of imports") - -End: - fmt.Fprintf(w, "\t\"$$\\n\"\n") + fmt.Fprintf(w, "\n") } diff --git a/src/cmd/compile/internal/gc/parser.go b/src/cmd/compile/internal/gc/parser.go index 2e4be63a34..dc6ae72d5f 100644 --- a/src/cmd/compile/internal/gc/parser.go +++ b/src/cmd/compile/internal/gc/parser.go @@ -67,7 +67,7 @@ func (p *parser) loadsys() { importpkg = Runtimepkg if Debug['A'] != 0 { - cannedimports("runtime.Builtin", "package runtime\n\n$$\n\n") + cannedimports("runtime.Builtin", "package runtime safe\n\n$$\n\n") } else { cannedimports("runtime.Builtin", runtimeimport) } From 98cc8b4cf219384792e19dec9bc17a0e49c466f6 Mon Sep 17 00:00:00 2001 From: Rhys Hiltner Date: Thu, 18 Feb 2016 13:35:49 -0800 Subject: [PATCH 036/117] cmd/link/internal/ld: remove unused call to os.Getwd This call to os.Getwd (or getwd) has been part of the linker since the C implementation in 7d507dc6e6. It stopped being used in 26438d4d80, and survived the conversion to Go in 1f9dbb60ef. Its return value goes unused (the linker gets the value for AT_comp_dir in dwarf.go), remove it. Change-Id: I3d4594813bb4ee0a6af31a36e19d99ec4b863677 Reviewed-on: https://go-review.googlesource.com/19655 Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot --- src/cmd/link/internal/ld/sym.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/cmd/link/internal/ld/sym.go b/src/cmd/link/internal/ld/sym.go index 731f3ede94..6122b85298 100644 --- a/src/cmd/link/internal/ld/sym.go +++ b/src/cmd/link/internal/ld/sym.go @@ -34,8 +34,6 @@ package ld import ( "cmd/internal/obj" "log" - "os" - "path/filepath" "strconv" ) @@ -70,13 +68,6 @@ func linknew(arch *LinkArch) *Link { log.Fatalf("invalid goarch %s (want %s)", p, arch.Name) } - var buf string - buf, _ = os.Getwd() - if buf == "" { - buf = "/???" - } - buf = filepath.ToSlash(buf) - ctxt.Headtype = headtype(obj.Getgoos()) if ctxt.Headtype < 0 { log.Fatalf("unknown goos %s", obj.Getgoos()) From 2eeaaaae7530337c23b0d4d76ac519e677c125dd Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 19 Feb 2016 04:29:13 +0530 Subject: [PATCH 037/117] net/http: fix bug where http2 wasn't enabled on DefaultTransport I had accidentally disabled a headline feature at the last second. :( Fixes #14391 Change-Id: I1992c9b801072b7538b95c55242be174075ff932 Reviewed-on: https://go-review.googlesource.com/19672 Reviewed-by: Ian Lance Taylor Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/net/http/transport.go | 10 +++++++--- src/net/http/transport_test.go | 5 +++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/net/http/transport.go b/src/net/http/transport.go index baf71d5e85..1e3ea11d9c 100644 --- a/src/net/http/transport.go +++ b/src/net/http/transport.go @@ -176,9 +176,13 @@ func (t *Transport) onceSetNextProtoDefaults() { // Issue 14275. return } - if t.ExpectContinueTimeout != 0 { - // Unsupported in http2, so disable http2 for now. - // Issue 13851. + if t.ExpectContinueTimeout != 0 && t != DefaultTransport { + // ExpectContinueTimeout is unsupported in http2, so + // if they explicitly asked for it (as opposed to just + // using the DefaultTransport, which sets it), then + // disable http2 for now. + // + // Issue 13851. (and changed in Issue 14391) return } t2, err := http2configureTransport(t) diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go index 0c901b30a4..d9da078fa0 100644 --- a/src/net/http/transport_test.go +++ b/src/net/http/transport_test.go @@ -2888,6 +2888,11 @@ func TestTransportAutomaticHTTP2(t *testing.T) { testTransportAutoHTTP(t, &Transport{}, true) } +// golang.org/issue/14391: also check DefaultTransport +func TestTransportAutomaticHTTP2_DefaultTransport(t *testing.T) { + testTransportAutoHTTP(t, DefaultTransport.(*Transport), true) +} + func TestTransportAutomaticHTTP2_TLSNextProto(t *testing.T) { testTransportAutoHTTP(t, &Transport{ TLSNextProto: make(map[string]func(string, *tls.Conn) RoundTripper), From 3ddfaa5653cfc5c8663319d017a5fb4de97814f4 Mon Sep 17 00:00:00 2001 From: Benoit Sigoure Date: Fri, 5 Feb 2016 17:18:46 -0800 Subject: [PATCH 038/117] cmd/gofmt: Ignore file not found errors. gofmt prints an error to stderr when a file is deleted during its `filepath.Walk()', which can happen in builds that change the tree concurrently with gofmt running. Change-Id: Ia1aa4804f6bc2172baf061c093e16fe56a3ee50c Reviewed-on: https://go-review.googlesource.com/19301 Reviewed-by: Robert Griesemer --- src/cmd/gofmt/gofmt.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go index cfebeffe4a..b10b804fd2 100644 --- a/src/cmd/gofmt/gofmt.go +++ b/src/cmd/gofmt/gofmt.go @@ -143,7 +143,9 @@ func visitFile(path string, f os.FileInfo, err error) error { if err == nil && isGoFile(f) { err = processFile(path, nil, os.Stdout, false) } - if err != nil { + // Don't complain if a file was deleted in the meantime (i.e. + // the directory changed concurrently while running gofmt). + if err != nil && !os.IsNotExist(err) { report(err) } return nil From 952c2fd606fad19b930937ca0d5c5571d7f5d4cb Mon Sep 17 00:00:00 2001 From: Ian Gudger Date: Thu, 18 Feb 2016 11:29:05 -0800 Subject: [PATCH 039/117] net: fix packDomainName encoding of root and invalid names Fixes #14372 Change-Id: I40d594582639e87ef2574d37ac868e37ffaa17dc Reviewed-on: https://go-review.googlesource.com/19623 Reviewed-by: Matthew Dempsky --- src/net/dnsmsg.go | 36 ++++++++++++++-- src/net/dnsmsg_test.go | 97 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+), 3 deletions(-) diff --git a/src/net/dnsmsg.go b/src/net/dnsmsg.go index 93078fe849..2ec4c8c301 100644 --- a/src/net/dnsmsg.go +++ b/src/net/dnsmsg.go @@ -406,6 +406,13 @@ func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) { s += "." } + // Allow root domain. + if s == "." { + msg[off] = 0 + off++ + return off, true + } + // Each dot ends a segment of the name. // We trade each dot byte for a length byte. // There is also a trailing zero. @@ -422,8 +429,13 @@ func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) { if i-begin >= 1<<6 { // top two bits of length must be clear return len(msg), false } + if i-begin == 0 { + return len(msg), false + } + msg[off] = byte(i - begin) off++ + for j := begin; j < i; j++ { msg[off] = s[j] off++ @@ -494,6 +506,9 @@ Loop: return "", len(msg), false } } + if len(s) == 0 { + s = "." + } if ptr == 0 { off1 = off } @@ -803,20 +818,32 @@ func (dns *dnsMsg) Pack() (msg []byte, ok bool) { // Pack it in: header and then the pieces. off := 0 off, ok = packStruct(&dh, msg, off) + if !ok { + return nil, false + } for i := 0; i < len(question); i++ { off, ok = packStruct(&question[i], msg, off) + if !ok { + return nil, false + } } for i := 0; i < len(answer); i++ { off, ok = packRR(answer[i], msg, off) + if !ok { + return nil, false + } } for i := 0; i < len(ns); i++ { off, ok = packRR(ns[i], msg, off) + if !ok { + return nil, false + } } for i := 0; i < len(extra); i++ { off, ok = packRR(extra[i], msg, off) - } - if !ok { - return nil, false + if !ok { + return nil, false + } } return msg[0:off], true } @@ -848,6 +875,9 @@ func (dns *dnsMsg) Unpack(msg []byte) bool { for i := 0; i < len(dns.question); i++ { off, ok = unpackStruct(&dns.question[i], msg, off) + if !ok { + return false + } } for i := 0; i < int(dh.Ancount); i++ { rec, off, ok = unpackRR(msg, off) diff --git a/src/net/dnsmsg_test.go b/src/net/dnsmsg_test.go index 1078d77ceb..339fb83c62 100644 --- a/src/net/dnsmsg_test.go +++ b/src/net/dnsmsg_test.go @@ -10,6 +10,103 @@ import ( "testing" ) +func TestStructPackUnpack(t *testing.T) { + want := dnsQuestion{ + Name: ".", + Qtype: dnsTypeA, + Qclass: dnsClassINET, + } + buf := make([]byte, 50) + n, ok := packStruct(&want, buf, 0) + if !ok { + t.Fatal("packing failed") + } + buf = buf[:n] + got := dnsQuestion{} + n, ok = unpackStruct(&got, buf, 0) + if !ok { + t.Fatal("unpacking failed") + } + if n != len(buf) { + t.Error("unpacked different amount than packed: got n = %d, want = %d", n, len(buf)) + } + if !reflect.DeepEqual(got, want) { + t.Errorf("got = %+v, want = %+v", got, want) + } +} + +func TestDomainNamePackUnpack(t *testing.T) { + tests := []struct { + in string + want string + ok bool + }{ + {"", ".", true}, + {".", ".", true}, + {"google..com", "", false}, + {"google.com", "google.com.", true}, + {"google..com.", "", false}, + {"google.com.", "google.com.", true}, + {".google.com.", "", false}, + {"www..google.com.", "", false}, + {"www.google.com.", "www.google.com.", true}, + } + + for _, test := range tests { + buf := make([]byte, 30) + n, ok := packDomainName(test.in, buf, 0) + if ok != test.ok { + t.Errorf("packing of %s: got ok = %t, want = %t", test.in, ok, test.ok) + continue + } + if !test.ok { + continue + } + buf = buf[:n] + got, n, ok := unpackDomainName(buf, 0) + if !ok { + t.Errorf("unpacking for %s failed", test.in) + continue + } + if n != len(buf) { + t.Error( + "unpacked different amount than packed for %s: got n = %d, want = %d", + test.in, + n, + len(buf), + ) + } + if got != test.want { + t.Errorf("unpacking packing of %s: got = %s, want = %s", test.in, got, test.want) + } + } +} + +func TestDNSPackUnpack(t *testing.T) { + want := dnsMsg{ + question: []dnsQuestion{{ + Name: ".", + Qtype: dnsTypeAAAA, + Qclass: dnsClassINET, + }}, + answer: []dnsRR{}, + ns: []dnsRR{}, + extra: []dnsRR{}, + } + b, ok := want.Pack() + if !ok { + t.Fatal("packing failed") + } + var got dnsMsg + ok = got.Unpack(b) + if !ok { + t.Fatal("unpacking failed") + } + if !reflect.DeepEqual(got, want) { + t.Errorf("got = %+v, want = %+v", got, want) + } +} + func TestDNSParseSRVReply(t *testing.T) { data, err := hex.DecodeString(dnsSRVReply) if err != nil { From b04f3b06ec347543b0eafe82dcfb0e05885d3feb Mon Sep 17 00:00:00 2001 From: Nathan VanBenschoten Date: Tue, 22 Dec 2015 02:40:47 -0500 Subject: [PATCH 040/117] all: replace strings.Index with strings.Contains where possible Change-Id: Ia613f1c37bfce800ece0533a5326fca91d99a66a Reviewed-on: https://go-review.googlesource.com/18120 Reviewed-by: Robert Griesemer Run-TryBot: Robert Griesemer --- src/cmd/compile/internal/big/ratconv.go | 4 ++-- src/cmd/compile/internal/gc/bexport.go | 2 +- src/encoding/csv/writer.go | 2 +- src/encoding/gob/codec_test.go | 2 +- src/encoding/gob/encoder_test.go | 8 ++++---- src/encoding/gob/gobencdec_test.go | 4 ++-- src/encoding/xml/marshal.go | 2 +- src/fmt/scan_test.go | 8 ++++---- src/go/doc/comment.go | 2 +- src/go/types/universe.go | 2 +- src/math/big/ratconv.go | 4 ++-- src/mime/grammar.go | 2 +- src/net/http/fs.go | 2 +- src/net/rpc/server_test.go | 4 ++-- src/net/url/url.go | 2 +- src/os/exec/lp_windows.go | 2 +- src/path/filepath/match.go | 4 ++-- src/path/filepath/match_test.go | 2 +- src/path/match.go | 2 +- src/regexp/regexp.go | 2 +- src/regexp/syntax/regexp.go | 2 +- src/runtime/debug/stack_test.go | 2 +- src/text/template/exec.go | 2 +- src/text/template/funcs.go | 2 +- src/text/template/parse/lex.go | 4 ++-- src/time/format_test.go | 2 +- 26 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/cmd/compile/internal/big/ratconv.go b/src/cmd/compile/internal/big/ratconv.go index 4566ff4e39..57df124e88 100644 --- a/src/cmd/compile/internal/big/ratconv.go +++ b/src/cmd/compile/internal/big/ratconv.go @@ -15,7 +15,7 @@ import ( ) func ratTok(ch rune) bool { - return strings.IndexRune("+-/0123456789.eE", ch) >= 0 + return strings.ContainsRune("+-/0123456789.eE", ch) } // Scan is a support routine for fmt.Scanner. It accepts the formats @@ -25,7 +25,7 @@ func (z *Rat) Scan(s fmt.ScanState, ch rune) error { if err != nil { return err } - if strings.IndexRune("efgEFGv", ch) < 0 { + if !strings.ContainsRune("efgEFGv", ch) { return errors.New("Rat.Scan: invalid verb") } if _, ok := z.SetString(string(tok)); !ok { diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go index b49f0fb552..3edd0488e7 100644 --- a/src/cmd/compile/internal/gc/bexport.go +++ b/src/cmd/compile/internal/gc/bexport.go @@ -877,7 +877,7 @@ func (p *exporter) byte(b byte) { // tracef is like fmt.Printf but it rewrites the format string // to take care of indentation. func (p *exporter) tracef(format string, args ...interface{}) { - if strings.IndexAny(format, "<>\n") >= 0 { + if strings.ContainsAny(format, "<>\n") { var buf bytes.Buffer for i := 0; i < len(format); i++ { // no need to deal with runes diff --git a/src/encoding/csv/writer.go b/src/encoding/csv/writer.go index 353d91f238..a6056285b4 100644 --- a/src/encoding/csv/writer.go +++ b/src/encoding/csv/writer.go @@ -130,7 +130,7 @@ func (w *Writer) fieldNeedsQuotes(field string) bool { if field == "" { return false } - if field == `\.` || strings.IndexRune(field, w.Comma) >= 0 || strings.IndexAny(field, "\"\r\n") >= 0 { + if field == `\.` || strings.ContainsRune(field, w.Comma) || strings.ContainsAny(field, "\"\r\n") { return true } diff --git a/src/encoding/gob/codec_test.go b/src/encoding/gob/codec_test.go index 8efcdc78ff..b772171f93 100644 --- a/src/encoding/gob/codec_test.go +++ b/src/encoding/gob/codec_test.go @@ -970,7 +970,7 @@ func TestBadRecursiveType(t *testing.T) { err := NewEncoder(b).Encode(&rec) if err == nil { t.Error("expected error; got none") - } else if strings.Index(err.Error(), "recursive") < 0 { + } else if !strings.Contains(err.Error(), "recursive") { t.Error("expected recursive type error; got", err) } // Can't test decode easily because we can't encode one, so we can't pass one to a Decoder. diff --git a/src/encoding/gob/encoder_test.go b/src/encoding/gob/encoder_test.go index 570d79696b..811dd2b18c 100644 --- a/src/encoding/gob/encoder_test.go +++ b/src/encoding/gob/encoder_test.go @@ -280,7 +280,7 @@ func TestValueError(t *testing.T) { } t4p := &Type4{3} var t4 Type4 // note: not a pointer. - if err := encAndDec(t4p, t4); err == nil || strings.Index(err.Error(), "pointer") < 0 { + if err := encAndDec(t4p, t4); err == nil || !strings.Contains(err.Error(), "pointer") { t.Error("expected error about pointer; got", err) } } @@ -388,7 +388,7 @@ func TestSingletons(t *testing.T) { t.Errorf("expected error decoding %v: %s", test.in, test.err) continue case err != nil && test.err != "": - if strings.Index(err.Error(), test.err) < 0 { + if !strings.Contains(err.Error(), test.err) { t.Errorf("wrong error decoding %v: wanted %s, got %v", test.in, test.err, err) } continue @@ -414,7 +414,7 @@ func TestStructNonStruct(t *testing.T) { var ns NonStruct if err := encAndDec(s, &ns); err == nil { t.Error("should get error for struct/non-struct") - } else if strings.Index(err.Error(), "type") < 0 { + } else if !strings.Contains(err.Error(), "type") { t.Error("for struct/non-struct expected type error; got", err) } // Now try the other way @@ -424,7 +424,7 @@ func TestStructNonStruct(t *testing.T) { } if err := encAndDec(ns, &s); err == nil { t.Error("should get error for non-struct/struct") - } else if strings.Index(err.Error(), "type") < 0 { + } else if !strings.Contains(err.Error(), "type") { t.Error("for non-struct/struct expected type error; got", err) } } diff --git a/src/encoding/gob/gobencdec_test.go b/src/encoding/gob/gobencdec_test.go index eb76b481d1..d674f0c784 100644 --- a/src/encoding/gob/gobencdec_test.go +++ b/src/encoding/gob/gobencdec_test.go @@ -548,7 +548,7 @@ func TestGobEncoderFieldTypeError(t *testing.T) { if err == nil { t.Fatal("expected decode error for mismatched fields (encoder to non-decoder)") } - if strings.Index(err.Error(), "type") < 0 { + if !strings.Contains(err.Error(), "type") { t.Fatal("expected type error; got", err) } // Non-encoder to GobDecoder: error @@ -562,7 +562,7 @@ func TestGobEncoderFieldTypeError(t *testing.T) { if err == nil { t.Fatal("expected decode error for mismatched fields (non-encoder to decoder)") } - if strings.Index(err.Error(), "type") < 0 { + if !strings.Contains(err.Error(), "type") { t.Fatal("expected type error; got", err) } } diff --git a/src/encoding/xml/marshal.go b/src/encoding/xml/marshal.go index 8ebd693030..9fcd5d7695 100644 --- a/src/encoding/xml/marshal.go +++ b/src/encoding/xml/marshal.go @@ -850,7 +850,7 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error { switch k { case reflect.String: s := vf.String() - dashDash = strings.Index(s, "--") >= 0 + dashDash = strings.Contains(s, "--") dashLast = s[len(s)-1] == '-' if !dashDash { p.WriteString(s) diff --git a/src/fmt/scan_test.go b/src/fmt/scan_test.go index 7ac74dcb4b..ce6f08659a 100644 --- a/src/fmt/scan_test.go +++ b/src/fmt/scan_test.go @@ -519,7 +519,7 @@ func testScanfMulti(name string, t *testing.T) { if err != nil { if test.err == "" { t.Errorf("got error scanning (%q, %q): %q", test.format, test.text, err) - } else if strings.Index(err.Error(), test.err) < 0 { + } else if !strings.Contains(err.Error(), test.err) { t.Errorf("got wrong error scanning (%q, %q): %q; expected %q", test.format, test.text, err, test.err) } continue @@ -613,7 +613,7 @@ func TestScanNotPointer(t *testing.T) { _, err := Fscan(r, a) if err == nil { t.Error("expected error scanning non-pointer") - } else if strings.Index(err.Error(), "pointer") < 0 { + } else if !strings.Contains(err.Error(), "pointer") { t.Errorf("expected pointer error scanning non-pointer, got: %s", err) } } @@ -623,7 +623,7 @@ func TestScanlnNoNewline(t *testing.T) { _, err := Sscanln("1 x\n", &a) if err == nil { t.Error("expected error scanning string missing newline") - } else if strings.Index(err.Error(), "newline") < 0 { + } else if !strings.Contains(err.Error(), "newline") { t.Errorf("expected newline error scanning string missing newline, got: %s", err) } } @@ -634,7 +634,7 @@ func TestScanlnWithMiddleNewline(t *testing.T) { _, err := Fscanln(r, &a, &b) if err == nil { t.Error("expected error scanning string with extra newline") - } else if strings.Index(err.Error(), "newline") < 0 { + } else if !strings.Contains(err.Error(), "newline") { t.Errorf("expected newline error scanning string with extra newline, got: %s", err) } } diff --git a/src/go/doc/comment.go b/src/go/doc/comment.go index f414ca4090..5631539abc 100644 --- a/src/go/doc/comment.go +++ b/src/go/doc/comment.go @@ -225,7 +225,7 @@ func heading(line string) string { } // exclude lines with illegal characters - if strings.IndexAny(line, ",.;:!?+*/=()[]{}_^°&§~%#@<\">\\") >= 0 { + if strings.ContainsAny(line, ",.;:!?+*/=()[]{}_^°&§~%#@<\">\\") { return "" } diff --git a/src/go/types/universe.go b/src/go/types/universe.go index 40185c1ad4..cc3bd5a370 100644 --- a/src/go/types/universe.go +++ b/src/go/types/universe.go @@ -196,7 +196,7 @@ func init() { // func def(obj Object) { name := obj.Name() - if strings.Index(name, " ") >= 0 { + if strings.Contains(name, " ") { return // nothing to do } // fix Obj link for named types diff --git a/src/math/big/ratconv.go b/src/math/big/ratconv.go index 4566ff4e39..57df124e88 100644 --- a/src/math/big/ratconv.go +++ b/src/math/big/ratconv.go @@ -15,7 +15,7 @@ import ( ) func ratTok(ch rune) bool { - return strings.IndexRune("+-/0123456789.eE", ch) >= 0 + return strings.ContainsRune("+-/0123456789.eE", ch) } // Scan is a support routine for fmt.Scanner. It accepts the formats @@ -25,7 +25,7 @@ func (z *Rat) Scan(s fmt.ScanState, ch rune) error { if err != nil { return err } - if strings.IndexRune("efgEFGv", ch) < 0 { + if !strings.ContainsRune("efgEFGv", ch) { return errors.New("Rat.Scan: invalid verb") } if _, ok := z.SetString(string(tok)); !ok { diff --git a/src/mime/grammar.go b/src/mime/grammar.go index 31b66e8f03..6a6f71dbd4 100644 --- a/src/mime/grammar.go +++ b/src/mime/grammar.go @@ -11,7 +11,7 @@ import ( // isTSpecial reports whether rune is in 'tspecials' as defined by RFC // 1521 and RFC 2045. func isTSpecial(r rune) bool { - return strings.IndexRune(`()<>@,;:\"/[]?=`, r) != -1 + return strings.ContainsRune(`()<>@,;:\"/[]?=`, r) } // isTokenChar reports whether rune is in 'token' as defined by RFC diff --git a/src/net/http/fs.go b/src/net/http/fs.go index f61c138c1d..8a5b8bba37 100644 --- a/src/net/http/fs.go +++ b/src/net/http/fs.go @@ -34,7 +34,7 @@ import ( type Dir string func (d Dir) Open(name string) (File, error) { - if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 || + if filepath.Separator != '/' && strings.ContainsRune(name, filepath.Separator) || strings.Contains(name, "\x00") { return nil, errors.New("http: invalid character in file path") } diff --git a/src/net/rpc/server_test.go b/src/net/rpc/server_test.go index 8871c88133..cf171ac4fb 100644 --- a/src/net/rpc/server_test.go +++ b/src/net/rpc/server_test.go @@ -183,7 +183,7 @@ func testRPC(t *testing.T, addr string) { err = client.Call("Arith.Unknown", args, reply) if err == nil { t.Error("expected error calling unknown service") - } else if strings.Index(err.Error(), "method") < 0 { + } else if !strings.Contains(err.Error(), "method") { t.Error("expected error about method; got", err) } @@ -226,7 +226,7 @@ func testRPC(t *testing.T, addr string) { err = client.Call("Arith.Add", reply, reply) // args, reply would be the correct thing to use if err == nil { t.Error("expected error calling Arith.Add with wrong arg type") - } else if strings.Index(err.Error(), "type") < 0 { + } else if !strings.Contains(err.Error(), "type") { t.Error("expected error about type; got", err) } diff --git a/src/net/url/url.go b/src/net/url/url.go index 1a93e3496e..b7e25ecfcb 100644 --- a/src/net/url/url.go +++ b/src/net/url/url.go @@ -511,7 +511,7 @@ func parseAuthority(authority string) (user *Userinfo, host string, err error) { return nil, host, nil } userinfo := authority[:i] - if strings.Index(userinfo, ":") < 0 { + if !strings.Contains(userinfo, ":") { if userinfo, err = unescape(userinfo, encodeUserPassword); err != nil { return nil, "", err } diff --git a/src/os/exec/lp_windows.go b/src/os/exec/lp_windows.go index c3efd67e9e..0b0712dcad 100644 --- a/src/os/exec/lp_windows.go +++ b/src/os/exec/lp_windows.go @@ -70,7 +70,7 @@ func LookPath(file string) (f string, err error) { } exts = append(exts, e) } - if strings.IndexAny(file, `:\/`) != -1 { + if strings.ContainsAny(file, `:\/`) { if f, err = findExecutable(file, exts); err == nil { return } diff --git a/src/path/filepath/match.go b/src/path/filepath/match.go index 89f16de355..d64bf84fc0 100644 --- a/src/path/filepath/match.go +++ b/src/path/filepath/match.go @@ -49,7 +49,7 @@ Pattern: star, chunk, pattern = scanChunk(pattern) if star && chunk == "" { // Trailing * matches rest of string unless it has a /. - return strings.Index(name, string(Separator)) < 0, nil + return !strings.Contains(name, string(Separator)), nil } // Look for match at current position. t, ok, err := matchChunk(chunk, name) @@ -305,5 +305,5 @@ func glob(dir, pattern string, matches []string) (m []string, e error) { // recognized by Match. func hasMeta(path string) bool { // TODO(niemeyer): Should other magic characters be added here? - return strings.IndexAny(path, "*?[") >= 0 + return strings.ContainsAny(path, "*?[") } diff --git a/src/path/filepath/match_test.go b/src/path/filepath/match_test.go index 0edbfc70c4..d8bab7f4da 100644 --- a/src/path/filepath/match_test.go +++ b/src/path/filepath/match_test.go @@ -88,7 +88,7 @@ func TestMatch(t *testing.T) { pattern := tt.pattern s := tt.s if runtime.GOOS == "windows" { - if strings.Index(pattern, "\\") >= 0 { + if strings.Contains(pattern, "\\") { // no escape allowed on windows. continue } diff --git a/src/path/match.go b/src/path/match.go index 75dd3b38e7..8d9aa513b1 100644 --- a/src/path/match.go +++ b/src/path/match.go @@ -43,7 +43,7 @@ Pattern: star, chunk, pattern = scanChunk(pattern) if star && chunk == "" { // Trailing * matches rest of string unless it has a /. - return strings.Index(name, "/") < 0, nil + return !strings.Contains(name, "/"), nil } // Look for match at current position. t, ok, err := matchChunk(chunk, name) diff --git a/src/regexp/regexp.go b/src/regexp/regexp.go index d7d0edb993..42ae6e1d7a 100644 --- a/src/regexp/regexp.go +++ b/src/regexp/regexp.go @@ -454,7 +454,7 @@ func Match(pattern string, b []byte) (matched bool, err error) { // in Expand, so for instance $1 represents the text of the first submatch. func (re *Regexp) ReplaceAllString(src, repl string) string { n := 2 - if strings.Index(repl, "$") >= 0 { + if strings.Contains(repl, "$") { n = 2 * (re.numSubexp + 1) } b := re.replaceAll(nil, src, n, func(dst []byte, match []int) []byte { diff --git a/src/regexp/syntax/regexp.go b/src/regexp/syntax/regexp.go index 75822cf981..ca5724063b 100644 --- a/src/regexp/syntax/regexp.go +++ b/src/regexp/syntax/regexp.go @@ -252,7 +252,7 @@ const meta = `\.+*?()|[]{}^$` func escape(b *bytes.Buffer, r rune, force bool) { if unicode.IsPrint(r) { - if strings.IndexRune(meta, r) >= 0 || force { + if strings.ContainsRune(meta, r) || force { b.WriteRune('\\') } b.WriteRune(r) diff --git a/src/runtime/debug/stack_test.go b/src/runtime/debug/stack_test.go index f54437231b..9376e82b84 100644 --- a/src/runtime/debug/stack_test.go +++ b/src/runtime/debug/stack_test.go @@ -59,7 +59,7 @@ func TestStack(t *testing.T) { } func check(t *testing.T, line, has string) { - if strings.Index(line, has) < 0 { + if !strings.Contains(line, has) { t.Errorf("expected %q in %q", has, line) } } diff --git a/src/text/template/exec.go b/src/text/template/exec.go index efe1817173..5ea45a4c53 100644 --- a/src/text/template/exec.go +++ b/src/text/template/exec.go @@ -446,7 +446,7 @@ func (s *state) idealConstant(constant *parse.NumberNode) reflect.Value { switch { case constant.IsComplex: return reflect.ValueOf(constant.Complex128) // incontrovertible. - case constant.IsFloat && !isHexConstant(constant.Text) && strings.IndexAny(constant.Text, ".eE") >= 0: + case constant.IsFloat && !isHexConstant(constant.Text) && strings.ContainsAny(constant.Text, ".eE"): return reflect.ValueOf(constant.Float64) case constant.IsInt: n := int(constant.Int64) diff --git a/src/text/template/funcs.go b/src/text/template/funcs.go index 49e9e7419a..58b8ea372d 100644 --- a/src/text/template/funcs.go +++ b/src/text/template/funcs.go @@ -515,7 +515,7 @@ func HTMLEscape(w io.Writer, b []byte) { // HTMLEscapeString returns the escaped HTML equivalent of the plain text data s. func HTMLEscapeString(s string) string { // Avoid allocation if we can. - if strings.IndexAny(s, `'"&<>`) < 0 { + if !strings.ContainsAny(s, `'"&<>`) { return s } var b bytes.Buffer diff --git a/src/text/template/parse/lex.go b/src/text/template/parse/lex.go index ea93e05142..079c0ea6f7 100644 --- a/src/text/template/parse/lex.go +++ b/src/text/template/parse/lex.go @@ -155,7 +155,7 @@ func (l *lexer) ignore() { // accept consumes the next rune if it's from the valid set. func (l *lexer) accept(valid string) bool { - if strings.IndexRune(valid, l.next()) >= 0 { + if strings.ContainsRune(valid, l.next()) { return true } l.backup() @@ -164,7 +164,7 @@ func (l *lexer) accept(valid string) bool { // acceptRun consumes a run of runes from the valid set. func (l *lexer) acceptRun(valid string) { - for strings.IndexRune(valid, l.next()) >= 0 { + for strings.ContainsRune(valid, l.next()) { } l.backup() } diff --git a/src/time/format_test.go b/src/time/format_test.go index af950a7c25..8c47dbcdd1 100644 --- a/src/time/format_test.go +++ b/src/time/format_test.go @@ -447,7 +447,7 @@ func TestParseErrors(t *testing.T) { _, err := Parse(test.format, test.value) if err == nil { t.Errorf("expected error for %q %q", test.format, test.value) - } else if strings.Index(err.Error(), test.expect) < 0 { + } else if !strings.Contains(err.Error(), test.expect) { t.Errorf("expected error with %q for %q %q; got %s", test.expect, test.format, test.value, err) } } From 76f272d71746fec4cc91f6772e81d8745aa65384 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Sun, 24 Jan 2016 11:14:46 -0500 Subject: [PATCH 041/117] cmd/asm: remove support for amd64 3DNow! instructions 3DNotAnymore! These only ever existed on AMD (not Intel) processors, and AMD cancelled support for them in August 2010. Change-Id: Ia362259add9d4f5788fd151fb373f91288677407 Reviewed-on: https://go-review.googlesource.com/19611 Reviewed-by: Ian Lance Taylor --- src/cmd/asm/internal/arch/arch.go | 2 -- src/cmd/internal/obj/x86/a.out.go | 24 ------------------- src/cmd/internal/obj/x86/anames.go | 23 ------------------- src/cmd/internal/obj/x86/asm6.go | 37 ------------------------------ 4 files changed, 86 deletions(-) diff --git a/src/cmd/asm/internal/arch/arch.go b/src/cmd/asm/internal/arch/arch.go index c14a13cdb1..f9436cb7f2 100644 --- a/src/cmd/asm/internal/arch/arch.go +++ b/src/cmd/asm/internal/arch/arch.go @@ -162,8 +162,6 @@ func archX86(linkArch *obj.LinkArch) *Arch { instructions["MOVDQ2Q"] = x86.AMOVQ instructions["MOVNTDQ"] = x86.AMOVNTO instructions["MOVOA"] = x86.AMOVO - instructions["PF2ID"] = x86.APF2IL - instructions["PI2FD"] = x86.API2FL instructions["PSLLDQ"] = x86.APSLLO instructions["PSRLDQ"] = x86.APSRLO instructions["PADDD"] = x86.APADDL diff --git a/src/cmd/internal/obj/x86/a.out.go b/src/cmd/internal/obj/x86/a.out.go index 12eaa90bf6..28c973b4a8 100644 --- a/src/cmd/internal/obj/x86/a.out.go +++ b/src/cmd/internal/obj/x86/a.out.go @@ -644,23 +644,6 @@ const ( APEXTRD APEXTRQ APEXTRW - APFACC - APFADD - APFCMPEQ - APFCMPGE - APFCMPGT - APFMAX - APFMIN - APFMUL - APFNACC - APFPNACC - APFRCP - APFRCPI2T - APFRCPIT1 - APFRSQIT1 - APFRSQRT - APFSUB - APFSUBR APHADDD APHADDSW APHADDW @@ -691,7 +674,6 @@ const ( APMOVZXWD APMOVZXWQ APMULDQ - APMULHRW APMULHUW APMULHW APMULLD @@ -722,7 +704,6 @@ const ( APSUBUSB APSUBUSW APSUBW - APSWAPL APUNPCKHBW APUNPCKHLQ APUNPCKHQDQ @@ -761,11 +742,6 @@ const ( AUNPCKLPS AXORPD AXORPS - - APF2IW - APF2IL - API2FW - API2FL ARETFW ARETFL ARETFQ diff --git a/src/cmd/internal/obj/x86/anames.go b/src/cmd/internal/obj/x86/anames.go index 1875eae418..3c3bc03622 100644 --- a/src/cmd/internal/obj/x86/anames.go +++ b/src/cmd/internal/obj/x86/anames.go @@ -593,23 +593,6 @@ var Anames = []string{ "PEXTRD", "PEXTRQ", "PEXTRW", - "PFACC", - "PFADD", - "PFCMPEQ", - "PFCMPGE", - "PFCMPGT", - "PFMAX", - "PFMIN", - "PFMUL", - "PFNACC", - "PFPNACC", - "PFRCP", - "PFRCPI2T", - "PFRCPIT1", - "PFRSQIT1", - "PFRSQRT", - "PFSUB", - "PFSUBR", "PHADDD", "PHADDSW", "PHADDW", @@ -640,7 +623,6 @@ var Anames = []string{ "PMOVZXWD", "PMOVZXWQ", "PMULDQ", - "PMULHRW", "PMULHUW", "PMULHW", "PMULLD", @@ -671,7 +653,6 @@ var Anames = []string{ "PSUBUSB", "PSUBUSW", "PSUBW", - "PSWAPL", "PUNPCKHBW", "PUNPCKHLQ", "PUNPCKHQDQ", @@ -710,10 +691,6 @@ var Anames = []string{ "UNPCKLPS", "XORPD", "XORPS", - "PF2IW", - "PF2IL", - "PI2FW", - "PI2FL", "RETFW", "RETFL", "RETFQ", diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go index 4ed1d8790b..a06d3097ad 100644 --- a/src/cmd/internal/obj/x86/asm6.go +++ b/src/cmd/internal/obj/x86/asm6.go @@ -184,7 +184,6 @@ const ( Zm2_r Zm_r_xm Zm_r_i_xm - Zm_r_3d Zm_r_xm_nr Zr_m_xm_nr Zibm_r /* mmx1,mmx2/mem64,imm8 */ @@ -753,10 +752,6 @@ var yxrrl = []ytab{ {Yxr, Ynone, Yrl, Zm_r, 1}, } -var ymfp = []ytab{ - {Ymm, Ynone, Ymr, Zm_r_3d, 1}, -} - var ymrxr = []ytab{ {Ymr, Ynone, Yxr, Zm_r, 1}, {Yxm, Ynone, Yxr, Zm_r_xm, 1}, @@ -1085,7 +1080,6 @@ var optab = {ACVTPD2PS, yxm, Pe, [23]uint8{0x5a}}, {ACVTPS2PL, yxcvm1, Px, [23]uint8{Pe, 0x5b, Pm, 0x2d}}, {ACVTPS2PD, yxm, Pm, [23]uint8{0x5a}}, - {API2FW, ymfp, Px, [23]uint8{0x0c}}, {ACVTSD2SL, yxcvfl, Pf2, [23]uint8{0x2d}}, {ACVTSD2SQ, yxcvfq, Pw, [23]uint8{Pf2, 0x2d}}, {ACVTSD2SS, yxm, Pf2, [23]uint8{0x5a}}, @@ -1303,26 +1297,6 @@ var optab = {APEXTRB, yextr, Pq, [23]uint8{0x3a, 0x14, 00}}, {APEXTRD, yextr, Pq, [23]uint8{0x3a, 0x16, 00}}, {APEXTRQ, yextr, Pq3, [23]uint8{0x3a, 0x16, 00}}, - {APF2IL, ymfp, Px, [23]uint8{0x1d}}, - {APF2IW, ymfp, Px, [23]uint8{0x1c}}, - {API2FL, ymfp, Px, [23]uint8{0x0d}}, - {APFACC, ymfp, Px, [23]uint8{0xae}}, - {APFADD, ymfp, Px, [23]uint8{0x9e}}, - {APFCMPEQ, ymfp, Px, [23]uint8{0xb0}}, - {APFCMPGE, ymfp, Px, [23]uint8{0x90}}, - {APFCMPGT, ymfp, Px, [23]uint8{0xa0}}, - {APFMAX, ymfp, Px, [23]uint8{0xa4}}, - {APFMIN, ymfp, Px, [23]uint8{0x94}}, - {APFMUL, ymfp, Px, [23]uint8{0xb4}}, - {APFNACC, ymfp, Px, [23]uint8{0x8a}}, - {APFPNACC, ymfp, Px, [23]uint8{0x8e}}, - {APFRCP, ymfp, Px, [23]uint8{0x96}}, - {APFRCPIT1, ymfp, Px, [23]uint8{0xa6}}, - {APFRCPI2T, ymfp, Px, [23]uint8{0xb6}}, - {APFRSQIT1, ymfp, Px, [23]uint8{0xa7}}, - {APFRSQRT, ymfp, Px, [23]uint8{0x97}}, - {APFSUB, ymfp, Px, [23]uint8{0x9a}}, - {APFSUBR, ymfp, Px, [23]uint8{0xaa}}, {APHADDD, ymmxmm0f38, Px, [23]uint8{0x0F, 0x38, 0x02, 0, 0x66, 0x0F, 0x38, 0x02, 0}}, {APHADDSW, yxm_q4, Pq4, [23]uint8{0x03}}, {APHADDW, yxm_q4, Pq4, [23]uint8{0x01}}, @@ -1353,7 +1327,6 @@ var optab = {APMOVZXWD, yxm_q4, Pq4, [23]uint8{0x33}}, {APMOVZXWQ, yxm_q4, Pq4, [23]uint8{0x34}}, {APMULDQ, yxm_q4, Pq4, [23]uint8{0x28}}, - {APMULHRW, ymfp, Px, [23]uint8{0xb7}}, {APMULHUW, ymm, Py1, [23]uint8{0xe4, Pe, 0xe4}}, {APMULHW, ymm, Py1, [23]uint8{0xe5, Pe, 0xe5}}, {APMULLD, yxm_q4, Pq4, [23]uint8{0x40}}, @@ -1395,7 +1368,6 @@ var optab = {APSUBUSB, yxm, Pe, [23]uint8{0xd8}}, {APSUBUSW, yxm, Pe, [23]uint8{0xd9}}, {APSUBW, yxm, Pe, [23]uint8{0xf9}}, - {APSWAPL, ymfp, Px, [23]uint8{0xbb}}, {APUNPCKHBW, ymm, Py1, [23]uint8{0x68, Pe, 0x68}}, {APUNPCKHLQ, ymm, Py1, [23]uint8{0x6a, Pe, 0x6a}}, {APUNPCKHQDQ, yxm, Pe, [23]uint8{0x6d}}, @@ -3533,15 +3505,6 @@ func doasm(ctxt *obj.Link, p *obj.Prog) { ctxt.Andptr[0] = byte(p.To.Offset) ctxt.Andptr = ctxt.Andptr[1:] - case Zm_r_3d: - ctxt.Andptr[0] = 0x0f - ctxt.Andptr = ctxt.Andptr[1:] - ctxt.Andptr[0] = 0x0f - ctxt.Andptr = ctxt.Andptr[1:] - asmand(ctxt, p, &p.From, &p.To) - ctxt.Andptr[0] = byte(op) - ctxt.Andptr = ctxt.Andptr[1:] - case Zibm_r, Zibr_m: for { tmp1 := z From 0b4f5782664b1e5ff6006cc3a66de520ed1c7c79 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 25 Jan 2016 15:21:10 -0500 Subject: [PATCH 042/117] cmd/asm: remove nonexistent amd64 instructions These have no accepted input syntax and, as far as I can tell, do not actually exist. Change-Id: Iafdfb71adccad76230191d922eb7ddf78b7d5898 Reviewed-on: https://go-review.googlesource.com/19612 Reviewed-by: Ian Lance Taylor --- src/cmd/internal/obj/x86/a.out.go | 9 --------- src/cmd/internal/obj/x86/anames.go | 9 --------- src/cmd/internal/obj/x86/asm6.go | 2 -- 3 files changed, 20 deletions(-) diff --git a/src/cmd/internal/obj/x86/a.out.go b/src/cmd/internal/obj/x86/a.out.go index 28c973b4a8..dacf612bc2 100644 --- a/src/cmd/internal/obj/x86/a.out.go +++ b/src/cmd/internal/obj/x86/a.out.go @@ -289,8 +289,6 @@ const ( AFMOVX AFMOVXP - AFCOMB - AFCOMBP AFCOMD AFCOMDP AFCOMDPP @@ -620,14 +618,7 @@ const ( APADDUSW APADDW APAND - APANDB - APANDL APANDN - APANDSB - APANDSW - APANDUSB - APANDUSW - APANDW APAVGB APAVGW APCMPEQB diff --git a/src/cmd/internal/obj/x86/anames.go b/src/cmd/internal/obj/x86/anames.go index 3c3bc03622..3b59e2f36f 100644 --- a/src/cmd/internal/obj/x86/anames.go +++ b/src/cmd/internal/obj/x86/anames.go @@ -255,8 +255,6 @@ var Anames = []string{ "FMOVWP", "FMOVX", "FMOVXP", - "FCOMB", - "FCOMBP", "FCOMD", "FCOMDP", "FCOMDPP", @@ -569,14 +567,7 @@ var Anames = []string{ "PADDUSW", "PADDW", "PAND", - "PANDB", - "PANDL", "PANDN", - "PANDSB", - "PANDSW", - "PANDUSB", - "PANDUSW", - "PANDW", "PAVGB", "PAVGW", "PCMPEQB", diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go index a06d3097ad..2b71822799 100644 --- a/src/cmd/internal/obj/x86/asm6.go +++ b/src/cmd/internal/obj/x86/asm6.go @@ -1525,8 +1525,6 @@ var optab = {AFCMOVNE, yfcmv, Px, [23]uint8{0xdb, 01}}, {AFCMOVNU, yfcmv, Px, [23]uint8{0xdb, 03}}, {AFCMOVUN, yfcmv, Px, [23]uint8{0xda, 03}}, - {AFCOMB, nil, 0, [23]uint8{}}, - {AFCOMBP, nil, 0, [23]uint8{}}, {AFCOMD, yfadd, Px, [23]uint8{0xdc, 02, 0xd8, 02, 0xdc, 02}}, /* botch */ {AFCOMDP, yfadd, Px, [23]uint8{0xdc, 03, 0xd8, 03, 0xdc, 03}}, /* botch */ {AFCOMDPP, ycompp, Px, [23]uint8{0xde, 03}}, From 51b624e6a29b135ce0fadb22b678acf4998ff16f Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 28 Jan 2016 22:50:03 -0500 Subject: [PATCH 043/117] cmd/link: remove alternate -X flag spelling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Go 1.6 release notes say we'll remove the “-X name value” form (in favor of the “-X name=value” form) in Go 1.7. Do that. Also establish the doc/go1.7.txt file. Change-Id: Ie4565a6bc5dbcf155181754d8d92bfbb23c75338 Reviewed-on: https://go-review.googlesource.com/19614 Reviewed-by: Ian Lance Taylor --- doc/go1.7.txt | 13 +++++++++++++ src/cmd/go/go_test.go | 4 ++-- src/cmd/link/internal/ld/pobj.go | 27 --------------------------- test/linkx_run.go | 2 +- 4 files changed, 16 insertions(+), 30 deletions(-) create mode 100644 doc/go1.7.txt diff --git a/doc/go1.7.txt b/doc/go1.7.txt new file mode 100644 index 0000000000..b2573bef83 --- /dev/null +++ b/doc/go1.7.txt @@ -0,0 +1,13 @@ +Tools: + +cmd/link: "-X name value" form gone (CL XXX) + +Ports: + +SOMETHING WILL HAPPEN + +API additions and behavior changes: + +SOMETHING WILL HAPPEN + + diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index e55fc360de..7d38915176 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -1657,8 +1657,8 @@ func TestLdflagsArgumentsWithSpacesIssue3941(t *testing.T) { func main() { println(extern) }`) - tg.run("run", "-ldflags", `-X main.extern "hello world"`, tg.path("main.go")) - tg.grepStderr("^hello world", `ldflags -X main.extern 'hello world' failed`) + tg.run("run", "-ldflags", `-X "main.extern=hello world"`, tg.path("main.go")) + tg.grepStderr("^hello world", `ldflags -X "main.extern=hello world"' failed`) } func TestGoTestCpuprofileLeavesBinaryBehind(t *testing.T) { diff --git a/src/cmd/link/internal/ld/pobj.go b/src/cmd/link/internal/ld/pobj.go index 808d377f8a..9ec14c24ed 100644 --- a/src/cmd/link/internal/ld/pobj.go +++ b/src/cmd/link/internal/ld/pobj.go @@ -119,33 +119,6 @@ func Ldmain() { obj.Flagstr("memprofile", "write memory profile to `file`", &memprofile) obj.Flagint64("memprofilerate", "set runtime.MemProfileRate to `rate`", &memprofilerate) - // Clumsy hack to preserve old two-argument -X name val syntax for old scripts. - // Rewrite that syntax into new syntax -X name=val. - // TODO(rsc): Delete this hack in Go 1.6 or later. - var args []string - for i := 0; i < len(os.Args); i++ { - arg := os.Args[i] - if (arg == "-X" || arg == "--X") && i+2 < len(os.Args) && !strings.Contains(os.Args[i+1], "=") { - fmt.Fprintf(os.Stderr, "link: warning: option %s %s %s may not work in future releases; use %s %s=%s\n", - arg, os.Args[i+1], os.Args[i+2], - arg, os.Args[i+1], os.Args[i+2]) - args = append(args, arg) - args = append(args, os.Args[i+1]+"="+os.Args[i+2]) - i += 2 - continue - } - if (strings.HasPrefix(arg, "-X=") || strings.HasPrefix(arg, "--X=")) && i+1 < len(os.Args) && strings.Count(arg, "=") == 1 { - fmt.Fprintf(os.Stderr, "link: warning: option %s %s may not work in future releases; use %s=%s\n", - arg, os.Args[i+1], - arg, os.Args[i+1]) - args = append(args, arg+"="+os.Args[i+1]) - i++ - continue - } - args = append(args, arg) - } - os.Args = args - obj.Flagparse(usage) startProfile() diff --git a/test/linkx_run.go b/test/linkx_run.go index a6c7c67014..440271ac4a 100644 --- a/test/linkx_run.go +++ b/test/linkx_run.go @@ -18,7 +18,7 @@ import ( ) func main() { - test(" ") // old deprecated syntax + // test(" ") // old deprecated & removed syntax test("=") // new syntax } From 3e23442518d9c66def2ae48f83026e29c5f26609 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 28 Jan 2016 22:51:50 -0500 Subject: [PATCH 044/117] cmd/go: remove GO15VENDOREXPERIMENT variable The Go 1.6 release notes say that Go 1.7 will remove support for the GO15VENDOREXPERIMENT environment variable, making vendoring always on. Do that. Change-Id: Iba8b79532455828869c1a8076a82edce84259468 Reviewed-on: https://go-review.googlesource.com/19615 Reviewed-by: Ian Lance Taylor --- doc/go1.7.txt | 3 ++- src/cmd/go/alldocs.go | 8 -------- src/cmd/go/env.go | 6 ------ src/cmd/go/help.go | 8 -------- src/cmd/go/pkg.go | 19 +++---------------- src/cmd/go/vcs.go | 8 ++++---- src/cmd/go/vendor_test.go | 14 -------------- 7 files changed, 9 insertions(+), 57 deletions(-) diff --git a/doc/go1.7.txt b/doc/go1.7.txt index b2573bef83..15efa287ce 100644 --- a/doc/go1.7.txt +++ b/doc/go1.7.txt @@ -1,6 +1,7 @@ Tools: -cmd/link: "-X name value" form gone (CL XXX) +cmd/go: GO15VENDOREXPERIMENT gone, assumed on (CL 19615) +cmd/link: "-X name value" form gone (CL 19614) Ports: diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index c81bd40864..bbad8d40e9 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -1022,12 +1022,6 @@ Vendor directories do not affect the placement of new repositories being checked out for the first time by 'go get': those are always placed in the main GOPATH, never in a vendor subtree. -In Go 1.5, as an experiment, setting the environment variable -GO15VENDOREXPERIMENT=1 enabled these features. -As of Go 1.6 they are on by default. To turn them off, set -GO15VENDOREXPERIMENT=0. In Go 1.7, the environment -variable will stop having any effect. - See https://golang.org/s/go15vendor for details. @@ -1094,8 +1088,6 @@ Special-purpose environment variables: installed in a location other than where it is built. File names in stack traces are rewritten from GOROOT to GOROOT_FINAL. - GO15VENDOREXPERIMENT - Set to 0 to disable vendoring semantics. GO_EXTLINK_ENABLED Whether the linker should use external linking mode when using -linkmode=auto with code that uses cgo. diff --git a/src/cmd/go/env.go b/src/cmd/go/env.go index 24f612756b..8d427b37c2 100644 --- a/src/cmd/go/env.go +++ b/src/cmd/go/env.go @@ -33,11 +33,6 @@ func mkEnv() []envVar { var b builder b.init() - vendorExpValue := "0" - if go15VendorExperiment { - vendorExpValue = "1" - } - env := []envVar{ {"GOARCH", goarch}, {"GOBIN", gobin}, @@ -49,7 +44,6 @@ func mkEnv() []envVar { {"GORACE", os.Getenv("GORACE")}, {"GOROOT", goroot}, {"GOTOOLDIR", toolDir}, - {"GO15VENDOREXPERIMENT", vendorExpValue}, // disable escape codes in clang errors {"TERM", "dumb"}, diff --git a/src/cmd/go/help.go b/src/cmd/go/help.go index d8e7efedb3..de5e5ddeab 100644 --- a/src/cmd/go/help.go +++ b/src/cmd/go/help.go @@ -421,12 +421,6 @@ Vendor directories do not affect the placement of new repositories being checked out for the first time by 'go get': those are always placed in the main GOPATH, never in a vendor subtree. -In Go 1.5, as an experiment, setting the environment variable -GO15VENDOREXPERIMENT=1 enabled these features. -As of Go 1.6 they are on by default. To turn them off, set -GO15VENDOREXPERIMENT=0. In Go 1.7, the environment -variable will stop having any effect. - See https://golang.org/s/go15vendor for details. `, } @@ -497,8 +491,6 @@ Special-purpose environment variables: installed in a location other than where it is built. File names in stack traces are rewritten from GOROOT to GOROOT_FINAL. - GO15VENDOREXPERIMENT - Set to 0 to disable vendoring semantics. GO_EXTLINK_ENABLED Whether the linker should use external linking mode when using -linkmode=auto with code that uses cgo. diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go index 0c0cf07e71..6b5ead2b8c 100644 --- a/src/cmd/go/pkg.go +++ b/src/cmd/go/pkg.go @@ -263,15 +263,6 @@ func reloadPackage(arg string, stk *importStack) *Package { return loadPackage(arg, stk) } -// The Go 1.5 vendoring experiment was enabled by setting GO15VENDOREXPERIMENT=1. -// In Go 1.6 this is on by default and is disabled by setting GO15VENDOREXPERIMENT=0. -// In Go 1.7 the variable will stop having any effect. -// The variable is obnoxiously long so that years from now when people find it in -// their profiles and wonder what it does, there is some chance that a web search -// might answer the question. -// There is a copy of this variable in src/go/build/build.go. Delete that one when this one goes away. -var go15VendorExperiment = os.Getenv("GO15VENDOREXPERIMENT") != "0" - // dirToImportPath returns the pseudo-import path we use for a package // outside the Go path. It begins with _/ and then contains the full path // to the directory. If the package lives in c:\home\gopher\my\pkg then @@ -361,7 +352,7 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo // TODO: After Go 1, decide when to pass build.AllowBinary here. // See issue 3268 for mistakes to avoid. buildMode := build.ImportComment - if !go15VendorExperiment || mode&useVendor == 0 || path != origPath { + if mode&useVendor == 0 || path != origPath { // Not vendoring, or we already found the vendored path. buildMode |= build.IgnoreVendor } @@ -371,7 +362,7 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo bp.BinDir = gobin } if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path && - (!go15VendorExperiment || (!strings.Contains(path, "/vendor/") && !strings.HasPrefix(path, "vendor/"))) { + !strings.Contains(path, "/vendor/") && !strings.HasPrefix(path, "vendor/") { err = fmt.Errorf("code in directory %s expects import %q", bp.Dir, bp.ImportComment) } p.load(stk, bp, err) @@ -412,7 +403,7 @@ func isDir(path string) bool { // x/vendor/path, vendor/path, or else stay path if none of those exist. // vendoredImportPath returns the expanded path or, if no expansion is found, the original. func vendoredImportPath(parent *Package, path string) (found string) { - if parent == nil || parent.Root == "" || !go15VendorExperiment { + if parent == nil || parent.Root == "" { return path } @@ -580,10 +571,6 @@ func findInternal(path string) (index int, ok bool) { // If the import is allowed, disallowVendor returns the original package p. // If not, it returns a new package containing just an appropriate error. func disallowVendor(srcDir, path string, p *Package, stk *importStack) *Package { - if !go15VendorExperiment { - return p - } - // The stack includes p.ImportPath. // If that's the only thing on the stack, we started // with a name given on the command line, not an diff --git a/src/cmd/go/vcs.go b/src/cmd/go/vcs.go index 342edee50d..797d91fb96 100644 --- a/src/cmd/go/vcs.go +++ b/src/cmd/go/vcs.go @@ -383,7 +383,7 @@ func (v *vcsCmd) ping(scheme, repo string) error { // The parent of dir must exist; dir must not. func (v *vcsCmd) create(dir, repo string) error { for _, cmd := range v.createCmd { - if !go15VendorExperiment && strings.Contains(cmd, "submodule") { + if strings.Contains(cmd, "submodule") { continue } if err := v.run(".", cmd, "dir", dir, "repo", repo); err != nil { @@ -396,7 +396,7 @@ func (v *vcsCmd) create(dir, repo string) error { // download downloads any new changes for the repo in dir. func (v *vcsCmd) download(dir string) error { for _, cmd := range v.downloadCmd { - if !go15VendorExperiment && strings.Contains(cmd, "submodule") { + if strings.Contains(cmd, "submodule") { continue } if err := v.run(dir, cmd); err != nil { @@ -445,7 +445,7 @@ func (v *vcsCmd) tagSync(dir, tag string) error { if tag == "" && v.tagSyncDefault != nil { for _, cmd := range v.tagSyncDefault { - if !go15VendorExperiment && strings.Contains(cmd, "submodule") { + if strings.Contains(cmd, "submodule") { continue } if err := v.run(dir, cmd); err != nil { @@ -456,7 +456,7 @@ func (v *vcsCmd) tagSync(dir, tag string) error { } for _, cmd := range v.tagSyncCmd { - if !go15VendorExperiment && strings.Contains(cmd, "submodule") { + if strings.Contains(cmd, "submodule") { continue } if err := v.run(dir, cmd, "tag", tag); err != nil { diff --git a/src/cmd/go/vendor_test.go b/src/cmd/go/vendor_test.go index 006a8c9d3f..40fe309b6d 100644 --- a/src/cmd/go/vendor_test.go +++ b/src/cmd/go/vendor_test.go @@ -20,7 +20,6 @@ func TestVendorImports(t *testing.T) { tg := testgo(t) defer tg.cleanup() tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) - tg.setenv("GO15VENDOREXPERIMENT", "1") tg.run("list", "-f", "{{.ImportPath}} {{.Imports}}", "vend/...") want := ` vend [vend/vendor/p r] @@ -51,7 +50,6 @@ func TestVendorBuild(t *testing.T) { tg := testgo(t) defer tg.cleanup() tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) - tg.setenv("GO15VENDOREXPERIMENT", "1") tg.run("build", "vend/x") } @@ -59,7 +57,6 @@ func TestVendorRun(t *testing.T) { tg := testgo(t) defer tg.cleanup() tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) - tg.setenv("GO15VENDOREXPERIMENT", "1") tg.cd(filepath.Join(tg.pwd(), "testdata/src/vend/hello")) tg.run("run", "hello.go") tg.grepStdout("hello, world", "missing hello world output") @@ -74,7 +71,6 @@ func TestVendorGOPATH(t *testing.T) { } gopath := changeVolume(filepath.Join(tg.pwd(), "testdata"), strings.ToLower) tg.setenv("GOPATH", gopath) - tg.setenv("GO15VENDOREXPERIMENT", "1") cd := changeVolume(filepath.Join(tg.pwd(), "testdata/src/vend/hello"), strings.ToUpper) tg.cd(cd) tg.run("run", "hello.go") @@ -85,7 +81,6 @@ func TestVendorTest(t *testing.T) { tg := testgo(t) defer tg.cleanup() tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) - tg.setenv("GO15VENDOREXPERIMENT", "1") tg.cd(filepath.Join(tg.pwd(), "testdata/src/vend/hello")) tg.run("test", "-v") tg.grepStdout("TestMsgInternal", "missing use in internal test") @@ -96,7 +91,6 @@ func TestVendorInvalid(t *testing.T) { tg := testgo(t) defer tg.cleanup() tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) - tg.setenv("GO15VENDOREXPERIMENT", "1") tg.runFail("build", "vend/x/invalid") tg.grepStderr("must be imported as foo", "missing vendor import error") @@ -106,7 +100,6 @@ func TestVendorImportError(t *testing.T) { tg := testgo(t) defer tg.cleanup() tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) - tg.setenv("GO15VENDOREXPERIMENT", "1") tg.runFail("build", "vend/x/vendor/p/p") @@ -173,7 +166,6 @@ func TestVendorGet(t *testing.T) { package p const C = 1`) tg.setenv("GOPATH", tg.path(".")) - tg.setenv("GO15VENDOREXPERIMENT", "1") tg.cd(tg.path("src/v")) tg.run("run", "m.go") tg.run("test") @@ -192,7 +184,6 @@ func TestVendorGetUpdate(t *testing.T) { defer tg.cleanup() tg.makeTempdir() tg.setenv("GOPATH", tg.path(".")) - tg.setenv("GO15VENDOREXPERIMENT", "1") tg.run("get", "github.com/rsc/go-get-issue-11864") tg.run("get", "-u", "github.com/rsc/go-get-issue-11864") } @@ -204,7 +195,6 @@ func TestGetSubmodules(t *testing.T) { defer tg.cleanup() tg.makeTempdir() tg.setenv("GOPATH", tg.path(".")) - tg.setenv("GO15VENDOREXPERIMENT", "1") tg.run("get", "-d", "github.com/rsc/go-get-issue-12612") tg.run("get", "-u", "-d", "github.com/rsc/go-get-issue-12612") } @@ -213,7 +203,6 @@ func TestVendorCache(t *testing.T) { tg := testgo(t) defer tg.cleanup() tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/testvendor")) - tg.setenv("GO15VENDOREXPERIMENT", "1") tg.runFail("build", "p") tg.grepStderr("must be imported as x", "did not fail to build p") } @@ -225,7 +214,6 @@ func TestVendorTest2(t *testing.T) { defer tg.cleanup() tg.makeTempdir() tg.setenv("GOPATH", tg.path(".")) - tg.setenv("GO15VENDOREXPERIMENT", "1") tg.run("get", "github.com/rsc/go-get-issue-11864") // build -i should work @@ -251,7 +239,6 @@ func TestVendorList(t *testing.T) { defer tg.cleanup() tg.makeTempdir() tg.setenv("GOPATH", tg.path(".")) - tg.setenv("GO15VENDOREXPERIMENT", "1") tg.run("get", "github.com/rsc/go-get-issue-11864") tg.run("list", "-f", `{{join .TestImports "\n"}}`, "github.com/rsc/go-get-issue-11864/t") @@ -272,7 +259,6 @@ func TestVendor12156(t *testing.T) { tg := testgo(t) defer tg.cleanup() tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/testvendor2")) - tg.setenv("GO15VENDOREXPERIMENT", "1") tg.cd(filepath.Join(tg.pwd(), "testdata/testvendor2/src/p")) tg.runFail("build", "p.go") tg.grepStderrNot("panic", "panicked") From 53ebde225e0ecaff8c3b71356a4726fad753d47c Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 1 Feb 2016 12:22:39 -0500 Subject: [PATCH 045/117] cmd/cgo: do not use gcc -xc - to compile standard input We have private reports of compilers that mishandle that. Write to a temporary file instead. Change-Id: I92e3cf4274b1a8048741e07fb52b8900c93b915e Reviewed-on: https://go-review.googlesource.com/19616 Reviewed-by: Ian Lance Taylor --- src/cmd/cgo/util.go | 47 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/cmd/cgo/util.go b/src/cmd/cgo/util.go index 3adb8e8783..52ca160ad9 100644 --- a/src/cmd/cgo/util.go +++ b/src/cmd/cgo/util.go @@ -8,6 +8,7 @@ import ( "bytes" "fmt" "go/token" + "io/ioutil" "os" "os/exec" ) @@ -16,6 +17,43 @@ import ( // It returns the output to standard output and standard error. // ok indicates whether the command exited successfully. func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) { + if i := find(argv, "-xc"); i >= 0 && argv[len(argv)-1] == "-" { + // Some compilers have trouble with standard input. + // Others have trouble with -xc. + // Avoid both problems by writing a file with a .c extension. + f, err := ioutil.TempFile("", "cgo-gcc-input-") + if err != nil { + fatalf("%s", err) + } + name := f.Name() + f.Close() + if err := ioutil.WriteFile(name+".c", stdin, 0666); err != nil { + os.Remove(name) + fatalf("%s", err) + } + defer os.Remove(name) + defer os.Remove(name + ".c") + + // Build new argument list without -xc and trailing -. + new := append(argv[:i:i], argv[i+1:len(argv)-1]...) + + // Since we are going to write the file to a temporary directory, + // we will need to add -I . explicitly to the command line: + // any #include "foo" before would have looked in the current + // directory as the directory "holding" standard input, but now + // the temporary directory holds the input. + // We've also run into compilers that reject "-I." but allow "-I", ".", + // so be sure to use two arguments. + // This matters mainly for people invoking cgo -godefs by hand. + new = append(new, "-I", ".") + + // Finish argument list with path to C file. + new = append(new, name+".c") + + argv = new + stdin = nil + } + p := exec.Command(argv[0], argv[1:]...) p.Stdin = bytes.NewReader(stdin) var bout, berr bytes.Buffer @@ -30,6 +68,15 @@ func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) { return } +func find(argv []string, target string) int { + for i, arg := range argv { + if arg == target { + return i + } + } + return -1 +} + func lineno(pos token.Pos) string { return fset.Position(pos).String() } From fe5eac63c4b8d8f9d541d40f9055c3e4d4454d67 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 4 Feb 2016 14:16:58 -0500 Subject: [PATCH 046/117] cmd/internal/obj: hoist fieldtrack code out of x86 back end Change-Id: I38e59088c37426d914ce2b4dfc79f3d476e06f49 Reviewed-on: https://go-review.googlesource.com/19617 Reviewed-by: David Crawshaw Reviewed-by: Ian Lance Taylor --- src/cmd/internal/obj/obj.go | 18 ++++++++++++++++++ src/cmd/internal/obj/objfile.go | 1 + src/cmd/internal/obj/x86/asm6.go | 9 --------- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/cmd/internal/obj/obj.go b/src/cmd/internal/obj/obj.go index 30ab54912e..343c93a6ee 100644 --- a/src/cmd/internal/obj/obj.go +++ b/src/cmd/internal/obj/obj.go @@ -281,3 +281,21 @@ func linkgetline(ctxt *Link, lineno int32, f **LSym, l *int32) { func Linkprfile(ctxt *Link, line int) { fmt.Printf("%s ", ctxt.LineHist.LineString(line)) } + +func fieldtrack(ctxt *Link, cursym *LSym) { + p := cursym.Text + if p == nil || p.Link == nil { // handle external functions and ELF section symbols + return + } + ctxt.Cursym = cursym + + for ; p != nil; p = p.Link { + if p.As == AUSEFIELD { + r := Addrel(ctxt.Cursym) + r.Off = 0 + r.Siz = 0 + r.Sym = p.From.Sym + r.Type = R_USEFIELD + } + } +} diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go index 8d4a506843..bae64f4a29 100644 --- a/src/cmd/internal/obj/objfile.go +++ b/src/cmd/internal/obj/objfile.go @@ -298,6 +298,7 @@ func Flushplist(ctxt *Link) { ctxt.Arch.Follow(ctxt, s) ctxt.Arch.Preprocess(ctxt, s) ctxt.Arch.Assemble(ctxt, s) + fieldtrack(ctxt, s) linkpcln(ctxt, s) } diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go index 2b71822799..115350637f 100644 --- a/src/cmd/internal/obj/x86/asm6.go +++ b/src/cmd/internal/obj/x86/asm6.go @@ -4556,15 +4556,6 @@ func asmins(ctxt *obj.Link, p *obj.Prog) { ctxt.Andptr = ctxt.And[:] ctxt.Asmode = int(p.Mode) - if p.As == obj.AUSEFIELD { - r := obj.Addrel(ctxt.Cursym) - r.Off = 0 - r.Siz = 0 - r.Sym = p.From.Sym - r.Type = obj.R_USEFIELD - return - } - if ctxt.Headtype == obj.Hnacl && p.Mode == 32 { switch p.As { case obj.ARET: From 9aa630faa868fde13af74e5b22ddba89a635d837 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 8 Feb 2016 07:08:14 -0500 Subject: [PATCH 047/117] cmd/dist: accept "//+build" with no spaces, like go/build The go/build parser accepts "//+build", with no spaces. Make the cmd/dist bootstrap parser do the same. While in theory we should always use the space form, I copied some code that did not into the standard tree, and I was very confused that 'go test' had had no problem but then make.bash died. (As a reminder, cmd/dist does not use go/build because cmd/dist must build against earlier versions of Go.) Change-Id: I90a18014bd878247b8811487e5c1a7589260cbfc Reviewed-on: https://go-review.googlesource.com/19618 Reviewed-by: Ian Lance Taylor --- src/cmd/dist/build.go | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go index 39a88ccab5..7f2f75341f 100644 --- a/src/cmd/dist/build.go +++ b/src/cmd/dist/build.go @@ -754,7 +754,7 @@ func matchtag(tag string) bool { } return !matchtag(tag[1:]) } - return tag == goos || tag == goarch || tag == "cmd_go_bootstrap" || tag == "go1.1" || (goos == "android" && tag == "linux") + return tag == "gc" || tag == goos || tag == goarch || tag == "cmd_go_bootstrap" || tag == "go1.1" || (goos == "android" && tag == "linux") } // shouldbuild reports whether we should build this file. @@ -798,10 +798,15 @@ func shouldbuild(file, dir string) bool { if p == "" { continue } - if strings.Contains(p, "package documentation") { + code := p + i := strings.Index(code, "//") + if i > 0 { + code = strings.TrimSpace(code[:i]) + } + if code == "package documentation" { return false } - if strings.Contains(p, "package main") && dir != "cmd/go" && dir != "cmd/cgo" { + if code == "package main" && dir != "cmd/go" && dir != "cmd/cgo" { return false } if !strings.HasPrefix(p, "//") { @@ -810,11 +815,11 @@ func shouldbuild(file, dir string) bool { if !strings.Contains(p, "+build") { continue } - fields := splitfields(p) - if len(fields) < 2 || fields[1] != "+build" { + fields := splitfields(p[2:]) + if len(fields) < 1 || fields[0] != "+build" { continue } - for _, p := range fields[2:] { + for _, p := range fields[1:] { if matchfield(p) { goto fieldmatch } From 277024bd6f3ecc9f34729cbeb95e226f70004733 Mon Sep 17 00:00:00 2001 From: Mohit Agarwal Date: Fri, 19 Feb 2016 19:35:46 +0530 Subject: [PATCH 048/117] cmd/go: don't set GO15VENDOREXPERIMENT in TestSymlinksVendor Change-Id: I14947b64bdafd975bf3915eceb07f98897304a85 Reviewed-on: https://go-review.googlesource.com/19708 Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot --- src/cmd/go/go_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index 7d38915176..ae426088ea 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -1726,7 +1726,6 @@ func TestSymlinksVendor(t *testing.T) { tg := testgo(t) defer tg.cleanup() - tg.setenv("GO15VENDOREXPERIMENT", "1") tg.tempDir("gopath/src/dir1/vendor/v") tg.tempFile("gopath/src/dir1/p.go", "package main\nimport _ `v`\nfunc main(){}") tg.tempFile("gopath/src/dir1/vendor/v/v.go", "package v") From c8e7b34b599c9e3c6747b3e8182e65a2145fd06f Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 18 Feb 2016 11:04:05 -0800 Subject: [PATCH 049/117] runtime: skip cgo check for non-pointer slice elements Fixes #14387. Change-Id: Icc98be80f549c5e1f55c5e693bfea97b456a6c41 Reviewed-on: https://go-review.googlesource.com/19621 Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/runtime/cgocall.go | 3 +++ src/runtime/crash_cgo_test.go | 31 +++++++++++++++++++++++++ src/runtime/testdata/testprogcgo/cgo.go | 10 ++++++++ 3 files changed, 44 insertions(+) diff --git a/src/runtime/cgocall.go b/src/runtime/cgocall.go index 66115fd8b4..fef8add46f 100644 --- a/src/runtime/cgocall.go +++ b/src/runtime/cgocall.go @@ -463,6 +463,9 @@ func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool, msg string) { if !top { panic(errorString(msg)) } + if st.elem.kind&kindNoPointers != 0 { + return + } for i := 0; i < s.cap; i++ { cgoCheckArg(st.elem, p, true, false, msg) p = add(p, st.elem.size) diff --git a/src/runtime/crash_cgo_test.go b/src/runtime/crash_cgo_test.go index d7b367f941..7685582aa8 100644 --- a/src/runtime/crash_cgo_test.go +++ b/src/runtime/crash_cgo_test.go @@ -7,10 +7,12 @@ package runtime_test import ( + "internal/testenv" "os/exec" "runtime" "strings" "testing" + "time" ) func TestCgoCrashHandler(t *testing.T) { @@ -147,3 +149,32 @@ func TestEnsureDropM(t *testing.T) { t.Errorf("expected %q, got %v", want, got) } } + +// Test for issue 14387. +// Test that the program that doesn't need any cgo pointer checking +// takes about the same amount of time with it as without it. +func TestCgoCheckBytes(t *testing.T) { + // Make sure we don't count the build time as part of the run time. + testenv.MustHaveGoBuild(t) + exe, err := buildTestProg(t, "testprogcgo") + if err != nil { + t.Fatal(err) + } + + cmd := testEnv(exec.Command(exe, "CgoCheckBytes")) + + start := time.Now() + cmd.Run() + d1 := time.Since(start) + + cmd = testEnv(exec.Command(exe, "CgoCheckBytes")) + cmd.Env = append(cmd.Env, "GODEBUG=cgocheck=0") + + start = time.Now() + cmd.Run() + d2 := time.Since(start) + + if d2*10 < d1 { + t.Errorf("cgo check too slow: got %v, expected at most %v", d1, d2*10) + } +} diff --git a/src/runtime/testdata/testprogcgo/cgo.go b/src/runtime/testdata/testprogcgo/cgo.go index cf1af8268c..5d2550dbb0 100644 --- a/src/runtime/testdata/testprogcgo/cgo.go +++ b/src/runtime/testdata/testprogcgo/cgo.go @@ -6,17 +6,20 @@ package main /* void foo1(void) {} +void foo2(void* p) {} */ import "C" import ( "fmt" "runtime" "time" + "unsafe" ) func init() { register("CgoSignalDeadlock", CgoSignalDeadlock) register("CgoTraceback", CgoTraceback) + register("CgoCheckBytes", CgoCheckBytes) } func CgoSignalDeadlock() { @@ -78,3 +81,10 @@ func CgoTraceback() { runtime.Stack(buf, true) fmt.Printf("OK\n") } + +func CgoCheckBytes() { + b := make([]byte, 1e6) + for i := 0; i < 1e3; i++ { + C.foo2(unsafe.Pointer(&b[0])) + } +} From 5c5e8d41054940ccf9e1c025bf21c86e85f33bde Mon Sep 17 00:00:00 2001 From: Tal Shprecher Date: Sat, 13 Feb 2016 22:39:16 -0800 Subject: [PATCH 050/117] cmd/compile: avoid leak of dottype expression if type does not contain pointers. Fixes #13805 Change-Id: Ica9aae2e054b74f67d28ab27f72c52a3f03eeb59 Reviewed-on: https://go-review.googlesource.com/19489 Run-TryBot: Michael Matloob TryBot-Result: Gobot Gobot Reviewed-by: David Chase --- src/cmd/compile/internal/gc/esc.go | 15 ++++++++++----- src/cmd/compile/internal/gc/typecheck.go | 1 - test/escape_iface.go | 20 ++++++++++++++++++++ 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go index ff983e717e..ccdb781040 100644 --- a/src/cmd/compile/internal/gc/esc.go +++ b/src/cmd/compile/internal/gc/esc.go @@ -962,7 +962,7 @@ func escassign(e *EscState, dst *Node, src *Node) { dst = &e.theSink } - case ODOT: // treat "dst.x = src" as "dst = src" + case ODOT: // treat "dst.x = src" as "dst = src" escassign(e, dst.Left, src) return @@ -1042,7 +1042,6 @@ func escassign(e *EscState, dst *Node, src *Node) { ODOTMETH, // treat recv.meth as a value with recv in it, only happens in ODEFER and OPROC // iface.method already leaks iface in esccall, no need to put in extra ODOTINTER edge here - ODOTTYPE, ODOTTYPE2, OSLICE, OSLICE3, @@ -1052,6 +1051,12 @@ func escassign(e *EscState, dst *Node, src *Node) { // Conversions, field access, slice all preserve the input value. escassign(e, dst, src.Left) + case ODOTTYPE: + if src.Type != nil && !haspointers(src.Type) { + break + } + escassign(e, dst, src.Left) + case OAPPEND: // Append returns first argument. // Subsequent arguments are already leaked because they are operands to append. @@ -1549,9 +1554,9 @@ func escflows(e *EscState, dst *Node, src *Node) { // finding an OADDR just means we're following the upstream of a dereference, // so this address doesn't leak (yet). // If level == 0, it means the /value/ of this node can reach the root of this flood. -// so if this node is an OADDR, it's argument should be marked as escaping iff -// it's currfn/e->loopdepth are different from the flood's root. -// Once an object has been moved to the heap, all of it's upstream should be considered +// so if this node is an OADDR, its argument should be marked as escaping iff +// its currfn/e->loopdepth are different from the flood's root. +// Once an object has been moved to the heap, all of its upstream should be considered // escaping to the global scope. func escflood(e *EscState, dst *Node) { switch dst.Op { diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index f74bb334aa..8fd6f85575 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -936,7 +936,6 @@ OpSwitch: n.Type = n.Right.Type n.Right = nil if n.Type == nil { - n.Type = nil return } } diff --git a/test/escape_iface.go b/test/escape_iface.go index 2b1144ad2c..9149fa1770 100644 --- a/test/escape_iface.go +++ b/test/escape_iface.go @@ -225,3 +225,23 @@ func dotTypeEscape() *T2 { // #11931 T1: *(x.(*T1)), // ERROR "&T2 literal escapes to heap" } } + +func dotTypeEscape2() { // #13805 + { + i := 0 + var v int + var x interface{} = i // ERROR "i does not escape" + *(&v) = x.(int) // ERROR "&v does not escape" + } + { + i := 0 + var x interface{} = i // ERROR "i does not escape" + sink = x.(int) // ERROR "x.\(int\) escapes to heap" + + } + { + i := 0 // ERROR "moved to heap: i" + var x interface{} = &i // ERROR "&i escapes to heap" + sink = x.(*int) // ERROR "x.\(\*int\) escapes to heap" + } +} From 9a184b22eef79ac0570330a17cf81a15a58bbf76 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 18 Feb 2016 16:44:06 -0800 Subject: [PATCH 051/117] cmd/compile: refresh builtin.go The export data format was augmented with a new "unsafe-uintptr" tag in https://golang.org/cl/18584, but builtin.go was not regenerated. While here, add a test to make sure builtin.go stays up to date in the future. Change-Id: I4ae17da29f0855bef6ec0fcc10e7082c8427d39c Reviewed-on: https://go-review.googlesource.com/19681 Run-TryBot: Matthew Dempsky TryBot-Result: Gobot Gobot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/gc/builtin.go | 72 ++++++++++----------- src/cmd/compile/internal/gc/builtin_test.go | 31 +++++++++ src/cmd/compile/internal/gc/mkbuiltin.go | 13 +++- 3 files changed, 79 insertions(+), 37 deletions(-) create mode 100644 src/cmd/compile/internal/gc/builtin_test.go diff --git a/src/cmd/compile/internal/gc/builtin.go b/src/cmd/compile/internal/gc/builtin.go index 1e1f85a4a1..7583e8fa13 100644 --- a/src/cmd/compile/internal/gc/builtin.go +++ b/src/cmd/compile/internal/gc/builtin.go @@ -44,7 +44,7 @@ const runtimeimport = "" + "func @\"\".stringtoslicerune (? *[32]rune, ? string) (? []rune)\n" + "func @\"\".stringiter (? string, ? int) (? int)\n" + "func @\"\".stringiter2 (? string, ? int) (@\"\".retk·1 int, @\"\".retv·2 rune)\n" + - "func @\"\".slicecopy (@\"\".to·2 any, @\"\".fr·3 any, @\"\".wid·4 uintptr) (? int)\n" + + "func @\"\".slicecopy (@\"\".to·2 any, @\"\".fr·3 any, @\"\".wid·4 uintptr \"unsafe-uintptr\") (? int)\n" + "func @\"\".slicestringcopy (@\"\".to·2 any, @\"\".fr·3 any) (? int)\n" + "func @\"\".typ2Itab (@\"\".typ·2 *byte, @\"\".typ2·3 *byte, @\"\".cache·4 **byte) (@\"\".ret·1 *byte)\n" + "func @\"\".convI2E (@\"\".elem·2 any) (@\"\".ret·1 any)\n" + @@ -91,31 +91,31 @@ const runtimeimport = "" + "func @\"\".writebarrierstring (@\"\".dst·1 *any, @\"\".src·2 any)\n" + "func @\"\".writebarrierslice (@\"\".dst·1 *any, @\"\".src·2 any)\n" + "func @\"\".writebarrieriface (@\"\".dst·1 *any, @\"\".src·2 any)\n" + - "func @\"\".writebarrierfat01 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" + - "func @\"\".writebarrierfat10 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" + - "func @\"\".writebarrierfat11 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" + - "func @\"\".writebarrierfat001 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" + - "func @\"\".writebarrierfat010 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" + - "func @\"\".writebarrierfat011 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" + - "func @\"\".writebarrierfat100 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" + - "func @\"\".writebarrierfat101 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" + - "func @\"\".writebarrierfat110 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" + - "func @\"\".writebarrierfat111 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" + - "func @\"\".writebarrierfat0001 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" + - "func @\"\".writebarrierfat0010 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" + - "func @\"\".writebarrierfat0011 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" + - "func @\"\".writebarrierfat0100 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" + - "func @\"\".writebarrierfat0101 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" + - "func @\"\".writebarrierfat0110 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" + - "func @\"\".writebarrierfat0111 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" + - "func @\"\".writebarrierfat1000 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" + - "func @\"\".writebarrierfat1001 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" + - "func @\"\".writebarrierfat1010 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" + - "func @\"\".writebarrierfat1011 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" + - "func @\"\".writebarrierfat1100 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" + - "func @\"\".writebarrierfat1101 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" + - "func @\"\".writebarrierfat1110 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" + - "func @\"\".writebarrierfat1111 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" + + "func @\"\".writebarrierfat01 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" + + "func @\"\".writebarrierfat10 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" + + "func @\"\".writebarrierfat11 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" + + "func @\"\".writebarrierfat001 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" + + "func @\"\".writebarrierfat010 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" + + "func @\"\".writebarrierfat011 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" + + "func @\"\".writebarrierfat100 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" + + "func @\"\".writebarrierfat101 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" + + "func @\"\".writebarrierfat110 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" + + "func @\"\".writebarrierfat111 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" + + "func @\"\".writebarrierfat0001 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" + + "func @\"\".writebarrierfat0010 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" + + "func @\"\".writebarrierfat0011 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" + + "func @\"\".writebarrierfat0100 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" + + "func @\"\".writebarrierfat0101 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" + + "func @\"\".writebarrierfat0110 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" + + "func @\"\".writebarrierfat0111 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" + + "func @\"\".writebarrierfat1000 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" + + "func @\"\".writebarrierfat1001 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" + + "func @\"\".writebarrierfat1010 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" + + "func @\"\".writebarrierfat1011 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" + + "func @\"\".writebarrierfat1100 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" + + "func @\"\".writebarrierfat1101 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" + + "func @\"\".writebarrierfat1110 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" + + "func @\"\".writebarrierfat1111 (@\"\".dst·1 *any, _ uintptr \"unsafe-uintptr\", @\"\".src·3 any)\n" + "func @\"\".typedmemmove (@\"\".typ·1 *byte, @\"\".dst·2 *any, @\"\".src·3 *any)\n" + "func @\"\".typedslicecopy (@\"\".typ·2 *byte, @\"\".dst·3 any, @\"\".src·4 any) (? int)\n" + "func @\"\".selectnbsend (@\"\".chanType·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 *any) (? bool)\n" + @@ -131,9 +131,9 @@ const runtimeimport = "" + "func @\"\".makeslice (@\"\".typ·2 *byte, @\"\".nel·3 int64, @\"\".cap·4 int64) (@\"\".ary·1 []any)\n" + "func @\"\".growslice (@\"\".typ·2 *byte, @\"\".old·3 []any, @\"\".cap·4 int) (@\"\".ary·1 []any)\n" + "func @\"\".growslice_n (@\"\".typ·2 *byte, @\"\".old·3 []any, @\"\".n·4 int) (@\"\".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 @\"\".memmove (@\"\".to·1 *any, @\"\".frm·2 *any, @\"\".length·3 uintptr \"unsafe-uintptr\")\n" + + "func @\"\".memclr (@\"\".ptr·1 *byte, @\"\".length·2 uintptr \"unsafe-uintptr\")\n" + + "func @\"\".memequal (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr \"unsafe-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" + @@ -148,14 +148,14 @@ const runtimeimport = "" + "func @\"\".int64tofloat64 (? int64) (? float64)\n" + "func @\"\".uint64tofloat64 (? uint64) (? float64)\n" + "func @\"\".complex128div (@\"\".num·2 complex128, @\"\".den·3 complex128) (@\"\".quo·1 complex128)\n" + - "func @\"\".racefuncenter (? uintptr)\n" + + "func @\"\".racefuncenter (? uintptr \"unsafe-uintptr\")\n" + "func @\"\".racefuncexit ()\n" + - "func @\"\".raceread (? uintptr)\n" + - "func @\"\".racewrite (? uintptr)\n" + - "func @\"\".racereadrange (@\"\".addr·1 uintptr, @\"\".size·2 uintptr)\n" + - "func @\"\".racewriterange (@\"\".addr·1 uintptr, @\"\".size·2 uintptr)\n" + - "func @\"\".msanread (@\"\".addr·1 uintptr, @\"\".size·2 uintptr)\n" + - "func @\"\".msanwrite (@\"\".addr·1 uintptr, @\"\".size·2 uintptr)\n" + + "func @\"\".raceread (? uintptr \"unsafe-uintptr\")\n" + + "func @\"\".racewrite (? uintptr \"unsafe-uintptr\")\n" + + "func @\"\".racereadrange (@\"\".addr·1 uintptr \"unsafe-uintptr\", @\"\".size·2 uintptr \"unsafe-uintptr\")\n" + + "func @\"\".racewriterange (@\"\".addr·1 uintptr \"unsafe-uintptr\", @\"\".size·2 uintptr \"unsafe-uintptr\")\n" + + "func @\"\".msanread (@\"\".addr·1 uintptr \"unsafe-uintptr\", @\"\".size·2 uintptr \"unsafe-uintptr\")\n" + + "func @\"\".msanwrite (@\"\".addr·1 uintptr \"unsafe-uintptr\", @\"\".size·2 uintptr \"unsafe-uintptr\")\n" + "\n" + "$$\n" diff --git a/src/cmd/compile/internal/gc/builtin_test.go b/src/cmd/compile/internal/gc/builtin_test.go new file mode 100644 index 0000000000..94111e640d --- /dev/null +++ b/src/cmd/compile/internal/gc/builtin_test.go @@ -0,0 +1,31 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package gc_test + +import ( + "bytes" + "internal/testenv" + "io/ioutil" + "os/exec" + "testing" +) + +func TestBuiltin(t *testing.T) { + testenv.MustHaveGoRun(t) + + old, err := ioutil.ReadFile("builtin.go") + if err != nil { + t.Fatal(err) + } + + new, err := exec.Command("go", "run", "mkbuiltin.go", "-stdout").Output() + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(old, new) { + t.Fatal("builtin.go out of date; run mkbuiltin.go") + } +} diff --git a/src/cmd/compile/internal/gc/mkbuiltin.go b/src/cmd/compile/internal/gc/mkbuiltin.go index 1b6cc4ae38..13cde5e8aa 100644 --- a/src/cmd/compile/internal/gc/mkbuiltin.go +++ b/src/cmd/compile/internal/gc/mkbuiltin.go @@ -12,6 +12,7 @@ package main import ( "bytes" + "flag" "fmt" "io" "io/ioutil" @@ -20,7 +21,11 @@ import ( "os/exec" ) +var stdout = flag.Bool("stdout", false, "write to stdout instead of builtin.go") + func main() { + flag.Parse() + var b bytes.Buffer fmt.Fprintln(&b, "// AUTO-GENERATED by mkbuiltin.go; DO NOT EDIT") fmt.Fprintln(&b, "") @@ -29,7 +34,13 @@ func main() { mkbuiltin(&b, "runtime") mkbuiltin(&b, "unsafe") - if err := ioutil.WriteFile("builtin.go", b.Bytes(), 0666); err != nil { + var err error + if *stdout { + _, err = os.Stdout.Write(b.Bytes()) + } else { + err = ioutil.WriteFile("builtin.go", b.Bytes(), 0666) + } + if err != nil { log.Fatal(err) } } From 0e34737c9aea6680b0a2a135cdf80557d61b83ce Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Fri, 19 Feb 2016 09:58:22 -0800 Subject: [PATCH 052/117] cmd/go: don't assume cc supports -gno-record-gcc-switches NetBSD's C compiler appears to support -fdebug-prefix-map but not -gno-record-gcc-switches. Remove assumption that support for the former implies the latter. Change-Id: Iecad9e4f497ea4edc1ce440010e6fe19dc3e0566 Reviewed-on: https://go-review.googlesource.com/19686 Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot --- src/cmd/go/build.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go index 1932f324ea..e65aee4a27 100644 --- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -2930,12 +2930,15 @@ func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string { // Tell gcc not to include the work directory in object files. if b.gccSupportsFlag("-fdebug-prefix-map=a=b") { - // -gno-record-gcc-switches is supported by all gcc/clang - // versions that support -fdebug-prefix-map. - a = append(a, "-gno-record-gcc-switches") a = append(a, "-fdebug-prefix-map="+b.work+"=/tmp/go-build") } + // Tell gcc not to include flags in object files, which defeats the + // point of -fdebug-prefix-map above. + if b.gccSupportsFlag("-gno-record-gcc-switches") { + a = append(a, "-gno-record-gcc-switches") + } + // On OS X, some of the compilers behave as if -fno-common // is always set, and the Mach-O linker in 6l/8l assumes this. // See https://golang.org/issue/3253. From fb2af2b35b8d2ad832f2398e981ea78c64b0663b Mon Sep 17 00:00:00 2001 From: David Chase Date: Fri, 19 Feb 2016 12:06:31 -0500 Subject: [PATCH 053/117] cmd/compile: don't walk field-name syntax in esc.go Walking the field name as if it were an expression caused a called to haspointers with a TFIELD, which panics. Trigger was a field at a large offset within a large struct, combined with a struct literal expression mentioning that field. Fixes #14405 Change-Id: I4589badae27cf3d7cf365f3a66c13447512f41f9 Reviewed-on: https://go-review.googlesource.com/19699 Reviewed-by: Russ Cox Run-TryBot: David Chase TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/gc/esc.go | 13 ++++++++++--- src/cmd/compile/internal/gc/fmt.go | 2 +- test/fixedbugs/issue14405.go | 17 +++++++++++++++++ 3 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 test/fixedbugs/issue14405.go diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go index ccdb781040..1a5a433eeb 100644 --- a/src/cmd/compile/internal/gc/esc.go +++ b/src/cmd/compile/internal/gc/esc.go @@ -576,6 +576,12 @@ func esc(e *EscState, n *Node, up *Node) { if n == nil { return } + if n.Type != nil && n.Type.Etype == TFIELD { + // This is the left side of x:y in a struct literal. + // x is syntax, not an expression. + // See #14405. + return + } lno := int(setlineno(n)) @@ -602,9 +608,10 @@ func esc(e *EscState, n *Node, up *Node) { // Big stuff escapes unconditionally // "Big" conditions that were scattered around in walk have been gathered here - if n.Esc != EscHeap && n.Type != nil && (n.Type.Width > MaxStackVarSize || - n.Op == ONEW && n.Type.Type.Width >= 1<<16 || - n.Op == OMAKESLICE && !isSmallMakeSlice(n)) { + if n.Esc != EscHeap && n.Type != nil && + (n.Type.Width > MaxStackVarSize || + n.Op == ONEW && n.Type.Type.Width >= 1<<16 || + n.Op == OMAKESLICE && !isSmallMakeSlice(n)) { if Debug['m'] > 1 { Warnl(int(n.Lineno), "%v is too large for stack", n) } diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go index d00e5a6c46..c0a1170839 100644 --- a/src/cmd/compile/internal/gc/fmt.go +++ b/src/cmd/compile/internal/gc/fmt.go @@ -1542,7 +1542,7 @@ func nodedump(n *Node, flag int) string { } else { fmt.Fprintf(&buf, "%v%v", Oconv(int(n.Op), 0), Jconv(n, 0)) } - if recur && n.Type == nil && n.Name.Param.Ntype != nil { + if recur && n.Type == nil && n.Name != nil && n.Name.Param != nil && n.Name.Param.Ntype != nil { indent(&buf) fmt.Fprintf(&buf, "%v-ntype%v", Oconv(int(n.Op), 0), n.Name.Param.Ntype) } diff --git a/test/fixedbugs/issue14405.go b/test/fixedbugs/issue14405.go new file mode 100644 index 0000000000..c2a89464ea --- /dev/null +++ b/test/fixedbugs/issue14405.go @@ -0,0 +1,17 @@ +// compile + +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Mention of field with large offset in struct literal causes crash +package p + +type T struct { + Slice [1 << 20][]int + Ptr *int +} + +func New(p *int) *T { + return &T{Ptr: p} +} From 1402e522c6e372d055748d8437bd2a127acacdca Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 1 Dec 2015 12:02:42 -0800 Subject: [PATCH 054/117] cmd/compile: load builtin export data only once Previously, the builtin runtime export data was reparsed before every Go source file, and the unsafe export data was reparsed for every import of package unsafe. Now, we parse both of them just once ahead of time. This does mean package unsafe's export data will be loaded even when compiling packages that don't import it, but it's tiny anyway. Change-Id: Ic6931bc58f6d62f664348bfa932f92d4ccacc3ef Reviewed-on: https://go-review.googlesource.com/19626 TryBot-Result: Gobot Gobot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/gc/lex.go | 30 +++++++++++++++++++++++++-- src/cmd/compile/internal/gc/parser.go | 23 -------------------- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go index a2a8be1610..8161cad568 100644 --- a/src/cmd/compile/internal/gc/lex.go +++ b/src/cmd/compile/internal/gc/lex.go @@ -311,6 +311,8 @@ func Main() { lexlineno = 1 const BOM = 0xFEFF + loadsys() + for _, infile = range flag.Args() { if trace && Debug['x'] != 0 { fmt.Printf("--- %s ---\n", infile) @@ -656,6 +658,30 @@ func findpkg(name string) (file string, ok bool) { return "", false } +// loadsys loads the definitions for the low-level runtime and unsafe functions, +// so that the compiler can generate calls to them, +// but does not make the names "runtime" or "unsafe" visible as packages. +func loadsys() { + if Debug['A'] != 0 { + return + } + + block = 1 + iota_ = -1000000 + + importpkg = Runtimepkg + cannedimports("runtime.Builtin", runtimeimport) + thenewparser.import_package() + thenewparser.import_there() + + importpkg = unsafepkg + cannedimports("unsafe.o", unsafeimport) + thenewparser.import_package() + thenewparser.import_there() + + importpkg = nil +} + func fakeimport() { importpkg = mkpkg("fake") cannedimports("fake.o", "$$\n") @@ -706,8 +732,8 @@ func importfile(f *Val, line int) { errorexit() } - importpkg = mkpkg(f.U.(string)) - cannedimports("unsafe.o", unsafeimport) + importpkg = unsafepkg + cannedimports("unsafe.o", "package unsafe\n\n$$\n\n") imported_unsafe = true return } diff --git a/src/cmd/compile/internal/gc/parser.go b/src/cmd/compile/internal/gc/parser.go index dc6ae72d5f..7e521d1f7d 100644 --- a/src/cmd/compile/internal/gc/parser.go +++ b/src/cmd/compile/internal/gc/parser.go @@ -51,33 +51,10 @@ func pop_parser() { // parse_file sets up a new parser and parses a single Go source file. func parse_file() { thenewparser = parser{} - thenewparser.loadsys() thenewparser.next() thenewparser.file() } -// loadsys loads the definitions for the low-level runtime functions, -// so that the compiler can generate calls to them, -// but does not make the name "runtime" visible as a package. -func (p *parser) loadsys() { - if trace && Debug['x'] != 0 { - defer p.trace("loadsys")() - } - - importpkg = Runtimepkg - - if Debug['A'] != 0 { - cannedimports("runtime.Builtin", "package runtime safe\n\n$$\n\n") - } else { - cannedimports("runtime.Builtin", runtimeimport) - } - - p.import_package() - p.import_there() - - importpkg = nil -} - type parser struct { tok int32 // next token (one-token look-ahead) op Op // valid if tok == LASOP From d930d69fd95e410107e84231f57ff629d1ef7f21 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 1 Dec 2015 12:05:30 -0800 Subject: [PATCH 055/117] cmd/compile: make -A and -newexport compatible Packages compiled with -A may reference the builtin "any" type, so it needs to be included in the list of predeclared types for binary import/export. Also, when -A is used, mark all symbols as SymExport instead of SymPackage in importsym. This parallels the logic in autoexport and is necessary to prevent a "export/package mismatch" errors in exportsym during dumpexport's verifyExport pass. Change-Id: Iff5ec5fbfe2219525ec9d1a975307fa8936af9b9 Reviewed-on: https://go-review.googlesource.com/19627 Reviewed-by: Robert Griesemer Run-TryBot: Matthew Dempsky TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/gc/bexport.go | 3 +++ src/cmd/compile/internal/gc/export.go | 2 +- src/go/internal/gcimporter/bimport.go | 4 ++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go index 3edd0488e7..ff0465f64c 100644 --- a/src/cmd/compile/internal/gc/bexport.go +++ b/src/cmd/compile/internal/gc/bexport.go @@ -1035,6 +1035,9 @@ func predeclared() []*Type { // package unsafe Types[TUNSAFEPTR], + + // any type, for builtin export data + Types[TANY], } } return predecl diff --git a/src/cmd/compile/internal/gc/export.go b/src/cmd/compile/internal/gc/export.go index e50cf383d7..1b61d7f228 100644 --- a/src/cmd/compile/internal/gc/export.go +++ b/src/cmd/compile/internal/gc/export.go @@ -442,7 +442,7 @@ func importsym(s *Sym, op Op) *Sym { // mark the symbol so it is not reexported if s.Def == nil { - if exportname(s.Name) || initname(s.Name) { + if Debug['A'] != 0 || exportname(s.Name) || initname(s.Name) { s.Flags |= SymExport } else { s.Flags |= SymPackage // package scope diff --git a/src/go/internal/gcimporter/bimport.go b/src/go/internal/gcimporter/bimport.go index 68690424a1..ad1c4cd02a 100644 --- a/src/go/internal/gcimporter/bimport.go +++ b/src/go/internal/gcimporter/bimport.go @@ -678,4 +678,8 @@ var predeclared = []types.Type{ // package unsafe types.Typ[types.UnsafePointer], + + // any type, for builtin export data + // TODO(mdempsky): Provide an actual Type value to represent "any"? + types.Typ[types.Invalid], } From 113c4d25818e67599d3ff647480e4e68d6857f82 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 1 Dec 2015 12:15:25 -0800 Subject: [PATCH 056/117] cmd/compile: refactor import statement parsing Combine parser's import_stmt and import_here methods as a single new importdcl method, and cleanup conditional logic slightly to make the code easier to follow. Also, eliminate importfile's unused line parameter, and get rid of all of its duplicate type assertions. Change-Id: Ic37ae8490afedc533f98ead9feef383e3599bc01 Reviewed-on: https://go-review.googlesource.com/19629 Reviewed-by: Robert Griesemer Run-TryBot: Matthew Dempsky TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/gc/go.go | 2 - src/cmd/compile/internal/gc/lex.go | 24 +++-- src/cmd/compile/internal/gc/parser.go | 134 ++++++++++++-------------- 3 files changed, 70 insertions(+), 90 deletions(-) diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go index 8053aaffe9..ebc6a5171b 100644 --- a/src/cmd/compile/internal/gc/go.go +++ b/src/cmd/compile/internal/gc/go.go @@ -492,8 +492,6 @@ var debugstr string var Debug_checknil int var Debug_typeassert int -var importmyname *Sym // my name for package - var localpkg *Pkg // package being compiled var importpkg *Pkg // package being imported diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go index 8161cad568..83f25a5e2a 100644 --- a/src/cmd/compile/internal/gc/lex.go +++ b/src/cmd/compile/internal/gc/lex.go @@ -687,21 +687,21 @@ func fakeimport() { cannedimports("fake.o", "$$\n") } -// TODO(gri) line argument doesn't appear to be used -func importfile(f *Val, line int) { - if _, ok := f.U.(string); !ok { +func importfile(f *Val) { + path_, ok := f.U.(string) + if !ok { Yyerror("import statement not a string") fakeimport() return } - if len(f.U.(string)) == 0 { + if len(path_) == 0 { Yyerror("import path is empty") fakeimport() return } - if isbadimport(f.U.(string)) { + if isbadimport(path_) { fakeimport() return } @@ -710,18 +710,16 @@ func importfile(f *Val, line int) { // but we reserve the import path "main" to identify // the main package, just as we reserve the import // path "math" to identify the standard math package. - if f.U.(string) == "main" { + if path_ == "main" { Yyerror("cannot import \"main\"") errorexit() } - if myimportpath != "" && f.U.(string) == myimportpath { - Yyerror("import %q while compiling that package (import cycle)", f.U.(string)) + if myimportpath != "" && path_ == myimportpath { + Yyerror("import %q while compiling that package (import cycle)", path_) errorexit() } - path_ := f.U.(string) - if mapped, ok := importMap[path_]; ok { path_ = mapped } @@ -763,7 +761,7 @@ func importfile(f *Val, line int) { file, found := findpkg(path_) if !found { - Yyerror("can't find import: %q", f.U.(string)) + Yyerror("can't find import: %q", path_) errorexit() } @@ -788,7 +786,7 @@ func importfile(f *Val, line int) { var imp *obj.Biobuf imp, err = obj.Bopenr(file) if err != nil { - Yyerror("can't open import: %q: %v", f.U.(string), err) + Yyerror("can't open import: %q: %v", path_, err) errorexit() } @@ -878,7 +876,7 @@ func importfile(f *Val, line int) { incannedimport = 0 default: - Yyerror("no import in %q", f.U.(string)) + Yyerror("no import in %q", path_) } } diff --git a/src/cmd/compile/internal/gc/parser.go b/src/cmd/compile/internal/gc/parser.go index 7e521d1f7d..6081383918 100644 --- a/src/cmd/compile/internal/gc/parser.go +++ b/src/cmd/compile/internal/gc/parser.go @@ -323,108 +323,92 @@ func (p *parser) import_() { p.want(LIMPORT) if p.got('(') { for p.tok != EOF && p.tok != ')' { - p.import_stmt() + p.importdcl() if !p.osemi(')') { break } } p.want(')') } else { - p.import_stmt() - } -} - -func (p *parser) import_stmt() { - if trace && Debug['x'] != 0 { - defer p.trace("import_stmt")() - } - - line := int32(p.import_here()) - if p.tok == LPACKAGE { - p.import_package() - p.import_there() - - ipkg := importpkg - my := importmyname - importpkg = nil - importmyname = nil - - if my == nil { - my = Lookup(ipkg.Name) - } - - pack := Nod(OPACK, nil, nil) - pack.Sym = my - pack.Name.Pkg = ipkg - pack.Lineno = line - - if strings.HasPrefix(my.Name, ".") { - importdot(ipkg, pack) - return - } - if my.Name == "init" { - lineno = line - Yyerror("cannot import package as init - init must be a func") - return - } - if my.Name == "_" { - return - } - if my.Def != nil { - lineno = line - redeclare(my, "as imported package name") - } - my.Def = pack - my.Lastlineno = line - my.Block = 1 // at top level - - return - } - - p.import_there() - // When an invalid import path is passed to importfile, - // it calls Yyerror and then sets up a fake import with - // no package statement. This allows us to test more - // than one invalid import statement in a single file. - if nerrors == 0 { - Fatalf("phase error in import") + p.importdcl() } } // ImportSpec = [ "." | PackageName ] ImportPath . // ImportPath = string_lit . -// -// import_here switches the underlying lexed source to the export data -// of the imported package. -func (p *parser) import_here() int { +func (p *parser) importdcl() { if trace && Debug['x'] != 0 { - defer p.trace("import_here")() + defer p.trace("importdcl")() } - importmyname = nil + var my *Sym switch p.tok { case LNAME, '@', '?': // import with given name - importmyname = p.sym() + my = p.sym() case '.': // import into my name space - importmyname = Lookup(".") + my = Lookup(".") p.next() } - var path Val - if p.tok == LLITERAL { - path = p.val - p.next() - } else { + if p.tok != LLITERAL { p.syntax_error("missing import path; require quoted string") p.advance(';', ')') + return } - line := parserline() - importfile(&path, line) - return line + line := int32(parserline()) + path := p.val + p.next() + + importfile(&path) + if p.tok != LPACKAGE { + // When an invalid import path is passed to importfile, + // it calls Yyerror and then sets up a fake import with + // no package statement. This allows us to test more + // than one invalid import statement in a single file. + p.import_there() + if nerrors == 0 { + Fatalf("phase error in import") + } + return + } + p.import_package() + p.import_there() + + ipkg := importpkg + importpkg = nil + + if my == nil { + my = Lookup(ipkg.Name) + } + + pack := Nod(OPACK, nil, nil) + pack.Sym = my + pack.Name.Pkg = ipkg + pack.Lineno = line + + if strings.HasPrefix(my.Name, ".") { + importdot(ipkg, pack) + return + } + if my.Name == "init" { + lineno = line + Yyerror("cannot import package as init - init must be a func") + return + } + if my.Name == "_" { + return + } + if my.Def != nil { + lineno = line + redeclare(my, "as imported package name") + } + my.Def = pack + my.Lastlineno = line + my.Block = 1 // at top level } // import_package parses the header of an imported package as exported From 5a9c128a0313df72973259bea946262cb8973d86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Mo=CC=88hrmann?= Date: Fri, 19 Feb 2016 22:45:38 +0100 Subject: [PATCH 057/117] fmt: remove math package dependency and avoid float operations Remove floating point comparisons and rely only on the information directly provided by appendFloat. Make restoring the zero padding flag explicit instead of using a defer. Rearrange some case distinctions to remove duplicated code. Add more test cases for zero padded floating point numbers with sign. benchmark old ns/op new ns/op delta BenchmarkSprintfFloat-4 187 180 -3.74% Change-Id: Ifa2ae85257909f40b1b18118c92b516933271729 Reviewed-on: https://go-review.googlesource.com/19721 Reviewed-by: Rob Pike --- src/fmt/fmt_test.go | 6 ++++++ src/fmt/format.go | 43 +++++++++++++++++-------------------------- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/fmt/fmt_test.go b/src/fmt/fmt_test.go index 793f709a79..8d7c36ceb1 100644 --- a/src/fmt/fmt_test.go +++ b/src/fmt/fmt_test.go @@ -259,6 +259,12 @@ var fmtTests = []struct { {"%+.3F", float32(-1.0), "-1.000"}, {"%+07.2f", 1.0, "+001.00"}, {"%+07.2f", -1.0, "-001.00"}, + {"%-07.2f", 1.0, "1.00 "}, + {"%-07.2f", -1.0, "-1.00 "}, + {"%+-07.2f", 1.0, "+1.00 "}, + {"%+-07.2f", -1.0, "-1.00 "}, + {"%-+07.2f", 1.0, "+1.00 "}, + {"%-+07.2f", -1.0, "-1.00 "}, {"%+10.2f", +1.0, " +1.00"}, {"%+10.2f", -1.0, " -1.00"}, {"% .3E", -1.0, "-1.000E+00"}, diff --git a/src/fmt/format.go b/src/fmt/format.go index 517b18f7d4..bf9d00bbc0 100644 --- a/src/fmt/format.go +++ b/src/fmt/format.go @@ -5,7 +5,6 @@ package fmt import ( - "math" "strconv" "unicode/utf8" ) @@ -405,42 +404,34 @@ func doPrec(f *fmt, def int) int { // formatFloat formats a float64; it is an efficient equivalent to f.pad(strconv.FormatFloat()...). func (f *fmt) formatFloat(v float64, verb byte, prec, n int) { // Format number, reserving space for leading + sign if needed. - num := strconv.AppendFloat(f.intbuf[0:1], v, verb, prec, n) + num := strconv.AppendFloat(f.intbuf[:1], v, verb, prec, n) if num[1] == '-' || num[1] == '+' { num = num[1:] } else { num[0] = '+' } - // Special handling for infinity, which doesn't look like a number so shouldn't be padded with zeros. - if math.IsInf(v, 0) { - if f.zero { - defer func() { f.zero = true }() - f.zero = false - } - } - // num is now a signed version of the number. - // If we're zero padding, want the sign before the leading zeros. - // Achieve this by writing the sign out and then padding the unsigned number. - if f.zero && f.widPresent && f.wid > len(num) { - if f.space && v >= 0 { - f.buf.WriteByte(' ') // This is what C does: even with zero, f.space means space. - f.wid-- - } else if f.plus || v < 0 { - f.buf.WriteByte(num[0]) - f.wid-- - } - f.pad(num[1:]) - return - } // f.space says to replace a leading + with a space. if f.space && num[0] == '+' { num[0] = ' ' + } + // Special handling for "+Inf" and "-Inf", + // which don't look like a number so shouldn't be padded with zeros. + if num[1] == 'I' { + oldZero := f.zero + f.zero = false f.pad(num) + f.zero = oldZero return } - // Now we know the sign is attached directly to the number, if present at all. - // We want a sign if asked for, if it's negative, or if it's infinity (+Inf vs. -Inf). - if f.plus || num[0] == '-' || math.IsInf(v, 0) { + // We want a sign if asked for and if the sign is not positive. + if f.plus || num[0] != '+' { + // If we're zero padding we want the sign before the leading zeros. + // Achieve this by writing the sign out and then padding the unsigned number. + if f.zero && f.widPresent && f.wid > len(num) { + f.buf.WriteByte(num[0]) + f.wid-- + num = num[1:] + } f.pad(num) return } From 0d5e6a3f07414ecf6a14bc601532aa305296f562 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 19 Feb 2016 11:42:34 -0800 Subject: [PATCH 058/117] cmd/api: fix benchmark to ignore internal packages Change-Id: I8ee46287ae0744efa83ad343997ad6835520fa5c Reviewed-on: https://go-review.googlesource.com/19688 Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/cmd/api/goapi_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/api/goapi_test.go b/src/cmd/api/goapi_test.go index 1d2cc9ac82..a3fe0efedc 100644 --- a/src/cmd/api/goapi_test.go +++ b/src/cmd/api/goapi_test.go @@ -178,7 +178,7 @@ func BenchmarkAll(b *testing.B) { for _, context := range contexts { w := NewWalker(context, filepath.Join(build.Default.GOROOT, "src")) for _, name := range pkgNames { - if name != "unsafe" && !strings.HasPrefix(name, "cmd/") { + if name != "unsafe" && !strings.HasPrefix(name, "cmd/") && !internalPkg.MatchString(name) { pkg, _ := w.Import(name) w.export(pkg) } From 7d3a40978aaa69c3cf08068a83252927b4514e9d Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 1 Dec 2015 12:19:36 -0800 Subject: [PATCH 059/117] cmd/compile: refactor export data parsing Merge push_parser and pop_parser into a single parse_import function and inline unimportfile. Shake out function boundaries a little bit so that the symmetry is readily visible. Move the import_package call into parse_import (and inline import_there into import_package). This means importfile no longer needs to provide fake import data to be needlessly lexed/parsed every time it's called. Also, instead of indicating import success/failure by whether the next token is "package", import_spec can just check whether importpkg is non-nil. Tangentially, this somehow alters the diagnostics produced for test/fixedbugs/issue11610.go. However, the new diagnostics are more consistent with those produced when the empty import statement is absent, which seems more desirable than maintaining the previous errors. Change-Id: I5cd1c22aa14da8a743ef569ff084711d137279d5 Reviewed-on: https://go-review.googlesource.com/19650 Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/gc/lex.go | 99 +++++++-------------------- src/cmd/compile/internal/gc/parser.go | 58 ++++------------ test/fixedbugs/issue11610.go | 4 +- 3 files changed, 39 insertions(+), 122 deletions(-) diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go index 83f25a5e2a..0bcfb3687d 100644 --- a/src/cmd/compile/internal/gc/lex.go +++ b/src/cmd/compile/internal/gc/lex.go @@ -671,38 +671,30 @@ func loadsys() { importpkg = Runtimepkg cannedimports("runtime.Builtin", runtimeimport) - thenewparser.import_package() - thenewparser.import_there() importpkg = unsafepkg cannedimports("unsafe.o", unsafeimport) - thenewparser.import_package() - thenewparser.import_there() importpkg = nil } -func fakeimport() { - importpkg = mkpkg("fake") - cannedimports("fake.o", "$$\n") -} - func importfile(f *Val) { + if importpkg != nil { + Fatalf("importpkg not nil") + } + path_, ok := f.U.(string) if !ok { Yyerror("import statement not a string") - fakeimport() return } if len(path_) == 0 { Yyerror("import path is empty") - fakeimport() return } if isbadimport(path_) { - fakeimport() return } @@ -731,7 +723,6 @@ func importfile(f *Val) { } importpkg = unsafepkg - cannedimports("unsafe.o", "package unsafe\n\n$$\n\n") imported_unsafe = true return } @@ -739,7 +730,6 @@ func importfile(f *Val) { if islocalname(path_) { if path_[0] == '/' { Yyerror("import path cannot be absolute path") - fakeimport() return } @@ -754,7 +744,6 @@ func importfile(f *Val) { path_ = cleanbuf if isbadimport(path_) { - fakeimport() return } } @@ -767,28 +756,18 @@ func importfile(f *Val) { importpkg = mkpkg(path_) - // If we already saw that package, feed a dummy statement - // to the lexer to avoid parsing export data twice. if importpkg.Imported { - tag := "" - if importpkg.Safe { - tag = "safe" - } - - p := fmt.Sprintf("package %s %s\n$$\n", importpkg.Name, tag) - cannedimports(file, p) return } importpkg.Imported = true - var err error - var imp *obj.Biobuf - imp, err = obj.Bopenr(file) + imp, err := obj.Bopenr(file) if err != nil { Yyerror("can't open import: %q: %v", path_, err) errorexit() } + defer obj.Bterm(imp) if strings.HasSuffix(file, ".a") { if !skiptopkgdef(imp) { @@ -845,74 +824,44 @@ func importfile(f *Val) { case '\n': // old export format pushedio = curio - - curio.bin = imp - curio.peekc = 0 - curio.peekc1 = 0 - curio.infile = file - curio.nlsemi = false + curio = Io{bin: imp, infile: file} typecheckok = true - push_parser() + parse_import() + + typecheckok = false + curio = pushedio + pushedio.bin = nil case 'B': // new export format obj.Bgetc(imp) // skip \n after $$B Import(imp) - // continue as if the package was imported before (see above) - tag := "" - if importpkg.Safe { - tag = "safe" - } - p := fmt.Sprintf("package %s %s\n$$\n", importpkg.Name, tag) - cannedimports(file, p) - // Reset incannedimport flag (we are not truly in a - // canned import) - this will cause importpkg.Direct to - // be set via parser.import_package (was issue #13977). - // - // TODO(gri) Remove this global variable and convoluted - // code in the process of streamlining the import code. - incannedimport = 0 - default: Yyerror("no import in %q", path_) - } -} - -func unimportfile() { - pop_parser() - - if curio.bin != nil { - obj.Bterm(curio.bin) - curio.bin = nil - } else { - lexlineno-- // re correct sys.6 line number + errorexit() } - curio = pushedio - - pushedio.bin = nil - incannedimport = 0 - typecheckok = false + if safemode != 0 && !importpkg.Safe { + Yyerror("cannot import unsafe package %q", importpkg.Path) + } } func cannedimports(file string, cp string) { lexlineno++ // if sys.6 is included on line 1, - pushedio = curio - - curio.bin = nil - curio.peekc = 0 - curio.peekc1 = 0 - curio.infile = file - curio.cp = cp - curio.nlsemi = false - + curio = Io{infile: file, cp: cp} typecheckok = true incannedimport = 1 - push_parser() + parse_import() + + typecheckok = false + incannedimport = 0 + curio = pushedio + pushedio.bin = nil + lexlineno-- // re correct sys.6 line number } func isSpace(c int) bool { diff --git a/src/cmd/compile/internal/gc/parser.go b/src/cmd/compile/internal/gc/parser.go index 6081383918..4a49836e8d 100644 --- a/src/cmd/compile/internal/gc/parser.go +++ b/src/cmd/compile/internal/gc/parser.go @@ -20,13 +20,11 @@ import ( const trace = false // if set, parse tracing can be enabled with -x -// TODO(gri) Once we handle imports w/o redirecting the underlying -// source of the lexer we can get rid of these. They are here for -// compatibility with the existing yacc-based parser setup (issue 13242). -var thenewparser parser // the parser in use -var savedstate []parser // saved parser state, used during import +// TODO(gri) Once we stop supporting the legacy export data format +// we can get rid of this (issue 13242). +var fileparser parser // the Go source file parser in use -func push_parser() { +func parse_import() { // Indentation (for tracing) must be preserved across parsers // since we are changing the lexer source (and parser state) // under foot, in the middle of productions. This won't be @@ -34,25 +32,16 @@ func push_parser() { // be the push/pop_parser functionality. // (Instead we could just use a global variable indent, but // but eventually indent should be parser-specific anyway.) - indent := thenewparser.indent - savedstate = append(savedstate, thenewparser) - thenewparser = parser{indent: indent} // preserve indentation - thenewparser.next() -} - -func pop_parser() { - indent := thenewparser.indent - n := len(savedstate) - 1 - thenewparser = savedstate[n] - thenewparser.indent = indent // preserve indentation - savedstate = savedstate[:n] + importparser := parser{indent: fileparser.indent} // preserve indentation + importparser.next() + importparser.import_package() } // parse_file sets up a new parser and parses a single Go source file. func parse_file() { - thenewparser = parser{} - thenewparser.next() - thenewparser.file() + fileparser = parser{} + fileparser.next() + fileparser.file() } type parser struct { @@ -364,23 +353,18 @@ func (p *parser) importdcl() { p.next() importfile(&path) - if p.tok != LPACKAGE { - // When an invalid import path is passed to importfile, - // it calls Yyerror and then sets up a fake import with - // no package statement. This allows us to test more - // than one invalid import statement in a single file. - p.import_there() + if importpkg == nil { if nerrors == 0 { Fatalf("phase error in import") } return } - p.import_package() - p.import_there() ipkg := importpkg importpkg = nil + ipkg.Direct = true + if my == nil { my = Lookup(ipkg.Name) } @@ -442,23 +426,8 @@ func (p *parser) import_package() { } else if importpkg.Name != name { Yyerror("conflicting names %s and %s for package %q", importpkg.Name, name, importpkg.Path) } - if incannedimport == 0 { - importpkg.Direct = true - } importpkg.Safe = importsafe - if safemode != 0 && !importsafe { - Yyerror("cannot import unsafe package %q", importpkg.Path) - } -} - -// import_there parses the imported package definitions and then switches -// the underlying lexed source back to the importing package. -func (p *parser) import_there() { - if trace && Debug['x'] != 0 { - defer p.trace("import_there")() - } - defercheckwidth() p.hidden_import_list() @@ -469,7 +438,6 @@ func (p *parser) import_there() { } resumecheckwidth() - unimportfile() } // Declaration = ConstDecl | TypeDecl | VarDecl . diff --git a/test/fixedbugs/issue11610.go b/test/fixedbugs/issue11610.go index a326249ed4..56f245dee5 100644 --- a/test/fixedbugs/issue11610.go +++ b/test/fixedbugs/issue11610.go @@ -9,9 +9,9 @@ package a import"" // ERROR "import path is empty" -var? // ERROR "invalid declaration" +var? // ERROR "unexpected \?" -var x int // ERROR "unexpected var" +var x int // ERROR "unexpected var" "cannot declare name" func main() { } From 699a2ba137fec09371da431907431ec2020a58af Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 19 Feb 2016 18:36:02 -0800 Subject: [PATCH 060/117] cmd/compile: switch cannedimports to use a Biobuf Allows eliminating the separate lexer code paths for reading from cp in the next CL. Change-Id: I49098ecef32b735c4a01374443c2f847235ff964 Reviewed-on: https://go-review.googlesource.com/19750 Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/gc/lex.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go index 0bcfb3687d..e506f7a117 100644 --- a/src/cmd/compile/internal/gc/lex.go +++ b/src/cmd/compile/internal/gc/lex.go @@ -851,7 +851,7 @@ func importfile(f *Val) { func cannedimports(file string, cp string) { lexlineno++ // if sys.6 is included on line 1, pushedio = curio - curio = Io{infile: file, cp: cp} + curio = Io{infile: file, bin: obj.Binitr(strings.NewReader(cp))} typecheckok = true incannedimport = 1 From f8e41f6f5907ce832cc263bdce749117d4d0b342 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 2 Dec 2015 11:30:34 -0800 Subject: [PATCH 061/117] cmd/compile: eliminate Io.infile and Io.cp infile is never read and cp is never written. Both are unneeded. Change-Id: I0a90bb772a53a580ea4be8e5f0f770da7c1acf3a Reviewed-on: https://go-review.googlesource.com/19651 Reviewed-by: Brad Fitzpatrick Reviewed-by: Dave Cheney Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/gc/go.go | 2 -- src/cmd/compile/internal/gc/lex.go | 48 +++++++++++------------------- 2 files changed, 17 insertions(+), 33 deletions(-) diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go index ebc6a5171b..71a5d88ccb 100644 --- a/src/cmd/compile/internal/gc/go.go +++ b/src/cmd/compile/internal/gc/go.go @@ -386,9 +386,7 @@ type Sig struct { } type Io struct { - infile string bin *obj.Biobuf - cp string // used for content when bin==nil last int peekc int peekc1 int // second peekc for ... diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go index e506f7a117..57b2959de6 100644 --- a/src/cmd/compile/internal/gc/lex.go +++ b/src/cmd/compile/internal/gc/lex.go @@ -320,7 +320,6 @@ func Main() { linehistpush(infile) - curio.infile = infile var err error curio.bin, err = obj.Bopenr(infile) if err != nil { @@ -824,7 +823,7 @@ func importfile(f *Val) { case '\n': // old export format pushedio = curio - curio = Io{bin: imp, infile: file} + curio = Io{bin: imp} typecheckok = true parse_import() @@ -851,7 +850,7 @@ func importfile(f *Val) { func cannedimports(file string, cp string) { lexlineno++ // if sys.6 is included on line 1, pushedio = curio - curio = Io{infile: file, bin: obj.Binitr(strings.NewReader(cp))} + curio = Io{bin: obj.Binitr(strings.NewReader(cp))} typecheckok = true incannedimport = 1 @@ -1903,42 +1902,29 @@ func getc() int { goto check } - if curio.bin == nil { - if len(curio.cp) == 0 { - c = 0 - } else { - c = int(curio.cp[0]) - curio.cp = curio.cp[1:] +loop: + c = obj.Bgetc(curio.bin) + // recognize BOM (U+FEFF): UTF-8 encoding is 0xef 0xbb 0xbf + if c == 0xef { + buf, err := curio.bin.Peek(2) + if err != nil { + yyerrorl(int(lexlineno), "illegal UTF-8 sequence ef % x followed by read error (%v)", string(buf), err) + errorexit() } - } else { - loop: - c = obj.Bgetc(curio.bin) - // recognize BOM (U+FEFF): UTF-8 encoding is 0xef 0xbb 0xbf - if c == 0xef { - buf, err := curio.bin.Peek(2) - if err != nil { - yyerrorl(int(lexlineno), "illegal UTF-8 sequence ef % x followed by read error (%v)", string(buf), err) - errorexit() - } - if buf[0] == 0xbb && buf[1] == 0xbf { - yyerrorl(int(lexlineno), "Unicode (UTF-8) BOM in middle of file") + if buf[0] == 0xbb && buf[1] == 0xbf { + yyerrorl(int(lexlineno), "Unicode (UTF-8) BOM in middle of file") - // consume BOM bytes - obj.Bgetc(curio.bin) - obj.Bgetc(curio.bin) - goto loop - } + // consume BOM bytes + obj.Bgetc(curio.bin) + obj.Bgetc(curio.bin) + goto loop } } check: switch c { case 0: - if curio.bin != nil { - Yyerror("illegal NUL byte") - break - } - fallthrough + Yyerror("illegal NUL byte") // insert \n at EOF case EOF: From 4e6e8e8c582bcd7d74378be31f070eecf0f1d5e4 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 19 Feb 2016 18:39:25 -0800 Subject: [PATCH 062/117] cmd/compile: change two pushedio.bin tests to use importpkg instead pushedio.bin and importpkg are both non-nil iff we're parsing an package's export data, so "pushedio.bin == nil" and "importpkg == nil" are equivalent tests. Change-Id: I571ee908fef867117ef72c5da1eb24fe9b3fd12d Reviewed-on: https://go-review.googlesource.com/19751 Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/gc/lex.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go index 57b2959de6..ae201a7d97 100644 --- a/src/cmd/compile/internal/gc/lex.go +++ b/src/cmd/compile/internal/gc/lex.go @@ -1936,7 +1936,7 @@ check: fallthrough case '\n': - if pushedio.bin == nil { + if importpkg == nil { lexlineno++ } } @@ -1948,7 +1948,7 @@ check: func ungetc(c int) { curio.peekc1 = curio.peekc curio.peekc = c - if c == '\n' && pushedio.bin == nil { + if c == '\n' && importpkg == nil { lexlineno-- } } From 338a891e79444de97d6f485b1632d42899c47c6d Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 19 Feb 2016 18:47:01 -0800 Subject: [PATCH 063/117] cmd/compile: eliminate pushedio and savedstate While here, get drop the lexlineno{++,--} hacks for canned imports. They were added in commit d3237f9, but don't seem to serve any purpose. Change-Id: I00f9e6be0ae9f217f2fa113b85e041dfd0303757 Reviewed-on: https://go-review.googlesource.com/19652 Reviewed-by: Robert Griesemer Run-TryBot: Matthew Dempsky --- src/cmd/compile/internal/gc/go.go | 2 -- src/cmd/compile/internal/gc/lex.go | 51 ++++++--------------------- src/cmd/compile/internal/gc/parser.go | 14 ++++++-- 3 files changed, 22 insertions(+), 45 deletions(-) diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go index 71a5d88ccb..7cfc2c9057 100644 --- a/src/cmd/compile/internal/gc/go.go +++ b/src/cmd/compile/internal/gc/go.go @@ -451,8 +451,6 @@ var dotlist [10]Dlist // size is max depth of embeddeds var curio Io -var pushedio Io - var lexlineno int32 var lineno int32 diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go index ae201a7d97..91b521e95b 100644 --- a/src/cmd/compile/internal/gc/lex.go +++ b/src/cmd/compile/internal/gc/lex.go @@ -320,22 +320,15 @@ func Main() { linehistpush(infile) - var err error - curio.bin, err = obj.Bopenr(infile) + bin, err := obj.Bopenr(infile) if err != nil { fmt.Printf("open %s: %v\n", infile, err) errorexit() } - curio.peekc = 0 - curio.peekc1 = 0 - curio.nlsemi = false - curio.eofnl = false - curio.last = 0 - // Skip initial BOM if present. - if obj.Bgetrune(curio.bin) != BOM { - obj.Bungetrune(curio.bin) + if obj.Bgetrune(bin) != BOM { + obj.Bungetrune(bin) } block = 1 @@ -343,15 +336,13 @@ func Main() { imported_unsafe = false - parse_file() + parse_file(bin) if nsyntaxerrors != 0 { errorexit() } linehistpop() - if curio.bin != nil { - obj.Bterm(curio.bin) - } + obj.Bterm(bin) } testdclstack() @@ -667,14 +658,16 @@ func loadsys() { block = 1 iota_ = -1000000 + incannedimport = 1 importpkg = Runtimepkg - cannedimports("runtime.Builtin", runtimeimport) + parse_import(obj.Binitr(strings.NewReader(runtimeimport))) importpkg = unsafepkg - cannedimports("unsafe.o", unsafeimport) + parse_import(obj.Binitr(strings.NewReader(unsafeimport))) importpkg = nil + incannedimport = 0 } func importfile(f *Val) { @@ -822,15 +815,7 @@ func importfile(f *Val) { switch c { case '\n': // old export format - pushedio = curio - curio = Io{bin: imp} - typecheckok = true - - parse_import() - - typecheckok = false - curio = pushedio - pushedio.bin = nil + parse_import(imp) case 'B': // new export format @@ -847,22 +832,6 @@ func importfile(f *Val) { } } -func cannedimports(file string, cp string) { - lexlineno++ // if sys.6 is included on line 1, - pushedio = curio - curio = Io{bin: obj.Binitr(strings.NewReader(cp))} - typecheckok = true - incannedimport = 1 - - parse_import() - - typecheckok = false - incannedimport = 0 - curio = pushedio - pushedio.bin = nil - lexlineno-- // re correct sys.6 line number -} - func isSpace(c int) bool { return c == ' ' || c == '\t' || c == '\n' || c == '\r' } diff --git a/src/cmd/compile/internal/gc/parser.go b/src/cmd/compile/internal/gc/parser.go index 4a49836e8d..e41f3b9e86 100644 --- a/src/cmd/compile/internal/gc/parser.go +++ b/src/cmd/compile/internal/gc/parser.go @@ -13,6 +13,7 @@ package gc // to handle optional commas and semicolons before a closing ) or } . import ( + "cmd/internal/obj" "fmt" "strconv" "strings" @@ -24,7 +25,10 @@ const trace = false // if set, parse tracing can be enabled with -x // we can get rid of this (issue 13242). var fileparser parser // the Go source file parser in use -func parse_import() { +func parse_import(bin *obj.Biobuf) { + pushedio := curio + curio = Io{bin: bin} + // Indentation (for tracing) must be preserved across parsers // since we are changing the lexer source (and parser state) // under foot, in the middle of productions. This won't be @@ -35,10 +39,14 @@ func parse_import() { importparser := parser{indent: fileparser.indent} // preserve indentation importparser.next() importparser.import_package() + + curio = pushedio } // parse_file sets up a new parser and parses a single Go source file. -func parse_file() { +func parse_file(bin *obj.Biobuf) { + curio = Io{bin: bin} + fileparser = parser{} fileparser.next() fileparser.file() @@ -428,6 +436,7 @@ func (p *parser) import_package() { } importpkg.Safe = importsafe + typecheckok = true defercheckwidth() p.hidden_import_list() @@ -438,6 +447,7 @@ func (p *parser) import_package() { } resumecheckwidth() + typecheckok = false } // Declaration = ConstDecl | TypeDecl | VarDecl . From 3e40f13cf3bf3f23f3f2f60dec174a1bdad57f16 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 19 Feb 2016 18:51:24 -0800 Subject: [PATCH 064/117] cmd/compile: eliminate global fileparser Change-Id: I9b8b13731ccc2ba33d21642b12cc614dde0804b1 Reviewed-on: https://go-review.googlesource.com/19752 Reviewed-by: Robert Griesemer Run-TryBot: Matthew Dempsky --- src/cmd/compile/internal/gc/lex.go | 8 ++++---- src/cmd/compile/internal/gc/parser.go | 19 ++++--------------- 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go index 91b521e95b..66cc01862d 100644 --- a/src/cmd/compile/internal/gc/lex.go +++ b/src/cmd/compile/internal/gc/lex.go @@ -661,16 +661,16 @@ func loadsys() { incannedimport = 1 importpkg = Runtimepkg - parse_import(obj.Binitr(strings.NewReader(runtimeimport))) + parse_import(obj.Binitr(strings.NewReader(runtimeimport)), nil) importpkg = unsafepkg - parse_import(obj.Binitr(strings.NewReader(unsafeimport))) + parse_import(obj.Binitr(strings.NewReader(unsafeimport)), nil) importpkg = nil incannedimport = 0 } -func importfile(f *Val) { +func importfile(f *Val, indent []byte) { if importpkg != nil { Fatalf("importpkg not nil") } @@ -815,7 +815,7 @@ func importfile(f *Val) { switch c { case '\n': // old export format - parse_import(imp) + parse_import(imp, indent) case 'B': // new export format diff --git a/src/cmd/compile/internal/gc/parser.go b/src/cmd/compile/internal/gc/parser.go index e41f3b9e86..048b81e01b 100644 --- a/src/cmd/compile/internal/gc/parser.go +++ b/src/cmd/compile/internal/gc/parser.go @@ -21,22 +21,11 @@ import ( const trace = false // if set, parse tracing can be enabled with -x -// TODO(gri) Once we stop supporting the legacy export data format -// we can get rid of this (issue 13242). -var fileparser parser // the Go source file parser in use - -func parse_import(bin *obj.Biobuf) { +func parse_import(bin *obj.Biobuf, indent []byte) { pushedio := curio curio = Io{bin: bin} - // Indentation (for tracing) must be preserved across parsers - // since we are changing the lexer source (and parser state) - // under foot, in the middle of productions. This won't be - // needed anymore once we fix issue 13242, but neither will - // be the push/pop_parser functionality. - // (Instead we could just use a global variable indent, but - // but eventually indent should be parser-specific anyway.) - importparser := parser{indent: fileparser.indent} // preserve indentation + importparser := parser{indent: indent} // preserve indentation importparser.next() importparser.import_package() @@ -47,7 +36,7 @@ func parse_import(bin *obj.Biobuf) { func parse_file(bin *obj.Biobuf) { curio = Io{bin: bin} - fileparser = parser{} + fileparser := parser{} fileparser.next() fileparser.file() } @@ -360,7 +349,7 @@ func (p *parser) importdcl() { path := p.val p.next() - importfile(&path) + importfile(&path, p.indent) if importpkg == nil { if nerrors == 0 { Fatalf("phase error in import") From 315f4c70f123cfbf061d097543af555547acd9c7 Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Thu, 18 Feb 2016 16:29:39 -0500 Subject: [PATCH 065/117] runtime: use correct psABI SP alignment before calling libc mmap Fixes #14384. Change-Id: Ib025cf2d20754b4c2db52f0a8a4717fd303371d6 Reviewed-on: https://go-review.googlesource.com/19660 Run-TryBot: Minux Ma TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor Reviewed-by: Austin Clements --- src/runtime/sys_linux_amd64.s | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/runtime/sys_linux_amd64.s b/src/runtime/sys_linux_amd64.s index aed85cb0aa..f407078176 100644 --- a/src/runtime/sys_linux_amd64.s +++ b/src/runtime/sys_linux_amd64.s @@ -258,7 +258,7 @@ TEXT runtime·sysMmap(SB),NOSPLIT,$0 // Call the function stored in _cgo_mmap using the GCC calling convention. // This must be called on the system stack. -TEXT runtime·callCgoMmap(SB),NOSPLIT,$0 +TEXT runtime·callCgoMmap(SB),NOSPLIT,$16 MOVQ addr+0(FP), DI MOVQ n+8(FP), SI MOVL prot+16(FP), DX @@ -266,7 +266,11 @@ TEXT runtime·callCgoMmap(SB),NOSPLIT,$0 MOVL fd+24(FP), R8 MOVL off+28(FP), R9 MOVQ _cgo_mmap(SB), AX + MOVQ SP, BX + ANDQ $~15, SP // alignment as per amd64 psABI + MOVQ BX, 0(SP) CALL AX + MOVQ 0(SP), SP MOVQ AX, ret+32(FP) RET From 5efbdd9d10908206d4e0351cb4724c5fefdfa2be Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 22 Jan 2016 13:31:57 -0800 Subject: [PATCH 066/117] net: fix race in (*resolverConfig).tryUpdate Fixes #14072. Change-Id: Ie31caa06690ac621906fc5acd34da2efa4e2049f Reviewed-on: https://go-review.googlesource.com/18860 Reviewed-by: Mikio Hara Run-TryBot: Mikio Hara --- src/net/dnsclient_unix.go | 22 ++++++---------------- src/net/dnsconfig_unix.go | 28 +++++++++++++++++++--------- src/net/dnsconfig_unix_test.go | 2 ++ 3 files changed, 27 insertions(+), 25 deletions(-) diff --git a/src/net/dnsclient_unix.go b/src/net/dnsclient_unix.go index 17188f0024..736e57322c 100644 --- a/src/net/dnsclient_unix.go +++ b/src/net/dnsclient_unix.go @@ -229,7 +229,6 @@ type resolverConfig struct { // time to recheck resolv.conf. ch chan struct{} // guards lastChecked and modTime lastChecked time.Time // last time resolv.conf was checked - modTime time.Time // time of resolv.conf modification mu sync.RWMutex // protects dnsConfig dnsConfig *dnsConfig // parsed resolv.conf structure used in lookups @@ -239,16 +238,12 @@ var resolvConf resolverConfig // init initializes conf and is only called via conf.initOnce. func (conf *resolverConfig) init() { - // Set dnsConfig, modTime, and lastChecked so we don't parse + // Set dnsConfig and lastChecked so we don't parse // resolv.conf twice the first time. conf.dnsConfig = systemConf().resolv if conf.dnsConfig == nil { conf.dnsConfig = dnsReadConfig("/etc/resolv.conf") } - - if fi, err := os.Stat("/etc/resolv.conf"); err == nil { - conf.modTime = fi.ModTime() - } conf.lastChecked = time.Now() // Prepare ch so that only one update of resolverConfig may @@ -274,17 +269,12 @@ func (conf *resolverConfig) tryUpdate(name string) { } conf.lastChecked = now + var mtime time.Time if fi, err := os.Stat(name); err == nil { - if fi.ModTime().Equal(conf.modTime) { - return - } - conf.modTime = fi.ModTime() - } else { - // If modTime wasn't set prior, assume nothing has changed. - if conf.modTime.IsZero() { - return - } - conf.modTime = time.Time{} + mtime = fi.ModTime() + } + if mtime.Equal(conf.dnsConfig.mtime) { + return } dnsConf := dnsReadConfig(name) diff --git a/src/net/dnsconfig_unix.go b/src/net/dnsconfig_unix.go index 6073fdb6d8..0515ca90de 100644 --- a/src/net/dnsconfig_unix.go +++ b/src/net/dnsconfig_unix.go @@ -8,18 +8,21 @@ package net +import "time" + var defaultNS = []string{"127.0.0.1", "::1"} type dnsConfig struct { - servers []string // servers to use - search []string // suffixes to append to local name - ndots int // number of dots in name to trigger absolute lookup - timeout int // seconds before giving up on packet - attempts int // lost packets before giving up on server - rotate bool // round robin among servers - unknownOpt bool // anything unknown was encountered - lookup []string // OpenBSD top-level database "lookup" order - err error // any error that occurs during open of resolv.conf + servers []string // servers to use + search []string // suffixes to append to local name + ndots int // number of dots in name to trigger absolute lookup + timeout int // seconds before giving up on packet + attempts int // lost packets before giving up on server + rotate bool // round robin among servers + unknownOpt bool // anything unknown was encountered + lookup []string // OpenBSD top-level database "lookup" order + err error // any error that occurs during open of resolv.conf + mtime time.Time // time of resolv.conf modification } // See resolv.conf(5) on a Linux machine. @@ -38,6 +41,13 @@ func dnsReadConfig(filename string) *dnsConfig { return conf } defer file.close() + if fi, err := file.file.Stat(); err == nil { + conf.mtime = fi.ModTime() + } else { + conf.servers = defaultNS + conf.err = err + return conf + } for line, ok := file.readLine(); ok; line, ok = file.readLine() { if len(line) > 0 && (line[0] == ';' || line[0] == '#') { // comment. diff --git a/src/net/dnsconfig_unix_test.go b/src/net/dnsconfig_unix_test.go index c8eed61890..849c0da93b 100644 --- a/src/net/dnsconfig_unix_test.go +++ b/src/net/dnsconfig_unix_test.go @@ -10,6 +10,7 @@ import ( "os" "reflect" "testing" + "time" ) var dnsReadConfigTests = []struct { @@ -76,6 +77,7 @@ func TestDNSReadConfig(t *testing.T) { if conf.err != nil { t.Fatal(conf.err) } + conf.mtime = time.Time{} if !reflect.DeepEqual(conf, tt.want) { t.Errorf("%s:\ngot: %+v\nwant: %+v", tt.name, conf, tt.want) } From 3a11c8d3190210c510c152471ddb85eb36a15e76 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Sat, 20 Feb 2016 00:00:53 -0800 Subject: [PATCH 067/117] cmd/compile: simplify if statement parsing Somewhat notably, this means long if statement chains are now parsed recursively, rather than iteratively. This shouldn't be a concern though, as several other functions (e.g., gen, typecheck, walk) already use recursion to process the parsed if statement Node trees. Change-Id: Ic8c12ace9021c870d60c06f5db86a48c4ec57084 Reviewed-on: https://go-review.googlesource.com/19756 Reviewed-by: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/gc/parser.go | 61 +++------------------------ 1 file changed, 6 insertions(+), 55 deletions(-) diff --git a/src/cmd/compile/internal/gc/parser.go b/src/cmd/compile/internal/gc/parser.go index 048b81e01b..3a5b508393 100644 --- a/src/cmd/compile/internal/gc/parser.go +++ b/src/cmd/compile/internal/gc/parser.go @@ -1064,65 +1064,16 @@ func (p *parser) if_stmt() *Node { stmt.Nbody = p.loop_body("if clause") - l := p.elseif_list_else() // does markdcl - - n := stmt - popdcl() - for nn := l; nn != nil; nn = nn.Next { - if nn.N.Op == OIF { - popdcl() - } - n.Rlist = list1(nn.N) - n = nn.N - } - - return stmt -} - -func (p *parser) elseif() *NodeList { - if trace && Debug['x'] != 0 { - defer p.trace("elseif")() - } - - // LELSE LIF already consumed - markdcl() // matching popdcl in if_stmt - - stmt := p.if_header() - if stmt.Left == nil { - Yyerror("missing condition in if statement") - } - - stmt.Nbody = p.loop_body("if clause") - - return list1(stmt) -} - -func (p *parser) elseif_list_else() (l *NodeList) { - if trace && Debug['x'] != 0 { - defer p.trace("elseif_list_else")() - } - - for p.got(LELSE) { - if p.got(LIF) { - l = concat(l, p.elseif()) + if p.got(LELSE) { + if p.tok == LIF { + stmt.Rlist = list1(p.if_stmt()) } else { - l = concat(l, p.else_()) - break + stmt.Rlist = list1(p.compound_stmt(true)) } } - return l -} - -func (p *parser) else_() *NodeList { - if trace && Debug['x'] != 0 { - defer p.trace("else")() - } - - l := &NodeList{N: p.compound_stmt(true)} - l.End = l - return l - + popdcl() + return stmt } // switch_stmt parses both expression and type switch statements. From 41eb5ca089be5495ab2299e2b6778fb8ceb8010a Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Wed, 17 Feb 2016 09:41:12 -0500 Subject: [PATCH 068/117] cmd/link: typo in error message Change-Id: Ideeef320d6a01a10c89524b6d895a64210a60f64 Reviewed-on: https://go-review.googlesource.com/19693 Reviewed-by: Brad Fitzpatrick Run-TryBot: David Crawshaw TryBot-Result: Gobot Gobot --- src/cmd/link/internal/ld/dwarf.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index a96b37a4be..fb3d8fb2cd 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -951,7 +951,7 @@ func defgotype(gotype *LSym) *DWDie { } if !strings.HasPrefix(gotype.Name, "type.") { - Diag("dwarf: type name doesn't start with \".type\": %s", gotype.Name) + Diag("dwarf: type name doesn't start with \"type.\": %s", gotype.Name) return mustFind(&dwtypes, "") } From e6d6ad47f52fa40dd07bb74b2df349321fad1eeb Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Tue, 16 Feb 2016 15:30:32 -0500 Subject: [PATCH 069/117] cmd/compile: update some type names in comments Change-Id: I741a1205bc6256c08b36efed43652bfbb75e4401 Reviewed-on: https://go-review.googlesource.com/19691 Reviewed-by: Brad Fitzpatrick Run-TryBot: David Crawshaw TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/gc/go.go | 3 +- src/cmd/compile/internal/gc/reflect.go | 48 +++++++++++++------------- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go index 7cfc2c9057..13a28c8720 100644 --- a/src/cmd/compile/internal/gc/go.go +++ b/src/cmd/compile/internal/gc/go.go @@ -329,8 +329,7 @@ const ( const ( // types of channel - // must match ../../pkg/nreflect/type.go:/Chandir - Cxxx = 0 + // must match ../../../../reflect/type.go:/ChanDir Crecv = 1 << 0 Csend = 1 << 1 Cboth = Crecv | Csend diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go index 264955c702..8693e3c112 100644 --- a/src/cmd/compile/internal/gc/reflect.go +++ b/src/cmd/compile/internal/gc/reflect.go @@ -45,7 +45,7 @@ func siglt(a, b *Sig) bool { // the given map type. This type is not visible to users - // we include only enough information to generate a correct GC // program for it. -// Make sure this stays in sync with ../../runtime/hashmap.go! +// Make sure this stays in sync with ../../../../runtime/hashmap.go! const ( BUCKETSIZE = 8 MAXKEYSIZE = 128 @@ -150,7 +150,7 @@ func mapbucket(t *Type) *Type { } // Builds a type representing a Hmap structure for the given map type. -// Make sure this stays in sync with ../../runtime/hashmap.go! +// Make sure this stays in sync with ../../../../runtime/hashmap.go! func hmap(t *Type) *Type { if t.Hmap != nil { return t.Hmap @@ -187,7 +187,7 @@ func hiter(t *Type) *Type { } // build a struct: - // hash_iter { + // hiter { // key *Key // val *Value // t *MapType @@ -201,7 +201,7 @@ func hiter(t *Type) *Type { // bucket uintptr // checkBucket uintptr // } - // must match ../../runtime/hashmap.go:hash_iter. + // must match ../../../../runtime/hashmap.go:hiter. var field [12]*Type field[0] = makefield("key", Ptrto(t.Down)) @@ -474,7 +474,7 @@ func dgopkgpath(s *Sym, ot int, pkg *Pkg) int { } // uncommonType -// ../../runtime/type.go:/uncommonType +// ../../../../runtime/type.go:/uncommonType func dextratype(sym *Sym, off int, t *Type, ptroff int) int { m := methods(t) if t.Sym == nil && len(m) == 0 { @@ -514,7 +514,7 @@ func dextratype(sym *Sym, off int, t *Type, ptroff int) int { // methods for _, a := range m { // method - // ../../runtime/type.go:/method + // ../../../../runtime/type.go:/method ot = dgostringptr(s, ot, a.name) ot = dgopkgpath(s, ot, a.pkg) @@ -711,21 +711,21 @@ func dcommontype(s *Sym, ot int, t *Type) int { gcsym, useGCProg, ptrdata := dgcsym(t) - // ../../pkg/reflect/type.go:/^type.commonType + // ../../../../reflect/type.go:/^type.rtype // actual type structure - // type commonType struct { + // type rtype struct { // size uintptr - // ptrsize uintptr + // ptrdata uintptr // hash uint32 // _ uint8 // align uint8 // fieldAlign uint8 // kind uint8 - // alg unsafe.Pointer - // gcdata unsafe.Pointer + // alg *typeAlg + // gcdata *byte // string *string - // *extraType - // ptrToThis *Type + // *uncommonType + // ptrToThis *rtype // } ot = duintptr(s, ot, uint64(t.Width)) ot = duintptr(s, ot, uint64(ptrdata)) @@ -1011,7 +1011,7 @@ ok: case TARRAY: if t.Bound >= 0 { - // ../../runtime/type.go:/ArrayType + // ../../../../runtime/type.go:/arrayType s1 := dtypesym(t.Type) t2 := typ(TARRAY) @@ -1024,7 +1024,7 @@ ok: ot = dsymptr(s, ot, s2, 0) ot = duintptr(s, ot, uint64(t.Bound)) } else { - // ../../runtime/type.go:/SliceType + // ../../../../runtime/type.go:/sliceType s1 := dtypesym(t.Type) ot = dcommontype(s, ot, t) @@ -1032,7 +1032,7 @@ ok: ot = dsymptr(s, ot, s1, 0) } - // ../../runtime/type.go:/ChanType + // ../../../../runtime/type.go:/chanType case TCHAN: s1 := dtypesym(t.Type) @@ -1091,7 +1091,7 @@ ok: dtypesym(a.type_) } - // ../../../runtime/type.go:/InterfaceType + // ../../../../runtime/type.go:/interfaceType ot = dcommontype(s, ot, t) xt = ot - 2*Widthptr @@ -1099,14 +1099,14 @@ ok: ot = duintxx(s, ot, uint64(n), Widthint) ot = duintxx(s, ot, uint64(n), Widthint) for _, a := range m { - // ../../../runtime/type.go:/imethod + // ../../../../runtime/type.go:/imethod ot = dgostringptr(s, ot, a.name) ot = dgopkgpath(s, ot, a.pkg) ot = dsymptr(s, ot, dtypesym(a.type_), 0) } - // ../../../runtime/type.go:/MapType + // ../../../../runtime/type.go:/mapType case TMAP: s1 := dtypesym(t.Down) @@ -1141,20 +1141,20 @@ ok: case TPTR32, TPTR64: if t.Type.Etype == TANY { - // ../../runtime/type.go:/UnsafePointerType + // ../../../../runtime/type.go:/UnsafePointerType ot = dcommontype(s, ot, t) break } - // ../../runtime/type.go:/PtrType + // ../../../../runtime/type.go:/ptrType s1 := dtypesym(t.Type) ot = dcommontype(s, ot, t) xt = ot - 2*Widthptr ot = dsymptr(s, ot, s1, 0) - // ../../runtime/type.go:/StructType + // ../../../../runtime/type.go:/structType // for security, only the exported fields. case TSTRUCT: n := 0 @@ -1170,7 +1170,7 @@ ok: ot = duintxx(s, ot, uint64(n), Widthint) ot = duintxx(s, ot, uint64(n), Widthint) for t1 := t.Type; t1 != nil; t1 = t1.Down { - // ../../runtime/type.go:/structField + // ../../../../runtime/type.go:/structField if t1.Sym != nil && t1.Embedded == 0 { ot = dgostringptr(s, ot, t1.Sym.Name) if exportname(t1.Sym.Name) { @@ -1350,7 +1350,7 @@ func dalgsym(t *Type) *Sym { ggloblsym(eqfunc, int32(Widthptr), obj.DUPOK|obj.RODATA) } - // ../../runtime/alg.go:/typeAlg + // ../../../../runtime/alg.go:/typeAlg ot := 0 ot = dsymptr(s, ot, hashfunc, 0) From 9194421eedfd64d2d71e66cbf060d19502610c30 Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Fri, 19 Feb 2016 17:41:44 +0900 Subject: [PATCH 070/117] net: deflake TestDialerDualStackFDLeak We need to stop the mock listener certainly for preventing it from pulling up pending connections during measurement. Fixes #14223. Change-Id: Ia40db01d1262963697b83ca867563dec77d772e3 Reviewed-on: https://go-review.googlesource.com/19246 Run-TryBot: Mikio Hara TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/net/dial_test.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/net/dial_test.go b/src/net/dial_test.go index 2311b10824..1a9dfb26d3 100644 --- a/src/net/dial_test.go +++ b/src/net/dial_test.go @@ -176,6 +176,7 @@ func TestDialerDualStackFDLeak(t *testing.T) { t.Skip("both IPv4 and IPv6 are required") } + before := sw.Sockets() origTestHookLookupIP := testHookLookupIP defer func() { testHookLookupIP = origTestHookLookupIP }() testHookLookupIP = lookupLocalhost @@ -195,17 +196,15 @@ func TestDialerDualStackFDLeak(t *testing.T) { if err != nil { t.Fatal(err) } - defer dss.teardown() if err := dss.buildup(handler); err != nil { + dss.teardown() t.Fatal(err) } - before := sw.Sockets() - const T = 100 * time.Millisecond const N = 10 var wg sync.WaitGroup wg.Add(N) - d := &Dialer{DualStack: true, Timeout: T} + d := &Dialer{DualStack: true, Timeout: 100 * time.Millisecond} for i := 0; i < N; i++ { go func() { defer wg.Done() @@ -218,7 +217,7 @@ func TestDialerDualStackFDLeak(t *testing.T) { }() } wg.Wait() - time.Sleep(2 * T) // wait for the dial racers to stop + dss.teardown() after := sw.Sockets() if len(after) != len(before) { t.Errorf("got %d; want %d", len(after), len(before)) From 6716a54e368be250b3840fcdef3c2437886e02e6 Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Fri, 19 Feb 2016 17:37:04 +0900 Subject: [PATCH 071/117] net: make newLocalListener handle network argument correcly Change-Id: I8987e705af069846e6668e2f2104e0254e695139 Reviewed-on: https://go-review.googlesource.com/19706 Run-TryBot: Mikio Hara TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/net/mockserver_test.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/net/mockserver_test.go b/src/net/mockserver_test.go index dd6f4df3b9..38b317af7d 100644 --- a/src/net/mockserver_test.go +++ b/src/net/mockserver_test.go @@ -30,10 +30,20 @@ func testUnixAddr() string { func newLocalListener(network string) (Listener, error) { switch network { - case "tcp", "tcp4", "tcp6": + case "tcp": + if supportsIPv4 { + if ln, err := Listen("tcp4", "127.0.0.1:0"); err == nil { + return ln, nil + } + } + if supportsIPv6 { + return Listen("tcp6", "[::1]:0") + } + case "tcp4": if supportsIPv4 { return Listen("tcp4", "127.0.0.1:0") } + case "tcp6": if supportsIPv6 { return Listen("tcp6", "[::1]:0") } From 64d2a88105d503d1a0275388823b8112a870d13b Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Fri, 19 Feb 2016 17:34:54 +0900 Subject: [PATCH 072/117] net/internal/socktest: add missing support for AcceptEx Change-Id: I37faedc6fa316fffac80093b01e15429995b0f5b Reviewed-on: https://go-review.googlesource.com/19705 Reviewed-by: Ian Lance Taylor --- src/net/internal/socktest/switch.go | 2 +- src/net/internal/socktest/sys_windows.go | 30 ++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/net/internal/socktest/switch.go b/src/net/internal/socktest/switch.go index 8bef06b97c..3c37b6ff80 100644 --- a/src/net/internal/socktest/switch.go +++ b/src/net/internal/socktest/switch.go @@ -121,7 +121,7 @@ const ( FilterSocket FilterType = iota // for Socket FilterConnect // for Connect or ConnectEx FilterListen // for Listen - FilterAccept // for Accept or Accept4 + FilterAccept // for Accept, Accept4 or AcceptEx FilterGetsockoptInt // for GetsockoptInt FilterClose // for Close or Closesocket ) diff --git a/src/net/internal/socktest/sys_windows.go b/src/net/internal/socktest/sys_windows.go index e61bf2be60..2e3d2bc7fc 100644 --- a/src/net/internal/socktest/sys_windows.go +++ b/src/net/internal/socktest/sys_windows.go @@ -154,3 +154,33 @@ func (sw *Switch) Listen(s syscall.Handle, backlog int) (err error) { sw.stats.getLocked(so.Cookie).Listened++ return nil } + +// AcceptEx wraps syscall.AcceptEx. +func (sw *Switch) AcceptEx(ls syscall.Handle, as syscall.Handle, b *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, rcvd *uint32, overlapped *syscall.Overlapped) error { + so := sw.sockso(ls) + if so == nil { + return syscall.AcceptEx(ls, as, b, rxdatalen, laddrlen, raddrlen, rcvd, overlapped) + } + sw.fmu.RLock() + f, _ := sw.fltab[FilterAccept] + sw.fmu.RUnlock() + + af, err := f.apply(so) + if err != nil { + return err + } + so.Err = syscall.AcceptEx(ls, as, b, rxdatalen, laddrlen, raddrlen, rcvd, overlapped) + if err = af.apply(so); err != nil { + return err + } + + sw.smu.Lock() + defer sw.smu.Unlock() + if so.Err != nil { + sw.stats.getLocked(so.Cookie).AcceptFailed++ + return so.Err + } + nso := sw.addLocked(as, so.Cookie.Family(), so.Cookie.Type(), so.Cookie.Protocol()) + sw.stats.getLocked(nso.Cookie).Accepted++ + return nil +} From 92b74d0940cd46e3a480137844d9d61986f7d895 Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Fri, 19 Feb 2016 17:45:22 +0900 Subject: [PATCH 073/117] net: add missing aborted connection handling on accept test This change adds TestAcceptIgnoreAbortedConnRequest to test accepting aborted connection requests on all supported platforms except Plan 9. Change-Id: I5936b04085184ff348539962289b1167ec4ac619 Reviewed-on: https://go-review.googlesource.com/19707 Reviewed-by: Ian Lance Taylor Run-TryBot: Mikio Hara TryBot-Result: Gobot Gobot --- src/net/error_plan9_test.go | 2 ++ src/net/error_posix_test.go | 10 ------- src/net/error_unix_test.go | 21 +++++++++++++ src/net/error_windows_test.go | 19 ++++++++++++ src/net/fd_windows.go | 2 +- src/net/hook_windows.go | 11 +++---- src/net/main_windows_test.go | 3 ++ src/net/net_test.go | 56 +++++++++++++++++++++++++++++++++++ 8 files changed, 108 insertions(+), 16 deletions(-) create mode 100644 src/net/error_unix_test.go create mode 100644 src/net/error_windows_test.go diff --git a/src/net/error_plan9_test.go b/src/net/error_plan9_test.go index 495ea96534..d7c7f1487f 100644 --- a/src/net/error_plan9_test.go +++ b/src/net/error_plan9_test.go @@ -9,6 +9,8 @@ import "syscall" var ( errTimedout = syscall.ETIMEDOUT errOpNotSupported = syscall.EPLAN9 + + abortedConnRequestErrors []error ) func isPlatformError(err error) bool { diff --git a/src/net/error_posix_test.go b/src/net/error_posix_test.go index 981cc837ba..b411a378df 100644 --- a/src/net/error_posix_test.go +++ b/src/net/error_posix_test.go @@ -12,16 +12,6 @@ import ( "testing" ) -var ( - errTimedout = syscall.ETIMEDOUT - errOpNotSupported = syscall.EOPNOTSUPP -) - -func isPlatformError(err error) bool { - _, ok := err.(syscall.Errno) - return ok -} - func TestSpuriousENOTAVAIL(t *testing.T) { for _, tt := range []struct { error diff --git a/src/net/error_unix_test.go b/src/net/error_unix_test.go new file mode 100644 index 0000000000..db66d0acf1 --- /dev/null +++ b/src/net/error_unix_test.go @@ -0,0 +1,21 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !plan9,!windows + +package net + +import "syscall" + +var ( + errTimedout = syscall.ETIMEDOUT + errOpNotSupported = syscall.EOPNOTSUPP + + abortedConnRequestErrors = []error{syscall.ECONNABORTED} // see accept in fd_unix.go +) + +func isPlatformError(err error) bool { + _, ok := err.(syscall.Errno) + return ok +} diff --git a/src/net/error_windows_test.go b/src/net/error_windows_test.go new file mode 100644 index 0000000000..834a9de441 --- /dev/null +++ b/src/net/error_windows_test.go @@ -0,0 +1,19 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import "syscall" + +var ( + errTimedout = syscall.ETIMEDOUT + errOpNotSupported = syscall.EOPNOTSUPP + + abortedConnRequestErrors = []error{syscall.ERROR_NETNAME_DELETED, syscall.WSAECONNRESET} // see accept in fd_windows.go +) + +func isPlatformError(err error) bool { + _, ok := err.(syscall.Errno) + return ok +} diff --git a/src/net/fd_windows.go b/src/net/fd_windows.go index fd50d772d6..abdee9d02c 100644 --- a/src/net/fd_windows.go +++ b/src/net/fd_windows.go @@ -579,7 +579,7 @@ func (fd *netFD) acceptOne(rawsa []syscall.RawSockaddrAny, o *operation) (*netFD o.handle = s o.rsan = int32(unsafe.Sizeof(rawsa[0])) _, err = rsrv.ExecIO(o, "AcceptEx", func(o *operation) error { - return syscall.AcceptEx(o.fd.sysfd, o.handle, (*byte)(unsafe.Pointer(&rawsa[0])), 0, uint32(o.rsan), uint32(o.rsan), &o.qty, &o.o) + return acceptFunc(o.fd.sysfd, o.handle, (*byte)(unsafe.Pointer(&rawsa[0])), 0, uint32(o.rsan), uint32(o.rsan), &o.qty, &o.o) }) if err != nil { netfd.Close() diff --git a/src/net/hook_windows.go b/src/net/hook_windows.go index 126b0ebdd1..63ea35ab8c 100644 --- a/src/net/hook_windows.go +++ b/src/net/hook_windows.go @@ -13,9 +13,10 @@ var ( testHookDialChannel = func() { time.Sleep(time.Millisecond) } // see golang.org/issue/5349 // Placeholders for socket system calls. - socketFunc func(int, int, int) (syscall.Handle, error) = syscall.Socket - closeFunc func(syscall.Handle) error = syscall.Closesocket - connectFunc func(syscall.Handle, syscall.Sockaddr) error = syscall.Connect - connectExFunc func(syscall.Handle, syscall.Sockaddr, *byte, uint32, *uint32, *syscall.Overlapped) error = syscall.ConnectEx - listenFunc func(syscall.Handle, int) error = syscall.Listen + socketFunc func(int, int, int) (syscall.Handle, error) = syscall.Socket + closeFunc func(syscall.Handle) error = syscall.Closesocket + connectFunc func(syscall.Handle, syscall.Sockaddr) error = syscall.Connect + connectExFunc func(syscall.Handle, syscall.Sockaddr, *byte, uint32, *uint32, *syscall.Overlapped) error = syscall.ConnectEx + listenFunc func(syscall.Handle, int) error = syscall.Listen + acceptFunc func(syscall.Handle, syscall.Handle, *byte, uint32, uint32, uint32, *uint32, *syscall.Overlapped) error = syscall.AcceptEx ) diff --git a/src/net/main_windows_test.go b/src/net/main_windows_test.go index 2d829743ec..b879717425 100644 --- a/src/net/main_windows_test.go +++ b/src/net/main_windows_test.go @@ -11,6 +11,7 @@ var ( origConnect = connectFunc origConnectEx = connectExFunc origListen = listenFunc + origAccept = acceptFunc ) func installTestHooks() { @@ -19,6 +20,7 @@ func installTestHooks() { connectFunc = sw.Connect connectExFunc = sw.ConnectEx listenFunc = sw.Listen + acceptFunc = sw.AcceptEx } func uninstallTestHooks() { @@ -27,6 +29,7 @@ func uninstallTestHooks() { connectFunc = origConnect connectExFunc = origConnectEx listenFunc = origListen + acceptFunc = origAccept } func forceCloseSockets() { diff --git a/src/net/net_test.go b/src/net/net_test.go index cd62b4373e..94392928c2 100644 --- a/src/net/net_test.go +++ b/src/net/net_test.go @@ -6,6 +6,7 @@ package net import ( "io" + "net/internal/socktest" "os" "runtime" "testing" @@ -304,3 +305,58 @@ func TestListenCloseListen(t *testing.T) { } t.Fatalf("failed to listen/close/listen on same address after %d tries", maxTries) } + +// See golang.org/issue/6163, golang.org/issue/6987. +func TestAcceptIgnoreAbortedConnRequest(t *testing.T) { + switch runtime.GOOS { + case "plan9": + t.Skipf("%s does not have full support of socktest", runtime.GOOS) + } + + syserr := make(chan error) + go func() { + defer close(syserr) + for _, err := range abortedConnRequestErrors { + syserr <- err + } + }() + sw.Set(socktest.FilterAccept, func(so *socktest.Status) (socktest.AfterFilter, error) { + if err, ok := <-syserr; ok { + return nil, err + } + return nil, nil + }) + defer sw.Set(socktest.FilterAccept, nil) + + operr := make(chan error, 1) + handler := func(ls *localServer, ln Listener) { + defer close(operr) + c, err := ln.Accept() + if err != nil { + if perr := parseAcceptError(err); perr != nil { + operr <- perr + } + operr <- err + return + } + c.Close() + } + ls, err := newLocalServer("tcp") + if err != nil { + t.Fatal(err) + } + defer ls.teardown() + if err := ls.buildup(handler); err != nil { + t.Fatal(err) + } + + c, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String()) + if err != nil { + t.Fatal(err) + } + c.Close() + + for err := range operr { + t.Error(err) + } +} From de6a5881bbf85113186d9cfdbe51fd3165ba7e4c Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Thu, 2 Jul 2015 17:56:13 -0700 Subject: [PATCH 074/117] bytes: make Buffer comment more accurate Change-Id: Ief22b3dbba9616dd40bf3ea8e2633d3c5e7d1886 Reviewed-on: https://go-review.googlesource.com/19761 Reviewed-by: Brad Fitzpatrick --- src/bytes/buffer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bytes/buffer.go b/src/bytes/buffer.go index ddaba3bff3..f135b46959 100644 --- a/src/bytes/buffer.go +++ b/src/bytes/buffer.go @@ -17,7 +17,7 @@ import ( type Buffer struct { buf []byte // contents are the bytes buf[off : len(buf)] off int // read at &buf[off], write at &buf[len(buf)] - runeBytes [utf8.UTFMax]byte // avoid allocation of slice on each WriteByte or Rune + runeBytes [utf8.UTFMax]byte // avoid allocation of slice on each call to WriteRune bootstrap [64]byte // memory to hold first slice; helps small buffers (Printf) avoid allocation. lastRead readOp // last read operation, so that Unread* can work correctly. } From 1dbba1a2b7c5d04bc7ad560010a887b441feb0f4 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Mon, 4 May 2015 14:56:52 -0700 Subject: [PATCH 075/117] encoding/hex: minor cleanup Change-Id: I404fd946dd0607fa41e2abe0d1d8081d4433ff0a Reviewed-on: https://go-review.googlesource.com/19762 Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/encoding/hex/hex.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/encoding/hex/hex.go b/src/encoding/hex/hex.go index d1fc7024a9..a51b1db61c 100644 --- a/src/encoding/hex/hex.go +++ b/src/encoding/hex/hex.go @@ -105,7 +105,7 @@ func Dump(data []byte) string { dumper := Dumper(&buf) dumper.Write(data) dumper.Close() - return string(buf.Bytes()) + return buf.String() } // Dumper returns a WriteCloser that writes a hex dump of all written data to From 5fc43c94bf3ba6158d970488bff715e60f37e33f Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Tue, 26 May 2015 15:41:42 -0700 Subject: [PATCH 076/117] net/url: simplify value lookup Change-Id: Ic998c189003d4dee758fca3b5ac954d5b54d3d36 Reviewed-on: https://go-review.googlesource.com/19764 Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/net/url/url.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/net/url/url.go b/src/net/url/url.go index b7e25ecfcb..b3513a85a3 100644 --- a/src/net/url/url.go +++ b/src/net/url/url.go @@ -709,8 +709,8 @@ func (v Values) Get(key string) string { if v == nil { return "" } - vs, ok := v[key] - if !ok || len(vs) == 0 { + vs := v[key] + if len(vs) == 0 { return "" } return vs[0] From 5621b09dadca86202e3c921b3a1e323ec60b2742 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 19 Feb 2016 23:01:10 -0800 Subject: [PATCH 077/117] cmd/compile: simplify import path handling Change-Id: I64c9b4c4978520a9bc989b7fd7d5708d364dc88a Reviewed-on: https://go-review.googlesource.com/19755 Run-TryBot: Matthew Dempsky TryBot-Result: Gobot Gobot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/gc/go.go | 7 ------- src/cmd/compile/internal/gc/lex.go | 19 +++++++------------ 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go index 13a28c8720..9b55eb8848 100644 --- a/src/cmd/compile/internal/gc/go.go +++ b/src/cmd/compile/internal/gc/go.go @@ -397,11 +397,6 @@ type Dlist struct { field *Type } -type Idir struct { - link *Idir - dir string -} - // argument passing to/from // smagic and umagic type Magic struct { @@ -519,8 +514,6 @@ var Tptr EType // either TPTR32 or TPTR64 var myimportpath string -var idirs *Idir - var localimport string var asmhdr string diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go index 66cc01862d..08545df953 100644 --- a/src/cmd/compile/internal/gc/lex.go +++ b/src/cmd/compile/internal/gc/lex.go @@ -561,17 +561,12 @@ func skiptopkgdef(b *obj.Biobuf) bool { return true } -func addidir(dir string) { - if dir == "" { - return - } +var idirs []string - var pp **Idir - for pp = &idirs; *pp != nil; pp = &(*pp).link { +func addidir(dir string) { + if dir != "" { + idirs = append(idirs, dir) } - *pp = new(Idir) - (*pp).link = nil - (*pp).dir = dir } // is this path a local name? begins with ./ or ../ or / @@ -610,12 +605,12 @@ func findpkg(name string) (file string, ok bool) { return "", false } - for p := idirs; p != nil; p = p.link { - file = fmt.Sprintf("%s/%s.a", p.dir, name) + for _, dir := range idirs { + file = fmt.Sprintf("%s/%s.a", dir, name) if _, err := os.Stat(file); err == nil { return file, true } - file = fmt.Sprintf("%s/%s.o", p.dir, name) + file = fmt.Sprintf("%s/%s.o", dir, name) if _, err := os.Stat(file); err == nil { return file, true } From 11e51ed4bc3d901c4272ba57bde4771bb7d8f6f6 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Sat, 20 Feb 2016 11:06:35 -0800 Subject: [PATCH 078/117] cmd/compile: remove gratuituous copying of lexer token data Rename yySymType to lexer; should eventually capture all lexer state. Embed lexer in parser and access lexer token data directly. Change-Id: I246194705d594f80426f3ba77d8580af9185daf7 Reviewed-on: https://go-review.googlesource.com/19759 Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/gc/lex.go | 29 ++++++++++++++++----------- src/cmd/compile/internal/gc/parser.go | 19 ++++-------------- 2 files changed, 21 insertions(+), 27 deletions(-) diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go index 08545df953..a6f65bec62 100644 --- a/src/cmd/compile/internal/gc/lex.go +++ b/src/cmd/compile/internal/gc/lex.go @@ -866,10 +866,15 @@ func isfrog(c int) bool { return false } -type yySymType struct { - sym *Sym - val Val - op Op +type lexer struct { + // TODO(gri) move other lexer state here and out of global variables + // (source, current line number, etc.) + + // current token + tok int32 + sym_ *Sym // valid if tok == LNAME + val Val // valid if tok == LLITERAL + op Op // valid if tok == LASOP } const ( @@ -920,7 +925,7 @@ const ( LRSH ) -func _yylex(yylval *yySymType) int32 { +func (yylval *lexer) _yylex() int32 { var c1 int var op Op var escflag int @@ -1402,7 +1407,7 @@ talph: if Debug['x'] != 0 { fmt.Printf("lex: %s %s\n", s, lexname(int(s.Lexical))) } - yylval.sym = s + yylval.sym_ = s return int32(s.Lexical) ncu: @@ -1828,16 +1833,16 @@ func pragcgo(text string) { } } -func yylex(yylval *yySymType) int32 { - lx := _yylex(yylval) +func (l *lexer) next() { + tok := l._yylex() - if curio.nlsemi && lx == EOF { + if curio.nlsemi && tok == EOF { // Treat EOF as "end of line" for the purposes // of inserting a semicolon. - lx = ';' + tok = ';' } - switch lx { + switch tok { case LNAME, LLITERAL, LBREAK, @@ -1855,7 +1860,7 @@ func yylex(yylval *yySymType) int32 { curio.nlsemi = false } - return lx + l.tok = tok } func getc() int { diff --git a/src/cmd/compile/internal/gc/parser.go b/src/cmd/compile/internal/gc/parser.go index 3a5b508393..deae40c21b 100644 --- a/src/cmd/compile/internal/gc/parser.go +++ b/src/cmd/compile/internal/gc/parser.go @@ -42,21 +42,10 @@ func parse_file(bin *obj.Biobuf) { } type parser struct { - tok int32 // next token (one-token look-ahead) - op Op // valid if tok == LASOP - val Val // valid if tok == LLITERAL - sym_ *Sym // valid if tok == LNAME - fnest int // function nesting level (for error handling) - xnest int // expression nesting level (for complit ambiguity resolution) - yy yySymType // for temporary use by next - indent []byte // tracing support -} - -func (p *parser) next() { - p.tok = yylex(&p.yy) - p.op = p.yy.op - p.val = p.yy.val - p.sym_ = p.yy.sym + lexer + fnest int // function nesting level (for error handling) + xnest int // expression nesting level (for complit ambiguity resolution) + indent []byte // tracing support } func (p *parser) got(tok int32) bool { From 20ee67acc920807d19d336b1cc1614d2ad529953 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Sat, 20 Feb 2016 11:16:21 -0800 Subject: [PATCH 079/117] cmd/compile: test for lower-case letters first in isAlpha Lower-case letters are more common in identifiers. Change-Id: I49c39e3ac810eea57d15c1433608daec212c9792 Reviewed-on: https://go-review.googlesource.com/19760 Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/gc/lex.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go index a6f65bec62..55d988b70a 100644 --- a/src/cmd/compile/internal/gc/lex.go +++ b/src/cmd/compile/internal/gc/lex.go @@ -832,7 +832,7 @@ func isSpace(c int) bool { } func isAlpha(c int) bool { - return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' + return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' } func isDigit(c int) bool { From aa5b44aeabccd25a320d6ea609c41781bdbf5ce0 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Sat, 20 Feb 2016 12:53:34 -0800 Subject: [PATCH 080/117] cmd/compile: set lexer nlsemi state directly The old code used an extra function call and switch to inspect the current token and determine the new state of curio.nlsemi. However, the lexer knows the token w/o the need of an extra test and thus can set curio.nlsemi directly: - removed need for extra function call in next - renamed _yylex to next - set nlsemi at the point a token is identified - moved nlsemi from curio to lexer - it's really part of the lexer state This change makes the lexer call sequence less convoluted and should also speed up the lexing a bit. Change-Id: Iaf2683081f04231cb62c94e1400d455f98f6f82a Reviewed-on: https://go-review.googlesource.com/19765 Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/gc/go.go | 1 - src/cmd/compile/internal/gc/lex.go | 135 +++++++++++++++-------------- 2 files changed, 71 insertions(+), 65 deletions(-) diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go index 9b55eb8848..d21b2fb196 100644 --- a/src/cmd/compile/internal/gc/go.go +++ b/src/cmd/compile/internal/gc/go.go @@ -389,7 +389,6 @@ type Io struct { last int peekc int peekc1 int // second peekc for ... - nlsemi bool eofnl bool } diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go index 55d988b70a..54c69c5449 100644 --- a/src/cmd/compile/internal/gc/lex.go +++ b/src/cmd/compile/internal/gc/lex.go @@ -869,6 +869,7 @@ func isfrog(c int) bool { type lexer struct { // TODO(gri) move other lexer state here and out of global variables // (source, current line number, etc.) + nlsemi bool // if set, '\n' and EOF translate to ';' // current token tok int32 @@ -925,7 +926,7 @@ const ( LRSH ) -func (yylval *lexer) _yylex() int32 { +func (l *lexer) next() { var c1 int var op Op var escflag int @@ -936,27 +937,31 @@ func (yylval *lexer) _yylex() int32 { prevlineno = lineno + nlsemi := l.nlsemi + l.nlsemi = false + l0: + // skip white space c := getc() - if isSpace(c) { - if c == '\n' && curio.nlsemi { + for isSpace(c) { + if c == '\n' && nlsemi { ungetc(c) if Debug['x'] != 0 { fmt.Printf("lex: implicit semi\n") } - return ';' + l.tok = ';' + return } - - goto l0 + c = getc() } - lineno = lexlineno // start of token + // start of token + lineno = lexlineno if c >= utf8.RuneSelf { // all multibyte runes are alpha cp = &lexbuf cp.Reset() - goto talph } @@ -1049,7 +1054,17 @@ l0: case EOF: lineno = prevlineno ungetc(EOF) - return -1 + // Treat EOF as "end of line" for the purposes + // of inserting a semicolon. + if nlsemi { + if Debug['x'] != 0 { + fmt.Printf("lex: implicit semi\n") + } + l.tok = ';' + return + } + l.tok = -1 + return case '_': cp = &lexbuf @@ -1137,14 +1152,16 @@ l0: } x := new(Mpint) - yylval.val.U = x + l.val.U = x Mpmovecfix(x, v) x.Rune = true if Debug['x'] != 0 { fmt.Printf("lex: codepoint literal\n") } litbuf = "string literal" - return LLITERAL + l.nlsemi = true + l.tok = LLITERAL + return case '/': c1 = getc() @@ -1217,6 +1234,7 @@ l0: case '+': c1 = getc() if c1 == '+' { + l.nlsemi = true c = int(LINC) goto lx } @@ -1229,6 +1247,7 @@ l0: case '-': c1 = getc() if c1 == '-' { + l.nlsemi = true c = int(LDEC) goto lx } @@ -1339,6 +1358,10 @@ l0: goto asop } + case ')', ']', '}': + l.nlsemi = true + goto lx + default: goto lx } @@ -1363,14 +1386,16 @@ lx: goto l0 } - return int32(c) + l.tok = int32(c) + return asop: - yylval.op = op + l.op = op if Debug['x'] != 0 { fmt.Printf("lex: TOKEN ASOP %s=\n", goopnames[op]) } - return LASOP + l.tok = LASOP + return // cp is set to lexbuf and some // prefix has been stored @@ -1407,26 +1432,33 @@ talph: if Debug['x'] != 0 { fmt.Printf("lex: %s %s\n", s, lexname(int(s.Lexical))) } - yylval.sym_ = s - return int32(s.Lexical) + l.sym_ = s + switch s.Lexical { + case LNAME, LRETURN, LBREAK, LCONTINUE, LFALL: + l.nlsemi = true + } + l.tok = int32(s.Lexical) + return ncu: cp = nil ungetc(c) str = lexbuf.String() - yylval.val.U = new(Mpint) - mpatofix(yylval.val.U.(*Mpint), str) - if yylval.val.U.(*Mpint).Ovf { + l.val.U = new(Mpint) + mpatofix(l.val.U.(*Mpint), str) + if l.val.U.(*Mpint).Ovf { Yyerror("overflow in constant") - Mpmovecfix(yylval.val.U.(*Mpint), 0) + Mpmovecfix(l.val.U.(*Mpint), 0) } if Debug['x'] != 0 { fmt.Printf("lex: integer literal\n") } litbuf = "literal " + str - return LLITERAL + l.nlsemi = true + l.tok = LLITERAL + return casedot: for { @@ -1475,45 +1507,50 @@ casei: cp = nil str = lexbuf.String() - yylval.val.U = new(Mpcplx) - Mpmovecflt(&yylval.val.U.(*Mpcplx).Real, 0.0) - mpatoflt(&yylval.val.U.(*Mpcplx).Imag, str) - if yylval.val.U.(*Mpcplx).Imag.Val.IsInf() { + l.val.U = new(Mpcplx) + Mpmovecflt(&l.val.U.(*Mpcplx).Real, 0.0) + mpatoflt(&l.val.U.(*Mpcplx).Imag, str) + if l.val.U.(*Mpcplx).Imag.Val.IsInf() { Yyerror("overflow in imaginary constant") - Mpmovecflt(&yylval.val.U.(*Mpcplx).Imag, 0.0) + Mpmovecflt(&l.val.U.(*Mpcplx).Imag, 0.0) } if Debug['x'] != 0 { fmt.Printf("lex: imaginary literal\n") } litbuf = "literal " + str - return LLITERAL + l.nlsemi = true + l.tok = LLITERAL + return caseout: cp = nil ungetc(c) str = lexbuf.String() - yylval.val.U = newMpflt() - mpatoflt(yylval.val.U.(*Mpflt), str) - if yylval.val.U.(*Mpflt).Val.IsInf() { + l.val.U = newMpflt() + mpatoflt(l.val.U.(*Mpflt), str) + if l.val.U.(*Mpflt).Val.IsInf() { Yyerror("overflow in float constant") - Mpmovecflt(yylval.val.U.(*Mpflt), 0.0) + Mpmovecflt(l.val.U.(*Mpflt), 0.0) } if Debug['x'] != 0 { fmt.Printf("lex: floating literal\n") } litbuf = "literal " + str - return LLITERAL + l.nlsemi = true + l.tok = LLITERAL + return strlit: - yylval.val.U = internString(cp.Bytes()) + l.val.U = internString(cp.Bytes()) if Debug['x'] != 0 { fmt.Printf("lex: string literal\n") } litbuf = "string literal" - return LLITERAL + l.nlsemi = true + l.tok = LLITERAL } var internedStrings = map[string]string{} @@ -1833,36 +1870,6 @@ func pragcgo(text string) { } } -func (l *lexer) next() { - tok := l._yylex() - - if curio.nlsemi && tok == EOF { - // Treat EOF as "end of line" for the purposes - // of inserting a semicolon. - tok = ';' - } - - switch tok { - case LNAME, - LLITERAL, - LBREAK, - LCONTINUE, - LFALL, - LRETURN, - LINC, - LDEC, - ')', - '}', - ']': - curio.nlsemi = true - - default: - curio.nlsemi = false - } - - l.tok = tok -} - func getc() int { c := curio.peekc if c != 0 { From 5dc053b9dec4dc25fac195065ad32462ac28a543 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Mo=CC=88hrmann?= Date: Sun, 21 Feb 2016 10:46:59 +0100 Subject: [PATCH 081/117] fmt: fix zero padding for NaN Makes zero padding of NaN and infinities consistent by using spaces instead of zeroes to pad NaN. Adds more tests for NaN formatting. Fixes #14421 Change-Id: Ia20f8e878cc81ac72a744ec10d65e84b94e09c6a Reviewed-on: https://go-review.googlesource.com/19723 Reviewed-by: Rob Pike --- src/fmt/fmt_test.go | 11 ++++++++++- src/fmt/format.go | 8 ++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/fmt/fmt_test.go b/src/fmt/fmt_test.go index 8d7c36ceb1..1d9d015f4a 100644 --- a/src/fmt/fmt_test.go +++ b/src/fmt/fmt_test.go @@ -386,6 +386,9 @@ var fmtTests = []struct { {"%20e", math.Inf(1), " +Inf"}, {"%-20f", math.Inf(-1), "-Inf "}, {"%20g", math.NaN(), " NaN"}, + {"%+20f", math.NaN(), " +NaN"}, + {"% -20f", math.NaN(), " NaN "}, + {"%+-20f", math.NaN(), "+NaN "}, // arrays {"%v", array, "[1 2 3 4 5]"}, @@ -654,13 +657,19 @@ var fmtTests = []struct { // Complex numbers: exhaustively tested in TestComplexFormatting. {"%7.2f", 1 + 2i, "( 1.00 +2.00i)"}, {"%+07.2f", -1 - 2i, "(-001.00-002.00i)"}, - // Zero padding does not apply to infinities. + // Zero padding does not apply to infinities and NaN. {"%020f", math.Inf(-1), " -Inf"}, {"%020f", math.Inf(+1), " +Inf"}, + {"%020f", math.NaN(), " NaN"}, {"% 020f", math.Inf(-1), " -Inf"}, {"% 020f", math.Inf(+1), " Inf"}, + {"% 020f", math.NaN(), " NaN"}, {"%+020f", math.Inf(-1), " -Inf"}, {"%+020f", math.Inf(+1), " +Inf"}, + {"%+020f", math.NaN(), " +NaN"}, + {"%-020f", math.Inf(-1), "-Inf "}, + {"%-020f", math.Inf(+1), "+Inf "}, + {"%-020f", math.NaN(), "NaN "}, {"%20f", -1.0, " -1.000000"}, // Make sure we can handle very large widths. {"%0100f", -1.0, zeroFill("-", 99, "1.000000")}, diff --git a/src/fmt/format.go b/src/fmt/format.go index bf9d00bbc0..c811cc6a3d 100644 --- a/src/fmt/format.go +++ b/src/fmt/format.go @@ -414,11 +414,15 @@ func (f *fmt) formatFloat(v float64, verb byte, prec, n int) { if f.space && num[0] == '+' { num[0] = ' ' } - // Special handling for "+Inf" and "-Inf", + // Special handling for infinities and NaN, // which don't look like a number so shouldn't be padded with zeros. - if num[1] == 'I' { + if num[1] == 'I' || num[1] == 'N' { oldZero := f.zero f.zero = false + // Remove sign before NaN if not asked for. + if num[1] == 'N' && !f.space && !f.plus { + num = num[1:] + } f.pad(num) f.zero = oldZero return From e43c74a0d8848d58814e1a8302d8f115d7f0b874 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Wed, 27 Jan 2016 12:49:13 -0800 Subject: [PATCH 082/117] all: use cannot instead of can not You can not use cannot, but you cannot spell cannot can not. Change-Id: I2f0971481a460804de96fd8c9e46a9cc62a3fc5b Reviewed-on: https://go-review.googlesource.com/19772 Reviewed-by: Rob Pike --- src/archive/zip/writer.go | 2 +- src/cmd/cgo/doc.go | 2 +- src/cmd/cgo/gcc.go | 4 ++-- src/cmd/compile/internal/gc/lex.go | 2 +- src/cmd/go/go_test.go | 2 +- src/database/sql/sql.go | 2 +- src/log/syslog/syslog.go | 2 +- src/net/http/server.go | 2 +- src/net/http/transport.go | 2 +- src/os/signal/doc.go | 2 +- src/runtime/cgocall.go | 2 +- src/runtime/mbarrier.go | 2 +- src/runtime/mfixalloc.go | 4 ++-- src/runtime/mstats.go | 4 ++-- src/runtime/norace_linux_test.go | 2 +- src/runtime/norace_test.go | 2 +- src/runtime/os1_darwin.go | 2 +- src/runtime/os1_dragonfly.go | 2 +- src/runtime/os1_freebsd.go | 2 +- src/runtime/os1_linux.go | 2 +- src/runtime/os1_nacl.go | 2 +- src/runtime/os1_netbsd.go | 2 +- src/runtime/os1_plan9.go | 2 +- src/runtime/os1_windows.go | 2 +- src/runtime/os3_solaris.go | 2 +- src/runtime/sys_darwin_arm.s | 2 +- src/runtime/sys_darwin_arm64.s | 2 +- src/runtime/vdso_linux_amd64.go | 2 +- src/sync/pool.go | 2 +- 29 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/archive/zip/writer.go b/src/archive/zip/writer.go index 5ce66e6be5..3a9292e380 100644 --- a/src/archive/zip/writer.go +++ b/src/archive/zip/writer.go @@ -52,7 +52,7 @@ func (w *Writer) Flush() error { } // Close finishes writing the zip file by writing the central directory. -// It does not (and can not) close the underlying writer. +// It does not (and cannot) close the underlying writer. func (w *Writer) Close() error { if w.last != nil && !w.last.closed { if err := w.last.close(); err != nil { diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go index 8b4e2bfd58..90c2584c7f 100644 --- a/src/cmd/cgo/doc.go +++ b/src/cmd/cgo/doc.go @@ -133,7 +133,7 @@ C's union types are represented as a Go byte array with the same length. Go structs cannot embed fields with C types. -Go code can not refer to zero-sized fields that occur at the end of +Go code cannot refer to zero-sized fields that occur at the end of non-empty C structs. To get the address of such a field (which is the only operation you can do with a zero-sized field) you must take the address of the struct and add the size of the struct. diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index fb5049c1a1..5bfdef785c 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -432,7 +432,7 @@ func (p *Package) loadDWARF(f *File, names []*Name) { fmt.Fprintf(&b, "\t0,\n") } } - // for the last entry, we can not use 0, otherwise + // for the last entry, we cannot use 0, otherwise // in case all __cgodebug_data is zero initialized, // LLVM-based gcc will place the it in the __DATA.__common // zero-filled section (our debug/macho doesn't support @@ -2025,7 +2025,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct // We can't permit that, because then the size of the Go // struct will not be the same as the size of the C struct. // Our only option in such a case is to remove the field, - // which means that it can not be referenced from Go. + // which means that it cannot be referenced from Go. for off > 0 && sizes[len(sizes)-1] == 0 { n := len(sizes) fld = fld[0 : n-1] diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go index 54c69c5449..0f8b20cea0 100644 --- a/src/cmd/compile/internal/gc/lex.go +++ b/src/cmd/compile/internal/gc/lex.go @@ -255,7 +255,7 @@ func Main() { msanpkg.Name = "msan" } if flag_race != 0 && flag_msan != 0 { - log.Fatal("can not use both -race and -msan") + log.Fatal("cannot use both -race and -msan") } else if flag_race != 0 || flag_msan != 0 { instrumenting = true } diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index ae426088ea..51931769d5 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -2337,7 +2337,7 @@ func TestGoGetHTTPS404(t *testing.T) { tg.run("get", "bazil.org/fuse/fs/fstestutil") } -// Test that you can not import a main package. +// Test that you cannot import a main package. func TestIssue4210(t *testing.T) { tg := testgo(t) defer tg.cleanup() diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go index d8e7cb77af..28c36160b5 100644 --- a/src/database/sql/sql.go +++ b/src/database/sql/sql.go @@ -199,7 +199,7 @@ type Scanner interface { // time.Time // nil - for NULL values // - // An error should be returned if the value can not be stored + // An error should be returned if the value cannot be stored // without loss of information. Scan(src interface{}) error } diff --git a/src/log/syslog/syslog.go b/src/log/syslog/syslog.go index 4bf447626f..0e342242ec 100644 --- a/src/log/syslog/syslog.go +++ b/src/log/syslog/syslog.go @@ -85,7 +85,7 @@ type Writer struct { } // This interface and the separate syslog_unix.go file exist for -// Solaris support as implemented by gccgo. On Solaris you can not +// Solaris support as implemented by gccgo. On Solaris you cannot // simply open a TCP connection to the syslog daemon. The gccgo // sources have a syslog_solaris.go file that implements unixSyslog to // return a type that satisfies this interface and simply calls the C diff --git a/src/net/http/server.go b/src/net/http/server.go index 5e3b6084ae..1b5cda3159 100644 --- a/src/net/http/server.go +++ b/src/net/http/server.go @@ -2032,7 +2032,7 @@ const ( // For HTTP/2, StateActive fires on the transition from zero // to one active request, and only transitions away once all // active requests are complete. That means that ConnState - // can not be used to do per-request work; ConnState only notes + // cannot be used to do per-request work; ConnState only notes // the overall state of the connection. StateActive diff --git a/src/net/http/transport.go b/src/net/http/transport.go index 1e3ea11d9c..feedb3420d 100644 --- a/src/net/http/transport.go +++ b/src/net/http/transport.go @@ -418,7 +418,7 @@ func (t *Transport) CloseIdleConnections() { // CancelRequest cancels an in-flight request by closing its connection. // CancelRequest should only be called after RoundTrip has returned. // -// Deprecated: Use Request.Cancel instead. CancelRequest can not cancel +// Deprecated: Use Request.Cancel instead. CancelRequest cannot cancel // HTTP/2 requests. func (t *Transport) CancelRequest(req *Request) { t.reqMu.Lock() diff --git a/src/os/signal/doc.go b/src/os/signal/doc.go index 80e66cffe5..9ee547b15d 100644 --- a/src/os/signal/doc.go +++ b/src/os/signal/doc.go @@ -11,7 +11,7 @@ package on Windows and Plan 9, see below. Types of signals The signals SIGKILL and SIGSTOP may not be caught by a program, and -therefore can not be affected by this package. +therefore cannot be affected by this package. Synchronous signals are signals triggered by errors in program execution: SIGBUS, SIGFPE, and SIGSEGV. These are only considered diff --git a/src/runtime/cgocall.go b/src/runtime/cgocall.go index fef8add46f..f632f7ab5a 100644 --- a/src/runtime/cgocall.go +++ b/src/runtime/cgocall.go @@ -340,7 +340,7 @@ var racecgosync uint64 // represents possible synchronization in C code // When and if we implement a moving garbage collector, // cgoCheckPointer will pin the pointer for the duration of the cgo // call. (This is necessary but not sufficient; the cgo program will -// also have to change to pin Go pointers that can not point to Go +// also have to change to pin Go pointers that cannot point to Go // pointers.) // cgoCheckPointer checks if the argument contains a Go pointer that diff --git a/src/runtime/mbarrier.go b/src/runtime/mbarrier.go index 45086c43cd..1204e8143e 100644 --- a/src/runtime/mbarrier.go +++ b/src/runtime/mbarrier.go @@ -100,7 +100,7 @@ func gcmarkwb_m(slot *uintptr, ptr uintptr) { // related operations. In particular there are times when the GC assumes // that the world is stopped but scheduler related code is still being // executed, dealing with syscalls, dealing with putting gs on runnable -// queues and so forth. This code can not execute write barriers because +// queues and so forth. This code cannot execute write barriers because // the GC might drop them on the floor. Stopping the world involves removing // the p associated with an m. We use the fact that m.p == nil to indicate // that we are in one these critical section and throw if the write is of diff --git a/src/runtime/mfixalloc.go b/src/runtime/mfixalloc.go index 8653a6a99f..569a304cf4 100644 --- a/src/runtime/mfixalloc.go +++ b/src/runtime/mfixalloc.go @@ -30,8 +30,8 @@ type fixalloc struct { } // A generic linked list of blocks. (Typically the block is bigger than sizeof(MLink).) -// Since assignments to mlink.next will result in a write barrier being preformed -// this can not be used by some of the internal GC structures. For example when +// Since assignments to mlink.next will result in a write barrier being performed +// this cannot be used by some of the internal GC structures. For example when // the sweeper is placing an unmarked object on the free list it does not want the // write barrier to be called since that could result in the object being reachable. type mlink struct { diff --git a/src/runtime/mstats.go b/src/runtime/mstats.go index 368687d006..8ae636077b 100644 --- a/src/runtime/mstats.go +++ b/src/runtime/mstats.go @@ -165,7 +165,7 @@ type MemStats struct { // Size of the trailing by_size array differs between Go and C, // and all data after by_size is local to runtime, not exported. -// NumSizeClasses was changed, but we can not change Go struct because of backward compatibility. +// NumSizeClasses was changed, but we cannot change Go struct because of backward compatibility. // sizeof_C_MStats is what C thinks about size of Go struct. var sizeof_C_MStats = unsafe.Offsetof(memstats.by_size) + 61*unsafe.Sizeof(memstats.by_size[0]) @@ -192,7 +192,7 @@ func readmemstats_m(stats *MemStats) { updatememstats(nil) // Size of the trailing by_size array differs between Go and C, - // NumSizeClasses was changed, but we can not change Go struct because of backward compatibility. + // NumSizeClasses was changed, but we cannot change Go struct because of backward compatibility. memmove(unsafe.Pointer(stats), unsafe.Pointer(&memstats), sizeof_C_MStats) // Stack numbers are part of the heap numbers, separate those out for user consumption diff --git a/src/runtime/norace_linux_test.go b/src/runtime/norace_linux_test.go index bbf9d0b413..049801d3fc 100644 --- a/src/runtime/norace_linux_test.go +++ b/src/runtime/norace_linux_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// The file contains tests that can not run under race detector for some reason. +// The file contains tests that cannot run under race detector for some reason. // +build !race package runtime_test diff --git a/src/runtime/norace_test.go b/src/runtime/norace_test.go index 3681bf190d..e9b39b2f45 100644 --- a/src/runtime/norace_test.go +++ b/src/runtime/norace_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// The file contains tests that can not run under race detector for some reason. +// The file contains tests that cannot run under race detector for some reason. // +build !race package runtime_test diff --git a/src/runtime/os1_darwin.go b/src/runtime/os1_darwin.go index 5c00407b2f..19bb0f16e0 100644 --- a/src/runtime/os1_darwin.go +++ b/src/runtime/os1_darwin.go @@ -157,7 +157,7 @@ func sigblock() { } // Called to initialize a new m (including the bootstrap m). -// Called on the new thread, can not allocate memory. +// Called on the new thread, cannot allocate memory. func minit() { // Initialize signal handling. _g_ := getg() diff --git a/src/runtime/os1_dragonfly.go b/src/runtime/os1_dragonfly.go index bf3e1ccb83..7e4f84e6a3 100644 --- a/src/runtime/os1_dragonfly.go +++ b/src/runtime/os1_dragonfly.go @@ -133,7 +133,7 @@ func sigblock() { } // Called to initialize a new m (including the bootstrap m). -// Called on the new thread, can not allocate memory. +// Called on the new thread, cannot allocate memory. func minit() { _g_ := getg() diff --git a/src/runtime/os1_freebsd.go b/src/runtime/os1_freebsd.go index 79d995476e..f00fdf4389 100644 --- a/src/runtime/os1_freebsd.go +++ b/src/runtime/os1_freebsd.go @@ -136,7 +136,7 @@ func sigblock() { } // Called to initialize a new m (including the bootstrap m). -// Called on the new thread, can not allocate memory. +// Called on the new thread, cannot allocate memory. func minit() { _g_ := getg() diff --git a/src/runtime/os1_linux.go b/src/runtime/os1_linux.go index b38cfc14f9..2d53b934f5 100644 --- a/src/runtime/os1_linux.go +++ b/src/runtime/os1_linux.go @@ -225,7 +225,7 @@ func sigblock() { func gettid() uint32 // Called to initialize a new m (including the bootstrap m). -// Called on the new thread, can not allocate memory. +// Called on the new thread, cannot allocate memory. func minit() { // Initialize signal handling. _g_ := getg() diff --git a/src/runtime/os1_nacl.go b/src/runtime/os1_nacl.go index dab205de6a..5526d906d8 100644 --- a/src/runtime/os1_nacl.go +++ b/src/runtime/os1_nacl.go @@ -30,7 +30,7 @@ func sigblock() { } // Called to initialize a new m (including the bootstrap m). -// Called on the new thread, can not allocate memory. +// Called on the new thread, cannot allocate memory. func minit() { _g_ := getg() diff --git a/src/runtime/os1_netbsd.go b/src/runtime/os1_netbsd.go index eab8eb8702..e32df9585c 100644 --- a/src/runtime/os1_netbsd.go +++ b/src/runtime/os1_netbsd.go @@ -167,7 +167,7 @@ func sigblock() { } // Called to initialize a new m (including the bootstrap m). -// Called on the new thread, can not allocate memory. +// Called on the new thread, cannot allocate memory. func minit() { _g_ := getg() _g_.m.procid = uint64(lwp_self()) diff --git a/src/runtime/os1_plan9.go b/src/runtime/os1_plan9.go index 7506d591df..9911077911 100644 --- a/src/runtime/os1_plan9.go +++ b/src/runtime/os1_plan9.go @@ -33,7 +33,7 @@ func sigblock() { } // Called to initialize a new m (including the bootstrap m). -// Called on the new thread, can not allocate memory. +// Called on the new thread, cannot allocate memory. func minit() { // Mask all SSE floating-point exceptions // when running on the 64-bit kernel. diff --git a/src/runtime/os1_windows.go b/src/runtime/os1_windows.go index a28e11e088..8d46bca36d 100644 --- a/src/runtime/os1_windows.go +++ b/src/runtime/os1_windows.go @@ -399,7 +399,7 @@ func sigblock() { } // Called to initialize a new m (including the bootstrap m). -// Called on the new thread, can not allocate memory. +// Called on the new thread, cannot allocate memory. func minit() { var thandle uintptr stdcall7(_DuplicateHandle, currentProcess, currentThread, currentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, _DUPLICATE_SAME_ACCESS) diff --git a/src/runtime/os3_solaris.go b/src/runtime/os3_solaris.go index 7ebb35c8e9..fdc817d3f7 100644 --- a/src/runtime/os3_solaris.go +++ b/src/runtime/os3_solaris.go @@ -208,7 +208,7 @@ func sigblock() { } // Called to initialize a new m (including the bootstrap m). -// Called on the new thread, can not allocate memory. +// Called on the new thread, cannot allocate memory. func minit() { _g_ := getg() asmcgocall(unsafe.Pointer(funcPC(miniterrno)), unsafe.Pointer(&libc____errno)) diff --git a/src/runtime/sys_darwin_arm.s b/src/runtime/sys_darwin_arm.s index 82a8db9914..6b6437dddd 100644 --- a/src/runtime/sys_darwin_arm.s +++ b/src/runtime/sys_darwin_arm.s @@ -261,7 +261,7 @@ cont: MOVW R1, 24(R6) // switch stack and g - MOVW R6, R13 // sigtramp can not re-entrant, so no need to back up R13. + MOVW R6, R13 // sigtramp is not re-entrant, so no need to back up R13. MOVW R5, g BL (R0) diff --git a/src/runtime/sys_darwin_arm64.s b/src/runtime/sys_darwin_arm64.s index d0034d5a33..a3b851d2fc 100644 --- a/src/runtime/sys_darwin_arm64.s +++ b/src/runtime/sys_darwin_arm64.s @@ -245,7 +245,7 @@ cont: MOVD R1, 48(R6) // switch stack and g - MOVD R6, RSP // sigtramp can not re-entrant, so no need to back up RSP. + MOVD R6, RSP // sigtramp is not re-entrant, so no need to back up RSP. MOVD R5, g BL (R0) diff --git a/src/runtime/vdso_linux_amd64.go b/src/runtime/vdso_linux_amd64.go index 38914bb2b9..42571e063c 100644 --- a/src/runtime/vdso_linux_amd64.go +++ b/src/runtime/vdso_linux_amd64.go @@ -263,7 +263,7 @@ func vdso_find_version(info *vdso_info, ver *version_key) int32 { def = (*elf64Verdef)(add(unsafe.Pointer(def), uintptr(def.vd_next))) } - return -1 // can not match any version + return -1 // cannot match any version } func vdso_parse_symbols(info *vdso_info, version int32) { diff --git a/src/sync/pool.go b/src/sync/pool.go index 381af0bead..4fb1a1af9d 100644 --- a/src/sync/pool.go +++ b/src/sync/pool.go @@ -149,7 +149,7 @@ func (p *Pool) getSlow() (x interface{}) { func (p *Pool) pin() *poolLocal { pid := runtime_procPin() // In pinSlow we store to localSize and then to local, here we load in opposite order. - // Since we've disabled preemption, GC can not happen in between. + // Since we've disabled preemption, GC cannot happen in between. // Thus here we must observe local at least as large localSize. // We can observe a newer/larger local, it is fine (we must observe its zero-initialized-ness). s := atomic.LoadUintptr(&p.localSize) // load-acquire From 9ad41f6243e7947ce1569140382f8847cc2a80dd Mon Sep 17 00:00:00 2001 From: Suharsh Sivakumar Date: Wed, 3 Feb 2016 13:22:40 -0800 Subject: [PATCH 083/117] net: ensure lookupStatic* returns copy of slice to disallow cache corruption. Fixes #14212 Change-Id: I74325dfaa1fb48f4b281c2d42157b563f1e42a94 Reviewed-on: https://go-review.googlesource.com/19201 Reviewed-by: Mikio Hara --- src/net/hosts.go | 8 ++++-- src/net/hosts_test.go | 62 +++++++++++++++++++++++++++++++++---------- 2 files changed, 54 insertions(+), 16 deletions(-) diff --git a/src/net/hosts.go b/src/net/hosts.go index c4de1b6a97..9c101c6ef5 100644 --- a/src/net/hosts.go +++ b/src/net/hosts.go @@ -110,7 +110,9 @@ func lookupStaticHost(host string) []string { lowerHost := []byte(host) lowerASCIIBytes(lowerHost) if ips, ok := hosts.byName[absDomainName(lowerHost)]; ok { - return ips + ipsCp := make([]string, len(ips)) + copy(ipsCp, ips) + return ipsCp } } return nil @@ -127,7 +129,9 @@ func lookupStaticAddr(addr string) []string { } if len(hosts.byAddr) != 0 { if hosts, ok := hosts.byAddr[addr]; ok { - return hosts + hostsCp := make([]string, len(hosts)) + copy(hostsCp, hosts) + return hostsCp } } return nil diff --git a/src/net/hosts_test.go b/src/net/hosts_test.go index 4c67bfa982..5d6c9cfe19 100644 --- a/src/net/hosts_test.go +++ b/src/net/hosts_test.go @@ -64,13 +64,17 @@ func TestLookupStaticHost(t *testing.T) { for _, tt := range lookupStaticHostTests { testHookHostsPath = tt.name for _, ent := range tt.ents { - ins := []string{ent.in, absDomainName([]byte(ent.in)), strings.ToLower(ent.in), strings.ToUpper(ent.in)} - for _, in := range ins { - addrs := lookupStaticHost(in) - if !reflect.DeepEqual(addrs, ent.out) { - t.Errorf("%s, lookupStaticHost(%s) = %v; want %v", tt.name, in, addrs, ent.out) - } - } + testStaticHost(t, tt.name, ent) + } + } +} + +func testStaticHost(t *testing.T, hostsPath string, ent staticHostEntry) { + ins := []string{ent.in, absDomainName([]byte(ent.in)), strings.ToLower(ent.in), strings.ToUpper(ent.in)} + for _, in := range ins { + addrs := lookupStaticHost(in) + if !reflect.DeepEqual(addrs, ent.out) { + t.Errorf("%s, lookupStaticHost(%s) = %v; want %v", hostsPath, in, addrs, ent.out) } } } @@ -129,13 +133,43 @@ func TestLookupStaticAddr(t *testing.T) { for _, tt := range lookupStaticAddrTests { testHookHostsPath = tt.name for _, ent := range tt.ents { - hosts := lookupStaticAddr(ent.in) - for i := range ent.out { - ent.out[i] = absDomainName([]byte(ent.out[i])) - } - if !reflect.DeepEqual(hosts, ent.out) { - t.Errorf("%s, lookupStaticAddr(%s) = %v; want %v", tt.name, ent.in, hosts, ent.out) - } + testStaticAddr(t, tt.name, ent) } } } + +func testStaticAddr(t *testing.T, hostsPath string, ent staticHostEntry) { + hosts := lookupStaticAddr(ent.in) + for i := range ent.out { + ent.out[i] = absDomainName([]byte(ent.out[i])) + } + if !reflect.DeepEqual(hosts, ent.out) { + t.Errorf("%s, lookupStaticAddr(%s) = %v; want %v", hostsPath, ent.in, hosts, ent.out) + } +} + +func TestHostCacheModification(t *testing.T) { + // Ensure that programs can't modify the internals of the host cache. + // See https://github.com/golang/go/issues/14212. + defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath) + + testHookHostsPath = "testdata/ipv4-hosts" + ent := staticHostEntry{"localhost", []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"}} + testStaticHost(t, testHookHostsPath, ent) + // Modify the addresses return by lookupStaticHost. + addrs := lookupStaticHost(ent.in) + for i := range addrs { + addrs[i] += "junk" + } + testStaticHost(t, testHookHostsPath, ent) + + testHookHostsPath = "testdata/ipv6-hosts" + ent = staticHostEntry{"::1", []string{"localhost"}} + testStaticAddr(t, testHookHostsPath, ent) + // Modify the hosts return by lookupStaticAddr. + hosts := lookupStaticAddr(ent.in) + for i := range hosts { + hosts[i] += "junk" + } + testStaticAddr(t, testHookHostsPath, ent) +} From 4cef0e980a5d4fca2b7d26ec26eb1de954cecc21 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Mon, 4 May 2015 15:02:09 -0700 Subject: [PATCH 084/117] cmd/compile: don't generate algs for [0]T and [1]T All [0]T values are equal. [1]T values are equal iff their sole components are. This types show up most frequently as a by-product of variadic function calls, such as fmt.Printf("abc") or fmt.Printf("%v", x). Cuts 12k off cmd/go and 22k off golang.org/x/tools/cmd/godoc, approx 0.1% each. For #6853 and #9930 Change-Id: Ic9b7aeb8cc945804246340f6f5e67bbf6008773e Reviewed-on: https://go-review.googlesource.com/19766 Reviewed-by: David Crawshaw Run-TryBot: David Crawshaw TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/gc/subr.go | 9 +++++++++ src/cmd/compile/internal/gc/walk.go | 15 +++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go index 0d25ddf2af..a17d7df60d 100644 --- a/src/cmd/compile/internal/gc/subr.go +++ b/src/cmd/compile/internal/gc/subr.go @@ -465,6 +465,15 @@ func algtype1(t *Type, bad **Type) int { return a } + switch t.Bound { + case 0: + // We checked above that the element type is comparable. + return AMEM + case 1: + // Single-element array is same as its lone element. + return a + } + return -1 // needs special compare case TSTRUCT: diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index e008317562..f324d5e00f 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -3193,6 +3193,21 @@ func walkcompare(np **Node, init **NodeList) { return } + if t.Etype == TARRAY { + // Zero- or single-element array, of any type. + switch t.Bound { + case 0: + finishcompare(np, n, Nodbool(n.Op == OEQ), init) + return + case 1: + l0 := Nod(OINDEX, l, Nodintconst(0)) + r0 := Nod(OINDEX, r, Nodintconst(0)) + a := Nod(n.Op, l0, r0) + finishcompare(np, n, a, init) + return + } + } + if t.Etype == TSTRUCT && countfield(t) <= 4 { // Struct of four or fewer fields. // Inline comparisons. From bc8458ab02878ae64af860f1cade78b6fa97e994 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Mon, 4 May 2015 16:12:52 -0700 Subject: [PATCH 085/117] cmd/compile: use && in generated eq algs This allows the compiler to generate better code containing fewer jumps and only a single return value. Cuts 12k off cmd/go and 16k off golang.org/x/tools/cmd/godoc, approx 0.1% each. For #6853 and #9930 Change-Id: I009616df797760b01e09f06357a2d6fd6ebcf307 Reviewed-on: https://go-review.googlesource.com/19767 Reviewed-by: David Crawshaw Run-TryBot: David Crawshaw TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/gc/subr.go | 67 ++++++++++++++++------------- 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go index a17d7df60d..a04c538e26 100644 --- a/src/cmd/compile/internal/gc/subr.go +++ b/src/cmd/compile/internal/gc/subr.go @@ -2649,17 +2649,13 @@ func genhash(sym *Sym, t *Type) { safemode = old_safemode } -// Return node for -// if p.field != q.field { return false } +// eqfield returns the node +// p.field == q.field func eqfield(p *Node, q *Node, field *Node) *Node { nx := Nod(OXDOT, p, field) ny := Nod(OXDOT, q, field) - nif := Nod(OIF, nil, nil) - nif.Left = Nod(ONE, nx, ny) - r := Nod(ORETURN, nil, nil) - r.List = list(r.List, Nodbool(false)) - nif.Nbody = list(nif.Nbody, r) - return nif + ne := Nod(OEQ, nx, ny) + return ne } func eqmemfunc(size int64, type_ *Type, needsize *int) *Node { @@ -2680,8 +2676,8 @@ func eqmemfunc(size int64, type_ *Type, needsize *int) *Node { return fn } -// Return node for -// if !memequal(&p.field, &q.field [, size]) { return false } +// eqmem returns the node +// memequal(&p.field, &q.field [, size]) func eqmem(p *Node, q *Node, field *Node, size int64) *Node { var needsize int @@ -2699,15 +2695,11 @@ func eqmem(p *Node, q *Node, field *Node, size int64) *Node { call.List = list(call.List, Nodintconst(size)) } - nif := Nod(OIF, nil, nil) - nif.Left = Nod(ONOT, call, nil) - r := Nod(ORETURN, nil, nil) - r.List = list(r.List, Nodbool(false)) - nif.Nbody = list(nif.Nbody, r) - return nif + return call } -// Generate a helper function to check equality of two values of type t. +// geneq generates a helper function to +// check equality of two values of type t. func geneq(sym *Sym, t *Type) { if Debug['r'] != 0 { fmt.Printf("geneq %v %v\n", sym, t) @@ -2777,12 +2769,18 @@ func geneq(sym *Sym, t *Type) { nrange.Nbody = list(nrange.Nbody, nif) fn.Nbody = list(fn.Nbody, nrange) - // Walk the struct using memequal for runs of AMEM + // return true + ret := Nod(ORETURN, nil, nil) + ret.List = list(ret.List, Nodbool(true)) + fn.Nbody = list(fn.Nbody, ret) + + // Walk the struct using memequal for runs of AMEM // and calling specific equality tests for the others. // Skip blank-named fields. case TSTRUCT: var first *Type + var conjuncts []*Node offend := int64(0) var size int64 for t1 := t.Type; ; t1 = t1.Down { @@ -2805,17 +2803,17 @@ func geneq(sym *Sym, t *Type) { // cross-package unexported fields. if first != nil { if first.Down == t1 { - fn.Nbody = list(fn.Nbody, eqfield(np, nq, newname(first.Sym))) + conjuncts = append(conjuncts, eqfield(np, nq, newname(first.Sym))) } else if first.Down.Down == t1 { - fn.Nbody = list(fn.Nbody, eqfield(np, nq, newname(first.Sym))) + conjuncts = append(conjuncts, eqfield(np, nq, newname(first.Sym))) first = first.Down if !isblanksym(first.Sym) { - fn.Nbody = list(fn.Nbody, eqfield(np, nq, newname(first.Sym))) + conjuncts = append(conjuncts, eqfield(np, nq, newname(first.Sym))) } } else { // More than two fields: use memequal. size = offend - first.Width // first->width is offset - fn.Nbody = list(fn.Nbody, eqmem(np, nq, newname(first.Sym), size)) + conjuncts = append(conjuncts, eqmem(np, nq, newname(first.Sym), size)) } first = nil @@ -2829,16 +2827,27 @@ func geneq(sym *Sym, t *Type) { } // Check this field, which is not just memory. - fn.Nbody = list(fn.Nbody, eqfield(np, nq, newname(t1.Sym))) + conjuncts = append(conjuncts, eqfield(np, nq, newname(t1.Sym))) } + + var and *Node + switch len(conjuncts) { + case 0: + and = Nodbool(true) + case 1: + and = conjuncts[0] + default: + and = Nod(OANDAND, conjuncts[0], conjuncts[1]) + for _, conjunct := range conjuncts[2:] { + and = Nod(OANDAND, and, conjunct) + } + } + + ret := Nod(ORETURN, nil, nil) + ret.List = list(ret.List, and) + fn.Nbody = list(fn.Nbody, ret) } - // return true - r := Nod(ORETURN, nil, nil) - - r.List = list(r.List, Nodbool(true)) - fn.Nbody = list(fn.Nbody, r) - if Debug['r'] != 0 { dumplist("geneq body", fn.Nbody) } From e960302410fafaf595c1ad92c28c61da3a254d63 Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Sun, 21 Feb 2016 13:56:08 -0500 Subject: [PATCH 086/117] runtime: when crash with panic, call user Error/String methods before freezing the world Fixes #14432. Change-Id: I0a92ef86de95de39217df9a664d8034ef685a906 Reviewed-on: https://go-review.googlesource.com/19792 Reviewed-by: Ian Lance Taylor Run-TryBot: Minux Ma TryBot-Result: Gobot Gobot --- src/runtime/crash_cgo_test.go | 9 ++++++ src/runtime/crash_test.go | 16 +++++++++++ src/runtime/panic.go | 19 +++++++++++++ src/runtime/testdata/testprog/deadlock.go | 25 ++++++++++++++++ src/runtime/testdata/testprogcgo/deadlock.go | 30 ++++++++++++++++++++ 5 files changed, 99 insertions(+) create mode 100644 src/runtime/testdata/testprogcgo/deadlock.go diff --git a/src/runtime/crash_cgo_test.go b/src/runtime/crash_cgo_test.go index 7685582aa8..63769e801c 100644 --- a/src/runtime/crash_cgo_test.go +++ b/src/runtime/crash_cgo_test.go @@ -178,3 +178,12 @@ func TestCgoCheckBytes(t *testing.T) { t.Errorf("cgo check too slow: got %v, expected at most %v", d1, d2*10) } } + +func TestCgoPanicDeadlock(t *testing.T) { + // test issue 14432 + got := runTestProg(t, "testprogcgo", "CgoPanicDeadlock") + want := "panic: cgo error\n\n" + if !strings.HasPrefix(got, want) { + t.Fatalf("output does not start with %q:\n%s", want, got) + } +} diff --git a/src/runtime/crash_test.go b/src/runtime/crash_test.go index 5f0e77b0dc..de45e832f8 100644 --- a/src/runtime/crash_test.go +++ b/src/runtime/crash_test.go @@ -336,3 +336,19 @@ func TestPanicTraceback(t *testing.T) { output = output[idx[1]:] } } + +func testPanicDeadlock(t *testing.T, name string, want string) { + // test issue 14432 + output := runTestProg(t, "testprog", name) + if !strings.HasPrefix(output, want) { + t.Fatalf("output does not start with %q:\n%s", want, output) + } +} + +func TestPanicDeadlockGosched(t *testing.T) { + testPanicDeadlock(t, "GoschedInPanic", "panic: errorThatGosched\n\n") +} + +func TestPanicDeadlockSyscall(t *testing.T) { + testPanicDeadlock(t, "SyscallInPanic", "1\n2\npanic: 3\n\n") +} diff --git a/src/runtime/panic.go b/src/runtime/panic.go index ba07330e35..349e997395 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -333,6 +333,21 @@ func Goexit() { goexit1() } +// Call all Error and String methods before freezing the world. +// Used when crashing with panicking. +// This must match types handled by printany. +func preprintpanics(p *_panic) { + for p != nil { + switch v := p.arg.(type) { + case error: + p.arg = v.Error() + case stringer: + p.arg = v.String() + } + p = p.link + } +} + // Print all currently active panics. Used when crashing. func printpanics(p *_panic) { if p.link != nil { @@ -459,6 +474,10 @@ func gopanic(e interface{}) { } // ran out of deferred calls - old-school panic now + // Because it is unsafe to call arbitrary user code after freezing + // the world, we call preprintpanics to invoke all necessary Error + // and String methods to prepare the panic strings before startpanic. + preprintpanics(gp._panic) startpanic() printpanics(gp._panic) dopanic(0) // should not return diff --git a/src/runtime/testdata/testprog/deadlock.go b/src/runtime/testdata/testprog/deadlock.go index 73fbf6224d..ff9c82d61b 100644 --- a/src/runtime/testdata/testprog/deadlock.go +++ b/src/runtime/testdata/testprog/deadlock.go @@ -30,6 +30,8 @@ func init() { register("PanicAfterGoexit", PanicAfterGoexit) register("RecoveredPanicAfterGoexit", RecoveredPanicAfterGoexit) register("PanicTraceback", PanicTraceback) + register("GoschedInPanic", GoschedInPanic) + register("SyscallInPanic", SyscallInPanic) } func SimpleDeadlock() { @@ -152,6 +154,29 @@ func GoexitInPanic() { runtime.Goexit() } +type errorThatGosched struct{} + +func (errorThatGosched) Error() string { + runtime.Gosched() + return "errorThatGosched" +} + +func GoschedInPanic() { + panic(errorThatGosched{}) +} + +type errorThatPrint struct{} + +func (errorThatPrint) Error() string { + fmt.Println("1") + fmt.Println("2") + return "3" +} + +func SyscallInPanic() { + panic(errorThatPrint{}) +} + func PanicAfterGoexit() { defer func() { panic("hello") diff --git a/src/runtime/testdata/testprogcgo/deadlock.go b/src/runtime/testdata/testprogcgo/deadlock.go new file mode 100644 index 0000000000..ac8855af3b --- /dev/null +++ b/src/runtime/testdata/testprogcgo/deadlock.go @@ -0,0 +1,30 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +/* +char *geterror() { + return "cgo error"; +} +*/ +import "C" +import ( + "fmt" +) + +func init() { + register("CgoPanicDeadlock", CgoPanicDeadlock) +} + +type cgoError struct{} + +func (cgoError) Error() string { + fmt.Print("") // necessary to trigger the deadlock + return C.GoString(C.geterror()) +} + +func CgoPanicDeadlock() { + panic(cgoError{}) +} From 8ffe496ae792a1cdc845c1c019323cf6c05fbb32 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Sat, 20 Feb 2016 22:52:15 -0800 Subject: [PATCH 087/117] cmd/compile, runtime: eliminate unnecessary algorithm types There's no need for 8 different ways to represent that a type is non-comparable. While here, move AMEM out of the runtime-known algorithm values since it's not needed at run-time, and get rid of the unused AUNK constant. Change-Id: Ie23972b692c6f27fc5f1a908561b3e26ef5a50e9 Reviewed-on: https://go-review.googlesource.com/19779 Run-TryBot: Matthew Dempsky TryBot-Result: Gobot Gobot Reviewed-by: David Crawshaw --- src/cmd/compile/internal/gc/go.go | 13 ++----------- src/cmd/compile/internal/gc/subr.go | 22 +++++++--------------- src/runtime/alg.go | 20 ++------------------ 3 files changed, 11 insertions(+), 44 deletions(-) diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go index d21b2fb196..3923bc6e31 100644 --- a/src/cmd/compile/internal/gc/go.go +++ b/src/cmd/compile/internal/gc/go.go @@ -28,30 +28,21 @@ const ( const ( // These values are known by runtime. - // The MEMx and NOEQx values must run in parallel. See algtype. - AMEM = iota + ANOEQ = iota AMEM0 AMEM8 AMEM16 AMEM32 AMEM64 AMEM128 - ANOEQ - ANOEQ0 - ANOEQ8 - ANOEQ16 - ANOEQ32 - ANOEQ64 - ANOEQ128 ASTRING AINTER ANILINTER - ASLICE AFLOAT32 AFLOAT64 ACPLX64 ACPLX128 - AUNK = 100 + AMEM = 100 ) const ( diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go index a04c538e26..ba0a257b3b 100644 --- a/src/cmd/compile/internal/gc/subr.go +++ b/src/cmd/compile/internal/gc/subr.go @@ -509,28 +509,20 @@ func algtype1(t *Type, bad **Type) int { func algtype(t *Type) int { a := algtype1(t, nil) - if a == AMEM || a == ANOEQ { - if Isslice(t) { - return ASLICE - } + if a == AMEM { switch t.Width { case 0: - return a + AMEM0 - AMEM - + return AMEM0 case 1: - return a + AMEM8 - AMEM - + return AMEM8 case 2: - return a + AMEM16 - AMEM - + return AMEM16 case 4: - return a + AMEM32 - AMEM - + return AMEM32 case 8: - return a + AMEM64 - AMEM - + return AMEM64 case 16: - return a + AMEM128 - AMEM + return AMEM128 } } diff --git a/src/runtime/alg.go b/src/runtime/alg.go index 9ea0eb0187..541649c62d 100644 --- a/src/runtime/alg.go +++ b/src/runtime/alg.go @@ -16,24 +16,16 @@ const ( // type algorithms - known to compiler const ( - alg_MEM = iota + alg_NOEQ = iota alg_MEM0 alg_MEM8 alg_MEM16 alg_MEM32 alg_MEM64 alg_MEM128 - alg_NOEQ - alg_NOEQ0 - alg_NOEQ8 - alg_NOEQ16 - alg_NOEQ32 - alg_NOEQ64 - alg_NOEQ128 alg_STRING alg_INTER alg_NILINTER - alg_SLICE alg_FLOAT32 alg_FLOAT64 alg_CPLX64 @@ -77,24 +69,16 @@ func memhash128(p unsafe.Pointer, h uintptr) uintptr { func memhash_varlen(p unsafe.Pointer, h uintptr) uintptr var algarray = [alg_max]typeAlg{ - alg_MEM: {nil, nil}, // not used + alg_NOEQ: {nil, nil}, 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}, - alg_NOEQ16: {nil, nil}, - alg_NOEQ32: {nil, nil}, - alg_NOEQ64: {nil, nil}, - alg_NOEQ128: {nil, nil}, alg_STRING: {strhash, strequal}, alg_INTER: {interhash, interequal}, alg_NILINTER: {nilinterhash, nilinterequal}, - alg_SLICE: {nil, nil}, alg_FLOAT32: {f32hash, f32equal}, alg_FLOAT64: {f64hash, f64equal}, alg_CPLX64: {c64hash, c64equal}, From 8caf19c46f9d7cc9011d7acdc464768b5fb15d7e Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Sat, 20 Feb 2016 20:33:34 -0800 Subject: [PATCH 088/117] net: fix TestUpdateResolvConf after CL 18860 When writing a fake dnsConfig to conf.dnsConfig, set lastChecked to an hour into the future. This causes dnsclient_unix.go's tryUpdate("/etc/resolv.conf") calls to short-circuit and ignore that /etc/resolv.conf's mtime differs from the test's fake resolv.conf file. We only need to zero out lastChecked in teardown. While here, this makes two other tryUpdate(conf.path) test calls pointless, since they'll now short circuit too. Fixes #14437. Change-Id: Ieb520388e319b9826dfa49f134907f4927608a53 Reviewed-on: https://go-review.googlesource.com/19777 Run-TryBot: Matthew Dempsky TryBot-Result: Gobot Gobot Reviewed-by: Mikio Hara --- src/net/dnsclient_unix_test.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/net/dnsclient_unix_test.go b/src/net/dnsclient_unix_test.go index 934f25b2c9..d7f00c784d 100644 --- a/src/net/dnsclient_unix_test.go +++ b/src/net/dnsclient_unix_test.go @@ -124,20 +124,20 @@ func (conf *resolvConfTest) writeAndUpdate(lines []string) error { return err } f.Close() - if err := conf.forceUpdate(conf.path); err != nil { + if err := conf.forceUpdate(conf.path, time.Now().Add(time.Hour)); err != nil { return err } return nil } -func (conf *resolvConfTest) forceUpdate(name string) error { +func (conf *resolvConfTest) forceUpdate(name string, lastChecked time.Time) error { dnsConf := dnsReadConfig(name) conf.mu.Lock() conf.dnsConfig = dnsConf conf.mu.Unlock() for i := 0; i < 5; i++ { if conf.tryAcquireSema() { - conf.lastChecked = time.Time{} + conf.lastChecked = lastChecked conf.releaseSema() return nil } @@ -153,7 +153,7 @@ func (conf *resolvConfTest) servers() []string { } func (conf *resolvConfTest) teardown() error { - err := conf.forceUpdate("/etc/resolv.conf") + err := conf.forceUpdate("/etc/resolv.conf", time.Time{}) os.RemoveAll(conf.dir) return err } @@ -353,7 +353,6 @@ func TestGoLookupIPWithResolverConfig(t *testing.T) { t.Error(err) continue } - conf.tryUpdate(conf.path) addrs, err := goLookupIP(tt.name) if err != nil { if err, ok := err.(*DNSError); !ok || (err.Name != tt.error.(*DNSError).Name || err.Server != tt.error.(*DNSError).Server || err.IsTimeout != tt.error.(*DNSError).IsTimeout) { @@ -392,7 +391,6 @@ func TestGoLookupIPOrderFallbackToFile(t *testing.T) { if err := conf.writeAndUpdate([]string{}); err != nil { t.Fatal(err) } - conf.tryUpdate(conf.path) // Redirect host file lookups. defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath) testHookHostsPath = "testdata/hosts" From a4b143bc22ff471a96c42458833998151df70cc0 Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Sat, 19 Sep 2015 06:59:06 -0400 Subject: [PATCH 089/117] go/types: skip $GOROOT/src/*.go in TestStdlib Change-Id: I4a75d98a48675e2beb5b4843fb2c6ff5d4c8d2a2 Reviewed-on: https://go-review.googlesource.com/14769 Reviewed-by: Robert Griesemer --- src/go/types/stdlib_test.go | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/go/types/stdlib_test.go b/src/go/types/stdlib_test.go index 09f2585bcf..97e6a69521 100644 --- a/src/go/types/stdlib_test.go +++ b/src/go/types/stdlib_test.go @@ -266,13 +266,16 @@ func walkDirs(t *testing.T, dir string) { } // typecheck package in directory - files, err := pkgFilenames(dir) - if err != nil { - t.Error(err) - return - } - if files != nil { - typecheck(t, dir, files) + // but ignore files directly under $GOROOT/src (might be temporary test files). + if dir != filepath.Join(runtime.GOROOT(), "src") { + files, err := pkgFilenames(dir) + if err != nil { + t.Error(err) + return + } + if files != nil { + typecheck(t, dir, files) + } } // traverse subdirectories, but don't walk into testdata From d70c04cf08683e2b0a26fb13808f8cacb1bcdd38 Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Sat, 20 Feb 2016 23:24:27 -0500 Subject: [PATCH 090/117] runtime: fix missing word in comment Change-Id: I6cb8ac7b59812e82111ab3b0f8303ab8194a5129 Reviewed-on: https://go-review.googlesource.com/19791 Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot --- src/runtime/proc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/proc.go b/src/runtime/proc.go index d1f5088b50..389917916f 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -2406,7 +2406,7 @@ func entersyscallblock_handoff() { // The goroutine g exited its system call. // Arrange for it to run on a cpu again. // This is called only from the go syscall library, not -// from the low-level system calls used by the +// from the low-level system calls used by the runtime. //go:nosplit func exitsyscall(dummy int32) { _g_ := getg() From 89cfdda44dec9f1e4e7f9ac360638fecee2482c6 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Sat, 20 Feb 2016 18:49:22 -0800 Subject: [PATCH 091/117] cmd/compile: replace Order's use of NodeLists with slices Order's "temp" and "free" fields use NodeLists in a rather non-idiomatic way. Instead of using the "list" or "concat" functions, it manipulates them directly and without the normal invariants (e.g., it doesn't maintain the "End" field). Rather than convert it to more typical usage, just replace with a slice, which ends up much simpler anyway. Passes toolstash/buildall. Change-Id: Ibd0f24324bd674c0d5bb1bc40d073b01e7824ad5 Reviewed-on: https://go-review.googlesource.com/19776 Run-TryBot: Matthew Dempsky TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/cmd/compile/internal/gc/order.go | 55 +++++++++------------------- 1 file changed, 17 insertions(+), 38 deletions(-) diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go index a2e12284d0..ddd6cb9719 100644 --- a/src/cmd/compile/internal/gc/order.go +++ b/src/cmd/compile/internal/gc/order.go @@ -42,8 +42,7 @@ import ( // Order holds state during the ordering process. type Order struct { out *NodeList // list of generated statements - temp *NodeList // head of stack of temporary variables - free *NodeList // free list of NodeList* structs (for use in temp) + temp []*Node // stack of temporary variables } // Order rewrites fn->nbody to apply the ordering constraints @@ -68,14 +67,7 @@ func ordertemp(t *Type, order *Order, clear bool) *Node { order.out = list(order.out, a) } - l := order.free - if l == nil { - l = new(NodeList) - } - order.free = l.Next - l.Next = order.temp - l.N = var_ - order.temp = l + order.temp = append(order.temp, var_) return var_ } @@ -215,41 +207,34 @@ func orderaddrtemp(np **Node, order *Order) { *np = ordercopyexpr(n, n.Type, order, 0) } +type ordermarker int + // Marktemp returns the top of the temporary variable stack. -func marktemp(order *Order) *NodeList { - return order.temp +func marktemp(order *Order) ordermarker { + return ordermarker(len(order.temp)) } // Poptemp pops temporaries off the stack until reaching the mark, // which must have been returned by marktemp. -func poptemp(mark *NodeList, order *Order) { - var l *NodeList - - for { - l = order.temp - if l == mark { - break - } - order.temp = l.Next - l.Next = order.free - order.free = l - } +func poptemp(mark ordermarker, order *Order) { + order.temp = order.temp[:mark] } // Cleantempnopop emits to *out VARKILL instructions for each temporary // above the mark on the temporary stack, but it does not pop them // from the stack. -func cleantempnopop(mark *NodeList, order *Order, out **NodeList) { +func cleantempnopop(mark ordermarker, order *Order, out **NodeList) { var kill *Node - for l := order.temp; l != mark; l = l.Next { - if l.N.Name.Keepalive { - l.N.Name.Keepalive = false - kill = Nod(OVARLIVE, l.N, nil) + for i := len(order.temp) - 1; i >= int(mark); i-- { + n := order.temp[i] + if n.Name.Keepalive { + n.Name.Keepalive = false + kill = Nod(OVARLIVE, n, nil) typecheck(&kill, Etop) *out = list(*out, kill) } - kill = Nod(OVARKILL, l.N, nil) + kill = Nod(OVARKILL, n, nil) typecheck(&kill, Etop) *out = list(*out, kill) } @@ -257,7 +242,7 @@ func cleantempnopop(mark *NodeList, order *Order, out **NodeList) { // Cleantemp emits VARKILL instructions for each temporary above the // mark on the temporary stack and removes them from the stack. -func cleantemp(top *NodeList, order *Order) { +func cleantemp(top ordermarker, order *Order) { cleantempnopop(top, order, &order.out) poptemp(top, order) } @@ -289,13 +274,7 @@ func orderexprinplace(np **Node, outer *Order) { // insert new temporaries from order // at head of outer list. - lp := &order.temp - - for *lp != nil { - lp = &(*lp).Next - } - *lp = outer.temp - outer.temp = order.temp + outer.temp = append(outer.temp, order.temp...) *np = n } From 8847a5913a5970b5f5c062f767c369da683648d6 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Thu, 18 Feb 2016 17:28:04 -0500 Subject: [PATCH 092/117] runtime: remove unused parfor code Change-Id: Ibbfae20cab48163f22d661604ef730705f2b97ba Reviewed-on: https://go-review.googlesource.com/19661 Run-TryBot: Austin Clements TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/runtime/export_test.go | 36 ------ src/runtime/parfor.go | 217 ------------------------------------- src/runtime/parfor_test.go | 128 ---------------------- 3 files changed, 381 deletions(-) delete mode 100644 src/runtime/parfor.go delete mode 100644 src/runtime/parfor_test.go diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go index 5400c1d14e..245cc88aae 100644 --- a/src/runtime/export_test.go +++ b/src/runtime/export_test.go @@ -45,42 +45,6 @@ func LFStackPop(head *uint64) *LFNode { return (*LFNode)(unsafe.Pointer(lfstackpop(head))) } -type ParFor struct { - body func(*ParFor, uint32) - done uint32 - Nthr uint32 - thrseq uint32 - Cnt uint32 - wait bool -} - -func NewParFor(nthrmax uint32) *ParFor { - var desc *ParFor - systemstack(func() { - desc = (*ParFor)(unsafe.Pointer(parforalloc(nthrmax))) - }) - return desc -} - -func ParForSetup(desc *ParFor, nthr, n uint32, wait bool, body func(*ParFor, uint32)) { - systemstack(func() { - parforsetup((*parfor)(unsafe.Pointer(desc)), nthr, n, wait, - *(*func(*parfor, uint32))(unsafe.Pointer(&body))) - }) -} - -func ParForDo(desc *ParFor) { - systemstack(func() { - parfordo((*parfor)(unsafe.Pointer(desc))) - }) -} - -func ParForIters(desc *ParFor, tid uint32) (uint32, uint32) { - desc1 := (*parfor)(unsafe.Pointer(desc)) - pos := desc1.thr[tid].pos - return uint32(pos), uint32(pos >> 32) -} - func GCMask(x interface{}) (ret []byte) { systemstack(func() { ret = getgcmask(x) diff --git a/src/runtime/parfor.go b/src/runtime/parfor.go deleted file mode 100644 index 9e11cb3e12..0000000000 --- a/src/runtime/parfor.go +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Parallel for algorithm. - -package runtime - -import ( - "runtime/internal/atomic" - "runtime/internal/sys" -) - -// A parfor holds state for the parallel for operation. -type parfor struct { - body func(*parfor, uint32) // executed for each element - done uint32 // number of idle threads - nthr uint32 // total number of threads - thrseq uint32 // thread id sequencer - cnt uint32 // iteration space [0, cnt) - wait bool // if true, wait while all threads finish processing, - // otherwise parfor may return while other threads are still working - - thr []parforthread // thread descriptors - - // stats - nsteal uint64 - nstealcnt uint64 - nprocyield uint64 - nosyield uint64 - nsleep uint64 -} - -// A parforthread holds state for a single thread in the parallel for. -type parforthread struct { - // the thread's iteration space [32lsb, 32msb) - pos uint64 - // stats - nsteal uint64 - nstealcnt uint64 - nprocyield uint64 - nosyield uint64 - nsleep uint64 - pad [sys.CacheLineSize]byte -} - -func parforalloc(nthrmax uint32) *parfor { - return &parfor{ - thr: make([]parforthread, nthrmax), - } -} - -// Parforsetup initializes desc for a parallel for operation with nthr -// threads executing n jobs. -// -// On return the nthr threads are each expected to call parfordo(desc) -// to run the operation. During those calls, for each i in [0, n), one -// thread will be used invoke body(desc, i). -// If wait is true, no parfordo will return until all work has been completed. -// If wait is false, parfordo may return when there is a small amount -// of work left, under the assumption that another thread has that -// work well in hand. -func parforsetup(desc *parfor, nthr, n uint32, wait bool, body func(*parfor, uint32)) { - if desc == nil || nthr == 0 || nthr > uint32(len(desc.thr)) || body == nil { - print("desc=", desc, " nthr=", nthr, " count=", n, " body=", body, "\n") - throw("parfor: invalid args") - } - - desc.body = body - desc.done = 0 - desc.nthr = nthr - desc.thrseq = 0 - desc.cnt = n - desc.wait = wait - desc.nsteal = 0 - desc.nstealcnt = 0 - desc.nprocyield = 0 - desc.nosyield = 0 - desc.nsleep = 0 - - for i := range desc.thr { - begin := uint32(uint64(n) * uint64(i) / uint64(nthr)) - end := uint32(uint64(n) * uint64(i+1) / uint64(nthr)) - desc.thr[i].pos = uint64(begin) | uint64(end)<<32 - } -} - -func parfordo(desc *parfor) { - // Obtain 0-based thread index. - tid := atomic.Xadd(&desc.thrseq, 1) - 1 - if tid >= desc.nthr { - print("tid=", tid, " nthr=", desc.nthr, "\n") - throw("parfor: invalid tid") - } - - // If single-threaded, just execute the for serially. - body := desc.body - if desc.nthr == 1 { - for i := uint32(0); i < desc.cnt; i++ { - body(desc, i) - } - return - } - - me := &desc.thr[tid] - mypos := &me.pos - for { - for { - // While there is local work, - // bump low index and execute the iteration. - pos := atomic.Xadd64(mypos, 1) - begin := uint32(pos) - 1 - end := uint32(pos >> 32) - if begin < end { - body(desc, begin) - continue - } - break - } - - // Out of work, need to steal something. - idle := false - for try := uint32(0); ; try++ { - // If we don't see any work for long enough, - // increment the done counter... - if try > desc.nthr*4 && !idle { - idle = true - atomic.Xadd(&desc.done, 1) - } - - // ...if all threads have incremented the counter, - // we are done. - extra := uint32(0) - if !idle { - extra = 1 - } - if desc.done+extra == desc.nthr { - if !idle { - atomic.Xadd(&desc.done, 1) - } - goto exit - } - - // Choose a random victim for stealing. - var begin, end uint32 - victim := fastrand1() % (desc.nthr - 1) - if victim >= tid { - victim++ - } - victimpos := &desc.thr[victim].pos - for { - // See if it has any work. - pos := atomic.Load64(victimpos) - begin = uint32(pos) - end = uint32(pos >> 32) - if begin+1 >= end { - end = 0 - begin = end - break - } - if idle { - atomic.Xadd(&desc.done, -1) - idle = false - } - begin2 := begin + (end-begin)/2 - newpos := uint64(begin) | uint64(begin2)<<32 - if atomic.Cas64(victimpos, pos, newpos) { - begin = begin2 - break - } - } - if begin < end { - // Has successfully stolen some work. - if idle { - throw("parfor: should not be idle") - } - atomic.Store64(mypos, uint64(begin)|uint64(end)<<32) - me.nsteal++ - me.nstealcnt += uint64(end) - uint64(begin) - break - } - - // Backoff. - if try < desc.nthr { - // nothing - } else if try < 4*desc.nthr { - me.nprocyield++ - procyield(20) - } else if !desc.wait { - // If a caller asked not to wait for the others, exit now - // (assume that most work is already done at this point). - if !idle { - atomic.Xadd(&desc.done, 1) - } - goto exit - } else if try < 6*desc.nthr { - me.nosyield++ - osyield() - } else { - me.nsleep++ - usleep(1) - } - } - } - -exit: - atomic.Xadd64(&desc.nsteal, int64(me.nsteal)) - atomic.Xadd64(&desc.nstealcnt, int64(me.nstealcnt)) - atomic.Xadd64(&desc.nprocyield, int64(me.nprocyield)) - atomic.Xadd64(&desc.nosyield, int64(me.nosyield)) - atomic.Xadd64(&desc.nsleep, int64(me.nsleep)) - me.nsteal = 0 - me.nstealcnt = 0 - me.nprocyield = 0 - me.nosyield = 0 - me.nsleep = 0 -} diff --git a/src/runtime/parfor_test.go b/src/runtime/parfor_test.go deleted file mode 100644 index 5d22aecc9b..0000000000 --- a/src/runtime/parfor_test.go +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// The race detector does not understand ParFor synchronization. -// +build !race - -package runtime_test - -import ( - . "runtime" - "testing" -) - -// Simple serial sanity test for parallelfor. -func TestParFor(t *testing.T) { - const P = 1 - const N = 20 - data := make([]uint64, N) - for i := uint64(0); i < N; i++ { - data[i] = i - } - desc := NewParFor(P) - ParForSetup(desc, P, N, true, func(desc *ParFor, i uint32) { - data[i] = data[i]*data[i] + 1 - }) - ParForDo(desc) - for i := uint64(0); i < N; i++ { - if data[i] != i*i+1 { - t.Fatalf("Wrong element %d: %d", i, data[i]) - } - } -} - -// Test that nonblocking parallelfor does not block. -func TestParFor2(t *testing.T) { - const P = 7 - const N = 1003 - data := make([]uint64, N) - for i := uint64(0); i < N; i++ { - data[i] = i - } - desc := NewParFor(P) - ParForSetup(desc, P, N, false, func(desc *ParFor, i uint32) { - data[i] = data[i]*data[i] + 1 - }) - for p := 0; p < P; p++ { - ParForDo(desc) - } - for i := uint64(0); i < N; i++ { - if data[i] != i*i+1 { - t.Fatalf("Wrong element %d: %d", i, data[i]) - } - } -} - -// Test that iterations are properly distributed. -func TestParForSetup(t *testing.T) { - const P = 11 - const N = 101 - desc := NewParFor(P) - for n := uint32(0); n < N; n++ { - for p := uint32(1); p <= P; p++ { - ParForSetup(desc, p, n, true, func(desc *ParFor, i uint32) {}) - sum := uint32(0) - size0 := uint32(0) - end0 := uint32(0) - for i := uint32(0); i < p; i++ { - begin, end := ParForIters(desc, i) - size := end - begin - sum += size - if i == 0 { - size0 = size - if begin != 0 { - t.Fatalf("incorrect begin: %d (n=%d, p=%d)", begin, n, p) - } - } else { - if size != size0 && size != size0+1 { - t.Fatalf("incorrect size: %d/%d (n=%d, p=%d)", size, size0, n, p) - } - if begin != end0 { - t.Fatalf("incorrect begin/end: %d/%d (n=%d, p=%d)", begin, end0, n, p) - } - } - end0 = end - } - if sum != n { - t.Fatalf("incorrect sum: %d/%d (p=%d)", sum, n, p) - } - } - } -} - -// Test parallel parallelfor. -func TestParForParallel(t *testing.T) { - N := uint64(1e7) - if testing.Short() { - N /= 10 - } - data := make([]uint64, N) - for i := uint64(0); i < N; i++ { - data[i] = i - } - P := GOMAXPROCS(-1) - c := make(chan bool, P) - desc := NewParFor(uint32(P)) - ParForSetup(desc, uint32(P), uint32(N), false, func(desc *ParFor, i uint32) { - data[i] = data[i]*data[i] + 1 - }) - for p := 1; p < P; p++ { - go func() { - ParForDo(desc) - c <- true - }() - } - ParForDo(desc) - for p := 1; p < P; p++ { - <-c - } - for i := uint64(0); i < N; i++ { - if data[i] != i*i+1 { - t.Fatalf("Wrong element %d: %d", i, data[i]) - } - } - - data, desc = nil, nil - GC() -} From 5609a48931593a0ba88cab4a54ea5c426b292c3e Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Sat, 20 Feb 2016 21:36:12 -0800 Subject: [PATCH 093/117] cmd/compile: make cmpstackvarlt properly asymmetric Previously, given two Nodes n1 and n2 of different non-PAUTO classes (e.g., PPARAM and PPARAMOUT), cmpstackvarlt(n1, n2) and cmpstackvarlt(n2, n1) both returned true, which is nonsense. This doesn't seem to cause any visible miscompilation problems, but notably fixing it does cause toolstash/buildall to fail. Change-Id: I33b2c66e902c5eced875d8fbf18b7cfdc81e8aed Reviewed-on: https://go-review.googlesource.com/19778 Run-TryBot: Matthew Dempsky Reviewed-by: Ian Lance Taylor TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/gc/pgen.go | 22 +++++----------------- src/cmd/compile/internal/gc/pgen_test.go | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/cmd/compile/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go index ffc0ab9cfb..3471b977ed 100644 --- a/src/cmd/compile/internal/gc/pgen.go +++ b/src/cmd/compile/internal/gc/pgen.go @@ -186,21 +186,12 @@ func emitptrargsmap() { // the top of the stack and increasing in size. // Non-autos sort on offset. func cmpstackvarlt(a, b *Node) bool { - if a.Class != b.Class { - if a.Class == PAUTO { - return false - } - return true + if (a.Class == PAUTO) != (b.Class == PAUTO) { + return b.Class == PAUTO } if a.Class != PAUTO { - if a.Xoffset < b.Xoffset { - return true - } - if a.Xoffset > b.Xoffset { - return false - } - return false + return a.Xoffset < b.Xoffset } if a.Used != b.Used { @@ -219,11 +210,8 @@ func cmpstackvarlt(a, b *Node) bool { return ap } - if a.Type.Width < b.Type.Width { - return false - } - if a.Type.Width > b.Type.Width { - return true + if a.Type.Width != b.Type.Width { + return a.Type.Width > b.Type.Width } return a.Sym.Name < b.Sym.Name diff --git a/src/cmd/compile/internal/gc/pgen_test.go b/src/cmd/compile/internal/gc/pgen_test.go index ebc9101135..909b8a9507 100644 --- a/src/cmd/compile/internal/gc/pgen_test.go +++ b/src/cmd/compile/internal/gc/pgen_test.go @@ -40,6 +40,16 @@ func TestCmpstackvar(t *testing.T) { Node{Class: PFUNC, Xoffset: 10}, false, }, + { + Node{Class: PPARAM, Xoffset: 10}, + Node{Class: PPARAMOUT, Xoffset: 20}, + true, + }, + { + Node{Class: PPARAMOUT, Xoffset: 10}, + Node{Class: PPARAM, Xoffset: 20}, + true, + }, { Node{Class: PAUTO, Used: true}, Node{Class: PAUTO, Used: false}, @@ -101,6 +111,10 @@ func TestCmpstackvar(t *testing.T) { if got != d.lt { t.Errorf("want %#v < %#v", d.a, d.b) } + // If we expect a < b to be true, check that b < a is false. + if d.lt && cmpstackvarlt(&d.b, &d.a) { + t.Errorf("unexpected %#v < %#v", d.b, d.a) + } } } From d0c11577b9c6d584959aceddf97266b9cbc336d0 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Sun, 21 Feb 2016 20:43:14 -0800 Subject: [PATCH 094/117] cmd/compile: inline {i,e}facethash These functions are really simple, the overhead of calling them (in both time and code size) is larger than the inlined versions. Reorganize how the nil case in a type switch is handled, as we have to check for nil explicitly now anyway. Saves about 0.8% in the binary size of the go tool. Change-Id: I8501b62d72fde43650b79f52b5f699f1fbd0e7e7 Reviewed-on: https://go-review.googlesource.com/19814 Run-TryBot: Keith Randall TryBot-Result: Gobot Gobot Reviewed-by: Josh Bleecher Snyder --- src/cmd/compile/internal/gc/builtin.go | 2 - .../compile/internal/gc/builtin/runtime.go | 2 - src/cmd/compile/internal/gc/swt.go | 76 +++++++++++++------ src/runtime/iface.go | 16 ---- 4 files changed, 53 insertions(+), 43 deletions(-) diff --git a/src/cmd/compile/internal/gc/builtin.go b/src/cmd/compile/internal/gc/builtin.go index 7583e8fa13..4a6e56fe47 100644 --- a/src/cmd/compile/internal/gc/builtin.go +++ b/src/cmd/compile/internal/gc/builtin.go @@ -66,8 +66,6 @@ const runtimeimport = "" + "func @\"\".panicdottype (@\"\".have·1 *byte, @\"\".want·2 *byte, @\"\".iface·3 *byte)\n" + "func @\"\".ifaceeq (@\"\".i1·2 any, @\"\".i2·3 any) (@\"\".ret·1 bool)\n" + "func @\"\".efaceeq (@\"\".i1·2 any, @\"\".i2·3 any) (@\"\".ret·1 bool)\n" + - "func @\"\".ifacethash (@\"\".i1·2 any) (@\"\".ret·1 uint32)\n" + - "func @\"\".efacethash (@\"\".i1·2 any) (@\"\".ret·1 uint32)\n" + "func @\"\".makemap (@\"\".mapType·2 *byte, @\"\".hint·3 int64, @\"\".mapbuf·4 *any, @\"\".bucketbuf·5 *any) (@\"\".hmap·1 map[any]any)\n" + "func @\"\".mapaccess1 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 *any) (@\"\".val·1 *any)\n" + "func @\"\".mapaccess1_fast32 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n" + diff --git a/src/cmd/compile/internal/gc/builtin/runtime.go b/src/cmd/compile/internal/gc/builtin/runtime.go index 08f925f41c..0fe6242e74 100644 --- a/src/cmd/compile/internal/gc/builtin/runtime.go +++ b/src/cmd/compile/internal/gc/builtin/runtime.go @@ -83,8 +83,6 @@ func panicdottype(have, want, iface *byte) func ifaceeq(i1 any, i2 any) (ret bool) func efaceeq(i1 any, i2 any) (ret bool) -func ifacethash(i1 any) (ret uint32) -func efacethash(i1 any) (ret uint32) // *byte is really *runtime.Type func makemap(mapType *byte, hint int64, mapbuf *any, bucketbuf *any) (hmap map[any]any) diff --git a/src/cmd/compile/internal/gc/swt.go b/src/cmd/compile/internal/gc/swt.go index f0433f3df7..661b3ee5a9 100644 --- a/src/cmd/compile/internal/gc/swt.go +++ b/src/cmd/compile/internal/gc/swt.go @@ -549,20 +549,6 @@ func (s *typeSwitch) walk(sw *Node) { // set up labels and jumps casebody(sw, s.facename) - // calculate type hash - t := cond.Right.Type - if isnilinter(t) { - a = syslook("efacethash", 1) - } else { - a = syslook("ifacethash", 1) - } - substArgTypes(a, t) - a = Nod(OCALL, a, nil) - a.List = list1(s.facename) - a = Nod(OAS, s.hashname, a) - typecheck(&a, Etop) - cas = list(cas, a) - cc := caseClauses(sw, switchKindType) sw.List = nil var def *Node @@ -572,22 +558,66 @@ func (s *typeSwitch) walk(sw *Node) { } else { def = Nod(OBREAK, nil, nil) } + var typenil *Node + if len(cc) > 0 && cc[0].typ == caseKindTypeNil { + typenil = cc[0].node.Right + cc = cc[1:] + } + + // For empty interfaces, do: + // if e._type == nil { + // do nil case if it exists, otherwise default + // } + // h := e._type.hash + // Use a similar strategy for non-empty interfaces. + + // Get interface descriptor word. + typ := Nod(OITAB, s.facename, nil) + + // Check for nil first. + i := Nod(OIF, nil, nil) + i.Left = Nod(OEQ, typ, nodnil()) + if typenil != nil { + // Do explicit nil case right here. + i.Nbody = list1(typenil) + } else { + // Jump to default case. + lbl := newCaseLabel() + i.Nbody = list1(Nod(OGOTO, lbl, nil)) + // Wrap default case with label. + blk := Nod(OBLOCK, nil, nil) + blk.List = list(list1(Nod(OLABEL, lbl, nil)), def) + def = blk + } + typecheck(&i.Left, Erv) + cas = list(cas, i) + + if !isnilinter(cond.Right.Type) { + // Load type from itab. + typ = Nod(ODOTPTR, typ, nil) + typ.Type = Ptrto(Types[TUINT8]) + typ.Typecheck = 1 + typ.Xoffset = int64(Widthptr) // offset of _type in runtime.itab + typ.Bounded = true // guaranteed not to fault + } + // Load hash from type. + h := Nod(ODOTPTR, typ, nil) + h.Type = Types[TUINT32] + h.Typecheck = 1 + h.Xoffset = int64(2 * Widthptr) // offset of hash in runtime._type + h.Bounded = true // guaranteed not to fault + a = Nod(OAS, s.hashname, h) + typecheck(&a, Etop) + cas = list(cas, a) // insert type equality check into each case block for _, c := range cc { n := c.node switch c.typ { - case caseKindTypeNil: - var v Val - v.U = new(NilVal) - a = Nod(OIF, nil, nil) - a.Left = Nod(OEQ, s.facename, nodlit(v)) - typecheck(&a.Left, Erv) - a.Nbody = list1(n.Right) // if i==nil { goto l } - n.Right = a - case caseKindTypeVar, caseKindTypeConst: n.Right = s.typeone(n) + default: + Fatalf("typeSwitch with bad kind: %d", c.typ) } } diff --git a/src/runtime/iface.go b/src/runtime/iface.go index 71dc865e07..50dff77e42 100644 --- a/src/runtime/iface.go +++ b/src/runtime/iface.go @@ -398,22 +398,6 @@ func assertE2E2(inter *interfacetype, e eface, r *eface) bool { return true } -func ifacethash(i iface) uint32 { - tab := i.tab - if tab == nil { - return 0 - } - return tab._type.hash -} - -func efacethash(e eface) uint32 { - t := e._type - if t == nil { - return 0 - } - return t.hash -} - func iterate_itabs(fn func(*itab)) { for _, h := range &hash { for ; h != nil; h = h.link { From f28bbb776a050cc3edca2bbe1241d81217a7a251 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 2 Nov 2015 10:46:58 -0800 Subject: [PATCH 095/117] cmd/compile: move hiter, hmap, and scase definitions into builtin.go Also eliminates per-maptype hiter and hmap types, since they're not really needed anyway. Update packages reflect and runtime accordingly. Reduces golang.org/x/tools/cmd/godoc's text segment by ~170kB: text data bss dec hex filename 13085702 140640 151520 13377862 cc2146 godoc.before 12915382 140640 151520 13207542 c987f6 godoc.after Updates #6853. Change-Id: I948b2bc1f22d477c1756204996b4e3e1fb568d81 Reviewed-on: https://go-review.googlesource.com/16610 Reviewed-by: Keith Randall --- src/cmd/compile/internal/gc/builtin.go | 10 +- .../compile/internal/gc/builtin/runtime.go | 49 +++++++++- src/cmd/compile/internal/gc/fmt.go | 8 -- src/cmd/compile/internal/gc/go.go | 4 +- src/cmd/compile/internal/gc/range.go | 22 +++-- src/cmd/compile/internal/gc/reflect.go | 94 +------------------ src/cmd/compile/internal/gc/select.go | 30 +----- src/cmd/compile/internal/gc/subr.go | 13 ++- src/cmd/compile/internal/gc/walk.go | 4 +- src/reflect/type.go | 1 - src/runtime/hashmap.go | 15 ++- src/runtime/runtime2.go | 2 - src/runtime/select.go | 4 +- src/runtime/type.go | 1 - 14 files changed, 94 insertions(+), 163 deletions(-) diff --git a/src/cmd/compile/internal/gc/builtin.go b/src/cmd/compile/internal/gc/builtin.go index 4a6e56fe47..d1827ef0fe 100644 --- a/src/cmd/compile/internal/gc/builtin.go +++ b/src/cmd/compile/internal/gc/builtin.go @@ -4,6 +4,10 @@ package gc const runtimeimport = "" + "package runtime safe\n" + + "type @\"\".hbucket uint8\n" + + "type @\"\".hmap struct { @\"\".count int; @\"\".flags uint8; B uint8; @\"\".hash0 uint32; @\"\".buckets *@\"\".hbucket; @\"\".oldbuckets *@\"\".hbucket; @\"\".nevacuate uintptr; @\"\".overflow *[2]*[]*@\"\".hbucket }\n" + + "type @\"\".hiter struct { @\"\".key *byte; @\"\".value *byte; @\"\".t *byte; @\"\".h *@\"\".hmap; @\"\".buckets *@\"\".hbucket; @\"\".bptr *@\"\".hbucket; @\"\".overflow [2]*[]*@\"\".hbucket; @\"\".startBucket uintptr; @\"\".offset uint8; @\"\".wrapped bool; B uint8; @\"\".i uint8; @\"\".bucket uintptr; @\"\".checkBucket uintptr }\n" + + "type @\"\".scase struct { @\"\".elem *byte; @\"\".c *byte; @\"\".pc uintptr; @\"\".kind uint16; @\"\".so uint16; @\"\".receivedp *bool; @\"\".releasetime int64 }\n" + "func @\"\".newobject (@\"\".typ·2 *byte) (? *any)\n" + "func @\"\".panicindex ()\n" + "func @\"\".panicslice ()\n" + @@ -66,7 +70,7 @@ const runtimeimport = "" + "func @\"\".panicdottype (@\"\".have·1 *byte, @\"\".want·2 *byte, @\"\".iface·3 *byte)\n" + "func @\"\".ifaceeq (@\"\".i1·2 any, @\"\".i2·3 any) (@\"\".ret·1 bool)\n" + "func @\"\".efaceeq (@\"\".i1·2 any, @\"\".i2·3 any) (@\"\".ret·1 bool)\n" + - "func @\"\".makemap (@\"\".mapType·2 *byte, @\"\".hint·3 int64, @\"\".mapbuf·4 *any, @\"\".bucketbuf·5 *any) (@\"\".hmap·1 map[any]any)\n" + + "func @\"\".makemap (@\"\".mapType·2 *byte, @\"\".hint·3 int64, @\"\".mapbuf·4 *@\"\".hmap, @\"\".bucketbuf·5 *any) (@\"\".hmap·1 map[any]any)\n" + "func @\"\".mapaccess1 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 *any) (@\"\".val·1 *any)\n" + "func @\"\".mapaccess1_fast32 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n" + "func @\"\".mapaccess1_fast64 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n" + @@ -76,9 +80,9 @@ const runtimeimport = "" + "func @\"\".mapaccess2_fast64 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n" + "func @\"\".mapaccess2_faststr (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n" + "func @\"\".mapassign1 (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 *any, @\"\".val·4 *any)\n" + - "func @\"\".mapiterinit (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".hiter·3 *any)\n" + + "func @\"\".mapiterinit (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".hiter·3 *@\"\".hiter)\n" + "func @\"\".mapdelete (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 *any)\n" + - "func @\"\".mapiternext (@\"\".hiter·1 *any)\n" + + "func @\"\".mapiternext (@\"\".hiter·1 *@\"\".hiter)\n" + "func @\"\".makechan (@\"\".chanType·2 *byte, @\"\".hint·3 int64) (@\"\".hchan·1 chan any)\n" + "func @\"\".chanrecv1 (@\"\".chanType·1 *byte, @\"\".hchan·2 <-chan any, @\"\".elem·3 *any)\n" + "func @\"\".chanrecv2 (@\"\".chanType·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any) (? bool)\n" + diff --git a/src/cmd/compile/internal/gc/builtin/runtime.go b/src/cmd/compile/internal/gc/builtin/runtime.go index 0fe6242e74..e067d0bfa8 100644 --- a/src/cmd/compile/internal/gc/builtin/runtime.go +++ b/src/cmd/compile/internal/gc/builtin/runtime.go @@ -12,6 +12,49 @@ package runtime // emitted by compiler, not referred to by go programs +type hbucket byte // placeholder + +// Changes here must also be made in src/runtime/hashmap.go. +type hmap struct { + count int + flags uint8 + B uint8 + hash0 uint32 + buckets *hbucket + oldbuckets *hbucket + nevacuate uintptr + overflow *[2]*[]*hbucket +} + +// Changes here must also be made in src/runtime/hashmap.go. +type hiter struct { + key *byte // field name known to walkrange + value *byte // field name known to walkrange + t *byte // *maptype + h *hmap + buckets *hbucket + bptr *hbucket + overflow [2]*[]*hbucket + startBucket uintptr + offset uint8 + wrapped bool + B uint8 + i uint8 + bucket uintptr + checkBucket uintptr +} + +// Changes here must also be made in src/runtime/select.go. +type scase struct { + elem *byte + c *byte + pc uintptr + kind uint16 + so uint16 + receivedp *bool + releasetime int64 +} + func newobject(typ *byte) *any func panicindex() func panicslice() @@ -85,7 +128,7 @@ func ifaceeq(i1 any, i2 any) (ret bool) func efaceeq(i1 any, i2 any) (ret bool) // *byte is really *runtime.Type -func makemap(mapType *byte, hint int64, mapbuf *any, bucketbuf *any) (hmap map[any]any) +func makemap(mapType *byte, hint int64, mapbuf *hmap, bucketbuf *any) (hmap map[any]any) func mapaccess1(mapType *byte, hmap map[any]any, key *any) (val *any) func mapaccess1_fast32(mapType *byte, hmap map[any]any, key any) (val *any) func mapaccess1_fast64(mapType *byte, hmap map[any]any, key any) (val *any) @@ -95,9 +138,9 @@ func mapaccess2_fast32(mapType *byte, hmap map[any]any, key any) (val *any, pres func mapaccess2_fast64(mapType *byte, hmap map[any]any, key any) (val *any, pres bool) func mapaccess2_faststr(mapType *byte, hmap map[any]any, key any) (val *any, pres bool) func mapassign1(mapType *byte, hmap map[any]any, key *any, val *any) -func mapiterinit(mapType *byte, hmap map[any]any, hiter *any) +func mapiterinit(mapType *byte, hmap map[any]any, hiter *hiter) func mapdelete(mapType *byte, hmap map[any]any, key *any) -func mapiternext(hiter *any) +func mapiternext(hiter *hiter) // *byte is really *runtime.Type func makechan(chanType *byte, hint int64) (hchan chan any) diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go index c0a1170839..91035b5d07 100644 --- a/src/cmd/compile/internal/gc/fmt.go +++ b/src/cmd/compile/internal/gc/fmt.go @@ -647,14 +647,6 @@ func typefmt(t *Type, flag int) string { return fmt.Sprintf("map.bucket[%v]%v", t.Map.Down, t.Map.Type) } - if t.Map.Hmap == t { - return fmt.Sprintf("map.hdr[%v]%v", t.Map.Down, t.Map.Type) - } - - if t.Map.Hiter == t { - return fmt.Sprintf("map.iter[%v]%v", t.Map.Down, t.Map.Type) - } - Yyerror("unknown internal map type") } diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go index 3923bc6e31..3c00f72ec1 100644 --- a/src/cmd/compile/internal/gc/go.go +++ b/src/cmd/compile/internal/gc/go.go @@ -191,9 +191,7 @@ type Type struct { // TMAP Bucket *Type // internal type representing a hash bucket - Hmap *Type // internal type representing a Hmap (map header object) - Hiter *Type // internal type representing hash iterator state - Map *Type // link from the above 3 internal types back to the map type. + Map *Type // link from hash bucket type back to the map type. Maplineno int32 // first use of TFORW as map key Embedlineno int32 // first use of TFORW as embedded type diff --git a/src/cmd/compile/internal/gc/range.go b/src/cmd/compile/internal/gc/range.go index 4386bcfeed..8c2eca20d4 100644 --- a/src/cmd/compile/internal/gc/range.go +++ b/src/cmd/compile/internal/gc/range.go @@ -223,24 +223,28 @@ func walkrange(n *Node) { case TMAP: ha := a - th := hiter(t) + th := syslook("hiter", 0).Type + keytype := t.Down + valtype := t.Type + hit := prealloc[n] hit.Type = th n.Left = nil - keyname := newname(th.Type.Sym) // depends on layout of iterator struct. See reflect.go:hiter - valname := newname(th.Type.Down.Sym) // ditto + + // These depend on hiter's field names. See builtin/runtime.go:hiter. + keyname := newname(Pkglookup("key", Runtimepkg)) + valname := newname(Pkglookup("value", Runtimepkg)) fn := syslook("mapiterinit", 1) - - substArgTypes(fn, t.Down, t.Type, th) + substArgTypes(fn, keytype, valtype) init = list(init, mkcall1(fn, nil, nil, typename(t), ha, Nod(OADDR, hit, nil))) n.Left = Nod(ONE, Nod(ODOT, hit, keyname), nodnil()) - fn = syslook("mapiternext", 1) - substArgTypes(fn, th) - n.Right = mkcall1(fn, nil, nil, Nod(OADDR, hit, nil)) + n.Right = mkcall("mapiternext", nil, nil, Nod(OADDR, hit, nil)) key := Nod(ODOT, hit, keyname) + key = Nod(OCONVNOP, key, nil) + key.Type = Ptrto(keytype) key = Nod(OIND, key, nil) if v1 == nil { body = nil @@ -248,6 +252,8 @@ func walkrange(n *Node) { body = list1(Nod(OAS, v1, key)) } else { val := Nod(ODOT, hit, valname) + val = Nod(OCONVNOP, val, nil) + val.Type = Ptrto(valtype) val = Nod(OIND, val, nil) a := Nod(OAS2, nil, nil) a.List = list(list1(v1), v2) diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go index 8693e3c112..369d015f19 100644 --- a/src/cmd/compile/internal/gc/reflect.go +++ b/src/cmd/compile/internal/gc/reflect.go @@ -149,92 +149,6 @@ func mapbucket(t *Type) *Type { return bucket } -// Builds a type representing a Hmap structure for the given map type. -// Make sure this stays in sync with ../../../../runtime/hashmap.go! -func hmap(t *Type) *Type { - if t.Hmap != nil { - return t.Hmap - } - - bucket := mapbucket(t) - var field [8]*Type - field[0] = makefield("count", Types[TINT]) - field[1] = makefield("flags", Types[TUINT8]) - field[2] = makefield("B", Types[TUINT8]) - field[3] = makefield("hash0", Types[TUINT32]) - field[4] = makefield("buckets", Ptrto(bucket)) - field[5] = makefield("oldbuckets", Ptrto(bucket)) - field[6] = makefield("nevacuate", Types[TUINTPTR]) - field[7] = makefield("overflow", Types[TUNSAFEPTR]) - - h := typ(TSTRUCT) - h.Noalg = true - h.Local = t.Local - h.Type = field[0] - for n := int32(0); n < int32(len(field)-1); n++ { - field[n].Down = field[n+1] - } - field[len(field)-1].Down = nil - dowidth(h) - t.Hmap = h - h.Map = t - return h -} - -func hiter(t *Type) *Type { - if t.Hiter != nil { - return t.Hiter - } - - // build a struct: - // hiter { - // key *Key - // val *Value - // t *MapType - // h *Hmap - // buckets *Bucket - // bptr *Bucket - // overflow0 unsafe.Pointer - // overflow1 unsafe.Pointer - // startBucket uintptr - // stuff uintptr - // bucket uintptr - // checkBucket uintptr - // } - // must match ../../../../runtime/hashmap.go:hiter. - var field [12]*Type - field[0] = makefield("key", Ptrto(t.Down)) - - field[1] = makefield("val", Ptrto(t.Type)) - field[2] = makefield("t", Ptrto(Types[TUINT8])) - field[3] = makefield("h", Ptrto(hmap(t))) - field[4] = makefield("buckets", Ptrto(mapbucket(t))) - field[5] = makefield("bptr", Ptrto(mapbucket(t))) - field[6] = makefield("overflow0", Types[TUNSAFEPTR]) - field[7] = makefield("overflow1", Types[TUNSAFEPTR]) - field[8] = makefield("startBucket", Types[TUINTPTR]) - field[9] = makefield("stuff", Types[TUINTPTR]) // offset+wrapped+B+I - field[10] = makefield("bucket", Types[TUINTPTR]) - field[11] = makefield("checkBucket", Types[TUINTPTR]) - - // build iterator struct holding the above fields - i := typ(TSTRUCT) - - i.Noalg = true - i.Type = field[0] - for n := int32(0); n < int32(len(field)-1); n++ { - field[n].Down = field[n+1] - } - field[len(field)-1].Down = nil - dowidth(i) - if i.Width != int64(12*Widthptr) { - Yyerror("hash_iter size not correct %d %d", i.Width, 12*Widthptr) - } - t.Hiter = i - i.Map = t - return i -} - // f is method type, with receiver. // return function type, receiver as first argument (or not). func methodfunc(f *Type, receiver *Type) *Type { @@ -1112,13 +1026,11 @@ ok: s2 := dtypesym(t.Type) s3 := dtypesym(mapbucket(t)) - s4 := dtypesym(hmap(t)) ot = dcommontype(s, ot, t) xt = ot - 2*Widthptr ot = dsymptr(s, ot, s1, 0) ot = dsymptr(s, ot, s2, 0) ot = dsymptr(s, ot, s3, 0) - ot = dsymptr(s, ot, s4, 0) if t.Down.Width > MAXKEYSIZE { ot = duint8(s, ot, uint8(Widthptr)) ot = duint8(s, ot, 1) // indirect @@ -1339,8 +1251,10 @@ func dalgsym(t *Type) *Sym { hashfunc = typesymprefix(".hashfunc", t) eqfunc = typesymprefix(".eqfunc", t) - genhash(hash, t) - geneq(eq, t) + if Debug['A'] == 0 { + genhash(hash, t) + geneq(eq, t) + } // make Go funcs (closures) for calling hash and equal from Go dsymptr(hashfunc, 0, hash, 0) diff --git a/src/cmd/compile/internal/gc/select.go b/src/cmd/compile/internal/gc/select.go index e770c8f18d..9a619a6d5a 100644 --- a/src/cmd/compile/internal/gc/select.go +++ b/src/cmd/compile/internal/gc/select.go @@ -318,35 +318,9 @@ out: lineno = int32(lno) } -// Keep in sync with src/runtime/runtime2.go and src/runtime/select.go. +// Keep in sync with src/runtime/select.go. func selecttype(size int32) *Type { - // TODO(dvyukov): it's possible to generate SudoG and Scase only once - // and then cache; and also cache Select per size. - sudog := Nod(OTSTRUCT, nil, nil) - - sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("g")), typenod(Ptrto(Types[TUINT8])))) - sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("selectdone")), typenod(Ptrto(Types[TUINT8])))) - sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("next")), typenod(Ptrto(Types[TUINT8])))) - sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("prev")), typenod(Ptrto(Types[TUINT8])))) - sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("elem")), typenod(Ptrto(Types[TUINT8])))) - sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("releasetime")), typenod(Types[TUINT64]))) - sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("nrelease")), typenod(Types[TINT32]))) - sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("waitlink")), typenod(Ptrto(Types[TUINT8])))) - typecheck(&sudog, Etype) - sudog.Type.Noalg = true - sudog.Type.Local = true - - scase := Nod(OTSTRUCT, nil, nil) - scase.List = list(scase.List, Nod(ODCLFIELD, newname(Lookup("elem")), typenod(Ptrto(Types[TUINT8])))) - scase.List = list(scase.List, Nod(ODCLFIELD, newname(Lookup("chan")), typenod(Ptrto(Types[TUINT8])))) - scase.List = list(scase.List, Nod(ODCLFIELD, newname(Lookup("pc")), typenod(Types[TUINTPTR]))) - scase.List = list(scase.List, Nod(ODCLFIELD, newname(Lookup("kind")), typenod(Types[TUINT16]))) - scase.List = list(scase.List, Nod(ODCLFIELD, newname(Lookup("so")), typenod(Types[TUINT16]))) - scase.List = list(scase.List, Nod(ODCLFIELD, newname(Lookup("receivedp")), typenod(Ptrto(Types[TUINT8])))) - scase.List = list(scase.List, Nod(ODCLFIELD, newname(Lookup("releasetime")), typenod(Types[TUINT64]))) - typecheck(&scase, Etype) - scase.Type.Noalg = true - scase.Type.Local = true + scase := syslook("scase", 0) sel := Nod(OTSTRUCT, nil, nil) sel.List = list(sel.List, Nod(ODCLFIELD, newname(Lookup("tcase")), typenod(Types[TUINT16]))) diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go index ba0a257b3b..f48b7cdc4f 100644 --- a/src/cmd/compile/internal/gc/subr.go +++ b/src/cmd/compile/internal/gc/subr.go @@ -1419,16 +1419,21 @@ func deep(t *Type) *Type { if t == nil { return nil } + if t.Etype == TANY { + nt := shallow(t) + nt.Copyany = true + return nt + } + if t.Sym != nil { + // share named types + return t + } var nt *Type switch t.Etype { default: nt = t // share from here down - case TANY: - nt = shallow(t) - nt.Copyany = true - case TPTR32, TPTR64, TCHAN, TARRAY: nt = shallow(t) nt.Type = deep(t.Type) diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index f324d5e00f..f3112c3a61 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -1375,7 +1375,7 @@ opswitch: r := nodnil() // bucket buffer if n.Esc == EscNone { // Allocate hmap buffer on stack. - var_ := temp(hmap(t)) + var_ := temp(syslook("hmap", 0).Type) a = Nod(OAS, var_, nil) // zero temp typecheck(&a, Etop) @@ -1393,7 +1393,7 @@ opswitch: r = Nod(OADDR, var_, nil) } - substArgTypes(fn, hmap(t), mapbucket(t), t.Down, t.Type) + substArgTypes(fn, mapbucket(t), t.Down, t.Type) n = mkcall1(fn, n.Type, init, typename(n.Type), conv(n.Left, Types[TINT64]), a, r) case OMAKESLICE: diff --git a/src/reflect/type.go b/src/reflect/type.go index 003c610cb1..91563dcf7e 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -340,7 +340,6 @@ type mapType struct { key *rtype // map key type elem *rtype // map element (value) type bucket *rtype // internal bucket structure - hmap *rtype // internal map header keysize uint8 // size of key slot indirectkey uint8 // store ptr to key instead of key itself valuesize uint8 // size of value slot diff --git a/src/runtime/hashmap.go b/src/runtime/hashmap.go index 892a79a914..fcfcd4b607 100644 --- a/src/runtime/hashmap.go +++ b/src/runtime/hashmap.go @@ -102,6 +102,7 @@ const ( ) // A header for a Go map. +// Changes here must also be made in src/cmd/compile/internal/gc/builtin/runtime.go. type hmap struct { // Note: the format of the Hmap is encoded in ../../cmd/internal/gc/reflect.go and // ../reflect/type.go. Don't change this structure without also changing that code! @@ -137,11 +138,10 @@ type bmap struct { } // A hash iteration structure. -// If you modify hiter, also change cmd/internal/gc/reflect.go to indicate -// the layout of this structure. +// Changes here must also be made in src/cmd/compile/internal/gc/builtin/runtime.go. type hiter struct { - key unsafe.Pointer // Must be in first position. Write nil to indicate iteration end (see cmd/internal/gc/range.go). - value unsafe.Pointer // Must be in second position (see cmd/internal/gc/range.go). + key unsafe.Pointer // Write nil to indicate iteration end (see cmd/compile/internal/gc/range.go). + value unsafe.Pointer t *maptype h *hmap buckets unsafe.Pointer // bucket ptr at hash_iter initialization time @@ -188,11 +188,10 @@ func (h *hmap) createOverflow() { // If h != nil, the map can be created directly in h. // If bucket != nil, bucket can be used as the first bucket. func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap { - if sz := unsafe.Sizeof(hmap{}); sz > 48 || sz != uintptr(t.hmap.size) { - println("runtime: sizeof(hmap) =", sz, ", t.hmap.size =", t.hmap.size) + if sz := unsafe.Sizeof(hmap{}); sz > 48 { + println("runtime: sizeof(hmap) =", sz) throw("bad hmap size") } - if hint < 0 || int64(int32(hint)) != hint { panic("makemap: size out of range") // TODO: make hint an int, then none of this nonsense @@ -254,7 +253,7 @@ func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap { // initialize Hmap if h == nil { - h = (*hmap)(newobject(t.hmap)) + h = &hmap{} } h.count = 0 h.B = B diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go index 917fe89d38..379fe2678b 100644 --- a/src/runtime/runtime2.go +++ b/src/runtime/runtime2.go @@ -160,8 +160,6 @@ type gobuf struct { bp uintptr // for GOEXPERIMENT=framepointer } -// Known to compiler. -// Changes here must also be made in src/cmd/internal/gc/select.go's selecttype. type sudog struct { g *g selectdone *uint32 diff --git a/src/runtime/select.go b/src/runtime/select.go index b6c3fea001..25ebdaa595 100644 --- a/src/runtime/select.go +++ b/src/runtime/select.go @@ -22,7 +22,7 @@ const ( // Select statement header. // Known to compiler. -// Changes here must also be made in src/cmd/internal/gc/select.go's selecttype. +// Changes here must also be made in src/cmd/compile/internal/gc/select.go's selecttype. type hselect struct { tcase uint16 // total count of scase[] ncase uint16 // currently filled scase[] @@ -33,7 +33,7 @@ type hselect struct { // Select case descriptor. // Known to compiler. -// Changes here must also be made in src/cmd/internal/gc/select.go's selecttype. +// Changes here must also be made in src/cmd/compile/internal/gc/builtin/runtime.go. type scase struct { elem unsafe.Pointer // data element c *hchan // chan diff --git a/src/runtime/type.go b/src/runtime/type.go index d5f3bb1ef0..8350976491 100644 --- a/src/runtime/type.go +++ b/src/runtime/type.go @@ -60,7 +60,6 @@ type maptype struct { key *_type elem *_type bucket *_type // internal type representing a hash bucket - hmap *_type // internal type representing a hmap keysize uint8 // size of key slot indirectkey bool // store ptr to key instead of key itself valuesize uint8 // size of value slot From 028247d2cd82243b44b00c5da477f971112e5ff9 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Thu, 11 Jun 2015 13:56:28 -0700 Subject: [PATCH 096/117] cmd/compile: reuse []Flow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Benchmarked using compilebench on a quiet but rather old OS X laptop. Benchmarks from others would be welcome, since the numbers look too good to be true. name old time/op new time/op delta Template 331ms ± 9% 303ms ± 4% -8.25% (p=0.000 n=24+24) GoTypes 946ms ± 4% 888ms ± 3% -6.17% (p=0.000 n=24+25) Compiler 3.20s ± 1% 3.10s ± 2% -3.07% (p=0.000 n=24+25) name old alloc/op new alloc/op delta Template 72.5MB ± 0% 61.8MB ± 0% -14.76% (p=0.000 n=25+24) GoTypes 224MB ± 0% 189MB ± 0% -15.65% (p=0.000 n=25+25) Compiler 695MB ± 0% 561MB ± 0% -19.26% (p=0.000 n=25+25) name old allocs/op new allocs/op delta Template 498k ± 0% 497k ± 0% -0.21% (p=0.000 n=25+23) GoTypes 1.47M ± 0% 1.47M ± 0% -0.25% (p=0.000 n=25+25) Compiler 4.09M ± 0% 4.08M ± 0% -0.18% (p=0.000 n=25+23) Change-Id: I2394bc748128d721863453257fa5756c410f7898 Reviewed-on: https://go-review.googlesource.com/19771 Reviewed-by: Russ Cox Run-TryBot: Russ Cox TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/gc/popt.go | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/gc/popt.go b/src/cmd/compile/internal/gc/popt.go index 4d71ab643d..b708222845 100644 --- a/src/cmd/compile/internal/gc/popt.go +++ b/src/cmd/compile/internal/gc/popt.go @@ -241,6 +241,19 @@ var flowmark int // will not have flow graphs and consequently will not be optimized. const MaxFlowProg = 50000 +var ffcache []Flow // reusable []Flow, to reduce allocation + +func growffcache(n int) { + if n > cap(ffcache) { + n = (n * 5) / 4 + if n > MaxFlowProg { + n = MaxFlowProg + } + ffcache = make([]Flow, n) + } + ffcache = ffcache[:n] +} + func Flowstart(firstp *obj.Prog, newData func() interface{}) *Graph { // Count and mark instructions to annotate. nf := 0 @@ -268,7 +281,9 @@ func Flowstart(firstp *obj.Prog, newData func() interface{}) *Graph { // Allocate annotations and assign to instructions. graph := new(Graph) - ff := make([]Flow, nf) + + growffcache(nf) + ff := ffcache start := &ff[0] id := 0 var last *Flow @@ -331,6 +346,10 @@ func Flowend(graph *Graph) { f.Prog.Info.Flags = 0 // drop cached proginfo f.Prog.Opt = nil } + clear := ffcache[:graph.Num] + for i := range clear { + clear[i] = Flow{} + } } // find looping structure From f39cca94af880253be22cdbb30d0a7d385f6b516 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 2 Feb 2016 10:14:36 -0800 Subject: [PATCH 097/117] cmd/compile: bring vendored copy of math/big up-to-date These files were not added to the repo. They contain conversion routines and corresponding tests not used by the compiler and thus are technically not needed. However, future changes to math/big (and corresponding updates of this vendored version) may require these files to exist. Add them to avoid unnecessary confusion. Change-Id: Ie390fb54f499463b2bba2fdc084967539afbeeb3 Reviewed-on: https://go-review.googlesource.com/19730 Reviewed-by: Alan Donovan --- .../compile/internal/big/example_rat_test.go | 65 +++++++++ src/cmd/compile/internal/big/floatmarsh.go | 33 +++++ .../compile/internal/big/floatmarsh_test.go | 54 ++++++++ src/cmd/compile/internal/big/intmarsh.go | 74 +++++++++++ src/cmd/compile/internal/big/intmarsh_test.go | 121 +++++++++++++++++ src/cmd/compile/internal/big/ratmarsh.go | 73 ++++++++++ src/cmd/compile/internal/big/ratmarsh_test.go | 125 ++++++++++++++++++ 7 files changed, 545 insertions(+) create mode 100644 src/cmd/compile/internal/big/example_rat_test.go create mode 100644 src/cmd/compile/internal/big/floatmarsh.go create mode 100644 src/cmd/compile/internal/big/floatmarsh_test.go create mode 100644 src/cmd/compile/internal/big/intmarsh.go create mode 100644 src/cmd/compile/internal/big/intmarsh_test.go create mode 100644 src/cmd/compile/internal/big/ratmarsh.go create mode 100644 src/cmd/compile/internal/big/ratmarsh_test.go diff --git a/src/cmd/compile/internal/big/example_rat_test.go b/src/cmd/compile/internal/big/example_rat_test.go new file mode 100644 index 0000000000..ef0649785a --- /dev/null +++ b/src/cmd/compile/internal/big/example_rat_test.go @@ -0,0 +1,65 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package big_test + +import ( + "cmd/compile/internal/big" + "fmt" +) + +// Use the classic continued fraction for e +// e = [1; 0, 1, 1, 2, 1, 1, ... 2n, 1, 1, ...] +// i.e., for the nth term, use +// 1 if n mod 3 != 1 +// (n-1)/3 * 2 if n mod 3 == 1 +func recur(n, lim int64) *big.Rat { + term := new(big.Rat) + if n%3 != 1 { + term.SetInt64(1) + } else { + term.SetInt64((n - 1) / 3 * 2) + } + + if n > lim { + return term + } + + // Directly initialize frac as the fractional + // inverse of the result of recur. + frac := new(big.Rat).Inv(recur(n+1, lim)) + + return term.Add(term, frac) +} + +// This example demonstrates how to use big.Rat to compute the +// first 15 terms in the sequence of rational convergents for +// the constant e (base of natural logarithm). +func Example_eConvergents() { + for i := 1; i <= 15; i++ { + r := recur(0, int64(i)) + + // Print r both as a fraction and as a floating-point number. + // Since big.Rat implements fmt.Formatter, we can use %-13s to + // get a left-aligned string representation of the fraction. + fmt.Printf("%-13s = %s\n", r, r.FloatString(8)) + } + + // Output: + // 2/1 = 2.00000000 + // 3/1 = 3.00000000 + // 8/3 = 2.66666667 + // 11/4 = 2.75000000 + // 19/7 = 2.71428571 + // 87/32 = 2.71875000 + // 106/39 = 2.71794872 + // 193/71 = 2.71830986 + // 1264/465 = 2.71827957 + // 1457/536 = 2.71828358 + // 2721/1001 = 2.71828172 + // 23225/8544 = 2.71828184 + // 25946/9545 = 2.71828182 + // 49171/18089 = 2.71828183 + // 517656/190435 = 2.71828183 +} diff --git a/src/cmd/compile/internal/big/floatmarsh.go b/src/cmd/compile/internal/big/floatmarsh.go new file mode 100644 index 0000000000..44987ee03a --- /dev/null +++ b/src/cmd/compile/internal/big/floatmarsh.go @@ -0,0 +1,33 @@ +// 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. + +// This file implements encoding/decoding of Floats. + +package big + +import "fmt" + +// MarshalText implements the encoding.TextMarshaler interface. +// Only the Float value is marshaled (in full precision), other +// attributes such as precision or accuracy are ignored. +func (x *Float) MarshalText() (text []byte, err error) { + if x == nil { + return []byte(""), nil + } + var buf []byte + return x.Append(buf, 'g', -1), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface. +// The result is rounded per the precision and rounding mode of z. +// If z's precision is 0, it is changed to 64 before rounding takes +// effect. +func (z *Float) UnmarshalText(text []byte) error { + // TODO(gri): get rid of the []byte/string conversion + _, _, err := z.Parse(string(text), 0) + if err != nil { + err = fmt.Errorf("math/big: cannot unmarshal %q into a *big.Float (%v)", text, err) + } + return err +} diff --git a/src/cmd/compile/internal/big/floatmarsh_test.go b/src/cmd/compile/internal/big/floatmarsh_test.go new file mode 100644 index 0000000000..d7ef2fca68 --- /dev/null +++ b/src/cmd/compile/internal/big/floatmarsh_test.go @@ -0,0 +1,54 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package big + +import ( + "encoding/json" + "testing" +) + +var floatVals = []string{ + "0", + "1", + "0.1", + "2.71828", + "1234567890", + "3.14e1234", + "3.14e-1234", + "0.738957395793475734757349579759957975985497e100", + "0.73895739579347546656564656573475734957975995797598589749859834759476745986795497e100", + "inf", + "Inf", +} + +func TestFloatJSONEncoding(t *testing.T) { + for _, test := range floatVals { + for _, sign := range []string{"", "+", "-"} { + for _, prec := range []uint{0, 1, 2, 10, 53, 64, 100, 1000} { + x := sign + test + var tx Float + _, _, err := tx.SetPrec(prec).Parse(x, 0) + if err != nil { + t.Errorf("parsing of %s (prec = %d) failed (invalid test case): %v", x, prec, err) + continue + } + b, err := json.Marshal(&tx) + if err != nil { + t.Errorf("marshaling of %v (prec = %d) failed: %v", &tx, prec, err) + continue + } + var rx Float + rx.SetPrec(prec) + if err := json.Unmarshal(b, &rx); err != nil { + t.Errorf("unmarshaling of %v (prec = %d) failed: %v", &tx, prec, err) + continue + } + if rx.Cmp(&tx) != 0 { + t.Errorf("JSON encoding of %v (prec = %d) failed: got %v want %v", &tx, prec, &rx, &tx) + } + } + } + } +} diff --git a/src/cmd/compile/internal/big/intmarsh.go b/src/cmd/compile/internal/big/intmarsh.go new file mode 100644 index 0000000000..4ff57b6464 --- /dev/null +++ b/src/cmd/compile/internal/big/intmarsh.go @@ -0,0 +1,74 @@ +// 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. + +// This file implements encoding/decoding of Ints. + +package big + +import "fmt" + +// Gob codec version. Permits backward-compatible changes to the encoding. +const intGobVersion byte = 1 + +// GobEncode implements the gob.GobEncoder interface. +func (x *Int) GobEncode() ([]byte, error) { + if x == nil { + return nil, nil + } + buf := make([]byte, 1+len(x.abs)*_S) // extra byte for version and sign bit + i := x.abs.bytes(buf) - 1 // i >= 0 + b := intGobVersion << 1 // make space for sign bit + if x.neg { + b |= 1 + } + buf[i] = b + return buf[i:], nil +} + +// GobDecode implements the gob.GobDecoder interface. +func (z *Int) GobDecode(buf []byte) error { + if len(buf) == 0 { + // Other side sent a nil or default value. + *z = Int{} + return nil + } + b := buf[0] + if b>>1 != intGobVersion { + return fmt.Errorf("Int.GobDecode: encoding version %d not supported", b>>1) + } + z.neg = b&1 != 0 + z.abs = z.abs.setBytes(buf[1:]) + return nil +} + +// MarshalText implements the encoding.TextMarshaler interface. +func (x *Int) MarshalText() (text []byte, err error) { + if x == nil { + return []byte(""), nil + } + return x.abs.itoa(x.neg, 10), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface. +func (z *Int) UnmarshalText(text []byte) error { + // TODO(gri): get rid of the []byte/string conversion + if _, ok := z.SetString(string(text), 0); !ok { + return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text) + } + return nil +} + +// The JSON marshallers are only here for API backward compatibility +// (programs that explicitly look for these two methods). JSON works +// fine with the TextMarshaler only. + +// MarshalJSON implements the json.Marshaler interface. +func (x *Int) MarshalJSON() ([]byte, error) { + return x.MarshalText() +} + +// UnmarshalJSON implements the json.Unmarshaler interface. +func (z *Int) UnmarshalJSON(text []byte) error { + return z.UnmarshalText(text) +} diff --git a/src/cmd/compile/internal/big/intmarsh_test.go b/src/cmd/compile/internal/big/intmarsh_test.go new file mode 100644 index 0000000000..f82956ceaf --- /dev/null +++ b/src/cmd/compile/internal/big/intmarsh_test.go @@ -0,0 +1,121 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package big + +import ( + "bytes" + "encoding/gob" + "encoding/json" + "encoding/xml" + "testing" +) + +var encodingTests = []string{ + "0", + "1", + "2", + "10", + "1000", + "1234567890", + "298472983472983471903246121093472394872319615612417471234712061", +} + +func TestIntGobEncoding(t *testing.T) { + var medium bytes.Buffer + enc := gob.NewEncoder(&medium) + dec := gob.NewDecoder(&medium) + for _, test := range encodingTests { + for _, sign := range []string{"", "+", "-"} { + x := sign + test + medium.Reset() // empty buffer for each test case (in case of failures) + var tx Int + tx.SetString(x, 10) + if err := enc.Encode(&tx); err != nil { + t.Errorf("encoding of %s failed: %s", &tx, err) + continue + } + var rx Int + if err := dec.Decode(&rx); err != nil { + t.Errorf("decoding of %s failed: %s", &tx, err) + continue + } + if rx.Cmp(&tx) != 0 { + t.Errorf("transmission of %s failed: got %s want %s", &tx, &rx, &tx) + } + } + } +} + +// Sending a nil Int pointer (inside a slice) on a round trip through gob should yield a zero. +// TODO: top-level nils. +func TestGobEncodingNilIntInSlice(t *testing.T) { + buf := new(bytes.Buffer) + enc := gob.NewEncoder(buf) + dec := gob.NewDecoder(buf) + + var in = make([]*Int, 1) + err := enc.Encode(&in) + if err != nil { + t.Errorf("gob encode failed: %q", err) + } + var out []*Int + err = dec.Decode(&out) + if err != nil { + t.Fatalf("gob decode failed: %q", err) + } + if len(out) != 1 { + t.Fatalf("wrong len; want 1 got %d", len(out)) + } + var zero Int + if out[0].Cmp(&zero) != 0 { + t.Fatalf("transmission of (*Int)(nil) failed: got %s want 0", out) + } +} + +func TestIntJSONEncoding(t *testing.T) { + for _, test := range encodingTests { + for _, sign := range []string{"", "+", "-"} { + x := sign + test + var tx Int + tx.SetString(x, 10) + b, err := json.Marshal(&tx) + if err != nil { + t.Errorf("marshaling of %s failed: %s", &tx, err) + continue + } + var rx Int + if err := json.Unmarshal(b, &rx); err != nil { + t.Errorf("unmarshaling of %s failed: %s", &tx, err) + continue + } + if rx.Cmp(&tx) != 0 { + t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx) + } + } + } +} + +func TestIntXMLEncoding(t *testing.T) { + for _, test := range encodingTests { + for _, sign := range []string{"", "+", "-"} { + x := sign + test + var tx Int + tx.SetString(x, 0) + b, err := xml.Marshal(&tx) + if err != nil { + t.Errorf("marshaling of %s failed: %s", &tx, err) + continue + } + var rx Int + if err := xml.Unmarshal(b, &rx); err != nil { + t.Errorf("unmarshaling of %s failed: %s", &tx, err) + continue + } + if rx.Cmp(&tx) != 0 { + t.Errorf("XML encoding of %s failed: got %s want %s", &tx, &rx, &tx) + } + } + } +} diff --git a/src/cmd/compile/internal/big/ratmarsh.go b/src/cmd/compile/internal/big/ratmarsh.go new file mode 100644 index 0000000000..b82e8d4ae8 --- /dev/null +++ b/src/cmd/compile/internal/big/ratmarsh.go @@ -0,0 +1,73 @@ +// 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. + +// This file implements encoding/decoding of Rats. + +package big + +import ( + "encoding/binary" + "errors" + "fmt" +) + +// Gob codec version. Permits backward-compatible changes to the encoding. +const ratGobVersion byte = 1 + +// GobEncode implements the gob.GobEncoder interface. +func (x *Rat) GobEncode() ([]byte, error) { + if x == nil { + return nil, nil + } + buf := make([]byte, 1+4+(len(x.a.abs)+len(x.b.abs))*_S) // extra bytes for version and sign bit (1), and numerator length (4) + i := x.b.abs.bytes(buf) + j := x.a.abs.bytes(buf[:i]) + n := i - j + if int(uint32(n)) != n { + // this should never happen + return nil, errors.New("Rat.GobEncode: numerator too large") + } + binary.BigEndian.PutUint32(buf[j-4:j], uint32(n)) + j -= 1 + 4 + b := ratGobVersion << 1 // make space for sign bit + if x.a.neg { + b |= 1 + } + buf[j] = b + return buf[j:], nil +} + +// GobDecode implements the gob.GobDecoder interface. +func (z *Rat) GobDecode(buf []byte) error { + if len(buf) == 0 { + // Other side sent a nil or default value. + *z = Rat{} + return nil + } + b := buf[0] + if b>>1 != ratGobVersion { + return fmt.Errorf("Rat.GobDecode: encoding version %d not supported", b>>1) + } + const j = 1 + 4 + i := j + binary.BigEndian.Uint32(buf[j-4:j]) + z.a.neg = b&1 != 0 + z.a.abs = z.a.abs.setBytes(buf[j:i]) + z.b.abs = z.b.abs.setBytes(buf[i:]) + return nil +} + +// MarshalText implements the encoding.TextMarshaler interface. +func (x *Rat) MarshalText() (text []byte, err error) { + // TODO(gri): get rid of the []byte/string conversion + return []byte(x.RatString()), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface. +func (z *Rat) UnmarshalText(text []byte) error { + // TODO(gri): get rid of the []byte/string conversion + if _, ok := z.SetString(string(text)); !ok { + return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Rat", text) + } + return nil +} diff --git a/src/cmd/compile/internal/big/ratmarsh_test.go b/src/cmd/compile/internal/big/ratmarsh_test.go new file mode 100644 index 0000000000..351d109f8d --- /dev/null +++ b/src/cmd/compile/internal/big/ratmarsh_test.go @@ -0,0 +1,125 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package big + +import ( + "bytes" + "encoding/gob" + "encoding/json" + "encoding/xml" + "testing" +) + +func TestRatGobEncoding(t *testing.T) { + var medium bytes.Buffer + enc := gob.NewEncoder(&medium) + dec := gob.NewDecoder(&medium) + for _, test := range encodingTests { + medium.Reset() // empty buffer for each test case (in case of failures) + var tx Rat + tx.SetString(test + ".14159265") + if err := enc.Encode(&tx); err != nil { + t.Errorf("encoding of %s failed: %s", &tx, err) + continue + } + var rx Rat + if err := dec.Decode(&rx); err != nil { + t.Errorf("decoding of %s failed: %s", &tx, err) + continue + } + if rx.Cmp(&tx) != 0 { + t.Errorf("transmission of %s failed: got %s want %s", &tx, &rx, &tx) + } + } +} + +// Sending a nil Rat pointer (inside a slice) on a round trip through gob should yield a zero. +// TODO: top-level nils. +func TestGobEncodingNilRatInSlice(t *testing.T) { + buf := new(bytes.Buffer) + enc := gob.NewEncoder(buf) + dec := gob.NewDecoder(buf) + + var in = make([]*Rat, 1) + err := enc.Encode(&in) + if err != nil { + t.Errorf("gob encode failed: %q", err) + } + var out []*Rat + err = dec.Decode(&out) + if err != nil { + t.Fatalf("gob decode failed: %q", err) + } + if len(out) != 1 { + t.Fatalf("wrong len; want 1 got %d", len(out)) + } + var zero Rat + if out[0].Cmp(&zero) != 0 { + t.Fatalf("transmission of (*Int)(nil) failed: got %s want 0", out) + } +} + +var ratNums = []string{ + "-141592653589793238462643383279502884197169399375105820974944592307816406286", + "-1415926535897932384626433832795028841971", + "-141592653589793", + "-1", + "0", + "1", + "141592653589793", + "1415926535897932384626433832795028841971", + "141592653589793238462643383279502884197169399375105820974944592307816406286", +} + +var ratDenoms = []string{ + "1", + "718281828459045", + "7182818284590452353602874713526624977572", + "718281828459045235360287471352662497757247093699959574966967627724076630353", +} + +func TestRatJSONEncoding(t *testing.T) { + for _, num := range ratNums { + for _, denom := range ratDenoms { + var tx Rat + tx.SetString(num + "/" + denom) + b, err := json.Marshal(&tx) + if err != nil { + t.Errorf("marshaling of %s failed: %s", &tx, err) + continue + } + var rx Rat + if err := json.Unmarshal(b, &rx); err != nil { + t.Errorf("unmarshaling of %s failed: %s", &tx, err) + continue + } + if rx.Cmp(&tx) != 0 { + t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx) + } + } + } +} + +func TestRatXMLEncoding(t *testing.T) { + for _, num := range ratNums { + for _, denom := range ratDenoms { + var tx Rat + tx.SetString(num + "/" + denom) + b, err := xml.Marshal(&tx) + if err != nil { + t.Errorf("marshaling of %s failed: %s", &tx, err) + continue + } + var rx Rat + if err := xml.Unmarshal(b, &rx); err != nil { + t.Errorf("unmarshaling of %s failed: %s", &tx, err) + continue + } + if rx.Cmp(&tx) != 0 { + t.Errorf("XML encoding of %s failed: got %s want %s", &tx, &rx, &tx) + } + } + } +} From e7f6d8b2d7baf2aa299c8bce778e2b0dab3a3798 Mon Sep 17 00:00:00 2001 From: Caio Marcelo de Oliveira Filho Date: Sat, 20 Feb 2016 23:23:01 -0300 Subject: [PATCH 098/117] cmd/cover: don't overskip children nodes when adding counters When visiting the AST to add counters, there are special cases in which the code calls cuts the walking short by returning nil. In some cases certain nodes are ignored, e.g. Init and Cond inside IfStmt. The fix is to explicitly walk all the children nodes (not only Body and Else) when cutting the current walk. Similar approach was taken with SwitchStmt and TypeSwitchStmt. While the existing test code doesn't handle different counters in the same line, the generated HTML report does it correctly (because it takes column into account). The previous behavior caused lines in function literals to not be tracked when those literals were inside Init or Cond of an IfStmt for example. Fixes #14039. Change-Id: Iad591363330843ad833bd79a0388d709c8d0c8aa Reviewed-on: https://go-review.googlesource.com/19775 Reviewed-by: Rob Pike --- src/cmd/cover/cover.go | 14 ++++++++++++++ src/cmd/cover/testdata/test.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/src/cmd/cover/cover.go b/src/cmd/cover/cover.go index 31ec434546..c5d1682651 100644 --- a/src/cmd/cover/cover.go +++ b/src/cmd/cover/cover.go @@ -181,6 +181,10 @@ func (f *File) Visit(node ast.Node) ast.Visitor { } n.List = f.addCounters(n.Lbrace, n.Rbrace+1, n.List, true) // +1 to step past closing brace. case *ast.IfStmt: + if n.Init != nil { + ast.Walk(f, n.Init) + } + ast.Walk(f, n.Cond) ast.Walk(f, n.Body) if n.Else == nil { return nil @@ -219,11 +223,21 @@ func (f *File) Visit(node ast.Node) ast.Visitor { case *ast.SwitchStmt: // Don't annotate an empty switch - creates a syntax error. if n.Body == nil || len(n.Body.List) == 0 { + if n.Init != nil { + ast.Walk(f, n.Init) + } + if n.Tag != nil { + ast.Walk(f, n.Tag) + } return nil } case *ast.TypeSwitchStmt: // Don't annotate an empty type switch - creates a syntax error. if n.Body == nil || len(n.Body.List) == 0 { + if n.Init != nil { + ast.Walk(f, n.Init) + } + ast.Walk(f, n.Assign) return nil } } diff --git a/src/cmd/cover/testdata/test.go b/src/cmd/cover/testdata/test.go index 9013950a2b..c4c0e15b0b 100644 --- a/src/cmd/cover/testdata/test.go +++ b/src/cmd/cover/testdata/test.go @@ -24,6 +24,7 @@ func testAll() { testSelect2() testPanic() testEmptySwitches() + testFunctionLiteral() } // The indexes of the counters in testPanic are known to main.go @@ -216,3 +217,32 @@ func testEmptySwitches() { <-c check(LINE, 1) } + +func testFunctionLiteral() { + a := func(f func()) error { + f() + f() + return nil + } + + b := func(f func()) bool { + f() + f() + return true + } + + check(LINE, 1) + a(func() { + check(LINE, 2) + }) + + if err := a(func() { + check(LINE, 2) + }); err != nil { + } + + switch b(func() { + check(LINE, 2) + }) { + } +} From 36694064e52c721b337f882473280b7da8282d1f Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Mon, 4 May 2015 18:16:50 -0700 Subject: [PATCH 099/117] cmd/compile: disable checknils during alg eq generation Cuts 20k off cmd/go and 32k off golang.org/x/tools/cmd/godoc, approx 0.15% each. For #6853 and #9930 Change-Id: Ic510b76b80a9153b1ede7b3533d2dbc16caa5c63 Reviewed-on: https://go-review.googlesource.com/19768 TryBot-Result: Gobot Gobot Reviewed-by: David Crawshaw --- src/cmd/compile/internal/gc/subr.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go index f48b7cdc4f..bda1c95137 100644 --- a/src/cmd/compile/internal/gc/subr.go +++ b/src/cmd/compile/internal/gc/subr.go @@ -2862,10 +2862,18 @@ func geneq(sym *Sym, t *Type) { // for a struct containing a reflect.Value, which itself has // an unexported field of type unsafe.Pointer. old_safemode := safemode - safemode = 0 + + // Disable checknils while compiling this code. + // We are comparing a struct or an array, + // neither of which can be nil, and our comparisons + // are shallow. + Disable_checknil++ + funccompile(fn) + safemode = old_safemode + Disable_checknil-- } func ifacelookdot(s *Sym, t *Type, followptr *bool, ignorecase int) *Type { From 756ea30eb05357b02af1ac512920ed647d4ee350 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 22 Feb 2016 11:27:32 -0800 Subject: [PATCH 100/117] runtime: simplify stack copying in ThreadCreateProfile Change-Id: I7414d2fab18ae6e7e7c50f8697ec64d38290f409 Reviewed-on: https://go-review.googlesource.com/19817 Run-TryBot: Matthew Dempsky TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/runtime/mprof.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/runtime/mprof.go b/src/runtime/mprof.go index fc73bbfbe1..3efa375d6a 100644 --- a/src/runtime/mprof.go +++ b/src/runtime/mprof.go @@ -506,9 +506,7 @@ func ThreadCreateProfile(p []StackRecord) (n int, ok bool) { ok = true i := 0 for mp := first; mp != nil; mp = mp.alllink { - for s := range mp.createstack { - p[i].Stack0[s] = uintptr(mp.createstack[s]) - } + p[i].Stack0 = mp.createstack i++ } } From a4b833940da77449afd95dc95f8596bae4fa1621 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 22 Feb 2016 11:32:56 -0800 Subject: [PATCH 101/117] runtime: move machport into darwin's mOS It's not needed on other OSes. Change-Id: Ia6b13510585392a7062374806527d33876beba2a Reviewed-on: https://go-review.googlesource.com/19818 Run-TryBot: Matthew Dempsky Reviewed-by: David Crawshaw Reviewed-by: Ian Lance Taylor TryBot-Result: Gobot Gobot --- src/runtime/os_darwin.go | 1 + src/runtime/runtime2.go | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/os_darwin.go b/src/runtime/os_darwin.go index b8257768ac..78557759cc 100644 --- a/src/runtime/os_darwin.go +++ b/src/runtime/os_darwin.go @@ -7,6 +7,7 @@ package runtime import "unsafe" type mOS struct { + machport uint32 // return address for mach ipc waitsema uint32 // semaphore for parking on locks } diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go index 379fe2678b..5bc5fca7f0 100644 --- a/src/runtime/runtime2.go +++ b/src/runtime/runtime2.go @@ -309,7 +309,6 @@ type m struct { park note alllink *m // on allm schedlink muintptr - machport uint32 // return address for mach ipc (os x) mcache *mcache lockedg *g createstack [32]uintptr // stack that created this thread. From 108218453a2cd26920f9be899b4a5102e80007a8 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Fri, 19 Feb 2016 16:36:03 +1100 Subject: [PATCH 102/117] cmd/doc: handle embedded fields properly The structure of the code meant that an embedded field was never checked for export status. We need to check the name of the type, which is either of type T or type *T, and T might be unexported. Fixes #14356. Change-Id: I56f468e9b8ae67e9ed7509ed0b91d860507baed2 Reviewed-on: https://go-review.googlesource.com/19701 Reviewed-by: Robert Griesemer --- src/cmd/doc/doc_test.go | 9 +++++++-- src/cmd/doc/pkg.go | 20 +++++++++++++++++++- src/cmd/doc/testdata/pkg.go | 8 ++++++-- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/cmd/doc/doc_test.go b/src/cmd/doc/doc_test.go index ed1d0e7c79..20b61702b4 100644 --- a/src/cmd/doc/doc_test.go +++ b/src/cmd/doc/doc_test.go @@ -221,6 +221,7 @@ var tests = []test{ `type ExportedType struct`, // Type definition. `Comment before exported field.*\n.*ExportedField +int` + `.*Comment on line with exported field.`, + `ExportedEmbeddedType.*Comment on line with exported embedded field.`, `Has unexported fields`, `func \(ExportedType\) ExportedMethod\(a int\) bool`, `const ExportedTypedConstant ExportedType = iota`, // Must include associated constant. @@ -228,6 +229,7 @@ var tests = []test{ }, []string{ `unexportedField`, // No unexported field. + `int.*embedded`, // No unexported embedded field. `Comment about exported method.`, // No comment about exported method. `unexportedMethod`, // No unexported method. `unexportedTypedConstant`, // No unexported constant. @@ -241,7 +243,11 @@ var tests = []test{ `Comment about exported type`, // Include comment. `type ExportedType struct`, // Type definition. `Comment before exported field.*\n.*ExportedField +int`, - `unexportedField int.*Comment on line with unexported field.`, + `unexportedField.*int.*Comment on line with unexported field.`, + `ExportedEmbeddedType.*Comment on line with exported embedded field.`, + `\*ExportedEmbeddedType.*Comment on line with exported embedded \*field.`, + `unexportedType.*Comment on line with unexported embedded field.`, + `\*unexportedType.*Comment on line with unexported embedded \*field.`, `func \(ExportedType\) unexportedMethod\(a int\) bool`, `unexportedTypedConstant`, }, @@ -448,7 +454,6 @@ var trimTests = []trimTest{ {"", "", "", true}, {"/usr/gopher", "/usr/gopher", "/usr/gopher", true}, {"/usr/gopher/bar", "/usr/gopher", "bar", true}, - {"/usr/gopher", "/usr/gopher", "/usr/gopher", true}, {"/usr/gopherflakes", "/usr/gopher", "/usr/gopherflakes", false}, {"/usr/gopher/bar", "/usr/zot", "/usr/gopher/bar", false}, } diff --git a/src/cmd/doc/pkg.go b/src/cmd/doc/pkg.go index 0b07f7cc7c..a14ccdb59b 100644 --- a/src/cmd/doc/pkg.go +++ b/src/cmd/doc/pkg.go @@ -487,9 +487,27 @@ func trimUnexportedFields(fields *ast.FieldList, what string) *ast.FieldList { trimmed := false list := make([]*ast.Field, 0, len(fields.List)) for _, field := range fields.List { + names := field.Names + if len(names) == 0 { + // Embedded type. Use the name of the type. It must be of type ident or *ident. + // Nothing else is allowed. + switch ident := field.Type.(type) { + case *ast.Ident: + names = []*ast.Ident{ident} + case *ast.StarExpr: + // Must have the form *identifier. + if ident, ok := ident.X.(*ast.Ident); ok { + names = []*ast.Ident{ident} + } + } + if names == nil { + // Can only happen if AST is incorrect. Safe to continue with a nil list. + log.Print("invalid program: unexpected type for embedded field") + } + } // Trims if any is unexported. Good enough in practice. ok := true - for _, name := range field.Names { + for _, name := range names { if !isExported(name.Name) { trimmed = true ok = false diff --git a/src/cmd/doc/testdata/pkg.go b/src/cmd/doc/testdata/pkg.go index 3e7acee50b..1a673f78d4 100644 --- a/src/cmd/doc/testdata/pkg.go +++ b/src/cmd/doc/testdata/pkg.go @@ -60,8 +60,12 @@ func internalFunc(a int) bool // Comment about exported type. type ExportedType struct { // Comment before exported field. - ExportedField int // Comment on line with exported field. - unexportedField int // Comment on line with unexported field. + ExportedField int // Comment on line with exported field. + unexportedField int // Comment on line with unexported field. + ExportedEmbeddedType // Comment on line with exported embedded field. + *ExportedEmbeddedType // Comment on line with exported embedded *field. + unexportedType // Comment on line with unexported embedded field. + *unexportedType // Comment on line with unexported embedded *field. } // Comment about exported method. From 1e00cc1647916b705682f8721b8a9e9e095bf4ee Mon Sep 17 00:00:00 2001 From: Brady Sullivan Date: Mon, 22 Feb 2016 15:19:18 -0800 Subject: [PATCH 103/117] crypto/tls: Improve ambiguous comment in cipher_suites.go A comment existed referencing RC4 coming before AES because of it's vulnerability to the Lucky 13 attack. This clarifies that the Lucky 13 attack only effects AES-CBC, and not AES-GCM. Fixes #14474 Change-Id: Idcb07b5e0cdb0f9257cf75abea60129ba495b5f5 Reviewed-on: https://go-review.googlesource.com/19845 Reviewed-by: Brad Fitzpatrick --- src/crypto/tls/cipher_suites.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crypto/tls/cipher_suites.go b/src/crypto/tls/cipher_suites.go index 869ffa50bd..224ed1bc86 100644 --- a/src/crypto/tls/cipher_suites.go +++ b/src/crypto/tls/cipher_suites.go @@ -74,7 +74,7 @@ type cipherSuite struct { var cipherSuites = []*cipherSuite{ // Ciphersuite order is chosen so that ECDHE comes before plain RSA - // and RC4 comes before AES (because of the Lucky13 attack). + // and RC4 comes before AES-CBC (because of the Lucky13 attack). {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM}, {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadAESGCM}, {TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM}, From bd70bd9cb2f458b23222083a3a11190f080af7fd Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Mon, 22 Feb 2016 13:20:38 -0800 Subject: [PATCH 104/117] runtime: unify memeq and memequal They do the same thing, except memequal also has the short-circuit check if the two pointers are equal. A) We might as well always do the short-circuit check, it is only 2 instructions. B) The extra function call (memequal->memeq) is expensive. benchmark old ns/op new ns/op delta BenchmarkArrayEqual-8 8.56 5.31 -37.97% No noticeable affect on the former memeq user (maps). Fixes #14302 Change-Id: I85d1ada59ed11e64dd6c54667f79d32cc5f81948 Reviewed-on: https://go-review.googlesource.com/19843 Run-TryBot: Keith Randall TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/runtime/alg.go | 7 ------- src/runtime/asm_386.s | 8 +++++++- src/runtime/asm_amd64.s | 8 +++++++- src/runtime/asm_amd64p32.s | 8 +++++++- src/runtime/asm_arm.s | 9 ++++++--- src/runtime/asm_arm64.s | 9 ++++++--- src/runtime/asm_mips64x.s | 12 +++++++++--- src/runtime/asm_ppc64x.s | 13 ++++++++++--- src/runtime/hashmap_fast.go | 12 ++++++------ src/runtime/string_test.go | 11 +++++++++++ src/runtime/stubs.go | 2 +- 11 files changed, 70 insertions(+), 29 deletions(-) diff --git a/src/runtime/alg.go b/src/runtime/alg.go index 541649c62d..9e19119f4a 100644 --- a/src/runtime/alg.go +++ b/src/runtime/alg.go @@ -172,13 +172,6 @@ func nilinterhash(p unsafe.Pointer, h uintptr) uintptr { } } -func memequal(p, q unsafe.Pointer, size uintptr) bool { - if p == q { - return true - } - return memeq(p, q, size) -} - func memequal0(p, q unsafe.Pointer) bool { return true } diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s index 4181859724..9237d57f24 100644 --- a/src/runtime/asm_386.s +++ b/src/runtime/asm_386.s @@ -1239,12 +1239,18 @@ TEXT ·checkASM(SB),NOSPLIT,$0-1 SETEQ ret+0(FP) RET -TEXT runtime·memeq(SB),NOSPLIT,$0-13 +// memequal(p, q unsafe.Pointer, size uintptr) bool +TEXT runtime·memequal(SB),NOSPLIT,$0-13 MOVL a+0(FP), SI MOVL b+4(FP), DI + CMPL SI, DI + JEQ eq MOVL size+8(FP), BX LEAL ret+12(FP), AX JMP runtime·memeqbody(SB) +eq: + MOVB $1, ret+12(FP) + RET // memequal_varlen(a, b unsafe.Pointer) bool TEXT runtime·memequal_varlen(SB),NOSPLIT,$0-9 diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index 5094812a05..98a8e839ed 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -1269,12 +1269,18 @@ DATA shifts<>+0xf0(SB)/8, $0x0807060504030201 DATA shifts<>+0xf8(SB)/8, $0xff0f0e0d0c0b0a09 GLOBL shifts<>(SB),RODATA,$256 -TEXT runtime·memeq(SB),NOSPLIT,$0-25 +// memequal(p, q unsafe.Pointer, size uintptr) bool +TEXT runtime·memequal(SB),NOSPLIT,$0-25 MOVQ a+0(FP), SI MOVQ b+8(FP), DI + CMPQ SI, DI + JEQ eq MOVQ size+16(FP), BX LEAQ ret+24(FP), AX JMP runtime·memeqbody(SB) +eq: + MOVB $1, ret+24(FP) + RET // memequal_varlen(a, b unsafe.Pointer) bool TEXT runtime·memequal_varlen(SB),NOSPLIT,$0-17 diff --git a/src/runtime/asm_amd64p32.s b/src/runtime/asm_amd64p32.s index ecbc5975bb..ae7a53821b 100644 --- a/src/runtime/asm_amd64p32.s +++ b/src/runtime/asm_amd64p32.s @@ -573,13 +573,19 @@ TEXT runtime·aeshash64(SB),NOSPLIT,$0-20 MOVL AX, ret+16(FP) RET -TEXT runtime·memeq(SB),NOSPLIT,$0-17 +// memequal(p, q unsafe.Pointer, size uintptr) bool +TEXT runtime·memequal(SB),NOSPLIT,$0-13 MOVL a+0(FP), SI MOVL b+4(FP), DI + CMPL SI, DI + JEQ eq MOVL size+8(FP), BX CALL runtime·memeqbody(SB) MOVB AX, ret+16(FP) RET +eq: + MOVB $1, ret+16(FP) + RET // memequal_varlen(a, b unsafe.Pointer) bool TEXT runtime·memequal_varlen(SB),NOSPLIT,$0-9 diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s index 07894a3a72..5d0206d1c9 100644 --- a/src/runtime/asm_arm.s +++ b/src/runtime/asm_arm.s @@ -750,13 +750,16 @@ TEXT runtime·memhash_varlen(SB),NOSPLIT,$16-12 MOVW R0, ret+8(FP) RET -TEXT runtime·memeq(SB),NOSPLIT,$-4-13 +// memequal(p, q unsafe.Pointer, size uintptr) bool +TEXT runtime·memequal(SB),NOSPLIT,$-4-13 MOVW a+0(FP), R1 MOVW b+4(FP), R2 MOVW size+8(FP), R3 ADD R1, R3, R6 MOVW $1, R0 MOVB R0, ret+12(FP) + CMP R1, R2 + RET.EQ loop: CMP R1, R6 RET.EQ @@ -779,7 +782,7 @@ TEXT runtime·memequal_varlen(SB),NOSPLIT,$16-9 MOVW R0, 4(R13) MOVW R1, 8(R13) MOVW R2, 12(R13) - BL runtime·memeq(SB) + BL runtime·memequal(SB) MOVB 16(R13), R0 MOVB R0, ret+8(FP) RET @@ -866,7 +869,7 @@ loop: MOVB R8, v+16(FP) RET -// TODO: share code with memeq? +// TODO: share code with memequal? TEXT bytes·Equal(SB),NOSPLIT,$0-25 MOVW a_len+4(FP), R1 MOVW b_len+16(FP), R3 diff --git a/src/runtime/asm_arm64.s b/src/runtime/asm_arm64.s index ab5d5b5e5f..5a5c64c270 100644 --- a/src/runtime/asm_arm64.s +++ b/src/runtime/asm_arm64.s @@ -765,13 +765,16 @@ TEXT runtime·memhash_varlen(SB),NOSPLIT,$40-24 MOVD R3, ret+16(FP) RET -TEXT runtime·memeq(SB),NOSPLIT,$-8-25 +// memequal(p, q unsafe.Pointer, size uintptr) bool +TEXT runtime·memequal(SB),NOSPLIT,$-8-25 MOVD a+0(FP), R1 MOVD b+8(FP), R2 MOVD size+16(FP), R3 ADD R1, R3, R6 MOVD $1, R0 MOVB R0, ret+24(FP) + CMP R1, R2 + BEQ done loop: CMP R1, R6 BEQ done @@ -794,7 +797,7 @@ TEXT runtime·memequal_varlen(SB),NOSPLIT,$40-17 MOVD R3, 8(RSP) MOVD R4, 16(RSP) MOVD R5, 24(RSP) - BL runtime·memeq(SB) + BL runtime·memequal(SB) MOVBU 32(RSP), R3 MOVB R3, ret+16(FP) RET @@ -929,7 +932,7 @@ notfound: MOVD R0, ret+24(FP) RET -// TODO: share code with memeq? +// TODO: share code with memequal? TEXT bytes·Equal(SB),NOSPLIT,$0-49 MOVD a_len+8(FP), R1 MOVD b_len+32(FP), R3 diff --git a/src/runtime/asm_mips64x.s b/src/runtime/asm_mips64x.s index 08482fed23..80cea8587a 100644 --- a/src/runtime/asm_mips64x.s +++ b/src/runtime/asm_mips64x.s @@ -647,9 +647,11 @@ TEXT runtime·aeshash64(SB),NOSPLIT,$-8-0 TEXT runtime·aeshashstr(SB),NOSPLIT,$-8-0 MOVW (R0), R1 -TEXT runtime·memeq(SB),NOSPLIT,$-8-25 +// memequal(p, q unsafe.Pointer, size uintptr) bool +TEXT runtime·memequal(SB),NOSPLIT,$-8-25 MOVV a+0(FP), R1 MOVV b+8(FP), R2 + BEQ R1, R2, eq MOVV size+16(FP), R3 ADDV R1, R3, R4 loop: @@ -666,6 +668,10 @@ test: MOVB R0, ret+24(FP) RET +eq: + MOVV $1, R1 + MOVB R1, ret+24(FP) + RET // memequal_varlen(a, b unsafe.Pointer) bool TEXT runtime·memequal_varlen(SB),NOSPLIT,$40-17 @@ -676,7 +682,7 @@ TEXT runtime·memequal_varlen(SB),NOSPLIT,$40-17 MOVV R1, 8(R29) MOVV R2, 16(R29) MOVV R3, 24(R29) - JAL runtime·memeq(SB) + JAL runtime·memequal(SB) MOVBU 32(R29), R1 MOVB R1, ret+16(FP) RET @@ -710,7 +716,7 @@ loop: MOVB R0, ret+32(FP) RET -// TODO: share code with memeq? +// TODO: share code with memequal? TEXT bytes·Equal(SB),NOSPLIT,$0-49 MOVV a_len+8(FP), R3 MOVV b_len+32(FP), R4 diff --git a/src/runtime/asm_ppc64x.s b/src/runtime/asm_ppc64x.s index 50c4f2623c..f067b4a9b9 100644 --- a/src/runtime/asm_ppc64x.s +++ b/src/runtime/asm_ppc64x.s @@ -795,9 +795,12 @@ TEXT runtime·aeshash64(SB),NOSPLIT|NOFRAME,$0-0 TEXT runtime·aeshashstr(SB),NOSPLIT|NOFRAME,$0-0 MOVW (R0), R1 -TEXT runtime·memeq(SB),NOSPLIT|NOFRAME,$0-25 +// memequal(p, q unsafe.Pointer, size uintptr) bool +TEXT runtime·memequal(SB),NOSPLIT|NOFRAME,$0-25 MOVD a+0(FP), R3 MOVD b+8(FP), R4 + CMP R3, R4 + BEQ eq MOVD size+16(FP), R5 SUB $1, R3 SUB $1, R4 @@ -816,6 +819,10 @@ test: MOVB R0, ret+24(FP) RET +eq: + MOVD $1, R1 + MOVB R1, ret+24(FP) + RET // memequal_varlen(a, b unsafe.Pointer) bool TEXT runtime·memequal_varlen(SB),NOSPLIT,$40-17 @@ -827,7 +834,7 @@ TEXT runtime·memequal_varlen(SB),NOSPLIT,$40-17 MOVD R3, FIXED_FRAME+0(R1) MOVD R4, FIXED_FRAME+8(R1) MOVD R5, FIXED_FRAME+16(R1) - BL runtime·memeq(SB) + BL runtime·memequal(SB) MOVBZ FIXED_FRAME+24(R1), R3 MOVB R3, ret+16(FP) RET @@ -864,7 +871,7 @@ loop: MOVB R0, ret+32(FP) RET -// TODO: share code with memeq? +// TODO: share code with memequal? TEXT bytes·Equal(SB),NOSPLIT,$0-49 MOVD a_len+8(FP), R3 MOVD b_len+32(FP), R4 diff --git a/src/runtime/hashmap_fast.go b/src/runtime/hashmap_fast.go index 519dc77f71..f95ea3e1b7 100644 --- a/src/runtime/hashmap_fast.go +++ b/src/runtime/hashmap_fast.go @@ -216,7 +216,7 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer { if k.len != key.len { continue } - if k.str == key.str || memeq(k.str, key.str, uintptr(key.len)) { + if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) { return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize)) } } @@ -254,7 +254,7 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer { } if keymaybe != bucketCnt { k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+keymaybe*2*sys.PtrSize)) - if memeq(k.str, key.str, uintptr(key.len)) { + if memequal(k.str, key.str, uintptr(key.len)) { return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+keymaybe*uintptr(t.valuesize)) } } @@ -284,7 +284,7 @@ dohash: if k.len != key.len { continue } - if k.str == key.str || memeq(k.str, key.str, uintptr(key.len)) { + if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) { return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize)) } } @@ -321,7 +321,7 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) { if k.len != key.len { continue } - if k.str == key.str || memeq(k.str, key.str, uintptr(key.len)) { + if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) { return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize)), true } } @@ -357,7 +357,7 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) { } if keymaybe != bucketCnt { k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+keymaybe*2*sys.PtrSize)) - if memeq(k.str, key.str, uintptr(key.len)) { + if memequal(k.str, key.str, uintptr(key.len)) { return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+keymaybe*uintptr(t.valuesize)), true } } @@ -387,7 +387,7 @@ dohash: if k.len != key.len { continue } - if k.str == key.str || memeq(k.str, key.str, uintptr(key.len)) { + if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) { return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize)), true } } diff --git a/src/runtime/string_test.go b/src/runtime/string_test.go index 150a25520a..37b75c1a89 100644 --- a/src/runtime/string_test.go +++ b/src/runtime/string_test.go @@ -102,6 +102,17 @@ func BenchmarkRuneIterate2(b *testing.B) { } } +func BenchmarkArrayEqual(b *testing.B) { + a1 := [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} + a2 := [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} + b.ResetTimer() + for i := 0; i < b.N; i++ { + if a1 != a2 { + b.Fatal("not equal") + } + } +} + func TestStringW(t *testing.T) { strings := []string{ "hello", diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go index f060182c22..6c28fd2e78 100644 --- a/src/runtime/stubs.go +++ b/src/runtime/stubs.go @@ -85,7 +85,7 @@ func fastrand1() uint32 // in asm_*.s //go:noescape -func memeq(a, b unsafe.Pointer, size uintptr) bool +func memequal(a, b unsafe.Pointer, size uintptr) bool // noescape hides a pointer from escape analysis. noescape is // the identity function but escape analysis doesn't think the From 0784e6918e931e8bc6e28252ae11a65664ecbaaa Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 22 Feb 2016 19:41:17 -0800 Subject: [PATCH 105/117] net/http: fix typo in doc string Fixes #14475. Change-Id: I1b5b0a9793a417572ec55f313185d03ad5ae9d01 Reviewed-on: https://go-review.googlesource.com/19846 Reviewed-by: Robert Griesemer --- src/net/http/fs.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net/http/fs.go b/src/net/http/fs.go index 8a5b8bba37..520a5477a7 100644 --- a/src/net/http/fs.go +++ b/src/net/http/fs.go @@ -451,7 +451,7 @@ func localRedirect(w ResponseWriter, r *Request, newPath string) { // ServeFile replies to the request with the contents of the named // file or directory. // -// If the provided file or direcory name is a relative path, it is +// If the provided file or directory name is a relative path, it is // interpreted relative to the current directory and may ascend to parent // directories. If the provided name is constructed from user input, it // should be sanitized before calling ServeFile. As a precaution, ServeFile From e7524d51fdf64b48a4ec2fbc13596a5c8a80cc05 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 22 Feb 2016 11:53:20 -0800 Subject: [PATCH 106/117] cmd/compile: move Io state into lexer and remove Io type Pass lexer around so state is accessible and dependency is explicit. In the process remove EOF -> '\n' conversion that has to be corrected for when reporting errors. Change-Id: If95564b70e7484dedc1f5348e585cd19acbc1243 Reviewed-on: https://go-review.googlesource.com/19819 Run-TryBot: Robert Griesemer TryBot-Result: Gobot Gobot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/gc/go.go | 10 -- src/cmd/compile/internal/gc/lex.go | 216 +++++++++++++------------- src/cmd/compile/internal/gc/parser.go | 28 ++-- src/cmd/compile/internal/gc/subr.go | 6 - 4 files changed, 119 insertions(+), 141 deletions(-) diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go index 3c00f72ec1..cdb976999f 100644 --- a/src/cmd/compile/internal/gc/go.go +++ b/src/cmd/compile/internal/gc/go.go @@ -373,14 +373,6 @@ type Sig struct { offset int32 } -type Io struct { - bin *obj.Biobuf - last int - peekc int - peekc1 int // second peekc for ... - eofnl bool -} - type Dlist struct { field *Type } @@ -431,8 +423,6 @@ var sizeof_String int // runtime sizeof(String) var dotlist [10]Dlist // size is max depth of embeddeds -var curio Io - var lexlineno int32 var lineno int32 diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go index 0f8b20cea0..91280e02e5 100644 --- a/src/cmd/compile/internal/gc/lex.go +++ b/src/cmd/compile/internal/gc/lex.go @@ -341,6 +341,11 @@ func Main() { errorexit() } + // Instead of converting EOF into '\n' in getc and count it as an extra line + // for the line history to work, and which then has to be corrected elsewhere, + // just add a line here. + lexlineno++ + linehistpop() obj.Bterm(bin) } @@ -867,8 +872,11 @@ func isfrog(c int) bool { } type lexer struct { - // TODO(gri) move other lexer state here and out of global variables - // (source, current line number, etc.) + // source + bin *obj.Biobuf + peekc int + peekc1 int // second peekc for ... + nlsemi bool // if set, '\n' and EOF translate to ';' // current token @@ -942,17 +950,17 @@ func (l *lexer) next() { l0: // skip white space - c := getc() + c := l.getc() for isSpace(c) { if c == '\n' && nlsemi { - ungetc(c) + l.ungetc(c) if Debug['x'] != 0 { fmt.Printf("lex: implicit semi\n") } l.tok = ';' return } - c = getc() + c = l.getc() } // start of token @@ -977,7 +985,7 @@ l0: if c != '0' { for { cp.WriteByte(byte(c)) - c = getc() + c = l.getc() if isDigit(c) { continue } @@ -995,11 +1003,11 @@ l0: } cp.WriteByte(byte(c)) - c = getc() + c = l.getc() if c == 'x' || c == 'X' { for { cp.WriteByte(byte(c)) - c = getc() + c = l.getc() if isDigit(c) { continue } @@ -1032,7 +1040,7 @@ l0: c1 = 1 // not octal } cp.WriteByte(byte(c)) - c = getc() + c = l.getc() } if c == '.' { @@ -1053,7 +1061,7 @@ l0: switch c { case EOF: lineno = prevlineno - ungetc(EOF) + l.ungetc(EOF) // Treat EOF as "end of line" for the purposes // of inserting a semicolon. if nlsemi { @@ -1072,7 +1080,7 @@ l0: goto talph case '.': - c1 = getc() + c1 = l.getc() if isDigit(c1) { cp = &lexbuf cp.Reset() @@ -1082,13 +1090,13 @@ l0: } if c1 == '.' { - c1 = getc() + c1 = l.getc() if c1 == '.' { c = LDDD goto lx } - ungetc(c1) + l.ungetc(c1) c1 = '.' } @@ -1101,7 +1109,7 @@ l0: cp.Reset() for { - if escchar('"', &escflag, &v) { + if l.escchar('"', &escflag, &v) { break } if v < utf8.RuneSelf || escflag != 0 { @@ -1122,7 +1130,7 @@ l0: cp.Reset() for { - c = int(getr()) + c = int(l.getr()) if c == '\r' { continue } @@ -1141,14 +1149,14 @@ l0: // '.' case '\'': - if escchar('\'', &escflag, &v) { + if l.escchar('\'', &escflag, &v) { Yyerror("empty character literal or unescaped ' in character literal") v = '\'' } - if !escchar('\'', &escflag, &v) { + if !l.escchar('\'', &escflag, &v) { Yyerror("missing '") - ungetc(int(v)) + l.ungetc(int(v)) } x := new(Mpint) @@ -1164,19 +1172,19 @@ l0: return case '/': - c1 = getc() + c1 = l.getc() if c1 == '*' { nl := false for { - c = int(getr()) + c = int(l.getr()) if c == '\n' { nl = true } for c == '*' { - c = int(getr()) + c = int(l.getr()) if c == '/' { if nl { - ungetc('\n') + l.ungetc('\n') } goto l0 } @@ -1194,14 +1202,14 @@ l0: } if c1 == '/' { - c = getlinepragma() + c = l.getlinepragma() for { if c == '\n' || c == EOF { - ungetc(c) + l.ungetc(c) goto l0 } - c = int(getr()) + c = int(l.getr()) } } @@ -1211,28 +1219,28 @@ l0: } case ':': - c1 = getc() + c1 = l.getc() if c1 == '=' { c = int(LCOLAS) goto lx } case '*': - c1 = getc() + c1 = l.getc() if c1 == '=' { op = OMUL goto asop } case '%': - c1 = getc() + c1 = l.getc() if c1 == '=' { op = OMOD goto asop } case '+': - c1 = getc() + c1 = l.getc() if c1 == '+' { l.nlsemi = true c = int(LINC) @@ -1245,7 +1253,7 @@ l0: } case '-': - c1 = getc() + c1 = l.getc() if c1 == '-' { l.nlsemi = true c = int(LDEC) @@ -1258,10 +1266,10 @@ l0: } case '>': - c1 = getc() + c1 = l.getc() if c1 == '>' { c = int(LRSH) - c1 = getc() + c1 = l.getc() if c1 == '=' { op = ORSH goto asop @@ -1278,10 +1286,10 @@ l0: c = int(LGT) case '<': - c1 = getc() + c1 = l.getc() if c1 == '<' { c = int(LLSH) - c1 = getc() + c1 = l.getc() if c1 == '=' { op = OLSH goto asop @@ -1303,21 +1311,21 @@ l0: c = int(LLT) case '=': - c1 = getc() + c1 = l.getc() if c1 == '=' { c = int(LEQ) goto lx } case '!': - c1 = getc() + c1 = l.getc() if c1 == '=' { c = int(LNE) goto lx } case '&': - c1 = getc() + c1 = l.getc() if c1 == '&' { c = int(LANDAND) goto lx @@ -1325,7 +1333,7 @@ l0: if c1 == '^' { c = int(LANDNOT) - c1 = getc() + c1 = l.getc() if c1 == '=' { op = OANDNOT goto asop @@ -1340,7 +1348,7 @@ l0: } case '|': - c1 = getc() + c1 = l.getc() if c1 == '|' { c = int(LOROR) goto lx @@ -1352,7 +1360,7 @@ l0: } case '^': - c1 = getc() + c1 = l.getc() if c1 == '=' { op = OXOR goto asop @@ -1366,7 +1374,7 @@ l0: goto lx } - ungetc(c1) + l.ungetc(c1) lx: if Debug['x'] != 0 { @@ -1402,8 +1410,8 @@ asop: talph: for { if c >= utf8.RuneSelf { - ungetc(c) - r := rune(getr()) + l.ungetc(c) + r := rune(l.getr()) // 0xb7 · is used for internal names if !unicode.IsLetter(r) && !unicode.IsDigit(r) && (importpkg == nil || r != 0xb7) { @@ -1418,11 +1426,11 @@ talph: } else { cp.WriteByte(byte(c)) } - c = getc() + c = l.getc() } cp = nil - ungetc(c) + l.ungetc(c) s = LookupBytes(lexbuf.Bytes()) if s.Lexical == LIGNORE { @@ -1442,7 +1450,7 @@ talph: ncu: cp = nil - ungetc(c) + l.ungetc(c) str = lexbuf.String() l.val.U = new(Mpint) @@ -1463,7 +1471,7 @@ ncu: casedot: for { cp.WriteByte(byte(c)) - c = getc() + c = l.getc() if !isDigit(c) { break } @@ -1483,10 +1491,10 @@ caseep: Yyerror("malformed floating point constant") } cp.WriteByte(byte(c)) - c = getc() + c = l.getc() if c == '+' || c == '-' { cp.WriteByte(byte(c)) - c = getc() + c = l.getc() } if !isDigit(c) { @@ -1494,7 +1502,7 @@ caseep: } for isDigit(c) { cp.WriteByte(byte(c)) - c = getc() + c = l.getc() } if c == 'i' { @@ -1525,7 +1533,7 @@ casei: caseout: cp = nil - ungetc(c) + l.ungetc(c) str = lexbuf.String() l.val.U = newMpflt() @@ -1557,11 +1565,10 @@ var internedStrings = map[string]string{} func internString(b []byte) string { s, ok := internedStrings[string(b)] // string(b) here doesn't allocate - if ok { - return s + if !ok { + s = string(b) + internedStrings[s] = s } - s = string(b) - internedStrings[s] = s return s } @@ -1578,16 +1585,16 @@ func more(pp *string) bool { // //line parse.y:15 // as a discontinuity in sequential line numbers. // the next line of input comes from parse.y:15 -func getlinepragma() int { +func (l *lexer) getlinepragma() int { var cmd, verb, name string - c := int(getr()) + c := int(l.getr()) if c == 'g' { cp := &lexbuf cp.Reset() cp.WriteByte('g') // already read for { - c = int(getr()) + c = int(l.getr()) if c == EOF || c >= utf8.RuneSelf { return c } @@ -1679,7 +1686,7 @@ func getlinepragma() int { return c } for i := 1; i < 5; i++ { - c = int(getr()) + c = int(l.getr()) if c != int("line "[i]) { return c } @@ -1689,7 +1696,7 @@ func getlinepragma() int { cp.Reset() linep := 0 for { - c = int(getr()) + c = int(l.getr()) if c == EOF { return c } @@ -1870,19 +1877,19 @@ func pragcgo(text string) { } } -func getc() int { - c := curio.peekc +func (l *lexer) getc() int { + c := l.peekc if c != 0 { - curio.peekc = curio.peekc1 - curio.peekc1 = 0 + l.peekc = l.peekc1 + l.peekc1 = 0 goto check } loop: - c = obj.Bgetc(curio.bin) + c = obj.Bgetc(l.bin) // recognize BOM (U+FEFF): UTF-8 encoding is 0xef 0xbb 0xbf if c == 0xef { - buf, err := curio.bin.Peek(2) + buf, err := l.bin.Peek(2) if err != nil { yyerrorl(int(lexlineno), "illegal UTF-8 sequence ef % x followed by read error (%v)", string(buf), err) errorexit() @@ -1891,49 +1898,36 @@ loop: yyerrorl(int(lexlineno), "Unicode (UTF-8) BOM in middle of file") // consume BOM bytes - obj.Bgetc(curio.bin) - obj.Bgetc(curio.bin) + obj.Bgetc(l.bin) + obj.Bgetc(l.bin) goto loop } } check: - switch c { - case 0: + if c == 0 { Yyerror("illegal NUL byte") - - // insert \n at EOF - case EOF: - if curio.eofnl || curio.last == '\n' { - return EOF - } - curio.eofnl = true - c = '\n' - fallthrough - - case '\n': - if importpkg == nil { - lexlineno++ - } + return 0 + } + if c == '\n' && importpkg == nil { + lexlineno++ } - - curio.last = c return c } -func ungetc(c int) { - curio.peekc1 = curio.peekc - curio.peekc = c +func (l *lexer) ungetc(c int) { + l.peekc1 = l.peekc + l.peekc = c if c == '\n' && importpkg == nil { lexlineno-- } } -func getr() int32 { +func (l *lexer) getr() int32 { var buf [utf8.UTFMax]byte for i := 0; ; i++ { - c := getc() + c := l.getc() if i == 0 && c < utf8.RuneSelf { return int32(c) } @@ -1952,10 +1946,10 @@ func getr() int32 { } } -func escchar(e int, escflg *int, val *int64) bool { +func (l *lexer) escchar(e int, escflg *int, val *int64) bool { *escflg = 0 - c := int(getr()) + c := int(l.getr()) switch c { case EOF: Yyerror("eof in string") @@ -1977,7 +1971,7 @@ func escchar(e int, escflg *int, val *int64) bool { } u := 0 - c = int(getr()) + c = int(l.getr()) var i int switch c { case 'x': @@ -2004,23 +1998,23 @@ func escchar(e int, escflg *int, val *int64) bool { '6', '7': *escflg = 1 // it's a byte - l := int64(c) - '0' + x := int64(c) - '0' for i := 2; i > 0; i-- { - c = getc() + c = l.getc() if c >= '0' && c <= '7' { - l = l*8 + int64(c) - '0' + x = x*8 + int64(c) - '0' continue } Yyerror("non-octal character in escape sequence: %c", c) - ungetc(c) + l.ungetc(c) } - if l > 255 { - Yyerror("octal escape value > 255: %d", l) + if x > 255 { + Yyerror("octal escape value > 255: %d", x) } - *val = l + *val = x return false case 'a': @@ -2050,35 +2044,35 @@ func escchar(e int, escflg *int, val *int64) bool { return false hex: - l := int64(0) + x := int64(0) for ; i > 0; i-- { - c = getc() + c = l.getc() if c >= '0' && c <= '9' { - l = l*16 + int64(c) - '0' + x = x*16 + int64(c) - '0' continue } if c >= 'a' && c <= 'f' { - l = l*16 + int64(c) - 'a' + 10 + x = x*16 + int64(c) - 'a' + 10 continue } if c >= 'A' && c <= 'F' { - l = l*16 + int64(c) - 'A' + 10 + x = x*16 + int64(c) - 'A' + 10 continue } Yyerror("non-hex character in escape sequence: %c", c) - ungetc(c) + l.ungetc(c) break } - if u != 0 && (l > utf8.MaxRune || (0xd800 <= l && l < 0xe000)) { - Yyerror("invalid Unicode code point in escape sequence: %#x", l) - l = utf8.RuneError + if u != 0 && (x > utf8.MaxRune || (0xd800 <= x && x < 0xe000)) { + Yyerror("invalid Unicode code point in escape sequence: %#x", x) + x = utf8.RuneError } - *val = l + *val = x return false } diff --git a/src/cmd/compile/internal/gc/parser.go b/src/cmd/compile/internal/gc/parser.go index deae40c21b..f49f69c798 100644 --- a/src/cmd/compile/internal/gc/parser.go +++ b/src/cmd/compile/internal/gc/parser.go @@ -21,24 +21,14 @@ import ( const trace = false // if set, parse tracing can be enabled with -x +// parse_import parses the export data of a package that is imported. func parse_import(bin *obj.Biobuf, indent []byte) { - pushedio := curio - curio = Io{bin: bin} - - importparser := parser{indent: indent} // preserve indentation - importparser.next() - importparser.import_package() - - curio = pushedio + newparser(bin, indent).import_package() } -// parse_file sets up a new parser and parses a single Go source file. +// parse_file parses a single Go source file. func parse_file(bin *obj.Biobuf) { - curio = Io{bin: bin} - - fileparser := parser{} - fileparser.next() - fileparser.file() + newparser(bin, nil).file() } type parser struct { @@ -48,6 +38,16 @@ type parser struct { indent []byte // tracing support } +// newparser returns a new parser ready to parse from src. +// indent is the initial indentation for tracing output. +func newparser(src *obj.Biobuf, indent []byte) *parser { + var p parser + p.bin = src + p.indent = indent + p.next() + return &p +} + func (p *parser) got(tok int32) bool { if p.tok == tok { p.next() diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go index bda1c95137..0415fd3da2 100644 --- a/src/cmd/compile/internal/gc/subr.go +++ b/src/cmd/compile/internal/gc/subr.go @@ -116,12 +116,6 @@ func Yyerror(format string, args ...interface{}) { if strings.HasPrefix(msg, "syntax error") { nsyntaxerrors++ - // An unexpected EOF caused a syntax error. Use the previous - // line number since getc generated a fake newline character. - if curio.eofnl { - lexlineno = prevlineno - } - // only one syntax error per line if int32(yyerror_lastsyntax) == lexlineno { return From e34295e64782d61725377e8d0979114bd790b47f Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 23 Feb 2016 02:14:32 -0800 Subject: [PATCH 107/117] cmd/compile: use path.Join in importfile Change-Id: Ib413b0cb16405965455d7764a8c4a22bf431389b Reviewed-on: https://go-review.googlesource.com/19850 Run-TryBot: Matthew Dempsky TryBot-Result: Gobot Gobot Reviewed-by: David Crawshaw --- src/cmd/compile/internal/gc/lex.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go index 91280e02e5..89b442796b 100644 --- a/src/cmd/compile/internal/gc/lex.go +++ b/src/cmd/compile/internal/gc/lex.go @@ -729,11 +729,7 @@ func importfile(f *Val, indent []byte) { if localimport != "" { prefix = localimport } - cleanbuf := prefix - cleanbuf += "/" - cleanbuf += path_ - cleanbuf = path.Clean(cleanbuf) - path_ = cleanbuf + path_ = path.Join(prefix, path_) if isbadimport(path_) { return From 3ec0651539d481100b6e735d54072627276f48d3 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 23 Feb 2016 02:19:25 -0800 Subject: [PATCH 108/117] cmd/compile: add copyright notice to util.go util.go was originally added in golang.org/cl/4851, and later moved to its current location in golang.org/cl/10287. Change-Id: I10b4941d42ae1ff2e78990c497c1347bbbae4e3d Reviewed-on: https://go-review.googlesource.com/19851 Reviewed-by: David Crawshaw --- src/cmd/compile/internal/gc/util.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/cmd/compile/internal/gc/util.go b/src/cmd/compile/internal/gc/util.go index 7ed3b39b83..18e990a91a 100644 --- a/src/cmd/compile/internal/gc/util.go +++ b/src/cmd/compile/internal/gc/util.go @@ -1,3 +1,7 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package gc import ( From abf4696ede52ebd980605b10034f39af32ac5d90 Mon Sep 17 00:00:00 2001 From: Alberto Donizetti Date: Fri, 29 Jan 2016 21:22:11 +0100 Subject: [PATCH 109/117] unicode/utf16: add benchmarks For #6957 Change-Id: Ic497c12f33efc933e9fe81f6cd1b2a0a01abbabf Reviewed-on: https://go-review.googlesource.com/19820 Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/unicode/utf16/utf16_test.go | 53 +++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/unicode/utf16/utf16_test.go b/src/unicode/utf16/utf16_test.go index 3dca472bbe..e5be504e08 100644 --- a/src/unicode/utf16/utf16_test.go +++ b/src/unicode/utf16/utf16_test.go @@ -147,3 +147,56 @@ func TestIsSurrogate(t *testing.T) { } } } + +func BenchmarkDecodeValidASCII(b *testing.B) { + // "hello world" + data := []uint16{104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100} + for i := 0; i < b.N; i++ { + Decode(data) + } +} + +func BenchmarkDecodeValidJapaneseChars(b *testing.B) { + // "日本語日本語日本語" + data := []uint16{26085, 26412, 35486, 26085, 26412, 35486, 26085, 26412, 35486} + for i := 0; i < b.N; i++ { + Decode(data) + } +} + +func BenchmarkDecodeRune(b *testing.B) { + rs := make([]rune, 10) + // U+1D4D0 to U+1D4D4: MATHEMATICAL BOLD SCRIPT CAPITAL LETTERS + for i, u := range []rune{'𝓐', '𝓑', '𝓒', '𝓓', '𝓔'} { + rs[2*i], rs[2*i+1] = EncodeRune(u) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + for j := 0; j < 5; j++ { + DecodeRune(rs[2*j], rs[2*j+1]) + } + } +} + +func BenchmarkEncodeValidASCII(b *testing.B) { + data := []rune{'h', 'e', 'l', 'l', 'o'} + for i := 0; i < b.N; i++ { + Encode(data) + } +} + +func BenchmarkEncodeValidJapaneseChars(b *testing.B) { + data := []rune{'日', '本', '語'} + for i := 0; i < b.N; i++ { + Encode(data) + } +} + +func BenchmarkEncodeRune(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, u := range []rune{'𝓐', '𝓑', '𝓒', '𝓓', '𝓔'} { + EncodeRune(u) + } + } +} From 58ec5839cd9c210dc7ad727a6b1f743ea6233ddf Mon Sep 17 00:00:00 2001 From: Shawn Smith Date: Sat, 6 Feb 2016 20:35:29 +0900 Subject: [PATCH 110/117] all: fix typos Change-Id: I6035941df8b0de6aeaf6c05df7257bcf6e9191fe Reviewed-on: https://go-review.googlesource.com/19320 Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/arm/prog.go | 4 ++-- src/cmd/compile/internal/gc/inl.go | 2 +- src/cmd/compile/internal/gc/parser.go | 2 +- src/cmd/internal/obj/arm/obj5.go | 2 +- src/crypto/rsa/rsa.go | 2 +- src/go/types/eval.go | 2 +- src/mime/encodedword.go | 4 ++-- src/net/dnsmsg.go | 2 +- src/net/http/httptest/server.go | 2 +- src/net/http/server.go | 2 +- src/net/http/transport.go | 2 +- src/os/os_windows_test.go | 2 +- src/path/filepath/symlink.go | 2 +- src/runtime/chan.go | 2 +- 14 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/cmd/compile/internal/arm/prog.go b/src/cmd/compile/internal/arm/prog.go index 81be77a5b0..49a329b535 100644 --- a/src/cmd/compile/internal/arm/prog.go +++ b/src/cmd/compile/internal/arm/prog.go @@ -98,11 +98,11 @@ var progtable = [arm.ALAST]obj.ProgInfo{ arm.AMOVH: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move}, arm.AMOVW: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move}, - // In addtion, duffzero reads R0,R1 and writes R1. This fact is + // In addition, duffzero reads R0,R1 and writes R1. This fact is // encoded in peep.c obj.ADUFFZERO: {Flags: gc.Call}, - // In addtion, duffcopy reads R1,R2 and writes R0,R1,R2. This fact is + // In addition, duffcopy reads R1,R2 and writes R0,R1,R2. This fact is // encoded in peep.c obj.ADUFFCOPY: {Flags: gc.Call}, diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go index 64afd67438..a445f712e2 100644 --- a/src/cmd/compile/internal/gc/inl.go +++ b/src/cmd/compile/internal/gc/inl.go @@ -7,7 +7,7 @@ // saves a copy of the body. Then inlcalls walks each function body to // expand calls to inlinable functions. // -// The debug['l'] flag controls the agressiveness. Note that main() swaps level 0 and 1, +// The debug['l'] flag controls the aggressiveness. Note that main() swaps level 0 and 1, // making 1 the default and -l disable. -ll and more is useful to flush out bugs. // These additional levels (beyond -l) may be buggy and are not supported. // 0: disabled diff --git a/src/cmd/compile/internal/gc/parser.go b/src/cmd/compile/internal/gc/parser.go index f49f69c798..fbc5a5e1eb 100644 --- a/src/cmd/compile/internal/gc/parser.go +++ b/src/cmd/compile/internal/gc/parser.go @@ -5,7 +5,7 @@ package gc // The recursive-descent parser is built around a slighty modified grammar -// of Go to accomodate for the constraints imposed by strict one token look- +// of Go to accommodate for the constraints imposed by strict one token look- // ahead, and for better error handling. Subsequent checks of the constructed // syntax tree restrict the language accepted by the compiler to proper Go. // diff --git a/src/cmd/internal/obj/arm/obj5.go b/src/cmd/internal/obj/arm/obj5.go index 19a70e177e..1a51dc3b88 100644 --- a/src/cmd/internal/obj/arm/obj5.go +++ b/src/cmd/internal/obj/arm/obj5.go @@ -60,7 +60,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) { // Treat MRC 15, 0, , C13, C0, 3 specially. case AMRC: if p.To.Offset&0xffff0fff == 0xee1d0f70 { - // Because the instruction might be rewriten to a BL which returns in R0 + // Because the instruction might be rewritten to a BL which returns in R0 // the register must be zero. if p.To.Offset&0xf000 != 0 { ctxt.Diag("%v: TLS MRC instruction must write to R0 as it might get translated into a BL instruction", p.Line()) diff --git a/src/crypto/rsa/rsa.go b/src/crypto/rsa/rsa.go index ee022b803a..dc57a6335a 100644 --- a/src/crypto/rsa/rsa.go +++ b/src/crypto/rsa/rsa.go @@ -14,7 +14,7 @@ // possible. // // Two sets of interfaces are included in this package. When a more abstract -// interface isn't neccessary, there are functions for encrypting/decrypting +// interface isn't necessary, there are functions for encrypting/decrypting // with v1.5/OAEP and signing/verifying with v1.5/PSS. If one needs to abstract // over the public-key primitive, the PrivateKey struct implements the // Decrypter and Signer interfaces from the crypto package. diff --git a/src/go/types/eval.go b/src/go/types/eval.go index 7b42ff1a9d..f928ee6923 100644 --- a/src/go/types/eval.go +++ b/src/go/types/eval.go @@ -44,7 +44,7 @@ func Eval(fset *token.FileSet, pkg *Package, pos token.Pos, expr string) (tv Typ scope = pkg.scope } else { // The package scope extent (position information) may be - // incorrect (files spread accross a wide range of fset + // incorrect (files spread across a wide range of fset // positions) - ignore it and just consider its children // (file scopes). for _, fscope := range pkg.scope.children { diff --git a/src/mime/encodedword.go b/src/mime/encodedword.go index db4b5f4510..d219bbd393 100644 --- a/src/mime/encodedword.go +++ b/src/mime/encodedword.go @@ -89,7 +89,7 @@ func (e WordEncoder) bEncode(buf *bytes.Buffer, charset, s string) { var currentLen, last, runeLen int for i := 0; i < len(s); i += runeLen { - // Multi-byte characters must not be split accross encoded-words. + // Multi-byte characters must not be split across encoded-words. // See RFC 2047, section 5.3. _, runeLen = utf8.DecodeRuneInString(s[i:]) @@ -119,7 +119,7 @@ func (e WordEncoder) qEncode(buf *bytes.Buffer, charset, s string) { var currentLen, runeLen int for i := 0; i < len(s); i += runeLen { b := s[i] - // Multi-byte characters must not be split accross encoded-words. + // Multi-byte characters must not be split across encoded-words. // See RFC 2047, section 5.3. var encLen int if b >= ' ' && b <= '~' && b != '=' && b != '?' && b != '_' { diff --git a/src/net/dnsmsg.go b/src/net/dnsmsg.go index 2ec4c8c301..5747fd232b 100644 --- a/src/net/dnsmsg.go +++ b/src/net/dnsmsg.go @@ -315,7 +315,7 @@ func (rr *dnsRR_TXT) Walk(f func(v interface{}, name, tag string) bool) bool { if !f(&txt, "Txt", "") { return false } - // more bytes than rr.Hdr.Rdlength said there woudld be + // more bytes than rr.Hdr.Rdlength said there would be if rr.Hdr.Rdlength-n < uint16(len(txt))+1 { return false } diff --git a/src/net/http/httptest/server.go b/src/net/http/httptest/server.go index a2573df251..7e52adb607 100644 --- a/src/net/http/httptest/server.go +++ b/src/net/http/httptest/server.go @@ -167,7 +167,7 @@ func (s *Server) Close() { // few milliseconds wasn't liked (early versions of // https://golang.org/cl/15151) so now we just // forcefully close StateNew. The docs for Server.Close say - // we wait for "oustanding requests", so we don't close things + // we wait for "outstanding requests", so we don't close things // in StateActive. if st == http.StateIdle || st == http.StateNew { s.closeConn(c) diff --git a/src/net/http/server.go b/src/net/http/server.go index 1b5cda3159..e2d8d277e0 100644 --- a/src/net/http/server.go +++ b/src/net/http/server.go @@ -1009,7 +1009,7 @@ func (cw *chunkWriter) writeHeader(p []byte) { w.closeAfterReply = true } default: - // Some other kind of error occured, like a read timeout, or + // Some other kind of error occurred, like a read timeout, or // corrupt chunked encoding. In any case, whatever remains // on the wire must not be parsed as another HTTP request. w.closeAfterReply = true diff --git a/src/net/http/transport.go b/src/net/http/transport.go index feedb3420d..03e9162b14 100644 --- a/src/net/http/transport.go +++ b/src/net/http/transport.go @@ -1357,7 +1357,7 @@ type writeRequest struct { req *transportRequest ch chan<- error - // Optional blocking chan for Expect: 100-continue (for recieve). + // Optional blocking chan for Expect: 100-continue (for receive). // If not nil, writeLoop blocks sending request body until // it receives from this chan. continueCh <-chan struct{} diff --git a/src/os/os_windows_test.go b/src/os/os_windows_test.go index 5c073da991..2f7d48d5bd 100644 --- a/src/os/os_windows_test.go +++ b/src/os/os_windows_test.go @@ -177,7 +177,7 @@ func TestStatDir(t *testing.T) { } if !os.SameFile(fi, fi2) { - t.Fatal("race condition occured") + t.Fatal("race condition occurred") } } diff --git a/src/path/filepath/symlink.go b/src/path/filepath/symlink.go index bc287c5ecb..f627a94ddb 100644 --- a/src/path/filepath/symlink.go +++ b/src/path/filepath/symlink.go @@ -100,7 +100,7 @@ func walkSymlinks(path string) (string, error) { return "", err } if runtime.GOOS == "windows" { - // walkLinks(".", ...) always retuns "." on unix. + // walkLinks(".", ...) always returns "." on unix. // But on windows it returns symlink target, if current // directory is a symlink. Stop the walk, if symlink // target is not absolute path, and return "." diff --git a/src/runtime/chan.go b/src/runtime/chan.go index 5be18beb23..063c5ce391 100644 --- a/src/runtime/chan.go +++ b/src/runtime/chan.go @@ -421,7 +421,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r if sg := c.sendq.dequeue(); sg != nil { // Found a waiting sender. If buffer is size 0, receive value - // directly from sender. Otherwise, recieve from head of queue + // directly from sender. Otherwise, receive from head of queue // and add sender's value to the tail of the queue (both map to // the same buffer slot because the queue is full). recv(c, sg, ep, func() { unlock(&c.lock) }) From 4ded58bd5a00f9f751bfc02cc1b7dd5970632a02 Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Wed, 13 Jan 2016 15:52:54 -0800 Subject: [PATCH 111/117] net/http/httputil: Keep response headers when response ContentLength is 0. Current code does not print any response headers from httputil.DumpResponse(). PUT /miniocloud/new-file HTTP/1.1 Host: s3.amazonaws.com User-Agent: Go-http-client/1.1 Content-Length: 11 Accept-Encoding: gzip HTTP/1.1 200 OK With this fix we get an appropriate output for httputil.DumpResponse(). PUT /miniocloud/new-file HTTP/1.1 Host: s3.amazonaws.com User-Agent: Go-http-client/1.1 Content-Length: 11 Accept-Encoding: gzip HTTP/1.1 200 OK Content-Length: 0 Date: Thu, 14 Jan 2016 03:04:42 GMT Etag: "3e25960a79dbc69b674cd4ec67a72c62" Server: AmazonS3 X-Amz-Id-2: qnXyH6sknlovV0Myy3emFAXTNtI/sQIcu1ZXNq/6wd17K32tQ7WNGB1qb3nzCpW2DhfeZ/MbWfw= X-Amz-Request-Id: 8422EACB0CC492BD Fixes #13942 Change-Id: Ida063cc3524a96170d8a837893f7c9f49b6cf98e Reviewed-on: https://go-review.googlesource.com/18624 Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/net/http/httputil/dump.go | 19 +++++++++++++------ src/net/http/httputil/dump_test.go | 21 +++++++++++++++++++++ 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/net/http/httputil/dump.go b/src/net/http/httputil/dump.go index e22cc66dbf..245eed0b21 100644 --- a/src/net/http/httputil/dump.go +++ b/src/net/http/httputil/dump.go @@ -264,19 +264,20 @@ func DumpRequest(req *http.Request, body bool) (dump []byte, err error) { return } -// errNoBody is a sentinel error value used by failureToReadBody so we can detect -// that the lack of body was intentional. +// errNoBody is a sentinel error value used by failureToReadBody so we +// can detect that the lack of body was intentional. var errNoBody = errors.New("sentinel error value") // failureToReadBody is a io.ReadCloser that just returns errNoBody on -// Read. It's swapped in when we don't actually want to consume the -// body, but need a non-nil one, and want to distinguish the error -// from reading the dummy body. +// Read. It's swapped in when we don't actually want to consume +// the body, but need a non-nil one, and want to distinguish the +// error from reading the dummy body. type failureToReadBody struct{} func (failureToReadBody) Read([]byte) (int, error) { return 0, errNoBody } func (failureToReadBody) Close() error { return nil } +// emptyBody is an instance of empty reader. var emptyBody = ioutil.NopCloser(strings.NewReader("")) // DumpResponse is like DumpRequest but dumps a response. @@ -286,7 +287,13 @@ func DumpResponse(resp *http.Response, body bool) (dump []byte, err error) { savecl := resp.ContentLength if !body { - resp.Body = failureToReadBody{} + // For content length of zero. Make sure the body is an empty + // reader, instead of returning error through failureToReadBody{}. + if resp.ContentLength == 0 { + resp.Body = emptyBody + } else { + resp.Body = failureToReadBody{} + } } else if resp.Body == nil { resp.Body = emptyBody } else { diff --git a/src/net/http/httputil/dump_test.go b/src/net/http/httputil/dump_test.go index 46bf521723..fc884347a6 100644 --- a/src/net/http/httputil/dump_test.go +++ b/src/net/http/httputil/dump_test.go @@ -288,6 +288,27 @@ Transfer-Encoding: chunked foo 0`, }, + { + res: &http.Response{ + Status: "200 OK", + StatusCode: 200, + Proto: "HTTP/1.1", + ProtoMajor: 1, + ProtoMinor: 1, + ContentLength: 0, + Header: http.Header{ + // To verify if headers are not filtered out. + "Foo1": []string{"Bar1"}, + "Foo2": []string{"Bar2"}, + }, + Body: nil, + }, + body: false, // to verify we see 0, not empty. + want: `HTTP/1.1 200 OK +Foo1: Bar1 +Foo2: Bar2 +Content-Length: 0`, + }, } func TestDumpResponse(t *testing.T) { From cd41db34bcd1776a783fb7507b68705a7de4e54a Mon Sep 17 00:00:00 2001 From: Alberto Donizetti Date: Sat, 30 Jan 2016 22:01:00 +0100 Subject: [PATCH 112/117] regexp: remove unreachable code Found running go vet on the package. It barks that regexp/backtrack.go:257: unreachable code regexp/backtrack.go:302: unreachable code For #11041 Change-Id: I0f5ba0d6183108fba3d144991b826273db0ffb09 Reviewed-on: https://go-review.googlesource.com/19824 Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/regexp/backtrack.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/regexp/backtrack.go b/src/regexp/backtrack.go index fd95604fe4..3a1100dde8 100644 --- a/src/regexp/backtrack.go +++ b/src/regexp/backtrack.go @@ -254,7 +254,6 @@ func (m *machine) tryBacktrack(b *bitState, i input, pc uint32, pos int) bool { } panic("bad arg in InstCapture") - continue case syntax.InstEmptyWidth: if syntax.EmptyOp(inst.Arg)&^i.context(pos) != 0 { @@ -299,7 +298,6 @@ func (m *machine) tryBacktrack(b *bitState, i input, pc uint32, pos int) bool { // Otherwise, continue on in hope of a longer match. continue } - panic("unreachable") } return m.matched From 735e5a483c428d6e99e7f62f7b40b3369afb3591 Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Thu, 18 Feb 2016 11:02:39 -0500 Subject: [PATCH 113/117] cmd/compile: stop aligning string data Makes godoc 10KB smaller. For #6853. Change-Id: Id54bd8c82cb2a1ba11d2d724e3107f73024b19d9 Reviewed-on: https://go-review.googlesource.com/19696 Run-TryBot: David Crawshaw TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/cmd/compile/internal/gc/obj.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go index 66549be5c4..0a96da61fa 100644 --- a/src/cmd/compile/internal/gc/obj.go +++ b/src/cmd/compile/internal/gc/obj.go @@ -233,8 +233,7 @@ func stringsym(s string) (hdr, data *Sym) { off = dsname(symdata, off, s[n:n+m]) } - off = duint8(symdata, off, 0) // terminating NUL for runtime - off = (off + Widthptr - 1) &^ (Widthptr - 1) // round to pointer alignment + off = duint8(symdata, off, 0) // terminating NUL for runtime ggloblsym(symdata, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL) return symhdr, symdata From 5583e8a4213467d3401710873f67403cb2de22f7 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 23 Feb 2016 10:42:06 -0800 Subject: [PATCH 114/117] spec: fix EBNF for slice syntax The () parentheses grouped wrongly. Removed them completely in favor of separate 2- and 3-index slice alternatives which is clearer. Fixes #14477. Change-Id: I0b7521ac912130d9ea8740b8793b3b88e2609418 Reviewed-on: https://go-review.googlesource.com/19853 Reviewed-by: Ian Lance Taylor --- doc/go_spec.html | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/doc/go_spec.html b/doc/go_spec.html index 6b6e75c7c9..437fc066bb 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,6 +1,6 @@ @@ -2443,9 +2443,8 @@ PrimaryExpr = Selector = "." identifier . Index = "[" Expression "]" . -Slice = "[" ( [ Expression ] ":" [ Expression ] ) | - ( [ Expression ] ":" Expression ":" Expression ) - "]" . +Slice = "[" [ Expression ] ":" [ Expression ] "]" | + "[" [ Expression ] ":" Expression ":" Expression "]" . TypeAssertion = "." "(" Type ")" . Arguments = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" . From 676550d040fcd91d080df5df85b61b3f32393e6f Mon Sep 17 00:00:00 2001 From: Paul Marks Date: Mon, 8 Feb 2016 20:25:38 -0800 Subject: [PATCH 115/117] net: use dialTCP cancelation for DualStack dialing. The previous Happy Eyeballs implementation would intentionally leak connections, because dialTCP could not be reliably terminated upon losing the race. Now that dialTCP supports cancelation (plan9 excluded), dialParallel can wait for responses from both the primary and fallback racers, strictly before returning control to the caller. In dial_test.go, we no longer need Sleep to avoid leaks. Also, fix a typo in the Benchmark IPv4 address. Updates #11225 Fixes #14279 Change-Id: Ibf3fe5c7ac2f7a438c1ab2cdb57032beb8bc27b5 Reviewed-on: https://go-review.googlesource.com/19390 Reviewed-by: Mikio Hara Reviewed-by: Brad Fitzpatrick --- src/net/dial.go | 97 ++++++++++++++++++++------------- src/net/dial_test.go | 125 +++++++++++++++++++++++++++++++------------ 2 files changed, 151 insertions(+), 71 deletions(-) diff --git a/src/net/dial.go b/src/net/dial.go index 193776fe41..0661c3ecdf 100644 --- a/src/net/dial.go +++ b/src/net/dial.go @@ -6,6 +6,7 @@ package net import ( "errors" + "runtime" "time" ) @@ -225,8 +226,10 @@ func (d *Dialer) Dial(network, address string) (Conn, error) { finalDeadline: finalDeadline, } + // DualStack mode requires that dialTCP support cancelation. This is + // not available on plan9 (golang.org/issue/11225), so we ignore it. var primaries, fallbacks addrList - if d.DualStack && network == "tcp" { + if d.DualStack && network == "tcp" && runtime.GOOS != "plan9" { primaries, fallbacks = addrs.partition(isIPv4) } else { primaries = addrs @@ -236,9 +239,9 @@ func (d *Dialer) Dial(network, address string) (Conn, error) { if len(fallbacks) == 0 { // dialParallel can accept an empty fallbacks list, // but this shortcut avoids the goroutine/channel overhead. - c, err = dialSerial(ctx, primaries, nil) + c, err = dialSerial(ctx, primaries, ctx.Cancel) } else { - c, err = dialParallel(ctx, primaries, fallbacks) + c, err = dialParallel(ctx, primaries, fallbacks, ctx.Cancel) } if d.KeepAlive > 0 && err == nil { @@ -255,10 +258,9 @@ func (d *Dialer) Dial(network, address string) (Conn, error) { // head start. It returns the first established connection and // closes the others. Otherwise it returns an error from the first // primary address. -func dialParallel(ctx *dialContext, primaries, fallbacks addrList) (Conn, error) { - results := make(chan dialResult) // unbuffered, so dialSerialAsync can detect race loss & cleanup +func dialParallel(ctx *dialContext, primaries, fallbacks addrList, userCancel <-chan struct{}) (Conn, error) { + results := make(chan dialResult, 2) cancel := make(chan struct{}) - defer close(cancel) // Spawn the primary racer. go dialSerialAsync(ctx, primaries, nil, cancel, results) @@ -267,28 +269,59 @@ func dialParallel(ctx *dialContext, primaries, fallbacks addrList) (Conn, error) fallbackTimer := time.NewTimer(ctx.fallbackDelay()) go dialSerialAsync(ctx, fallbacks, fallbackTimer, cancel, results) - var primaryErr error - for nracers := 2; nracers > 0; nracers-- { - res := <-results - // If we're still waiting for a connection, then hasten the delay. - // Otherwise, disable the Timer and let cancel take over. - if fallbackTimer.Stop() && res.error != nil { - fallbackTimer.Reset(0) - } - if res.error == nil { - return res.Conn, nil - } - if res.primary { - primaryErr = res.error + // Wait for both racers to succeed or fail. + var primaryResult, fallbackResult dialResult + for !primaryResult.done || !fallbackResult.done { + select { + case <-userCancel: + // Forward an external cancelation request. + if cancel != nil { + close(cancel) + cancel = nil + } + userCancel = nil + case res := <-results: + // Drop the result into its assigned bucket. + if res.primary { + primaryResult = res + } else { + fallbackResult = res + } + // On success, cancel the other racer (if one exists.) + if res.error == nil && cancel != nil { + close(cancel) + cancel = nil + } + // If the fallbackTimer was pending, then either we've canceled the + // fallback because we no longer want it, or we haven't canceled yet + // and therefore want it to wake up immediately. + if fallbackTimer.Stop() && cancel != nil { + fallbackTimer.Reset(0) + } } } - return nil, primaryErr + + // Return, in order of preference: + // 1. The primary connection (but close the other if we got both.) + // 2. The fallback connection. + // 3. The primary error. + if primaryResult.error == nil { + if fallbackResult.error == nil { + fallbackResult.Conn.Close() + } + return primaryResult.Conn, nil + } else if fallbackResult.error == nil { + return fallbackResult.Conn, nil + } else { + return nil, primaryResult.error + } } type dialResult struct { Conn error primary bool + done bool } // dialSerialAsync runs dialSerial after some delay, and returns the @@ -300,19 +333,11 @@ func dialSerialAsync(ctx *dialContext, ras addrList, timer *time.Timer, cancel < select { case <-timer.C: case <-cancel: - return + // dialSerial will immediately return errCanceled in this case. } } c, err := dialSerial(ctx, ras, cancel) - select { - case results <- dialResult{c, err, timer == nil}: - // We won the race. - case <-cancel: - // The other goroutine won the race. - if c != nil { - c.Close() - } - } + results <- dialResult{Conn: c, error: err, primary: timer == nil, done: true} } // dialSerial connects to a list of addresses in sequence, returning @@ -336,11 +361,11 @@ func dialSerial(ctx *dialContext, ras addrList, cancel <-chan struct{}) (Conn, e break } - // dialTCP does not support cancelation (see golang.org/issue/11225), - // so if cancel fires, we'll continue trying to connect until the next - // timeout, or return a spurious connection for the caller to close. + // If this dial is canceled, the implementation is expected to complete + // quickly, but it's still possible that we could return a spurious Conn, + // which the caller must Close. dialer := func(d time.Time) (Conn, error) { - return dialSingle(ctx, ra, d) + return dialSingle(ctx, ra, d, cancel) } c, err := dial(ctx.network, ra, dialer, partialDeadline) if err == nil { @@ -360,7 +385,7 @@ func dialSerial(ctx *dialContext, ras addrList, cancel <-chan struct{}) (Conn, e // dialSingle attempts to establish and returns a single connection to // the destination address. This must be called through the OS-specific // dial function, because some OSes don't implement the deadline feature. -func dialSingle(ctx *dialContext, ra Addr, deadline time.Time) (c Conn, err error) { +func dialSingle(ctx *dialContext, ra Addr, deadline time.Time, cancel <-chan struct{}) (c Conn, err error) { la := ctx.LocalAddr if la != nil && la.Network() != ra.Network() { return nil, &OpError{Op: "dial", Net: ctx.network, Source: la, Addr: ra, Err: errors.New("mismatched local address type " + la.Network())} @@ -368,7 +393,7 @@ func dialSingle(ctx *dialContext, ra Addr, deadline time.Time) (c Conn, err erro switch ra := ra.(type) { case *TCPAddr: la, _ := la.(*TCPAddr) - c, err = testHookDialTCP(ctx.network, la, ra, deadline, ctx.Cancel) + c, err = testHookDialTCP(ctx.network, la, ra, deadline, cancel) case *UDPAddr: la, _ := la.(*UDPAddr) c, err = dialUDP(ctx.network, la, ra, deadline) diff --git a/src/net/dial_test.go b/src/net/dial_test.go index 1a9dfb26d3..1df923f14b 100644 --- a/src/net/dial_test.go +++ b/src/net/dial_test.go @@ -228,9 +228,8 @@ func TestDialerDualStackFDLeak(t *testing.T) { // expected to hang until the timeout elapses. These addresses are reserved // for benchmarking by RFC 6890. const ( - slowDst4 = "192.18.0.254" - slowDst6 = "2001:2::254" - slowTimeout = 1 * time.Second + slowDst4 = "198.18.0.254" + slowDst6 = "2001:2::254" ) // In some environments, the slow IPs may be explicitly unreachable, and fail @@ -239,7 +238,10 @@ const ( func slowDialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time, cancel <-chan struct{}) (*TCPConn, error) { c, err := dialTCP(net, laddr, raddr, deadline, cancel) if ParseIP(slowDst4).Equal(raddr.IP) || ParseIP(slowDst6).Equal(raddr.IP) { - time.Sleep(deadline.Sub(time.Now())) + select { + case <-cancel: + case <-time.After(deadline.Sub(time.Now())): + } } return c, err } @@ -283,6 +285,9 @@ func TestDialParallel(t *testing.T) { if !supportsIPv4 || !supportsIPv6 { t.Skip("both IPv4 and IPv6 are required") } + if runtime.GOOS == "plan9" { + t.Skip("skipping on plan9; cannot cancel dialTCP, golang.org/issue/11225") + } closedPortDelay, expectClosedPortDelay := dialClosedPort() if closedPortDelay > expectClosedPortDelay { @@ -388,7 +393,6 @@ func TestDialParallel(t *testing.T) { fallbacks := makeAddrs(tt.fallbacks, dss.port) d := Dialer{ FallbackDelay: fallbackDelay, - Timeout: slowTimeout, } ctx := &dialContext{ Dialer: d, @@ -397,7 +401,7 @@ func TestDialParallel(t *testing.T) { finalDeadline: d.deadline(time.Now()), } startTime := time.Now() - c, err := dialParallel(ctx, primaries, fallbacks) + c, err := dialParallel(ctx, primaries, fallbacks, nil) elapsed := time.Now().Sub(startTime) if c != nil { @@ -417,9 +421,27 @@ func TestDialParallel(t *testing.T) { } else if !(elapsed <= expectElapsedMax) { t.Errorf("#%d: got %v; want <= %v", i, elapsed, expectElapsedMax) } + + // Repeat each case, ensuring that it can be canceled quickly. + cancel := make(chan struct{}) + var wg sync.WaitGroup + wg.Add(1) + go func() { + time.Sleep(5 * time.Millisecond) + close(cancel) + wg.Done() + }() + startTime = time.Now() + c, err = dialParallel(ctx, primaries, fallbacks, cancel) + if c != nil { + c.Close() + } + elapsed = time.Now().Sub(startTime) + if elapsed > 100*time.Millisecond { + t.Errorf("#%d (cancel): got %v; want <= 100ms", i, elapsed) + } + wg.Wait() } - // Wait for any slowDst4/slowDst6 connections to timeout. - time.Sleep(slowTimeout * 3 / 2) } func lookupSlowFast(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) { @@ -462,8 +484,6 @@ func TestDialerFallbackDelay(t *testing.T) { {true, 200 * time.Millisecond, 200 * time.Millisecond}, // The default is 300ms. {true, 0, 300 * time.Millisecond}, - // This case is last, in order to wait for hanging slowDst6 connections. - {false, 0, slowTimeout}, } handler := func(dss *dualStackServer, ln Listener) { @@ -487,7 +507,7 @@ func TestDialerFallbackDelay(t *testing.T) { } for i, tt := range testCases { - d := &Dialer{DualStack: tt.dualstack, FallbackDelay: tt.delay, Timeout: slowTimeout} + d := &Dialer{DualStack: tt.dualstack, FallbackDelay: tt.delay} startTime := time.Now() c, err := d.Dial("tcp", JoinHostPort("slow6loopback4", dss.port)) @@ -508,17 +528,58 @@ func TestDialerFallbackDelay(t *testing.T) { } } -func TestDialSerialAsyncSpuriousConnection(t *testing.T) { - if runtime.GOOS == "plan9" { - t.Skip("skipping on plan9; no deadline support, golang.org/issue/11932") +func TestDialParallelSpuriousConnection(t *testing.T) { + if !supportsIPv4 || !supportsIPv6 { + t.Skip("both IPv4 and IPv6 are required") } - ln, err := newLocalListener("tcp") + if runtime.GOOS == "plan9" { + t.Skip("skipping on plan9; cannot cancel dialTCP, golang.org/issue/11225") + } + + var wg sync.WaitGroup + wg.Add(2) + handler := func(dss *dualStackServer, ln Listener) { + // Accept one connection per address. + c, err := ln.Accept() + if err != nil { + t.Fatal(err) + } + // The client should close itself, without sending data. + c.SetReadDeadline(time.Now().Add(1 * time.Second)) + var b [1]byte + if _, err := c.Read(b[:]); err != io.EOF { + t.Errorf("got %v; want %v", err, io.EOF) + } + c.Close() + wg.Done() + } + dss, err := newDualStackServer([]streamListener{ + {network: "tcp4", address: "127.0.0.1"}, + {network: "tcp6", address: "::1"}, + }) if err != nil { t.Fatal(err) } - defer ln.Close() + defer dss.teardown() + if err := dss.buildup(handler); err != nil { + t.Fatal(err) + } - d := Dialer{} + const fallbackDelay = 100 * time.Millisecond + + origTestHookDialTCP := testHookDialTCP + defer func() { testHookDialTCP = origTestHookDialTCP }() + testHookDialTCP = func(net string, laddr, raddr *TCPAddr, deadline time.Time, cancel <-chan struct{}) (*TCPConn, error) { + // Sleep long enough for Happy Eyeballs to kick in, and inhibit cancelation. + // This forces dialParallel to juggle two successful connections. + time.Sleep(fallbackDelay * 2) + cancel = nil + return dialTCP(net, laddr, raddr, deadline, cancel) + } + + d := Dialer{ + FallbackDelay: fallbackDelay, + } ctx := &dialContext{ Dialer: d, network: "tcp", @@ -526,28 +587,23 @@ func TestDialSerialAsyncSpuriousConnection(t *testing.T) { finalDeadline: d.deadline(time.Now()), } - results := make(chan dialResult) - cancel := make(chan struct{}) + makeAddr := func(ip string) addrList { + addr, err := ResolveTCPAddr("tcp", JoinHostPort(ip, dss.port)) + if err != nil { + t.Fatal(err) + } + return addrList{addr} + } - // Spawn a connection in the background. - go dialSerialAsync(ctx, addrList{ln.Addr()}, nil, cancel, results) - - // Receive it at the server. - c, err := ln.Accept() + // dialParallel returns one connection (and closes the other.) + c, err := dialParallel(ctx, makeAddr("127.0.0.1"), makeAddr("::1"), nil) if err != nil { t.Fatal(err) } - defer c.Close() + c.Close() - // Tell dialSerialAsync that someone else won the race. - close(cancel) - - // The connection should close itself, without sending data. - c.SetReadDeadline(time.Now().Add(1 * time.Second)) - var b [1]byte - if _, err := c.Read(b[:]); err != io.EOF { - t.Errorf("got %v; want %v", err, io.EOF) - } + // The server should've seen both connections. + wg.Wait() } func TestDialerPartialDeadline(t *testing.T) { @@ -676,7 +732,6 @@ func TestDialerDualStack(t *testing.T) { c.Close() } } - time.Sleep(timeout * 3 / 2) // wait for the dial racers to stop } func TestDialerKeepAlive(t *testing.T) { From 9877900c8c9c21704c0052c65e39216c6f400706 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 23 Feb 2016 07:46:01 +0000 Subject: [PATCH 116/117] Revert "cmd/compile: move hiter, hmap, and scase definitions into builtin.go" This reverts commit f28bbb776a050cc3edca2bbe1241d81217a7a251. Change-Id: I82fb81dcff3ddcaefef72949f1ef3a41bcd22301 Reviewed-on: https://go-review.googlesource.com/19849 Run-TryBot: Matthew Dempsky TryBot-Result: Gobot Gobot Reviewed-by: Keith Randall --- src/cmd/compile/internal/gc/builtin.go | 10 +- .../compile/internal/gc/builtin/runtime.go | 49 +--------- src/cmd/compile/internal/gc/fmt.go | 8 ++ src/cmd/compile/internal/gc/go.go | 4 +- src/cmd/compile/internal/gc/range.go | 22 ++--- src/cmd/compile/internal/gc/reflect.go | 94 ++++++++++++++++++- src/cmd/compile/internal/gc/select.go | 30 +++++- src/cmd/compile/internal/gc/subr.go | 13 +-- src/cmd/compile/internal/gc/walk.go | 4 +- src/reflect/type.go | 1 + src/runtime/hashmap.go | 15 +-- src/runtime/runtime2.go | 2 + src/runtime/select.go | 4 +- src/runtime/type.go | 1 + 14 files changed, 163 insertions(+), 94 deletions(-) diff --git a/src/cmd/compile/internal/gc/builtin.go b/src/cmd/compile/internal/gc/builtin.go index d1827ef0fe..4a6e56fe47 100644 --- a/src/cmd/compile/internal/gc/builtin.go +++ b/src/cmd/compile/internal/gc/builtin.go @@ -4,10 +4,6 @@ package gc const runtimeimport = "" + "package runtime safe\n" + - "type @\"\".hbucket uint8\n" + - "type @\"\".hmap struct { @\"\".count int; @\"\".flags uint8; B uint8; @\"\".hash0 uint32; @\"\".buckets *@\"\".hbucket; @\"\".oldbuckets *@\"\".hbucket; @\"\".nevacuate uintptr; @\"\".overflow *[2]*[]*@\"\".hbucket }\n" + - "type @\"\".hiter struct { @\"\".key *byte; @\"\".value *byte; @\"\".t *byte; @\"\".h *@\"\".hmap; @\"\".buckets *@\"\".hbucket; @\"\".bptr *@\"\".hbucket; @\"\".overflow [2]*[]*@\"\".hbucket; @\"\".startBucket uintptr; @\"\".offset uint8; @\"\".wrapped bool; B uint8; @\"\".i uint8; @\"\".bucket uintptr; @\"\".checkBucket uintptr }\n" + - "type @\"\".scase struct { @\"\".elem *byte; @\"\".c *byte; @\"\".pc uintptr; @\"\".kind uint16; @\"\".so uint16; @\"\".receivedp *bool; @\"\".releasetime int64 }\n" + "func @\"\".newobject (@\"\".typ·2 *byte) (? *any)\n" + "func @\"\".panicindex ()\n" + "func @\"\".panicslice ()\n" + @@ -70,7 +66,7 @@ const runtimeimport = "" + "func @\"\".panicdottype (@\"\".have·1 *byte, @\"\".want·2 *byte, @\"\".iface·3 *byte)\n" + "func @\"\".ifaceeq (@\"\".i1·2 any, @\"\".i2·3 any) (@\"\".ret·1 bool)\n" + "func @\"\".efaceeq (@\"\".i1·2 any, @\"\".i2·3 any) (@\"\".ret·1 bool)\n" + - "func @\"\".makemap (@\"\".mapType·2 *byte, @\"\".hint·3 int64, @\"\".mapbuf·4 *@\"\".hmap, @\"\".bucketbuf·5 *any) (@\"\".hmap·1 map[any]any)\n" + + "func @\"\".makemap (@\"\".mapType·2 *byte, @\"\".hint·3 int64, @\"\".mapbuf·4 *any, @\"\".bucketbuf·5 *any) (@\"\".hmap·1 map[any]any)\n" + "func @\"\".mapaccess1 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 *any) (@\"\".val·1 *any)\n" + "func @\"\".mapaccess1_fast32 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n" + "func @\"\".mapaccess1_fast64 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n" + @@ -80,9 +76,9 @@ const runtimeimport = "" + "func @\"\".mapaccess2_fast64 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n" + "func @\"\".mapaccess2_faststr (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n" + "func @\"\".mapassign1 (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 *any, @\"\".val·4 *any)\n" + - "func @\"\".mapiterinit (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".hiter·3 *@\"\".hiter)\n" + + "func @\"\".mapiterinit (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".hiter·3 *any)\n" + "func @\"\".mapdelete (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 *any)\n" + - "func @\"\".mapiternext (@\"\".hiter·1 *@\"\".hiter)\n" + + "func @\"\".mapiternext (@\"\".hiter·1 *any)\n" + "func @\"\".makechan (@\"\".chanType·2 *byte, @\"\".hint·3 int64) (@\"\".hchan·1 chan any)\n" + "func @\"\".chanrecv1 (@\"\".chanType·1 *byte, @\"\".hchan·2 <-chan any, @\"\".elem·3 *any)\n" + "func @\"\".chanrecv2 (@\"\".chanType·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any) (? bool)\n" + diff --git a/src/cmd/compile/internal/gc/builtin/runtime.go b/src/cmd/compile/internal/gc/builtin/runtime.go index e067d0bfa8..0fe6242e74 100644 --- a/src/cmd/compile/internal/gc/builtin/runtime.go +++ b/src/cmd/compile/internal/gc/builtin/runtime.go @@ -12,49 +12,6 @@ package runtime // emitted by compiler, not referred to by go programs -type hbucket byte // placeholder - -// Changes here must also be made in src/runtime/hashmap.go. -type hmap struct { - count int - flags uint8 - B uint8 - hash0 uint32 - buckets *hbucket - oldbuckets *hbucket - nevacuate uintptr - overflow *[2]*[]*hbucket -} - -// Changes here must also be made in src/runtime/hashmap.go. -type hiter struct { - key *byte // field name known to walkrange - value *byte // field name known to walkrange - t *byte // *maptype - h *hmap - buckets *hbucket - bptr *hbucket - overflow [2]*[]*hbucket - startBucket uintptr - offset uint8 - wrapped bool - B uint8 - i uint8 - bucket uintptr - checkBucket uintptr -} - -// Changes here must also be made in src/runtime/select.go. -type scase struct { - elem *byte - c *byte - pc uintptr - kind uint16 - so uint16 - receivedp *bool - releasetime int64 -} - func newobject(typ *byte) *any func panicindex() func panicslice() @@ -128,7 +85,7 @@ func ifaceeq(i1 any, i2 any) (ret bool) func efaceeq(i1 any, i2 any) (ret bool) // *byte is really *runtime.Type -func makemap(mapType *byte, hint int64, mapbuf *hmap, bucketbuf *any) (hmap map[any]any) +func makemap(mapType *byte, hint int64, mapbuf *any, bucketbuf *any) (hmap map[any]any) func mapaccess1(mapType *byte, hmap map[any]any, key *any) (val *any) func mapaccess1_fast32(mapType *byte, hmap map[any]any, key any) (val *any) func mapaccess1_fast64(mapType *byte, hmap map[any]any, key any) (val *any) @@ -138,9 +95,9 @@ func mapaccess2_fast32(mapType *byte, hmap map[any]any, key any) (val *any, pres func mapaccess2_fast64(mapType *byte, hmap map[any]any, key any) (val *any, pres bool) func mapaccess2_faststr(mapType *byte, hmap map[any]any, key any) (val *any, pres bool) func mapassign1(mapType *byte, hmap map[any]any, key *any, val *any) -func mapiterinit(mapType *byte, hmap map[any]any, hiter *hiter) +func mapiterinit(mapType *byte, hmap map[any]any, hiter *any) func mapdelete(mapType *byte, hmap map[any]any, key *any) -func mapiternext(hiter *hiter) +func mapiternext(hiter *any) // *byte is really *runtime.Type func makechan(chanType *byte, hint int64) (hchan chan any) diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go index 91035b5d07..c0a1170839 100644 --- a/src/cmd/compile/internal/gc/fmt.go +++ b/src/cmd/compile/internal/gc/fmt.go @@ -647,6 +647,14 @@ func typefmt(t *Type, flag int) string { return fmt.Sprintf("map.bucket[%v]%v", t.Map.Down, t.Map.Type) } + if t.Map.Hmap == t { + return fmt.Sprintf("map.hdr[%v]%v", t.Map.Down, t.Map.Type) + } + + if t.Map.Hiter == t { + return fmt.Sprintf("map.iter[%v]%v", t.Map.Down, t.Map.Type) + } + Yyerror("unknown internal map type") } diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go index cdb976999f..1523c5efb3 100644 --- a/src/cmd/compile/internal/gc/go.go +++ b/src/cmd/compile/internal/gc/go.go @@ -191,7 +191,9 @@ type Type struct { // TMAP Bucket *Type // internal type representing a hash bucket - Map *Type // link from hash bucket type back to the map type. + Hmap *Type // internal type representing a Hmap (map header object) + Hiter *Type // internal type representing hash iterator state + Map *Type // link from the above 3 internal types back to the map type. Maplineno int32 // first use of TFORW as map key Embedlineno int32 // first use of TFORW as embedded type diff --git a/src/cmd/compile/internal/gc/range.go b/src/cmd/compile/internal/gc/range.go index 8c2eca20d4..4386bcfeed 100644 --- a/src/cmd/compile/internal/gc/range.go +++ b/src/cmd/compile/internal/gc/range.go @@ -223,28 +223,24 @@ func walkrange(n *Node) { case TMAP: ha := a - th := syslook("hiter", 0).Type - keytype := t.Down - valtype := t.Type - + th := hiter(t) hit := prealloc[n] hit.Type = th n.Left = nil - - // These depend on hiter's field names. See builtin/runtime.go:hiter. - keyname := newname(Pkglookup("key", Runtimepkg)) - valname := newname(Pkglookup("value", Runtimepkg)) + keyname := newname(th.Type.Sym) // depends on layout of iterator struct. See reflect.go:hiter + valname := newname(th.Type.Down.Sym) // ditto fn := syslook("mapiterinit", 1) - substArgTypes(fn, keytype, valtype) + + substArgTypes(fn, t.Down, t.Type, th) init = list(init, mkcall1(fn, nil, nil, typename(t), ha, Nod(OADDR, hit, nil))) n.Left = Nod(ONE, Nod(ODOT, hit, keyname), nodnil()) - n.Right = mkcall("mapiternext", nil, nil, Nod(OADDR, hit, nil)) + fn = syslook("mapiternext", 1) + substArgTypes(fn, th) + n.Right = mkcall1(fn, nil, nil, Nod(OADDR, hit, nil)) key := Nod(ODOT, hit, keyname) - key = Nod(OCONVNOP, key, nil) - key.Type = Ptrto(keytype) key = Nod(OIND, key, nil) if v1 == nil { body = nil @@ -252,8 +248,6 @@ func walkrange(n *Node) { body = list1(Nod(OAS, v1, key)) } else { val := Nod(ODOT, hit, valname) - val = Nod(OCONVNOP, val, nil) - val.Type = Ptrto(valtype) val = Nod(OIND, val, nil) a := Nod(OAS2, nil, nil) a.List = list(list1(v1), v2) diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go index 369d015f19..8693e3c112 100644 --- a/src/cmd/compile/internal/gc/reflect.go +++ b/src/cmd/compile/internal/gc/reflect.go @@ -149,6 +149,92 @@ func mapbucket(t *Type) *Type { return bucket } +// Builds a type representing a Hmap structure for the given map type. +// Make sure this stays in sync with ../../../../runtime/hashmap.go! +func hmap(t *Type) *Type { + if t.Hmap != nil { + return t.Hmap + } + + bucket := mapbucket(t) + var field [8]*Type + field[0] = makefield("count", Types[TINT]) + field[1] = makefield("flags", Types[TUINT8]) + field[2] = makefield("B", Types[TUINT8]) + field[3] = makefield("hash0", Types[TUINT32]) + field[4] = makefield("buckets", Ptrto(bucket)) + field[5] = makefield("oldbuckets", Ptrto(bucket)) + field[6] = makefield("nevacuate", Types[TUINTPTR]) + field[7] = makefield("overflow", Types[TUNSAFEPTR]) + + h := typ(TSTRUCT) + h.Noalg = true + h.Local = t.Local + h.Type = field[0] + for n := int32(0); n < int32(len(field)-1); n++ { + field[n].Down = field[n+1] + } + field[len(field)-1].Down = nil + dowidth(h) + t.Hmap = h + h.Map = t + return h +} + +func hiter(t *Type) *Type { + if t.Hiter != nil { + return t.Hiter + } + + // build a struct: + // hiter { + // key *Key + // val *Value + // t *MapType + // h *Hmap + // buckets *Bucket + // bptr *Bucket + // overflow0 unsafe.Pointer + // overflow1 unsafe.Pointer + // startBucket uintptr + // stuff uintptr + // bucket uintptr + // checkBucket uintptr + // } + // must match ../../../../runtime/hashmap.go:hiter. + var field [12]*Type + field[0] = makefield("key", Ptrto(t.Down)) + + field[1] = makefield("val", Ptrto(t.Type)) + field[2] = makefield("t", Ptrto(Types[TUINT8])) + field[3] = makefield("h", Ptrto(hmap(t))) + field[4] = makefield("buckets", Ptrto(mapbucket(t))) + field[5] = makefield("bptr", Ptrto(mapbucket(t))) + field[6] = makefield("overflow0", Types[TUNSAFEPTR]) + field[7] = makefield("overflow1", Types[TUNSAFEPTR]) + field[8] = makefield("startBucket", Types[TUINTPTR]) + field[9] = makefield("stuff", Types[TUINTPTR]) // offset+wrapped+B+I + field[10] = makefield("bucket", Types[TUINTPTR]) + field[11] = makefield("checkBucket", Types[TUINTPTR]) + + // build iterator struct holding the above fields + i := typ(TSTRUCT) + + i.Noalg = true + i.Type = field[0] + for n := int32(0); n < int32(len(field)-1); n++ { + field[n].Down = field[n+1] + } + field[len(field)-1].Down = nil + dowidth(i) + if i.Width != int64(12*Widthptr) { + Yyerror("hash_iter size not correct %d %d", i.Width, 12*Widthptr) + } + t.Hiter = i + i.Map = t + return i +} + // f is method type, with receiver. // return function type, receiver as first argument (or not). func methodfunc(f *Type, receiver *Type) *Type { @@ -1026,11 +1112,13 @@ ok: s2 := dtypesym(t.Type) s3 := dtypesym(mapbucket(t)) + s4 := dtypesym(hmap(t)) ot = dcommontype(s, ot, t) xt = ot - 2*Widthptr ot = dsymptr(s, ot, s1, 0) ot = dsymptr(s, ot, s2, 0) ot = dsymptr(s, ot, s3, 0) + ot = dsymptr(s, ot, s4, 0) if t.Down.Width > MAXKEYSIZE { ot = duint8(s, ot, uint8(Widthptr)) ot = duint8(s, ot, 1) // indirect @@ -1251,10 +1339,8 @@ func dalgsym(t *Type) *Sym { hashfunc = typesymprefix(".hashfunc", t) eqfunc = typesymprefix(".eqfunc", t) - if Debug['A'] == 0 { - genhash(hash, t) - geneq(eq, t) - } + genhash(hash, t) + geneq(eq, t) // make Go funcs (closures) for calling hash and equal from Go dsymptr(hashfunc, 0, hash, 0) diff --git a/src/cmd/compile/internal/gc/select.go b/src/cmd/compile/internal/gc/select.go index 9a619a6d5a..e770c8f18d 100644 --- a/src/cmd/compile/internal/gc/select.go +++ b/src/cmd/compile/internal/gc/select.go @@ -318,9 +318,35 @@ out: lineno = int32(lno) } -// Keep in sync with src/runtime/select.go. +// Keep in sync with src/runtime/runtime2.go and src/runtime/select.go. func selecttype(size int32) *Type { - scase := syslook("scase", 0) + // TODO(dvyukov): it's possible to generate SudoG and Scase only once + // and then cache; and also cache Select per size. + sudog := Nod(OTSTRUCT, nil, nil) + + sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("g")), typenod(Ptrto(Types[TUINT8])))) + sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("selectdone")), typenod(Ptrto(Types[TUINT8])))) + sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("next")), typenod(Ptrto(Types[TUINT8])))) + sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("prev")), typenod(Ptrto(Types[TUINT8])))) + sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("elem")), typenod(Ptrto(Types[TUINT8])))) + sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("releasetime")), typenod(Types[TUINT64]))) + sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("nrelease")), typenod(Types[TINT32]))) + sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("waitlink")), typenod(Ptrto(Types[TUINT8])))) + typecheck(&sudog, Etype) + sudog.Type.Noalg = true + sudog.Type.Local = true + + scase := Nod(OTSTRUCT, nil, nil) + scase.List = list(scase.List, Nod(ODCLFIELD, newname(Lookup("elem")), typenod(Ptrto(Types[TUINT8])))) + scase.List = list(scase.List, Nod(ODCLFIELD, newname(Lookup("chan")), typenod(Ptrto(Types[TUINT8])))) + scase.List = list(scase.List, Nod(ODCLFIELD, newname(Lookup("pc")), typenod(Types[TUINTPTR]))) + scase.List = list(scase.List, Nod(ODCLFIELD, newname(Lookup("kind")), typenod(Types[TUINT16]))) + scase.List = list(scase.List, Nod(ODCLFIELD, newname(Lookup("so")), typenod(Types[TUINT16]))) + scase.List = list(scase.List, Nod(ODCLFIELD, newname(Lookup("receivedp")), typenod(Ptrto(Types[TUINT8])))) + scase.List = list(scase.List, Nod(ODCLFIELD, newname(Lookup("releasetime")), typenod(Types[TUINT64]))) + typecheck(&scase, Etype) + scase.Type.Noalg = true + scase.Type.Local = true sel := Nod(OTSTRUCT, nil, nil) sel.List = list(sel.List, Nod(ODCLFIELD, newname(Lookup("tcase")), typenod(Types[TUINT16]))) diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go index 0415fd3da2..b6a26489e6 100644 --- a/src/cmd/compile/internal/gc/subr.go +++ b/src/cmd/compile/internal/gc/subr.go @@ -1413,21 +1413,16 @@ func deep(t *Type) *Type { if t == nil { return nil } - if t.Etype == TANY { - nt := shallow(t) - nt.Copyany = true - return nt - } - if t.Sym != nil { - // share named types - return t - } var nt *Type switch t.Etype { default: nt = t // share from here down + case TANY: + nt = shallow(t) + nt.Copyany = true + case TPTR32, TPTR64, TCHAN, TARRAY: nt = shallow(t) nt.Type = deep(t.Type) diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index f3112c3a61..f324d5e00f 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -1375,7 +1375,7 @@ opswitch: r := nodnil() // bucket buffer if n.Esc == EscNone { // Allocate hmap buffer on stack. - var_ := temp(syslook("hmap", 0).Type) + var_ := temp(hmap(t)) a = Nod(OAS, var_, nil) // zero temp typecheck(&a, Etop) @@ -1393,7 +1393,7 @@ opswitch: r = Nod(OADDR, var_, nil) } - substArgTypes(fn, mapbucket(t), t.Down, t.Type) + substArgTypes(fn, hmap(t), mapbucket(t), t.Down, t.Type) n = mkcall1(fn, n.Type, init, typename(n.Type), conv(n.Left, Types[TINT64]), a, r) case OMAKESLICE: diff --git a/src/reflect/type.go b/src/reflect/type.go index 91563dcf7e..003c610cb1 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -340,6 +340,7 @@ type mapType struct { key *rtype // map key type elem *rtype // map element (value) type bucket *rtype // internal bucket structure + hmap *rtype // internal map header keysize uint8 // size of key slot indirectkey uint8 // store ptr to key instead of key itself valuesize uint8 // size of value slot diff --git a/src/runtime/hashmap.go b/src/runtime/hashmap.go index fcfcd4b607..892a79a914 100644 --- a/src/runtime/hashmap.go +++ b/src/runtime/hashmap.go @@ -102,7 +102,6 @@ const ( ) // A header for a Go map. -// Changes here must also be made in src/cmd/compile/internal/gc/builtin/runtime.go. type hmap struct { // Note: the format of the Hmap is encoded in ../../cmd/internal/gc/reflect.go and // ../reflect/type.go. Don't change this structure without also changing that code! @@ -138,10 +137,11 @@ type bmap struct { } // A hash iteration structure. -// Changes here must also be made in src/cmd/compile/internal/gc/builtin/runtime.go. +// If you modify hiter, also change cmd/internal/gc/reflect.go to indicate +// the layout of this structure. type hiter struct { - key unsafe.Pointer // Write nil to indicate iteration end (see cmd/compile/internal/gc/range.go). - value unsafe.Pointer + key unsafe.Pointer // Must be in first position. Write nil to indicate iteration end (see cmd/internal/gc/range.go). + value unsafe.Pointer // Must be in second position (see cmd/internal/gc/range.go). t *maptype h *hmap buckets unsafe.Pointer // bucket ptr at hash_iter initialization time @@ -188,10 +188,11 @@ func (h *hmap) createOverflow() { // If h != nil, the map can be created directly in h. // If bucket != nil, bucket can be used as the first bucket. func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap { - if sz := unsafe.Sizeof(hmap{}); sz > 48 { - println("runtime: sizeof(hmap) =", sz) + if sz := unsafe.Sizeof(hmap{}); sz > 48 || sz != uintptr(t.hmap.size) { + println("runtime: sizeof(hmap) =", sz, ", t.hmap.size =", t.hmap.size) throw("bad hmap size") } + if hint < 0 || int64(int32(hint)) != hint { panic("makemap: size out of range") // TODO: make hint an int, then none of this nonsense @@ -253,7 +254,7 @@ func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap { // initialize Hmap if h == nil { - h = &hmap{} + h = (*hmap)(newobject(t.hmap)) } h.count = 0 h.B = B diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go index 5bc5fca7f0..6a4dfa17b8 100644 --- a/src/runtime/runtime2.go +++ b/src/runtime/runtime2.go @@ -160,6 +160,8 @@ type gobuf struct { bp uintptr // for GOEXPERIMENT=framepointer } +// Known to compiler. +// Changes here must also be made in src/cmd/internal/gc/select.go's selecttype. type sudog struct { g *g selectdone *uint32 diff --git a/src/runtime/select.go b/src/runtime/select.go index 25ebdaa595..b6c3fea001 100644 --- a/src/runtime/select.go +++ b/src/runtime/select.go @@ -22,7 +22,7 @@ const ( // Select statement header. // Known to compiler. -// Changes here must also be made in src/cmd/compile/internal/gc/select.go's selecttype. +// Changes here must also be made in src/cmd/internal/gc/select.go's selecttype. type hselect struct { tcase uint16 // total count of scase[] ncase uint16 // currently filled scase[] @@ -33,7 +33,7 @@ type hselect struct { // Select case descriptor. // Known to compiler. -// Changes here must also be made in src/cmd/compile/internal/gc/builtin/runtime.go. +// Changes here must also be made in src/cmd/internal/gc/select.go's selecttype. type scase struct { elem unsafe.Pointer // data element c *hchan // chan diff --git a/src/runtime/type.go b/src/runtime/type.go index 8350976491..d5f3bb1ef0 100644 --- a/src/runtime/type.go +++ b/src/runtime/type.go @@ -60,6 +60,7 @@ type maptype struct { key *_type elem *_type bucket *_type // internal type representing a hash bucket + hmap *_type // internal type representing a hmap keysize uint8 // size of key slot indirectkey bool // store ptr to key instead of key itself valuesize uint8 // size of value slot From 7786f9790561ceda98e9883256ed50d26fa136d6 Mon Sep 17 00:00:00 2001 From: Alberto Donizetti Date: Tue, 23 Feb 2016 18:45:38 +0100 Subject: [PATCH 117/117] unicode/utf16: speed up and clean up Decode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit name old time/op new time/op delta DecodeValidASCII-4 94.7ns ± 1% 87.4ns ± 1% -7.71% (p=0.000 n=10+9) DecodeValidJapaneseChars-4 91.0ns ± 2% 84.8ns ± 0% -6.77% (p=0.000 n=9+10) DecodeRune-4 16.5ns ± 0% 16.6ns ± 2% ~ (p=0.108 n=9+10) For #6957 Change-Id: I618c15c2a42ef7ec6a5cd163b7c3f1a65ca4ad01 Reviewed-on: https://go-review.googlesource.com/19826 Reviewed-by: Rob Pike --- src/unicode/utf16/utf16.go | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/unicode/utf16/utf16.go b/src/unicode/utf16/utf16.go index b497500778..276fce9e56 100644 --- a/src/unicode/utf16/utf16.go +++ b/src/unicode/utf16/utf16.go @@ -36,7 +36,7 @@ func IsSurrogate(r rune) bool { // the Unicode replacement code point U+FFFD. func DecodeRune(r1, r2 rune) rune { if surr1 <= r1 && r1 < surr2 && surr2 <= r2 && r2 < surr3 { - return (r1-surr1)<<10 | (r2 - surr2) + 0x10000 + return (r1-surr1)<<10 | (r2 - surr2) + surrSelf } return replacementChar } @@ -88,21 +88,19 @@ func Decode(s []uint16) []rune { n := 0 for i := 0; i < len(s); i++ { switch r := s[i]; { + case r < surr1, surr3 <= r: + // normal rune + a[n] = rune(r) case surr1 <= r && r < surr2 && i+1 < len(s) && surr2 <= s[i+1] && s[i+1] < surr3: // valid surrogate sequence a[n] = DecodeRune(rune(r), rune(s[i+1])) i++ - n++ - case surr1 <= r && r < surr3: + default: // invalid surrogate sequence a[n] = replacementChar - n++ - default: - // normal rune - a[n] = rune(r) - n++ } + n++ } - return a[0:n] + return a[:n] }