From f098a29630c48543df6c476cfa574ab013cfaaa6 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 6 Aug 2014 16:22:52 -0400 Subject: [PATCH 001/423] runtime: use better hash for non-empty interface The implementation 'return 0' results in too many collisions. LGTM=khr R=golang-codereviews, adonovan, khr CC=golang-codereviews, iant, khr, r https://golang.org/cl/125720044 --- src/pkg/runtime/alg.go | 17 ++++++++++++++++- src/pkg/runtime/iface.goc | 38 -------------------------------------- src/pkg/runtime/runtime.h | 28 +++++++++++++--------------- 3 files changed, 29 insertions(+), 54 deletions(-) diff --git a/src/pkg/runtime/alg.go b/src/pkg/runtime/alg.go index 000d4a18b7..e2917dabb6 100644 --- a/src/pkg/runtime/alg.go +++ b/src/pkg/runtime/alg.go @@ -111,7 +111,22 @@ func nohash(a unsafe.Pointer, s uintptr, h uintptr) uintptr { func interhash(a *interface { f() }, s uintptr, h uintptr) uintptr { - return 0 + tab := (*iface)(unsafe.Pointer(a)).tab + if tab == nil { + return h + } + t := tab._type + fn := goalg(t.alg).hash + if **(**uintptr)(unsafe.Pointer(&fn)) == nohashcode { + // calling nohash will panic too, + // but we can print a better error. + panic(errorString("hash of unhashable type " + *t._string)) + } + if uintptr(t.size) <= ptrSize { + return c1 * fn(unsafe.Pointer(&(*eface)(unsafe.Pointer(a)).data), uintptr(t.size), h^c0) + } else { + return c1 * fn((*eface)(unsafe.Pointer(a)).data, uintptr(t.size), h^c0) + } } func nilinterhash(a *interface{}, s uintptr, h uintptr) uintptr { diff --git a/src/pkg/runtime/iface.goc b/src/pkg/runtime/iface.goc index ec89746470..89c116e127 100644 --- a/src/pkg/runtime/iface.goc +++ b/src/pkg/runtime/iface.goc @@ -475,44 +475,6 @@ func assertE2E2(inter *InterfaceType, e Eface) (ret Eface, ok bool) { ok = e.type != nil; } -static uintptr -ifacehash1(void *data, Type *t, uintptr h) -{ - Alg *alg; - uintptr size; - Eface err; - - if(t == nil) - return 0; - - alg = t->alg; - size = t->size; - if(alg->hash->fn == (void(*)())runtime·nohash) { - // calling nohash will panic too, - // but we can print a better error. - runtime·newErrorString(runtime·catstring(runtime·gostringnocopy((byte*)"hash of unhashable type "), *t->string), &err); - runtime·panic(err); - } - if(size <= sizeof(data)) - return ((uintptr(*)(void**,uintptr,uintptr))alg->hash)(&data, size, h); - else - return ((uintptr(*)(void*,uintptr,uintptr))alg->hash)(data, size, h); -} - -uintptr -runtime·ifacehash(Iface a, uintptr h) -{ - if(a.tab == nil) - return h; - return ifacehash1(a.data, a.tab->type, h); -} - -uintptr -runtime·efacehash(Eface a, uintptr h) -{ - return ifacehash1(a.data, a.type, h); -} - static bool ifaceeq1(void *data1, void *data2, Type *t) { diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h index e6354d7e9c..1d1618b0d6 100644 --- a/src/pkg/runtime/runtime.h +++ b/src/pkg/runtime/runtime.h @@ -651,19 +651,19 @@ enum { }; void runtime·hashinit(void); -uintptr runtime·memhash(void*, uintptr, uintptr); -uintptr runtime·nohash(void*, uintptr, uintptr); -uintptr runtime·strhash(void*, uintptr, uintptr); -uintptr runtime·interhash(void*, uintptr, uintptr); -uintptr runtime·nilinterhash(void*, uintptr, uintptr); -uintptr runtime·f32hash(void*, uintptr, uintptr); -uintptr runtime·f64hash(void*, uintptr, uintptr); -uintptr runtime·c64hash(void*, uintptr, uintptr); -uintptr runtime·c128hash(void*, uintptr, uintptr); -uintptr runtime·aeshash(void*, uintptr, uintptr); -uintptr runtime·aeshash32(void*, uintptr, uintptr); -uintptr runtime·aeshash64(void*, uintptr, uintptr); -uintptr runtime·aeshashstr(void*, uintptr, uintptr); +void runtime·memhash(void*, uintptr, uintptr, uintptr); +void runtime·nohash(void*, uintptr, uintptr, uintptr); +void runtime·strhash(void*, uintptr, uintptr, uintptr); +void runtime·interhash(void*, uintptr, uintptr, uintptr); +void runtime·nilinterhash(void*, uintptr, uintptr, uintptr); +void runtime·f32hash(void*, uintptr, uintptr, uintptr); +void runtime·f64hash(void*, uintptr, uintptr, uintptr); +void runtime·c64hash(void*, uintptr, uintptr, uintptr); +void runtime·c128hash(void*, uintptr, uintptr, uintptr); +void runtime·aeshash(void*, uintptr, uintptr, uintptr); +void runtime·aeshash32(void*, uintptr, uintptr, uintptr); +void runtime·aeshash64(void*, uintptr, uintptr, uintptr); +void runtime·aeshashstr(void*, uintptr, uintptr, uintptr); void runtime·memequal(bool*, uintptr, void*, void*); void runtime·noequal(bool*, uintptr, void*, void*); @@ -876,8 +876,6 @@ void runtime·mallocinit(void); void runtime·chaninit(void); bool runtime·ifaceeq_c(Iface, Iface); bool runtime·efaceeq_c(Eface, Eface); -uintptr runtime·ifacehash(Iface, uintptr); -uintptr runtime·efacehash(Eface, uintptr); void* runtime·malloc(uintptr size); void runtime·runpanic(Panic*); uintptr runtime·getcallersp(void*); From ea3ac6ba75c5b7496b29117687b0859ad40f3f39 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Wed, 6 Aug 2014 13:42:00 -0700 Subject: [PATCH 002/423] runtime: shorten hash declarations LGTM=iant R=dvyukov, iant CC=golang-codereviews https://golang.org/cl/117680044 --- src/cmd/api/goapi.go | 2 +- src/pkg/runtime/alg.go | 34 ++++++++++++++++------------------ 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go index 932b5520f4..fe3c257a55 100644 --- a/src/cmd/api/goapi.go +++ b/src/cmd/api/goapi.go @@ -378,7 +378,7 @@ func (w *Walker) parseFile(dir, file string) (*ast.File, error) { } if w.context != nil && file == fmt.Sprintf("zruntime_defs_%s_%s.go", w.context.GOOS, w.context.GOARCH) { // Just enough to keep the api checker happy. - src := "package runtime; type maptype struct{}; type _type struct{}; type alg struct{}; type mspan struct{}; type m struct{}; type lock struct{}; type slicetype struct{};" + src := "package runtime; type maptype struct{}; type _type struct{}; type alg struct{}; type mspan struct{}; type m struct{}; type lock struct{}; type slicetype struct{}; type iface struct{}; type eface struct{}" f, err = parser.ParseFile(fset, filename, src, 0) if err != nil { log.Fatalf("incorrect generated file: %s", err) diff --git a/src/pkg/runtime/alg.go b/src/pkg/runtime/alg.go index e2917dabb6..251374a946 100644 --- a/src/pkg/runtime/alg.go +++ b/src/pkg/runtime/alg.go @@ -42,9 +42,9 @@ const nacl = GOOS == "nacl" var use_aeshash bool // in asm_*.s -func aeshash(p unsafe.Pointer, s uintptr, h uintptr) uintptr +func aeshash(p unsafe.Pointer, s, h uintptr) uintptr -func memhash(p unsafe.Pointer, s uintptr, h uintptr) uintptr { +func memhash(p unsafe.Pointer, s, h uintptr) uintptr { if !nacl && use_aeshash { return aeshash(p, s, h) } @@ -58,7 +58,7 @@ func memhash(p unsafe.Pointer, s uintptr, h uintptr) uintptr { return h } -func strhash(a *string, s uintptr, h uintptr) uintptr { +func strhash(a *string, s, h uintptr) uintptr { return memhash((*stringStruct)(unsafe.Pointer(a)).str, uintptr(len(*a)), h) } @@ -67,7 +67,7 @@ func strhash(a *string, s uintptr, h uintptr) uintptr { // To avoid long hash chains, we assign a random number // as the hash value for a NaN. -func f32hash(a *float32, s uintptr, h uintptr) uintptr { +func f32hash(a *float32, s, h uintptr) uintptr { f := *a switch { case f == 0: @@ -79,7 +79,7 @@ func f32hash(a *float32, s uintptr, h uintptr) uintptr { } } -func f64hash(a *float64, s uintptr, h uintptr) uintptr { +func f64hash(a *float64, s, h uintptr) uintptr { f := *a switch { case f == 0: @@ -94,24 +94,22 @@ func f64hash(a *float64, s uintptr, h uintptr) uintptr { } } -func c64hash(a *complex64, s uintptr, h uintptr) uintptr { +func c64hash(a *complex64, s, h uintptr) uintptr { x := (*[2]float32)(unsafe.Pointer(a)) return f32hash(&x[1], 4, f32hash(&x[0], 4, h)) } -func c128hash(a *complex128, s uintptr, h uintptr) uintptr { +func c128hash(a *complex128, s, h uintptr) uintptr { x := (*[2]float64)(unsafe.Pointer(a)) return f64hash(&x[1], 4, f64hash(&x[0], 4, h)) } -func nohash(a unsafe.Pointer, s uintptr, h uintptr) uintptr { +func nohash(a unsafe.Pointer, s, h uintptr) uintptr { panic(errorString("hash of unhashable type")) } -func interhash(a *interface { - f() -}, s uintptr, h uintptr) uintptr { - tab := (*iface)(unsafe.Pointer(a)).tab +func interhash(a *iface, s, h uintptr) uintptr { + tab := a.tab if tab == nil { return h } @@ -123,14 +121,14 @@ func interhash(a *interface { panic(errorString("hash of unhashable type " + *t._string)) } if uintptr(t.size) <= ptrSize { - return c1 * fn(unsafe.Pointer(&(*eface)(unsafe.Pointer(a)).data), uintptr(t.size), h^c0) + return c1 * fn(unsafe.Pointer(&a.data), uintptr(t.size), h^c0) } else { - return c1 * fn((*eface)(unsafe.Pointer(a)).data, uintptr(t.size), h^c0) + return c1 * fn(a.data, uintptr(t.size), h^c0) } } -func nilinterhash(a *interface{}, s uintptr, h uintptr) uintptr { - t := (*eface)(unsafe.Pointer(a))._type +func nilinterhash(a *eface, s, h uintptr) uintptr { + t := a._type if t == nil { return h } @@ -141,9 +139,9 @@ func nilinterhash(a *interface{}, s uintptr, h uintptr) uintptr { panic(errorString("hash of unhashable type " + *t._string)) } if uintptr(t.size) <= ptrSize { - return c1 * fn(unsafe.Pointer(&(*eface)(unsafe.Pointer(a)).data), uintptr(t.size), h^c0) + return c1 * fn(unsafe.Pointer(&a.data), uintptr(t.size), h^c0) } else { - return c1 * fn((*eface)(unsafe.Pointer(a)).data, uintptr(t.size), h^c0) + return c1 * fn(a.data, uintptr(t.size), h^c0) } } From 1338f327b2deb81ba81107b5033d1b10e97e3abe Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 6 Aug 2014 16:45:06 -0400 Subject: [PATCH 003/423] cmd/go: implement 'internal' convention See golang.org/s/go14internal for design. LGTM=r R=r, adg CC=golang-codereviews https://golang.org/cl/120600043 --- src/cmd/go/pkg.go | 65 +++++++++++++++++-- src/cmd/go/test.bash | 16 +++++ src/cmd/go/testdata/testinternal/p.go | 3 + src/cmd/go/testdata/testinternal2/p.go | 3 + .../testinternal2/x/y/z/internal/w/w.go | 1 + 5 files changed, 83 insertions(+), 5 deletions(-) create mode 100644 src/cmd/go/testdata/testinternal/p.go create mode 100644 src/cmd/go/testdata/testinternal2/p.go create mode 100644 src/cmd/go/testdata/testinternal2/x/y/z/internal/w/w.go diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go index d45df265b9..d0dbefed01 100644 --- a/src/cmd/go/pkg.go +++ b/src/cmd/go/pkg.go @@ -244,6 +244,9 @@ func loadImport(path string, srcDir string, stk *importStack, importPos []token. importPath = dirToImportPath(filepath.Join(srcDir, path)) } if p := packageCache[importPath]; p != nil { + if perr := disallowInternal(srcDir, p, stk); perr != p { + return perr + } return reusePackage(p, stk) } @@ -270,6 +273,10 @@ func loadImport(path string, srcDir string, stk *importStack, importPos []token. p.Error.Pos = pos.String() } + if perr := disallowInternal(srcDir, p, stk); perr != p { + return perr + } + return p } @@ -298,6 +305,54 @@ func reusePackage(p *Package, stk *importStack) *Package { return p } +// disallowInternal checks that srcDir is allowed to import p. +// If the import is allowed, disallowInternal returns the original package p. +// If not, it returns a new package containing just an appropriate error. +func disallowInternal(srcDir string, p *Package, stk *importStack) *Package { + // golang.org/s/go14internal: + // An import of a path containing the element “internal” + // is disallowed if the importing code is outside the tree + // rooted at the parent of the “internal” directory. + // + // ... For Go 1.4, we will implement the rule first for $GOROOT, but not $GOPATH. + + // Only applies to $GOROOT. + if !p.Standard { + 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 + // import. Anything listed on the command line is fine. + if len(*stk) == 1 { + return p + } + + // Check for "internal" element: four cases depending on begin of string and/or end of string. + if p.ImportPath != "internal" && + !strings.HasPrefix(p.ImportPath, "internal/") && + !strings.HasSuffix(p.ImportPath, "/internal") && + !strings.Contains(p.ImportPath, "/internal/") { + return p + } + + // Internal is present. Check directory. + parent := filepath.Dir(p.Dir) + if hasPathPrefix(srcDir, parent) { + return p + } + + // Internal is present, and srcDir is outside parent's tree. Not allowed. + perr := *p + perr.Error = &PackageError{ + ImportStack: stk.copy(), + Err: "use of internal package not allowed", + } + perr.Incomplete = true + return &perr +} + type targetDir int const ( @@ -482,7 +537,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package // Build list of imported packages and full dependency list. imports := make([]*Package, 0, len(p.Imports)) - deps := make(map[string]bool) + deps := make(map[string]*Package) for i, path := range importPaths { if path == "C" { continue @@ -502,10 +557,10 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package path = p1.ImportPath importPaths[i] = path } - deps[path] = true + deps[path] = p1 imports = append(imports, p1) - for _, dep := range p1.Deps { - deps[dep] = true + for _, dep := range p1.deps { + deps[dep.ImportPath] = dep } if p1.Incomplete { p.Incomplete = true @@ -519,7 +574,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package } sort.Strings(p.Deps) for _, dep := range p.Deps { - p1 := packageCache[dep] + p1 := deps[dep] if p1 == nil { panic("impossible: missing entry in package cache for " + dep + " imported by " + p.ImportPath) } diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash index c62f629405..e5ba12b1df 100755 --- a/src/cmd/go/test.bash +++ b/src/cmd/go/test.bash @@ -105,6 +105,22 @@ cp -R testdata/local "testdata/$bad" testlocal "$bad" 'with bad characters in path' rm -rf "testdata/$bad" +TEST 'internal packages in $GOROOT are respected' +if ./testgo build -v ./testdata/testinternal >testdata/std.out 2>&1; then + echo "go build ./testdata/testinternal succeeded incorrectly" + ok=false +elif ! grep 'use of internal package not allowed' testdata/std.out >/dev/null; then + echo "wrong error message for testdata/testinternal" + cat std.out + ok=false +fi + +TEST 'internal packages outside $GOROOT are not respected' +if ! ./testgo build -v ./testdata/testinternal2; then + echo "go build ./testdata/testinternal2 failed" + ok=false +fi + TEST error message for syntax error in test go file says FAIL export GOPATH=$(pwd)/testdata if ./testgo test syntaxerror 2>testdata/err; then diff --git a/src/cmd/go/testdata/testinternal/p.go b/src/cmd/go/testdata/testinternal/p.go new file mode 100644 index 0000000000..e3558a53b2 --- /dev/null +++ b/src/cmd/go/testdata/testinternal/p.go @@ -0,0 +1,3 @@ +package p + +import _ "net/http/internal" diff --git a/src/cmd/go/testdata/testinternal2/p.go b/src/cmd/go/testdata/testinternal2/p.go new file mode 100644 index 0000000000..c594f5c5e9 --- /dev/null +++ b/src/cmd/go/testdata/testinternal2/p.go @@ -0,0 +1,3 @@ +package p + +import _ "./x/y/z/internal/w" diff --git a/src/cmd/go/testdata/testinternal2/x/y/z/internal/w/w.go b/src/cmd/go/testdata/testinternal2/x/y/z/internal/w/w.go new file mode 100644 index 0000000000..a796c0b5f4 --- /dev/null +++ b/src/cmd/go/testdata/testinternal2/x/y/z/internal/w/w.go @@ -0,0 +1 @@ +package w From 5fbcdb26613a819ba693ee3933f6e283e139630b Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 6 Aug 2014 16:47:54 -0400 Subject: [PATCH 004/423] runtime: use better hash for floating point inputs Hashing on the bytes instead of the words does a (much) better job of using all the bits, so that maps of floats have linear performance. LGTM=khr R=golang-codereviews, khr CC=adonovan, golang-codereviews https://golang.org/cl/126720044 --- src/pkg/runtime/alg.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/pkg/runtime/alg.go b/src/pkg/runtime/alg.go index 251374a946..f2bb202c68 100644 --- a/src/pkg/runtime/alg.go +++ b/src/pkg/runtime/alg.go @@ -75,7 +75,7 @@ func f32hash(a *float32, s, h uintptr) uintptr { case f != f: return c1 * (c0 ^ h ^ uintptr(fastrand2())) // any kind of NaN default: - return c1 * (c0 ^ h ^ uintptr(*(*uint32)(unsafe.Pointer(a)))) + return memhash(unsafe.Pointer(a), 4, h) } } @@ -86,11 +86,8 @@ func f64hash(a *float64, s, h uintptr) uintptr { return c1 * (c0 ^ h) // +0, -0 case f != f: return c1 * (c0 ^ h ^ uintptr(fastrand2())) // any kind of NaN - case ptrSize == 4: - x := (*[2]uintptr)(unsafe.Pointer(a)) - return c1 * (c0 ^ h ^ (x[1] * c1) ^ x[0]) default: - return c1 * (c0 ^ h ^ *(*uintptr)(unsafe.Pointer(a))) + return memhash(unsafe.Pointer(a), 8, h) } } From 161ba662b19ca0ed367883c6d9233fc00c10654f Mon Sep 17 00:00:00 2001 From: Alan Donovan Date: Wed, 6 Aug 2014 17:02:55 -0400 Subject: [PATCH 005/423] test/mapnan.go: add regression test for non-empty interfaces. LGTM=rsc, khr R=rsc, khr, bradfitz CC=golang-codereviews https://golang.org/cl/126720043 --- test/map.go | 2 +- test/maplinear.go | 143 ++++++++++++++++++++++++++++++++++++++++++++++ test/mapnan.go | 56 ------------------ 3 files changed, 144 insertions(+), 57 deletions(-) create mode 100644 test/maplinear.go delete mode 100644 test/mapnan.go diff --git a/test/map.go b/test/map.go index 485e743fe4..2c1cf8a140 100644 --- a/test/map.go +++ b/test/map.go @@ -5,7 +5,7 @@ // license that can be found in the LICENSE file. // Test maps, almost exhaustively. -// NaN complexity test is in mapnan.go. +// Complexity (linearity) test is in maplinear.go. package main diff --git a/test/maplinear.go b/test/maplinear.go new file mode 100644 index 0000000000..56e50951af --- /dev/null +++ b/test/maplinear.go @@ -0,0 +1,143 @@ +// +build darwin linux +// run + +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test that maps don't go quadratic for NaNs and other values. + +package main + +import ( + "fmt" + "math" + "time" +) + +// checkLinear asserts that the running time of f(n) is in O(n). +// tries is the initial number of iterations. +func checkLinear(typ string, tries int, f func(n int)) { + // Depending on the machine and OS, this test might be too fast + // to measure with accurate enough granularity. On failure, + // make it run longer, hoping that the timing granularity + // is eventually sufficient. + + timeF := func(n int) time.Duration { + t1 := time.Now() + f(n) + return time.Since(t1) + } + + t0 := time.Now() + + n := tries + fails := 0 + for { + t1 := timeF(n) + t2 := timeF(2 * n) + + // should be 2x (linear); allow up to 3x + if t2 < 3*t1 { + if false { + fmt.Println(typ, "\t", time.Since(t0)) + } + return + } + fails++ + if fails == 6 { + panic(fmt.Sprintf("%s: too slow: %d inserts: %v; %d inserts: %v\n", + typ, n, t1, 2*n, t2)) + } + if fails < 4 { + n *= 2 + } + } +} + +type I interface { + f() +} + +type C int + +func (C) f() {} + +func main() { + // NaNs. ~31ms on a 1.6GHz Zeon. + checkLinear("NaN", 30000, func(n int) { + m := map[float64]int{} + nan := math.NaN() + for i := 0; i < n; i++ { + m[nan] = 1 + } + if len(m) != n { + panic("wrong size map after nan insertion") + } + }) + + // ~6ms on a 1.6GHz Zeon. + checkLinear("eface", 10000, func(n int) { + m := map[interface{}]int{} + for i := 0; i < n; i++ { + m[i] = 1 + } + }) + + // ~7ms on a 1.6GHz Zeon. + // Regression test for CL 119360043. + checkLinear("iface", 10000, func(n int) { + m := map[I]int{} + for i := 0; i < n; i++ { + m[C(i)] = 1 + } + }) + + // ~6ms on a 1.6GHz Zeon. + checkLinear("int", 10000, func(n int) { + m := map[int]int{} + for i := 0; i < n; i++ { + m[i] = 1 + } + }) + + // ~18ms on a 1.6GHz Zeon. + checkLinear("string", 10000, func(n int) { + m := map[string]int{} + for i := 0; i < n; i++ { + m[fmt.Sprint(i)] = 1 + } + }) + + // ~6ms on a 1.6GHz Zeon. + checkLinear("float32", 10000, func(n int) { + m := map[float32]int{} + for i := 0; i < n; i++ { + m[float32(i)] = 1 + } + }) + + // ~6ms on a 1.6GHz Zeon. + checkLinear("float64", 10000, func(n int) { + m := map[float64]int{} + for i := 0; i < n; i++ { + m[float64(i)] = 1 + } + }) + + // ~22ms on a 1.6GHz Zeon. + checkLinear("complex64", 10000, func(n int) { + m := map[complex64]int{} + for i := 0; i < n; i++ { + m[complex(float32(i), float32(i))] = 1 + } + }) + + // ~32ms on a 1.6GHz Zeon. + checkLinear("complex128", 10000, func(n int) { + m := map[complex128]int{} + for i := 0; i < n; i++ { + m[complex(float64(i), float64(i))] = 1 + } + }) +} diff --git a/test/mapnan.go b/test/mapnan.go deleted file mode 100644 index f081cab01d..0000000000 --- a/test/mapnan.go +++ /dev/null @@ -1,56 +0,0 @@ -// +build darwin linux -// run - -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Test that NaNs in maps don't go quadratic. - -package main - -import ( - "fmt" - "math" - "time" -) - -func main() { - - // Test that NaNs in maps don't go quadratic. - t := func(n int) time.Duration { - t1 := time.Now() - m := map[float64]int{} - nan := math.NaN() - for i := 0; i < n; i++ { - m[nan] = 1 - } - if len(m) != n { - panic("wrong size map after nan insertion") - } - return time.Since(t1) - } - - // Depending on the machine and OS, this test might be too fast - // to measure with accurate enough granularity. On failure, - // make it run longer, hoping that the timing granularity - // is eventually sufficient. - - n := 30000 // ~8ms user time on a Mid 2011 MacBook Air (1.8 GHz Core i7) - fails := 0 - for { - t1 := t(n) - t2 := t(2 * n) - // should be 2x (linear); allow up to 3x - if t2 < 3*t1 { - return - } - fails++ - if fails == 6 { - panic(fmt.Sprintf("too slow: %d inserts: %v; %d inserts: %v\n", n, t1, 2*n, t2)) - } - if fails < 4 { - n *= 2 - } - } -} From e359bea8ad0b381c1b28dd7c74ca17e17a7f3324 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Wed, 6 Aug 2014 14:33:57 -0700 Subject: [PATCH 006/423] runtime: clean up naming of mcallable functions. Introduce the mFunction type to represent an mcall/onM-able function. Name such functions using _m. LGTM=bradfitz R=bradfitz CC=golang-codereviews https://golang.org/cl/121320043 --- src/pkg/runtime/malloc.c | 6 +++--- src/pkg/runtime/malloc.go | 12 ++++++------ src/pkg/runtime/mgc0.c | 2 +- src/pkg/runtime/mprof.goc | 2 +- src/pkg/runtime/print.go | 10 ++++++---- src/pkg/runtime/stubs.go | 30 +++++++++++++++++++----------- 6 files changed, 36 insertions(+), 26 deletions(-) diff --git a/src/pkg/runtime/malloc.c b/src/pkg/runtime/malloc.c index d56d0dcf31..951117622f 100644 --- a/src/pkg/runtime/malloc.c +++ b/src/pkg/runtime/malloc.c @@ -514,7 +514,7 @@ throw: } void -runtime·setFinalizer(void) +runtime·setFinalizer_m(void) { Eface obj, finalizer; @@ -531,13 +531,13 @@ runtime·setFinalizer(void) // mcallable cache refill void -runtime·mcacheRefill(void) +runtime·mcacheRefill_m(void) { runtime·MCache_Refill(g->m->mcache, (int32)g->m->scalararg[0]); } void -runtime·largeAlloc(void) +runtime·largeAlloc_m(void) { uintptr npages, size; MSpan *s; diff --git a/src/pkg/runtime/malloc.go b/src/pkg/runtime/malloc.go index dedcea94a6..81769573c9 100644 --- a/src/pkg/runtime/malloc.go +++ b/src/pkg/runtime/malloc.go @@ -114,7 +114,7 @@ func gomallocgc(size uintptr, typ *_type, flags int) unsafe.Pointer { v := s.freelist if v == nil { mp.scalararg[0] = tinySizeClass - onM(&mcacheRefill) + onM(&mcacheRefill_m) s = c.alloc[tinySizeClass] v = s.freelist } @@ -143,7 +143,7 @@ func gomallocgc(size uintptr, typ *_type, flags int) unsafe.Pointer { v := s.freelist if v == nil { mp.scalararg[0] = uint(sizeclass) - onM(&mcacheRefill) + onM(&mcacheRefill_m) s = c.alloc[sizeclass] v = s.freelist } @@ -162,7 +162,7 @@ func gomallocgc(size uintptr, typ *_type, flags int) unsafe.Pointer { } else { mp.scalararg[0] = uint(size) mp.scalararg[1] = uint(flags) - onM(&largeAlloc) + onM(&largeAlloc_m) s = (*mspan)(mp.ptrarg[0]) mp.ptrarg[0] = nil x = unsafe.Pointer(uintptr(s.start << pageShift)) @@ -272,7 +272,7 @@ func profilealloc(mp *m, x unsafe.Pointer, size uintptr) { } mp.scalararg[0] = uint(size) mp.ptrarg[0] = x - onM(&mprofMalloc) + onM(&mprofMalloc_m) } // force = 1 - do GC regardless of current heap usage @@ -341,7 +341,7 @@ func gogc(force int32) { } else { mp.scalararg[1] = 0 } - onM(&mgc2) + onM(&gc_m) } // all done @@ -426,6 +426,6 @@ func SetFinalizer(obj interface{}, finalizer interface{}) { mp.ptrarg[1] = e.data mp.ptrarg[2] = unsafe.Pointer(ftyp) mp.ptrarg[3] = f.data - onM(&setFinalizer) + onM(&setFinalizer_m) releasem(mp) } diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c index e7955151ce..01e055cf04 100644 --- a/src/pkg/runtime/mgc0.c +++ b/src/pkg/runtime/mgc0.c @@ -1369,7 +1369,7 @@ mgc(G *gp) } void -runtime·mgc2(void) +runtime·gc_m(void) { struct gc_args a; G *gp; diff --git a/src/pkg/runtime/mprof.goc b/src/pkg/runtime/mprof.goc index 69187f2a74..053781193e 100644 --- a/src/pkg/runtime/mprof.goc +++ b/src/pkg/runtime/mprof.goc @@ -142,7 +142,7 @@ runtime·MProf_Malloc(void *p, uintptr size) // Called by malloc to record a profiled block. void -runtime·mprofMalloc(void) +runtime·mprofMalloc_m(void) { uintptr stk[32]; Bucket *b; diff --git a/src/pkg/runtime/print.go b/src/pkg/runtime/print.go index 904af5d333..4b94417c6e 100644 --- a/src/pkg/runtime/print.go +++ b/src/pkg/runtime/print.go @@ -10,10 +10,12 @@ import ( // these 4 functions are complicated enough that we will share // the print logic with the C printf. -var printstring_m byte -var printuint_m byte -var printhex_m byte -var printfloat_m byte +var ( + printstring_m, + printuint_m, + printhex_m, + printfloat_m mFunction +) func printstring(s string) { mp := acquirem() diff --git a/src/pkg/runtime/stubs.go b/src/pkg/runtime/stubs.go index 30638d1af8..8a2fc8a97e 100644 --- a/src/pkg/runtime/stubs.go +++ b/src/pkg/runtime/stubs.go @@ -44,21 +44,29 @@ func roundup(p unsafe.Pointer, n uintptr) unsafe.Pointer { func acquirem() *m func releasem(mp *m) -// in asm_*.s -func mcall(fn *byte) -func onM(fn *byte) +// An mFunction represents a C function that runs on the M stack. It +// can be called from Go using mcall or onM. Through the magic of +// linking, an mFunction variable and the corresponding C code entry +// point live at the same address. +type mFunction byte -// C routines that run on the M stack. Call these like -// mcall(&mcacheRefill) +// in asm_*.s +func mcall(fn *mFunction) +func onM(fn *mFunction) + +// C functions that run on the M stack. Call these like +// mcall(&mcacheRefill_m) // Arguments should be passed in m->scalararg[x] and // m->ptrarg[x]. Return values can be passed in those // same slots. -var mcacheRefill byte -var largeAlloc byte -var mprofMalloc byte -var mgc2 byte -var setFinalizer byte -var markallocated_m byte +var ( + mcacheRefill_m, + largeAlloc_m, + mprofMalloc_m, + gc_m, + setFinalizer_m, + markallocated_m mFunction +) // memclr clears n bytes starting at ptr. // in memclr_*.s From 7bcaff70ed92156eb98841ecac3fb5e234822ea3 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Wed, 6 Aug 2014 14:43:50 -0700 Subject: [PATCH 007/423] debug/dwarf: fix typos in comment for UnspecifiedType LGTM=iant, bradfitz R=bradfitz, iant CC=golang-codereviews https://golang.org/cl/120700043 --- src/pkg/debug/dwarf/type.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pkg/debug/dwarf/type.go b/src/pkg/debug/dwarf/type.go index e59737b0a4..b64333ecc5 100644 --- a/src/pkg/debug/dwarf/type.go +++ b/src/pkg/debug/dwarf/type.go @@ -88,7 +88,7 @@ type AddrType struct { BasicType } -// A UnspecifiedType represents implicit, unknown, ambiguous or nonexistent type. +// An UnspecifiedType represents an implicit, unknown, ambiguous or nonexistent type. type UnspecifiedType struct { BasicType } From fef54b22f8ee7a57a5ba04a6a02244a10f90e904 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 6 Aug 2014 17:59:30 -0400 Subject: [PATCH 008/423] cmd/go: revise disallowInternal This fixes two problems: x/internal/y/z was using parent = x/internal/y instead of x, and hasPathPrefix only looks at /, not \ for Windows. LGTM=bradfitz R=bradfitz CC=golang-codereviews https://golang.org/cl/121280045 --- src/cmd/go/pkg.go | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go index d0dbefed01..be691a6bc9 100644 --- a/src/cmd/go/pkg.go +++ b/src/cmd/go/pkg.go @@ -330,16 +330,18 @@ func disallowInternal(srcDir string, p *Package, stk *importStack) *Package { } // Check for "internal" element: four cases depending on begin of string and/or end of string. - if p.ImportPath != "internal" && - !strings.HasPrefix(p.ImportPath, "internal/") && - !strings.HasSuffix(p.ImportPath, "/internal") && - !strings.Contains(p.ImportPath, "/internal/") { + i, ok := findInternal(p.ImportPath) + if !ok { return p } - // Internal is present. Check directory. - parent := filepath.Dir(p.Dir) - if hasPathPrefix(srcDir, parent) { + // Internal is present. + // Map import path back to directory corresponding to parent of internal. + if i > 0 { + i-- // rewind over slash in ".../internal" + } + parent := p.Dir[:i+len(p.Dir)-len(p.ImportPath)] + if hasPathPrefix(filepath.ToSlash(srcDir), filepath.ToSlash(parent)) { return p } @@ -353,6 +355,25 @@ func disallowInternal(srcDir string, p *Package, stk *importStack) *Package { return &perr } +// findInternal looks for the final "internal" path element in the given import path. +// If there isn't one, findInternal returns ok=false. +// Otherwise, findInternal returns ok=true and the index of the "internal". +func findInternal(path string) (index int, ok bool) { + // Four cases, depending on internal at start/end of string or not. + // The order matters: we must return the index of the final element, + // because the final one produces the most restrictive requirement + // on the importer. + switch { + case strings.HasSuffix(path, "/internal"): + return len(path) - len("internal"), true + case strings.Contains(path, "/internal/"): + return strings.LastIndex(path, "/internal/") + 1, true + case path == "internal", strings.HasPrefix(path, "internal/"): + return 0, true + } + return 0, false +} + type targetDir int const ( From b91aea55366d3f72c6f16a2cb5651b4e3aa5fb0c Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 6 Aug 2014 18:00:06 -0400 Subject: [PATCH 009/423] encoding/xml: add InputOffset method to Decoder Among other things, this allows users to match the decoded pieces with the original XML, which can be necessary for implementing standards like XML signatures. Fixes #8484. LGTM=bradfitz R=bradfitz CC=golang-codereviews https://golang.org/cl/122960043 --- src/pkg/encoding/xml/xml.go | 11 +++++++++++ src/pkg/encoding/xml/xml_test.go | 31 +++++++++++++++++++++++++++---- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/pkg/encoding/xml/xml.go b/src/pkg/encoding/xml/xml.go index b473cb8458..a4cd4e29e0 100644 --- a/src/pkg/encoding/xml/xml.go +++ b/src/pkg/encoding/xml/xml.go @@ -29,6 +29,7 @@ import ( type SyntaxError struct { Msg string Line int + Byte int64 // byte offset from start of stream } func (e *SyntaxError) Error() string { @@ -196,6 +197,7 @@ type Decoder struct { ns map[string]string err error line int + offset int64 unmarshalDepth int } @@ -859,9 +861,17 @@ func (d *Decoder) getc() (b byte, ok bool) { if b == '\n' { d.line++ } + d.offset++ return b, true } +// InputOffset returns the input stream byte offset of the current decoder position. +// The offset gives the location of the end of the most recently returned token +// and the beginning of the next token. +func (d *Decoder) InputOffset() int64 { + return d.offset +} + // Return saved offset. // If we did ungetc (nextByte >= 0), have to back up one. func (d *Decoder) savedOffset() int { @@ -891,6 +901,7 @@ func (d *Decoder) ungetc(b byte) { d.line-- } d.nextByte = int(b) + d.offset-- } var entity = map[string]int{ diff --git a/src/pkg/encoding/xml/xml_test.go b/src/pkg/encoding/xml/xml_test.go index 7723ab1c9f..be995c0d52 100644 --- a/src/pkg/encoding/xml/xml_test.go +++ b/src/pkg/encoding/xml/xml_test.go @@ -170,7 +170,7 @@ var xmlInput = []string{ func TestRawToken(t *testing.T) { d := NewDecoder(strings.NewReader(testInput)) d.Entity = testEntity - testRawToken(t, d, rawTokens) + testRawToken(t, d, testInput, rawTokens) } const nonStrictInput = ` @@ -225,7 +225,7 @@ var nonStrictTokens = []Token{ func TestNonStrictRawToken(t *testing.T) { d := NewDecoder(strings.NewReader(nonStrictInput)) d.Strict = false - testRawToken(t, d, nonStrictTokens) + testRawToken(t, d, nonStrictInput, nonStrictTokens) } type downCaser struct { @@ -254,7 +254,7 @@ func TestRawTokenAltEncoding(t *testing.T) { } return &downCaser{t, input.(io.ByteReader)}, nil } - testRawToken(t, d, rawTokensAltEncoding) + testRawToken(t, d, testInputAltEncoding, rawTokensAltEncoding) } func TestRawTokenAltEncodingNoConverter(t *testing.T) { @@ -280,9 +280,12 @@ func TestRawTokenAltEncodingNoConverter(t *testing.T) { } } -func testRawToken(t *testing.T, d *Decoder, rawTokens []Token) { +func testRawToken(t *testing.T, d *Decoder, raw string, rawTokens []Token) { + lastEnd := int64(0) for i, want := range rawTokens { + start := d.InputOffset() have, err := d.RawToken() + end := d.InputOffset() if err != nil { t.Fatalf("token %d: unexpected error: %s", i, err) } @@ -300,6 +303,26 @@ func testRawToken(t *testing.T, d *Decoder, rawTokens []Token) { } t.Errorf("token %d = %s, want %s", i, shave, swant) } + + // Check that InputOffset returned actual token. + switch { + case start < lastEnd: + t.Errorf("token %d: position [%d,%d) for %T is before previous token", i, start, end, have) + case start >= end: + // Special case: EndElement can be synthesized. + if start == end && end == lastEnd { + break + } + t.Errorf("token %d: position [%d,%d) for %T is empty", i, start, end, have) + case end > int64(len(raw)): + t.Errorf("token %d: position [%d,%d) for %T extends beyond input", i, start, end, have) + default: + text := raw[start:end] + if strings.ContainsAny(text, "<>") && (!strings.HasPrefix(text, "<") || !strings.HasSuffix(text, ">")) { + t.Errorf("token %d: misaligned raw token %#q for %T", i, text, have) + } + } + lastEnd = end } } From a2d3669ef709c8a703534c113a95a283068ae43d Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Thu, 7 Aug 2014 10:22:10 +1000 Subject: [PATCH 010/423] path/filepath: do not restore original working directory twice in test LGTM=dave R=golang-codereviews, dave CC=golang-codereviews https://golang.org/cl/122910043 --- src/pkg/path/filepath/path_test.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/pkg/path/filepath/path_test.go b/src/pkg/path/filepath/path_test.go index 17b53bdf92..8cdc763f1b 100644 --- a/src/pkg/path/filepath/path_test.go +++ b/src/pkg/path/filepath/path_test.go @@ -784,12 +784,6 @@ var absTests = []string{ } func TestAbs(t *testing.T) { - oldwd, err := os.Getwd() - if err != nil { - t.Fatal("Getwd failed: ", err) - } - defer os.Chdir(oldwd) - root, err := ioutil.TempDir("", "TestAbs") if err != nil { t.Fatal("TempDir failed: ", err) From 7ce3406c8fe1d71d0d595bcd0842bf27f6d1bf32 Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Thu, 7 Aug 2014 10:25:50 +1000 Subject: [PATCH 011/423] doc/go1.4.txt: implement monotonic clocks on windows LGTM=dave R=golang-codereviews, dave CC=golang-codereviews https://golang.org/cl/126760043 --- doc/go1.4.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/go1.4.txt b/doc/go1.4.txt index 87904ee7ea..3ea1ca3c52 100644 --- a/doc/go1.4.txt +++ b/doc/go1.4.txt @@ -10,6 +10,7 @@ spec: permit for range x (CL 104680043) encoding/gob: remove unsafe (CL 102680045) misc: deleted editor support; refer to https://code.google.com/p/go-wiki/wiki/IDEsAndTextEditorPlugins instead (CL 105470043) os: implement symlink support for windows (CL 86160044) +runtime: implement monotonic clocks on windows (CL 108700045) runtime/race: freebsd is supported (CL 107270043) syscall: Setuid, Setgid are disabled on linux platforms. On linux those syscalls operate on the calling thread, not the whole process. This does not match the semantics of other platforms, nor the expectations of the caller, so the operations have been disabled until issue 1435 is resolved (CL 106170043) testing: add Coverage (CL 98150043) From cdf77676289de7580b1451a3862cc97f620df389 Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Thu, 7 Aug 2014 09:28:49 +0900 Subject: [PATCH 012/423] doc/go1.4.txt: add support for ALPN LGTM=minux R=r, agl, minux CC=golang-codereviews https://golang.org/cl/121340043 --- doc/go1.4.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/go1.4.txt b/doc/go1.4.txt index 3ea1ca3c52..20d2a6b7ed 100644 --- a/doc/go1.4.txt +++ b/doc/go1.4.txt @@ -7,6 +7,7 @@ Please keep the list sorted (as in sort.Strings of the lines). spec: permit for range x (CL 104680043) +crypto/tls: add support for ALPN (RFC 7301) (CL 108710046) encoding/gob: remove unsafe (CL 102680045) misc: deleted editor support; refer to https://code.google.com/p/go-wiki/wiki/IDEsAndTextEditorPlugins instead (CL 105470043) os: implement symlink support for windows (CL 86160044) From 9f07456c138f606350ff73f25a55ab65210e5b38 Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Thu, 7 Aug 2014 11:21:32 +1000 Subject: [PATCH 013/423] C: add Paul Nasrat (Google CLA) TBR=gobot R=golang-codereviews CC=golang-codereviews https://golang.org/cl/125790043 --- CONTRIBUTORS | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 1053057b5a..30a2b567db 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -455,6 +455,7 @@ Paul Borman Paul Chang Paul Hammond Paul Lalonde +Paul Nasrat Paul Sbarra Paul van Brouwershaven Pavel Zinovkin From cfed26c7ceeaf093d975e0a748d270cd1b716816 Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Thu, 7 Aug 2014 11:50:27 +1000 Subject: [PATCH 014/423] misc/nacl: wrap lines in README file LGTM=dan.kortschak, dave R=dave, dan.kortschak CC=golang-codereviews https://golang.org/cl/121350043 --- misc/nacl/README | 57 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/misc/nacl/README b/misc/nacl/README index 710587dfce..6f149f8ac8 100644 --- a/misc/nacl/README +++ b/misc/nacl/README @@ -1,12 +1,14 @@ Native Client ============= -This document outlines the basics of building and developing the Go runtime and programs in the Native Client (NaCl) environment. +This document outlines the basics of building and developing the Go runtime and +programs in the Native Client (NaCl) environment. Go 1.3 supports three architectures * nacl/386 which is standard 386. - * nacl/amd64p32 which is a 64 bit architecture, where the address space is limited to a 4gb window. + * nacl/amd64p32 which is a 64 bit architecture, where the address space is + limited to a 4gb window. * nacl/arm which is 32-bit ARMv7A architecture with 1GB address space. For background it is recommended that you read http://golang.org/s/go13nacl. @@ -14,34 +16,48 @@ For background it is recommended that you read http://golang.org/s/go13nacl. Prerequisites ------------- -Native Client programs are executed inside a sandbox, the NaCl runtime. This runtime must be installed before you can use NaCl programs. +Native Client programs are executed inside a sandbox, the NaCl runtime. This +runtime must be installed before you can use NaCl programs. -The NaCl distribution comes with an installer which ensures you have access to the latest version of the runtime. The version tracks the Chrome numbering scheme. +The NaCl distribution comes with an installer which ensures you have access to +the latest version of the runtime. The version tracks the Chrome numbering +scheme. # Download NaCl -Download nacl_sdk.zip file from https://developers.google.com/native-client/dev/sdk/download, and unpack it. I chose /opt/nacl_sdk +Download nacl_sdk.zip file from + https://developers.google.com/native-client/dev/sdk/download +and unpack it. I chose /opt/nacl_sdk. # Update -The zip file contains a small skeleton that can be used to download the correct sdk. These are released every 6-8 weeks, in line with Chrome releases. +The zip file contains a small skeleton that can be used to download the correct +sdk. These are released every 6-8 weeks, in line with Chrome releases. % cd /opt/nacl_sdk % ./naclsdk update -At this time pepper_33 is the stable version. If naclsdk downloads a later version, please adjust accordingly. As of June 2014, only the canary sdk provides support for nacl/arm. +At this time pepper_33 is the stable version. If naclsdk downloads a later +version, please adjust accordingly. As of June 2014, only the canary sdk +provides support for nacl/arm. -The cmd/go helper scripts expect that the runtime loaders, sel_ldr_{x86_{32,64},arm} and nacl_helper_bootstrap_arm are in your path. I find it easiest to make a symlink from the NaCl distribution to my $GOPATH/bin directory. +The cmd/go helper scripts expect that the loaders sel_ldr_{x86_{32,64},arm} and +nacl_helper_bootstrap_arm are in your path. I find it easiest to make a symlink +from the NaCl distribution to my $GOPATH/bin directory. % ln -nfs /opt/nacl_sdk/pepper_33/tools/sel_ldr_x86_32 $GOPATH/bin/sel_ldr_x86_32 % ln -nfs /opt/nacl_sdk/pepper_33/tools/sel_ldr_x86_64 $GOPATH/bin/sel_ldr_x86_64 % ln -nfs /opt/nacl_sdk/pepper_canary/tools/sel_ldr_arm $GOPATH/bin/sel_ldr_arm - % ln -nfs /opt/nacl_sdk/pepper_canary/tools/nacl_helper_bootstrap_arm $GOPATH/bin/nacl_helper_bootstrap_arm # only required for NaCl/ARM. + +Additionally, for NaCl/ARM only: + + % ln -nfs /opt/nacl_sdk/pepper_canary/tools/nacl_helper_bootstrap_arm $GOPATH/bin/nacl_helper_bootstrap_arm Support scripts --------------- -Symlink the two scripts in this directory into your $PATH, just as you did with NaCl sdk above. +Symlink the two scripts in this directory into your $PATH, just as you did with +NaCl sdk above. % ln -nfs $GOROOT/go/misc/nacl/go_nacl_amd64p32_exec $GOPATH/bin/go_nacl_amd64p32_exec % ln -nfs $GOROOT/go/misc/nacl/go_nacl_386_exec $GOPATH/bin/go_nacl_386_exec @@ -50,17 +66,28 @@ Symlink the two scripts in this directory into your $PATH, just as you did with Building and testing -------------------- -Building for NaCl is similar to cross compiling for other platforms. However, as it is not possible to ever build in a `native` NaCl environment, the cmd/go tool has been enhanced to allow the full build, all.bash, to be executed, rather than just the compile stage, make.bash. +Building for NaCl is similar to cross compiling for other platforms. However, +as it is not possible to ever build in a `native` NaCl environment, the cmd/go +tool has been enhanced to allow the full build, all.bash, to be executed, +rather than just the compile stage, make.bash. -The cmd/go tool knows that if GOOS is set to `nacl` it should not try to execute any binaries itself. Instead it passes their execution to a support script which sets up a Native Client environment and invokes the NaCl sandbox. +The cmd/go tool knows that if GOOS is set to `nacl` it should not try to +execute any binaries itself. Instead it passes their execution to a support +script which sets up a Native Client environment and invokes the NaCl sandbox. -The script's name has a special format, go_$GOOS_$GOARCH_exec, so cmd/go can find it. +The script's name has a special format, go_$GOOS_$GOARCH_exec, so cmd/go can +find it. -In short, if the support scripts are in place, the cmd/go tool can be used as per normal. +In short, if the support scripts are in place, the cmd/go tool can be used as +per normal. # Build and test Go for NaCl -NaCl does not permit direct file system access. Instead, package syscall provides a simulated file system served by in-memory data. The script nacltest.bash is the NaCl equivalent of all.bash. It builds NaCl with an in-memory file system containing files needed for tests, and then it runs the tests. +NaCl does not permit direct file system access. Instead, package syscall +provides a simulated file system served by in-memory data. The script +nacltest.bash is the NaCl equivalent of all.bash. It builds NaCl with an +in-memory file system containing files needed for tests, and then it runs the +tests. % cd go/src % env GOARCH=amd64p32 ./nacltest.bash From af403c08fcb848205466d1e4589f98df1984d0dd Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Thu, 7 Aug 2014 15:42:06 +1000 Subject: [PATCH 015/423] doc: document new ParseMultipartForm behavior Fixes #8403. LGTM=bradfitz R=golang-codereviews, bradfitz CC=golang-codereviews https://golang.org/cl/123860043 --- doc/go1.3.html | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/go1.3.html b/doc/go1.3.html index 0d2bda122d..042de1bc7b 100644 --- a/doc/go1.3.html +++ b/doc/go1.3.html @@ -521,6 +521,15 @@ field to specify an end-to-end timeout on requests made using the client. +
  • +The net/http package's +Request.ParseMultipartForm +method will now return an error if the body's Content-Type +is not mutipart/form-data. +Prior to Go 1.3 it would silently fail and return nil. +Code that relies on the previous behavior should be updated. +
  • +
  • In the net package, the Dialer struct now has a KeepAlive option to specify a keep-alive period for the connection. From 192bccbf33b7493b36989921c8a81ece41904aa5 Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Thu, 7 Aug 2014 12:55:28 +0400 Subject: [PATCH 016/423] runtime: shrink stacks in parallel Shrinkstack does not touch normal heap anymore, so we can shink stacks concurrently with marking. LGTM=khr R=golang-codereviews, khr CC=golang-codereviews, khr, rlh, rsc https://golang.org/cl/122130043 --- src/pkg/runtime/mgc0.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c index 01e055cf04..16d616b3f6 100644 --- a/src/pkg/runtime/mgc0.c +++ b/src/pkg/runtime/mgc0.c @@ -559,6 +559,8 @@ markroot(ParFor *desc, uint32 i) // needed only to output in traceback if((gp->status == Gwaiting || gp->status == Gsyscall) && gp->waitsince == 0) gp->waitsince = work.tstart; + // Shrink a stack if not much of it is being used. + runtime·shrinkstack(gp); scanstack(gp); break; @@ -1391,7 +1393,6 @@ gc(struct gc_args *args) int64 t0, t1, t2, t3, t4; uint64 heap0, heap1, obj; GCStats stats; - uint32 i; if(runtime·debug.allocfreetrace) runtime·tracegc(); @@ -1514,11 +1515,6 @@ gc(struct gc_args *args) sweep.npausesweep++; } - // Shrink a stack if not much of it is being used. - // TODO: do in a parfor - for(i = 0; i < runtime·allglen; i++) - runtime·shrinkstack(runtime·allg[i]); - runtime·MProf_GC(); g->m->traceback = 0; } From cd2f8356ce5515c87710bc7ababfee8fdbdee9c3 Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Thu, 7 Aug 2014 13:04:04 +0400 Subject: [PATCH 017/423] runtime: remove mal/malloc/FlagNoGC/FlagNoInvokeGC FlagNoGC is unused now. FlagNoInvokeGC is unneeded as we don't invoke GC on g0 and when holding locks anyway. mal/malloc have very few uses and you never remember the exact set of flags they use and the difference between them. Moreover, eventually we need to give exact types to all allocations, something what mal/malloc do not support. LGTM=khr R=golang-codereviews, khr CC=golang-codereviews, rsc https://golang.org/cl/117580043 --- src/pkg/runtime/cgo/callbacks.c | 4 ++-- src/pkg/runtime/env_posix.c | 4 ++-- src/pkg/runtime/heapdump.c | 2 -- src/pkg/runtime/malloc.c | 12 ------------ src/pkg/runtime/malloc.go | 5 ++--- src/pkg/runtime/malloc.h | 5 +---- src/pkg/runtime/mgc0.c | 4 ++-- src/pkg/runtime/panic.c | 2 +- src/pkg/runtime/parfor.c | 2 +- src/pkg/runtime/proc.c | 6 +++--- src/pkg/runtime/runtime.c | 4 ++-- src/pkg/runtime/runtime.h | 3 +-- src/pkg/runtime/time.goc | 2 +- 13 files changed, 18 insertions(+), 37 deletions(-) diff --git a/src/pkg/runtime/cgo/callbacks.c b/src/pkg/runtime/cgo/callbacks.c index 5a4889c9b3..954a1cdcc3 100644 --- a/src/pkg/runtime/cgo/callbacks.c +++ b/src/pkg/runtime/cgo/callbacks.c @@ -38,8 +38,8 @@ _cgo_allocate_internal(uintptr len, byte *ret) { CgoMal *c; - ret = runtime·mal(len); - c = runtime·mal(sizeof(*c)); + ret = runtime·mallocgc(len, nil, 0); + c = runtime·mallocgc(sizeof(*c), nil, 0); c->next = g->m->cgomal; c->alloc = ret; g->m->cgomal = c; diff --git a/src/pkg/runtime/env_posix.c b/src/pkg/runtime/env_posix.c index 9b3583ce8b..edd1d3568d 100644 --- a/src/pkg/runtime/env_posix.c +++ b/src/pkg/runtime/env_posix.c @@ -50,11 +50,11 @@ syscall·setenv_c(String k, String v) if(_cgo_setenv == nil) return; - arg[0] = runtime·malloc(k.len + 1); + arg[0] = runtime·mallocgc(k.len + 1, nil, 0); runtime·memmove(arg[0], k.str, k.len); arg[0][k.len] = 0; - arg[1] = runtime·malloc(v.len + 1); + arg[1] = runtime·mallocgc(v.len + 1, nil, 0); runtime·memmove(arg[1], v.str, v.len); arg[1][v.len] = 0; diff --git a/src/pkg/runtime/heapdump.c b/src/pkg/runtime/heapdump.c index eec34f2cb7..9e968a250e 100644 --- a/src/pkg/runtime/heapdump.c +++ b/src/pkg/runtime/heapdump.c @@ -544,8 +544,6 @@ dumpobjs(void) bitp = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1; shift = (off % wordsPerBitmapWord) * gcBits; bits = (*bitp >> shift) & bitMask; - - // Skip FlagNoGC allocations (stacks) if(bits != bitAllocated) continue; dumpobj(p, size, makeheapobjbv(p, size)); diff --git a/src/pkg/runtime/malloc.c b/src/pkg/runtime/malloc.c index 951117622f..be3280e0f1 100644 --- a/src/pkg/runtime/malloc.c +++ b/src/pkg/runtime/malloc.c @@ -35,12 +35,6 @@ runtime·mallocgc(uintptr size, Type *typ, uint32 flag) return ret; } -void* -runtime·malloc(uintptr size) -{ - return runtime·mallocgc(size, nil, FlagNoInvokeGC); -} - int32 runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **sp) { @@ -399,12 +393,6 @@ runtime·persistentalloc(uintptr size, uintptr align, uint64 *stat) // Runtime stubs. -void* -runtime·mal(uintptr n) -{ - return runtime·mallocgc(n, nil, 0); -} - static void* cnew(Type *typ, intgo n) { diff --git a/src/pkg/runtime/malloc.go b/src/pkg/runtime/malloc.go index 81769573c9..e7f23889af 100644 --- a/src/pkg/runtime/malloc.go +++ b/src/pkg/runtime/malloc.go @@ -11,8 +11,7 @@ import ( const ( flagNoScan = 1 << 0 // GC doesn't have to scan object flagNoProfiling = 1 << 1 // must not profile - flagNoZero = 1 << 3 // don't zero memory - flagNoInvokeGC = 1 << 4 // don't invoke GC + flagNoZero = 1 << 2 // don't zero memory kindArray = 17 kindFunc = 19 @@ -198,7 +197,7 @@ func gomallocgc(size uintptr, typ *_type, flags int) unsafe.Pointer { releasem(mp) - if flags&flagNoInvokeGC == 0 && memstats.heap_alloc >= memstats.next_gc { + if memstats.heap_alloc >= memstats.next_gc { gogc(0) } diff --git a/src/pkg/runtime/malloc.h b/src/pkg/runtime/malloc.h index 1e26509bd9..43feef79ed 100644 --- a/src/pkg/runtime/malloc.h +++ b/src/pkg/runtime/malloc.h @@ -513,7 +513,6 @@ void runtime·MHeap_MapBits(MHeap *h); void runtime·MHeap_MapSpans(MHeap *h); void runtime·MHeap_Scavenger(void); -void* runtime·mallocgc(uintptr size, Type* typ, uint32 flag); void* runtime·persistentalloc(uintptr size, uintptr align, uint64 *stat); int32 runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **s); void runtime·gc(int32 force); @@ -537,9 +536,7 @@ enum // flags to malloc FlagNoScan = 1<<0, // GC doesn't have to scan object FlagNoProfiling = 1<<1, // must not profile - FlagNoGC = 1<<2, // must not free or scan for pointers - FlagNoZero = 1<<3, // don't zero memory - FlagNoInvokeGC = 1<<4, // don't invoke GC + FlagNoZero = 1<<2, // don't zero memory }; void runtime·MProf_Malloc(void*, uintptr); diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c index 16d616b3f6..4637d68bce 100644 --- a/src/pkg/runtime/mgc0.c +++ b/src/pkg/runtime/mgc0.c @@ -966,7 +966,7 @@ runtime·MSpan_Sweep(MSpan *s) xbits = *bitp; bits = (xbits>>shift) & bitMask; - // Non-allocated or FlagNoGC object, ignore. + // Non-allocated object, ignore. if(bits == bitBoundary) continue; // Allocated and marked object, reset bits to allocated. @@ -1659,7 +1659,7 @@ runfinq(void) // all not yet finalized objects are stored in finq. // If we do not mark it as FlagNoScan, // the last finalized object is not collected. - frame = runtime·mallocgc(framesz, 0, FlagNoScan|FlagNoInvokeGC); + frame = runtime·mallocgc(framesz, 0, FlagNoScan); framecap = framesz; } if(f->fint == nil) diff --git a/src/pkg/runtime/panic.c b/src/pkg/runtime/panic.c index af8bb1bc0e..bc685398a6 100644 --- a/src/pkg/runtime/panic.c +++ b/src/pkg/runtime/panic.c @@ -42,7 +42,7 @@ newdefer(int32 siz) if(d == nil) { // deferpool is empty or just a big defer total = runtime·roundupsize(TOTALSIZE(siz)); - d = runtime·malloc(total); + d = runtime·mallocgc(total, nil, 0); } d->siz = siz; d->special = 0; diff --git a/src/pkg/runtime/parfor.c b/src/pkg/runtime/parfor.c index 4706e0a43a..1073dfa394 100644 --- a/src/pkg/runtime/parfor.c +++ b/src/pkg/runtime/parfor.c @@ -27,7 +27,7 @@ runtime·parforalloc(uint32 nthrmax) // The ParFor object is followed by CacheLineSize padding // and then nthrmax ParForThread. - desc = (ParFor*)runtime·malloc(sizeof(ParFor) + CacheLineSize + nthrmax * sizeof(ParForThread)); + desc = (ParFor*)runtime·mallocgc(sizeof(ParFor) + CacheLineSize + nthrmax * sizeof(ParForThread), nil, 0); desc->thr = (ParForThread*)((byte*)(desc+1) + CacheLineSize); desc->nthrmax = nthrmax; return desc; diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c index 26e687e3b4..137f49f5f0 100644 --- a/src/pkg/runtime/proc.c +++ b/src/pkg/runtime/proc.c @@ -183,7 +183,7 @@ runtime·schedinit(void) n = MaxGomaxprocs; procs = n; } - runtime·allp = runtime·malloc((MaxGomaxprocs+1)*sizeof(runtime·allp[0])); + runtime·allp = runtime·mallocgc((MaxGomaxprocs+1)*sizeof(runtime·allp[0]), nil, 0); procresize(procs); runtime·copystack = runtime·precisestack; @@ -1926,7 +1926,7 @@ allgadd(G *gp) cap = 4096/sizeof(new[0]); if(cap < 2*allgcap) cap = 2*allgcap; - new = runtime·malloc(cap*sizeof(new[0])); + new = runtime·mallocgc(cap*sizeof(new[0]), nil, 0); if(new == nil) runtime·throw("runtime: cannot allocate memory"); if(runtime·allg != nil) @@ -2396,7 +2396,7 @@ procresize(int32 new) for(i = 0; i < new; i++) { p = runtime·allp[i]; if(p == nil) { - p = (P*)runtime·mallocgc(sizeof(*p), 0, FlagNoInvokeGC); + p = (P*)runtime·mallocgc(sizeof(*p), 0, 0); p->id = i; p->status = Pgcstop; runtime·atomicstorep(&runtime·allp[i], p); diff --git a/src/pkg/runtime/runtime.c b/src/pkg/runtime/runtime.c index 31b853c87a..98c9edda41 100644 --- a/src/pkg/runtime/runtime.c +++ b/src/pkg/runtime/runtime.c @@ -111,7 +111,7 @@ runtime·goargs(void) if(Windows) return; - s = runtime·malloc(argc*sizeof s[0]); + s = runtime·mallocgc(argc*sizeof s[0], nil, 0); for(i=0; i Date: Thu, 7 Aug 2014 13:28:10 +0400 Subject: [PATCH 018/423] runtime: fix plan9/windows build Fix few remaining cases after cl/117580043. TBR=dfc R=golang-codereviews CC=dave, golang-codereviews https://golang.org/cl/124850043 --- src/pkg/runtime/callback_windows.c | 2 +- src/pkg/runtime/env_plan9.c | 2 +- src/pkg/runtime/os_plan9.c | 4 ++-- src/pkg/runtime/os_windows.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pkg/runtime/callback_windows.c b/src/pkg/runtime/callback_windows.c index 285678fbac..97b75e1d2c 100644 --- a/src/pkg/runtime/callback_windows.c +++ b/src/pkg/runtime/callback_windows.c @@ -60,7 +60,7 @@ runtime·compilecallback(Eface fn, bool cleanstack) } if(n >= cb_max) runtime·throw("too many callback functions"); - c = runtime·mal(sizeof *c); + c = runtime·mallocgc(sizeof *c, nil, 0); c->gobody = fn.data; c->argsize = argsize; c->cleanstack = cleanstack; diff --git a/src/pkg/runtime/env_plan9.c b/src/pkg/runtime/env_plan9.c index f732c9f294..b6e98514f3 100644 --- a/src/pkg/runtime/env_plan9.c +++ b/src/pkg/runtime/env_plan9.c @@ -33,7 +33,7 @@ runtime·getenv(int8 *s) runtime·memclr(b, sizeof b); p = b; }else - p = runtime·malloc(n+1); + p = runtime·mallocgc(n+1, nil, 0); r = runtime·pread(fd, p, n, 0); runtime·close(fd); if(r < 0) diff --git a/src/pkg/runtime/os_plan9.c b/src/pkg/runtime/os_plan9.c index 02723fd9e4..98e449251a 100644 --- a/src/pkg/runtime/os_plan9.c +++ b/src/pkg/runtime/os_plan9.c @@ -20,11 +20,11 @@ runtime·mpreinit(M *mp) // Initialize stack and goroutine for note handling. mp->gsignal = runtime·malg(32*1024); mp->gsignal->m = mp; - mp->notesig = (int8*)runtime·malloc(ERRMAX*sizeof(int8)); + mp->notesig = (int8*)runtime·mallocgc(ERRMAX*sizeof(int8), nil, 0); // Initialize stack for handling strings from the // errstr system call, as used in package syscall. - mp->errstr = (byte*)runtime·malloc(ERRMAX*sizeof(byte)); + mp->errstr = (byte*)runtime·mallocgc(ERRMAX*sizeof(byte), nil, 0); } // Called to initialize a new m (including the bootstrap m). diff --git a/src/pkg/runtime/os_windows.c b/src/pkg/runtime/os_windows.c index 1dc0780ba9..79dc2960f9 100644 --- a/src/pkg/runtime/os_windows.c +++ b/src/pkg/runtime/os_windows.c @@ -143,7 +143,7 @@ runtime·goenvs(void) for(p=env; *p; n++) p += runtime·findnullw(p)+1; - s = runtime·malloc(n*sizeof s[0]); + s = runtime·mallocgc(n*sizeof s[0], nil, 0); p = env; for(i=0; i Date: Thu, 7 Aug 2014 13:34:30 +0400 Subject: [PATCH 019/423] runtime: convert markallocated from C to Go benchmark old ns/op new ns/op delta BenchmarkMalloc8 28.7 22.4 -21.95% BenchmarkMalloc16 44.8 33.8 -24.55% BenchmarkMallocTypeInfo8 49.0 32.9 -32.86% BenchmarkMallocTypeInfo16 46.7 35.8 -23.34% BenchmarkMallocLargeStruct 907 901 -0.66% BenchmarkGobDecode 13235542 12036851 -9.06% BenchmarkGobEncode 10639699 9539155 -10.34% BenchmarkJSONEncode 25193036 21898922 -13.08% BenchmarkJSONDecode 96104044 89464904 -6.91% Fixes #8452. LGTM=khr R=golang-codereviews, bradfitz, rsc, dave, khr CC=golang-codereviews https://golang.org/cl/122090043 --- src/pkg/runtime/malloc.go | 130 ++++++++++++++++++++++++++++++++++++-- src/pkg/runtime/malloc.h | 1 - src/pkg/runtime/mgc0.c | 129 ++++++------------------------------- src/pkg/runtime/stubs.go | 11 +++- src/pkg/runtime/stubs.goc | 10 +++ 5 files changed, 161 insertions(+), 120 deletions(-) diff --git a/src/pkg/runtime/malloc.go b/src/pkg/runtime/malloc.go index e7f23889af..73dc9f20d6 100644 --- a/src/pkg/runtime/malloc.go +++ b/src/pkg/runtime/malloc.go @@ -9,6 +9,8 @@ import ( ) const ( + debugMalloc = false + flagNoScan = 1 << 0 // GC doesn't have to scan object flagNoProfiling = 1 << 1 // must not profile flagNoZero = 1 << 2 // don't zero memory @@ -29,6 +31,22 @@ const ( pageShift = 13 pageSize = 1 << pageShift pageMask = pageSize - 1 + + wordsPerBitmapWord = ptrSize * 8 / 4 + gcBits = 4 + bitsPerPointer = 2 + bitsMask = 1<>shift)&bitMask) != bitBoundary { + gothrow("bad bits in markallocated") + } + var ti, te uintptr + var ptrmask *uint8 + if flags&flagNoScan != 0 { + // bitsDead in the first quadruple means don't scan. + if size == ptrSize { + *xbits = (*xbits & ^((bitBoundary | bitPtrMask) << shift)) | ((bitAllocated + (bitsDead << 2)) << shift) + } else { + xbitsb := (*uint8)(add(unsafe.Pointer(xbits), shift/8)) + *xbitsb = bitAllocated + (bitsDead << 2) + } + goto marked + } + if size == ptrSize { + // It's one word and it has pointers, it must be a pointer. + *xbits = (*xbits & ^((bitBoundary | bitPtrMask) << shift)) | ((bitAllocated | (bitsPointer << 2)) << shift) + goto marked + } + if typ != nil && (uintptr(typ.gc[0])|uintptr(typ.gc[1])) != 0 && uintptr(typ.size) > ptrSize { + if typ.kind&kindGCProg != 0 { + nptr := (uintptr(typ.size) + ptrSize - 1) / ptrSize + masksize := nptr + if masksize%2 != 0 { + masksize *= 2 // repeated + } + masksize = masksize * pointersPerByte / 8 // 4 bits per word + masksize++ // unroll flag in the beginning + if masksize > maxGCMask && typ.gc[1] != 0 { + // If the mask is too large, unroll the program directly + // into the GC bitmap. It's 7 times slower than copying + // from the pre-unrolled mask, but saves 1/16 of type size + // memory for the mask. + mp.ptrarg[0] = x + mp.ptrarg[1] = unsafe.Pointer(typ) + mp.scalararg[0] = uint(size) + mp.scalararg[1] = uint(size0) + onM(&unrollgcproginplace_m) + goto marked + } + ptrmask = (*uint8)(unsafe.Pointer(uintptr(typ.gc[0]))) + // Check whether the program is already unrolled. + if uintptr(goatomicloadp(unsafe.Pointer(ptrmask)))&0xff == 0 { + mp.ptrarg[0] = unsafe.Pointer(typ) + onM(&unrollgcprog_m) + } + ptrmask = (*uint8)(add(unsafe.Pointer(ptrmask), 1)) // skip the unroll flag byte + } else { + ptrmask = (*uint8)(unsafe.Pointer(&typ.gc[0])) // embed mask + } + if size == 2*ptrSize { + xbitsb := (*uint8)(add(unsafe.Pointer(xbits), shift/8)) + *xbitsb = *ptrmask | bitAllocated + goto marked + } + te = uintptr(typ.size) / ptrSize + // If the type occupies odd number of words, its mask is repeated. + if te%2 == 0 { + te /= 2 + } + } + if size == 2*ptrSize { + xbitsb := (*uint8)(add(unsafe.Pointer(xbits), shift/8)) + *xbitsb = (bitsPointer << 2) | (bitsPointer << 6) | bitAllocated + goto marked + } + // Copy pointer bitmask into the bitmap. + for i := uintptr(0); i < size0; i += 2 * ptrSize { + v := uint8((bitsPointer << 2) | (bitsPointer << 6)) + if ptrmask != nil { + v = *(*uint8)(add(unsafe.Pointer(ptrmask), ti)) + ti++ + if ti == te { + ti = 0 + } + } + if i == 0 { + v |= bitAllocated + } + if i+ptrSize == size0 { + v &= ^uint8(bitPtrMask << 4) + } + + off := (uintptr(x) + i - arena_start) / ptrSize + xbits := (*uintptr)(unsafe.Pointer(arena_start - off/wordsPerBitmapWord*ptrSize - ptrSize)) + shift := (off % wordsPerBitmapWord) * gcBits + xbitsb := (*uint8)(add(unsafe.Pointer(xbits), shift/8)) + *xbitsb = v + } + if size0%(2*ptrSize) == 0 && size0 < size { + // Mark the word after last object's word as bitsDead. + off := (uintptr(x) + size0 - arena_start) / ptrSize + xbits := (*uintptr)(unsafe.Pointer(arena_start - off/wordsPerBitmapWord*ptrSize - ptrSize)) + shift := (off % wordsPerBitmapWord) * gcBits + xbitsb := (*uint8)(add(unsafe.Pointer(xbits), shift/8)) + *xbitsb = bitsDead << 2 + } +marked: mp.mallocing = 0 if raceenabled { diff --git a/src/pkg/runtime/malloc.h b/src/pkg/runtime/malloc.h index 43feef79ed..4b16c55536 100644 --- a/src/pkg/runtime/malloc.h +++ b/src/pkg/runtime/malloc.h @@ -517,7 +517,6 @@ void* runtime·persistentalloc(uintptr size, uintptr align, uint64 *stat); int32 runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **s); void runtime·gc(int32 force); uintptr runtime·sweepone(void); -void runtime·markallocated(void *v, uintptr size, uintptr size0, Type* typ, bool scan); void runtime·markspan(void *v, uintptr size, uintptr n, bool leftover); void runtime·unmarkspan(void *v, uintptr size); void runtime·purgecachedstats(MCache*); diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c index 4637d68bce..8998a871ae 100644 --- a/src/pkg/runtime/mgc0.c +++ b/src/pkg/runtime/mgc0.c @@ -1741,7 +1741,7 @@ runtime·wakefing(void) return res; } -// Recursively GC program in prog. +// Recursively unrolls GC program in prog. // mask is where to store the result. // ppos is a pointer to position in mask, in bits. // sparse says to generate 4-bits per word mask for heap (2-bits for data/bss otherwise). @@ -1833,11 +1833,20 @@ unrollglobgcprog(byte *prog, uintptr size) return mask; } -static void -unrollgcproginplace(void *v, uintptr size, uintptr size0, Type *typ) +void +runtime·unrollgcproginplace_m(void) { - uintptr *b, off, shift, pos; + uintptr size, size0, *b, off, shift, pos; byte *arena_start, *prog; + Type *typ; + void *v; + + v = g->m->ptrarg[0]; + typ = g->m->ptrarg[1]; + size = g->m->scalararg[0]; + size0 = g->m->scalararg[1]; + g->m->ptrarg[0] = nil; + g->m->ptrarg[1] = nil; pos = 0; prog = (byte*)typ->gc[1]; @@ -1859,14 +1868,18 @@ unrollgcproginplace(void *v, uintptr size, uintptr size0, Type *typ) } // Unrolls GC program in typ->gc[1] into typ->gc[0] -static void -unrollgcprog(Type *typ) +void +runtime·unrollgcprog_m(void) { static Lock lock; + Type *typ; byte *mask, *prog; uintptr pos; uint32 x; + typ = g->m->ptrarg[0]; + g->m->ptrarg[0] = nil; + runtime·lock(&lock); mask = (byte*)typ->gc[0]; if(mask[0] == 0) { @@ -1887,110 +1900,6 @@ unrollgcprog(Type *typ) runtime·unlock(&lock); } -void -runtime·markallocated(void *v, uintptr size, uintptr size0, Type *typ, bool scan) -{ - uintptr *b, off, shift, i, ti, te, nptr, masksize; - byte *arena_start, x; - bool *ptrmask; - - arena_start = runtime·mheap.arena_start; - off = (uintptr*)v - (uintptr*)arena_start; - b = (uintptr*)arena_start - off/wordsPerBitmapWord - 1; - shift = (off % wordsPerBitmapWord) * gcBits; - if(Debug && (((*b)>>shift)&bitMask) != bitBoundary) { - runtime·printf("runtime: bad bits in markallocated (%p) b=%p[%p]\n", v, b, *b); - runtime·throw("bad bits in markallocated"); - } - - if(!scan) { - // BitsDead in the first quadruple means don't scan. - if(size == PtrSize) - *b = (*b & ~((bitBoundary|bitPtrMask)<gc[0]|typ->gc[1]) != 0 && typ->size > PtrSize) { - if(typ->kind&KindGCProg) { - nptr = ROUND(typ->size, PtrSize)/PtrSize; - masksize = nptr; - if(masksize%2) - masksize *= 2; // repeated twice - masksize = masksize*PointersPerByte/8; // 4 bits per word - masksize++; // unroll flag in the beginning - if(masksize > MaxGCMask && typ->gc[1] != 0) { - // If the mask is too large, unroll the program directly - // into the GC bitmap. It's 7 times slower than copying - // from the pre-unrolled mask, but saves 1/16 of type size - // memory for the mask. - unrollgcproginplace(v, size, size0, typ); - return; - } - ptrmask = (byte*)typ->gc[0]; - // check whether the program is already unrolled - if((runtime·atomicload((uint32*)ptrmask)&0xff) == 0) - unrollgcprog(typ); - ptrmask++; // skip the unroll flag byte - } else - ptrmask = (byte*)&typ->gc[0]; // embed mask - if(size == 2*PtrSize) { - ((byte*)b)[shift/8] = ptrmask[0] | bitAllocated; - return; - } - te = typ->size/PtrSize; - // if the type occupies odd number of words, its mask is repeated twice - if((te%2) == 0) - te /= 2; - } - if(size == 2*PtrSize) { - ((byte*)b)[shift/8] = (BitsPointer<<2) | (BitsPointer<<6) | bitAllocated; - return; - } - // Copy pointer bitmask into the bitmap. - for(i=0; im; - runtime·markallocated(mp->ptrarg[0], mp->scalararg[0], mp->scalararg[1], mp->ptrarg[1], mp->scalararg[2] == 0); - mp->ptrarg[0] = nil; - mp->ptrarg[1] = nil; -} - // mark the span of memory at v as having n blocks of the given size. // if leftover is true, there is left over space at the end of the span. void diff --git a/src/pkg/runtime/stubs.go b/src/pkg/runtime/stubs.go index 8a2fc8a97e..fee18f0470 100644 --- a/src/pkg/runtime/stubs.go +++ b/src/pkg/runtime/stubs.go @@ -65,7 +65,9 @@ var ( mprofMalloc_m, gc_m, setFinalizer_m, - markallocated_m mFunction + markallocated_m, + unrollgcprog_m, + unrollgcproginplace_m mFunction ) // memclr clears n bytes starting at ptr. @@ -87,7 +89,12 @@ const ( concurrentSweep = true ) -// in asm_*.s +// Atomic operations to read/write a pointer. +// in stubs.goc +func goatomicloadp(p unsafe.Pointer) unsafe.Pointer // return *p +func goatomicstorep(p unsafe.Pointer, v unsafe.Pointer) // *p = v + +// in stubs.goc // if *p == x { *p = y; return true } else { return false }, atomically //go:noescape func gocas(p *uint32, x uint32, y uint32) bool diff --git a/src/pkg/runtime/stubs.goc b/src/pkg/runtime/stubs.goc index c64e73de05..42a4bf1434 100644 --- a/src/pkg/runtime/stubs.goc +++ b/src/pkg/runtime/stubs.goc @@ -48,6 +48,16 @@ func gonanotime() (r int64) { r = runtime·nanotime(); } +#pragma textflag NOSPLIT +func goatomicloadp(p **byte) (v *byte) { + v = runtime·atomicloadp(p); +} + +#pragma textflag NOSPLIT +func goatomicstorep(p **byte, v *byte) { + runtime·atomicstorep(p, v); +} + #pragma textflag NOSPLIT func runtime·gocas(p *uint32, x uint32, y uint32) (ret bool) { ret = runtime·cas(p, x, y); From 689995a73e7a03038e977b5080666b561173e2b6 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 7 Aug 2014 08:17:41 -0400 Subject: [PATCH 020/423] cmd/gc: remove ignored debugging arguments in Fconv print LGTM=dave R=golang-codereviews, dave CC=golang-codereviews https://golang.org/cl/123880043 --- src/cmd/gc/mparith1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/gc/mparith1.c b/src/cmd/gc/mparith1.c index 1519caec7a..d33a81e09d 100644 --- a/src/cmd/gc/mparith1.c +++ b/src/cmd/gc/mparith1.c @@ -591,7 +591,7 @@ Fconv(Fmt *fp) d = mpgetflt(fvp); if(d >= 0 && (fp->flags & FmtSign)) fmtprint(fp, "+"); - return fmtprint(fp, "%g", d, exp, fvp); + return fmtprint(fp, "%g", d); } // very out of range. compute decimal approximation by hand. From 6cee4d3e8f52d4ab5ba2f97ca58f11d5e4c29fd4 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 7 Aug 2014 08:58:25 -0400 Subject: [PATCH 021/423] os: in Getwd, $PWD override syscall.Getwd This makes os.Getwd mimic C getwd on OS X, and possibly other systems. The change on OS X was a regression from 1.2 to 1.3. Fixes #8400. LGTM=bradfitz R=iant, bradfitz CC=golang-codereviews https://golang.org/cl/118970043 --- src/pkg/os/getwd.go | 23 +++++++++++------------ src/pkg/os/os_test.go | 9 +++++++-- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/pkg/os/getwd.go b/src/pkg/os/getwd.go index a72edeaee6..eacb414660 100644 --- a/src/pkg/os/getwd.go +++ b/src/pkg/os/getwd.go @@ -23,22 +23,12 @@ var useSyscallwd = func(error) bool { return true } // reached via multiple paths (due to symbolic links), // Getwd may return any one of them. func Getwd() (dir string, err error) { - // If the operating system provides a Getwd call, use it. - if syscall.ImplementsGetwd { - s, e := syscall.Getwd() - if useSyscallwd(e) { - return s, NewSyscallError("getwd", e) - } - } - - // Otherwise, we're trying to find our way back to ".". + // Clumsy but widespread kludge: + // if $PWD is set and matches ".", use it. dot, err := Stat(".") if err != nil { return "", err } - - // Clumsy but widespread kludge: - // if $PWD is set and matches ".", use it. dir = Getenv("PWD") if len(dir) > 0 && dir[0] == '/' { d, err := Stat(dir) @@ -47,6 +37,15 @@ func Getwd() (dir string, err error) { } } + // If the operating system provides a Getwd call, use it. + // Otherwise, we're trying to find our way back to ".". + if syscall.ImplementsGetwd { + s, e := syscall.Getwd() + if useSyscallwd(e) { + return s, NewSyscallError("getwd", e) + } + } + // Apply same kludge but to cached dir instead of $PWD. getwdCache.Lock() dir = getwdCache.dir diff --git a/src/pkg/os/os_test.go b/src/pkg/os/os_test.go index 2811f29f34..0224c9b01d 100644 --- a/src/pkg/os/os_test.go +++ b/src/pkg/os/os_test.go @@ -811,8 +811,8 @@ func TestChdirAndGetwd(t *testing.T) { t.Fatalf("Open .: %s", err) } // These are chosen carefully not to be symlinks on a Mac - // (unlike, say, /var, /etc, and /tmp). - dirs := []string{"/", "/usr/bin"} + // (unlike, say, /var, /etc), except /tmp, which we handle below. + dirs := []string{"/", "/usr/bin", "/tmp"} // /usr/bin does not usually exist on Plan 9 or Android. switch runtime.GOOS { case "android": @@ -820,6 +820,7 @@ func TestChdirAndGetwd(t *testing.T) { case "plan9": dirs = []string{"/", "/usr"} } + oldwd := Getenv("PWD") for mode := 0; mode < 2; mode++ { for _, d := range dirs { if mode == 0 { @@ -833,7 +834,11 @@ func TestChdirAndGetwd(t *testing.T) { err = fd1.Chdir() fd1.Close() } + if d == "/tmp" { + Setenv("PWD", "/tmp") + } pwd, err1 := Getwd() + Setenv("PWD", oldwd) err2 := fd.Chdir() if err2 != nil { // We changed the current directory and cannot go back. From e03bce158fba5f13dd7f2f0a86a40eb14958300b Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Thu, 7 Aug 2014 09:00:02 -0400 Subject: [PATCH 022/423] cmd/cc, runtime: eliminate use of the unnamed substructure C extension Eliminating use of this extension makes it easier to port the Go runtime to other compilers. This CL also disables the extension in cc to prevent accidental use. LGTM=rsc, khr R=rsc, aram, khr, dvyukov CC=axwalk, golang-codereviews https://golang.org/cl/106790044 --- src/cmd/cc/dcl.c | 9 +- src/pkg/runtime/callback_windows.c | 8 +- src/pkg/runtime/chan.goc | 54 ++-- src/pkg/runtime/chan.h | 2 +- src/pkg/runtime/defs_plan9_386.h | 5 +- src/pkg/runtime/heapdump.c | 4 +- src/pkg/runtime/iface.goc | 14 +- src/pkg/runtime/malloc.c | 12 +- src/pkg/runtime/malloc.h | 10 +- src/pkg/runtime/mcache.c | 12 +- src/pkg/runtime/mcentral.c | 30 +-- src/pkg/runtime/mgc0.c | 20 +- src/pkg/runtime/mheap.c | 38 +-- src/pkg/runtime/mprof.goc | 66 ++--- src/pkg/runtime/mprof.h | 6 +- src/pkg/runtime/netpoll.goc | 36 +-- src/pkg/runtime/proc.c | 144 +++++----- src/pkg/runtime/runtime.h | 4 +- src/pkg/runtime/sema.goc | 32 +-- src/pkg/runtime/sigqueue.goc | 10 +- src/pkg/runtime/time.goc | 24 +- src/pkg/runtime/type.h | 12 +- src/pkg/runtime/vlrt_386.c | 412 ++++++++++++++--------------- src/pkg/runtime/vlrt_arm.c | 27 +- 24 files changed, 481 insertions(+), 510 deletions(-) diff --git a/src/cmd/cc/dcl.c b/src/cmd/cc/dcl.c index a7a9426865..051a6c0a74 100644 --- a/src/cmd/cc/dcl.c +++ b/src/cmd/cc/dcl.c @@ -1481,12 +1481,9 @@ edecl(int c, Type *t, Sym *s) { Type *t1; - if(s == S) { - if(!typesu[t->etype]) - diag(Z, "unnamed structure element must be struct/union"); - if(c != CXXX) - diag(Z, "unnamed structure element cannot have class"); - } else + if(s == S) + diag(Z, "unnamed structure elements not supported"); + else if(c != CXXX) diag(Z, "structure element cannot have class: %s", s->name); t1 = t; diff --git a/src/pkg/runtime/callback_windows.c b/src/pkg/runtime/callback_windows.c index 97b75e1d2c..f1283a85d6 100644 --- a/src/pkg/runtime/callback_windows.c +++ b/src/pkg/runtime/callback_windows.c @@ -11,7 +11,7 @@ typedef struct Callbacks Callbacks; struct Callbacks { - Lock; + Lock lock; WinCallbackContext* ctxt[cb_max]; int32 n; }; @@ -44,13 +44,13 @@ runtime·compilecallback(Eface fn, bool cleanstack) argsize += sizeof(uintptr); } - runtime·lock(&cbs); + runtime·lock(&cbs.lock); if(runtime·cbctxts == nil) runtime·cbctxts = &(cbs.ctxt[0]); n = cbs.n; for(i=0; igobody == fn.data && cbs.ctxt[i]->cleanstack == cleanstack) { - runtime·unlock(&cbs); + runtime·unlock(&cbs.lock); // runtime·callbackasm is just a series of CALL instructions // (each is 5 bytes long), and we want callback to arrive at // correspondent call instruction instead of start of @@ -70,7 +70,7 @@ runtime·compilecallback(Eface fn, bool cleanstack) c->restorestack = 0; cbs.ctxt[n] = c; cbs.n++; - runtime·unlock(&cbs); + runtime·unlock(&cbs.lock); // as before return (byte*)runtime·callbackasm + n * 5; diff --git a/src/pkg/runtime/chan.goc b/src/pkg/runtime/chan.goc index b3520b60fc..7ddfab3f99 100644 --- a/src/pkg/runtime/chan.goc +++ b/src/pkg/runtime/chan.goc @@ -136,7 +136,7 @@ chansend(ChanType *t, Hchan *c, byte *ep, bool block, void *pc) mysg.releasetime = -1; } - runtime·lock(c); + runtime·lock(&c->lock); if(raceenabled) runtime·racereadpc(c, pc, chansend); if(c->closed) @@ -149,7 +149,7 @@ chansend(ChanType *t, Hchan *c, byte *ep, bool block, void *pc) if(sg != nil) { if(raceenabled) racesync(c, sg); - runtime·unlock(c); + runtime·unlock(&c->lock); gp = sg->g; gp->param = sg; @@ -162,7 +162,7 @@ chansend(ChanType *t, Hchan *c, byte *ep, bool block, void *pc) } if(!block) { - runtime·unlock(c); + runtime·unlock(&c->lock); return false; } @@ -171,10 +171,10 @@ chansend(ChanType *t, Hchan *c, byte *ep, bool block, void *pc) mysg.selectdone = nil; g->param = nil; enqueue(&c->sendq, &mysg); - runtime·parkunlock(c, "chan send"); + runtime·parkunlock(&c->lock, "chan send"); if(g->param == nil) { - runtime·lock(c); + runtime·lock(&c->lock); if(!c->closed) runtime·throw("chansend: spurious wakeup"); goto closed; @@ -191,16 +191,16 @@ asynch: if(c->qcount >= c->dataqsiz) { if(!block) { - runtime·unlock(c); + runtime·unlock(&c->lock); return false; } mysg.g = g; mysg.elem = nil; mysg.selectdone = nil; enqueue(&c->sendq, &mysg); - runtime·parkunlock(c, "chan send"); + runtime·parkunlock(&c->lock, "chan send"); - runtime·lock(c); + runtime·lock(&c->lock); goto asynch; } @@ -217,18 +217,18 @@ asynch: sg = dequeue(&c->recvq); if(sg != nil) { gp = sg->g; - runtime·unlock(c); + runtime·unlock(&c->lock); if(sg->releasetime) sg->releasetime = runtime·cputicks(); runtime·ready(gp); } else - runtime·unlock(c); + runtime·unlock(&c->lock); if(mysg.releasetime > 0) runtime·blockevent(mysg.releasetime - t0, 2); return true; closed: - runtime·unlock(c); + runtime·unlock(&c->lock); runtime·panicstring("send on closed channel"); return false; // not reached } @@ -262,7 +262,7 @@ chanrecv(ChanType *t, Hchan* c, byte *ep, bool block, bool *received) mysg.releasetime = -1; } - runtime·lock(c); + runtime·lock(&c->lock); if(c->dataqsiz > 0) goto asynch; @@ -273,7 +273,7 @@ chanrecv(ChanType *t, Hchan* c, byte *ep, bool block, bool *received) if(sg != nil) { if(raceenabled) racesync(c, sg); - runtime·unlock(c); + runtime·unlock(&c->lock); if(ep != nil) c->elemtype->alg->copy(c->elemsize, ep, sg->elem); @@ -289,7 +289,7 @@ chanrecv(ChanType *t, Hchan* c, byte *ep, bool block, bool *received) } if(!block) { - runtime·unlock(c); + runtime·unlock(&c->lock); return false; } @@ -298,10 +298,10 @@ chanrecv(ChanType *t, Hchan* c, byte *ep, bool block, bool *received) mysg.selectdone = nil; g->param = nil; enqueue(&c->recvq, &mysg); - runtime·parkunlock(c, "chan receive"); + runtime·parkunlock(&c->lock, "chan receive"); if(g->param == nil) { - runtime·lock(c); + runtime·lock(&c->lock); if(!c->closed) runtime·throw("chanrecv: spurious wakeup"); goto closed; @@ -319,7 +319,7 @@ asynch: goto closed; if(!block) { - runtime·unlock(c); + runtime·unlock(&c->lock); if(received != nil) *received = false; return false; @@ -328,9 +328,9 @@ asynch: mysg.elem = nil; mysg.selectdone = nil; enqueue(&c->recvq, &mysg); - runtime·parkunlock(c, "chan receive"); + runtime·parkunlock(&c->lock, "chan receive"); - runtime·lock(c); + runtime·lock(&c->lock); goto asynch; } @@ -349,12 +349,12 @@ asynch: sg = dequeue(&c->sendq); if(sg != nil) { gp = sg->g; - runtime·unlock(c); + runtime·unlock(&c->lock); if(sg->releasetime) sg->releasetime = runtime·cputicks(); runtime·ready(gp); } else - runtime·unlock(c); + runtime·unlock(&c->lock); if(received != nil) *received = true; @@ -369,7 +369,7 @@ closed: *received = false; if(raceenabled) runtime·raceacquire(c); - runtime·unlock(c); + runtime·unlock(&c->lock); if(mysg.releasetime > 0) runtime·blockevent(mysg.releasetime - t0, 2); return true; @@ -617,7 +617,7 @@ sellock(Select *sel) c0 = sel->lockorder[i]; if(c0 && c0 != c) { c = sel->lockorder[i]; - runtime·lock(c); + runtime·lock(&c->lock); } } } @@ -645,7 +645,7 @@ selunlock(Select *sel) c = sel->lockorder[i]; if(i>0 && sel->lockorder[i-1] == c) continue; // will unlock it on the next iteration - runtime·unlock(c); + runtime·unlock(&c->lock); } } @@ -1067,9 +1067,9 @@ closechan(Hchan *c, void *pc) if(c == nil) runtime·panicstring("close of nil channel"); - runtime·lock(c); + runtime·lock(&c->lock); if(c->closed) { - runtime·unlock(c); + runtime·unlock(&c->lock); runtime·panicstring("close of closed channel"); } @@ -1104,7 +1104,7 @@ closechan(Hchan *c, void *pc) runtime·ready(gp); } - runtime·unlock(c); + runtime·unlock(&c->lock); } func reflect·chanlen(c *Hchan) (len int) { diff --git a/src/pkg/runtime/chan.h b/src/pkg/runtime/chan.h index 043ef7d21c..e6e6bacd32 100644 --- a/src/pkg/runtime/chan.h +++ b/src/pkg/runtime/chan.h @@ -38,7 +38,7 @@ struct Hchan uintgo recvx; // receive index WaitQ recvq; // list of recv waiters WaitQ sendq; // list of send waiters - Lock; + Lock lock; }; // Buffer follows Hchan immediately in memory. diff --git a/src/pkg/runtime/defs_plan9_386.h b/src/pkg/runtime/defs_plan9_386.h index bde299dee1..a762b85899 100644 --- a/src/pkg/runtime/defs_plan9_386.h +++ b/src/pkg/runtime/defs_plan9_386.h @@ -21,9 +21,6 @@ struct Ureg uint32 pc; /* pc */ uint32 cs; /* old context */ uint32 flags; /* old flags */ - union { - uint32 usp; - uint32 sp; - }; + uint32 sp; uint32 ss; /* old stack segment */ }; diff --git a/src/pkg/runtime/heapdump.c b/src/pkg/runtime/heapdump.c index 9e968a250e..b002feb1c2 100644 --- a/src/pkg/runtime/heapdump.c +++ b/src/pkg/runtime/heapdump.c @@ -515,7 +515,7 @@ dumproots(void) if(sp->kind != KindSpecialFinalizer) continue; spf = (SpecialFinalizer*)sp; - p = (byte*)((s->start << PageShift) + spf->offset); + p = (byte*)((s->start << PageShift) + spf->special.offset); dumpfinalizer(p, spf->fn, spf->fint, spf->ot); } } @@ -695,7 +695,7 @@ dumpmemprof(void) if(sp->kind != KindSpecialProfile) continue; spp = (SpecialProfile*)sp; - p = (byte*)((s->start << PageShift) + spp->offset); + p = (byte*)((s->start << PageShift) + spp->special.offset); dumpint(TagAllocSample); dumpint((uintptr)p); dumpint((uintptr)spp->b); diff --git a/src/pkg/runtime/iface.goc b/src/pkg/runtime/iface.goc index 89c116e127..719d115880 100644 --- a/src/pkg/runtime/iface.goc +++ b/src/pkg/runtime/iface.goc @@ -42,7 +42,7 @@ itab(InterfaceType *inter, Type *type, int32 canfail) } // compiler has provided some good hash codes for us. - h = inter->hash; + h = inter->typ.hash; h += 17 * type->hash; // TODO(rsc): h += 23 * x->mhash ? h %= nelem(hash); @@ -98,7 +98,7 @@ search: throw: // didn't find method runtime·newTypeAssertionError( - nil, type->string, inter->string, + nil, type->string, inter->typ.string, iname, &err); if(locked) runtime·unlock(&ifacelock); @@ -231,7 +231,7 @@ assertI2Tret(Type *t, Iface i, byte *ret) } if(tab->type != t) { runtime·newTypeAssertionError( - tab->inter->string, tab->type->string, t->string, + tab->inter->typ.string, tab->type->string, t->string, nil, &err); runtime·panic(err); } @@ -332,7 +332,7 @@ func assertI2E(inter *InterfaceType, i Iface) (ret Eface) { if(tab == nil) { // explicit conversions require non-nil interface value. runtime·newTypeAssertionError( - nil, nil, inter->string, + nil, nil, inter->typ.string, nil, &err); runtime·panic(err); } @@ -377,7 +377,7 @@ runtime·ifaceI2I(InterfaceType *inter, Iface i, Iface *ret) if(tab == nil) { // explicit conversions require non-nil interface value. runtime·newTypeAssertionError( - nil, nil, inter->string, + nil, nil, inter->typ.string, nil, &err); runtime·panic(err); } @@ -414,7 +414,7 @@ runtime·ifaceE2I(InterfaceType *inter, Eface e, Iface *ret) if(t == nil) { // explicit conversions require non-nil interface value. runtime·newTypeAssertionError( - nil, nil, inter->string, + nil, nil, inter->typ.string, nil, &err); runtime·panic(err); } @@ -462,7 +462,7 @@ func assertE2E(inter *InterfaceType, e Eface) (ret Eface) { if(t == nil) { // explicit conversions require non-nil interface value. runtime·newTypeAssertionError( - nil, nil, inter->string, + nil, nil, inter->typ.string, nil, &err); runtime·panic(err); } diff --git a/src/pkg/runtime/malloc.c b/src/pkg/runtime/malloc.c index be3280e0f1..8b9447dad6 100644 --- a/src/pkg/runtime/malloc.c +++ b/src/pkg/runtime/malloc.c @@ -45,9 +45,9 @@ runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **sp) g->m->mcache->local_nlookup++; if (sizeof(void*) == 4 && g->m->mcache->local_nlookup >= (1<<30)) { // purge cache stats to prevent overflow - runtime·lock(&runtime·mheap); + runtime·lock(&runtime·mheap.lock); runtime·purgecachedstats(g->m->mcache); - runtime·unlock(&runtime·mheap); + runtime·unlock(&runtime·mheap.lock); } s = runtime·MHeap_LookupMaybe(&runtime·mheap, v); @@ -341,7 +341,7 @@ runtime·MHeap_SysAlloc(MHeap *h, uintptr n) static struct { - Lock; + Lock lock; byte* pos; byte* end; } persistent; @@ -370,19 +370,19 @@ runtime·persistentalloc(uintptr size, uintptr align, uint64 *stat) align = 8; if(size >= PersistentAllocMaxBlock) return runtime·SysAlloc(size, stat); - runtime·lock(&persistent); + runtime·lock(&persistent.lock); persistent.pos = (byte*)ROUND((uintptr)persistent.pos, align); if(persistent.pos + size > persistent.end) { persistent.pos = runtime·SysAlloc(PersistentAllocChunk, &mstats.other_sys); if(persistent.pos == nil) { - runtime·unlock(&persistent); + runtime·unlock(&persistent.lock); runtime·throw("runtime: cannot allocate memory"); } persistent.end = persistent.pos + PersistentAllocChunk; } p = persistent.pos; persistent.pos += size; - runtime·unlock(&persistent); + runtime·unlock(&persistent.lock); if(stat != &mstats.other_sys) { // reaccount the allocation against provided stat runtime·xadd64(stat, size); diff --git a/src/pkg/runtime/malloc.h b/src/pkg/runtime/malloc.h index 4b16c55536..593e9b885b 100644 --- a/src/pkg/runtime/malloc.h +++ b/src/pkg/runtime/malloc.h @@ -370,7 +370,7 @@ struct Special typedef struct SpecialFinalizer SpecialFinalizer; struct SpecialFinalizer { - Special; + Special special; FuncVal* fn; uintptr nret; Type* fint; @@ -382,7 +382,7 @@ typedef struct Bucket Bucket; // from mprof.h typedef struct SpecialProfile SpecialProfile; struct SpecialProfile { - Special; + Special special; Bucket* b; }; @@ -438,7 +438,7 @@ void runtime·MSpanList_Remove(MSpan *span); // from whatever list it is in // Central list of free objects of a given size. struct MCentral { - Lock; + Lock lock; int32 sizeclass; MSpan nonempty; // list of spans with a free object MSpan empty; // list of spans with no free objects (or cached in an MCache) @@ -454,7 +454,7 @@ bool runtime·MCentral_FreeSpan(MCentral *c, MSpan *s, int32 n, MLink *start, ML // but all the other global data is here too. struct MHeap { - Lock; + Lock lock; MSpan free[MaxMHeapList]; // free lists of given length MSpan freelarge; // free lists length >= MaxMHeapList MSpan busy[MaxMHeapList]; // busy lists of large objects of given length @@ -483,7 +483,7 @@ struct MHeap // spaced CacheLineSize bytes apart, so that each MCentral.Lock // gets its own cache line. struct { - MCentral; + MCentral mcentral; byte pad[CacheLineSize]; } central[NumSizeClasses]; diff --git a/src/pkg/runtime/mcache.c b/src/pkg/runtime/mcache.c index 665173bff5..e17bd2144f 100644 --- a/src/pkg/runtime/mcache.c +++ b/src/pkg/runtime/mcache.c @@ -22,9 +22,9 @@ runtime·allocmcache(void) MCache *c; int32 i; - runtime·lock(&runtime·mheap); + runtime·lock(&runtime·mheap.lock); c = runtime·FixAlloc_Alloc(&runtime·mheap.cachealloc); - runtime·unlock(&runtime·mheap); + runtime·unlock(&runtime·mheap.lock); runtime·memclr((byte*)c, sizeof(*c)); for(i = 0; i < NumSizeClasses; i++) c->alloc[i] = &emptymspan; @@ -45,10 +45,10 @@ freemcache(MCache *c) runtime·MCache_ReleaseAll(c); runtime·stackcache_clear(c); runtime·gcworkbuffree(c->gcworkbuf); - runtime·lock(&runtime·mheap); + runtime·lock(&runtime·mheap.lock); runtime·purgecachedstats(c); runtime·FixAlloc_Free(&runtime·mheap.cachealloc, c); - runtime·unlock(&runtime·mheap); + runtime·unlock(&runtime·mheap.lock); } static void @@ -85,7 +85,7 @@ runtime·MCache_Refill(MCache *c, int32 sizeclass) s->incache = false; // Get a new cached span from the central lists. - s = runtime·MCentral_CacheSpan(&runtime·mheap.central[sizeclass]); + s = runtime·MCentral_CacheSpan(&runtime·mheap.central[sizeclass].mcentral); if(s == nil) runtime·throw("out of memory"); if(s->freelist == nil) { @@ -106,7 +106,7 @@ runtime·MCache_ReleaseAll(MCache *c) for(i=0; ialloc[i]; if(s != &emptymspan) { - runtime·MCentral_UncacheSpan(&runtime·mheap.central[i], s); + runtime·MCentral_UncacheSpan(&runtime·mheap.central[i].mcentral, s); c->alloc[i] = &emptymspan; } } diff --git a/src/pkg/runtime/mcentral.c b/src/pkg/runtime/mcentral.c index 3f64b5ed23..6b2de02c42 100644 --- a/src/pkg/runtime/mcentral.c +++ b/src/pkg/runtime/mcentral.c @@ -37,14 +37,14 @@ runtime·MCentral_CacheSpan(MCentral *c) int32 cap, n; uint32 sg; - runtime·lock(c); + runtime·lock(&c->lock); sg = runtime·mheap.sweepgen; retry: for(s = c->nonempty.next; s != &c->nonempty; s = s->next) { if(s->sweepgen == sg-2 && runtime·cas(&s->sweepgen, sg-2, sg-1)) { - runtime·unlock(c); + runtime·unlock(&c->lock); runtime·MSpan_Sweep(s); - runtime·lock(c); + runtime·lock(&c->lock); // the span could have been moved to heap, retry goto retry; } @@ -63,9 +63,9 @@ retry: runtime·MSpanList_Remove(s); // swept spans are at the end of the list runtime·MSpanList_InsertBack(&c->empty, s); - runtime·unlock(c); + runtime·unlock(&c->lock); runtime·MSpan_Sweep(s); - runtime·lock(c); + runtime·lock(&c->lock); // the span could be moved to nonempty or heap, retry goto retry; } @@ -80,7 +80,7 @@ retry: // Replenish central list if empty. if(!MCentral_Grow(c)) { - runtime·unlock(c); + runtime·unlock(&c->lock); return nil; } goto retry; @@ -95,7 +95,7 @@ havespan: runtime·MSpanList_Remove(s); runtime·MSpanList_InsertBack(&c->empty, s); s->incache = true; - runtime·unlock(c); + runtime·unlock(&c->lock); return s; } @@ -105,7 +105,7 @@ runtime·MCentral_UncacheSpan(MCentral *c, MSpan *s) { int32 cap, n; - runtime·lock(c); + runtime·lock(&c->lock); s->incache = false; @@ -118,7 +118,7 @@ runtime·MCentral_UncacheSpan(MCentral *c, MSpan *s) runtime·MSpanList_Remove(s); runtime·MSpanList_Insert(&c->nonempty, s); } - runtime·unlock(c); + runtime·unlock(&c->lock); } // Free n objects from a span s back into the central free list c. @@ -130,7 +130,7 @@ runtime·MCentral_FreeSpan(MCentral *c, MSpan *s, int32 n, MLink *start, MLink * { if(s->incache) runtime·throw("freespan into cached span"); - runtime·lock(c); + runtime·lock(&c->lock); // Move to nonempty if necessary. if(s->freelist == nil) { @@ -150,7 +150,7 @@ runtime·MCentral_FreeSpan(MCentral *c, MSpan *s, int32 n, MLink *start, MLink * runtime·atomicstore(&s->sweepgen, runtime·mheap.sweepgen); if(s->ref != 0) { - runtime·unlock(c); + runtime·unlock(&c->lock); return false; } @@ -158,7 +158,7 @@ runtime·MCentral_FreeSpan(MCentral *c, MSpan *s, int32 n, MLink *start, MLink * runtime·MSpanList_Remove(s); s->needzero = 1; s->freelist = nil; - runtime·unlock(c); + runtime·unlock(&c->lock); runtime·unmarkspan((byte*)(s->start<npages<lock); npages = runtime·class_to_allocnpages[c->sizeclass]; size = runtime·class_to_size[c->sizeclass]; n = (npages << PageShift) / size; s = runtime·MHeap_Alloc(&runtime·mheap, npages, c->sizeclass, 0, 1); if(s == nil) { // TODO(rsc): Log out of memory - runtime·lock(c); + runtime·lock(&c->lock); return false; } @@ -198,7 +198,7 @@ MCentral_Grow(MCentral *c) *tailp = nil; runtime·markspan((byte*)(s->start<npages<lock); runtime·MSpanList_Insert(&c->nonempty, s); return true; } diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c index 8998a871ae..d7e5d89f01 100644 --- a/src/pkg/runtime/mgc0.c +++ b/src/pkg/runtime/mgc0.c @@ -539,7 +539,7 @@ markroot(ParFor *desc, uint32 i) // retain everything it points to. spf = (SpecialFinalizer*)sp; // A finalizer can be set for an inner byte of an object, find object beginning. - p = (void*)((s->start << PageShift) + spf->offset/s->elemsize*s->elemsize); + p = (void*)((s->start << PageShift) + spf->special.offset/s->elemsize*s->elemsize); scanblock(p, s->elemsize, nil); scanblock((void*)&spf->fn, PtrSize, ScanConservatively); } @@ -1043,7 +1043,7 @@ runtime·MSpan_Sweep(MSpan *s) c->local_nsmallfree[cl] += nfree; c->local_cachealloc -= nfree * size; runtime·xadd64(&mstats.next_gc, -(uint64)(nfree * size * (runtime·gcpercent + 100)/100)); - res = runtime·MCentral_FreeSpan(&runtime·mheap.central[cl], s, nfree, head.next, end); + res = runtime·MCentral_FreeSpan(&runtime·mheap.central[cl].mcentral, s, nfree, head.next, end); // MCentral_FreeSpan updates sweepgen } return res; @@ -1308,10 +1308,10 @@ runtime·gc(int32 force) return; if(runtime·gcpercent == GcpercentUnknown) { // first time through - runtime·lock(&runtime·mheap); + runtime·lock(&runtime·mheap.lock); if(runtime·gcpercent == GcpercentUnknown) runtime·gcpercent = runtime·readgogc(); - runtime·unlock(&runtime·mheap); + runtime·unlock(&runtime·mheap.lock); } if(runtime·gcpercent < 0) return; @@ -1560,7 +1560,7 @@ runtime∕debug·readGCStats(Slice *pauses) // Pass back: pauses, last gc (absolute time), number of gc, total pause ns. p = (uint64*)pauses->array; - runtime·lock(&runtime·mheap); + runtime·lock(&runtime·mheap.lock); n = mstats.numgc; if(n > nelem(mstats.pause_ns)) n = nelem(mstats.pause_ns); @@ -1575,7 +1575,7 @@ runtime∕debug·readGCStats(Slice *pauses) p[n] = mstats.last_gc; p[n+1] = mstats.numgc; p[n+2] = mstats.pause_total_ns; - runtime·unlock(&runtime·mheap); + runtime·unlock(&runtime·mheap.lock); pauses->len = n+3; } @@ -1583,14 +1583,14 @@ int32 runtime·setgcpercent(int32 in) { int32 out; - runtime·lock(&runtime·mheap); + runtime·lock(&runtime·mheap.lock); if(runtime·gcpercent == GcpercentUnknown) runtime·gcpercent = runtime·readgogc(); out = runtime·gcpercent; if(in < 0) in = -1; runtime·gcpercent = in; - runtime·unlock(&runtime·mheap); + runtime·unlock(&runtime·mheap.lock); return out; } @@ -1670,11 +1670,11 @@ runfinq(void) } else if(((InterfaceType*)f->fint)->mhdr.len == 0) { // convert to empty interface ef = (Eface*)frame; - ef->type = f->ot; + ef->type = &f->ot->typ; ef->data = f->arg; } else { // convert to interface with methods, via empty interface. - ef1.type = f->ot; + ef1.type = &f->ot->typ; ef1.data = f->arg; if(!runtime·ifaceE2I2((InterfaceType*)f->fint, ef1, (Iface*)frame)) runtime·throw("invalid type conversion in runfinq"); diff --git a/src/pkg/runtime/mheap.c b/src/pkg/runtime/mheap.c index c7043bb143..908d668462 100644 --- a/src/pkg/runtime/mheap.c +++ b/src/pkg/runtime/mheap.c @@ -70,7 +70,7 @@ runtime·MHeap_Init(MHeap *h) runtime·MSpanList_Init(&h->freelarge); runtime·MSpanList_Init(&h->busylarge); for(i=0; icentral); i++) - runtime·MCentral_Init(&h->central[i], i); + runtime·MCentral_Init(&h->central[i].mcentral, i); } void @@ -106,9 +106,9 @@ retry: runtime·MSpanList_Remove(s); // swept spans are at the end of the list runtime·MSpanList_InsertBack(list, s); - runtime·unlock(h); + runtime·unlock(&h->lock); n += runtime·MSpan_Sweep(s); - runtime·lock(h); + runtime·lock(&h->lock); if(n >= npages) return n; // the span could have been moved elsewhere @@ -153,7 +153,7 @@ MHeap_Reclaim(MHeap *h, uintptr npage) } // Now sweep everything that is not yet swept. - runtime·unlock(h); + runtime·unlock(&h->lock); for(;;) { n = runtime·sweepone(); if(n == -1) // all spans are swept @@ -162,7 +162,7 @@ MHeap_Reclaim(MHeap *h, uintptr npage) if(reclaimed >= npage) break; } - runtime·lock(h); + runtime·lock(&h->lock); } // Allocate a new span of npage pages from the heap for GC'd memory @@ -174,7 +174,7 @@ mheap_alloc(MHeap *h, uintptr npage, int32 sizeclass, bool large) if(g != g->m->g0) runtime·throw("mheap_alloc not on M stack"); - runtime·lock(h); + runtime·lock(&h->lock); // To prevent excessive heap growth, before allocating n pages // we need to sweep and reclaim at least n pages. @@ -207,7 +207,7 @@ mheap_alloc(MHeap *h, uintptr npage, int32 sizeclass, bool large) runtime·MSpanList_InsertBack(&h->busylarge, s); } } - runtime·unlock(h); + runtime·unlock(&h->lock); return s; } @@ -259,7 +259,7 @@ runtime·MHeap_AllocStack(MHeap *h, uintptr npage) if(g != g->m->g0) runtime·throw("mheap_allocstack not on M stack"); - runtime·lock(h); + runtime·lock(&h->lock); s = MHeap_AllocSpanLocked(h, npage); if(s != nil) { s->state = MSpanStack; @@ -267,7 +267,7 @@ runtime·MHeap_AllocStack(MHeap *h, uintptr npage) s->ref = 0; mstats.stacks_inuse += s->npages<lock); return s; } @@ -460,7 +460,7 @@ mheap_free(MHeap *h, MSpan *s, int32 acct) { if(g != g->m->g0) runtime·throw("mheap_free not on M stack"); - runtime·lock(h); + runtime·lock(&h->lock); mstats.heap_alloc += g->m->mcache->local_cachealloc; g->m->mcache->local_cachealloc = 0; if(acct) { @@ -468,7 +468,7 @@ mheap_free(MHeap *h, MSpan *s, int32 acct) mstats.heap_objects--; } MHeap_FreeSpanLocked(h, s); - runtime·unlock(h); + runtime·unlock(&h->lock); } static void @@ -504,10 +504,10 @@ runtime·MHeap_FreeStack(MHeap *h, MSpan *s) if(g != g->m->g0) runtime·throw("mheap_freestack not on M stack"); s->needzero = 1; - runtime·lock(h); + runtime·lock(&h->lock); mstats.stacks_inuse -= s->npages<lock); } static void @@ -626,9 +626,9 @@ scavenge(int32 k, uint64 now, uint64 limit) static void scavenge_m(G *gp) { - runtime·lock(&runtime·mheap); + runtime·lock(&runtime·mheap.lock); scavenge(g->m->scalararg[0], g->m->scalararg[1], g->m->scalararg[2]); - runtime·unlock(&runtime·mheap); + runtime·unlock(&runtime·mheap.lock); runtime·gogo(&gp->sched); } @@ -865,12 +865,12 @@ runtime·addfinalizer(void *p, FuncVal *f, uintptr nret, Type *fint, PtrType *ot runtime·lock(&runtime·mheap.speciallock); s = runtime·FixAlloc_Alloc(&runtime·mheap.specialfinalizeralloc); runtime·unlock(&runtime·mheap.speciallock); - s->kind = KindSpecialFinalizer; + s->special.kind = KindSpecialFinalizer; s->fn = f; s->nret = nret; s->fint = fint; s->ot = ot; - if(addspecial(p, s)) + if(addspecial(p, &s->special)) return true; // There was an old finalizer @@ -903,9 +903,9 @@ runtime·setprofilebucket(void *p, Bucket *b) runtime·lock(&runtime·mheap.speciallock); s = runtime·FixAlloc_Alloc(&runtime·mheap.specialprofilealloc); runtime·unlock(&runtime·mheap.speciallock); - s->kind = KindSpecialProfile; + s->special.kind = KindSpecialProfile; s->b = b; - if(!addspecial(p, s)) + if(!addspecial(p, &s->special)) runtime·throw("setprofilebucket: profile already set"); } diff --git a/src/pkg/runtime/mprof.goc b/src/pkg/runtime/mprof.goc index 053781193e..6a028c31f3 100644 --- a/src/pkg/runtime/mprof.goc +++ b/src/pkg/runtime/mprof.goc @@ -92,20 +92,20 @@ MProf_GC(void) Bucket *b; for(b=mbuckets; b; b=b->allnext) { - b->allocs += b->prev_allocs; - b->frees += b->prev_frees; - b->alloc_bytes += b->prev_alloc_bytes; - b->free_bytes += b->prev_free_bytes; + b->data.mp.allocs += b->data.mp.prev_allocs; + b->data.mp.frees += b->data.mp.prev_frees; + b->data.mp.alloc_bytes += b->data.mp.prev_alloc_bytes; + b->data.mp.free_bytes += b->data.mp.prev_free_bytes; - b->prev_allocs = b->recent_allocs; - b->prev_frees = b->recent_frees; - b->prev_alloc_bytes = b->recent_alloc_bytes; - b->prev_free_bytes = b->recent_free_bytes; + b->data.mp.prev_allocs = b->data.mp.recent_allocs; + b->data.mp.prev_frees = b->data.mp.recent_frees; + b->data.mp.prev_alloc_bytes = b->data.mp.recent_alloc_bytes; + b->data.mp.prev_free_bytes = b->data.mp.recent_free_bytes; - b->recent_allocs = 0; - b->recent_frees = 0; - b->recent_alloc_bytes = 0; - b->recent_free_bytes = 0; + b->data.mp.recent_allocs = 0; + b->data.mp.recent_frees = 0; + b->data.mp.recent_alloc_bytes = 0; + b->data.mp.recent_free_bytes = 0; } } @@ -129,8 +129,8 @@ runtime·MProf_Malloc(void *p, uintptr size) nstk = runtime·callers(1, stk, nelem(stk)); runtime·lock(&proflock); b = stkbucket(MProf, size, stk, nstk, true); - b->recent_allocs++; - b->recent_alloc_bytes += size; + b->data.mp.recent_allocs++; + b->data.mp.recent_alloc_bytes += size; runtime·unlock(&proflock); // Setprofilebucket locks a bunch of other mutexes, so we call it outside of proflock. @@ -160,8 +160,8 @@ runtime·mprofMalloc_m(void) nstk = runtime·gcallers(g->m->curg, 1, stk, nelem(stk)); runtime·lock(&proflock); b = stkbucket(MProf, size, stk, nstk, true); - b->recent_allocs++; - b->recent_alloc_bytes += size; + b->data.mp.recent_allocs++; + b->data.mp.recent_alloc_bytes += size; runtime·unlock(&proflock); // Setprofilebucket locks a bunch of other mutexes, so we call it outside of proflock. @@ -177,11 +177,11 @@ runtime·MProf_Free(Bucket *b, uintptr size, bool freed) { runtime·lock(&proflock); if(freed) { - b->recent_frees++; - b->recent_free_bytes += size; + b->data.mp.recent_frees++; + b->data.mp.recent_free_bytes += size; } else { - b->prev_frees++; - b->prev_free_bytes += size; + b->data.mp.prev_frees++; + b->data.mp.prev_free_bytes += size; } runtime·unlock(&proflock); } @@ -221,8 +221,8 @@ runtime·blockevent(int64 cycles, int32 skip) nstk = runtime·callers(skip, stk, nelem(stk)); runtime·lock(&proflock); b = stkbucket(BProf, 0, stk, nstk, true); - b->count++; - b->cycles += cycles; + b->data.bp.count++; + b->data.bp.cycles += cycles; runtime·unlock(&proflock); } @@ -242,10 +242,10 @@ record(Record *r, Bucket *b) { int32 i; - r->alloc_bytes = b->alloc_bytes; - r->free_bytes = b->free_bytes; - r->alloc_objects = b->allocs; - r->free_objects = b->frees; + r->alloc_bytes = b->data.mp.alloc_bytes; + r->free_bytes = b->data.mp.free_bytes; + r->alloc_objects = b->data.mp.allocs; + r->free_objects = b->data.mp.frees; for(i=0; instk && istk); i++) r->stk[i] = b->stk[i]; for(; istk); i++) @@ -261,9 +261,9 @@ func MemProfile(p Slice, include_inuse_zero bool) (n int, ok bool) { n = 0; clear = true; for(b=mbuckets; b; b=b->allnext) { - if(include_inuse_zero || b->alloc_bytes != b->free_bytes) + if(include_inuse_zero || b->data.mp.alloc_bytes != b->data.mp.free_bytes) n++; - if(b->allocs != 0 || b->frees != 0) + if(b->data.mp.allocs != 0 || b->data.mp.frees != 0) clear = false; } if(clear) { @@ -275,7 +275,7 @@ func MemProfile(p Slice, include_inuse_zero bool) (n int, ok bool) { MProf_GC(); n = 0; for(b=mbuckets; b; b=b->allnext) - if(include_inuse_zero || b->alloc_bytes != b->free_bytes) + if(include_inuse_zero || b->data.mp.alloc_bytes != b->data.mp.free_bytes) n++; } ok = false; @@ -283,7 +283,7 @@ func MemProfile(p Slice, include_inuse_zero bool) (n int, ok bool) { ok = true; r = (Record*)p.array; for(b=mbuckets; b; b=b->allnext) - if(include_inuse_zero || b->alloc_bytes != b->free_bytes) + if(include_inuse_zero || b->data.mp.alloc_bytes != b->data.mp.free_bytes) record(r++, b); } runtime·unlock(&proflock); @@ -296,7 +296,7 @@ runtime·iterate_memprof(void (*callback)(Bucket*, uintptr, uintptr*, uintptr, u runtime·lock(&proflock); for(b=mbuckets; b; b=b->allnext) { - callback(b, b->nstk, b->stk, b->size, b->allocs, b->frees); + callback(b, b->nstk, b->stk, b->size, b->data.mp.allocs, b->data.mp.frees); } runtime·unlock(&proflock); } @@ -323,8 +323,8 @@ func BlockProfile(p Slice) (n int, ok bool) { ok = true; r = (BRecord*)p.array; for(b=bbuckets; b; b=b->allnext, r++) { - r->count = b->count; - r->cycles = b->cycles; + r->count = b->data.bp.count; + r->cycles = b->data.bp.cycles; for(i=0; instk && istk); i++) r->stk[i] = b->stk[i]; for(; istk); i++) diff --git a/src/pkg/runtime/mprof.h b/src/pkg/runtime/mprof.h index de5e707d60..5e9f3b55a4 100644 --- a/src/pkg/runtime/mprof.h +++ b/src/pkg/runtime/mprof.h @@ -42,13 +42,13 @@ struct Bucket uintptr recent_alloc_bytes; uintptr recent_free_bytes; - }; + } mp; struct // typ == BProf { int64 count; int64 cycles; - }; - }; + } bp; + } data; uintptr hash; // hash of size + stk uintptr size; uintptr nstk; diff --git a/src/pkg/runtime/netpoll.goc b/src/pkg/runtime/netpoll.goc index 7b3d16d02d..eb7f8878cb 100644 --- a/src/pkg/runtime/netpoll.goc +++ b/src/pkg/runtime/netpoll.goc @@ -48,7 +48,7 @@ struct PollDesc // pollReset, pollWait, pollWaitCanceled and runtime·netpollready (IO rediness notification) // proceed w/o taking the lock. So closing, rg, rd, wg and wd are manipulated // in a lock-free way by all operations. - Lock; // protectes the following fields + Lock lock; // protectes the following fields uintptr fd; bool closing; uintptr seq; // protects from stale timers and ready notifications @@ -63,7 +63,7 @@ struct PollDesc static struct { - Lock; + Lock lock; PollDesc* first; // PollDesc objects must be type-stable, // because we can get ready notification from epoll/kqueue @@ -95,7 +95,7 @@ func runtime_pollServerInit() { func runtime_pollOpen(fd uintptr) (pd *PollDesc, errno int) { pd = allocPollDesc(); - runtime·lock(pd); + runtime·lock(&pd->lock); if(pd->wg != nil && pd->wg != READY) runtime·throw("runtime_pollOpen: blocked write on free descriptor"); if(pd->rg != nil && pd->rg != READY) @@ -107,7 +107,7 @@ func runtime_pollOpen(fd uintptr) (pd *PollDesc, errno int) { pd->rd = 0; pd->wg = nil; pd->wd = 0; - runtime·unlock(pd); + runtime·unlock(&pd->lock); errno = runtime·netpollopen(fd, pd); } @@ -120,10 +120,10 @@ func runtime_pollClose(pd *PollDesc) { if(pd->rg != nil && pd->rg != READY) runtime·throw("runtime_pollClose: blocked read on closing descriptor"); runtime·netpollclose(pd->fd); - runtime·lock(&pollcache); + runtime·lock(&pollcache.lock); pd->link = pollcache.first; pollcache.first = pd; - runtime·unlock(&pollcache); + runtime·unlock(&pollcache.lock); } func runtime_pollReset(pd *PollDesc, mode int) (err int) { @@ -164,9 +164,9 @@ func runtime_pollWaitCanceled(pd *PollDesc, mode int) { func runtime_pollSetDeadline(pd *PollDesc, d int64, mode int) { G *rg, *wg; - runtime·lock(pd); + runtime·lock(&pd->lock); if(pd->closing) { - runtime·unlock(pd); + runtime·unlock(&pd->lock); return; } pd->seq++; // invalidate current timers @@ -218,7 +218,7 @@ func runtime_pollSetDeadline(pd *PollDesc, d int64, mode int) { rg = netpollunblock(pd, 'r', false); if(pd->wd < 0) wg = netpollunblock(pd, 'w', false); - runtime·unlock(pd); + runtime·unlock(&pd->lock); if(rg) runtime·ready(rg); if(wg) @@ -228,7 +228,7 @@ func runtime_pollSetDeadline(pd *PollDesc, d int64, mode int) { func runtime_pollUnblock(pd *PollDesc) { G *rg, *wg; - runtime·lock(pd); + runtime·lock(&pd->lock); if(pd->closing) runtime·throw("runtime_pollUnblock: already closing"); pd->closing = true; @@ -244,7 +244,7 @@ func runtime_pollUnblock(pd *PollDesc) { runtime·deltimer(&pd->wt); pd->wt.fv = nil; } - runtime·unlock(pd); + runtime·unlock(&pd->lock); if(rg) runtime·ready(rg); if(wg) @@ -272,13 +272,13 @@ runtime·netpollclosing(PollDesc *pd) void runtime·netpolllock(PollDesc *pd) { - runtime·lock(pd); + runtime·lock(&pd->lock); } void runtime·netpollunlock(PollDesc *pd) { - runtime·unlock(pd); + runtime·unlock(&pd->lock); } // make pd ready, newly runnable goroutines (if any) are enqueued info gpp list @@ -396,10 +396,10 @@ deadlineimpl(int64 now, Eface arg, bool read, bool write) // If it's stale, ignore the timer event. seq = (uintptr)arg.type; rg = wg = nil; - runtime·lock(pd); + runtime·lock(&pd->lock); if(seq != pd->seq) { // The descriptor was reused or timers were reset. - runtime·unlock(pd); + runtime·unlock(&pd->lock); return; } if(read) { @@ -416,7 +416,7 @@ deadlineimpl(int64 now, Eface arg, bool read, bool write) runtime·atomicstorep(&pd->wt.fv, nil); // full memory barrier between store to wd and load of wg in netpollunblock wg = netpollunblock(pd, 'w', false); } - runtime·unlock(pd); + runtime·unlock(&pd->lock); if(rg) runtime·ready(rg); if(wg) @@ -447,7 +447,7 @@ allocPollDesc(void) PollDesc *pd; uint32 i, n; - runtime·lock(&pollcache); + runtime·lock(&pollcache.lock); if(pollcache.first == nil) { n = PollBlockSize/sizeof(*pd); if(n == 0) @@ -462,6 +462,6 @@ allocPollDesc(void) } pd = pollcache.first; pollcache.first = pd->link; - runtime·unlock(&pollcache); + runtime·unlock(&pollcache.lock); return pd; } diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c index 137f49f5f0..cef41d95f2 100644 --- a/src/pkg/runtime/proc.c +++ b/src/pkg/runtime/proc.c @@ -26,7 +26,7 @@ typedef struct Sched Sched; struct Sched { - Lock; + Lock lock; uint64 goidgen; @@ -371,7 +371,7 @@ mcommoninit(M *mp) mp->fastrand = 0x49f6428aUL + mp->id + runtime·cputicks(); - runtime·lock(&runtime·sched); + runtime·lock(&runtime·sched.lock); mp->id = runtime·sched.mcount++; checkmcount(); runtime·mpreinit(mp); @@ -382,7 +382,7 @@ mcommoninit(M *mp) // runtime·NumCgoCall() iterates over allm w/o schedlock, // so we need to publish it safely. runtime·atomicstorep(&runtime·allm, mp); - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); } // Mark gp ready to run. @@ -411,7 +411,7 @@ runtime·gcprocs(void) // Figure out how many CPUs to use during GC. // Limited by gomaxprocs, number of actual CPUs, and MaxGcproc. - runtime·lock(&runtime·sched); + runtime·lock(&runtime·sched.lock); n = runtime·gomaxprocs; if(n > runtime·ncpu) n = runtime·ncpu; @@ -419,7 +419,7 @@ runtime·gcprocs(void) n = MaxGcproc; if(n > runtime·sched.nmidle+1) // one M is currently running n = runtime·sched.nmidle+1; - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); return n; } @@ -428,14 +428,14 @@ needaddgcproc(void) { int32 n; - runtime·lock(&runtime·sched); + runtime·lock(&runtime·sched.lock); n = runtime·gomaxprocs; if(n > runtime·ncpu) n = runtime·ncpu; if(n > MaxGcproc) n = MaxGcproc; n -= runtime·sched.nmidle+1; // one M is currently running - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); return n > 0; } @@ -445,7 +445,7 @@ runtime·helpgc(int32 nproc) M *mp; int32 n, pos; - runtime·lock(&runtime·sched); + runtime·lock(&runtime·sched.lock); pos = 0; for(n = 1; n < nproc; n++) { // one M is currently running if(runtime·allp[pos]->mcache == g->m->mcache) @@ -458,7 +458,7 @@ runtime·helpgc(int32 nproc) pos++; runtime·notewakeup(&mp->park); } - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); } // Similar to stoptheworld but best-effort and can be called several times. @@ -497,7 +497,7 @@ runtime·stoptheworld(void) P *p; bool wait; - runtime·lock(&runtime·sched); + runtime·lock(&runtime·sched.lock); runtime·sched.stopwait = runtime·gomaxprocs; runtime·atomicstore((uint32*)&runtime·sched.gcwaiting, 1); preemptall(); @@ -517,7 +517,7 @@ runtime·stoptheworld(void) runtime·sched.stopwait--; } wait = runtime·sched.stopwait > 0; - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); // wait for remaining P's to stop voluntarily if(wait) { @@ -557,7 +557,7 @@ runtime·starttheworld(void) gp = runtime·netpoll(false); // non-blocking injectglist(gp); add = needaddgcproc(); - runtime·lock(&runtime·sched); + runtime·lock(&runtime·sched.lock); if(newprocs) { procresize(newprocs); newprocs = 0; @@ -581,7 +581,7 @@ runtime·starttheworld(void) runtime·sched.sysmonwait = false; runtime·notewakeup(&runtime·sched.sysmonnote); } - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); while(p1) { p = p1; @@ -964,9 +964,9 @@ stopm(void) } retry: - runtime·lock(&runtime·sched); + runtime·lock(&runtime·sched.lock); mput(g->m); - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); runtime·notesleep(&g->m->park); runtime·noteclear(&g->m->park); if(g->m->helpgc) { @@ -993,18 +993,18 @@ startm(P *p, bool spinning) M *mp; void (*fn)(void); - runtime·lock(&runtime·sched); + runtime·lock(&runtime·sched.lock); if(p == nil) { p = pidleget(); if(p == nil) { - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); if(spinning) runtime·xadd(&runtime·sched.nmspinning, -1); return; } } mp = mget(); - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); if(mp == nil) { fn = nil; if(spinning) @@ -1037,28 +1037,28 @@ handoffp(P *p) startm(p, true); return; } - runtime·lock(&runtime·sched); + runtime·lock(&runtime·sched.lock); if(runtime·sched.gcwaiting) { p->status = Pgcstop; if(--runtime·sched.stopwait == 0) runtime·notewakeup(&runtime·sched.stopnote); - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); return; } if(runtime·sched.runqsize) { - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); startm(p, false); return; } // If this is the last running P and nobody is polling network, // need to wakeup another M to poll network. if(runtime·sched.npidle == runtime·gomaxprocs-1 && runtime·atomicload64(&runtime·sched.lastpoll) != 0) { - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); startm(p, false); return; } pidleput(p); - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); } // Tries to add one more P to execute G's. @@ -1130,11 +1130,11 @@ gcstopm(void) runtime·xadd(&runtime·sched.nmspinning, -1); } p = releasep(); - runtime·lock(&runtime·sched); + runtime·lock(&runtime·sched.lock); p->status = Pgcstop; if(--runtime·sched.stopwait == 0) runtime·notewakeup(&runtime·sched.stopnote); - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); stopm(); } @@ -1187,9 +1187,9 @@ top: return gp; // global runq if(runtime·sched.runqsize) { - runtime·lock(&runtime·sched); + runtime·lock(&runtime·sched.lock); gp = globrunqget(g->m->p, 0); - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); if(gp) return gp; } @@ -1223,19 +1223,19 @@ top: } stop: // return P and block - runtime·lock(&runtime·sched); + runtime·lock(&runtime·sched.lock); if(runtime·sched.gcwaiting) { - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); goto top; } if(runtime·sched.runqsize) { gp = globrunqget(g->m->p, 0); - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); return gp; } p = releasep(); pidleput(p); - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); if(g->m->spinning) { g->m->spinning = false; runtime·xadd(&runtime·sched.nmspinning, -1); @@ -1244,9 +1244,9 @@ stop: for(i = 0; i < runtime·gomaxprocs; i++) { p = runtime·allp[i]; if(p && p->runqhead != p->runqtail) { - runtime·lock(&runtime·sched); + runtime·lock(&runtime·sched.lock); p = pidleget(); - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); if(p) { acquirep(p); goto top; @@ -1263,9 +1263,9 @@ stop: gp = runtime·netpoll(true); // block until new work is available runtime·atomicstore64(&runtime·sched.lastpoll, runtime·nanotime()); if(gp) { - runtime·lock(&runtime·sched); + runtime·lock(&runtime·sched.lock); p = pidleget(); - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); if(p) { acquirep(p); injectglist(gp->schedlink); @@ -1308,14 +1308,14 @@ injectglist(G *glist) if(glist == nil) return; - runtime·lock(&runtime·sched); + runtime·lock(&runtime·sched.lock); for(n = 0; glist; n++) { gp = glist; glist = gp->schedlink; gp->status = Grunnable; globrunqput(gp); } - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); for(; n && runtime·sched.npidle; n--) startm(nil, false); @@ -1351,9 +1351,9 @@ top: // This is a fancy way to say tick%61==0, // it uses 2 MUL instructions instead of a single DIV and so is faster on modern processors. if(tick - (((uint64)tick*0x4325c53fu)>>36)*61 == 0 && runtime·sched.runqsize > 0) { - runtime·lock(&runtime·sched); + runtime·lock(&runtime·sched.lock); gp = globrunqget(g->m->p, 1); - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); if(gp) resetspinning(); } @@ -1459,9 +1459,9 @@ runtime·gosched0(G *gp) { gp->status = Grunnable; dropg(); - runtime·lock(&runtime·sched); + runtime·lock(&runtime·sched.lock); globrunqput(gp); - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); schedule(); } @@ -1551,12 +1551,12 @@ void } if(runtime·atomicload(&runtime·sched.sysmonwait)) { // TODO: fast atomic - runtime·lock(&runtime·sched); + runtime·lock(&runtime·sched.lock); if(runtime·atomicload(&runtime·sched.sysmonwait)) { runtime·atomicstore(&runtime·sched.sysmonwait, 0); runtime·notewakeup(&runtime·sched.sysmonnote); } - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); save(runtime·getcallerpc(&dummy), runtime·getcallersp(&dummy)); } @@ -1564,12 +1564,12 @@ void g->m->p->m = nil; runtime·atomicstore(&g->m->p->status, Psyscall); if(runtime·sched.gcwaiting) { - runtime·lock(&runtime·sched); + runtime·lock(&runtime·sched.lock); if (runtime·sched.stopwait > 0 && runtime·cas(&g->m->p->status, Psyscall, Pgcstop)) { if(--runtime·sched.stopwait == 0) runtime·notewakeup(&runtime·sched.stopnote); } - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); save(runtime·getcallerpc(&dummy), runtime·getcallersp(&dummy)); } @@ -1685,13 +1685,13 @@ exitsyscallfast(void) // Try to get any other idle P. g->m->p = nil; if(runtime·sched.pidle) { - runtime·lock(&runtime·sched); + runtime·lock(&runtime·sched.lock); p = pidleget(); if(p && runtime·atomicload(&runtime·sched.sysmonwait)) { runtime·atomicstore(&runtime·sched.sysmonwait, 0); runtime·notewakeup(&runtime·sched.sysmonnote); } - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); if(p) { acquirep(p); return true; @@ -1709,7 +1709,7 @@ exitsyscall0(G *gp) gp->status = Grunnable; dropg(); - runtime·lock(&runtime·sched); + runtime·lock(&runtime·sched.lock); p = pidleget(); if(p == nil) globrunqput(gp); @@ -1717,7 +1717,7 @@ exitsyscall0(G *gp) runtime·atomicstore(&runtime·sched.sysmonwait, 0); runtime·notewakeup(&runtime·sched.sysmonnote); } - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); if(p) { acquirep(p); execute(gp); // Never returns. @@ -2069,13 +2069,13 @@ runtime·gomaxprocsfunc(int32 n) if(n > MaxGomaxprocs) n = MaxGomaxprocs; - runtime·lock(&runtime·sched); + runtime·lock(&runtime·sched.lock); ret = runtime·gomaxprocs; if(n <= 0 || n == ret) { - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); return ret; } - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); runtime·semacquire(&runtime·worldsema, false); g->m->gcing = 1; @@ -2192,7 +2192,7 @@ runtime·badreflectcall(void) // called from assembly } static struct { - Lock; + Lock lock; void (*fn)(uintptr*, int32); int32 hz; uintptr pcbuf[100]; @@ -2300,9 +2300,9 @@ runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp) ((uint8*)runtime·gogo <= pc && pc < (uint8*)runtime·gogo + RuntimeGogoBytes)) traceback = false; - runtime·lock(&prof); + runtime·lock(&prof.lock); if(prof.fn == nil) { - runtime·unlock(&prof); + runtime·unlock(&prof.lock); mp->mallocing--; return; } @@ -2341,7 +2341,7 @@ runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp) } } prof.fn(prof.pcbuf, n); - runtime·unlock(&prof); + runtime·unlock(&prof.lock); mp->mallocing--; } @@ -2366,13 +2366,13 @@ runtime·setcpuprofilerate(void (*fn)(uintptr*, int32), int32 hz) // it would deadlock. runtime·resetcpuprofiler(0); - runtime·lock(&prof); + runtime·lock(&prof.lock); prof.fn = fn; prof.hz = hz; - runtime·unlock(&prof); - runtime·lock(&runtime·sched); + runtime·unlock(&prof.lock); + runtime·lock(&runtime·sched.lock); runtime·sched.profilehz = hz; - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); if(hz != 0) runtime·resetcpuprofiler(hz); @@ -2510,11 +2510,11 @@ releasep(void) static void incidlelocked(int32 v) { - runtime·lock(&runtime·sched); + runtime·lock(&runtime·sched.lock); runtime·sched.nmidlelocked += v; if(v > 0) checkdead(); - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); } // Check for deadlock situation. @@ -2583,16 +2583,16 @@ sysmon(void) runtime·usleep(delay); if(runtime·debug.schedtrace <= 0 && (runtime·sched.gcwaiting || runtime·atomicload(&runtime·sched.npidle) == runtime·gomaxprocs)) { // TODO: fast atomic - runtime·lock(&runtime·sched); + runtime·lock(&runtime·sched.lock); if(runtime·atomicload(&runtime·sched.gcwaiting) || runtime·atomicload(&runtime·sched.npidle) == runtime·gomaxprocs) { runtime·atomicstore(&runtime·sched.sysmonwait, 1); - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); runtime·notesleep(&runtime·sched.sysmonnote); runtime·noteclear(&runtime·sched.sysmonnote); idle = 0; delay = 20; } else - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); } // poll network if not polled for more than 10ms lastpoll = runtime·atomicload64(&runtime·sched.lastpoll); @@ -2757,7 +2757,7 @@ runtime·schedtrace(bool detailed) if(starttime == 0) starttime = now; - runtime·lock(&runtime·sched); + runtime·lock(&runtime·sched.lock); runtime·printf("SCHED %Dms: gomaxprocs=%d idleprocs=%d threads=%d spinningthreads=%d idlethreads=%d runqueue=%d", (now-starttime)/1000000, runtime·gomaxprocs, runtime·sched.npidle, runtime·sched.mcount, runtime·sched.nmspinning, runtime·sched.nmidle, runtime·sched.runqsize); @@ -2793,7 +2793,7 @@ runtime·schedtrace(bool detailed) } } if(!detailed) { - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); return; } for(mp = runtime·allm; mp; mp = mp->alllink) { @@ -2825,7 +2825,7 @@ runtime·schedtrace(bool detailed) lockedm ? lockedm->id : -1); } runtime·unlock(&allglock); - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); } // Put mp on midle list. @@ -2981,9 +2981,9 @@ runqputslow(P *p, G *gp, uint32 h, uint32 t) for(i=0; ischedlink = batch[i+1]; // Now put the batch on global queue. - runtime·lock(&runtime·sched); + runtime·lock(&runtime·sched.lock); globrunqputbatch(batch[0], batch[n], n+1); - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); return true; } @@ -3146,11 +3146,11 @@ runtime·setmaxthreads(int32 in) { int32 out; - runtime·lock(&runtime·sched); + runtime·lock(&runtime·sched.lock); out = runtime·sched.maxmcount; runtime·sched.maxmcount = in; checkmcount(); - runtime·unlock(&runtime·sched); + runtime·unlock(&runtime·sched.lock); return out; } diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h index 1687b85c44..b85198f480 100644 --- a/src/pkg/runtime/runtime.h +++ b/src/pkg/runtime/runtime.h @@ -375,7 +375,7 @@ struct M struct P { - Lock; + Lock lock; int32 id; uint32 status; // one of Pidle/Prunning/... @@ -506,7 +506,7 @@ enum { struct Timers { - Lock; + Lock lock; G *timerproc; bool sleeping; bool rescheduling; diff --git a/src/pkg/runtime/sema.goc b/src/pkg/runtime/sema.goc index c1e8e4e18b..59a890c3e2 100644 --- a/src/pkg/runtime/sema.goc +++ b/src/pkg/runtime/sema.goc @@ -36,7 +36,7 @@ struct SemaWaiter typedef struct SemaRoot SemaRoot; struct SemaRoot { - Lock; + Lock lock; SemaWaiter* head; SemaWaiter* tail; // Number of waiters. Read w/o the lock. @@ -48,7 +48,7 @@ struct SemaRoot struct semtable { - SemaRoot; + SemaRoot root; uint8 pad[CacheLineSize-sizeof(SemaRoot)]; }; #pragma dataflag NOPTR /* mark semtable as 'no pointers', hiding from garbage collector */ @@ -57,7 +57,7 @@ static struct semtable semtable[SEMTABLESZ]; static SemaRoot* semroot(uint32 *addr) { - return &semtable[((uintptr)addr >> 3) % SEMTABLESZ]; + return &semtable[((uintptr)addr >> 3) % SEMTABLESZ].root; } static void @@ -125,19 +125,19 @@ runtime·semacquire(uint32 volatile *addr, bool profile) s.releasetime = -1; } for(;;) { - runtime·lock(root); + runtime·lock(&root->lock); // Add ourselves to nwait to disable "easy case" in semrelease. runtime·xadd(&root->nwait, 1); // Check cansemacquire to avoid missed wakeup. if(cansemacquire(addr)) { runtime·xadd(&root->nwait, -1); - runtime·unlock(root); + runtime·unlock(&root->lock); return; } // Any semrelease after the cansemacquire knows we're waiting // (we set nwait above), so go to sleep. semqueue(root, addr, &s); - runtime·parkunlock(root, "semacquire"); + runtime·parkunlock(&root->lock, "semacquire"); if(cansemacquire(addr)) { if(t0) runtime·blockevent(s.releasetime - t0, 3); @@ -162,11 +162,11 @@ runtime·semrelease(uint32 volatile *addr) return; // Harder case: search for a waiter and wake it. - runtime·lock(root); + runtime·lock(&root->lock); if(runtime·atomicload(&root->nwait) == 0) { // The count is already consumed by another goroutine, // so no need to wake up another goroutine. - runtime·unlock(root); + runtime·unlock(&root->lock); return; } for(s = root->head; s; s = s->next) { @@ -176,7 +176,7 @@ runtime·semrelease(uint32 volatile *addr) break; } } - runtime·unlock(root); + runtime·unlock(&root->lock); if(s) { if(s->releasetime) s->releasetime = runtime·cputicks(); @@ -206,7 +206,7 @@ func runtime_Semrelease(addr *uint32) { typedef struct SyncSema SyncSema; struct SyncSema { - Lock; + Lock lock; SemaWaiter* head; SemaWaiter* tail; }; @@ -233,7 +233,7 @@ func runtime_Syncsemacquire(s *SyncSema) { w.releasetime = -1; } - runtime·lock(s); + runtime·lock(&s->lock); if(s->head && s->head->nrelease > 0) { // have pending release, consume it wake = nil; @@ -244,7 +244,7 @@ func runtime_Syncsemacquire(s *SyncSema) { if(s->head == nil) s->tail = nil; } - runtime·unlock(s); + runtime·unlock(&s->lock); if(wake) runtime·ready(wake->g); } else { @@ -254,7 +254,7 @@ func runtime_Syncsemacquire(s *SyncSema) { else s->tail->next = &w; s->tail = &w; - runtime·parkunlock(s, "semacquire"); + runtime·parkunlock(&s->lock, "semacquire"); if(t0) runtime·blockevent(w.releasetime - t0, 2); } @@ -269,7 +269,7 @@ func runtime_Syncsemrelease(s *SyncSema, n uint32) { w.next = nil; w.releasetime = 0; - runtime·lock(s); + runtime·lock(&s->lock); while(w.nrelease > 0 && s->head && s->head->nrelease < 0) { // have pending acquire, satisfy it wake = s->head; @@ -288,7 +288,7 @@ func runtime_Syncsemrelease(s *SyncSema, n uint32) { else s->tail->next = &w; s->tail = &w; - runtime·parkunlock(s, "semarelease"); + runtime·parkunlock(&s->lock, "semarelease"); } else - runtime·unlock(s); + runtime·unlock(&s->lock); } diff --git a/src/pkg/runtime/sigqueue.goc b/src/pkg/runtime/sigqueue.goc index 376e77a2e4..fa0eb51a1c 100644 --- a/src/pkg/runtime/sigqueue.goc +++ b/src/pkg/runtime/sigqueue.goc @@ -33,7 +33,7 @@ package runtime #pragma textflag NOPTR static struct { - Note; + Note note; uint32 mask[(NSIG+31)/32]; uint32 wanted[(NSIG+31)/32]; uint32 recv[(NSIG+31)/32]; @@ -72,7 +72,7 @@ runtime·sigsend(int32 s) new = HASSIGNAL; if(runtime·cas(&sig.state, old, new)) { if (old == HASWAITER) - runtime·notewakeup(&sig); + runtime·notewakeup(&sig.note); break; } } @@ -108,8 +108,8 @@ func signal_recv() (m uint32) { new = HASWAITER; if(runtime·cas(&sig.state, old, new)) { if (new == HASWAITER) { - runtime·notetsleepg(&sig, -1); - runtime·noteclear(&sig); + runtime·notetsleepg(&sig.note, -1); + runtime·noteclear(&sig.note); } break; } @@ -139,7 +139,7 @@ func signal_enable(s uint32) { // to use for initialization. It does not pass // signal information in m. sig.inuse = true; // enable reception of signals; cannot disable - runtime·noteclear(&sig); + runtime·noteclear(&sig.note); return; } diff --git a/src/pkg/runtime/time.goc b/src/pkg/runtime/time.goc index 10b8cea0ab..fa25671e6e 100644 --- a/src/pkg/runtime/time.goc +++ b/src/pkg/runtime/time.goc @@ -92,9 +92,9 @@ runtime·tsleep(int64 ns, int8 *reason) t.period = 0; t.fv = &readyv; t.arg.data = g; - runtime·lock(&timers); + runtime·lock(&timers.lock); addtimer(&t); - runtime·parkunlock(&timers, reason); + runtime·parkunlock(&timers.lock, reason); } static FuncVal timerprocv = {timerproc}; @@ -102,9 +102,9 @@ static FuncVal timerprocv = {timerproc}; void runtime·addtimer(Timer *t) { - runtime·lock(&timers); + runtime·lock(&timers.lock); addtimer(t); - runtime·unlock(&timers); + runtime·unlock(&timers.lock); } // Add a timer to the heap and start or kick the timer proc @@ -165,14 +165,14 @@ runtime·deltimer(Timer *t) i = t->i; USED(i); - runtime·lock(&timers); + runtime·lock(&timers.lock); // t may not be registered anymore and may have // a bogus i (typically 0, if generated by Go). // Verify it before proceeding. i = t->i; if(i < 0 || i >= timers.len || timers.t[i] != t) { - runtime·unlock(&timers); + runtime·unlock(&timers.lock); return false; } @@ -188,7 +188,7 @@ runtime·deltimer(Timer *t) } if(debug) dumptimers("deltimer"); - runtime·unlock(&timers); + runtime·unlock(&timers.lock); return true; } @@ -205,7 +205,7 @@ timerproc(void) Eface arg; for(;;) { - runtime·lock(&timers); + runtime·lock(&timers.lock); timers.sleeping = false; now = runtime·nanotime(); for(;;) { @@ -230,7 +230,7 @@ timerproc(void) } f = (void*)t->fv->fn; arg = t->arg; - runtime·unlock(&timers); + runtime·unlock(&timers.lock); if(raceenabled) runtime·raceacquire(t); f(now, arg); @@ -242,20 +242,20 @@ timerproc(void) arg.data = nil; USED(&arg); - runtime·lock(&timers); + runtime·lock(&timers.lock); } if(delta < 0) { // No timers left - put goroutine to sleep. timers.rescheduling = true; g->isbackground = true; - runtime·parkunlock(&timers, "timer goroutine (idle)"); + runtime·parkunlock(&timers.lock, "timer goroutine (idle)"); g->isbackground = false; continue; } // At least one timer pending. Sleep until then. timers.sleeping = true; runtime·noteclear(&timers.waitnote); - runtime·unlock(&timers); + runtime·unlock(&timers.lock); runtime·notetsleepg(&timers.waitnote, delta); } } diff --git a/src/pkg/runtime/type.h b/src/pkg/runtime/type.h index 2eda291aed..1da37323eb 100644 --- a/src/pkg/runtime/type.h +++ b/src/pkg/runtime/type.h @@ -66,14 +66,14 @@ struct IMethod struct InterfaceType { - Type; + Type typ; Slice mhdr; IMethod m[]; }; struct MapType { - Type; + Type typ; Type *key; Type *elem; Type *bucket; // internal type representing a hash bucket @@ -87,20 +87,20 @@ struct MapType struct ChanType { - Type; + Type typ; Type *elem; uintptr dir; }; struct SliceType { - Type; + Type typ; Type *elem; }; struct FuncType { - Type; + Type typ; bool dotdotdot; Slice in; Slice out; @@ -108,6 +108,6 @@ struct FuncType struct PtrType { - Type; + Type typ; Type *elem; }; diff --git a/src/pkg/runtime/vlrt_386.c b/src/pkg/runtime/vlrt_386.c index ace1beb4cc..bda67b1575 100644 --- a/src/pkg/runtime/vlrt_386.c +++ b/src/pkg/runtime/vlrt_386.c @@ -42,25 +42,15 @@ typedef signed char schar; #define SIGN(n) (1UL<<(n-1)) -typedef struct Vlong Vlong; -struct Vlong +typedef union Vlong Vlong; +union Vlong { - union + long long v; + struct { - long long v; - struct - { - ulong lo; - ulong hi; - }; - struct - { - ushort lols; - ushort loms; - ushort hils; - ushort hims; - }; - }; + ulong lo; + ulong hi; + } v2; }; void runtime·abort(void); @@ -68,15 +58,15 @@ void runtime·abort(void); void _d2v(Vlong *y, double d) { - union { double d; struct Vlong; } x; + union { double d; Vlong vl; } x; ulong xhi, xlo, ylo, yhi; int sh; x.d = d; - xhi = (x.hi & 0xfffff) | 0x100000; - xlo = x.lo; - sh = 1075 - ((x.hi >> 20) & 0x7ff); + xhi = (x.vl.v2.hi & 0xfffff) | 0x100000; + xlo = x.vl.v2.lo; + sh = 1075 - ((x.vl.v2.hi >> 20) & 0x7ff); ylo = 0; yhi = 0; @@ -109,7 +99,7 @@ _d2v(Vlong *y, double d) yhi = d; /* causes something awful */ } } - if(x.hi & SIGN(32)) { + if(x.vl.v2.hi & SIGN(32)) { if(ylo != 0) { ylo = -ylo; yhi = ~yhi; @@ -117,8 +107,8 @@ _d2v(Vlong *y, double d) yhi = -yhi; } - y->hi = yhi; - y->lo = ylo; + y->v2.hi = yhi; + y->v2.lo = ylo; } void @@ -131,15 +121,15 @@ _f2v(Vlong *y, float f) double _v2d(Vlong x) { - if(x.hi & SIGN(32)) { - if(x.lo) { - x.lo = -x.lo; - x.hi = ~x.hi; + if(x.v2.hi & SIGN(32)) { + if(x.v2.lo) { + x.v2.lo = -x.v2.lo; + x.v2.hi = ~x.v2.hi; } else - x.hi = -x.hi; - return -((long)x.hi*4294967296. + x.lo); + x.v2.hi = -x.v2.hi; + return -((long)x.v2.hi*4294967296. + x.v2.lo); } - return (long)x.hi*4294967296. + x.lo; + return (long)x.v2.hi*4294967296. + x.v2.lo; } float @@ -157,10 +147,10 @@ slowdodiv(Vlong num, Vlong den, Vlong *q, Vlong *r) ulong numlo, numhi, denhi, denlo, quohi, quolo, t; int i; - numhi = num.hi; - numlo = num.lo; - denhi = den.hi; - denlo = den.lo; + numhi = num.v2.hi; + numlo = num.v2.lo; + denhi = den.v2.hi; + denlo = den.v2.lo; /* * get a divide by zero @@ -204,12 +194,12 @@ slowdodiv(Vlong num, Vlong den, Vlong *q, Vlong *r) } if(q) { - q->lo = quolo; - q->hi = quohi; + q->v2.lo = quolo; + q->v2.hi = quohi; } if(r) { - r->lo = numlo; - r->hi = numhi; + r->v2.lo = numlo; + r->v2.hi = numhi; } } @@ -219,46 +209,46 @@ dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp) ulong n; Vlong x, q, r; - if(den.hi > num.hi || (den.hi == num.hi && den.lo > num.lo)){ + if(den.v2.hi > num.v2.hi || (den.v2.hi == num.v2.hi && den.v2.lo > num.v2.lo)){ if(qp) { - qp->hi = 0; - qp->lo = 0; + qp->v2.hi = 0; + qp->v2.lo = 0; } if(rp) { - rp->hi = num.hi; - rp->lo = num.lo; + rp->v2.hi = num.v2.hi; + rp->v2.lo = num.v2.lo; } return; } - if(den.hi != 0){ - q.hi = 0; - n = num.hi/den.hi; - if(_mul64by32(&x, den, n) || x.hi > num.hi || (x.hi == num.hi && x.lo > num.lo)) + if(den.v2.hi != 0){ + q.v2.hi = 0; + n = num.v2.hi/den.v2.hi; + if(_mul64by32(&x, den, n) || x.v2.hi > num.v2.hi || (x.v2.hi == num.v2.hi && x.v2.lo > num.v2.lo)) slowdodiv(num, den, &q, &r); else { - q.lo = n; + q.v2.lo = n; r.v = num.v - x.v; } } else { - if(num.hi >= den.lo){ - if(den.lo == 0) + if(num.v2.hi >= den.v2.lo){ + if(den.v2.lo == 0) runtime·panicdivide(); - q.hi = n = num.hi/den.lo; - num.hi -= den.lo*n; + q.v2.hi = n = num.v2.hi/den.v2.lo; + num.v2.hi -= den.v2.lo*n; } else { - q.hi = 0; + q.v2.hi = 0; } - q.lo = _div64by32(num, den.lo, &r.lo); - r.hi = 0; + q.v2.lo = _div64by32(num, den.v2.lo, &r.v2.lo); + r.v2.hi = 0; } if(qp) { - qp->lo = q.lo; - qp->hi = q.hi; + qp->v2.lo = q.v2.lo; + qp->v2.hi = q.v2.hi; } if(rp) { - rp->lo = r.lo; - rp->hi = r.hi; + rp->v2.lo = r.v2.lo; + rp->v2.hi = r.v2.hi; } } @@ -266,11 +256,11 @@ void _divvu(Vlong *q, Vlong n, Vlong d) { - if(n.hi == 0 && d.hi == 0) { - if(d.lo == 0) + if(n.v2.hi == 0 && d.v2.hi == 0) { + if(d.v2.lo == 0) runtime·panicdivide(); - q->hi = 0; - q->lo = n.lo / d.lo; + q->v2.hi = 0; + q->v2.lo = n.v2.lo / d.v2.lo; return; } dodiv(n, d, q, 0); @@ -286,11 +276,11 @@ void _modvu(Vlong *r, Vlong n, Vlong d) { - if(n.hi == 0 && d.hi == 0) { - if(d.lo == 0) + if(n.v2.hi == 0 && d.v2.hi == 0) { + if(d.v2.lo == 0) runtime·panicdivide(); - r->hi = 0; - r->lo = n.lo % d.lo; + r->v2.hi = 0; + r->v2.lo = n.v2.lo % d.v2.lo; return; } dodiv(n, d, 0, r); @@ -306,12 +296,12 @@ static void vneg(Vlong *v) { - if(v->lo == 0) { - v->hi = -v->hi; + if(v->v2.lo == 0) { + v->v2.hi = -v->v2.hi; return; } - v->lo = -v->lo; - v->hi = ~v->hi; + v->v2.lo = -v->v2.lo; + v->v2.hi = ~v->v2.hi; } void @@ -319,24 +309,24 @@ _divv(Vlong *q, Vlong n, Vlong d) { long nneg, dneg; - if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) { - if((long)n.lo == -0x80000000 && (long)d.lo == -1) { + if(n.v2.hi == (((long)n.v2.lo)>>31) && d.v2.hi == (((long)d.v2.lo)>>31)) { + if((long)n.v2.lo == -0x80000000 && (long)d.v2.lo == -1) { // special case: 32-bit -0x80000000 / -1 causes divide error, // but it's okay in this 64-bit context. - q->lo = 0x80000000; - q->hi = 0; + q->v2.lo = 0x80000000; + q->v2.hi = 0; return; } - if(d.lo == 0) + if(d.v2.lo == 0) runtime·panicdivide(); - q->lo = (long)n.lo / (long)d.lo; - q->hi = ((long)q->lo) >> 31; + q->v2.lo = (long)n.v2.lo / (long)d.v2.lo; + q->v2.hi = ((long)q->v2.lo) >> 31; return; } - nneg = n.hi >> 31; + nneg = n.v2.hi >> 31; if(nneg) vneg(&n); - dneg = d.hi >> 31; + dneg = d.v2.hi >> 31; if(dneg) vneg(&d); dodiv(n, d, q, 0); @@ -355,24 +345,24 @@ _modv(Vlong *r, Vlong n, Vlong d) { long nneg, dneg; - if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) { - if((long)n.lo == -0x80000000 && (long)d.lo == -1) { + if(n.v2.hi == (((long)n.v2.lo)>>31) && d.v2.hi == (((long)d.v2.lo)>>31)) { + if((long)n.v2.lo == -0x80000000 && (long)d.v2.lo == -1) { // special case: 32-bit -0x80000000 % -1 causes divide error, // but it's okay in this 64-bit context. - r->lo = 0; - r->hi = 0; + r->v2.lo = 0; + r->v2.hi = 0; return; } - if(d.lo == 0) + if(d.v2.lo == 0) runtime·panicdivide(); - r->lo = (long)n.lo % (long)d.lo; - r->hi = ((long)r->lo) >> 31; + r->v2.lo = (long)n.v2.lo % (long)d.v2.lo; + r->v2.hi = ((long)r->v2.lo) >> 31; return; } - nneg = n.hi >> 31; + nneg = n.v2.hi >> 31; if(nneg) vneg(&n); - dneg = d.hi >> 31; + dneg = d.v2.hi >> 31; if(dneg) vneg(&d); dodiv(n, d, 0, r); @@ -391,24 +381,24 @@ _rshav(Vlong *r, Vlong a, int b) { long t; - t = a.hi; + t = a.v2.hi; if(b >= 32) { - r->hi = t>>31; + r->v2.hi = t>>31; if(b >= 64) { /* this is illegal re C standard */ - r->lo = t>>31; + r->v2.lo = t>>31; return; } - r->lo = t >> (b-32); + r->v2.lo = t >> (b-32); return; } if(b <= 0) { - r->hi = t; - r->lo = a.lo; + r->v2.hi = t; + r->v2.lo = a.v2.lo; return; } - r->hi = t >> b; - r->lo = (t << (32-b)) | (a.lo >> b); + r->v2.hi = t >> b; + r->v2.lo = (t << (32-b)) | (a.v2.lo >> b); } void @@ -416,24 +406,24 @@ _rshlv(Vlong *r, Vlong a, int b) { ulong t; - t = a.hi; + t = a.v2.hi; if(b >= 32) { - r->hi = 0; + r->v2.hi = 0; if(b >= 64) { /* this is illegal re C standard */ - r->lo = 0; + r->v2.lo = 0; return; } - r->lo = t >> (b-32); + r->v2.lo = t >> (b-32); return; } if(b <= 0) { - r->hi = t; - r->lo = a.lo; + r->v2.hi = t; + r->v2.lo = a.v2.lo; return; } - r->hi = t >> b; - r->lo = (t << (32-b)) | (a.lo >> b); + r->v2.hi = t >> b; + r->v2.lo = (t << (32-b)) | (a.v2.lo >> b); } #pragma textflag NOSPLIT @@ -442,89 +432,89 @@ _lshv(Vlong *r, Vlong a, int b) { ulong t; - t = a.lo; + t = a.v2.lo; if(b >= 32) { - r->lo = 0; + r->v2.lo = 0; if(b >= 64) { /* this is illegal re C standard */ - r->hi = 0; + r->v2.hi = 0; return; } - r->hi = t << (b-32); + r->v2.hi = t << (b-32); return; } if(b <= 0) { - r->lo = t; - r->hi = a.hi; + r->v2.lo = t; + r->v2.hi = a.v2.hi; return; } - r->lo = t << b; - r->hi = (t >> (32-b)) | (a.hi << b); + r->v2.lo = t << b; + r->v2.hi = (t >> (32-b)) | (a.v2.hi << b); } void _andv(Vlong *r, Vlong a, Vlong b) { - r->hi = a.hi & b.hi; - r->lo = a.lo & b.lo; + r->v2.hi = a.v2.hi & b.v2.hi; + r->v2.lo = a.v2.lo & b.v2.lo; } void _orv(Vlong *r, Vlong a, Vlong b) { - r->hi = a.hi | b.hi; - r->lo = a.lo | b.lo; + r->v2.hi = a.v2.hi | b.v2.hi; + r->v2.lo = a.v2.lo | b.v2.lo; } void _xorv(Vlong *r, Vlong a, Vlong b) { - r->hi = a.hi ^ b.hi; - r->lo = a.lo ^ b.lo; + r->v2.hi = a.v2.hi ^ b.v2.hi; + r->v2.lo = a.v2.lo ^ b.v2.lo; } void _vpp(Vlong *l, Vlong *r) { - l->hi = r->hi; - l->lo = r->lo; - r->lo++; - if(r->lo == 0) - r->hi++; + l->v2.hi = r->v2.hi; + l->v2.lo = r->v2.lo; + r->v2.lo++; + if(r->v2.lo == 0) + r->v2.hi++; } void _vmm(Vlong *l, Vlong *r) { - l->hi = r->hi; - l->lo = r->lo; - if(r->lo == 0) - r->hi--; - r->lo--; + l->v2.hi = r->v2.hi; + l->v2.lo = r->v2.lo; + if(r->v2.lo == 0) + r->v2.hi--; + r->v2.lo--; } void _ppv(Vlong *l, Vlong *r) { - r->lo++; - if(r->lo == 0) - r->hi++; - l->hi = r->hi; - l->lo = r->lo; + r->v2.lo++; + if(r->v2.lo == 0) + r->v2.hi++; + l->v2.hi = r->v2.hi; + l->v2.lo = r->v2.lo; } void _mmv(Vlong *l, Vlong *r) { - if(r->lo == 0) - r->hi--; - r->lo--; - l->hi = r->hi; - l->lo = r->lo; + if(r->v2.lo == 0) + r->v2.hi--; + r->v2.lo--; + l->v2.hi = r->v2.hi; + l->v2.lo = r->v2.lo; } void @@ -532,67 +522,67 @@ _vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv) { Vlong t, u; - u.lo = 0; - u.hi = 0; + u.v2.lo = 0; + u.v2.hi = 0; switch(type) { default: runtime·abort(); break; case 1: /* schar */ - t.lo = *(schar*)lv; - t.hi = t.lo >> 31; + t.v2.lo = *(schar*)lv; + t.v2.hi = t.v2.lo >> 31; fn(&u, t, rv); - *(schar*)lv = u.lo; + *(schar*)lv = u.v2.lo; break; case 2: /* uchar */ - t.lo = *(uchar*)lv; - t.hi = 0; + t.v2.lo = *(uchar*)lv; + t.v2.hi = 0; fn(&u, t, rv); - *(uchar*)lv = u.lo; + *(uchar*)lv = u.v2.lo; break; case 3: /* short */ - t.lo = *(short*)lv; - t.hi = t.lo >> 31; + t.v2.lo = *(short*)lv; + t.v2.hi = t.v2.lo >> 31; fn(&u, t, rv); - *(short*)lv = u.lo; + *(short*)lv = u.v2.lo; break; case 4: /* ushort */ - t.lo = *(ushort*)lv; - t.hi = 0; + t.v2.lo = *(ushort*)lv; + t.v2.hi = 0; fn(&u, t, rv); - *(ushort*)lv = u.lo; + *(ushort*)lv = u.v2.lo; break; case 9: /* int */ - t.lo = *(int*)lv; - t.hi = t.lo >> 31; + t.v2.lo = *(int*)lv; + t.v2.hi = t.v2.lo >> 31; fn(&u, t, rv); - *(int*)lv = u.lo; + *(int*)lv = u.v2.lo; break; case 10: /* uint */ - t.lo = *(uint*)lv; - t.hi = 0; + t.v2.lo = *(uint*)lv; + t.v2.hi = 0; fn(&u, t, rv); - *(uint*)lv = u.lo; + *(uint*)lv = u.v2.lo; break; case 5: /* long */ - t.lo = *(long*)lv; - t.hi = t.lo >> 31; + t.v2.lo = *(long*)lv; + t.v2.hi = t.v2.lo >> 31; fn(&u, t, rv); - *(long*)lv = u.lo; + *(long*)lv = u.v2.lo; break; case 6: /* ulong */ - t.lo = *(ulong*)lv; - t.hi = 0; + t.v2.lo = *(ulong*)lv; + t.v2.hi = 0; fn(&u, t, rv); - *(ulong*)lv = u.lo; + *(ulong*)lv = u.v2.lo; break; case 7: /* vlong */ @@ -610,8 +600,8 @@ _p2v(Vlong *ret, void *p) long t; t = (ulong)p; - ret->lo = t; - ret->hi = 0; + ret->v2.lo = t; + ret->v2.hi = 0; } void @@ -620,8 +610,8 @@ _sl2v(Vlong *ret, long sl) long t; t = sl; - ret->lo = t; - ret->hi = t >> 31; + ret->v2.lo = t; + ret->v2.hi = t >> 31; } void @@ -630,8 +620,8 @@ _ul2v(Vlong *ret, ulong ul) long t; t = ul; - ret->lo = t; - ret->hi = 0; + ret->v2.lo = t; + ret->v2.hi = 0; } void @@ -640,8 +630,8 @@ _si2v(Vlong *ret, int si) long t; t = si; - ret->lo = t; - ret->hi = t >> 31; + ret->v2.lo = t; + ret->v2.hi = t >> 31; } void @@ -650,8 +640,8 @@ _ui2v(Vlong *ret, uint ui) long t; t = ui; - ret->lo = t; - ret->hi = 0; + ret->v2.lo = t; + ret->v2.hi = 0; } void @@ -660,8 +650,8 @@ _sh2v(Vlong *ret, long sh) long t; t = (sh << 16) >> 16; - ret->lo = t; - ret->hi = t >> 31; + ret->v2.lo = t; + ret->v2.hi = t >> 31; } void @@ -670,8 +660,8 @@ _uh2v(Vlong *ret, ulong ul) long t; t = ul & 0xffff; - ret->lo = t; - ret->hi = 0; + ret->v2.lo = t; + ret->v2.hi = 0; } void @@ -680,8 +670,8 @@ _sc2v(Vlong *ret, long uc) long t; t = (uc << 24) >> 24; - ret->lo = t; - ret->hi = t >> 31; + ret->v2.lo = t; + ret->v2.hi = t >> 31; } void @@ -690,8 +680,8 @@ _uc2v(Vlong *ret, ulong ul) long t; t = ul & 0xff; - ret->lo = t; - ret->hi = 0; + ret->v2.lo = t; + ret->v2.hi = 0; } long @@ -699,7 +689,7 @@ _v2sc(Vlong rv) { long t; - t = rv.lo & 0xff; + t = rv.v2.lo & 0xff; return (t << 24) >> 24; } @@ -707,7 +697,7 @@ long _v2uc(Vlong rv) { - return rv.lo & 0xff; + return rv.v2.lo & 0xff; } long @@ -715,7 +705,7 @@ _v2sh(Vlong rv) { long t; - t = rv.lo & 0xffff; + t = rv.v2.lo & 0xffff; return (t << 16) >> 16; } @@ -723,107 +713,107 @@ long _v2uh(Vlong rv) { - return rv.lo & 0xffff; + return rv.v2.lo & 0xffff; } long _v2sl(Vlong rv) { - return rv.lo; + return rv.v2.lo; } long _v2ul(Vlong rv) { - return rv.lo; + return rv.v2.lo; } long _v2si(Vlong rv) { - return rv.lo; + return rv.v2.lo; } long _v2ui(Vlong rv) { - return rv.lo; + return rv.v2.lo; } int _testv(Vlong rv) { - return rv.lo || rv.hi; + return rv.v2.lo || rv.v2.hi; } int _eqv(Vlong lv, Vlong rv) { - return lv.lo == rv.lo && lv.hi == rv.hi; + return lv.v2.lo == rv.v2.lo && lv.v2.hi == rv.v2.hi; } int _nev(Vlong lv, Vlong rv) { - return lv.lo != rv.lo || lv.hi != rv.hi; + return lv.v2.lo != rv.v2.lo || lv.v2.hi != rv.v2.hi; } int _ltv(Vlong lv, Vlong rv) { - return (long)lv.hi < (long)rv.hi || - (lv.hi == rv.hi && lv.lo < rv.lo); + return (long)lv.v2.hi < (long)rv.v2.hi || + (lv.v2.hi == rv.v2.hi && lv.v2.lo < rv.v2.lo); } int _lev(Vlong lv, Vlong rv) { - return (long)lv.hi < (long)rv.hi || - (lv.hi == rv.hi && lv.lo <= rv.lo); + return (long)lv.v2.hi < (long)rv.v2.hi || + (lv.v2.hi == rv.v2.hi && lv.v2.lo <= rv.v2.lo); } int _gtv(Vlong lv, Vlong rv) { - return (long)lv.hi > (long)rv.hi || - (lv.hi == rv.hi && lv.lo > rv.lo); + return (long)lv.v2.hi > (long)rv.v2.hi || + (lv.v2.hi == rv.v2.hi && lv.v2.lo > rv.v2.lo); } int _gev(Vlong lv, Vlong rv) { - return (long)lv.hi > (long)rv.hi || - (lv.hi == rv.hi && lv.lo >= rv.lo); + return (long)lv.v2.hi > (long)rv.v2.hi || + (lv.v2.hi == rv.v2.hi && lv.v2.lo >= rv.v2.lo); } int _lov(Vlong lv, Vlong rv) { - return lv.hi < rv.hi || - (lv.hi == rv.hi && lv.lo < rv.lo); + return lv.v2.hi < rv.v2.hi || + (lv.v2.hi == rv.v2.hi && lv.v2.lo < rv.v2.lo); } int _lsv(Vlong lv, Vlong rv) { - return lv.hi < rv.hi || - (lv.hi == rv.hi && lv.lo <= rv.lo); + return lv.v2.hi < rv.v2.hi || + (lv.v2.hi == rv.v2.hi && lv.v2.lo <= rv.v2.lo); } int _hiv(Vlong lv, Vlong rv) { - return lv.hi > rv.hi || - (lv.hi == rv.hi && lv.lo > rv.lo); + return lv.v2.hi > rv.v2.hi || + (lv.v2.hi == rv.v2.hi && lv.v2.lo > rv.v2.lo); } int _hsv(Vlong lv, Vlong rv) { - return lv.hi > rv.hi || - (lv.hi == rv.hi && lv.lo >= rv.lo); + return lv.v2.hi > rv.v2.hi || + (lv.v2.hi == rv.v2.hi && lv.v2.lo >= rv.v2.lo); } diff --git a/src/pkg/runtime/vlrt_arm.c b/src/pkg/runtime/vlrt_arm.c index 016fd7a357..48ae08be32 100644 --- a/src/pkg/runtime/vlrt_arm.c +++ b/src/pkg/runtime/vlrt_arm.c @@ -40,21 +40,8 @@ typedef signed char schar; typedef struct Vlong Vlong; struct Vlong { - union - { - struct - { - ulong lo; - ulong hi; - }; - struct - { - ushort lols; - ushort loms; - ushort hils; - ushort hims; - }; - }; + ulong lo; + ulong hi; }; void runtime·abort(void); @@ -82,15 +69,15 @@ _subv(Vlong *r, Vlong a, Vlong b) void _d2v(Vlong *y, double d) { - union { double d; struct Vlong; } x; + union { double d; Vlong vl; } x; ulong xhi, xlo, ylo, yhi; int sh; x.d = d; - xhi = (x.hi & 0xfffff) | 0x100000; - xlo = x.lo; - sh = 1075 - ((x.hi >> 20) & 0x7ff); + xhi = (x.vl.hi & 0xfffff) | 0x100000; + xlo = x.vl.lo; + sh = 1075 - ((x.vl.hi >> 20) & 0x7ff); ylo = 0; yhi = 0; @@ -123,7 +110,7 @@ _d2v(Vlong *y, double d) yhi = d; /* causes something awful */ } } - if(x.hi & SIGN(32)) { + if(x.vl.hi & SIGN(32)) { if(ylo != 0) { ylo = -ylo; yhi = ~yhi; From fad69a7b77a7996b0308bdbcd559b78b32046bb3 Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Thu, 7 Aug 2014 23:24:32 +1000 Subject: [PATCH 023/423] cmd/fix: mention -help instead of the non-existent -? flag Update #8314 TBR=r R=golang-codereviews CC=golang-codereviews https://golang.org/cl/123890043 --- src/cmd/fix/doc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/fix/doc.go b/src/cmd/fix/doc.go index 5de3e08c59..0570169576 100644 --- a/src/cmd/fix/doc.go +++ b/src/cmd/fix/doc.go @@ -27,7 +27,7 @@ rewrites are idempotent, so that it is safe to apply fix to updated or partially updated code even without using the -r flag. Fix prints the full list of fixes it can apply in its help output; -to see them, run go tool fix -?. +to see them, run go tool fix -help. Fix does not make backup copies of the files that it edits. Instead, use a version control system's ``diff'' functionality to inspect From 08033f9816e1e33092c93c050dc34514d8e3e926 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 7 Aug 2014 12:33:06 -0400 Subject: [PATCH 024/423] cmd/addr2line, cmd/nm: factor object reading into cmd/internal/objfile To do in another CL: make cmd/objdump use cmd/internal/objfile too. There is a package placement decision in this CL: cmd/internal/objfile instead of internal/objfile. I chose to put internal under cmd to make clear (and enforce) that no standard library packages should use this (it's a bit dependency-heavy). LGTM=r R=r CC=golang-codereviews https://golang.org/cl/123910043 --- src/cmd/addr2line/main.go | 159 +-------------------- src/cmd/{nm => internal/objfile}/elf.go | 48 +++++-- src/cmd/{nm => internal/objfile}/goobj.go | 35 +++-- src/cmd/{nm => internal/objfile}/macho.go | 53 +++++-- src/cmd/internal/objfile/objfile.go | 72 ++++++++++ src/cmd/internal/objfile/pe.go | 161 ++++++++++++++++++++++ src/cmd/internal/objfile/plan9obj.go | 100 ++++++++++++++ src/cmd/nm/nm.go | 57 ++------ src/cmd/nm/nm_test.go | 4 +- src/cmd/nm/pe.go | 98 ------------- src/cmd/nm/plan9obj.go | 48 ------- 11 files changed, 448 insertions(+), 387 deletions(-) rename src/cmd/{nm => internal/objfile}/elf.go (52%) rename src/cmd/{nm => internal/objfile}/goobj.go (72%) rename src/cmd/{nm => internal/objfile}/macho.go (55%) create mode 100644 src/cmd/internal/objfile/objfile.go create mode 100644 src/cmd/internal/objfile/pe.go create mode 100644 src/cmd/internal/objfile/plan9obj.go delete mode 100644 src/cmd/nm/pe.go delete mode 100644 src/cmd/nm/plan9obj.go diff --git a/src/cmd/addr2line/main.go b/src/cmd/addr2line/main.go index 3802f764f9..267f4170a8 100644 --- a/src/cmd/addr2line/main.go +++ b/src/cmd/addr2line/main.go @@ -19,17 +19,14 @@ package main import ( "bufio" - "debug/elf" - "debug/gosym" - "debug/macho" - "debug/pe" - "debug/plan9obj" "flag" "fmt" "log" "os" "strconv" "strings" + + "cmd/internal/objfile" ) func printUsage(w *os.File) { @@ -60,18 +57,12 @@ func main() { usage() } - f, err := os.Open(flag.Arg(0)) + f, err := objfile.Open(flag.Arg(0)) if err != nil { log.Fatal(err) } - textStart, symtab, pclntab, err := loadTables(f) - if err != nil { - log.Fatalf("reading %s: %v", flag.Arg(0), err) - } - - pcln := gosym.NewLineTable(pclntab, textStart) - tab, err := gosym.NewTable(symtab, pcln) + tab, err := f.PCLineTable() if err != nil { log.Fatalf("reading %s: %v", flag.Arg(0), err) } @@ -102,145 +93,3 @@ func main() { } stdout.Flush() } - -func loadTables(f *os.File) (textStart uint64, symtab, pclntab []byte, err error) { - if obj, err := elf.NewFile(f); err == nil { - if sect := obj.Section(".text"); sect != nil { - textStart = sect.Addr - } - if sect := obj.Section(".gosymtab"); sect != nil { - if symtab, err = sect.Data(); err != nil { - return 0, nil, nil, err - } - } - if sect := obj.Section(".gopclntab"); sect != nil { - if pclntab, err = sect.Data(); err != nil { - return 0, nil, nil, err - } - } - return textStart, symtab, pclntab, nil - } - - if obj, err := macho.NewFile(f); err == nil { - if sect := obj.Section("__text"); sect != nil { - textStart = sect.Addr - } - if sect := obj.Section("__gosymtab"); sect != nil { - if symtab, err = sect.Data(); err != nil { - return 0, nil, nil, err - } - } - if sect := obj.Section("__gopclntab"); sect != nil { - if pclntab, err = sect.Data(); err != nil { - return 0, nil, nil, err - } - } - return textStart, symtab, pclntab, nil - } - - if obj, err := pe.NewFile(f); err == nil { - var imageBase uint64 - switch oh := obj.OptionalHeader.(type) { - case *pe.OptionalHeader32: - imageBase = uint64(oh.ImageBase) - case *pe.OptionalHeader64: - imageBase = oh.ImageBase - default: - return 0, nil, nil, fmt.Errorf("pe file format not recognized") - } - if sect := obj.Section(".text"); sect != nil { - textStart = imageBase + uint64(sect.VirtualAddress) - } - if pclntab, err = loadPETable(obj, "pclntab", "epclntab"); err != nil { - return 0, nil, nil, err - } - if symtab, err = loadPETable(obj, "symtab", "esymtab"); err != nil { - return 0, nil, nil, err - } - return textStart, symtab, pclntab, nil - } - - if obj, err := plan9obj.NewFile(f); err == nil { - textStart = obj.LoadAddress + obj.HdrSize - if pclntab, err = loadPlan9Table(obj, "pclntab", "epclntab"); err != nil { - return 0, nil, nil, err - } - if symtab, err = loadPlan9Table(obj, "symtab", "esymtab"); err != nil { - return 0, nil, nil, err - } - return textStart, symtab, pclntab, nil - } - - return 0, nil, nil, fmt.Errorf("unrecognized binary format") -} - -func findPESymbol(f *pe.File, name string) (*pe.Symbol, error) { - for _, s := range f.Symbols { - if s.Name != name { - continue - } - if s.SectionNumber <= 0 { - return nil, fmt.Errorf("symbol %s: invalid section number %d", name, s.SectionNumber) - } - if len(f.Sections) < int(s.SectionNumber) { - return nil, fmt.Errorf("symbol %s: section number %d is larger than max %d", name, s.SectionNumber, len(f.Sections)) - } - return s, nil - } - return nil, fmt.Errorf("no %s symbol found", name) -} - -func loadPETable(f *pe.File, sname, ename string) ([]byte, error) { - ssym, err := findPESymbol(f, sname) - if err != nil { - return nil, err - } - esym, err := findPESymbol(f, ename) - if err != nil { - return nil, err - } - if ssym.SectionNumber != esym.SectionNumber { - return nil, fmt.Errorf("%s and %s symbols must be in the same section", sname, ename) - } - sect := f.Sections[ssym.SectionNumber-1] - data, err := sect.Data() - if err != nil { - return nil, err - } - return data[ssym.Value:esym.Value], nil -} - -func findPlan9Symbol(f *plan9obj.File, name string) (*plan9obj.Sym, error) { - syms, err := f.Symbols() - if err != nil { - return nil, err - } - for _, s := range syms { - if s.Name != name { - continue - } - return &s, nil - } - return nil, fmt.Errorf("no %s symbol found", name) -} - -func loadPlan9Table(f *plan9obj.File, sname, ename string) ([]byte, error) { - ssym, err := findPlan9Symbol(f, sname) - if err != nil { - return nil, err - } - esym, err := findPlan9Symbol(f, ename) - if err != nil { - return nil, err - } - sect := f.Section("text") - if sect == nil { - return nil, err - } - data, err := sect.Data() - if err != nil { - return nil, err - } - textStart := f.LoadAddress + f.HdrSize - return data[ssym.Value-textStart : esym.Value-textStart], nil -} diff --git a/src/cmd/nm/elf.go b/src/cmd/internal/objfile/elf.go similarity index 52% rename from src/cmd/nm/elf.go rename to src/cmd/internal/objfile/elf.go index 5aaa194dd1..8495fa7532 100644 --- a/src/cmd/nm/elf.go +++ b/src/cmd/internal/objfile/elf.go @@ -4,24 +4,29 @@ // Parsing of ELF executables (Linux, FreeBSD, and so on). -package main +package objfile import ( "debug/elf" "os" ) -func elfSymbols(f *os.File) []Sym { - p, err := elf.NewFile(f) - if err != nil { - errorf("parsing %s: %v", f.Name(), err) - return nil - } +type elfFile struct { + elf *elf.File +} - elfSyms, err := p.Symbols() +func openElf(r *os.File) (rawFile, error) { + f, err := elf.NewFile(r) if err != nil { - errorf("parsing %s: %v", f.Name(), err) - return nil + return nil, err + } + return &elfFile{f}, nil +} + +func (f *elfFile) symbols() ([]Sym, error) { + elfSyms, err := f.elf.Symbols() + if err != nil { + return nil, err } var syms []Sym @@ -34,10 +39,10 @@ func elfSymbols(f *os.File) []Sym { sym.Code = 'B' default: i := int(s.Section) - if i < 0 || i >= len(p.Sections) { + if i < 0 || i >= len(f.elf.Sections) { break } - sect := p.Sections[i] + sect := f.elf.Sections[i] switch sect.Flags & (elf.SHF_WRITE | elf.SHF_ALLOC | elf.SHF_EXECINSTR) { case elf.SHF_ALLOC | elf.SHF_EXECINSTR: sym.Code = 'T' @@ -53,5 +58,22 @@ func elfSymbols(f *os.File) []Sym { syms = append(syms, sym) } - return syms + return syms, nil +} + +func (f *elfFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) { + if sect := f.elf.Section(".text"); sect != nil { + textStart = sect.Addr + } + if sect := f.elf.Section(".gosymtab"); sect != nil { + if symtab, err = sect.Data(); err != nil { + return 0, nil, nil, err + } + } + if sect := f.elf.Section(".gopclntab"); sect != nil { + if pclntab, err = sect.Data(); err != nil { + return 0, nil, nil, err + } + } + return textStart, symtab, pclntab, nil } diff --git a/src/cmd/nm/goobj.go b/src/cmd/internal/objfile/goobj.go similarity index 72% rename from src/cmd/nm/goobj.go rename to src/cmd/internal/objfile/goobj.go index b0de51db9c..a4f49ebe44 100644 --- a/src/cmd/nm/goobj.go +++ b/src/cmd/internal/objfile/goobj.go @@ -4,7 +4,7 @@ // Parsing of Go intermediate object files and archives. -package main +package objfile import ( "debug/goobj" @@ -12,6 +12,18 @@ import ( "os" ) +type goobjFile struct { + goobj *goobj.Package +} + +func openGoobj(r *os.File) (rawFile, error) { + f, err := goobj.Parse(r, `""`) + if err != nil { + return nil, err + } + return &goobjFile{f}, nil +} + func goobjName(id goobj.SymID) string { if id.Version == 0 { return id.Name @@ -19,17 +31,11 @@ func goobjName(id goobj.SymID) string { return fmt.Sprintf("%s<%d>", id.Name, id.Version) } -func goobjSymbols(f *os.File) []Sym { - pkg, err := goobj.Parse(f, `""`) - if err != nil { - errorf("parsing %s: %v", f.Name(), err) - return nil - } - +func (f *goobjFile) symbols() ([]Sym, error) { seen := make(map[goobj.SymID]bool) var syms []Sym - for _, s := range pkg.Syms { + for _, s := range f.goobj.Syms { seen[s.SymID] = true sym := Sym{Addr: uint64(s.Data.Offset), Name: goobjName(s.SymID), Size: int64(s.Size), Type: s.Type.Name, Code: '?'} switch s.Kind { @@ -50,7 +56,7 @@ func goobjSymbols(f *os.File) []Sym { syms = append(syms, sym) } - for _, s := range pkg.Syms { + for _, s := range f.goobj.Syms { for _, r := range s.Reloc { if !seen[r.Sym] { seen[r.Sym] = true @@ -64,5 +70,12 @@ func goobjSymbols(f *os.File) []Sym { } } - return syms + return syms, nil +} + +// pcln does not make sense for Go object files, because each +// symbol has its own individual pcln table, so there is no global +// space of addresses to map. +func (f *goobjFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) { + return 0, nil, nil, fmt.Errorf("pcln not available in go object file") } diff --git a/src/cmd/nm/macho.go b/src/cmd/internal/objfile/macho.go similarity index 55% rename from src/cmd/nm/macho.go rename to src/cmd/internal/objfile/macho.go index c60bde55b4..f845792ffa 100644 --- a/src/cmd/nm/macho.go +++ b/src/cmd/internal/objfile/macho.go @@ -4,36 +4,42 @@ // Parsing of Mach-O executables (OS X). -package main +package objfile import ( "debug/macho" + "fmt" "os" "sort" ) -func machoSymbols(f *os.File) []Sym { - p, err := macho.NewFile(f) - if err != nil { - errorf("parsing %s: %v", f.Name(), err) - return nil - } +type machoFile struct { + macho *macho.File +} - if p.Symtab == nil { - errorf("%s: no symbol table", f.Name()) - return nil +func openMacho(r *os.File) (rawFile, error) { + f, err := macho.NewFile(r) + if err != nil { + return nil, err + } + return &machoFile{f}, nil +} + +func (f *machoFile) symbols() ([]Sym, error) { + if f.macho.Symtab == nil { + return nil, fmt.Errorf("missing symbol table") } // Build sorted list of addresses of all symbols. // We infer the size of a symbol by looking at where the next symbol begins. var addrs []uint64 - for _, s := range p.Symtab.Syms { + for _, s := range f.macho.Symtab.Syms { addrs = append(addrs, s.Value) } sort.Sort(uint64s(addrs)) var syms []Sym - for _, s := range p.Symtab.Syms { + for _, s := range f.macho.Symtab.Syms { sym := Sym{Name: s.Name, Addr: s.Value, Code: '?'} i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value }) if i < len(addrs) { @@ -41,8 +47,8 @@ func machoSymbols(f *os.File) []Sym { } if s.Sect == 0 { sym.Code = 'U' - } else if int(s.Sect) <= len(p.Sections) { - sect := p.Sections[s.Sect-1] + } else if int(s.Sect) <= len(f.macho.Sections) { + sect := f.macho.Sections[s.Sect-1] switch sect.Seg { case "__TEXT": sym.Code = 'R' @@ -59,7 +65,24 @@ func machoSymbols(f *os.File) []Sym { syms = append(syms, sym) } - return syms + return syms, nil +} + +func (f *machoFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) { + if sect := f.macho.Section("__text"); sect != nil { + textStart = sect.Addr + } + if sect := f.macho.Section("__gosymtab"); sect != nil { + if symtab, err = sect.Data(); err != nil { + return 0, nil, nil, err + } + } + if sect := f.macho.Section("__gopclntab"); sect != nil { + if pclntab, err = sect.Data(); err != nil { + return 0, nil, nil, err + } + } + return textStart, symtab, pclntab, nil } type uint64s []uint64 diff --git a/src/cmd/internal/objfile/objfile.go b/src/cmd/internal/objfile/objfile.go new file mode 100644 index 0000000000..09fa63e60b --- /dev/null +++ b/src/cmd/internal/objfile/objfile.go @@ -0,0 +1,72 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package objfile implements portable access to OS-specific executable files. +package objfile + +import ( + "debug/gosym" + "fmt" + "os" +) + +type rawFile interface { + symbols() (syms []Sym, err error) + pcln() (textStart uint64, symtab, pclntab []byte, err error) +} + +// A File is an opened executable file. +type File struct { + r *os.File + raw rawFile +} + +// A Sym is a symbol defined in an executable file. +type Sym struct { + Name string // symbol name + Addr uint64 // virtual address of symbol + Size int64 // size in bytes + Code rune // nm code (T for text, D for data, and so on) + Type string // XXX? +} + +var openers = []func(*os.File) (rawFile, error){ + openElf, + openGoobj, + openMacho, + openPE, + openPlan9, +} + +// Open opens the named file. +// The caller must call f.Close when the file is no longer needed. +func Open(name string) (*File, error) { + r, err := os.Open(name) + if err != nil { + return nil, err + } + for _, try := range openers { + if raw, err := try(r); err == nil { + return &File{r, raw}, nil + } + } + r.Close() + return nil, fmt.Errorf("open %s: unrecognized object file", name) +} + +func (f *File) Close() error { + return f.r.Close() +} + +func (f *File) Symbols() ([]Sym, error) { + return f.raw.symbols() +} + +func (f *File) PCLineTable() (*gosym.Table, error) { + textStart, symtab, pclntab, err := f.raw.pcln() + if err != nil { + return nil, err + } + return gosym.NewTable(symtab, gosym.NewLineTable(pclntab, textStart)) +} diff --git a/src/cmd/internal/objfile/pe.go b/src/cmd/internal/objfile/pe.go new file mode 100644 index 0000000000..492766d9a2 --- /dev/null +++ b/src/cmd/internal/objfile/pe.go @@ -0,0 +1,161 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Parsing of PE executables (Microsoft Windows). + +package objfile + +import ( + "debug/pe" + "fmt" + "os" + "sort" +) + +type peFile struct { + pe *pe.File +} + +func openPE(r *os.File) (rawFile, error) { + f, err := pe.NewFile(r) + if err != nil { + return nil, err + } + switch f.OptionalHeader.(type) { + case *pe.OptionalHeader32, *pe.OptionalHeader64: + // ok + default: + return nil, fmt.Errorf("unrecognized PE format") + } + return &peFile{f}, nil +} + +func (f *peFile) symbols() ([]Sym, error) { + // Build sorted list of addresses of all symbols. + // We infer the size of a symbol by looking at where the next symbol begins. + var addrs []uint64 + + var imageBase uint64 + switch oh := f.pe.OptionalHeader.(type) { + case *pe.OptionalHeader32: + imageBase = uint64(oh.ImageBase) + case *pe.OptionalHeader64: + imageBase = oh.ImageBase + } + + var syms []Sym + for _, s := range f.pe.Symbols { + const ( + N_UNDEF = 0 // An undefined (extern) symbol + N_ABS = -1 // An absolute symbol (e_value is a constant, not an address) + N_DEBUG = -2 // A debugging symbol + ) + sym := Sym{Name: s.Name, Addr: uint64(s.Value), Code: '?'} + switch s.SectionNumber { + case N_UNDEF: + sym.Code = 'U' + case N_ABS: + sym.Code = 'C' + case N_DEBUG: + sym.Code = '?' + default: + if s.SectionNumber < 0 || len(f.pe.Sections) < int(s.SectionNumber) { + return nil, fmt.Errorf("invalid section number in symbol table") + } + sect := f.pe.Sections[s.SectionNumber-1] + const ( + text = 0x20 + data = 0x40 + bss = 0x80 + permX = 0x20000000 + permR = 0x40000000 + permW = 0x80000000 + ) + ch := sect.Characteristics + switch { + case ch&text != 0: + sym.Code = 'T' + case ch&data != 0: + if ch&permW == 0 { + sym.Code = 'R' + } else { + sym.Code = 'D' + } + case ch&bss != 0: + sym.Code = 'B' + } + sym.Addr += imageBase + uint64(sect.VirtualAddress) + } + syms = append(syms, sym) + addrs = append(addrs, sym.Addr) + } + + sort.Sort(uint64s(addrs)) + for i := range syms { + j := sort.Search(len(addrs), func(x int) bool { return addrs[x] > syms[i].Addr }) + if j < len(addrs) { + syms[i].Size = int64(addrs[j] - syms[i].Addr) + } + } + + return syms, nil +} + +func (f *peFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) { + var imageBase uint64 + switch oh := f.pe.OptionalHeader.(type) { + case *pe.OptionalHeader32: + imageBase = uint64(oh.ImageBase) + case *pe.OptionalHeader64: + imageBase = oh.ImageBase + default: + return 0, nil, nil, fmt.Errorf("pe file format not recognized") + } + if sect := f.pe.Section(".text"); sect != nil { + textStart = imageBase + uint64(sect.VirtualAddress) + } + if pclntab, err = loadPETable(f.pe, "pclntab", "epclntab"); err != nil { + return 0, nil, nil, err + } + if symtab, err = loadPETable(f.pe, "symtab", "esymtab"); err != nil { + return 0, nil, nil, err + } + return textStart, symtab, pclntab, nil +} + +func findPESymbol(f *pe.File, name string) (*pe.Symbol, error) { + for _, s := range f.Symbols { + if s.Name != name { + continue + } + if s.SectionNumber <= 0 { + return nil, fmt.Errorf("symbol %s: invalid section number %d", name, s.SectionNumber) + } + if len(f.Sections) < int(s.SectionNumber) { + return nil, fmt.Errorf("symbol %s: section number %d is larger than max %d", name, s.SectionNumber, len(f.Sections)) + } + return s, nil + } + return nil, fmt.Errorf("no %s symbol found", name) +} + +func loadPETable(f *pe.File, sname, ename string) ([]byte, error) { + ssym, err := findPESymbol(f, sname) + if err != nil { + return nil, err + } + esym, err := findPESymbol(f, ename) + if err != nil { + return nil, err + } + if ssym.SectionNumber != esym.SectionNumber { + return nil, fmt.Errorf("%s and %s symbols must be in the same section", sname, ename) + } + sect := f.Sections[ssym.SectionNumber-1] + data, err := sect.Data() + if err != nil { + return nil, err + } + return data[ssym.Value:esym.Value], nil +} diff --git a/src/cmd/internal/objfile/plan9obj.go b/src/cmd/internal/objfile/plan9obj.go new file mode 100644 index 0000000000..3fe05ec03b --- /dev/null +++ b/src/cmd/internal/objfile/plan9obj.go @@ -0,0 +1,100 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Parsing of Plan 9 a.out executables. + +package objfile + +import ( + "debug/plan9obj" + "fmt" + "os" + "sort" +) + +type plan9File struct { + plan9 *plan9obj.File +} + +func openPlan9(r *os.File) (rawFile, error) { + f, err := plan9obj.NewFile(r) + if err != nil { + return nil, err + } + return &plan9File{f}, nil +} + +func (f *plan9File) symbols() ([]Sym, error) { + plan9Syms, err := f.plan9.Symbols() + if err != nil { + return nil, err + } + + // Build sorted list of addresses of all symbols. + // We infer the size of a symbol by looking at where the next symbol begins. + var addrs []uint64 + for _, s := range plan9Syms { + addrs = append(addrs, s.Value) + } + sort.Sort(uint64s(addrs)) + + var syms []Sym + + for _, s := range plan9Syms { + sym := Sym{Addr: s.Value, Name: s.Name, Code: rune(s.Type)} + i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value }) + if i < len(addrs) { + sym.Size = int64(addrs[i] - s.Value) + } + syms = append(syms, sym) + } + + return syms, nil +} + +func (f *plan9File) pcln() (textStart uint64, symtab, pclntab []byte, err error) { + textStart = f.plan9.LoadAddress + f.plan9.HdrSize + if pclntab, err = loadPlan9Table(f.plan9, "pclntab", "epclntab"); err != nil { + return 0, nil, nil, err + } + if symtab, err = loadPlan9Table(f.plan9, "symtab", "esymtab"); err != nil { + return 0, nil, nil, err + } + return textStart, symtab, pclntab, nil +} + +func findPlan9Symbol(f *plan9obj.File, name string) (*plan9obj.Sym, error) { + syms, err := f.Symbols() + if err != nil { + return nil, err + } + for _, s := range syms { + if s.Name != name { + continue + } + return &s, nil + } + return nil, fmt.Errorf("no %s symbol found", name) +} + +func loadPlan9Table(f *plan9obj.File, sname, ename string) ([]byte, error) { + ssym, err := findPlan9Symbol(f, sname) + if err != nil { + return nil, err + } + esym, err := findPlan9Symbol(f, ename) + if err != nil { + return nil, err + } + sect := f.Section("text") + if sect == nil { + return nil, err + } + data, err := sect.Data() + if err != nil { + return nil, err + } + textStart := f.LoadAddress + f.HdrSize + return data[ssym.Value-textStart : esym.Value-textStart], nil +} diff --git a/src/cmd/nm/nm.go b/src/cmd/nm/nm.go index a4036184e4..3089e481be 100644 --- a/src/cmd/nm/nm.go +++ b/src/cmd/nm/nm.go @@ -6,13 +6,13 @@ package main import ( "bufio" - "bytes" "flag" "fmt" - "io" "log" "os" "sort" + + "cmd/internal/objfile" ) func usage() { @@ -85,55 +85,22 @@ func errorf(format string, args ...interface{}) { exitCode = 1 } -type Sym struct { - Addr uint64 - Size int64 - Code rune - Name string - Type string -} - -var parsers = []struct { - prefix []byte - parse func(*os.File) []Sym -}{ - {[]byte("!\n"), goobjSymbols}, - {[]byte("go object "), goobjSymbols}, - {[]byte("\x7FELF"), elfSymbols}, - {[]byte("\xFE\xED\xFA\xCE"), machoSymbols}, - {[]byte("\xFE\xED\xFA\xCF"), machoSymbols}, - {[]byte("\xCE\xFA\xED\xFE"), machoSymbols}, - {[]byte("\xCF\xFA\xED\xFE"), machoSymbols}, - {[]byte("MZ"), peSymbols}, - {[]byte("\x00\x00\x01\xEB"), plan9Symbols}, // 386 - {[]byte("\x00\x00\x04\x07"), plan9Symbols}, // mips - {[]byte("\x00\x00\x06\x47"), plan9Symbols}, // arm - {[]byte("\x00\x00\x8A\x97"), plan9Symbols}, // amd64 -} - func nm(file string) { - f, err := os.Open(file) + f, err := objfile.Open(file) if err != nil { errorf("%v", err) return } defer f.Close() - buf := make([]byte, 16) - io.ReadFull(f, buf) - f.Seek(0, 0) - - var syms []Sym - for _, p := range parsers { - if bytes.HasPrefix(buf, p.prefix) { - syms = p.parse(f) - goto HaveSyms - } + syms, err := f.Symbols() + if err != nil { + errorf("reading %s: %v", file, err) + } + if len(syms) == 0 { + errorf("reading %s: no symbols", file) } - errorf("%v: unknown file format", file) - return -HaveSyms: switch *sortOrder { case "address": sort.Sort(byAddr(syms)) @@ -165,19 +132,19 @@ HaveSyms: w.Flush() } -type byAddr []Sym +type byAddr []objfile.Sym func (x byAddr) Len() int { return len(x) } func (x byAddr) Swap(i, j int) { x[i], x[j] = x[j], x[i] } func (x byAddr) Less(i, j int) bool { return x[i].Addr < x[j].Addr } -type byName []Sym +type byName []objfile.Sym func (x byName) Len() int { return len(x) } func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } func (x byName) Less(i, j int) bool { return x[i].Name < x[j].Name } -type bySize []Sym +type bySize []objfile.Sym func (x bySize) Len() int { return len(x) } func (x bySize) Swap(i, j int) { x[i], x[j] = x[j], x[i] } diff --git a/src/cmd/nm/nm_test.go b/src/cmd/nm/nm_test.go index 74773877f3..f447e8e491 100644 --- a/src/cmd/nm/nm_test.go +++ b/src/cmd/nm/nm_test.go @@ -77,7 +77,7 @@ func TestNM(t *testing.T) { "elf/testdata/gcc-amd64-linux-exec", "macho/testdata/gcc-386-darwin-exec", "macho/testdata/gcc-amd64-darwin-exec", - "pe/testdata/gcc-amd64-mingw-exec", + // "pe/testdata/gcc-amd64-mingw-exec", // no symbols! "pe/testdata/gcc-386-mingw-exec", "plan9obj/testdata/amd64-plan9-exec", "plan9obj/testdata/386-plan9-exec", @@ -87,7 +87,7 @@ func TestNM(t *testing.T) { cmd := exec.Command(testnmpath, exepath) out, err := cmd.CombinedOutput() if err != nil { - t.Fatalf("go tool nm %v: %v\n%s", exepath, err, string(out)) + t.Errorf("go tool nm %v: %v\n%s", exepath, err, string(out)) } } diff --git a/src/cmd/nm/pe.go b/src/cmd/nm/pe.go deleted file mode 100644 index 52d05e51d0..0000000000 --- a/src/cmd/nm/pe.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Parsing of PE executables (Microsoft Windows). - -package main - -import ( - "debug/pe" - "os" - "sort" -) - -func peSymbols(f *os.File) []Sym { - p, err := pe.NewFile(f) - if err != nil { - errorf("parsing %s: %v", f.Name(), err) - return nil - } - - // Build sorted list of addresses of all symbols. - // We infer the size of a symbol by looking at where the next symbol begins. - var addrs []uint64 - - var imageBase uint64 - switch oh := p.OptionalHeader.(type) { - case *pe.OptionalHeader32: - imageBase = uint64(oh.ImageBase) - case *pe.OptionalHeader64: - imageBase = oh.ImageBase - default: - errorf("parsing %s: file format not recognized", f.Name()) - return nil - } - - var syms []Sym - for _, s := range p.Symbols { - const ( - N_UNDEF = 0 // An undefined (extern) symbol - N_ABS = -1 // An absolute symbol (e_value is a constant, not an address) - N_DEBUG = -2 // A debugging symbol - ) - sym := Sym{Name: s.Name, Addr: uint64(s.Value), Code: '?'} - switch s.SectionNumber { - case N_UNDEF: - sym.Code = 'U' - case N_ABS: - sym.Code = 'C' - case N_DEBUG: - sym.Code = '?' - default: - if s.SectionNumber < 0 { - errorf("parsing %s: invalid section number %d", f.Name(), s.SectionNumber) - return nil - } - if len(p.Sections) < int(s.SectionNumber) { - errorf("parsing %s: section number %d is large then max %d", f.Name(), s.SectionNumber, len(p.Sections)) - return nil - } - sect := p.Sections[s.SectionNumber-1] - const ( - text = 0x20 - data = 0x40 - bss = 0x80 - permX = 0x20000000 - permR = 0x40000000 - permW = 0x80000000 - ) - ch := sect.Characteristics - switch { - case ch&text != 0: - sym.Code = 'T' - case ch&data != 0: - if ch&permW == 0 { - sym.Code = 'R' - } else { - sym.Code = 'D' - } - case ch&bss != 0: - sym.Code = 'B' - } - sym.Addr += imageBase + uint64(sect.VirtualAddress) - } - syms = append(syms, sym) - addrs = append(addrs, sym.Addr) - } - - sort.Sort(uint64s(addrs)) - for i := range syms { - j := sort.Search(len(addrs), func(x int) bool { return addrs[x] > syms[i].Addr }) - if j < len(addrs) { - syms[i].Size = int64(addrs[j] - syms[i].Addr) - } - } - - return syms -} diff --git a/src/cmd/nm/plan9obj.go b/src/cmd/nm/plan9obj.go deleted file mode 100644 index 006c66ebfd..0000000000 --- a/src/cmd/nm/plan9obj.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Parsing of Plan 9 a.out executables. - -package main - -import ( - "debug/plan9obj" - "os" - "sort" -) - -func plan9Symbols(f *os.File) []Sym { - p, err := plan9obj.NewFile(f) - if err != nil { - errorf("parsing %s: %v", f.Name(), err) - return nil - } - - plan9Syms, err := p.Symbols() - if err != nil { - errorf("parsing %s: %v", f.Name(), err) - return nil - } - - // Build sorted list of addresses of all symbols. - // We infer the size of a symbol by looking at where the next symbol begins. - var addrs []uint64 - for _, s := range plan9Syms { - addrs = append(addrs, s.Value) - } - sort.Sort(uint64s(addrs)) - - var syms []Sym - - for _, s := range plan9Syms { - sym := Sym{Addr: s.Value, Name: s.Name, Code: rune(s.Type)} - i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value }) - if i < len(addrs) { - sym.Size = int64(addrs[i] - s.Value) - } - syms = append(syms, sym) - } - - return syms -} From d078d483ce87b4311f79e988a0b609d3c53d3cb4 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 7 Aug 2014 12:33:19 -0400 Subject: [PATCH 025/423] go/build: look in $GOROOT/src/cmd/foo/bar for import cmd/foo/bar This lets us have non-main packages like cmd/internal or cmd/nm/internal/whatever. The src/pkg migration (see golang.org/s/go14mainrepo) will allow this as a natural side effect. The explicit change here just allows use of the effect a little sooner. LGTM=r R=r CC=golang-codereviews https://golang.org/cl/117630043 --- src/pkg/go/build/build.go | 7 ++++++- src/pkg/go/build/build_test.go | 10 ++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/pkg/go/build/build.go b/src/pkg/go/build/build.go index 09730d6351..6db0275032 100644 --- a/src/pkg/go/build/build.go +++ b/src/pkg/go/build/build.go @@ -521,7 +521,12 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa // Determine directory from import path. if ctxt.GOROOT != "" { - dir := ctxt.joinPath(ctxt.GOROOT, "src", "pkg", path) + var dir string + if strings.HasPrefix(path, "cmd/") { + dir = ctxt.joinPath(ctxt.GOROOT, "src", path) + } else { + dir = ctxt.joinPath(ctxt.GOROOT, "src", "pkg", path) + } isDir := ctxt.isDir(dir) binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(ctxt.GOROOT, pkga)) if isDir || binaryOnly { diff --git a/src/pkg/go/build/build_test.go b/src/pkg/go/build/build_test.go index f0d243cd53..0040101134 100644 --- a/src/pkg/go/build/build_test.go +++ b/src/pkg/go/build/build_test.go @@ -193,3 +193,13 @@ func TestMatchFile(t *testing.T) { } } } + +func TestImportCmd(t *testing.T) { + p, err := Import("cmd/internal/objfile", "", 0) + if err != nil { + t.Fatal(err) + } + if !strings.HasSuffix(filepath.ToSlash(p.Dir), "src/cmd/internal/objfile") { + t.Fatalf("Import cmd/internal/objfile returned Dir=%q, want %q", filepath.ToSlash(p.Dir), ".../src/cmd/internal/objfile") + } +} From cc063592b0307552af9fd80f03be6276838e52f9 Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Thu, 7 Aug 2014 21:39:32 +0400 Subject: [PATCH 026/423] encoding/gob: make benchmarks parallel There are lots of internal synchronization in gob, so it makes sense to have parallel benchmarks. Also add a benchmark with slices and interfaces. LGTM=r R=golang-codereviews, r CC=golang-codereviews https://golang.org/cl/115960043 --- src/pkg/encoding/gob/timing_test.go | 57 +++++++++++++++++++---------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/src/pkg/encoding/gob/timing_test.go b/src/pkg/encoding/gob/timing_test.go index acfb065b12..29c9b858b6 100644 --- a/src/pkg/encoding/gob/timing_test.go +++ b/src/pkg/encoding/gob/timing_test.go @@ -19,33 +19,52 @@ type Bench struct { D []byte } -func benchmarkEndToEnd(r io.Reader, w io.Writer, b *testing.B) { - b.StopTimer() - enc := NewEncoder(w) - dec := NewDecoder(r) - bench := &Bench{7, 3.2, "now is the time", bytes.Repeat([]byte("for all good men"), 100)} - b.StartTimer() - for i := 0; i < b.N; i++ { - if enc.Encode(bench) != nil { - panic("encode error") +func benchmarkEndToEnd(b *testing.B, v interface{}, pipe func() (r io.Reader, w io.Writer, err error)) { + b.RunParallel(func(pb *testing.PB) { + r, w, err := pipe() + if err != nil { + b.Fatal("can't get pipe:", err) } - if dec.Decode(bench) != nil { - panic("decode error") + enc := NewEncoder(w) + dec := NewDecoder(r) + for pb.Next() { + if err := enc.Encode(v); err != nil { + b.Fatal("encode error:", err) + } + if err := dec.Decode(v); err != nil { + b.Fatal("decode error:", err) + } } - } + }) } func BenchmarkEndToEndPipe(b *testing.B) { - r, w, err := os.Pipe() - if err != nil { - b.Fatal("can't get pipe:", err) - } - benchmarkEndToEnd(r, w, b) + v := &Bench{7, 3.2, "now is the time", bytes.Repeat([]byte("for all good men"), 100)} + benchmarkEndToEnd(b, v, func() (r io.Reader, w io.Writer, err error) { + r, w, err = os.Pipe() + return + }) } func BenchmarkEndToEndByteBuffer(b *testing.B) { - var buf bytes.Buffer - benchmarkEndToEnd(&buf, &buf, b) + v := &Bench{7, 3.2, "now is the time", bytes.Repeat([]byte("for all good men"), 100)} + benchmarkEndToEnd(b, v, func() (r io.Reader, w io.Writer, err error) { + var buf bytes.Buffer + return &buf, &buf, nil + }) +} + +func BenchmarkEndToEndSliceByteBuffer(b *testing.B) { + v := &Bench{7, 3.2, "now is the time", nil} + Register(v) + arr := make([]interface{}, 100) + for i := range arr { + arr[i] = v + } + benchmarkEndToEnd(b, &arr, func() (r io.Reader, w io.Writer, err error) { + var buf bytes.Buffer + return &buf, &buf, nil + }) } func TestCountEncodeMallocs(t *testing.T) { From 3d7e3691207fd9dabfe12a560ecac473e7e59737 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 7 Aug 2014 12:33:20 -0700 Subject: [PATCH 027/423] runtime: test distribution of interface hashes. LGTM=dvyukov R=dvyukov, khr CC=golang-codereviews https://golang.org/cl/121030043 --- src/pkg/runtime/alg.go | 10 ++++++ src/pkg/runtime/export_test.go | 2 ++ src/pkg/runtime/hash_test.go | 60 ++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+) diff --git a/src/pkg/runtime/alg.go b/src/pkg/runtime/alg.go index f2bb202c68..ea4156f1ed 100644 --- a/src/pkg/runtime/alg.go +++ b/src/pkg/runtime/alg.go @@ -163,3 +163,13 @@ func int32Hash(i uint32, seed uintptr) uintptr { func int64Hash(i uint64, seed uintptr) uintptr { return goalg(&algarray[alg_MEM64]).hash(noescape(unsafe.Pointer(&i)), 8, seed) } + +func efaceHash(i interface{}, seed uintptr) uintptr { + return goalg(&algarray[alg_NILINTER]).hash(noescape(unsafe.Pointer(&i)), unsafe.Sizeof(i), seed) +} + +func ifaceHash(i interface { + F() +}, seed uintptr) uintptr { + return goalg(&algarray[alg_INTER]).hash(noescape(unsafe.Pointer(&i)), unsafe.Sizeof(i), seed) +} diff --git a/src/pkg/runtime/export_test.go b/src/pkg/runtime/export_test.go index 01b47e17af..32c34aade6 100644 --- a/src/pkg/runtime/export_test.go +++ b/src/pkg/runtime/export_test.go @@ -76,6 +76,8 @@ var StringHash = stringHash var BytesHash = bytesHash var Int32Hash = int32Hash var Int64Hash = int64Hash +var EfaceHash = efaceHash +var IfaceHash = ifaceHash var HashLoad = &hashLoad diff --git a/src/pkg/runtime/hash_test.go b/src/pkg/runtime/hash_test.go index 1c11e0538d..41fff98eb0 100644 --- a/src/pkg/runtime/hash_test.go +++ b/src/pkg/runtime/hash_test.go @@ -344,6 +344,64 @@ func (k *Int64Key) name() string { return "int64" } +type EfaceKey struct { + i interface{} +} + +func (k *EfaceKey) clear() { + k.i = nil +} +func (k *EfaceKey) random(r *rand.Rand) { + k.i = uint64(r.Int63()) +} +func (k *EfaceKey) bits() int { + // use 64 bits. This tests inlined interfaces + // on 64-bit targets and indirect interfaces on + // 32-bit targets. + return 64 +} +func (k *EfaceKey) flipBit(i int) { + k.i = k.i.(uint64) ^ uint64(1)< Date: Thu, 7 Aug 2014 12:38:39 -0700 Subject: [PATCH 028/423] cmd/go: pass --build-id=none when generating a cgo .o Some systems, like Ubuntu, pass --build-id when linking. The effect is to put a note in the output file. This is not useful when generating an object file with the -r option, as it eventually causes multiple build ID notes in the final executable, all but one of which are for tiny portions of the file and are therefore useless. Disable that by passing an explicit --build-id=none when linking with -r on systems that might do this. LGTM=bradfitz R=golang-codereviews, bradfitz CC=golang-codereviews https://golang.org/cl/119460043 --- misc/cgo/test/buildid_linux.go | 77 +++++++++++++++++++++++++++++++++ misc/cgo/test/cgo_linux_test.go | 5 ++- src/cmd/go/build.go | 18 +++++++- 3 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 misc/cgo/test/buildid_linux.go diff --git a/misc/cgo/test/buildid_linux.go b/misc/cgo/test/buildid_linux.go new file mode 100644 index 0000000000..a3a86edfca --- /dev/null +++ b/misc/cgo/test/buildid_linux.go @@ -0,0 +1,77 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cgotest + +// Test that we have no more than one build ID. In the past we used +// to generate a separate build ID for each package using cgo, and the +// linker concatenated them all. We don't want that--we only want +// one. + +import ( + "bytes" + "debug/elf" + "os" + "testing" +) + +func testBuildID(t *testing.T) { + f, err := elf.Open("/proc/self/exe") + if err != nil { + if os.IsNotExist(err) { + t.Skip("no /proc/self/exe") + } + t.Fatalf("opening /proc/self/exe: ", err) + } + defer f.Close() + + c := 0 + for i, s := range f.Sections { + if s.Type != elf.SHT_NOTE { + continue + } + + d, err := s.Data() + if err != nil { + t.Logf("reading data of note section %d: %v", i, err) + continue + } + + for len(d) > 0 { + + // ELF standards differ as to the sizes in + // note sections. Both the GNU linker and + // gold always generate 32-bit sizes, so that + // is what we assume here. + + if len(d) < 12 { + t.Logf("note section %d too short (%d < 12)", i, len(d)) + continue + } + + namesz := f.ByteOrder.Uint32(d) + descsz := f.ByteOrder.Uint32(d[4:]) + typ := f.ByteOrder.Uint32(d[8:]) + + an := (namesz + 3) &^ 3 + ad := (descsz + 3) &^ 3 + + if int(12+an+ad) > len(d) { + t.Logf("note section %d too short for header (%d < 12 + align(%d,4) + align(%d,4))", i, len(d), namesz, descsz) + continue + } + + // 3 == NT_GNU_BUILD_ID + if typ == 3 && namesz == 4 && bytes.Equal(d[12:16], []byte("GNU\000")) { + c++ + } + + d = d[12+an+ad:] + } + } + + if c > 1 { + t.Errorf("found %d build ID notes", c) + } +} diff --git a/misc/cgo/test/cgo_linux_test.go b/misc/cgo/test/cgo_linux_test.go index 0a405c7a3b..4fe0db1b2b 100644 --- a/misc/cgo/test/cgo_linux_test.go +++ b/misc/cgo/test/cgo_linux_test.go @@ -6,5 +6,6 @@ package cgotest import "testing" -func TestSetgid(t *testing.T) { testSetgid(t) } -func Test6997(t *testing.T) { test6997(t) } +func TestSetgid(t *testing.T) { testSetgid(t) } +func Test6997(t *testing.T) { test6997(t) } +func TestBuildID(t *testing.T) { testBuildID(t) } diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go index fa9262c0f0..b39364ed89 100644 --- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -2312,7 +2312,23 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles nonGccObjs = append(nonGccObjs, f) } } - if err := b.gccld(p, ofile, stringList(bareLDFLAGS, "-Wl,-r", "-nostdlib", staticLibs), gccObjs); err != nil { + ldflags := stringList(bareLDFLAGS, "-Wl,-r", "-nostdlib", staticLibs) + + // Some systems, such as Ubuntu, always add --build-id to + // every link, but we don't want a build ID since we are + // producing an object file. On some of those system a plain + // -r (not -Wl,-r) will turn off --build-id, but clang 3.0 + // doesn't support a plain -r. I don't know how to turn off + // --build-id when using clang other than passing a trailing + // --build-id=none. So that is what we do, but only on + // systems likely to support it, which is to say, systems that + // normally use gold or the GNU linker. + switch goos { + case "android", "dragonfly", "freebsd", "linux", "netbsd", "openbsd": + ldflags = append(ldflags, "-Wl,--build-id=none") + } + + if err := b.gccld(p, ofile, ldflags, gccObjs); err != nil { return nil, nil, err } From a3c0ca54b01284af40e684422a739d41b4cb9cfe Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 7 Aug 2014 12:45:01 -0700 Subject: [PATCH 029/423] go/parser: don't do method receiver checks at parse-time The ast and printer don't care, and go/types can provide a better error message. This change requires an update to the tests for go/types (go.tools repo). CL forthcoming. Fixes #8493. LGTM=adonovan R=rsc, adonovan CC=golang-codereviews https://golang.org/cl/123010044 --- src/pkg/go/parser/parser.go | 32 +------------------------------- 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/src/pkg/go/parser/parser.go b/src/pkg/go/parser/parser.go index 8291f3f42d..4d6f36258c 100644 --- a/src/pkg/go/parser/parser.go +++ b/src/pkg/go/parser/parser.go @@ -2307,36 +2307,6 @@ func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.Gen } } -func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList { - if p.trace { - defer un(trace(p, "Receiver")) - } - - par := p.parseParameters(scope, false) - - // must have exactly one receiver - if par.NumFields() != 1 { - p.errorExpected(par.Opening, "exactly one receiver") - par.List = []*ast.Field{{Type: &ast.BadExpr{From: par.Opening, To: par.Closing + 1}}} - return par - } - - // recv type must be of the form ["*"] identifier, possibly using parentheses - recv := par.List[0] - base := unparen(deref(unparen(recv.Type))) - if _, isIdent := base.(*ast.Ident); !isIdent { - if _, isBad := base.(*ast.BadExpr); !isBad { - // only report error if it's a new one - p.errorExpected(base.Pos(), "(unqualified) identifier") - } - par.List = []*ast.Field{ - {Type: &ast.BadExpr{From: recv.Pos(), To: p.safePos(recv.End())}}, - } - } - - return par -} - func (p *parser) parseFuncDecl() *ast.FuncDecl { if p.trace { defer un(trace(p, "FunctionDecl")) @@ -2348,7 +2318,7 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl { var recv *ast.FieldList if p.tok == token.LPAREN { - recv = p.parseReceiver(scope) + recv = p.parseParameters(scope, false) } ident := p.parseIdent() From 3a3f8993ced61bf103e77d229722d0ce33fd0090 Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Thu, 7 Aug 2014 23:47:01 +0400 Subject: [PATCH 030/423] runtime: fix nacl/amd64p32 build C compiler does not support unnamed fields. LGTM=bradfitz R=golang-codereviews, bradfitz CC=golang-codereviews https://golang.org/cl/124870043 --- src/pkg/runtime/defs_nacl_amd64p32.h | 2 +- src/pkg/runtime/signal_nacl_amd64p32.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pkg/runtime/defs_nacl_amd64p32.h b/src/pkg/runtime/defs_nacl_amd64p32.h index 8d3068bf87..45663d40af 100644 --- a/src/pkg/runtime/defs_nacl_amd64p32.h +++ b/src/pkg/runtime/defs_nacl_amd64p32.h @@ -79,7 +79,7 @@ struct ExcContext union { ExcRegs386 regs; ExcRegsAmd64 regs64; - }; + } regs; }; struct ExcPortableContext diff --git a/src/pkg/runtime/signal_nacl_amd64p32.h b/src/pkg/runtime/signal_nacl_amd64p32.h index c58593a291..f62305cb52 100644 --- a/src/pkg/runtime/signal_nacl_amd64p32.h +++ b/src/pkg/runtime/signal_nacl_amd64p32.h @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#define SIG_REGS(ctxt) (((ExcContext*)(ctxt))->regs64) +#define SIG_REGS(ctxt) (((ExcContext*)(ctxt))->regs.regs64) #define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).rax) #define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).rbx) From 5ecbdb049bc9f33be49e1fd2e7279b6d84f801d2 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 7 Aug 2014 13:51:29 -0700 Subject: [PATCH 031/423] cmd/go: don't pass --buildid=none on FreeBSD According to the FreeBSD builder, it doesn't work. TBR=bradfitz CC=golang-codereviews https://golang.org/cl/121400043 --- src/cmd/go/build.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go index b39364ed89..88c2e29490 100644 --- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -2324,7 +2324,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles // systems likely to support it, which is to say, systems that // normally use gold or the GNU linker. switch goos { - case "android", "dragonfly", "freebsd", "linux", "netbsd", "openbsd": + case "android", "dragonfly", "linux", "netbsd", "openbsd": ldflags = append(ldflags, "-Wl,--build-id=none") } From 483cb6192133e737d5179e3fb579321288ed04c7 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 7 Aug 2014 13:58:42 -0700 Subject: [PATCH 032/423] runtime: convert interface routines from C to Go. LGTM=dvyukov R=golang-codereviews, dave, bradfitz, dvyukov, khr CC=golang-codereviews https://golang.org/cl/98510044 --- src/cmd/api/goapi.go | 2 +- src/pkg/reflect/asm_386.s | 6 + src/pkg/reflect/asm_amd64.s | 6 + src/pkg/reflect/asm_amd64p32.s | 6 + src/pkg/reflect/asm_arm.s | 6 + src/pkg/runtime/alg.goc | 3 + src/pkg/runtime/iface.go | 469 +++++++++++++++++++++++++++++++++ src/pkg/runtime/iface.goc | 404 ++-------------------------- src/pkg/runtime/stubs.go | 9 +- src/pkg/runtime/stubs.goc | 14 + 10 files changed, 535 insertions(+), 390 deletions(-) create mode 100644 src/pkg/runtime/iface.go diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go index fe3c257a55..38bf9592f2 100644 --- a/src/cmd/api/goapi.go +++ b/src/cmd/api/goapi.go @@ -378,7 +378,7 @@ func (w *Walker) parseFile(dir, file string) (*ast.File, error) { } if w.context != nil && file == fmt.Sprintf("zruntime_defs_%s_%s.go", w.context.GOOS, w.context.GOARCH) { // Just enough to keep the api checker happy. - src := "package runtime; type maptype struct{}; type _type struct{}; type alg struct{}; type mspan struct{}; type m struct{}; type lock struct{}; type slicetype struct{}; type iface struct{}; type eface struct{}" + src := "package runtime; type maptype struct{}; type _type struct{}; type alg struct{}; type mspan struct{}; type m struct{}; type lock struct{}; type slicetype struct{}; type iface struct{}; type eface struct{}; type interfacetype struct{}; type itab struct{}" f, err = parser.ParseFile(fset, filename, src, 0) if err != nil { log.Fatalf("incorrect generated file: %s", err) diff --git a/src/pkg/reflect/asm_386.s b/src/pkg/reflect/asm_386.s index 18b348adc1..a538624083 100644 --- a/src/pkg/reflect/asm_386.s +++ b/src/pkg/reflect/asm_386.s @@ -46,3 +46,9 @@ TEXT ·maplen(SB),NOSPLIT,$0-0 JMP runtime·reflect_maplen(SB) TEXT ·ismapkey(SB),NOSPLIT,$0-0 JMP runtime·reflect_ismapkey(SB) +TEXT ·ifaceE2I(SB),NOSPLIT,$0-0 + JMP runtime·reflect_ifaceE2I(SB) +TEXT ·unsafe_New(SB),NOSPLIT,$0-0 + JMP runtime·newobject(SB) +TEXT ·unsafe_NewArray(SB),NOSPLIT,$0-0 + JMP runtime·newarray(SB) diff --git a/src/pkg/reflect/asm_amd64.s b/src/pkg/reflect/asm_amd64.s index 9a9eed02aa..12a8879b79 100644 --- a/src/pkg/reflect/asm_amd64.s +++ b/src/pkg/reflect/asm_amd64.s @@ -46,3 +46,9 @@ TEXT ·maplen(SB),NOSPLIT,$0-0 JMP runtime·reflect_maplen(SB) TEXT ·ismapkey(SB),NOSPLIT,$0-0 JMP runtime·reflect_ismapkey(SB) +TEXT ·ifaceE2I(SB),NOSPLIT,$0-0 + JMP runtime·reflect_ifaceE2I(SB) +TEXT ·unsafe_New(SB),NOSPLIT,$0-0 + JMP runtime·newobject(SB) +TEXT ·unsafe_NewArray(SB),NOSPLIT,$0-0 + JMP runtime·newarray(SB) diff --git a/src/pkg/reflect/asm_amd64p32.s b/src/pkg/reflect/asm_amd64p32.s index 18b348adc1..a538624083 100644 --- a/src/pkg/reflect/asm_amd64p32.s +++ b/src/pkg/reflect/asm_amd64p32.s @@ -46,3 +46,9 @@ TEXT ·maplen(SB),NOSPLIT,$0-0 JMP runtime·reflect_maplen(SB) TEXT ·ismapkey(SB),NOSPLIT,$0-0 JMP runtime·reflect_ismapkey(SB) +TEXT ·ifaceE2I(SB),NOSPLIT,$0-0 + JMP runtime·reflect_ifaceE2I(SB) +TEXT ·unsafe_New(SB),NOSPLIT,$0-0 + JMP runtime·newobject(SB) +TEXT ·unsafe_NewArray(SB),NOSPLIT,$0-0 + JMP runtime·newarray(SB) diff --git a/src/pkg/reflect/asm_arm.s b/src/pkg/reflect/asm_arm.s index 1db6b9b9d4..69e4ab4888 100644 --- a/src/pkg/reflect/asm_arm.s +++ b/src/pkg/reflect/asm_arm.s @@ -46,3 +46,9 @@ TEXT ·maplen(SB),NOSPLIT,$-4-0 B runtime·reflect_maplen(SB) TEXT ·ismapkey(SB),NOSPLIT,$-4-0 B runtime·reflect_ismapkey(SB) +TEXT ·ifaceE2I(SB),NOSPLIT,$0-0 + B runtime·reflect_ifaceE2I(SB) +TEXT ·unsafe_New(SB),NOSPLIT,$0-0 + B runtime·newobject(SB) +TEXT ·unsafe_NewArray(SB),NOSPLIT,$0-0 + B runtime·newarray(SB) diff --git a/src/pkg/runtime/alg.goc b/src/pkg/runtime/alg.goc index 70c877ebbb..6207ae526c 100644 --- a/src/pkg/runtime/alg.goc +++ b/src/pkg/runtime/alg.goc @@ -308,6 +308,7 @@ runtime·nilintercopy(uintptr s, void *a, void *b) } extern uintptr runtime·nohashcode; +extern uintptr runtime·noequalcode; void runtime·noequal(bool *eq, uintptr s, void *a, void *b) @@ -371,6 +372,8 @@ void runtime·hashinit(void) { runtime·nohashcode = (uintptr)runtime·nohash; + runtime·noequalcode = (uintptr)runtime·noequal; + if(NaCl) return; diff --git a/src/pkg/runtime/iface.go b/src/pkg/runtime/iface.go new file mode 100644 index 0000000000..d3428e5a9c --- /dev/null +++ b/src/pkg/runtime/iface.go @@ -0,0 +1,469 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import ( + "unsafe" +) + +const ( + hashSize = 1009 +) + +var ( + ifaceLock lock // lock for accessing hash + hash [hashSize]*itab +) + +// fInterface is our standard non-empty interface. We use it instead +// of interface{f()} in function prototypes because gofmt insists on +// putting lots of newlines in the otherwise concise interface{f()}. +type fInterface interface { + f() +} + +func getitab(inter *interfacetype, typ *_type, canfail bool) *itab { + if len(inter.mhdr) == 0 { + gothrow("internal error - misuse of itab") + } + + // easy case + x := typ.x + if x == nil { + if canfail { + return nil + } + i := (*imethod)(add(unsafe.Pointer(inter), unsafe.Sizeof(interfacetype{}))) + panic(&TypeAssertionError{"", *typ._string, *inter.typ._string, *i.name}) + } + + // compiler has provided some good hash codes for us. + h := inter.typ.hash + h += 17 * typ.hash + // TODO(rsc): h += 23 * x.mhash ? + h %= hashSize + + // look twice - once without lock, once with. + // common case will be no lock contention. + var m *itab + var locked int + for locked = 0; locked < 2; locked++ { + if locked != 0 { + golock(&ifaceLock) + } + for m = (*itab)(goatomicloadp(unsafe.Pointer(&hash[h]))); m != nil; m = m.link { + if m.inter == inter && m._type == typ { + if m.bad != 0 { + m = nil + if !canfail { + // this can only happen if the conversion + // was already done once using the , ok form + // and we have a cached negative result. + // the cached result doesn't record which + // interface function was missing, so jump + // down to the interface check, which will + // do more work but give a better error. + goto search + } + } + if locked != 0 { + gounlock(&ifaceLock) + } + return m + } + } + } + + m = (*itab)(gopersistentalloc(unsafe.Sizeof(itab{}) + uintptr(len(inter.mhdr))*ptrSize)) + m.inter = inter + m._type = typ + +search: + // both inter and typ have method sorted by name, + // and interface names are unique, + // so can iterate over both in lock step; + // the loop is O(ni+nt) not O(ni*nt). + ni := len(inter.mhdr) + nt := len(x.mhdr) + j := 0 + for k := 0; k < ni; k++ { + i := (*imethod)(add(unsafe.Pointer(inter), unsafe.Sizeof(interfacetype{})+uintptr(k)*unsafe.Sizeof(imethod{}))) + iname := i.name + ipkgpath := i.pkgpath + itype := i._type + for ; j < nt; j++ { + t := (*method)(add(unsafe.Pointer(x), unsafe.Sizeof(uncommontype{})+uintptr(j)*unsafe.Sizeof(method{}))) + if t.mtyp == itype && t.name == iname && t.pkgpath == ipkgpath { + if m != nil { + f := (*func())(add(unsafe.Pointer(m), unsafe.Sizeof(itab{})+uintptr(k)*ptrSize)) + *f = t.ifn + } + goto nextimethod + } + } + // didn't find method + if !canfail { + if locked != 0 { + gounlock(&ifaceLock) + } + panic(&TypeAssertionError{"", *typ._string, *inter.typ._string, *iname}) + } + m.bad = 1 + break + nextimethod: + } + if locked == 0 { + gothrow("invalid itab locking") + } + m.link = hash[h] + goatomicstorep(unsafe.Pointer(&hash[h]), unsafe.Pointer(m)) + gounlock(&ifaceLock) + if m.bad != 0 { + return nil + } + return m +} + +func typ2Itab(t *_type, inter *interfacetype, cache **itab) *itab { + tab := getitab(inter, t, false) + goatomicstorep(unsafe.Pointer(cache), unsafe.Pointer(tab)) + return tab +} + +func convT2E(t *_type, elem unsafe.Pointer) (e interface{}) { + size := uintptr(t.size) + ep := (*eface)(unsafe.Pointer(&e)) + if size <= ptrSize { + ep._type = t + memmove(unsafe.Pointer(&ep.data), elem, size) + } else { + x := newobject(t) + // TODO: We allocate a zeroed object only to overwrite it with + // actual data. Figure out how to avoid zeroing. Also below in convT2I. + memmove(x, elem, size) + ep._type = t + ep.data = x + } + return +} + +func convT2I(t *_type, inter *interfacetype, cache **itab, elem unsafe.Pointer) (i fInterface) { + tab := (*itab)(goatomicloadp(unsafe.Pointer(cache))) + if tab == nil { + tab = getitab(inter, t, false) + goatomicstorep(unsafe.Pointer(cache), unsafe.Pointer(tab)) + } + size := uintptr(t.size) + pi := (*iface)(unsafe.Pointer(&i)) + if size <= ptrSize { + pi.tab = tab + memmove(unsafe.Pointer(&pi.data), elem, size) + } else { + x := newobject(t) + memmove(x, elem, size) + pi.tab = tab + pi.data = x + } + return +} + +// TODO: give these routines a pointer to the result area instead of writing +// extra data in the outargs section. Then we can get rid of go:nosplit. +//go:nosplit +func assertI2T(t *_type, i fInterface) (r struct{}) { + ip := (*iface)(unsafe.Pointer(&i)) + tab := ip.tab + if tab == nil { + panic(&TypeAssertionError{"", "", *t._string, ""}) + } + if tab._type != t { + panic(&TypeAssertionError{*tab.inter.typ._string, *tab._type._string, *t._string, ""}) + } + size := uintptr(t.size) + if size <= ptrSize { + memmove(unsafe.Pointer(&r), unsafe.Pointer(&ip.data), size) + } else { + memmove(unsafe.Pointer(&r), ip.data, size) + } + return +} + +//go:nosplit +func assertI2T2(t *_type, i fInterface) (r byte) { + ip := (*iface)(unsafe.Pointer(&i)) + size := uintptr(t.size) + ok := (*bool)(add(unsafe.Pointer(&r), size)) + tab := ip.tab + if tab == nil || tab._type != t { + *ok = false + memclr(unsafe.Pointer(&r), size) + return + } + *ok = true + if size <= ptrSize { + memmove(unsafe.Pointer(&r), unsafe.Pointer(&ip.data), size) + } else { + memmove(unsafe.Pointer(&r), ip.data, size) + } + return +} + +func assertI2TOK(t *_type, i fInterface) bool { + ip := (*iface)(unsafe.Pointer(&i)) + tab := ip.tab + return tab != nil && tab._type == t +} + +//go:nosplit +func assertE2T(t *_type, e interface{}) (r struct{}) { + ep := (*eface)(unsafe.Pointer(&e)) + if ep._type == nil { + panic(&TypeAssertionError{"", "", *t._string, ""}) + } + if ep._type != t { + panic(&TypeAssertionError{"", *ep._type._string, *t._string, ""}) + } + size := uintptr(t.size) + if size <= ptrSize { + memmove(unsafe.Pointer(&r), unsafe.Pointer(&ep.data), size) + } else { + memmove(unsafe.Pointer(&r), ep.data, size) + } + return +} + +//go:nosplit +func assertE2T2(t *_type, e interface{}) (r byte) { + ep := (*eface)(unsafe.Pointer(&e)) + size := uintptr(t.size) + ok := (*bool)(add(unsafe.Pointer(&r), size)) + if ep._type != t { + *ok = false + memclr(unsafe.Pointer(&r), size) + return + } + *ok = true + if size <= ptrSize { + memmove(unsafe.Pointer(&r), unsafe.Pointer(&ep.data), size) + } else { + memmove(unsafe.Pointer(&r), ep.data, size) + } + return +} + +func assertE2TOK(t *_type, e interface{}) bool { + ep := (*eface)(unsafe.Pointer(&e)) + return t == ep._type +} + +func convI2E(i fInterface) (r interface{}) { + ip := (*iface)(unsafe.Pointer(&i)) + tab := ip.tab + if tab == nil { + return + } + rp := (*eface)(unsafe.Pointer(&r)) + rp._type = tab._type + rp.data = ip.data + return +} + +func assertI2E(inter *interfacetype, i fInterface) (r interface{}) { + ip := (*iface)(unsafe.Pointer(&i)) + tab := ip.tab + if tab == nil { + // explicit conversions require non-nil interface value. + panic(&TypeAssertionError{"", "", *inter.typ._string, ""}) + } + rp := (*eface)(unsafe.Pointer(&r)) + rp._type = tab._type + rp.data = ip.data + return +} + +func assertI2E2(inter *interfacetype, i fInterface) (r interface{}, ok bool) { + ip := (*iface)(unsafe.Pointer(&i)) + tab := ip.tab + if tab == nil { + return + } + rp := (*eface)(unsafe.Pointer(&r)) + rp._type = tab._type + rp.data = ip.data + ok = true + return +} + +func convI2I(inter *interfacetype, i fInterface) (r fInterface) { + ip := (*iface)(unsafe.Pointer(&i)) + tab := ip.tab + if tab == nil { + return + } + rp := (*iface)(unsafe.Pointer(&r)) + if tab.inter == inter { + rp.tab = tab + rp.data = ip.data + return + } + rp.tab = getitab(inter, tab._type, false) + rp.data = ip.data + return +} + +func assertI2I(inter *interfacetype, i fInterface) (r fInterface) { + ip := (*iface)(unsafe.Pointer(&i)) + tab := ip.tab + if tab == nil { + // explicit conversions require non-nil interface value. + panic(&TypeAssertionError{"", "", *inter.typ._string, ""}) + } + rp := (*iface)(unsafe.Pointer(&r)) + if tab.inter == inter { + rp.tab = tab + rp.data = ip.data + return + } + rp.tab = getitab(inter, tab._type, false) + rp.data = ip.data + return +} + +func assertI2I2(inter *interfacetype, i fInterface) (r fInterface, ok bool) { + ip := (*iface)(unsafe.Pointer(&i)) + tab := ip.tab + if tab == nil { + return + } + rp := (*iface)(unsafe.Pointer(&r)) + if tab.inter == inter { + rp.tab = tab + rp.data = ip.data + ok = true + return + } + tab = getitab(inter, tab._type, true) + if tab == nil { + rp.data = nil + rp.tab = nil + ok = false + return + } + rp.tab = tab + rp.data = ip.data + ok = true + return +} + +func assertE2I(inter *interfacetype, e interface{}) (r fInterface) { + ep := (*eface)(unsafe.Pointer(&e)) + t := ep._type + if t == nil { + // explicit conversions require non-nil interface value. + panic(&TypeAssertionError{"", "", *inter.typ._string, ""}) + } + rp := (*iface)(unsafe.Pointer(&r)) + rp.tab = getitab(inter, t, false) + rp.data = ep.data + return +} + +func assertE2I2(inter *interfacetype, e interface{}) (r fInterface, ok bool) { + ep := (*eface)(unsafe.Pointer(&e)) + t := ep._type + if t == nil { + return + } + tab := getitab(inter, t, true) + if tab == nil { + return + } + rp := (*iface)(unsafe.Pointer(&r)) + rp.tab = tab + rp.data = ep.data + ok = true + return +} + +func reflect_ifaceE2I(inter *interfacetype, e interface{}, dst *fInterface) { + *dst = assertE2I(inter, e) +} + +func assertE2E(inter *interfacetype, e interface{}) interface{} { + ep := (*eface)(unsafe.Pointer(&e)) + if ep._type == nil { + // explicit conversions require non-nil interface value. + panic(&TypeAssertionError{"", "", *inter.typ._string, ""}) + } + return e +} + +func assertE2E2(inter *interfacetype, e interface{}) (interface{}, bool) { + ep := (*eface)(unsafe.Pointer(&e)) + if ep._type == nil { + return nil, false + } + return e, true +} + +func efaceeq(e1 interface{}, e2 interface{}) bool { + p1 := (*eface)(unsafe.Pointer(&e1)) + p2 := (*eface)(unsafe.Pointer(&e2)) + t := p1._type + if t != p2._type { + return false + } + if t == nil { + return true + } + + if *(*uintptr)(unsafe.Pointer(&t.alg.equal)) == noequalcode { + panic(errorString("comparing uncomparable type " + *t._string)) + } + size := uintptr(t.size) + if size <= ptrSize { + return goeq(t.alg, unsafe.Pointer(&p1.data), unsafe.Pointer(&p2.data), size) + } + return goeq(t.alg, p1.data, p2.data, size) +} + +func ifaceeq(i1 fInterface, i2 fInterface) bool { + p1 := (*iface)(unsafe.Pointer(&i1)) + p2 := (*iface)(unsafe.Pointer(&i2)) + tab := p1.tab + if tab != p2.tab { + return false + } + if tab == nil { + return true + } + t := tab._type + if *(*uintptr)(unsafe.Pointer(&t.alg.equal)) == noequalcode { + panic(errorString("comparing uncomparable type " + *t._string)) + } + size := uintptr(t.size) + if size <= ptrSize { + return goeq(t.alg, unsafe.Pointer(&p1.data), unsafe.Pointer(&p2.data), size) + } + return goeq(t.alg, p1.data, p2.data, size) +} + +func ifacethash(i fInterface) uint32 { + ip := (*iface)(unsafe.Pointer(&i)) + tab := ip.tab + if tab == nil { + return 0 + } + return tab._type.hash +} + +func efacethash(e interface{}) uint32 { + ep := (*eface)(unsafe.Pointer(&e)) + t := ep._type + if t == nil { + return 0 + } + return t.hash +} diff --git a/src/pkg/runtime/iface.goc b/src/pkg/runtime/iface.goc index 719d115880..a2e968fafa 100644 --- a/src/pkg/runtime/iface.goc +++ b/src/pkg/runtime/iface.goc @@ -10,9 +10,10 @@ package runtime #include "malloc.h" #include "../../cmd/ld/textflag.h" -static Itab* hash[1009]; -static Lock ifacelock; +extern Itab* runtime·hash[1009]; +extern Lock runtime·ifaceLock; +// TODO: delete this when no longer used (ifaceE2I2 is all that's left) static Itab* itab(InterfaceType *inter, Type *type, int32 canfail) { @@ -45,14 +46,14 @@ itab(InterfaceType *inter, Type *type, int32 canfail) h = inter->typ.hash; h += 17 * type->hash; // TODO(rsc): h += 23 * x->mhash ? - h %= nelem(hash); + h %= nelem(runtime·hash); // look twice - once without lock, once with. // common case will be no lock contention. for(locked=0; locked<2; locked++) { if(locked) - runtime·lock(&ifacelock); - for(m=runtime·atomicloadp(&hash[h]); m!=nil; m=m->link) { + runtime·lock(&runtime·ifaceLock); + for(m=runtime·atomicloadp(&runtime·hash[h]); m!=nil; m=m->link) { if(m->inter == inter && m->type == type) { if(m->bad) { m = nil; @@ -68,7 +69,7 @@ itab(InterfaceType *inter, Type *type, int32 canfail) } } if(locked) - runtime·unlock(&ifacelock); + runtime·unlock(&runtime·ifaceLock); return m; } } @@ -101,7 +102,7 @@ search: nil, type->string, inter->typ.string, iname, &err); if(locked) - runtime·unlock(&ifacelock); + runtime·unlock(&runtime·ifaceLock); runtime·panic(err); return nil; // not reached } @@ -118,9 +119,9 @@ search: out: if(!locked) runtime·panicstring("invalid itab locking"); - m->link = hash[h]; - runtime·atomicstorep(&hash[h], m); - runtime·unlock(&ifacelock); + m->link = runtime·hash[h]; + runtime·atomicstorep(&runtime·hash[h], m); + runtime·unlock(&runtime·ifaceLock); if(m->bad) return nil; return m; @@ -133,295 +134,16 @@ runtime·iterate_itabs(void (*callback)(Itab*)) int32 i; Itab *tab; - for(i = 0; i < nelem(hash); i++) { - for(tab = hash[i]; tab != nil; tab = tab->link) { + for(i = 0; i < nelem(runtime·hash); i++) { + for(tab = runtime·hash[i]; tab != nil; tab = tab->link) { callback(tab); } } } -static void -copyin(Type *t, void *src, void **dst) -{ - uintptr size; - void *p; - Alg *alg; - - size = t->size; - alg = t->alg; - - if(size <= sizeof(*dst)) - alg->copy(size, dst, src); - else { - p = runtime·cnew(t); - alg->copy(size, p, src); - *dst = p; - } -} - -static void -copyout(Type *t, void **src, void *dst) -{ - uintptr size; - Alg *alg; - - size = t->size; - alg = t->alg; - - if(size <= sizeof(*src)) - alg->copy(size, dst, src); - else - alg->copy(size, dst, *src); -} - -#pragma textflag NOSPLIT -func typ2Itab(t *Type, inter *InterfaceType, cache **Itab) (tab *Itab) { - tab = itab(inter, t, 0); - runtime·atomicstorep(cache, tab); -} - -#pragma textflag NOSPLIT -func convT2I(t *Type, inter *InterfaceType, cache **Itab, elem *byte) (ret Iface) { - Itab *tab; - - tab = runtime·atomicloadp(cache); - if(!tab) { - tab = itab(inter, t, 0); - runtime·atomicstorep(cache, tab); - } - ret.tab = tab; - copyin(t, elem, &ret.data); -} - -#pragma textflag NOSPLIT -func convT2E(t *Type, elem *byte) (ret Eface) { - ret.type = t; - copyin(t, elem, &ret.data); -} - -static void assertI2Tret(Type *t, Iface i, byte *ret); - -/* - * NOTE: Cannot use 'func' here, because we have to declare - * a return value, the only types we have are at least 1 byte large, - * goc2c will zero the return value, and the actual return value - * might have size 0 bytes, in which case the zeroing of the - * 1 or more bytes would be wrong. - * Using C lets us control (avoid) the initial zeroing. - */ -#pragma textflag NOSPLIT -void -runtime·assertI2T(Type *t, Iface i, GoOutput retbase) -{ - assertI2Tret(t, i, (byte*)&retbase); -} - -static void -assertI2Tret(Type *t, Iface i, byte *ret) -{ - Itab *tab; - Eface err; - - tab = i.tab; - if(tab == nil) { - runtime·newTypeAssertionError( - nil, nil, t->string, - nil, &err); - runtime·panic(err); - } - if(tab->type != t) { - runtime·newTypeAssertionError( - tab->inter->typ.string, tab->type->string, t->string, - nil, &err); - runtime·panic(err); - } - copyout(t, &i.data, ret); -} - -#pragma textflag NOSPLIT -func assertI2T2(t *Type, i Iface) (ret byte, ...) { - bool *ok; - int32 wid; - - wid = t->size; - ok = (bool*)(&ret + wid); - - if(i.tab == nil || i.tab->type != t) { - *ok = false; - runtime·memclr(&ret, wid); - return; - } - - *ok = true; - copyout(t, &i.data, &ret); -} - -func assertI2TOK(t *Type, i Iface) (ok bool) { - ok = i.tab!=nil && i.tab->type==t; -} - -static void assertE2Tret(Type *t, Eface e, byte *ret); - -/* - * NOTE: Cannot use 'func' here. See assertI2T above. - */ -#pragma textflag NOSPLIT -void -runtime·assertE2T(Type *t, Eface e, GoOutput retbase) -{ - assertE2Tret(t, e, (byte*)&retbase); -} - -static void -assertE2Tret(Type *t, Eface e, byte *ret) -{ - Eface err; - - if(e.type == nil) { - runtime·newTypeAssertionError( - nil, nil, t->string, - nil, &err); - runtime·panic(err); - } - if(e.type != t) { - runtime·newTypeAssertionError( - nil, e.type->string, t->string, - nil, &err); - runtime·panic(err); - } - copyout(t, &e.data, ret); -} - -#pragma textflag NOSPLIT -func assertE2T2(t *Type, e Eface) (ret byte, ...) { - bool *ok; - int32 wid; - - wid = t->size; - ok = (bool*)(&ret + wid); - - if(t != e.type) { - *ok = false; - runtime·memclr(&ret, wid); - return; - } - - *ok = true; - copyout(t, &e.data, &ret); -} - -func assertE2TOK(t *Type, e Eface) (ok bool) { - ok = t==e.type; -} - -func convI2E(i Iface) (ret Eface) { - Itab *tab; - - ret.data = i.data; - if((tab = i.tab) == nil) - ret.type = nil; - else - ret.type = tab->type; -} - -func assertI2E(inter *InterfaceType, i Iface) (ret Eface) { - Itab *tab; - Eface err; - - tab = i.tab; - if(tab == nil) { - // explicit conversions require non-nil interface value. - runtime·newTypeAssertionError( - nil, nil, inter->typ.string, - nil, &err); - runtime·panic(err); - } - ret.data = i.data; - ret.type = tab->type; -} - -func assertI2E2(inter *InterfaceType, i Iface) (ret Eface, ok bool) { - Itab *tab; - - USED(inter); - tab = i.tab; - if(tab == nil) { - ret.type = nil; - ok = 0; - } else { - ret.type = tab->type; - ok = 1; - } - ret.data = i.data; -} - -func convI2I(inter *InterfaceType, i Iface) (ret Iface) { - Itab *tab; - - ret.data = i.data; - if((tab = i.tab) == nil) - ret.tab = nil; - else if(tab->inter == inter) - ret.tab = tab; - else - ret.tab = itab(inter, tab->type, 0); -} - -void -runtime·ifaceI2I(InterfaceType *inter, Iface i, Iface *ret) -{ - Itab *tab; - Eface err; - - tab = i.tab; - if(tab == nil) { - // explicit conversions require non-nil interface value. - runtime·newTypeAssertionError( - nil, nil, inter->typ.string, - nil, &err); - runtime·panic(err); - } - ret->data = i.data; - ret->tab = itab(inter, tab->type, 0); -} - -func assertI2I(inter *InterfaceType, i Iface) (ret Iface) { - runtime·ifaceI2I(inter, i, &ret); -} - -func assertI2I2(inter *InterfaceType, i Iface) (ret Iface, ok bool) { - Itab *tab; - - tab = i.tab; - if(tab != nil && (tab->inter == inter || (tab = itab(inter, tab->type, 1)) != nil)) { - ret.data = i.data; - ret.tab = tab; - ok = 1; - } else { - ret.data = 0; - ret.tab = 0; - ok = 0; - } -} - -void -runtime·ifaceE2I(InterfaceType *inter, Eface e, Iface *ret) -{ - Type *t; - Eface err; - - t = e.type; - if(t == nil) { - // explicit conversions require non-nil interface value. - runtime·newTypeAssertionError( - nil, nil, inter->typ.string, - nil, &err); - runtime·panic(err); - } - ret->data = e.data; - ret->tab = itab(inter, t, 0); -} - +// Still in C because it is called from C for finalizers. This will +// get converted to Go in a separate CL. This is the last user of +// the C version of itab(). bool runtime·ifaceE2I2(InterfaceType *inter, Eface e, Iface *ret) { @@ -432,49 +154,6 @@ runtime·ifaceE2I2(InterfaceType *inter, Eface e, Iface *ret) return true; } -func reflect·ifaceE2I(inter *InterfaceType, e Eface, dst *Iface) { - runtime·ifaceE2I(inter, e, dst); -} - -func assertE2I(inter *InterfaceType, e Eface) (ret Iface) { - runtime·ifaceE2I(inter, e, &ret); -} - -func assertE2I2(inter *InterfaceType, e Eface) (ret Iface, ok bool) { - if(e.type == nil) { - ok = 0; - ret.data = nil; - ret.tab = nil; - } else if((ret.tab = itab(inter, e.type, 1)) == nil) { - ok = 0; - ret.data = nil; - } else { - ok = 1; - ret.data = e.data; - } -} - -func assertE2E(inter *InterfaceType, e Eface) (ret Eface) { - Type *t; - Eface err; - - t = e.type; - if(t == nil) { - // explicit conversions require non-nil interface value. - runtime·newTypeAssertionError( - nil, nil, inter->typ.string, - nil, &err); - runtime·panic(err); - } - ret = e; -} - -func assertE2E2(inter *InterfaceType, e Eface) (ret Eface, ok bool) { - USED(inter); - ret = e; - ok = e.type != nil; -} - static bool ifaceeq1(void *data1, void *data2, Type *t) { @@ -520,54 +199,3 @@ runtime·efaceeq_c(Eface e1, Eface e2) return true; return ifaceeq1(e1.data, e2.data, e1.type); } - -func ifaceeq(i1 Iface, i2 Iface) (ret bool) { - ret = runtime·ifaceeq_c(i1, i2); -} - -func efaceeq(e1 Eface, e2 Eface) (ret bool) { - ret = runtime·efaceeq_c(e1, e2); -} - -func ifacethash(i1 Iface) (ret uint32) { - Itab *tab; - - ret = 0; - tab = i1.tab; - if(tab != nil) - ret = tab->type->hash; -} - -func efacethash(e1 Eface) (ret uint32) { - Type *t; - - ret = 0; - t = e1.type; - if(t != nil) - ret = t->hash; -} - -func reflect·unsafe_Typeof(e Eface) (ret Eface) { - if(e.type == nil) { - ret.type = nil; - ret.data = nil; - } else { - ret = *(Eface*)(e.type); - } -} - -func reflect·unsafe_New(t *Type) (ret *byte) { - ret = runtime·cnew(t); -} - -func reflect·unsafe_NewArray(t *Type, n int) (ret *byte) { - ret = runtime·cnewarray(t, n); -} - -func reflect·typelinks() (ret Slice) { - extern Type *typelink[], *etypelink[]; - static int32 first = 1; - ret.array = (byte*)typelink; - ret.len = etypelink - typelink; - ret.cap = ret.len; -} diff --git a/src/pkg/runtime/stubs.go b/src/pkg/runtime/stubs.go index fee18f0470..77eece9433 100644 --- a/src/pkg/runtime/stubs.go +++ b/src/pkg/runtime/stubs.go @@ -72,6 +72,7 @@ var ( // memclr clears n bytes starting at ptr. // in memclr_*.s +//go:noescape func memclr(ptr unsafe.Pointer, n uintptr) func racemalloc(p unsafe.Pointer, size uintptr) @@ -79,6 +80,7 @@ func tracealloc(p unsafe.Pointer, size uintptr, typ *_type) // memmove copies n bytes from "from" to "to". // in memmove_*.s +//go:noescape func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr) // in asm_*.s @@ -124,8 +126,9 @@ var hashLoad = loadFactor //go:noescape func gomemeq(a, b unsafe.Pointer, size uintptr) bool -// Code pointer for the nohash algorithm. Used for producing better error messages. +// Code pointers for the nohash/noequal algorithms. Used for producing better error messages. var nohashcode uintptr +var noequalcode uintptr // Go version of runtime.throw. // in panic.c @@ -159,3 +162,7 @@ func noescape(p unsafe.Pointer) unsafe.Pointer { x := uintptr(p) return unsafe.Pointer(x ^ 0) } + +// gopersistentalloc allocates a permanent (not garbage collected) +// memory region of size n. Use wisely! +func gopersistentalloc(n uintptr) unsafe.Pointer diff --git a/src/pkg/runtime/stubs.goc b/src/pkg/runtime/stubs.goc index 42a4bf1434..8a043c63b0 100644 --- a/src/pkg/runtime/stubs.goc +++ b/src/pkg/runtime/stubs.goc @@ -89,3 +89,17 @@ func GCMask(x Eface) (mask Slice) { runtime·getgcmask(x.data, x.type, &mask.array, &mask.len); mask.cap = mask.len; } + +#pragma textflag NOSPLIT +func gopersistentalloc(size uintptr) (x *void) { + // TODO: used only for itabs for now. Need to make &mstats.other_sys arg parameterized. + x = runtime·persistentalloc(size, 0, &mstats.other_sys); +} + +#pragma textflag NOSPLIT +func reflect·typelinks() (ret Slice) { + extern Type *typelink[], *etypelink[]; + ret.array = (byte*)typelink; + ret.len = etypelink - typelink; + ret.cap = ret.len; +} From 12666cb91d619d85c32a4fb2308ba4c1dd235741 Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Thu, 7 Aug 2014 14:22:15 -0700 Subject: [PATCH 033/423] doc: add note about crypto/tls cert selection callback. CC=golang-codereviews https://golang.org/cl/123950043 --- doc/go1.4.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/go1.4.txt b/doc/go1.4.txt index 20d2a6b7ed..e480d9bcd5 100644 --- a/doc/go1.4.txt +++ b/doc/go1.4.txt @@ -8,6 +8,7 @@ Please keep the list sorted (as in sort.Strings of the lines). spec: permit for range x (CL 104680043) crypto/tls: add support for ALPN (RFC 7301) (CL 108710046) +crypto/tls: support programmatic selection of server certificates (CL 107400043) encoding/gob: remove unsafe (CL 102680045) misc: deleted editor support; refer to https://code.google.com/p/go-wiki/wiki/IDEsAndTextEditorPlugins instead (CL 105470043) os: implement symlink support for windows (CL 86160044) From 7aa4e5ac5fb3894e0eaf99fbc3704c32d934b199 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 7 Aug 2014 14:52:55 -0700 Subject: [PATCH 034/423] runtime: convert equality functions to Go LGTM=rsc R=rsc, khr CC=golang-codereviews https://golang.org/cl/121330043 --- src/cmd/gc/builtin.c | 13 +- src/cmd/gc/order.c | 13 ++ src/cmd/gc/reflect.c | 9 +- src/cmd/gc/runtime.go | 14 +-- src/cmd/gc/subr.c | 66 +++++----- src/cmd/gc/walk.c | 61 ++-------- src/pkg/runtime/alg.go | 100 +++++++++++++++ src/pkg/runtime/alg.goc | 210 ++++++-------------------------- src/pkg/runtime/asm_386.s | 43 +------ src/pkg/runtime/asm_amd64.s | 43 +------ src/pkg/runtime/asm_amd64p32.s | 43 +------ src/pkg/runtime/asm_arm.s | 54 +------- src/pkg/runtime/hashmap.go | 37 +++--- src/pkg/runtime/hashmap_fast.go | 12 +- src/pkg/runtime/iface.go | 42 ------- src/pkg/runtime/iface.goc | 46 ------- src/pkg/runtime/runtime.h | 26 ++-- src/pkg/runtime/stubs.go | 13 +- 18 files changed, 266 insertions(+), 579 deletions(-) diff --git a/src/cmd/gc/builtin.c b/src/cmd/gc/builtin.c index 4808269b7f..eba9199544 100644 --- a/src/cmd/gc/builtin.c +++ b/src/cmd/gc/builtin.c @@ -64,7 +64,6 @@ char *runtimeimport = "func @\"\".efaceeq (@\"\".i1·2 any, @\"\".i2·3 any) (@\"\".ret·1 bool)\n" "func @\"\".ifacethash (@\"\".i1·2 any) (@\"\".ret·1 uint32)\n" "func @\"\".efacethash (@\"\".i1·2 any) (@\"\".ret·1 uint32)\n" - "func @\"\".equal (@\"\".typ·2 *byte, @\"\".x1·3 any, @\"\".x2·4 any) (@\"\".ret·1 bool)\n" "func @\"\".makemap (@\"\".mapType·2 *byte, @\"\".hint·3 int64) (@\"\".hmap·1 map[any]any)\n" "func @\"\".mapaccess1 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 *any) (@\"\".val·1 *any)\n" "func @\"\".mapaccess1_fast32 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n" @@ -96,12 +95,12 @@ char *runtimeimport = "func @\"\".makeslice (@\"\".typ·2 *byte, @\"\".nel·3 int64, @\"\".cap·4 int64) (@\"\".ary·1 []any)\n" "func @\"\".growslice (@\"\".typ·2 *byte, @\"\".old·3 []any, @\"\".n·4 int64) (@\"\".ary·1 []any)\n" "func @\"\".memmove (@\"\".to·1 *any, @\"\".frm·2 *any, @\"\".length·3 uintptr)\n" - "func @\"\".memequal (@\"\".eq·1 *bool, @\"\".size·2 uintptr, @\"\".x·3 *any, @\"\".y·4 *any)\n" - "func @\"\".memequal8 (@\"\".eq·1 *bool, @\"\".size·2 uintptr, @\"\".x·3 *any, @\"\".y·4 *any)\n" - "func @\"\".memequal16 (@\"\".eq·1 *bool, @\"\".size·2 uintptr, @\"\".x·3 *any, @\"\".y·4 *any)\n" - "func @\"\".memequal32 (@\"\".eq·1 *bool, @\"\".size·2 uintptr, @\"\".x·3 *any, @\"\".y·4 *any)\n" - "func @\"\".memequal64 (@\"\".eq·1 *bool, @\"\".size·2 uintptr, @\"\".x·3 *any, @\"\".y·4 *any)\n" - "func @\"\".memequal128 (@\"\".eq·1 *bool, @\"\".size·2 uintptr, @\"\".x·3 *any, @\"\".y·4 *any)\n" + "func @\"\".memequal (@\"\".x·1 *any, @\"\".y·2 *any, @\"\".size·3 uintptr) (? bool)\n" + "func @\"\".memequal8 (@\"\".x·1 *any, @\"\".y·2 *any, @\"\".size·3 uintptr) (? bool)\n" + "func @\"\".memequal16 (@\"\".x·1 *any, @\"\".y·2 *any, @\"\".size·3 uintptr) (? bool)\n" + "func @\"\".memequal32 (@\"\".x·1 *any, @\"\".y·2 *any, @\"\".size·3 uintptr) (? bool)\n" + "func @\"\".memequal64 (@\"\".x·1 *any, @\"\".y·2 *any, @\"\".size·3 uintptr) (? bool)\n" + "func @\"\".memequal128 (@\"\".x·1 *any, @\"\".y·2 *any, @\"\".size·3 uintptr) (? bool)\n" "func @\"\".int64div (? int64, ? int64) (? int64)\n" "func @\"\".uint64div (? uint64, ? uint64) (? uint64)\n" "func @\"\".int64mod (? int64, ? int64) (? int64)\n" diff --git a/src/cmd/gc/order.c b/src/cmd/gc/order.c index 30dbc7dacc..728defe7c3 100644 --- a/src/cmd/gc/order.c +++ b/src/cmd/gc/order.c @@ -1055,6 +1055,19 @@ orderexpr(Node **np, Order *order) orderexpr(&n->left, order); n = ordercopyexpr(n, n->type, order, 1); break; + + case OEQ: + case ONE: + orderexpr(&n->left, order); + orderexpr(&n->right, order); + t = n->left->type; + if(t->etype == TSTRUCT || isfixedarray(t)) { + // for complex comparisons, we need both args to be + // addressable so we can pass them to the runtime. + orderaddrtemp(&n->left, order); + orderaddrtemp(&n->right, order); + } + break; } lineno = lno; diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c index 8170c15b62..6b3cd66bb6 100644 --- a/src/cmd/gc/reflect.c +++ b/src/cmd/gc/reflect.c @@ -1239,7 +1239,7 @@ static Sym* dalgsym(Type *t) { int ot; - Sym *s, *hash, *hashfunc, *eq; + Sym *s, *hash, *hashfunc, *eq, *eqfunc; char buf[100]; // dalgsym is only called for a type that needs an algorithm table, @@ -1251,15 +1251,18 @@ dalgsym(Type *t) eq = typesymprefix(".eq", t); geneq(eq, t); - // make Go func (a closure) for calling the hash function from Go + // make Go funcs (closures) for calling hash and equal from Go hashfunc = typesymprefix(".hashfunc", t); dsymptr(hashfunc, 0, hash, 0); ggloblsym(hashfunc, widthptr, DUPOK|RODATA); + eqfunc = typesymprefix(".eqfunc", t); + dsymptr(eqfunc, 0, eq, 0); + ggloblsym(eqfunc, widthptr, DUPOK|RODATA); // ../../pkg/runtime/runtime.h:/Alg ot = 0; ot = dsymptr(s, ot, hashfunc, 0); - ot = dsymptr(s, ot, eq, 0); + ot = dsymptr(s, ot, eqfunc, 0); ot = dsymptr(s, ot, pkglookup("memprint", runtimepkg), 0); switch(t->width) { default: diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go index 0257c3c7d6..7617eddd60 100644 --- a/src/cmd/gc/runtime.go +++ b/src/cmd/gc/runtime.go @@ -84,8 +84,6 @@ func efaceeq(i1 any, i2 any) (ret bool) func ifacethash(i1 any) (ret uint32) func efacethash(i1 any) (ret uint32) -func equal(typ *byte, x1, x2 any) (ret bool) - // *byte is really *runtime.Type func makemap(mapType *byte, hint int64) (hmap map[any]any) func mapaccess1(mapType *byte, hmap map[any]any, key *any) (val *any) @@ -124,12 +122,12 @@ func makeslice(typ *byte, nel int64, cap int64) (ary []any) func growslice(typ *byte, old []any, n int64) (ary []any) func memmove(to *any, frm *any, length uintptr) -func memequal(eq *bool, size uintptr, x, y *any) -func memequal8(eq *bool, size uintptr, x, y *any) -func memequal16(eq *bool, size uintptr, x, y *any) -func memequal32(eq *bool, size uintptr, x, y *any) -func memequal64(eq *bool, size uintptr, x, y *any) -func memequal128(eq *bool, size uintptr, x, y *any) +func memequal(x, y *any, size uintptr) bool +func memequal8(x, y *any, size uintptr) bool +func memequal16(x, y *any, size uintptr) bool +func memequal32(x, y *any, size uintptr) bool +func memequal64(x, y *any, size uintptr) bool +func memequal128(x, y *any, size uintptr) bool // only used on 32-bit func int64div(int64, int64) int64 diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index 0195f3d629..cd6c609567 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -2856,18 +2856,19 @@ genhash(Sym *sym, Type *t) } // Return node for -// if p.field != q.field { *eq = false; return } +// if p.field != q.field { return false } static Node* -eqfield(Node *p, Node *q, Node *field, Node *eq) +eqfield(Node *p, Node *q, Node *field) { - Node *nif, *nx, *ny; + Node *nif, *nx, *ny, *r; nx = nod(OXDOT, p, field); ny = nod(OXDOT, q, field); nif = nod(OIF, N, N); nif->ntest = nod(ONE, nx, ny); - nif->nbody = list(nif->nbody, nod(OAS, nod(OIND, eq, N), nodbool(0))); - nif->nbody = list(nif->nbody, nod(ORETURN, N, N)); + r = nod(ORETURN, N, N); + r->list = list(r->list, nodbool(0)); + nif->nbody = list(nif->nbody, r); return nif; } @@ -2896,11 +2897,11 @@ eqmemfunc(vlong size, Type *type) } // Return node for -// if memequal(size, &p.field, &q.field, eq); !*eq { return } +// if !memequal(&p.field, &q.field, size) { return false } static Node* -eqmem(Node *p, Node *q, Node *field, vlong size, Node *eq) +eqmem(Node *p, Node *q, Node *field, vlong size) { - Node *nif, *nx, *ny, *call; + Node *nif, *nx, *ny, *call, *r; nx = nod(OADDR, nod(OXDOT, p, field), N); nx->etype = 1; // does not escape @@ -2910,15 +2911,16 @@ eqmem(Node *p, Node *q, Node *field, vlong size, Node *eq) typecheck(&ny, Erv); call = nod(OCALL, eqmemfunc(size, nx->type->type), N); - call->list = list(call->list, eq); - call->list = list(call->list, nodintconst(size)); call->list = list(call->list, nx); call->list = list(call->list, ny); + call->list = list(call->list, nodintconst(size)); nif = nod(OIF, N, N); nif->ninit = list(nif->ninit, call); - nif->ntest = nod(ONOT, nod(OIND, eq, N), N); - nif->nbody = list(nif->nbody, nod(ORETURN, N, N)); + nif->ntest = nod(ONOT, call, N); + r = nod(ORETURN, N, N); + r->list = list(r->list, nodbool(0)); + nif->nbody = list(nif->nbody, r); return nif; } @@ -2928,7 +2930,7 @@ eqmem(Node *p, Node *q, Node *field, vlong size, Node *eq) void geneq(Sym *sym, Type *t) { - Node *n, *fn, *np, *neq, *nq, *tfn, *nif, *ni, *nx, *ny, *nrange; + Node *n, *fn, *np, *nq, *tfn, *nif, *ni, *nx, *ny, *nrange, *r; Type *t1, *first; int old_safemode; int64 size; @@ -2941,24 +2943,23 @@ geneq(Sym *sym, Type *t) dclcontext = PEXTERN; markdcl(); - // func sym(eq *bool, s uintptr, p, q *T) + // func sym(p, q *T, s uintptr) bool fn = nod(ODCLFUNC, N, N); fn->nname = newname(sym); fn->nname->class = PFUNC; tfn = nod(OTFUNC, N, N); fn->nname->ntype = tfn; - n = nod(ODCLFIELD, newname(lookup("eq")), typenod(ptrto(types[TBOOL]))); - tfn->list = list(tfn->list, n); - neq = n->left; - n = nod(ODCLFIELD, newname(lookup("s")), typenod(types[TUINTPTR])); - tfn->list = list(tfn->list, n); n = nod(ODCLFIELD, newname(lookup("p")), typenod(ptrto(t))); tfn->list = list(tfn->list, n); np = n->left; n = nod(ODCLFIELD, newname(lookup("q")), typenod(ptrto(t))); tfn->list = list(tfn->list, n); nq = n->left; + n = nod(ODCLFIELD, newname(lookup("s")), typenod(types[TUINTPTR])); + tfn->list = list(tfn->list, n); + n = nod(ODCLFIELD, N, typenod(types[TBOOL])); + tfn->rlist = list(tfn->rlist, n); funchdr(fn); @@ -2984,7 +2985,7 @@ geneq(Sym *sym, Type *t) colasdefn(nrange->list, nrange); ni = nrange->list->n; - // if p[i] != q[i] { *eq = false; return } + // if p[i] != q[i] { return false } nx = nod(OINDEX, np, ni); nx->bounded = 1; ny = nod(OINDEX, nq, ni); @@ -2992,13 +2993,11 @@ geneq(Sym *sym, Type *t) nif = nod(OIF, N, N); nif->ntest = nod(ONE, nx, ny); - nif->nbody = list(nif->nbody, nod(OAS, nod(OIND, neq, N), nodbool(0))); - nif->nbody = list(nif->nbody, nod(ORETURN, N, N)); + r = nod(ORETURN, N, N); + r->list = list(r->list, nodbool(0)); + nif->nbody = list(nif->nbody, r); nrange->nbody = list(nrange->nbody, nif); fn->nbody = list(fn->nbody, nrange); - - // *eq = true; - fn->nbody = list(fn->nbody, nod(OAS, nod(OIND, neq, N), nodbool(1))); break; case TSTRUCT: @@ -3023,16 +3022,16 @@ geneq(Sym *sym, Type *t) // cross-package unexported fields. if(first != T) { if(first->down == t1) { - fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq)); + fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym))); } else if(first->down->down == t1) { - fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq)); + fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym))); first = first->down; if(!isblanksym(first->sym)) - fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq)); + fn->nbody = list(fn->nbody, 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, neq)); + fn->nbody = list(fn->nbody, eqmem(np, nq, newname(first->sym), size)); } first = T; } @@ -3042,14 +3041,17 @@ geneq(Sym *sym, Type *t) continue; // Check this field, which is not just memory. - fn->nbody = list(fn->nbody, eqfield(np, nq, newname(t1->sym), neq)); + fn->nbody = list(fn->nbody, eqfield(np, nq, newname(t1->sym))); } - // *eq = true; - fn->nbody = list(fn->nbody, nod(OAS, nod(OIND, neq, N), nodbool(1))); break; } + // return true + r = nod(ORETURN, N, N); + r->list = list(r->list, nodbool(1)); + fn->nbody = list(fn->nbody, r); + if(debug['r']) dumplist("geneq body", fn->nbody); diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index be929e99ed..e50b917709 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -3013,10 +3013,10 @@ eqfor(Type *t) n = newname(sym); n->class = PFUNC; ntype = nod(OTFUNC, N, N); - ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(types[TBOOL])))); + ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(t)))); + ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(t)))); ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR]))); - ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(t)))); - ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(t)))); + ntype->rlist = list(ntype->rlist, nod(ODCLFIELD, N, typenod(types[TBOOL]))); typecheck(&ntype, Etype); n->type = ntype->type; return n; @@ -3037,10 +3037,9 @@ countfield(Type *t) static void walkcompare(Node **np, NodeList **init) { - Node *n, *l, *r, *fn, *call, *a, *li, *ri, *expr; + Node *n, *l, *r, *call, *a, *li, *ri, *expr; int andor, i; Type *t, *t1; - static Node *tempbool; n = *np; @@ -3058,8 +3057,9 @@ walkcompare(Node **np, NodeList **init) break; } - if(!islvalue(n->left) || !islvalue(n->right)) - goto hard; + if(!islvalue(n->left) || !islvalue(n->right)) { + fatal("arguments of comparison must be lvalues"); + } l = temp(ptrto(t)); a = nod(OAS, l, nod(OADDR, n->left, N)); @@ -3118,57 +3118,16 @@ walkcompare(Node **np, NodeList **init) goto ret; } - // Chose not to inline, but still have addresses. - // Call equality function directly. - // The equality function requires a bool pointer for - // storing its address, because it has to be callable - // from C, and C can't access an ordinary Go return value. - // To avoid creating many temporaries, cache one per function. - if(tempbool == N || tempbool->curfn != curfn) - tempbool = temp(types[TBOOL]); - + // Chose not to inline. Call equality function directly. call = nod(OCALL, eqfor(t), N); - a = nod(OADDR, tempbool, N); - a->etype = 1; // does not escape - call->list = list(call->list, a); - call->list = list(call->list, nodintconst(t->width)); call->list = list(call->list, l); call->list = list(call->list, r); - typecheck(&call, Etop); - walkstmt(&call); - *init = list(*init, call); - - // tempbool cannot be used directly as multiple comparison - // expressions may exist in the same statement. Create another - // temporary to hold the value (its address is not taken so it can - // be optimized away). - r = temp(types[TBOOL]); - a = nod(OAS, r, tempbool); - typecheck(&a, Etop); - walkstmt(&a); - *init = list(*init, a); - + call->list = list(call->list, nodintconst(t->width)); + r = call; if(n->op != OEQ) r = nod(ONOT, r, N); goto ret; -hard: - // Cannot take address of one or both of the operands. - // Instead, pass directly to runtime helper function. - // Easier on the stack than passing the address - // of temporary variables, because we are better at reusing - // the argument space than temporary variable space. - fn = syslook("equal", 1); - l = n->left; - r = n->right; - argtype(fn, n->left->type); - argtype(fn, n->left->type); - r = mkcall1(fn, n->type, init, typename(n->left->type), l, r); - if(n->op == ONE) { - r = nod(ONOT, r, N); - } - goto ret; - ret: typecheck(&r, Erv); walkexpr(&r, init); diff --git a/src/pkg/runtime/alg.go b/src/pkg/runtime/alg.go index ea4156f1ed..409f0fa0c5 100644 --- a/src/pkg/runtime/alg.go +++ b/src/pkg/runtime/alg.go @@ -142,6 +142,106 @@ func nilinterhash(a *eface, s, 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, size uintptr) bool { + return true +} +func memequal8(p, q unsafe.Pointer, size uintptr) bool { + return *(*int8)(p) == *(*int8)(q) +} +func memequal16(p, q unsafe.Pointer, size uintptr) bool { + return *(*int16)(p) == *(*int16)(q) +} +func memequal32(p, q unsafe.Pointer, size uintptr) bool { + return *(*int32)(p) == *(*int32)(q) +} +func memequal64(p, q unsafe.Pointer, size uintptr) bool { + return *(*int64)(p) == *(*int64)(q) +} +func memequal128(p, q unsafe.Pointer, size uintptr) bool { + return *(*[2]int64)(p) == *(*[2]int64)(q) +} +func f32equal(p, q unsafe.Pointer, size uintptr) bool { + return *(*float32)(p) == *(*float32)(q) +} +func f64equal(p, q unsafe.Pointer, size uintptr) bool { + return *(*float64)(p) == *(*float64)(q) +} +func c64equal(p, q unsafe.Pointer, size uintptr) bool { + return *(*complex64)(p) == *(*complex64)(q) +} +func c128equal(p, q unsafe.Pointer, size uintptr) bool { + return *(*complex128)(p) == *(*complex128)(q) +} +func strequal(p, q unsafe.Pointer, size uintptr) bool { + return *(*string)(p) == *(*string)(q) +} +func interequal(p, q unsafe.Pointer, size uintptr) bool { + return ifaceeq(*(*interface { + f() + })(p), *(*interface { + f() + })(q)) +} +func nilinterequal(p, q unsafe.Pointer, size uintptr) bool { + return efaceeq(*(*interface{})(p), *(*interface{})(q)) +} +func efaceeq(p, q interface{}) bool { + x := (*eface)(unsafe.Pointer(&p)) + y := (*eface)(unsafe.Pointer(&q)) + t := x._type + if t != y._type { + return false + } + if t == nil { + return true + } + eq := goalg(t.alg).equal + if **(**uintptr)(unsafe.Pointer(&eq)) == noequalcode { + // calling noequal will panic too, + // but we can print a better error. + panic(errorString("comparing uncomparable type " + *t._string)) + } + if uintptr(t.size) <= ptrSize { + return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)), uintptr(t.size)) + } + return eq(x.data, y.data, uintptr(t.size)) +} +func ifaceeq(p, q interface { + f() +}) bool { + x := (*iface)(unsafe.Pointer(&p)) + y := (*iface)(unsafe.Pointer(&q)) + xtab := x.tab + if xtab != y.tab { + return false + } + if xtab == nil { + return true + } + t := xtab._type + eq := goalg(t.alg).equal + if **(**uintptr)(unsafe.Pointer(&eq)) == noequalcode { + // calling noequal will panic too, + // but we can print a better error. + panic(errorString("comparing uncomparable type " + *t._string)) + } + if uintptr(t.size) <= ptrSize { + return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)), uintptr(t.size)) + } + return eq(x.data, y.data, uintptr(t.size)) +} + +func noequal(p, q unsafe.Pointer, size uintptr) bool { + panic(errorString("comparing uncomparable types")) +} + // Testing adapters for hash quality tests (see hash_test.go) func haveGoodHash() bool { return use_aeshash diff --git a/src/pkg/runtime/alg.goc b/src/pkg/runtime/alg.goc index 6207ae526c..f9e8892929 100644 --- a/src/pkg/runtime/alg.goc +++ b/src/pkg/runtime/alg.goc @@ -9,16 +9,6 @@ package runtime bool runtime·use_aeshash; -void -runtime·memequal(bool *eq, uintptr s, void *a, void *b) -{ - if(a == b) { - *eq = 1; - return; - } - *eq = runtime·memeq(a, b, s); -} - void runtime·memprint(uintptr s, void *a) { @@ -52,15 +42,6 @@ runtime·memcopy(uintptr s, void *a, void *b) runtime·memmove(a, b, s); } -void -runtime·memequal0(bool *eq, uintptr s, void *a, void *b) -{ - USED(s); - USED(a); - USED(b); - *eq = true; -} - void runtime·memcopy0(uintptr s, void *a, void *b) { @@ -69,13 +50,6 @@ runtime·memcopy0(uintptr s, void *a, void *b) USED(b); } -void -runtime·memequal8(bool *eq, uintptr s, void *a, void *b) -{ - USED(s); - *eq = *(uint8*)a == *(uint8*)b; -} - void runtime·memcopy8(uintptr s, void *a, void *b) { @@ -87,13 +61,6 @@ runtime·memcopy8(uintptr s, void *a, void *b) *(uint8*)a = *(uint8*)b; } -void -runtime·memequal16(bool *eq, uintptr s, void *a, void *b) -{ - USED(s); - *eq = *(uint16*)a == *(uint16*)b; -} - void runtime·memcopy16(uintptr s, void *a, void *b) { @@ -105,13 +72,6 @@ runtime·memcopy16(uintptr s, void *a, void *b) *(uint16*)a = *(uint16*)b; } -void -runtime·memequal32(bool *eq, uintptr s, void *a, void *b) -{ - USED(s); - *eq = *(uint32*)a == *(uint32*)b; -} - void runtime·memcopy32(uintptr s, void *a, void *b) { @@ -123,13 +83,6 @@ runtime·memcopy32(uintptr s, void *a, void *b) *(uint32*)a = *(uint32*)b; } -void -runtime·memequal64(bool *eq, uintptr s, void *a, void *b) -{ - USED(s); - *eq = *(uint64*)a == *(uint64*)b; -} - void runtime·memcopy64(uintptr s, void *a, void *b) { @@ -141,13 +94,6 @@ runtime·memcopy64(uintptr s, void *a, void *b) *(uint64*)a = *(uint64*)b; } -void -runtime·memequal128(bool *eq, uintptr s, void *a, void *b) -{ - USED(s); - *eq = ((uint64*)a)[0] == ((uint64*)b)[0] && ((uint64*)a)[1] == ((uint64*)b)[1]; -} - void runtime·memcopy128(uintptr s, void *a, void *b) { @@ -161,42 +107,6 @@ runtime·memcopy128(uintptr s, void *a, void *b) ((uint64*)a)[1] = ((uint64*)b)[1]; } -void -runtime·f32equal(bool *eq, uintptr s, void *a, void *b) -{ - USED(s); - *eq = *(float32*)a == *(float32*)b; -} - -void -runtime·f64equal(bool *eq, uintptr s, void *a, void *b) -{ - USED(s); - *eq = *(float64*)a == *(float64*)b; -} - -void -runtime·c64equal(bool *eq, uintptr s, void *a, void *b) -{ - Complex64 *ca, *cb; - - USED(s); - ca = a; - cb = b; - *eq = ca->real == cb->real && ca->imag == cb->imag; -} - -void -runtime·c128equal(bool *eq, uintptr s, void *a, void *b) -{ - Complex128 *ca, *cb; - - USED(s); - ca = a; - cb = b; - *eq = ca->real == cb->real && ca->imag == cb->imag; -} - void runtime·algslicecopy(uintptr s, void *a, void *b) { @@ -212,27 +122,6 @@ runtime·algslicecopy(uintptr s, void *a, void *b) ((Slice*)a)->cap = ((Slice*)b)->cap; } -void -runtime·strequal(bool *eq, uintptr s, void *a, void *b) -{ - intgo alen; - byte *s1, *s2; - - USED(s); - alen = ((String*)a)->len; - if(alen != ((String*)b)->len) { - *eq = false; - return; - } - s1 = ((String*)a)->str; - s2 = ((String*)b)->str; - if(s1 == s2) { - *eq = true; - return; - } - *eq = runtime·memeq(s1, s2, alen); -} - void runtime·strprint(uintptr s, void *a) { @@ -260,13 +149,6 @@ runtime·interprint(uintptr s, void *a) runtime·printiface_c(*(Iface*)a); } -void -runtime·interequal(bool *eq, uintptr s, void *a, void *b) -{ - USED(s); - *eq = runtime·ifaceeq_c(*(Iface*)a, *(Iface*)b); -} - void runtime·intercopy(uintptr s, void *a, void *b) { @@ -287,13 +169,6 @@ runtime·nilinterprint(uintptr s, void *a) runtime·printeface_c(*(Eface*)a); } -void -runtime·nilinterequal(bool *eq, uintptr s, void *a, void *b) -{ - USED(s); - *eq = runtime·efaceeq_c(*(Eface*)a, *(Eface*)b); -} - void runtime·nilintercopy(uintptr s, void *a, void *b) { @@ -310,16 +185,6 @@ runtime·nilintercopy(uintptr s, void *a, void *b) extern uintptr runtime·nohashcode; extern uintptr runtime·noequalcode; -void -runtime·noequal(bool *eq, uintptr s, void *a, void *b) -{ - USED(s); - USED(a); - USED(b); - USED(eq); - runtime·panicstring("comparing uncomparable types"); -} - static FuncVal memhashfunc = {(void*)runtime·memhash}; static FuncVal nohashfunc = {(void*)runtime·nohash}; static FuncVal strhashfunc = {(void*)runtime·strhash}; @@ -335,31 +200,48 @@ static FuncVal aeshash32func = {(void*)runtime·aeshash32}; static FuncVal aeshash64func = {(void*)runtime·aeshash64}; static FuncVal aeshashstrfunc = {(void*)runtime·aeshashstr}; +static FuncVal memequalfunc = {(void*)runtime·memequal}; +static FuncVal noequalfunc = {(void*)runtime·noequal}; +static FuncVal strequalfunc = {(void*)runtime·strequal}; +static FuncVal interequalfunc = {(void*)runtime·interequal}; +static FuncVal nilinterequalfunc = {(void*)runtime·nilinterequal}; +static FuncVal f32equalfunc = {(void*)runtime·f32equal}; +static FuncVal f64equalfunc = {(void*)runtime·f64equal}; +static FuncVal c64equalfunc = {(void*)runtime·c64equal}; +static FuncVal c128equalfunc = {(void*)runtime·c128equal}; +static FuncVal memequal0func = {(void*)runtime·memequal0}; +static FuncVal memequal8func = {(void*)runtime·memequal8}; +static FuncVal memequal16func = {(void*)runtime·memequal16}; +static FuncVal memequal32func = {(void*)runtime·memequal32}; +static FuncVal memequal64func = {(void*)runtime·memequal64}; +static FuncVal memequal128func = {(void*)runtime·memequal128}; + + Alg runtime·algarray[] = { -[AMEM] { &memhashfunc, runtime·memequal, runtime·memprint, runtime·memcopy }, -[ANOEQ] { &nohashfunc, runtime·noequal, runtime·memprint, runtime·memcopy }, -[ASTRING] { &strhashfunc, runtime·strequal, runtime·strprint, runtime·strcopy }, -[AINTER] { &interhashfunc, runtime·interequal, runtime·interprint, runtime·intercopy }, -[ANILINTER] { &nilinterhashfunc, runtime·nilinterequal, runtime·nilinterprint, runtime·nilintercopy }, -[ASLICE] { &nohashfunc, runtime·noequal, runtime·memprint, runtime·algslicecopy }, -[AFLOAT32] { &f32hashfunc, runtime·f32equal, runtime·memprint, runtime·memcopy }, -[AFLOAT64] { &f64hashfunc, runtime·f64equal, runtime·memprint, runtime·memcopy }, -[ACPLX64] { &c64hashfunc, runtime·c64equal, runtime·memprint, runtime·memcopy }, -[ACPLX128] { &c128hashfunc, runtime·c128equal, runtime·memprint, runtime·memcopy }, -[AMEM0] { &memhashfunc, runtime·memequal0, runtime·memprint, runtime·memcopy0 }, -[AMEM8] { &memhashfunc, runtime·memequal8, runtime·memprint, runtime·memcopy8 }, -[AMEM16] { &memhashfunc, runtime·memequal16, runtime·memprint, runtime·memcopy16 }, -[AMEM32] { &memhashfunc, runtime·memequal32, runtime·memprint, runtime·memcopy32 }, -[AMEM64] { &memhashfunc, runtime·memequal64, runtime·memprint, runtime·memcopy64 }, -[AMEM128] { &memhashfunc, runtime·memequal128, runtime·memprint, runtime·memcopy128 }, -[ANOEQ0] { &nohashfunc, runtime·noequal, runtime·memprint, runtime·memcopy0 }, -[ANOEQ8] { &nohashfunc, runtime·noequal, runtime·memprint, runtime·memcopy8 }, -[ANOEQ16] { &nohashfunc, runtime·noequal, runtime·memprint, runtime·memcopy16 }, -[ANOEQ32] { &nohashfunc, runtime·noequal, runtime·memprint, runtime·memcopy32 }, -[ANOEQ64] { &nohashfunc, runtime·noequal, runtime·memprint, runtime·memcopy64 }, -[ANOEQ128] { &nohashfunc, runtime·noequal, runtime·memprint, runtime·memcopy128 }, +[AMEM] { &memhashfunc, &memequalfunc, runtime·memprint, runtime·memcopy }, +[ANOEQ] { &nohashfunc, &noequalfunc, runtime·memprint, runtime·memcopy }, +[ASTRING] { &strhashfunc, &strequalfunc, runtime·strprint, runtime·strcopy }, +[AINTER] { &interhashfunc, &interequalfunc, runtime·interprint, runtime·intercopy }, +[ANILINTER] { &nilinterhashfunc, &nilinterequalfunc, runtime·nilinterprint, runtime·nilintercopy }, +[ASLICE] { &nohashfunc, &noequalfunc, runtime·memprint, runtime·algslicecopy }, +[AFLOAT32] { &f32hashfunc, &f32equalfunc, runtime·memprint, runtime·memcopy }, +[AFLOAT64] { &f64hashfunc, &f64equalfunc, runtime·memprint, runtime·memcopy }, +[ACPLX64] { &c64hashfunc, &c64equalfunc, runtime·memprint, runtime·memcopy }, +[ACPLX128] { &c128hashfunc, &c128equalfunc, runtime·memprint, runtime·memcopy }, +[AMEM0] { &memhashfunc, &memequal0func, runtime·memprint, runtime·memcopy0 }, +[AMEM8] { &memhashfunc, &memequal8func, runtime·memprint, runtime·memcopy8 }, +[AMEM16] { &memhashfunc, &memequal16func, runtime·memprint, runtime·memcopy16 }, +[AMEM32] { &memhashfunc, &memequal32func, runtime·memprint, runtime·memcopy32 }, +[AMEM64] { &memhashfunc, &memequal64func, runtime·memprint, runtime·memcopy64 }, +[AMEM128] { &memhashfunc, &memequal128func, runtime·memprint, runtime·memcopy128 }, +[ANOEQ0] { &nohashfunc, &noequalfunc, runtime·memprint, runtime·memcopy0 }, +[ANOEQ8] { &nohashfunc, &noequalfunc, runtime·memprint, runtime·memcopy8 }, +[ANOEQ16] { &nohashfunc, &noequalfunc, runtime·memprint, runtime·memcopy16 }, +[ANOEQ32] { &nohashfunc, &noequalfunc, runtime·memprint, runtime·memcopy32 }, +[ANOEQ64] { &nohashfunc, &noequalfunc, runtime·memprint, runtime·memcopy64 }, +[ANOEQ128] { &nohashfunc, &noequalfunc, runtime·memprint, runtime·memcopy128 }, }; // Runtime helpers. @@ -406,20 +288,6 @@ runtime·hashinit(void) } } -// func equal(t *Type, x T, y T) (ret bool) -#pragma textflag NOSPLIT -void -runtime·equal(Type *t, ...) -{ - byte *x, *y; - bool *ret; - - x = (byte*)ROUND((uintptr)(&t+1), t->align); - y = x + t->size; - ret = (bool*)ROUND((uintptr)(y+t->size), Structrnd); - t->alg->equal(ret, t->size, x, y); -} - // Testing adapter for memclr func memclrBytes(s Slice) { runtime·memclr(s.array, s.len); diff --git a/src/pkg/runtime/asm_386.s b/src/pkg/runtime/asm_386.s index d2c6e30469..0607bc8021 100644 --- a/src/pkg/runtime/asm_386.s +++ b/src/pkg/runtime/asm_386.s @@ -1149,13 +1149,7 @@ DATA shifts<>+0xfc(SB)/4, $0xff0f0e0d GLOBL shifts<>(SB),RODATA,$256 -TEXT runtime·memeq(SB),NOSPLIT,$0-12 - MOVL a+0(FP), SI - MOVL b+4(FP), DI - MOVL count+8(FP), BX - JMP runtime·memeqbody(SB) - -TEXT runtime·gomemeq(SB),NOSPLIT,$0-13 +TEXT runtime·memeq(SB),NOSPLIT,$0-13 MOVL a+0(FP), SI MOVL b+4(FP), DI MOVL size+8(FP), BX @@ -2266,38 +2260,3 @@ TEXT runtime·fastrand2(SB), NOSPLIT, $0-4 MOVL DX, m_fastrand(AX) MOVL DX, ret+0(FP) RET - -// The goeq trampoline is necessary while we have -// both Go and C calls to alg functions. Once we move all call -// sites to Go, we can redo the eq functions to use the -// Go calling convention and remove this. - -// convert call to: -// func (alg unsafe.Pointer, p, q unsafe.Pointer, size uintptr) bool -// to: -// func (eq *bool, size uintptr, p, q unsafe.Pointer) -TEXT runtime·goeq(SB), NOSPLIT, $16-17 - FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_goeq<>(SB) - FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_goeq<>(SB) - MOVL alg+0(FP), AX - MOVL alg_equal(AX), AX - MOVL p+4(FP), CX - MOVL q+8(FP), DX - MOVL size+12(FP), DI - LEAL ret+16(FP), SI - MOVL SI, 0(SP) - MOVL DI, 4(SP) - MOVL CX, 8(SP) - MOVL DX, 12(SP) - PCDATA $PCDATA_StackMapIndex, $0 - CALL *AX - RET - -DATA gcargs_goeq<>+0x00(SB)/4, $1 // 1 stackmap -DATA gcargs_goeq<>+0x04(SB)/4, $10 // 5 args -DATA gcargs_goeq<>+0x08(SB)/4, $(const_BitsPointer+(const_BitsPointer<<2)+(const_BitsPointer<<4)) -GLOBL gcargs_goeq<>(SB),RODATA,$12 - -DATA gclocals_goeq<>+0x00(SB)/4, $1 // 1 stackmap -DATA gclocals_goeq<>+0x04(SB)/4, $0 // 0 locals -GLOBL gclocals_goeq<>(SB),RODATA,$8 diff --git a/src/pkg/runtime/asm_amd64.s b/src/pkg/runtime/asm_amd64.s index 19e9f1d3a2..0fd21d1795 100644 --- a/src/pkg/runtime/asm_amd64.s +++ b/src/pkg/runtime/asm_amd64.s @@ -1117,13 +1117,7 @@ DATA shifts<>+0xf0(SB)/8, $0x0807060504030201 DATA shifts<>+0xf8(SB)/8, $0xff0f0e0d0c0b0a09 GLOBL shifts<>(SB),RODATA,$256 -TEXT runtime·memeq(SB),NOSPLIT,$0-24 - MOVQ a+0(FP), SI - MOVQ b+8(FP), DI - MOVQ count+16(FP), BX - JMP runtime·memeqbody(SB) - -TEXT runtime·gomemeq(SB),NOSPLIT,$0-25 +TEXT runtime·memeq(SB),NOSPLIT,$0-25 MOVQ a+0(FP), SI MOVQ b+8(FP), DI MOVQ size+16(FP), BX @@ -2305,38 +2299,3 @@ TEXT runtime·fastrand2(SB), NOSPLIT, $0-4 MOVL DX, m_fastrand(AX) MOVL DX, ret+0(FP) RET - -// goeq trampoline is necessary while we have -// both Go and C calls to alg functions. Once we move all call -// sites to Go, we can redo the eq function to use the -// Go calling convention and remove this. - -// convert call to: -// func (alg unsafe.Pointer, p, q unsafe.Pointer, size uintptr) bool -// to: -// func (eq *bool, size uintptr, p, q unsafe.Pointer) -TEXT runtime·goeq(SB), NOSPLIT, $32-33 - FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_goeq<>(SB) - FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_goeq<>(SB) - MOVQ alg+0(FP), AX - MOVQ alg_equal(AX), AX - MOVQ p+8(FP), CX - MOVQ q+16(FP), DX - MOVQ size+24(FP), DI - LEAQ ret+32(FP), SI - MOVQ SI, 0(SP) - MOVQ DI, 8(SP) - MOVQ CX, 16(SP) - MOVQ DX, 24(SP) - PCDATA $PCDATA_StackMapIndex, $0 - CALL *AX - RET - -DATA gcargs_goeq<>+0x00(SB)/4, $1 // 1 stackmap -DATA gcargs_goeq<>+0x04(SB)/4, $10 // 5 args -DATA gcargs_goeq<>+0x08(SB)/4, $(const_BitsPointer+(const_BitsPointer<<2)+(const_BitsPointer<<4)) -GLOBL gcargs_goeq<>(SB),RODATA,$12 - -DATA gclocals_goeq<>+0x00(SB)/4, $1 // 1 stackmap -DATA gclocals_goeq<>+0x04(SB)/4, $0 // 0 locals -GLOBL gclocals_goeq<>(SB),RODATA,$8 diff --git a/src/pkg/runtime/asm_amd64p32.s b/src/pkg/runtime/asm_amd64p32.s index f2a1f2a0bc..69e050f90d 100644 --- a/src/pkg/runtime/asm_amd64p32.s +++ b/src/pkg/runtime/asm_amd64p32.s @@ -775,13 +775,7 @@ TEXT runtime·aeshash32(SB),NOSPLIT,$0-24 TEXT runtime·aeshash64(SB),NOSPLIT,$0-24 RET -TEXT runtime·memeq(SB),NOSPLIT,$0-12 - MOVL a+0(FP), SI - MOVL b+4(FP), DI - MOVL count+8(FP), BX - JMP runtime·memeqbody(SB) - -TEXT runtime·gomemeq(SB),NOSPLIT,$0-17 +TEXT runtime·memeq(SB),NOSPLIT,$0-17 MOVL a+0(FP), SI MOVL b+4(FP), DI MOVL size+8(FP), BX @@ -1180,38 +1174,3 @@ TEXT runtime·fastrand2(SB), NOSPLIT, $0-4 MOVL DX, m_fastrand(AX) MOVL DX, ret+0(FP) RET - -// The goeq trampoline is necessary while we have -// both Go and C calls to alg functions. Once we move all call -// sites to Go, we can redo the eq functions to use the -// Go calling convention and remove this. - -// convert call to: -// func (alg unsafe.Pointer, p, q unsafe.Pointer, size uintptr) bool -// to: -// func (eq *bool, size uintptr, p, q unsafe.Pointer) -TEXT runtime·goeq(SB), NOSPLIT, $16-17 - FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_goeq<>(SB) - FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_goeq<>(SB) - MOVL alg+0(FP), AX - MOVL alg_equal(AX), AX - MOVL p+4(FP), CX - MOVL q+8(FP), DX - MOVL size+12(FP), DI - LEAL ret+16(FP), SI - MOVL SI, 0(SP) - MOVL DI, 4(SP) - MOVL CX, 8(SP) - MOVL DX, 12(SP) - PCDATA $PCDATA_StackMapIndex, $0 - CALL *AX - RET - -DATA gcargs_goeq<>+0x00(SB)/4, $1 // 1 stackmap -DATA gcargs_goeq<>+0x04(SB)/4, $10 // 5 args -DATA gcargs_goeq<>+0x08(SB)/4, $(const_BitsPointer+(const_BitsPointer<<2)+(const_BitsPointer<<4)) -GLOBL gcargs_goeq<>(SB),RODATA,$12 - -DATA gclocals_goeq<>+0x00(SB)/4, $1 // 1 stackmap -DATA gclocals_goeq<>+0x04(SB)/4, $0 // 0 locals -GLOBL gclocals_goeq<>(SB),RODATA,$8 diff --git a/src/pkg/runtime/asm_arm.s b/src/pkg/runtime/asm_arm.s index 406a426078..324b27b18f 100644 --- a/src/pkg/runtime/asm_arm.s +++ b/src/pkg/runtime/asm_arm.s @@ -703,24 +703,7 @@ TEXT runtime·aeshashstr(SB),NOSPLIT,$-4-0 MOVW $0, R0 MOVW (R0), R1 -TEXT runtime·memeq(SB),NOSPLIT,$-4-12 - MOVW a+0(FP), R1 - MOVW b+4(FP), R2 - MOVW n+8(FP), R3 - ADD R1, R3, R6 - MOVW $1, R0 -_next: - CMP R1, R6 - RET.EQ - MOVBU.P 1(R1), R4 - MOVBU.P 1(R2), R5 - CMP R4, R5 - BEQ _next - - MOVW $0, R0 - RET - -TEXT runtime·gomemeq(SB),NOSPLIT,$-4-13 +TEXT runtime·memeq(SB),NOSPLIT,$-4-13 MOVW a+0(FP), R1 MOVW b+4(FP), R2 MOVW size+8(FP), R3 @@ -1268,38 +1251,3 @@ TEXT runtime·fastrand2(SB), NOSPLIT, $-4-4 MOVW R0, m_fastrand(R1) MOVW R0, ret+0(FP) RET - -// The goeq trampoline is necessary while we have -// both Go and C calls to alg functions. Once we move all call -// sites to Go, we can redo the eq functions to use the -// Go calling convention and remove this. - -// convert call to: -// func (alg unsafe.Pointer, p, q unsafe.Pointer, size uintptr) bool -// to: -// func (eq *bool, size uintptr, p, q unsafe.Pointer) -TEXT runtime·goeq(SB), NOSPLIT, $16-17 - FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_goeq<>(SB) - FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_goeq<>(SB) - MOVW alg+0(FP), R0 - MOVW alg_equal(R0), R0 - MOVW p+4(FP), R1 - MOVW q+8(FP), R2 - MOVW size+12(FP), R3 - ADD $40, R13, R4 - MOVW R4, 4(R13) - MOVW R3, 8(R13) - MOVW R2, 12(R13) - MOVW R1, 16(R13) - PCDATA $PCDATA_StackMapIndex, $0 - BL (R0) - RET - -DATA gcargs_goeq<>+0x00(SB)/4, $1 // 1 stackmap -DATA gcargs_goeq<>+0x04(SB)/4, $10 // 5 args -DATA gcargs_goeq<>+0x08(SB)/4, $(const_BitsPointer+(const_BitsPointer<<2)+(const_BitsPointer<<4)) -GLOBL gcargs_goeq<>(SB),RODATA,$12 - -DATA gclocals_goeq<>+0x00(SB)/4, $1 // 1 stackmap -DATA gclocals_goeq<>+0x04(SB)/4, $0 // 0 locals -GLOBL gclocals_goeq<>(SB),RODATA,$8 diff --git a/src/pkg/runtime/hashmap.go b/src/pkg/runtime/hashmap.go index 6706290974..9dcf48242f 100644 --- a/src/pkg/runtime/hashmap.go +++ b/src/pkg/runtime/hashmap.go @@ -243,7 +243,8 @@ func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { if h == nil || h.count == 0 { return unsafe.Pointer(t.elem.zero) } - hash := goalg(t.key.alg).hash(key, uintptr(t.key.size), uintptr(h.hash0)) + alg := goalg(t.key.alg) + hash := alg.hash(key, uintptr(t.key.size), uintptr(h.hash0)) m := uintptr(1)<data = e.data; return true; } - -static bool -ifaceeq1(void *data1, void *data2, Type *t) -{ - uintptr size; - Alg *alg; - Eface err; - bool eq; - - alg = t->alg; - size = t->size; - - if(alg->equal == runtime·noequal) { - // calling noequal will panic too, - // but we can print a better error. - runtime·newErrorString(runtime·catstring(runtime·gostringnocopy((byte*)"comparing uncomparable type "), *t->string), &err); - runtime·panic(err); - } - - eq = 0; - if(size <= sizeof(data1)) - alg->equal(&eq, size, &data1, &data2); - else - alg->equal(&eq, size, data1, data2); - return eq; -} - -bool -runtime·ifaceeq_c(Iface i1, Iface i2) -{ - if(i1.tab != i2.tab) - return false; - if(i1.tab == nil) - return true; - return ifaceeq1(i1.data, i2.data, i1.tab->type); -} - -bool -runtime·efaceeq_c(Eface e1, Eface e2) -{ - if(e1.type != e2.type) - return false; - if(e1.type == nil) - return true; - return ifaceeq1(e1.data, e2.data, e1.type); -} diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h index b85198f480..62100a783a 100644 --- a/src/pkg/runtime/runtime.h +++ b/src/pkg/runtime/runtime.h @@ -634,7 +634,7 @@ typedef struct Alg Alg; struct Alg { FuncVal* hash; - void (*equal)(bool*, uintptr, void*, void*); + FuncVal* equal; void (*print)(uintptr, void*); void (*copy)(uintptr, void*, void*); }; @@ -665,13 +665,21 @@ void runtime·aeshash32(void*, uintptr, uintptr, uintptr); void runtime·aeshash64(void*, uintptr, uintptr, uintptr); void runtime·aeshashstr(void*, uintptr, uintptr, uintptr); -void runtime·memequal(bool*, uintptr, void*, void*); -void runtime·noequal(bool*, uintptr, void*, void*); -void runtime·strequal(bool*, uintptr, void*, void*); -void runtime·interequal(bool*, uintptr, void*, void*); -void runtime·nilinterequal(bool*, uintptr, void*, void*); - -bool runtime·memeq(void*, void*, uintptr); +void runtime·memequal(void*, void*, uintptr, bool); +void runtime·noequal(void*, void*, uintptr, bool); +void runtime·strequal(void*, void*, uintptr, bool); +void runtime·interequal(void*, void*, uintptr, bool); +void runtime·nilinterequal(void*, void*, uintptr, bool); +void runtime·f32equal(void*, void*, uintptr, bool); +void runtime·f64equal(void*, void*, uintptr, bool); +void runtime·c64equal(void*, void*, uintptr, bool); +void runtime·c128equal(void*, void*, uintptr, bool); +void runtime·memequal0(void*, void*, uintptr, bool); +void runtime·memequal8(void*, void*, uintptr, bool); +void runtime·memequal16(void*, void*, uintptr, bool); +void runtime·memequal32(void*, void*, uintptr, bool); +void runtime·memequal64(void*, void*, uintptr, bool); +void runtime·memequal128(void*, void*, uintptr, bool); void runtime·memprint(uintptr, void*); void runtime·strprint(uintptr, void*); @@ -873,8 +881,6 @@ MCache* runtime·allocmcache(void); void runtime·freemcache(MCache*); void runtime·mallocinit(void); void runtime·chaninit(void); -bool runtime·ifaceeq_c(Iface, Iface); -bool runtime·efaceeq_c(Eface, Eface); void* runtime·mallocgc(uintptr size, Type* typ, uint32 flag); void runtime·runpanic(Panic*); uintptr runtime·getcallersp(void*); diff --git a/src/pkg/runtime/stubs.go b/src/pkg/runtime/stubs.go index 77eece9433..9c18434d5d 100644 --- a/src/pkg/runtime/stubs.go +++ b/src/pkg/runtime/stubs.go @@ -111,20 +111,12 @@ func starttheworld() func stoptheworld() func clearpools() -// in asm_*.s -//go:noescape -func gohash(a *alg, p unsafe.Pointer, size uintptr, seed uintptr) uintptr - -// in asm_*.s -//go:noescape -func goeq(alg *alg, p, q unsafe.Pointer, size uintptr) bool - // exported value for testing var hashLoad = loadFactor // in asm_*.s //go:noescape -func gomemeq(a, b unsafe.Pointer, size uintptr) bool +func memeq(a, b unsafe.Pointer, size uintptr) bool // Code pointers for the nohash/noequal algorithms. Used for producing better error messages. var nohashcode uintptr @@ -147,6 +139,9 @@ type goalgtype struct { // function for hashing objects of this type // (ptr to object, size, seed) -> hash hash func(unsafe.Pointer, uintptr, uintptr) uintptr + // function for comparing objects of this type + // (ptr to object A, ptr to object B, size) -> ==? + equal func(unsafe.Pointer, unsafe.Pointer, uintptr) bool } func goalg(a *alg) *goalgtype { From 750bf48a5a5d2f7d0e00752544800ac09453b65f Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 7 Aug 2014 15:05:20 -0700 Subject: [PATCH 035/423] cmd/go: don't pass --buildid=none on OpenBSD According to the OpenBSD builder, it doesn't work. TBR=bradfitz CC=golang-codereviews https://golang.org/cl/126830043 --- src/cmd/go/build.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go index 88c2e29490..00df6b2915 100644 --- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -2324,7 +2324,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles // systems likely to support it, which is to say, systems that // normally use gold or the GNU linker. switch goos { - case "android", "dragonfly", "linux", "netbsd", "openbsd": + case "android", "dragonfly", "linux", "netbsd": ldflags = append(ldflags, "-Wl,--build-id=none") } From 10c2f56bf968884db3883a0c0b2a20f964a0ad4c Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Fri, 8 Aug 2014 08:56:40 +1000 Subject: [PATCH 036/423] cmd/go: download test dependencies of all named packages Fixes #8181. LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/123870043 --- src/cmd/go/get.go | 4 +++- src/cmd/go/test.bash | 11 +++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/cmd/go/get.go b/src/cmd/go/get.go index e708fcf779..a34286f540 100644 --- a/src/cmd/go/get.go +++ b/src/cmd/go/get.go @@ -151,7 +151,9 @@ func download(arg string, stk *importStack, getTestDeps bool) { } // Only process each package once. - if downloadCache[arg] { + // (Unless we're fetching test dependencies for this package, + // in which case we want to process it again.) + if downloadCache[arg] && !getTestDeps { return } downloadCache[arg] = true diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash index e5ba12b1df..411ef1863f 100755 --- a/src/cmd/go/test.bash +++ b/src/cmd/go/test.bash @@ -543,6 +543,17 @@ TEST go get cover unset GOPATH rm -rf $d +TEST go get -t "code.google.com/p/go-get-issue-8181/{a,b}" +d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX) +export GOPATH=$d +if ./testgo get -t code.google.com/p/go-get-issue-8181/{a,b}; then + ./testgo list ... | grep go.tools/godoc > /dev/null || ok=false +else + ok=false +fi +unset GOPATH +rm -rf $d + TEST shadowing logic export GOPATH=$(pwd)/testdata/shadow/root1:$(pwd)/testdata/shadow/root2 From f3fa0bbd1f011c7436f21a18ee08f719a15b02b8 Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Fri, 8 Aug 2014 08:57:18 +1000 Subject: [PATCH 037/423] flag: mention -h in docs Fixes #8314. LGTM=r R=r CC=golang-codereviews https://golang.org/cl/125820043 --- src/pkg/flag/flag.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pkg/flag/flag.go b/src/pkg/flag/flag.go index fa7760550c..de2d91f8b1 100644 --- a/src/pkg/flag/flag.go +++ b/src/pkg/flag/flag.go @@ -73,7 +73,8 @@ import ( "time" ) -// ErrHelp is the error returned if the flag -help is invoked but no such flag is defined. +// ErrHelp is the error returned if the -help or -h flag is invoked +// but no such flag is defined. var ErrHelp = errors.New("flag: help requested") // -- bool Value @@ -788,7 +789,7 @@ func (f *FlagSet) parseOne() (bool, error) { // Parse parses flag definitions from the argument list, which should not // include the command name. Must be called after all flags in the FlagSet // are defined and before flags are accessed by the program. -// The return value will be ErrHelp if -help was set but not defined. +// The return value will be ErrHelp if -help or -h were set but not defined. func (f *FlagSet) Parse(arguments []string) error { f.parsed = true f.args = arguments From 77a8dcab03c1bf8efa5cafaa2d9dc0a9f7a3dcf6 Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Fri, 8 Aug 2014 08:57:41 +1000 Subject: [PATCH 038/423] encoding/json: document coercion of invalid UTF-8 characters Fixes #8342. LGTM=iant R=golang-codereviews, iant CC=golang-codereviews https://golang.org/cl/122180043 --- src/pkg/encoding/json/encode.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pkg/encoding/json/encode.go b/src/pkg/encoding/json/encode.go index 741ddd89cb..5341a3a01b 100644 --- a/src/pkg/encoding/json/encode.go +++ b/src/pkg/encoding/json/encode.go @@ -40,8 +40,8 @@ import ( // // Floating point, integer, and Number values encode as JSON numbers. // -// String values encode as JSON strings. InvalidUTF8Error will be returned -// if an invalid UTF-8 sequence is encountered. +// String values encode as JSON strings coerced to valid UTF-8, +// replacing invalid bytes with the Unicode replacement rune. // The angle brackets "<" and ">" are escaped to "\u003c" and "\u003e" // to keep some browsers from misinterpreting JSON output as HTML. // Ampersand "&" is also escaped to "\u0026" for the same reason. From 6fb2a05ac9f6b4063f1c952df069871e9e6796d9 Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Fri, 8 Aug 2014 10:09:31 +1000 Subject: [PATCH 039/423] os: simplify windows Getwd (fixes build) Current version of Getwd calls Stat that calls Getwd therefore infinite recursion. LGTM=minux R=golang-codereviews, minux CC=golang-codereviews https://golang.org/cl/119600043 --- src/pkg/os/getwd.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/pkg/os/getwd.go b/src/pkg/os/getwd.go index eacb414660..d5da53b34b 100644 --- a/src/pkg/os/getwd.go +++ b/src/pkg/os/getwd.go @@ -5,6 +5,7 @@ package os import ( + "runtime" "sync" "syscall" ) @@ -23,6 +24,10 @@ var useSyscallwd = func(error) bool { return true } // reached via multiple paths (due to symbolic links), // Getwd may return any one of them. func Getwd() (dir string, err error) { + if runtime.GOOS == "windows" { + return syscall.Getwd() + } + // Clumsy but widespread kludge: // if $PWD is set and matches ".", use it. dot, err := Stat(".") From be96e52cce0723dac8288f8ef7ea5565492dc679 Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Thu, 7 Aug 2014 21:48:34 -0400 Subject: [PATCH 040/423] misc/nacl/testzip.proto: include cmd/internal/* to fix build LGTM=adg, dave R=golang-codereviews, adg, dave CC=golang-codereviews https://golang.org/cl/123050043 --- misc/nacl/testzip.proto | 2 ++ 1 file changed, 2 insertions(+) diff --git a/misc/nacl/testzip.proto b/misc/nacl/testzip.proto index 57c2e1b08a..596f50303c 100644 --- a/misc/nacl/testzip.proto +++ b/misc/nacl/testzip.proto @@ -10,6 +10,8 @@ usr src=../misc/nacl/testdata go src=.. src cmd + internal + + gofmt testdata + From 40b94405463415f6ba5d2decc0cd51eb61c67b65 Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Fri, 8 Aug 2014 16:19:45 +1000 Subject: [PATCH 041/423] debug/pe/testdata: make sure gcc-amd64-mingw-exec has symbols as per rsc request LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/123970043 --- src/pkg/debug/pe/file_test.go | 31 +++++++++++------- .../debug/pe/testdata/gcc-amd64-mingw-exec | Bin 37376 -> 273083 bytes 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/pkg/debug/pe/file_test.go b/src/pkg/debug/pe/file_test.go index ddbb271744..0d73969bca 100644 --- a/src/pkg/debug/pe/file_test.go +++ b/src/pkg/debug/pe/file_test.go @@ -125,9 +125,9 @@ var fileTests = []fileTest{ }, { "testdata/gcc-amd64-mingw-exec", - FileHeader{0x8664, 0x9, 0x53472993, 0x0, 0x0, 0xf0, 0x22f}, + FileHeader{0x8664, 0x11, 0x53e4364f, 0x39600, 0x6fc, 0xf0, 0x27}, &OptionalHeader64{ - 0x20b, 0x2, 0x16, 0x6a00, 0x2400, 0x1600, 0x14e0, 0x1000, 0x400000, 0x1000, 0x200, 0x4, 0x0, 0x0, 0x0, 0x5, 0x2, 0x0, 0x11000, 0x400, 0x1841e, 0x3, 0x0, 0x200000, 0x1000, 0x100000, 0x1000, 0x0, 0x10, + 0x20b, 0x2, 0x16, 0x6a00, 0x2400, 0x1600, 0x14e0, 0x1000, 0x400000, 0x1000, 0x200, 0x4, 0x0, 0x0, 0x0, 0x5, 0x2, 0x0, 0x45000, 0x600, 0x46f19, 0x3, 0x0, 0x200000, 0x1000, 0x100000, 0x1000, 0x0, 0x10, [16]DataDirectory{ {0x0, 0x0}, {0xe000, 0x990}, @@ -145,18 +145,25 @@ var fileTests = []fileTest{ {0x0, 0x0}, {0x0, 0x0}, {0x0, 0x0}, - }, - }, + }}, []*SectionHeader{ - {".text", 0x6860, 0x1000, 0x6a00, 0x400, 0x0, 0x0, 0x0, 0x0, 0x60500020}, - {".data", 0xe0, 0x8000, 0x200, 0x6e00, 0x0, 0x0, 0x0, 0x0, 0xc0500040}, - {".rdata", 0x6b0, 0x9000, 0x800, 0x7000, 0x0, 0x0, 0x0, 0x0, 0x40600040}, - {".pdata", 0x498, 0xa000, 0x600, 0x7800, 0x0, 0x0, 0x0, 0x0, 0x40300040}, - {".xdata", 0x488, 0xb000, 0x600, 0x7e00, 0x0, 0x0, 0x0, 0x0, 0x40300040}, + {".text", 0x6860, 0x1000, 0x6a00, 0x600, 0x0, 0x0, 0x0, 0x0, 0x60500020}, + {".data", 0xe0, 0x8000, 0x200, 0x7000, 0x0, 0x0, 0x0, 0x0, 0xc0500040}, + {".rdata", 0x6b0, 0x9000, 0x800, 0x7200, 0x0, 0x0, 0x0, 0x0, 0x40600040}, + {".pdata", 0x498, 0xa000, 0x600, 0x7a00, 0x0, 0x0, 0x0, 0x0, 0x40300040}, + {".xdata", 0x488, 0xb000, 0x600, 0x8000, 0x0, 0x0, 0x0, 0x0, 0x40300040}, {".bss", 0x1410, 0xc000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0600080}, - {".idata", 0x990, 0xe000, 0xa00, 0x8400, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, - {".CRT", 0x68, 0xf000, 0x200, 0x8e00, 0x0, 0x0, 0x0, 0x0, 0xc0400040}, - {".tls", 0x48, 0x10000, 0x200, 0x9000, 0x0, 0x0, 0x0, 0x0, 0xc0600040}, + {".idata", 0x990, 0xe000, 0xa00, 0x8600, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, + {".CRT", 0x68, 0xf000, 0x200, 0x9000, 0x0, 0x0, 0x0, 0x0, 0xc0400040}, + {".tls", 0x48, 0x10000, 0x200, 0x9200, 0x0, 0x0, 0x0, 0x0, 0xc0600040}, + {".debug_aranges", 0x600, 0x11000, 0x600, 0x9400, 0x0, 0x0, 0x0, 0x0, 0x42500040}, + {".debug_info", 0x1316e, 0x12000, 0x13200, 0x9a00, 0x0, 0x0, 0x0, 0x0, 0x42100040}, + {".debug_abbrev", 0x2ccb, 0x26000, 0x2e00, 0x1cc00, 0x0, 0x0, 0x0, 0x0, 0x42100040}, + {".debug_line", 0x3c4d, 0x29000, 0x3e00, 0x1fa00, 0x0, 0x0, 0x0, 0x0, 0x42100040}, + {".debug_frame", 0x18b8, 0x2d000, 0x1a00, 0x23800, 0x0, 0x0, 0x0, 0x0, 0x42400040}, + {".debug_str", 0x396, 0x2f000, 0x400, 0x25200, 0x0, 0x0, 0x0, 0x0, 0x42100040}, + {".debug_loc", 0x13240, 0x30000, 0x13400, 0x25600, 0x0, 0x0, 0x0, 0x0, 0x42100040}, + {".debug_ranges", 0xa70, 0x44000, 0xc00, 0x38a00, 0x0, 0x0, 0x0, 0x0, 0x42100040}, }, []*Symbol{}, }, diff --git a/src/pkg/debug/pe/testdata/gcc-amd64-mingw-exec b/src/pkg/debug/pe/testdata/gcc-amd64-mingw-exec index 78d4e5fed98b09866e047db6a670b9721c03badb..ce6feb6b7b6a4ca1fc5da067254d8acfd49f3377 100644 GIT binary patch literal 273083 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�itgmm?lVs%pdaM;AL;DPAarS~VMVcJb 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

    Js3LxhqvBHD_y@_@%5}RSk@riaW5}Rr1`G7eW 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�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�`-uI)TM&%!z}O%aVQN1HgSFHVof?q=1*p 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 From 21f7d83ffd3633869e9861efbe99f035daeb2201 Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Fri, 8 Aug 2014 16:20:20 +0900 Subject: [PATCH 042/423] cmd/go: fix build in airplane mode LGTM=iant R=golang-codereviews, adg, iant CC=golang-codereviews https://golang.org/cl/122190043 --- src/cmd/go/vcs_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/cmd/go/vcs_test.go b/src/cmd/go/vcs_test.go index f9bf75fef1..3097c4d1c5 100644 --- a/src/cmd/go/vcs_test.go +++ b/src/cmd/go/vcs_test.go @@ -12,6 +12,9 @@ import ( // Test that RepoRootForImportPath creates the correct RepoRoot for a given importPath. // TODO(cmang): Add tests for SVN and BZR. func TestRepoRootForImportPath(t *testing.T) { + if testing.Short() { + t.Skip("skipping test to avoid external network") + } switch runtime.GOOS { case "nacl", "android": t.Skipf("no networking available on %s", runtime.GOOS) From f7832df7695c1e5930b2c8ed5e02d529d00f21a4 Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Fri, 8 Aug 2014 12:48:34 +0400 Subject: [PATCH 043/423] encoding/gob: fix data races in benchmarks All goroutines decode into the same value. LGTM=r R=r, abursavich CC=golang-codereviews https://golang.org/cl/123930043 --- src/pkg/encoding/gob/timing_test.go | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/pkg/encoding/gob/timing_test.go b/src/pkg/encoding/gob/timing_test.go index 29c9b858b6..ec55c4d63d 100644 --- a/src/pkg/encoding/gob/timing_test.go +++ b/src/pkg/encoding/gob/timing_test.go @@ -19,12 +19,13 @@ type Bench struct { D []byte } -func benchmarkEndToEnd(b *testing.B, v interface{}, pipe func() (r io.Reader, w io.Writer, err error)) { +func benchmarkEndToEnd(b *testing.B, ctor func() interface{}, pipe func() (r io.Reader, w io.Writer, err error)) { b.RunParallel(func(pb *testing.PB) { r, w, err := pipe() if err != nil { b.Fatal("can't get pipe:", err) } + v := ctor() enc := NewEncoder(w) dec := NewDecoder(r) for pb.Next() { @@ -39,29 +40,33 @@ func benchmarkEndToEnd(b *testing.B, v interface{}, pipe func() (r io.Reader, w } func BenchmarkEndToEndPipe(b *testing.B) { - v := &Bench{7, 3.2, "now is the time", bytes.Repeat([]byte("for all good men"), 100)} - benchmarkEndToEnd(b, v, func() (r io.Reader, w io.Writer, err error) { + benchmarkEndToEnd(b, func() interface{} { + return &Bench{7, 3.2, "now is the time", bytes.Repeat([]byte("for all good men"), 100)} + }, func() (r io.Reader, w io.Writer, err error) { r, w, err = os.Pipe() return }) } func BenchmarkEndToEndByteBuffer(b *testing.B) { - v := &Bench{7, 3.2, "now is the time", bytes.Repeat([]byte("for all good men"), 100)} - benchmarkEndToEnd(b, v, func() (r io.Reader, w io.Writer, err error) { + benchmarkEndToEnd(b, func() interface{} { + return &Bench{7, 3.2, "now is the time", bytes.Repeat([]byte("for all good men"), 100)} + }, func() (r io.Reader, w io.Writer, err error) { var buf bytes.Buffer return &buf, &buf, nil }) } func BenchmarkEndToEndSliceByteBuffer(b *testing.B) { - v := &Bench{7, 3.2, "now is the time", nil} - Register(v) - arr := make([]interface{}, 100) - for i := range arr { - arr[i] = v - } - benchmarkEndToEnd(b, &arr, func() (r io.Reader, w io.Writer, err error) { + benchmarkEndToEnd(b, func() interface{} { + v := &Bench{7, 3.2, "now is the time", nil} + Register(v) + arr := make([]interface{}, 100) + for i := range arr { + arr[i] = v + } + return &arr + }, func() (r io.Reader, w io.Writer, err error) { var buf bytes.Buffer return &buf, &buf, nil }) From a83bbc9c488fb5b5405a5d1dc13a32d588a2fccd Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 8 Aug 2014 11:20:45 -0400 Subject: [PATCH 044/423] syscall: ignore EINVAL/ENOENT from readdirent on OS X 10.10 On OS X 10.10 Yosemite, if you have a directory that can be returned in a single getdirentries64 call (for example, a directory with one file), and you read from the directory at EOF twice, you get EOF both times: fd = open("dir") getdirentries64(fd) returns data getdirentries64(fd) returns 0 (EOF) getdirentries64(fd) returns 0 (EOF) But if you remove the file in the middle between the two calls, the second call returns an error instead. fd = open("dir") getdirentries64(fd) returns data getdirentries64(fd) returns 0 (EOF) remove("dir/file") getdirentries64(fd) returns ENOENT/EINVAL Whether you get ENOENT or EINVAL depends on exactly what was in the directory. It is deterministic, just data-dependent. This only happens in small directories. A directory containing more data than fits in a 4k getdirentries64 call will return EOF correctly. (It's not clear if the criteria is that the directory be split across multiple getdirentries64 calls or that it be split across multiple file system blocks.) We could change package os to avoid the second read at EOF, and maybe we should, but that's a bit involved. For now, treat the EINVAL/ENOENT as EOF. With this CL, all.bash passes on my MacBook Air running OS X 10.10 (14A299l) and Xcode 6 beta 5 (6A279r). I tried filing an issue with Apple using "Feedback Assistant", but it was unable to send the report and lost it. C program reproducing the issue, also at http://swtch.com/~rsc/readdirbug.c: #include #include #include #include #include #include #include #include static void test(int); int main(void) { int fd, n; DIR *dir; struct dirent *dp; struct stat st; char buf[10000]; long basep; int saw; if(stat("/tmp/readdirbug", &st) >= 0) { fprintf(stderr, "please rm -r /tmp/readdirbug and run again\n"); exit(1); } fprintf(stderr, "mkdir /tmp/readdirbug\n"); if(mkdir("/tmp/readdirbug", 0777) < 0) { perror("mkdir /tmp/readdirbug"); exit(1); } fprintf(stderr, "create /tmp/readdirbug/file1\n"); if((fd = creat("/tmp/readdirbug/file1", 0666)) < 0) { perror("create /tmp/readdirbug/file1"); exit(1); } close(fd); test(0); test(1); fprintf(stderr, "ok - everything worked\n"); } static void test(int doremove) { DIR *dir; struct dirent *dp; int numeof; fprintf(stderr, "\n"); fprintf(stderr, "opendir /tmp/readdirbug\n"); dir = opendir("/tmp/readdirbug"); if(dir == 0) { perror("open /tmp/readdirbug"); exit(1); } numeof = 0; for(;;) { errno = 0; dp = readdir(dir); if(dp != 0) { fprintf(stderr, "readdir: found %s\n", dp->d_name); continue; } if(errno != 0) { perror("readdir"); exit(1); } fprintf(stderr, "readdir: EOF\n"); if(++numeof == 3) break; if(doremove) { fprintf(stderr, "rm /tmp/readdirbug/file1\n"); if(remove("/tmp/readdirbug/file1") < 0) { perror("remove"); exit(1); } } } fprintf(stderr, "closedir\n"); closedir(dir); } Fixes #8423. LGTM=bradfitz, r R=golang-codereviews, bradfitz, dsymonds, dave, r CC=golang-codereviews, iant https://golang.org/cl/119530044 --- src/pkg/syscall/syscall_bsd.go | 35 +++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/pkg/syscall/syscall_bsd.go b/src/pkg/syscall/syscall_bsd.go index af563910b1..2556fa8746 100644 --- a/src/pkg/syscall/syscall_bsd.go +++ b/src/pkg/syscall/syscall_bsd.go @@ -68,7 +68,40 @@ func ReadDirent(fd int, buf []byte) (n int, err error) { // actual system call is getdirentries64, 64 is a good guess. // TODO(rsc): Can we use a single global basep for all calls? var base = (*uintptr)(unsafe.Pointer(new(uint64))) - return Getdirentries(fd, buf, base) + n, err = Getdirentries(fd, buf, base) + + // On OS X 10.10 Yosemite, if you have a directory that can be returned + // in a single getdirentries64 call (for example, a directory with one file), + // and you read from the directory at EOF twice, you get EOF both times: + // fd = open("dir") + // getdirentries64(fd) // returns data + // getdirentries64(fd) // returns 0 (EOF) + // getdirentries64(fd) // returns 0 (EOF) + // + // But if you remove the file in the middle between the two calls, the + // second call returns an error instead. + // fd = open("dir") + // getdirentries64(fd) // returns data + // getdirentries64(fd) // returns 0 (EOF) + // remove("dir/file") + // getdirentries64(fd) // returns ENOENT/EINVAL + // + // Whether you get ENOENT or EINVAL depends on exactly what was + // in the directory. It is deterministic, just data-dependent. + // + // This only happens in small directories. A directory containing more data + // than fits in a 4k getdirentries64 call will return EOF correctly. + // (It's not clear if the criteria is that the directory be split across multiple + // getdirentries64 calls or that it be split across multiple file system blocks.) + // + // We could change package os to avoid the second read at EOF, + // and maybe we should, but that's a bit involved. + // For now, treat the EINVAL/ENOENT as EOF. + if runtime.GOOS == "darwin" && (err == EINVAL || err == ENOENT) { + err = nil + } + + return } // Wait status is 7 bits at bottom, either 0 (exited), From d6d7170de414c16a7ea0125b5a458272557227b6 Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Fri, 8 Aug 2014 20:13:57 +0400 Subject: [PATCH 045/423] runtime: fix data race in stackalloc Stack shrinking happens during mark phase, and it assumes that it owns stackcache in mcache. Stack cache flushing also happens during mark phase, and it accesses stackcache's w/o any synchronization. This leads to stackcache corruption: http://goperfd.appspot.com/log/309af5571dfd7e1817259b9c9cf9bcf9b2c27610 LGTM=khr R=khr CC=golang-codereviews, rsc https://golang.org/cl/126870043 --- src/pkg/runtime/stack.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/pkg/runtime/stack.c b/src/pkg/runtime/stack.c index 0a806e8fab..772080af55 100644 --- a/src/pkg/runtime/stack.c +++ b/src/pkg/runtime/stack.c @@ -223,9 +223,11 @@ runtime·stackalloc(G *gp, uint32 n) n2 >>= 1; } c = g->m->mcache; - if(c == nil) { - // This can happen in the guts of exitsyscall or + if(c == nil || g->m->gcing || g->m->helpgc) { + // c == nil can happen in the guts of exitsyscall or // procresize. Just get a stack from the global pool. + // Also don't touch stackcache during gc + // as it's flushed concurrently. runtime·lock(&stackpoolmu); x = poolalloc(order); runtime·unlock(&stackpoolmu); @@ -285,7 +287,7 @@ runtime·stackfree(G *gp, void *v, Stktop *top) } x = (MLink*)v; c = g->m->mcache; - if(c == nil) { + if(c == nil || g->m->gcing || g->m->helpgc) { runtime·lock(&stackpoolmu); poolfree(x, order); runtime·unlock(&stackpoolmu); From 28cf62ed8565b481b94326321793614b544dfc17 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 8 Aug 2014 20:15:52 +0400 Subject: [PATCH 046/423] runtime: mark functions as static where possible Update #8092 LGTM=dvyukov R=golang-codereviews, minux, dvyukov CC=golang-codereviews https://golang.org/cl/122250043 --- src/pkg/runtime/cpuprof.goc | 2 +- src/pkg/runtime/mheap.c | 2 +- src/pkg/runtime/proc.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pkg/runtime/cpuprof.goc b/src/pkg/runtime/cpuprof.goc index faaea29435..cd4b210e23 100644 --- a/src/pkg/runtime/cpuprof.goc +++ b/src/pkg/runtime/cpuprof.goc @@ -314,7 +314,7 @@ flushlog(Profile *p) // getprofile blocks until the next block of profiling data is available // and returns it as a []byte. It is called from the writing goroutine. -Slice +static Slice getprofile(Profile *p) { uint32 i, j, n; diff --git a/src/pkg/runtime/mheap.c b/src/pkg/runtime/mheap.c index 908d668462..186fd48d47 100644 --- a/src/pkg/runtime/mheap.c +++ b/src/pkg/runtime/mheap.c @@ -211,7 +211,7 @@ mheap_alloc(MHeap *h, uintptr npage, int32 sizeclass, bool large) return s; } -void +static void mheap_alloc_m(G *gp) { MHeap *h; diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c index cef41d95f2..443bdda100 100644 --- a/src/pkg/runtime/proc.c +++ b/src/pkg/runtime/proc.c @@ -1384,7 +1384,7 @@ top: // appropriate time. After calling dropg and arranging for gp to be // readied later, the caller can do other work but eventually should // call schedule to restart the scheduling of goroutines on this m. -void +static void dropg(void) { if(g->m->lockedg == nil) { From 44106a088077da9e32bf038beff4a42cd8b88a7a Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Fri, 8 Aug 2014 20:52:11 +0400 Subject: [PATCH 047/423] runtime: bump MaxGcprocs to 32 There was a number of improvements related to GC parallelization: 1. Parallel roots/stacks scanning. 2. Parallel stack shrinking. 3. Per-thread workbuf caches. 4. Workset reduction. Currently 32 threads work well. go.benchmarks:garbage benchmark on 2 x Intel Xeon E5-2690 (16 HT cores) 1 thread/1 processor: time=16405255 cputime=16386223 gc-pause-one=546793975 gc-pause-total=3280763 2 threads/1 processor: time=9043497 cputime=18075822 gc-pause-one=331116489 gc-pause-total=2152257 4 threads/1 processor: time=4882030 cputime=19421337 gc-pause-one=174543105 gc-pause-total=1134530 8 threads/1 processor: time=4134757 cputime=20097075 gc-pause-one=158680588 gc-pause-total=1015555 16 threads/1 processor + HT: time=2006706 cputime=31960509 gc-pause-one=75425744 gc-pause-total=460097 16 threads/2 processors: time=1513373 cputime=23805571 gc-pause-one=56630946 gc-pause-total=345448 32 threads/2 processors + HT: time=1199312 cputime=37592764 gc-pause-one=48945064 gc-pause-total=278986 LGTM=rlh R=golang-codereviews, tracey.brendan, rlh CC=golang-codereviews, khr, rsc https://golang.org/cl/123920043 --- src/pkg/runtime/malloc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pkg/runtime/malloc.h b/src/pkg/runtime/malloc.h index 593e9b885b..556d6d4c03 100644 --- a/src/pkg/runtime/malloc.h +++ b/src/pkg/runtime/malloc.h @@ -141,8 +141,8 @@ enum // Max number of threads to run garbage collection. // 2, 3, and 4 are all plausible maximums depending // on the hardware details of the machine. The garbage - // collector scales well to 8 cpus. - MaxGcproc = 8, + // collector scales well to 32 cpus. + MaxGcproc = 32, }; // Maximum memory allocation size, a hint for callers. From f69f45c5383044c503add49d12659e14c1496491 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 8 Aug 2014 10:43:44 -0700 Subject: [PATCH 048/423] test: add another test case that gccgo crashed on LGTM=bradfitz R=golang-codereviews, bradfitz CC=golang-codereviews https://golang.org/cl/124020044 --- test/fixedbugs/bug490.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 test/fixedbugs/bug490.go diff --git a/test/fixedbugs/bug490.go b/test/fixedbugs/bug490.go new file mode 100644 index 0000000000..7d05f3945c --- /dev/null +++ b/test/fixedbugs/bug490.go @@ -0,0 +1,16 @@ +// compile + +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// The gccgo compiler used to crash building a comparison between an +// interface and an empty struct literal. + +package p + +type S struct{} + +func F(v interface{}) bool { + return v == S{} +} From 298c623e8caadf68198ba7bc4e6b128cb87983d7 Mon Sep 17 00:00:00 2001 From: Joel Stemmer Date: Fri, 8 Aug 2014 12:42:20 -0700 Subject: [PATCH 049/423] time: Fix missing colon when formatting time zone offsets with seconds When formatting time zone offsets with seconds using the stdISO8601Colon and stdNumColon layouts, the colon was missing between the hour and minute parts. Fixes #8497. LGTM=r R=golang-codereviews, iant, gobot, r CC=golang-codereviews https://golang.org/cl/126840043 --- src/pkg/time/format.go | 2 +- src/pkg/time/format_test.go | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/pkg/time/format.go b/src/pkg/time/format.go index 14b1250cb0..04e79f32dc 100644 --- a/src/pkg/time/format.go +++ b/src/pkg/time/format.go @@ -556,7 +556,7 @@ func (t Time) Format(layout string) string { b = append(b, '+') } b = appendUint(b, uint(zone/60), '0') - if std == stdISO8601ColonTZ || std == stdNumColonTZ { + if std == stdISO8601ColonTZ || std == stdNumColonTZ || std == stdISO8601ColonSecondsTZ || std == stdNumColonSecondsTZ { b = append(b, ':') } b = appendUint(b, uint(zone%60), '0') diff --git a/src/pkg/time/format_test.go b/src/pkg/time/format_test.go index 3bc8f42946..a7c6d55b2f 100644 --- a/src/pkg/time/format_test.go +++ b/src/pkg/time/format_test.go @@ -502,10 +502,11 @@ func TestParseSecondsInTimeZone(t *testing.T) { } func TestFormatSecondsInTimeZone(t *testing.T) { - d := Date(1871, 9, 17, 20, 4, 26, 0, FixedZone("LMT", -(34*60+8))) - timestr := d.Format("2006-01-02T15:04:05Z070000") - expected := "1871-09-17T20:04:26-003408" - if timestr != expected { - t.Errorf("Got %s, want %s", timestr, expected) + for _, test := range secondsTimeZoneOffsetTests { + d := Date(1871, 1, 1, 5, 33, 2, 0, FixedZone("LMT", test.expectedoffset)) + timestr := d.Format(test.format) + if timestr != test.value { + t.Errorf("Format = %s, want %s", timestr, test.value) + } } } From f0bfd7b03793a0b1018f2fe66e17bdc1e83b6357 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Fri, 8 Aug 2014 12:42:36 -0700 Subject: [PATCH 050/423] A+C: Joel Stemmer (individual CLA) Generated by a+c. R=gobot CC=golang-codereviews https://golang.org/cl/127800043 --- AUTHORS | 1 + CONTRIBUTORS | 1 + 2 files changed, 2 insertions(+) diff --git a/AUTHORS b/AUTHORS index c97790c7fa..6061e8e4cf 100644 --- a/AUTHORS +++ b/AUTHORS @@ -213,6 +213,7 @@ Jimmy Zelinskie Jingcheng Zhang Joakim Sernbrant Joe Poirier +Joel Stemmer John Asmuth John C Barstow John Graham-Cumming diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 30a2b567db..5386691e51 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -301,6 +301,7 @@ Jingcheng Zhang Joakim Sernbrant Joe Poirier Joel Sing +Joel Stemmer Johan Euphrosine John Asmuth John Beisley From 5a17aaa830a5951d2dc24aabb6c267d224a6b697 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Fri, 8 Aug 2014 14:54:04 -0700 Subject: [PATCH 051/423] doc/go1.4.txt: go.sys subrepo created CC=golang-codereviews https://golang.org/cl/124050043 --- doc/go1.4.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/go1.4.txt b/doc/go1.4.txt index e480d9bcd5..198529434a 100644 --- a/doc/go1.4.txt +++ b/doc/go1.4.txt @@ -19,3 +19,5 @@ testing: add Coverage (CL 98150043) text/scanner: add IsIdentRune field of Scanner. (CL 108030044) time: use the micro symbol (µ (U+00B5)) to print microsecond duration (CL 105030046) encoding/asn1: optional elements with a default value will now only be omitted if they have that value (CL 86960045). + +go.sys subrepo created: http://golang.org/s/go1.4-syscall From eae9fee3bf8c58c7403bcd103050ef2196fdfed1 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 11 Aug 2014 13:53:38 -0400 Subject: [PATCH 052/423] cmd/link: fix zig-zag decoding The >>1 shift needs to happen before converting to int32, otherwise large values will decode with an incorrect sign bit. The <<31 shift can happen before or after, but before is consistent with liblink and the go12symtab doc. Bug demo at http://play.golang.org/p/jLrhPUakIu LGTM=rsc R=golang-codereviews, minux, rsc CC=golang-codereviews https://golang.org/cl/119630043 --- src/cmd/link/pclntab.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/link/pclntab.go b/src/cmd/link/pclntab.go index b0b19ad53c..a950895aa5 100644 --- a/src/cmd/link/pclntab.go +++ b/src/cmd/link/pclntab.go @@ -437,7 +437,7 @@ func (it *PCIter) Next() { return } it.start = false - sv := int32(uv)>>1 ^ int32(uv)<<31>>31 + sv := int32(uv>>1) ^ int32(uv<<31)>>31 it.Value += sv // pc delta From 5b63ce4e1929914da33a0a53a0a2868b3fb092d2 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 11 Aug 2014 15:24:36 -0400 Subject: [PATCH 053/423] cmd/6g, cmd/8g: fix, test byte-sized magic multiply MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Credit to Rémy for finding and writing test case. Fixes #8325. LGTM=r R=golang-codereviews, r CC=dave, golang-codereviews, iant, remyoudompheng https://golang.org/cl/124950043 --- src/cmd/6g/ggen.c | 2 +- src/cmd/6g/peep.c | 5 +++++ src/cmd/8g/ggen.c | 2 +- src/cmd/8g/peep.c | 5 +++++ test/fixedbugs/issue8325.go | 31 +++++++++++++++++++++++++++++++ 5 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 test/fixedbugs/issue8325.go diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c index c385798f2e..9665d831b3 100644 --- a/src/cmd/6g/ggen.c +++ b/src/cmd/6g/ggen.c @@ -943,7 +943,7 @@ cgen_hmul(Node *nl, Node *nr, Node *res) if(t->width == 1) { // byte multiply behaves differently. nodreg(&ax, t, D_AH); - nodreg(&dx, t, D_DL); + nodreg(&dx, t, D_DX); gmove(&ax, &dx); } nodreg(&dx, t, D_DX); diff --git a/src/cmd/6g/peep.c b/src/cmd/6g/peep.c index 0f27204434..24617836fe 100644 --- a/src/cmd/6g/peep.c +++ b/src/cmd/6g/peep.c @@ -838,6 +838,11 @@ copyu(Prog *p, Adr *v, Adr *s) static int copyas(Adr *a, Adr *v) { + if(D_AL <= a->type && a->type <= D_R15B) + fatal("use of byte register"); + if(D_AL <= v->type && v->type <= D_R15B) + fatal("use of byte register"); + if(a->type != v->type) return 0; if(regtyp(v)) diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c index 2285a04e61..5e31404806 100644 --- a/src/cmd/8g/ggen.c +++ b/src/cmd/8g/ggen.c @@ -991,7 +991,7 @@ cgen_hmul(Node *nl, Node *nr, Node *res) if(t->width == 1) { // byte multiply behaves differently. nodreg(&ax, t, D_AH); - nodreg(&dx, t, D_DL); + nodreg(&dx, t, D_DX); gmove(&ax, &dx); } nodreg(&dx, t, D_DX); diff --git a/src/cmd/8g/peep.c b/src/cmd/8g/peep.c index d88987f954..35129a7c46 100644 --- a/src/cmd/8g/peep.c +++ b/src/cmd/8g/peep.c @@ -636,6 +636,11 @@ copyu(Prog *p, Adr *v, Adr *s) static int copyas(Adr *a, Adr *v) { + if(D_AL <= a->type && a->type <= D_R15B) + fatal("use of byte register"); + if(D_AL <= v->type && v->type <= D_R15B) + fatal("use of byte register"); + if(a->type != v->type) return 0; if(regtyp(v)) diff --git a/test/fixedbugs/issue8325.go b/test/fixedbugs/issue8325.go new file mode 100644 index 0000000000..e22fd319db --- /dev/null +++ b/test/fixedbugs/issue8325.go @@ -0,0 +1,31 @@ +// run + +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Issue 8325: corrupted byte operations during optimization +// pass. + +package main + +const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" + +func main() { + var bytes = []byte{10, 20, 30, 40, 50} + + for i, b := range bytes { + bytes[i] = alphanum[b%byte(len(alphanum))] + } + + for _, b := range bytes { + switch { + case '0' <= b && b <= '9', + 'A' <= b && b <= 'Z': + default: + println("found a bad character", string(b)) + panic("BUG") + } + + } +} From 988516ec46ae3ca753bcfcfdf88254f9a9d35ec1 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 11 Aug 2014 16:54:34 -0400 Subject: [PATCH 054/423] A+C: Andrew Bursavich (individual CLA) Generated by a+c. R=gobot CC=golang-codereviews https://golang.org/cl/124120043 --- AUTHORS | 1 + CONTRIBUTORS | 1 + 2 files changed, 2 insertions(+) diff --git a/AUTHORS b/AUTHORS index 6061e8e4cf..46e85a24f8 100644 --- a/AUTHORS +++ b/AUTHORS @@ -35,6 +35,7 @@ Amrut Joshi Andrei Vieru Andrew Balholm Andrew Bonventre +Andrew Bursavich Andrew Harding Andrew Lutomirski Andrew Pritchard diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 5386691e51..0cd3bcd5a9 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -66,6 +66,7 @@ Andreas Jellinghaus Andrei Vieru Andrew Balholm Andrew Bonventre +Andrew Bursavich Andrew Gerrand Andrew Harding Andrew Lutomirski From 2a37efbe1e25d30a4a998fc7ddad6d10c7df74da Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Mon, 11 Aug 2014 16:56:36 -0400 Subject: [PATCH 055/423] misc/nacl/testzip.proto: add fewer files to the zip LGTM=bradfitz, rsc R=rsc, iant, bradfitz CC=golang-codereviews https://golang.org/cl/126940043 --- misc/nacl/testzip.proto | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/misc/nacl/testzip.proto b/misc/nacl/testzip.proto index 596f50303c..29581dcfb3 100644 --- a/misc/nacl/testzip.proto +++ b/misc/nacl/testzip.proto @@ -11,7 +11,8 @@ go src=.. src cmd internal - + + objfile + objfile.go gofmt testdata + From 4769f87e0d39cbcce5309ff79c82465629798d15 Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Mon, 11 Aug 2014 17:10:23 -0400 Subject: [PATCH 056/423] runtime: no need to set R9 to m for runtime.sigpanic anymore Replaces CL 123980043 which I created on the dev.power64 branch. LGTM=rsc R=rsc, iant CC=golang-codereviews https://golang.org/cl/123120043 --- src/pkg/runtime/signal_arm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pkg/runtime/signal_arm.c b/src/pkg/runtime/signal_arm.c index 1f9a2325d1..3571cf3ac6 100644 --- a/src/pkg/runtime/signal_arm.c +++ b/src/pkg/runtime/signal_arm.c @@ -76,7 +76,6 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp) SIG_LR(info, ctxt) = gp->sigpc; // In case we are panicking from external C code SIG_R10(info, ctxt) = (uintptr)gp; - SIG_R9(info, ctxt) = (uintptr)g->m; SIG_PC(info, ctxt) = (uintptr)runtime·sigpanic; return; } From b5674a2b728d174bbd30be8e655b003528056d9f Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Mon, 11 Aug 2014 17:11:31 -0400 Subject: [PATCH 057/423] cmd/8g: fix build Fixes #8510. LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/129720043 --- src/cmd/8g/peep.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/8g/peep.c b/src/cmd/8g/peep.c index 35129a7c46..91a91d20db 100644 --- a/src/cmd/8g/peep.c +++ b/src/cmd/8g/peep.c @@ -636,9 +636,9 @@ copyu(Prog *p, Adr *v, Adr *s) static int copyas(Adr *a, Adr *v) { - if(D_AL <= a->type && a->type <= D_R15B) + if(D_AL <= a->type && a->type <= D_BL) fatal("use of byte register"); - if(D_AL <= v->type && v->type <= D_R15B) + if(D_AL <= v->type && v->type <= D_BL) fatal("use of byte register"); if(a->type != v->type) From 897f7a31fa040584f2c76d7901b9ef3257ca218f Mon Sep 17 00:00:00 2001 From: Chris Manghane Date: Mon, 11 Aug 2014 16:11:55 -0700 Subject: [PATCH 058/423] cmd/gc: comma-ok assignments produce untyped bool as 2nd result LGTM=rsc R=gri, rsc CC=golang-codereviews https://golang.org/cl/127950043 --- src/cmd/gc/order.c | 5 ++++- src/cmd/gc/typecheck.c | 2 +- src/cmd/gc/walk.c | 14 +++++++++++++- test/fixedbugs/issue8475.go | 25 +++++++++++++++++++++++++ test/named1.go | 8 ++++---- 5 files changed, 47 insertions(+), 7 deletions(-) create mode 100644 test/fixedbugs/issue8475.go diff --git a/src/cmd/gc/order.c b/src/cmd/gc/order.c index 728defe7c3..59231a0f1c 100644 --- a/src/cmd/gc/order.c +++ b/src/cmd/gc/order.c @@ -593,7 +593,10 @@ orderstmt(Node *n, Order *order) orderexpr(&n->rlist->n->left, order); // arg to recv ch = n->rlist->n->left->type; tmp1 = ordertemp(ch->type, order, haspointers(ch->type)); - tmp2 = ordertemp(types[TBOOL], order, 0); + if(!isblank(n->list->next->n)) + tmp2 = ordertemp(n->list->next->n->type, order, 0); + else + tmp2 = ordertemp(types[TBOOL], order, 0); order->out = list(order->out, n); r = nod(OAS, n->list->n, tmp1); typecheck(&r, Etop); diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index 92e9ad5215..c295cf6d21 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -2965,7 +2965,7 @@ typecheckas2(Node *n) if(l->defn == n) l->type = r->type; l = n->list->next->n; - if(l->type != T) + if(l->type != T && l->type->etype != TBOOL) checkassignto(types[TBOOL], l); if(l->defn == n && l->ntype == N) l->type = types[TBOOL]; diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index e50b917709..7ae75e5617 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -673,7 +673,7 @@ walkexpr(Node **np, NodeList **init) n1 = nod(OADDR, n->list->n, N); n1->etype = 1; // addr does not escape fn = chanfn("chanrecv2", 2, r->left->type); - r = mkcall1(fn, types[TBOOL], init, typename(r->left->type), r->left, n1); + r = mkcall1(fn, n->list->next->n->type, init, typename(r->left->type), r->left, n1); n = nod(OAS, n->list->next->n, r); typecheck(&n, Etop); goto ret; @@ -723,6 +723,12 @@ walkexpr(Node **np, NodeList **init) var->typecheck = 1; fn = mapfn(p, t); r = mkcall1(fn, getoutargx(fn->type), init, typename(t), r->left, key); + + // mapaccess2* returns a typed bool, but due to spec changes, + // the boolean result of i.(T) is now untyped so we make it the + // same type as the variable on the lhs. + if(!isblank(n->list->next->n)) + r->type->type->down->type = n->list->next->n->type; n->rlist = list1(r); n->op = OAS2FUNC; n->list->n = var; @@ -770,6 +776,12 @@ walkexpr(Node **np, NodeList **init) *p = '\0'; fn = syslook(buf, 1); + + // runtime.assert(E|I)2TOK returns a typed bool, but due + // to spec changes, the boolean result of i.(T) is now untyped + // so we make it the same type as the variable on the lhs. + if(!isblank(n->list->next->n)) + fn->type->type->down->type->type = n->list->next->n->type; ll = list1(typename(r->type)); ll = list(ll, r->left); argtype(fn, r->left->type); diff --git a/test/fixedbugs/issue8475.go b/test/fixedbugs/issue8475.go new file mode 100644 index 0000000000..e69794534c --- /dev/null +++ b/test/fixedbugs/issue8475.go @@ -0,0 +1,25 @@ +// build + +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Issue 8745: comma-ok assignments should produce untyped bool as 2nd result. + +package main + +type mybool bool + +func main() { + var ok mybool + _ = ok + + var i interface{} + _, ok = i.(int) + + var m map[int]int + _, ok = m[0] + + var c chan int + _, ok = <-c +} diff --git a/test/named1.go b/test/named1.go index 62b874c5cb..febad64ece 100644 --- a/test/named1.go +++ b/test/named1.go @@ -41,21 +41,21 @@ func main() { asBool(1 != 2) // ok now asBool(i < j) // ok now - _, b = m[2] // ERROR "cannot .* bool.*type Bool" + _, b = m[2] // ok now var inter interface{} - _, b = inter.(Map) // ERROR "cannot .* bool.*type Bool" + _, b = inter.(Map) // ok now _ = b var minter interface { M() } - _, b = minter.(Map) // ERROR "cannot .* bool.*type Bool" + _, b = minter.(Map) // ok now _ = b _, bb := <-c asBool(bb) // ERROR "cannot use.*type bool.*as type Bool" - _, b = <-c // ERROR "cannot .* bool.*type Bool" + _, b = <-c // ok now _ = b asString(String(slice)) // ok From f46f3432a60edafdcd6ec9925550859167812cd6 Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Tue, 12 Aug 2014 09:27:39 +1000 Subject: [PATCH 059/423] compress/{gzip,zlib}: mention that Close flushes Our other CloseFlushers (archive/tar, compress/flate) do mention this. The original change was accidentally submitted to the release branch: https://golang.org/cl/117430043/ TBR=rsc R=r, rsc CC=golang-codereviews https://golang.org/cl/124130043 --- src/pkg/compress/gzip/gzip.go | 3 ++- src/pkg/compress/zlib/writer.go | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pkg/compress/gzip/gzip.go b/src/pkg/compress/gzip/gzip.go index 3a0bf54e1b..5131d128e4 100644 --- a/src/pkg/compress/gzip/gzip.go +++ b/src/pkg/compress/gzip/gzip.go @@ -245,7 +245,8 @@ func (z *Writer) Flush() error { return z.err } -// Close closes the Writer. It does not close the underlying io.Writer. +// Close closes the Writer, flushing any unwritten data to the underlying +// io.Writer, but does not close the underlying io.Writer. func (z *Writer) Close() error { if z.err != nil { return z.err diff --git a/src/pkg/compress/zlib/writer.go b/src/pkg/compress/zlib/writer.go index fac7e15a7e..3b4313a8be 100644 --- a/src/pkg/compress/zlib/writer.go +++ b/src/pkg/compress/zlib/writer.go @@ -174,7 +174,8 @@ func (z *Writer) Flush() error { return z.err } -// Calling Close does not close the wrapped io.Writer originally passed to NewWriter. +// Close closes the Writer, flushing any unwritten data to the underlying +// io.Writer, but does not close the underlying io.Writer. func (z *Writer) Close() error { if !z.wroteHeader { z.err = z.writeHeader() From fce63888cecd22dfc01bf1b6dcb5a1429aecbc17 Mon Sep 17 00:00:00 2001 From: Andres Erbsen Date: Mon, 11 Aug 2014 16:40:42 -0700 Subject: [PATCH 060/423] crypto/tls: implement tls-unique channel binding (RFC 5929 section 3). Tested against GnuTLS and Python. LGTM=agl R=golang-codereviews, agl, ashankar CC=agl, golang-codereviews https://golang.org/cl/117100043 --- src/pkg/crypto/tls/common.go | 8 +++++ src/pkg/crypto/tls/conn.go | 6 ++++ src/pkg/crypto/tls/handshake_client.go | 14 ++++---- src/pkg/crypto/tls/handshake_server.go | 14 ++++---- src/pkg/crypto/tls/tls_test.go | 45 ++++++++++++++++++++++++++ 5 files changed, 75 insertions(+), 12 deletions(-) diff --git a/src/pkg/crypto/tls/common.go b/src/pkg/crypto/tls/common.go index 2b59136e65..f926d57728 100644 --- a/src/pkg/crypto/tls/common.go +++ b/src/pkg/crypto/tls/common.go @@ -165,6 +165,14 @@ type ConnectionState struct { ServerName string // server name requested by client, if any (server side only) PeerCertificates []*x509.Certificate // certificate chain presented by remote peer VerifiedChains [][]*x509.Certificate // verified chains built from PeerCertificates + + // TLSUnique contains the "tls-unique" channel binding value (see RFC + // 5929, section 3). For resumed sessions this value will be nil + // because resumption does not include enough context (see + // https://secure-resumption.com/#channelbindings). This will change in + // future versions of Go once the TLS master-secret fix has been + // standardized and implemented. + TLSUnique []byte } // ClientAuthType declares the policy the server will follow for diff --git a/src/pkg/crypto/tls/conn.go b/src/pkg/crypto/tls/conn.go index 8f7d2c144f..ba8e4c22b7 100644 --- a/src/pkg/crypto/tls/conn.go +++ b/src/pkg/crypto/tls/conn.go @@ -42,6 +42,9 @@ type Conn struct { verifiedChains [][]*x509.Certificate // serverName contains the server name indicated by the client, if any. serverName string + // firstFinished contains the first Finished hash sent during the + // handshake. This is the "tls-unique" channel binding value. + firstFinished [12]byte clientProtocol string clientProtocolFallback bool @@ -994,6 +997,9 @@ func (c *Conn) ConnectionState() ConnectionState { state.PeerCertificates = c.peerCertificates state.VerifiedChains = c.verifiedChains state.ServerName = c.serverName + if !c.didResume { + state.TLSUnique = c.firstFinished[:] + } } return state diff --git a/src/pkg/crypto/tls/handshake_client.go b/src/pkg/crypto/tls/handshake_client.go index 694a9a217f..3d9ef9b14e 100644 --- a/src/pkg/crypto/tls/handshake_client.go +++ b/src/pkg/crypto/tls/handshake_client.go @@ -187,10 +187,10 @@ NextCipherSuite: if err := hs.readSessionTicket(); err != nil { return err } - if err := hs.readFinished(); err != nil { + if err := hs.readFinished(c.firstFinished[:]); err != nil { return err } - if err := hs.sendFinished(); err != nil { + if err := hs.sendFinished(nil); err != nil { return err } } else { @@ -200,13 +200,13 @@ NextCipherSuite: if err := hs.establishKeys(); err != nil { return err } - if err := hs.sendFinished(); err != nil { + if err := hs.sendFinished(c.firstFinished[:]); err != nil { return err } if err := hs.readSessionTicket(); err != nil { return err } - if err := hs.readFinished(); err != nil { + if err := hs.readFinished(nil); err != nil { return err } } @@ -530,7 +530,7 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) { return false, nil } -func (hs *clientHandshakeState) readFinished() error { +func (hs *clientHandshakeState) readFinished(out []byte) error { c := hs.c c.readRecord(recordTypeChangeCipherSpec) @@ -555,6 +555,7 @@ func (hs *clientHandshakeState) readFinished() error { return errors.New("tls: server's Finished message was incorrect") } hs.finishedHash.Write(serverFinished.marshal()) + copy(out, verify) return nil } @@ -586,7 +587,7 @@ func (hs *clientHandshakeState) readSessionTicket() error { return nil } -func (hs *clientHandshakeState) sendFinished() error { +func (hs *clientHandshakeState) sendFinished(out []byte) error { c := hs.c c.writeRecord(recordTypeChangeCipherSpec, []byte{1}) @@ -605,6 +606,7 @@ func (hs *clientHandshakeState) sendFinished() error { finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret) hs.finishedHash.Write(finished.marshal()) c.writeRecord(recordTypeHandshake, finished.marshal()) + copy(out, finished.verifyData) return nil } diff --git a/src/pkg/crypto/tls/handshake_server.go b/src/pkg/crypto/tls/handshake_server.go index 39eeb363cd..684ab288f0 100644 --- a/src/pkg/crypto/tls/handshake_server.go +++ b/src/pkg/crypto/tls/handshake_server.go @@ -57,10 +57,10 @@ func (c *Conn) serverHandshake() error { if err := hs.establishKeys(); err != nil { return err } - if err := hs.sendFinished(); err != nil { + if err := hs.sendFinished(c.firstFinished[:]); err != nil { return err } - if err := hs.readFinished(); err != nil { + if err := hs.readFinished(nil); err != nil { return err } c.didResume = true @@ -73,13 +73,13 @@ func (c *Conn) serverHandshake() error { if err := hs.establishKeys(); err != nil { return err } - if err := hs.readFinished(); err != nil { + if err := hs.readFinished(c.firstFinished[:]); err != nil { return err } if err := hs.sendSessionTicket(); err != nil { return err } - if err := hs.sendFinished(); err != nil { + if err := hs.sendFinished(nil); err != nil { return err } } @@ -483,7 +483,7 @@ func (hs *serverHandshakeState) establishKeys() error { return nil } -func (hs *serverHandshakeState) readFinished() error { +func (hs *serverHandshakeState) readFinished(out []byte) error { c := hs.c c.readRecord(recordTypeChangeCipherSpec) @@ -523,6 +523,7 @@ func (hs *serverHandshakeState) readFinished() error { } hs.finishedHash.Write(clientFinished.marshal()) + copy(out, verify) return nil } @@ -552,7 +553,7 @@ func (hs *serverHandshakeState) sendSessionTicket() error { return nil } -func (hs *serverHandshakeState) sendFinished() error { +func (hs *serverHandshakeState) sendFinished(out []byte) error { c := hs.c c.writeRecord(recordTypeChangeCipherSpec, []byte{1}) @@ -563,6 +564,7 @@ func (hs *serverHandshakeState) sendFinished() error { c.writeRecord(recordTypeHandshake, finished.marshal()) c.cipherSuite = hs.suite.id + copy(out, finished.verifyData) return nil } diff --git a/src/pkg/crypto/tls/tls_test.go b/src/pkg/crypto/tls/tls_test.go index f8c94ff35d..e82579eee9 100644 --- a/src/pkg/crypto/tls/tls_test.go +++ b/src/pkg/crypto/tls/tls_test.go @@ -5,6 +5,7 @@ package tls import ( + "bytes" "fmt" "io" "net" @@ -235,3 +236,47 @@ func testConnReadNonzeroAndEOF(t *testing.T, delay time.Duration) error { } return nil } + +func TestTLSUniqueMatches(t *testing.T) { + ln := newLocalListener(t) + defer ln.Close() + + serverTLSUniques := make(chan []byte) + go func() { + for i := 0; i < 2; i++ { + sconn, err := ln.Accept() + if err != nil { + t.Fatal(err) + } + serverConfig := *testConfig + srv := Server(sconn, &serverConfig) + if err := srv.Handshake(); err != nil { + t.Fatal(err) + } + serverTLSUniques <- srv.ConnectionState().TLSUnique + } + }() + + clientConfig := *testConfig + clientConfig.ClientSessionCache = NewLRUClientSessionCache(1) + conn, err := Dial("tcp", ln.Addr().String(), &clientConfig) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(conn.ConnectionState().TLSUnique, <-serverTLSUniques) { + t.Error("client and server channel bindings differ") + } + conn.Close() + + conn, err = Dial("tcp", ln.Addr().String(), &clientConfig) + if err != nil { + t.Fatal(err) + } + defer conn.Close() + if !conn.ConnectionState().DidResume { + t.Error("second session did not use resumption") + } + if !bytes.Equal(conn.ConnectionState().TLSUnique, <-serverTLSUniques) { + t.Error("client and server channel bindings differ when session resumption is used") + } +} From 03e6a88ef04abd5916cd54d5255e7f6d6c78789f Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 11 Aug 2014 16:49:13 -0700 Subject: [PATCH 061/423] cmd/cgo: iterate over names in deterministic order This makes GCC behavior (and cgo build failures) deterministic. Fixes #8487. Ran this shell command on linux/amd64 (Ubuntu 12.04) before and after this change: for x in `seq 100`; do go tool cgo -debug-gcc=true issue8441.go 2>&1 | md5sum done | sort | uniq -c Before: 67 2cdcb8c7c4e290f7d9009abc581b83dd - 10 9a55390df94f7cec6d810f3e20590789 - 10 acfad22140d43d9b9517bbc5dfc3c0df - 13 c337f8fee2304b3a8e3158a4362d8698 - After: 100 785c316cbcbcd50896695050e2fa23c1 - LGTM=minux, iant R=golang-codereviews, bradfitz, minux, iant CC=golang-codereviews https://golang.org/cl/126990043 --- src/cmd/cgo/gcc.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index 841c848332..aa28060ea7 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -229,7 +229,8 @@ func (p *Package) guessKinds(f *File) []*Name { // Determine kinds for names we already know about, // like #defines or 'struct foo', before bothering with gcc. var names, needType []*Name - for _, n := range f.Name { + for _, key := range nameKeys(f.Name) { + n := f.Name[key] // If we've already found this name as a #define // and we can translate it as a constant value, do so. if n.Define != "" { From 31a996edb6303fdcd0e6c1816174b0b24a10b1f6 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 11 Aug 2014 22:10:17 -0700 Subject: [PATCH 062/423] cmd/cgo: fix default alignment for empty structs Fixes #5242. LGTM=iant R=iant CC=golang-codereviews https://golang.org/cl/125120043 --- misc/cgo/test/cgo_test.go | 1 + misc/cgo/test/issue5242.go | 31 +++++++++++++++++++++++++++++++ src/cmd/cgo/gcc.go | 3 +++ 3 files changed, 35 insertions(+) create mode 100644 misc/cgo/test/issue5242.go diff --git a/misc/cgo/test/cgo_test.go b/misc/cgo/test/cgo_test.go index eb237725a4..3c6d5cb59e 100644 --- a/misc/cgo/test/cgo_test.go +++ b/misc/cgo/test/cgo_test.go @@ -53,5 +53,6 @@ func Test5986(t *testing.T) { test5986(t) } func Test7665(t *testing.T) { test7665(t) } func TestNaming(t *testing.T) { testNaming(t) } func Test7560(t *testing.T) { test7560(t) } +func Test5242(t *testing.T) { test5242(t) } func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) } diff --git a/misc/cgo/test/issue5242.go b/misc/cgo/test/issue5242.go new file mode 100644 index 0000000000..fe0a6321c1 --- /dev/null +++ b/misc/cgo/test/issue5242.go @@ -0,0 +1,31 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Issue 5242. Cgo incorrectly computed the alignment of structs +// with no Go accessible fields as 0, and then panicked on +// modulo-by-zero computations. + +package cgotest + +/* +typedef struct { +} foo; + +typedef struct { + int x : 1; +} bar; + +int issue5242(foo f, bar b) { + return 5242; +} +*/ +import "C" + +import "testing" + +func test5242(t *testing.T) { + if got := C.issue5242(C.foo{}, C.bar{}); got != 5242 { + t.Errorf("got %v", got) + } +} diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index aa28060ea7..b79725ab01 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -1534,6 +1534,9 @@ func (c *typeConv) pad(fld []*ast.Field, size int64) []*ast.Field { // Struct conversion: return Go and (6g) C syntax for type. func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.StructType, csyntax string, align int64) { + // Minimum alignment for a struct is 1 byte. + align = 1 + var buf bytes.Buffer buf.WriteString("struct {") fld := make([]*ast.Field, 0, 2*len(dt.Field)+1) // enough for padding around every field From 444b928405444dcba8c0c008f44e8d21b9402547 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 12 Aug 2014 07:13:52 -0700 Subject: [PATCH 063/423] run.bash: run misc/cgo/testgodefs/test.bash misc/cgo/testgodefs was added by revision d1cf884a594f, but not add to run.bash. LGTM=iant R=iant CC=golang-codereviews https://golang.org/cl/129760044 --- src/run.bash | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/run.bash b/src/run.bash index d13161e9de..b5f061d885 100755 --- a/src/run.bash +++ b/src/run.bash @@ -162,7 +162,7 @@ android-arm | dragonfly-386 | dragonfly-amd64 | freebsd-386 | freebsd-amd64 | fr esac ) || exit $? -# This tests cgo -godefs. That mode is not supported, +# This tests cgo -cdefs. That mode is not supported, # so it's okay if it doesn't work on some systems. # In particular, it works badly with clang on OS X. [ "$CGO_ENABLED" != 1 ] || [ "$GOOS" == darwin ] || @@ -170,6 +170,11 @@ esac ./test.bash || exit 1 ) || exit $? +[ "$CGO_ENABLED" != 1 ] || [ "$GOOS" == darwin ] || +(xcd ../misc/cgo/testgodefs +./test.bash || exit 1 +) || exit $? + [ "$CGO_ENABLED" != 1 ] || [ "$GOHOSTOS" == windows ] || (xcd ../misc/cgo/testso From 881fbf9a7dad13555286400697892072383a63c9 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 12 Aug 2014 07:48:34 -0700 Subject: [PATCH 064/423] A+C: Thiago Fransosi Farina (individual CLA) Generated by a+c. LGTM=bradfitz R=bradfitz CC=golang-codereviews https://golang.org/cl/125960043 --- AUTHORS | 1 + CONTRIBUTORS | 1 + 2 files changed, 2 insertions(+) diff --git a/AUTHORS b/AUTHORS index 46e85a24f8..9aa3419715 100644 --- a/AUTHORS +++ b/AUTHORS @@ -401,6 +401,7 @@ Taj Khattra Tarmigan Casebolt Taru Karttunen Tetsuo Kiso +Thiago Fransosi Farina Thomas Alan Copeland Thomas Kappler Timo Savola diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 0cd3bcd5a9..2dbf02d4af 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -550,6 +550,7 @@ Taj Khattra Tarmigan Casebolt Taru Karttunen Tetsuo Kiso +Thiago Fransosi Farina Thomas Alan Copeland Thomas Habets Thomas Kappler From e4d4787581f0e00af743ae2eb41daf0e28003d23 Mon Sep 17 00:00:00 2001 From: Thiago Fransosi Farina Date: Tue, 12 Aug 2014 07:49:10 -0700 Subject: [PATCH 065/423] dist: Make vaddn private to buf.c This function does not have a declaration/prototype in a.h, and it is used only in buf.c, so it is local to it and thus can be marked as private by adding 'static' to it. LGTM=iant R=rsc, iant CC=golang-codereviews https://golang.org/cl/122300043 --- src/cmd/dist/buf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/dist/buf.c b/src/cmd/dist/buf.c index 45fb1954d3..2ddc6be752 100644 --- a/src/cmd/dist/buf.c +++ b/src/cmd/dist/buf.c @@ -202,7 +202,7 @@ vadd(Vec *v, char *p) } // vaddn adds a string consisting of the n bytes at p to the vector. -void +static void vaddn(Vec *v, char *p, int n) { char *q; From 11016f62d83435c352261fe250ae36660c50c17f Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 12 Aug 2014 12:55:12 -0700 Subject: [PATCH 066/423] cmd/cgo: make C function pointers non-assignable Fixes #7757. Fixes #8488. LGTM=iant R=iant CC=golang-codereviews https://golang.org/cl/118690044 --- misc/cgo/errors/issue7757.go | 14 ++++++++++++++ misc/cgo/errors/test.bash | 1 + src/cmd/cgo/gcc.go | 8 +++++++- src/cmd/cgo/out.go | 2 +- 4 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 misc/cgo/errors/issue7757.go diff --git a/misc/cgo/errors/issue7757.go b/misc/cgo/errors/issue7757.go new file mode 100644 index 0000000000..5eafd22e8a --- /dev/null +++ b/misc/cgo/errors/issue7757.go @@ -0,0 +1,14 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +/* +void foo() {} +*/ +import "C" + +func main() { + C.foo = C.foo // ERROR HERE +} diff --git a/misc/cgo/errors/test.bash b/misc/cgo/errors/test.bash index f0f60c8445..e5bf47a0dd 100755 --- a/misc/cgo/errors/test.bash +++ b/misc/cgo/errors/test.bash @@ -27,6 +27,7 @@ check() { check err1.go check err2.go check err3.go +check issue7757.go rm -rf errs _obj exit 0 diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index b79725ab01..26def654d0 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -650,7 +650,13 @@ func (p *Package) rewriteRef(f *File) { f.Name[fpName] = name } r.Name = name - expr = ast.NewIdent(name.Mangle) + // Rewrite into call to _Cgo_ptr to prevent assignments. The _Cgo_ptr + // function is defined in out.go and simply returns its argument. See + // issue 7757. + expr = &ast.CallExpr{ + Fun: &ast.Ident{NamePos: (*r.Expr).Pos(), Name: "_Cgo_ptr"}, + Args: []ast.Expr{ast.NewIdent(name.Mangle)}, + } } else if r.Name.Kind == "type" { // Okay - might be new(T) expr = r.Name.Type.Go diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 1ef78b757c..6322e0604a 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -64,7 +64,7 @@ func (p *Package) writeDefs() { if !*gccgo && *importRuntimeCgo { fmt.Fprintf(fgo2, "import _ \"runtime/cgo\"\n\n") } - fmt.Fprintf(fgo2, "type _ unsafe.Pointer\n\n") + fmt.Fprintf(fgo2, "func _Cgo_ptr(ptr unsafe.Pointer) unsafe.Pointer { return ptr }\n\n") if *importSyscall { fmt.Fprintf(fgo2, "func _Cerrno(dst *error, x int32) { *dst = syscall.Errno(x) }\n") } From fe7b29f5fd5be75484ce7ea89c2b63d96f9baa14 Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Wed, 13 Aug 2014 01:02:01 +0400 Subject: [PATCH 067/423] runtime/pprof: fix data race It's unclear why we do this broken double-checked locking. The mutex is not held for the whole duration of CPU profiling. Fixes #8365. LGTM=bradfitz R=golang-codereviews, bradfitz CC=golang-codereviews https://golang.org/cl/116290043 --- src/pkg/runtime/pprof/pprof.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/pkg/runtime/pprof/pprof.go b/src/pkg/runtime/pprof/pprof.go index 26aa0b8be5..236de54f38 100644 --- a/src/pkg/runtime/pprof/pprof.go +++ b/src/pkg/runtime/pprof/pprof.go @@ -574,12 +574,6 @@ func StartCPUProfile(w io.Writer) error { // each client to specify the frequency, we hard code it. const hz = 100 - // Avoid queueing behind StopCPUProfile. - // Could use TryLock instead if we had it. - if cpu.profiling { - return fmt.Errorf("cpu profiling already in use") - } - cpu.Lock() defer cpu.Unlock() if cpu.done == nil { From 1837419f302da9b36055bf12b6a7f92c420cb32b Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Wed, 13 Aug 2014 01:03:32 +0400 Subject: [PATCH 068/423] runtime: remove FlagNoProfile Turns out to be unused as well. LGTM=bradfitz R=golang-codereviews, bradfitz CC=golang-codereviews, khr https://golang.org/cl/127170044 --- src/pkg/runtime/malloc.go | 19 ++++++++----------- src/pkg/runtime/malloc.h | 3 +-- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/pkg/runtime/malloc.go b/src/pkg/runtime/malloc.go index 73dc9f20d6..71c0a4ecd7 100644 --- a/src/pkg/runtime/malloc.go +++ b/src/pkg/runtime/malloc.go @@ -11,9 +11,8 @@ import ( const ( debugMalloc = false - flagNoScan = 1 << 0 // GC doesn't have to scan object - flagNoProfiling = 1 << 1 // must not profile - flagNoZero = 1 << 2 // don't zero memory + flagNoScan = 1 << 0 // GC doesn't have to scan object + flagNoZero = 1 << 1 // don't zero memory kindArray = 17 kindFunc = 19 @@ -300,14 +299,12 @@ marked: if debug.allocfreetrace != 0 { tracealloc(x, size, typ) } - if flags&flagNoProfiling == 0 { - rate := MemProfileRate - if rate > 0 { - if size < uintptr(rate) && int32(size) < c.next_sample { - c.next_sample -= int32(size) - } else { - profilealloc(mp, x, size) - } + + if rate := MemProfileRate; rate > 0 { + if size < uintptr(rate) && int32(size) < c.next_sample { + c.next_sample -= int32(size) + } else { + profilealloc(mp, x, size) } } diff --git a/src/pkg/runtime/malloc.h b/src/pkg/runtime/malloc.h index 556d6d4c03..4612dddb16 100644 --- a/src/pkg/runtime/malloc.h +++ b/src/pkg/runtime/malloc.h @@ -534,8 +534,7 @@ enum { // flags to malloc FlagNoScan = 1<<0, // GC doesn't have to scan object - FlagNoProfiling = 1<<1, // must not profile - FlagNoZero = 1<<2, // don't zero memory + FlagNoZero = 1<<1, // don't zero memory }; void runtime·MProf_Malloc(void*, uintptr); From 67e1d40031d66bc2b67f422a17af0fea7e60effd Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Tue, 12 Aug 2014 14:35:27 -0700 Subject: [PATCH 069/423] crypto/rand: use getrandom system call on Linux Adds internal/syscall package. Fixes #8520 LGTM=r, agl R=agl, rsc, r CC=golang-codereviews, iant https://golang.org/cl/123260044 --- src/pkg/crypto/rand/rand_linux.go | 39 +++++++++++++++ src/pkg/crypto/rand/rand_unix.go | 11 ++++- src/pkg/go/build/deps_test.go | 2 +- src/pkg/internal/syscall/getrandom_linux.go | 55 +++++++++++++++++++++ 4 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 src/pkg/crypto/rand/rand_linux.go create mode 100644 src/pkg/internal/syscall/getrandom_linux.go diff --git a/src/pkg/crypto/rand/rand_linux.go b/src/pkg/crypto/rand/rand_linux.go new file mode 100644 index 0000000000..8cb59c75df --- /dev/null +++ b/src/pkg/crypto/rand/rand_linux.go @@ -0,0 +1,39 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package rand + +import ( + "internal/syscall" + "sync" +) + +func init() { + altGetRandom = getRandomLinux +} + +var ( + once sync.Once + useSyscall bool +) + +func pickStrategy() { + // Test whether we should use the system call or /dev/urandom. + // We'll fall back to urandom if: + // - the kernel is too old (before 3.17) + // - the machine has no entropy available (early boot + no hardware + // entropy source?) and we want to avoid blocking later. + var buf [1]byte + n, err := syscall.GetRandom(buf[:], syscall.GRND_NONBLOCK) + useSyscall = n == 1 && err == nil +} + +func getRandomLinux(p []byte) (ok bool) { + once.Do(pickStrategy) + if !useSyscall { + return false + } + n, err := syscall.GetRandom(p, 0) + return n == len(p) && err == nil +} diff --git a/src/pkg/crypto/rand/rand_unix.go b/src/pkg/crypto/rand/rand_unix.go index 1e741fda19..62d0fbdb35 100644 --- a/src/pkg/crypto/rand/rand_unix.go +++ b/src/pkg/crypto/rand/rand_unix.go @@ -20,6 +20,8 @@ import ( "time" ) +const urandomDevice = "/dev/urandom" + // Easy implementation: read from /dev/urandom. // This is sufficient on Linux, OS X, and FreeBSD. @@ -27,7 +29,7 @@ func init() { if runtime.GOOS == "plan9" { Reader = newReader(nil) } else { - Reader = &devReader{name: "/dev/urandom"} + Reader = &devReader{name: urandomDevice} } } @@ -38,7 +40,14 @@ type devReader struct { mu sync.Mutex } +// altGetRandom if non-nil specifies an OS-specific function to get +// urandom-style randomness. +var altGetRandom func([]byte) (ok bool) + func (r *devReader) Read(b []byte) (n int, err error) { + if altGetRandom != nil && r.name == urandomDevice && altGetRandom(b) { + return len(b), nil + } r.mu.Lock() defer r.mu.Unlock() if r.f == nil { diff --git a/src/pkg/go/build/deps_test.go b/src/pkg/go/build/deps_test.go index 99b985b51d..2a7173ba4c 100644 --- a/src/pkg/go/build/deps_test.go +++ b/src/pkg/go/build/deps_test.go @@ -279,7 +279,7 @@ var pkgDeps = map[string][]string{ // Random byte, number generation. // This would be part of core crypto except that it imports // math/big, which imports fmt. - "crypto/rand": {"L4", "CRYPTO", "OS", "math/big", "syscall"}, + "crypto/rand": {"L4", "CRYPTO", "OS", "math/big", "syscall", "internal/syscall"}, // Mathematical crypto: dependencies on fmt (L4) and math/big. // We could avoid some of the fmt, but math/big imports fmt anyway. diff --git a/src/pkg/internal/syscall/getrandom_linux.go b/src/pkg/internal/syscall/getrandom_linux.go new file mode 100644 index 0000000000..1c586ec9b7 --- /dev/null +++ b/src/pkg/internal/syscall/getrandom_linux.go @@ -0,0 +1,55 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package syscall + +import ( + "runtime" + "sync/atomic" + stdsyscall "syscall" + "unsafe" +) + +var randomTrap = map[string]uintptr{ + "amd64": 318, + "386": 355, +}[runtime.GOARCH] + +var randomUnsupported int32 // atomic + +// GetRandomFlag is a flag supported by the getrandom system call. +type GetRandomFlag uintptr + +const ( + // GRND_NONBLOCK means return EAGAIN rather than blocking. + GRND_NONBLOCK GetRandomFlag = 0x0001 + + // GRND_RANDOM means use the /dev/random pool instead of /dev/urandom. + GRND_RANDOM GetRandomFlag = 0x0002 +) + +// GetRandom calls the Linux getrandom system call. +// See https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c6e9d6f38894798696f23c8084ca7edbf16ee895 +func GetRandom(p []byte, flags GetRandomFlag) (n int, err error) { + if randomTrap == 0 { + return 0, stdsyscall.ENOSYS + } + if len(p) == 0 { + return 0, nil + } + if atomic.LoadInt32(&randomUnsupported) != 0 { + return 0, stdsyscall.ENOSYS + } + r1, _, errno := stdsyscall.Syscall(randomTrap, + uintptr(unsafe.Pointer(&p[0])), + uintptr(len(p)), + uintptr(flags)) + if errno != 0 { + if errno == stdsyscall.ENOSYS { + atomic.StoreInt32(&randomUnsupported, 1) + } + return 0, errno + } + return int(r1), nil +} From f497885c6343808b47811981ae42c2e816005163 Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Wed, 13 Aug 2014 07:39:52 +1000 Subject: [PATCH 070/423] doc: document go1.3.1 LGTM=r R=r, rsc CC=golang-codereviews https://golang.org/cl/126060043 --- doc/devel/release.html | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/devel/release.html b/doc/devel/release.html index 0824463f4c..c1d364c723 100644 --- a/doc/devel/release.html +++ b/doc/devel/release.html @@ -20,6 +20,13 @@ Go 1.3 is a major release of Go. Read the Go 1.3 Release Notes for more information.

    +

    Minor revisions

    + +

    +go1.3.1 (released 2014/08/13) includes bug fixes to the compiler and the the runtime, net, and crypto/rsa packages. +See the change history for details. +

    +

    go1.2 (released 2013/12/01)

    From 0c6146711c184b711c9d2d664056380e149fa714 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 12 Aug 2014 17:41:03 -0400 Subject: [PATCH 071/423] cmd/go, go/build: implement import comment checking See golang.org/s/go14customimport for design. Added case to deps_test to allow go/build to import regexp. Not a new dependency, because go/build already imports go/doc which imports regexp. Fixes #7453. LGTM=r R=r, josharian CC=golang-codereviews https://golang.org/cl/124940043 --- src/cmd/go/pkg.go | 5 +- src/cmd/go/test.bash | 36 ++++ src/cmd/go/testdata/importcom/bad.go | 3 + src/cmd/go/testdata/importcom/conflict.go | 3 + src/cmd/go/testdata/importcom/src/bad/bad.go | 1 + .../go/testdata/importcom/src/conflict/a.go | 1 + .../go/testdata/importcom/src/conflict/b.go | 1 + .../go/testdata/importcom/src/works/x/x.go | 1 + .../go/testdata/importcom/src/works/x/x1.go | 1 + .../go/testdata/importcom/src/wrongplace/x.go | 1 + src/cmd/go/testdata/importcom/works.go | 3 + src/cmd/go/testdata/importcom/wrongplace.go | 3 + src/pkg/go/build/build.go | 161 ++++++++++++++++-- 13 files changed, 206 insertions(+), 14 deletions(-) create mode 100644 src/cmd/go/testdata/importcom/bad.go create mode 100644 src/cmd/go/testdata/importcom/conflict.go create mode 100644 src/cmd/go/testdata/importcom/src/bad/bad.go create mode 100644 src/cmd/go/testdata/importcom/src/conflict/a.go create mode 100644 src/cmd/go/testdata/importcom/src/conflict/b.go create mode 100644 src/cmd/go/testdata/importcom/src/works/x/x.go create mode 100644 src/cmd/go/testdata/importcom/src/works/x/x1.go create mode 100644 src/cmd/go/testdata/importcom/src/wrongplace/x.go create mode 100644 src/cmd/go/testdata/importcom/works.go create mode 100644 src/cmd/go/testdata/importcom/wrongplace.go diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go index be691a6bc9..eb8c451783 100644 --- a/src/cmd/go/pkg.go +++ b/src/cmd/go/pkg.go @@ -261,11 +261,14 @@ func loadImport(path string, srcDir string, stk *importStack, importPos []token. // // TODO: After Go 1, decide when to pass build.AllowBinary here. // See issue 3268 for mistakes to avoid. - bp, err := buildContext.Import(path, srcDir, 0) + bp, err := buildContext.Import(path, srcDir, build.ImportComment) bp.ImportPath = importPath if gobin != "" { bp.BinDir = gobin } + if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path { + err = fmt.Errorf("directory %s contains package %q", bp.Dir, bp.ImportComment) + } p.load(stk, bp, err) if p.Error != nil && len(importPos) > 0 { pos := importPos[0] diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash index 411ef1863f..93a7c67c18 100755 --- a/src/cmd/go/test.bash +++ b/src/cmd/go/test.bash @@ -121,6 +121,42 @@ if ! ./testgo build -v ./testdata/testinternal2; then ok=false fi +export GOPATH=$(pwd)/testdata/importcom +TEST 'import comment - match' +if ! ./testgo build ./testdata/importcom/works.go; then + echo 'go build ./testdata/importcom/works.go failed' + ok=false +fi +TEST 'import comment - mismatch' +if ./testgo build ./testdata/importcom/wrongplace.go 2>testdata/err; then + echo 'go build ./testdata/importcom/wrongplace.go suceeded' + ok=false +elif ! grep 'wrongplace contains package "my/x"' testdata/err >/dev/null; then + echo 'go build did not mention incorrect import:' + cat testdata/err + ok=false +fi +TEST 'import comment - syntax error' +if ./testgo build ./testdata/importcom/bad.go 2>testdata/err; then + echo 'go build ./testdata/importcom/bad.go suceeded' + ok=false +elif ! grep 'cannot parse import comment' testdata/err >/dev/null; then + echo 'go build did not mention syntax error:' + cat testdata/err + ok=false +fi +TEST 'import comment - conflict' +if ./testgo build ./testdata/importcom/conflict.go 2>testdata/err; then + echo 'go build ./testdata/importcom/conflict.go suceeded' + ok=false +elif ! grep 'found import comments' testdata/err >/dev/null; then + echo 'go build did not mention comment conflict:' + cat testdata/err + ok=false +fi +rm -f ./testdata/err +unset GOPATH + TEST error message for syntax error in test go file says FAIL export GOPATH=$(pwd)/testdata if ./testgo test syntaxerror 2>testdata/err; then diff --git a/src/cmd/go/testdata/importcom/bad.go b/src/cmd/go/testdata/importcom/bad.go new file mode 100644 index 0000000000..e104c2e992 --- /dev/null +++ b/src/cmd/go/testdata/importcom/bad.go @@ -0,0 +1,3 @@ +package p + +import "bad" diff --git a/src/cmd/go/testdata/importcom/conflict.go b/src/cmd/go/testdata/importcom/conflict.go new file mode 100644 index 0000000000..995556c511 --- /dev/null +++ b/src/cmd/go/testdata/importcom/conflict.go @@ -0,0 +1,3 @@ +package p + +import "conflict" diff --git a/src/cmd/go/testdata/importcom/src/bad/bad.go b/src/cmd/go/testdata/importcom/src/bad/bad.go new file mode 100644 index 0000000000..bc51fd3fde --- /dev/null +++ b/src/cmd/go/testdata/importcom/src/bad/bad.go @@ -0,0 +1 @@ +package bad // import diff --git a/src/cmd/go/testdata/importcom/src/conflict/a.go b/src/cmd/go/testdata/importcom/src/conflict/a.go new file mode 100644 index 0000000000..2d67703511 --- /dev/null +++ b/src/cmd/go/testdata/importcom/src/conflict/a.go @@ -0,0 +1 @@ +package conflict // import "a" diff --git a/src/cmd/go/testdata/importcom/src/conflict/b.go b/src/cmd/go/testdata/importcom/src/conflict/b.go new file mode 100644 index 0000000000..8fcfb3c8bd --- /dev/null +++ b/src/cmd/go/testdata/importcom/src/conflict/b.go @@ -0,0 +1 @@ +package conflict /* import "b" */ diff --git a/src/cmd/go/testdata/importcom/src/works/x/x.go b/src/cmd/go/testdata/importcom/src/works/x/x.go new file mode 100644 index 0000000000..044c6eca80 --- /dev/null +++ b/src/cmd/go/testdata/importcom/src/works/x/x.go @@ -0,0 +1 @@ +package x // import "works/x" diff --git a/src/cmd/go/testdata/importcom/src/works/x/x1.go b/src/cmd/go/testdata/importcom/src/works/x/x1.go new file mode 100644 index 0000000000..2449b29df5 --- /dev/null +++ b/src/cmd/go/testdata/importcom/src/works/x/x1.go @@ -0,0 +1 @@ +package x // important! not an import comment diff --git a/src/cmd/go/testdata/importcom/src/wrongplace/x.go b/src/cmd/go/testdata/importcom/src/wrongplace/x.go new file mode 100644 index 0000000000..b89849da78 --- /dev/null +++ b/src/cmd/go/testdata/importcom/src/wrongplace/x.go @@ -0,0 +1 @@ +package x // import "my/x" diff --git a/src/cmd/go/testdata/importcom/works.go b/src/cmd/go/testdata/importcom/works.go new file mode 100644 index 0000000000..31b55d08a3 --- /dev/null +++ b/src/cmd/go/testdata/importcom/works.go @@ -0,0 +1,3 @@ +package p + +import _ "works/x" diff --git a/src/cmd/go/testdata/importcom/wrongplace.go b/src/cmd/go/testdata/importcom/wrongplace.go new file mode 100644 index 0000000000..e2535e01ae --- /dev/null +++ b/src/cmd/go/testdata/importcom/wrongplace.go @@ -0,0 +1,3 @@ +package p + +import "wrongplace" diff --git a/src/pkg/go/build/build.go b/src/pkg/go/build/build.go index 6db0275032..1a133041e8 100644 --- a/src/pkg/go/build/build.go +++ b/src/pkg/go/build/build.go @@ -23,6 +23,7 @@ import ( "strconv" "strings" "unicode" + "unicode/utf8" ) // A Context specifies the supporting context for a build. @@ -337,22 +338,29 @@ const ( // If AllowBinary is set, Import can be satisfied by a compiled // package object without corresponding sources. AllowBinary + + // If ImportComment is set, parse import comments on package statements. + // Import returns an error if it finds a comment it cannot understand + // or finds conflicting comments in multiple source files. + // See golang.org/s/go14customimport for more information. + ImportComment ) // A Package describes the Go package found in a directory. type Package struct { - Dir string // directory containing package sources - Name string // package name - Doc string // documentation synopsis - ImportPath string // import path of package ("" if unknown) - Root string // root of Go tree where this package lives - SrcRoot string // package source root directory ("" if unknown) - PkgRoot string // package install root directory ("" if unknown) - BinDir string // command install directory ("" if unknown) - Goroot bool // package found in Go root - PkgObj string // installed .a file - AllTags []string // tags that can influence file selection in this directory - ConflictDir string // this directory shadows Dir in $GOPATH + Dir string // directory containing package sources + Name string // package name + ImportComment string // path in import comment on package statement + Doc string // documentation synopsis + ImportPath string // import path of package ("" if unknown) + Root string // root of Go tree where this package lives + SrcRoot string // package source root directory ("" if unknown) + PkgRoot string // package install root directory ("" if unknown) + BinDir string // command install directory ("" if unknown) + Goroot bool // package found in Go root + PkgObj string // installed .a file + AllTags []string // tags that can influence file selection in this directory + ConflictDir string // this directory shadows Dir in $GOPATH // Source files GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) @@ -597,7 +605,7 @@ Found: } var Sfiles []string // files with ".S" (capital S) - var firstFile string + var firstFile, firstCommentFile string imported := make(map[string][]token.Position) testImported := make(map[string][]token.Position) xTestImported := make(map[string][]token.Position) @@ -684,6 +692,22 @@ Found: p.Doc = doc.Synopsis(pf.Doc.Text()) } + if mode&ImportComment != 0 { + qcom, line := findImportComment(data) + if line != 0 { + com, err := strconv.Unquote(qcom) + if err != nil { + return p, fmt.Errorf("%s:%d: cannot parse import comment", filename, line) + } + if p.ImportComment == "" { + p.ImportComment = com + firstCommentFile = name + } else if p.ImportComment != com { + return p, fmt.Errorf("found import comments %q (%s) and %q (%s) in %s", p.ImportComment, firstCommentFile, com, name, p.Dir) + } + } + } + // Record imports and information about cgo. isCgo := false for _, decl := range pf.Decls { @@ -764,6 +788,117 @@ Found: return p, pkgerr } +func findImportComment(data []byte) (s string, line int) { + // expect keyword package + word, data := parseWord(data) + if string(word) != "package" { + return "", 0 + } + + // expect package name + _, data = parseWord(data) + + // now ready for import comment, a // or /* */ comment + // beginning and ending on the current line. + for len(data) > 0 && (data[0] == ' ' || data[0] == '\t' || data[0] == '\r') { + data = data[1:] + } + + var comment []byte + switch { + case bytes.HasPrefix(data, slashSlash): + i := bytes.Index(data, newline) + if i < 0 { + i = len(data) + } + comment = data[2:i] + case bytes.HasPrefix(data, slashStar): + data = data[2:] + i := bytes.Index(data, starSlash) + if i < 0 { + // malformed comment + return "", 0 + } + comment = data[:i] + if bytes.Contains(comment, newline) { + return "", 0 + } + } + comment = bytes.TrimSpace(comment) + + // split comment into `import`, `"pkg"` + word, arg := parseWord(comment) + if string(word) != "import" { + return "", 0 + } + + line = 1 + bytes.Count(data[:cap(data)-cap(arg)], newline) + return strings.TrimSpace(string(arg)), line +} + +var ( + slashSlash = []byte("//") + slashStar = []byte("/*") + starSlash = []byte("*/") + newline = []byte("\n") +) + +// skipSpaceOrComment returns data with any leading spaces or comments removed. +func skipSpaceOrComment(data []byte) []byte { + for len(data) > 0 { + switch data[0] { + case ' ', '\t', '\r', '\n': + data = data[1:] + continue + case '/': + if bytes.HasPrefix(data, slashSlash) { + i := bytes.Index(data, newline) + if i < 0 { + return nil + } + data = data[i+1:] + continue + } + if bytes.HasPrefix(data, slashStar) { + data = data[2:] + i := bytes.Index(data, starSlash) + if i < 0 { + return nil + } + data = data[i+2:] + continue + } + } + break + } + return data +} + +// parseWord skips any leading spaces or comments in data +// and then parses the beginning of data as an identifier or keyword, +// returning that word and what remains after the word. +func parseWord(data []byte) (word, rest []byte) { + data = skipSpaceOrComment(data) + + // Parse past leading word characters. + rest = data + for { + r, size := utf8.DecodeRune(rest) + if unicode.IsLetter(r) || '0' <= r && r <= '9' || r == '_' { + rest = rest[size:] + continue + } + break + } + + word = data[:len(data)-len(rest)] + if len(word) == 0 { + return nil, nil + } + + return word, rest +} + // MatchFile reports whether the file with the given name in the given directory // matches the context and would be included in a Package created by ImportDir // of that directory. From 9abf0b6e9f7d1ae1a5f6e500ee58122d4b40f776 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 12 Aug 2014 17:41:16 -0400 Subject: [PATCH 072/423] cmd/ld: handle large link base addresses codeblk and datblk were truncating their arguments to int32. Don't do that. LGTM=dvyukov, rminnich R=iant, dvyukov, rminnich CC=golang-codereviews https://golang.org/cl/126050043 --- src/cmd/ld/data.c | 12 ++++++------ src/cmd/ld/lib.h | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c index 96eadd479a..c0dc3d05f2 100644 --- a/src/cmd/ld/data.c +++ b/src/cmd/ld/data.c @@ -425,10 +425,10 @@ dynreloc(void) } static void -blk(LSym *start, int32 addr, int32 size) +blk(LSym *start, int64 addr, int64 size) { LSym *sym; - int32 eaddr; + int64 eaddr; uchar *p, *ep; for(sym = start; sym != nil; sym = sym->next) @@ -467,10 +467,10 @@ blk(LSym *start, int32 addr, int32 size) } void -codeblk(int32 addr, int32 size) +codeblk(int64 addr, int64 size) { LSym *sym; - int32 eaddr, n; + int64 eaddr, n; uchar *q; if(debug['a']) @@ -527,10 +527,10 @@ codeblk(int32 addr, int32 size) } void -datblk(int32 addr, int32 size) +datblk(int64 addr, int64 size) { LSym *sym; - int32 i, eaddr; + int64 i, eaddr; uchar *p, *ep; char *typ, *rsname; Reloc *r; diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h index 4094dfa6b1..dd23990234 100644 --- a/src/cmd/ld/lib.h +++ b/src/cmd/ld/lib.h @@ -184,11 +184,11 @@ uint32 be32(uchar *b); uint64 be64(uchar *b); void callgraph(void); void cflush(void); -void codeblk(int32 addr, int32 size); +void codeblk(int64 addr, int64 size); vlong cpos(void); void cseek(vlong p); void cwrite(void *buf, int n); -void datblk(int32 addr, int32 size); +void datblk(int64 addr, int64 size); int datcmp(LSym *s1, LSym *s2); vlong datoff(vlong addr); void deadcode(void); From 160b2461b66c13f1014243f06a401bb1477b46dc Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Tue, 12 Aug 2014 15:28:45 -0700 Subject: [PATCH 073/423] syscall: freeze the package Add a clause to the doc comment for the package and a paragraph in the compatibility document explaining the situation. LGTM=bradfitz, adg, rsc R=golang-codereviews, adg, bradfitz, minux, rsc CC=golang-codereviews https://golang.org/cl/129820043 --- doc/go1compat.html | 14 ++++++++++++++ src/pkg/syscall/syscall.go | 7 +++++++ 2 files changed, 21 insertions(+) diff --git a/doc/go1compat.html b/doc/go1compat.html index d10b9af294..2c8d214840 100644 --- a/doc/go1compat.html +++ b/doc/go1compat.html @@ -152,6 +152,20 @@ will be tagged as appropriate to identify versions that are compatible with the Go 1 point releases.

    +

    Operating systems

    + +

    +It is impossible to guarantee long-term compatibility with operating +system interfaces, which are changed by outside parties. +The syscall package +is therefore outside the purview of the guarantees made here. +As of Go version 1.4, the syscall package is frozen. +Any evolution of the system call interface must be supported elsewhere, +such as in the go.sys subrepository. +For details and background, see +this document. +

    +

    Tools

    diff --git a/src/pkg/syscall/syscall.go b/src/pkg/syscall/syscall.go index f7473fd5aa..3fd95798f3 100644 --- a/src/pkg/syscall/syscall.go +++ b/src/pkg/syscall/syscall.go @@ -17,6 +17,13 @@ // These calls return err == nil to indicate success; otherwise // err is an operating system error describing the failure. // On most systems, that error has type syscall.Errno. +// +// NOTE: This package is locked down. Code outside the standard +// Go repository should be migrated to use the corresponding +// package in the go.sys subrepository. That is also where updates +// required by new systems or versions should be applied. +// See https://golang.org/s/go1.4-syscall for more information. +// package syscall // StringByteSlice is deprecated. Use ByteSliceFromString instead. From b049dc3074704856305bf12f421144b04d6844f9 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Tue, 12 Aug 2014 15:45:35 -0700 Subject: [PATCH 074/423] doc/compat1.html: link to go.sys You talked me into it. This and other links should be updated once the new import paths for the subrepos are established. LGTM=minux R=golang-codereviews, minux CC=golang-codereviews https://golang.org/cl/124260043 --- doc/go1compat.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/go1compat.html b/doc/go1compat.html index 2c8d214840..8ceaf32f97 100644 --- a/doc/go1compat.html +++ b/doc/go1compat.html @@ -161,7 +161,8 @@ The syscall package is therefore outside the purview of the guarantees made here. As of Go version 1.4, the syscall package is frozen. Any evolution of the system call interface must be supported elsewhere, -such as in the go.sys subrepository. +such as in the +go.sys subrepository. For details and background, see this document.

    From 9aa1e9afda4921fa1bb37e2733b4b84b5c468d48 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 12 Aug 2014 19:51:20 -0400 Subject: [PATCH 075/423] runtime: avoid using address as constant in amd64 assembly This allows changing the addressing mode for constant global addresses to use pc-relative addressing. LGTM=rminnich, iant R=golang-codereviews, rminnich, iant CC=golang-codereviews https://golang.org/cl/129830043 --- src/pkg/runtime/asm_amd64.s | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/pkg/runtime/asm_amd64.s b/src/pkg/runtime/asm_amd64.s index 0fd21d1795..d94df0bf8d 100644 --- a/src/pkg/runtime/asm_amd64.s +++ b/src/pkg/runtime/asm_amd64.s @@ -92,7 +92,8 @@ ok: CALL runtime·schedinit(SB) // create a new goroutine to start program - PUSHQ $runtime·main·f(SB) // entry + MOVQ $runtime·main·f(SB), BP // entry + PUSHQ BP PUSHQ $0 // arg size ARGSIZE(16) CALL runtime·newproc(SB) @@ -209,7 +210,8 @@ TEXT runtime·onM(SB), NOSPLIT, $0-8 // save our state in g->sched. Pretend to // be switchtoM if the G stack is scanned. - MOVQ $runtime·switchtoM(SB), (g_sched+gobuf_pc)(AX) + MOVQ $runtime·switchtoM(SB), BP + MOVQ BP, (g_sched+gobuf_pc)(AX) MOVQ SP, (g_sched+gobuf_sp)(AX) MOVQ AX, (g_sched+gobuf_g)(AX) @@ -302,7 +304,8 @@ TEXT runtime·newstackcall(SB), NOSPLIT, $0-20 // Save our own state as the PC and SP to restore // if this goroutine needs to be restarted. - MOVQ $runtime·newstackcall(SB), (g_sched+gobuf_pc)(AX) + MOVQ $runtime·newstackcall(SB), BP + MOVQ BP, (g_sched+gobuf_pc)(AX) MOVQ SP, (g_sched+gobuf_sp)(AX) // Set up morestack arguments to call f on a new stack. @@ -1002,7 +1005,8 @@ aessmall: // a page boundary, so we can load it directly. MOVOU (AX), X1 ADDQ CX, CX - PAND masks<>(SB)(CX*8), X1 + MOVQ $masks<>(SB), BP + PAND (BP)(CX*8), X1 JMP partial highpartial: // address ends in 1111xxxx. Might be up against @@ -1010,7 +1014,8 @@ highpartial: // Then shift bytes down using pshufb. MOVOU -16(AX)(CX*1), X1 ADDQ CX, CX - PSHUFB shifts<>(SB)(CX*8), X1 + MOVQ $shifts<>(SB), BP + PSHUFB (BP)(CX*8), X1 partial: // incorporate partial block into hash AESENC X3, X0 From 3763a395b227baba3a82d07c33c0a0ffd233f86f Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 12 Aug 2014 19:52:04 -0400 Subject: [PATCH 076/423] cmd/go: adjust import comment error Fixes #7453. LGTM=r R=r CC=golang-codereviews https://golang.org/cl/127210043 --- src/cmd/go/pkg.go | 2 +- src/cmd/go/test.bash | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go index eb8c451783..1af33f037a 100644 --- a/src/cmd/go/pkg.go +++ b/src/cmd/go/pkg.go @@ -267,7 +267,7 @@ func loadImport(path string, srcDir string, stk *importStack, importPos []token. bp.BinDir = gobin } if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path { - err = fmt.Errorf("directory %s contains package %q", bp.Dir, bp.ImportComment) + err = fmt.Errorf("code in directory %s expects import %q", bp.Dir, bp.ImportComment) } p.load(stk, bp, err) if p.Error != nil && len(importPos) > 0 { diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash index 93a7c67c18..2bb929fb03 100755 --- a/src/cmd/go/test.bash +++ b/src/cmd/go/test.bash @@ -131,7 +131,7 @@ TEST 'import comment - mismatch' if ./testgo build ./testdata/importcom/wrongplace.go 2>testdata/err; then echo 'go build ./testdata/importcom/wrongplace.go suceeded' ok=false -elif ! grep 'wrongplace contains package "my/x"' testdata/err >/dev/null; then +elif ! grep 'wrongplace expects import "my/x"' testdata/err >/dev/null; then echo 'go build did not mention incorrect import:' cat testdata/err ok=false From ce35994d4e8411a24833e4db3ddbfc6962eea467 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 12 Aug 2014 19:53:11 -0400 Subject: [PATCH 077/423] cmd/6c, cmd/6g: avoid address-as-constant in amd64 instructions This allows implementing address-of-global as a pc-relative address instead of as a 32-bit integer constant. LGTM=rminnich, iant R=golang-codereviews, rminnich, iant CC=golang-codereviews https://golang.org/cl/128070045 --- src/cmd/6c/sgen.c | 5 +---- src/cmd/6g/cgen.c | 7 +------ src/cmd/6g/gsubr.c | 5 +---- 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/src/cmd/6c/sgen.c b/src/cmd/6c/sgen.c index ba1c1f652d..c048e784d4 100644 --- a/src/cmd/6c/sgen.c +++ b/src/cmd/6c/sgen.c @@ -124,10 +124,7 @@ xcom(Node *n) break; case ONAME: - if(flag_largemodel) - n->addable = 9; - else - n->addable = 10; + n->addable = 9; if(n->class == CPARAM || n->class == CAUTO) n->addable = 11; break; diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c index 4dd505b086..bff2350621 100644 --- a/src/cmd/6g/cgen.c +++ b/src/cmd/6g/cgen.c @@ -752,12 +752,7 @@ agenr(Node *n, Node *a, Node *res) regalloc(&n3, types[tptr], res); p1 = gins(ALEAQ, N, &n3); datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from); - if(flag_largemodel) { - gins(AADDQ, &n2, &n3); - } else { - p1->from.scale = 1; - p1->from.index = n2.val.u.reg; - } + gins(AADDQ, &n2, &n3); goto indexdone; } diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c index f3464b7e1c..4ac2e92079 100644 --- a/src/cmd/6g/gsubr.c +++ b/src/cmd/6g/gsubr.c @@ -598,11 +598,8 @@ ismem(Node *n) case ONAME: case OPARAM: case OCLOSUREVAR: - return 1; case OADDR: - if(flag_largemodel) - return 1; - break; + return 1; } return 0; } From 8bca148a3e81631126b8d74e18c6cdb203313217 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Tue, 12 Aug 2014 17:04:45 -0700 Subject: [PATCH 078/423] all: copy cmd/ld/textflag.h into pkg/GOOS_GOARCH The file is used by assembly code to define symbols like NOSPLIT. Having it hidden inside the cmd directory makes it hard to access outside the standard repository. Solution: As with a couple of other files used by cgo, copy the file into the pkg directory and add a -I argument to the assembler to access it. Thus one can write just #include "textflag.h" in .s files. The names in runtime are not updated because in the boot sequence the file has not been copied yet when runtime is built. All other .s files in the repository are updated. Changes to doc/asm.html, src/cmd/dist/build.c, and src/cmd/go/build.go are hand-made. The rest are just the renaming done by a global substitution. (Yay sam). LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/128050043 --- doc/asm.html | 2 +- src/cmd/dist/build.c | 5 ++++- src/cmd/go/build.go | 4 +++- src/cmd/link/testdata/autosection.s | 2 +- src/cmd/link/testdata/layout.s | 2 +- src/pkg/crypto/aes/asm_amd64.s | 2 +- src/pkg/crypto/md5/md5block_386.s | 2 +- src/pkg/crypto/md5/md5block_amd64.s | 2 +- src/pkg/crypto/md5/md5block_amd64p32.s | 2 +- src/pkg/crypto/md5/md5block_arm.s | 2 +- src/pkg/crypto/rc4/rc4_386.s | 2 +- src/pkg/crypto/rc4/rc4_amd64.s | 2 +- src/pkg/crypto/rc4/rc4_amd64p32.s | 2 +- src/pkg/crypto/rc4/rc4_arm.s | 2 +- src/pkg/crypto/sha1/sha1block_386.s | 2 +- src/pkg/crypto/sha1/sha1block_amd64.s | 2 +- src/pkg/crypto/sha1/sha1block_amd64p32.s | 2 +- src/pkg/crypto/sha1/sha1block_arm.s | 2 +- src/pkg/crypto/sha256/sha256block_amd64.s | 2 +- src/pkg/crypto/sha512/sha512block_amd64.s | 2 +- src/pkg/hash/crc32/crc32_amd64.s | 2 +- src/pkg/hash/crc32/crc32_amd64p32.s | 2 +- src/pkg/math/abs_386.s | 2 +- src/pkg/math/abs_amd64.s | 2 +- src/pkg/math/abs_arm.s | 2 +- src/pkg/math/asin_386.s | 2 +- src/pkg/math/asin_amd64.s | 2 +- src/pkg/math/asin_arm.s | 2 +- src/pkg/math/atan2_386.s | 2 +- src/pkg/math/atan2_amd64.s | 2 +- src/pkg/math/atan2_arm.s | 2 +- src/pkg/math/atan_386.s | 2 +- src/pkg/math/atan_amd64.s | 2 +- src/pkg/math/atan_arm.s | 2 +- src/pkg/math/big/arith_386.s | 2 +- src/pkg/math/big/arith_amd64.s | 2 +- src/pkg/math/big/arith_amd64p32.s | 2 +- src/pkg/math/big/arith_arm.s | 2 +- src/pkg/math/dim_386.s | 2 +- src/pkg/math/dim_amd64.s | 2 +- src/pkg/math/dim_arm.s | 2 +- src/pkg/math/exp2_386.s | 2 +- src/pkg/math/exp2_amd64.s | 2 +- src/pkg/math/exp2_arm.s | 2 +- src/pkg/math/exp_386.s | 2 +- src/pkg/math/exp_amd64.s | 2 +- src/pkg/math/exp_arm.s | 2 +- src/pkg/math/expm1_386.s | 2 +- src/pkg/math/expm1_amd64.s | 2 +- src/pkg/math/expm1_arm.s | 2 +- src/pkg/math/floor_386.s | 2 +- src/pkg/math/floor_amd64.s | 2 +- src/pkg/math/floor_arm.s | 2 +- src/pkg/math/frexp_386.s | 2 +- src/pkg/math/frexp_amd64.s | 2 +- src/pkg/math/frexp_arm.s | 2 +- src/pkg/math/hypot_386.s | 2 +- src/pkg/math/hypot_amd64.s | 2 +- src/pkg/math/hypot_arm.s | 2 +- src/pkg/math/ldexp_386.s | 2 +- src/pkg/math/ldexp_amd64.s | 2 +- src/pkg/math/ldexp_arm.s | 2 +- src/pkg/math/log10_386.s | 2 +- src/pkg/math/log10_amd64.s | 2 +- src/pkg/math/log10_arm.s | 2 +- src/pkg/math/log1p_386.s | 2 +- src/pkg/math/log1p_amd64.s | 2 +- src/pkg/math/log1p_arm.s | 2 +- src/pkg/math/log_386.s | 2 +- src/pkg/math/log_amd64.s | 2 +- src/pkg/math/log_arm.s | 2 +- src/pkg/math/mod_386.s | 2 +- src/pkg/math/mod_amd64.s | 2 +- src/pkg/math/mod_arm.s | 2 +- src/pkg/math/modf_386.s | 2 +- src/pkg/math/modf_amd64.s | 2 +- src/pkg/math/modf_arm.s | 2 +- src/pkg/math/remainder_386.s | 2 +- src/pkg/math/remainder_amd64.s | 2 +- src/pkg/math/remainder_arm.s | 2 +- src/pkg/math/sin_386.s | 2 +- src/pkg/math/sin_amd64.s | 2 +- src/pkg/math/sin_arm.s | 2 +- src/pkg/math/sincos_386.s | 2 +- src/pkg/math/sincos_amd64.s | 2 +- src/pkg/math/sincos_arm.s | 2 +- src/pkg/math/sqrt_386.s | 2 +- src/pkg/math/sqrt_amd64.s | 2 +- src/pkg/math/sqrt_arm.s | 2 +- src/pkg/math/tan_386.s | 2 +- src/pkg/math/tan_amd64.s | 2 +- src/pkg/math/tan_arm.s | 2 +- src/pkg/os/signal/sig.s | 2 +- src/pkg/reflect/asm_386.s | 2 +- src/pkg/reflect/asm_amd64.s | 2 +- src/pkg/reflect/asm_amd64p32.s | 2 +- src/pkg/reflect/asm_arm.s | 2 +- src/pkg/sync/atomic/asm_386.s | 2 +- src/pkg/sync/atomic/asm_amd64.s | 2 +- src/pkg/sync/atomic/asm_amd64p32.s | 2 +- src/pkg/sync/atomic/asm_arm.s | 2 +- src/pkg/sync/atomic/asm_freebsd_arm.s | 2 +- src/pkg/sync/atomic/asm_linux_arm.s | 2 +- src/pkg/sync/atomic/asm_nacl_arm.s | 2 +- src/pkg/sync/atomic/asm_netbsd_arm.s | 2 +- src/pkg/syscall/asm_darwin_386.s | 2 +- src/pkg/syscall/asm_darwin_amd64.s | 2 +- src/pkg/syscall/asm_dragonfly_386.s | 2 +- src/pkg/syscall/asm_dragonfly_amd64.s | 2 +- src/pkg/syscall/asm_freebsd_386.s | 2 +- src/pkg/syscall/asm_freebsd_amd64.s | 2 +- src/pkg/syscall/asm_freebsd_arm.s | 2 +- src/pkg/syscall/asm_linux_386.s | 2 +- src/pkg/syscall/asm_linux_amd64.s | 2 +- src/pkg/syscall/asm_linux_arm.s | 2 +- src/pkg/syscall/asm_nacl_386.s | 2 +- src/pkg/syscall/asm_nacl_amd64p32.s | 2 +- src/pkg/syscall/asm_nacl_arm.s | 2 +- src/pkg/syscall/asm_netbsd_386.s | 2 +- src/pkg/syscall/asm_netbsd_amd64.s | 2 +- src/pkg/syscall/asm_netbsd_arm.s | 2 +- src/pkg/syscall/asm_openbsd_386.s | 2 +- src/pkg/syscall/asm_openbsd_amd64.s | 2 +- src/pkg/syscall/asm_plan9_386.s | 2 +- src/pkg/syscall/asm_plan9_amd64.s | 2 +- src/pkg/syscall/time_nacl_386.s | 2 +- src/pkg/syscall/time_nacl_amd64p32.s | 2 +- src/pkg/syscall/time_nacl_arm.s | 2 +- 128 files changed, 133 insertions(+), 128 deletions(-) diff --git a/doc/asm.html b/doc/asm.html index f4ef1e62f2..943347216e 100644 --- a/doc/asm.html +++ b/doc/asm.html @@ -253,7 +253,7 @@ There may be one or two arguments to the directives. If there are two, the first is a bit mask of flags, which can be written as numeric expressions, added or or-ed together, or can be set symbolically for easier absorption by a human. -Their values, defined in the file src/cmd/ld/textflag.h, are: +Their values, defined in the standard #include file textflag.h, are: