]> Cypherpunks.ru repositories - gostls13.git/commitdiff
Merge "[dev.ssa] Merge remote-tracking branch 'origin/master' into ssamerge" into...
authorGerrit Code Review <noreply-gerritcodereview@google.com>
Mon, 29 Feb 2016 23:19:17 +0000 (23:19 +0000)
committerGerrit Code Review <noreply-gerritcodereview@google.com>
Mon, 29 Feb 2016 23:19:17 +0000 (23:19 +0000)
240 files changed:
.github/ISSUE_TEMPLATE [new file with mode: 0644]
.github/PULL_REQUEST_TEMPLATE [new file with mode: 0644]
.gitignore
doc/go1.7.txt
doc/install-source.html
misc/cgo/errors/ptr.go
misc/cgo/fortran/answer.f90 [new file with mode: 0644]
misc/cgo/fortran/fortran.go [new file with mode: 0644]
misc/cgo/fortran/fortran_test.go [new file with mode: 0644]
misc/cgo/fortran/helloworld/helloworld.f90 [new file with mode: 0644]
misc/cgo/fortran/test.bash [new file with mode: 0755]
misc/cgo/testcshared/test.bash
misc/git/pre-commit
src/bufio/bufio.go
src/bufio/scan_test.go
src/buildall.bash
src/bytes/bytes_test.go
src/cmd/asm/doc.go
src/cmd/asm/internal/asm/endtoend_test.go
src/cmd/asm/internal/asm/parse.go
src/cmd/asm/internal/asm/pseudo_test.go
src/cmd/asm/internal/asm/testdata/arm64.s
src/cmd/asm/internal/flags/flags.go
src/cmd/asm/internal/lex/input.go
src/cmd/asm/internal/lex/lex.go
src/cmd/asm/main.go
src/cmd/cgo/doc.go
src/cmd/cgo/gcc.go
src/cmd/compile/internal/amd64/ggen.go
src/cmd/compile/internal/amd64/peep.go
src/cmd/compile/internal/arm/ggen.go
src/cmd/compile/internal/arm64/ggen.go
src/cmd/compile/internal/gc/alg.go [new file with mode: 0644]
src/cmd/compile/internal/gc/bexport.go
src/cmd/compile/internal/gc/bimport.go
src/cmd/compile/internal/gc/cgen.go
src/cmd/compile/internal/gc/closure.go
src/cmd/compile/internal/gc/dcl.go
src/cmd/compile/internal/gc/esc.go
src/cmd/compile/internal/gc/fmt.go
src/cmd/compile/internal/gc/gen.go
src/cmd/compile/internal/gc/global_test.go
src/cmd/compile/internal/gc/go.go
src/cmd/compile/internal/gc/gsubr.go
src/cmd/compile/internal/gc/inl.go
src/cmd/compile/internal/gc/lex.go
src/cmd/compile/internal/gc/mparith2.go
src/cmd/compile/internal/gc/mparith3.go
src/cmd/compile/internal/gc/order.go
src/cmd/compile/internal/gc/parser.go
src/cmd/compile/internal/gc/pgen.go
src/cmd/compile/internal/gc/plive.go
src/cmd/compile/internal/gc/popt.go
src/cmd/compile/internal/gc/racewalk.go
src/cmd/compile/internal/gc/reflect.go
src/cmd/compile/internal/gc/sinit.go
src/cmd/compile/internal/gc/ssa.go
src/cmd/compile/internal/gc/subr.go
src/cmd/compile/internal/gc/syntax.go
src/cmd/compile/internal/gc/typecheck.go
src/cmd/compile/internal/gc/walk.go
src/cmd/compile/internal/mips64/ggen.go
src/cmd/compile/internal/ppc64/ggen.go
src/cmd/compile/internal/x86/ggen.go
src/cmd/compile/internal/x86/peep.go
src/cmd/dist/build.go
src/cmd/dist/buildgo.go
src/cmd/dist/main.go
src/cmd/dist/test.go
src/cmd/go/build.go
src/cmd/go/get.go
src/cmd/go/go_test.go
src/cmd/go/list.go
src/cmd/go/pkg.go
src/cmd/go/test.go
src/cmd/internal/goobj/read.go
src/cmd/internal/obj/arm/obj5.go
src/cmd/internal/obj/link.go
src/cmd/internal/obj/mips/obj0.go
src/cmd/internal/obj/objfile.go
src/cmd/internal/obj/pass.go
src/cmd/internal/obj/sym.go
src/cmd/internal/obj/util.go
src/cmd/internal/obj/x86/obj6.go
src/cmd/link/internal/arm/asm.go
src/cmd/link/internal/arm/obj.go
src/cmd/link/internal/arm64/asm.go
src/cmd/link/internal/ld/dwarf_defs.go
src/cmd/link/internal/ld/ldelf.go
src/cmd/link/internal/ld/lib.go
src/cmd/link/internal/ld/macho.go
src/cmd/pprof/internal/report/report.go
src/cmd/pprof/internal/report/source.go
src/cmd/vet/doc.go
src/cmd/vet/example.go [deleted file]
src/cmd/vet/testdata/tests_test.go [moved from src/cmd/vet/testdata/examples_test.go with 59% similarity]
src/cmd/vet/tests.go [new file with mode: 0644]
src/crypto/ecdsa/ecdsa_test.go
src/crypto/md5/md5block_arm.s
src/crypto/rand/rand.go
src/crypto/rand/rand_openbsd.go [new file with mode: 0644]
src/crypto/tls/handshake_client.go
src/crypto/tls/handshake_client_test.go
src/crypto/x509/example_test.go
src/crypto/x509/root_darwin_test.go
src/crypto/x509/x509.go
src/database/sql/sql_test.go
src/debug/dwarf/entry.go
src/debug/gosym/pclntab_test.go
src/encoding/base32/base32_test.go
src/encoding/base64/base64_test.go
src/encoding/csv/reader.go
src/encoding/json/bench_test.go
src/expvar/expvar.go
src/expvar/expvar_test.go
src/fmt/fmt_test.go
src/fmt/format.go
src/fmt/print.go
src/fmt/scan.go
src/fmt/scan_test.go
src/go/build/build.go
src/go/build/build_test.go
src/go/internal/gcimporter/exportdata.go
src/go/internal/gcimporter/gcimporter.go
src/go/parser/parser.go
src/go/types/builtins.go
src/go/types/testdata/const0.src
src/html/template/template_test.go
src/image/gif/reader.go
src/internal/syscall/unix/getentropy_openbsd.go [new file with mode: 0644]
src/internal/syscall/windows/registry/registry_test.go
src/make.bash
src/make.bat
src/math/big/float.go
src/math/big/floatconv.go
src/net/dnsclient.go
src/net/dnsclient_unix_test.go
src/net/fd_poll_runtime.go
src/net/http/client_test.go
src/net/http/cookie.go
src/net/http/h2_bundle.go
src/net/http/httptest/server_test.go
src/net/http/request.go
src/net/http/request_test.go
src/net/http/requestwrite_test.go
src/net/http/server.go
src/net/http/transfer.go
src/net/http/transport.go
src/net/http/transport_test.go
src/net/interface_bsd.go
src/net/interface_darwin.go
src/net/interface_freebsd.go
src/net/interface_test.go
src/net/interface_unix_test.go
src/net/ip_test.go
src/net/iprawsock_test.go [moved from src/net/ipraw_test.go with 100% similarity]
src/net/ipsock_posix.go
src/net/listen_test.go
src/net/main_conf_test.go [new file with mode: 0644]
src/net/main_noconf_test.go [moved from src/net/non_unix_test.go with 78% similarity]
src/net/net_windows_test.go
src/net/sendfile_windows.go
src/net/tcpsock_test.go [moved from src/net/tcp_test.go with 100% similarity]
src/net/textproto/reader.go
src/net/textproto/reader_test.go
src/net/timeout_test.go
src/net/udpsock_test.go [moved from src/net/udp_test.go with 99% similarity]
src/net/unixsock_test.go [moved from src/net/unix_test.go with 93% similarity]
src/net/url/url.go
src/net/url/url_test.go
src/os/exec/exec_test.go
src/os/exec/lp_windows_test.go
src/os/os_test.go
src/os/str.go
src/os/user/lookup_windows.go
src/path/filepath/path_windows.go
src/reflect/all_test.go
src/reflect/export_test.go
src/reflect/type.go
src/regexp/exec_test.go
src/runtime/alg.go
src/runtime/asm_amd64.s
src/runtime/asm_arm.s
src/runtime/callers_test.go [new file with mode: 0644]
src/runtime/cgo/callbacks.go
src/runtime/chan.go
src/runtime/chan_test.go
src/runtime/crash_cgo_test.go
src/runtime/error.go
src/runtime/extern.go
src/runtime/heapdump.go
src/runtime/iface.go
src/runtime/mbitmap.go
src/runtime/mcentral.go
src/runtime/memclr_amd64.s
src/runtime/memmove_ppc64x.s
src/runtime/mfinal.go
src/runtime/mgc.go
src/runtime/mgcmark.go
src/runtime/mgcsweep.go
src/runtime/mgcwork.go
src/runtime/mprof.go
src/runtime/netpoll_solaris.go
src/runtime/os_linux_386.go
src/runtime/pprof/pprof.go
src/runtime/proc.go
src/runtime/race/output_test.go
src/runtime/rt0_linux_386.s
src/runtime/runtime1.go
src/runtime/runtime2.go
src/runtime/runtime_test.go
src/runtime/select.go
src/runtime/signal_386.go
src/runtime/softfloat_arm.go
src/runtime/string.go
src/runtime/symtab.go
src/runtime/sys_linux_386.s
src/runtime/sys_solaris_amd64.s
src/runtime/testdata/testprogcgo/cgo.go
src/runtime/traceback.go
src/runtime/type.go
src/sort/sort.go
src/sort/sort_test.go
src/strconv/quote.go
src/strconv/quote_test.go
src/sync/atomic/asm_plan9_arm.s [new file with mode: 0644]
src/sync/atomic/value_test.go
src/syscall/asm_linux_386.s
src/syscall/asm_plan9_arm.s [new file with mode: 0644]
src/syscall/route_bsd.go
src/syscall/zsyscall_plan9_arm.go [new file with mode: 0644]
src/testing/quick/quick.go
src/testing/quick/quick_test.go
src/text/tabwriter/example_test.go
src/text/tabwriter/tabwriter.go
src/text/template/multi_test.go
src/unicode/utf16/utf16.go
test/fixedbugs/bug108.go
test/fixedbugs/issue11610.go
test/fixedbugs/issue14520.go [new file with mode: 0644]

diff --git a/.github/ISSUE_TEMPLATE b/.github/ISSUE_TEMPLATE
new file mode 100644 (file)
index 0000000..f44c6b9
--- /dev/null
@@ -0,0 +1,18 @@
+Please answer these questions before submitting your issue. Thanks!
+
+1. What version of Go are you using (`go version`)?
+
+
+2. What operating system and processor architecture are you using (`go env`)?
+
+
+3. What did you do?
+(Use play.golang.org to provide a runnable example, if possible.)
+
+
+4. What did you expect to see?
+
+
+5. What did you see instead?
+
+
diff --git a/.github/PULL_REQUEST_TEMPLATE b/.github/PULL_REQUEST_TEMPLATE
new file mode 100644 (file)
index 0000000..00014e9
--- /dev/null
@@ -0,0 +1,7 @@
+Please do not send pull requests to the golang/* repositories.
+
+We do, however, take contributions gladly.
+
+See https://golang.org/doc/contribute.html
+
+Thanks!
index de48481bf1412148e9c839eea1dd27cceb238358..1677a18fc8bbb730711a6a4d9bc1830904d06ab0 100644 (file)
@@ -28,6 +28,7 @@ src/cmd/**/y.output
 src/cmd/cgo/zdefaultcc.go
 src/cmd/go/zdefaultcc.go
 src/cmd/internal/obj/zbootstrap.go
+src/go/build/zcgo.go
 src/go/doc/headscan
 src/runtime/internal/sys/zversion.go
 src/unicode/maketables
index 15efa287ce9aa4718a308d3514b9e22a1117e977..88f22b2df115e08785f648097b4cbda2474ca25b 100644 (file)
@@ -1,14 +1,20 @@
 Tools:
 
+cmd/dist: add list subcommand to list all supported platforms (CL 19837)
 cmd/go: GO15VENDOREXPERIMENT gone, assumed on (CL 19615)
 cmd/link: "-X name value" form gone (CL 19614)
+cmd/compile: smaller binaries (many CLs)
+cmd/go, go/build: add support for Fortran (CL 19670, CL 4114)
+cmd/dist: introduce list subcommand to list all supported platforms (CL 19837)
 
 Ports:
 
-SOMETHING WILL HAPPEN
+We now require OpenBSD 5.6+ (CL 18219, crypto/rand using getentropy)
+plan9/arm support? Start at least.
 
 API additions and behavior changes:
 
-SOMETHING WILL HAPPEN
-
-
+runtime: add CallerFrames and Frames (CL 19869)
+testing/quick: now generates nil values (CL 16470)
+net/url: support query string without values (CL 19931)
+net/textproto: permit all valid token chars in CanonicalMIMEHeaderKey input (CL 18725)
index 332c72097ea2b6da86ad1e1664bfbffb911d7931..b8cd8dbcfc611ff2ca1abf460dd886f2c3ac05ca 100644 (file)
@@ -445,6 +445,9 @@ The valid combinations of <code>$GOOS</code> and <code>$GOARCH</code> are:
 <th width="50"></th><th align="left" width="100"><code>$GOOS</code></th> <th align="left" width="100"><code>$GOARCH</code></th>
 </tr>
 <tr>
+<td></td><td><code>android</code></td> <td><code>arm</code></td>
+</tr>
+<tr>
 <td></td><td><code>darwin</code></td> <td><code>386</code></td>
 </tr>
 <tr>
index 834cde9199175de2df55b3223bc4ff4f549c0394..bbcaaabecb7bd4fb4ebed2eb48a70fe89564047e 100644 (file)
@@ -122,6 +122,16 @@ var ptrTests = []ptrTest{
                body:    `i := 0; p := &S{p:&i}; s := p.a[:]; C.f(unsafe.Pointer(&s[0]))`,
                fail:    false,
        },
+       {
+               // Passing the address of a slice of an array that is
+               // an element in a struct, with a type conversion.
+               name:    "slice-ok-4",
+               c:       `typedef void* PV; void f(PV p) {}`,
+               imports: []string{"unsafe"},
+               support: `type S struct { p *int; a [4]byte }`,
+               body:    `i := 0; p := &S{p:&i}; C.f(C.PV(unsafe.Pointer(&p.a[0])))`,
+               fail:    false,
+       },
        {
                // Passing the address of a static variable with no
                // pointers doesn't matter.
diff --git a/misc/cgo/fortran/answer.f90 b/misc/cgo/fortran/answer.f90
new file mode 100644 (file)
index 0000000..6b29d78
--- /dev/null
@@ -0,0 +1,9 @@
+! Copyright 2016 The Go Authors.  All rights reserved.
+! Use of this source code is governed by a BSD-style
+! license that can be found in the LICENSE file.
+
+function the_answer() result(j) bind(C)
+  use iso_c_binding, only: c_int
+  integer(c_int) :: j ! output
+  j = 42
+end function the_answer
diff --git a/misc/cgo/fortran/fortran.go b/misc/cgo/fortran/fortran.go
new file mode 100644 (file)
index 0000000..8d008b4
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright 2016 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fortran
+
+// int the_answer();
+import "C"
+
+func TheAnswer() int {
+       return int(C.the_answer())
+}
diff --git a/misc/cgo/fortran/fortran_test.go b/misc/cgo/fortran/fortran_test.go
new file mode 100644 (file)
index 0000000..a7ba648
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2016 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fortran
+
+import "testing"
+
+func TestFortran(t *testing.T) {
+       if a := TheAnswer(); a != 42 {
+               t.Errorf("Unexpected result for The Answer. Got: %d Want: 42", a)
+       }
+}
diff --git a/misc/cgo/fortran/helloworld/helloworld.f90 b/misc/cgo/fortran/helloworld/helloworld.f90
new file mode 100644 (file)
index 0000000..cbc34c1
--- /dev/null
@@ -0,0 +1,3 @@
+      program HelloWorldF90
+              write(*,*) "Hello World!"
+      end program HelloWorldF90
diff --git a/misc/cgo/fortran/test.bash b/misc/cgo/fortran/test.bash
new file mode 100755 (executable)
index 0000000..9350dbe
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/env bash
+# Copyright 2016 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# This directory is intended to test the use of Fortran with cgo.
+
+set -e
+
+FC=$1
+
+if ! $FC helloworld/helloworld.f90 -o main.exe >& /dev/null; then
+  echo "skipping Fortran test: could not build helloworld.f90 with $FC"
+  exit 0
+fi
+
+if ! go test; then
+  echo "FAIL: go test"
+  status=1
+fi
+
+exit $status
index 23c97675bb3e9e382278cdd0fa26d27042b2bbb5..c5c49a10e1865487e80d4f114b8f86413798d4b7 100755 (executable)
@@ -10,7 +10,7 @@ set -e
 
 if [ ! -f src/libgo/libgo.go ]; then
        cwd=$(pwd)
-       echo 'misc/cgo/testcshared/test.bash is running in $cwd' 1>&2
+       echo "misc/cgo/testcshared/test.bash is running in $cwd" 1>&2
        exit 1
 fi
 
index 18b7f832f36ec4ed349bd71fa67ee15fdf5bbd1c..242159f04af5436702e0880dedd00c8b6796498f 100755 (executable)
@@ -10,7 +10,7 @@
 #
 # This script does not handle file names that contain spaces.
 
-gofiles=$(git diff --cached --name-only --diff-filter=ACM | grep '.go$')
+gofiles=$(git diff --cached --name-only --diff-filter=ACM | grep '\.go$')
 [ -z "$gofiles" ] && exit 0
 
 unformatted=$(gofmt -l $gofiles)
index 6a70f7034d043142c30f27a19d56bb28d6113b2a..33470ccd416da567def80dea6f93a9c5c102e602 100644 (file)
@@ -705,7 +705,7 @@ func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) {
                }
        }
        if err == io.EOF {
-               // If we filled the buffer exactly, flush pre-emptively.
+               // If we filled the buffer exactly, flush preemptively.
                if b.Available() == 0 {
                        err = b.flush()
                } else {
index 07b1a56dc0a4654a294b5085c5a6a6aad15e5831..d64d0b45d7346aad071ed68708b0ec2780ebe9d1 100644 (file)
@@ -351,7 +351,7 @@ func TestSplitError(t *testing.T) {
 // Test that an EOF is overridden by a user-generated scan error.
 func TestErrAtEOF(t *testing.T) {
        s := NewScanner(strings.NewReader("1 2 33"))
-       // This spitter will fail on last entry, after s.err==EOF.
+       // This splitter will fail on last entry, after s.err==EOF.
        split := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
                advance, token, err = ScanWords(data, atEOF)
                if len(token) > 1 {
index f686dd8996434ec80583f1948951f83c345166d9..a322fe537a17c631eb1329c88c7fc409746b5abd 100755 (executable)
@@ -32,13 +32,13 @@ if [ "$pattern" = "" ]; then
     pattern=.
 fi
 
-# put linux, nacl first in the target list to get all the architectures up front.
-targets="$((ls runtime | sed -n 's/^rt0_\(.*\)_\(.*\)\.s/\1-\2/p'; echo linux-386-387 linux-arm-arm5) | sort | sed -e 's|linux-mips64x|linux-mips64 linux-mips64le|' | egrep -v android-arm | egrep "$pattern" | egrep 'linux|nacl')
-$(ls runtime | sed -n 's/^rt0_\(.*\)_\(.*\)\.s/\1-\2/p' | egrep -v 'android-arm|darwin-arm' | egrep "$pattern" | egrep -v 'linux|nacl')"
-
 ./make.bash || exit 1
 GOROOT="$(cd .. && pwd)"
 
+# put linux, nacl first in the target list to get all the architectures up front.
+targets="$((../bin/go tool dist list | sed -n 's/^\(.*\)\/\(.*\)/\1-\2/p'; echo linux-386-387 linux-arm-arm5) | sort | egrep -v android-arm | egrep "$pattern" | egrep 'linux|nacl')
+$(../bin/go tool dist list | sed -n 's/^\(.*\)\/\(.*\)/\1-\2/p' | egrep -v 'android-arm|darwin-arm' | egrep "$pattern" | egrep -v 'linux|nacl')"
+
 failed=false
 for target in $targets
 do
index 8df62fcc6aec1742a277d5fafd3d4a9705a63d30..a412dc89b9f054545e233294b329833d7ddcb23d 100644 (file)
@@ -335,6 +335,41 @@ func TestIndexByteBig(t *testing.T) {
        }
 }
 
+// test a small index across all page offsets
+func TestIndexByteSmall(t *testing.T) {
+       b := make([]byte, 5015) // bigger than a page
+       // Make sure we find the correct byte even when straddling a page.
+       for i := 0; i <= len(b)-15; i++ {
+               for j := 0; j < 15; j++ {
+                       b[i+j] = byte(100 + j)
+               }
+               for j := 0; j < 15; j++ {
+                       p := IndexByte(b[i:i+15], byte(100+j))
+                       if p != j {
+                               t.Errorf("IndexByte(%q, %d) = %d", b[i:i+15], 100+j, p)
+                       }
+               }
+               for j := 0; j < 15; j++ {
+                       b[i+j] = 0
+               }
+       }
+       // Make sure matches outside the slice never trigger.
+       for i := 0; i <= len(b)-15; i++ {
+               for j := 0; j < 15; j++ {
+                       b[i+j] = 1
+               }
+               for j := 0; j < 15; j++ {
+                       p := IndexByte(b[i:i+15], byte(0))
+                       if p != -1 {
+                               t.Errorf("IndexByte(%q, %d) = %d", b[i:i+15], 0, p)
+                       }
+               }
+               for j := 0; j < 15; j++ {
+                       b[i+j] = 0
+               }
+       }
+}
+
 func TestIndexRune(t *testing.T) {
        for _, tt := range indexRuneTests {
                a := []byte(tt.a)
@@ -348,10 +383,12 @@ func TestIndexRune(t *testing.T) {
 
 var bmbuf []byte
 
+func BenchmarkIndexByte10(b *testing.B)          { bmIndexByte(b, IndexByte, 10) }
 func BenchmarkIndexByte32(b *testing.B)          { bmIndexByte(b, IndexByte, 32) }
 func BenchmarkIndexByte4K(b *testing.B)          { bmIndexByte(b, IndexByte, 4<<10) }
 func BenchmarkIndexByte4M(b *testing.B)          { bmIndexByte(b, IndexByte, 4<<20) }
 func BenchmarkIndexByte64M(b *testing.B)         { bmIndexByte(b, IndexByte, 64<<20) }
+func BenchmarkIndexBytePortable10(b *testing.B)  { bmIndexByte(b, IndexBytePortable, 10) }
 func BenchmarkIndexBytePortable32(b *testing.B)  { bmIndexByte(b, IndexBytePortable, 32) }
 func BenchmarkIndexBytePortable4K(b *testing.B)  { bmIndexByte(b, IndexBytePortable, 4<<10) }
 func BenchmarkIndexBytePortable4M(b *testing.B)  { bmIndexByte(b, IndexBytePortable, 4<<20) }
index a9c8bfb7dbc3dbb099361df567a4c4e937b03e92..aa621479579aa1acd572b8678f022349f8d9c6d1 100644 (file)
@@ -20,7 +20,7 @@ The GOOS and GOARCH environment variables set the desired target.
 Flags:
 
        -D value
-               predefined symbol with optional simple value -D=identifer=value;
+               predefined symbol with optional simple value -D=identifier=value;
                can be set multiple times
        -I value
                include directory; can be set multiple times
index 4bc7e2fb7493e3602dcfaad45053c788f2ac2adc..4a3e0ee26593c8e3fb07b9e46988a8e3e6dda19a 100644 (file)
@@ -179,7 +179,7 @@ Diff:
                t.Errorf(format, args...)
                ok = false
        }
-       obj.Flushplist(ctxt)
+       obj.FlushplistNoFree(ctxt)
 
        for p := top; p != nil; p = p.Link {
                if p.As == obj.ATEXT {
index 4258c5ce263f0f58ed9d9035410b24343bdae40e..6c324ce3af7ed568d42a428c53b5ff0fc255ad6f 100644 (file)
@@ -297,7 +297,7 @@ func (p *Parser) operand(a *obj.Addr) bool {
                        p.errorf("illegal use of register list")
                }
                p.registerList(a)
-               p.expect(scanner.EOF)
+               p.expectOperandEnd()
                return true
        }
 
@@ -331,7 +331,7 @@ func (p *Parser) operand(a *obj.Addr) bool {
                        }
                }
                // fmt.Printf("REG %s\n", obj.Dconv(&emptyProg, 0, a))
-               p.expect(scanner.EOF)
+               p.expectOperandEnd()
                return true
        }
 
@@ -363,7 +363,7 @@ func (p *Parser) operand(a *obj.Addr) bool {
                        a.Type = obj.TYPE_FCONST
                        a.Val = p.floatExpr()
                        // fmt.Printf("FCONST %s\n", obj.Dconv(&emptyProg, 0, a))
-                       p.expect(scanner.EOF)
+                       p.expectOperandEnd()
                        return true
                }
                if p.have(scanner.String) {
@@ -378,7 +378,7 @@ func (p *Parser) operand(a *obj.Addr) bool {
                        a.Type = obj.TYPE_SCONST
                        a.Val = str
                        // fmt.Printf("SCONST %s\n", obj.Dconv(&emptyProg, 0, a))
-                       p.expect(scanner.EOF)
+                       p.expectOperandEnd()
                        return true
                }
                a.Offset = int64(p.expr())
@@ -392,7 +392,7 @@ func (p *Parser) operand(a *obj.Addr) bool {
                                a.Type = obj.TYPE_MEM
                        }
                        // fmt.Printf("CONST %d %s\n", a.Offset, obj.Dconv(&emptyProg, 0, a))
-                       p.expect(scanner.EOF)
+                       p.expectOperandEnd()
                        return true
                }
                // fmt.Printf("offset %d \n", a.Offset)
@@ -402,7 +402,7 @@ func (p *Parser) operand(a *obj.Addr) bool {
        p.registerIndirect(a, prefix)
        // fmt.Printf("DONE %s\n", p.arch.Dconv(&emptyProg, 0, a))
 
-       p.expect(scanner.EOF)
+       p.expectOperandEnd()
        return true
 }
 
@@ -983,14 +983,19 @@ func (p *Parser) more() bool {
 
 // get verifies that the next item has the expected type and returns it.
 func (p *Parser) get(expected lex.ScanToken) lex.Token {
-       p.expect(expected)
+       p.expect(expected, expected.String())
        return p.next()
 }
 
+// expectOperandEnd verifies that the parsing state is properly at the end of an operand.
+func (p *Parser) expectOperandEnd() {
+       p.expect(scanner.EOF, "end of operand")
+}
+
 // expect verifies that the next item has the expected type. It does not consume it.
-func (p *Parser) expect(expected lex.ScanToken) {
-       if p.peek() != expected {
-               p.errorf("expected %s, found %s", expected, p.next())
+func (p *Parser) expect(expectedToken lex.ScanToken, expectedMessage string) {
+       if p.peek() != expectedToken {
+               p.errorf("expected %s, found %s", expectedMessage, p.next())
        }
 }
 
index ee13b724ebecfe34567287d0204dfea2895a306d..2e6d6c8154f327225cceb9610945102ac671cfef 100644 (file)
@@ -35,8 +35,8 @@ func TestErroneous(t *testing.T) {
                {"TEXT", "%", "expect two or three operands for TEXT"},
                {"TEXT", "1, 1", "TEXT symbol \"<erroneous symbol>\" must be a symbol(SB)"},
                {"TEXT", "$\"foo\", 0, $1", "TEXT symbol \"<erroneous symbol>\" must be a symbol(SB)"},
-               {"TEXT", "$0É:0, 0, $1", "expected EOF, found Ã‰"},   // Issue #12467.
-               {"TEXT", "$:0:(SB, 0, $1", "expected '(', found 0"}, // Issue 12468.
+               {"TEXT", "$0É:0, 0, $1", "expected end of operand, found Ã‰"}, // Issue #12467.
+               {"TEXT", "$:0:(SB, 0, $1", "expected '(', found 0"},          // Issue 12468.
                {"FUNCDATA", "", "expect two operands for FUNCDATA"},
                {"FUNCDATA", "(SB ", "expect two operands for FUNCDATA"},
                {"DATA", "", "expect two operands for DATA"},
index 22d430631cf06735174a1d28a972038a18366856..6466da7190542ca631a70f882000c012da394127 100644 (file)
@@ -237,7 +237,7 @@ again:
 //
 //             LSTXR reg ',' addr ',' reg
 //     {
-//             outtcode($1, &$2, &$4, &$6);
+//             outcode($1, &$2, &$4, &$6);
 //     }
        LDAXRW  (R0), R2
        STLXRW  R1, (R0), R3
index 9f3c3bfc1da752209b44728f159684778eed2419..4557c2a7f9edf366eb59a3829da8b2ef33a53c05 100644 (file)
@@ -29,7 +29,7 @@ var (
 )
 
 func init() {
-       flag.Var(&D, "D", "predefined symbol with optional simple value -D=identifer=value; can be set multiple times")
+       flag.Var(&D, "D", "predefined symbol with optional simple value -D=identifier=value; can be set multiple times")
        flag.Var(&I, "I", "include directory; can be set multiple times")
 }
 
index 33b9d8adeaf439c009bcd4689e887ceb914241c3..4855daa892ff72b88e3e835ba22e1154865d2e4c 100644 (file)
@@ -30,7 +30,7 @@ type Input struct {
        peekText        string
 }
 
-// NewInput returns a
+// NewInput returns an Input from the given path.
 func NewInput(name string) *Input {
        return &Input{
                // include directories: look in source dir, then -I directories.
index 6fce55f7f4041f4349b71b0d57533be5f71f7d3e..81339059b197654a333d198a438c8522e2d2f12e 100644 (file)
@@ -77,7 +77,7 @@ func NewLexer(name string, ctxt *obj.Link) TokenReader {
        input := NewInput(name)
        fd, err := os.Open(name)
        if err != nil {
-               log.Fatalf("asm: %s\n", err)
+               log.Fatalf("%s\n", err)
        }
        input.Push(NewTokenizer(name, fd, fd))
        return input
index f48050c137871c7e73afab908a182dcad5d846fc..4e450bec9893cfcb5b5fcb831d3d428bf65e8796 100644 (file)
@@ -26,7 +26,7 @@ func main() {
 
        architecture := arch.Set(GOARCH)
        if architecture == nil {
-               log.Fatalf("asm: unrecognized architecture %s", GOARCH)
+               log.Fatalf("unrecognized architecture %s", GOARCH)
        }
 
        flags.Parse()
@@ -66,7 +66,7 @@ func main() {
                obj.Writeobjdirect(ctxt, output)
        }
        if !ok || diag {
-               log.Printf("asm: assembly of %s failed", flag.Arg(0))
+               log.Printf("assembly of %s failed", flag.Arg(0))
                os.Remove(*flags.OutputFile)
                os.Exit(1)
        }
index 90c2584c7fb0d7db09ada8fe238f10ad82662308..58be391573ce46ed0d30d60cd01843c761103fc4 100644 (file)
@@ -31,9 +31,9 @@ See $GOROOT/misc/cgo/stdio and $GOROOT/misc/cgo/gmp for examples.  See
 "C? Go? Cgo!" for an introduction to using cgo:
 https://golang.org/doc/articles/c_go_cgo.html.
 
-CFLAGS, CPPFLAGS, CXXFLAGS and LDFLAGS may be defined with pseudo #cgo
-directives within these comments to tweak the behavior of the C or C++
-compiler.  Values defined in multiple directives are concatenated
+CFLAGS, CPPFLAGS, CXXFLAGS, FFLAGS and LDFLAGS may be defined with pseudo
+#cgo directives within these comments to tweak the behavior of the C, C++
+or Fortran compiler.  Values defined in multiple directives are concatenated
 together.  The directive can include a list of build constraints limiting its
 effect to systems satisfying one of the constraints
 (see https://golang.org/pkg/go/build/#hdr-Build_Constraints for details about the constraint syntax).
@@ -53,7 +53,7 @@ For example:
        // #include <png.h>
        import "C"
 
-When building, the CGO_CFLAGS, CGO_CPPFLAGS, CGO_CXXFLAGS and
+When building, the CGO_CFLAGS, CGO_CPPFLAGS, CGO_CXXFLAGS, CGO_FFLAGS and
 CGO_LDFLAGS environment variables are added to the flags derived from
 these directives.  Package-specific flags should be set using the
 directives, not the environment variables, so that builds work in
@@ -62,10 +62,11 @@ unmodified environments.
 All the cgo CPPFLAGS and CFLAGS directives in a package are concatenated and
 used to compile C files in that package.  All the CPPFLAGS and CXXFLAGS
 directives in a package are concatenated and used to compile C++ files in that
-package.  All the LDFLAGS directives in any package in the program are
-concatenated and used at link time.  All the pkg-config directives are
-concatenated and sent to pkg-config simultaneously to add to each appropriate
-set of command-line flags.
+package.  All the CPPFLAGS and FFLAGS directives in a package are concatenated
+and used to compile Fortran files in that package.  All the LDFLAGS directives
+in any package in the program are concatenated and used at link time.  All the
+pkg-config directives are concatenated and sent to pkg-config simultaneously
+to add to each appropriate set of command-line flags.
 
 When the cgo directives are parsed, any occurrence of the string ${SRCDIR}
 will be replaced by the absolute path to the directory containing the source
@@ -83,7 +84,8 @@ When the Go tool sees that one or more Go files use the special import
 "C", it will look for other non-Go files in the directory and compile
 them as part of the Go package.  Any .c, .s, or .S files will be
 compiled with the C compiler.  Any .cc, .cpp, or .cxx files will be
-compiled with the C++ compiler.  Any .h, .hh, .hpp, or .hxx files will
+compiled with the C++ compiler.  Any .f, .F, .for or .f90 files will be
+compiled with the fortran compiler. Any .h, .hh, .hpp, or .hxx files will
 not be compiled separately, but, if these header files are changed,
 the C and C++ files will be recompiled.  The default C and C++
 compilers may be changed by the CC and CXX environment variables,
index 5bfdef785c10556dfb12dc88a1b3786b6628a63a..fe9af1769dc7ff1a0e781270dfe2f91503980c5c 100644 (file)
@@ -819,14 +819,17 @@ func (p *Package) hasSideEffects(f *File, x ast.Expr) bool {
 func (p *Package) isType(t ast.Expr) bool {
        switch t := t.(type) {
        case *ast.SelectorExpr:
-               if t.Sel.Name != "Pointer" {
-                       return false
-               }
                id, ok := t.X.(*ast.Ident)
                if !ok {
                        return false
                }
-               return id.Name == "unsafe"
+               if id.Name == "unsafe" && t.Sel.Name == "Pointer" {
+                       return true
+               }
+               if id.Name == "C" && typedef["_Ctype_"+t.Sel.Name] != nil {
+                       return true
+               }
+               return false
        case *ast.Ident:
                // TODO: This ignores shadowing.
                switch t.Name {
index 84c3d5d7d49a640067bf905717efe3001ec66f1c..55fb9e0a43311a4379b0c4c82549656a4f11a917 100644 (file)
@@ -10,9 +10,10 @@ import (
        "cmd/internal/obj/x86"
 )
 
-func defframe(ptxt *obj.Prog) {
-       var n *gc.Node
+// no floating point in note handlers on Plan 9
+var isPlan9 = obj.Getgoos() == "plan9"
 
+func defframe(ptxt *obj.Prog) {
        // fill in argument size, stack size
        ptxt.To.Type = obj.TYPE_TEXTSIZE
 
@@ -31,8 +32,7 @@ func defframe(ptxt *obj.Prog) {
        x0 := uint32(0)
 
        // iterate through declarations - they are sorted in decreasing xoffset order.
-       for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next {
-               n = l.N
+       for _, n := range gc.Curfn.Func.Dcl {
                if !n.Name.Needzero {
                        continue
                }
@@ -126,7 +126,7 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, ax *uint32, x0 *uin
                        *ax = 1
                }
                p = appendpp(p, x86.AMOVQ, obj.TYPE_REG, x86.REG_AX, 0, obj.TYPE_MEM, x86.REG_SP, frame+lo)
-       } else if cnt <= int64(8*gc.Widthreg) {
+       } else if !isPlan9 && cnt <= int64(8*gc.Widthreg) {
                if *x0 == 0 {
                        p = appendpp(p, x86.AXORPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_REG, x86.REG_X0, 0)
                        *x0 = 1
@@ -139,12 +139,11 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, ax *uint32, x0 *uin
                if cnt%16 != 0 {
                        p = appendpp(p, x86.AMOVUPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_MEM, x86.REG_SP, frame+lo+cnt-int64(16))
                }
-       } else if !gc.Nacl && (cnt <= int64(128*gc.Widthreg)) {
+       } else if !gc.Nacl && !isPlan9 && (cnt <= int64(128*gc.Widthreg)) {
                if *x0 == 0 {
                        p = appendpp(p, x86.AXORPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_REG, x86.REG_X0, 0)
                        *x0 = 1
                }
-
                p = appendpp(p, leaptr, obj.TYPE_MEM, x86.REG_SP, frame+lo+dzDI(cnt), obj.TYPE_REG, x86.REG_DI, 0)
                p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_ADDR, 0, dzOff(cnt))
                p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg))
@@ -563,7 +562,7 @@ func clearfat(nl *gc.Node) {
 
        w := nl.Type.Width
 
-       if w > 1024 || (gc.Nacl && w >= 64) {
+       if w > 1024 || (w >= 64 && (gc.Nacl || isPlan9)) {
                var oldn1 gc.Node
                var n1 gc.Node
                savex(x86.REG_DI, &n1, &oldn1, nil, gc.Types[gc.Tptr])
@@ -630,6 +629,22 @@ func clearfat(nl *gc.Node) {
 }
 
 func clearfat_tail(n1 *gc.Node, b int64) {
+       if b >= 16 && isPlan9 {
+               var z gc.Node
+               gc.Nodconst(&z, gc.Types[gc.TUINT64], 0)
+               q := b / 8
+               for ; q > 0; q-- {
+                       n1.Type = z.Type
+                       gins(x86.AMOVQ, &z, n1)
+                       n1.Xoffset += 8
+                       b -= 8
+               }
+               if b != 0 {
+                       n1.Xoffset -= 8 - b
+                       gins(x86.AMOVQ, &z, n1)
+               }
+               return
+       }
        if b >= 16 {
                var vec_zero gc.Node
                gc.Regalloc(&vec_zero, gc.Types[gc.TFLOAT64], nil)
index 452f954bd828c881e64adf082527543c89588559..810214504fac1782c96a4e510289707dfc214902 100644 (file)
@@ -427,7 +427,7 @@ func elimshortmov(g *gc.Graph) {
                        }
 
                        if regtyp(&p.From) || p.From.Type == obj.TYPE_CONST {
-                               // move or artihmetic into partial register.
+                               // move or arithmetic into partial register.
                                // from another register or constant can be movl.
                                // we don't switch to 64-bit arithmetic if it can
                                // change how the carry bit is set (and the carry bit is needed).
index 517b4f4c8e9e33659b0cca4385913b51fa7d9b6b..5e282c8cd59bbd88f5b50984a4f5376454530b8e 100644 (file)
@@ -11,8 +11,6 @@ import (
 )
 
 func defframe(ptxt *obj.Prog) {
-       var n *gc.Node
-
        // fill in argument size, stack size
        ptxt.To.Type = obj.TYPE_TEXTSIZE
 
@@ -28,8 +26,7 @@ func defframe(ptxt *obj.Prog) {
        hi := int64(0)
        lo := hi
        r0 := uint32(0)
-       for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next {
-               n = l.N
+       for _, n := range gc.Curfn.Func.Dcl {
                if !n.Name.Needzero {
                        continue
                }
index c495bbc77f9376234386cca59ebbc55df9f82582..a33b2b42bfffa8c15f6b6e69a37746a845ce0c33 100644 (file)
@@ -12,8 +12,6 @@ import (
 )
 
 func defframe(ptxt *obj.Prog) {
-       var n *gc.Node
-
        // fill in argument size, stack size
        ptxt.To.Type = obj.TYPE_TEXTSIZE
 
@@ -37,8 +35,7 @@ func defframe(ptxt *obj.Prog) {
        lo := hi
 
        // iterate through declarations - they are sorted in decreasing xoffset order.
-       for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next {
-               n = l.N
+       for _, n := range gc.Curfn.Func.Dcl {
                if !n.Name.Needzero {
                        continue
                }
@@ -146,7 +143,7 @@ func dodiv(op gc.Op, nl *gc.Node, nr *gc.Node, res *gc.Node) {
        // The hardware will generate undefined result.
        // Also need to explicitly trap on division on zero,
        // the hardware will silently generate undefined result.
-       // DIVW will leave unpredicable result in higher 32-bit,
+       // DIVW will leave unpredictable result in higher 32-bit,
        // so always use DIVD/DIVDU.
        t := nl.Type
 
diff --git a/src/cmd/compile/internal/gc/alg.go b/src/cmd/compile/internal/gc/alg.go
new file mode 100644 (file)
index 0000000..c993737
--- /dev/null
@@ -0,0 +1,626 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import "fmt"
+
+const (
+       // These values are known by runtime.
+       ANOEQ = iota
+       AMEM0
+       AMEM8
+       AMEM16
+       AMEM32
+       AMEM64
+       AMEM128
+       ASTRING
+       AINTER
+       ANILINTER
+       AFLOAT32
+       AFLOAT64
+       ACPLX64
+       ACPLX128
+       AMEM = 100
+)
+
+func algtype(t *Type) int {
+       a := algtype1(t, nil)
+       if a == AMEM {
+               switch t.Width {
+               case 0:
+                       return AMEM0
+               case 1:
+                       return AMEM8
+               case 2:
+                       return AMEM16
+               case 4:
+                       return AMEM32
+               case 8:
+                       return AMEM64
+               case 16:
+                       return AMEM128
+               }
+       }
+
+       return a
+}
+
+func algtype1(t *Type, bad **Type) int {
+       if bad != nil {
+               *bad = nil
+       }
+       if t.Broke {
+               return AMEM
+       }
+       if t.Noalg {
+               return ANOEQ
+       }
+
+       switch t.Etype {
+       // will be defined later.
+       case TANY, TFORW:
+               *bad = t
+
+               return -1
+
+       case TINT8,
+               TUINT8,
+               TINT16,
+               TUINT16,
+               TINT32,
+               TUINT32,
+               TINT64,
+               TUINT64,
+               TINT,
+               TUINT,
+               TUINTPTR,
+               TBOOL,
+               TPTR32,
+               TPTR64,
+               TCHAN,
+               TUNSAFEPTR:
+               return AMEM
+
+       case TFUNC, TMAP:
+               if bad != nil {
+                       *bad = t
+               }
+               return ANOEQ
+
+       case TFLOAT32:
+               return AFLOAT32
+
+       case TFLOAT64:
+               return AFLOAT64
+
+       case TCOMPLEX64:
+               return ACPLX64
+
+       case TCOMPLEX128:
+               return ACPLX128
+
+       case TSTRING:
+               return ASTRING
+
+       case TINTER:
+               if isnilinter(t) {
+                       return ANILINTER
+               }
+               return AINTER
+
+       case TARRAY:
+               if Isslice(t) {
+                       if bad != nil {
+                               *bad = t
+                       }
+                       return ANOEQ
+               }
+
+               a := algtype1(t.Type, bad)
+               if a == ANOEQ || a == AMEM {
+                       if a == ANOEQ && bad != nil {
+                               *bad = t
+                       }
+                       return a
+               }
+
+               switch t.Bound {
+               case 0:
+                       // We checked above that the element type is comparable.
+                       return AMEM
+               case 1:
+                       // Single-element array is same as its lone element.
+                       return a
+               }
+
+               return -1 // needs special compare
+
+       case TSTRUCT:
+               if t.Type != nil && t.Type.Down == nil && !isblanksym(t.Type.Sym) {
+                       // One-field struct is same as that one field alone.
+                       return algtype1(t.Type.Type, bad)
+               }
+
+               ret := AMEM
+               var a int
+               for t1 := t.Type; t1 != nil; t1 = t1.Down {
+                       // All fields must be comparable.
+                       a = algtype1(t1.Type, bad)
+
+                       if a == ANOEQ {
+                               return ANOEQ
+                       }
+
+                       // Blank fields, padded fields, fields with non-memory
+                       // equality need special compare.
+                       if a != AMEM || isblanksym(t1.Sym) || ispaddedfield(t1, t.Width) {
+                               ret = -1
+                               continue
+                       }
+               }
+
+               return ret
+       }
+
+       Fatalf("algtype1: unexpected type %v", t)
+       return 0
+}
+
+// Generate a helper function to compute the hash of a value of type t.
+func genhash(sym *Sym, t *Type) {
+       if Debug['r'] != 0 {
+               fmt.Printf("genhash %v %v\n", sym, t)
+       }
+
+       lineno = 1 // less confusing than end of input
+       dclcontext = PEXTERN
+       markdcl()
+
+       // func sym(p *T, h uintptr) uintptr
+       fn := Nod(ODCLFUNC, nil, nil)
+
+       fn.Func.Nname = newname(sym)
+       fn.Func.Nname.Class = PFUNC
+       tfn := Nod(OTFUNC, nil, nil)
+       fn.Func.Nname.Name.Param.Ntype = tfn
+
+       n := Nod(ODCLFIELD, newname(Lookup("p")), typenod(Ptrto(t)))
+       tfn.List = list(tfn.List, n)
+       np := n.Left
+       n = Nod(ODCLFIELD, newname(Lookup("h")), typenod(Types[TUINTPTR]))
+       tfn.List = list(tfn.List, n)
+       nh := n.Left
+       n = Nod(ODCLFIELD, nil, typenod(Types[TUINTPTR])) // return value
+       tfn.Rlist = list(tfn.Rlist, n)
+
+       funchdr(fn)
+       typecheck(&fn.Func.Nname.Name.Param.Ntype, Etype)
+
+       // genhash is only called for types that have equality but
+       // cannot be handled by the standard algorithms,
+       // so t must be either an array or a struct.
+       switch t.Etype {
+       default:
+               Fatalf("genhash %v", t)
+
+       case TARRAY:
+               if Isslice(t) {
+                       Fatalf("genhash %v", t)
+               }
+
+               // An array of pure memory would be handled by the
+               // standard algorithm, so the element type must not be
+               // pure memory.
+               hashel := hashfor(t.Type)
+
+               n := Nod(ORANGE, nil, Nod(OIND, np, nil))
+               ni := newname(Lookup("i"))
+               ni.Type = Types[TINT]
+               n.List = list1(ni)
+               n.Colas = true
+               colasdefn(n.List, n)
+               ni = n.List.N
+
+               // h = hashel(&p[i], h)
+               call := Nod(OCALL, hashel, nil)
+
+               nx := Nod(OINDEX, np, ni)
+               nx.Bounded = true
+               na := Nod(OADDR, nx, nil)
+               na.Etype = 1 // no escape to heap
+               call.List = list(call.List, na)
+               call.List = list(call.List, nh)
+               n.Nbody = list(n.Nbody, Nod(OAS, nh, call))
+
+               fn.Nbody = list(fn.Nbody, n)
+
+       // Walk the struct using memhash for runs of AMEM
+       // and calling specific hash functions for the others.
+       case TSTRUCT:
+               var call *Node
+               var nx *Node
+               var na *Node
+               var hashel *Node
+
+               t1 := t.Type
+               for {
+                       first, size, next := memrun(t, t1)
+                       t1 = next
+
+                       // Run memhash for fields up to this one.
+                       if first != nil {
+                               hashel = hashmem(first.Type)
+
+                               // h = hashel(&p.first, size, h)
+                               call = Nod(OCALL, hashel, nil)
+
+                               nx = Nod(OXDOT, np, newname(first.Sym)) // TODO: fields from other packages?
+                               na = Nod(OADDR, nx, nil)
+                               na.Etype = 1 // no escape to heap
+                               call.List = list(call.List, na)
+                               call.List = list(call.List, nh)
+                               call.List = list(call.List, Nodintconst(size))
+                               fn.Nbody = list(fn.Nbody, Nod(OAS, nh, call))
+                       }
+
+                       if t1 == nil {
+                               break
+                       }
+                       if isblanksym(t1.Sym) {
+                               t1 = t1.Down
+                               continue
+                       }
+                       if algtype1(t1.Type, nil) == AMEM {
+                               // Our memory run might have been stopped by padding or a blank field.
+                               // If the next field is memory-ish, it could be the start of a new run.
+                               continue
+                       }
+
+                       hashel = hashfor(t1.Type)
+                       call = Nod(OCALL, hashel, nil)
+                       nx = Nod(OXDOT, np, newname(t1.Sym)) // TODO: fields from other packages?
+                       na = Nod(OADDR, nx, nil)
+                       na.Etype = 1 // no escape to heap
+                       call.List = list(call.List, na)
+                       call.List = list(call.List, nh)
+                       fn.Nbody = list(fn.Nbody, Nod(OAS, nh, call))
+
+                       t1 = t1.Down
+               }
+       }
+
+       r := Nod(ORETURN, nil, nil)
+       r.List = list(r.List, nh)
+       fn.Nbody = list(fn.Nbody, r)
+
+       if Debug['r'] != 0 {
+               dumplist("genhash body", fn.Nbody)
+       }
+
+       funcbody(fn)
+       Curfn = fn
+       fn.Func.Dupok = true
+       typecheck(&fn, Etop)
+       typechecklist(fn.Nbody, Etop)
+       Curfn = nil
+
+       // Disable safemode while compiling this code: the code we
+       // generate internally can refer to unsafe.Pointer.
+       // In this case it can happen if we need to generate an ==
+       // for a struct containing a reflect.Value, which itself has
+       // an unexported field of type unsafe.Pointer.
+       old_safemode := safemode
+
+       safemode = 0
+       funccompile(fn)
+       safemode = old_safemode
+}
+
+func hashfor(t *Type) *Node {
+       var sym *Sym
+
+       a := algtype1(t, nil)
+       switch a {
+       case AMEM:
+               Fatalf("hashfor with AMEM type")
+
+       case AINTER:
+               sym = Pkglookup("interhash", Runtimepkg)
+
+       case ANILINTER:
+               sym = Pkglookup("nilinterhash", Runtimepkg)
+
+       case ASTRING:
+               sym = Pkglookup("strhash", Runtimepkg)
+
+       case AFLOAT32:
+               sym = Pkglookup("f32hash", Runtimepkg)
+
+       case AFLOAT64:
+               sym = Pkglookup("f64hash", Runtimepkg)
+
+       case ACPLX64:
+               sym = Pkglookup("c64hash", Runtimepkg)
+
+       case ACPLX128:
+               sym = Pkglookup("c128hash", Runtimepkg)
+
+       default:
+               sym = typesymprefix(".hash", t)
+       }
+
+       n := newname(sym)
+       n.Class = PFUNC
+       tfn := Nod(OTFUNC, nil, nil)
+       tfn.List = list(tfn.List, Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
+       tfn.List = list(tfn.List, Nod(ODCLFIELD, nil, typenod(Types[TUINTPTR])))
+       tfn.Rlist = list(tfn.Rlist, Nod(ODCLFIELD, nil, typenod(Types[TUINTPTR])))
+       typecheck(&tfn, Etype)
+       n.Type = tfn.Type
+       return n
+}
+
+// geneq generates a helper function to
+// check equality of two values of type t.
+func geneq(sym *Sym, t *Type) {
+       if Debug['r'] != 0 {
+               fmt.Printf("geneq %v %v\n", sym, t)
+       }
+
+       lineno = 1 // less confusing than end of input
+       dclcontext = PEXTERN
+       markdcl()
+
+       // func sym(p, q *T) bool
+       fn := Nod(ODCLFUNC, nil, nil)
+
+       fn.Func.Nname = newname(sym)
+       fn.Func.Nname.Class = PFUNC
+       tfn := Nod(OTFUNC, nil, nil)
+       fn.Func.Nname.Name.Param.Ntype = tfn
+
+       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, nil, typenod(Types[TBOOL]))
+       tfn.Rlist = list(tfn.Rlist, n)
+
+       funchdr(fn)
+
+       // geneq is only called for types that have equality but
+       // cannot be handled by the standard algorithms,
+       // so t must be either an array or a struct.
+       switch t.Etype {
+       default:
+               Fatalf("geneq %v", t)
+
+       case TARRAY:
+               if Isslice(t) {
+                       Fatalf("geneq %v", t)
+               }
+
+               // An array of pure memory would be handled by the
+               // standard memequal, so the element type must not be
+               // pure memory.  Even if we unrolled the range loop,
+               // each iteration would be a function call, so don't bother
+               // unrolling.
+               nrange := Nod(ORANGE, nil, Nod(OIND, np, nil))
+
+               ni := newname(Lookup("i"))
+               ni.Type = Types[TINT]
+               nrange.List = list1(ni)
+               nrange.Colas = true
+               colasdefn(nrange.List, nrange)
+               ni = nrange.List.N
+
+               // if p[i] != q[i] { return false }
+               nx := Nod(OINDEX, np, ni)
+
+               nx.Bounded = true
+               ny := Nod(OINDEX, nq, ni)
+               ny.Bounded = true
+
+               nif := Nod(OIF, nil, nil)
+               nif.Left = Nod(ONE, nx, ny)
+               r := Nod(ORETURN, nil, nil)
+               r.List = list(r.List, Nodbool(false))
+               nif.Nbody = list(nif.Nbody, r)
+               nrange.Nbody = list(nrange.Nbody, nif)
+               fn.Nbody = list(fn.Nbody, nrange)
+
+               // return true
+               ret := Nod(ORETURN, nil, nil)
+               ret.List = list(ret.List, Nodbool(true))
+               fn.Nbody = list(fn.Nbody, ret)
+
+       // Walk the struct using memequal for runs of AMEM
+       // and calling specific equality tests for the others.
+       // Skip blank-named fields.
+       case TSTRUCT:
+               var conjuncts []*Node
+
+               t1 := t.Type
+               for {
+                       first, size, next := memrun(t, t1)
+                       t1 = next
+
+                       // Run memequal for fields up to this one.
+                       // TODO(rsc): All the calls to newname are wrong for
+                       // cross-package unexported fields.
+                       if first != nil {
+                               if first.Down == t1 {
+                                       conjuncts = append(conjuncts, eqfield(np, nq, newname(first.Sym)))
+                               } else if first.Down.Down == t1 {
+                                       conjuncts = append(conjuncts, eqfield(np, nq, newname(first.Sym)))
+                                       first = first.Down
+                                       if !isblanksym(first.Sym) {
+                                               conjuncts = append(conjuncts, eqfield(np, nq, newname(first.Sym)))
+                                       }
+                               } else {
+                                       // More than two fields: use memequal.
+                                       conjuncts = append(conjuncts, eqmem(np, nq, newname(first.Sym), size))
+                               }
+                       }
+
+                       if t1 == nil {
+                               break
+                       }
+                       if isblanksym(t1.Sym) {
+                               t1 = t1.Down
+                               continue
+                       }
+                       if algtype1(t1.Type, nil) == AMEM {
+                               // Our memory run might have been stopped by padding or a blank field.
+                               // If the next field is memory-ish, it could be the start of a new run.
+                               continue
+                       }
+
+                       // Check this field, which is not just memory.
+                       conjuncts = append(conjuncts, eqfield(np, nq, newname(t1.Sym)))
+                       t1 = t1.Down
+               }
+
+               var and *Node
+               switch len(conjuncts) {
+               case 0:
+                       and = Nodbool(true)
+               case 1:
+                       and = conjuncts[0]
+               default:
+                       and = Nod(OANDAND, conjuncts[0], conjuncts[1])
+                       for _, conjunct := range conjuncts[2:] {
+                               and = Nod(OANDAND, and, conjunct)
+                       }
+               }
+
+               ret := Nod(ORETURN, nil, nil)
+               ret.List = list(ret.List, and)
+               fn.Nbody = list(fn.Nbody, ret)
+       }
+
+       if Debug['r'] != 0 {
+               dumplist("geneq body", fn.Nbody)
+       }
+
+       funcbody(fn)
+       Curfn = fn
+       fn.Func.Dupok = true
+       typecheck(&fn, Etop)
+       typechecklist(fn.Nbody, Etop)
+       Curfn = nil
+
+       // Disable safemode while compiling this code: the code we
+       // generate internally can refer to unsafe.Pointer.
+       // In this case it can happen if we need to generate an ==
+       // for a struct containing a reflect.Value, which itself has
+       // an unexported field of type unsafe.Pointer.
+       old_safemode := safemode
+       safemode = 0
+
+       // Disable checknils while compiling this code.
+       // We are comparing a struct or an array,
+       // neither of which can be nil, and our comparisons
+       // are shallow.
+       Disable_checknil++
+
+       funccompile(fn)
+
+       safemode = old_safemode
+       Disable_checknil--
+}
+
+// eqfield returns the node
+//     p.field == q.field
+func eqfield(p *Node, q *Node, field *Node) *Node {
+       nx := Nod(OXDOT, p, field)
+       ny := Nod(OXDOT, q, field)
+       ne := Nod(OEQ, nx, ny)
+       return ne
+}
+
+// eqmem returns the node
+//     memequal(&p.field, &q.field [, size])
+func eqmem(p *Node, q *Node, field *Node, size int64) *Node {
+       var needsize int
+
+       nx := Nod(OADDR, Nod(OXDOT, p, field), nil)
+       nx.Etype = 1 // does not escape
+       ny := Nod(OADDR, Nod(OXDOT, q, field), nil)
+       ny.Etype = 1 // does not escape
+       typecheck(&nx, Erv)
+       typecheck(&ny, Erv)
+
+       call := Nod(OCALL, eqmemfunc(size, nx.Type.Type, &needsize), nil)
+       call.List = list(call.List, nx)
+       call.List = list(call.List, ny)
+       if needsize != 0 {
+               call.List = list(call.List, Nodintconst(size))
+       }
+
+       return call
+}
+
+func eqmemfunc(size int64, type_ *Type, needsize *int) *Node {
+       var fn *Node
+
+       switch size {
+       default:
+               fn = syslook("memequal", 1)
+               *needsize = 1
+
+       case 1, 2, 4, 8, 16:
+               buf := fmt.Sprintf("memequal%d", int(size)*8)
+               fn = syslook(buf, 1)
+               *needsize = 0
+       }
+
+       substArgTypes(fn, type_, type_)
+       return fn
+}
+
+// memrun finds runs of struct fields for which memory-only algs are appropriate.
+// t is the parent struct type, and field is the field at which to start.
+// first is the first field in the memory run.
+// size is the length in bytes of the memory included in the run.
+// next is the next field after the memory run.
+func memrun(t *Type, field *Type) (first *Type, size int64, next *Type) {
+       var offend int64
+       for {
+               if field == nil || algtype1(field.Type, nil) != AMEM || isblanksym(field.Sym) {
+                       break
+               }
+               offend = field.Width + field.Type.Width
+               if first == nil {
+                       first = field
+               }
+
+               // If it's a memory field but it's padded, stop here.
+               if ispaddedfield(field, t.Width) {
+                       field = field.Down
+                       break
+               }
+               field = field.Down
+       }
+       if first != nil {
+               size = offend - first.Width // first.Width is offset
+       }
+       return first, size, field
+}
+
+// ispaddedfield reports whether the given field
+// is followed by padding. For the case where t is
+// the last field, total gives the size of the enclosing struct.
+func ispaddedfield(t *Type, total int64) bool {
+       if t.Etype != TFIELD {
+               Fatalf("ispaddedfield called non-field %v", t)
+       }
+       if t.Down == nil {
+               return t.Width+t.Type.Width != total
+       }
+       return t.Width+t.Type.Width != t.Down.Width
+}
index ff0465f64cb49431f5559935ae6adac11a05f1be..dc55bb023ed6a39c9b11f13ba7c9d8331db31ca8 100644 (file)
@@ -72,7 +72,7 @@ amount of space to hold the list without the need to grow it later.
 
 All integer values use a variable-length encoding for compact representation.
 
-If debugFormat is set, each integer and string value is preceeded by a marker
+If debugFormat is set, each integer and string value is preceded by a marker
 and position information in the encoding. This mechanism permits an importer
 to recognize immediately when it is out of sync. The importer recognizes this
 mode automatically (i.e., it can import export data produced with debugging
index 731f31ba52d3e5062056f172b25487c4b84576aa..f330f1b9e67222aa91a5c68de5a07acfb87bbda8 100644 (file)
@@ -240,10 +240,9 @@ func (p *importer) typ() *Type {
                        {
                                saved := structpkg
                                structpkg = tsym.Pkg
-                               addmethod(sym, n.Type, false, nointerface)
+                               addmethod(sym, n.Type, false, false)
                                structpkg = saved
                        }
-                       nointerface = false
                        funchdr(n)
 
                        // (comment from go.y)
index 6456240a12da1556f12a33c42a65856c7269b127..74f61129c260bda4b2d99dac11c1777184696061 100644 (file)
@@ -781,7 +781,7 @@ var sys_wbptr *Node
 
 func cgen_wbptr(n, res *Node) {
        if Curfn != nil {
-               if Curfn.Func.Nowritebarrier {
+               if Curfn.Func.Pragma&Nowritebarrier != 0 {
                        Yyerror("write barrier prohibited")
                }
                if Curfn.Func.WBLineno == 0 {
@@ -831,7 +831,7 @@ func cgen_wbptr(n, res *Node) {
 
 func cgen_wbfat(n, res *Node) {
        if Curfn != nil {
-               if Curfn.Func.Nowritebarrier {
+               if Curfn.Func.Pragma&Nowritebarrier != 0 {
                        Yyerror("write barrier prohibited")
                }
                if Curfn.Func.WBLineno == 0 {
@@ -2263,9 +2263,9 @@ func sgen_wb(n *Node, ns *Node, w int64, wb bool) {
        // If copying .args, that's all the results, so record definition sites
        // for them for the liveness analysis.
        if ns.Op == ONAME && ns.Sym.Name == ".args" {
-               for l := Curfn.Func.Dcl; l != nil; l = l.Next {
-                       if l.N.Class == PPARAMOUT {
-                               Gvardef(l.N)
+               for _, ln := range Curfn.Func.Dcl {
+                       if ln.Class == PPARAMOUT {
+                               Gvardef(ln)
                        }
                }
        }
@@ -2621,7 +2621,7 @@ func cgen_ret(n *Node) {
        if hasdefer {
                Ginscall(Deferreturn, 0)
        }
-       Genlist(Curfn.Func.Exit)
+       Genslice(Curfn.Func.Exit.Slice())
        p := Thearch.Gins(obj.ARET, nil, nil)
        if n != nil && n.Op == ORETJMP {
                p.To.Type = obj.TYPE_MEM
index 6853e625b0afebc27ce32305d34f02a3dbb50002..72aeeee2c4906fd6c66fefa267ded4c2563ca532 100644 (file)
@@ -67,9 +67,7 @@ func closurebody(body *NodeList) *Node {
        // ordinary ones in the symbol table; see oldname.
        // unhook them.
        // make the list of pointers for the closure call.
-       var v *Node
-       for l := func_.Func.Cvars; l != nil; l = l.Next {
-               v = l.N
+       for _, v := range func_.Func.Cvars.Slice() {
                v.Name.Param.Closure.Name.Param.Closure = v.Name.Param.Outer
                v.Name.Param.Outerexpr = oldname(v.Sym)
        }
@@ -78,10 +76,8 @@ func closurebody(body *NodeList) *Node {
 }
 
 func typecheckclosure(func_ *Node, top int) {
-       var n *Node
-
-       for l := func_.Func.Cvars; l != nil; l = l.Next {
-               n = l.N.Name.Param.Closure
+       for _, ln := range func_.Func.Cvars.Slice() {
+               n := ln.Name.Param.Closure
                if !n.Name.Captured {
                        n.Name.Captured = true
                        if n.Name.Decldepth == 0 {
@@ -96,9 +92,9 @@ func typecheckclosure(func_ *Node, top int) {
                }
        }
 
-       for l := func_.Func.Dcl; l != nil; l = l.Next {
-               if l.N.Op == ONAME && (l.N.Class == PPARAM || l.N.Class == PPARAMOUT) {
-                       l.N.Name.Decldepth = 1
+       for _, ln := range func_.Func.Dcl {
+               if ln.Op == ONAME && (ln.Class == PPARAM || ln.Class == PPARAMOUT) {
+                       ln.Name.Decldepth = 1
                }
        }
 
@@ -198,7 +194,8 @@ func makeclosure(func_ *Node) *Node {
        makefuncsym(xfunc.Func.Nname.Sym)
 
        xfunc.Nbody = func_.Nbody
-       xfunc.Func.Dcl = concat(func_.Func.Dcl, xfunc.Func.Dcl)
+       xfunc.Func.Dcl = append(func_.Func.Dcl, xfunc.Func.Dcl...)
+       func_.Func.Dcl = nil
        if xfunc.Nbody == nil {
                Fatalf("empty body - won't generate any code")
        }
@@ -220,16 +217,14 @@ func makeclosure(func_ *Node) *Node {
 // We use value capturing for values <= 128 bytes that are never reassigned
 // after capturing (effectively constant).
 func capturevars(xfunc *Node) {
-       var v *Node
        var outer *Node
 
        lno := int(lineno)
        lineno = xfunc.Lineno
 
        func_ := xfunc.Func.Closure
-       func_.Func.Enter = nil
-       for l := func_.Func.Cvars; l != nil; l = l.Next {
-               v = l.N
+       func_.Func.Enter.Set(nil)
+       for _, v := range func_.Func.Cvars.Slice() {
                if v.Type == nil {
                        // if v->type is nil, it means v looked like it was
                        // going to be used in the closure but wasn't.
@@ -270,7 +265,7 @@ func capturevars(xfunc *Node) {
                }
 
                typecheck(&outer, Erv)
-               func_.Func.Enter = list(func_.Func.Enter, outer)
+               func_.Func.Enter.Append(outer)
        }
 
        lineno = int32(lno)
@@ -309,11 +304,9 @@ func transformclosure(xfunc *Node) {
                original_dcl := xfunc.Func.Dcl
                xfunc.Func.Dcl = nil
 
-               var v *Node
                var addr *Node
                var fld *Type
-               for l := func_.Func.Cvars; l != nil; l = l.Next {
-                       v = l.N
+               for _, v := range func_.Func.Cvars.Slice() {
                        if v.Op == OXXX {
                                continue
                        }
@@ -341,13 +334,13 @@ func transformclosure(xfunc *Node) {
                        fld.Sym = fld.Nname.Sym
 
                        // Declare the new param and add it the first part of the input arguments.
-                       xfunc.Func.Dcl = list(xfunc.Func.Dcl, fld.Nname)
+                       xfunc.Func.Dcl = append(xfunc.Func.Dcl, fld.Nname)
 
                        *param = fld
                        param = &fld.Down
                }
                *param = original_args
-               xfunc.Func.Dcl = concat(xfunc.Func.Dcl, original_dcl)
+               xfunc.Func.Dcl = append(xfunc.Func.Dcl, original_dcl...)
 
                // Recalculate param offsets.
                if f.Type.Width > 0 {
@@ -357,19 +350,14 @@ func transformclosure(xfunc *Node) {
                xfunc.Type = f.Type // update type of ODCLFUNC
        } else {
                // The closure is not called, so it is going to stay as closure.
-               nvar := 0
-
-               var body *NodeList
+               var body []*Node
                offset := int64(Widthptr)
                var addr *Node
-               var v *Node
                var cv *Node
-               for l := func_.Func.Cvars; l != nil; l = l.Next {
-                       v = l.N
+               for _, v := range func_.Func.Cvars.Slice() {
                        if v.Op == OXXX {
                                continue
                        }
-                       nvar++
 
                        // cv refers to the field inside of closure OSTRUCTLIT.
                        cv = Nod(OCLOSUREVAR, nil, nil)
@@ -386,8 +374,8 @@ func transformclosure(xfunc *Node) {
                                // If it is a small variable captured by value, downgrade it to PAUTO.
                                v.Class = PAUTO
                                v.Ullman = 1
-                               xfunc.Func.Dcl = list(xfunc.Func.Dcl, v)
-                               body = list(body, Nod(OAS, v, cv))
+                               xfunc.Func.Dcl = append(xfunc.Func.Dcl, v)
+                               body = append(body, Nod(OAS, v, cv))
                        } else {
                                // Declare variable holding addresses taken from closure
                                // and initialize in entry prologue.
@@ -396,19 +384,21 @@ func transformclosure(xfunc *Node) {
                                addr.Class = PAUTO
                                addr.Used = true
                                addr.Name.Curfn = xfunc
-                               xfunc.Func.Dcl = list(xfunc.Func.Dcl, addr)
+                               xfunc.Func.Dcl = append(xfunc.Func.Dcl, addr)
                                v.Name.Heapaddr = addr
                                if v.Name.Byval {
                                        cv = Nod(OADDR, cv, nil)
                                }
-                               body = list(body, Nod(OAS, addr, cv))
+                               body = append(body, Nod(OAS, addr, cv))
                        }
                }
 
-               typechecklist(body, Etop)
-               walkstmtlist(body)
-               xfunc.Func.Enter = body
-               xfunc.Func.Needctxt = nvar > 0
+               if len(body) > 0 {
+                       typecheckslice(body, Etop)
+                       walkstmtslice(body)
+                       xfunc.Func.Enter.Set(body)
+                       xfunc.Func.Needctxt = true
+               }
        }
 
        lineno = int32(lno)
@@ -416,7 +406,7 @@ func transformclosure(xfunc *Node) {
 
 func walkclosure(func_ *Node, init **NodeList) *Node {
        // If no closure vars, don't bother wrapping.
-       if func_.Func.Cvars == nil {
+       if len(func_.Func.Cvars.Slice()) == 0 {
                return func_.Func.Closure.Func.Nname
        }
 
@@ -438,9 +428,7 @@ func walkclosure(func_ *Node, init **NodeList) *Node {
 
        typ.List = list1(Nod(ODCLFIELD, newname(Lookup(".F")), typenod(Types[TUINTPTR])))
        var typ1 *Node
-       var v *Node
-       for l := func_.Func.Cvars; l != nil; l = l.Next {
-               v = l.N
+       for _, v := range func_.Func.Cvars.Slice() {
                if v.Op == OXXX {
                        continue
                }
@@ -454,7 +442,7 @@ func walkclosure(func_ *Node, init **NodeList) *Node {
        clos := Nod(OCOMPLIT, nil, Nod(OIND, typ, nil))
        clos.Esc = func_.Esc
        clos.Right.Implicit = true
-       clos.List = concat(list1(Nod(OCFUNC, func_.Func.Closure.Func.Nname, nil)), func_.Func.Enter)
+       clos.List = concat(list1(Nod(OCFUNC, func_.Func.Closure.Func.Nname, nil)), func_.Func.Enter.NodeList())
 
        // Force type conversion from *struct to the func type.
        clos = Nod(OCONVNOP, clos, nil)
@@ -551,7 +539,7 @@ func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node {
                n = newname(Lookupf("a%d", i))
                i++
                n.Class = PPARAM
-               xfunc.Func.Dcl = list(xfunc.Func.Dcl, n)
+               xfunc.Func.Dcl = append(xfunc.Func.Dcl, n)
                callargs = list(callargs, n)
                fld = Nod(ODCLFIELD, n, typenod(t.Type))
                if t.Isddd {
@@ -570,7 +558,7 @@ func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node {
                n = newname(Lookupf("r%d", i))
                i++
                n.Class = PPARAMOUT
-               xfunc.Func.Dcl = list(xfunc.Func.Dcl, n)
+               xfunc.Func.Dcl = append(xfunc.Func.Dcl, n)
                retargs = list(retargs, n)
                l = list(l, Nod(ODCLFIELD, n, typenod(t.Type)))
        }
@@ -601,7 +589,7 @@ func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node {
        ptr.Used = true
        ptr.Name.Curfn = xfunc
        ptr.Xoffset = 0
-       xfunc.Func.Dcl = list(xfunc.Func.Dcl, ptr)
+       xfunc.Func.Dcl = append(xfunc.Func.Dcl, ptr)
        var body *NodeList
        if Isptr[rcvrtype.Etype] || Isinter(rcvrtype) {
                ptr.Name.Param.Ntype = typenod(rcvrtype)
index fc47a39ee62ee08919417c6079dd236beef5dbde..33c04c501d81b47b4af7964738a4530bb2ce01ba 100644 (file)
@@ -187,7 +187,7 @@ func declare(n *Node, ctxt Class) {
                        Fatalf("automatic outside function")
                }
                if Curfn != nil {
-                       Curfn.Func.Dcl = list(Curfn.Func.Dcl, n)
+                       Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
                }
                if n.Op == OTYPE {
                        declare_typegen++
@@ -426,7 +426,7 @@ func oldname(s *Sym) *Node {
                        n.Name.Param.Closure = c
                        c.Name.Param.Closure = n
                        c.Xoffset = 0
-                       Curfn.Func.Cvars = list(Curfn.Func.Cvars, c)
+                       Curfn.Func.Cvars.Append(c)
                }
 
                // return ref to closure var, not original
@@ -1449,8 +1449,13 @@ func funccompile(n *Node) {
        Funcdepth = n.Func.Depth + 1
        compile(n)
        Curfn = nil
+       Pc = nil
+       continpc = nil
+       breakpc = nil
        Funcdepth = 0
        dclcontext = PEXTERN
+       flushdata()
+       obj.Flushplist(Ctxt) // convert from Prog list to machine code
 }
 
 func funcsym(s *Sym) *Sym {
@@ -1525,7 +1530,7 @@ func checknowritebarrierrec() {
 
                // Check nowritebarrierrec functions.
                for _, n := range list {
-                       if !n.Func.Nowritebarrierrec {
+                       if n.Func.Pragma&Nowritebarrierrec == 0 {
                                continue
                        }
                        call, hasWB := c.best[n]
index 1a5a433eebdd923f46f25b9b0d9f0b543e7abbbf..57459947853e7dbe9b0639f07122bfc13f10039a 100644 (file)
@@ -476,35 +476,35 @@ func escfunc(e *EscState, func_ *Node) {
        savefn := Curfn
        Curfn = func_
 
-       for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
-               if ll.N.Op != ONAME {
+       for _, ln := range Curfn.Func.Dcl {
+               if ln.Op != ONAME {
                        continue
                }
-               llNE := e.nodeEscState(ll.N)
-               switch ll.N.Class {
+               llNE := e.nodeEscState(ln)
+               switch ln.Class {
                // out params are in a loopdepth between the sink and all local variables
                case PPARAMOUT:
                        llNE.Escloopdepth = 0
 
                case PPARAM:
                        llNE.Escloopdepth = 1
-                       if ll.N.Type != nil && !haspointers(ll.N.Type) {
+                       if ln.Type != nil && !haspointers(ln.Type) {
                                break
                        }
                        if Curfn.Nbody == nil && !Curfn.Noescape {
-                               ll.N.Esc = EscHeap
+                               ln.Esc = EscHeap
                        } else {
-                               ll.N.Esc = EscNone // prime for escflood later
+                               ln.Esc = EscNone // prime for escflood later
                        }
-                       e.noesc = list(e.noesc, ll.N)
+                       e.noesc = list(e.noesc, ln)
                }
        }
 
        // in a mutually recursive group we lose track of the return values
        if e.recursive {
-               for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
-                       if ll.N.Op == ONAME && ll.N.Class == PPARAMOUT {
-                               escflows(e, &e.theSink, ll.N)
+               for _, ln := range Curfn.Func.Dcl {
+                       if ln.Op == ONAME && ln.Class == PPARAMOUT {
+                               escflows(e, &e.theSink, ln)
                        }
                }
        }
@@ -779,11 +779,14 @@ func esc(e *EscState, n *Node, up *Node) {
                        ll = e.nodeEscState(n.List.N).Escretval
                }
 
-               for lr := Curfn.Func.Dcl; lr != nil && ll != nil; lr = lr.Next {
-                       if lr.N.Op != ONAME || lr.N.Class != PPARAMOUT {
+               for _, lrn := range Curfn.Func.Dcl {
+                       if ll == nil {
+                               break
+                       }
+                       if lrn.Op != ONAME || lrn.Class != PPARAMOUT {
                                continue
                        }
-                       escassign(e, lr.N, ll.N)
+                       escassign(e, lrn, ll.N)
                        ll = ll.Next
                }
 
@@ -861,9 +864,7 @@ func esc(e *EscState, n *Node, up *Node) {
                // Link addresses of captured variables to closure.
        case OCLOSURE:
                var a *Node
-               var v *Node
-               for ll := n.Func.Cvars; ll != nil; ll = ll.Next {
-                       v = ll.N
+               for _, v := range n.Func.Cvars.Slice() {
                        if v.Op == OXXX { // unnamed out argument; see dcl.go:/^funcargs
                                continue
                        }
@@ -1870,16 +1871,16 @@ func esctag(e *EscState, func_ *Node) {
        savefn := Curfn
        Curfn = func_
 
-       for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
-               if ll.N.Op != ONAME {
+       for _, ln := range Curfn.Func.Dcl {
+               if ln.Op != ONAME {
                        continue
                }
 
-               switch ll.N.Esc & EscMask {
+               switch ln.Esc & EscMask {
                case EscNone, // not touched by escflood
                        EscReturn:
-                       if haspointers(ll.N.Type) { // don't bother tagging for scalars
-                               ll.N.Name.Param.Field.Note = mktag(int(ll.N.Esc))
+                       if haspointers(ln.Type) { // don't bother tagging for scalars
+                               ln.Name.Param.Field.Note = mktag(int(ln.Esc))
                        }
 
                case EscHeap, // touched by escflood, moved to heap
index 69022814ef6ebec25e4ced4d9ce9360474dc822c..a7982706c78e7959f5ff6c93504bbe84c83362c2 100644 (file)
@@ -1730,10 +1730,42 @@ func Hconv(l *NodeList, flag int) string {
        return buf.String()
 }
 
+func Hconvslice(l []*Node, flag int) string {
+       if len(l) == 0 && fmtmode == FDbg {
+               return "<nil>"
+       }
+
+       sf := flag
+       sm, sb := setfmode(&flag)
+       sep := "; "
+       if fmtmode == FDbg {
+               sep = "\n"
+       } else if flag&obj.FmtComma != 0 {
+               sep = ", "
+       }
+
+       var buf bytes.Buffer
+       for i, n := range l {
+               buf.WriteString(Nconv(n, 0))
+               if i+1 < len(l) {
+                       buf.WriteString(sep)
+               }
+       }
+
+       flag = sf
+       fmtbody = sb
+       fmtmode = sm
+       return buf.String()
+}
+
 func dumplist(s string, l *NodeList) {
        fmt.Printf("%s%v\n", s, Hconv(l, obj.FmtSign))
 }
 
+func dumpslice(s string, l []*Node) {
+       fmt.Printf("%s%v\n", s, Hconvslice(l, obj.FmtSign))
+}
+
 func Dump(s string, n *Node) {
        fmt.Printf("%s [%p]%v\n", s, n, Nconv(n, obj.FmtSign))
 }
index 721ef31247931150d10b98304cb3b2400f9dd749..ddd864f6098c2f86a005c870f9413fbf310c9c1f 100644 (file)
@@ -76,6 +76,9 @@ func addrescapes(n *Node) {
                        oldfn := Curfn
 
                        Curfn = n.Name.Curfn
+                       if Curfn.Func.Closure != nil && Curfn.Op == OCLOSURE {
+                               Curfn = Curfn.Func.Closure
+                       }
                        n.Name.Heapaddr = temp(Ptrto(n.Type))
                        buf := fmt.Sprintf("&%v", n.Sym)
                        n.Name.Heapaddr.Sym = Lookup(buf)
@@ -218,6 +221,12 @@ func Genlist(l *NodeList) {
        }
 }
 
+func Genslice(l []*Node) {
+       for _, n := range l {
+               gen(n)
+       }
+}
+
 // generate code to start new proc running call n.
 func cgen_proc(n *Node, proc int) {
        switch n.Left.Op {
@@ -587,6 +596,10 @@ func Tempname(nn *Node, t *Type) {
        if Curfn == nil {
                Fatalf("no curfn for tempname")
        }
+       if Curfn.Func.Closure != nil && Curfn.Op == OCLOSURE {
+               Dump("Tempname", Curfn)
+               Fatalf("adding tempname to wrong closure function")
+       }
 
        if t == nil {
                Yyerror("tempname called with nil type")
@@ -606,7 +619,7 @@ func Tempname(nn *Node, t *Type) {
        n.Ullman = 1
        n.Esc = EscNever
        n.Name.Curfn = Curfn
-       Curfn.Func.Dcl = list(Curfn.Func.Dcl, n)
+       Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
 
        dowidth(t)
        n.Xoffset = 0
index 6c388aff7c93d4f9db37a4dcb53951838de23f5f..bd1391d9ad150e88276ed1ba38b92ac3b191d375 100644 (file)
@@ -11,7 +11,8 @@ import (
        "log"
        "os"
        "os/exec"
-       "path"
+       "path/filepath"
+       "strings"
        "testing"
 )
 
@@ -28,7 +29,7 @@ func TestScanfRemoval(t *testing.T) {
        defer os.RemoveAll(dir)
 
        // Create source.
-       src := path.Join(dir, "test.go")
+       src := filepath.Join(dir, "test.go")
        f, err := os.Create(src)
        if err != nil {
                log.Fatalf("could not create source file: %v", err)
@@ -43,7 +44,7 @@ func main() {
        f.Close()
 
        // Name of destination.
-       dst := path.Join(dir, "test")
+       dst := filepath.Join(dir, "test")
 
        // Compile source.
        cmd := exec.Command("go", "build", "-o", dst, src)
@@ -62,3 +63,53 @@ func main() {
                log.Fatalf("scanf code not removed from helloworld")
        }
 }
+
+// Make sure -S prints assembly code.  See issue 14515.
+func TestDashS(t *testing.T) {
+       testenv.MustHaveGoBuild(t)
+
+       // Make a directory to work in.
+       dir, err := ioutil.TempDir("", "issue14515-")
+       if err != nil {
+               log.Fatalf("could not create directory: %v", err)
+       }
+       defer os.RemoveAll(dir)
+
+       // Create source.
+       src := filepath.Join(dir, "test.go")
+       f, err := os.Create(src)
+       if err != nil {
+               log.Fatalf("could not create source file: %v", err)
+       }
+       f.Write([]byte(`
+package main
+import "fmt"
+func main() {
+       fmt.Println("hello world")
+}
+`))
+       f.Close()
+
+       // Compile source.
+       cmd := exec.Command("go", "build", "-gcflags", "-S", "-o", filepath.Join(dir, "test"), src)
+       out, err := cmd.CombinedOutput()
+       if err != nil {
+               log.Fatalf("could not build target: %v", err)
+       }
+
+       patterns := []string{
+               // It is hard to look for actual instructions in an
+               // arch-independent way.  So we'll just look for
+               // pseudo-ops that are arch-independent.
+               "\tTEXT\t",
+               "\tFUNCDATA\t",
+               "\tPCDATA\t",
+       }
+       outstr := string(out)
+       for _, p := range patterns {
+               if !strings.Contains(outstr, p) {
+                       println(outstr)
+                       panic("can't find pattern " + p)
+               }
+       }
+}
index f721fabfd79e184405886f53f42e5dfafeba68ad..fc63a514d04aaa5470b61707ad85f8e2da6fe2c3 100644 (file)
@@ -26,25 +26,6 @@ const (
        MaxStackVarSize = 10 * 1024 * 1024
 )
 
-const (
-       // These values are known by runtime.
-       ANOEQ = iota
-       AMEM0
-       AMEM8
-       AMEM16
-       AMEM32
-       AMEM64
-       AMEM128
-       ASTRING
-       AINTER
-       ANILINTER
-       AFLOAT32
-       AFLOAT64
-       ACPLX64
-       ACPLX128
-       AMEM = 100
-)
-
 const (
        // Maximum size in bits for Mpints before signalling
        // overflow and also mantissa precision for Mpflts.
@@ -122,10 +103,9 @@ type Pkg struct {
 }
 
 type Sym struct {
-       Lexical   uint16
        Flags     uint8
-       Link      *Sym
        Uniqgen   uint32
+       Link      *Sym
        Importdef *Pkg   // where imported definition was found
        Linkname  string // link name
 
@@ -425,12 +405,13 @@ var sizeof_String int // runtime sizeof(String)
 
 var dotlist [10]Dlist // size is max depth of embeddeds
 
+// lexlineno is the line number _after_ the most recently read rune.
+// In particular, it's advanced (or rewound) as newlines are read (or unread).
 var lexlineno int32
 
+// lineno is the line number at the start of the most recently lexed token.
 var lineno int32
 
-var prevlineno int32
-
 var pragcgobuf string
 
 var infile string
@@ -616,23 +597,10 @@ var flag_largemodel int
 // when the race detector is enabled.
 var instrumenting bool
 
-// Pending annotations for next func declaration.
-var (
-       noescape          bool
-       noinline          bool
-       norace            bool
-       nosplit           bool
-       nowritebarrier    bool
-       nowritebarrierrec bool
-       systemstack       bool
-)
-
 var debuglive int
 
 var Ctxt *obj.Link
 
-var nointerface bool
-
 var writearchive int
 
 var bstdout obj.Biobuf
index be0a0fb56dbd54c494c5cd5b88b43077c3e5efac..73f71dd0fbe7ae13297e24e1fc699e5b1f778000 100644 (file)
@@ -173,6 +173,18 @@ func dumpdata() {
        Clearp(Pc)
 }
 
+func flushdata() {
+       if dfirst == nil {
+               return
+       }
+       newplist()
+       *Pc = *dfirst
+       Pc = dpc
+       Clearp(Pc)
+       dfirst = nil
+       dpc = nil
+}
+
 // Fixup instructions after allocauto (formerly compactframe) has moved all autos around.
 func fixautoused(p *obj.Prog) {
        for lp := &p; ; {
@@ -554,9 +566,7 @@ func nodarg(t *Type, fp int) *Node {
        }
 
        if fp == 1 || fp == -1 {
-               var n *Node
-               for l := Curfn.Func.Dcl; l != nil; l = l.Next {
-                       n = l.N
+               for _, n := range Curfn.Func.Dcl {
                        if (n.Class == PPARAM || n.Class == PPARAMOUT) && !isblanksym(t.Sym) && n.Sym == t.Sym {
                                return n
                        }
index a445f712e278af3868f90f740231a2f34f298759..f5c3265a82f008b7a5095cd9f3bfaafe98d19518 100644 (file)
@@ -107,7 +107,7 @@ func caninl(fn *Node) {
        }
 
        // If marked "go:noinline", don't inline
-       if fn.Func.Noinline {
+       if fn.Func.Pragma&Noinline != 0 {
                return
        }
 
@@ -150,7 +150,10 @@ func caninl(fn *Node) {
 
        fn.Func.Nname.Func.Inl = fn.Nbody
        fn.Nbody = inlcopylist(fn.Func.Nname.Func.Inl)
-       fn.Func.Nname.Func.Inldcl = inlcopylist(fn.Func.Nname.Name.Defn.Func.Dcl)
+       inldcl := inlcopyslice(fn.Func.Nname.Name.Defn.Func.Dcl)
+       if len(inldcl) > 0 {
+               fn.Func.Nname.Func.Inldcl = &inldcl
+       }
        fn.Func.Nname.Func.InlCost = int32(maxBudget - budget)
 
        // hack, TODO, check for better way to link method nodes back to the thing with the ->inl
@@ -275,6 +278,18 @@ func inlcopy(n *Node) *Node {
        return m
 }
 
+// Inlcopyslice is like inlcopylist, but for a slice.
+func inlcopyslice(ll []*Node) []*Node {
+       r := make([]*Node, 0, len(ll))
+       for _, ln := range ll {
+               c := inlcopy(ln)
+               if c != nil {
+                       r = append(r, c)
+               }
+       }
+       return r
+}
+
 // Inlcalls/nodelist/node walks fn's statements and expressions and substitutes any
 // calls made to inlineable functions.  This is the external entry point.
 func inlcalls(fn *Node) {
@@ -556,10 +571,14 @@ func mkinlcall1(np **Node, fn *Node, isddd bool) {
 
        //dumplist("ninit pre", ninit);
 
-       var dcl *NodeList
-       if fn.Name.Defn != nil { // local function
-               dcl = fn.Func.Inldcl // imported function
+       var dcl []*Node
+       if fn.Name.Defn != nil {
+               // local function
+               if fn.Func.Inldcl != nil {
+                       dcl = *fn.Func.Inldcl
+               }
        } else {
+               // imported function
                dcl = fn.Func.Dcl
        }
 
@@ -567,18 +586,18 @@ func mkinlcall1(np **Node, fn *Node, isddd bool) {
        i := 0
 
        // Make temp names to use instead of the originals
-       for ll := dcl; ll != nil; ll = ll.Next {
-               if ll.N.Class == PPARAMOUT { // return values handled below.
+       for _, ln := range dcl {
+               if ln.Class == PPARAMOUT { // return values handled below.
                        continue
                }
-               if ll.N.Op == ONAME {
-                       ll.N.Name.Inlvar = inlvar(ll.N)
+               if ln.Op == ONAME {
+                       ln.Name.Inlvar = inlvar(ln)
 
                        // Typecheck because inlvar is not necessarily a function parameter.
-                       typecheck(&ll.N.Name.Inlvar, Erv)
+                       typecheck(&ln.Name.Inlvar, Erv)
 
-                       if ll.N.Class&^PHEAP != PAUTO {
-                               ninit = list(ninit, Nod(ODCL, ll.N.Name.Inlvar, nil)) // otherwise gen won't emit the allocations for heapallocs
+                       if ln.Class&^PHEAP != PAUTO {
+                               ninit = list(ninit, Nod(ODCL, ln.Name.Inlvar, nil)) // otherwise gen won't emit the allocations for heapallocs
                        }
                }
        }
@@ -852,7 +871,7 @@ func inlvar(var_ *Node) *Node {
                addrescapes(n)
        }
 
-       Curfn.Func.Dcl = list(Curfn.Func.Dcl, n)
+       Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
        return n
 }
 
@@ -863,7 +882,7 @@ func retvar(t *Type, i int) *Node {
        n.Class = PAUTO
        n.Used = true
        n.Name.Curfn = Curfn // the calling function, not the called one
-       Curfn.Func.Dcl = list(Curfn.Func.Dcl, n)
+       Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
        return n
 }
 
@@ -875,7 +894,7 @@ func argvar(t *Type, i int) *Node {
        n.Class = PAUTO
        n.Used = true
        n.Name.Curfn = Curfn // the calling function, not the called one
-       Curfn.Func.Dcl = list(Curfn.Func.Dcl, n)
+       Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
        return n
 }
 
index 46122d264d2a4c352ad677174c8200fb089c5ed5..49e5d6561accc2fd4833f0fab0c28f49bdf85566 100644 (file)
@@ -7,7 +7,6 @@
 package gc
 
 import (
-       "bytes"
        "cmd/compile/internal/ssa"
        "cmd/internal/obj"
        "flag"
@@ -38,6 +37,8 @@ var (
        Debug_wb     int
 )
 
+const BOM = 0xFEFF
+
 // Debug arguments.
 // These can be specified with the -d flag, as in "-d nil"
 // to set the debug_checknil variable. In general the list passed
@@ -237,6 +238,7 @@ func Main() {
        }
        Ctxt.Flag_shared = int32(flag_shared)
        Ctxt.Flag_dynlink = flag_dynlink
+       Ctxt.Flag_optimize = Debug['N'] == 0
 
        Ctxt.Debugasm = int32(Debug['S'])
        Ctxt.Debugvlog = int32(Debug['v'])
@@ -327,7 +329,6 @@ func Main() {
        dclcontext = PEXTERN
        nerrors = 0
        lexlineno = 1
-       const BOM = 0xFEFF
 
        loadsys()
 
@@ -566,22 +567,9 @@ func skiptopkgdef(b *obj.Biobuf) bool {
                return false
        }
 
-       // symbol table may be first; skip it
-       sz := arsize(b, "__.GOSYMDEF")
-
-       if sz >= 0 {
-               obj.Bseek(b, int64(sz), 1)
-       } else {
-               obj.Bseek(b, 8, 0)
-       }
-
-       // package export block is next
-       sz = arsize(b, "__.PKGDEF")
-
-       if sz <= 0 {
-               return false
-       }
-       return true
+       // package export block should be first
+       sz := arsize(b, "__.PKGDEF")
+       return sz > 0
 }
 
 var idirs []string
@@ -592,10 +580,14 @@ func addidir(dir string) {
        }
 }
 
+func isDriveLetter(b byte) bool {
+       return 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z'
+}
+
 // is this path a local name?  begins with ./ or ../ or /
 func islocalname(name string) bool {
        return strings.HasPrefix(name, "/") ||
-               Ctxt.Windows != 0 && len(name) >= 3 && isAlpha(int(name[0])) && name[1] == ':' && name[2] == '/' ||
+               Ctxt.Windows != 0 && len(name) >= 3 && isDriveLetter(name[0]) && name[1] == ':' && name[2] == '/' ||
                strings.HasPrefix(name, "./") || name == "." ||
                strings.HasPrefix(name, "../") || name == ".."
 }
@@ -846,20 +838,17 @@ func importfile(f *Val, indent []byte) {
        }
 }
 
-func isSpace(c int) bool {
+func isSpace(c rune) bool {
        return c == ' ' || c == '\t' || c == '\n' || c == '\r'
 }
 
-func isAlpha(c int) bool {
-       return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z'
+func isLetter(c rune) bool {
+       return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_'
 }
 
-func isDigit(c int) bool {
+func isDigit(c rune) bool {
        return '0' <= c && c <= '9'
 }
-func isAlnum(c int) bool {
-       return isAlpha(c) || isDigit(c)
-}
 
 func plan9quote(s string) string {
        if s == "" {
@@ -873,35 +862,55 @@ func plan9quote(s string) string {
        return s
 }
 
-func isfrog(c int) bool {
-       // complain about possibly invisible control characters
-       if c < ' ' {
-               return !isSpace(c) // exclude good white space
-       }
+type Pragma uint8
 
-       if 0x7f <= c && c <= 0xa0 { // DEL, unicode block including unbreakable space.
-               return true
-       }
-       return false
-}
+const (
+       Nointerface       Pragma = 1 << iota
+       Noescape                 // func parameters don't escape
+       Norace                   // func must not have race detector annotations
+       Nosplit                  // func should not execute on separate stack
+       Noinline                 // func should not be inlined
+       Systemstack              // func must run on system stack
+       Nowritebarrier           // emit compiler error instead of write barrier
+       Nowritebarrierrec        // error on write barrier in this or recursive callees
+)
 
 type lexer struct {
        // source
        bin    *obj.Biobuf
-       peekc  int
-       peekc1 int // second peekc for ...
+       peekr1 rune
+       peekr2 rune // second peekc for ...
 
        nlsemi bool // if set, '\n' and EOF translate to ';'
 
+       // pragma flags
+       // accumulated by lexer; reset by parser
+       pragma Pragma
+
        // current token
        tok  int32
-       sym_ *Sym // valid if tok == LNAME
-       val  Val  // valid if tok == LLITERAL
-       op   Op   // valid if tok == LASOP
+       sym_ *Sym   // valid if tok == LNAME
+       val  Val    // valid if tok == LLITERAL
+       op   Op     // valid if tok == LASOP or LINCOP, or prec > 0
+       prec OpPrec // operator precedence; 0 if not a binary operator
 }
 
+type OpPrec int
+
+const (
+       // Precedences of binary operators (must be > 0).
+       PCOMM OpPrec = 1 + iota
+       POROR
+       PANDAND
+       PCMP
+       PADD
+       PMUL
+)
+
 const (
-       LLITERAL = 57346 + iota
+       // The value of single-char tokens is just their character's Unicode value.
+       // They are all below utf8.RuneSelf. Shift other tokens up to avoid conflicts.
+       LLITERAL = utf8.RuneSelf + iota
        LASOP
        LCOLAS
        LBREAK
@@ -934,12 +943,11 @@ const (
        LANDAND
        LANDNOT
        LCOMM
-       LDEC
        LEQ
        LGE
        LGT
        LIGNORE
-       LINC
+       LINCOP
        LLE
        LLSH
        LLT
@@ -949,133 +957,48 @@ const (
 )
 
 func (l *lexer) next() {
-       var c1 int
-       var op Op
-       var escflag int
-       var v int64
-       var cp *bytes.Buffer
-       var s *Sym
-       var str string
-
-       prevlineno = lineno
-
        nlsemi := l.nlsemi
        l.nlsemi = false
+       l.prec = 0
 
 l0:
        // skip white space
-       c := l.getc()
+       c := l.getr()
        for isSpace(c) {
                if c == '\n' && nlsemi {
-                       l.ungetc(c)
                        if Debug['x'] != 0 {
                                fmt.Printf("lex: implicit semi\n")
                        }
+                       // Insert implicit semicolon on previous line,
+                       // before the newline character.
+                       lineno = lexlineno - 1
                        l.tok = ';'
                        return
                }
-               c = l.getc()
+               c = l.getr()
        }
 
        // start of token
        lineno = lexlineno
 
-       if c >= utf8.RuneSelf {
-               // all multibyte runes are alpha
-               cp = &lexbuf
-               cp.Reset()
-               goto talph
-       }
-
-       if isAlpha(c) {
-               cp = &lexbuf
-               cp.Reset()
-               goto talph
-       }
-
-       if isDigit(c) {
-               cp = &lexbuf
-               cp.Reset()
-               if c != '0' {
-                       for {
-                               cp.WriteByte(byte(c))
-                               c = l.getc()
-                               if isDigit(c) {
-                                       continue
-                               }
-                               if c == '.' {
-                                       goto casedot
-                               }
-                               if c == 'e' || c == 'E' || c == 'p' || c == 'P' {
-                                       goto caseep
-                               }
-                               if c == 'i' {
-                                       goto casei
-                               }
-                               goto ncu
-                       }
-               }
-
-               cp.WriteByte(byte(c))
-               c = l.getc()
-               if c == 'x' || c == 'X' {
-                       for {
-                               cp.WriteByte(byte(c))
-                               c = l.getc()
-                               if isDigit(c) {
-                                       continue
-                               }
-                               if c >= 'a' && c <= 'f' {
-                                       continue
-                               }
-                               if c >= 'A' && c <= 'F' {
-                                       continue
-                               }
-                               if lexbuf.Len() == 2 {
-                                       Yyerror("malformed hex constant")
-                               }
-                               if c == 'p' {
-                                       goto caseep
-                               }
-                               goto ncu
-                       }
+       // identifiers and keywords
+       // (for better error messages consume all chars >= utf8.RuneSelf for identifiers)
+       if isLetter(c) || c >= utf8.RuneSelf {
+               l.ident(c)
+               if l.tok == LIGNORE {
+                       goto l0
                }
-
-               if c == 'p' { // 0p begins floating point zero
-                       goto caseep
-               }
-
-               c1 = 0
-               for {
-                       if !isDigit(c) {
-                               break
-                       }
-                       if c < '0' || c > '7' {
-                               c1 = 1 // not octal
-                       }
-                       cp.WriteByte(byte(c))
-                       c = l.getc()
-               }
-
-               if c == '.' {
-                       goto casedot
-               }
-               if c == 'e' || c == 'E' {
-                       goto caseep
-               }
-               if c == 'i' {
-                       goto casei
-               }
-               if c1 != 0 {
-                       Yyerror("malformed octal constant")
-               }
-               goto ncu
+               return
        }
+       // c < utf8.RuneSelf
+
+       var c1 rune
+       var op Op
+       var prec OpPrec
 
        switch c {
        case EOF:
-               lineno = prevlineno
-               l.ungetc(EOF)
+               l.ungetr(EOF) // return EOF again in future next call
                // Treat EOF as "end of line" for the purposes
                // of inserting a semicolon.
                if nlsemi {
@@ -1088,427 +1011,469 @@ l0:
                l.tok = -1
                return
 
-       case '_':
-               cp = &lexbuf
-               cp.Reset()
-               goto talph
+       case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+               l.number(c)
+               return
 
        case '.':
-               c1 = l.getc()
+               c1 = l.getr()
                if isDigit(c1) {
-                       cp = &lexbuf
-                       cp.Reset()
-                       cp.WriteByte(byte(c))
-                       c = c1
-                       goto casedot
+                       l.ungetr(c1)
+                       l.number('.')
+                       return
                }
 
                if c1 == '.' {
-                       c1 = l.getc()
+                       c1 = l.getr()
                        if c1 == '.' {
                                c = LDDD
                                goto lx
                        }
 
-                       l.ungetc(c1)
+                       l.ungetr(c1)
                        c1 = '.'
                }
 
-               // "..."
        case '"':
-               lexbuf.Reset()
-               lexbuf.WriteString(`"<string>"`)
-
-               cp = &strbuf
-               cp.Reset()
-
-               for {
-                       if l.escchar('"', &escflag, &v) {
-                               break
-                       }
-                       if v < utf8.RuneSelf || escflag != 0 {
-                               cp.WriteByte(byte(v))
-                       } else {
-                               cp.WriteRune(rune(v))
-                       }
-               }
-
-               goto strlit
+               l.stdString()
+               return
 
-               // `...`
        case '`':
-               lexbuf.Reset()
-               lexbuf.WriteString("`<string>`")
-
-               cp = &strbuf
-               cp.Reset()
-
-               for {
-                       c = int(l.getr())
-                       if c == '\r' {
-                               continue
-                       }
-                       if c == EOF {
-                               Yyerror("eof in string")
-                               break
-                       }
-
-                       if c == '`' {
-                               break
-                       }
-                       cp.WriteRune(rune(c))
-               }
-
-               goto strlit
+               l.rawString()
+               return
 
-               // '.'
        case '\'':
-               if l.escchar('\'', &escflag, &v) {
-                       Yyerror("empty character literal or unescaped ' in character literal")
-                       v = '\''
-               }
-
-               if !l.escchar('\'', &escflag, &v) {
-                       Yyerror("missing '")
-                       l.ungetc(int(v))
-               }
-
-               x := new(Mpint)
-               l.val.U = x
-               Mpmovecfix(x, v)
-               x.Rune = true
-               if Debug['x'] != 0 {
-                       fmt.Printf("lex: codepoint literal\n")
-               }
-               litbuf = "string literal"
-               l.nlsemi = true
-               l.tok = LLITERAL
+               l.rune()
                return
 
        case '/':
-               c1 = l.getc()
+               c1 = l.getr()
                if c1 == '*' {
-                       nl := false
+                       c = l.getr()
                        for {
-                               c = int(l.getr())
-                               if c == '\n' {
-                                       nl = true
-                               }
-                               for c == '*' {
-                                       c = int(l.getr())
+                               if c == '*' {
+                                       c = l.getr()
                                        if c == '/' {
-                                               if nl {
-                                                       l.ungetc('\n')
-                                               }
-                                               goto l0
-                                       }
-
-                                       if c == '\n' {
-                                               nl = true
+                                               break
                                        }
+                                       continue
                                }
-
                                if c == EOF {
                                        Yyerror("eof in comment")
                                        errorexit()
                                }
+                               c = l.getr()
+                       }
+
+                       // A comment containing newlines acts like a newline.
+                       if lexlineno > lineno && nlsemi {
+                               if Debug['x'] != 0 {
+                                       fmt.Printf("lex: implicit semi\n")
+                               }
+                               l.tok = ';'
+                               return
                        }
+                       goto l0
                }
 
                if c1 == '/' {
                        c = l.getlinepragma()
                        for {
                                if c == '\n' || c == EOF {
-                                       l.ungetc(c)
+                                       l.ungetr(c)
                                        goto l0
                                }
 
-                               c = int(l.getr())
+                               c = l.getr()
                        }
                }
 
-               if c1 == '=' {
-                       op = ODIV
-                       goto asop
-               }
+               op = ODIV
+               prec = PMUL
+               goto binop1
 
        case ':':
-               c1 = l.getc()
+               c1 = l.getr()
                if c1 == '=' {
-                       c = int(LCOLAS)
+                       c = LCOLAS
                        goto lx
                }
 
        case '*':
-               c1 = l.getc()
-               if c1 == '=' {
-                       op = OMUL
-                       goto asop
-               }
+               op = OMUL
+               prec = PMUL
+               goto binop
 
        case '%':
-               c1 = l.getc()
-               if c1 == '=' {
-                       op = OMOD
-                       goto asop
-               }
+               op = OMOD
+               prec = PMUL
+               goto binop
 
        case '+':
-               c1 = l.getc()
-               if c1 == '+' {
-                       l.nlsemi = true
-                       c = int(LINC)
-                       goto lx
-               }
-
-               if c1 == '=' {
-                       op = OADD
-                       goto asop
-               }
+               op = OADD
+               goto incop
 
        case '-':
-               c1 = l.getc()
-               if c1 == '-' {
-                       l.nlsemi = true
-                       c = int(LDEC)
-                       goto lx
-               }
-
-               if c1 == '=' {
-                       op = OSUB
-                       goto asop
-               }
+               op = OSUB
+               goto incop
 
        case '>':
-               c1 = l.getc()
+               c1 = l.getr()
                if c1 == '>' {
-                       c = int(LRSH)
-                       c1 = l.getc()
-                       if c1 == '=' {
-                               op = ORSH
-                               goto asop
-                       }
-
-                       break
+                       c = LRSH
+                       op = ORSH
+                       prec = PMUL
+                       goto binop
                }
 
+               l.prec = PCMP
                if c1 == '=' {
-                       c = int(LGE)
+                       c = LGE
+                       l.op = OGE
                        goto lx
                }
-
-               c = int(LGT)
+               c = LGT
+               l.op = OGT
 
        case '<':
-               c1 = l.getc()
+               c1 = l.getr()
                if c1 == '<' {
-                       c = int(LLSH)
-                       c1 = l.getc()
-                       if c1 == '=' {
-                               op = OLSH
-                               goto asop
-                       }
-
-                       break
+                       c = LLSH
+                       op = OLSH
+                       prec = PMUL
+                       goto binop
                }
 
-               if c1 == '=' {
-                       c = int(LLE)
+               if c1 == '-' {
+                       c = LCOMM
+                       // Not a binary operator, but parsed as one
+                       // so we can give a good error message when used
+                       // in an expression context.
+                       l.prec = PCOMM
+                       l.op = OSEND
                        goto lx
                }
 
-               if c1 == '-' {
-                       c = int(LCOMM)
+               l.prec = PCMP
+               if c1 == '=' {
+                       c = LLE
+                       l.op = OLE
                        goto lx
                }
-
-               c = int(LLT)
+               c = LLT
+               l.op = OLT
 
        case '=':
-               c1 = l.getc()
+               c1 = l.getr()
                if c1 == '=' {
-                       c = int(LEQ)
+                       c = LEQ
+                       l.prec = PCMP
+                       l.op = OEQ
                        goto lx
                }
 
        case '!':
-               c1 = l.getc()
+               c1 = l.getr()
                if c1 == '=' {
-                       c = int(LNE)
+                       c = LNE
+                       l.prec = PCMP
+                       l.op = ONE
                        goto lx
                }
 
        case '&':
-               c1 = l.getc()
+               c1 = l.getr()
                if c1 == '&' {
-                       c = int(LANDAND)
+                       c = LANDAND
+                       l.prec = PANDAND
+                       l.op = OANDAND
                        goto lx
                }
 
                if c1 == '^' {
-                       c = int(LANDNOT)
-                       c1 = l.getc()
-                       if c1 == '=' {
-                               op = OANDNOT
-                               goto asop
-                       }
-
-                       break
+                       c = LANDNOT
+                       op = OANDNOT
+                       prec = PMUL
+                       goto binop
                }
 
-               if c1 == '=' {
-                       op = OAND
-                       goto asop
-               }
+               op = OAND
+               prec = PMUL
+               goto binop1
 
        case '|':
-               c1 = l.getc()
+               c1 = l.getr()
                if c1 == '|' {
-                       c = int(LOROR)
+                       c = LOROR
+                       l.prec = POROR
+                       l.op = OOROR
                        goto lx
                }
 
-               if c1 == '=' {
-                       op = OOR
-                       goto asop
-               }
+               op = OOR
+               prec = PADD
+               goto binop1
 
        case '^':
-               c1 = l.getc()
-               if c1 == '=' {
-                       op = OXOR
-                       goto asop
-               }
+               op = OXOR
+               prec = PADD
+               goto binop
+
+       case '(', '[', '{', ',', ';':
+               goto lx
 
        case ')', ']', '}':
                l.nlsemi = true
                goto lx
 
+       case '#', '$', '?', '@', '\\':
+               if importpkg != nil {
+                       goto lx
+               }
+               fallthrough
+
        default:
-               goto lx
+               // anything else is illegal
+               Yyerror("syntax error: illegal character %#U", c)
+               goto l0
        }
 
-       l.ungetc(c1)
+       l.ungetr(c1)
 
 lx:
        if Debug['x'] != 0 {
-               if c > 0xff {
-                       fmt.Printf("%v lex: TOKEN %s\n", Ctxt.Line(int(lexlineno)), lexname(c))
+               if c >= utf8.RuneSelf {
+                       fmt.Printf("%v lex: TOKEN %s\n", Ctxt.Line(int(lineno)), lexname(c))
                } else {
-                       fmt.Printf("%v lex: TOKEN '%c'\n", Ctxt.Line(int(lexlineno)), c)
+                       fmt.Printf("%v lex: TOKEN '%c'\n", Ctxt.Line(int(lineno)), c)
                }
        }
-       if isfrog(c) {
-               Yyerror("illegal character 0x%x", uint(c))
-               goto l0
-       }
 
-       if importpkg == nil && (c == '#' || c == '$' || c == '?' || c == '@' || c == '\\') {
-               Yyerror("%s: unexpected %c", "syntax error", c)
-               goto l0
+       l.tok = c
+       return
+
+incop:
+       c1 = l.getr()
+       if c1 == c {
+               l.nlsemi = true
+               l.op = op
+               c = LINCOP
+               goto lx
        }
+       prec = PADD
+       goto binop1
 
-       l.tok = int32(c)
-       return
+binop:
+       c1 = l.getr()
+binop1:
+       if c1 != '=' {
+               l.ungetr(c1)
+               l.op = op
+               l.prec = prec
+               goto lx
+       }
 
-asop:
        l.op = op
        if Debug['x'] != 0 {
                fmt.Printf("lex: TOKEN ASOP %s=\n", goopnames[op])
        }
        l.tok = LASOP
-       return
+}
+
+func (l *lexer) ident(c rune) {
+       cp := &lexbuf
+       cp.Reset()
 
-       // cp is set to lexbuf and some
-       // prefix has been stored
-talph:
+       // accelerate common case (7bit ASCII)
+       for isLetter(c) || isDigit(c) {
+               cp.WriteByte(byte(c))
+               c = l.getr()
+       }
+
+       // general case
        for {
                if c >= utf8.RuneSelf {
-                       l.ungetc(c)
-                       r := rune(l.getr())
-
-                       // 0xb7 Â· is used for internal names
-                       if !unicode.IsLetter(r) && !unicode.IsDigit(r) && (importpkg == nil || r != 0xb7) {
-                               Yyerror("invalid identifier character U+%04x", r)
-                       }
-                       if cp.Len() == 0 && unicode.IsDigit(r) {
-                               Yyerror("identifier cannot begin with digit U+%04x", r)
+                       if unicode.IsLetter(c) || c == '_' || unicode.IsDigit(c) || importpkg != nil && c == 0xb7 {
+                               if cp.Len() == 0 && unicode.IsDigit(c) {
+                                       Yyerror("identifier cannot begin with digit %#U", c)
+                               }
+                       } else {
+                               Yyerror("invalid identifier character %#U", c)
                        }
-                       cp.WriteRune(r)
-               } else if !isAlnum(c) && c != '_' {
-                       break
-               } else {
+                       cp.WriteRune(c)
+               } else if isLetter(c) || isDigit(c) {
                        cp.WriteByte(byte(c))
+               } else {
+                       break
                }
-               c = l.getc()
+               c = l.getr()
        }
 
        cp = nil
-       l.ungetc(c)
+       l.ungetr(c)
 
-       s = LookupBytes(lexbuf.Bytes())
-       if s.Lexical == LIGNORE {
-               goto l0
+       name := lexbuf.Bytes()
+
+       if len(name) >= 2 {
+               if tok, ok := keywords[string(name)]; ok {
+                       if Debug['x'] != 0 {
+                               fmt.Printf("lex: %s\n", lexname(tok))
+                       }
+                       switch tok {
+                       case LBREAK, LCONTINUE, LFALL, LRETURN:
+                               l.nlsemi = true
+                       }
+                       l.tok = tok
+                       return
+               }
        }
 
+       s := LookupBytes(name)
        if Debug['x'] != 0 {
-               fmt.Printf("lex: %s %s\n", s, lexname(int(s.Lexical)))
+               fmt.Printf("lex: ident %s\n", s)
        }
        l.sym_ = s
-       switch s.Lexical {
-       case LNAME, LRETURN, LBREAK, LCONTINUE, LFALL:
-               l.nlsemi = true
-       }
-       l.tok = int32(s.Lexical)
-       return
+       l.nlsemi = true
+       l.tok = LNAME
+}
 
-ncu:
-       cp = nil
-       l.ungetc(c)
+var keywords = map[string]int32{
+       "break":       LBREAK,
+       "case":        LCASE,
+       "chan":        LCHAN,
+       "const":       LCONST,
+       "continue":    LCONTINUE,
+       "default":     LDEFAULT,
+       "defer":       LDEFER,
+       "else":        LELSE,
+       "fallthrough": LFALL,
+       "for":         LFOR,
+       "func":        LFUNC,
+       "go":          LGO,
+       "goto":        LGOTO,
+       "if":          LIF,
+       "import":      LIMPORT,
+       "interface":   LINTERFACE,
+       "map":         LMAP,
+       "package":     LPACKAGE,
+       "range":       LRANGE,
+       "return":      LRETURN,
+       "select":      LSELECT,
+       "struct":      LSTRUCT,
+       "switch":      LSWITCH,
+       "type":        LTYPE,
+       "var":         LVAR,
+
+       // ðŸ’©
+       "notwithstanding":      LIGNORE,
+       "thetruthofthematter":  LIGNORE,
+       "despiteallobjections": LIGNORE,
+       "whereas":              LIGNORE,
+       "insofaras":            LIGNORE,
+}
 
-       str = lexbuf.String()
-       l.val.U = new(Mpint)
-       mpatofix(l.val.U.(*Mpint), str)
-       if l.val.U.(*Mpint).Ovf {
-               Yyerror("overflow in constant")
-               Mpmovecfix(l.val.U.(*Mpint), 0)
-       }
+func (l *lexer) number(c rune) {
+       // TODO(gri) this can be done nicely with fewer or even without labels
 
-       if Debug['x'] != 0 {
-               fmt.Printf("lex: integer literal\n")
+       var str string
+       cp := &lexbuf
+       cp.Reset()
+
+       if c != '.' {
+               if c != '0' {
+                       for isDigit(c) {
+                               cp.WriteByte(byte(c))
+                               c = l.getr()
+                       }
+                       if c == '.' {
+                               goto casedot
+                       }
+                       if c == 'e' || c == 'E' || c == 'p' || c == 'P' {
+                               goto caseep
+                       }
+                       if c == 'i' {
+                               goto casei
+                       }
+                       goto ncu
+               }
+
+               // c == 0
+               cp.WriteByte('0')
+               c = l.getr()
+               if c == 'x' || c == 'X' {
+                       cp.WriteByte(byte(c))
+                       c = l.getr()
+                       for isDigit(c) || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
+                               cp.WriteByte(byte(c))
+                               c = l.getr()
+                       }
+                       if lexbuf.Len() == 2 {
+                               Yyerror("malformed hex constant")
+                       }
+                       if c == 'p' {
+                               goto caseep
+                       }
+                       goto ncu
+               }
+
+               if c == 'p' { // 0p begins floating point zero
+                       goto caseep
+               }
+
+               has8or9 := false
+               for isDigit(c) {
+                       if c > '7' {
+                               has8or9 = true
+                       }
+                       cp.WriteByte(byte(c))
+                       c = l.getr()
+               }
+               if c == '.' {
+                       goto casedot
+               }
+               if c == 'e' || c == 'E' {
+                       goto caseep
+               }
+               if c == 'i' {
+                       goto casei
+               }
+               if has8or9 {
+                       Yyerror("malformed octal constant")
+               }
+               goto ncu
        }
-       litbuf = "literal " + str
-       l.nlsemi = true
-       l.tok = LLITERAL
-       return
 
 casedot:
-       for {
+       // fraction
+       // c == '.'
+       cp.WriteByte('.')
+       c = l.getr()
+       for isDigit(c) {
                cp.WriteByte(byte(c))
-               c = l.getc()
-               if !isDigit(c) {
-                       break
-               }
+               c = l.getr()
        }
-
        if c == 'i' {
                goto casei
        }
        if c != 'e' && c != 'E' {
                goto caseout
        }
+       // base-2-exponents (p or P) don't appear in numbers
+       // with fractions - ok to not test for 'p' or 'P'
+       // above
 
 caseep:
+       // exponent
        if importpkg == nil && (c == 'p' || c == 'P') {
                // <mantissa>p<base-2-exponent> is allowed in .a/.o imports,
                // but not in .go sources.  See #9036.
                Yyerror("malformed floating point constant")
        }
        cp.WriteByte(byte(c))
-       c = l.getc()
+       c = l.getr()
        if c == '+' || c == '-' {
                cp.WriteByte(byte(c))
-               c = l.getc()
+               c = l.getr()
        }
 
        if !isDigit(c) {
@@ -1516,16 +1481,15 @@ caseep:
        }
        for isDigit(c) {
                cp.WriteByte(byte(c))
-               c = l.getc()
+               c = l.getr()
        }
 
-       if c == 'i' {
-               goto casei
+       if c != 'i' {
+               goto caseout
        }
-       goto caseout
 
-       // imaginary constant
 casei:
+       // imaginary constant
        cp = nil
 
        str = lexbuf.String()
@@ -1540,14 +1504,11 @@ casei:
        if Debug['x'] != 0 {
                fmt.Printf("lex: imaginary literal\n")
        }
-       litbuf = "literal " + str
-       l.nlsemi = true
-       l.tok = LLITERAL
-       return
+       goto done
 
 caseout:
        cp = nil
-       l.ungetc(c)
+       l.ungetr(c)
 
        str = lexbuf.String()
        l.val.U = newMpflt()
@@ -1560,12 +1521,80 @@ caseout:
        if Debug['x'] != 0 {
                fmt.Printf("lex: floating literal\n")
        }
+       goto done
+
+ncu:
+       cp = nil
+       l.ungetr(c)
+
+       str = lexbuf.String()
+       l.val.U = new(Mpint)
+       mpatofix(l.val.U.(*Mpint), str)
+       if l.val.U.(*Mpint).Ovf {
+               Yyerror("overflow in constant")
+               Mpmovecfix(l.val.U.(*Mpint), 0)
+       }
+
+       if Debug['x'] != 0 {
+               fmt.Printf("lex: integer literal\n")
+       }
+
+done:
        litbuf = "literal " + str
        l.nlsemi = true
        l.tok = LLITERAL
-       return
+}
+
+func (l *lexer) stdString() {
+       lexbuf.Reset()
+       lexbuf.WriteString(`"<string>"`)
+
+       cp := &strbuf
+       cp.Reset()
+
+       for {
+               r, b, ok := l.onechar('"')
+               if !ok {
+                       break
+               }
+               if r == 0 {
+                       cp.WriteByte(b)
+               } else {
+                       cp.WriteRune(r)
+               }
+       }
+
+       l.val.U = internString(cp.Bytes())
+       if Debug['x'] != 0 {
+               fmt.Printf("lex: string literal\n")
+       }
+       litbuf = "string literal"
+       l.nlsemi = true
+       l.tok = LLITERAL
+}
+
+func (l *lexer) rawString() {
+       lexbuf.Reset()
+       lexbuf.WriteString("`<string>`")
+
+       cp := &strbuf
+       cp.Reset()
+
+       for {
+               c := l.getr()
+               if c == '\r' {
+                       continue
+               }
+               if c == EOF {
+                       Yyerror("eof in string")
+                       break
+               }
+               if c == '`' {
+                       break
+               }
+               cp.WriteRune(c)
+       }
 
-strlit:
        l.val.U = internString(cp.Bytes())
        if Debug['x'] != 0 {
                fmt.Printf("lex: string literal\n")
@@ -1575,6 +1604,33 @@ strlit:
        l.tok = LLITERAL
 }
 
+func (l *lexer) rune() {
+       r, b, ok := l.onechar('\'')
+       if !ok {
+               Yyerror("empty character literal or unescaped ' in character literal")
+               r = '\''
+       }
+       if r == 0 {
+               r = rune(b)
+       }
+
+       if c := l.getr(); c != '\'' {
+               Yyerror("missing '")
+               l.ungetr(c)
+       }
+
+       x := new(Mpint)
+       l.val.U = x
+       Mpmovecfix(x, int64(r))
+       x.Rune = true
+       if Debug['x'] != 0 {
+               fmt.Printf("lex: codepoint literal\n")
+       }
+       litbuf = "rune literal"
+       l.nlsemi = true
+       l.tok = LLITERAL
+}
+
 var internedStrings = map[string]string{}
 
 func internString(b []byte) string {
@@ -1588,7 +1644,7 @@ func internString(b []byte) string {
 
 func more(pp *string) bool {
        p := *pp
-       for p != "" && isSpace(int(p[0])) {
+       for p != "" && isSpace(rune(p[0])) {
                p = p[1:]
        }
        *pp = p
@@ -1599,16 +1655,14 @@ func more(pp *string) bool {
 // //line parse.y:15
 // as a discontinuity in sequential line numbers.
 // the next line of input comes from parse.y:15
-func (l *lexer) getlinepragma() int {
-       var cmd, verb, name string
-
-       c := int(l.getr())
-       if c == 'g' {
+func (l *lexer) getlinepragma() rune {
+       c := l.getr()
+       if c == 'g' { // check for //go: directive
                cp := &lexbuf
                cp.Reset()
                cp.WriteByte('g') // already read
                for {
-                       c = int(l.getr())
+                       c = l.getr()
                        if c == EOF || c >= utf8.RuneSelf {
                                return c
                        }
@@ -1625,83 +1679,60 @@ func (l *lexer) getlinepragma() int {
                        pragcgo(text)
                }
 
-               cmd = text
-               verb = cmd
-               if i := strings.Index(verb, " "); i >= 0 {
+               verb := text
+               if i := strings.Index(text, " "); i >= 0 {
                        verb = verb[:i]
                }
 
-               if verb == "go:linkname" {
+               switch verb {
+               case "go:linkname":
                        if !imported_unsafe {
                                Yyerror("//go:linkname only allowed in Go files that import \"unsafe\"")
                        }
-                       f := strings.Fields(cmd)
+                       f := strings.Fields(text)
                        if len(f) != 3 {
                                Yyerror("usage: //go:linkname localname linkname")
-                               return c
+                               break
                        }
-
                        Lookup(f[1]).Linkname = f[2]
-                       return c
-               }
-
-               if verb == "go:nointerface" && obj.Fieldtrack_enabled != 0 {
-                       nointerface = true
-                       return c
-               }
-
-               if verb == "go:noescape" {
-                       noescape = true
-                       return c
-               }
-
-               if verb == "go:norace" {
-                       norace = true
-                       return c
-               }
-
-               if verb == "go:nosplit" {
-                       nosplit = true
-                       return c
-               }
-
-               if verb == "go:noinline" {
-                       noinline = true
-                       return c
-               }
-
-               if verb == "go:systemstack" {
+               case "go:nointerface":
+                       if obj.Fieldtrack_enabled != 0 {
+                               l.pragma |= Nointerface
+                       }
+               case "go:noescape":
+                       l.pragma |= Noescape
+               case "go:norace":
+                       l.pragma |= Norace
+               case "go:nosplit":
+                       l.pragma |= Nosplit
+               case "go:noinline":
+                       l.pragma |= Noinline
+               case "go:systemstack":
                        if compiling_runtime == 0 {
                                Yyerror("//go:systemstack only allowed in runtime")
                        }
-                       systemstack = true
-                       return c
-               }
-
-               if verb == "go:nowritebarrier" {
+                       l.pragma |= Systemstack
+               case "go:nowritebarrier":
                        if compiling_runtime == 0 {
                                Yyerror("//go:nowritebarrier only allowed in runtime")
                        }
-                       nowritebarrier = true
-                       return c
-               }
-
-               if verb == "go:nowritebarrierrec" {
+                       l.pragma |= Nowritebarrier
+               case "go:nowritebarrierrec":
                        if compiling_runtime == 0 {
                                Yyerror("//go:nowritebarrierrec only allowed in runtime")
                        }
-                       nowritebarrierrec = true
-                       nowritebarrier = true // Implies nowritebarrier
-                       return c
+                       l.pragma |= Nowritebarrierrec | Nowritebarrier // implies Nowritebarrier
                }
                return c
        }
+
+       // check for //line directive
        if c != 'l' {
                return c
        }
        for i := 1; i < 5; i++ {
-               c = int(l.getr())
-               if c != int("line "[i]) {
+               c = l.getr()
+               if c != rune("line "[i]) {
                        return c
                }
        }
@@ -1710,7 +1741,7 @@ func (l *lexer) getlinepragma() int {
        cp.Reset()
        linep := 0
        for {
-               c = int(l.getr())
+               c = l.getr()
                if c == EOF {
                        return c
                }
@@ -1725,34 +1756,25 @@ func (l *lexer) getlinepragma() int {
                }
                cp.WriteByte(byte(c))
        }
-
        cp = nil
 
        if linep == 0 {
                return c
        }
        text := strings.TrimSuffix(lexbuf.String(), "\r")
-       n := 0
-       for _, c := range text[linep:] {
-               if c < '0' || c > '9' {
-                       goto out
-               }
-               n = n*10 + int(c) - '0'
-               if n > 1e8 {
-                       Yyerror("line number out of range")
-                       errorexit()
-               }
+       n, err := strconv.Atoi(text[linep:])
+       if err != nil {
+               return c // todo: make this an error instead? it is almost certainly a bug.
+       }
+       if n > 1e8 {
+               Yyerror("line number out of range")
+               errorexit()
        }
-
        if n <= 0 {
                return c
        }
 
-       name = text[:linep-1]
-       linehistupdate(name, n)
-       return c
-
-out:
+       linehistupdate(text[:linep-1], n)
        return c
 }
 
@@ -1763,7 +1785,7 @@ func getimpsym(pp *string) string {
                return ""
        }
        i := 0
-       for i < len(p) && !isSpace(int(p[i])) && p[i] != '"' {
+       for i < len(p) && !isSpace(rune(p[i])) && p[i] != '"' {
                i++
        }
        sym := p[:i]
@@ -1891,145 +1913,119 @@ func pragcgo(text string) {
        }
 }
 
-func (l *lexer) getc() int {
-       c := l.peekc
-       if c != 0 {
-               l.peekc = l.peekc1
-               l.peekc1 = 0
-               goto check
+func (l *lexer) getr() rune {
+       // unread rune != 0 available
+       if r := l.peekr1; r != 0 {
+               l.peekr1 = l.peekr2
+               l.peekr2 = 0
+               if r == '\n' && importpkg == nil {
+                       lexlineno++
+               }
+               return r
        }
 
-loop:
-       c = obj.Bgetc(l.bin)
-       // recognize BOM (U+FEFF): UTF-8 encoding is 0xef 0xbb 0xbf
-       if c == 0xef {
-               buf, err := l.bin.Peek(2)
-               if err != nil {
-                       yyerrorl(int(lexlineno), "illegal UTF-8 sequence ef % x followed by read error (%v)", string(buf), err)
-                       errorexit()
+redo:
+       // common case: 7bit ASCII
+       c := obj.Bgetc(l.bin)
+       if c < utf8.RuneSelf {
+               if c == 0 {
+                       yyerrorl(int(lexlineno), "illegal NUL byte")
+                       return 0
                }
-               if buf[0] == 0xbb && buf[1] == 0xbf {
-                       yyerrorl(int(lexlineno), "Unicode (UTF-8) BOM in middle of file")
-
-                       // consume BOM bytes
-                       obj.Bgetc(l.bin)
-                       obj.Bgetc(l.bin)
-                       goto loop
+               if c == '\n' && importpkg == nil {
+                       lexlineno++
                }
+               return rune(c)
        }
+       // c >= utf8.RuneSelf
 
-check:
-       if c == 0 {
-               Yyerror("illegal NUL byte")
-               return 0
+       // uncommon case: non-ASCII
+       var buf [utf8.UTFMax]byte
+       buf[0] = byte(c)
+       buf[1] = byte(obj.Bgetc(l.bin))
+       i := 2
+       for ; i < len(buf) && !utf8.FullRune(buf[:i]); i++ {
+               buf[i] = byte(obj.Bgetc(l.bin))
        }
-       if c == '\n' && importpkg == nil {
-               lexlineno++
+
+       r, w := utf8.DecodeRune(buf[:i])
+       if r == utf8.RuneError && w == 1 {
+               // The string conversion here makes a copy for passing
+               // to fmt.Printf, so that buf itself does not escape and
+               // can be allocated on the stack.
+               yyerrorl(int(lexlineno), "illegal UTF-8 sequence % x", string(buf[:i]))
        }
-       return c
-}
 
-func (l *lexer) ungetc(c int) {
-       l.peekc1 = l.peekc
-       l.peekc = c
-       if c == '\n' && importpkg == nil {
-               lexlineno--
+       if r == BOM {
+               yyerrorl(int(lexlineno), "Unicode (UTF-8) BOM in middle of file")
+               goto redo
        }
-}
 
-func (l *lexer) getr() int32 {
-       var buf [utf8.UTFMax]byte
+       return r
+}
 
-       for i := 0; ; i++ {
-               c := l.getc()
-               if i == 0 && c < utf8.RuneSelf {
-                       return int32(c)
-               }
-               buf[i] = byte(c)
-               if i+1 == len(buf) || utf8.FullRune(buf[:i+1]) {
-                       r, w := utf8.DecodeRune(buf[:i+1])
-                       if r == utf8.RuneError && w == 1 {
-                               lineno = lexlineno
-                               // The string conversion here makes a copy for passing
-                               // to fmt.Printf, so that buf itself does not escape and can
-                               // be allocated on the stack.
-                               Yyerror("illegal UTF-8 sequence % x", string(buf[:i+1]))
-                       }
-                       return int32(r)
-               }
+func (l *lexer) ungetr(r rune) {
+       l.peekr2 = l.peekr1
+       l.peekr1 = r
+       if r == '\n' && importpkg == nil {
+               lexlineno--
        }
 }
 
-func (l *lexer) escchar(e int, escflg *int, val *int64) bool {
-       *escflg = 0
-
-       c := int(l.getr())
+// onechar lexes a single character within a rune or interpreted string literal,
+// handling escape sequences as necessary.
+func (l *lexer) onechar(quote rune) (r rune, b byte, ok bool) {
+       c := l.getr()
        switch c {
        case EOF:
                Yyerror("eof in string")
-               return true
+               l.ungetr(EOF)
+               return
 
        case '\n':
                Yyerror("newline in string")
-               return true
+               l.ungetr('\n')
+               return
 
        case '\\':
                break
 
+       case quote:
+               return
+
        default:
-               if c == e {
-                       return true
-               }
-               *val = int64(c)
-               return false
+               return c, 0, true
        }
 
-       u := 0
-       c = int(l.getr())
-       var i int
+       c = l.getr()
        switch c {
        case 'x':
-               *escflg = 1 // it's a byte
-               i = 2
-               goto hex
+               return 0, byte(l.hexchar(2)), true
 
        case 'u':
-               i = 4
-               u = 1
-               goto hex
+               return l.unichar(4), 0, true
 
        case 'U':
-               i = 8
-               u = 1
-               goto hex
-
-       case '0',
-               '1',
-               '2',
-               '3',
-               '4',
-               '5',
-               '6',
-               '7':
-               *escflg = 1 // it's a byte
-               x := int64(c) - '0'
+               return l.unichar(8), 0, true
+
+       case '0', '1', '2', '3', '4', '5', '6', '7':
+               x := c - '0'
                for i := 2; i > 0; i-- {
-                       c = l.getc()
+                       c = l.getr()
                        if c >= '0' && c <= '7' {
-                               x = x*8 + int64(c) - '0'
+                               x = x*8 + c - '0'
                                continue
                        }
 
                        Yyerror("non-octal character in escape sequence: %c", c)
-                       l.ungetc(c)
+                       l.ungetr(c)
                }
 
                if x > 255 {
                        Yyerror("octal escape value > 255: %d", x)
                }
 
-               *val = x
-               return false
+               return 0, byte(x), true
 
        case 'a':
                c = '\a'
@@ -2049,153 +2045,115 @@ func (l *lexer) escchar(e int, escflg *int, val *int64) bool {
                c = '\\'
 
        default:
-               if c != e {
+               if c != quote {
                        Yyerror("unknown escape sequence: %c", c)
                }
        }
 
-       *val = int64(c)
-       return false
+       return c, 0, true
+}
 
-hex:
-       x := int64(0)
-       for ; i > 0; i-- {
-               c = l.getc()
-               if c >= '0' && c <= '9' {
-                       x = x*16 + int64(c) - '0'
-                       continue
-               }
+func (l *lexer) unichar(n int) rune {
+       x := l.hexchar(n)
+       if x > utf8.MaxRune || 0xd800 <= x && x < 0xe000 {
+               Yyerror("invalid Unicode code point in escape sequence: %#x", x)
+               x = utf8.RuneError
+       }
+       return rune(x)
+}
 
-               if c >= 'a' && c <= 'f' {
-                       x = x*16 + int64(c) - 'a' + 10
-                       continue
-               }
+func (l *lexer) hexchar(n int) uint32 {
+       var x uint32
 
-               if c >= 'A' && c <= 'F' {
-                       x = x*16 + int64(c) - 'A' + 10
-                       continue
+       for ; n > 0; n-- {
+               var d uint32
+               switch c := l.getr(); {
+               case isDigit(c):
+                       d = uint32(c - '0')
+               case 'a' <= c && c <= 'f':
+                       d = uint32(c - 'a' + 10)
+               case 'A' <= c && c <= 'F':
+                       d = uint32(c - 'A' + 10)
+               default:
+                       Yyerror("non-hex character in escape sequence: %c", c)
+                       l.ungetr(c)
+                       return x
                }
-
-               Yyerror("non-hex character in escape sequence: %c", c)
-               l.ungetc(c)
-               break
+               x = x*16 + d
        }
 
-       if u != 0 && (x > utf8.MaxRune || (0xd800 <= x && x < 0xe000)) {
-               Yyerror("invalid Unicode code point in escape sequence: %#x", x)
-               x = utf8.RuneError
-       }
+       return x
+}
 
-       *val = x
-       return false
+var basicTypes = [...]struct {
+       name  string
+       etype EType
+}{
+       {"int8", TINT8},
+       {"int16", TINT16},
+       {"int32", TINT32},
+       {"int64", TINT64},
+       {"uint8", TUINT8},
+       {"uint16", TUINT16},
+       {"uint32", TUINT32},
+       {"uint64", TUINT64},
+       {"float32", TFLOAT32},
+       {"float64", TFLOAT64},
+       {"complex64", TCOMPLEX64},
+       {"complex128", TCOMPLEX128},
+       {"bool", TBOOL},
+       {"string", TSTRING},
+       {"any", TANY},
 }
 
-var syms = []struct {
-       name    string
-       lexical int
-       etype   EType
-       op      Op
+var builtinFuncs = [...]struct {
+       name string
+       op   Op
 }{
-       // basic types
-       {"int8", LNAME, TINT8, OXXX},
-       {"int16", LNAME, TINT16, OXXX},
-       {"int32", LNAME, TINT32, OXXX},
-       {"int64", LNAME, TINT64, OXXX},
-       {"uint8", LNAME, TUINT8, OXXX},
-       {"uint16", LNAME, TUINT16, OXXX},
-       {"uint32", LNAME, TUINT32, OXXX},
-       {"uint64", LNAME, TUINT64, OXXX},
-       {"float32", LNAME, TFLOAT32, OXXX},
-       {"float64", LNAME, TFLOAT64, OXXX},
-       {"complex64", LNAME, TCOMPLEX64, OXXX},
-       {"complex128", LNAME, TCOMPLEX128, OXXX},
-       {"bool", LNAME, TBOOL, OXXX},
-       {"string", LNAME, TSTRING, OXXX},
-       {"any", LNAME, TANY, OXXX},
-       {"break", LBREAK, Txxx, OXXX},
-       {"case", LCASE, Txxx, OXXX},
-       {"chan", LCHAN, Txxx, OXXX},
-       {"const", LCONST, Txxx, OXXX},
-       {"continue", LCONTINUE, Txxx, OXXX},
-       {"default", LDEFAULT, Txxx, OXXX},
-       {"else", LELSE, Txxx, OXXX},
-       {"defer", LDEFER, Txxx, OXXX},
-       {"fallthrough", LFALL, Txxx, OXXX},
-       {"for", LFOR, Txxx, OXXX},
-       {"func", LFUNC, Txxx, OXXX},
-       {"go", LGO, Txxx, OXXX},
-       {"goto", LGOTO, Txxx, OXXX},
-       {"if", LIF, Txxx, OXXX},
-       {"import", LIMPORT, Txxx, OXXX},
-       {"interface", LINTERFACE, Txxx, OXXX},
-       {"map", LMAP, Txxx, OXXX},
-       {"package", LPACKAGE, Txxx, OXXX},
-       {"range", LRANGE, Txxx, OXXX},
-       {"return", LRETURN, Txxx, OXXX},
-       {"select", LSELECT, Txxx, OXXX},
-       {"struct", LSTRUCT, Txxx, OXXX},
-       {"switch", LSWITCH, Txxx, OXXX},
-       {"type", LTYPE, Txxx, OXXX},
-       {"var", LVAR, Txxx, OXXX},
-       {"append", LNAME, Txxx, OAPPEND},
-       {"cap", LNAME, Txxx, OCAP},
-       {"close", LNAME, Txxx, OCLOSE},
-       {"complex", LNAME, Txxx, OCOMPLEX},
-       {"copy", LNAME, Txxx, OCOPY},
-       {"delete", LNAME, Txxx, ODELETE},
-       {"imag", LNAME, Txxx, OIMAG},
-       {"len", LNAME, Txxx, OLEN},
-       {"make", LNAME, Txxx, OMAKE},
-       {"new", LNAME, Txxx, ONEW},
-       {"panic", LNAME, Txxx, OPANIC},
-       {"print", LNAME, Txxx, OPRINT},
-       {"println", LNAME, Txxx, OPRINTN},
-       {"real", LNAME, Txxx, OREAL},
-       {"recover", LNAME, Txxx, ORECOVER},
-       {"notwithstanding", LIGNORE, Txxx, OXXX},
-       {"thetruthofthematter", LIGNORE, Txxx, OXXX},
-       {"despiteallobjections", LIGNORE, Txxx, OXXX},
-       {"whereas", LIGNORE, Txxx, OXXX},
-       {"insofaras", LIGNORE, Txxx, OXXX},
+       {"append", OAPPEND},
+       {"cap", OCAP},
+       {"close", OCLOSE},
+       {"complex", OCOMPLEX},
+       {"copy", OCOPY},
+       {"delete", ODELETE},
+       {"imag", OIMAG},
+       {"len", OLEN},
+       {"make", OMAKE},
+       {"new", ONEW},
+       {"panic", OPANIC},
+       {"print", OPRINT},
+       {"println", OPRINTN},
+       {"real", OREAL},
+       {"recover", ORECOVER},
 }
 
 // lexinit initializes known symbols and the basic types.
 func lexinit() {
-       for _, s := range syms {
-               lex := s.lexical
-               s1 := Lookup(s.name)
-               s1.Lexical = uint16(lex)
-
-               if etype := s.etype; etype != Txxx {
-                       if int(etype) >= len(Types) {
-                               Fatalf("lexinit: %s bad etype", s.name)
+       for _, s := range basicTypes {
+               etype := s.etype
+               if int(etype) >= len(Types) {
+                       Fatalf("lexinit: %s bad etype", s.name)
+               }
+               s2 := Pkglookup(s.name, builtinpkg)
+               t := Types[etype]
+               if t == nil {
+                       t = typ(etype)
+                       t.Sym = s2
+                       if etype != TANY && etype != TSTRING {
+                               dowidth(t)
                        }
-                       s2 := Pkglookup(s.name, builtinpkg)
-                       t := Types[etype]
-                       if t == nil {
-                               t = typ(etype)
-                               t.Sym = s2
-
-                               if etype != TANY && etype != TSTRING {
-                                       dowidth(t)
-                               }
-                               Types[etype] = t
-                       }
-
-                       s2.Lexical = LNAME
-                       s2.Def = typenod(t)
-                       s2.Def.Name = new(Name)
-                       continue
+                       Types[etype] = t
                }
+               s2.Def = typenod(t)
+               s2.Def.Name = new(Name)
+       }
 
+       for _, s := range builtinFuncs {
                // TODO(marvin): Fix Node.EType type union.
-               if etype := s.op; etype != OXXX {
-                       s2 := Pkglookup(s.name, builtinpkg)
-                       s2.Lexical = LNAME
-                       s2.Def = Nod(ONAME, nil, nil)
-                       s2.Def.Sym = s2
-                       s2.Def.Etype = EType(etype)
-               }
+               s2 := Pkglookup(s.name, builtinpkg)
+               s2.Def = Nod(ONAME, nil, nil)
+               s2.Def.Sym = s2
+               s2.Def.Etype = EType(s.op)
        }
 
        // logically, the type of a string literal.
@@ -2241,6 +2199,11 @@ func lexinit() {
        s.Def = nodlit(v)
        s.Def.Sym = s
        s.Def.Name = new(Name)
+
+       s = Pkglookup("iota", builtinpkg)
+       s.Def = Nod(OIOTA, nil, nil)
+       s.Def.Sym = s
+       s.Def.Name = new(Name)
 }
 
 func lexinit1() {
@@ -2270,121 +2233,46 @@ func lexinit1() {
        t.Type.Type = f
 
        // error type
-       s := Lookup("error")
-
-       s.Lexical = LNAME
-       s1 := Pkglookup("error", builtinpkg)
+       s := Pkglookup("error", builtinpkg)
        errortype = t
-       errortype.Sym = s1
-       s1.Lexical = LNAME
-       s1.Def = typenod(errortype)
+       errortype.Sym = s
+       s.Def = typenod(errortype)
 
        // byte alias
-       s = Lookup("byte")
-
-       s.Lexical = LNAME
-       s1 = Pkglookup("byte", builtinpkg)
+       s = Pkglookup("byte", builtinpkg)
        bytetype = typ(TUINT8)
-       bytetype.Sym = s1
-       s1.Lexical = LNAME
-       s1.Def = typenod(bytetype)
-       s1.Def.Name = new(Name)
+       bytetype.Sym = s
+       s.Def = typenod(bytetype)
+       s.Def.Name = new(Name)
 
        // rune alias
-       s = Lookup("rune")
-
-       s.Lexical = LNAME
-       s1 = Pkglookup("rune", builtinpkg)
+       s = Pkglookup("rune", builtinpkg)
        runetype = typ(TINT32)
-       runetype.Sym = s1
-       s1.Lexical = LNAME
-       s1.Def = typenod(runetype)
-       s1.Def.Name = new(Name)
-}
-
-func lexfini() {
-       for i := range syms {
-               lex := syms[i].lexical
-               if lex != LNAME {
-                       continue
-               }
-               s := Lookup(syms[i].name)
-               s.Lexical = uint16(lex)
-
-               etype := syms[i].etype
-               if etype != Txxx && (etype != TANY || Debug['A'] != 0) && s.Def == nil {
-                       s.Def = typenod(Types[etype])
-                       s.Def.Name = new(Name)
-                       s.Origpkg = builtinpkg
-               }
-
-               // TODO(marvin): Fix Node.EType type union.
-               etype = EType(syms[i].op)
-               if etype != EType(OXXX) && s.Def == nil {
-                       s.Def = Nod(ONAME, nil, nil)
-                       s.Def.Sym = s
-                       s.Def.Etype = etype
-                       s.Origpkg = builtinpkg
-               }
-       }
+       runetype.Sym = s
+       s.Def = typenod(runetype)
+       s.Def.Name = new(Name)
 
        // backend-specific builtin types (e.g. int).
        for i := range Thearch.Typedefs {
-               s := Lookup(Thearch.Typedefs[i].Name)
-               if s.Def == nil {
-                       s.Def = typenod(Types[Thearch.Typedefs[i].Etype])
-                       s.Def.Name = new(Name)
-                       s.Origpkg = builtinpkg
-               }
-       }
-
-       // there's only so much table-driven we can handle.
-       // these are special cases.
-       if s := Lookup("byte"); s.Def == nil {
-               s.Def = typenod(bytetype)
-               s.Def.Name = new(Name)
-               s.Origpkg = builtinpkg
-       }
-
-       if s := Lookup("error"); s.Def == nil {
-               s.Def = typenod(errortype)
-               s.Def.Name = new(Name)
-               s.Origpkg = builtinpkg
-       }
-
-       if s := Lookup("rune"); s.Def == nil {
-               s.Def = typenod(runetype)
-               s.Def.Name = new(Name)
-               s.Origpkg = builtinpkg
-       }
-
-       if s := Lookup("nil"); s.Def == nil {
-               var v Val
-               v.U = new(NilVal)
-               s.Def = nodlit(v)
-               s.Def.Sym = s
+               s := Pkglookup(Thearch.Typedefs[i].Name, builtinpkg)
+               s.Def = typenod(Types[Thearch.Typedefs[i].Etype])
                s.Def.Name = new(Name)
                s.Origpkg = builtinpkg
        }
+}
 
-       if s := Lookup("iota"); s.Def == nil {
-               s.Def = Nod(OIOTA, nil, nil)
-               s.Def.Sym = s
-               s.Origpkg = builtinpkg
-       }
-
-       if s := Lookup("true"); s.Def == nil {
-               s.Def = Nodbool(true)
-               s.Def.Sym = s
-               s.Def.Name = new(Name)
-               s.Origpkg = builtinpkg
-       }
+func lexfini() {
+       for _, s := range builtinpkg.Syms {
+               if s.Def == nil {
+                       continue
+               }
+               s1 := Lookup(s.Name)
+               if s1.Def != nil {
+                       continue
+               }
 
-       if s := Lookup("false"); s.Def == nil {
-               s.Def = Nodbool(false)
-               s.Def.Sym = s
-               s.Def.Name = new(Name)
-               s.Origpkg = builtinpkg
+               s1.Def = s.Def
+               s1.Block = s.Block
        }
 
        nodfp = Nod(ONAME, nil, nil)
@@ -2394,7 +2282,7 @@ func lexfini() {
        nodfp.Sym = Lookup(".fp")
 }
 
-var lexn = map[int]string{
+var lexn = map[rune]string{
        LANDAND:    "ANDAND",
        LANDNOT:    "ANDNOT",
        LASOP:      "ASOP",
@@ -2406,7 +2294,6 @@ var lexn = map[int]string{
        LCONST:     "CONST",
        LCONTINUE:  "CONTINUE",
        LDDD:       "...",
-       LDEC:       "DEC",
        LDEFAULT:   "DEFAULT",
        LDEFER:     "DEFER",
        LELSE:      "ELSE",
@@ -2420,7 +2307,7 @@ var lexn = map[int]string{
        LGT:        "GT",
        LIF:        "IF",
        LIMPORT:    "IMPORT",
-       LINC:       "INC",
+       LINCOP:     "INCOP",
        LINTERFACE: "INTERFACE",
        LLE:        "LE",
        LLITERAL:   "LITERAL",
@@ -2441,7 +2328,7 @@ var lexn = map[int]string{
        LVAR:       "VAR",
 }
 
-func lexname(lex int) string {
+func lexname(lex rune) string {
        if s, ok := lexn[lex]; ok {
                return s
        }
index 28c3a00825e9b4773065e44823fda7490889aa40..67faf294796f2e48294033d8d1f94eb173f6d9f7 100644 (file)
@@ -217,7 +217,11 @@ func mplshfixfix(a, b *Mpint) {
 
        s := Mpgetfix(b)
        if s < 0 || s >= Mpprec {
-               Yyerror("stupid shift: %d", s)
+               msg := "shift count too large"
+               if s < 0 {
+                       msg = "invalid negative shift count"
+               }
+               Yyerror("%s: %d", msg, s)
                Mpmovecfix(a, 0)
                return
        }
@@ -236,7 +240,7 @@ func mprshfixfix(a, b *Mpint) {
 
        s := Mpgetfix(b)
        if s < 0 {
-               Yyerror("stupid shift: %d", s)
+               Yyerror("invalid negative shift count: %d", s)
                if a.Val.Sign() < 0 {
                        Mpmovecfix(a, -1)
                } else {
index 9bcfda7c0d7676743528a15449f4c8727f15112e..5b61a9e17fd32aa3f1840a316d7c4c9b93da8b81 100644 (file)
@@ -11,7 +11,7 @@ import (
        "math"
 )
 
-/// implements float arihmetic
+// implements float arithmetic
 
 func newMpflt() *Mpflt {
        var a Mpflt
index 12405d5f38b87b5c779b8f3849a5d73bf2fd9f84..df8fc5976d2b62b19bb93fffaab5192c1ee1adb8 100644 (file)
@@ -387,7 +387,7 @@ func ordercall(n *Node, order *Order) {
 
 // Ordermapassign appends n to order->out, introducing temporaries
 // to make sure that all map assignments have the form m[k] = x,
-// where x is adressable.
+// where x is addressable.
 // (Orderexpr has already been called on n, so we know k is addressable.)
 //
 // If n is m[k] = x where x is not addressable, the rewrite is:
@@ -1138,7 +1138,7 @@ func orderexpr(np **Node, order *Order, lhs *Node) {
                }
 
        case OCLOSURE:
-               if n.Noescape && n.Func.Cvars != nil {
+               if n.Noescape && len(n.Func.Cvars.Slice()) > 0 {
                        prealloc[n] = ordertemp(Types[TUINT8], order, false) // walk will fill in correct type
                }
 
index fbc5a5e1eb83c879b6f9b33a9488b75ec5fdc49b..621be57b5008ddd6034d44a3868601b703a26ddf 100644 (file)
@@ -102,6 +102,8 @@ func (p *parser) syntax_error(msg string) {
                }
        case LASOP:
                tok = goopnames[p.op] + "="
+       case LINCOP:
+               tok = goopnames[p.op] + goopnames[p.op]
        default:
                tok = tokstring(p.tok)
        }
@@ -110,11 +112,11 @@ func (p *parser) syntax_error(msg string) {
 }
 
 // Like syntax_error, but reports error at given line rather than current lexer line.
-func (p *parser) syntax_error_at(lineno int32, msg string) {
-       defer func(lineno int32) {
-               lexlineno = lineno
-       }(lexlineno)
-       lexlineno = lineno
+func (p *parser) syntax_error_at(lno int32, msg string) {
+       defer func(lno int32) {
+               lineno = lno
+       }(lineno)
+       lineno = lno
        p.syntax_error(msg)
 }
 
@@ -219,12 +221,11 @@ var tokstrings = map[int32]string{
        LANDAND:    "&&",
        LANDNOT:    "&^",
        LCOMM:      "<-",
-       LDEC:       "--",
        LEQ:        "==",
        LGE:        ">=",
        LGT:        ">",
        LIGNORE:    "LIGNORE", // we should never see this one
-       LINC:       "++",
+       LINCOP:     "opop",
        LLE:        "<=",
        LLSH:       "<<",
        LLT:        "<",
@@ -280,13 +281,11 @@ func (p *parser) package_() {
                defer p.trace("package_")()
        }
 
-       if p.got(LPACKAGE) {
-               mkpackage(p.sym().Name)
-       } else {
-               prevlineno = lineno // see issue #13267
+       if !p.got(LPACKAGE) {
                p.syntax_error("package statement must be first")
                errorexit()
        }
+       mkpackage(p.sym().Name)
 }
 
 // ImportDecl = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) .
@@ -335,20 +334,22 @@ func (p *parser) importdcl() {
        }
 
        line := int32(parserline())
-       path := p.val
-       p.next()
 
-       importfile(&path, p.indent)
-       if importpkg == nil {
+       // We need to clear importpkg before calling p.next(),
+       // otherwise it will affect lexlineno.
+       // TODO(mdempsky): Fix this clumsy API.
+       importfile(&p.val, p.indent)
+       ipkg := importpkg
+       importpkg = nil
+
+       p.next()
+       if ipkg == nil {
                if nerrors == 0 {
                        Fatalf("phase error in import")
                }
                return
        }
 
-       ipkg := importpkg
-       importpkg = nil
-
        ipkg.Direct = true
 
        if my == nil {
@@ -562,22 +563,13 @@ func (p *parser) simple_stmt(labelOk, rangeOk bool) *Node {
                        stmt.Etype = EType(op) // rathole to pass opcode
                        return stmt
 
-               case LINC:
-                       // expr LINC
-                       p.next()
-
-                       stmt := Nod(OASOP, lhs, Nodintconst(1))
-                       stmt.Implicit = true
-                       stmt.Etype = EType(OADD)
-                       return stmt
-
-               case LDEC:
-                       // expr LDEC
+               case LINCOP:
+                       // expr LINCOP
                        p.next()
 
                        stmt := Nod(OASOP, lhs, Nodintconst(1))
                        stmt.Implicit = true
-                       stmt.Etype = EType(OSUB)
+                       stmt.Etype = EType(p.op)
                        return stmt
 
                case ':':
@@ -689,7 +681,7 @@ func (p *parser) labeled_stmt(label *Node) *Node {
                ls = p.stmt()
                if ls == missing_stmt {
                        // report error at line of ':' token
-                       p.syntax_error_at(prevlineno, "missing statement after label")
+                       p.syntax_error_at(label.Lineno, "missing statement after label")
                        // we are already at the end of the labeled statement - no need to advance
                        return missing_stmt
                }
@@ -1104,55 +1096,18 @@ func (p *parser) select_stmt() *Node {
        return hdr
 }
 
-// TODO(gri) should have lexer return this info - no need for separate lookup
-// (issue 13244)
-var prectab = map[int32]struct {
-       prec int // > 0 (0 indicates not found)
-       op   Op
-}{
-       // not an expression anymore, but left in so we can give a good error
-       // message when used in expression context
-       LCOMM: {1, OSEND},
-
-       LOROR: {2, OOROR},
-
-       LANDAND: {3, OANDAND},
-
-       LEQ: {4, OEQ},
-       LNE: {4, ONE},
-       LLE: {4, OLE},
-       LGE: {4, OGE},
-       LLT: {4, OLT},
-       LGT: {4, OGT},
-
-       '+': {5, OADD},
-       '-': {5, OSUB},
-       '|': {5, OOR},
-       '^': {5, OXOR},
-
-       '*':     {6, OMUL},
-       '/':     {6, ODIV},
-       '%':     {6, OMOD},
-       '&':     {6, OAND},
-       LLSH:    {6, OLSH},
-       LRSH:    {6, ORSH},
-       LANDNOT: {6, OANDNOT},
-}
-
 // Expression = UnaryExpr | Expression binary_op Expression .
-func (p *parser) bexpr(prec int) *Node {
+func (p *parser) bexpr(prec OpPrec) *Node {
        // don't trace bexpr - only leads to overly nested trace output
 
+       // prec is precedence of the prior/enclosing binary operator (if any),
+       // so we only want to parse tokens of greater precedence.
+
        x := p.uexpr()
-       t := prectab[p.tok]
-       for tprec := t.prec; tprec >= prec; tprec-- {
-               for tprec == prec {
-                       p.next()
-                       y := p.bexpr(t.prec + 1)
-                       x = Nod(t.op, x, y)
-                       t = prectab[p.tok]
-                       tprec = t.prec
-               }
+       for p.prec > prec {
+               op, prec1 := p.op, p.prec
+               p.next()
+               x = Nod(op, x, p.bexpr(prec1))
        }
        return x
 }
@@ -1162,7 +1117,7 @@ func (p *parser) expr() *Node {
                defer p.trace("expr")()
        }
 
-       return p.bexpr(1)
+       return p.bexpr(0)
 }
 
 func unparen(x *Node) *Node {
@@ -1611,13 +1566,15 @@ func (p *parser) new_name(sym *Sym) *Node {
        return nil
 }
 
-func (p *parser) dcl_name(sym *Sym) *Node {
+func (p *parser) dcl_name() *Node {
        if trace && Debug['x'] != 0 {
                defer p.trace("dcl_name")()
        }
 
+       symlineno := lineno
+       sym := p.sym()
        if sym == nil {
-               yyerrorl(int(prevlineno), "invalid declaration")
+               yyerrorl(int(symlineno), "invalid declaration")
                return nil
        }
        return dclname(sym)
@@ -1894,25 +1851,21 @@ func (p *parser) xfndcl() *Node {
        }
 
        p.want(LFUNC)
-       f := p.fndcl()
+       f := p.fndcl(p.pragma&Nointerface != 0)
        body := p.fnbody()
 
        if f == nil {
                return nil
        }
-       if noescape && body != nil {
-               Yyerror("can only use //go:noescape with external func implementations")
-       }
 
        f.Nbody = body
+       f.Noescape = p.pragma&Noescape != 0
+       if f.Noescape && body != nil {
+               Yyerror("can only use //go:noescape with external func implementations")
+       }
+       f.Func.Pragma = p.pragma
        f.Func.Endlineno = lineno
-       f.Noescape = noescape
-       f.Func.Norace = norace
-       f.Func.Nosplit = nosplit
-       f.Func.Noinline = noinline
-       f.Func.Nowritebarrier = nowritebarrier
-       f.Func.Nowritebarrierrec = nowritebarrierrec
-       f.Func.Systemstack = systemstack
+
        funcbody(f)
 
        return f
@@ -1923,7 +1876,7 @@ func (p *parser) xfndcl() *Node {
 // Function     = Signature FunctionBody .
 // MethodDecl   = "func" Receiver MethodName ( Function | Signature ) .
 // Receiver     = Parameters .
-func (p *parser) fndcl() *Node {
+func (p *parser) fndcl(nointerface bool) *Node {
        if trace && Debug['x'] != 0 {
                defer p.trace("fndcl")()
        }
@@ -2059,8 +2012,7 @@ func (p *parser) hidden_fndcl() *Node {
                ss.Type = functype(s2.N, s6, s8)
 
                checkwidth(ss.Type)
-               addmethod(s4, ss.Type, false, nointerface)
-               nointerface = false
+               addmethod(s4, ss.Type, false, false)
                funchdr(ss)
 
                // inl.C's inlnode in on a dotmeth node expects to find the inlineable body as
@@ -2141,18 +2093,10 @@ loop:
                        testdclstack()
                }
 
-               noescape = false
-               noinline = false
-               nointerface = false
-               norace = false
-               nosplit = false
-               nowritebarrier = false
-               nowritebarrierrec = false
-               systemstack = false
+               // Reset p.pragma BEFORE advancing to the next token (consuming ';')
+               // since comments before may set pragmas for the next function decl.
+               p.pragma = 0
 
-               // Consume ';' AFTER resetting the above flags since
-               // it may read the subsequent comment line which may
-               // set the flags for the next function declaration.
                if p.tok != EOF && !p.got(';') {
                        p.syntax_error("after top level declaration")
                        p.advance(LVAR, LCONST, LTYPE, LFUNC)
@@ -2567,15 +2511,15 @@ func (p *parser) stmt() *Node {
                stmt := Nod(ORETURN, nil, nil)
                stmt.List = results
                if stmt.List == nil && Curfn != nil {
-                       for l := Curfn.Func.Dcl; l != nil; l = l.Next {
-                               if l.N.Class == PPARAM {
+                       for _, ln := range Curfn.Func.Dcl {
+                               if ln.Class == PPARAM {
                                        continue
                                }
-                               if l.N.Class != PPARAMOUT {
+                               if ln.Class != PPARAMOUT {
                                        break
                                }
-                               if l.N.Sym.Def != l.N {
-                                       Yyerror("%s is shadowed during return", l.N.Sym.Name)
+                               if ln.Sym.Def != ln {
+                                       Yyerror("%s is shadowed during return", ln.Sym.Name)
                                }
                        }
                }
@@ -2639,9 +2583,9 @@ func (p *parser) dcl_name_list() *NodeList {
                defer p.trace("dcl_name_list")()
        }
 
-       l := list1(p.dcl_name(p.sym()))
+       l := list1(p.dcl_name())
        for p.got(',') {
-               l = list(l, p.dcl_name(p.sym()))
+               l = list(l, p.dcl_name())
        }
        return l
 }
index 987da2bfdd78c512a5993453c6492cda97f2185d..a8b08ab3096604e0fef3b6bf2a51ba8cbf6ba069 100644 (file)
@@ -9,6 +9,7 @@ import (
        "cmd/internal/obj"
        "crypto/md5"
        "fmt"
+       "sort"
        "strings"
 )
 
@@ -218,6 +219,13 @@ func cmpstackvarlt(a, b *Node) bool {
        return a.Sym.Name < b.Sym.Name
 }
 
+// byStackvar implements sort.Interface for []*Node using cmpstackvarlt.
+type byStackVar []*Node
+
+func (s byStackVar) Len() int           { return len(s) }
+func (s byStackVar) Less(i, j int) bool { return cmpstackvarlt(s[i], s[j]) }
+func (s byStackVar) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
+
 // stkdelta records the stack offset delta for a node
 // during the compaction of the stack frame to remove
 // unused stack slots.
@@ -228,25 +236,23 @@ func allocauto(ptxt *obj.Prog) {
        Stksize = 0
        stkptrsize = 0
 
-       if Curfn.Func.Dcl == nil {
+       if len(Curfn.Func.Dcl) == 0 {
                return
        }
 
        // Mark the PAUTO's unused.
-       for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
-               if ll.N.Class == PAUTO {
-                       ll.N.Used = false
+       for _, ln := range Curfn.Func.Dcl {
+               if ln.Class == PAUTO {
+                       ln.Used = false
                }
        }
 
        markautoused(ptxt)
 
-       listsort(&Curfn.Func.Dcl, cmpstackvarlt)
+       sort.Sort(byStackVar(Curfn.Func.Dcl))
 
        // Unused autos are at the end, chop 'em off.
-       ll := Curfn.Func.Dcl
-
-       n := ll.N
+       n := Curfn.Func.Dcl[0]
        if n.Class == PAUTO && n.Op == ONAME && !n.Used {
                // No locals used at all
                Curfn.Func.Dcl = nil
@@ -255,19 +261,17 @@ func allocauto(ptxt *obj.Prog) {
                return
        }
 
-       for ll := Curfn.Func.Dcl; ll.Next != nil; ll = ll.Next {
-               n = ll.Next.N
+       for i := 1; i < len(Curfn.Func.Dcl); i++ {
+               n = Curfn.Func.Dcl[i]
                if n.Class == PAUTO && n.Op == ONAME && !n.Used {
-                       ll.Next = nil
-                       Curfn.Func.Dcl.End = ll
+                       Curfn.Func.Dcl = Curfn.Func.Dcl[:i]
                        break
                }
        }
 
        // Reassign stack offsets of the locals that are still there.
        var w int64
-       for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
-               n = ll.N
+       for _, n := range Curfn.Func.Dcl {
                if n.Class != PAUTO || n.Op != ONAME {
                        continue
                }
@@ -299,12 +303,12 @@ func allocauto(ptxt *obj.Prog) {
        fixautoused(ptxt)
 
        // The debug information needs accurate offsets on the symbols.
-       for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
-               if ll.N.Class != PAUTO || ll.N.Op != ONAME {
+       for _, ln := range Curfn.Func.Dcl {
+               if ln.Class != PAUTO || ln.Op != ONAME {
                        continue
                }
-               ll.N.Xoffset += stkdelta[ll.N]
-               delete(stkdelta, ll.N)
+               ln.Xoffset += stkdelta[ln]
+               delete(stkdelta, ln)
        }
 }
 
@@ -442,10 +446,10 @@ func compile(fn *Node) {
        if fn.Func.Needctxt {
                ptxt.From3.Offset |= obj.NEEDCTXT
        }
-       if fn.Func.Nosplit {
+       if fn.Func.Pragma&Nosplit != 0 {
                ptxt.From3.Offset |= obj.NOSPLIT
        }
-       if fn.Func.Systemstack {
+       if fn.Func.Pragma&Systemstack != 0 {
                ptxt.From.Sym.Cfunc = 1
        }
 
@@ -467,16 +471,15 @@ func compile(fn *Node) {
                gtrack(tracksym(t))
        }
 
-       for l := fn.Func.Dcl; l != nil; l = l.Next {
-               n = l.N
+       for _, n := range fn.Func.Dcl {
                if n.Op != ONAME { // might be OTYPE or OLITERAL
                        continue
                }
                switch n.Class {
                case PAUTO, PPARAM, PPARAMOUT:
-                       Nodconst(&nod1, Types[TUINTPTR], l.N.Type.Width)
-                       p = Thearch.Gins(obj.ATYPE, l.N, &nod1)
-                       p.From.Gotype = Linksym(ngotype(l.N))
+                       Nodconst(&nod1, Types[TUINTPTR], n.Type.Width)
+                       p = Thearch.Gins(obj.ATYPE, n, &nod1)
+                       p.From.Gotype = Linksym(ngotype(n))
                }
        }
 
@@ -488,7 +491,7 @@ func compile(fn *Node) {
                ssafn.Free()
                return
        }
-       Genlist(Curfn.Func.Enter)
+       Genslice(Curfn.Func.Enter.Slice())
        Genlist(Curfn.Nbody)
        gclean()
        checklabels()
index 458497dcff40503aa44a2a39942d30ab83108fd4..78872c1af29b3378d1b8d18cafd91b8f3ec7db87 100644 (file)
@@ -122,7 +122,7 @@ func addedge(from *BasicBlock, to *BasicBlock) {
 }
 
 // Inserts prev before curr in the instruction
-// stream.  Any control flow, such as branches or fall throughs, that target the
+// stream.  Any control flow, such as branches or fall-throughs, that target the
 // existing instruction are adjusted to target the new instruction.
 func splicebefore(lv *Liveness, bb *BasicBlock, prev *obj.Prog, curr *obj.Prog) {
        // There may be other instructions pointing at curr,
@@ -198,8 +198,8 @@ func blockany(bb *BasicBlock, f func(*obj.Prog) bool) bool {
 // variables.
 func getvariables(fn *Node) []*Node {
        result := make([]*Node, 0, 0)
-       for ll := fn.Func.Dcl; ll != nil; ll = ll.Next {
-               if ll.N.Op == ONAME {
+       for _, ln := range fn.Func.Dcl {
+               if ln.Op == ONAME {
                        // In order for GODEBUG=gcdead=1 to work, each bitmap needs
                        // to contain information about all variables covered by the bitmap.
                        // For local variables, the bitmap only covers the stkptrsize
@@ -219,24 +219,24 @@ func getvariables(fn *Node) []*Node {
                        // Later, when we want to find the index of a node in the variables list,
                        // we will check that n->curfn == curfn and n->opt > 0. Then n->opt - 1
                        // is the index in the variables list.
-                       ll.N.SetOpt(nil)
+                       ln.SetOpt(nil)
 
                        // The compiler doesn't emit initializations for zero-width parameters or results.
-                       if ll.N.Type.Width == 0 {
+                       if ln.Type.Width == 0 {
                                continue
                        }
 
-                       ll.N.Name.Curfn = Curfn
-                       switch ll.N.Class {
+                       ln.Name.Curfn = Curfn
+                       switch ln.Class {
                        case PAUTO:
-                               if haspointers(ll.N.Type) {
-                                       ll.N.SetOpt(int32(len(result)))
-                                       result = append(result, ll.N)
+                               if haspointers(ln.Type) {
+                                       ln.SetOpt(int32(len(result)))
+                                       result = append(result, ln)
                                }
 
                        case PPARAM, PPARAMOUT:
-                               ll.N.SetOpt(int32(len(result)))
-                               result = append(result, ll.N)
+                               ln.SetOpt(int32(len(result)))
+                               result = append(result, ln)
                        }
                }
        }
@@ -798,8 +798,8 @@ func livenessprintcfg(lv *Liveness) {
 }
 
 func checkauto(fn *Node, p *obj.Prog, n *Node) {
-       for l := fn.Func.Dcl; l != nil; l = l.Next {
-               if l.N.Op == ONAME && l.N.Class == PAUTO && l.N == n {
+       for _, ln := range fn.Func.Dcl {
+               if ln.Op == ONAME && ln.Class == PAUTO && ln == n {
                        return
                }
        }
@@ -810,8 +810,8 @@ func checkauto(fn *Node, p *obj.Prog, n *Node) {
        }
 
        fmt.Printf("checkauto %v: %v (%p; class=%d) not found in %p %v\n", funcSym(Curfn), n, n, n.Class, p, p)
-       for l := fn.Func.Dcl; l != nil; l = l.Next {
-               fmt.Printf("\t%v (%p; class=%d)\n", l.N, l.N, l.N.Class)
+       for _, ln := range fn.Func.Dcl {
+               fmt.Printf("\t%v (%p; class=%d)\n", ln, ln, ln.Class)
        }
        Yyerror("checkauto: invariant lost")
 }
@@ -820,10 +820,8 @@ func checkparam(fn *Node, p *obj.Prog, n *Node) {
        if isfunny(n) {
                return
        }
-       var a *Node
        var class Class
-       for l := fn.Func.Dcl; l != nil; l = l.Next {
-               a = l.N
+       for _, a := range fn.Func.Dcl {
                class = a.Class &^ PHEAP
                if a.Op == ONAME && (class == PPARAM || class == PPARAMOUT) && a == n {
                        return
@@ -831,8 +829,8 @@ func checkparam(fn *Node, p *obj.Prog, n *Node) {
        }
 
        fmt.Printf("checkparam %v: %v (%p; class=%d) not found in %v\n", Curfn, n, n, n.Class, p)
-       for l := fn.Func.Dcl; l != nil; l = l.Next {
-               fmt.Printf("\t%v (%p; class=%d)\n", l.N, l.N, l.N.Class)
+       for _, ln := range fn.Func.Dcl {
+               fmt.Printf("\t%v (%p; class=%d)\n", ln, ln, ln.Class)
        }
        Yyerror("checkparam: invariant lost")
 }
@@ -1815,9 +1813,9 @@ func liveness(fn *Node, firstp *obj.Prog, argssym *Sym, livesym *Sym) {
        onebitwritesymbol(lv.argslivepointers, argssym)
 
        // Free everything.
-       for l := fn.Func.Dcl; l != nil; l = l.Next {
-               if l.N != nil {
-                       l.N.SetOpt(nil)
+       for _, ln := range fn.Func.Dcl {
+               if ln != nil {
+                       ln.SetOpt(nil)
                }
        }
        freeliveness(lv)
index b70822284557a49a31f7648a0d2e09d72048f331..0a2d8c45d41673ba24c79e0b843eeeaa99fed0d2 100644 (file)
@@ -138,15 +138,16 @@ func fixjmp(firstp *obj.Prog) {
                        fmt.Printf("%v\n", p)
                }
                if p.As != obj.ACALL && p.To.Type == obj.TYPE_BRANCH && p.To.Val.(*obj.Prog) != nil && p.To.Val.(*obj.Prog).As == obj.AJMP {
-                       p.To.Val = chasejmp(p.To.Val.(*obj.Prog), &jmploop)
-                       if Debug['R'] != 0 && Debug['v'] != 0 {
-                               fmt.Printf("->%v\n", p)
+                       if Debug['N'] == 0 {
+                               p.To.Val = chasejmp(p.To.Val.(*obj.Prog), &jmploop)
+                               if Debug['R'] != 0 && Debug['v'] != 0 {
+                                       fmt.Printf("->%v\n", p)
+                               }
                        }
                }
 
                p.Opt = dead
        }
-
        if Debug['R'] != 0 && Debug['v'] != 0 {
                fmt.Printf("\n")
        }
@@ -186,7 +187,7 @@ func fixjmp(firstp *obj.Prog) {
 
        // pass 4: elide JMP to next instruction.
        // only safe if there are no jumps to JMPs anymore.
-       if jmploop == 0 {
+       if jmploop == 0 && Debug['N'] == 0 {
                var last *obj.Prog
                for p := firstp; p != nil; p = p.Link {
                        if p.As == obj.AJMP && p.To.Type == obj.TYPE_BRANCH && p.To.Val == p.Link {
@@ -217,22 +218,22 @@ func fixjmp(firstp *obj.Prog) {
 // Control flow analysis. The Flow structures hold predecessor and successor
 // information as well as basic loop analysis.
 //
-//     graph = flowstart(firstp, 0);
+//     graph = Flowstart(firstp, nil)
 //     ... use flow graph ...
-//     flowend(graph); // free graph
+//     Flowend(graph) // free graph
 //
 // Typical uses of the flow graph are to iterate over all the flow-relevant instructions:
 //
-//     for(f = graph->start; f != nil; f = f->link)
+//     for f := graph.Start; f != nil; f = f.Link {}
 //
 // or, given an instruction f, to iterate over all the predecessors, which is
-// f->p1 and this list:
+// f.P1 and this list:
 //
-//     for(f2 = f->p2; f2 != nil; f2 = f2->p2link)
+//     for f2 := f.P2; f2 != nil; f2 = f2.P2link {}
 //
-// The size argument to flowstart specifies an amount of zeroed memory
-// to allocate in every f->data field, for use by the client.
-// If size == 0, f->data will be nil.
+// The second argument (newData) to Flowstart specifies a func to create object
+// for every f.Data field, for use by the client.
+// If newData is nil, f.Data will be nil.
 
 var flowmark int
 
@@ -471,8 +472,8 @@ func flowrpo(g *Graph) {
                me = r1.Rpo
                d = -1
 
-               // rpo2r[r->rpo] == r protects against considering dead code,
-               // which has r->rpo == 0.
+               // rpo2r[r.Rpo] == r protects against considering dead code,
+               // which has r.Rpo == 0.
                if r1.P1 != nil && rpo2r[r1.P1.Rpo] == r1.P1 && r1.P1.Rpo < me {
                        d = r1.P1.Rpo
                }
@@ -588,8 +589,8 @@ func mergetemp(firstp *obj.Prog) {
 
        // Build list of all mergeable variables.
        var vars []*TempVar
-       for l := Curfn.Func.Dcl; l != nil; l = l.Next {
-               if n := l.N; canmerge(n) {
+       for _, n := range Curfn.Func.Dcl {
+               if canmerge(n) {
                        v := &TempVar{}
                        vars = append(vars, v)
                        n.SetOpt(v)
@@ -684,7 +685,7 @@ func mergetemp(firstp *obj.Prog) {
 
        // Traverse live range of each variable to set start, end.
        // Each flood uses a new value of gen so that we don't have
-       // to clear all the r->active words after each variable.
+       // to clear all the r.Active words after each variable.
        gen := uint32(0)
 
        for _, v := range vars {
@@ -818,22 +819,15 @@ func mergetemp(firstp *obj.Prog) {
        }
 
        // Delete merged nodes from declaration list.
-       for lp := &Curfn.Func.Dcl; ; {
-               l := *lp
-               if l == nil {
-                       break
-               }
-
-               Curfn.Func.Dcl.End = l
-               n := l.N
+       dcl := make([]*Node, 0, len(Curfn.Func.Dcl)-nkill)
+       for _, n := range Curfn.Func.Dcl {
                v, _ := n.Opt().(*TempVar)
                if v != nil && (v.merge != nil || v.removed) {
-                       *lp = l.Next
                        continue
                }
-
-               lp = &l.Next
+               dcl = append(dcl, n)
        }
+       Curfn.Func.Dcl = dcl
 
        // Clear aux structures.
        for _, v := range vars {
@@ -910,7 +904,7 @@ func varkillwalk(v *TempVar, f0 *Flow, gen uint32) {
 // from memory without being rechecked. Other variables need to be checked on
 // each load.
 
-var killed int // f->data is either nil or &killed
+var killed int // f.Data is either nil or &killed
 
 func nilopt(firstp *obj.Prog) {
        g := Flowstart(firstp, nil)
index ee4f3baffdf902c9e07753f84116a260c62ce978..e1b3ae68793e70dc4738ac16353bd17c9d8ac71a 100644 (file)
@@ -50,7 +50,7 @@ func ispkgin(pkgs []string) bool {
 }
 
 func instrument(fn *Node) {
-       if ispkgin(omit_pkgs) || fn.Func.Norace {
+       if ispkgin(omit_pkgs) || fn.Func.Pragma&Norace != 0 {
                return
        }
 
@@ -58,7 +58,7 @@ func instrument(fn *Node) {
                instrumentlist(fn.Nbody, nil)
 
                // nothing interesting for race detector in fn->enter
-               instrumentlist(fn.Func.Exit, nil)
+               instrumentslice(fn.Func.Exit.Slice(), nil)
        }
 
        if flag_race != 0 {
@@ -71,18 +71,18 @@ func instrument(fn *Node) {
                nodpc.Type = Types[TUINTPTR]
                nodpc.Xoffset = int64(-Widthptr)
                nd := mkcall("racefuncenter", nil, nil, nodpc)
-               fn.Func.Enter = concat(list1(nd), fn.Func.Enter)
+               fn.Func.Enter.Set(append([]*Node{nd}, fn.Func.Enter.Slice()...))
                nd = mkcall("racefuncexit", nil, nil)
-               fn.Func.Exit = list(fn.Func.Exit, nd)
+               fn.Func.Exit.Append(nd)
        }
 
        if Debug['W'] != 0 {
                s := fmt.Sprintf("after instrument %v", fn.Func.Nname.Sym)
                dumplist(s, fn.Nbody)
                s = fmt.Sprintf("enter %v", fn.Func.Nname.Sym)
-               dumplist(s, fn.Func.Enter)
+               dumpslice(s, fn.Func.Enter.Slice())
                s = fmt.Sprintf("exit %v", fn.Func.Nname.Sym)
-               dumplist(s, fn.Func.Exit)
+               dumpslice(s, fn.Func.Exit.Slice())
        }
 }
 
@@ -100,6 +100,18 @@ func instrumentlist(l *NodeList, init **NodeList) {
        }
 }
 
+func instrumentslice(l []*Node, init **NodeList) {
+       for i := range l {
+               var instr *NodeList
+               instrumentnode(&l[i], &instr, 0, 0)
+               if init == nil {
+                       l[i].Ninit = concat(l[i].Ninit, instr)
+               } else {
+                       *init = concat(*init, instr)
+               }
+       }
+}
+
 // walkexpr and walkstmt combined
 // walks the tree and adds calls to the
 // instrumentation code to top-level (statement) nodes' init
index 37c3bc9e6d1dbcc3beb7f27b1776fed0c7a18bce..43c6db0a00fe576fa06eccb59dfe1a6b06b13203 100644 (file)
@@ -491,16 +491,10 @@ func dextratype(sym *Sym, off int, t *Type, ptroff int) int {
 
        ot := off
        s := sym
-       if t.Sym != nil {
-               ot = dgostringptr(s, ot, t.Sym.Name)
-               if t != Types[t.Etype] && t != errortype {
-                       ot = dgopkgpath(s, ot, t.Sym.Pkg)
-               } else {
-                       ot = dgostringptr(s, ot, "")
-               }
+       if t.Sym != nil && t != Types[t.Etype] && t != errortype {
+               ot = dgopkgpath(s, ot, t.Sym.Pkg)
        } else {
                ot = dgostringptr(s, ot, "")
-               ot = dgostringptr(s, ot, "")
        }
 
        // slice header
@@ -700,12 +694,14 @@ func dcommontype(s *Sym, ot int, t *Type) int {
                algsym = dalgsym(t)
        }
 
-       var sptr *Sym
        tptr := Ptrto(t)
        if !Isptr[t.Etype] && (t.Sym != nil || methods(tptr) != nil) {
-               sptr = dtypesym(tptr)
-       } else {
-               sptr = weaktypesym(tptr)
+               sptr := dtypesym(tptr)
+               r := obj.Addrel(Linksym(s))
+               r.Off = 0
+               r.Siz = 0
+               r.Sym = sptr.Lsym
+               r.Type = obj.R_USETYPE
        }
 
        gcsym, useGCProg, ptrdata := dgcsym(t)
@@ -724,7 +720,6 @@ func dcommontype(s *Sym, ot int, t *Type) int {
        //              gcdata        *byte
        //              string        *string
        //              *uncommonType
-       //              ptrToThis     *rtype
        //      }
        ot = duintptr(s, ot, uint64(t.Width))
        ot = duintptr(s, ot, uint64(ptrdata))
@@ -763,12 +758,14 @@ func dcommontype(s *Sym, ot int, t *Type) int {
        } else {
                ot = dsymptr(s, ot, algsym, 0)
        }
-       ot = dsymptr(s, ot, gcsym, 0)
+       ot = dsymptr(s, ot, gcsym, 0) // gcdata
 
        p := Tconv(t, obj.FmtLeft|obj.FmtUnsigned)
 
-       //print("dcommontype: %s\n", p);
-       ot = dgostringptr(s, ot, p) // string
+       _, symdata := stringsym(p) // string
+       ot = dsymptr(s, ot, symdata, 0)
+       ot = duintxx(s, ot, uint64(len(p)), Widthint)
+       //fmt.Printf("dcommontype: %s\n", p)
 
        // skip pointer to extraType,
        // which follows the rest of this type structure.
@@ -776,7 +773,6 @@ func dcommontype(s *Sym, ot int, t *Type) int {
        // otherwise linker will assume 0.
        ot += Widthptr
 
-       ot = dsymptr(s, ot, sptr, 0) // ptrto type
        return ot
 }
 
@@ -1006,7 +1002,7 @@ ok:
        switch t.Etype {
        default:
                ot = dcommontype(s, ot, t)
-               xt = ot - 2*Widthptr
+               xt = ot - 1*Widthptr
 
        case TARRAY:
                if t.Bound >= 0 {
@@ -1018,7 +1014,7 @@ ok:
                        t2.Bound = -1 // slice
                        s2 := dtypesym(t2)
                        ot = dcommontype(s, ot, t)
-                       xt = ot - 2*Widthptr
+                       xt = ot - 1*Widthptr
                        ot = dsymptr(s, ot, s1, 0)
                        ot = dsymptr(s, ot, s2, 0)
                        ot = duintptr(s, ot, uint64(t.Bound))
@@ -1027,7 +1023,7 @@ ok:
                        s1 := dtypesym(t.Type)
 
                        ot = dcommontype(s, ot, t)
-                       xt = ot - 2*Widthptr
+                       xt = ot - 1*Widthptr
                        ot = dsymptr(s, ot, s1, 0)
                }
 
@@ -1036,7 +1032,7 @@ ok:
                s1 := dtypesym(t.Type)
 
                ot = dcommontype(s, ot, t)
-               xt = ot - 2*Widthptr
+               xt = ot - 1*Widthptr
                ot = dsymptr(s, ot, s1, 0)
                ot = duintptr(s, ot, uint64(t.Chan))
 
@@ -1055,7 +1051,7 @@ ok:
                }
 
                ot = dcommontype(s, ot, t)
-               xt = ot - 2*Widthptr
+               xt = ot - 1*Widthptr
                ot = duint8(s, ot, uint8(obj.Bool2int(isddd)))
 
                // two slice headers: in and out.
@@ -1093,7 +1089,7 @@ ok:
                // ../../../../runtime/type.go:/interfaceType
                ot = dcommontype(s, ot, t)
 
-               xt = ot - 2*Widthptr
+               xt = ot - 1*Widthptr
                ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint)
                ot = duintxx(s, ot, uint64(n), Widthint)
                ot = duintxx(s, ot, uint64(n), Widthint)
@@ -1113,7 +1109,7 @@ ok:
                s3 := dtypesym(mapbucket(t))
                s4 := dtypesym(hmap(t))
                ot = dcommontype(s, ot, t)
-               xt = ot - 2*Widthptr
+               xt = ot - 1*Widthptr
                ot = dsymptr(s, ot, s1, 0)
                ot = dsymptr(s, ot, s2, 0)
                ot = dsymptr(s, ot, s3, 0)
@@ -1150,7 +1146,7 @@ ok:
                s1 := dtypesym(t.Type)
 
                ot = dcommontype(s, ot, t)
-               xt = ot - 2*Widthptr
+               xt = ot - 1*Widthptr
                ot = dsymptr(s, ot, s1, 0)
 
        // ../../../../runtime/type.go:/structType
@@ -1164,7 +1160,7 @@ ok:
                }
 
                ot = dcommontype(s, ot, t)
-               xt = ot - 2*Widthptr
+               xt = ot - 1*Widthptr
                ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint)
                ot = duintxx(s, ot, uint64(n), Widthint)
                ot = duintxx(s, ot, uint64(n), Widthint)
@@ -1203,21 +1199,7 @@ ok:
        // we want be able to find.
        if t.Sym == nil {
                switch t.Etype {
-               case TPTR32, TPTR64:
-                       // The ptrto field of the type data cannot be relied on when
-                       // dynamic linking: a type T may be defined in a module that makes
-                       // no use of pointers to that type, but another module can contain
-                       // a package that imports the first one and does use *T pointers.
-                       // The second module will end up defining type data for *T and a
-                       // type.*T symbol pointing at it. It's important that calling
-                       // .PtrTo() on the reflect.Type for T returns this type data and
-                       // not some synthesized object, so we need reflect to be able to
-                       // find it!
-                       if !Ctxt.Flag_dynlink {
-                               break
-                       }
-                       fallthrough
-               case TARRAY, TCHAN, TFUNC, TMAP:
+               case TPTR32, TPTR64, TARRAY, TCHAN, TFUNC, TMAP:
                        slink := typelinksym(t)
                        dsymptr(slink, 0, s, 0)
                        ggloblsym(slink, int32(Widthptr), int16(dupok|obj.RODATA))
@@ -1377,7 +1359,7 @@ func dalgsym(t *Type) *Sym {
 // be multiples of four words. On 32-bit systems that's 16 bytes, and
 // all size classes >= 16 bytes are 16-byte aligned, so no real constraint.
 // On 64-bit systems, that's 32 bytes, and 32-byte alignment is guaranteed
-// for size classes >= 256 bytes. On a 64-bit sytem, 256 bytes allocated
+// for size classes >= 256 bytes. On a 64-bit system, 256 bytes allocated
 // is 32 pointers, the bits for which fit in 4 bytes. So maxPtrmaskBytes
 // must be >= 4.
 //
index 8af6ba24a231baeb6c6833b9768d833e51c41278..07177812f656fcead1a3e7db864710eae43a04c0 100644 (file)
@@ -475,7 +475,7 @@ func staticassign(l *Node, r *Node, out **NodeList) bool {
                break
 
        case OCLOSURE:
-               if r.Func.Cvars == nil {
+               if len(r.Func.Cvars.Slice()) == 0 {
                        // Closures with no captured variables are globals,
                        // so the assignment can be done at link time.
                        n := *l
index e81ca14571cf6df4569cda048c7f08f1435ea376..4399470471947fac9839a6c0b55251750f4caa26 100644 (file)
@@ -84,9 +84,9 @@ func buildssa(fn *Node) *ssa.Func {
        printssa := strings.HasSuffix(name, "_ssa") || strings.Contains(name, "_ssa.") || name == os.Getenv("GOSSAFUNC")
        if printssa {
                fmt.Println("generating SSA for", name)
-               dumplist("buildssa-enter", fn.Func.Enter)
+               dumpslice("buildssa-enter", fn.Func.Enter.Slice())
                dumplist("buildssa-body", fn.Nbody)
-               dumplist("buildssa-exit", fn.Func.Exit)
+               dumpslice("buildssa-exit", fn.Func.Exit.Slice())
        }
 
        var s state
@@ -132,8 +132,7 @@ func buildssa(fn *Node) *ssa.Func {
 
        // Generate addresses of local declarations
        s.decladdrs = map[*Node]*ssa.Value{}
-       for d := fn.Func.Dcl; d != nil; d = d.Next {
-               n := d.N
+       for _, n := range fn.Func.Dcl {
                switch n.Class {
                case PPARAM:
                        aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
@@ -159,12 +158,12 @@ func buildssa(fn *Node) *ssa.Func {
        }
 
        // Convert the AST-based IR to the SSA-based IR
-       s.stmtList(fn.Func.Enter)
+       s.stmts(fn.Func.Enter)
        s.stmtList(fn.Nbody)
 
        // fallthrough to exit
        if s.curBlock != nil {
-               s.stmtList(s.exitCode)
+               s.stmts(s.exitCode)
                m := s.mem()
                b := s.endBlock()
                b.Kind = ssa.BlockRet
@@ -201,7 +200,7 @@ func buildssa(fn *Node) *ssa.Func {
        s.linkForwardReferences()
 
        // Don't carry reference this around longer than necessary
-       s.exitCode = nil
+       s.exitCode = Nodes{}
 
        // Main call to ssa package to compile function
        ssa.Compile(s.f)
@@ -224,7 +223,7 @@ type state struct {
        fwdGotos []*Node
        // Code that must precede any return
        // (e.g., copying value of heap-escaped paramout back to true paramout)
-       exitCode *NodeList
+       exitCode Nodes
 
        // unlabeled break and continue statement tracking
        breakTo    *ssa.Block // current target for plain break statement
@@ -479,6 +478,12 @@ func (s *state) constInt(t ssa.Type, c int64) *ssa.Value {
        return s.constInt32(t, int32(c))
 }
 
+func (s *state) stmts(a Nodes) {
+       for _, x := range a.Slice() {
+               s.stmt(x)
+       }
+}
+
 // ssaStmtList converts the statement n to SSA and adds it to s.
 func (s *state) stmtList(l *NodeList) {
        for ; l != nil; l = l.Next {
@@ -697,14 +702,14 @@ func (s *state) stmt(n *Node) {
 
        case ORETURN:
                s.stmtList(n.List)
-               s.stmtList(s.exitCode)
+               s.stmts(s.exitCode)
                m := s.mem()
                b := s.endBlock()
                b.Kind = ssa.BlockRet
                b.Control = m
        case ORETJMP:
                s.stmtList(n.List)
-               s.stmtList(s.exitCode)
+               s.stmts(s.exitCode)
                m := s.mem()
                b := s.endBlock()
                b.Kind = ssa.BlockRetJmp
index b6a26489e61352533c41d402f91c211dda00dd9f..6c558203d3d34f1c453753df10a5bdd38df20f95 100644 (file)
@@ -19,7 +19,6 @@ import (
 
 type Error struct {
        lineno int
-       seq    int
        msg    string
 }
 
@@ -49,35 +48,24 @@ func adderrorname(n *Node) {
 
 func adderr(line int, format string, args ...interface{}) {
        errors = append(errors, Error{
-               seq:    len(errors),
                lineno: line,
                msg:    fmt.Sprintf("%v: %s\n", Ctxt.Line(line), fmt.Sprintf(format, args...)),
        })
 }
 
-// errcmp sorts errors by line, then seq, then message.
-type errcmp []Error
+// byLineno sorts errors by lineno.
+type byLineno []Error
 
-func (x errcmp) Len() int      { return len(x) }
-func (x errcmp) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
-func (x errcmp) Less(i, j int) bool {
-       a := &x[i]
-       b := &x[j]
-       if a.lineno != b.lineno {
-               return a.lineno < b.lineno
-       }
-       if a.seq != b.seq {
-               return a.seq < b.seq
-       }
-       return a.msg < b.msg
-}
+func (x byLineno) Len() int           { return len(x) }
+func (x byLineno) Less(i, j int) bool { return x[i].lineno < x[j].lineno }
+func (x byLineno) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
 
 func Flusherrors() {
        bstdout.Flush()
        if len(errors) == 0 {
                return
        }
-       sort.Sort(errcmp(errors))
+       sort.Stable(byLineno(errors))
        for i := 0; i < len(errors); i++ {
                if i == 0 || errors[i].msg != errors[i-1].msg {
                        fmt.Printf("%s", errors[i].msg)
@@ -109,7 +97,7 @@ func yyerrorl(line int, format string, args ...interface{}) {
        }
 }
 
-var yyerror_lastsyntax int
+var yyerror_lastsyntax int32
 
 func Yyerror(format string, args ...interface{}) {
        msg := fmt.Sprintf(format, args...)
@@ -117,18 +105,12 @@ func Yyerror(format string, args ...interface{}) {
                nsyntaxerrors++
 
                // only one syntax error per line
-               if int32(yyerror_lastsyntax) == lexlineno {
+               if yyerror_lastsyntax == lineno {
                        return
                }
-               yyerror_lastsyntax = int(lexlineno)
+               yyerror_lastsyntax = lineno
 
-               // plain "syntax error" gets "near foo" added
-               if msg == "syntax error" {
-                       yyerrorl(int(lexlineno), "syntax error near %s", lexbuf.String())
-                       return
-               }
-
-               yyerrorl(int(lexlineno), "%s", msg)
+               yyerrorl(int(lineno), "%s", msg)
                return
        }
 
@@ -256,9 +238,8 @@ func (pkg *Pkg) Lookup(name string) *Sym {
        }
 
        s := &Sym{
-               Name:    name,
-               Pkg:     pkg,
-               Lexical: LNAME,
+               Name: name,
+               Pkg:  pkg,
        }
        if name == "init" {
                initSyms = append(initSyms, s)
@@ -367,162 +348,6 @@ func saveorignode(n *Node) {
        n.Orig = norig
 }
 
-// ispaddedfield reports whether the given field
-// is followed by padding. For the case where t is
-// the last field, total gives the size of the enclosing struct.
-func ispaddedfield(t *Type, total int64) bool {
-       if t.Etype != TFIELD {
-               Fatalf("ispaddedfield called non-field %v", t)
-       }
-       if t.Down == nil {
-               return t.Width+t.Type.Width != total
-       }
-       return t.Width+t.Type.Width != t.Down.Width
-}
-
-func algtype1(t *Type, bad **Type) int {
-       if bad != nil {
-               *bad = nil
-       }
-       if t.Broke {
-               return AMEM
-       }
-       if t.Noalg {
-               return ANOEQ
-       }
-
-       switch t.Etype {
-       // will be defined later.
-       case TANY, TFORW:
-               *bad = t
-
-               return -1
-
-       case TINT8,
-               TUINT8,
-               TINT16,
-               TUINT16,
-               TINT32,
-               TUINT32,
-               TINT64,
-               TUINT64,
-               TINT,
-               TUINT,
-               TUINTPTR,
-               TBOOL,
-               TPTR32,
-               TPTR64,
-               TCHAN,
-               TUNSAFEPTR:
-               return AMEM
-
-       case TFUNC, TMAP:
-               if bad != nil {
-                       *bad = t
-               }
-               return ANOEQ
-
-       case TFLOAT32:
-               return AFLOAT32
-
-       case TFLOAT64:
-               return AFLOAT64
-
-       case TCOMPLEX64:
-               return ACPLX64
-
-       case TCOMPLEX128:
-               return ACPLX128
-
-       case TSTRING:
-               return ASTRING
-
-       case TINTER:
-               if isnilinter(t) {
-                       return ANILINTER
-               }
-               return AINTER
-
-       case TARRAY:
-               if Isslice(t) {
-                       if bad != nil {
-                               *bad = t
-                       }
-                       return ANOEQ
-               }
-
-               a := algtype1(t.Type, bad)
-               if a == ANOEQ || a == AMEM {
-                       if a == ANOEQ && bad != nil {
-                               *bad = t
-                       }
-                       return a
-               }
-
-               switch t.Bound {
-               case 0:
-                       // We checked above that the element type is comparable.
-                       return AMEM
-               case 1:
-                       // Single-element array is same as its lone element.
-                       return a
-               }
-
-               return -1 // needs special compare
-
-       case TSTRUCT:
-               if t.Type != nil && t.Type.Down == nil && !isblanksym(t.Type.Sym) {
-                       // One-field struct is same as that one field alone.
-                       return algtype1(t.Type.Type, bad)
-               }
-
-               ret := AMEM
-               var a int
-               for t1 := t.Type; t1 != nil; t1 = t1.Down {
-                       // All fields must be comparable.
-                       a = algtype1(t1.Type, bad)
-
-                       if a == ANOEQ {
-                               return ANOEQ
-                       }
-
-                       // Blank fields, padded fields, fields with non-memory
-                       // equality need special compare.
-                       if a != AMEM || isblanksym(t1.Sym) || ispaddedfield(t1, t.Width) {
-                               ret = -1
-                               continue
-                       }
-               }
-
-               return ret
-       }
-
-       Fatalf("algtype1: unexpected type %v", t)
-       return 0
-}
-
-func algtype(t *Type) int {
-       a := algtype1(t, nil)
-       if a == AMEM {
-               switch t.Width {
-               case 0:
-                       return AMEM0
-               case 1:
-                       return AMEM8
-               case 2:
-                       return AMEM16
-               case 4:
-                       return AMEM32
-               case 8:
-                       return AMEM64
-               case 16:
-                       return AMEM128
-               }
-       }
-
-       return a
-}
-
 func maptype(key *Type, val *Type) *Type {
        if key != nil {
                var bad *Type
@@ -1561,8 +1386,8 @@ func frame(context int) {
 
        if Curfn != nil {
                fmt.Printf("--- %v frame ---\n", Curfn.Func.Nname.Sym)
-               for l := Curfn.Func.Dcl; l != nil; l = l.Next {
-                       printframenode(l.N)
+               for _, ln := range Curfn.Func.Dcl {
+                       printframenode(ln)
                }
        }
 }
@@ -2414,457 +2239,6 @@ func hashmem(t *Type) *Node {
        return n
 }
 
-func hashfor(t *Type) *Node {
-       var sym *Sym
-
-       a := algtype1(t, nil)
-       switch a {
-       case AMEM:
-               Fatalf("hashfor with AMEM type")
-
-       case AINTER:
-               sym = Pkglookup("interhash", Runtimepkg)
-
-       case ANILINTER:
-               sym = Pkglookup("nilinterhash", Runtimepkg)
-
-       case ASTRING:
-               sym = Pkglookup("strhash", Runtimepkg)
-
-       case AFLOAT32:
-               sym = Pkglookup("f32hash", Runtimepkg)
-
-       case AFLOAT64:
-               sym = Pkglookup("f64hash", Runtimepkg)
-
-       case ACPLX64:
-               sym = Pkglookup("c64hash", Runtimepkg)
-
-       case ACPLX128:
-               sym = Pkglookup("c128hash", Runtimepkg)
-
-       default:
-               sym = typesymprefix(".hash", t)
-       }
-
-       n := newname(sym)
-       n.Class = PFUNC
-       tfn := Nod(OTFUNC, nil, nil)
-       tfn.List = list(tfn.List, Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
-       tfn.List = list(tfn.List, Nod(ODCLFIELD, nil, typenod(Types[TUINTPTR])))
-       tfn.Rlist = list(tfn.Rlist, Nod(ODCLFIELD, nil, typenod(Types[TUINTPTR])))
-       typecheck(&tfn, Etype)
-       n.Type = tfn.Type
-       return n
-}
-
-// Generate a helper function to compute the hash of a value of type t.
-func genhash(sym *Sym, t *Type) {
-       if Debug['r'] != 0 {
-               fmt.Printf("genhash %v %v\n", sym, t)
-       }
-
-       lineno = 1 // less confusing than end of input
-       dclcontext = PEXTERN
-       markdcl()
-
-       // func sym(p *T, h uintptr) uintptr
-       fn := Nod(ODCLFUNC, nil, nil)
-
-       fn.Func.Nname = newname(sym)
-       fn.Func.Nname.Class = PFUNC
-       tfn := Nod(OTFUNC, nil, nil)
-       fn.Func.Nname.Name.Param.Ntype = tfn
-
-       n := Nod(ODCLFIELD, newname(Lookup("p")), typenod(Ptrto(t)))
-       tfn.List = list(tfn.List, n)
-       np := n.Left
-       n = Nod(ODCLFIELD, newname(Lookup("h")), typenod(Types[TUINTPTR]))
-       tfn.List = list(tfn.List, n)
-       nh := n.Left
-       n = Nod(ODCLFIELD, nil, typenod(Types[TUINTPTR])) // return value
-       tfn.Rlist = list(tfn.Rlist, n)
-
-       funchdr(fn)
-       typecheck(&fn.Func.Nname.Name.Param.Ntype, Etype)
-
-       // genhash is only called for types that have equality but
-       // cannot be handled by the standard algorithms,
-       // so t must be either an array or a struct.
-       switch t.Etype {
-       default:
-               Fatalf("genhash %v", t)
-
-       case TARRAY:
-               if Isslice(t) {
-                       Fatalf("genhash %v", t)
-               }
-
-               // An array of pure memory would be handled by the
-               // standard algorithm, so the element type must not be
-               // pure memory.
-               hashel := hashfor(t.Type)
-
-               n := Nod(ORANGE, nil, Nod(OIND, np, nil))
-               ni := newname(Lookup("i"))
-               ni.Type = Types[TINT]
-               n.List = list1(ni)
-               n.Colas = true
-               colasdefn(n.List, n)
-               ni = n.List.N
-
-               // h = hashel(&p[i], h)
-               call := Nod(OCALL, hashel, nil)
-
-               nx := Nod(OINDEX, np, ni)
-               nx.Bounded = true
-               na := Nod(OADDR, nx, nil)
-               na.Etype = 1 // no escape to heap
-               call.List = list(call.List, na)
-               call.List = list(call.List, nh)
-               n.Nbody = list(n.Nbody, Nod(OAS, nh, call))
-
-               fn.Nbody = list(fn.Nbody, n)
-
-               // Walk the struct using memhash for runs of AMEM
-       // and calling specific hash functions for the others.
-       case TSTRUCT:
-               var first *Type
-
-               offend := int64(0)
-               var size int64
-               var call *Node
-               var nx *Node
-               var na *Node
-               var hashel *Node
-               for t1 := t.Type; ; t1 = t1.Down {
-                       if t1 != nil && algtype1(t1.Type, nil) == AMEM && !isblanksym(t1.Sym) {
-                               offend = t1.Width + t1.Type.Width
-                               if first == nil {
-                                       first = t1
-                               }
-
-                               // If it's a memory field but it's padded, stop here.
-                               if ispaddedfield(t1, t.Width) {
-                                       t1 = t1.Down
-                               } else {
-                                       continue
-                               }
-                       }
-
-                       // Run memhash for fields up to this one.
-                       if first != nil {
-                               size = offend - first.Width // first->width is offset
-                               hashel = hashmem(first.Type)
-
-                               // h = hashel(&p.first, size, h)
-                               call = Nod(OCALL, hashel, nil)
-
-                               nx = Nod(OXDOT, np, newname(first.Sym)) // TODO: fields from other packages?
-                               na = Nod(OADDR, nx, nil)
-                               na.Etype = 1 // no escape to heap
-                               call.List = list(call.List, na)
-                               call.List = list(call.List, nh)
-                               call.List = list(call.List, Nodintconst(size))
-                               fn.Nbody = list(fn.Nbody, Nod(OAS, nh, call))
-
-                               first = nil
-                       }
-
-                       if t1 == nil {
-                               break
-                       }
-                       if isblanksym(t1.Sym) {
-                               continue
-                       }
-
-                       // Run hash for this field.
-                       if algtype1(t1.Type, nil) == AMEM {
-                               hashel = hashmem(t1.Type)
-
-                               // h = memhash(&p.t1, h, size)
-                               call = Nod(OCALL, hashel, nil)
-
-                               nx = Nod(OXDOT, np, newname(t1.Sym)) // TODO: fields from other packages?
-                               na = Nod(OADDR, nx, nil)
-                               na.Etype = 1 // no escape to heap
-                               call.List = list(call.List, na)
-                               call.List = list(call.List, nh)
-                               call.List = list(call.List, Nodintconst(t1.Type.Width))
-                               fn.Nbody = list(fn.Nbody, Nod(OAS, nh, call))
-                       } else {
-                               hashel = hashfor(t1.Type)
-
-                               // h = hashel(&p.t1, h)
-                               call = Nod(OCALL, hashel, nil)
-
-                               nx = Nod(OXDOT, np, newname(t1.Sym)) // TODO: fields from other packages?
-                               na = Nod(OADDR, nx, nil)
-                               na.Etype = 1 // no escape to heap
-                               call.List = list(call.List, na)
-                               call.List = list(call.List, nh)
-                               fn.Nbody = list(fn.Nbody, Nod(OAS, nh, call))
-                       }
-               }
-       }
-
-       r := Nod(ORETURN, nil, nil)
-       r.List = list(r.List, nh)
-       fn.Nbody = list(fn.Nbody, r)
-
-       if Debug['r'] != 0 {
-               dumplist("genhash body", fn.Nbody)
-       }
-
-       funcbody(fn)
-       Curfn = fn
-       fn.Func.Dupok = true
-       typecheck(&fn, Etop)
-       typechecklist(fn.Nbody, Etop)
-       Curfn = nil
-
-       // Disable safemode while compiling this code: the code we
-       // generate internally can refer to unsafe.Pointer.
-       // In this case it can happen if we need to generate an ==
-       // for a struct containing a reflect.Value, which itself has
-       // an unexported field of type unsafe.Pointer.
-       old_safemode := safemode
-
-       safemode = 0
-       funccompile(fn)
-       safemode = old_safemode
-}
-
-// eqfield returns the node
-//     p.field == q.field
-func eqfield(p *Node, q *Node, field *Node) *Node {
-       nx := Nod(OXDOT, p, field)
-       ny := Nod(OXDOT, q, field)
-       ne := Nod(OEQ, nx, ny)
-       return ne
-}
-
-func eqmemfunc(size int64, type_ *Type, needsize *int) *Node {
-       var fn *Node
-
-       switch size {
-       default:
-               fn = syslook("memequal", 1)
-               *needsize = 1
-
-       case 1, 2, 4, 8, 16:
-               buf := fmt.Sprintf("memequal%d", int(size)*8)
-               fn = syslook(buf, 1)
-               *needsize = 0
-       }
-
-       substArgTypes(fn, type_, type_)
-       return fn
-}
-
-// eqmem returns the node
-//     memequal(&p.field, &q.field [, size])
-func eqmem(p *Node, q *Node, field *Node, size int64) *Node {
-       var needsize int
-
-       nx := Nod(OADDR, Nod(OXDOT, p, field), nil)
-       nx.Etype = 1 // does not escape
-       ny := Nod(OADDR, Nod(OXDOT, q, field), nil)
-       ny.Etype = 1 // does not escape
-       typecheck(&nx, Erv)
-       typecheck(&ny, Erv)
-
-       call := Nod(OCALL, eqmemfunc(size, nx.Type.Type, &needsize), nil)
-       call.List = list(call.List, nx)
-       call.List = list(call.List, ny)
-       if needsize != 0 {
-               call.List = list(call.List, Nodintconst(size))
-       }
-
-       return call
-}
-
-// geneq generates a helper function to
-// check equality of two values of type t.
-func geneq(sym *Sym, t *Type) {
-       if Debug['r'] != 0 {
-               fmt.Printf("geneq %v %v\n", sym, t)
-       }
-
-       lineno = 1 // less confusing than end of input
-       dclcontext = PEXTERN
-       markdcl()
-
-       // func sym(p, q *T) bool
-       fn := Nod(ODCLFUNC, nil, nil)
-
-       fn.Func.Nname = newname(sym)
-       fn.Func.Nname.Class = PFUNC
-       tfn := Nod(OTFUNC, nil, nil)
-       fn.Func.Nname.Name.Param.Ntype = tfn
-
-       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, nil, typenod(Types[TBOOL]))
-       tfn.Rlist = list(tfn.Rlist, n)
-
-       funchdr(fn)
-
-       // geneq is only called for types that have equality but
-       // cannot be handled by the standard algorithms,
-       // so t must be either an array or a struct.
-       switch t.Etype {
-       default:
-               Fatalf("geneq %v", t)
-
-       case TARRAY:
-               if Isslice(t) {
-                       Fatalf("geneq %v", t)
-               }
-
-               // An array of pure memory would be handled by the
-               // standard memequal, so the element type must not be
-               // pure memory.  Even if we unrolled the range loop,
-               // each iteration would be a function call, so don't bother
-               // unrolling.
-               nrange := Nod(ORANGE, nil, Nod(OIND, np, nil))
-
-               ni := newname(Lookup("i"))
-               ni.Type = Types[TINT]
-               nrange.List = list1(ni)
-               nrange.Colas = true
-               colasdefn(nrange.List, nrange)
-               ni = nrange.List.N
-
-               // if p[i] != q[i] { return false }
-               nx := Nod(OINDEX, np, ni)
-
-               nx.Bounded = true
-               ny := Nod(OINDEX, nq, ni)
-               ny.Bounded = true
-
-               nif := Nod(OIF, nil, nil)
-               nif.Left = Nod(ONE, nx, ny)
-               r := Nod(ORETURN, nil, nil)
-               r.List = list(r.List, Nodbool(false))
-               nif.Nbody = list(nif.Nbody, r)
-               nrange.Nbody = list(nrange.Nbody, nif)
-               fn.Nbody = list(fn.Nbody, nrange)
-
-               // return true
-               ret := Nod(ORETURN, nil, nil)
-               ret.List = list(ret.List, Nodbool(true))
-               fn.Nbody = list(fn.Nbody, ret)
-
-       // Walk the struct using memequal for runs of AMEM
-       // and calling specific equality tests for the others.
-       // Skip blank-named fields.
-       case TSTRUCT:
-               var first *Type
-
-               var conjuncts []*Node
-               offend := int64(0)
-               var size int64
-               for t1 := t.Type; ; t1 = t1.Down {
-                       if t1 != nil && algtype1(t1.Type, nil) == AMEM && !isblanksym(t1.Sym) {
-                               offend = t1.Width + t1.Type.Width
-                               if first == nil {
-                                       first = t1
-                               }
-
-                               // If it's a memory field but it's padded, stop here.
-                               if ispaddedfield(t1, t.Width) {
-                                       t1 = t1.Down
-                               } else {
-                                       continue
-                               }
-                       }
-
-                       // Run memequal for fields up to this one.
-                       // TODO(rsc): All the calls to newname are wrong for
-                       // cross-package unexported fields.
-                       if first != nil {
-                               if first.Down == t1 {
-                                       conjuncts = append(conjuncts, eqfield(np, nq, newname(first.Sym)))
-                               } else if first.Down.Down == t1 {
-                                       conjuncts = append(conjuncts, eqfield(np, nq, newname(first.Sym)))
-                                       first = first.Down
-                                       if !isblanksym(first.Sym) {
-                                               conjuncts = append(conjuncts, eqfield(np, nq, newname(first.Sym)))
-                                       }
-                               } else {
-                                       // More than two fields: use memequal.
-                                       size = offend - first.Width // first->width is offset
-                                       conjuncts = append(conjuncts, eqmem(np, nq, newname(first.Sym), size))
-                               }
-
-                               first = nil
-                       }
-
-                       if t1 == nil {
-                               break
-                       }
-                       if isblanksym(t1.Sym) {
-                               continue
-                       }
-
-                       // Check this field, which is not just memory.
-                       conjuncts = append(conjuncts, eqfield(np, nq, newname(t1.Sym)))
-               }
-
-               var and *Node
-               switch len(conjuncts) {
-               case 0:
-                       and = Nodbool(true)
-               case 1:
-                       and = conjuncts[0]
-               default:
-                       and = Nod(OANDAND, conjuncts[0], conjuncts[1])
-                       for _, conjunct := range conjuncts[2:] {
-                               and = Nod(OANDAND, and, conjunct)
-                       }
-               }
-
-               ret := Nod(ORETURN, nil, nil)
-               ret.List = list(ret.List, and)
-               fn.Nbody = list(fn.Nbody, ret)
-       }
-
-       if Debug['r'] != 0 {
-               dumplist("geneq body", fn.Nbody)
-       }
-
-       funcbody(fn)
-       Curfn = fn
-       fn.Func.Dupok = true
-       typecheck(&fn, Etop)
-       typechecklist(fn.Nbody, Etop)
-       Curfn = nil
-
-       // Disable safemode while compiling this code: the code we
-       // generate internally can refer to unsafe.Pointer.
-       // In this case it can happen if we need to generate an ==
-       // for a struct containing a reflect.Value, which itself has
-       // an unexported field of type unsafe.Pointer.
-       old_safemode := safemode
-       safemode = 0
-
-       // Disable checknils while compiling this code.
-       // We are comparing a struct or an array,
-       // neither of which can be nil, and our comparisons
-       // are shallow.
-       Disable_checknil++
-
-       funccompile(fn)
-
-       safemode = old_safemode
-       Disable_checknil--
-}
-
 func ifacelookdot(s *Sym, t *Type, followptr *bool, ignorecase int) *Type {
        *followptr = false
 
index b97cb3f80723abf25386cc611652711454bfe247..ec91043dbead95c93b4b602aa52b938959c30560 100644 (file)
@@ -149,11 +149,11 @@ type Param struct {
 // Func holds Node fields used only with function-like nodes.
 type Func struct {
        Shortname  *Node
-       Enter      *NodeList // for example, allocate and initialize memory for escaping parameters
-       Exit       *NodeList
-       Cvars      *NodeList // closure params
-       Dcl        *NodeList // autodcl for this func/closure
-       Inldcl     *NodeList // copy of dcl for use in inlining
+       Enter      Nodes // for example, allocate and initialize memory for escaping parameters
+       Exit       Nodes
+       Cvars      Nodes    // closure params
+       Dcl        []*Node  // autodcl for this func/closure
+       Inldcl     *[]*Node // copy of dcl for use in inlining
        Closgen    int
        Outerfunc  *Node
        Fieldtrack []*Type
@@ -169,18 +169,12 @@ type Func struct {
        Depth   int32
 
        Endlineno int32
+       WBLineno  int32 // line number of first write barrier
 
-       Norace            bool // func must not have race detector annotations
-       Nosplit           bool // func should not execute on separate stack
-       Noinline          bool // func should not be inlined
-       Nowritebarrier    bool // emit compiler error instead of write barrier
-       Nowritebarrierrec bool // error on write barrier in this or recursive callees
-       Dupok             bool // duplicate definitions ok
-       Wrapper           bool // is method wrapper
-       Needctxt          bool // function uses context register (has closure variables)
-       Systemstack       bool // must run on system stack
-
-       WBLineno int32 // line number of first write barrier
+       Pragma   Pragma // go:xxx function annotations
+       Dupok    bool   // duplicate definitions ok
+       Wrapper  bool   // is method wrapper
+       Needctxt bool   // function uses context register (has closure variables)
 }
 
 type Op uint8
@@ -491,3 +485,55 @@ func count(l *NodeList) int {
        }
        return int(n)
 }
+
+// Nodes is a pointer to a slice of *Node.
+// For fields that are not used in most nodes, this is used instead of
+// a slice to save space.
+type Nodes struct{ slice *[]*Node }
+
+// Slice returns the entries in Nodes as a slice.
+// Changes to the slice entries (as in s[i] = n) will be reflected in
+// the Nodes.
+func (n *Nodes) Slice() []*Node {
+       if n.slice == nil {
+               return nil
+       }
+       return *n.slice
+}
+
+// NodeList returns the entries in Nodes as a NodeList.
+// Changes to the NodeList entries (as in l.N = n) will *not* be
+// reflect in the Nodes.
+// This wastes memory and should be used as little as possible.
+func (n *Nodes) NodeList() *NodeList {
+       if n.slice == nil {
+               return nil
+       }
+       var ret *NodeList
+       for _, n := range *n.slice {
+               ret = list(ret, n)
+       }
+       return ret
+}
+
+// Set sets Nodes to a slice.
+// This takes ownership of the slice.
+func (n *Nodes) Set(s []*Node) {
+       if len(s) == 0 {
+               n.slice = nil
+       } else {
+               n.slice = &s
+       }
+}
+
+// Append appends entries to Nodes.
+// If a slice is passed in, this will take ownership of it.
+func (n *Nodes) Append(a ...*Node) {
+       if n.slice == nil {
+               if len(a) > 0 {
+                       n.slice = &a
+               }
+       } else {
+               *n.slice = append(*n.slice, a...)
+       }
+}
index 8fd6f8557500a55d684364e1f27adf0b242668e6..04455515e61e69a10c701c4b01e148df8b8c63f5 100644 (file)
@@ -40,6 +40,12 @@ func typechecklist(l *NodeList, top int) {
        }
 }
 
+func typecheckslice(l []*Node, top int) {
+       for i := range l {
+               typecheck(&l[i], top)
+       }
+}
+
 var _typekind = []string{
        TINT:        "int",
        TUINT:       "uint",
@@ -3433,9 +3439,9 @@ func typecheckfunc(n *Node) {
                addmethod(n.Func.Shortname.Sym, t, true, n.Func.Nname.Nointerface)
        }
 
-       for l := n.Func.Dcl; l != nil; l = l.Next {
-               if l.N.Op == ONAME && (l.N.Class == PPARAM || l.N.Class == PPARAMOUT) {
-                       l.N.Name.Decldepth = 1
+       for _, ln := range n.Func.Dcl {
+               if ln.Op == ONAME && (ln.Class == PPARAM || ln.Class == PPARAMOUT) {
+                       ln.Name.Decldepth = 1
                }
        }
 }
index 45b85b9b025cc9d344d4b501a3df25e1a69ac973..09888f8b9e6740b71e5b492ffc42620f70750819 100644 (file)
@@ -29,33 +29,34 @@ func walk(fn *Node) {
 
        // Final typecheck for any unused variables.
        // It's hard to be on the heap when not-used, but best to be consistent about &~PHEAP here and below.
-       for l := fn.Func.Dcl; l != nil; l = l.Next {
-               if l.N.Op == ONAME && l.N.Class&^PHEAP == PAUTO {
-                       typecheck(&l.N, Erv|Easgn)
+       for i, ln := range fn.Func.Dcl {
+               if ln.Op == ONAME && ln.Class&^PHEAP == PAUTO {
+                       typecheck(&ln, Erv|Easgn)
+                       fn.Func.Dcl[i] = ln
                }
        }
 
        // Propagate the used flag for typeswitch variables up to the NONAME in it's definition.
-       for l := fn.Func.Dcl; l != nil; l = l.Next {
-               if l.N.Op == ONAME && l.N.Class&^PHEAP == PAUTO && l.N.Name.Defn != nil && l.N.Name.Defn.Op == OTYPESW && l.N.Used {
-                       l.N.Name.Defn.Left.Used = true
+       for _, ln := range fn.Func.Dcl {
+               if ln.Op == ONAME && ln.Class&^PHEAP == PAUTO && ln.Name.Defn != nil && ln.Name.Defn.Op == OTYPESW && ln.Used {
+                       ln.Name.Defn.Left.Used = true
                }
        }
 
-       for l := fn.Func.Dcl; l != nil; l = l.Next {
-               if l.N.Op != ONAME || l.N.Class&^PHEAP != PAUTO || l.N.Sym.Name[0] == '&' || l.N.Used {
+       for _, ln := range fn.Func.Dcl {
+               if ln.Op != ONAME || ln.Class&^PHEAP != PAUTO || ln.Sym.Name[0] == '&' || ln.Used {
                        continue
                }
-               if defn := l.N.Name.Defn; defn != nil && defn.Op == OTYPESW {
+               if defn := ln.Name.Defn; defn != nil && defn.Op == OTYPESW {
                        if defn.Left.Used {
                                continue
                        }
                        lineno = defn.Left.Lineno
-                       Yyerror("%v declared and not used", l.N.Sym)
+                       Yyerror("%v declared and not used", ln.Sym)
                        defn.Left.Used = true // suppress repeats
                } else {
-                       lineno = l.N.Lineno
-                       Yyerror("%v declared and not used", l.N.Sym)
+                       lineno = ln.Lineno
+                       Yyerror("%v declared and not used", ln.Sym)
                }
        }
 
@@ -70,9 +71,9 @@ func walk(fn *Node) {
        }
 
        heapmoves()
-       if Debug['W'] != 0 && Curfn.Func.Enter != nil {
+       if Debug['W'] != 0 && len(Curfn.Func.Enter.Slice()) > 0 {
                s := fmt.Sprintf("enter %v", Curfn.Func.Nname.Sym)
-               dumplist(s, Curfn.Func.Enter)
+               dumpslice(s, Curfn.Func.Enter.Slice())
        }
 }
 
@@ -82,6 +83,12 @@ func walkstmtlist(l *NodeList) {
        }
 }
 
+func walkstmtslice(l []*Node) {
+       for i := range l {
+               walkstmt(&l[i])
+       }
+}
+
 func samelist(a *NodeList, b *NodeList) bool {
        for ; a != nil && b != nil; a, b = a.Next, b.Next {
                if a.N != b.N {
@@ -92,11 +99,11 @@ func samelist(a *NodeList, b *NodeList) bool {
 }
 
 func paramoutheap(fn *Node) bool {
-       for l := fn.Func.Dcl; l != nil; l = l.Next {
-               switch l.N.Class {
+       for _, ln := range fn.Func.Dcl {
+               switch ln.Class {
                case PPARAMOUT,
                        PPARAMOUT | PHEAP:
-                       return l.N.Addrtaken
+                       return ln.Addrtaken
 
                        // stop early - parameters are over
                case PAUTO,
@@ -290,13 +297,13 @@ func walkstmt(np **Node) {
                        var rl *NodeList
 
                        var cl Class
-                       for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
-                               cl = ll.N.Class &^ PHEAP
+                       for _, ln := range Curfn.Func.Dcl {
+                               cl = ln.Class &^ PHEAP
                                if cl == PAUTO {
                                        break
                                }
                                if cl == PPARAMOUT {
-                                       rl = list(rl, ll.N)
+                                       rl = list(rl, ln)
                                }
                        }
 
@@ -319,7 +326,7 @@ func walkstmt(np **Node) {
                        ll := ascompatee(n.Op, rl, n.List, &n.Ninit)
                        n.List = reorder3(ll)
                        for lr := n.List; lr != nil; lr = lr.Next {
-                               lr.N = applywritebarrier(lr.N, &n.Ninit)
+                               lr.N = applywritebarrier(lr.N)
                        }
                        break
                }
@@ -587,9 +594,9 @@ opswitch:
                        // transformclosure already did all preparation work.
 
                        // Prepend captured variables to argument list.
-                       n.List = concat(n.Left.Func.Enter, n.List)
+                       n.List = concat(n.Left.Func.Enter.NodeList(), n.List)
 
-                       n.Left.Func.Enter = nil
+                       n.Left.Func.Enter.Set(nil)
 
                        // Replace OCLOSURE with ONAME/PFUNC.
                        n.Left = n.Left.Func.Closure.Func.Nname
@@ -723,7 +730,7 @@ opswitch:
                        r := convas(Nod(OAS, n.Left, n.Right), init)
                        r.Dodata = n.Dodata
                        n = r
-                       n = applywritebarrier(n, init)
+                       n = applywritebarrier(n)
                }
 
        case OAS2:
@@ -734,7 +741,7 @@ opswitch:
                ll := ascompatee(OAS, n.List, n.Rlist, init)
                ll = reorder3(ll)
                for lr := ll; lr != nil; lr = lr.Next {
-                       lr.N = applywritebarrier(lr.N, init)
+                       lr.N = applywritebarrier(lr.N)
                }
                n = liststmt(ll)
 
@@ -749,7 +756,7 @@ opswitch:
 
                ll := ascompatet(n.Op, n.List, &r.Type, 0, init)
                for lr := ll; lr != nil; lr = lr.Next {
-                       lr.N = applywritebarrier(lr.N, init)
+                       lr.N = applywritebarrier(lr.N)
                }
                n = liststmt(concat(list1(r), ll))
 
@@ -2132,7 +2139,7 @@ func needwritebarrier(l *Node, r *Node) bool {
 
 // TODO(rsc): Perhaps componentgen should run before this.
 
-func applywritebarrier(n *Node, init **NodeList) *Node {
+func applywritebarrier(n *Node) *Node {
        if n.Left != nil && n.Right != nil && needwritebarrier(n.Left, n.Right) {
                if Debug_wb > 1 {
                        Warnl(int(n.Lineno), "marking %v for barrier", Nconv(n.Left, 0))
@@ -2541,12 +2548,12 @@ func vmatch1(l *Node, r *Node) bool {
 // walk through argin parameters.
 // generate and return code to allocate
 // copies of escaped parameters to the heap.
-func paramstoheap(argin **Type, out int) *NodeList {
+func paramstoheap(argin **Type, out int) []*Node {
        var savet Iter
        var v *Node
        var as *Node
 
-       var nn *NodeList
+       var nn []*Node
        for t := Structfirst(&savet, argin); t != nil; t = structnext(&savet) {
                v = t.Nname
                if v != nil && v.Sym != nil && v.Sym.Name[0] == '~' && v.Sym.Name[1] == 'r' { // unnamed result
@@ -2559,7 +2566,7 @@ func paramstoheap(argin **Type, out int) *NodeList {
                        // Defer might stop a panic and show the
                        // return values as they exist at the time of panic.
                        // Make sure to zero them on entry to the function.
-                       nn = list(nn, Nod(OAS, nodarg(t, -1), nil))
+                       nn = append(nn, Nod(OAS, nodarg(t, -1), nil))
                }
 
                if v == nil || v.Class&PHEAP == 0 {
@@ -2573,13 +2580,13 @@ func paramstoheap(argin **Type, out int) *NodeList {
                if prealloc[v] == nil {
                        prealloc[v] = callnew(v.Type)
                }
-               nn = list(nn, Nod(OAS, v.Name.Heapaddr, prealloc[v]))
+               nn = append(nn, Nod(OAS, v.Name.Heapaddr, prealloc[v]))
                if v.Class&^PHEAP != PPARAMOUT {
                        as = Nod(OAS, v, v.Name.Param.Stackparam)
                        v.Name.Param.Stackparam.Typecheck = 1
                        typecheck(&as, Etop)
-                       as = applywritebarrier(as, &nn)
-                       nn = list(nn, as)
+                       as = applywritebarrier(as)
+                       nn = append(nn, as)
                }
        }
 
@@ -2587,17 +2594,17 @@ func paramstoheap(argin **Type, out int) *NodeList {
 }
 
 // walk through argout parameters copying back to stack
-func returnsfromheap(argin **Type) *NodeList {
+func returnsfromheap(argin **Type) []*Node {
        var savet Iter
        var v *Node
 
-       var nn *NodeList
+       var nn []*Node
        for t := Structfirst(&savet, argin); t != nil; t = structnext(&savet) {
                v = t.Nname
                if v == nil || v.Class != PHEAP|PPARAMOUT {
                        continue
                }
-               nn = list(nn, Nod(OAS, v.Name.Param.Stackparam, v))
+               nn = append(nn, Nod(OAS, v.Name.Param.Stackparam, v))
        }
 
        return nn
@@ -2610,11 +2617,11 @@ func heapmoves() {
        lno := lineno
        lineno = Curfn.Lineno
        nn := paramstoheap(getthis(Curfn.Type), 0)
-       nn = concat(nn, paramstoheap(getinarg(Curfn.Type), 0))
-       nn = concat(nn, paramstoheap(Getoutarg(Curfn.Type), 1))
-       Curfn.Func.Enter = concat(Curfn.Func.Enter, nn)
+       nn = append(nn, paramstoheap(getinarg(Curfn.Type), 0)...)
+       nn = append(nn, paramstoheap(Getoutarg(Curfn.Type), 1)...)
+       Curfn.Func.Enter.Append(nn...)
        lineno = Curfn.Func.Endlineno
-       Curfn.Func.Exit = returnsfromheap(Getoutarg(Curfn.Type))
+       Curfn.Func.Exit.Append(returnsfromheap(Getoutarg(Curfn.Type))...)
        lineno = lno
 }
 
index 8c285a29525b5ed67596e96e0caaac7d0dd1c8f3..429eb351a261139af919851f70a92eab33aa2653 100644 (file)
@@ -12,8 +12,6 @@ import (
 )
 
 func defframe(ptxt *obj.Prog) {
-       var n *gc.Node
-
        // fill in argument size, stack size
        ptxt.To.Type = obj.TYPE_TEXTSIZE
 
@@ -30,8 +28,7 @@ func defframe(ptxt *obj.Prog) {
        lo := hi
 
        // iterate through declarations - they are sorted in decreasing xoffset order.
-       for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next {
-               n = l.N
+       for _, n := range gc.Curfn.Func.Dcl {
                if !n.Name.Needzero {
                        continue
                }
index 28fcecf8f4b338d103d83290dee414965a06b727..5e50f9e0e8fe88dea65ab1ff7987ef94ee505d0e 100644 (file)
@@ -12,8 +12,6 @@ import (
 )
 
 func defframe(ptxt *obj.Prog) {
-       var n *gc.Node
-
        // fill in argument size, stack size
        ptxt.To.Type = obj.TYPE_TEXTSIZE
 
@@ -30,8 +28,7 @@ func defframe(ptxt *obj.Prog) {
        lo := hi
 
        // iterate through declarations - they are sorted in decreasing xoffset order.
-       for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next {
-               n = l.N
+       for _, n := range gc.Curfn.Func.Dcl {
                if !n.Name.Needzero {
                        continue
                }
@@ -133,7 +130,7 @@ func dodiv(op gc.Op, nl *gc.Node, nr *gc.Node, res *gc.Node) {
        // The hardware will generate undefined result.
        // Also need to explicitly trap on division on zero,
        // the hardware will silently generate undefined result.
-       // DIVW will leave unpredicable result in higher 32-bit,
+       // DIVW will leave unpredictable result in higher 32-bit,
        // so always use DIVD/DIVDU.
        t := nl.Type
 
index 139b199b5788b6a85e28b46aaacc1501a08a3d11..480ae1c585d9e4fafbced11392fd330445746922 100644 (file)
@@ -11,8 +11,6 @@ import (
 )
 
 func defframe(ptxt *obj.Prog) {
-       var n *gc.Node
-
        // fill in argument size, stack size
        ptxt.To.Type = obj.TYPE_TEXTSIZE
 
@@ -28,8 +26,7 @@ func defframe(ptxt *obj.Prog) {
        hi := int64(0)
        lo := hi
        ax := uint32(0)
-       for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next {
-               n = l.N
+       for _, n := range gc.Curfn.Func.Dcl {
                if !n.Name.Needzero {
                        continue
                }
index 63e64cb77c057f9dd40b9cbe1e82514132336e0f..239e9cc35f9f45ede7916e70c791eac0f809f8ac 100644 (file)
@@ -284,7 +284,7 @@ func elimshortmov(g *gc.Graph) {
                        }
 
                        if regtyp(&p.From) || p.From.Type == obj.TYPE_CONST {
-                               // move or artihmetic into partial register.
+                               // move or arithmetic into partial register.
                                // from another register or constant can be movl.
                                // we don't switch to 32-bit arithmetic if it can
                                // change how the carry bit is set (and the carry bit is needed).
index 7f2f75341fabf7ca87bc7c7f0cfffdb6117f6a02..0b2ce271dc75ea652dc3c49202f2e7d3af9801db 100644 (file)
@@ -6,6 +6,7 @@ package main
 
 import (
        "bytes"
+       "encoding/json"
        "flag"
        "fmt"
        "os"
@@ -463,6 +464,9 @@ var deptab = []struct {
        {"runtime/internal/sys", []string{
                "zversion.go",
        }},
+       {"go/build", []string{
+               "zcgo.go",
+       }},
 }
 
 // depsuffix records the allowed suffixes for source files.
@@ -478,6 +482,7 @@ var gentab = []struct {
 }{
        {"zdefaultcc.go", mkzdefaultcc},
        {"zversion.go", mkzversion},
+       {"zcgo.go", mkzcgo},
 
        // not generated anymore, but delete the file if we see it
        {"enam.c", nil},
@@ -933,6 +938,7 @@ func usage() {
                "clean          deletes all built files\n" +
                "env [-p]       print environment (-p: include $PATH)\n" +
                "install [dir]  install individual directory\n" +
+               "list [-json]   list all supported platforms\n" +
                "test [-h]      run Go test(s)\n" +
                "version        print Go version\n" +
                "\n" +
@@ -1061,9 +1067,13 @@ func cmdbootstrap() {
        }
 }
 
-// Copied from go/build/build.go.
 // Cannot use go/build directly because cmd/dist for a new release
 // builds against an old release's go/build, which may be out of sync.
+// To reduce duplication, we generate the list for go/build from this.
+//
+// We list all supported platforms in this list, so that this is the
+// single point of truth for supported platforms. This list is used
+// by 'go tool dist list'.
 var cgoEnabled = map[string]bool{
        "darwin/386":      true,
        "darwin/amd64":    true,
@@ -1072,19 +1082,31 @@ var cgoEnabled = map[string]bool{
        "dragonfly/amd64": true,
        "freebsd/386":     true,
        "freebsd/amd64":   true,
+       "freebsd/arm":     false,
        "linux/386":       true,
        "linux/amd64":     true,
        "linux/arm":       true,
        "linux/arm64":     true,
+       "linux/ppc64":     false,
        "linux/ppc64le":   true,
+       "linux/mips64":    false,
+       "linux/mips64le":  false,
        "android/386":     true,
        "android/amd64":   true,
        "android/arm":     true,
+       "android/arm64":   true,
+       "nacl/386":        false,
+       "nacl/amd64p32":   false,
+       "nacl/arm":        false,
        "netbsd/386":      true,
        "netbsd/amd64":    true,
        "netbsd/arm":      true,
        "openbsd/386":     true,
        "openbsd/amd64":   true,
+       "openbsd/arm":     false,
+       "plan9/386":       false,
+       "plan9/amd64":     false,
+       "plan9/arm":       false,
        "solaris/amd64":   true,
        "windows/386":     true,
        "windows/amd64":   true,
@@ -1128,7 +1150,7 @@ func defaulttarg() string {
                fatal("current directory %s is not under %s", pwd, real_src)
        }
        pwd = pwd[len(real_src):]
-       // guard againt xrealwd return the directory without the trailing /
+       // guard against xrealwd returning the directory without the trailing /
        pwd = strings.TrimPrefix(pwd, "/")
 
        return pwd
@@ -1195,3 +1217,43 @@ func cmdversion() {
        xflagparse(0)
        xprintf("%s\n", findgoversion())
 }
+
+// cmdlist lists all supported platforms.
+func cmdlist() {
+       jsonFlag := flag.Bool("json", false, "produce JSON output")
+       xflagparse(0)
+
+       var plats []string
+       for p := range cgoEnabled {
+               plats = append(plats, p)
+       }
+       sort.Strings(plats)
+
+       if !*jsonFlag {
+               for _, p := range plats {
+                       xprintf("%s\n", p)
+               }
+               return
+       }
+
+       type jsonResult struct {
+               GOOS         string
+               GOARCH       string
+               CgoSupported bool
+       }
+       var results []jsonResult
+       for _, p := range plats {
+               fields := strings.Split(p, "/")
+               results = append(results, jsonResult{
+                       GOOS:         fields[0],
+                       GOARCH:       fields[1],
+                       CgoSupported: cgoEnabled[p]})
+       }
+       out, err := json.MarshalIndent(results, "", "\t")
+       if err != nil {
+               fatal("json marshal error: %v", err)
+       }
+       if _, err := os.Stdout.Write(out); err != nil {
+               fatal("write failed: %v", err)
+       }
+}
index 437e9dd9a0f7b24ef5508adfe08854862a100cc4..c0bdfad9b1ba27837c8ff2407aa13daee2bc828c 100644 (file)
@@ -4,7 +4,10 @@
 
 package main
 
-import "fmt"
+import (
+       "bytes"
+       "fmt"
+)
 
 /*
  * Helpers for building cmd/go and cmd/cgo.
@@ -37,3 +40,28 @@ func mkzdefaultcc(dir, file string) {
        file = file[:i] + "c" + file[i:]
        writefile(out, file, writeSkipSame)
 }
+
+// mkzcgo writes zcgo.go for go/build package:
+//
+//     package build
+//  var cgoEnabled = map[string]bool{}
+//
+// It is invoked to write go/build/zcgo.go.
+func mkzcgo(dir, file string) {
+       var buf bytes.Buffer
+
+       fmt.Fprintf(&buf,
+               "// auto generated by go tool dist\n"+
+                       "\n"+
+                       "package build\n"+
+                       "\n"+
+                       "var cgoEnabled = map[string]bool{\n")
+       for plat, hasCgo := range cgoEnabled {
+               if hasCgo {
+                       fmt.Fprintf(&buf, "\t%q: true,\n", plat)
+               }
+       }
+       fmt.Fprintf(&buf, "}")
+
+       writefile(buf.String(), file, writeSkipSame)
+}
index 1f19a7ca1836f786de0796e86308fd05f3120187..eaee28ada8268b16700b9477047a2edbd0bd4d0a 100644 (file)
@@ -21,6 +21,7 @@ var cmdtab = []struct {
        {"clean", cmdclean},
        {"env", cmdenv},
        {"install", cmdinstall},
+       {"list", cmdlist},
        {"test", cmdtest},
        {"version", cmdversion},
 }
index 36c829d1b93c1ca9742646b3438a6372db347caa..e268e1207e7c4cb0614bfbbe8f8331fd5733af78 100644 (file)
@@ -441,6 +441,20 @@ func (t *tester) registerTests() {
                                return nil
                        },
                })
+               fortran := os.Getenv("FC")
+               if fortran == "" {
+                       fortran, _ = exec.LookPath("gfortran")
+               }
+               if fortran != "" {
+                       t.tests = append(t.tests, distTest{
+                               name:    "cgo_fortran",
+                               heading: "../misc/cgo/fortran",
+                               fn: func(dt *distTest) error {
+                                       t.addCmd(dt, "misc/cgo/fortran", "./test.bash", fortran)
+                                       return nil
+                               },
+                       })
+               }
        }
        if t.cgoEnabled && t.goos != "android" && !t.iOS() {
                // TODO(crawshaw): reenable on android and iOS
index e65aee4a27b31ba043d4b0b8683d00840f4a7e87..89ab1c0dd4059453b31e78096f58c227228ee5ae 100644 (file)
@@ -1348,6 +1348,11 @@ func (b *builder) build(a *action) (err error) {
                return fmt.Errorf("can't build package %s because it contains Objective-C files (%s) but it's not using cgo nor SWIG",
                        a.p.ImportPath, strings.Join(a.p.MFiles, ","))
        }
+       // Same as above for Fortran files
+       if len(a.p.FFiles) > 0 && !a.p.usesCgo() && !a.p.usesSwig() {
+               return fmt.Errorf("can't build package %s because it contains Fortran files (%s) but it's not using cgo nor SWIG",
+                       a.p.ImportPath, strings.Join(a.p.FFiles, ","))
+       }
        defer func() {
                if err != nil && err != errPrintedOutput {
                        err = fmt.Errorf("go build %s: %v", a.p.ImportPath, err)
@@ -1437,7 +1442,7 @@ func (b *builder) build(a *action) (err error) {
                if a.cgo != nil && a.cgo.target != "" {
                        cgoExe = a.cgo.target
                }
-               outGo, outObj, err := b.cgo(a.p, cgoExe, obj, pcCFLAGS, pcLDFLAGS, cgofiles, gccfiles, cxxfiles, a.p.MFiles)
+               outGo, outObj, err := b.cgo(a.p, cgoExe, obj, pcCFLAGS, pcLDFLAGS, cgofiles, gccfiles, cxxfiles, a.p.MFiles, a.p.FFiles)
                if err != nil {
                        return err
                }
@@ -2272,7 +2277,7 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool,
        // so that it can give good error messages about forward declarations.
        // Exceptions: a few standard packages have forward declarations for
        // pieces supplied behind-the-scenes by package runtime.
-       extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.MFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles)
+       extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.MFiles) + len(p.FFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles)
        if p.Standard {
                switch p.ImportPath {
                case "bytes", "net", "os", "runtime/pprof", "sync", "time":
@@ -2623,6 +2628,7 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
        usesCgo := false
        cxx := len(root.p.CXXFiles) > 0 || len(root.p.SwigCXXFiles) > 0
        objc := len(root.p.MFiles) > 0
+       fortran := len(root.p.FFiles) > 0
 
        actionsSeen := make(map[*action]bool)
        // Make a pre-order depth-first traversal of the action graph, taking note of
@@ -2697,6 +2703,9 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
                if len(a.p.MFiles) > 0 {
                        objc = true
                }
+               if len(a.p.FFiles) > 0 {
+                       fortran = true
+               }
        }
 
        ldflags = append(ldflags, "-Wl,--whole-archive")
@@ -2768,6 +2777,17 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
                if objc {
                        ldflags = append(ldflags, "-lobjc")
                }
+               if fortran {
+                       fc := os.Getenv("FC")
+                       if fc == "" {
+                               fc = "gfortran"
+                       }
+                       // support gfortran out of the box and let others pass the correct link options
+                       // via CGO_LDFLAGS
+                       if strings.Contains(fc, "gfortran") {
+                               ldflags = append(ldflags, "-lgfortran")
+                       }
+               }
        }
 
        if err := b.run(".", root.p.ImportPath, nil, tools.linker(), "-o", out, ofiles, ldflags, buildGccgoflags); err != nil {
@@ -2862,6 +2882,11 @@ func (b *builder) gxx(p *Package, out string, flags []string, cxxfile string) er
        return b.ccompile(p, out, flags, cxxfile, b.gxxCmd(p.Dir))
 }
 
+// gfortran runs the gfortran Fortran compiler to create an object from a single Fortran file.
+func (b *builder) gfortran(p *Package, out string, flags []string, ffile string) error {
+       return b.ccompile(p, out, flags, ffile, b.gfortranCmd(p.Dir))
+}
+
 // ccompile runs the given C or C++ compiler and creates an object from a single source file.
 func (b *builder) ccompile(p *Package, out string, flags []string, file string, compiler []string) error {
        file = mkAbs(p.Dir, file)
@@ -2891,6 +2916,11 @@ func (b *builder) gxxCmd(objdir string) []string {
        return b.ccompilerCmd("CXX", defaultCXX, objdir)
 }
 
+// gfortranCmd returns a gfortran command line prefix.
+func (b *builder) gfortranCmd(objdir string) []string {
+       return b.ccompilerCmd("FC", "gfortran", objdir)
+}
+
 // ccompilerCmd returns a command line prefix for the given environment
 // variable and using the default command when the variable is empty.
 func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string {
@@ -3009,8 +3039,8 @@ func envList(key, def string) []string {
        return strings.Fields(v)
 }
 
-// Return the flags to use when invoking the C or C++ compilers, or cgo.
-func (b *builder) cflags(p *Package, def bool) (cppflags, cflags, cxxflags, ldflags []string) {
+// Return the flags to use when invoking the C, C++ or Fortran compilers, or cgo.
+func (b *builder) cflags(p *Package, def bool) (cppflags, cflags, cxxflags, fflags, ldflags []string) {
        var defaults string
        if def {
                defaults = "-g -O2"
@@ -3019,15 +3049,16 @@ func (b *builder) cflags(p *Package, def bool) (cppflags, cflags, cxxflags, ldfl
        cppflags = stringList(envList("CGO_CPPFLAGS", ""), p.CgoCPPFLAGS)
        cflags = stringList(envList("CGO_CFLAGS", defaults), p.CgoCFLAGS)
        cxxflags = stringList(envList("CGO_CXXFLAGS", defaults), p.CgoCXXFLAGS)
+       fflags = stringList(envList("CGO_FFLAGS", defaults), p.CgoFFLAGS)
        ldflags = stringList(envList("CGO_LDFLAGS", defaults), p.CgoLDFLAGS)
        return
 }
 
 var cgoRe = regexp.MustCompile(`[/\\:]`)
 
-func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofiles, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) {
-       cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoLDFLAGS := b.cflags(p, true)
-       _, cgoexeCFLAGS, _, _ := b.cflags(p, false)
+func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofiles, gccfiles, gxxfiles, mfiles, ffiles []string) (outGo, outObj []string, err error) {
+       cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS, cgoLDFLAGS := b.cflags(p, true)
+       _, cgoexeCFLAGS, _, _, _ := b.cflags(p, false)
        cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...)
        cgoLDFLAGS = append(cgoLDFLAGS, pcLDFLAGS...)
        // If we are compiling Objective-C code, then we need to link against libobjc
@@ -3035,6 +3066,19 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
                cgoLDFLAGS = append(cgoLDFLAGS, "-lobjc")
        }
 
+       // Likewise for Fortran, except there are many Fortran compilers.
+       // Support gfortran out of the box and let others pass the correct link options
+       // via CGO_LDFLAGS
+       if len(ffiles) > 0 {
+               fc := os.Getenv("FC")
+               if fc == "" {
+                       fc = "gfortran"
+               }
+               if strings.Contains(fc, "gfortran") {
+                       cgoLDFLAGS = append(cgoLDFLAGS, "-lgfortran")
+               }
+       }
+
        if buildMSan && p.ImportPath != "runtime/cgo" {
                cgoCFLAGS = append([]string{"-fsanitize=memory"}, cgoCFLAGS...)
                cgoLDFLAGS = append([]string{"-fsanitize=memory"}, cgoLDFLAGS...)
@@ -3202,6 +3246,17 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
                outObj = append(outObj, ofile)
        }
 
+       fflags := stringList(cgoCPPFLAGS, cgoFFLAGS)
+       for _, file := range ffiles {
+               // Append .o to the file, just in case the pkg has file.c and file.f
+               ofile := obj + cgoRe.ReplaceAllString(file, "_") + ".o"
+               if err := b.gfortran(p, ofile, fflags, file); err != nil {
+                       return nil, nil, err
+               }
+               linkobj = append(linkobj, ofile)
+               outObj = append(outObj, ofile)
+       }
+
        linkobj = append(linkobj, p.SysoFiles...)
        dynobj := obj + "_cgo_.o"
        pie := (goarch == "arm" && goos == "linux") || goos == "android"
@@ -3395,7 +3450,7 @@ func (b *builder) swigIntSize(obj string) (intsize string, err error) {
 
 // Run SWIG on one SWIG input file.
 func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx bool, intgosize string) (outGo, outC string, err error) {
-       cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true)
+       cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _, _ := b.cflags(p, true)
        var cflags []string
        if cxx {
                cflags = stringList(cgoCPPFLAGS, pcCFLAGS, cgoCXXFLAGS)
index a298049a9d21de2b498a3f6fa801fae8e1b4bf38..9d4b94acf18f338b4c25517a130ea6ccca5f0c05 100644 (file)
@@ -119,6 +119,14 @@ func runGet(cmd *Command, args []string) {
                delete(packageCache, name)
        }
 
+       // In order to rebuild packages information completely,
+       // we need to clear commands cache. Command packages are
+       // referring to evicted packages from the package cache.
+       // This leads to duplicated loads of the standard packages.
+       for name := range cmdCache {
+               delete(cmdCache, name)
+       }
+
        args = importPaths(args)
        packagesForBuild(args)
 
index 51931769d5a51aeb9947e643ac8f6650b5d0b93b..928224cee69a8a5a3985b141fe981fa44f33b0b9 100644 (file)
@@ -2122,7 +2122,7 @@ func TestIssue7108(t *testing.T) {
 // cmd/go: go test -a foo does not rebuild regexp.
 func TestIssue6844(t *testing.T) {
        if testing.Short() {
-               t.Skip("don't rebuild the standard libary in short mode")
+               t.Skip("don't rebuild the standard library in short mode")
        }
 
        tg := testgo(t)
@@ -2763,6 +2763,10 @@ func TestCgoConsistentResults(t *testing.T) {
        if !canCgo {
                t.Skip("skipping because cgo not enabled")
        }
+       if runtime.GOOS == "solaris" {
+               // See https://golang.org/issue/13247
+               t.Skip("skipping because Solaris builds are known to be inconsistent; see #13247")
+       }
 
        tg := testgo(t)
        defer tg.cleanup()
@@ -2785,3 +2789,15 @@ func TestCgoConsistentResults(t *testing.T) {
                t.Error("building cgotest twice did not produce the same output")
        }
 }
+
+// Issue 14444: go get -u .../ duplicate loads errors
+func TestGoGetUpdateAllDoesNotTryToLoadDuplicates(t *testing.T) {
+       testenv.MustHaveExternalNetwork(t)
+
+       tg := testgo(t)
+       defer tg.cleanup()
+       tg.makeTempdir()
+       tg.setenv("GOPATH", tg.path("."))
+       tg.run("get", "-u", ".../")
+       tg.grepStderrNot("duplicate loads of", "did not remove old packages from cache")
+}
index 8f741a636b1700219a972fca935a9c97e233ffa9..d2f1265985a66b3a5d79c0d1d15d4c4c1145eb4f 100644 (file)
@@ -51,6 +51,7 @@ syntax of package template.  The default output is equivalent to -f
         CXXFiles       []string // .cc, .cxx and .cpp source files
         MFiles         []string // .m source files
         HFiles         []string // .h, .hh, .hpp and .hxx source files
+        FFiles         []string // .f, .F, .for and .f90 Fortran source files
         SFiles         []string // .s source files
         SwigFiles      []string // .swig files
         SwigCXXFiles   []string // .swigcxx files
@@ -60,6 +61,7 @@ syntax of package template.  The default output is equivalent to -f
         CgoCFLAGS    []string // cgo: flags for C compiler
         CgoCPPFLAGS  []string // cgo: flags for C preprocessor
         CgoCXXFLAGS  []string // cgo: flags for C++ compiler
+        CgoFFLAGS    []string // cgo: flags for Fortran compiler
         CgoLDFLAGS   []string // cgo: flags for linker
         CgoPkgConfig []string // cgo: pkg-config names
 
index 6b5ead2b8c9a5a354df39d20b0ca3a074434ee31..ccff783c291b57d8c165586dbab87a4b924a5b48 100644 (file)
@@ -50,6 +50,7 @@ type Package struct {
        CXXFiles       []string `json:",omitempty"` // .cc, .cpp and .cxx source files
        MFiles         []string `json:",omitempty"` // .m source files
        HFiles         []string `json:",omitempty"` // .h, .hh, .hpp and .hxx source files
+       FFiles         []string `json:",omitempty"` // .f, .F, .for and .f90 Fortran source files
        SFiles         []string `json:",omitempty"` // .s source files
        SwigFiles      []string `json:",omitempty"` // .swig files
        SwigCXXFiles   []string `json:",omitempty"` // .swigcxx files
@@ -59,6 +60,7 @@ type Package struct {
        CgoCFLAGS    []string `json:",omitempty"` // cgo: flags for C compiler
        CgoCPPFLAGS  []string `json:",omitempty"` // cgo: flags for C preprocessor
        CgoCXXFLAGS  []string `json:",omitempty"` // cgo: flags for C++ compiler
+       CgoFFLAGS    []string `json:",omitempty"` // cgo: flags for Fortran compiler
        CgoLDFLAGS   []string `json:",omitempty"` // cgo: flags for linker
        CgoPkgConfig []string `json:",omitempty"` // cgo: pkg-config names
 
@@ -161,6 +163,7 @@ func (p *Package) copyBuild(pp *build.Package) {
        p.CXXFiles = pp.CXXFiles
        p.MFiles = pp.MFiles
        p.HFiles = pp.HFiles
+       p.FFiles = pp.FFiles
        p.SFiles = pp.SFiles
        p.SwigFiles = pp.SwigFiles
        p.SwigCXXFiles = pp.SwigCXXFiles
@@ -909,6 +912,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
                p.CXXFiles,
                p.MFiles,
                p.HFiles,
+               p.FFiles,
                p.SFiles,
                p.SysoFiles,
                p.SwigFiles,
@@ -1216,7 +1220,7 @@ var isGoRelease = strings.HasPrefix(runtime.Version(), "go1")
 // an explicit data comparison. Specifically, we build a list of the
 // inputs to the build, compute its SHA1 hash, and record that as the
 // ``build ID'' in the generated object. At the next build, we can
-// recompute the buid ID and compare it to the one in the generated
+// recompute the build ID and compare it to the one in the generated
 // object. If they differ, the list of inputs has changed, so the object
 // is out of date and must be rebuilt.
 //
@@ -1495,7 +1499,7 @@ func isStale(p *Package) bool {
        // to test for write access, and then skip GOPATH roots we don't have write
        // access to. But hopefully we can just use the mtimes always.
 
-       srcs := stringList(p.GoFiles, p.CFiles, p.CXXFiles, p.MFiles, p.HFiles, p.SFiles, p.CgoFiles, p.SysoFiles, p.SwigFiles, p.SwigCXXFiles)
+       srcs := stringList(p.GoFiles, p.CFiles, p.CXXFiles, p.MFiles, p.HFiles, p.FFiles, p.SFiles, p.CgoFiles, p.SysoFiles, p.SwigFiles, p.SwigCXXFiles)
        for _, src := range srcs {
                if olderThan(filepath.Join(p.Dir, src)) {
                        return true
index 995ba146f5195ed0fe6ac599691b4fd093091ddb..1d39a7219705dd81c4522b91a51454f13ceb4d6f 100644 (file)
@@ -1206,11 +1206,11 @@ func (b *builder) notest(a *action) error {
        return nil
 }
 
-// isTestMain tells whether fn is a TestMain(m *testing.M) function.
-func isTestMain(fn *ast.FuncDecl) bool {
-       if fn.Name.String() != "TestMain" ||
-               fn.Type.Results != nil && len(fn.Type.Results.List) > 0 ||
-               fn.Type.Params == nil ||
+// isTestFunc tells whether fn has the type of a testing function. arg
+// specifies the parameter type we look for: B, M or T.
+func isTestFunc(fn *ast.FuncDecl, arg string) bool {
+       if fn.Type.Results != nil && len(fn.Type.Results.List) > 0 ||
+               fn.Type.Params.List == nil ||
                len(fn.Type.Params.List) != 1 ||
                len(fn.Type.Params.List[0].Names) > 1 {
                return false
@@ -1222,10 +1222,11 @@ func isTestMain(fn *ast.FuncDecl) bool {
        // We can't easily check that the type is *testing.M
        // because we don't know how testing has been imported,
        // but at least check that it's *M or *something.M.
-       if name, ok := ptr.X.(*ast.Ident); ok && name.Name == "M" {
+       // Same applies for B and T.
+       if name, ok := ptr.X.(*ast.Ident); ok && name.Name == arg {
                return true
        }
-       if sel, ok := ptr.X.(*ast.SelectorExpr); ok && sel.Sel.Name == "M" {
+       if sel, ok := ptr.X.(*ast.SelectorExpr); ok && sel.Sel.Name == arg {
                return true
        }
        return false
@@ -1344,16 +1345,24 @@ func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error {
                }
                name := n.Name.String()
                switch {
-               case isTestMain(n):
+               case name == "TestMain" && isTestFunc(n, "M"):
                        if t.TestMain != nil {
                                return errors.New("multiple definitions of TestMain")
                        }
                        t.TestMain = &testFunc{pkg, name, ""}
                        *doImport, *seen = true, true
                case isTest(name, "Test"):
+                       err := checkTestFunc(n, "T")
+                       if err != nil {
+                               return err
+                       }
                        t.Tests = append(t.Tests, testFunc{pkg, name, ""})
                        *doImport, *seen = true, true
                case isTest(name, "Benchmark"):
+                       err := checkTestFunc(n, "B")
+                       if err != nil {
+                               return err
+                       }
                        t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, ""})
                        *doImport, *seen = true, true
                }
@@ -1372,6 +1381,15 @@ func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error {
        return nil
 }
 
+func checkTestFunc(fn *ast.FuncDecl, arg string) error {
+       if !isTestFunc(fn, arg) {
+               name := fn.Name.String()
+               pos := testFileSet.Position(fn.Pos())
+               return fmt.Errorf("%s: wrong signature for %s, must be: func %s(%s *testing.%s)", pos, name, name, strings.ToLower(arg), arg)
+       }
+       return nil
+}
+
 type byOrder []*doc.Example
 
 func (x byOrder) Len() int           { return len(x) }
index 7fdaf557c81500a11bf63a81ebcf6efc5cdbae7b..dff6224d850355912a1de46c3aa7b490f9449801 100644 (file)
@@ -530,7 +530,7 @@ func (r *objReader) parseArchive() error {
                        return errCorruptArchive
                }
                switch name {
-               case "__.SYMDEF", "__.GOSYMDEF", "__.PKGDEF":
+               case "__.PKGDEF":
                        r.skip(size)
                default:
                        oldLimit := r.limit
index 1a51dc3b88eb518d8a0f46f06bd04ed0beb02026..c5af929b14e8073c7b26126c0dbfade932d6d0da 100644 (file)
@@ -55,7 +55,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
                }
        }
 
-       // Replace TLS register fetches on older ARM procesors.
+       // Replace TLS register fetches on older ARM processors.
        switch p.As {
        // Treat MRC 15, 0, <reg>, C13, C0, 3 specially.
        case AMRC:
index 2e6df2c2f87fe8db11536549c0f8db7e3481ac92..4ae819178ddb30bd180b1029d754edaede614b14 100644 (file)
@@ -444,6 +444,11 @@ const (
        R_PLT1
        R_PLT2
        R_USEFIELD
+       // R_USETYPE resolves to an *rtype, but no relocation is created. The
+       // linker uses this as a signal that the pointed-to type information
+       // should be linked into the final binary, even if there are no other
+       // direct references. (This is used for types reachable by reflection.)
+       R_USETYPE
        R_POWER_TOC
        R_GOTPCREL
        // R_JMPMIPS (only used on mips64) resolves to non-PC-relative target address
@@ -572,6 +577,7 @@ type Link struct {
        Debugpcln          int32
        Flag_shared        int32
        Flag_dynlink       bool
+       Flag_optimize      bool
        Bso                *Biobuf
        Pathname           string
        Windows            int32
@@ -617,6 +623,10 @@ type Link struct {
        Data  *LSym
        Etext *LSym
        Edata *LSym
+
+       // Cache of Progs
+       allocIdx int
+       progs    [10000]Prog
 }
 
 func (ctxt *Link) Diag(format string, args ...interface{}) {
index a3ccad2764f7f781ac8b4f56adf3bf5f59d2d50a..fccff707be39095d87c3e7fa611717322e9fc428 100644 (file)
@@ -1234,7 +1234,7 @@ func markregused(ctxt *obj.Link, s *Sch) {
 }
 
 /*
- * test to see if 2 instrictions can be
+ * test to see if two instructions can be
  * interchanged without changing semantics
  */
 func depend(ctxt *obj.Link, sa, sb *Sch) bool {
index bae64f4a29bc077ca91b8f7c0456c27927b4000f..33330b472ef831ad9d026a42833e3ed8c71862d2 100644 (file)
@@ -116,6 +116,12 @@ func Writeobjdirect(ctxt *Link, b *Biobuf) {
 }
 
 func Flushplist(ctxt *Link) {
+       flushplist(ctxt, ctxt.Debugasm == 0)
+}
+func FlushplistNoFree(ctxt *Link) {
+       flushplist(ctxt, false)
+}
+func flushplist(ctxt *Link, freeProgs bool) {
        var flag int
        var s *LSym
        var p *Prog
@@ -295,21 +301,34 @@ func Flushplist(ctxt *Link) {
        for s := text; s != nil; s = s.Next {
                mkfwd(s)
                linkpatch(ctxt, s)
-               ctxt.Arch.Follow(ctxt, s)
+               if ctxt.Flag_optimize {
+                       ctxt.Arch.Follow(ctxt, s)
+               }
                ctxt.Arch.Preprocess(ctxt, s)
                ctxt.Arch.Assemble(ctxt, s)
                fieldtrack(ctxt, s)
                linkpcln(ctxt, s)
+               if freeProgs {
+                       s.Text = nil
+                       s.Etext = nil
+               }
        }
 
        // Add to running list in ctxt.
-       if ctxt.Etext == nil {
-               ctxt.Text = text
-       } else {
-               ctxt.Etext.Next = text
+       if text != nil {
+               if ctxt.Text == nil {
+                       ctxt.Text = text
+               } else {
+                       ctxt.Etext.Next = text
+               }
+               ctxt.Etext = etext
        }
-       ctxt.Etext = etext
        ctxt.Plist = nil
+       ctxt.Plast = nil
+       ctxt.Curp = nil
+       if freeProgs {
+               ctxt.freeProgs()
+       }
 }
 
 func Writeobjfile(ctxt *Link, b *Biobuf) {
index 14c9b6aaba6e2eb99e0c40dc31f238f722bb2d6b..f10fc60413c33a5d211afb1385d34d132832d910 100644 (file)
@@ -202,12 +202,14 @@ func linkpatch(ctxt *Link, sym *LSym) {
                p.Pcond = q
        }
 
-       for p := sym.Text; p != nil; p = p.Link {
-               if p.Pcond != nil {
-                       p.Pcond = brloop(ctxt, p.Pcond)
+       if ctxt.Flag_optimize {
+               for p := sym.Text; p != nil; p = p.Link {
                        if p.Pcond != nil {
-                               if p.To.Type == TYPE_BRANCH {
-                                       p.To.Offset = p.Pcond.Pc
+                               p.Pcond = brloop(ctxt, p.Pcond)
+                               if p.Pcond != nil {
+                                       if p.To.Type == TYPE_BRANCH {
+                                               p.To.Offset = p.Pcond.Pc
+                                       }
                                }
                        }
                }
index dd5297edc512507af9d9198daa5f89efe73accff..d9935b3d5139cfe144f0ed4e79074414f5b66790 100644 (file)
@@ -110,6 +110,7 @@ func Linknew(arch *LinkArch) *Link {
                ctxt.Goarm = Getgoarm()
        }
 
+       ctxt.Flag_optimize = true
        return ctxt
 }
 
index 459361cf48ee009f641f2b98f8d7573cb9e5e611..b6e644372fa3775af67e2e3af1687e2b3f8b177e 100644 (file)
@@ -287,6 +287,10 @@ func CConv(s uint8) string {
 }
 
 func (p *Prog) String() string {
+       if p == nil {
+               return "<nil Prog>"
+       }
+
        if p.Ctxt == nil {
                return "<Prog without ctxt>"
        }
@@ -325,10 +329,23 @@ func (p *Prog) String() string {
 }
 
 func (ctxt *Link) NewProg() *Prog {
-       p := new(Prog) // should be the only call to this; all others should use ctxt.NewProg
+       var p *Prog
+       if i := ctxt.allocIdx; i < len(ctxt.progs) {
+               p = &ctxt.progs[i]
+               ctxt.allocIdx = i + 1
+       } else {
+               p = new(Prog) // should be the only call to this; all others should use ctxt.NewProg
+       }
        p.Ctxt = ctxt
        return p
 }
+func (ctxt *Link) freeProgs() {
+       s := ctxt.progs[:ctxt.allocIdx]
+       for i := range s {
+               s[i] = Prog{}
+       }
+       ctxt.allocIdx = 0
+}
 
 func (ctxt *Link) Line(n int) string {
        return ctxt.LineHist.LineString(n)
index 1955aa560df9a82c37895d187ecd4ef3f32e2398..3f8426ae3867acea64184f2a37531ef5fac6a298 100644 (file)
@@ -189,7 +189,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
                }
        }
 
-       // Rewrite 0 to $0 in 3rd argment to CMPPS etc.
+       // Rewrite 0 to $0 in 3rd argument to CMPPS etc.
        // That's what the tables expect.
        switch p.As {
        case ACMPPD, ACMPPS, ACMPSD, ACMPSS:
index 74c22497029d4af3c29b7fc86ff9907bbb3c065f..ca5551257559afd6b491ba79841d0bd01dd7db29 100644 (file)
@@ -109,7 +109,7 @@ func gentext() {
 }
 
 // Preserve highest 8 bits of a, and do addition to lower 24-bit
-// of a and b; used to adjust ARM branch intruction's target
+// of a and b; used to adjust ARM branch instruction's target
 func braddoff(a int32, b int32) int32 {
        return int32((uint32(a))&0xff000000 | 0x00ffffff&uint32(a+b))
 }
index 10eb723bb9379d46c2eb5266c80e1b29745d6eaa..29a58c6fd27083d57e63dc768b2081d8829ff5bc 100644 (file)
@@ -156,7 +156,7 @@ func archinit() {
                }
 
        case obj.Hdarwin: /* apple MACH */
-               ld.Debug['w'] = 1 // disable DWARF generataion
+               ld.Debug['w'] = 1 // disable DWARF generation
                ld.Machoinit()
                ld.HEADR = ld.INITIAL_MACHO_HEADR
                if ld.INITTEXT == -1 {
index 0e5a2d0a63cdf26c51f854c0570c4fa987fb54c3..be8afa5d26899bb408ef967b4ef6bbcbc3222756 100644 (file)
@@ -162,7 +162,7 @@ func machoreloc1(r *ld.Reloc, sectoff int64) int {
        rs := r.Xsym
 
        // ld64 has a bug handling MACHO_ARM64_RELOC_UNSIGNED with !extern relocation.
-       // see cmd/internal/ld/data.go for details. The workarond is that don't use !extern
+       // see cmd/internal/ld/data.go for details. The workaround is that don't use !extern
        // UNSIGNED relocation at all.
        if rs.Type == obj.SHOSTOBJ || r.Type == obj.R_CALLARM64 || r.Type == obj.R_ADDRARM64 || r.Type == obj.R_ADDR {
                if rs.Dynid < 0 {
index 61389d9218c8a9c9b4b6bb838d98ffa1df21ea9a..c52879cbbe5d930a576c004cc84e6ff4af51da3d 100644 (file)
@@ -116,7 +116,7 @@ const (
        DW_CHILDREN_yes = 0x01
 )
 
-// Not from the spec, but logicaly belongs here
+// Not from the spec, but logically belongs here
 const (
        DW_CLS_ADDRESS = 0x01 + iota
        DW_CLS_BLOCK
index bea3f2dcc3bbaf0b8b9845b265faf8bc433f3aaa..9eeca218d3edc2955e375b2246a279beedb2ae7f 100644 (file)
@@ -1066,9 +1066,9 @@ func readelfsym(elfobj *ElfObj, i int, sym *ElfSym, needSym int) (err error) {
                        }
 
                        if needSym != 0 {
-                               // local names and hidden visiblity global names are unique
-                               // and should only reference by its index, not name, so we
-                               // don't bother to add them into hash table
+                               // local names and hidden global names are unique
+                               // and should only be referenced by their index, not name, so we
+                               // don't bother to add them into the hash table
                                s = linknewsym(Ctxt, sym.name, Ctxt.Version)
 
                                s.Type |= obj.SHIDDEN
index bdfa0563c3d269c659ccb628944883c5486361e7..461ebf8db1fd15bfdb61b805a1fdd24b9fc62673 100644 (file)
@@ -255,10 +255,7 @@ var coutbuf struct {
        f *os.File
 }
 
-const (
-       symname = "__.GOSYMDEF"
-       pkgname = "__.PKGDEF"
-)
+const pkgname = "__.PKGDEF"
 
 var (
        // Set if we see an object compiled by the host compiler that is not
@@ -781,7 +778,7 @@ func objfile(lib *Library) {
                return
        }
 
-       /* skip over optional __.GOSYMDEF and process __.PKGDEF */
+       /* process __.PKGDEF */
        off := obj.Boffset(f)
 
        var arhdr ArHdr
@@ -792,15 +789,6 @@ func objfile(lib *Library) {
                goto out
        }
 
-       if strings.HasPrefix(arhdr.name, symname) {
-               off += l
-               l = nextar(f, off, &arhdr)
-               if l <= 0 {
-                       Diag("%s: short read on archive file symbol header", lib.File)
-                       goto out
-               }
-       }
-
        if !strings.HasPrefix(arhdr.name, pkgname) {
                Diag("%s: cannot find package header", lib.File)
                goto out
@@ -829,7 +817,7 @@ func objfile(lib *Library) {
         * the individual symbols that are unused.
         *
         * loading every object will also make it possible to
-        * load foreign objects not referenced by __.GOSYMDEF.
+        * load foreign objects not referenced by __.PKGDEF.
         */
        for {
                l = nextar(f, off, &arhdr)
index 1c7f3a0d824cd93f35e7e9b7456854c5105f4467..010e7da0eedfde61412780dd7772c0638b8bd715 100644 (file)
@@ -569,7 +569,7 @@ func Asmbmacho() {
        if Linkmode == LinkInternal {
                // For lldb, must say LC_VERSION_MIN_MACOSX or else
                // it won't know that this Mach-O binary is from OS X
-               // (could be iOS or WatchOS intead).
+               // (could be iOS or WatchOS instead).
                // Go on iOS uses linkmode=external, and linkmode=external
                // adds this itself. So we only need this code for linkmode=internal
                // and we can assume OS X.
index 0265e2384cb4cb25bde3e58e679f0bc7d65a20b9..b6694f559ff392bc028160c59ba1ef67e8c08b5f 100644 (file)
@@ -1340,7 +1340,7 @@ const (
        addressOrder
 )
 
-// sort reoders the entries in a report based on the specified
+// sort reorders the entries in a report based on the specified
 // ordering criteria. The result is sorted in decreasing order for
 // numeric quantities, alphabetically for text, and increasing for
 // addresses.
index 73ae1b4ea2efadf747beab8629dff90cd7a72acc..908be21424f3cd95af306dfeae955ed74f2fa32f 100644 (file)
@@ -408,7 +408,7 @@ func getMissingFunctionSource(filename string, asm map[int]nodes, start, end int
        return fnodes, filename
 }
 
-// adjustSourcePath adjusts the pathe for a source file by trimmming
+// adjustSourcePath adjusts the path for a source file by trimming
 // known prefixes and searching for the file on all parents of the
 // current working dir.
 func adjustSourcePath(path string) (*os.File, string, error) {
index 53db6dde93bca7ec4d51e5f0c09f7a42ebbcc4c4..bb3238fc9ed46e21151315a59b308c063537f366 100644 (file)
@@ -85,12 +85,12 @@ Flag: -copylocks
 
 Locks that are erroneously passed by value.
 
-Documentation examples
+Tests, benchmarks and documentation examples
 
-Flag: -example
+Flag: -tests
 
-Mistakes involving example tests, including examples with incorrect names or
-function signatures, or that document identifiers not in the package.
+Mistakes involving tests including functions with incorrect names or signatures
+and example tests that document identifiers not in the package.
 
 Methods
 
diff --git a/src/cmd/vet/example.go b/src/cmd/vet/example.go
deleted file mode 100644 (file)
index 797c3ce..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
-       "go/ast"
-       "go/types"
-       "strings"
-       "unicode"
-       "unicode/utf8"
-)
-
-func init() {
-       register("example",
-               "check for common mistaken usages of documentation examples",
-               checkExample,
-               funcDecl)
-}
-
-func isExampleSuffix(s string) bool {
-       r, size := utf8.DecodeRuneInString(s)
-       return size > 0 && unicode.IsLower(r)
-}
-
-// checkExample walks the documentation example functions checking for common
-// mistakes of misnamed functions, failure to map functions to existing
-// identifiers, etc.
-func checkExample(f *File, node ast.Node) {
-       if !strings.HasSuffix(f.name, "_test.go") {
-               return
-       }
-       var (
-               pkg     = f.pkg
-               pkgName = pkg.typesPkg.Name()
-               scopes  = []*types.Scope{pkg.typesPkg.Scope()}
-               lookup  = func(name string) types.Object {
-                       for _, scope := range scopes {
-                               if o := scope.Lookup(name); o != nil {
-                                       return o
-                               }
-                       }
-                       return nil
-               }
-       )
-       if strings.HasSuffix(pkgName, "_test") {
-               // Treat 'package foo_test' as an alias for 'package foo'.
-               var (
-                       basePkg = strings.TrimSuffix(pkgName, "_test")
-                       pkg     = f.pkg
-               )
-               for _, p := range pkg.typesPkg.Imports() {
-                       if p.Name() == basePkg {
-                               scopes = append(scopes, p.Scope())
-                               break
-                       }
-               }
-       }
-       fn, ok := node.(*ast.FuncDecl)
-       if !ok {
-               // Ignore non-functions.
-               return
-       }
-       var (
-               fnName = fn.Name.Name
-               report = func(format string, args ...interface{}) { f.Badf(node.Pos(), format, args...) }
-       )
-       if fn.Recv != nil || !strings.HasPrefix(fnName, "Example") {
-               // Ignore methods and types not named "Example".
-               return
-       }
-       if params := fn.Type.Params; len(params.List) != 0 {
-               report("%s should be niladic", fnName)
-       }
-       if results := fn.Type.Results; results != nil && len(results.List) != 0 {
-               report("%s should return nothing", fnName)
-       }
-       if fnName == "Example" {
-               // Nothing more to do.
-               return
-       }
-       if filesRun && !includesNonTest {
-               // The coherence checks between a test and the package it tests
-               // will report false positives if no non-test files have
-               // been provided.
-               return
-       }
-       var (
-               exName = strings.TrimPrefix(fnName, "Example")
-               elems  = strings.SplitN(exName, "_", 3)
-               ident  = elems[0]
-               obj    = lookup(ident)
-       )
-       if ident != "" && obj == nil {
-               // Check ExampleFoo and ExampleBadFoo.
-               report("%s refers to unknown identifier: %s", fnName, ident)
-               // Abort since obj is absent and no subsequent checks can be performed.
-               return
-       }
-       if elemCnt := strings.Count(exName, "_"); elemCnt == 0 {
-               // Nothing more to do.
-               return
-       }
-       mmbr := elems[1]
-       if ident == "" {
-               // Check Example_suffix and Example_BadSuffix.
-               if residual := strings.TrimPrefix(exName, "_"); !isExampleSuffix(residual) {
-                       report("%s has malformed example suffix: %s", fnName, residual)
-               }
-               return
-       }
-       if !isExampleSuffix(mmbr) {
-               // Check ExampleFoo_Method and ExampleFoo_BadMethod.
-               if obj, _, _ := types.LookupFieldOrMethod(obj.Type(), true, obj.Pkg(), mmbr); obj == nil {
-                       report("%s refers to unknown field or method: %s.%s", fnName, ident, mmbr)
-               }
-       }
-       if len(elems) == 3 && !isExampleSuffix(elems[2]) {
-               // Check ExampleFoo_Method_suffix and ExampleFoo_Method_Badsuffix.
-               report("%s has malformed example suffix: %s", fnName, elems[2])
-       }
-       return
-}
similarity index 59%
rename from src/cmd/vet/testdata/examples_test.go
rename to src/cmd/vet/testdata/tests_test.go
index 9c53672a7d5ad5bc3a569ba00ae0e370c038abfc..f5bbc3922a99f1938b567c8c2156ad46314417c7 100644 (file)
@@ -1,7 +1,9 @@
-// Test of examples.
-
 package testdata
 
+import (
+       "testing"
+)
+
 // Buf is a ...
 type Buf []byte
 
@@ -46,3 +48,27 @@ func ExamplePuffer() // ERROR "ExamplePuffer refers to unknown identifier: Puffe
 func ExamplePuffer_Append() // ERROR "ExamplePuffer_Append refers to unknown identifier: Puffer"
 
 func ExamplePuffer_suffix() // ERROR "ExamplePuffer_suffix refers to unknown identifier: Puffer"
+
+func nonTest() {} // OK because it doesn't start with "Test".
+
+func (Buf) TesthasReceiver() {} // OK because it has a receiver.
+
+func TestOKSuffix(*testing.T) {} // OK because first char after "Test" is Uppercase.
+
+func TestÃœnicodeWorks(*testing.T) {} // OK because the first char after "Test" is Uppercase.
+
+func TestbadSuffix(*testing.T) {} // ERROR "first letter after 'Test' must not be lowercase"
+
+func TestemptyImportBadSuffix(*T) {} // ERROR "first letter after 'Test' must not be lowercase"
+
+func Test(*testing.T) {} // OK "Test" on its own is considered a test.
+
+func Testify() {} // OK because it takes no parameters.
+
+func TesttooManyParams(*testing.T, string) {} // OK because it takes too many parameters.
+
+func TesttooManyNames(a, b *testing.T) {} // OK because it takes too many names.
+
+func TestnoTParam(string) {} // OK because it doesn't take a *testing.T
+
+func BenchmarkbadSuffix(*testing.B) {} // ERROR "first letter after 'Benchmark' must not be lowercase"
diff --git a/src/cmd/vet/tests.go b/src/cmd/vet/tests.go
new file mode 100644 (file)
index 0000000..52ad334
--- /dev/null
@@ -0,0 +1,182 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+       "go/ast"
+       "go/types"
+       "strings"
+       "unicode"
+       "unicode/utf8"
+)
+
+func init() {
+       register("tests",
+               "check for common mistaken usages of tests/documentation examples",
+               checkTestFunctions,
+               funcDecl)
+}
+
+func isExampleSuffix(s string) bool {
+       r, size := utf8.DecodeRuneInString(s)
+       return size > 0 && unicode.IsLower(r)
+}
+
+func isTestSuffix(name string) bool {
+       if len(name) == 0 {
+               // "Test" is ok.
+               return true
+       }
+       r, _ := utf8.DecodeRuneInString(name)
+       return !unicode.IsLower(r)
+}
+
+func isTestParam(typ ast.Expr, wantType string) bool {
+       ptr, ok := typ.(*ast.StarExpr)
+       if !ok {
+               // Not a pointer.
+               return false
+       }
+       // No easy way of making sure it's a *testing.T or *testing.B:
+       // ensure the name of the type matches.
+       if name, ok := ptr.X.(*ast.Ident); ok {
+               return name.Name == wantType
+       }
+       if sel, ok := ptr.X.(*ast.SelectorExpr); ok {
+               return sel.Sel.Name == wantType
+       }
+       return false
+}
+
+func lookup(name string, scopes []*types.Scope) types.Object {
+       for _, scope := range scopes {
+               if o := scope.Lookup(name); o != nil {
+                       return o
+               }
+       }
+       return nil
+}
+
+func extendedScope(pkg *Package) []*types.Scope {
+       scopes := []*types.Scope{pkg.typesPkg.Scope()}
+
+       pkgName := pkg.typesPkg.Name()
+       if strings.HasPrefix(pkgName, "_test") {
+               basePkg := strings.TrimSuffix(pkgName, "_test")
+               for _, p := range pkg.typesPkg.Imports() {
+                       if p.Name() == basePkg {
+                               scopes = append(scopes, p.Scope())
+                               break
+                       }
+               }
+       }
+       return scopes
+}
+
+func checkExample(fn *ast.FuncDecl, pkg *Package, report reporter) {
+       fnName := fn.Name.Name
+       if params := fn.Type.Params; len(params.List) != 0 {
+               report("%s should be niladic", fnName)
+       }
+       if results := fn.Type.Results; results != nil && len(results.List) != 0 {
+               report("%s should return nothing", fnName)
+       }
+
+       if filesRun && !includesNonTest {
+               // The coherence checks between a test and the package it tests
+               // will report false positives if no non-test files have
+               // been provided.
+               return
+       }
+
+       if fnName == "Example" {
+               // Nothing more to do.
+               return
+       }
+
+       var (
+               exName = strings.TrimPrefix(fnName, "Example")
+               elems  = strings.SplitN(exName, "_", 3)
+               ident  = elems[0]
+               obj    = lookup(ident, extendedScope(pkg))
+       )
+       if ident != "" && obj == nil {
+               // Check ExampleFoo and ExampleBadFoo.
+               report("%s refers to unknown identifier: %s", fnName, ident)
+               // Abort since obj is absent and no subsequent checks can be performed.
+               return
+       }
+       if len(elems) < 2 {
+               // Nothing more to do.
+               return
+       }
+
+       if ident == "" {
+               // Check Example_suffix and Example_BadSuffix.
+               if residual := strings.TrimPrefix(exName, "_"); !isExampleSuffix(residual) {
+                       report("%s has malformed example suffix: %s", fnName, residual)
+               }
+               return
+       }
+
+       mmbr := elems[1]
+       if !isExampleSuffix(mmbr) {
+               // Check ExampleFoo_Method and ExampleFoo_BadMethod.
+               if obj, _, _ := types.LookupFieldOrMethod(obj.Type(), true, obj.Pkg(), mmbr); obj == nil {
+                       report("%s refers to unknown field or method: %s.%s", fnName, ident, mmbr)
+               }
+       }
+       if len(elems) == 3 && !isExampleSuffix(elems[2]) {
+               // Check ExampleFoo_Method_suffix and ExampleFoo_Method_Badsuffix.
+               report("%s has malformed example suffix: %s", fnName, elems[2])
+       }
+}
+
+func checkTest(fn *ast.FuncDecl, prefix string, report reporter) {
+       // Want functions with 0 results and 1 parameter.
+       if fn.Type.Results != nil && len(fn.Type.Results.List) > 0 ||
+               fn.Type.Params == nil ||
+               len(fn.Type.Params.List) != 1 ||
+               len(fn.Type.Params.List[0].Names) > 1 {
+               return
+       }
+
+       // The param must look like a *testing.T or *testing.B.
+       if !isTestParam(fn.Type.Params.List[0].Type, prefix[:1]) {
+               return
+       }
+
+       if !isTestSuffix(fn.Name.Name[len(prefix):]) {
+               report("%s has malformed name: first letter after '%s' must not be lowercase", fn.Name.Name, prefix)
+       }
+}
+
+type reporter func(format string, args ...interface{})
+
+// checkTestFunctions walks Test, Benchmark and Example functions checking
+// malformed names, wrong signatures and examples documenting inexistent
+// identifiers.
+func checkTestFunctions(f *File, node ast.Node) {
+       if !strings.HasSuffix(f.name, "_test.go") {
+               return
+       }
+
+       fn, ok := node.(*ast.FuncDecl)
+       if !ok || fn.Recv != nil {
+               // Ignore non-functions or functions with receivers.
+               return
+       }
+
+       report := func(format string, args ...interface{}) { f.Badf(node.Pos(), format, args...) }
+
+       switch {
+       case strings.HasPrefix(fn.Name.Name, "Example"):
+               checkExample(fn, f.pkg, report)
+       case strings.HasPrefix(fn.Name.Name, "Test"):
+               checkTest(fn, "Test", report)
+       case strings.HasPrefix(fn.Name.Name, "Benchmark"):
+               checkTest(fn, "Benchmark", report)
+       }
+}
index 62a3fcc49641349a5f99ee4b30cf137d652aa0c4..5e588b92582bbc18e1cfd27b461491c6270955e6 100644 (file)
@@ -130,7 +130,7 @@ func testNonceSafety(t *testing.T, c elliptic.Curve, tag string) {
        }
 
        if r0.Cmp(r1) == 0 {
-               t.Errorf("%s: the nonce used for two diferent messages was the same", tag)
+               t.Errorf("%s: the nonce used for two different messages was the same", tag)
        }
 }
 
index f1f0f67e5556aae843890eb4bcdd2ea85e6a9802..54d02b743a6a2b293b2e5de72d9cc0aedadc4291 100644 (file)
@@ -46,7 +46,7 @@ loop:
        BEQ     aligned                 // aligned detected - skip copy
 
        // Copy the unaligned source data into the aligned temporary buffer
-       // memove(to=4(R13), from=8(R13), n=12(R13)) - Corrupts all registers
+       // memmove(to=4(R13), from=8(R13), n=12(R13)) - Corrupts all registers
        MOVW    $buf, Rtable    // to
        MOVW    $64, Rc0                // n
        MOVM.IB [Rtable,Rdata,Rc0], (R13)
index ee32fa0bd67e52cffea909e36d7ba0eeeb1d2056..5e48fc9cd9ba2699ab4944f4dcc09e741af0bcbe 100644 (file)
@@ -11,8 +11,9 @@ import "io"
 // Reader is a global, shared instance of a cryptographically
 // strong pseudo-random generator.
 //
-// On Unix-like systems, Reader reads from /dev/urandom.
 // On Linux, Reader uses getrandom(2) if available, /dev/urandom otherwise.
+// On OpenBSD, Reader uses getentropy(2).
+// On other Unix-like systems, Reader reads from /dev/urandom.
 // On Windows systems, Reader uses the CryptGenRandom API.
 var Reader io.Reader
 
diff --git a/src/crypto/rand/rand_openbsd.go b/src/crypto/rand/rand_openbsd.go
new file mode 100644 (file)
index 0000000..405c091
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2016 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rand
+
+import (
+       "internal/syscall/unix"
+)
+
+func init() {
+       altGetRandom = getRandomOpenBSD
+}
+
+func getRandomOpenBSD(p []byte) (ok bool) {
+       // getentropy(2) returns a maximum of 256 bytes per call
+       for i := 0; i < len(p); i += 256 {
+               end := i + 256
+               if len(p) < end {
+                       end = len(p)
+               }
+               err := unix.GetEntropy(p[i:end])
+               if err != nil {
+                       return false
+               }
+       }
+       return true
+}
index 3c996acf8785b414e8efb630bdca3b6747b05c21..b1299229265ef2b6c45fa7ac3b5d281108a17bd6 100644 (file)
@@ -16,6 +16,7 @@ import (
        "io"
        "net"
        "strconv"
+       "strings"
 )
 
 type clientHandshakeState struct {
@@ -49,20 +50,13 @@ func (c *Conn) clientHandshake() error {
                return errors.New("tls: NextProtos values too large")
        }
 
-       sni := c.config.ServerName
-       // IP address literals are not permitted as SNI values. See
-       // https://tools.ietf.org/html/rfc6066#section-3.
-       if net.ParseIP(sni) != nil {
-               sni = ""
-       }
-
        hello := &clientHelloMsg{
                vers:                c.config.maxVersion(),
                compressionMethods:  []uint8{compressionNone},
                random:              make([]byte, 32),
                ocspStapling:        true,
                scts:                true,
-               serverName:          sni,
+               serverName:          hostnameInSNI(c.config.ServerName),
                supportedCurves:     c.config.curvePreferences(),
                supportedPoints:     []uint8{pointFormatUncompressed},
                nextProtoNeg:        len(c.config.NextProtos) > 0,
@@ -665,3 +659,23 @@ func mutualProtocol(protos, preferenceProtos []string) (string, bool) {
 
        return protos[0], true
 }
+
+// hostnameInSNI converts name into an approriate hostname for SNI.
+// Literal IP addresses and absolute FQDNs are not permitted as SNI values.
+// See https://tools.ietf.org/html/rfc6066#section-3.
+func hostnameInSNI(name string) string {
+       host := name
+       if len(host) > 0 && host[0] == '[' && host[len(host)-1] == ']' {
+               host = host[1 : len(host)-1]
+       }
+       if i := strings.LastIndex(host, "%"); i > 0 {
+               host = host[:i]
+       }
+       if net.ParseIP(host) != nil {
+               return ""
+       }
+       if len(name) > 0 && name[len(name)-1] == '.' {
+               name = name[:len(name)-1]
+       }
+       return name
+}
index f78cc4693550f504e55422d7611dce3e097bca46..9b6c4328a52a6c03a3c0962c7eb1fcfd62de598e 100644 (file)
@@ -448,7 +448,7 @@ func TestClientResumption(t *testing.T) {
                        t.Fatalf("%s resumed: %v, expected: %v", test, hs.DidResume, didResume)
                }
                if didResume && (hs.PeerCertificates == nil || hs.VerifiedChains == nil) {
-                       t.Fatalf("expected non-nil certificates after resumption. Got peerCertificates: %#v, verifedCertificates: %#v", hs.PeerCertificates, hs.VerifiedChains)
+                       t.Fatalf("expected non-nil certificates after resumption. Got peerCertificates: %#v, verifiedCertificates: %#v", hs.PeerCertificates, hs.VerifiedChains)
                }
        }
 
@@ -618,14 +618,35 @@ func TestHandshakClientSCTs(t *testing.T) {
        runClientTestTLS12(t, test)
 }
 
-func TestNoIPAddressesInSNI(t *testing.T) {
-       for _, ipLiteral := range []string{"1.2.3.4", "::1"} {
+var hostnameInSNITests = []struct {
+       in, out string
+}{
+       // Opaque string
+       {"", ""},
+       {"localhost", "localhost"},
+       {"foo, bar, baz and qux", "foo, bar, baz and qux"},
+
+       // DNS hostname
+       {"golang.org", "golang.org"},
+       {"golang.org.", "golang.org"},
+
+       // Literal IPv4 address
+       {"1.2.3.4", ""},
+
+       // Literal IPv6 address
+       {"::1", ""},
+       {"::1%lo0", ""}, // with zone identifier
+       {"[::1]", ""},   // as per RFC 5952 we allow the [] style as IPv6 literal
+       {"[::1%lo0]", ""},
+}
+
+func TestHostnameInSNI(t *testing.T) {
+       for _, tt := range hostnameInSNITests {
                c, s := net.Pipe()
 
-               go func() {
-                       client := Client(c, &Config{ServerName: ipLiteral})
-                       client.Handshake()
-               }()
+               go func(host string) {
+                       Client(c, &Config{ServerName: host, InsecureSkipVerify: true}).Handshake()
+               }(tt.in)
 
                var header [5]byte
                if _, err := io.ReadFull(s, header[:]); err != nil {
@@ -637,10 +658,20 @@ func TestNoIPAddressesInSNI(t *testing.T) {
                if _, err := io.ReadFull(s, record[:]); err != nil {
                        t.Fatal(err)
                }
+
+               c.Close()
                s.Close()
 
-               if bytes.Index(record, []byte(ipLiteral)) != -1 {
-                       t.Errorf("IP literal %q found in ClientHello: %x", ipLiteral, record)
+               var m clientHelloMsg
+               if !m.unmarshal(record) {
+                       t.Errorf("unmarshaling ClientHello for %q failed", tt.in)
+                       continue
+               }
+               if tt.in != tt.out && m.serverName == tt.in {
+                       t.Errorf("prohibited %q found in ClientHello: %x", tt.in, record)
+               }
+               if m.serverName != tt.out {
+                       t.Errorf("expected %q not found in ClientHello: %x", tt.out, record)
                }
        }
 }
index 29e7c21397516119614bffc6eedd30fec344c967..97c2ea2442e28ac38fd6bc083be18c5f4f215315 100644 (file)
@@ -5,8 +5,12 @@
 package x509_test
 
 import (
+       "crypto/dsa"
+       "crypto/ecdsa"
+       "crypto/rsa"
        "crypto/x509"
        "encoding/pem"
+       "fmt"
 )
 
 func ExampleCertificate_Verify() {
@@ -89,3 +93,42 @@ yE+vPxsiUkvQHdO2fojCkY8jg70jxM+gu59tPDNbw3Uh/2Ij310FgTHsnGQMyA==
                panic("failed to verify certificate: " + err.Error())
        }
 }
+
+func ExampleParsePKIXPublicKey() {
+       const pubPEM = `
+-----BEGIN PUBLIC KEY-----
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlRuRnThUjU8/prwYxbty
+WPT9pURI3lbsKMiB6Fn/VHOKE13p4D8xgOCADpdRagdT6n4etr9atzDKUSvpMtR3
+CP5noNc97WiNCggBjVWhs7szEe8ugyqF23XwpHQ6uV1LKH50m92MbOWfCtjU9p/x
+qhNpQQ1AZhqNy5Gevap5k8XzRmjSldNAFZMY7Yv3Gi+nyCwGwpVtBUwhuLzgNFK/
+yDtw2WcWmUU7NuC8Q6MWvPebxVtCfVp/iQU6q60yyt6aGOBkhAX0LpKAEhKidixY
+nP9PNVBvxgu3XZ4P36gZV6+ummKdBVnc3NqwBLu5+CcdRdusmHPHd5pHf4/38Z3/
+6qU2a/fPvWzceVTEgZ47QjFMTCTmCwNt29cvi7zZeQzjtwQgn4ipN9NibRH/Ax/q
+TbIzHfrJ1xa2RteWSdFjwtxi9C20HUkjXSeI4YlzQMH0fPX6KCE7aVePTOnB69I/
+a9/q96DiXZajwlpq3wFctrs1oXqBp5DVrCIj8hU2wNgB7LtQ1mCtsYz//heai0K9
+PhE4X6hiE0YmeAZjR0uHl8M/5aW9xCoJ72+12kKpWAa0SFRWLy6FejNYCYpkupVJ
+yecLk/4L1W0l6jQQZnWErXZYe0PNFcmwGXy1Rep83kfBRNKRy5tvocalLlwXLdUk
+AIU+2GKjyT3iMuzZxxFxPFMCAwEAAQ==
+-----END PUBLIC KEY-----`
+
+       block, _ := pem.Decode([]byte(pubPEM))
+       if block == nil {
+               panic("failed to parse PEM block containing the public key")
+       }
+
+       pub, err := x509.ParsePKIXPublicKey(block.Bytes)
+       if err != nil {
+               panic("failed to parse DER encoded public key: " + err.Error())
+       }
+
+       switch pub := pub.(type) {
+       case *rsa.PublicKey:
+               fmt.Println("pub is of type RSA:", pub)
+       case *dsa.PublicKey:
+               fmt.Println("pub is of type DSA:", pub)
+       case *ecdsa.PublicKey:
+               fmt.Println("pub is of type ECDSA:", pub)
+       default:
+               panic("unknown type of public key")
+       }
+}
index cc6d23c505583913c0e0c2d4f7d7ccad36151981..8b6b1516ae7008c794c3242d45306243c74c71a5 100644 (file)
@@ -57,6 +57,6 @@ func TestSystemRoots(t *testing.T) {
        }
 
        if have < want {
-               t.Errorf("insufficent overlap between cgo and non-cgo roots; want at least %d, have %d", want, have)
+               t.Errorf("insufficient overlap between cgo and non-cgo roots; want at least %d, have %d", want, have)
        }
 }
index d9288bb30e880f92e0385c155d0796ab22b7b6f1..dc793cadead24f76f6537e5e14708fae3a00c497 100644 (file)
@@ -36,6 +36,12 @@ type pkixPublicKey struct {
 
 // ParsePKIXPublicKey parses a DER encoded public key. These values are
 // typically found in PEM blocks with "BEGIN PUBLIC KEY".
+//
+// Supported key types include RSA, DSA, and ECDSA. Unknown key
+// types result in an error.
+//
+// On success, pub will be of type *rsa.PublicKey, *dsa.PublicKey,
+// or *ecdsa.PublicKey.
 func ParsePKIXPublicKey(derBytes []byte) (pub interface{}, err error) {
        var pki publicKeyInfo
        if rest, err := asn1.Unmarshal(derBytes, &pki); err != nil {
index 8ec70d99b02c5374b5e1de8177bc59096f3ff0e5..68f17fb6b00f4bf4fb51ac53d00df44c63e95fea 100644 (file)
@@ -1591,7 +1591,7 @@ func TestStmtCloseOrder(t *testing.T) {
 
        _, err := db.Query("SELECT|non_existent|name|")
        if err == nil {
-               t.Fatal("Quering non-existent table should fail")
+               t.Fatal("Querying non-existent table should fail")
        }
 }
 
index 5ca86679fa5116a3cd5122921b539fc209714f12..6b140c60c79b46408fae9c5e3afdbd1ad5984e97 100644 (file)
@@ -243,7 +243,7 @@ type Field struct {
        Class Class
 }
 
-// A Class is the DWARF 4 class of an attibute value.
+// A Class is the DWARF 4 class of an attribute value.
 //
 // In general, a given attribute's value may take on one of several
 // possible classes defined by DWARF, each of which leads to a
index 8d4aa547a020b38e3b4eeae3abf3bf1d09b68f42..355bb0433ed61cf0c6fdd1d6c5ef1f0d3f377c00 100644 (file)
@@ -42,7 +42,7 @@ func dotest(t *testing.T) {
        if err := cmd.Run(); err != nil {
                t.Fatal(err)
        }
-       cmd = exec.Command("go", "tool", "link", "-H", "linux", "-E", "main",
+       cmd = exec.Command("go", "tool", "link", "-H", "linux",
                "-o", pclinetestBinary, pclinetestBinary+".o")
        cmd.Stdout = os.Stdout
        cmd.Stderr = os.Stderr
index 5a68f06e1c94bc12e86fb2f91035fe3c1b3d4435..66a48a3f6f74d285de2d524b4b2ca18044d52011 100644 (file)
@@ -171,7 +171,7 @@ func TestDecodeCorrupt(t *testing.T) {
                _, err := StdEncoding.Decode(dbuf, []byte(tc.input))
                if tc.offset == -1 {
                        if err != nil {
-                               t.Error("Decoder wrongly detected coruption in", tc.input)
+                               t.Error("Decoder wrongly detected corruption in", tc.input)
                        }
                        continue
                }
index fc6a1ea654f75cae6721a366af336dd80f54f105..eebf113212a17122a188623dc13adbd861f2b80d 100644 (file)
@@ -221,7 +221,7 @@ func TestDecodeCorrupt(t *testing.T) {
                _, err := StdEncoding.Decode(dbuf, []byte(tc.input))
                if tc.offset == -1 {
                        if err != nil {
-                               t.Error("Decoder wrongly detected coruption in", tc.input)
+                               t.Error("Decoder wrongly detected corruption in", tc.input)
                        }
                        continue
                }
index a6bb780bf28a0b76de6fd02e323665d1db8cd5fc..816ed26754277673433b9c4afc7e541acf2c0b3e 100644 (file)
@@ -99,6 +99,8 @@ var (
 // non-doubled quote may appear in a quoted field.
 //
 // If TrimLeadingSpace is true, leading white space in a field is ignored.
+// If the field delimiter is white space, TrimLeadingSpace will trim the
+// delimiter.
 type Reader struct {
        Comma            rune // field delimiter (set to ',' by NewReader)
        Comment          rune // comment character for start of line
index ed89d1156eda8ef31a9ce243974acf1e987e1159..8a514e58cd08f462f49bd34caf9ccdee3b088a27 100644 (file)
@@ -158,7 +158,7 @@ func BenchmarkCodeUnmarshal(b *testing.B) {
        for i := 0; i < b.N; i++ {
                var r codeResponse
                if err := Unmarshal(codeJSON, &r); err != nil {
-                       b.Fatal("Unmmarshal:", err)
+                       b.Fatal("Unmarshal:", err)
                }
        }
        b.SetBytes(int64(len(codeJSON)))
@@ -173,7 +173,7 @@ func BenchmarkCodeUnmarshalReuse(b *testing.B) {
        var r codeResponse
        for i := 0; i < b.N; i++ {
                if err := Unmarshal(codeJSON, &r); err != nil {
-                       b.Fatal("Unmmarshal:", err)
+                       b.Fatal("Unmarshal:", err)
                }
        }
 }
index 24c2d6b29ab4221928104eb052ff693bb223f733..1d51bc97f9f5bf5ca6e5996c62f7dbe7943b9cda 100644 (file)
@@ -258,7 +258,8 @@ func Publish(name string, v Var) {
        sort.Strings(varKeys)
 }
 
-// Get retrieves a named exported variable.
+// Get retrieves a named exported variable. It returns nil if the name has
+// not been registered.
 func Get(name string) Var {
        mutex.RLock()
        defer mutex.RUnlock()
index 8bc633e4a9767acd61bd28e6cd6578b3046eca70..385fea81adbba98fa8467a716b1c19e8dc933dd0 100644 (file)
@@ -26,6 +26,14 @@ func RemoveAll() {
        varKeys = nil
 }
 
+func TestNil(t *testing.T) {
+       RemoveAll()
+       val := Get("missing")
+       if val != nil {
+               t.Errorf("got %v, want nil", val)
+       }
+}
+
 func TestInt(t *testing.T) {
        RemoveAll()
        reqs := NewInt("requests")
index 1d9d015f4ab426e1612da5cc4d8d24502611b1e1..05187af29e31c0fd675f441d368a3c277dc9494b 100644 (file)
@@ -674,6 +674,10 @@ var fmtTests = []struct {
        // Make sure we can handle very large widths.
        {"%0100f", -1.0, zeroFill("-", 99, "1.000000")},
 
+       // Use spaces instead of zero if padding to the right.
+       {"%0-5s", "abc", "abc  "},
+       {"%-05.1f", 1.0, "1.0  "},
+
        // Complex fmt used to leave the plus flag set for future entries in the array
        // causing +2+0i and +3+0i instead of 2+0i and 3+0i.
        {"%v", []complex64{1, 2, 3}, "[(1+0i) (2+0i) (3+0i)]"},
@@ -884,6 +888,14 @@ func TestReorder(t *testing.T) {
        }
 }
 
+func BenchmarkSprintfPadding(b *testing.B) {
+       b.RunParallel(func(pb *testing.PB) {
+               for pb.Next() {
+                       Sprintf("%16f", 1.0)
+               }
+       })
+}
+
 func BenchmarkSprintfEmpty(b *testing.B) {
        b.RunParallel(func(pb *testing.PB) {
                for pb.Next() {
@@ -931,6 +943,13 @@ func BenchmarkSprintfFloat(b *testing.B) {
                }
        })
 }
+func BenchmarkSprintfBoolean(b *testing.B) {
+       b.RunParallel(func(pb *testing.PB) {
+               for pb.Next() {
+                       Sprintf("%t", true)
+               }
+       })
+}
 
 func BenchmarkManyArgs(b *testing.B) {
        b.RunParallel(func(pb *testing.PB) {
index c811cc6a3d9d1b2a109ce7c91229da95259bf3b5..f7ac04722923291b89100542071d7176e53e9b85 100644 (file)
@@ -23,16 +23,6 @@ const (
        unsigned = false
 )
 
-var padZeroBytes = make([]byte, nByte)
-var padSpaceBytes = make([]byte, nByte)
-
-func init() {
-       for i := 0; i < nByte; i++ {
-               padZeroBytes[i] = '0'
-               padSpaceBytes[i] = ' '
-       }
-}
-
 // flags placed in a separate struct for easy clearing.
 type fmtFlags struct {
        widPresent  bool
@@ -72,84 +62,74 @@ func (f *fmt) init(buf *buffer) {
        f.clearflags()
 }
 
-// computePadding computes left and right padding widths (only one will be non-zero).
-func (f *fmt) computePadding(width int) (padding []byte, leftWidth, rightWidth int) {
-       left := !f.minus
-       w := f.wid
-       if w < 0 {
-               left = false
-               w = -w
-       }
-       w -= width
-       if w > 0 {
-               if left && f.zero {
-                       return padZeroBytes, w, 0
-               }
-               if left {
-                       return padSpaceBytes, w, 0
-               } else {
-                       // can't be zero padding on the right
-                       return padSpaceBytes, 0, w
-               }
-       }
-       return
-}
-
 // writePadding generates n bytes of padding.
-func (f *fmt) writePadding(n int, padding []byte) {
-       for n > 0 {
-               m := n
-               if m > nByte {
-                       m = nByte
-               }
-               f.buf.Write(padding[0:m])
-               n -= m
+func (f *fmt) writePadding(n int) {
+       if n <= 0 { // No padding bytes needed.
+               return
        }
+       buf := *f.buf
+       oldLen := len(buf)
+       newLen := oldLen + n
+       // Make enough room for padding.
+       if newLen > cap(buf) {
+               buf = make(buffer, cap(buf)*2+n)
+               copy(buf, *f.buf)
+       }
+       // Decide which byte the padding should be filled with.
+       padByte := byte(' ')
+       if f.zero {
+               padByte = byte('0')
+       }
+       // Fill padding with padByte.
+       padding := buf[oldLen:newLen]
+       for i := range padding {
+               padding[i] = padByte
+       }
+       *f.buf = buf[:newLen]
 }
 
-// pad appends b to f.buf, padded on left (w > 0) or right (w < 0 or f.minus).
+// pad appends b to f.buf, padded on left (!f.minus) or right (f.minus).
 func (f *fmt) pad(b []byte) {
        if !f.widPresent || f.wid == 0 {
                f.buf.Write(b)
                return
        }
-       padding, left, right := f.computePadding(utf8.RuneCount(b))
-       if left > 0 {
-               f.writePadding(left, padding)
-       }
-       f.buf.Write(b)
-       if right > 0 {
-               f.writePadding(right, padding)
+       width := f.wid - utf8.RuneCount(b)
+       if !f.minus {
+               // left padding
+               f.writePadding(width)
+               f.buf.Write(b)
+       } else {
+               // right padding
+               f.buf.Write(b)
+               f.writePadding(width)
        }
 }
 
-// padString appends s to buf, padded on left (w > 0) or right (w < 0 or f.minus).
+// padString appends s to f.buf, padded on left (!f.minus) or right (f.minus).
 func (f *fmt) padString(s string) {
        if !f.widPresent || f.wid == 0 {
                f.buf.WriteString(s)
                return
        }
-       padding, left, right := f.computePadding(utf8.RuneCountInString(s))
-       if left > 0 {
-               f.writePadding(left, padding)
-       }
-       f.buf.WriteString(s)
-       if right > 0 {
-               f.writePadding(right, padding)
+       width := f.wid - utf8.RuneCountInString(s)
+       if !f.minus {
+               // left padding
+               f.writePadding(width)
+               f.buf.WriteString(s)
+       } else {
+               // right padding
+               f.buf.WriteString(s)
+               f.writePadding(width)
        }
 }
 
-var (
-       trueBytes  = []byte("true")
-       falseBytes = []byte("false")
-)
-
 // fmt_boolean formats a boolean.
 func (f *fmt) fmt_boolean(v bool) {
        if v {
-               f.pad(trueBytes)
+               f.padString("true")
        } else {
-               f.pad(falseBytes)
+               f.padString("false")
        }
 }
 
@@ -526,5 +506,5 @@ func (f *fmt) fmt_complex(r, j float64, size int, verb rune) {
        f.space = oldSpace
        f.plus = oldPlus
        f.wid = oldWid
-       f.buf.Write(irparenBytes)
+       f.buf.WriteString("i)")
 }
index ebfa13e4d370a16515f064c3d7930fbf3379463b..b59599da65437fd2a9794e12fd2fad6ef2055339 100644 (file)
@@ -13,24 +13,24 @@ import (
        "unicode/utf8"
 )
 
-// Some constants in the form of bytes, to avoid string overhead.
-// Needlessly fastidious, I suppose.
-var (
-       commaSpaceBytes  = []byte(", ")
-       nilAngleBytes    = []byte("<nil>")
-       nilParenBytes    = []byte("(nil)")
-       nilBytes         = []byte("nil")
-       mapBytes         = []byte("map[")
-       percentBangBytes = []byte("%!")
-       missingBytes     = []byte("(MISSING)")
-       badIndexBytes    = []byte("(BADINDEX)")
-       panicBytes       = []byte("(PANIC=")
-       extraBytes       = []byte("%!(EXTRA ")
-       irparenBytes     = []byte("i)")
-       bytesBytes       = []byte("[]byte{")
-       badWidthBytes    = []byte("%!(BADWIDTH)")
-       badPrecBytes     = []byte("%!(BADPREC)")
-       noVerbBytes      = []byte("%!(NOVERB)")
+// Strings for use with buffer.WriteString.
+// This is less overhead than using buffer.Write with byte arrays.
+const (
+       commaSpaceString  = ", "
+       nilAngleString    = "<nil>"
+       nilParenString    = "(nil)"
+       nilString         = "nil"
+       mapString         = "map["
+       percentBangString = "%!"
+       missingString     = "(MISSING)"
+       badIndexString    = "(BADINDEX)"
+       panicString       = "(PANIC="
+       extraString       = "%!(EXTRA "
+       bytesString       = "[]byte{"
+       badWidthString    = "%!(BADWIDTH)"
+       badPrecString     = "%!(BADPREC)"
+       noVerbString      = "%!(NOVERB)"
+       invReflectString  = "<invalid reflect.Value>"
 )
 
 // State represents the printer state passed to custom formatters.
@@ -75,25 +75,22 @@ type GoStringer interface {
 // Use simple []byte instead of bytes.Buffer to avoid large dependency.
 type buffer []byte
 
-func (b *buffer) Write(p []byte) (n int, err error) {
+func (b *buffer) Write(p []byte) {
        *b = append(*b, p...)
-       return len(p), nil
 }
 
-func (b *buffer) WriteString(s string) (n int, err error) {
+func (b *buffer) WriteString(s string) {
        *b = append(*b, s...)
-       return len(s), nil
 }
 
-func (b *buffer) WriteByte(c byte) error {
+func (b *buffer) WriteByte(c byte) {
        *b = append(*b, c)
-       return nil
 }
 
-func (bp *buffer) WriteRune(r rune) error {
+func (bp *buffer) WriteRune(r rune) {
        if r < utf8.RuneSelf {
                *bp = append(*bp, byte(r))
-               return nil
+               return
        }
 
        b := *bp
@@ -103,7 +100,6 @@ func (bp *buffer) WriteRune(r rune) error {
        }
        w := utf8.EncodeRune(b[n:n+utf8.UTFMax], r)
        *bp = b[:n+w]
-       return nil
 }
 
 type pp struct {
@@ -169,14 +165,11 @@ func (p *pp) Flag(b int) bool {
        return false
 }
 
-func (p *pp) add(c rune) {
-       p.buf.WriteRune(c)
-}
-
 // Implement Write so we can call Fprintf on a pp (through State), for
 // recursive use in custom verbs.
 func (p *pp) Write(b []byte) (ret int, err error) {
-       return p.buf.Write(b)
+       p.buf.Write(b)
+       return len(b), nil
 }
 
 // These routines end in 'f' and take a format string.
@@ -309,7 +302,7 @@ func parsenum(s string, start, end int) (num int, isnum bool, newi int) {
 
 func (p *pp) unknownType(v reflect.Value) {
        if !v.IsValid() {
-               p.buf.Write(nilAngleBytes)
+               p.buf.WriteString(nilAngleString)
                return
        }
        p.buf.WriteByte('?')
@@ -319,23 +312,22 @@ func (p *pp) unknownType(v reflect.Value) {
 
 func (p *pp) badVerb(verb rune) {
        p.erroring = true
-       p.add('%')
-       p.add('!')
-       p.add(verb)
-       p.add('(')
+       p.buf.WriteString(percentBangString)
+       p.buf.WriteRune(verb)
+       p.buf.WriteByte('(')
        switch {
        case p.arg != nil:
                p.buf.WriteString(reflect.TypeOf(p.arg).String())
-               p.add('=')
+               p.buf.WriteByte('=')
                p.printArg(p.arg, 'v', 0)
        case p.value.IsValid():
                p.buf.WriteString(p.value.Type().String())
-               p.add('=')
+               p.buf.WriteByte('=')
                p.printValue(p.value, 'v', 0)
        default:
-               p.buf.Write(nilAngleBytes)
+               p.buf.WriteString(nilAngleString)
        }
-       p.add(')')
+       p.buf.WriteByte(')')
        p.erroring = false
 }
 
@@ -538,12 +530,12 @@ func (p *pp) fmtBytes(v []byte, verb rune, typ reflect.Type, depth int) {
                                        p.buf.WriteString("[]byte(nil)")
                                } else {
                                        p.buf.WriteString(typ.String())
-                                       p.buf.Write(nilParenBytes)
+                                       p.buf.WriteString(nilParenString)
                                }
                                return
                        }
                        if typ == nil {
-                               p.buf.Write(bytesBytes)
+                               p.buf.WriteString(bytesString)
                        } else {
                                p.buf.WriteString(typ.String())
                                p.buf.WriteByte('{')
@@ -554,7 +546,7 @@ func (p *pp) fmtBytes(v []byte, verb rune, typ reflect.Type, depth int) {
                for i, c := range v {
                        if i > 0 {
                                if p.fmt.sharpV {
-                                       p.buf.Write(commaSpaceBytes)
+                                       p.buf.WriteString(commaSpaceString)
                                } else {
                                        p.buf.WriteByte(' ')
                                }
@@ -605,18 +597,17 @@ func (p *pp) fmtPointer(value reflect.Value, verb rune) {
        }
 
        if p.fmt.sharpV {
-               p.add('(')
+               p.buf.WriteByte('(')
                p.buf.WriteString(value.Type().String())
-               p.add(')')
-               p.add('(')
+               p.buf.WriteString(")(")
                if u == 0 {
-                       p.buf.Write(nilBytes)
+                       p.buf.WriteString(nilString)
                } else {
                        p.fmt0x64(uint64(u), true)
                }
-               p.add(')')
+               p.buf.WriteByte(')')
        } else if verb == 'v' && u == 0 {
-               p.buf.Write(nilAngleBytes)
+               p.buf.WriteString(nilAngleString)
        } else {
                if use0x64 {
                        p.fmt0x64(uint64(u), !p.fmt.sharp)
@@ -637,7 +628,7 @@ func (p *pp) catchPanic(arg interface{}, verb rune) {
                // Stringer that fails to guard against nil or a nil pointer for a
                // value receiver, and in either case, "<nil>" is a nice result.
                if v := reflect.ValueOf(arg); v.Kind() == reflect.Ptr && v.IsNil() {
-                       p.buf.Write(nilAngleBytes)
+                       p.buf.WriteString(nilAngleString)
                        return
                }
                // Otherwise print a concise panic message. Most of the time the panic
@@ -647,9 +638,9 @@ func (p *pp) catchPanic(arg interface{}, verb rune) {
                        panic(err)
                }
                p.fmt.clearflags() // We are done, and for this output we want default behavior.
-               p.buf.Write(percentBangBytes)
-               p.add(verb)
-               p.buf.Write(panicBytes)
+               p.buf.WriteString(percentBangString)
+               p.buf.WriteRune(verb)
+               p.buf.WriteString(panicString)
                p.panicking = true
                p.printArg(err, 'v', 0)
                p.panicking = false
@@ -741,7 +732,7 @@ func (p *pp) printArg(arg interface{}, verb rune, depth int) (wasString bool) {
 
        if arg == nil {
                if verb == 'T' || verb == 'v' {
-                       p.fmt.pad(nilAngleBytes)
+                       p.fmt.padString(nilAngleString)
                } else {
                        p.badVerb(verb)
                }
@@ -817,7 +808,7 @@ func (p *pp) printArg(arg interface{}, verb rune, depth int) (wasString bool) {
 func (p *pp) printValue(value reflect.Value, verb rune, depth int) (wasString bool) {
        if !value.IsValid() {
                if verb == 'T' || verb == 'v' {
-                       p.buf.Write(nilAngleBytes)
+                       p.buf.WriteString(nilAngleString)
                } else {
                        p.badVerb(verb)
                }
@@ -858,7 +849,7 @@ func (p *pp) printReflectValue(value reflect.Value, verb rune, depth int) (wasSt
 BigSwitch:
        switch f := value; f.Kind() {
        case reflect.Invalid:
-               p.buf.WriteString("<invalid reflect.Value>")
+               p.buf.WriteString(invReflectString)
        case reflect.Bool:
                p.fmtBool(f.Bool(), verb)
        case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
@@ -883,18 +874,18 @@ BigSwitch:
                if p.fmt.sharpV {
                        p.buf.WriteString(f.Type().String())
                        if f.IsNil() {
-                               p.buf.WriteString("(nil)")
+                               p.buf.WriteString(nilParenString)
                                break
                        }
                        p.buf.WriteByte('{')
                } else {
-                       p.buf.Write(mapBytes)
+                       p.buf.WriteString(mapString)
                }
                keys := f.MapKeys()
                for i, key := range keys {
                        if i > 0 {
                                if p.fmt.sharpV {
-                                       p.buf.Write(commaSpaceBytes)
+                                       p.buf.WriteString(commaSpaceString)
                                } else {
                                        p.buf.WriteByte(' ')
                                }
@@ -912,13 +903,13 @@ BigSwitch:
                if p.fmt.sharpV {
                        p.buf.WriteString(value.Type().String())
                }
-               p.add('{')
+               p.buf.WriteByte('{')
                v := f
                t := v.Type()
                for i := 0; i < v.NumField(); i++ {
                        if i > 0 {
                                if p.fmt.sharpV {
-                                       p.buf.Write(commaSpaceBytes)
+                                       p.buf.WriteString(commaSpaceString)
                                } else {
                                        p.buf.WriteByte(' ')
                                }
@@ -937,9 +928,9 @@ BigSwitch:
                if !value.IsValid() {
                        if p.fmt.sharpV {
                                p.buf.WriteString(f.Type().String())
-                               p.buf.Write(nilParenBytes)
+                               p.buf.WriteString(nilParenString)
                        } else {
-                               p.buf.Write(nilAngleBytes)
+                               p.buf.WriteString(nilAngleString)
                        }
                } else {
                        wasString = p.printValue(value, verb, depth+1)
@@ -982,7 +973,7 @@ BigSwitch:
                for i := 0; i < f.Len(); i++ {
                        if i > 0 {
                                if p.fmt.sharpV {
-                                       p.buf.Write(commaSpaceBytes)
+                                       p.buf.WriteString(commaSpaceString)
                                } else {
                                        p.buf.WriteByte(' ')
                                }
@@ -1149,7 +1140,7 @@ func (p *pp) doPrintf(format string, a []interface{}) {
                        p.fmt.wid, p.fmt.widPresent, argNum = intFromArg(a, argNum)
 
                        if !p.fmt.widPresent {
-                               p.buf.Write(badWidthBytes)
+                               p.buf.WriteString(badWidthString)
                        }
 
                        // We have a negative width, so take its value and ensure
@@ -1182,7 +1173,7 @@ func (p *pp) doPrintf(format string, a []interface{}) {
                                        p.fmt.precPresent = false
                                }
                                if !p.fmt.precPresent {
-                                       p.buf.Write(badPrecBytes)
+                                       p.buf.WriteString(badPrecString)
                                }
                                afterIndex = false
                        } else {
@@ -1199,7 +1190,7 @@ func (p *pp) doPrintf(format string, a []interface{}) {
                }
 
                if i >= end {
-                       p.buf.Write(noVerbBytes)
+                       p.buf.WriteString(noVerbString)
                        continue
                }
                c, w := utf8.DecodeRuneInString(format[i:])
@@ -1210,14 +1201,14 @@ func (p *pp) doPrintf(format string, a []interface{}) {
                        continue
                }
                if !p.goodArgNum {
-                       p.buf.Write(percentBangBytes)
-                       p.add(c)
-                       p.buf.Write(badIndexBytes)
+                       p.buf.WriteString(percentBangString)
+                       p.buf.WriteRune(c)
+                       p.buf.WriteString(badIndexString)
                        continue
                } else if argNum >= len(a) { // out of operands
-                       p.buf.Write(percentBangBytes)
-                       p.add(c)
-                       p.buf.Write(missingBytes)
+                       p.buf.WriteString(percentBangString)
+                       p.buf.WriteRune(c)
+                       p.buf.WriteString(missingString)
                        continue
                }
                arg := a[argNum]
@@ -1235,6 +1226,12 @@ func (p *pp) doPrintf(format string, a []interface{}) {
                                p.fmt.plusV = true
                        }
                }
+
+               // Use space padding instead of zero padding to the right.
+               if p.fmt.minus {
+                       p.fmt.zero = false
+               }
+
                p.printArg(arg, c, 0)
        }
 
@@ -1242,7 +1239,7 @@ func (p *pp) doPrintf(format string, a []interface{}) {
        // out of order, in which case it's too expensive to detect if they've all
        // been used and arguably OK if they're not.
        if !p.reordered && argNum < len(a) {
-               p.buf.Write(extraBytes)
+               p.buf.WriteString(extraString)
                for ; argNum < len(a); argNum++ {
                        arg := a[argNum]
                        if arg != nil {
@@ -1251,7 +1248,7 @@ func (p *pp) doPrintf(format string, a []interface{}) {
                        }
                        p.printArg(arg, 'v', 0)
                        if argNum+1 < len(a) {
-                               p.buf.Write(commaSpaceBytes)
+                               p.buf.WriteString(commaSpaceString)
                        }
                }
                p.buf.WriteByte(')')
index 4618ed4a827f4ee41e10f7f53fb3796bf161b984..fa63e4983a5f099817ec6160e1cb3f72fc95748e 100644 (file)
@@ -15,14 +15,6 @@ import (
        "unicode/utf8"
 )
 
-// runeUnreader is the interface to something that can unread runes.
-// If the object provided to Scan does not satisfy this interface,
-// a local buffer will be used to back up the input, but its contents
-// will be lost when Scan returns.
-type runeUnreader interface {
-       UnreadRune() error
-}
-
 // ScanState represents the scanner state passed to custom scanners.
 // Scanners may do rune-at-a-time scanning or ask the ScanState
 // to discover the next space-delimited token.
@@ -163,12 +155,10 @@ const eof = -1
 
 // ss is the internal implementation of ScanState.
 type ss struct {
-       rr       io.RuneReader // where to read input
-       buf      buffer        // token accumulator
-       peekRune rune          // one-rune lookahead
-       prevRune rune          // last rune returned by ReadRune
-       count    int           // runes consumed so far.
-       atEOF    bool          // already read EOF
+       rs    io.RuneScanner // where to read input
+       buf   buffer         // token accumulator
+       count int            // runes consumed so far.
+       atEOF bool           // already read EOF
        ssave
 }
 
@@ -191,23 +181,17 @@ func (s *ss) Read(buf []byte) (n int, err error) {
 }
 
 func (s *ss) ReadRune() (r rune, size int, err error) {
-       if s.peekRune >= 0 {
-               s.count++
-               r = s.peekRune
-               size = utf8.RuneLen(r)
-               s.prevRune = r
-               s.peekRune = -1
-               return
-       }
-       if s.atEOF || s.nlIsEnd && s.prevRune == '\n' || s.count >= s.argLimit {
+       if s.atEOF || s.count >= s.argLimit {
                err = io.EOF
                return
        }
 
-       r, size, err = s.rr.ReadRune()
+       r, size, err = s.rs.ReadRune()
        if err == nil {
                s.count++
-               s.prevRune = r
+               if s.nlIsEnd && r == '\n' {
+                       s.atEOF = true
+               }
        } else if err == io.EOF {
                s.atEOF = true
        }
@@ -246,12 +230,8 @@ func (s *ss) mustReadRune() (r rune) {
 }
 
 func (s *ss) UnreadRune() error {
-       if u, ok := s.rr.(runeUnreader); ok {
-               u.UnreadRune()
-       } else {
-               s.peekRune = s.prevRune
-       }
-       s.prevRune = -1
+       s.rs.UnreadRune()
+       s.atEOF = false
        s.count--
        return nil
 }
@@ -326,13 +306,14 @@ func (s *ss) SkipSpace() {
 }
 
 // readRune is a structure to enable reading UTF-8 encoded code points
-// from an io.Reader.  It is used if the Reader given to the scanner does
-// not already implement io.RuneReader.
+// from an io.Reader. It is used if the Reader given to the scanner does
+// not already implement io.RuneScanner.
 type readRune struct {
-       reader  io.Reader
-       buf     [utf8.UTFMax]byte // used only inside ReadRune
-       pending int               // number of bytes in pendBuf; only >0 for bad UTF-8
-       pendBuf [utf8.UTFMax]byte // bytes left over
+       reader   io.Reader
+       buf      [utf8.UTFMax]byte // used only inside ReadRune
+       pending  int               // number of bytes in pendBuf; only >0 for bad UTF-8
+       pendBuf  [utf8.UTFMax]byte // bytes left over
+       peekRune rune              // if >=0 next rune; when <0 is ^(previous Rune)
 }
 
 // readByte returns the next byte from the input, which may be
@@ -344,33 +325,35 @@ func (r *readRune) readByte() (b byte, err error) {
                r.pending--
                return
        }
-       n, err := io.ReadFull(r.reader, r.pendBuf[0:1])
-       if n != 1 {
-               return 0, err
+       _, err = r.reader.Read(r.pendBuf[:1])
+       if err != nil {
+               return
        }
        return r.pendBuf[0], err
 }
 
-// unread saves the bytes for the next read.
-func (r *readRune) unread(buf []byte) {
-       copy(r.pendBuf[r.pending:], buf)
-       r.pending += len(buf)
-}
-
 // ReadRune returns the next UTF-8 encoded code point from the
 // io.Reader inside r.
 func (r *readRune) ReadRune() (rr rune, size int, err error) {
+       if r.peekRune >= 0 {
+               rr = r.peekRune
+               r.peekRune = ^r.peekRune
+               size = utf8.RuneLen(rr)
+               return
+       }
        r.buf[0], err = r.readByte()
        if err != nil {
-               return 0, 0, err
+               return
        }
        if r.buf[0] < utf8.RuneSelf { // fast check for common ASCII case
                rr = rune(r.buf[0])
                size = 1 // Known to be 1.
+               // Flip the bits of the rune so it's available to UnreadRune.
+               r.peekRune = ^rr
                return
        }
        var n int
-       for n = 1; !utf8.FullRune(r.buf[0:n]); n++ {
+       for n = 1; !utf8.FullRune(r.buf[:n]); n++ {
                r.buf[n], err = r.readByte()
                if err != nil {
                        if err == io.EOF {
@@ -380,13 +363,25 @@ func (r *readRune) ReadRune() (rr rune, size int, err error) {
                        return
                }
        }
-       rr, size = utf8.DecodeRune(r.buf[0:n])
-       if size < n { // an error
-               r.unread(r.buf[size:n])
+       rr, size = utf8.DecodeRune(r.buf[:n])
+       if size < n { // an error, save the bytes for the next read
+               copy(r.pendBuf[r.pending:], r.buf[size:n])
+               r.pending += n - size
        }
+       // Flip the bits of the rune so it's available to UnreadRune.
+       r.peekRune = ^rr
        return
 }
 
+func (r *readRune) UnreadRune() error {
+       if r.peekRune >= 0 {
+               return errors.New("fmt: scanning called UnreadRune with no rune available")
+       }
+       // Reverse bit flip of previously read rune to obtain valid >=0 state.
+       r.peekRune = ^r.peekRune
+       return nil
+}
+
 var ssFree = sync.Pool{
        New: func() interface{} { return new(ss) },
 }
@@ -394,15 +389,13 @@ var ssFree = sync.Pool{
 // newScanState allocates a new ss struct or grab a cached one.
 func newScanState(r io.Reader, nlIsSpace, nlIsEnd bool) (s *ss, old ssave) {
        s = ssFree.Get().(*ss)
-       if rr, ok := r.(io.RuneReader); ok {
-               s.rr = rr
+       if rs, ok := r.(io.RuneScanner); ok {
+               s.rs = rs
        } else {
-               s.rr = &readRune{reader: r}
+               s.rs = &readRune{reader: r, peekRune: -1}
        }
        s.nlIsSpace = nlIsSpace
        s.nlIsEnd = nlIsEnd
-       s.prevRune = -1
-       s.peekRune = -1
        s.atEOF = false
        s.limit = hugeWid
        s.argLimit = hugeWid
@@ -424,7 +417,7 @@ func (s *ss) free(old ssave) {
                return
        }
        s.buf = s.buf[:0]
-       s.rr = nil
+       s.rs = nil
        ssFree.Put(s)
 }
 
@@ -846,7 +839,7 @@ func (s *ss) quotedString() string {
                return string(s.buf)
        case '"':
                // Double-quoted: Include the quotes and let strconv.Unquote do the backslash escapes.
-               s.buf.WriteRune(quote)
+               s.buf.WriteByte('"')
                for {
                        r := s.mustReadRune()
                        s.buf.WriteRune(r)
@@ -1142,7 +1135,7 @@ func (s *ss) advance(format string) (i int) {
 }
 
 // doScanf does the real work when scanning with a format string.
-//  At the moment, it handles only pointers to basic types.
+// At the moment, it handles only pointers to basic types.
 func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err error) {
        defer errorHandler(&err)
        end := len(format) - 1
index ce6f08659acfda6420f884eb080f8e2bbafd4644..3302a7ca2dbd186e4e59d865f0171b65c2383480 100644 (file)
@@ -1001,6 +1001,18 @@ func BenchmarkScanRecursiveInt(b *testing.B) {
        }
 }
 
+func BenchmarkScanRecursiveIntReaderWrapper(b *testing.B) {
+       b.ResetTimer()
+       ints := makeInts(intCount)
+       var r RecursiveInt
+       for i := b.N - 1; i >= 0; i-- {
+               buf := newReader(string(ints))
+               b.StartTimer()
+               Fscan(buf, &r)
+               b.StopTimer()
+       }
+}
+
 // Issue 9124.
 // %x on bytes couldn't handle non-space bytes terminating the scan.
 func TestHexBytes(t *testing.T) {
index c1b70bcdd75133f35d74eed2ca251e718f52c8f5..d3b83b9f4687eb398138a8baf1f87e79d6d25899 100644 (file)
@@ -256,34 +256,6 @@ func (ctxt *Context) SrcDirs() []string {
 // if set, or else the compiled code's GOARCH, GOOS, and GOROOT.
 var Default Context = defaultContext()
 
-// Also known to cmd/dist/build.go.
-var cgoEnabled = map[string]bool{
-       "darwin/386":      true,
-       "darwin/amd64":    true,
-       "darwin/arm":      true,
-       "darwin/arm64":    true,
-       "dragonfly/amd64": true,
-       "freebsd/386":     true,
-       "freebsd/amd64":   true,
-       "freebsd/arm":     true,
-       "linux/386":       true,
-       "linux/amd64":     true,
-       "linux/arm":       true,
-       "linux/arm64":     true,
-       "linux/ppc64le":   true,
-       "android/386":     true,
-       "android/amd64":   true,
-       "android/arm":     true,
-       "netbsd/386":      true,
-       "netbsd/amd64":    true,
-       "netbsd/arm":      true,
-       "openbsd/386":     true,
-       "openbsd/amd64":   true,
-       "solaris/amd64":   true,
-       "windows/386":     true,
-       "windows/amd64":   true,
-}
-
 func defaultContext() Context {
        var c Context
 
@@ -386,6 +358,7 @@ type Package struct {
        CXXFiles       []string // .cc, .cpp and .cxx source files
        MFiles         []string // .m (Objective-C) source files
        HFiles         []string // .h, .hh, .hpp and .hxx source files
+       FFiles         []string // .f, .F, .for and .f90 Fortran source files
        SFiles         []string // .s source files
        SwigFiles      []string // .swig files
        SwigCXXFiles   []string // .swigcxx files
@@ -395,6 +368,7 @@ type Package struct {
        CgoCFLAGS    []string // Cgo CFLAGS directives
        CgoCPPFLAGS  []string // Cgo CPPFLAGS directives
        CgoCXXFLAGS  []string // Cgo CXXFLAGS directives
+       CgoFFLAGS    []string // Cgo FFLAGS directives
        CgoLDFLAGS   []string // Cgo LDFLAGS directives
        CgoPkgConfig []string // Cgo pkg-config directives
 
@@ -731,6 +705,9 @@ Found:
                case ".h", ".hh", ".hpp", ".hxx":
                        p.HFiles = append(p.HFiles, name)
                        continue
+               case ".f", ".F", ".for", ".f90":
+                       p.FFiles = append(p.FFiles, name)
+                       continue
                case ".s":
                        p.SFiles = append(p.SFiles, name)
                        continue
@@ -1045,7 +1022,7 @@ func (ctxt *Context) matchFile(dir, name string, returnImports bool, allTags map
        }
 
        switch ext {
-       case ".go", ".c", ".cc", ".cxx", ".cpp", ".m", ".s", ".h", ".hh", ".hpp", ".hxx", ".S", ".swig", ".swigcxx":
+       case ".go", ".c", ".cc", ".cxx", ".cpp", ".m", ".s", ".h", ".hh", ".hpp", ".hxx", ".f", ".F", ".f90", ".S", ".swig", ".swigcxx":
                // tentatively okay - read to make sure
        case ".syso":
                // binary, no reading
@@ -1236,6 +1213,8 @@ func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup)
                        di.CgoCPPFLAGS = append(di.CgoCPPFLAGS, args...)
                case "CXXFLAGS":
                        di.CgoCXXFLAGS = append(di.CgoCXXFLAGS, args...)
+               case "FFLAGS":
+                       di.CgoFFLAGS = append(di.CgoFFLAGS, args...)
                case "LDFLAGS":
                        di.CgoLDFLAGS = append(di.CgoLDFLAGS, args...)
                case "pkg-config":
@@ -1251,7 +1230,7 @@ func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup)
 // the result is safe for the shell.
 func expandSrcDir(str string, srcdir string) (string, bool) {
        // "\" delimited paths cause safeCgoName to fail
-       // so convert native paths with a different delimeter
+       // so convert native paths with a different delimiter
        // to "/" before starting (eg: on windows).
        srcdir = filepath.ToSlash(srcdir)
 
index 7312af08b57b14752dea88862d476dafa46041f7..9a473f41ec1850336f0f4de54c3e4c2d5f6be204 100644 (file)
@@ -155,15 +155,15 @@ func TestShouldBuild(t *testing.T) {
                t.Errorf("shouldBuild(file1) = false, want true")
        }
        if !reflect.DeepEqual(m, want1) {
-               t.Errorf("shoudBuild(file1) tags = %v, want %v", m, want1)
+               t.Errorf("shouldBuild(file1) tags = %v, want %v", m, want1)
        }
 
        m = map[string]bool{}
        if ctx.shouldBuild([]byte(file2), m) {
-               t.Errorf("shouldBuild(file2) = true, want fakse")
+               t.Errorf("shouldBuild(file2) = true, want false")
        }
        if !reflect.DeepEqual(m, want2) {
-               t.Errorf("shoudBuild(file2) tags = %v, want %v", m, want2)
+               t.Errorf("shouldBuild(file2) tags = %v, want %v", m, want2)
        }
 
        m = map[string]bool{}
@@ -172,7 +172,7 @@ func TestShouldBuild(t *testing.T) {
                t.Errorf("shouldBuild(file3) = false, want true")
        }
        if !reflect.DeepEqual(m, want3) {
-               t.Errorf("shoudBuild(file3) tags = %v, want %v", m, want3)
+               t.Errorf("shouldBuild(file3) tags = %v, want %v", m, want3)
        }
 }
 
index 18bea415ae49695174ab95be4dc2dec72cacf897..4c0d2fe7616588859cd4792017341909242bc462 100644 (file)
@@ -52,33 +52,11 @@ func FindExportData(r *bufio.Reader) (hdr string, err error) {
        if string(line) == "!<arch>\n" {
                // Archive file. Scan to __.PKGDEF.
                var name string
-               var size int
-               if name, size, err = readGopackHeader(r); err != nil {
+               if name, _, err = readGopackHeader(r); err != nil {
                        return
                }
 
-               // Optional leading __.GOSYMDEF or __.SYMDEF.
-               // Read and discard.
-               if name == "__.SYMDEF" || name == "__.GOSYMDEF" {
-                       const block = 4096
-                       tmp := make([]byte, block)
-                       for size > 0 {
-                               n := size
-                               if n > block {
-                                       n = block
-                               }
-                               if _, err = io.ReadFull(r, tmp[:n]); err != nil {
-                                       return
-                               }
-                               size -= n
-                       }
-
-                       if name, _, err = readGopackHeader(r); err != nil {
-                               return
-                       }
-               }
-
-               // First real entry should be __.PKGDEF.
+               // First entry should be __.PKGDEF.
                if name != "__.PKGDEF" {
                        err = errors.New("go archive is missing __.PKGDEF")
                        return
index 052277f4fe89acec47e2129ae83c495e03c944e1..b2848c3023696af3ccb8b4b3dd6ff09aa6369f32 100644 (file)
@@ -451,7 +451,7 @@ func (p *parser) parseMapType(parent *types.Package) types.Type {
 // For qualified names, the returned package is nil (and not created if
 // it doesn't exist yet) unless materializePkg is set (which creates an
 // unnamed package with valid package path). In the latter case, a
-// subequent import clause is expected to provide a name for the package.
+// subsequent import clause is expected to provide a name for the package.
 //
 func (p *parser) parseName(parent *types.Package, materializePkg bool) (pkg *types.Package, name string) {
        pkg = parent
index f3a26032eec448100159fd0255201158019d2aff..d3ef7db31eafbfe3c0f35007ce92e536bfebc8be 100644 (file)
@@ -1597,23 +1597,19 @@ func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr {
        }
 
        x := p.parseUnaryExpr(lhs)
-       for _, prec := p.tokPrec(); prec >= prec1; prec-- {
-               for {
-                       op, oprec := p.tokPrec()
-                       if oprec != prec {
-                               break
-                       }
-                       pos := p.expect(op)
-                       if lhs {
-                               p.resolve(x)
-                               lhs = false
-                       }
-                       y := p.parseBinaryExpr(false, prec+1)
-                       x = &ast.BinaryExpr{X: p.checkExpr(x), OpPos: pos, Op: op, Y: p.checkExpr(y)}
+       for {
+               op, oprec := p.tokPrec()
+               if oprec < prec1 {
+                       return x
+               }
+               pos := p.expect(op)
+               if lhs {
+                       p.resolve(x)
+                       lhs = false
                }
+               y := p.parseBinaryExpr(false, oprec+1)
+               x = &ast.BinaryExpr{X: p.checkExpr(x), OpPos: pos, Op: op, Y: p.checkExpr(y)}
        }
-
-       return x
 }
 
 // If lhs is set and the result is an identifier, it is not resolved.
index 803264fb585de442fd1f843b41aa6b78d88ada62..0082be9e2e95fd266679496cbe1d3f87035646f4 100644 (file)
@@ -366,7 +366,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
                        } else {
                                // an untyped non-constant argument may appear if
                                // it contains a (yet untyped non-constant) shift
-                               // epression: convert it to complex128 which will
+                               // expression: convert it to complex128 which will
                                // result in an error (shift of complex value)
                                check.convertUntyped(x, Typ[Complex128])
                                // x should be invalid now, but be conservative and check
index 716a5907ce3290d3e4d57449e00e0c192392d3d3..a61717887e02c732b340e35bcf86fc26990dcb67 100644 (file)
@@ -239,7 +239,7 @@ const (
 
 type A [iota /* ERROR "cannot use iota" */ ]int
 
-// constant expressions with operands accross different
+// constant expressions with operands across different
 // constant declarations must use the right iota values
 const (
        _c0 = iota
index 6f70d67de92595c83ec175bb0d02e177c9b8d63a..46df1f8d49562d3bc0057d9b827cff8c85e7e395 100644 (file)
@@ -13,7 +13,7 @@ func TestTemplateClone(t *testing.T) {
                t.Fatal(err)
        }
        if len(clone.Templates()) != len(orig.Templates()) {
-               t.Fatalf("Invalid lenth of t.Clone().Templates()")
+               t.Fatalf("Invalid length of t.Clone().Templates()")
        }
 
        const want = "stuff"
index 6a133124ad5bcb522d2266d2dfb52851920a0540..72b52e36e5764f796d19ad3652074417c719629c 100644 (file)
@@ -210,7 +210,7 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
                        // for an image". In practice, though, giflib (a widely used C
                        // library) does not enforce this, so we also accept lzwr returning
                        // io.ErrUnexpectedEOF (meaning that the encoded stream hit io.EOF
-                       // before the LZW decoder saw an explict end code), provided that
+                       // before the LZW decoder saw an explicit end code), provided that
                        // the io.ReadFull call above successfully read len(m.Pix) bytes.
                        // See https://golang.org/issue/9856 for an example GIF.
                        if n, err := lzwr.Read(d.tmp[:1]); n != 0 || (err != io.EOF && err != io.ErrUnexpectedEOF) {
diff --git a/src/internal/syscall/unix/getentropy_openbsd.go b/src/internal/syscall/unix/getentropy_openbsd.go
new file mode 100644 (file)
index 0000000..fd3dabc
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2016 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package unix
+
+import (
+       "syscall"
+       "unsafe"
+)
+
+// getentropy(2)'s syscall number, from /usr/src/sys/kern/syscalls.master
+const entropyTrap uintptr = 7
+
+// GetEntropy calls the OpenBSD getentropy system call.
+func GetEntropy(p []byte) error {
+       _, _, errno := syscall.Syscall(entropyTrap,
+               uintptr(unsafe.Pointer(&p[0])),
+               uintptr(len(p)),
+               0)
+       if errno != 0 {
+               return errno
+       }
+       return nil
+}
index a63c42022d159488e33c44dc6ae21c15b04f02ed..56069d7684d2880f471fb5d7f5f5c3dcb8defec3 100644 (file)
@@ -213,7 +213,7 @@ func enumerateValues(t *testing.T, k registry.Key) {
                }
        }
        for n, v := range haveNames {
-               t.Errorf("value %s (%v) is found while enumerating, but has not been cretaed", n, v)
+               t.Errorf("value %s (%v) is found while enumerating, but has not been created", n, v)
        }
 }
 
@@ -335,7 +335,7 @@ func testGetValue(t *testing.T, k registry.Key, test ValueTest, size int) {
        // read data with short buffer
        gotsize, gottype, err = k.GetValue(test.Name, make([]byte, size-1))
        if err == nil {
-               t.Errorf("GetValue(%s, [%d]byte) should fail, but suceeded", test.Name, size-1)
+               t.Errorf("GetValue(%s, [%d]byte) should fail, but succeeded", test.Name, size-1)
                return
        }
        if err != registry.ErrShortBuffer {
index 2531ca4bb33cfe466f53b0022d9f07df8f0e46e0..21cc29730da24d8b86c0ffd00c74f37207e9bcb3 100755 (executable)
@@ -44,6 +44,9 @@
 # This is used by cgo. Default is CXX, or, if that is not set, 
 # "g++" or "clang++".
 #
+# FC: Command line to run to compile Fortran code for GOARCH.
+# This is used by cgo. Default is "gfortran".
+#
 # GO_DISTFLAGS: extra flags to provide to "dist bootstrap".
 
 set -e
index 0efdcc576c1a92d21caa444d2dea13aae99d4751..a64777ee917d316985c1b93f37068b9932223b51 100644 (file)
@@ -31,6 +31,9 @@
 ::
 :: CC_FOR_TARGET: Command line to run compile C code for GOARCH.
 :: This is used by cgo. Default is CC.
+::
+:: FC: Command line to run to compile Fortran code.
+:: This is used by cgo. Default is "gfortran".
 
 @echo off
 
index b1c748c9a54daea4ec257f7f1056af0d488b1517..6460620bdeaf472d02fda546d7b77faf53f9097f 100644 (file)
@@ -1427,7 +1427,7 @@ func (z *Float) Add(x, y *Float) *Float {
        }
 
        if x.form == finite && y.form == finite {
-               // x + y (commom case)
+               // x + y (common case)
                z.neg = x.neg
                if x.neg == y.neg {
                        // x + y == x + y
index 37d5c06a6f33d6b132c665e7e17b55e28b6b6dea..a884df6fe1c4a27890d14f7da10b9ffb4bf9a274 100644 (file)
@@ -85,7 +85,7 @@ func (z *Float) scan(r io.ByteScanner, base int) (f *Float, b int, err error) {
        if fcount < 0 {
                // The mantissa has a "decimal" point ddd.dddd; and
                // -fcount is the number of digits to the right of '.'.
-               // Adjust relevant exponent accodingly.
+               // Adjust relevant exponent accordingly.
                d := int64(fcount)
                switch b {
                case 10:
index 5dc2a0368ceeb242593f306884a1ba25a94aecb4..5094ac4f1b790a64c342b6bb37225b83c3ac3d15 100644 (file)
@@ -161,7 +161,7 @@ func isDomainName(s string) bool {
        return ok
 }
 
-// absDomainName returns an absoulte domain name which ends with a
+// absDomainName returns an absolute domain name which ends with a
 // trailing dot to match pure Go reverse resolver and all other lookup
 // routines.
 // See golang.org/issue/12189.
index d7f00c784d55ccefd725ccbf38877c0235a2a184..4a5c438e46905845e3835c23c489a6f7eadfa6d0 100644 (file)
@@ -67,7 +67,7 @@ var specialDomainNameTests = []struct {
 
        // Name resolution APIs and libraries should recognize the
        // followings as special and should not send any queries.
-       // Though, we test those names here for verifying nagative
+       // Though, we test those names here for verifying negative
        // answers at DNS query-response interaction level.
        {"localhost.", dnsTypeALL, dnsRcodeNameError},
        {"invalid.", dnsTypeALL, dnsRcodeNameError},
@@ -355,7 +355,13 @@ func TestGoLookupIPWithResolverConfig(t *testing.T) {
                }
                addrs, err := goLookupIP(tt.name)
                if err != nil {
-                       if err, ok := err.(*DNSError); !ok || (err.Name != tt.error.(*DNSError).Name || err.Server != tt.error.(*DNSError).Server || err.IsTimeout != tt.error.(*DNSError).IsTimeout) {
+                       // This test uses external network connectivity.
+                       // We need to take care with errors on both
+                       // DNS message exchange layer and DNS
+                       // transport layer because goLookupIP may fail
+                       // when the IP connectivty on node under test
+                       // gets lost during its run.
+                       if err, ok := err.(*DNSError); !ok || tt.error != nil && (err.Name != tt.error.(*DNSError).Name || err.Server != tt.error.(*DNSError).Server || err.IsTimeout != tt.error.(*DNSError).IsTimeout) {
                                t.Errorf("got %v; want %v", err, tt.error)
                        }
                        continue
@@ -398,7 +404,7 @@ func TestGoLookupIPOrderFallbackToFile(t *testing.T) {
        for _, order := range []hostLookupOrder{hostLookupFilesDNS, hostLookupDNSFiles} {
                name := fmt.Sprintf("order %v", order)
 
-               // First ensure that we get an error when contacting a non-existant host.
+               // First ensure that we get an error when contacting a non-existent host.
                _, err := goLookupIPOrder("notarealhost", order)
                if err == nil {
                        t.Errorf("%s: expected error while looking up name not in hosts file", name)
index 8522ccebfb364315c2d5f57213d67b1d697a0a5a..5897e3d68c50631fbe15d5f51f08a46b26184ee5 100644 (file)
@@ -120,7 +120,13 @@ func (fd *netFD) setWriteDeadline(t time.Time) error {
 }
 
 func setDeadlineImpl(fd *netFD, t time.Time, mode int) error {
-       d := runtimeNano() + int64(t.Sub(time.Now()))
+       diff := int64(t.Sub(time.Now()))
+       d := runtimeNano() + diff
+       if d <= 0 && diff > 0 {
+               // If the user has a deadline in the future, but the delay calculation
+               // overflows, then set the deadline to the maximum possible value.
+               d = 1<<63 - 1
+       }
        if t.IsZero() {
                d = 0
        }
index 8939dc8baf9cc9ac4e95784fac3ca897543c5f4b..e4fed2680327a12419895ac820064d30df55fe8c 100644 (file)
@@ -273,7 +273,7 @@ func TestClientRedirects(t *testing.T) {
                t.Fatal("didn't see redirect")
        }
        if lastReq.Cancel != cancel {
-               t.Errorf("expected lastReq to have the cancel channel set on the inital req")
+               t.Errorf("expected lastReq to have the cancel channel set on the initial req")
        }
 
        checkErr = errors.New("no redirects allowed")
index 648709dd99780d37cae44b417fed9bc3983bdc50..1ea0e9397a37ec41042931a3a480d081334ff470 100644 (file)
@@ -223,7 +223,7 @@ func readCookies(h Header, filter string) []*Cookie {
        return cookies
 }
 
-// validCookieDomain returns wheter v is a valid cookie domain-value.
+// validCookieDomain returns whether v is a valid cookie domain-value.
 func validCookieDomain(v string) bool {
        if isCookieDomainName(v) {
                return true
index 4e19b3e71f7d33ca7a9b5e3a594efd203931ae1e..f778acb2b5dfd2987f2456726ce8f82b7b8f28d7 100644 (file)
@@ -288,7 +288,7 @@ func http2configureTransport(t1 *Transport) (*http2Transport, error) {
 }
 
 // registerHTTPSProtocol calls Transport.RegisterProtocol but
-// convering panics into errors.
+// converting panics into errors.
 func http2registerHTTPSProtocol(t *Transport, rt RoundTripper) (err error) {
        defer func() {
                if e := recover(); e != nil {
@@ -1410,7 +1410,7 @@ type http2PriorityFrame struct {
        http2PriorityParam
 }
 
-// PriorityParam are the stream prioritzation parameters.
+// PriorityParam are the stream prioritization parameters.
 type http2PriorityParam struct {
        // StreamDep is a 31-bit stream identifier for the
        // stream that this stream depends on. Zero means no
@@ -2850,7 +2850,7 @@ type http2stream struct {
        weight           uint8
        state            http2streamState
        sentReset        bool // only true once detached from streams map
-       gotReset         bool // only true once detacted from streams map
+       gotReset         bool // only true once detached from streams map
        gotTrailerHeader bool // HEADER frame for trailers was seen
 
        trailer    Header // accumulated trailers
@@ -4391,7 +4391,7 @@ const http2TrailerPrefix = "Trailer:"
 // trailers. That worked for a while, until we found the first major
 // user of Trailers in the wild: gRPC (using them only over http2),
 // and gRPC libraries permit setting trailers mid-stream without
-// predeclarnig them. So: change of plans. We still permit the old
+// predeclaring them. So: change of plans. We still permit the old
 // way, but we also permit this hack: if a Header() key begins with
 // "Trailer:", the suffix of that key is a Trailer. Because ':' is an
 // invalid token byte anyway, there is no ambiguity. (And it's already
@@ -4605,7 +4605,7 @@ type http2Transport struct {
        // send in the initial settings frame. It is how many bytes
        // of response headers are allow. Unlike the http2 spec, zero here
        // means to use a default limit (currently 10MB). If you actually
-       // want to advertise an ulimited value to the peer, Transport
+       // want to advertise an unlimited value to the peer, Transport
        // interprets the highest possible value here (0xffffffff or 1<<32-1)
        // to mean no limit.
        MaxHeaderListSize uint32
@@ -5012,7 +5012,7 @@ const http2maxAllocFrameSize = 512 << 10
 // frameBuffer returns a scratch buffer suitable for writing DATA frames.
 // They're capped at the min of the peer's max frame size or 512KB
 // (kinda arbitrarily), but definitely capped so we don't allocate 4GB
-// bufers.
+// buffers.
 func (cc *http2ClientConn) frameScratchBuffer() []byte {
        cc.mu.Lock()
        size := cc.maxFrameSize
@@ -6544,7 +6544,7 @@ func (ws *http2writeScheduler) take() (wm http2frameWriteMsg, ok bool) {
        return ws.takeFrom(q.streamID(), q)
 }
 
-// zeroCanSend is defered from take.
+// zeroCanSend is deferred from take.
 func (ws *http2writeScheduler) zeroCanSend() {
        for i := range ws.canSend {
                ws.canSend[i] = nil
index c9606f24198d1cf7b5af67b6495494572b483fd4..61470c382283d0da966a129b3a30d7fb26398201 100644 (file)
@@ -53,7 +53,7 @@ func TestGetAfterClose(t *testing.T) {
        res, err = http.Get(ts.URL)
        if err == nil {
                body, _ := ioutil.ReadAll(res.Body)
-               t.Fatalf("Unexected response after close: %v, %v, %s", res.Status, res.Header, body)
+               t.Fatalf("Unexpected response after close: %v, %v, %s", res.Status, res.Header, body)
        }
 }
 
index 8cdab02af5a057ca0382fcb17034a4086547a421..c3e43bb99da3f11d796b672eed7bfaf5208da105 100644 (file)
@@ -521,7 +521,7 @@ func cleanHost(in string) string {
        return in
 }
 
-// removeZone removes IPv6 zone identifer from host.
+// removeZone removes IPv6 zone identifier from host.
 // E.g., "[fe80::1%en0]:8080" to "[fe80::1]:8080"
 func removeZone(host string) string {
        if !strings.HasPrefix(host, "[") {
index 0ecdf85a5639a0bac57dbc8f433c8474024d8589..3d215ff5380bf499e1883594620dd84cc4b105c5 100644 (file)
@@ -99,7 +99,7 @@ type parseContentTypeTest struct {
 
 var parseContentTypeTests = []parseContentTypeTest{
        {false, stringMap{"Content-Type": {"text/plain"}}},
-       // Empty content type is legal - shoult be treated as
+       // Empty content type is legal - should be treated as
        // application/octet-stream (RFC 2616, section 7.2.1)
        {false, stringMap{}},
        {true, stringMap{"Content-Type": {"text/plain; boundary="}}},
index cfb95b0a800aaef72998b24383585f427d3fb1e7..9b70fcbf8aaefb3c957239b6ea0407401a462bcc 100644 (file)
@@ -573,7 +573,7 @@ func TestRequestWriteClosesBody(t *testing.T) {
                "Transfer-Encoding: chunked\r\n\r\n" +
                // TODO: currently we don't buffer before chunking, so we get a
                // single "m" chunk before the other chunks, as this was the 1-byte
-               // read from our MultiReader where we stiched the Body back together
+               // read from our MultiReader where we stitched the Body back together
                // after sniffing whether the Body was 0 bytes or not.
                chunk("m") +
                chunk("y body") +
index e2d8d277e0418b7b1c34183c8c7e22bc5aa559d1..773dd59c6bf8c19f466023a65d6a17411f844f2f 100644 (file)
@@ -1374,7 +1374,7 @@ func (c *conn) setState(nc net.Conn, state ConnState) {
 
 // badRequestError is a literal string (used by in the server in HTML,
 // unescaped) to tell the user why their request was bad. It should
-// be plain text without user info or other embeddded errors.
+// be plain text without user info or other embedded errors.
 type badRequestError string
 
 func (e badRequestError) Error() string { return "Bad Request: " + string(e) }
index 6e59af8f6f4fe9ab00cd813fc360c4f03121987f..7ff4953a14ab568b20e70c32e7433a92f02587c5 100644 (file)
@@ -558,21 +558,19 @@ func fixLength(isResponse bool, status int, requestMethod string, header Header,
 func shouldClose(major, minor int, header Header, removeCloseHeader bool) bool {
        if major < 1 {
                return true
-       } else if major == 1 && minor == 0 {
-               vv := header["Connection"]
-               if headerValuesContainsToken(vv, "close") || !headerValuesContainsToken(vv, "keep-alive") {
-                       return true
-               }
-               return false
-       } else {
-               if headerValuesContainsToken(header["Connection"], "close") {
-                       if removeCloseHeader {
-                               header.Del("Connection")
-                       }
-                       return true
-               }
        }
-       return false
+
+       conv := header["Connection"]
+       hasClose := headerValuesContainsToken(conv, "close")
+       if major == 1 && minor == 0 {
+               return hasClose || !headerValuesContainsToken(conv, "keep-alive")
+       }
+
+       if hasClose && removeCloseHeader {
+               header.Del("Connection")
+       }
+
+       return hasClose
 }
 
 // Parse the trailer header
index 03e9162b14f61d0ec6d53dab0c57b322758da4ba..f622f6f9834b3e4c6f76be46175da879d80bdcb6 100644 (file)
@@ -982,7 +982,7 @@ func (k connectMethodKey) String() string {
 // (but may be used for non-keep-alive requests as well)
 type persistConn struct {
        // alt optionally specifies the TLS NextProto RoundTripper.
-       // This is used for HTTP/2 today and future protocol laters.
+       // This is used for HTTP/2 today and future protocols later.
        // If it's non-nil, the rest of the fields are unused.
        alt RoundTripper
 
index d9da078fa0098f5c1d2513874710c221e73edbb3..e8a4623556806e4ac9a5f1b4ded2eadc60c21bff 100644 (file)
@@ -853,7 +853,7 @@ func TestTransportExpect100Continue(t *testing.T) {
                {path: "/100", body: []byte("hello"), sent: 5, status: 200},       // Got 100 followed by 200, entire body is sent.
                {path: "/200", body: []byte("hello"), sent: 0, status: 200},       // Got 200 without 100. body isn't sent.
                {path: "/500", body: []byte("hello"), sent: 0, status: 500},       // Got 500 without 100. body isn't sent.
-               {path: "/keepalive", body: []byte("hello"), sent: 0, status: 500}, // Althogh without Connection:close, body isn't sent.
+               {path: "/keepalive", body: []byte("hello"), sent: 0, status: 500}, // Although without Connection:close, body isn't sent.
                {path: "/timeout", body: []byte("hello"), sent: 5, status: 200},   // Timeout exceeded and entire body is sent.
        }
 
index 208f37f9fd34aa45d862f0886b78fb376d44dafd..e0814798e7a5b6239402754d5ee940563beefdcb 100644 (file)
@@ -161,7 +161,7 @@ func newAddr(ifi *Interface, m *syscall.InterfaceAddrMessage) (*IPNet, error) {
        case *syscall.SockaddrInet6:
                ifa.IP = make(IP, IPv6len)
                copy(ifa.IP, sa.Addr[:])
-               // NOTE: KAME based IPv6 protcol stack usually embeds
+               // NOTE: KAME based IPv6 protocol stack usually embeds
                // the interface index in the interface-local or
                // link-local address as the kernel-internal form.
                if ifa.IP.IsLinkLocalUnicast() {
index b7a333849d142f48322ab880de91413cdddb7e17..b3719d6092e708283703cfed873c089a0172a48e 100644 (file)
@@ -49,7 +49,7 @@ func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage)
        case *syscall.SockaddrInet6:
                ifma := IPAddr{IP: make(IP, IPv6len)}
                copy(ifma.IP, sa.Addr[:])
-               // NOTE: KAME based IPv6 protcol stack usually embeds
+               // NOTE: KAME based IPv6 protocol stack usually embeds
                // the interface index in the interface-local or
                // link-local address as the kernel-internal form.
                if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() {
index c42d90b7403e8b858673ff01b3971b72d975dc81..44ef2c1a2aebed7ba66291901b7d88f0c75967d5 100644 (file)
@@ -49,7 +49,7 @@ func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage)
        case *syscall.SockaddrInet6:
                ifma := IPAddr{IP: make(IP, IPv6len)}
                copy(ifma.IP, sa.Addr[:])
-               // NOTE: KAME based IPv6 protcol stack usually embeds
+               // NOTE: KAME based IPv6 protocol stack usually embeds
                // the interface index in the interface-local or
                // link-local address as the kernel-internal form.
                if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() {
index 7bdd924150371e9c6d369929dbb9389c9ce840ad..6721f72bb57bac8bd0bebbb4e75ebb8709d464f8 100644 (file)
@@ -102,7 +102,7 @@ func TestInterfaces(t *testing.T) {
                }
                // Test the existence of connected unicast routes for
                // IPv6. We can assume the existence of ::1/128 when
-               // at least one looopback interface is installed.
+               // at least one loopback interface is installed.
                if supportsIPv6 && stats.loop > 0 && stats.uni6 == 0 {
                        t.Errorf("num IPv6 unicast routes = 0; want >0; summary: %+v", stats)
                }
@@ -155,7 +155,7 @@ func TestInterfaceAddrs(t *testing.T) {
        }
        // Test the existence of connected unicast routes for IPv6.
        // We can assume the existence of ::1/128 when at least one
-       // looopback interface is installed.
+       // loopback interface is installed.
        if supportsIPv6 && stats.loop > 0 && stats.uni6 == 0 {
                t.Errorf("num IPv6 unicast routes = 0; want >0; summary: %+v", stats)
        }
index 93b3b79afda8c4099c023e42f4417fc698c611a6..dd20de4ac789a62e6e9bf2822612da197e5256a5 100644 (file)
@@ -56,7 +56,7 @@ func TestPointToPointInterface(t *testing.T) {
        for i := 0; i < 3; i++ {
                ti := &testInterface{local: local, remote: remote}
                if err := ti.setPointToPoint(5963 + i); err != nil {
-                       t.Skipf("test requries external command: %v", err)
+                       t.Skipf("test requires external command: %v", err)
                }
                if err := ti.setup(); err != nil {
                        t.Fatal(err)
index 3d95a73c097539a8b8400e0e9db1fdee7181ae82..2b24baf58e96338060b6862cbaad6a716121d8c1 100644 (file)
@@ -379,8 +379,8 @@ var splitJoinTests = []struct {
        {"", "0", ":0"},
 
        {"google.com", "https%foo", "google.com:https%foo"}, // Go 1.0 behavior
-       {"127.0.0.1", "", "127.0.0.1:"},                     // Go 1.0 behaviour
-       {"www.google.com", "", "www.google.com:"},           // Go 1.0 behaviour
+       {"127.0.0.1", "", "127.0.0.1:"},                     // Go 1.0 behavior
+       {"www.google.com", "", "www.google.com:"},           // Go 1.0 behavior
 }
 
 var splitFailureTests = []struct {
index 2bddd46a156e5bbc10f2f9c45a029e4d7b106e9d..d512fc3e57a74e01d1d6d7e3bd57001921ec0c93 100644 (file)
@@ -61,7 +61,7 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
                // Some released versions of DragonFly BSD pretend to
                // accept IPV6_V6ONLY=0 successfully, but the state
                // still stays IPV6_V6ONLY=1. Eventually DragonFly BSD
-               // stops preteding, but the transition period would
+               // stops pretending, but the transition period would
                // cause unpredictable behavior and we need to avoid
                // it.
                //
index 51ffe672388ef6829f6b869e69c1dbec5cd84e5c..0fc8889628b6da30788ead77ba1cb907a1e9cb26 100644 (file)
@@ -157,7 +157,7 @@ var dualStackTCPListenerTests = []struct {
        network2, address2 string // second listener
        xerr               error  // expected error value, nil or other
 }{
-       // Test cases and expected results for the attemping 2nd listen on the same port
+       // Test cases and expected results for the attempting 2nd listen on the same port
        // 1st listen                2nd listen                 darwin  freebsd  linux  openbsd
        // ------------------------------------------------------------------------------------
        // "tcp"  ""                 "tcp"  ""                    -        -       -       -
@@ -216,9 +216,12 @@ var dualStackTCPListenerTests = []struct {
 // TestDualStackTCPListener tests both single and double listen
 // to a test listener with various address families, different
 // listening address and same port.
+//
+// On DragonFly BSD, we expect the kernel version of node under test
+// to be greater than or equal to 4.4.
 func TestDualStackTCPListener(t *testing.T) {
        switch runtime.GOOS {
-       case "dragonfly", "nacl", "plan9": // re-enable on dragonfly once the new IP control block management has landed
+       case "nacl", "plan9":
                t.Skipf("not supported on %s", runtime.GOOS)
        }
        if !supportsIPv4 || !supportsIPv6 {
@@ -301,11 +304,14 @@ var dualStackUDPListenerTests = []struct {
 }
 
 // TestDualStackUDPListener tests both single and double listen
-// to a test listener with various address families, differnet
+// to a test listener with various address families, different
 // listening address and same port.
+//
+// On DragonFly BSD, we expect the kernel version of node under test
+// to be greater than or equal to 4.4.
 func TestDualStackUDPListener(t *testing.T) {
        switch runtime.GOOS {
-       case "dragonfly", "nacl", "plan9": // re-enable on dragonfly once the new IP control block management has landed
+       case "nacl", "plan9":
                t.Skipf("not supported on %s", runtime.GOOS)
        }
        if !supportsIPv4 || !supportsIPv6 {
diff --git a/src/net/main_conf_test.go b/src/net/main_conf_test.go
new file mode 100644 (file)
index 0000000..ba91e8b
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2015 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !nacl,!plan9,!windows
+
+package net
+
+// forceGoDNS forces the resolver configuration to use the pure Go resolver
+// and returns a fixup function to restore the old settings.
+func forceGoDNS() func() {
+       c := systemConf()
+       oldGo := c.netGo
+       oldCgo := c.netCgo
+       fixup := func() {
+               c.netGo = oldGo
+               c.netCgo = oldCgo
+       }
+       c.netGo = true
+       c.netCgo = false
+       return fixup
+}
+
+// forceCgoDNS forces the resolver configuration to use the cgo resolver
+// and returns a fixup function to restore the old settings.
+// (On non-Unix systems forceCgoDNS returns nil.)
+func forceCgoDNS() func() {
+       c := systemConf()
+       oldGo := c.netGo
+       oldCgo := c.netCgo
+       fixup := func() {
+               c.netGo = oldGo
+               c.netCgo = oldCgo
+       }
+       c.netGo = false
+       c.netCgo = true
+       return fixup
+}
similarity index 78%
rename from src/net/non_unix_test.go
rename to src/net/main_noconf_test.go
index db3427e7cb4f6fc9fc4de50cc6932f137caf5828..ce978365dcb1f6230e245ca288996c0624f96430 100644 (file)
@@ -8,7 +8,7 @@ package net
 
 import "runtime"
 
-// See unix_test.go for what these (don't) do.
+// See main_conf_test.go for what these (don't) do.
 func forceGoDNS() func() {
        switch runtime.GOOS {
        case "plan9", "windows":
@@ -18,5 +18,5 @@ func forceGoDNS() func() {
        }
 }
 
-// See unix_test.go for what these (don't) do.
+// See main_conf_test.go for what these (don't) do.
 func forceCgoDNS() func() { return nil }
index df390327218e3307a97609ff65f51bc1e505c3b7..ab217989690da13f91929e928370335f29cae51e 100644 (file)
@@ -315,7 +315,7 @@ func TestInterfacesWithNetsh(t *testing.T) {
 }
 
 func netshInterfaceIPv4ShowAddress(name string, netshOutput []byte) []string {
-       // adress information is listed like:
+       // Address information is listed like:
        //
        //Configuration for interface "Local Area Connection"
        //    DHCP enabled:                         Yes
@@ -378,7 +378,7 @@ func netshInterfaceIPv4ShowAddress(name string, netshOutput []byte) []string {
 }
 
 func netshInterfaceIPv6ShowAddress(name string, netshOutput []byte) []string {
-       // adress information is listed like:
+       // Address information is listed like:
        //
        //Address ::1 Parameters
        //---------------------------------------------------------
index f3f3b54b886b034b6a7d218d377d0177270bc51d..eafb372f7c40104da4f42c14407ac6386a01dc57 100644 (file)
@@ -18,7 +18,7 @@ import (
 //
 // if handled == false, sendFile performed no work.
 //
-// Note that sendfile for windows does not suppport >2GB file.
+// Note that sendfile for windows does not support >2GB file.
 func sendFile(fd *netFD, r io.Reader) (written int64, err error, handled bool) {
        var n int64 = 0 // by default, copy until EOF
 
similarity index 100%
rename from src/net/tcp_test.go
rename to src/net/tcpsock_test.go
index 91bbb573043c77e262e0de5908a22bd363b969fd..109afd3ceaacf5f2576e092db25590dd43671617 100644 (file)
@@ -581,18 +581,14 @@ func CanonicalMIMEHeaderKey(s string) string {
 const toLower = 'a' - 'A'
 
 // validHeaderFieldByte reports whether b is a valid byte in a header
-// field key. This is actually stricter than RFC 7230, which says:
+// field name. RFC 7230 says:
+//   header-field   = field-name ":" OWS field-value OWS
+//   field-name     = token
 //   tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
 //           "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
 //   token = 1*tchar
-// TODO: revisit in Go 1.6+ and possibly expand this. But note that many
-// servers have historically dropped '_' to prevent ambiguities when mapping
-// to CGI environment variables.
 func validHeaderFieldByte(b byte) bool {
-       return ('A' <= b && b <= 'Z') ||
-               ('a' <= b && b <= 'z') ||
-               ('0' <= b && b <= '9') ||
-               b == '-'
+       return int(b) < len(isTokenTable) && isTokenTable[b]
 }
 
 // canonicalMIMEHeaderKey is like CanonicalMIMEHeaderKey but is
@@ -682,3 +678,85 @@ func init() {
                commonHeader[v] = v
        }
 }
+
+// isTokenTable is a copy of net/http/lex.go's isTokenTable.
+// See https://httpwg.github.io/specs/rfc7230.html#rule.token.separators
+var isTokenTable = [127]bool{
+       '!':  true,
+       '#':  true,
+       '$':  true,
+       '%':  true,
+       '&':  true,
+       '\'': true,
+       '*':  true,
+       '+':  true,
+       '-':  true,
+       '.':  true,
+       '0':  true,
+       '1':  true,
+       '2':  true,
+       '3':  true,
+       '4':  true,
+       '5':  true,
+       '6':  true,
+       '7':  true,
+       '8':  true,
+       '9':  true,
+       'A':  true,
+       'B':  true,
+       'C':  true,
+       'D':  true,
+       'E':  true,
+       'F':  true,
+       'G':  true,
+       'H':  true,
+       'I':  true,
+       'J':  true,
+       'K':  true,
+       'L':  true,
+       'M':  true,
+       'N':  true,
+       'O':  true,
+       'P':  true,
+       'Q':  true,
+       'R':  true,
+       'S':  true,
+       'T':  true,
+       'U':  true,
+       'W':  true,
+       'V':  true,
+       'X':  true,
+       'Y':  true,
+       'Z':  true,
+       '^':  true,
+       '_':  true,
+       '`':  true,
+       'a':  true,
+       'b':  true,
+       'c':  true,
+       'd':  true,
+       'e':  true,
+       'f':  true,
+       'g':  true,
+       'h':  true,
+       'i':  true,
+       'j':  true,
+       'k':  true,
+       'l':  true,
+       'm':  true,
+       'n':  true,
+       'o':  true,
+       'p':  true,
+       'q':  true,
+       'r':  true,
+       's':  true,
+       't':  true,
+       'u':  true,
+       'v':  true,
+       'w':  true,
+       'x':  true,
+       'y':  true,
+       'z':  true,
+       '|':  true,
+       '~':  true,
+}
index 9c71594362ebb4be39cfd4e6be1c90203ef43a75..8a07adf4d304296380080859da1e36acf9d5ce7b 100644 (file)
@@ -25,6 +25,12 @@ var canonicalHeaderKeyTests = []canonicalHeaderKeyTest{
        {"user-agent", "User-Agent"},
        {"USER-AGENT", "User-Agent"},
 
+       // Other valid tchar bytes in tokens:
+       {"foo-bar_baz", "Foo-Bar_baz"},
+       {"foo-bar$baz", "Foo-Bar$baz"},
+       {"foo-bar~baz", "Foo-Bar~baz"},
+       {"foo-bar*baz", "Foo-Bar*baz"},
+
        // Non-ASCII or anything with spaces or non-token chars is unchanged:
        {"üser-agenT", "üser-agenT"},
        {"a B", "a B"},
index 98e3164fb9897a12fc022be72cc2c955bdb770c2..d80e478c7720ed7f80d0504ed41c26098f4f15d3 100644 (file)
@@ -26,6 +26,8 @@ var dialTimeoutTests = []struct {
        {-5 * time.Second, 0, -5 * time.Second, 100 * time.Millisecond},
        {0, -5 * time.Second, -5 * time.Second, 100 * time.Millisecond},
        {-5 * time.Second, 5 * time.Second, -5 * time.Second, 100 * time.Millisecond}, // timeout over deadline
+       {-1 << 63, 0, time.Second, 100 * time.Millisecond},
+       {0, -1 << 63, time.Second, 100 * time.Millisecond},
 
        {50 * time.Millisecond, 0, 100 * time.Millisecond, time.Second},
        {0, 50 * time.Millisecond, 100 * time.Millisecond, time.Second},
@@ -99,6 +101,54 @@ func TestDialTimeout(t *testing.T) {
        }
 }
 
+var dialTimeoutMaxDurationTests = []struct {
+       timeout time.Duration
+       delta   time.Duration // for deadline
+}{
+       // Large timeouts that will overflow an int64 unix nanos.
+       {1<<63 - 1, 0},
+       {0, 1<<63 - 1},
+}
+
+func TestDialTimeoutMaxDuration(t *testing.T) {
+       t.Parallel()
+
+       ln, err := newLocalListener("tcp")
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer ln.Close()
+
+       for i, tt := range dialTimeoutMaxDurationTests {
+               ch := make(chan error)
+               max := time.NewTimer(100 * time.Millisecond)
+               defer max.Stop()
+               go func() {
+                       d := Dialer{Timeout: tt.timeout}
+                       if tt.delta != 0 {
+                               d.Deadline = time.Now().Add(tt.delta)
+                       }
+                       c, err := d.Dial(ln.Addr().Network(), ln.Addr().String())
+                       if err == nil {
+                               c.Close()
+                       }
+                       ch <- err
+               }()
+
+               select {
+               case <-max.C:
+                       t.Fatalf("#%d: Dial didn't return in an expected time", i)
+               case err := <-ch:
+                       if perr := parseDialError(err); perr != nil {
+                               t.Error(perr)
+                       }
+                       if err != nil {
+                               t.Errorf("#%d: %v", i, err)
+                       }
+               }
+       }
+}
+
 var acceptTimeoutTests = []struct {
        timeout time.Duration
        xerrs   [2]error // expected errors in transition
similarity index 99%
rename from src/net/udp_test.go
rename to src/net/udpsock_test.go
index b25f96a3fd3a4642d5a7d7b5a1d3b61300cfd32f..12d1256f0a8ad07cd46d6dac4cba150dcd52fda8 100644 (file)
@@ -356,7 +356,7 @@ func TestUDPZeroByteBuffer(t *testing.T) {
                switch err {
                case nil: // ReadFrom succeeds
                default: // Read may timeout, it depends on the platform
-                       if nerr, ok := err.(Error); (!ok || !nerr.Timeout()) && runtime.GOOS != "windows" { // Windows retruns WSAEMSGSIZ
+                       if nerr, ok := err.(Error); (!ok || !nerr.Timeout()) && runtime.GOOS != "windows" { // Windows returns WSAEMSGSIZ
                                t.Fatal(err)
                        }
                }
similarity index 93%
rename from src/net/unix_test.go
rename to src/net/unixsock_test.go
index f0c583068ec08abf6bb93965e37107b3978ae02b..f5e069a1218c1165d760a8b48d65fe9271221d7c 100644 (file)
@@ -440,34 +440,3 @@ func TestUnixUnlink(t *testing.T) {
                t.Fatal("closing unix listener did not remove unix socket")
        }
 }
-
-// forceGoDNS forces the resolver configuration to use the pure Go resolver
-// and returns a fixup function to restore the old settings.
-func forceGoDNS() func() {
-       c := systemConf()
-       oldGo := c.netGo
-       oldCgo := c.netCgo
-       fixup := func() {
-               c.netGo = oldGo
-               c.netCgo = oldCgo
-       }
-       c.netGo = true
-       c.netCgo = false
-       return fixup
-}
-
-// forceCgoDNS forces the resolver configuration to use the cgo resolver
-// and returns a fixup function to restore the old settings.
-// (On non-Unix systems forceCgoDNS returns nil.)
-func forceCgoDNS() func() {
-       c := systemConf()
-       oldGo := c.netGo
-       oldCgo := c.netCgo
-       fixup := func() {
-               c.netGo = oldGo
-               c.netCgo = oldCgo
-       }
-       c.netGo = false
-       c.netCgo = true
-       return fixup
-}
index b3513a85a3f9f26f7c1aa7b443dd341bb249a9e6..48119f4a5dc35c342c727939b7f98c69d1939ac8 100644 (file)
@@ -307,14 +307,15 @@ func escape(s string, mode encoding) string {
 // construct a URL struct directly and set the Opaque field instead of Path.
 // These still work as well.
 type URL struct {
-       Scheme   string
-       Opaque   string    // encoded opaque data
-       User     *Userinfo // username and password information
-       Host     string    // host or host:port
-       Path     string
-       RawPath  string // encoded path hint (Go 1.5 and later only; see EscapedPath method)
-       RawQuery string // encoded query values, without '?'
-       Fragment string // fragment for references, without '#'
+       Scheme     string
+       Opaque     string    // encoded opaque data
+       User       *Userinfo // username and password information
+       Host       string    // host or host:port
+       Path       string
+       RawPath    string // encoded path hint (Go 1.5 and later only; see EscapedPath method)
+       ForceQuery bool   // append a query ('?') even if RawQuery is empty
+       RawQuery   string // encoded query values, without '?'
+       Fragment   string // fragment for references, without '#'
 }
 
 // User returns a Userinfo containing the provided username
@@ -459,7 +460,12 @@ func parse(rawurl string, viaRequest bool) (url *URL, err error) {
        }
        url.Scheme = strings.ToLower(url.Scheme)
 
-       rest, url.RawQuery = split(rest, "?", true)
+       if strings.HasSuffix(rest, "?") {
+               url.ForceQuery = true
+               rest = rest[:len(rest)-1]
+       } else {
+               rest, url.RawQuery = split(rest, "?", true)
+       }
 
        if !strings.HasPrefix(rest, "/") {
                if url.Scheme != "" {
@@ -684,7 +690,7 @@ func (u *URL) String() string {
                }
                buf.WriteString(path)
        }
-       if u.RawQuery != "" {
+       if u.ForceQuery || u.RawQuery != "" {
                buf.WriteByte('?')
                buf.WriteString(u.RawQuery)
        }
@@ -913,7 +919,7 @@ func (u *URL) RequestURI() string {
                        result = u.Scheme + ":" + result
                }
        }
-       if u.RawQuery != "" {
+       if u.ForceQuery || u.RawQuery != "" {
                result += "?" + u.RawQuery
        }
        return result
index d3f8487bd7c0addb96f8e7329f98619308589540..a3088ec0a3867d9b48eaba46b3bda98d915bbd9d 100644 (file)
@@ -72,6 +72,17 @@ var urltests = []URLTest{
                },
                "ftp://john%20doe@www.google.com/",
        },
+       // empty query
+       {
+               "http://www.google.com/?",
+               &URL{
+                       Scheme:     "http",
+                       Host:       "www.google.com",
+                       Path:       "/",
+                       ForceQuery: true,
+               },
+               "",
+       },
        // query
        {
                "http://www.google.com/?q=go+language",
@@ -874,11 +885,13 @@ var resolveReferenceTests = []struct {
        // Absolute URL references
        {"http://foo.com?a=b", "https://bar.com/", "https://bar.com/"},
        {"http://foo.com/", "https://bar.com/?a=b", "https://bar.com/?a=b"},
+       {"http://foo.com/", "https://bar.com/?", "https://bar.com/?"},
        {"http://foo.com/bar", "mailto:foo@example.com", "mailto:foo@example.com"},
 
        // Path-absolute references
        {"http://foo.com/bar", "/baz", "http://foo.com/baz"},
        {"http://foo.com/bar?a=b#f", "/baz", "http://foo.com/baz"},
+       {"http://foo.com/bar?a=b", "/baz?", "http://foo.com/baz?"},
        {"http://foo.com/bar?a=b", "/baz?c=d", "http://foo.com/baz?c=d"},
 
        // Scheme-relative
@@ -1217,6 +1230,15 @@ var requritests = []RequestURITest{
                },
                "//foo",
        },
+       {
+               &URL{
+                       Scheme:     "http",
+                       Host:       "example.com",
+                       Path:       "/foo",
+                       ForceQuery: true,
+               },
+               "/foo?",
+       },
 }
 
 func TestRequestURI(t *testing.T) {
index 52b4724ab02a20a790b9dae89ebff0bbc17e1686..a69b5176d5aff4c021733937f8390e9e502fb8b3 100644 (file)
@@ -341,7 +341,7 @@ func TestExtraFilesFDShuffle(t *testing.T) {
        //
        // We want to test that FDs in the child do not get overwritten
        // by one another as this shuffle occurs. The original implementation
-       // was buggy in that in some data dependent cases it would ovewrite
+       // was buggy in that in some data dependent cases it would overwrite
        // stderr in the child with one of the ExtraFile members.
        // Testing for this case is difficult because it relies on using
        // the same FD values as that case. In particular, an FD of 3
index 8e1d4239bf128c92035f477e4f93e5b6a33d313a..042e5a1389eb7db019d24441b3fef7cef40bed56 100644 (file)
@@ -117,7 +117,7 @@ func createEnv(dir, PATH, PATHEXT string) []string {
 }
 
 // createFiles copies srcPath file into multiply files.
-// It uses dir as preifx for all destination files.
+// It uses dir as prefix for all destination files.
 func createFiles(t *testing.T, dir string, files []string, srcPath string) {
        for _, f := range files {
                installProg(t, filepath.Join(dir, f), srcPath)
@@ -431,7 +431,7 @@ var commandTests = []commandTest{
        },
        {
                // LookPath(`a.exe`) will find `.\a.exe`, but prefixing that with
-               // dir `p\a.exe` will refer to not existant file
+               // dir `p\a.exe` will refer to a non-existent file
                files: []string{`a.exe`, `p\not_important_file`},
                dir:   `p`,
                arg0:  `a.exe`,
@@ -440,7 +440,7 @@ var commandTests = []commandTest{
        },
        {
                // like above, but making test succeed by installing file
-               // in refered destination (so LookPath(`a.exe`) will still
+               // in referred destination (so LookPath(`a.exe`) will still
                // find `.\a.exe`, but we successfully execute `p\a.exe`)
                files: []string{`a.exe`, `p\a.exe`},
                dir:   `p`,
index 945724b2b259652d72b55e6cba57baab2b421647..b2f45b48f8dce7991207422d4b81cd4f97dfcdf0 100644 (file)
@@ -47,10 +47,10 @@ var sysdir = func() *sysDir {
        switch runtime.GOOS {
        case "android":
                return &sysDir{
-                       "/system/framework",
+                       "/system/lib",
                        []string{
-                               "ext.jar",
-                               "framework.jar",
+                               "libmedia.so",
+                               "libpowermanager.so",
                        },
                }
        case "darwin":
@@ -538,7 +538,7 @@ func TestReaddirStatFailures(t *testing.T) {
                return s
        }
 
-       if got, want := names(mustReadDir("inital readdir")),
+       if got, want := names(mustReadDir("initial readdir")),
                []string{"good1", "good2", "x"}; !reflect.DeepEqual(got, want) {
                t.Errorf("initial readdir got %q; want %q", got, want)
        }
index d3e03e984954678ba309abd3cc1324927dbd7f74..cba9fa3e8d41de985a6f6c45eb293b4be322ea2f 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Simple converions to avoid depending on strconv.
+// Simple conversions to avoid depending on strconv.
 
 package os
 
index 99c325ff010c3dc18c7b828e88b094b308c4c40c..9fb3c5546f27fe10e4fd17532c3548f55ec2e8b0 100644 (file)
@@ -61,7 +61,7 @@ func lookupFullName(domain, username, domainAndUser string) (string, error) {
        if err == nil {
                return name, nil
        }
-       // domain worked neigher as a domain nor as a server
+       // domain worked neither as a domain nor as a server
        // could be domain server unavailable
        // pretend username is fullname
        return username, nil
index ef6e7ca93f4adaaed37d334cd1d6e90ef628ef05..41c57df73869c6fe302ad4ba36869b244ed7c930 100644 (file)
@@ -121,7 +121,7 @@ func join(elem []string) string {
 // joinNonEmpty is like join, but it assumes that the first element is non-empty.
 func joinNonEmpty(elem []string) string {
        if len(elem[0]) == 2 && elem[0][1] == ':' {
-               // First element is drive leter without terminating slash.
+               // First element is drive letter without terminating slash.
                // Keep path relative to current directory on that drive.
                return Clean(elem[0] + strings.Join(elem[1:], string(Separator)))
        }
index c80df3407777aef8a3502d572ffd78eb77f02b6d..2eb4f343f9808ea63ce4f9f9271b322fb40e9a77 100644 (file)
@@ -4465,7 +4465,7 @@ func TestFieldByIndexNil(t *testing.T) {
 // off the stack into the frame will store an *Inner there, and then if a garbage collection
 // happens to scan that argument frame before it is discarded, it will scan the *Inner
 // memory as if it were an *Outer. If the two have different memory layouts, the
-// collection will intepret the memory incorrectly.
+// collection will interpret the memory incorrectly.
 //
 // One such possible incorrect interpretation is to treat two arbitrary memory words
 // (Inner.P1 and Inner.P2 below) as an interface (Outer.R below). Because interpreting
@@ -5007,3 +5007,24 @@ func TestChanAlloc(t *testing.T) {
        // a limitation of escape analysis.  If that is ever fixed the
        // allocs < 0.5 condition will trigger and this test should be fixed.
 }
+
+type nameTest struct {
+       v    interface{}
+       want string
+}
+
+var nameTests = []nameTest{
+       {int32(0), "int32"},
+       {D1{}, "D1"},
+       {[]D1{}, ""},
+       {(chan D1)(nil), ""},
+       {(func() D1)(nil), ""},
+}
+
+func TestNames(t *testing.T) {
+       for _, test := range nameTests {
+               if got := TypeOf(test.v).Name(); got != test.want {
+                       t.Errorf("%T Name()=%q, want %q", test.v, got, test.want)
+               }
+       }
+}
index 26a648e193f1ad5bfd60d8daf7602460baff1e73..a6b0fda737adab85bd06acf0f693f67c39a0ee15 100644 (file)
@@ -48,7 +48,7 @@ func TypeLinks() []string {
        var r []string
        for _, m := range typelinks() {
                for _, t := range m {
-                       r = append(r, *t.string)
+                       r = append(r, t.string)
                }
        }
        return r
index 003c610cb14c2fc2baf561c3b7b1f215879d52cc..1367ba34e7fb130bc96b267001dcfef0cd591455 100644 (file)
@@ -254,9 +254,8 @@ type rtype struct {
        kind          uint8    // enumeration for C
        alg           *typeAlg // algorithm table
        gcdata        *byte    // garbage collection data
-       string        *string  // string form; unnecessary but undeniably useful
+       string        string   // string form; unnecessary but undeniably useful
        *uncommonType          // (relatively) uncommon fields
-       ptrToThis     *rtype   // type for pointer to this type, if used in binary or has methods
 }
 
 // a copy of runtime.typeAlg
@@ -284,7 +283,6 @@ type method struct {
 // Using a pointer to this struct reduces the overall size required
 // to describe an unnamed type with no methods.
 type uncommonType struct {
-       name    *string  // name of type
        pkgPath *string  // import path; nil for built-in types like int, string
        methods []method // methods associated with type
 }
@@ -453,14 +451,7 @@ func (t *uncommonType) PkgPath() string {
        return *t.pkgPath
 }
 
-func (t *uncommonType) Name() string {
-       if t == nil || t.name == nil {
-               return ""
-       }
-       return *t.name
-}
-
-func (t *rtype) String() string { return *t.string }
+func (t *rtype) String() string { return t.string }
 
 func (t *rtype) Size() uintptr { return t.size }
 
@@ -558,8 +549,34 @@ func (t *rtype) PkgPath() string {
        return t.uncommonType.PkgPath()
 }
 
+func hasPrefix(s, prefix string) bool {
+       return len(s) >= len(prefix) && s[:len(prefix)] == prefix
+}
+
 func (t *rtype) Name() string {
-       return t.uncommonType.Name()
+       if hasPrefix(t.string, "map[") {
+               return ""
+       }
+       if hasPrefix(t.string, "struct {") {
+               return ""
+       }
+       if hasPrefix(t.string, "chan ") {
+               return ""
+       }
+       if hasPrefix(t.string, "func(") {
+               return ""
+       }
+       if t.string[0] == '[' || t.string[0] == '*' {
+               return ""
+       }
+       i := len(t.string) - 1
+       for i >= 0 {
+               if t.string[i] == '.' {
+                       break
+               }
+               i--
+       }
+       return t.string[i+1:]
 }
 
 func (t *rtype) ChanDir() ChanDir {
@@ -1030,15 +1047,7 @@ func PtrTo(t Type) Type {
 }
 
 func (t *rtype) ptrTo() *rtype {
-       if p := t.ptrToThis; p != nil {
-               return p
-       }
-
-       // Otherwise, synthesize one.
-       // This only happens for pointers with no methods.
-       // We keep the mapping in a map on the side, because
-       // this operation is rare and a separate map lets us keep
-       // the type structures in read-only memory.
+       // Check the cache.
        ptrMap.RLock()
        if m := ptrMap.m; m != nil {
                if p := m[t]; p != nil {
@@ -1047,6 +1056,7 @@ func (t *rtype) ptrTo() *rtype {
                }
        }
        ptrMap.RUnlock()
+
        ptrMap.Lock()
        if ptrMap.m == nil {
                ptrMap.m = make(map[*rtype]*ptrType)
@@ -1059,7 +1069,7 @@ func (t *rtype) ptrTo() *rtype {
        }
 
        // Look in known types.
-       s := "*" + *t.string
+       s := "*" + t.string
        for _, tt := range typesByString(s) {
                p = (*ptrType)(unsafe.Pointer(tt))
                if p.elem == t {
@@ -1076,7 +1086,7 @@ func (t *rtype) ptrTo() *rtype {
        prototype := *(**ptrType)(unsafe.Pointer(&iptr))
        *p = *prototype
 
-       p.string = &s
+       p.string = s
 
        // For the type structures linked into the binary, the
        // compiler provides a good hash of the string.
@@ -1086,7 +1096,6 @@ func (t *rtype) ptrTo() *rtype {
        p.hash = fnv1(t.hash, '*')
 
        p.uncommonType = nil
-       p.ptrToThis = nil
        p.elem = t
 
        ptrMap.m[t] = p
@@ -1310,7 +1319,7 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool {
 // Note that strings are not unique identifiers for types:
 // there can be more than one with a given string.
 // Only types we might want to look up are included:
-// channels, maps, slices, and arrays.
+// pointers, channels, maps, slices, and arrays.
 func typelinks() [][]*rtype
 
 // typesByString returns the subslice of typelinks() whose elements have
@@ -1328,7 +1337,7 @@ func typesByString(s string) []*rtype {
                for i < j {
                        h := i + (j-i)/2 // avoid overflow when computing h
                        // i â‰¤ h < j
-                       if !(*typ[h].string >= s) {
+                       if !(typ[h].string >= s) {
                                i = h + 1 // preserves f(i-1) == false
                        } else {
                                j = h // preserves f(j) == true
@@ -1340,7 +1349,7 @@ func typesByString(s string) []*rtype {
                // We could do a second binary search, but the caller is going
                // to do a linear scan anyway.
                j = i
-               for j < len(typ) && *typ[j].string == s {
+               for j < len(typ) && typ[j].string == s {
                        j++
                }
 
@@ -1442,11 +1451,11 @@ func ChanOf(dir ChanDir, t Type) Type {
                lookupCache.Unlock()
                panic("reflect.ChanOf: invalid dir")
        case SendDir:
-               s = "chan<- " + *typ.string
+               s = "chan<- " + typ.string
        case RecvDir:
-               s = "<-chan " + *typ.string
+               s = "<-chan " + typ.string
        case BothDir:
-               s = "chan " + *typ.string
+               s = "chan " + typ.string
        }
        for _, tt := range typesByString(s) {
                ch := (*chanType)(unsafe.Pointer(tt))
@@ -1461,11 +1470,10 @@ func ChanOf(dir ChanDir, t Type) Type {
        ch := new(chanType)
        *ch = *prototype
        ch.dir = uintptr(dir)
-       ch.string = &s
+       ch.string = s
        ch.hash = fnv1(typ.hash, 'c', byte(dir))
        ch.elem = typ
        ch.uncommonType = nil
-       ch.ptrToThis = nil
 
        return cachePut(ckey, &ch.rtype)
 }
@@ -1493,7 +1501,7 @@ func MapOf(key, elem Type) Type {
        }
 
        // Look in known types.
-       s := "map[" + *ktyp.string + "]" + *etyp.string
+       s := "map[" + ktyp.string + "]" + etyp.string
        for _, tt := range typesByString(s) {
                mt := (*mapType)(unsafe.Pointer(tt))
                if mt.key == ktyp && mt.elem == etyp {
@@ -1505,7 +1513,7 @@ func MapOf(key, elem Type) Type {
        var imap interface{} = (map[unsafe.Pointer]unsafe.Pointer)(nil)
        mt := new(mapType)
        *mt = **(**mapType)(unsafe.Pointer(&imap))
-       mt.string = &s
+       mt.string = s
        mt.hash = fnv1(etyp.hash, 'm', byte(ktyp.hash>>24), byte(ktyp.hash>>16), byte(ktyp.hash>>8), byte(ktyp.hash))
        mt.key = ktyp
        mt.elem = etyp
@@ -1528,7 +1536,6 @@ func MapOf(key, elem Type) Type {
        mt.reflexivekey = isReflexive(ktyp)
        mt.needkeyupdate = needKeyUpdate(ktyp)
        mt.uncommonType = nil
-       mt.ptrToThis = nil
 
        return cachePut(ckey, &mt.rtype)
 }
@@ -1605,9 +1612,8 @@ func FuncOf(in, out []Type, variadic bool) Type {
        }
 
        // Populate the remaining fields of ft and store in cache.
-       ft.string = &str
+       ft.string = str
        ft.uncommonType = nil
-       ft.ptrToThis = nil
        funcLookupCache.m[hash] = append(funcLookupCache.m[hash], &ft.rtype)
 
        return &ft.rtype
@@ -1623,9 +1629,9 @@ func funcStr(ft *funcType) string {
                }
                if ft.dotdotdot && i == len(ft.in)-1 {
                        repr = append(repr, "..."...)
-                       repr = append(repr, *(*sliceType)(unsafe.Pointer(t)).elem.string...)
+                       repr = append(repr, (*sliceType)(unsafe.Pointer(t)).elem.string...)
                } else {
-                       repr = append(repr, *t.string...)
+                       repr = append(repr, t.string...)
                }
        }
        repr = append(repr, ')')
@@ -1638,7 +1644,7 @@ func funcStr(ft *funcType) string {
                if i > 0 {
                        repr = append(repr, ", "...)
                }
-               repr = append(repr, *t.string...)
+               repr = append(repr, t.string...)
        }
        if len(ft.out) > 1 {
                repr = append(repr, ')')
@@ -1803,8 +1809,8 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
        b.ptrdata = ptrdata
        b.kind = kind
        b.gcdata = gcdata
-       s := "bucket(" + *ktyp.string + "," + *etyp.string + ")"
-       b.string = &s
+       s := "bucket(" + ktyp.string + "," + etyp.string + ")"
+       b.string = s
        return b
 }
 
@@ -1820,7 +1826,7 @@ func SliceOf(t Type) Type {
        }
 
        // Look in known types.
-       s := "[]" + *typ.string
+       s := "[]" + typ.string
        for _, tt := range typesByString(s) {
                slice := (*sliceType)(unsafe.Pointer(tt))
                if slice.elem == typ {
@@ -1833,11 +1839,10 @@ func SliceOf(t Type) Type {
        prototype := *(**sliceType)(unsafe.Pointer(&islice))
        slice := new(sliceType)
        *slice = *prototype
-       slice.string = &s
+       slice.string = s
        slice.hash = fnv1(typ.hash, '[')
        slice.elem = typ
        slice.uncommonType = nil
-       slice.ptrToThis = nil
 
        return cachePut(ckey, &slice.rtype)
 }
@@ -1864,7 +1869,7 @@ func ArrayOf(count int, elem Type) Type {
        }
 
        // Look in known types.
-       s := "[" + strconv.Itoa(count) + "]" + *typ.string
+       s := "[" + strconv.Itoa(count) + "]" + typ.string
        for _, tt := range typesByString(s) {
                array := (*arrayType)(unsafe.Pointer(tt))
                if array.elem == typ {
@@ -1877,7 +1882,7 @@ func ArrayOf(count int, elem Type) Type {
        prototype := *(**arrayType)(unsafe.Pointer(&iarray))
        array := new(arrayType)
        *array = *prototype
-       array.string = &s
+       array.string = s
        array.hash = fnv1(typ.hash, '[')
        for n := uint32(count); n > 0; n >>= 8 {
                array.hash = fnv1(array.hash, byte(n))
@@ -1895,7 +1900,6 @@ func ArrayOf(count int, elem Type) Type {
        array.align = typ.align
        array.fieldAlign = typ.fieldAlign
        array.uncommonType = nil
-       array.ptrToThis = nil
        array.len = uintptr(count)
        array.slice = slice.(*rtype)
 
@@ -2133,11 +2137,11 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
 
        var s string
        if rcvr != nil {
-               s = "methodargs(" + *rcvr.string + ")(" + *t.string + ")"
+               s = "methodargs(" + rcvr.string + ")(" + t.string + ")"
        } else {
-               s = "funcargs(" + *t.string + ")"
+               s = "funcargs(" + t.string + ")"
        }
-       x.string = &s
+       x.string = s
 
        // cache result for future callers
        if layoutCache.m == nil {
index 4872cb3def44932859af81b4ba480a07232d224b..0f95b95972b971dc9b05a7312e53a948ffe8caad 100644 (file)
@@ -409,7 +409,7 @@ Reading:
                //     h        REG_MULTIREF            multiple digit backref
                //     i        REG_ICASE               ignore case
                //     j        REG_SPAN                . matches \n
-               //     k        REG_ESCAPE              \ to ecape [...] delimiter
+               //     k        REG_ESCAPE              \ to escape [...] delimiter
                //     l        REG_LEFT                implicit ^...
                //     m        REG_MINIMAL             minimal match
                //     n        REG_NEWLINE             explicit \n match
index 9e19119f4a9edf794d05ced4b0f37fd4e9952ed9..e507e717158f7aaa9bef7c84637679e1d96b753e 100644 (file)
@@ -146,7 +146,7 @@ func interhash(p unsafe.Pointer, h uintptr) uintptr {
        t := tab._type
        fn := t.alg.hash
        if fn == nil {
-               panic(errorString("hash of unhashable type " + *t._string))
+               panic(errorString("hash of unhashable type " + t._string))
        }
        if isDirectIface(t) {
                return c1 * fn(unsafe.Pointer(&a.data), h^c0)
@@ -163,7 +163,7 @@ func nilinterhash(p unsafe.Pointer, h uintptr) uintptr {
        }
        fn := t.alg.hash
        if fn == nil {
-               panic(errorString("hash of unhashable type " + *t._string))
+               panic(errorString("hash of unhashable type " + t._string))
        }
        if isDirectIface(t) {
                return c1 * fn(unsafe.Pointer(&a.data), h^c0)
@@ -221,7 +221,7 @@ func efaceeq(x, y eface) bool {
        }
        eq := t.alg.equal
        if eq == nil {
-               panic(errorString("comparing uncomparable type " + *t._string))
+               panic(errorString("comparing uncomparable type " + t._string))
        }
        if isDirectIface(t) {
                return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)))
@@ -239,7 +239,7 @@ func ifaceeq(x, y iface) bool {
        t := xtab._type
        eq := t.alg.equal
        if eq == nil {
-               panic(errorString("comparing uncomparable type " + *t._string))
+               panic(errorString("comparing uncomparable type " + t._string))
        }
        if isDirectIface(t) {
                return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)))
index 98a8e839edcd15578de03414dce0b38fea89ab8c..ac4630c833a7fd206fd47c6069d31f1fcd679ec0 100644 (file)
@@ -1838,80 +1838,98 @@ TEXT strings·IndexByte(SB),NOSPLIT,$0-32
 //   AL: byte sought
 //   R8: address to put result
 TEXT runtime·indexbytebody(SB),NOSPLIT,$0
-       MOVQ SI, DI
-
-       CMPQ BX, $16
-       JLT small
-
-       CMPQ BX, $32
-       JA avx2
-no_avx2:
-       // round up to first 16-byte boundary
-       TESTQ $15, SI
-       JZ aligned
-       MOVQ SI, CX
-       ANDQ $~15, CX
-       ADDQ $16, CX
-
-       // search the beginning
-       SUBQ SI, CX
-       REPN; SCASB
-       JZ success
-
-// DI is 16-byte aligned; get ready to search using SSE instructions
-aligned:
-       // round down to last 16-byte boundary
-       MOVQ BX, R11
-       ADDQ SI, R11
-       ANDQ $~15, R11
-
-       // shuffle X0 around so that each byte contains c
+       // Shuffle X0 around so that each byte contains
+       // the character we're looking for.
        MOVD AX, X0
        PUNPCKLBW X0, X0
        PUNPCKLBW X0, X0
        PSHUFL $0, X0, X0
-       JMP condition
+       
+       CMPQ BX, $16
+       JLT small
+
+       MOVQ SI, DI
 
+       CMPQ BX, $32
+       JA avx2
 sse:
-       // move the next 16-byte chunk of the buffer into X1
-       MOVO (DI), X1
-       // compare bytes in X0 to X1
-       PCMPEQB X0, X1
-       // take the top bit of each byte in X1 and put the result in DX
+       LEAQ    -16(SI)(BX*1), AX       // AX = address of last 16 bytes
+       JMP     sseloopentry
+       
+sseloop:
+       // Move the next 16-byte chunk of the data into X1.
+       MOVOU   (DI), X1
+       // Compare bytes in X0 to X1.
+       PCMPEQB X0, X1
+       // Take the top bit of each byte in X1 and put the result in DX.
        PMOVMSKB X1, DX
-       TESTL DX, DX
-       JNZ ssesuccess
-       ADDQ $16, DI
+       // Find first set bit, if any.
+       BSFL    DX, DX
+       JNZ     ssesuccess
+       // Advance to next block.
+       ADDQ    $16, DI
+sseloopentry:
+       CMPQ    DI, AX
+       JB      sseloop
 
-condition:
-       CMPQ DI, R11
-       JLT sse
-
-       // search the end
-       MOVQ SI, CX
-       ADDQ BX, CX
-       SUBQ R11, CX
-       // if CX == 0, the zero flag will be set and we'll end up
-       // returning a false success
-       JZ failure
-       REPN; SCASB
-       JZ success
+       // Search the last 16-byte chunk.  This chunk may overlap with the
+       // chunks we've already searched, but that's ok.
+       MOVQ    AX, DI
+       MOVOU   (AX), X1
+       PCMPEQB X0, X1
+       PMOVMSKB X1, DX
+       BSFL    DX, DX
+       JNZ     ssesuccess
 
 failure:
        MOVQ $-1, (R8)
        RET
 
+// We've found a chunk containing the byte.
+// The chunk was loaded from DI.
+// The index of the matching byte in the chunk is DX.
+// The start of the data is SI.
+ssesuccess:
+       SUBQ SI, DI     // Compute offset of chunk within data.
+       ADDQ DX, DI     // Add offset of byte within chunk.
+       MOVQ DI, (R8)
+       RET
+
 // handle for lengths < 16
 small:
-       MOVQ BX, CX
-       REPN; SCASB
-       JZ success
-       MOVQ $-1, (R8)
+       TESTQ   BX, BX
+       JEQ     failure
+
+       // Check if we'll load across a page boundary.
+       LEAQ    16(SI), AX
+       TESTW   $0xff0, AX
+       JEQ     endofpage
+
+       MOVOU   (SI), X1 // Load data
+       PCMPEQB X0, X1  // Compare target byte with each byte in data.
+       PMOVMSKB X1, DX // Move result bits to integer register.
+       BSFL    DX, DX  // Find first set bit.
+       JZ      failure // No set bit, failure.
+       CMPL    DX, BX
+       JAE     failure // Match is past end of data.
+       MOVQ    DX, (R8)
+       RET
+
+endofpage:
+       MOVOU   -16(SI)(BX*1), X1       // Load data into the high end of X1.
+       PCMPEQB X0, X1  // Compare target byte with each byte in data.
+       PMOVMSKB X1, DX // Move result bits to integer register.
+       MOVL    BX, CX
+       SHLL    CX, DX
+       SHRL    $16, DX // Shift desired bits down to bottom of register.
+       BSFL    DX, DX  // Find first set bit.
+       JZ      failure // No set bit, failure.
+       MOVQ    DX, (R8)
        RET
 
 avx2:
        CMPB   runtime·support_avx2(SB), $1
-       JNE no_avx2
+       JNE sse
        MOVD AX, X0
        LEAQ -32(SI)(BX*1), R11
        VPBROADCASTB  X0, Y1
@@ -1941,22 +1959,6 @@ avx2success:
        VZEROUPPER
        RET
 
-// we've found the chunk containing the byte
-// now just figure out which specific byte it is
-ssesuccess:
-       // get the index of the least significant set bit
-       BSFW DX, DX
-       SUBQ SI, DI
-       ADDQ DI, DX
-       MOVQ DX, (R8)
-       RET
-
-success:
-       SUBQ SI, DI
-       SUBL $1, DI
-       MOVQ DI, (R8)
-       RET
-
 TEXT bytes·Equal(SB),NOSPLIT,$0-49
        MOVQ    a_len+8(FP), BX
        MOVQ    b_len+32(FP), CX
index 5d0206d1c99bf4827d97376f8d640f3c5143249b..2fdfbea0e14f8e617380457bbb7a6cd736a41f6c 100644 (file)
@@ -706,7 +706,7 @@ TEXT runtime·abort(SB),NOSPLIT,$-4-0
 // armPublicationBarrier is a native store/store barrier for ARMv7+.
 // On earlier ARM revisions, armPublicationBarrier is a no-op.
 // This will not work on SMP ARMv6 machines, if any are in use.
-// To implement publiationBarrier in sys_$GOOS_arm.s using the native
+// To implement publicationBarrier in sys_$GOOS_arm.s using the native
 // instructions, use:
 //
 //     TEXT Â·publicationBarrier(SB),NOSPLIT,$-4-0
diff --git a/src/runtime/callers_test.go b/src/runtime/callers_test.go
new file mode 100644 (file)
index 0000000..cb3e6e8
--- /dev/null
@@ -0,0 +1,83 @@
+// Copyright 2016 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime_test
+
+import (
+       "runtime"
+       "strings"
+       "testing"
+)
+
+func f1(pan bool) []uintptr {
+       return f2(pan) // line 14
+}
+
+func f2(pan bool) []uintptr {
+       return f3(pan) // line 18
+}
+
+func f3(pan bool) []uintptr {
+       if pan {
+               panic("f3") // line 23
+       }
+       ret := make([]uintptr, 20)
+       return ret[:runtime.Callers(0, ret)] // line 26
+}
+
+func testCallers(t *testing.T, pcs []uintptr, pan bool) {
+       m := make(map[string]int, len(pcs))
+       frames := runtime.CallersFrames(pcs)
+       for {
+               frame, more := frames.Next()
+               if frame.Function != "" {
+                       m[frame.Function] = frame.Line
+               }
+               if !more {
+                       break
+               }
+       }
+
+       var seen []string
+       for k := range m {
+               seen = append(seen, k)
+       }
+       t.Logf("functions seen: %s", strings.Join(seen, " "))
+
+       var f3Line int
+       if pan {
+               f3Line = 23
+       } else {
+               f3Line = 26
+       }
+       want := []struct {
+               name string
+               line int
+       }{
+               {"f1", 14},
+               {"f2", 18},
+               {"f3", f3Line},
+       }
+       for _, w := range want {
+               if got := m["runtime_test."+w.name]; got != w.line {
+                       t.Errorf("%s is line %d, want %d", w.name, got, w.line)
+               }
+       }
+}
+
+func TestCallers(t *testing.T) {
+       testCallers(t, f1(false), false)
+}
+
+func TestCallersPanic(t *testing.T) {
+       defer func() {
+               if r := recover(); r == nil {
+                       t.Fatal("did not panic")
+               }
+               pcs := make([]uintptr, 20)
+               pcs = pcs[:runtime.Callers(0, pcs)]
+               testCallers(t, pcs, true)
+       }()
+       f1(true)
+}
index 08f230d47ef7632b665b14fe53b502b550604230..14ac9da0ac9c6e752db82736cc9938302b8a6056 100644 (file)
@@ -78,7 +78,7 @@ var _cgo_thread_start = &x_cgo_thread_start
 var x_cgo_sys_thread_create byte
 var _cgo_sys_thread_create = &x_cgo_sys_thread_create
 
-// Notifies that the runtime has been intialized.
+// Notifies that the runtime has been initialized.
 //
 // We currently block at every CGO entry point (via _cgo_wait_runtime_init_done)
 // to ensure that the runtime has been initialized before the CGO call is
index 063c5ce391d861c4eb1199765c54d9eea0c4a8d3..f6f3ce4d90ec275f1deaf0fc3176048df4d2d3fd 100644 (file)
@@ -203,6 +203,8 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
        if t0 != 0 {
                mysg.releasetime = -1
        }
+       // No stack splits between assigning elem and enqueuing mysg
+       // on gp.waiting where copystack can find it.
        mysg.elem = ep
        mysg.waitlink = nil
        mysg.g = gp
@@ -460,6 +462,8 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
        if t0 != 0 {
                mysg.releasetime = -1
        }
+       // No stack splits between assigning elem and enqueuing mysg
+       // on gp.waiting where copystack can find it.
        mysg.elem = ep
        mysg.waitlink = nil
        gp.waiting = mysg
index 497e87f43d95f4618fea9d43d649b62f49ec6626..2cdfae866c2560eedd189f1284f7a24b07f0d9f8 100644 (file)
@@ -573,7 +573,7 @@ func TestSelectDuplicateChannel(t *testing.T) {
                }
                e <- 9
        }()
-       time.Sleep(time.Millisecond) // make sure goroutine A gets qeueued first on c
+       time.Sleep(time.Millisecond) // make sure goroutine A gets queued first on c
 
        // goroutine B
        go func() {
index 63769e801c104c70561850ec21c0fb5db4c20a15..00686ee7559a8362292b85d5ff457362c090c559 100644 (file)
@@ -7,6 +7,7 @@
 package runtime_test
 
 import (
+       "fmt"
        "internal/testenv"
        "os/exec"
        "runtime"
@@ -161,22 +162,35 @@ func TestCgoCheckBytes(t *testing.T) {
                t.Fatal(err)
        }
 
-       cmd := testEnv(exec.Command(exe, "CgoCheckBytes"))
+       // Try it 10 times to avoid flakiness.
+       const tries = 10
+       var tot1, tot2 time.Duration
+       for i := 0; i < tries; i++ {
+               cmd := testEnv(exec.Command(exe, "CgoCheckBytes"))
+               cmd.Env = append(cmd.Env, "GODEBUG=cgocheck=0", fmt.Sprintf("GO_CGOCHECKBYTES_TRY=%d", i))
 
-       start := time.Now()
-       cmd.Run()
-       d1 := time.Since(start)
+               start := time.Now()
+               cmd.Run()
+               d1 := time.Since(start)
 
-       cmd = testEnv(exec.Command(exe, "CgoCheckBytes"))
-       cmd.Env = append(cmd.Env, "GODEBUG=cgocheck=0")
+               cmd = testEnv(exec.Command(exe, "CgoCheckBytes"))
+               cmd.Env = append(cmd.Env, fmt.Sprintf("GO_CGOCHECKBYTES_TRY=%d", i))
 
-       start = time.Now()
-       cmd.Run()
-       d2 := time.Since(start)
+               start = time.Now()
+               cmd.Run()
+               d2 := time.Since(start)
 
-       if d2*10 < d1 {
-               t.Errorf("cgo check too slow: got %v, expected at most %v", d1, d2*10)
+               if d1*20 > d2 {
+                       // The slow version (d2) was less than 20 times
+                       // slower than the fast version (d1), so OK.
+                       return
+               }
+
+               tot1 += d1
+               tot2 += d2
        }
+
+       t.Errorf("cgo check too slow: got %v, expected at most %v", tot2/tries, (tot1/tries)*20)
 }
 
 func TestCgoPanicDeadlock(t *testing.T) {
index de07bcb6434ee23659613594a38c8d533da805e3..3e1ec4bc5a78a06e5c96cd302b7d923a42133f71 100644 (file)
@@ -56,7 +56,7 @@ type stringer interface {
 
 func typestring(x interface{}) string {
        e := efaceOf(&x)
-       return *e._type._string
+       return e._type._string
 }
 
 // For calling from C.
index 2c98482e264712e50ee85e5a2ea5965130827f47..9c1f9f5a03ecc2dcda17a115acd79356007cbcda 100644 (file)
@@ -191,12 +191,9 @@ func Caller(skip int) (pc uintptr, file string, line int, ok bool) {
 //
 // Note that since each slice entry pc[i] is a return program counter,
 // looking up the file and line for pc[i] (for example, using (*Func).FileLine)
-// will return the file and line number of the instruction immediately
+// will normally return the file and line number of the instruction immediately
 // following the call.
-// To look up the file and line number of the call itself, use pc[i]-1.
-// As an exception to this rule, if pc[i-1] corresponds to the function
-// runtime.sigpanic, then pc[i] is the program counter of a faulting
-// instruction and should be used without any subtraction.
+// To easily look up file/line information for the call sequence, use Frames.
 func Callers(skip int, pc []uintptr) int {
        // runtime.callers uses pc.array==nil as a signal
        // to print a stack trace.  Pick off 0-length pc here
index 4d1da1c1dfbb61eba27fd895c042061cd373bed6..3bff36bd78788ddf511572c18908d5879b8a9a46 100644 (file)
@@ -183,11 +183,12 @@ func dumptype(t *_type) {
        dumpint(tagType)
        dumpint(uint64(uintptr(unsafe.Pointer(t))))
        dumpint(uint64(t.size))
-       if t.x == nil || t.x.pkgpath == nil || t.x.name == nil {
-               dumpstr(*t._string)
+       if t.x == nil || t.x.pkgpath == nil {
+               dumpstr(t._string)
        } else {
                pkgpath := stringStructOf(t.x.pkgpath)
-               name := stringStructOf(t.x.name)
+               namestr := t.name()
+               name := stringStructOf(&namestr)
                dumpint(uint64(uintptr(pkgpath.len) + 1 + uintptr(name.len)))
                dwrite(pkgpath.str, uintptr(pkgpath.len))
                dwritebyte('.')
@@ -502,28 +503,10 @@ func dumpparams() {
 
 func itab_callback(tab *itab) {
        t := tab._type
-       // Dump a map from itab* to the type of its data field.
-       // We want this map so we can deduce types of interface referents.
-       if t.kind&kindDirectIface == 0 {
-               // indirect - data slot is a pointer to t.
-               dumptype(t.ptrto)
-               dumpint(tagItab)
-               dumpint(uint64(uintptr(unsafe.Pointer(tab))))
-               dumpint(uint64(uintptr(unsafe.Pointer(t.ptrto))))
-       } else if t.kind&kindNoPointers == 0 {
-               // t is pointer-like - data slot is a t.
-               dumptype(t)
-               dumpint(tagItab)
-               dumpint(uint64(uintptr(unsafe.Pointer(tab))))
-               dumpint(uint64(uintptr(unsafe.Pointer(t))))
-       } else {
-               // Data slot is a scalar.  Dump type just for fun.
-               // With pointer-only interfaces, this shouldn't happen.
-               dumptype(t)
-               dumpint(tagItab)
-               dumpint(uint64(uintptr(unsafe.Pointer(tab))))
-               dumpint(uint64(uintptr(unsafe.Pointer(t))))
-       }
+       dumptype(t)
+       dumpint(tagItab)
+       dumpint(uint64(uintptr(unsafe.Pointer(tab))))
+       dumpint(uint64(uintptr(unsafe.Pointer(t))))
 }
 
 func dumpitabs() {
@@ -639,7 +622,7 @@ func dumpmemprof() {
        }
 }
 
-var dumphdr = []byte("go1.6 heap dump\n")
+var dumphdr = []byte("go1.7 heap dump\n")
 
 func mdump() {
        // make sure we're done sweeping
index 50dff77e42b6cda7cd3faf8c03da375f9a1b910c..d9803678668f63f86dc8867961a5c25a126b7835 100644 (file)
@@ -30,7 +30,7 @@ func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {
                if canfail {
                        return nil
                }
-               panic(&TypeAssertionError{"", *typ._string, *inter.typ._string, *inter.mhdr[0].name})
+               panic(&TypeAssertionError{"", typ._string, inter.typ._string, *inter.mhdr[0].name})
        }
 
        // compiler has provided some good hash codes for us.
@@ -101,7 +101,7 @@ search:
                        if locked != 0 {
                                unlock(&ifaceLock)
                        }
-                       panic(&TypeAssertionError{"", *typ._string, *inter.typ._string, *iname})
+                       panic(&TypeAssertionError{"", typ._string, inter.typ._string, *iname})
                }
                m.bad = 1
                break
@@ -177,18 +177,18 @@ func convT2I(t *_type, inter *interfacetype, cache **itab, elem unsafe.Pointer,
 func panicdottype(have, want, iface *_type) {
        haveString := ""
        if have != nil {
-               haveString = *have._string
+               haveString = have._string
        }
-       panic(&TypeAssertionError{*iface._string, haveString, *want._string, ""})
+       panic(&TypeAssertionError{iface._string, haveString, want._string, ""})
 }
 
 func assertI2T(t *_type, i iface, r unsafe.Pointer) {
        tab := i.tab
        if tab == nil {
-               panic(&TypeAssertionError{"", "", *t._string, ""})
+               panic(&TypeAssertionError{"", "", t._string, ""})
        }
        if tab._type != t {
-               panic(&TypeAssertionError{*tab.inter.typ._string, *tab._type._string, *t._string, ""})
+               panic(&TypeAssertionError{tab.inter.typ._string, tab._type._string, t._string, ""})
        }
        if r != nil {
                if isDirectIface(t) {
@@ -219,10 +219,10 @@ func assertI2T2(t *_type, i iface, r unsafe.Pointer) bool {
 
 func assertE2T(t *_type, e eface, r unsafe.Pointer) {
        if e._type == nil {
-               panic(&TypeAssertionError{"", "", *t._string, ""})
+               panic(&TypeAssertionError{"", "", t._string, ""})
        }
        if e._type != t {
-               panic(&TypeAssertionError{"", *e._type._string, *t._string, ""})
+               panic(&TypeAssertionError{"", e._type._string, t._string, ""})
        }
        if r != nil {
                if isDirectIface(t) {
@@ -266,7 +266,7 @@ func assertI2E(inter *interfacetype, i iface, r *eface) {
        tab := i.tab
        if tab == nil {
                // explicit conversions require non-nil interface value.
-               panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
+               panic(&TypeAssertionError{"", "", inter.typ._string, ""})
        }
        r._type = tab._type
        r.data = i.data
@@ -303,7 +303,7 @@ func assertI2I(inter *interfacetype, i iface, r *iface) {
        tab := i.tab
        if tab == nil {
                // explicit conversions require non-nil interface value.
-               panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
+               panic(&TypeAssertionError{"", "", inter.typ._string, ""})
        }
        if tab.inter == inter {
                r.tab = tab
@@ -342,7 +342,7 @@ func assertE2I(inter *interfacetype, e eface, r *iface) {
        t := e._type
        if t == nil {
                // explicit conversions require non-nil interface value.
-               panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
+               panic(&TypeAssertionError{"", "", inter.typ._string, ""})
        }
        r.tab = getitab(inter, t, false)
        r.data = e.data
@@ -383,7 +383,7 @@ func reflect_ifaceE2I(inter *interfacetype, e eface, dst *iface) {
 func assertE2E(inter *interfacetype, e eface, r *eface) {
        if e._type == nil {
                // explicit conversions require non-nil interface value.
-               panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
+               panic(&TypeAssertionError{"", "", inter.typ._string, ""})
        }
        *r = e
 }
index 336d4d8c811c8ad6a5ffaff1e078a25aebd2bb57..154fc3e0f316f4fd445d8304c9bf80924f518db1 100644 (file)
@@ -290,7 +290,9 @@ func (h heapBits) forward(n uintptr) heapBits {
 // The result includes in its higher bits the bits for subsequent words
 // described by the same bitmap byte.
 func (h heapBits) bits() uint32 {
-       return uint32(*h.bitp) >> h.shift
+       // The (shift & 31) eliminates a test and conditional branch
+       // from the generated code.
+       return uint32(*h.bitp) >> (h.shift & 31)
 }
 
 // isMarked reports whether the heap bits have the marked bit set.
@@ -459,11 +461,11 @@ func typeBitsBulkBarrier(typ *_type, p, size uintptr) {
                throw("runtime: typeBitsBulkBarrier without type")
        }
        if typ.size != size {
-               println("runtime: typeBitsBulkBarrier with type ", *typ._string, " of size ", typ.size, " but memory size", size)
+               println("runtime: typeBitsBulkBarrier with type ", typ._string, " of size ", typ.size, " but memory size", size)
                throw("runtime: invalid typeBitsBulkBarrier")
        }
        if typ.kind&kindGCProg != 0 {
-               println("runtime: typeBitsBulkBarrier with type ", *typ._string, " with GC prog")
+               println("runtime: typeBitsBulkBarrier with type ", typ._string, " with GC prog")
                throw("runtime: invalid typeBitsBulkBarrier")
        }
        if !writeBarrier.needed {
@@ -494,6 +496,10 @@ func typeBitsBulkBarrier(typ *_type, p, size uintptr) {
 // TODO(rsc): Perhaps introduce a different heapBitsSpan type.
 
 // initSpan initializes the heap bitmap for a span.
+// It clears all mark and checkmark bits.
+// If this is a span of pointer-sized objects, it initializes all
+// words to pointer (and there are no dead bits).
+// Otherwise, it initializes all words to scalar/dead.
 func (h heapBits) initSpan(size, n, total uintptr) {
        if total%heapBitmapScale != 0 {
                throw("initSpan: unaligned length")
@@ -558,7 +564,7 @@ func (h heapBits) clearCheckmarkSpan(size, n, total uintptr) {
 // heapBitsSweepSpan coordinates the sweeping of a span by reading
 // and updating the corresponding heap bitmap entries.
 // For each free object in the span, heapBitsSweepSpan sets the type
-// bits for the first two words (or one for single-word objects) to typeDead
+// bits for the first four words (less for smaller objects) to scalar/dead
 // and then calls f(p), where p is the object's base address.
 // f is expected to add the object to a free list.
 // For non-free objects, heapBitsSweepSpan turns off the marked bit.
@@ -910,7 +916,7 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
        }
        if nw == 0 {
                // No pointers! Caller was supposed to check.
-               println("runtime: invalid type ", *typ._string)
+               println("runtime: invalid type ", typ._string)
                throw("heapBitsSetType: called with non-pointer type")
                return
        }
@@ -1094,7 +1100,7 @@ Phase4:
        if doubleCheck {
                end := heapBitsForAddr(x + size)
                if typ.kind&kindGCProg == 0 && (hbitp != end.bitp || (w == nw+2) != (end.shift == 2)) {
-                       println("ended at wrong bitmap byte for", *typ._string, "x", dataSize/typ.size)
+                       println("ended at wrong bitmap byte for", typ._string, "x", dataSize/typ.size)
                        print("typ.size=", typ.size, " typ.ptrdata=", typ.ptrdata, " dataSize=", dataSize, " size=", size, "\n")
                        print("w=", w, " nw=", nw, " b=", hex(b), " nb=", nb, " hb=", hex(hb), "\n")
                        h0 := heapBitsForAddr(x)
@@ -1130,7 +1136,7 @@ Phase4:
                                }
                        }
                        if have != want {
-                               println("mismatch writing bits for", *typ._string, "x", dataSize/typ.size)
+                               println("mismatch writing bits for", typ._string, "x", dataSize/typ.size)
                                print("typ.size=", typ.size, " typ.ptrdata=", typ.ptrdata, " dataSize=", dataSize, " size=", size, "\n")
                                print("kindGCProg=", typ.kind&kindGCProg != 0, "\n")
                                print("w=", w, " nw=", nw, " b=", hex(b), " nb=", nb, " hb=", hex(hb), "\n")
index 29a7b77376273aabd6e27558cbf45bbd7fcdd1c3..8a2fbe98c9328cc4651ec9c4142c8f44c19ddfad 100644 (file)
@@ -195,7 +195,6 @@ func (c *mcentral) freeSpan(s *mspan, n int32, start gclinkptr, end gclinkptr, p
        s.needzero = 1
        s.freelist = 0
        unlock(&c.lock)
-       heapBitsForSpan(s.base()).initSpan(s.layout())
        mheap_.freeSpan(s, 0)
        return true
 }
index c257d59b30b85d9fd3971e934721cbe392d550d2..6f30eca2427b75d2229fa0e14a1184b635551cc7 100644 (file)
@@ -103,7 +103,7 @@ loop_avx2_huge:
        ADDQ    $128, DI
        CMPQ    BX, $128
        JAE     loop_avx2_huge
-       // In the desciption of MOVNTDQ in [1]
+       // In the description of MOVNTDQ in [1]
        // "... fencing operation implemented with the SFENCE or MFENCE instruction
        // should be used in conjunction with MOVNTDQ instructions..."
        // [1] 64-ia-32-architectures-software-developer-manual-325462.pdf
index b6d0b854598fb60092e9de2d9148b9baf6dc2876..ea73b455b478515f45262f37e30254d6020e5577 100644 (file)
@@ -24,7 +24,7 @@ check:
        BC      12, 9, backward // I think you should be able to write this as "BGT CR2, backward"
 
        // Copying forward proceeds by copying R6 words then copying R7 bytes.
-       // R3 and R4 are advanced as we copy. Becuase PPC64 lacks post-increment
+       // R3 and R4 are advanced as we copy. Because PPC64 lacks post-increment
        // load/store, R3 and R4 point before the bytes that are to be copied.
 
        BC      12, 6, noforwardlarge   // "BEQ CR1, noforwardlarge"
index 512edeffe81444ed920439d27f8fecceff2d02a7..7d458625217a47333f2456b2266999e7d4946db6 100644 (file)
@@ -274,7 +274,7 @@ func SetFinalizer(obj interface{}, finalizer interface{}) {
                throw("runtime.SetFinalizer: first argument is nil")
        }
        if etyp.kind&kindMask != kindPtr {
-               throw("runtime.SetFinalizer: first argument is " + *etyp._string + ", not pointer")
+               throw("runtime.SetFinalizer: first argument is " + etyp._string + ", not pointer")
        }
        ot := (*ptrtype)(unsafe.Pointer(etyp))
        if ot.elem == nil {
@@ -328,11 +328,11 @@ func SetFinalizer(obj interface{}, finalizer interface{}) {
        }
 
        if ftyp.kind&kindMask != kindFunc {
-               throw("runtime.SetFinalizer: second argument is " + *ftyp._string + ", not a function")
+               throw("runtime.SetFinalizer: second argument is " + ftyp._string + ", not a function")
        }
        ft := (*functype)(unsafe.Pointer(ftyp))
        if ft.dotdotdot || len(ft.in) != 1 {
-               throw("runtime.SetFinalizer: cannot pass " + *etyp._string + " to finalizer " + *ftyp._string)
+               throw("runtime.SetFinalizer: cannot pass " + etyp._string + " to finalizer " + ftyp._string)
        }
        fint := ft.in[0]
        switch {
@@ -340,7 +340,7 @@ func SetFinalizer(obj interface{}, finalizer interface{}) {
                // ok - same type
                goto okarg
        case fint.kind&kindMask == kindPtr:
-               if (fint.x == nil || fint.x.name == nil || etyp.x == nil || etyp.x.name == nil) && (*ptrtype)(unsafe.Pointer(fint)).elem == ot.elem {
+               if (fint.x == nil || etyp.x == nil) && (*ptrtype)(unsafe.Pointer(fint)).elem == ot.elem {
                        // ok - not same type, but both pointers,
                        // one or the other is unnamed, and same element type, so assignable.
                        goto okarg
@@ -355,7 +355,7 @@ func SetFinalizer(obj interface{}, finalizer interface{}) {
                        goto okarg
                }
        }
-       throw("runtime.SetFinalizer: cannot pass " + *etyp._string + " to finalizer " + *ftyp._string)
+       throw("runtime.SetFinalizer: cannot pass " + etyp._string + " to finalizer " + ftyp._string)
 okarg:
        // compute size needed for return parameters
        nret := uintptr(0)
index 102d44160e6c881c6ff025c7cce53655e7eae4c9..138a623ca55d712c8041bbeb91e2393b03a415e9 100644 (file)
@@ -1556,8 +1556,8 @@ func gcMark(start_time int64) {
 
        gchelperstart()
 
-       var gcw gcWork
-       gcDrain(&gcw, gcDrainBlock)
+       gcw := &getg().m.p.ptr().gcw
+       gcDrain(gcw, gcDrainBlock)
        gcw.dispose()
 
        gcMarkRootCheck()
@@ -1799,8 +1799,8 @@ func gchelper() {
 
        // Parallel mark over GC roots and heap
        if gcphase == _GCmarktermination {
-               var gcw gcWork
-               gcDrain(&gcw, gcDrainBlock) // blocks in getfull
+               gcw := &_g_.m.p.ptr().gcw
+               gcDrain(gcw, gcDrainBlock) // blocks in getfull
                gcw.dispose()
        }
 
index eac45ec16850e64e0e70bfaa7d6612f379058408..0be908bfe8c65761a5a6f5328ed9c200bfb5962e 100644 (file)
@@ -98,10 +98,7 @@ var oneptrmask = [...]uint8{1}
 // Preemption must be disabled (because this uses a gcWork).
 //
 //go:nowritebarrier
-func markroot(i uint32) {
-       // TODO: Consider using getg().m.p.ptr().gcw.
-       var gcw gcWork
-
+func markroot(gcw *gcWork, i uint32) {
        baseData := uint32(fixedRootCount)
        baseBSS := baseData + uint32(work.nDataRoots)
        baseSpans := baseBSS + uint32(work.nBSSRoots)
@@ -111,17 +108,17 @@ func markroot(i uint32) {
        switch {
        case baseData <= i && i < baseBSS:
                for datap := &firstmoduledata; datap != nil; datap = datap.next {
-                       markrootBlock(datap.data, datap.edata-datap.data, datap.gcdatamask.bytedata, &gcw, int(i-baseData))
+                       markrootBlock(datap.data, datap.edata-datap.data, datap.gcdatamask.bytedata, gcw, int(i-baseData))
                }
 
        case baseBSS <= i && i < baseSpans:
                for datap := &firstmoduledata; datap != nil; datap = datap.next {
-                       markrootBlock(datap.bss, datap.ebss-datap.bss, datap.gcbssmask.bytedata, &gcw, int(i-baseBSS))
+                       markrootBlock(datap.bss, datap.ebss-datap.bss, datap.gcbssmask.bytedata, gcw, int(i-baseBSS))
                }
 
        case i == fixedRootFinalizers:
                for fb := allfin; fb != nil; fb = fb.alllink {
-                       scanblock(uintptr(unsafe.Pointer(&fb.fin[0])), uintptr(fb.cnt)*unsafe.Sizeof(fb.fin[0]), &finptrmask[0], &gcw)
+                       scanblock(uintptr(unsafe.Pointer(&fb.fin[0])), uintptr(fb.cnt)*unsafe.Sizeof(fb.fin[0]), &finptrmask[0], gcw)
                }
 
        case i == fixedRootFlushCaches:
@@ -131,7 +128,7 @@ func markroot(i uint32) {
 
        case baseSpans <= i && i < baseStacks:
                // mark MSpan.specials
-               markrootSpans(&gcw, int(i-baseSpans))
+               markrootSpans(gcw, int(i-baseSpans))
 
        default:
                // the rest is scanning goroutine stacks
@@ -193,8 +190,6 @@ func markroot(i uint32) {
                        }
                })
        }
-
-       gcw.dispose()
 }
 
 // markrootBlock scans the shard'th shard of the block of memory [b0,
@@ -808,8 +803,7 @@ func gcDrain(gcw *gcWork, flags gcDrainFlags) {
                        if job >= work.markrootJobs {
                                break
                        }
-                       // TODO: Pass in gcw.
-                       markroot(job)
+                       markroot(gcw, job)
                }
        }
 
index b00ceb0a8a326d936192344c92e9b4ebb9cdf9dd..d6d91d202149171994e27439c9d15ad71654a491 100644 (file)
@@ -276,7 +276,6 @@ func (s *mspan) sweep(preserve bool) bool {
                        if preserve {
                                throw("can't preserve large span")
                        }
-                       heapBitsForSpan(p).initSpan(s.layout())
                        s.needzero = 1
 
                        // Free the span after heapBitsSweepSpan
index 0a0285d8163ca9f0225f8de06a7961213f1dc748..7bc4278195c374353ce7bf210e5dcef42307af33 100644 (file)
@@ -11,8 +11,7 @@ import (
 )
 
 const (
-       _Debugwbufs  = false // if true check wbufs consistency
-       _WorkbufSize = 2048  // in bytes; larger values result in less contention
+       _WorkbufSize = 2048 // in bytes; larger values result in less contention
 )
 
 // Garbage collector work pool abstraction.
@@ -44,14 +43,6 @@ func (wp wbufptr) ptr() *workbuf {
 //
 // A gcWork can be used on the stack as follows:
 //
-//     var gcw gcWork
-//     disable preemption
-//     .. call gcw.put() to produce and gcw.get() to consume ..
-//     gcw.dispose()
-//     enable preemption
-//
-// Or from the per-P gcWork cache:
-//
 //     (preemption must be disabled)
 //     gcw := &getg().m.p.ptr().gcw
 //     .. call gcw.put() to produce and gcw.get() to consume ..
@@ -94,10 +85,10 @@ type gcWork struct {
 }
 
 func (w *gcWork) init() {
-       w.wbuf1 = wbufptrOf(getempty(101))
-       wbuf2 := trygetfull(102)
+       w.wbuf1 = wbufptrOf(getempty())
+       wbuf2 := trygetfull()
        if wbuf2 == nil {
-               wbuf2 = getempty(103)
+               wbuf2 = getempty()
        }
        w.wbuf2 = wbufptrOf(wbuf2)
 }
@@ -105,9 +96,7 @@ func (w *gcWork) init() {
 // put enqueues a pointer for the garbage collector to trace.
 // obj must point to the beginning of a heap object.
 //go:nowritebarrier
-func (ww *gcWork) put(obj uintptr) {
-       w := (*gcWork)(noescape(unsafe.Pointer(ww))) // TODO: remove when escape analysis is fixed
-
+func (w *gcWork) put(obj uintptr) {
        wbuf := w.wbuf1.ptr()
        if wbuf == nil {
                w.init()
@@ -117,8 +106,8 @@ func (ww *gcWork) put(obj uintptr) {
                w.wbuf1, w.wbuf2 = w.wbuf2, w.wbuf1
                wbuf = w.wbuf1.ptr()
                if wbuf.nobj == len(wbuf.obj) {
-                       putfull(wbuf, 132)
-                       wbuf = getempty(133)
+                       putfull(wbuf)
+                       wbuf = getempty()
                        w.wbuf1 = wbufptrOf(wbuf)
                }
        }
@@ -133,9 +122,7 @@ func (ww *gcWork) put(obj uintptr) {
 // queue, tryGet returns 0.  Note that there may still be pointers in
 // other gcWork instances or other caches.
 //go:nowritebarrier
-func (ww *gcWork) tryGet() uintptr {
-       w := (*gcWork)(noescape(unsafe.Pointer(ww))) // TODO: remove when escape analysis is fixed
-
+func (w *gcWork) tryGet() uintptr {
        wbuf := w.wbuf1.ptr()
        if wbuf == nil {
                w.init()
@@ -147,11 +134,11 @@ func (ww *gcWork) tryGet() uintptr {
                wbuf = w.wbuf1.ptr()
                if wbuf.nobj == 0 {
                        owbuf := wbuf
-                       wbuf = trygetfull(167)
+                       wbuf = trygetfull()
                        if wbuf == nil {
                                return 0
                        }
-                       putempty(owbuf, 166)
+                       putempty(owbuf)
                        w.wbuf1 = wbufptrOf(wbuf)
                }
        }
@@ -164,9 +151,7 @@ func (ww *gcWork) tryGet() uintptr {
 // if necessary to ensure all pointers from all queues and caches have
 // been retrieved.  get returns 0 if there are no pointers remaining.
 //go:nowritebarrier
-func (ww *gcWork) get() uintptr {
-       w := (*gcWork)(noescape(unsafe.Pointer(ww))) // TODO: remove when escape analysis is fixed
-
+func (w *gcWork) get() uintptr {
        wbuf := w.wbuf1.ptr()
        if wbuf == nil {
                w.init()
@@ -178,11 +163,11 @@ func (ww *gcWork) get() uintptr {
                wbuf = w.wbuf1.ptr()
                if wbuf.nobj == 0 {
                        owbuf := wbuf
-                       wbuf = getfull(185)
+                       wbuf = getfull()
                        if wbuf == nil {
                                return 0
                        }
-                       putempty(owbuf, 184)
+                       putempty(owbuf)
                        w.wbuf1 = wbufptrOf(wbuf)
                }
        }
@@ -203,17 +188,17 @@ func (ww *gcWork) get() uintptr {
 func (w *gcWork) dispose() {
        if wbuf := w.wbuf1.ptr(); wbuf != nil {
                if wbuf.nobj == 0 {
-                       putempty(wbuf, 212)
+                       putempty(wbuf)
                } else {
-                       putfull(wbuf, 214)
+                       putfull(wbuf)
                }
                w.wbuf1 = 0
 
                wbuf = w.wbuf2.ptr()
                if wbuf.nobj == 0 {
-                       putempty(wbuf, 218)
+                       putempty(wbuf)
                } else {
-                       putfull(wbuf, 220)
+                       putfull(wbuf)
                }
                w.wbuf2 = 0
        }
@@ -239,8 +224,8 @@ func (w *gcWork) balance() {
                return
        }
        if wbuf := w.wbuf2.ptr(); wbuf.nobj != 0 {
-               putfull(wbuf, 246)
-               w.wbuf2 = wbufptrOf(getempty(247))
+               putfull(wbuf)
+               w.wbuf2 = wbufptrOf(getempty())
        } else if wbuf := w.wbuf1.ptr(); wbuf.nobj > 4 {
                w.wbuf1 = wbufptrOf(handoff(wbuf))
        }
@@ -257,10 +242,8 @@ func (w *gcWork) empty() bool {
 // avoid contending on the global work buffer lists.
 
 type workbufhdr struct {
-       node  lfnode // must be first
-       nobj  int
-       inuse bool   // This workbuf is in use by some gorotuine and is not on the work.empty/full queues.
-       log   [4]int // line numbers forming a history of ownership changes to workbuf
+       node lfnode // must be first
+       nobj int
 }
 
 type workbuf struct {
@@ -273,69 +256,23 @@ type workbuf struct {
 // workbufs.
 // If the GC asks for some work these are the only routines that
 // make wbufs available to the GC.
-// Each of the gets and puts also take an distinct integer that is used
-// to record a brief history of changes to ownership of the workbuf.
-// The convention is to use a unique line number but any encoding
-// is permissible. For example if you want to pass in 2 bits of information
-// you could simple add lineno1*100000+lineno2.
-
-// logget records the past few values of entry to aid in debugging.
-// logget checks the buffer b is not currently in use.
-func (b *workbuf) logget(entry int) {
-       if !_Debugwbufs {
-               return
-       }
-       if b.inuse {
-               println("runtime: logget fails log entry=", entry,
-                       "b.log[0]=", b.log[0], "b.log[1]=", b.log[1],
-                       "b.log[2]=", b.log[2], "b.log[3]=", b.log[3])
-               throw("logget: get not legal")
-       }
-       b.inuse = true
-       copy(b.log[1:], b.log[:])
-       b.log[0] = entry
-}
-
-// logput records the past few values of entry to aid in debugging.
-// logput checks the buffer b is currently in use.
-func (b *workbuf) logput(entry int) {
-       if !_Debugwbufs {
-               return
-       }
-       if !b.inuse {
-               println("runtime: logput fails log entry=", entry,
-                       "b.log[0]=", b.log[0], "b.log[1]=", b.log[1],
-                       "b.log[2]=", b.log[2], "b.log[3]=", b.log[3])
-               throw("logput: put not legal")
-       }
-       b.inuse = false
-       copy(b.log[1:], b.log[:])
-       b.log[0] = entry
-}
 
 func (b *workbuf) checknonempty() {
        if b.nobj == 0 {
-               println("runtime: nonempty check fails",
-                       "b.log[0]=", b.log[0], "b.log[1]=", b.log[1],
-                       "b.log[2]=", b.log[2], "b.log[3]=", b.log[3])
                throw("workbuf is empty")
        }
 }
 
 func (b *workbuf) checkempty() {
        if b.nobj != 0 {
-               println("runtime: empty check fails",
-                       "b.log[0]=", b.log[0], "b.log[1]=", b.log[1],
-                       "b.log[2]=", b.log[2], "b.log[3]=", b.log[3])
                throw("workbuf is not empty")
        }
 }
 
 // getempty pops an empty work buffer off the work.empty list,
 // allocating new buffers if none are available.
-// entry is used to record a brief history of ownership.
 //go:nowritebarrier
-func getempty(entry int) *workbuf {
+func getempty() *workbuf {
        var b *workbuf
        if work.empty != 0 {
                b = (*workbuf)(lfstackpop(&work.empty))
@@ -346,16 +283,14 @@ func getempty(entry int) *workbuf {
        if b == nil {
                b = (*workbuf)(persistentalloc(unsafe.Sizeof(*b), sys.CacheLineSize, &memstats.gc_sys))
        }
-       b.logget(entry)
        return b
 }
 
 // putempty puts a workbuf onto the work.empty list.
 // Upon entry this go routine owns b. The lfstackpush relinquishes ownership.
 //go:nowritebarrier
-func putempty(b *workbuf, entry int) {
+func putempty(b *workbuf) {
        b.checkempty()
-       b.logput(entry)
        lfstackpush(&work.empty, &b.node)
 }
 
@@ -363,9 +298,8 @@ func putempty(b *workbuf, entry int) {
 // putfull accepts partially full buffers so the GC can avoid competing
 // with the mutators for ownership of partially full buffers.
 //go:nowritebarrier
-func putfull(b *workbuf, entry int) {
+func putfull(b *workbuf) {
        b.checknonempty()
-       b.logput(entry)
        lfstackpush(&work.full, &b.node)
 
        // We just made more work available. Let the GC controller
@@ -378,10 +312,9 @@ func putfull(b *workbuf, entry int) {
 // trygetfull tries to get a full or partially empty workbuffer.
 // If one is not immediately available return nil
 //go:nowritebarrier
-func trygetfull(entry int) *workbuf {
+func trygetfull() *workbuf {
        b := (*workbuf)(lfstackpop(&work.full))
        if b != nil {
-               b.logget(entry)
                b.checknonempty()
                return b
        }
@@ -400,10 +333,9 @@ func trygetfull(entry int) *workbuf {
 // This is in fact the termination condition for the STW mark
 // phase.
 //go:nowritebarrier
-func getfull(entry int) *workbuf {
+func getfull() *workbuf {
        b := (*workbuf)(lfstackpop(&work.full))
        if b != nil {
-               b.logget(entry)
                b.checknonempty()
                return b
        }
@@ -422,7 +354,6 @@ func getfull(entry int) *workbuf {
                        }
                        b = (*workbuf)(lfstackpop(&work.full))
                        if b != nil {
-                               b.logget(entry)
                                b.checknonempty()
                                return b
                        }
@@ -452,7 +383,7 @@ func getfull(entry int) *workbuf {
 //go:nowritebarrier
 func handoff(b *workbuf) *workbuf {
        // Make new buffer with half of b's pointers.
-       b1 := getempty(915)
+       b1 := getempty()
        n := b.nobj / 2
        b.nobj -= n
        b1.nobj = n
@@ -462,6 +393,6 @@ func handoff(b *workbuf) *workbuf {
        _g_.m.gcstats.nhandoffcnt += uint64(n)
 
        // Put b on full list - let first half of b get stolen.
-       putfull(b, 942)
+       putfull(b)
        return b1
 }
index 3efa375d6a4afb2be0bbfac5a04cd6e6bf1a6961..d498a9328adc44952e428fed7c0ad1e91d269fba 100644 (file)
@@ -624,7 +624,7 @@ func tracealloc(p unsafe.Pointer, size uintptr, typ *_type) {
        if typ == nil {
                print("tracealloc(", p, ", ", hex(size), ")\n")
        } else {
-               print("tracealloc(", p, ", ", hex(size), ", ", *typ._string, ")\n")
+               print("tracealloc(", p, ", ", hex(size), ", ", typ._string, ")\n")
        }
        if gp.m.curg == nil || gp == gp.m.curg {
                goroutineheader(gp)
index 86e9b997ef658b93a0c8d4b3f8fb576d58a53cf9..53b2aacdb57746d75ad5db866c58bd94d84f4389 100644 (file)
@@ -58,7 +58,7 @@ import "unsafe"
 //
 // The open and arming mechanisms are serialized using the lock
 // inside PollDesc. This is required because the netpoll loop runs
-// asynchonously in respect to other Go code and by the time we get
+// asynchronously in respect to other Go code and by the time we get
 // to call port_associate to update the association in the loop, the
 // file descriptor might have been closed and reopened already. The
 // lock allows runtime·netpollupdate to be called synchronously from
@@ -125,7 +125,7 @@ func netpollopen(fd uintptr, pd *pollDesc) int32 {
        lock(&pd.lock)
        // We don't register for any specific type of events yet, that's
        // netpollarm's job. We merely ensure we call port_associate before
-       // asynchonous connect/accept completes, so when we actually want
+       // asynchronous connect/accept completes, so when we actually want
        // to do any I/O, the call to port_associate (from netpollarm,
        // with the interested event set) will unblock port_getn right away
        // because of the I/O readiness notification.
index 3577a2406b9741d5224ea68bbe7bab5e5d4e161b..0f39cade3b864f348651380188ba8772bc6d7b52 100644 (file)
@@ -15,8 +15,6 @@ const (
        _AT_SYSINFO = 32
 )
 
-var _vdso uint32
-
 func sysargs(argc int32, argv **byte) {
        // skip over argv, envv to get to auxv
        n := argc + 1
@@ -28,9 +26,6 @@ func sysargs(argc int32, argv **byte) {
 
        for i := 0; auxv[i] != _AT_NULL; i += 2 {
                switch auxv[i] {
-               case _AT_SYSINFO:
-                       _vdso = auxv[i+1]
-
                case _AT_RANDOM:
                        startupRandomData = (*[16]byte)(unsafe.Pointer(uintptr(auxv[i+1])))[:]
                }
index e09a33d5d9f8242f538a880257c1239daf992cba..5e91fa8abeab240ef6161d4b9f1a2b341d1f8985 100644 (file)
@@ -325,33 +325,24 @@ func printCountProfile(w io.Writer, debug int, name string, p countProfile) erro
 // for a single stack trace.
 func printStackRecord(w io.Writer, stk []uintptr, allFrames bool) {
        show := allFrames
-       wasPanic := false
-       for i, pc := range stk {
-               f := runtime.FuncForPC(pc)
-               if f == nil {
+       frames := runtime.CallersFrames(stk)
+       for {
+               frame, more := frames.Next()
+               name := frame.Function
+               if name == "" {
                        show = true
-                       fmt.Fprintf(w, "#\t%#x\n", pc)
-                       wasPanic = false
+                       fmt.Fprintf(w, "#\t%#x\n", frame.PC)
                } else {
-                       tracepc := pc
-                       // Back up to call instruction.
-                       if i > 0 && pc > f.Entry() && !wasPanic {
-                               if runtime.GOARCH == "386" || runtime.GOARCH == "amd64" {
-                                       tracepc--
-                               } else {
-                                       tracepc -= 4 // arm, etc
-                               }
-                       }
-                       file, line := f.FileLine(tracepc)
-                       name := f.Name()
                        // Hide runtime.goexit and any runtime functions at the beginning.
                        // This is useful mainly for allocation traces.
-                       wasPanic = name == "runtime.gopanic"
                        if name == "runtime.goexit" || !show && strings.HasPrefix(name, "runtime.") {
                                continue
                        }
                        show = true
-                       fmt.Fprintf(w, "#\t%#x\t%s+%#x\t%s:%d\n", pc, name, pc-f.Entry(), file, line)
+                       fmt.Fprintf(w, "#\t%#x\t%s+%#x\t%s:%d\n", frame.PC, name, frame.PC-frame.Entry, frame.File, frame.Line)
+               }
+               if !more {
+                       break
                }
        }
        if !show {
index 389917916fb9b50be0c083ef8409c536a1886b6e..16237e98ec1cbcb74548e79aa0133c36e5fc3e6b 100644 (file)
@@ -660,10 +660,6 @@ func casfrom_Gscanstatus(gp *g, oldval, newval uint32) {
                if newval == oldval&^_Gscan {
                        success = atomic.Cas(&gp.atomicstatus, oldval, newval)
                }
-       case _Gscanenqueue:
-               if newval == _Gwaiting {
-                       success = atomic.Cas(&gp.atomicstatus, oldval, newval)
-               }
        }
        if !success {
                print("runtime: casfrom_Gscanstatus failed gp=", gp, ", oldval=", hex(oldval), ", newval=", hex(newval), "\n")
@@ -680,15 +676,12 @@ func casfrom_Gscanstatus(gp *g, oldval, newval uint32) {
 func castogscanstatus(gp *g, oldval, newval uint32) bool {
        switch oldval {
        case _Grunnable,
+               _Grunning,
                _Gwaiting,
                _Gsyscall:
                if newval == oldval|_Gscan {
                        return atomic.Cas(&gp.atomicstatus, oldval, newval)
                }
-       case _Grunning:
-               if newval == _Gscanrunning || newval == _Gscanenqueue {
-                       return atomic.Cas(&gp.atomicstatus, oldval, newval)
-               }
        }
        print("runtime: castogscanstatus oldval=", hex(oldval), " newval=", hex(newval), "\n")
        throw("castogscanstatus")
@@ -843,17 +836,6 @@ func restartg(gp *g) {
                _Gscanwaiting,
                _Gscansyscall:
                casfrom_Gscanstatus(gp, s, s&^_Gscan)
-
-       // Scan is now completed.
-       // Goroutine now needs to be made runnable.
-       // We put it on the global run queue; ready blocks on the global scheduler lock.
-       case _Gscanenqueue:
-               casfrom_Gscanstatus(gp, _Gscanenqueue, _Gwaiting)
-               if gp != getg().m.curg {
-                       throw("processing Gscanenqueue on wrong m")
-               }
-               dropg()
-               ready(gp, 0)
        }
 }
 
@@ -2099,10 +2081,8 @@ top:
 func dropg() {
        _g_ := getg()
 
-       if _g_.m.lockedg == nil {
-               _g_.m.curg.m = nil
-               _g_.m.curg = nil
-       }
+       _g_.m.curg.m = nil
+       _g_.m.curg = nil
 }
 
 func parkunlock_c(gp *g, lock unsafe.Pointer) bool {
@@ -3910,7 +3890,7 @@ retry:
        if runqputslow(_p_, gp, h, t) {
                return
        }
-       // the queue is not full, now the put above must suceed
+       // the queue is not full, now the put above must succeed
        goto retry
 }
 
index 0c71a019dd59dd9f70102d423e39a95100a6bd9b..27d9efb6871eaca2d13f708f7c418407a6f7181e 100644 (file)
@@ -180,4 +180,21 @@ func TestFail(t *testing.T) {
 PASS
 Found 1 data race\(s\)
 FAIL`},
+
+       {"slicebytetostring_pc", "run", "atexit_sleep_ms=0", `
+package main
+func main() {
+       done := make(chan string)
+       data := make([]byte, 10)
+       go func() {
+               done <- string(data)
+       }()
+       data[0] = 1
+       <-done
+}
+`, `
+  runtime\.slicebytetostring\(\)
+      .*/runtime/string\.go:.*
+  main\.main\.func1\(\)
+      .*/main.go:7`},
 }
index 59a30b41e8bb9b58caf7b5e762929e866578bb42..23bfc98b100cddb5e647b8e40f09bd884f70fbaa 100644 (file)
@@ -73,11 +73,3 @@ GLOBL _rt0_386_linux_lib_argv<>(SB),NOPTR, $4
 
 TEXT main(SB),NOSPLIT,$0
        JMP     runtime·rt0_go(SB)
-
-TEXT _fallback_vdso(SB),NOSPLIT,$0
-       INT     $0x80
-       RET
-
-DATA   runtime·_vdso(SB)/4, $_fallback_vdso(SB)
-GLOBL  runtime·_vdso(SB), NOPTR, $4
-
index f63e09cc6177beba5b7e07149d0c929d215d71bb..400ea296a9b3bba93b65164c29b19221726618b1 100644 (file)
@@ -52,7 +52,7 @@ var (
        argv **byte
 )
 
-// nosplit for use in linux/386 startup linux_setup_vdso
+// nosplit for use in linux startup sysargs
 //go:nosplit
 func argv_index(argv **byte, i int32) *byte {
        return *(**byte)(add(unsafe.Pointer(argv), uintptr(i)*sys.PtrSize))
index 6a4dfa17b8ac0fcb5f861caa481de647f554b5f7..5f22afd863dc01779b29fb9dea1a5ab14073703f 100644 (file)
@@ -26,7 +26,7 @@ const (
        _Gwaiting                // 4
        _Gmoribund_unused        // 5 currently unused, but hardcoded in gdb scripts
        _Gdead                   // 6
-       _Genqueue                // 7 Only the Gscanenqueue is used.
+       _Genqueue_unused         // 7 currently unused
        _Gcopystack              // 8 in this state when newstack is moving the stack
        // the following encode that the GC is scanning the stack and what to do when it is done
        _Gscan = 0x1000 // atomicstatus&~Gscan = the non-scan state,
@@ -37,7 +37,7 @@ const (
        _Gscanwaiting  = _Gscan + _Gwaiting  //  0x1004 When scanning completes make it Gwaiting
        // _Gscanmoribund_unused,               //  not possible
        // _Gscandead,                          //  not possible
-       _Gscanenqueue = _Gscan + _Genqueue //  When scanning completes make it Grunnable and put on runqueue
+       // _Gscanenqueue_unused                 //  not possible
 )
 
 const (
index a6150a77ee9502b99b9673af7d7d86272d75024e..b3350ef82fff3e5aeee3c16bf7e14adbe0d84e76 100644 (file)
@@ -104,7 +104,7 @@ func TestStopCPUProfilingWithProfilerOff(t *testing.T) {
 // of the larger addresses must themselves be invalid addresses.
 // We might get unlucky and the OS might have mapped one of these
 // addresses, but probably not: they're all in the first page, very high
-// adderesses that normally an OS would reserve for itself, or malformed
+// addresses that normally an OS would reserve for itself, or malformed
 // addresses. Even so, we might have to remove one or two on different
 // systems. We will see.
 
index b6c3fea001db858c2b17621c6d280ab56a2988f3..b315dde6c616f3858027540320189d280d4cacae 100644 (file)
@@ -370,6 +370,8 @@ loop:
                sg.g = gp
                // Note: selectdone is adjusted for stack copies in stack1.go:adjustsudogs
                sg.selectdone = (*uint32)(noescape(unsafe.Pointer(&done)))
+               // No stack splits between assigning elem and enqueuing
+               // sg on gp.waiting where copystack can find it.
                sg.elem = cas.elem
                sg.releasetime = 0
                if t0 != 0 {
index 0374f4a2d7825ef7b5f0ae17042191562057ec3e..25187dad74a36aa14d2d1f390fc06c4590133ef8 100644 (file)
@@ -142,30 +142,7 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
        level, _, docrash := gotraceback()
        if level > 0 {
                goroutineheader(gp)
-
-               // On Linux/386, all system calls go through the vdso kernel_vsyscall routine.
-               // Normally we don't see those PCs, but during signals we can.
-               // If we see a PC in the vsyscall area (it moves around, but near the top of memory),
-               // assume we're blocked in the vsyscall routine, which has saved
-               // three words on the stack after the initial call saved the caller PC.
-               // Pop all four words off SP and use the saved PC.
-               // The check of the stack bounds here should suffice to avoid a fault
-               // during the actual PC pop.
-               // If we do load a bogus PC, not much harm done: we weren't going
-               // to get a decent traceback anyway.
-               // TODO(rsc): Make this more precise: we should do more checks on the PC,
-               // and we should find out whether different versions of the vdso page
-               // use different prologues that store different amounts on the stack.
-               pc := uintptr(c.eip())
-               sp := uintptr(c.esp())
-               if GOOS == "linux" && pc >= 0xf4000000 && gp.stack.lo <= sp && sp+16 <= gp.stack.hi {
-                       // Assume in vsyscall page.
-                       sp += 16
-                       pc = *(*uintptr)(unsafe.Pointer(sp - 4))
-                       print("runtime: unwind vdso kernel_vsyscall: pc=", hex(pc), " sp=", hex(sp), "\n")
-               }
-
-               tracebacktrap(pc, sp, 0, gp)
+               tracebacktrap(uintptr(c.eip()), uintptr(c.esp()), 0, gp)
                if crashing > 0 && gp != _g_.m.curg && _g_.m.curg != nil && readgstatus(_g_.m.curg)&^_Gscan == _Grunning {
                        // tracebackothers on original m skipped this one; trace it now.
                        goroutineheader(_g_.m.curg)
index 202e7bbf862bac6bdaabd1e492aae96c2383fa0b..99048d612eb600c99f113fe904b3863ca809de36 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Software floating point interpretaton of ARM 7500 FP instructions.
+// Software floating point interpretation of ARM 7500 FP instructions.
 // The interpretation is not bit compatible with the 7500.
 // It uses true little-endian doubles, while the 7500 used mixed-endian.
 
index dd04bda04ba3cb37833d1201c3defc70ec035310..5dc7e0295af770a108df6534d0b0846850866a76 100644 (file)
@@ -84,7 +84,7 @@ func slicebytetostring(buf *tmpBuf, b []byte) string {
        if raceenabled && l > 0 {
                racereadrangepc(unsafe.Pointer(&b[0]),
                        uintptr(l),
-                       getcallerpc(unsafe.Pointer(&b)),
+                       getcallerpc(unsafe.Pointer(&buf)),
                        funcPC(slicebytetostring))
        }
        if msanenabled && l > 0 {
@@ -189,7 +189,7 @@ func slicerunetostring(buf *tmpBuf, a []rune) string {
        if raceenabled && len(a) > 0 {
                racereadrangepc(unsafe.Pointer(&a[0]),
                        uintptr(len(a))*unsafe.Sizeof(a[0]),
-                       getcallerpc(unsafe.Pointer(&a)),
+                       getcallerpc(unsafe.Pointer(&buf)),
                        funcPC(slicerunetostring))
        }
        if msanenabled && len(a) > 0 {
index 00b0a850e0d4635239d1112f717243238bd6d2a9..afea41448fd97473fd77d72f3f3bf779e053399e 100644 (file)
@@ -9,6 +9,84 @@ import (
        "unsafe"
 )
 
+// Frames may be used to get function/file/line information for a
+// slice of PC values returned by Callers.
+type Frames struct {
+       callers []uintptr
+
+       // If previous caller in iteration was a panic, then
+       // ci.callers[0] is the address of the faulting instruction
+       // instead of the return address of the call.
+       wasPanic bool
+}
+
+// Frame is the information returned by Frames for each call frame.
+type Frame struct {
+       // Program counter for this frame; multiple frames may have
+       // the same PC value.
+       PC uintptr
+
+       // Func for this frame; may be nil for non-Go code or fully
+       // inlined functions.
+       Func *Func
+
+       // Function name, file name, and line number for this call frame.
+       // May be the empty string or zero if not known.
+       // If Func is not nil then Function == Func.Name().
+       Function string
+       File     string
+       Line     int
+
+       // Entry point for the function; may be zero if not known.
+       // If Func is not nil then Entry == Func.Entry().
+       Entry uintptr
+}
+
+// CallersFrames takes a slice of PC values returned by Callers and
+// prepares to return function/file/line information.
+// Do not change the slice until you are done with the Frames.
+func CallersFrames(callers []uintptr) *Frames {
+       return &Frames{callers, false}
+}
+
+// Next returns frame information for the next caller.
+// If more is false, there are no more callers (the Frame value is valid).
+func (ci *Frames) Next() (frame Frame, more bool) {
+       if len(ci.callers) == 0 {
+               ci.wasPanic = false
+               return Frame{}, false
+       }
+       pc := ci.callers[0]
+       ci.callers = ci.callers[1:]
+       more = len(ci.callers) > 0
+       f := FuncForPC(pc)
+       if f == nil {
+               ci.wasPanic = false
+               return Frame{}, more
+       }
+
+       entry := f.Entry()
+       xpc := pc
+       if xpc > entry && !ci.wasPanic {
+               xpc--
+       }
+       file, line := f.FileLine(xpc)
+
+       function := f.Name()
+       ci.wasPanic = entry == sigpanicPC
+
+       frame = Frame{
+               PC:       xpc,
+               Func:     f,
+               Function: function,
+               File:     file,
+               Line:     line,
+               Entry:    entry,
+       }
+
+       return frame, more
+}
+
 // NOTE: Func does not expose the actual unexported fields, because we return *Func
 // values to users, and we want to keep them from being able to overwrite the data
 // with (say) *f = Func{}.
index 1a3aaf0104714cd083b9b4b5581621b5521a1f58..4a74196032d76699d679954074451135b4adb23b 100644 (file)
 
 // Most linux systems use glibc's dynamic linker, which puts the
 // __kernel_vsyscall vdso helper at 0x10(GS) for easy access from position
-// independent code and setldt in this file does the same in the statically
-// linked case. Android, however, uses bionic's dynamic linker, which does not
-// save the helper anywhere, and so the only way to invoke a syscall from
-// position independent code is boring old int $0x80 (which is also what
-// bionic's syscall wrappers use).
-#ifdef GOOS_android
+// independent code and setldt in runtime does the same in the statically
+// linked case. However, systems that use alternative libc such as Android's
+// bionic and musl, do not save the helper anywhere, and so the only way to
+// invoke a syscall from position independent code is boring old int $0x80
+// (which is also what syscall wrappers in bionic/musl use).
+//
+// The benchmarks also showed that using int $0x80 is as fast as calling
+// *%gs:0x10 except on AMD Opteron. See https://golang.org/cl/19833
+// for the benchmark program and raw data.
+//#define INVOKE_SYSCALL       CALL    0x10(GS) // non-portable
 #define INVOKE_SYSCALL INT     $0x80
-#else
-#define INVOKE_SYSCALL CALL    0x10(GS)
-#endif
 
 TEXT runtime·exit(SB),NOSPLIT,$0
        MOVL    $252, AX        // syscall number
@@ -434,12 +435,6 @@ TEXT runtime·setldt(SB),NOSPLIT,$32
         */
        ADDL    $0x4, DX        // address
        MOVL    DX, 0(DX)
-        // We copy the glibc dynamic linker behaviour of storing the
-        // __kernel_vsyscall entry point at 0x10(GS) so that it can be invoked
-        // by "CALL 0x10(GS)" in all situations, not only those where the
-        // binary is actually dynamically linked.
-       MOVL    runtime·_vdso(SB), AX
-       MOVL    AX, 0x10(DX)
 #endif
 
        // set up user_desc
index 3a82674684b0fdbe3e6c5db7718d5b8ea0c538f8..09f22636a9f7f6835ef6482e2d009a08c47ecc5e 100644 (file)
@@ -52,7 +52,7 @@ TEXT runtime·nanotime1(SB),NOSPLIT,$0
 // pipe(3c) wrapper that returns fds in AX, DX.
 // NOT USING GO CALLING CONVENTION.
 TEXT runtime·pipe1(SB),NOSPLIT,$0
-       SUBQ    $16, SP // 8 bytes will do, but stack has to be 16-byte alligned
+       SUBQ    $16, SP // 8 bytes will do, but stack has to be 16-byte aligned
        MOVQ    SP, DI
        LEAQ    libc_pipe(SB), AX
        CALL    AX
index 5d2550dbb0343542bac5f3ee5ee64edd41d353c3..7a2e013d43b058e436aaa560692d3290192d766a 100644 (file)
@@ -11,7 +11,9 @@ void foo2(void* p) {}
 import "C"
 import (
        "fmt"
+       "os"
        "runtime"
+       "strconv"
        "time"
        "unsafe"
 )
@@ -83,8 +85,16 @@ func CgoTraceback() {
 }
 
 func CgoCheckBytes() {
-       b := make([]byte, 1e6)
-       for i := 0; i < 1e3; i++ {
+       try, _ := strconv.Atoi(os.Getenv("GO_CGOCHECKBYTES_TRY"))
+       if try <= 0 {
+               try = 1
+       }
+       b := make([]byte, 1e6*try)
+       start := time.Now()
+       for i := 0; i < 1e3*try; i++ {
                C.foo2(unsafe.Pointer(&b[0]))
+               if time.Since(start) > time.Second {
+                       break
+               }
        }
 }
index b4bfe716272929c8620704b19b890797a2005c31..1d76947380e5fe84b40201f2c3875ffe5715b349 100644 (file)
@@ -645,7 +645,6 @@ var gStatusStrings = [...]string{
        _Gsyscall:   "syscall",
        _Gwaiting:   "waiting",
        _Gdead:      "dead",
-       _Genqueue:   "enqueue",
        _Gcopystack: "copystack",
 }
 
index d5f3bb1ef02e06b50390153df3a950e839471753..18c6a32ecba710cbbbbb8b53bc9f52adc39a6a1b 100644 (file)
@@ -24,9 +24,38 @@ type _type struct {
        // If the KindGCProg bit is set in kind, gcdata is a GC program.
        // Otherwise it is a ptrmask bitmap. See mbitmap.go for details.
        gcdata  *byte
-       _string *string
+       _string string
        x       *uncommontype
-       ptrto   *_type
+}
+
+func hasPrefix(s, prefix string) bool {
+       return len(s) >= len(prefix) && s[:len(prefix)] == prefix
+}
+
+func (t *_type) name() string {
+       if hasPrefix(t._string, "map[") {
+               return ""
+       }
+       if hasPrefix(t._string, "struct {") {
+               return ""
+       }
+       if hasPrefix(t._string, "chan ") {
+               return ""
+       }
+       if hasPrefix(t._string, "func(") {
+               return ""
+       }
+       if t._string[0] == '[' || t._string[0] == '*' {
+               return ""
+       }
+       i := len(t._string) - 1
+       for i >= 0 {
+               if t._string[i] == '.' {
+                       break
+               }
+               i--
+       }
+       return t._string[i+1:]
 }
 
 type method struct {
@@ -39,7 +68,6 @@ type method struct {
 }
 
 type uncommontype struct {
-       name    *string
        pkgpath *string
        mhdr    []method
 }
index 5eb45c6d4a1cfe000e077259b9c862c57ce66d3d..ce3dc06f8868945c036317939a4538711d545e13 100644 (file)
@@ -119,15 +119,15 @@ func doPivot(data Interface, lo, hi int) (midlo, midhi int) {
        pivot := lo
        a, c := lo+1, hi-1
 
-       for ; a != c && data.Less(a, pivot); a++ {
+       for ; a < c && data.Less(a, pivot); a++ {
        }
        b := a
        for {
-               for ; b != c && !data.Less(pivot, b); b++ { // data[b] <= pivot
+               for ; b < c && !data.Less(pivot, b); b++ { // data[b] <= pivot
                }
-               for ; b != c && data.Less(pivot, c-1); c-- { // data[c-1] > pivot
+               for ; b < c && data.Less(pivot, c-1); c-- { // data[c-1] > pivot
                }
-               if b == c {
+               if b >= c {
                        break
                }
                // data[b] > pivot; data[c-1] <= pivot
@@ -167,11 +167,11 @@ func doPivot(data Interface, lo, hi int) (midlo, midhi int) {
                //      data[a <= i < b] unexamined
                //      data[b <= i < c] = pivot
                for {
-                       for ; a != b && !data.Less(b-1, pivot); b-- { // data[b] == pivot
+                       for ; a < b && !data.Less(b-1, pivot); b-- { // data[b] == pivot
                        }
-                       for ; a != b && data.Less(a, pivot); a++ { // data[a] < pivot
+                       for ; a < b && data.Less(a, pivot); a++ { // data[a] < pivot
                        }
-                       if a == b {
+                       if a >= b {
                                break
                        }
                        // data[a] == pivot; data[b-1] < pivot
index 6c36f30e0eebba98bc41e7ed50e45064498ee33f..60fac2d695180aadaf2bd1624715bafa8d311f00 100644 (file)
@@ -109,6 +109,43 @@ func TestReverseSortIntSlice(t *testing.T) {
        }
 }
 
+type nonDeterministicTestingData struct {
+       r *rand.Rand
+}
+
+func (t *nonDeterministicTestingData) Len() int {
+       return 500
+}
+func (t *nonDeterministicTestingData) Less(i, j int) bool {
+       if i < 0 || j < 0 || i >= t.Len() || j >= t.Len() {
+               panic("nondeterministic comparison out of bounds")
+       }
+       return t.r.Float32() < 0.5
+}
+func (t *nonDeterministicTestingData) Swap(i, j int) {
+       if i < 0 || j < 0 || i >= t.Len() || j >= t.Len() {
+               panic("nondeterministic comparison out of bounds")
+       }
+}
+
+func TestNonDeterministicComparison(t *testing.T) {
+       // Ensure that sort.Sort does not panic when Less returns inconsistent results.
+       // See https://golang.org/issue/14377.
+       defer func() {
+               if r := recover(); r != nil {
+                       t.Error(r)
+               }
+       }()
+
+       td := &nonDeterministicTestingData{
+               r: rand.New(rand.NewSource(0)),
+       }
+
+       for i := 0; i < 10; i++ {
+               Sort(td)
+       }
+}
+
 func BenchmarkSortString1K(b *testing.B) {
        b.StopTimer()
        for i := 0; i < b.N; i++ {
@@ -469,10 +506,10 @@ func TestStability(t *testing.T) {
        data.initB()
        Stable(data)
        if !IsSorted(data) {
-               t.Errorf("Stable shuffeled sorted %d ints (order)", n)
+               t.Errorf("Stable shuffled sorted %d ints (order)", n)
        }
        if !data.inOrder() {
-               t.Errorf("Stable shuffeled sorted %d ints (stability)", n)
+               t.Errorf("Stable shuffled sorted %d ints (stability)", n)
        }
 
        // sorted reversed
index 40d0667551a63c1c2f28f78f022d75d925cc396b..a37a309f2668e588890544ad601fd1338253cc29 100644 (file)
@@ -6,15 +6,19 @@
 
 package strconv
 
-import (
-       "unicode/utf8"
-)
+import "unicode/utf8"
 
 const lowerhex = "0123456789abcdef"
 
 func quoteWith(s string, quote byte, ASCIIonly, graphicOnly bool) string {
-       var runeTmp [utf8.UTFMax]byte
-       buf := make([]byte, 0, 3*len(s)/2) // Try to avoid more allocations.
+       return string(appendQuotedWith(make([]byte, 0, 3*len(s)/2), s, quote, ASCIIonly, graphicOnly))
+}
+
+func quoteRuneWith(r rune, quote byte, ASCIIonly, graphicOnly bool) string {
+       return string(appendQuotedRuneWith(nil, r, quote, ASCIIonly, graphicOnly))
+}
+
+func appendQuotedWith(buf []byte, s string, quote byte, ASCIIonly, graphicOnly bool) []byte {
        buf = append(buf, quote)
        for width := 0; len(s) > 0; s = s[width:] {
                r := rune(s[0])
@@ -28,61 +32,76 @@ func quoteWith(s string, quote byte, ASCIIonly, graphicOnly bool) string {
                        buf = append(buf, lowerhex[s[0]&0xF])
                        continue
                }
-               if r == rune(quote) || r == '\\' { // always backslashed
-                       buf = append(buf, '\\')
+               buf = appendEscapedRune(buf, r, width, quote, ASCIIonly, graphicOnly)
+       }
+       buf = append(buf, quote)
+       return buf
+}
+
+func appendQuotedRuneWith(buf []byte, r rune, quote byte, ASCIIonly, graphicOnly bool) []byte {
+       buf = append(buf, quote)
+       if !utf8.ValidRune(r) {
+               r = utf8.RuneError
+       }
+       buf = appendEscapedRune(buf, r, utf8.RuneLen(r), quote, ASCIIonly, graphicOnly)
+       buf = append(buf, quote)
+       return buf
+}
+
+func appendEscapedRune(buf []byte, r rune, width int, quote byte, ASCIIonly, graphicOnly bool) []byte {
+       var runeTmp [utf8.UTFMax]byte
+       if r == rune(quote) || r == '\\' { // always backslashed
+               buf = append(buf, '\\')
+               buf = append(buf, byte(r))
+               return buf
+       }
+       if ASCIIonly {
+               if r < utf8.RuneSelf && IsPrint(r) {
                        buf = append(buf, byte(r))
-                       continue
+                       return buf
                }
-               if ASCIIonly {
-                       if r < utf8.RuneSelf && IsPrint(r) {
-                               buf = append(buf, byte(r))
-                               continue
+       } else if IsPrint(r) || graphicOnly && isInGraphicList(r) {
+               n := utf8.EncodeRune(runeTmp[:], r)
+               buf = append(buf, runeTmp[:n]...)
+               return buf
+       }
+       switch r {
+       case '\a':
+               buf = append(buf, `\a`...)
+       case '\b':
+               buf = append(buf, `\b`...)
+       case '\f':
+               buf = append(buf, `\f`...)
+       case '\n':
+               buf = append(buf, `\n`...)
+       case '\r':
+               buf = append(buf, `\r`...)
+       case '\t':
+               buf = append(buf, `\t`...)
+       case '\v':
+               buf = append(buf, `\v`...)
+       default:
+               switch {
+               case r < ' ':
+                       buf = append(buf, `\x`...)
+                       buf = append(buf, lowerhex[byte(r)>>4])
+                       buf = append(buf, lowerhex[byte(r)&0xF])
+               case r > utf8.MaxRune:
+                       r = 0xFFFD
+                       fallthrough
+               case r < 0x10000:
+                       buf = append(buf, `\u`...)
+                       for s := 12; s >= 0; s -= 4 {
+                               buf = append(buf, lowerhex[r>>uint(s)&0xF])
                        }
-               } else if IsPrint(r) || graphicOnly && isInGraphicList(r) {
-                       n := utf8.EncodeRune(runeTmp[:], r)
-                       buf = append(buf, runeTmp[:n]...)
-                       continue
-               }
-               switch r {
-               case '\a':
-                       buf = append(buf, `\a`...)
-               case '\b':
-                       buf = append(buf, `\b`...)
-               case '\f':
-                       buf = append(buf, `\f`...)
-               case '\n':
-                       buf = append(buf, `\n`...)
-               case '\r':
-                       buf = append(buf, `\r`...)
-               case '\t':
-                       buf = append(buf, `\t`...)
-               case '\v':
-                       buf = append(buf, `\v`...)
                default:
-                       switch {
-                       case r < ' ':
-                               buf = append(buf, `\x`...)
-                               buf = append(buf, lowerhex[s[0]>>4])
-                               buf = append(buf, lowerhex[s[0]&0xF])
-                       case r > utf8.MaxRune:
-                               r = 0xFFFD
-                               fallthrough
-                       case r < 0x10000:
-                               buf = append(buf, `\u`...)
-                               for s := 12; s >= 0; s -= 4 {
-                                       buf = append(buf, lowerhex[r>>uint(s)&0xF])
-                               }
-                       default:
-                               buf = append(buf, `\U`...)
-                               for s := 28; s >= 0; s -= 4 {
-                                       buf = append(buf, lowerhex[r>>uint(s)&0xF])
-                               }
+                       buf = append(buf, `\U`...)
+                       for s := 28; s >= 0; s -= 4 {
+                               buf = append(buf, lowerhex[r>>uint(s)&0xF])
                        }
                }
        }
-       buf = append(buf, quote)
-       return string(buf)
-
+       return buf
 }
 
 // Quote returns a double-quoted Go string literal representing s.  The
@@ -96,7 +115,7 @@ func Quote(s string) string {
 // AppendQuote appends a double-quoted Go string literal representing s,
 // as generated by Quote, to dst and returns the extended buffer.
 func AppendQuote(dst []byte, s string) []byte {
-       return append(dst, Quote(s)...)
+       return appendQuotedWith(dst, s, '"', false, false)
 }
 
 // QuoteToASCII returns a double-quoted Go string literal representing s.
@@ -109,7 +128,7 @@ func QuoteToASCII(s string) string {
 // AppendQuoteToASCII appends a double-quoted Go string literal representing s,
 // as generated by QuoteToASCII, to dst and returns the extended buffer.
 func AppendQuoteToASCII(dst []byte, s string) []byte {
-       return append(dst, QuoteToASCII(s)...)
+       return appendQuotedWith(dst, s, '"', true, false)
 }
 
 // QuoteToGraphic returns a double-quoted Go string literal representing s.
@@ -122,21 +141,20 @@ func QuoteToGraphic(s string) string {
 // AppendQuoteToGraphic appends a double-quoted Go string literal representing s,
 // as generated by QuoteToGraphic, to dst and returns the extended buffer.
 func AppendQuoteToGraphic(dst []byte, s string) []byte {
-       return append(dst, QuoteToGraphic(s)...)
+       return appendQuotedWith(dst, s, '"', false, true)
 }
 
 // QuoteRune returns a single-quoted Go character literal representing the
 // rune. The returned string uses Go escape sequences (\t, \n, \xFF, \u0100)
 // for control characters and non-printable characters as defined by IsPrint.
 func QuoteRune(r rune) string {
-       // TODO: avoid the allocation here.
-       return quoteWith(string(r), '\'', false, false)
+       return quoteRuneWith(r, '\'', false, false)
 }
 
 // AppendQuoteRune appends a single-quoted Go character literal representing the rune,
 // as generated by QuoteRune, to dst and returns the extended buffer.
 func AppendQuoteRune(dst []byte, r rune) []byte {
-       return append(dst, QuoteRune(r)...)
+       return appendQuotedRuneWith(dst, r, '\'', false, false)
 }
 
 // QuoteRuneToASCII returns a single-quoted Go character literal representing
@@ -144,14 +162,13 @@ func AppendQuoteRune(dst []byte, r rune) []byte {
 // \u0100) for non-ASCII characters and non-printable characters as defined
 // by IsPrint.
 func QuoteRuneToASCII(r rune) string {
-       // TODO: avoid the allocation here.
-       return quoteWith(string(r), '\'', true, false)
+       return quoteRuneWith(r, '\'', true, false)
 }
 
 // AppendQuoteRuneToASCII appends a single-quoted Go character literal representing the rune,
 // as generated by QuoteRuneToASCII, to dst and returns the extended buffer.
 func AppendQuoteRuneToASCII(dst []byte, r rune) []byte {
-       return append(dst, QuoteRuneToASCII(r)...)
+       return appendQuotedRuneWith(dst, r, '\'', true, false)
 }
 
 // QuoteRuneToGraphic returns a single-quoted Go character literal representing
@@ -159,14 +176,13 @@ func AppendQuoteRuneToASCII(dst []byte, r rune) []byte {
 // \u0100) for non-ASCII characters and non-printable characters as defined
 // by IsGraphic.
 func QuoteRuneToGraphic(r rune) string {
-       // TODO: avoid the allocation here.
-       return quoteWith(string(r), '\'', false, true)
+       return quoteRuneWith(r, '\'', false, true)
 }
 
 // AppendQuoteRuneToGraphic appends a single-quoted Go character literal representing the rune,
 // as generated by QuoteRuneToGraphic, to dst and returns the extended buffer.
 func AppendQuoteRuneToGraphic(dst []byte, r rune) []byte {
-       return append(dst, QuoteRuneToGraphic(r)...)
+       return appendQuotedRuneWith(dst, r, '\'', false, true)
 }
 
 // CanBackquote reports whether the string s can be represented
index 3e8ec2c98f367828f0572735cdfae09a9e6abdcc..10735e316c7dd830da71738fadca5dea336b82d9 100644 (file)
@@ -89,6 +89,34 @@ func TestQuoteToGraphic(t *testing.T) {
        }
 }
 
+func BenchmarkQuote(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               Quote("\a\b\f\r\n\t\v\a\b\f\r\n\t\v\a\b\f\r\n\t\v")
+       }
+}
+
+func BenchmarkQuoteRune(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               QuoteRune('\a')
+       }
+}
+
+var benchQuoteBuf []byte
+
+func BenchmarkAppendQuote(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               benchQuoteBuf = AppendQuote(benchQuoteBuf[:0], "\a\b\f\r\n\t\v\a\b\f\r\n\t\v\a\b\f\r\n\t\v")
+       }
+}
+
+var benchQuoteRuneBuf []byte
+
+func BenchmarkAppendQuoteRune(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               benchQuoteRuneBuf = AppendQuoteRune(benchQuoteRuneBuf[:0], '\a')
+       }
+}
+
 type quoteRuneTest struct {
        in      rune
        out     string
diff --git a/src/sync/atomic/asm_plan9_arm.s b/src/sync/atomic/asm_plan9_arm.s
new file mode 100644 (file)
index 0000000..5108fc6
--- /dev/null
@@ -0,0 +1,108 @@
+// Copyright 2012 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+#define DMB_ISH_7 \
+       MOVB    runtime·goarm(SB), R11; \
+       CMP     $7, R11; \
+       BLT     2(PC); \
+       WORD    $0xf57ff05b     // dmb ish
+
+// Plan9/ARM atomic operations.
+// TODO(minux): this only supports ARMv6K or higher.
+
+TEXT Â·CompareAndSwapInt32(SB),NOSPLIT,$0
+       B Â·CompareAndSwapUint32(SB)
+
+TEXT Â·CompareAndSwapUint32(SB),NOSPLIT,$0
+       B Â·armCompareAndSwapUint32(SB)
+
+TEXT Â·CompareAndSwapUintptr(SB),NOSPLIT,$0
+       B Â·CompareAndSwapUint32(SB)
+
+TEXT Â·AddInt32(SB),NOSPLIT,$0
+       B Â·AddUint32(SB)
+
+TEXT Â·AddUint32(SB),NOSPLIT,$0
+       B Â·armAddUint32(SB)
+
+TEXT Â·AddUintptr(SB),NOSPLIT,$0
+       B Â·AddUint32(SB)
+
+TEXT Â·SwapInt32(SB),NOSPLIT,$0
+       B Â·SwapUint32(SB)
+
+TEXT Â·SwapUint32(SB),NOSPLIT,$0
+       B Â·armSwapUint32(SB)
+
+TEXT Â·SwapUintptr(SB),NOSPLIT,$0
+       B Â·SwapUint32(SB)
+
+TEXT Â·CompareAndSwapInt64(SB),NOSPLIT,$0
+       B Â·CompareAndSwapUint64(SB)
+
+TEXT Â·CompareAndSwapUint64(SB),NOSPLIT,$-4
+       B Â·armCompareAndSwapUint64(SB)
+
+TEXT Â·AddInt64(SB),NOSPLIT,$0
+       B Â·addUint64(SB)
+
+TEXT Â·AddUint64(SB),NOSPLIT,$0
+       B Â·addUint64(SB)
+
+TEXT Â·SwapInt64(SB),NOSPLIT,$0
+       B Â·swapUint64(SB)
+
+TEXT Â·SwapUint64(SB),NOSPLIT,$0
+       B Â·swapUint64(SB)
+
+TEXT Â·LoadInt32(SB),NOSPLIT,$0
+       B Â·LoadUint32(SB)
+
+TEXT Â·LoadUint32(SB),NOSPLIT,$0-8
+       MOVW addr+0(FP), R1
+load32loop:
+       LDREX (R1), R2          // loads R2
+       STREX R2, (R1), R0      // stores R2
+       CMP $0, R0
+       BNE load32loop
+       MOVW R2, val+4(FP)
+       DMB_ISH_7
+       RET
+
+TEXT Â·LoadInt64(SB),NOSPLIT,$0
+       B Â·loadUint64(SB)
+
+TEXT Â·LoadUint64(SB),NOSPLIT,$0
+       B Â·loadUint64(SB)
+
+TEXT Â·LoadUintptr(SB),NOSPLIT,$0
+       B Â·LoadUint32(SB)
+
+TEXT Â·LoadPointer(SB),NOSPLIT,$0
+       B Â·LoadUint32(SB)
+
+TEXT Â·StoreInt32(SB),NOSPLIT,$0
+       B Â·StoreUint32(SB)
+
+TEXT Â·StoreUint32(SB),NOSPLIT,$0-8
+       MOVW addr+0(FP), R1
+       MOVW val+4(FP), R2
+       DMB_ISH_7
+storeloop:
+       LDREX (R1), R4          // loads R4
+       STREX R2, (R1), R0      // stores R2
+       CMP $0, R0
+       BNE storeloop
+       RET
+
+TEXT Â·StoreInt64(SB),NOSPLIT,$0
+       B Â·storeUint64(SB)
+
+TEXT Â·StoreUint64(SB),NOSPLIT,$0
+       B Â·storeUint64(SB)
+
+TEXT Â·StoreUintptr(SB),NOSPLIT,$0
+       B Â·StoreUint32(SB)
index 382dc6854d1561af5af75952abcda4b5256f01b4..fd90451dd83f6afdce6da4ca95b79a38519de4e8 100644 (file)
@@ -86,6 +86,11 @@ func TestValueConcurrent(t *testing.T) {
                {complex(0, 0), complex(1, 2), complex(3, 4), complex(5, 6)},
        }
        p := 4 * runtime.GOMAXPROCS(0)
+       N := int(1e5)
+       if testing.Short() {
+               p /= 2
+               N = 1e3
+       }
        for _, test := range tests {
                var v Value
                done := make(chan bool)
@@ -93,7 +98,7 @@ func TestValueConcurrent(t *testing.T) {
                        go func() {
                                r := rand.New(rand.NewSource(rand.Int63()))
                        loop:
-                               for j := 0; j < 1e5; j++ {
+                               for j := 0; j < N; j++ {
                                        x := test[r.Intn(len(test))]
                                        v.Store(x)
                                        x = v.Load()
index c94060571b11c0205b5e22f1580f4c6cd09c1b9a..228a542cf1c8b3cf46e8270f273433b1edf8cc41 100644 (file)
 // func Syscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr);
 // Trap # in AX, args in BX CX DX SI DI, return in AX
 
-// Most linux systems use glibc's dynamic linker, which puts the
-// __kernel_vsyscall vdso helper at 0x10(GS) for easy access from position
-// independent code and setldt in runtime does the same in the statically
-// linked case. Android, however, uses bionic's dynamic linker, which does not
-// save the helper anywhere, and so the only way to invoke a syscall from
-// position independent code is boring old int $0x80 (which is also what
-// bionic's syscall wrappers use).
-#ifdef GOOS_android
+// See ../runtime/sys_linux_386.s for the reason why we always use int 0x80
+// instead of the glibc-specific "CALL 0x10(GS)".
 #define INVOKE_SYSCALL INT     $0x80
-#else
-#define INVOKE_SYSCALL CALL    0x10(GS)
-#endif
 
 TEXT   Â·Syscall(SB),NOSPLIT,$0-28
        CALL    runtime·entersyscall(SB)
diff --git a/src/syscall/asm_plan9_arm.s b/src/syscall/asm_plan9_arm.s
new file mode 100644 (file)
index 0000000..dd05844
--- /dev/null
@@ -0,0 +1,97 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+#define SYS_SEEK 39    /* from zsysnum_plan9.go */
+
+// System call support for plan9 on arm
+
+TEXT   sysresult<>(SB),NOSPLIT,$12
+       MOVW    $runtime·emptystring+0(SB), R2
+       CMP             $-1, R0
+       B.NE    ok
+       MOVW    R1, save-4(SP)
+       BL              runtime·errstr(SB)
+       MOVW    save-4(SP), R1
+       MOVW    $err-12(SP), R2
+ok:
+       MOVM.IA (R2), [R3-R4]
+       MOVM.IA [R3-R4], (R1)
+       RET
+       
+//func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err ErrorString)
+TEXT   Â·Syscall(SB),NOSPLIT,$0
+       BL              runtime·entersyscall(SB)
+       MOVW    trap+0(FP), R0  // syscall num
+       MOVM.IA.W       (R13),[R1-R2]   // pop LR and caller's LR
+       SWI             0
+       MOVM.DB.W       [R1-R2],(R13)   // push LR and caller's LR
+       MOVW    $0, R2
+       MOVW    $r1+16(FP), R1
+       MOVM.IA.W       [R0,R2], (R1)
+       BL              sysresult<>(SB)
+       BL              runtime·exitsyscall(SB)
+       RET
+
+//func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err ErrorString)
+// Actually Syscall5 but the rest of the code expects it to be named Syscall6.
+TEXT   Â·Syscall6(SB),NOSPLIT,$0
+       BL              runtime·entersyscall(SB)
+       MOVW    trap+0(FP), R0  // syscall num
+       MOVM.IA.W       (R13),[R1-R2]   // pop LR and caller's LR
+       SWI             0
+       MOVM.DB.W       [R1-R2],(R13)   // push LR and caller's LR
+       MOVW    $0, R1
+       MOVW    $r1+28(FP), R1
+       MOVM.IA.W       [R0,R2], (R1)
+       BL              sysresult<>(SB)
+       BL              runtime·exitsyscall(SB)
+       RET
+
+//func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
+TEXT Â·RawSyscall(SB),NOSPLIT,$0
+       MOVW    trap+0(FP), R0  // syscall num
+       MOVM.IA.W       (R13),[R1]              // pop caller's LR
+       SWI             0
+       MOVM.DB.W       [R1],(R13)              // push caller's LR
+       MOVW    R0, r1+16(FP)
+       MOVW    R0, r2+20(FP)
+       MOVW    R0, err+24(FP)
+       RET
+
+//func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
+// Actually RawSyscall5 but the rest of the code expects it to be named RawSyscall6.
+TEXT   Â·RawSyscall6(SB),NOSPLIT,$0
+       MOVW    trap+0(FP), R0  // syscall num
+       MOVM.IA.W       (R13),[R1]              // pop caller's LR
+       SWI             0
+       MOVM.DB.W       [R1],(R13)              // push caller's LR
+       MOVW    R0, r1+28(FP)
+       MOVW    R0, r2+32(FP)
+       MOVW    R0, err+36(FP)
+       RET
+
+//func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string)
+TEXT Â·seek(SB),NOSPLIT,$0
+       MOVW    $newoffset_lo+20(FP), R5
+       MOVW    R5, placeholder+0(FP)   //placeholder = dest for return value
+       MOVW    $SYS_SEEK, R0           // syscall num
+       MOVM.IA.W       (R13),[R1]              // pop LR
+       SWI             0
+       MOVM.DB.W       [R1],(R13)              // push LR
+       CMP             $-1, R0
+       MOVW.EQ R0, 0(R5)
+       MOVW.EQ R0, 4(R5)
+       MOVW    $err+28(FP), R1
+       BL              sysresult<>(SB)
+       RET
+
+//func exit(code int)
+// Import runtime·exit for cleanly exiting.
+TEXT Â·exit(SB),NOSPLIT,$4
+       MOVW    code+0(FP), R0
+       MOVW    R0, e-4(SP)
+       BL              runtime·exit(SB)
+       RET
index c635a1385e2b20904ebfee9b6b55f87300103ef9..d9b6697a759e60476bdceceb8a41251a41f2b8e1 100644 (file)
@@ -138,7 +138,7 @@ func parseNetworkLayerAddr(b []byte, family byte) (Sockaddr, error) {
        //
        // - The kernel form appends leading bytes to the prefix field
        //   to make the <length, prefix> tuple to be conformed with
-       //   the routing messeage boundary
+       //   the routing message boundary
        l := int(rsaAlignOf(int(b[0])))
        if len(b) < l {
                return nil, EINVAL
diff --git a/src/syscall/zsyscall_plan9_arm.go b/src/syscall/zsyscall_plan9_arm.go
new file mode 100644 (file)
index 0000000..d54aeff
--- /dev/null
@@ -0,0 +1,294 @@
+// mksyscall.pl -l32 -plan9 syscall_plan9.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// +build arm,plan9
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fd2path(fd int, buf []byte) (err error) {
+       var _p0 unsafe.Pointer
+       if len(buf) > 0 {
+               _p0 = unsafe.Pointer(&buf[0])
+       } else {
+               _p0 = unsafe.Pointer(&_zero)
+       }
+       r0, _, e1 := Syscall(SYS_FD2PATH, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
+       if int32(r0) == -1 {
+               err = e1
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func pipe(p *[2]int32) (err error) {
+       r0, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
+       if int32(r0) == -1 {
+               err = e1
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func await(s []byte) (n int, err error) {
+       var _p0 unsafe.Pointer
+       if len(s) > 0 {
+               _p0 = unsafe.Pointer(&s[0])
+       } else {
+               _p0 = unsafe.Pointer(&_zero)
+       }
+       r0, _, e1 := Syscall(SYS_AWAIT, uintptr(_p0), uintptr(len(s)), 0)
+       n = int(r0)
+       if int32(r0) == -1 {
+               err = e1
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func open(path string, mode int) (fd int, err error) {
+       var _p0 *byte
+       _p0, err = BytePtrFromString(path)
+       if err != nil {
+               return
+       }
+       r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+       use(unsafe.Pointer(_p0))
+       fd = int(r0)
+       if int32(r0) == -1 {
+               err = e1
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func create(path string, mode int, perm uint32) (fd int, err error) {
+       var _p0 *byte
+       _p0, err = BytePtrFromString(path)
+       if err != nil {
+               return
+       }
+       r0, _, e1 := Syscall(SYS_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
+       use(unsafe.Pointer(_p0))
+       fd = int(r0)
+       if int32(r0) == -1 {
+               err = e1
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func remove(path string) (err error) {
+       var _p0 *byte
+       _p0, err = BytePtrFromString(path)
+       if err != nil {
+               return
+       }
+       r0, _, e1 := Syscall(SYS_REMOVE, uintptr(unsafe.Pointer(_p0)), 0, 0)
+       use(unsafe.Pointer(_p0))
+       if int32(r0) == -1 {
+               err = e1
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func stat(path string, edir []byte) (n int, err error) {
+       var _p0 *byte
+       _p0, err = BytePtrFromString(path)
+       if err != nil {
+               return
+       }
+       var _p1 unsafe.Pointer
+       if len(edir) > 0 {
+               _p1 = unsafe.Pointer(&edir[0])
+       } else {
+               _p1 = unsafe.Pointer(&_zero)
+       }
+       r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
+       use(unsafe.Pointer(_p0))
+       n = int(r0)
+       if int32(r0) == -1 {
+               err = e1
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func bind(name string, old string, flag int) (err error) {
+       var _p0 *byte
+       _p0, err = BytePtrFromString(name)
+       if err != nil {
+               return
+       }
+       var _p1 *byte
+       _p1, err = BytePtrFromString(old)
+       if err != nil {
+               return
+       }
+       r0, _, e1 := Syscall(SYS_BIND, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flag))
+       use(unsafe.Pointer(_p0))
+       use(unsafe.Pointer(_p1))
+       if int32(r0) == -1 {
+               err = e1
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func mount(fd int, afd int, old string, flag int, aname string) (err error) {
+       var _p0 *byte
+       _p0, err = BytePtrFromString(old)
+       if err != nil {
+               return
+       }
+       var _p1 *byte
+       _p1, err = BytePtrFromString(aname)
+       if err != nil {
+               return
+       }
+       r0, _, e1 := Syscall6(SYS_MOUNT, uintptr(fd), uintptr(afd), uintptr(unsafe.Pointer(_p0)), uintptr(flag), uintptr(unsafe.Pointer(_p1)), 0)
+       use(unsafe.Pointer(_p0))
+       use(unsafe.Pointer(_p1))
+       if int32(r0) == -1 {
+               err = e1
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func wstat(path string, edir []byte) (err error) {
+       var _p0 *byte
+       _p0, err = BytePtrFromString(path)
+       if err != nil {
+               return
+       }
+       var _p1 unsafe.Pointer
+       if len(edir) > 0 {
+               _p1 = unsafe.Pointer(&edir[0])
+       } else {
+               _p1 = unsafe.Pointer(&_zero)
+       }
+       r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
+       use(unsafe.Pointer(_p0))
+       if int32(r0) == -1 {
+               err = e1
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func chdir(path string) (err error) {
+       var _p0 *byte
+       _p0, err = BytePtrFromString(path)
+       if err != nil {
+               return
+       }
+       r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
+       use(unsafe.Pointer(_p0))
+       if int32(r0) == -1 {
+               err = e1
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup(oldfd int, newfd int) (fd int, err error) {
+       r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), uintptr(newfd), 0)
+       fd = int(r0)
+       if int32(r0) == -1 {
+               err = e1
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
+       var _p0 unsafe.Pointer
+       if len(p) > 0 {
+               _p0 = unsafe.Pointer(&p[0])
+       } else {
+               _p0 = unsafe.Pointer(&_zero)
+       }
+       r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
+       n = int(r0)
+       if int32(r0) == -1 {
+               err = e1
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
+       var _p0 unsafe.Pointer
+       if len(p) > 0 {
+               _p0 = unsafe.Pointer(&p[0])
+       } else {
+               _p0 = unsafe.Pointer(&_zero)
+       }
+       r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
+       n = int(r0)
+       if int32(r0) == -1 {
+               err = e1
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Close(fd int) (err error) {
+       r0, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
+       if int32(r0) == -1 {
+               err = e1
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fstat(fd int, edir []byte) (n int, err error) {
+       var _p0 unsafe.Pointer
+       if len(edir) > 0 {
+               _p0 = unsafe.Pointer(&edir[0])
+       } else {
+               _p0 = unsafe.Pointer(&_zero)
+       }
+       r0, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
+       n = int(r0)
+       if int32(r0) == -1 {
+               err = e1
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fwstat(fd int, edir []byte) (err error) {
+       var _p0 unsafe.Pointer
+       if len(edir) > 0 {
+               _p0 = unsafe.Pointer(&edir[0])
+       } else {
+               _p0 = unsafe.Pointer(&_zero)
+       }
+       r0, _, e1 := Syscall(SYS_FWSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
+       if int32(r0) == -1 {
+               err = e1
+       }
+       return
+}
index 187195c75907d7333bda9ab601c2009d4d2222a0..0c2bf2d72b71812e938a58836185d6fcce72024e 100644 (file)
@@ -14,7 +14,7 @@ import (
        "strings"
 )
 
-var defaultMaxCount *int = flag.Int("quickchecks", 100, "The default number of iterations for each check")
+var defaultMaxCount = flag.Int("quickchecks", 100, "The default number of iterations for each check")
 
 // A Generator can generate random values of its own type.
 type Generator interface {
@@ -98,18 +98,22 @@ func sizedValue(t reflect.Type, rand *rand.Rand, size int) (value reflect.Value,
        case reflect.Uintptr:
                v.SetUint(uint64(randInt64(rand)))
        case reflect.Map:
-               numElems := rand.Intn(size)
-               v.Set(reflect.MakeMap(concrete))
-               for i := 0; i < numElems; i++ {
-                       key, ok1 := sizedValue(concrete.Key(), rand, size)
-                       value, ok2 := sizedValue(concrete.Elem(), rand, size)
-                       if !ok1 || !ok2 {
-                               return reflect.Value{}, false
+               if generateNilValue(rand) {
+                       v.Set(reflect.Zero(concrete)) // Generate nil map.
+               } else {
+                       numElems := rand.Intn(size)
+                       v.Set(reflect.MakeMap(concrete))
+                       for i := 0; i < numElems; i++ {
+                               key, ok1 := sizedValue(concrete.Key(), rand, size)
+                               value, ok2 := sizedValue(concrete.Elem(), rand, size)
+                               if !ok1 || !ok2 {
+                                       return reflect.Value{}, false
+                               }
+                               v.SetMapIndex(key, value)
                        }
-                       v.SetMapIndex(key, value)
                }
        case reflect.Ptr:
-               if rand.Intn(size) == 0 {
+               if generateNilValue(rand) {
                        v.Set(reflect.Zero(concrete)) // Generate nil pointer.
                } else {
                        elem, ok := sizedValue(concrete.Elem(), rand, size)
@@ -120,15 +124,20 @@ func sizedValue(t reflect.Type, rand *rand.Rand, size int) (value reflect.Value,
                        v.Elem().Set(elem)
                }
        case reflect.Slice:
-               numElems := rand.Intn(size)
-               sizeLeft := size - numElems
-               v.Set(reflect.MakeSlice(concrete, numElems, numElems))
-               for i := 0; i < numElems; i++ {
-                       elem, ok := sizedValue(concrete.Elem(), rand, sizeLeft)
-                       if !ok {
-                               return reflect.Value{}, false
+               if generateNilValue(rand) {
+                       v.Set(reflect.Zero(concrete)) // Generate nil slice.
+               } else {
+                       slCap := rand.Intn(size)
+                       slLen := rand.Intn(slCap + 1)
+                       sizeLeft := size - slCap
+                       v.Set(reflect.MakeSlice(concrete, slLen, slCap))
+                       for i := 0; i < slLen; i++ {
+                               elem, ok := sizedValue(concrete.Elem(), rand, sizeLeft)
+                               if !ok {
+                                       return reflect.Value{}, false
+                               }
+                               v.Index(i).Set(elem)
                        }
-                       v.Index(i).Set(elem)
                }
        case reflect.Array:
                for i := 0; i < v.Len(); i++ {
@@ -384,3 +393,5 @@ func toString(interfaces []interface{}) string {
        }
        return strings.Join(s, ", ")
 }
+
+func generateNilValue(r *rand.Rand) bool { return r.Intn(20) == 0 }
index fe443592f87bed611c3957fde67fc56dcb295798..018ece2a5289ed8ae8fd9059096b71a0bc032d95 100644 (file)
@@ -290,20 +290,3 @@ func TestMutuallyRecursive(t *testing.T) {
        f := func(a A) bool { return true }
        Check(f, nil)
 }
-
-// Some serialization formats (e.g. encoding/pem) cannot distinguish
-// between a nil and an empty map or slice, so avoid generating the
-// zero value for these.
-func TestNonZeroSliceAndMap(t *testing.T) {
-       type Q struct {
-               M map[int]int
-               S []int
-       }
-       f := func(q Q) bool {
-               return q.M != nil && q.S != nil
-       }
-       err := Check(f, nil)
-       if err != nil {
-               t.Fatal(err)
-       }
-}
index 20443cb1ffb84affd1215ad8beccfdcbdc4066a2..422ec117adbf602b7a903e52b71cf3d2100d4973 100644 (file)
@@ -36,3 +36,38 @@ func ExampleWriter_Init() {
        //     a     b       c         d.
        //   123 12345 1234567 123456789.
 }
+
+func Example_elastic() {
+       // Observe how the b's and the d's, despite appearing in the
+       // second cell of each line, belong to different columns.
+       w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, '.', tabwriter.AlignRight|tabwriter.Debug)
+       fmt.Fprintln(w, "a\tb\tc")
+       fmt.Fprintln(w, "aa\tbb\tcc")
+       fmt.Fprintln(w, "aaa\t") // trailing tab
+       fmt.Fprintln(w, "aaaa\tdddd\teeee")
+       w.Flush()
+
+       // output:
+       // ....a|..b|c
+       // ...aa|.bb|cc
+       // ..aaa|
+       // .aaaa|.dddd|eeee
+}
+
+func Example_trailingTab() {
+       // Observe that the third line has no trailing tab,
+       // so its final cell is not part of an aligned column.
+       const padding = 3
+       w := tabwriter.NewWriter(os.Stdout, 0, 0, padding, '-', tabwriter.AlignRight|tabwriter.Debug)
+       fmt.Fprintln(w, "a\tb\taligned\t")
+       fmt.Fprintln(w, "aa\tbb\taligned\t")
+       fmt.Fprintln(w, "aaa\tbbb\tunaligned") // no trailing tab
+       fmt.Fprintln(w, "aaaa\tbbbb\taligned\t")
+       w.Flush()
+
+       // output:
+       // ------a|------b|---aligned|
+       // -----aa|-----bb|---aligned|
+       // ----aaa|----bbb|unaligned
+       // ---aaaa|---bbbb|---aligned|
+}
index c0c32d5deca51d2057b4c4658be67486f2159284..4cafdba2b2ed21bd0d93d810970a3410b10719e8 100644 (file)
@@ -33,18 +33,32 @@ type cell struct {
 // A Writer is a filter that inserts padding around tab-delimited
 // columns in its input to align them in the output.
 //
-// The Writer treats incoming bytes as UTF-8 encoded text consisting
-// of cells terminated by (horizontal or vertical) tabs or line
-// breaks (newline or formfeed characters). Cells in adjacent lines
-// constitute a column. The Writer inserts padding as needed to
-// make all cells in a column have the same width, effectively
-// aligning the columns. It assumes that all characters have the
-// same width except for tabs for which a tabwidth must be specified.
-// Note that cells are tab-terminated, not tab-separated: trailing
-// non-tab text at the end of a line does not form a column cell.
+// The Writer treats incoming bytes as UTF-8-encoded text consisting
+// of cells terminated by horizontal ('\t') or vertical ('\v') tabs,
+// and newline ('\n') or formfeed ('\f') characters; both newline and
+// formfeed act as line breaks.
+//
+// Tab-terminated cells in contiguous lines constitute a column. The
+// Writer inserts padding as needed to make all cells in a column have
+// the same width, effectively aligning the columns. It assumes that
+// all characters have the same width, except for tabs for which a
+// tabwidth must be specified. Column cells must be tab-terminated, not
+// tab-separated: non-tab terminated trailing text at the end of a line
+// forms a cell but that cell is not part of an aligned column.
+// For instance, in this example (where | stands for a horizontal tab):
+//
+//     aaaa|bbb|d
+//     aa  |b  |dd
+//     a   |
+//     aa  |cccc|eee
+//
+// the b and c are in distinct columns (the b column is not contiguous
+// all the way). The d and e are not in a column at all (there's no
+// terminating tab, nor would the column be contiguous).
 //
 // The Writer assumes that all Unicode code points have the same width;
-// this may not be true in some fonts.
+// this may not be true in some fonts or if the string contains combining
+// characters.
 //
 // If DiscardEmptyColumns is set, empty columns that are terminated
 // entirely by vertical (or "soft") tabs are discarded. Columns
@@ -64,9 +78,9 @@ type cell struct {
 // width of the escaped text is always computed excluding the Escape
 // characters.
 //
-// The formfeed character ('\f') acts like a newline but it also
-// terminates all columns in the current line (effectively calling
-// Flush). Cells in the next line start new columns. Unless found
+// The formfeed character acts like a newline but it also terminates
+// all columns in the current line (effectively calling Flush). Tab-
+// terminated cells in the next line start new columns. Unless found
 // inside an HTML tag or inside an escaped text segment, formfeed
 // characters appear as newlines in the output.
 //
index a8342f50aa527e36c6f723feed9fe84afb15563e..c8723cb7a8b1529978273c0d744ae94b39d2a551 100644 (file)
@@ -4,7 +4,7 @@
 
 package template
 
-// Tests for mulitple-template parsing and execution.
+// Tests for multiple-template parsing and execution.
 
 import (
        "bytes"
index 276fce9e563461940eb6ee8dd28f3e7c88af6eaf..0a5a02ebe2690da213e2ec10de90162564cd424b 100644 (file)
@@ -45,7 +45,7 @@ func DecodeRune(r1, r2 rune) rune {
 // If the rune is not a valid Unicode code point or does not need encoding,
 // EncodeRune returns U+FFFD, U+FFFD.
 func EncodeRune(r rune) (r1, r2 rune) {
-       if r < surrSelf || r > maxRune || IsSurrogate(r) {
+       if r < surrSelf || r > maxRune {
                return replacementChar, replacementChar
        }
        r -= surrSelf
@@ -65,20 +65,22 @@ func Encode(s []rune) []uint16 {
        n = 0
        for _, v := range s {
                switch {
-               case v < 0, surr1 <= v && v < surr3, v > maxRune:
-                       v = replacementChar
-                       fallthrough
-               case v < surrSelf:
+               case 0 <= v && v < surr1, surr3 <= v && v < surrSelf:
+                       // normal rune
                        a[n] = uint16(v)
                        n++
-               default:
+               case surrSelf <= v && v <= maxRune:
+                       // needs surrogate sequence
                        r1, r2 := EncodeRune(v)
                        a[n] = uint16(r1)
                        a[n+1] = uint16(r2)
                        n += 2
+               default:
+                       a[n] = uint16(replacementChar)
+                       n++
                }
        }
-       return a[0:n]
+       return a[:n]
 }
 
 // Decode returns the Unicode code point sequence represented
index 9f2a27ebd97431e0d3c9b42499ab896473f2875d..cfec4c9f1f47138747714a37081c5b928425dcee 100644 (file)
@@ -6,6 +6,6 @@
 
 package main
 func f() {
-       v := 1 << 1025;         // ERROR "overflow|stupid shift"
+       v := 1 << 1025;         // ERROR "overflow|shift count too large"
        _ = v
 }
index 56f245dee513a430d28808b27115b0fdf712eef4..f32d48048254df25d272daee452a45622f6aab94 100644 (file)
@@ -9,7 +9,7 @@
 
 package a
 import""  // ERROR "import path is empty"
-var?      // ERROR "unexpected \?"
+var?      // ERROR "illegal character U\+003F '\?'"
 
 var x int // ERROR "unexpected var" "cannot declare name"
 
diff --git a/test/fixedbugs/issue14520.go b/test/fixedbugs/issue14520.go
new file mode 100644 (file)
index 0000000..43c48b5
--- /dev/null
@@ -0,0 +1,14 @@
+// errorcheck
+
+// Copyright 2016 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package f
+
+import /* // ERROR "import path" */ `
+bogus`
+
+func f(x int /* // ERROR "unexpected semicolon"
+
+*/)